git-svn: use path accessor for Git::SVN objects
[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         if (strlen(path) >= sizeof(lk->filename))
128                 return -1;
129         strcpy(lk->filename, path);
130         /*
131          * subtract 5 from size to make sure there's room for adding
132          * ".lock" for the lock file name
133          */
134         if (!(flags & LOCK_NODEREF))
135                 resolve_symlink(lk->filename, sizeof(lk->filename)-5);
136         strcat(lk->filename, ".lock");
137         lk->fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666);
138         if (0 <= lk->fd) {
139                 if (!lock_file_list) {
140                         sigchain_push_common(remove_lock_file_on_signal);
141                         atexit(remove_lock_file);
142                 }
143                 lk->owner = getpid();
144                 if (!lk->on_list) {
145                         lk->next = lock_file_list;
146                         lock_file_list = lk;
147                         lk->on_list = 1;
148                 }
149                 if (adjust_shared_perm(lk->filename))
150                         return error("cannot fix permission bits on %s",
151                                      lk->filename);
152         }
153         else
154                 lk->filename[0] = 0;
155         return lk->fd;
156 }
157
158 static char *unable_to_lock_message(const char *path, int err)
159 {
160         struct strbuf buf = STRBUF_INIT;
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         return strbuf_detach(&buf, NULL);
172 }
173
174 int unable_to_lock_error(const char *path, int err)
175 {
176         char *msg = unable_to_lock_message(path, err);
177         error("%s", msg);
178         free(msg);
179         return -1;
180 }
181
182 NORETURN void unable_to_lock_index_die(const char *path, int err)
183 {
184         die("%s", unable_to_lock_message(path, err));
185 }
186
187 int hold_lock_file_for_update(struct lock_file *lk, const char *path, int flags)
188 {
189         int fd = lock_file(lk, path, flags);
190         if (fd < 0 && (flags & LOCK_DIE_ON_ERROR))
191                 unable_to_lock_index_die(path, errno);
192         return fd;
193 }
194
195 int hold_lock_file_for_append(struct lock_file *lk, const char *path, int flags)
196 {
197         int fd, orig_fd;
198
199         fd = lock_file(lk, path, flags);
200         if (fd < 0) {
201                 if (flags & LOCK_DIE_ON_ERROR)
202                         unable_to_lock_index_die(path, errno);
203                 return fd;
204         }
205
206         orig_fd = open(path, O_RDONLY);
207         if (orig_fd < 0) {
208                 if (errno != ENOENT) {
209                         if (flags & LOCK_DIE_ON_ERROR)
210                                 die("cannot open '%s' for copying", path);
211                         close(fd);
212                         return error("cannot open '%s' for copying", path);
213                 }
214         } else if (copy_fd(orig_fd, fd)) {
215                 if (flags & LOCK_DIE_ON_ERROR)
216                         exit(128);
217                 close(fd);
218                 return -1;
219         }
220         return fd;
221 }
222
223 int close_lock_file(struct lock_file *lk)
224 {
225         int fd = lk->fd;
226         lk->fd = -1;
227         return close(fd);
228 }
229
230 int commit_lock_file(struct lock_file *lk)
231 {
232         char result_file[PATH_MAX];
233         size_t i;
234         if (lk->fd >= 0 && close_lock_file(lk))
235                 return -1;
236         strcpy(result_file, lk->filename);
237         i = strlen(result_file) - 5; /* .lock */
238         result_file[i] = 0;
239         if (rename(lk->filename, result_file))
240                 return -1;
241         lk->filename[0] = 0;
242         return 0;
243 }
244
245 int hold_locked_index(struct lock_file *lk, int die_on_error)
246 {
247         return hold_lock_file_for_update(lk, get_index_file(),
248                                          die_on_error
249                                          ? LOCK_DIE_ON_ERROR
250                                          : 0);
251 }
252
253 void set_alternate_index_output(const char *name)
254 {
255         alternate_index_output = name;
256 }
257
258 int commit_locked_index(struct lock_file *lk)
259 {
260         if (alternate_index_output) {
261                 if (lk->fd >= 0 && close_lock_file(lk))
262                         return -1;
263                 if (rename(lk->filename, alternate_index_output))
264                         return -1;
265                 lk->filename[0] = 0;
266                 return 0;
267         }
268         else
269                 return commit_lock_file(lk);
270 }
271
272 void rollback_lock_file(struct lock_file *lk)
273 {
274         if (lk->filename[0]) {
275                 if (lk->fd >= 0)
276                         close(lk->fd);
277                 unlink_or_warn(lk->filename);
278         }
279         lk->filename[0] = 0;
280 }