Commit ea790f33 by Andreas Ericsson Committed by Shawn O. Pearce

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>
parent 4188d28f
......@@ -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;
}
......@@ -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;
......
#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__ */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment