From 57b6a4c855120bc721cd4e76cca32c7b1a382407 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Sun, 22 Sep 2019 01:48:50 +0200 Subject: Add helper functions for working with inodes Signed-off-by: David Oberhollenzer --- lib/sqfs/Makemodule.am | 1 + lib/sqfs/data_reader.c | 38 +---- lib/sqfs/inode.c | 290 ++++++++++++++++++++++++++++++++++++++ lib/sqfshelper/data_reader_dump.c | 6 +- 4 files changed, 299 insertions(+), 36 deletions(-) create mode 100644 lib/sqfs/inode.c (limited to 'lib') diff --git a/lib/sqfs/Makemodule.am b/lib/sqfs/Makemodule.am index 16a07e9..44b5531 100644 --- a/lib/sqfs/Makemodule.am +++ b/lib/sqfs/Makemodule.am @@ -17,6 +17,7 @@ libsquashfs_la_SOURCES += lib/sqfs/dir_writer.c lib/sqfs/xattr_reader.c libsquashfs_la_SOURCES += lib/sqfs/read_table.c lib/sqfs/comp/compressor.c libsquashfs_la_SOURCES += lib/sqfs/io_stdin.c lib/sqfs/comp/internal.h libsquashfs_la_SOURCES += lib/sqfs/dir_reader.c lib/sqfs/read_tree.c +libsquashfs_la_SOURCES += lib/sqfs/inode.c libsquashfs_la_SOURCES += lib/sqfs/blk_proc/process_block.c lib/sqfs/io.c libsquashfs_la_SOURCES += lib/sqfs/blk_proc/internal.h lib/sqfs/data_reader.c libsquashfs_la_CPPFLAGS = $(AM_CPPFLAGS) diff --git a/lib/sqfs/data_reader.c b/lib/sqfs/data_reader.c index 3de59ff..2603cfe 100644 --- a/lib/sqfs/data_reader.c +++ b/lib/sqfs/data_reader.c @@ -209,15 +209,8 @@ int sqfs_data_reader_get_block(sqfs_data_reader_t *data, size_t i, unpacked_size; uint64_t off, filesz; - if (inode->base.type == SQFS_INODE_FILE) { - off = inode->data.file.blocks_start; - filesz = inode->data.file.file_size; - } else if (inode->base.type == SQFS_INODE_EXT_FILE) { - off = inode->data.file_ext.blocks_start; - filesz = inode->data.file_ext.file_size; - } else { - return SQFS_ERROR_NOT_FILE; - } + sqfs_inode_get_file_block_start(inode, &off); + sqfs_inode_get_file_size(inode, &filesz); if (index >= inode->num_file_blocks) return SQFS_ERROR_OUT_OF_BOUNDS; @@ -241,17 +234,8 @@ int sqfs_data_reader_get_fragment(sqfs_data_reader_t *data, sqfs_block_t *blk; uint64_t filesz; - if (inode->base.type == SQFS_INODE_EXT_FILE) { - filesz = inode->data.file_ext.file_size; - frag_idx = inode->data.file_ext.fragment_idx; - frag_off = inode->data.file_ext.fragment_offset; - } else if (inode->base.type == SQFS_INODE_FILE) { - filesz = inode->data.file.file_size; - frag_idx = inode->data.file.fragment_index; - frag_off = inode->data.file.fragment_offset; - } else { - return -1; - } + sqfs_inode_get_file_size(inode, &filesz); + sqfs_inode_get_frag_location(inode, &frag_idx, &frag_off); if (inode->num_file_blocks * data->block_size >= filesz) { *out = NULL; @@ -287,17 +271,9 @@ ssize_t sqfs_data_reader_read(sqfs_data_reader_t *data, char *ptr; /* work out file location and size */ - if (inode->base.type == SQFS_INODE_EXT_FILE) { - off = inode->data.file_ext.blocks_start; - filesz = inode->data.file_ext.file_size; - frag_idx = inode->data.file_ext.fragment_idx; - frag_off = inode->data.file_ext.fragment_offset; - } else { - off = inode->data.file.blocks_start; - filesz = inode->data.file.file_size; - frag_idx = inode->data.file.fragment_index; - frag_off = inode->data.file.fragment_offset; - } + sqfs_inode_get_file_size(inode, &filesz); + sqfs_inode_get_frag_location(inode, &frag_idx, &frag_off); + sqfs_inode_get_file_block_start(inode, &off); /* find location of the first block */ i = 0; diff --git a/lib/sqfs/inode.c b/lib/sqfs/inode.c new file mode 100644 index 0000000..d6c013c --- /dev/null +++ b/lib/sqfs/inode.c @@ -0,0 +1,290 @@ +/* SPDX-License-Identifier: LGPL-3.0-or-later */ +/* + * inode.c + * + * Copyright (C) 2019 David Oberhollenzer + */ +#define SQFS_BUILDING_DLL +#include "config.h" + +#include "sqfs/inode.h" +#include "sqfs/error.h" + +static int inverse_type[] = { + [SQFS_INODE_DIR] = SQFS_INODE_EXT_DIR, + [SQFS_INODE_FILE] = SQFS_INODE_EXT_FILE, + [SQFS_INODE_SLINK] = SQFS_INODE_EXT_SLINK, + [SQFS_INODE_BDEV] = SQFS_INODE_EXT_BDEV, + [SQFS_INODE_CDEV] = SQFS_INODE_EXT_CDEV, + [SQFS_INODE_FIFO] = SQFS_INODE_EXT_FIFO, + [SQFS_INODE_SOCKET] = SQFS_INODE_EXT_SOCKET, + [SQFS_INODE_EXT_DIR] = SQFS_INODE_DIR, + [SQFS_INODE_EXT_FILE] = SQFS_INODE_FILE, + [SQFS_INODE_EXT_SLINK] = SQFS_INODE_SLINK, + [SQFS_INODE_EXT_BDEV] = SQFS_INODE_BDEV, + [SQFS_INODE_EXT_CDEV] = SQFS_INODE_CDEV, + [SQFS_INODE_EXT_FIFO] = SQFS_INODE_FIFO, + [SQFS_INODE_EXT_SOCKET] = SQFS_INODE_SOCKET, +}; + +int sqfs_inode_get_xattr_index(const sqfs_inode_generic_t *inode, + uint32_t *out) +{ + switch (inode->base.type) { + case SQFS_INODE_DIR: + case SQFS_INODE_FILE: + case SQFS_INODE_SLINK: + case SQFS_INODE_BDEV: + case SQFS_INODE_CDEV: + case SQFS_INODE_FIFO: + case SQFS_INODE_SOCKET: + *out = 0xFFFFFFFF; + break; + case SQFS_INODE_EXT_DIR: + *out = inode->data.dir_ext.xattr_idx; + break; + case SQFS_INODE_EXT_FILE: + *out = inode->data.file_ext.xattr_idx; + break; + case SQFS_INODE_EXT_SLINK: + *out = inode->data.slink_ext.xattr_idx; + break; + case SQFS_INODE_EXT_BDEV: + case SQFS_INODE_EXT_CDEV: + *out = inode->data.dev_ext.xattr_idx; + break; + case SQFS_INODE_EXT_FIFO: + case SQFS_INODE_EXT_SOCKET: + *out = inode->data.ipc_ext.xattr_idx; + break; + default: + return SQFS_ERROR_CORRUPTED; + } + + return 0; +} + +int sqfs_inode_make_extended(sqfs_inode_generic_t *inode) +{ + switch (inode->base.type) { + case SQFS_INODE_DIR: { + sqfs_inode_dir_ext_t temp = { + .nlink = inode->data.dir.nlink, + .size = inode->data.dir.size, + .start_block = inode->data.dir.start_block, + .parent_inode = inode->data.dir.parent_inode, + .inodex_count = 0, + .offset = inode->data.dir.offset, + .xattr_idx = 0xFFFFFFFF, + }; + inode->data.dir_ext = temp; + break; + } + case SQFS_INODE_FILE: { + sqfs_inode_file_ext_t temp = { + .blocks_start = inode->data.file.blocks_start, + .file_size = inode->data.file.file_size, + .sparse = 0, + .nlink = 1, + .fragment_idx = inode->data.file.fragment_index, + .fragment_offset = inode->data.file.fragment_offset, + .xattr_idx = 0xFFFFFFFF, + }; + inode->data.file_ext = temp; + break; + } + case SQFS_INODE_SLINK: + inode->data.slink_ext.xattr_idx = 0xFFFFFFFF; + break; + case SQFS_INODE_BDEV: + case SQFS_INODE_CDEV: + inode->data.dev_ext.xattr_idx = 0xFFFFFFFF; + break; + case SQFS_INODE_FIFO: + case SQFS_INODE_SOCKET: + inode->data.dev_ext.xattr_idx = 0xFFFFFFFF; + break; + case SQFS_INODE_EXT_DIR: + case SQFS_INODE_EXT_FILE: + case SQFS_INODE_EXT_SLINK: + case SQFS_INODE_EXT_BDEV: + case SQFS_INODE_EXT_CDEV: + case SQFS_INODE_EXT_FIFO: + case SQFS_INODE_EXT_SOCKET: + return 0; + default: + return SQFS_ERROR_CORRUPTED; + } + + inode->base.type = inverse_type[inode->base.type]; + return 0; +} + +int sqfs_inode_make_basic(sqfs_inode_generic_t *inode) +{ + uint32_t xattr; + int err; + + err = sqfs_inode_get_xattr_index(inode, &xattr); + if (err != 0 || xattr != 0xFFFFFFFF) + return err; + + switch (inode->base.type) { + case SQFS_INODE_DIR: + case SQFS_INODE_FILE: + case SQFS_INODE_SLINK: + case SQFS_INODE_BDEV: + case SQFS_INODE_CDEV: + case SQFS_INODE_FIFO: + case SQFS_INODE_SOCKET: + return 0; + case SQFS_INODE_EXT_DIR: { + sqfs_inode_dir_t temp = { + .start_block = inode->data.dir_ext.start_block, + .nlink = inode->data.dir_ext.nlink, + .size = inode->data.dir_ext.size, + .offset = inode->data.dir_ext.offset, + .parent_inode = inode->data.dir_ext.parent_inode, + }; + + if (inode->data.dir_ext.size > 0x0FFFF) + return 0; + + inode->data.dir = temp; + break; + } + case SQFS_INODE_EXT_FILE: { + sqfs_inode_file_t temp = { + .blocks_start = inode->data.file_ext.blocks_start, + .fragment_index = inode->data.file_ext.fragment_idx, + .fragment_offset = inode->data.file_ext.fragment_offset, + .file_size = inode->data.file_ext.file_size, + }; + + if (inode->data.file_ext.blocks_start > 0x0FFFFFFFFUL) + return 0; + if (inode->data.file_ext.file_size > 0x0FFFFFFFFUL) + return 0; + if (inode->data.file_ext.sparse > 0) + return 0; + if (inode->data.file_ext.nlink > 1) + return 0; + + inode->data.file = temp; + break; + } + case SQFS_INODE_EXT_SLINK: + 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; + } + + inode->base.type = inverse_type[inode->base.type]; + return 0; +} + +int sqfs_inode_set_file_size(sqfs_inode_generic_t *inode, uint64_t size) +{ + if (inode->base.type == SQFS_INODE_EXT_FILE) { + inode->data.file_ext.file_size = size; + + if (size < 0x0FFFFFFFFUL) + sqfs_inode_make_basic(inode); + } else if (inode->base.type == SQFS_INODE_FILE) { + if (size > 0x0FFFFFFFFUL) { + sqfs_inode_make_extended(inode); + inode->data.file_ext.file_size = size; + } else { + inode->data.file.file_size = size; + } + } else { + return SQFS_ERROR_NOT_FILE; + } + + return 0; +} + +int sqfs_inode_set_frag_location(sqfs_inode_generic_t *inode, + uint32_t index, uint32_t offset) +{ + if (inode->base.type == SQFS_INODE_EXT_FILE) { + inode->data.file_ext.fragment_idx = index; + inode->data.file_ext.fragment_offset = offset; + } else if (inode->base.type == SQFS_INODE_FILE) { + inode->data.file.fragment_index = index; + inode->data.file.fragment_offset = offset; + } else { + return SQFS_ERROR_NOT_FILE; + } + + return 0; +} + +int sqfs_inode_set_file_block_start(sqfs_inode_generic_t *inode, + uint64_t location) +{ + if (inode->base.type == SQFS_INODE_EXT_FILE) { + inode->data.file_ext.blocks_start = location; + + if (location < 0x0FFFFFFFFUL) + sqfs_inode_make_basic(inode); + } else if (inode->base.type == SQFS_INODE_FILE) { + if (location > 0x0FFFFFFFFUL) { + sqfs_inode_make_extended(inode); + inode->data.file_ext.blocks_start = location; + } else { + inode->data.file.blocks_start = location; + } + } else { + return SQFS_ERROR_NOT_FILE; + } + + return 0; +} + +int sqfs_inode_get_file_size(const sqfs_inode_generic_t *inode, uint64_t *size) +{ + if (inode->base.type == SQFS_INODE_EXT_FILE) { + *size = inode->data.file_ext.file_size; + } else if (inode->base.type == SQFS_INODE_FILE) { + *size = inode->data.file.file_size; + } else { + return SQFS_ERROR_NOT_FILE; + } + + return 0; +} + +int sqfs_inode_get_frag_location(const sqfs_inode_generic_t *inode, + uint32_t *index, uint32_t *offset) +{ + if (inode->base.type == SQFS_INODE_EXT_FILE) { + *index = inode->data.file_ext.fragment_idx; + *offset = inode->data.file_ext.fragment_offset; + } else if (inode->base.type == SQFS_INODE_FILE) { + *index = inode->data.file.fragment_index; + *offset = inode->data.file.fragment_offset; + } else { + return SQFS_ERROR_NOT_FILE; + } + + return 0; +} + +int sqfs_inode_get_file_block_start(const sqfs_inode_generic_t *inode, + uint64_t *location) +{ + if (inode->base.type == SQFS_INODE_EXT_FILE) { + *location = inode->data.file_ext.blocks_start; + } else if (inode->base.type == SQFS_INODE_FILE) { + *location = inode->data.file.blocks_start; + } else { + return SQFS_ERROR_NOT_FILE; + } + + return 0; +} diff --git a/lib/sqfshelper/data_reader_dump.c b/lib/sqfshelper/data_reader_dump.c index e28bf20..a9b6bb9 100644 --- a/lib/sqfshelper/data_reader_dump.c +++ b/lib/sqfshelper/data_reader_dump.c @@ -25,11 +25,7 @@ int sqfs_data_reader_dump(sqfs_data_reader_t *data, size_t i, diff; int err; - if (inode->base.type == SQFS_INODE_EXT_FILE) { - filesz = inode->data.file_ext.file_size; - } else { - filesz = inode->data.file.file_size; - } + sqfs_inode_get_file_size(inode, &filesz); if (allow_sparse && ftruncate(outfd, filesz)) goto fail_sparse; -- cgit v1.2.3