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]) {16close(lock_file_list->fd);17unlink(lock_file_list->filename);18}19lock_file_list = lock_file_list->next;20}21}2223static void remove_lock_file_on_signal(int signo)24{25remove_lock_file();26signal(SIGINT, SIG_DFL);27raise(signo);28}2930/*31* p = absolute or relative path name32*33* Return a pointer into p showing the beginning of the last path name34* element. If p is empty or the root directory ("/"), just return p.35*/36static char *last_path_elm(char *p)37{38/* r starts pointing to null at the end of the string */39char *r = strchr(p, '\0');4041if (r == p)42return p; /* just return empty string */4344r--; /* back up to last non-null character */4546/* back up past trailing slashes, if any */47while (r > p && *r == '/')48r--;4950/*51* then go backwards until I hit a slash, or the beginning of52* the string53*/54while (r > p && *(r-1) != '/')55r--;56return r;57}585960/* We allow "recursive" symbolic links. Only within reason, though */61#define MAXDEPTH 56263/*64* p = path that may be a symlink65* s = full size of p66*67* If p is a symlink, attempt to overwrite p with a path to the real68* file or directory (which may or may not exist), following a chain of69* symlinks if necessary. Otherwise, leave p unmodified.70*71* This is a best-effort routine. If an error occurs, p will either be72* left unmodified or will name a different symlink in a symlink chain73* that started with p's initial contents.74*75* Always returns p.76*/7778static char *resolve_symlink(char *p, size_t s)79{80int depth = MAXDEPTH;8182while (depth--) {83char link[PATH_MAX];84int link_len = readlink(p, link, sizeof(link));85if (link_len < 0) {86/* not a symlink anymore */87return p;88}89else if (link_len < sizeof(link))90/* readlink() never null-terminates */91link[link_len] = '\0';92else {93warning("%s: symlink too long", p);94return p;95}9697if (is_absolute_path(link)) {98/* absolute path simply replaces p */99if (link_len < s)100strcpy(p, link);101else {102warning("%s: symlink too long", p);103return p;104}105} else {106/*107* link is a relative path, so I must replace the108* last element of p with it.109*/110char *r = (char*)last_path_elm(p);111if (r - p + link_len < s)112strcpy(r, link);113else {114warning("%s: symlink too long", p);115return p;116}117}118}119return p;120}121122123static int lock_file(struct lock_file *lk, const char *path)124{125if (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");133lk->fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666);134if (0 <= lk->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 lk->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;166close(lk->fd);167strcpy(result_file, lk->filename);168i = strlen(result_file) - 5; /* .lock */169result_file[i] = 0;170i = rename(lk->filename, result_file);171lk->filename[0] = 0;172return i;173}174175int hold_locked_index(struct lock_file *lk, int die_on_error)176{177return hold_lock_file_for_update(lk, get_index_file(), die_on_error);178}179180void set_alternate_index_output(const char *name)181{182alternate_index_output = name;183}184185int commit_locked_index(struct lock_file *lk)186{187if (alternate_index_output) {188int result = rename(lk->filename, alternate_index_output);189lk->filename[0] = 0;190return result;191}192else193return commit_lock_file(lk);194}195196void rollback_lock_file(struct lock_file *lk)197{198if (lk->filename[0]) {199close(lk->fd);200unlink(lk->filename);201}202lk->filename[0] = 0;203}