1/* 2 * Copyright (c) 2005, Junio C Hamano 3 */ 4 5#include"cache.h" 6#include"lockfile.h" 7 8/* 9 * path = absolute or relative path name 10 * 11 * Remove the last path name element from path (leaving the preceding 12 * "/", if any). If path is empty or the root directory ("/"), set 13 * path to the empty string. 14 */ 15static voidtrim_last_path_component(struct strbuf *path) 16{ 17int i = path->len; 18 19/* back up past trailing slashes, if any */ 20while(i && path->buf[i -1] =='/') 21 i--; 22 23/* 24 * then go backwards until a slash, or the beginning of the 25 * string 26 */ 27while(i && path->buf[i -1] !='/') 28 i--; 29 30strbuf_setlen(path, i); 31} 32 33 34/* We allow "recursive" symbolic links. Only within reason, though */ 35#define MAXDEPTH 5 36 37/* 38 * path contains a path that might be a symlink. 39 * 40 * If path is a symlink, attempt to overwrite it with a path to the 41 * real file or directory (which may or may not exist), following a 42 * chain of symlinks if necessary. Otherwise, leave path unmodified. 43 * 44 * This is a best-effort routine. If an error occurs, path will 45 * either be left unmodified or will name a different symlink in a 46 * symlink chain that started with the original path. 47 */ 48static voidresolve_symlink(struct strbuf *path) 49{ 50int depth = MAXDEPTH; 51static struct strbuf link = STRBUF_INIT; 52 53while(depth--) { 54if(strbuf_readlink(&link, path->buf, path->len) <0) 55break; 56 57if(is_absolute_path(link.buf)) 58/* absolute path simply replaces p */ 59strbuf_reset(path); 60else 61/* 62 * link is a relative path, so replace the 63 * last element of p with it. 64 */ 65trim_last_path_component(path); 66 67strbuf_addbuf(path, &link); 68} 69strbuf_reset(&link); 70} 71 72/* Make sure errno contains a meaningful value on error */ 73static intlock_file(struct lock_file *lk,const char*path,int flags) 74{ 75struct strbuf filename = STRBUF_INIT; 76 77strbuf_addstr(&filename, path); 78if(!(flags & LOCK_NO_DEREF)) 79resolve_symlink(&filename); 80 81strbuf_addstr(&filename, LOCK_SUFFIX); 82 lk->tempfile =create_tempfile(filename.buf); 83strbuf_release(&filename); 84return lk->tempfile ? lk->tempfile->fd : -1; 85} 86 87/* 88 * Constants defining the gaps between attempts to lock a file. The 89 * first backoff period is approximately INITIAL_BACKOFF_MS 90 * milliseconds. The longest backoff period is approximately 91 * (BACKOFF_MAX_MULTIPLIER * INITIAL_BACKOFF_MS) milliseconds. 92 */ 93#define INITIAL_BACKOFF_MS 1L 94#define BACKOFF_MAX_MULTIPLIER 1000 95 96/* 97 * Try locking path, retrying with quadratic backoff for at least 98 * timeout_ms milliseconds. If timeout_ms is 0, try locking the file 99 * exactly once. If timeout_ms is -1, try indefinitely. 100 */ 101static intlock_file_timeout(struct lock_file *lk,const char*path, 102int flags,long timeout_ms) 103{ 104int n =1; 105int multiplier =1; 106long remaining_ms =0; 107static int random_initialized =0; 108 109if(timeout_ms ==0) 110returnlock_file(lk, path, flags); 111 112if(!random_initialized) { 113srand((unsigned int)getpid()); 114 random_initialized =1; 115} 116 117if(timeout_ms >0) 118 remaining_ms = timeout_ms; 119 120while(1) { 121long backoff_ms, wait_ms; 122int fd; 123 124 fd =lock_file(lk, path, flags); 125 126if(fd >=0) 127return fd;/* success */ 128else if(errno != EEXIST) 129return-1;/* failure other than lock held */ 130else if(timeout_ms >0&& remaining_ms <=0) 131return-1;/* failure due to timeout */ 132 133 backoff_ms = multiplier * INITIAL_BACKOFF_MS; 134/* back off for between 0.75*backoff_ms and 1.25*backoff_ms */ 135 wait_ms = (750+rand() %500) * backoff_ms /1000; 136sleep_millisec(wait_ms); 137 remaining_ms -= wait_ms; 138 139/* Recursion: (n+1)^2 = n^2 + 2n + 1 */ 140 multiplier +=2*n +1; 141if(multiplier > BACKOFF_MAX_MULTIPLIER) 142 multiplier = BACKOFF_MAX_MULTIPLIER; 143else 144 n++; 145} 146} 147 148voidunable_to_lock_message(const char*path,int err,struct strbuf *buf) 149{ 150if(err == EEXIST) { 151strbuf_addf(buf,_("Unable to create '%s.lock':%s.\n\n" 152"Another git process seems to be running in this repository, e.g.\n" 153"an editor opened by 'git commit'. Please make sure all processes\n" 154"are terminated then try again. If it still fails, a git process\n" 155"may have crashed in this repository earlier:\n" 156"remove the file manually to continue."), 157absolute_path(path),strerror(err)); 158}else 159strbuf_addf(buf,_("Unable to create '%s.lock':%s"), 160absolute_path(path),strerror(err)); 161} 162 163NORETURN voidunable_to_lock_die(const char*path,int err) 164{ 165struct strbuf buf = STRBUF_INIT; 166 167unable_to_lock_message(path, err, &buf); 168die("%s", buf.buf); 169} 170 171/* This should return a meaningful errno on failure */ 172inthold_lock_file_for_update_timeout(struct lock_file *lk,const char*path, 173int flags,long timeout_ms) 174{ 175int fd =lock_file_timeout(lk, path, flags, timeout_ms); 176if(fd <0) { 177if(flags & LOCK_DIE_ON_ERROR) 178unable_to_lock_die(path, errno); 179if(flags & LOCK_REPORT_ON_ERROR) { 180struct strbuf buf = STRBUF_INIT; 181unable_to_lock_message(path, errno, &buf); 182error("%s", buf.buf); 183strbuf_release(&buf); 184} 185} 186return fd; 187} 188 189char*get_locked_file_path(struct lock_file *lk) 190{ 191struct strbuf ret = STRBUF_INIT; 192 193strbuf_addstr(&ret,get_tempfile_path(lk->tempfile)); 194if(ret.len <= LOCK_SUFFIX_LEN || 195strcmp(ret.buf + ret.len - LOCK_SUFFIX_LEN, LOCK_SUFFIX)) 196BUG("get_locked_file_path() called for malformed lock object"); 197/* remove ".lock": */ 198strbuf_setlen(&ret, ret.len - LOCK_SUFFIX_LEN); 199returnstrbuf_detach(&ret, NULL); 200} 201 202intcommit_lock_file(struct lock_file *lk) 203{ 204char*result_path =get_locked_file_path(lk); 205 206if(commit_lock_file_to(lk, result_path)) { 207int save_errno = errno; 208free(result_path); 209 errno = save_errno; 210return-1; 211} 212free(result_path); 213return0; 214}