Exemple #1
0
static void assert_sm_valid(git_repository *parent, git_repository *child, const char *sm_name)
{
	git_buf expected = GIT_BUF_INIT, actual = GIT_BUF_INIT;

	/* assert working directory */
	cl_git_pass(git_buf_joinpath(&expected, git_repository_workdir(parent), sm_name));
	cl_git_pass(git_path_prettify_dir(&expected, expected.ptr, NULL));
	cl_git_pass(git_buf_sets(&actual, git_repository_workdir(child)));
	cl_git_pass(git_path_prettify_dir(&actual, actual.ptr, NULL));
	cl_assert_equal_s(expected.ptr, actual.ptr);

	git_buf_clear(&expected);
	git_buf_clear(&actual);

	/* assert common directory */
	cl_git_pass(git_buf_joinpath(&expected, git_repository_commondir(parent), "modules"));
	cl_git_pass(git_buf_joinpath(&expected, expected.ptr, sm_name));
	cl_git_pass(git_path_prettify_dir(&expected, expected.ptr, NULL));
	cl_git_pass(git_buf_sets(&actual, git_repository_commondir(child)));
	cl_git_pass(git_path_prettify_dir(&actual, actual.ptr, NULL));
	cl_assert_equal_s(expected.ptr, actual.ptr);

	/* assert git directory */
	cl_git_pass(git_buf_sets(&actual, git_repository_path(child)));
	cl_git_pass(git_path_prettify_dir(&actual, actual.ptr, NULL));
	cl_assert_equal_s(expected.ptr, actual.ptr);

	git_buf_dispose(&expected);
	git_buf_dispose(&actual);
}
Exemple #2
0
void test_repo_init__bare_repo_escaping_current_workdir(void)
{
	git_buf path_repository = GIT_BUF_INIT;
	git_buf path_current_workdir = GIT_BUF_INIT;

	cl_git_pass(git_path_prettify_dir(&path_current_workdir, ".", NULL));

	cl_git_pass(git_buf_joinpath(&path_repository, git_buf_cstr(&path_current_workdir), "a/b/c"));
	cl_git_pass(git_futils_mkdir_r(git_buf_cstr(&path_repository), GIT_DIR_MODE));

	/* Change the current working directory */
	cl_git_pass(chdir(git_buf_cstr(&path_repository)));

	/* Initialize a bare repo with a relative path escaping out of the current working directory */
	cl_git_pass(git_repository_init(&_repo, "../d/e.git", 1));
	cl_git_pass(git__suffixcmp(git_repository_path(_repo), "/a/b/d/e.git/"));

	git_repository_free(_repo);

	/* Open a bare repo with a relative path escaping out of the current working directory */
	cl_git_pass(git_repository_open(&_repo, "../d/e.git"));

	cl_git_pass(chdir(git_buf_cstr(&path_current_workdir)));

	git_buf_free(&path_current_workdir);
	git_buf_free(&path_repository);

	cleanup_repository("a");
}
int git_repository_open_bare(
	git_repository **repo_ptr,
	const char *bare_path)
{
	int error;
	git_buf path = GIT_BUF_INIT;
	git_repository *repo = NULL;

	if ((error = git_path_prettify_dir(&path, bare_path, NULL)) < 0)
		return error;

	if (!valid_repository_path(&path)) {
		git_buf_free(&path);
		giterr_set(GITERR_REPOSITORY, "Path is not a repository: %s", bare_path);
		return GIT_ENOTFOUND;
	}

	repo = repository_alloc();
	GITERR_CHECK_ALLOC(repo);

	repo->path_repository = git_buf_detach(&path);
	GITERR_CHECK_ALLOC(repo->path_repository);

	/* of course we're bare! */
	repo->is_bare = 1;
	repo->workdir = NULL;

	*repo_ptr = repo;
	return 0;
}
/*
 * Read the contents of `file_path` and set `path_out` to the repo dir that
 * it points to.  Before calling, set `path_out` to the base directory that
 * should be used if the contents of `file_path` are a relative path.
 */
