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