]> git.ipfire.org Git - thirdparty/git.git/blame - lockfile.c
Enhance hold_lock_file_for_{update,append}() API
[thirdparty/git.git] / lockfile.c
CommitLineData
021b6e45
JH
1/*
2 * Copyright (c) 2005, Junio C Hamano
3 */
021b6e45
JH
4#include "cache.h"
5
6static struct lock_file *lock_file_list;
5e7f56ac 7static const char *alternate_index_output;
021b6e45
JH
8
9static void remove_lock_file(void)
10{
5e635e39
JH
11 pid_t me = getpid();
12
021b6e45 13 while (lock_file_list) {
5e635e39 14 if (lock_file_list->owner == me &&
4723ee99 15 lock_file_list->filename[0]) {
d6cf61bf
BC
16 if (lock_file_list->fd >= 0)
17 close(lock_file_list->fd);
021b6e45 18 unlink(lock_file_list->filename);
4723ee99 19 }
021b6e45
JH
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();
a1292939 27 signal(signo, SIG_DFL);
021b6e45
JH
28 raise(signo);
29}
30
5d5a7a67
BS
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
ecf4831d 98 if (is_absolute_path(link)) {
5d5a7a67
BS
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
acd3b9ec 124static int lock_file(struct lock_file *lk, const char *path, int flags)
021b6e45 125{
acd3b9ec
JH
126 if (strlen(path) >= sizeof(lk->filename))
127 return -1;
5d5a7a67
BS
128 strcpy(lk->filename, path);
129 /*
130 * subtract 5 from size to make sure there's room for adding
131 * ".lock" for the lock file name
132 */
acd3b9ec
JH
133 if (!(flags & LOCK_NODEREF))
134 resolve_symlink(lk->filename, sizeof(lk->filename)-5);
5d5a7a67 135 strcat(lk->filename, ".lock");
4723ee99
JS
136 lk->fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666);
137 if (0 <= lk->fd) {
9a4cbdca
SV
138 if (!lock_file_list) {
139 signal(SIGINT, remove_lock_file_on_signal);
ad5fa3cc
PB
140 signal(SIGHUP, remove_lock_file_on_signal);
141 signal(SIGTERM, remove_lock_file_on_signal);
142 signal(SIGQUIT, 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
acd3b9ec 160int hold_lock_file_for_update(struct lock_file *lk, const char *path, int flags)
40aaae88 161{
acd3b9ec
JH
162 int fd = lock_file(lk, path, flags);
163 if (fd < 0 && (flags & LOCK_DIE_ON_ERROR))
f9e8a43a 164 die("unable to create '%s.lock': %s", path, strerror(errno));
40aaae88
JH
165 return fd;
166}
167
acd3b9ec 168int hold_lock_file_for_append(struct lock_file *lk, const char *path, int flags)
ea3cd5c7
DB
169{
170 int fd, orig_fd;
171
acd3b9ec 172 fd = lock_file(lk, path, flags);
ea3cd5c7 173 if (fd < 0) {
acd3b9ec 174 if (flags & LOCK_DIE_ON_ERROR)
ea3cd5c7
DB
175 die("unable to create '%s.lock': %s", path, strerror(errno));
176 return fd;
177 }
178
179 orig_fd = open(path, O_RDONLY);
180 if (orig_fd < 0) {
181 if (errno != ENOENT) {
acd3b9ec 182 if (flags & LOCK_DIE_ON_ERROR)
ea3cd5c7
DB
183 die("cannot open '%s' for copying", path);
184 close(fd);
185 return error("cannot open '%s' for copying", path);
186 }
187 } else if (copy_fd(orig_fd, fd)) {
acd3b9ec 188 if (flags & LOCK_DIE_ON_ERROR)
ea3cd5c7
DB
189 exit(128);
190 close(fd);
191 return -1;
192 }
193 return fd;
194}
195
d6cf61bf
BC
196int close_lock_file(struct lock_file *lk)
197{
198 int fd = lk->fd;
199 lk->fd = -1;
200 return close(fd);
201}
202
021b6e45
JH
203int commit_lock_file(struct lock_file *lk)
204{
205 char result_file[PATH_MAX];
d6cf61bf
BC
206 size_t i;
207 if (lk->fd >= 0 && close_lock_file(lk))
208 return -1;
021b6e45
JH
209 strcpy(result_file, lk->filename);
210 i = strlen(result_file) - 5; /* .lock */
211 result_file[i] = 0;
d6cf61bf
BC
212 if (rename(lk->filename, result_file))
213 return -1;
021b6e45 214 lk->filename[0] = 0;
d6cf61bf 215 return 0;
021b6e45
JH
216}
217
30ca07a2
JH
218int hold_locked_index(struct lock_file *lk, int die_on_error)
219{
acd3b9ec
JH
220 return hold_lock_file_for_update(lk, get_index_file(),
221 die_on_error
222 ? LOCK_DIE_ON_ERROR
223 : 0);
30ca07a2
JH
224}
225
5e7f56ac
JH
226void set_alternate_index_output(const char *name)
227{
228 alternate_index_output = name;
229}
230
30ca07a2
JH
231int commit_locked_index(struct lock_file *lk)
232{
5e7f56ac 233 if (alternate_index_output) {
d6cf61bf
BC
234 if (lk->fd >= 0 && close_lock_file(lk))
235 return -1;
236 if (rename(lk->filename, alternate_index_output))
237 return -1;
30ca07a2 238 lk->filename[0] = 0;
d6cf61bf 239 return 0;
30ca07a2
JH
240 }
241 else
242 return commit_lock_file(lk);
243}
244
021b6e45
JH
245void rollback_lock_file(struct lock_file *lk)
246{
4723ee99 247 if (lk->filename[0]) {
d6cf61bf
BC
248 if (lk->fd >= 0)
249 close(lk->fd);
021b6e45 250 unlink(lk->filename);
4723ee99 251 }
021b6e45
JH
252 lk->filename[0] = 0;
253}