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

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_str 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
	cl_git_pass(git_str_sets(&d->path, d->sub));
31

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_str_dispose(&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 71 72 73 74 75 76 77 78 79 80 81 82 83
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;
}

84
static int one_entry(void *state, git_str *path)
Vicent Marti committed
85 86 87 88 89 90
{
	walk_data *d = (walk_data *) state;

	if (state != state_loc)
		return GIT_ERROR;

91
	if (path != &d->path)
Vicent Marti committed
92 93
		return GIT_ERROR;

94
	return update_count(d->names, path->ptr);
Vicent Marti committed
95 96 97 98 99 100 101 102 103 104 105
}


static name_data dot_names[] = {
	{ 0, "./a" },
	{ 0, "./asdf" },
	{ 0, "./pack-foo.pack" },
	{ 0, NULL }
};
static walk_data dot = {
	".",
106
	dot_names,
107
	GIT_STR_INIT
Vicent Marti committed
108 109 110
};

/* make sure that the '.' folder is not traversed */
111
void test_dirent__dont_traverse_dot(void)
Vicent Marti committed
112 113 114 115
{
	cl_set_cleanup(&dirent_cleanup__cb, &dot);
	setup(&dot);

116
	cl_git_pass(git_fs_path_direach(&dot.path, 0, one_entry, &dot));
Vicent Marti committed
117 118 119 120 121 122 123 124 125 126 127 128 129

	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",
130
	sub_names,
131
	GIT_STR_INIT
Vicent Marti committed
132 133 134
};

/* traverse a subfolder */
135
void test_dirent__traverse_subfolder(void)
Vicent Marti committed
136 137 138 139
{
	cl_set_cleanup(&dirent_cleanup__cb, &sub);
	setup(&sub);

140
	cl_git_pass(git_fs_path_direach(&sub.path, 0, one_entry, &sub));
Vicent Marti committed
141 142 143 144 145 146 147

	check_counts(&sub);
}


static walk_data sub_slash = {
	"sub/",
148
	sub_names,
149
	GIT_STR_INIT
Vicent Marti committed
150 151 152
};

/* traverse a slash-terminated subfolder */
153
void test_dirent__traverse_slash_terminated_folder(void)
Vicent Marti committed
154 155 156 157
{
	cl_set_cleanup(&dirent_cleanup__cb, &sub_slash);
	setup(&sub_slash);

158
	cl_git_pass(git_fs_path_direach(&sub_slash.path, 0, one_entry, &sub_slash));
Vicent Marti committed
159 160 161 162 163 164 165 166 167 168

	check_counts(&sub_slash);
}


static name_data empty_names[] = {
	{ 0, NULL }
};
static walk_data empty = {
	"empty",
169
	empty_names,
170
	GIT_STR_INIT
Vicent Marti committed
171 172 173
};

/* make sure that empty folders are not traversed */
174
void test_dirent__dont_traverse_empty_folders(void)
Vicent Marti committed
175 176 177 178
{
	cl_set_cleanup(&dirent_cleanup__cb, &empty);
	setup(&empty);

179
	cl_git_pass(git_fs_path_direach(&empty.path, 0, one_entry, &empty));
Vicent Marti committed
180 181 182 183

	check_counts(&empty);

	/* make sure callback not called */
184
	cl_assert(git_fs_path_is_empty_dir(empty.path.ptr));
Vicent Marti committed
185 186 187 188 189 190 191
}

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
192
	/* { 0, "odd/..d.." }, */
Vicent Marti committed
193 194 195 196
	{ 0, NULL }
};
static walk_data odd = {
	"odd",
197
	odd_names,
198
	GIT_STR_INIT
Vicent Marti committed
199 200 201
};

