diff options
| author | Derrick Stolee <stolee@gmail.com> | 2025-09-12 10:30:08 +0000 |
|---|---|---|
| committer | Junio C Hamano <gitster@pobox.com> | 2025-09-12 08:59:52 -0700 |
| commit | 1588e836bb956d14e6cb38e35933ed2749c023b4 (patch) | |
| tree | 4da578844afe9c2fd369aaf6db0cdbc56f933108 | |
| parent | sparse-checkout: match some 'clean' behavior (diff) | |
| download | git-1588e836bb956d14e6cb38e35933ed2749c023b4.tar.gz git-1588e836bb956d14e6cb38e35933ed2749c023b4.zip | |
dir: add generic "walk all files" helper
There is sometimes a need to visit every file within a directory,
recursively. The main example is remove_dir_recursively(), though it has
some extra flags that make it want to iterate over paths in a custom
way. There is also the fill_directory() approach but that involves an
index and a pathspec.
This change adds a new for_each_file_in_dir() method that will be
helpful in the next change.
Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
| -rw-r--r-- | dir.c | 28 | ||||
| -rw-r--r-- | dir.h | 14 |
2 files changed, 42 insertions, 0 deletions
@@ -30,6 +30,7 @@ #include "read-cache-ll.h" #include "setup.h" #include "sparse-index.h" +#include "strbuf.h" #include "submodule-config.h" #include "symlinks.h" #include "trace2.h" @@ -87,6 +88,33 @@ struct dirent *readdir_skip_dot_and_dotdot(DIR *dirp) return e; } +int for_each_file_in_dir(struct strbuf *path, file_iterator fn, const void *data) +{ + struct dirent *e; + int res = 0; + size_t baselen = path->len; + DIR *dir = opendir(path->buf); + + if (!dir) + return 0; + + while (!res && (e = readdir_skip_dot_and_dotdot(dir)) != NULL) { + unsigned char dtype = get_dtype(e, path, 0); + strbuf_setlen(path, baselen); + strbuf_addstr(path, e->d_name); + + if (dtype == DT_REG) { + res = fn(path->buf, data); + } else if (dtype == DT_DIR) { + strbuf_addch(path, '/'); + res = for_each_file_in_dir(path, fn, data); + } + } + + closedir(dir); + return res; +} + int count_slashes(const char *s) { int cnt = 0; @@ -537,6 +537,20 @@ int get_sparse_checkout_patterns(struct pattern_list *pl); int remove_dir_recursively(struct strbuf *path, int flag); /* + * This function pointer type is called on each file discovered in + * for_each_file_in_dir. The iteration stops if this method returns + * non-zero. + */ +typedef int (*file_iterator)(const char *path, const void *data); + +struct strbuf; +/* + * Given a directory path, recursively visit each file within, including + * within subdirectories. + */ +int for_each_file_in_dir(struct strbuf *path, file_iterator fn, const void *data); + +/* * Tries to remove the path, along with leading empty directories so long as * those empty directories are not startup_info->original_cwd. Ignores * ENOENT. |
