aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Del Campo Romero <xavi.dcr@tutanota.com>2023-03-06 05:04:26 +0100
committerXavier Del Campo Romero <xavi.dcr@tutanota.com>2023-03-06 05:06:30 +0100
commit804b8841f3fe59f7058c91fa25c1694f4433642a (patch)
tree1222273bfcbc1321095f0688837176d2fa0d46ad
parent3e95727e275f650d2c6703aa8753b1c72d366d40 (diff)
downloadslcl-804b8841f3fe59f7058c91fa25c1694f4433642a.tar.gz
Add cftw
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.
-rw-r--r--CMakeLists.txt1
-rw-r--r--Makefile1
-rw-r--r--cftw.c61
-rw-r--r--cftw.h11
4 files changed, 74 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f233ede..de2c9ac 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,6 +3,7 @@ project(slcl)
add_executable(${PROJECT_NAME}
auth.c
base64.c
+ cftw.c
handler.c
html.c
http.c
diff --git a/Makefile b/Makefile
index 7001c0b..e29c8ac 100644
--- a/Makefile
+++ b/Makefile
@@ -11,6 +11,7 @@ DEPS = $(OBJECTS:.o=.d)
OBJECTS = \
auth.o \
base64.o \
+ cftw.o \
handler.o \
html.o \
http.o \
diff --git a/cftw.c b/cftw.c
new file mode 100644
index 0000000..921a12e
--- /dev/null
+++ b/cftw.c
@@ -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;
+}
diff --git a/cftw.h b/cftw.h
new file mode 100644
index 0000000..612451e
--- /dev/null
+++ b/cftw.h
@@ -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 */