Ejemplo n.º 1
0
/**
 *  @brief Create a regular file.
 *
 *  @param dir_hdl Handle of parent directory where the file is to be created.
 *  @param filename Pointer to the name of the file to be created.
 *  @param op_ctx Authentication context for the operation (user,...).
 *  @param accessmode Mode for the file to be created.
 *  @param gpfs_fh Pointer to the handle of the created file.
 *  @param fsal_attr Attributes of the created file.
 *  @return ERR_FSAL_NO_ERROR on success, otherwise error
 *
 */
fsal_status_t
GPFSFSAL_create(struct fsal_obj_handle *dir_hdl, const char *filename,
                const struct req_op_context *op_ctx, uint32_t accessmode,
                struct gpfs_file_handle *gpfs_fh, struct attrlist *fsal_attr)
{
    fsal_status_t status;
    mode_t unix_mode;

    /* note : fsal_attr is optional. */
    if (!dir_hdl || !op_ctx || !gpfs_fh || !filename)
        return fsalstat(ERR_FSAL_FAULT, 0);

    /* convert fsal mode to unix mode. */
    unix_mode = fsal2unix_mode(accessmode);

    /* Apply umask */
    unix_mode = unix_mode & ~op_ctx->fsal_export->exp_ops.
                fs_umask(op_ctx->fsal_export);

    LogFullDebug(COMPONENT_FSAL, "Creation mode: 0%o", accessmode);

    /* call to filesystem */

    fsal_set_credentials(op_ctx->creds);
    status = fsal_internal_create(dir_hdl, filename, unix_mode | S_IFREG,
                                  0, gpfs_fh, NULL);
    fsal_restore_ganesha_credentials();
    if (FSAL_IS_ERROR(status))
        return status;

    /* retrieve file attributes */
    return GPFSFSAL_getattrs(op_ctx->fsal_export, dir_hdl->fs->private_data,
                             op_ctx, gpfs_fh, fsal_attr);
}
Ejemplo n.º 2
0
/**
 * FSAL_mkdir:
 * Create a directory.
 *
 * \param parent_directory_handle (input):
 *        Handle of the parent directory where
 *        the subdirectory is to be created.
 * \param p_dirname (input):
 *        Pointer to the name of the directory to be created.
 * \param cred (input):
 *        Authentication context for the operation (user,...).
 * \param accessmode (input):
 *        Mode for the directory to be created.
 *        (the umask defined into the FSAL configuration file
 *        will be applied on it).
 * \param object_handle (output):
 *        Pointer to the handle of the created directory.
 * \param object_attributes (optionnal input/output): 
 *        The attributes of the created directory.
 *        As input, it defines the attributes that the caller
 *        wants to retrieve (by positioning flags into this structure)
 *        and the output is built considering this input
 *        (it fills the structure according to the flags it contains).
 *        May be NULL.
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - ERR_FSAL_STALE        (parent_directory_handle does not address an existing object)
 *        - ERR_FSAL_FAULT        (a NULL pointer was passed as mandatory argument)
 *        - Other error codes can be returned :
 *          ERR_FSAL_ACCESS, ERR_FSAL_EXIST, ERR_FSAL_IO, ...
 *            
 *        NB: if getting postop attributes failed,
 *        the function does not return an error
 *        but the FSAL_ATTR_RDATTR_ERR bit is set in
 *        the object_attributes->asked_attributes field.
 */
fsal_status_t ZFSFSAL_mkdir(zfsfsal_handle_t * parent_directory_handle,       /* IN */
                            fsal_name_t * p_dirname,       /* IN */
                            zfsfsal_op_context_t * p_context, /* IN */
                            fsal_accessmode_t accessmode,  /* IN */
                            zfsfsal_handle_t * object_handle, /* OUT */
                            fsal_attrib_list_t * object_attributes /* [ IN/OUT ] */
    )
{

  int rc;
  mode_t unix_mode;

  /* sanity checks.
   * note : object_attributes is optional.
   */
  if(!parent_directory_handle || !p_context || !object_handle || !p_dirname)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mkdir);

  /* convert fsal args to ZFS args */
  unix_mode = fsal2unix_mode(accessmode);


   /* Applying FSAL umask */
   unix_mode = unix_mode & ~global_fs_info.umask;

  TakeTokenFSCall();

  /* Create the directory */
  inogen_t object;
  rc = libzfswrap_mkdir(p_context->export_context->p_vfs, &p_context->user_credential.cred,
                        parent_directory_handle->data.zfs_handle, p_dirname->name, unix_mode, &object);

  ReleaseTokenFSCall();

  /* >> interpret returned error << */
  if(rc)
    Return(posix2fsal_error(rc), 0, INDEX_FSAL_create);

  /* set output handle */
  object_handle->data.zfs_handle = object;
  object_handle->data.type = FSAL_TYPE_DIR;

  if(object_attributes)
    {
      /**@TODO: skip this => libzfswrap_mkdir might return attributes */
      fsal_status_t status = ZFSFSAL_getattrs(object_handle, p_context, object_attributes);

      /* on error, we set a special bit in the mask. */
      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(object_attributes->asked_attributes);
          FSAL_SET_MASK(object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }

    }

  /* OK */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_mkdir);

}
Ejemplo n.º 3
0
/**
 * FSAL_create:
 * Create a regular file.
 *
 * \param parent_directory_handle (input):
 *        Handle of the parent directory where the file is to be created.
 * \param p_filename (input):
 *        Pointer to the name of the file to be created.
 * \param cred (input):
 *        Authentication context for the operation (user, export...).
 * \param accessmode (input):
 *        Mode for the file to be created.
 *        (the umask defined into the FSAL configuration file
 *        will be applied on it).
 * \param object_handle (output):
 *        Pointer to the handle of the created file.
 * \param object_attributes (optionnal input/output): 
 *        The postop attributes of the created file.
 *        As input, it defines the attributes that the caller
 *        wants to retrieve (by positioning flags into this structure)
 *        and the output is built considering this input
 *        (it fills the structure according to the flags it contains).
 *        Can be NULL.
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - ERR_FSAL_STALE        (parent_directory_handle does not address an existing object)
 *        - ERR_FSAL_FAULT        (a NULL pointer was passed as mandatory argument)
 *        - Other error codes can be returned :
 *          ERR_FSAL_ACCESS, ERR_FSAL_EXIST, ERR_FSAL_IO, ...
 *            
 *        NB: if getting postop attributes failed,
 *        the function does not return an error
 *        but the FSAL_ATTR_RDATTR_ERR bit is set in
 *        the object_attributes->asked_attributes field.
 */
fsal_status_t ZFSFSAL_create(zfsfsal_handle_t * parent_directory_handle,      /* IN */
                             fsal_name_t * p_filename,     /* IN */
                             zfsfsal_op_context_t * p_context,        /* IN */
                             fsal_accessmode_t accessmode, /* IN */
                             zfsfsal_handle_t * object_handle,        /* OUT */
                             fsal_attrib_list_t * object_attributes        /* [ IN/OUT ] */
    )
{

  int rc;

  /* sanity checks.
   * note : object_attributes is optional.
   */
  if(!parent_directory_handle || !p_context || !object_handle || !p_filename)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create);

  /* >> convert fsal args to your fs args.
   * Don't forget applying FSAL umask :
   * mode = mode & ~global_fs_info.umask << */

  TakeTokenFSCall();

  inogen_t object;
  rc = libzfswrap_create(p_context->export_context->p_vfs, &p_context->user_credential.cred,
                         parent_directory_handle->data.zfs_handle, p_filename->name,
                         fsal2unix_mode(accessmode), &object);

  ReleaseTokenFSCall();

  /* >> interpret returned error << */
  if(rc)
    Return(posix2fsal_error(rc), 0, INDEX_FSAL_create);

  /* >> set output handle << */
  object_handle->data.zfs_handle = object;
  object_handle->data.type = FSAL_TYPE_FILE;

  if(object_attributes)
    {
      fsal_status_t status = ZFSFSAL_getattrs(object_handle, p_context, object_attributes);

      /* on error, we set a special bit in the mask. */
      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(object_attributes->asked_attributes);
          FSAL_SET_MASK(object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }
    }

  /* OK */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_create);

}
Ejemplo n.º 4
0
/**
 *  @brief Create a directory.
 *
 *  @param dir_hdl Handle of the parent directory
 *  @param dir_name Pointer to the name of the directory to be created.
 *  @param op_ctx Authentication context for the operation (user,...).
 *  @param accessmode Mode for the directory to be created.
 *  @param gpfs_fh Pointer to the handle of the created directory.
 *  @param fsal_attr Attributes of the created directory.
 *  @return ERR_FSAL_NO_ERROR on success, error otherwise
 *
 */
fsal_status_t
GPFSFSAL_mkdir(struct fsal_obj_handle *dir_hdl, const char *dir_name,
               const struct req_op_context *op_ctx, uint32_t accessmode,
               struct gpfs_file_handle *gpfs_fh, struct attrlist *obj_attr)
{
    mode_t unix_mode;
    fsal_status_t status;

    /* note : obj_attr is optional. */
    if (!dir_hdl || !op_ctx || !gpfs_fh || !dir_name)
        return fsalstat(ERR_FSAL_FAULT, 0);

    /* convert FSAL mode to unix mode. */
    unix_mode = fsal2unix_mode(accessmode);

    /* Apply umask */
    unix_mode = unix_mode &
                ~op_ctx->fsal_export->exp_ops.fs_umask(op_ctx->fsal_export);

    /* build new entry path */

    /* creates the directory and get its handle */

    fsal_set_credentials(op_ctx->creds);
    status = fsal_internal_create(dir_hdl, dir_name, unix_mode | S_IFDIR,
                                  0, gpfs_fh, NULL);
    fsal_restore_ganesha_credentials();

    if (FSAL_IS_ERROR(status))
        return status;

    /* retrieve file attributes */
    return GPFSFSAL_getattrs(op_ctx->fsal_export,
                             dir_hdl->fs->private_data,
                             op_ctx, gpfs_fh, obj_attr);
}
Ejemplo n.º 5
0
fsal_status_t vfs_open2(struct fsal_obj_handle *obj_hdl,
			struct state_t *state,
			fsal_openflags_t openflags,
			enum fsal_create_mode createmode,
			const char *name,
			struct attrlist *attrib_set,
			fsal_verifier_t verifier,
			struct fsal_obj_handle **new_obj,
			struct attrlist *attrs_out,
			bool *caller_perm_check)
{
	int posix_flags = 0;
	int fd, dir_fd;
	int retval = 0;
	mode_t unix_mode;
	fsal_status_t status = {0, 0};
	struct vfs_fd *my_fd = NULL;
	struct vfs_fsal_obj_handle *myself, *hdl = NULL;
	struct stat stat;
	vfs_file_handle_t *fh = NULL;
	bool truncated;
	bool created = false;

	if (state != NULL)
		my_fd = (struct vfs_fd *)(state + 1);

	myself = container_of(obj_hdl, struct vfs_fsal_obj_handle, obj_handle);

	LogAttrlist(COMPONENT_FSAL, NIV_FULL_DEBUG,
		    "attrib_set ", attrib_set, false);

	fsal2posix_openflags(openflags, &posix_flags);

	truncated = (posix_flags & O_TRUNC) != 0;

	LogFullDebug(COMPONENT_FSAL,
		     truncated ? "Truncate" : "No truncate");

	if (createmode >= FSAL_EXCLUSIVE) {
		/* Now fixup attrs for verifier if exclusive create */
		set_common_verifier(attrib_set, verifier);
	}

	if (name == NULL) {
		/* This is an open by handle */
		struct vfs_fsal_obj_handle *myself;

		myself = container_of(obj_hdl,
				      struct vfs_fsal_obj_handle,
				      obj_handle);

		if (obj_hdl->fsal != obj_hdl->fs->fsal) {
			LogDebug(COMPONENT_FSAL,
				 "FSAL %s operation for handle belonging to FSAL %s, return EXDEV",
				 obj_hdl->fsal->name, obj_hdl->fs->fsal->name);
			return fsalstat(posix2fsal_error(EXDEV), EXDEV);
		}

		if (state != NULL) {
			/* Prepare to take the share reservation, but only if we
			 * are called with a valid state (if state is NULL the
			 * caller is a stateless create such as NFS v3 CREATE).
			 */

			/* This can block over an I/O operation. */
			PTHREAD_RWLOCK_wrlock(&obj_hdl->lock);

			/* Check share reservation conflicts. */
			status = check_share_conflict(&myself->u.file.share,
						      openflags,
						      false);

			if (FSAL_IS_ERROR(status)) {
				PTHREAD_RWLOCK_unlock(&obj_hdl->lock);
				return status;
			}

			/* Take the share reservation now by updating the
			 * counters.
			 */
			update_share_counters(&myself->u.file.share,
					      FSAL_O_CLOSED,
					      openflags);

			PTHREAD_RWLOCK_unlock(&obj_hdl->lock);
		} else {
			/* We need to use the global fd to continue, and take
			 * the lock to protect it.
			 */
			my_fd = &hdl->u.file.fd;
			PTHREAD_RWLOCK_wrlock(&obj_hdl->lock);
		}

		status = vfs_open_my_fd(myself, openflags, posix_flags, my_fd);

		if (FSAL_IS_ERROR(status)) {
			if (state == NULL) {
				/* Release the lock taken above, and return
				 * since there is nothing to undo.
				 */
				PTHREAD_RWLOCK_unlock(&obj_hdl->lock);
				return status;
			} else {
				/* Error - need to release the share */
				goto undo_share;
			}
		}

		if (createmode >= FSAL_EXCLUSIVE || truncated) {
			/* Refresh the attributes */
			struct stat stat;

			retval = fstat(my_fd->fd, &stat);

			if (retval == 0) {
				LogFullDebug(COMPONENT_FSAL,
					     "New size = %" PRIx64,
					     stat.st_size);
			} else {
				if (errno == EBADF)
					errno = ESTALE;
				status = fsalstat(posix2fsal_error(errno),
						  errno);
			}

			/* Now check verifier for exclusive, but not for
			 * FSAL_EXCLUSIVE_9P.
			 */
			if (!FSAL_IS_ERROR(status) &&
			    createmode >= FSAL_EXCLUSIVE &&
			    createmode != FSAL_EXCLUSIVE_9P &&
			    !check_verifier_stat(&stat, verifier)) {
				/* Verifier didn't match, return EEXIST */
				status =
				    fsalstat(posix2fsal_error(EEXIST), EEXIST);
			}
		}

		if (state == NULL) {
			/* If no state, release the lock taken above and return
			 * status.
			 */
			PTHREAD_RWLOCK_unlock(&obj_hdl->lock);
			return status;
		}

		if (!FSAL_IS_ERROR(status)) {
			/* Return success. */
			return status;
		}

		(void) vfs_close_my_fd(my_fd);

 undo_share:

		/* Can only get here with state not NULL and an error */

		/* On error we need to release our share reservation
		 * and undo the update of the share counters.
		 * This can block over an I/O operation.
		 */
		PTHREAD_RWLOCK_wrlock(&obj_hdl->lock);

		update_share_counters(&myself->u.file.share,
				      openflags,
				      FSAL_O_CLOSED);

		PTHREAD_RWLOCK_unlock(&obj_hdl->lock);

		return status;
	}

	/* In this path where we are opening by name, we can't check share
	 * reservation yet since we don't have an object_handle yet. If we
	 * indeed create the object handle (there is no race with another
	 * open by name), then there CAN NOT be a share conflict, otherwise
	 * the share conflict will be resolved when the object handles are
	 * merged.
	 */

#ifdef ENABLE_VFS_DEBUG_ACL
	if (createmode != FSAL_NO_CREATE) {
		/* Need to ammend attributes for inherited ACL, these will be
		 * set later. We also need to test for permission to create
		 * since there might be an ACL.
		 */
		struct attrlist attrs;
		fsal_accessflags_t access_type;

		access_type = FSAL_MODE_MASK_SET(FSAL_W_OK) |
			FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_ADD_FILE);
		status = obj_hdl->obj_ops.test_access(obj_hdl, access_type,
						      NULL, NULL, false);

		if (FSAL_IS_ERROR(status))
			return status;

		fsal_prepare_attrs(&attrs, ATTR_ACL);

		status = obj_hdl->obj_ops.getattrs(obj_hdl, &attrs);

		if (FSAL_IS_ERROR(status))
			return status;

		status.major = fsal_inherit_acls(attrib_set, attrs.acl,
						 FSAL_ACE_FLAG_FILE_INHERIT);

		/* Done with the attrs */
		fsal_release_attrs(&attrs);

		if (FSAL_IS_ERROR(status))
			return status;
	}
