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]) { 16if(lock_file_list->fd >=0) 17close(lock_file_list->fd); 18unlink(lock_file_list->filename); 19} 20 lock_file_list = lock_file_list->next; 21} 22} 23 24static voidremove_lock_file_on_signal(int signo) 25{ 26remove_lock_file(); 27signal(SIGINT, SIG_DFL); 28raise(signo); 29} 30 31/* 32 * p = absolute or relative path name 33 * 34 * Return a pointer into p showing the beginning of the last path name 35 * element. If p is empty or the root directory ("/"), just return p. 36 */ 37static char*last_path_elm(char*p) 38{ 39/* r starts pointing to null at the end of the string */ 40char*r =strchr(p,'\0'); 41 42if(r == p) 43return p;/* just return empty string */ 44 45 r--;/* back up to last non-null character */ 46 47/* back up past trailing slashes, if any */ 48while(r > p && *r =='/') 49 r--; 50 51/* 52 * then go backwards until I hit a slash, or the beginning of 53 * the string 54 */ 55while(r > p && *(r-1) !='/') 56 r--; 57return r; 58} 59 60 61/* We allow "recursive" symbolic links. Only within reason, though */ 62#define MAXDEPTH 5 63 64/* 65 * p = path that may be a symlink 66 * s = full size of p 67 * 68 * If p is a symlink, attempt to overwrite p with a path to the real 69 * file or directory (which may or may not exist), following a chain of 70 * symlinks if necessary. Otherwise, leave p unmodified. 71 * 72 * This is a best-effort routine. If an error occurs, p will either be 73 * left unmodified or will name a different symlink in a symlink chain 74 * that started with p's initial contents. 75 * 76 * Always returns p. 77 */ 78 79static char*resolve_symlink(char*p,size_t s) 80{ 81int depth = MAXDEPTH; 82 83while(depth--) { 84char link[PATH_MAX]; 85int link_len =readlink(p, link,sizeof(link)); 86if(link_len <0) { 87/* not a symlink anymore */ 88return p; 89} 90else if(link_len <sizeof(link)) 91/* readlink() never null-terminates */ 92 link[link_len] ='\0'; 93else{ 94warning("%s: symlink too long", p); 95return p; 96} 97 98if(is_absolute_path(link)) { 99/* absolute path simply replaces p */ 100if(link_len < s) 101strcpy(p, link); 102else{ 103warning("%s: symlink too long", p); 104return p; 105} 106}else{ 107/* 108 * link is a relative path, so I must replace the 109 * last element of p with it. 110 */ 111char*r = (char*)last_path_elm(p); 112if(r - p + link_len < s) 113strcpy(r, link); 114else{ 115warning("%s: symlink too long", p); 116return p; 117} 118} 119} 120return p; 121} 122 123 124static intlock_file(struct lock_file *lk,const char*path) 125{ 126if(strlen(path) >=sizeof(lk->filename))return-1; 127strcpy(lk->filename, path); 128/* 129 * subtract 5 from size to make sure there's room for adding 130 * ".lock" for the lock file name 131 */ 132resolve_symlink(lk->filename,sizeof(lk->filename)-5); 133strcat(lk->filename,".lock"); 134 lk->fd =open(lk->filename, O_RDWR | O_CREAT | O_EXCL,0666); 135if(0<= lk->fd) { 136if(!lock_file_list) { 137signal(SIGINT, remove_lock_file_on_signal); 138atexit(remove_lock_file); 139} 140 lk->owner =getpid(); 141if(!lk->on_list) { 142 lk->next = lock_file_list; 143 lock_file_list = lk; 144 lk->on_list =1; 145} 146if(adjust_shared_perm(lk->filename)) 147returnerror("cannot fix permission bits on%s", 148 lk->filename); 149} 150else 151 lk->filename[0] =0; 152return lk->fd; 153} 154 155inthold_lock_file_for_update(struct lock_file *lk,const char*path,int die_on_error) 156{ 157int fd =lock_file(lk, path); 158if(fd <0&& die_on_error) 159die("unable to create '%s.lock':%s", path,strerror(errno)); 160return fd; 161} 162 163intclose_lock_file(struct lock_file *lk) 164{ 165int fd = lk->fd; 166 lk->fd = -1; 167returnclose(fd); 168} 169 170intcommit_lock_file(struct lock_file *lk) 171{ 172char result_file[PATH_MAX]; 173size_t i; 174if(lk->fd >=0&&close_lock_file(lk)) 175return-1; 176strcpy(result_file, lk->filename); 177 i =strlen(result_file) -5;/* .lock */ 178 result_file[i] =0; 179if(rename(lk->filename, result_file)) 180return-1; 181 lk->filename[0] =0; 182return0; 183} 184 185inthold_locked_index(struct lock_file *lk,int die_on_error) 186{ 187returnhold_lock_file_for_update(lk,get_index_file(), die_on_error); 188} 189 190voidset_alternate_index_output(const char*name) 191{ 192 alternate_index_output = name; 193} 194 195intcommit_locked_index(struct lock_file *lk) 196{ 197if(alternate_index_output) { 198if(lk->fd >=0&&close_lock_file(lk)) 199return-1; 200if(rename(lk->filename, alternate_index_output)) 201return-1; 202 lk->filename[0] =0; 203return0; 204} 205else 206returncommit_lock_file(lk); 207} 208 209voidrollback_lock_file(struct lock_file *lk) 210{ 211if(lk->filename[0]) { 212if(lk->fd >=0) 213close(lk->fd); 214unlink(lk->filename); 215} 216 lk->filename[0] =0; 217}