/** * @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); }
fsal_status_t GPFSFSAL_create2(struct fsal_obj_handle *dir_hdl, const char *filename, const struct req_op_context *op_ctx, mode_t unix_mode, struct gpfs_file_handle *gpfs_fh, int posix_flags, struct attrlist *fsal_attr) { fsal_status_t status; /* note : fsal_attr is optional. */ if (!dir_hdl || !op_ctx || !gpfs_fh || !filename) return fsalstat(ERR_FSAL_FAULT, 0); LogFullDebug(COMPONENT_FSAL, "Creation mode: 0%o", unix_mode); /* call to filesystem */ fsal_set_credentials(op_ctx->creds); status = fsal_internal_create(dir_hdl, filename, unix_mode | S_IFREG, posix_flags, 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); }
/** * @brief Create a hardlink. * * @param dir_hdl Handle of the target object. * @param gpfs_fh Pointer to the directory handle where hardlink is to be created. * @param linkname Pointer to the name of the hardlink to be created. * @param op_ctx Authentication context for the operation (user,...). * @return ERR_FSAL_NO_ERROR on success, error otherwise * */ fsal_status_t GPFSFSAL_link(struct fsal_obj_handle *dir_hdl, struct gpfs_file_handle *gpfs_fh, const char *linkname, const struct req_op_context *op_ctx) { struct gpfs_filesystem *gpfs_fs; fsal_status_t status; struct gpfs_fsal_obj_handle *dest_dir; /* note : fsal_attr is optional. */ if (!dir_hdl || !gpfs_fh || !op_ctx || !linkname) return fsalstat(ERR_FSAL_FAULT, 0); dest_dir = container_of(dir_hdl, struct gpfs_fsal_obj_handle, obj_handle); gpfs_fs = dir_hdl->fs->private_data; /* Tests if hardlinking is allowed by configuration. */ if (!op_ctx->fsal_export->exp_ops. fs_supports(op_ctx->fsal_export, fso_link_support)) return fsalstat(ERR_FSAL_NOTSUPP, 0); /* Create the link on the filesystem */ fsal_set_credentials(op_ctx->creds); status = fsal_internal_link_fh(gpfs_fs->root_fd, gpfs_fh, dest_dir->handle, linkname); fsal_restore_ganesha_credentials(); return status; }
fsal_status_t vfs_write(struct fsal_obj_handle *obj_hdl, uint64_t offset, size_t buffer_size, void *buffer, size_t *write_amount, bool *fsal_stable) { struct vfs_fsal_obj_handle *myself; ssize_t nb_written; fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR; int retval = 0; 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); retval = EXDEV; fsal_error = posix2fsal_error(retval); return fsalstat(fsal_error, retval); } /* Take read lock on object to protect file descriptor. */ PTHREAD_RWLOCK_rdlock(&obj_hdl->lock); assert(myself->u.file.fd >= 0 && myself->u.file.openflags != FSAL_O_CLOSED); fsal_set_credentials(op_ctx->creds); nb_written = pwrite(myself->u.file.fd, buffer, buffer_size, offset); if (offset == -1 || nb_written == -1) { retval = errno; fsal_error = posix2fsal_error(retval); goto out; } *write_amount = nb_written; /* attempt stability */ if (fsal_stable != NULL && *fsal_stable) { retval = fsync(myself->u.file.fd); if (retval == -1) { retval = errno; fsal_error = posix2fsal_error(retval); } *fsal_stable = true; } out: PTHREAD_RWLOCK_unlock(&obj_hdl->lock); fsal_restore_ganesha_credentials(); return fsalstat(fsal_error, retval); }
/** @fn fsal_status_t * GPFSFSAL_read(int fd, uint64_t offset, size_t buffer_size, caddr_t buffer, * size_t *p_read_amount, bool *p_end_of_file) * @brief Perform a read operation on an opened file. * @param fd The file descriptor returned by FSAL_open. * @offset Offset * @param buf_size Amount (in bytes) of data to be read. * @param buf Address where the read data is to be stored in memory. * @param read_amount Pointer to the amount of data (in bytes) that have been read * during this call. * @param end_of_file Pointer to a boolean that indicates whether the end of file * has been reached during this call. * * @return ERR_FSAL_NO_ERROR on success, error otherwise. */ fsal_status_t GPFSFSAL_read(int fd, uint64_t offset, size_t buf_size, caddr_t buf, size_t *read_amount, bool *end_of_file, int expfd) { struct read_arg rarg = {0}; ssize_t nb_read; int errsv; /* sanity checks. */ if (!buf || !read_amount || !end_of_file) return fsalstat(ERR_FSAL_FAULT, 0); rarg.mountdirfd = expfd; rarg.fd = fd; rarg.bufP = buf; rarg.offset = offset; rarg.length = buf_size; rarg.options = 0; fsal_set_credentials(op_ctx->creds); nb_read = gpfs_ganesha(OPENHANDLE_READ_BY_FD, &rarg); errsv = errno; fsal_restore_ganesha_credentials(); /* negative values mean error */ if (nb_read < 0) { /* if nb_read is not -1, the split rc/errno didn't work */ if (nb_read != -1) { errsv = labs(nb_read); LogWarn(COMPONENT_FSAL, "Received negative value (%d) from ioctl().", (int) nb_read); } if (errsv == EUNATCH) LogFatal(COMPONENT_FSAL, "GPFS Returned EUNATCH"); return fsalstat(posix2fsal_error(errsv), errsv); } if (nb_read == 0 || nb_read < buf_size) *end_of_file = true; *read_amount = nb_read; return fsalstat(ERR_FSAL_NO_ERROR, 0); }
fsal_status_t vfs_commit2(struct fsal_obj_handle *obj_hdl, off_t offset, size_t len) { struct vfs_fsal_obj_handle *myself; fsal_status_t status; int retval; struct vfs_fd temp_fd = {0, -1}, *out_fd = &temp_fd; bool has_lock = false; bool closefd = false; myself = container_of(obj_hdl, struct vfs_fsal_obj_handle, obj_handle); /* Make sure file is open in appropriate mode. * Do not check share reservation. */ status = fsal_reopen_obj(obj_hdl, false, false, FSAL_O_WRITE, (struct fsal_fd *)&myself->u.file.fd, &myself->u.file.share, vfs_open_func, vfs_close_func, (struct fsal_fd **)&out_fd, &has_lock, &closefd); if (!FSAL_IS_ERROR(status)) { fsal_set_credentials(op_ctx->creds); retval = fsync(out_fd->fd); if (retval == -1) { retval = errno; status = fsalstat(posix2fsal_error(retval), retval); } fsal_restore_ganesha_credentials(); } if (closefd) close(out_fd->fd); if (has_lock) PTHREAD_RWLOCK_unlock(&obj_hdl->lock); return status; }
/** @fn fsal_status_t * GPFSFSAL_write(int fd, uint64_t offset, size_t buf_size, caddr_t buf, * size_t *write_amount, bool *fsal_stable, * const struct req_op_context *op_ctx) * @brief Perform a write operation on an opened file. * * @param fd The file descriptor returned by FSAL_open. * @param buf_size Amount (in bytes) of data to be written. * @param buf Address where the data is in memory. * @param write_amount Pointer to the amount of data (in bytes) that have been written * during this call. * * @return ERR_FSAL_NO_ERROR on success, error otherwise */ fsal_status_t GPFSFSAL_write(int fd, uint64_t offset, size_t buf_size, caddr_t buf, size_t *write_amount, bool *fsal_stable, const struct req_op_context *op_ctx, int expfd) { struct write_arg warg = {0}; uint32_t stability_got = 0; ssize_t nb_write; int errsv; /* sanity checks. */ if (!buf || !write_amount) return fsalstat(ERR_FSAL_FAULT, 0); warg.mountdirfd = expfd; warg.fd = fd; warg.bufP = buf; warg.offset = offset; warg.length = buf_size; warg.stability_wanted = *fsal_stable; warg.stability_got = &stability_got; warg.options = 0; fsal_set_credentials(op_ctx->creds); nb_write = gpfs_ganesha(OPENHANDLE_WRITE_BY_FD, &warg); errsv = errno; fsal_restore_ganesha_credentials(); if (nb_write == -1) { if (errsv == EUNATCH) LogFatal(COMPONENT_FSAL, "GPFS Returned EUNATCH"); return fsalstat(posix2fsal_error(errsv), errsv); } *write_amount = nb_write; *fsal_stable = (stability_got) ? true : false; return fsalstat(ERR_FSAL_NO_ERROR, 0); }
/** @fn fsal_status_t * GPFSFSAL_open(struct fsal_obj_handle *obj_hdl, * const struct req_op_context *op_ctx, * fsal_openflags_t openflags, int *file_desc, * struct attrlist *fsal_attr) * * @brief Open a regular file for reading/writing its data content. * * @param obj_hdl Handle of the file to be read/modified. * @param op_ctx Authentication context for the operation (user,...). * @param openflags Flags that indicates behavior for file opening and access. * This is an inclusive OR of the following values * ( such of them are not compatible) : * - FSAL_O_RDONLY: opening file for reading only. * - FSAL_O_RDWR: opening file for reading and writing. * - FSAL_O_WRONLY: opening file for writting only. * - FSAL_O_APPEND: always write at the end of the file. * - FSAL_O_TRUNC: truncate the file to 0 on opening. * @param file_desc The file descriptor to be used for FSAL_read/write ops. * * @return ERR_FSAL_NO_ERROR on success, error otherwise */ fsal_status_t GPFSFSAL_open(struct fsal_obj_handle *obj_hdl, const struct req_op_context *op_ctx, int posix_flags, int *file_desc) { struct gpfs_fsal_obj_handle *myself; fsal_status_t status; struct gpfs_fsal_export *exp = container_of(op_ctx->fsal_export, struct gpfs_fsal_export, export); int export_fd = exp->export_fd; /* sanity checks. */ if (!obj_hdl || !file_desc) return fsalstat(ERR_FSAL_FAULT, 0); myself = container_of(obj_hdl, struct gpfs_fsal_obj_handle, obj_handle); LogFullDebug(COMPONENT_FSAL, "posix_flags 0x%X export_fd %d", posix_flags, export_fd); fsal_set_credentials(op_ctx->creds); status = fsal_internal_handle2fd(export_fd, myself->handle, file_desc, posix_flags); fsal_restore_ganesha_credentials(); if (FSAL_IS_ERROR(status)) { /** Try open as root access if the above call fails, * permission will be checked somewhere else in the code. */ status = fsal_internal_handle2fd(export_fd, myself->handle, file_desc, posix_flags); } return status; }
/** @fn fsal_status_t * GPFSFSAL_alloc(int fd, uint64_t offset, uint64_t length, bool allocate) * @brief Perform a de/allocc operation on an opened file. * @param fd The file descriptor returned by FSAL_open. * @param offset Offset * @param length Length * @param allocate Allocate * * @return ERR_FSAL_NO_ERROR on success, error otherwise */ fsal_status_t GPFSFSAL_alloc(int fd, uint64_t offset, uint64_t length, bool allocate) { struct alloc_arg aarg = {0}; int errsv; int rc; aarg.fd = fd; aarg.offset = offset; aarg.length = length; aarg.options = (allocate) ? IO_ALLOCATE : IO_DEALLOCATE; fsal_set_credentials(op_ctx->creds); rc = gpfs_ganesha(OPENHANDLE_ALLOCATE_BY_FD, &aarg); errsv = errno; fsal_restore_ganesha_credentials(); if (rc == -1) { if (errsv == EUNATCH) LogFatal(COMPONENT_FSAL, "GPFS Returned EUNATCH"); return fsalstat(posix2fsal_error(errsv), errsv); } return fsalstat(ERR_FSAL_NO_ERROR, 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); }
/** @fn fsal_status_t * GPFSFSAL_open(struct fsal_obj_handle *obj_hdl, * const struct req_op_context *op_ctx, * fsal_openflags_t openflags, int *file_desc, * struct attrlist *fsal_attr, bool reopen) * * @brief Open a regular file for reading/writing its data content. * * @param obj_hdl Handle of the file to be read/modified. * @param op_ctx Authentication context for the operation (user,...). * @param openflags Flags that indicates behavior for file opening and access. * This is an inclusive OR of the following values * ( such of them are not compatible) : * - FSAL_O_RDONLY: opening file for reading only. * - FSAL_O_RDWR: opening file for reading and writing. * - FSAL_O_WRONLY: opening file for writting only. * - FSAL_O_APPEND: always write at the end of the file. * - FSAL_O_TRUNC: truncate the file to 0 on opening. * @param file_desc The file descriptor to be used for FSAL_read/write ops. * * @return ERR_FSAL_NO_ERROR on success, error otherwise */ fsal_status_t GPFSFSAL_open(struct fsal_obj_handle *obj_hdl, const struct req_op_context *op_ctx, int posix_flags, int *file_desc, bool reopen) { struct gpfs_fsal_obj_handle *myself; struct gpfs_filesystem *gpfs_fs; fsal_status_t status; /* sanity checks. */ if (!obj_hdl || !file_desc) return fsalstat(ERR_FSAL_FAULT, 0); myself = container_of(obj_hdl, struct gpfs_fsal_obj_handle, obj_handle); gpfs_fs = obj_hdl->fs->private_data; LogFullDebug(COMPONENT_FSAL, "posix_flags 0x%X", posix_flags); status = fsal_internal_handle2fd(gpfs_fs->root_fd, myself->handle, file_desc, posix_flags, reopen); if (FSAL_IS_ERROR(status)) { /** In some environments, "root" is denied write access, * so try with the request credentials if the above call * fails. */ fsal_set_credentials(op_ctx->creds); status = fsal_internal_handle2fd(gpfs_fs->root_fd, myself->handle, file_desc, posix_flags, reopen); fsal_restore_ganesha_credentials(); } return status; }
fsal_status_t vfs_write2(struct fsal_obj_handle *obj_hdl, bool bypass, struct state_t *state, uint64_t offset, size_t buffer_size, void *buffer, size_t *wrote_amount, bool *fsal_stable, struct io_info *info) { ssize_t nb_written; fsal_status_t status; int retval = 0; int my_fd = -1; bool has_lock = false; bool need_fsync = false; bool closefd = false; fsal_openflags_t openflags = FSAL_O_WRITE; if (info != NULL) { /* Currently we don't support WRITE_PLUS */ return fsalstat(ERR_FSAL_NOTSUPP, 0); } 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 (*fsal_stable) openflags |= FSAL_O_SYNC; /* Get a usable file descriptor */ status = find_fd(&my_fd, obj_hdl, bypass, state, openflags, &has_lock, &need_fsync, &closefd, false); if (FSAL_IS_ERROR(status)) { LogDebug(COMPONENT_FSAL, "find_fd failed %s", msg_fsal_err(status.major)); goto out; } fsal_set_credentials(op_ctx->creds); nb_written = pwrite(my_fd, buffer, buffer_size, offset); if (nb_written == -1) { retval = errno; status = fsalstat(posix2fsal_error(retval), retval); goto out; } *wrote_amount = nb_written; /* attempt stability if we aren't using an O_SYNC fd */ if (need_fsync) { retval = fsync(my_fd); if (retval == -1) { retval = errno; status = fsalstat(posix2fsal_error(retval), retval); } } out: if (closefd) close(my_fd); if (has_lock) PTHREAD_RWLOCK_unlock(&obj_hdl->lock); fsal_restore_ganesha_credentials(); return status; }
static fsal_status_t 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 vfs_fsal_obj_handle *myself, *hdl; int dir_fd = -1; struct stat stat; mode_t unix_mode, create_mode = 0; fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR; int retval = 0; uid_t user; gid_t group; dev_t unix_dev = 0; int flags = O_PATH | O_NOACCESS; vfs_file_handle_t *fh = NULL; vfs_alloc_handle(fh); LogDebug(COMPONENT_FSAL, "create %s", name); *handle = NULL; /* poison it */ if (!dir_hdl->obj_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); } myself = container_of(dir_hdl, struct vfs_fsal_obj_handle, obj_handle); if (dir_hdl->fsal != dir_hdl->fs->fsal) { LogDebug(COMPONENT_FSAL, "FSAL %s operation for handle belonging to FSAL %s, return EXDEV", dir_hdl->fsal->name, dir_hdl->fs->fsal != NULL ? dir_hdl->fs->fsal->name : "(none)"); retval = EXDEV; goto hdlerr; } user = attrib->owner; group = attrib->group; unix_mode = fsal2unix_mode(attrib->mode) & ~op_ctx->fsal_export->exp_ops.fs_umask(op_ctx->fsal_export); switch (nodetype) { case BLOCK_FILE: create_mode = S_IFBLK; unix_dev = makedev(dev->major, dev->minor); break; case CHARACTER_FILE: create_mode = S_IFCHR; unix_dev = makedev(dev->major, dev->minor); 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); fsal_error = ERR_FSAL_INVAL; goto errout; } dir_fd = vfs_fsal_open(myself, flags, &fsal_error); if (dir_fd < 0) goto errout; retval = vfs_stat_by_handle(dir_fd, myself->handle, &stat, flags); if (retval < 0) { retval = errno; goto direrr; } if (stat.st_mode & S_ISGID) group = -1; /*setgid bit on dir propagates dir group owner */ /* create it with no access because we are root when we do this */ fsal_set_credentials(op_ctx->creds); retval = mknodat(dir_fd, name, create_mode, unix_dev); if (retval < 0) { retval = errno; fsal_restore_ganesha_credentials(); goto direrr; } fsal_restore_ganesha_credentials(); retval = make_file_safe(myself, op_ctx, dir_fd, name, unix_mode, user, group, &hdl); if (!retval) { close(dir_fd); /* done with parent */ *handle = &hdl->obj_handle; return fsalstat(ERR_FSAL_NO_ERROR, 0); } unlinkat(dir_fd, name, 0); direrr: close(dir_fd); /* done with parent */ hdlerr: fsal_error = posix2fsal_error(retval); errout: return fsalstat(fsal_error, retval); }
/** * 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); }
/** * @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); }
static fsal_status_t renamefile(struct fsal_obj_handle *obj_hdl, struct fsal_obj_handle *olddir_hdl, const char *old_name, struct fsal_obj_handle *newdir_hdl, const char *new_name) { struct vfs_fsal_obj_handle *olddir, *newdir, *obj; int oldfd = -1, newfd = -1; fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR; int retval = 0; olddir = container_of(olddir_hdl, struct vfs_fsal_obj_handle, obj_handle); if (olddir_hdl->fsal != olddir_hdl->fs->fsal) { LogDebug(COMPONENT_FSAL, "FSAL %s operation for handle belonging to FSAL %s, return EXDEV", olddir_hdl->fsal->name, olddir_hdl->fs->fsal != NULL ? olddir_hdl->fs->fsal->name : "(none)"); retval = EXDEV; fsal_error = posix2fsal_error(retval); goto out; } oldfd = vfs_fsal_open(olddir, O_PATH | O_NOACCESS, &fsal_error); if (oldfd < 0) { retval = -oldfd; goto out; } newdir = container_of(newdir_hdl, struct vfs_fsal_obj_handle, obj_handle); if (newdir_hdl->fsal != newdir_hdl->fs->fsal) { LogDebug(COMPONENT_FSAL, "FSAL %s operation for handle belonging to FSAL %s, return EXDEV", newdir_hdl->fsal->name, newdir_hdl->fs->fsal != NULL ? newdir_hdl->fs->fsal->name : "(none)"); retval = EXDEV; fsal_error = posix2fsal_error(retval); goto out; } obj = container_of(obj_hdl, struct vfs_fsal_obj_handle, obj_handle); newfd = vfs_fsal_open(newdir, O_PATH | O_NOACCESS, &fsal_error); if (newfd < 0) { retval = -newfd; goto out; } /* Become the user because we are creating/removing objects * in these dirs which messes with quotas and perms. */ fsal_set_credentials(op_ctx->creds); retval = renameat(oldfd, old_name, newfd, new_name); if (retval < 0) { retval = errno; fsal_error = posix2fsal_error(retval); } else if (vfs_unopenable_type(obj->obj_handle.type)) { /* A block, char, or socket has been renamed. Fixup * our information in the handle so we can still stat it. * Save the name in case we have to sort of undo. */ char *saved_name = obj->u.unopenable.name; memcpy(obj->u.unopenable.dir, newdir->handle, sizeof(vfs_file_handle_t)); obj->u.unopenable.name = gsh_strdup(new_name); if (obj->u.unopenable.name != NULL) { /* Discard saved_name */ gsh_free(saved_name); } else { /* It's a bad day, we're going to be messed up * no matter what we try and do, maybe leave * things not completely hosed. */ LogCrit(COMPONENT_FSAL, "Failed to allocate memory to rename special inode from %s to %s", old_name, new_name); obj->u.unopenable.name = saved_name; } } fsal_restore_ganesha_credentials(); out: if (oldfd >= 0) close(oldfd); if (newfd >= 0) close(newfd); return fsalstat(fsal_error, retval); }
static fsal_status_t makesymlink(struct fsal_obj_handle *dir_hdl, const char *name, const char *link_path, struct attrlist *attrib, struct fsal_obj_handle **handle) { struct vfs_fsal_obj_handle *myself, *hdl; int dir_fd = -1; struct stat stat; fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR; int retval = 0; int flags = O_PATH | O_NOACCESS; vfs_file_handle_t *fh = NULL; vfs_alloc_handle(fh); LogDebug(COMPONENT_FSAL, "create %s", name); *handle = NULL; /* poison it first */ if (!dir_hdl->obj_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); } myself = container_of(dir_hdl, struct vfs_fsal_obj_handle, obj_handle); if (dir_hdl->fsal != dir_hdl->fs->fsal) { LogDebug(COMPONENT_FSAL, "FSAL %s operation for handle belonging to FSAL %s, return EXDEV", dir_hdl->fsal->name, dir_hdl->fs->fsal != NULL ? dir_hdl->fs->fsal->name : "(none)"); retval = EXDEV; goto hdlerr; } dir_fd = vfs_fsal_open(myself, flags, &fsal_error); if (dir_fd < 0) return fsalstat(fsal_error, -dir_fd); flags |= O_NOFOLLOW; /* BSD needs O_NOFOLLOW for * fhopen() of symlinks */ retval = vfs_stat_by_handle(dir_fd, myself->handle, &stat, flags); if (retval < 0) { retval = errno; goto direrr; } /* Become the user because we are creating an object in this dir. */ fsal_set_credentials(op_ctx->creds); retval = symlinkat(link_path, dir_fd, name); if (retval < 0) { retval = errno; fsal_restore_ganesha_credentials(); goto direrr; } fsal_restore_ganesha_credentials(); retval = vfs_name_to_handle(dir_fd, dir_hdl->fs, name, fh); if (retval < 0) { retval = errno; goto linkerr; } /* now get attributes info, * being careful to get the link, not the target */ retval = fstatat(dir_fd, name, &stat, AT_SYMLINK_NOFOLLOW); if (retval < 0) { retval = errno; goto linkerr; } /* allocate an obj_handle and fill it up */ hdl = alloc_handle(dir_fd, fh, dir_hdl->fs, &stat, NULL, name, op_ctx->fsal_export); if (hdl == NULL) { retval = ENOMEM; goto linkerr; } *handle = &hdl->obj_handle; close(dir_fd); return fsalstat(ERR_FSAL_NO_ERROR, 0); linkerr: unlinkat(dir_fd, name, 0); direrr: close(dir_fd); hdlerr: if (retval == ENOENT) fsal_error = ERR_FSAL_STALE; else fsal_error = posix2fsal_error(retval); return fsalstat(fsal_error, retval); }
/** * 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); }
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); }
static struct closefd vfs_fsal_open_and_stat(struct fsal_export *exp, struct vfs_fsal_obj_handle *myself, struct stat *stat, int open_flags, fsal_errors_t *fsal_error) { struct fsal_obj_handle *obj_hdl = &myself->obj_handle; struct closefd cfd = { .fd = -1, .close_fd = false }; int retval = 0; vfs_file_handle_t *fh = NULL; vfs_alloc_handle(fh); const char *func = "unknown"; struct vfs_filesystem *vfs_fs = myself->obj_handle.fs->private; switch (obj_hdl->type) { case SOCKET_FILE: case CHARACTER_FILE: case BLOCK_FILE: cfd.fd = vfs_open_by_handle(vfs_fs, myself->u.unopenable.dir, O_PATH | O_NOACCESS, fsal_error); if (cfd.fd < 0) { LogDebug(COMPONENT_FSAL, "Failed with %s open_flags 0x%08x", strerror(-cfd.fd), O_PATH | O_NOACCESS); return cfd; } cfd.close_fd = true; retval = fstatat(cfd.fd, myself->u.unopenable.name, stat, AT_SYMLINK_NOFOLLOW); func = "fstatat"; break; case REGULAR_FILE: if (myself->u.file.openflags == FSAL_O_CLOSED) { /* no file open at the moment */ cfd.fd = vfs_fsal_open(myself, open_flags, fsal_error); if (cfd.fd < 0) { LogDebug(COMPONENT_FSAL, "Failed with %s open_flags 0x%08x", strerror(-cfd.fd), open_flags); return cfd; } cfd.close_fd = true; } else { cfd.fd = myself->u.file.fd; } retval = fstat(cfd.fd, stat); func = "fstat"; break; case SYMBOLIC_LINK: open_flags |= (O_PATH | O_RDWR | O_NOFOLLOW); goto vfos_open; case FIFO_FILE: open_flags |= O_NONBLOCK; /* fall through */ case DIRECTORY: default: vfos_open: cfd.fd = vfs_fsal_open(myself, open_flags, fsal_error); if (cfd.fd < 0) { LogDebug(COMPONENT_FSAL, "Failed with %s open_flags 0x%08x", strerror(-cfd.fd), open_flags); return cfd; } cfd.close_fd = true; retval = vfs_stat_by_handle(cfd.fd, myself->handle, stat, open_flags); func = "vfs_stat_by_handle"; break; } if (retval < 0) { retval = errno; if (cfd.close_fd) { int rc; rc = close(cfd.fd); if (rc < 0) { rc = errno; LogDebug(COMPONENT_FSAL, "close failed with %s", strerror(rc)); } } if (retval == ENOENT) retval = ESTALE; *fsal_error = posix2fsal_error(retval); LogDebug(COMPONENT_FSAL, "%s failed with %s", func, strerror(retval)); cfd.fd = -retval; cfd.close_fd = false; return cfd; } return cfd; } static fsal_status_t getattrs(struct fsal_obj_handle *obj_hdl) { struct vfs_fsal_obj_handle *myself; struct closefd cfd = { .fd = -1, .close_fd = false }; struct stat stat; fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR; fsal_status_t st; int retval = 0; 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 getattr for handle belonging to FSAL %s, ignoring", obj_hdl->fsal->name, obj_hdl->fs->fsal != NULL ? obj_hdl->fs->fsal->name : "(none)"); goto out; } cfd = vfs_fsal_open_and_stat(op_ctx->fsal_export, myself, &stat, O_RDONLY, &fsal_error); if (cfd.fd >= 0) { st = posix2fsal_attributes(&stat, &obj_hdl->attributes); if (cfd.close_fd) close(cfd.fd); if (FSAL_IS_ERROR(st)) { FSAL_CLEAR_MASK(obj_hdl->attributes.mask); FSAL_SET_MASK(obj_hdl->attributes.mask, ATTR_RDATTR_ERR); fsal_error = st.major; retval = st.minor; } else { obj_hdl->attributes.fsid = obj_hdl->fs->fsid; } } else { LogDebug(COMPONENT_FSAL, "Failed with %s, fsal_error %s", strerror(-cfd.fd), fsal_error == ERR_FSAL_STALE ? "ERR_FSAL_STALE" : "other"); if (obj_hdl->type == SYMBOLIC_LINK && cfd.fd == -EPERM) { /* You cannot open_by_handle (XFS on linux) 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. In this case, return the stat we got * at lookup time. If you *really* want to tweek things * like owners, get a modern linux kernel... */ fsal_error = ERR_FSAL_NO_ERROR; goto out; } retval = -cfd.fd; } out: return fsalstat(fsal_error, retval); } /* * NOTE: this is done under protection of the attributes rwlock * in the cache entry. */ static fsal_status_t setattrs(struct fsal_obj_handle *obj_hdl, struct attrlist *attrs) { struct vfs_fsal_obj_handle *myself; struct closefd cfd = { .fd = -1, .close_fd = false }; struct stat stat; fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR; int retval = 0; int open_flags = O_RDONLY; /* apply umask, if mode attribute is to be changed */ if (FSAL_TEST_MASK(attrs->mask, ATTR_MODE)) attrs->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)"); retval = EXDEV; fsal_error = posix2fsal_error(retval); goto hdlerr; } /* 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. */ if (FSAL_TEST_MASK(attrs->mask, ATTR_SIZE)) open_flags = O_RDWR; cfd = vfs_fsal_open_and_stat(op_ctx->fsal_export, myself, &stat, open_flags, &fsal_error); if (cfd.fd < 0) { if (obj_hdl->type == SYMBOLIC_LINK && cfd.fd == -EPERM) { /* 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... */ fsal_error = ERR_FSAL_NO_ERROR; goto out; } return fsalstat(fsal_error, cfd.fd); } /** TRUNCATE **/ if (FSAL_TEST_MASK(attrs->mask, ATTR_SIZE)) { if (obj_hdl->type != REGULAR_FILE) { fsal_error = ERR_FSAL_INVAL; goto fileerr; } retval = ftruncate(cfd.fd, attrs->filesize); if (retval != 0) { /* XXX ESXi volume creation pattern reliably * reaches this point and reliably can successfully * ftruncate on reopen. I don't know yet if fd if * we failed to handle a previous error, or what. * I don't see a prior failed op in wireshark. */ if (retval == -1 /* bad fd */) { vfs_close(obj_hdl); if (cfd.close_fd) close(cfd.fd); cfd = vfs_fsal_open_and_stat( op_ctx->fsal_export, myself, &stat, open_flags, &fsal_error); retval = ftruncate(cfd.fd, attrs->filesize); if (retval != 0) goto fileerr; } else goto fileerr; } } /** CHMOD **/ if (FSAL_TEST_MASK(attrs->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 (!S_ISLNK(stat.st_mode)) { if (vfs_unopenable_type(obj_hdl->type)) retval = fchmodat(cfd.fd, myself->u.unopenable.name, fsal2unix_mode(attrs->mode), 0); else retval = fchmod(cfd.fd, fsal2unix_mode(attrs->mode)); if (retval != 0) goto fileerr; } } /** CHOWN **/ if (FSAL_TEST_MASK(attrs->mask, ATTR_OWNER | ATTR_GROUP)) { uid_t user = FSAL_TEST_MASK(attrs->mask, ATTR_OWNER) ? (int)attrs->owner : -1; gid_t group = FSAL_TEST_MASK(attrs->mask, ATTR_GROUP) ? (int)attrs->group : -1; if (vfs_unopenable_type(obj_hdl->type)) retval = fchownat(cfd.fd, myself->u.unopenable.name, user, group, AT_SYMLINK_NOFOLLOW); else if (obj_hdl->type == SYMBOLIC_LINK) retval = fchownat(cfd.fd, "", user, group, AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH); else retval = fchown(cfd.fd, user, group); if (retval) goto fileerr; } /** UTIME **/ if (FSAL_TEST_MASK (attrs->mask, ATTR_ATIME | ATTR_MTIME | ATTR_ATIME_SERVER | ATTR_MTIME_SERVER)) { struct timespec timebuf[2]; if (obj_hdl->type == SYMBOLIC_LINK) goto out; /* Setting time on symlinks is illegal */ /* Atime */ if (FSAL_TEST_MASK(attrs->mask, ATTR_ATIME_SERVER)) { timebuf[0].tv_sec = 0; timebuf[0].tv_nsec = UTIME_NOW; } else if (FSAL_TEST_MASK(attrs->mask, ATTR_ATIME)) { timebuf[0] = attrs->atime; } else { timebuf[0].tv_sec = 0; timebuf[0].tv_nsec = UTIME_OMIT; } /* Mtime */ if (FSAL_TEST_MASK(attrs->mask, ATTR_MTIME_SERVER)) { timebuf[1].tv_sec = 0; timebuf[1].tv_nsec = UTIME_NOW; } else if (FSAL_TEST_MASK(attrs->mask, ATTR_MTIME)) { timebuf[1] = attrs->mtime; } else { timebuf[1].tv_sec = 0; timebuf[1].tv_nsec = UTIME_OMIT; } if (vfs_unopenable_type(obj_hdl->type)) retval = vfs_utimesat(cfd.fd, myself->u.unopenable.name, timebuf, AT_SYMLINK_NOFOLLOW); else retval = vfs_utimes(cfd.fd, timebuf); if (retval != 0) goto fileerr; } goto out; fileerr: retval = errno; fsal_error = posix2fsal_error(retval); out: if (cfd.close_fd) close(cfd.fd); hdlerr: return fsalstat(fsal_error, retval); } /* file_unlink * unlink the named file in the directory */ static fsal_status_t file_unlink(struct fsal_obj_handle *dir_hdl, const char *name) { struct vfs_fsal_obj_handle *myself; fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR; struct stat stat; int fd; int retval = 0; myself = container_of(dir_hdl, struct vfs_fsal_obj_handle, obj_handle); if (dir_hdl->fsal != dir_hdl->fs->fsal) { LogDebug(COMPONENT_FSAL, "FSAL %s operation for handle belonging to FSAL %s, return EXDEV", dir_hdl->fsal->name, dir_hdl->fs->fsal != NULL ? dir_hdl->fs->fsal->name : "(none)"); retval = EXDEV; fsal_error = posix2fsal_error(retval); goto out; } fd = vfs_fsal_open(myself, O_PATH | O_NOACCESS, &fsal_error); if (fd < 0) { retval = -fd; goto out; } retval = fstatat(fd, name, &stat, AT_SYMLINK_NOFOLLOW); if (retval < 0) { retval = errno; LogDebug(COMPONENT_FSAL, "fstatat %s failed %s", name, strerror(retval)); if (retval == ENOENT) fsal_error = ERR_FSAL_STALE; else fsal_error = posix2fsal_error(retval); goto errout; } fsal_set_credentials(op_ctx->creds); retval = unlinkat(fd, name, (S_ISDIR(stat.st_mode)) ? AT_REMOVEDIR : 0); if (retval < 0) { retval = errno; if (retval == ENOENT) fsal_error = ERR_FSAL_STALE; else fsal_error = posix2fsal_error(retval); } fsal_restore_ganesha_credentials(); errout: close(fd); out: return fsalstat(fsal_error, retval); } /* handle_digest * fill in the opaque f/s file handle part. * we zero the buffer to length first. This MAY already be done above * at which point, remove memset here because the caller is zeroing * the whole struct. */ static fsal_status_t handle_digest(const struct fsal_obj_handle *obj_hdl, fsal_digesttype_t output_type, struct gsh_buffdesc *fh_desc) { const 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) { /* Log, but allow digest */ LogDebug(COMPONENT_FSAL, "FSAL %s operation for handle belonging to FSAL %s", obj_hdl->fsal->name, obj_hdl->fs->fsal != NULL ? obj_hdl->fs->fsal->name : "(none)"); } switch (output_type) { case FSAL_DIGEST_NFSV3: case FSAL_DIGEST_NFSV4: if (fh_desc->len < myself->handle->handle_len) { LogMajor(COMPONENT_FSAL, "Space too small for handle. need %d, have %lu", (int) myself->handle->handle_len, fh_desc->len); return fsalstat(ERR_FSAL_TOOSMALL, 0); } memcpy(fh_desc->addr, myself->handle->handle_data, myself->handle->handle_len); break; default: return fsalstat(ERR_FSAL_SERVERFAULT, 0); } fh_desc->len = myself->handle->handle_len; return fsalstat(ERR_FSAL_NO_ERROR, 0); } /** * handle_to_key * return a handle descriptor into the handle in this object handle * @TODO reminder. make sure things like hash keys don't point here * after the handle is released. */ static void handle_to_key(struct fsal_obj_handle *obj_hdl, struct gsh_buffdesc *fh_desc) { struct vfs_fsal_obj_handle *myself; myself = container_of(obj_hdl, struct vfs_fsal_obj_handle, obj_handle); fh_desc->addr = myself->handle->handle_data; fh_desc->len = myself->handle->handle_len; } /* * release * release our export first so they know we are gone */ static void release(struct fsal_obj_handle *obj_hdl) { struct vfs_fsal_obj_handle *myself; object_file_type_t type = obj_hdl->type; myself = container_of(obj_hdl, struct vfs_fsal_obj_handle, obj_handle); if (type == REGULAR_FILE) { fsal_status_t st = vfs_close(obj_hdl); if (FSAL_IS_ERROR(st)) { LogCrit(COMPONENT_FSAL, "Could not close hdl 0x%p, error %s(%d)", obj_hdl, strerror(st.minor), st.minor); } } fsal_obj_handle_fini(obj_hdl); if (type == SYMBOLIC_LINK) { if (myself->u.symlink.link_content != NULL) gsh_free(myself->u.symlink.link_content); } else if (vfs_unopenable_type(type)) { if (myself->u.unopenable.name != NULL) gsh_free(myself->u.unopenable.name); if (myself->u.unopenable.dir != NULL) gsh_free(myself->u.unopenable.dir); } gsh_free(myself); } void vfs_handle_ops_init(struct fsal_obj_ops *ops) { ops->release = release; ops->lookup = lookup; ops->readdir = read_dirents; ops->create = create; ops->mkdir = makedir; ops->mknode = makenode; ops->symlink = makesymlink; ops->readlink = readsymlink; ops->test_access = fsal_test_access; ops->getattrs = getattrs; ops->setattrs = setattrs; ops->link = linkfile; ops->rename = renamefile; ops->unlink = file_unlink; ops->open = vfs_open; ops->status = vfs_status; ops->read = vfs_read; ops->write = vfs_write; ops->commit = vfs_commit; ops->lock_op = vfs_lock_op; ops->close = vfs_close; ops->lru_cleanup = vfs_lru_cleanup; ops->handle_digest = handle_digest; ops->handle_to_key = handle_to_key; /* xattr related functions */ ops->list_ext_attrs = vfs_list_ext_attrs; ops->getextattr_id_by_name = vfs_getextattr_id_by_name; ops->getextattr_value_by_name = vfs_getextattr_value_by_name; ops->getextattr_value_by_id = vfs_getextattr_value_by_id; ops->setextattr_value = vfs_setextattr_value; ops->setextattr_value_by_id = vfs_setextattr_value_by_id; ops->getextattr_attrs = vfs_getextattr_attrs; ops->remove_extattr_by_id = vfs_remove_extattr_by_id; ops->remove_extattr_by_name = vfs_remove_extattr_by_name; } /* export methods that create object handles */ /* lookup_path * modeled on old api except we don't stuff attributes. * KISS */ fsal_status_t vfs_lookup_path(struct fsal_export *exp_hdl, const char *path, struct fsal_obj_handle **handle) { int dir_fd = -1; struct stat stat; struct vfs_fsal_obj_handle *hdl; fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR; int retval = 0; struct fsal_filesystem *fs; struct fsal_dev__ dev; vfs_file_handle_t *fh = NULL; vfs_alloc_handle(fh); *handle = NULL; /* poison it */ dir_fd = open_dir_by_path_walk(-1, path, &stat); if (dir_fd < 0) { LogCrit(COMPONENT_FSAL, "Could not open directory for path %s", path); retval = -dir_fd; goto errout; } dev = posix2fsal_devt(stat.st_dev); fs = lookup_dev(&dev); if (fs == NULL) { LogInfo(COMPONENT_FSAL, "Could not find file system for path %s", path); retval = ENOENT; goto errout; } if (fs->fsal != exp_hdl->fsal) { LogInfo(COMPONENT_FSAL, "File system for path %s did not belong to FSAL %s", path, exp_hdl->fsal->name); retval = EACCES; goto errout; } LogDebug(COMPONENT_FSAL, "filesystem %s for path %s", fs->path, path); retval = vfs_fd_to_handle(dir_fd, fs, fh); if (retval < 0) { retval = errno; LogCrit(COMPONENT_FSAL, "Could not get handle for path %s, error %s", path, strerror(retval)); goto errout; } /* allocate an obj_handle and fill it up */ hdl = alloc_handle(-1, fh, fs, &stat, NULL, "", exp_hdl); if (hdl == NULL) { retval = ENOMEM; LogCrit(COMPONENT_FSAL, "Could not allocate handle for path %s", path); goto errout; } close(dir_fd); *handle = &hdl->obj_handle; return fsalstat(ERR_FSAL_NO_ERROR, 0); errout: if (dir_fd >= 0) close(dir_fd); fsal_error = posix2fsal_error(retval); return fsalstat(fsal_error, retval); } fsal_status_t vfs_check_handle(struct fsal_export *exp_hdl, struct gsh_buffdesc *hdl_desc, struct fsal_filesystem **fs, vfs_file_handle_t *fh, bool *dummy) { fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR; int retval = 0; struct fsal_fsid__ fsid; enum fsid_type fsid_type; *fs = NULL; if (!vfs_valid_handle(hdl_desc)) return fsalstat(ERR_FSAL_BADHANDLE, 0); memcpy(fh->handle_data, hdl_desc->addr, hdl_desc->len); fh->handle_len = hdl_desc->len; *dummy = vfs_is_dummy_handle(fh); retval = vfs_extract_fsid(fh, &fsid_type, &fsid); if (retval == 0) { *fs = lookup_fsid(&fsid, fsid_type); if (*fs == NULL) { LogInfo(COMPONENT_FSAL, "Could not map " "fsid=0x%016"PRIx64".0x%016"PRIx64 " to filesytem", fsid.major, fsid.minor); retval = ESTALE; fsal_error = posix2fsal_error(retval); goto errout; } if (((*fs)->fsal != exp_hdl->fsal) && !(*dummy)) { LogInfo(COMPONENT_FSAL, "fsid=0x%016"PRIx64".0x%016"PRIx64 " in handle not a %s filesystem", fsid.major, fsid.minor, exp_hdl->fsal->name); retval = ESTALE; fsal_error = posix2fsal_error(retval); goto errout; } LogDebug(COMPONENT_FSAL, "Found filesystem %s for handle for FSAL %s", (*fs)->path, (*fs)->fsal != NULL ? (*fs)->fsal->name : "(none)"); } else { LogDebug(COMPONENT_FSAL, "Could not map handle to fsid"); fsal_error = ERR_FSAL_BADHANDLE; goto errout; } errout: return fsalstat(fsal_error, retval); }
/** * 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); }
static fsal_status_t makedir(struct fsal_obj_handle *dir_hdl, const char *name, struct attrlist *attrib, struct fsal_obj_handle **handle) { struct vfs_fsal_obj_handle *myself, *hdl; int dir_fd; struct stat stat; mode_t unix_mode; fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR; int retval = 0; int flags = O_PATH | O_NOACCESS; vfs_file_handle_t *fh = NULL; vfs_alloc_handle(fh); LogDebug(COMPONENT_FSAL, "create %s", name); *handle = NULL; /* poison it */ if (!dir_hdl->obj_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); } myself = container_of(dir_hdl, struct vfs_fsal_obj_handle, obj_handle); if (dir_hdl->fsal != dir_hdl->fs->fsal) { LogDebug(COMPONENT_FSAL, "FSAL %s operation for handle belonging to FSAL %s, return EXDEV", dir_hdl->fsal->name, dir_hdl->fs->fsal != NULL ? dir_hdl->fs->fsal->name : "(none)"); retval = EXDEV; goto hdlerr; } unix_mode = fsal2unix_mode(attrib->mode) & ~op_ctx->fsal_export->exp_ops.fs_umask(op_ctx->fsal_export); dir_fd = vfs_fsal_open(myself, flags, &fsal_error); if (dir_fd < 0) return fsalstat(fsal_error, -dir_fd); retval = vfs_stat_by_handle(dir_fd, myself->handle, &stat, flags); if (retval < 0) { retval = errno; goto direrr; } /* Become the user because we are creating an object in this dir. */ fsal_set_credentials(op_ctx->creds); retval = mkdirat(dir_fd, name, unix_mode); if (retval < 0) { retval = errno; fsal_restore_ganesha_credentials(); goto direrr; } fsal_restore_ganesha_credentials(); retval = vfs_name_to_handle(dir_fd, dir_hdl->fs, name, fh); if (retval < 0) { retval = errno; goto fileerr; } retval = fstatat(dir_fd, name, &stat, AT_SYMLINK_NOFOLLOW); if (retval < 0) { retval = errno; goto fileerr; } /* allocate an obj_handle and fill it up */ hdl = alloc_handle(dir_fd, fh, dir_hdl->fs, &stat, myself->handle, name, op_ctx->fsal_export); if (hdl == NULL) { retval = ENOMEM; goto fileerr; } *handle = &hdl->obj_handle; close(dir_fd); return fsalstat(ERR_FSAL_NO_ERROR, 0); fileerr: unlinkat(dir_fd, name, 0); direrr: close(dir_fd); hdlerr: fsal_error = posix2fsal_error(retval); return fsalstat(fsal_error, retval); }
fsal_status_t GPFSFSAL_unlink(struct fsal_obj_handle *dir_hdl, /* IN */ const char *p_object_name, /* IN */ const struct req_op_context *p_context, /* IN */ struct attrlist *p_parent_attributes) { /* IN/OUT */ fsal_status_t status; gpfsfsal_xstat_t buffxstat; int mount_fd; struct gpfs_fsal_obj_handle *gpfs_hdl; /* sanity checks. */ if (!dir_hdl || !p_context || !p_object_name) return fsalstat(ERR_FSAL_FAULT, 0); gpfs_hdl = container_of(dir_hdl, struct gpfs_fsal_obj_handle, obj_handle); mount_fd = gpfs_get_root_fd(dir_hdl->export); /* build the child path */ /* get file metadata */ status = fsal_internal_stat_name(mount_fd, gpfs_hdl->handle, p_object_name, &buffxstat.buffstat); if (FSAL_IS_ERROR(status)) return status; /****************************** * DELETE FROM THE FILESYSTEM * ******************************/ fsal_set_credentials(p_context->creds); status = fsal_internal_unlink(mount_fd, gpfs_hdl->handle, p_object_name, &buffxstat.buffstat); fsal_restore_ganesha_credentials(); if (FSAL_IS_ERROR(status)) return status; /*********************** * FILL THE ATTRIBUTES * ***********************/ if (p_parent_attributes) { buffxstat.attr_valid = XATTR_STAT; status = gpfsfsal_xstat_2_fsal_attributes(&buffxstat, p_parent_attributes); if (FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_parent_attributes->mask); FSAL_SET_MASK(p_parent_attributes->mask, ATTR_RDATTR_ERR); } } /* OK */ return fsalstat(ERR_FSAL_NO_ERROR, 0); }
/** * @brief Create a symbolic link. * * @param dir_hdl Handle of the parent dir where the link is to be created. * @param linkname Name of the link to be created. * @param linkcontent Content of the link to be created. * @param op_ctx Authentication context for the operation (user,...). * @param accessmode Mode of the link to be created. * It has no sense in POSIX filesystems. * @param gpfs_fh Pointer to the handle of the created symlink. * @param link_attr Attributes of the newly created symlink. * 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_symlink(struct fsal_obj_handle *dir_hdl, const char *linkname, const char *linkcontent, const struct req_op_context *op_ctx, uint32_t accessmode, struct gpfs_file_handle *gpfs_fh, struct attrlist *link_attr) { int rc, errsv; fsal_status_t status; int fd; struct gpfs_fsal_obj_handle *gpfs_hdl; struct gpfs_filesystem *gpfs_fs; /* note : link_attr is optional. */ if (!dir_hdl || !op_ctx || !gpfs_fh || !linkname || !linkcontent) return fsalstat(ERR_FSAL_FAULT, 0); gpfs_hdl = container_of(dir_hdl, struct gpfs_fsal_obj_handle, obj_handle); gpfs_fs = dir_hdl->fs->private_data; /* Tests if symlinking is allowed by configuration. */ if (!op_ctx->fsal_export->exp_ops. fs_supports(op_ctx->fsal_export, fso_symlink_support)) return fsalstat(ERR_FSAL_NOTSUPP, 0); status = fsal_internal_handle2fd(gpfs_fs->root_fd, gpfs_hdl->handle, &fd, O_RDONLY | O_DIRECTORY, 0); if (FSAL_IS_ERROR(status)) return status; /* build symlink path */ /* create the symlink on the filesystem using the credentials * for proper ownership assignment. */ fsal_set_credentials(op_ctx->creds); rc = symlinkat(linkcontent, fd, linkname); errsv = errno; fsal_restore_ganesha_credentials(); if (rc) { close(fd); return fsalstat(posix2fsal_error(errsv), errsv); } /* now get the associated handle, while there is a race, there is also a race lower down */ status = fsal_internal_get_handle_at(fd, linkname, gpfs_fh); if (FSAL_IS_ERROR(status)) { close(fd); return status; } /* get attributes */ status = GPFSFSAL_getattrs(op_ctx->fsal_export, gpfs_fs, op_ctx, gpfs_fh, link_attr); if (!FSAL_IS_ERROR(status) && link_attr->type != SYMBOLIC_LINK) { /* We could wind up not failing the creation of the symlink * and the only way we know is that the object type isn't * a symlink. */ fsal_release_attrs(link_attr); status = fsalstat(ERR_FSAL_EXIST, 0); } close(fd); return status; }