From 1c8e61f284ff04e3b63c46044d7b890a7e93e302 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Wed, 21 Aug 2019 14:27:19 +0200 Subject: Make unified dir to sqfs comparison work Signed-off-by: David Oberhollenzer --- difftool/compare_files.c | 91 +++++++++++++++++++++++++----------------------- difftool/sqfsdiff.c | 74 ++++++++++++++++++++++++++++++++++----- difftool/sqfsdiff.h | 4 +++ 3 files changed, 118 insertions(+), 51 deletions(-) diff --git a/difftool/compare_files.c b/difftool/compare_files.c index 605df84..df767c1 100644 --- a/difftool/compare_files.c +++ b/difftool/compare_files.c @@ -9,14 +9,45 @@ static unsigned char old_buf[MAX_WINDOW_SIZE]; static unsigned char new_buf[MAX_WINDOW_SIZE]; +static int open_file(int dirfd, const char *prefix, const char *path) +{ + int fd = openat(dirfd, path, O_RDONLY); + + if (fd < 0) { + fprintf(stderr, "open %s/%s: %s\n", + prefix, path, strerror(errno)); + } + + return fd; +} + +static int read_blob(const char *prefix, const char *path, bool is_dir, + int fd, data_reader_t *rd, file_info_t *fi, void *buffer, + off_t offset, size_t size) +{ + ssize_t ret; + + if (is_dir) { + ret = read_data_at(path, offset, fd, buffer, size); + } else { + ret = data_reader_read(rd, fi, offset, buffer, size); + ret = (ret < 0 || (size_t)ret < size) ? -1 : 0; + } + + if (ret) { + fprintf(stderr, "Failed to read %s from %s\n", + path, prefix); + return -1; + } + + return 0; +} + int compare_files(sqfsdiff_t *sd, file_info_t *old, file_info_t *new, const char *path) { - 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; + int old_fd = -1, new_fd = -1, status = 0, ret; uint64_t offset, diff; - ssize_t ret; if (old->size != new->size) goto out_different; @@ -25,23 +56,15 @@ int compare_files(sqfsdiff_t *sd, file_info_t *old, file_info_t *new, return 0; 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) { - perror(old_name); + old_fd = open_file(sd->old_fd, sd->old_path, path); + if (old_fd < 0) goto fail; - } } 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) { - perror(new_name); + new_fd = open_file(sd->new_fd, sd->new_path, path); + if (new_fd < 0) goto fail; - } } for (offset = 0; offset < old->size; offset += diff) { @@ -50,33 +73,15 @@ int compare_files(sqfsdiff_t *sd, file_info_t *old, file_info_t *new, if (diff > MAX_WINDOW_SIZE) diff = MAX_WINDOW_SIZE; - if (sd->old_is_dir) { - if (read_data_at(old_name, offset, old_fd, - old_buf, diff)) - goto out; - } else { - 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, sd->old_path); - return -1; - } - } - - if (sd->new_is_dir) { - if (read_data_at(new_name, offset, new_fd, - new_buf, diff)) - goto out; - } else { - 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, sd->new_path); - return -1; - } - } + ret = read_blob(sd->old_path, path, sd->old_is_dir, old_fd, + sd->sqfs_old.data, old, old_buf, offset, diff); + if (ret) + goto fail; + + ret = read_blob(sd->new_path, path, sd->new_is_dir, new_fd, + sd->sqfs_new.data, new, new_buf, offset, diff); + if (ret) + goto fail; if (memcmp(old_buf, new_buf, diff) != 0) goto out_different; diff --git a/difftool/sqfsdiff.c b/difftool/sqfsdiff.c index 2bc733b..601ffba 100644 --- a/difftool/sqfsdiff.c +++ b/difftool/sqfsdiff.c @@ -19,12 +19,60 @@ int main(int argc, char **argv) return EXIT_FAILURE; } - if (sqfs_reader_open(&sd.sqfs_old, sd.old_path, 0)) - return 2; + /* open first source */ + sd.old_fd = open(sd.old_path, O_DIRECTORY | O_PATH | O_RDONLY); + if (sd.old_fd < 0) { + if (errno == ENOTDIR) { + sd.old_is_dir = false; - if (sqfs_reader_open(&sd.sqfs_new, sd.new_path, 0)) { - status = 2; - goto out_sqfs_old; + if (sqfs_reader_open(&sd.sqfs_old, sd.old_path, 0)) + return 2; + } else { + perror(sd.old_path); + return 2; + } + } else { + sd.old_is_dir = true; + if (fstree_init(&sd.sqfs_old.fs, 512, NULL)) + return 2; + + if (fstree_from_dir(&sd.sqfs_old.fs, sd.old_path, 0)) { + fstree_cleanup(&sd.sqfs_old.fs); + return 2; + } + + tree_node_sort_recursive(sd.sqfs_old.fs.root); + } + + /* open second source */ + sd.new_fd = open(sd.new_path, O_DIRECTORY | O_PATH | O_RDONLY); + if (sd.new_fd < 0) { + if (errno == ENOTDIR) { + sd.new_is_dir = false; + + if (sqfs_reader_open(&sd.sqfs_new, sd.new_path, 0)) { + status = 2; + goto out_sqfs_old; + } + } else { + status = 2; + perror(sd.new_path); + goto out_sqfs_old; + } + } else { + sd.new_is_dir = true; + if (fstree_init(&sd.sqfs_new.fs, 512, NULL)) { + status = 2; + goto out_sqfs_old; + } + + if (fstree_from_dir(&sd.sqfs_new.fs, sd.new_path, 0)) { + status = 2; + fstree_cleanup(&sd.sqfs_old.fs); + goto out_sqfs_old; + } + + tree_node_sort_recursive(sd.sqfs_new.fs.root); } if (sd.extract_dir != NULL) { @@ -39,7 +87,7 @@ int main(int argc, char **argv) if (ret != 0) goto out; - if (sd.compare_super) { + if (sd.compare_super && !sd.old_is_dir && !sd.new_is_dir) { ret = compare_super_blocks(&sd.sqfs_old.super, &sd.sqfs_new.super); if (ret != 0) @@ -53,8 +101,18 @@ out: } else { status = 0; } - sqfs_reader_close(&sd.sqfs_new); + if (sd.new_is_dir) { + close(sd.new_fd); + fstree_cleanup(&sd.sqfs_new.fs); + } else { + sqfs_reader_close(&sd.sqfs_new); + } out_sqfs_old: - sqfs_reader_close(&sd.sqfs_old); + if (sd.old_is_dir) { + close(sd.old_fd); + fstree_cleanup(&sd.sqfs_old.fs); + } else { + sqfs_reader_close(&sd.sqfs_old); + } return status; } diff --git a/difftool/sqfsdiff.h b/difftool/sqfsdiff.h index ce6929f..836b499 100644 --- a/difftool/sqfsdiff.h +++ b/difftool/sqfsdiff.h @@ -33,6 +33,10 @@ typedef struct { bool new_is_dir; bool compare_super; const char *extract_dir; + + /* holds the coresponding dirfds if old or new is a directory */ + int old_fd; + int new_fd; } sqfsdiff_t; enum { -- cgit v1.2.3