diff options
Diffstat (limited to 'src/basic/mkdir.c')
-rw-r--r-- | src/basic/mkdir.c | 21 |
1 files changed, 18 insertions, 3 deletions
diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c index 7db09fc6a1..4386b38c4a 100644 --- a/src/basic/mkdir.c +++ b/src/basic/mkdir.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -22,6 +23,7 @@ #include <string.h> #include <sys/stat.h> +#include "alloc-util.h" #include "fs-util.h" #include "macro.h" #include "mkdir.h" @@ -29,7 +31,7 @@ #include "stat-util.h" #include "user-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; @@ -42,6 +44,19 @@ int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, mkd 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) || @@ -53,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) { |