2 Virtual File System: FTP file system
4 Copyright (C) 2015-2025
5 The Free Software Foundation, Inc.
7 Written by: Andrew Borodin <aborodin@vmail.ru>, 2013
9 This file is part of the Midnight Commander.
11 The Midnight Commander is free software: you can redistribute it
12 and/or modify it under the terms of the GNU General Public License as
13 published by the Free Software Foundation, either version 3 of the License,
14 or (at your option) any later version.
16 The Midnight Commander is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <https://www.gnu.org/licenses/>.
26 * \brief Source: Virtual File System: FTP file system
27 * \author Andrew Borodin
30 * Parser of ftp long file list (reply to "LIST -la" command).
31 * Borrowed from lftp project (https://lftp.yar.ru).
32 * Author of original lftp code: Alexander V. Lukyanov (lav@yars.free.net)
37 #include <ctype.h> // isdigit()
38 #include <stdio.h> // sscanf()
41 #include <sys/stat.h> // mode_t
44 #include <sys/types.h>
46 #include "lib/global.h"
48 #include "lib/vfs/vfs.h"
49 #include "lib/vfs/utilvfs.h"
53 /*** global variables ****************************************************************************/
55 /*** file scope macro definitions ****************************************************************/
57 #define number_of_parsers 7
59 #define NO_SIZE ((off_t) (-1L))
60 #define NO_DATE ((time_t) (-1L))
62 #define FIRST_TOKEN strtok (line, " \t")
63 #define NEXT_TOKEN strtok (NULL, " \t")
64 #define FIRST_TOKEN_R strtok_r (line, " \t", &next)
65 #define NEXT_TOKEN_R strtok_r (NULL, " \t", &next)
75 /*** file scope type declarations ****************************************************************/
85 typedef gboolean (*ftpfs_line_parser
) (char *line
, struct stat
*s
, char **filename
, char **linkname
,
88 /*** forward declarations (file scope functions) *************************************************/
90 static gboolean
ftpfs_parse_long_list_UNIX (char *line
, struct stat
*s
, char **filename
,
91 char **linkname
, int *err
);
92 static gboolean
ftpfs_parse_long_list_NT (char *line
, struct stat
*s
, char **filename
,
93 char **linkname
, int *err
);
94 static gboolean
ftpfs_parse_long_list_EPLF (char *line
, struct stat
*s
, char **filename
,
95 char **linkname
, int *err
);
96 static gboolean
ftpfs_parse_long_list_MLSD (char *line
, struct stat
*s
, char **filename
,
97 char **linkname
, int *err
);
98 static gboolean
ftpfs_parse_long_list_AS400 (char *line
, struct stat
*s
, char **filename
,
99 char **linkname
, int *err
);
100 static gboolean
ftpfs_parse_long_list_OS2 (char *line
, struct stat
*s
, char **filename
,
101 char **linkname
, int *err
);
102 static gboolean
ftpfs_parse_long_list_MacWebStar (char *line
, struct stat
*s
, char **filename
,
103 char **linkname
, int *err
);
105 /*** file scope variables ************************************************************************/
107 static time_t rawnow
;
108 static struct tm now
;
110 static ftpfs_line_parser line_parsers
[number_of_parsers
] = {
111 ftpfs_parse_long_list_UNIX
, ftpfs_parse_long_list_NT
, ftpfs_parse_long_list_EPLF
,
112 ftpfs_parse_long_list_MLSD
, ftpfs_parse_long_list_AS400
, ftpfs_parse_long_list_OS2
,
113 ftpfs_parse_long_list_MacWebStar
116 /* --------------------------------------------------------------------------------------------- */
117 /*** file scope functions ************************************************************************/
118 /* --------------------------------------------------------------------------------------------- */
121 ftpfs_get_uid (const char *s
)
125 if (*s
< '0' || *s
> '9')
128 u
= (uid_t
) atol (s
);
133 /* --------------------------------------------------------------------------------------------- */
136 ftpfs_get_gid (const char *s
)
140 if (*s
< '0' || *s
> '9')
143 g
= (gid_t
) atol (s
);
148 /* --------------------------------------------------------------------------------------------- */
151 ftpfs_init_time (void)
154 now
= *localtime (&rawnow
);
157 /* --------------------------------------------------------------------------------------------- */
160 guess_year (int month
, int day
, int hour
, int minute
)
167 year
= now
.tm_year
+ 1900;
169 if (month
* 32 + day
> now
.tm_mon
* 32 + now
.tm_mday
+ 6)
175 /* --------------------------------------------------------------------------------------------- */
178 parse_year_or_time (const char *year_or_time
, int *year
, int *hour
, int *minute
)
180 if (year_or_time
[2] == ':')
182 if (sscanf (year_or_time
, "%2d:%2d", hour
, minute
) != 2)
189 if (sscanf (year_or_time
, "%d", year
) != 1)
198 /* --------------------------------------------------------------------------------------------- */
200 /* Converts struct tm to time_t, assuming the data in tm is UTC rather
201 than local timezone (mktime assumes the latter).
203 Contributed by Roger Beeman <beeman@cisco.com>, with the help of
204 Mark Baushke <mdb@cisco.com> and the rest of the Gurus at CISCO. */
206 mktime_from_utc (const struct tm
*t
)
211 memcpy (&tc
, t
, sizeof (struct tm
));
213 /* UTC times are never DST; if we say -1, we'll introduce odd localtime-
214 * dependent errors. */
222 tb
= mktime (gmtime (&tl
));
224 return (tl
<= tb
? (tl
+ (tl
- tb
)) : (tl
- (tb
- tl
)));
227 /* --------------------------------------------------------------------------------------------- */
230 ftpfs_convert_date (const char *s
)
233 int year
, month
, day
, hour
, minute
, second
;
237 memset (&tm
, 0, sizeof (tm
));
239 n
= sscanf (s
, "%4d%n", &year
, &skip
);
241 /* try to workaround server's y2k bug *
242 * I hope in the next 300 years the y2k bug will be finally fixed :) */
243 if (n
== 1 && year
>= 1910 && year
<= 1930)
245 n
= sscanf (s
, "%5d%n", &year
, &skip
);
246 year
= year
- 19100 + 2000;
252 n
= sscanf (s
+ skip
, "%2d%2d%2d%2d%2d", &month
, &day
, &hour
, &minute
, &second
);
257 tm
.tm_year
= year
- 1900;
258 tm
.tm_mon
= month
- 1;
264 return mktime_from_utc (&tm
);
267 /* --------------------------------------------------------------------------------------------- */
270 -rwxr-xr-x 1 lav root 4771 Sep 12 1996 install-sh
271 -rw-r--r-- 1 lav root 1349 Feb 2 14:10 lftp.lsm
272 drwxr-xr-x 4 lav root 1024 Feb 22 15:32 lib
273 lrwxrwxrwx 1 lav root 33 Feb 14 17:45 ltconfig -> /usr/share/libtool/ltconfig
275 NOTE: group may be missing.
279 parse_ls_line (char *line
, struct stat
*s
, char **filename
, char **linkname
)
283 mode_t type
, mode
= 0;
286 const char *day_of_month
;
287 gboolean year_anomaly
= FALSE
;
295 if (!vfs_parse_filetype (t
, NULL
, &type
))
298 if (vfs_parse_fileperms (t
+ 1, NULL
, &mode
))
307 s
->st_nlink
= atol (t
);
314 s
->st_uid
= ftpfs_get_uid (t
);
317 group_or_size
= NEXT_TOKEN_R
;
323 if (isdigit ((unsigned char) *t
))
325 // it's size, so the previous was group:
329 s
->st_gid
= ftpfs_get_gid (group_or_size
);
331 if (sscanf (t
, "%lld%n", &size
, &n
) == 1 && t
[n
] == '\0')
332 s
->st_size
= (off_t
) size
;
339 // it was month, so the previous was size:
343 if (sscanf (group_or_size
, "%lld%n", &size
, &n
) == 1 && group_or_size
[n
] == '\0')
344 s
->st_size
= (off_t
) size
;
347 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
350 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
351 s
->st_blocks
= (s
->st_size
+ 511) / 512;
354 memset (&date
, 0, sizeof (date
));
356 if (!vfs_parse_month (t
, &date
))
359 day_of_month
= NEXT_TOKEN_R
;
360 if (day_of_month
== NULL
)
362 date
.tm_mday
= atoi (day_of_month
);
369 date
.tm_hour
= date
.tm_min
= 0;
372 if (sscanf (t
, "%2d:%2d", &date
.tm_hour
, &date
.tm_min
) == 2)
373 date
.tm_year
= guess_year (date
.tm_mon
, date
.tm_mday
, date
.tm_hour
, date
.tm_min
) - 1900;
376 if (day_of_month
+ strlen (day_of_month
) + 1 == t
)
378 date
.tm_year
= atoi (t
) - 1900;
379 /* We don't know the hour. Set it to something other than 0, or
380 * DST -1 will end up changing the date. */
386 s
->st_mtime
= mktime (&date
);
387 // Use resulting time value
388 s
->st_atime
= s
->st_ctime
= s
->st_mtime
;
390 name
= strtok_r (NULL
, "", &next
);
394 // there are ls which output extra space after year
395 if (year_anomaly
&& *name
== ' ')
398 if (!S_ISLNK (s
->st_mode
))
404 for (arrow
= name
; (arrow
= strstr (arrow
, " -> ")) != NULL
; arrow
++)
405 if (arrow
!= name
&& arrow
[4] != '\0')
408 *linkname
= g_strdup (arrow
+ 4);
413 *filename
= g_strdup (name
);
418 /* --------------------------------------------------------------------------------------------- */
421 ftpfs_parse_long_list_UNIX (char *line
, struct stat
*s
, char **filename
, char **linkname
, int *err
)
426 if (sscanf (line
, "total %d", &tmp
) == 1)
429 if (strncasecmp (line
, "Status of ", 10) == 0)
430 return FALSE
; // STAT output
432 ret
= parse_ls_line (line
, s
, filename
, linkname
);
439 /* --------------------------------------------------------------------------------------------- */
442 07-13-98 09:06PM <DIR> aix
443 07-13-98 09:06PM <DIR> hpux
444 07-13-98 09:06PM <DIR> linux
445 07-13-98 09:06PM <DIR> ncr
446 07-13-98 09:06PM <DIR> solaris
447 03-18-98 06:01AM 2109440 nlxb318e.tar
448 07-02-98 11:17AM 13844 Whatsnew.txt
452 ftpfs_parse_long_list_NT (char *line
, struct stat
*s
, char **filename
, char **linkname
, int *err
)
455 int month
, day
, year
, hour
, minute
;
463 if (sscanf (t
, "%2d-%2d-%2d", &month
, &day
, &year
) != 3)
473 am
= 'A'; // AM/PM is optional
474 if (sscanf (t
, "%2d:%2d%c", &hour
, &minute
, &am
) < 2)
481 if (am
== 'P') // PM - after noon
488 tms
.tm_sec
= 30; // seconds after the minute [0, 61]
489 tms
.tm_min
= minute
; // minutes after the hour [0, 59]
490 tms
.tm_hour
= hour
; // hour since midnight [0, 23]
491 tms
.tm_mday
= day
; // day of the month [1, 31]
492 tms
.tm_mon
= month
- 1; // months since January [0, 11]
493 tms
.tm_year
= year
- 1900; // years since 1900
496 s
->st_mtime
= mktime (&tms
);
497 // Use resulting time value
498 s
->st_atime
= s
->st_ctime
= s
->st_mtime
;
500 if (strcmp (t
, "<DIR>") == 0)
501 s
->st_mode
= S_IFDIR
;
504 s
->st_mode
= S_IFREG
;
505 if (sscanf (t
, "%lld", &size
) != 1)
507 s
->st_size
= (off_t
) size
;
510 t
= strtok (NULL
, "");
518 *filename
= g_strdup (t
);
524 /* --------------------------------------------------------------------------------------------- */
527 +i774.71425,m951188401,/, users
528 +i774.49602,m917883130,r,s79126, jgr_www2.exe
532 first character of field is type:
534 m - modification time
538 up - permissions in octal
539 \t - file name follows.
543 ftpfs_parse_long_list_EPLF (char *line
, struct stat
*s
, char **filename
, char **linkname
, int *err
)
547 const char *name
= NULL
;
549 off_t size
= NO_SIZE
;
550 time_t date
= NO_DATE
;
553 gboolean dir
= FALSE
;
554 gboolean type_known
= FALSE
;
562 if (len
< 2 || b
[0] != '+')
568 while (scan
!= NULL
&& scan_len
> 0)
574 case '\t': // the rest is file name
576 name_len
= scan_len
- 1;
580 if (sscanf (scan
+ 1, "%lld", &size_ll
) != 1)
585 if (sscanf (scan
+ 1, "%ld", &date_l
) != 1)
600 if (scan
[1] == 'p') // permissions
601 if (sscanf (scan
+ 2, "%o", (unsigned int *) &perms
) != 1)
609 if (scan
== NULL
|| scan_len
== 0)
612 comma
= (const char *) memchr (scan
, ',', scan_len
);
616 scan_len
-= comma
+ 1 - scan
;
620 if (name
== NULL
|| !type_known
)
623 *filename
= g_strndup (name
, name_len
);
631 // Use resulting time value
632 s
->st_atime
= s
->st_ctime
= s
->st_mtime
;
635 s
->st_mode
= dir
? S_IFDIR
: S_IFREG
;
637 s
->st_mode
|= perms
; // FIXME
642 /* --------------------------------------------------------------------------------------------- */
644 Type=cdir;Modify=20021029173810;Perm=el;Unique=BP8AAjJufAA; /
645 Type=pdir;Modify=20021029173810;Perm=el;Unique=BP8AAjJufAA; ..
646 Type=dir;Modify=20010118144705;Perm=e;Unique=BP8AAjNufAA; bin
647 Type=dir;Modify=19981021003019;Perm=el;Unique=BP8AAlhufAA; pub
648 Type=file;Size=12303;Modify=19970124132601;Perm=r;Unique=BP8AAo9ufAA; mailserv.FAQ
649 modify=20161215062118;perm=flcdmpe;type=dir;UNIX.group=503;UNIX.mode=0700; directory-name
650 modify=20161213121618;perm=adfrw;size=6369064;type=file;UNIX.group=503;UNIX.mode=0644; file-name
651 modify=20120103123744;perm=adfrw;size=11;type=OS.unix=symlink;UNIX.group=0;UNIX.mode=0777; www
655 ftpfs_parse_long_list_MLSD (char *line
, struct stat
*s
, char **filename
, char **linkname
, int *err
)
657 const char *name
= NULL
;
658 off_t size
= NO_SIZE
;
659 time_t date
= NO_DATE
;
660 const char *owner
= NULL
;
661 const char *group
= NULL
;
662 filetype type
= UNKNOWN
;
667 space
= strstr (line
, "; ");
675 // NcFTPd does not put a semicolon after last fact, workaround it
676 space
= strchr (line
, ' ');
683 for (tok
= strtok (line
, ";"); tok
!= NULL
; tok
= strtok (NULL
, ";"))
685 if (strcasecmp (tok
, "Type=cdir") == 0 || strcasecmp (tok
, "Type=pdir") == 0
686 || strcasecmp (tok
, "Type=dir") == 0)
691 if (strcasecmp (tok
, "Type=file") == 0)
696 if (strcasecmp (tok
, "Type=OS.unix=symlink") == 0)
701 if (strncasecmp (tok
, "Modify=", 7) == 0)
703 date
= ftpfs_convert_date (tok
+ 7);
706 if (strncasecmp (tok
, "Size=", 5) == 0)
710 if (sscanf (tok
+ 5, "%lld", &size_ll
) == 1)
714 if (strncasecmp (tok
, "Perm=", 5) == 0)
717 for (tok
+= 5; *tok
!= '\0'; tok
++)
719 switch (g_ascii_tolower (*tok
))
742 if (strncasecmp (tok
, "UNIX.mode=", 10) == 0)
744 if (sscanf (tok
+ 10, "%o", (unsigned int *) &perms
) != 1)
748 if (strncasecmp (tok
, "UNIX.owner=", 11) == 0)
753 if (strncasecmp (tok
, "UNIX.group=", 11) == 0)
758 if (strncasecmp (tok
, "UNIX.uid=", 9) == 0)
764 if (strncasecmp (tok
, "UNIX.gid=", 9) == 0)
771 if (name
== NULL
|| name
[0] == '\0' || type
== UNKNOWN
)
774 *filename
= g_strdup (name
);
782 // Use resulting time value
783 s
->st_atime
= s
->st_ctime
= s
->st_mtime
;
788 s
->st_mode
= S_IFDIR
;
791 s
->st_mode
= S_IFLNK
;
794 s
->st_mode
= S_IFREG
;
797 g_assert_not_reached ();
800 s
->st_mode
|= perms
; // FIXME
802 s
->st_uid
= ftpfs_get_uid (owner
);
804 s
->st_gid
= ftpfs_get_gid (group
);
809 /* --------------------------------------------------------------------------------------------- */
812 ASUSER 8192 04/26/05 13:54:16 *DIR dir/
813 ASUSER 8192 04/26/05 13:57:34 *DIR dir1/
814 ASUSER 365255 02/28/01 15:41:40 *STMF readme.txt
815 ASUSER 8489625 03/18/03 09:37:00 *STMF saved.zip
816 ASUSER 365255 02/28/01 15:41:40 *STMF unist.old
820 ftpfs_parse_long_list_AS400 (char *line
, struct stat
*s
, char **filename
, char **linkname
, int *err
)
825 int month
, day
, year
, hour
, minute
, second
;
839 if (sscanf (t
, "%lld", &size
) != 1)
845 if (sscanf (t
, "%2d/%2d/%2d", &month
, &day
, &year
) != 3)
855 if (sscanf (t
, "%2d:%2d:%2d", &hour
, &minute
, &second
) != 3)
862 tms
.tm_sec
= second
; // seconds after the minute [0, 61]
863 tms
.tm_min
= minute
; // minutes after the hour [0, 59]
864 tms
.tm_hour
= hour
; // hour since midnight [0, 23]
865 tms
.tm_mday
= day
; // day of the month [1, 31]
866 tms
.tm_mon
= month
- 1; // months since January [0, 11]
867 tms
.tm_year
= year
- 1900; // years since 1900
869 mtime
= mktime (&tms
);
874 if (strcmp (t
, "*DIR") == 0)
879 t
= strtok (NULL
, "");
889 slash
= strchr (t
, '/');
897 if (slash
[1] != '\0')
899 *filename
= g_strdup (t
);
900 s
->st_mode
= type
; // FIXME
905 *filename
= g_strdup (t
);
907 s
->st_size
= (off_t
) size
;
909 // Use resulting time value
910 s
->st_atime
= s
->st_ctime
= s
->st_mtime
;
911 s
->st_uid
= ftpfs_get_uid (user
);
916 /* --------------------------------------------------------------------------------------------- */
919 0 DIR 06-27-96 11:57 PROTOCOL
920 169 11-29-94 09:20 SYSLEVEL.MPT
924 ftpfs_parse_long_list_OS2 (char *line
, struct stat
*s
, char **filename
, char **linkname
, int *err
)
928 int month
, day
, year
, hour
, minute
;
935 if (sscanf (t
, "%lld", &size
) != 1)
937 s
->st_size
= (off_t
) size
;
942 s
->st_mode
= S_IFREG
;
943 if (strcmp (t
, "DIR") == 0)
945 s
->st_mode
= S_IFDIR
;
952 if (sscanf (t
, "%2d-%2d-%2d", &month
, &day
, &year
) != 3)
962 if (sscanf (t
, "%2d:%2d", &hour
, &minute
) != 3)
965 tms
.tm_sec
= 30; // seconds after the minute [0, 61]
966 tms
.tm_min
= minute
; // minutes after the hour [0, 59]
967 tms
.tm_hour
= hour
; // hour since midnight [0, 23]
968 tms
.tm_mday
= day
; // day of the month [1, 31]
969 tms
.tm_mon
= month
- 1; // months since January [0, 11]
970 tms
.tm_year
= year
- 1900; // years since 1900
972 s
->st_mtime
= mktime (&tms
);
973 // Use resulting time value
974 s
->st_atime
= s
->st_ctime
= s
->st_mtime
;
976 t
= strtok (NULL
, "");
983 *filename
= g_strdup (t
);
989 /* --------------------------------------------------------------------------------------------- */
992 ftpfs_parse_long_list_MacWebStar (char *line
, struct stat
*s
, char **filename
, char **linkname
,
998 const char *day_of_month
;
1005 if (!vfs_parse_filetype (t
, NULL
, &type
))
1010 if (!vfs_parse_fileperms (t
+ 1, NULL
, &mode
))
1012 // permissions are meaningless here
1019 if (strcmp (t
, "folder") != 0)
1031 if (!isdigit ((unsigned char) *t
))
1034 if (sscanf (t
, "%lld", &size
) == 1)
1035 s
->st_size
= (off_t
) size
;
1050 memset (&date
, 0, sizeof (date
));
1052 if (!vfs_parse_month (t
, &date
))
1055 day_of_month
= NEXT_TOKEN
;
1056 if (day_of_month
== NULL
)
1059 date
.tm_mday
= atoi (day_of_month
);
1065 if (!parse_year_or_time (t
, &date
.tm_year
, &date
.tm_hour
, &date
.tm_min
))
1070 if (date
.tm_year
== -1)
1071 date
.tm_year
= guess_year (date
.tm_mon
, date
.tm_mday
, date
.tm_hour
, date
.tm_min
) - 1900;
1075 s
->st_mtime
= mktime (&date
);
1076 // Use resulting time value
1077 s
->st_atime
= s
->st_ctime
= s
->st_mtime
;
1079 name
= strtok (NULL
, "");
1083 // no symlinks on Mac, but anyway
1084 if (!S_ISLNK (s
->st_mode
))
1090 for (arrow
= name
; (arrow
= strstr (arrow
, " -> ")) != NULL
; arrow
++)
1091 if (arrow
!= name
&& arrow
[4] != '\0')
1094 *linkname
= g_strdup (arrow
+ 4);
1099 *filename
= g_strdup (name
);
1104 /* --------------------------------------------------------------------------------------------- */
1105 /*** public functions ****************************************************************************/
1106 /* --------------------------------------------------------------------------------------------- */
1109 ftpfs_parse_long_list (struct vfs_class
*me
, struct vfs_s_inode
*dir
, GSList
*buf
, int *err_ret
)
1111 int err
[number_of_parsers
];
1112 GSList
*set
[number_of_parsers
]; // arrays of struct vfs_s_entry
1115 ftpfs_line_parser guessed_parser
= NULL
;
1116 GSList
**the_set
= NULL
;
1117 int *the_err
= NULL
;
1118 int *best_err1
= &err
[0];
1119 int *best_err2
= &err
[1];
1123 if (err_ret
!= NULL
)
1126 memset (&err
, 0, sizeof (err
));
1127 memset (&set
, 0, sizeof (set
));
1129 for (bufp
= buf
; bufp
!= NULL
; bufp
= g_slist_next (bufp
))
1131 char *b
= (char *) bufp
->data
;
1136 if (b
[blen
- 1] == '\r')
1145 if (guessed_parser
== NULL
)
1147 for (i
= 0; i
< number_of_parsers
; i
++)
1149 struct vfs_s_entry
*info
;
1154 // parser can clobber the line - work on a copy
1155 tmp_line
= g_strndup (b
, blen
);
1157 info
= vfs_s_generate_entry (me
, NULL
, dir
, 0);
1158 nlink
= info
->ino
->st
.st_nlink
;
1159 ok
= (*line_parsers
[i
]) (tmp_line
, &info
->ino
->st
, &info
->name
,
1160 &info
->ino
->linkname
, &err
[i
]);
1161 if (ok
&& strchr (info
->name
, '/') == NULL
)
1163 info
->ino
->st
.st_nlink
= nlink
; // Ouch, we need to preserve our counts :-(
1164 set
[i
] = g_slist_prepend (set
[i
], info
);
1167 vfs_s_free_entry (me
, info
);
1171 if (*best_err1
> err
[i
])
1172 best_err1
= &err
[i
];
1173 if (*best_err2
> err
[i
] && best_err1
!= &err
[i
])
1174 best_err2
= &err
[i
];
1176 if (*best_err1
> 16)
1177 goto leave
; // too many errors with best parser
1180 if (*best_err2
> (*best_err1
+ 1) * 16)
1182 i
= (size_t) (best_err1
- err
);
1183 guessed_parser
= line_parsers
[i
];
1190 struct vfs_s_entry
*info
;
1195 // parser can clobber the line - work on a copy
1196 tmp_line
= g_strndup (b
, blen
);
1198 info
= vfs_s_generate_entry (me
, NULL
, dir
, 0);
1199 nlink
= info
->ino
->st
.st_nlink
;
1200 ok
= guessed_parser (tmp_line
, &info
->ino
->st
, &info
->name
, &info
->ino
->linkname
,
1202 if (ok
&& strchr (info
->name
, '/') == NULL
)
1204 info
->ino
->st
.st_nlink
= nlink
; // Ouch, we need to preserve our counts :-(
1205 *the_set
= g_slist_prepend (*the_set
, info
);
1208 vfs_s_free_entry (me
, info
);
1214 if (the_set
== NULL
)
1216 i
= best_err1
- err
;
1222 for (i
= 0; i
< number_of_parsers
; i
++)
1223 if (&set
[i
] != the_set
)
1225 for (bufp
= set
[i
]; bufp
!= NULL
; bufp
= g_slist_next (bufp
))
1226 vfs_s_free_entry (me
, VFS_ENTRY (bufp
->data
));
1228 g_slist_free (set
[i
]);
1231 if (err_ret
!= NULL
&& the_err
!= NULL
)
1232 *err_ret
= *the_err
;
1234 return the_set
!= NULL
? g_slist_reverse (*the_set
) : NULL
;
1237 /* --------------------------------------------------------------------------------------------- */