path.c 21.5 KB
Newer Older
1
/*
2
 * Utilities for paths and pathnames
3 4
 */
#include "cache.h"
5
#include "strbuf.h"
6
#include "string-list.h"
7
#include "dir.h"
8

9
static int get_st_mode_bits(const char *path, int *mode)
10 11 12 13 14 15 16 17
{
	struct stat st;
	if (lstat(path, &st) < 0)
		return -1;
	*mode = st.st_mode;
	return 0;
}

18 19
static char bad_path[] = "/bad-path/";

20
static struct strbuf *get_pathname(void)
21
{
22 23 24
	static struct strbuf pathname_array[4] = {
		STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
	};
25
	static int index;
26 27 28
	struct strbuf *sb = &pathname_array[3 & ++index];
	strbuf_reset(sb);
	return sb;
29 30
}

31 32 33 34 35 36 37 38 39 40 41
static char *cleanup_path(char *path)
{
	/* Clean it up */
	if (!memcmp(path, "./", 2)) {
		path += 2;
		while (*path == '/')
			path++;
	}
	return path;
}

42 43 44 45 46 47 48
static void strbuf_cleanup_path(struct strbuf *sb)
{
	char *path = cleanup_path(sb->buf);
	if (path > sb->buf)
		strbuf_remove(sb, 0, path - sb->buf);
}

49 50 51 52 53 54 55 56 57
char *mksnpath(char *buf, size_t n, const char *fmt, ...)
{
	va_list args;
	unsigned len;

	va_start(args, fmt);
	len = vsnprintf(buf, n, fmt, args);
	va_end(args);
	if (len >= n) {
58
		strlcpy(buf, bad_path, n);
59 60 61 62 63
		return buf;
	}
	return cleanup_path(buf);
}

64
static int dir_prefix(const char *buf, const char *dir)
65
{
66 67 68 69
	int len = strlen(dir);
	return !strncmp(buf, dir, len) &&
		(is_dir_sep(buf[len]) || buf[len] == '\0');
}
70

71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
/* $buf =~ m|$dir/+$file| but without regex */
static int is_dir_file(const char *buf, const char *dir, const char *file)
{
	int len = strlen(dir);
	if (strncmp(buf, dir, len) || !is_dir_sep(buf[len]))
		return 0;
	while (is_dir_sep(buf[len]))
		len++;
	return !strcmp(buf + len, file);
}

static void replace_dir(struct strbuf *buf, int len, const char *newdir)
{
	int newlen = strlen(newdir);
	int need_sep = (buf->buf[len] && !is_dir_sep(buf->buf[len])) &&
		!is_dir_sep(newdir[newlen - 1]);
	if (need_sep)
		len--;	 /* keep one char, to be replaced with '/'  */
	strbuf_splice(buf, 0, len, newdir, newlen);
	if (need_sep)
		buf->buf[newlen] = '/';
}

94
static const char *common_list[] = {
95
	"/branches", "/hooks", "/info", "!/logs", "/lost-found",
96
	"/objects", "/refs", "/remotes", "/worktrees", "/rr-cache", "/svn",
97
	"config", "!gc.pid", "packed-refs", "shallow",
98 99 100 101 102 103 104 105
	NULL
};

static void update_common_dir(struct strbuf *buf, int git_dir_len)
{
	char *base = buf->buf + git_dir_len;
	const char **p;

106 107
	if (is_dir_file(base, "logs", "HEAD") ||
	    is_dir_file(base, "info", "sparse-checkout"))
108 109 110 111
		return;	/* keep this in $GIT_DIR */
	for (p = common_list; *p; p++) {
		const char *path = *p;
		int is_dir = 0;
112 113
		if (*path == '!')
			path++;
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
		if (*path == '/') {
			path++;
			is_dir = 1;
		}
		if (is_dir && dir_prefix(base, path)) {
			replace_dir(buf, git_dir_len, get_git_common_dir());
			return;
		}
		if (!is_dir && !strcmp(base, path)) {
			replace_dir(buf, git_dir_len, get_git_common_dir());
			return;
		}
	}
}

