mirror of
https://git.savannah.gnu.org/git/coreutils.git
synced 2025-09-10 07:59:52 +02:00
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/
This commit is contained in:
3
NEWS
3
NEWS
@@ -12,6 +12,9 @@ GNU coreutils NEWS -*- outline -*-
|
||||
|
||||
cp uses much less memory in some situations
|
||||
|
||||
du --files0-from=FILE no longer reads all of FILE into RAM before
|
||||
processing the first file name
|
||||
|
||||
seq 9223372036854775807 9223372036854775808 now prints only two numbers
|
||||
on systems with extended long double support and good library support.
|
||||
Even with this patch, on some systems, it still produces invalid output,
|
||||
|
||||
1
THANKS
1
THANKS
@@ -58,6 +58,7 @@ Augey Mikus mikus@dqc.org
|
||||
Aurelien Jarno aurel32@debian.org
|
||||
Austin Donnelly Austin.Donnelly@cl.cam.ac.uk
|
||||
Axel Kittenberger Anshil@gmx.net
|
||||
Barry Kelly http://barrkel.blogspot.com/
|
||||
Bauke Jan Douma bjdouma@xs4all.nl
|
||||
Ben Elliston bje@air.net.au
|
||||
Ben Harris bjh21@netbsd.org
|
||||
|
||||
150
src/du.c
150
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;
|
||||
|
||||
for (j = 0; ; j++)
|
||||
{
|
||||
if (i != j)
|
||||
files[i] = files[j];
|
||||
|
||||
if ( ! files[i])
|
||||
break;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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"));
|
||||
}
|
||||
}
|
||||
|
||||
ok = (i == j);
|
||||
}
|
||||
|
||||
bit_flags |= symlink_deref_bits;
|
||||
ok &= du_files (files, bit_flags);
|
||||
static char *temp_argv[] = { NULL, NULL };
|
||||
|
||||
/* This isn't really necessary, but it does ensure we
|
||||
exercise this function. */
|
||||
if (files_from)
|
||||
readtokens0_free (&tok);
|
||||
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;
|
||||
|
||||
case AI_ERR_MEM:
|
||||
xalloc_die ();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
argv_iter_free (ai);
|
||||
|
||||
if (files_from && (ferror (stdin) || fclose (stdin) != 0))
|
||||
error (EXIT_FAILURE, 0, _("error reading %s"), quote (files_from));
|
||||
|
||||
if (print_grand_total)
|
||||
print_size (&tot_dui, _("total"));
|
||||
|
||||
hash_free (htab);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user