#endif /* ENABLE_VFS_DEBUG_ACL */

	if (createmode != FSAL_NO_CREATE) {
		/* Now add in O_CREAT and O_EXCL. */
		posix_flags |= O_CREAT;

		/* And if we are at least FSAL_GUARDED, do an O_EXCL create. */
		if (createmode >= FSAL_GUARDED)
			posix_flags |= O_EXCL;

		/* Fetch the mode attribute to use in the openat system call. */
		unix_mode = fsal2unix_mode(attrib_set->mode) &
		    ~op_ctx->fsal_export->exp_ops.fs_umask(op_ctx->fsal_export);

		/* Don't set the mode if we later set the attributes */
		FSAL_UNSET_MASK(attrib_set->mask, ATTR_MODE);
	}

	if (createmode == FSAL_UNCHECKED && (attrib_set->mask != 0)) {
		/* If we have FSAL_UNCHECKED and want to set more attributes
		 * than the mode, we attempt an O_EXCL create first, if that
		 * succeeds, then we will be allowed to set the additional
		 * attributes, otherwise, we don't know we created the file
		 * and this can NOT set the attributes.
		 */
		posix_flags |= O_EXCL;
	}

	dir_fd = vfs_fsal_open(myself, O_PATH | O_NOACCESS, &status.major);

	if (dir_fd < 0)
		return fsalstat(status.major, -dir_fd);

	/** @todo: not sure what this accomplishes... */
	retval = vfs_stat_by_handle(dir_fd, &stat);

	if (retval < 0) {
		retval = errno;
		status = fsalstat(posix2fsal_error(retval), retval);
		goto direrr;
	}

	/* Become the user because we are creating an object in this dir.
	 */
	if (createmode != FSAL_NO_CREATE)
		fsal_set_credentials(op_ctx->creds);

	if ((posix_flags & O_CREAT) != 0)
		fd = openat(dir_fd, name, posix_flags, unix_mode);
	else
		fd = openat(dir_fd, name, posix_flags);

	if (fd == -1 && errno == EEXIST && createmode == FSAL_UNCHECKED) {
		/* We tried to create O_EXCL to set attributes and failed.
		 * Remove O_EXCL and retry. We still try O_CREAT again just in
		 * case file disappears out from under us.
		 *
		 * Note that because we have dropped O_EXCL, later on we will
		 * not assume we created the file, and thus will not set
		 * additional attributes. We don't need to separately track
		 * the condition of not wanting to set attributes.
		 */
		posix_flags &= ~O_EXCL;
		fd = openat(dir_fd, name, posix_flags, unix_mode);
	}

	/* Preserve errno */
	retval = errno;

	/* If we were creating, restore credentials now. */
	if (createmode != FSAL_NO_CREATE)
		fsal_restore_ganesha_credentials();

	if (fd < 0) {
		status = fsalstat(posix2fsal_error(retval), retval);
		goto direrr;
	}

	/* Remember if we were responsible for creating the file.
	 * Note that in an UNCHECKED retry we MIGHT have re-created the
	 * file and won't remember that. Oh well, so in that rare case we
	 * leak a partially created file if we have a subsequent error in here.
	 * Also notify caller to do permission check if we DID NOT create the
	 * file. Note it IS possible in the case of a race between an UNCHECKED
	 * open and an external unlink, we did create the file, but we will
	 * still force a permission check. Of course that permission check
	 * SHOULD succeed since we also won't set the mode the caller requested
	 * and the default file create permissions SHOULD allow the owner
	 * read/write.
	 */
	created = (posix_flags & O_EXCL) != 0;
	*caller_perm_check = !created;

	vfs_alloc_handle(fh);

	retval = vfs_name_to_handle(dir_fd, obj_hdl->fs, name, fh);

	if (retval < 0) {
		retval = errno;
		status = fsalstat(posix2fsal_error(retval), retval);
		goto fileerr;
	}

	retval = fstat(fd, &stat);

	if (retval < 0) {
		retval = errno;
		status = fsalstat(posix2fsal_error(retval), retval);
		goto fileerr;
	}

	/* allocate an obj_handle and fill it up */
	hdl = alloc_handle(dir_fd, fh, obj_hdl->fs, &stat, myself->handle, name,
			   op_ctx->fsal_export);

	if (hdl == NULL) {
		status = fsalstat(posix2fsal_error(ENOMEM), ENOMEM);
		goto fileerr;
	}

	/* If we didn't have a state above, use the global fd. At this point,
	 * since we just created the global fd, no one else can have a
	 * reference to it, and thus we can mamnipulate unlocked which is
	 * handy since we can then call setattr2 which WILL take the lock
	 * without a double locking deadlock.
	 */
	if (my_fd == NULL)
		my_fd = &hdl->u.file.fd;

	my_fd->fd = fd;
	my_fd->openflags = openflags;

	*new_obj = &hdl->obj_handle;

	if (created && attrib_set->mask != 0) {
		/* Set attributes using our newly opened file descriptor as the
		 * share_fd if there are any left to set (mode and truncate
		 * have already been handled).
		 *
		 * Note that we only set the attributes if we were responsible
		 * for creating the file and we have attributes to set.
		 *
		 * Note if we have ENABLE_VFS_DEBUG_ACL an inherited ACL might
		 * be part of the attributes we are setting here.
		 */
		status = (*new_obj)->obj_ops.setattr2(*new_obj,
						      false,
						      state,
						      attrib_set);

		if (FSAL_IS_ERROR(status)) {
			/* Release the handle we just allocated. */
			(*new_obj)->obj_ops.release(*new_obj);
			*new_obj = NULL;
			goto fileerr;
		}

		if (attrs_out != NULL) {
			status = (*new_obj)->obj_ops.getattrs(*new_obj,
							      attrs_out);
			if (FSAL_IS_ERROR(status) &&
			    (attrs_out->mask & ATTR_RDATTR_ERR) == 0) {
				/* Get attributes failed and caller expected
				 * to get the attributes. Otherwise continue
				 * with attrs_out indicating ATTR_RDATTR_ERR.
				 */
				goto fileerr;
			}
		}
	} else if (attrs_out != NULL) {
		/* Since we haven't set any attributes other than what was set
		 * on create (if we even created), just use the stat results
		 * we used to create the fsal_obj_handle.
		 */
		posix2fsal_attributes(&stat, attrs_out);

		/* Make sure ATTR_RDATTR_ERR is cleared on success. */
		attrs_out->mask &= ~ATTR_RDATTR_ERR;
	}

	close(dir_fd);

	if (state != NULL) {
		/* Prepare to take the share reservation, but only if we are
		 * called with a valid state (if state is NULL the caller is
		 * a stateless create such as NFS v3 CREATE).
		 */

		/* This can block over an I/O operation. */
		PTHREAD_RWLOCK_wrlock(&(*new_obj)->lock);

		/* Take the share reservation now by updating the counters. */
		update_share_counters(&hdl->u.file.share,
				      FSAL_O_CLOSED,
				      openflags);

		PTHREAD_RWLOCK_unlock(&(*new_obj)->lock);
	}

	return fsalstat(ERR_FSAL_NO_ERROR, 0);

 fileerr:

	close(fd);

	/* Delete the file if we actually created it. */
	if (created)
		unlinkat(dir_fd, name, 0);

 direrr:

	close(dir_fd);
	return fsalstat(posix2fsal_error(retval), retval);
}
Ejemplo n.º 6
0
/**
 * @brief Set attributes on an object
 *
 * This function sets attributes on an object.  Which attributes are
 * set is determined by attrib_set->mask. The FSAL must manage bypass
 * or not of share reservations, and a state may be passed.
 *
 * @param[in] obj_hdl    File on which to operate
 * @param[in] state      state_t to use for this operation
 * @param[in] attrib_set Attributes to set
 *
 * @return FSAL status.
 */
fsal_status_t vfs_setattr2(struct fsal_obj_handle *obj_hdl,
			   bool bypass,
			   struct state_t *state,
			   struct attrlist *attrib_set)
{
	struct vfs_fsal_obj_handle *myself;
	fsal_status_t status = {0, 0};
	int retval = 0;
	fsal_openflags_t openflags = FSAL_O_ANY;
	bool has_lock = false;
	bool need_fsync = false;
	bool closefd = false;
	int my_fd;
	const char *func;

	/* apply umask, if mode attribute is to be changed */
	if (FSAL_TEST_MASK(attrib_set->mask, ATTR_MODE))
		attrib_set->mode &=
		    ~op_ctx->fsal_export->exp_ops.fs_umask(op_ctx->fsal_export);

	myself = container_of(obj_hdl, struct vfs_fsal_obj_handle, obj_handle);

	if (obj_hdl->fsal != obj_hdl->fs->fsal) {
		LogDebug(COMPONENT_FSAL,
			 "FSAL %s operation for handle belonging to FSAL %s, return EXDEV",
			 obj_hdl->fsal->name,
			 obj_hdl->fs->fsal != NULL
				? obj_hdl->fs->fsal->name
				: "(none)");
		return fsalstat(posix2fsal_error(EXDEV), EXDEV);
	}

#ifdef ENABLE_VFS_DEBUG_ACL
#ifdef ENABLE_RFC_ACL
	if (FSAL_TEST_MASK(attrib_set->mask, ATTR_MODE) &&
	    !FSAL_TEST_MASK(attrib_set->mask, ATTR_ACL)) {
		/* Set ACL from MODE */
		struct attrlist attrs;

		fsal_prepare_attrs(&attrs, ATTR_ACL);

		status = obj_hdl->obj_ops.getattrs(obj_hdl, &attrs);

		if (FSAL_IS_ERROR(status))
			return status;

		status = fsal_mode_to_acl(attrib_set, attrs.acl);

		/* Done with the attrs */
		fsal_release_attrs(&attrs);
	} else {
		/* If ATTR_ACL is set, mode needs to be adjusted no matter what.
		 * See 7530 s 6.4.1.3 */
		if (!FSAL_TEST_MASK(attrib_set->mask, ATTR_MODE))
			attrib_set->mode = myself->mode;
		status = fsal_acl_to_mode(attrib_set);
	}

	if (FSAL_IS_ERROR(status))
		return status;
#endif /* ENABLE_RFC_ACL */
#endif

	/* This is yet another "you can't get there from here".  If this object
	 * is a socket (AF_UNIX), an fd on the socket s useless _period_.
	 * If it is for a symlink, without O_PATH, you will get an ELOOP error
	 * and (f)chmod doesn't work for a symlink anyway - not that it matters
	 * because access checking is not done on the symlink but the final
	 * target.
	 * AF_UNIX sockets are also ozone material.  If the socket is already
	 * active listeners et al, you can manipulate the mode etc.  If it is
	 * just sitting there as in you made it with a mknod.
	 * (one of those leaky abstractions...)
	 * or the listener forgot to unlink it, it is lame duck.
	 */

	/* Test if size is being set, make sure file is regular and if so,
	 * require a read/write file descriptor.
	 */
	if (FSAL_TEST_MASK(attrib_set->mask, ATTR_SIZE)) {
		if (obj_hdl->type != REGULAR_FILE) {
			LogFullDebug(COMPONENT_FSAL,
				     "Setting size on non-regular file");
			return fsalstat(ERR_FSAL_INVAL, EINVAL);
		}
		openflags = FSAL_O_RDWR;
	}

	/* Get a usable file descriptor. Share conflict is only possible if
	 * size is being set.
	 */
	status = find_fd(&my_fd, obj_hdl, bypass, state, openflags,
			 &has_lock, &need_fsync, &closefd, false);

	if (FSAL_IS_ERROR(status)) {
		if (obj_hdl->type == SYMBOLIC_LINK &&
		    status.major == ERR_FSAL_PERM) {
			/* You cannot open_by_handle (XFS) a symlink and it
			 * throws an EPERM error for it.  open_by_handle_at
			 * does not throw that error for symlinks so we play a
			 * game here.  Since there is not much we can do with
			 * symlinks anyway, say that we did it
			 * but don't actually do anything.
			 * If you *really* want to tweek things
			 * like owners, get a modern linux kernel...
			 */
			status = fsalstat(ERR_FSAL_NO_ERROR, 0);
		}
		LogFullDebug(COMPONENT_FSAL,
			     "find_fd status=%s",
			     fsal_err_txt(status));
		goto out;
	}

	/** TRUNCATE **/
	if (FSAL_TEST_MASK(attrib_set->mask, ATTR_SIZE)) {
		retval = ftruncate(my_fd, attrib_set->filesize);
		if (retval != 0) {
			/** @todo FSF: is this still necessary?
			 *
			 * XXX ESXi volume creation pattern reliably
			 * reached this point in the past, however now that we
			 * only use the already open file descriptor if it is
			 * open read/write, this may no longer fail.
			 * If there is some other error from ftruncate, then
			 * we will needlessly retry, but without more detail
			 * of the original failure, we can't be sure.
			 * Fortunately permission checking is done by
			 * Ganesha before calling here, so we won't get an
			 * EACCES since this call is done as root. We could
			 * get EFBIG, EPERM, or EINVAL.
			 */
			/** @todo FSF: re-open if we really still need this
			 */

			retval = ftruncate(my_fd, attrib_set->filesize);
			if (retval != 0) {
				func = "truncate";
				goto fileerr;
			}
		}
	}

	/** CHMOD **/
	if (FSAL_TEST_MASK(attrib_set->mask, ATTR_MODE)) {
		/* The POSIX chmod call doesn't affect the symlink object, but
		 * the entry it points to. So we must ignore it.
		 */
		if (obj_hdl->type != SYMBOLIC_LINK) {
			if (vfs_unopenable_type(obj_hdl->type))
				retval = fchmodat(
					my_fd,
					myself->u.unopenable.name,
					fsal2unix_mode(attrib_set->mode),
					0);
			else
				retval = fchmod(
					my_fd,
					fsal2unix_mode(attrib_set->mode));

			if (retval != 0) {
				func = "chmod";
				goto fileerr;
			}
		}
	}

	/**  CHOWN  **/
	if (FSAL_TEST_MASK(attrib_set->mask, ATTR_OWNER | ATTR_GROUP)) {
		uid_t user = FSAL_TEST_MASK(attrib_set->mask, ATTR_OWNER)
		    ? (int)attrib_set->owner : -1;
		gid_t group = FSAL_TEST_MASK(attrib_set->mask, ATTR_GROUP)
		    ? (int)attrib_set->group : -1;

		if (vfs_unopenable_type(obj_hdl->type))
			retval = fchownat(my_fd, myself->u.unopenable.name,
					  user, group, AT_SYMLINK_NOFOLLOW);
		else if (obj_hdl->type == SYMBOLIC_LINK)
			retval = fchownat(my_fd, "", user, group,
					  AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH);
		else
			retval = fchown(my_fd, user, group);

		if (retval) {
			func = "chown";
			goto fileerr;
		}
	}

	/**  UTIME  **/
	if (FSAL_TEST_MASK(attrib_set->mask, ATTRS_SET_TIME)) {
		struct timespec timebuf[2];

		if (obj_hdl->type == SYMBOLIC_LINK)
			goto out; /* Setting time on symlinks is illegal */
		/* Atime */
		if (FSAL_TEST_MASK(attrib_set->mask, ATTR_ATIME_SERVER)) {
			timebuf[0].tv_sec = 0;
			timebuf[0].tv_nsec = UTIME_NOW;
		} else if (FSAL_TEST_MASK(attrib_set->mask, ATTR_ATIME)) {
			timebuf[0] = attrib_set->atime;
		} else {
			timebuf[0].tv_sec = 0;
			timebuf[0].tv_nsec = UTIME_OMIT;
		}

		/* Mtime */
		if (FSAL_TEST_MASK(attrib_set->mask, ATTR_MTIME_SERVER)) {
			timebuf[1].tv_sec = 0;
			timebuf[1].tv_nsec = UTIME_NOW;
		} else if (FSAL_TEST_MASK(attrib_set->mask, ATTR_MTIME)) {
			timebuf[1] = attrib_set->mtime;
		} else {
			timebuf[1].tv_sec = 0;
			timebuf[1].tv_nsec = UTIME_OMIT;
		}
		if (vfs_unopenable_type(obj_hdl->type))
			retval = vfs_utimesat(my_fd, myself->u.unopenable.name,
					      timebuf, AT_SYMLINK_NOFOLLOW);
		else
			retval = vfs_utimes(my_fd, timebuf);
		if (retval != 0) {
			func = "utimes";
			goto fileerr;
		}
	}

	/** SUBFSAL **/
	if (myself->sub_ops && myself->sub_ops->setattrs) {
		status = myself->sub_ops->setattrs(
					myself,
					my_fd,
					attrib_set->mask, attrib_set);
		if (FSAL_IS_ERROR(status))
			goto out;
	}

	errno = 0;

 fileerr:

	retval = errno;

	if (retval != 0) {
		LogDebug(COMPONENT_FSAL,
			 "%s returned %s",
			 func, strerror(retval));
	}

	status = fsalstat(posix2fsal_error(retval), retval);

 out:

	if (closefd)
		close(my_fd);

	if (has_lock)
		PTHREAD_RWLOCK_unlock(&obj_hdl->lock);

	return status;
}
Ejemplo n.º 7
0
static fsal_status_t lustre_makedir(struct fsal_obj_handle *dir_hdl,
				    const char *name, struct attrlist *attrib,
				    struct fsal_obj_handle **handle)
{
	struct lustre_fsal_obj_handle *myself, *hdl;
	char dirpath[MAXPATHLEN];
	char newpath[MAXPATHLEN];
	struct stat stat;
	mode_t unix_mode;
	fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR;
	int rc = 0;
	struct lustre_file_handle *fh =
	    alloca(sizeof(struct lustre_file_handle));

	*handle = NULL;		/* poison it */
	if (!dir_hdl->ops->handle_is(dir_hdl, DIRECTORY)) {
		LogCrit(COMPONENT_FSAL,
			"Parent handle is not a directory. hdl = 0x%p",
			dir_hdl);
		return fsalstat(ERR_FSAL_NOTDIR, 0);
	}
	memset(fh, 0, sizeof(struct lustre_file_handle));
	myself =
	    container_of(dir_hdl, struct lustre_fsal_obj_handle, obj_handle);
	unix_mode = fsal2unix_mode(attrib->mode)
	    & ~op_ctx->fsal_export->ops->fs_umask(op_ctx->fsal_export);
	lustre_handle_to_path(dir_hdl->fs->path,
			      myself->handle, dirpath);
	rc = lstat(dirpath, &stat);
	if (rc < 0) {
		rc = errno;
		goto direrr;
	}

	/* create it with no access because we are root when we do this */
	snprintf(newpath, MAXPATHLEN, "%s/%s", dirpath, name);
	rc = CRED_WRAP(op_ctx->creds, int, mkdir, newpath, unix_mode);
	if (rc < 0) {
		rc = errno;
		goto direrr;
	}
	rc =
	    get_stat_by_handle_at(dir_hdl->fs->path,
				  myself->handle, name, fh, &stat);
	if (rc < 0)
		goto fileerr;

	/* allocate an obj_handle and fill it up */
	hdl = alloc_handle(fh, dir_hdl->fs,
			   &stat, NULL, NULL, NULL, op_ctx->fsal_export);
	if (hdl != NULL) {
		*handle = &hdl->obj_handle;
	} else {
		fsal_error = ERR_FSAL_NOMEM;
		goto errout;
	}
	return fsalstat(ERR_FSAL_NO_ERROR, 0);

 direrr:
	rc = errno;
	fsal_error = posix2fsal_error(rc);

	return fsalstat(fsal_error, rc);

