summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--difftool/compare_files.c13
-rw-r--r--include/sqfs/inode.h134
-rw-r--r--lib/sqfs/Makemodule.am1
-rw-r--r--lib/sqfs/data_reader.c38
-rw-r--r--lib/sqfs/inode.c290
-rw-r--r--lib/sqfshelper/data_reader_dump.c6
-rw-r--r--tar/sqfs2tar.c22
-rw-r--r--unpack/dump_xattrs.c22
-rw-r--r--unpack/fill_files.c73
-rw-r--r--unpack/list_files.c11
-rw-r--r--unpack/restore_fstree.c22
11 files changed, 465 insertions, 167 deletions
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 <goliath@infraroot.at>
+ */
+#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;