The connect_msg_to_attr() function

Updated: April 19, 2023

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:

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);
}
  1. 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.
  2. 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.
  3. 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.
  4. We're missing an intermediate component (i.e., /valid/missing/extra/extra where missing is not present).
  5. 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.
  6. 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).
  7. Everything passed.