summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFabian Groffen <grobian@gentoo.org>2018-03-03 22:42:43 +0100
committerFabian Groffen <grobian@gentoo.org>2018-03-03 22:42:43 +0100
commit4d65987d63d5c2e573ae2be35dc5427950ff3677 (patch)
treeaef0c57f630ef331fcf18bb08b1c8b7627c0b491 /scripts
parentscripts/rsync-generation/hashgen: report some stats (diff)
downloadprefix-4d65987d63d5c2e573ae2be35dc5427950ff3677.tar.gz
prefix-4d65987d63d5c2e573ae2be35dc5427950ff3677.tar.bz2
prefix-4d65987d63d5c2e573ae2be35dc5427950ff3677.zip
scripts/rsync-generation/hashgen: rewrite hashgen to be simpler
a logic rewrite was necessary to be able to properly generate the right type of Manifest for the level at hand
Diffstat (limited to 'scripts')
-rw-r--r--scripts/rsync-generation/hashgen.c424
1 files changed, 256 insertions, 168 deletions
diff --git a/scripts/rsync-generation/hashgen.c b/scripts/rsync-generation/hashgen.c
index 446299f92e..7bedc75ca4 100644
--- a/scripts/rsync-generation/hashgen.c
+++ b/scripts/rsync-generation/hashgen.c
@@ -342,13 +342,12 @@ write_hashes_dir(
}
static char
-process_files(const char *dir, const char *off, FILE *m)
+process_files(struct timeval *tv, const char *dir, const char *off, FILE *m)
{
char path[8192];
char **dentries;
size_t dentrieslen;
size_t i;
- struct timeval tv[2]; /* dummy, won't use its result */
snprintf(path, sizeof(path), "%s/%s", dir, off);
if (list_dir(&dentries, &dentrieslen, path) == 0) {
@@ -356,7 +355,7 @@ process_files(const char *dir, const char *off, FILE *m)
snprintf(path, sizeof(path), "%s%s%s",
off, *off == '\0' ? "" : "/", dentries[i]);
free(dentries[i]);
- if (process_files(dir, path, m) == 0)
+ if (process_files(tv, dir, path, m) == 0)
continue;
/* regular file */
write_hashes(tv, dir, path, "AUX", m, NULL);
@@ -452,22 +451,22 @@ parse_layout_conf(const char *path)
static char *str_manifest = "Manifest";
static char *str_manifest_gz = "Manifest.gz";
static char *str_manifest_files_gz = "Manifest.files.gz";
+enum type_manifest {
+ GLOBAL_MANIFEST, /* Manifest.files.gz + Manifest */
+ SUBTREE_MANIFEST, /* Manifest.gz for recursive list of files */
+ EBUILD_MANIFEST, /* Manifest thick from thin */
+ CATEGORY_MANIFEST /* Manifest.gz with Manifest entries */
+};
static char *
-process_dir_gen(const char *dir)
+generate_dir(const char *dir, enum type_manifest mtype)
{
- char manifest[8192];
FILE *f;
char path[8192];
- const char *p;
- int newhashes;
- enum {
- GLOBAL_MANIFEST, /* Manifest.files.gz + Manifest */
- SUBTREE_MANIFEST, /* Manifest.gz for recursive list of files */
- EBUILD_MANIFEST, /* Manifest thick from thin */
- CATEGORY_MANIFEST /* Manifest.gz with Manifest entries */
- } type_manifest;
struct stat s;
struct timeval tv[2];
+ char **dentries;
+ size_t dentrieslen;
+ size_t i;
/* our timestamp strategy is as follows:
* - when a Manifest exists, use its timestamp
@@ -482,155 +481,216 @@ process_dir_gen(const char *dir)
tv[1].tv_sec = 0;
tv[1].tv_usec = 0;
- type_manifest = CATEGORY_MANIFEST;
- snprintf(path, sizeof(path), "%s/metadata/layout.conf", dir);
- if ((newhashes = parse_layout_conf(path)) != 0) {
- type_manifest = GLOBAL_MANIFEST;
- hashes = newhashes;
- } else {
- if ((p = strrchr(dir, '/')) != NULL) {
- p++;
- } else {
- p = dir;
+ if (mtype == GLOBAL_MANIFEST) {
+ char *mfest;
+ size_t len;
+ gzFile mf;
+ time_t rtime;
+
+ snprintf(path, sizeof(path), "%s/%s", dir, str_manifest_files_gz);
+ if ((mf = gzopen(path, "wb9")) == NULL) {
+ fprintf(stderr, "failed to open file '%s' for writing: %s\n",
+ path, strerror(errno));
+ return NULL;
}
- if (
- strcmp(p, "eclass") == 0 ||
- strcmp(p, "licenses") == 0 ||
- strcmp(p, "metadata") == 0 ||
- strcmp(p, "profiles") == 0 ||
- strcmp(p, "scripts") == 0
- )
- {
- type_manifest = SUBTREE_MANIFEST;
+ /* These "IGNORE" entries are taken from gx86, there is no
+ * standardisation on this, on purpose, apparently. */
+ len = snprintf(path, sizeof(path),
+ "IGNORE distfiles\n"
+ "IGNORE local\n"
+ "IGNORE lost+found\n"
+ "IGNORE packages\n");
+ gzwrite(mf, path, len);
+
+ if (list_dir(&dentries, &dentrieslen, dir) != 0)
+ return NULL;
+
+ for (i = 0; i < dentrieslen; i++) {
+ /* ignore existing Manifests */
+ if (strcmp(dentries[i], str_manifest_files_gz) == 0 ||
+ strcmp(dentries[i], str_manifest) == 0)
+ {
+ free(dentries[i]);
+ continue;
+ }
+
+ snprintf(path, sizeof(path), "%s/%s", dir, dentries[i]);
+
+ mfest = NULL;
+ if (!stat(path, &s)) {
+ if (s.st_mode & S_IFDIR) {
+ if (
+ strcmp(dentries[i], "eclass") == 0 ||
+ strcmp(dentries[i], "licenses") == 0 ||
+ strcmp(dentries[i], "metadata") == 0 ||
+ strcmp(dentries[i], "profiles") == 0 ||
+ strcmp(dentries[i], "scripts") == 0
+ )
+ {
+ mfest = generate_dir(path, SUBTREE_MANIFEST);
+ } else {
+ mfest = generate_dir(path, CATEGORY_MANIFEST);
+ }
+
+ if (mfest == NULL) {
+ fprintf(stderr, "generating Manifest for %s failed!\n",
+ path);
+ gzclose(mf);
+ return NULL;
+ }
+
+ snprintf(path, sizeof(path), "%s/%s",
+ dentries[i], mfest);
+ write_hashes(tv, dir, path, "MANIFEST", NULL, mf);
+ } else if (s.st_mode & S_IFREG) {
+ write_hashes(tv, dir, dentries[i], "DATA", NULL, mf);
+ } /* ignore other "things" (like symlinks) as they
+ don't belong in a tree */
+ } else {
+ fprintf(stderr, "stat(%s) failed: %s\n",
+ path, strerror(errno));
+ }
+ free(dentries[i]);
}
- }
+ free(dentries);
+ gzclose(mf);
- /* If a Manifest file exists, this is an ebuild dir, unless we
- * already established this is the top level dir which also has a
- * Manifest file. */
- snprintf(manifest, sizeof(manifest), "%s/%s", dir, str_manifest);
- if (type_manifest == GLOBAL_MANIFEST ||
- (f = fopen(manifest, "r")) == NULL)
- {
- /* all of these types (GLOBAL, SUBTREE, CATEGORY) have a gzipped
- * Manifest */
+ if (tv[0].tv_sec != 0) {
+ snprintf(path, sizeof(path), "%s/%s", dir, str_manifest_files_gz);
+ utimes(path, tv);
+ }
+
+ /* create global Manifest */
+ snprintf(path, sizeof(path), "%s/%s", dir, str_manifest);
+ if ((f = fopen(path, "w")) == NULL) {
+ fprintf(stderr, "failed to open file '%s' for writing: %s\n",
+ path, strerror(errno));
+ return NULL;
+ }
+
+ write_hashes(tv, dir, str_manifest_files_gz, "MANIFEST", f, NULL);
+ time(&rtime);
+ len = strftime(path, sizeof(path),
+ "TIMESTAMP %Y-%m-%dT%H:%M:%SZ\n", gmtime(&rtime));
+ fwrite(path, len, 1, f);
+ fflush(f);
+ fclose(f);
+
+ /* because we write a timestamp in Manifest, we don't mess with
+ * its mtime, else it would obviously lie */
+ return str_manifest_files_gz;
+ } else if (mtype == SUBTREE_MANIFEST) {
+ const char *ldir;
gzFile mf;
- char **dentries;
- size_t dentrieslen;
- size_t i;
- if (list_dir(&dentries, &dentrieslen, dir) == 0) {
- char *my_manifest = str_manifest_gz;
+ snprintf(path, sizeof(path), "%s/%s", dir, str_manifest_gz);
+ if ((mf = gzopen(path, "wb9")) == NULL) {
+ fprintf(stderr, "failed to open file '%s' for writing: %s\n",
+ path, strerror(errno));
+ return NULL;
+ }
- if (type_manifest == GLOBAL_MANIFEST)
- my_manifest = str_manifest_files_gz;
+ ldir = strrchr(dir, '/');
+ if (ldir == NULL)
+ ldir = dir;
+ if (strcmp(ldir, "metadata") == 0) {
+ size_t len;
+ len = snprintf(path, sizeof(path),
+ "IGNORE timestamp\n"
+ "IGNORE timestamp.chk\n"
+ "IGNORE timestamp.commit\n"
+ "IGNORE timestamp.x\n");
+ gzwrite(mf, path, len);
+ }
+
+ if (list_dir(&dentries, &dentrieslen, dir) != 0)
+ return NULL;
- snprintf(manifest, sizeof(manifest), "%s/%s", dir, my_manifest);
- if ((mf = gzopen(manifest, "wb9")) == NULL) {
- fprintf(stderr, "failed to open file '%s' for writing: %s\n",
- manifest, strerror(errno));
- return NULL;
+ for (i = 0; i < dentrieslen; i++) {
+ /* ignore existing Manifests */
+ if (strcmp(dentries[i], str_manifest_gz) == 0) {
+ free(dentries[i]);
+ continue;
}
- for (i = 0; i < dentrieslen; i++) {
- /* ignore existing Manifests */
- if (strcmp(dentries[i], my_manifest) == 0 ||
- strcmp(dentries[i], str_manifest) == 0)
- {
- free(dentries[i]);
- continue;
- }
+ if (write_hashes_dir(tv, dir, dentries[i], mf) != 0)
+ write_hashes(tv, dir, dentries[i], "DATA", NULL, mf);
+ free(dentries[i]);
+ }
- snprintf(path, sizeof(path), "%s/%s", dir, dentries[i]);
- if (!stat(path, &s)) {
- if (s.st_mode & S_IFDIR) {
- if (type_manifest == SUBTREE_MANIFEST) {
- write_hashes_dir(tv, dir, dentries[i], mf);
- if (strcmp(dentries[i], "metadata") == 0) {
- char buf[2048];
- size_t len;
- len = snprintf(buf, sizeof(buf),
- "IGNORE timestamp\n"
- "IGNORE timestamp.chk\n"
- "IGNORE timestamp.commit\n"
- "IGNORE timestamp.x\n");
- gzwrite(mf, buf, len);
- }
- free(dentries[i]);
- } else {
- char *mfest = process_dir_gen(path);
- if (mfest == NULL) {
- gzclose(mf);
- free(dentries[i]);
- return NULL;
- }
- snprintf(path, sizeof(path), "%s/%s",
- dentries[i], mfest);
- free(dentries[i]);
- write_hashes(tv, dir, path, "MANIFEST", NULL, mf);
- }
- } else if (s.st_mode & S_IFREG) {
- write_hashes(tv, dir, dentries[i], "DATA", NULL, mf);
- free(dentries[i]);
- }
- }
+ free(dentries);
+ gzclose(mf);
+
+ if (tv[0].tv_sec != 0) {
+ /* set Manifest and dir mtime to most recent file found */
+ snprintf(path, sizeof(path), "%s/%s", dir, str_manifest_gz);
+ utimes(path, tv);
+ utimes(dir, tv);
+ }
+
+ return str_manifest_gz;
+ } else if (mtype == CATEGORY_MANIFEST) {
+ char *mfest;
+ gzFile mf;
+
+ snprintf(path, sizeof(path), "%s/%s", dir, str_manifest_gz);
+ if ((mf = gzopen(path, "wb9")) == NULL) {
+ fprintf(stderr, "failed to open file '%s' for writing: %s\n",
+ path, strerror(errno));
+ return NULL;
+ }
+
+ if (list_dir(&dentries, &dentrieslen, dir) != 0)
+ return NULL;
+
+ for (i = 0; i < dentrieslen; i++) {
+ /* ignore existing Manifests */
+ if (strcmp(dentries[i], str_manifest_gz) == 0) {
+ free(dentries[i]);
+ continue;
}
- free(dentries);
- if (type_manifest == GLOBAL_MANIFEST) {
- char globmanifest[8192];
- char buf[2048];
- size_t len;
- FILE *m;
- time_t rtime;
- struct timeval ntv[2]; /* dummy, not used */
-
- len = snprintf(buf, sizeof(buf),
- "IGNORE distfiles\n"
- "IGNORE local\n"
- "IGNORE lost+found\n"
- "IGNORE packages\n");
- gzwrite(mf, buf, len);
- gzclose(mf);
-
- /* create global Manifest */
- snprintf(globmanifest, sizeof(globmanifest),
- "%s/%s", dir, str_manifest);
- if ((m = fopen(globmanifest, "w")) == NULL) {
- fprintf(stderr, "failed to open file '%s' "
- "for writing: %s\n",
- globmanifest, strerror(errno));
- return NULL;
- }
+ snprintf(path, sizeof(path), "%s/%s", dir, dentries[i]);
+ if (!stat(path, &s)) {
+ if (s.st_mode & S_IFDIR) {
+ mfest = generate_dir(path, EBUILD_MANIFEST);
+
+ if (mfest == NULL) {
+ fprintf(stderr, "generating Manifest for %s failed!\n",
+ path);
+ gzclose(mf);
+ return NULL;
+ }
- write_hashes(ntv, dir, my_manifest, "MANIFEST", m, NULL);
- time(&rtime);
- len = strftime(buf, sizeof(buf),
- "TIMESTAMP %Y-%m-%dT%H:%M:%SZ\n", gmtime(&rtime));
- fwrite(buf, len, 1, m);
- fflush(m);
- fclose(m);
+ snprintf(path, sizeof(path), "%s/%s",
+ dentries[i], mfest);
+ write_hashes(tv, dir, path, "MANIFEST", NULL, mf);
+ } else if (s.st_mode & S_IFREG) {
+ write_hashes(tv, dir, dentries[i], "DATA", NULL, mf);
+ } /* ignore other "things" (like symlinks) as they
+ don't belong in a tree */
} else {
- gzclose(mf);
+ fprintf(stderr, "stat(%s) failed: %s\n",
+ path, strerror(errno));
}
+ free(dentries[i]);
+ }
- if (tv[0].tv_sec != 0) {
- /* restore dir mtime, and set Manifest mtime to match it */
- utimes(manifest, tv);
- utimes(dir, tv);
- }
+ free(dentries);
+ gzclose(mf);
+
+ if (tv[0].tv_sec != 0) {
+ /* set Manifest and dir mtime to most ebuild dir found */
+ snprintf(path, sizeof(path), "%s/%s", dir, str_manifest_gz);
+ utimes(path, tv);
+ utimes(dir, tv);
}
return str_manifest_gz;
- } else {
- /* this looks like an ebuild dir, so update the Manifest */
- FILE *m;
+ } else if (mtype == EBUILD_MANIFEST) {
char newmanifest[8192];
- char buf[8192];
- char **dentries;
- size_t dentrieslen;
- size_t i;
+ FILE *m;
snprintf(newmanifest, sizeof(newmanifest), "%s/.Manifest.new", dir);
if ((m = fopen(newmanifest, "w")) == NULL) {
@@ -643,20 +703,30 @@ process_dir_gen(const char *dir)
* prefixed with AUX, hence, if it exists, we need to do it
* first */
snprintf(path, sizeof(path), "%s/files", dir);
- process_files(path, "", m);
-
- /* copy the DIST entries, we could do it unconditional, but this
- * way we can re-run without producing invalid Manifests */
- while (fgets(buf, sizeof(buf), f) != NULL) {
- if (strncmp(buf, "DIST ", 5) == 0)
- if (fwrite(buf, strlen(buf), 1, m) != 1) {
- fprintf(stderr, "failed to write to %s/.Manifest.new: %s\n",
- dir, strerror(errno));
- fclose(f);
- return NULL;
- }
+ process_files(tv, path, "", m);
+
+ /* the Manifest file may be missing in case there are no DIST
+ * entries to be stored */
+ snprintf(path, sizeof(path), "%s/%s", dir, str_manifest);
+ if (!stat(path, &s))
+ update_times(tv, &s);
+ f = fopen(path, "r");
+ if (f != NULL) {
+ /* copy the DIST entries, we could do it unconditional, but this
+ * way we can re-run without producing invalid Manifests */
+ while (fgets(path, sizeof(path), f) != NULL) {
+ if (strncmp(path, "DIST ", 5) == 0)
+ if (fwrite(path, strlen(path), 1, m) != 1) {
+ fprintf(stderr, "failed to write to "
+ "%s/.Manifest.new: %s\n",
+ dir, strerror(errno));
+ fclose(f);
+ fclose(m);
+ return NULL;
+ }
+ }
+ fclose(f);
}
- fclose(f);
if (list_dir(&dentries, &dentrieslen, dir) == 0) {
for (i = 0; i < dentrieslen; i++) {
@@ -678,25 +748,43 @@ process_dir_gen(const char *dir)
fflush(m);
fclose(m);
- if (stat(manifest, &s)) {
- tv[0].tv_sec = 0;
- tv[0].tv_usec = 0;
- } else {
- tv[0].tv_sec = s.st_atim.tv_sec;
- tv[0].tv_usec = s.st_atim.tv_nsec / 1000;
- tv[1].tv_sec = s.st_mtim.tv_sec;
- tv[1].tv_usec = s.st_mtim.tv_nsec / 1000;
- }
+ snprintf(path, sizeof(path), "%s/%s", dir, str_manifest);
+ rename(newmanifest, path);
- rename(newmanifest, manifest);
if (tv[0].tv_sec != 0) {
- /* restore dir mtime, and set Manifest mtime to match it */
- utimes(manifest, tv);
+ /* set Manifest and dir mtime to most recent file we found */
+ utimes(path, tv);
utimes(dir, tv);
}
return str_manifest;
+ } else {
+ return NULL;
+ }
+}
+
+static char *
+process_dir_gen(const char *dir)
+{
+ char path[8192];
+ int newhashes;
+
+ snprintf(path, sizeof(path), "%s/metadata/layout.conf", dir);
+ if ((newhashes = parse_layout_conf(path)) != 0) {
+ hashes = newhashes;
+ } else {
+ return "generation must be done on a full tree";
+ }
+
+ if (chdir(dir) != 0) {
+ fprintf(stderr, "cannot chdir() to %s: %s\n", dir, strerror(errno));
+ return "not a directory";
}
+
+ if (generate_dir(".\0", GLOBAL_MANIFEST) == NULL)
+ return "generation failed";
+
+ return NULL;
}
static char
@@ -1396,14 +1484,14 @@ main(int argc, char *argv[])
if (argc > 1) {
for (; arg < argc; arg++) {
rsn = runfunc(argv[arg]);
- if (runfunc == &process_dir_vrfy && rsn != NULL) {
+ if (rsn != NULL) {
printf("%s\n", rsn);
ret |= 1;
}
}
} else {
rsn = runfunc(".");
- if (runfunc == &process_dir_vrfy && rsn != NULL) {
+ if (rsn != NULL) {
printf("%s\n", rsn);
ret |= 1;
}