This source file includes following definitions.
- ftpfs_get_uid
- ftpfs_get_gid
- ftpfs_init_time
- guess_year
- parse_year_or_time
- mktime_from_utc
- ftpfs_convert_date
- parse_ls_line
- ftpfs_parse_long_list_UNIX
- ftpfs_parse_long_list_NT
- ftpfs_parse_long_list_EPLF
- ftpfs_parse_long_list_MLSD
- ftpfs_parse_long_list_AS400
- ftpfs_parse_long_list_OS2
- ftpfs_parse_long_list_MacWebStar
- ftpfs_parse_long_list
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 #include <config.h>
36
37 #include <ctype.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <sys/stat.h>
42 #include <time.h>
43 #include <unistd.h>
44 #include <sys/types.h>
45
46 #include "lib/global.h"
47
48 #include "lib/vfs/vfs.h"
49 #include "lib/vfs/utilvfs.h"
50
51 #include "ftpfs.h"
52
53
54
55
56
57 #define number_of_parsers 7
58
59 #define NO_SIZE ((off_t) (-1L))
60 #define NO_DATE ((time_t) (-1L))
61
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)
66
67 #define ERR2 do { (*err)++; return FALSE; } while (FALSE)
68
69
70
71 typedef enum
72 {
73 UNKNOWN = 0,
74 DIRECTORY,
75 SYMLINK,
76 NORMAL
77 } filetype;
78
79 typedef gboolean (*ftpfs_line_parser) (char *line, struct stat * s, char **filename,
80 char **linkname, int *err);
81
82
83
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);
98
99
100
101 static time_t rawnow;
102 static struct tm now;
103
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
112 };
113
114
115
116
117
118 static inline uid_t
119 ftpfs_get_uid (const char *s)
120 {
121 uid_t u;
122
123 if (*s < '0' || *s > '9')
124 u = vfs_finduid (s);
125 else
126 u = (uid_t) atol (s);
127
128 return u;
129 }
130
131
132
133 static inline gid_t
134 ftpfs_get_gid (const char *s)
135 {
136 gid_t g;
137
138 if (*s < '0' || *s > '9')
139 g = vfs_findgid (s);
140 else
141 g = (gid_t) atol (s);
142
143 return g;
144 }
145
146
147
148 static void
149 ftpfs_init_time (void)
150 {
151 time (&rawnow);
152 now = *localtime (&rawnow);
153 }
154
155
156
157 static int
158 guess_year (int month, int day, int hour, int minute)
159 {
160 int year;
161
162 (void) hour;
163 (void) minute;
164
165 year = now.tm_year + 1900;
166
167 if (month * 32 + day > now.tm_mon * 32 + now.tm_mday + 6)
168 year--;
169
170 return year;
171 }
172
173
174
175 static gboolean
176 parse_year_or_time (const char *year_or_time, int *year, int *hour, int *minute)
177 {
178 if (year_or_time[2] == ':')
179 {
180 if (sscanf (year_or_time, "%2d:%2d", hour, minute) != 2)
181 return FALSE;
182
183 *year = -1;
184 }
185 else
186 {
187 if (sscanf (year_or_time, "%d", year) != 1)
188 return FALSE;
189
190 *hour = *minute = 0;
191 }
192
193 return TRUE;
194 }
195
196
197
198
199
200
201
202
203 static time_t
204 mktime_from_utc (const struct tm *t)
205 {
206 struct tm tc;
207 time_t tl, tb;
208
209 memcpy (&tc, t, sizeof (struct tm));
210
211
212
213
214 tc.tm_isdst = 0;
215
216 tl = mktime (&tc);
217 if (tl == -1)
218 return (-1);
219
220 tb = mktime (gmtime (&tl));
221
222 return (tl <= tb ? (tl + (tl - tb)) : (tl - (tb - tl)));
223 }
224
225
226
227 static time_t
228 ftpfs_convert_date (const char *s)
229 {
230 struct tm tm;
231 int year, month, day, hour, minute, second;
232 int skip = 0;
233 int n;
234
235 memset (&tm, 0, sizeof (tm));
236
237 n = sscanf (s, "%4d%n", &year, &skip);
238
239
240
241 if (n == 1 && year >= 1910 && year <= 1930)
242 {
243 n = sscanf (s, "%5d%n", &year, &skip);
244 year = year - 19100 + 2000;
245 }
246
247 if (n != 1)
248 return NO_DATE;
249
250 n = sscanf (s + skip, "%2d%2d%2d%2d%2d", &month, &day, &hour, &minute, &second);
251
252 if (n != 5)
253 return NO_DATE;
254
255 tm.tm_year = year - 1900;
256 tm.tm_mon = month - 1;
257 tm.tm_mday = day;
258 tm.tm_hour = hour;
259 tm.tm_min = minute;
260 tm.tm_sec = second;
261
262 return mktime_from_utc (&tm);
263 }
264
265
266
267
268
269
270
271
272
273
274
275
276 static gboolean
277 parse_ls_line (char *line, struct stat *s, char **filename, char **linkname)
278 {
279 char *next = NULL;
280 char *t;
281 mode_t type, mode = 0;
282 char *group_or_size;
283 struct tm date;
284 const char *day_of_month;
285 gboolean year_anomaly = FALSE;
286 char *name;
287
288
289 t = FIRST_TOKEN_R;
290 if (t == NULL)
291 return FALSE;
292
293 if (!vfs_parse_filetype (t, NULL, &type))
294 return FALSE;
295
296 if (vfs_parse_fileperms (t + 1, NULL, &mode))
297 mode |= type;
298
299 s->st_mode = mode;
300
301
302 t = NEXT_TOKEN_R;
303 if (t == NULL)
304 return FALSE;
305 s->st_nlink = atol (t);
306
307
308 t = NEXT_TOKEN_R;
309 if (t == NULL)
310 return FALSE;
311
312 s->st_uid = ftpfs_get_uid (t);
313
314
315 group_or_size = NEXT_TOKEN_R;
316
317
318 t = NEXT_TOKEN_R;
319 if (t == NULL)
320 return FALSE;
321 if (isdigit ((unsigned char) *t))
322 {
323
324 long long size;
325 int n;
326
327 s->st_gid = ftpfs_get_gid (group_or_size);
328
329 if (sscanf (t, "%lld%n", &size, &n) == 1 && t[n] == '\0')
330 s->st_size = (off_t) size;
331 t = NEXT_TOKEN_R;
332 if (t == NULL)
333 return FALSE;
334 }
335 else
336 {
337
338 long long size;
339 int n;
340
341 if (sscanf (group_or_size, "%lld%n", &size, &n) == 1 && group_or_size[n] == '\0')
342 s->st_size = (off_t) size;
343 }
344
345 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
346 s->st_blksize = 512;
347 #endif
348 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
349 s->st_blocks = (s->st_size + 511) / 512;
350 #endif
351
352 memset (&date, 0, sizeof (date));
353
354 if (!vfs_parse_month (t, &date))
355 date.tm_mon = 0;
356
357 day_of_month = NEXT_TOKEN_R;
358 if (day_of_month == NULL)
359 return FALSE;
360 date.tm_mday = atoi (day_of_month);
361
362
363 t = NEXT_TOKEN_R;
364 if (t == NULL)
365 return FALSE;
366 date.tm_isdst = -1;
367 date.tm_hour = date.tm_min = 0;
368 date.tm_sec = 30;
369
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;
372 else
373 {
374 if (day_of_month + strlen (day_of_month) + 1 == t)
375 year_anomaly = TRUE;
376 date.tm_year = atoi (t) - 1900;
377
378
379 date.tm_hour = 12;
380 date.tm_min = 0;
381 date.tm_sec = 0;
382 }
383
384 s->st_mtime = mktime (&date);
385
386 s->st_atime = s->st_ctime = s->st_mtime;
387
388 name = strtok_r (NULL, "", &next);
389 if (name == NULL)
390 return FALSE;
391
392
393 if (year_anomaly && *name == ' ')
394 name++;
395
396 if (!S_ISLNK (s->st_mode))
397 *linkname = NULL;
398 else
399 {
400 char *arrow;
401
402 for (arrow = name; (arrow = strstr (arrow, " -> ")) != NULL; arrow++)
403 if (arrow != name && arrow[4] != '\0')
404 {
405 *arrow = '\0';
406 *linkname = g_strdup (arrow + 4);
407 break;
408 }
409 }
410
411 *filename = g_strdup (name);
412
413 return TRUE;
414 }
415
416
417
418 static gboolean
419 ftpfs_parse_long_list_UNIX (char *line, struct stat *s, char **filename, char **linkname, int *err)
420 {
421 int tmp;
422 gboolean ret;
423
424 if (sscanf (line, "total %d", &tmp) == 1)
425 return FALSE;
426
427 if (strncasecmp (line, "Status of ", 10) == 0)
428 return FALSE;
429
430 ret = parse_ls_line (line, s, filename, linkname);
431 if (!ret)
432 (*err)++;
433
434 return ret;
435 }
436
437
438
439
440
441
442
443
444
445
446
447
448
449 static gboolean
450 ftpfs_parse_long_list_NT (char *line, struct stat *s, char **filename, char **linkname, int *err)
451 {
452 char *t;
453 int month, day, year, hour, minute;
454 char am;
455 struct tm tms;
456 long long size;
457
458 t = FIRST_TOKEN;
459 if (t == NULL)
460 ERR2;
461 if (sscanf (t, "%2d-%2d-%2d", &month, &day, &year) != 3)
462 ERR2;
463 if (year >= 70)
464 year += 1900;
465 else
466 year += 2000;
467
468 t = NEXT_TOKEN;
469 if (t == NULL)
470 ERR2;
471 am = 'A';
472 if (sscanf (t, "%2d:%2d%c", &hour, &minute, &am) < 2)
473 ERR2;
474
475 t = NEXT_TOKEN;
476 if (t == NULL)
477 ERR2;
478
479 if (am == 'P')
480 {
481 hour += 12;
482 if (hour == 24)
483 hour = 0;
484 }
485
486 tms.tm_sec = 30;
487 tms.tm_min = minute;
488 tms.tm_hour = hour;
489 tms.tm_mday = day;
490 tms.tm_mon = month - 1;
491 tms.tm_year = year - 1900;
492 tms.tm_isdst = -1;
493
494
495 s->st_mtime = mktime (&tms);
496
497 s->st_atime = s->st_ctime = s->st_mtime;
498
499 if (strcmp (t, "<DIR>") == 0)
500 s->st_mode = S_IFDIR;
501 else
502 {
503 s->st_mode = S_IFREG;
504 if (sscanf (t, "%lld", &size) != 1)
505 ERR2;
506 s->st_size = (off_t) size;
507 }
508
509 t = strtok (NULL, "");
510 if (t == NULL)
511 ERR2;
512 while (*t == ' ')
513 t++;
514 if (*t == '\0')
515 ERR2;
516
517 *filename = g_strdup (t);
518 *linkname = NULL;
519
520 return TRUE;
521 }
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541 static gboolean
542 ftpfs_parse_long_list_EPLF (char *line, struct stat *s, char **filename, char **linkname, int *err)
543 {
544 size_t len;
545 const char *b;
546 const char *name = NULL;
547 size_t name_len = 0;
548 off_t size = NO_SIZE;
549 time_t date = NO_DATE;
550 long date_l;
551 long long size_ll;
552 gboolean dir = FALSE;
553 gboolean type_known = FALSE;
554 int perms = -1;
555 const char *scan;
556 ssize_t scan_len;
557
558 len = strlen (line);
559 b = line;
560
561 if (len < 2 || b[0] != '+')
562 ERR2;
563
564 scan = b + 1;
565 scan_len = len - 1;
566
567 while (scan != NULL && scan_len > 0)
568 {
569 const char *comma;
570
571 switch (*scan)
572 {
573 case '\t':
574 name = scan + 1;
575 name_len = scan_len - 1;
576 scan = NULL;
577 break;
578 case 's':
579 if (sscanf (scan + 1, "%lld", &size_ll) != 1)
580 break;
581 size = size_ll;
582 break;
583 case 'm':
584 if (sscanf (scan + 1, "%ld", &date_l) != 1)
585 break;
586 date = date_l;
587 break;
588 case '/':
589 dir = TRUE;
590 type_known = TRUE;
591 break;
592 case 'r':
593 dir = FALSE;
594 type_known = TRUE;
595 break;
596 case 'i':
597 break;
598 case 'u':
599 if (scan[1] == 'p')
600 if (sscanf (scan + 2, "%o", (unsigned int *) &perms) != 1)
601 perms = -1;
602 break;
603 default:
604 name = NULL;
605 scan = NULL;
606 break;
607 }
608 if (scan == NULL || scan_len == 0)
609 break;
610
611 comma = (const char *) memchr (scan, ',', scan_len);
612 if (comma == NULL)
613 break;
614
615 scan_len -= comma + 1 - scan;
616 scan = comma + 1;
617 }
618
619 if (name == NULL || !type_known)
620 ERR2;
621
622 *filename = g_strndup (name, name_len);
623 *linkname = NULL;
624
625 if (size != NO_SIZE)
626 s->st_size = size;
627 if (date != NO_DATE)
628 {
629 s->st_mtime = date;
630
631 s->st_atime = s->st_ctime = s->st_mtime;
632 }
633 if (type_known)
634 s->st_mode = dir ? S_IFDIR : S_IFREG;
635 if (perms != -1)
636 s->st_mode |= perms;
637
638 return TRUE;
639 }
640
641
642
643
644
645
646
647
648
649
650
651
652
653 static gboolean
654 ftpfs_parse_long_list_MLSD (char *line, struct stat *s, char **filename, char **linkname, int *err)
655 {
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;
662 int perms = -1;
663 char *space;
664 char *tok;
665
666 space = strstr (line, "; ");
667 if (space != NULL)
668 {
669 name = space + 2;
670 *space = '\0';
671 }
672 else
673 {
674
675 space = strchr (line, ' ');
676 if (space == NULL)
677 ERR2;
678 name = space + 1;
679 *space = '\0';
680 }
681
682 for (tok = strtok (line, ";"); tok != NULL; tok = strtok (NULL, ";"))
683 {
684 if (strcasecmp (tok, "Type=cdir") == 0
685 || strcasecmp (tok, "Type=pdir") == 0 || strcasecmp (tok, "Type=dir") == 0)
686 {
687 type = DIRECTORY;
688 continue;
689 }
690 if (strcasecmp (tok, "Type=file") == 0)
691 {
692 type = NORMAL;
693 continue;
694 }
695 if (strcasecmp (tok, "Type=OS.unix=symlink") == 0)
696 {
697 type = SYMLINK;
698 continue;
699 }
700 if (strncasecmp (tok, "Modify=", 7) == 0)
701 {
702 date = ftpfs_convert_date (tok + 7);
703 continue;
704 }
705 if (strncasecmp (tok, "Size=", 5) == 0)
706 {
707 long long size_ll;
708
709 if (sscanf (tok + 5, "%lld", &size_ll) == 1)
710 size = size_ll;
711 continue;
712 }
713 if (strncasecmp (tok, "Perm=", 5) == 0)
714 {
715 perms = 0;
716 for (tok += 5; *tok != '\0'; tok++)
717 {
718 switch (g_ascii_tolower (*tok))
719 {
720 case 'e':
721 perms |= 0111;
722 break;
723 case 'l':
724 perms |= 0444;
725 break;
726 case 'r':
727 perms |= 0444;
728 break;
729 case 'c':
730 perms |= 0200;
731 break;
732 case 'w':
733 perms |= 0200;
734 break;
735 default:
736 break;
737 }
738 }
739 continue;
740 }
741 if (strncasecmp (tok, "UNIX.mode=", 10) == 0)
742 {
743 if (sscanf (tok + 10, "%o", (unsigned int *) &perms) != 1)
744 perms = -1;
745 continue;
746 }
747 if (strncasecmp (tok, "UNIX.owner=", 11) == 0)
748 {
749 owner = tok + 11;
750 continue;
751 }
752 if (strncasecmp (tok, "UNIX.group=", 11) == 0)
753 {
754 group = tok + 11;
755 continue;
756 }
757 if (strncasecmp (tok, "UNIX.uid=", 9) == 0)
758 {
759 if (owner == NULL)
760 owner = tok + 9;
761 continue;
762 }
763 if (strncasecmp (tok, "UNIX.gid=", 9) == 0)
764 {
765 if (group == NULL)
766 group = tok + 9;
767 continue;
768 }
769 }
770 if (name == NULL || name[0] == '\0' || type == UNKNOWN)
771 ERR2;
772
773 *filename = g_strdup (name);
774 *linkname = NULL;
775
776 if (size != NO_SIZE)
777 s->st_size = size;
778 if (date != NO_DATE)
779 {
780 s->st_mtime = date;
781
782 s->st_atime = s->st_ctime = s->st_mtime;
783 }
784 switch (type)
785 {
786 case DIRECTORY:
787 s->st_mode = S_IFDIR;
788 break;
789 case SYMLINK:
790 s->st_mode = S_IFLNK;
791 break;
792 case NORMAL:
793 s->st_mode = S_IFREG;
794 break;
795 default:
796 g_assert_not_reached ();
797 }
798 if (perms != -1)
799 s->st_mode |= perms;
800 if (owner != NULL)
801 s->st_uid = ftpfs_get_uid (owner);
802 if (group != NULL)
803 s->st_gid = ftpfs_get_gid (group);
804
805 return TRUE;
806 }
807
808
809
810
811
812
813
814
815
816
817
818 static gboolean
819 ftpfs_parse_long_list_AS400 (char *line, struct stat *s, char **filename, char **linkname, int *err)
820 {
821 char *t;
822 char *user;
823 long long size;
824 int month, day, year, hour, minute, second;
825 struct tm tms;
826 time_t mtime;
827 mode_t type;
828 char *slash;
829
830 t = FIRST_TOKEN;
831 if (t == NULL)
832 ERR2;
833 user = t;
834
835 t = NEXT_TOKEN;
836 if (t == NULL)
837 ERR2;
838 if (sscanf (t, "%lld", &size) != 1)
839 ERR2;
840
841 t = NEXT_TOKEN;
842 if (t == NULL)
843 ERR2;
844 if (sscanf (t, "%2d/%2d/%2d", &month, &day, &year) != 3)
845 ERR2;
846 if (year >= 70)
847 year += 1900;
848 else
849 year += 2000;
850
851 t = NEXT_TOKEN;
852 if (t == NULL)
853 ERR2;
854 if (sscanf (t, "%2d:%2d:%2d", &hour, &minute, &second) != 3)
855 ERR2;
856
857 t = NEXT_TOKEN;
858 if (t == NULL)
859 ERR2;
860
861 tms.tm_sec = second;
862 tms.tm_min = minute;
863 tms.tm_hour = hour;
864 tms.tm_mday = day;
865 tms.tm_mon = month - 1;
866 tms.tm_year = year - 1900;
867 tms.tm_isdst = -1;
868 mtime = mktime (&tms);
869
870 t = NEXT_TOKEN;
871 if (t == NULL)
872 ERR2;
873 if (strcmp (t, "*DIR") == 0)
874 type = S_IFDIR;
875 else
876 type = S_IFREG;
877
878 t = strtok (NULL, "");
879 if (t == NULL)
880 ERR2;
881 while (*t == ' ')
882 t++;
883 if (*t == '\0')
884 ERR2;
885
886 *linkname = NULL;
887
888 slash = strchr (t, '/');
889 if (slash != NULL)
890 {
891 if (slash == t)
892 return FALSE;
893
894 *slash = '\0';
895 type = S_IFDIR;
896 if (slash[1] != '\0')
897 {
898 *filename = g_strdup (t);
899 s->st_mode = type;
900 return TRUE;
901 }
902 }
903
904 *filename = g_strdup (t);
905 s->st_mode = type;
906 s->st_size = (off_t) size;
907 s->st_mtime = mtime;
908
909 s->st_atime = s->st_ctime = s->st_mtime;
910 s->st_uid = ftpfs_get_uid (user);
911
912 return TRUE;
913 }
914
915
916
917
918
919
920
921
922 static gboolean
923 ftpfs_parse_long_list_OS2 (char *line, struct stat *s, char **filename, char **linkname, int *err)
924 {
925 char *t;
926 long long size;
927 int month, day, year, hour, minute;
928 struct tm tms;
929
930 t = FIRST_TOKEN;
931 if (t == NULL)
932 ERR2;
933
934 if (sscanf (t, "%lld", &size) != 1)
935 ERR2;
936 s->st_size = (off_t) size;
937
938 t = NEXT_TOKEN;
939 if (t == NULL)
940 ERR2;
941 s->st_mode = S_IFREG;
942 if (strcmp (t, "DIR") == 0)
943 {
944 s->st_mode = S_IFDIR;
945 t = NEXT_TOKEN;
946
947 if (t == NULL)
948 ERR2;
949 }
950
951 if (sscanf (t, "%2d-%2d-%2d", &month, &day, &year) != 3)
952 ERR2;
953 if (year >= 70)
954 year += 1900;
955 else
956 year += 2000;
957
958 t = NEXT_TOKEN;
959 if (t == NULL)
960 ERR2;
961 if (sscanf (t, "%2d:%2d", &hour, &minute) != 3)
962 ERR2;
963
964 tms.tm_sec = 30;
965 tms.tm_min = minute;
966 tms.tm_hour = hour;
967 tms.tm_mday = day;
968 tms.tm_mon = month - 1;
969 tms.tm_year = year - 1900;
970 tms.tm_isdst = -1;
971 s->st_mtime = mktime (&tms);
972
973 s->st_atime = s->st_ctime = s->st_mtime;
974
975 t = strtok (NULL, "");
976 if (t == NULL)
977 ERR2;
978 while (*t == ' ')
979 t++;
980 if (*t == '\0')
981 ERR2;
982 *filename = g_strdup (t);
983 *linkname = NULL;
984
985 return TRUE;
986 }
987
988
989
990 static gboolean
991 ftpfs_parse_long_list_MacWebStar (char *line, struct stat *s, char **filename,
992 char **linkname, int *err)
993 {
994 char *t;
995 mode_t type, mode;
996 struct tm date;
997 const char *day_of_month;
998 char *name;
999
1000 t = FIRST_TOKEN;
1001 if (t == NULL)
1002 ERR2;
1003
1004 if (!vfs_parse_filetype (t, NULL, &type))
1005 ERR2;
1006
1007 s->st_mode = type;
1008
1009 if (!vfs_parse_fileperms (t + 1, NULL, &mode))
1010 ERR2;
1011
1012
1013
1014 t = NEXT_TOKEN;
1015 if (t == NULL)
1016 ERR2;
1017
1018 if (strcmp (t, "folder") != 0)
1019 {
1020 long long size;
1021
1022
1023 t = NEXT_TOKEN;
1024 if (t == NULL)
1025 ERR2;
1026
1027 t = NEXT_TOKEN;
1028 if (t == NULL)
1029 ERR2;
1030 if (!isdigit ((unsigned char) *t))
1031 ERR2;
1032
1033 if (sscanf (t, "%lld", &size) == 1)
1034 s->st_size = (off_t) size;
1035 }
1036 else
1037 {
1038
1039 t = NEXT_TOKEN;
1040 if (t == NULL)
1041 ERR2;
1042 }
1043
1044
1045 t = NEXT_TOKEN;
1046 if (t == NULL)
1047 ERR2;
1048
1049 memset (&date, 0, sizeof (date));
1050
1051 if (!vfs_parse_month (t, &date))
1052 ERR2;
1053
1054 day_of_month = NEXT_TOKEN;
1055 if (day_of_month == NULL)
1056 ERR2;
1057
1058 date.tm_mday = atoi (day_of_month);
1059
1060
1061 t = NEXT_TOKEN;
1062 if (t == NULL)
1063 ERR2;
1064 if (!parse_year_or_time (t, &date.tm_year, &date.tm_hour, &date.tm_min))
1065 ERR2;
1066
1067 date.tm_isdst = -1;
1068 date.tm_sec = 30;
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;
1071 else
1072 date.tm_hour = 12;
1073
1074 s->st_mtime = mktime (&date);
1075
1076 s->st_atime = s->st_ctime = s->st_mtime;
1077
1078 name = strtok (NULL, "");
1079 if (name == NULL)
1080 ERR2;
1081
1082
1083 if (!S_ISLNK (s->st_mode))
1084 *linkname = NULL;
1085 else
1086 {
1087 char *arrow;
1088
1089 for (arrow = name; (arrow = strstr (arrow, " -> ")) != NULL; arrow++)
1090 if (arrow != name && arrow[4] != '\0')
1091 {
1092 *arrow = '\0';
1093 *linkname = g_strdup (arrow + 4);
1094 break;
1095 }
1096 }
1097
1098 *filename = g_strdup (name);
1099
1100 return TRUE;
1101 }
1102
1103
1104
1105
1106
1107 GSList *
1108 ftpfs_parse_long_list (struct vfs_class *me, struct vfs_s_inode *dir, GSList *buf, int *err_ret)
1109 {
1110 int err[number_of_parsers];
1111 GSList *set[number_of_parsers];
1112 size_t i;
1113 GSList *bufp;
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];
1119
1120 ftpfs_init_time ();
1121
1122 if (err_ret != NULL)
1123 *err_ret = 0;
1124
1125 memset (&err, 0, sizeof (err));
1126 memset (&set, 0, sizeof (set));
1127
1128 for (bufp = buf; bufp != NULL; bufp = g_slist_next (bufp))
1129 {
1130 char *b = (char *) bufp->data;
1131 size_t blen;
1132
1133 blen = strlen (b);
1134
1135 if (b[blen - 1] == '\r')
1136 {
1137 b[blen - 1] = '\0';
1138 blen--;
1139 }
1140
1141 if (blen == 0)
1142 continue;
1143
1144 if (guessed_parser == NULL)
1145 {
1146 for (i = 0; i < number_of_parsers; i++)
1147 {
1148 struct vfs_s_entry *info;
1149 gboolean ok;
1150 char *tmp_line;
1151 int nlink;
1152
1153
1154 tmp_line = g_strndup (b, blen);
1155
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)
1161 {
1162 info->ino->st.st_nlink = nlink;
1163 set[i] = g_slist_prepend (set[i], info);
1164 }
1165 else
1166 vfs_s_free_entry (me, info);
1167
1168 g_free (tmp_line);
1169
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];
1174
1175 if (*best_err1 > 16)
1176 goto leave;
1177 }
1178
1179 if (*best_err2 > (*best_err1 + 1) * 16)
1180 {
1181 i = (size_t) (best_err1 - err);
1182 guessed_parser = line_parsers[i];
1183 the_set = &set[i];
1184 the_err = &err[i];
1185 }
1186 }
1187 else
1188 {
1189 struct vfs_s_entry *info;
1190 gboolean ok;
1191 char *tmp_line;
1192 int nlink;
1193
1194
1195 tmp_line = g_strndup (b, blen);
1196
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,
1200 the_err);
1201 if (ok && strchr (info->name, '/') == NULL)
1202 {
1203 info->ino->st.st_nlink = nlink;
1204 *the_set = g_slist_prepend (*the_set, info);
1205 }
1206 else
1207 vfs_s_free_entry (me, info);
1208
1209 g_free (tmp_line);
1210 }
1211 }
1212
1213 if (the_set == NULL)
1214 {
1215 i = best_err1 - err;
1216 the_set = &set[i];
1217 the_err = &err[i];
1218 }
1219
1220 leave:
1221 for (i = 0; i < number_of_parsers; i++)
1222 if (&set[i] != the_set)
1223 {
1224 for (bufp = set[i]; bufp != NULL; bufp = g_slist_next (bufp))
1225 vfs_s_free_entry (me, VFS_ENTRY (bufp->data));
1226
1227 g_slist_free (set[i]);
1228 }
1229
1230 if (err_ret != NULL && the_err != NULL)
1231 *err_ret = *the_err;
1232
1233 return the_set != NULL ? g_slist_reverse (*the_set) : NULL;
1234 }
1235
1236