@matheusbsbs / matheus-bagliano / commits / c3b0dec509
Fork 0

Be more careful about updating refs

This makes write_ref_sha1() more careful: it actually checks the SHA1 of the ref it is updating, and refuses to update a ref with an object that it cannot find. Perhaps more importantly, it also refuses to update a branch head with a non-commit object. I don't quite know *how* the stable series maintainers were able to corrupt their repository to have a HEAD that pointed to a tag rather than a commit object, but they did. Which results in a totally broken repository that cannot be cloned or committed on. So make it harder for people to shoot themselves in the foot like that. The test t1400-update-ref.sh is fixed at the same time, as it assumed that the commands involved in the particular test would not care about corrupted repositories whose refs point at nonexistant bogus objects. That assumption does not hold true anymore. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Linus Torvalds committed Jan 15, 2008 at 15:50 UTC c3b0dec509fe136c5417422f31898b5a4e2d5e02
2 files changed +32 -6
refs.c
+19
@@ -1119,10 +1119,16 @@ static int log_ref_write(const char *ref_name, const unsigned char *old_sha1,
1119 return 0;
1120 }
1121
1122 +static int is_branch(const char *refname)
1123 +{
1124 + return !strcmp(refname, "HEAD") || !prefixcmp(refname, "refs/heads/");
1125 +}
1126 +
1127 int write_ref_sha1(struct ref_lock *lock,
1128 const unsigned char *sha1, const char *logmsg)
1129 {
1130 static char term = '\n';
1131 + struct object *o;
1132
1133 if (!lock)
1134 return -1;
@@ -1130,6 +1136,19 @@ int write_ref_sha1(struct ref_lock *lock,
1136 unlock_ref(lock);
1137 return 0;
1138 }
1139 + o = parse_object(sha1);
1140 + if (!o) {
1141 + error("Trying to write ref %s with nonexistant object %s",
1142 + lock->ref_name, sha1_to_hex(sha1));
1143 + unlock_ref(lock);
1144 + return -1;
1145 + }
1146 + if (o->type != OBJ_COMMIT && is_branch(lock->ref_name)) {
1147 + error("Trying to write non-commit object %s to branch %s",
1148 + sha1_to_hex(sha1), lock->ref_name);
1149 + unlock_ref(lock);
1150 + return -1;
1151 + }
1152 if (write_in_full(lock->lock_fd, sha1_to_hex(sha1), 40) != 40 ||
1153 write_in_full(lock->lock_fd, &term, 1) != 1
1154 || close(lock->lock_fd) < 0) {
t/t1400-update-ref.sh
+13 -6
@@ -7,12 +7,19 @@ test_description='Test git update-ref and basic ref logging'
7 . ./test-lib.sh
8
9 Z=0000000000000000000000000000000000000000
10 -A=1111111111111111111111111111111111111111
11 -B=2222222222222222222222222222222222222222
12 -C=3333333333333333333333333333333333333333
13 -D=4444444444444444444444444444444444444444
14 -E=5555555555555555555555555555555555555555
15 -F=6666666666666666666666666666666666666666
10 +
11 +test_expect_success setup '
12 +
13 + for name in A B C D E F
14 + do
15 + test_tick &&
16 + T=$(git write-tree) &&
17 + sha1=$(echo $name | git commit-tree $T) &&
18 + eval $name=$sha1
19 + done
20 +
21 +'
22 +
23 m=refs/heads/master
24 n_dir=refs/heads/gu
25 n=$n_dir/fixes