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 |
} |