Support using a "crib tree" for speeding up
diff --git a/mkzftree.1 b/mkzftree.1
index f7b70c0..cedf453 100644
--- a/mkzftree.1
+++ b/mkzftree.1
@@ -50,6 +50,17 @@
Do not cross filesystem boundaries, and do not create directory stubs
at mount points.
.TP
+\fB\-C\fP \fIpath\fP, \fB\-\-crib-path\fP \fIpath\fP
+Steal ("crib") files from another directory if it looks (based on
+name, size, type and modification time) like they match entries in the
+new filesystem. The "crib tree" is usually the compressed version of
+an older version of the same workload; this thus allows for
+"incremental rebuilds" of a compressed filesystem tree. The files are
+hardlinked from the crib tree to the output tree, so if it is
+desirable to keep the link count correct the crib path should be
+deleted before running \fBmkisofs\fP. The crib tree must be on the
+same filesystem as the output tree.
+.TP
\fB\-l\fP, \fB\-\-local\fP
Do not recurse into subdirectories, but create the directories
themselves.
diff --git a/mkzftree.c b/mkzftree.c
index f98904c..8adfdb7 100644
--- a/mkzftree.c
+++ b/mkzftree.c
@@ -103,6 +103,7 @@
{ "parallelism", 1, 0, 'p' },
{ "one-filesystem", 0, 0, 'x' },
{ "strict-one-filesystem", 0, 0, 'X' },
+ { "crib-tree", 1, 0, 'C' },
{ "local", 0, 0, 'l' },
{ "strict-local", 0, 0, 'L' },
{ "file", 0, 0, 'F' },
@@ -130,6 +131,7 @@
LO(" --parallelism # ")" -p # Process up to # files in parallel\n"
LO(" --one-filesystem ")" -x Do not cross filesystem boundaries\n"
LO(" --strict-one-filesystem")" -X Same as -x, but don't create stubs dirs\n"
+ LO(" --crib-tree ")" -C Steal \"crib\" files from an old tree\n"
LO(" --local ")" -l Do not recurse into subdirectoires\n"
LO(" --strict-local ")" -L Same as -l, but don't create stubs dirs\n"
LO(" --file ")" -F Operate possibly on a single file\n"
@@ -158,7 +160,7 @@
int main(int argc, char *argv[])
{
- const char *in, *out;
+ const char *in, *out, *crib = NULL;
struct stat st;
struct utimbuf ut;
int optch, err;
@@ -191,6 +193,9 @@
case 'u':
opt.munger = block_uncompress_file;
break;
+ case 'C':
+ crib = optarg;
+ break;
case 'p':
opt.parallel = opt_atoi(optarg);
break;
@@ -238,7 +243,7 @@
exit(EX_NOINPUT);
}
- err = munge_entry(in, out, NULL);
+ err = munge_entry(in, out, crib, NULL);
} else {
/* Special case: we use stat() for the root, not lstat() */
if ( stat(in, &st) ) {
@@ -250,7 +255,7 @@
exit(EX_DATAERR);
}
- err = munge_tree(in, out);
+ err = munge_tree(in, out, crib);
}
wait_for_all_workers();
diff --git a/mkzftree.h b/mkzftree.h
index 0034600..f954e6f 100644
--- a/mkzftree.h
+++ b/mkzftree.h
@@ -49,6 +49,7 @@
vl_quiet, /* No messages */
vl_error, /* Error messages only */
vl_filename, /* Display filenames */
+ vl_crib, /* Cribbing files */
};
#define default_verbosity vl_error
struct cmdline_options {
@@ -66,8 +67,8 @@
extern struct cmdline_options opt;
/* walk.c */
-int munge_tree(const char *, const char *);
-int munge_entry(const char *, const char *, const struct stat *);
+int munge_tree(const char *, const char *, const char *);
+int munge_entry(const char *, const char *, const char *, const struct stat *);
/* workers.c */
void wait_for_all_workers(void);
diff --git a/walk.c b/walk.c
index 137572b..569371f 100644
--- a/walk.c
+++ b/walk.c
@@ -1,7 +1,7 @@
#ident "$Id$"
/* ----------------------------------------------------------------------- *
*
- * Copyright 2001 H. Peter Anvin - All Rights Reserved
+ * Copyright 2001-2002 H. Peter Anvin - All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -28,13 +28,53 @@
#include <sys/stat.h>
#include <sys/types.h>
#include "mkzftree.h"
+#include "iso9660.h"
-static int munge_path(const char *inpath, const char *outpath, struct stat *st)
+static int munge_file(const char *inpath, const char *outpath,
+ const char *cribpath, struct stat *st)
{
FILE *in, *out;
int err = 0;
struct utimbuf ut;
+ if ( cribpath ) {
+ struct stat cst;
+ struct compressed_file_header cfh;
+
+ /* Compare as much as we realistically can */
+ if ( !stat(cribpath, &cst) &&
+ st->st_mode == cst.st_mode &&
+ st->st_uid == cst.st_uid &&
+ st->st_gid == cst.st_gid &&
+ st->st_mtime == cst.st_mtime ) {
+ if ( (in = fopen(cribpath, "rb")) ) {
+ int e = fread(&cfh, 1, sizeof cfh, in);
+ fclose(in);
+ /* Attempt to restore the atime */
+ ut.actime = cst.st_atime;
+ ut.modtime = cst.st_mtime;
+ utime(cribpath, &ut);
+
+ if ( (e == sizeof cfh &&
+ !memcmp(cfh.magic, zisofs_magic, sizeof zisofs_magic) &&
+ (off_t)get_731(cfh.uncompressed_len) == st->st_size) ||
+ (st->st_size == cst.st_size &&
+ (e < (int)(sizeof zisofs_magic) ||
+ memcmp(cfh.magic, zisofs_magic, sizeof zisofs_magic))) ) {
+ /* File is cribbable. Steal it. */
+ if ( !link(cribpath, outpath) ) {
+ message(vl_crib, "crib: %s -> %s\n", cribpath, outpath);
+ ut.actime = st->st_atime;
+ ut.modtime = st->st_mtime;
+ utime(outpath, &ut); /* Set the the atime */
+
+ return 0;
+ }
+ }
+ }
+ }
+ }
+
in = fopen(inpath, "rb");
if ( !in )
return EX_NOINPUT;
@@ -49,19 +89,12 @@
fclose(in);
fclose(out);
-#ifdef HAVE_LCHOWN
- lchown(outpath, st->st_uid, st->st_gid);
-#endif
- if ( !S_ISLNK(st->st_mode) ) {
-#ifndef HAVE_LCHOWN
- chown(outpath, st->st_uid, st->st_gid);
-#endif
- chmod(outpath, st->st_mode);
- ut.actime = st->st_atime;
- ut.modtime = st->st_mtime;
- utime(outpath, &ut);
- }
-
+ chown(outpath, st->st_uid, st->st_gid);
+ chmod(outpath, st->st_mode);
+ ut.actime = st->st_atime;
+ ut.modtime = st->st_mtime;
+ utime(outpath, &ut);
+
end_worker(err);
} else {
fclose(in);
@@ -71,9 +104,10 @@
return err;
}
-int munge_tree(const char *intree, const char *outtree)
+int munge_tree(const char *intree, const char *outtree, const char *cribtree)
{
- char *in_path, *out_path, *in_file, *out_file;
+ char *in_path, *out_path, *crib_path;
+ char *in_file, *out_file, *crib_file;
DIR *thisdir;
struct dirent *dirent;
struct stat dirst;
@@ -82,17 +116,24 @@
/* Construct buffers with the common filename prefix, and point to the end */
in_path = xmalloc(strlen(intree) + NAME_MAX + 2);
- out_path = xmalloc(strlen(outtree) + NAME_MAX + 2);
-
strcpy(in_path, intree);
- strcpy(out_path, outtree);
-
in_file = strchr(in_path, '\0');
- out_file = strchr(out_path, '\0');
-
*in_file++ = '/';
+
+ out_path = xmalloc(strlen(outtree) + NAME_MAX + 2);
+ strcpy(out_path, outtree);
+ out_file = strchr(out_path, '\0');
*out_file++ = '/';
+ if ( cribtree ) {
+ crib_path = xmalloc(strlen(cribtree) + NAME_MAX + 2);
+ strcpy(crib_path, cribtree);
+ crib_file = strchr(crib_path, '\0');
+ *crib_file++ = '/';
+ } else {
+ crib_path = crib_file = NULL;
+ }
+
/* Get directory information */
if ( stat(intree, &dirst) ) {
message(vl_error, "%s: Failed to stat directory %s: %s\n",
@@ -122,8 +163,10 @@
strcpy(in_file, dirent->d_name);
strcpy(out_file, dirent->d_name);
+ if ( crib_file )
+ strcpy(crib_file, dirent->d_name);
- err = munge_entry(in_path, out_path, &dirst);
+ err = munge_entry(in_path, out_path, crib_path, &dirst);
if ( err )
break;
}
@@ -136,7 +179,8 @@
}
-int munge_entry(const char *in_path, const char *out_path, const struct stat *dirst)
+int munge_entry(const char *in_path, const char *out_path,
+ const char *crib_path, const struct stat *dirst)
{
struct stat st;
struct utimbuf ut;
@@ -165,7 +209,7 @@
}
} else {
/* First encounter, compress and enter into hash */
- if ( (err = munge_path(in_path, out_path, &st)) != 0 ) {
+ if ( (err = munge_file(in_path, out_path, crib_path, &st)) != 0 ) {
message(vl_error, "%s: %s: %s", program, in_path, strerror(errno));
return err;
}
@@ -173,7 +217,7 @@
}
} else {
/* Singleton file; no funnies */
- if ( (err = munge_path(in_path, out_path, &st)) != 0 ) {
+ if ( (err = munge_file(in_path, out_path, crib_path, &st)) != 0 ) {
message(vl_error, "%s: %s: %s", program, in_path, strerror(errno));
return err;
}
@@ -182,7 +226,7 @@
/* Recursion: see recursion */
if ( !opt.onedir &&
(!opt.onefs || (dirst && dirst->st_dev == st.st_dev)) ) {
- if ( (err = munge_tree(in_path, out_path)) != 0 )
+ if ( (err = munge_tree(in_path, out_path, crib_path)) != 0 )
return err;
} else if ( opt.do_mkdir ) {
/* Create stub directories */
@@ -244,7 +288,7 @@
}
}
- /* This is done by munge_path() for files */
+ /* This is done by munge_file() for files */
if ( !S_ISREG(st.st_mode) ) {
#ifdef HAVE_LCHOWN
if ( lchown(out_path, st.st_uid, st.st_gid) && opt.sloppy && !err ) {