There is a utility (restorevol) in OpenAFS to unpack a vos dump image
into a file tree, but I wanted something to just give me a listing of
what files/directories were in the volume, so I hacked up the attached,
which adds "tocvol" to the OpenAFS tree to do a table of contents of a
vos dump image.

Why did I want this? I'm working on integrating AFS backups into 
Amanda, and I wanted a table of contents of the volume dump so
I can have file level backup indexing...

Anyway, it's mostly restorevol with most of its guts replaced with
a (wimpy, horribly inefficient, but simple) vnode graph.


*** src/volser/Makefile.in.orig	Thu May  9 11:43:41 2002
--- src/volser/Makefile.in	Thu May  9 11:42:21 2002
***************
*** 8,14 ****
  srcdir=@srcdir@
  include @TOP_OBJDIR@/src/config/Makefile.config
  
- 
  CFLAGS=-I. -I${srcdir} ${DBG} ${OPTMZ} -I${TOP_OBJDIR}/src/config -I${TOP_INCDIR} ${XCFLAGS}
  LDFLAGS=${DBG} ${OPTMZ} ${XLDFLAGS}
  
--- 8,13 ----
***************
*** 48,54 ****
  SOBJS=volmain.o volprocs.o physio.o common.o voltrans.o volerr.o \
   volint.cs.o dumpstuff.o volint.ss.o volint.xdr.o
  
! all: volserver vos restorevol \
  	${TOP_INCDIR}/afs/volser.h \
  	${TOP_INCDIR}/afs/volint.h \
  	${TOP_LIBDIR}/libvolser.a
--- 47,53 ----
  SOBJS=volmain.o volprocs.o physio.o common.o voltrans.o volerr.o \
   volint.cs.o dumpstuff.o volint.ss.o volint.xdr.o
  
! all: volserver vos restorevol tocvol \
  	${TOP_INCDIR}/afs/volser.h \
  	${TOP_INCDIR}/afs/volint.h \
  	${TOP_LIBDIR}/libvolser.a
***************
*** 57,62 ****
--- 56,65 ----
  	${CC} ${CFLAGS} -o restorevol ${srcdir}/restorevol.c \
  		${TOP_LIBDIR}/libcmd.a ${TOP_LIBDIR}/util.a
  
+ tocvol: tocvol.c
+ 	${CC} ${CFLAGS} -o tocvol ${srcdir}/tocvol.c \
+ 		${TOP_LIBDIR}/libcmd.a ${TOP_LIBDIR}/util.a
+ 
  vos: vos.o ${VSOBJS} libvolser.a ${LIBS}
  	${CC} ${LDFLAGS} -o vos vos.o $(VSOBJS) libvolser.a ${LIBS} ${XLIBS}
  
***************
*** 111,116 ****
--- 114,120 ----
  #
  install: \
  	${DESTDIR}${sbindir}/restorevol \
+ 	${DESTDIR}${sbindir}/tocvol \
  	${DESTDIR}${includedir}/afs/volser.h \
  	${DESTDIR}${includedir}/afs/volint.h \
  	${DESTDIR}${sbindir}/vos \
***************
*** 126,131 ****
--- 130,138 ----
  	${INSTALL} $? $@
  
  ${DEST}/etc/restorevol: restorevol
+ 	${INSTALL} $? $@
+ 
+ ${DEST}/etc/tocvol: tocvol
  	${INSTALL} $? $@
  
  ${DEST}/etc/vos ${DEST}/root.server/usr/afs/bin/vos: vos
