/* @brief Initialize the configuration * * Given the root of the Ganesha configuration structure, initialize * the FSAL parameters. * * @param[in] fsal_hdl The FSAL module * @param[in] config_struct Parsed ganesha configuration file * * @return FSAL status. */ static fsal_status_t init_config(struct fsal_module *fsal_hdl, config_file_t /*config_struct*/) { struct this_fsal_module *module_me = container_of(fsal_hdl, struct this_fsal_module, fsal); /* Get a copy of the defaults */ module_me->fs_info = default_ovs_info; display_fsinfo(&module_me->fs_info); try { initialize_logging(); } CATCH_STD_ALL_EWHAT({ std::stringstream ss; ss << EWHAT; LogMajor(COMPONENT_FSAL, const_cast<char*>("VFS FSAL: failed to initialize logging: %s"), ss.str().c_str()); return fsalstat(ERR_FSAL_BAD_INIT, 0); });
static fsal_status_t lustre_linkfile(struct fsal_obj_handle *obj_hdl, struct fsal_obj_handle *destdir_hdl, const char *name) { struct lustre_fsal_obj_handle *myself, *destdir; char srcpath[MAXPATHLEN]; char destdirpath[MAXPATHLEN]; char destnamepath[MAXPATHLEN]; int rc = 0; fsal_errors_t fsal_error = ERR_FSAL_NO_ERROR; if (!op_ctx->fsal_export->ops-> fs_supports(op_ctx->fsal_export, fso_link_support)) { fsal_error = ERR_FSAL_NOTSUPP; goto out; } myself = container_of(obj_hdl, struct lustre_fsal_obj_handle, obj_handle); lustre_handle_to_path(obj_hdl->fs->path, myself->handle, srcpath); destdir = container_of(destdir_hdl, struct lustre_fsal_obj_handle, obj_handle); lustre_handle_to_path(obj_hdl->fs->path, destdir->handle, destdirpath); snprintf(destnamepath, MAXPATHLEN, "%s/%s", destdirpath, name); rc = CRED_WRAP(op_ctx->creds, int, link, srcpath, destnamepath); if (rc == -1) { rc = errno; fsal_error = posix2fsal_error(rc); } out: return fsalstat(fsal_error, rc); }
/** @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; }
/** @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; }
/** * @brief Set file attributes into PanFS * * Convert attributes into PanFS format and set them * * @param[in] panfs_hdl PanFS Object handle to operate on * @param[in] fd Open FD to operate on * @param[in,out] attrib Attributes to get / storage for attributes * @return ERR_FSAL_NO_ERROR on success, other error code on failure */ fsal_status_t PanFS_setattrs(struct panfs_fsal_obj_handle *panfs_hdl, int fd, struct attrlist *attrib) { fsal_status_t st; struct pan_attrs pattrs; struct pan_fs_ace_s paces[PAN_FS_ACL_LEN_MAX]; pattrs.acls.naces = PAN_FS_ACL_LEN_MAX; pattrs.acls.aces = paces; st = fsal_acl_2_panfs_acl(attrib, &pattrs.acls); if (FSAL_IS_ERROR(st)) { FSAL_CLEAR_MASK(attrib->mask); FSAL_SET_MASK(attrib->mask, ATTR_RDATTR_ERR); return st; } st = panfs_um_set_attr(fd, &pattrs); if (FSAL_IS_ERROR(st)) return st; 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); }
fsal_status_t hpss_setextattr_value_by_id(struct fsal_obj_handle *fsal_obj_hdl, unsigned int xattr_id, caddr_t buffer_addr, size_t buffer_size) { struct hpss_fsal_obj_handle *obj_hdl; int rc, index, listlen; sec_cred_t ucreds; hpss_userattr_list_t attr_list; if (!fsal_obj_hdl || !buffer_addr) return fsalstat(ERR_FSAL_FAULT, 0); if (attr_is_read_only(xattr_id)) return fsalstat(ERR_FSAL_PERM, 0); if (((char *)buffer_addr)[0] == '\0') return fsalstat(ERR_FSAL_NO_ERROR, 0); obj_hdl = container_of(fsal_obj_hdl, struct hpss_fsal_obj_handle, obj_handle); HPSSFSAL_ucreds_from_opctx(op_ctx, &ucreds); if (xattr_id < XATTR_COUNT) rc = xattr_list[xattr_id].set_func(fsal_obj_hdl, buffer_addr, buffer_size, 0, &ucreds); else { memset(&attr_list, 0, sizeof(hpss_userattr_list_t)); LogFullDebug(COMPONENT_FSAL, "Setting value for UDA #%u", xattr_id - XATTR_COUNT); /* get list of UDAs for this entry, and return the good value */ rc = hpss_UserAttrListAttrHandle(&(obj_hdl->handle->ns_handle), NULL, &ucreds, &attr_list, XML_ATTR); if (rc != 0) return fsalstat(hpss2fsal_error(rc), rc); else if (xattr_id - XATTR_COUNT >= attr_list.len) return fsalstat(ERR_FSAL_STALE, 0); listlen = attr_list.len; attr_list.Pair[0].Key = attr_list.Pair[xattr_id - XATTR_COUNT].Key; attr_list.Pair[0].Value = buffer_addr; attr_list.len = 1; rc = hpss_UserAttrSetAttrHandle(&(obj_hdl->handle->ns_handle), NULL, &ucreds, &attr_list, UDA_API_VALUE); /* Allocated by hpss - use free */ for (index = 0; index < listlen; index++) { free(attr_list.Pair[index].Key); free(attr_list.Pair[index].Value); } free(attr_list.Pair); if (rc) rc = hpss2fsal_error(rc); } return fsalstat(rc, 0); }
fsal_status_t hpss_getextattr_value_by_name( struct fsal_obj_handle *fsal_obj_hdl, const char *xattr_name, caddr_t buffer_addr, size_t buffer_size, size_t *p_output_size) { struct hpss_fsal_obj_handle *obj_hdl; int rc, index; sec_cred_t ucreds; hpss_userattr_list_t attr; char attrpath[MAXNAMLEN]; char attrval[MAXPATHLEN]; if (!fsal_obj_hdl || !p_output_size) return fsalstat(ERR_FSAL_FAULT, 0); /* check if this is an indexed fake xattr */ for (index = 0; index < XATTR_COUNT; index++) if (do_match_type(xattr_list[index].flags, fsal_obj_hdl->type) && !strcmp(xattr_list[index].xattr_name, xattr_name)) return hpss_getextattr_value_by_id(fsal_obj_hdl, index, buffer_addr, buffer_size, p_output_size); obj_hdl = container_of(fsal_obj_hdl, struct hpss_fsal_obj_handle, obj_handle); HPSSFSAL_ucreds_from_opctx(op_ctx, &ucreds); if (fsal_xattr_name_2_uda(xattr_name, attrpath) == 0) { attr.len = 1; /* use malloc because HPSS may free it */ attr.Pair = malloc(sizeof(hpss_userattr_t)); if (attr.Pair == NULL) return fsalstat(ERR_FSAL_NOMEM, errno); attr.Pair[0].Key = attrpath; attr.Pair[0].Value = attrval; rc = hpss_UserAttrGetAttrHandle(&(obj_hdl->handle->ns_handle), NULL, &ucreds, &attr, UDA_API_VALUE); if (rc) { free(attr.Pair); return fsalstat(hpss2fsal_error(rc), rc); } if (attr.len > 0) { if (attr.Pair[0].Value != NULL) { char *noxml = hpss_ChompXMLHeader( attr.Pair[0].Value, NULL); strcpy(attrval, noxml); free(noxml); strncpy((char *)buffer_addr, attrval, buffer_size); *p_output_size = strlen(attrval) + 1; } else { strcpy((char *)buffer_addr, ""); *p_output_size = 1; } free(attr.Pair); rc = 0; } else { free(attr.Pair); rc = ERR_FSAL_NOENT; } } return fsalstat(rc, 0); }
fsal_status_t tank_list_ext_attrs(struct fsal_obj_handle *obj_hdl, unsigned int argcookie, fsal_xattrent_t *xattrs_tab, unsigned int xattrs_tabsize, unsigned int *p_nb_returned, int *end_of_list) { unsigned int index; unsigned int out_index; unsigned int cookie = argcookie; struct zfs_fsal_obj_handle *obj_handle = NULL; char names[MAXPATHLEN], *ptr; size_t namesize; int xattr_idx; int retval; creden_t cred; /* sanity checks */ if (!obj_hdl || !xattrs_tab || !p_nb_returned || !end_of_list) return fsalstat(ERR_FSAL_FAULT, 0); obj_handle = container_of(obj_hdl, struct zfs_fsal_obj_handle, obj_handle); cred.uid = op_ctx->creds->caller_uid; cred.gid = op_ctx->creds->caller_gid; /* Deal with special cookie */ if (cookie == XATTR_RW_COOKIE) cookie = XATTR_COUNT; for (index = cookie, out_index = 0; index < XATTR_COUNT && out_index < xattrs_tabsize; index++) { if (do_match_type(xattr_list[index].flags, obj_hdl->attributes.type)) { /* fills an xattr entry */ xattrs_tab[out_index].xattr_id = index; strncpy(xattr_list[index].xattr_name, xattrs_tab[out_index].xattr_name, MAXNAMLEN); xattr_list[index].xattr_name[MAXNAMLEN] = '\0'; xattrs_tab[out_index].xattr_cookie = index + 1; /* set asked attributes (all supported) */ xattrs_tab[out_index].attributes.mask = obj_hdl->attributes.mask; if (file_attributes_to_xattr_attrs(&obj_hdl->attributes, &xattrs_tab [out_index] .attributes, index)) { /* set error flag */ xattrs_tab[out_index].attributes.mask = ATTR_RDATTR_ERR; } /* next output slot */ out_index++; } } /* save a call if output array is full */ if (out_index == xattrs_tabsize) { *end_of_list = false; *p_nb_returned = out_index; return fsalstat(ERR_FSAL_NO_ERROR, 0); } /* get the path of the file in Lustre */ /* get xattrs */ retval = libzfswrap_listxattr(ZFSFSAL_GetVFS(obj_handle->handle), &cred, obj_handle->handle->zfs_handle, (char **)&names, &namesize); if (retval) return fsalstat(posix2fsal_error(retval), retval); if (namesize > 0) { size_t len = 0; errno = 0; for (ptr = names, xattr_idx = 0; (ptr < names + namesize) && (out_index < xattrs_tabsize); xattr_idx++, ptr += len + 1) { len = strlen(ptr); index = XATTR_COUNT + xattr_idx; /* skip if index is before cookie */ if (index < cookie) continue; /* fills an xattr entry */ xattrs_tab[out_index].xattr_id = index; strncpy(xattrs_tab[out_index].xattr_name, ptr, len + 1); xattrs_tab[out_index].xattr_cookie = index + 1; /* set asked attributes (all supported) */ xattrs_tab[out_index].attributes.mask = obj_hdl->attributes.mask; if (file_attributes_to_xattr_attrs (&obj_hdl->attributes, &xattrs_tab[out_index].attributes, index)) { /* set error flag */ xattrs_tab[out_index].attributes.mask = ATTR_RDATTR_ERR; } /* next output slot */ out_index++; } /* all xattrs are in the output array */ if (ptr >= names + namesize) *end_of_list = true; else *end_of_list = false; } else /* no xattrs */ *end_of_list = true; *p_nb_returned = out_index; return fsalstat(ERR_FSAL_NO_ERROR, 0); }
fsal_status_t posix2fsal_attributes(const struct stat *buffstat, struct attrlist *fsalattr) { /* sanity checks */ if (!buffstat || !fsalattr) return fsalstat(ERR_FSAL_FAULT, 0); FSAL_CLEAR_MASK(fsalattr->mask); /* Fills the output struct */ fsalattr->type = posix2fsal_type(buffstat->st_mode); FSAL_SET_MASK(fsalattr->mask, ATTR_TYPE); fsalattr->filesize = buffstat->st_size; FSAL_SET_MASK(fsalattr->mask, ATTR_SIZE); fsalattr->fsid = posix2fsal_fsid(buffstat->st_dev); FSAL_SET_MASK(fsalattr->mask, ATTR_FSID); fsalattr->fileid = buffstat->st_ino; FSAL_SET_MASK(fsalattr->mask, ATTR_FILEID); fsalattr->mode = unix2fsal_mode(buffstat->st_mode); FSAL_SET_MASK(fsalattr->mask, ATTR_MODE); fsalattr->numlinks = buffstat->st_nlink; FSAL_SET_MASK(fsalattr->mask, ATTR_NUMLINKS); fsalattr->owner = buffstat->st_uid; FSAL_SET_MASK(fsalattr->mask, ATTR_OWNER); fsalattr->group = buffstat->st_gid; FSAL_SET_MASK(fsalattr->mask, ATTR_GROUP); /* Use full timer resolution */ #ifdef LINUX fsalattr->atime = buffstat->st_atim; fsalattr->ctime = buffstat->st_ctim; fsalattr->mtime = buffstat->st_mtim; fsalattr->chgtime = (gsh_time_cmp(&buffstat->st_mtim, &buffstat->st_ctim) > 0) ? fsalattr->mtime : fsalattr->ctime; #elif FREEBSD fsalattr->atime = buffstat->st_atimespec; fsalattr->ctime = buffstat->st_ctimespec; fsalattr->mtime = buffstat->st_mtimespec; fsalattr->chgtime = (gsh_time_cmp(&buffstat->st_mtimespec, &buffstat->st_ctimespec) > 0) ? fsalattr->mtime : fsalattr->ctime; #endif FSAL_SET_MASK(fsalattr->mask, ATTR_ATIME); FSAL_SET_MASK(fsalattr->mask, ATTR_CTIME); FSAL_SET_MASK(fsalattr->mask, ATTR_MTIME); fsalattr->change = timespec_to_nsecs(&fsalattr->chgtime); FSAL_SET_MASK(fsalattr->mask, ATTR_CHGTIME); fsalattr->spaceused = buffstat->st_blocks * S_BLKSIZE; FSAL_SET_MASK(fsalattr->mask, ATTR_SPACEUSED); fsalattr->rawdev = posix2fsal_devt(buffstat->st_rdev); FSAL_SET_MASK(fsalattr->mask, ATTR_RAWDEV); return fsalstat(ERR_FSAL_NO_ERROR, 0); }
int nfs3_remove(nfs_arg_t *arg, struct svc_req *req, nfs_res_t *res) { struct fsal_obj_handle *parent_obj = NULL; struct fsal_obj_handle *child_obj = NULL; pre_op_attr pre_parent = { .attributes_follow = false }; fsal_status_t fsal_status; const char *name = arg->arg_remove3.object.name; int rc = NFS_REQ_OK; if (isDebug(COMPONENT_NFSPROTO)) { char str[LEN_FH_STR]; nfs_FhandleToStr(req->rq_msg.cb_vers, &arg->arg_create3.where.dir, NULL, str); LogDebug(COMPONENT_NFSPROTO, "REQUEST PROCESSING: Calling nfs_Remove handle: %s name: %s", str, name); } /* Convert file handle into a pentry */ /* to avoid setting it on each error case */ res->res_remove3.REMOVE3res_u.resfail.dir_wcc.before.attributes_follow = FALSE; res->res_remove3.REMOVE3res_u.resfail.dir_wcc.after.attributes_follow = FALSE; parent_obj = nfs3_FhandleToCache(&arg->arg_remove3.object.dir, &res->res_remove3.status, &rc); if (parent_obj == NULL) { /* Status and rc have been set by nfs3_FhandleToCache */ goto out; } nfs_SetPreOpAttr(parent_obj, &pre_parent); /* Sanity checks: file name must be non-null; parent must be a * directory. */ if (parent_obj->type != DIRECTORY) { res->res_remove3.status = NFS3ERR_NOTDIR; rc = NFS_REQ_OK; goto out; } if (name == NULL || *name == '\0') { fsal_status = fsalstat(ERR_FSAL_INVAL, 0); goto out_fail; } /* Lookup the child entry to verify that it is not a directory */ fsal_status = fsal_lookup(parent_obj, name, &child_obj, NULL); if (!FSAL_IS_ERROR(fsal_status)) { /* Sanity check: make sure we are not removing a * directory */ if (child_obj->type == DIRECTORY) { res->res_remove3.status = NFS3ERR_ISDIR; rc = NFS_REQ_OK; goto out; } } LogFullDebug(COMPONENT_NFSPROTO, "Trying to remove file %s", name); /* Remove the entry. */ fsal_status = fsal_remove(parent_obj, name); if (FSAL_IS_ERROR(fsal_status)) goto out_fail; /* Build Weak Cache Coherency data */ nfs_SetWccData(&pre_parent, parent_obj, &res->res_remove3.REMOVE3res_u.resok.dir_wcc); res->res_remove3.status = NFS3_OK; rc = NFS_REQ_OK; goto out; out_fail: res->res_remove3.status = nfs3_Errno_status(fsal_status); nfs_SetWccData(&pre_parent, parent_obj, &res->res_remove3.REMOVE3res_u.resfail.dir_wcc); if (nfs_RetryableError(fsal_status.major)) rc = NFS_REQ_DROP; out: /* return references */ if (child_obj) child_obj->obj_ops.put_ref(child_obj); if (parent_obj) parent_obj->obj_ops.put_ref(parent_obj); return rc; } /* nfs3_remove */ /** * @brief Free the result structure allocated for nfs3_remove. * * This function frees the result structure allocated for nfs3_remove. * * @param[in,out] res Result structure * */ void nfs3_remove_free(nfs_res_t *res) { /* Nothing to do here */ }
fsal_status_t vfs_read2(struct fsal_obj_handle *obj_hdl, bool bypass, struct state_t *state, uint64_t offset, size_t buffer_size, void *buffer, size_t *read_amount, bool *end_of_file, struct io_info *info) { int my_fd = -1; ssize_t nb_read; fsal_status_t status; int retval = 0; bool has_lock = false; bool need_fsync = false; bool closefd = false; if (info != NULL) { /* Currently we don't support READ_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); } /* Get a usable file descriptor */ status = find_fd(&my_fd, obj_hdl, bypass, state, FSAL_O_READ, &has_lock, &need_fsync, &closefd, false); if (FSAL_IS_ERROR(status)) goto out; nb_read = pread(my_fd, buffer, buffer_size, offset); if (offset == -1 || nb_read == -1) { retval = errno; status = fsalstat(posix2fsal_error(retval), retval); goto out; } *read_amount = nb_read; *end_of_file = (nb_read == 0); #if 0 /** @todo * * Is this all we really need to do to support READ_PLUS? Will anyone * ever get upset that we don't return holes, even for blocks of all * zeroes? * */ if (info != NULL) { info->io_content.what = NFS4_CONTENT_DATA; info->io_content.data.d_offset = offset + nb_read; info->io_content.data.d_data.data_len = nb_read; info->io_content.data.d_data.data_val = buffer; } #endif out: if (closefd) close(my_fd); if (has_lock) PTHREAD_RWLOCK_unlock(&obj_hdl->lock); return status; }
fsal_status_t find_fd(int *fd, struct fsal_obj_handle *obj_hdl, bool bypass, struct state_t *state, fsal_openflags_t openflags, bool *has_lock, bool *need_fsync, bool *closefd, bool open_for_locks) { struct vfs_fsal_obj_handle *myself; struct vfs_filesystem *vfs_fs; struct vfs_fd temp_fd = {0, -1}, *out_fd = &temp_fd; fsal_status_t status = {ERR_FSAL_NO_ERROR, 0}; int rc, posix_flags; myself = container_of(obj_hdl, struct vfs_fsal_obj_handle, obj_handle); vfs_fs = myself->obj_handle.fs->private_data; fsal2posix_openflags(openflags, &posix_flags); /* Handle nom-regular files */ switch (obj_hdl->type) { case SOCKET_FILE: case CHARACTER_FILE: case BLOCK_FILE: rc = vfs_open_by_handle(vfs_fs, myself->u.unopenable.dir, O_PATH | O_NOACCESS, &status.major); if (rc < 0) { LogDebug(COMPONENT_FSAL, "Failed with %s openflags 0x%08x", strerror(-rc), O_PATH | O_NOACCESS); return fsalstat(posix2fsal_error(-rc), -rc); } *fd = rc; *closefd = true; return status; case REGULAR_FILE: status = fsal_find_fd((struct fsal_fd **)&out_fd, obj_hdl, (struct fsal_fd *)&myself->u.file.fd, &myself->u.file.share, bypass, state, openflags, vfs_open_func, vfs_close_func, has_lock, need_fsync, closefd, open_for_locks); *fd = out_fd->fd; return status; case SYMBOLIC_LINK: posix_flags |= (O_PATH | O_RDWR | O_NOFOLLOW); break; case FIFO_FILE: posix_flags |= O_NONBLOCK; break; case DIRECTORY: break; case NO_FILE_TYPE: case EXTENDED_ATTR: return fsalstat(posix2fsal_error(EINVAL), EINVAL); } /* Open file descriptor for non-regular files. */ rc = vfs_fsal_open(myself, posix_flags, &status.major); if (rc < 0) { LogDebug(COMPONENT_FSAL, "Failed with %s openflags 0x%08x", strerror(-rc), openflags); return fsalstat(posix2fsal_error(-rc), -rc); } LogFullDebug(COMPONENT_FSAL, "Opened fd=%d for file of type %s", rc, object_file_type_to_str(obj_hdl->type)); *fd = rc; *closefd = true; return status; }
fsal_status_t vfs_reopen2(struct fsal_obj_handle *obj_hdl, struct state_t *state, fsal_openflags_t openflags) { struct vfs_fd fd, *my_fd = &fd, *my_share_fd; struct vfs_fsal_obj_handle *myself; fsal_status_t status = {0, 0}; int posix_flags = 0; fsal_openflags_t old_openflags; my_share_fd = (struct vfs_fd *)(state + 1); fsal2posix_openflags(openflags, &posix_flags); LogFullDebug(COMPONENT_FSAL, posix_flags & O_TRUNC ? "Truncate" : "No truncate"); memset(my_fd, 0, sizeof(*my_fd)); fd.fd = -1; 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); } /* This can block over an I/O operation. */ PTHREAD_RWLOCK_wrlock(&obj_hdl->lock); old_openflags = my_share_fd->openflags; /* We can conflict with old share, so go ahead and check now. */ status = check_share_conflict(&myself->u.file.share, openflags, false); if (FSAL_IS_ERROR(status)) { PTHREAD_RWLOCK_unlock(&obj_hdl->lock); return status; } /* Set up the new share so we can drop the lock and not have a * conflicting share be asserted, updating the share counters. */ update_share_counters(&myself->u.file.share, old_openflags, openflags); PTHREAD_RWLOCK_unlock(&obj_hdl->lock); status = vfs_open_my_fd(myself, openflags, posix_flags, my_fd); if (!FSAL_IS_ERROR(status)) { /* Close the existing file descriptor and copy the new * one over. */ vfs_close_my_fd(my_share_fd); *my_share_fd = fd; } else { /* We had a failure on open - we need to revert the share. * This can block over an I/O operation. */ PTHREAD_RWLOCK_wrlock(&obj_hdl->lock); update_share_counters(&myself->u.file.share, openflags, old_openflags); PTHREAD_RWLOCK_unlock(&obj_hdl->lock); } return status; }
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); }
/** * @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; }
fsal_status_t fetch_attrs(struct vfs_fsal_obj_handle *myself, int my_fd, struct attrlist *attrs) { struct stat stat; int retval = 0; fsal_status_t status = {0, 0}; const char *func = "unknown"; /* Now stat the file as appropriate */ switch (myself->obj_handle.type) { case SOCKET_FILE: case CHARACTER_FILE: case BLOCK_FILE: retval = fstatat(my_fd, myself->u.unopenable.name, &stat, AT_SYMLINK_NOFOLLOW); func = "fstatat"; break; case REGULAR_FILE: retval = fstat(my_fd, &stat); func = "fstat"; break; case SYMBOLIC_LINK: case FIFO_FILE: case DIRECTORY: retval = vfs_stat_by_handle(my_fd, &stat); func = "vfs_stat_by_handle"; break; case NO_FILE_TYPE: case EXTENDED_ATTR: /* Caught during open with EINVAL */ break; } if (retval < 0) { if (errno == ENOENT) retval = ESTALE; else retval = errno; LogDebug(COMPONENT_FSAL, "%s failed with %s", func, strerror(retval)); if (attrs->mask & ATTR_RDATTR_ERR) { /* Caller asked for error to be visible. */ attrs->mask = ATTR_RDATTR_ERR; } return fsalstat(posix2fsal_error(retval), retval); } posix2fsal_attributes(&stat, attrs); attrs->fsid = myself->obj_handle.fs->fsid; if (myself->sub_ops && myself->sub_ops->getattrs) { status = myself->sub_ops->getattrs(myself, my_fd, attrs->mask, attrs); if (FSAL_IS_ERROR(status) && (attrs->mask & ATTR_RDATTR_ERR) != 0) { /* Caller asked for error to be visible. */ attrs->mask = ATTR_RDATTR_ERR; } } if (!FSAL_IS_ERROR(status)) { /* Make sure ATTR_RDATTR_ERR is cleared on success. */ attrs->mask &= ~ATTR_RDATTR_ERR; } return status; }
/* Covert FSAL ACLs to GPFS NFS4 ACLs. */ fsal_status_t fsal_acl_2_gpfs_acl(struct fsal_obj_handle *dir_hdl, fsal_acl_t *p_fsalacl, gpfsfsal_xstat_t *p_buffxstat) { int i; fsal_ace_t *pace; gpfs_acl_t *p_gpfsacl; p_gpfsacl = (gpfs_acl_t *) p_buffxstat->buffacl; p_gpfsacl->acl_level = 0; p_gpfsacl->acl_version = GPFS_ACL_VERSION_NFS4; p_gpfsacl->acl_type = GPFS_ACL_TYPE_NFS4; p_gpfsacl->acl_nace = p_fsalacl->naces; p_gpfsacl->acl_len = ((int)(signed long)&(((gpfs_acl_t *) 0)->ace_v1)) + p_gpfsacl->acl_nace * sizeof(gpfs_ace_v4_t); for (pace = p_fsalacl->aces, i = 0; pace < p_fsalacl->aces + p_fsalacl->naces; pace++, i++) { p_gpfsacl->ace_v4[i].aceType = pace->type; p_gpfsacl->ace_v4[i].aceFlags = pace->flag; p_gpfsacl->ace_v4[i].aceIFlags = pace->iflag; p_gpfsacl->ace_v4[i].aceMask = pace->perm; if (IS_FSAL_ACE_SPECIAL_ID(*pace)) p_gpfsacl->ace_v4[i].aceWho = pace->who.uid; else { if (IS_FSAL_ACE_GROUP_ID(*pace)) p_gpfsacl->ace_v4[i].aceWho = pace->who.gid; else p_gpfsacl->ace_v4[i].aceWho = pace->who.uid; } LogMidDebug(COMPONENT_FSAL, "fsal_acl_2_gpfs_acl: gpfs ace: type = 0x%x, flag = 0x%x, perm = 0x%x, special = %d, %s = 0x%x", p_gpfsacl->ace_v4[i].aceType, p_gpfsacl->ace_v4[i].aceFlags, p_gpfsacl->ace_v4[i].aceMask, (p_gpfsacl->ace_v4[i]. aceIFlags & FSAL_ACE_IFLAG_SPECIAL_ID) ? 1 : 0, (p_gpfsacl->ace_v4[i]. aceFlags & FSAL_ACE_FLAG_GROUP_ID) ? "gid" : "uid", p_gpfsacl->ace_v4[i].aceWho); /* It is invalid to set inherit flags on non dir objects */ if (dir_hdl->type != DIRECTORY && (p_gpfsacl->ace_v4[i].aceFlags & FSAL_ACE_FLAG_INHERIT) != 0) { LogMidDebug(COMPONENT_FSAL, "attempt to set inherit flag to non dir object"); return fsalstat(ERR_FSAL_INVAL, 0); } /* It is invalid to set inherit only with * out an actual inherit flag */ if ((p_gpfsacl->ace_v4[i].aceFlags & FSAL_ACE_FLAG_INHERIT) == FSAL_ACE_FLAG_INHERIT_ONLY) { LogMidDebug(COMPONENT_FSAL, "attempt to set inherit only without an inherit flag"); return fsalstat(ERR_FSAL_INVAL, 0); } } return fsalstat(ERR_FSAL_NO_ERROR, 0); }
/* Same function as posixstat64_2_fsal_attributes. When NFS4 ACL support * is enabled, this will replace posixstat64_2_fsal_attributes. */ fsal_status_t gpfsfsal_xstat_2_fsal_attributes(gpfsfsal_xstat_t *p_buffxstat, struct attrlist *p_fsalattr_out, bool use_acl) { struct stat *p_buffstat; /* sanity checks */ if (!p_buffxstat || !p_fsalattr_out) return fsalstat(ERR_FSAL_FAULT, 0); p_buffstat = &p_buffxstat->buffstat; LogDebug(COMPONENT_FSAL, "inode %ld", p_buffstat->st_ino); /* Fills the output struct */ if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_TYPE)) { p_fsalattr_out->type = posix2fsal_type(p_buffstat->st_mode); LogFullDebug(COMPONENT_FSAL, "type = 0x%x", p_fsalattr_out->type); } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_SIZE)) { p_fsalattr_out->filesize = p_buffstat->st_size; LogFullDebug(COMPONENT_FSAL, "filesize = %llu", (unsigned long long)p_fsalattr_out->filesize); } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_FSID)) { p_fsalattr_out->fsid = p_buffxstat->fsal_fsid; LogFullDebug(COMPONENT_FSAL, "fsid=0x%016"PRIx64".0x%016"PRIx64, p_fsalattr_out->fsid.major, p_fsalattr_out->fsid.minor); } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_ACL)) { p_fsalattr_out->acl = NULL; if (use_acl && p_buffxstat->attr_valid & XATTR_ACL) { /* ACL is valid, so try to convert fsal acl. */ gpfs_acl_2_fsal_acl(p_fsalattr_out, (gpfs_acl_t *) p_buffxstat-> buffacl); } LogFullDebug(COMPONENT_FSAL, "acl = %p", p_fsalattr_out->acl); } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_FILEID)) { p_fsalattr_out->fileid = (uint64_t) (p_buffstat->st_ino); LogFullDebug(COMPONENT_FSAL, "fileid = %lu", p_fsalattr_out->fileid); } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_MODE)) { p_fsalattr_out->mode = unix2fsal_mode(p_buffstat->st_mode); LogFullDebug(COMPONENT_FSAL, "mode = %"PRIu32, p_fsalattr_out->mode); } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_NUMLINKS)) { p_fsalattr_out->numlinks = p_buffstat->st_nlink; LogFullDebug(COMPONENT_FSAL, "numlinks = %u", p_fsalattr_out->numlinks); } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_OWNER)) { p_fsalattr_out->owner = p_buffstat->st_uid; LogFullDebug(COMPONENT_FSAL, "owner = %lu", p_fsalattr_out->owner); } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_GROUP)) { p_fsalattr_out->group = p_buffstat->st_gid; LogFullDebug(COMPONENT_FSAL, "group = %lu", p_fsalattr_out->group); } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_ATIME)) { p_fsalattr_out->atime = posix2fsal_time(p_buffstat->st_atime, p_buffstat->st_atim.tv_nsec); LogFullDebug(COMPONENT_FSAL, "atime = %lu", p_fsalattr_out->atime.tv_sec); } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_CTIME)) { p_fsalattr_out->ctime = posix2fsal_time(p_buffstat->st_ctime, p_buffstat->st_ctim.tv_nsec); LogFullDebug(COMPONENT_FSAL, "ctime = %lu", p_fsalattr_out->ctime.tv_sec); } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_MTIME)) { p_fsalattr_out->mtime = posix2fsal_time(p_buffstat->st_mtime, p_buffstat->st_mtim.tv_nsec); LogFullDebug(COMPONENT_FSAL, "mtime = %lu", p_fsalattr_out->mtime.tv_sec); } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_CHGTIME)) { if (p_buffstat->st_mtime == p_buffstat->st_ctime) { if (p_buffstat->st_mtim.tv_nsec > p_buffstat->st_ctim.tv_nsec) p_fsalattr_out->chgtime = posix2fsal_time(p_buffstat->st_mtime, p_buffstat->st_mtim. tv_nsec); else p_fsalattr_out->chgtime = posix2fsal_time(p_buffstat->st_ctime, p_buffstat->st_ctim. tv_nsec); } else if (p_buffstat->st_mtime > p_buffstat->st_ctime) { p_fsalattr_out->chgtime = posix2fsal_time(p_buffstat->st_mtime, p_buffstat->st_mtim.tv_nsec); } else { p_fsalattr_out->chgtime = posix2fsal_time(p_buffstat->st_ctime, p_buffstat->st_ctim.tv_nsec); } p_fsalattr_out->change = (uint64_t) p_fsalattr_out->chgtime.tv_sec + (uint64_t) p_fsalattr_out->chgtime.tv_nsec; LogFullDebug(COMPONENT_FSAL, "chgtime = %lu", p_fsalattr_out->chgtime.tv_sec); } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_SPACEUSED)) { p_fsalattr_out->spaceused = p_buffstat->st_blocks * S_BLKSIZE; LogFullDebug(COMPONENT_FSAL, "spaceused = %llu", (unsigned long long)p_fsalattr_out->spaceused); } if (FSAL_TEST_MASK(p_fsalattr_out->mask, ATTR_RAWDEV)) { p_fsalattr_out->rawdev = posix2fsal_devt(p_buffstat->st_rdev); LogFullDebug(COMPONENT_FSAL, "rawdev major = %u, minor = %u", (unsigned int)p_fsalattr_out->rawdev.major, (unsigned int)p_fsalattr_out->rawdev.minor); } /* everything has been copied ! */ return fsalstat(ERR_FSAL_NO_ERROR, 0); }
fsal_status_t hpss_remove_extattr_by_id(struct fsal_obj_handle *obj_hdl, unsigned int xattr_id) { return fsalstat(ERR_FSAL_NOTSUPP, 0); }
static fsal_status_t init_config(struct fsal_module *fsal_hdl, config_file_t config_struct) { return fsalstat(ERR_FSAL_NO_ERROR, 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); }
fsal_status_t hpss_remove_extattr_by_name(struct fsal_obj_handle *obj_hdl, const char *xattr_name) { return fsalstat(ERR_FSAL_NOTSUPP, 0); }
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); }
/** * 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); }
fsal_status_t hpss_list_ext_attrs(struct fsal_obj_handle *fsal_obj_hdl, unsigned int cookie, fsal_xattrent_t *xattrs_tab, unsigned int xattrs_tabsize, unsigned int *p_nb_returned, int *end_of_list) { struct hpss_fsal_obj_handle *obj_hdl; int index, out_index, rc; sec_cred_t ucreds; hpss_userattr_list_t attr_list; if (!fsal_obj_hdl || !xattrs_tab || !p_nb_returned || !end_of_list) return fsalstat(ERR_FSAL_FAULT, 0); obj_hdl = container_of(fsal_obj_hdl, struct hpss_fsal_obj_handle, obj_handle); HPSSFSAL_ucreds_from_opctx(op_ctx, &ucreds); for (index = cookie, out_index = 0; index < XATTR_COUNT && out_index < xattrs_tabsize; index++) { if (do_match_type(xattr_list[index].flags, fsal_obj_hdl->type)) { /* fills an xattr entry */ xattrs_tab[out_index].xattr_id = index; memcpy(xattrs_tab[out_index].xattr_name, xattr_list[index].xattr_name, strlen(xattr_list[index].xattr_name)+1); xattrs_tab[out_index].xattr_cookie = index + 1; /* set asked attributes */ file_attributes_to_xattr_attrs( &obj_hdl->attributes, &xattrs_tab[out_index].attributes, index); /* next output slot */ out_index++; } } /* save a call if output array is full */ if (out_index == xattrs_tabsize) { *end_of_list = FALSE; *p_nb_returned = out_index; return fsalstat(ERR_FSAL_NO_ERROR, 0); } /* get list of UDAs for this entry */ memset(&attr_list, 0, sizeof(hpss_userattr_list_t)); rc = hpss_UserAttrListAttrHandle(&(obj_hdl->handle->ns_handle), NULL, &ucreds, &attr_list, XML_ATTR); if (rc == -ENOENT) attr_list.len = 0; else if (rc) return fsalstat(hpss2fsal_error(rc), -rc); unsigned int i; for (i = 0; (i < attr_list.len) && (out_index < xattrs_tabsize); i++) { char attr_name[MAXNAMLEN]; /* the id is XATTR_COUNT + index of HPSS UDA */ index = XATTR_COUNT + i; /* continue while index < cookie */ if (index < cookie) continue; xattrs_tab[out_index].xattr_id = index; if (strlen(attr_list.Pair[i].Key) >= MAXNAMLEN) return fsalstat(ERR_FSAL_NAMETOOLONG, 0); /* HPSS UDAs namespace is slash-separated. * we convert '/' to '.' */ rc = hpss_uda_name_2_fsal(attr_list.Pair[i].Key, attr_name); if (rc != ERR_FSAL_NO_ERROR) return fsalstat(rc, 0); memcpy(xattrs_tab[out_index].xattr_name, attr_name, strlen(attr_name)+1); xattrs_tab[out_index].xattr_cookie = index + 1; /* set asked attributes */ file_attributes_to_xattr_attrs( &obj_hdl->attributes, &xattrs_tab[out_index].attributes, index); /* we know the size here (+2 for \n\0) */ if (attr_list.Pair[i].Value != NULL) xattrs_tab[out_index].attributes.filesize = strlen(attr_list.Pair[i].Value) + 2; /* next output slot */ out_index++; } /* Allocated by hpss - use free */ for (index = 0; index < attr_list.len; index++) { free(attr_list.Pair[index].Key); free(attr_list.Pair[index].Value); } free(attr_list.Pair); /* not end of list if there is more UDAs */ if (i < attr_list.len) *end_of_list = FALSE; else *end_of_list = TRUE; *p_nb_returned = out_index; return fsalstat(ERR_FSAL_NO_ERROR, 0); }
fsal_status_t gpfs_read_plus(struct fsal_obj_handle *obj_hdl, uint64_t offset, size_t buffer_size, void *buffer, size_t *read_amount, bool *end_of_file, struct io_info *info) { struct gpfs_fsal_obj_handle *myself; fsal_status_t status = { ERR_FSAL_NO_ERROR, 0 }; struct read_arg rarg; ssize_t nb_read; int errsv = 0; if (!buffer || !read_amount || !end_of_file || !info) return fsalstat(ERR_FSAL_FAULT, 0); myself = container_of(obj_hdl, struct gpfs_fsal_obj_handle, obj_handle); assert(myself->u.file.fd >= 0 && myself->u.file.openflags != FSAL_O_CLOSED); rarg.mountdirfd = myself->u.file.fd; rarg.fd = myself->u.file.fd; rarg.bufP = buffer; rarg.offset = offset; rarg.length = buffer_size; rarg.options = IO_SKIP_HOLE; nb_read = gpfs_ganesha(OPENHANDLE_READ_BY_FD, &rarg); errsv = errno; if (nb_read < 0) { if (errsv == EUNATCH) LogFatal(COMPONENT_FSAL, "GPFS Returned EUNATCH"); if (errsv != ENODATA) return fsalstat(posix2fsal_error(errsv), errsv); /* errsv == ENODATA */ info->io_content.what = NFS4_CONTENT_HOLE; info->io_content.hole.di_offset = offset; /*offset of hole*/ info->io_content.hole.di_length = buffer_size;/*length of hole*/ *read_amount = buffer_size; if ((buffer_size + offset) > myself->attributes.filesize) { if (offset > myself->attributes.filesize) *read_amount = 0; else *read_amount = myself->attributes.filesize - offset; info->io_content.hole.di_length = *read_amount; } } else { info->io_content.what = NFS4_CONTENT_DATA; info->io_content.data.d_offset = offset + nb_read; info->io_content.data.d_data.data_len = nb_read; info->io_content.data.d_data.data_val = buffer; *read_amount = nb_read; } if (nb_read != -1 && (nb_read == 0 || nb_read < buffer_size || ((offset + nb_read) >= myself->attributes.filesize))) *end_of_file = true; else *end_of_file = false; return status; }
fsal_status_t hpss_getextattr_id_by_name(struct fsal_obj_handle *fsal_obj_hdl, const char *xattr_name, unsigned int *pxattr_id) { struct hpss_fsal_obj_handle *obj_hdl; unsigned int index; int found = FALSE; if (!fsal_obj_hdl || !xattr_name || !pxattr_id) return fsalstat(ERR_FSAL_FAULT, 0); obj_hdl = container_of(fsal_obj_hdl, struct hpss_fsal_obj_handle, obj_handle); for (index = 0; index < XATTR_COUNT; index++) { if (do_match_type(xattr_list[index].flags, fsal_obj_hdl->type) && !strcmp(xattr_list[index].xattr_name, xattr_name)) { found = TRUE; break; } } if (!found) { /* search for name in UDAs */ hpss_userattr_list_t attr_list; unsigned int i; int rc; char attrpath[MAXNAMLEN]; sec_cred_t ucreds; HPSSFSAL_ucreds_from_opctx(op_ctx, &ucreds); /* convert FSAL xattr name to HPSS attr path. * returns error if it is not a UDA name. */ if (fsal_xattr_name_2_uda(xattr_name, attrpath) == 0) { memset(&attr_list, 0, sizeof(hpss_userattr_list_t)); LogFullDebug(COMPONENT_FSAL, "looking for xattr '%s' in UDAs", xattr_name); /* get list of UDAs, and return the good index*/ rc = hpss_UserAttrListAttrHandle(&(obj_hdl->handle->ns_handle), NULL, &ucreds, &attr_list, XML_ATTR); if (rc == 0) for (i = 0; i < attr_list.len; i++) if (!strcmp(attr_list.Pair[i].Key, attrpath)) { /* xattr index is XATTR_COUNT + * UDA index */ index = XATTR_COUNT + i; found = TRUE; break; } /* Allocated by hpss - use free */ for (i = 0; i < attr_list.len; i++) { free(attr_list.Pair[i].Key); free(attr_list.Pair[i].Value); } free(attr_list.Pair); } } if (found) { *pxattr_id = index; return fsalstat(ERR_FSAL_NO_ERROR, 0); } else return fsalstat(ERR_FSAL_NOENT, ENOENT); }
fsal_status_t tank_getextattr_value_by_id(struct fsal_obj_handle *obj_hdl, unsigned int xattr_id, caddr_t buffer_addr, size_t buffer_size, size_t *p_output_size) { struct zfs_fsal_obj_handle *obj_handle = NULL; int retval = -1; creden_t cred; obj_handle = container_of(obj_hdl, struct zfs_fsal_obj_handle, obj_handle); /* sanity checks */ if (!obj_hdl || !p_output_size || !buffer_addr) return fsalstat(ERR_FSAL_FAULT, 0); cred.uid = op_ctx->creds->caller_uid; cred.gid = op_ctx->creds->caller_gid; /* check that this index match the type of entry */ if ((xattr_id < XATTR_COUNT) && !do_match_type(xattr_list[xattr_id].flags, obj_hdl->attributes.type)) { return fsalstat(ERR_FSAL_INVAL, 0); } else if (xattr_id >= XATTR_COUNT) { char attr_name[MAXPATHLEN]; /* get the name for this attr */ retval = xattr_id_to_name(ZFSFSAL_GetVFS(obj_handle->handle), &cred, obj_handle->handle->zfs_handle, xattr_id, attr_name); if (retval) return fsalstat(retval, 0); retval = libzfswrap_getxattr(ZFSFSAL_GetVFS(obj_handle->handle), &cred, obj_handle->handle->zfs_handle, attr_name, &buffer_addr); if (retval) return fsalstat(posix2fsal_error(retval), retval); /* the xattr value can be a binary, or a string. * trying to determine its type... */ *p_output_size = strnlen(buffer_addr, buffer_size); xattr_format_value(buffer_addr, p_output_size, buffer_size); return fsalstat(ERR_FSAL_NO_ERROR, 0); } else { /* built-in attr */ /* get the value */ retval = xattr_list[xattr_id].get_func(obj_hdl, buffer_addr, buffer_size, p_output_size, xattr_list[xattr_id] .arg); return fsalstat(retval, 0); } }
fsal_status_t hpss_getextattr_value_by_id(struct fsal_obj_handle *fsal_obj_hdl, unsigned int xattr_id, caddr_t buffer_addr, size_t buffer_size, size_t *p_output_size) { struct hpss_fsal_obj_handle *obj_hdl; int rc, i; sec_cred_t ucreds; hpss_userattr_list_t attr_list; if (!fsal_obj_hdl || !p_output_size) return fsalstat(ERR_FSAL_FAULT, 0); obj_hdl = container_of(fsal_obj_hdl, struct hpss_fsal_obj_handle, obj_handle); HPSSFSAL_ucreds_from_opctx(op_ctx, &ucreds); /* check that this index match the type of entry */ if (xattr_id < XATTR_COUNT) { if (!do_match_type(xattr_list[xattr_id].flags, fsal_obj_hdl->type)) return fsalstat(ERR_FSAL_INVAL, 0); rc = xattr_list[xattr_id].get_func(fsal_obj_hdl, buffer_addr, buffer_size, p_output_size, &ucreds); } else if (xattr_id >= XATTR_COUNT) { memset(&attr_list, 0, sizeof(hpss_userattr_list_t)); LogFullDebug(COMPONENT_FSAL, "Getting value for UDA #%u", xattr_id - XATTR_COUNT); /* get list of UDAs for this entry, and * return the good value */ rc = hpss_UserAttrListAttrHandle(&(obj_hdl->handle->ns_handle), NULL, &ucreds, &attr_list, XML_ATTR); if (rc != 0) return fsalstat(hpss2fsal_error(rc), rc); else if (xattr_id - XATTR_COUNT >= attr_list.len) return fsalstat(ERR_FSAL_STALE, 0); if ((attr_list.Pair[xattr_id - XATTR_COUNT].Value != NULL) && (attr_list.Pair[xattr_id - XATTR_COUNT].Value[0] != '\0')) *p_output_size = snprintf((char *)buffer_addr, buffer_size, "%s\n", attr_list.Pair[xattr_id - XATTR_COUNT].Value); else { ((char *)buffer_addr)[0] = '\0'; *p_output_size = 0; } /* Allocated by hpss - use free */ for (i = 0; i < attr_list.len; i++) { free(attr_list.Pair[i].Key); free(attr_list.Pair[i].Value); } free(attr_list.Pair); return fsalstat(ERR_FSAL_NO_ERROR, 0); } return fsalstat(rc, 0); }