]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/basic/mkdir.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / basic / mkdir.c
index 5d7fb9a12d9721031fd49ad99fed940b16e07315..4386b38c4a3df9d5708a9aee661c718afc5e0470 100644 (file)
@@ -1,5 +1,4 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
+/* SPDX-License-Identifier: LGPL-2.1+ */
 /***
   This file is part of systemd.
 
 ***/
 
 #include <errno.h>
+#include <stdbool.h>
 #include <string.h>
+#include <sys/stat.h>
 
+#include "alloc-util.h"
 #include "fs-util.h"
+#include "macro.h"
 #include "mkdir.h"
 #include "path-util.h"
 #include "stat-util.h"
 #include "user-util.h"
-#include "util.h"
 
-int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, mkdir_func_t _mkdir) {
+int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, bool follow_symlink, mkdir_func_t _mkdir) {
         struct stat st;
+        int r;
 
-        if (_mkdir(path, mode) >= 0)
-                if (chmod_and_chown(path, mode, uid, gid) < 0)
-                        return -errno;
+        if (_mkdir(path, mode) >= 0) {
+                r = chmod_and_chown(path, mode, uid, gid);
+                if (r < 0)
+                        return r;
+        }
 
         if (lstat(path, &st) < 0)
                 return -errno;
 
+        if (follow_symlink && S_ISLNK(st.st_mode)) {
+                _cleanup_free_ char *p = NULL;
+
+                r = chase_symlinks(path, NULL, CHASE_NONEXISTENT, &p);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return mkdir_safe_internal(p, mode, uid, gid, false, _mkdir);
+
+                if (lstat(p, &st) < 0)
+                        return -errno;
+        }
+
         if ((st.st_mode & 0007) > (mode & 0007) ||
             (st.st_mode & 0070) > (mode & 0070) ||
             (st.st_mode & 0700) > (mode & 0700) ||
@@ -50,8 +68,8 @@ int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, mkd
         return 0;
 }
 
-int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid) {
-        return mkdir_safe_internal(path, mode, uid, gid, mkdir);
+int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid, bool follow_symlink) {
+        return mkdir_safe_internal(path, mode, uid, gid, follow_symlink, mkdir);
 }
 
 int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir) {