summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-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
4 files changed, 299 insertions, 36 deletions
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;