How to unlink (remove) the special hardlink "." created for a folder?
It is technically possible to delete .
, at least on EXT4 filesystems. If you create a filesystem image in test.img
, mount it and create a test
folder, then unmount it again, you can edit it using debugfs
:
debugfs -w test.img
cd test
unlink .
debugfs
doesn't complain and dutifully deletes the .
directory entry in the filesystem. The test
directory is still usable, with one surprise:
sudo mount test.img /mnt/temp
cd /mnt/temp/test
ls
shows only
..
so .
really is gone. Yet cd .
, ls .
, pwd
still behave as usual!
I'd previously done this test using rmdir .
, but that deletes the directory's inode (huge thanks to BowlOfRed for pointing this out), which leaves test
a dangling directory entry and is the real reason for the problems encountered. In this scenario, the test
folder then becomes unusable; after mounting the image, running ls
produces
ls: cannot access '/mnt/test': Structure needs cleaning
and the kernel log shows
EXT4-fs error (device loop2): ext4_lookup:1606: inode #2: comm ls: deleted inode referenced: 38913
Running e2fsck
in this situation on the image deletes the test
directory entirely (the directory inode is gone so there's nothing to restore).
All this shows that .
exists as a specific entity in the EXT4 filesystem. I got the impression from the filesystem code in the kernel that it expects .
and ..
to exist, and warns if they don't (see namei.c
), but with the unlink .
-based test I didn't see that warning. e2fsck
doesn't like the missing .
directory entry, and offers to fix it:
$ /sbin/e2fsck -f test.img
e2fsck 1.43.3 (04-Sep-2016)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Missing '.' in directory inode 30721.
Fix<y>?
This re-creates the .
directory entry.
There is no way to remove this directory entry. The .
entry means "this directory", the ..
entry means "this directory's parent directory". They're not actually hard links, that's just how the directory structure gets created / represented.
As described in Lion's Notes on the Unix 6 Source Code early Unix had a disk file where both files and directories were represented on the disk by inode structures. There was a special bit that indicated that the file contents were a directory. Each inode had a link to its owning inode that allowed a file to know what directory it was in. The exception was the '/' directory which owned itself. There was also a link to contents. If an inode had no contents it could be returned to the free list. Since a directory was just a blessed file even an empty directory had to have contents to keep it from being garbage collected. Thus the .. was the inode's link to the parent inode and the . was there to indicate the directory still was usable. rmdir (by calling unlink) could remove the . directory if there were no other contents and the inode would then move to the free list when there were no more references to it.