From 10ab81a0de97513d82d05945c12bff87b02ede27 Mon Sep 17 00:00:00 2001
From: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Date: Sat, 2 Jul 2022 21:10:49 +0200
Subject: Cleanup: move mkdir_p from libcommon to libutil

Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
---
 lib/util/Makemodule.am |   1 +
 lib/util/mkdir_p.c     | 170 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 171 insertions(+)
 create mode 100644 lib/util/mkdir_p.c

(limited to 'lib/util')

diff --git a/lib/util/Makemodule.am b/lib/util/Makemodule.am
index 9578fb2..bc3d618 100644
--- a/lib/util/Makemodule.am
+++ b/lib/util/Makemodule.am
@@ -9,6 +9,7 @@ libutil_a_SOURCES += include/util/threadpool.h
 libutil_a_SOURCES += include/util/w32threadwrap.h
 libutil_a_SOURCES += lib/util/threadpool_serial.c
 libutil_a_SOURCES += lib/util/is_memory_zero.c
+libutil_a_SOURCES += lib/util/mkdir_p.c
 libutil_a_CFLAGS = $(AM_CFLAGS)
 libutil_a_CPPFLAGS = $(AM_CPPFLAGS)
 
diff --git a/lib/util/mkdir_p.c b/lib/util/mkdir_p.c
new file mode 100644
index 0000000..993d8ec
--- /dev/null
+++ b/lib/util/mkdir_p.c
@@ -0,0 +1,170 @@
+/* SPDX-License-Identifier: LGPL-3.0-or-later */
+/*
+ * mkdir_p.c
+ *
+ * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
+ */
+#include "util/util.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#ifdef _WIN32
+/*
+  Supported paths:
+   - <letter>:\ <absolute path>
+   - \\<server>\<share>\ <absolute path>
+   - \\?\<letter>:\ <absolute path>
+   - \\?\UNC\<server>\<share>\ <absolute path>
+   - Relative path not starting with '\'
+ */
+
+static WCHAR *skip_unc_path(WCHAR *ptr)
+{
+	/* server */
+	if (*ptr == '\0' || *ptr == '\\')
+		return NULL;
+
+	while (*ptr != '\0' && *ptr != '\\')
+		++ptr;
+
+	if (*(ptr++) != '\\')
+		return NULL;
+
+	/* share */
+	if (*ptr == '\0' || *ptr == '\\')
+		return NULL;
+
+	while (*ptr != '\0' && *ptr != '\\')
+		++ptr;
+
+	return (*ptr == '\\') ? (ptr + 1) : ptr;
+}
+
+static WCHAR *skip_prefix(WCHAR *ptr)
+{
+	if (isalpha(ptr[0]) && ptr[1] == ':' && ptr[2] == '\\')
+		return ptr + 3;
+
+	if (ptr[0] == '\\' && ptr[1] == '\\') {
+		if (ptr[2] == '?') {
+			if (ptr[3] != '\\')
+				return NULL;
+
+			ptr += 4;
+
+			if ((ptr[0] == 'u' || ptr[0] == 'U') &&
+			    (ptr[1] == 'n' || ptr[1] == 'N') &&
+			    (ptr[2] == 'c' || ptr[2] == 'C') &&
+			    ptr[3] == '\\') {
+				ptr += 4;
+
+				return skip_unc_path(ptr);
+			}
+
+			if (isalpha(ptr[0]) && ptr[1] == ':' && ptr[2] == '\\')
+				return ptr + 3;
+
+			return NULL;
+		}
+
+		return skip_unc_path(ptr);
+	}
+
+	if (ptr[0] == '\\')
+		return NULL;
+
+	return ptr;
+}
+
+int mkdir_p(const char *path)
+{
+	WCHAR *wpath, *ptr, *end;
+	DWORD error;
+	bool done;
+
+
+	wpath = path_to_windows(path);
+	if (wpath == NULL)
+		return -1;
+
+	ptr = skip_prefix(wpath);
+	if (ptr == NULL) {
+		fprintf(stderr, "Illegal or unsupported path: %s\n", path);
+		goto fail;
+	}
+
+	while (*ptr != '\0') {
+		if (*ptr == '\\') {
+			++ptr;
+			continue;
+		}
+
+		for (end = ptr; *end != '\0' && *end != '\\'; ++end)
+			++end;
+
+		if (*end == '\\') {
+			done = false;
+			*end = '\0';
+		} else {
+			done = true;
+		}
+
+		if (!CreateDirectoryW(wpath, NULL)) {
+			error = GetLastError();
+
+			if (error != ERROR_ALREADY_EXISTS) {
+				fprintf(stderr, "Creating %s: %ld\n",
+					path, error);
+				goto fail;
+			}
+		}
+
+		if (!done)
+			*end = '\\';
+
+		ptr = done ? end : (end + 1);
+	}
+
+	free(wpath);
+	return 0;
+fail:
+	free(wpath);
+	return -1;
+}
+#else
+int mkdir_p(const char *path)
+{
+	size_t i, len;
+	char *buffer;
+
+	while (path[0] == '/' && path[1] == '/')
+		++path;
+
+	if (*path == '\0' || (path[0] == '/' && path[1] == '\0'))
+		return 0;
+
+	len = strlen(path) + 1;
+	buffer = alloca(len);
+
+	for (i = 0; i < len; ++i) {
+		if (i > 0 && (path[i] == '/' || path[i] == '\0')) {
+			buffer[i] = '\0';
+
+			if (mkdir(buffer, 0755) != 0) {
+				if (errno != EEXIST) {
+					fprintf(stderr, "mkdir %s: %s\n",
+						buffer, strerror(errno));
+					return -1;
+				}
+			}
+		}
+
+		buffer[i] = path[i];
+	}
+
+	return 0;
+}
+#endif
-- 
cgit v1.2.3