Package: coreutils;
Reported by: Samuel Thibault <samuel.thibault <at> gnu.org>
Date: Mon, 7 May 2012 00:59:02 UTC
Severity: normal
Done: Jim Meyering <jim <at> meyering.net>
Bug is archived. No further changes may be made.
Message #11 received at 11424 <at> debbugs.gnu.org (full text, mbox):
From: Paul Eggert <eggert <at> cs.ucla.edu> To: Samuel Thibault <samuel.thibault <at> gnu.org> Cc: 11424 <at> debbugs.gnu.org Subject: Re: bug#11424: coreutils: split tests hang on /dev/zero on GNU/Hurd Date: Mon, 07 May 2012 00:50:00 -0700
Thanks, here's a quick cut at a patch to 'split' to fix the problem. Also, the test cases also need to be adjusted, so as not to attempt to split -n on a device. diff --git a/src/split.c b/src/split.c index 99f6390..8b966bc 100644 --- a/src/split.c +++ b/src/split.c @@ -1344,7 +1344,9 @@ main (int argc, char **argv) if (split_type == type_chunk_bytes || split_type == type_chunk_lines) { off_t input_offset = lseek (STDIN_FILENO, 0, SEEK_CUR); - if (input_offset < 0) + if (input_offset < 0 + || ! (S_ISREG (stat_buf.st_mode) + || S_TYPEISSHM (&stat_buf) || S_TYPEISTMO (&stat_buf))) error (EXIT_FAILURE, 0, _("%s: cannot determine file size"), quote (infile)); file_size -= input_offset; I audited coreutils for other misuses of st_size and found some; here are additional quick cuts at patches that look like they're needed. I didn't attempt to look for missed optimizations; just errors. diff --git a/src/dd.c b/src/dd.c index 4626de2..147b69d 100644 --- a/src/dd.c +++ b/src/dd.c @@ -1544,7 +1544,8 @@ skip (int fdesc, char const *file, uintmax_t records, size_t blocksize, struct stat st; if (fstat (STDIN_FILENO, &st) != 0) error (EXIT_FAILURE, errno, _("cannot fstat %s"), quote (file)); - if (S_ISREG (st.st_mode) && st.st_size < (input_offset + offset)) + if ((S_ISREG (st.st_mode) || S_TYPEISSHM (&st) || S_TYPEISTMO (&st)) + && st.st_size < input_offset + offset) { /* When skipping past EOF, return the number of _full_ blocks * that are not skipped, and set offset to EOF, so the caller @@ -2104,8 +2105,8 @@ dd_copy (void) } } - /* If the last write was converted to a seek, then for a regular file, - ftruncate to extend the size. */ + /* If the last write was converted to a seek, then for a regular file + or shared memory object, ftruncate to extend the size. */ if (final_op_was_seek) { struct stat stdout_stat; @@ -2114,7 +2115,7 @@ dd_copy (void) error (0, errno, _("cannot fstat %s"), quote (output_file)); return EXIT_FAILURE; } - if (S_ISREG (stdout_stat.st_mode)) + if (S_ISREG (stdout_stat.st_mode) || S_TYPEISSHM (&stdout_stat)) { off_t output_offset = lseek (STDOUT_FILENO, 0, SEEK_CUR); if (output_offset > stdout_stat.st_size) diff --git a/src/du.c b/src/du.c index 41c9535..7333941 100644 --- a/src/du.c +++ b/src/du.c @@ -99,7 +99,8 @@ duinfo_set (struct duinfo *a, uintmax_t size, struct timespec tmax) static inline void duinfo_add (struct duinfo *a, struct duinfo const *b) { - a->size += b->size; + uintmax_t sum = a->size + b->size; + a->size = a->size <= sum ? sum : UINTMAX_MAX; if (timespec_cmp (a->tmax, b->tmax) < 0) a->tmax = b->tmax; } @@ -370,8 +371,11 @@ static void print_only_size (uintmax_t n_bytes) { char buf[LONGEST_HUMAN_READABLE + 1]; - fputs (human_readable (n_bytes, buf, human_output_opts, - 1, output_block_size), stdout); + fputs ((n_bytes == UINTMAX_MAX + ? _("Infinity") + : human_readable (n_bytes, buf, human_output_opts, + 1, output_block_size)), + stdout); } /* Print size (and optionally time) indicated by *PDUI, followed by STRING. */ @@ -495,7 +499,7 @@ process_file (FTS *fts, FTSENT *ent) duinfo_set (&dui, (apparent_size - ? sb->st_size + ? MAX (0, sb->st_size) : (uintmax_t) ST_NBLOCKS (*sb) * ST_NBLOCKSIZE), (time_type == time_mtime ? get_stat_mtime (sb) : time_type == time_atime ? get_stat_atime (sb) diff --git a/src/od.c b/src/od.c index 7593796..a25f965 100644 --- a/src/od.c +++ b/src/od.c @@ -983,8 +983,7 @@ skip (uintmax_t n_skip) if (fstat (fileno (in_stream), &file_stats) == 0) { - /* The st_size field is valid only for regular files - (and for symbolic links, which cannot occur here). + /* The st_size field is valid for regular files. If the number of bytes left to skip is larger than the size of the current file, we can decrement n_skip and go on to the next file. Skip this optimization also diff --git a/src/stat.c b/src/stat.c index b2e1030..d001cda 100644 --- a/src/stat.c +++ b/src/stat.c @@ -954,7 +954,7 @@ print_stat (char *pformat, size_t prefix_len, unsigned int m, out_uint_x (pformat, prefix_len, minor (statbuf->st_rdev)); break; case 's': - out_uint (pformat, prefix_len, statbuf->st_size); + out_int (pformat, prefix_len, statbuf->st_size); break; case 'B': out_uint (pformat, prefix_len, ST_NBLOCKSIZE); diff --git a/src/truncate.c b/src/truncate.c index 9b847d2..eaef598 100644 --- a/src/truncate.c +++ b/src/truncate.c @@ -161,7 +161,8 @@ do_ftruncate (int fd, char const *fname, off_t ssize, off_t rsize, if (rsize < 0) /* fstat used above to get size. */ { - if (!S_ISREG (sb.st_mode) && !S_TYPEISSHM (&sb)) + if (!S_ISREG (sb.st_mode) + && !S_TYPEISSHM (&sb) && !S_TYPEISTMO (&sb)) { error (0, 0, _("cannot get the size of %s"), quote (fname)); return false; @@ -350,7 +351,7 @@ main (int argc, char **argv) struct stat sb; if (stat (ref_file, &sb) != 0) error (EXIT_FAILURE, errno, _("cannot stat %s"), quote (ref_file)); - if (!S_ISREG (sb.st_mode) && !S_TYPEISSHM (&sb)) + if (!S_ISREG (sb.st_mode) && !S_TYPEISSHM (&sb) && !S_TYPEISTMO (&sb)) error (EXIT_FAILURE, 0, _("cannot get the size of %s"), quote (ref_file)); if (!got_size)
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.