]> git.ipfire.org Git - thirdparty/git.git/blame_incremental - lockfile.c
l10n: sv.po: Update Swedish translation (2298t0f0u)
[thirdparty/git.git] / lockfile.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 2005, Junio C Hamano
3 */
4#include "cache.h"
5#include "lockfile.h"
6#include "sigchain.h"
7
8static struct lock_file *volatile lock_file_list;
9
10static void remove_lock_files(int skip_fclose)
11{
12 pid_t me = getpid();
13
14 while (lock_file_list) {
15 if (lock_file_list->owner == me) {
16 /* fclose() is not safe to call in a signal handler */
17 if (skip_fclose)
18 lock_file_list->fp = NULL;
19 rollback_lock_file(lock_file_list);
20 }
21 lock_file_list = lock_file_list->next;
22 }
23}
24
25static void remove_lock_files_on_exit(void)
26{
27 remove_lock_files(0);
28}
29
30static void remove_lock_files_on_signal(int signo)
31{
32 remove_lock_files(1);
33 sigchain_pop(signo);
34 raise(signo);
35}
36
37/*
38 * path = absolute or relative path name
39 *
40 * Remove the last path name element from path (leaving the preceding
41 * "/", if any). If path is empty or the root directory ("/"), set
42 * path to the empty string.
43 */
44static void trim_last_path_component(struct strbuf *path)
45{
46 int i = path->len;
47
48 /* back up past trailing slashes, if any */
49 while (i && path->buf[i - 1] == '/')
50 i--;
51
52 /*
53 * then go backwards until a slash, or the beginning of the
54 * string
55 */
56 while (i && path->buf[i - 1] != '/')
57 i--;
58
59 strbuf_setlen(path, i);
60}
61
62
63/* We allow "recursive" symbolic links. Only within reason, though */
64#define MAXDEPTH 5
65
66/*
67 * path contains a path that might be a symlink.
68 *
69 * If path is a symlink, attempt to overwrite it with a path to the
70 * real file or directory (which may or may not exist), following a
71 * chain of symlinks if necessary. Otherwise, leave path unmodified.
72 *
73 * This is a best-effort routine. If an error occurs, path will
74 * either be left unmodified or will name a different symlink in a
75 * symlink chain that started with the original path.
76 */
77static void resolve_symlink(struct strbuf *path)
78{
79 int depth = MAXDEPTH;
80 static struct strbuf link = STRBUF_INIT;
81
82 while (depth--) {
83 if (strbuf_readlink(&link, path->buf, path->len) < 0)
84 break;
85
86 if (is_absolute_path(link.buf))
87 /* absolute path simply replaces p */
88 strbuf_reset(path);
89 else
90 /*
91 * link is a relative path, so replace the
92 * last element of p with it.
93 */
94 trim_last_path_component(path);
95
96 strbuf_addbuf(path, &link);
97 }
98 strbuf_reset(&link);
99}
100
101/* Make sure errno contains a meaningful value on error */
102static int lock_file(struct lock_file *lk, const char *path, int flags)
103{
104 size_t pathlen = strlen(path);
105
106 if (!lock_file_list) {
107 /* One-time initialization */
108 sigchain_push_common(remove_lock_files_on_signal);
109 atexit(remove_lock_files_on_exit);
110 }
111
112 if (lk->active)
113 die("BUG: cannot lock_file(\"%s\") using active struct lock_file",
114 path);
115 if (!lk->on_list) {
116 /* Initialize *lk and add it to lock_file_list: */
117 lk->fd = -1;
118 lk->fp = NULL;
119 lk->active = 0;
120 lk->owner = 0;
121 strbuf_init(&lk->filename, pathlen + LOCK_SUFFIX_LEN);
122 lk->next = lock_file_list;
123 lock_file_list = lk;
124 lk->on_list = 1;
125 } else if (lk->filename.len) {
126 /* This shouldn't happen, but better safe than sorry. */
127 die("BUG: lock_file(\"%s\") called with improperly-reset lock_file object",
128 path);
129 }
130
131 if (flags & LOCK_NO_DEREF) {
132 strbuf_add_absolute_path(&lk->filename, path);
133 } else {
134 struct strbuf resolved_path = STRBUF_INIT;
135
136 strbuf_add(&resolved_path, path, pathlen);
137 resolve_symlink(&resolved_path);
138 strbuf_add_absolute_path(&lk->filename, resolved_path.buf);
139 strbuf_release(&resolved_path);
140 }
141
142 strbuf_addstr(&lk->filename, LOCK_SUFFIX);
143 lk->fd = open(lk->filename.buf, O_RDWR | O_CREAT | O_EXCL, 0666);
144 if (lk->fd < 0) {
145 strbuf_reset(&lk->filename);
146 return -1;
147 }
148 lk->owner = getpid();
149 lk->active = 1;
150 if (adjust_shared_perm(lk->filename.buf)) {
151 int save_errno = errno;
152 error("cannot fix permission bits on %s", lk->filename.buf);
153 rollback_lock_file(lk);
154 errno = save_errno;
155 return -1;
156 }
157 return lk->fd;
158}
159
160void unable_to_lock_message(const char *path, int err, struct strbuf *buf)
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 absolute_path(path), strerror(err));
168 } else
169 strbuf_addf(buf, "Unable to create '%s.lock': %s",
170 absolute_path(path), strerror(err));
171}
172
173NORETURN void unable_to_lock_die(const char *path, int err)
174{
175 struct strbuf buf = STRBUF_INIT;
176
177 unable_to_lock_message(path, err, &buf);
178 die("%s", buf.buf);
179}
180
181/* This should return a meaningful errno on failure */
182int hold_lock_file_for_update(struct lock_file *lk, const char *path, int flags)
183{
184 int fd = lock_file(lk, path, flags);
185 if (fd < 0 && (flags & LOCK_DIE_ON_ERROR))
186 unable_to_lock_die(path, errno);
187 return fd;
188}
189
190int hold_lock_file_for_append(struct lock_file *lk, const char *path, int flags)
191{
192 int fd, orig_fd;
193
194 fd = lock_file(lk, path, flags);
195 if (fd < 0) {
196 if (flags & LOCK_DIE_ON_ERROR)
197 unable_to_lock_die(path, errno);
198 return fd;
199 }
200
201 orig_fd = open(path, O_RDONLY);
202 if (orig_fd < 0) {
203 if (errno != ENOENT) {
204 int save_errno = errno;
205
206 if (flags & LOCK_DIE_ON_ERROR)
207 die("cannot open '%s' for copying", path);
208 rollback_lock_file(lk);
209 error("cannot open '%s' for copying", path);
210 errno = save_errno;
211 return -1;
212 }
213 } else if (copy_fd(orig_fd, fd)) {
214 int save_errno = errno;
215
216 if (flags & LOCK_DIE_ON_ERROR)
217 exit(128);
218 close(orig_fd);
219 rollback_lock_file(lk);
220 errno = save_errno;
221 return -1;
222 } else {
223 close(orig_fd);
224 }
225 return fd;
226}
227
228FILE *fdopen_lock_file(struct lock_file *lk, const char *mode)
229{
230 if (!lk->active)
231 die("BUG: fdopen_lock_file() called for unlocked object");
232 if (lk->fp)
233 die("BUG: fdopen_lock_file() called twice for file '%s'", lk->filename.buf);
234
235 lk->fp = fdopen(lk->fd, mode);
236 return lk->fp;
237}
238
239char *get_locked_file_path(struct lock_file *lk)
240{
241 if (!lk->active)
242 die("BUG: get_locked_file_path() called for unlocked object");
243 if (lk->filename.len <= LOCK_SUFFIX_LEN)
244 die("BUG: get_locked_file_path() called for malformed lock object");
245 return xmemdupz(lk->filename.buf, lk->filename.len - LOCK_SUFFIX_LEN);
246}
247
248int close_lock_file(struct lock_file *lk)
249{
250 int fd = lk->fd;
251 FILE *fp = lk->fp;
252 int err;
253
254 if (fd < 0)
255 return 0;
256
257 lk->fd = -1;
258 if (fp) {
259 lk->fp = NULL;
260
261 /*
262 * Note: no short-circuiting here; we want to fclose()
263 * in any case!
264 */
265 err = ferror(fp) | fclose(fp);
266 } else {
267 err = close(fd);
268 }
269
270 if (err) {
271 int save_errno = errno;
272 rollback_lock_file(lk);
273 errno = save_errno;
274 return -1;
275 }
276
277 return 0;
278}
279
280int reopen_lock_file(struct lock_file *lk)
281{
282 if (0 <= lk->fd)
283 die(_("BUG: reopen a lockfile that is still open"));
284 if (!lk->active)
285 die(_("BUG: reopen a lockfile that has been committed"));
286 lk->fd = open(lk->filename.buf, O_WRONLY);
287 return lk->fd;
288}
289
290int commit_lock_file_to(struct lock_file *lk, const char *path)
291{
292 if (!lk->active)
293 die("BUG: attempt to commit unlocked object to \"%s\"", path);
294
295 if (close_lock_file(lk))
296 return -1;
297
298 if (rename(lk->filename.buf, path)) {
299 int save_errno = errno;
300 rollback_lock_file(lk);
301 errno = save_errno;
302 return -1;
303 }
304
305 lk->active = 0;
306 strbuf_reset(&lk->filename);
307 return 0;
308}
309
310int commit_lock_file(struct lock_file *lk)
311{
312 static struct strbuf result_file = STRBUF_INIT;
313 int err;
314
315 if (!lk->active)
316 die("BUG: attempt to commit unlocked object");
317
318 if (lk->filename.len <= LOCK_SUFFIX_LEN ||
319 strcmp(lk->filename.buf + lk->filename.len - LOCK_SUFFIX_LEN, LOCK_SUFFIX))
320 die("BUG: lockfile filename corrupt");
321
322 /* remove ".lock": */
323 strbuf_add(&result_file, lk->filename.buf,
324 lk->filename.len - LOCK_SUFFIX_LEN);
325 err = commit_lock_file_to(lk, result_file.buf);
326 strbuf_reset(&result_file);
327 return err;
328}
329
330void rollback_lock_file(struct lock_file *lk)
331{
332 if (!lk->active)
333 return;
334
335 if (!close_lock_file(lk)) {
336 unlink_or_warn(lk->filename.buf);
337 lk->active = 0;
338 strbuf_reset(&lk->filename);
339 }
340}