diff --git a/src/fileops.c b/src/fileops.c index 1dd35dc8e..0867c7b57 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -187,31 +187,25 @@ int gitfo_close_cached(gitfo_cache *ioc) return gitfo_close(fd); } -/** - * Walk a directory and run 'fn' for each encountered entry - * (except '.' and '..'). - */ -int git_foreach_dirent(const char *wd, int (*fn)(void *, const char *), void *arg) +int gitfo_dirent( + char *path, + size_t path_sz, + int (*fn)(void *, char *), + void *arg) { - char path[GIT_PATH_MAX]; - size_t wd_len; + size_t wd_len = strlen(path); DIR *dir; struct dirent *de; - if (!wd) + if (!wd_len || path_sz < wd_len + 2) return GIT_ERROR; - wd_len = strlen(wd); - if (!wd_len || sizeof(path) < wd_len + 2) - return GIT_ERROR; - - strcpy(path, wd); while (path[wd_len - 1] == '/') wd_len--; path[wd_len++] = '/'; path[wd_len] = '\0'; - dir = opendir(wd); + dir = opendir(path); if (!dir) return git_os_error(); @@ -228,7 +222,7 @@ int git_foreach_dirent(const char *wd, int (*fn)(void *, const char *), void *ar } de_len = strlen(de->d_name); - if (sizeof(path) < wd_len + de_len + 1) { + if (path_sz < wd_len + de_len + 1) { closedir(dir); return GIT_ERROR; } diff --git a/src/fileops.h b/src/fileops.h index 336ab27f4..86726c5a8 100644 --- a/src/fileops.h +++ b/src/fileops.h @@ -9,6 +9,7 @@ /** Force 64 bit off_t size on POSIX. */ #define _FILE_OFFSET_BITS 64 +#include "common.h" #include #include #include @@ -18,8 +19,6 @@ #include #include #include -#include "errors.h" -#include "git/fileops.h" #define GITFO_BUF_INIT {NULL, 0} @@ -43,6 +42,23 @@ extern off_t gitfo_size(git_file fd); extern int gitfo_read_file(gitfo_buf *obj, const char *path); extern void gitfo_free_buf(gitfo_buf *obj); +/** + * Walk each directory entry, except '.' and '..', calling fn(state). + * + * @param pathbuf buffer the function reads the initial directory + * path from, and updates with each successive entry's name. + * @param pathmax maximum allocation of pathbuf. + * @param fn function to invoke with each entry. The first arg is + * the input state and the second arg is pathbuf. The function + * may modify the pathbuf, but only by appending new text. + * @param state to pass to fn as the first arg. + */ +extern int gitfo_dirent( + char *pathbuf, + size_t pathmax, + int (*fn)(void *, char *), + void *state); + extern gitfo_cache *gitfo_enable_caching(git_file fd, size_t cache_size); extern int gitfo_write_cached(gitfo_cache *ioc, void *buf, size_t len); extern int gitfo_flush_cached(gitfo_cache *ioc); diff --git a/src/git/fileops.h b/src/git/fileops.h deleted file mode 100644 index 657cec148..000000000 --- a/src/git/fileops.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef INCLUDE_git_fileops_h__ -#define INCLUDE_git_fileops_h__ - -#include "common.h" - -/** - * @file git/fileops.h - * @brief Git platform agnostic filesystem operations - * @defgroup git_fileops Git filesystem operations - * @ingroup Git - * @{ - */ -GIT_BEGIN_DECL - -/** - * For each directory entry (except "." and ".."), run the function - * "fn", passing it "arg" as its first argument and the path to - * the entry as the second argument. - * @param dir The directory to walk - * @param fn The callback function to run for each entry in *dir. - * "fn" may return >0 to signal "I'm done. Stop parsing and - * return successfully" or <0 to signal an error. All non-zero - * return codes cause directory traversal to stop. - * @param arg The first argument that will be passed to 'fn' - * @return GIT_SUCCESS if all entries were successfully traversed, - * otherwise the result of fn. - */ -GIT_EXTERN(int) git_foreach_dirent(const char *dir, - int (*fn)(void *, const char *), void *arg); - -/** @} */ -GIT_END_DECL -#endif /* INCLUDE_git_fileops_h__ */ diff --git a/tests/t0020-dirent.c b/tests/t0020-dirent.c new file mode 100644 index 000000000..4c6545319 --- /dev/null +++ b/tests/t0020-dirent.c @@ -0,0 +1,48 @@ +#include "test_lib.h" +#include "fileops.h" + +static char path_buffer[GIT_PATH_MAX]; +static int state_loc; +static const char* names[] = { + "./a", + "./asdf", + "./pack-foo.pack", + NULL +}; + +static int one_entry(void *state, char *path) +{ + const char **c; + + must_be_true(state == &state_loc); + must_be_true(path == path_buffer); + for (c = names; *c; c++) { + if (!strcmp(*c, path)) { + *c = ""; + return 0; + } + } + test_die("unexpected path \"%s\"", path); +} + +BEGIN_TEST(setup) + const char **c; + for (c = names; *c; c++) { + git_file fd = gitfo_creat(*c, 0600); + must_be_true(fd >= 0); + gitfo_close(fd); + } +END_TEST + +BEGIN_TEST(direent_walk) + const char **c; + + strcpy(path_buffer, "."); + must_pass(gitfo_dirent(path_buffer, + sizeof(path_buffer), + one_entry, + &state_loc)); + + for (c = names; *c; c++) + must_pass(strcmp("", *c)); +END_TEST