| Updated: October 28, 2024 | 
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: