A directory contains a list of filename ⇒ inode mappings. Your directory
/home/tim includes an entry with filename
tim.pdf, pointing at (say) inode
How do we get at that directory? Well, a directory is really a special kind of file that contains those entries. We can find it the same way we find other files, by looking in its parent:
/home will have an entry with filename
tim that points to the inode of the directory. In turn, we can find
/home by looking in its parent,
/ is the root, and it's a little bit more special. The system knows how to get to it directly, because it has no parent.
The name of a file is the local name it has in its directory:
tim.pdf. The path of a file describes how you get to it from the root:
/home/tim/tim.pdf. If you like, you can think of that as a set of instructions: first find
/, then find
home inside that, then
tim, then finally
tim.pdf that you were looking for.
Resolving any path is in effect a recursive algorithm with this pseudocode:
inode find_file(inode where_i_am, string remaining_path):
if remaining_path is empty:
# Nothing more to look at - we've found the file!
current_item = remaining_path
rest_of_path = remaining_path[1..]
for entry in directory_entries(where_i_am):
if entry.filename == current_item:
return find_file(entry.inode, rest_of_path)
return file not found
We'd find your file with:
find_file(inode_of_root, ["home", "tim", "tim.pdf"])
There are a few cases where things get slightly more complicated, which the pseudocode doesn't cover. One of those is mounts: when you mount another partition at, say,
/home, the system remembers that when it goes to
/home it should shift over to that other partition, and start looking for
tim in the root of that file system instead. The new file system will have its own set of inodes, so you actually need to know both the inode and the device to access a file's data. A real structure actually includes both.
Symbolic links tell the system to go and look up some other path at this point, and then continue on searching from that new location.
Another case is hard links (your old friend). An ordinary file inode can have arbitrarily many hard links to it. You could make a link with
ln tim.pdf pdf.tim, which would have the same contents and live at the same point on disk. There would be a separate directory entry
pdf.tim that pointed at the same inode
1234 as the entry for
tim.pdf. Our algorithm works just fine for this case: a hard link to a file is exactly the same as the original file, and we don't need to distinguish it at all in any way. The fact that a hard link is just another name for an inode is why you can't make hard links across file systems.
Yet another is the special entries
... These are (often, but filesystem-dependent) real directory entries. They're essentially hard links to the directory itself and to its parent. Our algorithm deals with that too. There's an interesting case that comes up with mounts: because the underlying filesystem doesn't know where it would be mounted, it couldn't have the right
.. entry. To deal with that the system essentially cheats and shows the
.. entry from the directory on the parent device, rather than from the root of the mounted file system.
So when you're looking at things from the perspective of inodes like this then:
- A file name is a name a particular inode is called inside a particular directory.
- A path is some instructions for how to reach an inode from a known point.