static int read_gitfile(git_buf *path_out, const char *file_path)
{
	int     error = 0;
	git_buf file = GIT_BUF_INIT;
	size_t  prefix_len = strlen(GIT_FILE_CONTENT_PREFIX);

	assert(path_out && file_path);

	if (git_futils_readbuffer(&file, file_path) < 0)
		return -1;

	git_buf_rtrim(&file);
	/* apparently on Windows, some people use backslashes in paths */
	git_path_mkposix(file.ptr);

	if (git_buf_len(&file) <= prefix_len ||
		memcmp(git_buf_cstr(&file), GIT_FILE_CONTENT_PREFIX, prefix_len) != 0)
	{
		giterr_set(GITERR_REPOSITORY,
			"The `.git` file at '%s' is malformed", file_path);
		error = -1;
	}
	else if ((error = git_path_dirname_r(path_out, file_path)) >= 0) {
		const char *gitlink = git_buf_cstr(&file) + prefix_len;
		while (*gitlink && git__isspace(*gitlink)) gitlink++;

		error = git_path_prettify_dir(
			path_out, gitlink, git_buf_cstr(path_out));
	}

	git_buf_free(&file);
	return error;
}
static int load_workdir(git_repository *repo, git_config *config, git_buf *parent_path)
{
	int         error;
	const git_config_entry *ce;
	git_buf     worktree = GIT_BUF_INIT;

	if (repo->is_bare)
		return 0;

	if ((error = git_config__lookup_entry(
			&ce, config, "core.worktree", false)) < 0)
		return error;

	if (ce && ce->value) {
		if ((error = git_path_prettify_dir(
				&worktree, ce->value, repo->path_repository)) < 0)
			return error;

		repo->workdir = git_buf_detach(&worktree);
	}
	else if (parent_path && git_path_isdir(parent_path->ptr))
		repo->workdir = git_buf_detach(parent_path);
	else {
		if (git_path_dirname_r(&worktree, repo->path_repository) < 0 ||
			git_path_to_dir(&worktree) < 0)
			return -1;

		repo->workdir = git_buf_detach(&worktree);
	}

	GITERR_CHECK_ALLOC(repo->workdir);
	return 0;
}
Exemple #6
0
/*
 * Read the contents of `file_path` and set `path_out` to the repo dir that
 * it points to.  Before calling, set `path_out` to the base directory that
 * should be used if the contents of `file_path` are a relative path.
 */
