summaryrefslogtreecommitdiff
path: root/difftool
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-08-09 11:43:15 +0200
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-08-09 12:11:12 +0200
commitb3c3401aee91bc2ff46ba0eab0ceb88c78cb5bbb (patch)
tree097241e9080420385db37a3985c5beabe42cb57b /difftool
parentfd98948e840f6e67cd2d7c72f57d2fd80ed9a418 (diff)
Add option to sqfsdiff to extract regular files that are different
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'difftool')
-rw-r--r--difftool/Makemodule.am1
-rw-r--r--difftool/compare_files_sqfs.c10
-rw-r--r--difftool/difftool.h3
-rw-r--r--difftool/extract.c52
-rw-r--r--difftool/sqfsdiff.c26
5 files changed, 89 insertions, 3 deletions
diff --git a/difftool/Makemodule.am b/difftool/Makemodule.am
index 1b0011b..83e5f83 100644
--- a/difftool/Makemodule.am
+++ b/difftool/Makemodule.am
@@ -6,6 +6,7 @@ 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 difftool/super.c
+sqfsdiff_SOURCES += difftool/extract.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_sqfs.c b/difftool/compare_files_sqfs.c
index 76fae7a..32b97b1 100644
--- a/difftool/compare_files_sqfs.c
+++ b/difftool/compare_files_sqfs.c
@@ -15,7 +15,7 @@ int compare_files(file_info_t *a, file_info_t *b, const char *path)
ssize_t ret;
if (a->size != b->size)
- return 1;
+ goto out_different;
if (compare_flags & COMPARE_NO_CONTENTS)
return 0;
@@ -41,8 +41,14 @@ int compare_files(file_info_t *a, file_info_t *b, const char *path)
}
if (memcmp(a_buf, b_buf, diff) != 0)
- return 1;
+ goto out_different;
}
return 0;
+out_different:
+ if (compare_flags & COMPARE_EXTRACT_FILES) {
+ if (extract_files(a, b, path))
+ return -1;
+ }
+ return 1;
}
diff --git a/difftool/difftool.h b/difftool/difftool.h
index 23a161c..bd04fd2 100644
--- a/difftool/difftool.h
+++ b/difftool/difftool.h
@@ -35,6 +35,7 @@ enum {
COMPARE_NO_CONTENTS = 0x04,
COMPARE_TIMESTAMP = 0x08,
COMPARE_INODE_NUM = 0x10,
+ COMPARE_EXTRACT_FILES = 0x20,
};
int compare_dir_entries(tree_node_t *a, tree_node_t *b);
@@ -47,4 +48,6 @@ int node_compare(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);
+
#endif /* DIFFTOOL_H */
diff --git a/difftool/extract.c b/difftool/extract.c
new file mode 100644
index 0000000..9d84265
--- /dev/null
+++ b/difftool/extract.c
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+/*
+ * extract.c
+ *
+ * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
+ */
+#include "difftool.h"
+
+static int extract(data_reader_t *data, file_info_t *fi,
+ const char *path, char prefix)
+{
+ char *ptr, *temp = alloca(strlen(path) + 3);
+ int fd;
+
+ temp[0] = prefix;
+ temp[1] = '/';
+ strcpy(temp + 2, path);
+
+ ptr = strrchr(temp, '/');
+ *ptr = '\0';
+ if (mkdir_p(temp))
+ return -1;
+ *ptr = '/';
+
+ fd = open(temp, O_CREAT | O_EXCL | O_WRONLY, 0600);
+ if (fd < 0) {
+ perror(temp);
+ return -1;
+ }
+
+ if (data_reader_dump_file(data, fi, fd, true)) {
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+int extract_files(file_info_t *a, file_info_t *b, const char *path)
+{
+ if (a != NULL) {
+ if (extract(sqfs_a.data, a, path, 'a'))
+ return -1;
+ }
+
+ if (b != NULL) {
+ if (extract(sqfs_b.data, b, path, 'b'))
+ return -1;
+ }
+ return 0;
+}
diff --git a/difftool/sqfsdiff.c b/difftool/sqfsdiff.c
index 8818a37..4754557 100644
--- a/difftool/sqfsdiff.c
+++ b/difftool/sqfsdiff.c
@@ -13,11 +13,12 @@ static struct option long_opts[] = {
{ "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 = "OPCTIShV";
+static const char *short_opts = "OPCTISe:hV";
static const char *usagestr =
"Usage: sqfsdiff [OPTIONS...] <first> <second>\n"
@@ -45,6 +46,11 @@ static const char *usagestr =
" --inode-num, -I Compare inode numbers of all files.\n"
" --super, -S Also compare metadata in super blocks.\n"
"\n"
+" --extract, -e <path> 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";
@@ -55,6 +61,7 @@ const char *second_path;
sqfs_reader_t sqfs_a;
sqfs_reader_t sqfs_b;
static bool compare_super = false;
+static const char *extract_dir;
static void process_options(int argc, char **argv)
{
@@ -84,6 +91,10 @@ static void process_options(int argc, char **argv)
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);
@@ -125,6 +136,11 @@ int main(int argc, char **argv)
process_options(argc, argv);
+ if (extract_dir != NULL) {
+ if (mkdir_p(extract_dir))
+ return EXIT_FAILURE;
+ }
+
if (sqfs_reader_open(&sqfs_a, first_path, 0))
return 2;
@@ -133,6 +149,14 @@ int main(int argc, char **argv)
goto out_sqfs_a;
}
+ if (extract_dir != NULL) {
+ if (chdir(extract_dir)) {
+ perror(extract_dir);
+ ret = -1;
+ goto out;
+ }
+ }
+
ret = node_compare(sqfs_a.fs.root, sqfs_b.fs.root);
if (ret != 0)
goto out;