From ab0c4a02ba9d1a836f62a8601699c971b72eec07 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Mon, 16 Sep 2019 15:50:46 +0200 Subject: Add directory reader data structure This moves a lot of the stuff that is done manually in the tree deserializer to a generic helper in libsquashfs. Due to how the fstree is implemented, as a work around, the inode needs to be temporarily stored in the tree node, but some of the directory details could be removed. Signed-off-by: David Oberhollenzer --- include/sqfs/dir.h | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/sqfs/error.h | 4 ++ include/sqfs/predef.h | 1 + 3 files changed, 164 insertions(+) (limited to 'include/sqfs') diff --git a/include/sqfs/dir.h b/include/sqfs/dir.h index 18950df..d8603d7 100644 --- a/include/sqfs/dir.h +++ b/include/sqfs/dir.h @@ -59,6 +59,29 @@ * writer used for inodes. */ +/** + * @struct sqfs_dir_reader_t + * + * @brief Abstracts reading of directory entries + * + * SquashFS stores directory listings and inode structures seperated from + * each other in meta data blocks. + * + * The sqfs_dir_reader_t abstracts access to the filesystem tree in a SquashFS + * through a fairly simple interface. It keeps two meta data readers internally + * for reading directory listings and inodes. Externally, it offers a few + * simple functions for iterating over the contents of a directory that + * completely take care of fetching/decoding headers and sifting through the + * multi level hierarchie used for storing them on disk. + * + * See @ref sqfs_dir_writer_t for an overview on how directory entries are + * stored in SquashFS. + * + * The reader also abstracts easy access to the underlying inodes, allowing + * direct access to the inode referred to by a directory entry. + */ + + #define SQFS_MAX_DIR_ENT 256 /** @@ -341,6 +364,142 @@ SQFS_API sqfs_inode_generic_t *sqfs_dir_writer_create_inode(const sqfs_dir_writer_t *writer, size_t hlinks, uint32_t xattr, uint32_t parent_ino); +/** + * @brief Create a directory reader. + * + * @memberof sqfs_dir_reader_t + * + * @param super A pointer to the super block. Kept internally an used for + * resolving table positions. + * @param cmp A compressor to use for unpacking meta data blocks. + * @param file The input file to read from. + * + * @return A new directory reader on success, NULL on allocation failure. + */ +SQFS_API sqfs_dir_reader_t *sqfs_dir_reader_create(const sqfs_super_t *super, + sqfs_compressor_t *cmp, + sqfs_file_t *file); + +/** + * @brief Cleanup a directory reader and free all its memory. + * + * @memberof sqfs_dir_reader_t + */ +SQFS_API void sqfs_dir_reader_destroy(sqfs_dir_reader_t *rd); + +/** + * @brief Navigate a directory reader to the location of a directory + * represented by an inode. + * + * @memberof sqfs_dir_reader_t + * + * This function seeks to the meta data block containing the directory + * listing that the given inode referes to and resets the internal state. + * After that, consequtive cals to @ref sqfs_dir_reader_read can be made + * to iterate over the directory contents. + * + * @param rd A pointer to a directory reader. + * @param inode An directory or extended directory inode. + * + * @return Zero on success, an @ref E_SQFS_ERROR value on failure. + */ +SQFS_API int sqfs_dir_reader_open_dir(sqfs_dir_reader_t *rd, + const sqfs_inode_generic_t *inode); + +/** + * @brief Reset a directory reader back to the beginning of the listing. + * + * @memberof sqfs_dir_reader_t + * + * @param rd A pointer to a directory reader. + * + * @return Zero on success, an @ref E_SQFS_ERROR value on failure. + */ +SQFS_API int sqfs_dir_reader_rewind(sqfs_dir_reader_t *rd); + +/** + * @brief Seek through the current directory listing to locate an + * entry by name. + * + * @memberof sqfs_dir_reader_t + * + * @param rd A pointer to a directory reader. + * @param name The name of the entry to find. + * + * @return Zero on success, an @ref E_SQFS_ERROR value on failure. + */ +SQFS_API int sqfs_dir_reader_find(sqfs_dir_reader_t *rd, const char *name); + +/** + * @brief Read a directory entry and advance the internal position indicator + * to the next one. + * + * @memberof sqfs_dir_reader_t + * + * Call this function repeatedly to iterate over a directory listing. It + * returns a positive number to indicate that it couldn't fetch any more data + * because the end of the listing was reached. A negative value indicates an + * error. + * + * After calling this function, you can use @ref sqfs_dir_reader_get_inode to + * read the full inode structure that the current entry referes to. + * + * @param rd A pointer to a directory reader. + * @param out Returns a pointer to a directory entry on success that can be + * freed with a single free call. + * + * @return Zero on success, an @ref E_SQFS_ERROR value on failure, a positive + * number if the end of the current directory listing has been reached. + */ +SQFS_API int sqfs_dir_reader_read(sqfs_dir_reader_t *rd, + sqfs_dir_entry_t **out); + +/** + * @brief Read the inode that the current directory entry points to. + * + * @memberof sqfs_dir_reader_t + * + * @param rd A pointer to a directory reader. + * @param out Returns a pointer to a generic inode that can be freed with a + * single free call. + * + * @return Zero on success, an @ref E_SQFS_ERROR value on failure. + */ +SQFS_API int sqfs_dir_reader_get_inode(sqfs_dir_reader_t *rd, + sqfs_inode_generic_t **inode); + +/** + * @brief Read the root inode using the location given by the super block. + * + * @memberof sqfs_dir_reader_t + * + * @param rd A pointer to a directory reader. + * @param out Returns a pointer to a generic inode that can be freed with a + * single free call. + * + * @return Zero on success, an @ref E_SQFS_ERROR value on failure. + */ +SQFS_API int sqfs_dir_reader_get_root_inode(sqfs_dir_reader_t *rd, + sqfs_inode_generic_t **inode); + +/** + * @brief Find an inode through path traversal from the root node downwards. + * + * @memberof sqfs_dir_reader_t + * + * @param rd A pointer to a directory reader. + * @param path A path to resolve into an inode. Forward or backward slashes can + * be used to seperate path components. Resolving '.' or '..' is + * not supported. + * @param out Returns a pointer to a generic inode that can be freed with a + * single free call. + * + * @return Zero on success, an @ref E_SQFS_ERROR value on failure. + */ +SQFS_API int sqfs_dir_reader_find_by_path(sqfs_dir_reader_t *rd, + const char *path, + sqfs_inode_generic_t **out); + #ifdef __cplusplus } #endif diff --git a/include/sqfs/error.h b/include/sqfs/error.h index a9a0acf..ddfeadd 100644 --- a/include/sqfs/error.h +++ b/include/sqfs/error.h @@ -103,6 +103,10 @@ typedef enum { * legal range (4k to 1M). */ SQFS_ERROR_SUPER_BLOCK_SIZE = -11, + + SQFS_ERROR_NOT_DIR = -12, + + SQFS_ERROR_NO_ENTRY = -13, } E_SQFS_ERROR; #endif /* SQFS_ERROR_H */ diff --git a/include/sqfs/predef.h b/include/sqfs/predef.h index 95d907f..4041a57 100644 --- a/include/sqfs/predef.h +++ b/include/sqfs/predef.h @@ -63,6 +63,7 @@ typedef struct sqfs_block_processor_t sqfs_block_processor_t; typedef struct sqfs_compressor_config_t sqfs_compressor_config_t; typedef struct sqfs_compressor_t sqfs_compressor_t; typedef struct sqfs_dir_writer_t sqfs_dir_writer_t; +typedef struct sqfs_dir_reader_t sqfs_dir_reader_t; typedef struct sqfs_id_table_t sqfs_id_table_t; typedef struct sqfs_meta_reader_t sqfs_meta_reader_t; typedef struct sqfs_meta_writer_t sqfs_meta_writer_t; -- cgit v1.2.3