msvc: add pragmas for common warnings
[git] / lockfile.c
1 /*
2  * Copyright (c) 2005, Junio C Hamano
3  */
4
5 #include "cache.h"
6 #include "lockfile.h"
7
8 /*
9  * path = absolute or relative path name
10  *
11  * Remove the last path name element from path (leaving the preceding
12  * "/", if any).  If path is empty or the root directory ("/"), set
13  * path to the empty string.
14  */
15 static void trim_last_path_component(struct strbuf *path)
16 {
17         int i = path->len;
18
19         /* back up past trailing slashes, if any */
20         while (i && path->buf[i - 1] == '/')
21                 i--;
22
23         /*
24          * then go backwards until a slash, or the beginning of the
25          * string
26          */
27         while (i && path->buf[i - 1] != '/')
28                 i--;
29
30         strbuf_setlen(path, i);
31 }
32
33
34 /* We allow "recursive" symbolic links. Only within reason, though */
35 #define MAXDEPTH 5
36
37 /*
38  * path contains a path that might be a symlink.
39  *
40  * If path is a symlink, attempt to overwrite it with a path to the
41  * real file or directory (which may or may not exist), following a
42  * chain of symlinks if necessary.  Otherwise, leave path unmodified.
43  *
44  * This is a best-effort routine.  If an error occurs, path will
45  * either be left unmodified or will name a different symlink in a
46  * symlink chain that started with the original path.
47  */
48 static void resolve_symlink(struct strbuf *path)
49 {
50         int depth = MAXDEPTH;
51         static struct strbuf link = STRBUF_INIT;
52
53         while (depth--) {
54                 if (strbuf_readlink(&link, path->buf, path->len) < 0)
55                         break;
56
57                 if (is_absolute_path(link.buf))
58                         /* absolute path simply replaces p */
59                         strbuf_reset(path);
60                 else
61                         /*
62                          * link is a relative path, so replace the
63                          * last element of p with it.
64                          */
65                         trim_last_path_component(path);
66
67                 strbuf_addbuf(path, &link);
68         }
69         strbuf_reset(&link);
70 }
71
72 /* Make sure errno contains a meaningful value on error */
73 static int lock_file(struct lock_file *lk, const char *path, int flags)
74 {
75         struct strbuf filename = STRBUF_INIT;
76
77         strbuf_addstr(&filename, path);
78         if (!(flags & LOCK_NO_DEREF))
79                 resolve_symlink(&filename);
80
81         strbuf_addstr(&filename, LOCK_SUFFIX);
82         lk->tempfile = create_tempfile(filename.buf);
83         strbuf_release(&filename);
84         return lk->tempfile ? lk->tempfile->fd : -1;
85 }
86
87 /*
88  * Constants defining the gaps between attempts to lock a file. The
89  * first backoff period is approximately INITIAL_BACKOFF_MS
90  * milliseconds. The longest backoff period is approximately
91  * (BACKOFF_MAX_MULTIPLIER * INITIAL_BACKOFF_MS) milliseconds.
92  */
93 #define INITIAL_BACKOFF_MS 1L
94 #define BACKOFF_MAX_MULTIPLIER 1000
95
96 /*
97  * Try locking path, retrying with quadratic backoff for at least
98  * timeout_ms milliseconds. If timeout_ms is 0, try locking the file
99  * exactly once. If timeout_ms is -1, try indefinitely.
100  */
101 static int lock_file_timeout(struct lock_file *lk, const char *path,
102                              int flags, long timeout_ms)
103 {
104         int n = 1;
105         int multiplier = 1;
106         long remaining_ms = 0;
107         static int random_initialized = 0;
108
109         if (timeout_ms == 0)
110                 return lock_file(lk, path, flags);
111
112         if (!random_initialized) {
113                 srand((unsigned int)getpid());
114                 random_initialized = 1;
115         }
116
117         if (timeout_ms > 0)
118                 remaining_ms = timeout_ms;
119
120         while (1) {
121                 long backoff_ms, wait_ms;
122                 int fd;
123
124                 fd = lock_file(lk, path, flags);
125
126                 if (fd >= 0)
127                         return fd; /* success */
128                 else if (errno != EEXIST)
129                         return -1; /* failure other than lock held */
130                 else if (timeout_ms > 0 && remaining_ms <= 0)
131                         return -1; /* failure due to timeout */
132
133                 backoff_ms = multiplier * INITIAL_BACKOFF_MS;
134                 /* back off for between 0.75*backoff_ms and 1.25*backoff_ms */
135                 wait_ms = (750 + rand() % 500) * backoff_ms / 1000;
136                 sleep_millisec(wait_ms);
137                 remaining_ms -= wait_ms;
138
139                 /* Recursion: (n+1)^2 = n^2 + 2n + 1 */
140                 multiplier += 2*n + 1;
141                 if (multiplier > BACKOFF_MAX_MULTIPLIER)
142                         multiplier = BACKOFF_MAX_MULTIPLIER;
143                 else
144                         n++;
145         }
146 }
147
148 void unable_to_lock_message(const char *path, int err, struct strbuf *buf)
149 {
150         if (err == EEXIST) {
151                 strbuf_addf(buf, _("Unable to create '%s.lock': %s.\n\n"
152                     "Another git process seems to be running in this repository, e.g.\n"
153                     "an editor opened by 'git commit'. Please make sure all processes\n"
154                     "are terminated then try again. If it still fails, a git process\n"
155                     "may have crashed in this repository earlier:\n"
156                     "remove the file manually to continue."),
157                             absolute_path(path), strerror(err));
158         } else
159                 strbuf_addf(buf, _("Unable to create '%s.lock': %s"),
160                             absolute_path(path), strerror(err));
161 }
162
163 NORETURN void unable_to_lock_die(const char *path, int err)
164 {
165         struct strbuf buf = STRBUF_INIT;
166
167         unable_to_lock_message(path, err, &buf);
168         die("%s", buf.buf);
169 }
170
171 /* This should return a meaningful errno on failure */
172 int hold_lock_file_for_update_timeout(struct lock_file *lk, const char *path,
173                                       int flags, long timeout_ms)
174 {
175         int fd = lock_file_timeout(lk, path, flags, timeout_ms);
176         if (fd < 0) {
177                 if (flags & LOCK_DIE_ON_ERROR)
178                         unable_to_lock_die(path, errno);
179                 if (flags & LOCK_REPORT_ON_ERROR) {
180                         struct strbuf buf = STRBUF_INIT;
181                         unable_to_lock_message(path, errno, &buf);
182                         error("%s", buf.buf);
183                         strbuf_release(&buf);
184                 }
185         }
186         return fd;
187 }
188
189 char *get_locked_file_path(struct lock_file *lk)
190 {
191         struct strbuf ret = STRBUF_INIT;
192
193         strbuf_addstr(&ret, get_tempfile_path(lk->tempfile));
194         if (ret.len <= LOCK_SUFFIX_LEN ||
195             strcmp(ret.buf + ret.len - LOCK_SUFFIX_LEN, LOCK_SUFFIX))
196                 BUG("get_locked_file_path() called for malformed lock object");
197         /* remove ".lock": */
198         strbuf_setlen(&ret, ret.len - LOCK_SUFFIX_LEN);
199         return strbuf_detach(&ret, NULL);
200 }
201
202 int commit_lock_file(struct lock_file *lk)
203 {
204         char *result_path = get_locked_file_path(lk);
205
206         if (commit_lock_file_to(lk, result_path)) {
207                 int save_errno = errno;
208                 free(result_path);
209                 errno = save_errno;
210                 return -1;
211         }
212         free(result_path);
213         return 0;
214 }