Skip to content

Commit

Permalink
repart: respect SOURCE_DATE_EPOCH on mkdir_p_root
Browse files Browse the repository at this point in the history
This let's systemd-repart respect the `SOURCE_DATE_EPOCH` environment
variable when creating directories in the local tree through `CopyFiles`
or `MakeDirectories`.

To do this, we pass a timestamp `ts` to `mkdir_p_root`, which it will
use to fix up `mtime` and `atime` of the directory it creates as
well as the `mtime` of the directory it creates the other directory *in*,
as the `mtime` of the latter is modified when creating a directory in it.

For the same reason, it also needs to fixup the `mtime` of the upper
directory when copying a file into it through `CopyFiles`.

If `SOURCE_DATE_EPOCH`, times are left as is. (`UTIME_OMIT`)
  • Loading branch information
msanft committed Apr 26, 2024
1 parent 469fdfb commit de3b55c
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 14 deletions.
24 changes: 14 additions & 10 deletions src/basic/mkdir.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <string.h>

#include "alloc-util.h"
#include "bits/time.h"
#include "btrfs.h"
#include "chase.h"
#include "fd-util.h"
Expand Down Expand Up @@ -204,9 +205,10 @@ 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, char **subvolumes, usec_t ts) {
_cleanup_free_ char *pp = NULL, *bn = NULL;
_cleanup_close_ int dfd = -EBADF;
_cleanup_close_ int nfd = -EBADF;
int r;

r = path_extract_directory(p, &pp);
Expand All @@ -222,7 +224,7 @@ 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, subvolumes, ts);
if (r < 0)
return r;

Expand All @@ -248,16 +250,18 @@ int mkdir_p_root(const char *root, const char *p, uid_t uid, gid_t gid, mode_t m
return r;
}

