diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2011-05-13 17:28:46 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2011-05-13 17:28:46 +0200 |
commit | 4029e21b37a18bea86dd438d4a9138789ecdce6c (patch) | |
tree | 4e23c08d7fab2bb2a62959c313b0cc081f09a0f3 /coreutils | |
parent | 2a81639534bcfd075dee12eacc6c45e657e4488e (diff) | |
download | busybox-w32-4029e21b37a18bea86dd438d4a9138789ecdce6c.tar.gz busybox-w32-4029e21b37a18bea86dd438d4a9138789ecdce6c.tar.bz2 busybox-w32-4029e21b37a18bea86dd438d4a9138789ecdce6c.zip |
ls: reorder and rename functions. No code changes
function old new delta
display_single - 931 +931
scan_and_display_dirs_recur - 497 +497
display_files - 422 +422
showfiles 422 - -422
showdirs 497 - -497
list_single 931 - -931
------------------------------------------------------------------------------
(add/remove: 3/3 grow/shrink: 0/0 up/down: 1850/-1850) Total: 0 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'coreutils')
-rw-r--r-- | coreutils/ls.c | 478 |
1 files changed, 240 insertions, 238 deletions
diff --git a/coreutils/ls.c b/coreutils/ls.c index 52c2c4db7..907955077 100644 --- a/coreutils/ls.c +++ b/coreutils/ls.c | |||
@@ -326,7 +326,7 @@ struct dnode { | |||
326 | // (such as nanosecond-resolution timespamps) | 326 | // (such as nanosecond-resolution timespamps) |
327 | // and padding, which we also don't want to store. | 327 | // and padding, which we also don't want to store. |
328 | // We also can pre-parse dev_t dn_rdev (in glibc, it's huge). | 328 | // We also can pre-parse dev_t dn_rdev (in glibc, it's huge). |
329 | // On 32-bit uclibc: dnode size went from 112 to 84 bytes | 329 | // On 32-bit uclibc: dnode size went from 112 to 84 bytes. |
330 | // | 330 | // |
331 | /* Same names as in struct stat, but with dn_ instead of st_ pfx: */ | 331 | /* Same names as in struct stat, but with dn_ instead of st_ pfx: */ |
332 | mode_t dn_mode; /* obtained with lstat OR stat, depending on -L etc */ | 332 | mode_t dn_mode; /* obtained with lstat OR stat, depending on -L etc */ |
@@ -376,61 +376,8 @@ struct globals { | |||
376 | } while (0) | 376 | } while (0) |
377 | 377 | ||
378 | 378 | ||
379 | static struct dnode *my_stat(const char *fullname, const char *name, int force_follow) | 379 | /*** Output code ***/ |
380 | { | ||
381 | struct stat statbuf; | ||
382 | struct dnode *cur; | ||
383 | 380 | ||
384 | cur = xzalloc(sizeof(*cur)); | ||
385 | cur->fullname = fullname; | ||
386 | cur->name = name; | ||
387 | |||
388 | if ((option_mask32 & OPT_L) || force_follow) { | ||
389 | #if ENABLE_SELINUX | ||
390 | if (is_selinux_enabled()) { | ||
391 | getfilecon(fullname, &cur->sid); | ||
392 | } | ||
393 | #endif | ||
394 | if (stat(fullname, &statbuf)) { | ||
395 | bb_simple_perror_msg(fullname); | ||
396 | G.exit_code = EXIT_FAILURE; | ||
397 | free(cur); | ||
398 | return NULL; | ||
399 | } | ||
400 | cur->dn_mode_stat = statbuf.st_mode; | ||
401 | } else { | ||
402 | #if ENABLE_SELINUX | ||
403 | if (is_selinux_enabled()) { | ||
404 | lgetfilecon(fullname, &cur->sid); | ||
405 | } | ||
406 | #endif | ||
407 | if (lstat(fullname, &statbuf)) { | ||
408 | bb_simple_perror_msg(fullname); | ||
409 | G.exit_code = EXIT_FAILURE; | ||
410 | free(cur); | ||
411 | return NULL; | ||
412 | } | ||
413 | cur->dn_mode_lstat = statbuf.st_mode; | ||
414 | } | ||
415 | |||
416 | /* cur->dstat = statbuf: */ | ||
417 | cur->dn_mode = statbuf.st_mode ; | ||
418 | cur->dn_size = statbuf.st_size ; | ||
419 | #if ENABLE_FEATURE_LS_TIMESTAMPS || ENABLE_FEATURE_LS_SORTFILES | ||
420 | cur->dn_atime = statbuf.st_atime ; | ||
421 | cur->dn_mtime = statbuf.st_mtime ; | ||
422 | cur->dn_ctime = statbuf.st_ctime ; | ||
423 | #endif | ||
424 | cur->dn_ino = statbuf.st_ino ; | ||
425 | cur->dn_blocks = statbuf.st_blocks; | ||
426 | cur->dn_nlink = statbuf.st_nlink ; | ||
427 | cur->dn_uid = statbuf.st_uid ; | ||
428 | cur->dn_gid = statbuf.st_gid ; | ||
429 | cur->dn_rdev_maj = major(statbuf.st_rdev); | ||
430 | cur->dn_rdev_min = minor(statbuf.st_rdev); | ||
431 | |||
432 | return cur; | ||
433 | } | ||
434 | 381 | ||
435 | /* FYI type values: 1:fifo 2:char 4:dir 6:blk 8:file 10:link 12:socket | 382 | /* FYI type values: 1:fifo 2:char 4:dir 6:blk 8:file 10:link 12:socket |
436 | * (various wacky OSes: 13:Sun door 14:BSD whiteout 5:XENIX named file | 383 | * (various wacky OSes: 13:Sun door 14:BSD whiteout 5:XENIX named file |
@@ -493,155 +440,6 @@ static char append_char(mode_t mode) | |||
493 | } | 440 | } |
494 | #endif | 441 | #endif |
495 | 442 | ||
496 | static unsigned count_dirs(struct dnode **dn, int which) | ||
497 | { | ||
498 | unsigned dirs, all; | ||
499 | |||
500 | if (!dn) | ||
501 | return 0; | ||
502 | |||
503 | dirs = all = 0; | ||
504 | for (; *dn; dn++) { | ||
505 | const char *name; | ||
506 | |||
507 | all++; | ||
508 | if (!S_ISDIR((*dn)->dn_mode)) | ||
509 | continue; | ||
510 | |||
511 | name = (*dn)->name; | ||
512 | if (which != SPLIT_SUBDIR /* if not requested to skip . / .. */ | ||
513 | /* or if it's not . or .. */ | ||
514 | || name[0] != '.' | ||
515 | || (name[1] && (name[1] != '.' || name[2])) | ||
516 | ) { | ||
517 | dirs++; | ||
518 | } | ||
519 | } | ||
520 | return which != SPLIT_FILE ? dirs : all - dirs; | ||
521 | } | ||
522 | |||
523 | /* get memory to hold an array of pointers */ | ||
524 | static struct dnode **dnalloc(unsigned num) | ||
525 | { | ||
526 | if (num < 1) | ||
527 | return NULL; | ||
528 | |||
529 | num++; /* so that we have terminating NULL */ | ||
530 | return xzalloc(num * sizeof(struct dnode *)); | ||
531 | } | ||
532 | |||
533 | #if ENABLE_FEATURE_LS_RECURSIVE | ||
534 | static void dfree(struct dnode **dnp) | ||
535 | { | ||
536 | unsigned i; | ||
537 | |||
538 | if (dnp == NULL) | ||
539 | return; | ||
540 | |||
541 | for (i = 0; dnp[i]; i++) { | ||
542 | struct dnode *cur = dnp[i]; | ||
543 | if (cur->fname_allocated) | ||
544 | free((char*)cur->fullname); | ||
545 | free(cur); | ||
546 | } | ||
547 | free(dnp); | ||
548 | } | ||
549 | #else | ||
550 | #define dfree(...) ((void)0) | ||
551 | #endif | ||
552 | |||
553 | /* Returns NULL-terminated malloced vector of pointers (or NULL) */ | ||
554 | static struct dnode **splitdnarray(struct dnode **dn, int which) | ||
555 | { | ||
556 | unsigned dncnt, d; | ||
557 | struct dnode **dnp; | ||
558 | |||
559 | if (dn == NULL) | ||
560 | return NULL; | ||
561 | |||
562 | /* count how many dirs or files there are */ | ||
563 | dncnt = count_dirs(dn, which); | ||
564 | |||
565 | /* allocate a file array and a dir array */ | ||
566 | dnp = dnalloc(dncnt); | ||
567 | |||
568 | /* copy the entrys into the file or dir array */ | ||
569 | for (d = 0; *dn; dn++) { | ||
570 | if (S_ISDIR((*dn)->dn_mode)) { | ||
571 | const char *name; | ||
572 | |||
573 | if (which == SPLIT_FILE) | ||
574 | continue; | ||
575 | |||
576 | name = (*dn)->name; | ||
577 | if ((which & SPLIT_DIR) /* any dir... */ | ||
578 | /* ... or not . or .. */ | ||
579 | || name[0] != '.' | ||
580 | || (name[1] && (name[1] != '.' || name[2])) | ||
581 | ) { | ||
582 | dnp[d++] = *dn; | ||
583 | } | ||
584 | } else | ||
585 | if (which == SPLIT_FILE) { | ||
586 | dnp[d++] = *dn; | ||
587 | } | ||
588 | } | ||
589 | return dnp; | ||
590 | } | ||
591 | |||
592 | #if ENABLE_FEATURE_LS_SORTFILES | ||
593 | static int sortcmp(const void *a, const void *b) | ||
594 | { | ||
595 | struct dnode *d1 = *(struct dnode **)a; | ||
596 | struct dnode *d2 = *(struct dnode **)b; | ||
597 | unsigned sort_opts = G.all_fmt & SORT_MASK; | ||
598 | off_t dif; | ||
599 | |||
600 | dif = 0; /* assume SORT_NAME */ | ||
601 | // TODO: use pre-initialized function pointer | ||
602 | // instead of branch forest | ||
603 | if (sort_opts == SORT_SIZE) { | ||
604 | dif = (d2->dn_size - d1->dn_size); | ||
605 | } else if (sort_opts == SORT_ATIME) { | ||
606 | dif = (d2->dn_atime - d1->dn_atime); | ||
607 | } else if (sort_opts == SORT_CTIME) { | ||
608 | dif = (d2->dn_ctime - d1->dn_ctime); | ||
609 | } else if (sort_opts == SORT_MTIME) { | ||
610 | dif = (d2->dn_mtime - d1->dn_mtime); | ||
611 | } else if (sort_opts == SORT_DIR) { | ||
612 | dif = S_ISDIR(d2->dn_mode) - S_ISDIR(d1->dn_mode); | ||
613 | /* } else if (sort_opts == SORT_VERSION) { */ | ||
614 | /* } else if (sort_opts == SORT_EXT) { */ | ||
615 | } | ||
616 | if (dif == 0) { | ||
617 | /* sort by name, or tie_breaker for other sorts */ | ||
618 | if (ENABLE_LOCALE_SUPPORT) | ||
619 | dif = strcoll(d1->name, d2->name); | ||
620 | else | ||
621 | dif = strcmp(d1->name, d2->name); | ||
622 | } | ||
623 | |||
624 | /* Make dif fit into an int */ | ||
625 | if (sizeof(dif) > sizeof(int)) { | ||
626 | enum { BITS_TO_SHIFT = 8 * (sizeof(dif) - sizeof(int)) }; | ||
627 | /* shift leaving only "int" worth of bits */ | ||
628 | if (dif != 0) { | ||
629 | dif = 1 | (int)((uoff_t)dif >> BITS_TO_SHIFT); | ||
630 | } | ||
631 | } | ||
632 | |||
633 | return (G.all_fmt & SORT_REVERSE) ? -(int)dif : (int)dif; | ||
634 | } | ||
635 | |||
636 | static void dnsort(struct dnode **dn, int size) | ||
637 | { | ||
638 | qsort(dn, size, sizeof(*dn), sortcmp); | ||
639 | } | ||
640 | #else | ||
641 | #define dnsort(dn, size) ((void)0) | ||
642 | #endif | ||
643 | |||
644 | |||
645 | static unsigned calc_name_len(const char *name) | 443 | static unsigned calc_name_len(const char *name) |
646 | { | 444 | { |
647 | unsigned len; | 445 | unsigned len; |
@@ -664,7 +462,6 @@ static unsigned calc_name_len(const char *name) | |||
664 | return len; | 462 | return len; |
665 | } | 463 | } |
666 | 464 | ||
667 | |||
668 | /* Return the number of used columns. | 465 | /* Return the number of used columns. |
669 | * Note that only STYLE_COLUMNAR uses return value. | 466 | * Note that only STYLE_COLUMNAR uses return value. |
670 | * STYLE_SINGLE and STYLE_LONG don't care. | 467 | * STYLE_SINGLE and STYLE_LONG don't care. |
@@ -703,7 +500,7 @@ static unsigned print_name(const char *name) | |||
703 | * Note that only STYLE_COLUMNAR uses return value, | 500 | * Note that only STYLE_COLUMNAR uses return value, |
704 | * STYLE_SINGLE and STYLE_LONG don't care. | 501 | * STYLE_SINGLE and STYLE_LONG don't care. |
705 | */ | 502 | */ |
706 | static NOINLINE unsigned list_single(const struct dnode *dn) | 503 | static NOINLINE unsigned display_single(const struct dnode *dn) |
707 | { | 504 | { |
708 | unsigned column = 0; | 505 | unsigned column = 0; |
709 | char *lpath; | 506 | char *lpath; |
@@ -854,7 +651,7 @@ static NOINLINE unsigned list_single(const struct dnode *dn) | |||
854 | return column; | 651 | return column; |
855 | } | 652 | } |
856 | 653 | ||
857 | static void showfiles(struct dnode **dn, unsigned nfiles) | 654 | static void display_files(struct dnode **dn, unsigned nfiles) |
858 | { | 655 | { |
859 | unsigned i, ncols, nrows, row, nc; | 656 | unsigned i, ncols, nrows, row, nc; |
860 | unsigned column; | 657 | unsigned column; |
@@ -902,7 +699,7 @@ static void showfiles(struct dnode **dn, unsigned nfiles) | |||
902 | column += nexttab + 1; | 699 | column += nexttab + 1; |
903 | } | 700 | } |
904 | nexttab = column + column_width; | 701 | nexttab = column + column_width; |
905 | column += list_single(dn[i]); | 702 | column += display_single(dn[i]); |
906 | } | 703 | } |
907 | } | 704 | } |
908 | putchar('\n'); | 705 | putchar('\n'); |
@@ -911,38 +708,214 @@ static void showfiles(struct dnode **dn, unsigned nfiles) | |||
911 | } | 708 | } |
912 | 709 | ||
913 | 710 | ||
914 | #if ENABLE_DESKTOP | 711 | /*** Dir scanning code ***/ |
915 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/ls.html | 712 | |
916 | * If any of the -l, -n, -s options is specified, each list | 713 | static struct dnode *my_stat(const char *fullname, const char *name, int force_follow) |
917 | * of files within the directory shall be preceded by a | ||
918 | * status line indicating the number of file system blocks | ||
919 | * occupied by files in the directory in 512-byte units if | ||
920 | * the -k option is not specified, or 1024-byte units if the | ||
921 | * -k option is specified, rounded up to the next integral | ||
922 | * number of units. | ||
923 | */ | ||
924 | /* by Jorgen Overgaard (jorgen AT antistaten.se) */ | ||
925 | static off_t calculate_blocks(struct dnode **dn) | ||
926 | { | 714 | { |
927 | uoff_t blocks = 1; | 715 | struct stat statbuf; |
928 | if (dn) { | 716 | struct dnode *cur; |
929 | while (*dn) { | 717 | |
930 | /* st_blocks is in 512 byte blocks */ | 718 | cur = xzalloc(sizeof(*cur)); |
931 | blocks += (*dn)->dn_blocks; | 719 | cur->fullname = fullname; |
932 | dn++; | 720 | cur->name = name; |
721 | |||
722 | if ((option_mask32 & OPT_L) || force_follow) { | ||
723 | #if ENABLE_SELINUX | ||
724 | if (is_selinux_enabled()) { | ||
725 | getfilecon(fullname, &cur->sid); | ||
726 | } | ||
727 | #endif | ||
728 | if (stat(fullname, &statbuf)) { | ||
729 | bb_simple_perror_msg(fullname); | ||
730 | G.exit_code = EXIT_FAILURE; | ||
731 | free(cur); | ||
732 | return NULL; | ||
733 | } | ||
734 | cur->dn_mode_stat = statbuf.st_mode; | ||
735 | } else { | ||
736 | #if ENABLE_SELINUX | ||
737 | if (is_selinux_enabled()) { | ||
738 | lgetfilecon(fullname, &cur->sid); | ||
739 | } | ||
740 | #endif | ||
741 | if (lstat(fullname, &statbuf)) { | ||
742 | bb_simple_perror_msg(fullname); | ||
743 | G.exit_code = EXIT_FAILURE; | ||
744 | free(cur); | ||
745 | return NULL; | ||
933 | } | 746 | } |
747 | cur->dn_mode_lstat = statbuf.st_mode; | ||
934 | } | 748 | } |
935 | 749 | ||
936 | /* Even though standard says use 512 byte blocks, coreutils use 1k */ | 750 | /* cur->dstat = statbuf: */ |
937 | /* Actually, we round up by calculating (blocks + 1) / 2, | 751 | cur->dn_mode = statbuf.st_mode ; |
938 | * "+ 1" was done when we initialized blocks to 1 */ | 752 | cur->dn_size = statbuf.st_size ; |
939 | return blocks >> 1; | 753 | #if ENABLE_FEATURE_LS_TIMESTAMPS || ENABLE_FEATURE_LS_SORTFILES |
754 | cur->dn_atime = statbuf.st_atime ; | ||
755 | cur->dn_mtime = statbuf.st_mtime ; | ||
756 | cur->dn_ctime = statbuf.st_ctime ; | ||
757 | #endif | ||
758 | cur->dn_ino = statbuf.st_ino ; | ||
759 | cur->dn_blocks = statbuf.st_blocks; | ||
760 | cur->dn_nlink = statbuf.st_nlink ; | ||
761 | cur->dn_uid = statbuf.st_uid ; | ||
762 | cur->dn_gid = statbuf.st_gid ; | ||
763 | cur->dn_rdev_maj = major(statbuf.st_rdev); | ||
764 | cur->dn_rdev_min = minor(statbuf.st_rdev); | ||
765 | |||
766 | return cur; | ||
940 | } | 767 | } |
768 | |||
769 | static unsigned count_dirs(struct dnode **dn, int which) | ||
770 | { | ||
771 | unsigned dirs, all; | ||
772 | |||
773 | if (!dn) | ||
774 | return 0; | ||
775 | |||
776 | dirs = all = 0; | ||
777 | for (; *dn; dn++) { | ||
778 | const char *name; | ||
779 | |||
780 | all++; | ||
781 | if (!S_ISDIR((*dn)->dn_mode)) | ||
782 | continue; | ||
783 | |||
784 | name = (*dn)->name; | ||
785 | if (which != SPLIT_SUBDIR /* if not requested to skip . / .. */ | ||
786 | /* or if it's not . or .. */ | ||
787 | || name[0] != '.' | ||
788 | || (name[1] && (name[1] != '.' || name[2])) | ||
789 | ) { | ||
790 | dirs++; | ||
791 | } | ||
792 | } | ||
793 | return which != SPLIT_FILE ? dirs : all - dirs; | ||
794 | } | ||
795 | |||
796 | /* get memory to hold an array of pointers */ | ||
797 | static struct dnode **dnalloc(unsigned num) | ||
798 | { | ||
799 | if (num < 1) | ||
800 | return NULL; | ||
801 | |||
802 | num++; /* so that we have terminating NULL */ | ||
803 | return xzalloc(num * sizeof(struct dnode *)); | ||
804 | } | ||
805 | |||
806 | #if ENABLE_FEATURE_LS_RECURSIVE | ||
807 | static void dfree(struct dnode **dnp) | ||
808 | { | ||
809 | unsigned i; | ||
810 | |||
811 | if (dnp == NULL) | ||
812 | return; | ||
813 | |||
814 | for (i = 0; dnp[i]; i++) { | ||
815 | struct dnode *cur = dnp[i]; | ||
816 | if (cur->fname_allocated) | ||
817 | free((char*)cur->fullname); | ||
818 | free(cur); | ||
819 | } | ||
820 | free(dnp); | ||
821 | } | ||
822 | #else | ||
823 | #define dfree(...) ((void)0) | ||
941 | #endif | 824 | #endif |
942 | 825 | ||
826 | /* Returns NULL-terminated malloced vector of pointers (or NULL) */ | ||
827 | static struct dnode **splitdnarray(struct dnode **dn, int which) | ||
828 | { | ||
829 | unsigned dncnt, d; | ||
830 | struct dnode **dnp; | ||
831 | |||
832 | if (dn == NULL) | ||
833 | return NULL; | ||
834 | |||
835 | /* count how many dirs or files there are */ | ||
836 | dncnt = count_dirs(dn, which); | ||
837 | |||
838 | /* allocate a file array and a dir array */ | ||
839 | dnp = dnalloc(dncnt); | ||
840 | |||
841 | /* copy the entrys into the file or dir array */ | ||
842 | for (d = 0; *dn; dn++) { | ||
843 | if (S_ISDIR((*dn)->dn_mode)) { | ||
844 | const char *name; | ||
845 | |||
846 | if (which == SPLIT_FILE) | ||
847 | continue; | ||
848 | |||
849 | name = (*dn)->name; | ||
850 | if ((which & SPLIT_DIR) /* any dir... */ | ||
851 | /* ... or not . or .. */ | ||
852 | || name[0] != '.' | ||
853 | || (name[1] && (name[1] != '.' || name[2])) | ||
854 | ) { | ||
855 | dnp[d++] = *dn; | ||
856 | } | ||
857 | } else | ||
858 | if (which == SPLIT_FILE) { | ||
859 | dnp[d++] = *dn; | ||
860 | } | ||
861 | } | ||
862 | return dnp; | ||
863 | } | ||
864 | |||
865 | #if ENABLE_FEATURE_LS_SORTFILES | ||
866 | static int sortcmp(const void *a, const void *b) | ||
867 | { | ||
868 | struct dnode *d1 = *(struct dnode **)a; | ||
869 | struct dnode *d2 = *(struct dnode **)b; | ||
870 | unsigned sort_opts = G.all_fmt & SORT_MASK; | ||
871 | off_t dif; | ||
872 | |||
873 | dif = 0; /* assume SORT_NAME */ | ||
874 | // TODO: use pre-initialized function pointer | ||
875 | // instead of branch forest | ||
876 | if (sort_opts == SORT_SIZE) { | ||
877 | dif = (d2->dn_size - d1->dn_size); | ||
878 | } else if (sort_opts == SORT_ATIME) { | ||
879 | dif = (d2->dn_atime - d1->dn_atime); | ||
880 | } else if (sort_opts == SORT_CTIME) { | ||
881 | dif = (d2->dn_ctime - d1->dn_ctime); | ||
882 | } else if (sort_opts == SORT_MTIME) { | ||
883 | dif = (d2->dn_mtime - d1->dn_mtime); | ||
884 | } else if (sort_opts == SORT_DIR) { | ||
885 | dif = S_ISDIR(d2->dn_mode) - S_ISDIR(d1->dn_mode); | ||
886 | /* } else if (sort_opts == SORT_VERSION) { */ | ||
887 | /* } else if (sort_opts == SORT_EXT) { */ | ||
888 | } | ||
889 | if (dif == 0) { | ||
890 | /* sort by name, or tie_breaker for other sorts */ | ||
891 | if (ENABLE_LOCALE_SUPPORT) | ||
892 | dif = strcoll(d1->name, d2->name); | ||
893 | else | ||
894 | dif = strcmp(d1->name, d2->name); | ||
895 | } | ||
896 | |||
897 | /* Make dif fit into an int */ | ||
898 | if (sizeof(dif) > sizeof(int)) { | ||
899 | enum { BITS_TO_SHIFT = 8 * (sizeof(dif) - sizeof(int)) }; | ||
900 | /* shift leaving only "int" worth of bits */ | ||
901 | if (dif != 0) { | ||
902 | dif = 1 | (int)((uoff_t)dif >> BITS_TO_SHIFT); | ||
903 | } | ||
904 | } | ||
905 | |||
906 | return (G.all_fmt & SORT_REVERSE) ? -(int)dif : (int)dif; | ||
907 | } | ||
908 | |||
909 | static void dnsort(struct dnode **dn, int size) | ||
910 | { | ||
911 | qsort(dn, size, sizeof(*dn), sortcmp); | ||
912 | } | ||
913 | #else | ||
914 | #define dnsort(dn, size) ((void)0) | ||
915 | #endif | ||
943 | 916 | ||
944 | /* Returns NULL-terminated malloced vector of pointers (or NULL) */ | 917 | /* Returns NULL-terminated malloced vector of pointers (or NULL) */ |
945 | static struct dnode **list_dir(const char *path, unsigned *nfiles_p) | 918 | static struct dnode **scan_one_dir(const char *path, unsigned *nfiles_p) |
946 | { | 919 | { |
947 | struct dnode *dn, *cur, **dnp; | 920 | struct dnode *dn, *cur, **dnp; |
948 | struct dirent *entry; | 921 | struct dirent *entry; |
@@ -1001,8 +974,36 @@ static struct dnode **list_dir(const char *path, unsigned *nfiles_p) | |||
1001 | return dnp; | 974 | return dnp; |
1002 | } | 975 | } |
1003 | 976 | ||
977 | #if ENABLE_DESKTOP | ||
978 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/ls.html | ||
979 | * If any of the -l, -n, -s options is specified, each list | ||
980 | * of files within the directory shall be preceded by a | ||
981 | * status line indicating the number of file system blocks | ||
982 | * occupied by files in the directory in 512-byte units if | ||
983 | * the -k option is not specified, or 1024-byte units if the | ||
984 | * -k option is specified, rounded up to the next integral | ||
985 | * number of units. | ||
986 | */ | ||
987 | /* by Jorgen Overgaard (jorgen AT antistaten.se) */ | ||
988 | static off_t calculate_blocks(struct dnode **dn) | ||
989 | { | ||
990 | uoff_t blocks = 1; | ||
991 | if (dn) { | ||
992 | while (*dn) { | ||
993 | /* st_blocks is in 512 byte blocks */ | ||
994 | blocks += (*dn)->dn_blocks; | ||
995 | dn++; | ||
996 | } | ||
997 | } | ||
998 | |||
999 | /* Even though standard says use 512 byte blocks, coreutils use 1k */ | ||
1000 | /* Actually, we round up by calculating (blocks + 1) / 2, | ||
1001 | * "+ 1" was done when we initialized blocks to 1 */ | ||
1002 | return blocks >> 1; | ||
1003 | } | ||
1004 | #endif | ||
1004 | 1005 | ||
1005 | static void showdirs(struct dnode **dn, int first) | 1006 | static void scan_and_display_dirs_recur(struct dnode **dn, int first) |
1006 | { | 1007 | { |
1007 | unsigned nfiles; | 1008 | unsigned nfiles; |
1008 | struct dnode **subdnp; | 1009 | struct dnode **subdnp; |
@@ -1014,7 +1015,7 @@ static void showdirs(struct dnode **dn, int first) | |||
1014 | first = 0; | 1015 | first = 0; |
1015 | printf("%s:\n", (*dn)->fullname); | 1016 | printf("%s:\n", (*dn)->fullname); |
1016 | } | 1017 | } |
1017 | subdnp = list_dir((*dn)->fullname, &nfiles); | 1018 | subdnp = scan_one_dir((*dn)->fullname, &nfiles); |
1018 | #if ENABLE_DESKTOP | 1019 | #if ENABLE_DESKTOP |
1019 | if ((G.all_fmt & STYLE_MASK) == STYLE_LONG) | 1020 | if ((G.all_fmt & STYLE_MASK) == STYLE_LONG) |
1020 | printf("total %"OFF_FMT"u\n", calculate_blocks(subdnp)); | 1021 | printf("total %"OFF_FMT"u\n", calculate_blocks(subdnp)); |
@@ -1022,7 +1023,8 @@ static void showdirs(struct dnode **dn, int first) | |||
1022 | if (nfiles > 0) { | 1023 | if (nfiles > 0) { |
1023 | /* list all files at this level */ | 1024 | /* list all files at this level */ |
1024 | dnsort(subdnp, nfiles); | 1025 | dnsort(subdnp, nfiles); |
1025 | showfiles(subdnp, nfiles); | 1026 | display_files(subdnp, nfiles); |
1027 | |||
1026 | if (ENABLE_FEATURE_LS_RECURSIVE | 1028 | if (ENABLE_FEATURE_LS_RECURSIVE |
1027 | && (G.all_fmt & DISP_RECURSIVE) | 1029 | && (G.all_fmt & DISP_RECURSIVE) |
1028 | ) { | 1030 | ) { |
@@ -1033,7 +1035,7 @@ static void showdirs(struct dnode **dn, int first) | |||
1033 | dndirs = count_dirs(subdnp, SPLIT_SUBDIR); | 1035 | dndirs = count_dirs(subdnp, SPLIT_SUBDIR); |
1034 | if (dndirs > 0) { | 1036 | if (dndirs > 0) { |
1035 | dnsort(dnd, dndirs); | 1037 | dnsort(dnd, dndirs); |
1036 | showdirs(dnd, 0); | 1038 | scan_and_display_dirs_recur(dnd, 0); |
1037 | /* free the array of dnode pointers to the dirs */ | 1039 | /* free the array of dnode pointers to the dirs */ |
1038 | free(dnd); | 1040 | free(dnd); |
1039 | } | 1041 | } |
@@ -1215,7 +1217,7 @@ int ls_main(int argc UNUSED_PARAM, char **argv) | |||
1215 | 1217 | ||
1216 | if (G.all_fmt & DISP_NOLIST) { | 1218 | if (G.all_fmt & DISP_NOLIST) { |
1217 | dnsort(dnp, nfiles); | 1219 | dnsort(dnp, nfiles); |
1218 | showfiles(dnp, nfiles); | 1220 | display_files(dnp, nfiles); |
1219 | } else { | 1221 | } else { |
1220 | dnd = splitdnarray(dnp, SPLIT_DIR); | 1222 | dnd = splitdnarray(dnp, SPLIT_DIR); |
1221 | dnf = splitdnarray(dnp, SPLIT_FILE); | 1223 | dnf = splitdnarray(dnp, SPLIT_FILE); |
@@ -1223,13 +1225,13 @@ int ls_main(int argc UNUSED_PARAM, char **argv) | |||
1223 | dnfiles = nfiles - dndirs; | 1225 | dnfiles = nfiles - dndirs; |
1224 | if (dnfiles > 0) { | 1226 | if (dnfiles > 0) { |
1225 | dnsort(dnf, dnfiles); | 1227 | dnsort(dnf, dnfiles); |
1226 | showfiles(dnf, dnfiles); | 1228 | display_files(dnf, dnfiles); |
1227 | if (ENABLE_FEATURE_CLEAN_UP) | 1229 | if (ENABLE_FEATURE_CLEAN_UP) |
1228 | free(dnf); | 1230 | free(dnf); |
1229 | } | 1231 | } |
1230 | if (dndirs > 0) { | 1232 | if (dndirs > 0) { |
1231 | dnsort(dnd, dndirs); | 1233 | dnsort(dnd, dndirs); |
1232 | showdirs(dnd, dnfiles == 0); | 1234 | scan_and_display_dirs_recur(dnd, dnfiles == 0); |
1233 | if (ENABLE_FEATURE_CLEAN_UP) | 1235 | if (ENABLE_FEATURE_CLEAN_UP) |
1234 | free(dnd); | 1236 | free(dnd); |
1235 | } | 1237 | } |