Reputation: 438
I was going through the book The Linux Programming Interface
. On page 73 in Chapter 4,
it is written:
fd = open("w.log", O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, S_IRUSR | S_IWUSR);
I read that O_TRUC
flag is used to truncate the file length to zero that destroys any existing data in the file.
O_APPEND
flag is used to append data to the end of the file.
The kernel records a file offset
, sometimes also called the read-write offset or pointer
. This is the location in the file at which the next read()
or write()
will commence.
I am confused that if the file is truncated and the kernel does the subsequent writing at the end of the file, why is the append flag is needed to explicitly tell to append at the end of the file?
Without the append flag (if the file is truncated), the kernel writes at the end of the file for the subsequent write()
function call.
Upvotes: 0
Views: 1310
Reputation: 58578
O_APPEND
rarely makes sense with O_TRUNC
. I think no combination of the C fopen
modes will produce that combination (on POSIX systems, where this is relevant).
O_APPEND
ensures that every write is done at the end of the file, automatically, regardless of the write position. In particular, this means that if multiple processes are writing to the file, they do not stomp over each other's writes.
note that POSIX does not require the atomic behavior of
O_APPEND
. It requires that an automatic seek takes place to the (current) end of the file before the write, but it doesn't require that position to still be the end of of the file when the write occurs. Even on implementations which feature atomicO_APPEND
, it might not work for all file systems. The Linux man page onopen
cautions thatO_APPEND
doesn't work atomically on NFS.
Now, if every process uses O_TRUNC
when opening the file, it will be clobbering everything that every other process wrote. That conflicts with the idea that the processes shouldn't be clobbering each other's writes, for which O_APPEND
was specified.
O_APPEND
is not required for appending to a file by a single process which is understood to be the only writer. It is possible to just seek to the end and then start writing new data. Sometimes O_APPEND
is used in the exclusive case anyway simply because it's a programming shortcut. We don't have to bother making an extra call to position to the end of the file. Compare:
FILE *f = fopen("file.txt", "a");
// check f and start writing
versus:
FILE *f = fopen("file.txt", "r+");
// check f
fseek(f, 0, SEEK_END); // go to the end, also check this for errors
// start writing
We can think about the idea that we have a group of processes using O_APPEND
to a file, such that the first one also performs O_TRUNC
to truncate it first. But it seems awkward to program this; it's not easy for a process to tell whether it is the first one to be opening the file.
If such a situation is required on, say, boot-up, where the old file from before the boot is irrelevant for some reason, just have a boot-time action (script or whatever) remove the old file before these multiple processes are started. Each one then uses O_CREAT
to create the file if necessary (in case it is the first process) but without O_TRUNC
(in case they are not the first process), and with O_APPEND
to do the atomic (if available) appending thing.
Upvotes: 2
Reputation: 180201
O_APPEND
flag is used to append data to the end of the file.
That's true, but incomplete enough to be potentially misleading. And I suspect that you are in fact confused in that regard.
The kernel records a file offset, sometimes also called the read-write offset or pointer. This is the location in the file at which the next
read()
orwrite()
will commence.
That's also incomplete. There is a file offset associated with at least each seekable file. That is the position where the next read()
will commence. It is where the next write()
will commence if the file is not open in append mode, but in append mode every write happens at the end of the file, as if it were repositioned with lseek(fd, 0, SEEK_END)
before each one. In that case, then, the current file offset might not be the position where the next write()
will commence.
I am confused that if the file is truncated and the the kernel does the subsequent writing at the end of the file why the append flag is needed to explicitly tell to append at the end of the file ?
It is not needed to cause the first write (by any process) after truncation to occur at the end of the file because immediately after the file has been truncated there isn't any other position.
With out the append flag (if the file is truncated), the kernel writes at the end of the file for the subsequent write() function call.
It is not needed for subsequent writes either, as long as the file is not repositioned or externally modified. Otherwise, the location of the next write depends on whether the file is open in append mode or not.
In practice, it is not necessarily the case that every combination of flags is useful, but the combination of O_TRUNC
and O_APPEND
has observably different effect than does either flag without the other, and the combination is useful in certain situations.
Upvotes: 2
Reputation: 123470
The two are entirely independent. The file is simply opened with O_APPEND
because it's a log file.
The author wants concurrent messages to concatenate instead of overwrite each other (e.g. if the program forks), and if an admin or log rotation tool truncates the file then new messages should start being written at line #1 instead of at line #1000000 where the last log entry was written. This would not happen without O_APPEND.
Upvotes: 0