bug-coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

fyi: new program: truncate


From: Jim Meyering
Subject: fyi: new program: truncate
Date: Fri, 06 Jun 2008 15:52:23 +0200

I've just pushed the following change by Pádraig Brady.
That brings the total to 102 programs.

>From 75e0047c4b916393b6be3cb985c4c4d4a2d1a836 Mon Sep 17 00:00:00 2001
From: =?utf-8?q?P=C3=A1draig=20Brady?= <address@hidden>
Date: Fri, 28 Mar 2008 22:55:31 +0000
Subject: [PATCH] Add new program: truncate

* AUTHORS: Register as the author
* NEWS: Mention this change
* README: Add truncate command to list
* src/truncate.c: New command
* src/Makefile.am: Add truncate command to list to build
* src/.gitignore: Add truncate binary to list to ignore
* doc/coreutils.texi (truncate invocation): Add truncate info
* man/Makefile.am: Add truncate man page to list to build
* man/truncate.x: Add truncate man page template
* po/POTFILES.in: Add truncate to list to translate
* tests/Makefile.am: Add truncate tests
* tests/misc/help-version: Add support for new truncate command
* tests/misc/truncate-dangling-symlink: check dangling link ok
* tests/misc/truncate-dir-fail: ensure dirs fail
* tests/misc/truncate-fail-diag: validate messages for missing paths
* tests/misc/truncate-fifo: ensure fifos ignored
* tests/misc/truncate-no-create-missing: ensure -c option honoured
* tests/misc/truncate-overflow: check signed integer overflows
* tests/misc/truncate-owned-by-other: root permissions check
* tests/misc/truncate-parameters: check invalid parameter combinations
* tests/misc/truncate-relative: check invalid relative sizes
---
 AUTHORS                               |    1 +
 NEWS                                  |    1 +
 README                                |    3 +-
 doc/coreutils.texi                    |   80 +++++++-
 man/Makefile.am                       |    1 +
 man/truncate.x                        |    6 +
 po/POTFILES.in                        |    1 +
 src/.gitignore                        |    1 +
 src/Makefile.am                       |    2 +-
 src/truncate.c                        |  405 +++++++++++++++++++++++++++++++++
 tests/Makefile.am                     |    9 +
 tests/misc/help-version               |    1 +
 tests/misc/truncate-dangling-symlink  |   33 +++
 tests/misc/truncate-dir-fail          |   14 ++
 tests/misc/truncate-fail-diag         |   50 ++++
 tests/misc/truncate-fifo              |   32 +++
 tests/misc/truncate-no-create-missing |   31 +++
 tests/misc/truncate-overflow          |   55 +++++
 tests/misc/truncate-owned-by-other    |   40 ++++
 tests/misc/truncate-parameters        |   43 ++++
 tests/misc/truncate-relative          |   40 ++++
 21 files changed, 846 insertions(+), 3 deletions(-)
 create mode 100644 man/truncate.x
 create mode 100644 src/truncate.c
 create mode 100755 tests/misc/truncate-dangling-symlink
 create mode 100755 tests/misc/truncate-dir-fail
 create mode 100755 tests/misc/truncate-fail-diag
 create mode 100755 tests/misc/truncate-fifo
 create mode 100755 tests/misc/truncate-no-create-missing
 create mode 100755 tests/misc/truncate-overflow
 create mode 100755 tests/misc/truncate-owned-by-other
 create mode 100755 tests/misc/truncate-parameters
 create mode 100755 tests/misc/truncate-relative

diff --git a/AUTHORS b/AUTHORS
index 36d0bd7..404cf70 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -88,6 +88,7 @@ timeout: Pádraig Brady
 touch: Paul Rubin, Arnold Robbins, Jim Kingdon, David MacKenzie, Randy Smith
 tr: Jim Meyering
 true: Jim Meyering
+truncate: Pádraig Brady
 tsort: Mark Kettenis
 tty: David MacKenzie
 uname: David MacKenzie
