diff options
author | Andreas Ericsson <ae@op5.se> | 2008-11-29 15:34:20 +0100 |
---|---|---|
committer | Shawn O. Pearce <spearce@spearce.org> | 2008-12-02 09:18:19 -0800 |
commit | ea790f337b0e401f5e4acabf9af9c2bc756d5f3b (patch) | |
tree | 8ec389978cc56e25a6a5bdf6be993c7664e762b5 | |
parent | 4188d28f1c38240392d896fc79561cc461fb12c0 (diff) | |
download | libgit2-ea790f337b0e401f5e4acabf9af9c2bc756d5f3b.tar.gz |
Add a dirent walker to the fileops API
Since at least MS have something like GetFirstDirEnt() and
GetNextDirEnt() (presumably with superior performance), we
can let MS hackers add support for a dirent walker using
that API instead, while we stick with the posix-style
readdir() calls.
Signed-off-by: Andreas Ericsson <ae@op5.se>
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
-rw-r--r-- | src/fileops.c | 62 | ||||
-rw-r--r-- | src/fileops.h | 2 | ||||
-rw-r--r-- | src/git/fileops.h | 32 |
3 files changed, 96 insertions, 0 deletions
diff --git a/src/fileops.c b/src/fileops.c index 62da145b9..0e6e7fdcb 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -134,3 +134,65 @@ 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) +{ + char path[PATH_MAX]; + size_t wd_len; + DIR *dir; + struct dirent *de; + + if (!wd) + 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); + if (!dir) + return GIT_ERROR; + + while ((de = readdir(dir))) { + size_t de_len; + int result; + + /* always skip '.' and '..' */ + if (de->d_name[0] == '.') { + if (de->d_name[1] == '\0') + continue; + if (de->d_name[1] == '.' && de->d_name[2] == '\0') + continue; + } + + de_len = strlen(de->d_name); + if (sizeof(path) < wd_len + de_len + 1) { + closedir(dir); + return GIT_ERROR; + } + + strcpy(path + wd_len, de->d_name); + result = fn(arg, path); + if (result < 0) { + closedir(dir); + return result; + } + if (result > 0) { + closedir(dir); + return result; + } + } + + closedir(dir); + return GIT_SUCCESS; +} diff --git a/src/fileops.h b/src/fileops.h index 56d0888fe..2683a6b43 100644 --- a/src/fileops.h +++ b/src/fileops.h @@ -17,7 +17,9 @@ #include <time.h> #include <stdlib.h> #include <string.h> +#include <dirent.h> #include "errors.h" +#include "git/fileops.h" typedef int git_file; typedef struct stat gitfo_statbuf; diff --git a/src/git/fileops.h b/src/git/fileops.h new file mode 100644 index 000000000..856017fbf --- /dev/null +++ b/src/git/fileops.h @@ -0,0 +1,32 @@ +#ifndef INCLUDE_git_fileops_h__ +#define INCLUDE_git_fileops_h__ + +/** + * @file git/fileops.h + * @brief Git platform agnostic filesystem operations + * @defgroup Git gitfiles + * @ingroup Git + * @{ + */ + +#include "common.h" +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__ */ |