/** * 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 LUSTREFSAL_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; fsal_status_t st; fsal_path_t fsalpath; 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); /* get the path of the file */ st = fsal_internal_Handle2FidPath(p_context, p_filehandle, &fsalpath); if(FSAL_IS_ERROR(st)) ReturnStatus(st, INDEX_FSAL_getattrs); /* get file metadata */ TakeTokenFSCall(); rc = lstat(fsalpath.path, &buffstat); ReleaseTokenFSCall(); if(rc != 0) { rc = errno; if(rc == ENOENT) Return(ERR_FSAL_STALE, rc, INDEX_FSAL_getattrs); else Return(posix2fsal_error(rc), rc, 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); }
/** * FSAL_dynamic_fsinfo: * Return dynamic filesystem info such as * used size, free size, number of objects... * * \param filehandle (input): * Handle of an object in the filesystem * whom info is to be retrieved. * \param cred (input): * Authentication context for the operation (user,...). * \param dynamicinfo (output): * Pointer to the static info of the filesystem. * * \return Major error codes: * - ERR_FSAL_NO_ERROR: no error. * - ERR_FSAL_FAULT: NULL pointer passed as input parameter. * - ERR_FSAL_SERVERFAULT: Unexpected error. */ fsal_status_t LUSTREFSAL_dynamic_fsinfo(fsal_handle_t * p_filehandle, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_dynamicfsinfo_t * p_dynamicinfo /* OUT */ ) { fsal_path_t pathfsal; fsal_status_t status; struct statvfs buffstatvfs; int rc, errsv; /* sanity checks. */ if(!p_filehandle || !p_dynamicinfo || !p_context) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_dynamic_fsinfo); status = fsal_internal_Handle2FidPath(p_context, p_filehandle, &pathfsal); if(FSAL_IS_ERROR(status)) Return(status.major, status.minor, INDEX_FSAL_dynamic_fsinfo); TakeTokenFSCall(); rc = statvfs(pathfsal.path, &buffstatvfs); errsv = errno; ReleaseTokenFSCall(); if(rc) Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_dynamic_fsinfo); p_dynamicinfo->total_bytes = buffstatvfs.f_frsize * buffstatvfs.f_blocks; p_dynamicinfo->free_bytes = buffstatvfs.f_frsize * buffstatvfs.f_bfree; p_dynamicinfo->avail_bytes = buffstatvfs.f_frsize * buffstatvfs.f_bavail; p_dynamicinfo->total_files = buffstatvfs.f_files; p_dynamicinfo->free_files = buffstatvfs.f_ffree; p_dynamicinfo->avail_files = buffstatvfs.f_favail; p_dynamicinfo->time_delta.seconds = 1; p_dynamicinfo->time_delta.nseconds = 0; Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_dynamic_fsinfo); }
fsal_status_t LUSTREFSAL_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; fsal_path_t fsalpath; /* sanity checks. */ if(!p_parent_directory_handle || !p_context || !p_object_name) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_unlink); /* build the FID path */ status = fsal_internal_Handle2FidPath(p_context, p_parent_directory_handle, &fsalpath); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_unlink); /* get directory metadata */ TakeTokenFSCall(); rc = lstat(fsalpath.path, &buffstat_parent); errsv = errno; ReleaseTokenFSCall(); if(rc) { if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_unlink); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_unlink); } /* build the child path */ status = fsal_internal_appendNameToPath(&fsalpath, p_object_name); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_unlink); /* get file metadata */ TakeTokenFSCall(); rc = lstat(fsalpath.path, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) Return(posix2fsal_error(errsv), errsv, 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 != p_context->credential.user && buffstat.st_uid != p_context->credential.user && p_context->credential.user != 0) { 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)) ? rmdir(fsalpath.path) : unlink(fsalpath.path); errsv = errno; ReleaseTokenFSCall(); if(rc) Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_unlink); /*********************** * FILL THE ATTRIBUTES * ***********************/ if(p_parent_directory_attributes) { status = LUSTREFSAL_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 LUSTREFSAL_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 ] */ ) { int rc; fsal_status_t status; fsal_path_t fsalpath; struct stat buffstat; lustrefsal_dir_t *p_dir_descriptor = (lustrefsal_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 */ status = fsal_internal_Handle2FidPath(p_context, p_dir_handle, &fsalpath); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_opendir); /* get directory metadata */ TakeTokenFSCall(); rc = lstat(fsalpath.path, &buffstat); ReleaseTokenFSCall(); if(rc != 0) { rc = errno; if(rc == ENOENT) Return(ERR_FSAL_STALE, rc, INDEX_FSAL_opendir); else Return(posix2fsal_error(rc), rc, 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 : */ TakeTokenFSCall(); p_dir_descriptor->p_dir = opendir(fsalpath.path); ReleaseTokenFSCall(); if(!p_dir_descriptor->p_dir) Return(posix2fsal_error(errno), errno, INDEX_FSAL_opendir); memcpy(&(p_dir_descriptor->context), p_context, sizeof(lustrefsal_op_context_t)); memcpy(&(p_dir_descriptor->path), &fsalpath, sizeof(fsal_path_t)); memcpy(&(p_dir_descriptor->handle), p_dir_handle, sizeof(lustrefsal_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); } } Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_opendir); }
/** * 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 LUSTREFSAL_open(lustrefsal_handle_t * p_filehandle, /* IN */ lustrefsal_op_context_t * p_context, /* IN */ fsal_openflags_t openflags, /* IN */ lustrefsal_file_t * p_file_descriptor, /* OUT */ fsal_attrib_list_t * p_file_attributes /* [ IN/OUT ] */ ) { int rc, errsv; fsal_status_t status; fsal_path_t fsalpath; 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); status = fsal_internal_Handle2FidPath(p_context, p_filehandle, &fsalpath); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_open); /* retrieve file attributes for checking access rights */ TakeTokenFSCall(); rc = lstat(fsalpath.path, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) { if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_open); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_open); } status = fsal_internal_testAccess(p_context, openflags & FSAL_O_RDONLY ? FSAL_R_OK : FSAL_W_OK, &buffstat, NULL); if(FSAL_IS_ERROR(status)) ReturnStatus(status, 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(); p_file_descriptor->fd = open(fsalpath.path, posix_flags, 0644); errsv = errno; ReleaseTokenFSCall(); if(p_file_descriptor->fd == -1) Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_open); /* set the read-only flag of the file descriptor */ 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 LUSTREFSAL_rename(lustrefsal_handle_t * p_old_parentdir_handle, /* IN */ fsal_name_t * p_old_name, /* IN */ lustrefsal_handle_t * p_new_parentdir_handle, /* IN */ fsal_name_t * p_new_name, /* IN */ lustrefsal_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; fsal_path_t old_fsalpath, new_fsalpath; int src_equal_tgt = FALSE; /* 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 */ status = fsal_internal_Handle2FidPath(p_context, p_old_parentdir_handle, &old_fsalpath); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_rename); /* retrieve directory metadata for checking access rights */ TakeTokenFSCall(); rc = lstat(old_fsalpath.path, &old_parent_buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) { 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(!LUSTREFSAL_handlecmp(p_old_parentdir_handle, p_new_parentdir_handle, &status)) { FSAL_pathcpy(&new_fsalpath, &old_fsalpath); src_equal_tgt = TRUE; new_parent_buffstat = old_parent_buffstat; } else { status = fsal_internal_Handle2FidPath(p_context, p_new_parentdir_handle, &new_fsalpath); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_rename); /* retrieve destination attrs */ TakeTokenFSCall(); rc = lstat(new_fsalpath.path, &new_parent_buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) { 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_internal_testAccess(p_context, FSAL_W_OK | FSAL_X_OK, &old_parent_buffstat, NULL); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_rename); if(!src_equal_tgt) { status = fsal_internal_testAccess(p_context, FSAL_W_OK | FSAL_X_OK, &new_parent_buffstat, NULL); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_rename); } /* build file paths */ status = fsal_internal_appendNameToPath(&old_fsalpath, p_old_name); if(FSAL_IS_ERROR(status)) Return(status.major, status.minor, INDEX_FSAL_rename); status = fsal_internal_appendNameToPath(&new_fsalpath, p_new_name); if(FSAL_IS_ERROR(status)) Return(status.major, status.minor, INDEX_FSAL_rename); TakeTokenFSCall(); rc = lstat(old_fsalpath.path, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) 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 != p_context->credential.user && buffstat.st_uid != p_context->credential.user && p_context->credential.user != 0) 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 = lstat(new_fsalpath.path, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) { if(errsv != ENOENT) Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename); } else if(new_parent_buffstat.st_uid != p_context->credential.user && buffstat.st_uid != p_context->credential.user && p_context->credential.user != 0) Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_rename); } /************************************* * Rename the file on the filesystem * *************************************/ TakeTokenFSCall(); rc = rename(old_fsalpath.path, new_fsalpath.path); errsv = errno; ReleaseTokenFSCall(); if(rc) Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_rename); /*********************** * Fill the attributes * ***********************/ if(p_src_dir_attributes) { status = LUSTREFSAL_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 = LUSTREFSAL_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_status_t LUSTREFSAL_truncate(fsal_handle_t * p_filehandle, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_size_t length, /* IN */ fsal_file_t * file_descriptor, /* Unused in this FSAL */ fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */ ) { int rc, errsv; fsal_path_t fsalpath; fsal_status_t st; int no_trunc = 0; /* 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 */ st = fsal_internal_Handle2FidPath(p_context, p_filehandle, &fsalpath); if(FSAL_IS_ERROR(st)) ReturnStatus(st, INDEX_FSAL_truncate); #ifdef _SHOOK /* If the file is not online: * - if truncate(0) => call tuncate(0), then "shook restore_trunc" * - if truncate(>0) => call "shook restore", then truncate */ shook_state state; rc = shook_get_status(fsalpath.path, &state, FALSE); if (rc) { LogEvent(COMPONENT_FSAL, "Error retrieving shook status of %s: %s", fsalpath.path, strerror(-rc)); if (rc) Return(posix2fsal_error(-rc), -rc, INDEX_FSAL_truncate); } else if (state != SS_ONLINE) { if (length == 0) { LogInfo(COMPONENT_FSAL, "File is offline: calling shook restore_trunc"); /* first truncate the file, them call the shook_svr to clear * the 'released' flag */ TakeTokenFSCall(); rc = truncate(fsalpath.path, 0); errsv = errno; ReleaseTokenFSCall(); if (rc == 0) { /* use a short timeout of 2s */ rc = shook_server_call(SA_RESTORE_TRUNC, ((lustrefsal_op_context_t *)p_context)->export_context->fsname, &((lustrefsal_handle_t *)p_filehandle)->data.fid, 2); if (rc) Return(posix2fsal_error(-rc), -rc, INDEX_FSAL_truncate); else { /* check that file is online, else operation is still * in progress: return err jukebox */ rc = shook_get_status(fsalpath.path, &state, FALSE); if (rc) { LogEvent(COMPONENT_FSAL, "Error retrieving shook status of %s: %s", fsalpath.path, strerror(-rc)); if (rc) Return(posix2fsal_error(-rc), -rc, INDEX_FSAL_truncate); } else if (state != SS_ONLINE) Return(ERR_FSAL_DELAY, -rc, INDEX_FSAL_truncate); /* OK */ } /* file is already truncated, no need to truncate again */ no_trunc = 1; } else { if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_truncate); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_truncate); } } else /* length > 0 */ { /* trigger restore. Give it a chance to retrieve the file in less than a second. * Else, it returns ETIME that is converted in ERR_DELAY */ rc = shook_server_call(SA_RESTORE, ((lustrefsal_op_context_t *)p_context)->export_context->fsname, &((lustrefsal_handle_t *)p_filehandle)->data.fid, 1); if (rc) Return(posix2fsal_error(-rc), -rc, INDEX_FSAL_truncate); else { /* check that file is online, else operation is still * in progress: return err jukebox */ rc = shook_get_status(fsalpath.path, &state, FALSE); if (rc) { LogEvent(COMPONENT_FSAL, "Error retrieving shook status of %s: %s", fsalpath.path, strerror(-rc)); if (rc) Return(posix2fsal_error(-rc), -rc, INDEX_FSAL_truncate); } else if (state != SS_ONLINE) Return(ERR_FSAL_DELAY, -rc, INDEX_FSAL_truncate); /* OK */ } /* if rc = 0, file can be opened */ } } /* else file is on line */ #endif /* Executes the POSIX truncate operation */ if (!no_trunc) { TakeTokenFSCall(); rc = truncate(fsalpath.path, length); errsv = errno; ReleaseTokenFSCall(); } /* 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 = LUSTREFSAL_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_readlink: * Read the content of a symbolic link. * * \param linkhandle (input): * Handle of the link to be read. * \param cred (input): * Authentication context for the operation (user,...). * \param p_link_content (output): * Pointer to an fsal path structure where * the link content is to be stored.. * \param link_attributes (optionnal input/output): * The post operation attributes of the symlink link. * 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 LUSTREFSAL_readlink(fsal_handle_t * p_linkhandle, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_path_t * p_link_content, /* OUT */ fsal_attrib_list_t * p_link_attributes /* [ IN/OUT ] */ ) { int rc, errsv; fsal_status_t status; char link_content_out[FSAL_MAX_PATH_LEN]; fsal_path_t fsalpath; /* sanity checks. * note : link_attributes is optional. */ if(!p_linkhandle || !p_context || !p_link_content) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_readlink); status = fsal_internal_Handle2FidPath(p_context, p_linkhandle, &fsalpath); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_readlink); memset(link_content_out, 0, FSAL_MAX_PATH_LEN); /* Read the link on the filesystem */ TakeTokenFSCall(); rc = readlink(fsalpath.path, link_content_out, FSAL_MAX_PATH_LEN); errsv = errno; ReleaseTokenFSCall(); /* rc is the length for the symlink content or -1 on error !!! */ if(rc < 0) Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_readlink); /* convert char * to fsal_path_t */ status = FSAL_str2path(link_content_out, FSAL_MAX_PATH_LEN, p_link_content); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_readlink); /* retrieves object attributes, if asked */ if(p_link_attributes) { status = LUSTREFSAL_getattrs(p_linkhandle, p_context, p_link_attributes); /* On error, we set a flag in the returned attributes */ if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_link_attributes->asked_attributes); FSAL_SET_MASK(p_link_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_readlink); }
/** * FSAL_symlink: * Create a symbolic link. * * \param parent_directory_handle (input): * Handle of the parent directory where the link is to be created. * \param p_linkname (input): * Name of the link to be created. * \param p_linkcontent (input): * Content of the link to be created. * \param cred (input): * Authentication context for the operation (user,...). * \param accessmode (ignored input): * Mode of the link to be created. * It has no sense in HPSS nor UNIX filesystems. * \param link_handle (output): * Pointer to the handle of the created symlink. * \param link_attributes (optionnal input/output): * 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 LUSTREFSAL_symlink(fsal_handle_t * p_parent_directory_handle, /* IN */ fsal_name_t * p_linkname, /* IN */ fsal_path_t * p_linkcontent, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_accessmode_t accessmode, /* IN (ignored) */ fsal_handle_t * p_link_handle, /* OUT */ fsal_attrib_list_t * p_link_attributes /* [ IN/OUT ] */ ) { int rc, errsv; fsal_status_t status; fsal_path_t fsalpath; struct stat buffstat; int setgid_bit = FALSE; /* sanity checks. * note : link_attributes is optional. */ if(!p_parent_directory_handle || !p_context || !p_link_handle || !p_linkname || !p_linkcontent) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_symlink); /* Tests if symlinking is allowed by configuration. */ if(!global_fs_info.symlink_support) Return(ERR_FSAL_NOTSUPP, 0, INDEX_FSAL_symlink); /* build the new path and check the permissions on the parent directory */ status = fsal_internal_Handle2FidPath(p_context, p_parent_directory_handle, &fsalpath); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_symlink); /* retrieve directory metadata, for checking access */ TakeTokenFSCall(); rc = lstat(fsalpath.path, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) { if(errsv == ENOENT) Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_symlink); else Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_symlink); } if(buffstat.st_mode & S_ISGID) setgid_bit = TRUE; status = fsal_internal_testAccess(p_context, FSAL_W_OK, &buffstat, NULL); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_symlink); /* build symlink path */ status = fsal_internal_appendNameToPath(&fsalpath, p_linkname); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_symlink); /* create the symlink on the filesystem. */ TakeTokenFSCall(); rc = symlink(p_linkcontent->path, fsalpath.path); errsv = errno; ReleaseTokenFSCall(); if(rc) Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_symlink); /* Get symlink handle */ TakeTokenFSCall(); status = fsal_internal_Path2Handle(p_context, &fsalpath, p_link_handle); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_lookup); /* chown the symlink to the current user/group */ TakeTokenFSCall(); rc = lchown(fsalpath.path, p_context->credential.user, setgid_bit ? -1 : p_context->credential.group); errsv = errno; ReleaseTokenFSCall(); if(rc) Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_symlink); /* get attributes if asked */ if(p_link_attributes) { status = LUSTREFSAL_getattrs(p_link_handle, p_context, p_link_attributes); /* On error, we set a flag in the returned attributes */ if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_link_attributes->asked_attributes); FSAL_SET_MASK(p_link_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_symlink); }
/** * FSAL_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 LUSTREFSAL_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 ] */ ) { int rc, errsv; unsigned int i; fsal_status_t status; fsal_attrib_list_t attrs; fsal_path_t fsalpath; 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; /* 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); } /* convert handle into path */ status = fsal_internal_Handle2FidPath(p_context, p_filehandle, &fsalpath); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_setattrs); /* get current attributes */ TakeTokenFSCall(); rc = lstat(fsalpath.path, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc != 0) { 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((p_context->credential.user != 0) && (p_context->credential.user != buffstat.st_uid)) { LogFullDebug(COMPONENT_FSAL, "Permission denied for CHMOD opeartion: current owner=%d, credential=%d", buffstat.st_uid, p_context->credential.user); Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); } TakeTokenFSCall(); rc = chmod(fsalpath.path, fsal2unix_mode(attrs.mode)); errsv = errno; ReleaseTokenFSCall(); if(rc) { 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((p_context->credential.user != 0) && ((p_context->credential.user != buffstat.st_uid) || (p_context->credential.user != attrs.owner))) { LogFullDebug(COMPONENT_FSAL, "Permission denied for CHOWN opeartion: current owner=%d, credential=%d, new owner=%d", buffstat.st_uid, p_context->credential.user, attrs.owner); 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((p_context->credential.user != 0) && (p_context->credential.user != buffstat.st_uid)) Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); int in_grp = 0; /* set in_grp */ if(p_context->credential.group == attrs.group) in_grp = 1; else for(i = 0; i < p_context->credential.nbgroups; i++) { if((in_grp = (attrs.group == p_context->credential.alt_groups[i]))) break; } /* it must also be in target group */ if(p_context->credential.user != 0 && !in_grp) { LogFullDebug(COMPONENT_FSAL, "Permission denied for CHOWN operation: current group=%d, credential=%d, new group=%d", buffstat.st_gid, p_context->credential.group, attrs.group); 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 = lchown(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); ReleaseTokenFSCall(); if(rc) 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) && (p_context->credential.user != 0) && (p_context->credential.user != buffstat.st_uid) && ((status = fsal_internal_testAccess(p_context, FSAL_R_OK, &buffstat, NULL)).major != ERR_FSAL_NO_ERROR)) 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) && (p_context->credential.user != 0) && (p_context->credential.user != buffstat.st_uid) && ((status = fsal_internal_testAccess(p_context, FSAL_W_OK, &buffstat, NULL)).major != ERR_FSAL_NO_ERROR)) ReturnStatus(status, INDEX_FSAL_setattrs); if(FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME | FSAL_ATTR_MTIME)) { struct utimbuf timebuf; timebuf.actime = (FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_ATIME) ? (time_t) attrs. atime.seconds : buffstat.st_atime); timebuf.modtime = (FSAL_TEST_MASK(attrs.asked_attributes, FSAL_ATTR_MTIME) ? (time_t) attrs. mtime.seconds : buffstat.st_mtime); TakeTokenFSCall(); rc = utime(fsalpath.path, &timebuf); errsv = errno; ReleaseTokenFSCall(); if(rc) Return(posix2fsal_error(errno), errno, INDEX_FSAL_setattrs); } /* Optionaly fills output attributes. */ if(p_object_attributes) { status = LUSTREFSAL_getattrs(p_filehandle, p_context, p_object_attributes); /* on error, we set a special bit in the mask. */ if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_object_attributes->asked_attributes); FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_setattrs); }
/** * FSAL_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 LUSTREFSAL_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 * p_object_handle, /* OUT */ fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */ ) { int rc, errsv; fsal_status_t status; struct stat buffstat; fsal_path_t pathfsal; /* 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 */ FSAL_str2path(((lustrefsal_op_context_t *)p_context)->export_context->mount_point, ((lustrefsal_op_context_t *)p_context)->export_context->mnt_len, &pathfsal); TakeTokenFSCall(); status = fsal_internal_Path2Handle(p_context, &pathfsal, p_object_handle); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_lookup); /* get attributes, if asked */ if(p_object_attributes) { status = LUSTREFSAL_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 */ status = fsal_internal_Handle2FidPath(p_context, p_parent_directory_handle, &pathfsal); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_lookup); /* get directory metadata */ TakeTokenFSCall(); rc = lstat(pathfsal.path, &buffstat); errsv = errno; ReleaseTokenFSCall(); if(rc) { 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: // 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 %s/%s\n", pathfsal.path, p_filename->name); /* check rights to enter into the directory */ status = fsal_internal_testAccess(p_context, FSAL_X_OK, &buffstat, NULL); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_lookup); status = fsal_internal_appendNameToPath(&pathfsal, p_filename); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_lookup); /* get file handle, it it exists */ TakeTokenFSCall(); status = fsal_internal_Path2Handle(p_context, &pathfsal, p_object_handle); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_lookup); /* get object attributes */ if(p_object_attributes) { status = LUSTREFSAL_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); } } /* lookup complete ! */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_lookup); }