Skip to content

Commit de3b55c

Browse files
committed
repart: respect SOURCE_DATE_EPOCH on mkdir_p_root
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`)
1 parent 469fdfb commit de3b55c

File tree

4 files changed

+67
-14
lines changed

4 files changed

+67
-14
lines changed

src/basic/mkdir.c

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <string.h>
66

77
#include "alloc-util.h"
8+
#include "bits/time.h"
89
#include "btrfs.h"
910
#include "chase.h"
1011
#include "fd-util.h"
@@ -204,9 +205,10 @@ int mkdir_p_safe(const char *prefix, const char *path, mode_t mode, uid_t uid, g
204205
return mkdir_p_internal(prefix, path, mode, uid, gid, flags, mkdirat_errno_wrapper);
205206
}
206207

207-
int mkdir_p_root(const char *root, const char *p, uid_t uid, gid_t gid, mode_t m, char **subvolumes) {
208+
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) {
208209
_cleanup_free_ char *pp = NULL, *bn = NULL;
209210
_cleanup_close_ int dfd = -EBADF;
211+
_cleanup_close_ int nfd = -EBADF;
210212
int r;
211213

212214
r = path_extract_directory(p, &pp);
@@ -222,7 +224,7 @@ int mkdir_p_root(const char *root, const char *p, uid_t uid, gid_t gid, mode_t m
222224
return r;
223225
else {
224226
/* Extracting the parent dir worked, hence we aren't top-level? Recurse up first. */
225-
r = mkdir_p_root(root, pp, uid, gid, m, subvolumes);
227+
r = mkdir_p_root_full(root, pp, uid, gid, m, subvolumes, ts);
226228
if (r < 0)
227229
return r;
228230

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

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

254-
nfd = openat(dfd, bn, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
255-
if (nfd < 0)
256-
return -errno;
256+
nfd = openat(dfd, bn, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
257+
if (nfd < 0)
258+
return -errno;
257259

258-
if (fchown(nfd, uid, gid) < 0)
259-
return -errno;
260-
}
260+
if (futimens(nfd, (const struct timespec[2]){ { .tv_nsec = ts }, { .tv_nsec = ts } }) < 0)
261+
return -errno;
262+
263+
if ((uid_is_valid(uid) || gid_is_valid(gid)) && (fchown(nfd, uid, gid) < 0))
264+
return -errno;
261265

262266
return 1;
263267
}

src/basic/mkdir.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
/* SPDX-License-Identifier: LGPL-2.1-or-later */
22
#pragma once
33

4+
#include <bits/time.h>
45
#include <fcntl.h>
56
#include <sys/types.h>
67

8+
#include "time-util.h"
9+
710
typedef enum MkdirFlags {
811
MKDIR_FOLLOW_SYMLINK = 1 << 0,
912
MKDIR_IGNORE_EXISTING = 1 << 1, /* Quietly accept a preexisting directory (or file) */
@@ -23,7 +26,10 @@ static inline int mkdir_parents(const char *path, mode_t mode) {
2326
int mkdir_parents_safe(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags);
2427
int mkdir_p(const char *path, mode_t mode);
2528
int mkdir_p_safe(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags);
26-
int mkdir_p_root(const char *root, const char *p, uid_t uid, gid_t gid, mode_t m, char **subvolumes);
29+
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);
30+
static inline int mkdir_p_root(const char *root, const char *p, uid_t uid, gid_t gid, mode_t m, char **subvolumes) {
31+
return mkdir_p_root_full(root, p, uid, gid, m, subvolumes, now(CLOCK_REALTIME));
32+
}
2733

2834
/* The following are used to implement the mkdir_xyz_label() calls, don't use otherwise. */
2935
typedef int (*mkdirat_func_t)(int dir_fd, const char *pathname, mode_t mode);

src/partition/repart.c

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4775,6 +4775,18 @@ static int make_subvolumes_set(
47754775
return 0;
47764776
}
47774777

4778+
static usec_t epoch_or_utime_omit(void) {
4779+
uint64_t epoch;
4780+
4781+
if (secure_getenv_uint64("SOURCE_DATE_EPOCH", &epoch) >= 0) {
4782+
if (epoch > UINT64_MAX / USEC_PER_SEC) /* Overflow check */
4783+
return USEC_INFINITY;
4784+
return (usec_t) epoch * USEC_PER_SEC;
4785+
}
4786+
4787+
return (usec_t) UTIME_OMIT;
4788+
}
4789+
47784790
static int do_copy_files(Context *context, Partition *p, const char *root) {
47794791
int r;
47804792

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

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

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

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

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

@@ -4907,6 +4920,10 @@ static int do_copy_files(Context *context, Partition *p, const char *root) {
49074920
(void) copy_xattr(sfd, NULL, tfd, NULL, COPY_ALL_XATTRS);
49084921
(void) copy_access(sfd, tfd);
49094922
(void) copy_times(sfd, tfd, 0);
4923+
4924+
ts = epoch_or_utime_omit();
4925+
if (futimens(pfd, (const struct timespec[2]){ { .tv_nsec = UTIME_OMIT }, { .tv_nsec = ts } }) <0)
4926+
return -errno;
49104927
}
49114928
}
49124929

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

49224939
STRV_FOREACH(d, p->make_directories) {
4923-
r = mkdir_p_root(root, *d, UID_INVALID, GID_INVALID, 0755, p->subvolumes);
4940+
r = mkdir_p_root_full(root, *d, UID_INVALID, GID_INVALID, 0755, p->subvolumes, epoch_or_utime_omit());
49244941
if (r < 0)
49254942
return log_error_errno(r, "Failed to create directory '%s' in file system: %m", *d);
49264943
}

src/test/test-mkdir.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,4 +138,30 @@ TEST(mkdir_p_root) {
138138
*/
139139
}
140140

141+
TEST(mkdir_p_root_full) {
142+
_cleanup_(rm_rf_physical_and_freep) char *tmp = NULL;
143+
_cleanup_free_ char *p = NULL;
144+
struct stat st;
145+
146+
assert_se(mkdtemp_malloc("/tmp/test-mkdir-XXXXXX", &tmp) >= 0);
147+
148+
assert_se(p = path_join(tmp, "foo"));
149+
assert_se(mkdir_p_root_full(tmp, "/foo", UID_INVALID, GID_INVALID, 0755, NULL, 1234) >= 0);
150+
assert_se(is_dir(p, false) > 0);
151+
assert_se(is_dir(p, true) > 0);
152+
assert_se(stat(p, &st) >= 0);
153+
assert_se(st.st_mtim.tv_nsec == 1234);
154+
assert_se(st.st_atim.tv_nsec == 1234);
155+
156+
p = mfree(p);
157+
assert_se(p = path_join(tmp, "dir-not-exists/foo"));
158+
assert_se(mkdir_p_root_full(tmp, "/dir-not-exists/foo", UID_INVALID, GID_INVALID, 0755, NULL, 5678) >= 0);
159+
assert_se(is_dir(p, false) > 0);
160+
assert_se(is_dir(p, true) > 0);
161+
assert_se(p = path_join(tmp, "dir-not-exists"));
162+
assert_se(stat(p, &st) >= 0);
163+
assert_se(st.st_mtim.tv_nsec == 5678);
164+
assert_se(st.st_atim.tv_nsec == 5678);
165+
}
166+
141167
DEFINE_TEST_MAIN(LOG_DEBUG);

0 commit comments

Comments
 (0)