]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/mkdir.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / basic / mkdir.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
49e942b2
KS
2/***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
49e942b2
KS
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 15 Lesser General Public License for more details.
49e942b2 16
5430f7f2 17 You should have received a copy of the GNU Lesser General Public License
49e942b2
KS
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
49e942b2 21#include <errno.h>
11c3a366 22#include <stdbool.h>
cf0fbc49 23#include <string.h>
11c3a366 24#include <sys/stat.h>
49e942b2 25
c31ad024 26#include "alloc-util.h"
f4f15635 27#include "fs-util.h"
93cc7779 28#include "macro.h"
4ad49000 29#include "mkdir.h"
f4f15635 30#include "path-util.h"
8fcde012 31#include "stat-util.h"
ee104e11 32#include "user-util.h"
49e942b2 33
c31ad024 34int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, bool follow_symlink, mkdir_func_t _mkdir) {
49e942b2 35 struct stat st;
8f2c2f20 36 int r;
49e942b2 37
8f2c2f20
LP
38 if (_mkdir(path, mode) >= 0) {
39 r = chmod_and_chown(path, mode, uid, gid);
40 if (r < 0)
41 return r;
42 }
49e942b2
KS
43
44 if (lstat(path, &st) < 0)
45 return -errno;
46
c31ad024
YW
47 if (follow_symlink && S_ISLNK(st.st_mode)) {
48 _cleanup_free_ char *p = NULL;
49
50 r = chase_symlinks(path, NULL, CHASE_NONEXISTENT, &p);
51 if (r < 0)
52 return r;
53 if (r == 0)
54 return mkdir_safe_internal(p, mode, uid, gid, false, _mkdir);
55
56 if (lstat(p, &st) < 0)
57 return -errno;
58 }
59
0cb9fbcd
LP
60 if ((st.st_mode & 0007) > (mode & 0007) ||
61 (st.st_mode & 0070) > (mode & 0070) ||
62 (st.st_mode & 0700) > (mode & 0700) ||
fed1e721
LP
63 (uid != UID_INVALID && st.st_uid != uid) ||
64 (gid != GID_INVALID && st.st_gid != gid) ||
2e6534a9
ZJS
65 !S_ISDIR(st.st_mode))
66 return -EEXIST;
49e942b2
KS
67
68 return 0;
69}
70
c31ad024
YW
71int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid, bool follow_symlink) {
72 return mkdir_safe_internal(path, mode, uid, gid, follow_symlink, mkdir);
c66e7f04
KS
73}
74
39bdfa31 75int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir) {
49e942b2 76 const char *p, *e;
4ad49000 77 int r;
49e942b2
KS
78
79 assert(path);
80
4ad49000
LP
81 if (prefix && !path_startswith(path, prefix))
82 return -ENOTDIR;
83
9e13dbae
KS
84 /* return immediately if directory exists */
85 e = strrchr(path, '/');
86 if (!e)
87 return -EINVAL;
4ad49000
LP
88
89 if (e == path)
90 return 0;
91
9e13dbae 92 p = strndupa(path, e - path);
e73a03e0 93 r = is_dir(p, true);
4ad49000
LP
94 if (r > 0)
95 return 0;
96 if (r == 0)
97 return -ENOTDIR;
49e942b2 98
9e13dbae 99 /* create every parent directory in the path, except the last component */
49e942b2
KS
100 p = path + strspn(path, "/");
101 for (;;) {
4ad49000 102 char t[strlen(path) + 1];
49e942b2
KS
103
104 e = p + strcspn(p, "/");
105 p = e + strspn(e, "/");
106
107 /* Is this the last component? If so, then we're
108 * done */
109 if (*p == 0)
110 return 0;
111
4ad49000
LP
112 memcpy(t, path, e - path);
113 t[e-path] = 0;
49e942b2 114
4ad49000
LP
115 if (prefix && path_startswith(prefix, t))
116 continue;
49e942b2 117
39bdfa31 118 r = _mkdir(t, mode);
49e942b2
KS
119 if (r < 0 && errno != EEXIST)
120 return -errno;
121 }
122}
123
c66e7f04 124int mkdir_parents(const char *path, mode_t mode) {
39bdfa31 125 return mkdir_parents_internal(NULL, path, mode, mkdir);
5b585b53
ZJS
126}
127
39bdfa31 128int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir) {
49e942b2
KS
129 int r;
130
131 /* Like mkdir -p */
132
39bdfa31 133 r = mkdir_parents_internal(prefix, path, mode, _mkdir);
c66e7f04 134 if (r < 0)
49e942b2
KS
135 return r;
136
39bdfa31 137 r = _mkdir(path, mode);
e73a03e0 138 if (r < 0 && (errno != EEXIST || is_dir(path, true) <= 0))
49e942b2
KS
139 return -errno;
140
141 return 0;
142}
c66e7f04
KS
143
144int mkdir_p(const char *path, mode_t mode) {
39bdfa31 145 return mkdir_p_internal(NULL, path, mode, mkdir);
4ad49000 146}