diff options
| author | Xavier Del Campo Romero <xavi92@disroot.org> | 2025-10-06 16:19:16 +0200 |
|---|---|---|
| committer | Xavier Del Campo Romero <xavi92@disroot.org> | 2025-10-06 16:28:59 +0200 |
| commit | 3e939dde0ad07d1ecbb9bed2123fff6d2d92dcab (patch) | |
| tree | bcd8a7c8462813d4c0ecff2373bfcc02302af84c | |
| parent | cf10ad5c11764ae83b00ac8c57fa4985045daadb (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.c | 36 |
1 files changed, 24 insertions, 12 deletions
@@ -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 *, |
