setup.c 3.3 KB
Newer Older
1 2
#include "cache.h"

J
Junio C Hamano 已提交
3
const char *prefix_path(const char *prefix, int len, const char *path)
4
{
J
Junio C Hamano 已提交
5
	const char *orig = path;
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
	for (;;) {
		char c;
		if (*path != '.')
			break;
		c = path[1];
		/* "." */
		if (!c) {
			path++;
			break;
		}
		/* "./" */
		if (c == '/') {
			path += 2;
			continue;
		}
		if (c != '.')
			break;
		c = path[2];
		if (!c)
			path += 2;
		else if (c == '/')
			path += 3;
		else
			break;
		/* ".." and "../" */
		/* Remove last component of the prefix */
		do {
			if (!len)
				die("'%s' is outside repository", orig);
			len--;
		} while (len && prefix[len-1] != '/');
		continue;
	}
	if (len) {
		int speclen = strlen(path);
		char *n = xmalloc(speclen + len + 1);
	
		memcpy(n, prefix, len);
		memcpy(n + len, path, speclen+1);
		path = n;
	}
	return path;
}

J
Junio C Hamano 已提交
50
const char **get_pathspec(const char *prefix, const char **pathspec)
51
{
J
Junio C Hamano 已提交
52 53
	const char *entry = *pathspec;
	const char **p;
54 55
	int prefixlen;

56 57
	if (!prefix && !entry)
		return NULL;
58 59 60 61 62 63 64 65 66 67

	if (!entry) {
		static const char *spec[2];
		spec[0] = prefix;
		spec[1] = NULL;
		return spec;
	}

	/* Otherwise we have to re-write the entries.. */
	p = pathspec;
68
	prefixlen = prefix ? strlen(prefix) : 0;
69
	do {
70
		*p = prefix_path(prefix, prefixlen, entry);
71 72 73 74
	} while ((entry = *++p) != NULL);
	return (const char **) pathspec;
}

75
/*
76 77
 * Test if it looks like we're at the top level git directory.
 * We want to see:
78 79 80
 *
 *  - either a .git/objects/ directory _or_ the proper
 *    GIT_OBJECT_DIRECTORY environment variable
J
Junio C Hamano 已提交
81 82 83
 *  - a refs/ directory under ".git"
 *  - either a HEAD symlink or a HEAD file that is formatted as
 *    a proper "ref:".
84 85 86
 */
static int is_toplevel_directory(void)
{
J
Junio C Hamano 已提交
87 88 89 90 91 92
	if (access(".git/refs/", X_OK) ||
	    access(getenv(DB_ENVIRONMENT) ?
		   getenv(DB_ENVIRONMENT) : ".git/objects/", X_OK) ||
	    validate_symref(".git/HEAD"))
		return 0;
	return 1;
93 94
}

95
static const char *setup_git_directory_1(void)
96 97 98 99 100 101
{
	static char cwd[PATH_MAX+1];
	int len, offset;

	/*
	 * If GIT_DIR is set explicitly, we're not going
102 103
	 * to do any discovery, but we still do repository
	 * validation.
104
	 */
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
	if (getenv(GIT_DIR_ENVIRONMENT)) {
		char path[PATH_MAX];
		int len = strlen(getenv(GIT_DIR_ENVIRONMENT));
		if (sizeof(path) - 40 < len)
			die("'$%s' too big", GIT_DIR_ENVIRONMENT);
		memcpy(path, getenv(GIT_DIR_ENVIRONMENT), len);
		
		strcpy(path + len, "/refs");
		if (access(path, X_OK))
			goto bad_dir_environ;
		strcpy(path + len, "/HEAD");
		if (validate_symref(path))
			goto bad_dir_environ;
		if (getenv(DB_ENVIRONMENT)) {
			if (access(DB_ENVIRONMENT, X_OK))
				goto bad_dir_environ;
		}
		else {
			strcpy(path + len, "/objects");
			if (access(path, X_OK))
				goto bad_dir_environ;
		}
127
		return NULL;
128 129 130 131
	bad_dir_environ:
		path[len] = 0;
		die("Not a git repository: '%s'", path);
	}
132 133 134 135 136 137

	if (!getcwd(cwd, sizeof(cwd)) || cwd[0] != '/')
		die("Unable to read current working directory");

	offset = len = strlen(cwd);
	for (;;) {
138 139
		if (is_toplevel_directory())
			break;
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
		chdir("..");
		do {
			if (!offset)
				die("Not a git repository");
		} while (cwd[--offset] != '/');
	}

	if (offset == len)
		return NULL;

	/* Make "offset" point to past the '/', and add a '/' at the end */
	offset++;
	cwd[len++] = '/';
	cwd[len] = 0;
	return cwd + offset;
}
156 157 158 159 160 161

const char *setup_git_directory(void)
{
	const char *retval = setup_git_directory_1();
	return retval;
}