You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
84 lines
2.0 KiB
84 lines
2.0 KiB
#include "cache.h" |
|
#include "refs.h" |
|
|
|
static const char git_update_ref_usage[] = "git-update-ref <refname> <value> [<oldval>]"; |
|
|
|
static int re_verify(const char *path, unsigned char *oldsha1, unsigned char *currsha1) |
|
{ |
|
char buf[40]; |
|
int fd = open(path, O_RDONLY), nr; |
|
if (fd < 0) |
|
return -1; |
|
nr = read(fd, buf, 40); |
|
close(fd); |
|
if (nr != 40 || get_sha1_hex(buf, currsha1) < 0) |
|
return -1; |
|
return memcmp(oldsha1, currsha1, 20) ? -1 : 0; |
|
} |
|
|
|
int main(int argc, char **argv) |
|
{ |
|
char *hex; |
|
const char *refname, *value, *oldval, *path; |
|
char *lockpath; |
|
unsigned char sha1[20], oldsha1[20], currsha1[20]; |
|
int fd, written; |
|
|
|
setup_git_directory(); |
|
if (argc < 3 || argc > 4) |
|
usage(git_update_ref_usage); |
|
|
|
refname = argv[1]; |
|
value = argv[2]; |
|
oldval = argv[3]; |
|
if (get_sha1(value, sha1) < 0) |
|
die("%s: not a valid SHA1", value); |
|
memset(oldsha1, 0, 20); |
|
if (oldval && get_sha1(oldval, oldsha1) < 0) |
|
die("%s: not a valid old SHA1", oldval); |
|
|
|
path = resolve_ref(git_path("%s", refname), currsha1, !!oldval); |
|
if (!path) |
|
die("No such ref: %s", refname); |
|
|
|
if (oldval) { |
|
if (memcmp(currsha1, oldsha1, 20)) |
|
die("Ref %s is at %s but expected %s", refname, sha1_to_hex(currsha1), sha1_to_hex(oldsha1)); |
|
/* Nothing to do? */ |
|
if (!memcmp(oldsha1, sha1, 20)) |
|
exit(0); |
|
} |
|
path = strdup(path); |
|
lockpath = mkpath("%s.lock", path); |
|
if (safe_create_leading_directories(lockpath) < 0) |
|
die("Unable to create all of %s", lockpath); |
|
|
|
fd = open(lockpath, O_CREAT | O_EXCL | O_WRONLY, 0666); |
|
if (fd < 0) |
|
die("Unable to create %s", lockpath); |
|
hex = sha1_to_hex(sha1); |
|
hex[40] = '\n'; |
|
written = write(fd, hex, 41); |
|
close(fd); |
|
if (written != 41) { |
|
unlink(lockpath); |
|
die("Unable to write to %s", lockpath); |
|
} |
|
|
|
/* |
|
* Re-read the ref after getting the lock to verify |
|
*/ |
|
if (oldval && re_verify(path, oldsha1, currsha1) < 0) { |
|
unlink(lockpath); |
|
die("Ref lock failed"); |
|
} |
|
|
|
/* |
|
* Finally, replace the old ref with the new one |
|
*/ |
|
if (rename(lockpath, path) < 0) { |
|
unlink(lockpath); |
|
die("Unable to create %s", path); |
|
} |
|
return 0; |
|
}
|
|
|