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 static gboolean ftpfs_parse_long_list_UNIX (char *line, struct stat *s, char **filename,
84 char **linkname, int *err);
85 static gboolean ftpfs_parse_long_list_NT (char *line, struct stat *s, char **filename,
86 char **linkname, int *err);
87 static gboolean ftpfs_parse_long_list_EPLF (char *line, struct stat *s, char **filename,
88 char **linkname, int *err);
89 static gboolean ftpfs_parse_long_list_MLSD (char *line, struct stat *s, char **filename,
90 char **linkname, int *err);
91 static gboolean ftpfs_parse_long_list_AS400 (char *line, struct stat *s, char **filename,
92 char **linkname, int *err);
93 static gboolean ftpfs_parse_long_list_OS2 (char *line, struct stat *s, char **filename,
94 char **linkname, int *err);
95 static gboolean ftpfs_parse_long_list_MacWebStar (char *line, struct stat *s, char **filename,
96 char **linkname, int *err);
97
98
99
100 static time_t rawnow;
101 static struct tm now;
102
103 static ftpfs_line_parser line_parsers[number_of_parsers] = {
104 ftpfs_parse_long_list_UNIX,
105 ftpfs_parse_long_list_NT,
106 ftpfs_parse_long_list_EPLF,
107 ftpfs_parse_long_list_MLSD,
108 ftpfs_parse_long_list_AS400,
109 ftpfs_parse_long_list_OS2,
110 ftpfs_parse_long_list_MacWebStar
111 };
112
113
114
115
116
117 static inline uid_t
118 ftpfs_get_uid (const char *s)
119 {
120 uid_t u;
121
122 if (*s < '0' || *s > '9')
123 u = vfs_finduid (s);
124 else
125 u = (uid_t) atol (s);
126
127 return u;
128 }
129
130
131
132 static inline gid_t
133 ftpfs_get_gid (const char *s)
134 {
135 gid_t g;
136
137 if (*s < '0' || *s > '9')
138 g = vfs_findgid (s);
139 else
140 g = (gid_t) atol (s);
141
142 return g;
143 }
144
145
146
147 static void
148 ftpfs_init_time (void)
149 {
150 time (&rawnow);
151 now = *localtime (&rawnow);
152 }
153
154
155
156 static int
157 guess_year (int month, int day, int hour, int minute)
158 {
159 int year;
160
161 (void) hour;
162 (void) minute;
163
164 year = now.tm_year + 1900;
165
166 if (month * 32 + day > now.tm_mon * 32 + now.tm_mday + 6)
167 year--;
168
169 return year;
170 }
171
172
173
174 static gboolean
175 parse_year_or_time (const char *year_or_time, int *year, int *hour, int *minute)
176 {
177 if (year_or_time[2] == ':')
178 {
179 if (sscanf (year_or_time, "%2d:%2d", hour, minute) != 2)
180 return FALSE;
181
182 *year = -1;
183 }
184 else
185 {
186 if (sscanf (year_or_time, "%d", year) != 1)
187 return FALSE;
188
189 *hour = *minute = 0;
190 }
191
192 return TRUE;
193 }
194
195
196
197
198
199
200
201
202 static time_t
203 mktime_from_utc (const struct tm *t)
204 {
205 struct tm tc;
206 time_t tl, tb;
207
208 memcpy (&tc, t, sizeof (struct tm));
209
210
211
212
213 tc.tm_isdst = 0;
214
215 tl = mktime (&tc);
216 if (tl == -1)
217 return (-1);
218
219 tb = mktime (gmtime (&tl));
220
221 return (tl <= tb ? (tl + (tl - tb)) : (tl - (tb - tl)));
222 }
223
224
225
226 static time_t
227 ftpfs_convert_date (const char *s)
228 {
229 struct tm tm;
230 int year, month, day, hour, minute, second;
231 int skip = 0;
232 int n;
233
234 memset (&tm, 0, sizeof (tm));
235
236 n = sscanf (s, "%4d%n", &year, &skip);
237
238
239
240 if (n == 1 && year >= 1910 && year <= 1930)
241 {
242 n = sscanf (s, "%5d%n", &year, &skip);
243 year = year - 19100 + 2000;
244 }
245
246 if (n != 1)
247 return NO_DATE;
248
249 n = sscanf (s + skip, "%2d%2d%2d%2d%2d", &month, &day, &hour, &minute, &second);
250
251 if (n != 5)
252 return NO_DATE;
253
254 tm.tm_year = year - 1900;
255 tm.tm_mon = month - 1;
256 tm.tm_mday = day;
257 tm.tm_hour = hour;
258 tm.tm_min = minute;
259 tm.tm_sec = second;
260
261 return mktime_from_utc (&tm);
262 }
263
264
265
266
267
268
269
270
271
272
273
274
275 static gboolean
276 parse_ls_line (char *line, struct stat *s, char **filename, char **linkname)
277 {
278 char *next = NULL;
279 char *t;
280 mode_t type, mode = 0;
281 char *group_or_size;
282 struct tm date;
283 const char *day_of_month;
284 gboolean year_anomaly = FALSE;
285 char *name;
286
287
288 t = FIRST_TOKEN_R;
289 if (t == NULL)
290 return FALSE;
291
292 if (!vfs_parse_filetype (t, NULL, &type))
293 return FALSE;
294
295 if (vfs_parse_fileperms (t + 1, NULL, &mode))
296 mode |= type;
297
298 s->st_mode = mode;
299
300
301 t = NEXT_TOKEN_R;
302 if (t == NULL)
303 return FALSE;
304 s->st_nlink = atol (t);
305
306
307 t = NEXT_TOKEN_R;
308 if (t == NULL)
309 return FALSE;
310
311 s->st_uid = ftpfs_get_uid (t);
312
313
314 group_or_size = NEXT_TOKEN_R;
315
316
317 t = NEXT_TOKEN_R;
318 if (t == NULL)
319 return FALSE;
320 if (isdigit ((unsigned char) *t))
321 {
322
323 long long size;
324 int n;
325
326 s->st_gid = ftpfs_get_gid (t);
327
328 if (sscanf (t, "%lld%n", &size, &n) == 1 && t[n] == '\0')
329 s->st_size = (off_t) size;
330 t = NEXT_TOKEN_R;
331 if (t == NULL)
332 return FALSE;
333 }
334 else
335 {
336
337 long long size;
338 int n;
339
340 if (sscanf (group_or_size, "%lld%n", &size, &n) == 1 && group_or_size[n] == '\0')
341 s->st_size = (off_t) size;
342 }
343
344 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
345 s->st_blksize = 512;
346 #endif
347 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
348 s->st_blocks = (s->st_size + 511) / 512;
349 #endif
350
351 memset (&date, 0, sizeof (date));
352
353 if (!vfs_parse_month (t, &date))
354 date.tm_mon = 0;
355
356 day_of_month = NEXT_TOKEN_R;
357 if (day_of_month == NULL)
358 return FALSE;
359 date.tm_mday = atoi (day_of_month);
360
361
362 t = NEXT_TOKEN_R;
363 if (t == NULL)
364 return FALSE;
365 date.tm_isdst = -1;
366 date.tm_hour = date.tm_min = 0;
367 date.tm_sec = 30;
368
369 if (sscanf (t, "%2d:%2d", &date.tm_hour, &date.tm_min) == 2)
370 date.tm_year = guess_year (date.tm_mon, date.tm_mday, date.tm_hour, date.tm_min) - 1900;
371 else
372 {
373 if (day_of_month + strlen (day_of_month) + 1 == t)
374 year_anomaly = TRUE;
375 date.tm_year = atoi (t) - 1900;
376
377
378 date.tm_hour = 12;
379 date.tm_min = 0;
380 date.tm_sec = 0;
381 }
382
383 s->st_mtime = mktime (&date);
384
385 s->st_atime = s->st_ctime = s->st_mtime;
386
387 name = strtok_r (NULL, "", &next);
388 if (name == NULL)
389 return FALSE;
390
391
392 if (year_anomaly && *name == ' ')
393 name++;
394
395 if (!S_ISLNK (s->st_mode))
396 *linkname = NULL;
397 else
398 {
399 char *arrow;
400
401 for (arrow = name; (arrow = strstr (arrow, " -> ")) != NULL; arrow++)
402 if (arrow != name && arrow[4] != '\0')
403 {
404 *arrow = '\0';
405 *linkname = g_strdup (arrow + 4);
406 break;
407 }
408 }
409
410 *filename = g_strdup (name);
411
412 return TRUE;
413 }
414
415
416
417 static gboolean
418 ftpfs_parse_long_list_UNIX (char *line, struct stat *s, char **filename, char **linkname, int *err)
419 {
420 int tmp;
421 gboolean ret;
422
423 if (sscanf (line, "total %d", &tmp) == 1)
424 return FALSE;
425
426 if (strncasecmp (line, "Status of ", 10) == 0)
427 return FALSE;
428 if (strchr ("bcpsD", line[0]) != NULL)
429 return FALSE;
430
431 ret = parse_ls_line (line, s, filename, linkname);
432 if (!ret)
433 (*err)++;
434
435 return ret;
436 }
437
438
439
440
441
442
443
444
445
446
447
448
449
450 static gboolean
451 ftpfs_parse_long_list_NT (char *line, struct stat *s, char **filename, char **linkname, int *err)
452 {
453 char *t;
454 int month, day, year, hour, minute;
455 char am;
456 struct tm tms;
457 long long size;
458
459 t = FIRST_TOKEN;
460 if (t == NULL)
461 ERR2;
462 if (sscanf (t, "%2d-%2d-%2d", &month, &day, &year) != 3)
463 ERR2;
464 if (year >= 70)
465 year += 1900;
466 else
467 year += 2000;
468
469 t = NEXT_TOKEN;
470 if (t == NULL)
471 ERR2;
472 am = 'A';
473 if (sscanf (t, "%2d:%2d%c", &hour, &minute, &am) < 2)
474 ERR2;
475
476 t = NEXT_TOKEN;
477 if (t == NULL)
478 ERR2;
479
480 if (am == 'P')
481 {
482 hour += 12;
483 if (hour == 24)
484 hour = 0;
485 }
486
487 tms.tm_sec = 30;
488 tms.tm_min = minute;
489 tms.tm_hour = hour;
490 tms.tm_mday = day;
491 tms.tm_mon = month - 1;
492 tms.tm_year = year - 1900;
493 tms.tm_isdst = -1;
494
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
686 || strcasecmp (tok, "Type=pdir") == 0 || 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_uid = 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,
993 char **linkname, 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