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