Git fork

rerere: let `rerere_path()` write paths into a caller-provided buffer

Same as with `get_worktree_git_dir()` a couple of commits ago, the
`rerere_path()` function returns paths that need not be free'd by the
caller because `git_path()` internally uses `get_pathname()`.

Refactor the function to instead accept a caller-provided buffer that
the path will be written into, passing on ownership to the caller. This
refactoring prepares us for the removal of `git_path()`.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>

authored by

Patrick Steinhardt and committed by
Junio C Hamano
8ee018d8 07242c2a

+69 -32
+7 -4
builtin/rerere.c
··· 4 #include "config.h" 5 #include "gettext.h" 6 #include "parse-options.h" 7 - 8 - #include "string-list.h" 9 #include "rerere.h" 10 #include "xdiff/xdiff.h" 11 #include "xdiff-interface.h" 12 #include "pathspec.h" ··· 112 merge_rr.items[i].util = NULL; 113 } 114 } else if (!strcmp(argv[0], "diff")) { 115 if (setup_rerere(the_repository, &merge_rr, 116 flags | RERERE_READONLY) < 0) 117 return 0; 118 for (size_t i = 0; i < merge_rr.nr; i++) { 119 const char *path = merge_rr.items[i].string; 120 const struct rerere_id *id = merge_rr.items[i].util; 121 - if (diff_two(rerere_path(id, "preimage"), path, path, path)) 122 - die(_("unable to generate diff for '%s'"), rerere_path(id, NULL)); 123 } 124 } else 125 usage_with_options(rerere_usage, options); 126
··· 4 #include "config.h" 5 #include "gettext.h" 6 #include "parse-options.h" 7 #include "rerere.h" 8 + #include "strbuf.h" 9 + #include "string-list.h" 10 #include "xdiff/xdiff.h" 11 #include "xdiff-interface.h" 12 #include "pathspec.h" ··· 112 merge_rr.items[i].util = NULL; 113 } 114 } else if (!strcmp(argv[0], "diff")) { 115 + struct strbuf buf = STRBUF_INIT; 116 if (setup_rerere(the_repository, &merge_rr, 117 flags | RERERE_READONLY) < 0) 118 return 0; 119 for (size_t i = 0; i < merge_rr.nr; i++) { 120 const char *path = merge_rr.items[i].string; 121 const struct rerere_id *id = merge_rr.items[i].util; 122 + if (diff_two(rerere_path(&buf, id, "preimage"), path, path, path)) 123 + die(_("unable to generate diff for '%s'"), rerere_path(&buf, id, NULL)); 124 } 125 + 126 + strbuf_release(&buf); 127 } else 128 usage_with_options(rerere_usage, options); 129
+60 -27
rerere.c
··· 91 id->variant = variant; 92 } 93 94 - const char *rerere_path(const struct rerere_id *id, const char *file) 95 { 96 if (!file) 97 - return git_path("rr-cache/%s", rerere_id_hex(id)); 98 99 if (id->variant <= 0) 100 - return git_path("rr-cache/%s/%s", rerere_id_hex(id), file); 101 102 - return git_path("rr-cache/%s/%s.%d", 103 - rerere_id_hex(id), file, id->variant); 104 } 105 106 static int is_rr_file(const char *name, const char *filename, int *variant) ··· 624 { 625 enum ll_merge_result ret; 626 mmfile_t base = {NULL, 0}, other = {NULL, 0}; 627 628 - if (read_mmfile(&base, rerere_path(id, "preimage")) || 629 - read_mmfile(&other, rerere_path(id, "postimage"))) { 630 ret = LL_MERGE_CONFLICT; 631 } else { 632 /* ··· 637 istate, NULL); 638 } 639 640 free(base.ptr); 641 free(other.ptr); 642 ··· 657 { 658 FILE *f; 659 int ret; 660 mmfile_t cur = {NULL, 0}; 661 mmbuffer_t result = {NULL, 0}; 662 ··· 664 * Normalize the conflicts in path and write it out to 665 * "thisimage" temporary file. 666 */ 667 - if ((handle_file(istate, path, NULL, rerere_path(id, "thisimage")) < 0) || 668 - read_mmfile(&cur, rerere_path(id, "thisimage"))) { 669 ret = 1; 670 goto out; 671 } ··· 678 * A successful replay of recorded resolution. 679 * Mark that "postimage" was used to help gc. 680 */ 681 - if (utime(rerere_path(id, "postimage"), NULL) < 0) 682 warning_errno(_("failed utime() on '%s'"), 683 - rerere_path(id, "postimage")); 684 685 /* Update "path" with the resolution */ 686 f = fopen(path, "w"); ··· 694 out: 695 free(cur.ptr); 696 free(result.ptr); 697 698 return ret; 699 } ··· 720 721 static void remove_variant(struct rerere_id *id) 722 { 723 - unlink_or_warn(rerere_path(id, "postimage")); 724 - unlink_or_warn(rerere_path(id, "preimage")); 725 id->collection->status[id->variant] = 0; 726 } 727 728 /* ··· 739 const char *path = rr_item->string; 740 struct rerere_id *id = rr_item->util; 741 struct rerere_dir *rr_dir = id->collection; 742 int variant; 743 744 variant = id->variant; ··· 746 /* Has the user resolved it already? */ 747 if (variant >= 0) { 748 if (!handle_file(istate, path, NULL, NULL)) { 749 - copy_file(rerere_path(id, "postimage"), path, 0666); 750 id->collection->status[variant] |= RR_HAS_POSTIMAGE; 751 fprintf_ln(stderr, _("Recorded resolution for '%s'."), path); 752 free_rerere_id(rr_item); 753 rr_item->util = NULL; 754 - return; 755 } 756 /* 757 * There may be other variants that can cleanly ··· 787 path); 788 free_rerere_id(rr_item); 789 rr_item->util = NULL; 790 - return; 791 } 792 793 /* None of the existing one applies; we need a new variant */ 794 assign_variant(id); 795 796 variant = id->variant; 797 - handle_file(istate, path, NULL, rerere_path(id, "preimage")); 798 if (id->collection->status[variant] & RR_HAS_POSTIMAGE) { 799 - const char *path = rerere_path(id, "postimage"); 800 if (unlink(path)) 801 die_errno(_("cannot unlink stray '%s'"), path); 802 id->collection->status[variant] &= ~RR_HAS_POSTIMAGE; 803 } 804 id->collection->status[variant] |= RR_HAS_PREIMAGE; 805 fprintf_ln(stderr, _("Recorded preimage for '%s'"), path); 806 } 807 808 static int do_plain_rerere(struct repository *r, ··· 810 { 811 struct string_list conflict = STRING_LIST_INIT_DUP; 812 struct string_list update = STRING_LIST_INIT_DUP; 813 int i; 814 815 find_conflict(r, &conflict); ··· 843 string_list_insert(rr, path)->util = id; 844 845 /* Ensure that the directory exists. */ 846 - mkdir_in_gitdir(rerere_path(id, NULL)); 847 } 848 849 for (i = 0; i < rr->nr; i++) ··· 854 855 string_list_clear(&conflict, 0); 856 string_list_clear(&update, 0); 857 return write_rr(rr, fd); 858 } 859 ··· 1033 struct rerere_id *id; 1034 unsigned char hash[GIT_MAX_RAWSZ]; 1035 int ret; 1036 struct string_list_item *item; 1037 1038 /* ··· 1056 if (!has_rerere_resolution(id)) 1057 continue; 1058 1059 - handle_cache(istate, path, hash, rerere_path(id, "thisimage")); 1060 - if (read_mmfile(&cur, rerere_path(id, "thisimage"))) { 1061 free(cur.ptr); 1062 error(_("failed to update conflicted state in '%s'"), path); 1063 goto fail_exit; ··· 1074 goto fail_exit; 1075 } 1076 1077 - filename = rerere_path(id, "postimage"); 1078 if (unlink(filename)) { 1079 if (errno == ENOENT) 1080 error(_("no remembered resolution for '%s'"), path); ··· 1088 * conflict in the working tree, run us again to record 1089 * the postimage. 1090 */ 1091 - handle_cache(istate, path, hash, rerere_path(id, "preimage")); 1092 fprintf_ln(stderr, _("Updated preimage for '%s'"), path); 1093 1094 /* ··· 1099 free_rerere_id(item); 1100 item->util = id; 1101 fprintf(stderr, _("Forgot resolution for '%s'\n"), path); 1102 return 0; 1103 1104 fail_exit: 1105 free(id); 1106 return -1; 1107 } ··· 1147 1148 static timestamp_t rerere_created_at(struct rerere_id *id) 1149 { 1150 struct stat st; 1151 1152 - return stat(rerere_path(id, "preimage"), &st) ? (time_t) 0 : st.st_mtime; 1153 } 1154 1155 static timestamp_t rerere_last_used_at(struct rerere_id *id) 1156 { 1157 struct stat st; 1158 1159 - return stat(rerere_path(id, "postimage"), &st) ? (time_t) 0 : st.st_mtime; 1160 } 1161 1162 /* ··· 1164 */ 1165 static void unlink_rr_item(struct rerere_id *id) 1166 { 1167 - unlink_or_warn(rerere_path(id, "thisimage")); 1168 remove_variant(id); 1169 id->collection->status[id->variant] = 0; 1170 } 1171 1172 static void prune_one(struct rerere_id *id, ··· 1264 1265 for (i = 0; i < merge_rr->nr; i++) { 1266 struct rerere_id *id = merge_rr->items[i].util; 1267 if (!has_rerere_resolution(id)) { 1268 unlink_rr_item(id); 1269 - rmdir(rerere_path(id, NULL)); 1270 } 1271 } 1272 unlink_or_warn(git_path_merge_rr(r)); 1273 rollback_lock_file(&write_lock);
··· 91 id->variant = variant; 92 } 93 94 + const char *rerere_path(struct strbuf *buf, const struct rerere_id *id, const char *file) 95 { 96 if (!file) 97 + return repo_git_path_replace(the_repository, buf, "rr-cache/%s", 98 + rerere_id_hex(id)); 99 100 if (id->variant <= 0) 101 + return repo_git_path_replace(the_repository, buf, "rr-cache/%s/%s", 102 + rerere_id_hex(id), file); 103 104 + return repo_git_path_replace(the_repository, buf, "rr-cache/%s/%s.%d", 105 + rerere_id_hex(id), file, id->variant); 106 } 107 108 static int is_rr_file(const char *name, const char *filename, int *variant) ··· 626 { 627 enum ll_merge_result ret; 628 mmfile_t base = {NULL, 0}, other = {NULL, 0}; 629 + struct strbuf buf = STRBUF_INIT; 630 631 + if (read_mmfile(&base, rerere_path(&buf, id, "preimage")) || 632 + read_mmfile(&other, rerere_path(&buf, id, "postimage"))) { 633 ret = LL_MERGE_CONFLICT; 634 } else { 635 /* ··· 640 istate, NULL); 641 } 642 643 + strbuf_release(&buf); 644 free(base.ptr); 645 free(other.ptr); 646 ··· 661 { 662 FILE *f; 663 int ret; 664 + struct strbuf buf = STRBUF_INIT; 665 mmfile_t cur = {NULL, 0}; 666 mmbuffer_t result = {NULL, 0}; 667 ··· 669 * Normalize the conflicts in path and write it out to 670 * "thisimage" temporary file. 671 */ 672 + if ((handle_file(istate, path, NULL, rerere_path(&buf, id, "thisimage")) < 0) || 673 + read_mmfile(&cur, rerere_path(&buf, id, "thisimage"))) { 674 ret = 1; 675 goto out; 676 } ··· 683 * A successful replay of recorded resolution. 684 * Mark that "postimage" was used to help gc. 685 */ 686 + if (utime(rerere_path(&buf, id, "postimage"), NULL) < 0) 687 warning_errno(_("failed utime() on '%s'"), 688 + rerere_path(&buf, id, "postimage")); 689 690 /* Update "path" with the resolution */ 691 f = fopen(path, "w"); ··· 699 out: 700 free(cur.ptr); 701 free(result.ptr); 702 + strbuf_release(&buf); 703 704 return ret; 705 } ··· 726 727 static void remove_variant(struct rerere_id *id) 728 { 729 + struct strbuf buf = STRBUF_INIT; 730 + unlink_or_warn(rerere_path(&buf, id, "postimage")); 731 + unlink_or_warn(rerere_path(&buf, id, "preimage")); 732 id->collection->status[id->variant] = 0; 733 + strbuf_release(&buf); 734 } 735 736 /* ··· 747 const char *path = rr_item->string; 748 struct rerere_id *id = rr_item->util; 749 struct rerere_dir *rr_dir = id->collection; 750 + struct strbuf buf = STRBUF_INIT; 751 int variant; 752 753 variant = id->variant; ··· 755 /* Has the user resolved it already? */ 756 if (variant >= 0) { 757 if (!handle_file(istate, path, NULL, NULL)) { 758 + copy_file(rerere_path(&buf, id, "postimage"), path, 0666); 759 id->collection->status[variant] |= RR_HAS_POSTIMAGE; 760 fprintf_ln(stderr, _("Recorded resolution for '%s'."), path); 761 free_rerere_id(rr_item); 762 rr_item->util = NULL; 763 + goto out; 764 } 765 /* 766 * There may be other variants that can cleanly ··· 796 path); 797 free_rerere_id(rr_item); 798 rr_item->util = NULL; 799 + goto out; 800 } 801 802 /* None of the existing one applies; we need a new variant */ 803 assign_variant(id); 804 805 variant = id->variant; 806 + handle_file(istate, path, NULL, rerere_path(&buf, id, "preimage")); 807 if (id->collection->status[variant] & RR_HAS_POSTIMAGE) { 808 + const char *path = rerere_path(&buf, id, "postimage"); 809 if (unlink(path)) 810 die_errno(_("cannot unlink stray '%s'"), path); 811 id->collection->status[variant] &= ~RR_HAS_POSTIMAGE; 812 } 813 id->collection->status[variant] |= RR_HAS_PREIMAGE; 814 fprintf_ln(stderr, _("Recorded preimage for '%s'"), path); 815 + 816 + out: 817 + strbuf_release(&buf); 818 } 819 820 static int do_plain_rerere(struct repository *r, ··· 822 { 823 struct string_list conflict = STRING_LIST_INIT_DUP; 824 struct string_list update = STRING_LIST_INIT_DUP; 825 + struct strbuf buf = STRBUF_INIT; 826 int i; 827 828 find_conflict(r, &conflict); ··· 856 string_list_insert(rr, path)->util = id; 857 858 /* Ensure that the directory exists. */ 859 + mkdir_in_gitdir(rerere_path(&buf, id, NULL)); 860 } 861 862 for (i = 0; i < rr->nr; i++) ··· 867 868 string_list_clear(&conflict, 0); 869 string_list_clear(&update, 0); 870 + strbuf_release(&buf); 871 return write_rr(rr, fd); 872 } 873 ··· 1047 struct rerere_id *id; 1048 unsigned char hash[GIT_MAX_RAWSZ]; 1049 int ret; 1050 + struct strbuf buf = STRBUF_INIT; 1051 struct string_list_item *item; 1052 1053 /* ··· 1071 if (!has_rerere_resolution(id)) 1072 continue; 1073 1074 + handle_cache(istate, path, hash, rerere_path(&buf, id, "thisimage")); 1075 + if (read_mmfile(&cur, rerere_path(&buf, id, "thisimage"))) { 1076 free(cur.ptr); 1077 error(_("failed to update conflicted state in '%s'"), path); 1078 goto fail_exit; ··· 1089 goto fail_exit; 1090 } 1091 1092 + filename = rerere_path(&buf, id, "postimage"); 1093 if (unlink(filename)) { 1094 if (errno == ENOENT) 1095 error(_("no remembered resolution for '%s'"), path); ··· 1103 * conflict in the working tree, run us again to record 1104 * the postimage. 1105 */ 1106 + handle_cache(istate, path, hash, rerere_path(&buf, id, "preimage")); 1107 fprintf_ln(stderr, _("Updated preimage for '%s'"), path); 1108 1109 /* ··· 1114 free_rerere_id(item); 1115 item->util = id; 1116 fprintf(stderr, _("Forgot resolution for '%s'\n"), path); 1117 + strbuf_release(&buf); 1118 return 0; 1119 1120 fail_exit: 1121 + strbuf_release(&buf); 1122 free(id); 1123 return -1; 1124 } ··· 1164 1165 static timestamp_t rerere_created_at(struct rerere_id *id) 1166 { 1167 + struct strbuf buf = STRBUF_INIT; 1168 struct stat st; 1169 + timestamp_t ret; 1170 1171 + ret = stat(rerere_path(&buf, id, "preimage"), &st) ? (time_t) 0 : st.st_mtime; 1172 + 1173 + strbuf_release(&buf); 1174 + return ret; 1175 } 1176 1177 static timestamp_t rerere_last_used_at(struct rerere_id *id) 1178 { 1179 + struct strbuf buf = STRBUF_INIT; 1180 struct stat st; 1181 + timestamp_t ret; 1182 + 1183 + ret = stat(rerere_path(&buf, id, "postimage"), &st) ? (time_t) 0 : st.st_mtime; 1184 1185 + strbuf_release(&buf); 1186 + return ret; 1187 } 1188 1189 /* ··· 1191 */ 1192 static void unlink_rr_item(struct rerere_id *id) 1193 { 1194 + struct strbuf buf = STRBUF_INIT; 1195 + unlink_or_warn(rerere_path(&buf, id, "thisimage")); 1196 remove_variant(id); 1197 id->collection->status[id->variant] = 0; 1198 + strbuf_release(&buf); 1199 } 1200 1201 static void prune_one(struct rerere_id *id, ··· 1293 1294 for (i = 0; i < merge_rr->nr; i++) { 1295 struct rerere_id *id = merge_rr->items[i].util; 1296 + struct strbuf buf = STRBUF_INIT; 1297 + 1298 if (!has_rerere_resolution(id)) { 1299 unlink_rr_item(id); 1300 + rmdir(rerere_path(&buf, id, NULL)); 1301 } 1302 + 1303 + strbuf_release(&buf); 1304 } 1305 unlink_or_warn(git_path_merge_rr(r)); 1306 rollback_lock_file(&write_lock);
+2 -1
rerere.h
··· 32 * path to that filesystem entity. With "file" specified with NULL, 33 * return the path to the directory that houses these files. 34 */ 35 - const char *rerere_path(const struct rerere_id *, const char *file); 36 int rerere_forget(struct repository *, struct pathspec *); 37 int rerere_remaining(struct repository *, struct string_list *); 38 void rerere_clear(struct repository *, struct string_list *);
··· 32 * path to that filesystem entity. With "file" specified with NULL, 33 * return the path to the directory that houses these files. 34 */ 35 + const char *rerere_path(struct strbuf *buf, const struct rerere_id *, 36 + const char *file); 37 int rerere_forget(struct repository *, struct pathspec *); 38 int rerere_remaining(struct repository *, struct string_list *); 39 void rerere_clear(struct repository *, struct string_list *);