Exemplo n.º 1
0
bool make_pseudofs_node(char *name, struct pseudofs_state *state)
{
	struct fsal_obj_handle *new_node = NULL;
	fsal_status_t fsal_status;
	bool retried = false;
	struct attrlist sattr;

retry:

	/* First, try to lookup the entry */
	fsal_status = fsal_lookup(state->obj, name, &new_node, NULL);

	if (!FSAL_IS_ERROR(fsal_status)) {
		/* Make sure new node is a directory */
		if (new_node->type != DIRECTORY) {
			LogCrit(COMPONENT_EXPORT,
				"BUILDING PSEUDOFS: Export_Id %d Path %s Pseudo Path %s LOOKUP %s is not a directory",
				state->export->export_id,
				state->export->fullpath,
				state->export->pseudopath,
				name);
			/* Release the reference on the new node */
			new_node->obj_ops.put_ref(new_node);
			return false;
		}

		LogDebug(COMPONENT_EXPORT,
			 "BUILDING PSEUDOFS: Parent %p entry %p %s FSAL %s already exists",
			 state->obj, new_node, name,
			 new_node->fsal->name);

		state->obj->obj_ops.put_ref(state->obj);
		/* Make new node the current node */
		state->obj = new_node;
		return true;
	}
Exemplo n.º 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 */
}
Exemplo n.º 3
0
static void open4_ex(OPEN4args *arg,
		     compound_data_t *data,
		     OPEN4res *res_OPEN4,
		     nfs_client_id_t *clientid,
		     state_owner_t *owner,
		     state_t **file_state,
		     bool *new_state)
{
	/* Parent directory in which to open the file. */
	struct fsal_obj_handle *parent = NULL;
	/* The entry we associated with the desired file before open. */
	struct fsal_obj_handle *file_obj = NULL;
	/* Indicator that file_obj came from lookup. */
	bool looked_up_file_obj = false;
	/* The in_obj to pass to fsal_open2. */
	struct fsal_obj_handle *in_obj = NULL;
	/* The entry open associated with the file. */
	struct fsal_obj_handle *out_obj = NULL;
	fsal_openflags_t openflags = 0;
	fsal_openflags_t old_openflags = 0;
	enum fsal_create_mode createmode = FSAL_NO_CREATE;
	/* The filename to create */
	char *filename = NULL;
	/* The supplied calim type */
	open_claim_type4 claim = arg->claim.claim;
	fsal_verifier_t verifier;
	struct attrlist sattr;
	/* Status for fsal calls */
	fsal_status_t status = {0, 0};
	/* The open state for the file */
	bool state_lock_held = false;

	/* Make sure the attributes are initialized */
	memset(&sattr, 0, sizeof(sattr));

	/* Make sure... */
	*file_state = NULL;
	*new_state = false;

	/* Pre-process the claim type */
	switch (claim) {
	case CLAIM_NULL:
		/* Check parent */
		parent = data->current_obj;
		in_obj = parent;

		/* Parent must be a directory */
		if (parent->type != DIRECTORY) {
			if (parent->type == SYMBOLIC_LINK) {
				res_OPEN4->status = NFS4ERR_SYMLINK;
				goto out;
			} else {
				res_OPEN4->status = NFS4ERR_NOTDIR;
				goto out;
			}
		}

		/* Validate and convert the utf8 filename */
		res_OPEN4->status =
		    nfs4_utf8string2dynamic(&arg->claim.open_claim4_u.file,
					    UTF8_SCAN_ALL, &filename);

		if (res_OPEN4->status != NFS4_OK)
			goto out;

		/* Set the createmode if appropriate) */
		if (arg->openhow.opentype == OPEN4_CREATE) {
			open4_ex_create_args(arg, data, res_OPEN4, verifier,
					     &createmode, &sattr);

			if (res_OPEN4->status != NFS4_OK)
				goto out;
		}

		status = fsal_lookup(parent, filename, &file_obj, NULL);

		if (!FSAL_IS_ERROR(status)) {
			/* Check create situations. */
			if (arg->openhow.opentype == OPEN4_CREATE) {
				if (createmode >= FSAL_EXCLUSIVE) {
					/* Could be a replay, need to continue.
					 */
					LogFullDebug(COMPONENT_STATE,
						     "EXCLUSIVE open with existing file %s",
						     filename);
				} else if (createmode == FSAL_GUARDED) {
					/* This will be a failure no matter'
					 * what.
					 */
					looked_up_file_obj = true;
					res_OPEN4->status = NFS4ERR_EXIST;
					goto out;
				} else {
					/* FSAL_UNCHECKED, may be a truncate
					 * and we need to pass in the case
					 * of fsal_reopen2 case.
					 */
					if (FSAL_TEST_MASK(sattr.valid_mask,
							   ATTR_SIZE) &&
					    sattr.filesize == 0) {
						LogFullDebug(COMPONENT_STATE,
							     "Truncate");
						openflags |= FSAL_O_TRUNC;
					}
				}
			}

			/* We found the file by lookup, discard the filename
			 * and remember that we found the entry by lookup.
			 */
			looked_up_file_obj = true;
			gsh_free(filename);
			filename = NULL;
		} else if (status.major != ERR_FSAL_NOENT ||
			   arg->openhow.opentype != OPEN4_CREATE) {
			/* A real error occurred */
			res_OPEN4->status = nfs4_Errno_status(status);
			goto out;
		}

		break;

		/* Both of these just use the current filehandle. */
	case CLAIM_PREVIOUS:
		owner->so_owner.so_nfs4_owner.so_confirmed = true;
		if (!nfs4_check_deleg_reclaim(clientid, &data->currentFH)) {
			/* It must have been revoked. Can't reclaim.*/
			LogInfo(COMPONENT_NFS_V4, "Can't reclaim delegation");
			res_OPEN4->status = NFS4ERR_RECLAIM_BAD;
			goto out;
		}
		openflags |= FSAL_O_RECLAIM;
		file_obj = data->current_obj;
		break;

	case CLAIM_FH:
		file_obj = data->current_obj;
		break;

	case CLAIM_DELEGATE_PREV:
		/* FIXME: Remove this when we have full support
		 * for CLAIM_DELEGATE_PREV and delegpurge operations
		 */
		res_OPEN4->status = NFS4ERR_NOTSUPP;
		goto out;

	case CLAIM_DELEGATE_CUR:
		res_OPEN4->status = open4_claim_deleg(arg, data);
		if (res_OPEN4->status != NFS4_OK)
			goto out;
		openflags |= FSAL_O_RECLAIM;
		file_obj = data->current_obj;
		break;

	default:
		LogFatal(COMPONENT_STATE,
			 "Programming error.  Invalid claim after check.");
	}

	if ((arg->share_access & OPEN4_SHARE_ACCESS_READ) != 0)
		openflags |= FSAL_O_READ;

	if ((arg->share_access & OPEN4_SHARE_ACCESS_WRITE) != 0)
		openflags |= FSAL_O_WRITE;

	if ((arg->share_deny & OPEN4_SHARE_DENY_READ) != 0)
		openflags |= FSAL_O_DENY_READ;

	if ((arg->share_deny & OPEN4_SHARE_DENY_WRITE) != 0)
		openflags |= FSAL_O_DENY_WRITE_MAND;

	/* Check if file_obj a REGULAR_FILE */
	if (file_obj != NULL && file_obj->type != REGULAR_FILE) {
		LogDebug(COMPONENT_NFS_V4,
			 "Wrong file type expected REGULAR_FILE actual %s",
			 object_file_type_to_str(file_obj->type));

		if (file_obj->type == DIRECTORY) {
			res_OPEN4->status = NFS4ERR_ISDIR;
		} else {
			/* All special nodes must return NFS4ERR_SYMLINK for
			 * proper client behavior per this linux-nfs post:
			 * http://marc.info/?l=linux-nfs&m=131342421825436&w=2
			 */
			res_OPEN4->status = NFS4ERR_SYMLINK;
		}

		goto out;
	}

	if (file_obj != NULL) {
		/* Go ahead and take the state lock now. */
		PTHREAD_RWLOCK_wrlock(&file_obj->state_hdl->state_lock);
		state_lock_held = true;
		in_obj = file_obj;

		/* Check if any existing delegations conflict with this open.
		 * Delegation recalls will be scheduled if there is a conflict.
		 */
		if (state_deleg_conflict(file_obj,
					  (arg->share_access &
					   OPEN4_SHARE_ACCESS_WRITE) != 0)) {
			res_OPEN4->status = NFS4ERR_DELAY;
			goto out;
		}

		/* Check if there is already a state for this entry and owner.
		 */
		*file_state = nfs4_State_Get_Obj(file_obj, owner);

		if (isFullDebug(COMPONENT_STATE) && *file_state != NULL) {
			char str[LOG_BUFF_LEN] = "\0";
			struct display_buffer dspbuf = {sizeof(str), str, str};

			display_stateid(&dspbuf, *file_state);

			LogFullDebug(COMPONENT_STATE,
				     "Found existing state %s",
				     str);
		}

		/* Check if open from another export */
		if (*file_state != NULL &&
		    !state_same_export(*file_state, op_ctx->ctx_export)) {
			LogEvent(COMPONENT_STATE,
				 "Lock Owner Export Conflict, Lock held for export %"
				 PRIu16" request for export %"PRIu16,
				 state_export_id(*file_state),
				 op_ctx->ctx_export->export_id);
			res_OPEN4->status = NFS4ERR_INVAL;
			goto out;
		}
	}

	/* If that did not succeed, allocate a state from the FSAL. */
	if (*file_state == NULL) {
		*file_state = op_ctx->fsal_export->exp_ops.alloc_state(
							op_ctx->fsal_export,
							STATE_TYPE_SHARE,
							NULL);

		/* Remember we allocated a new state */
		*new_state = true;

		/* We are ready to perform the open (with possible create).
		 * in_obj has been set to the file itself or the parent.
		 * filename is NULL if in_obj is the file itself.
		 *
		 * Permission check has been done on directory if appropriate,
		 * otherwise fsal_open2 will do a directory permission
		 * check.
		 *
		 * fsal_open2 handles the permission check on the file
		 * itself and also handles all the share reservation stuff.
		 *
		 * fsal_open2 returns with a ref on out_obj, which should be
		 * passed to the state.
		 */
		LogFullDebug(COMPONENT_STATE,
			     "Calling open2 for %s", filename);

		status = fsal_open2(in_obj,
				    *file_state,
				    openflags,
				    createmode,
				    filename,
				    &sattr,
				    verifier,
				    &out_obj,
				    NULL);

		if (FSAL_IS_ERROR(status)) {
			res_OPEN4->status = nfs4_Errno_status(status);
			goto out;
		}
	} else if (createmode >= FSAL_EXCLUSIVE) {
		/* We have an EXCLUSIVE create with an existing
		 * state. We still need to verify it, but no need
		 * to call reopen2.
		 */
		LogFullDebug(COMPONENT_STATE, "Calling verify2 ");

		status = fsal_verify2(file_obj, verifier);

		if (FSAL_IS_ERROR(status)) {
			res_OPEN4->status = nfs4_Errno_status(status);
			goto out;
		}

		/* We need an extra reference below. */
		file_obj->obj_ops->get_ref(file_obj);
	} else {
		old_openflags =
			file_obj->obj_ops->status2(file_obj, *file_state);

		/* Open upgrade */
		LogFullDebug(COMPONENT_STATE, "Calling reopen2");

		status = fsal_reopen2(file_obj, *file_state,
				      openflags | old_openflags,
				      false);

		if (FSAL_IS_ERROR(status)) {
			res_OPEN4->status = nfs4_Errno_status(status);
			goto out;
		}

		/* We need an extra reference below. */
		file_obj->obj_ops->get_ref(file_obj);
	}

	if (file_obj == NULL) {
		/* We have a new cache inode entry, take the state lock. */
		file_obj = out_obj;
		PTHREAD_RWLOCK_wrlock(&file_obj->state_hdl->state_lock);
		state_lock_held = true;
	}

	/* Now the state_lock is held for sure and we have an extra LRU
	 * reference to file_obj, which is the opened file.
	 */

	if (*new_state) {
		/* The state data to be added */
		union state_data candidate_data;
		/* Tracking data for the open state */
		struct state_refer refer, *p_refer = NULL;
		state_status_t state_status;

		candidate_data.share.share_access =
		    arg->share_access & OPEN4_SHARE_ACCESS_BOTH;
		candidate_data.share.share_deny = arg->share_deny;
		candidate_data.share.share_access_prev =
			(1 << candidate_data.share.share_access);
		candidate_data.share.share_deny_prev =
			(1 << candidate_data.share.share_deny);

		LogFullDebug(COMPONENT_STATE,
			     "Creating new state access=%x deny=%x access_prev=%x deny_prev=%x",
			     candidate_data.share.share_access,
			     candidate_data.share.share_deny,
			     candidate_data.share.share_access_prev,
			     candidate_data.share.share_deny_prev);

		/* Record the sequence info */
		if (data->minorversion > 0) {
			memcpy(refer.session,
			       data->session->session_id,
			       sizeof(sessionid4));
			refer.sequence = data->sequence;
			refer.slot = data->slot;
			p_refer = &refer;
		}

		/* We need to register this state now. */
		state_status = state_add_impl(file_obj,
					      STATE_TYPE_SHARE,
					      &candidate_data,
					      owner,
					      file_state,
					      p_refer);

		if (state_status != STATE_SUCCESS) {
			/* state_add_impl failure closed and freed state.
			 * file_state will also be NULL at this point. Also
			 * release the ref on file_obj, since the state add
			 * failed.
			 */
			file_obj->obj_ops->put_ref(file_obj);
			res_OPEN4->status = nfs4_Errno_state(state_status);
			*new_state = false;
			goto out;
		}

		glist_init(&(*file_state)->state_data.share.share_lockstates);
	}

	res_OPEN4->status = open4_create_fh(data, file_obj, true);

	if (res_OPEN4->status != NFS4_OK) {
		if (*new_state) {
			/* state_del_locked will close the file. */
			state_del_locked(*file_state);
			*file_state = NULL;
			*new_state = false;
		} else {
			/*Do an open downgrade to the old open flags */
			status = file_obj->obj_ops->reopen2(file_obj,
							   *file_state,
							   old_openflags);
			if (FSAL_IS_ERROR(status)) {
				LogCrit(COMPONENT_NFS_V4,
					"Failed to allocate handle, reopen2 failed with %s",
					fsal_err_txt(status));
			}

			/* Need to release the state_lock before the put_ref
			 * call.
			 */
			PTHREAD_RWLOCK_unlock(&file_obj->state_hdl->state_lock);
			state_lock_held = false;

			/* Release the extra LRU reference on file_obj. */
			file_obj->obj_ops->put_ref(file_obj);
			goto out;
		}
	}

	/* Since open4_create_fh succeeded the LRU reference to file_obj was
	 * consumed by data->current_obj.
	 */

	if (!(*new_state)) {
		LogFullDebug(COMPONENT_STATE,
			     "Open upgrade old access=%x deny=%x access_prev=%x deny_prev=%x",
			     (*file_state)->state_data.share.share_access,
			     (*file_state)->state_data.share.share_deny,
			     (*file_state)->state_data.share.share_access_prev,
			     (*file_state)->state_data.share.share_deny_prev);

		LogFullDebug(COMPONENT_STATE,
			     "Open upgrade to access=%x deny=%x",
			     arg->share_access,
			     arg->share_deny);

		/* Update share_access and share_deny */
		(*file_state)->state_data.share.share_access |=
			arg->share_access & OPEN4_SHARE_ACCESS_BOTH;

		(*file_state)->state_data.share.share_deny |=
			arg->share_deny;

		/* Update share_access_prev and share_deny_prev */
		(*file_state)->state_data.share.share_access_prev |=
			(1 << (arg->share_access & OPEN4_SHARE_ACCESS_BOTH));

		(*file_state)->state_data.share.share_deny_prev |=
			(1 << arg->share_deny);

		LogFullDebug(COMPONENT_STATE,
			     "Open upgrade new access=%x deny=%x access_prev=%x deny_prev=%x",
			     (*file_state)->state_data.share.share_access,
			     (*file_state)->state_data.share.share_deny,
			     (*file_state)->state_data.share.share_access_prev,
			     (*file_state)->state_data.share.share_deny_prev);
	}

	do_delegation(arg, res_OPEN4, data, owner, *file_state, clientid);
 out:

	/* Release the attributes (may release an inherited ACL) */
	fsal_release_attrs(&sattr);

	if (state_lock_held)
		PTHREAD_RWLOCK_unlock(&file_obj->state_hdl->state_lock);

	if (filename)
		gsh_free(filename);

	if (res_OPEN4->status != NFS4_OK) {
		/* Cleanup state on error */
		if (*new_state)
			(*file_state)
				->state_exp->exp_ops.free_state(
					(*file_state)->state_exp, *file_state);
		else if (*file_state != NULL)
			dec_state_t_ref(*file_state);
		*file_state = NULL;
	}

	if (looked_up_file_obj) {
		/* We got file_obj via lookup, we need to unref it. */
		file_obj->obj_ops->put_ref(file_obj);
	}
}
Exemplo n.º 4
0
/**
 * @brief Check delegation claims while opening a file
 *
 * This function implements the CLAIM_DELEGATE_CUR claim.
 *
 * @param[in]     arg   OPEN4 arguments
 * @param[in,out] data  Comopund's data
 */
