diff options
Diffstat (limited to 'src/basic/mkdir.c')
-rw-r--r-- | src/basic/mkdir.c | 50 |
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; } |