129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
void report_linked_checkout_garbage(void)
{
	struct strbuf sb = STRBUF_INIT;
	const char **p;
	int len;

	if (!git_common_dir_env)
		return;
	strbuf_addf(&sb, "%s/", get_git_dir());
	len = sb.len;
	for (p = common_list; *p; p++) {
		const char *path = *p;
		if (*path == '!')
			continue;
		strbuf_setlen(&sb, len);
		strbuf_addstr(&sb, path);
		if (file_exists(sb.buf))
			report_garbage("unused in linked checkout", sb.buf);
	}
	strbuf_release(&sb);
149 150
}

151 152 153 154 155 156 157 158 159 160 161
static void adjust_git_path(struct strbuf *buf, int git_dir_len)
{
	const char *base = buf->buf + git_dir_len;
	if (git_graft_env && is_dir_file(base, "info", "grafts"))
		strbuf_splice(buf, 0, buf->len,
			      get_graft_file(), strlen(get_graft_file()));
	else if (git_index_env && !strcmp(base, "index"))
		strbuf_splice(buf, 0, buf->len,
			      get_index_file(), strlen(get_index_file()));
	else if (git_db_env && dir_prefix(base, "objects"))
		replace_dir(buf, git_dir_len + 7, get_object_directory());
162 163
	else if (git_common_dir_env)
		update_common_dir(buf, git_dir_len);
164 165
}

166
static void do_git_path(struct strbuf *buf, const char *fmt, va_list args)
167
{
168 169
	int gitdir_len;
	strbuf_addstr(buf, get_git_dir());
170 171
	if (buf->len && !is_dir_sep(buf->buf[buf->len - 1]))
		strbuf_addch(buf, '/');
172
	gitdir_len = buf->len;
173
	strbuf_vaddf(buf, fmt, args);
174
	adjust_git_path(buf, gitdir_len);
175
	strbuf_cleanup_path(buf);
176 177
}

178
void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
179 180 181
{
	va_list args;
	va_start(args, fmt);
182
	do_git_path(sb, fmt, args);
183 184 185
	va_end(args);
}

186
const char *git_path(const char *fmt, ...)
187
{
188
	struct strbuf *pathname = get_pathname();
189 190
	va_list args;
	va_start(args, fmt);
191
	do_git_path(pathname, fmt, args);
192
	va_end(args);
193
	return pathname->buf;
194 195 196
}

char *git_pathdup(const char *fmt, ...)
197
{
198
	struct strbuf path = STRBUF_INIT;
199 200
	va_list args;
	va_start(args, fmt);
201
	do_git_path(&path, fmt, args);
202
	va_end(args);
203
	return strbuf_detach(&path, NULL);
204 205 206
}

char *mkpathdup(const char *fmt, ...)
207
{
208
	struct strbuf sb = STRBUF_INIT;
209 210
	va_list args;
	va_start(args, fmt);
211
	strbuf_vaddf(&sb, fmt, args);
212
	va_end(args);
213 214
	strbuf_cleanup_path(&sb);
	return strbuf_detach(&sb, NULL);
215 216
}

217
const char *mkpath(const char *fmt, ...)
218 219
{
	va_list args;
220
	struct strbuf *pathname = get_pathname();
221
	va_start(args, fmt);
222
	strbuf_vaddf(pathname, fmt, args);
223
	va_end(args);
224
	return cleanup_path(pathname->buf);
225
}
226

227 228
static void do_submodule_path(struct strbuf *buf, const char *path,
			      const char *fmt, va_list args)
229 230 231
{
	const char *git_dir;

232 233 234 235
	strbuf_addstr(buf, path);
	if (buf->len && buf->buf[buf->len - 1] != '/')
		strbuf_addch(buf, '/');
	strbuf_addstr(buf, ".git");
236

237
	git_dir = read_gitfile(buf->buf);
238
	if (git_dir) {
239 240
		strbuf_reset(buf);
		strbuf_addstr(buf, git_dir);
241
	}
242
	strbuf_addch(buf, '/');
243

244 245
	strbuf_vaddf(buf, fmt, args);
	strbuf_cleanup_path(buf);
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
}

char *git_pathdup_submodule(const char *path, const char *fmt, ...)
{
	va_list args;
	struct strbuf buf = STRBUF_INIT;
	va_start(args, fmt);
	do_submodule_path(&buf, path, fmt, args);
	va_end(args);
	return strbuf_detach(&buf, NULL);
}

void strbuf_git_path_submodule(struct strbuf *buf, const char *path,
			       const char *fmt, ...)
{
	va_list args;
	va_start(args, fmt);
	do_submodule_path(buf, path, fmt, args);
	va_end(args);
}

