POSIX functions ftw(3) and nftw(3) do not allow passing an opaque
pointer to the callback they call, so it forces the use of statically
allocated data.

ctfw (from "custom ftw") is a custom implementation that solves this,
while also removing unneeded stuff.

This function will be used by future commits.
This commit is contained in:
Xavier Del Campo Romero 2023-03-06 05:04:26 +01:00
parent 3e95727e27
commit 804b8841f3
Signed by: xavi
GPG Key ID: 84FF3612A9BF43F2
4 changed files with 74 additions and 0 deletions

View File

@ -3,6 +3,7 @@ project(slcl)
add_executable(${PROJECT_NAME}
auth.c
base64.c
cftw.c
handler.c
html.c
http.c

View File

@ -11,6 +11,7 @@ DEPS = $(OBJECTS:.o=.d)
OBJECTS = \
auth.o \
base64.o \
cftw.o \
handler.o \
html.o \
http.o \

61
cftw.c Normal file
View File

@ -0,0 +1,61 @@
#include "cftw.h"
#include <dynstr.h>
#include <dirent.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
int cftw(const char *const dirpath, int (*const fn)(const char *,
const struct stat *, void *), void *const user)
{
DIR *const d = opendir(dirpath);
struct dirent *de;
if (!d)
{
fprintf(stderr, "%s: opendir(2): %s\n", __func__, strerror(errno));
return -1;
}
while ((de = readdir(d)))
{
const char *const path = de->d_name;
if (!strcmp(path, ".") || !strcmp(path, ".."))
continue;
struct stat sb;
struct dynstr d;
dynstr_init(&d);
if (dynstr_append(&d, "%s/%s", dirpath, path))
{
fprintf(stderr, "%s: dynstr_append failed\n", __func__);
return -1;
}
const int r = stat(d.str, &sb);
int ret = -1;
if (r)
fprintf(stderr, "%s: stat(2) %s: %s\n",
__func__, path, strerror(errno));
else if (S_ISDIR(sb.st_mode))
ret = cftw(d.str, fn, user);
else if (S_ISREG(sb.st_mode))
ret = fn(d.str, &sb, user);
else
fprintf(stderr, "%s: unexpected st_mode %ju\n",
__func__, (uintmax_t)sb.st_mode);
dynstr_free(&d);
if (ret)
return ret;
}
return 0;
}

11
cftw.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef CFTW_H
#define CFTW_H
#include <sys/stat.h>
/* Thread-safe variant of ftw(3) and nftw(3) that allows passing an
* opaque pointer and removes some unneeded parameters. */
int cftw(const char *dirpath, int (*fn)(const char *fpath,
const struct stat *sb, void *user), void *user);
#endif /* CFTW_H */