summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--unpack/Makemodule.am2
-rw-r--r--unpack/read_fstree.c138
-rw-r--r--unpack/unsquashfs.c10
-rw-r--r--unpack/unsquashfs.h3
4 files changed, 145 insertions, 8 deletions
diff --git a/unpack/Makemodule.am b/unpack/Makemodule.am
index e21fd0c..2a08295 100644
--- a/unpack/Makemodule.am
+++ b/unpack/Makemodule.am
@@ -1,5 +1,5 @@
unsquashfs_SOURCES = unpack/unsquashfs.c unpack/tree_node_from_inode.c
-unsquashfs_SOURCES += unpack/unsquashfs.h
+unsquashfs_SOURCES += unpack/unsquashfs.h unpack/read_fstree.c
unsquashfs_LDADD = libsquashfs.a libfstree.a libcompress.a libutil.a
if WITH_LZMA
diff --git a/unpack/read_fstree.c b/unpack/read_fstree.c
new file mode 100644
index 0000000..a6903b0
--- /dev/null
+++ b/unpack/read_fstree.c
@@ -0,0 +1,138 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+#include "unsquashfs.h"
+
+
+static int fill_dir(meta_reader_t *ir, meta_reader_t *dr, tree_node_t *root,
+ sqfs_super_t *super, id_table_t *idtbl)
+{
+ sqfs_inode_generic_t *inode;
+ sqfs_dir_header_t hdr;
+ sqfs_dir_entry_t *ent;
+ uint64_t block_start;
+ size_t size, diff;
+ tree_node_t *n;
+ uint32_t i;
+
+ block_start = root->data.dir->start_block;
+ block_start += super->directory_table_start;
+
+ if (meta_reader_seek(dr, block_start, root->data.dir->block_offset))
+ return -1;
+
+ size = root->data.dir->size;
+
+ while (size != 0) {
+ if (meta_reader_read_dir_header(dr, &hdr))
+ return -1;
+
+ size -= sizeof(hdr) > size ? size : sizeof(hdr);
+
+ for (i = 0; i <= hdr.count; ++i) {
+ ent = meta_reader_read_dir_ent(dr);
+ if (ent == NULL)
+ return -1;
+
+ diff = sizeof(*ent) + strlen((char *)ent->name);
+ size -= diff > size ? size : diff;
+
+ inode = meta_reader_read_inode(ir, super,
+ hdr.start_block,
+ ent->offset);
+ if (inode == NULL) {
+ free(ent);
+ return -1;
+ }
+
+ n = tree_node_from_inode(inode, idtbl,
+ (char *)ent->name,
+ super->block_size);
+ free(ent);
+ free(inode);
+
+ if (n == NULL)
+ return -1;
+
+ n->parent = root;
+ n->next = root->data.dir->children;
+ root->data.dir->children = n;
+ }
+ }
+
+ for (n = root->data.dir->children; n != NULL; n = n->next) {
+ if (S_ISDIR(n->mode)) {
+ if (fill_dir(ir, dr, n, super, idtbl))
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int read_fstree(fstree_t *out, int fd, sqfs_super_t *super, compressor_t *cmp)
+{
+ sqfs_inode_generic_t *root;
+ meta_reader_t *ir, *dr;
+ uint64_t block_start;
+ id_table_t idtbl;
+ int status = -1;
+ size_t offset;
+
+ ir = meta_reader_create(fd, cmp);
+ if (ir == NULL)
+ return -1;
+
+ dr = meta_reader_create(fd, cmp);
+ if (dr == NULL)
+ goto out_ir;
+
+ if (id_table_init(&idtbl))
+ goto out_dr;
+
+ if (id_table_read(&idtbl, fd, super, cmp))
+ goto out_id;
+
+ block_start = super->root_inode_ref >> 16;
+ offset = super->root_inode_ref & 0xFFFF;
+ root = meta_reader_read_inode(ir, super, block_start, offset);
+ if (root == NULL)
+ goto out_id;
+
+ if (root->base.type != SQFS_INODE_DIR &&
+ root->base.type != SQFS_INODE_EXT_DIR) {
+ free(root);
+ fputs("File system root inode is not a directory inode!\n",
+ stderr);
+ goto out_id;
+ }
+
+ memset(out, 0, sizeof(*out));
+ out->block_size = super->block_size;
+ out->default_uid = 0;
+ out->default_gid = 0;
+ out->default_mode = 0755;
+ out->default_mtime = super->modification_time;
+
+ out->root = tree_node_from_inode(root, &idtbl, "", super->block_size);
+ free(root);
+ root = NULL;
+
+ if (out->root == NULL)
+ goto out_id;
+
+ if (fill_dir(ir, dr, out->root, super, &idtbl))
+ goto fail_fs;
+
+ fstree_sort(out);
+
+ status = 0;
+out_id:
+ id_table_cleanup(&idtbl);
+out_dr:
+ meta_reader_destroy(dr);
+out_ir:
+ meta_reader_destroy(ir);
+ return status;
+fail_fs:
+ fstree_cleanup(out);
+ goto out_id;
+}
diff --git a/unpack/unsquashfs.c b/unpack/unsquashfs.c
index 1493081..d332dee 100644
--- a/unpack/unsquashfs.c
+++ b/unpack/unsquashfs.c
@@ -8,7 +8,7 @@ int main(int argc, char **argv)
int fd, status = EXIT_FAILURE;
sqfs_super_t super;
compressor_t *cmp;
- id_table_t idtbl;
+ fstree_t fs;
if (argc != 2) {
fprintf(stderr, "Usage: %s <filename>\n", __progname);
@@ -51,15 +51,11 @@ int main(int argc, char **argv)
if (cmp == NULL)
goto out;
- if (id_table_init(&idtbl))
+ if (read_fstree(&fs, fd, &super, cmp))
goto out_cmp;
- if (id_table_read(&idtbl, fd, &super, cmp))
- goto out_idtbl;
-
status = EXIT_SUCCESS;
-out_idtbl:
- id_table_cleanup(&idtbl);
+ fstree_cleanup(&fs);
out_cmp:
cmp->destroy(cmp);
out:
diff --git a/unpack/unsquashfs.h b/unpack/unsquashfs.h
index e50646d..5553012 100644
--- a/unpack/unsquashfs.h
+++ b/unpack/unsquashfs.h
@@ -2,6 +2,7 @@
#ifndef UNSQUASHFS_H
#define UNSQUASHFS_H
+#include "meta_reader.h"
#include "squashfs.h"
#include "compress.h"
#include "id_table.h"
@@ -18,4 +19,6 @@ tree_node_t *tree_node_from_inode(sqfs_inode_generic_t *inode,
const char *name,
size_t block_size);
+int read_fstree(fstree_t *out, int fd, sqfs_super_t *super, compressor_t *cmp);
+
#endif /* UNSQUASHFS_H */