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 */
}
#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];
--- /dev/null
+#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;
+}