lockfile: fix buffer overflow in path handling
[git/git.git] / lockfile.c
CommitLineData
021b6e45
JH
1/*
2 * Copyright (c) 2005, Junio C Hamano
3 */
021b6e45 4#include "cache.h"
4a16d072 5#include "sigchain.h"
021b6e45
JH
6
7static struct lock_file *lock_file_list;
5e7f56ac 8static const char *alternate_index_output;
021b6e45
JH
9
10static void remove_lock_file(void)
11{
5e635e39
JH
12 pid_t me = getpid();
13
021b6e45 14 while (lock_file_list) {
5e635e39 15 if (lock_file_list->owner == me &&
4723ee99 16 lock_file_list->filename[0]) {
d6cf61bf
BC
17 if (lock_file_list->fd >= 0)
18 close(lock_file_list->fd);
691f1a28 19 unlink_or_warn(lock_file_list->filename);
4723ee99 20 }
021b6e45
JH
21 lock_file_list = lock_file_list->next;
22 }
23}
24
25static void remove_lock_file_on_signal(int signo)
26{
27 remove_lock_file();
4a16d072 28 sigchain_pop(signo);
021b6e45
JH
29 raise(signo);
30}
31
5d5a7a67
BS
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 */
38static 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
80static 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
ecf4831d 99 if (is_absolute_path(link)) {
5d5a7a67
BS
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 */
4b25d091 112 char *r = (char *)last_path_elm(p);
5d5a7a67
BS
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
acd3b9ec 125static int lock_file(struct lock_file *lk, const char *path, int flags)
021b6e45 126{
5d5a7a67
BS
127 /*
128 * subtract 5 from size to make sure there's room for adding
129 * ".lock" for the lock file name
130 */
2fbd4f92
MH
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);
acd3b9ec 136 if (!(flags & LOCK_NODEREF))
2fbd4f92 137 resolve_symlink(lk->filename, max_path_len);
5d5a7a67 138 strcat(lk->filename, ".lock");
4723ee99
JS
139 lk->fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666);
140 if (0 <= lk->fd) {
9a4cbdca 141 if (!lock_file_list) {
57b235a4 142 sigchain_push_common(remove_lock_file_on_signal);
9a4cbdca
SV
143 atexit(remove_lock_file);
144 }
5e635e39 145 lk->owner = getpid();
1084b845 146 if (!lk->on_list) {
138086a7
JH
147 lk->next = lock_file_list;
148 lock_file_list = lk;
1084b845
JH
149 lk->on_list = 1;
150 }
138086a7
JH
151 if (adjust_shared_perm(lk->filename))
152 return error("cannot fix permission bits on %s",
153 lk->filename);
021b6e45 154 }
1084b845
JH
155 else
156 lk->filename[0] = 0;
4723ee99 157 return lk->fd;
021b6e45
JH
158}
159
1b018fd9 160static char *unable_to_lock_message(const char *path, int err)
e43a6fd3 161{
1b018fd9
MV
162 struct strbuf buf = STRBUF_INIT;
163
bdfd739d 164 if (err == EEXIST) {
1b018fd9 165 strbuf_addf(&buf, "Unable to create '%s.lock': %s.\n\n"
e43a6fd3
MM
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.",
e2a57aac 169 absolute_path(path), strerror(err));
1b018fd9 170 } else
a8c37a0e 171 strbuf_addf(&buf, "Unable to create '%s.lock': %s",
e2a57aac 172 absolute_path(path), strerror(err));
1b018fd9
MV
173 return strbuf_detach(&buf, NULL);
174}
175
176int unable_to_lock_error(const char *path, int err)
177{
178 char *msg = unable_to_lock_message(path, err);
179 error("%s", msg);
180 free(msg);
181 return -1;
182}
183
184NORETURN void unable_to_lock_index_die(const char *path, int err)
185{
186 die("%s", unable_to_lock_message(path, err));
e43a6fd3
MM
187}
188
acd3b9ec 189int hold_lock_file_for_update(struct lock_file *lk, const char *path, int flags)
40aaae88 190{
acd3b9ec
JH
191 int fd = lock_file(lk, path, flags);
192 if (fd < 0 && (flags & LOCK_DIE_ON_ERROR))
e43a6fd3 193 unable_to_lock_index_die(path, errno);
40aaae88
JH
194 return fd;
195}
196
acd3b9ec 197int hold_lock_file_for_append(struct lock_file *lk, const char *path, int flags)
ea3cd5c7
DB
198{
199 int fd, orig_fd;
200
acd3b9ec 201 fd = lock_file(lk, path, flags);
ea3cd5c7 202 if (fd < 0) {
acd3b9ec 203 if (flags & LOCK_DIE_ON_ERROR)
bdfd739d 204 unable_to_lock_index_die(path, errno);
ea3cd5c7
DB
205 return fd;
206 }
207
208 orig_fd = open(path, O_RDONLY);
209 if (orig_fd < 0) {
210 if (errno != ENOENT) {
acd3b9ec 211 if (flags & LOCK_DIE_ON_ERROR)
ea3cd5c7
DB
212 die("cannot open '%s' for copying", path);
213 close(fd);
214 return error("cannot open '%s' for copying", path);
215 }
216 } else if (copy_fd(orig_fd, fd)) {
acd3b9ec 217 if (flags & LOCK_DIE_ON_ERROR)
ea3cd5c7
DB
218 exit(128);
219 close(fd);
220 return -1;
221 }
222 return fd;
223}
224
d6cf61bf
BC
225int close_lock_file(struct lock_file *lk)
226{
227 int fd = lk->fd;
228 lk->fd = -1;
229 return close(fd);
230}
231
021b6e45
JH
232int commit_lock_file(struct lock_file *lk)
233{
234 char result_file[PATH_MAX];
d6cf61bf
BC
235 size_t i;
236 if (lk->fd >= 0 && close_lock_file(lk))
237 return -1;
021b6e45
JH
238 strcpy(result_file, lk->filename);
239 i = strlen(result_file) - 5; /* .lock */
240 result_file[i] = 0;
d6cf61bf
BC
241 if (rename(lk->filename, result_file))
242 return -1;
021b6e45 243 lk->filename[0] = 0;
d6cf61bf 244 return 0;
021b6e45
JH
245}
246
30ca07a2
JH
247int hold_locked_index(struct lock_file *lk, int die_on_error)
248{
acd3b9ec
JH
249 return hold_lock_file_for_update(lk, get_index_file(),
250 die_on_error
251 ? LOCK_DIE_ON_ERROR
252 : 0);
30ca07a2
JH
253}
254
5e7f56ac
JH
255void set_alternate_index_output(const char *name)
256{
257 alternate_index_output = name;
258}
259
30ca07a2
JH
260int commit_locked_index(struct lock_file *lk)
261{
5e7f56ac 262 if (alternate_index_output) {
d6cf61bf
BC
263 if (lk->fd >= 0 && close_lock_file(lk))
264 return -1;
265 if (rename(lk->filename, alternate_index_output))
266 return -1;
30ca07a2 267 lk->filename[0] = 0;
d6cf61bf 268 return 0;
30ca07a2
JH
269 }
270 else
271 return commit_lock_file(lk);
272}
273
021b6e45
JH
274void rollback_lock_file(struct lock_file *lk)
275{
4723ee99 276 if (lk->filename[0]) {
d6cf61bf
BC
277 if (lk->fd >= 0)
278 close(lk->fd);
691f1a28 279 unlink_or_warn(lk->filename);
4723ee99 280 }
021b6e45
JH
281 lk->filename[0] = 0;
282}