]> git.ipfire.org Git - thirdparty/git.git/blame - lockfile.c
Merge master into aw/mirror-push
[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
JH
14 if (lock_file_list->owner == me &&
15 lock_file_list->filename[0])
021b6e45
JH
16 unlink(lock_file_list->filename);
17 lock_file_list = lock_file_list->next;
18 }
19}
20
21static void remove_lock_file_on_signal(int signo)
22{
23 remove_lock_file();
24 signal(SIGINT, SIG_DFL);
25 raise(signo);
26}
27
5d5a7a67
BS
28/*
29 * p = absolute or relative path name
30 *
31 * Return a pointer into p showing the beginning of the last path name
32 * element. If p is empty or the root directory ("/"), just return p.
33 */
34static char *last_path_elm(char *p)
35{
36 /* r starts pointing to null at the end of the string */
37 char *r = strchr(p, '\0');
38
39 if (r == p)
40 return p; /* just return empty string */
41
42 r--; /* back up to last non-null character */
43
44 /* back up past trailing slashes, if any */
45 while (r > p && *r == '/')
46 r--;
47
48 /*
49 * then go backwards until I hit a slash, or the beginning of
50 * the string
51 */
52 while (r > p && *(r-1) != '/')
53 r--;
54 return r;
55}
56
57
58/* We allow "recursive" symbolic links. Only within reason, though */
59#define MAXDEPTH 5
60
61/*
62 * p = path that may be a symlink
63 * s = full size of p
64 *
65 * If p is a symlink, attempt to overwrite p with a path to the real
66 * file or directory (which may or may not exist), following a chain of
67 * symlinks if necessary. Otherwise, leave p unmodified.
68 *
69 * This is a best-effort routine. If an error occurs, p will either be
70 * left unmodified or will name a different symlink in a symlink chain
71 * that started with p's initial contents.
72 *
73 * Always returns p.
74 */
75
76static char *resolve_symlink(char *p, size_t s)
77{
78 int depth = MAXDEPTH;
79
80 while (depth--) {
81 char link[PATH_MAX];
82 int link_len = readlink(p, link, sizeof(link));
83 if (link_len < 0) {
84 /* not a symlink anymore */
85 return p;
86 }
87 else if (link_len < sizeof(link))
88 /* readlink() never null-terminates */
89 link[link_len] = '\0';
90 else {
91 warning("%s: symlink too long", p);
92 return p;
93 }
94
95 if (link[0] == '/') {
96 /* absolute path simply replaces p */
97 if (link_len < s)
98 strcpy(p, link);
99 else {
100 warning("%s: symlink too long", p);
101 return p;
102 }
103 } else {
104 /*
105 * link is a relative path, so I must replace the
106 * last element of p with it.
107 */
108 char *r = (char*)last_path_elm(p);
109 if (r - p + link_len < s)
110 strcpy(r, link);
111 else {
112 warning("%s: symlink too long", p);
113 return p;
114 }
115 }
116 }
117 return p;
118}
119
120
40aaae88 121static int lock_file(struct lock_file *lk, const char *path)
021b6e45
JH
122{
123 int fd;
5d5a7a67
BS
124
125 if (strlen(path) >= sizeof(lk->filename)) return -1;
126 strcpy(lk->filename, path);
127 /*
128 * subtract 5 from size to make sure there's room for adding
129 * ".lock" for the lock file name
130 */
131 resolve_symlink(lk->filename, sizeof(lk->filename)-5);
132 strcat(lk->filename, ".lock");
021b6e45 133 fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666);
138086a7 134 if (0 <= fd) {
9a4cbdca
SV
135 if (!lock_file_list) {
136 signal(SIGINT, remove_lock_file_on_signal);
137 atexit(remove_lock_file);
138 }
5e635e39 139 lk->owner = getpid();
1084b845 140 if (!lk->on_list) {
138086a7
JH
141 lk->next = lock_file_list;
142 lock_file_list = lk;
1084b845
JH
143 lk->on_list = 1;
144 }
138086a7
JH
145 if (adjust_shared_perm(lk->filename))
146 return error("cannot fix permission bits on %s",
147 lk->filename);
021b6e45 148 }
1084b845
JH
149 else
150 lk->filename[0] = 0;
021b6e45
JH
151 return fd;
152}
153
40aaae88
JH
154int hold_lock_file_for_update(struct lock_file *lk, const char *path, int die_on_error)
155{
156 int fd = lock_file(lk, path);
157 if (fd < 0 && die_on_error)
f9e8a43a 158 die("unable to create '%s.lock': %s", path, strerror(errno));
40aaae88
JH
159 return fd;
160}
161
021b6e45
JH
162int commit_lock_file(struct lock_file *lk)
163{
164 char result_file[PATH_MAX];
165 int i;
166 strcpy(result_file, lk->filename);
167 i = strlen(result_file) - 5; /* .lock */
168 result_file[i] = 0;
169 i = rename(lk->filename, result_file);
170 lk->filename[0] = 0;
171 return i;
172}
173
30ca07a2
JH
174int hold_locked_index(struct lock_file *lk, int die_on_error)
175{
176 return hold_lock_file_for_update(lk, get_index_file(), die_on_error);
177}
178
5e7f56ac
JH
179void set_alternate_index_output(const char *name)
180{
181 alternate_index_output = name;
182}
183
30ca07a2
JH
184int commit_locked_index(struct lock_file *lk)
185{
5e7f56ac
JH
186 if (alternate_index_output) {
187 int result = rename(lk->filename, alternate_index_output);
30ca07a2
JH
188 lk->filename[0] = 0;
189 return result;
190 }
191 else
192 return commit_lock_file(lk);
193}
194
021b6e45
JH
195void rollback_lock_file(struct lock_file *lk)
196{
197 if (lk->filename[0])
198 unlink(lk->filename);
199 lk->filename[0] = 0;
200}