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 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 else if (is_dos_date (p))
584 {
585
586 p[2] = p[5] = '-';
587
588 if (sscanf (p, "%2d-%2d-%d", &d[0], &d[1], &d[2]) != 3)
589 return 0;
590
591
592 if (d[0] > 0)
593 d[0]--;
594
595 if (d[2] > 1900)
596 d[2] -= 1900;
597 else if (d[2] < 70)
598
599 d[2] += 100;
600
601 tim.tm_mon = d[0];
602 tim.tm_mday = d[1];
603 tim.tm_year = d[2];
604 got_year = TRUE;
605 }
606 else if (is_localized_month (p) && is_num (idx++))
607
608 l10n = TRUE;
609 else
610 return 0;
611
612
613 if (!is_num (idx)
614 || !(is_time (columns[idx], &tim) || (got_year = is_year (columns[idx], &tim))))
615 return 0;
616
617 idx++;
618
619
620
621
622
623
624
625 if (!got_year && local_time->tm_mon < 6 && local_time->tm_mon < tim.tm_mon
626 && tim.tm_mon - local_time->tm_mon >= 6)
627 tim.tm_year--;
628
629 *t = mktime (&tim);
630 if (l10n || (*t < 0))
631 *t = 0;
632
633 return idx;
634 }
635
636
637
638 int
639 vfs_split_text (char *p)
640 {
641 char *original = p;
642 int numcols;
643
644 memset (columns, 0, sizeof (columns));
645
646 for (numcols = 0; *p != '\0' && numcols < MAXCOLS; numcols++)
647 {
648 for (; *p == ' ' || *p == '\r' || *p == '\n'; p++)
649 *p = '\0';
650
651 columns[numcols] = p;
652 column_ptr[numcols] = p - original;
653
654 for (; *p != '\0' && *p != ' ' && *p != '\r' && *p != '\n'; p++)
655 ;
656 }
657
658 return numcols;
659 }
660
661
662
663 void
664 vfs_parse_ls_lga_init (void)
665 {
666 vfs_parse_ls_final_num_spaces = 1;
667 }
668
669
670
671 size_t
672 vfs_parse_ls_lga_get_final_spaces (void)
673 {
674 return vfs_parse_ls_final_num_spaces;
675 }
676
677
678
679 gboolean
680 vfs_parse_ls_lga (const char *p, struct stat *s, char **filename, char **linkname,
681 size_t *num_spaces)
682 {
683 int idx, idx2, num_cols;
684 int i;
685 char *p_copy = NULL;
686 char *t = NULL;
687 const char *line = p;
688 size_t skipped;
689
690 if (strncmp (p, "total", 5) == 0)
691 return FALSE;
692
693 if (!vfs_parse_filetype (p, &skipped, &s->st_mode))
694 goto error;
695
696 p += skipped;
697 if (*p == ' ')
698 p++;
699 if (*p == '[')
700 {
701 if (strlen (p) <= 8 || p[8] != ']')
702 goto error;
703
704
705 if (S_ISDIR (s->st_mode))
706 s->st_mode |= (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IXUSR | S_IXGRP | S_IXOTH);
707 else
708 s->st_mode |= (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR);
709 p += 9;
710 }
711 else
712 {
713 size_t lc_skipped;
714 mode_t perms;
715
716 if (!vfs_parse_fileperms (p, &lc_skipped, &perms))
717 goto error;
718
719 p += lc_skipped;
720 s->st_mode |= perms;
721 }
722
723 p_copy = g_strdup (p);
724 num_cols = vfs_split_text (p_copy);
725
726 s->st_nlink = atol (columns[0]);
727 if (s->st_nlink <= 0)
728 goto error;
729
730 if (!is_num (1))
731 s->st_uid = vfs_finduid (columns[1]);
732 else
733 s->st_uid = (uid_t) atol (columns[1]);
734
735
736 for (idx = 3; idx <= 5; idx++)
737 if (vfs_parse_month (columns[idx], NULL) || is_week (columns[idx], NULL)
738 || is_dos_date (columns[idx]) || is_localized_month (columns[idx]))
739 break;
740
741 if (idx == 6 || (idx == 5 && !S_ISCHR (s->st_mode) && !S_ISBLK (s->st_mode)))
742 goto error;
743
744
745 if (idx == 3 || (idx == 4 && (S_ISCHR (s->st_mode) || S_ISBLK (s->st_mode))))
746 idx2 = 2;
747 else
748 {
749
750 if (is_num (2))
751 s->st_gid = (gid_t) atol (columns[2]);
752 else
753 s->st_gid = vfs_findgid (columns[2]);
754 idx2 = 3;
755 }
756
757
758 if (S_ISCHR (s->st_mode) || S_ISBLK (s->st_mode))
759 {
760 int maj, min;
761
762
763 if (!is_num (idx2) && idx2 == 2)
764 {
765 if (!is_num (++idx2) || sscanf (columns[idx2], " %d,%d", &maj, &min) != 2)
766 goto error;
767 }
768 else
769 {
770 if (!is_num (idx2) || sscanf (columns[idx2], " %d,", &maj) != 1)
771 goto error;
772
773 if (!is_num (++idx2) || sscanf (columns[idx2], " %d", &min) != 1)
774 goto error;
775 }
776 #ifdef HAVE_STRUCT_STAT_ST_RDEV
777 s->st_rdev = makedev (maj, min);
778 #endif
779 s->st_size = 0;
780 }
781 else
782 {
783
784 if (!is_num (idx2))
785 goto error;
786
787 s->st_size = (off_t) g_ascii_strtoll (columns[idx2], NULL, 10);
788 #ifdef HAVE_STRUCT_STAT_ST_RDEV
789 s->st_rdev = 0;
790 #endif
791 }
792
793 vfs_zero_stat_times (s);
794
795 idx = vfs_parse_filedate (idx, &s->st_mtime);
796 if (idx == 0)
797 goto error;
798
799
800 s->st_atime = s->st_ctime = s->st_mtime;
801
802
803 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
804 s->st_blksize = 512;
805 #endif
806 vfs_adjust_stat (s);
807
808 if (num_spaces != NULL)
809 {
810 *num_spaces = column_ptr[idx] - column_ptr[idx - 1] - strlen (columns[idx - 1]);
811 if (DIR_IS_DOTDOT (columns[idx]))
812 vfs_parse_ls_final_num_spaces = *num_spaces;
813 }
814
815 for (i = idx + 1, idx2 = 0; i < num_cols; i++)
816 if (strcmp (columns[i], "->") == 0)
817 {
818 idx2 = i;
819 break;
820 }
821
822 if (((S_ISLNK (s->st_mode)
823 || (num_cols == idx + 3 && s->st_nlink > 1)))
824 && idx2 != 0)
825 {
826 if (filename != NULL)
827 *filename = g_strndup (p + column_ptr[idx], column_ptr[idx2] - column_ptr[idx] - 1);
828
829 if (linkname != NULL)
830 {
831 t = g_strdup (p + column_ptr[idx2 + 1]);
832 *linkname = t;
833 }
834 }
835 else
836 {
837
838
839
840 if (filename != NULL)
841 {
842
843 t = g_strdup (p + column_ptr[idx]);
844 *filename = t;
845 }
846
847 if (linkname != NULL)
848 *linkname = NULL;
849 }
850
851 str_rstrip_eol (t);
852
853 g_free (p_copy);
854 return TRUE;
855
856 error:
857 {
858 static int errorcount = 0;
859
860 if (++errorcount < 5)
861 message (D_ERROR, _ ("Cannot parse:"), "%s",
862 (p_copy != NULL && *p_copy != '\0') ? p_copy : line);
863 else if (errorcount == 5)
864 message (D_ERROR, MSG_ERROR, _ ("More parsing errors will be ignored."));
865 }
866
867 g_free (p_copy);
868 return FALSE;
869 }
870
871