Directory – What Happens When the Current Directory is Deleted

deleted-filesdirectorylspwd

In the first terminal A, I create a directory, enter the directory, and create a file:

$ mkdir test
$ cd test
$ touch file1.txt
$ ls
file1.txt

Then in another terminal B, I delete the directory:

$ rm -r test
$ mkdir test
$ cd test
$ touch file2.txt

And back again the terminal A (not doing any cd), I try to list the files:

$ ls

ls doesn't see anything and it doesn't complain either.

What happens in the background? How comes that ls doesn't see the problem? And is there a standard, portable, and/or recommended way to find out that something is not right in the terminal A?

pwd just prints the seemingly correct directory name. touch file3.txt says no such file or directory which is not helpful. Only bash -c "pwd" gives a two long error lines which somehow give away that something is wrong but are not really descriptive and I'm not sure how portable that is between different systems (I'm on Ubuntu 16.04). cd .. && cd test fixes the problem, but does not really explain what happened.

Best Answer

How comes that ls doesn't see the problem?

There is no "problem" in the first place.

something is not right in the terminal A

There is nothing not right. There are defined semantics for processes having unlinked directories open just as there are defined semantics for processes having unlinked files open. Both are normal things.

There are defined semantics for unlinking a directory entry that referenced something (whilst having that something open somewhere) and then creating a directory entry by the original name linking to something else: You now have two of those somethings, and referencing the open description for the first does not access the second, or vice versa. This is as true of directories as it is of files.

A process can have an open file description for a directory by dint of:

  • it being the process's working directory;
  • it being the process's root directory;
  • it being open by the process having called the opendir() library function; or
  • it being open by the process having called the open() library function.

rmdir() is allowed to fail to remove links to a still-open directory (which was the behaviour of some old Unices and is the behaviour of some non-Unix-non-Linux POSIX-conformant systems), and is required to fail if the still-open directory is unlinked via a name that ends in a pathname component .; but if it succeeds and removes the final link to the directory the defined semantics are that a still-open but unlinked directory:

  • has no directory entries at all;
  • cannot have any directory entries created thereafter, even if the attempting process has write access or privileged access.

Your operating system is one of the ones that does not return EBUSY from rmdir() in these circumstances, and your shell in the first terminal session has an unlinked but still open directory as its current directory. Everything that you saw was the defined behaviour in that circumstance. ls, for example, showed the empty still open first directory, of the two directories that you had at that point.

Even the output of pwd was. When run as a built-in command in that shell it was that shell internally keeping track of the name of the current directory in a shell/environment variable. When run as a built-in command in another shell, it was the other shell failing to match the device and i-node number of its working directory to the second directory now named by the contents of the PWD environment variable that it inherited, thus deciding not to trust the contents of PWD, and then failing in the getcwd() library function because the working directory does not have any names any longer, it having been unlinked.

Further reading

Related Question