diff --git a/NEWS b/NEWS
index 5d0b77e..645fcbe 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,7 @@ GNU coreutils NEWS                                    -*- 
outline -*-
 ** New programs

   timeout: Run a command with bounded time.
+  truncate: Set the size of a file to a specified size.

 ** New features

diff --git a/README b/README
index d1a2cec..157432e 100644
--- a/README
+++ b/README
@@ -14,7 +14,8 @@ The programs that can be built with this package are:
   od paste pathchk pinky pr printenv printf ptx pwd readlink rm rmdir
   runcon seq sha1sum sha224sum sha256sum sha384sum sha512sum shred shuf
   sleep sort split stat stty su sum sync tac tail tee test timeout touch tr
-  true tsort tty uname unexpand uniq unlink uptime users vdir wc who whoami yes
+  true truncate tsort tty uname unexpand uniq unlink uptime users vdir wc who
+  whoami yes

 See the file NEWS for a list of major changes in the current release.

diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 8103ec2..fa7959d 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -117,6 +117,7 @@
 * touch: (coreutils)touch invocation.           Change file timestamps.
 * tr: (coreutils)tr invocation.                 Translate characters.
 * true: (coreutils)true invocation.             Do nothing, successfully.
+* truncate: (coreutils)truncate invocation.     Shrink/extend size of a file.
 * tsort: (coreutils)tsort invocation.           Topological sort.
 * tty: (coreutils)tty invocation.               Print terminal name.
 * uname: (coreutils)uname invocation.           Print system information.
@@ -185,7 +186,7 @@ Free Documentation License''.
 * Basic operations::                   cp dd install mv rm shred
 * Special file types::                 ln mkdir rmdir mkfifo mknod
 * Changing file attributes::           chgrp chmod chown touch
-* Disk usage::                         df du stat sync
+* Disk usage::                         df du stat sync truncate
 * Printing text::                      echo printf yes
 * Conditions::                         false true test expr
 * Redirection::                        tee
@@ -334,6 +335,7 @@ Disk usage
 * du invocation::               Estimate file space usage
 * stat invocation::             Report file or file system status
 * sync invocation::             Synchronize data on disk with memory
+* truncate invocation::         Shrink or extend the size of a file

 Printing text

@@ -9571,6 +9573,7 @@ file status information, and write buffers to disk.
 * du invocation::               Estimate file space usage.
 * stat invocation::             Report file or file system status.
 * sync invocation::             Synchronize memory and disk.
+* truncate invocation::         Shrink or extend the size of a file.
 @end menu


@@ -10214,6 +10217,81 @@ Any arguments are ignored, except for a lone 
@option{--help} or
 @exitstatus


address@hidden truncate invocation
address@hidden @command{truncate}: Shrink or extend the size of a file
+
address@hidden truncate
address@hidden truncating, file sizes
+
address@hidden shrinks or extends the size of each @var{file} to the
+specified size. Synopsis:
+
address@hidden
+truncate @address@hidden @address@hidden
address@hidden example
+
address@hidden files, creating
+Any @var{file} that does not exist is created.
+
address@hidden sparse files, creating
address@hidden holes, creating files with
+If a @var{file} is larger than the specified size, the extra data is lost.
+If a @var{file} is shorter, it is extended and the extended part (or hole)
+reads as zero bytes.
+
+The program accepts the following options.  Also see @ref{Common options}.
+
address@hidden @samp
+
address@hidden -c
address@hidden --no-create
address@hidden -c
address@hidden --no-create
+Do not create files that do not exist.
+
address@hidden -o
address@hidden --io-blocks
address@hidden -o
address@hidden --io-blocks
+Treat @var{size} as number of I/O blocks of the @var{FILE} rather than bytes.
+
address@hidden -r @var{rfile}
address@hidden address@hidden
address@hidden -r
address@hidden --reference
+Set the size of each @var{file} to the same size as @var{rfile}.
+
address@hidden -s @var{size}
address@hidden address@hidden
address@hidden -s
address@hidden --size
+Set the size of each @var{file} to this @var{size}.
address@hidden is a number which may be followed by one of these
+multiplicative suffixes:
address@hidden
address@hidden =>      1000 (KiloBytes)
address@hidden  =>      1024 (KibiBytes)
address@hidden => 1000*1000 (MegaBytes)
address@hidden  => 1024*1024 (MebiBytes)
address@hidden example
+and so on for @samp{G}, @samp{T}, @samp{P}, @samp{E}, @samp{Z}, and @samp{Y}.
+
address@hidden may also be prefixed by one of the following to adjust
+the size of each @var{file} based on their current size:
address@hidden
address@hidden  => extend by
address@hidden  => reduce by
address@hidden<}  => at most
address@hidden>}  => at least
address@hidden/}  => round down to multiple of
address@hidden  => round up to multiple of
address@hidden example
+
address@hidden table
+
address@hidden
+
+
 @node Printing text
 @chapter Printing text