267
int validate_headref(const char *path)
268 269 270
{
	struct stat st;
	char *buf, buffer[256];
271
	unsigned char sha1[20];
272 273
	int fd;
	ssize_t len;
274 275 276 277 278 279 280

	if (lstat(path, &st) < 0)
		return -1;

	/* Make sure it is a "refs/.." symlink */
	if (S_ISLNK(st.st_mode)) {
		len = readlink(path, buffer, sizeof(buffer)-1);
281
		if (len >= 5 && !memcmp("refs/", buffer, 5))
282 283 284 285 286 287 288 289 290 291
			return 0;
		return -1;
	}

	/*
	 * Anything else, just open it and try to see if it is a symbolic ref.
	 */
	fd = open(path, O_RDONLY);
	if (fd < 0)
		return -1;
292
	len = read_in_full(fd, buffer, sizeof(buffer)-1);
293 294 295 296 297
	close(fd);

	/*
	 * Is it a symbolic ref?
	 */
298
	if (len < 4)
299
		return -1;
300 301 302 303 304
	if (!memcmp("ref:", buffer, 4)) {
		buf = buffer + 4;
		len -= 4;
		while (len && isspace(*buf))
			buf++, len--;
305
		if (len >= 5 && !memcmp("refs/", buf, 5))
306 307 308 309 310 311 312
			return 0;
	}

	/*
	 * Is this a detached HEAD?
	 */
	if (!get_sha1_hex(buffer, sha1))
313
		return 0;
314

315 316 317
	return -1;
}

318
static struct passwd *getpw_str(const char *username, size_t len)
319
{
320
	struct passwd *pw;
321
	char *username_z = xmemdupz(username, len);
322 323 324 325
	pw = getpwnam(username_z);
	free(username_z);
	return pw;
}
326

327 328 329 330 331 332 333 334 335 336 337 338 339
/*
 * Return a string with ~ and ~user expanded via getpw*.  If buf != NULL,
 * then it is a newly allocated string. Returns NULL on getpw failure or
 * if path is NULL.
 */
char *expand_user_path(const char *path)
{
	struct strbuf user_path = STRBUF_INIT;
	const char *to_copy = path;

	if (path == NULL)
		goto return_null;
	if (path[0] == '~') {
340
		const char *first_slash = strchrnul(path, '/');
341 342
		const char *username = path + 1;
		size_t username_len = first_slash - username;
343 344
		if (username_len == 0) {
			const char *home = getenv("HOME");
345 346
			if (!home)
				goto return_null;
347
			strbuf_addstr(&user_path, home);
348 349 350 351
		} else {
			struct passwd *pw = getpw_str(username, username_len);
			if (!pw)
				goto return_null;
352
			strbuf_addstr(&user_path, pw->pw_dir);
353
		}
354
		to_copy = first_slash;
355
	}
356
	strbuf_addstr(&user_path, to_copy);
357 358 359 360
	return strbuf_detach(&user_path, NULL);
return_null:
	strbuf_release(&user_path);
	return NULL;
361 362
}

363 364 365 366 367 368 369 370 371 372
/*
 * First, one directory to try is determined by the following algorithm.
 *
 * (0) If "strict" is given, the path is used as given and no DWIM is
 *     done. Otherwise:
 * (1) "~/path" to mean path under the running user's home directory;
 * (2) "~user/path" to mean path under named user's home directory;
 * (3) "relative/path" to mean cwd relative directory; or
 * (4) "/absolute/path" to mean absolute directory.
 *
373 374 375
 * Unless "strict" is given, we check "%s/.git", "%s", "%s.git/.git", "%s.git"
 * in this order. We select the first one that is a valid git repository, and
 * chdir() to it. If none match, or we fail to chdir, we return NULL.
376 377 378 379 380 381
 *
 * If all goes well, we return the directory we used to chdir() (but
 * before ~user is expanded), avoiding getcwd() resolving symbolic
 * links.  User relative paths are also returned as they are given,
 * except DWIM suffixing.
 */
