Exemple #1
0
static void open4_ex_create_args(OPEN4args *arg,
				 compound_data_t *data,
				 OPEN4res *res_OPEN4,
				 void *verifier,
				 enum fsal_create_mode *createmode,
				 struct attrlist *sattr)
{
	createhow4 *createhow = &arg->openhow.openflag4_u.how;
	fattr4 *arg_attrs = NULL;

	*createmode = nfs4_createmode_to_fsal(createhow->mode);

	if (createhow->mode == EXCLUSIVE4_1) {
		memcpy(verifier,
		       createhow->createhow4_u.ch_createboth.cva_verf,
		       sizeof(fsal_verifier_t));
	} else if (createhow->mode == EXCLUSIVE4) {
		memcpy(verifier,
		       createhow->createhow4_u.createverf,
		       sizeof(fsal_verifier_t));
	}

	/* Select the correct attributes */
	if (createhow->mode == GUARDED4 || createhow->mode == UNCHECKED4)
		arg_attrs = &createhow->createhow4_u.createattrs;
	else if (createhow->mode == EXCLUSIVE4_1)
		arg_attrs = &createhow->createhow4_u.ch_createboth.cva_attrs;

	if (arg_attrs != NULL) {
		/* Check if asked attributes are correct */
		if (!nfs4_Fattr_Supported(arg_attrs)) {
			res_OPEN4->status = NFS4ERR_ATTRNOTSUPP;
			return;
		}

		if (!nfs4_Fattr_Check_Access(arg_attrs, FATTR4_ATTR_WRITE)) {
			res_OPEN4->status = NFS4ERR_INVAL;
			return;
		}

		/* Convert the attributes */
		if (arg_attrs->attrmask.bitmap4_len != 0) {
			/* Convert fattr4 so nfs4_sattr */
			res_OPEN4->status =
			    nfs4_Fattr_To_FSAL_attr(sattr, arg_attrs, data);

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

		if (createhow->mode == EXCLUSIVE4_1) {
			/** @todo FSF: this needs to be corrected in case FSAL
			 *             uses different attributes for the
			 *             verifier.
			 */
			/* Check that we aren't trying to set the verifier
			 * attributes.
			 */
			if (FSAL_TEST_MASK(sattr->valid_mask, ATTR_ATIME) ||
			    FSAL_TEST_MASK(sattr->valid_mask, ATTR_MTIME)) {
				res_OPEN4->status = NFS4ERR_INVAL;
				return;
			}
		}

		/* If owner or owner_group are set, and the credential was
		 * squashed, then we must squash the set owner and owner_group.
		 */
		squash_setattr(sattr);
	}

	if (!(sattr->valid_mask & ATTR_MODE)) {
		/* Make sure mode is set, even for exclusive create. */
		sattr->mode = 0600;
		sattr->valid_mask |= ATTR_MODE;
	}
}
Exemple #2
0
int nfs4_op_setattr(struct nfs_argop4 *op, compound_data_t *data,
		    struct nfs_resop4 *resp)
{
	SETATTR4args * const arg_SETATTR4 = &op->nfs_argop4_u.opsetattr;
	SETATTR4res * const res_SETATTR4 = &resp->nfs_resop4_u.opsetattr;
	struct attrlist sattr;
	cache_inode_status_t cache_status = CACHE_INODE_SUCCESS;
	const char *tag = "SETATTR";
	state_t *state_found = NULL;
	state_t *state_open = NULL;
	cache_entry_t *entry = NULL;
	bool anonymous_started = false;

	resp->resop = NFS4_OP_SETATTR;
	res_SETATTR4->status = NFS4_OK;

	/* Do basic checks on a filehandle */
	res_SETATTR4->status = nfs4_sanity_check_FH(data, NO_FILE_TYPE, false);

	if (res_SETATTR4->status != NFS4_OK)
		return res_SETATTR4->status;