*** src/volser/tocvol.c.orig	Thu May  9 13:54:52 2002
--- src/volser/tocvol.c	Thu May  9 13:58:11 2002
***************
*** 0 ****
--- 1,715 ----
+ /*
+  * Copyright 2000, International Business Machines Corporation and others.
+  * All Rights Reserved.
+  * 
+  * This software has been released under the terms of the IBM Public
+  * License.  For details, see the LICENSE file in the top-level source
+  * directory or online at http://www.openafs.org/dl/license10.html
+  */
+ 
+ /*
+  * Read a vos dump and print a table of contents
+  *
+  * tocvol [-file <dump file>]
+  *            [-dir <restore dir>]
+  *            [-extension <name extension>]
+  *            [-mountpoint <mount point root>]
+  *            [-umask <mode mask>]
+  * Based on restorevol, but with an internal index instead of symlinks.
+  *
+  */
+ 
+ #include <afsconfig.h>
+ #include <afs/param.h>
+ 
+ RCSID("$Header: /cvs/openafs/src/volser/restorevol.c,v 1.6 2001/08/08 00:04:26 shadow Exp $");
+ 
+ #include <afs/afsint.h>
+ #include <afs/nfs.h>
+ #include <lock.h>
+ #include <afs/ihandle.h>
+ #include <afs/vnode.h>
+ #include <afs/volume.h>
+ #include "volint.h"
+ #include "dump.h"
+ #include <afs/cmd.h>
+ 
+ #include <sys/param.h>
+ #include <sys/types.h>
+ #include <sys/uio.h>
+ #include <stdio.h>
+ #include <errno.h>
+ #include <netinet/in.h>
+ #include <sys/stat.h>
+ #include <fcntl.h>
+ #include <dirent.h>
+ 
+ struct vmapnode {
+ 	char *name;
+ 	int parent;
+ 	char printed;
+ 	char isset;
+ } *vnodemap = 0;
+ int  vnodemaplen = 0;
+ int  vnodemapmax = 0;
+ 
+ growvnodemap(int n) {
+     int i;
+     if (n > vnodemapmax) {
+ 	vnodemapmax = 2 * n;
+ 	/* fprintf(stderr,"growing map to %d\n", vnodemapmax); */
+         /* fflush(stderr); */
+ 	vnodemap = realloc(vnodemap, sizeof(struct vmapnode) * vnodemapmax );
+ 	for ( i = vnodemaplen+1; i < vnodemapmax; i++ )
+              vnodemap[i].isset = 0;
+     }
+     if (n > vnodemaplen)
+ 	vnodemaplen = n;
+ }
+ 
+ void
+ setvnode(int n, char *name, int parent) {
+     /* fprintf(stderr, "setting map for %d to %s parent %d\n", n, name, parent); */
+     /* fflush(stderr); */
+     growvnodemap(n);
+     vnodemap[n].name = (char *)strdup(name);
+     vnodemap[n].parent = parent;
+     vnodemap[n].isset = 1;
+ }
+ 
+ int
+ getvnodename(int n, char *p, int max) {
+     int len, nlen;
+     /* printf("getvnodename(%d)\n", n); */
+     if( vnodemap[n].isset ) {
+ 	nlen = strlen(vnodemap[n].name);
+ 	if (n != 1 && vnodemap[n].parent != n ) {
+ 	    len = getvnodename(vnodemap[n].parent, p, max);
+ 	} else { 
+ 	    /* root vnode */
+ 	    p[0] = '.';
+ 	    p[1] = 0;
+ 	    return 1;
+         }
+ 	if (len != 0 && len + nlen + 1 < max) {
+ 	    strcat(p+len, "/");
+ 	    strcat(p+len, vnodemap[n].name);
+ 	    return len + nlen + 1;
+ 	}
+     } else { 
+ 	/* printf("notset\n") */;
+     }
+     return 0;
+ }
+ 
+ int printvnode(int n) {
+     char buf[1024];
+     int len;
+     /* printf ("printvnode %d\n", n); */
+     if (!vnodemap[n].printed && vnodemap[n].isset) {
+ 	len = getvnodename(n, buf, 1024);
+ 	if( len != 0 ) {
+ 	    printf("%s\n", buf);
+ 	    vnodemap[n].printed = 1;
+ 	}   
+     }
+ }
+ 
+ int  inc_dump = 0;
+ 
+ FILE *dumpfile;
+ 
+ afs_int32 readvalue(size)
+ {
+   afs_int32 value, s;
+   int   code;
+   char  *ptr;
+ 
+   value = 0;
+   ptr = (char *) &value;
+ 
+   s = sizeof(value) - size;
+   if (size < 0) {
+       fprintf (stderr, "Too much data in afs_int32\n");
+       return 0;
+   }
+   
+   code = fread (&ptr[s], 1, size, dumpfile);
+   if (code != size) fprintf (stderr, "Code = %d; Errno = %d\n", code, errno);
+ 
+   return (value);
+ }
+ 
+ char readchar()
+ {
+   char  value;
+   int   code;
+   char  *ptr;
+ 
+   value = '\0';
+   code = fread (&value, 1, 1, dumpfile);
+   if (code != 1) fprintf (stderr, "Code = %d; Errno = %d\n", code, errno);
+ 
+   return (value);
+ }
+ 
+ #define BUFSIZE 16384
+ char buf[BUFSIZE];
+ 
+ char readdata(buffer, size)
+   char  *buffer;
+   afs_int32 size;
+ {
+   int   code;
+   afs_int32 s;
+ 
+   if (!buffer) {
+       while (size > 0) {
+ 	  s = ((size > BUFSIZE) ? BUFSIZE : size);
+ 	  code = fread(buf, 1, s, dumpfile);
+ 	  if (code != s) fprintf (stderr, "Code = %d; Errno = %d\n", code, errno);
+ 	  size -= s;
+       }
+   }
+   else {
+       code = fread (buffer, 1, size, dumpfile);
+       if (code != size) {
+ 	 if (code < 0)
+ 	    fprintf (stderr, "Code = %d; Errno = %d\n", code, errno);
+ 	 else 
+ 	    fprintf (stderr, "Read %d bytes out of %d\n", code, size);
+       }
+       if ((code >= 0) && (code < BUFSIZE))
+ 	 buffer[size] = 0;      /* Add null char at end */
+   }
+ }
+ 
+ afs_int32 ReadDumpHeader(dh)
+   struct DumpHeader *dh;                  /* Defined in dump.h */
+ {
+   int               code, i, done;
+   char              tag, c;
+   afs_int32             magic;
+ 
+ /*  memset(&dh, 0, sizeof(dh)); */
+ 
+   magic   = ntohl(readvalue(4));
+   dh->version = ntohl(readvalue(4));
+ 
+   done = 0;
+   while (!done) {
+       tag = readchar();
+       switch (tag) {
+           case 'v':
+ 	      dh->volumeId = ntohl(readvalue(4));
+ 	      break;
+ 
+ 	  case 'n':
+ 	      for (i=0, c='a'; c!='\0'; i++) {
+ 		  dh->volumeName[i] = c = readchar();
+ 	      }
+ 	      dh->volumeName[i] = c;
+ 	      break;
+ 
+ 	  case 't':
+ 	      dh->nDumpTimes = ntohl(readvalue(2)) >> 1;
+ 	      for (i=0; i<dh->nDumpTimes; i++) {
+ 		  dh->dumpTimes[i].from = ntohl(readvalue(4));
+ 		  dh->dumpTimes[i].to   = ntohl(readvalue(4));
+ 	      }
+ 	      break;
+ 
+ 	  default:
+ 	      done = 1;
+ 	      break;
+       }
+   }
+ 
+   return((afs_int32)tag);
+ }
+ 
+ struct volumeHeader
+ {
+   afs_int32         volumeId;
+   char          volumeName[100];
+   afs_int32         volType;
+   afs_int32         uniquifier;
+   afs_int32         parentVol;
+   afs_int32         cloneId;
+   afs_int32         maxQuota;
+   afs_int32         minQuota;
+   afs_int32         diskUsed;
+   afs_int32         fileCount;
+   afs_int32         accountNumber;
+   afs_int32         owner;
+   afs_int32         creationDate;
+   afs_int32         accessDate;
+   afs_int32         updateDate;
+   afs_int32         expirationDate;
+   afs_int32         backupDate;
+   afs_int32         dayUseDate;
+   afs_int32         dayUse;
+   afs_int32         weekCount;
+   afs_int32         weekUse[100];    /* weekCount of these */
+   char          motd[1024];
+   int           inService;
+   int           blessed;
+   char          message[1024];
+ };
+ 
+ afs_int32 ReadVolumeHeader(count)
+   afs_int32 count;
+ {
+   struct volumeHeader vh;
+   int               code, i, done, entries;
+   char              tag, c;
+ 
+ /*  memset(&vh, 0, sizeof(vh)); */
+ 
+   done = 0;
+   while (!done) {
+       tag = readchar();
+       switch (tag) {
+           case 'i':
+ 	      vh.volumeId = ntohl(readvalue(4));
+ 	      break;
+ 
+ 	  case 'v':
+ 	      ntohl(readvalue(4));   /* version stamp - ignore */
+               break;
+ 
+ 	  case 'n':
+ 	      for (i=0, c='a'; c!='\0'; i++) {
+ 		  vh.volumeName[i] = c = readchar();
+ 	      }
+ 	      vh.volumeName[i] = c;
+ 	      break;
+ 
+ 	  case 's':
+ 	      vh.inService = ntohl(readvalue(1));
+ 	      break;
+ 
+ 	  case 'b':
+ 	      vh.blessed = ntohl(readvalue(1));
+ 	      break;
+ 
+ 	  case 'u':
+ 	      vh.uniquifier = ntohl(readvalue(4));
+               break;
+ 
+ 	  case 't':
+ 	      vh.volType = ntohl(readvalue(1));
+               break;
+ 
+ 	  case 'p':
+ 	      vh.parentVol = ntohl(readvalue(4));
+               break;
+ 
+ 	  case 'c':
+ 	      vh.cloneId = ntohl(readvalue(4));
+               break;
+ 
+ 	  case 'q':
+ 	      vh.maxQuota = ntohl(readvalue(4));
+               break;
+ 
+ 	  case 'm':
+ 	      vh.minQuota = ntohl(readvalue(4));
+               break;
+ 
+ 	  case 'd':
+ 	      vh.diskUsed = ntohl(readvalue(4));
+               break;
+ 
+ 	  case 'f':
+ 	      vh.fileCount = ntohl(readvalue(4));
+               break;
+ 
+ 	  case 'a':
+ 	      vh.accountNumber = ntohl(readvalue(4));
+               break;
+ 
+ 	  case 'o':
+ 	      vh.owner = ntohl(readvalue(4));
+               break;
+ 
+ 	  case 'C':
+ 	      vh.creationDate = ntohl(readvalue(4));
+               break;
+ 
+ 	  case 'A':
+ 	      vh.accessDate = ntohl(readvalue(4));
+               break;
+ 
+ 	  case 'U':
+ 	      vh.updateDate = ntohl(readvalue(4));
+               break;
+ 
+ 	  case 'E':
+ 	      vh.expirationDate = ntohl(readvalue(4));
+               break;
+ 
+ 	  case 'B':
+ 	      vh.backupDate = ntohl(readvalue(4));
+               break;
+ 
+ 	  case 'O':
+ 	      for (i=0, c='a'; c!='\0'; i++) {
+ 		  vh.message[i] = c = readchar();
+ 	      }
+ 	      vh.volumeName[i] = c;
+ 	      break;
+ 
+ 	  case 'W':
+ 	      vh.weekCount = ntohl(readvalue(2));
+ 	      for (i=0; i<vh.weekCount; i++) {
+ 		  vh.weekUse[i] = ntohl(readvalue(4));
+ 	      }
+ 	      break;
+ 
+ 	  case 'M':
+ 	      for (i=0, c='a'; c!='\0'; i++) {
+ 		  vh.motd[i] = c = readchar();
+ 	      }
+ 	      break;
+ 
+ 	  case 'D':
+ 	      vh.dayUseDate = ntohl(readvalue(4));
+               break;
+ 
+ 	  case 'Z':
+ 	      vh.dayUse = ntohl(readvalue(4));
+               break;
+ 
+ 	  default:
+ 	      done = 1;
+ 	      break;
+       }
+   }
+ 
+   return((afs_int32)tag);
+ }
+ 
+ struct vNode
+ {
+   afs_int32 vnode;
+   afs_int32 uniquifier;
+   afs_int32 type;
+   afs_int32 linkCount;
+   afs_int32 dataVersion;
+   afs_int32 unixModTime;
+   afs_int32 servModTime;
+   afs_int32 author;
+   afs_int32 owner;
+   afs_int32 group;
+   afs_int32 modebits;
+   afs_int32 parent;
+   char acl[192];
+ #ifdef notdef
+   struct acl_accessList 
+   {
+     int size;           /*size of this access list in bytes, including MySize itself*/    
+     int version;        /*to deal with upward compatibility ; <= ACL_ACLVERSION*/
+     int total;
+     int positive;       /* number of positive entries */
+     int negative;       /* number of minus entries */
+     struct acl_accessEntry 
+     {
+       int id;         /*internally-used ID of user or group*/
+       int rights;     /*mask*/
+     } entries[100];
+   } acl;
+ #endif
+   afs_int32 dataSize;
+ };
+ 
+ #define MAXNAMELEN 256
+ 
+ afs_int32 ReadVNode(count, tocflag)
+   afs_int32 count;
+   int tocflag;
+ {
+   struct vNode      vn;
+   int               code, i, done, entries;
+   char              tag, c;
+   char              dirname[MAXNAMELEN], linkname[MAXNAMELEN], lname[MAXNAMELEN];
+   char              parentdir[MAXNAMELEN], vflink[MAXNAMELEN];
+   char              filename[MAXNAMELEN], fname[MAXNAMELEN];
+   int               len;
+   afs_int32             vnode;
+   afs_int32             mode=0;
+ 
+ /*  memset(&vn, 0, sizeof(vn)); */
+   vn.dataSize = 0;
+   vn.vnode = 0;
+   vn.parent = 0;
+   vn.type = 0;
+ 
+   vn.vnode = ntohl(readvalue(4));
+   vn.uniquifier = ntohl(readvalue(4));
+   
+   done = 0;
+   while (!done) {
+       tag = readchar();
+       switch (tag) {
+           case 't':
+ 	      vn.type = ntohl(readvalue(1));
+ 	      break;
+ 
+           case 'l':
+ 	      vn.linkCount = ntohl(readvalue(2));
+ 	      break;
+ 
+           case 'v':
+ 	      vn.dataVersion = ntohl(readvalue(4));
+ 	      break;
+ 
+           case 'm':
+ 	      vn.unixModTime = ntohl(readvalue(4));
+ 	      break;
+ 
+           case 's':
+ 	      vn.servModTime = ntohl(readvalue(4));
+ 	      break;
+ 
+           case 'a':
+ 	      vn.author = ntohl(readvalue(4));
+ 	      break;
+ 
+           case 'o':
+ 	      vn.owner = ntohl(readvalue(4));
+ 	      break;
+ 
+           case 'g':
+ 	      vn.group = ntohl(readvalue(4));
+ 	      break;
+ 
+           case 'b':
+ 	      vn.modebits = ntohl(readvalue(2));
+ 	      break;
+ 
+           case 'p':
+ 	      vn.parent = ntohl(readvalue(4));
+ 	      break;
+ 
+           case 'A':
+ 	      readdata(vn.acl, 192);             /* Skip ACL data */
+ 	      break;
+ 
+           case 'f':
+ 	      vn.dataSize = ntohl(readvalue(4));
+ 
+ 	      /* parentdir is the name of this dir's vnode-file-link
+ 	       * or this file's parent vnode-file-link.
+ 	       * "./AFSDir-<#>". It's a symbolic link to its real dir.
+ 	       * The parent dir and symbolic link to it must exist.
+ 	       */
+ 	      vnode = ((vn.type == 2) ? vn.vnode : vn.parent);
+ 
+ 	      if (vn.type == 2) {
+ 		  /*ITSADIR*/
+ 		  /* We read the directory entries. If the entry is a
+ 		   * directory, the subdir is created and the root dir
+ 		   * will contain a link to it. If its a file, we only
+ 		   * create a symlink in the dir to the file name.
+ 		   */
+ 		  char           *buffer;
+ 		  unsigned short j;
+ 		  afs_int32          this_vn;
+ 		  char           *this_name;
+ 
+ 		  struct DirEntry
+ 		  {
+ 		      char flag;
+ 		      char length;
+ 		      unsigned short next;
+ 		      struct MKFid
+ 		      {
+ 			  afs_int32 vnode;
+ 			  afs_int32 vunique;
+ 		      } fid;
+ 		      char name[20];
+ 		  };
+ 
+ 		  struct Pageheader
+ 		  {
+ 		      unsigned short pgcount;
+ 		      unsigned short tag;
+ 		      char           freecount;
+ 		      char           freebitmap[8];
+ 		      char           padding[19];
+ 		  };
+ 
+ 		  struct DirHeader
+ 		  {
+ 		      struct Pageheader  header;
+ 		      char               alloMap[128];
+ 		      unsigned short     hashTable[128];
+ 		  };
+ 
+ 		  struct Page0
+ 		  {
+ 		      struct DirHeader header;
+ 		      struct DirEntry  entry[1];
+ 		  } *page0;
+ 		  
+ 
+ 		  buffer = (char *)0;
+ 		  buffer = (char *)malloc(vn.dataSize);
+ 
+ 		  readdata(buffer, vn.dataSize);
+ 		  page0 = (struct Page0 *)buffer;
+ 
+ 		  /* Step through each bucket in the hash table, i,
+ 		   * and follow each element in the hash chain, j.
+ 		   * This gives us each entry of the dir.
+ 		   */
+ 		  for (i=0; i<128; i++) {
+ 		     for (j=ntohs(page0->header.hashTable[i]); j;
+ 			  j=ntohs(page0->entry[j].next)) {
+ 		        j -= 13;
+ 			this_vn   = ntohl(page0->entry[j].fid.vnode);
+ 			this_name = page0->entry[j].name;
+ 
+ 			if ((strcmp(this_name,"." ) == 0) ||
+ 			    (strcmp(this_name,"..") == 0))
+ 			   continue;                      /* Skip these */
+ 
+ 		       setvnode(this_vn,this_name, vnode);
+ 		       printvnode(this_vn);
+ 		     }
+ 		  }
+ 		  free(buffer);
+ 	      } /*ITSADIR*/
+ 
+ 	      else if (vn.type == 1) {
+ 		  /*ITSAFILE*/
+ 		  /* A file vnode. So create it into the desired directory. A
+ 		   * link should exist in the directory naming the file.
+ 		   */
+ 		  int fid;
+ 		  int lfile;
+ 		  afs_int32 size, s;
+ 
+ 		  size = vn.dataSize;
+ 		  while (size > 0) {
+ 		     s = ((size > BUFSIZE) ? BUFSIZE : size);
+ 		     code = fread(buf, 1, s, dumpfile);
+ 		     if (code > 0) {
+ 			size -= code;
+ 		     }
+ 		     if (code != s) {
+ 		        if (code < 0)
+ 			   fprintf (stderr, "Code = %d; Errno = %d\n", code, errno);
+ 			else 
+ 			   fprintf (stderr, "Read %d bytes out of %d\n", 
+ 				    (vn.dataSize - size), vn.dataSize);
+ 			break;
+ 		     }
+ 		  }
+ 		  if (size != 0) {
+ 		     fprintf(stderr, "   File %s (%s) is incomplete\n", filename, fname);
+ 		  }
+ 
+ 	      } /*ITSAFILE*/
+ 
+ 	      else if (vn.type == 3) {
+ 		  /*ITSASYMLINK*/
+ 		  /* A symlink vnode. So read it into the desired directory. This could
+ 		   * also be a mount point. If the volume is being restored to AFS, this
+ 		   * will become a mountpoint. If not, it becomes a symlink to no-where.
+ 		   */
+ 		  int fid;
+ 		  afs_int32 size, s;
+ 
+ 		  /* Check if its vnode-file-link exists and create pathname
+ 		   * of the symbolic link. If it doesn't exist,
+ 		   * then the link will be an orphaned link.
+ 		   */
+ 		  /* Read the link in */
+ 		  readdata(buf, vn.dataSize);
+ 	      }	/*ITSASYMLINK*/
+ 	      else {
+ 		 fprintf (stderr, "Unknown Vnode block\n");
+ 	      }
+ 	      break;
+ 
+ 	  default:
+ 	      done = 1;
+ 	      break;
+       }
+   }
+   if (vn.type == 0)
+      inc_dump = 1;
+ 
+   return((afs_int32)tag);
+ }
+ 
+ WorkerBee(as, arock)
+   struct cmd_syndesc *as;
+   char *arock;
+ {
+   int    code=0, c, len;
+   afs_int32  type, count, vcount;
+   DIR           *dirP, *dirQ;
+   struct dirent *dirE, *dirF;
+   char   fname[MAXNAMELEN], name[MAXNAMELEN], lname[MAXNAMELEN], mname[MAXNAMELEN];
+   char   thisdir[MAXPATHLEN], *t;
+   struct DumpHeader dh;                  /* Defined in dump.h */
+ #if 0/*ndef HAVE_GETCWD*/ /* XXX enable when autoconf happens */
+   extern char *getwd();
+ #define getcwd(x,y) getwd(x)
+ #endif
+   
+   if (as->parms[0].items) {                         /* -file <dumpfile> */
+      dumpfile = fopen(as->parms[0].items->data, "r");
+      if (!dumpfile) {
+         fprintf(stderr, "Cannot open '%s'. Code = %d\n",
+ 		as->parms[0].items->data, errno);
+ 	goto cleanup;
+      }
+   } else {
+      dumpfile = (FILE *)stdin;                     /* use stdin */
+   }
+ 
+   /* Read the dump header. From it we get the volume name */
+   type = ntohl(readvalue(1));
+   if (type != 1) {
+       fprintf(stderr, "Expected DumpHeader\n");
+       code = -1;
+       goto cleanup;
+   }
+   type = ReadDumpHeader(&dh);
+ 
+   fprintf(stderr, "Table of Contents of volume dump of '%s':\n",
+ 	  dh.volumeName);
+ 
+   for (count=1; type==2; count++) {
+       type = ReadVolumeHeader(count);
+       for (vcount=1; type==3; vcount++)
+ 	  type = ReadVNode(vcount, as->parms[5].items);
+   }
+   for (count=1; count < vnodemaplen ; count++ ) {
+       printvnode(count);
+   }
+ 
+ cleanup:
+   return(code);
+ }
+ 
+ main(argc, argv)
+   int  argc;
+   char **argv;
+ {
+   struct cmd_syndesc *ts;
+   struct cmd_item    *ti;
+ 
+   setlinebuf(stdout);
+   setvnode(1,"/",1);
+   printvnode(1);
+ 
+   ts=cmd_CreateSyntax((char *)0, WorkerBee, (char *) 0, "vldb check");
+   cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL, "dump file");
+ 
+   return cmd_Dispatch(argc, argv);
+ }

Reply via email to