/** * 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_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); }
/** * FSAL_getattrs: * Get 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 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 XFSFSAL_getattrs(fsal_handle_t * p_filehandle, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_attrib_list_t * p_object_attributes /* IN/OUT */ ) { int rc, errsv; fsal_status_t st; int fd; struct stat buffstat; /* sanity checks. * note : object_attributes is mandatory in FSAL_getattrs. */ if(!p_filehandle || !p_context || !p_object_attributes) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_getattrs); TakeTokenFSCall(); st = fsal_internal_handle2fd(p_context, p_filehandle, &fd, O_RDONLY); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(st)) ReturnStatus(st, INDEX_FSAL_getattrs); /* get file metadata */ TakeTokenFSCall(); rc = fstat(fd, &buffstat); errsv = errno; ReleaseTokenFSCall(); close(fd); if(rc != 0) { if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_getattrs); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_getattrs); } /* convert attributes */ st = posix2fsal_attributes(&buffstat, 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); ReturnStatus(st, INDEX_FSAL_getattrs); } Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_getattrs); }
/** @fn fsal_status_t * GPFSFSAL_open(struct fsal_obj_handle *obj_hdl, * const struct req_op_context *op_ctx, * fsal_openflags_t openflags, int *file_desc, * struct attrlist *fsal_attr) * * @brief Open a regular file for reading/writing its data content. * * @param obj_hdl Handle of the file to be read/modified. * @param op_ctx Authentication context for the operation (user,...). * @param openflags Flags that indicates behavior for file opening and access. * This is an inclusive OR of the following values * ( such of them are not compatible) : * - FSAL_O_RDONLY: opening file for reading only. * - FSAL_O_RDWR: opening file for reading and writing. * - FSAL_O_WRONLY: opening file for writting only. * - FSAL_O_APPEND: always write at the end of the file. * - FSAL_O_TRUNC: truncate the file to 0 on opening. * @param file_desc The file descriptor to be used for FSAL_read/write ops. * * @return ERR_FSAL_NO_ERROR on success, error otherwise */ fsal_status_t GPFSFSAL_open(struct fsal_obj_handle *obj_hdl, const struct req_op_context *op_ctx, int posix_flags, int *file_desc) { struct gpfs_fsal_obj_handle *myself; fsal_status_t status; struct gpfs_fsal_export *exp = container_of(op_ctx->fsal_export, struct gpfs_fsal_export, export); int export_fd = exp->export_fd; /* sanity checks. */ if (!obj_hdl || !file_desc) return fsalstat(ERR_FSAL_FAULT, 0); myself = container_of(obj_hdl, struct gpfs_fsal_obj_handle, obj_handle); LogFullDebug(COMPONENT_FSAL, "posix_flags 0x%X export_fd %d", posix_flags, export_fd); fsal_set_credentials(op_ctx->creds); status = fsal_internal_handle2fd(export_fd, myself->handle, file_desc, posix_flags); fsal_restore_ganesha_credentials(); if (FSAL_IS_ERROR(status)) { /** Try open as root access if the above call fails, * permission will be checked somewhere else in the code. */ status = fsal_internal_handle2fd(export_fd, myself->handle, file_desc, posix_flags); } return status; }
/** @fn fsal_status_t * GPFSFSAL_open(struct fsal_obj_handle *obj_hdl, * const struct req_op_context *op_ctx, * fsal_openflags_t openflags, int *file_desc, * struct attrlist *fsal_attr, bool reopen) * * @brief Open a regular file for reading/writing its data content. * * @param obj_hdl Handle of the file to be read/modified. * @param op_ctx Authentication context for the operation (user,...). * @param openflags Flags that indicates behavior for file opening and access. * This is an inclusive OR of the following values * ( such of them are not compatible) : * - FSAL_O_RDONLY: opening file for reading only. * - FSAL_O_RDWR: opening file for reading and writing. * - FSAL_O_WRONLY: opening file for writting only. * - FSAL_O_APPEND: always write at the end of the file. * - FSAL_O_TRUNC: truncate the file to 0 on opening. * @param file_desc The file descriptor to be used for FSAL_read/write ops. * * @return ERR_FSAL_NO_ERROR on success, error otherwise */ fsal_status_t GPFSFSAL_open(struct fsal_obj_handle *obj_hdl, const struct req_op_context *op_ctx, int posix_flags, int *file_desc, bool reopen) { struct gpfs_fsal_obj_handle *myself; struct gpfs_filesystem *gpfs_fs; fsal_status_t status; /* sanity checks. */ if (!obj_hdl || !file_desc) return fsalstat(ERR_FSAL_FAULT, 0); myself = container_of(obj_hdl, struct gpfs_fsal_obj_handle, obj_handle); gpfs_fs = obj_hdl->fs->private_data; LogFullDebug(COMPONENT_FSAL, "posix_flags 0x%X", posix_flags); status = fsal_internal_handle2fd(gpfs_fs->root_fd, myself->handle, file_desc, posix_flags, reopen); if (FSAL_IS_ERROR(status)) { /** In some environments, "root" is denied write access, * so try with the request credentials if the above call * fails. */ fsal_set_credentials(op_ctx->creds); status = fsal_internal_handle2fd(gpfs_fs->root_fd, myself->handle, file_desc, posix_flags, reopen); fsal_restore_ganesha_credentials(); } return status; }
/** * FSAL_getetxattrs: * Get 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 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 XFSFSAL_getextattrs(xfsfsal_handle_t * p_filehandle, /* IN */ xfsfsal_op_context_t * p_context, /* IN */ fsal_extattrib_list_t * p_object_attributes /* OUT */ ) { fsal_status_t st ; xfs_bstat_t bstat; xfs_ino_t xfs_ino; struct stat buffstat; int fd = 0 ; /* sanity checks. * note : object_attributes is mandatory in FSAL_getattrs. */ if(!p_filehandle || !p_context || !p_object_attributes) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_getattrs); TakeTokenFSCall(); st = fsal_internal_handle2fd(p_context, p_filehandle, &fd, O_RDONLY); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(st)) ReturnStatus(st, INDEX_FSAL_getextattrs); if( p_object_attributes->asked_attributes & FSAL_ATTR_GENERATION ) { /* get file metadata */ xfs_ino = p_filehandle->data.inode ; TakeTokenFSCall(); if(fsal_internal_get_bulkstat_by_inode(fd, &xfs_ino, &bstat) < 0) { close(fd); ReleaseTokenFSCall(); ReturnCode(posix2fsal_error(errno), errno); } ReleaseTokenFSCall(); p_object_attributes->generation = bstat.bs_gen ; } Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_getextattrs); } /* XFSFSAL_getextattrs */
/** * 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 XFSFSAL_open(fsal_handle_t * p_filehandle, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_openflags_t openflags, /* IN */ fsal_file_t * p_file_descriptor, /* OUT */ fsal_attrib_list_t * p_file_attributes /* [ IN/OUT ] */ ) { int rc, errsv; fsal_status_t status; int fd = 0 ; struct stat buffstat; int posix_flags = 0; /* 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) { LogEvent(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 */ TakeTokenFSCall(); rc = fstat(fd, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) { close(fd); if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_open); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_open); } #if 0 /* No required, the open would have failed if not permitted */ status = fsal_check_access(p_context, openflags & FSAL_O_RDONLY ? FSAL_R_OK : FSAL_W_OK, &buffstat, NULL); if(FSAL_IS_ERROR(status)) { close(fd); ReturnStatus(status, INDEX_FSAL_open); } #endif TakeTokenFSCall(); ((xfsfsal_file_t *)p_file_descriptor)->fd = fd; errsv = errno; ReleaseTokenFSCall(); /* set the read-only flag of the file descriptor */ ((xfsfsal_file_t *)p_file_descriptor)->ro = openflags & FSAL_O_RDONLY; /* output attributes */ if(p_file_attributes) { status = posix2fsal_attributes(&buffstat, p_file_attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_file_attributes->asked_attributes); FSAL_SET_MASK(p_file_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_open); }
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); }
/** * 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); }
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); }
fsal_status_t VFSFSAL_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 old_parent_buffstat, new_parent_buffstat, buffstat; int old_parent_fd, new_parent_fd; int src_equal_tgt = FALSE; uid_t user = ((vfsfsal_op_context_t *)p_context)->credential.user; /* 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 */ TakeTokenFSCall(); rc = fstat(old_parent_fd, &old_parent_buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) { close(old_parent_fd); if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_rename); else Return(posix2fsal_error(errsv), errsv, 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; new_parent_buffstat = old_parent_buffstat; } 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 */ TakeTokenFSCall(); rc = fstat(new_parent_fd, &new_parent_buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) { /* close old and new parent fd */ close(old_parent_fd); close(new_parent_fd); if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_rename); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename); } } /* check access rights */ status = fsal_check_access(p_context, FSAL_W_OK | FSAL_X_OK, &old_parent_buffstat, NULL); 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) { status = fsal_check_access(p_context, FSAL_W_OK | FSAL_X_OK, &new_parent_buffstat, NULL); 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((old_parent_buffstat.st_mode & S_ISVTX) && old_parent_buffstat.st_uid != user && buffstat.st_uid != user && 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(new_parent_buffstat.st_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(new_parent_buffstat.st_uid != user && buffstat.st_uid != user && 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 = VFSFSAL_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 = VFSFSAL_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); }
/** * 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); }
/** * VFSFSAL_setattrs: * Set attributes for the object specified by its filehandle. * * \param filehandle (input): * The handle of the object to get parameters. * \param cred (input): * Authentication context for the operation (user,...). * \param attrib_set (mandatory input): * The attributes to be set for the object. * It defines the attributes that the caller * wants to set and their values. * \param object_attributes (optionnal input/output): * The post operation attributes for the object. * As input, it defines the attributes that the caller * wants to retrieve (by positioning flags into this structure) * and the output is built considering this input * (it fills the structure according to the flags it contains). * May be NULL. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - Another error code if an error occured. */ fsal_status_t VFSFSAL_setattrs(fsal_handle_t * p_filehandle, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_attrib_list_t * p_attrib_set, /* IN */ fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */ ) { vfsfsal_op_context_t * vfs_context = (vfsfsal_op_context_t *) p_context; int rc, errsv; unsigned int i; fsal_status_t status; fsal_attrib_list_t attrs; int fd; struct stat buffstat; /* sanity checks. * note : object_attributes is optional. */ if(!p_filehandle || !p_context || !p_attrib_set) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_setattrs); /* local copy of attributes */ attrs = *p_attrib_set; /* It does not make sense to setattr on a symlink */ /* if(p_filehandle->type == DT_LNK) return fsal_internal_setattrs_symlink(p_filehandle, p_context, p_attrib_set, p_object_attributes); */ /* First, check that FSAL attributes changes are allowed. */ /* Is it allowed to change times ? */ if(!global_fs_info.cansettime) { if(attrs.asked_attributes & (FSAL_ATTR_ATIME | FSAL_ATTR_CREATION | FSAL_ATTR_CTIME | FSAL_ATTR_MTIME)) { /* handled as an unsettable attribute. */ Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_setattrs); } } /* apply umask, if mode attribute is to be changed */ if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MODE)) { attrs.mode &= (~global_fs_info.umask); } TakeTokenFSCall(); status = fsal_internal_handle2fd(p_context, p_filehandle, &fd, O_RDONLY); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) { /* Symbolic link are handled here, they are to be opened as O_PATH */ if( status.minor == ELOOP ) { if(p_object_attributes) { status = VFSFSAL_getattrs(p_filehandle, p_context, p_object_attributes); /* on error, we set a special bit in the mask. */ if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_object_attributes->asked_attributes); FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_setattrs); } ReturnStatus( status, INDEX_FSAL_setattrs); } /* get current attributes */ TakeTokenFSCall(); rc = fstat(fd, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc != 0) { close(fd); if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_setattrs); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_setattrs); } /*********** * CHMOD * ***********/ if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MODE)) { /* The POSIX chmod call don't affect the symlink object, but * the entry it points to. So we must ignore it. */ if(!S_ISLNK(buffstat.st_mode)) { /* For modifying mode, user must be root or the owner */ if((vfs_context->credential.user != 0) && (vfs_context->credential.user != buffstat.st_uid)) { LogFullDebug(COMPONENT_FSAL, "Permission denied for CHMOD opeartion: current owner=%d, credential=%d", buffstat.st_uid, vfs_context->credential.user); close(fd); Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); } TakeTokenFSCall(); rc = fchmod(fd, fsal2unix_mode(attrs.mode)); errsv = errno; ReleaseTokenFSCall(); if(rc) { close(fd); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_setattrs); } } } /*********** * CHOWN * ***********/ /* Only root can change uid and A normal user must be in the group he wants to set */ if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_OWNER)) { /* For modifying owner, user must be root or current owner==wanted==client */ if((vfs_context->credential.user != 0) && ((vfs_context->credential.user != buffstat.st_uid) || (vfs_context->credential.user != attrs.owner))) { LogFullDebug(COMPONENT_FSAL, "Permission denied for CHOWN opeartion: current owner=%d, credential=%d, new owner=%d", buffstat.st_uid, vfs_context->credential.user, attrs.owner); close(fd); Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); } } if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_GROUP)) { /* For modifying group, user must be root or current owner */ if((vfs_context->credential.user != 0) && (vfs_context->credential.user != buffstat.st_uid)) { close(fd); Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); } int in_grp = 0; /* set in_grp */ if(vfs_context->credential.group == attrs.group) in_grp = 1; else for(i = 0; i < vfs_context->credential.nbgroups; i++) { if((in_grp = (attrs.group == vfs_context->credential.alt_groups[i]))) break; } /* it must also be in target group */ if(vfs_context->credential.user != 0 && !in_grp) { LogFullDebug(COMPONENT_FSAL, "Permission denied for CHOWN operation: current group=%d, credential=%d, new group=%d", buffstat.st_gid, vfs_context->credential.group, attrs.group); close(fd); Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); } } if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_OWNER | FSAL_ATTR_GROUP)) { /* LogFullDebug(COMPONENT_FSAL, "Performing chown(%s, %d,%d)", fsalpath.path, FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_OWNER) ? (int)attrs.owner : -1, FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_GROUP) ? (int)attrs.group : -1);*/ TakeTokenFSCall(); rc = fchown(fd, FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_OWNER) ? (int)attrs.owner : -1, FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_GROUP) ? (int)attrs.group : -1); ReleaseTokenFSCall(); if(rc) { close(fd); Return(posix2fsal_error(errno), errno, INDEX_FSAL_setattrs); } } /*********** * UTIME * ***********/ /* user must be the owner or have read access to modify 'atime' */ if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME) && (vfs_context->credential.user != 0) && (vfs_context->credential.user != buffstat.st_uid) && ((status = fsal_check_access(p_context, FSAL_R_OK, &buffstat, NULL)).major != ERR_FSAL_NO_ERROR)) { close(fd); ReturnStatus(status, INDEX_FSAL_setattrs); } /* user must be the owner or have write access to modify 'mtime' */ if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MTIME) && (vfs_context->credential.user != 0) && (vfs_context->credential.user != buffstat.st_uid) && ((status = fsal_check_access(p_context, FSAL_W_OK, &buffstat, NULL)).major != ERR_FSAL_NO_ERROR)) { close(fd); ReturnStatus(status, INDEX_FSAL_setattrs); } if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME | FSAL_ATTR_MTIME)) { struct timeval timebuf[2]; /* Atime */ timebuf[0].tv_sec = (FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME) ? (time_t) attrs. atime.seconds : buffstat.st_atime); timebuf[0].tv_usec = 0; /* Mtime */ timebuf[1].tv_sec = (FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MTIME) ? (time_t) attrs. mtime.seconds : buffstat.st_mtime); timebuf[1].tv_usec = 0; TakeTokenFSCall(); rc = futimes(fd, timebuf); errsv = errno; ReleaseTokenFSCall(); if(rc) { close(fd); Return(posix2fsal_error(errno), errno, INDEX_FSAL_setattrs); } } /* Optionaly fills output attributes. */ if(p_object_attributes) { status = VFSFSAL_getattrs(p_filehandle, p_context, p_object_attributes); /* on error, we set a special bit in the mask. */ if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_object_attributes->asked_attributes); FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } close(fd); Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_setattrs); }
/** * 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). * * \return - ERR_FSAL_NO_ERROR, if no error. * - Another error code else. * */ fsal_status_t XFSFSAL_lookup(fsal_handle_t * parent_handle, /* IN */ fsal_name_t * p_filename, /* IN */ fsal_op_context_t * context, /* IN */ fsal_handle_t * object_handle, /* OUT */ fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */ ) { xfsfsal_handle_t * p_parent_directory_handle = (xfsfsal_handle_t *)parent_handle; xfsfsal_op_context_t * p_context = (xfsfsal_op_context_t *)context; xfsfsal_handle_t * p_object_handle = (xfsfsal_handle_t *)object_handle; int rc = 0 , errsv = 0 ; fsal_status_t status; struct stat buffstat; int parentfd; /* sanity checks * note : object_attributes is optionnal * 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) { /* get handle for the mount point */ memcpy(p_object_handle->data.handle_val, p_context->export_context->mnt_handle_val, p_context->export_context->mnt_handle_len); p_object_handle->data.handle_len = p_context->export_context->mnt_handle_len; /* get attributes, if asked */ if(p_object_attributes) { status = XFSFSAL_getattrs(p_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(context, parent_handle, &parentfd, O_RDONLY); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_lookup); /* get directory metadata */ TakeTokenFSCall(); rc = fstat(parentfd, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) { close( parentfd ) ; if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_lookup); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_lookup); } /* Be careful about junction crossing, symlinks, hardlinks,... */ switch (posix2fsal_type(buffstat.st_mode)) { case FSAL_TYPE_DIR: // OK break; case FSAL_TYPE_JUNCTION: close( parentfd ) ; // This is a junction Return(ERR_FSAL_XDEV, 0, INDEX_FSAL_lookup); case FSAL_TYPE_FILE: case FSAL_TYPE_LNK: case FSAL_TYPE_XATTR: close( parentfd ) ; // not a directory Return(ERR_FSAL_NOTDIR, 0, INDEX_FSAL_lookup); default: close( parentfd ) ; Return(ERR_FSAL_SERVERFAULT, 0, INDEX_FSAL_lookup); } LogFullDebug(COMPONENT_FSAL, "lookup of inode=%"PRIu64"/%s", buffstat.st_ino, p_filename->name); /* check rights to enter into the directory */ status = fsal_check_access(context, FSAL_X_OK, &buffstat, NULL); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_lookup); status = xfsfsal_stat_by_name(context, parentfd, p_filename->name, object_handle, p_object_attributes); close(parentfd); ReturnStatus(status, INDEX_FSAL_lookup); }
/** * 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 XFSFSAL_mkdir(xfsfsal_handle_t * p_parent_directory_handle, /* IN */ fsal_name_t * p_dirname, /* IN */ xfsfsal_op_context_t * p_context, /* IN */ fsal_accessmode_t accessmode, /* IN */ xfsfsal_handle_t * p_object_handle, /* OUT */ fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */ ) { int rc, errsv; int setgid_bit = 0; struct stat buffstat; mode_t unix_mode; fsal_status_t status; int fd, newfd; /* sanity checks. * note : object_attributes is optional. */ if(!p_parent_directory_handle || !p_context || !p_object_handle || !p_dirname) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mkdir); /* convert FSAL mode to HPSS mode. */ unix_mode = fsal2unix_mode(accessmode); /* Apply umask */ unix_mode = unix_mode & ~global_fs_info.umask; TakeTokenFSCall(); status = fsal_internal_handle2fd(p_context, p_parent_directory_handle, &fd, O_DIRECTORY); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_mkdir); /* get directory metadata */ TakeTokenFSCall(); rc = fstat(fd, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) { close(fd); if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_create); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create); } /* Check the user can write in the directory, and check the setgid bit on the directory */ if(buffstat.st_mode & S_ISGID) setgid_bit = 1; status = fsal_internal_testAccess(p_context, FSAL_W_OK | FSAL_X_OK, &buffstat, NULL); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_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); } /* get the new handle */ if((newfd = openat(fd, p_dirname->name, O_RDONLY | O_DIRECTORY, 0600)) < 0) { errsv = errno; close(fd); ReleaseTokenFSCall(); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir); } status = fsal_internal_fd2handle(p_context, newfd, p_object_handle); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) { close(fd); close(newfd); ReturnStatus(status, INDEX_FSAL_mkdir); } /* the directory has been created */ /* chown the file to the current user/group */ if(p_context->credential.user != geteuid()) { TakeTokenFSCall(); /* if the setgid_bit was set on the parent directory, do not change the group of the created file, because it's already the parentdir's group */ rc = 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 = XFSFSAL_getattrs(p_object_handle, p_context, p_object_attributes); /* on error, we set a special bit in the mask. */ if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_object_attributes->asked_attributes); FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_mkdir); }
fsal_status_t XFSFSAL_unlink(fsal_handle_t * p_parent_directory_handle, /* IN */ fsal_name_t * p_object_name, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_attrib_list_t * p_parent_directory_attributes /* [IN/OUT ] */ ) { fsal_status_t status; int rc, errsv; struct stat buffstat, buffstat_parent; int fd; /* sanity checks. */ if(!p_parent_directory_handle || !p_context || !p_object_name) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_unlink); /* build the FID path */ TakeTokenFSCall(); status = fsal_internal_handle2fd(p_context, p_parent_directory_handle, &fd, O_DIRECTORY); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_unlink); /* get directory metadata */ TakeTokenFSCall(); rc = fstat(fd, &buffstat_parent); errsv = errno; ReleaseTokenFSCall(); if(rc) { close(fd); if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_unlink); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_unlink); } /* build the child path */ /* get file metadata */ TakeTokenFSCall(); rc = fstatat(fd, p_object_name->name, &buffstat, AT_SYMLINK_NOFOLLOW); errsv = errno; ReleaseTokenFSCall(); if(rc) { close(fd); Return(posix2fsal_error(errno), errno, INDEX_FSAL_unlink); } /* check access rights */ /* Sticky bit on the directory => the user who wants to delete the file must own it or its parent dir */ if((buffstat_parent.st_mode & S_ISVTX) && buffstat_parent.st_uid != ((xfsfsal_op_context_t *)p_context)->credential.user && buffstat.st_uid != ((xfsfsal_op_context_t *)p_context)->credential.user && ((xfsfsal_op_context_t *)p_context)->credential.user != 0) { close(fd); Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_unlink); } /* client must be able to lookup the parent directory and modify it */ status = fsal_internal_testAccess(p_context, FSAL_W_OK | FSAL_X_OK, &buffstat_parent, NULL); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_unlink); /****************************** * DELETE FROM THE FILESYSTEM * ******************************/ TakeTokenFSCall(); /* If the object to delete is a directory, use 'rmdir' to delete the object, else use 'unlink' */ rc = (S_ISDIR(buffstat.st_mode)) ? unlinkat(fd, p_object_name->name, AT_REMOVEDIR) : unlinkat(fd, p_object_name->name, 0); errsv = errno; ReleaseTokenFSCall(); close(fd); if(rc) Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_unlink); /*********************** * FILL THE ATTRIBUTES * ***********************/ if(p_parent_directory_attributes) { status = XFSFSAL_getattrs(p_parent_directory_handle, p_context, p_parent_directory_attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_parent_directory_attributes->asked_attributes); FSAL_SET_MASK(p_parent_directory_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_unlink); }
/** * 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 VFSFSAL_opendir(vfsfsal_handle_t * p_dir_handle, /* IN */ vfsfsal_op_context_t * p_context, /* IN */ vfsfsal_dir_t * p_dir_descriptor, /* OUT */ fsal_attrib_list_t * p_dir_attributes /* [ IN/OUT ] */ ) { int rc, errsv; fsal_status_t status; struct stat buffstat; /* 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 */ TakeTokenFSCall(); rc = fstat(p_dir_descriptor->fd, &buffstat); ReleaseTokenFSCall(); if(rc != 0) { close(p_dir_descriptor->fd); if(rc == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_opendir); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_opendir); } /* Test access rights for this directory */ status = fsal_internal_testAccess(p_context, FSAL_R_OK, &buffstat, NULL); 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(vfsfsal_op_context_t)); memcpy(&(p_dir_descriptor->handle), p_dir_handle, sizeof(vfsfsal_handle_t)); if(p_dir_attributes) { status = posix2fsal_attributes(&buffstat, p_dir_attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_dir_attributes->asked_attributes); FSAL_SET_MASK(p_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } p_dir_descriptor->dir_offset = 0; Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_opendir); }
/** * 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_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 XFSFSAL_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 ] */ ) { int rc, errsv; fsal_status_t status; int srcfd, dstfd; struct stat buffstat_dir; /* sanity checks. * note : attributes is optional. */ if(!p_target_handle || !p_dir_handle || !p_context || !p_link_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); /* LogFullDebug(COMPONENT_FSAL, "linking %#llx:%#x:%#x to %#llx:%#x:%#x/%s", */ /* get the target handle access by fid */ TakeTokenFSCall(); status = fsal_internal_handle2fd(p_context, p_target_handle, &srcfd, O_DIRECTORY); 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_DIRECTORY); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) { close(srcfd); ReturnStatus(status, INDEX_FSAL_link); } /* retrieve target directory metadata */ TakeTokenFSCall(); rc = fstat(dstfd, &buffstat_dir); errsv = errno; ReleaseTokenFSCall(); if(rc) { close(srcfd); close(dstfd); if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_link); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_link); } /* check permission on target directory */ status = fsal_internal_testAccess(p_context, FSAL_W_OK | FSAL_X_OK, &buffstat_dir, NULL); if(FSAL_IS_ERROR(status)) { close(srcfd), close(dstfd); ReturnStatus(status, INDEX_FSAL_link); } /* Create the link on the filesystem */ TakeTokenFSCall(); rc = linkat2(srcfd, dstfd, p_link_name->name); errsv = errno; ReleaseTokenFSCall(); if(rc) { close(srcfd), close(dstfd); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_link); } /* optionnaly get attributes */ if(p_attributes) { status = XFSFSAL_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); } } /* OK */ close(srcfd); close(dstfd); Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_link); }
/** * 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); }
/** * PTFSAL_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 PTFSAL_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; ptfsal_xstat_t buffxstat; fsal_accessflags_t access_mask = 0; fsal_attrib_list_t wanted_attrs, current_attrs; mode_t st_mode_in_cache = 0; char fsi_name[PATH_MAX]; int rc; int fd; FSI_TRACE(FSI_DEBUG, "Begin-----------------------------------------\n"); /* 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; /* First, check that FSAL attributes changes are allowed. */ 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 = PTFS_SUPPORTED_ATTRIBUTES; status = PTFSAL_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); } /************** * TRUNCATE * **************/ if(FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_SIZE)) { status = fsal_internal_handle2fd(p_context, p_filehandle, &fd, O_RDONLY); if (FSAL_IS_ERROR(status)) { ReturnStatus(status, INDEX_FSAL_setattrs); } status = PTFSAL_truncate( p_filehandle, p_context, wanted_attrs.filesize, &fd, p_object_attributes); if (FSAL_IS_ERROR(status)) { ReturnStatus(status, INDEX_FSAL_setattrs); } } /*********** * CHMOD * ***********/ if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_MODE)) { FSI_TRACE(FSI_DEBUG, "Begin chmod------------------\n"); /* 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) { /* For modifying mode, user must be root or the owner */ if ((p_context->credential.user != 0) && (p_context->credential.user != current_attrs.owner)) { FSI_TRACE(FSI_DEBUG, "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 /* Check permission using ACL. */ access_mask = FSAL_MODE_MASK_SET(0) | /* Dummy. */ FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_ATTR); if (!p_context->export_context->fe_static_fs_info->accesscheck_support) status = fsal_internal_testAccess(p_context, access_mask, NULL, ¤t_attrs); else status = fsal_internal_access(p_context, p_filehandle, access_mask, ¤t_attrs); if (FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_setattrs); #endif /* Fill wanted mode. */ buffxstat.buffstat.st_mode = fsal2unix_mode(wanted_attrs.mode); FSI_TRACE(FSI_DEBUG, "current mode = %o, new mode = %o", fsal2unix_mode(current_attrs.mode), buffxstat.buffstat.st_mode); rc = fsi_get_name_from_handle(p_context, p_filehandle->data.handle.f_handle, fsi_name, NULL); if (rc < 0) { FSI_TRACE(FSI_ERR, "Failed to convert file handle back to filename" ); FSI_TRACE(FSI_DEBUG, "Handle to name failed for hanlde %s", p_filehandle->data.handle.f_handle); Return (ERR_FSAL_BADHANDLE, 0, INDEX_FSAL_setattrs); } FSI_TRACE(FSI_DEBUG, "Handle to name: %s for handle %s", fsi_name, p_filehandle->data.handle.f_handle); rc = ptfsal_chmod(p_context, fsi_name, buffxstat.buffstat.st_mode); if (rc == -1) { FSI_TRACE(FSI_ERR, "chmod FAILED"); Return (ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); } else { st_mode_in_cache = (buffxstat.buffstat.st_mode | fsal_type2unix(current_attrs.type)); fsi_update_cache_stat(fsi_name, st_mode_in_cache, p_context->export_context->pt_export_id); FSI_TRACE(FSI_INFO, "Chmod SUCCEED with st_mode in cache being %o", st_mode_in_cache); } } FSI_TRACE(FSI_DEBUG, "End chmod-------------------\n"); } /*********** * CHOWN * ***********/ FSI_TRACE(FSI_DEBUG, "Begin chown------------------------------\n"); /* 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)) { /* 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))) { FSI_TRACE(FSI_DEBUG, "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 /* Check permission using ACL. */ access_mask = FSAL_MODE_MASK_SET(0) | /* Dummy. */ FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_OWNER); if (!p_context->export_context->fe_static_fs_info->accesscheck_support) status = fsal_internal_testAccess(p_context, access_mask, NULL, ¤t_attrs); else status = fsal_internal_access(p_context, p_filehandle, access_mask, ¤t_attrs); if (FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_setattrs); #endif } if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_GROUP)) { /* 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) { FSI_TRACE(FSI_DEBUG, "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 /* Check permission using ACL. */ access_mask = FSAL_MODE_MASK_SET(0) | /* Dummy. */ FSAL_ACE4_MASK_SET(FSAL_ACE_PERM_WRITE_OWNER); if (!p_context->export_context->fe_static_fs_info->accesscheck_support) status = fsal_internal_testAccess(p_context, access_mask, NULL, ¤t_attrs); else status = fsal_internal_access(p_context, p_filehandle, access_mask, ¤t_attrs); if (FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_setattrs); #endif } if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_OWNER | FSAL_ATTR_GROUP)) { /* Fill wanted owner. */ if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_OWNER)) { buffxstat.buffstat.st_uid = (int)wanted_attrs.owner; } else { buffxstat.buffstat.st_uid = (int)current_attrs.owner; } FSI_TRACE(FSI_DEBUG, "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; } else { buffxstat.buffstat.st_gid = (int)current_attrs.group; } FSI_TRACE(FSI_DEBUG, "current gid = %d, new gid = %d", current_attrs.group, buffxstat.buffstat.st_gid); rc = fsi_get_name_from_handle(p_context, p_filehandle->data.handle.f_handle, fsi_name, NULL); if (rc < 0) { FSI_TRACE(FSI_ERR, "Failed to convert file handle back to filename" ); FSI_TRACE(FSI_DEBUG, "Handle to name failed for hanlde %s", p_filehandle->data.handle.f_handle); Return (ERR_FSAL_BADHANDLE, 0, INDEX_FSAL_setattrs); } FSI_TRACE(FSI_DEBUG, "handle to name: %s for handle %s", fsi_name, p_filehandle->data.handle.f_handle); rc = ptfsal_chown(p_context, fsi_name, buffxstat.buffstat.st_uid, buffxstat.buffstat.st_gid); if (rc == -1) { FSI_TRACE(FSI_ERR, "chown FAILED"); Return (ERR_FSAL_PERM, 1, INDEX_FSAL_setattrs); } else { FSI_TRACE(FSI_INFO, "Chown SUCCEED"); } } FSI_TRACE(FSI_DEBUG, "End chown-----------------------------------\n"); /*********** * UTIME * ***********/ FSI_TRACE(FSI_DEBUG, "Begin UTIME-----------------------------------\n"); /* 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 (!p_context->export_context->fe_static_fs_info->accesscheck_support) { status = fsal_internal_testAccess(p_context, access_mask, NULL, ¤t_attrs); } else { status = fsal_internal_access(p_context, p_filehandle, access_mask, ¤t_attrs); } if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_ATIME) && (p_context->credential.user != 0) && (p_context->credential.user != current_attrs.owner) && (status.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 (!p_context->export_context->fe_static_fs_info->accesscheck_support) { status = fsal_internal_testAccess(p_context, access_mask, NULL, ¤t_attrs); } else { status = fsal_internal_access(p_context, p_filehandle, access_mask, ¤t_attrs); } if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_MTIME) && (p_context->credential.user != 0) && (p_context->credential.user != current_attrs.owner) && (status.major != ERR_FSAL_NO_ERROR)) { ReturnStatus(status, INDEX_FSAL_setattrs); } if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_ATIME | FSAL_ATTR_MTIME)) { /* Fill wanted atime. */ if (FSAL_TEST_MASK(wanted_attrs.asked_attributes, FSAL_ATTR_ATIME)) { buffxstat.buffstat.st_atime = (time_t) wanted_attrs.atime.seconds; FSI_TRACE(FSI_DEBUG, "current atime = %lu, new atime = %lu", (unsigned long)current_attrs.atime.seconds, (unsigned long)buffxstat.buffstat.st_atime); } else { buffxstat.buffstat.st_atime = (time_t) current_attrs.atime.seconds; } FSI_TRACE(FSI_DEBUG, "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)) { buffxstat.buffstat.st_mtime = (time_t) wanted_attrs.mtime.seconds; } else { buffxstat.buffstat.st_mtime = (time_t) current_attrs.mtime.seconds; } FSI_TRACE(FSI_DEBUG, "current mtime = %lu, new mtime = %lu", (unsigned long)current_attrs.mtime.seconds, (unsigned long)buffxstat.buffstat.st_mtime); rc = fsi_get_name_from_handle(p_context, p_filehandle->data.handle.f_handle, fsi_name, NULL); if (rc < 0) { FSI_TRACE(FSI_ERR, "Failed to convert file handle back to filename " "from cache" ); FSI_TRACE(FSI_DEBUG, "Handle to name failed for hanlde %s", p_filehandle->data.handle.f_handle); Return (ERR_FSAL_BADHANDLE, 0, INDEX_FSAL_setattrs); } FSI_TRACE(FSI_DEBUG, "Handle to name: %s for handle %s", fsi_name, p_filehandle->data.handle.f_handle); rc = ptfsal_ntimes(p_context, fsi_name, buffxstat.buffstat.st_atime, buffxstat.buffstat.st_mtime); if (rc == -1) { FSI_TRACE(FSI_ERR, "ntime FAILED"); Return (ERR_FSAL_PERM, 2, INDEX_FSAL_setattrs); } else { FSI_TRACE(FSI_INFO, "ntime SUCCEED"); } } FSI_TRACE(FSI_DEBUG, "End UTIME------------------------------\n"); #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); if (!p_context->export_context->fe_static_fs_info->accesscheck_support) status = fsal_internal_testAccess(p_context, access_mask, NULL, ¤t_attrs); else status = fsal_internal_access(p_context, p_filehandle, access_mask, ¤t_attrs); if (FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_setattrs); if (wanted_attrs.acl) { LogDebug(COMPONENT_FSAL, "setattr acl = %p", wanted_attrs.acl); /* Convert FSAL ACL to PTFS NFS4 ACL and fill the buffer. */ status = fsal_acl_2_ptfs_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 */ /* Optionaly fills output attributes. */ if (p_object_attributes) { status = PTFSAL_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); } } FSI_TRACE(FSI_DEBUG, "End--------------------------------------------\n"); Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_setattrs); }
/** * 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_create: * Create a regular file. * * \param parent_directory_handle (input): * Handle of the parent directory where the file is to be created. * \param p_filename (input): * Pointer to the name of the file to be created. * \param cred (input): * Authentication context for the operation (user,...). * \param accessmode (input): * Mode for the file to be created. * (the umask defined into the FSAL configuration file * will be applied on it). * \param object_handle (output): * Pointer to the handle of the created file. * \param object_attributes (optional input/output): * The attributes of the created file. * As input, it defines the attributes that the caller * wants to retrieve (by positioning flags into this structure) * and the output is built considering this input * (it fills the structure according to the flags it contains). * May be NULL. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - Another error code if an error occurred. */ fsal_status_t XFSFSAL_create(fsal_handle_t * p_parent_directory_handle, /* IN */ fsal_name_t * p_filename, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_accessmode_t accessmode, /* IN */ fsal_handle_t * p_object_handle, /* OUT */ fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */ ) { int rc, errsv; int setgid_bit = 0; fsal_status_t status; int fd, newfd; struct stat buffstat; mode_t unix_mode; /* sanity checks. * note : object_attributes is optional. */ if(!p_parent_directory_handle || !p_context || !p_object_handle || !p_filename) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create); /* convert fsal mode to unix mode. */ unix_mode = fsal2unix_mode(accessmode); /* Apply umask */ unix_mode = unix_mode & ~global_fs_info.umask; LogFullDebug(COMPONENT_FSAL, "Creation mode: 0%o", accessmode); TakeTokenFSCall(); status = fsal_internal_handle2fd(p_context, p_parent_directory_handle, &fd, O_DIRECTORY); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_create); /* retrieve directory metadata */ TakeTokenFSCall(); rc = fstat(fd, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) { close(fd); if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_create); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create); } /* Check the user can write in the directory, and check the setgid bit on the directory */ if(buffstat.st_mode & S_ISGID) setgid_bit = 1; status = fsal_internal_testAccess(p_context, FSAL_W_OK | FSAL_X_OK, &buffstat, NULL); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_create); /* call to filesystem */ TakeTokenFSCall(); /* create the file. * O_EXCL=> error if the file already exists */ newfd = openat(fd, p_filename->name, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, unix_mode); errsv = errno; if(newfd == -1) { close(fd); ReleaseTokenFSCall(); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create); } /* get the new file handle */ status = fsal_internal_fd2handle(p_context, newfd, p_object_handle); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) { close(fd); close(newfd); ReturnStatus(status, INDEX_FSAL_create); } /* the file has been created */ /* chown the file to the current user */ if(((xfsfsal_op_context_t *)p_context)->credential.user != geteuid()) { TakeTokenFSCall(); /* if the setgid_bit was set on the parent directory, do not change the group of the created file, because it's already the parentdir's group */ rc = fchown(newfd, ((xfsfsal_op_context_t *)p_context)->credential.user, setgid_bit ? -1 : (int)((xfsfsal_op_context_t *)p_context)->credential.group); errsv = errno; ReleaseTokenFSCall(); if(rc) { close(fd); close(newfd); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create); } } close(fd); close(newfd); /* retrieve file attributes */ if(p_object_attributes) { status = XFSFSAL_getattrs(p_object_handle, p_context, p_object_attributes); /* on error, we set a special bit in the mask. */ if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_object_attributes->asked_attributes); FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_create); }
/** * FSAL_mknode: * Create a special object in the filesystem. * Not supported upon HPSS. * * \return ERR_FSAL_NOTSUPP. */ fsal_status_t XFSFSAL_mknode(fsal_handle_t * parentdir_handle, /* IN */ fsal_name_t * p_node_name, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_accessmode_t accessmode, /* IN */ fsal_nodetype_t nodetype, /* IN */ fsal_dev_t * dev, /* IN */ fsal_handle_t * p_object_handle, /* OUT (handle to the created node) */ fsal_attrib_list_t * node_attributes /* [ IN/OUT ] */ ) { int rc, errsv; int setgid_bit = 0; struct stat buffstat; fsal_status_t status; int fd, newfd; mode_t unix_mode = 0; dev_t unix_dev = 0; /* sanity checks. * note : link_attributes is optional. */ if(!parentdir_handle || !p_context || !p_node_name) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mknode); unix_mode = fsal2unix_mode(accessmode); /* Apply umask */ unix_mode = unix_mode & ~global_fs_info.umask; switch (nodetype) { case FSAL_TYPE_BLK: if(!dev) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mknode); unix_mode |= S_IFBLK; unix_dev = (dev->major << 8) | (dev->minor & 0xFF); break; case FSAL_TYPE_CHR: if(!dev) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mknode); unix_mode |= S_IFCHR; unix_dev = (dev->major << 8) | (dev->minor & 0xFF); break; case FSAL_TYPE_SOCK: unix_mode |= S_IFSOCK; break; case FSAL_TYPE_FIFO: unix_mode |= S_IFIFO; break; default: LogMajor(COMPONENT_FSAL, "Invalid node type in FSAL_mknode: %d", nodetype); Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_mknode); } /* build the directory path */ TakeTokenFSCall(); status = fsal_internal_handle2fd(p_context, parentdir_handle, &fd, O_DIRECTORY); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_mknode); /* retrieve directory attributes */ TakeTokenFSCall(); rc = fstat(fd, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) { close(fd); if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_mknode); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mknode); } /* Check the user can write in the directory, and check weither the setgid bit on the directory */ if(buffstat.st_mode & S_ISGID) setgid_bit = 1; status = fsal_internal_testAccess(p_context, FSAL_W_OK | FSAL_X_OK, &buffstat, NULL); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_mknode); /* creates the node, then stats it */ TakeTokenFSCall(); rc = mknodat(fd, p_node_name->name, unix_mode, unix_dev); errsv = errno; if(rc) { close(fd); ReleaseTokenFSCall(); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mknode); } /* get the new object handle */ if((newfd = openat(fd, p_node_name->name, O_RDONLY, 0600)) < 0) { errsv = errno; close(fd); ReleaseTokenFSCall(); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir); } status = fsal_internal_fd2handle(p_context, newfd, p_object_handle); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) { close(fd); close(newfd); ReturnStatus(status, INDEX_FSAL_mknode); } /* the node has been created */ /* chown the file to the current user/group */ if(((xfsfsal_op_context_t *)p_context)->credential.user != geteuid()) { TakeTokenFSCall(); /* if the setgid_bit was set on the parent directory, do not change the group of the created file, because it's already the parentdir's group */ rc = fchown(newfd, ((xfsfsal_op_context_t *)p_context)->credential.user, setgid_bit ? -1 : (int)((xfsfsal_op_context_t *)p_context)->credential.group); errsv = errno; ReleaseTokenFSCall(); if(rc) { close(fd); close(newfd); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mknode); } } close(fd); close(newfd); /* Fills the attributes if needed */ if(node_attributes) { status = XFSFSAL_getattrs(p_object_handle, p_context, node_attributes); /* on error, we set a special bit in the mask. */ if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(node_attributes->asked_attributes); FSAL_SET_MASK(node_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } /* Finished */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_mknode); }
/** * @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; }