diff options
Diffstat (limited to 'lockfile.c')
-rw-r--r-- | lockfile.c | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/lockfile.c b/lockfile.c new file mode 100644 index 0000000000..9202472498 --- /dev/null +++ b/lockfile.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2005, Junio C Hamano + */ +#include "cache.h" + +static struct lock_file *lock_file_list; +static const char *alternate_index_output; + +static void remove_lock_file(void) +{ + pid_t me = getpid(); + + while (lock_file_list) { + if (lock_file_list->owner == me && + lock_file_list->filename[0]) + unlink(lock_file_list->filename); + lock_file_list = lock_file_list->next; + } +} + +static void remove_lock_file_on_signal(int signo) +{ + remove_lock_file(); + signal(SIGINT, SIG_DFL); + raise(signo); +} + +static int lock_file(struct lock_file *lk, const char *path) +{ + int fd; + struct stat st; + + if ((!lstat(path, &st)) && S_ISLNK(st.st_mode)) { + ssize_t sz; + static char target[PATH_MAX]; + sz = readlink(path, target, sizeof(target)); + if (sz < 0) + warning("Cannot readlink %s", path); + else if (target[0] != '/') + warning("Cannot lock target of relative symlink %s", path); + else + path = target; + } + sprintf(lk->filename, "%s.lock", path); + fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666); + if (0 <= fd) { + if (!lock_file_list) { + signal(SIGINT, remove_lock_file_on_signal); + atexit(remove_lock_file); + } + lk->owner = getpid(); + if (!lk->on_list) { + lk->next = lock_file_list; + lock_file_list = lk; + lk->on_list = 1; + } + if (adjust_shared_perm(lk->filename)) + return error("cannot fix permission bits on %s", + lk->filename); + } + else + lk->filename[0] = 0; + return fd; +} + +int hold_lock_file_for_update(struct lock_file *lk, const char *path, int die_on_error) +{ + int fd = lock_file(lk, path); + if (fd < 0 && die_on_error) + die("unable to create '%s.lock': %s", path, strerror(errno)); + return fd; +} + +int commit_lock_file(struct lock_file *lk) +{ + char result_file[PATH_MAX]; + int i; + strcpy(result_file, lk->filename); + i = strlen(result_file) - 5; /* .lock */ + result_file[i] = 0; + i = rename(lk->filename, result_file); + lk->filename[0] = 0; + return i; +} + +int hold_locked_index(struct lock_file *lk, int die_on_error) +{ + return hold_lock_file_for_update(lk, get_index_file(), die_on_error); +} + +void set_alternate_index_output(const char *name) +{ + alternate_index_output = name; +} + +int commit_locked_index(struct lock_file *lk) +{ + if (alternate_index_output) { + int result = rename(lk->filename, alternate_index_output); + lk->filename[0] = 0; + return result; + } + else + return commit_lock_file(lk); +} + +void rollback_lock_file(struct lock_file *lk) +{ + if (lk->filename[0]) + unlink(lk->filename); + lk->filename[0] = 0; +} |