static nfsstat4 open4_claim_deleg(OPEN4args *arg, compound_data_t *data)
{
	open_claim_type4 claim = arg->claim.claim;
	stateid4 *rcurr_state;
	struct fsal_obj_handle *obj_lookup;
	const utf8string *utfname;
	char *filename;
	fsal_status_t fsal_status;
	nfsstat4 status;
	state_t *found_state = NULL;

	if (!(op_ctx->fsal_export->exp_ops.fs_supports(
					op_ctx->fsal_export, fso_delegations_w)
	      || op_ctx->fsal_export->exp_ops.fs_supports(
					op_ctx->fsal_export, fso_delegations_r))
	      ) {
		LogDebug(COMPONENT_STATE,
			 "NFS4 OPEN returning NFS4ERR_NOTSUPP for CLAIM_DELEGATE");
		return NFS4ERR_NOTSUPP;
	}

	assert(claim == CLAIM_DELEGATE_CUR);
	utfname = &arg->claim.open_claim4_u.delegate_cur_info.file;
	rcurr_state =
		&arg->claim.open_claim4_u.delegate_cur_info.delegate_stateid;

	LogDebug(COMPONENT_NFS_V4, "file name: %.*s",
		 utfname->utf8string_len, utfname->utf8string_val);

	/* Check if filename is correct */
	status = nfs4_utf8string2dynamic(utfname, UTF8_SCAN_ALL, &filename);
	if (status != NFS4_OK) {
		LogDebug(COMPONENT_NFS_V4, "Invalid filename");
		return status;
	}

	/* Does a file with this name already exist ? */
	fsal_status = fsal_lookup(data->current_obj, filename,
				  &obj_lookup, NULL);

	if (FSAL_IS_ERROR(fsal_status)) {
		LogDebug(COMPONENT_NFS_V4, "%s lookup failed.", filename);
		gsh_free(filename);
		return nfs4_Errno_status(fsal_status);
	}
	gsh_free(filename);

	status = open4_create_fh(data, obj_lookup, false);
	if (status != NFS4_OK) {
		LogDebug(COMPONENT_NFS_V4, "open4_create_fh failed");
		return status;
	}

	found_state = nfs4_State_Get_Pointer(rcurr_state->other);

	if (found_state == NULL) {
		LogDebug(COMPONENT_NFS_V4,
			 "state not found with CLAIM_DELEGATE_CUR");
		return NFS4ERR_BAD_STATEID;
	} else {
		if (isFullDebug(COMPONENT_NFS_V4)) {
			char str[LOG_BUFF_LEN] = "\0";
			struct display_buffer dspbuf = {sizeof(str), str, str};

			display_stateid(&dspbuf, found_state);

			LogFullDebug(COMPONENT_NFS_V4,
				     "found matching %s", str);
		}
		dec_state_t_ref(found_state);
	}

	LogFullDebug(COMPONENT_NFS_V4, "done with CLAIM_DELEGATE_CUR");

	return NFS4_OK;
}
Exemplo n.º 5
0
bool open4_open_owner(struct nfs_argop4 *op, compound_data_t *data,
		      struct nfs_resop4 *res, nfs_client_id_t *clientid,
		      state_owner_t **owner)
{
	/* Shortcut to open args */
	OPEN4args * const arg_OPEN4 = &(op->nfs_argop4_u.opopen);
	/* Shortcut to open args */
	OPEN4res * const res_OPEN4 = &(res->nfs_resop4_u.opopen);
	/* The parsed-out name of the open owner */
	state_nfs4_owner_name_t owner_name;
	/* Indicates if the owner is new */
	bool_t isnew;
	/* Return value of FSAL operations */
	fsal_status_t status = {0, 0};
	struct fsal_obj_handle *obj_lookup = NULL;

	/* Is this open_owner known? If so, get it so we can use
	 * replay cache
	 */
	convert_nfs4_open_owner(&arg_OPEN4->owner, &owner_name);

	/* If this open owner is not known yet, allocate and set up a new one */
	*owner = create_nfs4_owner(&owner_name,
				   clientid,
				   STATE_OPEN_OWNER_NFSV4,
				   NULL,
				   0,
				   &isnew,
				   CARE_ALWAYS, data->minorversion != 0);

	LogStateOwner("Open: ", *owner);

	if (*owner == NULL) {
		res_OPEN4->status = NFS4ERR_RESOURCE;
		LogEvent(COMPONENT_STATE,
			 "NFS4 OPEN returning NFS4ERR_RESOURCE for CLAIM_NULL (could not create NFS4 Owner");
		return false;
	}

	/* Seqid checking is only proper for reused NFSv4.0 owner */
	if (isnew || (data->minorversion != 0))
		return true;

	if (arg_OPEN4->seqid == 0) {
		LogDebug(COMPONENT_STATE,
			 "Previously known open_owner is used with seqid=0, ask the client to confirm it again");
		(*owner)->so_owner.so_nfs4_owner.so_confirmed = false;
		return true;
	}

	/* Check for replay */
	if (Check_nfs4_seqid(*owner,
			     arg_OPEN4->seqid,
			     op,
			     data->current_obj,
			     res,
			     open_tag)) {
		/* No replay */
		return true;
	}

	/* Response is setup for us and LogDebug told what was
	 * wrong.
	 *
	 * Or if this is a seqid replay, find the file entry
	 * and update currentFH
	 */
	if (res_OPEN4->status == NFS4_OK) {
		utf8string *utfile;
		open_claim4 *oc = &arg_OPEN4->claim;
		char *filename;

		/* Load up CLAIM_DELEGATE_CUR file */

		switch (oc->claim) {
		case CLAIM_NULL:
			utfile = &oc->open_claim4_u.file;
			break;
		case CLAIM_DELEGATE_CUR:
			utfile = &oc->open_claim4_u.delegate_cur_info.file;
			break;
		case CLAIM_DELEGATE_PREV:
		default:
			return false;
		}
		/* Check if filename is correct */
		res_OPEN4->status = nfs4_utf8string2dynamic(
					utfile, UTF8_SCAN_ALL, &filename);

		if (res_OPEN4->status != NFS4_OK)
			return false;

		status = fsal_lookup(data->current_obj,
				     filename,
				     &obj_lookup,
				     NULL);

		gsh_free(filename);

		if (obj_lookup == NULL) {
			res_OPEN4->status = nfs4_Errno_status(status);
			return false;
		}
		res_OPEN4->status = open4_create_fh(data, obj_lookup, false);
	}

	return false;
}
Exemplo n.º 6
0
int nfs3_lookup(nfs_arg_t *arg, struct svc_req *req, nfs_res_t *res)
{
	struct fsal_obj_handle *obj_dir = NULL;
	struct fsal_obj_handle *obj_file = NULL;
	fsal_status_t fsal_status;
	char *name = NULL;
	int rc = NFS_REQ_OK;
	struct attrlist attrs;

	/* We have the option of not sending attributes, so set ATTR_RDATTR_ERR.
	 */
	fsal_prepare_attrs(&attrs, ATTRS_NFS3 | ATTR_RDATTR_ERR);

	if (isDebug(COMPONENT_NFSPROTO)) {
		char str[LEN_FH_STR];

		name = arg->arg_lookup3.what.name;

		nfs_FhandleToStr(req->rq_msg.cb_vers,
				 &(arg->arg_lookup3.what.dir),
				 NULL, str);
		LogDebug(COMPONENT_NFSPROTO,
			 "REQUEST PROCESSING: Calling nfs_Lookup handle: %s name: %s",
			 str, name);
	}

	/* to avoid setting it on each error case */
	res->res_lookup3.LOOKUP3res_u.resfail.dir_attributes.attributes_follow =
	    FALSE;

	obj_dir = nfs3_FhandleToCache(&arg->arg_lookup3.what.dir,
					&res->res_lookup3.status,
					&rc);

	if (obj_dir == NULL) {
		/* Status and rc have been set by nfs3_FhandleToCache */
		goto out;
	}

	name = arg->arg_lookup3.what.name;

	fsal_status = fsal_lookup(obj_dir, name, &obj_file, &attrs);

	if (FSAL_IS_ERROR(fsal_status)) {
		/* If we are here, there was an error */
		if (nfs_RetryableError(fsal_status.major)) {
			rc = NFS_REQ_DROP;
			goto out;
		}

		res->res_lookup3.status = nfs3_Errno_status(fsal_status);
		nfs_SetPostOpAttr(obj_dir,
				  &res->res_lookup3.LOOKUP3res_u.resfail.
					dir_attributes,
				  NULL);
	} else {
		/* Build FH */
		if (nfs3_FSALToFhandle(
			    true,
			    &res->res_lookup3.LOOKUP3res_u.resok.object,
			    obj_file,
			    op_ctx->ctx_export)) {
			/* Build entry attributes */
			nfs_SetPostOpAttr(obj_file,
					  &res->res_lookup3.LOOKUP3res_u.
						resok.obj_attributes,
					  &attrs);

			/* Build directory attributes */
			nfs_SetPostOpAttr(obj_dir,
					  &res->res_lookup3.
					     LOOKUP3res_u.resok.dir_attributes,
					  NULL);
			res->res_lookup3.status = NFS3_OK;
		} else {
			res->res_lookup3.status = NFS3ERR_BADHANDLE;
		}
	}

	rc = NFS_REQ_OK;

 out:

	/* Release the attributes. */
	fsal_release_attrs(&attrs);

	/* return references */
	if (obj_dir)
		obj_dir->obj_ops.put_ref(obj_dir);

	if (obj_file)
		obj_file->obj_ops.put_ref(obj_file);

	return rc;
}				/* nfs3_lookup */
Exemplo n.º 7
0
int nfs4_op_lookup(struct nfs_argop4 *op, compound_data_t *data,
		   struct nfs_resop4 *resp)
{
	/* Convenient alias for the arguments */
	LOOKUP4args * const arg_LOOKUP4 = &op->nfs_argop4_u.oplookup;
	/* Convenient alias for the response  */
	LOOKUP4res * const res_LOOKUP4 = &resp->nfs_resop4_u.oplookup;
	/* The name to look up */
	char *name = NULL;
	/* The directory in which to look up the name */
	struct fsal_obj_handle *dir_obj = NULL;
	/* The name found */
	struct fsal_obj_handle *file_obj = NULL;
	/* Status code from fsal */
	fsal_status_t status = {0, 0};

