diff options
Diffstat (limited to 'unpack')
| -rw-r--r-- | unpack/Makemodule.am | 2 | ||||
| -rw-r--r-- | unpack/read_fstree.c | 138 | ||||
| -rw-r--r-- | unpack/unsquashfs.c | 10 | ||||
| -rw-r--r-- | unpack/unsquashfs.h | 3 | 
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 */  | 
