The c_readlink() function

Updated: April 19, 2023

This is a simple one. You've already seen how symlinks are stored internally in the RAM-disk resource manager. The job of c_readlink() is to return the value of the symbolic link. It's called when you do a full ls, for example:

# ls -lF /my_temp
lrwxrwxrwx  1 root    root    4 Aug 16 14:06 /my_temp@ -> /tmp

Since this code shares a lot in common with the processing for c_open(), I'll just point out the major differences.

int
cfs_c_readlink (resmgr_context_t *ctp, io_readlink_t *msg,
                RESMGR_HANDLE_T *handle, void *reserved)
{
  des_t   parent, target;
  int     sts, sts2;
  int     eflag;
  struct  _client_info *cinfo;
  int     tmp;

  // get client info
  if ((sts = iofunc_client_info_ext (ctp, 0, &cinfo, IOFUNC_CLIENTINFO_GETGROUPS)) != EOK) {
    return (sts);
  }

  // get parent and target
  sts2 = connect_msg_to_attr (ctp, &msg -> connect, handle,
                              &parent, &target, &sts, cinfo);
  (void)iofunc_client_info_ext_free (&cinfo);

  if (sts2 != EOK) {
      return (sts);
  }

  // there has to be a target!
  if (!target.attr) {
    return (sts);
  }

  // 1) call the helper function
  sts = iofunc_readlink (ctp, msg, &target.attr -> attr, NULL);
  if (sts != EOK) {
    return (sts);
  }

  // 2) preserve eflag...
  eflag = msg -> connect.eflag;
  memset (&msg -> link_reply, 0, sizeof (msg -> link_reply));
  msg -> link_reply.eflag = eflag;

  // 3) return data
  tmp = strlen (target.attr -> type.symlinkdata);
  SETIOV (&ctp -> iov [0], &msg -> link_reply,
          sizeof (msg -> link_reply));
  SETIOV (&ctp -> iov[1], target.attr -> type.symlinkdata, tmp);
  msg -> link_reply.path_len = tmp;
  MsgReplyv (ctp -> rcvid, EOK, ctp -> iov, 2);
  return (_RESMGR_NOREPLY);
}

The detailed code walkthrough is as follows:

  1. We use the helper function iofunc_readlink() to do basic checking for us. If it's not happy with the parameters, then we return whatever it returned.
  2. Just like in symlink redirection, we need to preserve flags; in this case it's just the eflag—we zero-out everything else.
  3. And, just as in the symlink redirection, we return a two-part IOV; the first part points to the header, the second part points to the string. Note that in this case, unlike symlink redirection, we didn't need to construct the pathname. That's because the goal of this function is to return just the contents of the symlink, and we know that they're sitting in the symlinkdata member of the extended attributes structure.