dirent.c 4.06 KB
Newer Older
1
#include "clar_libgit2.h"
Vicent Marti committed
2 3 4
#include "fileops.h"

typedef struct name_data {
Vicent Marti committed
5 6
	int count; /* return count */
	char *name; /* filename		*/
Vicent Marti committed
7 8 9
} name_data;

typedef struct walk_data {
Vicent Marti committed
10 11
	char *sub;		/* sub-directory name */
	name_data *names; /* name state data	*/
12
	git_buf path;
Vicent Marti committed
13 14 15 16 17 18 19 20 21 22
} walk_data;


static char *top_dir = "dir-walk";
static walk_data *state_loc;

static void setup(walk_data *d)
{
	name_data *n;

23
	cl_must_pass(p_mkdir(top_dir, 0777));
Vicent Marti committed
24 25 26 27

	cl_must_pass(p_chdir(top_dir));

	if (strcmp(d->sub, ".") != 0)
28
		cl_must_pass(p_mkdir(d->sub, 0777));
Vicent Marti committed
29

30 31
	cl_git_pass(git_buf_sets(&d->path, d->sub));

Vicent Marti committed
32 33 34
	state_loc = d;

	for (n = d->names; n->name; n++) {
35
		git_file fd = p_creat(n->name, 0666);
Vicent Marti committed
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
		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));
57 58

	git_buf_free(&d->path);
Vicent Marti committed
59 60 61 62 63 64 65 66 67 68 69
}

static void check_counts(walk_data *d)
{
	name_data *n;

	for (n = d->names; n->name; n++) {
		cl_assert(n->count == 1);
	}
}

70
static int one_entry(void *state, git_buf *path)
Vicent Marti committed
71 72 73 74 75 76 77
{
	walk_data *d = (walk_data *) state;
	name_data *n;

	if (state != state_loc)
		return GIT_ERROR;

78
	if (path != &d->path)
Vicent Marti committed
79 80 81
		return GIT_ERROR;

	for (n = d->names; n->name; n++) {
82
		if (!strcmp(n->name, path->ptr)) {
Vicent Marti committed
83 84 85 86 87 88 89 90
			n->count++;
			return 0;
		}
	}

	return GIT_ERROR;
}

91
static int dont_call_me(void *state, git_buf *path)
Vicent Marti committed
92
{
93 94
	GIT_UNUSED(state);
	GIT_UNUSED(path);
Vicent Marti committed
95 96 97 98 99 100 101 102 103 104 105 106 107
	return GIT_ERROR;
}



static name_data dot_names[] = {
	{ 0, "./a" },
	{ 0, "./asdf" },
	{ 0, "./pack-foo.pack" },
	{ 0, NULL }
};
static walk_data dot = {
	".",
108 109
	dot_names,
	GIT_BUF_INIT
Vicent Marti committed
110 111 112 113 114 115 116 117
};

/* 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);

118
	cl_git_pass(git_path_direach(&dot.path,
Vicent Marti committed
119 120
					one_entry,
					&dot));
Vicent Marti committed
121 122 123 124 125 126 127 128 129 130 131 132 133

	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",
134 135
	sub_names,
	GIT_BUF_INIT
Vicent Marti committed
136 137 138 139 140 141 142 143
};

/* traverse a subfolder */
void test_core_dirent__traverse_subfolder(void)
{
	cl_set_cleanup(&dirent_cleanup__cb, &sub);
	setup(&sub);

144
	cl_git_pass(git_path_direach(&sub.path,
Vicent Marti committed
145 146
					one_entry,
					&sub));
Vicent Marti committed
147 148 149 150 151 152 153

	check_counts(&sub);
}


static walk_data sub_slash = {
	"sub/",
154 155
	sub_names,
	GIT_BUF_INIT
Vicent Marti committed
156 157 158 159 160 161 162 163
};

/* 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);

164
	cl_git_pass(git_path_direach(&sub_slash.path,
Vicent Marti committed
165 166
					one_entry,
					&sub_slash));
Vicent Marti committed
167 168 169 170 171 172 173 174 175 176

	check_counts(&sub_slash);
}


static name_data empty_names[] = {
	{ 0, NULL }
};
static walk_data empty = {
	"empty",
177 178
	empty_names,
	GIT_BUF_INIT
Vicent Marti committed
179 180 181 182 183 184 185 186
};

/* 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);

187
	cl_git_pass(git_path_direach(&empty.path,
Vicent Marti committed
188 189
					one_entry,
					&empty));
Vicent Marti committed
190 191 192 193

	check_counts(&empty);

	/* make sure callback not called */
194
	cl_git_pass(git_path_direach(&empty.path,
Vicent Marti committed
195 196
					dont_call_me,
					&empty));
Vicent Marti committed
197 198 199 200 201 202 203
}

static name_data odd_names[] = {
	{ 0, "odd/.a" },
	{ 0, "odd/..c" },
	/* the following don't work on cygwin/win32 */
	/* { 0, "odd/.b." }, */
Vicent Marti committed
204
	/* { 0, "odd/..d.." }, */
Vicent Marti committed
205 206 207 208
	{ 0, NULL }
};
static walk_data odd = {
	"odd",
209 210
	odd_names,
	GIT_BUF_INIT
Vicent Marti committed
211 212 213 214 215 216 217 218
};

/* 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);

219
	cl_git_pass(git_path_direach(&odd.path,
Vicent Marti committed
220 221
					one_entry,
					&odd));
Vicent Marti committed
222 223 224

	check_counts(&odd);
}
225 226 227 228 229 230 231 232 233 234 235

/* 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);
}