Suppose I have some non-directory (file, named pipe/socket, whatever) at the pathname
/tmp/foo and some other non-directory at the pathname
/tmp/bar. Then two (or more) processes start executing concurrently:
Process one does:
unlink('/tmp/foo') /* or rename('/tmp/foo', '/tmp/removed') */ unlink('/tmp/bar') /* or rename('/tmp/bar', '/tmp/removed') */
Process two (and so on) does:
As I understand it, there is no way process two could possibly succeed (either the
link(2) is attempted while
/tmp/foo is still present, in which case
/tmp/bar is also present so it must fail with
/tmp/foo is gone so is must fail with
But this intuition relies on the assumption that the
rename(2) system calls are inherently sequential in their unlinking effects, so I am looking for verification of my understanding: Is there any *nix-like system out there whose kernel allows the two
rename(2) calls to succeed, but simultaneously causes
link(2) to succeed as well (whether due to re-order the unlinking of
/tmp/bar and not abstracting/hiding that from the process calling
link(2), or through through some other quirky race condition/bug)?
I have read the manpages for
link(2) for Linux and a few BSDs, and the POSIX specification for these functions. But I don't think they actually contain anything reassuring on this matter, upon careful consideration. At least with
rename(2), we're promised that the destination is atomically replaced if it's already present (bugs in the OS itself aside), but nothing else.
I have seen claims that multiple simultaneous executions of
rename(foo, qux) will atomically and portably have all but one rename fail with
ENOENT - so that's promising! I am just uncertain if that can be extended to having a
link(foo, bar) fail with
ENOENT under the same circumstances as well.
I realize that this is one of those "can't prove a negative" situations - we can at best only note that there is no evidence that a *nix-like system which will allow process two's
link(2) to succeed exists.
So what I'm looking for is answers covering as many *nix-like systems as possible (at least Linux, OS X, and the various BSDs, but ideally also the proprietary still-in-some-use systems like Solaris 10) - from people who have sufficient familiarity with these systems and this narrow set of problems (atomic/well-ordered file system operations) that they're confident (as much as one realistically can be) that they'd know of issues like the aforementioned Mac OS X
rename(2)-not-actually-atomic bug if they existed on the platforms they're familiar with. That would give me enough confidence that this works the way I think it does in a portable-enough manner to rely on.
This isn't an "X/Y problem" question - there's no underlying problem that can be answered by referring me to the various locking/IPC mechanisms or something else that works around the uncertainty about how these particular system calls interact: I specifically want to know if one can rely on the above system calls portably interacting as expected across *nix-like systems in practical use today.