In traditional Unix, file systems contain special files. These are: symbolic links, character devices, block devices, named pipes, and named sockets. Naturally the Hurd also support these.
However, if you take a look at
find that there are no RPCs that deal specifically with these types.
Sure, you can get the type of the file through
io_stat (among other
things), but there are none that e.g. lets you create a symbolic link.
If you take a look at how glibc implements
symlink, you'll notice
that all it does is create a new file and set its passive translator to
/hurd/symlink DEST. You can verify this yourself by creating a symlink
ln -s foo bar and print its passive translator setting with
This is how the other special files are implemented as well. The header
hurd/paths.h contains a list of paths that are used to implement
So all special files are implemented through special-purpose translators,
right? Not quite, instead the translators of this list are often
implemented in their underlying filesystem through translator
short-circuiting. In fact,
blkdev aren't even implemented
as translators at all.
Translator short-circuiting is when a file system server implements the
functionality of a passive translator itself, instead of actually starting
it. For instance, all the
FS_RETRY_* reply to the caller. So instead of starting it, the file
system server can simply continue the file name look-up internally by
appending the target of the symbolic link to the path being looked-up.
This way, we can skip starting the
symlink translator, skip retrying
the look-up on the newly started translator, and we might also skip a
retry to the same file system server again, if the target of the symbolic
link is in it.
In fact, the list's translators that actually are implemented (
ifsock) are only used as a default implementation if the underlying
file system's translator does not implement the functionality itself, i.e., if
it doesn't short-circuit it.
To make sure that you use one of these translators, there by bypassing the
short-circuiting mechanism, you can either start it as
an active translator, or use a different path from the one in
settrans bar /hurd/./symlink foo.
There is also a
FS_TRANS_FORCE flag defined for the
RPCs, but it currently isn't set from anywhere.
The best example of how short-circuiting is implemented can be found
libdiskfs. Notice how it detects if a translator to store
is a special file in
diskfs_S_file_set_translator and instead
of storing a real passive translator setting on the disk, stores it as a
symlink node (using
diskfs_create_symlink_hook or a generic implementation).
In later look-ups to the node, it checks the node's
stat structure in
diskfs_S_dir_lookup and handles special file types appropriately.
Doing this translator short-circuiting has disadvantages: code duplication, or
in general adding code complexity that isn't needed for implementing the same
functionality, but it also has advantages: using functionality that the file
system's data structures nevertheless already provide -- storing symbolic links
ext2fs' inodes instead of storing passive translator settings -- and thus
staying compatible with other operating systems mounting that file system.
Also, this short-circuiting does preserve system resources, as it's no longer
required to start a
symlink translator for resolving each symbolic link, as
well as it does reduce the RPC overhead.
It can also confuse users who expect the passive translator to start. For instance, if a user notices that's code is lacking some functionality, but that it unexpectedly works when the user tries to run it.