|  | /* | 
|  | * Copyright (c) 2023 Antmicro <www.antmicro.com> | 
|  | * | 
|  | * SPDX-License-Identifier: Apache-2.0 | 
|  | */ | 
|  |  | 
|  | #ifndef __EXT2_IMPL_H__ | 
|  | #define __EXT2_IMPL_H__ | 
|  |  | 
|  | #include <zephyr/fs/fs.h> | 
|  | #include <zephyr/fs/ext2.h> | 
|  |  | 
|  | #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__ */ |