return unit_bytes;
}
+/*
+ * current_fixed_time() tries to detect if SOURCE_DATE_EPOCH is in our
+ * environment, and set input timespec's timestamp to that value.
+ *
+ * Returns true on success, fail otherwise.
+ */
+bool
+current_fixed_time(
+ struct timespec64 *tv)
+{
+ /*
+ * To avoid many getenv() we'll use an initialization static flag, so
+ * we only read once.
+ */
+ static bool enabled = false;
+ static bool read_env = false;
+ static time64_t epoch;
+ char *endp;
+ char *source_date_epoch;
+
+ if (!read_env) {
+ read_env = true;
+ source_date_epoch = getenv("SOURCE_DATE_EPOCH");
+ if (source_date_epoch && source_date_epoch[0] != '\0') {
+ errno = 0;
+ epoch = strtoll(source_date_epoch, &endp, 10);
+ if (errno != 0 || *endp != '\0') {
+ fprintf(stderr,
+ "%s: SOURCE_DATE_EPOCH '%s' invalid timestamp, ignoring.\n",
+ progname, source_date_epoch);
+
+ return false;
+ }
+
+ enabled = true;
+ }
+ }
+
+ /*
+ * This will happen only if we successfully read a valid
+ * SOURCE_DATE_EPOCH and properly initiated the epoch value.
+ */
+ if (read_env && enabled) {
+ tv->tv_sec = epoch;
+ tv->tv_nsec = 0;
+ return true;
+ }
+
+ /*
+ * We initialized but had no valid SOURCE_DATE_EPOCH so we fall back
+ * to regular behaviour.
+ */
+ return false;
+}
+
struct timespec64
current_time(struct inode *inode)
{
struct timespec64 tv;
struct timeval stv;
+ /*
+ * Check if we're creating a reproducible filesystem.
+ * In this case we try to parse our SOURCE_DATE_EPOCH from environment.
+ * If it fails, fall back to returning gettimeofday()
+ * like we used to do.
+ */
+ if (current_fixed_time(&tv))
+ return tv;
+
gettimeofday(&stv, (struct timezone *)0);
tv.tv_sec = stv.tv_sec;
tv.tv_nsec = stv.tv_usec * 1000;
void xfs_da_mark_sick(struct xfs_da_args *args) { }
void xfs_inode_mark_sick(struct xfs_inode *ip, unsigned int mask) { }
+/*
+ * get_deterministic_seed() tries to detect if DETERMINISTIC_SEED=1 is in our
+ * environment, and set our result to 0x53454544 (SEED) instead of
+ * extracting from getrandom().
+ *
+ * Returns true on success, fail otherwise.
+ */
+bool
+get_deterministic_seed(
+ uint32_t *result)
+{
+ /*
+ * To avoid many getenv() we'll use an initialization static flag, so
+ * we only read once.
+ */
+ static bool enabled = false;
+ static bool read_env = false;
+ static uint32_t deterministic_seed = 0x53454544; /* SEED */
+ char *seed_env;
+
+ if (!read_env) {
+ read_env = true;
+ seed_env = getenv("DETERMINISTIC_SEED");
+ if (seed_env && strcmp(seed_env, "1") == 0)
+ enabled = true;
+ }
+
+ /*
+ * This will happen only if we successfully read DETERMINISTIC_SEED=1.
+ */
+ if (read_env && enabled) {
+ *result = deterministic_seed;
+
+ return true;
+ }
+
+ /*
+ * We initialized but had no DETERMINISTIC_SEED=1 in env so we fall
+ * back to regular behaviour.
+ */
+ return false;
+}
+
#ifdef HAVE_GETRANDOM_NONBLOCK
uint32_t
get_random_u32(void)
uint32_t ret;
ssize_t sz;
+ /*
+ * Check for DETERMINISTIC_SEED in environment, it means we're
+ * creating a reproducible filesystem.
+ * If it fails, fall back to returning getrandom() like we used to do.
+ */
+ if (get_deterministic_seed(&ret))
+ return ret;
/*
* Try to extract a u32 of randomness from /dev/urandom. If that
* fails, fall back to returning zero like we used to do.