9

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.

  • 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 --Stop Harming Monica-- Jan 23 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. – Sergiy Kolodyazhnyy Jan 23 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 Jan 23 at 16:18
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.

  • 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. – mgarciaisaia Jan 23 at 12:42
  • 1
    On Linux, see also fallocate(FALLOC_FL_COLLAPSE_RANGE) – Stéphane Chazelas Jan 23 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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.