This source file includes following definitions.
- is_num
- is_dos_date
- is_week
- is_localized_month
- is_time
- is_year
- vfs_parse_filetype
- vfs_parse_fileperms
- vfs_parse_filemode
- vfs_parse_raw_filemode
- vfs_parse_month
- vfs_parse_filedate
- vfs_split_text
- vfs_parse_ls_lga_init
- vfs_parse_ls_lga_get_final_spaces
- vfs_parse_ls_lga
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
36 #include <config.h>
37
38 #include <ctype.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41
42 #include "lib/global.h"
43 #include "lib/unixcompat.h"
44 #include "lib/widget.h"
45
46 #include "utilvfs.h"
47
48
49
50
51
52
53 #define MAXCOLS 30
54
55
56
57
58
59
60
61 static char *columns[MAXCOLS];
62 static int column_ptr[MAXCOLS];
63 static size_t vfs_parse_ls_final_num_spaces = 0;
64
65
66
67
68
69 static gboolean
70 is_num (int idx)
71 {
72 char *column = columns[idx];
73
74 return (column != NULL && isdigit (column[0]));
75 }
76
77
78
79
80 static gboolean
81 is_dos_date (const char *str)
82 {
83 size_t len;
84
85 if (str == NULL)
86 return FALSE;
87
88 len = strlen (str);
89 if (len != 8 && len != 10)
90 return FALSE;
91
92 if (str[2] != str[5])
93 return FALSE;
94
95 return (strchr ("\\-/", (int) str[2]) != NULL);
96 }
97
98
99
100 static gboolean
101 is_week (const char *str, struct tm *tim)
102 {
103 static const char *week = "SunMonTueWedThuFriSat";
104 const char *pos;
105
106 if (str == NULL)
107 return FALSE;
108
109 pos = strstr (week, str);
110 if (pos == NULL)
111 return FALSE;
112
113 if (tim != NULL)
114 tim->tm_wday = (pos - week) / 3;
115
116 return TRUE;
117 }
118
119
120
121
122
123
124
125
126
127 static gboolean
128 is_localized_month (const char *month)
129 {
130 int i;
131
132 if (month == NULL)
133 return FALSE;
134
135 for (i = 0;
136 i < 3 && *month != '\0' && !isdigit ((unsigned char) *month)
137 && !iscntrl ((unsigned char) *month) && !ispunct ((unsigned char) *month); i++, month++)
138 ;
139
140 return (i == 3 && *month == '\0');
141 }
142
143
144
145 static gboolean
146 is_time (const char *str, struct tm *tim)
147 {
148 const char *p, *p2;
149
150 if (str == NULL)
151 return FALSE;
152
153 p = strchr (str, ':');
154 if (p == NULL)
155 return FALSE;
156
157 p2 = strrchr (str, ':');
158 if (p2 == NULL)
159 return FALSE;
160
161 if (p != p2)
162 {
163 if (sscanf (str, "%2d:%2d:%2d", &tim->tm_hour, &tim->tm_min, &tim->tm_sec) != 3)
164 return FALSE;
165 }
166 else
167 {
168 if (sscanf (str, "%2d:%2d", &tim->tm_hour, &tim->tm_min) != 2)
169 return FALSE;
170 }
171
172 return TRUE;
173 }
174
175
176
177 static gboolean
178 is_year (char *str, struct tm *tim)
179 {
180 long year;
181
182 if (str == NULL)
183 return FALSE;
184
185 if (strchr (str, ':') != NULL)
186 return FALSE;
187
188 if (strlen (str) != 4)
189 return FALSE;
190
191
192 if (sscanf (str, "%ld", &year) != 1)
193 return FALSE;
194
195 if (year < 1900 || year > 3000)
196 return FALSE;
197
198 tim->tm_year = (int) (year - 1900);
199
200 return TRUE;
201 }
202
203
204
205
206
207 gboolean
208 vfs_parse_filetype (const char *s, size_t *ret_skipped, mode_t *ret_type)
209 {
210 mode_t type;
211
212 switch (*s)
213 {
214 case 'd':
215 type = S_IFDIR;
216 break;
217 case 'b':
218 type = S_IFBLK;
219 break;
220 case 'c':
221 type = S_IFCHR;
222 break;
223 case 'l':
224 type = S_IFLNK;
225 break;
226 #ifdef S_IFSOCK
227 case 's':
228 type = S_IFSOCK;
229 break;
230 #else
231 case 's':
232 type = S_IFIFO;
233 break;
234 #endif
235 #ifdef S_IFDOOR
236 case 'D':
237 type = S_IFDOOR;
238 break;
239 #else
240 case 'D':
241 type = S_IFIFO;
242 break;
243 #endif
244 case 'p':
245 type = S_IFIFO;
246 break;
247 #ifdef S_IFNAM
248 case 'n':
249 type = S_IFNAM;
250 break;
251 #else
252 case 'n':
253 type = S_IFREG;
254 break;
255 #endif
256 case 'm':
257 case '-':
258 case '?':
259 type = S_IFREG;
260 break;
261 default:
262 return FALSE;
263 }
264
265 *ret_type = type;
266
267 if (ret_skipped != NULL)
268 *ret_skipped = 1;
269 return TRUE;
270 }
271
272
273
274 gboolean
275 vfs_parse_fileperms (const char *s, size_t *ret_skipped, mode_t *ret_perms)
276 {
277 const char *p = s;
278 mode_t perms = 0;
279
280 switch (*p++)
281 {
282 case '-':
283 break;
284 case 'r':
285 perms |= S_IRUSR;
286 break;
287 default:
288 return FALSE;
289 }
290
291 switch (*p++)
292 {
293 case '-':
294 break;
295 case 'w':
296 perms |= S_IWUSR;
297 break;
298 default:
299 return FALSE;
300 }
301
302 switch (*p++)
303 {
304 case '-':
305 break;
306 case 'S':
307 perms |= S_ISUID;
308 break;
309 case 's':
310 perms |= S_IXUSR | S_ISUID;
311 break;
312 case 'x':
313 perms |= S_IXUSR;
314 break;
315 default:
316 return FALSE;
317 }
318
319 switch (*p++)
320 {
321 case '-':
322 break;
323 case 'r':
324 perms |= S_IRGRP;
325 break;
326 default:
327 return FALSE;
328 }
329
330 switch (*p++)
331 {
332 case '-':
333 break;
334 case 'w':
335 perms |= S_IWGRP;
336 break;
337 default:
338 return FALSE;
339 }
340
341 switch (*p++)
342 {
343 case '-':
344 break;
345 case 'S':
346 perms |= S_ISGID;
347 break;
348 case 'l':
349 perms |= S_ISGID;
350 break;
351 case 's':
352 perms |= S_IXGRP | S_ISGID;
353 break;
354 case 'x':
355 perms |= S_IXGRP;
356 break;
357 default:
358 return FALSE;
359 }
360
361 switch (*p++)
362 {
363 case '-':
364 break;
365 case 'r':
366 perms |= S_IROTH;
367 break;
368 default:
369 return FALSE;
370 }
371
372 switch (*p++)
373 {
374 case '-':
375 break;
376 case 'w':
377 perms |= S_IWOTH;
378 break;
379 default:
380 return FALSE;
381 }
382
383 switch (*p++)
384 {
385 case '-':
386 break;
387 case 'T':
388 perms |= S_ISVTX;
389 break;
390 case 't':
391 perms |= S_IXOTH | S_ISVTX;
392 break;
393 case 'x':
394 perms |= S_IXOTH;
395 break;
396 default:
397 return FALSE;
398 }
399
400 if (*p == '+')
401
402 p++;
403
404 if (ret_skipped != NULL)
405 *ret_skipped = p - s;
406 *ret_perms = perms;
407
408 return TRUE;
409 }
410
411
412
413 gboolean
414 vfs_parse_filemode (const char *s, size_t *ret_skipped, mode_t *ret_mode)
415 {
416 const char *p = s;
417 mode_t type, perms;
418 size_t skipped;
419
420 if (!vfs_parse_filetype (p, &skipped, &type))
421 return FALSE;
422
423 p += skipped;
424 if (!vfs_parse_fileperms (p, &skipped, &perms))
425 return FALSE;
426
427 p += skipped;
428 *ret_skipped = p - s;
429 *ret_mode = type | perms;
430
431 return TRUE;
432 }
433
434
435
436 gboolean
437 vfs_parse_raw_filemode (const char *s, size_t *ret_skipped, mode_t *ret_mode)
438 {
439 const char *p = s;
440 mode_t remote_type = 0, local_type, perms = 0;
441
442
443 for (; *p >= '0' && *p <= '7'; p++)
444 {
445 perms *= 010;
446 perms += (*p - '0');
447 }
448
449 if (*p++ != ' ')
450 return FALSE;
451
452 for (; *p >= '0' && *p <= '7'; p++)
453 {
454 remote_type *= 010;
455 remote_type += (*p - '0');
456 }
457
458 if (*p++ != ' ')
459 return FALSE;
460
461
462
463
464
465
466
467
468
469 switch (remote_type)
470 {
471 case 020000:
472 local_type = S_IFCHR;
473 break;
474 case 040000:
475 local_type = S_IFDIR;
476 break;
477 case 060000:
478 local_type = S_IFBLK;
479 break;
480 case 0120000:
481 local_type = S_IFLNK;
482 break;
483 case 0100000:
484 default:
485 local_type = S_IFREG;
486 break;
487 }
488
489 *ret_skipped = p - s;
490 *ret_mode = local_type | perms;
491
492 return TRUE;
493 }
494
495
496
497 gboolean
498 vfs_parse_month (const char *str, struct tm *tim)
499 {
500 static const char *month = "JanFebMarAprMayJunJulAugSepOctNovDec";
501 const char *pos;
502
503 if (str == NULL)
504 return FALSE;
505
506 pos = strstr (month, str);
507 if (pos == NULL)
508 return FALSE;
509
510 if (tim != NULL)
511 tim->tm_mon = (pos - month) / 3;
512
513 return TRUE;
514 }
515
516
517
518
519 int
520 vfs_parse_filedate (int idx, time_t *t)
521 {
522 char *p;
523 struct tm tim;
524 int d[3];
525 gboolean got_year = FALSE;
526 gboolean l10n = FALSE;
527 time_t current_time;
528 struct tm *local_time;
529
530
531 current_time = time (NULL);
532 local_time = localtime (¤t_time);
533 tim.tm_mday = local_time->tm_mday;
534 tim.tm_mon = local_time->tm_mon;
535 tim.tm_year = local_time->tm_year;
536
537 tim.tm_hour = 0;
538 tim.tm_min = 0;
539 tim.tm_sec = 0;
540 tim.tm_isdst = -1;
541
542 p = columns[idx++];
543
544
545 if (is_week (p, &tim))
546 p = columns[idx++];
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575 if (vfs_parse_month (p, &tim))
576 {
577
578 if (!is_num (idx))
579 return 0;
580
581 tim.tm_mday = (int) atol (columns[idx++]);
582
583 }
584 else if (is_dos_date (p))
585 {
586
587 p[2] = p[5] = '-';
588
589
590 if (sscanf (p, "%2d-%2d-%d", &d[0], &d[1], &d[2]) != 3)
591 return 0;
592
593
594 if (d[0] > 0)
595 d[0]--;
596
597 if (d[2] > 1900)
598 d[2] -= 1900;
599 else if (d[2] < 70)
600
601 d[2] += 100;
602
603 tim.tm_mon = d[0];
604 tim.tm_mday = d[1];
605 tim.tm_year = d[2];
606 got_year = TRUE;
607 }
608 else if (is_localized_month (p) && is_num (idx++))
609
610 l10n = TRUE;
611 else
612 return 0;
613
614
615 if (!is_num (idx)
616 || !(is_time (columns[idx], &tim) || (got_year = is_year (columns[idx], &tim))))
617 return 0;
618
619 idx++;
620
621
622
623
624
625
626
627 if (!got_year && local_time->tm_mon < 6 && local_time->tm_mon < tim.tm_mon
628 && tim.tm_mon - local_time->tm_mon >= 6)
629 tim.tm_year--;
630
631 *t = mktime (&tim);
632 if (l10n || (*t < 0))
633 *t = 0;
634
635 return idx;
636 }
637
638
639
640 int
641 vfs_split_text (char *p)
642 {
643 char *original = p;
644 int numcols;
645
646 memset (columns, 0, sizeof (columns));
647
648 for (numcols = 0; *p != '\0' && numcols < MAXCOLS; numcols++)
649 {
650 for (; *p == ' ' || *p == '\r' || *p == '\n'; p++)
651 *p = '\0';
652
653 columns[numcols] = p;
654 column_ptr[numcols] = p - original;
655
656 for (; *p != '\0' && *p != ' ' && *p != '\r' && *p != '\n'; p++)
657 ;
658 }
659
660 return numcols;
661 }
662
663
664
665 void
666 vfs_parse_ls_lga_init (void)
667 {
668 vfs_parse_ls_final_num_spaces = 1;
669 }
670
671
672
673 size_t
674 vfs_parse_ls_lga_get_final_spaces (void)
675 {
676 return vfs_parse_ls_final_num_spaces;
677 }
678
679
680
681 gboolean
682 vfs_parse_ls_lga (const char *p, struct stat *s, char **filename, char **linkname,
683 size_t *num_spaces)
684 {
685 int idx, idx2, num_cols;
686 int i;
687 char *p_copy = NULL;
688 char *t = NULL;
689 const char *line = p;
690 size_t skipped;
691
692 if (strncmp (p, "total", 5) == 0)
693 return FALSE;
694
695 if (!vfs_parse_filetype (p, &skipped, &s->st_mode))
696 goto error;
697
698 p += skipped;
699 if (*p == ' ')
700 p++;
701 if (*p == '[')
702 {
703 if (strlen (p) <= 8 || p[8] != ']')
704 goto error;
705
706
707 if (S_ISDIR (s->st_mode))
708 s->st_mode |= (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IXUSR | S_IXGRP | S_IXOTH);
709 else
710 s->st_mode |= (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR);
711 p += 9;
712 }
713 else
714 {
715 size_t lc_skipped;
716 mode_t perms;
717
718 if (!vfs_parse_fileperms (p, &lc_skipped, &perms))
719 goto error;
720
721 p += lc_skipped;
722 s->st_mode |= perms;
723 }
724
725 p_copy = g_strdup (p);
726 num_cols = vfs_split_text (p_copy);
727
728 s->st_nlink = atol (columns[0]);
729 if (s->st_nlink <= 0)
730 goto error;
731
732 if (!is_num (1))
733 s->st_uid = vfs_finduid (columns[1]);
734 else
735 s->st_uid = (uid_t) atol (columns[1]);
736
737
738 for (idx = 3; idx <= 5; idx++)
739 if (vfs_parse_month (columns[idx], NULL) || is_week (columns[idx], NULL)
740 || is_dos_date (columns[idx]) || is_localized_month (columns[idx]))
741 break;
742
743 if (idx == 6 || (idx == 5 && !S_ISCHR (s->st_mode) && !S_ISBLK (s->st_mode)))
744 goto error;
745
746
747 if (idx == 3 || (idx == 4 && (S_ISCHR (s->st_mode) || S_ISBLK (s->st_mode))))
748 idx2 = 2;
749 else
750 {
751
752 if (is_num (2))
753 s->st_gid = (gid_t) atol (columns[2]);
754 else
755 s->st_gid = vfs_findgid (columns[2]);
756 idx2 = 3;
757 }
758
759
760 if (S_ISCHR (s->st_mode) || S_ISBLK (s->st_mode))
761 {
762 int maj, min;
763
764
765 if (!is_num (idx2) && idx2 == 2)
766 {
767
768 if (!is_num (++idx2) || sscanf (columns[idx2], " %d,%d", &maj, &min) != 2)
769 goto error;
770 }
771 else
772 {
773
774 if (!is_num (idx2) || sscanf (columns[idx2], " %d,", &maj) != 1)
775 goto error;
776
777
778 if (!is_num (++idx2) || sscanf (columns[idx2], " %d", &min) != 1)
779 goto error;
780 }
781 #ifdef HAVE_STRUCT_STAT_ST_RDEV
782 s->st_rdev = makedev (maj, min);
783 #endif
784 s->st_size = 0;
785
786 }
787 else
788 {
789
790 if (!is_num (idx2))
791 goto error;
792
793 s->st_size = (off_t) g_ascii_strtoll (columns[idx2], NULL, 10);
794 #ifdef HAVE_STRUCT_STAT_ST_RDEV
795 s->st_rdev = 0;
796 #endif
797 }
798
799 vfs_zero_stat_times (s);
800
801 idx = vfs_parse_filedate (idx, &s->st_mtime);
802 if (idx == 0)
803 goto error;
804
805
806 s->st_atime = s->st_ctime = s->st_mtime;
807
808
809 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
810 s->st_blksize = 512;
811 #endif
812 vfs_adjust_stat (s);
813
814 if (num_spaces != NULL)
815 {
816 *num_spaces = column_ptr[idx] - column_ptr[idx - 1] - strlen (columns[idx - 1]);
817 if (DIR_IS_DOTDOT (columns[idx]))
818 vfs_parse_ls_final_num_spaces = *num_spaces;
819 }
820
821 for (i = idx + 1, idx2 = 0; i < num_cols; i++)
822 if (strcmp (columns[i], "->") == 0)
823 {
824 idx2 = i;
825 break;
826 }
827
828 if (((S_ISLNK (s->st_mode) || (num_cols == idx + 3 && s->st_nlink > 1)))
829 && idx2 != 0)
830 {
831 if (filename != NULL)
832 *filename = g_strndup (p + column_ptr[idx], column_ptr[idx2] - column_ptr[idx] - 1);
833
834 if (linkname != NULL)
835 {
836 t = g_strdup (p + column_ptr[idx2 + 1]);
837 *linkname = t;
838 }
839 }
840 else
841 {
842
843
844
845 if (filename != NULL)
846 {
847
848 t = g_strdup (p + column_ptr[idx]);
849 *filename = t;
850 }
851
852 if (linkname != NULL)
853 *linkname = NULL;
854 }
855
856 if (t != NULL)
857 {
858 size_t p2;
859
860 p2 = strlen (t);
861 if (--p2 > 0 && (t[p2] == '\r' || t[p2] == '\n'))
862 t[p2] = '\0';
863 if (--p2 > 0 && (t[p2] == '\r' || t[p2] == '\n'))
864 t[p2] = '\0';
865 }
866
867 g_free (p_copy);
868 return TRUE;
869
870 error:
871 {
872 static int errorcount = 0;
873
874 if (++errorcount < 5)
875 message (D_ERROR, _("Cannot parse:"), "%s",
876 (p_copy != NULL && *p_copy != '\0') ? p_copy : line);
877 else if (errorcount == 5)
878 message (D_ERROR, MSG_ERROR, _("More parsing errors will be ignored."));
879 }
880
881 g_free (p_copy);
882 return FALSE;
883 }
884
885