lockfile.c 5.9 KB
Newer Older
1 2 3 4
/*
 * Copyright (c) 2005, Junio C Hamano
 */
#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 11

static void remove_lock_file(void)
{
12 13
	pid_t me = getpid();

14
	while (lock_file_list) {
15
		if (lock_file_list->owner == me &&
16
		    lock_file_list->filename[0]) {
17 18
			if (lock_file_list->fd >= 0)
				close(lock_file_list->fd);
19
			unlink_or_warn(lock_file_list->filename);
20
		}
21 22 23 24 25 26 27
		lock_file_list = lock_file_list->next;
	}
}

static void remove_lock_file_on_signal(int signo)
{
	remove_lock_file();
28
	sigchain_pop(signo);
29 30 31
	raise(signo);
}

32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
/*
 * p = absolute or relative path name
 *
 * Return a pointer into p showing the beginning of the last path name
 * element.  If p is empty or the root directory ("/"), just return p.
 */
static char *last_path_elm(char *p)
{
	/* r starts pointing to null at the end of the string */
	char *r = strchr(p, '\0');

	if (r == p)
		return p; /* just return empty string */

	r--; /* back up to last non-null character */

	/* back up past trailing slashes, if any */
	while (r > p && *r == '/')
		r--;

	/*
	 * then go backwards until I hit a slash, or the beginning of
	 * the string
	 */
	while (r > p && *(r-1) != '/')
		r--;
	return r;
}


/* We allow "recursive" symbolic links. Only within reason, though */
#define MAXDEPTH 5

/*
 * p = path that may be a symlink
 * s = full size of p
 *
 * If p is a symlink, attempt to overwrite p with a path to the real
 * file or directory (which may or may not exist), following a chain of
 * symlinks if necessary.  Otherwise, leave p unmodified.
 *
 * This is a best-effort routine.  If an error occurs, p will either be
 * left unmodified or will name a different symlink in a symlink chain
 * that started with p's initial contents.
 *
 * Always returns p.
 */

static char *resolve_symlink(char *p, size_t s)
{
	int depth = MAXDEPTH;

	while (depth--) {
		char link[PATH_MAX];
		int link_len = readlink(p, link, sizeof(link));
		if (link_len < 0) {
			/* not a symlink anymore */
			return p;
		}
		else if (link_len < sizeof(link))
			/* readlink() never null-terminates */
			link[link_len] = '\0';
		else {
			warning("%s: symlink too long", p);
			return p;
		}

99
		if (is_absolute_path(link)) {
100 101 102 103 104 105 106 107 108 109 110 111
			/* absolute path simply replaces p */
			if (link_len < s)
				strcpy(p, link);
			else {
				warning("%s: symlink too long", p);
				return p;
			}
		} else {
			/*
			 * link is a relative path, so I must replace the
			 * last element of p with it.
			 */
112
			char *r = (char *)last_path_elm(p);
113 114 115 116 117 118 119 120 121 122 123 124
			if (r - p + link_len < s)
				strcpy(r, link);
			else {
				warning("%s: symlink too long", p);
				return p;
			}
		}
	}
	return p;
}


125
static int lock_file(struct lock_file *lk, const char *path, int flags)
126
{
127 128
	if (strlen(path) >= sizeof(lk->filename))
		return -1;
129 130 131 132 133
	strcpy(lk->filename, path);
	/*
	 * subtract 5 from size to make sure there's room for adding
	 * ".lock" for the lock file name
	 */
134 135
	if (!(flags & LOCK_NODEREF))
		resolve_symlink(lk->filename, sizeof(lk->filename)-5);
136
	strcat(lk->filename, ".lock");
137 138
	lk->fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666);
	if (0 <= lk->fd) {
139
		if (!lock_file_list) {
140
			sigchain_push_common(remove_lock_file_on_signal);
141 142
			atexit(remove_lock_file);
		}
143
		lk->owner = getpid();
144
		if (!lk->on_list) {
145 146
			lk->next = lock_file_list;
			lock_file_list = lk;
147 148
			lk->on_list = 1;
		}
149 150 151
		if (adjust_shared_perm(lk->filename))
			return error("cannot fix permission bits on %s",
				     lk->filename);
152
	}
153 154
	else
		lk->filename[0] = 0;
155
	return lk->fd;
156 157
}

158 159 160

NORETURN void unable_to_lock_index_die(const char *path, int err)
{
161
	if (err == EEXIST) {
162 163 164 165 166 167 168 169 170 171
		die("Unable to create '%s.lock': %s.\n\n"
		    "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.",
		    path, strerror(err));
	} else {
		die("Unable to create '%s.lock': %s", path, strerror(err));
	}
}

172
int hold_lock_file_for_update(struct lock_file *lk, const char *path, int flags)
173
{
174 175
	int fd = lock_file(lk, path, flags);
	if (fd < 0 && (flags & LOCK_DIE_ON_ERROR))
176
		unable_to_lock_index_die(path, errno);
177 178 179
	return fd;
}

180
int hold_lock_file_for_append(struct lock_file *lk, const char *path, int flags)
181 182 183
{
	int fd, orig_fd;

184
	fd = lock_file(lk, path, flags);
185
	if (fd < 0) {
186
		if (flags & LOCK_DIE_ON_ERROR)
187
			unable_to_lock_index_die(path, errno);
188 189 190 191 192 193
		return fd;
	}

	orig_fd = open(path, O_RDONLY);
	if (orig_fd < 0) {
		if (errno != ENOENT) {
194
			if (flags & LOCK_DIE_ON_ERROR)
195 196 197 198 199
				die("cannot open '%s' for copying", path);
			close(fd);
			return error("cannot open '%s' for copying", path);
		}
	} else if (copy_fd(orig_fd, fd)) {
200
		if (flags & LOCK_DIE_ON_ERROR)
201 202 203 204 205 206 207
			exit(128);
		close(fd);
		return -1;
	}
	return fd;
}

208 209 210 211 212 213 214
int close_lock_file(struct lock_file *lk)
{
	int fd = lk->fd;
	lk->fd = -1;
	return close(fd);
}

215 216 217
int commit_lock_file(struct lock_file *lk)
{
	char result_file[PATH_MAX];
218 219 220
	size_t i;
	if (lk->fd >= 0 && close_lock_file(lk))
		return -1;
221 222 223
	strcpy(result_file, lk->filename);
	i = strlen(result_file) - 5; /* .lock */
	result_file[i] = 0;
224 225
	if (rename(lk->filename, result_file))
		return -1;
226
	lk->filename[0] = 0;
227
	return 0;
228 229
}

230 231
int hold_locked_index(struct lock_file *lk, int die_on_error)
{
232 233 234 235
	return hold_lock_file_for_update(lk, get_index_file(),
					 die_on_error
					 ? LOCK_DIE_ON_ERROR
					 : 0);
236 237
}

238 239 240 241 242
void set_alternate_index_output(const char *name)
{
	alternate_index_output = name;
}

243 244
int commit_locked_index(struct lock_file *lk)
{
245
	if (alternate_index_output) {
246 247 248 249
		if (lk->fd >= 0 && close_lock_file(lk))
			return -1;
		if (rename(lk->filename, alternate_index_output))
			return -1;
250
		lk->filename[0] = 0;
251
		return 0;
252 253 254 255 256
	}
	else
		return commit_lock_file(lk);
}

257 258
void rollback_lock_file(struct lock_file *lk)
{
259
	if (lk->filename[0]) {
260 261
		if (lk->fd >= 0)
			close(lk->fd);
262
		unlink_or_warn(lk->filename);
263
	}
264 265
	lk->filename[0] = 0;
}