Why can’t I edit links and directories directly

directoryhexdumpsymlink

There are programs such as hexedit that allow one to edit each bit of a file, and as I keep hearing that in Unix "everything is a file", I tried to edit some directory, expecting bytes referring to inodes or filenames. Instead, I get:

hexedit: teste: not a file

However, I was happy in finding that it did work with many dev files (partitions, entire hard drives, fake components (such as /dev/null), you name it).

And for soft links, hexedit follows them, and the error is the same as the destination's, though with the name of the link instead, in my test:

hexedit: testeln: not a file

Even if the original file is removed and the link invalid, the behaviour is the same. But this isn't all.

If one copies symbolic links without a special option to preserve (or use rsync's options), they become regular files, and fortunately, I had an old link like that:

00000000   49 6E 74 78  4C 4E 4B 01  2F 00 73 00  72 00 76 00  2F 00 73 00  61 00 6D 00  62 00 61 00  2F 00 73 00  IntxLNK./.s.r.v./.s.a.m.b.a./.s.
00000020   68 00 61 00  72 00 65 00                                                                                h.a.r.e.

In the case of /dev/initctl, loop-control, snapshot and tty2 (even if it's open and I have read/write privileges), hexedit gives (after clearing the screen, in the last line):

the long seek failed (-1 instead of 0), leaving :(

For /dev/log:

hexedit: log: No such device or address

Can I see directories in such a way? Why are links automatically followed? How can I change that behaviour? Why does hexedit behave like that just (AFAIK) for symlinks and directories? I suspect some weird files I found in /dev are only seemingly empty, even if I use sudo.

Best Answer

POSIX requires this behaviour for files of certain types on the system call level. The open function follows symbolic links, except if the O_NOFOLLOW flag is set – which hexedit most probably does not do.

For directories, the read function shall return an error code and set errno to EISDIR. From http://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html:

The fildes argument refers to a directory and the implementation does not allow the directory to be read using read() or pread(). The readdir() function should be used instead.

As @goldilocks suggested, there are 7 different file types at least, each with different semantics:

  • regular files
  • symbolic links
  • directories
  • block devices
  • character devices
  • FIFOs and
  • sockets
Related Question