diff options
-rw-r--r-- | include/sqfs/inode.h | 18 | ||||
-rw-r--r-- | lib/sqfs/inode.c | 49 |
2 files changed, 67 insertions, 0 deletions
diff --git a/include/sqfs/inode.h b/include/sqfs/inode.h index 336a394..2b4a550 100644 --- a/include/sqfs/inode.h +++ b/include/sqfs/inode.h @@ -537,6 +537,24 @@ extern "C" { #endif /** + * @brief Create a deep copy of a generic inode. + * + * The @ref sqfs_inode_generic_t structure contains inlined fields that have a + * size depending on the inode data and pointers to the inlined fields. This + * helper function calculates the actual size of the structure in memory, makes + * a copy and propperly sets up the pointers. + * + * @param src The inode to copy. + * @param copy Returns a pointer to the copy on success. Can be released with a + * single free call. + * + * @return Zero on success, an @ref SQFS_ERROR_CORRUPTED if the node has + * an unknown type set. + */ +SQFS_API int sqfs_inode_copy(const sqfs_inode_generic_t *src, + sqfs_inode_generic_t **copy); + +/** * @brief Get the extended attribute index of an inode * * For basic inodes, this returns the inode index 0xFFFFFFFF, i.e. the diff --git a/lib/sqfs/inode.c b/lib/sqfs/inode.c index 4a75e64..bb1ccef 100644 --- a/lib/sqfs/inode.c +++ b/lib/sqfs/inode.c @@ -10,6 +10,9 @@ #include "sqfs/inode.h" #include "sqfs/error.h" +#include <string.h> +#include <stdlib.h> + static int inverse_type[] = { [SQFS_INODE_DIR] = SQFS_INODE_EXT_DIR, [SQFS_INODE_FILE] = SQFS_INODE_EXT_FILE, @@ -27,6 +30,52 @@ static int inverse_type[] = { [SQFS_INODE_EXT_SOCKET] = SQFS_INODE_SOCKET, }; +int sqfs_inode_copy(const sqfs_inode_generic_t *src, + sqfs_inode_generic_t **out) +{ + sqfs_inode_generic_t *copy; + size_t size = sizeof(*src); + + switch (src->base.type) { + case SQFS_INODE_FILE: + case SQFS_INODE_EXT_FILE: + size += src->num_file_blocks; + break; + case SQFS_INODE_DIR: + case SQFS_INODE_EXT_DIR: + size += src->num_dir_idx_bytes; + break; + case SQFS_INODE_SLINK: + size += src->data.slink.target_size; + break; + case SQFS_INODE_EXT_SLINK: + size += src->data.slink_ext.target_size; + break; + case SQFS_INODE_BDEV: + case SQFS_INODE_CDEV: + case SQFS_INODE_FIFO: + case SQFS_INODE_SOCKET: + case SQFS_INODE_EXT_BDEV: + case SQFS_INODE_EXT_CDEV: + case SQFS_INODE_EXT_FIFO: + case SQFS_INODE_EXT_SOCKET: + break; + default: + return SQFS_ERROR_CORRUPTED; + } + + copy = calloc(1, size); + if (copy == NULL) + return SQFS_ERROR_ALLOC; + + memcpy(copy, src, size); + copy->block_sizes = (sqfs_u32 *)copy->extra; + copy->slink_target = (char *)copy->extra; + + *out = copy; + return 0; +} + int sqfs_inode_get_xattr_index(const sqfs_inode_generic_t *inode, sqfs_u32 *out) { |