Unlinking an open file (source code)

= Unlinking an open file

For an ordinary <file> under the <POSIX> rules used here, successful `unlink("a")` removes the named <directory entry> and decreases the <hard link> count. An existing <open file description> still refers to the same <file>; removing a name does not detach an already open <file descriptor>. When the final <hard link> disappears, the contents remain available through open references until those references close. This distinction is between the lifetime of a name and the lifetime of the underlying <file>. https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html[The Open Group, POSIX.1-2017, unlink: removal of names and deferred removal of open-file contents]{ref}

Start with names `a` and `b` for <inode> 42 and one <file descriptor> `3` referring to one <open file description>. Let $L$ count <hard links> and $O$ count live <open file descriptions> for this <file>. Assume successful operations, no additional references, and no <memory-mapped file>. The stages are
$$
(L,O):\quad (2,1)\xrightarrow{\mathrm{unlink}(a)}(1,1)\xrightarrow{\mathrm{unlink}(b)}(0,1)\xrightarrow{\mathrm{close}(3)}(0,0).
$$
After the first removal, `b` still works. After the second, neither name works, but a read through the existing <file descriptor> can still obtain all six <bytes> if its <open file description>'s current position is at the beginning. The final close releases the last open reference, allowing the <inode> and its <file data blocks> to be reclaimed. Freed storage is reusable; this does not promise that old <bytes> are securely erased. https://pubs.opengroup.org/onlinepubs/009604499/functions/close.html[The Open Group, POSIX, close: releasing descriptors, open file descriptions and unlinked-file storage]{ref}

\Image[/unlink-open-file-lifetime.png]
{title=<Hard link> and open-reference counts distinguish removal of names from reclamation of a <file>}

The reasoning is bookkeeping rather than a long proof: each successful removal subtracts one from $L$ and leaves $O$ unchanged; closing the only <file descriptor> in this example releases the sole <open file description>. Storage is reclaimable only at the last stage. $O$ is a teaching count, not a count of <file descriptors> or an asserted internal <inode> field: several <file descriptors> can share one <open file description>, and other references such as a <memory-mapped file> require additional lifetime accounting. The diagrams are abstract models, not operations on actual user <files>.