	resp->resop = NFS4_OP_LOOKUP;
	res_LOOKUP4->status = NFS4_OK;

	/* Do basic checks on a filehandle */
	res_LOOKUP4->status = nfs4_sanity_check_FH(data, DIRECTORY, false);
	if (res_LOOKUP4->status != NFS4_OK) {
		/* for some reason lookup is picky.  Just not being
		 * dir is not enough.  We want to know it is a symlink
		 */
		if (res_LOOKUP4->status == NFS4ERR_NOTDIR
		    && data->current_filetype == SYMBOLIC_LINK)
			res_LOOKUP4->status = NFS4ERR_SYMLINK;
		goto out;
	}

	/* Validate and convert the UFT8 objname to a regular string */
	res_LOOKUP4->status = nfs4_utf8string2dynamic(&arg_LOOKUP4->objname,
						      UTF8_SCAN_ALL,
						      &name);

	if (res_LOOKUP4->status != NFS4_OK)
		goto out;

	LogDebug(COMPONENT_NFS_V4, "name=%s", name);

	/* Do the lookup in the FSAL */
	file_obj = NULL;
	dir_obj = data->current_obj;

	/* Sanity check: dir_obj should be ACTUALLY a directory */

	status = fsal_lookup(dir_obj, name, &file_obj, NULL);
	if (FSAL_IS_ERROR(status)) {
		res_LOOKUP4->status = nfs4_Errno_status(status);
		goto out;
	}

