trailer: add data structures and basic functions
[git/mjg.git] / lockfile.c
blob2a800cef33ed7fb1ba7d3499459eccd824ab33e4
1 /*
2 * Copyright (c) 2005, Junio C Hamano
3 */
4 #include "cache.h"
5 #include "sigchain.h"
7 static struct lock_file *lock_file_list;
9 static void remove_lock_file(void)
11 pid_t me = getpid();
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);
20 lock_file_list = lock_file_list->next;
24 static void remove_lock_file_on_signal(int signo)
26 remove_lock_file();
27 sigchain_pop(signo);
28 raise(signo);
32 * p = absolute or relative path name
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.
37 static char *last_path_elm(char *p)
39 /* r starts pointing to null at the end of the string */
40 char *r = strchr(p, '\0');
42 if (r == p)
43 return p; /* just return empty string */
45 r--; /* back up to last non-null character */
47 /* back up past trailing slashes, if any */
48 while (r > p && *r == '/')
49 r--;
52 * then go backwards until I hit a slash, or the beginning of
53 * the string
55 while (r > p && *(r-1) != '/')
56 r--;
57 return r;
61 /* We allow "recursive" symbolic links. Only within reason, though */
62 #define MAXDEPTH 5
65 * p = path that may be a symlink
66 * s = full size of p
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.
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.
76 * Always returns p.
79 static char *resolve_symlink(char *p, size_t s)
81 int depth = MAXDEPTH;
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;
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;
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;
106 } else {
108 * link is a relative path, so I must replace the
109 * last element of p with it.
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;
120 return p;
123 /* Make sure errno contains a meaningful value on error */
124 static int lock_file(struct lock_file *lk, const char *path, int flags)
127 * subtract 5 from size to make sure there's room for adding
128 * ".lock" for the lock file name
130 static const size_t max_path_len = sizeof(lk->filename) - 5;
132 if (strlen(path) >= max_path_len) {
133 errno = ENAMETOOLONG;
134 return -1;
136 strcpy(lk->filename, path);
137 if (!(flags & LOCK_NODEREF))
138 resolve_symlink(lk->filename, max_path_len);
139 strcat(lk->filename, ".lock");
140 lk->fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666);
141 if (0 <= lk->fd) {
142 if (!lock_file_list) {
143 sigchain_push_common(remove_lock_file_on_signal);
144 atexit(remove_lock_file);
146 lk->owner = getpid();
147 if (!lk->on_list) {
148 lk->next = lock_file_list;
149 lock_file_list = lk;
150 lk->on_list = 1;
152 if (adjust_shared_perm(lk->filename)) {
153 int save_errno = errno;
154 error("cannot fix permission bits on %s",
155 lk->filename);
156 errno = save_errno;
157 return -1;
160 else
161 lk->filename[0] = 0;
162 return lk->fd;
165 void unable_to_lock_message(const char *path, int err, struct strbuf *buf)
167 if (err == EEXIST) {
168 strbuf_addf(buf, "Unable to create '%s.lock': %s.\n\n"
169 "If no other git process is currently running, this probably means a\n"
170 "git process crashed in this repository earlier. Make sure no other git\n"
171 "process is running and remove the file manually to continue.",
172 absolute_path(path), strerror(err));
173 } else
174 strbuf_addf(buf, "Unable to create '%s.lock': %s",
175 absolute_path(path), strerror(err));
178 int unable_to_lock_error(const char *path, int err)
180 struct strbuf buf = STRBUF_INIT;
182 unable_to_lock_message(path, err, &buf);
183 error("%s", buf.buf);
184 strbuf_release(&buf);
185 return -1;
188 NORETURN void unable_to_lock_index_die(const char *path, int err)
190 struct strbuf buf = STRBUF_INIT;
192 unable_to_lock_message(path, err, &buf);
193 die("%s", buf.buf);
196 /* This should return a meaningful errno on failure */
197 int hold_lock_file_for_update(struct lock_file *lk, const char *path, int flags)
199 int fd = lock_file(lk, path, flags);
200 if (fd < 0 && (flags & LOCK_DIE_ON_ERROR))
201 unable_to_lock_index_die(path, errno);
202 return fd;
205 int hold_lock_file_for_append(struct lock_file *lk, const char *path, int flags)
207 int fd, orig_fd;
209 fd = lock_file(lk, path, flags);
210 if (fd < 0) {
211 if (flags & LOCK_DIE_ON_ERROR)
212 unable_to_lock_index_die(path, errno);
213 return fd;
216 orig_fd = open(path, O_RDONLY);
217 if (orig_fd < 0) {
218 if (errno != ENOENT) {
219 if (flags & LOCK_DIE_ON_ERROR)
220 die("cannot open '%s' for copying", path);
221 close(fd);
222 return error("cannot open '%s' for copying", path);
224 } else if (copy_fd(orig_fd, fd)) {
225 if (flags & LOCK_DIE_ON_ERROR)
226 exit(128);
227 close(fd);
228 return -1;
230 return fd;
233 int close_lock_file(struct lock_file *lk)
235 int fd = lk->fd;
236 lk->fd = -1;
237 return close(fd);
240 int reopen_lock_file(struct lock_file *lk)
242 if (0 <= lk->fd)
243 die(_("BUG: reopen a lockfile that is still open"));
244 if (!lk->filename[0])
245 die(_("BUG: reopen a lockfile that has been committed"));
246 lk->fd = open(lk->filename, O_WRONLY);
247 return lk->fd;
250 int commit_lock_file(struct lock_file *lk)
252 char result_file[PATH_MAX];
253 size_t i;
254 if (lk->fd >= 0 && close_lock_file(lk))
255 return -1;
256 strcpy(result_file, lk->filename);
257 i = strlen(result_file) - 5; /* .lock */
258 result_file[i] = 0;
259 if (rename(lk->filename, result_file))
260 return -1;
261 lk->filename[0] = 0;
262 return 0;
265 int hold_locked_index(struct lock_file *lk, int die_on_error)
267 return hold_lock_file_for_update(lk, get_index_file(),
268 die_on_error
269 ? LOCK_DIE_ON_ERROR
270 : 0);
273 void rollback_lock_file(struct lock_file *lk)
275 if (lk->filename[0]) {
276 if (lk->fd >= 0)
277 close(lk->fd);
278 unlink_or_warn(lk->filename);
280 lk->filename[0] = 0;