On 26/05/10 02:01, Pádraig Brady wrote: > On 25/05/10 15:32, Richard W.M. Jones wrote: >> The manpage for truncate says: >> >> Note that the -r and -s options are mutually exclusive. >> >> and indeed you cannot have both: >> >> $ truncate -r /tmp/ref -s +10M /tmp/new >> truncate: you must specify one of `--size' or `--reference' >> >> We suggest using the 'truncate' command in the 'virt-resize' >> documentation[1]. We want users to create a file which is the size of >> an existing file + some extra amount. Naturally this would be: >> >> truncate -r old-disk.img -s +1G new-disk.img >> >> but this does not work and we have to suggest that users use two >> separate 'truncate' commands[2]. > > That seems like a worthwhile change. > I.E. allow relative --size with -r. > I'll cook up a patch in the morning
Attached. >> Related to this feature request, it would be nice if you could suffix >> a size with a % sign to indicate that you want to increase a file by a >> certain percentage of the old or reference size, eg: >> >> truncate -r old-disk.img -s +10% new-disk.img >> >> truncate -r old-disk.img -s 110% new-disk.img > > I'm a little less enthusiastic about the need for that. > Given how awkward it is to achieve then I might do it > (as a separate patch). Here's how you'd might do it > handling overflow currently: > > truncate -s$(echo "$(stat --format %s file) * 1.1" | bc | cut -d. -f1) file > > I guess it would be OK to truncate the result > rather than round to nearest? With multi-precision expr now in fedora one could simplify to: truncate -s$(expr $(stat --format %s file) '*' 110 / 100) file I'm still not convinced it's worth bringing % calculations within truncate. cheers, Pádraig.
>From 63786cdaf2189d326d837a868d936e62e855abcc Mon Sep 17 00:00:00 2001 From: =?utf-8?q?P=C3=A1draig=20Brady?= <p...@draigbrady.com> Date: Wed, 26 May 2010 09:27:53 +0100 Subject: [PATCH] truncate: support sizes relative to an existing file * doc/coreutils.texi (truncate invocation): Mention that --reference bases the --size rather than just setting it. * src/truncate.c (usage): Likewise. Also remove the clause describing --size and --reference as being mutually exclusive. (do_truncate): Add an extra parameter to hold the size of a referenced file, and use it if positive. (main): Pass the size of a referenced file to do_truncate(). * tests/misc/truncate-parameters: Adjust for the new combinations. * NEWS: Mention the change Suggested by Richard W.M. Jones --- NEWS | 1 + doc/coreutils.texi | 4 ++-- src/truncate.c | 36 ++++++++++++++++++++++-------------- tests/misc/truncate-parameters | 12 +++++++++++- 4 files changed, 36 insertions(+), 17 deletions(-) diff --git a/NEWS b/NEWS index 19436fe..7a294f4 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,7 @@ 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. * Noteworthy changes in release 8.5 (2010-04-23) [stable] diff --git a/doc/coreutils.texi b/doc/coreutils.texi index 115e5fb..d1c3085 100644 --- a/doc/coreutils.texi +++ b/doc/coreutils.texi @@ -10767,13 +10767,13 @@ Treat @var{size} as number of I/O blocks of the @var{file} rather than bytes. @itemx --referen...@var{rfile} @opindex -r @opindex --reference -Set the size of each @var{file} to the same size as @var{rfile}. +Base the size of each @var{file} on the size of @var{rfile}. @item -s @var{size} @itemx --si...@var{size} @opindex -s @opindex --size -Set the size of each @var{file} to this @var{size}. +Set or adjust the size of each @var{file} according to @var{size}. @multiplierSuffixesNoBlocks{size} @var{size} may also be prefixed by one of the following to adjust diff --git a/src/truncate.c b/src/truncate.c index ece52ee..08090ab 100644 --- a/src/truncate.c +++ b/src/truncate.c @@ -115,8 +115,8 @@ Mandatory arguments to long options are mandatory for short options too.\n\ -o, --io-blocks treat SIZE as number of IO blocks instead of bytes\n\ "), stdout); fputs (_("\ - -r, --reference=FILE use this FILE's size\n\ - -s, --size=SIZE use this SIZE\n"), stdout); + -r, --reference=RFILE base size on RFILE\n\ + -s, --size=SIZE set or adjust the file size by SIZE\n"), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); emit_size_note (); @@ -124,10 +124,6 @@ Mandatory arguments to long options are mandatory for short options too.\n\ SIZE may also be prefixed by one of the following modifying characters:\n\ `+' extend by, `-' reduce by, `<' at most, `>' at least,\n\ `/' round down to multiple of, `%' round up to multiple of.\n"), stdout); - fputs (_("\ -\n\ -Note that the -r and -s options are mutually exclusive.\n\ -"), stdout); emit_ancillary_info (); } exit (status); @@ -135,12 +131,13 @@ Note that the -r and -s options are mutually exclusive.\n\ /* return 1 on error, 0 on success */ static int -do_ftruncate (int fd, char const *fname, off_t ssize, rel_mode_t rel_mode) +do_ftruncate (int fd, char const *fname, off_t ssize, off_t rsize, + rel_mode_t rel_mode) { struct stat sb; off_t nsize; - if ((block_mode || rel_mode) && fstat (fd, &sb) != 0) + if ((block_mode || (rel_mode && rsize < 0)) && fstat (fd, &sb) != 0) { error (0, errno, _("cannot fstat %s"), quote (fname)); return 1; @@ -161,9 +158,9 @@ do_ftruncate (int fd, char const *fname, off_t ssize, rel_mode_t rel_mode) } if (rel_mode) { - uintmax_t const fsize = sb.st_size; + uintmax_t const fsize = rsize < 0 ? sb.st_size : rsize; - if (sb.st_size < 0) + if (rsize < 0 && sb.st_size < 0) { /* Complain only for a regular file, a directory, or a shared memory object, as POSIX 1003.1-2004 specifies @@ -248,6 +245,7 @@ main (int argc, char **argv) { bool got_size = false; off_t size IF_LINT (= 0); + off_t rsize = -1; rel_mode_t rel_mode = rm_abs; mode_t omode; int c, errors = 0, fd = -1, oflags; @@ -335,9 +333,16 @@ main (int argc, char **argv) argc -= optind; /* must specify either size or reference file */ - if ((ref_file && got_size) || (!ref_file && !got_size)) + if (!ref_file && !got_size) + { + error (0, 0, _("you must specify either %s or %s"), + quote_n (0, "--size"), quote_n (1, "--reference")); + usage (EXIT_FAILURE); + } + /* must specify a relative size with a reference file */ + if (ref_file && got_size && !rel_mode) { - error (0, 0, _("you must specify one of %s or %s"), + error (0, 0, _("you must specify a relative %s with %s"), quote_n (0, "--size"), quote_n (1, "--reference")); usage (EXIT_FAILURE); } @@ -360,7 +365,10 @@ main (int argc, char **argv) struct stat sb; if (stat (ref_file, &sb) != 0) error (EXIT_FAILURE, errno, _("cannot stat %s"), quote (ref_file)); - size = sb.st_size; + if (!got_size) + size = sb.st_size; + else + rsize = sb.st_size; } oflags = O_WRONLY | (no_create ? 0 : O_CREAT) | O_NONBLOCK; @@ -397,7 +405,7 @@ main (int argc, char **argv) if (fd != -1) { - errors += do_ftruncate (fd, fname, size, rel_mode); + errors += do_ftruncate (fd, fname, size, rsize, rel_mode); if (close (fd) != 0) { error (0, errno, _("closing %s"), quote (fname)); diff --git a/tests/misc/truncate-parameters b/tests/misc/truncate-parameters index 6524070..c2f7019 100755 --- a/tests/misc/truncate-parameters +++ b/tests/misc/truncate-parameters @@ -30,7 +30,7 @@ truncate --size=0 && fail=1 # must specify size. don't default to 0 truncate file && fail=1 -# mixture of size & reference not allowed +# mixture of absolute size & reference not allowed truncate --size=0 --reference=file file && fail=1 # blocks without size is not valid @@ -45,4 +45,14 @@ truncate --size=" >1" file || fail=1 #file now 1 truncate --size=" +1" file || fail=1 #file now 2 test $(stat --format %s file) = 2 || fail=1 +# reference allowed with relative size +truncate --size=" +1" -r file file || fail=1 #file now 3 +test $(stat --format %s file) = 3 || fail=1 + +# reference allowed alone also +truncate -r file file || fail=1 #file still 3 +test $(stat --format %s file) = 3 || fail=1 +truncate -r file file2 || fail=1 #file2 now 3 +test $(stat --format %s file2) = 3 || fail=1 + Exit $fail -- 1.6.2.5