]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/mkdir.c
util-lib: move a number of fs operations into fs-util.[ch]
[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 <string.h>
49e942b2 23#include <errno.h>
49e942b2 24
f4f15635 25#include "fs-util.h"
4ad49000 26#include "mkdir.h"
f4f15635
LP
27#include "path-util.h"
28#include "util.h"
49e942b2 29
39bdfa31 30int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, mkdir_func_t _mkdir) {
49e942b2
KS
31 struct stat st;
32
39bdfa31 33 if (_mkdir(path, mode) >= 0)
49e942b2
KS
34 if (chmod_and_chown(path, mode, uid, gid) < 0)
35 return -errno;
36
37 if (lstat(path, &st) < 0)
38 return -errno;
39
0cb9fbcd
LP
40 if ((st.st_mode & 0007) > (mode & 0007) ||
41 (st.st_mode & 0070) > (mode & 0070) ||
42 (st.st_mode & 0700) > (mode & 0700) ||
fed1e721
LP
43 (uid != UID_INVALID && st.st_uid != uid) ||
44 (gid != GID_INVALID && st.st_gid != gid) ||
2e6534a9
ZJS
45 !S_ISDIR(st.st_mode))
46 return -EEXIST;
49e942b2
KS
47
48 return 0;
49}
50
c66e7f04 51int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid) {
69c2b6be 52 return mkdir_safe_internal(path, mode, uid, gid, mkdir);
c66e7f04
KS
53}
54
39bdfa31 55int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir) {
49e942b2 56 const char *p, *e;
4ad49000 57 int r;
49e942b2
KS
58
59 assert(path);
60
4ad49000
LP
61 if (prefix && !path_startswith(path, prefix))
62 return -ENOTDIR;
63
9e13dbae
KS
64 /* return immediately if directory exists */
65 e = strrchr(path, '/');
66 if (!e)
67 return -EINVAL;
4ad49000
LP
68
69 if (e == path)
70 return 0;
71
9e13dbae 72 p = strndupa(path, e - path);
e73a03e0 73 r = is_dir(p, true);
4ad49000
LP
74 if (r > 0)
75 return 0;
76 if (r == 0)
77 return -ENOTDIR;
49e942b2 78
9e13dbae 79 /* create every parent directory in the path, except the last component */
49e942b2
KS
80 p = path + strspn(path, "/");
81 for (;;) {
4ad49000 82 char t[strlen(path) + 1];
49e942b2
KS
83
84 e = p + strcspn(p, "/");
85 p = e + strspn(e, "/");
86
87 /* Is this the last component? If so, then we're
88 * done */
89 if (*p == 0)
90 return 0;
91
4ad49000
LP
92 memcpy(t, path, e - path);
93 t[e-path] = 0;
49e942b2 94
4ad49000
LP
95 if (prefix && path_startswith(prefix, t))
96 continue;
49e942b2 97
39bdfa31 98 r = _mkdir(t, mode);
49e942b2
KS
99 if (r < 0 && errno != EEXIST)
100 return -errno;
101 }
102}
103
c66e7f04 104int mkdir_parents(const char *path, mode_t mode) {
39bdfa31 105 return mkdir_parents_internal(NULL, path, mode, mkdir);
5b585b53
ZJS
106}
107
39bdfa31 108int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir) {
49e942b2
KS
109 int r;
110
111 /* Like mkdir -p */
112
39bdfa31 113 r = mkdir_parents_internal(prefix, path, mode, _mkdir);
c66e7f04 114 if (r < 0)
49e942b2
KS
115 return r;
116
39bdfa31 117 r = _mkdir(path, mode);
e73a03e0 118 if (r < 0 && (errno != EEXIST || is_dir(path, true) <= 0))
49e942b2
KS
119 return -errno;
120
121 return 0;
122}
c66e7f04
KS
123
124int mkdir_p(const char *path, mode_t mode) {
39bdfa31 125 return mkdir_p_internal(NULL, path, mode, mkdir);
4ad49000 126}