diff options
Diffstat (limited to 'src')
| -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__ */  | 