382
const char *enter_repo(const char *path, int strict)
383
{
384 385 386 387
	static char used_path[PATH_MAX];
	static char validated_path[PATH_MAX];

	if (!path)
388 389
		return NULL;

390 391
	if (!strict) {
		static const char *suffix[] = {
392
			"/.git", "", ".git/.git", ".git", NULL,
393
		};
394
		const char *gitfile;
395 396
		int len = strlen(path);
		int i;
397
		while ((1 < len) && (path[len-1] == '/'))
398
			len--;
399

400
		if (PATH_MAX <= len)
401
			return NULL;
402 403 404 405 406
		strncpy(used_path, path, len); used_path[len] = 0 ;
		strcpy(validated_path, used_path);

		if (used_path[0] == '~') {
			char *newpath = expand_user_path(used_path);
407 408
			if (!newpath || (PATH_MAX - 10 < strlen(newpath))) {
				free(newpath);
409
				return NULL;
410 411 412 413 414 415 416 417
			}
			/*
			 * Copy back into the static buffer. A pity
			 * since newpath was not bounded, but other
			 * branches of the if are limited by PATH_MAX
			 * anyway.
			 */
			strcpy(used_path, newpath); free(newpath);
418 419 420
		}
		else if (PATH_MAX - 10 < len)
			return NULL;
421
		len = strlen(used_path);
422
		for (i = 0; suffix[i]; i++) {
423
			struct stat st;
424
			strcpy(used_path + len, suffix[i]);
425 426 427
			if (!stat(used_path, &st) &&
			    (S_ISREG(st.st_mode) ||
			    (S_ISDIR(st.st_mode) && is_git_directory(used_path)))) {
428 429 430 431
				strcat(validated_path, suffix[i]);
				break;
			}
		}
432 433 434 435 436 437
		if (!suffix[i])
			return NULL;
		gitfile = read_gitfile(used_path) ;
		if (gitfile)
			strcpy(used_path, gitfile);
		if (chdir(used_path))
438
			return NULL;
439
		path = validated_path;
440
	}
441 442
	else if (chdir(path))
		return NULL;
443

444
	if (access("objects", X_OK) == 0 && access("refs", X_OK) == 0 &&
445
	    validate_headref("HEAD") == 0) {
René Scharfe's avatar
René Scharfe committed
446
		set_git_dir(".");
447
		check_repository_format();
448
		return path;
449 450 451 452
	}

	return NULL;
}
453

454
static int calc_shared_perm(int mode)
455
{
456
	int tweak;
457

458
	if (shared_repository < 0)
459
		tweak = -shared_repository;
460
	else
461
		tweak = shared_repository;
462 463 464 465 466 467 468 469 470

	if (!(mode & S_IWUSR))
		tweak &= ~0222;
	if (mode & S_IXUSR)
		/* Copy read bits to execute bits */
		tweak |= (tweak & 0444) >> 2;
	if (shared_repository < 0)
		mode = (mode & ~0777) | tweak;
	else
471
		mode |= tweak;
472

473 474 475 476 477 478 479 480 481 482 483 484 485 486 487
	return mode;
}


int adjust_shared_perm(const char *path)
{
	int old_mode, new_mode;

	if (!shared_repository)
		return 0;
	if (get_st_mode_bits(path, &old_mode) < 0)
		return -1;

	new_mode = calc_shared_perm(old_mode);
	if (S_ISDIR(old_mode)) {
488
		/* Copy read bits to execute bits */
489 490
		new_mode |= (new_mode & 0444) >> 2;
		new_mode |= FORCE_DIR_SET_GID;
491 492
	}

493 494
	if (((old_mode ^ new_mode) & ~S_IFMT) &&
			chmod(path, (new_mode & ~S_IFMT)) < 0)
495 496 497
		return -2;
	return 0;
}
498

499 500 501 502 503 504 505 506 507 508
static int have_same_root(const char *path1, const char *path2)
{
	int is_abs1, is_abs2;

	is_abs1 = is_absolute_path(path1);
	is_abs2 = is_absolute_path(path2);
	return (is_abs1 && is_abs2 && tolower(path1[0]) == tolower(path2[0])) ||
	       (!is_abs1 && !is_abs2);
}

509 510 511 512 513 514 515 516
/*
 * Give path as relative to prefix.
 *
 * The strbuf may or may not be used, so do not assume it contains the
 * returned path.
 */
const char *relative_path(const char *in, const char *prefix,
			  struct strbuf *sb)
