1/*2* Copyright (c) 2005, Junio C Hamano3*/4#include "cache.h"56static struct lock_file *lock_file_list;7static const char *alternate_index_output;89static void remove_lock_file(void)10{11pid_t me = getpid();1213while (lock_file_list) {14if (lock_file_list->owner == me &&15lock_file_list->filename[0])16unlink(lock_file_list->filename);17lock_file_list = lock_file_list->next;18}19}2021static void remove_lock_file_on_signal(int signo)22{23remove_lock_file();24signal(SIGINT, SIG_DFL);25raise(signo);26}2728/*29* p = absolute or relative path name30*31* Return a pointer into p showing the beginning of the last path name32* element. If p is empty or the root directory ("/"), just return p.33*/34static char *last_path_elm(char *p)35{36/* r starts pointing to null at the end of the string */37char *r = strchr(p, '\0');3839if (r == p)40return p; /* just return empty string */4142r--; /* back up to last non-null character */4344/* back up past trailing slashes, if any */45while (r > p && *r == '/')46r--;4748/*49* then go backwards until I hit a slash, or the beginning of50* the string51*/52while (r > p && *(r-1) != '/')53r--;54return r;55}565758/* We allow "recursive" symbolic links. Only within reason, though */59#define MAXDEPTH 56061/*62* p = path that may be a symlink63* s = full size of p64*65* If p is a symlink, attempt to overwrite p with a path to the real66* file or directory (which may or may not exist), following a chain of67* symlinks if necessary. Otherwise, leave p unmodified.68*69* This is a best-effort routine. If an error occurs, p will either be70* left unmodified or will name a different symlink in a symlink chain71* that started with p's initial contents.72*73* Always returns p.74*/7576static char *resolve_symlink(char *p, size_t s)77{78int depth = MAXDEPTH;7980while (depth--) {81char link[PATH_MAX];82int link_len = readlink(p, link, sizeof(link));83if (link_len < 0) {84/* not a symlink anymore */85return p;86}87else if (link_len < sizeof(link))88/* readlink() never null-terminates */89link[link_len] = '\0';90else {91warning("%s: symlink too long", p);92return p;93}9495if (link[0] == '/') {96/* absolute path simply replaces p */97if (link_len < s)98strcpy(p, link);99else {100warning("%s: symlink too long", p);101return p;102}103} else {104/*105* link is a relative path, so I must replace the106* last element of p with it.107*/108char *r = (char*)last_path_elm(p);109if (r - p + link_len < s)110strcpy(r, link);111else {112warning("%s: symlink too long", p);113return p;114}115}116}117return p;118}119120121static int lock_file(struct lock_file *lk, const char *path)122{123int fd;124125if (strlen(path) >= sizeof(lk->filename)) return -1;126strcpy(lk->filename, path);127/*128* subtract 5 from size to make sure there's room for adding129* ".lock" for the lock file name130*/131resolve_symlink(lk->filename, sizeof(lk->filename)-5);132strcat(lk->filename, ".lock");133fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666);134if (0 <= fd) {135if (!lock_file_list) {136signal(SIGINT, remove_lock_file_on_signal);137atexit(remove_lock_file);138}139lk->owner = getpid();140if (!lk->on_list) {141lk->next = lock_file_list;142lock_file_list = lk;143lk->on_list = 1;144}145if (adjust_shared_perm(lk->filename))146return error("cannot fix permission bits on %s",147lk->filename);148}149else150lk->filename[0] = 0;151return fd;152}153154int hold_lock_file_for_update(struct lock_file *lk, const char *path, int die_on_error)155{156int fd = lock_file(lk, path);157if (fd < 0 && die_on_error)158die("unable to create '%s.lock': %s", path, strerror(errno));159return fd;160}161162int commit_lock_file(struct lock_file *lk)163{164char result_file[PATH_MAX];165int i;166strcpy(result_file, lk->filename);167i = strlen(result_file) - 5; /* .lock */168result_file[i] = 0;169i = rename(lk->filename, result_file);170lk->filename[0] = 0;171return i;172}173174int hold_locked_index(struct lock_file *lk, int die_on_error)175{176return hold_lock_file_for_update(lk, get_index_file(), die_on_error);177}178179void set_alternate_index_output(const char *name)180{181alternate_index_output = name;182}183184int commit_locked_index(struct lock_file *lk)185{186if (alternate_index_output) {187int result = rename(lk->filename, alternate_index_output);188lk->filename[0] = 0;189return result;190}191else192return commit_lock_file(lk);193}194195void rollback_lock_file(struct lock_file *lk)196{197if (lk->filename[0])198unlink(lk->filename);199lk->filename[0] = 0;200}