 fileerr:
	fsal_error = posix2fsal_error(rc);
	rmdir(newpath);		/* remove the evidence on errors */
 errout:
	return fsalstat(fsal_error, rc);
}
Ejemplo n.º 8
0
/**
 * FSAL_mkdir:
 * Create a directory.
 *
 * \param dir_hdl (input):
 *        Handle of the parent directory where
 *        the subdirectory is to be created.
 * \param p_context (input):
 *        Pointer to the name of the directory to be created.
 * \param cred (input):
 *        Authentication context for the operation (user,...).
 * \param accessmode (input):
 *        Mode for the directory to be created.
 *        (the umask defined into the FSAL configuration file
 *        will be applied on it).
 * \param p_object_handle (output):
 *        Pointer to the handle of the created directory.
 * \param p_object_attributes (optionnal input/output):
 *        The attributes of the created directory.
 *        As input, it defines the attributes that the caller
 *        wants to retrieve (by positioning flags into this structure)
 *        and the output is built considering this input
 *        (it fills the structure according to the flags it contains).
 *        May be NULL.
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - Another error code if an error occured.
 */
fsal_status_t PTFSAL_mkdir(struct fsal_obj_handle *dir_hdl,	/* IN */
			   const char *p_dirname,	/* IN */
			   const struct req_op_context *p_context,	/* IN */
			   uint32_t accessmode,	/* IN */
			   ptfsal_handle_t *p_object_handle,	/* OUT */
			   struct attrlist *p_object_attributes)
{				/* IN/OUT */

	int rc, errsv;
	int setgid_bit = 0;
	mode_t unix_mode;
	fsal_status_t status;
	struct attrlist parent_dir_attrs;
	char newPath[PATH_MAX];
	struct pt_fsal_obj_handle *pt_hdl;

	FSI_TRACE(FSI_INFO, "MKDIR BEGIN-------------------------\n");

	/* sanity checks.
	 * note : object_attributes is optional.
	 */
	if (!dir_hdl || !p_context || !p_object_handle || !p_dirname)
		return fsalstat(ERR_FSAL_FAULT, 0);

	pt_hdl = container_of(dir_hdl, struct pt_fsal_obj_handle, obj_handle);

	/* convert FSAL mode to unix mode. */
	unix_mode = fsal2unix_mode(accessmode);

	/* Apply umask */
	unix_mode = unix_mode & ~p_context->fsal_export->exp_ops.
			fs_umask(p_context->fsal_export);

	/* get directory metadata */
	parent_dir_attrs.mask = p_context->fsal_export->exp_ops.
				fs_supported_attrs(p_context->fsal_export);
	status =
	    PTFSAL_getattrs(p_context->fsal_export, p_context, pt_hdl->handle,
			    &parent_dir_attrs);

	if (FSAL_IS_ERROR(status))
		return status;

	/* Check the user can write in the directory, and check the
	 * setgid bit on the directory
	 */

	if (fsal2unix_mode(parent_dir_attrs.mode) & S_ISGID)
		setgid_bit = 1;

	rc = ptfsal_mkdir(pt_hdl, p_dirname, p_context, unix_mode,
			  p_object_handle);
	errsv = errno;
	if (rc)
		return fsalstat(posix2fsal_error(errsv), errsv);

	if (FSAL_IS_ERROR(status))
		return status;

	/* the directory has been created */
	/* chown the dir to the current user/group */

	if (p_context->creds->caller_uid != geteuid()) {
		FSI_TRACE(FSI_DEBUG, "MKDIR %d", __LINE__);
		/* if the setgid_bit was set on the parent directory, do not
		 * change the group of the created file, because it's already
		 * the parentdir's group
		 */

		if (fsi_get_name_from_handle
		    (p_context, p_context->fsal_export, pt_hdl->handle,
		     (char *)newPath, NULL) < 0) {
			FSI_TRACE(FSI_DEBUG,
				  "Failed to get name from handle %s",
				  (char *)p_object_handle->data.handle.
				  f_handle);
			return fsalstat(posix2fsal_error(errsv), errsv);
		}
		rc = ptfsal_chown(p_context, p_context->fsal_export, newPath,
				  p_context->creds->caller_uid,
				  setgid_bit ? -1 : (int)p_context->creds->
				  caller_gid);
		errsv = errno;
		if (rc)
			return fsalstat(posix2fsal_error(errsv), errsv);
	}

	/* retrieve file attributes */
	if (p_object_attributes) {
		FSI_TRACE(FSI_DEBUG, "MKDIR %d", __LINE__);
		status = PTFSAL_getattrs(p_context->fsal_export, p_context,
					 p_object_handle,
					 p_object_attributes);

		/* on error, we set a special bit in the mask. */
		if (FSAL_IS_ERROR(status)) {
			FSAL_CLEAR_MASK(p_object_attributes->mask);
			FSAL_SET_MASK(p_object_attributes->mask,
				      ATTR_RDATTR_ERR);
		}

	}
	FSI_TRACE(FSI_INFO, "MKDIR END ------------------\n");
	FSI_TRACE(FSI_DEBUG, "MKDIR %d", __LINE__);
	/* OK */
	return fsalstat(ERR_FSAL_NO_ERROR, 0);

}
Ejemplo n.º 9
0
/**
 * FSAL_mknode:
 * Create a special object in the filesystem.
 * Not supported upon HPSS.
 *
 * \return ERR_FSAL_NOTSUPP.
 */
fsal_status_t GPFSFSAL_mknode(fsal_handle_t * parentdir_handle,     /* IN */
                          fsal_name_t * p_node_name,    /* IN */
                          fsal_op_context_t * p_context,        /* IN */
                          fsal_accessmode_t accessmode, /* IN */
                          fsal_nodetype_t nodetype,     /* IN */
                          fsal_dev_t * dev,     /* IN */
                          fsal_handle_t * p_object_handle,      /* OUT (handle to the created node) */
                          fsal_attrib_list_t * node_attributes  /* [ IN/OUT ] */
    )
{
  int rc, errsv;
  int setgid_bit = 0;
  fsal_status_t status;
  int fd, newfd;

  mode_t unix_mode = 0;
  dev_t unix_dev = 0;
  fsal_accessflags_t access_mask = 0;
  fsal_attrib_list_t parent_dir_attrs;

  /* sanity checks.
   * note : link_attributes is optional.
   */
  if(!parentdir_handle || !p_context || !p_node_name)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mknode);

  unix_mode = fsal2unix_mode(accessmode);

  /* Apply umask */
  unix_mode = unix_mode & ~global_fs_info.umask;

  switch (nodetype)
    {
    case FSAL_TYPE_BLK:
      if(!dev)
        Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mknode);
      unix_mode |= S_IFBLK;
      unix_dev = (dev->major << 8) | (dev->minor & 0xFF);
      break;

    case FSAL_TYPE_CHR:
      if(!dev)
        Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mknode);
      unix_mode |= S_IFCHR;
      unix_dev = (dev->major << 8) | (dev->minor & 0xFF);
      break;

    case FSAL_TYPE_SOCK:
      unix_mode |= S_IFSOCK;
      break;

    case FSAL_TYPE_FIFO:
      unix_mode |= S_IFIFO;
      break;

    default:
      LogMajor(COMPONENT_FSAL,
               "Invalid node type in FSAL_mknode: %d", nodetype);
      Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_mknode);
    }

  /* build the directory path */
  status =
      fsal_internal_handle2fd(p_context, parentdir_handle, &fd, O_RDONLY | O_DIRECTORY);

  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_mknode);

  /* retrieve directory attributes */
  parent_dir_attrs.asked_attributes = GPFS_SUPPORTED_ATTRIBUTES;
  status = GPFSFSAL_getattrs(parentdir_handle, p_context, &parent_dir_attrs);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_mknode);

  /* Check the user can write in the directory, and check weither the setgid bit on the directory */
  if(fsal2unix_mode(parent_dir_attrs.mode) & S_ISGID)
    setgid_bit = 1;

  /* Set both mode and ace4 mask */
  access_mask = FSAL_MODE_MASK_SET(FSAL_W_OK | FSAL_X_OK) |
                FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_ADD_FILE);

  status = fsal_internal_testAccess(p_context, access_mask, NULL, &parent_dir_attrs);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_mknode);

  /* creates the node, then stats it */
  rc = mknodat(fd, p_node_name->name, unix_mode, unix_dev);
  errsv = errno;

  if(rc)
    {
      close(fd);
      Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mknode);
    }

  /* WARNING:
   * After creating the new node, the node name could have been changed.
   * This is a race condition. However only root creates new nodes. This
   * is an unlikely race condition, but hopefully can be fixed someday.
   */

  if(FSAL_IS_ERROR(status = fsal_internal_get_handle_at(fd, p_node_name,
                                                        p_object_handle)))
    {
      close(fd);
      ReturnStatus(status, INDEX_FSAL_mknode);
    }

  if(FSAL_IS_ERROR(status = fsal_internal_handle2fd_at(fd,
                                                       p_object_handle, &newfd,
                                                       O_RDONLY | O_NOFOLLOW)))
    {
      close(fd);
      ReturnStatus(status, INDEX_FSAL_mknode);
    }

  /* the node has been created */
  /* chown the file to the current user/group */

  if(p_context->credential.user != geteuid())
    {
      /* if the setgid_bit was set on the parent directory, do not change the group of the created file, because it's already the parentdir's group */
      rc = fchown(newfd, p_context->credential.user,
                  setgid_bit ? -1 : (int)p_context->credential.group);
      errsv = errno;

      if(rc)
        {
          close(fd);
          close(newfd);
          Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mknode);
        }
    }

  close(fd);
  close(newfd);

  /* Fills the attributes if needed */
  if(node_attributes)
    {

      status = GPFSFSAL_getattrs(p_object_handle, p_context, node_attributes);

      /* on error, we set a special bit in the mask. */

      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(node_attributes->asked_attributes);
          FSAL_SET_MASK(node_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }

    }

  /* Finished */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_mknode);

}
Ejemplo n.º 10
0
/**
 * FSAL_create:
 * Create a regular file.
 *
 * \param parent_directory_handle (input):
 *        Handle of the parent directory where the file is to be created.
 * \param p_filename (input):
 *        Pointer to the name of the file to be created.
 * \param cred (input):
 *        Authentication context for the operation (user,...).
 * \param accessmode (input):
 *        Mode for the file to be created.
 *        (the umask defined into the FSAL configuration file
 *        will be applied on it).
 * \param object_handle (output):
 *        Pointer to the handle of the created file.
 * \param object_attributes (optional input/output): 
 *        The attributes of the created file.
 *        As input, it defines the attributes that the caller
 *        wants to retrieve (by positioning flags into this structure)
 *        and the output is built considering this input
 *        (it fills the structure according to the flags it contains).
 *        May be NULL.
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - Another error code if an error occurred.
 */
fsal_status_t POSIXFSAL_create(fsal_handle_t * parent_directory_handle,  /* IN */
                               fsal_name_t * p_filename,        /* IN */
                               fsal_op_context_t * context,      /* IN */
                               fsal_accessmode_t accessmode,    /* IN */
                               fsal_handle_t * object_handle,    /* OUT */
                               fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */
    )
{

  posixfsal_handle_t * p_parent_directory_handle
    = (posixfsal_handle_t *) parent_directory_handle;
  posixfsal_op_context_t * p_context = (posixfsal_op_context_t *) context;
  posixfsal_handle_t * p_object_handle = (posixfsal_handle_t *) p_object_handle;
  int rc, fd, errsv;
  int setgid_bit = 0;
  fsal_status_t status;

  fsal_path_t fsalpath;
  struct stat buffstat;
  fsal_posixdb_fileinfo_t info;
  mode_t unix_mode;

  /* sanity checks.
   * note : object_attributes is optional.
   */
  if(!p_parent_directory_handle || !p_context || !p_object_handle || !p_filename)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create);

  /* convert fsal mode to unix mode. */
  unix_mode = fsal2unix_mode(accessmode);

  /* Apply umask */
  unix_mode = unix_mode & ~global_fs_info.umask;

  LogFullDebug(COMPONENT_FSAL, "Creation mode: 0%o", accessmode);

  /* build the destination path */
  status =
      fsal_internal_getPathFromHandle(p_context, p_parent_directory_handle, 1, &fsalpath,
                                      &buffstat);
  if(FSAL_IS_ERROR(status))
    Return(status.major, status.minor, INDEX_FSAL_create);

  /* Check the user can write in the directory, and check the setgid bit on the directory */
  if(buffstat.st_mode & S_ISGID)
    setgid_bit = 1;

  status = fsal_internal_testAccess(p_context, FSAL_W_OK | FSAL_X_OK, &buffstat, NULL);
  if(FSAL_IS_ERROR(status))
    Return(status.major, status.minor, INDEX_FSAL_create);

  status = fsal_internal_appendFSALNameToFSALPath(&fsalpath, p_filename);
  if(FSAL_IS_ERROR(status))
    Return(status.major, status.minor, INDEX_FSAL_create);

  /* call to API */

  TakeTokenFSCall();
  /* create the file */
  fd = open(fsalpath.path, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, unix_mode);   /* error if the file already exists */
  errsv = errno;
  if(fd == -1)
    goto releaseToken;
  /* close the file descriptor */
  rc = close(fd);
  errsv = errno;
  if(rc)
    goto releaseToken;
  /* stat the new file */
  rc = lstat(fsalpath.path, &buffstat);
  errsv = errno;

 releaseToken:
  ReleaseTokenFSCall();

  if(fd == -1 || rc)
    Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create);

  /* add the file to the database */
  if(FSAL_IS_ERROR(status = fsal_internal_posix2posixdb_fileinfo(&buffstat, &info)))
    Return(status.major, status.minor, INDEX_FSAL_create);
  if(FSAL_IS_ERROR
     (status =
      fsal_internal_posixdb_add_entry(p_context->p_conn, p_filename, &info,
                                      p_parent_directory_handle, p_object_handle)))
    Return(status.major, status.minor, INDEX_FSAL_create);

  /* the file has been created */
  /* chown the file to the current user */

  if(p_context->credential.user != geteuid())
    {
      TakeTokenFSCall();
      /* if the setgid_bit was set on the parent directory,
       * do not change the group of the created file,
       * because it's already the parentdir's group */
      rc = lchown(fsalpath.path, p_context->credential.user,
                  setgid_bit ? -1 : (int)p_context->credential.group);
      errsv = errno;
      ReleaseTokenFSCall();
      if(rc)
        Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create);

      buffstat.st_uid = p_context->credential.user;
      buffstat.st_gid = p_context->credential.group;
    }

  /* add the file to the database */

  if(p_object_attributes)
    {

      /* convert POSIX attributes to fsal attributes */
      status = posix2fsal_attributes(&buffstat, p_object_attributes);
      /* on error, we set a special bit in the mask. */
      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
          FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }

    }

  /* OK */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_create);

}
Ejemplo n.º 11
0
/**
 *  @brief Create a special object in the filesystem.
 *
 *  @param dir_hdl Handle of the parent dir where the file is to be created.
 *  @param node_name Pointer to the name of the file to be created.
 *  @param op_ctx Authentication context for the operation (user,...).
 *  @param accessmode Mode for the file to be created.
 *  @param node_type Type of file to create.
 *  @param dev Device id of file to create.
 *  @param gpfs_fh Pointer to the handle of the created file.
 *  @param fsal_attr Attributes of the created file.
 *  @return ERR_FSAL_NO_ERROR on success, error otherwise
 *
 */
fsal_status_t
GPFSFSAL_mknode(struct fsal_obj_handle *dir_hdl, const char *node_name,
                const struct req_op_context *op_ctx, uint32_t accessmode,
                mode_t nodetype, fsal_dev_t *dev,
                struct gpfs_file_handle *gpfs_fh, struct attrlist *fsal_attr)
{
    fsal_status_t status;
    mode_t unix_mode = 0;
    dev_t unix_dev = 0;

    /* note : fsal_attr is optional. */
    if (!dir_hdl || !op_ctx || !node_name)
        return fsalstat(ERR_FSAL_FAULT, 0);

    unix_mode = fsal2unix_mode(accessmode);

    /* Apply umask */
    unix_mode = unix_mode & ~op_ctx->fsal_export->exp_ops.
                fs_umask(op_ctx->fsal_export);

    switch (nodetype) {
    case BLOCK_FILE:
        if (!dev)
            return fsalstat(ERR_FSAL_FAULT, 0);
        unix_mode |= S_IFBLK;
        unix_dev = (dev->major << 20) | (dev->minor & 0xFFFFF);
        break;

    case CHARACTER_FILE:
        if (!dev)
            return fsalstat(ERR_FSAL_FAULT, 0);
        unix_mode |= S_IFCHR;
        unix_dev = (dev->major << 20) | (dev->minor & 0xFFFFF);
        break;

    case SOCKET_FILE:
        unix_mode |= S_IFSOCK;
        break;

    case FIFO_FILE:
        unix_mode |= S_IFIFO;
        break;

    default:
        LogMajor(COMPONENT_FSAL, "Invalid node type in FSAL_mknode: %d",
                 nodetype);
        return fsalstat(ERR_FSAL_INVAL, 0);
    }

    fsal_set_credentials(op_ctx->creds);
    status = fsal_internal_mknode(dir_hdl, node_name, unix_mode, unix_dev,
                                  gpfs_fh, NULL);

    fsal_restore_ganesha_credentials();

    if (FSAL_IS_ERROR(status))
        return status;

    /* Fills the attributes */
    return GPFSFSAL_getattrs(op_ctx->fsal_export,
                             dir_hdl->fs->private_data,
                             op_ctx, gpfs_fh, fsal_attr);
}
Ejemplo n.º 12
0
/**
 * FSAL_mknode:
 * Create a special object in the filesystem.
 * Not supported upon HPSS.
 *
 * \return ERR_FSAL_NOTSUPP.
 */
fsal_status_t GPFSFSAL_mknode(fsal_handle_t * parentdir_handle,     /* IN */
                          fsal_name_t * p_node_name,    /* IN */
                          fsal_op_context_t * p_context,        /* IN */
                          fsal_accessmode_t accessmode, /* IN */
                          fsal_nodetype_t nodetype,     /* IN */
                          fsal_dev_t * dev,     /* IN */
                          fsal_handle_t * p_object_handle,      /* OUT (handle to the created node) */
                          fsal_attrib_list_t * node_attributes  /* [ IN/OUT ] */
    )
{
  fsal_status_t status;
/*   int flags=(O_RDONLY|O_NOFOLLOW); */
  mode_t unix_mode = 0;
  dev_t unix_dev = 0;
  fsal_accessflags_t access_mask = 0;
  fsal_attrib_list_t parent_dir_attrs;

  /* sanity checks.
   * note : link_attributes is optional.
   */
  if(!parentdir_handle || !p_context || !p_node_name)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mknode);

  unix_mode = fsal2unix_mode(accessmode);

  /* Apply umask */
  unix_mode = unix_mode & ~global_fs_info.umask;

  switch (nodetype)
    {
    case FSAL_TYPE_BLK:
      if(!dev)
        Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mknode);
      unix_mode |= S_IFBLK;
      unix_dev = (dev->major << 8) | (dev->minor & 0xFF);
      break;

    case FSAL_TYPE_CHR:
      if(!dev)
        Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mknode);
      unix_mode |= S_IFCHR;
      unix_dev = (dev->major << 8) | (dev->minor & 0xFF);
      break;

    case FSAL_TYPE_SOCK:
      unix_mode |= S_IFSOCK;
      break;

    case FSAL_TYPE_FIFO:
      unix_mode |= S_IFIFO;
