blob: eb931eded5a6ed20f1d80dadf08cbb8009d85767 [file] [log] [blame]
Junio C Hamano021b6e42006-06-06 12:51:49 -07001/*
2 * Copyright (c) 2005, Junio C Hamano
3 */
Junio C Hamano021b6e42006-06-06 12:51:49 -07004#include "cache.h"
Jeff King4a16d072009-01-22 01:02:35 -05005#include "sigchain.h"
Junio C Hamano021b6e42006-06-06 12:51:49 -07006
7static struct lock_file *lock_file_list;
Junio C Hamano5e7f56a2007-03-31 23:27:41 -07008static const char *alternate_index_output;
Junio C Hamano021b6e42006-06-06 12:51:49 -07009
10static void remove_lock_file(void)
11{
Junio C Hamano5e635e32007-04-21 03:11:10 -070012 pid_t me = getpid();
13
Junio C Hamano021b6e42006-06-06 12:51:49 -070014 while (lock_file_list) {
Junio C Hamano5e635e32007-04-21 03:11:10 -070015 if (lock_file_list->owner == me &&
Johannes Schindelin4723ee92007-11-13 21:05:03 +010016 lock_file_list->filename[0]) {
Brandon Caseyd6cf61b2008-01-16 11:05:32 -080017 if (lock_file_list->fd >= 0)
18 close(lock_file_list->fd);
Alex Riesen691f1a22009-04-29 23:22:56 +020019 unlink_or_warn(lock_file_list->filename);
Johannes Schindelin4723ee92007-11-13 21:05:03 +010020 }
Junio C Hamano021b6e42006-06-06 12:51:49 -070021 lock_file_list = lock_file_list->next;
22 }
23}
24
25static void remove_lock_file_on_signal(int signo)
26{
27 remove_lock_file();
Jeff King4a16d072009-01-22 01:02:35 -050028 sigchain_pop(signo);
Junio C Hamano021b6e42006-06-06 12:51:49 -070029 raise(signo);
30}
31
Bradford C. Smith5d5a7a62007-07-26 13:34:14 -040032/*
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 */
41 char *r = strchr(p, '\0');
42
43 if (r == p)
44 return p; /* just return empty string */
45
46 r--; /* back up to last non-null character */
47
48 /* back up past trailing slashes, if any */
49 while (r > p && *r == '/')
50 r--;
51
52 /*
53 * then go backwards until I hit a slash, or the beginning of
54 * the string
55 */
56 while (r > p && *(r-1) != '/')
57 r--;
58 return 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{
82 int depth = MAXDEPTH;
83
84 while (depth--) {
85 char link[PATH_MAX];
86 int link_len = readlink(p, link, sizeof(link));
87 if (link_len < 0) {
88 /* not a symlink anymore */
89 return p;
90 }
91 else if (link_len < sizeof(link))
92 /* readlink() never null-terminates */
93 link[link_len] = '\0';
94 else {
95 warning("%s: symlink too long", p);
96 return p;
97 }
98
Steffen Prohaskaecf48312007-11-25 23:29:03 +010099 if (is_absolute_path(link)) {
Bradford C. Smith5d5a7a62007-07-26 13:34:14 -0400100 /* absolute path simply replaces p */
101 if (link_len < s)
102 strcpy(p, link);
103 else {
104 warning("%s: symlink too long", p);
105 return p;
106 }
107 } else {
108 /*
109 * link is a relative path, so I must replace the
110 * last element of p with it.
111 */
Felipe Contreras4b25d092009-05-01 12:06:36 +0300112 char *r = (char *)last_path_elm(p);
Bradford C. Smith5d5a7a62007-07-26 13:34:14 -0400113 if (r - p + link_len < s)
114 strcpy(r, link);
115 else {
116 warning("%s: symlink too long", p);
117 return p;
118 }
119 }
120 }
121 return p;
122}
123
124
Junio C Hamanoacd3b9e2008-10-17 15:44:39 -0700125static int lock_file(struct lock_file *lk, const char *path, int flags)
Junio C Hamano021b6e42006-06-06 12:51:49 -0700126{
Junio C Hamanoacd3b9e2008-10-17 15:44:39 -0700127 if (strlen(path) >= sizeof(lk->filename))
128 return -1;
Bradford C. Smith5d5a7a62007-07-26 13:34:14 -0400129 strcpy(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 */
Junio C Hamanoacd3b9e2008-10-17 15:44:39 -0700134 if (!(flags & LOCK_NODEREF))
135 resolve_symlink(lk->filename, sizeof(lk->filename)-5);
Bradford C. Smith5d5a7a62007-07-26 13:34:14 -0400136 strcat(lk->filename, ".lock");
Johannes Schindelin4723ee92007-11-13 21:05:03 +0100137 lk->fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666);
138 if (0 <= lk->fd) {
Sven Verdoolaege9a4cbdc2007-07-13 16:14:50 +0200139 if (!lock_file_list) {
Jeff King57b235a2009-01-22 01:03:08 -0500140 sigchain_push_common(remove_lock_file_on_signal);
Sven Verdoolaege9a4cbdc2007-07-13 16:14:50 +0200141 atexit(remove_lock_file);
142 }
Junio C Hamano5e635e32007-04-21 03:11:10 -0700143 lk->owner = getpid();
Junio C Hamano1084b842007-01-02 11:19:05 -0800144 if (!lk->on_list) {
Junio C Hamano138086a2006-06-09 22:07:23 -0700145 lk->next = lock_file_list;
146 lock_file_list = lk;
Junio C Hamano1084b842007-01-02 11:19:05 -0800147 lk->on_list = 1;
148 }
Junio C Hamano138086a2006-06-09 22:07:23 -0700149 if (adjust_shared_perm(lk->filename))
150 return error("cannot fix permission bits on %s",
151 lk->filename);
Junio C Hamano021b6e42006-06-06 12:51:49 -0700152 }
Junio C Hamano1084b842007-01-02 11:19:05 -0800153 else
154 lk->filename[0] = 0;
Johannes Schindelin4723ee92007-11-13 21:05:03 +0100155 return lk->fd;
Junio C Hamano021b6e42006-06-06 12:51:49 -0700156}
157
Matthieu Moye43a6fd2009-02-19 13:54:18 +0100158
159NORETURN void unable_to_lock_index_die(const char *path, int err)
160{
John Tapsellbdfd7392009-03-04 15:00:44 +0000161 if (err == EEXIST) {
Matthieu Moye43a6fd2009-02-19 13:54:18 +0100162 die("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 {
168 die("Unable to create '%s.lock': %s", path, strerror(err));
169 }
170}
171
Junio C Hamanoacd3b9e2008-10-17 15:44:39 -0700172int hold_lock_file_for_update(struct lock_file *lk, const char *path, int flags)
Junio C Hamano40aaae82006-08-12 01:03:47 -0700173{
Junio C Hamanoacd3b9e2008-10-17 15:44:39 -0700174 int fd = lock_file(lk, path, flags);
175 if (fd < 0 && (flags & LOCK_DIE_ON_ERROR))
Matthieu Moye43a6fd2009-02-19 13:54:18 +0100176 unable_to_lock_index_die(path, errno);
Junio C Hamano40aaae82006-08-12 01:03:47 -0700177 return fd;
178}
179
Junio C Hamanoacd3b9e2008-10-17 15:44:39 -0700180int hold_lock_file_for_append(struct lock_file *lk, const char *path, int flags)
Daniel Barkalowea3cd5c2008-04-17 19:32:26 -0400181{
182 int fd, orig_fd;
183
Junio C Hamanoacd3b9e2008-10-17 15:44:39 -0700184 fd = lock_file(lk, path, flags);
Daniel Barkalowea3cd5c2008-04-17 19:32:26 -0400185 if (fd < 0) {
Junio C Hamanoacd3b9e2008-10-17 15:44:39 -0700186 if (flags & LOCK_DIE_ON_ERROR)
John Tapsellbdfd7392009-03-04 15:00:44 +0000187 unable_to_lock_index_die(path, errno);
Daniel Barkalowea3cd5c2008-04-17 19:32:26 -0400188 return fd;
189 }
190
191 orig_fd = open(path, O_RDONLY);
192 if (orig_fd < 0) {
193 if (errno != ENOENT) {
Junio C Hamanoacd3b9e2008-10-17 15:44:39 -0700194 if (flags & LOCK_DIE_ON_ERROR)
Daniel Barkalowea3cd5c2008-04-17 19:32:26 -0400195 die("cannot open '%s' for copying", path);
196 close(fd);
197 return error("cannot open '%s' for copying", path);
198 }
199 } else if (copy_fd(orig_fd, fd)) {
Junio C Hamanoacd3b9e2008-10-17 15:44:39 -0700200 if (flags & LOCK_DIE_ON_ERROR)
Daniel Barkalowea3cd5c2008-04-17 19:32:26 -0400201 exit(128);
202 close(fd);
203 return -1;
204 }
205 return fd;
206}
207
Brandon Caseyd6cf61b2008-01-16 11:05:32 -0800208int close_lock_file(struct lock_file *lk)
209{
210 int fd = lk->fd;
211 lk->fd = -1;
212 return close(fd);
213}
214
Junio C Hamano021b6e42006-06-06 12:51:49 -0700215int commit_lock_file(struct lock_file *lk)
216{
217 char result_file[PATH_MAX];
Brandon Caseyd6cf61b2008-01-16 11:05:32 -0800218 size_t i;
219 if (lk->fd >= 0 && close_lock_file(lk))
220 return -1;
Junio C Hamano021b6e42006-06-06 12:51:49 -0700221 strcpy(result_file, lk->filename);
222 i = strlen(result_file) - 5; /* .lock */
223 result_file[i] = 0;
Brandon Caseyd6cf61b2008-01-16 11:05:32 -0800224 if (rename(lk->filename, result_file))
225 return -1;
Junio C Hamano021b6e42006-06-06 12:51:49 -0700226 lk->filename[0] = 0;
Brandon Caseyd6cf61b2008-01-16 11:05:32 -0800227 return 0;
Junio C Hamano021b6e42006-06-06 12:51:49 -0700228}
229
Junio C Hamano30ca07a2007-03-31 23:09:02 -0700230int hold_locked_index(struct lock_file *lk, int die_on_error)
231{
Junio C Hamanoacd3b9e2008-10-17 15:44:39 -0700232 return hold_lock_file_for_update(lk, get_index_file(),
233 die_on_error
234 ? LOCK_DIE_ON_ERROR
235 : 0);
Junio C Hamano30ca07a2007-03-31 23:09:02 -0700236}
237
Junio C Hamano5e7f56a2007-03-31 23:27:41 -0700238void set_alternate_index_output(const char *name)
239{
240 alternate_index_output = name;
241}
242
Junio C Hamano30ca07a2007-03-31 23:09:02 -0700243int commit_locked_index(struct lock_file *lk)
244{
Junio C Hamano5e7f56a2007-03-31 23:27:41 -0700245 if (alternate_index_output) {
Brandon Caseyd6cf61b2008-01-16 11:05:32 -0800246 if (lk->fd >= 0 && close_lock_file(lk))
247 return -1;
248 if (rename(lk->filename, alternate_index_output))
249 return -1;
Junio C Hamano30ca07a2007-03-31 23:09:02 -0700250 lk->filename[0] = 0;
Brandon Caseyd6cf61b2008-01-16 11:05:32 -0800251 return 0;
Junio C Hamano30ca07a2007-03-31 23:09:02 -0700252 }
253 else
254 return commit_lock_file(lk);
255}
256
Junio C Hamano021b6e42006-06-06 12:51:49 -0700257void rollback_lock_file(struct lock_file *lk)
258{
Johannes Schindelin4723ee92007-11-13 21:05:03 +0100259 if (lk->filename[0]) {
Brandon Caseyd6cf61b2008-01-16 11:05:32 -0800260 if (lk->fd >= 0)
261 close(lk->fd);
Alex Riesen691f1a22009-04-29 23:22:56 +0200262 unlink_or_warn(lk->filename);
Johannes Schindelin4723ee92007-11-13 21:05:03 +0100263 }
Junio C Hamano021b6e42006-06-06 12:51:49 -0700264 lk->filename[0] = 0;
265}