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.
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
EINVAL
EFBIG
EIO
EPERM
EINTR
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
EACCES
EINVAL
EFBIG
EIO
EPERM
EINTR
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.