volser: project tviced usd kauth audit
${COMPILE_PART1} volser ${COMPILE_PART2}
-tools: volser
- ${COMPILE_PART1} tools ${COMPILE_PART2}
-
venus: project volser ptserver
${COMPILE_PART1} venus ${COMPILE_PART2}
${COMPILE_PART1} venus/test ${COMPILE_PART2}
finale: project cmd comerr afsd allrcmds butc tbutc @ENABLE_KERNEL_MODULE@ libuafs audit kauth log package \
ptserver scout bu_utils ubik uss bozo vfsck volser \
- venus update xstat afsmonitor dauth tools rxdebug libafsrpc \
+ venus update xstat afsmonitor dauth rxdebug libafsrpc \
libafsauthent libadmin
${COMPILE_PART1} finale ${COMPILE_PART2}
finale_nolibafs: project cmd comerr afsd allrcmds butc tbutc libuafs audit kauth log package \
ptserver scout bu_utils ubik uss bozo vfsck volser \
- venus update xstat afsmonitor dauth tools rxdebug libafsrpc \
+ venus update xstat afsmonitor dauth rxdebug libafsrpc \
libafsauthent libadmin
${COMPILE_PART1} finale ${COMPILE_PART2}
-${COMPILE_PART1} bucoord ${COMPILE_CLEAN}
-${COMPILE_PART1} xstat ${COMPILE_CLEAN}
-${COMPILE_PART1} afsmonitor ${COMPILE_CLEAN}
- -${COMPILE_PART1} tools ${COMPILE_CLEAN}
+ -${COMPILE_PART1} tests ${COMPILE_CLEAN}
-${COMPILE_PART1} rxdebug ${COMPILE_CLEAN}
-${COMPILE_PART1} libafsrpc ${COMPILE_CLEAN}
-${COMPILE_PART1} libafsauthent ${COMPILE_CLEAN}
src/sia/Makefile \
src/sys/Makefile \
src/tbutc/Makefile \
- src/tools/Makefile \
+ src/tests/Makefile \
+ src/tests/Dirpath.pm \
src/tsm41/Makefile \
src/tviced/Makefile \
src/ubik/Makefile \
src/tbutc/Makefile \
src/tests/Makefile \
src/tests/Dirpath.pm \
-src/tools/Makefile \
src/tsm41/Makefile \
src/tviced/Makefile \
src/ubik/Makefile \
CFLAGS = -I. -I${srcdir} ${DBG} ${OPTMZ} -I${TOP_OBJDIR}/src/config -I${TOP_INCDIR} ${XCFLAGS}
LDFLAGS=${DBG} ${OPTMZ} ${XLDFLAGS}
+INCDIRS=-I${TOP_OBJDIR}/src/config -I${TOP_INCDIR}/afs -I${TOP_INCDIR}
+INCLIBS=-L${SRCDIR}/lib/afs -L${TOP_LIBDIR}
+
+LIBS=\
+ ${TOP_LIBDIR}/libdumpscan.a \
+ ${TOP_LIBDIR}/libxfiles.a \
+ ${TOP_LIBDIR}/libauth.a \
+ ${TOP_LIBDIR}/libaudit.a \
+ ${TOP_LIBDIR}/libvolser.a \
+ ${TOP_LIBDIR}/libvldb.a \
+ ${TOP_LIBDIR}/libubik.a \
+ ${TOP_LIBDIR}/librxkad.a \
+ ${TOP_LIBDIR}/libsys.a \
+ ${TOP_LIBDIR}/librx.a \
+ ${TOP_LIBDIR}/liblwp.a \
+ ${TOP_LIBDIR}/util.a \
+ ${TOP_LIBDIR}/libcom_err.a \
+ ${XLIBS}
+
+OBJS_afsdump_scan = afsdump_scan.o repair.o
+OBJS_afsdump_xsed = afsdump_xsed.o repair.o
+OBJS_libxfiles.a = xfiles.o xf_errs.o xf_printf.o int64.o \
+ xf_files.o xf_rxcall.o xf_profile.o
+OBJS_libdumpscan.a = primitive.o util.o dumpscan_errs.o parsetag.o \
+ parsedump.o parsevol.o parsevnode.o dump.o \
+ directory.o pathname.o backuphdr.o stagehdr.o
+
+TARGETS = libxfiles.a libdumpscan.a \
+ afsdump_scan afsdump_dirlist afsdump_extract dumptool
+
+afsdump_scan: libxfiles.a libdumpscan.a $(OBJS_afsdump_scan)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o afsdump_scan $(OBJS_afsdump_scan) $(LIBS)
+
+afsdump_xsed: libxfiles.a libdumpscan.a $(OBJS_afsdump_xsed)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o afsdump_xsed $(OBJS_afsdump_xsed) $(LIBS)
+
+afsdump_dirlist: libxfiles.a libdumpscan.a afsdump_dirlist.o
+ $(CC) $(CFLAGS) $(LDFLAGS) -o afsdump_dirlist afsdump_dirlist.o $(LIBS)
+
+afsdump_extract: libxfiles.a libdumpscan.a afsdump_extract.o
+ $(CC) $(CFLAGS) $(LDFLAGS) -o afsdump_extract afsdump_extract.o $(LIBS)
+
+null-search: libxfiles.a libdumpscan.a null-search.c
+ $(CC) $(CFLAGS) $(LDFLAGS) -o null-search null-search.c $(LIBS)
+
+dumptool: dumptool.c
+ $(CC) $(CFLAGS) $(LDFLAGS) -o dumptool dumptool.c
+
+libxfiles.a: $(OBJS_libxfiles.a)
+ -rm -f libxfiles.a
+ $(AR) r libxfiles.a $(OBJS_libxfiles.a)
+ $(RANLIB) libxfiles.a
+
+libdumpscan.a: $(OBJS_libdumpscan.a)
+ -rm -f libdumpscan.a
+ $(AR) r libdumpscan.a $(OBJS_libdumpscan.a)
+ $(RANLIB) libdumpscan.a
+
+xf_errs.c xf_errs.h: xf_errs.et
+ $(COMPILE_ET) xf_errs.et
+
+dumpscan_errs.c dumpscan_errs.h: dumpscan_errs.et
+ $(COMPILE_ET) dumpscan_errs.et
+
+util.o xfiles.o xf_files.o: xf_errs.h
+backuphdr.o directory.o parsedump.o parsetag.o: dumpscan_errs.h
+parsevnode.o parsevol.o pathname.o repair.o: dumpscan_errs.h
+stagehdr.o util.o: dumpscan_errs.h
+
+${DEST}/etc/afsdump_scan: afsdump_scan
+ ${INSTALL} $? $@
+
+${DEST}/etc/afsdump_dirlist: afsdump_dirlist
+ ${INSTALL} $? $@
+
+${DEST}/etc/afsdump_extract: afsdump_extract
+ ${INSTALL} $? $@
+
+${DEST}/etc/dumptool: dumptool
+ ${INSTALL} $? $@
+
+${DESTDIR}${sbindir}/afsdump_scan: afsdump_scan
+ ${INSTALL} $? $@
+
+${DESTDIR}${sbindir}/afsdump_dirlist: afsdump_dirlist
+ ${INSTALL} $? $@
+
+${DESTDIR}${sbindir}/afsdump_extract: afsdump_extract
+ ${INSTALL} $? $@
+
+${DESTDIR}${sbindir}/dumptool: dumptool
+ ${INSTALL} $? $@
+
+${TOP_LIBDIR}/libxfiles.a: libxfiles.a
+ ${INSTALL} $? $@
+
+${TOP_LIBDIR}/libdumpscan.a: libdumpscan.a
+ ${INSTALL} $? $@
+
SYS_LIBS = ${TOP_LIBDIR}/libsys.a ${TOP_LIBDIR}/librx.a ${TOP_LIBDIR}/liblwp.a ${TOP_LIBDIR}/util.a
AUTH_LIBS = ${TOP_LIBDIR}/libauth.a ${SYS_LIBS}
EXTRA_OBJS = err.o errx.o warn.o warnx.o
-all: run-tests $(TEST_PROGRAMS) OS.pm
-
OS.pm: OS-$(MKAFS_OSTYPE).pm
$(CP) OS-$(MKAFS_OSTYPE).pm OS.pm
sed -e "s!%bindir%!$(bindir)!" $(srcdir)/mountpoint.in > $@
chmod +x mountpoint
-clean:
- rm -f run-tests $(TEST_PROGRAMS) *.o *~ OS.pm
+dest:
install:
uninstall:
+all: run-tests $(TEST_PROGRAMS) OS.pm ${TOP_LIBDIR}/libxfiles.a \
+ ${TOP_LIBDIR}/libdumpscan.a \
+ afsdump_scan afsdump_dirlist afsdump_extract dumptool
+
+clean:
+ -rm xf_errs.c xf_errs.h dumpscan_errs.c dumpscan_errs.h *.o \
+ $(TARGETS) run-tests $(TEST_PROGRAMS) OS.pm
+
+include ../config/Makefile.version
TAGS: $(TEST_SRCS)
etags $(TEST_SRCS)
--- /dev/null
+$Id$
+
+This is the README for dumptool, a program to interactively restore
+AFS volume dump files.
+
+
+INTRODUCTION
+
+Dumptool arose out of a need here at NRL to perform maintenance of
+MR-AFS (Multi-Resident AFS) volumes. After it was written, we found
+that it worked great on standard AFS volumes as well, and relatively
+few changes were required to make it compile with a standard AFS
+installation.
+
+Dumptool provides an interface similar to the interactive Unix restore;
+given a dump file, a user can navigate through the filesystem inside
+the dump using familiar commands such as "cd" and "ls". Also provided
+is a "cp" command to copy individual files out of the dump into a
+normal filesystem space. This eliminates the need to restore an
+entire volume just to retrieve a single file.
+
+Dumptool was written at the Naval Research Laboratory by Ken Hornstein
+<kenh@cmf.nrl.navy.mil>. The latest and greatest version of dumptool
+can always be found in the AFS contrib directory at:
+
+/afs/transarc.com/public/afs-contrib/dumptool/
+
+
+INSTALLATION & OPERATION
+
+The standard Makefile target will build a dumptool for a vanilla AFS
+installation. The "mrafs" target will build a dumptool that can
+operate on MR-AFS dumps. In either case, you may need to change some
+of the Makefile variables to reflect your site; see the Makefile for
+more information.
+
+Once dumptool is built successfully, you can run it on any AFS dump
+file. Without any additional arguments, dumptool will scan the dump file,
+build indexes of all listed vnodes, and present a prompt (">") that
+accepts the following commands:
+
+ ls Lists files in the current directory. Filename globbing
+ (e.g., wildcards such as * ?) are supported via the system
+ fnmatch() function. Accepts the following flags:
+
+ -l Generates a "long" listing, similar to the -l switch for
+ the Unix ls. Displays Unix mode mask, owner, group,
+ and file size.
+ -i Displays volume, vnode, and uniquifier for each matching
+ file in the format volume.vnode.uniquifier. Note that
+ the volume displayed is that of the _parent_ volume,
+ which in the case of a backup volume is the _original_
+ volume from which it was generated.
+ -F Append / to filenames for directories, @ for symlinks,
+ and * for files which have the execute bits set.
+ -R Recurse through all subdirectories.
+
+ cd Change the current directory
+
+ cp Copy a file from the dump. Note that globbing is NOT
+ supported, and you must give a filename (the Unix
+ idiom of just giving a destination directory for the
+ second argument to cp will NOT work).
+
+ vcp Copy a file from the dump, by the vnode. The first
+ argument is the vnode number, optionally followed by
+ the uniqifier. E.g:
+
+ vcp 126278 /tmp/file1
+ vcp 126278.43289 /tmp/file2
+
+ quit Exits dumptool.
+ exit
+
+
+ADDITIONAL OPTIONS TO DUMPTOOL
+
+Dumptool supports a number of command-line options. They are detailed
+below:
+
+ -v Verbose mode. Output additional information during dump
+ processing. Each -v will increate output.
+
+ -f Force dump processing. Attempt to continue processing
+ a dump even when some errors are detected. Not completely
+ tested.
+
+ -i Inode dump. Dump a list of all files in the volume,
+ with their volume/vnode/uniqifier information.
+
+
+SUPPORT FOR MR-AFS
+
+Dumptool also supports the extra information in MR-AFS dumps, and
+provides some extra commands/options for dealing with MR-AFS dumps:
+
+Additional command line options:
+
+ -d Dump all residency filenames in the dump file to standard
+ output.
+
+ -t Residency tag information. Allows a user to specify the
+ tag of a residency if the rsserver is not available.
+ Format of option is Residency/Tag
+
+ -r Residency filesystem information. Allows a user to specify
+ the residency filesystem information if dumptool is not
+ run on the same host as the residency in the dump. Format
+ of option is Residency/Type/Size/Algorithm.
+
+Additional commands:
+
+ file Displays to standard output the residency filename of a
+ given dump filename. All residencies available are shown.
+
+
+CAVEATS
+
+The user interface needs some work. "ls" doesn't support nearly as many
+options as the standard Unix one. "cp" also doesn't have all of the features
+found in common Unix variants.
+
+Right now two passes are done through the dump file to scan all vnodes.
+With some clever work this could be sped up somewhat and changed to only
+do a single scan.
+
+
+MODIFYING DUMPTOOL
+
+I welcome changes to dumptool, but I have some guidelines.
+
+First, I DEMAND that the changes be sent in context diff format. I prefer
+unidiff (diff -u), but standard context diffs are okay. It's extremely
+difficult to deal with new code in any other way.
+
+If the changes you want to do require some significant
+rearchitecturing, it might be a good idea to contact me first. That
+way we can coordinate the modifications in a meaningful way (I might
+have made changes since the last released version).
+
+If you're making MR-AFS specific changes, please follow the example
+I've set and protect them with #ifdef RESIDENCY.
+
+And please ... follow my code style, okay? I always try to follow
+whatever wacky code style I find in source code that I modify, and I
+think it's only polite for you to do the same.
+
+
+CONTACT INFORMATION
+
+As always, please send comments, suggestions, or new features to me,
+Ken Hornstein <kenh@cmf.nrl.navy.mil>. Shar and enjoy.
--- /dev/null
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
--- /dev/null
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/* afsdump_dirlist.c - List an AFS directory file */
+
+#include <sys/fcntl.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "dumpscan.h"
+
+extern int optind;
+extern char *optarg;
+
+char *argv0;
+static char *input_path;
+static int quiet, verbose, error_count;
+
+static path_hashinfo phi;
+static dump_parser dp;
+
+
+/* Print a usage message and exit */
+static void usage(int status, char *msg)
+{
+ if (msg) fprintf(stderr, "%s: %s\n", argv0, msg);
+ fprintf(stderr, "Usage: %s [options] [file]\n", argv0);
+ fprintf(stderr, " -h Print this help message\n");
+ fprintf(stderr, " -q Quiet mode (don't print errors)\n");
+ fprintf(stderr, " -v Verbose mode\n");
+ exit(status);
+}
+
+
+/* Parse the command-line options */
+static void parse_options(int argc, char **argv)
+{
+ int c;
+
+ /* Set the program name */
+ if (argv0 = strrchr(argv[0], '/')) argv0++;
+ else argv0 = argv[0];
+
+ /* Initialize options */
+ input_path = 0;
+ quiet = verbose = 0;
+
+ /* Initialize other stuff */
+ error_count = 0;
+
+ /* Parse the options */
+ while ((c = getopt(argc, argv, "hqv")) != EOF) {
+ switch (c) {
+ case 'q': quiet = 1; continue;
+ case 'v': verbose = 1; continue;
+ case 'h': usage(0, 0);
+ default: usage(1, "Invalid option!");
+ }
+ }
+
+ if (quiet && verbose) usage(1, "Can't specify both -q and -v");
+
+ /* Parse non-option arguments */
+ if (argc - optind > 1) usage(1, "Too many arguments!");
+ input_path = (argc == optind) ? "-" : argv[optind];
+}
+
+
+/* A callback to count and print errors */
+static afs_uint32 my_error_cb(afs_uint32 code, int fatal, void *ref, char *msg, ...)
+{
+ va_list alist;
+
+ error_count++;
+ if (!quiet) {
+ va_start(alist, msg);
+ com_err_va(argv0, code, msg, alist);
+ va_end(alist);
+ }
+}
+
+
+/* Main program */
+void main(int argc, char **argv)
+{
+ XFILE input_file;
+ afs_uint32 r;
+
+ parse_options(argc, argv);
+ initialize_acfg_error_table();
+ initialize_AVds_error_table();
+ initialize_rxk_error_table();
+ initialize_u_error_table();
+ initialize_vl_error_table();
+ initialize_vols_error_table();
+ initialize_xFil_error_table();
+ r = xfopen(&input_file, O_RDONLY, input_path);
+ if (r) {
+ com_err(argv0, r, "opening %s", input_path);
+ exit(2);
+ }
+
+ memset(&dp, 0, sizeof(dp));
+ dp.cb_error = my_error_cb;
+ dp.print_flags = DSPRINT_DIR;
+ if (input_file.is_seekable) dp.flags |= DSFLAG_SEEK;
+
+ r = ParseDirectory(&input_file, &dp, 0, 1);
+ xfclose(&input_file);
+
+ if (verbose && error_count) fprintf(stderr, "*** %d errors\n", error_count);
+ if (r && !quiet) fprintf(stderr, "*** FAILED: %s\n", error_message(r));
+ exit(0);
+}
--- /dev/null
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/* afsdump_extract.c - Extract files from an AFS dump */
+
+#include <sys/fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "dumpscan.h"
+#include "dumpscan_errs.h"
+
+#define COPYBUFSIZE (256*1024)
+
+extern int optind;
+extern char *optarg;
+
+char *argv0;
+static char **file_names;
+static int *file_vnums, name_count, vnum_count;
+
+static char *input_path, *target;
+static int quiet, verbose, error_count, dirs_done, extract_all;
+static int nomode, use_realpath, use_vnum;
+static int do_acls, do_headers;
+
+static path_hashinfo phi;
+static dump_parser dp;
+
+/* Print a usage message and exit */
+static void usage(int status, char *msg)
+{
+ if (msg) fprintf(stderr, "%s: %s\n", argv0, msg);
+ fprintf(stderr, "Usage: %s [options] dumpfile [dest [files...]]\n", argv0);
+ fprintf(stderr, " -A Save ACL's\n");
+ fprintf(stderr, " -H Save headers\n");
+ fprintf(stderr, " -h Print this help message\n");
+ fprintf(stderr, " -i Use vnode numbers\n");
+ fprintf(stderr, " -n Don't actually create files\n");
+ fprintf(stderr, " -p Use real pathnames internally\n");
+ fprintf(stderr, " -q Quiet mode (don't print errors)\n");
+ fprintf(stderr, " -v Verbose mode\n");
+ fprintf(stderr, "The destination directory defaults to .\n");
+ fprintf(stderr, "Files may be vnode numbers or volume-relative paths;\n");
+ fprintf(stderr, "If vnode numbers are used, files will be extracted\n");
+ fprintf(stderr, "a name generated from the vnode number and uniqifier.\n");
+ fprintf(stderr, "If paths are used, -p is implied and files will be\n");
+ fprintf(stderr, "into correctly-named files.\n");
+ exit(status);
+}
+
+
+/* Parse the command-line options */
+static void parse_options(int argc, char **argv)
+{
+ int c, i, i_name, i_vnum;
+
+ /* Set the program name */
+ if (argv0 = strrchr(argv[0], '/')) argv0++;
+ else argv0 = argv[0];
+
+ /* Initialize options */
+ input_path = 0;
+ quiet = verbose = nomode = 0;
+ use_realpath = use_vnum = do_acls = do_headers = extract_all = 0;
+
+ /* Initialize other stuff */
+ error_count = 0;
+
+ /* Parse the options */
+ while ((c = getopt(argc, argv, "AHhinpqv")) != EOF) {
+ switch (c) {
+ case 'A': do_acls = 1; continue;
+ case 'H': do_headers = 1; continue;
+ case 'i': use_vnum = 1; continue;
+ case 'n': nomode = 1; continue;
+ case 'p': use_realpath = 1; continue;
+ case 'q': quiet = 1; continue;
+ case 'v': verbose = 1; continue;
+ case 'h': usage(0, 0);
+ default: usage(1, "Invalid option!");
+ }
+ }
+
+ if (quiet && verbose) usage(1, "Can't specify both -q and -v");
+
+ /* Parse non-option arguments */
+ if (argc - optind < 1) usage(1, "Dumpfile name required!");
+ input_path = argv[optind];
+
+ if (argc - optind < 2) target = ".";
+ target = argv[optind + 1];
+
+ vnum_count = name_count = 0;
+ if (argc - optind < 3) extract_all = 1;
+ else {
+ argv += optind + 2;
+ argc -= optind + 2;
+ for (i = 0; i < argc; i++) {
+ if (argv[i][0] == '/') name_count++;
+ else vnum_count++;
+ }
+ file_names = (char **)malloc(name_count + sizeof(char *));
+ file_vnums = (afs_uint32 *)malloc(vnum_count + sizeof(afs_uint32));
+ if (name_count) use_realpath = 1;
+
+ i_name = i_vnum = 0;
+ for (i = 0; i < argc; i++) {
+ if (argv[i][0] == '/') file_names[i_name++] = argv[i];
+ else file_vnums[i_vnum++] = strtol(argv[i], 0, 0);
+ }
+ }
+}
+
+
+static int mkdirp(char *path)
+{
+ char *x = path, slash;
+ struct stat statbuf;
+
+ for (;;) {
+ while (*x && *x != '/') x++;
+ slash = *x;
+ *x = 0;
+
+ if (stat(path, &statbuf)) {
+ if (errno == ENOENT) {
+ if (verbose) printf("> mkdir %s\n", path);
+ if (!mkdir(path, 0755)) errno = 0;
+ }
+ }
+ if (!slash) break;
+ *x++ = '/';
+ if (errno) return errno;
+ }
+
+ return 0;
+}
+
+
+static char *modestr(int mode)
+{
+ static char str[10];
+ int i;
+
+ strcpy(str, "rwxrwxrwx");
+ for (i = 0; i < 9; i++) {
+ if (!(mode & (1 << i)))
+ str[8 - i] = '-';
+ }
+ if (mode & 01000) str[8] = (str[8] == '-') ? 'T' : 't';
+ if (mode & 02000) str[5] = (str[5] == '-') ? 'S' : 's';
+ if (mode & 04000) str[2] = (str[2] == '-') ? 'S' : 's';
+ return str;
+}
+
+
+static char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+static char *datestr(time_t date)
+{
+ static char str[13];
+ time_t clock = time(0);
+ struct tm *now, *then;
+ int diff;
+
+ now = localtime(&clock);
+ then = localtime(&date);
+
+ diff = now->tm_mon - then->tm_mon;
+ if (then->tm_year == now->tm_year - 1) diff += 12;
+ if (then->tm_year == now->tm_year + 1) diff -= 12;
+
+ if (diff < 5 || diff > 5)
+ sprintf(str, "%3s %2d %4d", month[then->tm_mon], then->tm_mday,
+ then->tm_year + 1900);
+ else
+ sprintf(str, "%3s %2d %2d:%2d", month[then->tm_mon], then->tm_mday,
+ then->tm_hour, then->tm_min);
+ return str;
+}
+
+
+/* Should we use this vnode?
+ * Return 0 if no, non-0 if yes
+ */
+static int usevnode(XFILE *X, afs_uint32 vnum, char *vnodepath)
+{
+ int vl, vpl, r, i;
+
+ /* Special case */
+ if (extract_all || !strcmp(vnodepath, "/"))
+ return 1;
+
+ for (i = 0; i < vnum_count; i++)
+ if (vnum == file_vnums[i]) return 2;
+
+ vl = strlen(vnodepath);
+/*fprintf(stderr, "++ checking %s\n", vnodepath);*/
+ for (i = 0; i < name_count; i++) {
+ vpl = strlen(file_names[i]);
+/* fprintf(stderr, " %s\n", file_names[i]);*/
+
+ if (vl > vpl) {
+ r = !strncmp(file_names[i], vnodepath, vpl) && vnodepath[vpl] == '/';
+ } else if (vl < vpl) {
+ r = !strncmp(file_names[i], vnodepath, vl) && file_names[i][vl] == '/';
+ } else {
+ r = !strcmp(file_names[i], vnodepath);
+ }
+ if (r) return 1;
+ }
+ return 0;
+}
+
+
+static int copyfile(XFILE *in, XFILE *out, int size)
+{
+ static char buf[COPYBUFSIZE];
+ int nr, nw, r;
+
+ while (size) {
+ nr = (size > COPYBUFSIZE) ? COPYBUFSIZE : size;
+ if (r = xfread(in, buf, nr)) return r;
+ if (r = xfwrite(out, buf, nr)) return r;
+ size -= nr;
+ }
+ return 0;
+}
+
+
+/* A callback to count and print errors */
+static afs_uint32 my_error_cb(afs_uint32 code, int fatal, void *ref, char *msg, ...)
+{
+ va_list alist;
+
+ error_count++;
+ if (!quiet) {
+ va_start(alist, msg);
+ com_err_va(argv0, code, msg, alist);
+ va_end(alist);
+ }
+}
+
+
+static afs_uint32 dumphdr_cb(afs_dump_header *hdr, XFILE *X, void *refcon)
+{
+ return 0;
+}
+
+
+static afs_uint32 volhdr_cb(afs_vol_header *hdr, XFILE *X, void *refcon)
+{
+ return 0;
+}
+
+
+static afs_uint32 directory_cb(afs_vnode *v, XFILE *X, void *refcon)
+{
+ char *vnodepath;
+ int r, use;
+
+ /* Should we even use this? */
+ if (!use_vnum) {
+ if (r = Path_Build(X, &phi, v->vnode, &vnodepath, !use_realpath))
+ return r;
+ if (!(use = usevnode(X, v->vnode, vnodepath))) {
+ free(vnodepath);
+ return 0;
+ }
+ }
+
+ /* Print it out */
+ if (verbose) {
+ if (use_vnum)
+ printf("d%s %3d %-11d %11d %s #%d:%d\n",
+ modestr(v->mode), v->nlinks, v->owner, v->size,
+ datestr(v->server_date), v->vnode, v->vuniq);
+ else
+ printf("d%s %3d %-11d %11d %s %s\n",
+ modestr(v->mode), v->nlinks, v->owner, v->size,
+ datestr(v->server_date), vnodepath);
+ }
+ else if (!quiet && !use_vnum)
+ printf("%s\n", vnodepath);
+
+ /* Make the directory, if needed */
+ if (!nomode && !use_vnum && use != 2) {
+ if (strcmp(vnodepath, "/")
+ && (r = mkdirp(vnodepath + 1))) {
+ free(vnodepath);
+ return r;
+ }
+ if (do_acls) {
+ /* XXX do ACL's later */
+ }
+ }
+ if (!use_vnum) free(vnodepath);
+ return 0;
+}
+
+
+static afs_uint32 file_cb(afs_vnode *v, XFILE *X, void *refcon)
+{
+ char *vnodepath, vnpx[30];
+ u_int64 where;
+ XFILE OX;
+ int r, use;
+
+ if (!dirs_done) {
+ dirs_done = 1;
+ if (verbose) printf("* Extracting files...\n");
+ }
+
+ /* Should we even use this? */
+ if (!use_vnum) {
+ if (r = Path_Build(X, &phi, v->vnode, &vnodepath, !use_realpath))
+ return r;
+ if (!(use = usevnode(X, v->vnode, vnodepath))) {
+ free(vnodepath);
+ return 0;
+ }
+ if (use == 2) {
+ free(vnodepath);
+ sprintf(vnpx, "#%d:%d", v->vnode, v->vuniq);
+ vnodepath = vnpx;
+ }
+ } else {
+ sprintf(vnpx, "#%d:%d", v->vnode, v->vuniq);
+ vnodepath = vnpx;
+ }
+
+ /* Print it out */
+ if (verbose) {
+ printf("-%s %3d %-11d %11d %s %s\n",
+ modestr(v->mode), v->nlinks, v->owner, v->size,
+ datestr(v->server_date), vnodepath);
+ } else if (!quiet) {
+ printf("%s\n", vnodepath);
+ }
+
+ if (!nomode) {
+ if ((r = xftell(X, &where))
+ || (r = xfseek(X, &v->d_offset))
+ || (r = xfopen_path(&OX, O_RDWR|O_CREAT|O_TRUNC, vnodepath + 1, 0644))) {
+ if (!use_vnum) free(vnodepath);
+ return r;
+ }
+ r = copyfile(X, &OX, v->size);
+ xfclose(&OX);
+ xfseek(X, &where);
+ } else r = 0;
+
+ if (!use_vnum && use != 2) free(vnodepath);
+ return r;
+}
+
+
+static afs_uint32 symlink_cb(afs_vnode *v, XFILE *X, void *refcon)
+{
+ char *vnodepath, *linktarget, vnpx[30];
+ u_int64 where;
+ int r, use;
+
+ if (!dirs_done) {
+ dirs_done = 1;
+ if (verbose) printf("* Extracting files...\n");
+ }
+
+ /* Should we even use this? */
+ if (!use_vnum) {
+ if (r = Path_Build(X, &phi, v->vnode, &vnodepath, !use_realpath))
+ return r;
+ if (!(use = usevnode(X, v->vnode, vnodepath))) {
+ free(vnodepath);
+ return 0;
+ }
+ if (use == 2) {
+ free(vnodepath);
+ sprintf(vnpx, "#%d:%d", v->vnode, v->vuniq);
+ vnodepath = vnpx;
+ }
+ } else {
+ sprintf(vnpx, "#%d:%d", v->vnode, v->vuniq);
+ vnodepath = vnpx;
+ }
+
+ if (!(linktarget = (char *)malloc(v->size + 1))) {
+ if (!use_vnum && use != 2) free(vnodepath);
+ return DSERR_MEM;
+ }
+ if ((r = xftell(X, &where))
+ || (r = xfseek(X, &v->d_offset))
+ || (r = xfread(X, linktarget, v->size))) {
+ if (!use_vnum && use != 2) free(vnodepath);
+ free(linktarget);
+ return r;
+ }
+ xfseek(X, &where);
+ linktarget[v->size] = 0;
+
+ /* Print it out */
+ if (verbose)
+ printf("l%s %3d %-11d %11d %s %s -> %s\n",
+ modestr(v->mode), v->nlinks, v->owner, v->size,
+ datestr(v->server_date), vnodepath, linktarget);
+ else if (!quiet)
+ printf("%s\n", vnodepath);
+
+ r = 0;
+ if (!nomode) {
+ if (symlink(linktarget, vnodepath + 1))
+ r = errno;
+ }
+
+ free(linktarget);
+ if (!use_vnum && use != 2) free(vnodepath);
+ return r;
+}
+
+
+static afs_uint32 lose_cb(afs_vnode *v, XFILE *F, void *refcon)
+{
+ int r;
+
+ if (!dirs_done) {
+ dirs_done = 1;
+ if (verbose) printf("* Extracting files...\n");
+ }
+
+ return 0;
+}
+
+
+/* Main program */
+void main(int argc, char **argv)
+{
+ XFILE input_file;
+ afs_uint32 r;
+
+ parse_options(argc, argv);
+ initialize_acfg_error_table();
+ initialize_AVds_error_table();
+ initialize_rxk_error_table();
+ initialize_u_error_table();
+ initialize_vl_error_table();
+ initialize_vols_error_table();
+ initialize_xFil_error_table();
+ r = xfopen(&input_file, O_RDONLY, input_path);
+ if (r) {
+ com_err(argv0, r, "opening %s", input_path);
+ exit(2);
+ }
+
+ memset(&dp, 0, sizeof(dp));
+ dp.cb_error = my_error_cb;
+ if (input_file.is_seekable) dp.flags |= DSFLAG_SEEK;
+ dirs_done = 0;
+
+ if (!use_vnum) {
+ u_int64 where;
+
+ memset(&phi, 0, sizeof(phi));
+ phi.p = &dp;
+
+ if (verbose) printf("* Building pathname info...\n");
+ if ((r = xftell(&input_file, &where))
+ || (r = Path_PreScan(&input_file, &phi, 1))
+ || (r = xfseek(&input_file, &where))) {
+ com_err(argv0, r, "- path initialization failed");
+ xfclose(&input_file);
+ exit(1);
+ }
+ }
+
+ dp.cb_vnode_dir = directory_cb;
+ dp.cb_vnode_file = file_cb;
+ dp.cb_vnode_link = symlink_cb;
+ dp.cb_vnode_empty = lose_cb;
+ dp.cb_vnode_wierd = lose_cb;
+ if (do_headers) {
+ dp.cb_dumphdr = dumphdr_cb;
+ dp.cb_volhdr = volhdr_cb;
+ }
+
+ if (!nomode) {
+ mkdir(target, 0755);
+ if (chdir(target)) {
+ fprintf(stderr, "chdir %s failed: %s\n", target, strerror(errno));
+ exit(1);
+ }
+ }
+ r = ParseDumpFile(&input_file, &dp);
+
+ if (verbose && error_count) fprintf(stderr, "*** %d errors\n", error_count);
+ if (r && !quiet) fprintf(stderr, "*** FAILED: %s\n", error_message(r));
+ exit(0);
+}
--- /dev/null
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/* afsdump_scan.c - General-purpose dump scanner */
+
+#include <sys/fcntl.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "dumpscan.h"
+
+extern int optind;
+extern char *optarg;
+
+extern XFILE repair_output;
+extern afs_uint32 repair_dumphdr_cb(afs_dump_header *, XFILE *, void *);
+extern afs_uint32 repair_volhdr_cb(afs_vol_header *, XFILE *, void *);
+extern afs_uint32 repair_vnode_cb(afs_vnode *, XFILE *, void *);
+
+char *argv0;
+static char *input_path, *gendump_path;
+static afs_uint32 printflags, repairflags;
+static int quiet, verbose, error_count;
+
+static path_hashinfo phi;
+static dump_parser dp;
+
+
+/* Print a usage message and exit */
+static void usage(int status, char *msg)
+{
+ if (msg) fprintf(stderr, "%s: %s\n", argv0, msg);
+ fprintf(stderr, "Usage: %s [options] [file]\n", argv0);
+ fprintf(stderr, " -Pxxx Set print options:\n");
+ fprintf(stderr, " B = Print backup system header (if any)\n");
+ fprintf(stderr, " H = Print AFS dump header\n");
+ fprintf(stderr, " V = Print AFS volume header\n");
+ fprintf(stderr, " v = List vnodes\n");
+ fprintf(stderr, " p = Include path to each vnode\n");
+ fprintf(stderr, " i = Include info for each vnode\n");
+ fprintf(stderr, " d = List directory contents\n");
+ fprintf(stderr, " a = List access control lists\n");
+ fprintf(stderr, " g = Print debugging info\n");
+ fprintf(stderr, " -Rxxx Set repair options:\n");
+ fprintf(stderr, " 0 = Skip null tags\n");
+ fprintf(stderr, " b = Seek backward to find skipped tags\n");
+ fprintf(stderr, " d = Resync after vnode data\n");
+ fprintf(stderr, " v = Resync after corrupted vnodes\n");
+ fprintf(stderr, " -h Print this help message\n");
+ fprintf(stderr, " -gxxx Generate a new dump in file xxx\n");
+ fprintf(stderr, " -q Quiet mode (don't print errors)\n");
+ fprintf(stderr, " -v Verbose mode\n");
+ exit(status);
+}
+
+
+/* Parse the argument given to the -P option.
+ * Returns the resulting * dumpscan print flags (DSPRINT_*).
+ * If an unrecognized flag is used, prints an error message and exits.
+ */
+static afs_uint32 parse_printflags(char *flags)
+{
+ afs_uint32 result = 0;
+ char *x;
+
+ for (x = flags; *x; x++) switch (*x) {
+ case 'B': result |= DSPRINT_BCKHDR; continue;
+ case 'H': result |= DSPRINT_DUMPHDR; continue;
+ case 'V': result |= DSPRINT_VOLHDR; continue;
+ case 'v': result |= DSPRINT_ITEM; continue;
+ case 'p': result |= DSPRINT_PATH; continue;
+ case 'i': result |= DSPRINT_VNODE; continue;
+ case 'd': result |= DSPRINT_DIR; continue;
+ case 'a': result |= DSPRINT_ACL; continue;
+ case 'g': result |= DSPRINT_DEBUG; continue;
+ default: usage(1, "Invalid print options!");
+ }
+ return result;
+}
+
+
+/* Parse the argument given to the -R option.
+ * Returns the resulting * dumpscan repair flags (DSFIX_*).
+ * If an unrecognized flag is used, prints an error message and exits.
+ */
+static afs_uint32 parse_repairflags(char *flags)
+{
+ afs_uint32 result = 0;
+ char *x;
+
+ for (x = flags; *x; x++) switch (*x) {
+ case '0': result |= DSFIX_SKIP; continue;
+ case 'b': result |= DSFIX_RSKIP; continue;
+ case 'd': result |= DSFIX_VDSYNC; continue;
+ case 'v': result |= DSFIX_VFSYNC; continue;
+ default: usage(1, "Invalid repair options!");
+ }
+ return result;
+}
+
+
+/* Parse the command-line options */
+static void parse_options(int argc, char **argv)
+{
+ int c;
+
+ /* Set the program name */
+ if (argv0 = strrchr(argv[0], '/')) argv0++;
+ else argv0 = argv[0];
+
+ /* Initialize options */
+ input_path = gendump_path = 0;
+ printflags = repairflags = 0;
+ quiet = verbose = 0;
+
+ /* Initialize other stuff */
+ error_count = 0;
+
+ /* Parse the options */
+ while ((c = getopt(argc, argv, "P:R:g:hqv")) != EOF) {
+ switch (c) {
+ case 'P': printflags = parse_printflags(optarg); continue;
+ case 'R': repairflags = parse_repairflags(optarg); continue;
+ case 'g': gendump_path = optarg; continue;
+ case 'q': quiet = 1; continue;
+ case 'v': verbose = 1; continue;
+ case 'h': usage(0, 0);
+ default: usage(1, "Invalid option!");
+ }
+ }
+
+ if (quiet && verbose) usage(1, "Can't specify both -q and -v");
+
+ /* Parse non-option arguments */
+ if (argc - optind > 1) usage(1, "Too many arguments!");
+ input_path = (argc == optind) ? "-" : argv[optind];
+}
+
+
+/* A callback to count and print errors */
+static afs_uint32 my_error_cb(afs_uint32 code, int fatal, void *ref, char *msg, ...)
+{
+ va_list alist;
+
+ error_count++;
+ if (!quiet) {
+ va_start(alist, msg);
+ com_err_va(argv0, code, msg, alist);
+ va_end(alist);
+ }
+}
+
+
+/* A callback to print the path of a vnode. */
+static afs_uint32 print_vnode_path(afs_vnode *v, XFILE *X, void *refcon)
+{
+ afs_uint32 r;
+ char *name = 0;
+
+ /* Do repair, but only for known vnode types */
+ if (gendump_path
+ && (!(v->field_mask & F_VNODE_TYPE)
+ || v->type != vFile
+ || v->type != vDirectory
+ || v->type != vSymlink)) {
+ r = repair_vnode_cb(v, X, refcon);
+ if (r) return r;
+ }
+ r = Path_Build(X, &phi, v->vnode, &name, 0);
+ if (!r && name) printf(" Path: %s\n", name);
+ if (name) free(name);
+ return r;
+}
+
+
+/* Setup for generating a repaired dump */
+static afs_uint32 setup_repair(void)
+{
+ afs_uint32 r;
+
+ r = xfopen(&repair_output, O_RDWR|O_CREAT|O_TRUNC, gendump_path);
+ if (r) return r;
+
+ dp.cb_dumphdr = repair_dumphdr_cb;
+ dp.cb_volhdr = repair_volhdr_cb;
+ dp.cb_vnode_dir = repair_vnode_cb;
+ dp.cb_vnode_file = repair_vnode_cb;
+ dp.cb_vnode_link = repair_vnode_cb;
+ dp.cb_vnode_empty = repair_vnode_cb;
+ return 0;
+}
+
+
+/* Main program */
+void main(int argc, char **argv)
+{
+ XFILE input_file;
+ afs_uint32 r;
+
+ parse_options(argc, argv);
+ initialize_acfg_error_table();
+ initialize_AVds_error_table();
+ initialize_rxk_error_table();
+ initialize_u_error_table();
+ initialize_vl_error_table();
+ initialize_vols_error_table();
+ initialize_xFil_error_table();
+ r = xfopen(&input_file, O_RDONLY, input_path);
+ if (r) {
+ com_err(argv0, r, "opening %s", input_path);
+ exit(2);
+ }
+
+ memset(&dp, 0, sizeof(dp));
+ dp.cb_error = my_error_cb;
+ dp.repair_flags = repairflags;
+ if (input_file.is_seekable) dp.flags |= DSFLAG_SEEK;
+ else {
+ if (repairflags)
+ fprintf(stderr, "Repair modes available only for seekable dumps\n");
+ if (printflags & DSPRINT_PATH)
+ fprintf(stderr, "Path-printing available only for seekable dumps\n");
+ if (repairflags || (printflags & DSPRINT_PATH))
+ exit(1);
+ }
+
+ if (gendump_path && (r = setup_repair())) {
+ com_err(argv0, r, "setting up repair output");
+ xfclose(&input_file);
+ exit(2);
+ }
+
+ if (printflags & DSPRINT_PATH) {
+ u_int64 where;
+
+ dp.print_flags = printflags & DSPRINT_DEBUG;
+ memset(&phi, 0, sizeof(phi));
+ phi.p = &dp;
+
+ if ((r = xftell(&input_file, &where))
+ || (r = Path_PreScan(&input_file, &phi, 0))
+ || (r = xfseek(&input_file, &where))) {
+ com_err(argv0, r, "- path initialization failed");
+ xfclose(&input_file);
+ exit(2);
+ }
+
+ dp.cb_vnode_dir = print_vnode_path;
+ dp.cb_vnode_file = print_vnode_path;
+ dp.cb_vnode_link = print_vnode_path;
+ dp.cb_vnode_empty = print_vnode_path;
+ dp.cb_vnode_wierd = print_vnode_path;
+ }
+
+ dp.print_flags = printflags;
+ r = ParseDumpFile(&input_file, &dp);
+ xfclose(&input_file);
+ if (gendump_path) {
+ if (!r) r = DumpDumpEnd(&repair_output);
+ if (!r) r = xfclose(&repair_output);
+ else xfclose(&repair_output);
+ }
+
+ if (verbose && error_count) fprintf(stderr, "*** %d errors\n", error_count);
+ if (r && !quiet) fprintf(stderr, "*** FAILED: %s\n", error_message(r));
+ exit(0);
+}
--- /dev/null
+/*
+ * COPYRIGHT NOTICE
+ * Copyright (c) 1997 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/* UB - Unified Backups */
+/* methods/afs/dumpscan/afsdump_scan.c - General-purpose dump scanner */
+
+#include "dumpscan.h"
+#include <sys/fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+extern int opterr, optind;
+extern char *optarg;
+
+extern XFILE repair_output;
+extern afs_uint32 repair_dumphdr_cb(afs_dump_header *, XFILE *, void *);
+extern afs_uint32 repair_volhdr_cb(afs_vol_header *, XFILE *, void *);
+extern afs_uint32 repair_vnode_cb(afs_vnode *, XFILE *, void *);
+
+char *argv0;
+static char *input_path, *gendump_path;
+static afs_uint32 printflags, repairflags, add_admin;
+static int quiet, verbose, error_count;
+
+static path_hashinfo phi;
+static dump_parser dp;
+
+
+/* Print a usage message and exit */
+static void usage(int status, char *msg)
+{
+ if (msg) fprintf(stderr, "%s: %s\n", argv0, msg);
+ fprintf(stderr, "Usage: %s [options] [file]\n", argv0);
+ fprintf(stderr, " -Pxxx Set print options:\n");
+ fprintf(stderr, " B = Print backup system header (if any)\n");
+ fprintf(stderr, " H = Print AFS dump header\n");
+ fprintf(stderr, " V = Print AFS volume header\n");
+ fprintf(stderr, " v = List vnodes\n");
+ fprintf(stderr, " p = Include path to each vnode\n");
+ fprintf(stderr, " i = Include info for each vnode\n");
+ fprintf(stderr, " d = List directory contents\n");
+ fprintf(stderr, " a = List access control lists\n");
+ fprintf(stderr, " g = Print debugging info\n");
+ fprintf(stderr, " -Rxxx Set repair options:\n");
+ fprintf(stderr, " 0 = Skip null tags\n");
+ fprintf(stderr, " b = Seek backward to find skipped tags\n");
+ fprintf(stderr, " d = Resync after vnode data\n");
+ fprintf(stderr, " v = Resync after corrupted vnodes\n");
+ fprintf(stderr, " -Annn Add all rights for ID nnn to every directory\n");
+ fprintf(stderr, " -h Print this help message\n");
+ fprintf(stderr, " -gxxx Generate a new dump in file xxx\n");
+ fprintf(stderr, " -q Quiet mode (don't print errors)\n");
+ fprintf(stderr, " -v Verbose mode\n");
+ exit(status);
+}
+
+
+/* Parse the argument given to the -P option.
+ * Returns the resulting * dumpscan print flags (DSPRINT_*).
+ * If an unrecognized flag is used, prints an error message and exits.
+ */
+static afs_uint32 parse_printflags(char *flags)
+{
+ afs_uint32 result = 0;
+ char *x;
+
+ for (x = flags; *x; x++) switch (*x) {
+ case 'B': result |= DSPRINT_BCKHDR; continue;
+ case 'H': result |= DSPRINT_DUMPHDR; continue;
+ case 'V': result |= DSPRINT_VOLHDR; continue;
+ case 'v': result |= DSPRINT_ITEM; continue;
+ case 'p': result |= DSPRINT_PATH; continue;
+ case 'i': result |= DSPRINT_VNODE; continue;
+ case 'd': result |= DSPRINT_DIR; continue;
+ case 'a': result |= DSPRINT_ACL; continue;
+ case 'g': result |= DSPRINT_DEBUG; continue;
+ default: usage(1, "Invalid print options!");
+ }
+ return result;
+}
+
+
+/* Parse the argument given to the -R option.
+ * Returns the resulting * dumpscan repair flags (DSFIX_*).
+ * If an unrecognized flag is used, prints an error message and exits.
+ */
+static afs_uint32 parse_repairflags(char *flags)
+{
+ afs_uint32 result = 0;
+ char *x;
+
+ for (x = flags; *x; x++) switch (*x) {
+ case '0': result |= DSFIX_SKIP; continue;
+ case 'b': result |= DSFIX_RSKIP; continue;
+ case 'd': result |= DSFIX_VDSYNC; continue;
+ case 'v': result |= DSFIX_VFSYNC; continue;
+ default: usage(1, "Invalid repair options!");
+ }
+ return result;
+}
+
+
+/* Parse the command-line options */
+static void parse_options(int argc, char **argv)
+{
+ int c;
+
+ /* Set the program name */
+ if (argv0 = strrchr(argv[0], '/')) argv0++;
+ else argv0 = argv[0];
+
+ /* Initialize options */
+ input_path = gendump_path = 0;
+ printflags = repairflags = add_admin = 0;
+ quiet = verbose = 0;
+
+ /* Initialize other stuff */
+ error_count = 0;
+
+ /* Parse the options */
+ while ((c = getopt(argc, argv, "A:P:R:g:hv")) != EOF) {
+ switch (c) {
+ case 'A': add_admin = atoi(optarg); continue;
+ case 'P': printflags = parse_printflags(optarg); continue;
+ case 'R': repairflags = parse_repairflags(optarg); continue;
+ case 'g': gendump_path = optarg; continue;
+ case 'q': quiet = 1; continue;
+ case 'v': verbose = 1; continue;
+ case 'h': usage(0, 0);
+ default: usage(1, "Invalid option!");
+ }
+ }
+
+ if (quiet && verbose) usage(1, "Can't specify both -q and -v");
+
+ /* Parse non-option arguments */
+ if (argc - optind > 1) usage(1, "Too many arguments!");
+ input_path = (argc == optind) ? "-" : argv[optind];
+ if (add_admin && !gendump_path) add_admin = 0;
+}
+
+
+/* A callback to count and print errors */
+static afs_uint32 my_error_cb(afs_uint32 code, int fatal, void *ref, char *msg, ...)
+{
+ va_list alist;
+
+ error_count++;
+ if (!quiet) {
+ va_start(alist, msg);
+ com_err_va(argv0, code, msg, alist);
+ va_end(alist);
+ }
+}
+
+
+/* A callback to print the path of a vnode. */
+static afs_uint32 print_vnode_path(afs_vnode *v, XFILE *X, void *refcon)
+{
+ afs_uint32 r;
+ char *name = 0;
+
+ /* Do repair, but only for known vnode types */
+ if (gendump_path
+ && (!(v->field_mask & F_VNODE_TYPE)
+ || v->type != vFile
+ || v->type != vDirectory
+ || v->type != vSymlink)) {
+ r = repair_vnode_cb(v, X, refcon);
+ if (r) return r;
+ }
+ r = Path_Build(X, &phi, v->vnode, &name, 0);
+ if (!r && name) printf(" Path: %s\n", name);
+ if (name) free(name);
+ return r;
+}
+
+
+static afs_uint32 munge_admin_acl(afs_vnode *v, XFILE *X, void *refcon)
+{
+ struct acl_accessList *acl;
+ int add_entry = 1, remove_entry = -1;
+ int i, o, n;
+
+ acl = (struct acl_accessList *)(v->acl);
+ o = n = ntohl(acl->positive);
+ for (i = 0; i < n; i++)
+ if (ntohl(acl->entries[i].id) == add_admin) add_entry = 0;
+ n = ntohl(acl->negative);
+ for (i = o; i < n + o; i++)
+ if (ntohl(acl->entries[i].id) == add_admin) remove_entry = i;
+
+ if (add_entry) {
+ for (i = (remove_entry < 0) ? o + n : remove_entry; i > o; i--) {
+ acl->entries[i].id = acl->entries[i-1].id;
+ acl->entries[i].rights = acl->entries[i-1].rights;
+ }
+ acl->entries[o].id = htonl(add_admin);
+ acl->entries[o].rights = htonl((PRSFS_READ | PRSFS_LOOKUP
+ | PRSFS_INSERT | PRSFS_DELETE
+ | PRSFS_WRITE | PRSFS_LOCK
+ | PRSFS_ADMINISTER));
+ acl->positive = htonl(o + 1);
+ if (remove_entry < 0) acl->total = htonl(o + n + 1);
+ else acl->negative = htonl(n - 1);
+ } else if (remove_entry >= 0) {
+ for (i = remove_entry; i < o + n - 1; i++) {
+ acl->entries[i].id = acl->entries[i+1].id;
+ acl->entries[i].rights = acl->entries[i+1].rights;
+ }
+ acl->negative = htonl(n - 1);
+ acl->total = htonl(o + n - 1);
+ }
+ return repair_vnode_cb(v, X, refcon);
+}
+
+
+/* Setup for generating a repaired dump */
+static afs_uint32 setup_repair(void)
+{
+ afs_uint32 r;
+
+ r = xfopen(&repair_output, gendump_path, O_RDWR, 0644);
+ if (r) return r;
+
+ dp.cb_dumphdr = repair_dumphdr_cb;
+ dp.cb_volhdr = repair_volhdr_cb;
+ dp.cb_vnode_dir = repair_vnode_cb;
+ dp.cb_vnode_file = repair_vnode_cb;
+ dp.cb_vnode_link = repair_vnode_cb;
+ dp.cb_vnode_empty = repair_vnode_cb;
+ return 0;
+}
+
+
+/* Main program */
+void main(int argc, char **argv)
+{
+ XFILE *X;
+ afs_uint32 r;
+
+ parse_options(argc, argv);
+ initialize_UB_error_table();
+ initialize_UBsp_error_table();
+ initialize_AVds_error_table();
+ r = xfopen(&X, input_path, O_RDONLY, 0);
+ if (r) {
+ com_err(argv0, r, "opening %s", input_path);
+ exit(2);
+ }
+
+ bzero(&dp, sizeof(dp));
+ dp.cb_error = my_error_cb;
+ dp.repair_flags = repairflags;
+ if (X->is_seekable) dp.flags |= DSFLAG_SEEK;
+ else {
+ if (repairflags)
+ fprintf(stderr, "Repair modes available only for seekable dumps\n");
+ if (printflags & DSPRINT_PATH)
+ fprintf(stderr, "Path-printing available only for seekable dumps\n");
+ if (repairflags || (printflags & DSPRINT_PATH))
+ exit(1);
+ }
+
+ if (gendump_path && (r = setup_repair())) {
+ com_err(argv0, r, "setting up repair output");
+ xfclose(X);
+ exit(2);
+ }
+
+ if (printflags & DSPRINT_PATH) {
+ u_int64 where;
+
+ dp.print_flags = printflags & DSPRINT_DEBUG;
+ bzero(&phi, sizeof(phi));
+ phi.p = &dp;
+
+ if ((r = xftell(X, &where))
+ || (r = Path_PreScan(X, &phi, 0))
+ || (r = xfseek(X, &where))) {
+ com_err(argv0, r, "- path initialization failed");
+ xfclose(X);
+ exit(2);
+ }
+
+ dp.cb_vnode_dir = print_vnode_path;
+ dp.cb_vnode_file = print_vnode_path;
+ dp.cb_vnode_link = print_vnode_path;
+ dp.cb_vnode_empty = print_vnode_path;
+ dp.cb_vnode_wierd = print_vnode_path;
+ }
+
+ if (add_admin) {
+ dp.cb_vnode_dir = munge_admin_acl;
+ }
+
+ dp.print_flags = printflags;
+ r = ParseDumpFile(X, &dp);
+ if (gendump_path) {
+ if (!r) r = DumpDumpEnd(&repair_output);
+ if (!r) r = xfclose(&repair_output);
+ else xfclose(&repair_output);
+ }
+
+ if (verbose && error_count) fprintf(stderr, "*** %d errors\n", error_count);
+ if (r && !quiet) fprintf(stderr, "*** FAILED: %s\n", error_message(r));
+ exit(0);
+}
--- /dev/null
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/* backuphdr.c - Parse and print backup system headers */
+
+#include <stdlib.h>
+
+#include "dumpscan.h"
+#include "dumpscan_errs.h"
+#include "stagehdr.h"
+
+afs_uint32 try_backuphdr(XFILE *X, char *tag, tagged_field *field,
+ afs_uint32 value, tag_parse_info *pi,
+ void *g_refcon, void *l_refcon)
+{
+ dump_parser *p = (dump_parser *)g_refcon;
+ backup_system_header bh;
+ u_int64 where;
+ afs_uint32 r;
+
+ /* Which header should we try (if any)? */
+ switch (*tag) {
+ case STAGE_VERSMIN: r = ParseStageHdr(X, tag, &bh); break;
+ default: return DSERR_MAGIC;
+ }
+ if (r) return r;
+
+ /* Do something with it... */
+ if (p->print_flags & DSPRINT_BCKHDR) PrintBackupHdr(&bh);
+ if (p->cb_bckhdr) {
+ r = xftell(X, &where);
+ if (!r && p->cb_bckhdr)
+ r = (p->cb_bckhdr)(&bh, X, p->refcon);
+ if (p->flags & DSFLAG_SEEK) {
+ if (!r) r = xfseek(X, &where);
+ else xfseek(X, &where);
+ }
+ }
+ if (bh.server) free(bh.server);
+ if (bh.part) free(bh.part);
+ if (bh.volname) free(bh.volname);
+ return r;
+}
+
+
+void PrintBackupHdr(backup_system_header *hdr)
+{
+ time_t from = hdr->from_date, to = hdr->to_date, dd = hdr->dump_date;
+
+ printf("* BACKUP SYSTEM HEADER\n");
+ printf(" Version: %d\n", hdr->version);
+ printf(" Volume: %s (%d)\n", hdr->volname, hdr->volid);
+ printf(" Location: %s %s\n", hdr->server, hdr->part);
+ printf(" Level: %d\n", hdr->level);
+ printf(" Range: %d => %d\n", hdr->from_date, hdr->to_date);
+ printf(" == %s", ctime(&from));
+ printf(" => %s", ctime(&to));
+ printf(" Dump Time: %d == %s", hdr->dump_date, ctime(&dd));
+ printf(" Dump Flags: 0x%08x\n", hdr->flags);
+ printf(" Length: %d\n", hdr->dumplen);
+ printf(" File Num: %d\n", hdr->filenum);
+}
--- /dev/null
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/* directory.c - Parse an AFS directory */
+/* See the end of this file for a description of the directory format */
+
+#include <errno.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#include "dumpscan.h"
+#include "dumpscan_errs.h"
+#include "xf_errs.h"
+#include "dumpfmt.h"
+#include "internal.h"
+
+#include <afs/dir.h>
+
+static afs_dir_page page;
+
+#define allocbit(x) (page.header.freebitmap[(x)>>3] & (1 << ((x) & 7)))
+#define DPHE (DHE + 1)
+
+static void fixup(char *name, int l)
+{
+ name += 16;
+ l -= 15;
+
+ while (l-- > 0) {
+ name[0] = name[4];
+ name++;
+ }
+}
+
+afs_uint32 parse_directory(XFILE *X, dump_parser *p, afs_vnode *v,
+ afs_uint32 size, int toeof)
+{
+ afs_dir_entry de;
+ int pgno, i, j, l, n;
+ afs_uint32 r;
+ u_int64 where;
+
+ if (p->print_flags & DSPRINT_DIR) {
+ printf(" VNode Uniqifier Name\n");
+ printf(" ========== ========== ==============================\n");
+ }
+ if ((p->flags & DSFLAG_SEEK) && (r = xftell(X, &where))) return r;
+ for (pgno = 0; toeof || size; pgno++, size -= (toeof ? 0 : AFS_PAGESIZE)) {
+ if ((p->flags & DSFLAG_SEEK) && (r = xfseek(X, &where))) return r;
+ if (r = xfread(X, &page, AFS_PAGESIZE)) {
+ if (toeof && r == ERROR_XFILE_EOF) break;
+ return r;
+ }
+ if ((p->flags & DSFLAG_SEEK) && (r = xftell(X, &where))) return r;
+ if (page.header.tag != htons(1234)) {
+ if (p->cb_error)
+ (p->cb_error)(DSERR_MAGIC, 1, p->err_refcon,
+ "Invalid page tag (%d) in page %d",
+ ntohs(page.header.tag), pgno);
+ return DSERR_MAGIC;
+ }
+ for (i = (pgno ? 1 : DPHE); i < EPP; i++) {
+ if (!allocbit(i)) continue;
+ if (page.entry[i].flag != FFIRST) {
+ if (p->cb_error)
+ (p->cb_error)(DSERR_MAGIC, 0, p->err_refcon,
+ "Invalid entry flag %d in entry %d/%d; skipping...",
+ page.entry[i].flag, pgno, i);
+ continue;
+ }
+ n = (EPP - i - 1) * 32 + 16;
+ for (l = 0; n && page.entry[i].name[l]; l++, n--);
+ if (page.entry[i].name[l]) {
+ if (p->cb_error)
+ (p->cb_error)(DSERR_FMT, 0, p->err_refcon,
+ "Filename too long in entry %d/%d; skipping page",
+ pgno, i);
+ break;
+ }
+/* fixup(page.entry[i].name, l); */
+ if (pgno) de.slot = i - 1 + (pgno - 1) * (EPP - 1) + (EPP - DPHE);
+ else de.slot = i - DPHE;
+ de.name = page.entry[i].name;
+ de.vnode = ntohl(page.entry[i].vnode);
+ de.uniq = ntohl(page.entry[i].vunique);
+ if (p->print_flags & DSPRINT_DIR)
+ printf(" %10d %10d %s\n", de.vnode, de.uniq, de.name);
+ if (p->cb_dirent) {
+ r = (p->cb_dirent)(v, &de, X, p->refcon);
+ }
+ if (p->cb_dirent && (r = (p->cb_dirent)(v, &de, X, p->refcon)))
+ return r;
+ i += ((l + 16) >> 5);
+ }
+ }
+ if ((p->flags & DSFLAG_SEEK) && (r = xfseek(X, &where))) return r;
+ return 0;
+}
+
+
+afs_uint32 ParseDirectory(XFILE *X, dump_parser *p, afs_uint32 size, int toeof)
+{
+ afs_uint32 r;
+
+ r = parse_directory(X, p, 0, size, toeof);
+}
+
+
+typedef struct {
+ char **name;
+ afs_uint32 *vnode;
+ afs_uint32 *vuniq;
+} dirlookup_stat;
+
+
+static afs_uint32 dirlookup_cb(afs_vnode *v, afs_dir_entry *de,
+ XFILE *X, void *refcon)
+{
+ dirlookup_stat *s = (dirlookup_stat *)refcon;
+
+ if (s->name && s->name[0]) { /* Search by filename */
+ if (strcmp(de->name, s->name[0])) return 0; /* Not it! */
+ if (s->vnode) s->vnode[0] = de->vnode;
+ if (s->vuniq) s->vuniq[0] = de->uniq;
+ } else if (s->vnode) { /* Search by vnode */
+ if (de->vnode != s->vnode[0]) return 0; /* Not it! */
+ if (s->name) {
+ s->name[0] = (char *)malloc(strlen(de->name) + 1);
+ if (!s->name[0]) return ENOMEM;
+ strcpy(s->name[0], de->name);
+ }
+ if (s->vuniq) s->vuniq[0] = de->uniq;
+ }
+ return DSERR_DONE;
+}
+
+
+/* Look up an entry in a directory, by name or vnode.
+ * If *name is NULL, we are looking up by vnode.
+ * Otherwise, we are looking for a filename.
+ * In any event, any of name, vnode, vuniq that are
+ * neither NULL nor the search key are filled in on
+ * success.
+ *
+ * Call this with X pointing to the start of the directory,
+ * and size set to the length of the directory.
+ * Returns 0 on success, whether or not the entry is found.
+ */
+afs_uint32 DirectoryLookup(XFILE *X, dump_parser *p, afs_uint32 size,
+ char **name, afs_uint32 *vnode, afs_uint32 *vuniq)
+{
+ dump_parser my_p;
+ dirlookup_stat my_s;
+ afs_uint32 r;
+
+ memset(&my_s, 0, sizeof(my_s));
+ my_s.name = name;
+ my_s.vnode = vnode;
+ my_s.vuniq = vuniq;
+
+ memset(&my_p, 0, sizeof(my_p));
+ my_p.refcon = (void *)&my_s;
+ my_p.err_refcon = p->err_refcon;
+ my_p.cb_error = p->cb_error;
+ my_p.cb_dirent = dirlookup_cb;
+
+ r = parse_directory(X, &my_p, 0, size, 0);
+ if (!r) r = DSERR_DONE;
+ return handle_return(r, X, 0, p);
+}
+
+
+/* AFS directory format:
+ * AFS directories are stored in volume dumps in exactly the same format
+ * that is used on disk, which makes them relatively easy to dump and restore,
+ * but means we have to do some work to interpret them.
+ *
+ * The ACL for a directory is stored on disk in the last part of a "large"
+ * (directory) vnode. This part of the vnode, which has fixed size
+ * SIZEOF_LARGEDISKVNODE - SIZEOF_SMALLDISKVNODE, is copied directly into
+ * the dump file with a tag of 'A' (VTAG_ACL). The structure of this
+ * section is described in <afs/acl.h>.
+ *
+ * The name-to-vnode mappings are also stored exactly as they appear on
+ * disk, using the file data ('f') attribute. As usual, this attribute
+ * consists of a 32-bit number containing the size, immediately followed
+ * by the data itself. The interesting structures and constants are
+ * defined in <afs/dir.h>
+ *
+ * A directory consists of one or more 'pages', each of which is 2K
+ * (AFS_PAGESIZE). Each page contains EPP (currently 64) 'entries', each
+ * of which is 32 bytes. The first page begins with a DirHeader, which
+ * is DHE entries long, and includes a PageHeader. All other pages begin
+ * with just a PageHeader, which is 1 entry long. Every other entry is
+ * a DirEntry, a DirXEntry (name extension), or unused.
+ *
+ * A Page Header contains the following elements:
+ * - pgcount contains a count of the number of pages in the directory,
+ * if the directory is new-style (>128 pages), or 0 if it is
+ * old-style. This field is meaningful only in the Dir Header.
+ * - tag a magic number, which must be 1234
+ * - freecount apparently unused
+ * - freebitmap A bitmap of free entries. Each byte corresponds to 8
+ * entries, with the least significant bit referring to the
+ * first of those. Each bit is set iff the corresponding
+ * entry is allocated. Entries used by the page and dir
+ * headers are considered allocated.
+ *
+ * A Dir Header consists of a Page Header, followed by an allocation map
+ * and hash table. The allocation map contains one byte for each of the
+ * first 128 pages; that byte contains the number of entries in that page
+ * that are allocated. Every page that actually exists has at peast one
+ * entry allocated (the Page Header); if a byte in this map is 0, it means
+ * that the page does not yet exist.
+ *
+ * Each bucket in the hash table is a linked list, using 'blob numbers'
+ * as pointers. A blob number is defined as (page# * EPP) + entry#.
+ * The head of each chain is kept in the hash table, and the next pointers
+ * are kept in the 'next' entry of each directory.
+ *
+ * Directory entries themselves contain the following elements:
+ * - flag Set to FFIRST iff this is the first blob in an entry
+ * (otherwise it will be a name continuation). This is
+ * probably not reliable.
+ * - length Unused
+ * - next Pointer to the next element in this hash chain
+ * - fid FileID (vnode and uniquifier)
+ * - name Filename (null-terminated)
+ */
--- /dev/null
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/* dump.c - Write out parts of a volume dump */
+
+#include "dumpscan.h"
+#include "dumpfmt.h"
+
+#define COPYBUFSIZE 65536
+
+afs_uint32 DumpDumpHeader(XFILE *OX, afs_dump_header *hdr)
+{
+ afs_uint32 r;
+
+ if (r = WriteTagInt32Pair(OX, TAG_DUMPHEADER, hdr->magic, hdr->version))
+ return r;
+
+ if (hdr->field_mask & F_DUMPHDR_VOLID) {
+ if (r = WriteTagInt32(OX, DHTAG_VOLID, hdr->volid)) return r;
+ }
+ if (hdr->field_mask & F_DUMPHDR_VOLNAME) {
+ if (r = WriteByte(OX, DHTAG_VOLNAME)) return r;
+ if (r = WriteString(OX, hdr->volname)) return r;
+ }
+ if (hdr->field_mask & (F_DUMPHDR_FROM | F_DUMPHDR_TO)) {
+ if (r = WriteTagInt16(OX, DHTAG_DUMPTIMES, 2))
+ return r;
+ if (r = WriteInt32(OX, (hdr->field_mask & F_DUMPHDR_FROM)
+ ? hdr->from_date : 0))
+ return r;
+ if (r = WriteInt32(OX, (hdr->field_mask & F_DUMPHDR_TO)
+ ? hdr->to_date : time(0)))
+ return r;
+ }
+ return 0;
+}
+
+
+afs_uint32 DumpVolumeHeader(XFILE *OX, afs_vol_header *hdr)
+{
+ afs_uint32 r;
+ int i;
+
+ if (r = WriteByte(OX, TAG_VOLHEADER)) return r;
+
+ if (hdr->field_mask & F_VOLHDR_VOLID) {
+ if (r = WriteTagInt32(OX, VHTAG_VOLID, hdr->volid)) return r;
+ }
+ if (hdr->field_mask & F_VOLHDR_VOLVERS) {
+ if (r = WriteTagInt32(OX, VHTAG_VERS, hdr->volvers)) return r;
+ }
+ if (hdr->field_mask & F_VOLHDR_VOLNAME) {
+ if (r = WriteByte(OX, VHTAG_VOLNAME)) return r;
+ if (r = WriteString(OX, hdr->volname)) return r;
+ }
+ if (hdr->field_mask & F_VOLHDR_INSERV) {
+ if (r = WriteTagByte(OX, VHTAG_INSERV, hdr->flag_inservice)) return r;
+ }
+ if (hdr->field_mask & F_VOLHDR_BLESSED) {
+ if (r = WriteTagByte(OX, VHTAG_BLESSED, hdr->flag_blessed)) return r;
+ }
+ if (hdr->field_mask & F_VOLHDR_VOLUNIQ) {
+ if (r = WriteTagInt32(OX, VHTAG_VUNIQ, hdr->voluniq)) return r;
+ }
+ if (hdr->field_mask & F_VOLHDR_VOLTYPE) {
+ if (r = WriteTagByte(OX, VHTAG_TYPE, hdr->voltype)) return r;
+ }
+ if (hdr->field_mask & F_VOLHDR_PARENT) {
+ if (r = WriteTagInt32(OX, VHTAG_PARENT, hdr->parent_volid)) return r;
+ }
+ if (hdr->field_mask & F_VOLHDR_CLONE) {
+ if (r = WriteTagInt32(OX, VHTAG_CLONE, hdr->clone_volid)) return r;
+ }
+ if (hdr->field_mask & F_VOLHDR_MAXQ) {
+ if (r = WriteTagInt32(OX, VHTAG_MAXQUOTA, hdr->maxquota)) return r;
+ }
+ if (hdr->field_mask & F_VOLHDR_MINQ) {
+ if (r = WriteTagInt32(OX, VHTAG_MINQUOTA, hdr->minquota)) return r;
+ }
+ if (hdr->field_mask & F_VOLHDR_DISKUSED) {
+ if (r = WriteTagInt32(OX, VHTAG_DISKUSED, hdr->diskused)) return r;
+ }
+ if (hdr->field_mask & F_VOLHDR_NFILES) {
+ if (r = WriteTagInt32(OX, VHTAG_FILECNT, hdr->nfiles)) return r;
+ }
+ if (hdr->field_mask & F_VOLHDR_ACCOUNT) {
+ if (r = WriteTagInt32(OX, VHTAG_ACCOUNT, hdr->account_no)) return r;
+ }
+ if (hdr->field_mask & F_VOLHDR_OWNER) {
+ if (r = WriteTagInt32(OX, VHTAG_OWNER, hdr->owner)) return r;
+ }
+ if (hdr->field_mask & F_VOLHDR_CREATE_DATE) {
+ if (r = WriteTagInt32(OX, VHTAG_CREAT, hdr->create_date)) return r;
+ }
+ if (hdr->field_mask & F_VOLHDR_ACCESS_DATE) {
+ if (r = WriteTagInt32(OX, VHTAG_ACCESS, hdr->access_date)) return r;
+ }
+ if (hdr->field_mask & F_VOLHDR_UPDATE_DATE) {
+ if (r = WriteTagInt32(OX, VHTAG_UPDATE, hdr->update_date)) return r;
+ }
+ if (hdr->field_mask & F_VOLHDR_EXPIRE_DATE) {
+ if (r = WriteTagInt32(OX, VHTAG_EXPIRE, hdr->expire_date)) return r;
+ }
+ if (hdr->field_mask & F_VOLHDR_BACKUP_DATE) {
+ if (r = WriteTagInt32(OX, VHTAG_BACKUP, hdr->backup_date)) return r;
+ }
+ if (hdr->field_mask & F_VOLHDR_OFFLINE_MSG) {
+ if (r = WriteTagInt32(OX, VHTAG_OFFLINE, hdr->offline_msg)) return r;
+ }
+ if (hdr->field_mask & F_VOLHDR_MOTD) {
+ if (r = WriteTagInt32(OX, VHTAG_MOTD, hdr->motd_msg)) return r;
+ }
+ if (hdr->field_mask & F_VOLHDR_WEEKUSE) {
+ if (r = WriteTagInt16(OX, VHTAG_WEEKUSE, 7)) return r;
+ for (i = 0; i < 7; i++)
+ if (r = WriteInt32(OX, hdr->weekuse[i])) return r;
+ }
+ if (hdr->field_mask & F_VOLHDR_DAYUSE_DATE) {
+ if (r = WriteTagInt32(OX, VHTAG_DUDATE, hdr->dayuse_date)) return r;
+ }
+ if (hdr->field_mask & F_VOLHDR_DAYUSE) {
+ if (r = WriteTagInt32(OX, VHTAG_DAYUSE, hdr->dayuse)) return r;
+ }
+ return 0;
+}
+
+
+afs_uint32 DumpVNode(XFILE *OX, afs_vnode *v)
+{
+ afs_uint32 r;
+
+ if (r = WriteTagInt32Pair(OX, TAG_VNODE, v->vnode, v->vuniq)) return r;
+
+ if (v->field_mask & F_VNODE_TYPE) {
+ if (r = WriteTagByte(OX, VTAG_TYPE, v->type)) return r;
+ }
+ if (v->field_mask & F_VNODE_NLINKS) {
+ if (r = WriteTagInt16(OX, VTAG_NLINKS, v->nlinks)) return r;
+ }
+ if (v->field_mask & F_VNODE_DVERS) {
+ if (r = WriteTagInt32(OX, VTAG_DVERS, v->datavers)) return r;
+ }
+ if (v->field_mask & F_VNODE_SDATE) {
+ if (r = WriteTagInt32(OX, VTAG_SERVER_DATE, v->server_date)) return r;
+ }
+ if (v->field_mask & F_VNODE_AUTHOR) {
+ if (r = WriteTagInt32(OX, VTAG_AUTHOR, v->author)) return r;
+ }
+ if (v->field_mask & F_VNODE_OWNER) {
+ if (r = WriteTagInt32(OX, VTAG_OWNER, v->owner)) return r;
+ }
+ if (v->field_mask & F_VNODE_GROUP) {
+ if (r = WriteTagInt32(OX, VTAG_GROUP, v->group)) return r;
+ }
+ if (v->field_mask & F_VNODE_MODE) {
+ if (r = WriteTagInt16(OX, VTAG_MODE, v->mode)) return r;
+ }
+ if (v->field_mask & F_VNODE_PARENT) {
+ if (r = WriteTagInt32(OX, VTAG_PARENT, v->parent)) return r;
+ }
+ if (v->field_mask & F_VNODE_CDATE) {
+ if (r = WriteTagInt32(OX, VTAG_CLIENT_DATE, v->client_date)) return r;
+ }
+ if (v->field_mask & F_VNODE_ACL) {
+ if (r = WriteByte(OX, VTAG_ACL)) return r;
+ if (r = xfwrite(OX, v->acl, SIZEOF_LARGEDISKVNODE - SIZEOF_SMALLDISKVNODE))
+ return r;
+ }
+ return 0;
+}
+
+
+afs_uint32 DumpVNodeData(XFILE *OX, char *buf, afs_uint32 size)
+{
+ afs_uint32 r;
+
+ if (r = WriteTagInt32(OX, VTAG_DATA, size)) return r;
+ if (r = xfwrite(OX, buf, size)) return r;
+ return 0;
+}
+
+
+afs_uint32 CopyVNodeData(XFILE *OX, XFILE *X, afs_uint32 size)
+{
+ afs_uint32 r, n;
+ static char buf[COPYBUFSIZE];
+
+ if (r = WriteTagInt32(OX, VTAG_DATA, size)) return r;
+ while (size) {
+ n = (size > COPYBUFSIZE) ? COPYBUFSIZE : size;
+ if (r = xfread(X, buf, n)) return r;
+ if (r = xfwrite(OX, buf, n)) return r;
+ size -= n;
+ }
+ return 0;
+}
+
+
+afs_uint32 DumpDumpEnd(XFILE *OX) {
+ afs_uint32 r;
+
+ if (r = WriteTagInt32(OX, TAG_DUMPEND, DUMPENDMAGIC)) return r;
+ return 0;
+}
--- /dev/null
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/* dumpfmt.h - Description of AFS dump format */
+
+#ifndef _DUMPFMT_H_
+#define _DUMPFMT_H_
+
+#include "intNN.h"
+
+/* AFS dump file format:
+ * All data in AFS dumps is tagged; that is, each data item is preceeded
+ * by a 1-byte tag which identifies what the data item is. There is no
+ * explicit mention of what the data type is, but the type of each possible
+ * data item (and thus, each possible tag) is fixed. Usually this is
+ * a relatively simple, fixed amount of data (byte, short, word), but
+ * sometimes it is more complex.
+ *
+ * There is some amount of structure to an AFS volume dump. Basically,
+ * you get a dump header, followed by a volume header, followed by some
+ * vnodes, followed by a dump end. Each of these items (header, vnode,
+ * dump end) consists of a tag, a fixed amount of required information,
+ * and 0 or more tagged attributes (except dump-end, which has no attributes).
+ *
+ * Vnodes, in turn, are usually listed in a particular order. First, we
+ * list all the directory vnodes in the volume, in increasing order by
+ * vnode. Then, we list all the file vnodes, again in increasing order.
+ * Directory vnodes must have a complete set of attributes and data, but
+ * in an incremental dump, file vnodes may have no attributes if the vnode
+ * has not changed since the reference date.
+ *
+ * The primary purpose of this file is to define the tags and some magic
+ * numbers. There is also some information that is defined in the Transarc
+ * provided header files.
+ */
+
+
+/** MAGIC NUMBERS **/
+#define DUMPVERSION 1
+#define DUMPBEGINMAGIC 0xb3a11322
+#define DUMPENDMAGIC 0x3a214b6e
+
+
+/** TOP-LEVEL TAGS **/
+#define TAG_DUMPHEADER 1
+#define TAG_VOLHEADER 2
+#define TAG_VNODE 3
+#define TAG_DUMPEND 4
+
+
+/** DUMP HEADER TAGS **/
+#define DHTAG_VOLNAME 'n'
+#define DHTAG_VOLID 'v'
+#define DHTAG_DUMPTIMES 't'
+
+
+/** VOLUME HEADER TAGS **/
+#define VHTAG_VOLID 'i'
+#define VHTAG_VERS 'v'
+#define VHTAG_VOLNAME 'n'
+#define VHTAG_INSERV 's'
+#define VHTAG_BLESSED 'b'
+#define VHTAG_VUNIQ 'u'
+#define VHTAG_TYPE 't'
+#define VHTAG_PARENT 'p'
+#define VHTAG_CLONE 'c'
+#define VHTAG_MAXQUOTA 'q'
+#define VHTAG_MINQUOTA 'm'
+#define VHTAG_DISKUSED 'd'
+#define VHTAG_FILECNT 'f'
+#define VHTAG_ACCOUNT 'a'
+#define VHTAG_OWNER 'o'
+#define VHTAG_CREAT 'C'
+#define VHTAG_ACCESS 'A'
+#define VHTAG_UPDATE 'U'
+#define VHTAG_EXPIRE 'E'
+#define VHTAG_BACKUP 'B'
+#define VHTAG_OFFLINE 'O'
+#define VHTAG_MOTD 'M'
+#define VHTAG_WEEKUSE 'W'
+#define VHTAG_DUDATE 'D'
+#define VHTAG_DAYUSE 'Z'
+
+
+/** VNODE TAGS **/
+#define VTAG_TYPE 't'
+#define VTAG_NLINKS 'l'
+#define VTAG_DVERS 'v'
+#define VTAG_CLIENT_DATE 'm'
+#define VTAG_AUTHOR 'a'
+#define VTAG_OWNER 'o'
+#define VTAG_GROUP 'g'
+#define VTAG_MODE 'b'
+#define VTAG_PARENT 'p'
+#define VTAG_SERVER_DATE 's'
+#define VTAG_ACL 'A'
+#define VTAG_DATA 'f'
+
+
+#define AFS_DIR_EPP 64
+
+typedef struct {
+ afs_uint16 pgcount;
+ afs_uint16 tag;
+ char freecount;
+ char freebitmap[AFS_DIR_EPP/8];
+ char padding[32 - (5 + AFS_DIR_EPP/8)];
+} afs_dir_pagehdr;
+
+typedef struct {
+ char flag;
+ char length;
+ afs_uint16 next;
+ afs_uint32 vnode;
+ afs_uint32 vunique;
+ char name[16];
+ char padding[4];
+} afs_dir_direntry;
+
+typedef union {
+ afs_dir_pagehdr header;
+ afs_dir_direntry entry[AFS_DIR_EPP];
+} afs_dir_page;
+
+#endif /* _DUMPFMT_H_ */
--- /dev/null
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/* dumpscan.h - Public interface */
+
+#ifndef _DUMPSCAN_H_
+#define _DUMPSCAN_H_
+
+#include "intNN.h"
+#include "xfiles.h"
+
+#include <lock.h>
+#include <afs/afsint.h>
+#include <afs/nfs.h>
+#include <afs/ihandle.h>
+#include <afs/vnode.h>
+#include <afs/cmd.h>
+#include <afs/auth.h>
+#include <afs/bnode.h>
+#include <afs/cellconfig.h>
+#include <afs/kautils.h>
+#include <afs/pterror.h>
+#include <afs/vlserver.h>
+#include <afs/volser.h>
+#include <ubik.h>
+
+/* Random useful types */
+typedef struct tagged_field tagged_field;
+typedef struct tag_parse_info tag_parse_info;
+typedef afs_uint32 (*tag_parser)(XFILE *, unsigned char *, tagged_field *,
+ afs_uint32, tag_parse_info *, void *, void *);
+
+/* Error codes used within dumpscan.
+ * Any of the routines declared below, or callbacks used by them,
+ * may signal a system error by returning the error number, or
+ * some other error by returning a com_err code. Note that
+ * ParseTaggedData does _not_ return DSERR_TAG; instead, it returns
+ * 0, assuming the tag will be handled at a higher level.
+ *
+ * In addition, these errors may be reported to the caller of
+ * ParseDumpFile using the error callback. Such reports will be
+ * issued whether or not error recovery is possible or attempted.
+ *
+ * NB: These errors are now in dumpscan_errs.h
+ */
+
+
+/* Backup system dump header */
+/* Right now, this looks a lot like an old stage header. Eventually, it
+ * should contain enough fields to fully represent headers from old or
+ * new stage, Transarc, or other backup systems, and the appropriate read
+ * functions should extract as much data as possible from the actual file
+ * to fill this in. */
+typedef struct {
+ afs_uint32 version;
+ afs_uint32 from_date;
+ afs_uint32 to_date;
+ afs_uint32 dump_date;
+ afs_uint32 filenum;
+ unsigned char *server;
+ unsigned char *part;
+ unsigned char *volname;
+ afs_uint32 volid;
+ afs_uint32 dumplen;
+ afs_uint32 level;
+ afs_uint32 magic;
+ afs_uint32 cksum;
+ afs_uint32 flags;
+} backup_system_header;
+
+
+/** AFS dump header **/
+#define F_DUMPHDR_VOLID 0x00000001
+#define F_DUMPHDR_VOLNAME 0x00000002
+#define F_DUMPHDR_FROM 0x00000004
+#define F_DUMPHDR_TO 0x00000008
+typedef struct {
+ u_int64 offset; /* Where in the file is it? */
+ afs_uint32 field_mask; /* What fields are present? */
+ afs_uint32 magic; /* Magic number */
+ afs_uint32 version; /* Dump format version */
+ afs_uint32 volid; /* VolID of volume in dump */
+ unsigned char *volname; /* Name of volume in dump */
+ afs_uint32 from_date; /* Reference date */
+ afs_uint32 to_date; /* Date of dump */
+} afs_dump_header;
+
+
+/** AFS volume header **/
+#define F_VOLHDR_VOLID 0x00000001
+#define F_VOLHDR_VOLVERS 0x00000002
+#define F_VOLHDR_VOLNAME 0x00000004
+#define F_VOLHDR_INSERV 0x00000008
+#define F_VOLHDR_BLESSED 0x00000010
+#define F_VOLHDR_VOLUNIQ 0x00000020
+#define F_VOLHDR_VOLTYPE 0x00000040
+#define F_VOLHDR_PARENT 0x00000080
+#define F_VOLHDR_CLONE 0x00000100
+#define F_VOLHDR_MAXQ 0x00000200
+#define F_VOLHDR_MINQ 0x00000400
+#define F_VOLHDR_DISKUSED 0x00000800
+#define F_VOLHDR_NFILES 0x00001000
+#define F_VOLHDR_ACCOUNT 0x00002000
+#define F_VOLHDR_OWNER 0x00004000
+#define F_VOLHDR_CREATE_DATE 0x00008000
+#define F_VOLHDR_ACCESS_DATE 0x00010000
+#define F_VOLHDR_UPDATE_DATE 0x00020000
+#define F_VOLHDR_EXPIRE_DATE 0x00040000
+#define F_VOLHDR_BACKUP_DATE 0x00080000
+#define F_VOLHDR_OFFLINE_MSG 0x00100000
+#define F_VOLHDR_MOTD 0x00200000
+#define F_VOLHDR_WEEKUSE 0x00400000
+#define F_VOLHDR_DAYUSE 0x00800000
+#define F_VOLHDR_DAYUSE_DATE 0x01000000
+typedef struct {
+ u_int64 offset; /* Where in the file is it? */
+ afs_uint32 field_mask; /* What fields are present? */
+ afs_uint32 volid; /* Volume ID */
+ afs_uint32 volvers; /* ?? */
+ unsigned char *volname; /* Volume Name */
+ int flag_inservice; /* Inservice flag (0 or not) */
+ int flag_blessed; /* Blessed to come online (0 or not) */
+ afs_uint32 voluniq; /* Volume uniquifier */
+ int voltype; /* Volume type */
+ afs_uint32 parent_volid; /* Parent volume ID */
+ afs_uint32 clone_volid; /* Clone volume ID */
+ afs_uint32 maxquota; /* Max quota */
+ afs_uint32 minquota; /* Min quota (obsolete) */
+ afs_uint32 diskused; /* Disk blocks used */
+ afs_uint32 nfiles; /* Number of files in volume */
+ afs_uint32 account_no; /* Account number (unused) */
+ afs_uint32 owner; /* Volume owner */
+ afs_uint32 create_date; /* Creation date of this copy */
+ afs_uint32 access_date; /* Last access */
+ afs_uint32 update_date; /* Last modification */
+ afs_uint32 expire_date; /* Expiration (unused) */
+ afs_uint32 backup_date; /* Last backup clone */
+ unsigned char *offline_msg; /* Offline message */
+ unsigned char *motd_msg; /* Volume MOTD */
+ afs_uint32 weekuse[7]; /* Weekuse data */
+ afs_uint32 dayuse; /* # accesses in last day */
+ afs_uint32 dayuse_date; /* Date for which dayuse is valid */
+} afs_vol_header;
+
+
+/** AFS vnode **/
+#define F_VNODE_TYPE 0x00000001
+#define F_VNODE_NLINKS 0x00000002
+#define F_VNODE_PARENT 0x00000004
+#define F_VNODE_DVERS 0x00000008
+#define F_VNODE_AUTHOR 0x00000010
+#define F_VNODE_OWNER 0x00000020
+#define F_VNODE_GROUP 0x00000040
+#define F_VNODE_MODE 0x00000080
+#define F_VNODE_CDATE 0x00000100
+#define F_VNODE_SDATE 0x00000200
+#define F_VNODE_SIZE 0x00000800
+#define F_VNODE_DATA 0x00001000
+#define F_VNODE_ACL 0x00000400
+typedef struct {
+ u_int64 offset; /* Where in the file is it? */
+ afs_uint32 field_mask; /* What fields are present? */
+ afs_uint32 vnode; /* Vnode number */
+ afs_uint32 vuniq; /* Uniquifier */
+ int type; /* Vnode type */
+ afs_uint16 nlinks; /* Number of links (should be in 1 dir!) */
+ afs_uint32 parent; /* Parent vnode */
+ afs_uint32 datavers; /* Data version */
+ afs_uint32 author; /* Last writer */
+ afs_uint32 owner; /* Owner UID */
+ afs_uint32 group; /* Owning group */
+ afs_uint16 mode; /* UNIX mode bits */
+ afs_uint32 client_date; /* Last modified date from client */
+ afs_uint32 server_date; /* Last modified date on server */
+ afs_uint32 size; /* Size of data */
+ u_int64 d_offset; /* Where in the file is the data? */
+ unsigned char acl[SIZEOF_LARGEDISKVNODE - SIZEOF_SMALLDISKVNODE];
+} afs_vnode;
+
+
+/** AFS directory entry **/
+typedef struct {
+ int slot; /* Directory slot # (info only) */
+ char *name; /* Name of entry */
+ afs_uint32 vnode; /* Vnode number */
+ afs_uint32 uniq; /* Uniquifier */
+} afs_dir_entry;
+
+
+/** Tagged field definitions **/
+#define DKIND_NOOP 0x00 /* No data */
+#define DKIND_BYTE 0x10 /* 1 byte - decimal */
+#define DKIND_HEX8 0x11 /* 1 byte - hex */
+#define DKIND_CHAR 0x12 /* 1 byte - character */
+#define DKIND_FLAG 0x13 /* 1 byte - true/false */
+#define DKIND_INT16 0x20 /* 2 bytes - decimal */
+#define DKIND_HEX16 0x21 /* 2 bytes - hex */
+#define DKIND_INT32 0x30 /* 4 bytes - decimal */
+#define DKIND_HEX32 0x31 /* 4 bytes - hex */
+#define DKIND_TIME 0x32 /* 4 bytes - time */
+#define DKIND_STRING 0x40 /* ASCIIZ string */
+#define DKIND_SPECIAL 0x50 /* Custom parser */
+#define DKIND_MASK (~0x0f)
+struct tag_parse_info {
+ void *err_refcon;
+ afs_uint32 (*cb_error)(afs_uint32, int, void *, char *, ...);
+ afs_uint32 flags;
+#define TPFLAG_SKIP 0x0001
+#define TPFLAG_RSKIP 0x0002
+ int shift_offset;
+ u_int64 shift_start;
+};
+struct tagged_field {
+ char tag; /* Tag character */
+ int kind; /* Kind of object */
+ char *label; /* Label to use (for debugging) */
+ tag_parser func; /* Parser function (for DKIND_SPECIAL) */
+ void *refptr; /* Reference pointer (for parser's use) */
+ int refarg; /* Reference argument (for parser's use) */
+};
+
+
+/** Control structure for parsing volume dumps **/
+typedef struct {
+ /* Callback functions:
+ * Whenever a "complex" object is parsed, we call a callback function.
+ * The callback gets a pointer to the complex object, the file pointer
+ * for the dump we're parsing, and the value of refcon in this structure.
+ * Callbacks should return 0 if all is well, non-0 to abort the dump.
+ * By convention, positive numbers should be errno values, and negative
+ * numbers can be used for other things. It is OK to _try_ to seek anywhere
+ * in the file. Beware, though, that the input is not always seekable.
+ * Also, note that the structures passed to these callbacks are going to
+ * go away after the callback returns. There is no way to prevent this;
+ * make a copy if you want one.
+ */
+ void *refcon;
+ afs_uint32 (*cb_bckhdr)(backup_system_header *, XFILE *, void *); /* Backup */
+ afs_uint32 (*cb_dumphdr)(afs_dump_header *, XFILE *, void *); /* Dump hdr */
+ afs_uint32 (*cb_volhdr)(afs_vol_header *, XFILE *, void *); /* Volume hdr */
+ afs_uint32 (*cb_vnode_dir)(afs_vnode *, XFILE *, void *); /* Directory */
+ afs_uint32 (*cb_vnode_file)(afs_vnode *, XFILE *, void *); /* File */
+ afs_uint32 (*cb_vnode_link)(afs_vnode *, XFILE *, void *); /* Symlink */
+ afs_uint32 (*cb_vnode_empty)(afs_vnode *, XFILE *, void *); /* vnode+uniq */
+ afs_uint32 (*cb_vnode_wierd)(afs_vnode *, XFILE *, void *); /* Unknown type */
+
+ /* This function is called when there is an error in the dump. */
+ /* (cb_error)(errno, fatal, refcon, msg_fmt, msg_args...) */
+ void *err_refcon; /* If set, use instead of refcon for dir entries */
+ afs_uint32 (*cb_error)(afs_uint32, int, void *, char *, ...);
+
+ /* This function is called for each directory entry, if set */
+ afs_uint32 (*cb_dirent)(afs_vnode *, afs_dir_entry *, XFILE *, void *);
+
+ int flags; /* Flags and options */
+#define DSFLAG_SEEK 0x0001 /* Input file is seekable */
+
+ int print_flags; /* Flags to control what is printed */
+#define DSPRINT_BCKHDR 0x0001 /* Print backup system header */
+#define DSPRINT_DUMPHDR 0x0002 /* Print AFS dump header */
+#define DSPRINT_VOLHDR 0x0004 /* Print AFS volume header */
+#define DSPRINT_ITEM 0x0010 /* Print top-level tags */
+#define DSPRINT_VNODE 0x0020 /* Print vnode attributes */
+#define DSPRINT_ACL 0x0040 /* Print directory ACL's */
+#define DSPRINT_DIR 0x0080 /* Print directory contents */
+#define DSPRINT_DEBUG 0x0100 /* Print debugging info */
+#define DSPRINT_PATH 0x0200 /* Print vnode paths */
+
+ int repair_flags; /* Flags to control what is repaired.
+ * Most of these _require_ DSFLAG_SEEK */
+#define DSFIX_SKIP 0x0001 /* Try to skip null tags */
+#define DSFIX_RSKIP 0x0002 /* Seek back to fing skipped tags */
+#define DSFIX_VDSYNC 0x0004 /* Resync location after vnode data */
+#define DSFIX_VFSYNC 0x0008 /* Try to resync after bad vnode */
+
+ /** Things below this point for internal use only **/
+ afs_uint32 vol_uniquifier;
+} dump_parser;
+
+
+/** Hash table and control info for pathname manipulation **/
+typedef struct vhash_ent {
+ struct vhash_ent *next; /* Pointer to next entry */
+ afs_uint32 vnode; /* VNode number */
+ afs_uint32 parent; /* Parent VNode number */
+ u_int64 v_offset; /* Offset to start of vnode */
+ u_int64 d_offset; /* Offset to data (0 if none) */
+ afs_uint32 d_size; /* Size of data */
+} vhash_ent;
+typedef struct {
+ afs_uint32 n_vnodes; /* Number of vnodes in volume */
+ afs_uint32 n_dirs; /* Number of file vnodes */
+ afs_uint32 n_files; /* Number of directory vnodes */
+ int hash_size; /* Hash table size (bits) */
+ vhash_ent **hash_table; /* Hash table */
+ dump_parser *p; /* Dump parser to use */
+} path_hashinfo;
+
+
+/** Function prototypes **/
+/** Only the functions declared below are public interfaces **/
+/** Maybe someday, I'll write man pages for these **/
+
+/* primitive.c - I/O primitives */
+extern afs_uint32 ReadByte(XFILE *, unsigned char *);
+extern afs_uint32 ReadInt16(XFILE *, afs_uint16 *);
+extern afs_uint32 ReadInt32(XFILE *, afs_uint32 *);
+extern afs_uint32 ReadString(XFILE *, unsigned char **);
+extern afs_uint32 WriteByte(XFILE *, unsigned char);
+extern afs_uint32 WriteInt16(XFILE *, afs_uint16);
+extern afs_uint32 WriteInt32(XFILE *, afs_uint32);
+extern afs_uint32 WriteString(XFILE *, unsigned char *);
+extern afs_uint32 WriteTagByte(XFILE *, unsigned char, unsigned char);
+extern afs_uint32 WriteTagInt16(XFILE *, unsigned char, afs_uint16);
+extern afs_uint32 WriteTagInt32(XFILE *, unsigned char, afs_uint32);
+extern afs_uint32 WriteTagInt32Pair(XFILE *, unsigned char, afs_uint32, afs_uint32);
+
+/* parsetag.c - Parse tagged data */
+extern afs_uint32 ParseTaggedData(XFILE *, tagged_field *, unsigned char *,
+ tag_parse_info *, void *, void *);
+
+/* stagehdr.c - Parse and dump Stage dump headers */
+extern afs_uint32 ParseStageHdr(XFILE *, unsigned char *, backup_system_header *);
+extern afs_uint32 DumpStagehdr(XFILE *, backup_system_header *);
+
+/* backuphdr.c - Parse and print backup system headers */
+extern void PrintBackupHdr(backup_system_header *);
+
+/* parsedump.c - Parse all or part of a volume dump */
+extern afs_uint32 ParseDumpFile(XFILE *, dump_parser *);
+extern afs_uint32 ParseDumpHeader(XFILE *, dump_parser *);
+extern afs_uint32 ParseVolumeHeader(XFILE *, dump_parser *);
+extern afs_uint32 ParseVNode(XFILE *, dump_parser *);
+
+
+/* directory.c - Directory parsing and lookup */
+extern afs_uint32 ParseDirectory(XFILE *, dump_parser *, afs_uint32, int);
+extern afs_uint32 DirectoryLookup(XFILE *, dump_parser *, afs_uint32,
+ char **, afs_uint32 *, afs_uint32 *);
+
+/* dump.c - Dump parts of a volume dump */
+extern afs_uint32 DumpDumpHeader(XFILE *, afs_dump_header *);
+extern afs_uint32 DumpVolumeHeader(XFILE *, afs_vol_header *);
+extern afs_uint32 DumpVNode(XFILE *, afs_vnode *);
+extern afs_uint32 DumpVnodeData(XFILE *, char *, afs_uint32);
+extern afs_uint32 CopyVnodeData(XFILE *, XFILE *, afs_uint32);
+
+/* pathname.c - Follow and construct pathnames */
+extern afs_uint32 Path_PreScan(XFILE *, path_hashinfo *, int);
+extern void Path_FreeHashTable(path_hashinfo *);
+extern afs_uint32 Path_Follow(XFILE *, path_hashinfo *, char *, vhash_ent *);
+extern afs_uint32 Path_Build(XFILE *, path_hashinfo *, afs_uint32, char **, int);
+
+#endif
--- /dev/null
+# COPYRIGHT NOTICE
+# Copyright (c) 1997 Carnegie Mellon University
+# All Rights Reserved.
+#
+# Permission to use, copy, modify and distribute this software and its
+# documentation is hereby granted, provided that both the copyright
+# notice and this permission notice appear in all copies of the
+# software, derivative works or modified versions, and any portions
+# thereof, and that both notices appear in supporting documentation.
+#
+# CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+# CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+# ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+#
+# Carnegie Mellon requests users of this software to return to
+#
+# Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
+# School of Computer Science
+# Carnegie Mellon University
+# Pittsburgh PA 15213-3890
+#
+# any improvements or extensions that they make and grant Carnegie Mellon
+# the rights to redistribute these changes.
+
+# UB - Unified Backups
+# methods/afs/dumpscan/afsdump_errs.et - AFS dump scanner errors
+
+error_table AVds
+ ec DSERR_TAG, "Unknown tag in AFS volume dump"
+ ec DSERR_MAGIC, "Bad magic number in AFS volume dump"
+ ec DSERR_BOGUS, "Bogus value in AFS volume dump"
+ ec DSERR_FMT, "AFS volume dump format incorrect"
+ ec DSERR_KEEP, "[AFS dumpscan internal: keep string]"
+ ec DSERR_PANIC, "[AFS dumpscan internal: panic]"
+ ec DSERR_DONE, "[AFS dumpscan internal: done]"
+ ec DSERR_MEM, "[AFS dumpscan internal: out of memory]"
+end
--- /dev/null
+/*
+ * $Id$
+ *
+ * dumptool - A tool to manage MR-AFS dump files
+ *
+ * The dump file format ought to be documented _somewhere_, and
+ * this seems like a good as a place as any ...
+ *
+ * A AFS dump file is marked off into a series of sections. Each
+ * section marked by a dump tag. A tag is a single byte who's value
+ * corresponds with the next section. The sections are (in order):
+ *
+ * DUMPHEADER (tag 0x01)
+ * VOLUMEHEADER (tag 0x02)
+ * VNODE (tag 0x03)
+ * DUMPEND (tag 0x04)
+ *
+ * Descriptions of the sections follow. Note that in all cases, data is
+ * stored in the dump in network byte order.
+ *
+ * DUMPHEADER:
+ *
+ * DUMPHEADER contains two parts: the DUMPMAGIC magic number (32 bits)
+ * and the dump header itself.
+ *
+ * The dump header itself consists of a series of tagged values,
+ * each tag marking out members of the DumpHeader structure. The
+ * routine ReadDumpHeader explains the specifics of these tags.
+ *
+ * VOLUMEHEADER:
+ *
+ * VOLUMEHEADER is a series of tagged values corresponding to the elements
+ * of the VolumeDiskData structure. See ReadVolumeHeader for more
+ * information
+ *
+ * VNODE:
+ *
+ * The VNODE section is all vnodes contained in the volume (each vnode
+ * itself is marked with the VNODE tag, so it's really a sequence of
+ * VNODE tags, unlike other sections).
+ *
+ * Each vnode consists of three parts: the vnode number (32 bits), the
+ * uniqifier (32 bits), and a tagged list of elements corresponding to
+ * the elements of the VnodeDiskData structure. See ScanVnodes for
+ * more information. Note that if file data is associated with a vnode,
+ * it will be contained here.
+ *
+ * DUMPEND:
+ *
+ * The DUMPEND section consists of one part: the DUMPENDMAGIC magic
+ * number (32 bits).
+ *
+ * Notes:
+ *
+ * The tagged elements are all ASCII letters, as opposed to the section
+ * headers (which are 0x01, 0x02, ...). Thus, an easy way to tell when
+ * you've reached the end of an element sequence is to check to see if
+ * the next tag is a printable character (this code tests for < 20).
+ *
+ * "vos dump" dumps the large vnode index, then the small vnode index,
+ * so directories will appear first in the VNODE section.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <termios.h>
+#include <fnmatch.h>
+
+#include <lock.h>
+#include <afs/param.h>
+#include <afs/afsint.h>
+#include <afs/nfs.h>
+#include <afs/acl.h>
+#if !defined(PRE_AFS_36) && !defined(RESIDENCY)
+#include <afs/ihandle.h>
+#endif /* !defined(PRE_AFS_36) && !defined(RESIDENCY) */
+#include <afs/vnode.h>
+#include <afs/volume.h>
+
+#ifdef RESIDENCY
+#include <afs/rsdefs.h>
+#include <afs/remioint.h>
+#endif /* RESIDENCY */
+
+#include <afs/dir.h>
+
+/*
+ * Sigh. Linux blows it again
+ */
+
+#ifdef linux
+#include <pty.h>
+#endif
+
+/*
+ * Stuff that is in private AFS header files, unfortunately
+ */
+
+#define DUMPVERSION 1
+#define DUMPENDMAGIC 0x3A214B6E
+#define DUMPBEGINMAGIC 0xB3A11322
+#define D_DUMPHEADER 1
+#define D_VOLUMEHEADER 2
+#define D_VNODE 3
+#define D_DUMPEND 4
+#define D_MAX 20
+
+#define MAXDUMPTIMES 50
+
+struct DumpHeader {
+ int32_t version;
+ VolumeId volumeId;
+ char volumeName[VNAMESIZE];
+ int nDumpTimes; /* Number of pairs */
+ struct {
+ int32_t from, to;
+ } dumpTimes[MAXDUMPTIMES];
+};
+
+/*
+ * Our command-line arguments
+ */
+
+#ifdef RESIDENCY
+struct {
+ int Algorithm; /* Conversion algorithm */
+ int Size; /* Directory hierarchy size */
+ int FSType; /* File system type */
+ int DeviceTag; /* Device Tag */
+} rscmdlineinfo[RS_MAXRESIDENCIES];
+
+/*
+ * This stuff comes from ufsname.c (which itself takes it from
+ * ufs_interfaces.c)
+ */
+
+/* There is an assumption that all of the prefixes will have exactly one '/' */
+static char *Ufs_Prefixes[] = {"/ufs", "/slowufs", "/cdmf", "/sdmf"};
+#define MAX_ITERATIONS 10
+#define UFS_SUMMARYTREENAME "Summaries"
+#define UFS_STAGINGTREENAME "Staging"
+#define UFS_VOLUMEHEADERTREENAME "VolHeaders"
+#define UFS_VOLUMETREENAME "Volumes"
+#define UFS_ALGORITHMBASE 'A'
+#define UFS_MOUNTPOINTBASE 'a'
+#define UFS_ALGORITHMS 3
+#define UFS_LINK_MAX 64 /* Arbitrary. */
+#define HARD_LINKED_FILE -2
+#define TAGSTONAME(FileName, MountPoint, Sections, Level1, RWVolume, Vnode, Uniquifier, Algorithm) \
+{ \
+ if (Level1) \
+ sprintf(FileName,"%s/%lu/%lu/%c%lu.%lu.%lu.%lu.%lu", MountPoint, \
+ (Sections)[0], (Sections)[1], UFS_ALGORITHMBASE + Algorithm, \
+ (Sections)[2], (Sections)[3], RWVolume, Vnode, Uniquifier); \
+ else \
+ sprintf(FileName,"%s/%lu/%c%lu.%lu.%lu.%lu.%lu", MountPoint, \
+ (Sections)[0], UFS_ALGORITHMBASE + Algorithm, \
+ (Sections)[1], (Sections)[2], RWVolume, Vnode, Uniquifier); \
+}
+#define TAGSTOSTAGINGNAME(FileName, MountPoint, RWVolume, Vnode, Uniquifier) \
+ sprintf(FileName,"%s/%s/%lu.%lu.%lu", MountPoint, \
+ UFS_STAGINGTREENAME, RWVolume, Vnode, Uniquifier)
+#define TAGSTOVOLUMEHEADERNAME(FileName, MountPoint, FileTag1, FileTag2) \
+ sprintf(FileName,"%s/%s/%lu", MountPoint, UFS_VOLUMEHEADERTREENAME, \
+ FileTag1)
+#define TAGSTOVOLUMEINFONAME(FileName, MountPoint, FileTag1, FileTag2) \
+ sprintf(FileName,"%s/%s/%lu/%lu", MountPoint, \
+ UFS_VOLUMETREENAME, FileTag2, FileTag1)
+#define TAGSTOVOLUMENAME(FileName, MountPoint, FileTag1, FileTag2, RWVolume) \
+ sprintf(FileName,"%s/%s/%lu/%lu.%lu", MountPoint, \
+ UFS_VOLUMETREENAME, FileTag2, FileTag1, RWVolume)
+#define TAGSTOSUMMARYNAME(FileName, MountPoint, FileTag1, FileTag2, SummaryRequestor, Residency) \
+ sprintf(FileName,"%s/%s/%lu.%lu.%lu.%lu", MountPoint, \
+ UFS_SUMMARYTREENAME, FileTag1, FileTag2, SummaryRequestor, \
+ Residency)
+#define DEVICETAGNUMBERTOMOUNTPOINT(MountPoint, DeviceTagNumber, FSType) \
+ sprintf(MountPoint,"%s%c", Ufs_Prefixes[FSType], UFS_MOUNTPOINTBASE + \
+ DeviceTagNumber)
+#define MOUNTPOINTTODEVICETAGNUMBER(MountPoint) \
+ MountPoint[strlen(MountPoint) - 1] - UFS_MOUNTPOINTBASE
+#define DEVICETAGNUMBERTOVOLUMEHEADERTREE(TreeName, MountPoint) \
+ sprintf(TreeName,"%s/%s", MountPoint, UFS_VOLUMEHEADERTREENAME)
+#define UFS_RESIDENCIES_FILE "Residencies"
+
+/* We don't ever want to map to uid/gid -1. fchown() takes that as a
+ don't change flag. We know however that volume number range from
+ 0x2000000 to 0x20FFFFFF (see VAllocateVolumeId() in vol/vutil.c)
+ so we will use that to insure that -1 never appears. */
+#define RWVolumeToUid(RWVolume) ((RWVolume >> 12) & 0xFFFF)
+#define RWVolumeToGid(RWVolume) ((RWVolume & 0xFFF) | \
+ (((RWVolume >> 28) & 0xF) << 12))
+#define UidGidToRWVolume(Uid, Gid) ((Gid & 0xFFF) | ((Uid & 0xFFFF) << 12) | \
+ ((Gid & 0xF000) << 16))
+
+
+/* These routines generate a file name to correspond to the given tag
+ numbers. */
+
+/* The following entropy array contains the order of bits from highest entropy
+ to lowest in the numbers FileTag1 and FileTag2. Bit numbers 32 and above
+ correspond to FileTag2. This ordering was determined by examining all read-
+ write volumes in the psc.edu cell. */
+char UfsEntropy[1][64] = {
+ {1, 2, 3, 4, 33, 5, 6, 7, 44, 45, 46, 36, 8, 34, 42, 35,
+ 9, 40, 38, 32, 43, 10, 39, 37, 11, 41, 12, 13, 14, 0,
+ 15, 16, 61, 17, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51,
+ 50, 49, 48, 47, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22,
+ 21, 20, 19, 18, 62, 63},
+};
+
+uint32_t Directories[3][2] = { {256, 0}, {256, 16}, {256, 256}, };
+#endif /* RESIDENCY */
+
+static int verbose = 0;
+static int numNoDirData = 0;
+static int termsize = 0;
+int Testing = 0;
+#ifdef RESIDENCY
+extern resid ServerRequestorId;
+#endif /* RESIDENCY */
+
+/*
+ * We use this structure to hold vnode data in our hash table.
+ * It's indexed by vnode number.
+ */
+
+struct vnodeData {
+ struct VnodeDiskObject *vnode; /* A pointer to the disk vnode */
+ int vnodeNumber; /* The vnode number */
+ long dumpdata; /* File offset of dump data (if
+ available */
+ unsigned char *filedata; /* A pointer to the actual file
+ data itself (if available) */
+ unsigned int datalength; /* The length of the data */
+};
+
+/*
+ * This contains the current location when we're doing a scan of a
+ * directory.
+ */
+
+struct DirCursor {
+ int hashbucket; /* Current hash bucket */
+ int entry; /* Entry within hash bucket */
+};
+
+/*
+ * Arrays to hold vnode data
+ */
+
+struct vnodeData **LargeVnodeIndex;
+struct vnodeData **SmallVnodeIndex;
+int numLargeVnodes = 0;
+int numSmallVnodes = 0;
+
+/*
+ * Crap for the libraries
+ */
+
+int ShutdownInProgress = 0;
+
+/*
+ * Our local function prototypes
+ */
+
+static int ReadDumpHeader(FILE *, struct DumpHeader *);
+static int ReadVolumeHeader(FILE *, VolumeDiskData *);
+static int ScanVnodes(FILE *, VolumeDiskData *, int);
+static int DumpVnodeFile(FILE *, struct VnodeDiskObject *, VolumeDiskData *);
+static struct vnodeData *InsertVnode(unsigned int, struct VnodeDiskObject *);
+static struct vnodeData *GetVnode(unsigned int);
+static int CompareVnode(const void *, const void *);
+static void InteractiveRestore(FILE *, VolumeDiskData *);
+static void DirectoryList(int, char **, struct vnodeData *, VolumeDiskData *);
+static void DirListInternal(struct vnodeData *, char *[], int, int, int, int,
+ int, int, VolumeDiskData *, char *);
+static int CompareDirEntry(const void *, const void *);
+static struct vnodeData *ChangeDirectory(int, char **, struct vnodeData *);
+static void CopyFile(int, char **, struct vnodeData *, FILE *);
+static void CopyVnode(int, char **, FILE *);
+static void DumpAllFiles(int, char **, struct vnodeData *, VolumeDiskData *);
+static void DumpAllResidencies(FILE *, struct vnodeData *, VolumeDiskData *);
+static struct vnodeData *FindFile(struct vnodeData *, char *);
+static void ResetDirCursor(struct DirCursor *, struct vnodeData *);
+static struct DirEntry *ReadNextDir(struct DirCursor *, struct vnodeData *);
+static void MakeArgv(char *, int *, char ***);
+static char *GetToken(char *, char **, char *, char *[]);
+static int ReadInt16(FILE *, uint16_t *);
+static int ReadInt32(FILE *, uint32_t *);
+static int ReadString(FILE *, char *, int);
+static int ReadByteString(FILE *, void *, int);
+
+int
+main(int argc, char *argv[])
+{
+ int c, errflg = 0, dumpvnodes = 0, force = 0, inode = 0;
+ unsigned int magic;
+ struct DumpHeader dheader;
+ VolumeDiskData vol;
+ long offset;
+ int Res, Arg1, Arg2, Arg3, i;
+ char *p;
+ struct winsize win;
+ FILE *f;
+
+#ifdef RESIDENCY
+ for (i = 0; i < RS_MAXRESIDENCIES; i++) {
+ rscmdlineinfo[i].Algorithm = -1;
+ rscmdlineinfo[i].Size = -1;
+ rscmdlineinfo[i].DeviceTag = -1;
+ rscmdlineinfo[i].FSType = - 1;
+ }
+#endif /* RESIDENCY */
+
+ /*
+ * Sigh, this is dumb, but we need the terminal window size
+ * to do intelligent things with "ls" later on.
+ */
+
+ if (isatty(STDOUT_FILENO)) {
+ if ((p = getenv("COLUMNS")) != NULL)
+ termsize = atoi(p);
+ else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0 &&
+ win.ws_col > 0)
+ termsize = win.ws_col;
+ }
+
+ while ((c = getopt(argc, argv, "difr:t:v")) != EOF)
+ switch (c) {
+ case 't':
+#ifdef RESIDENCY
+ if (sscanf(optarg, "%d/%d", &Res, &Arg1) != 2) {
+ errflg++;
+ break;
+ }
+
+ if (1 << (ffs(Res) - 1) != Res) {
+ fprintf(stderr, "Invalid residency %d\n", Res);
+ errflg++;
+ break;
+ }
+
+ if (Arg1 < 0 || Arg1 > 26) {
+ fprintf(stderr, "Invalid device tag: %d\n",
+ Arg1);
+ errflg++;
+ break;
+ }
+ rscmdlineinfo[ffs(Res) - 1].DeviceTag = Arg1;
+#else /* RESIDENCY */
+ fprintf(stderr, "-t not supported in non-MRAFS "
+ "dumptool.\n");
+ errflg++;
+#endif /* RESIDENCY */
+ break;
+
+ case 'r':
+#ifdef RESIDENCY
+ if (sscanf(optarg, "%d/%d/%d/%d", &Res, &Arg1, &Arg2,
+ &Arg3) != 4) {
+ errflg++;
+ break;
+ }
+
+ if (Arg1 < 0 || Arg1 > 3) {
+ fprintf(stderr, "Invalid fstype: %d\n", Arg1);
+ errflg++;
+ break;
+ }
+
+ if (Arg2 < 0 || Arg2 > 2) {
+ fprintf(stderr, "Invalid size: %d\n", Arg2);
+ errflg++;
+ break;
+ }
+
+ if (Arg3 <= 0 || Arg3 > UFS_ALGORITHMS) {
+ fprintf(stderr, "Invalid algorithm: %d\n",
+ Arg3);
+ errflg++;
+ break;
+ }
+ rscmdlineinfo[ffs(Res) - 1].FSType = Arg1;
+ rscmdlineinfo[ffs(Res) - 1].Size = Arg2;
+ rscmdlineinfo[ffs(Res) - 1].Algorithm = Arg3;
+#else /* RESIDENCY */
+ fprintf(stderr, "-r not supported in non-MRAFS "
+ "dumptool.\n");
+ errflg++;
+#endif /* RESIDENCY */
+ break;
+ case 'd':
+#ifdef RESIDENCY
+ dumpvnodes++;
+#else /* RESIDENCY */
+ fprintf(stderr, "-d not supported in non-MRAFS "
+ "dumptool.\n");
+ errflg++;
+#endif /* RESIDENCY */
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'f':
+ force++;
+ break;
+ case 'i':
+ inode++;
+ break;
+ case '?':
+ default:
+ errflg++;
+ }
+
+ if (errflg || optind == argc) {
+ fprintf(stderr, "Usage: %s\n\t[-v] [-f]\n\t"
+#ifdef RESIDENCY
+ "[-t Residency/Tag]\n\t"
+ "[-r Residency/Type/Size/Algorithm]\n\t"
+ "[-d] filename [file_in_dump [file in dump ...]]\n",
+#else /* RESIDENCY */
+ "filename\n",
+#endif /* RESIDENCY */
+ argv[0]);
+ exit(1);
+ }
+
+ /*
+ * Try opening the dump file
+ */
+
+ if ((f = fopen(argv[optind], "rb")) == NULL) {
+ fprintf(stderr, "open of dumpfile %s failed: %s\n", argv[optind],
+ strerror(errno));
+ exit(1);
+ }
+
+ if (ReadDumpHeader(f, &dheader)) {
+ fprintf(stderr, "Failed to read dump header!\n");
+ exit(1);
+ }
+
+ if (verbose)
+ printf("Dump is for volume %lu (%s)\n", dheader.volumeId,
+ dheader.volumeName);
+
+ if (getc(f) != D_VOLUMEHEADER) {
+ fprintf(stderr, "Volume header is missing from dump, aborting\n");
+ exit(1);
+ }
+
+ if (ReadVolumeHeader(f, &vol)) {
+ fprintf(stderr, "Unable to read volume header\n");
+ exit(1);
+ }
+
+ if (verbose) {
+ printf("Volume information:\n");
+ printf("\tid = %lu\n", vol.id);
+ printf("\tparent id = %lu\n", vol.parentId);
+ printf("\tname = %s\n", vol.name);
+ printf("\tflags =");
+ if (vol.inUse)
+ printf(" inUse");
+ if (vol.inService)
+ printf(" inService");
+ if (vol.blessed)
+ printf(" blessed");
+ if (vol.needsSalvaged)
+ printf(" needsSalvaged");
+ printf("\n");
+ printf("\tuniquifier = %lu\n", vol.uniquifier);
+ printf("\tCreation date = %s", ctime((time_t *) &vol.creationDate));
+ printf("\tLast access date = %s", ctime((time_t *) &vol.accessDate));
+ printf("\tLast update date = %s", ctime((time_t *) &vol.updateDate));
+ printf("\tVolume owner = %lu\n", vol.owner);
+ }
+
+ if (verbose)
+ printf("Scanning vnodes (this may take a while)\n");
+
+ /*
+ * We need to do two vnode scans; one to get the number of
+ * vnodes, the other to actually build the index.
+ */
+
+ offset = ftell(f);
+
+ if (ScanVnodes(f, &vol, 1)) {
+ fprintf(stderr, "First vnode scan failed, aborting\n");
+ exit(1);
+ }
+
+ fseek(f, offset, SEEK_SET);
+
+ if (ScanVnodes(f, &vol, 0)) {
+ fprintf(stderr, "Second vnode scan failed, aborting\n");
+ exit(1);
+ }
+
+ if (getc(f) != D_DUMPEND || ReadInt32(f, &magic) ||
+ magic != DUMPENDMAGIC) {
+ fprintf(stderr, "Couldn't find dump postamble, ");
+ if (! force) {
+ fprintf(stderr, "aborting (use -f to override)\n");
+ exit(1);
+ } else {
+ fprintf(stderr, "continuing anyway\n");
+ fprintf(stderr, "WARNING: Dump may not be complete!\n");
+ }
+ }
+
+ /*
+ * If we wanted to simply dump all vnodes, do it now
+ */
+
+#ifdef RESIDENCY
+ if (dumpvnodes) {
+ struct vnodeData *vdata;
+
+ for (i = 0; i < numLargeVnodes; i++) {
+
+ vdata = LargeVnodeIndex[i];
+
+ if (vdata->vnode->type == vFidLookup)
+ if (DumpVnodeFile(stdout, vdata->vnode, &vol)) {
+ fprintf(stderr, "DumpVnodeFile failed, "
+ "aborting\n");
+ exit(1);
+ }
+ }
+
+ for (i = 0; i < numSmallVnodes; i++) {
+
+ vdata = SmallVnodeIndex[i];
+
+ if (vdata->vnode->type == vFidLookup)
+ if (DumpVnodeFile(stdout, vdata->vnode, &vol)) {
+ fprintf(stderr, "DumpVnodeFile failed, "
+ "aborting\n");
+ exit(1);
+ }
+ }
+
+ } else
+#endif /* RESIDENCY */
+ if (inode) {
+ /*
+ * Dump out all filenames with their corresponding FID
+ */
+
+ struct vnodeData *rootvdata;
+
+ if ((rootvdata = GetVnode(1)) == NULL) {
+ fprintf(stderr, "Can't get vnode data for root "
+ "vnode! Aborting\n");
+ exit(1);
+ }
+
+ DirListInternal(rootvdata, NULL, 0, 0, 1, 0, 1, 0, &vol, "");
+
+ } else if (argc > optind + 1) {
+#ifdef RESIDENCY
+ /*
+ * Dump out residencies of files given on the command line.
+ */
+
+ struct vnodeData *vdata, *rootvdata;
+
+ if ((rootvdata = GetVnode(1)) == NULL) {
+ fprintf(stderr, "Can't get vnode data for root "
+ "vnode! Aborting\n");
+ exit(1);
+ }
+
+ for (i = optind + 1; i < argc; i++) {
+
+ if ((vdata = FindFile(rootvdata, argv[i])) == NULL) {
+ fprintf(stderr, "Skipping file %s\n",
+ argv[i]);
+ continue;
+ }
+
+ if (verbose)
+ printf("Residency locations for %s:\n",
+ argv[i]);
+
+ while (vdata->vnode->NextVnodeId != 0) {
+
+ vdata = GetVnode(vdata->vnode->NextVnodeId);
+
+ if (vdata == NULL) {
+ fprintf(stderr, "We had a vnode chain "
+ "pointer to a vnode that "
+ "doesn't exist, aborting!\n");
+ exit(1);
+ }
+ if (vdata->vnode->type == vFidLookup)
+ DumpVnodeFile(stdout, vdata->vnode,
+ &vol);
+ }
+ }
+#else /* RESIDENCY */
+ fprintf(stderr, "Extra arguments after dump filename: %s\n",
+ argv[optind]);
+ exit(1);
+#endif /* RESIDENCY */
+ } else {
+ /*
+ * Perform an interactive restore
+ */
+
+ InteractiveRestore(f, &vol);
+ }
+
+ exit(0);
+}
+
+/*
+ * Read the dump header, which is at the beginning of every dump
+ */
+
+static int
+ReadDumpHeader(FILE *f, struct DumpHeader *header)
+{
+ unsigned int magic;
+ int tag, i;
+
+ if (getc(f) != D_DUMPHEADER ||
+ ReadInt32(f, &magic) || ReadInt32(f, (unsigned int *)
+ &header->version) ||
+ magic != DUMPBEGINMAGIC) {
+ if (verbose)
+ fprintf(stderr, "Couldn't find dump magic numbers\n");
+ return -1;
+ }
+
+ header->volumeId = 0;
+ header->nDumpTimes = 0;
+
+ while ((tag = getc(f)) > D_MAX && tag != EOF) {
+ unsigned short length;
+ switch (tag) {
+ case 'v':
+ if (ReadInt32(f, &header->volumeId)) {
+ if (verbose)
+ fprintf(stderr, "Failed to read "
+ "volumeId\n");
+ return -1;
+ }
+ break;
+ case 'n':
+ if (ReadString(f, header->volumeName,
+ sizeof(header->volumeName))) {
+ if (verbose)
+ fprintf(stderr, "Failed to read "
+ "volume name\n");
+ return -1;
+ }
+ break;
+ case 't':
+ if (ReadInt16(f, &length)) {
+ if (verbose)
+ fprintf(stderr, "Failed to read "
+ "dump time array length\n");
+ return -1;
+ }
+ header->nDumpTimes = (length >> 1);
+ for (i = 0; i < header->nDumpTimes; i++)
+ if (ReadInt32(f, (unsigned int *)
+ &header->dumpTimes[i].from) ||
+ ReadInt32(f, (unsigned int *)
+ &header->dumpTimes[i].to)) {
+ if (verbose)
+ fprintf(stderr, "Failed to "
+ "read dump times\n");
+ return -1;
+ }
+ break;
+ default:
+ if (verbose)
+ fprintf(stderr, "Unknown dump tag \"%c\"\n",
+ tag);
+ return -1;
+ }
+ }
+
+ if (!header->volumeId || !header->nDumpTimes) {
+ if (verbose)
+ fprintf(stderr, "We didn't get a volume Id or "
+ "dump times listing\n");
+ return 1;
+ }
+
+ ungetc(tag, f);
+ return 0;
+}
+
+/*
+ * Read the volume header; this is the information stored in VolumeDiskData.
+ *
+ * I'm not sure we need all of this, but read it in just in case.
+ */
+
+static int
+ReadVolumeHeader(FILE *f, VolumeDiskData *vol)
+{
+ int tag;
+ unsigned int trash;
+ memset((void *) vol, 0, sizeof(*vol));
+
+ while ((tag = getc(f)) > D_MAX && tag != EOF) {
+ switch (tag) {
+ case 'i':
+ if (ReadInt32(f, &vol->id))
+ return -1;
+ break;
+ case 'v':
+ if (ReadInt32(f, &trash))
+ return -1;
+ break;
+ case 'n':
+ if (ReadString(f, vol->name, sizeof(vol->name)))
+ return -1;
+ break;
+ case 's':
+ vol->inService = getc(f);
+ break;
+ case 'b':
+ vol->blessed = getc(f);
+ break;
+ case 'u':
+ if (ReadInt32(f, &vol->uniquifier))
+ return -1;
+ break;
+ case 't':
+ vol->type = getc(f);
+ break;
+ case 'p':
+ if (ReadInt32(f, &vol->parentId))
+ return -1;
+ break;
+ case 'c':
+ if (ReadInt32(f, &vol->cloneId))
+ return -1;
+ break;
+ case 'q':
+ if (ReadInt32(f, (uint32_t *) &vol->maxquota))
+ return -1;
+ break;
+ case 'm':
+ if (ReadInt32(f, (uint32_t *) &vol->minquota))
+ return -1;
+ break;
+ case 'd':
+ if (ReadInt32(f, (uint32_t *) &vol->diskused))
+ return -1;
+ break;
+ case 'f':
+ if (ReadInt32(f, (uint32_t *) &vol->filecount))
+ return -1;
+ break;
+ case 'a':
+ if (ReadInt32(f, &vol->accountNumber))
+ return -1;
+ break;
+ case 'o':
+ if (ReadInt32(f, &vol->owner))
+ return -1;
+ break;
+ case 'C':
+ if (ReadInt32(f, &vol->creationDate))
+ return -1;
+ break;
+ case 'A':
+ if (ReadInt32(f, &vol->accessDate))
+ return -1;
+ break;
+ case 'U':
+ if (ReadInt32(f, &vol->updateDate))
+ return -1;
+ break;
+ case 'E':
+ if (ReadInt32(f, &vol->expirationDate))
+ return -1;
+ break;
+ case 'B':
+ if (ReadInt32(f, &vol->backupDate))
+ return -1;
+ break;
+ case 'O':
+ if (ReadString(f, vol->offlineMessage,
+ sizeof(vol->offlineMessage)))
+ return -1;
+ break;
+ case 'M':
+ if (ReadString(f, (char *) vol->stat_reads, VMSGSIZE))
+ return -1;
+ break;
+ case 'W': {
+ unsigned short length;
+ int i;
+ unsigned int data;
+ if (ReadInt16(f, &length))
+ return -1;
+ for (i = 0; i < length; i++) {
+ if (ReadInt32(f, &data))
+ return -1;
+ if (i < sizeof(vol->weekUse) /
+ sizeof(vol->weekUse[0]))
+ vol->weekUse[i] = data;
+ }
+ break;
+ }
+ case 'D':
+ if (ReadInt32(f, &vol->dayUseDate))
+ return -1;
+ break;
+ case 'Z':
+ if (ReadInt32(f, (uint32_t *) &vol->dayUse))
+ return -1;
+ break;
+#ifdef RESIDENCY
+ case 'R': {
+ unsigned short length;
+ int i;
+ unsigned int data;
+
+ if (ReadInt16(f, &length))
+ return -1;
+ for (i = 0; i < length; i++) {
+ if (ReadInt32(f, &data))
+ return -1;
+ if (i < sizeof(vol->DesiredInfo.DesiredResidencyWords) /
+ sizeof(vol->DesiredInfo.DesiredResidencyWords[0]))
+ vol->DesiredInfo.DesiredResidencyWords[i] = data;
+ }
+ break;
+ }
+ case 'S': {
+ unsigned short length;
+ int i;
+ unsigned int data;
+
+ if (ReadInt16(f, &length))
+ return -1;
+ for (i = 0; i < length; i++) {
+ if (ReadInt32(f, &data))
+ return -1;
+ if (i < sizeof(vol->UnDesiredInfo.UnDesiredResidencyWords) /
+ sizeof(vol->UnDesiredInfo.UnDesiredResidencyWords[0]))
+ vol->UnDesiredInfo.UnDesiredResidencyWords[i] = data;
+ }
+ break;
+ }
+#endif
+ default:
+ if (verbose)
+ fprintf(stderr, "Unknown dump tag \"%c\"\n",
+ tag);
+ return -1;
+ }
+ }
+
+ ungetc(tag, f);
+ return 0;
+}
+
+/*
+ * Scan all our vnode entries, and build indexing information.
+ */
+
+static int
+ScanVnodes(FILE *f, VolumeDiskData *vol, int sizescan)
+{
+ int vnodeNumber;
+ int tag;
+ int numFileVnodes = 0;
+ int numDirVnodes = 0;
+ unsigned char buf[SIZEOF_LARGEDISKVNODE];
+ struct VnodeDiskObject *vnode = (struct VnodeDiskObject *) buf;
+ long offset, oldoffset;
+ struct vnodeData *vdata;
+ unsigned int length;
+
+ tag = getc(f);
+
+ while (tag == D_VNODE) {
+
+ offset = 0;
+ length = 0;
+ vnode->type = -1;
+ vnode->length = -1;
+
+ if (ReadInt32(f, (uint32_t *) &vnodeNumber))
+ {
+ fprintf(stderr, "failed int32 for 'vnodenum'\n");
+ return -1;
+ }
+
+ if (ReadInt32(f, &vnode->uniquifier))
+ {
+ fprintf(stderr, "failed int32 for 'uniquifier'\n");
+ return -1;
+ }
+
+ if (verbose > 1 && !sizescan)
+ printf("Got vnode %d\n", vnodeNumber);
+
+ while ((tag = getc(f)) > D_MAX && tag != EOF)
+ switch (tag) {
+ case 't':
+ vnode->type = (VnodeType) getc(f);
+ break;
+ case 'l':
+ {
+ unsigned short tmp;
+ if (ReadInt16(f, &tmp))
+ {
+ fprintf(stderr, "failed int16 for 'l'\n");
+ return -1;
+ }
+ vnode->linkCount = tmp;
+ }
+ break;
+ case 'v':
+ if (ReadInt32(f, &vnode->dataVersion))
+ {
+ fprintf(stderr, "failed int32 for 'v'\n");
+ return -1;
+ }
+ break;
+ case 'm':
+ if (ReadInt32(f, (uint32_t *) &vnode->unixModifyTime))
+ {
+ fprintf(stderr, "failed int32 for 'm'\n");
+ return -1;
+ }
+ break;
+ case 's':
+ if (ReadInt32(f, (uint32_t *) &vnode->serverModifyTime))
+ {
+ fprintf(stderr, "failed int32 for 's'\n");
+ return -1;
+ }
+ break;
+ case 'a':
+ if (ReadInt32(f, &vnode->author))
+ {
+ fprintf(stderr, "failed int32 for 'a'\n");
+ return -1;
+ }
+ break;
+ case 'o':
+ if (ReadInt32(f, &vnode->owner))
+ {
+ fprintf(stderr, "failed int32 for 'o'\n");
+ return -1;
+ }
+ break;
+ case 'g':
+ if (ReadInt32(f, (uint32_t *) &vnode->group))
+ {
+ fprintf(stderr, "failed int32 for 'g'\n");
+ return -1;
+ }
+ break;
+ case 'b': {
+ unsigned short modeBits;
+ if (ReadInt16(f, &modeBits))
+ return -1;
+ vnode->modeBits = modeBits;
+ break;
+ }
+ case 'p':
+ if (ReadInt32(f, &vnode->parent))
+ {
+ fprintf(stderr, "failed int32 for 'p'\n");
+ return -1;
+ }
+ break;
+#ifdef RESIDENCY
+ case 'N':
+ if (ReadInt32(f, &vnode->NextVnodeId))
+ {
+ fprintf(stderr, "failed int32 for 'N'\n");
+ return -1;
+ }
+ break;
+ case 'R':
+ if (ReadInt32(f, &VLkp_Residencies(vnode)))
+ {
+ fprintf(stderr, "failed int32 for 'R'\n");
+ return -1;
+ }
+ break;
+#endif
+ case 'S':
+ if (ReadInt32(f, &vnode->length))
+ {
+ fprintf(stderr, "failed int32 for 'S'\n");
+ return -1;
+ }
+ break;
+ case 'F':
+ if (ReadInt32(f, (uint32_t *) &vnode->vn_ino_lo))
+ return -1;
+ break;
+ case 'A':
+ if (ReadByteString(f,
+ (void *)VVnodeDiskACL(vnode),
+ VAclDiskSize(vnode)))
+ {
+ fprintf(stderr, "failed readbystring for 'A'\n");
+ return -1;
+ }
+#if 0
+ acl_NtohACL(VVnodeDiskACL(vnode));
+#endif
+ break;
+#ifdef RESIDENCY
+ case 'h':
+ if (ReadInt32(f, &vnode->length_hi))
+ {
+ fprintf(stderr, "failed int32 for 'h'\n");
+ return -1;
+ }
+#endif
+ case 'f':
+ if (verbose > 1 && ! sizescan)
+ printf("We have file data!\n");
+ if (ReadInt32(f, &length))
+ {
+ fprintf(stderr, "failed int32 for 'f'\n");
+ return -1;
+ }
+ vnode->length = length;
+ offset = ftell(f);
+ fseek(f, length, SEEK_CUR);
+ break;
+ default:
+ if (verbose)
+ fprintf(stderr, "Unknown dump tag \"%c\"\n",
+ tag);
+ return -1;
+ }
+
+ /*
+ * If we're doing an incremental restore, then vnodes
+ * will be listed in the dump, but won't contain any
+ * vnode information at all (I don't know why they're
+ * included _at all_). If we get one of these vnodes, then
+ * just skip it (because we can't do anything with it.
+ */
+
+ if (vnode->type == -1)
+ continue;
+
+#ifdef RESIDENCY
+ if (verbose > 1 && vnode->type == vFidLookup && ! sizescan) {
+ printf("This is an auxiliary vnode (lookup) for vnode %d, residency %d\n",
+ VLkp_ParentVnodeId(vnode),
+ VLkp_Residencies(vnode));
+ if (DumpVnodeFile(stdout, vnode, vol))
+ return -1;
+ }
+
+ if (verbose > 1 && vnode->type == vAccessHistory && ! sizescan)
+ printf("This is an auxiliary vnode (history) for vnode %d\n",
+ VLkp_ParentVnodeId(vnode));
+#endif
+
+ if (vnode->type == vDirectory)
+ numDirVnodes++;
+ else
+ numFileVnodes++;
+
+ /*
+ * We know now all we would ever know about the vnode;
+ * insert it into our hash table (but only if we're not
+ * doing a vnode scan).
+ */
+
+ if (!sizescan) {
+
+ vdata = InsertVnode(vnodeNumber, vnode);
+
+ if (vdata == NULL) {
+ if (verbose)
+ fprintf(stderr, "Failed to insert "
+ "vnode into hash table");
+ return -1;
+ }
+
+ vdata->dumpdata = offset;
+ vdata->datalength = length;
+
+ /*
+ * Save directory data, since we'll need it later.
+ */
+
+ if (vnode->type == vDirectory && length) {
+
+ vdata->filedata = malloc(length);
+
+ if (!vdata->filedata) {
+ if (verbose)
+ fprintf(stderr, "Unable to "
+ "allocate space for "
+ "file data (%d)\n",
+ length);
+ return -1;
+ }
+
+ oldoffset = ftell(f);
+ fseek(f, offset, SEEK_SET);
+
+ if (fread(vdata->filedata, length, 1, f) != 1) {
+ if (verbose)
+ fprintf(stderr, "Unable to "
+ "read in file data!\n");
+ return -1;
+ }
+
+ fseek(f, oldoffset, SEEK_SET);
+ } else if (vnode->type == vDirectory)
+ /*
+ * Warn the user we may not have all directory
+ * vnodes
+ */
+ numNoDirData++;
+ }
+ }
+
+ ungetc(tag, f);
+
+ if (!sizescan) {
+
+ numLargeVnodes = numDirVnodes;
+ numSmallVnodes = numFileVnodes;
+
+ } else {
+ LargeVnodeIndex = (struct vnodeData **)
+ malloc(numDirVnodes *
+ sizeof(struct vnodeData));
+ SmallVnodeIndex = (struct vnodeData **)
+ malloc(numFileVnodes *
+ sizeof(struct vnodeData));
+
+ if (LargeVnodeIndex == NULL || SmallVnodeIndex == NULL) {
+ if (verbose)
+ fprintf(stderr, "Unable to allocate space "
+ "for vnode tables\n");
+ return -1;
+ }
+ }
+
+ if (verbose)
+ fprintf(stderr,"%s vnode scan completed\n",
+ sizescan ? "Primary" : "Secondary");
+
+ return 0;
+}
+
+/*
+ * Perform an interactive restore
+ *
+ * Parsing the directory information is a pain, but other than that
+ * we just use the other tools we already have in here.
+ */
+
+static void
+InteractiveRestore(FILE *f, VolumeDiskData *vol)
+{
+ struct vnodeData *vdatacwd; /* Vnode data for our current dir */
+ char cmdbuf[256];
+ int argc;
+ char **argv;
+
+ /*
+ * Let's see if we can at least get the data for our root directory.
+ * If we can't, there's no way we can do an interactive restore.
+ */
+
+ if ((vdatacwd = GetVnode(1)) == NULL) {
+ fprintf(stderr, "No entry for our root vnode! Aborting\n");
+ return;
+ }
+
+ if (! vdatacwd->filedata) {
+ fprintf(stderr, "There is no directory data for the root "
+ "vnode (1.1). An interactive\nrestore is not "
+ "possible.\n");
+ return;
+ }
+
+ /*
+ * If you're doing a selective dump correctly, then you should get all
+ * directory vnode data. But just in case you didn't, let the user
+ * know there may be a problem.
+ */
+
+ if (numNoDirData)
+ fprintf(stderr, "WARNING: %d directory vnodes had no file "
+ "data. An interactive restore\nmay not be possible\n",
+ numNoDirData);
+
+ printf("> ");
+ while (fgets(cmdbuf, 256, stdin)) {
+
+ cmdbuf[strlen(cmdbuf) - 1] = '\0';
+
+ if (strlen(cmdbuf) == 0) {
+ printf("> ");
+ continue;
+ }
+
+ MakeArgv(cmdbuf, &argc, &argv);
+
+ if (strcmp(argv[0], "ls") == 0) {
+ DirectoryList(argc, argv, vdatacwd, vol);
+ } else if (strcmp(argv[0], "cd") == 0) {
+ struct vnodeData *newvdata;
+
+ newvdata = ChangeDirectory(argc, argv, vdatacwd);
+
+ if (newvdata)
+ vdatacwd = newvdata;
+ } else if (strcmp(argv[0], "file") == 0) {
+ DumpAllFiles(argc, argv, vdatacwd, vol);
+ } else if (strcmp(argv[0], "cp") == 0) {
+ CopyFile(argc, argv, vdatacwd, f);
+ } else if (strcmp(argv[0], "vcp") == 0) {
+ CopyVnode(argc, argv, f);
+ } else if (strcmp(argv[0], "quit") == 0 ||
+ strcmp(argv[0], "exit") == 0)
+ break;
+ else if (strcmp(argv[0], "?") == 0 ||
+ strcmp(argv[0], "help") == 0) {
+ printf("Valid commands are:\n");
+ printf("\tls\t\tList current directory\n");
+ printf("\tcd\t\tChange current directory\n");
+ printf("\tcp\t\tCopy file from dump\n");
+ printf("\tvcp\t\tCopy file from dump (via vnode)\n");
+#ifdef RESIDENCY
+ printf("\tfile\t\tList residency filenames\n");
+#endif /* RESIDENCY */
+ printf("\tquit | exit\tExit program\n");
+ printf("\thelp | ?\tBrief help\n");
+ } else
+ fprintf(stderr, "Unknown command, \"%s\", enter "
+ "\"help\" for a list of commands.\n",
+ argv[0]);
+
+ printf("> ");
+ }
+
+ return;
+}
+
+/*
+ * Do a listing of all files in a directory. Sigh, I wish this wasn't
+ * so complicated.
+ *
+ * With the reorganizing, this is just a front-end to DirListInternal()
+ */
+
+static void
+DirectoryList(int argc, char **argv, struct vnodeData *vdata,
+ VolumeDiskData *vol)
+{
+ int errflg = 0, lflag = 0, iflag = 0, Fflag = 0, sflag = 0, Rflag = 0;
+ int c;
+
+ optind = 1;
+
+ while ((c = getopt(argc, argv, "liFRs")) != EOF)
+ switch (c) {
+ case 'l':
+ lflag++;
+ break;
+ case 'i':
+ iflag++;
+ break;
+ case 'F':
+ Fflag++;
+ break;
+ case 'R':
+ Rflag++;
+ case 's':
+ sflag++;
+ break;
+ case '?':
+ default:
+ errflg++;
+ }
+
+ if (errflg) {
+ fprintf(stderr, "Usage: %s [-liFs] filename [filename ...]\n",
+ argv[0]);
+ return;
+ }
+
+ DirListInternal(vdata, &(argv[optind]), argc - optind, lflag, iflag,
+ Fflag, Rflag, 1, vol, NULL);
+
+ return;
+}
+
+/*
+ * Function that does the REAL work in terms of directory listing
+ */
+
+static void
+DirListInternal(struct vnodeData *vdata, char *pathnames[], int numpathnames,
+ int lflag, int iflag, int Fflag, int Rflag, int verbose,
+ VolumeDiskData *vol, char *path)
+{
+ struct DirEntry *ep, **eplist = NULL, **eprecurse = NULL;
+ struct DirCursor cursor;
+ struct vnodeData *lvdata;
+
+ int i, j, numentries = 0, longestname = 0, numcols, col, numrows;
+ int numrecurse = 0;
+
+ if (! vdata->filedata) {
+ fprintf(stderr, "There is no vnode data for this "
+ "directory!\n");
+ return;
+ }
+
+ ResetDirCursor(&cursor, vdata);
+
+ /*
+ * Scan through the whole directory
+ */
+
+ while ((ep = ReadNextDir(&cursor, vdata)) != NULL) {
+
+ /*
+ * If we didn't get any filenames on the command line,
+ * get them all.
+ */
+
+ if (numpathnames == 0) {
+ eplist = realloc(eplist, sizeof(struct DirEntry *) *
+ ++numentries);
+ eplist[numentries - 1] = ep;
+ if (strlen(ep->name) > longestname)
+ longestname = strlen(ep->name);
+ if (Rflag)
+ if ((lvdata = GetVnode(ntohl(ep->fid.vnode))) &&
+ lvdata->vnode->type == vDirectory &&
+ !(strcmp(ep->name, ".") == 0 ||
+ strcmp(ep->name, "..") == 0)) {
+ eprecurse = realloc(eprecurse,
+ sizeof(struct DirEntry *) *
+ ++numrecurse);
+ eprecurse[numrecurse - 1] = ep;
+ }
+
+ } else {
+ /*
+ * Do glob matching via fnmatch()
+ */
+
+ for (i = 0; i < numpathnames; i++)
+ if (fnmatch(pathnames[i], ep->name,
+ FNM_PATHNAME) == 0) {
+ eplist = realloc(eplist,
+ sizeof(struct DirEntry *) *
+ ++numentries);
+ eplist[numentries - 1] = ep;
+ if (strlen(ep->name) > longestname)
+ longestname = strlen(ep->name);
+ if (Rflag)
+ if ((lvdata =
+ GetVnode(ntohl(ep->fid.vnode))) &&
+ lvdata->vnode->type ==
+ vDirectory &&
+ !(strcmp(ep->name, ".") == 0 ||
+ strcmp(ep->name, "..") == 0)) {
+ eprecurse =
+ realloc(eprecurse,
+ sizeof(struct DirEntry *) *
+ ++numrecurse);
+ eprecurse[numrecurse - 1] = ep;
+ }
+ break;
+ }
+ }
+ }
+
+ qsort((void *) eplist, numentries, sizeof(struct DirEntry *),
+ CompareDirEntry);
+
+ if (Rflag && eprecurse)
+ qsort((void *) eprecurse, numrecurse,
+ sizeof(struct DirEntry *), CompareDirEntry);
+ /*
+ * We don't have to do column printing if we have the -l or the -i
+ * options. Sigh, column printing is WAY TOO FUCKING COMPLICATED!
+ */
+
+ if (!lflag && !iflag) {
+ char c;
+
+ if (Fflag)
+ longestname++;
+
+ longestname++;
+
+ numcols = termsize / longestname ? termsize / longestname : 1;
+ numrows = numentries / numcols +
+ (numentries % numcols ? 1 : 0);
+
+ for (i = 0; i < numrows; i++) {
+ col = 0;
+ while (col < numcols && (i + col * numrows) <
+ numentries) {
+ ep = eplist[i + col++ * numrows];
+ if (Fflag) {
+ if (!(lvdata =
+ GetVnode(ntohl(ep->fid.vnode))))
+ c = ' ';
+ else if (lvdata->vnode->type ==
+ vDirectory)
+ c = '/';
+ else if (lvdata->vnode->type ==
+ vSymlink)
+ c = '@';
+ else if (lvdata->vnode->modeBits &
+ 0111 != 0)
+ c = '*';
+ else
+ c = ' ';
+ printf("%s%-*c", ep->name,
+ longestname - strlen(ep->name), c);
+ } else
+ printf("%-*s", longestname, ep->name);
+ }
+
+ printf("\n");
+ }
+ } else if (iflag)
+ for (i = 0; i < numentries; i++)
+ if (!(lvdata = GetVnode(ntohl(eplist[i]->fid.vnode))))
+ printf("%d.0.0\t%s\n",
+ vol->parentId ? vol->parentId : vol->id,
+ eplist[i]->name);
+ else
+ if (path)
+ printf("%d.%d.%d\t%s/%s\n",
+ vol->id,
+ ntohl(eplist[i]->fid.vnode),
+ ntohl(eplist[i]->fid.vunique),
+ path, eplist[i]->name);
+ else
+ printf("%d.%d.%d\t%s\n",
+ vol->id,
+ ntohl(eplist[i]->fid.vnode),
+ ntohl(eplist[i]->fid.vunique),
+ eplist[i]->name);
+ else if (lflag) {
+ for (i = 0; i < numentries; i++)
+ if (!(lvdata = GetVnode(ntohl(eplist[i]->fid.vnode))))
+ printf("---------- 0 0 "
+ "0 0 %s\n",
+ eplist[i]->name);
+ else {
+ switch (lvdata->vnode->type) {
+ case vDirectory:
+ printf("d");
+ break;
+ case vSymlink:
+ printf("l");
+ break;
+ default:
+ printf("-");
+ }
+
+ for (j = 8; j >= 0; j--) {
+ if (lvdata->vnode->modeBits & (1 << j))
+ switch (j % 3) {
+ case 2: printf("r");
+ break;
+ case 1: printf("w");
+ break;
+ case 0: printf("x");
+ }
+ else
+ printf("-");
+ }
+
+ printf(" %-3d %-8d %-8d %10d %s\n",
+ lvdata->vnode->linkCount,
+ lvdata->vnode->owner,
+ lvdata->vnode->group,
+ lvdata->vnode->length,
+ eplist[i]->name);
+ }
+ }
+
+ free(eplist);
+
+ if (Rflag && eprecurse) {
+ char *lpath;
+ lpath = NULL;
+ for (i = 0; i < numrecurse; i++) {
+ if (verbose)
+ printf("\n%s:\n", eprecurse[i]->name);
+ if (path) {
+ lpath = malloc(strlen(path) +
+ strlen(eprecurse[i]->name) + 2);
+ if (lpath)
+ sprintf(lpath, "%s/%s", path,
+ eprecurse[i]->name);
+ }
+ DirListInternal(
+ GetVnode(ntohl(eprecurse[i]->fid.vnode)),
+ NULL, 0, lflag, iflag, Fflag, Rflag,
+ verbose, vol, lpath);
+ if (lpath) {
+ free(lpath);
+ lpath = NULL;
+ }
+ }
+ }
+
+ if (eprecurse)
+ free(eprecurse);
+
+ return;
+}
+
+
+/*
+ * Directory name comparison function, used by qsort
+ */
+
+static int
+CompareDirEntry(const void *e1, const void *e2)
+{
+ struct DirEntry **ep1 = (struct DirEntry **) e1;
+ struct DirEntry **ep2 = (struct DirEntry **) e2;
+
+ return strcmp((*ep1)->name, (*ep2)->name);
+}
+
+/*
+ * Change a directory. Return a pointer to our new vdata structure for
+ * this directory.
+ */
+
+static struct vnodeData *
+ChangeDirectory(int argc, char **argv, struct vnodeData *vdatacwd)
+{
+ struct vnodeData *newvdatacwd;
+
+ if (argc != 2) {
+ fprintf(stderr, "Usage: %s directory\n", argv[0]);
+ return NULL;
+ }
+
+ if ((newvdatacwd = FindFile(vdatacwd, argv[1])) == NULL)
+ return NULL;
+
+ if (newvdatacwd->vnode->type != vDirectory) {
+ fprintf(stderr, "%s: Not a directory\n", argv[1]);
+ return NULL;
+ }
+
+ if (newvdatacwd->filedata == NULL) {
+ fprintf(stderr, "%s: No directory data found.\n", argv[1]);
+ return NULL;
+ }
+
+ return newvdatacwd;
+}
+
+/*
+ * Copy a file from out of the dump file
+ */
+
+#define COPYBUFSIZE 8192
+
+static void
+CopyFile(int argc, char **argv, struct vnodeData *vdatacwd, FILE *f)
+{
+ struct vnodeData *vdata;
+ FILE *out;
+ long cur = 0;
+ int bytes, ret;
+ char buffer[COPYBUFSIZE];
+
+ if (argc != 3) {
+ fprintf(stderr, "Usage: %s dumpfile destfile\n", argv[0]);
+ return;
+ }
+
+ if ((vdata = FindFile(vdatacwd, argv[1])) == NULL)
+ return;
+
+ if (vdata->dumpdata == 0) {
+ fprintf(stderr, "File %s has no data in dump file\n",
+ argv[1]);
+ return;
+ }
+
+ if ((out = fopen(argv[2], "wb")) == NULL) {
+ fprintf(stderr, "Open of %s failed: %s\n", argv[2],
+ strerror(errno));
+ return;
+ }
+
+ if (fseek(f, vdata->dumpdata, SEEK_SET)) {
+ fprintf(stderr, "Seek failed: %s\n", strerror(errno));
+ fclose(out);
+ return;
+ }
+
+ while (cur < vdata->datalength) {
+
+ bytes = cur + COPYBUFSIZE < vdata->datalength ?
+ COPYBUFSIZE : vdata->datalength - cur;
+
+ ret = fread(buffer, sizeof(char), bytes, f);
+ if (ret != bytes) {
+ if (ret != 0)
+ fprintf(stderr, "Short read (expected %d, "
+ "got %d)\n", bytes, ret);
+ else
+ fprintf(stderr, "Error during read: %s\n",
+ strerror(errno));
+ fclose(out);
+ return;
+ }
+
+ ret = fwrite(buffer, sizeof(char), bytes, out);
+ if (ret != bytes) {
+ if (ret != 0)
+ fprintf(stderr, "Short write (expected %d, "
+ "got %d)\n", bytes, ret);
+ else
+ fprintf(stderr, "Error during write: %s\n",
+ strerror(errno));
+ fclose(out);
+ return;
+ }
+
+ cur += bytes;
+ }
+
+ fclose(out);
+}
+
+/*
+ * Copy a file from out of the dump file, by using the vnode
+ */
+
+static void
+CopyVnode(int argc, char *argv[], FILE *f)
+{
+ struct vnodeData *vdata;
+ FILE *out;
+ long cur = 0;
+ int bytes, ret;
+ char buffer[COPYBUFSIZE];
+ unsigned int vnode, uniquifier = 0;
+
+ if (argc != 3) {
+ fprintf(stderr, "Usage: %s vnode[.uniqifier] destfile\n",
+ argv[0]);
+ return;
+ }
+
+ ret = sscanf(argv[1], "%d.%d", &vnode, &uniquifier);
+
+ if (ret < 1) {
+ fprintf(stderr, "Invalid file identifier: %s\n", argv[1]);
+ return;
+ }
+
+ if (!(vdata = GetVnode(vnode))) {
+ fprintf(stderr, "Vnode %d not in dump file\n", vnode);
+ return;
+ }
+
+ if (ret == 2 && vdata->vnode->uniquifier != uniquifier) {
+ fprintf(stderr, "Specified uniquifier %d did not match "
+ "uniquifier %d found in dump file!\n", uniquifier,
+ vdata->vnode->uniquifier);
+ return;
+ }
+
+ if (vdata->dumpdata == 0) {
+ fprintf(stderr, "File %s has no data in dump file\n",
+ argv[1]);
+ return;
+ }
+
+ if ((out = fopen(argv[2], "wb")) == NULL) {
+ fprintf(stderr, "Open of %s failed: %s\n", argv[2],
+ strerror(errno));
+ return;
+ }
+
+ if (fseek(f, vdata->dumpdata, SEEK_SET)) {
+ fprintf(stderr, "Seek failed: %s\n", strerror(errno));
+ fclose(out);
+ return;
+ }
+
+ while (cur < vdata->datalength) {
+
+ bytes = cur + COPYBUFSIZE < vdata->datalength ?
+ COPYBUFSIZE : vdata->datalength - cur;
+
+ ret = fread(buffer, sizeof(char), bytes, f);
+ if (ret != bytes) {
+ if (ret != 0)
+ fprintf(stderr, "Short read (expected %d, "
+ "got %d)\n", bytes, ret);
+ else
+ fprintf(stderr, "Error during read: %s\n",
+ strerror(errno));
+ fclose(out);
+ return;
+ }
+
+ ret = fwrite(buffer, sizeof(char), bytes, out);
+ if (ret != bytes) {
+ if (ret != 0)
+ fprintf(stderr, "Short write (expected %d, "
+ "got %d)\n", bytes, ret);
+ else
+ fprintf(stderr, "Error during write: %s\n",
+ strerror(errno));
+ fclose(out);
+ return;
+ }
+
+ cur += bytes;
+ }
+
+ fclose(out);
+}
+/*
+ * Dump all residency filenames associated with a file, or all files
+ * within a directory.
+ */
+
+static void
+DumpAllFiles(int argc, char **argv, struct vnodeData *vdatacwd,
+ VolumeDiskData *vol)
+{
+#ifdef RESIDENCY
+ struct vnodeData *vdata, *nvdata;
+ struct DirCursor cursor;
+ struct DirEntry *ep;
+ FILE *f = stdout;
+ int c, i;
+ int dflag = 0, fflag = 0, errflg = 0;
+
+ optind = 1;
+
+ while ((c = getopt(argc, argv, "df:")) != EOF)
+ switch (c) {
+ case 'd':
+ dflag++;
+ break;
+ case 'f':
+ if ((f = fopen(optarg, "a")) == NULL) {
+ fprintf(stderr, "Cannot open \"%s\": %s\n",
+ optarg, strerror(errno));
+ return;
+ }
+ fflag++;
+ break;
+ case 'h':
+ case '?':
+ default:
+ errflg++;
+ }
+
+ if (errflg || argc == optind) {
+ fprintf(stderr, "Usage: %s [-d] [-f filename] file "
+ "[file ...]\n", argv[0]);
+ if (fflag)
+ fclose(f);
+ return;
+ }
+
+ for (i = optind; i < argc; i++) {
+
+ if ((vdata = FindFile(vdatacwd, argv[i])) == NULL)
+ continue;
+
+ if (vdata->vnode->type == vDirectory && ! dflag) {
+
+ ResetDirCursor(&cursor, vdata);
+
+ while ((ep = ReadNextDir(&cursor, vdata)) != NULL) {
+
+ if (!(nvdata =
+ GetVnode(ntohl(ep->fid.vnode)))) {
+ fprintf(stderr, "Cannot find vnode "
+ "entry for %s (%d)\n",
+ ep->name, ntohl(ep->fid.vnode));
+ continue;
+ }
+
+
+ if (!fflag) {
+ printf("Residency locations for %s:\n",
+ ep->name);
+
+ if (nvdata->dumpdata)
+ printf("Local disk (in dump "
+ "file)\n");
+ }
+
+ DumpAllResidencies(f, nvdata, vol);
+
+ }
+
+ } else {
+ if (!fflag) {
+ printf("Residency locations for %s:\n",
+ argv[i]);
+
+ if (vdata->dumpdata)
+ printf("Local disk (in dump file)\n");
+ }
+
+ DumpAllResidencies(f, vdata, vol);
+ }
+ }
+
+ if (fflag)
+ fclose(f);
+#else /* RESIDENCY */
+ fprintf(stderr, "The \"file\" command is not available in the non-"
+ "MRAFS version of dumptool.\n");
+#endif /* RESIDENCY */
+ return;
+}
+
+/*
+ * Take a vnode, traverse the vnode chain, and dump out all files on
+ * all residencies corresponding to that parent vnode.
+ */
+
+#ifdef RESIDENCY
+static void
+DumpAllResidencies(FILE *f, struct vnodeData *vdata, struct VolumeDiskData *vol)
+{
+ unsigned int nextVnodeNum;
+
+ while (nextVnodeNum = vdata->vnode->NextVnodeId) {
+ if ((vdata = GetVnode(nextVnodeNum)) == NULL) {
+ fprintf(stderr, "We had a pointer to %lu in it's "
+ "vnode chain, but there\nisn't a record of "
+ "it! The dump might be corrupt.\n",
+ nextVnodeNum);
+ return;
+ }
+
+ if (vdata->vnode->type == vFidLookup)
+ DumpVnodeFile(f, vdata->vnode, vol);
+ }
+
+ return;
+}
+#endif
+
+
+/*
+ * Given a directory vnode and a filename, return the vnode corresponding
+ * to the file in that directory.
+ *
+ * We now handle pathnames with directories in them.
+ */
+
+static struct vnodeData *
+FindFile(struct vnodeData *vdatacwd, char *filename)
+{
+ struct DirHeader *dhp;
+ struct DirEntry *ep;
+ int i, num;
+ struct vnodeData *vdata;
+ char *c, newstr[MAXPATHLEN];
+
+ if (! vdatacwd->filedata) {
+ fprintf(stderr, "There is no vnode data for this "
+ "directory!\n");
+ return NULL;
+ }
+
+ /*
+ * If we have a "/" in here, look up the vnode data for the
+ * directory (everything before the "/") and use that as our
+ * current directory. We automagically handle multiple directories
+ * by using FindFile recursively.
+ */
+
+ if ((c = strrchr(filename, '/')) != NULL) {
+
+ strncpy(newstr, filename, c - filename);
+ newstr[c - filename] = '\0';
+
+ if ((vdatacwd = FindFile(vdatacwd, newstr)) == NULL)
+ return NULL;
+
+ if (vdatacwd->vnode->type != vDirectory) {
+ fprintf(stderr, "%s: Not a directory\n", newstr);
+ return NULL;
+ }
+
+ filename = c + 1;
+ }
+
+ dhp = (struct DirHeader *) vdatacwd->filedata;
+
+ i = DirHash(filename);
+
+ num = ntohs(dhp->hashTable[i]);
+
+ while (num) {
+ ep = (struct DirEntry *) (vdatacwd->filedata + (num * 32));
+ if (strcmp(ep->name, filename) == 0)
+ break;
+ num = ntohs(ep->next);
+ }
+
+ if (! num) {
+ fprintf(stderr, "%s: No such file or directory\n", filename);
+ return NULL;
+ }
+
+ if ((vdata = GetVnode(ntohl(ep->fid.vnode))) == NULL) {
+ fprintf(stderr, "%s: No vnode information for %lu found\n",
+ filename, ntohl(ep->fid.vnode));
+ return NULL;
+ }
+
+ return vdata;
+}
+
+/*
+ * Reset a structure containing the current directory scan location
+ */
+
+static void
+ResetDirCursor(struct DirCursor *cursor, struct vnodeData *vdata)
+{
+ struct DirHeader *dhp;
+
+ cursor->hashbucket = 0;
+
+ dhp = (struct DirHeader *) vdata->filedata;
+
+ cursor->entry = ntohs(dhp->hashTable[0]);
+}
+
+/*
+ * Given a cursor and a directory entry, return the next entry in the
+ * directory.
+ */
+
+static struct DirEntry *
+ReadNextDir(struct DirCursor *cursor, struct vnodeData *vdata)
+{
+ struct DirHeader *dhp;
+ struct DirEntry *ep;
+
+ dhp = (struct DirHeader *) vdata->filedata;
+
+ if (cursor->entry) {
+ ep = (struct DirEntry *) (vdata->filedata +
+ (cursor->entry * 32));
+ cursor->entry = ntohs(ep->next);
+ return ep;
+ } else {
+ while (++(cursor->hashbucket) < NHASHENT) {
+ cursor->entry =
+ ntohs(dhp->hashTable[cursor->hashbucket]);
+ if (cursor->entry) {
+ ep = (struct DirEntry *) (vdata->filedata +
+ (cursor->entry * 32));
+ cursor->entry = ntohs(ep->next);
+ return ep;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Given a string, split it up into components a la Unix argc/argv.
+ *
+ * This code is most stolen from ftp.
+ */
+
+static void
+MakeArgv(char *string, int *argc, char ***argv)
+{
+ static char *largv[64];
+ char **la = largv;
+ char *s = string;
+ static char argbuf[256];
+ char *ap = argbuf;
+
+ *argc = 0;
+ *argv = largv;
+
+ while (*la++ = GetToken(s, &s, ap, &ap))
+ (*argc)++;
+}
+
+/*
+ * Return a pointer to the next token, and update the current string
+ * position.
+ */
+
+static char *
+GetToken(char *string, char **nexttoken, char argbuf[], char *nextargbuf[])
+{
+ char *sp = string;
+ char *ap = argbuf;
+ int got_one = 0;
+
+S0:
+ switch (*sp) {
+
+ case '\0':
+ goto OUTTOKEN;
+
+ case ' ':
+ case '\t':
+ sp++; goto S0;
+
+ default:
+ goto S1;
+ }
+
+S1:
+ switch (*sp) {
+
+ case ' ':
+ case '\t':
+ case '\0':
+ goto OUTTOKEN; /* End of our token */
+
+ case '\\':
+ sp++; goto S2; /* Get next character */
+
+ case '"':
+ sp++; goto S3; /* Get quoted string */
+
+ default:
+ *ap++ = *sp++; /* Add a character to our token */
+ got_one = 1;
+ goto S1;
+ }
+
+S2:
+ switch (*sp) {
+
+ case '\0':
+ goto OUTTOKEN;
+
+ default:
+ *ap++ = *sp++;
+ got_one = 1;
+ goto S1;
+ }
+
+S3:
+ switch (*sp) {
+
+ case '\0':
+ goto OUTTOKEN;
+
+ case '"':
+ sp++; goto S1;
+
+ default:
+ *ap++ = *sp++;
+ got_one = 1;
+ goto S3;
+ }
+
+OUTTOKEN:
+ if (got_one)
+ *ap++ = '\0';
+ *nextargbuf = ap; /* Update storage pointer */
+ *nexttoken = sp; /* Update token pointer */
+
+ return got_one ? argbuf : NULL;
+}
+
+/*
+ * Insert vnodes into our hash table.
+ */
+
+static struct vnodeData *
+InsertVnode(unsigned int vnodeNumber, struct VnodeDiskObject *vnode)
+{
+ struct VnodeDiskObject *nvnode;
+ struct vnodeData *vdata;
+ static int curSmallVnodeIndex = 0;
+ static int curLargeVnodeIndex = 0;
+ struct vnodeData ***vnodeIndex;
+ int *curIndex;
+
+ nvnode = (struct VnodeDiskObject *) malloc(sizeof(struct VnodeDiskObject));
+
+ if (!nvnode) {
+ if (verbose)
+ fprintf(stderr, "Unable to allocate space for vnode\n");
+ return NULL;
+ }
+
+ memcpy((void *) nvnode, (void *) vnode, sizeof(struct VnodeDiskObject));
+
+ if (vnodeNumber & 1) {
+ vnodeIndex = &LargeVnodeIndex;
+ curIndex = &curLargeVnodeIndex;
+ } else {
+ vnodeIndex = &SmallVnodeIndex;
+ curIndex = &curSmallVnodeIndex;
+ }
+
+ vdata = (struct vnodeData *) malloc(sizeof(struct vnodeData));
+
+ vdata->vnode = nvnode;
+ vdata->vnodeNumber = vnodeNumber;
+ vdata->dumpdata = 0;
+ vdata->filedata = 0;
+ vdata->datalength = 0;
+
+ (*vnodeIndex)[(*curIndex)++] = vdata;
+
+ return vdata;
+}
+
+/*
+ * Routine to retrieve a vnode from the hash table.
+ */
+
+static struct vnodeData *
+GetVnode(unsigned int vnodeNumber)
+{
+ struct vnodeData vnode, *vnodep, **tmp;
+
+ vnode.vnodeNumber = vnodeNumber;
+ vnodep = &vnode;
+
+ tmp = (struct vnodeData **)
+ bsearch((void *) &vnodep,
+ vnodeNumber & 1 ? LargeVnodeIndex : SmallVnodeIndex,
+ vnodeNumber & 1 ? numLargeVnodes : numSmallVnodes,
+ sizeof(struct vnodeData *), CompareVnode);
+
+ return tmp ? *tmp : NULL;
+}
+
+/*
+ * Our comparator function for bsearch
+ */
+
+static int
+CompareVnode(const void *node1, const void *node2)
+{
+ struct vnodeData **vnode1 = (struct vnodeData **) node1;
+ struct vnodeData **vnode2 = (struct vnodeData **) node2;
+
+ if ((*vnode1)->vnodeNumber == (*vnode2)->vnodeNumber)
+ return 0;
+ else if ((*vnode1)->vnodeNumber > (*vnode2)->vnodeNumber)
+ return 1;
+ else
+ return -1;
+}
+
+#ifdef RESIDENCY
+/*
+ * Dump out the filename corresponding to a particular vnode.
+ *
+ * This routine has the following dependancies:
+ *
+ * - Only will work on UFS filesystems at this point
+ * - Has to talk to the rsserver.
+ * - Can only determine UFS algorithm type when run on the same machine
+ * as the residency (unless you manually specify algorithm information)
+ */
+
+static int
+DumpVnodeFile(FILE *f, struct VnodeDiskObject *vnode, VolumeDiskData *vol)
+{
+ static int rscache = 0;
+ static rsaccessinfoList rsnlist = {0, 0};
+ char MountPoint[MAXPATHLEN + 1];
+ char FileName[MAXPATHLEN + 1];
+ unsigned int Size, Level[4];
+ unsigned int DeviceTag, Algorithm;
+ FileSystems *FSInfo;
+ int i, found, FSType, rsindex;
+
+ /*
+ * Maybe we found out something about this residency via the
+ * command-line; check that first.
+ */
+
+ rsindex = ffs(VLkp_Residencies(vnode)) - 1;
+
+ /*
+ * We need to get information from the rsserver (so we can
+ * find out the device tag for a given residency). If we
+ * haven't cached that, talk to the rsserver to get it.
+ * If we have info about this already, then don't talk to
+ * the rsserver (this lets us still do disaster recovery if
+ * MR-AFS is completely hosed).
+ */
+
+ if (! rscache && rscmdlineinfo[rsindex].DeviceTag == -1) {
+ int code;
+
+ code = ServerInitResidencyConnection();
+
+ if (code) {
+ fprintf(stderr, "ServerInitResidencyConnection failed "
+ "with code %d\n", code);
+ return -1;
+ }
+
+ code = rs_GetResidencySummary(ServerRequestorId, &rsnlist);
+
+ if (code) {
+ fprintf(stderr, "rs_GetResidencySummary failed "
+ "with code %d\n", code);
+ return -1;
+ }
+
+ rscache = 1;
+ }
+
+ /*
+ * For a given residency (as specified in the vnode),
+ * find out it's device tag number, either via the rsserver
+ * or via the command line.
+ */
+
+ if (rscmdlineinfo[rsindex].DeviceTag != -1) {
+ DeviceTag = rscmdlineinfo[rsindex].DeviceTag;
+ found = 1;
+ } else
+ for (i = 0, found = 0; (i < rsnlist.rsaccessinfoList_len) &&
+ (!found); i++) {
+ if (rsnlist.rsaccessinfoList_val[i].id.residency ==
+ VLkp_Residencies(vnode)) {
+ found = 1;
+ DeviceTag =
+ rsnlist.rsaccessinfoList_val[i].devicetagnumber;
+ break;
+ }
+ }
+
+ if (! found) {
+ if (verbose)
+ fprintf(stderr, "Unable to find residency %d in "
+ "rsserver database, aborting\n",
+ VLkp_Residencies(vnode));
+ return -1;
+ }
+
+ /*
+ * Okay, now we've got the DeviceTag ... which we can use to
+ * lookup the on-disk configuration information (which we
+ * assume is locally stored). We also need the DeviceTag to
+ * print out which partition we're using (but that comes later).
+ *
+ * We lookup the on-disk configuration information by calling
+ * Ufs_GetFSInfo() to get the configuration information on the
+ * filesystems specified by the given DeviceTag.
+ *
+ * Before we call Ufs_GetFSInfo, check the command-line cache;
+ * if we got something via the command-line, don't go to disk.
+ */
+
+ if (rscmdlineinfo[rsindex].FSType == -1 &&
+ Ufs_GetFSInfo(&FSInfo, DeviceTag)) {
+ if (verbose)
+ fprintf(stderr, "Ufs_GetFSInfo failed for DeviceTag "
+ "%d, Residency %d\n", DeviceTag,
+ VLkp_Residencies(vnode));
+ return -1;
+ }
+
+ /*
+ * The FSInfo structure has the last two things we need: the
+ * FSType (ufs, slowufs, etc etc), and the usage algorithm (which
+ * ends up being how many directories are being used on the
+ * residency filesystem).
+ *
+ * With these last two parameters, use routines stolen from
+ * ufsname to generate the filename.
+ *
+ * (Actually, I lied - we also need the "Size" parameter, which
+ * we can also get from FSInfo);
+ */
+
+ if (rscmdlineinfo[rsindex].FSType != -1) {
+ FSType = rscmdlineinfo[rsindex].FSType;
+ Algorithm = rscmdlineinfo[rsindex].Algorithm;
+ Size = rscmdlineinfo[rsindex].Size;
+ } else {
+ FSType = FSInfo->FileSystems_u.UfsInterface.FSType;
+ Algorithm = FSInfo->FileSystems_u.UfsInterface.Algorithm;
+ if (FSInfo->FileSystems_u.UfsInterface.Directories[1] == 0)
+ Size = 0;
+ else if (FSInfo->FileSystems_u.UfsInterface.Directories[1] == 16)
+ Size = 1;
+ else if (FSInfo->FileSystems_u.UfsInterface.Directories[1] == 256)
+ Size = 2;
+ else {
+ if (verbose)
+ fprintf(stderr, "Unknown directory size %d, "
+ "aborting\n",
+ FSInfo->FileSystems_u.UfsInterface.Directories[1]);
+ return -1;
+ }
+ }
+
+ /*
+ * First, generate our mount point from the DeviceTag and
+ * FSType.
+ */
+
+ DEVICETAGNUMBERTOMOUNTPOINT(MountPoint, DeviceTag, FSType);
+
+ /*
+ * Then, generate the "level" (directory bitmasks) from the
+ * file tags, size, and algorithm
+ */
+
+ UfsTagsToLevel(VLkp_FileTag1(vnode), VLkp_FileTag2(vnode), Algorithm,
+ Size, Level, VLkp_ParentVnodeId(vnode),
+ VLkp_ParentUniquifierId(vnode));
+
+ /*
+ * Finally, take the above information and generate the
+ * corresponding filename (this macro ends up being a
+ * sprintf() call)
+ */
+
+ TAGSTONAME(FileName, MountPoint, Level, Directories[Size][1],
+ vol->parentId, VLkp_ParentVnodeId(vnode),
+ VLkp_ParentUniquifierId(vnode), Algorithm);
+
+ fprintf(f, "%s\n", FileName);
+
+ return 0;
+}
+#endif
+
+/*
+ * Read a 16 bit integer in network order
+ */
+
+static int
+ReadInt16(FILE *f, unsigned short *s)
+{
+ unsigned short in;
+
+ if (fread((void *)&in, sizeof(in), 1, f) != 1) {
+ if (verbose)
+ fprintf(stderr, "ReadInt16 failed!\n");
+ return -1;
+ }
+
+ *s = ntohs(in);
+
+ return 0;
+}
+
+
+/*
+ * Read a 32 bit integer in network order
+ */
+
+static int
+ReadInt32(FILE *f, unsigned int *i)
+{
+ unsigned int in;
+
+ if (fread((void *)&in, sizeof(in), 1, f) != 1) {
+ if (verbose)
+ fprintf(stderr, "ReadInt32 failed!\n");
+ return -1;
+ }
+
+ *i = ntohl((unsigned long) in);
+
+ return 0;
+}
+
+/*
+ * Read a string from a dump file
+ */
+
+static int
+ReadString(FILE *f, char *string, int maxlen)
+{
+ int c;
+
+ while (maxlen--) {
+ if ((*string++ = getc(f)) == 0)
+ break;
+ }
+
+ /*
+ * I'm not sure what the _hell_ this is supposed to do ...
+ * but it was in the original dump code
+ */
+
+ if (string[-1]) {
+ while ((c = getc(f)) && c != EOF);
+ string[-1] = 0;
+ }
+
+ return 0;
+}
+
+static int
+ReadByteString(FILE *f, void *s, int size)
+{
+ unsigned char *c = (unsigned char *) s;
+
+ while (size--)
+ *c++ = getc(f);
+
+ return 0;
+}
+
+/*
+ * The directory hashing algorithm used by AFS
+ */
+
+DirHash (string)
+ register char *string; {
+ /* Hash a string to a number between 0 and NHASHENT. */
+ register unsigned char tc;
+ register int hval;
+ register int tval;
+ hval = 0;
+ while(tc=(*string++)) {
+ hval *= 173;
+ hval += tc;
+ }
+ tval = hval & (NHASHENT-1);
+#ifdef AFS_CRAY_ENV /* actually, any > 32 bit environment */
+ if (tval == 0) return tval;
+ else if (hval & 0x80000000) tval = NHASHENT-tval;
+#else /* AFS_CRAY_ENV */
+ if (tval == 0) return tval;
+ else if (hval < 0) tval = NHASHENT-tval;
+#endif /* AFS_CRAY_ENV */
+ return tval;
+}
+
+#ifdef RESIDENCY
+/*
+ * Sigh, we need this for the AFS libraries
+ */
+
+int
+LogErrors(int level, char *a, char *b, char *c, char *d, char *e, char *f,
+ char *g, char *h, char *i, char *j, char *k)
+{
+ if (level <= 0) {
+ fprintf(stderr, a, b, c, d, e, f, g, h, i, j, k);
+ }
+ return 0;
+}
+
+/*
+ * These are routines taken from AFS libraries and programs. Most of
+ * them are from ufsname.c, but a few are from the dir library (the dir
+ * library has a bunch of hidden dependancies, so it's not suitable to
+ * include it outright).
+ */
+
+UfsEntropiesToTags(HighEntropy,LowEntropy,Algorithm,FileTag1,FileTag2)
+ uint32_t HighEntropy;
+ uint32_t LowEntropy;
+ uint32_t Algorithm;
+ uint32_t *FileTag1;
+ uint32_t *FileTag2;
+{
+ int i;
+
+ if ((Algorithm > UFS_ALGORITHMS) || (Algorithm <= 0))
+ return -1;
+ *FileTag1 = 0;
+ *FileTag2 = 0;
+ for (i=0;i<32;++i) {
+ if (UfsEntropy[Algorithm-1][i] < 32)
+ *FileTag1 |= ((HighEntropy & (1 << i)) == 0) ?
+ 0 : 1 << UfsEntropy[Algorithm-1][i];
+ else
+ *FileTag2 |= ((HighEntropy & (1 << i)) == 0) ?
+ 0 : 1 << (UfsEntropy[Algorithm-1][i] - 32);
+ }
+ for (i=32;i<64;++i) {
+ if (UfsEntropy[Algorithm-1][i] < 32)
+ *FileTag1 |=((LowEntropy & (1 << (i - 32))) == 0) ?
+ 0 : 1 << UfsEntropy[Algorithm-1][i];
+ else
+ *FileTag2 |=((LowEntropy & (1 << (i - 32))) == 0) ?
+ 0 : 1 << (UfsEntropy[Algorithm-1][i] - 32);
+ }
+ return 0;
+}
+
+uint32_t UfsTagsToHighEntropy(FileTag1,FileTag2,Algorithm)
+ uint32_t FileTag1;
+ uint32_t FileTag2;
+ uint32_t Algorithm;
+{
+ int i;
+ uint32_t Value;
+
+ Value = 0;
+ for (i=0;i<32;++i) {
+ if (UfsEntropy[Algorithm-1][i] < 32)
+ Value |= ((FileTag1 & (1 << UfsEntropy[Algorithm-1][i]))
+ == 0) ? 0: 1 << i;
+ else
+ Value |= ((FileTag2 & (1 << (UfsEntropy[Algorithm-1][i] -
+ 32))) == 0) ? 0: 1 << i;
+ }
+ return Value;
+}
+
+uint32_t UfsTagsToLowEntropy(FileTag1,FileTag2,Algorithm)
+ uint32_t FileTag1;
+ uint32_t FileTag2;
+ uint32_t Algorithm;
+{
+ int i;
+ uint32_t Value;
+
+ Value = 0;
+ for (i=32;i<64;++i) {
+ if (UfsEntropy[Algorithm-1][i] < 32)
+ Value |= ((FileTag1 & (1 << UfsEntropy[Algorithm-1][i]))
+ == 0) ? 0: 1 << (i - 32);
+ else
+ Value |= ((FileTag2 & (1 << (UfsEntropy[Algorithm-1][i] -
+ 32))) == 0) ? 0: 1 << (i - 32) ;
+ }
+ return Value;
+}
+
+UfsTagsToLevel(FileTag1, FileTag2, Algorithm, Size, Sections, vnode, Uniquifier)
+ uint32_t FileTag1;
+ uint32_t FileTag2;
+ uint32_t Algorithm;
+ uint32_t Size;
+ uint32_t Sections[4];
+ uint32_t vnode;
+ uint32_t Uniquifier;
+{
+ uint32_t HighEntropy;
+ uint32_t LowEntropy;
+
+ switch (Algorithm) {
+ case 1:
+ LowEntropy = UfsTagsToLowEntropy(
+ FileTag1,
+ FileTag2,
+ Algorithm);
+ HighEntropy = UfsTagsToHighEntropy(
+ FileTag1,
+ FileTag2,
+ Algorithm);
+ Sections[0] = HighEntropy % Directories[Size][0];
+ HighEntropy /= Directories[Size][0];
+ if (Directories[Size][1]) {
+ Sections[1] = HighEntropy % Directories[Size][1];
+ HighEntropy /= Directories[Size][1];
+ Sections[2] = HighEntropy;
+ Sections[3] = LowEntropy;
+ } else {
+ Sections[1] = HighEntropy;
+ Sections[2] = LowEntropy;
+ }
+ break;
+ case 2:
+ Sections[0] = FileTag1 & 0xff;
+ if (Directories[Size][1]) {
+ Sections[1] = Uniquifier & 0xff;
+ if (Directories[Size][1] == 16) Sections[1] &= 0xf;
+ Sections[2] = FileTag1;
+ Sections[3] = FileTag2;
+ } else {
+ Sections[1] = FileTag1;
+ Sections[2] = FileTag2;
+ }
+ break;
+ case 3:
+ Sections[0] = FileTag1 & 0xff;
+ if (Directories[Size][1]) {
+ Sections[1] = (vnode >> 1) & 0xff;
+ if (Directories[Size][1] == 16) Sections[1] &= 0xf;
+ Sections[2] = FileTag1;
+ Sections[3] = FileTag2;
+ } else {
+ Sections[1] = FileTag1;
+ Sections[2] = FileTag2;
+ }
+ break;
+ default:
+ fprintf(stderr,"UfsTagsToLevel: bad algorithm %lu!\n", Algorithm);
+ return -1;
+ }
+ return 0;
+}
+
+#include <afs/afscbdummies.h>
+#endif /* RESIDENCY */
--- /dev/null
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/* int64.c - Support for 64-bit integers */
+
+#include <stdio.h>
+#include <string.h>
+#include "intNN.h"
+
+char *hexify_int64(u_int64 *X, char *buf)
+{
+ static char mybuf[17];
+
+#ifdef NATIVE_INT64
+ char c, *p;
+ u_int64 x = *X;
+
+ if (!buf) buf = mybuf;
+ p = buf + 16;
+ *p-- = 0;
+ while (x && p >= buf) {
+ c = x & 0xf;
+ c += ((c < 10) ? '0' : 'a' - 10);
+ *p-- = c;
+ x >>= 4;
+ }
+ while (p >= buf) *p-- = '0';
+
+#else
+ if (!buf) buf = mybuf;
+ sprintf(buf, "%08lx%08lx", X->hi, X->lo);
+#endif
+
+ return buf;
+}
+
+
+#ifdef NATIVE_INT64
+char *decimate_int64(u_int64 *X, char *buf)
+{
+ static char mybuf[21];
+ char *p;
+ u_int64 x = *X;
+
+ if (!buf) buf = mybuf;
+ p = buf + 21;
+ *--p = 0;
+ while (x && p > buf) {
+ *--p = ((x % 10) + '0');
+ x /= 10;
+ }
+ if (!*p) *--p = '0';
+ return p;
+}
+
+#else
+static char bitvals[64][21] = {
+/* 1 */ "00000000000000000001",
+/* 2 */ "00000000000000000002",
+/* 4 */ "00000000000000000004",
+/* 8 */ "00000000000000000008",
+/* 10 */ "00000000000000000016",
+/* 20 */ "00000000000000000032",
+/* 40 */ "00000000000000000064",
+/* 80 */ "00000000000000000128",
+/* 100 */ "00000000000000000256",
+/* 200 */ "00000000000000000512",
+/* 400 */ "00000000000000001024",
+/* 800 */ "00000000000000002048",
+/* 1000 */ "00000000000000004096",
+/* 2000 */ "00000000000000008192",
+/* 4000 */ "00000000000000016384",
+/* 8000 */ "00000000000000032768",
+/* 10000 */ "00000000000000065536",
+/* 20000 */ "00000000000000131072",
+/* 40000 */ "00000000000000262144",
+/* 80000 */ "00000000000000524288",
+/* 100000 */ "00000000000001048576",
+/* 200000 */ "00000000000002097152",
+/* 400000 */ "00000000000004194304",
+/* 800000 */ "00000000000008388608",
+/* 1000000 */ "00000000000016777216",
+/* 2000000 */ "00000000000033554432",
+/* 4000000 */ "00000000000067108864",
+/* 8000000 */ "00000000000134217728",
+/* 10000000 */ "00000000000268435456",
+/* 20000000 */ "00000000000536870912",
+/* 40000000 */ "00000000001073741824",
+/* 80000000 */ "00000000002147483648",
+/* 100000000 */ "00000000004294967296",
+/* 200000000 */ "00000000008589934592",
+/* 400000000 */ "00000000017179869184",
+/* 800000000 */ "00000000034359738368",
+/* 1000000000 */ "00000000068719476736",
+/* 2000000000 */ "00000000137438953472",
+/* 4000000000 */ "00000000274877906944",
+/* 8000000000 */ "00000000549755813888",
+/* 10000000000 */ "00000001099511627776",
+/* 20000000000 */ "00000002199023255552",
+/* 40000000000 */ "00000004398046511104",
+/* 80000000000 */ "00000008796093022208",
+/* 100000000000 */ "00000017592186044416",
+/* 200000000000 */ "00000035184372088832",
+/* 400000000000 */ "00000070368744177664",
+/* 800000000000 */ "00000140737488355328",
+/* 1000000000000 */ "00000281474976710656",
+/* 2000000000000 */ "00000562949953421312",
+/* 4000000000000 */ "00001125899906842624",
+/* 8000000000000 */ "00002251799813685248",
+/* 10000000000000 */ "00004503599627370496",
+/* 20000000000000 */ "00009007199254740992",
+/* 40000000000000 */ "00018014398509481984",
+/* 80000000000000 */ "00036028797018963968",
+/* 100000000000000 */ "00072057594037927936",
+/* 200000000000000 */ "00144115188075855872",
+/* 400000000000000 */ "00288230376151711744",
+/* 800000000000000 */ "00576460752303423488",
+/* 1000000000000000 */ "01152921504606846976",
+/* 2000000000000000 */ "02305843009213693952",
+/* 4000000000000000 */ "04611686018427387904",
+/* 8000000000000000 */ "09223372036854775808" };
+
+
+static void prep_table(void)
+{
+ int bit, digit;
+
+ if (bitvals[0][0] < '0') return;
+ for (bit = 0; bit < 64; bit++)
+ for (digit = 0; digit < 20; digit++)
+ bitvals[bit][digit] -= '0';
+}
+
+
+static void add_bit(int bit, char *answer)
+{
+ int digit;
+
+ for (digit = 19; digit >= 0; digit--) {
+ answer[digit] += bitvals[bit][digit];
+ if (!digit) break;
+ while(answer[digit] > 9) {
+ answer[digit] -= 10;
+ answer[digit-1]++;
+ }
+ }
+}
+
+
+static void decimate(unsigned long hi, unsigned long lo, char *answer)
+{
+ unsigned long mask;
+ int bit, digit;
+
+ memset(answer, 0, 21);
+ for (bit = 0, mask = 1; bit < 32; bit++, mask <<= 1)
+ if (lo&mask) add_bit(bit, answer);
+ for (bit = 0, mask = 1; bit < 32; bit++, mask <<= 1)
+ if (hi&mask) add_bit(bit + 32, answer);
+
+ for (digit = 0; digit < 20; digit++)
+ answer[digit] += '0';
+}
+
+char *decimate_int64(u_int64 *X, char *buf)
+{
+ static char mybuf[21];
+ char *p;
+
+ prep_table();
+ if (!buf) buf = mybuf;
+ decimate(X->hi, X->lo, buf);
+ for (p = buf; *p == '0'; p++);
+ return (*p) ? p : p-1;
+}
+
+#endif /* NATIVE_INT64 */
+
+
+void shift_int64(u_int64 *X, int bits)
+{
+#ifdef NATIVE_INT64
+ if (bits < 0) *X >>= (-bits);
+ else *X <<= bits;
+#else
+ if (bits < 0) {
+ bits = -bits;
+ if (bits >= 32) {
+ X->lo = ((X->hi & 0xffffffffL) >> (bits - 32));
+ X->hi = 0;
+ } else {
+ X->lo = ((X->lo & 0xffffffffL) >> bits)
+ | ((X->hi & ((1 << (32 - bits)) - 1)) << (32 - bits));
+ X->hi = ((X->hi & 0xffffffffL) >> bits);
+ }
+ } else {
+ if (bits >= 32) {
+ X->hi = ((X->lo & 0xffffffffL) << (bits - 32));
+ X->lo = 0;
+ } else {
+ X->hi = ((X->hi & 0xffffffffL) << bits)
+ | ((X->lo & (((1 << bits) - 1) << (32 - bits))) >> (32 - bits));
+ X->lo = ((X->lo & 0xffffffffL) << bits);
+ }
+ }
+#endif
+}
+
+
+#ifdef TEST_INT64
+
+/** the rest of this is for testing the int64 suite **/
+
+#ifdef NATIVE_INT64
+
+#define xize(x) #x
+#define stringize(x) xize(x)
+#define INT64_NAME stringize(unsigned NATIVE_INT64)
+
+
+#endif /* NATIVE_INT64 */
+
+
+void verify_int64_size () {
+#ifdef NATIVE_INT64
+ signed char testchar = -1;
+ unsigned int testint = (unsigned char)testchar;
+
+ printf("We think '%s' is a native 64-bit type\n", INT64_NAME);
+
+ if (testint != 0xff) {
+ printf("testint = 0x%x; should be 0xff\n", testint);
+ fprintf(stderr, "Hmm... char's are not 8 bits. That sucks!\n");
+ exit(-1);
+ }
+ printf("Looks like a char is 8 bits...\n");
+
+ if (sizeof(unsigned NATIVE_INT64) != 8) {
+ printf("sizeof(%s) = %d; should be 8\n", INT64_NAME, sizeof(unsigned NATIVE_INT64));
+ fprintf(stderr, "Hey! You said a %s was 64-bits wide!\n", INT64_NAME);
+ exit(-1);
+ }
+ printf("Yippee! We have a native 64-bit type (%s)\n\n", INT64_NAME);
+
+#else /* !NATIVE_INT64 */
+
+ printf("Using fake 64-bit integers...\n\n");
+#endif /* NATIVE_INT64 */
+}
+
+
+void test_int64_constructs(void)
+{
+ u_int64 x, y;
+ afs_uint32 hi, lo;
+ int failures = 0, pass;
+ char buf[17];
+
+ printf("Constructor/accessor tests:\n");
+ printf("Setting x := %s\n", INT64_TEST_STR);
+ mk64(x, INT64_TEST_HI, INT64_TEST_LO);
+
+#ifdef NATIVE_INT64
+ pass = (x == INT64_TEST_CONST);
+ hexify_int64(&x, buf);
+ printf("NATIVE mk64: x = 0x%16s %s\n",
+ buf, pass ? "PASSED" : "FAILED");
+ if (!pass) failures++;
+#else
+ pass = (x.hi == INT64_TEST_HI && x.lo == INT64_TEST_LO);
+ printf("FAKE mk64: x.hi = 0x%08lx x.lo = 0x%08lx %s\n",
+ x.hi, x.lo, pass ? "PASSED" : "FAILED");
+ if (!pass) failures++;
+#endif
+
+ pass = (hi64(x) == INT64_TEST_HI && lo64(x) == INT64_TEST_LO);
+ printf("hi64/lo64: hi64(x) = 0x%08lx lo64(x) = 0x%08lx %s\n",
+ hi64(x), lo64(x), pass ? "PASSED" : "FAILED");
+ if (!pass) failures++;
+
+ ex64(x, hi, lo);
+ pass = (hi == INT64_TEST_HI && lo == INT64_TEST_LO);
+ printf("ex64: hi = 0x%08lx lo = 0x%08lx %s\n",
+ hi, lo, pass ? "PASSED" : "FAILED");
+ if (!pass) failures++;
+
+ cp64(y, x);
+ pass = (hi64(y) == INT64_TEST_HI && lo64(y) == INT64_TEST_LO);
+ printf("cp64: hi64(y) = 0x%08lx lo64(y) = 0x%08lx %s\n",
+ hi64(y), lo64(y), pass ? "PASSED" : "FAILED");
+ if (!pass) failures++;
+
+ if (failures) printf("%d/4 tests FAILED\n\n", failures);
+ else printf("All 4 tests PASSED\n\n");
+}
+
+
+void test_int64_compares()
+{
+#define NCOMPARE 9
+ u_int64 control, test[NCOMPARE];
+ char cbuf[17], tbuf[17];
+ int i, r, result[NCOMPARE];
+ int pass, failures, FAILURES = 0;
+
+ printf("Comparison tests:\n");
+
+ mk64(control, 0x12345678, 0xabcdabcd);
+ mk64(test[0], 0x12340000, 0xabcd0000); result[0] = +1;
+ mk64(test[1], 0x12340000, 0xabcdabcd); result[1] = +1;
+ mk64(test[2], 0x12340000, 0xabcdffff); result[2] = +1;
+ mk64(test[3], 0x12345678, 0xabcd0000); result[3] = +1;
+ mk64(test[4], 0x12345678, 0xabcdabcd); result[4] = 0;
+ mk64(test[5], 0x12345678, 0xabcdffff); result[5] = -1;
+ mk64(test[6], 0x1234ffff, 0xabcd0000); result[6] = -1;
+ mk64(test[7], 0x1234ffff, 0xabcdabcd); result[7] = -1;
+ mk64(test[8], 0x1234ffff, 0xabcdffff); result[8] = -1;
+
+ for (i = 0; i < NCOMPARE; i++) {
+ failures = 0;
+ hexify_int64(&control, cbuf);
+ hexify_int64(&test[i], tbuf);
+
+ r = eq64(control, test[i]);
+ pass = (r == (result[i] == 0)); if (!pass) failures++;
+ printf("0x%s == 0x%s %s\n", cbuf, tbuf, pass ? "PASSED" : "FAILED");
+
+ r = ne64(control, test[i]);
+ pass = (r == (result[i] != 0)); if (!pass) failures++;
+ printf("0x%s != 0x%s %s\n", cbuf, tbuf, pass ? "PASSED" : "FAILED");
+
+ r = lt64(control, test[i]);
+ pass = (r == (result[i] < 0)); if (!pass) failures++;
+ printf("0x%s < 0x%s %s\n", cbuf, tbuf, pass ? "PASSED" : "FAILED");
+
+ r = le64(control, test[i]);
+ pass = (r == (result[i] <= 0)); if (!pass) failures++;
+ printf("0x%s <= 0x%s %s\n", cbuf, tbuf, pass ? "PASSED" : "FAILED");
+
+ r = gt64(control, test[i]);
+ pass = (r == (result[i] > 0)); if (!pass) failures++;
+ printf("0x%s > 0x%s %s\n", cbuf, tbuf, pass ? "PASSED" : "FAILED");
+
+ r = ge64(control, test[i]);
+ pass = (r == (result[i] >= 0)); if (!pass) failures++;
+ printf("0x%s >= 0x%s %s\n", cbuf, tbuf, pass ? "PASSED" : "FAILED");
+
+ r = zero64(test[i]);
+ pass = !r; if (!pass) failures++;
+ printf("0x%s is nonzero %s\n",
+ tbuf, pass ? "PASSED" : "FAILED");
+
+ if (failures) printf("%d/7 tests on this pair FAILED\n\n", failures);
+ else printf("All 7 tests on this pair PASSED\n\n");
+ }
+
+ mk64(control, 0, 0);
+ pass = zero64(control); if (!pass) FAILURES++;
+ printf("0x0000000000000000 is zero %s\n",
+ pass ? "PASSED" : "FAILED");
+
+ if (FAILURES)
+ printf("%d/%d comparison tests FAILED\n\n", FAILURES, 7 * NCOMPARE + 1);
+ else
+ printf("All %d comparison tests PASSED\n\n", 7 * NCOMPARE + 1);
+}
+
+
+void test_int64_arith()
+{
+ printf("No arithmetic tests yet!!!\n");
+}
+
+
+void main() {
+ verify_int64_size();
+ test_int64_constructs();
+ test_int64_compares();
+ test_int64_arith();
+ exit(0);
+}
+#endif
--- /dev/null
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#ifndef _INTNN_H_
+#define _INTNN_H_
+
+/* intNN.h - Sized integer types */
+#include <afs/stds.h>
+#if 0
+typedef short afs_int16;
+typedef unsigned short afs_uint16;
+
+typedef long afs_int32;
+typedef unsigned long afs_uint32;
+#endif
+
+
+/* Support for 64-bit integers.
+ * Presently, only unsigned 64-bit numbers are supported.
+ */
+#define INT64_TEST_STR "0x12345678fedcba98"
+#define INT64_TEST_HI 0x12345678
+#define INT64_TEST_LO 0xfedcba98
+
+
+#ifdef NATIVE_INT64
+typedef unsigned NATIVE_INT64 u_int64;
+
+/* construct/extract/assign */
+#define mk64(X,H,L) ((X) = ( ((u_int64)(H) << 32) \
+ | ((u_int64)(L) & 0xffffffff)))
+#define hi64(Y) ((afs_uint32)(((Y) >> 32) & 0xffffffff))
+#define lo64(Y) ((afs_uint32)((Y) & 0xffffffff))
+#define ex64(Y,H,L) ((H) = hi64(Y), (L) = lo64(Y))
+#define cp64(X,Y) ((X) = (Y))
+#define get64(X) (X)
+#define set64(X,V) ((X) = (V))
+
+/* Comparison */
+#define eq64(X,Y) ((X) == (Y))
+#define ne64(X,Y) ((X) != (Y))
+#define lt64(X,Y) ((X) < (Y))
+#define le64(X,Y) ((X) <= (Y))
+#define gt64(X,Y) ((X) > (Y))
+#define ge64(X,Y) ((X) >= (Y))
+#define zero64(X) (!(X))
+
+/* Arithmetic */
+#define add64_32(X,A,B) ((X) = (A) + (u_int64)(B))
+#define add64_64(X,A,B) ((X) = (A) + (B))
+#define sub64_32(X,A,B) ((X) = (A) - (u_int64)(B))
+#define sub64_64(X,A,B) ((X) = (A) - (B))
+
+/* Byte-order */
+#ifdef WORDS_BIGENDIAN
+#define hton64(X,Y) cp64(X,Y)
+#define ntoh64(X,Y) cp64(X,Y)
+#else
+#define hton64(X,Y) mk64(X,htonl(lo64(Y)),htonl(hi64(Y)))
+#define ntoh64(X,Y) mk64(X,ntohl(lo64(Y)),ntohl(hi64(Y)))
+#endif
+
+#else /* !NATIVE_INT64 */
+/** We have to provide our own 64-bit integers **/
+typedef struct { afs_uint32 hi, lo; } u_int64;
+
+/* construct/extract/assign */
+#define mk64(X,H,L) ((X).hi = (H), (X).lo = (L))
+#define ex64(Y,H,L) ((H) = (Y).hi, (L) = (Y).lo)
+#define hi64(Y) ((Y).hi)
+#define lo64(Y) ((Y).lo)
+#define cp64(X,Y) ((X).hi = (Y).hi, (X).lo = (Y).lo)
+#define get64(X) ((X).lo)
+#define set64(X,V) ((X).hi = 0, (X).lo = (V))
+
+/* Comparison */
+#define eq64(A,B) ((A).hi == (B).hi && (A).lo == (B).lo)
+#define ne64(A,B) ((A).hi != (B).hi || (A).lo != (B).lo)
+#define lt64(A,B) ((A).hi < (B).hi || ((A).hi == (B).hi && (A).lo < (B).lo))
+#define le64(A,B) ((A).hi < (B).hi || ((A).hi == (B).hi && (A).lo <= (B).lo))
+#define gt64(A,B) ((A).hi > (B).hi || ((A).hi == (B).hi && (A).lo > (B).lo))
+#define ge64(A,B) ((A).hi > (B).hi || ((A).hi == (B).hi && (A).lo >= (B).lo))
+#define zero64(X) ((X).hi == 0 && (X).lo == 0)
+
+/* Arithmetic */
+#define add64_32(X,A,B) ( \
+ (X).lo = (A).lo + (B), \
+ (X).hi = (A).hi + \
+ (((((A).lo & 0x80000000) ^ ((B) & 0x80000000)) && !((X).lo & 0x80000000)) \
+ || (((A).lo & 0x80000000) && ((B) & 0x80000000))) \
+ )
+#define add64_64(X,A,B) (add64_32(X,A,(B).lo), (X).hi += (B).hi)
+
+#define sub64_32(X,A,B) ((X).lo = (A).lo - (B), \
+ (X).hi = (A).hi - ((A).lo < (B)))
+#define sub64_64(X,A,B) (sub64_32(X,A,(B).lo), (X).hi -= (B).hi)
+
+/* Byte-order */
+#define hton64(X,Y) mk64(X,htonl(hi64(Y)),htonl(lo64(Y)))
+#define ntoh64(X,Y) mk64(X,ntohl(hi64(Y)),ntohl(lo64(Y)))
+
+#endif /* NATIVE_INT64 */
+
+
+/* The following are too complex to be macros: */
+
+/* char *hexify_int64(u_int64 a, char *buf)
+ * Produces an ASCII representation of a in hexadecimal, and returns
+ * a pointer to the resulting string. If buf is non-NULL, it is taken
+ * to be a pointer to the buffer to be used, which must be at least 17
+ * bytes long. This function is thread-safe iff buf is provided.
+ */
+extern char *hexify_int64(u_int64 *, char *);
+
+/* char *decimate_int64(u_int64 a, char *buf)
+ * Produces an ASCII representation of a in decimal, and returns
+ * a pointer to the resulting string. If buf is non-NULL, it is taken
+ * to be a pointer to the buffer to be used, which must be at least 21
+ * bytes long. This function is thread-safe iff buf is provided.
+ */
+extern char *decimate_int64(u_int64 *, char *);
+
+/* void shift_int64(u_int64 a, int bits)
+ * Shifts the 64-bit integer in a by the specified number of bits.
+ * If bits is positive, the shift is to the left; if negative, the
+ * shift is to the right.
+ */
+extern void shift_int64(u_int64 *, int);
+
+#endif /* _INTNN_H_ */
--- /dev/null
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/* internal.h - Routines for internal use only */
+
+#include "xfiles.h"
+#include "dumpscan.h"
+
+
+/* parsevol.c - Routines to parse volume headers */
+extern afs_uint32 parse_volhdr(XFILE *, unsigned char *, tagged_field *, afs_uint32,
+ tag_parse_info *, void *, void *);
+
+/* parsevnode.c - Routines to parse vnodes and their fields */
+extern afs_uint32 parse_vnode(XFILE *, unsigned char *, tagged_field *, afs_uint32,
+ tag_parse_info *, void *, void *);
+
+/* directory.c - Routines for parsing AFS directories */
+extern afs_uint32 parse_directory(XFILE *, dump_parser *, afs_vnode *,
+ afs_uint32, int);
+
+/* backuphdr.c - Generic support for backup system headers */
+extern afs_uint32 try_backuphdr(XFILE *X, unsigned char *tag, tagged_field *field,
+ afs_uint32 value, tag_parse_info *pi,
+ void *g_refcon, void *l_refcon);
+
+/* util.c - Random utilities */
+extern afs_uint32 handle_return(int, XFILE *, unsigned char, dump_parser *);
+extern void prep_pi(dump_parser *, tag_parse_info *);
+extern afs_uint32 match_next_vnode(XFILE *, dump_parser *, u_int64 *, afs_uint32);
--- /dev/null
+#include <sys/fcntl.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "dumpscan.h"
+
+char *argv0;
+static char *input_path = 0;
+static int quiet = 0, showpaths = 0, searchcount = 1;
+static int error_count = 0, bad_count = 0;
+static path_hashinfo phi;
+static dump_parser dp;
+
+/* Print a usage message and exit */
+static void usage(int status, char *msg)
+{
+ if (msg) fprintf(stderr, "%s: %s\n", argv0, msg);
+ fprintf(stderr, "Usage: %s [options] [file]\n", argv0);
+ fprintf(stderr, " -h Print this help message\n");
+ fprintf(stderr, " -p Print paths of bad vnodes\n");
+ fprintf(stderr, " -q Quiet mode (don't print errors)\n");
+ exit(status);
+}
+
+
+/* Parse the command-line options */
+static void parse_options(int argc, char **argv)
+{
+ int c;
+
+ if (argv0 = strrchr(argv[0], '/')) argv0++;
+ else argv0 = argv[0];
+
+ /* Parse the options */
+ while ((c = getopt(argc, argv, "n:hpq")) != EOF) {
+ switch (c) {
+ case 'n': searchcount = atoi(optarg); continue;
+ case 'p': showpaths = 1; continue;
+ case 'q': quiet = 1; continue;
+ case 'h': usage(0, 0);
+ default: usage(1, "Invalid option!");
+ }
+ }
+
+ if (argc - optind > 1) usage(1, "Too many arguments!");
+ input_path = (argc == optind) ? "-" : argv[optind];
+}
+
+
+/* A callback to count and print errors */
+static afs_uint32 my_error_cb(afs_uint32 code, int fatal, void *ref, char *msg, ...)
+{
+ va_list alist;
+
+ error_count++;
+ if (!quiet) {
+ va_start(alist, msg);
+ com_err_va(argv0, code, msg, alist);
+ va_end(alist);
+ }
+}
+
+
+/* A callback to process file vnodes */
+static afs_uint32 my_file_cb(afs_vnode *v, XFILE *X, void *refcon)
+{
+ static char buf[1024];
+ afs_uint32 size, nulls, cnulls, maxcnulls, n, r;
+ char *name = 0;
+ int i;
+
+ nulls = cnulls = maxcnulls = 0;
+ size = v->size;
+ if ((r = xfseek(X, &v->d_offset))) return r;
+ while (size) {
+ n = (size > 1024) ? 1024 : size;
+ if (r = xfread(X, buf, n)) return r;
+ for (i = 0; i < n; i++) {
+ if (buf[i]) {
+ if (cnulls > maxcnulls) maxcnulls = cnulls;
+ cnulls = 0;
+ } else {
+ nulls++;
+ cnulls++;
+ }
+ }
+ size -= n;
+ }
+ if (maxcnulls >= searchcount) {
+ bad_count++;
+ if (showpaths) Path_Build(X, &phi, v->vnode, &name, 0);
+ if (name) {
+ printf("*** BAD %d (%s) - %d nulls, %d consecutive\n",
+ v->vnode, name, nulls, maxcnulls);
+ free(name);
+ } else {
+ printf("*** BAD %d - %d nulls, %d consecutive\n",
+ v->vnode, nulls, maxcnulls);
+ }
+ }
+ return r;
+}
+
+
+int main(int argc, char **argv)
+{
+ XFILE input_file;
+ afs_uint32 r;
+
+ parse_options(argc, argv);
+ initialize_acfg_error_table();
+ initialize_AVds_error_table();
+ initialize_rxk_error_table();
+ initialize_u_error_table();
+ initialize_vl_error_table();
+ initialize_vols_error_table();
+ initialize_xFil_error_table();
+ r = xfopen(&input_file, O_RDONLY, input_path);
+ if (r) {
+ com_err(argv0, r, "opening %s", input_path);
+ exit(2);
+ }
+
+ memset(&dp, 0, sizeof(dp));
+ dp.cb_error = my_error_cb;
+ if (input_file.is_seekable) dp.flags |= DSFLAG_SEEK;
+ if (showpaths) {
+ u_int64 where;
+
+ memset(&phi, 0, sizeof(phi));
+ phi.p = &dp;
+
+ if ((r = xftell(&input_file, &where))
+ || (r = Path_PreScan(&input_file, &phi, 0))
+ || (r = xfseek(&input_file, &where))) {
+ com_err(argv0, r, "- path initialization failed");
+ xfclose(&input_file);
+ exit(2);
+ }
+ }
+
+ dp.cb_vnode_file = my_file_cb;
+ r = ParseDumpFile(&input_file, &dp);
+ xfclose(&input_file);
+
+ if (error_count) printf("*** %d errors\n", error_count);
+ if (bad_count) printf("*** %d bad files\n", bad_count);
+ if (r && !quiet) printf("*** FAILED: %s\n", error_message(r));
+}
--- /dev/null
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/* parsedump.c - Parse a volume dump file */
+
+#include "dumpscan.h"
+#include "dumpscan_errs.h"
+#include "dumpfmt.h"
+#include "internal.h"
+#include "stagehdr.h"
+
+static afs_uint32 parse_dumphdr (XFILE *, unsigned char *, tagged_field *,
+ afs_uint32, tag_parse_info *, void *, void *);
+static afs_uint32 parse_dumpend (XFILE *, unsigned char *, tagged_field *,
+ afs_uint32, tag_parse_info *, void *, void *);
+static afs_uint32 store_dumphdr (XFILE *, unsigned char *, tagged_field *,
+ afs_uint32, tag_parse_info *, void *, void *);
+static afs_uint32 parse_dumptimes(XFILE *, unsigned char *, tagged_field *,
+ afs_uint32, tag_parse_info *, void *, void *);
+
+/** Field list for top-level objects **/
+static tagged_field top_fields[] = {
+ { TAG_DUMPHEADER, DKIND_SPECIAL, "* DUMP HEADER", parse_dumphdr, 0, 0 },
+ { TAG_VOLHEADER, DKIND_SPECIAL, "* VOLUME HEADER", parse_volhdr, 0, 0 },
+ { TAG_VNODE, DKIND_SPECIAL, "* VNODE ", parse_vnode, 0, 0 },
+ { TAG_DUMPEND, DKIND_INT32, "* DUMP END", parse_dumpend, 0, 0 },
+ { STAGE_VERSMIN, DKIND_SPECIAL, "* STAGE HEADER", try_backuphdr, 0, 0 },
+ { 0,0,0,0,0,0 }};
+
+
+/** Field list for dump headers **/
+static tagged_field dumphdr_fields[] = {
+ { DHTAG_VOLNAME, DKIND_STRING, " Volume name: ", store_dumphdr, 0, 0 },
+ { DHTAG_VOLID, DKIND_INT32, " Volume ID: ", store_dumphdr, 0, 0 },
+ { DHTAG_DUMPTIMES, DKIND_SPECIAL, " Dump Range: ", parse_dumptimes, 0, 0 },
+ { 0,0,0,0,0,0 }};
+
+
+/* Parse a dump header, including its tagged attributes, and call the
+ * dump-header callback, if one is defined.
+ */
+static afs_uint32 parse_dumphdr(XFILE *X, unsigned char *tag, tagged_field *field,
+ afs_uint32 value, tag_parse_info *pi,
+ void *g_refcon, void *l_refcon)
+{
+ dump_parser *p = (dump_parser *)g_refcon;
+ afs_dump_header hdr;
+ u_int64 where;
+ afs_uint32 r;
+
+ memset(&hdr, 0, sizeof(hdr));
+ if (r = xftell(X, &where)) return r;
+ sub64_32(hdr.offset, where, 1);
+
+ if (r = ReadInt32(X, &hdr.magic)) return r;
+ if (r = ReadInt32(X, &hdr.version)) return r;
+
+ if (hdr.magic != DUMPBEGINMAGIC) {
+ if (p->cb_error)
+ (p->cb_error)(DSERR_MAGIC, 1, p->err_refcon,
+ "Invalid magic number (0x%08x) in dump header",
+ hdr.magic);
+ return DSERR_MAGIC;
+ }
+ if (hdr.version != DUMPVERSION) {
+ if (p->cb_error)
+ (p->cb_error)(DSERR_MAGIC, 1, p->err_refcon,
+ "Unknown dump format version (%d) in dump header",
+ hdr.version);
+ return DSERR_MAGIC;
+ }
+
+ if (p->print_flags & DSPRINT_DUMPHDR)
+ printf("%s [%s = 0x%s]\n", field->label,
+ decimate_int64(&hdr.offset, 0), hexify_int64(&hdr.offset, 0));
+ if (p->print_flags & DSPRINT_DUMPHDR) {
+ printf(" Magic number: 0x%08x\n", hdr.magic);
+ printf(" Version: %d\n", hdr.version);
+ }
+ r = ParseTaggedData(X, dumphdr_fields, tag, pi, g_refcon, (void *)&hdr);
+
+ if (!r && p->cb_dumphdr) {
+ r = xftell(X, &where);
+ if (!r) r = (p->cb_dumphdr)(&hdr, X, p->refcon);
+ if (p->flags & DSFLAG_SEEK) {
+ if (!r) r = xfseek(X, &where);
+ else xfseek(X, &where);
+ }
+ }
+ if (hdr.field_mask & F_DUMPHDR_VOLNAME)
+ free(hdr.volname);
+ return r;
+}
+
+
+/* Store tagged attributes into a dump header */
+static afs_uint32 store_dumphdr(XFILE *X, unsigned char *tag, tagged_field *field,
+ afs_uint32 value, tag_parse_info *pi,
+ void *g_refcon, void *l_refcon)
+{
+ dump_parser *p = (dump_parser *)g_refcon;
+ afs_dump_header *hdr = (afs_dump_header *)l_refcon;
+
+ switch (field->tag) {
+ case DHTAG_VOLID:
+ hdr->field_mask |= F_DUMPHDR_VOLID;
+ hdr->volid = value;
+ if (p->print_flags & DSPRINT_DUMPHDR)
+ printf("%s%d\n", field->label, hdr->volid);
+ return 0;
+
+ case DHTAG_VOLNAME:
+ if (tag && tag[0]) {
+ hdr->field_mask |= F_DUMPHDR_VOLNAME;
+ hdr->volname = tag;
+ if (p->print_flags & DSPRINT_DUMPHDR)
+ printf("%s%s\n", field->label, hdr->volname);
+ return DSERR_KEEP;
+ } else return 0;
+
+ default:
+ if (p->print_flags & DSPRINT_DUMPHDR)
+ printf("%s<<< UNKNOWN FIELD >>>\n", field->label);
+ return 0;
+ }
+}
+
+
+/* Parse and store the dump time range from a dump header */
+static afs_uint32 parse_dumptimes(XFILE *X, unsigned char *tag,
+ tagged_field *field, afs_uint32 value,
+ tag_parse_info *pi,
+ void *g_refcon, void *l_refcon)
+{
+ dump_parser *p = (dump_parser *)g_refcon;
+ afs_dump_header *hdr = (afs_dump_header *)l_refcon;
+ afs_uint16 count;
+ afs_uint32 r;
+
+ if (r = ReadInt16(X, &count)) return r;
+ if (count != 2) {
+ if (p->cb_error)
+ (p->cb_error)(DSERR_FMT, 1, p->err_refcon,
+ "Incorrect array count (%d) in dump times", count);
+ return DSERR_FMT;
+ }
+ if (r = ReadInt32(X, &hdr->from_date)) return r;
+ if (r = ReadInt32(X, &hdr->to_date)) return r;
+ hdr->field_mask |= (F_DUMPHDR_FROM | F_DUMPHDR_TO);
+ if (p->print_flags & DSPRINT_DUMPHDR)
+ printf("%s%d => %d\n", field->label, hdr->from_date, hdr->to_date);
+
+ return ReadByte(X, tag);
+}
+
+
+/* Parse a dump_end record */
+static afs_uint32 parse_dumpend(XFILE *X, unsigned char *tag, tagged_field *field,
+ afs_uint32 value, tag_parse_info *pi,
+ void *g_refcon, void *l_refcon)
+{
+ dump_parser *p = (dump_parser *)g_refcon;
+ afs_uint32 r;
+
+ if (value != DUMPENDMAGIC) {
+ if (p->cb_error)
+ (p->cb_error)(DSERR_MAGIC, 1, p->err_refcon,
+ "Invalid magic number (0x%08x) in dump trailer",
+ value);
+ return DSERR_MAGIC;
+ }
+ if (p->print_flags & (DSPRINT_DUMPHDR | DSPRINT_ITEM))
+ printf("%s\n", field->label);
+ return DSERR_DONE;
+}
+
+
+
+afs_uint32 ParseDumpFile(XFILE *X, dump_parser *p)
+{
+ tag_parse_info pi;
+ unsigned char tag;
+ afs_uint32 r;
+
+ prep_pi(p, &pi);
+ r = ParseTaggedData(X, top_fields, &tag, &pi, (void *)p, 0);
+ return handle_return(r, X, tag, p);
+}
+
+
+afs_uint32 ParseDumpHeader(XFILE *X, dump_parser *p)
+{
+ tag_parse_info pi;
+ unsigned char tag;
+ afs_uint32 r;
+
+ prep_pi(p, &pi);
+ if (r = ReadByte(X, &tag)) return handle_return(r, X, tag, p);
+ if (tag != TAG_DUMPHEADER) return handle_return(0, X, tag, p);
+ r = parse_dumphdr(X, &tag, &top_fields[0], 0, &pi, (void *)p, 0);
+ if (!r && tag >= 1 && tag <= 4) r = DSERR_DONE;
+ return handle_return(r, X, tag, p);
+}
+
+
+afs_uint32 ParseVolumeHeader(XFILE *X, dump_parser *p)
+{
+ tag_parse_info pi;
+ unsigned char tag;
+ afs_uint32 r;
+
+ prep_pi(p, &pi);
+ if (r = ReadByte(X, &tag)) return handle_return(r, X, tag, p);
+ if (tag != TAG_VOLHEADER) return handle_return(0, X, tag, p);
+ r = parse_volhdr(X, &tag, &top_fields[1], 0, &pi, (void *)p, 0);
+ if (!r && tag >= 1 && tag <= 4) r = DSERR_DONE;
+ return handle_return(r, X, tag, p);
+}
+
+
+afs_uint32 ParseVNode(XFILE *X, dump_parser *p)
+{
+ tag_parse_info pi;
+ unsigned char tag;
+ afs_uint32 r;
+
+ prep_pi(p, &pi);
+ if (r = ReadByte(X, &tag)) return handle_return(r, X, tag, p);
+ if (tag != TAG_VNODE) return handle_return(0, X, tag, p);
+ r = parse_vnode(X, &tag, &top_fields[2], 0, &pi, (void *)p, 0);
+ if (!r && tag >= 1 && tag <= 4) r = DSERR_DONE;
+ return handle_return(r, X, tag, p);
+}
--- /dev/null
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/* parsetag.c - Parse a tagged data stream */
+
+#include "dumpscan.h"
+#include "dumpscan_errs.h"
+
+/* If a parser function is defined, it will be called after the data value
+ * (if any) is read. The parser is called as follows:
+ *
+ * parser(input_file, &tag, &field_rec, value, g_refcon, l_refcon);
+ *
+ * - input_file is the FILE * for the input stream
+ * - field_rec is a pointer to the field record for the field just read
+ * - g_refcon and l_refcon are as passed in to ParseTaggedData
+ * - For integer types, value is the integer value
+ * - For DKIND_STRING, tag is a pointer to the string just read
+ * - For DKIND_SPEACH, tag is a pointer to the place to put the next tag.
+ *
+ * If the field type is DKIND_SPECIAL, the parser is expected to read its
+ * own data from the input stream, and return when ParseTaggedData is supposed
+ * to take over, with the next tag to process in *tag. At no other time
+ * should the parser read, write, or reposition the input stream.
+ *
+ * The parser routine should return 0 on success, non-0 on failure. If the
+ * data type is DKIND_STRING, the parser may return DSERR_KEEP to indicate
+ * that the memory allocated for the value should not be freed.
+ */
+
+/* Parse a file containing tagged data and attributes **/
+afs_uint32 ParseTaggedData(XFILE *X, tagged_field *fields, unsigned char *tag,
+ tag_parse_info *pi, void *g_refcon, void *l_refcon)
+{
+ int i = -1;
+ afs_uint32 r, val;
+ afs_uint16 val16;
+ unsigned char val8;
+ unsigned char *strval;
+
+ for (;;) {
+ if (i < 0 || (fields[i].kind & DKIND_MASK) != DKIND_SPECIAL) {
+ /* Need to read in a tag */
+ if (r = ReadByte(X, tag)) return r;
+ }
+
+ /* Simple error recovery - if we encounter a 0, it can never be
+ * a valid tag. If TPFLAG_SKIP is set, we can skip over any
+ * such null bytes, and process whatever tag we find beyond.
+ * In addition, if TPFLAG_RSKIP is set, then the next time
+ * we encounter a 0, try skipping backwards. That seems to
+ * work much of the time.
+ */
+ if (!*tag && pi->shift_offset && (pi->flags & TPFLAG_RSKIP)) {
+ u_int64 where, tmp64a, tmp64b;
+ char buf1[21], buf2[21], buf3[21];
+ char *p1, *p2, *p3;
+
+ if (r = xftell(X, &tmp64a)) return r;
+ sub64_32(where, tmp64a, pi->shift_offset + 1);
+ if (r = xfseek(X, &where)) return r;
+ if (pi->cb_error){
+ (pi->cb_error)(DSERR_FMT, 0, pi->err_refcon,
+ "Inserted %d bytes before offset %d",
+ pi->shift_offset, decimate_int64(&where, 0));
+ add64_32(tmp64a, pi->shift_start, pi->shift_offset);
+ p1 = decimate_int64(&tmp64a, buf1);
+ sub64_64(tmp64b, where, tmp64a);
+ p2 = decimate_int64(&tmp64b, buf2);
+ p3 = decimate_int64(&pi->shift_start, buf3);
+ (pi->cb_error)(DSERR_FMT, 0, pi->err_refcon,
+ ">>> SHIFT start=%s length=%s target=%s",
+ p1, p2, p3);
+ }
+ pi->shift_offset = 0;
+ if (r = ReadByte(X, tag)) return r;
+ }
+ if (!*tag && (pi->flags & TPFLAG_SKIP)) {
+ int count = 0;
+ u_int64 where, tmp64a;
+
+ if (r = xftell(X, &where)) return r;
+
+ while (!*tag) {
+ if (r = ReadByte(X, tag)) return r;
+ count++;
+ }
+ pi->shift_offset += count;
+ cp64(pi->shift_start, where);
+ if (pi->cb_error) {
+ sub64_32(tmp64a, where, 1);
+ (pi->cb_error)(DSERR_FMT, 0, pi->err_refcon,
+ "Skipped %d bytes at offset %s",
+ count, decimate_int64(&tmp64a, 0));
+ }
+ }
+
+ for (i = 0; fields[i].tag && fields[i].tag != *tag; i++);
+ if (!fields[i].tag) return 0;
+
+ switch (fields[i].kind & DKIND_MASK) {
+ case DKIND_NOOP:
+ if (fields[i].func) {
+ r = (fields[i].func)(X, 0, fields+i, 0, pi, g_refcon, l_refcon);
+ if (r) return r;
+ }
+ break;
+
+ case DKIND_BYTE:
+ if (r = ReadByte(X, &val8)) return r;
+ if (fields[i].func) {
+ r = (fields[i].func)(X, 0, fields+i, val8, pi, g_refcon, l_refcon);
+ if (r) return r;
+ }
+ break;
+
+ case DKIND_INT16:
+ if (r = ReadInt16(X, &val16)) return r;
+ if (fields[i].func) {
+ r = (fields[i].func)(X, 0, fields+i, val16, pi, g_refcon, l_refcon);
+ if (r) return r;
+ }
+ break;
+
+ case DKIND_INT32:
+ if (r = ReadInt32(X, &val)) return r;
+ if (fields[i].func) {
+ r = (fields[i].func)(X, 0, fields+i, val, pi, g_refcon, l_refcon);
+ if (r) return r;
+ }
+ break;
+
+ case DKIND_STRING:
+ if (r = ReadString(X, &strval)) return r;
+ if (fields[i].func) {
+ r = (fields[i].func)(X, strval, fields+i, 0, pi, g_refcon, l_refcon);
+ if (r != DSERR_KEEP) free(strval);
+ if (r && r != DSERR_KEEP) return r;
+ } else free(strval);
+ break;
+
+ case DKIND_SPECIAL:
+ if (fields[i].func) {
+ r = (fields[i].func)(X, tag, fields+i, 0, pi, g_refcon, l_refcon);
+ if (r) return r;
+ } else i = -1;
+ }
+ }
+}
--- /dev/null
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/* parsevnode.c - Parse a VNode */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <errno.h>
+
+#include "dumpscan.h"
+#include "dumpscan_errs.h"
+#include "dumpfmt.h"
+#include "internal.h"
+
+#include <afs/acl.h>
+#include <afs/prs_fs.h>
+
+static afs_uint32 LastGoodVNode = 0;
+static afs_uint32 store_vnode(XFILE *, unsigned char *, tagged_field *, afs_uint32,
+ tag_parse_info *, void *, void *);
+static afs_uint32 parse_acl (XFILE *, unsigned char *, tagged_field *, afs_uint32,
+ tag_parse_info *, void *, void *);
+static afs_uint32 parse_vdata(XFILE *, unsigned char *, tagged_field *, afs_uint32,
+ tag_parse_info *, void *, void *);
+
+/** Field list for vnodes **/
+static tagged_field vnode_fields[] = {
+ { VTAG_TYPE, DKIND_BYTE, " VNode type: ", store_vnode, 0, 0 },
+ { VTAG_NLINKS, DKIND_INT16, " Link count: ", store_vnode, 0, 0 },
+ { VTAG_DVERS, DKIND_INT32, " Version: ", store_vnode, 0, 0 },
+ { VTAG_CLIENT_DATE, DKIND_TIME, " Server Date: ", store_vnode, 0, 0 },
+ { VTAG_AUTHOR, DKIND_INT32, " Author: ", store_vnode, 0, 0 },
+ { VTAG_OWNER, DKIND_INT32, " Owner: ", store_vnode, 0, 0 },
+ { VTAG_GROUP, DKIND_INT32, " Group: ", store_vnode, 0, 0 },
+ { VTAG_MODE, DKIND_INT16, " UNIX mode: ", store_vnode, 0, 0 },
+ { VTAG_PARENT, DKIND_INT32, " Parent: ", store_vnode, 0, 0 },
+ { VTAG_SERVER_DATE, DKIND_TIME, " Client Date: ", store_vnode, 0, 0 },
+ { VTAG_ACL, DKIND_SPECIAL, " xxxxxxxx ACL: ", parse_acl, 0, 0 },
+ { VTAG_DATA, DKIND_SPECIAL, " Contents: ", parse_vdata, 0, 0 },
+ { 0,0,0,0,0,0 }};
+
+
+static afs_uint32 resync_vnode(XFILE *X, dump_parser *p, afs_vnode *v,
+ int start, int limit)
+{
+ u_int64 where, expected_where;
+ afs_uint32 r;
+ int i;
+
+ if (r = xftell(X, &expected_where)) return r;
+ cp64(where, expected_where);
+
+ r = match_next_vnode(X, p, &where, v->vnode);
+ if (r && r != DSERR_FMT) return r;
+ if (r) for (i = -start; i < limit; i++) {
+ add64_32(where, expected_where, i);
+ r = match_next_vnode(X, p, &where, v->vnode);
+ if (!r) break;
+ if (r != DSERR_FMT) return r;
+ }
+ if (r) {
+ if (p->cb_error)
+ (p->cb_error)(r, 1, p->err_refcon,
+ "Unable to resync after vnode %d [%s = 0x%s]",
+ v->vnode, decimate_int64(&expected_where, 0),
+ hexify_int64(&expected_where, 0));
+ return r;
+ }
+ if (ne64(where, expected_where) && p->cb_error) {
+ (p->cb_error)(DSERR_FMT, 0, p->err_refcon,
+ "Vnode after %d not in expected location",
+ v->vnode);
+ (p->cb_error)(DSERR_FMT, 0, p->err_refcon, "Expected location: %s = 0x%s",
+ decimate_int64(&expected_where, 0),
+ hexify_int64(&expected_where, 0));
+ (p->cb_error)(DSERR_FMT, 0, p->err_refcon, "Actual location: %s = 0x%s",
+ decimate_int64(&where, 0), hexify_int64(&where, 0));
+ }
+ return xfseek(X, &where);
+}
+
+
+/* Parse a VNode, including any tagged attributes and data, and call the
+ * appropriate callback, if one is defined.
+ */
+afs_uint32 parse_vnode(XFILE *X, unsigned char *tag, tagged_field *field,
+ afs_uint32 value, tag_parse_info *pi,
+ void *g_refcon, void *l_refcon)
+{
+ dump_parser *p = (dump_parser *)g_refcon;
+ afs_uint32 (*cb)(afs_vnode *, XFILE *, void *);
+ u_int64 where, offset2k;
+ afs_vnode v;
+ afs_uint32 r;
+
+
+ if (r = xftell(X, &where)) return r;
+ memset(&v, 0, sizeof(v));
+ sub64_32(v.offset, where, 1);
+ if (r = ReadInt32(X, &v.vnode)) return r;
+ if (r = ReadInt32(X, &v.vuniq)) return r;
+
+ mk64(offset2k, 0, 2048);
+ if (!LastGoodVNode
+ || ((p->flags & DSFLAG_SEEK) && v.vnode == 1
+ && lt64(v.offset, offset2k)))
+ LastGoodVNode = -1;
+
+ if (p->print_flags & DSPRINT_ITEM) {
+ printf("%s %d/%d [%s = 0x%s]\n", field->label, v.vnode, v.vuniq,
+ decimate_int64(&where, 0), hexify_int64(&where, 0));
+ }
+
+ r = ParseTaggedData(X, vnode_fields, tag, pi, g_refcon, (void *)&v);
+
+ /* Try to resync, if requested */
+ if (!r && (p->repair_flags & DSFIX_VFSYNC)) {
+ afs_uint32 drop;
+ u_int64 xwhere;
+
+ if (r = xftell(X, &where)) return r;
+ sub64_32(xwhere, where, 1);
+
+ /* Are we at the start of a valid vnode (or dump end)? */
+ r = match_next_vnode(X, p, &xwhere, v.vnode);
+ if (r && r != DSERR_FMT) return r;
+ if (r) { /* Nope. */
+ /* Was _this_ a valid vnode? If so, we can keep it and search for
+ * the next one. Otherwise, we throw it out, and start the search
+ * at the starting point of this vnode.
+ */
+ drop = r = match_next_vnode(X, p, &v.offset, LastGoodVNode);
+ if (r && r != DSERR_FMT) return r;
+ if (!r) {
+ add64_32(where, v.offset, 1);
+ if (r = xfseek(X, &v.offset)) return r;
+ } else {
+ if (r = xfseek(X, &xwhere)) return r;
+ }
+ if (r = resync_vnode(X, p, &v, 0, 1024)) return r;
+ if (r = ReadByte(X, tag)) return r;
+ if (drop) {
+ if (p->cb_error)
+ (p->cb_error)(DSERR_FMT, 0, p->err_refcon,
+ "Dropping vnode %d", v.vnode);
+ return 0;
+ }
+ } else {
+ if (r = xfseek(X, &where)) return r;
+ }
+ }
+ LastGoodVNode = v.vnode;
+
+ if (!r) {
+ if (v.field_mask & F_VNODE_TYPE)
+ switch (v.type) {
+ case vFile: cb = p->cb_vnode_file; break;
+ case vDirectory: cb = p->cb_vnode_dir; break;
+ case vSymlink: cb = p->cb_vnode_link; break;
+ default: cb = p->cb_vnode_wierd; break;
+ }
+ else cb = p->cb_vnode_empty;
+ if (cb) {
+ u_int64 where;
+
+ if (r = xftell(X, &where)) return r;
+ r = (cb)(&v, X, p->refcon);
+ if (p->flags & DSFLAG_SEEK) {
+ if (!r) r = xfseek(X, &where);
+ else xfseek(X, &where);
+ }
+ }
+ }
+ return r;
+}
+
+
+/* Store data in a vnode */
+static afs_uint32 store_vnode(XFILE *X, unsigned char *tag, tagged_field *field,
+ afs_uint32 value, tag_parse_info *pi,
+ void *g_refcon, void *l_refcon)
+{
+ dump_parser *p = (dump_parser *)g_refcon;
+ afs_vnode *v = (afs_vnode *)l_refcon;
+ time_t when;
+ afs_uint32 r = 0;
+
+ switch (field->tag) {
+ case VTAG_TYPE:
+ v->field_mask |= F_VNODE_TYPE;
+ v->type = value;
+ if (p->print_flags & DSPRINT_VNODE) {
+ switch (value) {
+ case vFile:
+ printf("%sFile (%d)\n", field->label, value);
+ break;
+ case vDirectory:
+ printf("%sDirectory (%d)\n", field->label, value);
+ break;
+ case vSymlink:
+ printf("%sSymbolic Link (%d)\n", field->label, value);
+ break;
+ default:
+ printf("%s??? (%d)\n", field->label, value);
+ }
+ return r;
+ }
+ break;
+
+ case VTAG_NLINKS:
+ v->field_mask |= F_VNODE_NLINKS;
+ v->nlinks = value;
+ break;
+
+ case VTAG_DVERS:
+ v->field_mask |= F_VNODE_DVERS;
+ v->datavers = value;
+ break;
+
+ case VTAG_CLIENT_DATE:
+ v->field_mask |= F_VNODE_CDATE;
+ v->client_date = value;
+ break;
+
+ case VTAG_SERVER_DATE:
+ v->field_mask |= F_VNODE_SDATE;
+ v->server_date = value;
+ break;
+
+ case VTAG_AUTHOR:
+ v->field_mask |= F_VNODE_AUTHOR;
+ v->author = value;
+ break;
+
+ case VTAG_OWNER:
+ v->field_mask |= F_VNODE_OWNER;
+ v->owner = value;
+ break;
+
+ case VTAG_GROUP:
+ v->field_mask |= F_VNODE_GROUP;
+ v->group = value;
+ break;
+
+ case VTAG_MODE:
+ v->field_mask |= F_VNODE_MODE;
+ v->mode = value;
+ break;
+
+ case VTAG_PARENT:
+ v->field_mask |= F_VNODE_PARENT;
+ v->parent = value;
+ break;
+ }
+
+ if (p->print_flags & DSPRINT_VNODE)
+ switch (field->kind) {
+ case DKIND_BYTE:
+ case DKIND_INT16:
+ case DKIND_INT32: printf("%s%d\n", field->label, value); break;
+ case DKIND_HEX8: printf("%s0x%02x\n", field->label, value); break;
+ case DKIND_HEX16: printf("%s0x%04x\n", field->label, value); break;
+ case DKIND_HEX32: printf("%s0x%08x\n", field->label, value); break;
+ case DKIND_CHAR: printf("%s%c\n", field->label, value); break;
+ case DKIND_STRING: printf("%s%s\n", field->label, tag); break;
+ case DKIND_FLAG:
+ printf("%s%s\n", field->label, value ? "true" : "false");
+ break;
+ case DKIND_TIME:
+ when = value;
+ printf("%s%s", field->label, ctime(&when));
+ break;
+ }
+ return r;
+}
+
+
+static char *rights2str(afs_uint32 rights)
+{
+ static char str[16];
+ char *p = str;
+
+ if (rights & PRSFS_READ) *p++ = 'r';
+ if (rights & PRSFS_LOOKUP) *p++ = 'l';
+ if (rights & PRSFS_INSERT) *p++ = 'i';
+ if (rights & PRSFS_DELETE) *p++ = 'd';
+ if (rights & PRSFS_WRITE) *p++ = 'w';
+ if (rights & PRSFS_LOCK) *p++ = 'k';
+ if (rights & PRSFS_ADMINISTER) *p++ = 'a';
+ if (rights & PRSFS_USR0) *p++ = 'A';
+ if (rights & PRSFS_USR1) *p++ = 'B';
+ if (rights & PRSFS_USR2) *p++ = 'C';
+ if (rights & PRSFS_USR3) *p++ = 'D';
+ if (rights & PRSFS_USR4) *p++ = 'E';
+ if (rights & PRSFS_USR5) *p++ = 'F';
+ if (rights & PRSFS_USR6) *p++ = 'G';
+ if (rights & PRSFS_USR7) *p++ = 'H';
+
+ *p = 0;
+ if (!str[0]) strcpy(str, "none");
+ return str;
+}
+
+
+/* Parse and store the ACL data from a directory vnode */
+static afs_uint32 parse_acl(XFILE *X, unsigned char *tag, tagged_field *field,
+ afs_uint32 value, tag_parse_info *pi,
+ void *g_refcon, void *l_refcon)
+{
+ struct acl_accessList *acl;
+ dump_parser *p = (dump_parser *)g_refcon;
+ afs_vnode *v = (afs_vnode *)l_refcon;
+ afs_uint32 r, i, n;
+
+ if (r = xfread(X, v->acl, SIZEOF_LARGEDISKVNODE - SIZEOF_SMALLDISKVNODE))
+ return r;
+
+ v->field_mask |= F_VNODE_ACL;
+ if (p->print_flags & DSPRINT_ACL) {
+ acl = (struct acl_accessList *)(v->acl);
+ n = ntohl(acl->positive);
+ if (n) {
+ printf("Positive ACL: %d entries\n", n);
+ for (i = 0; i < n; i++)
+ printf(" %9d %s\n",
+ ntohl(acl->entries[i].id),
+ rights2str(acl->entries[i].rights));
+ }
+ n = ntohl(acl->negative);
+ if (n) {
+ printf("Positive ACL: %d entries\n", n);
+ for (i = ntohl(acl->positive); i < ntohl(acl->total); i++)
+ printf(" %9d %s\n",
+ ntohl(acl->entries[i].id),
+ rights2str(acl->entries[i].rights));
+ }
+ }
+ return ReadByte(X, tag);
+}
+
+
+/* Parse or skip over the vnode data */
+static afs_uint32 parse_vdata(XFILE *X, unsigned char *tag, tagged_field *field,
+ afs_uint32 value, tag_parse_info *pi,
+ void *g_refcon, void *l_refcon)
+{
+ dump_parser *p = (dump_parser *)g_refcon;
+ afs_vnode *v = (afs_vnode *)l_refcon;
+ static char *symlink_buf = 0;
+ static int symlink_size = 0;
+ afs_uint32 r;
+
+ if (r = ReadInt32(X, &v->size)) return r;
+ v->field_mask |= F_VNODE_SIZE;
+
+ if (v->size) {
+ v->field_mask |= F_VNODE_DATA;
+ if (r = xftell(X, &v->d_offset)) return r;
+ if (p->print_flags & DSPRINT_VNODE)
+ printf("%s%d (0x%08x) bytes at %s (0x%s)\n", field->label,
+ v->size, v->size, decimate_int64(&v->d_offset, 0),
+ hexify_int64(&v->d_offset, 0));
+
+ switch (v->type) {
+ case vSymlink:
+ if (v->size > symlink_size) {
+ if (symlink_buf) symlink_buf = (char *)realloc(symlink_buf, v->size + 1);
+ else symlink_buf = (char *)malloc(v->size + 1);
+ symlink_size = symlink_buf ? v->size : 0;
+ }
+ if (symlink_buf) {
+ if (r = xfread(X, symlink_buf, v->size)) return r;
+ symlink_buf[v->size] = 0;
+ if (p->print_flags & DSPRINT_VNODE)
+ printf("Target: %s\n", symlink_buf);
+ } else {
+ /* Call the callback here, because it's non-fatal */
+ if (p->cb_error)
+ (p->cb_error)(ENOMEM, 0, p->err_refcon,
+ "Out of memory reading symlink");
+ if (r = xfskip(X, v->size)) return r;
+ }
+ break;
+
+ case vDirectory:
+ if (p->cb_dirent || (p->print_flags & DSPRINT_DIR)) {
+ if (r = parse_directory(X, p, v, v->size, 0)) return r;
+ break;
+ }
+
+ default:
+ if (r = xfskip(X, v->size)) return r;
+ }
+ } else if (p->print_flags & DSPRINT_VNODE) {
+ printf("%sEmpty\n", field->label);
+ }
+ if (p->repair_flags & DSFIX_VDSYNC) {
+ r = resync_vnode(X, p, v, 10, 15);
+ if (r) return r;
+ }
+ return ReadByte(X, tag);
+}
--- /dev/null
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/* parsevol.c - Parse a volume header */
+
+#include "dumpscan.h"
+#include "dumpscan_errs.h"
+#include "dumpfmt.h"
+
+static afs_uint32 store_volhdr (XFILE *, unsigned char *, tagged_field *,
+ afs_uint32, tag_parse_info *, void *, void *);
+static afs_uint32 parse_weekuse (XFILE *, unsigned char *, tagged_field *,
+ afs_uint32, tag_parse_info *, void *, void *);
+
+/** Field list for volume headers **/
+static tagged_field volhdr_fields[] = {
+ { VHTAG_VOLID, DKIND_INT32, " Volume ID: ", store_volhdr, 0, 0 },
+ { VHTAG_VERS, DKIND_INT32, " Version: ", store_volhdr, 0, 0 },
+ { VHTAG_VOLNAME, DKIND_STRING, " Volume name: ", store_volhdr, 0, 0 },
+ { VHTAG_INSERV, DKIND_FLAG, " In service? ", store_volhdr, 0, 0 },
+ { VHTAG_BLESSED, DKIND_FLAG, " Blessed? ", store_volhdr, 0, 0 },
+ { VHTAG_VUNIQ, DKIND_INT32, " Uniquifier: ", store_volhdr, 0, 0 },
+ { VHTAG_TYPE, DKIND_BYTE, " Type: ", store_volhdr, 0, 0 },
+ { VHTAG_PARENT, DKIND_INT32, " Parent ID: ", store_volhdr, 0, 0 },
+ { VHTAG_CLONE, DKIND_INT32, " Clone ID: ", store_volhdr, 0, 0 },
+ { VHTAG_MAXQUOTA, DKIND_INT32, " Max quota: ", store_volhdr, 0, 0 },
+ { VHTAG_MINQUOTA, DKIND_INT32, " Min quota: ", store_volhdr, 0, 0 },
+ { VHTAG_DISKUSED, DKIND_INT32, " Disk used: ", store_volhdr, 0, 0 },
+ { VHTAG_FILECNT, DKIND_INT32, " File count: ", store_volhdr, 0, 0 },
+ { VHTAG_ACCOUNT, DKIND_INT32, " Account: ", store_volhdr, 0, 0 },
+ { VHTAG_OWNER, DKIND_INT32, " Owner: ", store_volhdr, 0, 0 },
+ { VHTAG_CREAT, DKIND_TIME, " Created: ", store_volhdr, 0, 0 },
+ { VHTAG_ACCESS, DKIND_TIME, " Accessed: ", store_volhdr, 0, 0 },
+ { VHTAG_UPDATE, DKIND_TIME, " Updated: ", store_volhdr, 0, 0 },
+ { VHTAG_EXPIRE, DKIND_TIME, " Expires: ", store_volhdr, 0, 0 },
+ { VHTAG_BACKUP, DKIND_TIME, " Backed up: ", store_volhdr, 0, 0 },
+ { VHTAG_OFFLINE, DKIND_STRING, " Offine Msg: ", store_volhdr, 0, 0 },
+ { VHTAG_MOTD, DKIND_STRING, " MOTD: ", store_volhdr, 0, 0 },
+ { VHTAG_WEEKUSE, DKIND_SPECIAL, " Weekuse: ", parse_weekuse, 0, 0 },
+ { VHTAG_DUDATE, DKIND_TIME, " Dayuse Date: ", store_volhdr, 0, 0 },
+ { VHTAG_DAYUSE, DKIND_INT32, " Daily usage: ", store_volhdr, 0, 0 },
+ { 0,0,0,0,0,0 }};
+
+
+/* Parse a volume header, including any tagged attributes, and call the
+ * volume-header callback, if one is defined.
+ */
+afs_uint32 parse_volhdr(XFILE *X, unsigned char *tag, tagged_field *field,
+ afs_uint32 value, tag_parse_info *pi,
+ void *g_refcon, void *l_refcon)
+{
+ dump_parser *p = (dump_parser *)g_refcon;
+ afs_vol_header hdr;
+ u_int64 where;
+ afs_uint32 r;
+
+ memset(&hdr, 0, sizeof(hdr));
+ if (r = xftell(X, &where)) return r;
+ sub64_32(hdr.offset, where, 1);
+ if (p->print_flags & DSPRINT_VOLHDR)
+ printf("%s [%s = 0x%s]\n", field->label,
+ decimate_int64(&hdr.offset, 0), hexify_int64(&hdr.offset, 0));
+
+ r = ParseTaggedData(X, volhdr_fields, tag, pi, g_refcon, (void *)&hdr);
+
+ if (!r && p->cb_volhdr) {
+ if (r = xftell(X, &where)) return r;
+ r = (p->cb_volhdr)(&hdr, X, p->refcon);
+ if (p->flags & DSFLAG_SEEK) {
+ if (!r) r = xfseek(X, &where);
+ else xfseek(X, &where);
+ }
+ }
+ if (hdr.field_mask & F_VOLHDR_VOLUNIQ)
+ p->vol_uniquifier = hdr.voluniq;
+ if (hdr.field_mask & F_VOLHDR_VOLNAME)
+ free(hdr.volname);
+ if (hdr.field_mask & F_VOLHDR_OFFLINE_MSG)
+ free(hdr.offline_msg);
+ if (hdr.field_mask & F_VOLHDR_MOTD)
+ free(hdr.motd_msg);
+ return r;
+}
+
+
+/* Store data in a volume header */
+static afs_uint32 store_volhdr(XFILE *X, unsigned char *tag, tagged_field *field,
+ afs_uint32 value, tag_parse_info *pi,
+ void *g_refcon, void *l_refcon)
+{
+ dump_parser *p = (dump_parser *)g_refcon;
+ afs_vol_header *hdr = (afs_vol_header *)l_refcon;
+ time_t when;
+ afs_uint32 r = 0;
+
+ switch (field->tag) {
+ case VHTAG_VOLID:
+ hdr->field_mask |= F_VOLHDR_VOLID;
+ hdr->volid = value;
+ break;
+
+ case VHTAG_VERS:
+ hdr->field_mask |= F_VOLHDR_VOLVERS;
+ hdr->volvers = value;
+ break;
+
+ case VHTAG_VOLNAME:
+ if (tag && tag[0]) {
+ hdr->field_mask |= F_VOLHDR_VOLNAME;
+ hdr->volname = tag;
+ r = DSERR_KEEP;
+ }
+ break;
+
+ case VHTAG_INSERV:
+ hdr->field_mask |= F_VOLHDR_INSERV;
+ hdr->flag_inservice = value;
+ break;
+
+ case VHTAG_BLESSED:
+ hdr->field_mask |= F_VOLHDR_BLESSED;
+ hdr->flag_blessed = value;
+ break;
+
+ case VHTAG_VUNIQ:
+ hdr->field_mask |= F_VOLHDR_VOLUNIQ;
+ hdr->voluniq = value;
+ break;
+
+ case VHTAG_TYPE:
+ hdr->field_mask |= F_VOLHDR_VOLTYPE;
+ hdr->voltype = value;
+ break;
+
+ case VHTAG_PARENT:
+ hdr->field_mask |= F_VOLHDR_PARENT;
+ hdr->parent_volid = value;
+ break;
+
+ case VHTAG_CLONE:
+ hdr->field_mask |= F_VOLHDR_CLONE;
+ hdr->clone_volid = value;
+ break;
+
+ case VHTAG_MAXQUOTA:
+ hdr->field_mask |= F_VOLHDR_MAXQ;
+ hdr->maxquota = value;
+ break;
+
+ case VHTAG_MINQUOTA:
+ hdr->field_mask |= F_VOLHDR_MINQ;
+ hdr->minquota = value;
+ break;
+
+ case VHTAG_DISKUSED:
+ hdr->field_mask |= F_VOLHDR_DISKUSED;
+ hdr->diskused = value;
+ break;
+
+ case VHTAG_FILECNT:
+ hdr->field_mask |= F_VOLHDR_NFILES;
+ hdr->nfiles = value;
+ break;
+
+ case VHTAG_ACCOUNT:
+ hdr->field_mask |= F_VOLHDR_ACCOUNT;
+ hdr->account_no = value;
+ break;
+
+ case VHTAG_OWNER:
+ hdr->field_mask |= F_VOLHDR_OWNER;
+ hdr->owner = value;
+ break;
+
+ case VHTAG_CREAT:
+ hdr->field_mask |= F_VOLHDR_CREATE_DATE;
+ hdr->create_date = value;
+ break;
+
+ case VHTAG_ACCESS:
+ hdr->field_mask |= F_VOLHDR_ACCESS_DATE;
+ hdr->access_date = value;
+ break;
+
+ case VHTAG_UPDATE:
+ hdr->field_mask |= F_VOLHDR_UPDATE_DATE;
+ hdr->update_date = value;
+ break;
+
+ case VHTAG_EXPIRE:
+ hdr->field_mask |= F_VOLHDR_EXPIRE_DATE;
+ hdr->expire_date = value;
+ break;
+
+ case VHTAG_BACKUP:
+ hdr->field_mask |= F_VOLHDR_BACKUP_DATE;
+ hdr->backup_date = value;
+ break;
+
+ case VHTAG_OFFLINE:
+ if (tag && tag[0]) {
+ hdr->field_mask |= F_VOLHDR_OFFLINE_MSG;
+ hdr->offline_msg = tag;
+ r = DSERR_KEEP;
+ }
+ break;
+
+ case VHTAG_MOTD:
+ if (tag && tag[0]) {
+ hdr->field_mask |= F_VOLHDR_MOTD;
+ hdr->motd_msg = tag;
+ r = DSERR_KEEP;
+ }
+ break;
+
+ case VHTAG_DUDATE:
+ hdr->field_mask |= F_VOLHDR_DAYUSE_DATE;
+ hdr->dayuse_date = value;
+ break;
+
+ case VHTAG_DAYUSE:
+ hdr->field_mask |= F_VOLHDR_DAYUSE;
+ hdr->dayuse = value;
+ break;
+ }
+
+ if (p->print_flags & DSPRINT_VOLHDR)
+ switch (field->kind) {
+ case DKIND_BYTE:
+ case DKIND_INT16:
+ case DKIND_INT32: printf("%s%d\n", field->label, value); break;
+ case DKIND_HEX8: printf("%s0x%02x\n", field->label, value); break;
+ case DKIND_HEX16: printf("%s0x%04x\n", field->label, value); break;
+ case DKIND_HEX32: printf("%s0x%08x\n", field->label, value); break;
+ case DKIND_CHAR: printf("%s%c\n", field->label, value); break;
+ case DKIND_STRING: printf("%s%s\n", field->label, tag); break;
+ case DKIND_FLAG:
+ printf("%s%s\n", field->label, value ? "true" : "false");
+ break;
+ case DKIND_TIME:
+ when = value;
+ printf("%s%s", field->label, ctime(&when));
+ break;
+ }
+ return r;
+}
+
+
+/* Parse and store the week use data from a volume header */
+static afs_uint32 parse_weekuse(XFILE *X, unsigned char *tag, tagged_field *field,
+ afs_uint32 value, tag_parse_info *pi,
+ void *g_refcon, void *l_refcon)
+{
+ dump_parser *p = (dump_parser *)g_refcon;
+ afs_vol_header *hdr = (afs_vol_header *)l_refcon;
+ afs_uint16 count;
+ afs_uint32 r;
+ unsigned int i;
+
+ if (r = ReadInt16(X, &count)) return r;
+ if (count != 7) {
+ if (p->cb_error)
+ (p->cb_error)(DSERR_FMT, 1, p->err_refcon,
+ "Incorrect array count (%d) in weekuse data", count);
+ return DSERR_FMT;
+ }
+ for (i = 0; i < count; i++)
+ if (r = ReadInt32(X, hdr->weekuse + i)) return r;
+ hdr->field_mask |= F_VOLHDR_WEEKUSE;
+ if (p->print_flags & DSPRINT_VOLHDR) {
+ printf("%s%10d %10d %10d %10d\n", field->label,
+ hdr->weekuse[0], hdr->weekuse[1], hdr->weekuse[2], hdr->weekuse[3]);
+ printf("%s%10d %10d %10d\n", field->label,
+ hdr->weekuse[4], hdr->weekuse[5], hdr->weekuse[6]);
+ }
+ return ReadByte(X, tag);
+}
--- /dev/null
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/* pathname.c - Pathname lookup and traversal */
+
+#include <errno.h>
+#include <string.h>
+
+#include "dumpscan.h"
+#include "dumpscan_errs.h"
+
+/* Hash function for a vnode */
+#define BUCKET_SIZE 32
+#define vnode_hash(phi,vnode) ((vnode) & ((1 << (phi)->hash_size) - 1))
+
+
+static vhash_ent *get_vhash_ent(path_hashinfo *phi, afs_uint32 vnode, int make)
+{
+ int key = vnode_hash(phi, vnode);
+ vhash_ent *vhe;
+
+ for (vhe = phi->hash_table[key];
+ vhe && vhe->vnode != vnode;
+ vhe = vhe->next);
+ if (make && !vhe) {
+ vhe = (vhash_ent *)malloc(sizeof(vhash_ent));
+ if (vhe) {
+ memset(vhe, 0, sizeof(vhash_ent));
+ vhe->vnode = vnode;
+ vhe->next = phi->hash_table[key];
+ phi->hash_table[key] = vhe;
+ }
+ }
+ return vhe;
+}
+
+
+static afs_uint32 volhdr_cb(afs_vol_header *hdr, XFILE *X, void *refcon)
+{
+ path_hashinfo *phi = (path_hashinfo *)refcon;
+ int nfiles, hsize;
+
+ if (hdr->field_mask & F_VOLHDR_NFILES) {
+ nfiles = phi->n_vnodes = hdr->nfiles;
+ for (phi->hash_size = 1;
+ nfiles > BUCKET_SIZE;
+ phi->hash_size++, nfiles >>= 1);
+ hsize = (1 << phi->hash_size);
+ phi->hash_table = (vhash_ent **)malloc(hsize * sizeof(vhash_ent *));
+ if (!phi->hash_table) return ENOMEM;
+ memset(phi->hash_table, 0, hsize * sizeof(vhash_ent *));
+ return 0;
+ } else {
+ if (phi->p->cb_error)
+ (phi->p->cb_error)(DSERR_FMT, 1, phi->p->err_refcon,
+ "File count missing from volume header");
+ return DSERR_FMT;
+ }
+}
+
+
+static afs_uint32 vnode_keep(afs_vnode *v, XFILE *X, void *refcon)
+{
+ path_hashinfo *phi = (path_hashinfo *)refcon;
+ vhash_ent *vhe;
+
+ if (!phi->hash_table) {
+ if (phi->p->cb_error)
+ (phi->p->cb_error)(DSERR_FMT, 1, phi->p->refcon,
+ "No volume header in dump???");
+ return DSERR_FMT;
+ }
+ vhe = get_vhash_ent(phi, v->vnode, 1);
+ if (!vhe) return ENOMEM;
+ cp64(vhe->v_offset, v->offset);
+ if (v->field_mask & F_VNODE_PARENT)
+ vhe->parent = v->parent;
+ if (v->field_mask & F_VNODE_DATA) {
+ cp64(vhe->d_offset, v->d_offset);
+ vhe->d_size = v->size;
+ }
+ if ((v->field_mask & F_VNODE_TYPE) && v->type == vDirectory)
+ phi->n_dirs++;
+ else
+ phi->n_files++;
+ return 0;
+}
+
+
+static afs_uint32 vnode_stop(afs_vnode *v, XFILE *X, void *refcon)
+{
+ path_hashinfo *phi = (path_hashinfo *)refcon;
+ int r;
+
+ /* If the file is seekable, try to position so we can pick up later... */
+ if (phi->p->flags && DSFLAG_SEEK)
+ if (r = xfseek(X, &v->offset)) return r;
+ return DSERR_DONE;
+}
+
+
+static afs_uint32 dirent_cb(afs_vnode *v, afs_dir_entry *de,
+ XFILE *X, void *refcon)
+{
+ path_hashinfo *phi = (path_hashinfo *)refcon;
+ vhash_ent *vhe;
+
+ if (!phi->hash_table) {
+ if (phi->p->cb_error)
+ (phi->p->cb_error)(DSERR_FMT, 1, phi->p->refcon,
+ "No volume header in dump???");
+ return DSERR_FMT;
+ }
+ if (!strcmp(de->name, ".") || !strcmp(de->name, "..")) return 0;
+ vhe = get_vhash_ent(phi, de->vnode, 1);
+ if (!vhe) return ENOMEM;
+ vhe->parent = v->vnode;
+ return 0;
+}
+
+
+/* Prescan the vnodes in a dump file, collecting information that will
+ * be useful in generating and following pathnames.
+ */
+afs_uint32 Path_PreScan(XFILE *X, path_hashinfo *phi, int full)
+{
+ dump_parser my_p, *p = phi->p;
+ int r;
+
+ memset(phi, 0, sizeof(path_hashinfo));
+ phi->p = p;
+ memset(&my_p, 0, sizeof(my_p));
+ my_p.refcon = (void *)phi;
+ my_p.cb_volhdr = volhdr_cb;
+ my_p.cb_vnode_dir = vnode_keep;
+ if (full) {
+ my_p.cb_vnode_file = vnode_keep;
+ my_p.cb_vnode_link = vnode_keep;
+ my_p.cb_vnode_empty = vnode_keep;
+ my_p.cb_vnode_wierd = vnode_keep;
+ } else {
+ my_p.cb_vnode_file = vnode_stop;
+ my_p.cb_vnode_link = vnode_stop;
+ my_p.cb_vnode_empty = vnode_stop;
+ my_p.cb_vnode_wierd = vnode_stop;
+ }
+ my_p.err_refcon = p->err_refcon;
+ my_p.cb_error = p->cb_error;
+ my_p.cb_dirent = dirent_cb;
+ my_p.flags = p->flags;
+ my_p.print_flags = p->print_flags;
+ my_p.repair_flags = p->repair_flags;
+
+ return ParseDumpFile(X, &my_p);
+}
+
+
+/* Free the hash table in a path_hashinfo */
+void Path_FreeHashTable(path_hashinfo *phi)
+{
+ int i, size;
+ vhash_ent *vhe, *next_vhe;
+
+ if (phi->hash_table) {
+ size = (1 << phi->hash_size);
+ for (i = 0; i < size; i++)
+ for (vhe = phi->hash_table[i]; vhe; vhe = next_vhe) {
+ next_vhe = vhe->next;
+ free(vhe);
+ }
+ free(phi->hash_table);
+ }
+}
+
+
+/* Follow a pathname to the vnode it represents */
+afs_uint32 Path_Follow(XFILE *X, path_hashinfo *phi,
+ char *path, vhash_ent *his_vhe)
+{
+ vhash_ent *vhe;
+ char *name;
+ afs_uint32 r, vnum = 1;
+
+ if (*path == '/') path++;
+ name = strtok(path, "/");
+
+ for (name = strtok(path, "/"); name; name = strtok(0, "/")) {
+ if (!(vnum & 1)) {
+ if (phi->p->cb_error)
+ (phi->p->cb_error)(ENOTDIR, 1, phi->p->err_refcon,
+ "Not a directory vnode");
+ return ENOTDIR;
+ }
+ vhe = get_vhash_ent(phi, vnum, 0);
+ if (!vhe) {
+ if (phi->p->cb_error)
+ (phi->p->cb_error)(DSERR_FMT, 1, phi->p->err_refcon,
+ "Vnode %d not found in hash table", vnum);
+ return DSERR_FMT;
+ }
+ if (zero64(vhe->d_offset)) {
+ if (phi->p->cb_error)
+ (phi->p->cb_error)(DSERR_FMT, 1, phi->p->err_refcon,
+ "Directory vnode %d is incomplete", vnum);
+ return DSERR_FMT;
+ }
+ if (r = xfseek(X, &vhe->d_offset)) {
+ if (phi->p->cb_error)
+ (phi->p->cb_error)(r, 1, phi->p->err_refcon,
+ "Unable to seek to directory %d", vnum);
+ return r;
+ }
+ vnum = 0;
+ r = DirectoryLookup(X, phi->p, vhe->d_size, &name, &vnum, 0);
+ if (r) return r;
+ if (!vnum) {
+ if (phi->p->cb_error)
+ (phi->p->cb_error)(ENOENT, 1, phi->p->err_refcon,
+ "No such vnode");
+ return ENOENT;
+ }
+ }
+ vhe = get_vhash_ent(phi, vnum, 0);
+ if (!vhe) {
+ if (phi->p->cb_error)
+ (phi->p->cb_error)(DSERR_FMT, 1, phi->p->err_refcon,
+ "Vnode %d not found in hash table", vnum);
+ return DSERR_FMT;
+ }
+ if (his_vhe) *his_vhe = *vhe;
+ return 0;
+}
+
+
+afs_uint32 Path_Build(XFILE *X, path_hashinfo *phi, afs_uint32 vnode,
+ char **his_path, int fast)
+{
+ vhash_ent *vhe;
+ char *name, *path = 0, fastbuf[12];
+ char *x, *y;
+ afs_uint32 parent, r;
+ int nl, pl = 0;
+
+ if (vnode == 1) {
+ *his_path = (char *)malloc(2);
+ if (!his_path) {
+ if (phi->p->cb_error)
+ (phi->p->cb_error)(ENOMEM, 1, phi->p->err_refcon,
+ "No memory for pathname of vnode 1");
+ return ENOMEM;
+ }
+ strcpy(*his_path, "/");
+ return 0;
+ }
+
+ *his_path = 0;
+ vhe = get_vhash_ent(phi, vnode, 0);
+ if (!vhe) {
+ if (phi->p->cb_error)
+ (phi->p->cb_error)(DSERR_FMT, 1, phi->p->err_refcon,
+ "Vnode %d not found in hash table", vnode);
+ return DSERR_FMT;
+ }
+ while (vnode != 1) {
+ /* Find the parent */
+ if (!vhe->parent) {
+ if (phi->p->cb_error)
+ (phi->p->cb_error)(DSERR_FMT, 1, phi->p->err_refcon,
+ "Vnode %d has no parent?", vnode);
+ if (path) free(path);
+ return DSERR_FMT;
+ }
+ parent = vhe->parent;
+ vhe = get_vhash_ent(phi, parent, 0);
+ if (phi->p->print_flags & DSPRINT_DEBUG)
+ fprintf(stderr, "Searching for vnode %d in parent %d\n", vnode, parent);
+ if (!vhe) {
+ if (phi->p->cb_error)
+ (phi->p->cb_error)(DSERR_FMT, 1, phi->p->err_refcon,
+ "Vnode %d not found in hash table", parent);
+ if (path) free(path);
+ return DSERR_FMT;
+ }
+
+ if (fast) {
+ /* Make up a path component from the vnode number */
+ sprintf(fastbuf, "%d", vnode);
+ name = fastbuf;
+ } else {
+ /* Do a reverse-lookup in the parent directory */
+ if (zero64(vhe->d_offset)) {
+ if (phi->p->cb_error)
+ (phi->p->cb_error)(DSERR_FMT, 1, phi->p->err_refcon,
+ "Directory vnode %d is incomplete", parent);
+ if (path) free(path);
+ return DSERR_FMT;
+ }
+ if (r = xfseek(X, &vhe->d_offset)) {
+ if (phi->p->cb_error)
+ (phi->p->cb_error)(errno, 1, phi->p->err_refcon,
+ "Unable to seek to directory %d", parent);
+ if (path) free(path);
+ return r;
+ }
+
+ name = 0;
+ r = DirectoryLookup(X, phi->p, vhe->d_size, &name, &vnode, 0);
+ if (r) return r;
+ if (!name) {
+ if (phi->p->cb_error)
+ (phi->p->cb_error)(DSERR_FMT, 1, phi->p->err_refcon,
+ "No entry for vnode %d in directory %d",
+ vnode, parent);
+ if (path) free(path);
+ return ENOENT;
+ }
+ }
+
+ nl = strlen(name);
+ if (path) {
+ path = (char *)realloc(path, nl + pl + 2);
+ if (!path) {
+ if (phi->p->cb_error)
+ (phi->p->cb_error)(ENOMEM, 1, phi->p->err_refcon,
+ "No memory for pathname of vnode 1");
+ return ENOMEM;
+ }
+ x = path + pl;
+ y = x + nl + 1;
+ while (x >= path) *y-- = *x--;
+ path[0] = '/';
+ for (x = name, y = path + 1; *x;) *y++ = *x++;
+ pl += nl + 1;
+ } else {
+ path = (char *)malloc(nl + 2);
+ if (!path) {
+ if (phi->p->cb_error)
+ (phi->p->cb_error)(ENOMEM, 1, phi->p->err_refcon,
+ "No memory for pathname of vnode 1");
+ return ENOMEM;
+ }
+ path[0] = '/';
+ strcpy(path + 1, name);
+ pl = nl + 1;
+ }
+ if (!fast) free(name);
+ vnode = parent;
+ }
+ *his_path = path;
+ return 0;
+}
--- /dev/null
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/* primitive.c - Routines for reading and writing low-level things */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "dumpscan.h"
+
+#define BUFSIZE 256
+
+
+afs_uint32 ReadByte(XFILE *X, unsigned char *val)
+{
+ return xfread(X, val, 1);
+}
+
+afs_uint32 ReadInt16(XFILE *X, afs_uint16 *val)
+{
+ afs_uint32 r;
+
+ if (r = xfread(X, val, 2)) return r;
+ *val = ntohs(*val);
+ return 0;
+}
+
+afs_uint32 ReadInt32(XFILE *X, afs_uint32 *val)
+{
+ afs_uint32 r;
+
+ if (r = xfread(X, val, 4)) return r;
+ *val = ntohl(*val);
+ return 0;
+}
+
+/* Read in a NUL-terminated string. This method is kind of messy, but
+ * has the advantage that it reads the data stream only once, doesn't
+ * read anything extra, and never has to seek on the data stream.
+ */
+afs_uint32 ReadString(XFILE *X, unsigned char **val)
+{
+ static unsigned char buf[BUFSIZE];
+ unsigned char *result = 0;
+ afs_uint32 r;
+ int i, l = 0;
+
+ *val = 0;
+ for (;;) {
+ for (i = 0; i < BUFSIZE; i++) {
+ r = ReadByte(X, buf + i);
+ if (r) {
+ if (result) free(result);
+ return r;
+ }
+ if (!buf[i]) break;
+ }
+ /* iff we found a null, i < BUFSIZE and buf[i] holds the NUL */
+ if (result) result = (unsigned char *)realloc(result, l + i + 1);
+ else result = (unsigned char *)malloc(i + 1);
+ if (!result) return ENOMEM;
+ memcpy(result + l, buf, i);
+ result[l+i] = 0;
+ l += i;
+ if (i < BUFSIZE) break;
+ }
+ *val = result;
+ return 0;
+}
+
+
+afs_uint32 WriteByte(XFILE *X, unsigned char val)
+{
+ return xfwrite(X, &val, 1);
+}
+
+afs_uint32 WriteInt16(XFILE *X, afs_uint16 val)
+{
+ val = htons(val);
+ return xfwrite(X, &val, 2);
+}
+
+afs_uint32 WriteInt32(XFILE *X, afs_uint32 val)
+{
+ val = htonl(val);
+ return xfwrite(X, &val, 4);
+}
+
+afs_uint32 WriteString(XFILE *X, unsigned char *str)
+{
+ int len = strlen((char *)str) + 1;
+ return xfwrite(X, str, len);
+}
+
+afs_uint32 WriteTagByte(XFILE *X, unsigned char tag, unsigned char val)
+{
+ char buffer[2];
+ buffer[0] = tag;
+ buffer[1] = val;
+ return xfwrite(X, buffer, 2);
+}
+
+afs_uint32 WriteTagInt16(XFILE *X, unsigned char tag, afs_uint16 val)
+{
+ char buffer[3];
+ buffer[0] = tag;
+ buffer[1] = (val & 0xff00) >> 8;
+ buffer[2] = val & 0xff;
+ return xfwrite(X, buffer, 3);
+}
+
+afs_uint32 WriteTagInt32(XFILE *X, unsigned char tag, afs_uint32 val)
+{
+ char buffer[5];
+ buffer[0] = tag;
+ buffer[1] = (val & 0xff000000) >> 24;
+ buffer[2] = (val & 0xff0000) >> 16;
+ buffer[3] = (val & 0xff00) >> 8;
+ buffer[4] = val & 0xff;
+ return xfwrite(X, buffer, 5);
+}
+
+afs_uint32 WriteTagInt32Pair(XFILE *X, unsigned char tag,
+ afs_uint32 val1, afs_uint32 val2)
+{
+ char buffer[9];
+ buffer[0] = tag;
+ buffer[1] = (val1 & 0xff000000) >> 24;
+ buffer[2] = (val1 & 0xff0000) >> 16;
+ buffer[3] = (val1 & 0xff00) >> 8;
+ buffer[4] = val1 & 0xff;
+ buffer[5] = (val2 & 0xff000000) >> 24;
+ buffer[6] = (val2 & 0xff0000) >> 16;
+ buffer[7] = (val2 & 0xff00) >> 8;
+ buffer[8] = val2 & 0xff;
+ return xfwrite(X, buffer, 9);
+}
--- /dev/null
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/* repair.c - Routines to generate a repaired dump */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "dumpscan.h"
+#include "dumpscan_errs.h"
+#include "dumpfmt.h"
+
+#include <afs/acl.h>
+#include <afs/dir.h>
+#include <afs/prs_fs.h>
+
+XFILE repair_output;
+int repair_verbose;
+#define RV repair_verbose
+
+
+/* Try to dump a dump header. Generate missing fields, if neccessary */
+afs_uint32 repair_dumphdr_cb(afs_dump_header *hdr, XFILE *X, void *refcon)
+{
+ afs_uint32 r, field_mask = hdr->field_mask;
+ char volname[22];
+
+ if (!(field_mask & F_DUMPHDR_VOLID)) {
+ if (RV) fprintf(stderr, ">>> DUMP HEADER missing volume ID\n");
+ return DSERR_FMT;
+ }
+ if (!(field_mask & F_DUMPHDR_VOLNAME)) {
+ if (RV) {
+ fprintf(stderr, ">>> DUMP HEADER missing volume name\n");
+ fprintf(stderr, ">>> Will use RESTORED.%d\n", hdr->volid);
+ }
+ sprintf(volname, "RESTORED.%d", hdr->volid);
+ hdr->volname = (unsigned char *)malloc(strlen(volname) + 1);
+ if (!hdr->volname) return ENOMEM;
+ strcpy(hdr->volname, volname);
+ hdr->field_mask |= F_DUMPHDR_VOLNAME;
+ }
+ if (!(field_mask & F_DUMPHDR_FROM)) {
+ if (RV) fprintf(stderr, ">>> DUMP HEADER missing from time (using 0)\n");
+ hdr->from_date = 0;
+ hdr->field_mask |= F_DUMPHDR_FROM;
+ }
+ if (!(field_mask & F_DUMPHDR_TO)) {
+ hdr->to_date = time(0);
+ if (RV) fprintf(stderr, ">>> DUMP HEADER missing from time (using %d)\n",
+ hdr->to_date);
+ hdr->field_mask |= F_DUMPHDR_TO;
+ }
+
+ return DumpDumpHeader(&repair_output, hdr);
+}
+
+
+/* Try to dump a volume header. Generate missing fields, if necessary */
+afs_uint32 repair_volhdr_cb(afs_vol_header *hdr, XFILE *X, void *refcon)
+{
+ afs_uint32 r, field_mask = hdr->field_mask;
+ char volname[22];
+
+ if (!(field_mask & F_VOLHDR_VOLID)) {
+ if (RV) fprintf(stderr, ">>> VOL HEADER missing volume ID\n");
+ return DSERR_FMT;
+ }
+ if (!(field_mask & F_VOLHDR_VOLVERS)) {
+ if (RV) fprintf(stderr, ">>> VOL HEADER missing version (using 1)\n");
+ hdr->volvers = 1;
+ hdr->field_mask |= F_VOLHDR_VOLVERS;
+ } else if (hdr->volvers != 1) {
+ if (RV) fprintf(stderr, ">>> VOL HEADER bogus version %d (using 1)\n",
+ hdr->volvers);
+ hdr->volvers = 1;
+ }
+ if (!(field_mask & F_VOLHDR_VOLNAME)) {
+ if (RV) {
+ fprintf(stderr, ">>> VOL HEADER missing volume name\n");
+ fprintf(stderr, ">>> Will use RESTORED.%d\n", hdr->volid);
+ }
+ sprintf(volname, "RESTORED.%d", hdr->volid);
+ hdr->volname = (unsigned char *)malloc(strlen(volname) + 1);
+ if (!hdr->volname) return ENOMEM;
+ strcpy(hdr->volname, volname);
+ hdr->field_mask |= F_VOLHDR_VOLNAME;
+ }
+ if (!(field_mask & F_VOLHDR_INSERV)) {
+ if (RV)
+ fprintf(stderr, ">>> VOL HEADER missing in-service flag (using 1)\n");
+ hdr->flag_inservice = 1;
+ hdr->field_mask |= F_VOLHDR_INSERV;
+ }
+ if (!(field_mask & F_VOLHDR_BLESSED)) {
+ if (RV) fprintf(stderr, ">>> VOL HEADER missing blessed flag (using 1)\n");
+ hdr->flag_blessed = 1;
+ hdr->field_mask |= F_VOLHDR_BLESSED;
+ }
+ if (!(field_mask & F_VOLHDR_VOLUNIQ)) {
+ if (RV) fprintf(stderr, ">>> VOL HEADER missing uniquifier (using 1)\n");
+ hdr->voluniq = 1;
+ hdr->field_mask |= F_VOLHDR_VOLUNIQ;
+ }
+ if (!(field_mask & F_VOLHDR_VOLTYPE)) {
+ if (RV) fprintf(stderr, ">>> VOL HEADER missing type (using 0: RW)\n");
+ hdr->voltype = 0;
+ hdr->field_mask |= F_VOLHDR_VOLTYPE;
+ } else if (hdr->voltype < 0 || hdr->voltype > 2) {
+ if (RV) fprintf(stderr, ">>> VOL HEADER bogus type %d (using 0: RW)\n",
+ hdr->voltype);
+ hdr->voltype = 0;
+ }
+ if (!(field_mask & F_VOLHDR_PARENT)) {
+ if (RV) fprintf(stderr, ">>> VOL HEADER parent (using %d)\n", hdr->volid);
+ hdr->parent_volid = hdr->volid;
+ hdr->field_mask |= F_VOLHDR_PARENT;
+ }
+ if (!(field_mask & F_VOLHDR_MAXQ)) {
+ if (field_mask & F_VOLHDR_DISKUSED) hdr->maxquota = hdr->diskused;
+ else hdr->maxquota = 1;
+ if (RV) fprintf(stderr, ">>> VOL HEADER missing max quota (using %d)\n",
+ hdr->maxquota);
+ hdr->field_mask |= F_VOLHDR_MAXQ;
+ }
+ if (!(field_mask & F_VOLHDR_DISKUSED)) {
+ if (RV) fprintf(stderr, ">>> VOL HEADER missing disk used (using 2048)\n");
+ hdr->diskused = 2048;
+ hdr->field_mask |= F_VOLHDR_DISKUSED;
+ }
+ if (!(field_mask & F_VOLHDR_NFILES)) {
+ if (RV) fprintf(stderr, ">>> VOL HEADER missing file count (using 1)\n");
+ hdr->nfiles = 1;
+ hdr->field_mask |= F_VOLHDR_NFILES;
+ }
+ if (!(field_mask & F_VOLHDR_CREATE_DATE)) {
+ hdr->create_date = 0;
+ if ((field_mask & F_VOLHDR_ACCESS_DATE)
+ && (!hdr->create_date || hdr->access_date < hdr->create_date))
+ hdr->create_date = hdr->access_date;
+ if ((field_mask & F_VOLHDR_UPDATE_DATE)
+ && (!hdr->create_date || hdr->update_date < hdr->create_date))
+ hdr->create_date = hdr->update_date;
+ if ((field_mask & F_VOLHDR_BACKUP_DATE)
+ && (!hdr->create_date || hdr->backup_date < hdr->create_date))
+ hdr->create_date = hdr->backup_date;
+
+ if (RV) fprintf(stderr, ">>> VOL HEADER missing create date (using %d)\n",
+ hdr->create_date);
+ hdr->field_mask |= F_VOLHDR_CREATE_DATE;
+ }
+ if (!(field_mask & F_VOLHDR_ACCESS_DATE)) {
+ hdr->access_date = 0;
+ if ((field_mask & F_VOLHDR_CREATE_DATE)
+ && (!hdr->access_date || hdr->create_date > hdr->access_date))
+ hdr->access_date = hdr->create_date;
+ if ((field_mask & F_VOLHDR_UPDATE_DATE)
+ && (!hdr->access_date || hdr->update_date > hdr->access_date))
+ hdr->access_date = hdr->update_date;
+ if ((field_mask & F_VOLHDR_BACKUP_DATE)
+ && (!hdr->access_date || hdr->backup_date > hdr->access_date))
+ hdr->access_date = hdr->backup_date;
+
+ if (RV) fprintf(stderr, ">>> VOL HEADER missing access date (using %d)\n",
+ hdr->access_date);
+ hdr->field_mask |= F_VOLHDR_ACCESS_DATE;
+ }
+ if (!(field_mask & F_VOLHDR_UPDATE_DATE)) {
+ hdr->update_date = 0;
+ if ((field_mask & F_VOLHDR_CREATE_DATE)
+ && (!hdr->update_date || hdr->create_date > hdr->update_date))
+ hdr->update_date = hdr->create_date;
+ if ((field_mask & F_VOLHDR_ACCESS_DATE) && !hdr->update_date)
+ hdr->update_date = hdr->access_date;
+ if ((field_mask & F_VOLHDR_BACKUP_DATE) && !hdr->update_date)
+ hdr->update_date = hdr->backup_date;
+
+ if (RV) fprintf(stderr, ">>> VOL HEADER missing update date (using %d)\n",
+ hdr->update_date);
+ hdr->field_mask |= F_VOLHDR_UPDATE_DATE;
+ }
+
+ return DumpVolumeHeader(&repair_output, hdr);
+}
+
+
+/* Try to dump a vnode. Generate missing fields, if necessary */
+afs_uint32 repair_vnode_cb(afs_vnode *v, XFILE *X, void *refcon)
+{
+ afs_uint32 r, field_mask = v->field_mask;
+
+ if ((v->vnode & 1) && !field_mask) {
+ if (RV) fprintf(stderr, ">>> VNODE %d is directory but has no fields?\n");
+ v->type = vDirectory;
+ v->field_mask |= F_VNODE_TYPE;
+ field_mask = F_VNODE_TYPE; /* Messy! */
+ }
+ if (field_mask && !(field_mask & F_VNODE_TYPE)) {
+ v->type = (v->vnode & 1) ? vDirectory : vFile;
+ if (RV) fprintf(stderr, ">>> VNODE %d missing type (using %d)\n",
+ v->vnode, v->type);
+ v->field_mask |= F_VNODE_TYPE;
+ }
+ if (field_mask && !(field_mask & F_VNODE_NLINKS)) {
+ if (RV)
+ fprintf(stderr, ">>> VNODE %d missing link count (using 1)\n", v->vnode);
+ v->nlinks = 1;
+ v->field_mask |= F_VNODE_NLINKS;
+ }
+ if (field_mask && !(field_mask & F_VNODE_PARENT)) {
+ if (RV)
+ fprintf(stderr, ">>> VNODE %d missing parent (using 1)\n", v->vnode);
+ v->parent = 1;
+ v->field_mask |= F_VNODE_PARENT;
+ }
+ if (field_mask && !(field_mask & F_VNODE_DVERS)) {
+ if (RV) fprintf(stderr, ">>> VNODE %d missing data version (using 1)\n",
+ v->vnode);
+ v->datavers = 1;
+ v->field_mask |= F_VNODE_DVERS;
+ }
+ if (field_mask && !(field_mask & F_VNODE_AUTHOR)) {
+ if (field_mask & F_VNODE_OWNER) v->author = v->owner;
+ else v->author = 0;
+ if (RV) fprintf(stderr, ">>> VNODE %d missing author (using %d)\n",
+ v->vnode, v->author);
+ v->field_mask |= F_VNODE_AUTHOR;
+ }
+ if (field_mask && !(field_mask & F_VNODE_OWNER)) {
+ if (field_mask & F_VNODE_AUTHOR) v->owner = v->author;
+ else v->owner = 0;
+ if (RV) fprintf(stderr, ">>> VNODE %d missing owner (using %d)\n",
+ v->vnode, v->owner);
+ v->field_mask |= F_VNODE_OWNER;
+ }
+ if (field_mask && !(field_mask & F_VNODE_MODE)) {
+ v->mode = (v->vnode & 1) ? 0755 : 0644;
+ if (RV) fprintf(stderr, ">>> VNODE missing mode (using %d)\n", v->mode);
+ v->field_mask |= F_VNODE_MODE;
+ }
+ if (field_mask && !(field_mask & F_VNODE_CDATE)) {
+ if (field_mask & F_VNODE_SDATE) v->client_date = v->server_date;
+ else v->client_date = 0;
+
+ if (RV) fprintf(stderr, ">>> VNODE %d missing client date (using %d)\n",
+ v->vnode, v->client_date);
+ v->field_mask |= F_VNODE_CDATE;
+ }
+ if (field_mask && !(field_mask & F_VNODE_SDATE)) {
+ if (field_mask & F_VNODE_CDATE) v->server_date = v->client_date;
+ else v->server_date = 0;
+
+ if (RV) fprintf(stderr, ">>> VNODE %d missing server date (using %d)\n",
+ v->vnode, v->server_date);
+ v->field_mask |= F_VNODE_SDATE;
+ }
+ if (field_mask && !(field_mask & F_VNODE_SIZE)) {
+ if (RV) fprintf(stderr, ">>> VNODE %d has no data size (using 0)\n");
+ v->size = 0;
+ v->field_mask |= F_VNODE_SIZE;
+ }
+ if ((field_mask & F_VNODE_DATA) && !v->size) {
+ if (RV)
+ fprintf(stderr, ">>> VNODE %d has data, but size == 0 (ignoring)\n",
+ v->vnode);
+ v->field_mask &=~ F_VNODE_DATA;
+ }
+ if (field_mask && v->type == vDirectory && !(field_mask & F_VNODE_ACL)) {
+ struct acl_accessList *acl = (struct acl_accessList *)v->acl;
+ if (RV) {
+ fprintf(stderr, ">>> VNODE %d is directory but has no ACL\n");
+ fprintf(stderr, ">>> Will generate default ACL\n");
+ }
+ memset(v->acl, 0, SIZEOF_LARGEDISKVNODE - SIZEOF_SMALLDISKVNODE);
+ acl->size = htonl(SIZEOF_LARGEDISKVNODE - SIZEOF_SMALLDISKVNODE);
+ acl->version = htonl(ACL_ACLVERSION);
+ acl->total = htonl(v->owner ? 0 : 1);
+ acl->positive = acl->total;
+ acl->negative = 0;
+ if (v->owner) {
+ acl->entries[0].id = htonl(v->owner);
+ acl->entries[0].rights = htonl((PRSFS_READ | PRSFS_WRITE
+ | PRSFS_INSERT | PRSFS_LOOKUP
+ | PRSFS_DELETE | PRSFS_LOCK
+ | PRSFS_ADMINISTER));
+ }
+ v->field_mask |= F_VNODE_ACL;
+ }
+
+ r = DumpVNode(&repair_output, v);
+ if (r) return r;
+
+ if (v->size) {
+ if (r = xfseek(X, &v->d_offset)) return r;
+ r = CopyVNodeData(&repair_output, X, v->size);
+ } else if (v->type == vDirectory) {
+ afs_dir_page page;
+ struct DirHeader *dhp = (struct DirHeader *)&page;
+ int i;
+
+ if (RV) {
+ fprintf(stderr, ">>> VNODE %d is directory but has no contents\n");
+ fprintf(stderr, ">>> Will generate deafult directory entries\n");
+ }
+ memset(&page, 0, sizeof(page));
+
+ /* Page and Directory Headers */
+ page.header.tag = htons(1234);
+ page.header.freecount = (EPP - DHE - 3);
+ page.header.freebitmap[0] = 0xff;
+ page.header.freebitmap[1] = 0x7f;
+ dhp->alloMap[0] = EPP - DHE - 3;
+ for (i = 1; i < MAXPAGES; i++) dhp->alloMap[i] = EPP;
+
+ /* Entry for . */
+ page.entry[DHE + 1].flag = FFIRST;
+ page.entry[DHE + 1].length = 1;
+ page.entry[DHE + 1].vnode = v->vnode;
+ page.entry[DHE + 1].vunique = v->vuniq;
+ strcpy(page.entry[DHE + 1].name, ".");
+ dhp->hashTable[0x2e] = DHE + 1;
+
+ /* Entry for .. */
+ page.entry[DHE + 2].flag = FFIRST;
+ page.entry[DHE + 2].length = 1;
+ page.entry[DHE + 2].vnode = v->parent;
+ page.entry[DHE + 2].vunique = 1; /* Can't have everything! */
+ strcpy(page.entry[DHE + 2].name, "..");
+ dhp->hashTable[0x44] = DHE + 2;
+
+ r = DumpVNodeData(&repair_output, (char *)&page, 2048);
+ } else if (field_mask) {
+ /* We wrote out attributes, so we should also write the 0-length data */
+ r = DumpVNodeData(&repair_output, "", 0);
+ }
+
+ return r;
+}
--- /dev/null
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/* stagehdr.c - Parse and dump stage backup headers */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "dumpscan.h"
+#include "dumpscan_errs.h"
+#include "xf_errs.h"
+#include "stagehdr.h"
+
+static afs_uint32 hdr_checksum(char *buf, int size)
+{
+ afs_uint32 sum = 0, n = size / sizeof(afs_uint32), *words = (afs_uint32 *)buf;
+
+ while (--n)
+ sum += ntohl(*words++);
+ return sum;
+}
+
+
+/* Parse a stage backup header.
+ * If tag is non-NULL, *tag should contain the first byte (already read),
+ * and will be filled in with the first byte after the header, if one exists.
+ * On success, returns 0 and leaves us positioned after the header
+ * On failure, returns an error and position is undefined
+ * Iff there is no header, returns DSERR_MAGIC and leaves us
+ * positioned where we started.
+ */
+afs_uint32 ParseStageHdr(XFILE *X, unsigned char *tag, backup_system_header *hdr)
+{
+ char buf[STAGE_HDRLEN];
+ struct stage_header *bckhdr = (struct stage_header *)buf;
+ u_int64 where;
+ afs_uint32 r;
+
+ if (r = xftell(X, &where)) return r;
+ if (hdr) memset(hdr, 0, sizeof(*hdr));
+ if (tag) {
+ if (*tag != STAGE_VERSMIN) return DSERR_MAGIC;
+ buf[0] = *tag;
+ r = xfread(X, buf + 1, STAGE_HDRLEN - 1);
+ } else {
+ r = xfread(X, buf, STAGE_HDRLEN);
+ }
+
+ if (r == ERROR_XFILE_EOF) {
+ r = xfseek(X, &where);
+ return r ? r : DSERR_MAGIC;
+ } else if (r) return r;
+
+ if (bckhdr->c_vers < STAGE_VERSMIN
+ || ntohl(bckhdr->c_magic) != STAGE_MAGIC
+ || hdr_checksum(buf, STAGE_HDRLEN) != STAGE_CHECKSUM) {
+ r = xfseek(X, &where);
+ return r ? r : DSERR_MAGIC;
+ }
+
+ if (hdr) {
+ hdr->version = bckhdr->c_vers;
+ hdr->from_date = ntohl(bckhdr->c_fdate);
+ hdr->to_date = ntohl(bckhdr->c_tdate);
+ hdr->dump_date = ntohl(bckhdr->c_time);
+ hdr->filenum = ntohl(bckhdr->c_filenum);
+ hdr->volid = ntohl(bckhdr->c_id);
+ hdr->dumplen = ntohl(bckhdr->c_length);
+ hdr->level = ntohl(bckhdr->c_level);
+ hdr->magic = ntohl(bckhdr->c_magic);
+ hdr->cksum = ntohl(bckhdr->c_checksum);
+ hdr->flags = ntohl(bckhdr->c_flags);
+ hdr->server = malloc(strlen(bckhdr->c_host) + 1);
+ hdr->part = malloc(strlen(bckhdr->c_disk) + 1);
+ hdr->volname = malloc(strlen(bckhdr->c_name) + 1);
+
+ if (!hdr->server || !hdr->part || !hdr->volname) {
+ if (hdr->server) free(hdr->server);
+ if (hdr->part) free(hdr->part);
+ if (hdr->volname) free(hdr->volname);
+ return ENOMEM;
+ }
+ strcpy(hdr->server, bckhdr->c_host);
+ strcpy(hdr->part, bckhdr->c_disk);
+ strcpy(hdr->volname, bckhdr->c_name);
+ }
+
+ if (tag) return ReadByte(X, tag);
+ else return 0;
+}
+
+
+/* Dump a stage backup header */
+afs_uint32 DumpStageHdr(XFILE *OX, backup_system_header *hdr)
+{
+ char buf[STAGE_HDRLEN];
+ struct stage_header *bckhdr = (struct stage_header *)buf;
+ afs_uint32 checksum;
+ afs_uint32 r;
+
+ memset(buf, 0, STAGE_HDRLEN);
+ bckhdr->c_vers = hdr->version;
+ bckhdr->c_fdate = htonl(hdr->from_date);
+ bckhdr->c_tdate = htonl(hdr->to_date);
+ bckhdr->c_filenum = htonl(hdr->filenum);
+ bckhdr->c_time = htonl(hdr->dump_date);
+ bckhdr->c_id = htonl(hdr->volid);
+ bckhdr->c_length = htonl(hdr->dumplen);
+ bckhdr->c_level = htonl(hdr->level);
+ bckhdr->c_magic = htonl(STAGE_MAGIC);
+ bckhdr->c_flags = htonl(hdr->flags);
+
+ strcpy(bckhdr->c_host, hdr->server);
+ strcpy(bckhdr->c_disk, hdr->part);
+ strcpy(bckhdr->c_name, hdr->volname);
+
+ /* Now, compute the checksum */
+ checksum = hdr_checksum(buf, STAGE_HDRLEN);
+ bckhdr->c_checksum = htonl(STAGE_CHECKSUM - checksum);
+
+ if (r = xfwrite(OX, buf, STAGE_HDRLEN)) return r;
+ return 0;
+}
--- /dev/null
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/* stagehdr.h - (old) Stage backup header format */
+
+#ifndef _STAGEHDR_H_
+#define _STAGEHDR_H_
+
+#include "intNN.h"
+
+/* Stage-related constants */
+#define STAGE_MAGIC 0x00adf8bc /* magic number for stage header */
+#define STAGE_CHECKSUM 84446 /* checksum (same as 4.2bsd dump) */
+#define STAGE_VERSMIN 20 /* minimum version */
+#define STAGE_NAMLEN 64 /* length of host/part/vol names */
+#define STAGE_HDRLEN 1024 /* size of the header */
+
+struct stage_header {
+ unsigned char c_vers; /* header version (starts at 20) */
+ unsigned char c_notused[3];
+ afs_uint32 c_fdate; /* dump "from" date */
+ afs_uint32 c_tdate; /* dump "to" date */
+ afs_uint32 c_filenum; /* tape file number */
+ afs_uint32 c_time; /* time dump was done */
+ char c_host[STAGE_NAMLEN]; /* hostname volume came from */
+ char c_disk[STAGE_NAMLEN]; /* partition volume came from */
+ char c_name[STAGE_NAMLEN]; /* volume name */
+ afs_uint32 c_id; /* volume ID */
+ afs_uint32 c_length; /* length of the dump */
+ afs_uint32 c_level; /* dump level */
+ afs_uint32 c_magic; /* magic number */
+ afs_uint32 c_checksum; /* checksum of backup header */
+ afs_uint32 c_flags; /* feature flags */
+};
+
+#endif /* _STAGEHDR_H_ */
--- /dev/null
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/* util.c - Useful utilities */
+
+#include <errno.h>
+
+#include "xf_errs.h"
+#include "dumpscan.h"
+#include "dumpscan_errs.h"
+#include "dumpfmt.h"
+
+
+/* Take care of errno, ERROR_XFILE_EOF, and ENOMEM return codes.
+ * Call whatever callbacks are necessary, and return the code to
+ * actually use. If you don't want '0' to result in a DSERR_TAG,
+ * then you must translate it to DSERR_DONE before calling this.
+ */
+/*** THIS FUNCTION INTENDED FOR INTERNAL USE ONLY ***/
+int handle_return(int r, XFILE *X, unsigned char tag, dump_parser *p)
+{
+ u_int64 where, xwhere;
+
+ switch (r) {
+ case 0:
+ if (p->cb_error) {
+ xftell(X, &where);
+ sub64_32(xwhere, where, 1);
+ (p->cb_error)(DSERR_TAG, 1, p->err_refcon,
+ (tag > 0x20 && tag < 0x7f)
+ ? "Unexpected tag '%c' at %s = 0x%s"
+ : "Unexpected tag 0x%02x at %s = 0x%s",
+ tag, decimate_int64(&xwhere, 0), hexify_int64(&xwhere, 0));
+ }
+ return DSERR_TAG;
+
+ case ERROR_XFILE_EOF:
+ if (p->cb_error) {
+ xftell(X, &where);
+ (p->cb_error)(ERROR_XFILE_EOF, 1, p->err_refcon,
+ "Unexpected EOF at %s = 0x%s",
+ decimate_int64(&where, 0), hexify_int64(&where, 0));
+ }
+ return ERROR_XFILE_EOF;
+
+ case ENOMEM:
+ if (p->cb_error) {
+ xftell(X, &where);
+ (p->cb_error)(ENOMEM, 1, p->err_refcon,
+ "Out of memory at %s = 0x%s",
+ decimate_int64(&where, 0), hexify_int64(&where, 0));
+ }
+ return ENOMEM;
+
+ case DSERR_DONE:
+ return 0;
+
+ default:
+ /* For other negative valuees, the callback was already done */
+ if (r > 0 && p->cb_error)
+ (p->cb_error)(r, 1, p->err_refcon,
+ "System error %d reading dump file", r);
+ return r;
+ }
+}
+
+
+/* Prepare a tag_parse_info for use by the dump parser. *
+/*** THIS FUNCTION INTENDED FOR INTERNAL USE ONLY ***/
+void prep_pi(dump_parser *p, tag_parse_info *pi)
+{
+ memset(pi, 0, sizeof(tag_parse_info));
+ pi->err_refcon = p->err_refcon;
+ pi->cb_error = p->cb_error;
+
+ if (p->repair_flags & DSFIX_SKIP)
+ pi->flags |= TPFLAG_SKIP;
+ if ((p->flags & DSFLAG_SEEK) && (p->repair_flags & DSFIX_RSKIP))
+ pi->flags |= TPFLAG_RSKIP;
+}
+
+
+/* Does the designated location match a vnode?
+ * Returns 0 if yes, DSERR_FMT if no, something else on error
+ */
+/*** THIS FUNCTION INTENDED FOR INTERNAL USE ONLY ***/
+int match_next_vnode(XFILE *X, dump_parser *p, u_int64 *where, afs_uint32 vnode)
+{
+ afs_uint32 r, x, y, z;
+ unsigned char tag;
+
+ if (r = xfseek(X, where)) return r;
+ if (r = ReadByte(X, &tag)) return r;
+ switch (tag) {
+ case 3: /* A vnode? */
+ if (r = ReadInt32(X, &x)) return r;
+ if (r = ReadInt32(X, &y)) return r;
+ if (r = ReadByte(X, &tag)) return r;
+ if ( !((vnode & 1) && !(x & 1) && x < vnode)
+ && !((vnode & 1) == (x & 1) && x > vnode))
+ return DSERR_FMT;
+ if (x > vnode && x - vnode > 10000) return DSERR_FMT;
+ if (y < 0 || y > p->vol_uniquifier) return DSERR_FMT;
+
+ /* Now, what follows the vnode/uniquifier? */
+ switch (tag) {
+ case 3: /* Another vnode? - Only if this is a non-directory */
+ if (x & 1) return DSERR_FMT;
+ if (r = ReadInt32(X, &z)) return r;
+ if ( !((x & 1) && !(z & 1) && z < x)
+ && !((x & 1) == (z & 1) && z > x))
+ return DSERR_FMT;
+ return 0;
+
+ case 4: /* Dump end - Only if this is a non-directory */
+ if (x & 1) return DSERR_FMT;
+ if (r = ReadInt32(X, &z)) return r;
+ if (z != DUMPENDMAGIC) return DSERR_FMT;
+ return 0;
+
+ case 't': /* Vnode type byte */
+ if (r = ReadByte(X, &tag)) return r;
+ if ((tag == vFile || tag == vSymlink) && !(x & 1)) return 0;
+ if (tag == vDirectory && (x & 1)) return 0;
+ return DSERR_FMT;
+
+ default:
+ return DSERR_FMT;
+ }
+
+ case 4: /* A dump end? */
+ if (r = ReadInt32(X, &x)) return r;
+ if (x != DUMPENDMAGIC) return DSERR_FMT;
+ return 0;
+
+ default:
+ return DSERR_FMT;
+ }
+}
--- /dev/null
+# CMUCS AFStools
+# dumpscan - routines for scanning and manipulating AFS volume dumps
+#
+# Copyright (c) 1998 Carnegie Mellon University
+# All Rights Reserved.
+#
+# Permission to use, copy, modify and distribute this software and its
+# documentation is hereby granted, provided that both the copyright
+# notice and this permission notice appear in all copies of the
+# software, derivative works or modified versions, and any portions
+# thereof, and that both notices appear in supporting documentation.
+#
+# CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+# CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+# ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+#
+# Carnegie Mellon requests users of this software to return to
+#
+# Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
+# School of Computer Science
+# Carnegie Mellon University
+# Pittsburgh PA 15213-3890
+#
+# any improvements or extensions that they make and grant Carnegie Mellon
+# the rights to redistribute these changes.
+
+# xf_errs.et - Error table for xfiles
+
+error_table xFil
+ ec ERROR_XFILE_EOF, "EOF while reading XFILE"
+ ec ERROR_XFILE_WRONLY, "XFILE may not be opened write-only"
+ ec ERROR_XFILE_RDONLY, "XFILE is read-only"
+ ec ERROR_XFILE_NOSEEK, "XFILE is not seekable"
+ ec ERROR_XFILE_ISPASS, "XFILE passthru already set"
+ ec ERROR_XFILE_NOPASS, "XFILE passthru not set"
+ ec ERROR_XFILE_TYPE, "unknown XFILE type"
+end
--- /dev/null
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/* xf_files.c - XFILE routines for accessing UNIX files */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "xfiles.h"
+#include "xf_errs.h"
+
+#define O_MODE_MASK (O_RDONLY | O_WRONLY | O_RDWR)
+
+
+/* do_read for stdio xfiles */
+static afs_uint32 xf_FILE_do_read(XFILE *X, void *buf, afs_uint32 count)
+{
+ FILE *F = X->refcon;
+
+ /* XXX: handle short and interrupted reads */
+ if (fread(buf, count, 1, F) != 1)
+ return ferror(F) ? errno : ERROR_XFILE_EOF;
+ return 0;
+}
+
+
+/* do_write for stdio xfiles */
+static afs_uint32 xf_FILE_do_write(XFILE *X, void *buf, afs_uint32 count)
+{
+ FILE *F = X->refcon;
+
+ /* XXX: handle interrupted writes */
+ if (fwrite(buf, count, 1, F) != 1)
+ return errno;
+ return 0;
+}
+
+
+/* do_tell for stdio xfiles */
+static afs_uint32 xf_FILE_do_tell(XFILE *X, u_int64 *offset)
+{
+ FILE *F = X->refcon;
+ off_t where;
+
+ where = ftell(F);
+ if (where == -1) return errno;
+ set64(*offset, where);
+ return 0;
+}
+
+
+/* do_seek for stdio xfiles */
+static afs_uint32 xf_FILE_do_seek(XFILE *X, u_int64 *offset)
+{
+ FILE *F = X->refcon;
+ off_t where = get64(*offset);
+
+ if (fseek(F, where, SEEK_SET) == -1) return errno;
+ return 0;
+}
+
+
+/* do_skip for stdio xfiles */
+static afs_uint32 xf_FILE_do_skip(XFILE *X, afs_uint32 count)
+{
+ FILE *F = X->refcon;
+
+ if (fseek(F, count, SEEK_CUR) == -1) return errno;
+ return 0;
+}
+
+
+/* do_close for stdio xfiles */
+static afs_uint32 xf_FILE_do_close(XFILE *X)
+{
+ FILE *F = X->refcon;
+
+ X->refcon = 0;
+ if (fclose(F)) return errno;
+ return 0;
+}
+
+
+/* Prepare a stdio XFILE */
+static void prepare(XFILE *X, FILE *F, int xflag)
+{
+ struct stat st;
+
+ memset(X, 0, sizeof(*X));
+ X->do_read = xf_FILE_do_read;
+ X->do_write = xf_FILE_do_write;
+ X->do_tell = xf_FILE_do_tell;
+ X->do_close = xf_FILE_do_close;
+ X->refcon = F;
+ if (xflag == O_RDWR) X->is_writable = 1;
+
+ if (!fstat(fileno(F), &st)
+ && ((st.st_mode & S_IFMT) == S_IFREG
+ || (st.st_mode & S_IFMT) == S_IFBLK)) {
+ X->is_seekable = 1;
+ X->do_seek = xf_FILE_do_seek;
+ X->do_skip = xf_FILE_do_skip;
+ }
+}
+
+
+/* Open an XFILE by path */
+afs_uint32 xfopen_path(XFILE *X, int flag, char *path, int mode)
+{
+ FILE *F = 0;
+ int fd = -1, xflag;
+ afs_uint32 code;
+
+ xflag = flag & O_MODE_MASK;
+ if (xflag == O_WRONLY) return ERROR_XFILE_WRONLY;
+
+ if ((fd = open(path, flag, mode)) < 0) return errno;
+ if (!(F = fdopen(fd, (xflag == O_RDONLY) ? "r" : "r+"))) {
+ code = errno;
+ close(fd);
+ return code;
+ }
+
+ prepare(X, F, xflag);
+ return 0;
+}
+
+
+/* Open an XFILE by FILE * */
+afs_uint32 xfopen_FILE(XFILE *X, int flag, FILE *F)
+{
+ flag &= O_MODE_MASK;
+ if (flag == O_WRONLY) return ERROR_XFILE_WRONLY;
+ prepare(X, F, flag);
+ return 0;
+}
+
+
+/* Open an XFILE by file descriptor */
+afs_uint32 xfopen_fd(XFILE *X, int flag, int fd)
+{
+ FILE *F;
+
+ flag &= O_MODE_MASK;
+ if (flag == O_WRONLY) return ERROR_XFILE_WRONLY;
+ if (!(F = fdopen(fd, (flag == O_RDONLY) ? "r" : "r+"))) return errno;
+ prepare(X, F, flag);
+ return 0;
+}
+
+
+/* open-by-name support for filenames */
+afs_uint32 xfon_path(XFILE *X, int flag, char *name)
+{
+ return xfopen_path(X, flag, name, 0644);
+}
+
+
+/* open-by-name support for file descriptors */
+afs_uint32 xfon_fd(XFILE *X, int flag, char *name)
+{
+ int fd = atoi(name);
+ return xfopen_fd(X, flag, fd);
+}
+
+
+/* open-by-name support for standard I/O */
+afs_uint32 xfon_stdio(XFILE *X, int flag)
+{
+ flag &= O_MODE_MASK;
+ if (flag == O_WRONLY) flag = O_RDWR;
+ return xfopen_FILE(X, flag, (flag == O_RDONLY) ? stdin : stdout);
+}
--- /dev/null
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <stdarg.h>
+
+#include "xfiles.h"
+#include "xf_errs.h"
+
+#define SPBUFLEN 40
+static char spbuf[SPBUFLEN + 1] = "";
+
+
+#define MAXPREC 100
+
+/* Generate an ASCII representation of an integer <val>, as follows:
+ * <base> indicates the base to be used (2-36)
+ * <uc> is nonzero if letter digits should be uppercase
+ * <prec> is the minimum number of digits
+ * The resulting number is stored in <buf>, which must be long enough
+ * to receive it. The minimum length is <prec> or ceil(log{base}(val)),
+ * whichever is larger, plus room for a trailing NUL.
+ */
+static void mkint(char *buf, unsigned long val, int base, int uc, int prec)
+{
+ int len = 0, dig, i;
+
+ while (val) {
+ dig = val % base;
+ val = (val - dig) / base;
+ if (dig < 10) dig = dig + '0';
+ else if (uc) dig = dig + 'A' - 10;
+ else dig = dig + 'a' - 10;
+ buf[len++] = dig;
+ }
+ while (len < prec) buf[len++] = '0';
+ for (i = 0; i < (len + 1) / 2; i++) {
+ dig = buf[i];
+ buf[i] = buf[len - i - 1];
+ buf[len - i - 1] = dig;
+ }
+ buf[len] = 0;
+}
+
+
+/* Write spaces faster than one at a time */
+static afs_uint32 wsp(XFILE *X, int count)
+{
+ char *x;
+ afs_uint32 err;
+ int i;
+
+ if (!spbuf[0]) {
+ for (x = spbuf, i = SPBUFLEN; i; x++, i--) *x = ' ';
+ }
+
+ while (count > SPBUFLEN) {
+ err = xfwrite(X, spbuf, SPBUFLEN);
+ if (err) return err;
+ count -= SPBUFLEN;
+ }
+ if (count > 0) return xfwrite(X, spbuf, count);
+ return 0;
+}
+
+
+/* This function is a mostly-complete implementation of snprintf,
+ * with the following features:
+ *
+ * - Actually obeys the length limit, which (unfortunately) many
+ * implementations of snprintf do not.
+ *
+ * - Supports all the standard format specifiers for integers
+ * (d, i, o, u, x, X), floating-point values (f, e, E, g, G),
+ * and strings and characters (c, s, %), plus a few unusual
+ * but useful ones described below.
+ *
+ * - Supports all the standard flags (-, 0, +, space, #). These
+ * flags are ignored if used when they are not appropriate.
+ *
+ * - Supports the standard size modifiers for short (h), long (h),
+ * and double (L) arguments. These modifiers are ignored if used
+ * when they are not appropriate.
+ *
+ * - Supports minimum field width and precision, where appropriate,
+ * including the use of '*' to specify a value given as an argument
+ * instead of in the format string. There is a maximum precision
+ * of 100 digits.
+ *
+ * - At present, the 'p' specifier for printing pointers is not
+ * implemented, because it is inherently non-portable and thus
+ * can be implemented correctly only by the compiler's run-time
+ * library.
+ *
+ * - Floating-point specifier (%e, %f, %g) are implemented by
+ * calling the standard sprintf, and thus may be unsafe.
+ *
+ * - The '%...$' notation is used primarily when the format string
+ * is specified by the user, who knows but cannot change the order
+ * of the arguments. Such usage is inherently dangerous and
+ * insecure; thus, it is not supported.
+ *
+ * The custom format specifier '%I' is supported. This specifier
+ * takes as its argument an unsigned long integer containing an
+ * IPv4 address in network byte order. The address is rendered
+ * either as a hostname or as a dotted quad, as follows:
+ *
+ * - If precision is nonzero or unspecified, a hostname lookup
+ * is attempted; if it is successful, the hostname is printed.
+ * If the hostname lookup fails, the address is printed in
+ * dotted-quad notation.
+ *
+ * - If precision is explicitly specified as 0, then the hostname
+ * lookup is skipped, and dotted-quad notation is always used.
+ *
+ * - If a hostname is to be printed:
+ * + The precision controls the maximum number of characters
+ * printed, as with %s.
+ * + If the '#' flag is specified, any letters in the hostname
+ * will be forced to lower case before printing.
+ * + If the '+' flag is specified, any letters in the hostname
+ * will be forced to upper case before printing. If both
+ * '#' and '+' are given, the '+' flag will be ignored.
+ * + The '0' and ' ' flags have no effect.
+ *
+ * - If a dotted quad is to be printed:
+ * + The precision has no effect; dotted quads are always
+ * 7 to 12 characters in length, depending on the value
+ * to be printed and the format flags used.
+ * + If the '0' flag is given, each field (byte) of the address
+ * will be padded with '0' on the left to three digits.
+ * + If the ' ' flag is given, each field (byte) of the address
+ * will be padded with spaces on the left to three digits. If
+ * both '0' and ' ' are given, the ' ' flag will be ignored.
+ * + The '#' and '+' flags have no effect.
+ */
+
+afs_uint32 vxfprintf(XFILE *X, char *fmt, va_list ap)
+{
+ unsigned int width, precision, haveprec, len;
+ int ljust, plsign, spsign, altform, zfill;
+ int hflag, lflag, count, *countp, j;
+ char *x, *y, *lit = 0, xbuf[MAXPREC + 21], fbuf[20];
+ struct hostent *he;
+ struct in_addr ia;
+ unsigned long UVAL;
+ long SVAL, *lcountp;
+ double FVAL;
+ short *hcountp;
+ afs_uint32 err;
+
+ count = 0;
+ while (*fmt) {
+ if (*fmt != '%') {
+ if (!lit) lit = fmt;
+ fmt++;
+ count++;
+ continue;
+ }
+ if (lit) {
+ if ((err = xfwrite(X, lit, fmt - lit))) return err;
+ lit = 0;
+ }
+
+ /** Found a format specifier **/
+ ljust = plsign = spsign = altform = zfill = 0;
+ width = precision = haveprec = 0;
+ hflag = lflag = 0;
+ fmt++;
+
+ /* parse format flags */
+ while (*fmt) {
+ switch (*fmt) {
+ case '-': ljust = 1; fmt++; continue; /* left justify */
+ case '+': plsign = 1; fmt++; continue; /* use + or - */
+ case ' ': spsign = 1; fmt++; continue; /* use space or - */
+ case '#': altform = 1; fmt++; continue; /* alternate form */
+ case '0': zfill = 1; fmt++; continue; /* pad with 0 */
+ default: break;
+ }
+ break;
+ }
+
+ /* parse minimum width */
+ if (*fmt == '*') {
+ width = va_arg(ap, int);
+ fmt++;
+ } else while (isdigit(*fmt)) {
+ width = (width * 10) + (*fmt - '0');
+ fmt++;
+ }
+
+ /* parse precision */
+ if (*fmt == '.') {
+ fmt++;
+ haveprec = 1;
+ if (*fmt == '*') {
+ precision = va_arg(ap, int);
+ fmt++;
+ } else while (isdigit(*fmt)) {
+ precision = (precision * 10) + (*fmt - '0');
+ fmt++;
+ }
+ }
+
+ /* parse size flags */
+ while (*fmt) {
+ switch (*fmt) {
+ case 'h': hflag = 1; fmt++; continue; /* short argument */
+ case 'l': lflag = 1; fmt++; continue; /* long argument */
+ default: break;
+ }
+ break;
+ }
+
+ /* parse format specifier */
+ if (!*fmt) break;
+ switch (*fmt++) {
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+ FVAL = va_arg(ap, double);
+ sprintf(fbuf, "%%%s%s.*L%c", plsign ? "+" : (spsign ? " " : ""),
+ altform ? "#" : "", fmt[-1]);
+ if (!haveprec) precision = 6;
+ if (precision > MAXPREC) precision = MAXPREC;
+ sprintf(xbuf, fbuf, precision, FVAL);
+ x = xbuf;
+ len = strlen(x);
+ break;
+
+ case 'i':
+ case 'd': /* signed decimal integer */
+ if (lflag) SVAL = va_arg(ap, long);
+ else if (hflag) SVAL = va_arg(ap, int);
+ else SVAL = va_arg(ap, int);
+ UVAL = (SVAL < 0) ? -SVAL : SVAL;
+
+ if (SVAL < 0) xbuf[0] = '-';
+ else if (plsign) xbuf[0] = '+';
+ else if (spsign) xbuf[0] = ' ';
+ else xbuf[0] = 0;
+
+ if (!haveprec) {
+ if (zfill && !ljust) precision = width - !!xbuf[0];
+ else precision = 1;
+ if (precision < 1 + !!xbuf[0]) precision = 1 + !!xbuf[0];
+ }
+ if (precision > MAXPREC) precision = MAXPREC;
+
+ mkint(xbuf + 1, UVAL, 10, 0, precision);
+ x = xbuf + !xbuf[0];
+ len = strlen(x);
+ break;
+
+
+ case 'o': /* unsigned octal integer */
+ if (lflag) UVAL = va_arg(ap, unsigned long);
+ else if (hflag) UVAL = va_arg(ap, unsigned int);
+ else UVAL = va_arg(ap, unsigned int);
+
+ xbuf[0] = '0';
+
+ if (!haveprec) {
+ if (zfill && !ljust) precision = width;
+ else precision = 1;
+ }
+ if (precision > MAXPREC) precision = MAXPREC;
+
+ mkint(xbuf + 1, UVAL, 8, 0, precision);
+ x = xbuf + (xbuf[1] == '0' || !altform);
+ len = strlen(x);
+ break;
+
+ case 'u': /* unsigned decimal integer */
+ if (lflag) UVAL = va_arg(ap, unsigned long);
+ else if (hflag) UVAL = va_arg(ap, unsigned int);
+ else UVAL = va_arg(ap, unsigned int);
+
+ if (!haveprec) {
+ if (zfill && !ljust) precision = width;
+ else precision = 1;
+ }
+ if (precision > MAXPREC) precision = MAXPREC;
+
+ mkint(xbuf, UVAL, 10, 0, precision);
+ x = xbuf;
+ len = strlen(x);
+ break;
+
+ case 'x':
+ case 'X': /* unsigned hexadecimal integer */
+ if (lflag) UVAL = va_arg(ap, unsigned long);
+ else if (hflag) UVAL = va_arg(ap, unsigned int);
+ else UVAL = va_arg(ap, unsigned int);
+
+ xbuf[0] = '0';
+ xbuf[1] = 'x';
+
+ if (!haveprec) {
+ if (zfill && !ljust) precision = width;
+ else precision = 1;
+ }
+ if (precision > MAXPREC) precision = MAXPREC;
+
+ mkint(xbuf + 2, UVAL, 16, 0, precision);
+ x = xbuf + ((altform && UVAL) ? 0 : 2);
+ len = strlen(x);
+ break;
+
+ case '%': /* literal % */
+ xbuf[0] = '%';
+ xbuf[1] = 0;
+ x = xbuf;
+ len = 1;
+ break;
+
+ case 'c': /* character */
+ xbuf[0] = va_arg(ap, int);
+ xbuf[1] = 0;
+ x = xbuf;
+ len = 1;
+ break;
+
+ case 's': /* string */
+ x = va_arg(ap, char *);
+ if (!x) x = "<null>";
+ len = strlen(x);
+ if (haveprec && precision < len) len = precision;
+ break;
+
+ case 'I': /* IP address:
+ * value is provided as a network-order unsigned long integer
+ * precision specifies max hostname length, as for %s
+ * if precision is explicitly 0, no hostname lookup is done
+ * if 0fill specified, IPaddr fields are 0-filled to 3 digits
+ * if spsign specified, IPaddr fields are space-filled to 3 digits
+ */
+ UVAL = va_arg(ap, unsigned long);
+ ia.s_addr = UVAL;
+ /* XXX: add support for an application-provided function
+ * for doing hostname lookups. We don't do it automatically
+ * because on some platforms that would prevent us from
+ * being fully statically linked.
+ */
+ if (haveprec && !precision) he = 0;
+ else he = gethostbyaddr((char *)&ia, 4, AF_INET);
+ if (he) {
+ x = he->h_name;
+ len = strlen(x);
+ if (haveprec && precision < len) len = precision;
+ if (altform)
+ for (y = x; *y; y++) if (isupper(*y)) *y = tolower(*y);
+ else if (plsign)
+ for (y = x; *y; y++) if (islower(*y)) *y = toupper(*y);
+ } else {
+ UVAL = ntohl(UVAL);
+ if (zfill) x = "%03u.%03u.%03u.%03u";
+ else if (spsign) x = "%3u.%3u.%3u.%3u";
+ else x = "%u.%u.%u.%u";
+ sprintf(xbuf, x,
+ (UVAL & 0xff000000) >> 24, (UVAL & 0x00ff0000) >> 16,
+ (UVAL & 0x0000ff00) >> 8, (UVAL & 0x000000ff));
+ x = xbuf;
+ len = strlen(xbuf);
+ }
+ break;
+
+ case 'n': /* report count so far */
+ if (lflag) {
+ lcountp = va_arg(ap, long *);
+ *lcountp = count;
+ } else if (hflag) {
+ hcountp = va_arg(ap, short *);
+ *hcountp = count;
+ } else {
+ countp = va_arg(ap, int *);
+ *countp = count;
+ }
+ continue;
+
+ default: /* unknown specifier */
+ continue;
+ }
+
+ /* render the results */
+ if (!width) width = len;
+ j = width - len;
+ if (j > 0) count += j;
+ count += len;
+
+ if (!ljust && (err = wsp(X, j))) return err;
+ if ((err = xfwrite(X, x, len))) return err;
+ if (ljust && (err = wsp(X, j))) return err;
+ }
+ if (lit && (err = xfwrite(X, lit, fmt - lit))) return err;
+ return 0;
+lose:
+ return err;
+}
+
+
+afs_uint32 xfprintf(XFILE *X, char *fmt, ...)
+{
+ va_list ap;
+ afs_uint32 err;
+
+ va_start(ap, fmt);
+ err = vxfprintf(X, fmt, ap);
+ va_end(ap);
+ return err;
+}
--- /dev/null
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/* xf_profile.c - XFILE routines for read/write profiling */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "xfiles.h"
+#include "xf_errs.h"
+
+#define O_MODE_MASK (O_RDONLY | O_WRONLY | O_RDWR)
+
+typedef struct {
+ XFILE content;
+ XFILE profile;
+} PFILE;
+
+
+/* do_read for profiled xfiles */
+static afs_uint32 xf_PROFILE_do_read(XFILE *X, void *buf, afs_uint32 count)
+{
+ PFILE *PF = X->refcon;
+ afs_uint32 err;
+
+ err = xfread(&PF->content, buf, count);
+ xfprintf(&PF->profile, "R %ld =%ld\n", (long)count, (long)err);
+ return err;
+}
+
+
+/* do_write for profiled xfiles */
+static afs_uint32 xf_PROFILE_do_write(XFILE *X, void *buf, afs_uint32 count)
+{
+ PFILE *PF = X->refcon;
+ afs_uint32 err;
+
+ err = xfwrite(&PF->content, buf, count);
+ xfprintf(&PF->profile, "W %ld =%ld\n", (long)count, (long)err);
+ return err;
+}
+
+
+/* do_tell for profiled xfiles */
+static afs_uint32 xf_PROFILE_do_tell(XFILE *X, u_int64 *offset)
+{
+ PFILE *PF = X->refcon;
+ afs_uint32 err;
+
+ err = xftell(&PF->content, offset);
+ if (err) xfprintf(&PF->profile, "TELL ERR =%ld\n", (long)err);
+ else xfprintf(&PF->profile, "TELL %s =0\n", hexify_int64(offset, 0));
+ return err;
+}
+
+
+/* do_seek for profiled xfiles */
+static afs_uint32 xf_PROFILE_do_seek(XFILE *X, u_int64 *offset)
+{
+ PFILE *PF = X->refcon;
+ afs_uint32 err;
+
+ err = xfseek(&PF->content, offset);
+ xfprintf(&PF->profile, "SEEK %s =%ld\n", hexify_int64(offset, 0), (long)err);
+ return err;
+}
+
+
+/* do_skip for profiled xfiles */
+static afs_uint32 xf_PROFILE_do_skip(XFILE *X, afs_uint32 count)
+{
+ PFILE *PF = X->refcon;
+ afs_uint32 err;
+
+ err = xfskip(&PF->content, count);
+ xfprintf(&PF->profile, "SKIP %ld =%ld\n", (long)count, (long)err);
+ return err;
+}
+
+
+/* do_close for profiled xfiles */
+static afs_uint32 xf_PROFILE_do_close(XFILE *X)
+{
+ PFILE *PF = X->refcon;
+ afs_uint32 err, err2;
+
+ err = xfclose(&PF->content);
+ err2 = xfclose(&PF->profile);
+ free(PF);
+ return err ? err : err2;
+}
+
+
+/* Open a profiled XFILE */
+afs_uint32 xfopen_profile(XFILE *X, int flag, char *xname, char *profile)
+{
+ PFILE *PF;
+ afs_uint32 err;
+
+ PF = malloc(sizeof(*PF));
+ if (!PF) return ENOMEM;
+ memset(PF, 0, sizeof(*PF));
+
+ err = xfopen(&PF->profile, O_RDWR|O_CREAT|O_TRUNC, profile);
+ if (err) {
+ free(PF);
+ return err;
+ }
+
+ err = xfopen(&PF->content, flag, xname);
+ if (err) {
+ xfclose(&PF->profile);
+ free(PF);
+ return err;
+ }
+
+ memset(X, 0, sizeof(*X));
+ X->refcon = PF;
+ X->do_read = xf_PROFILE_do_read;
+ X->do_write = xf_PROFILE_do_write;
+ X->do_tell = xf_PROFILE_do_tell;
+ X->do_close = xf_PROFILE_do_close;
+ X->is_writable = PF->content.is_writable;
+ if (PF->content.is_seekable) {
+ X->is_seekable;
+ X->do_seek = xf_PROFILE_do_seek;
+ X->do_skip = xf_PROFILE_do_skip;
+ }
+ xfprintf(&PF->profile, "OPEN %s\n", xname);
+ return 0;
+}
+
+
+afs_uint32 xfon_profile(XFILE *X, int flag, char *name)
+{
+ char *x, *profile, *xname;
+ afs_uint32 err;
+
+ if (!(name = strdup(name))) return ENOMEM;
+
+ profile = "-";
+ xname = name;
+ for (x = name; *x; x++) {
+ if (x[0] == ':' && x[1] == ':') {
+ *x = 0;
+ profile = name;
+ xname = x + 2;
+ break;
+ }
+ }
+ if (!*name) profile = "-";
+ err = xfopen_profile(X, flag, xname, profile);
+ free(name);
+ return err;
+}
--- /dev/null
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/* xf_rxcall.c - XFILE routines for Rx bulk data transfers */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <netdb.h>
+
+#include "xfiles.h"
+#include "xf_errs.h"
+
+#include <rx/xdr.h>
+#include <rx/rx.h>
+#include <rx/rx_null.h>
+#include <rx/rxkad.h>
+#include <afs/auth.h>
+#include <afs/cellconfig.h>
+#include <afs/vlserver.h>
+#include <afs/volser.h>
+
+#ifndef AFSCONF_CLIENTNAME
+#include <afs/dirpath.h>
+#define AFSCONF_CLIENTNAME AFSDIR_CLIENT_ETC_DIRPATH
+#endif
+
+#define O_MODE_MASK (O_RDONLY | O_WRONLY | O_RDWR)
+
+struct rxinfo {
+ struct rx_connection *conn; /* connection */
+ struct rx_call *call; /* call */
+ afs_int32 tid; /* volser transaction ID */
+ afs_uint32 code; /* result code */
+};
+
+static afs_uint32 xf_rxcall_do_read(XFILE *X, void *buf, afs_uint32 count)
+{
+ struct rxinfo *i = X->refcon;
+ afs_uint32 xcount;
+
+ xcount = rx_Read(i->call, buf, count);
+ if (xcount == count) return 0;
+ i->code = rx_EndCall(i->call, 0);
+ i->call = 0;
+ return i->code ? i->code : ERROR_XFILE_RDONLY;
+}
+
+
+static afs_uint32 xf_rxcall_do_write(XFILE *X, void *buf, afs_uint32 count)
+{
+ struct rxinfo *i = X->refcon;
+ afs_uint32 xcount;
+
+ xcount = rx_Write(i->call, buf, count);
+ if (xcount == count) return 0;
+ i->code = rx_EndCall(i->call, 0);
+ i->call = 0;
+ return i->code;
+}
+
+
+static afs_uint32 xf_rxcall_do_close(XFILE *X)
+{
+ struct rxinfo *i = X->refcon;
+ afs_uint32 code;
+
+ if (i->call) {
+ code = rx_EndCall(i->call, i->code);
+ i->call = 0;
+ } else {
+ code = i->code;
+ }
+ free(i);
+ return code;
+}
+
+
+static afs_uint32 xf_voldump_do_close(XFILE *X)
+{
+ struct rxinfo *i = X->refcon;
+ struct rx_connection *conn = i->conn;
+ afs_uint32 code, rcode, xcode;
+ afs_int32 tid = i->tid;
+
+ code = xf_rxcall_do_close(X);
+ xcode = AFSVolEndTrans(conn, tid, &rcode);
+ if (!code) code = xcode ? xcode : rcode;
+ return code;
+}
+
+
+afs_uint32 xfopen_rxcall(XFILE *X, int flag, struct rx_call *call)
+{
+ struct rxinfo *i;
+
+ flag &= O_MODE_MASK;
+ if (flag == O_WRONLY) return ERROR_XFILE_WRONLY;
+ memset(X, 0, sizeof(*X));
+ if (!(i = (struct rxinfo *)malloc(sizeof(struct rxinfo)))) return ENOMEM;
+ i->call = call;
+ i->code = 0;
+ X->do_read = xf_rxcall_do_read;
+ X->do_write = xf_rxcall_do_write;
+ X->do_close = xf_rxcall_do_close;
+ X->is_writable = (flag == O_RDWR);
+ X->refcon = i;
+ return 0;
+}
+
+
+afs_uint32 xfopen_voldump(XFILE *X, struct rx_connection *conn,
+ afs_int32 part, afs_int32 volid, afs_int32 date)
+{
+ struct rx_call *call;
+ struct rxinfo *i;
+ afs_uint32 code, rcode;
+ afs_int32 tid;
+
+ if (code = AFSVolTransCreate(conn, volid, part, ITBusy, &tid)) return code;
+ call = rx_NewCall(conn);
+ if ((code = StartAFSVolDump(call, tid, date))
+ || (code = xfopen_rxcall(X, O_RDONLY, call))) {
+ rx_EndCall(call, 0);
+ AFSVolEndTrans(conn, tid, &rcode);
+ return code;
+ }
+
+ i = X->refcon;
+ i->conn = conn;
+ i->tid = tid;
+ X->do_close = xf_voldump_do_close;
+ return 0;
+}
+
+
+afs_uint32 xfon_voldump(XFILE *X, int flag, char *name)
+{
+ struct hostent *he;
+ struct rx_securityClass *class;
+ struct rx_connection *conn;
+ struct ktc_principal sname;
+ struct ktc_token token;
+ struct afsconf_dir *confdir;
+ afs_uint32 code, server_addr;
+ afs_int32 volid, partid, date;
+ int isnum, index;
+ char *x, *y;
+
+ /* Parse out the optional date and server location */
+ if (code = rx_Init(0)) return code;
+ if (!(name = strdup(name))) return ENOMEM;
+ if (x = strrchr(name, ',')) {
+ *x++ = 0;
+ date = atoi(x);
+ } else {
+ date = 0;
+ }
+ if (x = strrchr(name, '@')) {
+ int a, b, c, d;
+
+ *x++ = 0;
+ if (!(y = strchr(x, '/'))) {
+ free(name);
+ return VL_BADPARTITION;
+ }
+ *y++ = 0;
+ if (sscanf(x, "%d.%d.%d.%d", &a, &b, &c, &d) == 4
+ && a >= 0 && a <= 255 && b >= 0 && b <= 255
+ && c >= 0 && c <= 255 && d >= 0 && d <= 255) {
+ server_addr = (a << 24) | (b << 16) | (c << 8) | d;
+ server_addr = htonl(server_addr);
+ } else {
+ he = gethostbyname(x);
+ if (!he) {
+ free(name);
+ return VL_BADSERVER;
+ }
+ memcpy(&server_addr, he->h_addr, sizeof(server_addr));
+ }
+ partid = volutil_GetPartitionID(y);
+ if (partid < 0) {
+ free(name);
+ return VL_BADPARTITION;
+ }
+ }
+
+ /* Get tokens and set up a security object */
+ confdir = afsconf_Open(AFSCONF_CLIENTNAME);
+ if (!confdir) {
+ free(name);
+ return AFSCONF_NODB;
+ }
+ if (code = afsconf_GetLocalCell(confdir, sname.cell, MAXKTCNAMELEN)) {
+ free(name);
+ return code;
+ }
+ afsconf_Close(confdir);
+ strcpy(sname.name, "afs");
+ sname.instance[0] = 0;
+ code = ktc_GetToken(&sname, &token, sizeof(token), 0);
+ if (code) {
+ class = rxnull_NewClientSecurityObject();
+ index = 0;
+ } else {
+ class = rxkad_NewClientSecurityObject(rxkad_clear, &token.sessionKey,
+ token.kvno, token.ticketLen, token.ticket);
+ index = 2;
+ }
+
+ /* Figure out the volume ID, looking it up in the VLDB if neccessary.
+ * Also look up the server and partition, if they were not specified.
+ */
+ for (isnum = 1, y = name; *y; y++)
+ if (*y < '0' || *y > '9') isnum = 0;
+ if (isnum) {
+ volid = atoi(name);
+ if (!x) {
+ fprintf(stderr, "XXX: need to lookup volume by ID!\n");
+ exit(-1);
+ }
+ } else {
+ fprintf(stderr, "XXX: need to lookup volume by name!\n");
+ exit(-1);
+ }
+ free(name);
+
+ /* Establish a connection and start the call */
+ conn = rx_NewConnection(server_addr, htons(AFSCONF_VOLUMEPORT),
+ VOLSERVICE_ID, class, index);
+ return xfopen_voldump(X, conn, partid, volid, date);
+}
--- /dev/null
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/* xfiles.c - General support routines for xfiles */
+#include <sys/types.h>
+#include <string.h>
+#include <errno.h>
+
+#include "xfiles.h"
+#include "xf_errs.h"
+
+#define SKIP_SIZE 65536
+
+extern afs_uint32 xfon_path(XFILE *, int, char *);
+extern afs_uint32 xfon_fd(XFILE *, int, char *);
+extern afs_uint32 xfon_voldump(XFILE *, int, char *);
+extern afs_uint32 xfon_profile(XFILE *, int, char *);
+extern afs_uint32 xfon_stdio(XFILE *, int);
+
+struct xftype {
+ struct xftype *next;
+ char *name;
+ afs_uint32 (*do_on)(XFILE *, int, char *);
+};
+
+
+static struct xftype *xftypes = 0;
+static int did_register_defaults = 0;
+
+
+afs_uint32 xfread(XFILE *X, void *buf, afs_uint32 count)
+{
+ afs_uint32 code;
+ u_int64 tmp64;
+
+ code = (X->do_read)(X, buf, count);
+ if (code) return code;
+
+ add64_32(tmp64, X->filepos, count);
+ cp64(X->filepos, tmp64);
+ if (X->passthru) return xfwrite(X->passthru, buf, count);
+ return 0;
+}
+
+
+afs_uint32 xfwrite(XFILE *X, void *buf, afs_uint32 count)
+{
+ afs_uint32 code;
+ u_int64 tmp64;
+
+ if (!X->is_writable) return ERROR_XFILE_RDONLY;
+ code = (X->do_write)(X, buf, count);
+ if (code) return code;
+
+ add64_32(tmp64, X->filepos, count);
+ cp64(X->filepos, tmp64);
+ return 0;
+}
+
+
+afs_uint32 xftell(XFILE *X, u_int64 *offset)
+{
+ if (X->do_tell) return (X->do_tell)(X, offset);
+ cp64(*offset, X->filepos);
+ return 0;
+}
+
+
+afs_uint32 xfseek(XFILE *X, u_int64 *offset)
+{
+ afs_uint32 code;
+
+ if (!X->do_seek) return ERROR_XFILE_NOSEEK;
+ code = (X->do_seek)(X, offset);
+ if (code) return code;
+ cp64(X->filepos, *offset);
+ return 0;
+}
+
+
+afs_uint32 xfskip(XFILE *X, afs_uint32 count)
+{
+ afs_uint32 code;
+ u_int64 tmp64;
+
+ /* Use the skip method, if there is one */
+ if (X->do_skip && !X->passthru) {
+ code = (X->do_skip)(X, count);
+ if (code) return code;
+ add64_32(tmp64, X->filepos, count);
+ cp64(X->filepos, tmp64);
+ return 0;
+ }
+
+ /* Simulate using absolute seek, if available */
+ if (X->do_seek && !X->passthru) {
+ if (code = xftell(X, &tmp64)) return code;
+ add64_32(X->filepos, tmp64, count);
+ cp64(tmp64, X->filepos);
+ return xfseek(X, &tmp64);
+ }
+
+ /* Do it the hard/slow way - read all the data to be skipped.
+ * This is done if no other method is available, or if we are
+ * supposed to be copying all the data to another XFILE
+ */
+ {
+ char buf[SKIP_SIZE];
+ afs_uint32 n;
+
+ while (count) {
+ n = (count > SKIP_SIZE) ? SKIP_SIZE : count;
+ if (code = xfread(X, buf, n)) return code;
+ count -= n;
+ }
+ return 0;
+ }
+}
+
+
+afs_uint32 xfpass(XFILE *X, XFILE *Y)
+{
+ if (X->passthru) return ERROR_XFILE_ISPASS;
+ if (!Y->is_writable) return ERROR_XFILE_RDONLY;
+ X->passthru = Y;
+ return 0;
+}
+
+
+afs_uint32 xfunpass(XFILE *X)
+{
+ if (!X->passthru) return ERROR_XFILE_NOPASS;
+ X->passthru = 0;
+ return 0;
+}
+
+
+afs_uint32 xfclose(XFILE *X)
+{
+ int code = 0;
+
+ if (X->do_close) code = (X->do_close)(X);
+ memset(X, 0, sizeof(*X));
+ return 0;
+}
+
+
+afs_uint32 xfregister(char *name, afs_uint32 (*do_on)(XFILE *, int, char *))
+{
+ struct xftype *x;
+
+ if (!(x = (struct xftype *)malloc(sizeof(struct xftype)))) return ENOMEM;
+ memset(x, 0, sizeof(*x));
+ x->next = xftypes;
+ x->name = name;
+ x->do_on = do_on;
+ xftypes = x;
+}
+
+
+static void register_default_types(void)
+{
+ xfregister("FILE", xfon_path);
+ xfregister("FD", xfon_fd);
+ xfregister("AFSDUMP", xfon_voldump);
+ xfregister("PROFILE", xfon_profile);
+ did_register_defaults = 1;
+}
+
+
+afs_uint32 xfopen(XFILE *X, int flag, char *name)
+{
+ struct xftype *x;
+ char *type, *sep;
+
+ if (!did_register_defaults) register_default_types();
+ if (!strcmp(name, "-")) return xfon_stdio(X, flag);
+
+ for (type = name; *name && *name != ':'; name++);
+ if (*name) {
+ sep = name;
+ *name++ = 0;
+ } else {
+ sep = 0;
+ name = type;
+ type = "FILE";
+ }
+
+ for (x = xftypes; x; x = x->next)
+ if (!strcmp(type, x->name)) break;
+ if (sep) *sep = ':';
+ if (x) return (x->do_on)(X, flag, name);
+ return ERROR_XFILE_TYPE;
+}
--- /dev/null
+/*
+ * CMUCS AFStools
+ * dumpscan - routines for scanning and manipulating AFS volume dumps
+ *
+ * Copyright (c) 1998 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+/* xfiles.h - Type, constant, and function declarations for
+ * extensible file-like things */
+
+#ifndef _XFILES_H_
+#define _XFILES_H_
+
+#include <stdio.h>
+#include <stdarg.h>
+#include "intNN.h"
+
+struct rx_call;
+struct rx_connection;
+
+/* The XFILE structure */
+typedef struct XFILE XFILE;
+struct XFILE {
+ afs_uint32 (*do_read)(XFILE *, void *, afs_uint32); /* read data */
+ afs_uint32 (*do_write)(XFILE *, void *, afs_uint32); /* write data */
+ afs_uint32 (*do_tell)(XFILE *, u_int64 *); /* find position */
+ afs_uint32 (*do_seek)(XFILE *, u_int64 *); /* set position */
+ afs_uint32 (*do_skip)(XFILE *, afs_uint32); /* skip forward */
+ afs_uint32 (*do_close)(XFILE *); /* close */
+ u_int64 filepos; /* position (counted) */
+ int is_seekable; /* 1 if seek works */
+ int is_writable; /* 1 if write works */
+ XFILE *passthru; /* XFILE to pass thru to */
+ void *refcon; /* type-specific data */
+};
+
+
+/* Functions for opening XFILEs. For these, the first two arguments are
+ * always a pointer to an XFILE to fill in, and the mode in which to
+ * open the file. O_RDONLY and O_RDWR are permitted; O_WRONLY is not.
+ * Other open modes may or may not be used, depending on the object type.
+ * Remaining arguments are a function of the object type
+ */
+extern afs_uint32 xfopen (XFILE *, int, char *); /* open by TYPE:name */
+extern afs_uint32 xfopen_path(XFILE *, int, char *, int); /* open by path */
+extern afs_uint32 xfopen_FILE(XFILE *, int, FILE *); /* open by FILE * */
+extern afs_uint32 xfopen_fd (XFILE *, int, int); /* open by fd */
+extern afs_uint32 xfopen_rxcall (XFILE *, int, struct rx_call *);
+extern afs_uint32 xfopen_voldump(XFILE *, struct rx_connection *,
+ afs_int32, afs_int32, afs_int32);
+extern afs_uint32 xfopen_profile(XFILE *, int, char *, char *);
+
+extern afs_uint32 xfregister(char *, afs_uint32 (*)(XFILE *, int, char *));
+
+/* Standard operations on XFILEs */
+extern afs_uint32 xfread(XFILE *, void *, afs_uint32); /* read data */
+extern afs_uint32 xfwrite(XFILE *, void *, afs_uint32); /* write data */
+extern afs_uint32 xfprintf(XFILE *, char *, ...); /* formatted */
+extern afs_uint32 vxfprintf(XFILE *, char *, va_list); /* formatted VA */
+extern afs_uint32 xftell(XFILE *, u_int64 *); /* get position */
+extern afs_uint32 xfseek(XFILE *, u_int64 *); /* set position */
+extern afs_uint32 xfskip(XFILE *, afs_uint32); /* skip forward */
+extern afs_uint32 xfpass(XFILE *, XFILE *); /* set passthru */
+extern afs_uint32 xfunpass(XFILE *); /* unset passthru */
+extern afs_uint32 xfclose(XFILE *); /* close */
+
+#endif /* _XFILES_H_ */