Linus Torvalds | 66bf85a | 2005-09-25 11:43:05 -0700 | [diff] [blame] | 1 | #include "cache.h" |
| 2 | #include "refs.h" |
| 3 | |
| 4 | static const char git_update_ref_usage[] = "git-update-ref <refname> <value> [<oldval>]"; |
| 5 | |
Junio C Hamano | 152da3d | 2005-09-25 16:28:51 -0700 | [diff] [blame] | 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 | |
Linus Torvalds | 66bf85a | 2005-09-25 11:43:05 -0700 | [diff] [blame] | 19 | int main(int argc, char **argv) |
| 20 | { |
| 21 | char *hex; |
Alex Riesen | 08db81a | 2005-11-14 23:10:59 +0100 | [diff] [blame] | 22 | const char *refname, *value, *oldval, *path; |
| 23 | char *lockpath; |
Linus Torvalds | 66bf85a | 2005-09-25 11:43:05 -0700 | [diff] [blame] | 24 | unsigned char sha1[20], oldsha1[20], currsha1[20]; |
| 25 | int fd, written; |
| 26 | |
| 27 | setup_git_directory(); |
Junio C Hamano | 84a9b58 | 2006-03-23 23:41:18 -0800 | [diff] [blame] | 28 | git_config(git_default_config); |
Linus Torvalds | 66bf85a | 2005-09-25 11:43:05 -0700 | [diff] [blame] | 29 | if (argc < 3 || argc > 4) |
| 30 | usage(git_update_ref_usage); |
| 31 | |
| 32 | refname = argv[1]; |
| 33 | value = argv[2]; |
| 34 | oldval = argv[3]; |
| 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); |
| 40 | |
Junio C Hamano | a876ed8 | 2005-09-30 14:08:25 -0700 | [diff] [blame] | 41 | path = resolve_ref(git_path("%s", refname), currsha1, !!oldval); |
Linus Torvalds | 66bf85a | 2005-09-25 11:43:05 -0700 | [diff] [blame] | 42 | if (!path) |
| 43 | die("No such ref: %s", refname); |
| 44 | |
| 45 | if (oldval) { |
| 46 | if (memcmp(currsha1, oldsha1, 20)) |
Petr Baudis | ad7db62 | 2005-11-10 20:55:13 +0100 | [diff] [blame] | 47 | die("Ref %s is at %s but expected %s", refname, sha1_to_hex(currsha1), sha1_to_hex(oldsha1)); |
Linus Torvalds | 66bf85a | 2005-09-25 11:43:05 -0700 | [diff] [blame] | 48 | /* Nothing to do? */ |
| 49 | if (!memcmp(oldsha1, sha1, 20)) |
| 50 | exit(0); |
| 51 | } |
| 52 | path = strdup(path); |
| 53 | lockpath = mkpath("%s.lock", path); |
Alex Riesen | 08db81a | 2005-11-14 23:10:59 +0100 | [diff] [blame] | 54 | if (safe_create_leading_directories(lockpath) < 0) |
| 55 | die("Unable to create all of %s", lockpath); |
Linus Torvalds | 66bf85a | 2005-09-25 11:43:05 -0700 | [diff] [blame] | 56 | |
| 57 | fd = open(lockpath, O_CREAT | O_EXCL | O_WRONLY, 0666); |
| 58 | if (fd < 0) |
| 59 | die("Unable to create %s", lockpath); |
| 60 | hex = sha1_to_hex(sha1); |
| 61 | hex[40] = '\n'; |
| 62 | written = write(fd, hex, 41); |
| 63 | close(fd); |
| 64 | if (written != 41) { |
| 65 | unlink(lockpath); |
| 66 | die("Unable to write to %s", lockpath); |
| 67 | } |
| 68 | |
| 69 | /* |
Junio C Hamano | 152da3d | 2005-09-25 16:28:51 -0700 | [diff] [blame] | 70 | * Re-read the ref after getting the lock to verify |
Linus Torvalds | 66bf85a | 2005-09-25 11:43:05 -0700 | [diff] [blame] | 71 | */ |
Junio C Hamano | 152da3d | 2005-09-25 16:28:51 -0700 | [diff] [blame] | 72 | if (oldval && re_verify(path, oldsha1, currsha1) < 0) { |
| 73 | unlink(lockpath); |
| 74 | die("Ref lock failed"); |
| 75 | } |
Linus Torvalds | 66bf85a | 2005-09-25 11:43:05 -0700 | [diff] [blame] | 76 | |
Junio C Hamano | 152da3d | 2005-09-25 16:28:51 -0700 | [diff] [blame] | 77 | /* |
| 78 | * Finally, replace the old ref with the new one |
| 79 | */ |
Linus Torvalds | 66bf85a | 2005-09-25 11:43:05 -0700 | [diff] [blame] | 80 | if (rename(lockpath, path) < 0) { |
| 81 | unlink(lockpath); |
| 82 | die("Unable to create %s", path); |
| 83 | } |
| 84 | return 0; |
| 85 | } |