517
{
518 519 520 521
	int in_len = in ? strlen(in) : 0;
	int prefix_len = prefix ? strlen(prefix) : 0;
	int in_off = 0;
	int prefix_off = 0;
522 523
	int i = 0, j = 0;

524 525 526 527 528
	if (!in_len)
		return "./";
	else if (!prefix_len)
		return in;

529 530 531 532 533 534 535 536 537 538
	if (have_same_root(in, prefix)) {
		/* bypass dos_drive, for "c:" is identical to "C:" */
		if (has_dos_drive_prefix(in)) {
			i = 2;
			j = 2;
		}
	} else {
		return in;
	}

539 540 541
	while (i < prefix_len && j < in_len && prefix[i] == in[j]) {
		if (is_dir_sep(prefix[i])) {
			while (is_dir_sep(prefix[i]))
542
				i++;
543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566
			while (is_dir_sep(in[j]))
				j++;
			prefix_off = i;
			in_off = j;
		} else {
			i++;
			j++;
		}
	}

	if (
	    /* "prefix" seems like prefix of "in" */
	    i >= prefix_len &&
	    /*
	     * but "/foo" is not a prefix of "/foobar"
	     * (i.e. prefix not end with '/')
	     */
	    prefix_off < prefix_len) {
		if (j >= in_len) {
			/* in="/a/b", prefix="/a/b" */
			in_off = in_len;
		} else if (is_dir_sep(in[j])) {
			/* in="/a/b/c", prefix="/a/b" */
			while (is_dir_sep(in[j]))
567
				j++;
568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602
			in_off = j;
		} else {
			/* in="/a/bbb/c", prefix="/a/b" */
			i = prefix_off;
		}
	} else if (
		   /* "in" is short than "prefix" */
		   j >= in_len &&
		   /* "in" not end with '/' */
		   in_off < in_len) {
		if (is_dir_sep(prefix[i])) {
			/* in="/a/b", prefix="/a/b/c/" */
			while (is_dir_sep(prefix[i]))
				i++;
			in_off = in_len;
		}
	}
	in += in_off;
	in_len -= in_off;

	if (i >= prefix_len) {
		if (!in_len)
			return "./";
		else
			return in;
	}

	strbuf_reset(sb);
	strbuf_grow(sb, in_len);

	while (i < prefix_len) {
		if (is_dir_sep(prefix[i])) {
			strbuf_addstr(sb, "../");
			while (is_dir_sep(prefix[i]))
				i++;
603 604 605 606
			continue;
		}
		i++;
	}
607 608 609 610 611 612
	if (!is_dir_sep(prefix[prefix_len - 1]))
		strbuf_addstr(sb, "../");

	strbuf_addstr(sb, in);

	return sb->buf;
613
}
614

615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659
/*
 * A simpler implementation of relative_path
 *
 * Get relative path by removing "prefix" from "in". This function
 * first appears in v1.5.6-1-g044bbbc, and makes git_dir shorter
 * to increase performance when traversing the path to work_tree.
 */
const char *remove_leading_path(const char *in, const char *prefix)
{
	static char buf[PATH_MAX + 1];
	int i = 0, j = 0;

	if (!prefix || !prefix[0])
		return in;
	while (prefix[i]) {
		if (is_dir_sep(prefix[i])) {
			if (!is_dir_sep(in[j]))
				return in;
			while (is_dir_sep(prefix[i]))
				i++;
			while (is_dir_sep(in[j]))
				j++;
			continue;
		} else if (in[j] != prefix[i]) {
			return in;
		}
		i++;
		j++;
	}
	if (
	    /* "/foo" is a prefix of "/foo" */
	    in[j] &&
	    /* "/foo" is not a prefix of "/foobar" */
	    !is_dir_sep(prefix[i-1]) && !is_dir_sep(in[j])
	   )
		return in;
	while (is_dir_sep(in[j]))
		j++;
	if (!in[j])
		strcpy(buf, ".");
	else
		strcpy(buf, in + j);
	return buf;
}

660
/*
661
 * It is okay if dst == src, but they should not overlap otherwise.
662
 *
663 664 665
 * Performs the following normalizations on src, storing the result in dst:
 * - Ensures that components are separated by '/' (Windows only)
 * - Squashes sequences of '/'.
666 667
 * - Removes "." components.
 * - Removes ".." components, and the components the precede them.
668 669
 * Returns failure (non-zero) if a ".." component appears as first path
 * component anytime during the normalization. Otherwise, returns success (0).
670 671 672
 *
 * Note that this function is purely textual.  It does not follow symlinks,
 * verify the existence of the path, or make any system calls.
673 674 675 676 677 678
 *
 * prefix_len != NULL is for a specific case of prefix_pathspec():
 * assume that src == dst and src[0..prefix_len-1] is already
 * normalized, any time "../" eats up to the prefix_len part,
 * prefix_len is reduced. In the end prefix_len is the remaining
 * prefix that has not been overridden by user pathspec.
679
 */
