[patch] 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 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>

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) {
      fprintf(stderr, "mknod(%s) errno %d - %m\n", 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)
      printf("truncate(\"%s\") failed with errno %s - %m\n", 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)
      fprintf(stderr, "unlink(%s) errno %d - %m\n", nodes[n].fname, errno);
  }
}
=====================================================

Compile the program and run it as user root.

output should be:
truncate("/tmp/trunc_file") succeeded
truncate("/tmp/trunc_fifo") failed with errno EINVAL - Invalid argument
truncate("/tmp/trunc_socket") failed with errno EINVAL - Invalid argument
truncate("/tmp/trunc_char_dev") failed with errno EINVAL - Invalid argument
truncate("/tmp/trunc_blk_dev") failed with errno EINVAL - Invalid argument
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..9fc14ce5b 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