/*       flags = (O_RDONLY | O_NOFOLLOW | O_NONBLOCK); */
      break;

    default:
      LogMajor(COMPONENT_FSAL,
               "Invalid node type in FSAL_mknode: %d", nodetype);
      Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_mknode);
    }

  /* retrieve directory attributes */
  parent_dir_attrs.asked_attributes = GPFS_SUPPORTED_ATTRIBUTES;
  status = GPFSFSAL_getattrs(parentdir_handle, p_context, &parent_dir_attrs);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_mknode);

  /* Check the user can write in the directory */

  /* Set both mode and ace4 mask */
  access_mask = FSAL_MODE_MASK_SET(FSAL_W_OK | FSAL_X_OK) |
                FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_ADD_FILE);

  if(!p_context->export_context->fe_static_fs_info->accesscheck_support)
  status = fsal_internal_testAccess(p_context, access_mask, NULL, &parent_dir_attrs);
  else
    status = fsal_internal_access(p_context, parentdir_handle, access_mask,
                                  &parent_dir_attrs);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_mknode);

  fsal_set_credentials(p_context);

  TakeTokenFSCall();
  status = fsal_internal_create(p_context, parentdir_handle,
                                p_node_name, unix_mode, unix_dev,
                                p_object_handle, NULL);
  ReleaseTokenFSCall();

  fsal_restore_ganesha_credentials();

  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_mknode);

  /* Fills the attributes if needed */
  if(node_attributes)
    {

      status = GPFSFSAL_getattrs(p_object_handle, p_context, node_attributes);

      /* on error, we set a special bit in the mask. */

      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(node_attributes->asked_attributes);
          FSAL_SET_MASK(node_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }

    }

  /* Finished */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_mknode);

}
Ejemplo n.º 13
0
/**
 * FSAL_create:
 * Create a regular file.
 *
 * \param parent_directory_handle (input):
 *        Handle of the parent directory where the file is to be created.
 * \param p_filename (input):
 *        Pointer to the name of the file to be created.
 * \param cred (input):
 *        Authentication context for the operation (user,...).
 * \param accessmode (input):
 *        Mode for the file to be created.
 *        (the umask defined into the FSAL configuration file
 *        will be applied on it).
 * \param object_handle (output):
 *        Pointer to the handle of the created file.
 * \param object_attributes (optional input/output):
 *        The attributes of the created file.
 *        As input, it defines the attributes that the caller
 *        wants to retrieve (by positioning flags into this structure)
 *        and the output is built considering this input
 *        (it fills the structure according to the flags it contains).
 *        May be NULL.
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - Another error code if an error occurred.
 */
fsal_status_t
PTFSAL_create(fsal_handle_t      * p_parent_directory_handle, /* IN */
              fsal_name_t        * p_filename,                /* IN */
              fsal_op_context_t  * p_context,                 /* IN */
              fsal_accessmode_t    accessmode,                /* IN */
              fsal_handle_t      * p_object_handle,           /* OUT */
              fsal_attrib_list_t * p_object_attributes        /* [ IN/OUT ] */)
{

  int errsv;
  int setgid_bit = 0;
  fsal_status_t status;

  mode_t unix_mode;
  fsal_accessflags_t access_mask = 0;
  fsal_attrib_list_t parent_dir_attrs;
  int open_rc;
  ptfsal_handle_t * p_fsi_handle = (ptfsal_handle_t *)p_object_handle;

  FSI_TRACE(FSI_DEBUG, "Begin to create file************************\n");

  /* sanity checks.
   * note : object_attributes is optional.
   */
  if(!p_parent_directory_handle || !p_context || !p_object_handle || 
     !p_filename) {
    FSI_TRACE(FSI_DEBUG, "BAD Happen!");
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create);
  }

  /* convert fsal mode to unix mode. */
  unix_mode = fsal2unix_mode(accessmode);

  /* Apply umask */
  unix_mode = unix_mode & ~global_fs_info.umask;

  LogFullDebug(COMPONENT_FSAL, "Creation mode: 0%o", accessmode);

  /* retrieve directory metadata */
  parent_dir_attrs.asked_attributes = PTFS_SUPPORTED_ATTRIBUTES;
  status = PTFSAL_getattrs(p_parent_directory_handle, p_context, 
                           &parent_dir_attrs);
  if(FSAL_IS_ERROR(status)) {
    ReturnStatus(status, INDEX_FSAL_create);
  }

  /* Check the user can write in the directory, and check the setgid bit 
   * on the directory 
   */

  if(fsal2unix_mode(parent_dir_attrs.mode) & S_ISGID) {
    setgid_bit = 1;
  }

  /* Set both mode and ace4 mask */
  access_mask = FSAL_MODE_MASK_SET(FSAL_W_OK | FSAL_X_OK) |
                FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_ADD_FILE);

  if(!p_context->export_context->fe_static_fs_info->accesscheck_support) {
    status = fsal_internal_testAccess(p_context, access_mask, NULL, 
                                      &parent_dir_attrs);
  } else {
    status = fsal_internal_access(p_context, 
                                  p_parent_directory_handle, 
                                  access_mask,
                                  &parent_dir_attrs);
  }
  if(FSAL_IS_ERROR(status)) {
    ReturnStatus(status, INDEX_FSAL_create);
  }

  // Create the file, return handle
  open_rc = ptfsal_open(p_parent_directory_handle, 
                        p_filename, p_context, unix_mode, p_object_handle);
  if (open_rc < 0) {
     errsv = errno;
     Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create);
  }

  FSI_TRACE(FSI_DEBUG, "New Handle = %s", 
            (char *)p_fsi_handle->data.handle.f_handle);

  /* retrieve file attributes */
  if(p_object_attributes) {
    status = PTFSAL_getattrs(p_object_handle, 
                             p_context, 
                             p_object_attributes);

    /* on error, we set a special bit in the mask. */
    if(FSAL_IS_ERROR(status)) {
      FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
      FSAL_SET_MASK(p_object_attributes->asked_attributes, 
                    FSAL_ATTR_RDATTR_ERR);
    }

  }

  FSI_TRACE(FSI_DEBUG, "End to create file************************\n");

  /* OK */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_create);

}
Ejemplo n.º 14
0
/**
 * FSAL_mkdir:
 * Create a directory.
 *
 * \param parent_directory_handle (input):
 *        Handle of the parent directory where
 *        the subdirectory is to be created.
 * \param p_dirname (input):
 *        Pointer to the name of the directory to be created.
 * \param cred (input):
 *        Authentication context for the operation (user,...).
 * \param accessmode (input):
 *        Mode for the directory to be created.
 *        (the umask defined into the FSAL configuration file
 *        will be applied on it).
 * \param object_handle (output):
 *        Pointer to the handle of the created directory.
 * \param object_attributes (optionnal input/output):
 *        The attributes of the created directory.
 *        As input, it defines the attributes that the caller
 *        wants to retrieve (by positioning flags into this structure)
 *        and the output is built considering this input
 *        (it fills the structure according to the flags it contains).
 *        May be NULL.
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - Another error code if an error occured.
 */
fsal_status_t
PTFSAL_mkdir(fsal_handle_t      * p_parent_directory_handle, /* IN */
             fsal_name_t        * p_dirname,                 /* IN */
             fsal_op_context_t  * p_context,                 /* IN */
             fsal_accessmode_t    accessmode,                /* IN */
             fsal_handle_t      * p_object_handle,           /* OUT */
             fsal_attrib_list_t * p_object_attributes        /* [ IN/OUT ] */)
{

  int rc, errsv;
  int setgid_bit = 0;
  mode_t unix_mode;
  fsal_status_t status;
  fsal_accessflags_t access_mask = 0;
  fsal_attrib_list_t parent_dir_attrs;
  char               newPath[PATH_MAX];

  FSI_TRACE(FSI_INFO,"MKDIR BEGIN-------------------------\n");

  /* sanity checks.
   * note : object_attributes is optional.
   */
  if(!p_parent_directory_handle || !p_context || !p_object_handle || 
     !p_dirname) {
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mkdir);
  }

  /* convert FSAL mode to unix mode. */
  unix_mode = fsal2unix_mode(accessmode);

  /* Apply umask */
  unix_mode = unix_mode & ~global_fs_info.umask;

  /* get directory metadata */
  parent_dir_attrs.asked_attributes = PTFS_SUPPORTED_ATTRIBUTES;
  status = PTFSAL_getattrs(p_parent_directory_handle, p_context, 
                           &parent_dir_attrs);
  if(FSAL_IS_ERROR(status)) {
    ReturnStatus(status, INDEX_FSAL_create);
  }

  /* Check the user can write in the directory, and check the 
   * setgid bit on the directory 
   */

  if(fsal2unix_mode(parent_dir_attrs.mode) & S_ISGID) {
    setgid_bit = 1;
  }

  /* Set both mode and ace4 mask */
  access_mask = FSAL_MODE_MASK_SET(FSAL_W_OK | FSAL_X_OK) |
    FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_ADD_SUBDIRECTORY);

  if(!p_context->export_context->fe_static_fs_info->accesscheck_support) {
    status = fsal_internal_testAccess(p_context, access_mask, NULL, 
                                      &parent_dir_attrs);
  } else {
    status = fsal_internal_access(p_context, p_parent_directory_handle, 
                                  access_mask,
                                  &parent_dir_attrs);
  }
  if(FSAL_IS_ERROR(status)) {
    ReturnStatus(status, INDEX_FSAL_mkdir);
  }

  rc = ptfsal_mkdir(p_parent_directory_handle, p_dirname, 
                    p_context, unix_mode, p_object_handle);
  errsv = errno;
  if(rc) {
    Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir);
  }

  if(FSAL_IS_ERROR(status)) {
    ReturnStatus(status, INDEX_FSAL_mkdir);
  }

  /* the directory has been created */
  /* chown the dir to the current user/group */

  if(p_context->credential.user != geteuid()) {
    FSI_TRACE(FSI_DEBUG, "MKDIR %d",__LINE__);
    /* if the setgid_bit was set on the parent directory, do not change 
     * the group of the created file, because it's already the parentdir's 
     * group       
     */

    if(fsi_get_name_from_handle(
       p_context, 
       (char *)p_object_handle->data.handle.f_handle, 
       (char *)newPath, NULL) < 0) {
       FSI_TRACE(FSI_DEBUG, "Failed to get name from handle %s", 
                 (char *)p_object_handle->data.handle.f_handle);
       Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir);
    }  
    rc = ptfsal_chown(p_context, newPath,
                      p_context->credential.user,
                      setgid_bit ? -1 : (int)p_context->credential.group);
    errsv = errno;
    if(rc) {
      Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir);
    }
  }

  /* retrieve file attributes */
  if(p_object_attributes) {
    FSI_TRACE(FSI_DEBUG, "MKDIR %d",__LINE__);
    status = PTFSAL_getattrs(p_object_handle, p_context, 
                             p_object_attributes);

    /* on error, we set a special bit in the mask. */
    if(FSAL_IS_ERROR(status)) {
      FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
      FSAL_SET_MASK(p_object_attributes->asked_attributes, 
                    FSAL_ATTR_RDATTR_ERR);
    }

  }
  FSI_TRACE(FSI_INFO,"MKDIR END ------------------\n");
  FSI_TRACE(FSI_DEBUG, "MKDIR %d",__LINE__);
  /* OK */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_mkdir);

}
Ejemplo n.º 15
0
/**
 * FSAL_create:
 * Create a regular file.
 *
 * \param parent_directory_handle (input):
 *        Handle of the parent directory where the file is to be created.
 * \param p_filename (input):
 *        Pointer to the name of the file to be created.
 * \param cred (input):
 *        Authentication context for the operation (user,...).
 * \param accessmode (input):
 *        Mode for the file to be created.
 *        (the umask defined into the FSAL configuration file
 *        will be applied on it).
 * \param object_handle (output):
 *        Pointer to the handle of the created file.
 * \param object_attributes (optional input/output): 
 *        The attributes of the created file.
 *        As input, it defines the attributes that the caller
 *        wants to retrieve (by positioning flags into this structure)
 *        and the output is built considering this input
 *        (it fills the structure according to the flags it contains).
 *        May be NULL.
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - Another error code if an error occurred.
 */
fsal_status_t XFSFSAL_create(fsal_handle_t * p_parent_directory_handle,      /* IN */
                             fsal_name_t * p_filename,  /* IN */
                             fsal_op_context_t * p_context,  /* IN */
                             fsal_accessmode_t accessmode,      /* IN */
                             fsal_handle_t * p_object_handle,        /* OUT */
                             fsal_attrib_list_t * p_object_attributes   /* [ IN/OUT ] */
    )
{

  int rc, errsv;
  int setgid_bit = 0;
  fsal_status_t status;

  int fd, newfd;
  struct stat buffstat;
  mode_t unix_mode;

  /* sanity checks.
   * note : object_attributes is optional.
   */
  if(!p_parent_directory_handle || !p_context || !p_object_handle || !p_filename)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create);

  /* convert fsal mode to unix mode. */
  unix_mode = fsal2unix_mode(accessmode);

  /* Apply umask */
  unix_mode = unix_mode & ~global_fs_info.umask;

  LogFullDebug(COMPONENT_FSAL, "Creation mode: 0%o", accessmode);

  TakeTokenFSCall();
  status =
      fsal_internal_handle2fd(p_context, p_parent_directory_handle, &fd, O_DIRECTORY);
  ReleaseTokenFSCall();
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_create);

  /* retrieve directory metadata */
  TakeTokenFSCall();
  rc = fstat(fd, &buffstat);
  errsv = errno;
  ReleaseTokenFSCall();
  if(rc)
    {
      close(fd);

      if(errsv == ENOENT)
        Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_create);
      else
        Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create);
    }

  /* Check the user can write in the directory, and check the setgid bit on the directory */

  if(buffstat.st_mode & S_ISGID)
    setgid_bit = 1;

  status = fsal_internal_testAccess(p_context, FSAL_W_OK | FSAL_X_OK, &buffstat, NULL);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_create);

  /* call to filesystem */

  TakeTokenFSCall();
  /* create the file.
   * O_EXCL=>  error if the file already exists */
  newfd = openat(fd, p_filename->name, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, unix_mode);
  errsv = errno;

  if(newfd == -1)
    {
      close(fd);
      ReleaseTokenFSCall();
      Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create);
    }

  /* get the new file handle */
  status = fsal_internal_fd2handle(p_context, newfd, p_object_handle);

  ReleaseTokenFSCall();

  if(FSAL_IS_ERROR(status))
    {
      close(fd);
      close(newfd);
      ReturnStatus(status, INDEX_FSAL_create);
    }
  /* the file has been created */
  /* chown the file to the current user */

  if(((xfsfsal_op_context_t *)p_context)->credential.user != geteuid())
    {
      TakeTokenFSCall();
      /* if the setgid_bit was set on the parent directory, do not change the group of the created file, because it's already the parentdir's group */
      rc = fchown(newfd, ((xfsfsal_op_context_t *)p_context)->credential.user,
                  setgid_bit ? -1 : (int)((xfsfsal_op_context_t *)p_context)->credential.group);
      errsv = errno;
      ReleaseTokenFSCall();
      if(rc)
        {
          close(fd);
          close(newfd);
          Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create);
        }
    }

  close(fd);
  close(newfd);

  /* retrieve file attributes */
  if(p_object_attributes)
    {
      status = XFSFSAL_getattrs(p_object_handle, p_context, p_object_attributes);

      /* on error, we set a special bit in the mask. */
      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
          FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }

    }

  /* OK */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_create);

}
Ejemplo n.º 16
0
/**
 * FSAL_mknode:
 * Create a special object in the filesystem.
 * Not supported upon HPSS.
 *
 * \return ERR_FSAL_NOTSUPP.
 */
