pseudorefs: create and use pseudoref update and delete functions

Pseudorefs should not be updated through the ref transaction API, because alternate ref backends still need to store pseudorefs in GIT_DIR (instead of wherever they store refs). Instead, change update_ref and delete_ref to call pseudoref-specific functions. Signed-off-by: David Turner <dturner@twopensource.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

David Turner committed Jul 31, 2015 at 02:06 UTC 74ec19d4be76c52b872e6f95b39ecbfbe5d9100c
1 file changed +93 -8
refs.c
+93 -8
@@ -2847,11 +2847,87 @@ enum ref_type ref_type(const char *refname)
2847 return REF_TYPE_NORMAL;
2848 }
2849
2850 +static int write_pseudoref(const char *pseudoref, const unsigned char *sha1,
2851 + const unsigned char *old_sha1, struct strbuf *err)
2852 +{
2853 + const char *filename;
2854 + int fd;
2855 + static struct lock_file lock;
2856 + struct strbuf buf = STRBUF_INIT;
2857 + int ret = -1;
2858 +
2859 + strbuf_addf(&buf, "%s\n", sha1_to_hex(sha1));
2860 +
2861 + filename = git_path("%s", pseudoref);
2862 + fd = hold_lock_file_for_update(&lock, filename, LOCK_DIE_ON_ERROR);
2863 + if (fd < 0) {
2864 + strbuf_addf(err, "Could not open '%s' for writing: %s",
2865 + filename, strerror(errno));
2866 + return -1;
2867 + }
2868 +
2869 + if (old_sha1) {
2870 + unsigned char actual_old_sha1[20];
2871 + read_ref(pseudoref, actual_old_sha1);
2872 + if (hashcmp(actual_old_sha1, old_sha1)) {
2873 + strbuf_addf(err, "Unexpected sha1 when writing %s", pseudoref);
2874 + rollback_lock_file(&lock);
2875 + goto done;
2876 + }
2877 + }
2878 +
2879 + if (write_in_full(fd, buf.buf, buf.len) != buf.len) {
2880 + strbuf_addf(err, "Could not write to '%s'", filename);
2881 + rollback_lock_file(&lock);
2882 + goto done;
2883 + }
2884 +
2885 + commit_lock_file(&lock);
2886 + ret = 0;
2887 +done:
2888 + strbuf_release(&buf);
2889 + return ret;
2890 +}
2891 +
2892 +static int delete_pseudoref(const char *pseudoref, const unsigned char *old_sha1)
2893 +{
2894 + static struct lock_file lock;
2895 + const char *filename;
2896 +
2897 + filename = git_path("%s", pseudoref);
2898 +
2899 + if (old_sha1 && !is_null_sha1(old_sha1)) {
2900 + int fd;
2901 + unsigned char actual_old_sha1[20];
2902 +
2903 + fd = hold_lock_file_for_update(&lock, filename,
2904 + LOCK_DIE_ON_ERROR);
2905 + if (fd < 0)
2906 + die_errno(_("Could not open '%s' for writing"), filename);
2907 + read_ref(pseudoref, actual_old_sha1);
2908 + if (hashcmp(actual_old_sha1, old_sha1)) {
2909 + warning("Unexpected sha1 when deleting %s", pseudoref);
2910 + rollback_lock_file(&lock);
2911 + return -1;
2912 + }
2913 +
2914 + unlink(filename);
2915 + rollback_lock_file(&lock);
2916 + } else {
2917 + unlink(filename);
2918 + }
2919 +
2920 + return 0;
2921 +}
2922 +
2923 int delete_ref(const char *refname, const unsigned char *sha1, unsigned int flags)
2924 {
2925 struct ref_transaction *transaction;
2926 struct strbuf err = STRBUF_INIT;
2927
2928 + if (ref_type(refname) == REF_TYPE_PSEUDOREF)
2929 + return delete_pseudoref(refname, sha1);
2930 +
2931 transaction = ref_transaction_begin(&err);
2932 if (!transaction ||
2933 ref_transaction_delete(transaction, refname,
@@ -3908,17 +3984,25 @@ int update_ref(const char *msg, const char *refname,
3984 const unsigned char *new_sha1, const unsigned char *old_sha1,
3985 unsigned int flags, enum action_on_err onerr)
3986 {
3911 - struct ref_transaction *t;
3987 + struct ref_transaction *t = NULL;
3988 struct strbuf err = STRBUF_INIT;
3989 + int ret = 0;
3990
3914 - t = ref_transaction_begin(&err);
3915 - if (!t ||
3916 - ref_transaction_update(t, refname, new_sha1, old_sha1,
3917 - flags, msg, &err) ||
3918 - ref_transaction_commit(t, &err)) {
3991 + if (ref_type(refname) == REF_TYPE_PSEUDOREF) {
3992 + ret = write_pseudoref(refname, new_sha1, old_sha1, &err);
3993 + } else {
3994 + t = ref_transaction_begin(&err);
3995 + if (!t ||
3996 + ref_transaction_update(t, refname, new_sha1, old_sha1,
3997 + flags, msg, &err) ||
3998 + ref_transaction_commit(t, &err)) {
3999 + ret = 1;
4000 + ref_transaction_free(t);
4001 + }
4002 + }
4003 + if (ret) {
4004 const char *str = "update_ref failed for ref '%s': %s";
4005
3921 - ref_transaction_free(t);
4006 switch (onerr) {
4007 case UPDATE_REFS_MSG_ON_ERR:
4008 error(str, refname, err.buf);
@@ -3933,7 +4017,8 @@ int update_ref(const char *msg, const char *refname,
4017 return 1;
4018 }
4019 strbuf_release(&err);
3936 - ref_transaction_free(t);
4020 + if (t)
4021 + ref_transaction_free(t);
4022 return 0;
4023 }
4024