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