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