/** * PTFSAL_getattrs_descriptor: * Get attributes for the object specified by its descriptor or by it's * filehandle. * * \param p_file_descriptor (input): * The file descriptor of the object to get parameters. * \param p_filehandle (input): * The handle of the object to get parameters. * \param p_context (input): * Authentication context for the operation (user,...). * \param p_object_attributes (mandatory input/output): * The retrieved attributes for the object. * As input, it defines the attributes that the caller * wants to retrieve (by positioning flags into this structure) * and the output is built considering this input * (it fills the structure according to the flags it contains). * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - Another error code if an error occured. */ fsal_status_t PTFSAL_getattrs_descriptor( fsal_file_t * p_file_descriptor, /* IN */ fsal_handle_t * p_filehandle, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_attrib_list_t * p_object_attributes /* IN/OUT */) { if (!p_file_descriptor) { Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_getattrs_descriptor); } ptfsal_file_t * p_file_desc = (ptfsal_file_t *)p_file_descriptor; FSI_TRACE(FSI_DEBUG, "FSI---File descriptor=%d\n", p_file_desc->fd); return PTFSAL_getattrs(p_filehandle, p_context, p_object_attributes); }
/** * FSAL_readlink: * Read the content of a symbolic link. * * \param dir_hdl (input): * Handle of the link to be read. * \param p_context (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_len (input/output): * In pointer to len of content buff. . Out actual len of content. * \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 PTFSAL_readlink(struct fsal_obj_handle *dir_hdl, /* IN */ const struct req_op_context *p_context, /* IN */ char *p_link_content, /* OUT */ size_t *link_len, /* IN/OUT */ struct attrlist *p_link_attributes) { /* IN/OUT */ fsal_status_t status; struct pt_fsal_obj_handle *pt_hdl; char link_content_out[PATH_MAX]; /* sanity checks. * note : link_attributes is optional. */ if (!dir_hdl || !p_context || !p_link_content) return fsalstat(ERR_FSAL_FAULT, 0); pt_hdl = container_of(dir_hdl, struct pt_fsal_obj_handle, obj_handle); memset(link_content_out, 0, sizeof(link_content_out)); /* Read the link on the filesystem */ status = fsal_readlink_by_handle(p_context, p_context->fsal_export, pt_hdl->handle, p_link_content, *link_len); if (FSAL_IS_ERROR(status)) return status; /* retrieves object attributes, if asked */ if (p_link_attributes) { status = PTFSAL_getattrs(p_context->fsal_export, p_context, pt_hdl->handle, p_link_attributes); /* On error, we set a flag in the returned attributes */ if (FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_link_attributes->mask); FSAL_SET_MASK(p_link_attributes->mask, ATTR_RDATTR_ERR); } } return fsalstat(ERR_FSAL_NO_ERROR, 0); }
/** * FSAL_create: * Create a regular file. * * \param parent_hdl (input): * Handle of the parent directory where the file is to be created. * \param p_filename (input): * Pointer to the name of the file to be created. * \param p_context (input): * Authentication context for the operation (user,...). * \param accessmode (input): * Mode for the file to be created. * (the umask defined into the FSAL configuration file * will be applied on it). * \param p_object_handle (output): * Pointer to the handle of the created file. * \param p_object_attributes (optional input/output): * The attributes of the created file. * As input, it defines the attributes that the caller * wants to retrieve (by positioning flags into this structure) * and the output is built considering this input * (it fills the structure according to the flags it contains). * May be NULL. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - Another error code if an error occurred. */ fsal_status_t PTFSAL_create(struct fsal_obj_handle *dir_hdl, /* IN */ const char *p_filename, /* IN */ const struct req_op_context *p_context, /* IN */ uint32_t accessmode, /* IN */ ptfsal_handle_t *p_object_handle, /* OUT */ struct attrlist *p_object_attributes) { /* IN/OUT */ int errsv; fsal_status_t status; struct pt_fsal_obj_handle *pt_hdl; mode_t unix_mode; int open_rc; ptfsal_handle_t *p_fsi_handle = (ptfsal_handle_t *) p_object_handle; FSI_TRACE(FSI_DEBUG, "Begin to create file************************\n"); /* sanity checks. * note : object_attributes is optional. */ if (!dir_hdl || !p_context || !p_object_handle || !p_filename) return fsalstat(ERR_FSAL_FAULT, 0); pt_hdl = container_of(dir_hdl, struct pt_fsal_obj_handle, obj_handle); /* convert fsal mode to unix mode. */ unix_mode = fsal2unix_mode(accessmode); /* Apply umask */ unix_mode = unix_mode & ~p_context->fsal_export->exp_ops. fs_umask(p_context->fsal_export); LogFullDebug(COMPONENT_FSAL, "Creation mode: 0%o", accessmode); open_rc = ptfsal_open(pt_hdl, p_filename, p_context, unix_mode, p_object_handle); if (open_rc < 0) { errsv = errno; return fsalstat(posix2fsal_error(errsv), errsv); } FSI_TRACE(FSI_DEBUG, "New Handle = %s", (char *)p_fsi_handle->data.handle.f_handle); /* retrieve file attributes */ if (p_object_attributes) { status = PTFSAL_getattrs(p_context->fsal_export, p_context, p_object_handle, p_object_attributes); /* on error, we set a special bit in the mask. */ if (FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_object_attributes->mask); FSAL_SET_MASK(p_object_attributes->mask, ATTR_RDATTR_ERR); } } FSI_TRACE(FSI_DEBUG, "End to create file************************\n"); /* OK */ return fsalstat(ERR_FSAL_NO_ERROR, 0); }
/** * FSAL_mkdir: * Create a directory. * * \param dir_hdl (input): * Handle of the parent directory where * the subdirectory is to be created. * \param p_context (input): * Pointer to the name of the directory to be created. * \param cred (input): * Authentication context for the operation (user,...). * \param accessmode (input): * Mode for the directory to be created. * (the umask defined into the FSAL configuration file * will be applied on it). * \param p_object_handle (output): * Pointer to the handle of the created directory. * \param p_object_attributes (optionnal input/output): * The attributes of the created directory. * As input, it defines the attributes that the caller * wants to retrieve (by positioning flags into this structure) * and the output is built considering this input * (it fills the structure according to the flags it contains). * May be NULL. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - Another error code if an error occured. */ fsal_status_t PTFSAL_mkdir(struct fsal_obj_handle *dir_hdl, /* IN */ const char *p_dirname, /* IN */ const struct req_op_context *p_context, /* IN */ uint32_t accessmode, /* IN */ ptfsal_handle_t *p_object_handle, /* OUT */ struct attrlist *p_object_attributes) { /* IN/OUT */ int rc, errsv; int setgid_bit = 0; mode_t unix_mode; fsal_status_t status; struct attrlist parent_dir_attrs; char newPath[PATH_MAX]; struct pt_fsal_obj_handle *pt_hdl; FSI_TRACE(FSI_INFO, "MKDIR BEGIN-------------------------\n"); /* sanity checks. * note : object_attributes is optional. */ if (!dir_hdl || !p_context || !p_object_handle || !p_dirname) return fsalstat(ERR_FSAL_FAULT, 0); pt_hdl = container_of(dir_hdl, struct pt_fsal_obj_handle, obj_handle); /* convert FSAL mode to unix mode. */ unix_mode = fsal2unix_mode(accessmode); /* Apply umask */ unix_mode = unix_mode & ~p_context->fsal_export->exp_ops. fs_umask(p_context->fsal_export); /* get directory metadata */ parent_dir_attrs.mask = p_context->fsal_export->exp_ops. fs_supported_attrs(p_context->fsal_export); status = PTFSAL_getattrs(p_context->fsal_export, p_context, pt_hdl->handle, &parent_dir_attrs); if (FSAL_IS_ERROR(status)) return status; /* Check the user can write in the directory, and check the * setgid bit on the directory */ if (fsal2unix_mode(parent_dir_attrs.mode) & S_ISGID) setgid_bit = 1; rc = ptfsal_mkdir(pt_hdl, p_dirname, p_context, unix_mode, p_object_handle); errsv = errno; if (rc) return fsalstat(posix2fsal_error(errsv), errsv); if (FSAL_IS_ERROR(status)) return status; /* the directory has been created */ /* chown the dir to the current user/group */ if (p_context->creds->caller_uid != geteuid()) { FSI_TRACE(FSI_DEBUG, "MKDIR %d", __LINE__); /* if the setgid_bit was set on the parent directory, do not * change the group of the created file, because it's already * the parentdir's group */ if (fsi_get_name_from_handle (p_context, p_context->fsal_export, pt_hdl->handle, (char *)newPath, NULL) < 0) { FSI_TRACE(FSI_DEBUG, "Failed to get name from handle %s", (char *)p_object_handle->data.handle. f_handle); return fsalstat(posix2fsal_error(errsv), errsv); } rc = ptfsal_chown(p_context, p_context->fsal_export, newPath, p_context->creds->caller_uid, setgid_bit ? -1 : (int)p_context->creds-> caller_gid); errsv = errno; if (rc) return fsalstat(posix2fsal_error(errsv), errsv); } /* retrieve file attributes */ if (p_object_attributes) { FSI_TRACE(FSI_DEBUG, "MKDIR %d", __LINE__); status = PTFSAL_getattrs(p_context->fsal_export, p_context, p_object_handle, p_object_attributes); /* on error, we set a special bit in the mask. */ if (FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_object_attributes->mask); FSAL_SET_MASK(p_object_attributes->mask, ATTR_RDATTR_ERR); } } FSI_TRACE(FSI_INFO, "MKDIR END ------------------\n"); FSI_TRACE(FSI_DEBUG, "MKDIR %d", __LINE__); /* OK */ return fsalstat(ERR_FSAL_NO_ERROR, 0); }
/** * FSAL_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 PTFSAL_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 errsv; int setgid_bit = 0; fsal_status_t status; mode_t unix_mode; fsal_accessflags_t access_mask = 0; fsal_attrib_list_t parent_dir_attrs; int open_rc; ptfsal_handle_t * p_fsi_handle = (ptfsal_handle_t *)p_object_handle; FSI_TRACE(FSI_DEBUG, "Begin to create file************************\n"); /* sanity checks. * note : object_attributes is optional. */ if(!p_parent_directory_handle || !p_context || !p_object_handle || !p_filename) { FSI_TRACE(FSI_DEBUG, "BAD Happen!"); Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_create); } /* convert fsal mode to unix mode. */ unix_mode = fsal2unix_mode(accessmode); /* Apply umask */ unix_mode = unix_mode & ~global_fs_info.umask; LogFullDebug(COMPONENT_FSAL, "Creation mode: 0%o", accessmode); /* retrieve directory metadata */ parent_dir_attrs.asked_attributes = PTFS_SUPPORTED_ATTRIBUTES; status = PTFSAL_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); if(!p_context->export_context->fe_static_fs_info->accesscheck_support) { status = fsal_internal_testAccess(p_context, access_mask, NULL, &parent_dir_attrs); } else { status = fsal_internal_access(p_context, p_parent_directory_handle, access_mask, &parent_dir_attrs); } if(FSAL_IS_ERROR(status)) { ReturnStatus(status, INDEX_FSAL_create); } // Create the file, return handle open_rc = ptfsal_open(p_parent_directory_handle, p_filename, p_context, unix_mode, p_object_handle); if (open_rc < 0) { errsv = errno; Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_create); } FSI_TRACE(FSI_DEBUG, "New Handle = %s", (char *)p_fsi_handle->data.handle.f_handle); /* retrieve file attributes */ if(p_object_attributes) { status = PTFSAL_getattrs(p_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); } } FSI_TRACE(FSI_DEBUG, "End to create file************************\n"); /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_create); }
/** * 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 PTFSAL_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; fsal_accessflags_t access_mask = 0; fsal_attrib_list_t parent_dir_attrs; char newPath[PATH_MAX]; FSI_TRACE(FSI_INFO,"MKDIR BEGIN-------------------------\n"); /* sanity checks. * note : object_attributes is optional. */ if(!p_parent_directory_handle || !p_context || !p_object_handle || !p_dirname) { Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_mkdir); } /* convert FSAL mode to unix mode. */ unix_mode = fsal2unix_mode(accessmode); /* Apply umask */ unix_mode = unix_mode & ~global_fs_info.umask; /* get directory metadata */ parent_dir_attrs.asked_attributes = PTFS_SUPPORTED_ATTRIBUTES; status = PTFSAL_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); if(!p_context->export_context->fe_static_fs_info->accesscheck_support) { status = fsal_internal_testAccess(p_context, access_mask, NULL, &parent_dir_attrs); } else { status = fsal_internal_access(p_context, p_parent_directory_handle, access_mask, &parent_dir_attrs); } if(FSAL_IS_ERROR(status)) { ReturnStatus(status, INDEX_FSAL_mkdir); } rc = ptfsal_mkdir(p_parent_directory_handle, p_dirname, p_context, unix_mode, p_object_handle); errsv = errno; if(rc) { Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir); } if(FSAL_IS_ERROR(status)) { ReturnStatus(status, INDEX_FSAL_mkdir); } /* the directory has been created */ /* chown the dir to the current user/group */ if(p_context->credential.user != geteuid()) { FSI_TRACE(FSI_DEBUG, "MKDIR %d",__LINE__); /* if the setgid_bit was set on the parent directory, do not change * the group of the created file, because it's already the parentdir's * group */ if(fsi_get_name_from_handle( p_context, (char *)p_object_handle->data.handle.f_handle, (char *)newPath, NULL) < 0) { FSI_TRACE(FSI_DEBUG, "Failed to get name from handle %s", (char *)p_object_handle->data.handle.f_handle); Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir); } rc = ptfsal_chown(p_context, newPath, p_context->credential.user, setgid_bit ? -1 : (int)p_context->credential.group); errsv = errno; if(rc) { Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_mkdir); } } /* retrieve file attributes */ if(p_object_attributes) { FSI_TRACE(FSI_DEBUG, "MKDIR %d",__LINE__); status = PTFSAL_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); } } FSI_TRACE(FSI_INFO,"MKDIR END ------------------\n"); FSI_TRACE(FSI_DEBUG, "MKDIR %d",__LINE__); /* OK */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_mkdir); }
/** * 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 PTFSAL_lookup(const struct req_op_context *p_context, struct fsal_obj_handle *parent, const char *p_filename, struct attrlist *p_object_attr, ptfsal_handle_t *fh) { fsal_status_t status; int parent_fd; struct attrlist *parent_dir_attrs; fsi_stat_struct buffstat; int rc; struct pt_fsal_obj_handle *parent_hdl; FSI_TRACE(FSI_DEBUG, "Begin##################################\n"); if (p_filename != NULL) FSI_TRACE(FSI_DEBUG, "FSI - fsal_lookup file [%s]\n", p_filename); if (parent != NULL) FSI_TRACE(FSI_DEBUG, "FSI - fsal_lookup parent dir\n"); if (!parent || !p_filename) return fsalstat(ERR_FSAL_FAULT, 0); parent_hdl = container_of(parent, struct pt_fsal_obj_handle, obj_handle); parent_dir_attrs = &parent_hdl->obj_handle.attributes; /* get directory metadata */ parent_dir_attrs->mask = p_context->fsal_export->exp_ops. fs_supported_attrs(p_context->fsal_export); status = fsal_internal_handle2fd_at(p_context, parent_hdl, &parent_fd, O_RDONLY); if (FSAL_IS_ERROR(status)) return status; FSI_TRACE(FSI_DEBUG, "FSI - lookup parent directory type = %d\n", parent_dir_attrs->type); /* Be careful about junction crossing, symlinks, hardlinks,... */ switch (parent_dir_attrs->type) { case DIRECTORY: /* OK */ break; case REGULAR_FILE: case SYMBOLIC_LINK: /* not a directory */ pt_close(parent); return fsalstat(ERR_FSAL_NOTDIR, 0); default: return fsalstat(ERR_FSAL_SERVERFAULT, 0); } /* get file handle, it it exists */ /* This might be a race, but it's the best we can currently do */ rc = ptfsal_stat_by_parent_name(p_context, parent_hdl, p_filename, &buffstat); if (rc < 0) { ptfsal_closedir_fd(p_context, p_context->fsal_export, parent_fd); return fsalstat(ERR_FSAL_NOENT, errno); } memset(fh->data.handle.f_handle, 0, sizeof(fh->data.handle.f_handle)); memcpy(&fh->data.handle.f_handle, &buffstat.st_persistentHandle.handle, FSI_CCL_PERSISTENT_HANDLE_N_BYTES); fh->data.handle.handle_size = FSI_CCL_PERSISTENT_HANDLE_N_BYTES; fh->data.handle.handle_key_size = OPENHANDLE_KEY_LEN; fh->data.handle.handle_version = OPENHANDLE_VERSION; fh->data.handle.handle_type = posix2fsal_type(buffstat.st_mode); /* get object attributes */ if (p_object_attr) { p_object_attr->mask = p_context->fsal_export->exp_ops. fs_supported_attrs(p_context->fsal_export); status = PTFSAL_getattrs(p_context->fsal_export, p_context, fh, p_object_attr); if (FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_object_attr->mask); FSAL_SET_MASK(p_object_attr->mask, ATTR_RDATTR_ERR); } } ptfsal_closedir_fd(p_context, p_context->fsal_export, parent_fd); FSI_TRACE(FSI_DEBUG, "End##################################\n"); /* lookup complete ! */ return fsalstat(ERR_FSAL_NO_ERROR, 0); }
/** * 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_unlink: * Remove a filesystem object . * * \param dir_hdl (input): * Handle of the parent directory of the object to be deleted. * \param p_object_name (input): * Name of the object to be removed. * \param p_context (input): * Authentication context for the operation (user,...). * \param p_parentdir_attributes (optionnal input/output): * Post operation attributes of the parent directory. * As input, it defines the attributes that the caller * wants to retrieve (by positioning flags into this structure) * and the output is built considering this input * (it fills the structure according to the flags it contains). * May be NULL. * * \return Major error codes : * - ERR_FSAL_NO_ERROR (no error) * - Another error code if an error occured. */ fsal_status_t PTFSAL_unlink(struct fsal_obj_handle *dir_hdl, /* IN */ const char *p_object_name, /* IN */ const struct req_op_context *p_context, /* IN */ struct attrlist *p_parent_attributes) { /* IN/OUT */ fsal_status_t status; int rc, errsv; fsi_stat_struct buffstat; struct pt_fsal_obj_handle *pt_hdl; /* sanity checks. */ if (!dir_hdl || !p_context || !p_object_name) return fsalstat(ERR_FSAL_FAULT, 0); pt_hdl = container_of(dir_hdl, struct pt_fsal_obj_handle, obj_handle); FSI_TRACE(FSI_DEBUG, "FSI - PTFSAL_unlink [%s] entry\n", p_object_name); /* build the child path */ FSI_TRACE(FSI_DEBUG, "FSI - PTFSAL_unlink [%s] build child path\n", p_object_name); /* get file metadata */ rc = ptfsal_stat_by_parent_name(p_context, pt_hdl, p_object_name, &buffstat); if (rc) { FSI_TRACE(FSI_DEBUG, "FSI - PTFSAL_unlink stat [%s] rc %d\n", p_object_name, rc); return fsalstat(posix2fsal_error(errno), errno); } /****************************** * DELETE FROM THE FILESYSTEM * ******************************/ /* If the object to delete is a directory, use 'rmdir' to delete * the object else use 'unlink' */ if (S_ISDIR(buffstat.st_mode)) { FSI_TRACE(FSI_DEBUG, "Deleting directory %s", p_object_name); rc = ptfsal_rmdir(p_context, pt_hdl, p_object_name); } else { FSI_TRACE(FSI_DEBUG, "Deleting file %s", p_object_name); rc = ptfsal_unlink(p_context, pt_hdl, p_object_name); } if (rc) { errsv = errno; return fsalstat(posix2fsal_error(errsv), errsv); } /*********************** * FILL THE ATTRIBUTES * ***********************/ if (p_parent_attributes) { status = PTFSAL_getattrs(p_context->fsal_export, p_context, pt_hdl->handle, p_parent_attributes); if (FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_parent_attributes->mask); FSAL_SET_MASK(p_parent_attributes->mask, ATTR_RDATTR_ERR); } } /* OK */ return fsalstat(ERR_FSAL_NO_ERROR, 0); }