summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--difftool/compare_files.c91
-rw-r--r--difftool/sqfsdiff.c74
-rw-r--r--difftool/sqfsdiff.h4
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 {