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 --- difftool/compare_files.c | 13 +- include/sqfs/inode.h | 134 ++++++++++++++++++ lib/sqfs/Makemodule.am | 1 + lib/sqfs/data_reader.c | 38 +---- lib/sqfs/inode.c | 290 ++++++++++++++++++++++++++++++++++++++ lib/sqfshelper/data_reader_dump.c | 6 +- tar/sqfs2tar.c | 22 +-- unpack/dump_xattrs.c | 22 +-- unpack/fill_files.c | 73 +++------- unpack/list_files.c | 11 +- unpack/restore_fstree.c | 22 +-- 11 files changed, 465 insertions(+), 167 deletions(-) create mode 100644 lib/sqfs/inode.c diff --git a/difftool/compare_files.c b/difftool/compare_files.c index a977d95..aa11f43 100644 --- a/difftool/compare_files.c +++ b/difftool/compare_files.c @@ -33,17 +33,8 @@ int compare_files(sqfsdiff_t *sd, const sqfs_inode_generic_t *old, uint64_t offset, diff, oldsz, newsz; int status = 0, ret; - if (old->base.type == SQFS_INODE_EXT_FILE) { - oldsz = old->data.file_ext.file_size; - } else { - oldsz = old->data.file.file_size; - } - - if (new->base.type == SQFS_INODE_EXT_FILE) { - newsz = new->data.file_ext.file_size; - } else { - newsz = new->data.file.file_size; - } + sqfs_inode_get_file_size(old, &oldsz); + sqfs_inode_get_file_size(new, &newsz); if (oldsz != newsz) goto out_different; diff --git a/include/sqfs/inode.h b/include/sqfs/inode.h index 0019360..a65215b 100644 --- a/include/sqfs/inode.h +++ b/include/sqfs/inode.h @@ -452,4 +452,138 @@ struct sqfs_inode_generic_t { uint8_t extra[]; }; +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Get the extended attribute index of an inode + * + * For basic inodes, this returns the inode index 0xFFFFFFFF, i.e. the + * sentinel value indicating that there are no xattrs. + * + * @param inode A pointer to an inode. + * @param out Returns the extended attribute index on success. + * + * @return Zero on success, an @ref SQFS_ERROR_CORRUPTED if the node has + * an unknown type set. + */ +SQFS_API int sqfs_inode_get_xattr_index(const sqfs_inode_generic_t *inode, + uint32_t *out); + +/** + * @brief Convert a basic inode to an extended inode. + * + * For inodes that already have an extended type, this is a no-op. + * + * @param inode A pointer to an inode. + * + * @return Zero on success, an @ref SQFS_ERROR_CORRUPTED if the node has + * an unknown type set. + */ +SQFS_API int sqfs_inode_make_extended(sqfs_inode_generic_t *inode); + +/** + * @brief Convert an extended inode to a basic inode if possible. + * + * For inodes that already have a basic type, this is a no-op. If the inode + * has values set that the coresponding basic type doesn't support (e.g. it + * has an xattr index set or a regular file which requires 64 bit size + * counter), it is left as an extended type and success state is returned. + * + * @param inode A pointer to an inode. + * + * @return Zero on success, an @ref SQFS_ERROR_CORRUPTED if the node has + * an unknown type set. + */ +SQFS_API int sqfs_inode_make_basic(sqfs_inode_generic_t *inode); + +/** + * @brief Update the file size of a regular file inode. + * + * If the new size is wider than 32 bit, a basic file inode is transparently + * promoted to an extended file inode. For extended inodes, if the new size + * is small enough and was the only requirement for the extended type, the + * node is transparently demoted to a basic file inode. + * + * @param inode A pointer to an inode. + * @param size The new size to set. + * + * @return Zero on success, @ref SQFS_ERROR_NOT_FILE if the node is + * not a regular file. + */ +SQFS_API int sqfs_inode_set_file_size(sqfs_inode_generic_t *inode, + uint64_t size); + +/** + * @brief Update the location of the first data block of a regular file inode. + * + * If the new location is wider than 32 bit, a basic file inode is + * transparently promoted to an extended file inode. For extended inodes, + * if the new size is small enough and was the only requirement for the + * extended type, the node is transparently demoted to a basic file inode. + * + * @param inode A pointer to an inode. + * @param location The new location to set. + * + * @return Zero on success, @ref SQFS_ERROR_NOT_FILE if the node is + * not a regular file. + */ +SQFS_API int sqfs_inode_set_file_block_start(sqfs_inode_generic_t *inode, + uint64_t location); + +/** + * @brief Update the file fragment location of a regular file inode. + * + * @param inode A pointer to an inode. + * @param index The new fragment index to set. + * @param offset The new fragment offset to set. + * + * @return Zero on success, @ref SQFS_ERROR_NOT_FILE if the node is + * not a regular file. + */ +SQFS_API int sqfs_inode_set_frag_location(sqfs_inode_generic_t *inode, + uint32_t index, uint32_t offset); + +/** + * @brief Get the file size of a regular file inode. + * + * @param inode A pointer to an inode. + * @param size Returns the file size. + * + * @return Zero on success, @ref SQFS_ERROR_NOT_FILE if the node is + * not a regular file. + */ +SQFS_API int sqfs_inode_get_file_size(const sqfs_inode_generic_t *inode, + uint64_t *size); + +/** + * @brief Get the file fragment location of a regular file inode. + * + * @param inode A pointer to an inode. + * @param index Returns the fragment index. + * @param offset Returns the fragment offset. + * + * @return Zero on success, @ref SQFS_ERROR_NOT_FILE if the node is + * not a regular file. + */ +SQFS_API int sqfs_inode_get_frag_location(const sqfs_inode_generic_t *inode, + uint32_t *index, uint32_t *offset); + +/** + * @brief Get the location of the first data block of a regular file inode. + * + * @param inode A pointer to an inode. + * @param location Returns the location. + * + * @return Zero on success, @ref SQFS_ERROR_NOT_FILE if the node is + * not a regular file. + */ +SQFS_API int sqfs_inode_get_file_block_start(const sqfs_inode_generic_t *inode, + uint64_t *location); + +#ifdef __cplusplus +} +#endif + #endif /* SQFS_INODE_H */ 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; diff --git a/tar/sqfs2tar.c b/tar/sqfs2tar.c index 0bacd0e..1afbedf 100644 --- a/tar/sqfs2tar.c +++ b/tar/sqfs2tar.c @@ -195,27 +195,7 @@ static int get_xattrs(const sqfs_inode_generic_t *inode, tar_xattr_t **out) if (xr == NULL) return 0; - switch (inode->base.type) { - case SQFS_INODE_EXT_DIR: - index = inode->data.dir_ext.xattr_idx; - break; - case SQFS_INODE_EXT_FILE: - index = inode->data.file_ext.xattr_idx; - break; - case SQFS_INODE_EXT_SLINK: - index = inode->data.slink_ext.xattr_idx; - break; - case SQFS_INODE_EXT_BDEV: - case SQFS_INODE_EXT_CDEV: - index = inode->data.dev_ext.xattr_idx; - break; - case SQFS_INODE_EXT_FIFO: - case SQFS_INODE_EXT_SOCKET: - index = inode->data.ipc_ext.xattr_idx; - break; - default: - return 0; - } + sqfs_inode_get_xattr_index(inode, &index); if (index == 0xFFFFFFFF) return 0; diff --git a/unpack/dump_xattrs.c b/unpack/dump_xattrs.c index c619767..13bddfe 100644 --- a/unpack/dump_xattrs.c +++ b/unpack/dump_xattrs.c @@ -17,27 +17,7 @@ int dump_xattrs(sqfs_xattr_reader_t *xattr, const sqfs_inode_generic_t *inode) if (xattr == NULL) return 0; - switch (inode->base.type) { - case SQFS_INODE_EXT_DIR: - index = inode->data.dir_ext.xattr_idx; - break; - case SQFS_INODE_EXT_FILE: - index = inode->data.file_ext.xattr_idx; - break; - case SQFS_INODE_EXT_SLINK: - index = inode->data.slink_ext.xattr_idx; - break; - case SQFS_INODE_EXT_BDEV: - case SQFS_INODE_EXT_CDEV: - index = inode->data.dev_ext.xattr_idx; - break; - case SQFS_INODE_EXT_FIFO: - case SQFS_INODE_EXT_SOCKET: - index = inode->data.ipc_ext.xattr_idx; - break; - default: - return 0; - } + sqfs_inode_get_xattr_index(inode, &index); if (index == 0xFFFFFFFF) return 0; diff --git a/unpack/fill_files.c b/unpack/fill_files.c index 2c20ab0..3d1e7b2 100644 --- a/unpack/fill_files.c +++ b/unpack/fill_files.c @@ -15,80 +15,51 @@ static struct file_ent { static size_t num_files = 0, max_files = 0; static size_t block_size = 0; -static uint32_t get_frag_idx(const sqfs_inode_generic_t *inode) -{ - if (inode->base.type == SQFS_INODE_EXT_FILE) - return inode->data.file_ext.fragment_idx; - - return inode->data.file.fragment_index; -} - -static uint32_t get_frag_off(const sqfs_inode_generic_t *inode) -{ - if (inode->base.type == SQFS_INODE_EXT_FILE) - return inode->data.file_ext.fragment_offset; - - return inode->data.file.fragment_offset; -} - -static uint64_t get_size(const sqfs_inode_generic_t *inode) -{ - if (inode->base.type == SQFS_INODE_EXT_FILE) - return inode->data.file_ext.file_size; - - return inode->data.file.file_size; -} - -static uint64_t get_start(const sqfs_inode_generic_t *inode) -{ - if (inode->base.type == SQFS_INODE_EXT_FILE) - return inode->data.file_ext.blocks_start; - - return inode->data.file.blocks_start; -} - -static bool has_fragment(const struct file_ent *ent) -{ - if (get_size(ent->inode) % block_size == 0) - return false; - - return get_frag_off(ent->inode) < block_size && - (get_frag_idx(ent->inode) != 0xFFFFFFFF); -} - static int compare_files(const void *l, const void *r) { + uint32_t lhs_frag_idx, lhs_frag_off, rhs_frag_idx, rhs_frag_off; + uint64_t lhs_size, rhs_size, lhs_start, rhs_start; const struct file_ent *lhs = l, *rhs = r; + sqfs_inode_get_frag_location(lhs->inode, &lhs_frag_idx, &lhs_frag_off); + sqfs_inode_get_file_block_start(lhs->inode, &lhs_start); + sqfs_inode_get_file_size(lhs->inode, &lhs_size); + + sqfs_inode_get_frag_location(rhs->inode, &rhs_frag_idx, &rhs_frag_off); + sqfs_inode_get_file_block_start(rhs->inode, &rhs_start); + sqfs_inode_get_file_size(rhs->inode, &rhs_size); + /* Files with fragments come first, ordered by ID. In case of tie, files without data blocks come first, and the others are ordered by start block. */ - if (has_fragment(lhs)) { - if (!(has_fragment(rhs))) + if ((lhs_size % block_size) && (lhs_frag_off < block_size) && + (lhs_frag_idx != 0xFFFFFFFF)) { + if ((rhs_size % block_size) && (rhs_frag_off < block_size) && + (rhs_frag_idx != 0xFFFFFFFF)) return -1; - if (get_frag_idx(lhs->inode) < get_frag_idx(rhs->inode)) + if (lhs_frag_idx < rhs_frag_idx) return -1; - if (get_frag_idx(lhs->inode) > get_frag_idx(rhs->inode)) + if (lhs_frag_idx > rhs_frag_idx) return 1; - if (get_size(lhs->inode) < block_size) - return (get_size(rhs->inode) < block_size) ? 0 : -1; + if (lhs_size < block_size) + return (rhs_size < block_size) ? 0 : -1; - if (get_size(rhs->inode) < block_size) + if (rhs_size < block_size) return 1; goto order_by_start; } - if (has_fragment(rhs)) + if ((rhs_size % block_size) && (rhs_frag_off < block_size) && + (rhs_frag_idx != 0xFFFFFFFF)) return 1; /* order the rest by start block */ order_by_start: - return get_start(lhs->inode) < get_start(rhs->inode) ? -1 : - get_start(lhs->inode) > get_start(rhs->inode) ? 1 : 0; + return lhs_start < rhs_start ? -1 : lhs_start > rhs_start ? 1 : 0; } static int add_file(const sqfs_tree_node_t *node) diff --git a/unpack/list_files.c b/unpack/list_files.c index 11e18cb..ae259bd 100644 --- a/unpack/list_files.c +++ b/unpack/list_files.c @@ -87,13 +87,12 @@ static void print_node_size(const sqfs_tree_node_t *n, char *buffer) case S_IFLNK: print_size(strlen(n->inode->slink_target), buffer); break; - case S_IFREG: - if (n->inode->base.type == SQFS_INODE_EXT_FILE) { - print_size(n->inode->data.file_ext.file_size, buffer); - } else { - print_size(n->inode->data.file.file_size, buffer); - } + case S_IFREG: { + uint64_t size; + sqfs_inode_get_file_size(n->inode, &size); + print_size(size, buffer); break; + } case S_IFDIR: if (n->inode->base.type == SQFS_INODE_EXT_DIR) { print_size(n->inode->data.dir_ext.size, buffer); diff --git a/unpack/restore_fstree.c b/unpack/restore_fstree.c index afa4abb..5b82de4 100644 --- a/unpack/restore_fstree.c +++ b/unpack/restore_fstree.c @@ -101,27 +101,7 @@ static int set_xattr(sqfs_xattr_reader_t *xattr, const sqfs_tree_node_t *n) size_t i; int ret; - switch (n->inode->base.type) { - case SQFS_INODE_EXT_DIR: - index = n->inode->data.dir_ext.xattr_idx; - break; - case SQFS_INODE_EXT_FILE: - index = n->inode->data.file_ext.xattr_idx; - break; - case SQFS_INODE_EXT_SLINK: - index = n->inode->data.slink_ext.xattr_idx; - break; - case SQFS_INODE_EXT_BDEV: - case SQFS_INODE_EXT_CDEV: - index = n->inode->data.dev_ext.xattr_idx; - break; - case SQFS_INODE_EXT_FIFO: - case SQFS_INODE_EXT_SOCKET: - index = n->inode->data.ipc_ext.xattr_idx; - break; - default: - return 0; - } + sqfs_inode_get_xattr_index(n->inode, &index); if (index == 0xFFFFFFFF) return 0; -- cgit v1.2.3