fsal_status_t XFSFSAL_mknode(fsal_handle_t * parentdir_handle,       /* IN */
                             fsal_name_t * p_node_name, /* IN */
                             fsal_op_context_t * p_context,  /* IN */
                             fsal_accessmode_t accessmode,      /* IN */
                             fsal_nodetype_t nodetype,  /* IN */
                             fsal_dev_t * dev,  /* IN */
                             fsal_handle_t * p_object_handle, /* OUT (handle to the created node) */
                             fsal_attrib_list_t * node_attributes       /* [ IN/OUT ] */
    )
{
  int rc, errsv;
  int setgid_bit = 0;
  struct stat buffstat;
  fsal_status_t status;
  int fd, newfd;

  mode_t unix_mode = 0;
  dev_t unix_dev = 0;

  /* sanity checks.
   * note : link_attributes is optional.
   */
  if(!parentdir_handle || !p_context || !p_node_name)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mknode);

  unix_mode = fsal2unix_mode(accessmode);

  /* Apply umask */
  unix_mode = unix_mode & ~global_fs_info.umask;

  switch (nodetype)
    {
    case FSAL_TYPE_BLK:
      if(!dev)
        Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mknode);
      unix_mode |= S_IFBLK;
      unix_dev = (dev->major << 8) | (dev->minor & 0xFF);
      break;

    case FSAL_TYPE_CHR:
      if(!dev)
        Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mknode);
      unix_mode |= S_IFCHR;
      unix_dev = (dev->major << 8) | (dev->minor & 0xFF);
      break;

    case FSAL_TYPE_SOCK:
      unix_mode |= S_IFSOCK;
      break;

    case FSAL_TYPE_FIFO:
      unix_mode |= S_IFIFO;
      break;

    default:
      LogMajor(COMPONENT_FSAL, "Invalid node type in FSAL_mknode: %d",
                        nodetype);
      Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_mknode);
    }

  /* build the directory path */
  TakeTokenFSCall();
  status = fsal_internal_handle2fd(p_context, parentdir_handle, &fd, O_DIRECTORY);
  ReleaseTokenFSCall();

  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_mknode);

  /* retrieve directory attributes */
  TakeTokenFSCall();
  rc = fstat(fd, &buffstat);
  errsv = errno;
  ReleaseTokenFSCall();

  if(rc)
    {
      close(fd);

      if(errsv == ENOENT)
        Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_mknode);
      else
        Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mknode);
    }

  /* Check the user can write in the directory, and check weither the setgid bit on the directory */
  if(buffstat.st_mode & S_ISGID)
    setgid_bit = 1;

  status = fsal_internal_testAccess(p_context, FSAL_W_OK | FSAL_X_OK, &buffstat, NULL);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_mknode);

  /* creates the node, then stats it */
  TakeTokenFSCall();
  rc = mknodat(fd, p_node_name->name, unix_mode, unix_dev);
  errsv = errno;

  if(rc)
    {
      close(fd);
      ReleaseTokenFSCall();
      Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mknode);
    }

  /* get the new object handle */
  if((newfd = openat(fd, p_node_name->name, O_RDONLY, 0600)) < 0)
    {
      errsv = errno;
      close(fd);
      ReleaseTokenFSCall();
      Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir);
    }

  status = fsal_internal_fd2handle(p_context, newfd, p_object_handle);
  ReleaseTokenFSCall();

  if(FSAL_IS_ERROR(status))
    {
      close(fd);
      close(newfd);
      ReturnStatus(status, INDEX_FSAL_mknode);
    }

  /* the node has been created */
  /* chown the file to the current user/group */

  if(((xfsfsal_op_context_t *)p_context)->credential.user != geteuid())
    {
      TakeTokenFSCall();

      /* if the setgid_bit was set on the parent directory, do not change the group of the created file, because it's already the parentdir's group */
      rc = fchown(newfd, ((xfsfsal_op_context_t *)p_context)->credential.user,
                  setgid_bit ? -1 : (int)((xfsfsal_op_context_t *)p_context)->credential.group);
      errsv = errno;

      ReleaseTokenFSCall();

      if(rc)
        {
          close(fd);
          close(newfd);
          Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mknode);
        }
    }

  close(fd);
  close(newfd);

  /* Fills the attributes if needed */
  if(node_attributes)
    {

      status = XFSFSAL_getattrs(p_object_handle, p_context, node_attributes);

      /* on error, we set a special bit in the mask. */

      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(node_attributes->asked_attributes);
          FSAL_SET_MASK(node_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }

    }

  /* Finished */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_mknode);

}
Ejemplo n.º 17
0
static fsal_status_t lustre_makenode(struct fsal_obj_handle *dir_hdl,
				     const char *name,
				     object_file_type_t nodetype,	/* IN */
				     fsal_dev_t *dev,	/* IN */
				     struct attrlist *attrib,
				     struct fsal_obj_handle **handle)
{
	struct lustre_fsal_obj_handle *myself, *hdl;
	char dirpath[MAXPATHLEN];
	char newpath[MAXPATHLEN];
	struct stat stat;
	mode_t unix_mode;
	fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR;
	int rc = 0;
	dev_t unix_dev = 0;
	struct lustre_file_handle *dir_fh = NULL;
	const char *sock_name = NULL;
	struct lustre_file_handle *fh =
	    alloca(sizeof(struct lustre_file_handle));

	*handle = NULL;		/* poison it */
	if (!dir_hdl->ops->handle_is(dir_hdl, DIRECTORY)) {
		LogCrit(COMPONENT_FSAL,
			"Parent handle is not a directory. hdl = 0x%p",
			dir_hdl);

		return fsalstat(ERR_FSAL_NOTDIR, 0);
	}
	memset(fh, 0, sizeof(struct lustre_file_handle));
	myself =
	    container_of(dir_hdl, struct lustre_fsal_obj_handle, obj_handle);
	unix_mode = fsal2unix_mode(attrib->mode)
	    & ~op_ctx->fsal_export->ops->fs_umask(op_ctx->fsal_export);
	switch (nodetype) {
	case BLOCK_FILE:
		if (!dev) {
			fsal_error = ERR_FSAL_FAULT;
			goto errout;
		}
		unix_dev =
		    CRED_WRAP(op_ctx->creds, dev_t, makedev, dev->major,
			      dev->minor);
		break;
	case CHARACTER_FILE:
		if (!dev) {
			fsal_error = ERR_FSAL_FAULT;
			goto errout;

		}
		unix_dev =
		    CRED_WRAP(op_ctx->creds, dev_t, makedev, dev->major,
			      dev->minor);
		break;
	case FIFO_FILE:
		break;
	case SOCKET_FILE:
		dir_fh = myself->handle;
		sock_name = name;
		break;
	default:
		LogMajor(COMPONENT_FSAL, "Invalid node type in FSAL_mknode: %d",
			 nodetype);
		fsal_error = ERR_FSAL_INVAL;
		goto errout;
	}
	lustre_handle_to_path(dir_hdl->fs->path,
			      myself->handle, dirpath);
	rc = lstat(dirpath, &stat);
	if (rc < 0) {
		rc = errno;
		goto errout;
	}

	/* create it with no access because we are root when we do this */
	snprintf(newpath, MAXPATHLEN, "%s/%s", dirpath, name);
	rc =
	    CRED_WRAP(op_ctx->creds, int, mknod, newpath, unix_mode, unix_dev);
	if (rc < 0) {
		rc = errno;
		goto direrr;
	}
	rc =
	    get_stat_by_handle_at(dir_hdl->fs->path,
				  myself->handle, name, fh, &stat);
	if (rc < 0)
		goto direrr;

	/* allocate an obj_handle and fill it up */
	hdl = alloc_handle(fh, dir_hdl->fs,
			   &stat, NULL, dir_fh, sock_name,
			   op_ctx->fsal_export);
	if (hdl == NULL) {
		fsal_error = ERR_FSAL_NOMEM;
		goto unlinkout;
	}
	*handle = &hdl->obj_handle;
	return fsalstat(ERR_FSAL_NO_ERROR, 0);

 direrr:
	fsal_error = posix2fsal_error(rc);
 unlinkout:
	unlink(newpath);
 errout:
	return fsalstat(fsal_error, rc);
}
Ejemplo n.º 18
0
/**
 * GPFSFSAL_setattrs:
 * Set attributes for the object specified by its filehandle.
 *
 * \param filehandle (input):
 *        The handle of the object to get parameters.
 * \param cred (input):
 *        Authentication context for the operation (user,...).
 * \param attrib_set (mandatory input):
 *        The attributes to be set for the object.
 *        It defines the attributes that the caller
 *        wants to set and their values.
 * \param object_attributes (optionnal input/output):
 *        The post operation attributes for the object.
 *        As input, it defines the attributes that the caller
 *        wants to retrieve (by positioning flags into this structure)
 *        and the output is built considering this input
 *        (it fills the structure according to the flags it contains).
 *        May be NULL.
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - Another error code if an error occured.
 */
fsal_status_t GPFSFSAL_setattrs(fsal_handle_t * p_filehandle,       /* IN */
                            fsal_op_context_t * p_context,      /* IN */
                            fsal_attrib_list_t * p_attrib_set,  /* IN */
                            fsal_attrib_list_t * p_object_attributes    /* [ IN/OUT ] */
    )
{
  unsigned int i;
  fsal_status_t status;

  /* Buffer that will be passed to gpfs_ganesha API. */
  gpfsfsal_xstat_t buffxstat;

  /* Indicate if stat or acl or both should be changed. */
  int attr_valid = 0;

  /* Indiate which attribute in stat should be changed. */
  int attr_changed = 0;

  fsal_accessflags_t access_mask = 0;
  fsal_attrib_list_t wanted_attrs, current_attrs;

  /* sanity checks.
   * note : object_attributes is optional.
   */
  if(!p_filehandle || !p_context || !p_attrib_set)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_setattrs);

  /* local copy of attributes */
  wanted_attrs = *p_attrib_set;

  /* It does not make sense to setattr on a symlink */
  /* if(p_filehandle->type == DT_LNK)
     return fsal_internal_setattrs_symlink(p_filehandle, p_context, p_attrib_set,
     p_object_attributes);
   */
  /* First, check that FSAL attributes changes are allowed. */

  /* Is it allowed to change times ? */

  if(!global_fs_info.cansettime)
    {

      if(wanted_attrs.asked_attributes
         & (FSAL_ATTR_ATIME | FSAL_ATTR_CREATION | FSAL_ATTR_CTIME | FSAL_ATTR_MTIME))
        {
          /* handled as an unsettable attribute. */
          Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_setattrs);
        }
    }

  /* apply umask, if mode attribute is to be changed */
  if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_MODE))
    {
      wanted_attrs.mode &= (~global_fs_info.umask);
    }

  /* get current attributes */
  current_attrs.asked_attributes = GPFS_SUPPORTED_ATTRIBUTES;
  status = GPFSFSAL_getattrs(p_filehandle, p_context, &current_attrs);
  if(FSAL_IS_ERROR(status))
    {
      FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
      FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
      ReturnStatus(status, INDEX_FSAL_setattrs);
    }

  /***********
   *  CHMOD  *
   ***********/
  if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_MODE))
    {

      /* The POSIX chmod call don't affect the symlink object, but
       * the entry it points to. So we must ignore it.
       */
      if(current_attrs.type != FSAL_TYPE_LNK)
        {

#ifdef _USE_NFS4_ACL
          if(current_attrs.acl)
            {
              /* Check permission using ACL. */
              access_mask = FSAL_MODE_MASK_SET(0) |  /* Dummy. */
                            FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_ATTR);

              status = fsal_internal_testAccess(p_context, access_mask, NULL, &current_attrs);
              if(FSAL_IS_ERROR(status))
                ReturnStatus(status, INDEX_FSAL_setattrs);
            }
          else
            {
#endif
              /* For modifying mode, user must be root or the owner */
              if((p_context->credential.user != 0)
                 && (p_context->credential.user != current_attrs.owner))
                {
                  LogFullDebug(COMPONENT_FSAL,
                               "Permission denied for CHMOD opeartion: current owner=%d, credential=%d",
                               current_attrs.owner, p_context->credential.user);
                  Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
                }
#ifdef _USE_NFS4_ACL
             }
#endif
    
            attr_valid |= XATTR_STAT;
            attr_changed |= XATTR_MODE;
    
            /* Fill wanted mode. */
            buffxstat.buffstat.st_mode = fsal2unix_mode(wanted_attrs.mode);
            LogDebug(COMPONENT_FSAL,
                     "current mode = %o, new mode = %o",
                     fsal2unix_mode(current_attrs.mode), buffxstat.buffstat.st_mode);

        }

    }

  /***********
   *  CHOWN  *
   ***********/
  /* Only root can change uid and A normal user must be in the group he wants to set */
  if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_OWNER))
    {

#ifdef _USE_NFS4_ACL
      if(current_attrs.acl)
        {
          /* Check permission using ACL. */
          access_mask = FSAL_MODE_MASK_SET(0) |  /* Dummy. */
                        FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_OWNER);

          status = fsal_internal_testAccess(p_context, access_mask, NULL, &current_attrs);
          if(FSAL_IS_ERROR(status))
            ReturnStatus(status, INDEX_FSAL_setattrs);
        }
      else
        {
#endif
          /* For modifying owner, user must be root or current owner==wanted==client */
          if((p_context->credential.user != 0) &&
             ((p_context->credential.user != current_attrs.owner) ||
              (p_context->credential.user != wanted_attrs.owner)))
            {
              LogFullDebug(COMPONENT_FSAL,
                           "Permission denied for CHOWN opeartion: current owner=%d, credential=%d, new owner=%d",
                           current_attrs.owner, p_context->credential.user, wanted_attrs.owner);
              Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
            }
#ifdef _USE_NFS4_ACL
        }
#endif

    }

  if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_GROUP))
    {

#ifdef _USE_NFS4_ACL
      if(current_attrs.acl)
        {
          /* Check permission using ACL. */
          access_mask = FSAL_MODE_MASK_SET(0) |  /* Dummy. */
                        FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_OWNER);

          status = fsal_internal_testAccess(p_context, access_mask, NULL, &current_attrs);
          if(FSAL_IS_ERROR(status))
            ReturnStatus(status, INDEX_FSAL_setattrs);
        }
      else
        {
#endif
          /* For modifying group, user must be root or current owner */
          if((p_context->credential.user != 0)
             && (p_context->credential.user != current_attrs.owner))
            {
              Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
            }
    
          int in_grp = 0;
          /* set in_grp */
          if(p_context->credential.group == wanted_attrs.group)
            in_grp = 1;
          else
            for(i = 0; i < p_context->credential.nbgroups; i++)
              {
                if((in_grp = (wanted_attrs.group == p_context->credential.alt_groups[i])))
                  break;
              }
    
          /* it must also be in target group */
          if(p_context->credential.user != 0 && !in_grp)
            {
              LogFullDebug(COMPONENT_FSAL,
                           "Permission denied for CHOWN operation: current group=%d, credential=%d, new group=%d",
                           current_attrs.group, p_context->credential.group, wanted_attrs.group);
              Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
            }
#ifdef _USE_NFS4_ACL
        }
#endif
    }

  if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_OWNER | FSAL_ATTR_GROUP))
    {
      /*      LogFullDebug(COMPONENT_FSAL, "Performing chown(%s, %d,%d)",
                        fsalpath.path, FSAL_TEST_MASK(wanted_attrs.asked_attributes,
                                                      FSAL_ATTR_OWNER) ? (int)wanted_attrs.owner
                        : -1, FSAL_TEST_MASK(wanted_attrs.asked_attributes,
			FSAL_ATTR_GROUP) ? (int)wanted_attrs.group : -1);*/

      attr_valid |= XATTR_STAT;
      attr_changed |= FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_OWNER) ?
                      XATTR_UID : XATTR_GID;

      /* Fill wanted owner. */
      if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_OWNER))
        {
          buffxstat.buffstat.st_uid = (int)wanted_attrs.owner;
          LogDebug(COMPONENT_FSAL,
                   "current uid = %d, new uid = %d",
                   current_attrs.owner, buffxstat.buffstat.st_uid);
        }

      /* Fill wanted group. */
      if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_GROUP))
        {
          buffxstat.buffstat.st_gid = (int)wanted_attrs.group;
          LogDebug(COMPONENT_FSAL,
                   "current gid = %d, new gid = %d",
                   current_attrs.group, buffxstat.buffstat.st_gid);
        }

    }

  /***********
   *  UTIME  *
   ***********/

  /* user must be the owner or have read access to modify 'atime' */
  access_mask = FSAL_MODE_MASK_SET(FSAL_R_OK) |
                FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_ATTR);
  if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_ATIME)
     && (p_context->credential.user != 0)
     && (p_context->credential.user != current_attrs.owner)
     && ((status = fsal_internal_testAccess(p_context, access_mask, NULL, &current_attrs)).major
         != ERR_FSAL_NO_ERROR))
    {
      ReturnStatus(status, INDEX_FSAL_setattrs);
    }
  /* user must be the owner or have write access to modify 'mtime' */
  access_mask = FSAL_MODE_MASK_SET(FSAL_W_OK) |
                FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_ATTR);
  if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_MTIME)
     && (p_context->credential.user != 0)
     && (p_context->credential.user != current_attrs.owner)
     && ((status = fsal_internal_testAccess(p_context, access_mask, NULL, &current_attrs)).major
         != ERR_FSAL_NO_ERROR))
    {
      ReturnStatus(status, INDEX_FSAL_setattrs);
    }

  if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_ATIME | FSAL_ATTR_MTIME))
    {
      attr_valid |= XATTR_STAT;

      /* Fill wanted atime. */
      if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_ATIME))
        {
          attr_changed |= XATTR_ATIME;
          buffxstat.buffstat.st_atime = (time_t) wanted_attrs.atime.seconds;
          LogDebug(COMPONENT_FSAL,
                   "current atime = %lu, new atime = %lu",
                   (unsigned long)current_attrs.atime.seconds, (unsigned long)buffxstat.buffstat.st_atime);
        }

      /* Fill wanted mtime. */
      if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_MTIME))
        {
          attr_changed |= XATTR_CTIME;
          buffxstat.buffstat.st_mtime = (time_t) wanted_attrs.mtime.seconds;
          LogDebug(COMPONENT_FSAL,
                   "current mtime = %lu, new mtime = %lu",
                   (unsigned long)current_attrs.mtime.seconds, (unsigned long)buffxstat.buffstat.st_mtime);
        }
    }

#ifdef _USE_NFS4_ACL
   /***********
   *  ACL  *
   ***********/

  if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_ACL))
    {
      /* Check permission to set ACL. */
      access_mask = FSAL_MODE_MASK_SET(0) |  /* Dummy */
                    FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_ACL);

      status = fsal_internal_testAccess(p_context, access_mask, NULL, &current_attrs);
      if(FSAL_IS_ERROR(status))
        ReturnStatus(status, INDEX_FSAL_setattrs);

      if(wanted_attrs.acl)
        {
          attr_valid |= XATTR_ACL;
          LogDebug(COMPONENT_FSAL, "setattr acl = %p", wanted_attrs.acl);

          /* Convert FSAL ACL to GPFS NFS4 ACL and fill the buffer. */
          status = fsal_acl_2_gpfs_acl(wanted_attrs.acl, &buffxstat);

          if(FSAL_IS_ERROR(status))
            ReturnStatus(status, INDEX_FSAL_setattrs);
        }
      else
        {
          LogCrit(COMPONENT_FSAL, "setattr acl is NULL");
          Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_setattrs);
        }
    }
