Go to the first, previous, next, last section, table of contents.


File Size

Normally file sizes are maintained automatically. A file begins with a size of @math{0} and is automatically extended when data is written past its end. It is also possible to empty a file completely in an open or fopen call.

However, sometimes it is necessary to reduce the size of a file. This can be done with the truncate and ftruncate functions. They were introduced in BSD Unix. ftruncate was later added to POSIX.1.

Some systems allow you to extend a file (creating holes) with these functions. This is useful when using memory-mapped I/O (see section Memory-mapped I/O), where files are not automatically extended. However it is not portable but must be implemented if mmap allows mapping of files (i.e., _POSIX_MAPPED_FILES is defined).

Using these functions on anything other than a regular file gives undefined results. On many systems, such a call will appear to succeed, without actually accomplishing anything.

Function: int truncate (const char *filename, off_t length)

The truncate function changes the size of filename to length. If length is shorter than the previous length, data at the end will be lost.

If length is longer, holes will be added to the end. However, some systems do not support this feature and will leave the file unchanged.

The return value is @math{0} for success, or @math{-1} for an error. In addition to the usual file name errors, the following errors may occur:

EACCES
The file is a directory or not writable.
EINVAL
length is negative.
EFBIG
The operation would extend the file beyond the limits of the operating system.
EIO
A hardware I/O error occurred.
EPERM
The file is "append-only" or "immutable".
EINTR
The operation was interrupted by a signal.

Function: int ftruncate (int fd, off_t length)

This is like truncate, but it works on a file descriptor fd.

ftruncate is especially useful in combination with mmap. Since the mapped region must have a fixed size one cannot enlarge the file by writing something beyond the last mapped page. Instead one has to enlarge the file itself and then remap the file with the new size. The example below shows how this works.

The return value is @math{0} for success, or @math{-1} for an error. The following errors may occur:

EBADF
fd does not correspond to an open file.
EACCES
fd is a directory or not open for write.
EINVAL
length is negative.
EFBIG
The operation would extend the file beyond the limits of the operating system.
EIO
A hardware I/O error occurred.
EPERM
The file is "append-only" or "immutable".
EINTR
The operation was interrupted by a signal.

As announced here is a little example how to use ftruncate in combination with mmap:

int fd;
void *start;
size_t len;

int
add (off_t at, void *block, size_t size)
{
  if (at + size > len)
    {
      /* Resize the file and remap.  */
      size_t ps = sysconf (_SC_PAGESIZE);
      size_t ns = (at + size + ps - 1) & ~(ps - 1);
      void *np;
      if (ftruncate (fd, ns) < 0)
        return -1;
      np = mmap (NULL, ns, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
      if (np == MAP_FAILED)
        return -1;
      start = np;
      len = ns;
    }
  memcpy ((char *) start + at, block, size);
  return 0;
}

The function add allows to add at arbitrary positions in the file given blocks of memory. If the current size of the file is too small it is extended. Please note the it is extended in multiples of a pagesize. This is a requirement of mmap. The program has to track the real size and once the program finished to work a final ftruncate call should set the real size of the file.


Go to the first, previous, next, last section, table of contents.