mirror of
git://git.sv.gnu.org/coreutils.git
synced 2026-04-10 06:03:31 +02:00
truncate: improve handling of non regular files
Previously we copied `dd` and suppressed error messages when truncating neither regular files or shared mem objects. This was valid for `dd`, as truncation is ancillary to copying it may also do, but for `truncate` we should display all errors. Also we used the st_size from non regular files which is undefined, so we display an error when the user tries this. * src/truncate (do_truncate): Error when referencing the size of non regular files or non shared memory objects. Display all errors returned by ftruncate(). (main): Error when referencing the size of non regular files or non shared memory objects. Don't suppress error messages for any file types that can't be opened for writing. * tests/misc/truncate-dir-fail: Check that referencing the size of a directory is not supported. * tests/misc/truncate-fifo: Ensure the test doesn't hang by using the `timeout` command. Don't test the return from running ftruncate on the fifo as it's system dependent as to whether this fails or not. NEWS: Mention the change in behavior. Reported by Jim Meyering.
This commit is contained in:
2
NEWS
2
NEWS
@@ -15,6 +15,8 @@ GNU coreutils NEWS -*- outline -*-
|
||||
sort -g now uses long doubles for greater range and precision.
|
||||
|
||||
truncate now supports setting file sizes relative to a reference file.
|
||||
Also errors are no longer suppressed for unsupported file types, and
|
||||
relative sizes are restricted to supported file types.
|
||||
|
||||
* Noteworthy changes in release 8.5 (2010-04-23) [stable]
|
||||
|
||||
|
||||
@@ -160,21 +160,21 @@ do_ftruncate (int fd, char const *fname, off_t ssize, off_t rsize,
|
||||
{
|
||||
uintmax_t const fsize = rsize < 0 ? sb.st_size : rsize;
|
||||
|
||||
if (rsize < 0 && sb.st_size < 0)
|
||||
if (rsize < 0) /* fstat used above to get size. */
|
||||
{
|
||||
/* Complain only for a regular file, a directory,
|
||||
or a shared memory object, as POSIX 1003.1-2004 specifies
|
||||
ftruncate's behavior only for these file types. */
|
||||
if (S_ISREG (sb.st_mode) || S_ISDIR (sb.st_mode)
|
||||
|| S_TYPEISSHM (&sb))
|
||||
if (!S_ISREG (sb.st_mode) && !S_TYPEISSHM (&sb))
|
||||
{
|
||||
/* overflow is the only reason I can think
|
||||
this would ever go negative for the above types */
|
||||
error (0, 0, _("cannot get the size of %s"), quote (fname));
|
||||
return 1;
|
||||
}
|
||||
if (sb.st_size < 0)
|
||||
{
|
||||
/* Sanity check. Overflow is the only reason I can think
|
||||
this would ever go negative. */
|
||||
error (0, 0, _("%s has unusable, apparently negative size"),
|
||||
quote (fname));
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rel_mode == rm_min)
|
||||
@@ -215,26 +215,10 @@ do_ftruncate (int fd, char const *fname, off_t ssize, off_t rsize,
|
||||
|
||||
if (ftruncate (fd, nsize) == -1) /* note updates mtime & ctime */
|
||||
{
|
||||
/* Complain only when ftruncate fails on a regular file, a
|
||||
directory, or a shared memory object, as POSIX 1003.1-2004
|
||||
specifies ftruncate's behavior only for these file types.
|
||||
For example, do not complain when Linux kernel 2.4 ftruncate
|
||||
fails on /dev/fd0. */
|
||||
int const ftruncate_errno = errno;
|
||||
if (fstat (fd, &sb) != 0)
|
||||
{
|
||||
error (0, errno, _("cannot fstat %s"), quote (fname));
|
||||
return 1;
|
||||
}
|
||||
else if (S_ISREG (sb.st_mode) || S_ISDIR (sb.st_mode)
|
||||
|| S_TYPEISSHM (&sb))
|
||||
{
|
||||
error (0, ftruncate_errno,
|
||||
_("truncating %s at %" PRIdMAX " bytes"), quote (fname),
|
||||
(intmax_t) nsize);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
error (0, errno,
|
||||
_("failed to truncate %s at %" PRIdMAX " bytes"), quote (fname),
|
||||
(intmax_t) nsize);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -362,9 +346,13 @@ main (int argc, char **argv)
|
||||
|
||||
if (ref_file)
|
||||
{
|
||||
/* FIXME: Maybe support getting size of block devices. */
|
||||
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))
|
||||
error (EXIT_FAILURE, 0, _("cannot get the size of %s"),
|
||||
quote (ref_file));
|
||||
if (!got_size)
|
||||
size = sb.st_size;
|
||||
else
|
||||
@@ -384,18 +372,7 @@ main (int argc, char **argv)
|
||||
`truncate -s0 .` should gen EISDIR error */
|
||||
if (!(no_create && errno == ENOENT))
|
||||
{
|
||||
int const open_errno = errno;
|
||||
struct stat sb;
|
||||
if (stat (fname, &sb) == 0)
|
||||
{
|
||||
/* Complain only for a regular file, a directory,
|
||||
or a shared memory object, as POSIX 1003.1-2004 specifies
|
||||
ftruncate's behavior only for these file types. */
|
||||
if (!S_ISREG (sb.st_mode) && !S_ISDIR (sb.st_mode)
|
||||
&& !S_TYPEISSHM (&sb))
|
||||
continue;
|
||||
}
|
||||
error (0, open_errno, _("cannot open %s for writing"),
|
||||
error (0, errno, _("cannot open %s for writing"),
|
||||
quote (fname));
|
||||
errors++;
|
||||
}
|
||||
|
||||
@@ -26,4 +26,7 @@ fi
|
||||
# truncate on dir not allowed
|
||||
truncate -s+0 . && fail=1
|
||||
|
||||
# getting the size of a dir is not allowed
|
||||
truncate -r. file && fail=1
|
||||
|
||||
Exit $fail
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/bin/sh
|
||||
# Make sure truncate works on fifos without hanging or errors
|
||||
# Make sure truncate works on fifos without hanging
|
||||
|
||||
# Copyright (C) 2008-2010 Free Software Foundation, Inc.
|
||||
|
||||
@@ -23,9 +23,9 @@ fi
|
||||
|
||||
. $srcdir/test-lib.sh
|
||||
|
||||
mkfifo_or_skip_ "fifo"
|
||||
mkfifo_or_skip_ fifo
|
||||
|
||||
|
||||
truncate -s0 "fifo" || fail=1
|
||||
timeout 10 truncate -s0 fifo
|
||||
test "$?" = 124 && fail=1
|
||||
|
||||
Exit $fail
|
||||
|
||||
Reference in New Issue
Block a user