#endif                          /* _USE_NFS4_ACL */

  /* If there is any change in stat or acl or both, send it down to file system. */
  if((attr_valid == XATTR_STAT && attr_changed !=0) || attr_valid == XATTR_ACL)
    {
      status = fsal_set_xstat_by_handle(p_context,
                                        p_filehandle,
                                        attr_valid,
                                        attr_changed,
                                        &buffxstat);

      if(FSAL_IS_ERROR(status))
        ReturnStatus(status, INDEX_FSAL_setattrs);
    }

  /* Optionaly fills output attributes. */

  if(p_object_attributes)
    {
      status = GPFSFSAL_getattrs(p_filehandle, p_context, p_object_attributes);

      /* on error, we set a special bit in the mask. */
      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
          FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }

    }

  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_setattrs);

}
Ejemplo n.º 19
0
/**
 * FSAL_mkdir:
 * Create a directory.
 *
 * \param parent_directory_handle (input):
 *        Handle of the parent directory where
 *        the subdirectory is to be created.
 * \param p_dirname (input):
 *        Pointer to the name of the directory to be created.
 * \param cred (input):
 *        Authentication context for the operation (user,...).
 * \param accessmode (input):
 *        Mode for the directory to be created.
 *        (the umask defined into the FSAL configuration file
 *        will be applied on it).
 * \param object_handle (output):
 *        Pointer to the handle of the created directory.
 * \param object_attributes (optionnal input/output): 
 *        The attributes of the created directory.
 *        As input, it defines the attributes that the caller
 *        wants to retrieve (by positioning flags into this structure)
 *        and the output is built considering this input
 *        (it fills the structure according to the flags it contains).
 *        May be NULL.
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - Another error code if an error occured.
 */
fsal_status_t GPFSFSAL_mkdir(fsal_handle_t * p_parent_directory_handle,     /* IN */
                         fsal_name_t * p_dirname,       /* IN */
                         fsal_op_context_t * p_context, /* IN */
                         fsal_accessmode_t accessmode,  /* IN */
                         fsal_handle_t * p_object_handle,       /* OUT */
                         fsal_attrib_list_t * p_object_attributes       /* [ IN/OUT ] */
    )
{
/*   int setgid_bit = 0; */
  mode_t unix_mode;
  fsal_status_t status;
  fsal_accessflags_t access_mask = 0;
  fsal_attrib_list_t parent_dir_attrs;

  /* sanity checks.
   * note : object_attributes is optional.
   */
  if(!p_parent_directory_handle || !p_context || !p_object_handle || !p_dirname)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mkdir);

  /* convert FSAL mode to unix mode. */
  unix_mode = fsal2unix_mode(accessmode);

  /* Apply umask */
  unix_mode = unix_mode & ~global_fs_info.umask;

  /* get directory metadata */
  parent_dir_attrs.asked_attributes = GPFS_SUPPORTED_ATTRIBUTES;
  status = GPFSFSAL_getattrs(p_parent_directory_handle, p_context, &parent_dir_attrs);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_mkdir);

  /* Check the user can write in the directory, and check the setgid bit on the directory */

/*   if(fsal2unix_mode(parent_dir_attrs.mode) & S_ISGID) */
/*     setgid_bit = 1; */

  /* Set both mode and ace4 mask */
  access_mask = FSAL_MODE_MASK_SET(FSAL_W_OK | FSAL_X_OK) |
                FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_ADD_SUBDIRECTORY);

  if(!p_context->export_context->fe_static_fs_info->accesscheck_support)
  status = fsal_internal_testAccess(p_context, access_mask, NULL, &parent_dir_attrs);
  else
    status = fsal_internal_access(p_context, p_parent_directory_handle, access_mask,
                                  &parent_dir_attrs);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_mkdir);

  /* build new entry path */

  /* creates the directory and get its handle */

  fsal_set_credentials(p_context);

  TakeTokenFSCall();
  status = fsal_internal_create(p_context, p_parent_directory_handle,
                                p_dirname, unix_mode | S_IFDIR, 0,
                                p_object_handle, NULL);
  ReleaseTokenFSCall();
  fsal_restore_ganesha_credentials();

  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_mkdir);

  /* retrieve file attributes */
  if(p_object_attributes)
    {
      status = GPFSFSAL_getattrs(p_object_handle, p_context, p_object_attributes);

      /* on error, we set a special bit in the mask. */
      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
          FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }

    }

  /* OK */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_mkdir);

}
Ejemplo n.º 20
0
/**
 * FSAL_mkdir:
 * Create a directory.
 *
 * \param parent_directory_handle (input):
 *        Handle of the parent directory where
 *        the subdirectory is to be created.
 * \param p_dirname (input):
 *        Pointer to the name of the directory to be created.
 * \param cred (input):
 *        Authentication context for the operation (user,...).
 * \param accessmode (input):
 *        Mode for the directory to be created.
 *        (the umask defined into the FSAL configuration file
 *        will be applied on it).
 * \param object_handle (output):
 *        Pointer to the handle of the created directory.
 * \param object_attributes (optionnal input/output): 
 *        The attributes of the created directory.
 *        As input, it defines the attributes that the caller
 *        wants to retrieve (by positioning flags into this structure)
 *        and the output is built considering this input
 *        (it fills the structure according to the flags it contains).
 *        May be NULL.
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - Another error code if an error occured.
 */
fsal_status_t POSIXFSAL_mkdir(fsal_handle_t * parent_directory_handle,   /* IN */
                              fsal_name_t * p_dirname,  /* IN */
                              fsal_op_context_t * context,       /* IN */
                              fsal_accessmode_t accessmode,     /* IN */
                              fsal_handle_t * object_handle,     /* OUT */
                              fsal_attrib_list_t * p_object_attributes  /* [ IN/OUT ] */
    )
{

  posixfsal_handle_t * p_parent_directory_handle
    = (posixfsal_handle_t *) parent_directory_handle;
  posixfsal_op_context_t * p_context = (posixfsal_op_context_t *) context;
  posixfsal_handle_t * p_object_handle = (posixfsal_handle_t *) object_handle;
  int rc, errsv;
  int setgid_bit = 0;
  struct stat buffstat;
  mode_t unix_mode;
  fsal_status_t status;
  fsal_path_t fsalpath;
  fsal_posixdb_fileinfo_t info;

  /* sanity checks.
   * note : object_attributes is optional.
   */
  if(!p_parent_directory_handle || !p_context || !p_object_handle || !p_dirname)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mkdir);

  /* convert FSAL mode to HPSS mode. */
  unix_mode = fsal2unix_mode(accessmode);

  /* Apply umask */
  unix_mode = unix_mode & ~global_fs_info.umask;

  /* build the destination path */
  status =
      fsal_internal_getPathFromHandle(p_context, p_parent_directory_handle, 1, &fsalpath,
                                      &buffstat);
  if(FSAL_IS_ERROR(status))
    Return(status.major, status.minor, INDEX_FSAL_mkdir);

  /* Check the user can write in the directory, and check the setgid bit on the directory */
  if(buffstat.st_mode & S_ISGID)
    setgid_bit = 1;

  status = fsal_internal_testAccess(p_context, FSAL_W_OK | FSAL_X_OK, &buffstat, NULL);
  if(FSAL_IS_ERROR(status))
    Return(status.major, status.minor, INDEX_FSAL_mkdir);

  status = fsal_internal_appendFSALNameToFSALPath(&fsalpath, p_dirname);
  if(FSAL_IS_ERROR(status))
    Return(status.major, status.minor, INDEX_FSAL_mkdir);

  /* creates the directory and stats it */
  TakeTokenFSCall();

  rc = mkdir(fsalpath.path, unix_mode);
  if(!rc)
    rc = lstat(fsalpath.path, &buffstat);
  errsv = errno;

  ReleaseTokenFSCall();

  if(rc)
    Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir);

  /* add the directory to the database */
  if(FSAL_IS_ERROR(status = fsal_internal_posix2posixdb_fileinfo(&buffstat, &info)))
    Return(status.major, status.minor, INDEX_FSAL_mkdir);
  if(FSAL_IS_ERROR
     (status =
      fsal_internal_posixdb_add_entry(p_context->p_conn, p_dirname, &info,
                                      p_parent_directory_handle, p_object_handle)))
    Return(status.major, status.minor, INDEX_FSAL_mkdir);

  /* the directory has been created */
  /* chown the file to the current user/group */

  if(p_context->credential.user != geteuid())
    {
      TakeTokenFSCall();
      /* if the setgid_bit was set on the parent directory, do not change the group of the created file, because it's already the parentdir's group */
      rc = lchown(fsalpath.path, p_context->credential.user,
                  setgid_bit ? -1 : (int)p_context->credential.group);
      errsv = errno;
      ReleaseTokenFSCall();
      if(rc)
        Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir);

      buffstat.st_uid = p_context->credential.user;
      buffstat.st_gid = p_context->credential.group;
    }

  /* Fills the attributes if needed */
  if(p_object_attributes)
    {

      status = posix2fsal_attributes(&buffstat, p_object_attributes);

      /* on error, we set a special bit in the mask. */

      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
          FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }

    }

  /* OK */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_mkdir);

}
Ejemplo n.º 21
0
/**
 * FSAL_create:
 * Create a regular file.
 *
 * \param parent_directory_handle (input):
 *        Handle of the parent directory where the file is to be created.
 * \param p_filename (input):
 *        Pointer to the name of the file to be created.
 * \param cred (input):
 *        Authentication context for the operation (user,...).
 * \param accessmode (input):
 *        Mode for the file to be created.
 *        (the umask defined into the FSAL configuration file
 *        will be applied on it).
 * \param object_handle (output):
 *        Pointer to the handle of the created file.
 * \param object_attributes (optional input/output): 
 *        The attributes of the created file.
 *        As input, it defines the attributes that the caller
 *        wants to retrieve (by positioning flags into this structure)
 *        and the output is built considering this input
 *        (it fills the structure according to the flags it contains).
 *        May be NULL.
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - Another error code if an error occurred.
 */
fsal_status_t GPFSFSAL_create(fsal_handle_t * p_parent_directory_handle,    /* IN */
                          fsal_name_t * p_filename,     /* IN */
                          fsal_op_context_t * p_context,        /* IN */
                          fsal_accessmode_t accessmode, /* IN */
                          fsal_handle_t * p_object_handle,      /* OUT */
                          fsal_attrib_list_t * p_object_attributes      /* [ IN/OUT ] */
    )
{
  fsal_status_t status;

  mode_t unix_mode;
  fsal_accessflags_t access_mask = 0;
  fsal_attrib_list_t parent_dir_attrs;

  /* sanity checks.
   * note : object_attributes is optional.
   */
  if(!p_parent_directory_handle || !p_context || !p_object_handle || !p_filename)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create);

  /* convert fsal mode to unix mode. */
  unix_mode = fsal2unix_mode(accessmode);

  /* Apply umask */
  unix_mode = unix_mode & ~global_fs_info.umask;

  LogFullDebug(COMPONENT_FSAL, "Creation mode: 0%o", accessmode);

  /* retrieve directory metadata */
  parent_dir_attrs.asked_attributes = GPFS_SUPPORTED_ATTRIBUTES;
  status = GPFSFSAL_getattrs(p_parent_directory_handle, p_context, &parent_dir_attrs);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_create);

  /* Check the user can write in the directory */

  /* Set both mode and ace4 mask */
  access_mask = FSAL_MODE_MASK_SET(FSAL_W_OK | FSAL_X_OK) |
                FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_ADD_FILE);

  if(!p_context->export_context->fe_static_fs_info->accesscheck_support)
  status = fsal_internal_testAccess(p_context, access_mask, NULL, &parent_dir_attrs);
  else
    status = fsal_internal_access(p_context, p_parent_directory_handle, access_mask,
                                  &parent_dir_attrs);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_create);

  /* call to filesystem */

  fsal_set_credentials(p_context);
  TakeTokenFSCall();
  status = fsal_internal_create(p_context, p_parent_directory_handle,
                                p_filename, unix_mode | S_IFREG, 0,
                                p_object_handle, NULL);
  ReleaseTokenFSCall();
  fsal_restore_ganesha_credentials();
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_create);

  /* retrieve file attributes */
  if(p_object_attributes)
    {
      status = GPFSFSAL_getattrs(p_object_handle, p_context, p_object_attributes);

      /* on error, we set a special bit in the mask. */
      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
          FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }

    }

  // error injection to test DRC
  //sleep(61);
  /* OK */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_create);

}
Ejemplo n.º 22
0
fsal_status_t GPFSFSAL_rename(fsal_handle_t * p_old_parentdir_handle,       /* IN */
                          fsal_name_t * p_old_name,     /* IN */
                          fsal_handle_t * p_new_parentdir_handle,       /* IN */
                          fsal_name_t * p_new_name,     /* IN */
                          fsal_op_context_t * p_context,        /* IN */
                          fsal_attrib_list_t * p_src_dir_attributes,    /* [ IN/OUT ] */
                          fsal_attrib_list_t * p_tgt_dir_attributes     /* [ IN/OUT ] */
    )
{

  int rc, errsv;
  fsal_status_t status;
  struct stat buffstat;
  int old_parent_fd, new_parent_fd;
  int src_equal_tgt = FALSE;
  fsal_accessflags_t access_mask = 0;
  fsal_attrib_list_t src_dir_attrs, tgt_dir_attrs;

  /* sanity checks.
   * note : src/tgt_dir_attributes are optional.
   */
  if(!p_old_parentdir_handle || !p_new_parentdir_handle
     || !p_old_name || !p_new_name || !p_context)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_rename);

  /* Get directory access path by fid */

  TakeTokenFSCall();
  status = fsal_internal_handle2fd(p_context, p_old_parentdir_handle,
                                   &old_parent_fd,
                                   O_RDONLY | O_DIRECTORY);
  ReleaseTokenFSCall();

  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_rename);

  /* retrieve directory metadata for checking access rights */

  src_dir_attrs.asked_attributes = GPFS_SUPPORTED_ATTRIBUTES;
  status = GPFSFSAL_getattrs(p_old_parentdir_handle, p_context, &src_dir_attrs);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_rename);

  /* optimisation : don't do the job twice if source dir = dest dir  */
  if(!FSAL_handlecmp(p_old_parentdir_handle, p_new_parentdir_handle, &status))
    {
      new_parent_fd = old_parent_fd;
      src_equal_tgt = TRUE;
      tgt_dir_attrs = src_dir_attrs;
    }
  else
    {
      TakeTokenFSCall();
      status = fsal_internal_handle2fd(p_context, p_new_parentdir_handle,
                                       &new_parent_fd,
                                       O_RDONLY | O_DIRECTORY);
      ReleaseTokenFSCall();

      if(FSAL_IS_ERROR(status))
        {
          close(old_parent_fd);
          ReturnStatus(status, INDEX_FSAL_rename);
        }

      /* retrieve destination attrs */
      tgt_dir_attrs.asked_attributes = GPFS_SUPPORTED_ATTRIBUTES;
      status = GPFSFSAL_getattrs(p_new_parentdir_handle, p_context, &tgt_dir_attrs);
      if(FSAL_IS_ERROR(status))
        ReturnStatus(status, INDEX_FSAL_rename);
    }

  /* check access rights */

  /* Set both mode and ace4 mask */
  access_mask = FSAL_MODE_MASK_SET(FSAL_W_OK | FSAL_X_OK) |
                FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_DELETE_CHILD);

  if(!p_context->export_context->fe_static_fs_info->accesscheck_support)
  status = fsal_internal_testAccess(p_context, access_mask, NULL, &src_dir_attrs);
  else
    status = fsal_internal_access(p_context, p_old_parentdir_handle, access_mask,
                                  &src_dir_attrs);
  if(FSAL_IS_ERROR(status)) {
    close(old_parent_fd);
    if (!src_equal_tgt)
      close(new_parent_fd);
    ReturnStatus(status, INDEX_FSAL_rename);
  }

  if(!src_equal_tgt)
    {
      access_mask = FSAL_MODE_MASK_SET(FSAL_W_OK | FSAL_X_OK) |
                FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_ADD_FILE |
                                   FSAL_ACE_PERM_ADD_SUBDIRECTORY);

	  if(!p_context->export_context->fe_static_fs_info->accesscheck_support)
      status = fsal_internal_testAccess(p_context, access_mask, NULL, &tgt_dir_attrs);
	  else
	    status = fsal_internal_access(p_context, p_new_parentdir_handle, access_mask,
	                                  &tgt_dir_attrs);
      if(FSAL_IS_ERROR(status)) {
        close(old_parent_fd);
        close(new_parent_fd);
        ReturnStatus(status, INDEX_FSAL_rename);
      }
    }

  /* build file paths */
  TakeTokenFSCall();
  rc = fstatat(old_parent_fd, p_old_name->name, &buffstat, AT_SYMLINK_NOFOLLOW);
  errsv = errno;
  ReleaseTokenFSCall();
  if(rc) {
    close(old_parent_fd);
    if (!src_equal_tgt)
      close(new_parent_fd);
    Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename);
  }

  /* Check sticky bits */

  /* Sticky bit on the source directory => the user who wants to delete the file must own it or its parent dir */
  if((fsal2unix_mode(src_dir_attrs.mode) & S_ISVTX) &&
     src_dir_attrs.owner != p_context->credential.user &&
     buffstat.st_uid != p_context->credential.user && p_context->credential.user != 0) {
    close(old_parent_fd);
    if (!src_equal_tgt)
      close(new_parent_fd);
    Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_rename);
  }

  /* Sticky bit on the target directory => the user who wants to create the file must own it or its parent dir */
  if(fsal2unix_mode(tgt_dir_attrs.mode) & S_ISVTX)
    {
      TakeTokenFSCall();
      rc = fstatat(new_parent_fd, p_new_name->name, &buffstat, AT_SYMLINK_NOFOLLOW);
      errsv = errno;
      ReleaseTokenFSCall();

      if(rc < 0)
        {
          if(errsv != ENOENT)
            {
              close(old_parent_fd);
              if (!src_equal_tgt)
                close(new_parent_fd);
              Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename);
            }
        }
      else
        {

          if(tgt_dir_attrs.owner != p_context->credential.user
             && buffstat.st_uid != p_context->credential.user
             && p_context->credential.user != 0)
            {
              close(old_parent_fd);
              if (!src_equal_tgt)
                close(new_parent_fd);
              Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_rename);
            }
        }
    }

  /*************************************
   * Rename the file on the filesystem *
   *************************************/
  TakeTokenFSCall();
  rc = renameat(old_parent_fd, p_old_name->name, new_parent_fd, p_new_name->name);
  errsv = errno;
  ReleaseTokenFSCall();
  close(old_parent_fd);
  if (!src_equal_tgt)
    close(new_parent_fd);

  if(rc)
    Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename);

  /***********************
   * Fill the attributes *
   ***********************/

  if(p_src_dir_attributes)
    {

      status = GPFSFSAL_getattrs(p_old_parentdir_handle, p_context, p_src_dir_attributes);

      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(p_src_dir_attributes->asked_attributes);
          FSAL_SET_MASK(p_src_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }

    }

  if(p_tgt_dir_attributes)
    {

      status = GPFSFSAL_getattrs(p_new_parentdir_handle, p_context, p_tgt_dir_attributes);

      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(p_tgt_dir_attributes->asked_attributes);
          FSAL_SET_MASK(p_tgt_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }

    }

  /* OK */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_rename);

}
Ejemplo n.º 23
0
/**
 * FSAL_mknode:
 * Create a special object in the filesystem.
 * Not supported upon HPSS.
 *
 * \return ERR_FSAL_NOTSUPP.
 */
