update cached timestamps of files left unmodified after a merge
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
diff --git a/lib/worktree.c b/lib/worktree.c
index 4eccffd..43324d9 100644
--- a/lib/worktree.c
+++ b/lib/worktree.c
@@ -601,6 +601,96 @@ done:
return err;
}
+static const struct got_error *
+check_file_contents_equal(int *same, FILE *f1, FILE *f2)
+{
+ const struct got_error *err = NULL;
+ uint8_t fbuf1[8192];
+ uint8_t fbuf2[8192];
+ size_t flen1 = 0, flen2 = 0;
+
+ *same = 1;
+
+ while (1) {
+ flen1 = fread(fbuf1, 1, sizeof(fbuf1), f1);
+ if (flen1 == 0 && ferror(f1)) {
+ err = got_error_from_errno();
+ break;
+ }
+ flen2 = fread(fbuf2, 1, sizeof(fbuf2), f2);
+ if (flen2 == 0 && ferror(f2)) {
+ err = got_error_from_errno();
+ break;
+ }
+ if (flen1 == 0) {
+ if (flen2 != 0)
+ *same = 0;
+ break;
+ } else if (flen2 == 0) {
+ if (flen1 != 0)
+ *same = 0;
+ break;
+ } else if (flen1 == flen2) {
+ if (memcmp(fbuf1, fbuf2, flen2) != 0) {
+ *same = 0;
+ break;
+ }
+ } else {
+ *same = 0;
+ break;
+ }
+ }
+
+ return err;
+}
+
+static const struct got_error *
+check_files_equal(int *same, const char *f1_path, const char *f2_path)
+{
+ const struct got_error *err = NULL;
+ struct stat sb;
+ size_t size1, size2;
+ FILE *f1 = NULL, *f2 = NULL;
+
+ *same = 1;
+
+ if (lstat(f1_path, &sb) != 0) {
+ err = got_error_from_errno();
+ goto done;
+ }
+ size1 = sb.st_size;
+
+ if (lstat(f2_path, &sb) != 0) {
+ err = got_error_from_errno();
+ goto done;
+ }
+ size2 = sb.st_size;
+
+ if (size1 != size2) {
+ *same = 0;
+ return NULL;
+ }
+
+ f1 = fopen(f1_path, "r");
+ if (f1 == NULL)
+ return got_error_from_errno();
+
+ f2 = fopen(f2_path, "r");
+ if (f2 == NULL) {
+ err = got_error_from_errno();
+ goto done;
+ }
+
+ err = check_file_contents_equal(same, f1, f2);
+done:
+ if (f1 && fclose(f1) != 0 && err == NULL)
+ err = got_error_from_errno();
+ if (f2 && fclose(f2) != 0 && err == NULL)
+ err = got_error_from_errno();
+
+ return err;
+}
+
/*
* Perform a 3-way merge where the file's version in the file index (blob2)
* acts as the common ancestor, the incoming blob (blob1) acts as the first
@@ -622,7 +712,7 @@ merge_blob(struct got_worktree *worktree, struct got_fileindex *fileindex,
struct got_object_id id2;
char *id_str = NULL;
char *label1 = NULL;
- int overlapcnt = 0;
+ int overlapcnt = 0, update_timestamps = 0;
char *parent;
parent = dirname(ondisk_path);
@@ -691,6 +781,14 @@ merge_blob(struct got_worktree *worktree, struct got_fileindex *fileindex,
goto done;
}
+ /* Check if a clean merge has subsumed all local changes. */
+ if (overlapcnt == 0) {
+ err = check_files_equal(&update_timestamps, blob1_path,
+ merged_path);
+ if (err)
+ goto done;
+ }
+
if (rename(merged_path, ondisk_path) != 0) {
err = got_error_from_errno();
goto done;
@@ -701,7 +799,7 @@ merge_blob(struct got_worktree *worktree, struct got_fileindex *fileindex,
* the status walk would treat them as unmodified files again.
*/
err = got_fileindex_entry_update(ie, ondisk_path,
- blob1->id.sha1, worktree->base_commit_id->sha1, 0);
+ blob1->id.sha1, worktree->base_commit_id->sha1, update_timestamps);
done:
if (merged_fd != -1 && close(merged_fd) != 0 && err == NULL)
err = got_error_from_errno();