680
int normalize_path_copy_len(char *dst, const char *src, int *prefix_len)
681
{
682
	char *dst0;
683

684 685 686
	if (has_dos_drive_prefix(src)) {
		*dst++ = *src++;
		*dst++ = *src++;
687
	}
688
	dst0 = dst;
689

690
	if (is_dir_sep(*src)) {
691
		*dst++ = '/';
692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730
		while (is_dir_sep(*src))
			src++;
	}

	for (;;) {
		char c = *src;

		/*
		 * A path component that begins with . could be
		 * special:
		 * (1) "." and ends   -- ignore and terminate.
		 * (2) "./"           -- ignore them, eat slash and continue.
		 * (3) ".." and ends  -- strip one and terminate.
		 * (4) "../"          -- strip one, eat slash and continue.
		 */
		if (c == '.') {
			if (!src[1]) {
				/* (1) */
				src++;
			} else if (is_dir_sep(src[1])) {
				/* (2) */
				src += 2;
				while (is_dir_sep(*src))
					src++;
				continue;
			} else if (src[1] == '.') {
				if (!src[2]) {
					/* (3) */
					src += 2;
					goto up_one;
				} else if (is_dir_sep(src[2])) {
					/* (4) */
					src += 3;
					while (is_dir_sep(*src))
						src++;
					goto up_one;
				}
			}
		}
731

732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748
		/* copy up to the next '/', and eat all '/' */
		while ((c = *src++) != '\0' && !is_dir_sep(c))
			*dst++ = c;
		if (is_dir_sep(c)) {
			*dst++ = '/';
			while (is_dir_sep(c))
				c = *src++;
			src--;
		} else if (!c)
			break;
		continue;

	up_one:
		/*
		 * dst0..dst is prefix portion, and dst[-1] is '/';
		 * go up one level.
		 */
749 750
		dst--;	/* go to trailing '/' */
		if (dst <= dst0)
751
			return -1;
752 753 754
		/* Windows: dst[-1] cannot be backslash anymore */
		while (dst0 < dst && dst[-1] != '/')
			dst--;
755 756
		if (prefix_len && *prefix_len > dst - dst0)
			*prefix_len = dst - dst0;
757
	}
758
	*dst = '\0';
759
	return 0;
760
}
761

762 763 764 765 766
int normalize_path_copy(char *dst, const char *src)
{
	return normalize_path_copy_len(dst, src, NULL);
}

767 768
/*
 * path = Canonical absolute path
769 770
 * prefixes = string_list containing normalized, absolute paths without
 * trailing slashes (except for the root directory, which is denoted by "/").
771
 *
772
 * Determines, for each path in prefixes, whether the "prefix"
773 774
 * is an ancestor directory of path.  Returns the length of the longest
 * ancestor directory, excluding any trailing slashes, or -1 if no prefix
775 776
 * is an ancestor.  (Note that this means 0 is returned if prefixes is
 * ["/"].) "/foo" is not considered an ancestor of "/foobar".  Directories
777 778
 * are not considered to be their own ancestors.  path must be in a
 * canonical form: empty components, or "." or ".." components are not
779
 * allowed.
780
 */
781
int longest_ancestor_length(const char *path, struct string_list *prefixes)
782
{
783
	int i, max_len = -1;
784

785
	if (!strcmp(path, "/"))
786 787
		return -1;

788 789
	for (i = 0; i < prefixes->nr; i++) {
		const char *ceil = prefixes->items[i].string;
790 791
		int len = strlen(ceil);

792 793 794 795 796 797
		if (len == 1 && ceil[0] == '/')
			len = 0; /* root matches anything, with length 0 */
		else if (!strncmp(path, ceil, len) && path[len] == '/')
			; /* match of length len */
		else
			continue; /* no match */
798

799
		if (len > max_len)
800 801 802 803 804
			max_len = len;
	}

	return max_len;
}
805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840

