summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJim Meyering <meyering@redhat.com>2008-11-24 09:55:55 +0100
committerJim Meyering <meyering@redhat.com>2008-12-02 13:12:13 +0100
commit031e2fb5e9501fb9cda4d739a92abb02e2b05a52 (patch)
tree1ac3a5640ea8d70cd9ee8de9ea182ed330067aa8 /src
parente181802521d4e19e367dbe8cfa877296bb5dafb2 (diff)
downloadcoreutils-031e2fb5e9501fb9cda4d739a92abb02e2b05a52.tar.xz
du: read and process --files0-from= input a name at a time,
rather than by reading the entire input into memory and *then* processing each file name. * src/du.c: Include "argv-iter.h", not "readtokens0.h". (main): Rewrite to use argv-iter. Call xfts_open on each argument, rather than on the entire argv list at once. Call print_size here, not from du_files. Diagnose read failure. * NEWS (Bug fixes): Mention it. * THANKS: update. Reported by Barry Kelly. More details in http://article.gmane.org/gmane.comp.gnu.core-utils.bugs/15159/
Diffstat (limited to 'src')
-rw-r--r--src/du.c140
1 files changed, 77 insertions, 63 deletions
diff --git a/src/du.c b/src/du.c
index e5669786d..6e4d28b64 100644
--- a/src/du.c
+++ b/src/du.c
@@ -30,6 +30,7 @@
#include <assert.h>
#include "system.h"
#include "argmatch.h"
+#include "argv-iter.h"
#include "error.h"
#include "exclude.h"
#include "fprintftime.h"
@@ -37,7 +38,6 @@
#include "human.h"
#include "quote.h"
#include "quotearg.h"
-#include "readtokens0.h"
#include "same.h"
#include "stat-time.h"
#include "xfts.h"
@@ -649,9 +649,6 @@ du_files (char **files, int bit_flags)
fts_close (fts);
}
- if (print_grand_total)
- print_size (&tot_dui, _("total"));
-
return ok;
}
@@ -660,10 +657,8 @@ main (int argc, char **argv)
{
char *cwd_only[2];
bool max_depth_specified = false;
- char **files;
bool ok = true;
char *files_from = NULL;
- struct Tokens tok;
/* Bit flags that control how fts works. */
int bit_flags = FTS_TIGHT_CYCLE_CHECK;
@@ -926,6 +921,7 @@ main (int argc, char **argv)
}
}
+ struct argv_iterator *ai;
if (files_from)
{
/* When using --files0-from=F, you may not specify any files
@@ -942,78 +938,96 @@ main (int argc, char **argv)
error (EXIT_FAILURE, errno, _("cannot open %s for reading"),
quote (files_from));
- readtokens0_init (&tok);
-
- if (! readtokens0 (stdin, &tok) || fclose (stdin) != 0)
- error (EXIT_FAILURE, 0, _("cannot read file names from %s"),
- quote (files_from));
-
- files = tok.tok;
+ ai = argv_iter_init_stream (stdin);
}
else
{
- files = (optind < argc ? argv + optind : cwd_only);
+ char **files = (optind < argc ? argv + optind : cwd_only);
+ ai = argv_iter_init_argv (files);
}
+ if (!ai)
+ xalloc_die ();
+
/* Initialize the hash structure for inode numbers. */
hash_init ();
- /* Report and filter out any empty file names before invoking fts.
- This works around a glitch in fts, which fails immediately
- (without looking at the other file names) when given an empty
- file name. */
- {
- size_t i = 0;
- size_t j;
+ bit_flags |= symlink_deref_bits;
+ static char *temp_argv[] = { NULL, NULL };
- for (j = 0; ; j++)
- {
- if (i != j)
- files[i] = files[j];
+ while (true)
+ {
+ bool skip_file = false;
+ enum argv_iter_err ai_err;
+ char *file_name = argv_iter (ai, &ai_err);
+ if (ai_err == AI_ERR_EOF)
+ break;
+ if (!file_name)
+ {
+ switch (ai_err)
+ {
+ case AI_ERR_READ:
+ error (0, errno, _("%s: read error"), quote (files_from));
+ skip_file = true;
+ continue;
- if ( ! files[i])
- break;
+ case AI_ERR_MEM:
+ xalloc_die ();
- if (files_from && STREQ (files_from, "-") && STREQ (files[i], "-"))
- {
- /* Give a better diagnostic in an unusual case:
- printf - | du --files0-from=- */
- error (0, 0, _("when reading file names from stdin, "
- "no file name of %s allowed"),
- quote ("-"));
- continue;
- }
+ default:
+ assert (!"unexpected error code from argv_iter");
+ }
+ }
+ if (files_from && STREQ (files_from, "-") && STREQ (file_name, "-"))
+ {
+ /* Give a better diagnostic in an unusual case:
+ printf - | du --files0-from=- */
+ error (0, 0, _("when reading file names from stdin, "
+ "no file name of %s allowed"),
+ quote (file_name));
+ skip_file = true;
+ }
- if (files[i][0])
- i++;
- else
- {
- /* Diagnose a zero-length file name. When it's one
- among many, knowing the record number may help. */
- if (files_from)
- {
- /* Using the standard `filename:line-number:' prefix here is
- not totally appropriate, since NUL is the separator, not NL,
- but it might be better than nothing. */
- unsigned long int file_number = j + 1;
- error (0, 0, "%s:%lu: %s", quotearg_colon (files_from),
- file_number, _("invalid zero-length file name"));
- }
- else
- error (0, 0, "%s", _("invalid zero-length file name"));
- }
- }
+ /* Report and skip any empty file names before invoking fts.
+ This works around a glitch in fts, which fails immediately
+ (without looking at the other file names) when given an empty
+ file name. */
+ if (!file_name[0])
+ {
+ /* Diagnose a zero-length file name. When it's one
+ among many, knowing the record number may help.
+ FIXME: currently print the record number only with
+ --files0-from=FILE. Maybe do it for argv, too? */
+ if (files_from == NULL)
+ error (0, 0, "%s", _("invalid zero-length file name"));
+ else
+ {
+ /* Using the standard `filename:line-number:' prefix here is
+ not totally appropriate, since NUL is the separator, not NL,
+ but it might be better than nothing. */
+ unsigned long int file_number = argv_iter_n_args (ai);
+ error (0, 0, "%s:%lu: %s", quotearg_colon (files_from),
+ file_number, _("invalid zero-length file name"));
+ }
+ skip_file = true;
+ }
+
+ if (skip_file)
+ ok = false;
+ else
+ {
+ temp_argv[0] = file_name;
+ ok &= du_files (temp_argv, bit_flags);
+ }
+ }
- ok = (i == j);
- }
+ argv_iter_free (ai);
- bit_flags |= symlink_deref_bits;
- ok &= du_files (files, bit_flags);
+ if (files_from && (ferror (stdin) || fclose (stdin) != 0))
+ error (EXIT_FAILURE, 0, _("error reading %s"), quote (files_from));
- /* This isn't really necessary, but it does ensure we
- exercise this function. */
- if (files_from)
- readtokens0_free (&tok);
+ if (print_grand_total)
+ print_size (&tot_dui, _("total"));
hash_free (htab);