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 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_open: * Open a regular file for reading/writing its data content. * * \param filehandle (input): * Handle of the file to be read/modified. * \param cred (input): * Authentication context for the operation (user,...). * \param openflags (input): * 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_descriptor (output): * The file descriptor to be used for FSAL_read/write operations. * \param file_attributes (optionnal input/output): * Post operation attributes. * 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). * * \return Major error codes: * - ERR_FSAL_NO_ERROR: no error. * - Another error code if an error occured during this call. */ fsal_status_t GPFSFSAL_open(fsal_handle_t * p_filehandle, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_openflags_t openflags, /* IN */ fsal_file_t * file_desc, /* OUT */ fsal_attrib_list_t * p_file_attributes /* [ IN/OUT ] */ ) { int rc, errsv; fsal_status_t status; int fd; int posix_flags = 0; gpfsfsal_file_t * p_file_descriptor = (gpfsfsal_file_t *)file_desc; /* sanity checks. * note : file_attributes is optional. */ if(!p_filehandle || !p_context || !p_file_descriptor) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_open); /* convert fsal open flags to posix open flags */ rc = fsal2posix_openflags(openflags, &posix_flags); /* flags conflicts. */ if(rc) { LogWarn(COMPONENT_FSAL, "Invalid/conflicting flags : %#X", openflags); Return(rc, 0, INDEX_FSAL_open); } TakeTokenFSCall(); status = fsal_internal_handle2fd(p_context, p_filehandle, &fd, posix_flags); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_open); /* output attributes */ if(p_file_attributes) { p_file_attributes->asked_attributes = GPFS_SUPPORTED_ATTRIBUTES; status = GPFSFSAL_getattrs(p_filehandle, p_context, p_file_attributes); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_open); } TakeTokenFSCall(); p_file_descriptor->fd = fd; errsv = errno; ReleaseTokenFSCall(); /* set the read-only flag of the file descriptor */ p_file_descriptor->ro = openflags & FSAL_O_RDONLY; Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_open); }
fsal_status_t WRAP_GPFSFSAL_getattrs(fsal_handle_t * p_filehandle, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_attrib_list_t * p_object_attributes /* IN/OUT */ ) { return GPFSFSAL_getattrs((gpfsfsal_handle_t *) p_filehandle, (gpfsfsal_op_context_t *) p_context, p_object_attributes); }
/** * GPFSFSAL_getattrs_descriptor: * Get attributes for the object specified by its descriptor or by it's filehandle. * * \param p_file_descriptor (input): * The file descriptor of the object to get parameters. * \param p_filehandle (input): * The handle of the object to get parameters. * \param p_context (input): * Authentication context for the operation (user,...). * \param p_object_attributes (mandatory input/output): * The retrieved attributes for the object. * As input, it defines the attributes that the caller * wants to retrieve (by positioning flags into this structure) * and the output is built considering this input * (it fills the structure according to the flags it contains). * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - Another error code if an error occured. */ fsal_status_t GPFSFSAL_getattrs_descriptor(fsal_file_t * p_file_descriptor, /* IN */ fsal_handle_t * p_filehandle, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_attrib_list_t * p_object_attributes /* IN/OUT */ ) { return GPFSFSAL_getattrs(p_filehandle, p_context, p_object_attributes); }
/** * FSAL_opendir : * Opens a directory for reading its content. * * \param dir_handle (input) * the handle of the directory to be opened. * \param cred (input) * Permission context for the operation (user,...). * \param dir_descriptor (output) * pointer to an allocated structure that will receive * directory stream informations, on successfull completion. * \param dir_attributes (optional output) * On successfull completion,the structure pointed * by dir_attributes receives the new directory attributes. * May be NULL. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - Another error code if an error occured. */ fsal_status_t GPFSFSAL_opendir(fsal_handle_t * p_dir_handle, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_dir_t * dir_desc, /* OUT */ fsal_attrib_list_t * p_dir_attributes /* [ IN/OUT ] */ ) { fsal_status_t status; fsal_accessflags_t access_mask = 0; fsal_attrib_list_t dir_attrs; gpfsfsal_dir_t *p_dir_descriptor = (gpfsfsal_dir_t *)dir_desc; /* sanity checks * note : dir_attributes is optionnal. */ if(!p_dir_handle || !p_context || !p_dir_descriptor) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_opendir); /* get the path of the directory */ TakeTokenFSCall(); status = fsal_internal_handle2fd(p_context, p_dir_handle, &p_dir_descriptor->fd, O_RDONLY | O_DIRECTORY); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_opendir); /* get directory metadata */ dir_attrs.asked_attributes = GPFS_SUPPORTED_ATTRIBUTES; status = GPFSFSAL_getattrs(p_dir_handle, p_context, &dir_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_opendir); /* Test access rights for this directory */ /* Set both mode and ace4 mask */ access_mask = FSAL_MODE_MASK_SET(FSAL_R_OK) | FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_LIST_DIR); status = fsal_internal_testAccess(p_context, access_mask, NULL, &dir_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_opendir); /* if everything is OK, fills the dir_desc structure : */ memcpy(&(p_dir_descriptor->context), p_context, sizeof(fsal_op_context_t)); memcpy(&(p_dir_descriptor->handle), p_dir_handle, sizeof(fsal_handle_t)); if(p_dir_attributes) *p_dir_attributes = dir_attrs; p_dir_descriptor->dir_offset = 0; Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_opendir); }
/** * Get the attributes of an extended attribute from its index. * * \param p_objecthandle Handle of the object you want to get attribute for. * \param p_context pointer to the current security context. * \param xattr_cookie xattr's cookie (as returned by listxattrs). * \param p_attrs xattr's attributes. */ fsal_status_t GPFSFSAL_GetXAttrAttrs(fsal_handle_t * p_objecthandle, /* IN */ fsal_op_context_t * p_context, /* IN */ unsigned int xattr_id, /* IN */ fsal_attrib_list_t * p_attrs /**< IN/OUT xattr attributes (if supported) */ ) { #if 0 int rc; char buff[MAXNAMLEN+1]; fsal_status_t st; fsal_attrib_list_t file_attrs; #endif /* sanity checks */ if(!p_objecthandle || !p_context || !p_attrs) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_GetXAttrAttrs); /* @todo: to be implemented */ Return(ERR_FSAL_NOTSUPP, 0, INDEX_FSAL_GetXAttrAttrs); #if 0 /* check that this index match the type of entry */ if(xattr_id >= XATTR_COUNT || !do_match_type(xattr_list[xattr_id].flags, p_objecthandle->handle.handle_type)) { Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_GetXAttrAttrs); } /* object attributes we want to retrieve from parent */ file_attrs.asked_attributes = FSAL_ATTR_MODE | FSAL_ATTR_FILEID | FSAL_ATTR_OWNER | FSAL_ATTR_GROUP | FSAL_ATTR_ATIME | FSAL_ATTR_MTIME | FSAL_ATTR_CTIME | FSAL_ATTR_CREATION | FSAL_ATTR_CHGTIME | FSAL_ATTR_FSID; /* don't retrieve attributes not asked */ file_attrs.asked_attributes &= p_attrs->asked_attributes; st = GPFSFSAL_getattrs(p_objecthandle, p_context, &file_attrs); if(FSAL_IS_ERROR(st)) Return(st.major, st.minor, INDEX_FSAL_GetXAttrAttrs); if((rc = file_attributes_to_xattr_attrs(&file_attrs, p_attrs, xattr_id))) { Return(ERR_FSAL_INVAL, rc, INDEX_FSAL_GetXAttrAttrs); } Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_GetXAttrAttrs); #endif } /* FSAL_GetXAttrAttrs */
static fsal_status_t getattrs(struct fsal_obj_handle *obj_hdl, struct attrlist *attrs) { struct gpfs_fsal_obj_handle *myself; fsal_status_t status; myself = container_of(obj_hdl, struct gpfs_fsal_obj_handle, obj_handle); status = GPFSFSAL_getattrs(op_ctx->fsal_export, obj_hdl->fs->private_data, op_ctx, myself->handle, attrs); if (FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(attrs->mask); FSAL_SET_MASK(attrs->mask, ATTR_RDATTR_ERR); } return status; }
fsal_status_t GPFSFSAL_lookupPath(fsal_path_t * p_path, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_handle_t * object_handle, /* OUT */ fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */ ) { fsal_status_t status; /* sanity checks * note : object_attributes is optionnal. */ if(!object_handle || !p_context || !p_path) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_lookupPath); /* test whether the path begins with a slash */ if(p_path->path[0] != '/') Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_lookupPath); /* directly call the lookup function */ status = fsal_internal_get_handle(p_context, p_path, object_handle); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_lookupPath); /* get object attributes */ if(p_object_attributes) { status = GPFSFSAL_getattrs(object_handle, p_context, p_object_attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_object_attributes->asked_attributes); FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_lookupPath); }
/** * @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_mkdir: * Create a directory. * * \param parent_directory_handle (input): * Handle of the parent directory where * the subdirectory is to be created. * \param p_dirname (input): * Pointer to the name of the directory to be created. * \param cred (input): * Authentication context for the operation (user,...). * \param accessmode (input): * Mode for the directory to be created. * (the umask defined into the FSAL configuration file * will be applied on it). * \param object_handle (output): * Pointer to the handle of the created directory. * \param object_attributes (optionnal input/output): * The attributes of the created directory. * As input, it defines the attributes that the caller * wants to retrieve (by positioning flags into this structure) * and the output is built considering this input * (it fills the structure according to the flags it contains). * May be NULL. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - Another error code if an error occured. */ fsal_status_t GPFSFSAL_mkdir(fsal_handle_t * p_parent_directory_handle, /* IN */ fsal_name_t * p_dirname, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_accessmode_t accessmode, /* IN */ fsal_handle_t * p_object_handle, /* OUT */ fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */ ) { int rc, errsv; int setgid_bit = 0; mode_t unix_mode; fsal_status_t status; int fd, newfd; fsal_accessflags_t access_mask = 0; fsal_attrib_list_t parent_dir_attrs; /* sanity checks. * note : object_attributes is optional. */ if(!p_parent_directory_handle || !p_context || !p_object_handle || !p_dirname) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mkdir); /* convert FSAL mode to unix mode. */ unix_mode = fsal2unix_mode(accessmode); /* Apply umask */ unix_mode = unix_mode & ~global_fs_info.umask; TakeTokenFSCall(); status = fsal_internal_handle2fd(p_context, p_parent_directory_handle, &fd, O_RDONLY); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_mkdir); /* get directory metadata */ parent_dir_attrs.asked_attributes = GPFS_SUPPORTED_ATTRIBUTES; status = GPFSFSAL_getattrs(p_parent_directory_handle, p_context, &parent_dir_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_create); /* Check the user can write in the directory, and check the setgid bit on the directory */ if(fsal2unix_mode(parent_dir_attrs.mode) & S_ISGID) setgid_bit = 1; /* Set both mode and ace4 mask */ access_mask = FSAL_MODE_MASK_SET(FSAL_W_OK | FSAL_X_OK) | FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_ADD_SUBDIRECTORY); status = fsal_internal_testAccess(p_context, access_mask, NULL, &parent_dir_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_mkdir); /* build new entry path */ /* creates the directory and get its handle */ TakeTokenFSCall(); rc = mkdirat(fd, p_dirname->name, unix_mode); errsv = errno; if(rc) { close(fd); ReleaseTokenFSCall(); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir); } ReleaseTokenFSCall(); /**** * There is a race here between mkdir creation and the open, not * sure there is any way to close it in practice. */ /* get the new handle */ TakeTokenFSCall(); status = fsal_internal_get_handle_at(fd, p_dirname, p_object_handle); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) { close(fd); ReturnStatus(status, INDEX_FSAL_mkdir); } TakeTokenFSCall(); status = fsal_internal_handle2fd_at(fd, p_object_handle, &newfd, O_RDONLY | O_DIRECTORY); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) { close(fd); ReturnStatus(status, INDEX_FSAL_mkdir); } /* the directory has been created */ /* chown the dir to the current user/group */ if(p_context->credential.user != geteuid()) { TakeTokenFSCall(); /* if the setgid_bit was set on the parent directory, do not change the group of the created file, because it's already the parentdir's group */ rc = fchown(newfd, p_context->credential.user, setgid_bit ? -1 : (int)p_context->credential.group); errsv = errno; ReleaseTokenFSCall(); if(rc) { close(fd); close(newfd); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir); } } close(fd); close(newfd); /* retrieve file attributes */ if(p_object_attributes) { status = GPFSFSAL_getattrs(p_object_handle, p_context, p_object_attributes); /* on error, we set a special bit in the mask. */ if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_object_attributes->asked_attributes); FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_mkdir); }
/** * 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_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); }
/** * 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); }
fsal_status_t GPFSFSAL_truncate(gpfsfsal_handle_t * p_filehandle, /* IN */ gpfsfsal_op_context_t * p_context, /* IN */ fsal_size_t length, /* IN */ gpfsfsal_file_t * file_descriptor, /* Unused in this FSAL */ fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */ ) { int rc, errsv; int fd; fsal_status_t st; /* sanity checks. * note : object_attributes is optional. */ if(!p_filehandle || !p_context) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_truncate); /* get the path of the file and its handle */ TakeTokenFSCall(); st = fsal_internal_handle2fd(p_context, p_filehandle, &fd, O_RDWR); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(st)) ReturnStatus(st, INDEX_FSAL_truncate); /* Executes the POSIX truncate operation */ TakeTokenFSCall(); rc = ftruncate(fd, length); errsv = errno; ReleaseTokenFSCall(); close(fd); /* convert return code */ if(rc) { if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_truncate); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_truncate); } /* Optionally retrieve attributes */ if(p_object_attributes) { fsal_status_t st; st = GPFSFSAL_getattrs(p_filehandle, p_context, p_object_attributes); if(FSAL_IS_ERROR(st)) { FSAL_CLEAR_MASK(p_object_attributes->asked_attributes); FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } /* No error occurred */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_truncate); }
/** * GPFSFSAL_setattrs: * Set attributes for the object specified by its filehandle. * * \param filehandle (input): * The handle of the object to get parameters. * \param cred (input): * Authentication context for the operation (user,...). * \param attrib_set (mandatory input): * The attributes to be set for the object. * It defines the attributes that the caller * wants to set and their values. * \param object_attributes (optionnal input/output): * The post operation attributes for the object. * As input, it defines the attributes that the caller * wants to retrieve (by positioning flags into this structure) * and the output is built considering this input * (it fills the structure according to the flags it contains). * May be NULL. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - Another error code if an error occured. */ fsal_status_t GPFSFSAL_setattrs(fsal_handle_t * p_filehandle, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_attrib_list_t * p_attrib_set, /* IN */ fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */ ) { unsigned int i; fsal_status_t status; /* Buffer that will be passed to gpfs_ganesha API. */ gpfsfsal_xstat_t buffxstat; /* Indicate if stat or acl or both should be changed. */ int attr_valid = 0; /* Indiate which attribute in stat should be changed. */ int attr_changed = 0; fsal_accessflags_t access_mask = 0; fsal_attrib_list_t wanted_attrs, current_attrs; /* sanity checks. * note : object_attributes is optional. */ if(!p_filehandle || !p_context || !p_attrib_set) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_setattrs); /* local copy of attributes */ wanted_attrs = *p_attrib_set; /* It does not make sense to setattr on a symlink */ /* if(p_filehandle->type == DT_LNK) return fsal_internal_setattrs_symlink(p_filehandle, p_context, p_attrib_set, p_object_attributes); */ /* First, check that FSAL attributes changes are allowed. */ /* Is it allowed to change times ? */ if(!global_fs_info.cansettime) { if(wanted_attrs.asked_attributes & (FSAL_ATTR_ATIME | FSAL_ATTR_CREATION | FSAL_ATTR_CTIME | FSAL_ATTR_MTIME)) { /* handled as an unsettable attribute. */ Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_setattrs); } } /* apply umask, if mode attribute is to be changed */ if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_MODE)) { wanted_attrs.mode &= (~global_fs_info.umask); } /* get current attributes */ current_attrs.asked_attributes = GPFS_SUPPORTED_ATTRIBUTES; status = GPFSFSAL_getattrs(p_filehandle, p_context, ¤t_attrs); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_object_attributes->asked_attributes); FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); ReturnStatus(status, INDEX_FSAL_setattrs); } /*********** * CHMOD * ***********/ if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_MODE)) { /* The POSIX chmod call don't affect the symlink object, but * the entry it points to. So we must ignore it. */ if(current_attrs.type != FSAL_TYPE_LNK) { #ifdef _USE_NFS4_ACL if(current_attrs.acl) { /* Check permission using ACL. */ access_mask = FSAL_MODE_MASK_SET(0) | /* Dummy. */ FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_ATTR); status = fsal_internal_testAccess(p_context, access_mask, NULL, ¤t_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_setattrs); } else { #endif /* For modifying mode, user must be root or the owner */ if((p_context->credential.user != 0) && (p_context->credential.user != current_attrs.owner)) { LogFullDebug(COMPONENT_FSAL, "Permission denied for CHMOD opeartion: current owner=%d, credential=%d", current_attrs.owner, p_context->credential.user); Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); } #ifdef _USE_NFS4_ACL } #endif attr_valid |= XATTR_STAT; attr_changed |= XATTR_MODE; /* Fill wanted mode. */ buffxstat.buffstat.st_mode = fsal2unix_mode(wanted_attrs.mode); LogDebug(COMPONENT_FSAL, "current mode = %o, new mode = %o", fsal2unix_mode(current_attrs.mode), buffxstat.buffstat.st_mode); } } /*********** * CHOWN * ***********/ /* Only root can change uid and A normal user must be in the group he wants to set */ if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_OWNER)) { #ifdef _USE_NFS4_ACL if(current_attrs.acl) { /* Check permission using ACL. */ access_mask = FSAL_MODE_MASK_SET(0) | /* Dummy. */ FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_OWNER); status = fsal_internal_testAccess(p_context, access_mask, NULL, ¤t_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_setattrs); } else { #endif /* For modifying owner, user must be root or current owner==wanted==client */ if((p_context->credential.user != 0) && ((p_context->credential.user != current_attrs.owner) || (p_context->credential.user != wanted_attrs.owner))) { LogFullDebug(COMPONENT_FSAL, "Permission denied for CHOWN opeartion: current owner=%d, credential=%d, new owner=%d", current_attrs.owner, p_context->credential.user, wanted_attrs.owner); Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); } #ifdef _USE_NFS4_ACL } #endif } if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_GROUP)) { #ifdef _USE_NFS4_ACL if(current_attrs.acl) { /* Check permission using ACL. */ access_mask = FSAL_MODE_MASK_SET(0) | /* Dummy. */ FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_OWNER); status = fsal_internal_testAccess(p_context, access_mask, NULL, ¤t_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_setattrs); } else { #endif /* For modifying group, user must be root or current owner */ if((p_context->credential.user != 0) && (p_context->credential.user != current_attrs.owner)) { Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); } int in_grp = 0; /* set in_grp */ if(p_context->credential.group == wanted_attrs.group) in_grp = 1; else for(i = 0; i < p_context->credential.nbgroups; i++) { if((in_grp = (wanted_attrs.group == p_context->credential.alt_groups[i]))) break; } /* it must also be in target group */ if(p_context->credential.user != 0 && !in_grp) { LogFullDebug(COMPONENT_FSAL, "Permission denied for CHOWN operation: current group=%d, credential=%d, new group=%d", current_attrs.group, p_context->credential.group, wanted_attrs.group); Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); } #ifdef _USE_NFS4_ACL } #endif } if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_OWNER | FSAL_ATTR_GROUP)) { /* LogFullDebug(COMPONENT_FSAL, "Performing chown(%s, %d,%d)", fsalpath.path, FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_OWNER) ? (int)wanted_attrs.owner : -1, FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_GROUP) ? (int)wanted_attrs.group : -1);*/ attr_valid |= XATTR_STAT; attr_changed |= FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_OWNER) ? XATTR_UID : XATTR_GID; /* Fill wanted owner. */ if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_OWNER)) { buffxstat.buffstat.st_uid = (int)wanted_attrs.owner; LogDebug(COMPONENT_FSAL, "current uid = %d, new uid = %d", current_attrs.owner, buffxstat.buffstat.st_uid); } /* Fill wanted group. */ if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_GROUP)) { buffxstat.buffstat.st_gid = (int)wanted_attrs.group; LogDebug(COMPONENT_FSAL, "current gid = %d, new gid = %d", current_attrs.group, buffxstat.buffstat.st_gid); } } /*********** * UTIME * ***********/ /* user must be the owner or have read access to modify 'atime' */ access_mask = FSAL_MODE_MASK_SET(FSAL_R_OK) | FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_ATTR); if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_ATIME) && (p_context->credential.user != 0) && (p_context->credential.user != current_attrs.owner) && ((status = fsal_internal_testAccess(p_context, access_mask, NULL, ¤t_attrs)).major != ERR_FSAL_NO_ERROR)) { ReturnStatus(status, INDEX_FSAL_setattrs); } /* user must be the owner or have write access to modify 'mtime' */ access_mask = FSAL_MODE_MASK_SET(FSAL_W_OK) | FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_ATTR); if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_MTIME) && (p_context->credential.user != 0) && (p_context->credential.user != current_attrs.owner) && ((status = fsal_internal_testAccess(p_context, access_mask, NULL, ¤t_attrs)).major != ERR_FSAL_NO_ERROR)) { ReturnStatus(status, INDEX_FSAL_setattrs); } if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_ATIME | FSAL_ATTR_MTIME)) { attr_valid |= XATTR_STAT; /* Fill wanted atime. */ if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_ATIME)) { attr_changed |= XATTR_ATIME; buffxstat.buffstat.st_atime = (time_t) wanted_attrs.atime.seconds; LogDebug(COMPONENT_FSAL, "current atime = %lu, new atime = %lu", (unsigned long)current_attrs.atime.seconds, (unsigned long)buffxstat.buffstat.st_atime); } /* Fill wanted mtime. */ if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_MTIME)) { attr_changed |= XATTR_CTIME; buffxstat.buffstat.st_mtime = (time_t) wanted_attrs.mtime.seconds; LogDebug(COMPONENT_FSAL, "current mtime = %lu, new mtime = %lu", (unsigned long)current_attrs.mtime.seconds, (unsigned long)buffxstat.buffstat.st_mtime); } } #ifdef _USE_NFS4_ACL /*********** * ACL * ***********/ if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_ACL)) { /* Check permission to set ACL. */ access_mask = FSAL_MODE_MASK_SET(0) | /* Dummy */ FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_ACL); status = fsal_internal_testAccess(p_context, access_mask, NULL, ¤t_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_setattrs); if(wanted_attrs.acl) { attr_valid |= XATTR_ACL; LogDebug(COMPONENT_FSAL, "setattr acl = %p", wanted_attrs.acl); /* Convert FSAL ACL to GPFS NFS4 ACL and fill the buffer. */ status = fsal_acl_2_gpfs_acl(wanted_attrs.acl, &buffxstat); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_setattrs); } else { LogCrit(COMPONENT_FSAL, "setattr acl is NULL"); Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_setattrs); } } #endif /* _USE_NFS4_ACL */ /* If there is any change in stat or acl or both, send it down to file system. */ if((attr_valid == XATTR_STAT && attr_changed !=0) || attr_valid == XATTR_ACL) { status = fsal_set_xstat_by_handle(p_context, p_filehandle, attr_valid, attr_changed, &buffxstat); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_setattrs); } /* Optionaly fills output attributes. */ if(p_object_attributes) { status = GPFSFSAL_getattrs(p_filehandle, p_context, p_object_attributes); /* on error, we set a special bit in the mask. */ if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_object_attributes->asked_attributes); FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_setattrs); }
/** * FSAL_open: * Open a regular file for reading/writing its data content. * * \param filehandle (input): * Handle of the file to be read/modified. * \param cred (input): * Authentication context for the operation (user,...). * \param openflags (input): * 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_descriptor (output): * The file descriptor to be used for FSAL_read/write operations. * \param file_attributes (optionnal input/output): * Post operation attributes. * 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). * * \return Major error codes: * - ERR_FSAL_NO_ERROR: no error. * - Another error code if an error occured during this call. */ fsal_status_t GPFSFSAL_open(fsal_handle_t * p_filehandle, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_openflags_t openflags, /* IN */ fsal_file_t * file_desc, /* OUT */ fsal_attrib_list_t * p_file_attributes /* [ IN/OUT ] */ ) { int rc, errsv; fsal_status_t status; int fd; int posix_flags = 0; fsal_accessflags_t access_mask = 0; fsal_attrib_list_t file_attrs; gpfsfsal_file_t * p_file_descriptor = (gpfsfsal_file_t *)file_desc; /* sanity checks. * note : file_attributes is optional. */ if(!p_filehandle || !p_context || !p_file_descriptor) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_open); /* convert fsal open flags to posix open flags */ rc = fsal2posix_openflags(openflags, &posix_flags); /* flags conflicts. */ if(rc) { LogWarn(COMPONENT_FSAL, "Invalid/conflicting flags : %#X", openflags); Return(rc, 0, INDEX_FSAL_open); } TakeTokenFSCall(); status = fsal_internal_handle2fd(p_context, p_filehandle, &fd, posix_flags); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_open); /* retrieve file attributes for checking access rights */ file_attrs.asked_attributes = GPFS_SUPPORTED_ATTRIBUTES; status = GPFSFSAL_getattrs(p_filehandle, p_context, &file_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_open); /* Set both mode and ace4 mask */ if(openflags & FSAL_O_RDONLY) access_mask = FSAL_MODE_MASK_SET(FSAL_R_OK | FSAL_OWNER_OK) | FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_READ_DATA); else access_mask = FSAL_MODE_MASK_SET(FSAL_W_OK | FSAL_OWNER_OK) | FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_DATA | FSAL_ACE_PERM_APPEND_DATA); status = fsal_internal_testAccess(p_context, access_mask, NULL, &file_attrs); if(FSAL_IS_ERROR(status)) { close(fd); ReturnStatus(status, INDEX_FSAL_open); } TakeTokenFSCall(); p_file_descriptor->fd = fd; errsv = errno; ReleaseTokenFSCall(); /* set the read-only flag of the file descriptor */ p_file_descriptor->ro = openflags & FSAL_O_RDONLY; /* output attributes */ if(p_file_attributes) *p_file_attributes = file_attrs; Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_open); }
/** * FSAL_create: * Create a regular file. * * \param parent_directory_handle (input): * Handle of the parent directory where the file is to be created. * \param p_filename (input): * Pointer to the name of the file to be created. * \param cred (input): * Authentication context for the operation (user,...). * \param accessmode (input): * Mode for the file to be created. * (the umask defined into the FSAL configuration file * will be applied on it). * \param object_handle (output): * Pointer to the handle of the created file. * \param object_attributes (optional input/output): * The attributes of the created file. * As input, it defines the attributes that the caller * wants to retrieve (by positioning flags into this structure) * and the output is built considering this input * (it fills the structure according to the flags it contains). * May be NULL. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - Another error code if an error occurred. */ fsal_status_t GPFSFSAL_create(fsal_handle_t * p_parent_directory_handle, /* IN */ fsal_name_t * p_filename, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_accessmode_t accessmode, /* IN */ fsal_handle_t * p_object_handle, /* OUT */ fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */ ) { int rc = 0, errsv; int setgid_bit = 0; fsal_status_t status; int fd, newfd; mode_t unix_mode; fsal_accessflags_t access_mask = 0; fsal_attrib_list_t parent_dir_attrs; /* sanity checks. * note : object_attributes is optional. */ if(!p_parent_directory_handle || !p_context || !p_object_handle || !p_filename) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create); /* convert fsal mode to unix mode. */ unix_mode = fsal2unix_mode(accessmode); /* Apply umask */ unix_mode = unix_mode & ~global_fs_info.umask; LogFullDebug(COMPONENT_FSAL, "Creation mode: 0%o", accessmode); TakeTokenFSCall(); status = fsal_internal_handle2fd(p_context, p_parent_directory_handle, &fd, O_RDONLY | O_DIRECTORY); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_create); /* retrieve directory metadata */ parent_dir_attrs.asked_attributes = GPFS_SUPPORTED_ATTRIBUTES; status = GPFSFSAL_getattrs(p_parent_directory_handle, p_context, &parent_dir_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_create); /* Check the user can write in the directory, and check the setgid bit on the directory */ if(fsal2unix_mode(parent_dir_attrs.mode) & S_ISGID) setgid_bit = 1; /* Set both mode and ace4 mask */ access_mask = FSAL_MODE_MASK_SET(FSAL_W_OK | FSAL_X_OK) | FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_ADD_FILE); status = fsal_internal_testAccess(p_context, access_mask, NULL, &parent_dir_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_create); /* call to filesystem */ TakeTokenFSCall(); /* create the file. * O_EXCL=> error if the file already exists */ newfd = openat(fd, p_filename->name, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, unix_mode); errsv = errno; if(newfd < 0) { close(fd); ReleaseTokenFSCall(); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create); } /* we no longer need the parent directory open any more */ close(fd); /* close the file descriptor */ /*** * Previously the file handle was closed here. I don't think that we need that, but leaving the commented out logic just in case. rc = close(newfd); errsv = errno; if(rc) { close(fd); ReleaseTokenFSCall(); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create); } */ /* get a handle for this new fd, doing this directly ensures no race because we still have the fd open until the end of this function */ status = fsal_internal_fd2handle(newfd, p_object_handle); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) { close(newfd); ReturnStatus(status, INDEX_FSAL_create); } /* the file has been created */ /* chown the file to the current user */ if(p_context->credential.user != geteuid()) { TakeTokenFSCall(); /* if the setgid_bit was set on the parent directory, do not change the group of the created file, because it's already the parentdir's group */ rc = fchown(newfd, p_context->credential.user, setgid_bit ? -1 : (int)p_context->credential.group); errsv = errno; ReleaseTokenFSCall(); if(rc) { close(newfd); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create); } } /* if we got this far successfully, but the file close fails, we've got a problem, possibly a disk full problem. */ close(newfd); if(rc) Return(posix2fsal_error(errno), errno, INDEX_FSAL_create); /* retrieve file attributes */ if(p_object_attributes) { status = GPFSFSAL_getattrs(p_object_handle, p_context, p_object_attributes); /* on error, we set a special bit in the mask. */ if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_object_attributes->asked_attributes); FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_create); }
/** * FSAL_link: * Create a hardlink. * * \param target_handle (input): * Handle of the target object. * \param dir_handle (input): * Pointer to the directory handle where * the hardlink is to be created. * \param p_link_name (input): * Pointer to the name of the hardlink 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 attributes (optionnal input/output): * The post_operation attributes of the linked object. * As input, it defines the attributes that the caller * wants to retrieve (by positioning flags into this structure) * and the output is built considering this input * (it fills the structure according to the flags it contains). * May be NULL. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - Another error code if an error occured. */ fsal_status_t GPFSFSAL_link(fsal_handle_t * p_target_handle, /* IN */ fsal_handle_t * p_dir_handle, /* IN */ fsal_name_t * p_link_name, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_attrib_list_t * p_attributes /* [ IN/OUT ] */ ) { fsal_status_t status; int srcfd, dstfd; fsal_accessflags_t access_mask = 0; fsal_attrib_list_t parent_dir_attrs; /* sanity checks. * note : attributes is optional. */ if(!p_target_handle || !p_dir_handle || !p_context || !p_context->export_context || !p_link_name || !p_link_name->name) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_link); /* Tests if hardlinking is allowed by configuration. */ if(!global_fs_info.link_support) Return(ERR_FSAL_NOTSUPP, 0, INDEX_FSAL_link); /* get the target handle access by fid */ TakeTokenFSCall(); status = fsal_internal_handle2fd(p_context, p_target_handle, &srcfd, O_RDONLY); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_link); /* build the destination path and check permissions on the directory */ TakeTokenFSCall(); status = fsal_internal_handle2fd(p_context, p_dir_handle, &dstfd, O_RDONLY | O_DIRECTORY); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) { close(srcfd); ReturnStatus(status, INDEX_FSAL_link); } /* retrieve target directory metadata */ parent_dir_attrs.asked_attributes = GPFS_SUPPORTED_ATTRIBUTES; status = GPFSFSAL_getattrs(p_dir_handle, p_context, &parent_dir_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_link); /* check permission on target 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); status = fsal_internal_testAccess(p_context, access_mask, NULL, &parent_dir_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_link); /* Create the link on the filesystem */ TakeTokenFSCall(); status = fsal_internal_link_at(srcfd, dstfd, p_link_name->name); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) { close(srcfd); close(dstfd); ReturnStatus(status, INDEX_FSAL_link); } /* optionnaly get attributes */ if(p_attributes) { status = GPFSFSAL_getattrs(p_target_handle, p_context, p_attributes); /* on error, we set a special bit in the mask. */ if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_attributes->asked_attributes); FSAL_SET_MASK(p_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } close(srcfd); close(dstfd); /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_link); }
/** * @brief create GPFS handle * * @param exp_hdl export handle * @param hdl_desc handle description * @param handle object handle * @return status * * Does what original FSAL_ExpandHandle did (sort of) * returns a ref counted handle to be later used in cache_inode etc. * NOTE! you must release this thing when done with it! * BEWARE! Thanks to some holes in the *AT syscalls implementation, * we cannot get an fd on an AF_UNIX socket, nor reliably on block or * character special devices. Sorry, it just doesn't... * we could if we had the handle of the dir it is in, but this method * is for getting handles off the wire for cache entries that have LRU'd. * Ideas and/or clever hacks are welcome... */ fsal_status_t gpfs_create_handle(struct fsal_export *exp_hdl, struct gsh_buffdesc *hdl_desc, struct fsal_obj_handle **handle, struct attrlist *attrs_out) { int retval = 0; fsal_status_t status; struct gpfs_fsal_obj_handle *hdl; struct gpfs_file_handle *fh; struct attrlist attrib; char *link_content = NULL; ssize_t retlink = PATH_MAX - 1; char link_buff[PATH_MAX]; struct fsal_fsid__ fsid; struct fsal_filesystem *fs; struct gpfs_filesystem *gpfs_fs; *handle = NULL; /* poison it first */ if ((hdl_desc->len > (sizeof(struct gpfs_file_handle)))) return fsalstat(ERR_FSAL_FAULT, 0); fh = alloca(hdl_desc->len); memcpy(fh, hdl_desc->addr, hdl_desc->len); /* struct aligned copy */ gpfs_extract_fsid(fh, &fsid); fs = lookup_fsid(&fsid, GPFS_FSID_TYPE); if (fs == NULL) { LogInfo(COMPONENT_FSAL, "Could not find filesystem for fsid=0x%016"PRIx64 ".0x%016"PRIx64" from handle", fsid.major, fsid.minor); return fsalstat(ERR_FSAL_STALE, ESTALE); } if (fs->fsal != exp_hdl->fsal) { LogInfo(COMPONENT_FSAL, "Non GPFS filesystem fsid=0x%016"PRIx64 ".0x%016"PRIx64" from handle", fsid.major, fsid.minor); return fsalstat(ERR_FSAL_STALE, ESTALE); } gpfs_fs = fs->private_data; fsal_prepare_attrs(&attrib, ATTR_GPFS_ALLOC_HANDLE); if (attrs_out != NULL) attrib.mask |= attrs_out->mask; status = GPFSFSAL_getattrs(exp_hdl, gpfs_fs, op_ctx, fh, &attrib); if (FSAL_IS_ERROR(status)) return status; if (attrib.type == SYMBOLIC_LINK) { /* I could lazy eval this... */ status = fsal_readlink_by_handle(gpfs_fs->root_fd, fh, link_buff, &retlink); if (FSAL_IS_ERROR(status)) return status; if (retlink < 0 || retlink == PATH_MAX) { retval = errno; if (retlink == PATH_MAX) retval = ENAMETOOLONG; return fsalstat(posix2fsal_error(retval), retval); } link_buff[retlink] = '\0'; link_content = link_buff; } hdl = alloc_handle(fh, fs, &attrib, link_content, exp_hdl); if (attrs_out != NULL) { /* Copy the attributes to caller, passing ACL ref. */ fsal_copy_attrs(attrs_out, &attrib, true); } else { /* Done with the attrs */ fsal_release_attrs(&attrib); } *handle = &hdl->obj_handle; return status; }
fsal_status_t GPFSFSAL_rename(fsal_handle_t * p_old_parentdir_handle, /* IN */ fsal_name_t * p_old_name, /* IN */ fsal_handle_t * p_new_parentdir_handle, /* IN */ fsal_name_t * p_new_name, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_attrib_list_t * p_src_dir_attributes, /* [ IN/OUT ] */ fsal_attrib_list_t * p_tgt_dir_attributes /* [ IN/OUT ] */ ) { int rc, errsv; fsal_status_t status; struct stat buffstat; int old_parent_fd, new_parent_fd; int src_equal_tgt = FALSE; fsal_accessflags_t access_mask = 0; fsal_attrib_list_t src_dir_attrs, tgt_dir_attrs; /* sanity checks. * note : src/tgt_dir_attributes are optional. */ if(!p_old_parentdir_handle || !p_new_parentdir_handle || !p_old_name || !p_new_name || !p_context) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_rename); /* Get directory access path by fid */ TakeTokenFSCall(); status = fsal_internal_handle2fd(p_context, p_old_parentdir_handle, &old_parent_fd, O_RDONLY | O_DIRECTORY); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_rename); /* retrieve directory metadata for checking access rights */ src_dir_attrs.asked_attributes = GPFS_SUPPORTED_ATTRIBUTES; status = GPFSFSAL_getattrs(p_old_parentdir_handle, p_context, &src_dir_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_rename); /* optimisation : don't do the job twice if source dir = dest dir */ if(!FSAL_handlecmp(p_old_parentdir_handle, p_new_parentdir_handle, &status)) { new_parent_fd = old_parent_fd; src_equal_tgt = TRUE; tgt_dir_attrs = src_dir_attrs; } else { TakeTokenFSCall(); status = fsal_internal_handle2fd(p_context, p_new_parentdir_handle, &new_parent_fd, O_RDONLY | O_DIRECTORY); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) { close(old_parent_fd); ReturnStatus(status, INDEX_FSAL_rename); } /* retrieve destination attrs */ tgt_dir_attrs.asked_attributes = GPFS_SUPPORTED_ATTRIBUTES; status = GPFSFSAL_getattrs(p_new_parentdir_handle, p_context, &tgt_dir_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_rename); } /* check access rights */ /* Set both mode and ace4 mask */ access_mask = FSAL_MODE_MASK_SET(FSAL_W_OK | FSAL_X_OK) | FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_DELETE_CHILD); if(!p_context->export_context->fe_static_fs_info->accesscheck_support) status = fsal_internal_testAccess(p_context, access_mask, NULL, &src_dir_attrs); else status = fsal_internal_access(p_context, p_old_parentdir_handle, access_mask, &src_dir_attrs); if(FSAL_IS_ERROR(status)) { close(old_parent_fd); if (!src_equal_tgt) close(new_parent_fd); ReturnStatus(status, INDEX_FSAL_rename); } if(!src_equal_tgt) { access_mask = FSAL_MODE_MASK_SET(FSAL_W_OK | FSAL_X_OK) | FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_ADD_FILE | FSAL_ACE_PERM_ADD_SUBDIRECTORY); if(!p_context->export_context->fe_static_fs_info->accesscheck_support) status = fsal_internal_testAccess(p_context, access_mask, NULL, &tgt_dir_attrs); else status = fsal_internal_access(p_context, p_new_parentdir_handle, access_mask, &tgt_dir_attrs); if(FSAL_IS_ERROR(status)) { close(old_parent_fd); close(new_parent_fd); ReturnStatus(status, INDEX_FSAL_rename); } } /* build file paths */ TakeTokenFSCall(); rc = fstatat(old_parent_fd, p_old_name->name, &buffstat, AT_SYMLINK_NOFOLLOW); errsv = errno; ReleaseTokenFSCall(); if(rc) { close(old_parent_fd); if (!src_equal_tgt) close(new_parent_fd); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename); } /* Check sticky bits */ /* Sticky bit on the source directory => the user who wants to delete the file must own it or its parent dir */ if((fsal2unix_mode(src_dir_attrs.mode) & S_ISVTX) && src_dir_attrs.owner != p_context->credential.user && buffstat.st_uid != p_context->credential.user && p_context->credential.user != 0) { close(old_parent_fd); if (!src_equal_tgt) close(new_parent_fd); Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_rename); } /* Sticky bit on the target directory => the user who wants to create the file must own it or its parent dir */ if(fsal2unix_mode(tgt_dir_attrs.mode) & S_ISVTX) { TakeTokenFSCall(); rc = fstatat(new_parent_fd, p_new_name->name, &buffstat, AT_SYMLINK_NOFOLLOW); errsv = errno; ReleaseTokenFSCall(); if(rc < 0) { if(errsv != ENOENT) { close(old_parent_fd); if (!src_equal_tgt) close(new_parent_fd); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename); } } else { if(tgt_dir_attrs.owner != p_context->credential.user && buffstat.st_uid != p_context->credential.user && p_context->credential.user != 0) { close(old_parent_fd); if (!src_equal_tgt) close(new_parent_fd); Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_rename); } } } /************************************* * Rename the file on the filesystem * *************************************/ TakeTokenFSCall(); rc = renameat(old_parent_fd, p_old_name->name, new_parent_fd, p_new_name->name); errsv = errno; ReleaseTokenFSCall(); close(old_parent_fd); if (!src_equal_tgt) close(new_parent_fd); if(rc) Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename); /*********************** * Fill the attributes * ***********************/ if(p_src_dir_attributes) { status = GPFSFSAL_getattrs(p_old_parentdir_handle, p_context, p_src_dir_attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_src_dir_attributes->asked_attributes); FSAL_SET_MASK(p_src_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } if(p_tgt_dir_attributes) { status = GPFSFSAL_getattrs(p_new_parentdir_handle, p_context, p_tgt_dir_attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_tgt_dir_attributes->asked_attributes); FSAL_SET_MASK(p_tgt_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_rename); }
/** * @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; }
/** * @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); }
/** * FSAL_mknode: * Create a special object in the filesystem. * Not supported upon HPSS. * * \return ERR_FSAL_NOTSUPP. */ fsal_status_t GPFSFSAL_mknode(fsal_handle_t * parentdir_handle, /* IN */ fsal_name_t * p_node_name, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_accessmode_t accessmode, /* IN */ fsal_nodetype_t nodetype, /* IN */ fsal_dev_t * dev, /* IN */ fsal_handle_t * p_object_handle, /* OUT (handle to the created node) */ fsal_attrib_list_t * node_attributes /* [ IN/OUT ] */ ) { int rc, errsv; int setgid_bit = 0; fsal_status_t status; int fd, newfd; mode_t unix_mode = 0; dev_t unix_dev = 0; fsal_accessflags_t access_mask = 0; fsal_attrib_list_t parent_dir_attrs; /* sanity checks. * note : link_attributes is optional. */ if(!parentdir_handle || !p_context || !p_node_name) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mknode); unix_mode = fsal2unix_mode(accessmode); /* Apply umask */ unix_mode = unix_mode & ~global_fs_info.umask; switch (nodetype) { case FSAL_TYPE_BLK: if(!dev) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mknode); unix_mode |= S_IFBLK; unix_dev = (dev->major << 8) | (dev->minor & 0xFF); break; case FSAL_TYPE_CHR: if(!dev) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mknode); unix_mode |= S_IFCHR; unix_dev = (dev->major << 8) | (dev->minor & 0xFF); break; case FSAL_TYPE_SOCK: unix_mode |= S_IFSOCK; break; case FSAL_TYPE_FIFO: unix_mode |= S_IFIFO; break; default: LogMajor(COMPONENT_FSAL, "Invalid node type in FSAL_mknode: %d", nodetype); Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_mknode); } /* build the directory path */ status = fsal_internal_handle2fd(p_context, parentdir_handle, &fd, O_RDONLY | O_DIRECTORY); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_mknode); /* retrieve directory attributes */ parent_dir_attrs.asked_attributes = GPFS_SUPPORTED_ATTRIBUTES; status = GPFSFSAL_getattrs(parentdir_handle, p_context, &parent_dir_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_mknode); /* Check the user can write in the directory, and check weither the setgid bit on the directory */ if(fsal2unix_mode(parent_dir_attrs.mode) & S_ISGID) setgid_bit = 1; /* Set both mode and ace4 mask */ access_mask = FSAL_MODE_MASK_SET(FSAL_W_OK | FSAL_X_OK) | FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_ADD_FILE); status = fsal_internal_testAccess(p_context, access_mask, NULL, &parent_dir_attrs); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_mknode); /* creates the node, then stats it */ rc = mknodat(fd, p_node_name->name, unix_mode, unix_dev); errsv = errno; if(rc) { close(fd); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mknode); } /* WARNING: * After creating the new node, the node name could have been changed. * This is a race condition. However only root creates new nodes. This * is an unlikely race condition, but hopefully can be fixed someday. */ if(FSAL_IS_ERROR(status = fsal_internal_get_handle_at(fd, p_node_name, p_object_handle))) { close(fd); ReturnStatus(status, INDEX_FSAL_mknode); } if(FSAL_IS_ERROR(status = fsal_internal_handle2fd_at(fd, p_object_handle, &newfd, O_RDONLY | O_NOFOLLOW))) { close(fd); ReturnStatus(status, INDEX_FSAL_mknode); } /* the node has been created */ /* chown the file to the current user/group */ if(p_context->credential.user != geteuid()) { /* if the setgid_bit was set on the parent directory, do not change the group of the created file, because it's already the parentdir's group */ rc = fchown(newfd, p_context->credential.user, setgid_bit ? -1 : (int)p_context->credential.group); errsv = errno; if(rc) { close(fd); close(newfd); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mknode); } } close(fd); close(newfd); /* Fills the attributes if needed */ if(node_attributes) { status = GPFSFSAL_getattrs(p_object_handle, p_context, node_attributes); /* on error, we set a special bit in the mask. */ if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(node_attributes->asked_attributes); FSAL_SET_MASK(node_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } /* Finished */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_mknode); }
/** * FSAL_lookup : * Looks up for an object into a directory. * * Note : if parent handle and filename are NULL, * this retrieves root's handle. * * \param parent_directory_handle (input) * Handle of the parent directory to search the object in. * \param filename (input) * The name of the object to find. * \param p_context (input) * Authentication context for the operation (user,...). * \param object_handle (output) * The handle of the object corresponding to filename. * \param object_attributes (optional input/output) * Pointer to the attributes of the object we found. * 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). * It can be NULL (increases performances). * * \return - ERR_FSAL_NO_ERROR, if no error. * - Another error code else. * */ fsal_status_t GPFSFSAL_lookup(fsal_handle_t * p_parent_directory_handle, /* IN */ fsal_name_t * p_filename, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_handle_t * object_handle, /* OUT */ fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */ ) { fsal_status_t status; int parentfd; fsal_accessflags_t access_mask = 0; fsal_attrib_list_t parent_dir_attrs; gpfsfsal_handle_t *p_object_handle = (gpfsfsal_handle_t *)object_handle; /* sanity checks * note : object_attributes is optional * parent_directory_handle may be null for getting FS root. */ if(!p_object_handle || !p_context) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_lookup); /* filename AND parent handle are NULL => lookup "/" */ if((p_parent_directory_handle && !p_filename) || (!p_parent_directory_handle && p_filename)) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_lookup); /* get information about root */ if(!p_parent_directory_handle) { gpfsfsal_handle_t *root_handle = &((gpfsfsal_op_context_t *)p_context)->export_context->mount_root_handle; /* get handle for the mount point */ memcpy(p_object_handle->data.handle.f_handle, root_handle->data.handle.f_handle, sizeof(root_handle->data.handle.handle_size)); p_object_handle->data.handle.handle_size = root_handle->data.handle.handle_size; p_object_handle->data.handle.handle_key_size = root_handle->data.handle.handle_key_size; /* get attributes, if asked */ if(p_object_attributes) { status = GPFSFSAL_getattrs(object_handle, p_context, p_object_attributes); 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); } } /* Done */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_lookup); } /* retrieve directory attributes */ TakeTokenFSCall(); status = fsal_internal_handle2fd(p_context, p_parent_directory_handle, &parentfd, O_RDONLY); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_lookup); /* 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_lookup); /* Be careful about junction crossing, symlinks, hardlinks,... */ switch (parent_dir_attrs.type) { case FSAL_TYPE_DIR: // OK break; case FSAL_TYPE_JUNCTION: // This is a junction Return(ERR_FSAL_XDEV, 0, INDEX_FSAL_lookup); case FSAL_TYPE_FILE: case FSAL_TYPE_LNK: case FSAL_TYPE_XATTR: // not a directory Return(ERR_FSAL_NOTDIR, 0, INDEX_FSAL_lookup); default: Return(ERR_FSAL_SERVERFAULT, 0, INDEX_FSAL_lookup); } // LogFullDebug(COMPONENT_FSAL, // "lookup of %#llx:%#x:%#x/%s", p_parent_directory_handle->seq, // p_parent_directory_handle->oid, p_parent_directory_handle->ver, // p_filename->name); /* check rights to enter into the directory */ /* Set both mode and ace4 mask */ access_mask = FSAL_MODE_MASK_SET(FSAL_R_OK | FSAL_X_OK) | FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_LIST_DIR); 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_lookup); /* get file handle, it it exists */ /* This might be a race, but it's the best we can currently do */ status = fsal_internal_get_handle_at(parentfd, p_filename, object_handle); close(parentfd); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_lookup); /* get object attributes */ if(p_object_attributes) { status = GPFSFSAL_getattrs(object_handle, p_context, p_object_attributes); 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); } } /* lookup complete ! */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_lookup); }
fsal_status_t GPFSFSAL_readdir(gpfsfsal_dir_t * p_dir_descriptor, /* IN */ gpfsfsal_cookie_t start_position, /* IN */ fsal_attrib_mask_t get_attr_mask, /* IN */ fsal_mdsize_t buffersize, /* IN */ fsal_dirent_t * p_pdirent, /* OUT */ gpfsfsal_cookie_t * p_end_position, /* OUT */ fsal_count_t * p_nb_entries, /* OUT */ fsal_boolean_t * p_end_of_dir /* OUT */ ) { fsal_status_t st; fsal_count_t max_dir_entries; fsal_name_t entry_name; char buff[BUF_SIZE]; struct linux_dirent *dp = NULL; int bpos = 0; int tmpfd = 0; char d_type; struct stat buffstat; int rc = 0; memset(buff, 0, BUF_SIZE); memset(&entry_name, 0, sizeof(fsal_name_t)); /*****************/ /* sanity checks */ /*****************/ if(!p_dir_descriptor || !p_pdirent || !p_end_position || !p_nb_entries || !p_end_of_dir) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_readdir); max_dir_entries = (buffersize / sizeof(fsal_dirent_t)); /***************************/ /* seek into the directory */ /***************************/ errno = 0; if(start_position.data.cookie == 0) { //rewinddir(p_dir_descriptor->p_dir); rc = errno; } else { //seekdir(p_dir_descriptor->p_dir, start_position.cookie); rc = errno; } if(rc) Return(posix2fsal_error(rc), rc, INDEX_FSAL_readdir); /************************/ /* browse the directory */ /************************/ *p_nb_entries = 0; while(*p_nb_entries < max_dir_entries) { /***********************/ /* read the next entry */ /***********************/ TakeTokenFSCall(); rc = syscall(SYS_getdents, p_dir_descriptor->fd, buff, BUF_SIZE); ReleaseTokenFSCall(); if(rc < 0) { rc = errno; Return(posix2fsal_error(rc), rc, INDEX_FSAL_readdir); } /* End of directory */ if(rc == 0) { *p_end_of_dir = 1; break; } /***********************************/ /* Get information about the entry */ /***********************************/ for(bpos = 0; bpos < rc;) { dp = (struct linux_dirent *)(buff + bpos); d_type = *(buff + bpos + dp->d_reclen - 1); /** @todo not used for the moment. Waiting for information on symlink management */ bpos += dp->d_reclen; /* LogFullDebug(COMPONENT_FSAL, "\tino=%8ld|%8lx off=%d|%x reclen=%d|%x name=%s|%d", dp->d_ino, dp->d_ino, (int)dp->d_off, (int)dp->d_off, dp->d_reclen, dp->d_reclen, dp->d_name, (int)dp->d_name[0] ) ; */ if(!(*p_nb_entries < max_dir_entries)) break; /* skip . and .. */ if(!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue; /* build the full path of the file into "fsalpath */ if(FSAL_IS_ERROR (st = FSAL_str2name(dp->d_name, FSAL_MAX_NAME_LEN, &(p_pdirent[*p_nb_entries].name)))) ReturnStatus(st, INDEX_FSAL_readdir); d_type = DT_UNKNOWN; // TODO: there is a race here, because between handle fetch // and open at things might change. we need to figure out if there // is another way to open without the pcontext strncpy(entry_name.name, dp->d_name, sizeof(entry_name.name)); entry_name.len = strlen(entry_name.name); if(FSAL_IS_ERROR (st = fsal_internal_get_handle_at(p_dir_descriptor->fd, &entry_name, &(p_pdirent[*p_nb_entries].handle)))) ReturnStatus(st, INDEX_FSAL_readdir); if(FSAL_IS_ERROR (st = fsal_internal_handle2fd_at(p_dir_descriptor->fd, &(p_pdirent[*p_nb_entries].handle), &tmpfd, O_RDONLY | O_NOFOLLOW))) { if(errno != ELOOP) /* ( p_dir_descriptor->fd, dp->d_name) is not a symlink */ ReturnStatus(st, INDEX_FSAL_readdir); else d_type = DT_LNK; } /* get object handle */ TakeTokenFSCall(); if(d_type != DT_LNK) { close(tmpfd); } else { if(fstatat(p_dir_descriptor->fd, dp->d_name, &buffstat, AT_SYMLINK_NOFOLLOW) < 0) { ReleaseTokenFSCall(); Return(posix2fsal_error(errno), errno, INDEX_FSAL_readdir); } p_pdirent[*p_nb_entries].attributes.asked_attributes = get_attr_mask; st = posix2fsal_attributes(&buffstat, &p_pdirent[*p_nb_entries].attributes); if(FSAL_IS_ERROR(st)) { ReleaseTokenFSCall(); FSAL_CLEAR_MASK(p_pdirent[*p_nb_entries].attributes.asked_attributes); FSAL_SET_MASK(p_pdirent[*p_nb_entries].attributes.asked_attributes, FSAL_ATTR_RDATTR_ERR); ReturnStatus(st, INDEX_FSAL_getattrs); } } ReleaseTokenFSCall(); if(FSAL_IS_ERROR(st)) ReturnStatus(st, INDEX_FSAL_readdir); /************************ * Fills the attributes * ************************/ if(d_type != DT_LNK) { p_pdirent[*p_nb_entries].attributes.asked_attributes = get_attr_mask; st = GPFSFSAL_getattrs(&(p_pdirent[*p_nb_entries].handle), &p_dir_descriptor->context, &p_pdirent[*p_nb_entries].attributes); if(FSAL_IS_ERROR(st)) { FSAL_CLEAR_MASK(p_pdirent[*p_nb_entries].attributes.asked_attributes); FSAL_SET_MASK(p_pdirent[*p_nb_entries].attributes.asked_attributes, FSAL_ATTR_RDATTR_ERR); } } p_pdirent[*p_nb_entries].cookie.data.cookie = dp->d_off; p_pdirent[*p_nb_entries].nextentry = NULL; if(*p_nb_entries) p_pdirent[*p_nb_entries - 1].nextentry = &(p_pdirent[*p_nb_entries]); (*p_end_position) = p_pdirent[*p_nb_entries].cookie; (*p_nb_entries)++; } /* for */ } /* While */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_readdir); }
/** * Retrieves the list of extended attributes for an object in the filesystem. * * \param p_objecthandle Handle of the object we want to get extended attributes. * \param cookie index of the next entry to be returned. * \param p_context pointer to the current security context. * \param xattrs_tab a table for storing extended attributes list to. * \param xattrs_tabsize the maximum number of xattr entries that xattrs_tab * can contain. * \param p_nb_returned the number of xattr entries actually stored in xattrs_tab. * \param end_of_list this boolean indicates that the end of xattrs list has been reached. */ fsal_status_t GPFSFSAL_ListXAttrs(fsal_handle_t * p_objecthandle, /* IN */ unsigned int cookie, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_xattrent_t * xattrs_tab, /* IN/OUT */ unsigned int xattrs_tabsize, /* IN */ unsigned int *p_nb_returned, /* OUT */ int *end_of_list /* OUT */ ) { #if 0 int rc; unsigned int index; unsigned int out_index; char object_path[FSAL_MAX_PATH_LEN]; fsal_status_t st; fsal_attrib_list_t file_attrs; #endif /* sanity checks */ if(!p_objecthandle || !p_context || !xattrs_tab || !p_nb_returned || !end_of_list) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_ListXAttrs); /* @todo: to be implemented */ Return(ERR_FSAL_NOTSUPP, 0, INDEX_FSAL_ListXAttrs); #if 0 /* object attributes we want to retrieve from parent */ file_attrs.asked_attributes = FSAL_ATTR_MODE | FSAL_ATTR_FILEID | FSAL_ATTR_OWNER | FSAL_ATTR_GROUP | FSAL_ATTR_ATIME | FSAL_ATTR_MTIME | FSAL_ATTR_CTIME | FSAL_ATTR_CREATION | FSAL_ATTR_CHGTIME | FSAL_ATTR_FSID; /* don't retrieve unsuipported attributes */ file_attrs.asked_attributes &= global_fs_info.supported_attrs; st = GPFSFSAL_getattrs(p_objecthandle, p_context, &file_attrs); if(FSAL_IS_ERROR(st)) Return(st.major, st.minor, INDEX_FSAL_ListXAttrs); for(index = cookie, out_index = 0; index < XATTR_COUNT && out_index < xattrs_tabsize; index++) { if(do_match_type(xattr_list[index].flags, p_objecthandle->handle.handle_type)) { /* fills an xattr entry */ xattrs_tab[out_index].xattr_id = index; FSAL_str2name(xattr_list[index].xattr_name, 0, &xattrs_tab[out_index].xattr_name); xattrs_tab[out_index].xattr_cookie = index + 1; /* set asked attributes (all supported) */ xattrs_tab[out_index].attributes.asked_attributes = global_fs_info.supported_attrs; if(file_attributes_to_xattr_attrs (&file_attrs, &xattrs_tab[out_index].attributes, index)) { /* set error flag */ xattrs_tab[out_index].attributes.asked_attributes = FSAL_ATTR_RDATTR_ERR; } /* next output slot */ out_index++; } } *p_nb_returned = out_index; *end_of_list = (index == XATTR_COUNT); Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_ListXAttrs); #endif }