static int read_gitfile(git_buf *path_out, const char *file_path)
{
	int     error = 0;
	git_buf file = GIT_BUF_INIT;
	size_t  prefix_len = strlen(GIT_FILE_CONTENT_PREFIX);

	assert(path_out && file_path);

	if (git_futils_readbuffer(&file, file_path) < 0)
		return -1;

	git_buf_rtrim(&file);

	if (file.size <= prefix_len ||
		memcmp(file.ptr, GIT_FILE_CONTENT_PREFIX, prefix_len) != 0)
	{
		giterr_set(GITERR_REPOSITORY, "The `.git` file at '%s' is malformed", file_path);
		error = -1;
	}
	else if ((error = git_path_dirname_r(path_out, file_path)) >= 0) {
		const char *gitlink = ((const char *)file.ptr) + prefix_len;
		while (*gitlink && git__isspace(*gitlink)) gitlink++;
		error = git_path_prettify_dir(path_out, gitlink, path_out->ptr);
	}

	git_buf_free(&file);
	return error;
}
Exemple #7
0
static void env_cd_(
	const char *path,
	void (*passfail_)(const char *, const char *, int),
	const char *file, int line)
{
	git_buf cwd_buf = GIT_BUF_INIT;
	cl_git_pass(git_path_prettify_dir(&cwd_buf, ".", NULL));
	cl_must_pass(p_chdir(path));
	passfail_(NULL, file, line);
	cl_must_pass(p_chdir(git_buf_cstr(&cwd_buf)));
	git_buf_free(&cwd_buf);
}
Exemple #8
0
//no check is performed on ceiling_dirs length, so be sure it's long enough
static void append_ceiling_dir(git_buf *ceiling_dirs, const char *path)
{
	git_buf pretty_path = GIT_BUF_INIT;
	char ceiling_separator[2] = { GIT_PATH_LIST_SEPARATOR, '\0' };

	cl_git_pass(git_path_prettify_dir(&pretty_path, path, NULL));

	if (ceiling_dirs->size > 0)
		git_buf_puts(ceiling_dirs, ceiling_separator);

	git_buf_puts(ceiling_dirs, pretty_path.ptr);

	git_buf_free(&pretty_path);
	cl_assert(git_buf_oom(ceiling_dirs) == 0);
}
Exemple #9
0
void test_object_blob_write__can_create_a_blob_in_a_bare_repo_from_a_absolute_filepath(void)
{
    git_buf full_path = GIT_BUF_INIT;

    repo = cl_git_sandbox_init(BARE_REPO);

    cl_must_pass(p_mkdir(ELSEWHERE, 0777));
    cl_must_pass(git_path_prettify_dir(&full_path, ELSEWHERE, NULL));
    cl_must_pass(git_buf_puts(&full_path, "test.txt"));

    assert_blob_creation(ELSEWHERE "/test.txt", git_buf_cstr(&full_path), &git_blob_create_fromdisk);

    git_buf_free(&full_path);
    cl_must_pass(git_futils_rmdir_r(ELSEWHERE, GIT_DIRREMOVAL_FILES_AND_DIRS));
}
Exemple #10
0
void test_object_blob_write__can_create_a_blob_in_a_standard_repo_from_a_absolute_filepath_pointing_outside_of_the_working_directory(void)
{
    git_buf full_path = GIT_BUF_INIT;

    repo = cl_git_sandbox_init(WORKDIR);

    cl_must_pass(p_mkdir(ELSEWHERE, 0777));
    cl_must_pass(git_path_prettify_dir(&full_path, ELSEWHERE, NULL));
    cl_must_pass(git_buf_puts(&full_path, "test.txt"));

    assert_blob_creation(ELSEWHERE "/test.txt", git_buf_cstr(&full_path), &git_blob_create_fromdisk);

    git_buf_free(&full_path);
    cl_must_pass(git_futils_rmdir_r(ELSEWHERE, GIT_DIRREMOVAL_FILES_AND_DIRS));
}
Exemple #11
0
int git_repository_set_workdir(git_repository *repo, const char *workdir)
{
	git_buf path = GIT_BUF_INIT;

	assert(repo && workdir);

	if (git_path_prettify_dir(&path, workdir, NULL) < 0)
		return -1;

	git__free(repo->workdir);

	repo->workdir = git_buf_detach(&path);
	repo->is_bare = 0;
	return 0;
}
Exemple #12
0
const char* cl_git_path_url(const char *path)
{
	static char url[4096];

	const char *in_buf;
	git_buf path_buf = GIT_BUF_INIT;
	git_buf url_buf = GIT_BUF_INIT;

	cl_git_pass(git_path_prettify_dir(&path_buf, path, NULL));
	cl_git_pass(git_buf_puts(&url_buf, "file://"));

#ifdef GIT_WIN32
	/*
	 * A FILE uri matches the following format: file://[host]/path
	 * where "host" can be empty and "path" is an absolute path to the resource.
	 *
	 * In this test, no hostname is used, but we have to ensure the leading triple slashes:
	 *
	 * *nix: file:///usr/home/...
	 * Windows: file:///C:/Users/...
	 */
	cl_git_pass(git_buf_putc(&url_buf, '/'));
#endif

	in_buf = git_buf_cstr(&path_buf);

	/*
	 * A very hacky Url encoding that only takes care of escaping the spaces
	 */
	while (*in_buf) {
		if (*in_buf == ' ')
			cl_git_pass(git_buf_puts(&url_buf, "%20"));
		else
			cl_git_pass(git_buf_putc(&url_buf, *in_buf));

		in_buf++;
	}

	cl_assert(url_buf.size < 4096);

	strncpy(url, git_buf_cstr(&url_buf), 4096);
	git_buf_free(&url_buf);
	git_buf_free(&path_buf);
	return url;
}
Exemple #13
0
static void build_local_file_url(git_buf *out, const char *fixture)
{
	const char *in_buf;

	git_buf path_buf = GIT_BUF_INIT;

	cl_git_pass(git_path_prettify_dir(&path_buf, fixture, NULL));
	cl_git_pass(git_buf_puts(out, "file://"));

#ifdef _MSC_VER
	/*
	 * A FILE uri matches the following format: file://[host]/path
	 * where "host" can be empty and "path" is an absolute path to the resource.
	 * 
	 * In this test, no hostname is used, but we have to ensure the leading triple slashes:
	 * 
	 * *nix: file:///usr/home/...
	 * Windows: file:///C:/Users/...
	 */
	cl_git_pass(git_buf_putc(out, '/'));
#endif

	in_buf = git_buf_cstr(&path_buf);

	/*
	 * A very hacky Url encoding that only takes care of escaping the spaces
	 */
	while (*in_buf) {
		if (*in_buf == ' ')
			cl_git_pass(git_buf_puts(out, "%20"));
		else
			cl_git_pass(git_buf_putc(out, *in_buf));

		in_buf++;
	}

	git_buf_free(&path_buf);
}
Exemple #14
0
static void build_local_file_url(git_buf *out, const char *fixture)
{
	git_buf path_buf = GIT_BUF_INIT;

	cl_git_pass(git_path_prettify_dir(&path_buf, cl_fixture(fixture), NULL));
	cl_git_pass(git_buf_puts(out, "file://"));

#ifdef _MSC_VER
	/*
	 * A FILE uri matches the following format: file://[host]/path
	 * where "host" can be empty and "path" is an absolute path to the resource.
	 * 
	 * In this test, no hostname is used, but we have to ensure the leading triple slashes:
	 * 
	 * *nix: file:///usr/home/...
	 * Windows: file:///C:/Users/...
	 */
	cl_git_pass(git_buf_putc(out, '/'));
#endif

	cl_git_pass(git_buf_puts(out, git_buf_cstr(&path_buf)));

	git_buf_free(&path_buf);
}
Exemple #15
0
void test_repo_env__open(void)
{
	git_repository *repo = NULL;
	git_buf repo_dir_buf = GIT_BUF_INIT;
	const char *repo_dir = NULL;
	git_index *index = NULL;
	const char *t_obj = "testrepo.git/objects";
	const char *p_obj = "peeled.git/objects";

	clear_git_env();

	cl_fixture_sandbox("attr");
	cl_fixture_sandbox("testrepo.git");
	cl_fixture_sandbox("peeled.git");
	cl_git_pass(p_rename("attr/.gitted", "attr/.git"));

	cl_git_pass(git_path_prettify_dir(&repo_dir_buf, "attr", NULL));
	repo_dir = git_buf_cstr(&repo_dir_buf);

	/* GIT_DIR that doesn't exist */
	cl_setenv("GIT_DIR", "does-not-exist");
	env_fail(NULL);
	/* Explicit start_path overrides GIT_DIR */
	env_pass("attr");
	env_pass("attr/.git");
	env_pass("attr/sub");
	env_pass("attr/sub/sub");

	/* GIT_DIR with relative paths */
	cl_setenv("GIT_DIR", "attr/.git");
	env_pass(NULL);
	cl_setenv("GIT_DIR", "attr");
	env_fail(NULL);
	cl_setenv("GIT_DIR", "attr/sub");
	env_fail(NULL);
	cl_setenv("GIT_DIR", "attr/sub/sub");
	env_fail(NULL);

	/* GIT_DIR with absolute paths */
	cl_setenv_printf("GIT_DIR", "%s/.git", repo_dir);
	env_pass(NULL);
	cl_setenv("GIT_DIR", repo_dir);
	env_fail(NULL);
	cl_setenv_printf("GIT_DIR", "%s/sub", repo_dir);
	env_fail(NULL);
	cl_setenv_printf("GIT_DIR", "%s/sub/sub", repo_dir);
	env_fail(NULL);
	cl_setenv("GIT_DIR", NULL);

	/* Searching from the current directory */
	env_cd_pass("attr");
	env_cd_pass("attr/.git");
	env_cd_pass("attr/sub");
	env_cd_pass("attr/sub/sub");

	/* A ceiling directory blocks searches from ascending into that
	 * directory, but doesn't block the start_path itself. */
	cl_setenv("GIT_CEILING_DIRECTORIES", repo_dir);
	env_cd_pass("attr");
	env_cd_fail("attr/sub");
	env_cd_fail("attr/sub/sub");

	cl_setenv_printf("GIT_CEILING_DIRECTORIES", "%s/sub", repo_dir);
	env_cd_pass("attr");
	env_cd_pass("attr/sub");
	env_cd_fail("attr/sub/sub");

	/* Multiple ceiling directories */
	cl_setenv_printf("GIT_CEILING_DIRECTORIES", "123%c%s/sub%cabc",
		GIT_PATH_LIST_SEPARATOR, repo_dir, GIT_PATH_LIST_SEPARATOR);
	env_cd_pass("attr");
	env_cd_pass("attr/sub");
	env_cd_fail("attr/sub/sub");

	cl_setenv_printf("GIT_CEILING_DIRECTORIES", "%s%c%s/sub",
		repo_dir, GIT_PATH_LIST_SEPARATOR, repo_dir);
	env_cd_pass("attr");
	env_cd_fail("attr/sub");
	env_cd_fail("attr/sub/sub");

	cl_setenv_printf("GIT_CEILING_DIRECTORIES", "%s/sub%c%s",
		repo_dir, GIT_PATH_LIST_SEPARATOR, repo_dir);
	env_cd_pass("attr");
	env_cd_fail("attr/sub");
	env_cd_fail("attr/sub/sub");

	cl_setenv_printf("GIT_CEILING_DIRECTORIES", "%s%c%s/sub/sub",
		repo_dir, GIT_PATH_LIST_SEPARATOR, repo_dir);
	env_cd_pass("attr");
	env_cd_fail("attr/sub");
	env_cd_fail("attr/sub/sub");

	cl_setenv("GIT_CEILING_DIRECTORIES", NULL);

	/* Index files */
	cl_setenv("GIT_INDEX_FILE", cl_fixture("gitgit.index"));
	cl_git_pass(git_repository_open_ext(&repo, "attr", GIT_REPOSITORY_OPEN_FROM_ENV, NULL));
	cl_git_pass(git_repository_index(&index, repo));
	cl_assert_equal_s(git_index_path(index), cl_fixture("gitgit.index"));
	cl_assert_equal_i(git_index_entrycount(index), 1437);
	git_index_free(index);
	git_repository_free(repo);
	cl_setenv("GIT_INDEX_FILE", NULL);

	/* Namespaces */
	cl_setenv("GIT_NAMESPACE", "some-namespace");
	cl_git_pass(git_repository_open_ext(&repo, "attr", GIT_REPOSITORY_OPEN_FROM_ENV, NULL));
	cl_assert_equal_s(git_repository_get_namespace(repo), "some-namespace");
	git_repository_free(repo);
	cl_setenv("GIT_NAMESPACE", NULL);

	/* Object directories and alternates */
	env_check_objects(true, false, false);

	cl_setenv("GIT_OBJECT_DIRECTORY", t_obj);
	env_check_objects(false, true, false);
	cl_setenv("GIT_OBJECT_DIRECTORY", NULL);

	cl_setenv("GIT_ALTERNATE_OBJECT_DIRECTORIES", t_obj);
	env_check_objects(true, true, false);
	cl_setenv("GIT_ALTERNATE_OBJECT_DIRECTORIES", NULL);

	cl_setenv("GIT_OBJECT_DIRECTORY", p_obj);
	env_check_objects(false, false, true);
	cl_setenv("GIT_OBJECT_DIRECTORY", NULL);

	cl_setenv("GIT_OBJECT_DIRECTORY", t_obj);
	cl_setenv("GIT_ALTERNATE_OBJECT_DIRECTORIES", p_obj);
	env_check_objects(false, true, true);
	cl_setenv("GIT_ALTERNATE_OBJECT_DIRECTORIES", NULL);
	cl_setenv("GIT_OBJECT_DIRECTORY", NULL);

	cl_setenv_printf("GIT_ALTERNATE_OBJECT_DIRECTORIES",
			"%s%c%s", t_obj, GIT_PATH_LIST_SEPARATOR, p_obj);
	env_check_objects(true, true, true);
	cl_setenv("GIT_ALTERNATE_OBJECT_DIRECTORIES", NULL);

	cl_setenv_printf("GIT_ALTERNATE_OBJECT_DIRECTORIES",
			"%s%c%s", p_obj, GIT_PATH_LIST_SEPARATOR, t_obj);
	env_check_objects(true, true, true);
	cl_setenv("GIT_ALTERNATE_OBJECT_DIRECTORIES", NULL);

	cl_fixture_cleanup("peeled.git");
	cl_fixture_cleanup("testrepo.git");
	cl_fixture_cleanup("attr");

	git_buf_free(&repo_dir_buf);

	clear_git_env();
}
Exemple #16
0
static int find_repo(
	git_buf *repo_path,
	git_buf *parent_path,
	const char *start_path,
	uint32_t flags,
	const char *ceiling_dirs)
{
	int error;
	git_buf path = GIT_BUF_INIT;
	struct stat st;
	dev_t initial_device = 0;
	bool try_with_dot_git = false;
	int ceiling_offset;

	git_buf_free(repo_path);

	if ((error = git_path_prettify_dir(&path, start_path, NULL)) < 0)
		return error;

	ceiling_offset = find_ceiling_dir_offset(path.ptr, ceiling_dirs);

	if ((error = git_buf_joinpath(&path, path.ptr, DOT_GIT)) < 0)
		return error;

	while (!error && !git_buf_len(repo_path)) {
		if (p_stat(path.ptr, &st) == 0) {
			/* check that we have not crossed device boundaries */
			if (initial_device == 0)
				initial_device = st.st_dev;
			else if (st.st_dev != initial_device &&
				(flags & GIT_REPOSITORY_OPEN_CROSS_FS) == 0)
				break;

			if (S_ISDIR(st.st_mode)) {
				if (valid_repository_path(&path)) {
					git_path_to_dir(&path);
					git_buf_set(repo_path, path.ptr, path.size);
					break;
				}
			}
			else if (S_ISREG(st.st_mode)) {
				git_buf repo_link = GIT_BUF_INIT;

				if (!(error = read_gitfile(&repo_link, path.ptr))) {
					if (valid_repository_path(&repo_link))
						git_buf_swap(repo_path, &repo_link);

					git_buf_free(&repo_link);
					break;
				}
				git_buf_free(&repo_link);
			}
		}

		/* move up one directory level */
		if (git_path_dirname_r(&path, path.ptr) < 0) {
			error = -1;
			break;
		}

		if (try_with_dot_git) {
			/* if we tried original dir with and without .git AND either hit
			 * directory ceiling or NO_SEARCH was requested, then be done.
			 */
			if (path.ptr[ceiling_offset] == '\0' ||
				(flags & GIT_REPOSITORY_OPEN_NO_SEARCH) != 0)
				break;
			/* otherwise look first for .git item */
			error = git_buf_joinpath(&path, path.ptr, DOT_GIT);
		}
		try_with_dot_git = !try_with_dot_git;
	}

	if (!error && parent_path != NULL) {
		if (!git_buf_len(repo_path))
			git_buf_clear(parent_path);
		else {
			git_path_dirname_r(parent_path, path.ptr);
			git_path_to_dir(parent_path);
		}
		if (git_buf_oom(parent_path))
			return -1;
	}

	git_buf_free(&path);

	if (!git_buf_len(repo_path) && !error) {
		giterr_set(GITERR_REPOSITORY,
			"Could not find repository from '%s'", start_path);
		error = GIT_ENOTFOUND;
	}

	return error;
}