int nfs_Remove(nfs_arg_t *parg, exportlist_t *pexport, fsal_op_context_t *pcontext, nfs_worker_data_t *pworker, struct svc_req *preq, nfs_res_t *pres) { cache_entry_t *parent_pentry = NULL; cache_entry_t *pentry_child = NULL; fsal_attrib_list_t pre_parent_attr; fsal_attrib_list_t pentry_child_attr; fsal_attrib_list_t parent_attr; fsal_attrib_list_t *pparent_attr = NULL; cache_inode_file_type_t filetype; cache_inode_file_type_t childtype; cache_inode_status_t cache_status; char *file_name = NULL; fsal_name_t name; int rc = NFS_REQ_OK; if(isDebug(COMPONENT_NFSPROTO)) { char str[LEN_FH_STR]; switch (preq->rq_vers) { case NFS_V2: file_name = parg->arg_remove2.name; break; case NFS_V3: file_name = parg->arg_remove3.object.name; break; } nfs_FhandleToStr(preq->rq_vers, &(parg->arg_create2.where.dir), &(parg->arg_create3.where.dir), NULL, str); LogDebug(COMPONENT_NFSPROTO, "REQUEST PROCESSING: Calling nfs_Remove handle: %s name: %s", str, file_name); } if(preq->rq_vers == NFS_V3) { /* to avoid setting it on each error case */ pres->res_remove3.REMOVE3res_u.resfail.dir_wcc.before.attributes_follow = FALSE; pres->res_remove3.REMOVE3res_u.resfail.dir_wcc.after.attributes_follow = FALSE; pparent_attr = NULL; } /* Convert file handle into a pentry */ if((parent_pentry = nfs_FhandleToCache(preq->rq_vers, &(parg->arg_remove2.dir), &(parg->arg_remove3.object.dir), NULL, &(pres->res_dirop2.status), &(pres->res_remove3.status), NULL, &pre_parent_attr, pcontext, &rc)) == NULL) { /* Stale NFS FH ? */ goto out; } if((preq->rq_vers == NFS_V3) && (nfs3_Is_Fh_Xattr(&(parg->arg_remove3.object.dir)))) { rc = nfs3_Remove_Xattr(parg, pexport, pcontext, preq, pres); goto out; } /* get directory attributes before action (for V3 reply) */ pparent_attr = &pre_parent_attr; /* Extract the filetype */ filetype = cache_inode_fsal_type_convert(pre_parent_attr.type); /* * Sanity checks: new directory name must be non-null; parent must be * a directory. */ if(filetype != DIRECTORY) { switch (preq->rq_vers) { case NFS_V2: pres->res_stat2 = NFSERR_NOTDIR; break; case NFS_V3: pres->res_remove3.status = NFS3ERR_NOTDIR; break; } rc = NFS_REQ_OK; goto out; } switch (preq->rq_vers) { case NFS_V2: file_name = parg->arg_remove2.name; break; case NFS_V3: file_name = parg->arg_remove3.object.name; break; } //if(file_name == NULL || strlen(file_name) == 0) if(file_name == NULL || *file_name == '\0' ) { cache_status = CACHE_INODE_INVALID_ARGUMENT; /* for lack of better... */ } else { if((cache_status = cache_inode_error_convert(FSAL_str2name(file_name, 0, &name))) == CACHE_INODE_SUCCESS) { /* * Lookup to the child entry to check if it is a directory * */ if((pentry_child = cache_inode_lookup(parent_pentry, &name, &pentry_child_attr, pcontext, &cache_status)) != NULL) { /* Extract the filetype */ childtype = cache_inode_fsal_type_convert(pentry_child_attr.type); /* * Sanity check: make sure we are about to remove a directory */ if(childtype == DIRECTORY) { switch (preq->rq_vers) { case NFS_V2: pres->res_stat2 = NFSERR_ISDIR; break; case NFS_V3: pres->res_remove3.status = NFS3ERR_ISDIR; break; } rc = NFS_REQ_OK; goto out; } LogFullDebug(COMPONENT_NFSPROTO, "==== NFS REMOVE ====> Trying to remove file %s", name.name); /* * Remove the entry. */ if(cache_inode_remove(parent_pentry, &name, &parent_attr, pcontext, &cache_status) == CACHE_INODE_SUCCESS) { switch (preq->rq_vers) { case NFS_V2: pres->res_stat2 = NFS_OK; break; case NFS_V3: /* Build Weak Cache Coherency data */ nfs_SetWccData(pexport, pparent_attr, &parent_attr, &(pres->res_remove3.REMOVE3res_u.resok.dir_wcc)); pres->res_remove3.status = NFS3_OK; break; } rc = NFS_REQ_OK; goto out; } } } } /* If we are here, there was an error */ rc = nfs_SetFailedStatus(pexport, preq->rq_vers, cache_status, &pres->res_stat2, &pres->res_remove3.status, NULL, pparent_attr, &(pres->res_remove3.REMOVE3res_u.resfail.dir_wcc), NULL, NULL); out: /* return references */ if (pentry_child) cache_inode_put(pentry_child); if (parent_pentry) cache_inode_put(parent_pentry); return (rc); } /* nfs_Remove */
int nfs4_op_remove(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp) { cache_entry_t *parent_entry = NULL; fsal_attrib_list_t attr_parent; fsal_name_t name; cache_inode_status_t cache_status; #ifdef _USE_PNFS pnfs_file_t pnfs_file; #endif char __attribute__ ((__unused__)) funcname[] = "nfs4_op_remove"; resp->resop = NFS4_OP_REMOVE; res_REMOVE4.status = NFS4_OK; /* If there is no FH */ if(nfs4_Is_Fh_Empty(&(data->currentFH))) { res_REMOVE4.status = NFS4ERR_NOFILEHANDLE; return res_REMOVE4.status; } /* If the filehandle is invalid */ if(nfs4_Is_Fh_Invalid(&(data->currentFH))) { res_REMOVE4.status = NFS4ERR_BADHANDLE; return res_REMOVE4.status; } /* Tests if the Filehandle is expired (for volatile filehandle) */ if(nfs4_Is_Fh_Expired(&(data->currentFH))) { res_REMOVE4.status = NFS4ERR_FHEXPIRED; return res_REMOVE4.status; } /* Pseudo Fs is explictely a Read-Only File system */ if(nfs4_Is_Fh_Pseudo(&(data->currentFH))) { res_REMOVE4.status = NFS4ERR_ROFS; return res_REMOVE4.status; } /* If Filehandle points to a xattr object, manage it via the xattrs specific functions */ if(nfs4_Is_Fh_Xattr(&(data->currentFH))) return nfs4_op_remove_xattr(op, data, resp); /* Get the parent entry (aka the current one in the compound data) */ parent_entry = data->current_entry; /* We have to keep track of the 'change' file attribute for reply structure */ memset(&(res_REMOVE4.REMOVE4res_u.resok4.cinfo.before), 0, sizeof(changeid4)); res_REMOVE4.REMOVE4res_u.resok4.cinfo.before = (changeid4) parent_entry->internal_md.mod_time; /* The operation delete object named arg_REMOVE4.target in directory pointed bt cuurentFH */ /* Make sur the currentFH is pointed a directory */ if(data->current_filetype != DIR_BEGINNING && data->current_filetype != DIR_CONTINUE) { res_REMOVE4.status = NFS4ERR_NOTDIR; return res_REMOVE4.status; } /* Check for name length */ if(arg_REMOVE4.target.utf8string_len > FSAL_MAX_NAME_LEN) { res_REMOVE4.status = NFS4ERR_NAMETOOLONG; return res_REMOVE4.status; } /* get the filename from the argument, it should not be empty */ if(arg_REMOVE4.target.utf8string_len == 0) { res_REMOVE4.status = NFS4ERR_INVAL; return res_REMOVE4.status; } /* NFS4_OP_REMOVE can delete files as well as directory, it replaces NFS3_RMDIR and NFS3_REMOVE * because of this, we have to know if object is a directory or not */ if((cache_status = cache_inode_error_convert(FSAL_buffdesc2name ((fsal_buffdesc_t *) & arg_REMOVE4.target, &name))) != CACHE_INODE_SUCCESS) { res_REMOVE4.status = nfs4_Errno(cache_status); return res_REMOVE4.status; } /* Test RM7: remiving '.' should return NFS4ERR_BADNAME */ if(!FSAL_namecmp(&name, (fsal_name_t *) & FSAL_DOT) || !FSAL_namecmp(&name, (fsal_name_t *) & FSAL_DOT_DOT)) { res_REMOVE4.status = NFS4ERR_BADNAME; return res_REMOVE4.status; } if((cache_status = cache_inode_remove(parent_entry, &name, &attr_parent, data->ht, data->pclient, data->pcontext, &cache_status)) != CACHE_INODE_SUCCESS) { res_REMOVE4.status = nfs4_Errno(cache_status); return res_REMOVE4.status; } /* We have to keep track of the 'change' file attribute for reply structure */ memset(&(res_REMOVE4.REMOVE4res_u.resok4.cinfo.before), 0, sizeof(changeid4)); res_REMOVE4.REMOVE4res_u.resok4.cinfo.after = (changeid4) parent_entry->internal_md.mod_time; /* Operation was not atomic .... */ res_REMOVE4.REMOVE4res_u.resok4.cinfo.atomic = TRUE; /* If you reach this point, everything was ok */ res_REMOVE4.status = NFS4_OK; return NFS4_OK; } /* nfs4_op_remove */
int _9p_remove(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; /* Get data */ _9p_getptr(cursor, msgtag, u16); _9p_getptr(cursor, fid, u32); LogDebug(COMPONENT_9P, "TREMOVE: 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); if ((op_ctx->export_perms->options & EXPORT_OPTION_WRITE_ACCESS) == 0) return _9p_rerror(req9p, msgtag, EROFS, plenout, preply); cache_status = cache_inode_remove(pfid->ppentry, pfid->name); if (cache_status != CACHE_INODE_SUCCESS) return _9p_rerror(req9p, msgtag, _9p_tools_errno(cache_status), plenout, preply); /* If object is an opened file, close it */ if ((pfid->pentry->type == REGULAR_FILE) && is_open(pfid->pentry)) { if (pfid->opens) { cache_inode_dec_pin_ref(pfid->pentry, false); pfid->opens = 0; /* dead */ /* Under this flag, pin ref is still checked */ cache_status = cache_inode_close(pfid->pentry, CACHE_INODE_FLAG_REALLYCLOSE); if (cache_status != CACHE_INODE_SUCCESS) { FREE_FID(pfid, fid, req9p); return _9p_rerror(req9p, msgtag, _9p_tools_errno(cache_status), plenout, preply); } } } /* Clean the fid */ FREE_FID(pfid, fid, req9p); /* Build the reply */ _9p_setinitptr(cursor, preply, _9P_RREMOVE); _9p_setptr(cursor, msgtag, u16); _9p_setendptr(cursor, preply); _9p_checkbound(cursor, preply, plenout); LogDebug(COMPONENT_9P, "TREMOVE: tag=%u fid=%u", (u32) *msgtag, *fid); /* _9p_stat_update( *pmsgtype, TRUE, &pwkrdata->stats._9p_stat_req); */ return 1; }
int nfs3_rmdir(nfs_arg_t *arg, nfs_worker_data_t *worker, struct svc_req *req, nfs_res_t *res) { cache_entry_t *parent_entry = NULL; cache_entry_t *child_entry = NULL; pre_op_attr pre_parent = { .attributes_follow = false }; cache_inode_status_t cache_status; const char *name = arg->arg_rmdir3.object.name; int rc = NFS_REQ_OK; if (isDebug(COMPONENT_NFSPROTO)) { char str[LEN_FH_STR]; nfs_FhandleToStr(req->rq_vers, &arg->arg_rmdir3.object.dir, NULL, str); LogDebug(COMPONENT_NFSPROTO, "REQUEST PROCESSING: Calling nfs3_rmdir handle: %s " "name: %s", str, name); } /* Convert file handle into a pentry */ /* to avoid setting it on each error case */ res->res_rmdir3.RMDIR3res_u.resfail.dir_wcc.before.attributes_follow = FALSE; res->res_rmdir3.RMDIR3res_u.resfail.dir_wcc.after.attributes_follow = FALSE; parent_entry = nfs3_FhandleToCache(&arg->arg_rmdir3.object.dir, &res->res_rmdir3.status, &rc); if (parent_entry == NULL) { /* Status and rc have been set by nfs3_FhandleToCache */ goto out; } nfs_SetPreOpAttr(parent_entry, &pre_parent); /* Sanity checks: directory name must be non-null; parent * must be a directory. */ if (parent_entry->type != DIRECTORY) { res->res_rmdir3.status = NFS3ERR_NOTDIR; rc = NFS_REQ_OK; goto out; } if ((name == NULL) || (*name == '\0')) { cache_status = CACHE_INODE_INVALID_ARGUMENT; goto out_fail; } /* Lookup to the entry to be removed to check that it is a * directory */ cache_status = cache_inode_lookup(parent_entry, name, &child_entry); if (child_entry != NULL) { /* Sanity check: make sure we are about to remove a * directory */ if (child_entry->type != DIRECTORY) { res->res_rmdir3.status = NFS3ERR_NOTDIR; rc = NFS_REQ_OK; goto out; } } cache_status = cache_inode_remove(parent_entry, name); if (cache_status != CACHE_INODE_SUCCESS) goto out_fail; nfs_SetWccData(&pre_parent, parent_entry, &res->res_rmdir3.RMDIR3res_u.resok.dir_wcc); res->res_rmdir3.status = NFS3_OK; rc = NFS_REQ_OK; goto out; out_fail: res->res_rmdir3.status = nfs3_Errno(cache_status); nfs_SetWccData(&pre_parent, parent_entry, &res->res_rmdir3.RMDIR3res_u.resfail.dir_wcc); /* If we are here, there was an error */ if (nfs_RetryableError(cache_status)) rc = NFS_REQ_DROP; out: /* return references */ if (child_entry) cache_inode_put(child_entry); if (parent_entry) cache_inode_put(parent_entry); return rc; } /* nfs3_rmdir */ /** * @brief Free the result structure allocated for nfs3_rmdir * * This function frees the result structure allocated for nfs3_rmdir. * * @param[in,out] res Result structure * */ void nfs3_rmdir_free(nfs_res_t *res) { return; }
int _9p_unlinkat( _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 * dfid = NULL ; u16 * name_len = NULL ; char * name_str = NULL ; u32 * flags = NULL ; int rc = 0 ; u32 err = 0 ; _9p_fid_t * pdfid = NULL ; fsal_attrib_list_t fsalattr ; cache_inode_status_t cache_status ; fsal_name_t name ; if ( !preq9p || !pworker_data || !plenout || !preply ) return -1 ; /* Get data */ _9p_getptr( cursor, msgtag, u16 ) ; _9p_getptr( cursor, dfid, u32 ) ; _9p_getstr( cursor, name_len, name_str ) ; _9p_getptr( cursor, flags, u32 ) ; LogDebug( COMPONENT_9P, "TUNLINKAT: tag=%u dfid=%u name=%.*s", (u32)*msgtag, *dfid, *name_len, name_str ) ; if( *dfid >= _9P_FID_PER_CONN ) { err = ERANGE ; rc = _9p_rerror( preq9p, msgtag, &err, plenout, preply ) ; return rc ; } pdfid = &preq9p->pconn->fids[*dfid] ; /* Let's do the job */ snprintf( name.name, FSAL_MAX_NAME_LEN, "%.*s", *name_len, name_str ) ; if( cache_inode_remove( pdfid->pentry, &name, &fsalattr, pwkrdata->ht, &pwkrdata->cache_inode_client, &pdfid->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_RUNLINKAT ) ; _9p_setptr( cursor, msgtag, u16 ) ; _9p_setendptr( cursor, preply ) ; _9p_checkbound( cursor, preply, plenout ) ; LogDebug( COMPONENT_9P, "TUNLINKAT: tag=%u dfid=%u name=%.*s", (u32)*msgtag, *dfid, *name_len, name_str ) ; return 1 ; }
int nfs4_op_remove(struct nfs_argop4 *op, compound_data_t * data, struct nfs_resop4 *resp) { char __attribute__ ((__unused__)) funcname[] = "nfs4_op_remove"; cache_entry_t * parent_entry = NULL; fsal_attrib_list_t attr_parent; fsal_name_t name; cache_inode_status_t cache_status; resp->resop = NFS4_OP_REMOVE; res_REMOVE4.status = NFS4_OK; /* * Do basic checks on a filehandle * Delete arg_REMOVE4.target in directory pointed by currentFH * Make sure the currentFH is pointed a directory */ res_REMOVE4.status = nfs4_sanity_check_FH(data, DIRECTORY); if(res_REMOVE4.status != NFS4_OK) return res_REMOVE4.status; /* Pseudo Fs is explictely a Read-Only File system */ if(nfs4_Is_Fh_Pseudo(&(data->currentFH))) { res_REMOVE4.status = NFS4ERR_ROFS; return res_REMOVE4.status; } if (nfs_in_grace()) { res_REMOVE4.status = NFS4ERR_GRACE; return res_REMOVE4.status; } /* If Filehandle points to a xattr object, manage it via the xattrs specific functions */ if(nfs4_Is_Fh_Xattr(&(data->currentFH))) return nfs4_op_remove_xattr(op, data, resp); /* Get the parent entry (aka the current one in the compound data) */ parent_entry = data->current_entry; /* We have to keep track of the 'change' file attribute for reply structure */ memset(&(res_REMOVE4.REMOVE4res_u.resok4.cinfo.before), 0, sizeof(changeid4)); res_REMOVE4.REMOVE4res_u.resok4.cinfo.before = cache_inode_get_changeid4(parent_entry); /* Check for name length */ if(arg_REMOVE4.target.utf8string_len > FSAL_MAX_NAME_LEN) { res_REMOVE4.status = NFS4ERR_NAMETOOLONG; return res_REMOVE4.status; } /* get the filename from the argument, it should not be empty */ if(arg_REMOVE4.target.utf8string_len == 0) { res_REMOVE4.status = NFS4ERR_INVAL; return res_REMOVE4.status; } /* NFS4_OP_REMOVE can delete files as well as directory, it replaces NFS3_RMDIR and NFS3_REMOVE * because of this, we have to know if object is a directory or not */ if((cache_status = cache_inode_error_convert(FSAL_buffdesc2name ((fsal_buffdesc_t *) & arg_REMOVE4.target, &name))) != CACHE_INODE_SUCCESS) { res_REMOVE4.status = nfs4_Errno(cache_status); return res_REMOVE4.status; } /* Test RM7: remiving '.' should return NFS4ERR_BADNAME */ if(!FSAL_namecmp(&name, (fsal_name_t *) & FSAL_DOT) || !FSAL_namecmp(&name, (fsal_name_t *) & FSAL_DOT_DOT)) { res_REMOVE4.status = NFS4ERR_BADNAME; return res_REMOVE4.status; } if((cache_status = cache_inode_remove(parent_entry, &name, &attr_parent, data->pcontext, &cache_status)) != CACHE_INODE_SUCCESS) { res_REMOVE4.status = nfs4_Errno(cache_status); return res_REMOVE4.status; } res_REMOVE4.REMOVE4res_u.resok4.cinfo.after = cache_inode_get_changeid4(parent_entry); /* Operation was not atomic .... */ res_REMOVE4.REMOVE4res_u.resok4.cinfo.atomic = FALSE; /* If you reach this point, everything was ok */ res_REMOVE4.status = NFS4_OK; return NFS4_OK; } /* nfs4_op_remove */
int _9p_unlinkat(struct _9p_request_data *req9p, void *worker_data, u32 *plenout, char *preply) { char *cursor = req9p->_9pmsg + _9P_HDR_SIZE + _9P_TYPE_SIZE; u16 *msgtag = NULL; u32 *dfid = NULL; u16 *name_len = NULL; char *name_str = NULL; __attribute__ ((unused)) u32 *flags = NULL; struct _9p_fid *pdfid = NULL; cache_inode_status_t cache_status; char name[MAXNAMLEN]; /* Get data */ _9p_getptr(cursor, msgtag, u16); _9p_getptr(cursor, dfid, u32); _9p_getstr(cursor, name_len, name_str); _9p_getptr(cursor, flags, u32); LogDebug(COMPONENT_9P, "TUNLINKAT: tag=%u dfid=%u name=%.*s", (u32) *msgtag, *dfid, *name_len, name_str); if (*dfid >= _9P_FID_PER_CONN) return _9p_rerror(req9p, worker_data, msgtag, ERANGE, plenout, preply); pdfid = req9p->pconn->fids[*dfid]; /* Check that it is a valid fid */ if (pdfid == NULL || pdfid->pentry == NULL) { LogDebug(COMPONENT_9P, "request on invalid fid=%u", *dfid); return _9p_rerror(req9p, worker_data, msgtag, EIO, plenout, preply); } if ((pdfid->op_context.export_perms->options & EXPORT_OPTION_WRITE_ACCESS) == 0) return _9p_rerror(req9p, worker_data, msgtag, EROFS, plenout, preply); op_ctx = &pdfid->op_context; /* Let's do the job */ snprintf(name, MAXNAMLEN, "%.*s", *name_len, name_str); cache_status = cache_inode_remove(pdfid->pentry, name); if (cache_status != CACHE_INODE_SUCCESS) return _9p_rerror(req9p, worker_data, msgtag, _9p_tools_errno(cache_status), plenout, preply); /* Build the reply */ _9p_setinitptr(cursor, preply, _9P_RUNLINKAT); _9p_setptr(cursor, msgtag, u16); _9p_setendptr(cursor, preply); _9p_checkbound(cursor, preply, plenout); LogDebug(COMPONENT_9P, "TUNLINKAT: tag=%u dfid=%u name=%.*s", (u32) *msgtag, *dfid, *name_len, name_str); return 1; }
int nfs4_op_remove(struct nfs_argop4 *op, compound_data_t *data, struct nfs_resop4 *resp) { REMOVE4args * const arg_REMOVE4 = &op->nfs_argop4_u.opremove; REMOVE4res * const res_REMOVE4 = &resp->nfs_resop4_u.opremove; cache_entry_t *parent_entry = NULL; char *name = NULL; cache_inode_status_t cache_status = CACHE_INODE_SUCCESS; resp->resop = NFS4_OP_REMOVE; res_REMOVE4->status = NFS4_OK; /* Do basic checks on a filehandle * Delete arg_REMOVE4.target in directory pointed by currentFH * Make sure the currentFH is pointed a directory */ res_REMOVE4->status = nfs4_sanity_check_FH(data, DIRECTORY, false); if (res_REMOVE4->status != NFS4_OK) goto out; /* Validate and convert the UFT8 target to a regular string */ res_REMOVE4->status = nfs4_utf8string2dynamic(&arg_REMOVE4->target, UTF8_SCAN_ALL, &name); if (res_REMOVE4->status != NFS4_OK) goto out; if (nfs_in_grace()) { res_REMOVE4->status = NFS4ERR_GRACE; goto out; } /* Get the parent entry (aka the current one in the compound data) */ parent_entry = data->current_entry; /* We have to keep track of the 'change' file attribute * for reply structure */ memset(&res_REMOVE4->REMOVE4res_u.resok4.cinfo.before, 0, sizeof(changeid4)); res_REMOVE4->REMOVE4res_u.resok4.cinfo.before = cache_inode_get_changeid4(parent_entry, data->req_ctx); cache_status = cache_inode_remove(parent_entry, name, data->req_ctx); if (cache_status != CACHE_INODE_SUCCESS) { res_REMOVE4->status = nfs4_Errno(cache_status); goto out; } res_REMOVE4->REMOVE4res_u.resok4.cinfo.after = cache_inode_get_changeid4(parent_entry, data->req_ctx); /* Operation was not atomic .... */ res_REMOVE4->REMOVE4res_u.resok4.cinfo.atomic = FALSE; /* If you reach this point, everything was ok */ res_REMOVE4->status = NFS4_OK; out: if (name) gsh_free(name); return res_REMOVE4->status; } /* nfs4_op_remove */
int nfs_Rename(nfs_arg_t * parg /* IN */ , exportlist_t * pexport /* IN */ , fsal_op_context_t * pcontext /* IN */ , cache_inode_client_t * pclient /* IN */ , hash_table_t * ht /* INOUT */ , struct svc_req *preq /* IN */ , nfs_res_t * pres /* OUT */ ) { static char __attribute__ ((__unused__)) funcName[] = "nfs_Rename"; char *str_entry_name = NULL; fsal_name_t entry_name; char *str_new_entry_name = NULL; fsal_name_t new_entry_name; cache_entry_t *pentry = NULL; cache_entry_t *new_pentry = NULL; cache_entry_t *parent_pentry = NULL; cache_entry_t *new_parent_pentry = NULL; cache_entry_t *should_not_exists = NULL; cache_entry_t *should_exists = NULL; cache_inode_status_t cache_status; int rc; fsal_attrib_list_t *ppre_attr; fsal_attrib_list_t pre_attr; fsal_attrib_list_t *pnew_pre_attr; fsal_attrib_list_t new_attr; fsal_attrib_list_t new_parent_attr; fsal_attrib_list_t attr; fsal_attrib_list_t tst_attr; cache_inode_file_type_t parent_filetype; cache_inode_file_type_t new_parent_filetype; if(preq->rq_vers == NFS_V3) { /* to avoid setting it on each error case */ pres->res_rename3.RENAME3res_u.resfail.fromdir_wcc.before.attributes_follow = FALSE; pres->res_rename3.RENAME3res_u.resfail.fromdir_wcc.after.attributes_follow = FALSE; pres->res_rename3.RENAME3res_u.resfail.todir_wcc.before.attributes_follow = FALSE; pres->res_rename3.RENAME3res_u.resfail.todir_wcc.after.attributes_follow = FALSE; ppre_attr = NULL; pnew_pre_attr = NULL; } /* Convert fromdir file handle into a cache_entry */ if((parent_pentry = nfs_FhandleToCache(preq->rq_vers, &(parg->arg_rename2.from.dir), &(parg->arg_rename3.from.dir), NULL, &(pres->res_dirop2.status), &(pres->res_create3.status), NULL, &pre_attr, pcontext, pclient, ht, &rc)) == NULL) { /* Stale NFS FH ? */ return rc; } /* Convert todir file handle into a cache_entry */ if((new_parent_pentry = nfs_FhandleToCache(preq->rq_vers, &(parg->arg_rename2.to.dir), &(parg->arg_rename3.to.dir), NULL, &(pres->res_dirop2.status), &(pres->res_create3.status), NULL, &new_parent_attr, pcontext, pclient, ht, &rc)) == NULL) { /* Stale NFS FH ? */ return rc; } /* get the attr pointers */ ppre_attr = &pre_attr; pnew_pre_attr = &new_parent_attr; /* Get the filetypes */ parent_filetype = cache_inode_fsal_type_convert(pre_attr.type); new_parent_filetype = cache_inode_fsal_type_convert(new_parent_attr.type); /* * Sanity checks: we must manage directories */ if((parent_filetype != DIR_BEGINNING && parent_filetype != DIR_CONTINUE) || (new_parent_filetype != DIR_BEGINNING && new_parent_filetype != DIR_CONTINUE)) { switch (preq->rq_vers) { case NFS_V2: pres->res_stat2 = NFSERR_NOTDIR; break; case NFS_V3: pres->res_rename3.status = NFS3ERR_NOTDIR; break; } return NFS_REQ_OK; } switch (preq->rq_vers) { case NFS_V2: str_entry_name = parg->arg_rename2.from.name; str_new_entry_name = parg->arg_rename2.to.name; break; case NFS_V3: str_entry_name = parg->arg_rename3.from.name; str_new_entry_name = parg->arg_rename3.to.name; break; } pentry = new_pentry = NULL; if(str_entry_name == NULL || strlen(str_entry_name) == 0 || str_new_entry_name == NULL || strlen(str_new_entry_name) == 0 || FSAL_IS_ERROR(FSAL_str2name(str_entry_name, FSAL_MAX_NAME_LEN, &entry_name)) || FSAL_IS_ERROR(FSAL_str2name(str_new_entry_name, FSAL_MAX_NAME_LEN, &new_entry_name))) { cache_status = CACHE_INODE_INVALID_ARGUMENT; } else { /* * Lookup file to see if new entry exists * */ should_not_exists = cache_inode_lookup(new_parent_pentry, &new_entry_name, &tst_attr, ht, pclient, pcontext, &cache_status); if(cache_status == CACHE_INODE_NOT_FOUND) { /* We need to lookup over the old entry also */ should_exists = cache_inode_lookup(parent_pentry, &entry_name, &tst_attr, ht, pclient, pcontext, &cache_status); /* Rename entry */ if(cache_status == CACHE_INODE_SUCCESS) cache_inode_rename(parent_pentry, &entry_name, new_parent_pentry, &new_entry_name, &attr, &new_attr, ht, pclient, pcontext, &cache_status); if(cache_status == CACHE_INODE_SUCCESS) { switch (preq->rq_vers) { case NFS_V2: pres->res_stat2 = NFS_OK; break; case NFS_V3: /* * Build Weak Cache Coherency * data */ nfs_SetWccData(pcontext, pexport, parent_pentry, ppre_attr, &attr, &(pres->res_rename3.RENAME3res_u.resok.fromdir_wcc)); nfs_SetWccData(pcontext, pexport, new_parent_pentry, pnew_pre_attr, &new_attr, &(pres->res_rename3.RENAME3res_u.resok.todir_wcc)); pres->res_rename3.status = NFS3_OK; break; } return NFS_REQ_OK; } } else { /* If name are the same (basically renaming a/file1 to a/file1, this is a non-erroneous situation to be managed */ if(new_parent_pentry == parent_pentry) { if(!FSAL_namecmp(&new_entry_name, &entry_name)) { /* trying to rename a file to himself, this is allowed */ cache_status = CACHE_INODE_SUCCESS; switch (preq->rq_vers) { case NFS_V2: pres->res_stat2 = NFS_OK; break; case NFS_V3: /* * Build Weak Cache Coherency * data */ nfs_SetWccData(pcontext, pexport, parent_pentry, ppre_attr, &attr, &(pres->res_rename3.RENAME3res_u.resok.fromdir_wcc)); nfs_SetWccData(pcontext, pexport, parent_pentry, ppre_attr, &attr, &(pres->res_rename3.RENAME3res_u.resok.todir_wcc)); pres->res_rename3.status = NFS3_OK; break; } return NFS_REQ_OK; } } /* New entry already exists. In this case (see RFC), entry should be compatible: Both are non-directories or * both are directories and 'todir' is empty. If compatible, old 'todir' entry is scratched, if not returns EEXISTS */ if(should_not_exists != NULL) { /* We need to lookup over the old entry also */ if((should_exists = cache_inode_lookup(parent_pentry, &entry_name, &tst_attr, ht, pclient, pcontext, &cache_status)) != NULL) { if(cache_inode_type_are_rename_compatible (should_exists, should_not_exists)) { /* Remove the old entry before renaming it */ if(cache_inode_remove(new_parent_pentry, &new_entry_name, &tst_attr, ht, pclient, pcontext, &cache_status) == CACHE_INODE_SUCCESS) { if(cache_inode_rename(parent_pentry, &entry_name, new_parent_pentry, &new_entry_name, &attr, &new_attr, ht, pclient, pcontext, &cache_status) == CACHE_INODE_SUCCESS) { /* trying to rename a file to himself, this is allowed */ switch (preq->rq_vers) { case NFS_V2: pres->res_stat2 = NFS_OK; break; case NFS_V3: /* * Build Weak Cache Coherency * data */ nfs_SetWccData(pcontext, pexport, parent_pentry, ppre_attr, &attr, &(pres->res_rename3.RENAME3res_u.resok. fromdir_wcc)); nfs_SetWccData(pcontext, pexport, parent_pentry, ppre_attr, &attr, &(pres->res_rename3.RENAME3res_u.resok. todir_wcc)); pres->res_rename3.status = NFS3_OK; break; } return NFS_REQ_OK; } } } } /* if( cache_inode_type_are_rename_compatible( should_exists, should_not_exists ) ) */ } /* if( ( should_exists = cache_inode_lookup( parent_pentry, .... */ /* If this point is reached, then destination object already exists with that name in the directory and types are not compatible, we should return that the file exists */ cache_status = CACHE_INODE_ENTRY_EXISTS; } /* if( should_not_exists != NULL ) */ } /* 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_stat2, &pres->res_rename3.status, NULL, NULL, parent_pentry, ppre_attr, &(pres->res_rename3.RENAME3res_u.resfail.fromdir_wcc), new_parent_pentry, pnew_pre_attr, &(pres->res_rename3.RENAME3res_u.resfail.todir_wcc)); return NFS_REQ_OK; } /* nfs_Rename */