| #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 one_entry(void *state, git_buf *path) |
| { |
| walk_data *d = (walk_data *) state; |
| name_data *n; |
| |
| if (state != state_loc) |
| return GIT_ERROR; |
| |
| if (path != &d->path) |
| return GIT_ERROR; |
| |
| for (n = d->names; n->name; n++) { |
| if (!strcmp(n->name, path->ptr)) { |
| n->count++; |
| return 0; |
| } |
| } |
| |
| return GIT_ERROR; |
| } |
| |
| static int dont_call_me(void *state, git_buf *path) |
| { |
| GIT_UNUSED(state); |
| GIT_UNUSED(path); |
| return GIT_ERROR; |
| } |
| |
| |
| |
| 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, |
| 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, |
| 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, |
| 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, |
| one_entry, |
| &empty)); |
| |
| check_counts(&empty); |
| |
| /* make sure callback not called */ |
| cl_git_pass(git_path_direach(&empty.path, |
| dont_call_me, |
| &empty)); |
| } |
| |
| 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, |
| 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); |
| } |