What happens when I truncate a file that is in use?
Note although the system call is called truncate, it actually is better interpreted as saying "Make my file report this many bytes in size". As per the system call manpage:
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.
If the file previously was larger than this size, the extra data is lost. If the file previously was shorter, it is extended, and the extended part reads as null bytes ('\0').
So, one can truncate a file and have it be larger, rather than smaller.
So my questions is, if my process has an opened file in pos 1000 and i did truncate -s0 filename, if the truncate works, what happening in the next process write?
- You have truncated. The file size at this stage is 0 bytes. The offset is 1000.
- The write at position 1001 occurs.
- The file size is 1002 bytes. Bytes 0-1000 contain '\0' (null). Bytes 1001+ contain data written.
When you write to a file from a position larger than the file itself, the data between the end of the file and the new write becomes null bytes and the file data between those two points is referred as being sparse.
Indeed, you can do the following and produce the same affect.
import os, sys
f = open('data.txt','w')
f.seek(1048576)
f.write('a')
f.flush()
f.close()
You also mentioned that opening in append mode avoids this behaviour. This is true because you are instructing the kernel in that case to "write to the actual end of the file every time". If you truncate then the end of the file does change. In append you cannot reposition your file pointer.
Here is a sample program which demonstrates what happens to the file, the offsets and the data in a file that has been truncated.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <err.h>
#define FPATH "/tmp/data.txt"
#define FSIZE 65536
int main() {
int a,b;
char buf[FSIZE];
char byte;
struct stat st;
memset(buf, 'A', FSIZE);
a = open(FPATH, O_WRONLY|O_CREAT);
b = open(FPATH, O_RDONLY);
if (a < 0 || b < 0)
errx(EXIT_FAILURE, "Could not open file");
printf("Writing %d * 'A' into file\n", FSIZE);
/* Write some bytes */
if(write(a, buf, FSIZE) != FSIZE)
errx(EXIT_FAILURE, "Couldn't write complete size out");
/* Seek to a new position in the file */
lseek(b, FSIZE/2, SEEK_SET);
printf("Current position of handle 'a': %d\n", lseek(a, 0, SEEK_CUR));
printf("Current position of handle 'b': %d\n", lseek(b, 0, SEEK_CUR));
stat(FPATH, &st);
printf("Reported size on filesystem of %s: %d\n", FPATH, st.st_size);
/* OK -- now, read the byte at the position */
if (read(b, &byte, 1) < 0)
err(EXIT_FAILURE, "Could not read file");
printf("Character at current position of handle 'b': '%c'\n", byte);
/* Truncate the file in the 'a' handle */
printf("Performing truncate...\n");
if (ftruncate(a, 0) < 0)
err(EXIT_FAILURE, "Cannot truncate file");
printf("Current position of handle 'a': %d\n", lseek(a, 0, SEEK_CUR));
printf("Current position of handle 'b': %d\n", lseek(b, 0, SEEK_CUR));
stat(FPATH, &st);
printf("Reported size on filesystem of %s: %d\n", FPATH, st.st_size);
printf("Writing one byte via handle 'a'\n");
if (write(a, buf, 1) < 0)
err(EXIT_FAILURE, "Cannot perform second write");
printf("Current position of handle 'a': %d\n", lseek(a, 0, SEEK_CUR));
printf("Current position of handle 'b': %d\n", lseek(b, 0, SEEK_CUR));
stat(FPATH, &st);
printf("Reported size on filesystem of %s: %d\n", FPATH, st.st_size);
if (read(b, &byte, 1) < 0)
err(EXIT_FAILURE, "Could not read file");
printf("Character at current position of handle 'b': '%c'\n", byte);
close(a);
close(b);
exit(0);
}
This results in the following output;
Writing 65536 * 'A' into file
Current position of handle 'a': 65536
Current position of handle 'b': 32768
Reported size on filesystem of /tmp/data.txt: 65536
Character at current position of handle 'b': 'A'
Performing truncate...
Current position of handle 'a': 65536
Current position of handle 'b': 32769
Reported size on filesystem of /tmp/data.txt: 0
Writing one byte via handle 'a'
Current position of handle 'a': 65537
Current position of handle 'b': 32769
Reported size on filesystem of /tmp/data.txt: 65537
Character at current position of handle 'b': ''