X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=du.c;h=fb649aee5e15f6720bec55ee5f4caebc9fbceb41;hb=6fc92a506ab3c490a4dc028334c908f19c0d0806;hp=f1a44427abf5c88dca2b45a10e243b34d419e868;hpb=17ad45aace3141d1b997208a43979495ead98f7c;p=oweals%2Fbusybox.git diff --git a/du.c b/du.c index f1a44427a..fb649aee5 100644 --- a/du.c +++ b/du.c @@ -3,7 +3,7 @@ * Mini du implementation for busybox * * - * Copyright (C) 1999,2000 by Lineo, inc. + * Copyright (C) 1999,2000,2001 by Lineo, inc. * Written by John Beppu * * This program is free software; you can redistribute it and/or modify @@ -22,29 +22,22 @@ * */ -#include "internal.h" -#define BB_DECLARE_EXTERN -#define bb_need_name_too_long -#include "messages.c" - #include #include #include #include +#include +#include +#include #include +#include "busybox.h" -typedef void (Display) (long, char *); -static const char du_usage[] = - "du [OPTION]... [FILE]...\n" -#ifndef BB_FEATURE_TRIVIAL_HELP - "\nSummarizes disk space used for each FILE and/or directory.\n" - "Disk space is printed in units of 1024 bytes.\n\n" - "Options:\n" - "\t-l\tcount sizes many times if hard linked\n" - "\t-s\tdisplay only a total for each argument\n" +#ifdef BB_FEATURE_HUMAN_READABLE +static unsigned long disp_hr = KILOBYTE; #endif - ; + +typedef void (Display) (long, char *); static int du_depth = 0; static int count_hardlinks = 0; @@ -53,7 +46,11 @@ static Display *print; static void print_normal(long size, char *filename) { - fprintf(stdout, "%ld\t%s\n", size, filename); +#ifdef BB_FEATURE_HUMAN_READABLE + printf("%s\t%s\n", make_human_readable_str(size<<10, 1, disp_hr), filename); +#else + printf("%ld\t%s\n", size, filename); +#endif } static void print_summary(long size, char *filename) @@ -63,15 +60,86 @@ static void print_summary(long size, char *filename) } } +#define HASH_SIZE 311 /* Should be prime */ +#define hash_inode(i) ((i) % HASH_SIZE) + +typedef struct ino_dev_hash_bucket_struct { + struct ino_dev_hash_bucket_struct *next; + ino_t ino; + dev_t dev; + char name[1]; +} ino_dev_hashtable_bucket_t; + +static ino_dev_hashtable_bucket_t *ino_dev_hashtable[HASH_SIZE]; + +/* + * Return 1 if statbuf->st_ino && statbuf->st_dev are recorded in + * `ino_dev_hashtable', else return 0 + * + * If NAME is a non-NULL pointer to a character pointer, and there is + * a match, then set *NAME to the value of the name slot in that + * bucket. + */ +static int is_in_ino_dev_hashtable(const struct stat *statbuf, char **name) +{ + ino_dev_hashtable_bucket_t *bucket; + + bucket = ino_dev_hashtable[hash_inode(statbuf->st_ino)]; + while (bucket != NULL) { + if ((bucket->ino == statbuf->st_ino) && + (bucket->dev == statbuf->st_dev)) + { + if (name) *name = bucket->name; + return 1; + } + bucket = bucket->next; + } + return 0; +} + +/* Add statbuf to statbuf hash table */ +static void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name) +{ + int i; + size_t s; + ino_dev_hashtable_bucket_t *bucket; + + i = hash_inode(statbuf->st_ino); + s = name ? strlen(name) : 0; + bucket = xmalloc(sizeof(ino_dev_hashtable_bucket_t) + s); + bucket->ino = statbuf->st_ino; + bucket->dev = statbuf->st_dev; + if (name) + strcpy(bucket->name, name); + else + bucket->name[0] = '\0'; + bucket->next = ino_dev_hashtable[i]; + ino_dev_hashtable[i] = bucket; +} + +/* Clear statbuf hash table */ +static void reset_ino_dev_hashtable(void) +{ + int i; + ino_dev_hashtable_bucket_t *bucket; + + for (i = 0; i < HASH_SIZE; i++) { + while (ino_dev_hashtable[i] != NULL) { + bucket = ino_dev_hashtable[i]->next; + free(ino_dev_hashtable[i]); + ino_dev_hashtable[i] = bucket; + } + } +} + /* tiny recursive du */ static long du(char *filename) { struct stat statbuf; long sum; - int len; if ((lstat(filename, &statbuf)) != 0) { - printf("du: %s: %s\n", filename, strerror(errno)); + perror_msg("%s", filename); return 0; } @@ -81,12 +149,13 @@ static long du(char *filename) /* Don't add in stuff pointed to by symbolic links */ if (S_ISLNK(statbuf.st_mode)) { sum = 0L; - if (du_depth == 1) - print(sum, filename); + if (du_depth == 1) { + } } if (S_ISDIR(statbuf.st_mode)) { DIR *dir; struct dirent *entry; + char *newfile; dir = opendir(filename); if (!dir) { @@ -94,27 +163,20 @@ static long du(char *filename) return 0; } - len = strlen(filename); - if (filename[len - 1] == '/') - filename[--len] = '\0'; + newfile = last_char_is(filename, '/'); + if (newfile) + *newfile = '\0'; while ((entry = readdir(dir))) { - char newfile[BUFSIZ + 1]; char *name = entry->d_name; if ((strcmp(name, "..") == 0) || (strcmp(name, ".") == 0)) { continue; } - - if (len + strlen(name) + 1 > BUFSIZ) { - errorMsg(name_too_long); - du_depth--; - return 0; - } - sprintf(newfile, "%s/%s", filename, name); - + newfile = concat_path_file(filename, name); sum += du(newfile); + free(newfile); } closedir(dir); print(sum, filename); @@ -136,14 +198,19 @@ static long du(char *filename) int du_main(int argc, char **argv) { + int status = EXIT_SUCCESS; int i; - char c; + int c; /* default behaviour */ print = print_normal; /* parse argv[] */ - while ((c = getopt(argc, argv, "sl")) != EOF) { + while ((c = getopt(argc, argv, "sl" +#ifdef BB_FEATURE_HUMAN_READABLE +"hm" +#endif +"k")) != EOF) { switch (c) { case 's': print = print_summary; @@ -151,30 +218,36 @@ int du_main(int argc, char **argv) case 'l': count_hardlinks = 1; break; +#ifdef BB_FEATURE_HUMAN_READABLE + case 'h': disp_hr = 0; break; + case 'm': disp_hr = MEGABYTE; break; +#endif + case 'k': break; default: - usage(du_usage); + show_usage(); } } /* go through remaining args (if any) */ if (optind >= argc) { - du("."); + if (du(".") == 0) + status = EXIT_FAILURE; } else { long sum; for (i=optind; i < argc; i++) { sum = du(argv[i]); - if (sum && isDirectory(argv[i], FALSE, NULL)) { + if(is_directory(argv[i], FALSE, NULL)==FALSE) { print_normal(sum, argv[i]); } reset_ino_dev_hashtable(); } } - return(0); + return status; } -/* $Id: du.c,v 1.22 2000/07/14 18:38:26 andersen Exp $ */ +/* $Id: du.c,v 1.50 2001/06/30 17:54:20 andersen Exp $ */ /* Local Variables: c-file-style: "linux"