From d6149732b67fbedc7ac2d2ba984c07ab466392f1 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Wed, 7 Aug 2019 11:09:34 +0200 Subject: 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 --- difftool/Makemodule.am | 7 +++ difftool/compare_files_sqfs.c | 45 ++++++++++++++++ difftool/difftool.h | 4 ++ difftool/sqfsdiff.c | 121 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 177 insertions(+) create mode 100644 difftool/compare_files_sqfs.c create mode 100644 difftool/sqfsdiff.c (limited to 'difftool') 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 + */ +#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 + */ +#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...] \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; +} -- cgit v1.2.3