int nfs4_op_link(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp) { char __attribute__ ((__unused__)) funcname[] = "nfs4_op_link"; cache_entry_t * dir_pentry = NULL; cache_entry_t * file_pentry = NULL; cache_inode_status_t cache_status; fsal_attrib_list_t attr; fsal_name_t newname; resp->resop = NFS4_OP_LINK; res_LINK4.status = NFS4_OK; /* Do basic checks on a filehandle */ res_LINK4.status = nfs4_sanity_check_FH(data, 0LL); if(res_LINK4.status != NFS4_OK) return res_LINK4.status; /* If there is no FH */ if(nfs4_Is_Fh_Empty(&(data->savedFH))) { res_LINK4.status = NFS4ERR_NOFILEHANDLE; return res_LINK4.status; } /* If the filehandle is invalid */ if(nfs4_Is_Fh_Invalid(&(data->savedFH))) { res_LINK4.status = NFS4ERR_BADHANDLE; return res_LINK4.status; } /* Tests if the Filehandle is expired (for volatile filehandle) */ if(nfs4_Is_Fh_Expired(&(data->savedFH))) { res_LINK4.status = NFS4ERR_FHEXPIRED; return res_LINK4.status; } /* Pseudo Fs is explictely a Read-Only File system */ if(nfs4_Is_Fh_Pseudo(&(data->currentFH))) { res_LINK4.status = NFS4ERR_ROFS; return res_LINK4.status; } /* If data->exportp is null, a junction from pseudo fs was traversed, credp and exportp have to be updated */ if(data->pexport == NULL) { res_LINK4.status = nfs4_SetCompoundExport(data); if(res_LINK4.status != NFS4_OK) return res_LINK4.status; } /* * This operation creates a hard link, for the file represented by the saved FH, in directory represented by currentFH under the * name arg_LINK4.target */ /* Crossing device is not allowed */ if(((file_handle_v4_t *) (data->currentFH.nfs_fh4_val))->exportid != ((file_handle_v4_t *) (data->savedFH.nfs_fh4_val))->exportid) { res_LINK4.status = NFS4ERR_XDEV; return res_LINK4.status; } /* If name is empty, return EINVAL */ if(arg_LINK4.newname.utf8string_len == 0) { res_LINK4.status = NFS4ERR_INVAL; return res_LINK4.status; } /* Check for name to long */ if(arg_LINK4.newname.utf8string_len > FSAL_MAX_NAME_LEN) { res_LINK4.status = NFS4ERR_NAMETOOLONG; return res_LINK4.status; } /* Convert the UFT8 objname to a regular string */ if((cache_status = cache_inode_error_convert(FSAL_buffdesc2name ((fsal_buffdesc_t *) & arg_LINK4.newname, &newname))) != CACHE_INODE_SUCCESS) { res_LINK4.status = nfs4_Errno(cache_status); return res_LINK4.status; } /* Sanity check: never create a link named '.' or '..' */ if(!FSAL_namecmp(&newname, (fsal_name_t *) & FSAL_DOT) || !FSAL_namecmp(&newname, (fsal_name_t *) & FSAL_DOT_DOT)) { res_LINK4.status = NFS4ERR_BADNAME; return res_LINK4.status; } /* get info from compound data */ dir_pentry = data->current_entry; /* Destination FH (the currentFH) must be a directory */ if(data->current_filetype != DIRECTORY) { res_LINK4.status = NFS4ERR_NOTDIR; return res_LINK4.status; } /* Target object (the savedFH) must not be a directory */ if(data->saved_filetype == DIRECTORY) { res_LINK4.status = NFS4ERR_ISDIR; return res_LINK4.status; } /* We have to keep track of the 'change' file attribute for reply structure */ if((cache_status = cache_inode_getattr(dir_pentry, &attr, data->pcontext, &cache_status)) != CACHE_INODE_SUCCESS) { res_LINK4.status = nfs4_Errno(cache_status); return res_LINK4.status; } res_LINK4.LINK4res_u.resok4.cinfo.before = cache_inode_get_changeid4(dir_pentry); /* Convert savedFH into a vnode */ file_pentry = data->saved_entry; /* make the link */ if(cache_inode_link(file_pentry, dir_pentry, &newname, &attr, data->pcontext, &cache_status) != CACHE_INODE_SUCCESS) { res_LINK4.status = nfs4_Errno(cache_status); return res_LINK4.status; } res_LINK4.LINK4res_u.resok4.cinfo.after = cache_inode_get_changeid4(dir_pentry); res_LINK4.LINK4res_u.resok4.cinfo.atomic = FALSE; res_LINK4.status = NFS4_OK; return NFS4_OK; } /* nfs4_op_link */
int nfs4_op_putfh(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp) { int rc; int error; fsal_attrib_list_t attr; char outstr[1024]; char __attribute__ ((__unused__)) funcname[] = "nfs4_op_putfh"; resp->resop = NFS4_OP_PUTFH; res_PUTFH4.status = NFS4_OK; /* If there is no FH */ if(nfs4_Is_Fh_Empty(&(arg_PUTFH4.object))) { res_PUTFH4.status = NFS4ERR_NOFILEHANDLE; return res_PUTFH4.status; } /* If the filehandle is invalid */ if(nfs4_Is_Fh_Invalid(&(arg_PUTFH4.object))) { res_PUTFH4.status = NFS4ERR_BADHANDLE; return res_PUTFH4.status; } /* Tests if teh Filehandle is expired (for volatile filehandle) */ if(nfs4_Is_Fh_Expired(&(arg_PUTFH4.object))) { res_PUTFH4.status = NFS4ERR_FHEXPIRED; return res_PUTFH4.status; } /* If no currentFH were set, allocate one */ if(data->currentFH.nfs_fh4_len == 0) { if((error = nfs4_AllocateFH(&(data->currentFH))) != NFS4_OK) { res_PUTFH4.status = error; return res_PUTFH4.status; } } /* The same is to be done with mounted_on_FH */ if(data->mounted_on_FH.nfs_fh4_len == 0) { if((error = nfs4_AllocateFH(&(data->mounted_on_FH))) != NFS4_OK) { res_PUTFH4.status = error; return res_PUTFH4.status; } } /* Copy the filehandle from the reply structure */ data->currentFH.nfs_fh4_len = arg_PUTFH4.object.nfs_fh4_len; data->mounted_on_FH.nfs_fh4_len = arg_PUTFH4.object.nfs_fh4_len; /* Put the data in place */ memcpy(data->currentFH.nfs_fh4_val, arg_PUTFH4.object.nfs_fh4_val, arg_PUTFH4.object.nfs_fh4_len); memcpy(data->mounted_on_FH.nfs_fh4_val, arg_PUTFH4.object.nfs_fh4_val, arg_PUTFH4.object.nfs_fh4_len); nfs4_sprint_fhandle(&arg_PUTFH4.object, outstr); LogDebug(COMPONENT_NFS_V4, "NFS4_OP_PUTFH CURRENTFH BEFORE: File handle = %s", outstr); /* If the filehandle is not pseudo hs file handle, get the entry related to it, otherwise use fake values */ if(nfs4_Is_Fh_Pseudo(&(data->currentFH))) { data->current_entry = NULL; data->current_filetype = DIR_BEGINNING; data->pexport = NULL; /* No exportlist is related to pseudo fs */ } else { /* If data->exportp is null, a junction from pseudo fs was traversed, credp and exportp have to be updated */ if(data->pexport == NULL) { if((error = nfs4_SetCompoundExport(data)) != NFS4_OK) { res_PUTFH4.status = error; return res_PUTFH4.status; } } /* Build the pentry */ if((data->current_entry = nfs_FhandleToCache(NFS_V4, NULL, NULL, &(data->currentFH), NULL, NULL, &(res_PUTFH4.status), &attr, data->pcontext, data->pclient, data->ht, &rc)) == NULL) { res_PUTFH4.status = NFS4ERR_BADHANDLE; return res_PUTFH4.status; } /* Extract the filetype */ data->current_filetype = cache_inode_fsal_type_convert(attr.type); } /* Trace */ return NFS4_OK; } /* nfs4_op_putfh */
int nfs4_op_restorefh(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp) { char __attribute__ ((__unused__)) funcname[] = "nfs4_op_restorefh"; /* First of all, set the reply to zero to make sure it contains no parasite information */ memset(resp, 0, sizeof(struct nfs_resop4)); resp->resop = NFS4_OP_RESTOREFH; res_RESTOREFH.status = NFS4_OK; /* If there is no currentFH, teh return an error */ if(nfs4_Is_Fh_Empty(&(data->savedFH))) { /* There is no current FH, return NFS4ERR_RESTOREFH (cg RFC3530, page 202) */ res_RESTOREFH.status = NFS4ERR_RESTOREFH; return res_RESTOREFH.status; } /* If the filehandle is invalid */ if(nfs4_Is_Fh_Invalid(&(data->savedFH))) { res_RESTOREFH.status = NFS4ERR_BADHANDLE; return res_RESTOREFH.status; } /* Tests if the Filehandle is expired (for volatile filehandle) */ if(nfs4_Is_Fh_Expired(&(data->savedFH))) { res_RESTOREFH.status = NFS4ERR_FHEXPIRED; return res_RESTOREFH.status; } /* If data->exportp is null, a junction from pseudo fs was traversed, credp and exportp have to be updated */ if(data->pexport == NULL) { res_RESTOREFH.status = nfs4_SetCompoundExport(data); if(res_RESTOREFH.status != NFS4_OK) { LogCrit(COMPONENT_NFS_V4, "Error %d in nfs4_SetCompoundExport", res_RESTOREFH.status); return res_RESTOREFH.status; } } /* Copy the data from current FH to saved FH */ memcpy(data->currentFH.nfs_fh4_val, data->savedFH.nfs_fh4_val, data->savedFH.nfs_fh4_len); data->currentFH.nfs_fh4_len = data->savedFH.nfs_fh4_len; /* If current and saved entry are identical, get no references and make no changes. */ if (data->current_entry == data->saved_entry) { goto out; } if (data->current_entry) { cache_inode_put(data->current_entry); data->current_entry = NULL; } data->current_entry = data->saved_entry; data->current_filetype = data->saved_filetype; /* Take another reference. As of now the filehandle is both saved and current and both must be counted. Protect in case of pseudofs handle. */ if (data->current_entry) { if (cache_inode_lru_ref(data->current_entry, LRU_FLAG_NONE) != CACHE_INODE_SUCCESS) { resp->nfs_resop4_u.opgetfh.status = NFS4ERR_STALE; data->current_entry = NULL; return resp->nfs_resop4_u.opgetfh.status; } } out: if(isFullDebug(COMPONENT_NFS_V4)) { char str[LEN_FH_STR]; sprint_fhandle4(str, &data->currentFH); LogFullDebug(COMPONENT_NFS_V4, "RESTORE FH: Current FH %s", str); } return NFS4_OK; } /* nfs4_op_restorefh */
int nfs4_op_lookupp(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp) { fsal_name_t name; cache_entry_t *dir_pentry = NULL; cache_entry_t *file_pentry = NULL; fsal_attrib_list_t attrlookup; cache_inode_status_t cache_status; int error = 0; fsal_handle_t *pfsal_handle = NULL; char __attribute__ ((__unused__)) funcname[] = "nfs4_op_lookupp"; resp->resop = NFS4_OP_LOOKUPP; resp->nfs_resop4_u.oplookupp.status = NFS4_OK; /* If there is no FH */ if(nfs4_Is_Fh_Empty(&(data->currentFH))) { res_LOOKUPP4.status = NFS4ERR_NOFILEHANDLE; return res_LOOKUPP4.status; } /* If the filehandle is invalid */ if(nfs4_Is_Fh_Invalid(&(data->currentFH))) { res_LOOKUPP4.status = NFS4ERR_BADHANDLE; return res_LOOKUPP4.status; } /* Tests if the Filehandle is expired (for volatile filehandle) */ if(nfs4_Is_Fh_Expired(&(data->currentFH))) { res_LOOKUPP4.status = NFS4ERR_FHEXPIRED; return res_LOOKUPP4.status; } /* looking up for parent directory from ROOTFH return NFS4ERR_NOENT (RFC3530, page 166) */ if(data->currentFH.nfs_fh4_len == data->rootFH.nfs_fh4_len && memcmp(data->currentFH.nfs_fh4_val, data->rootFH.nfs_fh4_val, data->currentFH.nfs_fh4_len) == 0) { /* Nothing to do, just reply with success */ res_LOOKUPP4.status = NFS4ERR_NOENT; return res_LOOKUPP4.status; } /* If in pseudoFS, proceed with pseudoFS specific functions */ if(nfs4_Is_Fh_Pseudo(&(data->currentFH))) return nfs4_op_lookupp_pseudo(op, data, resp); /* If Filehandle points to a xattr object, manage it via the xattrs specific functions */ if(nfs4_Is_Fh_Xattr(&(data->currentFH))) return nfs4_op_lookupp_xattr(op, data, resp); /* If data->exportp is null, a junction from pseudo fs was traversed, credp and exportp have to be updated */ if(data->pexport == NULL) { if((error = nfs4_SetCompoundExport(data)) != NFS4_OK) { res_LOOKUPP4.status = error; return res_LOOKUPP4.status; } } /* Preparying for cache_inode_lookup ".." */ file_pentry = NULL; dir_pentry = data->current_entry; name = FSAL_DOT_DOT; /* BUGAZOMEU: Faire la gestion des cross junction traverse */ if((file_pentry = cache_inode_lookup(dir_pentry, &name, data->pexport->cache_inode_policy, &attrlookup, data->ht, data->pclient, data->pcontext, &cache_status)) != NULL) { /* Extract the fsal attributes from the cache inode pentry */ pfsal_handle = cache_inode_get_fsal_handle(file_pentry, &cache_status); if(cache_status != CACHE_INODE_SUCCESS) { res_LOOKUPP4.status = NFS4ERR_SERVERFAULT; return res_LOOKUPP4.status; } /* Convert it to a file handle */ if(!nfs4_FSALToFhandle(&data->currentFH, pfsal_handle, data)) { res_LOOKUPP4.status = NFS4ERR_SERVERFAULT; return res_LOOKUPP4.status; } /* Copy this to the mounted on FH (if no junction is traversed */ memcpy((char *)(data->mounted_on_FH.nfs_fh4_val), (char *)(data->currentFH.nfs_fh4_val), data->currentFH.nfs_fh4_len); data->mounted_on_FH.nfs_fh4_len = data->currentFH.nfs_fh4_len; /* Keep the pointer within the compound data */ data->current_entry = file_pentry; data->current_filetype = file_pentry->internal_md.type; /* Return successfully */ res_LOOKUPP4.status = NFS4_OK; return NFS4_OK; } /* If the part of the code is reached, then something wrong occured in the lookup process, status is not HPSS_E_NOERROR * and contains the code for the error */ /* If NFS4ERR_SYMLINK should be returned for a symlink instead of ENOTDIR */ if((cache_status == CACHE_INODE_NOT_A_DIRECTORY) && (dir_pentry->internal_md.type == SYMBOLIC_LINK)) res_LOOKUPP4.status = NFS4ERR_SYMLINK; else res_LOOKUPP4.status = nfs4_Errno(cache_status); return res_LOOKUPP4.status; } /* nfs4_op_lookupp */