/* * Copyright (c) 2023 Antmicro * * SPDX-License-Identifier: Apache-2.0 */ #ifndef __EXT2_IMPL_H__ #define __EXT2_IMPL_H__ #include #include #include "ext2_struct.h" extern struct k_heap direntry_heap; void error_behavior(struct ext2_data *fs, const char *msg); /* Memory allocation for ext2 implementation */ void *ext2_heap_alloc(size_t size); void ext2_heap_free(void *ptr); /* Initialization of disk storage. */ int ext2_init_disk_access_backend(struct ext2_data *fs, const void *storage_dev, int flags); /** * @brief Get block from the disk. */ struct ext2_block *ext2_get_block(struct ext2_data *fs, uint32_t block); struct ext2_block *ext2_get_empty_block(struct ext2_data *fs); /** * @brief Free the block structure. */ void ext2_drop_block(struct ext2_block *b); /** * @brief Write block to the disk. * * NOTICE: to ensure that all writes has ended the sync of disk must be triggered * (fs::sync function). */ int ext2_write_block(struct ext2_data *fs, struct ext2_block *b); void ext2_init_blocks_slab(struct ext2_data *fs); /** * @brief Write block to the disk. * * NOTICE: to ensure that all writes has ended the sync of disk must be triggered * (fs::sync function). */ int ext2_write_block(struct ext2_data *fs, struct ext2_block *b); int ext2_assign_block_num(struct ext2_data *fs, struct ext2_block *b); /* FS operations */ /** * @brief Initialize structure with data needed to access the storage device * * @param fs File system data structure to initialize * @param storage_dev Pointer to storage * @param flags Additional flags (e.g. RO flag) * * @retval 0 on success * @retval -EINVAL when superblock of ext2 was not detected * @retval -ENOTSUP when described file system is not supported * @retval <0 other error */ int ext2_init_storage(struct ext2_data **fsp, const void *storage_dev, int flags); /** * @brief Verify superblock of file system * * Checks if file system is supported by the implementation. * @retval 0 when superblock is valid * @retval -EROFS when superblock is not valid but file system may be mounted read only * @retval -EINVAL when superblock is not valid and file system cannot be mounted at all * @retval -ENOTSUP when superblock has some field set to value that we don't support */ int ext2_verify_disk_superblock(struct ext2_disk_superblock *sb); /** * @brief Initialize all data needed to perform operations on file system * * Fetches the superblock. Initializes structure fields. */ int ext2_init_fs(struct ext2_data *fs); /** * @brief Clear the data used by file system implementation * */ int ext2_close_fs(struct ext2_data *fs); /** * @brief Clear the data used to communicate with storage device * */ int ext2_close_struct(struct ext2_data *fs); /** * @brief Create the ext2 file system * * This function uses functions stored in `ext2_data` structure to create new * file system on storage device. * * NOTICE: fs structure must be first initialized with `ext2_init_fs` function. * * After this function succeeds the `ext2_clean` function must be called. * * @param fs File system data (must be initialized before) * * @retval 0 on success * @retval -ENOSPC when storage device is too small for ext2 file system * @retval -ENOTSUP when storage device is too big (file systems with more than * 8192 blocks are not supported) */ int ext2_format(struct ext2_data *fs, struct ext2_cfg *cfg); /* Lookup flags */ #define LOOKUP_ARG_OPEN BIT(0) #define LOOKUP_ARG_CREATE BIT(1) #define LOOKUP_ARG_STAT BIT(2) #define LOOKUP_ARG_UNLINK BIT(3) /* Structure for lookup arguments and results. * * Required fields (must be filled when lookup function is invoked): * - path * - flags * * Fields that hold the result: * - inode * - parent * - offset * - name_pos * - name_len * * Some of these fields have a meaning only for a specific function. * (E.g. during stat only the fields parent and offset are used) * * Field is marked with these labels when lookup is used from other function: * OP -- open * CR -- create * ST -- stat * UN -- unlink */ struct ext2_lookup_args { const char *path; /* path of inode */ struct ext2_inode *inode; /* (OP, CR, ST, UN) found inode */ struct ext2_inode *parent; /* (CR, ST, UN) parent of found inode */ uint32_t offset; /* (CR, ST, UN) offset of entry in directory */ uint32_t name_pos; /* (CR) position of name in input path */ uint32_t name_len; /* (CR) length of name */ uint8_t flags; /* indicates from which function lookup is invoked */ }; /** * @brief Look for an inode. * * @param fs File system data * @param args All needed arguments for lookup * * @retval 0 on success * @retval -ENOENT inode or path component not found * @retval -ENOTDIR path component not a directory * @retval <0 other error */ int ext2_lookup_inode(struct ext2_data *fs, struct ext2_lookup_args *args); /* Inode operations */ /** * @brief Read from inode at given offset * * @param inode Inode * @param buf Buffer to hold read data * @param offset Offset in inode * @param nbytes Number of bytes to read * * @retval >=0 number of bytes read on success * @retval <0 error code */ ssize_t ext2_inode_read(struct ext2_inode *inode, void *buf, uint32_t offset, size_t nbytes); /** * @brief Write to inode at given offset * * @param inode Inode * @param buf Buffer with data to write * @param offset Offset in inode * @param nbytes Number of bytes to write * * @retval >=0 number of bytes read on success * @retval <0 error code */ ssize_t ext2_inode_write(struct ext2_inode *inode, const void *buf, uint32_t offset, size_t nbytes); /** * @brief Truncate the inode * * @param inode Inode * @param size New size for inode * * @retval 0 on success * @retval -ENOTSUP when requested size is too big * @retval <0 other error */ int ext2_inode_trunc(struct ext2_inode *inode, off_t size); /** * @brief Sync currently fetched blocks * * @param inode Inode * */ int ext2_inode_sync(struct ext2_inode *inode); /* Directory operations */ /** * @brief Get directory entry * * Reads directory entry that is at offset specified in `ext2_file` structure. * * @param dir Read directory * @param ent Directory entry to fill in * * @retval 0 on success * @retval <0 on error */ int ext2_get_direntry(struct ext2_file *dir, struct fs_dirent *ent); /** * @brief Create a directory entry with given attributes * * Automatically calculates and sets de_rec_len field. * * NOTE: if you need to adjust the size (e.g. when this entry is the last one in the block) * then just update the size after this function returns. * * @param name Name of direntry * @param namelen Length of name * @param ino Inode associated with that entry * @param filetype File type of that entry * * @returns structure allocated on direntry_heap filled with given data */ struct ext2_direntry *ext2_create_direntry(const char *name, uint8_t namelen, uint32_t ino, uint8_t filetype); /** * @brief Create a file * * @param parent Parent directory * @param inode Pointer to inode structure that will be filled with new inode * @param args Lookup arguments that describe file to create * * @retval 0 on success * @retval -ENOSPC there is not enough memory on storage device to create a file * @retval <0 on error */ int ext2_create_file(struct ext2_inode *parent, struct ext2_inode *inode, struct ext2_lookup_args *args); /** * @brief Create a directory * * @param parent Parent directory * @param inode Pointer to inode structure that will be filled with new inode * @param args Lookup arguments that describe directory to create * * @retval 0 on success * @retval -ENOSPC there is not enough memory on storage device to create a file * @retval <0 on error */ int ext2_create_dir(struct ext2_inode *parent, struct ext2_inode *inode, struct ext2_lookup_args *args); /** * @brief Unlink the directory entry at given offset in parent directory * * @param parent Parent directory * @param inode File to unlink * @param offset Offset of unlinked file in the parent directory * * @retval 0 on success * @retval -ENOTEMPTY when directory to unlink is not empty * @retval <0 other error */ int ext2_inode_unlink(struct ext2_inode *parent, struct ext2_inode *inode, uint32_t offset); /** * @brief Move a file * * Invoked when rename destination entry doesn't exist. * * @param args_from Describe source file * @param args_to Describe destination * * @retval 0 on success * @retval <0 on error */ int ext2_move_file(struct ext2_lookup_args *args_from, struct ext2_lookup_args *args_to); /** * @brief Replace the file with another * * Invoked when rename destination entry does exist * * @param args_from Describe source file * @param args_to Describe destination file * * @retval 0 on success * @retval <0 on error */ int ext2_replace_file(struct ext2_lookup_args *args_from, struct ext2_lookup_args *args_to); /* Inode pool operations */ /** * @brief Get the inode * * Retrieves inode structure and stores it in the inode pool. The inode is * filled with data of requested inode. * * @param fs File system data * @param ino Inode number * @param ret Pointer to place where to store new inode pointer * * @retval 0 on success * @retval -ENOMEM when there is no memory to hold the requested inode * @retval <0 on error */ int ext2_inode_get(struct ext2_data *fs, uint32_t ino, struct ext2_inode **ret); /** * @brief Remove reference to the inode structure * * When removed reference is the last reference to that inode then it is freed. * * @param inode Dropped inode * * @retval 0 on success * @retval -EINVAL the dropped inode is not stored in the inode pool * @retval <0 on error */ int ext2_inode_drop(struct ext2_inode *inode); /* Drop blocks fetched in inode structure. */ void ext2_inode_drop_blocks(struct ext2_inode *inode); /** * @brief Remove all blocks starting with some block * * @param first First block to remove * * @retval >=0 number of removed blocks * @retval <0 error code */ int64_t ext2_inode_remove_blocks(struct ext2_inode *inode, uint32_t first); #endif /* __EXT2_IMPL_H__ */