aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Del Campo Romero <xavi92@disroot.org>2025-10-06 16:19:16 +0200
committerXavier Del Campo Romero <xavi92@disroot.org>2025-10-06 16:28:59 +0200
commit3e939dde0ad07d1ecbb9bed2123fff6d2d92dcab (patch)
treebcd8a7c8462813d4c0ecff2373bfcc02302af84c
parentcf10ad5c11764ae83b00ac8c57fa4985045daadb (diff)
cftw.c: Call user function at the end for directories
The older, synchronous implementation for cftw recursed as long as there were children directories and, finally, it called the user function. This commit therefore fixes the newer, asynchronous implementation to honor that behaviour. Otherwise, rmdir_r would fail because rmdir(2) would be called for non-empty directories.
-rw-r--r--cftw.c36
1 files changed, 24 insertions, 12 deletions
diff --git a/cftw.c b/cftw.c
index f512232..5083cc4 100644
--- a/cftw.c
+++ b/cftw.c
@@ -101,11 +101,14 @@ failure:
return NULL;
}
-static enum cftw_state run(struct cftw *const c, struct cftw_entry *const e)
+static enum cftw_state run(struct cftw *const c, struct cftw_entry *const e,
+ struct cftw_entry *const root)
{
- int error;
+ int error = 0;
struct dirent *de;
struct dynstr d;
+ const char *const dirpath = e->dirpath;
+ struct stat sb;
dynstr_init(&d);
errno = 0;
@@ -117,15 +120,25 @@ static enum cftw_state run(struct cftw *const c, struct cftw_entry *const e)
goto failure;
}
else if (!de)
- return CFTW_OK;
+ {
+ if (e == root)
+ return CFTW_OK;
+ else if (stat(dirpath, &sb))
+ {
+ fprintf(stderr, "%s: stat(2) %s: %s\n", __func__, dirpath,
+ strerror(errno));
+ goto failure;
+ }
- const char *const path = de->d_name, *const dirpath = e->dirpath;
+ return c->fn(dirpath, &sb, &c->done, c->user) ? CFTW_FATAL : CFTW_OK;
+ }
+
+ const char *const path = de->d_name;
if (!strcmp(path, ".") || !strcmp(path, ".."))
return CFTW_AGAIN;
const char *const sep = dirpath[strlen(dirpath) - 1] == '/' ? "" : "/";
- struct stat sb;
if (dynstr_append(&d, "%s%s%s", dirpath, sep, path))
{
@@ -145,8 +158,6 @@ static enum cftw_state run(struct cftw *const c, struct cftw_entry *const e)
{
if (!(e->child = entry(d.str)))
goto failure;
-
- error = c->fn(d.str, &sb, &c->done, c->user);
}
else if (S_ISREG(sb.st_mode))
error = c->fn(d.str, &sb, &c->done, c->user);
@@ -171,11 +182,12 @@ failure:
return CFTW_FATAL;
}
-static enum cftw_state step(struct cftw *const c, struct cftw_entry *const e)
+static enum cftw_state step(struct cftw *const c, struct cftw_entry *const e,
+ struct cftw_entry *const root)
{
if (e->child)
{
- switch (step(c, e->child))
+ switch (step(c, e->child, root))
{
case CFTW_AGAIN:
return CFTW_AGAIN;
@@ -195,12 +207,12 @@ static enum cftw_state step(struct cftw *const c, struct cftw_entry *const e)
return CFTW_AGAIN;
}
- return run(c, e);
+ return run(c, e, root);
}
-enum cftw_state cftw_step(struct cftw *c)
+enum cftw_state cftw_step(struct cftw *const c)
{
- return step(c, c->root);
+ return step(c, c->root, c->root);
}
struct cftw *cftw(const char *const dirpath, int (*const fn)(const char *,