Re: [PATCH v2 4/8] dir: add generic "walk all files" helper
- From
Elijah Newren <newren@gmail.com>
- Date
- Aug 5, 2025, 22:22 UTC
- Message-ID
- <CABPp-BEEr=pcF4ySreK4MeVUZ-L+HeCCKbZ=a0R+AkAVCqgFJw@mail.gmail.com>
- In-Reply-To
- <fd9a20a392265a5aaed27301a3b324164bb0af86.1752716054.git.gitgitgadget@gmail.com>
On Wed, Jul 16, 2025 at 6:34 PM Derrick Stolee via GitGitGadget <gitgitgadget@gmail.com> wrote:
Show 91 quoted lines
>
> From: Derrick Stolee <stolee@gmail.com>
>
> 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>
> ---
> dir.c | 28 ++++++++++++++++++++++++++++
> dir.h | 14 ++++++++++++++
> 2 files changed, 42 insertions(+)
>
> diff --git a/dir.c b/dir.c
> index d2b0a5aef670..2e567ff92746 100644
> --- a/dir.c
> +++ b/dir.c
> @@ -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;
> diff --git a/dir.h b/dir.h
> index d7e71aa8daa7..f4235cc12a2f 100644
> --- a/dir.h
> +++ b/dir.h
> @@ -536,6 +536,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
> --
> gitgitgadgetLooks reasonable.