int stat ();
int lstat ();
-static int hash_insert PARAMS ((ino_t ino, dev_t dev));
-static int hash_insert2 PARAMS ((struct htab *_htab, ino_t ino, dev_t dev));
-static uintmax_t count_entry PARAMS ((const char *ent, int top, dev_t last_dev,
- int depth));
-static void du_files PARAMS ((char **files));
-static void hash_init PARAMS ((unsigned int modulus,
- unsigned int entry_tab_size));
-static void hash_reset PARAMS ((void));
-static void str_concatc PARAMS ((String *s1, char *cstr));
-static void str_copyc PARAMS ((String *s1, char *cstr));
-static void str_init PARAMS ((String **s1, unsigned int size));
-static void str_trunc PARAMS ((String *s1, unsigned int length));
-
/* Name under which this program was invoked. */
char *program_name;
exit (status);
}
-int
-main (int argc, char **argv)
-{
- int c;
- char *cwd_only[2];
- int max_depth_specified = 0;
-
- /* If nonzero, display only a total for each argument. */
- int opt_summarize_only = 0;
-
- cwd_only[0] = ".";
- cwd_only[1] = NULL;
+/* Initialize string S1 to hold SIZE characters. */
- program_name = argv[0];
- setlocale (LC_ALL, "");
- bindtextdomain (PACKAGE, LOCALEDIR);
- textdomain (PACKAGE);
+static void
+str_init (String **s1, unsigned int size)
+{
+ String *s;
- exclude = new_exclude ();
- xstat = lstat;
+ s = (String *) xmalloc (sizeof (struct String));
+ s->text = xmalloc (size + 1);
- human_block_size (getenv ("DU_BLOCK_SIZE"), 0, &output_block_size);
+ s->alloc = size;
+ *s1 = s;
+}
- while ((c = getopt_long (argc, argv, "abchHklmsxDLSX:", long_options, NULL))
- != -1)
+static void
+ensure_space (String *s, unsigned int size)
+{
+ if (s->alloc < size)
{
- long int tmp_long;
- switch (c)
- {
- case 0: /* Long option. */
- break;
-
- case 'a':
- opt_all = 1;
- break;
-
- case 'b':
- output_block_size = 1;
- break;
-
- case 'c':
- opt_combined_arguments = 1;
- break;
-
- case 'h':
- output_block_size = -1024;
- break;
-
- case 'H':
- output_block_size = -1000;
- break;
-
- case 'k':
- output_block_size = 1024;
- break;
-
- case CHAR_MAX + 3: /* --max-depth=N */
- if (xstrtol (optarg, NULL, 0, &tmp_long, NULL) != LONGINT_OK
- || tmp_long < 0 || tmp_long > INT_MAX)
- error (1, 0, _("invalid maximum depth `%s'"), optarg);
-
- max_depth_specified = 1;
- max_depth = (int) tmp_long;
- break;
-
- case 'm':
- output_block_size = 1024 * 1024;
- break;
-
- case 'l':
- opt_count_all = 1;
- break;
-
- case 's':
- opt_summarize_only = 1;
- break;
-
- case 'x':
- opt_one_file_system = 1;
- break;
-
- case 'D':
- opt_dereference_arguments = 1;
- break;
-
- case 'L':
- xstat = stat;
- break;
-
- case 'S':
- opt_separate_dirs = 1;
- break;
-
- case 'X':
- if (add_exclude_file (exclude, optarg, '\n') != 0)
- error (1, errno, "%s", optarg);
- break;
-
- case CHAR_MAX + 1:
- add_exclude (exclude, optarg);
- break;
-
- case CHAR_MAX + 2:
- human_block_size (optarg, 1, &output_block_size);
- break;
+ s->text = xrealloc (s->text, size + 1);
+ s->alloc = size;
+ }
+}
- case_GETOPT_HELP_CHAR;
+/* Assign the null-terminated C-string CSTR to S1. */
- case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
+static void
+str_copyc (String *s1, const char *cstr)
+{
+ unsigned l = strlen (cstr);
+ ensure_space (s1, l);
+ strcpy (s1->text, cstr);
+ s1->length = l;
+}
- default:
- usage (1);
- }
- }
+static void
+str_concatc (String *s1, const char *cstr)
+{
+ unsigned l1 = s1->length;
+ unsigned l2 = strlen (cstr);
+ unsigned l = l1 + l2;
- if (opt_all && opt_summarize_only)
- {
- error (0, 0, _("cannot both summarize and show all entries"));
- usage (1);
- }
+ ensure_space (s1, l);
+ strcpy (s1->text + l1, cstr);
+ s1->length = l;
+}
- if (opt_summarize_only && max_depth_specified && max_depth == 0)
- {
- error (0, 0,
- _("warning: summarizing is the same as using --max-depth=0"));
- }
+/* Truncate the string S1 to have length LENGTH. */
- if (opt_summarize_only && max_depth_specified && max_depth != 0)
+static void
+str_trunc (String *s1, unsigned int length)
+{
+ if (s1->length > length)
{
- error (0, 0,
- _("warning: summarizing conflicts with --max-depth=%d"),
- max_depth);
- usage (1);
+ s1->text[length] = 0;
+ s1->length = length;
}
-
- if (opt_summarize_only)
- max_depth = 0;
-
- /* Initialize the hash structure for inode numbers. */
- hash_init (INITIAL_HASH_MODULE, INITIAL_ENTRY_TAB_SIZE);
-
- str_init (&path, INITIAL_PATH_SIZE);
-
- du_files (optind == argc ? cwd_only : argv + optind);
-
- close_stdout ();
- exit (exit_status);
}
/* Print N_BLOCKS followed by STRING on a line. NBLOCKS is the number of
fflush (stdout);
}
-/* Recursively print the sizes of the directories (and, if selected, files)
- named in FILES, the last entry of which is NULL. */
+/* Reset the hash structure in the global variable `htab' to
+ contain no entries. */
static void
-du_files (char **files)
+hash_reset (void)
{
- struct saved_cwd cwd;
- ino_t initial_ino; /* Initial directory's inode. */
- dev_t initial_dev; /* Initial directory's device. */
- int i; /* Index in FILES. */
-
- if (save_cwd (&cwd))
- exit (1);
-
- /* Remember the inode and device number of the current directory. */
- if (stat (".", &stat_buf))
- error (1, errno, _("current directory"));
- initial_ino = stat_buf.st_ino;
- initial_dev = stat_buf.st_dev;
-
- for (i = 0; files[i]; i++)
- {
- char *arg;
- int s;
+ int i;
+ struct entry **p;
- arg = files[i];
+ htab->first_free_entry = 0;
- /* Delete final slash in the argument, unless the slash is alone. */
- s = strlen (arg) - 1;
- if (s != 0)
- {
- if (arg[s] == '/')
- arg[s] = 0;
+ p = htab->hash;
+ for (i = htab->modulus; i > 0; i--)
+ *p++ = NULL;
+}
- str_copyc (path, arg);
- }
- else if (arg[0] == '/')
- str_trunc (path, 0); /* Null path for root directory. */
- else
- str_copyc (path, arg);
+/* Allocate space for the hash structures, and set the global
+ variable `htab' to point to it. The initial hash module is specified in
+ MODULUS, and the number of entries are specified in ENTRY_TAB_SIZE. (The
+ hash structure will be rebuilt when ENTRY_TAB_SIZE entries have been
+ inserted, and MODULUS and ENTRY_TAB_SIZE in the global `htab' will be
+ doubled.) */
- if (!opt_combined_arguments)
- hash_reset ();
+static void
+hash_init (unsigned int modulus, unsigned int entry_tab_size)
+{
+ struct htab *htab_r;
- count_entry (arg, 1, 0, 0);
+ htab_r = (struct htab *)
+ xmalloc (sizeof (struct htab) + sizeof (struct entry *) * modulus);
- /* chdir if `count_entry' has changed the working directory. */
- if (stat (".", &stat_buf))
- error (1, errno, ".");
- if (stat_buf.st_ino != initial_ino || stat_buf.st_dev != initial_dev)
- {
- if (restore_cwd (&cwd, _("starting directory"), NULL))
- exit (1);
- }
- }
+ htab_r->entry_tab = (struct entry *)
+ xmalloc (sizeof (struct entry) * entry_tab_size);
- if (opt_combined_arguments)
- print_size (tot_size, _("total"));
+ htab_r->modulus = modulus;
+ htab_r->entry_tab_size = entry_tab_size;
+ htab = htab_r;
- free_cwd (&cwd);
+ hash_reset ();
}
-/* Print (if appropriate) the size (in units determined by `output_block_size')
- of file or directory ENT. Return the size of ENT in units of 512-byte
+/* Insert INO and DEV in the hash structure HTAB, if not
+ already present. Return zero if inserted and nonzero if it
+ already existed. */
+
+static int
+hash_insert2 (struct htab *ht, ino_t ino, dev_t dev)
+{
+ struct entry **hp, *ep2, *ep;
+ hp = &ht->hash[ino % ht->modulus];
+ ep2 = *hp;
+
+ /* Collision? */
+
+ if (ep2 != NULL)
+ {
+ ep = ep2;
+
+ /* Search for an entry with the same data. */
+
+ do
+ {
+ if (ep->ino == ino && ep->dev == dev)
+ return 1; /* Found an entry with the same data. */
+ ep = ep->coll_link;
+ }
+ while (ep != NULL);
+
+ /* Did not find it. */
+
+ }
+
+ ep = *hp = &ht->entry_tab[ht->first_free_entry++];
+ ep->ino = ino;
+ ep->dev = dev;
+ ep->coll_link = ep2; /* `ep2' is NULL if no collision. */
+
+ return 0;
+}
+
+/* Insert an item (inode INO and device DEV) in the hash
+ structure in the global variable `htab', if an entry with the same data
+ was not found already. Return zero if the item was inserted and nonzero
+ if it wasn't. */
+
+static int
+hash_insert (ino_t ino, dev_t dev)
+{
+ struct htab *htab_r = htab; /* Initially a copy of the global `htab'. */
+
+ if (htab_r->first_free_entry >= htab_r->entry_tab_size)
+ {
+ int i;
+ struct entry *ep;
+ unsigned modulus;
+ unsigned entry_tab_size;
+
+ /* Increase the number of hash entries, and re-hash the data.
+ The method of shrimping and increasing is made to compactify
+ the heap. If twice as much data would be allocated
+ straightforwardly, we would never re-use a byte of memory. */
+
+ /* Let `htab' shrimp. Keep only the header, not the pointer vector. */
+
+ htab_r = (struct htab *)
+ xrealloc ((char *) htab_r, sizeof (struct htab));
+
+ modulus = 2 * htab_r->modulus;
+ entry_tab_size = 2 * htab_r->entry_tab_size;
+
+ /* Increase the number of possible entries. */
+
+ htab_r->entry_tab = (struct entry *)
+ xrealloc ((char *) htab_r->entry_tab,
+ sizeof (struct entry) * entry_tab_size);
+
+ /* Increase the size of htab again. */
+
+ htab_r = (struct htab *)
+ xrealloc ((char *) htab_r,
+ sizeof (struct htab) + sizeof (struct entry *) * modulus);
+
+ htab_r->modulus = modulus;
+ htab_r->entry_tab_size = entry_tab_size;
+ htab = htab_r;
+
+ i = htab_r->first_free_entry;
+
+ /* Make the increased hash table empty. The entries are still
+ available in htab->entry_tab. */
+
+ hash_reset ();
+
+ /* Go through the entries and install them in the pointer vector
+ htab->hash. The items are actually inserted in htab->entry_tab at
+ the position where they already are. The htab->coll_link need
+ however be updated. Could be made a little more efficient. */
+
+ for (ep = htab_r->entry_tab; i > 0; i--)
+ {
+ hash_insert2 (htab_r, ep->ino, ep->dev);
+ ep++;
+ }
+ }
+
+ return hash_insert2 (htab_r, ino, dev);
+}
+
+/* Print (if appropriate) the size (in units determined by `output_block_size')
+ of file or directory ENT. Return the size of ENT in units of 512-byte
blocks. TOP is one for external calls, zero for recursive calls.
LAST_DEV is the device that the parent directory of ENT is on.
DEPTH is the number of levels (in hierarchy) down from a command
return size;
}
-/* Allocate space for the hash structures, and set the global
- variable `htab' to point to it. The initial hash module is specified in
- MODULUS, and the number of entries are specified in ENTRY_TAB_SIZE. (The
- hash structure will be rebuilt when ENTRY_TAB_SIZE entries have been
- inserted, and MODULUS and ENTRY_TAB_SIZE in the global `htab' will be
- doubled.) */
+/* Recursively print the sizes of the directories (and, if selected, files)
+ named in FILES, the last entry of which is NULL. */
static void
-hash_init (unsigned int modulus, unsigned int entry_tab_size)
+du_files (char **files)
{
- struct htab *htab_r;
+ struct saved_cwd cwd;
+ ino_t initial_ino; /* Initial directory's inode. */
+ dev_t initial_dev; /* Initial directory's device. */
+ int i; /* Index in FILES. */
- htab_r = (struct htab *)
- xmalloc (sizeof (struct htab) + sizeof (struct entry *) * modulus);
+ if (save_cwd (&cwd))
+ exit (1);
- htab_r->entry_tab = (struct entry *)
- xmalloc (sizeof (struct entry) * entry_tab_size);
+ /* Remember the inode and device number of the current directory. */
+ if (stat (".", &stat_buf))
+ error (1, errno, _("current directory"));
+ initial_ino = stat_buf.st_ino;
+ initial_dev = stat_buf.st_dev;
- htab_r->modulus = modulus;
- htab_r->entry_tab_size = entry_tab_size;
- htab = htab_r;
+ for (i = 0; files[i]; i++)
+ {
+ char *arg;
+ int s;
- hash_reset ();
-}
+ arg = files[i];
-/* Reset the hash structure in the global variable `htab' to
- contain no entries. */
+ /* Delete final slash in the argument, unless the slash is alone. */
+ s = strlen (arg) - 1;
+ if (s != 0)
+ {
+ if (arg[s] == '/')
+ arg[s] = 0;
-static void
-hash_reset (void)
-{
- int i;
- struct entry **p;
+ str_copyc (path, arg);
+ }
+ else if (arg[0] == '/')
+ str_trunc (path, 0); /* Null path for root directory. */
+ else
+ str_copyc (path, arg);
- htab->first_free_entry = 0;
+ if (!opt_combined_arguments)
+ hash_reset ();
- p = htab->hash;
- for (i = htab->modulus; i > 0; i--)
- *p++ = NULL;
-}
+ count_entry (arg, 1, 0, 0);
-/* Insert an item (inode INO and device DEV) in the hash
- structure in the global variable `htab', if an entry with the same data
- was not found already. Return zero if the item was inserted and nonzero
- if it wasn't. */
+ /* chdir if `count_entry' has changed the working directory. */
+ if (stat (".", &stat_buf))
+ error (1, errno, ".");
+ if (stat_buf.st_ino != initial_ino || stat_buf.st_dev != initial_dev)
+ {
+ if (restore_cwd (&cwd, _("starting directory"), NULL))
+ exit (1);
+ }
+ }
-static int
-hash_insert (ino_t ino, dev_t dev)
-{
- struct htab *htab_r = htab; /* Initially a copy of the global `htab'. */
+ if (opt_combined_arguments)
+ print_size (tot_size, _("total"));
- if (htab_r->first_free_entry >= htab_r->entry_tab_size)
- {
- int i;
- struct entry *ep;
- unsigned modulus;
- unsigned entry_tab_size;
+ free_cwd (&cwd);
+}
- /* Increase the number of hash entries, and re-hash the data.
- The method of shrimping and increasing is made to compactify
- the heap. If twice as much data would be allocated
- straightforwardly, we would never re-use a byte of memory. */
+int
+main (int argc, char **argv)
+{
+ int c;
+ char *cwd_only[2];
+ int max_depth_specified = 0;
- /* Let `htab' shrimp. Keep only the header, not the pointer vector. */
+ /* If nonzero, display only a total for each argument. */
+ int opt_summarize_only = 0;
- htab_r = (struct htab *)
- xrealloc ((char *) htab_r, sizeof (struct htab));
+ cwd_only[0] = ".";
+ cwd_only[1] = NULL;
- modulus = 2 * htab_r->modulus;
- entry_tab_size = 2 * htab_r->entry_tab_size;
+ program_name = argv[0];
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
- /* Increase the number of possible entries. */
+ exclude = new_exclude ();
+ xstat = lstat;
- htab_r->entry_tab = (struct entry *)
- xrealloc ((char *) htab_r->entry_tab,
- sizeof (struct entry) * entry_tab_size);
+ human_block_size (getenv ("DU_BLOCK_SIZE"), 0, &output_block_size);
- /* Increase the size of htab again. */
+ while ((c = getopt_long (argc, argv, "abchHklmsxDLSX:", long_options, NULL))
+ != -1)
+ {
+ long int tmp_long;
+ switch (c)
+ {
+ case 0: /* Long option. */
+ break;
- htab_r = (struct htab *)
- xrealloc ((char *) htab_r,
- sizeof (struct htab) + sizeof (struct entry *) * modulus);
+ case 'a':
+ opt_all = 1;
+ break;
- htab_r->modulus = modulus;
- htab_r->entry_tab_size = entry_tab_size;
- htab = htab_r;
+ case 'b':
+ output_block_size = 1;
+ break;
- i = htab_r->first_free_entry;
+ case 'c':
+ opt_combined_arguments = 1;
+ break;
- /* Make the increased hash table empty. The entries are still
- available in htab->entry_tab. */
+ case 'h':
+ output_block_size = -1024;
+ break;
- hash_reset ();
+ case 'H':
+ output_block_size = -1000;
+ break;
- /* Go through the entries and install them in the pointer vector
- htab->hash. The items are actually inserted in htab->entry_tab at
- the position where they already are. The htab->coll_link need
- however be updated. Could be made a little more efficient. */
+ case 'k':
+ output_block_size = 1024;
+ break;
- for (ep = htab_r->entry_tab; i > 0; i--)
- {
- hash_insert2 (htab_r, ep->ino, ep->dev);
- ep++;
- }
- }
+ case CHAR_MAX + 3: /* --max-depth=N */
+ if (xstrtol (optarg, NULL, 0, &tmp_long, NULL) != LONGINT_OK
+ || tmp_long < 0 || tmp_long > INT_MAX)
+ error (1, 0, _("invalid maximum depth `%s'"), optarg);
- return hash_insert2 (htab_r, ino, dev);
-}
+ max_depth_specified = 1;
+ max_depth = (int) tmp_long;
+ break;
-/* Insert INO and DEV in the hash structure HTAB, if not
- already present. Return zero if inserted and nonzero if it
- already existed. */
+ case 'm':
+ output_block_size = 1024 * 1024;
+ break;
-static int
-hash_insert2 (struct htab *ht, ino_t ino, dev_t dev)
-{
- struct entry **hp, *ep2, *ep;
- hp = &ht->hash[ino % ht->modulus];
- ep2 = *hp;
+ case 'l':
+ opt_count_all = 1;
+ break;
- /* Collision? */
+ case 's':
+ opt_summarize_only = 1;
+ break;
- if (ep2 != NULL)
- {
- ep = ep2;
+ case 'x':
+ opt_one_file_system = 1;
+ break;
- /* Search for an entry with the same data. */
+ case 'D':
+ opt_dereference_arguments = 1;
+ break;
- do
- {
- if (ep->ino == ino && ep->dev == dev)
- return 1; /* Found an entry with the same data. */
- ep = ep->coll_link;
- }
- while (ep != NULL);
+ case 'L':
+ xstat = stat;
+ break;
- /* Did not find it. */
+ case 'S':
+ opt_separate_dirs = 1;
+ break;
- }
+ case 'X':
+ if (add_exclude_file (exclude, optarg, '\n') != 0)
+ error (1, errno, "%s", optarg);
+ break;
- ep = *hp = &ht->entry_tab[ht->first_free_entry++];
- ep->ino = ino;
- ep->dev = dev;
- ep->coll_link = ep2; /* `ep2' is NULL if no collision. */
+ case CHAR_MAX + 1:
+ add_exclude (exclude, optarg);
+ break;
- return 0;
-}
+ case CHAR_MAX + 2:
+ human_block_size (optarg, 1, &output_block_size);
+ break;
-/* Initialize string S1 to hold SIZE characters. */
+ case_GETOPT_HELP_CHAR;
-static void
-str_init (String **s1, unsigned int size)
-{
- String *s;
+ case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
- s = (String *) xmalloc (sizeof (struct String));
- s->text = xmalloc (size + 1);
+ default:
+ usage (1);
+ }
+ }
- s->alloc = size;
- *s1 = s;
-}
+ if (opt_all && opt_summarize_only)
+ {
+ error (0, 0, _("cannot both summarize and show all entries"));
+ usage (1);
+ }
-static void
-ensure_space (String *s, unsigned int size)
-{
- if (s->alloc < size)
+ if (opt_summarize_only && max_depth_specified && max_depth == 0)
{
- s->text = xrealloc (s->text, size + 1);
- s->alloc = size;
+ error (0, 0,
+ _("warning: summarizing is the same as using --max-depth=0"));
}
-}
-/* Assign the null-terminated C-string CSTR to S1. */
+ if (opt_summarize_only && max_depth_specified && max_depth != 0)
+ {
+ error (0, 0,
+ _("warning: summarizing conflicts with --max-depth=%d"),
+ max_depth);
+ usage (1);
+ }
-static void
-str_copyc (String *s1, char *cstr)
-{
- unsigned l = strlen (cstr);
- ensure_space (s1, l);
- strcpy (s1->text, cstr);
- s1->length = l;
-}
+ if (opt_summarize_only)
+ max_depth = 0;
-static void
-str_concatc (String *s1, char *cstr)
-{
- unsigned l1 = s1->length;
- unsigned l2 = strlen (cstr);
- unsigned l = l1 + l2;
+ /* Initialize the hash structure for inode numbers. */
+ hash_init (INITIAL_HASH_MODULE, INITIAL_ENTRY_TAB_SIZE);
- ensure_space (s1, l);
- strcpy (s1->text + l1, cstr);
- s1->length = l;
-}
+ str_init (&path, INITIAL_PATH_SIZE);
-/* Truncate the string S1 to have length LENGTH. */
+ du_files (optind == argc ? cwd_only : argv + optind);
-static void
-str_trunc (String *s1, unsigned int length)
-{
- if (s1->length > length)
- {
- s1->text[length] = 0;
- s1->length = length;
- }
+ close_stdout ();
+ exit (exit_status);
}