10

Is there a way to open() a file and cause it to shrink? One can, of course, open them in append-mode or seek to the end and write to cause them to grow. However, as far as I know, there is no method to shrink a file via typical unix-style system call interfaces.

The only way to do so, as far as I know, is by faking it by creating a new shorter file and rename() it in place of the older one.

I just wanted confirmation, because I saw an answer that implied that it was possible to make file editors that worked directly on a file instead of going through the process of making a new one and renaming it in place.

I've always thought that the file api in libc and unix-style system call interfaces did not allow for the shrinking of files to ease implementation of filesystems and maybe avoid usage patterns that might contribute to fragmentation.

3
  • 2
    Just opening a file with fopen in mode "w" (or "w+") will truncate it to zero length automatically. Or do you mean shrinking to a non-zero size, to preserve some of the old contents?
    – Wyzard
    Commented Jan 23, 2019 at 7:43
  • 4
    Just FYI, open() and openat() already have a flag for truncating, O_TRUNC so technically it does cause the file to shrink - that is, shrink completely - without changing inode. Most famous example of that is command > file.txt, where file will be truncated if it exists. If you run strace on bash -c 'true > /dev/null' you'll see openat(AT_FDCWD, "/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) in the output. Of course for variable size of truncation you need truncate() syscall. Let me know if you want this as an actual answer instead of the comment. Commented Jan 23, 2019 at 8:19
  • @SergiyKolodyazhnyy I was thinking of shrinking to an arbitrary size. I've upvoted David Foerster's answer because it answers a subset of the question, but I'm not accepting it in light of icarus's. I would have taken it as a yes-and-no type answer, whereas icarus's answer already showed that the real answer is a "yes".
    – JoL
    Commented Jan 23, 2019 at 16:18

2 Answers 2

22

man -s 2 ftruncate says

DESCRIPTION
   The  truncate()  and  ftruncate()  functions cause the regular file
   named by path or referenced by fd to be truncated to a size of precisely
   length bytes.

...

CONFORMING TO
   POSIX.1-2001, POSIX.1-2008, 4.4BSD, SVr4 (these calls first appeared in 4.2BSD).

it goes on to say that if you use ftruncate you must have opened the file for writing, and if you use truncate the file must be writable.

2
  • Appending to a file causes the OS to first truncate it to accommodate for the new file size, and then write it. So truncate is the system call you're looking for. Commented Jan 23, 2019 at 12:42
  • 1
    On Linux, see also fallocate(FALLOC_FL_COLLAPSE_RANGE) Commented Jan 23, 2019 at 17:40
2

The open(2) system call accepts the O_TRUNC flag that can reduce file size:

O_TRUNC – If the file exists and is a regular file, and the file is successfully opened O_RDWR or O_WRONLY, its length shall be truncated to 0, and the mode and owner shall be unchanged. It shall have no effect on FIFO special files or terminal device files. Its effect on other file types is implementation-defined. The result of using O_TRUNC without either O_RDWR or O_WRONLY is undefined.

It is frequently used when the program aims to overwrite the content of a file entirely. An example is your shell’s file redirection operator as in command > file.

0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .