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