== A brief history of fiddling with Unix directories In the beginning (say V7 Unix), Unix directories were [[remarkably non-special DirectoryLinkCounts]]. They were basically files that the kernel knew a bit about. In particular, there was no _mkdir(2)_ system call and the _._ and _.._ entries in each directory were real directory entries (and real hardlinks), created by hand by [[the _mkdir_ program http://minnie.tuhs.org/cgi-bin/utree.pl?file=V7/usr/src/cmd/mkdir.c]]. Similarly there was no _rmdir()_ system call and [[_rmdir_ http://minnie.tuhs.org/cgi-bin/utree.pl?file=V7/usr/src/cmd/rmdir.c]] directly called _unlink()_ on _dir/.._, _dir/._, and _dir_ itself. To avoid the possibility of users accidentally damaging the directory tree in various ways, calling _link(2)_ and _unlink(2)_ on directories was restricted to the superuser. (In part to save the superuser from themselves, commands like _ln_ and _rm_ then generally refused to operate on directories at all, explicitly checking for 'is this a directory' and erroring out if it was. V7 _rm_ would remove directories with '_rm -r_', but it deferred to _rmdir_ to do the actual work. Only [[V7 _mv_ http://minnie.tuhs.org/cgi-bin/utree.pl?file=V7/usr/src/cmd/mv.c]] has special handling for directories; it knew how to actually rename them by manipulating hardlinks to them, although this only worked when _mv_ was run by the superuser.) It took until 4.1 BSD or so for the kernel to take over the work of creating and deleting directories, with real _mkdir()_ and _rmdir()_ system calls. The kernel also picked up a _rename()_ system call at the same time, instead of requiring _mv_ to do the work with _link(2)_ and _unlink(2)_ calls; this _rename()_ also worked on directories. This was the point, not coincidentally, where [[BSD directories themselves became more complicated ReaddirHistory]]. Interestingly, even in 4.2 BSD _link(2)_ and _unlink(2)_ would work on directories if you were root and _mknod(2)_ could still be used to create them (again, if you were root), although I suspect no user level programs made use of this (and certainly _rm_ still rejected directories as before). (As a surprising bit of trivia, it appears that [[the 4.2 BSD _ln_ http://minnie.tuhs.org/cgi-bin/utree.pl?file=4.2BSD/usr/src/bin/ln.c]] lacked a specific 'is the source a directory' guard and so a superuser probably could accidentally use it to make extra hardlinks to a directory, thereby doing bad things to directory tree integrity.) To my further surprise, raw _link(2)_ and _unlink(2)_ continued to work on directories as late as 4.4 BSD; it was left for other Unixes to reject this outright. Since the early Linux kernel source is relatively simple to read, I can say that Linux did from very early on. Other Unixes, I have no idea about. (I assume but don't know for sure that modern *BSD derived Unixes do reject this at the kernel level.) (I've written other entries on aspects of Unix directories and their history: [[1 ReaddirHistory]], [[2 UnixLinearDirectories]], [[3 DirectoryLinkCounts]], [[4 ReaddirOrder]].) PS: Yes, this does mean that V7 _mkdir_ and _rmdir_ were setuid root, as far as I know. They did do their own permission checking in a perfectly V7-appropriate way, but in general, well, you really don't want to think too hard about V7, directory creation and deletion, and concurrency races. In general and despite what I say about it sometimes, V7 made decisions that were appropriate for its time and its job of being a minimal system on a relatively small machine that was being operated in what was ultimately a friendly environment. Delegating proper maintenance of a core filesystem property like directory tree integrity to user code may sound very wrong to us now but I'm sure it made sense at the time (and it did things like reduce the kernel size a bit).