This source file includes following definitions.
- key_collate
- clean_sort_keys
- handle_dirent
- dir_get_dotdot_stat
- alloc_dir_copy
- dir_list_grow
- dir_list_append
- unsorted
- sort_name
- sort_vers
- sort_ext
- sort_time
- sort_ctime
- sort_atime
- sort_inode
- sort_size
- dir_list_sort
- dir_list_clean
- dir_list_free_list
- dir_list_init
- handle_path
- dir_list_load
- if_link_is_exe
- dir_list_reload
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 #include <config.h>
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/stat.h>
37
38 #include "lib/global.h"
39 #include "lib/tty/tty.h"
40 #include "lib/search.h"
41 #include "lib/vfs/vfs.h"
42 #include "lib/fs.h"
43 #include "lib/strutil.h"
44 #include "lib/util.h"
45
46 #include "src/setup.h"
47
48 #include "treestore.h"
49 #include "file.h"
50 #include "dir.h"
51
52
53
54
55
56 #define MY_ISDIR(x) (\
57 (is_exe (x->st.st_mode) && !(S_ISDIR (x->st.st_mode) || link_isdir (x)) && exec_first) \
58 ? 1 \
59 : ( (S_ISDIR (x->st.st_mode) || link_isdir (x)) ? 2 : 0) )
60
61
62
63
64
65
66 static int reverse = 1;
67
68
69 static gboolean case_sensitive = OS_SORT_CASE_SENSITIVE_DEFAULT;
70
71
72 static gboolean exec_first = TRUE;
73
74 static dir_list dir_copy = { NULL, 0, 0, NULL };
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92 static inline int
93 key_collate (const char *t1, const char *t2)
94 {
95 int dotdot = 0;
96 int ret;
97
98 dotdot = (t1[0] == '.' ? 1 : 0) | ((t2[0] == '.' ? 1 : 0) << 1);
99
100 switch (dotdot)
101 {
102 case 0:
103 case 3:
104 ret = str_key_collate (t1, t2, case_sensitive) * reverse;
105 break;
106 case 1:
107 ret = -1;
108 break;
109 case 2:
110 ret = 1;
111 break;
112 default:
113 ret = 0;
114 }
115
116 return ret;
117 }
118
119
120
121
122
123
124 static void
125 clean_sort_keys (dir_list * list, int start, int count)
126 {
127 int i;
128
129 for (i = 0; i < count; i++)
130 {
131 file_entry_t *fentry;
132
133 fentry = &list->list[i + start];
134 str_release_key (fentry->sort_key, case_sensitive);
135 fentry->sort_key = NULL;
136 str_release_key (fentry->second_sort_key, case_sensitive);
137 fentry->second_sort_key = NULL;
138 }
139 }
140
141
142
143
144
145
146
147 static gboolean
148 handle_dirent (struct vfs_dirent *dp, const char *fltr, struct stat *buf1, gboolean * link_to_dir,
149 gboolean * stale_link)
150 {
151 vfs_path_t *vpath;
152
153 if (DIR_IS_DOT (dp->d_name) || DIR_IS_DOTDOT (dp->d_name))
154 return FALSE;
155 if (!panels_options.show_dot_files && (dp->d_name[0] == '.'))
156 return FALSE;
157 if (!panels_options.show_backups && dp->d_name[strlen (dp->d_name) - 1] == '~')
158 return FALSE;
159
160 vpath = vfs_path_from_str (dp->d_name);
161 if (mc_lstat (vpath, buf1) == -1)
162 {
163
164
165
166
167
168 memset (buf1, 0, sizeof (*buf1));
169 }
170
171 if (S_ISDIR (buf1->st_mode))
172 tree_store_mark_checked (dp->d_name);
173
174
175 *link_to_dir = file_is_symlink_to_dir (vpath, buf1, stale_link);
176
177 vfs_path_free (vpath);
178
179 return (S_ISDIR (buf1->st_mode) || *link_to_dir || fltr == NULL
180 || mc_search (fltr, NULL, dp->d_name, MC_SEARCH_T_GLOB));
181 }
182
183
184
185
186 static gboolean
187 dir_get_dotdot_stat (const vfs_path_t * vpath, struct stat *st)
188 {
189 gboolean ret = FALSE;
190
191 if ((vpath != NULL) && (st != NULL))
192 {
193 const char *path;
194
195 path = vfs_path_get_by_index (vpath, 0)->path;
196 if (path != NULL && *path != '\0')
197 {
198 vfs_path_t *tmp_vpath;
199
200 tmp_vpath = vfs_path_append_new (vpath, "..", (char *) NULL);
201 ret = mc_stat (tmp_vpath, st) == 0;
202 vfs_path_free (tmp_vpath);
203 }
204 }
205
206 return ret;
207 }
208
209
210
211 static void
212 alloc_dir_copy (int size)
213 {
214 if (dir_copy.size < size)
215 {
216 if (dir_copy.list != NULL)
217 dir_list_free_list (&dir_copy);
218
219 dir_copy.list = g_new0 (file_entry_t, size);
220 dir_copy.size = size;
221 dir_copy.len = 0;
222 }
223 }
224
225
226
227
228
229
230
231
232
233
234
235
236
237 gboolean
238 dir_list_grow (dir_list * list, int delta)
239 {
240 int size;
241 gboolean clear_flag = FALSE;
242
243 if (list == NULL)
244 return FALSE;
245
246 if (delta == 0)
247 return TRUE;
248
249 size = list->size + delta;
250 if (size <= 0)
251 {
252 size = DIR_LIST_MIN_SIZE;
253 clear_flag = TRUE;
254 }
255
256 if (size != list->size)
257 {
258 file_entry_t *fe;
259
260 fe = g_try_renew (file_entry_t, list->list, size);
261 if (fe == NULL)
262 return FALSE;
263
264 list->list = fe;
265 list->size = size;
266 }
267
268 list->len = clear_flag ? 0 : MIN (list->len, size);
269
270 return TRUE;
271 }
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286 gboolean
287 dir_list_append (dir_list * list, const char *fname, const struct stat * st,
288 gboolean link_to_dir, gboolean stale_link)
289 {
290 file_entry_t *fentry;
291
292
293 if (list->len == list->size && !dir_list_grow (list, DIR_LIST_RESIZE_STEP))
294 return FALSE;
295
296 fentry = &list->list[list->len];
297 fentry->fnamelen = strlen (fname);
298 fentry->fname = g_strndup (fname, fentry->fnamelen);
299 fentry->f.marked = 0;
300 fentry->f.link_to_dir = link_to_dir ? 1 : 0;
301 fentry->f.stale_link = stale_link ? 1 : 0;
302 fentry->f.dir_size_computed = 0;
303 fentry->st = *st;
304 fentry->sort_key = NULL;
305 fentry->second_sort_key = NULL;
306
307 list->len++;
308
309 return TRUE;
310 }
311
312
313
314 int
315 unsorted (file_entry_t * a, file_entry_t * b)
316 {
317 (void) a;
318 (void) b;
319
320 return 0;
321 }
322
323
324
325 int
326 sort_name (file_entry_t * a, file_entry_t * b)
327 {
328 int ad = MY_ISDIR (a);
329 int bd = MY_ISDIR (b);
330
331 if (ad == bd || panels_options.mix_all_files)
332 {
333
334 if (a->sort_key == NULL)
335 a->sort_key = str_create_key_for_filename (a->fname, case_sensitive);
336 if (b->sort_key == NULL)
337 b->sort_key = str_create_key_for_filename (b->fname, case_sensitive);
338
339 return key_collate (a->sort_key, b->sort_key);
340 }
341
342 return bd - ad;
343 }
344
345
346
347 int
348 sort_vers (file_entry_t * a, file_entry_t * b)
349 {
350 int ad = MY_ISDIR (a);
351 int bd = MY_ISDIR (b);
352
353 if (ad == bd || panels_options.mix_all_files)
354 return filevercmp (a->fname, b->fname) * reverse;
355
356 return bd - ad;
357 }
358
359
360
361 int
362 sort_ext (file_entry_t * a, file_entry_t * b)
363 {
364 int ad = MY_ISDIR (a);
365 int bd = MY_ISDIR (b);
366
367 if (ad == bd || panels_options.mix_all_files)
368 {
369 int r;
370
371 if (a->second_sort_key == NULL)
372 a->second_sort_key = str_create_key (extension (a->fname), case_sensitive);
373 if (b->second_sort_key == NULL)
374 b->second_sort_key = str_create_key (extension (b->fname), case_sensitive);
375
376 r = str_key_collate (a->second_sort_key, b->second_sort_key, case_sensitive);
377 if (r != 0)
378 return r * reverse;
379
380 return sort_name (a, b);
381 }
382
383 return bd - ad;
384 }
385
386
387
388 int
389 sort_time (file_entry_t * a, file_entry_t * b)
390 {
391 int ad = MY_ISDIR (a);
392 int bd = MY_ISDIR (b);
393
394 if (ad == bd || panels_options.mix_all_files)
395 {
396 int result = _GL_CMP (a->st.st_mtime, b->st.st_mtime);
397
398 if (result != 0)
399 return result * reverse;
400
401 return sort_name (a, b);
402 }
403
404 return bd - ad;
405 }
406
407
408
409 int
410 sort_ctime (file_entry_t * a, file_entry_t * b)
411 {
412 int ad = MY_ISDIR (a);
413 int bd = MY_ISDIR (b);
414
415 if (ad == bd || panels_options.mix_all_files)
416 {
417 int result = _GL_CMP (a->st.st_ctime, b->st.st_ctime);
418
419 if (result != 0)
420 return result * reverse;
421
422 return sort_name (a, b);
423 }
424
425 return bd - ad;
426 }
427
428
429
430 int
431 sort_atime (file_entry_t * a, file_entry_t * b)
432 {
433 int ad = MY_ISDIR (a);
434 int bd = MY_ISDIR (b);
435
436 if (ad == bd || panels_options.mix_all_files)
437 {
438 int result = _GL_CMP (a->st.st_atime, b->st.st_atime);
439
440 if (result != 0)
441 return result * reverse;
442
443 return sort_name (a, b);
444 }
445
446 return bd - ad;
447 }
448
449
450
451 int
452 sort_inode (file_entry_t * a, file_entry_t * b)
453 {
454 int ad = MY_ISDIR (a);
455 int bd = MY_ISDIR (b);
456
457 if (ad == bd || panels_options.mix_all_files)
458 return (a->st.st_ino - b->st.st_ino) * reverse;
459
460 return bd - ad;
461 }
462
463
464
465 int
466 sort_size (file_entry_t * a, file_entry_t * b)
467 {
468 int ad = MY_ISDIR (a);
469 int bd = MY_ISDIR (b);
470
471 if (ad == bd || panels_options.mix_all_files)
472 {
473 int result = _GL_CMP (a->st.st_size, b->st.st_size);
474
475 if (result != 0)
476 return result * reverse;
477
478 return sort_name (a, b);
479 }
480
481 return bd - ad;
482 }
483
484
485
486 void
487 dir_list_sort (dir_list * list, GCompareFunc sort, const dir_sort_options_t * sort_op)
488 {
489 if (list->len > 1 && sort != (GCompareFunc) unsorted)
490 {
491 file_entry_t *fentry = &list->list[0];
492 int dot_dot_found;
493
494
495
496 dot_dot_found = DIR_IS_DOTDOT (fentry->fname) ? 1 : 0;
497 reverse = sort_op->reverse ? -1 : 1;
498 case_sensitive = sort_op->case_sensitive ? 1 : 0;
499 exec_first = sort_op->exec_first;
500 qsort (&(list->list)[dot_dot_found], list->len - dot_dot_found, sizeof (file_entry_t),
501 sort);
502
503 clean_sort_keys (list, dot_dot_found, list->len - dot_dot_found);
504 }
505 }
506
507
508
509 void
510 dir_list_clean (dir_list * list)
511 {
512 int i;
513
514 for (i = 0; i < list->len; i++)
515 {
516 file_entry_t *fentry;
517
518 fentry = &list->list[i];
519 MC_PTR_FREE (fentry->fname);
520 }
521
522 list->len = 0;
523
524 dir_list_grow (list, DIR_LIST_MIN_SIZE - list->size);
525 }
526
527
528
529 void
530 dir_list_free_list (dir_list * list)
531 {
532 int i;
533
534 for (i = 0; i < list->len; i++)
535 {
536 file_entry_t *fentry;
537
538 fentry = &list->list[i];
539 g_free (fentry->fname);
540 }
541
542 MC_PTR_FREE (list->list);
543 list->len = 0;
544 list->size = 0;
545 }
546
547
548
549
550 gboolean
551 dir_list_init (dir_list * list)
552 {
553 file_entry_t *fentry;
554
555
556 if (list->size == 0 && !dir_list_grow (list, DIR_LIST_RESIZE_STEP))
557 {
558 list->len = 0;
559 return FALSE;
560 }
561
562 fentry = &list->list[0];
563 memset (fentry, 0, sizeof (*fentry));
564 fentry->fnamelen = 2;
565 fentry->fname = g_strndup ("..", fentry->fnamelen);
566 fentry->f.link_to_dir = 0;
567 fentry->f.stale_link = 0;
568 fentry->f.dir_size_computed = 0;
569 fentry->f.marked = 0;
570 fentry->st.st_mode = 040755;
571 list->len = 1;
572 return TRUE;
573 }
574
575
576
577
578
579
580
581
582
583
584 gboolean
585 handle_path (const char *path, struct stat * buf1, gboolean * link_to_dir, gboolean * stale_link)
586 {
587 vfs_path_t *vpath;
588
589 if (DIR_IS_DOT (path) || DIR_IS_DOTDOT (path))
590 return FALSE;
591
592 vpath = vfs_path_from_str (path);
593 if (mc_lstat (vpath, buf1) == -1)
594 {
595 vfs_path_free (vpath);
596 return FALSE;
597 }
598
599 if (S_ISDIR (buf1->st_mode))
600 tree_store_mark_checked (path);
601
602
603 *link_to_dir = FALSE;
604 *stale_link = FALSE;
605 if (S_ISLNK (buf1->st_mode))
606 {
607 struct stat buf2;
608
609 if (mc_stat (vpath, &buf2) == 0)
610 *link_to_dir = S_ISDIR (buf2.st_mode) != 0;
611 else
612 *stale_link = TRUE;
613 }
614
615 vfs_path_free (vpath);
616
617 return TRUE;
618 }
619
620
621
622 gboolean
623 dir_list_load (dir_list * list, const vfs_path_t * vpath, GCompareFunc sort,
624 const dir_sort_options_t * sort_op, const char *fltr)
625 {
626 DIR *dirp;
627 struct vfs_dirent *dp;
628 struct stat st;
629 file_entry_t *fentry;
630 const char *vpath_str;
631 gboolean ret = TRUE;
632
633
634 if (!dir_list_init (list))
635 return FALSE;
636
637 fentry = &list->list[0];
638 if (dir_get_dotdot_stat (vpath, &st))
639 fentry->st = st;
640
641 if (list->callback != NULL)
642 list->callback (DIR_OPEN, (void *) vpath);
643 dirp = mc_opendir (vpath);
644 if (dirp == NULL)
645 return FALSE;
646
647 tree_store_start_check (vpath);
648
649 vpath_str = vfs_path_as_str (vpath);
650
651 if (IS_PATH_SEP (vpath_str[0]) && vpath_str[1] == '\0')
652 dir_list_clean (list);
653
654 while (ret && (dp = mc_readdir (dirp)) != NULL)
655 {
656 gboolean link_to_dir, stale_link;
657
658 if (list->callback != NULL)
659 list->callback (DIR_READ, dp);
660
661 if (!handle_dirent (dp, fltr, &st, &link_to_dir, &stale_link))
662 continue;
663
664 if (!dir_list_append (list, dp->d_name, &st, link_to_dir, stale_link))
665 ret = FALSE;
666 }
667
668 if (ret)
669 dir_list_sort (list, sort, sort_op);
670
671 if (list->callback != NULL)
672 list->callback (DIR_CLOSE, NULL);
673 mc_closedir (dirp);
674 tree_store_end_check ();
675
676 return ret;
677 }
678
679
680
681 gboolean
682 if_link_is_exe (const vfs_path_t * full_name_vpath, const file_entry_t * file)
683 {
684 struct stat b;
685
686 if (S_ISLNK (file->st.st_mode) && mc_stat (full_name_vpath, &b) == 0)
687 return is_exe (b.st_mode);
688
689 return TRUE;
690 }
691
692
693
694
695 gboolean
696 dir_list_reload (dir_list * list, const vfs_path_t * vpath, GCompareFunc sort,
697 const dir_sort_options_t * sort_op, const char *fltr)
698 {
699 DIR *dirp;
700 struct vfs_dirent *dp;
701 int i;
702 struct stat st;
703 int marked_cnt;
704 GHashTable *marked_files;
705 const char *tmp_path;
706 gboolean ret = TRUE;
707
708 if (list->callback != NULL)
709 list->callback (DIR_OPEN, (void *) vpath);
710 dirp = mc_opendir (vpath);
711 if (dirp == NULL)
712 {
713 dir_list_clean (list);
714 dir_list_init (list);
715 return FALSE;
716 }
717
718 tree_store_start_check (vpath);
719
720 marked_files = g_hash_table_new (g_str_hash, g_str_equal);
721 alloc_dir_copy (list->len);
722 for (marked_cnt = i = 0; i < list->len; i++)
723 {
724 file_entry_t *fentry, *dfentry;
725
726 fentry = &list->list[i];
727 dfentry = &dir_copy.list[i];
728
729 dfentry->fnamelen = fentry->fnamelen;
730 dfentry->fname = g_strndup (fentry->fname, fentry->fnamelen);
731 dfentry->f.marked = fentry->f.marked;
732 dfentry->f.dir_size_computed = fentry->f.dir_size_computed;
733 dfentry->f.link_to_dir = fentry->f.link_to_dir;
734 dfentry->f.stale_link = fentry->f.stale_link;
735 dfentry->sort_key = NULL;
736 dfentry->second_sort_key = NULL;
737 if (fentry->f.marked)
738 {
739 g_hash_table_insert (marked_files, dfentry->fname, dfentry);
740 marked_cnt++;
741 }
742 }
743
744
745 dir_copy.len = list->len;
746
747
748
749 tmp_path = vfs_path_get_by_index (vpath, 0)->path;
750 if (vfs_path_elements_count (vpath) == 1 && IS_PATH_SEP (tmp_path[0]) && tmp_path[1] == '\0')
751 {
752
753 dir_list_clean (list);
754 }
755 else
756 {
757 dir_list_clean (list);
758 if (!dir_list_init (list))
759 {
760 dir_list_free_list (&dir_copy);
761 return FALSE;
762 }
763
764 if (dir_get_dotdot_stat (vpath, &st))
765 {
766 file_entry_t *fentry;
767
768 fentry = &list->list[0];
769 fentry->st = st;
770 }
771 }
772
773 while (ret && (dp = mc_readdir (dirp)) != NULL)
774 {
775 gboolean link_to_dir, stale_link;
776
777 if (list->callback != NULL)
778 list->callback (DIR_READ, dp);
779
780 if (!handle_dirent (dp, fltr, &st, &link_to_dir, &stale_link))
781 continue;
782
783 if (!dir_list_append (list, dp->d_name, &st, link_to_dir, stale_link))
784 ret = FALSE;
785 else
786 {
787 file_entry_t *fentry;
788
789 fentry = &list->list[list->len - 1];
790
791
792
793
794
795
796 fentry->f.marked = (marked_cnt > 0
797 && g_hash_table_lookup (marked_files, dp->d_name) != NULL);
798 if (fentry->f.marked)
799 marked_cnt--;
800 }
801 }
802
803 if (ret)
804 dir_list_sort (list, sort, sort_op);
805
806 if (list->callback != NULL)
807 list->callback (DIR_CLOSE, NULL);
808 mc_closedir (dirp);
809 tree_store_end_check ();
810
811 g_hash_table_destroy (marked_files);
812 dir_list_free_list (&dir_copy);
813
814 return ret;
815 }
816
817