Пример #1
0
/**
 * @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;
}
Пример #2
0
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 */
}
Пример #3
0
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;
}