	/* Don't allow attribute change while we are in grace period.
	 * Required for delegation reclaims and may be needed for other
	 * reclaimable states as well.
	 */
	if (nfs_in_grace()) {
		res_SETATTR4->status = NFS4ERR_GRACE;
		return res_SETATTR4->status;
	}

	/* Get only attributes that are allowed to be read */
	if (!nfs4_Fattr_Check_Access
	    (&arg_SETATTR4->obj_attributes, FATTR4_ATTR_WRITE)) {
		res_SETATTR4->status = NFS4ERR_INVAL;
		return res_SETATTR4->status;
	}

	/* Ask only for supported attributes */
	if (!nfs4_Fattr_Supported(&arg_SETATTR4->obj_attributes)) {
		res_SETATTR4->status = NFS4ERR_ATTRNOTSUPP;
		return res_SETATTR4->status;
	}

	/* Convert the fattr4 in the request to a fsal sattr structure */
	res_SETATTR4->status =
		nfs4_Fattr_To_FSAL_attr(&sattr,
					&arg_SETATTR4->obj_attributes,
					data);

	if (res_SETATTR4->status != NFS4_OK)
		return res_SETATTR4->status;

	/* Trunc may change Xtime so we have to start with trunc and
	 * finish by the mtime and atime
	 */
	if ((FSAL_TEST_MASK(sattr.mask, ATTR_SIZE))
	     || (FSAL_TEST_MASK(sattr.mask, ATTR4_SPACE_RESERVED))) {
		/* Setting the size of a directory is prohibited */
		if (data->current_filetype == DIRECTORY) {
			res_SETATTR4->status = NFS4ERR_ISDIR;
			return res_SETATTR4->status;
		}

		/* Object should be a file */
		if (data->current_entry->type != REGULAR_FILE) {
			res_SETATTR4->status = NFS4ERR_INVAL;
			return res_SETATTR4->status;
		}

		entry = data->current_entry;

		/* Check stateid correctness and get pointer to state */
		res_SETATTR4->status =
		    nfs4_Check_Stateid(&arg_SETATTR4->stateid,
				       data->current_entry,
				       &state_found,
				       data,
				       STATEID_SPECIAL_ANY,
				       0,
				       false,
				       tag);

		if (res_SETATTR4->status != NFS4_OK)
			return res_SETATTR4->status;

		/* NB: After this point, if state_found == NULL, then
		 * the stateid is all-0 or all-1
		 */
		if (state_found != NULL) {
			switch (state_found->state_type) {
			case STATE_TYPE_SHARE:
				state_open = state_found;
				/* Note this causes an extra refcount, but it
				 * simplifies logic below.
				 */
				inc_state_t_ref(state_open);
				break;

			case STATE_TYPE_LOCK:
				state_open =
				    state_found->state_data.lock.openstate;
				inc_state_t_ref(state_open);
				break;

			case STATE_TYPE_DELEG:
				state_open = NULL;
				break;

			default:
				res_SETATTR4->status = NFS4ERR_BAD_STATEID;
				return res_SETATTR4->status;
			}

			/* This is a size operation, this means that
			 * the file MUST have been opened for writing
			 */
			if (state_open != NULL &&
			    (state_open->state_data.share.share_access &
			     OPEN4_SHARE_ACCESS_WRITE) == 0) {
				/* Bad open mode, return NFS4ERR_OPENMODE */
				res_SETATTR4->status = NFS4ERR_OPENMODE;
				return res_SETATTR4->status;
			}
		} else {
			/* Special stateid, no open state, check to
			 * see if any share conflicts
			 */
			state_open = NULL;

			/* Special stateid, no open state, check to see if
			 * any share conflicts The stateid is all-0 or all-1
			 */
			res_SETATTR4->status = nfs4_Errno_state(
				state_share_anonymous_io_start(
					entry,
					OPEN4_SHARE_ACCESS_WRITE,
					SHARE_BYPASS_NONE));

			if (res_SETATTR4->status != NFS4_OK)
				return res_SETATTR4->status;

			anonymous_started = true;
		}
	}

