Blame tests/checkout/nasty.c

Packit Service 20376f
#include "clar_libgit2.h"
Packit Service 20376f
#include "checkout_helpers.h"
Packit Service 20376f
Packit Service 20376f
#include "git2/checkout.h"
Packit Service 20376f
#include "repository.h"
Packit Service 20376f
#include "buffer.h"
Packit Service 20376f
#include "fileops.h"
Packit Service 20376f
Packit Service 20376f
static const char *repo_name = "nasty";
Packit Service 20376f
static git_repository *repo;
Packit Service 20376f
static git_checkout_options checkout_opts;
Packit Service 20376f
Packit Service 20376f
void test_checkout_nasty__initialize(void)
Packit Service 20376f
{
Packit Service 20376f
	repo = cl_git_sandbox_init(repo_name);
Packit Service 20376f
Packit Service 20376f
	GIT_INIT_STRUCTURE(&checkout_opts, GIT_CHECKOUT_OPTIONS_VERSION);
Packit Service 20376f
	checkout_opts.checkout_strategy = GIT_CHECKOUT_FORCE;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_checkout_nasty__cleanup(void)
Packit Service 20376f
{
Packit Service 20376f
	cl_git_sandbox_cleanup();
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static void test_checkout_passes(const char *refname, const char *filename)
Packit Service 20376f
{
Packit Service 20376f
	git_oid commit_id;
Packit Service 20376f
	git_commit *commit;
Packit Service 20376f
	git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
Packit Service 20376f
	git_buf path = GIT_BUF_INIT;
Packit Service 20376f
Packit Service 20376f
	cl_git_pass(git_buf_joinpath(&path, repo_name, filename));
Packit Service 20376f
Packit Service 20376f
	cl_git_pass(git_reference_name_to_id(&commit_id, repo, refname));
Packit Service 20376f
	cl_git_pass(git_commit_lookup(&commit, repo, &commit_id));
Packit Service 20376f
Packit Service 20376f
	opts.checkout_strategy = GIT_CHECKOUT_FORCE |
Packit Service 20376f
		GIT_CHECKOUT_DONT_UPDATE_INDEX;
Packit Service 20376f
Packit Service 20376f
	cl_git_pass(git_checkout_tree(repo, (const git_object *)commit, &opts));
Packit Service 20376f
	cl_assert(!git_path_exists(path.ptr));
Packit Service 20376f
Packit Service 20376f
	git_commit_free(commit);
Packit Service 20376f
	git_buf_free(&path);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static void test_checkout_fails(const char *refname, const char *filename)
Packit Service 20376f
{
Packit Service 20376f
	git_oid commit_id;
Packit Service 20376f
	git_commit *commit;
Packit Service 20376f
	git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
Packit Service 20376f
	git_buf path = GIT_BUF_INIT;
Packit Service 20376f
Packit Service 20376f
	cl_git_pass(git_buf_joinpath(&path, repo_name, filename));
Packit Service 20376f
Packit Service 20376f
	cl_git_pass(git_reference_name_to_id(&commit_id, repo, refname));
Packit Service 20376f
	cl_git_pass(git_commit_lookup(&commit, repo, &commit_id));
Packit Service 20376f
Packit Service 20376f
	opts.checkout_strategy = GIT_CHECKOUT_FORCE;
Packit Service 20376f
Packit Service 20376f
	cl_git_fail(git_checkout_tree(repo, (const git_object *)commit, &opts));
Packit Service 20376f
	cl_assert(!git_path_exists(path.ptr));
Packit Service 20376f
Packit Service 20376f
	git_commit_free(commit);
Packit Service 20376f
	git_buf_free(&path);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* A tree that contains ".git" as a tree, with a blob inside
Packit Service 20376f
 * (".git/foobar").
Packit Service 20376f
 */
Packit Service 20376f
void test_checkout_nasty__dotgit_tree(void)
Packit Service 20376f
{
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_tree", ".git/foobar");
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* A tree that contains ".GIT" as a tree, with a blob inside
Packit Service 20376f
 * (".GIT/foobar").
Packit Service 20376f
 */
Packit Service 20376f
void test_checkout_nasty__dotcapitalgit_tree(void)
Packit Service 20376f
{
Packit Service 20376f
	test_checkout_fails("refs/heads/dotcapitalgit_tree", ".GIT/foobar");
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* A tree that contains a tree ".", with a blob inside ("./foobar").
Packit Service 20376f
 */
Packit Service 20376f
void test_checkout_nasty__dot_tree(void)
Packit Service 20376f
{
Packit Service 20376f
	test_checkout_fails("refs/heads/dot_tree", "foobar");
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* A tree that contains a tree ".", with a tree ".git", with a blob
Packit Service 20376f
 * inside ("./.git/foobar").
Packit Service 20376f
 */
Packit Service 20376f
void test_checkout_nasty__dot_dotgit_tree(void)
Packit Service 20376f
{
Packit Service 20376f
	test_checkout_fails("refs/heads/dot_dotgit_tree", ".git/foobar");
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* A tree that contains a tree, with a tree "..", with a tree ".git", with a
Packit Service 20376f
 * blob inside ("foo/../.git/foobar").
Packit Service 20376f
 */
Packit Service 20376f
void test_checkout_nasty__dotdot_dotgit_tree(void)
Packit Service 20376f
{
Packit Service 20376f
	test_checkout_fails("refs/heads/dotdot_dotgit_tree", ".git/foobar");
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* A tree that contains a tree, with a tree "..", with a blob inside
Packit Service 20376f
 * ("foo/../foobar").
Packit Service 20376f
 */
Packit Service 20376f
void test_checkout_nasty__dotdot_tree(void)
Packit Service 20376f
{
Packit Service 20376f
	test_checkout_fails("refs/heads/dotdot_tree", "foobar");
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* A tree that contains a blob with the rogue name ".git/foobar" */
Packit Service 20376f
void test_checkout_nasty__dotgit_path(void)
Packit Service 20376f
{
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_path", ".git/foobar");
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* A tree that contains a blob with the rogue name ".GIT/foobar" */
Packit Service 20376f
void test_checkout_nasty__dotcapitalgit_path(void)
Packit Service 20376f
{
Packit Service 20376f
	test_checkout_fails("refs/heads/dotcapitalgit_path", ".GIT/foobar");
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* A tree that contains a blob with the rogue name "./.git/foobar" */
Packit Service 20376f
void test_checkout_nasty__dot_dotgit_path(void)
Packit Service 20376f
{
Packit Service 20376f
	test_checkout_fails("refs/heads/dot_dotgit_path", ".git/foobar");
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* A tree that contains a blob with the rogue name "./.GIT/foobar" */
Packit Service 20376f
void test_checkout_nasty__dot_dotcapitalgit_path(void)
Packit Service 20376f
{
Packit Service 20376f
	test_checkout_fails("refs/heads/dot_dotcapitalgit_path", ".GIT/foobar");
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* A tree that contains a blob with the rogue name "foo/../.git/foobar" */
Packit Service 20376f
void test_checkout_nasty__dotdot_dotgit_path(void)
Packit Service 20376f
{
Packit Service 20376f
	test_checkout_fails("refs/heads/dotdot_dotgit_path", ".git/foobar");
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* A tree that contains a blob with the rogue name "foo/../.GIT/foobar" */
Packit Service 20376f
void test_checkout_nasty__dotdot_dotcapitalgit_path(void)
Packit Service 20376f
{
Packit Service 20376f
	test_checkout_fails("refs/heads/dotdot_dotcapitalgit_path", ".GIT/foobar");
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* A tree that contains a blob with the rogue name "foo/." */
Packit Service 20376f
void test_checkout_nasty__dot_path(void)
Packit Service 20376f
{
Packit Service 20376f
	test_checkout_fails("refs/heads/dot_path", "./foobar");
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* A tree that contains a blob with the rogue name "foo/." */
Packit Service 20376f
void test_checkout_nasty__dot_path_two(void)
Packit Service 20376f
{
Packit Service 20376f
	test_checkout_fails("refs/heads/dot_path_two", "foo/.");
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* A tree that contains a blob with the rogue name "foo/../foobar" */
Packit Service 20376f
void test_checkout_nasty__dotdot_path(void)
Packit Service 20376f
{
Packit Service 20376f
	test_checkout_fails("refs/heads/dotdot_path", "foobar");
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* A tree that contains an entry with a backslash ".git\foobar"  */
Packit Service 20376f
void test_checkout_nasty__dotgit_backslash_path(void)
Packit Service 20376f
{
Packit Service 20376f
#ifdef GIT_WIN32
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_backslash_path", ".git/foobar");
Packit Service 20376f
#endif
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* A tree that contains an entry with a backslash ".GIT\foobar"  */
Packit Service 20376f
void test_checkout_nasty__dotcapitalgit_backslash_path(void)
Packit Service 20376f
{
Packit Service 20376f
#ifdef GIT_WIN32
Packit Service 20376f
	test_checkout_fails("refs/heads/dotcapitalgit_backslash_path", ".GIT/foobar");
Packit Service 20376f
#endif
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* A tree that contains an entry with a backslash ".\.GIT\foobar"  */
Packit Service 20376f
void test_checkout_nasty__dot_backslash_dotcapitalgit_path(void)
Packit Service 20376f
{
Packit Service 20376f
#ifdef GIT_WIN32
Packit Service 20376f
	test_checkout_fails("refs/heads/dot_backslash_dotcapitalgit_path", ".GIT/foobar");
Packit Service 20376f
#endif
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* A tree that contains an entry ".git.", because Win32 APIs will drop the
Packit Service 20376f
 * trailing slash.
Packit Service 20376f
 */
Packit Service 20376f
void test_checkout_nasty__dot_git_dot(void)
Packit Service 20376f
{
Packit Service 20376f
#ifdef GIT_WIN32
Packit Service 20376f
	test_checkout_fails("refs/heads/dot_git_dot", ".git/foobar");
Packit Service 20376f
#endif
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* A tree that contains an entry "git~1", because that is typically the
Packit Service 20376f
 * short name for ".git".
Packit Service 20376f
 */
Packit Service 20376f
void test_checkout_nasty__git_tilde1(void)
Packit Service 20376f
{
Packit Service 20376f
#ifdef GIT_WIN32
Packit Service 20376f
	test_checkout_fails("refs/heads/git_tilde1", ".git/foobar");
Packit Service 20376f
#endif
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* A tree that contains an entry "git~2", when we have forced the short
Packit Service 20376f
 * name for ".git" into "GIT~2".
Packit Service 20376f
 */
Packit Service 20376f
void test_checkout_nasty__git_custom_shortname(void)
Packit Service 20376f
{
Packit Service 20376f
#ifdef GIT_WIN32
Packit Service 20376f
	if (!cl_sandbox_supports_8dot3())
Packit Service 20376f
		clar__skip();
Packit Service 20376f
Packit Service 20376f
	cl_must_pass(p_rename("nasty/.git", "nasty/_temp"));
Packit Service 20376f
	cl_git_write2file("nasty/git~1", "", 0, O_RDWR|O_CREAT, 0666);
Packit Service 20376f
	cl_must_pass(p_rename("nasty/_temp", "nasty/.git"));
Packit Service 20376f
	test_checkout_fails("refs/heads/git_tilde2", ".git/foobar");
Packit Service 20376f
#endif
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* A tree that contains an entry "git~3", which should be allowed, since
Packit Service 20376f
 * it is not the typical short name ("GIT~1") or the actual short name
Packit Service 20376f
 * ("GIT~2") for ".git".
Packit Service 20376f
 */
Packit Service 20376f
void test_checkout_nasty__only_looks_like_a_git_shortname(void)
Packit Service 20376f
{
Packit Service 20376f
#ifdef GIT_WIN32
Packit Service 20376f
	git_oid commit_id;
Packit Service 20376f
	git_commit *commit;
Packit Service 20376f
	git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT;
Packit Service 20376f
Packit Service 20376f
	cl_must_pass(p_rename("nasty/.git", "nasty/_temp"));
Packit Service 20376f
	cl_git_write2file("nasty/git~1", "", 0, O_RDWR|O_CREAT, 0666);
Packit Service 20376f
	cl_must_pass(p_rename("nasty/_temp", "nasty/.git"));
Packit Service 20376f
Packit Service 20376f
	cl_git_pass(git_reference_name_to_id(&commit_id, repo, "refs/heads/git_tilde3"));
Packit Service 20376f
	cl_git_pass(git_commit_lookup(&commit, repo, &commit_id));
Packit Service 20376f
Packit Service 20376f
	opts.checkout_strategy = GIT_CHECKOUT_FORCE;
Packit Service 20376f
Packit Service 20376f
	cl_git_pass(git_checkout_tree(repo, (const git_object *)commit, &opts));
Packit Service 20376f
	cl_assert(git_path_exists("nasty/git~3/foobar"));
Packit Service 20376f
Packit Service 20376f
	git_commit_free(commit);
Packit Service 20376f
#endif
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* A tree that contains an entry "git:", because Win32 APIs will reject
Packit Service 20376f
 * that as looking too similar to a drive letter.
Packit Service 20376f
 */
Packit Service 20376f
void test_checkout_nasty__dot_git_colon(void)
Packit Service 20376f
{
Packit Service 20376f
#ifdef GIT_WIN32
Packit Service 20376f
	test_checkout_fails("refs/heads/dot_git_colon", ".git/foobar");
Packit Service 20376f
#endif
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* A tree that contains an entry "git:foo", because Win32 APIs will turn
Packit Service 20376f
 * that into ".git".
Packit Service 20376f
 */
Packit Service 20376f
void test_checkout_nasty__dot_git_colon_stuff(void)
Packit Service 20376f
{
Packit Service 20376f
#ifdef GIT_WIN32
Packit Service 20376f
	test_checkout_fails("refs/heads/dot_git_colon_stuff", ".git/foobar");
Packit Service 20376f
#endif
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
/* Trees that contains entries with a tree ".git" that contain
Packit Service 20376f
 * byte sequences:
Packit Service 20376f
 * { 0xe2, 0x80, 0x8c }
Packit Service 20376f
 * { 0xe2, 0x80, 0x8d }
Packit Service 20376f
 * { 0xe2, 0x80, 0x8e }
Packit Service 20376f
 * { 0xe2, 0x80, 0x8f }
Packit Service 20376f
 * { 0xe2, 0x80, 0xaa }
Packit Service 20376f
 * { 0xe2, 0x80, 0xab }
Packit Service 20376f
 * { 0xe2, 0x80, 0xac }
Packit Service 20376f
 * { 0xe2, 0x80, 0xad }
Packit Service 20376f
 * { 0xe2, 0x81, 0xae }
Packit Service 20376f
 * { 0xe2, 0x81, 0xaa }
Packit Service 20376f
 * { 0xe2, 0x81, 0xab }
Packit Service 20376f
 * { 0xe2, 0x81, 0xac }
Packit Service 20376f
 * { 0xe2, 0x81, 0xad }
Packit Service 20376f
 * { 0xe2, 0x81, 0xae }
Packit Service 20376f
 * { 0xe2, 0x81, 0xaf }
Packit Service 20376f
 * { 0xef, 0xbb, 0xbf }
Packit Service 20376f
 * Because these map to characters that HFS filesystems "ignore".  Thus
Packit Service 20376f
 * ".git<U+200C>" will map to ".git".
Packit Service 20376f
 */
Packit Service 20376f
void test_checkout_nasty__dot_git_hfs_ignorable(void)
Packit Service 20376f
{
Packit Service 20376f
#ifdef __APPLE__
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_1", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_2", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_3", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_4", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_5", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_6", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_7", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_8", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_9", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_10", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_11", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_12", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_13", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_14", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_15", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_16", ".git/foobar");
Packit Service 20376f
#endif
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_checkout_nasty__honors_core_protecthfs(void)
Packit Service 20376f
{
Packit Service 20376f
	cl_repo_set_bool(repo, "core.protectHFS", true);
Packit Service 20376f
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_1", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_2", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_3", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_4", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_5", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_6", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_7", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_8", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_9", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_10", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_11", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_12", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_13", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_14", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_15", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_hfs_ignorable_16", ".git/foobar");
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_checkout_nasty__honors_core_protectntfs(void)
Packit Service 20376f
{
Packit Service 20376f
	cl_repo_set_bool(repo, "core.protectNTFS", true);
Packit Service 20376f
Packit Service 20376f
	test_checkout_fails("refs/heads/dotgit_backslash_path", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dotcapitalgit_backslash_path", ".GIT/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/dot_git_dot", ".git/foobar");
Packit Service 20376f
	test_checkout_fails("refs/heads/git_tilde1", ".git/foobar");
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_checkout_nasty__symlink1(void)
Packit Service 20376f
{
Packit Service 20376f
	test_checkout_passes("refs/heads/symlink1", ".git/foobar");
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_checkout_nasty__symlink2(void)
Packit Service 20376f
{
Packit Service 20376f
	test_checkout_passes("refs/heads/symlink2", ".git/foobar");
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_checkout_nasty__symlink3(void)
Packit Service 20376f
{
Packit Service 20376f
	test_checkout_passes("refs/heads/symlink3", ".git/foobar");
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_checkout_nasty__gitmodules_symlink(void)
Packit Service 20376f
{
Packit Service 20376f
	cl_repo_set_bool(repo, "core.protectHFS", true);
Packit Service 20376f
	test_checkout_fails("refs/heads/gitmodules-symlink", ".gitmodules");
Packit Service 20376f
	cl_repo_set_bool(repo, "core.protectHFS", false);
Packit Service 20376f
Packit Service 20376f
	cl_repo_set_bool(repo, "core.protectNTFS", true);
Packit Service 20376f
	test_checkout_fails("refs/heads/gitmodules-symlink", ".gitmodules");
Packit Service 20376f
	cl_repo_set_bool(repo, "core.protectNTFS", false);
Packit Service 20376f
Packit Service 20376f
	test_checkout_fails("refs/heads/gitmodules-symlink", ".gitmodules");
Packit Service 20376f
}