	if (file_obj->type == DIRECTORY) {
		PTHREAD_RWLOCK_rdlock(&file_obj->state_hdl->state_lock);

		if (file_obj->state_hdl->dir.junction_export != NULL) {
			/* Handle junction */
			struct fsal_obj_handle *obj = NULL;

			/* Attempt to get a reference to the export across the
			 * junction.
			 */
			if (!export_ready(
				file_obj->state_hdl->dir.junction_export)) {
				/* If we could not get a reference, return
				 * stale.  Release state_lock
				 */
				LogDebug(COMPONENT_EXPORT,
					 "NFS4ERR_STALE on LOOKUP of %s", name);
				res_LOOKUP4->status = NFS4ERR_STALE;
				PTHREAD_RWLOCK_unlock(
					&file_obj->state_hdl->state_lock);
				goto out;
			}

			get_gsh_export_ref(
				file_obj->state_hdl->dir.junction_export);

			/* Release any old export reference */
			if (op_ctx->ctx_export != NULL)
				put_gsh_export(op_ctx->ctx_export);

			/* Stash the new export in the compound data. */
			op_ctx->ctx_export =
				file_obj->state_hdl->dir.junction_export;
			op_ctx->fsal_export = op_ctx->ctx_export->fsal_export;

			PTHREAD_RWLOCK_unlock(&file_obj->state_hdl->state_lock);
			/* Build credentials */
			res_LOOKUP4->status =
				nfs4_export_check_access(data->req);

			/* Test for access error (export should not be visible).
			 */
			if (res_LOOKUP4->status == NFS4ERR_ACCESS) {
				/* If return is NFS4ERR_ACCESS then this client
				 * doesn't have access to this export, return
				 * NFS4ERR_NOENT to hide it. It was not visible
				 * in READDIR response.
				 */
				LogDebug(COMPONENT_EXPORT,
					"NFS4ERR_ACCESS Hiding Export_Id %d Pseudo %s with NFS4ERR_NOENT",
					op_ctx->ctx_export->export_id,
					op_ctx->ctx_export->pseudopath);
				res_LOOKUP4->status = NFS4ERR_NOENT;
				goto out;
			}

			if (res_LOOKUP4->status == NFS4ERR_WRONGSEC) {
				/* LogInfo already documents why */
				goto out;
			}

			if (res_LOOKUP4->status != NFS4_OK) {
				/* Should never get here,
				 * nfs4_export_check_access can only return
				 * NFS4_OK, NFS4ERR_ACCESS or NFS4ERR_WRONGSEC.
				 */
				LogMajor(COMPONENT_EXPORT,
					"PSEUDO FS JUNCTION TRAVERSAL: Failed with %s for %s, id=%d",
					nfsstat4_to_str(res_LOOKUP4->status),
					op_ctx->ctx_export->pseudopath,
					op_ctx->ctx_export->export_id);
				goto out;
			}

			status = nfs_export_get_root_entry(op_ctx->ctx_export,
							   &obj);

			if (FSAL_IS_ERROR(status)) {
				LogMajor(COMPONENT_EXPORT,
					"PSEUDO FS JUNCTION TRAVERSAL: Failed to get root for %s, id=%d, status = %s",
					op_ctx->ctx_export->pseudopath,
					op_ctx->ctx_export->export_id,
					msg_fsal_err(status.major));

				res_LOOKUP4->status = nfs4_Errno_status(status);
				goto out;
			}

			LogDebug(COMPONENT_EXPORT,
				"PSEUDO FS JUNCTION TRAVERSAL: Crossed to %s, id=%d for name=%s",
				op_ctx->ctx_export->pseudopath,
				op_ctx->ctx_export->export_id, name);

			file_obj->obj_ops->put_ref(file_obj);
			file_obj = obj;
		} else {
			PTHREAD_RWLOCK_unlock(&file_obj->state_hdl->state_lock);
		}
	}

	/* Convert it to a file handle */
	if (!nfs4_FSALToFhandle(false, &data->currentFH, file_obj,
					op_ctx->ctx_export)) {
		res_LOOKUP4->status = NFS4ERR_SERVERFAULT;
		goto out;
	}

	/* Keep the pointer within the compound data */
	set_current_entry(data, file_obj);

	/* Put our ref */
	file_obj->obj_ops->put_ref(file_obj);
	file_obj = NULL;

	/* Return successfully */
	res_LOOKUP4->status = NFS4_OK;

 out:
	/* Release reference on file_obj if we didn't utilze it. */
	if (file_obj)
		file_obj->obj_ops->put_ref(file_obj);

	gsh_free(name);

	return res_LOOKUP4->status;
}				/* nfs4_op_lookup */