	const time_t S_NSECS = 1000000000UL;
	/* Set the atime and mtime (ctime is not setable) */

	/* A carry into seconds considered invalid */
	if (sattr.atime.tv_nsec >= S_NSECS) {
		res_SETATTR4->status = NFS4ERR_INVAL;
		goto done;
	}

	if (sattr.mtime.tv_nsec >= S_NSECS) {
		res_SETATTR4->status = NFS4ERR_INVAL;
		goto done;
	}

	/* If owner or owner_group are set, and the credential was
	 * squashed, then we must squash the set owner and owner_group.
	 */
	squash_setattr(&sattr);

	/* If a SETATTR comes with an open stateid, and size is being
	 * set, then the open MUST be for write (checked above), so
	 * is_open_write is simple at this stage, it's just a check that
	 * we have an open owner.
	 */
	cache_status = cache_inode_setattr(data->current_entry,
					   &sattr,
					   state_open != NULL);

	if (cache_status != CACHE_INODE_SUCCESS) {
		res_SETATTR4->status = nfs4_Errno(cache_status);
		goto done;
	}

	/* Set the replyed structure */
	res_SETATTR4->attrsset = arg_SETATTR4->obj_attributes.attrmask;

	/* Exit with no error */
	res_SETATTR4->status = NFS4_OK;

 done:

	if (anonymous_started)
		state_share_anonymous_io_done(entry, OPEN4_SHARE_ACCESS_WRITE);

	if (state_found != NULL)
		dec_state_t_ref(state_found);

	if (state_open != NULL)
		dec_state_t_ref(state_open);

	return res_SETATTR4->status;
}				/* nfs4_op_setattr */
Exemple #3
0
int nfs_Symlink(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)
{
  char *str_symlink_name = NULL;
  fsal_name_t symlink_name;
  char *str_target_path = NULL;
  cache_inode_create_arg_t create_arg;
  fsal_accessmode_t mode = 0777;
  cache_entry_t *symlink_pentry = NULL;
  cache_entry_t *parent_pentry;
  cache_inode_file_type_t parent_filetype;
  fsal_attrib_list_t parent_attr;
  fsal_attrib_list_t attr_symlink;
  fsal_attrib_list_t attributes_symlink;
  fsal_attrib_list_t attr_parent_after;
  fsal_attrib_list_t *ppre_attr;
  cache_inode_status_t cache_status;
  cache_inode_status_t cache_status_parent;
  fsal_handle_t *pfsal_handle;
  int rc = NFS_REQ_OK;
#ifdef _USE_QUOTA
  fsal_status_t fsal_status ;
#endif

  memset(&create_arg, 0, sizeof(create_arg));

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

      switch (preq->rq_vers)
        {
        case NFS_V2:
          str_symlink_name = parg->arg_symlink2.from.name;
          str_target_path = parg->arg_symlink2.to;
          break;
        case NFS_V3:
          str_symlink_name = parg->arg_symlink3.where.name;
          str_target_path = parg->arg_symlink3.symlink.symlink_data;
          break;
        }

      nfs_FhandleToStr(preq->rq_vers,
                       &(parg->arg_symlink2.from.dir),
                       &(parg->arg_symlink3.where.dir),
                       NULL,
                       str);
      LogDebug(COMPONENT_NFSPROTO,
               "REQUEST PROCESSING: Calling nfs_Symlink handle: %s name: %s target: %s",
               str, str_symlink_name, str_target_path);
    }

  if(preq->rq_vers == NFS_V3)
    {
      /* to avoid setting it on each error case */
      pres->res_symlink3.SYMLINK3res_u.resfail.dir_wcc.before.attributes_follow = FALSE;
      pres->res_symlink3.SYMLINK3res_u.resfail.dir_wcc.after.attributes_follow = FALSE;
      ppre_attr = NULL;
    }

