]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/mkdir.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
7 #include "alloc-util.h"
8 #include "format-util.h"
12 #include "path-util.h"
13 #include "stat-util.h"
14 #include "stdio-util.h"
15 #include "user-util.h"
17 int mkdir_safe_internal(const char *path
, mode_t mode
, uid_t uid
, gid_t gid
, MkdirFlags flags
, mkdir_func_t _mkdir
) {
21 assert(_mkdir
!= mkdir
);
23 if (_mkdir(path
, mode
) >= 0) {
24 r
= chmod_and_chown(path
, mode
, uid
, gid
);
29 if (lstat(path
, &st
) < 0)
32 if ((flags
& MKDIR_FOLLOW_SYMLINK
) && S_ISLNK(st
.st_mode
)) {
33 _cleanup_free_
char *p
= NULL
;
35 r
= chase_symlinks(path
, NULL
, CHASE_NONEXISTENT
, &p
, NULL
);
39 return mkdir_safe_internal(p
, mode
, uid
, gid
,
40 flags
& ~MKDIR_FOLLOW_SYMLINK
,
43 if (lstat(p
, &st
) < 0)
47 if (!S_ISDIR(st
.st_mode
)) {
48 log_full(flags
& MKDIR_WARN_MODE
? LOG_WARNING
: LOG_DEBUG
,
49 "Path \"%s\" already exists and is not a directory, refusing.", path
);
52 if ((st
.st_mode
& 0007) > (mode
& 0007) ||
53 (st
.st_mode
& 0070) > (mode
& 0070) ||
54 (st
.st_mode
& 0700) > (mode
& 0700)) {
55 log_full(flags
& MKDIR_WARN_MODE
? LOG_WARNING
: LOG_DEBUG
,
56 "Directory \"%s\" already exists, but has mode %04o that is too permissive (%04o was requested), refusing.",
57 path
, st
.st_mode
& 0777, mode
);
60 if ((uid
!= UID_INVALID
&& st
.st_uid
!= uid
) ||
61 (gid
!= GID_INVALID
&& st
.st_gid
!= gid
)) {
62 char u
[DECIMAL_STR_MAX(uid_t
)] = "-", g
[DECIMAL_STR_MAX(gid_t
)] = "-";
64 if (uid
!= UID_INVALID
)
65 xsprintf(u
, UID_FMT
, uid
);
66 if (gid
!= UID_INVALID
)
67 xsprintf(g
, GID_FMT
, gid
);
68 log_full(flags
& MKDIR_WARN_MODE
? LOG_WARNING
: LOG_DEBUG
,
69 "Directory \"%s\" already exists, but is owned by "UID_FMT
":"GID_FMT
" (%s:%s was requested), refusing.",
70 path
, st
.st_uid
, st
.st_gid
, u
, g
);
77 int mkdir_errno_wrapper(const char *pathname
, mode_t mode
) {
78 if (mkdir(pathname
, mode
) < 0)
83 int mkdirat_errno_wrapper(int dirfd
, const char *pathname
, mode_t mode
) {
84 if (mkdirat(dirfd
, pathname
, mode
) < 0)
89 int mkdir_safe(const char *path
, mode_t mode
, uid_t uid
, gid_t gid
, MkdirFlags flags
) {
90 return mkdir_safe_internal(path
, mode
, uid
, gid
, flags
, mkdir_errno_wrapper
);
93 int mkdir_parents_internal(const char *prefix
, const char *path
, mode_t mode
, mkdir_func_t _mkdir
) {
98 assert(_mkdir
!= mkdir
);
100 if (prefix
&& !path_startswith(path
, prefix
))
103 /* return immediately if directory exists */
104 e
= strrchr(path
, '/');
111 p
= strndupa(path
, e
- path
);
118 /* create every parent directory in the path, except the last component */
119 p
= path
+ strspn(path
, "/");
121 char t
[strlen(path
) + 1];
123 e
= p
+ strcspn(p
, "/");
124 p
= e
+ strspn(e
, "/");
126 /* Is this the last component? If so, then we're done */
130 memcpy(t
, path
, e
- path
);
133 if (prefix
&& path_startswith(prefix
, t
))
137 if (r
< 0 && r
!= -EEXIST
)
142 int mkdir_parents(const char *path
, mode_t mode
) {
143 return mkdir_parents_internal(NULL
, path
, mode
, mkdir_errno_wrapper
);
146 int mkdir_p_internal(const char *prefix
, const char *path
, mode_t mode
, mkdir_func_t _mkdir
) {
151 assert(_mkdir
!= mkdir
);
153 r
= mkdir_parents_internal(prefix
, path
, mode
, _mkdir
);
157 r
= _mkdir(path
, mode
);
158 if (r
< 0 && (r
!= -EEXIST
|| is_dir(path
, true) <= 0))
164 int mkdir_p(const char *path
, mode_t mode
) {
165 return mkdir_p_internal(NULL
, path
, mode
, mkdir_errno_wrapper
);