fsal_status_t POSIXFSAL_mknode(fsal_handle_t * parentdir_hdl,   /* IN */
                               fsal_name_t * p_node_name,       /* IN */
                               fsal_op_context_t * context,      /* IN */
                               fsal_accessmode_t accessmode,    /* IN */
                               fsal_nodetype_t nodetype,        /* IN */
                               fsal_dev_t * dev,        /* IN */
                               fsal_handle_t * object_handle,    /* OUT (handle to the created node) */
                               fsal_attrib_list_t * node_attributes     /* [ IN/OUT ] */
    )
{
  posixfsal_handle_t * parentdir_handle = (posixfsal_handle_t *) parentdir_hdl;
  posixfsal_op_context_t * p_context = (posixfsal_op_context_t *) context;
  posixfsal_handle_t * p_object_handle = (posixfsal_handle_t *) object_handle;
  int rc, errsv;
  int setgid_bit = 0;
  struct stat buffstat;
  fsal_status_t status;
  fsal_path_t fsalpath;
  fsal_posixdb_fileinfo_t info;

  mode_t unix_mode = 0;
  dev_t unix_dev = 0;

  /* sanity checks.
   * note : link_attributes is optional.
   */
  if(!parentdir_handle || !p_context || !p_node_name)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mknode);

  unix_mode = fsal2unix_mode(accessmode);

  /* Apply umask */
  unix_mode = unix_mode & ~global_fs_info.umask;

  switch (nodetype)
    {
    case FSAL_TYPE_BLK:
      if(!dev)
        Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mknode);
      unix_mode |= S_IFBLK;
      unix_dev = (dev->major << 8) | (dev->minor & 0xFF);
      break;

    case FSAL_TYPE_CHR:
      if(!dev)
        Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mknode);
      unix_mode |= S_IFCHR;
      unix_dev = (dev->major << 8) | (dev->minor & 0xFF);
      break;

    case FSAL_TYPE_SOCK:
      unix_mode |= S_IFSOCK;
      break;

    case FSAL_TYPE_FIFO:
      unix_mode |= S_IFIFO;
      break;

    default:
      LogMajor(COMPONENT_FSAL, "Invalid node type in FSAL_mknode: %d", nodetype);
      Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_mknode);
    }

  /* build the destination path */
  status =
      fsal_internal_getPathFromHandle(p_context, parentdir_handle, 1, &fsalpath,
                                      &buffstat);
  if(FSAL_IS_ERROR(status))
    Return(status.major, status.minor, INDEX_FSAL_mknode);

  /* Check the user can write in the directory, and check weither the setgid bit on the directory */
  if(buffstat.st_mode & S_ISGID)
    setgid_bit = 1;

  status = fsal_internal_testAccess(p_context, FSAL_W_OK | FSAL_X_OK, &buffstat, NULL);
  if(FSAL_IS_ERROR(status))
    Return(status.major, status.minor, INDEX_FSAL_mknode);

  status = fsal_internal_appendFSALNameToFSALPath(&fsalpath, p_node_name);
  if(FSAL_IS_ERROR(status))
    Return(status.major, status.minor, INDEX_FSAL_mknode);

  /* creates the node, then stats it */
  TakeTokenFSCall();

  rc = mknod(fsalpath.path, unix_mode, unix_dev);
  if(!rc)
    rc = lstat(fsalpath.path, &buffstat);
  errsv = errno;

  ReleaseTokenFSCall();

  if(rc)
    Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mknode);

  /* add the object to the database */
  if(FSAL_IS_ERROR(status = fsal_internal_posix2posixdb_fileinfo(&buffstat, &info)))
    Return(status.major, status.minor, INDEX_FSAL_mknode);

  if(FSAL_IS_ERROR
     (status =
      fsal_internal_posixdb_add_entry(p_context->p_conn, p_node_name, &info,
                                      parentdir_handle, p_object_handle)))
    Return(status.major, status.minor, INDEX_FSAL_mknode);

  /* the node has been created */
  /* chown the file to the current user/group */

  if(p_context->credential.user != geteuid())
    {
      TakeTokenFSCall();

      /* if the setgid_bit was set on the parent directory, do not change the group of the created file, because it's already the parentdir's group */
      rc = lchown(fsalpath.path, p_context->credential.user,
                  setgid_bit ? -1 : (int)p_context->credential.group);
      errsv = errno;

      ReleaseTokenFSCall();

      if(rc)
        Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mknode);

      buffstat.st_uid = p_context->credential.user;
      buffstat.st_gid = p_context->credential.group;
    }

  /* Fills the attributes if needed */
  if(node_attributes)
    {

      status = posix2fsal_attributes(&buffstat, node_attributes);

      /* on error, we set a special bit in the mask. */

      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(node_attributes->asked_attributes);
          FSAL_SET_MASK(node_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }

    }

  /* Finished */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_mknode);

}
Ejemplo n.º 24
0
static fsal_status_t makedir(struct fsal_obj_handle *dir_hdl,
			     const struct req_op_context *opctx,
			     const char *name, struct attrlist *attrib,
			     struct fsal_obj_handle **handle)
{
	int rc = 0;
	fsal_status_t status = { ERR_FSAL_NO_ERROR, 0 };
	struct stat sb;
	struct glfs_object *glhandle = NULL;
	unsigned char globjhdl[GLAPI_HANDLE_LENGTH];
	struct glusterfs_handle *objhandle = NULL;
	struct glusterfs_export *glfs_export =
	    container_of(dir_hdl->export, struct glusterfs_export, export);
	struct glusterfs_handle *parenthandle =
	    container_of(dir_hdl, struct glusterfs_handle, handle);
#ifdef GLTIMING
	struct timespec s_time, e_time;

	now(&s_time);
#endif

	rc = setglustercreds(glfs_export, &opctx->creds->caller_uid,
			     &opctx->creds->caller_gid,
			     opctx->creds->caller_glen,
			     opctx->creds->caller_garray);
	if (rc != 0) {
		status = gluster2fsal_error(EPERM);
		LogFatal(COMPONENT_FSAL, "Could not set Ganesha credentials");
		goto out;
	}

	/* FIXME: what else from attrib should we use? */
	glhandle =
	    glfs_h_mkdir(glfs_export->gl_fs, parenthandle->glhandle, name,
			 fsal2unix_mode(attrib->mode), &sb);

	rc = setglustercreds(glfs_export, NULL, NULL, 0, NULL);
	if (rc != 0) {
		status = gluster2fsal_error(EPERM);
		LogFatal(COMPONENT_FSAL, "Could not set Ganesha credentials");
		goto out;
	}

	if (glhandle == NULL) {
		status = gluster2fsal_error(errno);
		goto out;
	}

	rc = glfs_h_extract_handle(glhandle, globjhdl, GLAPI_HANDLE_LENGTH);
	if (rc < 0) {
		status = gluster2fsal_error(errno);
		goto out;
	}

	rc = construct_handle(glfs_export, &sb, glhandle, globjhdl,
			      GLAPI_HANDLE_LENGTH, &objhandle);
	if (rc != 0) {
		status = gluster2fsal_error(rc);
		goto out;
	}

	*handle = &objhandle->handle;
	*attrib = objhandle->handle.attributes;

 out:
	if (status.major != ERR_FSAL_NO_ERROR) {
		gluster_cleanup_vars(glhandle);
	}
#ifdef GLTIMING
	now(&e_time);
	latency_update(&s_time, &e_time, lat_makedir);
#endif
	return status;
}
Ejemplo n.º 25
0
/**
 * FSAL_mkdir:
 * Create a directory.
 *
 * \param parent_directory_handle (input):
 *        Handle of the parent directory where
 *        the subdirectory is to be created.
 * \param p_dirname (input):
 *        Pointer to the name of the directory to be created.
 * \param cred (input):
 *        Authentication context for the operation (user,...).
 * \param accessmode (input):
 *        Mode for the directory to be created.
 *        (the umask defined into the FSAL configuration file
 *        will be applied on it).
 * \param object_handle (output):
 *        Pointer to the handle of the created directory.
 * \param object_attributes (optionnal input/output): 
 *        The attributes of the created directory.
 *        As input, it defines the attributes that the caller
 *        wants to retrieve (by positioning flags into this structure)
 *        and the output is built considering this input
 *        (it fills the structure according to the flags it contains).
 *        May be NULL.
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - Another error code if an error occured.
 */
fsal_status_t GPFSFSAL_mkdir(fsal_handle_t * p_parent_directory_handle,     /* IN */
                         fsal_name_t * p_dirname,       /* IN */
                         fsal_op_context_t * p_context, /* IN */
                         fsal_accessmode_t accessmode,  /* IN */
                         fsal_handle_t * p_object_handle,       /* OUT */
                         fsal_attrib_list_t * p_object_attributes       /* [ IN/OUT ] */
    )
{

  int rc, errsv;
  int setgid_bit = 0;
  mode_t unix_mode;
  fsal_status_t status;
  int fd, newfd;
  fsal_accessflags_t access_mask = 0;
  fsal_attrib_list_t parent_dir_attrs;

  /* sanity checks.
   * note : object_attributes is optional.
   */
  if(!p_parent_directory_handle || !p_context || !p_object_handle || !p_dirname)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mkdir);

  /* convert FSAL mode to unix mode. */
  unix_mode = fsal2unix_mode(accessmode);

  /* Apply umask */
  unix_mode = unix_mode & ~global_fs_info.umask;

  TakeTokenFSCall();
  status = fsal_internal_handle2fd(p_context, p_parent_directory_handle, &fd, O_RDONLY);
  ReleaseTokenFSCall();

  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_mkdir);

  /* get directory metadata */
  parent_dir_attrs.asked_attributes = GPFS_SUPPORTED_ATTRIBUTES;
  status = GPFSFSAL_getattrs(p_parent_directory_handle, p_context, &parent_dir_attrs);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_create);

  /* Check the user can write in the directory, and check the setgid bit on the directory */

  if(fsal2unix_mode(parent_dir_attrs.mode) & S_ISGID)
    setgid_bit = 1;

  /* Set both mode and ace4 mask */
  access_mask = FSAL_MODE_MASK_SET(FSAL_W_OK | FSAL_X_OK) |
                FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_ADD_SUBDIRECTORY);

  status = fsal_internal_testAccess(p_context, access_mask, NULL, &parent_dir_attrs);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_mkdir);

  /* build new entry path */

  /* creates the directory and get its handle */

  TakeTokenFSCall();
  rc = mkdirat(fd, p_dirname->name, unix_mode);
  errsv = errno;
  if(rc)
    {
      close(fd);

      ReleaseTokenFSCall();
      Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir);
    }

  ReleaseTokenFSCall();

  /****
   *  There is a race here between mkdir creation and the open, not
   *  sure there is any way to close it in practice.
   */

  /* get the new handle */
  TakeTokenFSCall();
  status = fsal_internal_get_handle_at(fd, p_dirname, p_object_handle);
  ReleaseTokenFSCall();

  if(FSAL_IS_ERROR(status))
    {
      close(fd);
      ReturnStatus(status, INDEX_FSAL_mkdir);
    }

  TakeTokenFSCall();
  status =
      fsal_internal_handle2fd_at(fd, p_object_handle, &newfd, O_RDONLY | O_DIRECTORY);
  ReleaseTokenFSCall();

  if(FSAL_IS_ERROR(status))
    {
      close(fd);
      ReturnStatus(status, INDEX_FSAL_mkdir);
    }

  /* the directory has been created */
  /* chown the dir to the current user/group */

  if(p_context->credential.user != geteuid())
    {
      TakeTokenFSCall();
      /* if the setgid_bit was set on the parent directory, do not change the group of the created file, because it's already the parentdir's group */
      rc = fchown(newfd, p_context->credential.user,
                  setgid_bit ? -1 : (int)p_context->credential.group);
      errsv = errno;
      ReleaseTokenFSCall();
      if(rc)
        {
          close(fd);
          close(newfd);
          Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir);
        }
    }

  close(fd);
  close(newfd);

  /* retrieve file attributes */
  if(p_object_attributes)
    {
      status = GPFSFSAL_getattrs(p_object_handle, p_context, p_object_attributes);

      /* on error, we set a special bit in the mask. */
      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
          FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }

    }

  /* OK */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_mkdir);

}
Ejemplo n.º 26
0
static fsal_status_t makenode(struct fsal_obj_handle *dir_hdl,
			      const struct req_op_context *opctx,
			      const char *name, object_file_type_t nodetype,
			      fsal_dev_t * dev, struct attrlist *attrib,
			      struct fsal_obj_handle **handle)
{
	int rc = 0;
	fsal_status_t status = { ERR_FSAL_NO_ERROR, 0 };
	struct stat sb;
	struct glfs_object *glhandle = NULL;
	unsigned char globjhdl[GLAPI_HANDLE_LENGTH];
	struct glusterfs_handle *objhandle = NULL;
	dev_t ndev = { 0, };
	struct glusterfs_export *glfs_export =
	    container_of(dir_hdl->export, struct glusterfs_export, export);
	struct glusterfs_handle *parenthandle =
	    container_of(dir_hdl, struct glusterfs_handle, handle);
	mode_t create_mode;
#ifdef GLTIMING
	struct timespec s_time, e_time;

	now(&s_time);
#endif

	switch (nodetype) {
	case BLOCK_FILE:
		if (!dev)
			return fsalstat(ERR_FSAL_INVAL, 0);
		/* FIXME: This needs a feature flag test? */
		ndev = makedev(dev->major, dev->minor);
		create_mode = S_IFBLK;
		break;
	case CHARACTER_FILE:
		if (!dev)
			return fsalstat(ERR_FSAL_INVAL, 0);
		ndev = makedev(dev->major, dev->minor);
		create_mode = S_IFCHR;
		break;
	case FIFO_FILE:
		create_mode = S_IFIFO;
		break;
	case SOCKET_FILE:
		create_mode = S_IFSOCK;
		break;
	default:
		LogMajor(COMPONENT_FSAL, "Invalid node type in FSAL_mknode: %d",
			 nodetype);
		return fsalstat(ERR_FSAL_INVAL, 0);
	}

	rc = setglustercreds(glfs_export, &opctx->creds->caller_uid,
			     &opctx->creds->caller_gid,
			     opctx->creds->caller_glen,
			     opctx->creds->caller_garray);
	if (rc != 0) {
		status = gluster2fsal_error(EPERM);
		LogFatal(COMPONENT_FSAL, "Could not set Ganesha credentials");
		goto out;
	}

	/* FIXME: what else from attrib should we use? */
	glhandle =
	    glfs_h_mknod(glfs_export->gl_fs, parenthandle->glhandle, name,
			 create_mode | fsal2unix_mode(attrib->mode), ndev, &sb);

	rc = setglustercreds(glfs_export, NULL, NULL, 0, NULL);
	if (rc != 0) {
		status = gluster2fsal_error(EPERM);
		LogFatal(COMPONENT_FSAL, "Could not set Ganesha credentials");
		goto out;
	}

	if (glhandle == NULL) {
		status = gluster2fsal_error(errno);
		goto out;
	}

	rc = glfs_h_extract_handle(glhandle, globjhdl, GLAPI_HANDLE_LENGTH);
	if (rc < 0) {
		status = gluster2fsal_error(errno);
		goto out;
	}

	rc = construct_handle(glfs_export, &sb, glhandle, globjhdl,
			      GLAPI_HANDLE_LENGTH, &objhandle);
	if (rc != 0) {
		status = gluster2fsal_error(rc);
		goto out;
	}

	*handle = &objhandle->handle;
	*attrib = objhandle->handle.attributes;

 out:
	if (status.major != ERR_FSAL_NO_ERROR) {
		gluster_cleanup_vars(glhandle);
	}
#ifdef GLTIMING
	now(&e_time);
	latency_update(&s_time, &e_time, lat_makenode);
#endif
	return status;
}
Ejemplo n.º 27
0
/**
 * FSAL_create:
 * Create a regular file.
 *
 * \param parent_directory_handle (input):
 *        Handle of the parent directory where the file is to be created.
 * \param p_filename (input):
 *        Pointer to the name of the file to be created.
 * \param cred (input):
 *        Authentication context for the operation (user,...).
 * \param accessmode (input):
 *        Mode for the file to be created.
 *        (the umask defined into the FSAL configuration file
 *        will be applied on it).
 * \param object_handle (output):
 *        Pointer to the handle of the created file.
 * \param object_attributes (optional input/output): 
 *        The attributes of the created file.
 *        As input, it defines the attributes that the caller
 *        wants to retrieve (by positioning flags into this structure)
 *        and the output is built considering this input
 *        (it fills the structure according to the flags it contains).
 *        May be NULL.
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - Another error code if an error occurred.
 */
