]>
Commit | Line | Data |
---|---|---|
66bf85a4 LT |
1 | #include "cache.h" |
2 | #include "refs.h" | |
152da3df | 3 | #include <ctype.h> |
66bf85a4 LT |
4 | |
5 | static const char git_update_ref_usage[] = "git-update-ref <refname> <value> [<oldval>]"; | |
6 | ||
152da3df JH |
7 | static int re_verify(const char *path, unsigned char *oldsha1, unsigned char *currsha1) |
8 | { | |
9 | char buf[40]; | |
10 | int fd = open(path, O_RDONLY), nr; | |
11 | if (fd < 0) | |
12 | return -1; | |
13 | nr = read(fd, buf, 40); | |
14 | close(fd); | |
15 | if (nr != 40 || get_sha1_hex(buf, currsha1) < 0) | |
16 | return -1; | |
17 | return memcmp(oldsha1, currsha1, 20) ? -1 : 0; | |
18 | } | |
19 | ||
66bf85a4 LT |
20 | int main(int argc, char **argv) |
21 | { | |
22 | char *hex; | |
23 | const char *refname, *value, *oldval, *path, *lockpath; | |
24 | unsigned char sha1[20], oldsha1[20], currsha1[20]; | |
25 | int fd, written; | |
26 | ||
27 | setup_git_directory(); | |
28 | if (argc < 3 || argc > 4) | |
29 | usage(git_update_ref_usage); | |
30 | ||
31 | refname = argv[1]; | |
32 | value = argv[2]; | |
33 | oldval = argv[3]; | |
34 | if (get_sha1(value, sha1) < 0) | |
35 | die("%s: not a valid SHA1", value); | |
36 | memset(oldsha1, 0, 20); | |
37 | if (oldval && get_sha1(oldval, oldsha1) < 0) | |
38 | die("%s: not a valid old SHA1", oldval); | |
39 | ||
a876ed83 | 40 | path = resolve_ref(git_path("%s", refname), currsha1, !!oldval); |
66bf85a4 LT |
41 | if (!path) |
42 | die("No such ref: %s", refname); | |
43 | ||
44 | if (oldval) { | |
45 | if (memcmp(currsha1, oldsha1, 20)) | |
46 | die("Ref %s changed to %s", refname, sha1_to_hex(currsha1)); | |
47 | /* Nothing to do? */ | |
48 | if (!memcmp(oldsha1, sha1, 20)) | |
49 | exit(0); | |
50 | } | |
51 | path = strdup(path); | |
52 | lockpath = mkpath("%s.lock", path); | |
53 | ||
54 | fd = open(lockpath, O_CREAT | O_EXCL | O_WRONLY, 0666); | |
55 | if (fd < 0) | |
56 | die("Unable to create %s", lockpath); | |
57 | hex = sha1_to_hex(sha1); | |
58 | hex[40] = '\n'; | |
59 | written = write(fd, hex, 41); | |
60 | close(fd); | |
61 | if (written != 41) { | |
62 | unlink(lockpath); | |
63 | die("Unable to write to %s", lockpath); | |
64 | } | |
65 | ||
66 | /* | |
152da3df | 67 | * Re-read the ref after getting the lock to verify |
66bf85a4 | 68 | */ |
152da3df JH |
69 | if (oldval && re_verify(path, oldsha1, currsha1) < 0) { |
70 | unlink(lockpath); | |
71 | die("Ref lock failed"); | |
72 | } | |
66bf85a4 | 73 | |
152da3df JH |
74 | /* |
75 | * Finally, replace the old ref with the new one | |
76 | */ | |
66bf85a4 LT |
77 | if (rename(lockpath, path) < 0) { |
78 | unlink(lockpath); | |
79 | die("Unable to create %s", path); | |
80 | } | |
81 | return 0; | |
82 | } |