Gentoo Archives: gentoo-commits

From: Fabian Groffen <grobian@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] repo/proj/prefix:master commit in: scripts/rsync-generation/
Date: Sat, 17 Feb 2018 17:19:59
Message-Id: 1518887854.88995923511b937f0a3c6a7218fb071838964c47.grobian@gentoo
1 commit: 88995923511b937f0a3c6a7218fb071838964c47
2 Author: Fabian Groffen <grobian <AT> gentoo <DOT> org>
3 AuthorDate: Sat Feb 17 17:17:34 2018 +0000
4 Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org>
5 CommitDate: Sat Feb 17 17:17:34 2018 +0000
6 URL: https://gitweb.gentoo.org/repo/proj/prefix.git/commit/?id=88995923
7
8 scripts/rsync-generation/hashgen: update timestamps more sensibly
9
10 Directory mtimes don't change when a file gets modified, so don't rely
11 on it. Instead, base Manifest mtime on the latest file they describe,
12 such that they stay the same when nothing changes on a subsequent run.
13
14 scripts/rsync-generation/hashgen.c | 91 ++++++++++++++++++++++++--------------
15 1 file changed, 59 insertions(+), 32 deletions(-)
16
17 diff --git a/scripts/rsync-generation/hashgen.c b/scripts/rsync-generation/hashgen.c
18 index 78944ba9ee..fa0519fb04 100644
19 --- a/scripts/rsync-generation/hashgen.c
20 +++ b/scripts/rsync-generation/hashgen.c
21 @@ -44,8 +44,23 @@ hex_hash(char *out, const unsigned char *buf, const int length)
22 }
23 }
24
25 +static inline void
26 +update_times(struct timeval *tv, struct stat *s)
27 +{
28 + if (tv[1].tv_sec < s->st_mtim.tv_sec ||
29 + (tv[1].tv_sec == s->st_mtim.tv_sec &&
30 + tv[1].tv_usec < s->st_mtim.tv_nsec / 1000))
31 + {
32 + tv[0].tv_sec = s->st_atim.tv_sec;
33 + tv[0].tv_usec = s->st_atim.tv_nsec / 1000;
34 + tv[1].tv_sec = s->st_mtim.tv_sec;
35 + tv[1].tv_usec = s->st_mtim.tv_nsec / 1000;
36 + }
37 +}
38 +
39 static void
40 write_hashes(
41 + struct timeval *tv,
42 const char *root,
43 const char *name,
44 const char *type,
45 @@ -65,11 +80,15 @@ write_hashes(
46 SHA512_CTX s512;
47 WHIRLPOOL_CTX whrl;
48 blake2b_state bl2b;
49 + struct stat s;
50
51 snprintf(fname, sizeof(fname), "%s/%s", root, name);
52 if ((f = fopen(fname, "r")) == NULL)
53 return;
54
55 + if (stat(fname, &s) == 0)
56 + update_times(tv, &s);
57 +
58 SHA256_Init(&s256);
59 SHA512_Init(&s512);
60 WHIRLPOOL_Init(&whrl);
61 @@ -160,7 +179,11 @@ write_hashes(
62 }
63
64 static char
65 -write_hashes_dir(const char *root, const char *name, gzFile zm)
66 +write_hashes_dir(
67 + struct timeval *tv,
68 + const char *root,
69 + const char *name,
70 + gzFile zm)
71 {
72 char path[8192];
73 DIR *d;
74 @@ -172,12 +195,11 @@ write_hashes_dir(const char *root, const char *name, gzFile zm)
75 /* skip all dotfiles */
76 if (e->d_name[0] == '.')
77 continue;
78 - snprintf(path, sizeof(path), "%s/%s",
79 - name, e->d_name);
80 - if (write_hashes_dir(root, path, zm))
81 + snprintf(path, sizeof(path), "%s/%s", name, e->d_name);
82 + if (write_hashes_dir(tv, root, path, zm))
83 continue;
84 /* regular file */
85 - write_hashes(root, path, "DATA", NULL, zm);
86 + write_hashes(tv, root, path, "DATA", NULL, zm);
87 }
88 closedir(d);
89 return 1;
90 @@ -192,6 +214,7 @@ process_files(const char *dir, const char *off, FILE *m)
91 char path[8192];
92 DIR *d;
93 struct dirent *e;
94 + struct timeval tv[2]; /* dummy, won't use its result */
95
96 snprintf(path, sizeof(path), "%s/%s", dir, off);
97 if ((d = opendir(path)) != NULL) {
98 @@ -204,7 +227,7 @@ process_files(const char *dir, const char *off, FILE *m)
99 if (process_files(dir, path, m))
100 continue;
101 /* regular file */
102 - write_hashes(dir, path, "AUX", m, NULL);
103 + write_hashes(tv, dir, path, "AUX", m, NULL);
104 }
105 closedir(d);
106 return 1;
107 @@ -316,19 +339,18 @@ process_dir(const char *dir)
108 struct stat s;
109 struct timeval tv[2];
110
111 - /* set mtime of Manifest(.gz) to the one of the parent dir, this way
112 - * we ensure the Manifest gets mtime bumped upon any change made
113 - * to the directory, that is, a DIST change (Manifest itself) or
114 - * any other change (ebuild, files, metadata) */
115 - if (stat(dir, &s)) {
116 - tv[0].tv_sec = 0;
117 - tv[0].tv_usec = 0;
118 - } else {
119 - tv[0].tv_sec = s.st_atim.tv_sec;
120 - tv[0].tv_usec = s.st_atim.tv_nsec / 1000;
121 - tv[1].tv_sec = s.st_mtim.tv_sec;
122 - tv[1].tv_usec = s.st_mtim.tv_nsec / 1000;
123 - }
124 + /* our timestamp strategy is as follows:
125 + * - when a Manifest exists, use its timestamp
126 + * - when a meta-Manifest is written (non-ebuilds) use the timestamp
127 + * of the latest Manifest referenced
128 + * - when a Manifest is written for something like eclasses, use the
129 + * timestamp of the latest file in the dir
130 + * this way we should keep updates limited to where changes are, and
131 + * also get reproducible mtimes. */
132 + tv[0].tv_sec = 0;
133 + tv[0].tv_usec = 0;
134 + tv[1].tv_sec = 0;
135 + tv[1].tv_usec = 0;
136
137 type_manifest = CATEGORY_MANIFEST;
138 snprintf(path, sizeof(path), "%s/metadata/layout.conf", dir);
139 @@ -366,7 +388,6 @@ process_dir(const char *dir)
140 gzFile mf;
141
142 if ((d = opendir(dir)) != NULL) {
143 - struct stat s;
144 char *my_manifest = str_manifest_gz;
145
146 if (type_manifest == GLOBAL_MANIFEST)
147 @@ -393,7 +414,7 @@ process_dir(const char *dir)
148 if (!stat(path, &s)) {
149 if (s.st_mode & S_IFDIR) {
150 if (type_manifest == SUBTREE_MANIFEST) {
151 - write_hashes_dir(dir, e->d_name, mf);
152 + write_hashes_dir(tv, dir, e->d_name, mf);
153 if (strcmp(e->d_name, "metadata") == 0) {
154 char buf[2048];
155 size_t len;
156 @@ -412,10 +433,10 @@ process_dir(const char *dir)
157 }
158 snprintf(path, sizeof(path), "%s/%s",
159 e->d_name, mfest);
160 - write_hashes(dir, path, "MANIFEST", NULL, mf);
161 + write_hashes(tv, dir, path, "MANIFEST", NULL, mf);
162 }
163 } else if (s.st_mode & S_IFREG) {
164 - write_hashes(dir, e->d_name, "DATA", NULL, mf);
165 + write_hashes(tv, dir, e->d_name, "DATA", NULL, mf);
166 }
167 }
168 }
169 @@ -427,6 +448,7 @@ process_dir(const char *dir)
170 size_t len;
171 FILE *m;
172 time_t rtime;
173 + struct timeval ntv[2]; /* dummy, not used */
174
175 len = snprintf(buf, sizeof(buf),
176 "IGNORE distfiles\n"
177 @@ -446,18 +468,13 @@ process_dir(const char *dir)
178 return NULL;
179 }
180
181 - write_hashes(dir, my_manifest, "MANIFEST", m, NULL);
182 + write_hashes(ntv, dir, my_manifest, "MANIFEST", m, NULL);
183 time(&rtime);
184 len = strftime(buf, sizeof(buf),
185 "TIMESTAMP %Y-%m-%dT%H:%M:%SZ\n", gmtime(&rtime));
186 fwrite(buf, len, 1, m);
187 fflush(m);
188 fclose(m);
189 -
190 - if (tv[0].tv_sec != 0) {
191 - /* restore dir mtime, and set Manifest mtime to match it */
192 - utimes(globmanifest, tv);
193 - }
194 } else {
195 gzclose(mf);
196 }
197 @@ -511,17 +528,27 @@ process_dir(const char *dir)
198 continue;
199 if (strcmp(e->d_name + strlen(e->d_name) - 7, ".ebuild") != 0)
200 continue;
201 - write_hashes(dir, e->d_name, "EBUILD", m, NULL);
202 + write_hashes(tv, dir, e->d_name, "EBUILD", m, NULL);
203 }
204 closedir(d);
205 }
206
207 - write_hashes(dir, "ChangeLog", "MISC", m, NULL);
208 - write_hashes(dir, "metadata.xml", "MISC", m, NULL);
209 + write_hashes(tv, dir, "ChangeLog", "MISC", m, NULL);
210 + write_hashes(tv, dir, "metadata.xml", "MISC", m, NULL);
211
212 fflush(m);
213 fclose(m);
214
215 + if (stat(manifest, &s)) {
216 + tv[0].tv_sec = 0;
217 + tv[0].tv_usec = 0;
218 + } else {
219 + tv[0].tv_sec = s.st_atim.tv_sec;
220 + tv[0].tv_usec = s.st_atim.tv_nsec / 1000;
221 + tv[1].tv_sec = s.st_mtim.tv_sec;
222 + tv[1].tv_usec = s.st_mtim.tv_nsec / 1000;
223 + }
224 +
225 rename(newmanifest, manifest);
226 if (tv[0].tv_sec != 0) {
227 /* restore dir mtime, and set Manifest mtime to match it */