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