diff options
author | H. Peter Anvin <hpa@zytor.com> | 2001-07-27 15:37:08 +0000 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2001-07-27 15:37:08 +0000 |
commit | 79eb556198d5d655cdbc11f422ce7e673f25bfb0 (patch) | |
tree | f7f108cb38174ad1f8a431aba2ea44a4d2af671d | |
parent | 31dc00ec66c37d95e02913d4e785a287412e2b83 (diff) | |
download | zisofs-tools-79eb556198d5d655cdbc11f422ce7e673f25bfb0.tar.gz |
Reinstate recursion control and file root options.
-rw-r--r-- | iso9660.h | 5 | ||||
-rw-r--r-- | mkzftree.1 | 24 | ||||
-rw-r--r-- | mkzftree.c | 106 | ||||
-rw-r--r-- | mkzftree.h | 3 | ||||
-rw-r--r-- | walk.c | 219 |
5 files changed, 216 insertions, 141 deletions
@@ -36,11 +36,10 @@ unsigned int get_721(void *); void set_722(void *, unsigned int); unsigned int get_722(void *); void set_723(void *, unsigned int); -#define get_723(x) get_721(x) -void set_731(void *pnt, unsigned int); +void set_731(void *, unsigned int); unsigned int get_731(void *); void set_732(void *, unsigned int); unsigned int get_732(void *); void set_733(void *, unsigned int); +#define get_723(x) get_721(x) #define get_733(x) get_731(x) - @@ -41,10 +41,28 @@ Compress in parallel. The .I parallelism value indicates how many compression threads are allowed to run. .TP -\fB-x\fP, \fB\-\-one-filesystem\fP -Do not cross filesystem boundaries. +\fB\-x\fP, \fB\-\-one-filesystem\fP +Do not cross filesystem boundaries, but create directory stubs at +mount points. .TP -\fB-v\fP, \fB\-\-verbose\fP +\fB\-X\fP, \fB\-\-strict-one-filesystem\fP +Do not cross filesystem boundaries, and do not create directory stubs +at mount points. +.TP +\fB\-l\fP, \fB\-\-local\fP +Do not recurse into subdirectories, but create the directories +themselves. +.TP +\fB\-L\fP, \fB\-\-strict-local\fP +Do not recurse into subdirectories, and do not create directories. +.TP +\fB\-F\fP, \fB\-\-file\fP +Indicates that \fIINPUT\fP may not necessarily be a directory; this +allows operation on a single file. If \fI\-F\fP is specified, and +\fIINPUT\fP is a symlink, the symlink will be copied rather than +whatever it happens to point to. +.TP +\fB\-v\fP, \fB\-\-verbose\fP Increase the program verbosity. .TP \fB\-V\fP \fIvalue\fP, \fB\-\-verbosity\fP \fIvalue\fP @@ -80,6 +80,8 @@ int force = 0; /* Always compress */ int level = 9; /* Compression level */ int parallel = 0; /* Parallelism (0 = strictly serial) */ int onefs = 0; /* One filesystem only */ +int onedir = 0; /* One directory only */ +int do_mkdir = 1; /* Create stub directories */ enum verbosity verbosity = default_verbosity; /* Default verbosity */ munger_func munger = block_compress_file; /* Default action */ @@ -87,18 +89,22 @@ munger_func munger = block_compress_file; /* Default action */ const char *program; /* Long options */ -#define OPTSTRING "fl:up:xvqV:h" +#define OPTSTRING "fl:up:xXlLFvqV:h" #ifdef HAVE_GETOPT_LONG const struct option long_options[] = { - { "force", 0, 0, 'f' }, - { "level", 1, 0, 'l' }, - { "uncompress", 0, 0, 'u' }, - { "parallelism", 1, 0, 'p' }, - { "one-filesystem", 0, 0, 'x' }, - { "verbose", 0, 0, 'v' }, - { "quiet", 0, 0, 'q' }, - { "verbosity", 1, 0, 'V' }, - { "help", 0, 0, 'h' }, + { "force", 0, 0, 'f' }, + { "level", 1, 0, 'l' }, + { "uncompress", 0, 0, 'u' }, + { "parallelism", 1, 0, 'p' }, + { "one-filesystem", 0, 0, 'x' }, + { "strict-one-filesystem", 0, 0, 'X' }, + { "local", 0, 0, 'l' }, + { "strict-local", 0, 0, 'L' }, + { "file", 0, 0, 'F' }, + { "verbose", 0, 0, 'v' }, + { "quiet", 0, 0, 'q' }, + { "verbosity", 1, 0, 'V' }, + { "help", 0, 0, 'h' }, { 0, 0, 0, 0 } }; #define LO(X) X @@ -111,14 +117,18 @@ static void usage(enum verbosity level, int err) { message(level, "Usage: %s [options] intree outtree\n" - LO(" --force ")" -f Always compress, even if result is larger\n" - LO(" --level # ")" -z # Set compression level (1-9)\n" - LO(" --uncompress ")" -u Uncompress an already compressed tree\n" - LO(" --parallelism # ")" -p # Process up to # files in parallel\n" - LO(" --one-filesystem")" -x Do not cross filesystem boundaries\n" - LO(" --verbose ")" -v Increase message verbosity\n" - LO(" --verbosity # ")" -V # Set message verbosity to # (default = %d)\n" - LO(" --quiet ")" -q No messages, not even errors (-V 0)\n" + LO(" --force ")" -f Always compress, even if result is larger\n" + LO(" --level # ")" -z # Set compression level (1-9)\n" + LO(" --uncompress ")" -u Uncompress an already compressed tree\n" + 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(" --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" + LO(" --verbose ")" -v Increase message verbosity\n" + LO(" --verbosity # ")" -V # Set message verbosity to # (default = %d)\n" + LO(" --quiet ")" -q No messages, not even errors (-V 0)\n" ,program, (int)default_verbosity); exit(err); } @@ -142,6 +152,7 @@ int main(int argc, char *argv[]) struct stat st; struct utimbuf ut; int opt, err; + int file_root = 0; program = argv[0]; @@ -180,6 +191,22 @@ int main(int argc, char *argv[]) break; case 'x': onefs = 1; + do_mkdir = 1; + break; + case 'l': + onedir = 1; + do_mkdir = 1; + break; + case 'X': + onefs = 1; + do_mkdir = 0; + break; + case 'L': + onedir = 1; + do_mkdir = 0; + break; + case 'F': + file_root = 1; break; default: usage(vl_error, EX_USAGE); @@ -195,28 +222,39 @@ int main(int argc, char *argv[]) umask(077); - /* Special case: we use stat() for the root, not lstat() */ - if ( stat(in, &st) ) { - message(vl_error, "%s: %s: %s\n", program, in, strerror(errno)); - exit(EX_NOINPUT); - } - if ( !S_ISDIR(st.st_mode) ) { - message(vl_error, "%s: %s: Not a directory\n", program, in); - exit(EX_DATAERR); - } + if ( file_root ) { + if ( lstat(in, &st) ) { + message(vl_error, "%s: %s: %s\n", program, in, strerror(errno)); + exit(EX_NOINPUT); + } - err = munge_tree(in, out); + err = munge_entry(in, out, NULL); + } else { + /* Special case: we use stat() for the root, not lstat() */ + if ( stat(in, &st) ) { + message(vl_error, "%s: %s: %s\n", program, in, strerror(errno)); + exit(EX_NOINPUT); + } + if ( !S_ISDIR(st.st_mode) ) { + message(vl_error, "%s: %s: Not a directory\n", program, in); + exit(EX_DATAERR); + } + + err = munge_tree(in, out); + } wait_for_all_workers(); - + if ( err ) exit(err); - chown(out, st.st_uid, st.st_gid); - chmod(out, st.st_mode); - ut.actime = st.st_atime; - ut.modtime = st.st_mtime; - utime(out, &ut); + if ( !file_root ) { + chown(out, st.st_uid, st.st_gid); + chmod(out, st.st_mode); + ut.actime = st.st_atime; + ut.modtime = st.st_mtime; + utime(out, &ut); + } return 0; } @@ -49,6 +49,8 @@ extern int force; /* Always compress */ extern int level; /* Compression level */ extern int parallel; /* Parallelism (0 = strictly serial) */ extern int onefs; /* One filesystem only */ +extern int onedir; /* One directory only */ +extern int do_mkdir; /* Create stub directories */ extern munger_func munger; /* Default action */ enum verbosity { vl_quiet, /* No messages */ @@ -60,6 +62,7 @@ extern enum verbosity verbosity; /* Message verbosity */ /* walk.c */ int munge_tree(const char *, const char *); +int munge_entry(const char *, const char *, const struct stat *); /* workers.c */ void wait_for_all_workers(void); @@ -73,12 +73,10 @@ static int munge_path(const char *inpath, const char *outpath, struct stat *st) int munge_tree(const char *intree, const char *outtree) { - char buffer[BUFSIZ]; char *in_path, *out_path, *in_file, *out_file; DIR *thisdir; struct dirent *dirent; - struct stat st, dirst; - struct utimbuf ut; + struct stat dirst; int err = 0; /* Construct buffers with the common filename prefix, and point to the end */ @@ -121,126 +119,145 @@ int munge_tree(const char *intree, const char *outtree) if ( !strcmp(dirent->d_name, ".") || !strcmp(dirent->d_name, "..") ) continue; /* Ignore . and .. */ - + strcpy(in_file, dirent->d_name); strcpy(out_file, dirent->d_name); + + err = munge_entry(in_path, out_path, &dirst); + if ( err ) + break; + } + closedir(thisdir); + + free(in_path); + free(out_path); + + return err; +} - message(vl_filename, "%s -> %s\n", in_path, out_path); - if ( lstat(in_path, &st) ) { - message(vl_error, "%s: Failed to stat file %s: %s\n", - program, in_path, strerror(errno)); - err = EX_NOINPUT; - break; - } - - if ( S_ISREG(st.st_mode) ) { - if ( st.st_nlink > 1 ) { - /* Hard link. */ - const char *linkname; - - if ( (linkname = hash_find_file(&st)) != NULL ) { - /* We've seen it before, hard link it */ - - if ( link(linkname, out_path) ) { - message(vl_error, "%s: hard link %s -> %s failed: %s\n", - program, out_path, linkname, strerror(errno)); - err = EX_CANTCREAT; - break; - } - } else { - /* First encounter, compress and enter into hash */ - if ( (err = munge_path(in_path, out_path, &st)) != 0 ) { - message(vl_error, "%s: %s: %s", program, in_path, strerror(errno)); - break; - } - hash_insert_file(&st, out_path); +int munge_entry(const char *in_path, const char *out_path, const struct stat *dirst) +{ + struct stat st; + struct utimbuf ut; + int err = 0; + + message(vl_filename, "%s -> %s\n", in_path, out_path); + + if ( lstat(in_path, &st) ) { + message(vl_error, "%s: Failed to stat file %s: %s\n", + program, in_path, strerror(errno)); + return EX_NOINPUT; + } + + if ( S_ISREG(st.st_mode) ) { + if ( st.st_nlink > 1 ) { + /* Hard link. */ + const char *linkname; + + if ( (linkname = hash_find_file(&st)) != NULL ) { + /* We've seen it before, hard link it */ + + if ( link(linkname, out_path) ) { + message(vl_error, "%s: hard link %s -> %s failed: %s\n", + program, out_path, linkname, strerror(errno)); + return EX_CANTCREAT; } } else { - /* Singleton file; no funnies */ + /* First encounter, compress and enter into hash */ if ( (err = munge_path(in_path, out_path, &st)) != 0 ) { message(vl_error, "%s: %s: %s", program, in_path, strerror(errno)); - break; + return err; } + hash_insert_file(&st, out_path); } - } else if ( S_ISDIR(st.st_mode) ) { - /* Recursion: see recursion */ - /* Don't decend if -x is specified and st_dev is different */ - if ( !onefs || dirst.st_dev == st.st_dev ) { - if ( (err = munge_tree(in_path, out_path)) != 0 ) - break; - } - } else if ( S_ISLNK(st.st_mode) ) { - int chars; - if ( (chars = readlink(in_path, buffer, BUFSIZ)) < 0 ) { - message(vl_error, "%s: readlink failed for %s: %s\n", - program, in_path, strerror(errno)); - err = EX_NOINPUT; - break; + } else { + /* Singleton file; no funnies */ + if ( (err = munge_path(in_path, out_path, &st)) != 0 ) { + message(vl_error, "%s: %s: %s", program, in_path, strerror(errno)); + return err; } - buffer[chars] = '\0'; - if ( symlink(buffer, out_path) ) { - message(vl_error, "%s: symlink %s -> %s failed: %s\n", - program, out_path, buffer, strerror(errno)); - err = EX_CANTCREAT; - break; + } + } else if ( S_ISDIR(st.st_mode) ) { + /* Recursion: see recursion */ + if ( !onedir && (!onefs || (dirst && dirst->st_dev == st.st_dev)) ) { + if ( (err = munge_tree(in_path, out_path)) != 0 ) + return err; + } else if ( do_mkdir ) { + /* Create stub directories */ + if ( mkdir(out_path, st.st_mode) ) { + message(vl_error, "%s: %s: %s", program, out_path, strerror(errno)); + return EX_CANTCREAT; } - } else { - if ( st.st_nlink > 1 ) { - /* Hard link. */ - const char *linkname; - - if ( (linkname = hash_find_file(&st)) != NULL ) { - /* We've seen it before, hard link it */ - - if ( link(linkname, out_path) ) { - message(vl_error, "%s: hard link %s -> %s failed: %s\n", - program, out_path, linkname, strerror(errno)); - err = EX_CANTCREAT; - break; - } - } else { - /* First encounter, create and enter into hash */ - if ( mknod(out_path, st.st_mode, st.st_rdev) ) { - message(vl_error, "%s: mknod failed for %s: %s\n", - program, out_path, strerror(errno)); - err = EX_CANTCREAT; - break; - } - hash_insert_file(&st, out_path); + } + } else if ( S_ISLNK(st.st_mode) ) { + int chars; +#ifdef PATH_MAX +#define BUFFER_SLACK PATH_MAX +#else +#define BUFFER_SLACK BUFSIZ +#endif + int buffer_len = st.st_size + BUFFER_SLACK + 1; + char *buffer = xmalloc(buffer_len); + if ( (chars = readlink(in_path, buffer, buffer_len)) < 0 ) { + message(vl_error, "%s: readlink failed for %s: %s\n", + program, in_path, strerror(errno)); + return EX_NOINPUT; + } + buffer[chars] = '\0'; + if ( symlink(buffer, out_path) ) { + message(vl_error, "%s: symlink %s -> %s failed: %s\n", + program, out_path, buffer, strerror(errno)); + return EX_CANTCREAT; + } + } else { + if ( st.st_nlink > 1 ) { + /* Hard link. */ + const char *linkname; + + if ( (linkname = hash_find_file(&st)) != NULL ) { + /* We've seen it before, hard link it */ + + if ( link(linkname, out_path) ) { + message(vl_error, "%s: hard link %s -> %s failed: %s\n", + program, out_path, linkname, strerror(errno)); + return EX_CANTCREAT; } } else { - /* Singleton node; no funnies */ - if ( mknod(out_path, st.st_mode, st.st_rdev) ) { - message(vl_error, "%s: mknod failed for %s: %s\n", - program, out_path, strerror(errno)); - err = EX_CANTCREAT; - break; - } + /* First encounter, create and enter into hash */ + if ( mknod(out_path, st.st_mode, st.st_rdev) ) { + message(vl_error, "%s: mknod failed for %s: %s\n", + program, out_path, strerror(errno)); + return EX_CANTCREAT; + } + hash_insert_file(&st, out_path); + } + } else { + /* Singleton node; no funnies */ + if ( mknod(out_path, st.st_mode, st.st_rdev) ) { + message(vl_error, "%s: mknod failed for %s: %s\n", + program, out_path, strerror(errno)); + return EX_CANTCREAT; } } - - /* This is done by munge_path() for files */ - if ( !S_ISREG(st.st_mode) ) { + } + + /* This is done by munge_path() for files */ + if ( !S_ISREG(st.st_mode) ) { #ifdef HAVE_LCHOWN - lchown(out_path, st.st_uid, st.st_gid); + lchown(out_path, st.st_uid, st.st_gid); #endif - if ( !S_ISLNK(st.st_mode) ) { + if ( !S_ISLNK(st.st_mode) ) { #ifndef HAVE_LCHOWN - chown(out_path, st.st_uid, st.st_gid); + chown(out_path, st.st_uid, st.st_gid); #endif - chmod(out_path, st.st_mode); - ut.actime = st.st_atime; - ut.modtime = st.st_mtime; - utime(out_path, &ut); - } + chmod(out_path, st.st_mode); + ut.actime = st.st_atime; + ut.modtime = st.st_mtime; + utime(out_path, &ut); } } - closedir(thisdir); - - free(in_path); - free(out_path); - + return err; } |