4 static const char git_update_ref_usage
[] = "git-update-ref <refname> <value> [<oldval>]";
6 static int re_verify(const char *path
, unsigned char *oldsha1
, unsigned char *currsha1
)
9 int fd
= open(path
, O_RDONLY
), nr
;
12 nr
= read(fd
, buf
, 40);
14 if (nr
!= 40 || get_sha1_hex(buf
, currsha1
) < 0)
16 return memcmp(oldsha1
, currsha1
, 20) ? -1 : 0;
19 int main(int argc
, char **argv
)
22 const char *refname
, *value
, *oldval
, *path
;
24 unsigned char sha1
[20], oldsha1
[20], currsha1
[20];
27 setup_git_directory();
28 git_config(git_default_config
);
29 if (argc
< 3 || argc
> 4)
30 usage(git_update_ref_usage
);
35 if (get_sha1(value
, sha1
) < 0)
36 die("%s: not a valid SHA1", value
);
37 memset(oldsha1
, 0, 20);
38 if (oldval
&& get_sha1(oldval
, oldsha1
) < 0)
39 die("%s: not a valid old SHA1", oldval
);
41 path
= resolve_ref(git_path("%s", refname
), currsha1
, !!oldval
);
43 die("No such ref: %s", refname
);
46 if (memcmp(currsha1
, oldsha1
, 20))
47 die("Ref %s is at %s but expected %s", refname
, sha1_to_hex(currsha1
), sha1_to_hex(oldsha1
));
49 if (!memcmp(oldsha1
, sha1
, 20))
53 lockpath
= mkpath("%s.lock", path
);
54 if (safe_create_leading_directories(lockpath
) < 0)
55 die("Unable to create all of %s", lockpath
);
57 fd
= open(lockpath
, O_CREAT
| O_EXCL
| O_WRONLY
, 0666);
59 die("Unable to create %s", lockpath
);
60 hex
= sha1_to_hex(sha1
);
62 written
= write(fd
, hex
, 41);
66 die("Unable to write to %s", lockpath
);
70 * Re-read the ref after getting the lock to verify
72 if (oldval
&& re_verify(path
, oldsha1
, currsha1
) < 0) {
74 die("Ref lock failed");
78 * Finally, replace the old ref with the new one
80 if (rename(lockpath
, path
) < 0) {
82 die("Unable to create %s", path
);