[patch v2] truncate.2: EINVAL is returned for non regular files except directories

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

 



truncate(2) returns EINVAL if the file argument is a socket, a FIFO or
a character or block device. The current man page indicates that
ftruncate() returns EINVAL for an fd that does not reference a regular
file, but for truncate() the only reason given for returning EINVAL is
that the length is invalid.

The following test program demonstrates the errors returned by truncate():
=====================================================
#define _GNU_SOURCE

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <string.h>
#include <err.h>

struct {
  const char *fname;
  mode_t mode;
  unsigned dev_maj;
  unsigned dev_min;
} nodes[] = {
  { "/tmp/trunc_file", S_IFREG | 0666 },
  { "/tmp/trunc_fifo", S_IFIFO | 0666 },
  { "/tmp/trunc_socket", S_IFSOCK | 0666 },
  { "/tmp/trunc_char_dev", S_IFCHR | 0666, 10, 7},  // Second Amiga mouse, /dev/amigamouse1
  { "/tmp/trunc_blk_dev", S_IFBLK | 0666, 13, 3 },  // Was XT disk /dev/xd3
  { "/tmp/trunc_dir", 0666 },
};

int main(int C, char **V)
{
  int n;
  int ret;

  for (n = 0; n < sizeof(nodes) / sizeof(nodes[0]); n++) {
    /* Create the nodes */
    if (!(nodes[n].mode & S_IFMT))
      ret = mkdir(nodes[n].fname, nodes[n].mode);
    else
      ret = mknod(nodes[n].fname, nodes[n].mode,
                  makedev(nodes[n].dev_maj, nodes[n].dev_min));

    if (ret) {
      warn("mknod(%s) errno %d", nodes[n].fname, errno);
      continue;
    }

    /* Returns EINVAL for IFSOCK, IFIFO, S_IFBLK, S_IFCHR, EISDIR for a directory */
    ret = truncate(nodes[n].fname, 0);

    if (ret)
      warn("truncate(\"%s\") failed with errno %s", nodes[n].fname,
              strerrorname_np(errno));
    else
      printf("truncate(\"%s\") succeeded\n", nodes[n].fname);

    /* Remove the nodes */
    if (!(nodes[n].mode & S_IFMT))
      ret = rmdir(nodes[n].fname);
    else
      ret = unlink(nodes[n].fname);
    if (ret)
      warn("unlink(%s) errno %d", nodes[n].fname, errno);
  }
}
=====================================================

Compile the program and run it as user root.

output (if program name is trunc) should be:
truncate("/tmp/trunc_file") succeeded
trunc: truncate("/tmp/trunc_fifo") failed with errno EINVAL: Invalid argument
trunc: truncate("/tmp/trunc_socket") failed with errno EINVAL: Invalid argument
trunc: truncate("/tmp/trunc_char_dev") failed with errno EINVAL: Invalid argument
trunc: truncate("/tmp/trunc_blk_dev") failed with errno EINVAL: Invalid argument
trunc: truncate("/tmp/trunc_dir") failed with errno EISDIR: Is a directory

Signed-off-by: Quentin Armitage <quentin@xxxxxxxxxxxxxxx>

diff --git a/man2/truncate.2 b/man2/truncate.2
index 703f598b3..44750b9e2 100644
--- a/man2/truncate.2
+++ b/man2/truncate.2
@@ -112,7 +112,9 @@ and
 .B EINVAL
 The argument
 .I length
-is negative or larger than the maximum file size.
+is negative or larger than the maximum file size,
+or the named file is a socket, a FIFO,
+or a block or character device.
 .TP
 .B EIO
 An I/O error occurred updating the inode.




[Index of Archives]     [Kernel Documentation]     [Netdev]     [Linux Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux