2006-06-06 21:51:49 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2005, Junio C Hamano
|
|
|
|
*/
|
2015-08-10 11:47:36 +02:00
|
|
|
|
2006-06-06 21:51:49 +02:00
|
|
|
#include "cache.h"
|
2014-10-01 12:28:42 +02:00
|
|
|
#include "lockfile.h"
|
2006-06-06 21:51:49 +02:00
|
|
|
|
2007-07-26 19:34:14 +02:00
|
|
|
/*
|
2014-10-01 12:28:35 +02:00
|
|
|
* path = absolute or relative path name
|
2007-07-26 19:34:14 +02:00
|
|
|
*
|
2014-10-01 12:28:35 +02:00
|
|
|
* Remove the last path name element from path (leaving the preceding
|
|
|
|
* "/", if any). If path is empty or the root directory ("/"), set
|
|
|
|
* path to the empty string.
|
2007-07-26 19:34:14 +02:00
|
|
|
*/
|
2014-10-01 12:28:35 +02:00
|
|
|
static void trim_last_path_component(struct strbuf *path)
|
2007-07-26 19:34:14 +02:00
|
|
|
{
|
2014-10-01 12:28:35 +02:00
|
|
|
int i = path->len;
|
2007-07-26 19:34:14 +02:00
|
|
|
|
|
|
|
/* back up past trailing slashes, if any */
|
2014-10-01 12:28:35 +02:00
|
|
|
while (i && path->buf[i - 1] == '/')
|
|
|
|
i--;
|
2007-07-26 19:34:14 +02:00
|
|
|
|
|
|
|
/*
|
2014-10-01 12:28:35 +02:00
|
|
|
* then go backwards until a slash, or the beginning of the
|
|
|
|
* string
|
2007-07-26 19:34:14 +02:00
|
|
|
*/
|
2014-10-01 12:28:35 +02:00
|
|
|
while (i && path->buf[i - 1] != '/')
|
|
|
|
i--;
|
|
|
|
|
|
|
|
strbuf_setlen(path, i);
|
2007-07-26 19:34:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* We allow "recursive" symbolic links. Only within reason, though */
|
|
|
|
#define MAXDEPTH 5
|
|
|
|
|
|
|
|
/*
|
2014-10-01 12:28:34 +02:00
|
|
|
* path contains a path that might be a symlink.
|
2007-07-26 19:34:14 +02:00
|
|
|
*
|
2014-10-01 12:28:34 +02:00
|
|
|
* If path is a symlink, attempt to overwrite it with a path to the
|
|
|
|
* real file or directory (which may or may not exist), following a
|
|
|
|
* chain of symlinks if necessary. Otherwise, leave path unmodified.
|
2007-07-26 19:34:14 +02:00
|
|
|
*
|
2014-10-01 12:28:34 +02:00
|
|
|
* This is a best-effort routine. If an error occurs, path will
|
|
|
|
* either be left unmodified or will name a different symlink in a
|
|
|
|
* symlink chain that started with the original path.
|
2007-07-26 19:34:14 +02:00
|
|
|
*/
|
2014-10-01 12:28:34 +02:00
|
|
|
static void resolve_symlink(struct strbuf *path)
|
2007-07-26 19:34:14 +02:00
|
|
|
{
|
|
|
|
int depth = MAXDEPTH;
|
2014-10-01 12:28:33 +02:00
|
|
|
static struct strbuf link = STRBUF_INIT;
|
2007-07-26 19:34:14 +02:00
|
|
|
|
|
|
|
while (depth--) {
|
2014-10-01 12:28:34 +02:00
|
|
|
if (strbuf_readlink(&link, path->buf, path->len) < 0)
|
2014-10-01 12:28:33 +02:00
|
|
|
break;
|
2007-07-26 19:34:14 +02:00
|
|
|
|
2014-10-01 12:28:34 +02:00
|
|
|
if (is_absolute_path(link.buf))
|
2007-07-26 19:34:14 +02:00
|
|
|
/* absolute path simply replaces p */
|
2014-10-01 12:28:34 +02:00
|
|
|
strbuf_reset(path);
|
2014-10-01 12:28:35 +02:00
|
|
|
else
|
2007-07-26 19:34:14 +02:00
|
|
|
/*
|
2014-10-01 12:28:33 +02:00
|
|
|
* link is a relative path, so replace the
|
2007-07-26 19:34:14 +02:00
|
|
|
* last element of p with it.
|
|
|
|
*/
|
2014-10-01 12:28:35 +02:00
|
|
|
trim_last_path_component(path);
|
2014-10-01 12:28:34 +02:00
|
|
|
|
|
|
|
strbuf_addbuf(path, &link);
|
2007-07-26 19:34:14 +02:00
|
|
|
}
|
2014-10-01 12:28:33 +02:00
|
|
|
strbuf_reset(&link);
|
2007-07-26 19:34:14 +02:00
|
|
|
}
|
|
|
|
|
2014-06-20 16:42:48 +02:00
|
|
|
/* Make sure errno contains a meaningful value on error */
|
2008-10-18 00:44:39 +02:00
|
|
|
static int lock_file(struct lock_file *lk, const char *path, int flags)
|
2006-06-06 21:51:49 +02:00
|
|
|
{
|
2015-08-10 11:47:41 +02:00
|
|
|
int fd;
|
|
|
|
struct strbuf filename = STRBUF_INIT;
|
2014-10-01 12:28:13 +02:00
|
|
|
|
2015-08-10 11:47:41 +02:00
|
|
|
strbuf_addstr(&filename, path);
|
|
|
|
if (!(flags & LOCK_NO_DEREF))
|
|
|
|
resolve_symlink(&filename);
|
2014-10-01 12:28:13 +02:00
|
|
|
|
2015-08-10 11:47:41 +02:00
|
|
|
strbuf_addstr(&filename, LOCK_SUFFIX);
|
|
|
|
fd = create_tempfile(&lk->tempfile, filename.buf);
|
|
|
|
strbuf_release(&filename);
|
|
|
|
return fd;
|
2006-06-06 21:51:49 +02:00
|
|
|
}
|
|
|
|
|
2015-05-11 12:35:25 +02:00
|
|
|
static int sleep_microseconds(long us)
|
|
|
|
{
|
|
|
|
struct timeval tv;
|
|
|
|
tv.tv_sec = 0;
|
|
|
|
tv.tv_usec = us;
|
|
|
|
return select(0, NULL, NULL, NULL, &tv);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Constants defining the gaps between attempts to lock a file. The
|
|
|
|
* first backoff period is approximately INITIAL_BACKOFF_MS
|
|
|
|
* milliseconds. The longest backoff period is approximately
|
|
|
|
* (BACKOFF_MAX_MULTIPLIER * INITIAL_BACKOFF_MS) milliseconds.
|
|
|
|
*/
|
|
|
|
#define INITIAL_BACKOFF_MS 1L
|
|
|
|
#define BACKOFF_MAX_MULTIPLIER 1000
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Try locking path, retrying with quadratic backoff for at least
|
|
|
|
* timeout_ms milliseconds. If timeout_ms is 0, try locking the file
|
|
|
|
* exactly once. If timeout_ms is -1, try indefinitely.
|
|
|
|
*/
|
|
|
|
static int lock_file_timeout(struct lock_file *lk, const char *path,
|
|
|
|
int flags, long timeout_ms)
|
|
|
|
{
|
|
|
|
int n = 1;
|
|
|
|
int multiplier = 1;
|
|
|
|
long remaining_us = 0;
|
|
|
|
static int random_initialized = 0;
|
|
|
|
|
|
|
|
if (timeout_ms == 0)
|
|
|
|
return lock_file(lk, path, flags);
|
|
|
|
|
|
|
|
if (!random_initialized) {
|
|
|
|
srandom((unsigned int)getpid());
|
|
|
|
random_initialized = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (timeout_ms > 0) {
|
|
|
|
/* avoid overflow */
|
|
|
|
if (timeout_ms <= LONG_MAX / 1000)
|
|
|
|
remaining_us = timeout_ms * 1000;
|
|
|
|
else
|
|
|
|
remaining_us = LONG_MAX;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
long backoff_ms, wait_us;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
fd = lock_file(lk, path, flags);
|
|
|
|
|
|
|
|
if (fd >= 0)
|
|
|
|
return fd; /* success */
|
|
|
|
else if (errno != EEXIST)
|
|
|
|
return -1; /* failure other than lock held */
|
|
|
|
else if (timeout_ms > 0 && remaining_us <= 0)
|
|
|
|
return -1; /* failure due to timeout */
|
|
|
|
|
|
|
|
backoff_ms = multiplier * INITIAL_BACKOFF_MS;
|
|
|
|
/* back off for between 0.75*backoff_ms and 1.25*backoff_ms */
|
|
|
|
wait_us = (750 + random() % 500) * backoff_ms;
|
|
|
|
sleep_microseconds(wait_us);
|
|
|
|
remaining_us -= wait_us;
|
|
|
|
|
|
|
|
/* Recursion: (n+1)^2 = n^2 + 2n + 1 */
|
|
|
|
multiplier += 2*n + 1;
|
|
|
|
if (multiplier > BACKOFF_MAX_MULTIPLIER)
|
|
|
|
multiplier = BACKOFF_MAX_MULTIPLIER;
|
|
|
|
else
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-20 16:42:47 +02:00
|
|
|
void unable_to_lock_message(const char *path, int err, struct strbuf *buf)
|
2009-02-19 13:54:18 +01:00
|
|
|
{
|
2009-03-04 16:00:44 +01:00
|
|
|
if (err == EEXIST) {
|
2014-06-20 16:42:47 +02:00
|
|
|
strbuf_addf(buf, "Unable to create '%s.lock': %s.\n\n"
|
2009-02-19 13:54:18 +01:00
|
|
|
"If no other git process is currently running, this probably means a\n"
|
|
|
|
"git process crashed in this repository earlier. Make sure no other git\n"
|
|
|
|
"process is running and remove the file manually to continue.",
|
2011-03-17 12:26:46 +01:00
|
|
|
absolute_path(path), strerror(err));
|
2009-09-27 01:15:09 +02:00
|
|
|
} else
|
2014-06-20 16:42:47 +02:00
|
|
|
strbuf_addf(buf, "Unable to create '%s.lock': %s",
|
2011-03-17 12:26:46 +01:00
|
|
|
absolute_path(path), strerror(err));
|
2009-09-27 01:15:09 +02:00
|
|
|
}
|
|
|
|
|
2014-10-01 12:28:05 +02:00
|
|
|
NORETURN void unable_to_lock_die(const char *path, int err)
|
2009-09-27 01:15:09 +02:00
|
|
|
{
|
2014-06-20 16:42:47 +02:00
|
|
|
struct strbuf buf = STRBUF_INIT;
|
|
|
|
|
|
|
|
unable_to_lock_message(path, err, &buf);
|
|
|
|
die("%s", buf.buf);
|
2009-02-19 13:54:18 +01:00
|
|
|
}
|
|
|
|
|
2014-06-20 16:42:48 +02:00
|
|
|
/* This should return a meaningful errno on failure */
|
2015-05-11 12:35:25 +02:00
|
|
|
int hold_lock_file_for_update_timeout(struct lock_file *lk, const char *path,
|
|
|
|
int flags, long timeout_ms)
|
2006-08-12 10:03:47 +02:00
|
|
|
{
|
2015-05-11 12:35:25 +02:00
|
|
|
int fd = lock_file_timeout(lk, path, flags, timeout_ms);
|
2008-10-18 00:44:39 +02:00
|
|
|
if (fd < 0 && (flags & LOCK_DIE_ON_ERROR))
|
2014-10-01 12:28:05 +02:00
|
|
|
unable_to_lock_die(path, errno);
|
2006-08-12 10:03:47 +02:00
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2008-10-18 00:44:39 +02:00
|
|
|
int hold_lock_file_for_append(struct lock_file *lk, const char *path, int flags)
|
2008-04-18 01:32:26 +02:00
|
|
|
{
|
|
|
|
int fd, orig_fd;
|
|
|
|
|
2008-10-18 00:44:39 +02:00
|
|
|
fd = lock_file(lk, path, flags);
|
2008-04-18 01:32:26 +02:00
|
|
|
if (fd < 0) {
|
2008-10-18 00:44:39 +02:00
|
|
|
if (flags & LOCK_DIE_ON_ERROR)
|
2014-10-01 12:28:05 +02:00
|
|
|
unable_to_lock_die(path, errno);
|
2008-04-18 01:32:26 +02:00
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
orig_fd = open(path, O_RDONLY);
|
|
|
|
if (orig_fd < 0) {
|
|
|
|
if (errno != ENOENT) {
|
2014-10-01 12:28:40 +02:00
|
|
|
int save_errno = errno;
|
|
|
|
|
2008-10-18 00:44:39 +02:00
|
|
|
if (flags & LOCK_DIE_ON_ERROR)
|
2008-04-18 01:32:26 +02:00
|
|
|
die("cannot open '%s' for copying", path);
|
2014-10-01 12:28:12 +02:00
|
|
|
rollback_lock_file(lk);
|
2014-10-01 12:28:40 +02:00
|
|
|
error("cannot open '%s' for copying", path);
|
|
|
|
errno = save_errno;
|
|
|
|
return -1;
|
2008-04-18 01:32:26 +02:00
|
|
|
}
|
|
|
|
} else if (copy_fd(orig_fd, fd)) {
|
2014-10-01 12:28:40 +02:00
|
|
|
int save_errno = errno;
|
|
|
|
|
2008-10-18 00:44:39 +02:00
|
|
|
if (flags & LOCK_DIE_ON_ERROR)
|
2015-05-19 19:55:16 +02:00
|
|
|
die("failed to prepare '%s' for appending", path);
|
2014-08-26 17:23:24 +02:00
|
|
|
close(orig_fd);
|
2014-10-01 12:28:12 +02:00
|
|
|
rollback_lock_file(lk);
|
2014-10-01 12:28:40 +02:00
|
|
|
errno = save_errno;
|
2008-04-18 01:32:26 +02:00
|
|
|
return -1;
|
2014-08-26 17:23:24 +02:00
|
|
|
} else {
|
|
|
|
close(orig_fd);
|
2008-04-18 01:32:26 +02:00
|
|
|
}
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
2014-10-01 12:28:39 +02:00
|
|
|
char *get_locked_file_path(struct lock_file *lk)
|
|
|
|
{
|
2015-08-10 11:47:41 +02:00
|
|
|
struct strbuf ret = STRBUF_INIT;
|
|
|
|
|
|
|
|
strbuf_addstr(&ret, get_tempfile_path(&lk->tempfile));
|
|
|
|
if (ret.len <= LOCK_SUFFIX_LEN ||
|
|
|
|
strcmp(ret.buf + ret.len - LOCK_SUFFIX_LEN, LOCK_SUFFIX))
|
2014-10-01 12:28:39 +02:00
|
|
|
die("BUG: get_locked_file_path() called for malformed lock object");
|
2015-08-10 11:47:40 +02:00
|
|
|
/* remove ".lock": */
|
2015-08-10 11:47:41 +02:00
|
|
|
strbuf_setlen(&ret, ret.len - LOCK_SUFFIX_LEN);
|
|
|
|
return strbuf_detach(&ret, NULL);
|
2006-06-06 21:51:49 +02:00
|
|
|
}
|
|
|
|
|
2014-10-01 12:28:36 +02:00
|
|
|
int commit_lock_file(struct lock_file *lk)
|
_GIT_INDEX_OUTPUT: allow plumbing to output to an alternative index file.
When defined, this allows plumbing commands that update the
index (add, apply, checkout-index, merge-recursive, mv,
read-tree, rm, update-index, and write-tree) to write their
resulting index to an alternative index file while holding a
lock to the original index file. With this, git-commit that
jumps the index does not have to make an extra copy of the index
file, and more importantly, it can do the update while holding
the lock on the index.
However, I think the interface to let an environment variable
specify the output is a mistake, as shown in the documentation.
If a curious user has the environment variable set to something
other than the file GIT_INDEX_FILE points at, almost everything
will break. This should instead be a command line parameter to
tell these plumbing commands to write the result in the named
file, to prevent stupid mistakes.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-01 08:09:02 +02:00
|
|
|
{
|
2015-08-10 11:47:40 +02:00
|
|
|
char *result_path = get_locked_file_path(lk);
|
2014-10-01 12:28:36 +02:00
|
|
|
|
2015-08-10 11:47:40 +02:00
|
|
|
if (commit_lock_file_to(lk, result_path)) {
|
|
|
|
int save_errno = errno;
|
|
|
|
free(result_path);
|
|
|
|
errno = save_errno;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
free(result_path);
|
|
|
|
return 0;
|
_GIT_INDEX_OUTPUT: allow plumbing to output to an alternative index file.
When defined, this allows plumbing commands that update the
index (add, apply, checkout-index, merge-recursive, mv,
read-tree, rm, update-index, and write-tree) to write their
resulting index to an alternative index file while holding a
lock to the original index file. With this, git-commit that
jumps the index does not have to make an extra copy of the index
file, and more importantly, it can do the update while holding
the lock on the index.
However, I think the interface to let an environment variable
specify the output is a mistake, as shown in the documentation.
If a curious user has the environment variable set to something
other than the file GIT_INDEX_FILE points at, almost everything
will break. This should instead be a command line parameter to
tell these plumbing commands to write the result in the named
file, to prevent stupid mistakes.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-01 08:09:02 +02:00
|
|
|
}
|