zephyr/subsys/fs/ext2/ext2_impl.h
Franciszek Zdobylak 1eb104795e fs: ext2: Use disk structs to access data on disk
This commits changes how data on the disk is accessed. There are disk
structures which are packed and their fields are stored in little endian
byte order. To use data in the program structures it has to be translated
from little endian to cpu endianness.

Signed-off-by: Franciszek Zdobylak <fzdobylak@antmicro.com>
2023-08-03 12:22:01 -04:00

371 lines
10 KiB
C

/*
* 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__ */