[PATCH v2] Added miscutil/tree.c

tito farmatito at tiscali.it
Sun Apr 17 08:10:50 UTC 2022


On Sat, 16 Apr 2022 21:13:02 +0200
tito <farmatito at tiscali.it> wrote:

> On Sat, 16 Apr 2022 16:54:19 +0000
> Roger Knecht <rknecht at pm.me> wrote:
> 
> > Adds the tree program to list directories and files in a tree structure.
> > 
> > function                                             old     new   delta
> > static.tree_print                                      -     352    +352
> > .rodata                                            95677   95756     +79
> > tree_main                                              -      69     +69
> > globals                                                -      24     +24
> > applet_main                                         3192    3200      +8
> > applet_names                                        2747    2752      +5
> > packed_usage                                       34414   34396     -18
> > ------------------------------------------------------------------------------
> > (add/remove: 4/0 grow/shrink: 3/1 up/down: 537/-18)           Total: 519 bytes
> > ---
> > As Ron pointed out V1 was overwriting the find help text and therefore invalidating
> > the bloatcheck. V1 added 1171 bytes (not 349 bytes as originally mentioned).
> > 
> > V2 is reducing the size by using scandir(), chdir() and avoiding string concatenations.
> > 
> > Changelog:
> > 
> > V2:
> > - Fixed tree help text
> > - Reduced size by 652 bytes
> 
> Hi,
> just out of curiosity, for fun and to refresh my C skills I wrote
> an alternative version of tree that is somewhat similar to yours
> in using scandir.
> 
> One problem I see in your V2 is that unlike real tree it does not
> handle multiple paths as command line args:
> 
> tree dir dir2 dirn
> 
> Also the use of  DT_DIR is problematic as only some filesystems
> have full support.

On more minor glitch is that file and dir count differs from original
tree program when links are involved.
For example:

./busybox_unstripped tree ../../test/
../../test/
├── test1
│   └── a
├── test2
│   ├── b
│   ├── c
│   ├── k
│   └── test3
├── test4
├── test5
├── test6
└── test7

4 directories, 7 files

tree ../../test/
../../test/
├── test1
│   └── a
├── test2
│   ├── b
│   ├── c
│   ├── k -> b
│   └── test3
├── test4 -> test2
├── test5
├── test6 -> test7
└── test7 -> test6

5 directories, 6 files

Ciao,
Tito

> 
> Bloatcheck is:
> 
> function                                             old     new   delta
> tree                                                   -     501    +501
> tree_main                                              -     125    +125
> .rodata                                            99024   99106     +82
> packed_usage                                       34414   34448     +34
> applet_main                                         3192    3200      +8
> applet_names                                        2747    2752      +5
> ------------------------------------------------------------------------------
> (add/remove: 3/0 grow/shrink: 4/0 up/down: 755/0)             Total: 755 bytes
>    text    data     bss     dec     hex filename
> 1002271   16403    1848 1020522   f926a busybox_old
> 1003180   16427    1848 1021455   f960f busybox_unstripped
> 
> Features are:
> 1) correct link handling:
> 
> ./busybox tree ../../test/
> ../../test/
> ├── test1
> │   └── a
> ├── test2
> │   ├── b
> │   ├── c
> │   └── test3
> ├── test4 -> test2
> └── test5
> 
> 2) Uses scandir and passes the testsuite.
> 3) It is worth mentioning that by using alphasort
>     as sorting algorithm the output of complex trees
>     is somewhat different in the ordering of files
>      ( for example uppercase , lowercase)
>     as the real tree program.
> 
> For easier review code is attached as patch and 
> also in the mail body.
> 
> #include "libbb.h"
> 
> #define HIDDEN(s)        ((s)[0] == '.')
> 
> #define CHILD            "├── "
> #define LAST_CHILD       "└── "
> #define GRAND_CHILD      "│   "
> #define LAST_GRAND_CHILD "    "
> 
> #define MAX_CHILD_SIZE (MAX(MAX(MAX((sizeof(CHILD)), \
> 									(sizeof(LAST_CHILD))), \
> 									(sizeof(GRAND_CHILD))), \
> 									(sizeof(LAST_GRAND_CHILD))))
> 
> static void tree(char *path, int *dcount, int *fcount, char **list)
> {
> 	int i = 0;
> 	int n;
> 	int l;
> 	char *fullpath = NULL;
> 	char *linkname = NULL;
> 	struct dirent **namelist;
> 
> 	if ((n = scandir(path, &namelist, NULL, alphasort)) < 0) {
> 		printf("%s [error opening dir]\n", path);
> 		return;
> 	} else if (!**list) {
> 		printf("%s\n", path);
> 	}
> 
> 	l = strlen(*list);
> 
> 	while (i < n) {
> 		if (!DOT_OR_DOTDOT(namelist[i]->d_name) && !HIDDEN(namelist[i]->d_name)) {
> 			*list = xrealloc(*list, l + MAX_CHILD_SIZE);
> 			strcpy(*list + l, (i == (n - 1)) ? LAST_CHILD : CHILD);
> 			printf("%s%s", *list, namelist[i]->d_name);
> 			fullpath = concat_path_file(path, namelist[i]->d_name);
> 			if((linkname = xmalloc_readlink(fullpath)) != NULL) {
> 				printf(" -> %s", linkname);
> 			}
> 			bb_putchar('\n');
> 			if (is_directory(fullpath, /*followLinks*/ 1)) {
> 				(*dcount)++;
> 				strcpy(*list + l, (i == (n - 1)) ? LAST_GRAND_CHILD : GRAND_CHILD);
> 				if (linkname == NULL) {
> 					tree(fullpath, dcount, fcount, list);
> 				}
> 			} else {
> 				(*fcount)++;
> 			}
> 			free(linkname);
> 			free(fullpath);
> 		}
> 		free(namelist[i]);
> 		i++;
> 	}
> 	strcpy(*list + l,  "");
> 	free(namelist);
> }
> 
> int tree_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
> int tree_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
> {
> 	int dircount = 0;
> 	int filecount = 0;
> 	char *list = xzalloc(1);
> 
> 	if (argc == 1) {
> 		*argv = (char *) ".";
> 	} else {
> 		argv++;
> 	}
> 
> 	do {
> 		tree(*argv, &dircount, &filecount, &list);
> 	} while (*++argv);
> 	printf("\n%d directories, %d files\n", dircount, filecount);
> 	if (ENABLE_FEATURE_CLEAN_UP) {
> 		 free(list);
> 	}
> 	return EXIT_SUCCESS;
> }
>   
> Hints on how to shrink it even more, improvements and critics are welcome! Enjoy.
> 
> Ciao,
> Tito
>      



More information about the busybox mailing list