if (uid_is_valid(uid) || gid_is_valid(gid)) {
_cleanup_close_ int nfd = -EBADF;
if (futimens(dfd, (const struct timespec[2]){ { .tv_nsec = UTIME_OMIT }, { .tv_nsec = ts } }) < 0)
return -errno;

nfd = openat(dfd, bn, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
if (nfd < 0)
return -errno;
nfd = openat(dfd, bn, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
if (nfd < 0)
return -errno;

if (fchown(nfd, uid, gid) < 0)
return -errno;
}
if (futimens(nfd, (const struct timespec[2]){ { .tv_nsec = ts }, { .tv_nsec = ts } }) < 0)
return -errno;

if ((uid_is_valid(uid) || gid_is_valid(gid)) && (fchown(nfd, uid, gid) < 0))
return -errno;

return 1;
}
8 changes: 7 additions & 1 deletion src/basic/mkdir.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once

#include <bits/time.h>
#include <fcntl.h>
#include <sys/types.h>

#include "time-util.h"

typedef enum MkdirFlags {
MKDIR_FOLLOW_SYMLINK = 1 << 0,
MKDIR_IGNORE_EXISTING = 1 << 1, /* Quietly accept a preexisting directory (or file) */
Expand All @@ -23,7 +26,10 @@ static inline int mkdir_parents(const char *path, mode_t mode) {
int mkdir_parents_safe(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags);
int mkdir_p(const char *path, mode_t mode);
int mkdir_p_safe(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags);
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, char **subvolumes, usec_t ts);
static inline int mkdir_p_root(const char *root, const char *p, uid_t uid, gid_t gid, mode_t m, char **subvolumes) {
return mkdir_p_root_full(root, p, uid, gid, m, subvolumes, now(CLOCK_REALTIME));
}

/* The following are used to implement the mkdir_xyz_label() calls, don't use otherwise. */
typedef int (*mkdirat_func_t)(int dir_fd, const char *pathname, mode_t mode);
Expand Down
23 changes: 20 additions & 3 deletions src/partition/repart.c
Original file line number Diff line number Diff line change
Expand Up @@ -4775,6 +4775,18 @@ static int make_subvolumes_set(
return 0;
}

static usec_t epoch_or_utime_omit(void) {
uint64_t epoch;

if (secure_getenv_uint64("SOURCE_DATE_EPOCH", &epoch) >= 0) {
if (epoch > UINT64_MAX / USEC_PER_SEC) /* Overflow check */
return USEC_INFINITY;
return (usec_t) epoch * USEC_PER_SEC;
}

return (usec_t) UTIME_OMIT;
}

static int do_copy_files(Context *context, Partition *p, const char *root) {
int r;

Expand Down Expand Up @@ -4810,6 +4822,7 @@ static int do_copy_files(Context *context, Partition *p, const char *root) {
_cleanup_hashmap_free_ Hashmap *denylist = NULL;
_cleanup_set_free_ Set *subvolumes_by_source_inode = NULL;
_cleanup_close_ int sfd = -EBADF, pfd = -EBADF, tfd = -EBADF;
usec_t ts;

r = make_copy_files_denylist(context, p, *source, *target, &denylist);
if (r < 0)
Expand Down Expand Up @@ -4848,7 +4861,7 @@ static int do_copy_files(Context *context, Partition *p, const char *root) {
if (r < 0)
return log_error_errno(r, "Failed to extract directory from '%s': %m", *target);

r = mkdir_p_root(root, dn, UID_INVALID, GID_INVALID, 0755, p->subvolumes);
r = mkdir_p_root_full(root, dn, UID_INVALID, GID_INVALID, 0755, p->subvolumes, epoch_or_utime_omit());
if (r < 0)
return log_error_errno(r, "Failed to create parent directory '%s': %m", dn);

Expand Down Expand Up @@ -4888,7 +4901,7 @@ static int do_copy_files(Context *context, Partition *p, const char *root) {
if (r < 0)
return log_error_errno(r, "Failed to extract directory from '%s': %m", *target);

r = mkdir_p_root(root, dn, UID_INVALID, GID_INVALID, 0755, p->subvolumes);
r = mkdir_p_root_full(root, dn, UID_INVALID, GID_INVALID, 0755, p->subvolumes, epoch_or_utime_omit());
if (r < 0)
return log_error_errno(r, "Failed to create parent directory: %m");

Expand All @@ -4907,6 +4920,10 @@ static int do_copy_files(Context *context, Partition *p, const char *root) {
(void) copy_xattr(sfd, NULL, tfd, NULL, COPY_ALL_XATTRS);
(void) copy_access(sfd, tfd);
(void) copy_times(sfd, tfd, 0);

ts = epoch_or_utime_omit();
if (futimens(pfd, (const struct timespec[2]){ { .tv_nsec = UTIME_OMIT }, { .tv_nsec = ts } }) <0)
return -errno;
}
}

Expand All @@ -4920,7 +4937,7 @@ static int do_make_directories(Partition *p, const char *root) {
assert(root);

STRV_FOREACH(d, p->make_directories) {
r = mkdir_p_root(root, *d, UID_INVALID, GID_INVALID, 0755, p->subvolumes);
r = mkdir_p_root_full(root, *d, UID_INVALID, GID_INVALID, 0755, p->subvolumes, epoch_or_utime_omit());
if (r < 0)
return log_error_errno(r, "Failed to create directory '%s' in file system: %m", *d);
}
Expand Down
26 changes: 26 additions & 0 deletions src/test/test-mkdir.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,4 +138,30 @@ TEST(mkdir_p_root) {
*/
}

TEST(mkdir_p_root_full) {
_cleanup_(rm_rf_physical_and_freep) char *tmp = NULL;
_cleanup_free_ char *p = NULL;
struct stat st;

assert_se(mkdtemp_malloc("/tmp/test-mkdir-XXXXXX", &tmp) >= 0);

assert_se(p = path_join(tmp, "foo"));
assert_se(mkdir_p_root_full(tmp, "/foo", UID_INVALID, GID_INVALID, 0755, NULL, 1234) >= 0);
assert_se(is_dir(p, false) > 0);
assert_se(is_dir(p, true) > 0);
assert_se(stat(p, &st) >= 0);
assert_se(st.st_mtim.tv_nsec == 1234);
assert_se(st.st_atim.tv_nsec == 1234);

p = mfree(p);
assert_se(p = path_join(tmp, "dir-not-exists/foo"));
assert_se(mkdir_p_root_full(tmp, "/dir-not-exists/foo", UID_INVALID, GID_INVALID, 0755, NULL, 5678) >= 0);
assert_se(is_dir(p, false) > 0);
assert_se(is_dir(p, true) > 0);
assert_se(p = path_join(tmp, "dir-not-exists"));
assert_se(stat(p, &st) >= 0);
assert_se(st.st_mtim.tv_nsec == 5678);
assert_se(st.st_atim.tv_nsec == 5678);
}

DEFINE_TEST_MAIN(LOG_DEBUG);

0 comments on commit de3b55c

Please sign in to comment.