1/* 2 * Copyright (c) 2005, Junio C Hamano 3 */ 4#include"cache.h" 5 6static struct lock_file *lock_file_list; 7static const char*alternate_index_output; 8 9static voidremove_lock_file(void) 10{ 11 pid_t me =getpid(); 12 13while(lock_file_list) { 14if(lock_file_list->owner == me && 15 lock_file_list->filename[0]) 16unlink(lock_file_list->filename); 17 lock_file_list = lock_file_list->next; 18} 19} 20 21static voidremove_lock_file_on_signal(int signo) 22{ 23remove_lock_file(); 24signal(SIGINT, SIG_DFL); 25raise(signo); 26} 27 28/* 29 * p = absolute or relative path name 30 * 31 * Return a pointer into p showing the beginning of the last path name 32 * 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'); 38 39if(r == p) 40return p;/* just return empty string */ 41 42 r--;/* back up to last non-null character */ 43 44/* back up past trailing slashes, if any */ 45while(r > p && *r =='/') 46 r--; 47 48/* 49 * then go backwards until I hit a slash, or the beginning of 50 * the string 51 */ 52while(r > p && *(r-1) !='/') 53 r--; 54return r; 55} 56 57 58/* We allow "recursive" symbolic links. Only within reason, though */ 59#define MAXDEPTH 5 60 61/* 62 * p = path that may be a symlink 63 * s = full size of p 64 * 65 * If p is a symlink, attempt to overwrite p with a path to the real 66 * file or directory (which may or may not exist), following a chain of 67 * symlinks if necessary. Otherwise, leave p unmodified. 68 * 69 * This is a best-effort routine. If an error occurs, p will either be 70 * left unmodified or will name a different symlink in a symlink chain 71 * that started with p's initial contents. 72 * 73 * Always returns p. 74 */ 75 76static char*resolve_symlink(char*p,size_t s) 77{ 78int depth = MAXDEPTH; 79 80while(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 */ 89 link[link_len] ='\0'; 90else{ 91warning("%s: symlink too long", p); 92return p; 93} 94 95if(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 the 106 * 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} 119 120 121static intlock_file(struct lock_file *lk,const char*path) 122{ 123int fd; 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 adding 129 * ".lock" for the lock file name 130 */ 131resolve_symlink(lk->filename,sizeof(lk->filename)-5); 132strcat(lk->filename,".lock"); 133 fd =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} 139 lk->owner =getpid(); 140if(!lk->on_list) { 141 lk->next = lock_file_list; 142 lock_file_list = lk; 143 lk->on_list =1; 144} 145if(adjust_shared_perm(lk->filename)) 146returnerror("cannot fix permission bits on%s", 147 lk->filename); 148} 149else 150 lk->filename[0] =0; 151return fd; 152} 153 154inthold_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} 161 162intcommit_lock_file(struct lock_file *lk) 163{ 164char result_file[PATH_MAX]; 165int i; 166strcpy(result_file, lk->filename); 167 i =strlen(result_file) -5;/* .lock */ 168 result_file[i] =0; 169 i =rename(lk->filename, result_file); 170 lk->filename[0] =0; 171return i; 172} 173 174inthold_locked_index(struct lock_file *lk,int die_on_error) 175{ 176returnhold_lock_file_for_update(lk,get_index_file(), die_on_error); 177} 178 179voidset_alternate_index_output(const char*name) 180{ 181 alternate_index_output = name; 182} 183 184intcommit_locked_index(struct lock_file *lk) 185{ 186if(alternate_index_output) { 187int result =rename(lk->filename, alternate_index_output); 188 lk->filename[0] =0; 189return result; 190} 191else 192returncommit_lock_file(lk); 193} 194 195voidrollback_lock_file(struct lock_file *lk) 196{ 197if(lk->filename[0]) 198unlink(lk->filename); 199 lk->filename[0] =0; 200}