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 8 9 10

static struct lock_file *lock_file_list;

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

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

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

31 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
/*
 * 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;
		}

98
		if (is_absolute_path(link)) {
99 100 101 102 103 104 105 106 107 108 109 110
			/* 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.
			 */
111
			char *r = (char *)last_path_elm(p);
112 113 114 115 116 117 118 119 120 121 122 123
			if (r - p + link_len < s)
				strcpy(r, link);
			else {
				warning("%s: symlink too long", p);
				return p;
			}
		}
	}
	return p;
}


124
static int lock_file(struct lock_file *lk, const char *path, int flags)
125
{
126 127 128 129
	/*
	 * subtract 5 from size to make sure there's room for adding
	 * ".lock" for the lock file name
	 */
130 131 132 133 134
	static const size_t max_path_len = sizeof(lk->filename) - 5;

	if (strlen(path) >= max_path_len)
		return -1;
	strcpy(lk->filename, path);
135
	if (!(flags & LOCK_NODEREF))
136
		resolve_symlink(lk->filename, max_path_len);
137
	strcat(lk->filename, ".lock");
138 139
	lk->fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666);
	if (0 <= lk->fd) {
140
		if (!lock_file_list) {
141
			sigchain_push_common(remove_lock_file_on_signal);
142 143
			atexit(remove_lock_file);
		}
144
		lk->owner = getpid();
145
		if (!lk->on_list) {
146 147
			lk->next = lock_file_list;
			lock_file_list = lk;
148 149
			lk->on_list = 1;
		}
150 151 152
		if (adjust_shared_perm(lk->filename))
			return error("cannot fix permission bits on %s",
				     lk->filename);
153
	}
154 155
	else
		lk->filename[0] = 0;
156
	return lk->fd;
157 158
}

159
static char *unable_to_lock_message(const char *path, int err)
160
{
161 162
	struct strbuf buf = STRBUF_INIT;

163
	if (err == EEXIST) {
164
		strbuf_addf(&buf, "Unable to create '%s.lock': %s.\n\n"
165 166 167
		    "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.",
168
			    absolute_path(path), strerror(err));
169
	} else
170
		strbuf_addf(&buf, "Unable to create '%s.lock': %s",
171
			    absolute_path(path), strerror(err));
172 173 174 175 176 177 178 179 180 181 182 183 184 185
	return strbuf_detach(&buf, NULL);
}

int unable_to_lock_error(const char *path, int err)
{
	char *msg = unable_to_lock_message(path, err);
	error("%s", msg);
	free(msg);
	return -1;
}

NORETURN void unable_to_lock_index_die(const char *path, int err)
{
	die("%s", unable_to_lock_message(path, err));
186 187
}

188
int hold_lock_file_for_update(struct lock_file *lk, const char *path, int flags)
189
{
190 191
	int fd = lock_file(lk, path, flags);
	if (fd < 0 && (flags & LOCK_DIE_ON_ERROR))
192
		unable_to_lock_index_die(path, errno);
193 194 195
	return fd;
}

196
int hold_lock_file_for_append(struct lock_file *lk, const char *path, int flags)
197 198 199
{
	int fd, orig_fd;

200
	fd = lock_file(lk, path, flags);
201
	if (fd < 0) {
202
		if (flags & LOCK_DIE_ON_ERROR)
203
			unable_to_lock_index_die(path, errno);
204 205 206 207 208 209
		return fd;
	}

	orig_fd = open(path, O_RDONLY);
	if (orig_fd < 0) {
		if (errno != ENOENT) {
210
			if (flags & LOCK_DIE_ON_ERROR)
211 212 213 214 215
				die("cannot open '%s' for copying", path);
			close(fd);
			return error("cannot open '%s' for copying", path);
		}
	} else if (copy_fd(orig_fd, fd)) {
216
		if (flags & LOCK_DIE_ON_ERROR)
217 218 219 220 221 222 223
			exit(128);
		close(fd);
		return -1;
	}
	return fd;
}

224 225 226 227 228 229 230
int close_lock_file(struct lock_file *lk)
{
	int fd = lk->fd;
	lk->fd = -1;
	return close(fd);
}

231 232 233
int commit_lock_file(struct lock_file *lk)
{
	char result_file[PATH_MAX];
234 235 236
	size_t i;
	if (lk->fd >= 0 && close_lock_file(lk))
		return -1;
237 238 239
	strcpy(result_file, lk->filename);
	i = strlen(result_file) - 5; /* .lock */
	result_file[i] = 0;
240 241
	if (rename(lk->filename, result_file))
		return -1;
242
	lk->filename[0] = 0;
243
	return 0;
244 245
}

246 247
int hold_locked_index(struct lock_file *lk, int die_on_error)
{
248 249 250 251
	return hold_lock_file_for_update(lk, get_index_file(),
					 die_on_error
					 ? LOCK_DIE_ON_ERROR
					 : 0);
252 253
}

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