summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile.am1
-rw-r--r--include/squashfs.h2
-rw-r--r--lib/Makemodule.am1
-rw-r--r--lib/sqfs/read_super.c84
-rw-r--r--unpack/Makemodule.am12
-rw-r--r--unpack/unsquashfs.c65
7 files changed, 166 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index d10a7fe..944a414 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,3 +19,4 @@ config.h
*.a
*~
mksquashfs
+unsquashfs
diff --git a/Makefile.am b/Makefile.am
index 1b8284b..7fc95c3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -10,3 +10,4 @@ EXTRA_DIST = autogen.sh LICENSE
include lib/Makemodule.am
include mkfs/Makemodule.am
+include unpack/Makemodule.am
diff --git a/include/squashfs.h b/include/squashfs.h
index 30c7d3d..a690aad 100644
--- a/include/squashfs.h
+++ b/include/squashfs.h
@@ -184,4 +184,6 @@ int sqfs_super_init(sqfs_super_t *super, size_t block_size, uint32_t mtime,
int sqfs_super_write(sqfs_super_t *super, int fd);
+int sqfs_super_read(sqfs_super_t *super, int fd);
+
#endif /* SQUASHFS_H */
diff --git a/lib/Makemodule.am b/lib/Makemodule.am
index c2d7dab..026e3f1 100644
--- a/lib/Makemodule.am
+++ b/lib/Makemodule.am
@@ -11,6 +11,7 @@ libsquashfs_a_SOURCES = include/meta_writer.h include/squashfs.h
libsquashfs_a_SOURCES += lib/sqfs/meta_writer.c lib/sqfs/super.c
libsquashfs_a_SOURCES += lib/sqfs/id_table.c include/id_table.h
libsquashfs_a_SOURCES += lib/sqfs/table.c include/table.h
+libsquashfs_a_SOURCES += lib/sqfs/read_super.c
libutil_a_SOURCES = lib/util/canonicalize_name.c lib/util/write_retry.c
libutil_a_SOURCES += lib/util/read_retry.c include/util.h
diff --git a/lib/sqfs/read_super.c b/lib/sqfs/read_super.c
new file mode 100644
index 0000000..22dd822
--- /dev/null
+++ b/lib/sqfs/read_super.c
@@ -0,0 +1,84 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+#include "squashfs.h"
+#include "util.h"
+
+#include <endian.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+
+int sqfs_super_read(sqfs_super_t *super, int fd)
+{
+ sqfs_super_t temp;
+ size_t block_size;
+ ssize_t ret;
+ int i;
+
+ if (lseek(fd, 0, SEEK_SET) == (off_t)-1)
+ goto fail_seek;
+
+ ret = read_retry(fd, &temp, sizeof(temp));
+
+ if (ret < 0) {
+ perror("reading super block");
+ return -1;
+ }
+
+ if ((size_t)ret < sizeof(temp)) {
+ fputs("reading super block: unexpected end of file\n", stderr);
+ return -1;
+ }
+
+ temp.magic = le32toh(temp.magic);
+ temp.inode_count = le32toh(temp.inode_count);
+ temp.modification_time = le32toh(temp.modification_time);
+ temp.block_size = le32toh(temp.block_size);
+ temp.fragment_entry_count = le32toh(temp.fragment_entry_count);
+ temp.compression_id = le16toh(temp.compression_id);
+ temp.block_log = le16toh(temp.block_log);
+ temp.flags = le16toh(temp.flags);
+ temp.id_count = le16toh(temp.id_count);
+ temp.version_major = le16toh(temp.version_major);
+ temp.version_minor = le16toh(temp.version_minor);
+ temp.root_inode_ref = le64toh(temp.root_inode_ref);
+ temp.bytes_used = le64toh(temp.bytes_used);
+ temp.id_table_start = le64toh(temp.id_table_start);
+ temp.xattr_id_table_start = le64toh(temp.xattr_id_table_start);
+ temp.inode_table_start = le64toh(temp.inode_table_start);
+ temp.directory_table_start = le64toh(temp.directory_table_start);
+ temp.fragment_table_start = le64toh(temp.fragment_table_start);
+ temp.export_table_start = le64toh(temp.export_table_start);
+
+ if (temp.magic != SQFS_MAGIC) {
+ fputs("Magic number missing. Not a squashfs image.\n", stderr);
+ return -1;
+ }
+
+ if ((temp.block_size - 1) & temp.block_size) {
+ fputs("Block size in image is not a power of 2!\n", stderr);
+ return -1;
+ }
+
+ block_size = 1;
+
+ for (i = 0; i < temp.block_log; ++i)
+ block_size <<= 1;
+
+ if (temp.block_size != block_size) {
+ fputs("Mismatch between block size and block log\n", stderr);
+ fputs("Filesystem probably currupted.\n", stderr);
+ return -1;
+ }
+
+ if (temp.compression_id < SQFS_COMP_MIN ||
+ temp.compression_id > SQFS_COMP_MAX) {
+ fputs("Image uses an unsupported compressor\n", stderr);
+ return -1;
+ }
+
+ memcpy(super, &temp, sizeof(temp));
+ return 0;
+fail_seek:
+ perror("squashfs writing super block: seek on output file");
+ return -1;
+}
diff --git a/unpack/Makemodule.am b/unpack/Makemodule.am
new file mode 100644
index 0000000..190803e
--- /dev/null
+++ b/unpack/Makemodule.am
@@ -0,0 +1,12 @@
+unsquashfs_SOURCES = unpack/unsquashfs.c
+unsquashfs_LDADD = libsquashfs.a libfstree.a libcompress.a libutil.a
+
+if WITH_LZMA
+unsquashfs_LDADD += $(XZ_LIBS)
+endif
+
+if WITH_ZLIB
+unsquashfs_LDADD += $(ZLIB_LIBS)
+endif
+
+bin_PROGRAMS += unsquashfs
diff --git a/unpack/unsquashfs.c b/unpack/unsquashfs.c
new file mode 100644
index 0000000..4606366
--- /dev/null
+++ b/unpack/unsquashfs.c
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+#include "squashfs.h"
+#include "compress.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+extern const char *__progname;
+
+int main(int argc, char **argv)
+{
+ int fd, status = EXIT_FAILURE;
+ sqfs_super_t super;
+ compressor_t *cmp;
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s <filename>\n", __progname);
+ return EXIT_FAILURE;
+ }
+
+ fd = open(argv[1], O_RDONLY);
+ if (fd < 0) {
+ perror(argv[1]);
+ return EXIT_FAILURE;
+ }
+
+ if (sqfs_super_read(&super, fd))
+ goto out;
+
+ if ((super.version_major != SQFS_VERSION_MAJOR) ||
+ (super.version_minor != SQFS_VERSION_MINOR)) {
+ fprintf(stderr,
+ "The image uses squashfs version %d.%d\n"
+ "We currently only supports version %d.%d (sorry).\n",
+ super.version_major, super.version_minor,
+ SQFS_VERSION_MAJOR, SQFS_VERSION_MINOR);
+ goto out;
+ }
+
+ if (super.flags & SQFS_FLAG_COMPRESSOR_OPTIONS) {
+ fputs("Image has been built with compressor options.\n"
+ "This is not yet supported.\n",
+ stderr);
+ goto out;
+ }
+
+ if (!compressor_exists(super.compression_id)) {
+ fputs("Image uses a compressor that has not been built in\n",
+ stderr);
+ goto out;
+ }
+
+ cmp = compressor_create(super.compression_id, false, super.block_size);
+ if (cmp == NULL)
+ goto out;
+
+ status = EXIT_SUCCESS;
+
+ cmp->destroy(cmp);
+out:
+ close(fd);
+ return status;
+}