/* strip arbitrary amount of directory separators at end of path */
static inline int chomp_trailing_dir_sep(const char *path, int len)
{
	while (len && is_dir_sep(path[len - 1]))
		len--;
	return len;
}

/*
 * If path ends with suffix (complete path components), returns the
 * part before suffix (sans trailing directory separators).
 * Otherwise returns NULL.
 */
char *strip_path_suffix(const char *path, const char *suffix)
{
	int path_len = strlen(path), suffix_len = strlen(suffix);

	while (suffix_len) {
		if (!path_len)
			return NULL;

		if (is_dir_sep(path[path_len - 1])) {
			if (!is_dir_sep(suffix[suffix_len - 1]))
				return NULL;
			path_len = chomp_trailing_dir_sep(path, path_len);
			suffix_len = chomp_trailing_dir_sep(suffix, suffix_len);
		}
		else if (path[--path_len] != suffix[--suffix_len])
			return NULL;
	}

	if (path_len && !is_dir_sep(path[path_len - 1]))
		return NULL;
	return xstrndup(path, chomp_trailing_dir_sep(path, path_len));
}
841 842 843 844 845 846 847 848

int daemon_avoid_alias(const char *p)
{
	int sl, ndot;

	/*
	 * This resurrects the belts and suspenders paranoia check by HPA
	 * done in <[email protected]> thread, now enter_repo()
849
	 * does not do getcwd() based path canonicalization.
850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887
	 *
	 * sl becomes true immediately after seeing '/' and continues to
	 * be true as long as dots continue after that without intervening
	 * non-dot character.
	 */
	if (!p || (*p != '/' && *p != '~'))
		return -1;
	sl = 1; ndot = 0;
	p++;

	while (1) {
		char ch = *p++;
		if (sl) {
			if (ch == '.')
				ndot++;
			else if (ch == '/') {
				if (ndot < 3)
					/* reject //, /./ and /../ */
					return -1;
				ndot = 0;
			}
			else if (ch == 0) {
				if (0 < ndot && ndot < 3)
					/* reject /.$ and /..$ */
					return -1;
				return 0;
			}
			else
				sl = ndot = 0;
		}
		else if (ch == 0)
			return 0;
		else if (ch == '/') {
			sl = 1;
			ndot = 0;
		}
	}
}
888

889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920
static int only_spaces_and_periods(const char *path, size_t len, size_t skip)
{
	if (len < skip)
		return 0;
	len -= skip;
	path += skip;
	while (len-- > 0) {
		char c = *(path++);
		if (c != ' ' && c != '.')
			return 0;
	}
	return 1;
}

int is_ntfs_dotgit(const char *name)
{
	int len;

	for (len = 0; ; len++)
		if (!name[len] || name[len] == '\\' || is_dir_sep(name[len])) {
			if (only_spaces_and_periods(name, len, 4) &&
					!strncasecmp(name, ".git", 4))
				return 1;
			if (only_spaces_and_periods(name, len, 5) &&
					!strncasecmp(name, "git~1", 5))
				return 1;
			if (name[len] != '\\')
				return 0;
			name += len + 1;
			len = -1;
		}
}
921 922 923 924 925 926 927 928 929 930 931 932 933 934 935

char *xdg_config_home(const char *filename)
{
	const char *home, *config_home;

	assert(filename);
	config_home = getenv("XDG_CONFIG_HOME");
	if (config_home && *config_home)
		return mkpathdup("%s/git/%s", config_home, filename);

	home = getenv("HOME");
	if (home)
		return mkpathdup("%s/.config/git/%s", home, filename);
	return NULL;
}
936 937 938 939 940 941 942 943 944 945

GIT_PATH_FUNC(git_path_cherry_pick_head, "CHERRY_PICK_HEAD")
GIT_PATH_FUNC(git_path_revert_head, "REVERT_HEAD")
GIT_PATH_FUNC(git_path_squash_msg, "SQUASH_MSG")
GIT_PATH_FUNC(git_path_merge_msg, "MERGE_MSG")
GIT_PATH_FUNC(git_path_merge_rr, "MERGE_RR")
GIT_PATH_FUNC(git_path_merge_mode, "MERGE_MODE")
GIT_PATH_FUNC(git_path_merge_head, "MERGE_HEAD")
GIT_PATH_FUNC(git_path_fetch_head, "FETCH_HEAD")
GIT_PATH_FUNC(git_path_shallow, "shallow")