/** * @brief Delete the unecessary directories from pseudo FS * * @param pseudopath [IN] full path of the node * @param entry [IN] cache entry for the last directory in the path * * If this entry is present is pseudo FSAL, and is unnecessary, then remove it. * Check recursively if the parent entry is needed. * * The pseudopath is deconstructed in place to create the subsequently shorter * pseudo paths. * * When called the first time, entry is the mount point of an export that has * been unmounted from the PseudoFS. By definition, it is NOT the root of a * PseudoFS. Also, the PseudoFS root filesystem is NOT mounted and thus this * function will not be called for it. The req_op_context references the * export for the PseudoFS entry is within. Note that the caller is * responsible for checking if it is an FSAL_PSEUDO export (we only clean up * directories in FSAL_PSEUDO filesystems). */ void cleanup_pseudofs_node(char *pseudopath, struct fsal_obj_handle *obj) { struct fsal_obj_handle *parent_obj; char *pos = pseudopath + strlen(pseudopath) - 1; char *name; fsal_status_t fsal_status; /* Strip trailing / from pseudopath */ while (*pos == '/') pos--; /* Replace first trailing / if any with NUL */ pos[1] = '\0'; /* Find the previous slash. * We will NEVER back up PAST the root, so no need to check * for walking off the beginning of the string. */ while (*pos != '/') pos--; /* Remember the element name for remove */ name = pos + 1; LogDebug(COMPONENT_EXPORT, "Checking if pseudo node %s is needed", pseudopath); fsal_status = fsal_lookupp(obj, &parent_obj, NULL); if (FSAL_IS_ERROR(fsal_status)) { /* Truncate the pseudopath to be the path to the parent */ *pos = '\0'; LogCrit(COMPONENT_EXPORT, "Could not find cache entry for parent directory %s", pseudopath); return; } fsal_status = fsal_remove(parent_obj, name); if (FSAL_IS_ERROR(fsal_status)) { LogCrit(COMPONENT_EXPORT, "Removing pseudo node %s failed with %s", pseudopath, msg_fsal_err(fsal_status.major)); goto out; } /* Before recursing the check the parent, get export lock for looking at * exp_root_obj so we can check if we have reached the root of * the mounted on export. */ PTHREAD_RWLOCK_rdlock(&op_ctx->ctx_export->lock); if (parent_obj == op_ctx->ctx_export->exp_root_obj) { LogDebug(COMPONENT_EXPORT, "Reached root of PseudoFS %s", op_ctx->ctx_export->pseudopath); PTHREAD_RWLOCK_unlock(&op_ctx->ctx_export->lock); goto out; } PTHREAD_RWLOCK_unlock(&op_ctx->ctx_export->lock); /* Truncate the pseudopath to be the path to the parent */ *pos = '\0'; /* check if the parent directory is needed */ cleanup_pseudofs_node(pseudopath, parent_obj); out: parent_obj->obj_ops.put_ref(parent_obj); return; }
int nfs3_remove(nfs_arg_t *arg, struct svc_req *req, nfs_res_t *res) { struct fsal_obj_handle *parent_obj = NULL; struct fsal_obj_handle *child_obj = NULL; pre_op_attr pre_parent = { .attributes_follow = false }; fsal_status_t fsal_status; const char *name = arg->arg_remove3.object.name; int rc = NFS_REQ_OK; if (isDebug(COMPONENT_NFSPROTO)) { char str[LEN_FH_STR]; nfs_FhandleToStr(req->rq_msg.cb_vers, &arg->arg_create3.where.dir, NULL, str); LogDebug(COMPONENT_NFSPROTO, "REQUEST PROCESSING: Calling nfs_Remove handle: %s name: %s", str, name); } /* Convert file handle into a pentry */ /* to avoid setting it on each error case */ res->res_remove3.REMOVE3res_u.resfail.dir_wcc.before.attributes_follow = FALSE; res->res_remove3.REMOVE3res_u.resfail.dir_wcc.after.attributes_follow = FALSE; parent_obj = nfs3_FhandleToCache(&arg->arg_remove3.object.dir, &res->res_remove3.status, &rc); if (parent_obj == NULL) { /* Status and rc have been set by nfs3_FhandleToCache */ goto out; } nfs_SetPreOpAttr(parent_obj, &pre_parent); /* Sanity checks: file name must be non-null; parent must be a * directory. */ if (parent_obj->type != DIRECTORY) { res->res_remove3.status = NFS3ERR_NOTDIR; rc = NFS_REQ_OK; goto out; } if (name == NULL || *name == '\0') { fsal_status = fsalstat(ERR_FSAL_INVAL, 0); goto out_fail; } /* Lookup the child entry to verify that it is not a directory */ fsal_status = fsal_lookup(parent_obj, name, &child_obj, NULL); if (!FSAL_IS_ERROR(fsal_status)) { /* Sanity check: make sure we are not removing a * directory */ if (child_obj->type == DIRECTORY) { res->res_remove3.status = NFS3ERR_ISDIR; rc = NFS_REQ_OK; goto out; } } LogFullDebug(COMPONENT_NFSPROTO, "Trying to remove file %s", name); /* Remove the entry. */ fsal_status = fsal_remove(parent_obj, name); if (FSAL_IS_ERROR(fsal_status)) goto out_fail; /* Build Weak Cache Coherency data */ nfs_SetWccData(&pre_parent, parent_obj, &res->res_remove3.REMOVE3res_u.resok.dir_wcc); res->res_remove3.status = NFS3_OK; rc = NFS_REQ_OK; goto out; out_fail: res->res_remove3.status = nfs3_Errno_status(fsal_status); nfs_SetWccData(&pre_parent, parent_obj, &res->res_remove3.REMOVE3res_u.resfail.dir_wcc); if (nfs_RetryableError(fsal_status.major)) rc = NFS_REQ_DROP; out: /* return references */ if (child_obj) child_obj->obj_ops.put_ref(child_obj); if (parent_obj) parent_obj->obj_ops.put_ref(parent_obj); return rc; } /* nfs3_remove */ /** * @brief Free the result structure allocated for nfs3_remove. * * This function frees the result structure allocated for nfs3_remove. * * @param[in,out] res Result structure * */ void nfs3_remove_free(nfs_res_t *res) { /* Nothing to do here */ }
int _9p_unlinkat(struct _9p_request_data *req9p, 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; /* flags are not used */ __attribute__ ((unused)) u32 *flags = NULL; struct _9p_fid *pdfid = NULL; fsal_status_t fsal_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, 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, msgtag, EIO, plenout, preply); } _9p_init_opctx(pdfid, req9p); if ((op_ctx->export_perms->options & EXPORT_OPTION_WRITE_ACCESS) == 0) return _9p_rerror(req9p, msgtag, EROFS, plenout, preply); /* Let's do the job */ snprintf(name, MAXNAMLEN, "%.*s", *name_len, name_str); fsal_status = fsal_remove(pdfid->pentry, name); if (FSAL_IS_ERROR(fsal_status)) return _9p_rerror(req9p, msgtag, _9p_tools_errno(fsal_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; }