int nfs4_op_readlink(struct nfs_argop4 *op, compound_data_t *data, struct nfs_resop4 *resp) { READLINK4res * const res_READLINK4 = &resp->nfs_resop4_u.opreadlink; cache_inode_status_t cache_status; struct gsh_buffdesc link_buffer = {.addr = NULL, .len = 0 }; resp->resop = NFS4_OP_READLINK; res_READLINK4->status = NFS4_OK; /* * Do basic checks on a filehandle You can readlink only on a link * ... */ res_READLINK4->status = nfs4_sanity_check_FH(data, SYMBOLIC_LINK, false); if (res_READLINK4->status != NFS4_OK) return res_READLINK4->status; /* Using cache_inode_readlink */ cache_status = cache_inode_readlink(data->current_entry, &link_buffer); if (cache_status != CACHE_INODE_SUCCESS) { res_READLINK4->status = nfs4_Errno(cache_status); return res_READLINK4->status; } res_READLINK4->READLINK4res_u.resok4.link.utf8string_val = link_buffer.addr; /* NFSv4 does not require the \NUL terminator. */ res_READLINK4->READLINK4res_u.resok4.link.utf8string_len = link_buffer.len - 1; res_READLINK4->status = NFS4_OK; return res_READLINK4->status; } /* nfs4_op_readlink */ /** * @brief Free memory allocated for READLINK result * * This function frees the memory allocated for the resutl of the * NFS4_OP_READLINK operation. * * @param[in,out] resp nfs4_op results */ void nfs4_op_readlink_Free(nfs_resop4 *res) { READLINK4res *resp = &res->nfs_resop4_u.opreadlink; if (resp->status == NFS4_OK && resp->READLINK4res_u.resok4.link.utf8string_val) gsh_free(resp->READLINK4res_u.resok4.link.utf8string_val); return; } /* nfs4_op_readlink_Free */
int _9p_readlink(struct _9p_request_data *req9p, u32 *plenout, char *preply) { char *cursor = req9p->_9pmsg + _9P_HDR_SIZE + _9P_TYPE_SIZE; u16 *msgtag = NULL; u32 *fid = NULL; struct _9p_fid *pfid = NULL; cache_inode_status_t cache_status; struct gsh_buffdesc link_buffer = {.addr = NULL, .len = 0 }; /* Get data */ _9p_getptr(cursor, msgtag, u16); _9p_getptr(cursor, fid, u32); LogDebug(COMPONENT_9P, "TREADLINK: tag=%u fid=%u", (u32) *msgtag, *fid); if (*fid >= _9P_FID_PER_CONN) return _9p_rerror(req9p, msgtag, ERANGE, plenout, preply); pfid = req9p->pconn->fids[*fid]; /* Check that it is a valid fid */ if (pfid == NULL || pfid->pentry == NULL) { LogDebug(COMPONENT_9P, "request on invalid fid=%u", *fid); return _9p_rerror(req9p, msgtag, EIO, plenout, preply); } _9p_init_opctx(pfid, req9p); /* let's do the job */ cache_status = cache_inode_readlink(pfid->pentry, &link_buffer); if (cache_status != CACHE_INODE_SUCCESS) return _9p_rerror(req9p, msgtag, _9p_tools_errno(cache_status), plenout, preply); /* Build the reply */ _9p_setinitptr(cursor, preply, _9P_RREADLINK); _9p_setptr(cursor, msgtag, u16); _9p_setstr(cursor, link_buffer.len - 1, link_buffer.addr); _9p_setendptr(cursor, preply); _9p_checkbound(cursor, preply, plenout); LogDebug(COMPONENT_9P, "RREADLINK: tag=%u fid=%u link=%s", *msgtag, (u32) *fid, (char *) link_buffer.addr); gsh_free(link_buffer.addr); return 1; }
int nfs4_op_readlink(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp) { cache_inode_status_t cache_status; fsal_path_t symlink_path; char __attribute__ ((__unused__)) funcname[] = "nfs4_op_readlink"; resp->resop = NFS4_OP_READLINK; res_READLINK4.status = NFS4_OK; /* If there is no FH */ if(nfs4_Is_Fh_Empty(&(data->currentFH))) { res_READLINK4.status = NFS4ERR_NOFILEHANDLE; return NFS4ERR_NOFILEHANDLE; } /* If the filehandle is invalid */ if(nfs4_Is_Fh_Invalid(&(data->currentFH))) { res_READLINK4.status = NFS4ERR_BADHANDLE; return NFS4ERR_BADHANDLE; } /* Tests if the Filehandle is expired (for volatile filehandle) */ if(nfs4_Is_Fh_Expired(&(data->currentFH))) { res_READLINK4.status = NFS4ERR_FHEXPIRED; return NFS4ERR_FHEXPIRED; } /* You can readlink only on a link ... */ if(data->current_filetype != SYMBOLIC_LINK) { /* As said on page 194 of RFC3530, return NFS4ERR_INVAL in this case */ res_READLINK4.status = NFS4ERR_INVAL; return res_READLINK4.status; } /* Using cache_inode_readlink */ if(cache_inode_readlink(data->current_entry, &symlink_path, data->ht, data->pclient, data->pcontext, &cache_status) == CACHE_INODE_SUCCESS) { /* Alloc read link */ if((res_READLINK4.READLINK4res_u.resok4.link.utf8string_val = (char *)Mem_Alloc_Label(symlink_path.len, "nfs4_op_readlink")) == NULL) { res_READLINK4.status = NFS4ERR_INVAL; return res_READLINK4.status; } /* convert the fsal path to a utf8 string */ if(str2utf8((char *)symlink_path.path, &res_READLINK4.READLINK4res_u.resok4.link) == -1) { res_READLINK4.status = NFS4ERR_INVAL; return res_READLINK4.status; } res_READLINK4.status = NFS4_OK; return res_READLINK4.status; } res_READLINK4.status = nfs4_Errno(cache_status); return res_READLINK4.status; } /* nfs4_op_readlink */
int _9p_readlink( _9p_request_data_t * preq9p, void * pworker_data, u32 * plenout, char * preply) { char * cursor = preq9p->_9pmsg + _9P_HDR_SIZE + _9P_TYPE_SIZE ; nfs_worker_data_t * pwkrdata = (nfs_worker_data_t *)pworker_data ; u16 * msgtag = NULL ; u32 * fid = NULL ; _9p_fid_t * pfid = NULL ; int rc = 0 ; int err = 0 ; fsal_path_t symlink_data; cache_inode_status_t cache_status ; if ( !preq9p || !pworker_data || !plenout || !preply ) return -1 ; /* Get data */ _9p_getptr( cursor, msgtag, u16 ) ; _9p_getptr( cursor, fid, u32 ) ; LogDebug( COMPONENT_9P, "TREADLINK: tag=%u fid=%u",(u32)*msgtag, *fid ) ; if( *fid >= _9P_FID_PER_CONN ) { err = ERANGE ; rc = _9p_rerror( preq9p, msgtag, &err, plenout, preply ) ; return rc ; } pfid = &preq9p->pconn->fids[*fid] ; /* let's do the job */ if( cache_inode_readlink( pfid->pentry, &symlink_data, pwkrdata->ht, &pwkrdata->cache_inode_client, &pfid->fsal_op_context, &cache_status ) != CACHE_INODE_SUCCESS ) { err = _9p_tools_errno( cache_status ) ; ; rc = _9p_rerror( preq9p, msgtag, &err, plenout, preply ) ; return rc ; } /* Build the reply */ _9p_setinitptr( cursor, preply, _9P_RREADLINK ) ; _9p_setptr( cursor, msgtag, u16 ) ; _9p_setstr( cursor, strlen( symlink_data.path ), symlink_data.path ) ; _9p_setendptr( cursor, preply ) ; _9p_checkbound( cursor, preply, plenout ) ; LogDebug( COMPONENT_9P, "RREADLINK: tag=%u fid=%u link=%s", *msgtag, (u32)*fid, symlink_data.path ) ; return 1 ; }
int nfs_Readlink(nfs_arg_t * parg, exportlist_t * pexport, fsal_op_context_t * pcontext, cache_inode_client_t * pclient, hash_table_t * ht, struct svc_req *preq, nfs_res_t * pres) { static char __attribute__ ((__unused__)) funcName[] = "nfs_Readlink"; cache_entry_t *pentry = NULL; fsal_attrib_list_t attr; cache_inode_file_type_t filetype; cache_inode_status_t cache_status; int rc; fsal_path_t symlink_data; char *ptr = NULL; if(preq->rq_vers == NFS_V3) { /* to avoid setting it on each error case */ pres->res_readlink3.READLINK3res_u.resfail.symlink_attributes.attributes_follow = FALSE; } /* Convert file handle into a vnode */ if((pentry = nfs_FhandleToCache(preq->rq_vers, &(parg->arg_readlink2), &(parg->arg_readlink3.symlink), NULL, &(pres->res_readlink2.status), &(pres->res_readlink3.status), NULL, &attr, pcontext, pclient, ht, &rc)) == NULL) { /* Stale NFS FH ? */ return rc; } /* Extract the filetype */ filetype = cache_inode_fsal_type_convert(attr.type); /* Sanity Check: the pentry must be a link */ if(filetype != SYMBOLIC_LINK) { switch (preq->rq_vers) { case NFS_V2: pres->res_readlink2.status = NFSERR_IO; break; case NFS_V3: pres->res_readlink3.status = NFS3ERR_INVAL; } /* switch */ return NFS_REQ_OK; } /* if */ /* Perform readlink on the pentry */ if(cache_inode_readlink(pentry, &symlink_data, ht, pclient, pcontext, &cache_status) == CACHE_INODE_SUCCESS) { if((ptr = Mem_Alloc(FSAL_MAX_NAME_LEN)) == NULL) { switch (preq->rq_vers) { case NFS_V2: pres->res_readlink2.status = NFSERR_NXIO; break; case NFS_V3: pres->res_readlink3.status = NFS3ERR_IO; } /* switch */ return NFS_REQ_OK; } strcpy(ptr, symlink_data.path); /* Reply to the client (think about Mem_Free data after use ) */ switch (preq->rq_vers) { case NFS_V2: pres->res_readlink2.READLINK2res_u.data = ptr; pres->res_readlink2.status = NFS_OK; break; case NFS_V3: pres->res_readlink3.READLINK3res_u.resok.data = ptr; nfs_SetPostOpAttr(pcontext, pexport, pentry, &attr, &(pres->res_readlink3.READLINK3res_u.resok. symlink_attributes)); pres->res_readlink3.status = NFS3_OK; break; } return NFS_REQ_OK; } /* If we are here, there was an error */ if(nfs_RetryableError(cache_status)) { return NFS_REQ_DROP; } nfs_SetFailedStatus(pcontext, pexport, preq->rq_vers, cache_status, &pres->res_readlink2.status, &pres->res_readlink3.status, pentry, &(pres->res_readlink3.READLINK3res_u.resfail.symlink_attributes), NULL, NULL, NULL, NULL, NULL, NULL); return NFS_REQ_OK; } /* nfs_Readlink */
int nfs3_readlink(nfs_arg_t *arg, struct svc_req *req, nfs_res_t *res) { cache_entry_t *entry = NULL; cache_inode_status_t cache_status; struct gsh_buffdesc link_buffer = { .addr = NULL, .len = 0 }; int rc = NFS_REQ_OK; if (isDebug(COMPONENT_NFSPROTO)) { char str[LEN_FH_STR]; nfs_FhandleToStr(req->rq_vers, &(arg->arg_readlink3.symlink), NULL, str); LogDebug(COMPONENT_NFSPROTO, "REQUEST PROCESSING: Calling nfs_Readlink handle: %s", str); } /* to avoid setting it on each error case */ res->res_readlink3.READLINK3res_u.resfail.symlink_attributes. attributes_follow = false; entry = nfs3_FhandleToCache(&arg->arg_readlink3.symlink, &res->res_readlink3.status, &rc); if (entry == NULL) { /* Status and rc have been set by nfs3_FhandleToCache */ goto out; } /* Sanity Check: the entry must be a link */ if (entry->type != SYMBOLIC_LINK) { res->res_readlink3.status = NFS3ERR_INVAL; rc = NFS_REQ_OK; goto out; } cache_status = cache_inode_readlink(entry, &link_buffer); if (cache_status != CACHE_INODE_SUCCESS) { res->res_readlink3.status = nfs3_Errno(cache_status); nfs_SetPostOpAttr(entry, &res->res_readlink3.READLINK3res_u.resfail. symlink_attributes); if (nfs_RetryableError(cache_status)) rc = NFS_REQ_DROP; goto out; } /* Reply to the client */ res->res_readlink3.READLINK3res_u.resok.data = link_buffer.addr; nfs_SetPostOpAttr(entry, &res->res_readlink3.READLINK3res_u. resok.symlink_attributes); res->res_readlink3.status = NFS3_OK; rc = NFS_REQ_OK; out: /* return references */ if (entry) cache_inode_put(entry); return rc; } /* nfs3_readlink */ /** * @brief Free the result structure allocated for nfs3_readlink. * * This function frees the result structure allocated for * nfs3_readlink. * * @param[in,out] res Result structure * */ void nfs3_readlink_free(nfs_res_t *res) { if (res->res_readlink3.status == NFS3_OK) gsh_free(res->res_readlink3.READLINK3res_u.resok.data); }