summaryrefslogtreecommitdiffstats
path: root/tools/dosfstools/patches/100-source-date-epoch.patch
blob: c758caa4c1df173807924bf5a6e5a15fc598e8d9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
From 8da7bc93315cb0c32ad868f17808468b81fa76ec Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B8rn=20Forsman?= <bjorn.forsman@gmail.com>
Date: Wed, 5 Dec 2018 19:52:51 +0100
Subject: [PATCH] Honor the SOURCE_DATE_EPOCH variable
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Implement the SOURCE_DATE_EPOCH specification[1] for reproducible
builds. If SOURCE_DATE_EPOCH is set, use it as timestamp instead of the
current time.

[1] https://reproducible-builds.org/specs/source-date-epoch/

Signed-off-by: Bjørn Forsman <bjorn.forsman@gmail.com>
---
 src/boot.c     | 23 +++++++++++++++++++++--
 src/common.c   | 18 ++++++++++++++++--
 src/mkfs.fat.c | 19 ++++++++++++++++---
 3 files changed, 53 insertions(+), 7 deletions(-)

--- a/src/boot.c
+++ b/src/boot.c
@@ -33,6 +33,8 @@
 #include <stdlib.h>
 #include <sys/types.h>
 #include <time.h>
+#include <errno.h>
+#include <ctype.h>
 
 #include "common.h"
 #include "fsck.fat.h"
@@ -672,6 +674,7 @@ void write_volume_label(DOS_FS * fs, cha
 {
     time_t now;
     struct tm *mtime;
+    char *source_date_epoch = NULL;
     off_t offset;
     int created;
     DIR_ENT de;
@@ -687,8 +690,24 @@ void write_volume_label(DOS_FS * fs, cha
     if (de.name[0] == 0xe5)
 	de.name[0] = 0x05;
 
-    now = time(NULL);
-    mtime = (now != (time_t)-1) ? localtime(&now) : NULL;
+    source_date_epoch = getenv("SOURCE_DATE_EPOCH");
+    if (source_date_epoch) {
+        char *tmp = NULL;
+        long long conversion = 0;
+        errno = 0;
+        conversion = strtoll(source_date_epoch, &tmp, 10);
+        now = conversion;
+        if (!isdigit((unsigned char)*source_date_epoch) || *tmp != '\0'
+                || errno != 0 || (long long)now != conversion) {
+            die("SOURCE_DATE_EPOCH is too big or contains non-digits: \"%s\"",
+                source_date_epoch);
+        }
+        mtime = gmtime(&now);
+    } else {
+        now = time(NULL);
+        mtime = (now != (time_t)-1) ? localtime(&now) : NULL;
+    }
+
     if (mtime && mtime->tm_year >= 80 && mtime->tm_year <= 207) {
 	de.time = htole16((unsigned short)((mtime->tm_sec >> 1) +
 					   (mtime->tm_min << 5) +
--- a/src/common.c
+++ b/src/common.c
@@ -30,6 +30,7 @@
 #include <string.h>
 #include <stdarg.h>
 #include <errno.h>
+#include <ctype.h>
 #include <wctype.h>
 #include <termios.h>
 #include <sys/time.h>
@@ -298,8 +299,21 @@ void check_atari(void)
 uint32_t generate_volume_id(void)
 {
     struct timeval now;
+    char *source_date_epoch = NULL;
 
-    if (gettimeofday(&now, NULL) != 0 || now.tv_sec == (time_t)-1 || now.tv_sec < 0) {
+    source_date_epoch = getenv("SOURCE_DATE_EPOCH");
+    if (source_date_epoch) {
+        char *tmp = NULL;
+        long long conversion = 0;
+        errno = 0;
+        conversion = strtoll(source_date_epoch, &tmp, 10);
+        if (!isdigit((unsigned char)*source_date_epoch) || *tmp != '\0'
+                || errno != 0) {
+            die("SOURCE_DATE_EPOCH is too big or contains non-digits: \"%s\"",
+                source_date_epoch);
+        }
+        return (uint32_t)conversion;
+    } else if (gettimeofday(&now, NULL) != 0 || now.tv_sec == (time_t)-1 || now.tv_sec < 0) {
         srand(getpid());
         /* rand() returns int from [0,RAND_MAX], therefore only 31 bits */
         return (((uint32_t)(rand() & 0xFFFF)) << 16) | ((uint32_t)(rand() & 0xFFFF));
--- a/src/mkfs.fat.c
+++ b/src/mkfs.fat.c
@@ -1074,7 +1074,7 @@ static void setup_tables(void)
         }
 
         /* If is not available then generate random 32 bit disk signature */
-        if (invariant)
+        if (invariant || getenv("SOURCE_DATE_EPOCH"))
             disk_sig = volume_id;
         else if (!disk_sig)
             disk_sig = generate_volume_id();
@@ -1287,7 +1287,7 @@ static void setup_tables(void)
 	    de->name[0] = 0x05;
 	de->attr = ATTR_VOLUME;
 	if (create_time != (time_t)-1) {
-	    if (!invariant)
+	    if (!invariant && !getenv("SOURCE_DATE_EPOCH"))
 		ctime = localtime(&create_time);
 	    else
 		ctime = gmtime(&create_time);
@@ -1477,6 +1477,7 @@ int main(int argc, char **argv)
     int blocks_specified = 0;
     struct timeval create_timeval;
     long long conversion;
+    char *source_date_epoch = NULL;
 
     enum {OPT_HELP=1000, OPT_INVARIANT, OPT_MBR, OPT_VARIANT, OPT_CODEPAGE, OPT_OFFSET};
     const struct option long_options[] = {
@@ -1497,8 +1498,20 @@ int main(int argc, char **argv)
 	    program_name = p + 1;
     }
 
-    if (gettimeofday(&create_timeval, NULL) == 0 && create_timeval.tv_sec != (time_t)-1)
+    source_date_epoch = getenv("SOURCE_DATE_EPOCH");
+    if (source_date_epoch) {
+        errno = 0;
+        conversion = strtoll(source_date_epoch, &tmp, 10);
+        create_time = conversion;
+        if (!isdigit((unsigned char)*source_date_epoch) || *tmp != '\0'
+                || errno != 0 || (long long)create_time != conversion) {
+            die("SOURCE_DATE_EPOCH is too big or contains non-digits: \"%s\"",
+                source_date_epoch);
+        }
+    } else if (gettimeofday(&create_timeval, NULL) == 0 && create_timeval.tv_sec != (time_t)-1) {
         create_time = create_timeval.tv_sec;
+    }
+
     volume_id = generate_volume_id();
     check_atari();