Blame tests/core/link.c

Packit Service 20376f
#include "clar_libgit2.h"
Packit Service 20376f
#include "posix.h"
Packit Service 20376f
#include "buffer.h"
Packit Service 20376f
#include "path.h"
Packit Service 20376f
Packit Service 20376f
#ifdef GIT_WIN32
Packit Service 20376f
# include "win32/reparse.h"
Packit Service 20376f
#endif
Packit Service 20376f
Packit Service 20376f
void test_core_link__cleanup(void)
Packit Service 20376f
{
Packit Service 20376f
#ifdef GIT_WIN32
Packit Service 20376f
	RemoveDirectory("lstat_junction");
Packit Service 20376f
	RemoveDirectory("lstat_dangling");
Packit Service 20376f
	RemoveDirectory("lstat_dangling_dir");
Packit Service 20376f
	RemoveDirectory("lstat_dangling_junction");
Packit Service 20376f
Packit Service 20376f
	RemoveDirectory("stat_junction");
Packit Service 20376f
	RemoveDirectory("stat_dangling");
Packit Service 20376f
	RemoveDirectory("stat_dangling_dir");
Packit Service 20376f
	RemoveDirectory("stat_dangling_junction");
Packit Service 20376f
#endif
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
#ifdef GIT_WIN32
Packit Service 20376f
static bool should_run(void)
Packit Service 20376f
{
Packit Service 20376f
	static SID_IDENTIFIER_AUTHORITY authority = { SECURITY_NT_AUTHORITY };
Packit Service 20376f
	PSID admin_sid;
Packit Service 20376f
	BOOL is_admin;
Packit Service 20376f
Packit Service 20376f
	cl_win32_pass(AllocateAndInitializeSid(&authority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &admin_sid));
Packit Service 20376f
	cl_win32_pass(CheckTokenMembership(NULL, admin_sid, &is_admin));
Packit Service 20376f
	FreeSid(admin_sid);
Packit Service 20376f
Packit Service 20376f
	return is_admin ? true : false;
Packit Service 20376f
}
Packit Service 20376f
#else
Packit Service 20376f
static bool should_run(void)
Packit Service 20376f
{
Packit Service 20376f
	return true;
Packit Service 20376f
}
Packit Service 20376f
#endif
Packit Service 20376f
Packit Service 20376f
static void do_symlink(const char *old, const char *new, int is_dir)
Packit Service 20376f
{
Packit Service 20376f
#ifndef GIT_WIN32
Packit Service 20376f
	GIT_UNUSED(is_dir);
Packit Service 20376f
Packit Service 20376f
	cl_must_pass(symlink(old, new));
Packit Service 20376f
#else
Packit Service 20376f
	typedef DWORD (WINAPI *create_symlink_func)(LPCTSTR, LPCTSTR, DWORD);
Packit Service 20376f
	HMODULE module;
Packit Service 20376f
	create_symlink_func pCreateSymbolicLink;
Packit Service 20376f
Packit Service 20376f
	cl_assert(module = GetModuleHandle("kernel32"));
Packit Service 20376f
	cl_assert(pCreateSymbolicLink = (create_symlink_func)GetProcAddress(module, "CreateSymbolicLinkA"));
Packit Service 20376f
Packit Service 20376f
	cl_win32_pass(pCreateSymbolicLink(new, old, is_dir));
Packit Service 20376f
#endif
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static void do_hardlink(const char *old, const char *new)
Packit Service 20376f
{
Packit Service 20376f
#ifndef GIT_WIN32
Packit Service 20376f
	cl_must_pass(link(old, new));
Packit Service 20376f
#else
Packit Service 20376f
	typedef DWORD (WINAPI *create_hardlink_func)(LPCTSTR, LPCTSTR, LPSECURITY_ATTRIBUTES);
Packit Service 20376f
	HMODULE module;
Packit Service 20376f
	create_hardlink_func pCreateHardLink;
Packit Service 20376f
Packit Service 20376f
	cl_assert(module = GetModuleHandle("kernel32"));
Packit Service 20376f
	cl_assert(pCreateHardLink = (create_hardlink_func)GetProcAddress(module, "CreateHardLinkA"));
Packit Service 20376f
Packit Service 20376f
	cl_win32_pass(pCreateHardLink(new, old, 0));
Packit Service 20376f
#endif
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
#ifdef GIT_WIN32
Packit Service 20376f
Packit Service 20376f
static void do_junction(const char *old, const char *new)
Packit Service 20376f
{
Packit Service 20376f
	GIT_REPARSE_DATA_BUFFER *reparse_buf;
Packit Service 20376f
	HANDLE handle;
Packit Service 20376f
	git_buf unparsed_buf = GIT_BUF_INIT;
Packit Service 20376f
	wchar_t *subst_utf16, *print_utf16;
Packit Service 20376f
	DWORD ioctl_ret;
Packit Service 20376f
	int subst_utf16_len, subst_byte_len, print_utf16_len, print_byte_len, ret;
Packit Service 20376f
	USHORT reparse_buflen;
Packit Service 20376f
	size_t i;
Packit Service 20376f
Packit Service 20376f
	/* Junction targets must be the unparsed name, starting with \??\, using
Packit Service 20376f
	 * backslashes instead of forward, and end in a trailing backslash.
Packit Service 20376f
	 * eg: \??\C:\Foo\
Packit Service 20376f
	 */
Packit Service 20376f
	git_buf_puts(&unparsed_buf, "\\??\\");
Packit Service 20376f
Packit Service 20376f
	for (i = 0; i < strlen(old); i++)
Packit Service 20376f
		git_buf_putc(&unparsed_buf, old[i] == '/' ? '\\' : old[i]);
Packit Service 20376f
Packit Service 20376f
	git_buf_putc(&unparsed_buf, '\\');
Packit Service 20376f
Packit Service 20376f
	subst_utf16_len = git__utf8_to_16(NULL, 0, git_buf_cstr(&unparsed_buf));
Packit Service 20376f
	subst_byte_len = subst_utf16_len * sizeof(WCHAR);
Packit Service 20376f
Packit Service 20376f
	print_utf16_len = subst_utf16_len - 4;
Packit Service 20376f
	print_byte_len = subst_byte_len - (4 * sizeof(WCHAR));
Packit Service 20376f
Packit Service 20376f
	/* The junction must be an empty directory before the junction attribute
Packit Service 20376f
	 * can be added.
Packit Service 20376f
	 */
Packit Service 20376f
	cl_win32_pass(CreateDirectoryA(new, NULL));
Packit Service 20376f
Packit Service 20376f
	handle = CreateFileA(new, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
Packit Service 20376f
		FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);
Packit Service 20376f
	cl_win32_pass(handle != INVALID_HANDLE_VALUE);
Packit Service 20376f
Packit Service 20376f
	reparse_buflen = (USHORT)(REPARSE_DATA_HEADER_SIZE +
Packit Service 20376f
		REPARSE_DATA_MOUNTPOINT_HEADER_SIZE +
Packit Service 20376f
		subst_byte_len + sizeof(WCHAR) +
Packit Service 20376f
		print_byte_len + sizeof(WCHAR));
Packit Service 20376f
Packit Service 20376f
	reparse_buf = LocalAlloc(LMEM_FIXED|LMEM_ZEROINIT, reparse_buflen);
Packit Service 20376f
	cl_assert(reparse_buf);
Packit Service 20376f
Packit Service 20376f
	subst_utf16 = reparse_buf->MountPointReparseBuffer.PathBuffer;
Packit Service 20376f
	print_utf16 = subst_utf16 + subst_utf16_len + 1;
Packit Service 20376f
Packit Service 20376f
	ret = git__utf8_to_16(subst_utf16, subst_utf16_len + 1,
Packit Service 20376f
		git_buf_cstr(&unparsed_buf));
Packit Service 20376f
	cl_assert_equal_i(subst_utf16_len, ret);
Packit Service 20376f
Packit Service 20376f
	ret = git__utf8_to_16(print_utf16,
Packit Service 20376f
		print_utf16_len + 1, git_buf_cstr(&unparsed_buf) + 4);
Packit Service 20376f
	cl_assert_equal_i(print_utf16_len, ret);
Packit Service 20376f
Packit Service 20376f
	reparse_buf->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
Packit Service 20376f
	reparse_buf->MountPointReparseBuffer.SubstituteNameOffset = 0;
Packit Service 20376f
	reparse_buf->MountPointReparseBuffer.SubstituteNameLength = subst_byte_len;
Packit Service 20376f
	reparse_buf->MountPointReparseBuffer.PrintNameOffset = (USHORT)(subst_byte_len + sizeof(WCHAR));
Packit Service 20376f
	reparse_buf->MountPointReparseBuffer.PrintNameLength = print_byte_len;
Packit Service 20376f
	reparse_buf->ReparseDataLength = reparse_buflen - REPARSE_DATA_HEADER_SIZE;
Packit Service 20376f
Packit Service 20376f
	cl_win32_pass(DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT,
Packit Service 20376f
		reparse_buf, reparse_buflen, NULL, 0, &ioctl_ret, NULL));
Packit Service 20376f
Packit Service 20376f
	CloseHandle(handle);
Packit Service 20376f
	LocalFree(reparse_buf);
Packit Service 20376f
Packit Service 20376f
	git_buf_free(&unparsed_buf);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
static void do_custom_reparse(const char *path)
Packit Service 20376f
{
Packit Service 20376f
	REPARSE_GUID_DATA_BUFFER *reparse_buf;
Packit Service 20376f
	HANDLE handle;
Packit Service 20376f
	DWORD ioctl_ret;
Packit Service 20376f
Packit Service 20376f
	const char *reparse_data = "Reparse points are silly.";
Packit Service 20376f
	size_t reparse_buflen = REPARSE_GUID_DATA_BUFFER_HEADER_SIZE +
Packit Service 20376f
		strlen(reparse_data) + 1;
Packit Service 20376f
Packit Service 20376f
	reparse_buf = LocalAlloc(LMEM_FIXED|LMEM_ZEROINIT, reparse_buflen);
Packit Service 20376f
	cl_assert(reparse_buf);
Packit Service 20376f
Packit Service 20376f
	reparse_buf->ReparseTag = 42;
Packit Service 20376f
	reparse_buf->ReparseDataLength = (WORD)(strlen(reparse_data) + 1);
Packit Service 20376f
Packit Service 20376f
	reparse_buf->ReparseGuid.Data1 = 0xdeadbeef;
Packit Service 20376f
	reparse_buf->ReparseGuid.Data2 = 0xdead;
Packit Service 20376f
	reparse_buf->ReparseGuid.Data3 = 0xbeef;
Packit Service 20376f
	reparse_buf->ReparseGuid.Data4[0] = 42;
Packit Service 20376f
	reparse_buf->ReparseGuid.Data4[1] = 42;
Packit Service 20376f
	reparse_buf->ReparseGuid.Data4[2] = 42;
Packit Service 20376f
	reparse_buf->ReparseGuid.Data4[3] = 42;
Packit Service 20376f
	reparse_buf->ReparseGuid.Data4[4] = 42;
Packit Service 20376f
	reparse_buf->ReparseGuid.Data4[5] = 42;
Packit Service 20376f
	reparse_buf->ReparseGuid.Data4[6] = 42;
Packit Service 20376f
	reparse_buf->ReparseGuid.Data4[7] = 42;
Packit Service 20376f
	reparse_buf->ReparseGuid.Data4[8] = 42;
Packit Service 20376f
Packit Service 20376f
	memcpy(reparse_buf->GenericReparseBuffer.DataBuffer,
Packit Service 20376f
		reparse_data, strlen(reparse_data) + 1);
Packit Service 20376f
Packit Service 20376f
	handle = CreateFileA(path, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
Packit Service 20376f
		FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);
Packit Service 20376f
	cl_win32_pass(handle != INVALID_HANDLE_VALUE);
Packit Service 20376f
Packit Service 20376f
	cl_win32_pass(DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT,
Packit Service 20376f
		reparse_buf,
Packit Service 20376f
		reparse_buf->ReparseDataLength + REPARSE_GUID_DATA_BUFFER_HEADER_SIZE,
Packit Service 20376f
		NULL, 0, &ioctl_ret, NULL));
Packit Service 20376f
Packit Service 20376f
	CloseHandle(handle);
Packit Service 20376f
	LocalFree(reparse_buf);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
#endif
Packit Service 20376f
Packit Service 20376f
void test_core_link__stat_regular_file(void)
Packit Service 20376f
{
Packit Service 20376f
	struct stat st;
Packit Service 20376f
Packit Service 20376f
	cl_git_rewritefile("stat_regfile", "This is a regular file!\n");
Packit Service 20376f
Packit Service 20376f
	cl_must_pass(p_stat("stat_regfile", &st);;
Packit Service 20376f
	cl_assert(S_ISREG(st.st_mode));
Packit Service 20376f
	cl_assert_equal_i(24, st.st_size);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_core_link__lstat_regular_file(void)
Packit Service 20376f
{
Packit Service 20376f
	struct stat st;
Packit Service 20376f
Packit Service 20376f
	cl_git_rewritefile("lstat_regfile", "This is a regular file!\n");
Packit Service 20376f
Packit Service 20376f
	cl_must_pass(p_stat("lstat_regfile", &st);;
Packit Service 20376f
	cl_assert(S_ISREG(st.st_mode));
Packit Service 20376f
	cl_assert_equal_i(24, st.st_size);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_core_link__stat_symlink(void)
Packit Service 20376f
{
Packit Service 20376f
	struct stat st;
Packit Service 20376f
Packit Service 20376f
	if (!should_run())
Packit Service 20376f
		clar__skip();
Packit Service 20376f
Packit Service 20376f
	cl_git_rewritefile("stat_target", "This is the target of a symbolic link.\n");
Packit Service 20376f
	do_symlink("stat_target", "stat_symlink", 0);
Packit Service 20376f
Packit Service 20376f
	cl_must_pass(p_stat("stat_target", &st);;
Packit Service 20376f
	cl_assert(S_ISREG(st.st_mode));
Packit Service 20376f
	cl_assert_equal_i(39, st.st_size);
Packit Service 20376f
Packit Service 20376f
	cl_must_pass(p_stat("stat_symlink", &st);;
Packit Service 20376f
	cl_assert(S_ISREG(st.st_mode));
Packit Service 20376f
	cl_assert_equal_i(39, st.st_size);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_core_link__stat_symlink_directory(void)
Packit Service 20376f
{
Packit Service 20376f
	struct stat st;
Packit Service 20376f
Packit Service 20376f
	if (!should_run())
Packit Service 20376f
		clar__skip();
Packit Service 20376f
Packit Service 20376f
	p_mkdir("stat_dirtarget", 0777);
Packit Service 20376f
	do_symlink("stat_dirtarget", "stat_dirlink", 1);
Packit Service 20376f
Packit Service 20376f
	cl_must_pass(p_stat("stat_dirtarget", &st);;
Packit Service 20376f
	cl_assert(S_ISDIR(st.st_mode));
Packit Service 20376f
Packit Service 20376f
	cl_must_pass(p_stat("stat_dirlink", &st);;
Packit Service 20376f
	cl_assert(S_ISDIR(st.st_mode));
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_core_link__stat_symlink_chain(void)
Packit Service 20376f
{
Packit Service 20376f
	struct stat st;
Packit Service 20376f
Packit Service 20376f
	if (!should_run())
Packit Service 20376f
		clar__skip();
Packit Service 20376f
Packit Service 20376f
	cl_git_rewritefile("stat_final_target", "Final target of some symbolic links...\n");
Packit Service 20376f
	do_symlink("stat_final_target", "stat_chain_3", 0);
Packit Service 20376f
	do_symlink("stat_chain_3", "stat_chain_2", 0);
Packit Service 20376f
	do_symlink("stat_chain_2", "stat_chain_1", 0);
Packit Service 20376f
Packit Service 20376f
	cl_must_pass(p_stat("stat_chain_1", &st);;
Packit Service 20376f
	cl_assert(S_ISREG(st.st_mode));
Packit Service 20376f
	cl_assert_equal_i(39, st.st_size);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_core_link__stat_dangling_symlink(void)
Packit Service 20376f
{
Packit Service 20376f
	struct stat st;
Packit Service 20376f
Packit Service 20376f
	if (!should_run())
Packit Service 20376f
		clar__skip();
Packit Service 20376f
Packit Service 20376f
	do_symlink("stat_nonexistent", "stat_dangling", 0);
Packit Service 20376f
Packit Service 20376f
	cl_must_fail(p_stat("stat_nonexistent", &st);;
Packit Service 20376f
	cl_must_fail(p_stat("stat_dangling", &st);;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_core_link__stat_dangling_symlink_directory(void)
Packit Service 20376f
{
Packit Service 20376f
	struct stat st;
Packit Service 20376f
Packit Service 20376f
	if (!should_run())
Packit Service 20376f
		clar__skip();
Packit Service 20376f
Packit Service 20376f
	do_symlink("stat_nonexistent", "stat_dangling_dir", 1);
Packit Service 20376f
Packit Service 20376f
	cl_must_fail(p_stat("stat_nonexistent_dir", &st);;
Packit Service 20376f
	cl_must_fail(p_stat("stat_dangling", &st);;
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_core_link__lstat_symlink(void)
Packit Service 20376f
{
Packit Service 20376f
	git_buf target_path = GIT_BUF_INIT;
Packit Service 20376f
	struct stat st;
Packit Service 20376f
Packit Service 20376f
	if (!should_run())
Packit Service 20376f
		clar__skip();
Packit Service 20376f
Packit Service 20376f
	/* Windows always writes the canonical path as the link target, so
Packit Service 20376f
	 * write the full path on all platforms.
Packit Service 20376f
	 */
Packit Service 20376f
	git_buf_join(&target_path, '/', clar_sandbox_path(), "lstat_target");
Packit Service 20376f
Packit Service 20376f
	cl_git_rewritefile("lstat_target", "This is the target of a symbolic link.\n");
Packit Service 20376f
	do_symlink(git_buf_cstr(&target_path), "lstat_symlink", 0);
Packit Service 20376f
Packit Service 20376f
	cl_must_pass(p_lstat("lstat_target", &st);;
Packit Service 20376f
	cl_assert(S_ISREG(st.st_mode));
Packit Service 20376f
	cl_assert_equal_i(39, st.st_size);
Packit Service 20376f
Packit Service 20376f
	cl_must_pass(p_lstat("lstat_symlink", &st);;
Packit Service 20376f
	cl_assert(S_ISLNK(st.st_mode));
Packit Service 20376f
	cl_assert_equal_i(git_buf_len(&target_path), st.st_size);
Packit Service 20376f
Packit Service 20376f
	git_buf_free(&target_path);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_core_link__lstat_symlink_directory(void)
Packit Service 20376f
{
Packit Service 20376f
	git_buf target_path = GIT_BUF_INIT;
Packit Service 20376f
	struct stat st;
Packit Service 20376f
Packit Service 20376f
	if (!should_run())
Packit Service 20376f
		clar__skip();
Packit Service 20376f
Packit Service 20376f
	git_buf_join(&target_path, '/', clar_sandbox_path(), "lstat_dirtarget");
Packit Service 20376f
Packit Service 20376f
	p_mkdir("lstat_dirtarget", 0777);
Packit Service 20376f
	do_symlink(git_buf_cstr(&target_path), "lstat_dirlink", 1);
Packit Service 20376f
Packit Service 20376f
	cl_must_pass(p_lstat("lstat_dirtarget", &st);;
Packit Service 20376f
	cl_assert(S_ISDIR(st.st_mode));
Packit Service 20376f
Packit Service 20376f
	cl_must_pass(p_lstat("lstat_dirlink", &st);;
Packit Service 20376f
	cl_assert(S_ISLNK(st.st_mode));
Packit Service 20376f
	cl_assert_equal_i(git_buf_len(&target_path), st.st_size);
Packit Service 20376f
Packit Service 20376f
	git_buf_free(&target_path);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_core_link__lstat_dangling_symlink(void)
Packit Service 20376f
{
Packit Service 20376f
	struct stat st;
Packit Service 20376f
Packit Service 20376f
	if (!should_run())
Packit Service 20376f
		clar__skip();
Packit Service 20376f
Packit Service 20376f
	do_symlink("lstat_nonexistent", "lstat_dangling", 0);
Packit Service 20376f
Packit Service 20376f
	cl_must_fail(p_lstat("lstat_nonexistent", &st);;
Packit Service 20376f
Packit Service 20376f
	cl_must_pass(p_lstat("lstat_dangling", &st);;
Packit Service 20376f
	cl_assert(S_ISLNK(st.st_mode));
Packit Service 20376f
	cl_assert_equal_i(strlen("lstat_nonexistent"), st.st_size);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_core_link__lstat_dangling_symlink_directory(void)
Packit Service 20376f
{
Packit Service 20376f
	struct stat st;
Packit Service 20376f
Packit Service 20376f
	if (!should_run())
Packit Service 20376f
		clar__skip();
Packit Service 20376f
Packit Service 20376f
	do_symlink("lstat_nonexistent", "lstat_dangling_dir", 1);
Packit Service 20376f
Packit Service 20376f
	cl_must_fail(p_lstat("lstat_nonexistent", &st);;
Packit Service 20376f
Packit Service 20376f
	cl_must_pass(p_lstat("lstat_dangling_dir", &st);;
Packit Service 20376f
	cl_assert(S_ISLNK(st.st_mode));
Packit Service 20376f
	cl_assert_equal_i(strlen("lstat_nonexistent"), st.st_size);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_core_link__stat_junction(void)
Packit Service 20376f
{
Packit Service 20376f
#ifdef GIT_WIN32
Packit Service 20376f
	git_buf target_path = GIT_BUF_INIT;
Packit Service 20376f
	struct stat st;
Packit Service 20376f
Packit Service 20376f
	git_buf_join(&target_path, '/', clar_sandbox_path(), "stat_junctarget");
Packit Service 20376f
Packit Service 20376f
	p_mkdir("stat_junctarget", 0777);
Packit Service 20376f
	do_junction(git_buf_cstr(&target_path), "stat_junction");
Packit Service 20376f
Packit Service 20376f
	cl_must_pass(p_stat("stat_junctarget", &st);;
Packit Service 20376f
	cl_assert(S_ISDIR(st.st_mode));
Packit Service 20376f
Packit Service 20376f
	cl_must_pass(p_stat("stat_junction", &st);;
Packit Service 20376f
	cl_assert(S_ISDIR(st.st_mode));
Packit Service 20376f
Packit Service 20376f
	git_buf_free(&target_path);
Packit Service 20376f
#endif
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_core_link__stat_dangling_junction(void)
Packit Service 20376f
{
Packit Service 20376f
#ifdef GIT_WIN32
Packit Service 20376f
	git_buf target_path = GIT_BUF_INIT;
Packit Service 20376f
	struct stat st;
Packit Service 20376f
Packit Service 20376f
	git_buf_join(&target_path, '/', clar_sandbox_path(), "stat_nonexistent_junctarget");
Packit Service 20376f
Packit Service 20376f
	p_mkdir("stat_nonexistent_junctarget", 0777);
Packit Service 20376f
	do_junction(git_buf_cstr(&target_path), "stat_dangling_junction");
Packit Service 20376f
Packit Service 20376f
	RemoveDirectory("stat_nonexistent_junctarget");
Packit Service 20376f
Packit Service 20376f
	cl_must_fail(p_stat("stat_nonexistent_junctarget", &st);;
Packit Service 20376f
	cl_must_fail(p_stat("stat_dangling_junction", &st);;
Packit Service 20376f
Packit Service 20376f
	git_buf_free(&target_path);
Packit Service 20376f
#endif
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_core_link__lstat_junction(void)
Packit Service 20376f
{
Packit Service 20376f
#ifdef GIT_WIN32
Packit Service 20376f
	git_buf target_path = GIT_BUF_INIT;
Packit Service 20376f
	struct stat st;
Packit Service 20376f
Packit Service 20376f
	git_buf_join(&target_path, '/', clar_sandbox_path(), "lstat_junctarget");
Packit Service 20376f
Packit Service 20376f
	p_mkdir("lstat_junctarget", 0777);
Packit Service 20376f
	do_junction(git_buf_cstr(&target_path), "lstat_junction");
Packit Service 20376f
Packit Service 20376f
	cl_must_pass(p_lstat("lstat_junctarget", &st);;
Packit Service 20376f
	cl_assert(S_ISDIR(st.st_mode));
Packit Service 20376f
Packit Service 20376f
	cl_must_pass(p_lstat("lstat_junction", &st);;
Packit Service 20376f
	cl_assert(S_ISLNK(st.st_mode));
Packit Service 20376f
Packit Service 20376f
	git_buf_free(&target_path);
Packit Service 20376f
#endif
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_core_link__lstat_dangling_junction(void)
Packit Service 20376f
{
Packit Service 20376f
#ifdef GIT_WIN32
Packit Service 20376f
	git_buf target_path = GIT_BUF_INIT;
Packit Service 20376f
	struct stat st;
Packit Service 20376f
Packit Service 20376f
	git_buf_join(&target_path, '/', clar_sandbox_path(), "lstat_nonexistent_junctarget");
Packit Service 20376f
Packit Service 20376f
	p_mkdir("lstat_nonexistent_junctarget", 0777);
Packit Service 20376f
	do_junction(git_buf_cstr(&target_path), "lstat_dangling_junction");
Packit Service 20376f
Packit Service 20376f
	RemoveDirectory("lstat_nonexistent_junctarget");
Packit Service 20376f
Packit Service 20376f
	cl_must_fail(p_lstat("lstat_nonexistent_junctarget", &st);;
Packit Service 20376f
Packit Service 20376f
	cl_must_pass(p_lstat("lstat_dangling_junction", &st);;
Packit Service 20376f
	cl_assert(S_ISLNK(st.st_mode));
Packit Service 20376f
	cl_assert_equal_i(git_buf_len(&target_path), st.st_size);
Packit Service 20376f
Packit Service 20376f
	git_buf_free(&target_path);
Packit Service 20376f
#endif
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_core_link__stat_hardlink(void)
Packit Service 20376f
{
Packit Service 20376f
	struct stat st;
Packit Service 20376f
Packit Service 20376f
	if (!should_run())
Packit Service 20376f
		clar__skip();
Packit Service 20376f
Packit Service 20376f
	cl_git_rewritefile("stat_hardlink1", "This file has many names!\n");
Packit Service 20376f
	do_hardlink("stat_hardlink1", "stat_hardlink2");
Packit Service 20376f
Packit Service 20376f
	cl_must_pass(p_stat("stat_hardlink1", &st);;
Packit Service 20376f
	cl_assert(S_ISREG(st.st_mode));
Packit Service 20376f
	cl_assert_equal_i(26, st.st_size);
Packit Service 20376f
Packit Service 20376f
	cl_must_pass(p_stat("stat_hardlink2", &st);;
Packit Service 20376f
	cl_assert(S_ISREG(st.st_mode));
Packit Service 20376f
	cl_assert_equal_i(26, st.st_size);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_core_link__lstat_hardlink(void)
Packit Service 20376f
{
Packit Service 20376f
	struct stat st;
Packit Service 20376f
Packit Service 20376f
	if (!should_run())
Packit Service 20376f
		clar__skip();
Packit Service 20376f
Packit Service 20376f
	cl_git_rewritefile("lstat_hardlink1", "This file has many names!\n");
Packit Service 20376f
	do_hardlink("lstat_hardlink1", "lstat_hardlink2");
Packit Service 20376f
Packit Service 20376f
	cl_must_pass(p_lstat("lstat_hardlink1", &st);;
Packit Service 20376f
	cl_assert(S_ISREG(st.st_mode));
Packit Service 20376f
	cl_assert_equal_i(26, st.st_size);
Packit Service 20376f
Packit Service 20376f
	cl_must_pass(p_lstat("lstat_hardlink2", &st);;
Packit Service 20376f
	cl_assert(S_ISREG(st.st_mode));
Packit Service 20376f
	cl_assert_equal_i(26, st.st_size);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_core_link__stat_reparse_point(void)
Packit Service 20376f
{
Packit Service 20376f
#ifdef GIT_WIN32
Packit Service 20376f
	struct stat st;
Packit Service 20376f
Packit Service 20376f
	/* Generic reparse points should be treated as regular files, only
Packit Service 20376f
	 * symlinks and junctions should be treated as links.
Packit Service 20376f
	 */
Packit Service 20376f
Packit Service 20376f
	cl_git_rewritefile("stat_reparse", "This is a reparse point!\n");
Packit Service 20376f
	do_custom_reparse("stat_reparse");
Packit Service 20376f
Packit Service 20376f
	cl_must_pass(p_lstat("stat_reparse", &st);;
Packit Service 20376f
	cl_assert(S_ISREG(st.st_mode));
Packit Service 20376f
	cl_assert_equal_i(25, st.st_size);
Packit Service 20376f
#endif
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_core_link__lstat_reparse_point(void)
Packit Service 20376f
{
Packit Service 20376f
#ifdef GIT_WIN32
Packit Service 20376f
	struct stat st;
Packit Service 20376f
Packit Service 20376f
	cl_git_rewritefile("lstat_reparse", "This is a reparse point!\n");
Packit Service 20376f
	do_custom_reparse("lstat_reparse");
Packit Service 20376f
Packit Service 20376f
	cl_must_pass(p_lstat("lstat_reparse", &st);;
Packit Service 20376f
	cl_assert(S_ISREG(st.st_mode));
Packit Service 20376f
	cl_assert_equal_i(25, st.st_size);
Packit Service 20376f
#endif
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_core_link__readlink_nonexistent_file(void)
Packit Service 20376f
{
Packit Service 20376f
	char buf[2048];
Packit Service 20376f
Packit Service 20376f
	cl_must_fail(p_readlink("readlink_nonexistent", buf, 2048));
Packit Service 20376f
	cl_assert_equal_i(ENOENT, errno);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_core_link__readlink_normal_file(void)
Packit Service 20376f
{
Packit Service 20376f
	char buf[2048];
Packit Service 20376f
Packit Service 20376f
	cl_git_rewritefile("readlink_regfile", "This is a regular file!\n");
Packit Service 20376f
	cl_must_fail(p_readlink("readlink_regfile", buf, 2048));
Packit Service 20376f
	cl_assert_equal_i(EINVAL, errno);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_core_link__readlink_symlink(void)
Packit Service 20376f
{
Packit Service 20376f
	git_buf target_path = GIT_BUF_INIT;
Packit Service 20376f
	int len;
Packit Service 20376f
	char buf[2048];
Packit Service 20376f
Packit Service 20376f
	if (!should_run())
Packit Service 20376f
		clar__skip();
Packit Service 20376f
Packit Service 20376f
	git_buf_join(&target_path, '/', clar_sandbox_path(), "readlink_target");
Packit Service 20376f
Packit Service 20376f
	cl_git_rewritefile("readlink_target", "This is the target of a symlink\n");
Packit Service 20376f
	do_symlink(git_buf_cstr(&target_path), "readlink_link", 0);
Packit Service 20376f
Packit Service 20376f
	len = p_readlink("readlink_link", buf, 2048);
Packit Service 20376f
	cl_must_pass(len);
Packit Service 20376f
Packit Service 20376f
	buf[len] = 0;
Packit Service 20376f
Packit Service 20376f
	cl_assert_equal_s(git_buf_cstr(&target_path), buf);
Packit Service 20376f
Packit Service 20376f
	git_buf_free(&target_path);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_core_link__readlink_dangling(void)
Packit Service 20376f
{
Packit Service 20376f
	git_buf target_path = GIT_BUF_INIT;
Packit Service 20376f
	int len;
Packit Service 20376f
	char buf[2048];
Packit Service 20376f
Packit Service 20376f
	if (!should_run())
Packit Service 20376f
		clar__skip();
Packit Service 20376f
Packit Service 20376f
	git_buf_join(&target_path, '/', clar_sandbox_path(), "readlink_nonexistent");
Packit Service 20376f
Packit Service 20376f
	do_symlink(git_buf_cstr(&target_path), "readlink_dangling", 0);
Packit Service 20376f
Packit Service 20376f
	len = p_readlink("readlink_dangling", buf, 2048);
Packit Service 20376f
	cl_must_pass(len);
Packit Service 20376f
Packit Service 20376f
	buf[len] = 0;
Packit Service 20376f
Packit Service 20376f
	cl_assert_equal_s(git_buf_cstr(&target_path), buf);
Packit Service 20376f
Packit Service 20376f
	git_buf_free(&target_path);
Packit Service 20376f
}
Packit Service 20376f
Packit Service 20376f
void test_core_link__readlink_multiple(void)
Packit Service 20376f
{
Packit Service 20376f
	git_buf target_path = GIT_BUF_INIT,
Packit Service 20376f
		path3 = GIT_BUF_INIT, path2 = GIT_BUF_INIT, path1 = GIT_BUF_INIT;
Packit Service 20376f
	int len;
Packit Service 20376f
	char buf[2048];
Packit Service 20376f
Packit Service 20376f
	if (!should_run())
Packit Service 20376f
		clar__skip();
Packit Service 20376f
Packit Service 20376f
	git_buf_join(&target_path, '/', clar_sandbox_path(), "readlink_final");
Packit Service 20376f
	git_buf_join(&path3, '/', clar_sandbox_path(), "readlink_3");
Packit Service 20376f
	git_buf_join(&path2, '/', clar_sandbox_path(), "readlink_2");
Packit Service 20376f
	git_buf_join(&path1, '/', clar_sandbox_path(), "readlink_1");
Packit Service 20376f
Packit Service 20376f
	do_symlink(git_buf_cstr(&target_path), git_buf_cstr(&path3), 0);
Packit Service 20376f
	do_symlink(git_buf_cstr(&path3), git_buf_cstr(&path2), 0);
Packit Service 20376f
	do_symlink(git_buf_cstr(&path2), git_buf_cstr(&path1), 0);
Packit Service 20376f
Packit Service 20376f
	len = p_readlink("readlink_1", buf, 2048);
Packit Service 20376f
	cl_must_pass(len);
Packit Service 20376f
Packit Service 20376f
	buf[len] = 0;
Packit Service 20376f
Packit Service 20376f
	cl_assert_equal_s(git_buf_cstr(&path2), buf);
Packit Service 20376f
Packit Service 20376f
	git_buf_free(&path1);
Packit Service 20376f
	git_buf_free(&path2);
Packit Service 20376f
	git_buf_free(&path3);
Packit Service 20376f
	git_buf_free(&target_path);
Packit Service 20376f
}