mirror of
				https://git.proxmox.com/git/libgit2
				synced 2025-11-04 07:09:14 +00:00 
			
		
		
		
	Ensure that we can iterate the filesystem root and that paths come back well-formed, not with an additional '/'. (eg, when iterating `c:/`, expect that we do not get some path like `c://autoexec.bat`).
		
			
				
	
	
		
			307 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			307 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#include "clar_libgit2.h"
 | 
						|
#include "fileops.h"
 | 
						|
 | 
						|
typedef struct name_data {
 | 
						|
	int count; /* return count */
 | 
						|
	char *name; /* filename		*/
 | 
						|
} name_data;
 | 
						|
 | 
						|
typedef struct walk_data {
 | 
						|
	char *sub;		/* sub-directory name */
 | 
						|
	name_data *names; /* name state data	*/
 | 
						|
	git_buf path;
 | 
						|
} walk_data;
 | 
						|
 | 
						|
 | 
						|
static char *top_dir = "dir-walk";
 | 
						|
static walk_data *state_loc;
 | 
						|
 | 
						|
static void setup(walk_data *d)
 | 
						|
{
 | 
						|
	name_data *n;
 | 
						|
 | 
						|
	cl_must_pass(p_mkdir(top_dir, 0777));
 | 
						|
 | 
						|
	cl_must_pass(p_chdir(top_dir));
 | 
						|
 | 
						|
	if (strcmp(d->sub, ".") != 0)
 | 
						|
		cl_must_pass(p_mkdir(d->sub, 0777));
 | 
						|
 | 
						|
	cl_git_pass(git_buf_sets(&d->path, d->sub));
 | 
						|
 | 
						|
	state_loc = d;
 | 
						|
 | 
						|
	for (n = d->names; n->name; n++) {
 | 
						|
		git_file fd = p_creat(n->name, 0666);
 | 
						|
		cl_assert(fd >= 0);
 | 
						|
		p_close(fd);
 | 
						|
		n->count = 0;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void dirent_cleanup__cb(void *_d)
 | 
						|
{
 | 
						|
	walk_data *d = _d;
 | 
						|
	name_data *n;
 | 
						|
 | 
						|
	for (n = d->names; n->name; n++) {
 | 
						|
		cl_must_pass(p_unlink(n->name));
 | 
						|
	}
 | 
						|
 | 
						|
	if (strcmp(d->sub, ".") != 0)
 | 
						|
		cl_must_pass(p_rmdir(d->sub));
 | 
						|
 | 
						|
	cl_must_pass(p_chdir(".."));
 | 
						|
 | 
						|
	cl_must_pass(p_rmdir(top_dir));
 | 
						|
 | 
						|
	git_buf_free(&d->path);
 | 
						|
}
 | 
						|
 | 
						|
static void check_counts(walk_data *d)
 | 
						|
{
 | 
						|
	name_data *n;
 | 
						|
 | 
						|
	for (n = d->names; n->name; n++) {
 | 
						|
		cl_assert(n->count == 1);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static int update_count(name_data *data, const char *name)
 | 
						|
{
 | 
						|
	name_data *n;
 | 
						|
 | 
						|
	for (n = data; n->name; n++) {
 | 
						|
		if (!strcmp(n->name, name)) {
 | 
						|
			n->count++;
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return GIT_ERROR;
 | 
						|
}
 | 
						|
 | 
						|
static int one_entry(void *state, git_buf *path)
 | 
						|
{
 | 
						|
	walk_data *d = (walk_data *) state;
 | 
						|
 | 
						|
	if (state != state_loc)
 | 
						|
		return GIT_ERROR;
 | 
						|
 | 
						|
	if (path != &d->path)
 | 
						|
		return GIT_ERROR;
 | 
						|
 | 
						|
	return update_count(d->names, path->ptr);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static name_data dot_names[] = {
 | 
						|
	{ 0, "./a" },
 | 
						|
	{ 0, "./asdf" },
 | 
						|
	{ 0, "./pack-foo.pack" },
 | 
						|
	{ 0, NULL }
 | 
						|
};
 | 
						|
static walk_data dot = {
 | 
						|
	".",
 | 
						|
	dot_names,
 | 
						|
	GIT_BUF_INIT
 | 
						|
};
 | 
						|
 | 
						|
/* make sure that the '.' folder is not traversed */
 | 
						|
void test_core_dirent__dont_traverse_dot(void)
 | 
						|
{
 | 
						|
	cl_set_cleanup(&dirent_cleanup__cb, &dot);
 | 
						|
	setup(&dot);
 | 
						|
 | 
						|
	cl_git_pass(git_path_direach(&dot.path, 0, one_entry, &dot));
 | 
						|
 | 
						|
	check_counts(&dot);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static name_data sub_names[] = {
 | 
						|
	{ 0, "sub/a" },
 | 
						|
	{ 0, "sub/asdf" },
 | 
						|
	{ 0, "sub/pack-foo.pack" },
 | 
						|
	{ 0, NULL }
 | 
						|
};
 | 
						|
static walk_data sub = {
 | 
						|
	"sub",
 | 
						|
	sub_names,
 | 
						|
	GIT_BUF_INIT
 | 
						|
};
 | 
						|
 | 
						|
/* traverse a subfolder */
 | 
						|
void test_core_dirent__traverse_subfolder(void)
 | 
						|
{
 | 
						|
	cl_set_cleanup(&dirent_cleanup__cb, &sub);
 | 
						|
	setup(&sub);
 | 
						|
 | 
						|
	cl_git_pass(git_path_direach(&sub.path, 0, one_entry, &sub));
 | 
						|
 | 
						|
	check_counts(&sub);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static walk_data sub_slash = {
 | 
						|
	"sub/",
 | 
						|
	sub_names,
 | 
						|
	GIT_BUF_INIT
 | 
						|
};
 | 
						|
 | 
						|
/* traverse a slash-terminated subfolder */
 | 
						|
void test_core_dirent__traverse_slash_terminated_folder(void)
 | 
						|
{
 | 
						|
	cl_set_cleanup(&dirent_cleanup__cb, &sub_slash);
 | 
						|
	setup(&sub_slash);
 | 
						|
 | 
						|
	cl_git_pass(git_path_direach(&sub_slash.path, 0, one_entry, &sub_slash));
 | 
						|
 | 
						|
	check_counts(&sub_slash);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static name_data empty_names[] = {
 | 
						|
	{ 0, NULL }
 | 
						|
};
 | 
						|
static walk_data empty = {
 | 
						|
	"empty",
 | 
						|
	empty_names,
 | 
						|
	GIT_BUF_INIT
 | 
						|
};
 | 
						|
 | 
						|
/* make sure that empty folders are not traversed */
 | 
						|
void test_core_dirent__dont_traverse_empty_folders(void)
 | 
						|
{
 | 
						|
	cl_set_cleanup(&dirent_cleanup__cb, &empty);
 | 
						|
	setup(&empty);
 | 
						|
 | 
						|
	cl_git_pass(git_path_direach(&empty.path, 0, one_entry, &empty));
 | 
						|
 | 
						|
	check_counts(&empty);
 | 
						|
 | 
						|
	/* make sure callback not called */
 | 
						|
	cl_assert(git_path_is_empty_dir(empty.path.ptr));
 | 
						|
}
 | 
						|
 | 
						|
static name_data odd_names[] = {
 | 
						|
	{ 0, "odd/.a" },
 | 
						|
	{ 0, "odd/..c" },
 | 
						|
	/* the following don't work on cygwin/win32 */
 | 
						|
	/* { 0, "odd/.b." }, */
 | 
						|
	/* { 0, "odd/..d.." }, */
 | 
						|
	{ 0, NULL }
 | 
						|
};
 | 
						|
static walk_data odd = {
 | 
						|
	"odd",
 | 
						|
	odd_names,
 | 
						|
	GIT_BUF_INIT
 | 
						|
};
 | 
						|
 | 
						|
/* make sure that strange looking filenames ('..c') are traversed */
 | 
						|
void test_core_dirent__traverse_weird_filenames(void)
 | 
						|
{
 | 
						|
	cl_set_cleanup(&dirent_cleanup__cb, &odd);
 | 
						|
	setup(&odd);
 | 
						|
 | 
						|
	cl_git_pass(git_path_direach(&odd.path, 0, one_entry, &odd));
 | 
						|
 | 
						|
	check_counts(&odd);
 | 
						|
}
 | 
						|
 | 
						|
/* test filename length limits */
 | 
						|
void test_core_dirent__length_limits(void)
 | 
						|
{
 | 
						|
	char *big_filename = (char *)git__malloc(FILENAME_MAX + 1);
 | 
						|
	memset(big_filename, 'a', FILENAME_MAX + 1);
 | 
						|
	big_filename[FILENAME_MAX] = 0;
 | 
						|
 | 
						|
	cl_must_fail(p_creat(big_filename, 0666));
 | 
						|
 | 
						|
	git__free(big_filename);
 | 
						|
}
 | 
						|
 | 
						|
void test_core_dirent__empty_dir(void)
 | 
						|
{
 | 
						|
	cl_must_pass(p_mkdir("empty_dir", 0777));
 | 
						|
	cl_assert(git_path_is_empty_dir("empty_dir"));
 | 
						|
 | 
						|
	cl_git_mkfile("empty_dir/content", "whatever\n");
 | 
						|
	cl_assert(!git_path_is_empty_dir("empty_dir"));
 | 
						|
	cl_assert(!git_path_is_empty_dir("empty_dir/content"));
 | 
						|
 | 
						|
	cl_must_pass(p_unlink("empty_dir/content"));
 | 
						|
 | 
						|
	cl_must_pass(p_mkdir("empty_dir/content", 0777));
 | 
						|
	cl_assert(!git_path_is_empty_dir("empty_dir"));
 | 
						|
	cl_assert(git_path_is_empty_dir("empty_dir/content"));
 | 
						|
 | 
						|
	cl_must_pass(p_rmdir("empty_dir/content"));
 | 
						|
 | 
						|
	cl_must_pass(p_rmdir("empty_dir"));
 | 
						|
}
 | 
						|
 | 
						|
static void handle_next(git_path_diriter *diriter, walk_data *walk)
 | 
						|
{
 | 
						|
	const char *fullpath, *filename;
 | 
						|
	size_t fullpath_len, filename_len;
 | 
						|
 | 
						|
	cl_git_pass(git_path_diriter_fullpath(&fullpath, &fullpath_len, diriter));
 | 
						|
	cl_git_pass(git_path_diriter_filename(&filename, &filename_len, diriter));
 | 
						|
 | 
						|
	cl_assert_equal_strn(fullpath, "sub/", 4);
 | 
						|
	cl_assert_equal_s(fullpath+4, filename);
 | 
						|
 | 
						|
	update_count(walk->names, fullpath);
 | 
						|
}
 | 
						|
 | 
						|
/* test directory iterator */
 | 
						|
void test_core_dirent__diriter_with_fullname(void)
 | 
						|
{
 | 
						|
	git_path_diriter diriter = GIT_PATH_DIRITER_INIT;
 | 
						|
	int error;
 | 
						|
 | 
						|
	cl_set_cleanup(&dirent_cleanup__cb, &sub);
 | 
						|
	setup(&sub);
 | 
						|
 | 
						|
	cl_git_pass(git_path_diriter_init(&diriter, sub.path.ptr, 0));
 | 
						|
 | 
						|
	while ((error = git_path_diriter_next(&diriter)) == 0)
 | 
						|
		handle_next(&diriter, &sub);
 | 
						|
 | 
						|
	cl_assert_equal_i(error, GIT_ITEROVER);
 | 
						|
 | 
						|
	git_path_diriter_free(&diriter);
 | 
						|
 | 
						|
	check_counts(&sub);
 | 
						|
}
 | 
						|
 | 
						|
void test_core_dirent__diriter_at_directory_root(void)
 | 
						|
{
 | 
						|
	git_path_diriter diriter = GIT_PATH_DIRITER_INIT;
 | 
						|
	const char *sandbox_path, *path;
 | 
						|
	char *root_path;
 | 
						|
	size_t path_len;
 | 
						|
	int root_offset, error;
 | 
						|
 | 
						|
	sandbox_path = clar_sandbox_path();
 | 
						|
	cl_assert((root_offset = git_path_root(sandbox_path)) >= 0);
 | 
						|
 | 
						|
	cl_assert(root_path = git__calloc(1, root_offset + 2));
 | 
						|
	strncpy(root_path, sandbox_path, root_offset + 1);
 | 
						|
 | 
						|
	cl_git_pass(git_path_diriter_init(&diriter, root_path, 0));
 | 
						|
 | 
						|
	while ((error = git_path_diriter_next(&diriter)) == 0) {
 | 
						|
		cl_git_pass(git_path_diriter_fullpath(&path, &path_len, &diriter));
 | 
						|
 | 
						|
		cl_assert(path_len > (size_t)(root_offset + 1));
 | 
						|
		cl_assert(path[root_offset+1] != '/');
 | 
						|
	}
 | 
						|
 | 
						|
	cl_assert_equal_i(error, GIT_ITEROVER);
 | 
						|
 | 
						|
	git_path_diriter_free(&diriter);
 | 
						|
	git__free(root_path);
 | 
						|
}
 |