1/* 2 * Copyright (c) 2005, Junio C Hamano 3 */ 4#include"cache.h" 5#include"sigchain.h" 6 7static struct lock_file *lock_file_list; 8static const char*alternate_index_output; 9 10static voidremove_lock_file(void) 11{ 12 pid_t me =getpid(); 13 14while(lock_file_list) { 15if(lock_file_list->owner == me && 16 lock_file_list->filename[0]) { 17if(lock_file_list->fd >=0) 18close(lock_file_list->fd); 19unlink(lock_file_list->filename); 20} 21 lock_file_list = lock_file_list->next; 22} 23} 24 25static voidremove_lock_file_on_signal(int signo) 26{ 27remove_lock_file(); 28sigchain_pop(signo); 29raise(signo); 30} 31 32/* 33 * p = absolute or relative path name 34 * 35 * Return a pointer into p showing the beginning of the last path name 36 * element. If p is empty or the root directory ("/"), just return p. 37 */ 38static char*last_path_elm(char*p) 39{ 40/* r starts pointing to null at the end of the string */ 41char*r =strchr(p,'\0'); 42 43if(r == p) 44return p;/* just return empty string */ 45 46 r--;/* back up to last non-null character */ 47 48/* back up past trailing slashes, if any */ 49while(r > p && *r =='/') 50 r--; 51 52/* 53 * then go backwards until I hit a slash, or the beginning of 54 * the string 55 */ 56while(r > p && *(r-1) !='/') 57 r--; 58return r; 59} 60 61 62/* We allow "recursive" symbolic links. Only within reason, though */ 63#define MAXDEPTH 5 64 65/* 66 * p = path that may be a symlink 67 * s = full size of p 68 * 69 * If p is a symlink, attempt to overwrite p with a path to the real 70 * file or directory (which may or may not exist), following a chain of 71 * symlinks if necessary. Otherwise, leave p unmodified. 72 * 73 * This is a best-effort routine. If an error occurs, p will either be 74 * left unmodified or will name a different symlink in a symlink chain 75 * that started with p's initial contents. 76 * 77 * Always returns p. 78 */ 79 80static char*resolve_symlink(char*p,size_t s) 81{ 82int depth = MAXDEPTH; 83 84while(depth--) { 85char link[PATH_MAX]; 86int link_len =readlink(p, link,sizeof(link)); 87if(link_len <0) { 88/* not a symlink anymore */ 89return p; 90} 91else if(link_len <sizeof(link)) 92/* readlink() never null-terminates */ 93 link[link_len] ='\0'; 94else{ 95warning("%s: symlink too long", p); 96return p; 97} 98 99if(is_absolute_path(link)) { 100/* absolute path simply replaces p */ 101if(link_len < s) 102strcpy(p, link); 103else{ 104warning("%s: symlink too long", p); 105return p; 106} 107}else{ 108/* 109 * link is a relative path, so I must replace the 110 * last element of p with it. 111 */ 112char*r = (char*)last_path_elm(p); 113if(r - p + link_len < s) 114strcpy(r, link); 115else{ 116warning("%s: symlink too long", p); 117return p; 118} 119} 120} 121return p; 122} 123 124 125static intlock_file(struct lock_file *lk,const char*path,int flags) 126{ 127if(strlen(path) >=sizeof(lk->filename)) 128return-1; 129strcpy(lk->filename, path); 130/* 131 * subtract 5 from size to make sure there's room for adding 132 * ".lock" for the lock file name 133 */ 134if(!(flags & LOCK_NODEREF)) 135resolve_symlink(lk->filename,sizeof(lk->filename)-5); 136strcat(lk->filename,".lock"); 137 lk->fd =open(lk->filename, O_RDWR | O_CREAT | O_EXCL,0666); 138if(0<= lk->fd) { 139if(!lock_file_list) { 140sigchain_push_common(remove_lock_file_on_signal); 141atexit(remove_lock_file); 142} 143 lk->owner =getpid(); 144if(!lk->on_list) { 145 lk->next = lock_file_list; 146 lock_file_list = lk; 147 lk->on_list =1; 148} 149if(adjust_shared_perm(lk->filename)) 150returnerror("cannot fix permission bits on%s", 151 lk->filename); 152} 153else 154 lk->filename[0] =0; 155return lk->fd; 156} 157 158 159NORETURN voidunable_to_lock_index_die(const char*path,int err) 160{ 161if(err == EEXIST) { 162die("Unable to create '%s.lock':%s.\n\n" 163"If no other git process is currently running, this probably means a\n" 164"git process crashed in this repository earlier. Make sure no other git\n" 165"process is running and remove the file manually to continue.", 166 path,strerror(err)); 167}else{ 168die("Unable to create '%s.lock':%s", path,strerror(err)); 169} 170} 171 172inthold_lock_file_for_update(struct lock_file *lk,const char*path,int flags) 173{ 174int fd =lock_file(lk, path, flags); 175if(fd <0&& (flags & LOCK_DIE_ON_ERROR)) 176unable_to_lock_index_die(path, errno); 177return fd; 178} 179 180inthold_lock_file_for_append(struct lock_file *lk,const char*path,int flags) 181{ 182int fd, orig_fd; 183 184 fd =lock_file(lk, path, flags); 185if(fd <0) { 186if(flags & LOCK_DIE_ON_ERROR) 187unable_to_lock_index_die(path, errno); 188return fd; 189} 190 191 orig_fd =open(path, O_RDONLY); 192if(orig_fd <0) { 193if(errno != ENOENT) { 194if(flags & LOCK_DIE_ON_ERROR) 195die("cannot open '%s' for copying", path); 196close(fd); 197returnerror("cannot open '%s' for copying", path); 198} 199}else if(copy_fd(orig_fd, fd)) { 200if(flags & LOCK_DIE_ON_ERROR) 201exit(128); 202close(fd); 203return-1; 204} 205return fd; 206} 207 208intclose_lock_file(struct lock_file *lk) 209{ 210int fd = lk->fd; 211 lk->fd = -1; 212returnclose(fd); 213} 214 215intcommit_lock_file(struct lock_file *lk) 216{ 217char result_file[PATH_MAX]; 218size_t i; 219if(lk->fd >=0&&close_lock_file(lk)) 220return-1; 221strcpy(result_file, lk->filename); 222 i =strlen(result_file) -5;/* .lock */ 223 result_file[i] =0; 224if(rename(lk->filename, result_file)) 225return-1; 226 lk->filename[0] =0; 227return0; 228} 229 230inthold_locked_index(struct lock_file *lk,int die_on_error) 231{ 232returnhold_lock_file_for_update(lk,get_index_file(), 233 die_on_error 234? LOCK_DIE_ON_ERROR 235:0); 236} 237 238voidset_alternate_index_output(const char*name) 239{ 240 alternate_index_output = name; 241} 242 243intcommit_locked_index(struct lock_file *lk) 244{ 245if(alternate_index_output) { 246if(lk->fd >=0&&close_lock_file(lk)) 247return-1; 248if(rename(lk->filename, alternate_index_output)) 249return-1; 250 lk->filename[0] =0; 251return0; 252} 253else 254returncommit_lock_file(lk); 255} 256 257voidrollback_lock_file(struct lock_file *lk) 258{ 259if(lk->filename[0]) { 260if(lk->fd >=0) 261close(lk->fd); 262unlink(lk->filename); 263} 264 lk->filename[0] =0; 265}