  /* Convert directory file handle into a vnode */
  if((parent_pentry = nfs_FhandleToCache(preq->rq_vers,
                                         &(parg->arg_symlink2.from.dir),
                                         &(parg->arg_symlink3.where.dir),
                                         NULL,
                                         &(pres->res_stat2),
                                         &(pres->res_symlink3.status),
                                         NULL,
                                         &parent_attr,
                                         pcontext, &rc)) == NULL)
    {
      /* Stale NFS FH ? */
      goto out;;
    }

  /* get directory attributes before action (for V3 reply) */
  ppre_attr = &parent_attr;

  /* Extract the filetype */
  parent_filetype = cache_inode_fsal_type_convert(parent_attr.type);

  /*
   * Sanity checks: new directory name must be non-null; parent must be
   * a directory. 
   */
  if(parent_filetype != DIRECTORY)
    {
      switch (preq->rq_vers)
        {
        case NFS_V2:
          pres->res_stat2 = NFSERR_NOTDIR;
          break;

        case NFS_V3:
          pres->res_symlink3.status = NFS3ERR_NOTDIR;
          break;
        }

      rc = NFS_REQ_OK;
      goto out;
    }

#ifdef _USE_QUOTA
    /* if quota support is active, then we should check is the FSAL allows inode creation or not */
    fsal_status = FSAL_check_quota( pexport->fullpath, 
                                    FSAL_QUOTA_INODES,
                                    FSAL_OP_CONTEXT_TO_UID( pcontext ) ) ;
    if( FSAL_IS_ERROR( fsal_status ) )
     {

       switch (preq->rq_vers)
         {
           case NFS_V2:
             pres->res_stat2 = NFSERR_DQUOT ;
             break;

           case NFS_V3:
             pres->res_symlink3.status = NFS3ERR_DQUOT;
             break;
         }

       rc = NFS_REQ_OK;
       goto out;
     }
#endif /* _USE_QUOTA */


  switch (preq->rq_vers)
    {
    case NFS_V2:
      str_symlink_name = parg->arg_symlink2.from.name;
      str_target_path = parg->arg_symlink2.to;
      break;

    case NFS_V3:
      str_symlink_name = parg->arg_symlink3.where.name;
      str_target_path = parg->arg_symlink3.symlink.symlink_data;
      break;
    }

