jobcore/ppp/ppp-utils-mkdir.patch

287 lines
6.2 KiB
Diff

From b0e7307b3569a5dad0f2606d2736cc8317851598 Mon Sep 17 00:00:00 2001
From: Dominique Martinet <dominique.martinet@atmark-techno.com>
Date: Wed, 30 Aug 2023 11:46:01 +0900
Subject: [PATCH] utils: add mkdir_recursive
This will be used in the next commit.
A test file for utils has also been added to check mkdir works as
intended.
Signed-off-by: Dominique Martinet <dominique.martinet@atmark-techno.com>
---
pppd/Makefile.am | 6 ++
pppd/pppd-private.h | 1 +
pppd/utils.c | 82 ++++++++++++++++++++++++++
pppd/utils_utest.c | 139 ++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 228 insertions(+)
create mode 100644 pppd/utils_utest.c
diff --git a/pppd/Makefile.am b/pppd/Makefile.am
index 7cb300533..c5fe10776 100644
--- a/pppd/Makefile.am
+++ b/pppd/Makefile.am
@@ -20,6 +20,12 @@ utest_pppcrypt_LDFLAGS =
check_PROGRAMS += utest_crypto
+utest_utils_SOURCES = utils.c utils_utest.c
+utest_utils_CPPFLAGS = -DUNIT_TEST
+utest_utils_LDFLAGS =
+
+check_PROGRAMS += utest_utils
+
if WITH_SRP
sbin_PROGRAMS += srp-entry
dist_man8_MANS += srp-entry.8
diff --git a/pppd/pppd-private.h b/pppd/pppd-private.h
index 2883e4622..46ce0c8bd 100644
--- a/pppd/pppd-private.h
+++ b/pppd/pppd-private.h
@@ -437,6 +437,7 @@ int sifproxyarp(int, u_int32_t);
int cifproxyarp(int, u_int32_t);
/* Delete proxy ARP entry for peer */
u_int32_t GetMask(u_int32_t); /* Get appropriate netmask for address */
+int mkdir_recursive(const char *); /* Recursively create directory */
int lock(char *); /* Create lock file for device */
int relock(int); /* Rewrite lock file with new pid */
void unlock(void); /* Delete previously-created lock file */
diff --git a/pppd/utils.c b/pppd/utils.c
index c1bdbbbfe..c47192e67 100644
--- a/pppd/utils.c
+++ b/pppd/utils.c
@@ -781,6 +781,88 @@ complete_read(int fd, void *buf, size_t count)
}
#endif
+/*
+ * mkdir_check - helper for mkdir_recursive, creates a directory
+ * but do not error on EEXIST if and only if entry is a directory
+ * The caller must check for errno == ENOENT if appropriate.
+ */
+static int
+mkdir_check(const char *path)
+{
+ struct stat statbuf;
+
+ if (mkdir(path, 0755) >= 0)
+ return 0;
+
+ if (errno == EEXIST) {
+ if (stat(path, &statbuf) < 0)
+ /* got raced? */
+ return -1;
+
+ if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
+ return 0;
+
+ /* already exists but not a dir, treat as failure */
+ errno = EEXIST;
+ return -1;
+ }
+
+ return -1;
+}
+
+/*
+ * mkdir_parent - helper for mkdir_recursive, modifies the string in place
+ * Assumes mkdir(path) already failed, so it first creates the parent then
+ * full path again.
+ */
+static int
+mkdir_parent(char *path)
+{
+ char *slash;
+ int rc;
+
+ slash = strrchr(path, '/');
+ if (!slash)
+ return -1;
+
+ *slash = 0;
+ if (mkdir_check(path) < 0) {
+ if (errno != ENOENT) {
+ *slash = '/';
+ return -1;
+ }
+ if (mkdir_parent(path) < 0) {
+ *slash = '/';
+ return -1;
+ }
+ }
+ *slash = '/';
+
+ return mkdir_check(path);
+}
+
+/*
+ * mkdir_recursive - recursively create directory if it didn't exist
+ */
+int
+mkdir_recursive(const char *path)
+{
+ char *copy;
+ int rc;
+
+ // optimistically try on full path first to avoid allocation
+ if (mkdir_check(path) == 0)
+ return 0;
+
+ copy = strdup(path);
+ if (!copy)
+ return -1;
+
+ rc = mkdir_parent(copy);
+ free(copy);
+ return rc;
+}
+
/* Procedures for locking the serial device using a lock file. */
static char lock_file[MAXPATHLEN];
diff --git a/pppd/utils_utest.c b/pppd/utils_utest.c
new file mode 100644
index 000000000..cdca97e6d
--- /dev/null
+++ b/pppd/utils_utest.c
@@ -0,0 +1,139 @@
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "pppd-private.h"
+
+/* globals used in test.c... */
+int debug = 1;
+int error_count;
+int unsuccess;
+
+/* check if path exists and returns its type */
+static int
+file_type(char *path)
+{
+ struct stat statbuf;
+
+ if (stat(path, &statbuf) < 0)
+ return -1;
+
+ return statbuf.st_mode & S_IFMT;
+}
+
+int
+test_simple() {
+ if (mkdir_recursive("dir"))
+ return -1;
+
+ if (file_type("dir") != S_IFDIR)
+ return -1;
+
+ rmdir("dir");
+ return 0;
+}
+
+int
+test_recurse() {
+ if (mkdir_recursive("dir/subdir/subsubdir"))
+ return -1;
+
+ if (file_type("dir/subdir/subsubdir") != S_IFDIR)
+ return -1;
+
+ rmdir("dir/subdir/subsubdir");
+
+ /* try again with partial existence */
+ if (mkdir_recursive("dir/subdir/subsubdir"))
+ return -1;
+
+ if (file_type("dir/subdir/subsubdir") != S_IFDIR)
+ return -1;
+
+ rmdir("dir/subdir/subsubdir");
+ rmdir("dir/subdir");
+ rmdir("dir");
+ return 0;
+}
+
+int
+test_recurse_multislash() {
+ if (mkdir_recursive("dir/subdir///subsubdir"))
+ return -1;
+
+ if (file_type("dir/subdir/subsubdir") != S_IFDIR)
+ return -1;
+
+ rmdir("dir/subdir/subsubdir");
+ rmdir("dir/subdir");
+
+ /* try again with partial existence */
+ if (mkdir_recursive("dir/subdir/subsubdir///"))
+ return -1;
+
+ if (file_type("dir/subdir/subsubdir") != S_IFDIR)
+ return -1;
+
+ rmdir("dir/subdir/subsubdir");
+ rmdir("dir/subdir");
+ rmdir("dir");
+ return 0;
+}
+
+int
+test_parent_notdir() {
+ int fd = open("file", O_CREAT, 0600);
+ if (fd < 0)
+ return -1;
+ close(fd);
+
+ if (mkdir_recursive("file") == 0)
+ return -1;
+ if (mkdir_recursive("file/dir") == 0)
+ return -1;
+
+ unlink("file");
+ return 0;
+}
+
+int
+main()
+{
+ char *base_dir = strdup("/tmp/ppp_utils_utest.XXXXXX");
+ int failure = 0;
+
+ if (mkdtemp(base_dir) == NULL) {
+ printf("Could not create test directory, aborting\n");
+ return 1;
+ }
+
+ if (chdir(base_dir) < 0) {
+ printf("Could not enter newly created test dir, aborting\n");
+ return 1;
+ }
+
+ if (test_simple()) {
+ printf("Could not create simple directory\n");
+ failure++;
+ }
+
+ if (test_recurse()) {
+ printf("Could not create recursive directory\n");
+ failure++;
+ }
+
+ if (test_recurse_multislash()) {
+ printf("Could not create recursive directory with multiple slashes\n");
+ failure++;
+ }
+
+ if (test_parent_notdir()) {
+ printf("Creating over a file appeared to work?\n");
+ failure++;
+ }
+
+ rmdir(base_dir);
+ free(base_dir);
+ return failure;
+}