The next-higher function in the call hierarchy is connect_msg_to_attr().
It calls pathwalk() to break apart the pathname, and then looks at
the return code, the type of request, and other parameters to make a decision.
You'll see this function used in most of the resource manager connect functions in the RAM disk.
After pathwalk(), several scenarios are possible:
- All components within the pathname were accessible, of the correct type, and present.
In this case, pathname processing is done, and we can continue on to the next step (a zero value,
indicating all OK, is returned).
- As above, except that the final component doesn't exist.
In this case, we may be done; it depends on whether we're creating the final component or not
(a zero value is returned, but rval is set to ENOENT).
We leave it to a higher level to determine if the final component was required.
- A component in the pathname was not a directory, does not exist, or the client doesn't have permission to access it.
In this case, we're done as well, but we abort with an error return (a nonzero is returned,
and rval is set to the error number).
- A component in the pathname is a symbolic link.
In this case, we're done as well, and we perform a symlink redirect.
A nonzero is returned, which should be passed up to the resource-manager framework of the caller.
This function accepts two parameters, parent and target,
which are used extensively
in the upper levels to describe the directory that contains the target, as well as the target itself (if it exists).
int
connect_msg_to_attr (resmgr_context_t *ctp,
struct _io_connect *cmsg,
RESMGR_HANDLE_T *handle,
des_t *parent, des_t *target,
int *sts, struct _client_info *cinfo)
{
des_t components [_POSIX_PATH_MAX];
int ncomponents;
// 1) Find target, validate accessibility of components
ncomponents = _POSIX_PATH_MAX;
*sts = pathwalk (ctp, cmsg -> path, handle, 0, components,
&ncomponents, cinfo);
// 2) Assign parent and target
*target = components [ncomponents - 1];
*parent = ncomponents == 1 ? *target
: components [ncomponents - 2];
// 3) See if we have an error, abort.
if (*sts == ENOTDIR || *sts == EACCES) {
return (1);
}
// 4) missing non-final component
if (components [ncomponents].name != NULL && *sts == ENOENT) {
return (1);
}
if (*sts == EOK) {
// 5) if they wanted a directory, and we aren't one, honk.
if (S_ISDIR (cmsg -> mode)
&& !S_ISDIR (components [ncomponents-1].attr->attr.mode)) {
*sts = ENOTDIR;
return (1);
}
// 6) yes, symbolic links are complicated!
// (See walkthrough and notes)
if (S_ISLNK (components [ncomponents - 1].attr -> attr.mode)
&& (components [ncomponents].name
|| (cmsg -> eflag & _IO_CONNECT_EFLAG_DIR)
|| !S_ISLNK (cmsg -> mode))) {
redirect_symlink (ctp, cmsg, target -> attr,
components, ncomponents);
*sts = _RESMGR_NOREPLY;
return (1);
}
}
// 7) all OK
return (0);
}
- Call pathwalk() to validate the accessibility of all components.
Notice that we use the des_t directory entry structure that we used in the extended attributes structure
for the call to pathwalk()—it's best if you don't need to reinvent many similar but slightly different data types.
- The last two entries in the broken-up components array are the last two pathname components.
However, there may be only one entry.
(Imagine creating a file in the root directory of the filesystem—the file that you're creating
doesn't exist, and the root directory of the filesystem is the first and only entry in
the broken-up pathname components.)
If there is only one entry, then assign the last entry to both the parent and target.
- Now take a look and see if there were any problems.
The two problems that we're interested in at this point are missing directory components and the inability to access some path component
along the way.
If it's either of these two problems, we can give up right away.
- We're missing an intermediate component (i.e., /valid/missing/extra/extra where
missing is not present).
- The caller of connect_msg_to_attr() passes its connect message, which includes a mode field.
This indicates what kind of thing it's expecting the target to be.
If the caller wanted a directory, but the final component isn't a directory, we return an error as well.
- Symbolic links.
Remember that pathwalk() aborted at the symbolic link (if it found one) and didn't process any
of the entries below the symlink (see below).
- Everything passed.