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/strutil.h"
44 #include "lib/unixcompat.h"
45 #include "lib/widget.h"
46
47 #include "utilvfs.h"
48
49
50
51
52
53
54 #define MAXCOLS 30
55
56
57
58
59
60
61
62 static char *columns[MAXCOLS];
63 static int column_ptr[MAXCOLS];
64 static size_t vfs_parse_ls_final_num_spaces = 0;
65
66
67
68
69
70 static gboolean
71 is_num (int idx)
72 {
73 char *column = columns[idx];
74
75 return (column != NULL && isdigit (column[0]));
76 }
77
78
79
80
81 static gboolean
82 is_dos_date (const char *str)
83 {
84 size_t len;
85
86 if (str == NULL)
87 return FALSE;
88
89 len = strlen (str);
90 if (len != 8 && len != 10)
91 return FALSE;
92
93 if (str[2] != str[5])
94 return FALSE;
95
96 return (strchr ("\\-/", (int) str[2]) != NULL);
97 }
98
99
100
101 static gboolean
102 is_week (const char *str, struct tm *tim)
103 {
104 static const char *week = "SunMonTueWedThuFriSat";
105 const char *pos;
106
107 if (str == NULL)
108 return FALSE;
109
110 pos = strstr (week, str);
111 if (pos == NULL)
112 return FALSE;
113
114 if (tim != NULL)
115 tim->tm_wday = (pos - week) / 3;
116
117 return TRUE;
118 }
119
120
121
122
123
124
125
126
127
128 static gboolean
129 is_localized_month (const char *month)
130 {
131 int i;
132
133 if (month == NULL)
134 return FALSE;
135
136 for (i = 0; i < 3 && *month != '\0' && !isdigit ((unsigned char) *month)
137 && !iscntrl ((unsigned char) *month) && !ispunct ((unsigned char) *month);
138 i++, month++)
139 ;
140
141 return (i == 3 && *month == '\0');
142 }
143
144
145
146 static gboolean
147 is_time (const char *str, struct tm *tim)
148 {
149 const char *p, *p2;
150
151 if (str == NULL)
152 return FALSE;
153
154 p = strchr (str, ':');
155 if (p == NULL)
156 return FALSE;
157
158 p2 = strrchr (str, ':');
159 if (p2 == NULL)
160 return FALSE;
161
162 if (p != p2)
163 {
164 if (sscanf (str, "%2d:%2d:%2d", &tim->tm_hour, &tim->tm_min, &tim->tm_sec) != 3)
165 return FALSE;
166 }
167 else
168 {
169 if (sscanf (str, "%2d:%2d", &tim->tm_hour, &tim->tm_min) != 2)
170 return FALSE;
171 }
172
173 return TRUE;
174 }
175
176
177
178 static gboolean
179 is_year (char *str, struct tm *tim)
180 {
181 long year;
182
183 if (str == NULL)
184 return FALSE;
185
186 if (strchr (str, ':') != NULL)
187 return FALSE;
188
189 if (strlen (str) != 4)
190 return FALSE;
191
192
193 if (sscanf (str, "%ld", &year) != 1)
194 return FALSE;
195
196 if (year < 1900 || year > 3000)
197 return FALSE;
198
199 tim->tm_year = (int) (year - 1900);
200
201 return TRUE;
202 }
203
204
205
206
207
208 gboolean
209 vfs_parse_filetype (const char *s, size_t *ret_skipped, mode_t *ret_type)
210 {
211 mode_t type;
212
213 switch (*s)
214 {
215 case 'd':
216 type = S_IFDIR;
217 break;
218 case 'b':
219 type = S_IFBLK;
220 break;
221 case 'c':
222 type = S_IFCHR;
223 break;
224 case 'l':
225 type = S_IFLNK;
226 break;
227 #ifdef S_IFSOCK
228 case 's':
229 type = S_IFSOCK;
230 break;
231 #else
232 case 's':
233 type = S_IFIFO;
234 break;
235 #endif
236 #ifdef S_IFDOOR
237 case 'D':
238 type = S_IFDOOR;
239 break;
240 #else
241 case 'D':
242 type = S_IFIFO;
243 break;
244 #endif
245 case 'p':
246 type = S_IFIFO;
247 break;
248 #ifdef S_IFNAM
249 case 'n':
250 type = S_IFNAM;
251 break;
252 #else
253 case 'n':
254 type = S_IFREG;
255 break;
256 #endif
257 case 'm':
258 case '-':
259 case '?':
260 type = S_IFREG;
261 break;
262 default:
263 return FALSE;
264 }
265
266 *ret_type = type;
267
268 if (ret_skipped != NULL)
269 *ret_skipped = 1;
270 return TRUE;
271 }
272
273
274
275 gboolean
276 vfs_parse_fileperms (const char *s, size_t *ret_skipped, mode_t *ret_perms)
277 {
278 const char *p = s;
279 mode_t perms = 0;
280
281 switch (*p++)
282 {
283 case '-':
284 break;
285 case 'r':
286 perms |= S_IRUSR;
287 break;
288 default:
289 return FALSE;
290 }
291
292 switch (*p++)
293 {
294 case '-':
295 break;
296 case 'w':
297 perms |= S_IWUSR;
298 break;
299 default:
300 return FALSE;
301 }
302
303 switch (*p++)
304 {
305 case '-':
306 break;
307 case 'S':
308 perms |= S_ISUID;
309 break;
310 case 's':
311 perms |= S_IXUSR | S_ISUID;
312 break;
313 case 'x':
314 perms |= S_IXUSR;
315 break;
316 default:
317 return FALSE;
318 }
319
320 switch (*p++)
321 {
322 case '-':
323 break;
324 case 'r':
325 perms |= S_IRGRP;
326 break;
327 default:
328 return FALSE;
329 }
330
331 switch (*p++)
332 {
333 case '-':
334 break;
335 case 'w':
336 perms |= S_IWGRP;
337 break;
338 default:
339 return FALSE;
340 }
341
342 switch (*p++)
343 {
344 case '-':
345 break;
346 case 'S':
347 perms |= S_ISGID;
348 break;
349 case 'l':
350 perms |= S_ISGID;
351 break;
352 case 's':
353 perms |= S_IXGRP | S_ISGID;
354 break;
355 case 'x':
356 perms |= S_IXGRP;
357 break;
358 default:
359 return FALSE;
360 }
361
362 switch (*p++)
363 {
364 case '-':
365 break;
366 case 'r':
367 perms |= S_IROTH;
368 break;
369 default:
370 return FALSE;
371 }
372
373 switch (*p++)
374 {
375 case '-':
376 break;
377 case 'w':
378 perms |= S_IWOTH;
379 break;
380 default:
381 return FALSE;
382 }
383
384 switch (*p++)
385 {
386 case '-':
387 break;
388 case 'T':
389 perms |= S_ISVTX;
390 break;
391 case 't':
392 perms |= S_IXOTH | S_ISVTX;
393 break;
394 case 'x':
395 perms |= S_IXOTH;
396 break;
397 default:
398 return FALSE;
399 }
400
401 if (*p == '+')
402
403 p++;
404
405 if (ret_skipped != NULL)
406 *ret_skipped = p - s;
407 *ret_perms = perms;
408
409 return TRUE;
410 }
411
412
413
414 gboolean
415 vfs_parse_filemode (const char *s, size_t *ret_skipped, mode_t *ret_mode)
416 {
417 const char *p = s;
418 mode_t type, perms;
419 size_t skipped;
420
421 if (!vfs_parse_filetype (p, &skipped, &type))
422 return FALSE;
423
424 p += skipped;
425 if (!vfs_parse_fileperms (p, &skipped, &perms))
426 return FALSE;
427
428 p += skipped;
429 *ret_skipped = p - s;
430 *ret_mode = type | perms;
431
432 return TRUE;
433 }
434
435
436
437 gboolean
438 vfs_parse_raw_filemode (const char *s, size_t *ret_skipped, mode_t *ret_mode)
439 {
440 const char *p = s;
441 mode_t remote_type = 0, local_type, perms = 0;
442
443
444 for (; *p >= '0' && *p <= '7'; p++)
445 {
446 perms *= 010;
447 perms += (*p - '0');
448 }
449
450 if (*p++ != ' ')
451 return FALSE;
452
453 for (; *p >= '0' && *p <= '7'; p++)
454 {
455 remote_type *= 010;
456 remote_type += (*p - '0');
457 }
458
459 if (*p++ != ' ')
460 return FALSE;
461
462
463
464
465
466
467
468
469
470 switch (remote_type)
471 {
472 case 020000:
473 local_type = S_IFCHR;
474 break;
475 case 040000:
476 local_type = S_IFDIR;
477 break;
478 case 060000:
479 local_type = S_IFBLK;
480 break;
481 case 0120000:
482 local_type = S_IFLNK;
483 break;
484 case 0100000:
485 default:
486 local_type = S_IFREG;
487 break;
488 }
489
490 *ret_skipped = p - s;
491 *ret_mode = local_type | perms;
492
493 return TRUE;
494 }
495
496
497
498 gboolean
499 vfs_parse_month (const char *str, struct tm *tim)
500 {
501 static const char *month = "JanFebMarAprMayJunJulAugSepOctNovDec";
502 const char *pos;
503
504 if (str == NULL)
505 return FALSE;
506
507 pos = strstr (month, str);
508 if (pos == NULL)
509 return FALSE;
510
511 if (tim != NULL)
512 tim->tm_mon = (pos - month) / 3;
513
514 return TRUE;
515 }
516
517
518
519
520 int
521 vfs_parse_filedate (int idx, time_t *t)
522 {
523 char *p;
524 struct tm tim;
525 int d[3];
526 gboolean got_year = FALSE;
527 gboolean l10n = FALSE;
528 time_t current_time;
529 struct tm *local_time;
530
531
532 current_time = time (NULL);
533 local_time = localtime (¤t_time);
534 tim.tm_mday = local_time->tm_mday;
535 tim.tm_mon = local_time->tm_mon;
536 tim.tm_year = local_time->tm_year;
537
538 tim.tm_hour = 0;
539 tim.tm_min = 0;
540 tim.tm_sec = 0;
541 tim.tm_isdst = -1;
542
543 p = columns[idx++];
544
545
546 if (is_week (p, &tim))
547 p = columns[idx++];
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
576 if (vfs_parse_month (p, &tim))
577 {
578
579 if (!is_num (idx))
580 return 0;
581
582 tim.tm_mday = (int) atol (columns[idx++]);
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 else
787 {
788
789 if (!is_num (idx2))
790 goto error;
791
792 s->st_size = (off_t) g_ascii_strtoll (columns[idx2], NULL, 10);
793 #ifdef HAVE_STRUCT_STAT_ST_RDEV
794 s->st_rdev = 0;
795 #endif
796 }
797
798 vfs_zero_stat_times (s);
799
800 idx = vfs_parse_filedate (idx, &s->st_mtime);
801 if (idx == 0)
802 goto error;
803
804
805 s->st_atime = s->st_ctime = s->st_mtime;
806
807
808 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
809 s->st_blksize = 512;
810 #endif
811 vfs_adjust_stat (s);
812
813 if (num_spaces != NULL)
814 {
815 *num_spaces = column_ptr[idx] - column_ptr[idx - 1] - strlen (columns[idx - 1]);
816 if (DIR_IS_DOTDOT (columns[idx]))
817 vfs_parse_ls_final_num_spaces = *num_spaces;
818 }
819
820 for (i = idx + 1, idx2 = 0; i < num_cols; i++)
821 if (strcmp (columns[i], "->") == 0)
822 {
823 idx2 = i;
824 break;
825 }
826
827 if (((S_ISLNK (s->st_mode)
828 || (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 str_rstrip_eol (t);
857
858 g_free (p_copy);
859 return TRUE;
860
861 error:
862 {
863 static int errorcount = 0;
864
865 if (++errorcount < 5)
866 message (D_ERROR, _ ("Cannot parse:"), "%s",
867 (p_copy != NULL && *p_copy != '\0') ? p_copy : line);
868 else if (errorcount == 5)
869 message (D_ERROR, MSG_ERROR, _ ("More parsing errors will be ignored."));
870 }
871
872 g_free (p_copy);
873 return FALSE;
874 }
875
876