From 4ff2b4f689f4e530b6c6f3eed17a595f7ccf56fb Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Wed, 21 Aug 2019 14:04:43 +0200 Subject: Isolate sqfsdiff global state and split off option processing Signed-off-by: David Oberhollenzer --- difftool/Makemodule.am | 2 +- difftool/compare_files.c | 33 +++++----- difftool/extract.c | 11 ++-- difftool/node_compare.c | 14 ++-- difftool/options.c | 130 +++++++++++++++++++++++++++++++++++++ difftool/sqfsdiff.c | 162 +++++------------------------------------------ difftool/sqfsdiff.h | 28 +++++--- 7 files changed, 195 insertions(+), 185 deletions(-) create mode 100644 difftool/options.c (limited to 'difftool') diff --git a/difftool/Makemodule.am b/difftool/Makemodule.am index e687cb0..9b6e713 100644 --- a/difftool/Makemodule.am +++ b/difftool/Makemodule.am @@ -1,7 +1,7 @@ sqfsdiff_SOURCES = difftool/sqfsdiff.c difftool/sqfsdiff.h difftool/util.c sqfsdiff_SOURCES += difftool/compare_dir.c difftool/node_compare.c sqfsdiff_SOURCES += difftool/compare_files.c difftool/super.c -sqfsdiff_SOURCES += difftool/extract.c +sqfsdiff_SOURCES += difftool/extract.c difftool/options.c sqfsdiff_LDADD = libsquashfs.a libfstree.a libcompress.a libutil.a sqfsdiff_LDADD += $(XZ_LIBS) $(ZLIB_LIBS) $(LZO_LIBS) $(LZ4_LIBS) $(ZSTD_LIBS) diff --git a/difftool/compare_files.c b/difftool/compare_files.c index 46e170b..605df84 100644 --- a/difftool/compare_files.c +++ b/difftool/compare_files.c @@ -9,10 +9,11 @@ static unsigned char old_buf[MAX_WINDOW_SIZE]; static unsigned char new_buf[MAX_WINDOW_SIZE]; -int compare_files(file_info_t *old, file_info_t *new, const char *path) +int compare_files(sqfsdiff_t *sd, file_info_t *old, file_info_t *new, + const char *path) { - char new_name[strlen(new_path) + strlen(path) + 2]; - char old_name[strlen(old_path) + strlen(path) + 2]; + char new_name[strlen(sd->new_path) + strlen(path) + 2]; + char old_name[strlen(sd->old_path) + strlen(path) + 2]; int old_fd = -1, new_fd = -1, status = 0; uint64_t offset, diff; ssize_t ret; @@ -20,11 +21,11 @@ int compare_files(file_info_t *old, file_info_t *new, const char *path) if (old->size != new->size) goto out_different; - if (compare_flags & COMPARE_NO_CONTENTS) + if (sd->compare_flags & COMPARE_NO_CONTENTS) return 0; - if (old_is_dir) { - sprintf(old_name, "%s/%s", old_path, path); + if (sd->old_is_dir) { + sprintf(old_name, "%s/%s", sd->old_path, path); old_fd = open(old_name, O_RDONLY); if (old_fd < 0) { @@ -33,8 +34,8 @@ int compare_files(file_info_t *old, file_info_t *new, const char *path) } } - if (new_is_dir) { - sprintf(new_name, "%s/%s", new_path, path); + if (sd->new_is_dir) { + sprintf(new_name, "%s/%s", sd->new_path, path); new_fd = open(new_name, O_RDONLY); if (new_fd < 0) { @@ -49,30 +50,30 @@ int compare_files(file_info_t *old, file_info_t *new, const char *path) if (diff > MAX_WINDOW_SIZE) diff = MAX_WINDOW_SIZE; - if (old_is_dir) { + if (sd->old_is_dir) { if (read_data_at(old_name, offset, old_fd, old_buf, diff)) goto out; } else { - ret = data_reader_read(sqfs_old.data, old, offset, + ret = data_reader_read(sd->sqfs_old.data, old, offset, old_buf, diff); if (ret < 0 || (size_t)ret < diff) { fprintf(stderr, "Failed to read %s from %s\n", - path, old_path); + path, sd->old_path); return -1; } } - if (new_is_dir) { + if (sd->new_is_dir) { if (read_data_at(new_name, offset, new_fd, new_buf, diff)) goto out; } else { - ret = data_reader_read(sqfs_new.data, new, offset, + ret = data_reader_read(sd->sqfs_new.data, new, offset, new_buf, diff); if (ret < 0 || (size_t)ret < diff) { fprintf(stderr, "Failed to read %s from %s\n", - path, new_path); + path, sd->new_path); return -1; } } @@ -90,8 +91,8 @@ fail: status = -1; goto out; out_different: - if (compare_flags & COMPARE_EXTRACT_FILES) { - if (extract_files(old, new, path)) + if (sd->compare_flags & COMPARE_EXTRACT_FILES) { + if (extract_files(sd, old, new, path)) goto fail; } status = 1; diff --git a/difftool/extract.c b/difftool/extract.c index f40de60..cefba62 100644 --- a/difftool/extract.c +++ b/difftool/extract.c @@ -37,15 +37,16 @@ static int extract(data_reader_t *data, file_info_t *fi, return 0; } -int extract_files(file_info_t *old, file_info_t *new, const char *path) +int extract_files(sqfsdiff_t *sd, file_info_t *old, file_info_t *new, + const char *path) { - if (old != NULL && !old_is_dir) { - if (extract(sqfs_old.data, old, path, 'a')) + if (old != NULL && !sd->old_is_dir) { + if (extract(sd->sqfs_old.data, old, path, 'a')) return -1; } - if (new != NULL && !new_is_dir) { - if (extract(sqfs_new.data, new, path, 'b')) + if (new != NULL && !sd->new_is_dir) { + if (extract(sd->sqfs_new.data, new, path, 'b')) return -1; } return 0; diff --git a/difftool/node_compare.c b/difftool/node_compare.c index 1c68ab2..35fd07b 100644 --- a/difftool/node_compare.c +++ b/difftool/node_compare.c @@ -6,7 +6,7 @@ */ #include "sqfsdiff.h" -int node_compare(tree_node_t *a, tree_node_t *b) +int node_compare(sqfsdiff_t *sd, tree_node_t *a, tree_node_t *b) { char *path = node_path(a); tree_node_t *ait, *bit; @@ -21,7 +21,7 @@ int node_compare(tree_node_t *a, tree_node_t *b) return 1; } - if (!(compare_flags & COMPARE_NO_PERM)) { + if (!(sd->compare_flags & COMPARE_NO_PERM)) { if ((a->mode & ~S_IFMT) != (b->mode & ~S_IFMT)) { fprintf(stdout, "%s has different permissions\n", path); @@ -29,21 +29,21 @@ int node_compare(tree_node_t *a, tree_node_t *b) } } - if (!(compare_flags & COMPARE_NO_OWNER)) { + if (!(sd->compare_flags & COMPARE_NO_OWNER)) { if (a->uid != b->uid || a->gid != b->gid) { fprintf(stdout, "%s has different ownership\n", path); status = 1; } } - if (compare_flags & COMPARE_TIMESTAMP) { + if (sd->compare_flags & COMPARE_TIMESTAMP) { if (a->mod_time != b->mod_time) { fprintf(stdout, "%s has a different timestamp\n", path); status = 1; } } - if (compare_flags & COMPARE_INODE_NUM) { + if (sd->compare_flags & COMPARE_INODE_NUM) { if (a->inode_num != b->inode_num) { fprintf(stdout, "%s has a different inode number\n", path); @@ -85,7 +85,7 @@ int node_compare(tree_node_t *a, tree_node_t *b) bit = b->data.dir->children; while (ait != NULL && bit != NULL) { - ret = node_compare(ait, bit); + ret = node_compare(sd, ait, bit); if (ret < 0) return -1; if (ret > 0) @@ -96,7 +96,7 @@ int node_compare(tree_node_t *a, tree_node_t *b) } break; case S_IFREG: - ret = compare_files(a->data.file, b->data.file, path); + ret = compare_files(sd, a->data.file, b->data.file, path); if (ret < 0) { status = -1; } else if (ret > 0) { diff --git a/difftool/options.c b/difftool/options.c new file mode 100644 index 0000000..8224b1d --- /dev/null +++ b/difftool/options.c @@ -0,0 +1,130 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * sqfsdiff.c + * + * Copyright (C) 2019 David Oberhollenzer + */ +#include "sqfsdiff.h" + +static struct option long_opts[] = { + { "old", required_argument, NULL, 'a' }, + { "new", required_argument, NULL, 'b' }, + { "no-owner", no_argument, NULL, 'O' }, + { "no-permissions", no_argument, NULL, 'P' }, + { "no-contents", no_argument, NULL, 'C' }, + { "timestamps", no_argument, NULL, 'T' }, + { "inode-num", no_argument, NULL, 'I' }, + { "super", no_argument, NULL, 'S' }, + { "extract", required_argument, NULL, 'e' }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, +}; + +static const char *short_opts = "a:b:OPCTISe:hV"; + +static const char *usagestr = +"Usage: sqfsdiff [OPTIONS...] --old,-a --new,-b \n" +"\n" +"Compare two squashfs images. In contrast to doing a direct diff of the\n" +"images, this actually parses the filesystems and generates a more\n" +"meaningful difference report.\n" +"\n" +"If only contents are compared, any differences in packed file layout,\n" +"ordering, compression, inode allocation and so on is ignored and the two\n" +"images are considered equal if each directory contains the same entries,\n" +"symlink with the same paths have the same targets, device nodes the same\n" +"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" +" --old, -a The first of the two images to compare.\n" +" --new, -b The second of the two images to compare.\n" +"\n" +" --no-contents, -C Do not compare file contents.\n" +" --no-owner, -O Do not compare file owners.\n" +" --no-permissions, -P Do not compare permission bits.\n" +"\n" +" --timestamps, -T Compare file timestamps.\n" +" --inode-num, -I Compare inode numbers of all files.\n" +" --super, -S Also compare metadata in super blocks.\n" +"\n" +" --extract, -e Extract files that differ to the specified\n" +" directory. Contents of the first image end up\n" +" in a subdirectory 'a' and of the second image\n" +" in a subdirectory 'b'.\n" +"\n" +" --help, -h Print help text and exit.\n" +" --version, -V Print version information and exit.\n" +"\n"; + +void process_options(sqfsdiff_t *sd, int argc, char **argv) +{ + int i; + + for (;;) { + i = getopt_long(argc, argv, short_opts, long_opts, NULL); + if (i == -1) + break; + + switch (i) { + case 'a': + sd->old_path = optarg; + break; + case 'b': + sd->new_path = optarg; + break; + case 'O': + sd->compare_flags |= COMPARE_NO_OWNER; + break; + case 'P': + sd->compare_flags |= COMPARE_NO_PERM; + break; + case 'C': + sd->compare_flags |= COMPARE_NO_CONTENTS; + break; + case 'T': + sd->compare_flags |= COMPARE_TIMESTAMP; + break; + case 'I': + sd->compare_flags |= COMPARE_INODE_NUM; + break; + case 'S': + sd->compare_super = true; + break; + case 'e': + sd->compare_flags |= COMPARE_EXTRACT_FILES; + sd->extract_dir = optarg; + break; + case 'h': + fputs(usagestr, stdout); + exit(EXIT_SUCCESS); + case 'V': + print_version(); + exit(EXIT_SUCCESS); + default: + goto fail_arg; + } + } + + if (sd->old_path == NULL) { + fputs("Missing arguments: first filesystem\n", stderr); + goto fail_arg; + } + + if (sd->new_path == NULL) { + fputs("Missing arguments: second filesystem\n", stderr); + goto fail_arg; + } + + 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); +} diff --git a/difftool/sqfsdiff.c b/difftool/sqfsdiff.c index ddc2686..2bc733b 100644 --- a/difftool/sqfsdiff.c +++ b/difftool/sqfsdiff.c @@ -6,172 +6,42 @@ */ #include "sqfsdiff.h" -static struct option long_opts[] = { - { "old", required_argument, NULL, 'a' }, - { "new", required_argument, NULL, 'b' }, - { "no-owner", no_argument, NULL, 'O' }, - { "no-permissions", no_argument, NULL, 'P' }, - { "no-contents", no_argument, NULL, 'C' }, - { "timestamps", no_argument, NULL, 'T' }, - { "inode-num", no_argument, NULL, 'I' }, - { "super", no_argument, NULL, 'S' }, - { "extract", required_argument, NULL, 'e' }, - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, -}; - -static const char *short_opts = "a:b:OPCTISe:hV"; - -static const char *usagestr = -"Usage: sqfsdiff [OPTIONS...] --old,-a --new,-b \n" -"\n" -"Compare two squashfs images. In contrast to doing a direct diff of the\n" -"images, this actually parses the filesystems and generates a more\n" -"meaningful difference report.\n" -"\n" -"If only contents are compared, any differences in packed file layout,\n" -"ordering, compression, inode allocation and so on is ignored and the two\n" -"images are considered equal if each directory contains the same entries,\n" -"symlink with the same paths have the same targets, device nodes the same\n" -"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" -" --old, -a The first of the two images to compare.\n" -" --new, -b The second of the two images to compare.\n" -"\n" -" --no-contents, -C Do not compare file contents.\n" -" --no-owner, -O Do not compare file owners.\n" -" --no-permissions, -P Do not compare permission bits.\n" -"\n" -" --timestamps, -T Compare file timestamps.\n" -" --inode-num, -I Compare inode numbers of all files.\n" -" --super, -S Also compare metadata in super blocks.\n" -"\n" -" --extract, -e Extract files that differ to the specified\n" -" directory. Contents of the first image end up\n" -" in a subdirectory 'a' and of the second image\n" -" in a subdirectory 'b'.\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 *old_path; -const char *new_path; -sqfs_reader_t sqfs_old; -sqfs_reader_t sqfs_new; -bool old_is_dir; -bool new_is_dir; -static bool compare_super = false; -static const char *extract_dir; - -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 'a': - old_path = optarg; - break; - case 'b': - new_path = optarg; - break; - case 'O': - compare_flags |= COMPARE_NO_OWNER; - break; - case 'P': - compare_flags |= COMPARE_NO_PERM; - break; - case 'C': - compare_flags |= COMPARE_NO_CONTENTS; - break; - case 'T': - compare_flags |= COMPARE_TIMESTAMP; - break; - case 'I': - compare_flags |= COMPARE_INODE_NUM; - break; - case 'S': - compare_super = true; - break; - case 'e': - compare_flags |= COMPARE_EXTRACT_FILES; - extract_dir = optarg; - break; - case 'h': - fputs(usagestr, stdout); - exit(EXIT_SUCCESS); - case 'V': - print_version(); - exit(EXIT_SUCCESS); - default: - goto fail_arg; - } - } - - if (old_path == NULL) { - fputs("Missing arguments: first filesystem\n", stderr); - goto fail_arg; - } - - if (new_path == NULL) { - fputs("Missing arguments: second filesystem\n", stderr); - goto fail_arg; - } - - 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 status, ret = 0; + sqfsdiff_t sd; - process_options(argc, argv); + memset(&sd, 0, sizeof(sd)); + process_options(&sd, argc, argv); - if (extract_dir != NULL) { - if (mkdir_p(extract_dir)) + if (sd.extract_dir != NULL) { + if (mkdir_p(sd.extract_dir)) return EXIT_FAILURE; } - if (sqfs_reader_open(&sqfs_old, old_path, 0)) + if (sqfs_reader_open(&sd.sqfs_old, sd.old_path, 0)) return 2; - if (sqfs_reader_open(&sqfs_new, new_path, 0)) { + if (sqfs_reader_open(&sd.sqfs_new, sd.new_path, 0)) { status = 2; goto out_sqfs_old; } - if (extract_dir != NULL) { - if (chdir(extract_dir)) { - perror(extract_dir); + if (sd.extract_dir != NULL) { + if (chdir(sd.extract_dir)) { + perror(sd.extract_dir); ret = -1; goto out; } } - ret = node_compare(sqfs_old.fs.root, sqfs_new.fs.root); + ret = node_compare(&sd, sd.sqfs_old.fs.root, sd.sqfs_new.fs.root); if (ret != 0) goto out; - if (compare_super) { - ret = compare_super_blocks(&sqfs_old.super, &sqfs_new.super); + if (sd.compare_super) { + ret = compare_super_blocks(&sd.sqfs_old.super, + &sd.sqfs_new.super); if (ret != 0) goto out; } @@ -183,8 +53,8 @@ out: } else { status = 0; } - sqfs_reader_close(&sqfs_new); + sqfs_reader_close(&sd.sqfs_new); out_sqfs_old: - sqfs_reader_close(&sqfs_old); + sqfs_reader_close(&sd.sqfs_old); return status; } diff --git a/difftool/sqfsdiff.h b/difftool/sqfsdiff.h index f7d5139..ce6929f 100644 --- a/difftool/sqfsdiff.h +++ b/difftool/sqfsdiff.h @@ -23,13 +23,17 @@ #define MAX_WINDOW_SIZE (1024 * 1024 * 4) -extern const char *old_path; -extern const char *new_path; -extern int compare_flags; -extern sqfs_reader_t sqfs_old; -extern sqfs_reader_t sqfs_new; -extern bool old_is_dir; -extern bool new_is_dir; +typedef struct { + const char *old_path; + const char *new_path; + int compare_flags; + sqfs_reader_t sqfs_old; + sqfs_reader_t sqfs_new; + bool old_is_dir; + bool new_is_dir; + bool compare_super; + const char *extract_dir; +} sqfsdiff_t; enum { COMPARE_NO_PERM = 0x01, @@ -44,12 +48,16 @@ int compare_dir_entries(tree_node_t *a, tree_node_t *b); char *node_path(tree_node_t *n); -int compare_files(file_info_t *a, file_info_t *b, const char *path); +int compare_files(sqfsdiff_t *sd, file_info_t *a, file_info_t *b, + const char *path); -int node_compare(tree_node_t *a, tree_node_t *b); +int node_compare(sqfsdiff_t *sd, tree_node_t *a, tree_node_t *b); int compare_super_blocks(const sqfs_super_t *a, const sqfs_super_t *b); -int extract_files(file_info_t *a, file_info_t *b, const char *path); +int extract_files(sqfsdiff_t *sd, file_info_t *old, file_info_t *new, + const char *path); + +void process_options(sqfsdiff_t *sd, int argc, char **argv); #endif /* DIFFTOOL_H */ -- cgit v1.2.3