Ticket #10: fish-fix.patch

File fish-fix.patch, 16.3 KB (added by Patrick Winnertz, 16 years ago)

Added by email2trac

  • ChangeLog

     ChangeLog     |    5 +
     mhl/string.h  |    7 ++-
     vfs/fish.c    |  240 +++++++++++++++++++++++++++++++++++++++++++--------------
     vfs/utilvfs.c |   58 ++++++++++++++
     vfs/utilvfs.h |    2 +
     5 files changed, 254 insertions(+), 58 deletions(-)
    
    diff --git a/ChangeLog b/ChangeLog
    index e71071b..f1dbe82 100644
    a b  
     12009-01-25 Patrick Winnertz <winnie@debian.org> & Sergei Trofimovich  <slyfox@inbox.ru> 
     2 
     3        * mhl/string.h, vfs/fish.c, vfs/utilvfs.c, vfs/utilvfs.h: Reworked fish code 
     4          so that symlinks and files which special characters works now 
     5 
    162009-01-25 Enrico Weigelt <weigelt@metux.de> 
    27 
    38        * edit/editcmd.c, src/cmd.c, src/ext.c, src/history.h: 
  • mhl/string.h

    diff --git a/mhl/string.h b/mhl/string.h
    index fde86a7..28f6198 100644
    a b  
    99#define mhl_str_ndup(str,len)   ((str ? strndup(str,len) : strdup(""))) 
    1010#define mhl_str_len(str)        ((str ? strlen(str) : 0)) 
    1111 
     12static inline char * mhl_str_dup_range(const char * s_start, const char * s_bound) 
     13{ 
     14    return mhl_str_ndup(s_start, s_bound - s_start); 
     15} 
     16 
    1217static inline char* mhl_str_trim(char* str) 
    1318{ 
    1419    if (!str) return NULL;      // NULL string ?! bail out. 
    static inline char* mhl_str_reverse(char* ptr) 
    121126    return ptr; 
    122127} 
    123128 
    124 #endif 
     129#endif /* __MHL_STRING_H */ 
  • vfs/fish.c

    diff --git a/vfs/fish.c b/vfs/fish.c
    index 2a2deb6..c639498 100644
    a b  
    5050#include "tcputil.h" 
    5151#include "../src/unixcompat.h" 
    5252#include "fish.h" 
     53#include "../mhl/memory.h" 
     54#include "../mhl/string.h" 
     55#include "../mhl/escape.h" 
    5356 
    5457int fish_directory_timeout = 900; 
    5558 
    fish_dir_load(struct vfs_class *me, struct vfs_s_inode *dir, char *remote_path) 
    358361    char *quoted_path; 
    359362    int reply_code; 
    360363 
     364#if 0 
     365    /* 
     366     * Simple FISH debug interface :] 
     367     */ 
     368    if (!(MEDATA->logfile)) 
     369    { 
     370        MEDATA->logfile = fopen("/tmp/mc-FISH.sh", "w"); 
     371    } 
     372#endif // 0 
     373 
    361374    logfile = MEDATA->logfile; 
    362375 
    363376    print_vfs_message(_("fish: Reading directory %s..."), remote_path); 
    364377 
    365378    gettimeofday(&dir->timestamp, NULL); 
    366379    dir->timestamp.tv_sec += fish_directory_timeout; 
    367     quoted_path = name_quote (remote_path, 0); 
     380    quoted_path = mhl_shell_escape_dup (remote_path); 
    368381    fish_command (me, super, NONE, 
    369             "#LIST /%s\n" 
    370             "if ls -1 /%s >/dev/null 2>&1 ;\n" 
    371             "then\n" 
    372             "ls -lLan /%s 2>/dev/null | grep '^[^cbt]' | (\n" 
    373               "while read p l u g s m d y n; do\n" 
    374                 "echo \"P$p $u.$g\nS$s\nd$m $d $y\n:$n\n\"\n" 
    375               "done\n" 
    376             ")\n" 
    377             "ls -lan /%s 2>/dev/null | grep '^[cb]' | (\n" 
    378               "while read p l u g a i m d y n; do\n" 
    379                 "echo \"P$p $u.$g\nE$a$i\nd$m $d $y\n:$n\n\"\n" 
    380               "done\n" 
    381             ")\n" 
    382             "echo '### 200'\n" 
    383             "else\n" 
    384             "echo '### 500'\n" 
    385             "fi\n", 
    386             remote_path, quoted_path, quoted_path, quoted_path); 
    387     g_free (quoted_path); 
     382                "#LIST /%s\n" 
     383                "if `perl -v > /dev/null 2>&1` ; then\n" 
     384                  "perl -e '\n" 
     385                   "use strict;\n" 
     386                   "use POSIX;\n" 
     387                   "use Fcntl;\n" 
     388                   "use POSIX \":fcntl_h\"; #S_ISLNK was here until 5.6\n" 
     389                   "import Fcntl \":mode\" unless defined &S_ISLNK; #and is now here\n" 
     390                   "my $dirname = $ARGV[0];\n" 
     391                   "if (opendir ( DIR, $dirname )) {\n" 
     392                   "while( (my $filename = readdir(DIR))){\n" 
     393                   "my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = lstat(\"$dirname/$filename\");\n" 
     394                   "my $mloctime= scalar localtime $mtime;\n" 
     395                   "\n" 
     396                   "# shell escs are taken from here: http://www.slac.stanford.edu/slac/www/resource/how-to-use/cgi-rexx/cgi-esc.html\n" 
     397                   "  sub esc_shell_chars {\n" 
     398                   "     my $s = $_[0];\n" 
     399                   "     $s =~ s/([;<>\\*\\|`&\\$!#\\(\\)\\[\\]\\{\\}:'\\''\"\\ \\\\])/\\\\$1/g;\n" 
     400                   "     return $s;\n" 
     401                   "  }\n" 
     402                   "\n" 
     403                   "my $e_filename = esc_shell_chars($filename);\n" 
     404                   "if (S_ISLNK($mode) ) {\n" 
     405                   "my $linkname = readlink (\"$dirname/$filename\");\n" 
     406                   "my $e_linkname = esc_shell_chars($linkname);\n" 
     407                   "\n" 
     408                          "printf(\"R%%o %%o $uid.$gid\\n" 
     409                                    "S$size\\n" 
     410                                    "d$mloctime\\n" 
     411                                    ":\\\"$e_filename\\\" -> \\\"$e_linkname\\\"\\n" 
     412                                    "\\n\", S_IMODE($mode), S_IFMT($mode));\n" 
     413                   "} else {\n" 
     414                          "printf(\"R%%o %%o $uid.$gid\\n" 
     415                                    "S$size\\n" 
     416                                    "d$mloctime\\n" 
     417                                    ":\\\"$e_filename\\\"\\n" 
     418                                    "\\n\", S_IMODE($mode), S_IFMT($mode));\n" 
     419                   "}}\n" 
     420                   "printf(\"### 200\\n\");\n" 
     421                   "closedir(DIR);\n" 
     422                   "} else {\n" 
     423                    "printf(\"### 500\\n\");\n" 
     424                   "}\n" 
     425                   "exit 0\n" 
     426                   "' /%s ||\n" /* ARGV[0] - path to browse */ 
     427                   "    echo '### 500'\n" /* do not hang if perl is to eval it */ 
     428                "elif `ls -1 /%s >/dev/null 2>&1` ; then\n" 
     429                  "if `ls -Q /%s >/dev/null 2>&1`; then\n" 
     430                          "LSOPT=\"-Qlan\";\n" 
     431                          "ADD=0;\n" 
     432                  "else\n" 
     433                          "LSOPT=\"-lan\";\n" 
     434                          "ADD=1;\n" 
     435                  "fi\n" 
     436                  "ls $LSOPT \"/%s\" 2>/dev/null | grep '^[^cbt]' | (\n" 
     437                          "while read p l u g s m d y n; do\n" 
     438                                  "if [ $ADD  = 0 ]; then\n" 
     439                                          "echo \"P$p $u.$g\nS$s\nd$m $d $y\n:$n\n\"\n" 
     440                                  "elif `sed --version >/dev/null 2>&1` ; then\n" 
     441                                          "file=`echo $n | sed -e 's#^\\(.*\\) -> \\(.*\\)#\\1\" -> \"\\2#'`\n" 
     442                                          "echo \"P$p $u $g\nS$s\nd$m $d $y\n:\"$file\"\n\"\n" 
     443                                  "else\n" 
     444                                          "echo \"P$p $u $g\nS$s\nd$m $d $y\n:\"$n\"\n\"\n" 
     445                                  "fi\n" 
     446                          "done )\n" 
     447                  "ls $LSOPT /%s 2>/dev/null | grep '^[cb]' | (\n" 
     448                          "while read p l u g a i m d y n; do\n" 
     449                                  "if [ $ADD = 0 ]; then\n" 
     450                                          "echo \"P$p $u.$g\nE$a$i\nd$m $d $y\n:$n\n\"\n" 
     451                                  "elif `sed --version >/dev/null 2>&1` ; then\n" 
     452                                          "file=`echo $n | sed -e 's#^\\(.*\\) -> \\(.*\\)#\\1\" -> \"\\2#'`\n" 
     453                                          "echo \"P$p $u $g\nS$s\nd$m $d $y\n:\"$file\"\n\"\n" 
     454                                  "else\n" 
     455                                          "echo \"P$p $u $g\nS$s\nd$m $d $y\n:\"$n\"\n\"\n" 
     456                                  "fi\n" 
     457                          "done)\n" 
     458                  "echo '### 200'\n" 
     459        "else\n" 
     460                  "echo '### 500'\n" 
     461        "fi\n", 
     462            quoted_path, quoted_path, quoted_path, quoted_path, quoted_path, quoted_path); 
     463    mhl_mem_free (quoted_path); 
    388464    ent = vfs_s_generate_entry(me, NULL, dir, 0); 
    389465    while (1) { 
    390466        int res = vfs_s_get_line_interruptible (me, buffer, sizeof (buffer), SUP.sockr);  
    fish_dir_load(struct vfs_class *me, struct vfs_s_inode *dir, char *remote_path) 
    412488 
    413489        switch(buffer[0]) { 
    414490        case ':': { 
    415                       if (!strcmp(buffer+1, ".") || !strcmp(buffer+1, "..")) 
    416                           break;  /* We'll do . and .. ourself */ 
    417                       ent->name = g_strdup(buffer+1);  
    418                       break; 
    419                   } 
     491            char *data_start = buffer+1; 
     492            char *filename = data_start; 
     493            char *linkname = data_start; 
     494            char *filename_bound = filename + strlen(filename); 
     495            char *linkname_bound = filename_bound; 
     496            if (!strcmp(data_start, "\".\"") || !strcmp(data_start, "\"..\"")) 
     497                        break;  /* We'll do "." and ".." ourselves */ 
     498 
     499                if (S_ISLNK(ST.st_mode)) { 
     500                        // we expect: "escaped-name" -> "escaped-name" 
     501                        //     -> cannot occur in filenames, 
     502                        //     because it will be escaped to -\> 
     503 
     504                        if (*filename == '"') 
     505                                ++filename; 
     506 
     507                        linkname = strstr(filename, "\" -> \""); 
     508                        if (!linkname) 
     509                        { 
     510                                /* broken client, or smth goes wrong */ 
     511                                linkname = filename_bound; 
     512                                if (filename_bound > filename 
     513                                    && *(filename_bound - 1) == '"') 
     514                                        --filename_bound; // skip trailing " 
     515                        } 
     516                        else 
     517                        { 
     518                                filename_bound = linkname; 
     519                                linkname += 6; // strlen ("\" -> \"") 
     520                                if (*(linkname_bound - 1) == '"') 
     521                                        --linkname_bound; // skip trailing " 
     522                        } 
     523 
     524                        ent->name = mhl_str_dup_range(filename, filename_bound); 
     525                        mhl_shell_unescape_buf(ent->name); 
     526 
     527                        ent->ino->linkname = mhl_str_dup_range(linkname, linkname_bound); 
     528                        mhl_shell_unescape_buf(ent->ino->linkname); 
     529                } else { 
     530                        // we expect: "escaped-name" 
     531                        if (filename_bound - filename > 2) 
     532                        { 
     533                                // there is at least 2 " 
     534                                // and we skip them 
     535                                if (*filename == '"') 
     536                                        ++filename; 
     537                                if (*(filename_bound - 1) == '"') 
     538                                        --filename_bound; 
     539                        } 
     540 
     541                        ent->name = mhl_str_dup_range(filename, filename_bound); 
     542                        mhl_shell_unescape_buf(ent->name); 
     543                } 
     544                break; 
     545        } 
    420546        case 'S': 
    421547#ifdef HAVE_ATOLL 
    422548            ST.st_size = (off_t) atoll (buffer+1); 
    fish_dir_load(struct vfs_class *me, struct vfs_s_inode *dir, char *remote_path) 
    426552            break; 
    427553        case 'P': { 
    428554            size_t skipped; 
    429  
    430             if (vfs_parse_filemode (buffer + 1, &skipped, &ST.st_mode)) { 
    431                 if (S_ISLNK(ST.st_mode)) 
    432                     ST.st_mode = 0; 
    433             } 
     555            vfs_parse_filemode (buffer + 1, &skipped, &ST.st_mode); 
     556            break; 
     557        } 
     558        case 'R': { 
     559            // raw filemode: 
     560            // we expect: Roctal-filemode octal-filetype uid.gid 
     561            size_t skipped; 
     562            vfs_parse_raw_filemode (buffer + 1, &skipped, &ST.st_mode); 
    434563            break; 
    435564        } 
    436565        case 'd': { 
    fish_dir_load(struct vfs_class *me, struct vfs_s_inode *dir, char *remote_path) 
    456585                      ST.st_rdev = makedev (maj, min); 
    457586#endif 
    458587                  } 
    459         case 'L': ent->ino->linkname = g_strdup(buffer+1); 
    460                   break; 
    461588        } 
    462589    } 
    463590     
    fish_file_store(struct vfs_class *me, struct vfs_s_fh *fh, char *name, char *loc 
    528655     *  algorithm for file appending case, therefore just "dd" is used for it. 
    529656     */ 
    530657 
    531     print_vfs_message(_("fish: store %s: sending command..."), name ); 
    532     quoted_name = name_quote (name, 0); 
     658    quoted_name = mhl_shell_escape_dup(name); 
     659    print_vfs_message(_("fish: store %s: sending command..."), quoted_name ); 
    533660 
    534661    /* FIXME: File size is limited to ULONG_MAX */ 
    535662    if (!fh->u.fish.append) 
    fish_file_store(struct vfs_class *me, struct vfs_s_fh *fh, char *name, char *loc 
    541668                 "(\n" 
    542669                   "head -c %lu -q - || echo DD >&3\n" 
    543670                 ") 2>/dev/null | (\n" 
    544                    "cat > \"$file\"\n" 
     671                   "cat > $file\n" 
    545672                   "cat > /dev/null\n" 
    546673                 ")`; [ \"$res\" = DD ] && {\n" 
    547674                        "> \"$file\"\n" 
    fish_file_store(struct vfs_class *me, struct vfs_s_fh *fh, char *name, char *loc 
    553680                        "    rest=`expr $rest - $n`\n" 
    554681                        "done\n" 
    555682                 "}; echo '### 200'\n", 
    556                  (unsigned long) s.st_size, name, 
     683                 (unsigned long) s.st_size, quoted_name, 
    557684                 quoted_name, (unsigned long) s.st_size, 
    558685                 (unsigned long) s.st_size); 
    559686    else 
    fish_file_store(struct vfs_class *me, struct vfs_s_fh *fh, char *name, char *loc 
    566693                        "while [ $rest -gt 0 ]\n" 
    567694                        "do\n" 
    568695                        "    cnt=`expr \\( $rest + 255 \\) / 256`\n" 
    569                         "    n=`dd bs=256 count=$cnt | tee -a \"$file\" | wc -c`\n" 
     696                        "    n=`dd bs=256 count=$cnt | tee -a $file | wc -c`\n" 
    570697                        "    rest=`expr $rest - $n`\n" 
    571698                        "done\n" 
    572699                 "}; echo '### 200'\n", 
    573                  (unsigned long) s.st_size, name, 
     700                 (unsigned long) s.st_size, quoted_name, 
    574701                 quoted_name, (unsigned long) s.st_size); 
    575702 
    576     g_free (quoted_name); 
    577703    if (n != PRELIM) { 
    578704        close (h); 
    579705        ERRNOR(E_REMOTE, -1); 
    fish_file_store(struct vfs_class *me, struct vfs_s_fh *fh, char *name, char *loc 
    606732                          (unsigned long) s.st_size); 
    607733    } 
    608734    close(h); 
     735    mhl_mem_free(quoted_name); 
    609736    if ((fish_get_reply (me, SUP.sockr, NULL, 0) != COMPLETE) || was_error) 
    610737        ERRNOR (E_REMOTE, -1); 
    611738    return 0; 
    612739error_return: 
    613740    close(h); 
    614741    fish_get_reply(me, SUP.sockr, NULL, 0); 
     742    mhl_mem_free(quoted_name); 
    615743    return -1; 
    616744} 
    617745 
    fish_linear_start (struct vfs_class *me, struct vfs_s_fh *fh, off_t offset) 
    625753    name = vfs_s_fullpath (me, fh->ino); 
    626754    if (!name) 
    627755        return 0; 
    628     quoted_name = name_quote (name, 0); 
    629     g_free (name); 
    630     name = quoted_name; 
     756    quoted_name = mhl_shell_escape_dup(name); 
    631757    fh->u.fish.append = 0; 
    632758 
    633759    /* 
    fish_linear_start (struct vfs_class *me, struct vfs_s_fh *fh, off_t offset) 
    642768                "then\n" 
    643769                "ls -ln /%s 2>/dev/null | (\n" 
    644770                  "read p l u g s r\n" 
    645                   "echo \"$s\"\n" 
     771                  "echo $s\n" 
    646772                ")\n" 
    647773                "echo '### 100'\n" 
    648774                "cat /%s\n" 
    649775                "echo '### 200'\n" 
    650776                "else\n" 
    651                 "echo '### 500'\n"  
     777                "echo '### 500'\n" 
    652778                "fi\n", 
    653                 name, name, name, name ); 
    654     g_free (name); 
     779                quoted_name, quoted_name, quoted_name, quoted_name ); 
     780    g_free (quoted_name); 
    655781    if (offset != PRELIM) ERRNOR (E_REMOTE, 0); 
    656782    fh->linear = LS_LINEAR_OPEN; 
    657783    fh->u.fish.got = 0; 
    fish_send_command(struct vfs_class *me, struct vfs_s_super *super, const char *c 
    766892        g_free (mpath); \ 
    767893        return -1; \ 
    768894    } \ 
    769     rpath = name_quote (crpath, 0); \ 
     895    rpath = mhl_shell_escape_dup(crpath); \ 
    770896    g_free (mpath); 
    771897 
    772898#define POSTFIX(flags) \ 
    fish_chmod (struct vfs_class *me, const char *path, int mode) 
    778904{ 
    779905    PREFIX 
    780906    g_snprintf(buf, sizeof(buf), "#CHMOD %4.4o /%s\n" 
    781                                  "chmod %4.4o \"/%s\" 2>/dev/null\n" 
     907                                 "chmod %4.4o /%s 2>/dev/null\n" 
    782908                                 "echo '### 000'\n",  
    783909            mode & 07777, rpath, 
    784910            mode & 07777, rpath); 
    static int fish_##name (struct vfs_class *me, const char *path1, const char *pat 
    801927        g_free (mpath2); \ 
    802928        return -1; \ 
    803929    } \ 
    804     rpath1 = name_quote (crpath1, 0); \ 
     930    rpath1 = mhl_shell_escape_dup (crpath1); \ 
    805931    g_free (mpath1); \ 
    806     rpath2 = name_quote (crpath2, 0); \ 
     932    rpath2 = mhl_shell_escape_dup (crpath2); \ 
    807933    g_free (mpath2); \ 
    808934    g_snprintf(buf, sizeof(buf), string "\n", rpath1, rpath2, rpath1, rpath2); \ 
    809     g_free (rpath1); \ 
    810     g_free (rpath2); \ 
     935    mhl_mem_free (rpath1); \ 
     936    mhl_mem_free (rpath2); \ 
    811937    return fish_send_command(me, super2, buf, OPT_FLUSH); \ 
    812938} 
    813939 
    static int fish_symlink (struct vfs_class *me, const char *setto, const char *pa 
    822948{ 
    823949    char *qsetto; 
    824950    PREFIX 
    825     qsetto = name_quote (setto, 0); 
     951    qsetto = mhl_shell_escape_dup (setto); 
    826952    g_snprintf(buf, sizeof(buf), 
    827953            "#SYMLINK %s /%s\n" 
    828954            "ln -s %s /%s 2>/dev/null\n" 
    829955            "echo '### 000'\n", 
    830956            qsetto, rpath, qsetto, rpath); 
    831     g_free (qsetto); 
     957    mhl_mem_free (qsetto); 
    832958    POSTFIX(OPT_FLUSH); 
    833959} 
    834960 
    fish_chown (struct vfs_class *me, const char *path, int owner, int group) 
    850976    { 
    851977        PREFIX 
    852978        g_snprintf (buf, sizeof(buf), 
    853             "#CHOWN /%s /%s\n" 
     979            "#CHOWN %s /%s\n" 
    854980            "chown %s /%s 2>/dev/null\n" 
    855981            "echo '### 000'\n",  
    856982            sowner, rpath, 
    fish_chown (struct vfs_class *me, const char *path, int owner, int group) 
    858984        fish_send_command (me, super, buf, OPT_FLUSH);  
    859985        /* FIXME: what should we report if chgrp succeeds but chown fails? */ 
    860986        g_snprintf (buf, sizeof(buf), 
    861             "#CHGRP /%s /%s\n" 
    862             "chgrp %s /%s 2>/dev/null\n" 
     987            "#CHGRP /%s \"/%s\"\n" 
     988            "chgrp %s \"/%s\" 2>/dev/null\n" 
    863989            "echo '### 000'\n",  
    864990            sgroup, rpath, 
    865991            sgroup, rpath); 
  • vfs/utilvfs.c

    diff --git a/vfs/utilvfs.c b/vfs/utilvfs.c
    index 8284c8a..a2000a7 100644
    a b vfs_parse_filemode (const char *s, size_t *ret_skipped, 
    539539    return TRUE; 
    540540} 
    541541 
     542gboolean 
     543vfs_parse_raw_filemode (const char *s, size_t *ret_skipped, 
     544                    mode_t *ret_mode) 
     545{ 
     546    const char *p; 
     547    mode_t remote_type = 0, local_type, perms = 0; 
     548 
     549    p = s; 
     550 
     551    // isoctal 
     552    while(*p >= '0' && *p <= '7') 
     553    { 
     554        perms *= 010; 
     555        perms += (*p - '0'); 
     556        ++p; 
     557    } 
     558 
     559    if (*p++ != ' ') 
     560        return FALSE; 
     561 
     562    while(*p >= '0' && *p <= '7') 
     563    { 
     564        remote_type *= 010; 
     565        remote_type += (*p - '0'); 
     566        ++p; 
     567    } 
     568 
     569    if (*p++ != ' ') 
     570        return FALSE; 
     571 
     572    /* generated with: 
     573        $ perl -e 'use Fcntl ":mode"; 
     574                   my @modes = (S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFREG); 
     575                   foreach $t (@modes) { printf ("%o\n", $t); };' 
     576        TODO: S_IFDOOR, S_IFIFO, S_IFSOCK (if supported by os) 
     577              (see vfs_parse_filetype) 
     578     */ 
     579 
     580    switch (remote_type) 
     581    { 
     582        case 020000: 
     583            local_type = S_IFCHR; break; 
     584        case 040000: 
     585            local_type = S_IFDIR; break; 
     586        case 060000: 
     587            local_type = S_IFBLK; break; 
     588        case 0120000: 
     589            local_type = S_IFLNK; break; 
     590        case 0100000: 
     591        default:// don't know what is it 
     592            local_type = S_IFREG; break; 
     593    } 
     594 
     595    *ret_skipped = p - s; 
     596    *ret_mode = local_type | perms; 
     597    return TRUE; 
     598} 
     599 
    542600/* This function parses from idx in the columns[] array */ 
    543601int 
    544602vfs_parse_filedate (int idx, time_t *t) 
  • vfs/utilvfs.h

    diff --git a/vfs/utilvfs.h b/vfs/utilvfs.h
    index c920610..d025503 100644
    a b gboolean vfs_parse_fileperms (const char *s, size_t *ret_skipped, 
    2424                              mode_t *ret_perms); 
    2525gboolean vfs_parse_filemode (const char *s, size_t *ret_skipped, 
    2626                             mode_t *ret_mode); 
     27gboolean vfs_parse_raw_filemode (const char *s, size_t *ret_skipped, 
     28                             mode_t *ret_mode); 
    2729 
    2830int vfs_parse_ls_lga (const char *p, struct stat *s, char **filename, 
    2931                      char **linkname);