diff: use tempfile module
[git/mingw/j6t.git] / lockfile.c
blobe1d68f77cadc5d93f3bb5ae39f446d4390af2c59
1 /*
2 * Copyright (c) 2005, Junio C Hamano
3 */
5 #include "cache.h"
6 #include "lockfile.h"
8 /*
9 * path = absolute or relative path name
11 * Remove the last path name element from path (leaving the preceding
12 * "/", if any). If path is empty or the root directory ("/"), set
13 * path to the empty string.
15 static void trim_last_path_component(struct strbuf *path)
17 int i = path->len;
19 /* back up past trailing slashes, if any */
20 while (i && path->buf[i - 1] == '/')
21 i--;
24 * then go backwards until a slash, or the beginning of the
25 * string
27 while (i && path->buf[i - 1] != '/')
28 i--;
30 strbuf_setlen(path, i);
34 /* We allow "recursive" symbolic links. Only within reason, though */
35 #define MAXDEPTH 5
38 * path contains a path that might be a symlink.
40 * If path is a symlink, attempt to overwrite it with a path to the
41 * real file or directory (which may or may not exist), following a
42 * chain of symlinks if necessary. Otherwise, leave path unmodified.
44 * This is a best-effort routine. If an error occurs, path will
45 * either be left unmodified or will name a different symlink in a
46 * symlink chain that started with the original path.
48 static void resolve_symlink(struct strbuf *path)
50 int depth = MAXDEPTH;
51 static struct strbuf link = STRBUF_INIT;
53 while (depth--) {
54 if (strbuf_readlink(&link, path->buf, path->len) < 0)
55 break;
57 if (is_absolute_path(link.buf))
58 /* absolute path simply replaces p */
59 strbuf_reset(path);
60 else
62 * link is a relative path, so replace the
63 * last element of p with it.
65 trim_last_path_component(path);
67 strbuf_addbuf(path, &link);
69 strbuf_reset(&link);
72 /* Make sure errno contains a meaningful value on error */
73 static int lock_file(struct lock_file *lk, const char *path, int flags)
75 int fd;
76 struct strbuf filename = STRBUF_INIT;
78 strbuf_addstr(&filename, path);
79 if (!(flags & LOCK_NO_DEREF))
80 resolve_symlink(&filename);
82 strbuf_addstr(&filename, LOCK_SUFFIX);
83 fd = create_tempfile(&lk->tempfile, filename.buf);
84 strbuf_release(&filename);
85 return fd;
88 static int sleep_microseconds(long us)
90 struct timeval tv;
91 tv.tv_sec = 0;
92 tv.tv_usec = us;
93 return select(0, NULL, NULL, NULL, &tv);
97 * Constants defining the gaps between attempts to lock a file. The
98 * first backoff period is approximately INITIAL_BACKOFF_MS
99 * milliseconds. The longest backoff period is approximately
100 * (BACKOFF_MAX_MULTIPLIER * INITIAL_BACKOFF_MS) milliseconds.
102 #define INITIAL_BACKOFF_MS 1L
103 #define BACKOFF_MAX_MULTIPLIER 1000
106 * Try locking path, retrying with quadratic backoff for at least
107 * timeout_ms milliseconds. If timeout_ms is 0, try locking the file
108 * exactly once. If timeout_ms is -1, try indefinitely.
110 static int lock_file_timeout(struct lock_file *lk, const char *path,
111 int flags, long timeout_ms)
113 int n = 1;
114 int multiplier = 1;
115 long remaining_us = 0;
116 static int random_initialized = 0;
118 if (timeout_ms == 0)
119 return lock_file(lk, path, flags);
121 if (!random_initialized) {
122 srandom((unsigned int)getpid());
123 random_initialized = 1;
126 if (timeout_ms > 0) {
127 /* avoid overflow */
128 if (timeout_ms <= LONG_MAX / 1000)
129 remaining_us = timeout_ms * 1000;
130 else
131 remaining_us = LONG_MAX;
134 while (1) {
135 long backoff_ms, wait_us;
136 int fd;
138 fd = lock_file(lk, path, flags);
140 if (fd >= 0)
141 return fd; /* success */
142 else if (errno != EEXIST)
143 return -1; /* failure other than lock held */
144 else if (timeout_ms > 0 && remaining_us <= 0)
145 return -1; /* failure due to timeout */
147 backoff_ms = multiplier * INITIAL_BACKOFF_MS;
148 /* back off for between 0.75*backoff_ms and 1.25*backoff_ms */
149 wait_us = (750 + random() % 500) * backoff_ms;
150 sleep_microseconds(wait_us);
151 remaining_us -= wait_us;
153 /* Recursion: (n+1)^2 = n^2 + 2n + 1 */
154 multiplier += 2*n + 1;
155 if (multiplier > BACKOFF_MAX_MULTIPLIER)
156 multiplier = BACKOFF_MAX_MULTIPLIER;
157 else
158 n++;
162 void unable_to_lock_message(const char *path, int err, struct strbuf *buf)
164 if (err == EEXIST) {
165 strbuf_addf(buf, "Unable to create '%s.lock': %s.\n\n"
166 "If no other git process is currently running, this probably means a\n"
167 "git process crashed in this repository earlier. Make sure no other git\n"
168 "process is running and remove the file manually to continue.",
169 absolute_path(path), strerror(err));
170 } else
171 strbuf_addf(buf, "Unable to create '%s.lock': %s",
172 absolute_path(path), strerror(err));
175 NORETURN void unable_to_lock_die(const char *path, int err)
177 struct strbuf buf = STRBUF_INIT;
179 unable_to_lock_message(path, err, &buf);
180 die("%s", buf.buf);
183 /* This should return a meaningful errno on failure */
184 int hold_lock_file_for_update_timeout(struct lock_file *lk, const char *path,
185 int flags, long timeout_ms)
187 int fd = lock_file_timeout(lk, path, flags, timeout_ms);
188 if (fd < 0 && (flags & LOCK_DIE_ON_ERROR))
189 unable_to_lock_die(path, errno);
190 return fd;
193 int hold_lock_file_for_append(struct lock_file *lk, const char *path, int flags)
195 int fd, orig_fd;
197 fd = lock_file(lk, path, flags);
198 if (fd < 0) {
199 if (flags & LOCK_DIE_ON_ERROR)
200 unable_to_lock_die(path, errno);
201 return fd;
204 orig_fd = open(path, O_RDONLY);
205 if (orig_fd < 0) {
206 if (errno != ENOENT) {
207 int save_errno = errno;
209 if (flags & LOCK_DIE_ON_ERROR)
210 die("cannot open '%s' for copying", path);
211 rollback_lock_file(lk);
212 error("cannot open '%s' for copying", path);
213 errno = save_errno;
214 return -1;
216 } else if (copy_fd(orig_fd, fd)) {
217 int save_errno = errno;
219 if (flags & LOCK_DIE_ON_ERROR)
220 die("failed to prepare '%s' for appending", path);
221 close(orig_fd);
222 rollback_lock_file(lk);
223 errno = save_errno;
224 return -1;
225 } else {
226 close(orig_fd);
228 return fd;
231 char *get_locked_file_path(struct lock_file *lk)
233 struct strbuf ret = STRBUF_INIT;
235 strbuf_addstr(&ret, get_tempfile_path(&lk->tempfile));
236 if (ret.len <= LOCK_SUFFIX_LEN ||
237 strcmp(ret.buf + ret.len - LOCK_SUFFIX_LEN, LOCK_SUFFIX))
238 die("BUG: get_locked_file_path() called for malformed lock object");
239 /* remove ".lock": */
240 strbuf_setlen(&ret, ret.len - LOCK_SUFFIX_LEN);
241 return strbuf_detach(&ret, NULL);
244 int commit_lock_file(struct lock_file *lk)
246 char *result_path = get_locked_file_path(lk);
248 if (commit_lock_file_to(lk, result_path)) {
249 int save_errno = errno;
250 free(result_path);
251 errno = save_errno;
252 return -1;
254 free(result_path);
255 return 0;