fsal_status_t GPFSFSAL_create(fsal_handle_t * p_parent_directory_handle,    /* IN */
                          fsal_name_t * p_filename,     /* IN */
                          fsal_op_context_t * p_context,        /* IN */
                          fsal_accessmode_t accessmode, /* IN */
                          fsal_handle_t * p_object_handle,      /* OUT */
                          fsal_attrib_list_t * p_object_attributes      /* [ IN/OUT ] */
    )
{

  int rc = 0, errsv;
  int setgid_bit = 0;
  fsal_status_t status;

  int fd, newfd;
  mode_t unix_mode;
  fsal_accessflags_t access_mask = 0;
  fsal_attrib_list_t parent_dir_attrs;

  /* sanity checks.
   * note : object_attributes is optional.
   */
  if(!p_parent_directory_handle || !p_context || !p_object_handle || !p_filename)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create);

  /* convert fsal mode to unix mode. */
  unix_mode = fsal2unix_mode(accessmode);

  /* Apply umask */
  unix_mode = unix_mode & ~global_fs_info.umask;

  LogFullDebug(COMPONENT_FSAL, "Creation mode: 0%o", accessmode);

  TakeTokenFSCall();
  status =
      fsal_internal_handle2fd(p_context, p_parent_directory_handle, &fd,
                              O_RDONLY | O_DIRECTORY);
  ReleaseTokenFSCall();
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_create);

  /* retrieve directory metadata */
  parent_dir_attrs.asked_attributes = GPFS_SUPPORTED_ATTRIBUTES;
  status = GPFSFSAL_getattrs(p_parent_directory_handle, p_context, &parent_dir_attrs);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_create);

  /* Check the user can write in the directory, and check the setgid bit on the directory */

  if(fsal2unix_mode(parent_dir_attrs.mode) & S_ISGID)
    setgid_bit = 1;

  /* Set both mode and ace4 mask */
  access_mask = FSAL_MODE_MASK_SET(FSAL_W_OK | FSAL_X_OK) |
                FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_ADD_FILE);

  status = fsal_internal_testAccess(p_context, access_mask, NULL, &parent_dir_attrs);
  if(FSAL_IS_ERROR(status))
    ReturnStatus(status, INDEX_FSAL_create);

  /* call to filesystem */

  TakeTokenFSCall();
  /* create the file.
   * O_EXCL=>  error if the file already exists */
  newfd = openat(fd, p_filename->name, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, unix_mode);
  errsv = errno;

  if(newfd < 0)
    {
      close(fd);
      ReleaseTokenFSCall();
      Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create);
    }

  /* we no longer need the parent directory open any more */
  close(fd);

  /* close the file descriptor */
  /*** 
   * Previously the file handle was closed here.  I don't think that
   we need that, but leaving the commented out logic just in case.
   rc = close(newfd);
   
   errsv = errno;
   if(rc)
   {
   close(fd);
   ReleaseTokenFSCall();
   Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create);
   }
  */

  /* get a handle for this new fd, doing this directly ensures no race
     because we still have the fd open until the end of this function */
  status = fsal_internal_fd2handle(newfd, p_object_handle);
  ReleaseTokenFSCall();

  if(FSAL_IS_ERROR(status))
    {
      close(newfd);
      ReturnStatus(status, INDEX_FSAL_create);
    }

  /* the file has been created */
  /* chown the file to the current user */

  if(p_context->credential.user != geteuid())
    {
      TakeTokenFSCall();
      /* if the setgid_bit was set on the parent directory, do not change the group of the created file, because it's already the parentdir's group */
      rc = fchown(newfd, p_context->credential.user,
                  setgid_bit ? -1 : (int)p_context->credential.group);
      errsv = errno;
      ReleaseTokenFSCall();
      if(rc)
        {
          close(newfd);
          Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create);
        }
    }

  /* if we got this far successfully, but the file close fails, we've
     got a problem, possibly a disk full problem. */
  close(newfd);
  if(rc)
    Return(posix2fsal_error(errno), errno, INDEX_FSAL_create);

  /* retrieve file attributes */
  if(p_object_attributes)
    {
      status = GPFSFSAL_getattrs(p_object_handle, p_context, p_object_attributes);

      /* on error, we set a special bit in the mask. */
      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
          FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }

    }

  /* OK */
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_create);

}
Ejemplo n.º 28
0
static fsal_status_t setattrs(struct fsal_obj_handle *obj_hdl,
			      const struct req_op_context *opctx,
			      struct attrlist *attrs)
{
	int rc = 0;
	fsal_status_t status = { ERR_FSAL_NO_ERROR, 0 };
	struct stat sb;
	int mask = 0;
	struct glusterfs_export *glfs_export =
	    container_of(obj_hdl->export, struct glusterfs_export, export);
	struct glusterfs_handle *objhandle =
	    container_of(obj_hdl, struct glusterfs_handle, handle);
#ifdef GLTIMING
	struct timespec s_time, e_time;

	now(&s_time);
#endif

	memset(&sb, 0, sizeof(struct stat));

	if (FSAL_TEST_MASK(attrs->mask, ATTR_SIZE)) {
		rc = glfs_h_truncate(glfs_export->gl_fs, objhandle->glhandle,
				     attrs->filesize);
		if (rc != 0) {
			status = gluster2fsal_error(errno);
			goto out;
		}
	}

	if (FSAL_TEST_MASK(attrs->mask, ATTR_MODE)) {
		mask |= GLAPI_SET_ATTR_MODE;
		sb.st_mode = fsal2unix_mode(attrs->mode);
	}

	if (FSAL_TEST_MASK(attrs->mask, ATTR_OWNER)) {
		mask |= GLAPI_SET_ATTR_UID;
		sb.st_uid = attrs->owner;
	}

	if (FSAL_TEST_MASK(attrs->mask, ATTR_GROUP)) {
		mask |= GLAPI_SET_ATTR_GID;
		sb.st_gid = attrs->group;
	}

	if (FSAL_TEST_MASK(attrs->mask, ATTR_ATIME)) {
		mask |= GLAPI_SET_ATTR_ATIME;
		sb.st_atim = attrs->atime;
	}

	if (FSAL_TEST_MASK(attrs->mask, ATTR_ATIME_SERVER)) {
		mask |= GLAPI_SET_ATTR_ATIME;
		struct timespec timestamp;

		rc = clock_gettime(CLOCK_REALTIME, &timestamp);
		if (rc != 0) {
			status = gluster2fsal_error(errno);
			goto out;
		}
		sb.st_atim = timestamp;
	}

	if (FSAL_TEST_MASK(attrs->mask, ATTR_MTIME)) {
		mask |= GLAPI_SET_ATTR_MTIME;
		sb.st_mtim = attrs->mtime;
	}
	if (FSAL_TEST_MASK(attrs->mask, ATTR_MTIME_SERVER)) {
		mask |= GLAPI_SET_ATTR_MTIME;
		struct timespec timestamp;

		rc = clock_gettime(CLOCK_REALTIME, &timestamp);
		if (rc != 0) {
			status = gluster2fsal_error(rc);
			goto out;
		}
		sb.st_mtim = timestamp;
	}

	rc = glfs_h_setattrs(glfs_export->gl_fs, objhandle->glhandle, &sb,
			     mask);
	if (rc != 0) {
		status = gluster2fsal_error(errno);
		goto out;
	}

 out:
#ifdef GLTIMING
	now(&e_time);
	latency_update(&s_time, &e_time, lat_setattrs);
#endif
	return status;
}
Ejemplo n.º 29
0
/**
 * FSAL_create:
 * Create a regular file.
 *
 * \param parent_hdl (input):
 *        Handle of the parent directory where the file is to be created.
 * \param p_filename (input):
 *        Pointer to the name of the file to be created.
 * \param p_context (input):
 *        Authentication context for the operation (user,...).
 * \param accessmode (input):
 *        Mode for the file to be created.
 *        (the umask defined into the FSAL configuration file
 *        will be applied on it).
 * \param p_object_handle (output):
 *        Pointer to the handle of the created file.
 * \param p_object_attributes (optional input/output):
 *        The attributes of the created file.
 *        As input, it defines the attributes that the caller
 *        wants to retrieve (by positioning flags into this structure)
 *        and the output is built considering this input
 *        (it fills the structure according to the flags it contains).
 *        May be NULL.
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - Another error code if an error occurred.
 */
fsal_status_t PTFSAL_create(struct fsal_obj_handle *dir_hdl,	/* IN */
			    const char *p_filename,	/* IN */
			    const struct req_op_context *p_context,	/* IN */
			    uint32_t accessmode,	/* IN */
			    ptfsal_handle_t *p_object_handle,	/* OUT */
			    struct attrlist *p_object_attributes)
{				/* IN/OUT */

	int errsv;
	fsal_status_t status;
	struct pt_fsal_obj_handle *pt_hdl;
	mode_t unix_mode;
	int open_rc;
	ptfsal_handle_t *p_fsi_handle = (ptfsal_handle_t *) p_object_handle;

	FSI_TRACE(FSI_DEBUG, "Begin to create file************************\n");

	/* sanity checks.
	 * note : object_attributes is optional.
	 */
	if (!dir_hdl || !p_context || !p_object_handle || !p_filename)
		return fsalstat(ERR_FSAL_FAULT, 0);

	pt_hdl = container_of(dir_hdl, struct pt_fsal_obj_handle, obj_handle);

	/* convert fsal mode to unix mode. */
	unix_mode = fsal2unix_mode(accessmode);

	/* Apply umask */
	unix_mode = unix_mode & ~p_context->fsal_export->exp_ops.
			fs_umask(p_context->fsal_export);

	LogFullDebug(COMPONENT_FSAL, "Creation mode: 0%o", accessmode);

	open_rc =
	    ptfsal_open(pt_hdl, p_filename, p_context, unix_mode,
			p_object_handle);
	if (open_rc < 0) {
		errsv = errno;
		return fsalstat(posix2fsal_error(errsv), errsv);
	}

	FSI_TRACE(FSI_DEBUG, "New Handle = %s",
		  (char *)p_fsi_handle->data.handle.f_handle);

	/* retrieve file attributes */
	if (p_object_attributes) {
		status = PTFSAL_getattrs(p_context->fsal_export, p_context,
					 p_object_handle,
					 p_object_attributes);

		/* on error, we set a special bit in the mask. */
		if (FSAL_IS_ERROR(status)) {
			FSAL_CLEAR_MASK(p_object_attributes->mask);
			FSAL_SET_MASK(p_object_attributes->mask,
				      ATTR_RDATTR_ERR);
		}

	}

	FSI_TRACE(FSI_DEBUG, "End to create file************************\n");

	/* OK */
	return fsalstat(ERR_FSAL_NO_ERROR, 0);

}
Ejemplo n.º 30
0
/**
 * VFSFSAL_setattrs:
 * Set attributes for the object specified by its filehandle.
 *
 * \param filehandle (input):
 *        The handle of the object to get parameters.
 * \param cred (input):
 *        Authentication context for the operation (user,...).
 * \param attrib_set (mandatory input):
 *        The attributes to be set for the object.
 *        It defines the attributes that the caller
 *        wants to set and their values.
 * \param object_attributes (optionnal input/output):
 *        The post operation attributes for the object.
 *        As input, it defines the attributes that the caller
 *        wants to retrieve (by positioning flags into this structure)
 *        and the output is built considering this input
 *        (it fills the structure according to the flags it contains).
 *        May be NULL.
 *
 * \return Major error codes :
 *        - ERR_FSAL_NO_ERROR     (no error)
 *        - Another error code if an error occured.
 */
fsal_status_t VFSFSAL_setattrs(fsal_handle_t * p_filehandle,       /* IN */
                            fsal_op_context_t * p_context,      /* IN */
                            fsal_attrib_list_t * p_attrib_set,  /* IN */
                            fsal_attrib_list_t * p_object_attributes    /* [ IN/OUT ] */
    )
{
  vfsfsal_op_context_t * vfs_context = (vfsfsal_op_context_t *) p_context;
  int rc, errsv;
  unsigned int i;
  fsal_status_t status;
  fsal_attrib_list_t attrs;

  int fd;
  struct stat buffstat;

  /* sanity checks.
   * note : object_attributes is optional.
   */
  if(!p_filehandle || !p_context || !p_attrib_set)
    Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_setattrs);

  /* local copy of attributes */
  attrs = *p_attrib_set;

  /* It does not make sense to setattr on a symlink */
  /* if(p_filehandle->type == DT_LNK)
     return fsal_internal_setattrs_symlink(p_filehandle, p_context, p_attrib_set,
     p_object_attributes);
   */
  /* First, check that FSAL attributes changes are allowed. */

  /* Is it allowed to change times ? */

  if(!global_fs_info.cansettime)
    {

      if(attrs.asked_attributes
         & (FSAL_ATTR_ATIME | FSAL_ATTR_CREATION | FSAL_ATTR_CTIME | FSAL_ATTR_MTIME))
        {
          /* handled as an unsettable attribute. */
          Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_setattrs);
        }
    }

  /* apply umask, if mode attribute is to be changed */
  if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MODE))
    {
      attrs.mode &= (~global_fs_info.umask);
    }

  TakeTokenFSCall();
  status = fsal_internal_handle2fd(p_context, p_filehandle, &fd, O_RDONLY);
  ReleaseTokenFSCall();
  if(FSAL_IS_ERROR(status))
   {
     /* Symbolic link are handled here, they are to be opened as O_PATH */
     if( status.minor == ELOOP )
      {
           if(p_object_attributes)
             {
               status = VFSFSAL_getattrs(p_filehandle, p_context, p_object_attributes);

               /* on error, we set a special bit in the mask. */
               if(FSAL_IS_ERROR(status))
                 {
                   FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
                   FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
                 }
             }
           Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_setattrs);
      }

     ReturnStatus( status, INDEX_FSAL_setattrs);
   }

  /* get current attributes */
  TakeTokenFSCall();
  rc = fstat(fd, &buffstat);
  errsv = errno;
  ReleaseTokenFSCall();

  if(rc != 0)
    {
      close(fd);

      if(errsv == ENOENT)
        Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_setattrs);
      else
        Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_setattrs);
    }

  /***********
   *  CHMOD  *
   ***********/
  if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MODE))
    {

      /* The POSIX chmod call don't affect the symlink object, but
       * the entry it points to. So we must ignore it.
       */
      if(!S_ISLNK(buffstat.st_mode))
        {

          /* For modifying mode, user must be root or the owner */
          if((vfs_context->credential.user != 0)
             && (vfs_context->credential.user != buffstat.st_uid))
            {
              LogFullDebug(COMPONENT_FSAL,
                           "Permission denied for CHMOD opeartion: current owner=%d, credential=%d",
                           buffstat.st_uid, vfs_context->credential.user);
              close(fd);
              Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
            }

          TakeTokenFSCall();
          rc = fchmod(fd, fsal2unix_mode(attrs.mode));
          errsv = errno;
          ReleaseTokenFSCall();

          if(rc)
            {
              close(fd);
              Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_setattrs);
            }

        }

    }

  /***********
   *  CHOWN  *
   ***********/
  /* Only root can change uid and A normal user must be in the group he wants to set */
  if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_OWNER))
    {

      /* For modifying owner, user must be root or current owner==wanted==client */
      if((vfs_context->credential.user != 0) &&
         ((vfs_context->credential.user != buffstat.st_uid) ||
          (vfs_context->credential.user != attrs.owner)))
        {
          LogFullDebug(COMPONENT_FSAL,
                       "Permission denied for CHOWN opeartion: current owner=%d, credential=%d, new owner=%d",
                       buffstat.st_uid, vfs_context->credential.user, attrs.owner);
          close(fd);
          Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
        }
    }

  if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_GROUP))
    {

      /* For modifying group, user must be root or current owner */
      if((vfs_context->credential.user != 0)
         && (vfs_context->credential.user != buffstat.st_uid))
        {
          close(fd);
          Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
        }

      int in_grp = 0;
      /* set in_grp */
      if(vfs_context->credential.group == attrs.group)
        in_grp = 1;
      else
        for(i = 0; i < vfs_context->credential.nbgroups; i++)
          {
            if((in_grp = (attrs.group == vfs_context->credential.alt_groups[i])))
              break;
          }

      /* it must also be in target group */
      if(vfs_context->credential.user != 0 && !in_grp)
        {
          LogFullDebug(COMPONENT_FSAL,
                       "Permission denied for CHOWN operation: current group=%d, credential=%d, new group=%d",
                       buffstat.st_gid, vfs_context->credential.group, attrs.group);
          close(fd);
          Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs);
        }
    }

  if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_OWNER | FSAL_ATTR_GROUP))
    {
      /*      LogFullDebug(COMPONENT_FSAL, "Performing chown(%s, %d,%d)",
                        fsalpath.path, FSAL_TEST_MASK(attrs.asked_attributes,
                                                      FSAL_ATTR_OWNER) ? (int)attrs.owner
                        : -1, FSAL_TEST_MASK(attrs.asked_attributes,
			FSAL_ATTR_GROUP) ? (int)attrs.group : -1);*/

      TakeTokenFSCall();
      rc = fchown(fd,
                  FSAL_TEST_MASK(attrs.asked_attributes,
                                 FSAL_ATTR_OWNER) ? (int)attrs.owner : -1,
                  FSAL_TEST_MASK(attrs.asked_attributes,
                                 FSAL_ATTR_GROUP) ? (int)attrs.group : -1);
      ReleaseTokenFSCall();
      if(rc)
        {
          close(fd);
          Return(posix2fsal_error(errno), errno, INDEX_FSAL_setattrs);
        }
    }

  /***********
   *  UTIME  *
   ***********/

  /* user must be the owner or have read access to modify 'atime' */
  if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME)
     && (vfs_context->credential.user != 0)
     && (vfs_context->credential.user != buffstat.st_uid)
     && ((status = fsal_check_access(p_context, FSAL_R_OK, &buffstat, NULL)).major
         != ERR_FSAL_NO_ERROR))
    {
      close(fd);
      ReturnStatus(status, INDEX_FSAL_setattrs);
    }
  /* user must be the owner or have write access to modify 'mtime' */
  if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MTIME)
     && (vfs_context->credential.user != 0)
     && (vfs_context->credential.user != buffstat.st_uid)
     && ((status = fsal_check_access(p_context, FSAL_W_OK, &buffstat, NULL)).major
         != ERR_FSAL_NO_ERROR))
    {
      close(fd);
      ReturnStatus(status, INDEX_FSAL_setattrs);
    }

  if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME | FSAL_ATTR_MTIME))
    {

      struct timeval timebuf[2];

      /* Atime */
      timebuf[0].tv_sec =
          (FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME) ? (time_t) attrs.
           atime.seconds : buffstat.st_atime);
      timebuf[0].tv_usec = 0;

      /* Mtime */
      timebuf[1].tv_sec =
          (FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MTIME) ? (time_t) attrs.
           mtime.seconds : buffstat.st_mtime);
      timebuf[1].tv_usec = 0;

      TakeTokenFSCall();
      rc = futimes(fd, timebuf);
      errsv = errno;
      ReleaseTokenFSCall();
      if(rc)
        {
          close(fd);
          Return(posix2fsal_error(errno), errno, INDEX_FSAL_setattrs);
        }
    }

  /* Optionaly fills output attributes. */

  if(p_object_attributes)
    {
      status = VFSFSAL_getattrs(p_filehandle, p_context, p_object_attributes);

      /* on error, we set a special bit in the mask. */
      if(FSAL_IS_ERROR(status))
        {
          FSAL_CLEAR_MASK(p_object_attributes->asked_attributes);
          FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR);
        }

    }

  close(fd);
  Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_setattrs);

}