/** * FSAL_access : * Tests whether the user or entity identified by its cred * can access the object identified by object_handle, * as indicated by the access_type parameters. * * \param object_handle (input): * The handle of the object to test permissions on. * \param cred (input): * Authentication context for the operation (user,...). * \param access_type (input): * Indicates the permissions to test. * This is an inclusive OR of the permissions * to be checked for the user identified by cred. * Permissions constants are : * - FSAL_R_OK : test for read permission * - FSAL_W_OK : test for write permission * - FSAL_X_OK : test for exec permission * - FSAL_F_OK : test for file existence * \param object_attributes (optional 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 XFSFSAL_access(fsal_handle_t * p_object_handle, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_accessflags_t access_type, /* IN */ fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */ ) { fsal_status_t status; /* sanity checks. * note : object_attributes is optionnal in FSAL_getattrs. */ if(!p_object_handle || !p_context) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_access); /* * If an error occures during getattr operation, * it is returned, even though the access operation succeeded. */ if(p_object_attributes) { FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_OWNER | FSAL_ATTR_GROUP | FSAL_ATTR_ACL | FSAL_ATTR_MODE); 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); Return(status.major, status.minor, INDEX_FSAL_access); } status = fsal_internal_testAccess(p_context, access_type, NULL, p_object_attributes); } else { /* p_object_attributes is NULL */ fsal_attrib_list_t attrs; FSAL_CLEAR_MASK(attrs.asked_attributes); FSAL_SET_MASK(attrs.asked_attributes, FSAL_ATTR_OWNER | FSAL_ATTR_GROUP | FSAL_ATTR_ACL | FSAL_ATTR_MODE); status = XFSFSAL_getattrs(p_object_handle, p_context, &attrs); /* on error, we set a special bit in the mask. */ if(FSAL_IS_ERROR(status)) Return(status.major, status.minor, INDEX_FSAL_access); status = fsal_internal_testAccess(p_context, access_type, NULL, &attrs); } Return(status.major, status.minor, INDEX_FSAL_access); }
fsal_status_t XFSFSAL_lookupPath(fsal_path_t * p_path, /* IN */ fsal_op_context_t * p_context, /* IN */ fsal_handle_t * object_handle, /* OUT */ fsal_attrib_list_t * p_object_attributes /* [ IN/OUT ] */ ) { fsal_status_t status; /* sanity checks * note : object_attributes is optionnal. */ if(!object_handle || !p_context || !p_path) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_lookupPath); /* test whether the path begins with a slash */ if(p_path->path[0] != '/') Return(ERR_FSAL_INVAL, 0, INDEX_FSAL_lookupPath); /* directly call the lookup function */ status = fsal_internal_Path2Handle(p_context, p_path, object_handle); if(FSAL_IS_ERROR(status)) ReturnStatus(status, INDEX_FSAL_lookupPath); /* get object attributes */ if(p_object_attributes) { status = XFSFSAL_getattrs(object_handle, p_context, p_object_attributes); if(FSAL_IS_ERROR(status)) { FSAL_CLEAR_MASK(p_object_attributes->asked_attributes); FSAL_SET_MASK(p_object_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); } } Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_lookupPath); }
/** * 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); }
/** * 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_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_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 XFSFSAL_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; int fd; struct stat buffstat; uid_t userid = ((xfsfsal_op_context_t *)p_context)->credential.user; gid_t groupid = ((xfsfsal_op_context_t *)p_context)->credential.group; /* 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(((xfsfsal_handle_t *)p_filehandle)->data.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_RDWR); ReleaseTokenFSCall(); if(FSAL_IS_ERROR(status)) 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((userid != 0) && (userid != buffstat.st_uid)) { LogFullDebug(COMPONENT_FSAL, "Permission denied for CHMOD opeartion: current owner=%d, credential=%d", buffstat.st_uid, userid); 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((userid != 0) && ((userid != buffstat.st_uid) || (userid != attrs.owner))) { LogFullDebug(COMPONENT_FSAL, "Permission denied for CHOWN opeartion: current owner=%d, credential=%d, new owner=%d", buffstat.st_uid, userid, 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((userid != 0) && (userid != buffstat.st_uid)) { close(fd); Return(ERR_FSAL_PERM, 0, INDEX_FSAL_setattrs); } int in_grp = 0; /* set in_grp */ if(groupid == attrs.group) in_grp = 1; else for(i = 0; i < ((xfsfsal_op_context_t *)p_context)->credential.nbgroups; i++) { if((in_grp = (attrs.group == ((xfsfsal_op_context_t *)p_context)->credential.alt_groups[i]))) break; } /* it must also be in target group */ if(userid != 0 && !in_grp) { LogFullDebug(COMPONENT_FSAL, "Permission denied for CHOWN operation: current group=%d, credential=%d, new group=%d", buffstat.st_gid, groupid, 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(inode=%"PRIu64", %d,%d)", buffstat.st_ino, 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) && (userid != 0) && (userid != buffstat.st_uid) && ((status = fsal_internal_testAccess(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) && (userid != 0) && (userid != buffstat.st_uid) && ((status = fsal_internal_testAccess(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 = XFSFSAL_getattrs(p_filehandle, p_context, p_object_attributes); /* on error, we set a special bit in the mask. */ if(FSAL_IS_ERROR(status)) { close(fd); 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_status_t XFSFSAL_readdir(fsal_dir_t * dir_descriptor, /* IN */ fsal_cookie_t startposition, /* IN */ fsal_attrib_mask_t get_attr_mask, /* IN */ fsal_mdsize_t buffersize, /* IN */ fsal_dirent_t * p_pdirent, /* OUT */ fsal_cookie_t * end_position, /* OUT */ fsal_count_t * p_nb_entries, /* OUT */ fsal_boolean_t * p_end_of_dir /* OUT */ ) { xfsfsal_dir_t * p_dir_descriptor = (xfsfsal_dir_t * ) dir_descriptor; xfsfsal_cookie_t start_position; xfsfsal_cookie_t * p_end_position = (xfsfsal_cookie_t *) end_position; fsal_status_t st; fsal_count_t max_dir_entries; char buff[BUF_SIZE]; struct linux_dirent *dp = NULL; int bpos = 0; int tmpfd = 0; char d_type; struct stat buffstat; int errsv = 0, rc = 0; memset(buff, 0, BUF_SIZE); /*****************/ /* sanity checks */ /*****************/ if(!p_dir_descriptor || !p_pdirent || !p_end_position || !p_nb_entries || !p_end_of_dir) Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_readdir); max_dir_entries = (buffersize / sizeof(fsal_dirent_t)); /***************************/ /* seek into the directory */ /***************************/ start_position.data.cookie = (off_t) startposition.data; errno = 0; if(start_position.data.cookie == 0) { //rewinddir(p_dir_descriptor->p_dir); rc = errno; } else { //seekdir(p_dir_descriptor->p_dir, start_position.cookie); rc = errno; } if(rc) Return(posix2fsal_error(rc), rc, INDEX_FSAL_readdir); /************************/ /* browse the directory */ /************************/ *p_nb_entries = 0; while(*p_nb_entries < max_dir_entries) { /***********************/ /* read the next entry */ /***********************/ TakeTokenFSCall(); rc = syscall(SYS_getdents, p_dir_descriptor->fd, buff, BUF_SIZE); ReleaseTokenFSCall(); if(rc < 0) { rc = errno; Return(posix2fsal_error(rc), rc, INDEX_FSAL_readdir); } /* End of directory */ if(rc == 0) { *p_end_of_dir = 1; break; } /***********************************/ /* Get information about the entry */ /***********************************/ for(bpos = 0; bpos < rc;) { dp = (struct linux_dirent *)(buff + bpos); d_type = *(buff + bpos + dp->d_reclen - 1); /** @todo not used for the moment. Waiting for information on symlink management */ bpos += dp->d_reclen; /* LogFullDebug(COMPONENT_FSAL, "\tino=%8ld|%8lx off=%d|%x reclen=%d|%x name=%s|%d", dp->d_ino, dp->d_ino, (int)dp->d_off, (int)dp->d_off, dp->d_reclen, dp->d_reclen, dp->d_name, (int)dp->d_name[0] ) ; */ if(!(*p_nb_entries < max_dir_entries)) break; /* skip . and .. */ if(!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue; /* build the full path of the file into "fsalpath */ if(FSAL_IS_ERROR (st = FSAL_str2name(dp->d_name, FSAL_MAX_NAME_LEN, &(p_pdirent[*p_nb_entries].name)))) ReturnStatus(st, INDEX_FSAL_readdir); d_type = DT_UNKNOWN; if((tmpfd = openat(p_dir_descriptor->fd, dp->d_name, O_RDONLY | O_NOFOLLOW, 0600)) < 0) { if(errno != ELOOP) /* ( p_dir_descriptor->fd, dp->d_name) is not a symlink */ Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_readdir); else d_type = DT_LNK; } /* get object handle */ TakeTokenFSCall(); if(d_type != DT_LNK) { st = fsal_internal_fd2handle((fsal_op_context_t *)&(p_dir_descriptor->context), tmpfd, &(p_pdirent[*p_nb_entries].handle)); close(tmpfd); } else { if(fstatat(p_dir_descriptor->fd, dp->d_name, &buffstat, AT_SYMLINK_NOFOLLOW) < 0) { ReleaseTokenFSCall(); Return(posix2fsal_error(errno), errno, INDEX_FSAL_readdir); } st = fsal_internal_inum2handle(&p_dir_descriptor->context, buffstat.st_ino, &(p_pdirent[*p_nb_entries].handle)); if(FSAL_IS_ERROR(st)) { ReleaseTokenFSCall(); ReturnStatus(st, INDEX_FSAL_readdir); } p_pdirent[*p_nb_entries].attributes.asked_attributes = get_attr_mask; st = posix2fsal_attributes(&buffstat, &p_pdirent[*p_nb_entries].attributes); if(FSAL_IS_ERROR(st)) { ReleaseTokenFSCall(); FSAL_CLEAR_MASK(p_pdirent[*p_nb_entries].attributes.asked_attributes); FSAL_SET_MASK(p_pdirent[*p_nb_entries].attributes.asked_attributes, FSAL_ATTR_RDATTR_ERR); ReturnStatus(st, INDEX_FSAL_getattrs); } } ReleaseTokenFSCall(); if(FSAL_IS_ERROR(st)) ReturnStatus(st, INDEX_FSAL_readdir); /************************ * Fills the attributes * ************************/ if(d_type != DT_LNK) { p_pdirent[*p_nb_entries].attributes.asked_attributes = get_attr_mask; st = XFSFSAL_getattrs((xfsfsal_handle_t *) (&(p_pdirent[*p_nb_entries].handle)), (xfsfsal_op_context_t *) & p_dir_descriptor->context, &p_pdirent[*p_nb_entries].attributes); if(FSAL_IS_ERROR(st)) { FSAL_CLEAR_MASK(p_pdirent[*p_nb_entries].attributes.asked_attributes); FSAL_SET_MASK(p_pdirent[*p_nb_entries].attributes.asked_attributes, FSAL_ATTR_RDATTR_ERR); } } //p_pdirent[*p_nb_entries].cookie.cookie = dp->d_off; ((xfsfsal_cookie_t *) (&p_pdirent[*p_nb_entries].cookie))->data.cookie = dp->d_off; p_pdirent[*p_nb_entries].nextentry = NULL; if(*p_nb_entries) p_pdirent[*p_nb_entries - 1].nextentry = &(p_pdirent[*p_nb_entries]); //(*p_end_position) = p_pdirent[*p_nb_entries].cookie; memcpy((char *)p_end_position, (char *)&p_pdirent[*p_nb_entries].cookie, sizeof(xfsfsal_cookie_t)); (*p_nb_entries)++; } /* for */ } /* While */ Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_readdir); }