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