tree: new applet
Adds the tree program to list directories and files in a tree structure. function old new delta tree_print - 343 +343 scandir64 - 330 +330 scandir - 330 +330 tree_main - 86 +86 .rodata 105150 105228 +78 packed_usage 34511 34557 +46 alphasort64 - 31 +31 alphasort - 31 +31 strcoll - 5 +5 applet_names 2801 2806 +5 applet_main 1616 1620 +4 applet_suid 101 102 +1 applet_install_loc 202 203 +1 ------------------------------------------------------------------------------ (add/remove: 11/0 grow/shrink: 6/0 up/down: 1291/0) Total: 1291 bytes Signed-off-by: Roger Knecht <rknecht@pm.me> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
		
				
					committed by
					
						 Denys Vlasenko
						Denys Vlasenko
					
				
			
			
				
	
			
			
			
						parent
						
							2617a5e4c6
						
					
				
				
					commit
					20a4f70eca
				
			
							
								
								
									
										118
									
								
								miscutils/tree.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								miscutils/tree.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,118 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * Copyright (C) 2022 Roger Knecht <rknecht@pm.me> | ||||
|  * | ||||
|  * Licensed under GPLv2, see file LICENSE in this source tree. | ||||
|  */ | ||||
| //config:config TREE | ||||
| //config:	bool "tree (0.6 kb)" | ||||
| //config:	default y | ||||
| //config:	help | ||||
| //config:	List files and directories in a tree structure. | ||||
|  | ||||
| //applet:IF_TREE(APPLET(tree, BB_DIR_USR_BIN, BB_SUID_DROP)) | ||||
|  | ||||
| //kbuild:lib-$(CONFIG_TREE) += tree.o | ||||
|  | ||||
| //usage:#define tree_trivial_usage NOUSAGE_STR | ||||
| //usage:#define tree_full_usage "" | ||||
|  | ||||
| #include "libbb.h" | ||||
| #include "common_bufsiz.h" | ||||
|  | ||||
| #define prefix_buf bb_common_bufsiz1 | ||||
|  | ||||
| static void tree_print(unsigned count[2], const char* directory_name, char* prefix_pos) | ||||
| { | ||||
| 	struct dirent **entries; | ||||
| 	int index, size; | ||||
|  | ||||
| 	// read directory entries | ||||
| 	size = scandir(directory_name, &entries, NULL, alphasort); | ||||
|  | ||||
| 	if (size < 0) { | ||||
| 		fputs_stdout(directory_name); | ||||
| 		puts(" [error opening dir]"); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	// print directory name | ||||
| 	puts(directory_name); | ||||
|  | ||||
| 	// switch to sub directory | ||||
| 	xchdir(directory_name); | ||||
|  | ||||
| 	// print all directory entries | ||||
| 	for (index = 0; index < size;) { | ||||
| 		struct dirent *dirent = entries[index++]; | ||||
|  | ||||
| 		// filter hidden files and directories | ||||
| 		if (dirent->d_name[0] != '.') { | ||||
| 			int status; | ||||
| 			struct stat statBuf; | ||||
|  | ||||
| //TODO: when -l is implemented, use stat, not lstat, if -l | ||||
| 			status = lstat(dirent->d_name, &statBuf); | ||||
|  | ||||
| 			if (index == size) { | ||||
| 				strcpy(prefix_pos, "└── "); | ||||
| 			} else { | ||||
| 				strcpy(prefix_pos, "├── "); | ||||
| 			} | ||||
| 			fputs_stdout(prefix_buf); | ||||
|  | ||||
| 			if (status == 0 && S_ISLNK(statBuf.st_mode)) { | ||||
| 				// handle symlink | ||||
| 				char* symlink_path = xmalloc_readlink(dirent->d_name); | ||||
| 				printf("%s -> %s\n", dirent->d_name, symlink_path); | ||||
| 				free(symlink_path); | ||||
| 				count[1]++; | ||||
| 			} else if (status == 0 && S_ISDIR(statBuf.st_mode) | ||||
| 			 && (prefix_pos - prefix_buf) < (COMMON_BUFSIZE - 16) | ||||
| 			) { | ||||
| 				// handle directory | ||||
| 				char* pos; | ||||
| 				if (index == size) { | ||||
| 					pos = stpcpy(prefix_pos, "    "); | ||||
| 				} else { | ||||
| 					pos = stpcpy(prefix_pos, "│   "); | ||||
| 				} | ||||
| 				tree_print(count, dirent->d_name, pos); | ||||
| 				count[0]++; | ||||
| 			} else { | ||||
| 				// handle file | ||||
| 				puts(dirent->d_name); | ||||
| 				count[1]++; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// release directory entry | ||||
| 		free(dirent); | ||||
| 	} | ||||
|  | ||||
| 	// release directory array | ||||
| 	free(entries); | ||||
|  | ||||
| 	// switch to parent directory | ||||
| 	xchdir(".."); | ||||
| } | ||||
|  | ||||
| int tree_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||||
| int tree_main(int argc UNUSED_PARAM, char **argv) | ||||
| { | ||||
| 	unsigned count[2] = { 0, 0 }; | ||||
|  | ||||
| 	setup_common_bufsiz(); | ||||
|  | ||||
| 	if (!argv[1]) | ||||
| 		*argv-- = (char*)"."; | ||||
|  | ||||
| 	// list directories given as command line arguments | ||||
| 	while (*(++argv)) | ||||
| 		tree_print(count, *argv, prefix_buf); | ||||
|  | ||||
| 	// print statistic | ||||
| 	printf("\n%u directories, %u files\n", count[0], count[1]); | ||||
|  | ||||
| 	return EXIT_SUCCESS; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user