Linux – Can POSIX/Linux unlink file entries entirely?

Can POSIX/Linux unlink file entries entirely?… here is a solution to the problem.

Can POSIX/Linux unlink file entries entirely?

POSIX is known for allowing processes to rename and unlink file entries regardless of the impact on others who use them, while Windows throws an error by default if you even try to touch inside the timestamp of a directory that opened a file handle somewhere.

Windows doesn’t need to be so conservative, however. If you open all file handles with FILE_FLAG_BACKUP_SEMANTICS and FILE_SHARE_DELETE, and take care to rename the file to a random name before marking it for deletion, you will get POSIX semantics, including no restrictions on file paths where the operation contains open file handles.

One very neat thing Windows can do is to perform renaming and deleting and hard links using only the open file descriptor, so you can delete a file without worrying about whether another process has renamed it or any directory in its previous path. This tool lets you perform completely uncontested file deletion – once you have the correct file open file handle, you can no longer care about what other processes do to the file system, at least for deletion (which is the most important because it implicitly involves destroying data).

Does this raise the POSIX question? On POSIX, unlink() takes a path, and between retrieving the current path to the file descriptor using /proc/self/fd/x or F_GETPATH and calling unlink(), someone may have changed that path, thus potentially causing the wrong file to be unlinked and data to be lost.

A fairly safe solution is:

  1. Use /proc/self/fd/x or F_GETPATH to get one of the current paths to open the file descriptor.
  2. Open its containing directory.
  3. Execute statat() on the directory containing the leaf name of the open file descriptor to check that the device ID and inode match.
  4. If they match, unlinkat() is executed to remove the leaf name.

This is safe from the parent directory upwards, although the hard link you remove may not be expected. However, if a third-party process in the include directory renames your file to a different name and another file to your leaf name, it is not race safe between checking inode equivalence and calling unlinkat(). Wrong files may be deleted here, and data may be lost.

So I’m asking the question: does POSIX or any particular POSIX implementation (e.g. Linux) allow programs to completely uncompete for linked file entries? One solution could be to unlink the file entry via the open file descriptor and the other to unlink the file entry via inode, but Google hasn’t found a solution for either method. Interestingly, NTFS does allow you to delete by selecting inodes or GUIDs in addition to deleting through open file handles (yes, NTFS does provide inodes, you can get them from the NT kernel), but that’s not not helping much here.

If this problem seems too esoteric, this problem affects proposed Boost.AFIO I need to determine which filesystem contention I can mitigate and which I can’t, as part of the hard behavior guarantee of its records.

EDIT: Clarifying that the open file descriptor does not have a canonical current path, and in this use case we don’t care – we just want to unlink the file.

Solution

No one answered the question, and I spent days browsing the Linux source code. I believe the answer is “at the moment you can’t unlink file competition for free”, so I https://bugzilla.kernel.org/show_bug.cgi?id=93441 opened a feature request. Let Linux extend unlinkat() with the AT_EMPTY_PATH Linux extension flag. If they accept the idea, I will mark this answer as the correct answer.

Related Problems and Solutions