/* SPDX-License-Identifier: LGPL-3.0-or-later */ /* * dir_reader.h - This file is part of libsquashfs * * Copyright (C) 2019 David Oberhollenzer * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef SQFS_DIR_READER_H #define SQFS_DIR_READER_H #include "sqfs/predef.h" /** * @file dir_reader.h * * @brief Contains declarations for the @ref sqfs_dir_reader_t */ /** * @struct sqfs_dir_reader_t * * @implements sqfs_object_t * * @brief Abstracts reading of directory entries * * SquashFS stores directory listings and inode structures separated 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. */ /** * @enum SQFS_TREE_FILTER_FLAGS * * @brief Filter flags for @ref sqfs_dir_reader_get_full_hierarchy */ typedef enum { /** * @brief Omit device special files from the final tree. */ SQFS_TREE_NO_DEVICES = 0x01, /** * @brief Omit socket files from the final tree. */ SQFS_TREE_NO_SOCKETS = 0x02, /** * @brief Omit named pipes from the final tree. */ SQFS_TREE_NO_FIFO = 0x04, /** * @brief Omit symbolic links from the final tree. */ SQFS_TREE_NO_SLINKS = 0x08, /** * @brief Omit empty directories from the final tree. * * If a directory is not empty on-disk, but ends up empty after * applying all the other filter rules, it is also omitted. */ SQFS_TREE_NO_EMPTY = 0x10, /** * @brief Do not recurse into sub directories. * * If the start node is a directory, the tree deserializer will still * recurse into it, but it will not go beyond that. */ SQFS_TREE_NO_RECURSE = 0x20, /** * @brief Store the list of parent nodes all the way to the target node * * When traversing towards the selected node, also collect the chain * of parent nodes with the subtree stored at the end. */ SQFS_TREE_STORE_PARENTS = 0x40, SQFS_TREE_ALL_FLAGS = 0x7F, } SQFS_TREE_FILTER_FLAGS; /** * @struct sqfs_tree_node_t * * @brief Encapsulates a node in the filesystem tree read by * @ref sqfs_dir_reader_get_full_hierarchy. */ struct sqfs_tree_node_t { /** * @brief Pointer to parent, NULL for the root node */ sqfs_tree_node_t *parent; /** * @brief For directories, a linked list of children. */ sqfs_tree_node_t *children; /** * @brief Linked list next pointer for children list. */ sqfs_tree_node_t *next; /** * @brief Inode representing this element in the tree. */ sqfs_inode_generic_t *inode; /** * @brief Resolved 32 bit user ID from the inode */ sqfs_u32 uid; /** * @brief Resolved 32 bit group ID from the inode */ sqfs_u32 gid; /** * @brief null-terminated entry name. */ sqfs_u8 name[]; }; #ifdef __cplusplus extern "C" { #endif /** * @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. * @param flags Currently must be zero or the function fails. * * @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, sqfs_u32 flags); /** * @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. * @param flags Currently must be zero or the function fails. * * @return Zero on success, an @ref SQFS_ERROR value on failure. */ SQFS_API int sqfs_dir_reader_open_dir(sqfs_dir_reader_t *rd, const sqfs_inode_generic_t *inode, sqfs_u32 flags); /** * @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 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 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 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 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 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 starting from the root or a * given node downwards. * * @memberof sqfs_dir_reader_t * * @param rd A pointer to a directory reader. * @param start If not NULL, path traversal starts at this node downwards. If * set to NULL, start at the root node. * @param path A path to resolve into an inode. Forward or backward slashes can * be used to separate 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 SQFS_ERROR value on failure. */ SQFS_API int sqfs_dir_reader_find_by_path(sqfs_dir_reader_t *rd, const sqfs_inode_generic_t *start, const char *path, sqfs_inode_generic_t **out); /** * @brief High level helper function for deserializing the entire file system * hierarchy into an in-memory tree structure. * * @memberof sqfs_dir_reader_t * * This function internally navigates to a specified inode using * @ref sqfs_dir_reader_find_by_path and starting from that recursively * deserializes the entire hierarchy into a tree structure holding all inodes. * * @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 separate path components. Resolving '.' or '..' is * not supported. Can be set to NULL to get the root inode. * @param flags A combination of @ref SQFS_TREE_FILTER_FLAGS flags. * @param out Returns the top most tree node. * * @return Zero on success, an @ref SQFS_ERROR value on failure. */ SQFS_API int sqfs_dir_reader_get_full_hierarchy(sqfs_dir_reader_t *rd, const sqfs_id_table_t *idtbl, const char *path, sqfs_u32 flags, sqfs_tree_node_t **out); /** * @brief Recursively destroy a tree of @ref sqfs_tree_node_t nodes * * This function can be used to clean up after * @ref sqfs_dir_reader_get_full_hierarchy. * * @param root A pointer to the root node. */ SQFS_API void sqfs_dir_tree_destroy(sqfs_tree_node_t *root); #ifdef __cplusplus } #endif #endif /* SQFS_DIR_READER_H */