diff options
-rw-r--r-- | unpack/Makemodule.am | 3 | ||||
-rw-r--r-- | unpack/tree_node_from_inode.c | 144 | ||||
-rw-r--r-- | unpack/unsquashfs.c | 9 | ||||
-rw-r--r-- | unpack/unsquashfs.h | 21 |
4 files changed, 168 insertions, 9 deletions
diff --git a/unpack/Makemodule.am b/unpack/Makemodule.am index 190803e..e21fd0c 100644 --- a/unpack/Makemodule.am +++ b/unpack/Makemodule.am @@ -1,4 +1,5 @@ -unsquashfs_SOURCES = unpack/unsquashfs.c +unsquashfs_SOURCES = unpack/unsquashfs.c unpack/tree_node_from_inode.c +unsquashfs_SOURCES += unpack/unsquashfs.h unsquashfs_LDADD = libsquashfs.a libfstree.a libcompress.a libutil.a if WITH_LZMA diff --git a/unpack/tree_node_from_inode.c b/unpack/tree_node_from_inode.c new file mode 100644 index 0000000..95056a7 --- /dev/null +++ b/unpack/tree_node_from_inode.c @@ -0,0 +1,144 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +#include "unsquashfs.h" + +static size_t compute_size(sqfs_inode_generic_t *inode, const char *name, + size_t block_size) +{ + size_t size = sizeof(tree_node_t) + strlen(name) + 1; + size_t block_count = 0; + + switch (inode->base.type) { + case SQFS_INODE_DIR: + case SQFS_INODE_EXT_DIR: + size += sizeof(dir_info_t); + break; + case SQFS_INODE_FILE: + size += sizeof(file_info_t); + block_count = inode->data.file.file_size / block_size; + break; + case SQFS_INODE_EXT_FILE: + size += sizeof(file_info_t); + block_count = inode->data.file_ext.file_size / block_size; + break; + case SQFS_INODE_SLINK: + case SQFS_INODE_EXT_SLINK: + size += strlen(inode->slink_target) + 1; + break; + default: + break; + } + + return size + block_count * sizeof(uint32_t); +} + +static void copy_block_sizes(sqfs_inode_generic_t *inode, tree_node_t *out, + size_t block_size) +{ + size_t block_count = out->data.file->size / block_size; + + out->name += block_count * sizeof(uint32_t); + + if (block_count) { + memcpy(out->data.file->blocksizes, inode->block_sizes, + block_count * sizeof(uint32_t)); + } +} + +tree_node_t *tree_node_from_inode(sqfs_inode_generic_t *inode, + const id_table_t *idtbl, + const char *name, + size_t block_size) +{ + tree_node_t *out; + + if (inode->base.uid_idx >= idtbl->num_ids) { + fputs("converting inode to fs tree node: UID out of range\n", + stderr); + return NULL; + } + + if (inode->base.gid_idx >= idtbl->num_ids) { + fputs("converting inode to fs tree node: GID out of range\n", + stderr); + return NULL; + } + + out = calloc(1, compute_size(inode, name, block_size)); + if (out == NULL) { + perror("converting inode to fs tree node"); + return NULL; + } + + out->uid = idtbl->ids[inode->base.uid_idx]; + out->gid = idtbl->ids[inode->base.gid_idx]; + out->mode = inode->base.mode; + out->type = inode->base.type; + out->inode_num = inode->base.inode_number; + out->name = (char *)out->payload; + + switch (inode->base.type) { + case SQFS_INODE_DIR: + out->data.dir = (dir_info_t *)out->payload; + out->name += sizeof(dir_info_t); + + out->data.dir->size = inode->data.dir.size; + out->data.dir->start_block = inode->data.dir.start_block; + out->data.dir->block_offset = inode->data.dir.offset; + break; + case SQFS_INODE_EXT_DIR: + out->data.dir = (dir_info_t *)out->payload; + out->name += sizeof(dir_info_t); + + out->data.dir->size = inode->data.dir_ext.size; + out->data.dir->start_block = inode->data.dir_ext.start_block; + out->data.dir->block_offset = inode->data.dir_ext.offset; + break; + case SQFS_INODE_FILE: + out->data.file = (file_info_t *)out->payload; + out->name += sizeof(file_info_t); + + out->data.file->size = inode->data.file.file_size; + out->data.file->startblock = inode->data.file.blocks_start; + out->data.file->fragment = inode->data.file.fragment_index; + out->data.file->fragment_offset = + inode->data.file.fragment_offset; + + copy_block_sizes(inode, out, block_size); + break; + case SQFS_INODE_EXT_FILE: + out->data.file = (file_info_t *)out->payload; + out->name += sizeof(file_info_t); + + out->data.file->size = inode->data.file_ext.file_size; + out->data.file->startblock = inode->data.file_ext.blocks_start; + out->data.file->fragment = inode->data.file_ext.fragment_idx; + out->data.file->fragment_offset = + inode->data.file_ext.fragment_offset; + + copy_block_sizes(inode, out, block_size); + break; + case SQFS_INODE_SLINK: + case SQFS_INODE_EXT_SLINK: + out->data.slink_target = (char *)out->payload; + strcpy(out->data.slink_target, inode->slink_target); + + out->name = (char *)out->payload + + strlen(inode->slink_target) + 1; + break; + case SQFS_INODE_BDEV: + case SQFS_INODE_CDEV: + out->name = (char *)out->payload; + out->data.devno = inode->data.dev.devno; + break; + case SQFS_INODE_EXT_BDEV: + case SQFS_INODE_EXT_CDEV: + out->name = (char *)out->payload; + out->data.devno = inode->data.dev_ext.devno; + break; + default: + break; + } + + strcpy(out->name, name); + return out; +} diff --git a/unpack/unsquashfs.c b/unpack/unsquashfs.c index f5c3a43..1493081 100644 --- a/unpack/unsquashfs.c +++ b/unpack/unsquashfs.c @@ -1,12 +1,5 @@ /* SPDX-License-Identifier: GPL-3.0-or-later */ -#include "squashfs.h" -#include "compress.h" -#include "id_table.h" - -#include <stdlib.h> -#include <unistd.h> -#include <stdio.h> -#include <fcntl.h> +#include "unsquashfs.h" extern const char *__progname; diff --git a/unpack/unsquashfs.h b/unpack/unsquashfs.h new file mode 100644 index 0000000..e50646d --- /dev/null +++ b/unpack/unsquashfs.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +#ifndef UNSQUASHFS_H +#define UNSQUASHFS_H + +#include "squashfs.h" +#include "compress.h" +#include "id_table.h" +#include "fstree.h" + +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> + +tree_node_t *tree_node_from_inode(sqfs_inode_generic_t *inode, + const id_table_t *idtbl, + const char *name, + size_t block_size); + +#endif /* UNSQUASHFS_H */ |