diff --git a/man/Makefile.am b/man/Makefile.am
index 3fa2260..67ac4bd 100644
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -117,6 +117,7 @@ timeout.1:  $(common_dep)   $(srcdir)/timeout.x     
../src/timeout.c
 touch.1:       $(common_dep)   $(srcdir)/touch.x       ../src/touch.c
 tr.1:          $(common_dep)   $(srcdir)/tr.x          ../src/tr.c
 true.1:                $(common_dep)   $(srcdir)/true.x        ../src/true.c
+truncate.1:    $(common_dep)   $(srcdir)/truncate.x    ../src/truncate.c
 tsort.1:       $(common_dep)   $(srcdir)/tsort.x       ../src/tsort.c
 tty.1:         $(common_dep)   $(srcdir)/tty.x         ../src/tty.c
 uname.1:       $(common_dep)   $(srcdir)/uname.x       ../src/uname.c
diff --git a/man/truncate.x b/man/truncate.x
new file mode 100644
index 0000000..29fa155
--- /dev/null
+++ b/man/truncate.x
@@ -0,0 +1,6 @@
+[NAME]
+truncate \- shrink or extend the size of a file to the specifed size
+[DESCRIPTION]
+.\" Add any additional description here
+[SEE ALSO]
+dd(1), truncate(2), ftruncate(2)
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 2c55552..c8e97d6 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -120,6 +120,7 @@ src/timeout.c
 src/touch.c
 src/tr.c
 src/true.c
+src/truncate.c
 src/tsort.c
 src/tty.c
 src/uname.c
diff --git a/src/.gitignore b/src/.gitignore
index cee550b..ed3111f 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -91,6 +91,7 @@ timeout
 touch
 tr
 true
+truncate
 tsort
 tty
 uname
diff --git a/src/Makefile.am b/src/Makefile.am
index 97dd33b..04c4615 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -39,7 +39,7 @@ EXTRA_PROGRAMS = \
   basename date dirname echo env expr factor false \
   id kill logname pathchk printenv printf pwd \
   runcon seq sleep tee \
-  test timeout true tty whoami yes \
+  test timeout true truncate tty whoami yes \
   base64

 bin_PROGRAMS = $(OPTIONAL_BIN_PROGS)
