[net.bugs.4bsd] unlink

chris@umcp-cs.UUCP (Chris Torek) (07/25/86)

In article <2517@umcp-cs.UUCP> I wrote:
>...  it may help to think of a `bizarre bazzar'

Eep!  That should be `bizarre bazaar'.  Thanks to Jim Shankland,
rtech!jas, for spotting this.

Now, to make this message otherwise productive, I shall follow a
suggestion from Doug Hosking, convex!hosking, and explain a bit.
I have added net.unix since this has nothing to do with a 4BSD bug.

>Ai!  You do NOT want to `unlink' a directory.  Use `rmdir'!

Why not?  I will have to explain a bit about the file system
structure.  (Incidentally, the mkdir and rmdir system calls
are specific to 4.2BSD and derivatives.  Other systems must
use careful fork/exec sequences to run the mkdir and rmdir
programs.)

Every file in the Unix file system---and a directory is just a
file, albeit a rather special one---is represented by one `inode'
and one or more names (directory entries).  In a sense, the inode
*is* the file; each name is a `link' to this inode.  An ordinary
file may have anywhere from one to several thousand links (the
exact limit is system-dependent), but a directory never has any
fewer than two.  Every directory has at least two names.

Suppose you start in /usr/tmp and do a `mkdir x'.  What are the
two links to x?  They are `/usr/tmp/x' (a directory entry in
/usr/tmp) and `/usr/tmp/x/.' (a directory entry in /usr/tmp/x).
This might seem rather odd at first: how can a directory name
itself?  It is not hard: you first create `/usr/tmp/x', a completely
empty diretory, then link `/usr/tmp/x/.' to `/usr/tmp/x'.  All
`link' does is take its first name and turn it into an inode (the
file itself), then make the second name point to that inode.
You need also link `/usr/tmp' to `/usr/tmp/x/..' to make a properly
formed directory.  `mkdir' (the program and the system call)
does all this properly; and there is no other way for anyone
except the super-user to create a directory.

Here is where the trouble creeps in.  All `unlink' does is take
the name it is given, convert it to an inode, and remove the name.
If the name was the last link to that inode, the file itself is
destroyed as well; if not, it is left intact and may still be
accessed by its other name(s).  So what happens if you unlink a
directory?  Well, if it is completely empty, it goes away and
everything is fine.  However, if it still has `.' and `..' in it,
things are not so good.  The `.' link to the directory itself still
exists, so the file that is the directory is not deleted.  The
name `/usr/tmp/x' *is* deleted, and that leaves us with a pretty
problem: how can we get rid of that last `.' and `..'?

The answer is that we cannot.  That directory will stick around
forever.  Worse, it has in it another name for, or link to, /usr/tmp,
which means that that too cannot be deleted.  Of course, fsck
(which does not use the regular file system mechanisms) can clean
this up, but this does essentially require a system shutdown.
For this reason, again, only the super-user may unlink a directory.
Ordinary processes must use rmdir (the program or the system call).
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1516)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@mimsy.umd.edu