286 lines
6.2 KiB
Diff
286 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;
|
|
+}
|