summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-08-07 11:09:34 +0200
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-08-07 11:24:20 +0200
commitd6149732b67fbedc7ac2d2ba984c07ab466392f1 (patch)
tree80e0fd22e6110fb1c5b977ac687479d9f7a9a21a
parent73b4ec8392541a27815bccbaeccbdf1cdd5e19dd (diff)
Extend filesystem diff utility to work on squashfs images
Since it already works on an fstree_t instance (constructed from the input paths), and we now have a handy sqfs_reader_t, it is quite simple to extend. Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
-rw-r--r--.gitignore1
-rw-r--r--difftool/Makemodule.am7
-rw-r--r--difftool/compare_files_sqfs.c45
-rw-r--r--difftool/difftool.h4
-rw-r--r--difftool/sqfsdiff.c121
5 files changed, 178 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index 2fecd17..83e68ac 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,6 +22,7 @@ gensquashfs
rdsquashfs
sqfs2tar
tar2sqfs
+sqfsdiff
test_*
test-*
fscompare
diff --git a/difftool/Makemodule.am b/difftool/Makemodule.am
index 4a03495..62c9197 100644
--- a/difftool/Makemodule.am
+++ b/difftool/Makemodule.am
@@ -3,4 +3,11 @@ fscompare_SOURCES += difftool/compare_dir.c difftool/node_compare.c
fscompare_SOURCES += difftool/compare_file.c
fscompare_LDADD = libfstree.a libutil.a
+sqfsdiff_SOURCES = difftool/sqfsdiff.c difftool/difftool.h difftool/util.c
+sqfsdiff_SOURCES += difftool/compare_dir.c difftool/node_compare.c
+sqfsdiff_SOURCES += difftool/compare_files_sqfs.c
+sqfsdiff_LDADD = libsquashfs.a libfstree.a libcompress.a libutil.a
+sqfsdiff_LDADD += $(XZ_LIBS) $(ZLIB_LIBS) $(LZO_LIBS) $(LZ4_LIBS) $(ZSTD_LIBS)
+
noinst_PROGRAMS += fscompare
+bin_PROGRAMS += sqfsdiff
diff --git a/difftool/compare_files_sqfs.c b/difftool/compare_files_sqfs.c
new file mode 100644
index 0000000..d8bef83
--- /dev/null
+++ b/difftool/compare_files_sqfs.c
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+/*
+ * compare_file_sfqs.c
+ *
+ * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
+ */
+#include "difftool.h"
+
+static unsigned char a_buf[MAX_WINDOW_SIZE];
+static unsigned char b_buf[MAX_WINDOW_SIZE];
+
+int compare_files(file_info_t *a, file_info_t *b, const char *path)
+{
+ uint64_t offset, diff;
+ ssize_t ret;
+
+ if (a->size != b->size)
+ return 1;
+
+ for (offset = 0; offset < a->size; offset += diff) {
+ diff = a->size - offset;
+
+ if (diff > MAX_WINDOW_SIZE)
+ diff = MAX_WINDOW_SIZE;
+
+ ret = data_reader_read(sqfs_a.data, a, offset, a_buf, diff);
+ if (ret < 0 || (size_t)ret < diff) {
+ fprintf(stderr, "Failed to read %s from %s\n",
+ path, first_path);
+ return -1;
+ }
+
+ ret = data_reader_read(sqfs_b.data, b, offset, b_buf, diff);
+ if (ret < 0 || (size_t)ret < diff) {
+ fprintf(stderr, "Failed to read %s from %s\n",
+ path, second_path);
+ return -1;
+ }
+
+ if (memcmp(a_buf, b_buf, diff) != 0)
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/difftool/difftool.h b/difftool/difftool.h
index 0dea6d5..f7739c4 100644
--- a/difftool/difftool.h
+++ b/difftool/difftool.h
@@ -8,6 +8,8 @@
#define DIFFTOOL_H
#include "config.h"
+
+#include "highlevel.h"
#include "fstree.h"
#include "util.h"
@@ -24,6 +26,8 @@
extern const char *first_path;
extern const char *second_path;
extern int compare_flags;
+extern sqfs_reader_t sqfs_a;
+extern sqfs_reader_t sqfs_b;
enum {
COMPARE_NO_PERM = 0x01,
diff --git a/difftool/sqfsdiff.c b/difftool/sqfsdiff.c
new file mode 100644
index 0000000..2fc10a1
--- /dev/null
+++ b/difftool/sqfsdiff.c
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+/*
+ * sqfsdiff.c
+ *
+ * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
+ */
+#include "difftool.h"
+
+static struct option long_opts[] = {
+ { "no-owner", no_argument, NULL, 'O' },
+ { "no-permissions", no_argument, NULL, 'P' },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'V' },
+};
+
+static const char *short_opts = "OPhV";
+
+static const char *usagestr =
+"Usage: sqfsdiff [OPTIONS...] <first> <second>\n"
+"\n"
+"Compare the contents of two squashfs images. In contrast to doing a direct\n"
+"diff of the images, this actually recovers the file system trees and\n"
+"recursively compares them against each other.\n"
+"\n"
+"Any differences in packed file layout, ordering, compression, inode\n"
+"allocation and so on is ignored, only the contents are compared.\n"
+"\n"
+"The two images are considered equal if each directory contains the same\n"
+"entries, symlink with the same paths have the same targets, device nodes\n"
+"the same device number and files the same size and contents.\n"
+"\n"
+"A report of any difference is printed to stdout. The exit status is similar\n"
+"that of diff(1): 0 means equal, 1 means different, 2 means problem.\n"
+"\n"
+"Possible options:\n"
+"\n"
+" --no-owner, -O Do not compare file owners.\n"
+" --no-permissions, -P Do not compare permission bits.\n"
+"\n"
+" --help, -h Print help text and exit.\n"
+" --version, -V Print version information and exit.\n"
+"\n";
+
+int compare_flags = 0;
+const char *first_path;
+const char *second_path;
+sqfs_reader_t sqfs_a;
+sqfs_reader_t sqfs_b;
+
+static void process_options(int argc, char **argv)
+{
+ int i;
+
+ for (;;) {
+ i = getopt_long(argc, argv, short_opts, long_opts, NULL);
+ if (i == -1)
+ break;
+
+ switch (i) {
+ case 'O':
+ compare_flags |= COMPARE_NO_OWNER;
+ break;
+ case 'P':
+ compare_flags |= COMPARE_NO_PERM;
+ break;
+ case 'h':
+ fputs(usagestr, stdout);
+ exit(EXIT_SUCCESS);
+ case 'V':
+ print_version();
+ exit(EXIT_SUCCESS);
+ default:
+ goto fail_arg;
+ }
+ }
+
+ if (optind >= argc) {
+ fputs("Missing arguments: first filesystem\n", stderr);
+ goto fail_arg;
+ }
+
+ first_path = argv[optind++];
+
+ if (optind >= argc) {
+ fputs("Missing arguments: second filesystem\n", stderr);
+ goto fail_arg;
+ }
+
+ second_path = argv[optind++];
+
+ if (optind < argc) {
+ fputs("Unknown extra arguments\n", stderr);
+ goto fail_arg;
+ }
+ return;
+fail_arg:
+ fprintf(stderr, "Try `sqfsdiff --help' for more information.\n");
+ exit(EXIT_FAILURE);
+}
+
+int main(int argc, char **argv)
+{
+ int ret = EXIT_FAILURE;
+
+ process_options(argc, argv);
+
+ if (sqfs_reader_open(&sqfs_a, first_path, 0))
+ return EXIT_FAILURE;
+
+ if (sqfs_reader_open(&sqfs_b, second_path, 0))
+ goto out_sqfs_a;
+
+ ret = node_compare(sqfs_a.fs.root, sqfs_b.fs.root);
+ if (ret < 0)
+ ret = 2;
+
+ sqfs_reader_close(&sqfs_b);
+out_sqfs_a:
+ sqfs_reader_close(&sqfs_a);
+ return ret;
+}