diff --git a/src/truncate.c b/src/truncate.c
new file mode 100644
index 0000000..f353067
--- /dev/null
+++ b/src/truncate.c
@@ -0,0 +1,405 @@
+/* truncate -- truncate or extend the length of files.
+   Copyright (C) 2008 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Written by Pádraig Brady
+
+   This is backwards compatible with the FreeBSD utility, but is more
+   flexible wrt the size specifications and the use of long options,
+   to better fit the "GNU" environment.
+
+   Note if !defined(HAVE_FTRUNCATE) then the --skip-ftruncate configure flag
+   was specified or we're in a mingw environment. In these cases gnulib
+   emulation will be used and GNULIB_FTRUNCATE is defined. Note if emulation
+   can't even be provided ftruncate() will return EIO.  */
+
+#include <config.h>             /* sets _FILE_OFFSET_BITS=64 etc. */
+#include <stdio.h>
+#include <getopt.h>
+#include <sys/types.h>
+
+#include "system.h"
+#include "error.h"
+#include "posixver.h"
+#include "quote.h"
+#include "xstrtol.h"
+
+/* The official name of this program (e.g., no `g' prefix).  */
+#define PROGRAM_NAME "truncate"
+
+#define AUTHORS proper_name_utf8 ("Padraig Brady", "P\303\241draig Brady")
+
+/* (-c) If true, don't create if not already there */
+static bool no_create;
+
+/* (-o) If true, --size refers to blocks not bytes */
+static bool block_mode;
+
+/* (-r) Reference file to use size from */
+static char const *ref_file;
+
+static struct option const longopts[] = {
+  {"no-create", no_argument, NULL, 'c'},
+  {"io-blocks", no_argument, NULL, 'o'},
+  {"reference", required_argument, NULL, 'r'},
+  {"size", required_argument, NULL, 's'},
+  {GETOPT_HELP_OPTION_DECL},
+  {GETOPT_VERSION_OPTION_DECL},
+  {NULL, 0, NULL, 0}
+};
+
+typedef enum
+{ rm_abs = 0, rm_rel, rm_min, rm_max, rm_rdn, rm_rup } rel_mode_t;
+
+/* Set size to the value of STR, interpreted as a decimal integer,
+   optionally multiplied by various values.
+   Return -1 on error, 0 on success.
+
+   This supports dd BLOCK size suffixes + lowercase g,t,m for bsd compat
+   Note we don't support dd's b=512, c=1, w=2 or 21x512MiB formats.  */
+static int
+parse_len (char const *str, off_t *size)
+{
+  enum strtol_error e;
+  /* OFF_T_MAX = INTMAX_MAX */
+  e = xstrtoimax (str, NULL, 10, size, "EgGkKmMPtTYZ0");
+  errno = (e == LONGINT_OVERFLOW) ? EOVERFLOW : 0;
+  return (e == LONGINT_OK) ? 0 : -1;
+}
+
+static void
+usage (int status)
+{
+  if (status != EXIT_SUCCESS)
+    fprintf (stderr, _("Try `%s --help' for more information.\n"),
+             program_name);
+  else
+    {
+      printf (_("Usage: %s OPTION... FILE...\n"), program_name);
+      fputs (_("\
+Shrink or extend the size of each FILE to the specified size\n\
+\n\
+A FILE argument that does not exist is created.\n\
+\n\
+If a FILE is larger than the specified size, the extra data is lost.\n\
+If a FILE is shorter, it is extended and the extended part (hole)\n\
+reads as zero bytes.\n\
+\n\
+"), stdout);
+      fputs (_("\
+Mandatory arguments to long options are mandatory for short options too.\n\
+"), stdout);
+      fputs (_("\
+  -c, --no-create        do not create any files\n\
+"), stdout);
+      fputs (_("\
+  -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);
+      fputs (HELP_OPTION_DESCRIPTION, stdout);
+      fputs (VERSION_OPTION_DESCRIPTION, stdout);
+      fputs (_("\n\
+SIZE is a number which may be followed by one of the following suffixes:\n\
+KB 1000, K 1024, MB 1000*1000, M 1024*1024, and so on for G, T, P, E, Z, Y.\n\
+"), stdout);
+      fputs (_("\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_bug_reporting_address ();
+    }
+  exit (status);
+}
+
+/* return 1 on error, 0 on success */
+static int
+do_ftruncate (int fd, char const *fname, off_t ssize, rel_mode_t rel_mode)
+{
+  struct stat sb;
+  off_t nsize;
+
+  if ((block_mode || rel_mode) && fstat (fd, &sb) != 0)
+    {
+      error (0, errno, _("cannot fstat %s"), quote (fname));
+      return 1;
+    }
+  if (block_mode)
+    {
+      size_t const blksize = ST_BLKSIZE (sb);
+      if (ssize < OFF_T_MIN / blksize || ssize > OFF_T_MAX / blksize)
+        {
+          error (0, 0,
+                 _("overflow in %" PRIdMAX
+                   " * %zu byte blocks for file %s"), ssize, blksize,
+                 quote (fname));
+          return 1;
+        }
+      ssize *= blksize;
+    }
+  if (rel_mode)
+    {
+      uintmax_t const fsize = sb.st_size;
+
+      if (sb.st_size < 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))
+            {
+              /* overflow is the only reason I can think
+                 this would ever go negative for the above types */
+              error (0, 0, _("%s has unusable, apparently negative size"),
+                     quote (fname));
+              return 1;
+            }
+          return 0;
+        }
+
+      if (rel_mode == rm_min)
+        nsize = MAX (fsize, ssize);
+      else if (rel_mode == rm_max)
+        nsize = MIN (fsize, ssize);
+      else if (rel_mode == rm_rdn)
+        /* 0..ssize-1 -> 0 */
+        nsize = (fsize / ssize) * ssize;
+      else if (rel_mode == rm_rup)
+        /* 1..ssize -> ssize */
+        {
+          /* Here ssize>=1 && fsize>=0 */
+          uintmax_t const overflow = ((fsize + ssize - 1) / ssize) * ssize;
+          if (overflow > OFF_T_MAX)
+            {
+              error (0, 0, _("overflow rounding up size of file %s"),
+                     quote (fname));
+              return 1;
+            }
+          nsize = overflow;
+        }
+      else
+        {
+          if (ssize > OFF_T_MAX - (off_t)fsize)
+            {
+              error (0, 0, _("overflow extending size of file %s"),
+                     quote (fname));
+              return 1;
+            }
+          nsize = fsize + ssize;
+        }
+    }
+  else
+    nsize = ssize;
+  if (nsize < 0)
+    nsize = 0;
+
+  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 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),
+                 nsize);
+          return 1;
+        }
+      return 0;
+    }
+
+  return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+  bool got_size = false;
+  off_t size;
+  rel_mode_t rel_mode = rm_abs;
+  mode_t omode;
+  int c, errors = 0, fd = -1, oflags;
+  char const *fname;
+
+  initialize_main (&argc, &argv);
+  set_program_name (argv[0]);
+  setlocale (LC_ALL, "");
+  bindtextdomain (PACKAGE, LOCALEDIR);
+  textdomain (PACKAGE);
+
+  atexit (close_stdout);
+
+  while ((c = getopt_long (argc, argv, "cor:s:", longopts, NULL)) != -1)
+    {
+      switch (c)
+        {
+        case 'c':
+          no_create = true;
+          break;
+
+        case 'o':
+          block_mode = true;
+          break;
+
+        case 'r':
+          ref_file = optarg;
+          break;
+
+        case 's':
+          switch (*optarg)
+            {
+            case '<':
+              rel_mode = rm_max;
+              optarg++;
+              break;
+            case '>':
+              rel_mode = rm_min;
+              optarg++;
+              break;
+            case '/':
+              rel_mode = rm_rdn;
+              optarg++;
+              break;
+            case '%':
+              rel_mode = rm_rup;
+              optarg++;
+              break;
+            }
+          if (*optarg == '+' || *optarg == '-')
+            {
+              if (rel_mode)
+                {
+                  error (0, 0, _("multiple relative modifiers specified"));
+                  /* Note other combinations are flagged as invalid numbers */
+                  usage (EXIT_FAILURE);
+                }
+              rel_mode = rm_rel;
+            }
+          if (parse_len (optarg, &size) == -1)
+            error (EXIT_FAILURE, errno, _("invalid number %s"),
+                   quote (optarg));
+          /* Rounding to multiple of 0 is nonsensical */
+          if ((rel_mode == rm_rup || rel_mode == rm_rdn) && size == 0)
+            error (EXIT_FAILURE, 0, _("division by zero"));
+          got_size = true;
+          break;
+
+        case_GETOPT_HELP_CHAR;
+
+        case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
+
+        default:
+          usage (EXIT_FAILURE);
+        }
+    }
+
+  argv += optind;
+  argc -= optind;
+
+  /* must specify either size or reference file */
+  if ((ref_file && got_size) || (!ref_file && !got_size))
+    {
+      error (0, 0, _("You must specify one of %s or %s"),
+             quote_n (0, "--size"), quote_n (1, "--reference"));
+      usage (EXIT_FAILURE);
+    }
+  /* block_mode without size is not valid */
+  if (block_mode && !got_size)
+    {
+      error (0, 0, _("%s was specified but %s was not"),
+             quote_n (0, "--io-blocks"), quote_n (1, "--size"));
+      usage (EXIT_FAILURE);
+    }
+  /* must specify at least 1 file */
+  if (argc < 1)
+    {
+      error (0, 0, _("missing file operand"));
+      usage (EXIT_FAILURE);
+    }
+
+  if (ref_file)
+    {
+      struct stat sb;
+      if (stat (ref_file, &sb) != 0)
+        error (EXIT_FAILURE, errno, _("cannot stat %s"), quote (ref_file));
+      size = sb.st_size;
+    }
+
+  oflags = O_WRONLY | (no_create ? 0 : O_CREAT) | O_NONBLOCK;
+  omode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+
+  while ((fname = *argv++) != NULL)
+    {
+      if ((fd = open (fname, oflags, omode)) == -1)
+        {
+          /* `truncate -s0 -c no-such-file`  shouldn't gen error
+             `truncate -s0 no-such-dir/file` should gen ENOENT error
+             `truncate -s0 no-such-dir/` should gen EISDIR error
+             `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"),
+                     quote (fname));
+              errors++;
+            }
+          continue;
+        }
+
+
+      if (fd != -1)
+        {
+          errors += do_ftruncate (fd, fname, size, rel_mode);
+          if (close (fd) != 0)
+            {
+              error (0, errno, _("closing %s"), quote (fname));
+              errors++;
+            }
+        }
+    }
+
+  return errors ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
+/*
+ * Local variables:
+ *  indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index e5042b9..bc17299 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -28,6 +28,7 @@ root_tests =                                  \
   ls/nameless-uid                              \
   misc/chcon                                   \
   misc/selinux                                 \
+  misc/truncate-owned-by-other                 \
   mkdir/writable-under-readonly                        \
   mv/sticky-to-xpart                           \
   rm/fail-2eperm                               \
@@ -212,6 +213,14 @@ TESTS =                                            \
   misc/timeout                                 \
   misc/timeout-parameters                      \
   misc/tr                                      \
+  misc/truncate-dangling-symlink               \
+  misc/truncate-dir-fail                       \
+  misc/truncate-fail-diag                      \
+  misc/truncate-fifo                           \
+  misc/truncate-no-create-missing              \
+  misc/truncate-overflow                       \
+  misc/truncate-parameters                     \
+  misc/truncate-relative                       \
   misc/tsort                                   \
   misc/tty-eof                                 \
   misc/unexpand                                        \
diff --git a/tests/misc/help-version b/tests/misc/help-version
index ff0133a..77d37bb 100755
--- a/tests/misc/help-version
+++ b/tests/misc/help-version
@@ -131,6 +131,7 @@ rmdir_args=$tmp_dir
 rm_args=$tmp_in
 shred_args=$tmp_in
 touch_args=$tmp_in2
+truncate_args="--reference=$tmp_in $tmp_in2"

 basename_args=$tmp_in
 dirname_args=$tmp_in
diff --git a/tests/misc/truncate-dangling-symlink 
b/tests/misc/truncate-dangling-symlink
new file mode 100755
index 0000000..e16da95
--- /dev/null
+++ b/tests/misc/truncate-dangling-symlink
@@ -0,0 +1,33 @@
+#!/bin/sh
+# Make sure truncate can create a file through a dangling symlink.
+
+# Copyright (C) 2008 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+if test "$VERBOSE" = yes; then
+  set -x
+  truncate --version
+fi
+
+. $srcdir/test-lib.sh
+
+ln -s truncate-target t-symlink
+fail=0
+
+truncate -s0 t-symlink || fail=1
+
+test -f truncate-target || fail=1
+
+(exit $fail); exit $fail
diff --git a/tests/misc/truncate-dir-fail b/tests/misc/truncate-dir-fail
new file mode 100755
index 0000000..3ae918e
--- /dev/null
+++ b/tests/misc/truncate-dir-fail
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Make sure truncate fails for a directory.
+
+if test "$VERBOSE" = yes; then
+  set -x
+  truncate --version
+fi
+
+. $srcdir/test-lib.sh
+
+# truncate on dir not allowed
+truncate -s+0 . && fail=1 || fail=0
+
+(exit $fail); exit $fail
diff --git a/tests/misc/truncate-fail-diag b/tests/misc/truncate-fail-diag
new file mode 100755
index 0000000..3289625
--- /dev/null
+++ b/tests/misc/truncate-fail-diag
@@ -0,0 +1,50 @@
+#!/bin/sh
+# make sure truncate gives reasonable diagnostics
+# Note open() checks for trailing '/' before checking for existance
+# open (".", O_CREAT & (O_WRONLY | O_RDWR), ...) -> EISDIR
+# open ("missing/", O_CREAT & (O_WRONLY | O_RDWR), ...) -> EISDIR
+# open ("missing/file", O_CREAT & (O_WRONLY | O_RDWR), ...) -> ENOENT
+
+# Copyright (C) 2008 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+if test "$VERBOSE" = yes; then
+  set -x
+  truncate --version
+fi
+
+. $srcdir/lang-default
+. $srcdir/test-lib.sh
+skip_if_root_
+
+fail=0
+
+d1=no
+
+dir=$d1/such-dir
+truncate -s0 $dir > out 2>&1 && fail=1
+cat <<EOF > exp
+truncate: cannot open \`$dir' for writing: No such file or directory
+EOF
+compare out exp || fail=1
+
+dir=$d1/
+truncate -s0 $dir > out 2>&1 && fail=1
+cat <<EOF > exp
+truncate: cannot open \`$dir' for writing: Is a directory
+EOF
+compare out exp || fail=1
+
+(exit $fail); exit $fail
diff --git a/tests/misc/truncate-fifo b/tests/misc/truncate-fifo
new file mode 100755
index 0000000..f2decc6
--- /dev/null
+++ b/tests/misc/truncate-fifo
@@ -0,0 +1,32 @@
+#!/bin/sh
+# Make sure truncate works on fifos without hanging or errors
+
+# Copyright (C) 2008 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+if test "$VERBOSE" = yes; then
+  set -x
+  truncate --version
+fi
+
+. $srcdir/test-lib.sh
+
+mkfifo_or_skip_ "fifo"
+
+fail=0
+
+truncate -s0 "fifo" || fail=1
+
+(exit $fail); exit $fail
diff --git a/tests/misc/truncate-no-create-missing 
b/tests/misc/truncate-no-create-missing
new file mode 100755
index 0000000..bbe8e85
--- /dev/null
+++ b/tests/misc/truncate-no-create-missing
@@ -0,0 +1,31 @@
+#!/bin/sh
+# Ensure that truncate -c no-such-file doesn't fail.
+
+# Copyright (C) 2008 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+if test "$VERBOSE" = yes; then
+  set -x
+  truncate --version
+fi
+
+. $srcdir/test-lib.sh
+
+fail=0
+
+# truncate -c no-such-file should not fail.
+truncate -s0 -c no-such-file || fail=1
+
+(exit $fail); exit $fail
diff --git a/tests/misc/truncate-overflow b/tests/misc/truncate-overflow
new file mode 100755
index 0000000..5dbbf38
--- /dev/null
+++ b/tests/misc/truncate-overflow
@@ -0,0 +1,55 @@
+#!/bin/sh
+# Validate truncate integer overflow
+
+# Copyright (C) 2008 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+if test "$VERBOSE" = yes; then
+  set -x
+  truncate --version
+fi
+
+. $srcdir/test-lib.sh
+
+fail=0
+
+# -= overflow
+truncate -s-1 create-zero-len-file || fail=1
+
+echo > non-empty-file
+
+truncate -s2147483648 -c no-such-file && _FILE_OFFSET_BITS=64
+
+if [ $_FILE_OFFSET_BITS -eq 64 ]; then
+    # signed overflow
+    truncate -s9223372036854775808 file && fail=1
+
+    # *= signed overflow
+    truncate --io-blocks --size="1E" file && fail=1
+
+    # += signed overflow
+    truncate -s+9223372036854775807 non-empty-file && fail=1
+else
+    # signed overflow
+    truncate -s2147483648 file && fail=1
+
+    # *= signed overflow
+    truncate --io-blocks --size="1G" file && fail=1
+
+    # += signed overflow
+    truncate -s+2147483647 non-empty-file && fail=1
+fi
+
+(exit $fail); exit $fail
diff --git a/tests/misc/truncate-owned-by-other 
b/tests/misc/truncate-owned-by-other
new file mode 100755
index 0000000..a7ad278
--- /dev/null
+++ b/tests/misc/truncate-owned-by-other
@@ -0,0 +1,40 @@
+#!/bin/sh
+# Demonstrate that "truncate -s0 writable-but-owned-by-other" works.
+
+# Copyright (C) 2008 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+if test "$VERBOSE" = yes; then
+  set -x
+  truncate --version
+fi
+
+. $srcdir/envvar-check
+. $srcdir/test-lib.sh
+require_root_
+
+group_num=$(id -g $NON_ROOT_USERNAME)
+
+# Create a file owned by root, and writable by $NON_ROOT_USERNAME.
+echo > root-owned || framework_failure
+chgrp +$group_num . root-owned || framework_failure
+chmod g+w root-owned
+
+# Ensure that the current directory is searchable by $NON_ROOT_USERNAME.
+chmod g+x .
+
+setuidgid $NON_ROOT_USERNAME env PATH="$PATH" truncate -s0 root-owned || fail=1
+
+(exit $fail); exit $fail
diff --git a/tests/misc/truncate-parameters b/tests/misc/truncate-parameters
new file mode 100755
index 0000000..e416831
--- /dev/null
+++ b/tests/misc/truncate-parameters
@@ -0,0 +1,43 @@
+#!/bin/sh
+# Validate truncate parameter combinations
+
+# Copyright (C) 2008 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+if test "$VERBOSE" = yes; then
+  set -x
+  truncate --version
+fi
+
+. $srcdir/test-lib.sh
+
+fail=0
+
+# must specify at least 1 file
+truncate --size=0 && fail=1
+
+# must specify size. don't default to 0
+truncate file && fail=1
+
+# mixture of size & reference not allowed
+truncate --size=0 --reference=file file && fail=1
+
+# blocks without size is not valid
+truncate --io-blocks --reference=file file && fail=1
+
+# must specify valid numbers
+truncate --size="invalid" file && fail=1
+
+(exit $fail); exit $fail
diff --git a/tests/misc/truncate-relative b/tests/misc/truncate-relative
new file mode 100755
index 0000000..dedb76f
--- /dev/null
+++ b/tests/misc/truncate-relative
@@ -0,0 +1,40 @@
+#!/bin/sh
+# Validate truncate relative sizes
+
+# Copyright (C) 2008 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+if test "$VERBOSE" = yes; then
+  set -x
+  truncate --version
+fi
+
+. $srcdir/test-lib.sh
+
+fail=0
+
+# mixture of relative modifiers not allowed
+truncate --size="+>0" file && fail=1
+
+# mixture of relative modifiers not allowed
+truncate --size=">+0" file && fail=1
+
+# division by zero
+truncate --size="/0" file && fail=1
+
+# division by zero
+truncate --size="%0" file && fail=1
+
+(exit $fail); exit $fail
--
1.5.6.rc1.14.gc64191




reply via email to

[Prev in Thread] Current Thread [Next in Thread]