]> git.ipfire.org Git - thirdparty/git.git/blame - lockfile.c
coverity: allow overriding the Coverity project
[thirdparty/git.git] / lockfile.c
CommitLineData
021b6e45
JH
1/*
2 * Copyright (c) 2005, Junio C Hamano
3 */
2db69de8 4
a64acf72 5#include "git-compat-util.h"
0b027f6c 6#include "abspath.h"
f394e093 7#include "gettext.h"
697cc8ef 8#include "lockfile.h"
021b6e45 9
5d5a7a67 10/*
0c0d6e86 11 * path = absolute or relative path name
5d5a7a67 12 *
0c0d6e86
MH
13 * Remove the last path name element from path (leaving the preceding
14 * "/", if any). If path is empty or the root directory ("/"), set
15 * path to the empty string.
5d5a7a67 16 */
0c0d6e86 17static void trim_last_path_component(struct strbuf *path)
5d5a7a67 18{
0c0d6e86 19 int i = path->len;
5d5a7a67
BS
20
21 /* back up past trailing slashes, if any */
0c0d6e86
MH
22 while (i && path->buf[i - 1] == '/')
23 i--;
5d5a7a67
BS
24
25 /*
0c0d6e86
MH
26 * then go backwards until a slash, or the beginning of the
27 * string
5d5a7a67 28 */
0c0d6e86
MH
29 while (i && path->buf[i - 1] != '/')
30 i--;
31
32 strbuf_setlen(path, i);
5d5a7a67
BS
33}
34
35
36/* We allow "recursive" symbolic links. Only within reason, though */
37#define MAXDEPTH 5
38
39/*
6cad8053 40 * path contains a path that might be a symlink.
5d5a7a67 41 *
6cad8053
MH
42 * If path is a symlink, attempt to overwrite it with a path to the
43 * real file or directory (which may or may not exist), following a
44 * chain of symlinks if necessary. Otherwise, leave path unmodified.
5d5a7a67 45 *
6cad8053
MH
46 * This is a best-effort routine. If an error occurs, path will
47 * either be left unmodified or will name a different symlink in a
48 * symlink chain that started with the original path.
5d5a7a67 49 */
6cad8053 50static void resolve_symlink(struct strbuf *path)
5d5a7a67
BS
51{
52 int depth = MAXDEPTH;
5025d845 53 static struct strbuf link = STRBUF_INIT;
5d5a7a67
BS
54
55 while (depth--) {
6cad8053 56 if (strbuf_readlink(&link, path->buf, path->len) < 0)
5025d845 57 break;
5d5a7a67 58
6cad8053 59 if (is_absolute_path(link.buf))
5d5a7a67 60 /* absolute path simply replaces p */
6cad8053 61 strbuf_reset(path);
0c0d6e86 62 else
5d5a7a67 63 /*
5025d845 64 * link is a relative path, so replace the
5d5a7a67
BS
65 * last element of p with it.
66 */
0c0d6e86 67 trim_last_path_component(path);
6cad8053
MH
68
69 strbuf_addbuf(path, &link);
5d5a7a67 70 }
5025d845 71 strbuf_reset(&link);
5d5a7a67
BS
72}
73
447ff1bf 74/* Make sure errno contains a meaningful value on error */
fa3bff24
TB
75static int lock_file(struct lock_file *lk, const char *path, int flags,
76 int mode)
021b6e45 77{
1a9d15db 78 struct strbuf filename = STRBUF_INIT;
04e57d4d 79
1a9d15db
MH
80 strbuf_addstr(&filename, path);
81 if (!(flags & LOCK_NO_DEREF))
82 resolve_symlink(&filename);
fa137f67 83
1a9d15db 84 strbuf_addstr(&filename, LOCK_SUFFIX);
fa3bff24 85 lk->tempfile = create_tempfile_mode(filename.buf, mode);
1a9d15db 86 strbuf_release(&filename);
076aa2cb 87 return lk->tempfile ? lk->tempfile->fd : -1;
021b6e45
JH
88}
89
044b6a9e
MH
90/*
91 * Constants defining the gaps between attempts to lock a file. The
92 * first backoff period is approximately INITIAL_BACKOFF_MS
93 * milliseconds. The longest backoff period is approximately
94 * (BACKOFF_MAX_MULTIPLIER * INITIAL_BACKOFF_MS) milliseconds.
95 */
96#define INITIAL_BACKOFF_MS 1L
97#define BACKOFF_MAX_MULTIPLIER 1000
98
99/*
100 * Try locking path, retrying with quadratic backoff for at least
101 * timeout_ms milliseconds. If timeout_ms is 0, try locking the file
102 * exactly once. If timeout_ms is -1, try indefinitely.
103 */
104static int lock_file_timeout(struct lock_file *lk, const char *path,
fa3bff24 105 int flags, long timeout_ms, int mode)
044b6a9e
MH
106{
107 int n = 1;
108 int multiplier = 1;
a8a17756 109 long remaining_ms = 0;
044b6a9e
MH
110 static int random_initialized = 0;
111
112 if (timeout_ms == 0)
fa3bff24 113 return lock_file(lk, path, flags, mode);
044b6a9e
MH
114
115 if (!random_initialized) {
1e9676ec 116 srand((unsigned int)getpid());
044b6a9e
MH
117 random_initialized = 1;
118 }
119
a8a17756
JS
120 if (timeout_ms > 0)
121 remaining_ms = timeout_ms;
044b6a9e
MH
122
123 while (1) {
a8a17756 124 long backoff_ms, wait_ms;
044b6a9e
MH
125 int fd;
126
fa3bff24 127 fd = lock_file(lk, path, flags, mode);
044b6a9e
MH
128
129 if (fd >= 0)
130 return fd; /* success */
131 else if (errno != EEXIST)
132 return -1; /* failure other than lock held */
a8a17756 133 else if (timeout_ms > 0 && remaining_ms <= 0)
044b6a9e
MH
134 return -1; /* failure due to timeout */
135
136 backoff_ms = multiplier * INITIAL_BACKOFF_MS;
137 /* back off for between 0.75*backoff_ms and 1.25*backoff_ms */
a8a17756 138 wait_ms = (750 + rand() % 500) * backoff_ms / 1000;
30f8160d 139 sleep_millisec(wait_ms);
a8a17756 140 remaining_ms -= wait_ms;
044b6a9e
MH
141
142 /* Recursion: (n+1)^2 = n^2 + 2n + 1 */
143 multiplier += 2*n + 1;
144 if (multiplier > BACKOFF_MAX_MULTIPLIER)
145 multiplier = BACKOFF_MAX_MULTIPLIER;
146 else
147 n++;
148 }
149}
150
6af926e8 151void unable_to_lock_message(const char *path, int err, struct strbuf *buf)
e43a6fd3 152{
bdfd739d 153 if (err == EEXIST) {
3030c295 154 strbuf_addf(buf, _("Unable to create '%s.lock': %s.\n\n"
aed7480c
MM
155 "Another git process seems to be running in this repository, e.g.\n"
156 "an editor opened by 'git commit'. Please make sure all processes\n"
157 "are terminated then try again. If it still fails, a git process\n"
158 "may have crashed in this repository earlier:\n"
159 "remove the file manually to continue."),
e2a57aac 160 absolute_path(path), strerror(err));
1b018fd9 161 } else
3030c295 162 strbuf_addf(buf, _("Unable to create '%s.lock': %s"),
e2a57aac 163 absolute_path(path), strerror(err));
1b018fd9
MV
164}
165
e197c218 166NORETURN void unable_to_lock_die(const char *path, int err)
1b018fd9 167{
6af926e8
RS
168 struct strbuf buf = STRBUF_INIT;
169
170 unable_to_lock_message(path, err, &buf);
171 die("%s", buf.buf);
e43a6fd3
MM
172}
173
447ff1bf 174/* This should return a meaningful errno on failure */
fa3bff24
TB
175int hold_lock_file_for_update_timeout_mode(struct lock_file *lk,
176 const char *path, int flags,
177 long timeout_ms, int mode)
40aaae88 178{
fa3bff24 179 int fd = lock_file_timeout(lk, path, flags, timeout_ms, mode);
3f061bf5
JH
180 if (fd < 0) {
181 if (flags & LOCK_DIE_ON_ERROR)
182 unable_to_lock_die(path, errno);
183 if (flags & LOCK_REPORT_ON_ERROR) {
184 struct strbuf buf = STRBUF_INIT;
185 unable_to_lock_message(path, errno, &buf);
186 error("%s", buf.buf);
187 strbuf_release(&buf);
188 }
189 }
40aaae88
JH
190 return fd;
191}
192
ec38b4e4
MH
193char *get_locked_file_path(struct lock_file *lk)
194{
1a9d15db 195 struct strbuf ret = STRBUF_INIT;
013870cd 196
076aa2cb 197 strbuf_addstr(&ret, get_tempfile_path(lk->tempfile));
1a9d15db
MH
198 if (ret.len <= LOCK_SUFFIX_LEN ||
199 strcmp(ret.buf + ret.len - LOCK_SUFFIX_LEN, LOCK_SUFFIX))
033abf97 200 BUG("get_locked_file_path() called for malformed lock object");
9c77381d 201 /* remove ".lock": */
1a9d15db
MH
202 strbuf_setlen(&ret, ret.len - LOCK_SUFFIX_LEN);
203 return strbuf_detach(&ret, NULL);
93dcaea2
JH
204}
205
751baced 206int commit_lock_file(struct lock_file *lk)
021b6e45 207{
9c77381d 208 char *result_path = get_locked_file_path(lk);
8a1c7533 209
9c77381d 210 if (commit_lock_file_to(lk, result_path)) {
1b1648f4 211 int save_errno = errno;
9c77381d 212 free(result_path);
1b1648f4 213 errno = save_errno;
d6cf61bf 214 return -1;
1b1648f4 215 }
9c77381d 216 free(result_path);
d6cf61bf 217 return 0;
021b6e45 218}