cvs commit: src/sys/ufs/ufs ufs_vnops.c

Bruce Evans bde at
Thu Jun 1 15:11:24 UTC 2006

On Thu, 1 Jun 2006, Ceri Davies wrote:

> On Thu, Jun 01, 2006 at 12:05:23PM +0930, Greg 'groggy' Lehey wrote:
>> On Wednesday, 31 May 2006 at 13:15:29 +0000, Maxim Konovalov wrote:
>>> maxim       2006-05-31 13:15:29 UTC
>>>   FreeBSD src repository
>>>   Modified files:
>>>     sys/ufs/ufs          ufs_vnops.c
>>>   Log:
>>>   o According to POSIX, the result of ftruncate(2) is unspecified
>>>   for file types other than VREG, VDIR and shared memory objects.
>>>   We already handle VREG, VLNK and VDIR cases.  Silently ignore
>>>   Revision  Changes    Path
>>>   1.276     +22 -4     src/sys/ufs/ufs/ufs_vnops.c
>> Is this worth a man page update?

Only to the extent that the man page is generally broken.  It has
always tried to document the behaviour now implemented in ffs but it
omits some details and is not clear on the [EROFS] case.  The commit
makes the man page actually agree with one file system (ffs; file
systems cut and pasted from ffs, e.g., ext2fs, still panic).

> Undoubtedly.  Does the attached look like enough?  I'm not sure if we

Sorry, no.

> want to add a STANDARDS section for this when it's valid behaviour.

> Index: src/lib/libc/sys/truncate.2
> ===================================================================
> RCS file: /home/ncvs/src/lib/libc/sys/truncate.2,v
> retrieving revision 1.17
> diff -u -r1.17 truncate.2
> --- src/lib/libc/sys/truncate.2	20 Jan 2005 09:17:05 -0000	1.17
> +++ src/lib/libc/sys/truncate.2	1 Jun 2006 09:47:19 -0000
> ...
> @@ -69,6 +69,10 @@
>  the file must be open for writing.
>  .Rv -std
> +If the file to be modified is not a directory or
> +a regular file, the
> +.Fn truncate
> +call will return the value 0.
>  The
>  .Fn truncate

The man page already says this (in standard wording in ".Rv -std" and

%      Upon successful completion, the value 0 is returned; otherwise the
%      value -1 is returned and the global variable errno is set to indicate the
%      error.
%      The truncate() system call succeeds unless:
% [... various unrelated errors]
%      [EISDIR]           The named file is a directory.

This covers the behaviour for directories in more detail.

%      [EROFS]            The named file resides on a read-only file system.

I originally misinterpreted "resides" as strictly applying to the name of
a fifo (since fifo contents don't really reside anywhere) but it obviously
should only apply to the contents.  open(2) uses the same wording.

The actual behaviour was (and still is on some file systems containing code
cut and pasted from ffs, e.g., ext2fs):

- [f]truncate() of a fifo on a r/w file system (for ffs and clones) acts as
   if there were a resource fork of the file, with one half of the fork
   containing the fifo and the other half containing a irregular file, where
   an irregular file in this context is a regular file that is inaccessible
   from userland except via stat(2) and statfs(2) to see some of its side
   effects, and via unlink(2) to clean it up.  This used to be a small
   problem.  However, some versions of FreeBSD have debugging code that
   panics on attempts to truncate the irregular file.
- I thinl [f]truncate() of a fifo on a r/o file system panics unless the
   new size is 0.

% [... various unrelated errors]
%      The ftruncate() system call succeeds unless:
%      [EBADF]            The fd argument is not a valid descriptor.
%      [EINVAL]           The fd argument references a socket, not a file.
%      [EINVAL]           The fd descriptor is not open for writing.

Note that there is no !directory or r/o restrictions here.  These
restrictions are in in open(2).

There is an additional restriction here for sockets.  Either this or
the lack of such a restriction for truncate(2) must be a bug, since
sockets may be bound to file systems and whether truncation succeeds
shouldn't depend on the syscall used to do it.

% ...
%      Use of truncate() to extend a file is not portable.

This can only be a bug in programs which assume that extension using
[f]truncate() is portable, not in [f]truncate().  (File) extension is an
XSI (specification) extension in POSIX.

The main bugs here are:
- truncate.2 doesn't say that except for regular files, success consists
   of doing nothing (even when the caller asks for something to be done).
- truncate.2 doesn't say that for regular files, certain timestamps
   (mainly ctime) are set on successful completion (even when the caller
   asks for nothing to be done).  It shares this bug with most or all
   FreeBSD man pages for fs syscalls.  POSIX is much more careful about
   such details.  POSIX may be harder to read because it is more formal,
   but when detail is just absent in an informal description it is
   impossible to recover from the description.


More information about the cvs-src mailing list