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{ 75int fd; 76struct strbuf filename = STRBUF_INIT; 77 78strbuf_addstr(&filename, path); 79if(!(flags & LOCK_NO_DEREF)) 80resolve_symlink(&filename); 81 82strbuf_addstr(&filename, LOCK_SUFFIX); 83 fd =create_tempfile(&lk->tempfile, filename.buf); 84strbuf_release(&filename); 85return fd; 86} 87 88/* 89 * Constants defining the gaps between attempts to lock a file. The 90 * first backoff period is approximately INITIAL_BACKOFF_MS 91 * milliseconds. The longest backoff period is approximately 92 * (BACKOFF_MAX_MULTIPLIER * INITIAL_BACKOFF_MS) milliseconds. 93 */ 94#define INITIAL_BACKOFF_MS 1L 95#define BACKOFF_MAX_MULTIPLIER 1000 96 97/* 98 * Try locking path, retrying with quadratic backoff for at least 99 * timeout_ms milliseconds. If timeout_ms is 0, try locking the file 100 * exactly once. If timeout_ms is -1, try indefinitely. 101 */ 102static intlock_file_timeout(struct lock_file *lk,const char*path, 103int flags,long timeout_ms) 104{ 105int n =1; 106int multiplier =1; 107long remaining_ms =0; 108static int random_initialized =0; 109 110if(timeout_ms ==0) 111returnlock_file(lk, path, flags); 112 113if(!random_initialized) { 114srand((unsigned int)getpid()); 115 random_initialized =1; 116} 117 118if(timeout_ms >0) 119 remaining_ms = timeout_ms; 120 121while(1) { 122long backoff_ms, wait_ms; 123int fd; 124 125 fd =lock_file(lk, path, flags); 126 127if(fd >=0) 128return fd;/* success */ 129else if(errno != EEXIST) 130return-1;/* failure other than lock held */ 131else if(timeout_ms >0&& remaining_ms <=0) 132return-1;/* failure due to timeout */ 133 134 backoff_ms = multiplier * INITIAL_BACKOFF_MS; 135/* back off for between 0.75*backoff_ms and 1.25*backoff_ms */ 136 wait_ms = (750+rand() %500) * backoff_ms /1000; 137sleep_millisec(wait_ms); 138 remaining_ms -= wait_ms; 139 140/* Recursion: (n+1)^2 = n^2 + 2n + 1 */ 141 multiplier +=2*n +1; 142if(multiplier > BACKOFF_MAX_MULTIPLIER) 143 multiplier = BACKOFF_MAX_MULTIPLIER; 144else 145 n++; 146} 147} 148 149voidunable_to_lock_message(const char*path,int err,struct strbuf *buf) 150{ 151if(err == EEXIST) { 152strbuf_addf(buf,_("Unable to create '%s.lock':%s.\n\n" 153"Another git process seems to be running in this repository, e.g.\n" 154"an editor opened by 'git commit'. Please make sure all processes\n" 155"are terminated then try again. If it still fails, a git process\n" 156"may have crashed in this repository earlier:\n" 157"remove the file manually to continue."), 158absolute_path(path),strerror(err)); 159}else 160strbuf_addf(buf,_("Unable to create '%s.lock':%s"), 161absolute_path(path),strerror(err)); 162} 163 164NORETURN voidunable_to_lock_die(const char*path,int err) 165{ 166struct strbuf buf = STRBUF_INIT; 167 168unable_to_lock_message(path, err, &buf); 169die("%s", buf.buf); 170} 171 172/* This should return a meaningful errno on failure */ 173inthold_lock_file_for_update_timeout(struct lock_file *lk,const char*path, 174int flags,long timeout_ms) 175{ 176int fd =lock_file_timeout(lk, path, flags, timeout_ms); 177if(fd <0&& (flags & LOCK_DIE_ON_ERROR)) 178unable_to_lock_die(path, errno); 179return fd; 180} 181 182char*get_locked_file_path(struct lock_file *lk) 183{ 184struct strbuf ret = STRBUF_INIT; 185 186strbuf_addstr(&ret,get_tempfile_path(&lk->tempfile)); 187if(ret.len <= LOCK_SUFFIX_LEN || 188strcmp(ret.buf + ret.len - LOCK_SUFFIX_LEN, LOCK_SUFFIX)) 189die("BUG: get_locked_file_path() called for malformed lock object"); 190/* remove ".lock": */ 191strbuf_setlen(&ret, ret.len - LOCK_SUFFIX_LEN); 192returnstrbuf_detach(&ret, NULL); 193} 194 195intcommit_lock_file(struct lock_file *lk) 196{ 197char*result_path =get_locked_file_path(lk); 198 199if(commit_lock_file_to(lk, result_path)) { 200int save_errno = errno; 201free(result_path); 202 errno = save_errno; 203return-1; 204} 205free(result_path); 206return0; 207}