summaryrefslogtreecommitdiffstats
path: root/src/basic/mkdir.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/basic/mkdir.c')
-rw-r--r--src/basic/mkdir.c50
1 files changed, 27 insertions, 23 deletions
diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c
index c770e5e..f87de0a 100644
--- a/src/basic/mkdir.c
+++ b/src/basic/mkdir.c
@@ -70,17 +70,11 @@ int mkdirat_safe_internal(
path, st.st_mode & 0777, mode);
if ((uid != UID_INVALID && st.st_uid != uid) ||
- (gid != GID_INVALID && st.st_gid != gid)) {
- char u[DECIMAL_STR_MAX(uid_t)] = "-", g[DECIMAL_STR_MAX(gid_t)] = "-";
-
- if (uid != UID_INVALID)
- xsprintf(u, UID_FMT, uid);
- if (gid != UID_INVALID)
- xsprintf(g, GID_FMT, gid);
+ (gid != GID_INVALID && st.st_gid != gid))
return log_full_errno(flags & MKDIR_WARN_MODE ? LOG_WARNING : LOG_DEBUG, SYNTHETIC_ERRNO(EEXIST),
"Directory \"%s\" already exists, but is owned by "UID_FMT":"GID_FMT" (%s:%s was requested), refusing.",
- path, st.st_uid, st.st_gid, u, g);
- }
+ path, st.st_uid, st.st_gid, uid != UID_INVALID ? FORMAT_UID(uid) : "-",
+ gid != UID_INVALID ? FORMAT_GID(gid) : "-");
return 0;
}
@@ -118,7 +112,7 @@ int mkdirat_parents_internal(int dir_fd, const char *path, mode_t mode, uid_t ui
/* drop the last component */
path = strndupa_safe(path, e - path);
- r = is_dir_full(dir_fd, path, true);
+ r = is_dir_at(dir_fd, path, /* follow = */ true);
if (r > 0)
return 0;
if (r == 0)
@@ -210,11 +204,13 @@ int mkdir_p_safe(const char *prefix, const char *path, mode_t mode, uid_t uid, g
return mkdir_p_internal(prefix, path, mode, uid, gid, flags, mkdirat_errno_wrapper);
}
-int mkdir_p_root(const char *root, const char *p, uid_t uid, gid_t gid, mode_t m, char **subvolumes) {
+int mkdir_p_root_full(const char *root, const char *p, uid_t uid, gid_t gid, mode_t m, usec_t ts, char **subvolumes) {
_cleanup_free_ char *pp = NULL, *bn = NULL;
_cleanup_close_ int dfd = -EBADF;
int r;
+ assert(p);
+
r = path_extract_directory(p, &pp);
if (r == -EDESTADDRREQ) {
/* only fname is passed, no prefix to operate on */
@@ -228,11 +224,11 @@ int mkdir_p_root(const char *root, const char *p, uid_t uid, gid_t gid, mode_t m
return r;
else {
/* Extracting the parent dir worked, hence we aren't top-level? Recurse up first. */
- r = mkdir_p_root(root, pp, uid, gid, m, subvolumes);
+ r = mkdir_p_root_full(root, pp, uid, gid, m, ts, subvolumes);
if (r < 0)
return r;
- dfd = chase_and_open(pp, root, CHASE_PREFIX_ROOT, O_RDONLY|O_CLOEXEC|O_DIRECTORY, NULL);
+ dfd = chase_and_open(pp, root, CHASE_PREFIX_ROOT, O_CLOEXEC|O_DIRECTORY, NULL);
if (dfd < 0)
return dfd;
}
@@ -247,23 +243,31 @@ int mkdir_p_root(const char *root, const char *p, uid_t uid, gid_t gid, mode_t m
r = btrfs_subvol_make_fallback(dfd, bn, m);
else
r = RET_NERRNO(mkdirat(dfd, bn, m));
- if (r < 0) {
- if (r == -EEXIST)
- return 0;
-
+ if (r == -EEXIST)
+ return 0;
+ if (r < 0)
return r;
- }
- if (uid_is_valid(uid) || gid_is_valid(gid)) {
- _cleanup_close_ int nfd = -EBADF;
+ if (ts == USEC_INFINITY && !uid_is_valid(uid) && !gid_is_valid(gid))
+ return 1;
+
+ _cleanup_close_ int nfd = openat(dfd, bn, O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
+ if (nfd < 0)
+ return -errno;
+
+ if (ts != USEC_INFINITY) {
+ struct timespec tspec;
+ timespec_store(&tspec, ts);
- nfd = openat(dfd, bn, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
- if (nfd < 0)
+ if (futimens(dfd, (const struct timespec[2]) { TIMESPEC_OMIT, tspec }) < 0)
return -errno;
- if (fchown(nfd, uid, gid) < 0)
+ if (futimens(nfd, (const struct timespec[2]) { tspec, tspec }) < 0)
return -errno;
}
+ if ((uid_is_valid(uid) || gid_is_valid(gid)) && fchown(nfd, uid, gid) < 0)
+ return -errno;
+
return 1;
}