  if(str_symlink_name == NULL ||
     *str_symlink_name == '\0'||
     str_target_path == NULL  ||
     *str_target_path == '\0' ||
     FSAL_IS_ERROR(FSAL_str2name(str_symlink_name, 0, &symlink_name)) ||
     FSAL_IS_ERROR(FSAL_str2path(str_target_path, 0, &create_arg.link_content)))
    {
      cache_status = CACHE_INODE_INVALID_ARGUMENT;
    }
  else
    {
      /* Make the symlink */
      if((symlink_pentry = cache_inode_create(parent_pentry,
                                              &symlink_name,
                                              SYMBOLIC_LINK,
                                              mode,
                                              &create_arg,
                                              &attr_symlink,
                                              pcontext, &cache_status)) != NULL)
        {
          switch (preq->rq_vers)
            {
            case NFS_V2:
              pres->res_stat2 = NFS_OK;
              break;

            case NFS_V3:
              /* Build file handle */
              pfsal_handle = &symlink_pentry->handle;

              /* Some clients (like the Spec NFS benchmark) set attributes with the NFSPROC3_SYMLINK request */
              if(nfs3_Sattr_To_FSALattr(&attributes_symlink,
                                        &parg->arg_symlink3.symlink.symlink_attributes) == 0)
                {
                  pres->res_create3.status = NFS3ERR_INVAL;
                  rc = NFS_REQ_OK;
                  goto out;
                }

              /* Mode is managed above (in cache_inode_create), there is no need 
               * to manage it */
              if(attributes_symlink.asked_attributes & FSAL_ATTR_MODE)
                attributes_symlink.asked_attributes &= ~FSAL_ATTR_MODE;

              /* Some clients (like Solaris 10) try to set the size of the file to 0
               * at creation time. The FSAL create empty file, so we ignore this */
              if(attributes_symlink.asked_attributes & FSAL_ATTR_SIZE)
                attributes_symlink.asked_attributes &= ~FSAL_ATTR_SIZE;

              if(attributes_symlink.asked_attributes & FSAL_ATTR_SPACEUSED)
                attributes_symlink.asked_attributes &= ~FSAL_ATTR_SPACEUSED;

              /* If owner or owner_group are set, and the credential was
               * squashed, then we must squash the set owner and owner_group.
               */
              squash_setattr(&pworker->export_perms,
                             &pworker->user_credentials,
                             &attributes_symlink);

              /* Are there attributes to be set (additional to the mode) ? */
              if(attributes_symlink.asked_attributes != 0ULL &&
                 attributes_symlink.asked_attributes != FSAL_ATTR_MODE)
                {
                  /* A call to cache_inode_setattr is required */
                  if(cache_inode_setattr(symlink_pentry,
                                         &attributes_symlink,
                                         pcontext,
                                         FALSE,
                                         &cache_status) != CACHE_INODE_SUCCESS)
                    {
                      goto out_error;
                    }
                }

              if ((pres->res_symlink3.status =
                   (nfs3_AllocateFH(&pres->res_symlink3.SYMLINK3res_u
                                    .resok.obj.post_op_fh3_u.handle)))
                  != NFS3_OK) {
                   pres->res_symlink3.status = NFS3ERR_IO;
                   rc = NFS_REQ_OK;
                   goto out;
              }

              if(nfs3_FSALToFhandle
                 (&pres->res_symlink3.SYMLINK3res_u.resok.obj.post_op_fh3_u.handle,
                  pfsal_handle, pexport) == 0)
                {
                  gsh_free(pres->res_symlink3.SYMLINK3res_u.resok.obj.
                           post_op_fh3_u.handle.data.data_val);

                  pres->res_symlink3.status = NFS3ERR_BADHANDLE;
                  rc = NFS_REQ_OK;
                  goto out;
                }

              /* The the parent pentry attributes for building Wcc Data */
              if(cache_inode_getattr(parent_pentry,
                                     &attr_parent_after,
                                     pcontext,
                                     &cache_status_parent)
                 != CACHE_INODE_SUCCESS)
                {
                  gsh_free(pres->res_symlink3.SYMLINK3res_u.resok.obj.
                           post_op_fh3_u.handle.data.data_val);

                  pres->res_symlink3.status = NFS3ERR_BADHANDLE;
                  rc = NFS_REQ_OK;
                  goto out;
                }

              /* Set Post Op Fh3 structure */
              pres->res_symlink3.SYMLINK3res_u.resok.obj.handle_follows = TRUE;

              /* Build entry attributes */
              nfs_SetPostOpAttr(pexport,
                                &attr_symlink,
                                &(pres->res_symlink3.SYMLINK3res_u
                                  .resok.obj_attributes));

              /* Build Weak Cache Coherency data */
              nfs_SetWccData(pexport,
                             ppre_attr,
                             &attr_parent_after,
                             &(pres->res_symlink3.SYMLINK3res_u.resok.dir_wcc));

              pres->res_symlink3.status = NFS3_OK;
              break;
            }                   /* switch */

          rc = NFS_REQ_OK;
          goto out;
        }
    }

out_error:
  rc = nfs_SetFailedStatus(pexport, preq->rq_vers, cache_status,
                           &pres->res_stat2, &pres->res_symlink3.status,
                           NULL, ppre_attr,
                           &(pres->res_symlink3.SYMLINK3res_u.resfail.dir_wcc),
                           NULL, NULL);
out:
  /* return references */
  if (parent_pentry)
      cache_inode_put(parent_pentry);

  if (symlink_pentry)
      cache_inode_put(symlink_pentry);

  return (rc);

}                               /* nfs_Symlink */