2 Virtual File System: FTP file system
4 Copyright (C) 2015-2024
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 <http://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 (http://http://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)
67 #define ERR2 do { (*err)++; return FALSE; } while (FALSE)
69 /*** file scope type declarations ****************************************************************/
79 typedef gboolean (*ftpfs_line_parser
) (char *line
, struct stat
* s
, char **filename
,
80 char **linkname
, int *err
);
82 /*** forward declarations (file scope functions) *************************************************/
84 static gboolean
ftpfs_parse_long_list_UNIX (char *line
, struct stat
*s
, char **filename
,
85 char **linkname
, int *err
);
86 static gboolean
ftpfs_parse_long_list_NT (char *line
, struct stat
*s
, char **filename
,
87 char **linkname
, int *err
);
88 static gboolean
ftpfs_parse_long_list_EPLF (char *line
, struct stat
*s
, char **filename
,
89 char **linkname
, int *err
);
90 static gboolean
ftpfs_parse_long_list_MLSD (char *line
, struct stat
*s
, char **filename
,
91 char **linkname
, int *err
);
92 static gboolean
ftpfs_parse_long_list_AS400 (char *line
, struct stat
*s
, char **filename
,
93 char **linkname
, int *err
);
94 static gboolean
ftpfs_parse_long_list_OS2 (char *line
, struct stat
*s
, char **filename
,
95 char **linkname
, int *err
);
96 static gboolean
ftpfs_parse_long_list_MacWebStar (char *line
, struct stat
*s
, char **filename
,
97 char **linkname
, int *err
);
99 /*** file scope variables ************************************************************************/
101 static time_t rawnow
;
102 static struct tm now
;
104 static ftpfs_line_parser line_parsers
[number_of_parsers
] = {
105 ftpfs_parse_long_list_UNIX
,
106 ftpfs_parse_long_list_NT
,
107 ftpfs_parse_long_list_EPLF
,
108 ftpfs_parse_long_list_MLSD
,
109 ftpfs_parse_long_list_AS400
,
110 ftpfs_parse_long_list_OS2
,
111 ftpfs_parse_long_list_MacWebStar
114 /* --------------------------------------------------------------------------------------------- */
115 /*** file scope functions ************************************************************************/
116 /* --------------------------------------------------------------------------------------------- */
119 ftpfs_get_uid (const char *s
)
123 if (*s
< '0' || *s
> '9')
126 u
= (uid_t
) atol (s
);
131 /* --------------------------------------------------------------------------------------------- */
134 ftpfs_get_gid (const char *s
)
138 if (*s
< '0' || *s
> '9')
141 g
= (gid_t
) atol (s
);
146 /* --------------------------------------------------------------------------------------------- */
149 ftpfs_init_time (void)
152 now
= *localtime (&rawnow
);
155 /* --------------------------------------------------------------------------------------------- */
158 guess_year (int month
, int day
, int hour
, int minute
)
165 year
= now
.tm_year
+ 1900;
167 if (month
* 32 + day
> now
.tm_mon
* 32 + now
.tm_mday
+ 6)
173 /* --------------------------------------------------------------------------------------------- */
176 parse_year_or_time (const char *year_or_time
, int *year
, int *hour
, int *minute
)
178 if (year_or_time
[2] == ':')
180 if (sscanf (year_or_time
, "%2d:%2d", hour
, minute
) != 2)
187 if (sscanf (year_or_time
, "%d", year
) != 1)
196 /* --------------------------------------------------------------------------------------------- */
198 /* Converts struct tm to time_t, assuming the data in tm is UTC rather
199 than local timezone (mktime assumes the latter).
201 Contributed by Roger Beeman <beeman@cisco.com>, with the help of
202 Mark Baushke <mdb@cisco.com> and the rest of the Gurus at CISCO. */
204 mktime_from_utc (const struct tm
*t
)
209 memcpy (&tc
, t
, sizeof (struct tm
));
211 /* UTC times are never DST; if we say -1, we'll introduce odd localtime-
212 * dependent errors. */
220 tb
= mktime (gmtime (&tl
));
222 return (tl
<= tb
? (tl
+ (tl
- tb
)) : (tl
- (tb
- tl
)));
225 /* --------------------------------------------------------------------------------------------- */
228 ftpfs_convert_date (const char *s
)
231 int year
, month
, day
, hour
, minute
, second
;
235 memset (&tm
, 0, sizeof (tm
));
237 n
= sscanf (s
, "%4d%n", &year
, &skip
);
239 /* try to workaround server's y2k bug *
240 * I hope in the next 300 years the y2k bug will be finally fixed :) */
241 if (n
== 1 && year
>= 1910 && year
<= 1930)
243 n
= sscanf (s
, "%5d%n", &year
, &skip
);
244 year
= year
- 19100 + 2000;
250 n
= sscanf (s
+ skip
, "%2d%2d%2d%2d%2d", &month
, &day
, &hour
, &minute
, &second
);
255 tm
.tm_year
= year
- 1900;
256 tm
.tm_mon
= month
- 1;
262 return mktime_from_utc (&tm
);
265 /* --------------------------------------------------------------------------------------------- */
268 -rwxr-xr-x 1 lav root 4771 Sep 12 1996 install-sh
269 -rw-r--r-- 1 lav root 1349 Feb 2 14:10 lftp.lsm
270 drwxr-xr-x 4 lav root 1024 Feb 22 15:32 lib
271 lrwxrwxrwx 1 lav root 33 Feb 14 17:45 ltconfig -> /usr/share/libtool/ltconfig
273 NOTE: group may be missing.
277 parse_ls_line (char *line
, struct stat
*s
, char **filename
, char **linkname
)
281 mode_t type
, mode
= 0;
284 const char *day_of_month
;
285 gboolean year_anomaly
= FALSE
;
293 if (!vfs_parse_filetype (t
, NULL
, &type
))
296 if (vfs_parse_fileperms (t
+ 1, NULL
, &mode
))
305 s
->st_nlink
= atol (t
);
312 s
->st_uid
= ftpfs_get_uid (t
);
315 group_or_size
= NEXT_TOKEN_R
;
321 if (isdigit ((unsigned char) *t
))
323 /* it's size, so the previous was group: */
327 s
->st_gid
= ftpfs_get_gid (group_or_size
);
329 if (sscanf (t
, "%lld%n", &size
, &n
) == 1 && t
[n
] == '\0')
330 s
->st_size
= (off_t
) size
;
337 /* it was month, so the previous was size: */
341 if (sscanf (group_or_size
, "%lld%n", &size
, &n
) == 1 && group_or_size
[n
] == '\0')
342 s
->st_size
= (off_t
) size
;
345 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
348 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
349 s
->st_blocks
= (s
->st_size
+ 511) / 512;
352 memset (&date
, 0, sizeof (date
));
354 if (!vfs_parse_month (t
, &date
))
357 day_of_month
= NEXT_TOKEN_R
;
358 if (day_of_month
== NULL
)
360 date
.tm_mday
= atoi (day_of_month
);
367 date
.tm_hour
= date
.tm_min
= 0;
370 if (sscanf (t
, "%2d:%2d", &date
.tm_hour
, &date
.tm_min
) == 2)
371 date
.tm_year
= guess_year (date
.tm_mon
, date
.tm_mday
, date
.tm_hour
, date
.tm_min
) - 1900;
374 if (day_of_month
+ strlen (day_of_month
) + 1 == t
)
376 date
.tm_year
= atoi (t
) - 1900;
377 /* We don't know the hour. Set it to something other than 0, or
378 * DST -1 will end up changing the date. */
384 s
->st_mtime
= mktime (&date
);
385 /* Use resulting time value */
386 s
->st_atime
= s
->st_ctime
= s
->st_mtime
;
388 name
= strtok_r (NULL
, "", &next
);
392 /* there are ls which output extra space after year. */
393 if (year_anomaly
&& *name
== ' ')
396 if (!S_ISLNK (s
->st_mode
))
402 for (arrow
= name
; (arrow
= strstr (arrow
, " -> ")) != NULL
; arrow
++)
403 if (arrow
!= name
&& arrow
[4] != '\0')
406 *linkname
= g_strdup (arrow
+ 4);
411 *filename
= g_strdup (name
);
416 /* --------------------------------------------------------------------------------------------- */
419 ftpfs_parse_long_list_UNIX (char *line
, struct stat
*s
, char **filename
, char **linkname
, int *err
)
424 if (sscanf (line
, "total %d", &tmp
) == 1)
427 if (strncasecmp (line
, "Status of ", 10) == 0)
428 return FALSE
; /* STAT output. */
430 ret
= parse_ls_line (line
, s
, filename
, linkname
);
437 /* --------------------------------------------------------------------------------------------- */
440 07-13-98 09:06PM <DIR> aix
441 07-13-98 09:06PM <DIR> hpux
442 07-13-98 09:06PM <DIR> linux
443 07-13-98 09:06PM <DIR> ncr
444 07-13-98 09:06PM <DIR> solaris
445 03-18-98 06:01AM 2109440 nlxb318e.tar
446 07-02-98 11:17AM 13844 Whatsnew.txt
450 ftpfs_parse_long_list_NT (char *line
, struct stat
*s
, char **filename
, char **linkname
, int *err
)
453 int month
, day
, year
, hour
, minute
;
461 if (sscanf (t
, "%2d-%2d-%2d", &month
, &day
, &year
) != 3)
471 am
= 'A'; /* AM/PM is optional */
472 if (sscanf (t
, "%2d:%2d%c", &hour
, &minute
, &am
) < 2)
479 if (am
== 'P') /* PM - after noon */
486 tms
.tm_sec
= 30; /* seconds after the minute [0, 61] */
487 tms
.tm_min
= minute
; /* minutes after the hour [0, 59] */
488 tms
.tm_hour
= hour
; /* hour since midnight [0, 23] */
489 tms
.tm_mday
= day
; /* day of the month [1, 31] */
490 tms
.tm_mon
= month
- 1; /* months since January [0, 11] */
491 tms
.tm_year
= year
- 1900; /* years since 1900 */
495 s
->st_mtime
= mktime (&tms
);
496 /* Use resulting time value */
497 s
->st_atime
= s
->st_ctime
= s
->st_mtime
;
499 if (strcmp (t
, "<DIR>") == 0)
500 s
->st_mode
= S_IFDIR
;
503 s
->st_mode
= S_IFREG
;
504 if (sscanf (t
, "%lld", &size
) != 1)
506 s
->st_size
= (off_t
) size
;
509 t
= strtok (NULL
, "");
517 *filename
= g_strdup (t
);
523 /* --------------------------------------------------------------------------------------------- */
526 +i774.71425,m951188401,/, users
527 +i774.49602,m917883130,r,s79126, jgr_www2.exe
531 first character of field is type:
533 m - modification time
537 up - permissions in octal
538 \t - file name follows.
542 ftpfs_parse_long_list_EPLF (char *line
, struct stat
*s
, char **filename
, char **linkname
, int *err
)
546 const char *name
= NULL
;
548 off_t size
= NO_SIZE
;
549 time_t date
= NO_DATE
;
552 gboolean dir
= FALSE
;
553 gboolean type_known
= FALSE
;
561 if (len
< 2 || b
[0] != '+')
567 while (scan
!= NULL
&& scan_len
> 0)
573 case '\t': /* the rest is file name. */
575 name_len
= scan_len
- 1;
579 if (sscanf (scan
+ 1, "%lld", &size_ll
) != 1)
584 if (sscanf (scan
+ 1, "%ld", &date_l
) != 1)
599 if (scan
[1] == 'p') /* permissions. */
600 if (sscanf (scan
+ 2, "%o", (unsigned int *) &perms
) != 1)
608 if (scan
== NULL
|| scan_len
== 0)
611 comma
= (const char *) memchr (scan
, ',', scan_len
);
615 scan_len
-= comma
+ 1 - scan
;
619 if (name
== NULL
|| !type_known
)
622 *filename
= g_strndup (name
, name_len
);
630 /* Use resulting time value */
631 s
->st_atime
= s
->st_ctime
= s
->st_mtime
;
634 s
->st_mode
= dir
? S_IFDIR
: S_IFREG
;
636 s
->st_mode
|= perms
; /* FIXME */
641 /* --------------------------------------------------------------------------------------------- */
643 Type=cdir;Modify=20021029173810;Perm=el;Unique=BP8AAjJufAA; /
644 Type=pdir;Modify=20021029173810;Perm=el;Unique=BP8AAjJufAA; ..
645 Type=dir;Modify=20010118144705;Perm=e;Unique=BP8AAjNufAA; bin
646 Type=dir;Modify=19981021003019;Perm=el;Unique=BP8AAlhufAA; pub
647 Type=file;Size=12303;Modify=19970124132601;Perm=r;Unique=BP8AAo9ufAA; mailserv.FAQ
648 modify=20161215062118;perm=flcdmpe;type=dir;UNIX.group=503;UNIX.mode=0700; directory-name
649 modify=20161213121618;perm=adfrw;size=6369064;type=file;UNIX.group=503;UNIX.mode=0644; file-name
650 modify=20120103123744;perm=adfrw;size=11;type=OS.unix=symlink;UNIX.group=0;UNIX.mode=0777; www
654 ftpfs_parse_long_list_MLSD (char *line
, struct stat
*s
, char **filename
, char **linkname
, int *err
)
656 const char *name
= NULL
;
657 off_t size
= NO_SIZE
;
658 time_t date
= NO_DATE
;
659 const char *owner
= NULL
;
660 const char *group
= NULL
;
661 filetype type
= UNKNOWN
;
666 space
= strstr (line
, "; ");
674 /* NcFTPd does not put a semicolon after last fact, workaround it. */
675 space
= strchr (line
, ' ');
682 for (tok
= strtok (line
, ";"); tok
!= NULL
; tok
= strtok (NULL
, ";"))
684 if (strcasecmp (tok
, "Type=cdir") == 0
685 || strcasecmp (tok
, "Type=pdir") == 0 || strcasecmp (tok
, "Type=dir") == 0)
690 if (strcasecmp (tok
, "Type=file") == 0)
695 if (strcasecmp (tok
, "Type=OS.unix=symlink") == 0)
700 if (strncasecmp (tok
, "Modify=", 7) == 0)
702 date
= ftpfs_convert_date (tok
+ 7);
705 if (strncasecmp (tok
, "Size=", 5) == 0)
709 if (sscanf (tok
+ 5, "%lld", &size_ll
) == 1)
713 if (strncasecmp (tok
, "Perm=", 5) == 0)
716 for (tok
+= 5; *tok
!= '\0'; tok
++)
718 switch (g_ascii_tolower (*tok
))
741 if (strncasecmp (tok
, "UNIX.mode=", 10) == 0)
743 if (sscanf (tok
+ 10, "%o", (unsigned int *) &perms
) != 1)
747 if (strncasecmp (tok
, "UNIX.owner=", 11) == 0)
752 if (strncasecmp (tok
, "UNIX.group=", 11) == 0)
757 if (strncasecmp (tok
, "UNIX.uid=", 9) == 0)
763 if (strncasecmp (tok
, "UNIX.gid=", 9) == 0)
770 if (name
== NULL
|| name
[0] == '\0' || type
== UNKNOWN
)
773 *filename
= g_strdup (name
);
781 /* Use resulting time value */
782 s
->st_atime
= s
->st_ctime
= s
->st_mtime
;
787 s
->st_mode
= S_IFDIR
;
790 s
->st_mode
= S_IFLNK
;
793 s
->st_mode
= S_IFREG
;
796 g_assert_not_reached ();
799 s
->st_mode
|= perms
; /* FIXME */
801 s
->st_uid
= ftpfs_get_uid (owner
);
803 s
->st_gid
= ftpfs_get_gid (group
);
808 /* --------------------------------------------------------------------------------------------- */
811 ASUSER 8192 04/26/05 13:54:16 *DIR dir/
812 ASUSER 8192 04/26/05 13:57:34 *DIR dir1/
813 ASUSER 365255 02/28/01 15:41:40 *STMF readme.txt
814 ASUSER 8489625 03/18/03 09:37:00 *STMF saved.zip
815 ASUSER 365255 02/28/01 15:41:40 *STMF unist.old
819 ftpfs_parse_long_list_AS400 (char *line
, struct stat
*s
, char **filename
, char **linkname
, int *err
)
824 int month
, day
, year
, hour
, minute
, second
;
838 if (sscanf (t
, "%lld", &size
) != 1)
844 if (sscanf (t
, "%2d/%2d/%2d", &month
, &day
, &year
) != 3)
854 if (sscanf (t
, "%2d:%2d:%2d", &hour
, &minute
, &second
) != 3)
861 tms
.tm_sec
= second
; /* seconds after the minute [0, 61] */
862 tms
.tm_min
= minute
; /* minutes after the hour [0, 59] */
863 tms
.tm_hour
= hour
; /* hour since midnight [0, 23] */
864 tms
.tm_mday
= day
; /* day of the month [1, 31] */
865 tms
.tm_mon
= month
- 1; /* months since January [0, 11] */
866 tms
.tm_year
= year
- 1900; /* years since 1900 */
868 mtime
= mktime (&tms
);
873 if (strcmp (t
, "*DIR") == 0)
878 t
= strtok (NULL
, "");
888 slash
= strchr (t
, '/');
896 if (slash
[1] != '\0')
898 *filename
= g_strdup (t
);
899 s
->st_mode
= type
; /* FIXME */
904 *filename
= g_strdup (t
);
906 s
->st_size
= (off_t
) size
;
908 /* Use resulting time value */
909 s
->st_atime
= s
->st_ctime
= s
->st_mtime
;
910 s
->st_uid
= ftpfs_get_uid (user
);
915 /* --------------------------------------------------------------------------------------------- */
918 0 DIR 06-27-96 11:57 PROTOCOL
919 169 11-29-94 09:20 SYSLEVEL.MPT
923 ftpfs_parse_long_list_OS2 (char *line
, struct stat
*s
, char **filename
, char **linkname
, int *err
)
927 int month
, day
, year
, hour
, minute
;
934 if (sscanf (t
, "%lld", &size
) != 1)
936 s
->st_size
= (off_t
) size
;
941 s
->st_mode
= S_IFREG
;
942 if (strcmp (t
, "DIR") == 0)
944 s
->st_mode
= S_IFDIR
;
951 if (sscanf (t
, "%2d-%2d-%2d", &month
, &day
, &year
) != 3)
961 if (sscanf (t
, "%2d:%2d", &hour
, &minute
) != 3)
964 tms
.tm_sec
= 30; /* seconds after the minute [0, 61] */
965 tms
.tm_min
= minute
; /* minutes after the hour [0, 59] */
966 tms
.tm_hour
= hour
; /* hour since midnight [0, 23] */
967 tms
.tm_mday
= day
; /* day of the month [1, 31] */
968 tms
.tm_mon
= month
- 1; /* months since January [0, 11] */
969 tms
.tm_year
= year
- 1900; /* years since 1900 */
971 s
->st_mtime
= mktime (&tms
);
972 /* Use resulting time value */
973 s
->st_atime
= s
->st_ctime
= s
->st_mtime
;
975 t
= strtok (NULL
, "");
982 *filename
= g_strdup (t
);
988 /* --------------------------------------------------------------------------------------------- */
991 ftpfs_parse_long_list_MacWebStar (char *line
, struct stat
*s
, char **filename
,
992 char **linkname
, int *err
)
997 const char *day_of_month
;
1004 if (!vfs_parse_filetype (t
, NULL
, &type
))
1009 if (!vfs_parse_fileperms (t
+ 1, NULL
, &mode
))
1011 /* permissions are meaningless here. */
1018 if (strcmp (t
, "folder") != 0)
1030 if (!isdigit ((unsigned char) *t
))
1033 if (sscanf (t
, "%lld", &size
) == 1)
1034 s
->st_size
= (off_t
) size
;
1049 memset (&date
, 0, sizeof (date
));
1051 if (!vfs_parse_month (t
, &date
))
1054 day_of_month
= NEXT_TOKEN
;
1055 if (day_of_month
== NULL
)
1058 date
.tm_mday
= atoi (day_of_month
);
1064 if (!parse_year_or_time (t
, &date
.tm_year
, &date
.tm_hour
, &date
.tm_min
))
1069 if (date
.tm_year
== -1)
1070 date
.tm_year
= guess_year (date
.tm_mon
, date
.tm_mday
, date
.tm_hour
, date
.tm_min
) - 1900;
1074 s
->st_mtime
= mktime (&date
);
1075 /* Use resulting time value */
1076 s
->st_atime
= s
->st_ctime
= s
->st_mtime
;
1078 name
= strtok (NULL
, "");
1082 /* no symlinks on Mac, but anyway. */
1083 if (!S_ISLNK (s
->st_mode
))
1089 for (arrow
= name
; (arrow
= strstr (arrow
, " -> ")) != NULL
; arrow
++)
1090 if (arrow
!= name
&& arrow
[4] != '\0')
1093 *linkname
= g_strdup (arrow
+ 4);
1098 *filename
= g_strdup (name
);
1103 /* --------------------------------------------------------------------------------------------- */
1104 /*** public functions ****************************************************************************/
1105 /* --------------------------------------------------------------------------------------------- */
1108 ftpfs_parse_long_list (struct vfs_class
*me
, struct vfs_s_inode
*dir
, GSList
*buf
, int *err_ret
)
1110 int err
[number_of_parsers
];
1111 GSList
*set
[number_of_parsers
]; /* arrays of struct vfs_s_entry */
1114 ftpfs_line_parser guessed_parser
= NULL
;
1115 GSList
**the_set
= NULL
;
1116 int *the_err
= NULL
;
1117 int *best_err1
= &err
[0];
1118 int *best_err2
= &err
[1];
1122 if (err_ret
!= NULL
)
1125 memset (&err
, 0, sizeof (err
));
1126 memset (&set
, 0, sizeof (set
));
1128 for (bufp
= buf
; bufp
!= NULL
; bufp
= g_slist_next (bufp
))
1130 char *b
= (char *) bufp
->data
;
1135 if (b
[blen
- 1] == '\r')
1144 if (guessed_parser
== NULL
)
1146 for (i
= 0; i
< number_of_parsers
; i
++)
1148 struct vfs_s_entry
*info
;
1153 /* parser can clobber the line - work on a copy */
1154 tmp_line
= g_strndup (b
, blen
);
1156 info
= vfs_s_generate_entry (me
, NULL
, dir
, 0);
1157 nlink
= info
->ino
->st
.st_nlink
;
1158 ok
= (*line_parsers
[i
]) (tmp_line
, &info
->ino
->st
, &info
->name
,
1159 &info
->ino
->linkname
, &err
[i
]);
1160 if (ok
&& strchr (info
->name
, '/') == NULL
)
1162 info
->ino
->st
.st_nlink
= nlink
; /* Ouch, we need to preserve our counts :-( */
1163 set
[i
] = g_slist_prepend (set
[i
], info
);
1166 vfs_s_free_entry (me
, info
);
1170 if (*best_err1
> err
[i
])
1171 best_err1
= &err
[i
];
1172 if (*best_err2
> err
[i
] && best_err1
!= &err
[i
])
1173 best_err2
= &err
[i
];
1175 if (*best_err1
> 16)
1176 goto leave
; /* too many errors with best parser. */
1179 if (*best_err2
> (*best_err1
+ 1) * 16)
1181 i
= (size_t) (best_err1
- err
);
1182 guessed_parser
= line_parsers
[i
];
1189 struct vfs_s_entry
*info
;
1194 /* parser can clobber the line - work on a copy */
1195 tmp_line
= g_strndup (b
, blen
);
1197 info
= vfs_s_generate_entry (me
, NULL
, dir
, 0);
1198 nlink
= info
->ino
->st
.st_nlink
;
1199 ok
= guessed_parser (tmp_line
, &info
->ino
->st
, &info
->name
, &info
->ino
->linkname
,
1201 if (ok
&& strchr (info
->name
, '/') == NULL
)
1203 info
->ino
->st
.st_nlink
= nlink
; /* Ouch, we need to preserve our counts :-( */
1204 *the_set
= g_slist_prepend (*the_set
, info
);
1207 vfs_s_free_entry (me
, info
);
1213 if (the_set
== NULL
)
1215 i
= best_err1
- err
;
1221 for (i
= 0; i
< number_of_parsers
; i
++)
1222 if (&set
[i
] != the_set
)
1224 for (bufp
= set
[i
]; bufp
!= NULL
; bufp
= g_slist_next (bufp
))
1225 vfs_s_free_entry (me
, VFS_ENTRY (bufp
->data
));
1227 g_slist_free (set
[i
]);
1230 if (err_ret
!= NULL
&& the_err
!= NULL
)
1231 *err_ret
= *the_err
;
1233 return the_set
!= NULL
? g_slist_reverse (*the_set
) : NULL
;
1236 /* --------------------------------------------------------------------------------------------- */