Assuming you meant to say
cat /dev/null > file_log.txt
or
cp /dev/null file_log.txt
which has the same effect for that matter, the answer is that the process that has the file open for writing did so without O_APPEND
, or it sets the offset into the file arbitrarily, in which case a sparse file is created.
The manual page for write(2)
explains that pretty clear:
For a seekable file (i.e., one to which lseek(2) may be applied, for
example, a regular file) writing takes place at the file offset, and
the file offset is incremented by the number of bytes actually
written. If the file was open(2)ed with O_APPEND, the file offset is
first set to the end of the file before writing. The adjustment of the file offset and the write operation are performed as an atomic step.
The said offset is a property of the according file descriptor of the writing process - if another process truncates the file or writes itself to the file, this will not have any effect on the offset. (Moreover, if the same process opens the file for writing without O_APPEND
it will receive a different file descriptor for that and writing to the file through the new file descriptor will have the same effect.)
Suppose that process P opens a file for writing without appending, yielding file descriptor fd. Then the effect on the file size (as stat()
reports it) of truncating a file (e.g. by copying /dev/null
to it) will be undone as soon as P writes to fd. Specifically, on write()
to fd the system will move ("seek") to the offset associated with fd, filling the space from the current end of file (possibly to the beginning, if it was entirely truncated) up to the offset with zeros. However, if the file has grown larger in the mean time, writing to fd will overwrite the content of the file, beginning at the offset.
A sparse file is a file that contains "holes", i.e. the system "knows" that there are large regions with zeroes, which are not really written to disk. This is why du
and ls
disagree - du
looks at the actual disk usage, while ls
uses simply stat()
to extract the file size attribute.
Remedy: restart the process. If possible, rewrite the part where the file is opened to use O_APPEND
(or mode a
when using fopen()
).
cat /dev/null > file_log.txt
?ls -l file_log.txt
anddu file_log.txt
say?