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 void remove_lock_file(void)
11{
12 pid_t me = getpid();
13
14 while (lock_file_list) {
15 if (lock_file_list->owner == me &&
16 lock_file_list->filename[0]) {
17 if (lock_file_list->fd >= 0)
18 close(lock_file_list->fd);
19 unlink_or_warn(lock_file_list->filename);
20 }
21 lock_file_list = lock_file_list->next;
22 }
23}
24
25static void remove_lock_file_on_signal(int signo)
26{
27 remove_lock_file();
28 sigchain_pop(signo);
29 raise(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 */
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
99 if (is_absolute_path(link)) {
100 /* 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 */
112 char *r = (char *)last_path_elm(p);
113 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
125static int lock_file(struct lock_file *lk, const char *path, int flags)
126{
127 if (strlen(path) >= sizeof(lk->filename))
128 return -1;
129 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 */
134 if (!(flags & LOCK_NODEREF))
135 resolve_symlink(lk->filename, sizeof(lk->filename)-5);
136 strcat(lk->filename, ".lock");
137 lk->fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666);
138 if (0 <= lk->fd) {
139 if (!lock_file_list) {
140 sigchain_push_common(remove_lock_file_on_signal);
141 atexit(remove_lock_file);
142 }
143 lk->owner = getpid();
144 if (!lk->on_list) {
145 lk->next = lock_file_list;
146 lock_file_list = lk;
147 lk->on_list = 1;
148 }
149 if (adjust_shared_perm(lk->filename))
150 return error("cannot fix permission bits on %s",
151 lk->filename);
152 }
153 else
154 lk->filename[0] = 0;
155 return lk->fd;
156}
157
158static char *unable_to_lock_message(const char *path, int err)
159{
160 struct strbuf buf = STRBUF_INIT;
161
162 if (err == EEXIST) {
163 strbuf_addf(&buf, "Unable to create '%s.lock': %s.\n\n"
164 "If no other git process is currently running, this probably means a\n"
165 "git process crashed in this repository earlier. Make sure no other git\n"
166 "process is running and remove the file manually to continue.",
167 path, strerror(err));
168 } else
169 strbuf_addf(&buf, "Unable to create '%s.lock': %s", path, strerror(err));
170 return strbuf_detach(&buf, NULL);
171}
172
173int unable_to_lock_error(const char *path, int err)
174{
175 char *msg = unable_to_lock_message(path, err);
176 error("%s", msg);
177 free(msg);
178 return -1;
179}
180
181NORETURN void unable_to_lock_index_die(const char *path, int err)
182{
183 die("%s", unable_to_lock_message(path, err));
184}
185
186int hold_lock_file_for_update(struct lock_file *lk, const char *path, int flags)
187{
188 int fd = lock_file(lk, path, flags);
189 if (fd < 0 && (flags & LOCK_DIE_ON_ERROR))
190 unable_to_lock_index_die(path, errno);
191 return fd;
192}
193
194int hold_lock_file_for_append(struct lock_file *lk, const char *path, int flags)
195{
196 int fd, orig_fd;
197
198 fd = lock_file(lk, path, flags);
199 if (fd < 0) {
200 if (flags & LOCK_DIE_ON_ERROR)
201 unable_to_lock_index_die(path, errno);
202 return fd;
203 }
204
205 orig_fd = open(path, O_RDONLY);
206 if (orig_fd < 0) {
207 if (errno != ENOENT) {
208 if (flags & LOCK_DIE_ON_ERROR)
209 die("cannot open '%s' for copying", path);
210 close(fd);
211 return error("cannot open '%s' for copying", path);
212 }
213 } else if (copy_fd(orig_fd, fd)) {
214 if (flags & LOCK_DIE_ON_ERROR)
215 exit(128);
216 close(fd);
217 return -1;
218 }
219 return fd;
220}
221
222int close_lock_file(struct lock_file *lk)
223{
224 int fd = lk->fd;
225 lk->fd = -1;
226 return close(fd);
227}
228
229int commit_lock_file(struct lock_file *lk)
230{
231 char result_file[PATH_MAX];
232 size_t i;
233 if (lk->fd >= 0 && close_lock_file(lk))
234 return -1;
235 strcpy(result_file, lk->filename);
236 i = strlen(result_file) - 5; /* .lock */
237 result_file[i] = 0;
238 if (rename(lk->filename, result_file))
239 return -1;
240 lk->filename[0] = 0;
241 return 0;
242}
243
244int hold_locked_index(struct lock_file *lk, int die_on_error)
245{
246 return hold_lock_file_for_update(lk, get_index_file(),
247 die_on_error
248 ? LOCK_DIE_ON_ERROR
249 : 0);
250}
251
252void set_alternate_index_output(const char *name)
253{
254 alternate_index_output = name;
255}
256
257int commit_locked_index(struct lock_file *lk)
258{
259 if (alternate_index_output) {
260 if (lk->fd >= 0 && close_lock_file(lk))
261 return -1;
262 if (rename(lk->filename, alternate_index_output))
263 return -1;
264 lk->filename[0] = 0;
265 return 0;
266 }
267 else
268 return commit_lock_file(lk);
269}
270
271void rollback_lock_file(struct lock_file *lk)
272{
273 if (lk->filename[0]) {
274 if (lk->fd >= 0)
275 close(lk->fd);
276 unlink_or_warn(lk->filename);
277 }
278 lk->filename[0] = 0;
279}