/* make sure that strange looking filenames ('..c') are traversed */
202
void test_dirent__traverse_weird_filenames(void)
Vicent Marti committed
203 204 205 206
{
	cl_set_cleanup(&dirent_cleanup__cb, &odd);
	setup(&odd);

207
	cl_git_pass(git_fs_path_direach(&odd.path, 0, one_entry, &odd));
Vicent Marti committed
208 209 210

	check_counts(&odd);
}
211 212

/* test filename length limits */
213
void test_dirent__length_limits(void)
214 215 216 217 218 219
{
	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));
220

221 222
	git__free(big_filename);
}
223

224
void test_dirent__empty_dir(void)
225 226
{
	cl_must_pass(p_mkdir("empty_dir", 0777));
227
	cl_assert(git_fs_path_is_empty_dir("empty_dir"));
228 229

	cl_git_mkfile("empty_dir/content", "whatever\n");
230 231
	cl_assert(!git_fs_path_is_empty_dir("empty_dir"));
	cl_assert(!git_fs_path_is_empty_dir("empty_dir/content"));
232 233 234 235

	cl_must_pass(p_unlink("empty_dir/content"));

	cl_must_pass(p_mkdir("empty_dir/content", 0777));
236 237
	cl_assert(!git_fs_path_is_empty_dir("empty_dir"));
	cl_assert(git_fs_path_is_empty_dir("empty_dir/content"));
238 239 240 241 242

	cl_must_pass(p_rmdir("empty_dir/content"));

	cl_must_pass(p_rmdir("empty_dir"));
}
243

244
static void handle_next(git_fs_path_diriter *diriter, walk_data *walk)
245 246 247 248
{
	const char *fullpath, *filename;
	size_t fullpath_len, filename_len;

249 250
	cl_git_pass(git_fs_path_diriter_fullpath(&fullpath, &fullpath_len, diriter));
	cl_git_pass(git_fs_path_diriter_filename(&filename, &filename_len, diriter));
251 252 253 254 255 256 257 258

	cl_assert_equal_strn(fullpath, "sub/", 4);
	cl_assert_equal_s(fullpath+4, filename);

	update_count(walk->names, fullpath);
}

/* test directory iterator */
259
void test_dirent__diriter_with_fullname(void)
260
{
261
	git_fs_path_diriter diriter = GIT_FS_PATH_DIRITER_INIT;
262 263 264 265 266
	int error;

	cl_set_cleanup(&dirent_cleanup__cb, &sub);
	setup(&sub);

267
	cl_git_pass(git_fs_path_diriter_init(&diriter, sub.path.ptr, 0));
268

269
	while ((error = git_fs_path_diriter_next(&diriter)) == 0)
270 271 272 273
		handle_next(&diriter, &sub);

	cl_assert_equal_i(error, GIT_ITEROVER);

274
	git_fs_path_diriter_free(&diriter);
275 276 277

	check_counts(&sub);
}
278

279
void test_dirent__diriter_at_directory_root(void)
280
{
281
	git_fs_path_diriter diriter = GIT_FS_PATH_DIRITER_INIT;
282 283 284 285 286 287
	const char *sandbox_path, *path;
	char *root_path;
	size_t path_len;
	int root_offset, error;

	sandbox_path = clar_sandbox_path();
288
	cl_assert((root_offset = git_fs_path_root(sandbox_path)) >= 0);
289 290 291 292

	cl_assert(root_path = git__calloc(1, root_offset + 2));
	strncpy(root_path, sandbox_path, root_offset + 1);

293
	cl_git_pass(git_fs_path_diriter_init(&diriter, root_path, 0));
294

295 296
	while ((error = git_fs_path_diriter_next(&diriter)) == 0) {
		cl_git_pass(git_fs_path_diriter_fullpath(&path, &path_len, &diriter));
297 298 299 300 301 302 303

		cl_assert(path_len > (size_t)(root_offset + 1));
		cl_assert(path[root_offset+1] != '/');
	}

	cl_assert_equal_i(error, GIT_ITEROVER);

304
	git_fs_path_diriter_free(&diriter);
305 306
	git__free(root_path);
}