Pathname resolution

The next function that your filesystem must perform is called pathname resolution. This is the process of accepting an arbitrary pathname, and analyzing the components within the pathname to determine if the target is accessible, possibly creating the target, and eventually resolving the target into an attributes structure.

While this may sound fairly trivial, it's actually a fair bit of work to get it just right, especially if you want to handle symbolic links correctly along the way. :-)

The algorithm can be summarized as follows. Break up the pathname into components (each component is delimited by the forward slash / character). For each pathname component, perform the following:

  1. If there are additional components after this one, then this component must be a directory. Return an error if this component is not a directory.
  2. Check to see that we can access the current component (permission checks). If we can't, return an error indicating the access problem.
  3. Search the directory of the parent to see if this component exists. If not, return an error (for new component creation, this error is handled higher up, and a new component is created.)
  4. If this component is a symbolic link (symlink), and it's either a non-terminal symlink, or certain flags are set, redirect the symlink (processing ends).

If all of the above steps proceeded without problems, we've effectively performed "pathname resolution." We now have either a pointer to an attributes structure that identifies the target (and, for convenience, the target's parent attributes structure as well), or we have a pointer to just the parent attributes structure. The reason we might not have a pointer to the target is when we're creating the target. We need to verify that we can actually get to where the target will be, but obviously we don't expect the target to exist.

Returning to our example of /home/jack/spud.txt, let's imagine a user trying to open that file for reading. Here's the diagram we used earlier:

Figure 1. Internal resource manager view of filesystem.

We see that the root of this filesystem is the attributes structure at address 0x80001234. We're assuming (for simplicity) that this filesystem is mounted at the root of the filesystem space. The first component we see in /home/jack/spud.txt is home. Because we have the address of the attributes structure (0x80001234), we can look at the array of directory elements and see if we can find the component home. According to our first rule, since there are additional components after this one (in fact, they are jack/spud.txt), we know that home must be a directory. So we check the attributes structure's mode member, and discover that home is indeed a directory.

Next, we need to look at the attributes structure's uid, gid, and mode fields to verify that the user doing the open() call (to open the file for reading) is actually allowed to perform that operation. Note that we look at all the pathname components along the way, not just the final one! We assume this passes. We repeat the process for the attributes structure at 0x80005678, and this time search for the next component, jack. We find it, and we have the appropriate permissions. Next we perform this process again for the attributes structure at 0x80009000, and find spud.txt (and once again assume permissions are OK). This leads us to the attributes structure at 0x8000ABCD, which contains the data that we're after. Since we're only doing an open(), we don't actually return any data. We bind our OCB to the attributes structure at 0x8000ABCD and declare the open() a terrific success.