]> git.ipfire.org Git - thirdparty/git.git/blob - lockfile.c
lockfile.c: add a new public function unable_to_lock_message
[thirdparty/git.git] / lockfile.c
1 /*
2 * Copyright (c) 2005, Junio C Hamano
3 */
4 #include "cache.h"
5 #include "sigchain.h"
6
7 static struct lock_file *lock_file_list;
8 static const char *alternate_index_output;
9
10 static void remove_lock_file(void)
11 {
12 pid_t me = getpid();
13
14 while (lock_file_list) {
15 if (lock_file_list->owner == me &&
16 lock_file_list->filename[0]) {
17 if (lock_file_list->fd >= 0)
18 close(lock_file_list->fd);
19 unlink_or_warn(lock_file_list->filename);
20 }
21 lock_file_list = lock_file_list->next;
22 }
23 }
24
25 static void remove_lock_file_on_signal(int signo)
26 {
27 remove_lock_file();
28 sigchain_pop(signo);
29 raise(signo);
30 }
31
32 /*
33 * p = absolute or relative path name
34 *
35 * Return a pointer into p showing the beginning of the last path name
36 * element. If p is empty or the root directory ("/"), just return p.
37 */
38 static char *last_path_elm(char *p)
39 {
40 /* r starts pointing to null at the end of the string */
41 char *r = strchr(p, '\0');
42
43 if (r == p)
44 return p; /* just return empty string */
45
46 r--; /* back up to last non-null character */
47
48 /* back up past trailing slashes, if any */
49 while (r > p && *r == '/')
50 r--;
51
52 /*
53 * then go backwards until I hit a slash, or the beginning of
54 * the string
55 */
56 while (r > p && *(r-1) != '/')
57 r--;
58 return r;
59 }
60
61
62 /* We allow "recursive" symbolic links. Only within reason, though */
63 #define MAXDEPTH 5
64
65 /*
66 * p = path that may be a symlink
67 * s = full size of p
68 *
69 * If p is a symlink, attempt to overwrite p with a path to the real
70 * file or directory (which may or may not exist), following a chain of
71 * symlinks if necessary. Otherwise, leave p unmodified.
72 *
73 * This is a best-effort routine. If an error occurs, p will either be
74 * left unmodified or will name a different symlink in a symlink chain
75 * that started with p's initial contents.
76 *
77 * Always returns p.
78 */
79
80 static char *resolve_symlink(char *p, size_t s)
81 {
82 int depth = MAXDEPTH;
83
84 while (depth--) {
85 char link[PATH_MAX];
86 int link_len = readlink(p, link, sizeof(link));
87 if (link_len < 0) {
88 /* not a symlink anymore */
89 return p;
90 }
91 else if (link_len < sizeof(link))
92 /* readlink() never null-terminates */
93 link[link_len] = '\0';
94 else {
95 warning("%s: symlink too long", p);
96 return p;
97 }
98
99 if (is_absolute_path(link)) {
100 /* absolute path simply replaces p */
101 if (link_len < s)
102 strcpy(p, link);
103 else {
104 warning("%s: symlink too long", p);
105 return p;
106 }
107 } else {
108 /*
109 * link is a relative path, so I must replace the
110 * last element of p with it.
111 */
112 char *r = (char *)last_path_elm(p);
113 if (r - p + link_len < s)
114 strcpy(r, link);
115 else {
116 warning("%s: symlink too long", p);
117 return p;
118 }
119 }
120 }
121 return p;
122 }
123
124
125 static int lock_file(struct lock_file *lk, const char *path, int flags)
126 {
127 /*
128 * subtract 5 from size to make sure there's room for adding
129 * ".lock" for the lock file name
130 */
131 static const size_t max_path_len = sizeof(lk->filename) - 5;
132
133 if (strlen(path) >= max_path_len)
134 return -1;
135 strcpy(lk->filename, path);
136 if (!(flags & LOCK_NODEREF))
137 resolve_symlink(lk->filename, max_path_len);
138 strcat(lk->filename, ".lock");
139 lk->fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666);
140 if (0 <= lk->fd) {
141 if (!lock_file_list) {
142 sigchain_push_common(remove_lock_file_on_signal);
143 atexit(remove_lock_file);
144 }
145 lk->owner = getpid();
146 if (!lk->on_list) {
147 lk->next = lock_file_list;
148 lock_file_list = lk;
149 lk->on_list = 1;
150 }
151 if (adjust_shared_perm(lk->filename))
152 return error("cannot fix permission bits on %s",
153 lk->filename);
154 }
155 else
156 lk->filename[0] = 0;
157 return lk->fd;
158 }
159
160 void 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
173 int unable_to_lock_error(const char *path, int err)
174 {
175 struct strbuf buf = STRBUF_INIT;
176
177 unable_to_lock_message(path, err, &buf);
178 error("%s", buf.buf);
179 strbuf_release(&buf);
180 return -1;
181 }
182
183 NORETURN void unable_to_lock_index_die(const char *path, int err)
184 {
185 struct strbuf buf = STRBUF_INIT;
186
187 unable_to_lock_message(path, err, &buf);
188 die("%s", buf.buf);
189 }
190
191 int hold_lock_file_for_update(struct lock_file *lk, const char *path, int flags)
192 {
193 int fd = lock_file(lk, path, flags);
194 if (fd < 0 && (flags & LOCK_DIE_ON_ERROR))
195 unable_to_lock_index_die(path, errno);
196 return fd;
197 }
198
199 int hold_lock_file_for_append(struct lock_file *lk, const char *path, int flags)
200 {
201 int fd, orig_fd;
202
203 fd = lock_file(lk, path, flags);
204 if (fd < 0) {
205 if (flags & LOCK_DIE_ON_ERROR)
206 unable_to_lock_index_die(path, errno);
207 return fd;
208 }
209
210 orig_fd = open(path, O_RDONLY);
211 if (orig_fd < 0) {
212 if (errno != ENOENT) {
213 if (flags & LOCK_DIE_ON_ERROR)
214 die("cannot open '%s' for copying", path);
215 close(fd);
216 return error("cannot open '%s' for copying", path);
217 }
218 } else if (copy_fd(orig_fd, fd)) {
219 if (flags & LOCK_DIE_ON_ERROR)
220 exit(128);
221 close(fd);
222 return -1;
223 }
224 return fd;
225 }
226
227 int close_lock_file(struct lock_file *lk)
228 {
229 int fd = lk->fd;
230 lk->fd = -1;
231 return close(fd);
232 }
233
234 int commit_lock_file(struct lock_file *lk)
235 {
236 char result_file[PATH_MAX];
237 size_t i;
238 if (lk->fd >= 0 && close_lock_file(lk))
239 return -1;
240 strcpy(result_file, lk->filename);
241 i = strlen(result_file) - 5; /* .lock */
242 result_file[i] = 0;
243 if (rename(lk->filename, result_file))
244 return -1;
245 lk->filename[0] = 0;
246 return 0;
247 }
248
249 int hold_locked_index(struct lock_file *lk, int die_on_error)
250 {
251 return hold_lock_file_for_update(lk, get_index_file(),
252 die_on_error
253 ? LOCK_DIE_ON_ERROR
254 : 0);
255 }
256
257 void set_alternate_index_output(const char *name)
258 {
259 alternate_index_output = name;
260 }
261
262 int commit_locked_index(struct lock_file *lk)
263 {
264 if (alternate_index_output) {
265 if (lk->fd >= 0 && close_lock_file(lk))
266 return -1;
267 if (rename(lk->filename, alternate_index_output))
268 return -1;
269 lk->filename[0] = 0;
270 return 0;
271 }
272 else
273 return commit_lock_file(lk);
274 }
275
276 void rollback_lock_file(struct lock_file *lk)
277 {
278 if (lk->filename[0]) {
279 if (lk->fd >= 0)
280 close(lk->fd);
281 unlink_or_warn(lk->filename);
282 }
283 lk->filename[0] = 0;
284 }