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: Wed, 29 Nov 2017 14:38:30
Message-Id: 1511965740.bb8b83447563ef869f083703e01ad9d6fdceb1cb.grobian@gentoo
1 commit: bb8b83447563ef869f083703e01ad9d6fdceb1cb
2 Author: Fabian Groffen <grobian <AT> gentoo <DOT> org>
3 AuthorDate: Wed Nov 29 14:28:01 2017 +0000
4 Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org>
5 CommitDate: Wed Nov 29 14:29:00 2017 +0000
6 URL: https://gitweb.gentoo.org/repo/proj/prefix.git/commit/?id=bb8b8344
7
8 hashgen: first pass on generating cascading Manifest.gz files
9
10 scripts/rsync-generation/hashgen.c | 215 +++++++++++++++++++++++++++++--------
11 1 file changed, 173 insertions(+), 42 deletions(-)
12
13 diff --git a/scripts/rsync-generation/hashgen.c b/scripts/rsync-generation/hashgen.c
14 index ddc52752b4..68d5575ad2 100644
15 --- a/scripts/rsync-generation/hashgen.c
16 +++ b/scripts/rsync-generation/hashgen.c
17 @@ -2,6 +2,7 @@
18 #include <stdio.h>
19 #include <string.h>
20 #include <strings.h>
21 +#include <ctype.h>
22 #include <dirent.h>
23 #include <errno.h>
24 #include <sys/stat.h>
25 @@ -10,14 +11,16 @@
26 #include <openssl/sha.h>
27 #include <openssl/whrlpool.h>
28 #include <blake2.h>
29 +#include <zlib.h>
30
31 /* Generate thick Manifests based on thin Manifests */
32
33 /* In order to build this program, the following packages are required:
34 * - app-crypt/libb2 (for BLAKE2, for as long as openssl doesn't include it)
35 * - dev-libs/openssl (for SHA, WHIRLPOOL)
36 + * - sys-libs/zlib (for compressing Manifest files)
37 * compile like this
38 - * ${CC} -o hashgen -fopenmp ${CFLAGS} -lssl -lcrypto -lb2 hashgen.c
39 + * ${CC} -o hashgen -fopenmp ${CFLAGS} -lssl -lcrypto -lb2 -lz hashgen.c
40 */
41
42 enum hash_impls {
43 @@ -26,7 +29,8 @@ enum hash_impls {
44 HASH_WHIRLPOOL = 1<<2,
45 HASH_BLAKE2B = 1<<3
46 };
47 -/* default changed from sha256, sha512, whirlpool to blake2b, sha512 */
48 +/* default changed from sha256, sha512, whirlpool
49 + * to blake2b, sha512 on 2017-11-21 */
50 static int hashes = HASH_BLAKE2B | HASH_SHA512;
51
52 static inline void
53 @@ -39,16 +43,21 @@ hex_hash(char *out, const unsigned char *buf, const int length)
54 }
55
56 static void
57 -write_hashes(const char *root, const char *name, const char *type, FILE *m)
58 +write_hashes(
59 + const char *root,
60 + const char *name,
61 + const char *type,
62 + FILE *m,
63 + gzFile gm)
64 {
65 FILE *f;
66 - char fname[8096];
67 + char fname[8192];
68 size_t flen = 0;
69 char sha256[(SHA256_DIGEST_LENGTH * 2) + 1];
70 char sha512[(SHA512_DIGEST_LENGTH * 2) + 1];
71 char whrlpl[(WHIRLPOOL_DIGEST_LENGTH * 2) + 1];
72 char blak2b[(BLAKE2B_OUTBYTES * 2) + 1];
73 - char data[8096];
74 + char data[8192];
75 size_t len;
76 SHA256_CTX s256;
77 SHA512_CTX s512;
78 @@ -121,28 +130,37 @@ write_hashes(const char *root, const char *name, const char *type, FILE *m)
79 if (hashes & HASH_BLAKE2B) {
80 unsigned char blak2bbuf[BLAKE2B_OUTBYTES];
81 blake2b_final(&bl2b, blak2bbuf, BLAKE2B_OUTBYTES);
82 - hex_hash(blak2b, blak2bbuf, WHIRLPOOL_DIGEST_LENGTH);
83 + hex_hash(blak2b, blak2bbuf, BLAKE2B_OUTBYTES);
84 }
85 }
86 }
87 fclose(f);
88
89 - fprintf(m, "%s %s %zd",type, name, flen);
90 + len = snprintf(data, sizeof(data), "%s %s %zd", type, name, flen);
91 if (hashes & HASH_BLAKE2B)
92 - fprintf(m, " BLAKE2B %s", blak2b);
93 + len += snprintf(data + len, sizeof(data) - len,
94 + " BLAKE2B %s", blak2b);
95 if (hashes & HASH_SHA256)
96 - fprintf(m, " SHA256 %s", sha256);
97 + len += snprintf(data + len, sizeof(data) - len,
98 + " SHA256 %s", sha256);
99 if (hashes & HASH_SHA512)
100 - fprintf(m, " SHA512 %s", sha512);
101 + len += snprintf(data + len, sizeof(data) - len,
102 + " SHA512 %s", sha512);
103 if (hashes & HASH_WHIRLPOOL)
104 - fprintf(m, " WHIRLPOOL %s", whrlpl);
105 - fprintf(m, "\n");
106 + len += snprintf(data + len, sizeof(data) - len,
107 + " WHIRLPOOL %s", whrlpl);
108 + len += snprintf(data + len, sizeof(data) - len, "\n");
109 +
110 + if (m != NULL)
111 + fwrite(data, 1, len, m);
112 + if (gm != NULL)
113 + gzwrite(gm, data, len);
114 }
115
116 static char
117 process_files(const char *dir, const char *off, FILE *m)
118 {
119 - char path[8096];
120 + char path[8192];
121 DIR *d;
122 struct dirent *e;
123
124 @@ -157,7 +175,7 @@ process_files(const char *dir, const char *off, FILE *m)
125 if (process_files(dir, path, m))
126 continue;
127 /* regular file */
128 - write_hashes(dir, path, "AUX", m);
129 + write_hashes(dir, path, "AUX", m, NULL);
130 }
131 closedir(d);
132 return 1;
133 @@ -166,17 +184,124 @@ process_files(const char *dir, const char *off, FILE *m)
134 }
135 }
136
137 -static void
138 +static int
139 +parse_layout_conf(const char *path)
140 +{
141 + FILE *f;
142 + char buf[8192];
143 + size_t len = 0;
144 + size_t sz;
145 + char *p;
146 + char *q;
147 + char *tok;
148 + char *last_nl;
149 + int ret = 0;
150 +
151 + if ((f = fopen(path, "r")) == NULL)
152 + return 0;
153 +
154 + /* read file, examine lines after encountering a newline, that is,
155 + * if the file doesn't end with a newline, the final bit is ignored */
156 + while (sz = fread(buf + len, 1, sizeof(buf) - len, f) > 0) {
157 + len += sz;
158 + last_nl = NULL;
159 + for (p = buf; p - buf < len; p++) {
160 + if (*p == '\n') {
161 + last_nl = p;
162 + sz = strlen("manifest-hashes");
163 + if (strncmp(buf, "manifest-hashes", sz))
164 + continue;
165 + if ((q = strchr(buf + sz, '=')) == NULL)
166 + continue;
167 + q++;
168 + while (isspace((int)*q))
169 + q++;
170 + /* parse the tokens, whitespace separated */
171 + tok = q;
172 + do {
173 + while (!isspace((int)*q))
174 + q++;
175 + sz = q - tok;
176 + if (strncmp(tok, "SHA256", sz) == 0) {
177 + ret |= HASH_SHA256;
178 + } else if (strncmp(tok, "SHA512", sz) == 0) {
179 + ret |= HASH_SHA512;
180 + } else if (strncmp(tok, "WHIRLPOOL", sz) == 0) {
181 + ret |= HASH_WHIRLPOOL;
182 + } else if (strncmp(tok, "BLAKE2B", sz) == 0) {
183 + ret |= HASH_BLAKE2B;
184 + }
185 + while (isspace((int)*q) && *q != '\n')
186 + q++;
187 + tok = q;
188 + } while (*q != '\n');
189 + /* got it, expect only once, so stop processing */
190 + fclose(f);
191 + return ret;
192 + }
193 + }
194 + if (last_nl != NULL) {
195 + last_nl++; /* skip \n */
196 + len = last_nl - buf;
197 + memmove(buf, last_nl, len);
198 + } else {
199 + /* too long line, just skip */
200 + len = 0;
201 + }
202 + }
203 +
204 + fclose(f);
205 + return 0;
206 +}
207 +
208 +static char *str_manifest = "Manifest";
209 +static char *str_manifest_gz = "Manifest.gz";
210 +static char *
211 process_dir(const char *dir)
212 {
213 - char manifest[8096];
214 + char manifest[8192];
215 FILE *f;
216 DIR *d;
217 struct dirent *e;
218 - char path[8096];
219 + char path[8192];
220 + int newhashes;
221 + char global_manifest = 0;
222 + struct stat s;
223 + struct timeval tv[2];
224 +
225 + /* set mtime of Manifest(.gz) to the one of the parent dir, this way
226 + * we ensure the Manifest gets mtime bumped upon any change made
227 + * to the directory, that is, a DIST change (Manifest itself) or
228 + * any other change (ebuild, files, metadata) */
229 + if (stat(dir, &s)) {
230 + tv[0].tv_sec = 0;
231 + tv[0].tv_usec = 0;
232 + } else {
233 + tv[0].tv_sec = s.st_atim.tv_sec;
234 + tv[0].tv_usec = s.st_atim.tv_nsec / 1000;
235 + tv[1].tv_sec = s.st_mtim.tv_sec;
236 + tv[1].tv_usec = s.st_mtim.tv_nsec / 1000;
237 + }
238 +
239 + snprintf(path, sizeof(path), "%s/metadata/layout.conf", dir);
240 + if ((newhashes = parse_layout_conf(path)) != 0) {
241 + global_manifest = 1;
242 + hashes = newhashes;
243 + }
244
245 snprintf(manifest, sizeof(manifest), "%s/Manifest", dir);
246 if ((f = fopen(manifest, "r")) == NULL) {
247 + gzFile mf;
248 +
249 + /* open up a gzipped Manifest to keep the hashes of the
250 + * Manifests in the subdirs */
251 + snprintf(manifest, sizeof(manifest), "%s/Manifest.gz", dir);
252 + if ((mf = gzopen(manifest, "wb9")) == NULL) {
253 + fprintf(stderr, "failed to open file '%s' for writing: %s\n",
254 + manifest, strerror(errno));
255 + return NULL;
256 + }
257 +
258 /* recurse into subdirs */
259 if ((d = opendir(dir)) != NULL) {
260 struct stat s;
261 @@ -184,38 +309,42 @@ process_dir(const char *dir)
262 if (e->d_name[0] == '.')
263 continue;
264 snprintf(path, sizeof(path), "%s/%s", dir, e->d_name);
265 - if (!stat(path, &s) && s.st_mode & S_IFDIR)
266 - process_dir(path);
267 + if (!stat(path, &s)) {
268 + if (s.st_mode & S_IFDIR) {
269 + char *mfest = process_dir(path);
270 + if (mfest == NULL) {
271 + gzclose(mf);
272 + return NULL;
273 + }
274 + snprintf(path, sizeof(path), "%s/%s", e->d_name, mfest);
275 + write_hashes(dir, path, "MANIFEST", NULL, mf);
276 + } else if (s.st_mode & S_IFREG) {
277 + write_hashes(dir, e->d_name, "DATA", NULL, mf);
278 + }
279 + }
280 }
281 closedir(d);
282 }
283 +
284 + gzclose(mf);
285 + if (tv[0].tv_sec != 0) {
286 + /* restore dir mtime, and set Manifest mtime to match it */
287 + utimes(manifest, tv);
288 + utimes(dir, tv);
289 + }
290 +
291 + return str_manifest_gz;
292 } else {
293 /* this looks like an ebuild dir, so update the Manifest */
294 FILE *m;
295 - char newmanifest[8096];
296 - char buf[8096];
297 - struct stat s;
298 - struct timeval tv[2];
299 -
300 - /* set mtime of Manifest to the one of the parent dir, this way
301 - * we ensure the Manifest gets mtime bumped upon any change made
302 - * to the directory, that is, a DIST change (Manifest itself) or
303 - * any other change (ebuild, files, metadata) */
304 - if (stat(dir, &s)) {
305 - tv[0].tv_sec = 0;
306 - tv[0].tv_usec = 0;
307 - } else {
308 - tv[0].tv_sec = s.st_atim.tv_sec;
309 - tv[0].tv_usec = s.st_atim.tv_nsec / 1000;
310 - tv[1].tv_sec = s.st_mtim.tv_sec;
311 - tv[1].tv_usec = s.st_mtim.tv_nsec / 1000;
312 - }
313 + char newmanifest[8192];
314 + char buf[8192];
315
316 snprintf(newmanifest, sizeof(newmanifest), "%s/.Manifest.new", dir);
317 if ((m = fopen(newmanifest, "w")) == NULL) {
318 fprintf(stderr, "failed to open file '%s' for writing: %s\n",
319 newmanifest, strerror(errno));
320 - return;
321 + return NULL;
322 }
323
324 /* we know the Manifest is sorted, and stuff in files/ is
325 @@ -232,7 +361,7 @@ process_dir(const char *dir)
326 fprintf(stderr, "failed to write to %s/.Manifest.new: %s\n",
327 dir, strerror(errno));
328 fclose(f);
329 - return;
330 + return NULL;
331 }
332 }
333 fclose(f);
334 @@ -246,13 +375,13 @@ process_dir(const char *dir)
335 continue;
336 if (strcmp(e->d_name + strlen(e->d_name) - 7, ".ebuild") != 0)
337 continue;
338 - write_hashes(dir, e->d_name, "EBUILD", m);
339 + write_hashes(dir, e->d_name, "EBUILD", m, NULL);
340 }
341 closedir(d);
342 }
343
344 - write_hashes(dir, "ChangeLog", "MISC", m);
345 - write_hashes(dir, "metadata.xml", "MISC", m);
346 + write_hashes(dir, "ChangeLog", "MISC", m, NULL);
347 + write_hashes(dir, "metadata.xml", "MISC", m, NULL);
348
349 fflush(m);
350 fclose(m);
351 @@ -263,6 +392,8 @@ process_dir(const char *dir)
352 utimes(manifest, tv);
353 utimes(dir, tv);
354 }
355 +
356 + return str_manifest;
357 }
358 }