Always include afsconfig.h
[openafs.git] / src / tests / dumptool.c
1 /*
2  * $Id$
3  *
4  * dumptool - A tool to manage MR-AFS dump files
5  *
6  * The dump file format ought to be documented _somewhere_, and
7  * this seems like a good as a place as any ...
8  *
9  * A AFS dump file is marked off into a series of sections.  Each
10  * section marked by a dump tag.  A tag is a single byte who's value
11  * corresponds with the next section.  The sections are (in order):
12  *
13  * DUMPHEADER (tag 0x01)
14  * VOLUMEHEADER (tag 0x02)
15  * VNODE (tag 0x03)
16  * DUMPEND (tag 0x04)
17  *
18  * Descriptions of the sections follow.  Note that in all cases, data is
19  * stored in the dump in network byte order.
20  *
21  * DUMPHEADER:
22  *
23  * DUMPHEADER contains two parts: the DUMPMAGIC magic number (32 bits)
24  * and the dump header itself.
25  *
26  * The dump header itself consists of a series of tagged values,
27  * each tag marking out members of the DumpHeader structure.  The
28  * routine ReadDumpHeader explains the specifics of these tags.
29  *
30  * VOLUMEHEADER:
31  *
32  * VOLUMEHEADER is a series of tagged values corresponding to the elements
33  * of the VolumeDiskData structure.  See ReadVolumeHeader for more
34  * information
35  *
36  * VNODE:
37  *
38  * The VNODE section is all vnodes contained in the volume (each vnode
39  * itself is marked with the VNODE tag, so it's really a sequence of
40  * VNODE tags, unlike other sections).
41  *
42  * Each vnode consists of three parts: the vnode number (32 bits), the
43  * uniqifier (32 bits), and a tagged list of elements corresponding to
44  * the elements of the VnodeDiskData structure.  See ScanVnodes for
45  * more information.  Note that if file data is associated with a vnode,
46  * it will be contained here.
47  *
48  * DUMPEND:
49  *
50  * The DUMPEND section consists of one part: the DUMPENDMAGIC magic
51  * number (32 bits).
52  * 
53  * Notes:
54  *
55  * The tagged elements are all ASCII letters, as opposed to the section
56  * headers (which are 0x01, 0x02, ...).  Thus, an easy way to tell when
57  * you've reached the end of an element sequence is to check to see if
58  * the next tag is a printable character (this code tests for < 20).
59  *
60  * "vos dump" dumps the large vnode index, then the small vnode index,
61  * so directories will appear first in the VNODE section.
62  */
63
64 #include <afsconfig.h>
65 #include <afs/param.h>
66
67 #include <stdio.h>
68 #include <sys/types.h>
69 #include <sys/param.h>
70 #include <netinet/in.h>
71 #include <unistd.h>
72 #include <stdlib.h>
73 #include <string.h>
74 #include <errno.h>
75 #include <termios.h>
76 #include <fnmatch.h>
77 #include <fcntl.h>
78
79 #include <lock.h>
80 #include <afs/afsint.h>
81 #include <afs/nfs.h>
82 #include <afs/acl.h>
83 #if !defined(PRE_AFS_36) && !defined(RESIDENCY)
84 #include <afs/ihandle.h>
85 #endif /* !defined(PRE_AFS_36) && !defined(RESIDENCY) */
86 #include <afs/vnode.h>
87 #include <afs/volume.h>
88
89 #ifdef AFS_LINUX24_ENV
90 #define _LARGEFILE64_SOURCE 1
91 #endif
92 #ifdef RESIDENCY
93 #include <afs/rsdefs.h>
94 #include <afs/remioint.h>
95 #endif /* RESIDENCY */
96
97 #include <afs/dir.h>
98
99 /*
100  * Sigh.  Linux blows it again
101  */
102
103 #ifdef linux
104 #include <pty.h>
105 #endif
106
107 /*
108  * Stuff that is in private AFS header files, unfortunately
109  */
110
111 #define DUMPVERSION     1
112 #define DUMPENDMAGIC    0x3A214B6E
113 #define DUMPBEGINMAGIC  0xB3A11322
114 #define D_DUMPHEADER    1
115 #define D_VOLUMEHEADER  2
116 #define D_VNODE         3
117 #define D_DUMPEND       4
118 #define D_MAX           20
119
120 #define MAXDUMPTIMES    50
121
122 struct DumpHeader {
123     int32_t version;
124     VolumeId volumeId;
125     char volumeName[VNAMESIZE];
126     int nDumpTimes;             /* Number of pairs */
127     struct {
128         int32_t from, to;
129     } dumpTimes[MAXDUMPTIMES];
130 };
131
132 /*
133  * Our command-line arguments
134  */
135
136 #ifdef RESIDENCY
137 struct {
138     int Algorithm;              /* Conversion algorithm */
139     int Size;                   /* Directory hierarchy size */
140     int FSType;                 /* File system type */
141     int DeviceTag;              /* Device Tag */
142 } rscmdlineinfo[RS_MAXRESIDENCIES];
143
144 /*
145  * This stuff comes from ufsname.c (which itself takes it from
146  * ufs_interfaces.c)
147  */
148
149 /* There is an assumption that all of the prefixes will have exactly one '/' */
150 static char *Ufs_Prefixes[] = { "/ufs", "/slowufs", "/cdmf", "/sdmf" };
151
152 #define MAX_ITERATIONS 10
153 #define UFS_SUMMARYTREENAME "Summaries"
154 #define UFS_STAGINGTREENAME "Staging"
155 #define UFS_VOLUMEHEADERTREENAME "VolHeaders"
156 #define UFS_VOLUMETREENAME "Volumes"
157 #define UFS_ALGORITHMBASE 'A'
158 #define UFS_MOUNTPOINTBASE 'a'
159 #define UFS_ALGORITHMS 3
160 #define UFS_LINK_MAX 64         /* Arbitrary. */
161 #define HARD_LINKED_FILE -2
162 #define TAGSTONAME(FileName, MountPoint, Sections, Level1, RWVolume, Vnode, Uniquifier, Algorithm) \
163 { \
164     if (Level1) \
165         sprintf(FileName,"%s/%lu/%lu/%c%lu.%lu.%lu.%lu.%lu", MountPoint, \
166                 (Sections)[0], (Sections)[1], UFS_ALGORITHMBASE + Algorithm, \
167                 (Sections)[2], (Sections)[3], RWVolume, Vnode, Uniquifier); \
168     else \
169         sprintf(FileName,"%s/%lu/%c%lu.%lu.%lu.%lu.%lu", MountPoint, \
170                 (Sections)[0], UFS_ALGORITHMBASE + Algorithm, \
171                 (Sections)[1], (Sections)[2], RWVolume, Vnode, Uniquifier); \
172 }
173 #define TAGSTOSTAGINGNAME(FileName, MountPoint, RWVolume, Vnode, Uniquifier) \
174     sprintf(FileName,"%s/%s/%lu.%lu.%lu", MountPoint, \
175             UFS_STAGINGTREENAME, RWVolume, Vnode, Uniquifier)
176 #define TAGSTOVOLUMEHEADERNAME(FileName, MountPoint, FileTag1, FileTag2) \
177     sprintf(FileName,"%s/%s/%lu", MountPoint, UFS_VOLUMEHEADERTREENAME, \
178             FileTag1)
179 #define TAGSTOVOLUMEINFONAME(FileName, MountPoint, FileTag1, FileTag2) \
180     sprintf(FileName,"%s/%s/%lu/%lu", MountPoint, \
181             UFS_VOLUMETREENAME, FileTag2, FileTag1)
182 #define TAGSTOVOLUMENAME(FileName, MountPoint, FileTag1, FileTag2, RWVolume) \
183     sprintf(FileName,"%s/%s/%lu/%lu.%lu", MountPoint, \
184             UFS_VOLUMETREENAME, FileTag2, FileTag1, RWVolume)
185 #define TAGSTOSUMMARYNAME(FileName, MountPoint, FileTag1, FileTag2, SummaryRequestor, Residency) \
186     sprintf(FileName,"%s/%s/%lu.%lu.%lu.%lu", MountPoint, \
187             UFS_SUMMARYTREENAME, FileTag1, FileTag2, SummaryRequestor, \
188             Residency)
189 #define DEVICETAGNUMBERTOMOUNTPOINT(MountPoint, DeviceTagNumber, FSType) \
190     sprintf(MountPoint,"%s%c", Ufs_Prefixes[FSType], UFS_MOUNTPOINTBASE + \
191             DeviceTagNumber)
192 #define MOUNTPOINTTODEVICETAGNUMBER(MountPoint) \
193     MountPoint[strlen(MountPoint) - 1] - UFS_MOUNTPOINTBASE
194 #define DEVICETAGNUMBERTOVOLUMEHEADERTREE(TreeName, MountPoint) \
195     sprintf(TreeName,"%s/%s", MountPoint, UFS_VOLUMEHEADERTREENAME)
196 #define UFS_RESIDENCIES_FILE "Residencies"
197
198 /* We don't ever want to map to uid/gid -1.  fchown() takes that as a
199    don't change flag.  We know however that volume number range from
200    0x2000000 to 0x20FFFFFF (see VAllocateVolumeId() in vol/vutil.c)
201    so we will use that to insure that -1 never appears. */
202 #define RWVolumeToUid(RWVolume) ((RWVolume >> 12) & 0xFFFF)
203 #define RWVolumeToGid(RWVolume) ((RWVolume & 0xFFF) | \
204                                  (((RWVolume >> 28) & 0xF) << 12))
205 #define UidGidToRWVolume(Uid, Gid) ((Gid & 0xFFF) | ((Uid & 0xFFFF) << 12) | \
206                                     ((Gid & 0xF000) << 16))
207
208
209 /* These routines generate a file name to correspond to the given tag
210    numbers. */
211
212 /* The following entropy array contains the order of bits from highest entropy
213    to lowest in the numbers FileTag1 and FileTag2.  Bit numbers 32 and above
214    correspond to FileTag2.  This ordering was determined by examining all read-
215    write volumes in the psc.edu cell. */
216 char UfsEntropy[1][64] = {
217     {1, 2, 3, 4, 33, 5, 6, 7, 44, 45, 46, 36, 8, 34, 42, 35,
218      9, 40, 38, 32, 43, 10, 39, 37, 11, 41, 12, 13, 14, 0,
219      15, 16, 61, 17, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51,
220      50, 49, 48, 47, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22,
221      21, 20, 19, 18, 62, 63},
222 };
223
224 uint32_t Directories[3][2] = { {256, 0}, {256, 16}, {256, 256}, };
225 #endif /* RESIDENCY */
226
227 static int verbose = 0;
228 static int numNoDirData = 0;
229 static int termsize = 0;
230 int Testing = 0;
231 #ifdef RESIDENCY
232 extern resid ServerRequestorId;
233 #endif /* RESIDENCY */
234
235 /*
236  * We use this structure to hold vnode data in our hash table.
237  * It's indexed by vnode number.
238  */
239
240 struct vnodeData {
241     struct VnodeDiskObject *vnode;      /* A pointer to the disk vnode */
242     int vnodeNumber;            /* The vnode number */
243     off64_t dumpdata;           /* File offset of dump data (if
244                                  * available */
245     unsigned char *filedata;    /* A pointer to the actual file
246                                  * data itself (if available) */
247     unsigned int datalength;    /* The length of the data */
248 };
249
250 /*
251  * This contains the current location when we're doing a scan of a
252  * directory.
253  */
254
255 struct DirCursor {
256     int hashbucket;             /* Current hash bucket */
257     int entry;                  /* Entry within hash bucket */
258 };
259
260 /*
261  * Arrays to hold vnode data
262  */
263
264 struct vnodeData **LargeVnodeIndex;
265 struct vnodeData **SmallVnodeIndex;
266 int numLargeVnodes = 0;
267 int numSmallVnodes = 0;
268
269 /*
270  * Crap for the libraries
271  */
272
273 int ShutdownInProgress = 0;
274
275 /*
276  * Our local function prototypes
277  */
278
279 static int ReadDumpHeader(FILE *, struct DumpHeader *);
280 static int ReadVolumeHeader(FILE *, VolumeDiskData *);
281 static int ScanVnodes(FILE *, VolumeDiskData *, int);
282 static int DumpVnodeFile(FILE *, struct VnodeDiskObject *, VolumeDiskData *);
283 static struct vnodeData *InsertVnode(unsigned int, struct VnodeDiskObject *);
284 static struct vnodeData *GetVnode(unsigned int);
285 static int CompareVnode(const void *, const void *);
286 static void InteractiveRestore(FILE *, VolumeDiskData *);
287 static void DirectoryList(int, char **, struct vnodeData *, VolumeDiskData *);
288 static void DirListInternal(struct vnodeData *, char *[], int, int, int, int,
289                             int, int, VolumeDiskData *, char *);
290 static int CompareDirEntry(const void *, const void *);
291 static struct vnodeData *ChangeDirectory(int, char **, struct vnodeData *);
292 static void CopyFile(int, char **, struct vnodeData *, FILE *);
293 static void CopyVnode(int, char **, FILE *);
294 static void DumpAllFiles(int, char **, struct vnodeData *, VolumeDiskData *);
295 static void DumpAllResidencies(FILE *, struct vnodeData *, VolumeDiskData *);
296 static struct vnodeData *FindFile(struct vnodeData *, char *);
297 static void ResetDirCursor(struct DirCursor *, struct vnodeData *);
298 static struct DirEntry *ReadNextDir(struct DirCursor *, struct vnodeData *);
299 static void MakeArgv(char *, int *, char ***);
300 static char *GetToken(char *, char **, char *, char *[]);
301 static int ReadInt16(FILE *, uint16_t *);
302 static int ReadInt32(FILE *, uint32_t *);
303 static int ReadString(FILE *, char *, int);
304 static int ReadByteString(FILE *, void *, int);
305
306 int
307 main(int argc, char *argv[])
308 {
309     int c, errflg = 0, dumpvnodes = 0, force = 0, inode = 0;
310     unsigned int magic;
311     struct DumpHeader dheader;
312     VolumeDiskData vol;
313     off64_t offset;
314     int Res, Arg1, Arg2, Arg3, i;
315     char *p;
316     struct winsize win;
317     FILE *f;
318     int fd;
319     time_t tmv;
320
321 #ifdef RESIDENCY
322     for (i = 0; i < RS_MAXRESIDENCIES; i++) {
323         rscmdlineinfo[i].Algorithm = -1;
324         rscmdlineinfo[i].Size = -1;
325         rscmdlineinfo[i].DeviceTag = -1;
326         rscmdlineinfo[i].FSType = -1;
327     }
328 #endif /* RESIDENCY */
329
330     /*
331      * Sigh, this is dumb, but we need the terminal window size
332      * to do intelligent things with "ls" later on.
333      */
334
335     if (isatty(STDOUT_FILENO)) {
336         if ((p = getenv("COLUMNS")) != NULL)
337             termsize = atoi(p);
338         else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0
339                  && win.ws_col > 0)
340             termsize = win.ws_col;
341     }
342
343     while ((c = getopt(argc, argv, "difr:t:v")) != EOF)
344         switch (c) {
345         case 't':
346 #ifdef RESIDENCY
347             if (sscanf(optarg, "%d/%d", &Res, &Arg1) != 2) {
348                 errflg++;
349                 break;
350             }
351
352             if (1 << (ffs(Res) - 1) != Res) {
353                 fprintf(stderr, "Invalid residency %d\n", Res);
354                 errflg++;
355                 break;
356             }
357
358             if (Arg1 < 0 || Arg1 > 26) {
359                 fprintf(stderr, "Invalid device tag: %d\n", Arg1);
360                 errflg++;
361                 break;
362             }
363             rscmdlineinfo[ffs(Res) - 1].DeviceTag = Arg1;
364 #else /* RESIDENCY */
365             fprintf(stderr, "-t not supported in non-MRAFS " "dumptool.\n");
366             errflg++;
367 #endif /* RESIDENCY */
368             break;
369
370         case 'r':
371 #ifdef RESIDENCY
372             if (sscanf(optarg, "%d/%d/%d/%d", &Res, &Arg1, &Arg2, &Arg3) != 4) {
373                 errflg++;
374                 break;
375             }
376
377             if (Arg1 < 0 || Arg1 > 3) {
378                 fprintf(stderr, "Invalid fstype: %d\n", Arg1);
379                 errflg++;
380                 break;
381             }
382
383             if (Arg2 < 0 || Arg2 > 2) {
384                 fprintf(stderr, "Invalid size: %d\n", Arg2);
385                 errflg++;
386                 break;
387             }
388
389             if (Arg3 <= 0 || Arg3 > UFS_ALGORITHMS) {
390                 fprintf(stderr, "Invalid algorithm: %d\n", Arg3);
391                 errflg++;
392                 break;
393             }
394             rscmdlineinfo[ffs(Res) - 1].FSType = Arg1;
395             rscmdlineinfo[ffs(Res) - 1].Size = Arg2;
396             rscmdlineinfo[ffs(Res) - 1].Algorithm = Arg3;
397 #else /* RESIDENCY */
398             fprintf(stderr, "-r not supported in non-MRAFS " "dumptool.\n");
399             errflg++;
400 #endif /* RESIDENCY */
401             break;
402         case 'd':
403 #ifdef RESIDENCY
404             dumpvnodes++;
405 #else /* RESIDENCY */
406             fprintf(stderr, "-d not supported in non-MRAFS " "dumptool.\n");
407             errflg++;
408 #endif /* RESIDENCY */
409             break;
410         case 'v':
411             verbose++;
412             break;
413         case 'f':
414             force++;
415             break;
416         case 'i':
417             inode++;
418             break;
419         case '?':
420         default:
421             errflg++;
422         }
423
424     if (errflg || optind == argc) {
425         fprintf(stderr, "Usage: %s\n\t[-v] [-f]\n\t"
426 #ifdef RESIDENCY
427                 "[-t Residency/Tag]\n\t"
428                 "[-r Residency/Type/Size/Algorithm]\n\t"
429                 "[-d] filename [file_in_dump [file in dump ...]]\n",
430 #else /* RESIDENCY */
431                 "filename\n",
432 #endif /* RESIDENCY */
433                 argv[0]);
434         exit(1);
435     }
436
437     /*
438      * Try opening the dump file
439      */
440
441 #ifdef O_LARGEFILE
442     if ((fd = open(argv[optind], O_RDONLY | O_LARGEFILE)) < 0) {
443 #else
444     if ((fd = open(argv[optind], O_RDONLY)) < 0) {
445 #endif
446         fprintf(stderr, "open of dumpfile %s failed: %s\n", argv[optind],
447                 strerror(errno));
448         exit(1);
449     }
450
451     if ((f = fdopen(fd, "rb")) == NULL) {
452         fprintf(stderr, "fdopen of dumpfile %s failed: %s\n", argv[optind],
453                 strerror(errno));
454         exit(1);
455     }
456
457     if (ReadDumpHeader(f, &dheader)) {
458         fprintf(stderr, "Failed to read dump header!\n");
459         exit(1);
460     }
461
462     if (verbose)
463         printf("Dump is for volume %lu (%s)\n", dheader.volumeId,
464                dheader.volumeName);
465
466     if (getc(f) != D_VOLUMEHEADER) {
467         fprintf(stderr, "Volume header is missing from dump, aborting\n");
468         exit(1);
469     }
470
471     if (ReadVolumeHeader(f, &vol)) {
472         fprintf(stderr, "Unable to read volume header\n");
473         exit(1);
474     }
475
476     if (verbose) {
477         printf("Volume information:\n");
478         printf("\tid = %lu\n", vol.id);
479         printf("\tparent id = %lu\n", vol.parentId);
480         printf("\tname = %s\n", vol.name);
481         printf("\tflags =");
482         if (vol.inUse)
483             printf(" inUse");
484         if (vol.inService)
485             printf(" inService");
486         if (vol.blessed)
487             printf(" blessed");
488         if (vol.needsSalvaged)
489             printf(" needsSalvaged");
490         printf("\n");
491         printf("\tuniquifier = %lu\n", vol.uniquifier);
492         tmv = vol.creationDate;
493         printf("\tCreation date = %s", ctime(&tmv));
494         tmv = vol.accessDate;
495         printf("\tLast access date = %s", ctime(&tmv));
496         tmv = vol.updateDate;
497         printf("\tLast update date = %s", ctime(&tmv));
498         printf("\tVolume owner = %lu\n", vol.owner);
499     }
500
501     if (verbose)
502         printf("Scanning vnodes (this may take a while)\n");
503
504     /*
505      * We need to do two vnode scans; one to get the number of
506      * vnodes, the other to actually build the index.
507      */
508
509     offset = ftello64(f);
510
511     if (ScanVnodes(f, &vol, 1)) {
512         fprintf(stderr, "First vnode scan failed, aborting\n");
513         exit(1);
514     }
515
516     fseeko64(f, offset, SEEK_SET);
517
518     if (ScanVnodes(f, &vol, 0)) {
519         fprintf(stderr, "Second vnode scan failed, aborting\n");
520         exit(1);
521     }
522
523     if (getc(f) != D_DUMPEND || ReadInt32(f, &magic) || magic != DUMPENDMAGIC) {
524         fprintf(stderr, "Couldn't find dump postamble, ");
525         if (!force) {
526             fprintf(stderr, "aborting (use -f to override)\n");
527             exit(1);
528         } else {
529             fprintf(stderr, "continuing anyway\n");
530             fprintf(stderr, "WARNING: Dump may not be complete!\n");
531         }
532     }
533
534     /*
535      * If we wanted to simply dump all vnodes, do it now
536      */
537
538 #ifdef RESIDENCY
539     if (dumpvnodes) {
540         struct vnodeData *vdata;
541
542         for (i = 0; i < numLargeVnodes; i++) {
543
544             vdata = LargeVnodeIndex[i];
545
546             if (vdata->vnode->type == vFidLookup)
547                 if (DumpVnodeFile(stdout, vdata->vnode, &vol)) {
548                     fprintf(stderr, "DumpVnodeFile failed, " "aborting\n");
549                     exit(1);
550                 }
551         }
552
553         for (i = 0; i < numSmallVnodes; i++) {
554
555             vdata = SmallVnodeIndex[i];
556
557             if (vdata->vnode->type == vFidLookup)
558                 if (DumpVnodeFile(stdout, vdata->vnode, &vol)) {
559                     fprintf(stderr, "DumpVnodeFile failed, " "aborting\n");
560                     exit(1);
561                 }
562         }
563
564     } else
565 #endif /* RESIDENCY */
566     if (inode) {
567         /*
568          * Dump out all filenames with their corresponding FID
569          */
570
571         struct vnodeData *rootvdata;
572
573         if ((rootvdata = GetVnode(1)) == NULL) {
574             fprintf(stderr,
575                     "Can't get vnode data for root " "vnode!  Aborting\n");
576             exit(1);
577         }
578
579         DirListInternal(rootvdata, NULL, 0, 0, 1, 0, 1, 0, &vol, "");
580
581     } else if (argc > optind + 1) {
582 #ifdef RESIDENCY
583         /*
584          * Dump out residencies of files given on the command line.
585          */
586
587         struct vnodeData *vdata, *rootvdata;
588
589         if ((rootvdata = GetVnode(1)) == NULL) {
590             fprintf(stderr,
591                     "Can't get vnode data for root " "vnode!  Aborting\n");
592             exit(1);
593         }
594
595         for (i = optind + 1; i < argc; i++) {
596
597             if ((vdata = FindFile(rootvdata, argv[i])) == NULL) {
598                 fprintf(stderr, "Skipping file %s\n", argv[i]);
599                 continue;
600             }
601
602             if (verbose)
603                 printf("Residency locations for %s:\n", argv[i]);
604
605             while (vdata->vnode->NextVnodeId != 0) {
606
607                 vdata = GetVnode(vdata->vnode->NextVnodeId);
608
609                 if (vdata == NULL) {
610                     fprintf(stderr,
611                             "We had a vnode chain " "pointer to a vnode that "
612                             "doesn't exist, aborting!\n");
613                     exit(1);
614                 }
615                 if (vdata->vnode->type == vFidLookup)
616                     DumpVnodeFile(stdout, vdata->vnode, &vol);
617             }
618         }
619 #else /* RESIDENCY */
620         fprintf(stderr, "Extra arguments after dump filename: %s\n",
621                 argv[optind]);
622         exit(1);
623 #endif /* RESIDENCY */
624     } else {
625         /*
626          * Perform an interactive restore
627          */
628
629         InteractiveRestore(f, &vol);
630     }
631
632     exit(0);
633 }
634
635 /*
636  * Read the dump header, which is at the beginning of every dump
637  */
638
639 static int
640 ReadDumpHeader(FILE * f, struct DumpHeader *header)
641 {
642     unsigned int magic;
643     int tag, i;
644
645     if (getc(f) != D_DUMPHEADER || ReadInt32(f, &magic)
646         || ReadInt32(f, (unsigned int *)
647                      &header->version) || magic != DUMPBEGINMAGIC) {
648         if (verbose)
649             fprintf(stderr, "Couldn't find dump magic numbers\n");
650         return -1;
651     }
652
653     header->volumeId = 0;
654     header->nDumpTimes = 0;
655
656     while ((tag = getc(f)) > D_MAX && tag != EOF) {
657         unsigned short length;
658         switch (tag) {
659         case 'v':
660             if (ReadInt32(f, &header->volumeId)) {
661                 if (verbose)
662                     fprintf(stderr, "Failed to read " "volumeId\n");
663                 return -1;
664             }
665             break;
666         case 'n':
667             if (ReadString(f, header->volumeName, sizeof(header->volumeName))) {
668                 if (verbose)
669                     fprintf(stderr, "Failed to read " "volume name\n");
670                 return -1;
671             }
672             break;
673         case 't':
674             if (ReadInt16(f, &length)) {
675                 if (verbose)
676                     fprintf(stderr,
677                             "Failed to read " "dump time array length\n");
678                 return -1;
679             }
680             header->nDumpTimes = (length >> 1);
681             for (i = 0; i < header->nDumpTimes; i++)
682                 if (ReadInt32(f, (unsigned int *)
683                               &header->dumpTimes[i].from)
684                     || ReadInt32(f, (unsigned int *)
685                                  &header->dumpTimes[i].to)) {
686                     if (verbose)
687                         fprintf(stderr, "Failed to " "read dump times\n");
688                     return -1;
689                 }
690             break;
691         default:
692             if (verbose)
693                 fprintf(stderr, "Unknown dump tag \"%c\"\n", tag);
694             return -1;
695         }
696     }
697
698     if (!header->volumeId || !header->nDumpTimes) {
699         if (verbose)
700             fprintf(stderr,
701                     "We didn't get a volume Id or " "dump times listing\n");
702         return 1;
703     }
704
705     ungetc(tag, f);
706     return 0;
707 }
708
709 /*
710  * Read the volume header; this is the information stored in VolumeDiskData.
711  *
712  * I'm not sure we need all of this, but read it in just in case.
713  */
714
715 static int
716 ReadVolumeHeader(FILE * f, VolumeDiskData * vol)
717 {
718     int tag;
719     unsigned int trash;
720     memset((void *)vol, 0, sizeof(*vol));
721
722     while ((tag = getc(f)) > D_MAX && tag != EOF) {
723         switch (tag) {
724         case 'i':
725             if (ReadInt32(f, &vol->id))
726                 return -1;
727             break;
728         case 'v':
729             if (ReadInt32(f, &trash))
730                 return -1;
731             break;
732         case 'n':
733             if (ReadString(f, vol->name, sizeof(vol->name)))
734                 return -1;
735             break;
736         case 's':
737             vol->inService = getc(f);
738             break;
739         case 'b':
740             vol->blessed = getc(f);
741             break;
742         case 'u':
743             if (ReadInt32(f, &vol->uniquifier))
744                 return -1;
745             break;
746         case 't':
747             vol->type = getc(f);
748             break;
749         case 'p':
750             if (ReadInt32(f, &vol->parentId))
751                 return -1;
752             break;
753         case 'c':
754             if (ReadInt32(f, &vol->cloneId))
755                 return -1;
756             break;
757         case 'q':
758             if (ReadInt32(f, (uint32_t *) & vol->maxquota))
759                 return -1;
760             break;
761         case 'm':
762             if (ReadInt32(f, (uint32_t *) & vol->minquota))
763                 return -1;
764             break;
765         case 'd':
766             if (ReadInt32(f, (uint32_t *) & vol->diskused))
767                 return -1;
768             break;
769         case 'f':
770             if (ReadInt32(f, (uint32_t *) & vol->filecount))
771                 return -1;
772             break;
773         case 'a':
774             if (ReadInt32(f, &vol->accountNumber))
775                 return -1;
776             break;
777         case 'o':
778             if (ReadInt32(f, &vol->owner))
779                 return -1;
780             break;
781         case 'C':
782             if (ReadInt32(f, &vol->creationDate))
783                 return -1;
784             break;
785         case 'A':
786             if (ReadInt32(f, &vol->accessDate))
787                 return -1;
788             break;
789         case 'U':
790             if (ReadInt32(f, &vol->updateDate))
791                 return -1;
792             break;
793         case 'E':
794             if (ReadInt32(f, &vol->expirationDate))
795                 return -1;
796             break;
797         case 'B':
798             if (ReadInt32(f, &vol->backupDate))
799                 return -1;
800             break;
801         case 'O':
802             if (ReadString
803                 (f, vol->offlineMessage, sizeof(vol->offlineMessage)))
804                 return -1;
805             break;
806         case 'M':
807             if (ReadString(f, (char *)vol->stat_reads, VMSGSIZE))
808                 return -1;
809             break;
810         case 'W':{
811                 unsigned short length;
812                 int i;
813                 unsigned int data;
814                 if (ReadInt16(f, &length))
815                     return -1;
816                 for (i = 0; i < length; i++) {
817                     if (ReadInt32(f, &data))
818                         return -1;
819                     if (i < sizeof(vol->weekUse) / sizeof(vol->weekUse[0]))
820                         vol->weekUse[i] = data;
821                 }
822                 break;
823             }
824         case 'D':
825             if (ReadInt32(f, &vol->dayUseDate))
826                 return -1;
827             break;
828         case 'Z':
829             if (ReadInt32(f, (uint32_t *) & vol->dayUse))
830                 return -1;
831             break;
832 #ifdef RESIDENCY
833         case 'R':{
834                 unsigned short length;
835                 int i;
836                 unsigned int data;
837
838                 if (ReadInt16(f, &length))
839                     return -1;
840                 for (i = 0; i < length; i++) {
841                     if (ReadInt32(f, &data))
842                         return -1;
843                     if (i <
844                         sizeof(vol->DesiredInfo.DesiredResidencyWords) /
845                         sizeof(vol->DesiredInfo.DesiredResidencyWords[0]))
846                         vol->DesiredInfo.DesiredResidencyWords[i] = data;
847                 }
848                 break;
849             }
850         case 'S':{
851                 unsigned short length;
852                 int i;
853                 unsigned int data;
854
855                 if (ReadInt16(f, &length))
856                     return -1;
857                 for (i = 0; i < length; i++) {
858                     if (ReadInt32(f, &data))
859                         return -1;
860                     if (i <
861                         sizeof(vol->UnDesiredInfo.UnDesiredResidencyWords) /
862                         sizeof(vol->UnDesiredInfo.UnDesiredResidencyWords[0]))
863                         vol->UnDesiredInfo.UnDesiredResidencyWords[i] = data;
864                 }
865                 break;
866             }
867 #endif
868         default:
869             if (verbose)
870                 fprintf(stderr, "Unknown dump tag \"%c\"\n", tag);
871             return -1;
872         }
873     }
874
875     ungetc(tag, f);
876     return 0;
877 }
878
879 /*
880  * Scan all our vnode entries, and build indexing information.
881  */
882
883 static int
884 ScanVnodes(FILE * f, VolumeDiskData * vol, int sizescan)
885 {
886     int vnodeNumber;
887     int tag;
888     int numFileVnodes = 0;
889     int numDirVnodes = 0;
890     unsigned char buf[SIZEOF_LARGEDISKVNODE];
891     struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)buf;
892     off64_t offset, oldoffset;
893     struct vnodeData *vdata;
894     unsigned int length;
895
896     tag = getc(f);
897
898     while (tag == D_VNODE) {
899
900         offset = 0;
901         length = 0;
902         vnode->type = -1;
903         vnode->length = -1;
904
905         if (ReadInt32(f, (uint32_t *) & vnodeNumber)) {
906             fprintf(stderr, "failed int32 for 'vnodenum'\n");
907             return -1;
908         }
909
910         if (ReadInt32(f, &vnode->uniquifier)) {
911             fprintf(stderr, "failed int32 for 'uniquifier'\n");
912             return -1;
913         }
914
915         if (verbose > 1 && !sizescan)
916             printf("Got vnode %d\n", vnodeNumber);
917
918         while ((tag = getc(f)) > D_MAX && tag != EOF)
919             switch (tag) {
920             case 't':
921                 vnode->type = (VnodeType) getc(f);
922                 break;
923             case 'l':
924                 {
925                     unsigned short tmp;
926                     if (ReadInt16(f, &tmp)) {
927                         fprintf(stderr, "failed int16 for 'l'\n");
928                         return -1;
929                     }
930                     vnode->linkCount = tmp;
931                 }
932                 break;
933             case 'v':
934                 if (ReadInt32(f, &vnode->dataVersion)) {
935                     fprintf(stderr, "failed int32 for 'v'\n");
936                     return -1;
937                 }
938                 break;
939             case 'm':
940                 if (ReadInt32(f, (uint32_t *) & vnode->unixModifyTime)) {
941                     fprintf(stderr, "failed int32 for 'm'\n");
942                     return -1;
943                 }
944                 break;
945             case 's':
946                 if (ReadInt32(f, (uint32_t *) & vnode->serverModifyTime)) {
947                     fprintf(stderr, "failed int32 for 's'\n");
948                     return -1;
949                 }
950                 break;
951             case 'a':
952                 if (ReadInt32(f, &vnode->author)) {
953                     fprintf(stderr, "failed int32 for 'a'\n");
954                     return -1;
955                 }
956                 break;
957             case 'o':
958                 if (ReadInt32(f, &vnode->owner)) {
959                     fprintf(stderr, "failed int32 for 'o'\n");
960                     return -1;
961                 }
962                 break;
963             case 'g':
964                 if (ReadInt32(f, (uint32_t *) & vnode->group)) {
965                     fprintf(stderr, "failed int32 for 'g'\n");
966                     return -1;
967                 }
968                 break;
969             case 'b':{
970                     unsigned short modeBits;
971                     if (ReadInt16(f, &modeBits))
972                         return -1;
973                     vnode->modeBits = modeBits;
974                     break;
975                 }
976             case 'p':
977                 if (ReadInt32(f, &vnode->parent)) {
978                     fprintf(stderr, "failed int32 for 'p'\n");
979                     return -1;
980                 }
981                 break;
982 #ifdef RESIDENCY
983             case 'N':
984                 if (ReadInt32(f, &vnode->NextVnodeId)) {
985                     fprintf(stderr, "failed int32 for 'N'\n");
986                     return -1;
987                 }
988                 break;
989             case 'R':
990                 if (ReadInt32(f, &VLkp_Residencies(vnode))) {
991                     fprintf(stderr, "failed int32 for 'R'\n");
992                     return -1;
993                 }
994                 break;
995 #endif
996             case 'S':
997                 if (ReadInt32(f, &vnode->length)) {
998                     fprintf(stderr, "failed int32 for 'S'\n");
999                     return -1;
1000                 }
1001                 break;
1002             case 'F':
1003                 if (ReadInt32(f, (uint32_t *) & vnode->vn_ino_lo))
1004                     return -1;
1005                 break;
1006             case 'A':
1007                 if (ReadByteString
1008                     (f, (void *)VVnodeDiskACL(vnode), VAclDiskSize(vnode))) {
1009                     fprintf(stderr, "failed readbystring for 'A'\n");
1010                     return -1;
1011                 }
1012 #if 0
1013                 acl_NtohACL(VVnodeDiskACL(vnode));
1014 #endif
1015                 break;
1016 #ifdef RESIDENCY
1017             case 'h':
1018                 if (ReadInt32(f, &vnode->length_hi)) {
1019                     fprintf(stderr, "failed int32 for 'h'\n");
1020                     return -1;
1021                 }
1022 #endif
1023             case 'f':
1024                 if (verbose > 1 && !sizescan)
1025                     printf("We have file data!\n");
1026                 if (ReadInt32(f, &length)) {
1027                     fprintf(stderr, "failed int32 for 'f'\n");
1028                     return -1;
1029                 }
1030                 vnode->length = length;
1031                 offset = ftello64(f);
1032                 fseeko64(f, length, SEEK_CUR);
1033                 break;
1034             default:
1035                 if (verbose)
1036                     fprintf(stderr, "Unknown dump tag \"%c\"\n", tag);
1037                 return -1;
1038             }
1039
1040         /*
1041          * If we're doing an incremental restore, then vnodes
1042          * will be listed in the dump, but won't contain any
1043          * vnode information at all (I don't know why they're
1044          * included _at all_).  If we get one of these vnodes, then
1045          * just skip it (because we can't do anything with it.
1046          */
1047
1048         if (vnode->type == -1)
1049             continue;
1050
1051 #ifdef RESIDENCY
1052         if (verbose > 1 && vnode->type == vFidLookup && !sizescan) {
1053             printf
1054                 ("This is an auxiliary vnode (lookup) for vnode %d, residency %d\n",
1055                  VLkp_ParentVnodeId(vnode), VLkp_Residencies(vnode));
1056             if (DumpVnodeFile(stdout, vnode, vol))
1057                 return -1;
1058         }
1059
1060         if (verbose > 1 && vnode->type == vAccessHistory && !sizescan)
1061             printf("This is an auxiliary vnode (history) for vnode %d\n",
1062                    VLkp_ParentVnodeId(vnode));
1063 #endif
1064
1065         if (vnode->type == vDirectory)
1066             numDirVnodes++;
1067         else
1068             numFileVnodes++;
1069
1070         /*
1071          * We know now all we would ever know about the vnode;
1072          * insert it into our hash table (but only if we're not
1073          * doing a vnode scan).
1074          */
1075
1076         if (!sizescan) {
1077
1078             vdata = InsertVnode(vnodeNumber, vnode);
1079
1080             if (vdata == NULL) {
1081                 if (verbose)
1082                     fprintf(stderr,
1083                             "Failed to insert " "vnode into hash table");
1084                 return -1;
1085             }
1086
1087             vdata->dumpdata = offset;
1088             vdata->datalength = length;
1089
1090             /*
1091              * Save directory data, since we'll need it later.
1092              */
1093
1094             if (vnode->type == vDirectory && length) {
1095
1096                 vdata->filedata = malloc(length);
1097
1098                 if (!vdata->filedata) {
1099                     if (verbose)
1100                         fprintf(stderr,
1101                                 "Unable to " "allocate space for "
1102                                 "file data (%d)\n", length);
1103                     return -1;
1104                 }
1105
1106                 oldoffset = ftello64(f);
1107                 fseeko64(f, offset, SEEK_SET);
1108
1109                 if (fread(vdata->filedata, length, 1, f) != 1) {
1110                     if (verbose)
1111                         fprintf(stderr, "Unable to " "read in file data!\n");
1112                     return -1;
1113                 }
1114
1115                 fseeko64(f, oldoffset, SEEK_SET);
1116             } else if (vnode->type == vDirectory)
1117                 /*
1118                  * Warn the user we may not have all directory
1119                  * vnodes
1120                  */
1121                 numNoDirData++;
1122         }
1123     }
1124
1125     ungetc(tag, f);
1126
1127     if (!sizescan) {
1128
1129         numLargeVnodes = numDirVnodes;
1130         numSmallVnodes = numFileVnodes;
1131
1132     } else {
1133         LargeVnodeIndex = (struct vnodeData **)
1134             malloc(numDirVnodes * sizeof(struct vnodeData));
1135         SmallVnodeIndex = (struct vnodeData **)
1136             malloc(numFileVnodes * sizeof(struct vnodeData));
1137
1138         if (LargeVnodeIndex == NULL || SmallVnodeIndex == NULL) {
1139             if (verbose)
1140                 fprintf(stderr,
1141                         "Unable to allocate space " "for vnode tables\n");
1142             return -1;
1143         }
1144     }
1145
1146     if (verbose)
1147         fprintf(stderr, "%s vnode scan completed\n",
1148                 sizescan ? "Primary" : "Secondary");
1149
1150     return 0;
1151 }
1152
1153 /*
1154  * Perform an interactive restore
1155  *
1156  * Parsing the directory information is a pain, but other than that
1157  * we just use the other tools we already have in here.
1158  */
1159 #define CMDBUFSIZE      (AFSPATHMAX * 2)
1160 static void
1161 InteractiveRestore(FILE * f, VolumeDiskData * vol)
1162 {
1163     struct vnodeData *vdatacwd; /* Vnode data for our current dir */
1164     char cmdbuf[CMDBUFSIZE];
1165     int argc;
1166     char **argv;
1167
1168     /*
1169      * Let's see if we can at least get the data for our root directory.
1170      * If we can't, there's no way we can do an interactive restore.
1171      */
1172
1173     if ((vdatacwd = GetVnode(1)) == NULL) {
1174         fprintf(stderr, "No entry for our root vnode!  Aborting\n");
1175         return;
1176     }
1177
1178     if (!vdatacwd->filedata) {
1179         fprintf(stderr,
1180                 "There is no directory data for the root "
1181                 "vnode (1.1).  An interactive\nrestore is not "
1182                 "possible.\n");
1183         return;
1184     }
1185
1186     /*
1187      * If you're doing a selective dump correctly, then you should get all
1188      * directory vnode data.  But just in case you didn't, let the user
1189      * know there may be a problem.
1190      */
1191
1192     if (numNoDirData)
1193         fprintf(stderr,
1194                 "WARNING: %d directory vnodes had no file "
1195                 "data.  An interactive restore\nmay not be possible\n",
1196                 numNoDirData);
1197
1198     printf("> ");
1199     while (fgets(cmdbuf, CMDBUFSIZE, stdin)) {
1200
1201         cmdbuf[strlen(cmdbuf) - 1] = '\0';
1202
1203         if (strlen(cmdbuf) == 0) {
1204             printf("> ");
1205             continue;
1206         }
1207
1208         MakeArgv(cmdbuf, &argc, &argv);
1209
1210         if (strcmp(argv[0], "ls") == 0) {
1211             DirectoryList(argc, argv, vdatacwd, vol);
1212         } else if (strcmp(argv[0], "cd") == 0) {
1213             struct vnodeData *newvdata;
1214
1215             newvdata = ChangeDirectory(argc, argv, vdatacwd);
1216
1217             if (newvdata)
1218                 vdatacwd = newvdata;
1219         } else if (strcmp(argv[0], "file") == 0) {
1220             DumpAllFiles(argc, argv, vdatacwd, vol);
1221         } else if (strcmp(argv[0], "cp") == 0) {
1222             CopyFile(argc, argv, vdatacwd, f);
1223         } else if (strcmp(argv[0], "vcp") == 0) {
1224             CopyVnode(argc, argv, f);
1225         } else if (strcmp(argv[0], "quit") == 0
1226                    || strcmp(argv[0], "exit") == 0)
1227             break;
1228         else if (strcmp(argv[0], "?") == 0 || strcmp(argv[0], "help") == 0) {
1229             printf("Valid commands are:\n");
1230             printf("\tls\t\tList current directory\n");
1231             printf("\tcd\t\tChange current directory\n");
1232             printf("\tcp\t\tCopy file from dump\n");
1233             printf("\tvcp\t\tCopy file from dump (via vnode)\n");
1234 #ifdef RESIDENCY
1235             printf("\tfile\t\tList residency filenames\n");
1236 #endif /* RESIDENCY */
1237             printf("\tquit | exit\tExit program\n");
1238             printf("\thelp | ?\tBrief help\n");
1239         } else
1240             fprintf(stderr,
1241                     "Unknown command, \"%s\", enter "
1242                     "\"help\" for a list of commands.\n", argv[0]);
1243
1244         printf("> ");
1245     }
1246
1247     return;
1248 }
1249
1250 /*
1251  * Do a listing of all files in a directory.  Sigh, I wish this wasn't
1252  * so complicated.
1253  *
1254  * With the reorganizing, this is just a front-end to DirListInternal()
1255  */
1256
1257 static void
1258 DirectoryList(int argc, char **argv, struct vnodeData *vdata,
1259               VolumeDiskData * vol)
1260 {
1261     int errflg = 0, lflag = 0, iflag = 0, Fflag = 0, sflag = 0, Rflag = 0;
1262     int c;
1263
1264     optind = 1;
1265
1266     while ((c = getopt(argc, argv, "liFRs")) != EOF)
1267         switch (c) {
1268         case 'l':
1269             lflag++;
1270             break;
1271         case 'i':
1272             iflag++;
1273             break;
1274         case 'F':
1275             Fflag++;
1276             break;
1277         case 'R':
1278             Rflag++;
1279         case 's':
1280             sflag++;
1281             break;
1282         case '?':
1283         default:
1284             errflg++;
1285         }
1286
1287     if (errflg) {
1288         fprintf(stderr, "Usage: %s [-liFs] filename [filename ...]\n",
1289                 argv[0]);
1290         return;
1291     }
1292
1293     DirListInternal(vdata, &(argv[optind]), argc - optind, lflag, iflag,
1294                     Fflag, Rflag, 1, vol, NULL);
1295
1296     return;
1297 }
1298
1299 /*
1300  * Function that does the REAL work in terms of directory listing
1301  */
1302
1303 static void
1304 DirListInternal(struct vnodeData *vdata, char *pathnames[], int numpathnames,
1305                 int lflag, int iflag, int Fflag, int Rflag, int verbose,
1306                 VolumeDiskData * vol, char *path)
1307 {
1308     struct DirEntry *ep, **eplist = NULL, **eprecurse = NULL;
1309     struct DirCursor cursor;
1310     struct vnodeData *lvdata;
1311
1312     int i, j, numentries = 0, longestname = 0, numcols, col, numrows;
1313     int numrecurse = 0;
1314
1315     if (!vdata->filedata) {
1316         fprintf(stderr, "There is no vnode data for this " "directory!\n");
1317         return;
1318     }
1319
1320     ResetDirCursor(&cursor, vdata);
1321
1322     /*
1323      * Scan through the whole directory
1324      */
1325
1326     while ((ep = ReadNextDir(&cursor, vdata)) != NULL) {
1327
1328         /*
1329          * If we didn't get any filenames on the command line,
1330          * get them all.
1331          */
1332
1333         if (numpathnames == 0) {
1334             eplist =
1335                 realloc(eplist, sizeof(struct DirEntry *) * ++numentries);
1336             eplist[numentries - 1] = ep;
1337             if (strlen(ep->name) > longestname)
1338                 longestname = strlen(ep->name);
1339             if (Rflag)
1340                 if ((lvdata = GetVnode(ntohl(ep->fid.vnode)))
1341                     && lvdata->vnode->type == vDirectory
1342                     && !(strcmp(ep->name, ".") == 0
1343                          || strcmp(ep->name, "..") == 0)) {
1344                     eprecurse =
1345                         realloc(eprecurse,
1346                                 sizeof(struct DirEntry *) * ++numrecurse);
1347                     eprecurse[numrecurse - 1] = ep;
1348                 }
1349
1350         } else {
1351             /*
1352              * Do glob matching via fnmatch()
1353              */
1354
1355             for (i = 0; i < numpathnames; i++)
1356                 if (fnmatch(pathnames[i], ep->name, FNM_PATHNAME) == 0) {
1357                     eplist =
1358                         realloc(eplist,
1359                                 sizeof(struct DirEntry *) * ++numentries);
1360                     eplist[numentries - 1] = ep;
1361                     if (strlen(ep->name) > longestname)
1362                         longestname = strlen(ep->name);
1363                     if (Rflag)
1364                         if ((lvdata = GetVnode(ntohl(ep->fid.vnode)))
1365                             && lvdata->vnode->type == vDirectory
1366                             && !(strcmp(ep->name, ".") == 0
1367                                  || strcmp(ep->name, "..") == 0)) {
1368                             eprecurse =
1369                                 realloc(eprecurse,
1370                                         sizeof(struct DirEntry *) *
1371                                         ++numrecurse);
1372                             eprecurse[numrecurse - 1] = ep;
1373                         }
1374                     break;
1375                 }
1376         }
1377     }
1378
1379     qsort((void *)eplist, numentries, sizeof(struct DirEntry *),
1380           CompareDirEntry);
1381
1382     if (Rflag && eprecurse)
1383         qsort((void *)eprecurse, numrecurse, sizeof(struct DirEntry *),
1384               CompareDirEntry);
1385     /*
1386      * We don't have to do column printing if we have the -l or the -i
1387      * options.  Sigh, column printing is WAY TOO FUCKING COMPLICATED!
1388      */
1389
1390     if (!lflag && !iflag) {
1391         char c;
1392
1393         if (Fflag)
1394             longestname++;
1395
1396         longestname++;
1397
1398         numcols = termsize / longestname ? termsize / longestname : 1;
1399         numrows = numentries / numcols + (numentries % numcols ? 1 : 0);
1400
1401         for (i = 0; i < numrows; i++) {
1402             col = 0;
1403             while (col < numcols && (i + col * numrows) < numentries) {
1404                 ep = eplist[i + col++ * numrows];
1405                 if (Fflag) {
1406                     if (!(lvdata = GetVnode(ntohl(ep->fid.vnode))))
1407                         c = ' ';
1408                     else if (lvdata->vnode->type == vDirectory)
1409                         c = '/';
1410                     else if (lvdata->vnode->type == vSymlink)
1411                         c = '@';
1412                     else if (lvdata->vnode->modeBits & 0111 != 0)
1413                         c = '*';
1414                     else
1415                         c = ' ';
1416                     printf("%s%-*c", ep->name, longestname - strlen(ep->name),
1417                            c);
1418                 } else
1419                     printf("%-*s", longestname, ep->name);
1420             }
1421
1422             printf("\n");
1423         }
1424     } else if (iflag)
1425         for (i = 0; i < numentries; i++)
1426             if (!(lvdata = GetVnode(ntohl(eplist[i]->fid.vnode))))
1427                 printf("%d.0.0\t%s\n",
1428                        vol->parentId ? vol->parentId : vol->id,
1429                        eplist[i]->name);
1430             else if (path)
1431                 printf("%d.%d.%d\t%s/%s\n", vol->id,
1432                        ntohl(eplist[i]->fid.vnode),
1433                        ntohl(eplist[i]->fid.vunique), path, eplist[i]->name);
1434             else
1435                 printf("%d.%d.%d\t%s\n", vol->id, ntohl(eplist[i]->fid.vnode),
1436                        ntohl(eplist[i]->fid.vunique), eplist[i]->name);
1437     else if (lflag) {
1438         for (i = 0; i < numentries; i++)
1439             if (!(lvdata = GetVnode(ntohl(eplist[i]->fid.vnode))))
1440                 printf("----------   0 0        " "0                 0 %s\n",
1441                        eplist[i]->name);
1442             else {
1443                 switch (lvdata->vnode->type) {
1444                 case vDirectory:
1445                     printf("d");
1446                     break;
1447                 case vSymlink:
1448                     printf("l");
1449                     break;
1450                 default:
1451                     printf("-");
1452                 }
1453
1454                 for (j = 8; j >= 0; j--) {
1455                     if (lvdata->vnode->modeBits & (1 << j))
1456                         switch (j % 3) {
1457                         case 2:
1458                             printf("r");
1459                             break;
1460                         case 1:
1461                             printf("w");
1462                             break;
1463                         case 0:
1464                             printf("x");
1465                     } else
1466                         printf("-");
1467                 }
1468
1469                 printf(" %-3d %-8d %-8d %10d %s\n", lvdata->vnode->linkCount,
1470                        lvdata->vnode->owner, lvdata->vnode->group,
1471                        lvdata->vnode->length, eplist[i]->name);
1472             }
1473     }
1474
1475     free(eplist);
1476
1477     if (Rflag && eprecurse) {
1478         char *lpath;
1479         lpath = NULL;
1480         for (i = 0; i < numrecurse; i++) {
1481             if (verbose)
1482                 printf("\n%s:\n", eprecurse[i]->name);
1483             if (path) {
1484                 lpath = malloc(strlen(path) + strlen(eprecurse[i]->name) + 2);
1485                 if (lpath)
1486                     sprintf(lpath, "%s/%s", path, eprecurse[i]->name);
1487             }
1488             DirListInternal(GetVnode(ntohl(eprecurse[i]->fid.vnode)), NULL, 0,
1489                             lflag, iflag, Fflag, Rflag, verbose, vol, lpath);
1490             if (lpath) {
1491                 free(lpath);
1492                 lpath = NULL;
1493             }
1494         }
1495     }
1496
1497     if (eprecurse)
1498         free(eprecurse);
1499
1500     return;
1501 }
1502
1503
1504 /*
1505  * Directory name comparison function, used by qsort
1506  */
1507
1508 static int
1509 CompareDirEntry(const void *e1, const void *e2)
1510 {
1511     struct DirEntry **ep1 = (struct DirEntry **)e1;
1512     struct DirEntry **ep2 = (struct DirEntry **)e2;
1513
1514     return strcmp((*ep1)->name, (*ep2)->name);
1515 }
1516
1517 /*
1518  * Change a directory.  Return a pointer to our new vdata structure for
1519  * this directory.
1520  */
1521
1522 static struct vnodeData *
1523 ChangeDirectory(int argc, char **argv, struct vnodeData *vdatacwd)
1524 {
1525     struct vnodeData *newvdatacwd;
1526
1527     if (argc != 2) {
1528         fprintf(stderr, "Usage: %s directory\n", argv[0]);
1529         return NULL;
1530     }
1531
1532     if ((newvdatacwd = FindFile(vdatacwd, argv[1])) == NULL)
1533         return NULL;
1534
1535     if (newvdatacwd->vnode->type != vDirectory) {
1536         fprintf(stderr, "%s: Not a directory\n", argv[1]);
1537         return NULL;
1538     }
1539
1540     if (newvdatacwd->filedata == NULL) {
1541         fprintf(stderr, "%s: No directory data found.\n", argv[1]);
1542         return NULL;
1543     }
1544
1545     return newvdatacwd;
1546 }
1547
1548 /*
1549  * Copy a file from out of the dump file
1550  */
1551
1552 #define COPYBUFSIZE 8192
1553
1554 static void
1555 CopyFile(int argc, char **argv, struct vnodeData *vdatacwd, FILE * f)
1556 {
1557     struct vnodeData *vdata;
1558     FILE *out;
1559     off64_t cur = 0;
1560     int bytes, ret;
1561     char buffer[COPYBUFSIZE];
1562
1563     if (argc != 3) {
1564         fprintf(stderr, "Usage: %s dumpfile destfile\n", argv[0]);
1565         return;
1566     }
1567
1568     if ((vdata = FindFile(vdatacwd, argv[1])) == NULL)
1569         return;
1570
1571     if (vdata->dumpdata == 0) {
1572         fprintf(stderr, "File %s has no data in dump file\n", argv[1]);
1573         return;
1574     }
1575
1576     if ((out = fopen(argv[2], "wb")) == NULL) {
1577         fprintf(stderr, "Open of %s failed: %s\n", argv[2], strerror(errno));
1578         return;
1579     }
1580
1581     if (fseeko64(f, vdata->dumpdata, SEEK_SET)) {
1582         fprintf(stderr, "Seek failed: %s\n", strerror(errno));
1583         fclose(out);
1584         return;
1585     }
1586
1587     while (cur < vdata->datalength) {
1588
1589         bytes =
1590             cur + COPYBUFSIZE <
1591             vdata->datalength ? COPYBUFSIZE : vdata->datalength - cur;
1592
1593         ret = fread(buffer, sizeof(char), bytes, f);
1594         if (ret != bytes) {
1595             if (ret != 0)
1596                 fprintf(stderr, "Short read (expected %d, " "got %d)\n",
1597                         bytes, ret);
1598             else
1599                 fprintf(stderr, "Error during read: %s\n", strerror(errno));
1600             fclose(out);
1601             return;
1602         }
1603
1604         ret = fwrite(buffer, sizeof(char), bytes, out);
1605         if (ret != bytes) {
1606             if (ret != 0)
1607                 fprintf(stderr, "Short write (expected %d, " "got %d)\n",
1608                         bytes, ret);
1609             else
1610                 fprintf(stderr, "Error during write: %s\n", strerror(errno));
1611             fclose(out);
1612             return;
1613         }
1614
1615         cur += bytes;
1616     }
1617
1618     fclose(out);
1619 }
1620
1621 /*
1622  * Copy a file from out of the dump file, by using the vnode
1623  */
1624
1625 static void
1626 CopyVnode(int argc, char *argv[], FILE * f)
1627 {
1628     struct vnodeData *vdata;
1629     FILE *out;
1630     off64_t cur = 0;
1631     int bytes, ret;
1632     char buffer[COPYBUFSIZE];
1633     unsigned int vnode, uniquifier = 0;
1634
1635     if (argc != 3) {
1636         fprintf(stderr, "Usage: %s vnode[.uniqifier] destfile\n", argv[0]);
1637         return;
1638     }
1639
1640     ret = sscanf(argv[1], "%d.%d", &vnode, &uniquifier);
1641
1642     if (ret < 1) {
1643         fprintf(stderr, "Invalid file identifier: %s\n", argv[1]);
1644         return;
1645     }
1646
1647     if (!(vdata = GetVnode(vnode))) {
1648         fprintf(stderr, "Vnode %d not in dump file\n", vnode);
1649         return;
1650     }
1651
1652     if (ret == 2 && vdata->vnode->uniquifier != uniquifier) {
1653         fprintf(stderr,
1654                 "Specified uniquifier %d did not match "
1655                 "uniquifier %d found in dump file!\n", uniquifier,
1656                 vdata->vnode->uniquifier);
1657         return;
1658     }
1659
1660     if (vdata->dumpdata == 0) {
1661         fprintf(stderr, "File %s has no data in dump file\n", argv[1]);
1662         return;
1663     }
1664
1665     if ((out = fopen(argv[2], "wb")) == NULL) {
1666         fprintf(stderr, "Open of %s failed: %s\n", argv[2], strerror(errno));
1667         return;
1668     }
1669
1670     if (fseeko64(f, vdata->dumpdata, SEEK_SET)) {
1671         fprintf(stderr, "Seek failed: %s\n", strerror(errno));
1672         fclose(out);
1673         return;
1674     }
1675
1676     while (cur < vdata->datalength) {
1677
1678         bytes =
1679             cur + COPYBUFSIZE <
1680             vdata->datalength ? COPYBUFSIZE : vdata->datalength - cur;
1681
1682         ret = fread(buffer, sizeof(char), bytes, f);
1683         if (ret != bytes) {
1684             if (ret != 0)
1685                 fprintf(stderr, "Short read (expected %d, " "got %d)\n",
1686                         bytes, ret);
1687             else
1688                 fprintf(stderr, "Error during read: %s\n", strerror(errno));
1689             fclose(out);
1690             return;
1691         }
1692
1693         ret = fwrite(buffer, sizeof(char), bytes, out);
1694         if (ret != bytes) {
1695             if (ret != 0)
1696                 fprintf(stderr, "Short write (expected %d, " "got %d)\n",
1697                         bytes, ret);
1698             else
1699                 fprintf(stderr, "Error during write: %s\n", strerror(errno));
1700             fclose(out);
1701             return;
1702         }
1703
1704         cur += bytes;
1705     }
1706
1707     fclose(out);
1708 }
1709
1710 /*
1711  * Dump all residency filenames associated with a file, or all files
1712  * within a directory.
1713  */
1714
1715 static void
1716 DumpAllFiles(int argc, char **argv, struct vnodeData *vdatacwd,
1717              VolumeDiskData * vol)
1718 {
1719 #ifdef RESIDENCY
1720     struct vnodeData *vdata, *nvdata;
1721     struct DirCursor cursor;
1722     struct DirEntry *ep;
1723     FILE *f = stdout;
1724     int c, i;
1725     int dflag = 0, fflag = 0, errflg = 0;
1726
1727     optind = 1;
1728
1729     while ((c = getopt(argc, argv, "df:")) != EOF)
1730         switch (c) {
1731         case 'd':
1732             dflag++;
1733             break;
1734         case 'f':
1735             if ((f = fopen(optarg, "a")) == NULL) {
1736                 fprintf(stderr, "Cannot open \"%s\": %s\n", optarg,
1737                         strerror(errno));
1738                 return;
1739             }
1740             fflag++;
1741             break;
1742         case 'h':
1743         case '?':
1744         default:
1745             errflg++;
1746         }
1747
1748     if (errflg || argc == optind) {
1749         fprintf(stderr, "Usage: %s [-d] [-f filename] file " "[file ...]\n",
1750                 argv[0]);
1751         if (fflag)
1752             fclose(f);
1753         return;
1754     }
1755
1756     for (i = optind; i < argc; i++) {
1757
1758         if ((vdata = FindFile(vdatacwd, argv[i])) == NULL)
1759             continue;
1760
1761         if (vdata->vnode->type == vDirectory && !dflag) {
1762
1763             ResetDirCursor(&cursor, vdata);
1764
1765             while ((ep = ReadNextDir(&cursor, vdata)) != NULL) {
1766
1767                 if (!(nvdata = GetVnode(ntohl(ep->fid.vnode)))) {
1768                     fprintf(stderr,
1769                             "Cannot find vnode " "entry for %s (%d)\n",
1770                             ep->name, ntohl(ep->fid.vnode));
1771                     continue;
1772                 }
1773
1774
1775                 if (!fflag) {
1776                     printf("Residency locations for %s:\n", ep->name);
1777
1778                     if (nvdata->dumpdata)
1779                         printf("Local disk (in dump " "file)\n");
1780                 }
1781
1782                 DumpAllResidencies(f, nvdata, vol);
1783
1784             }
1785
1786         } else {
1787             if (!fflag) {
1788                 printf("Residency locations for %s:\n", argv[i]);
1789
1790                 if (vdata->dumpdata)
1791                     printf("Local disk (in dump file)\n");
1792             }
1793
1794             DumpAllResidencies(f, vdata, vol);
1795         }
1796     }
1797
1798     if (fflag)
1799         fclose(f);
1800 #else /* RESIDENCY */
1801     fprintf(stderr,
1802             "The \"file\" command is not available in the non-"
1803             "MRAFS version of dumptool.\n");
1804 #endif /* RESIDENCY */
1805     return;
1806 }
1807
1808 /*
1809  * Take a vnode, traverse the vnode chain, and dump out all files on
1810  * all residencies corresponding to that parent vnode.
1811  */
1812
1813 #ifdef RESIDENCY
1814 static void
1815 DumpAllResidencies(FILE * f, struct vnodeData *vdata,
1816                    struct VolumeDiskData *vol)
1817 {
1818     unsigned int nextVnodeNum;
1819
1820     while (nextVnodeNum = vdata->vnode->NextVnodeId) {
1821         if ((vdata = GetVnode(nextVnodeNum)) == NULL) {
1822             fprintf(stderr,
1823                     "We had a pointer to %lu in it's "
1824                     "vnode chain, but there\nisn't a record of "
1825                     "it!  The dump might be corrupt.\n", nextVnodeNum);
1826             return;
1827         }
1828
1829         if (vdata->vnode->type == vFidLookup)
1830             DumpVnodeFile(f, vdata->vnode, vol);
1831     }
1832
1833     return;
1834 }
1835 #endif
1836
1837
1838 /*
1839  * Given a directory vnode and a filename, return the vnode corresponding
1840  * to the file in that directory.
1841  * 
1842  * We now handle pathnames with directories in them.
1843  */
1844
1845 static struct vnodeData *
1846 FindFile(struct vnodeData *vdatacwd, char *filename)
1847 {
1848     struct DirHeader *dhp;
1849     struct DirEntry *ep;
1850     int i, num;
1851     struct vnodeData *vdata;
1852     char *c, newstr[MAXPATHLEN];
1853
1854     if (!vdatacwd->filedata) {
1855         fprintf(stderr, "There is no vnode data for this " "directory!\n");
1856         return NULL;
1857     }
1858
1859     /*
1860      * If we have a "/" in here, look up the vnode data for the
1861      * directory (everything before the "/") and use that as our
1862      * current directory.  We automagically handle multiple directories
1863      * by using FindFile recursively.
1864      */
1865
1866     if ((c = strrchr(filename, '/')) != NULL) {
1867
1868         strncpy(newstr, filename, c - filename);
1869         newstr[c - filename] = '\0';
1870
1871         if ((vdatacwd = FindFile(vdatacwd, newstr)) == NULL)
1872             return NULL;
1873
1874         if (vdatacwd->vnode->type != vDirectory) {
1875             fprintf(stderr, "%s: Not a directory\n", newstr);
1876             return NULL;
1877         }
1878
1879         filename = c + 1;
1880     }
1881
1882     dhp = (struct DirHeader *)vdatacwd->filedata;
1883
1884     i = DirHash(filename);
1885
1886     num = ntohs(dhp->hashTable[i]);
1887
1888     while (num) {
1889         ep = (struct DirEntry *)(vdatacwd->filedata + (num * 32));
1890         if (strcmp(ep->name, filename) == 0)
1891             break;
1892         num = ntohs(ep->next);
1893     }
1894
1895     if (!num) {
1896         fprintf(stderr, "%s: No such file or directory\n", filename);
1897         return NULL;
1898     }
1899
1900     if ((vdata = GetVnode(ntohl(ep->fid.vnode))) == NULL) {
1901         fprintf(stderr, "%s: No vnode information for %lu found\n", filename,
1902                 ntohl(ep->fid.vnode));
1903         return NULL;
1904     }
1905
1906     return vdata;
1907 }
1908
1909 /*
1910  * Reset a structure containing the current directory scan location
1911  */
1912
1913 static void
1914 ResetDirCursor(struct DirCursor *cursor, struct vnodeData *vdata)
1915 {
1916     struct DirHeader *dhp;
1917
1918     cursor->hashbucket = 0;
1919
1920     dhp = (struct DirHeader *)vdata->filedata;
1921
1922     cursor->entry = ntohs(dhp->hashTable[0]);
1923 }
1924
1925 /*
1926  * Given a cursor and a directory entry, return the next entry in the
1927  * directory.
1928  */
1929
1930 static struct DirEntry *
1931 ReadNextDir(struct DirCursor *cursor, struct vnodeData *vdata)
1932 {
1933     struct DirHeader *dhp;
1934     struct DirEntry *ep;
1935
1936     dhp = (struct DirHeader *)vdata->filedata;
1937
1938     if (cursor->entry) {
1939         ep = (struct DirEntry *)(vdata->filedata + (cursor->entry * 32));
1940         cursor->entry = ntohs(ep->next);
1941         return ep;
1942     } else {
1943         while (++(cursor->hashbucket) < NHASHENT) {
1944             cursor->entry = ntohs(dhp->hashTable[cursor->hashbucket]);
1945             if (cursor->entry) {
1946                 ep = (struct DirEntry *)(vdata->filedata +
1947                                          (cursor->entry * 32));
1948                 cursor->entry = ntohs(ep->next);
1949                 return ep;
1950             }
1951         }
1952     }
1953
1954     return NULL;
1955 }
1956
1957 /*
1958  * Given a string, split it up into components a la Unix argc/argv.
1959  *
1960  * This code is most stolen from ftp.
1961  */
1962
1963 static void
1964 MakeArgv(char *string, int *argc, char ***argv)
1965 {
1966     static char *largv[64];
1967     char **la = largv;
1968     char *s = string;
1969     static char argbuf[CMDBUFSIZE];
1970     char *ap = argbuf;
1971
1972     *argc = 0;
1973     *argv = largv;
1974
1975     while (*la++ = GetToken(s, &s, ap, &ap))
1976         (*argc)++;
1977 }
1978
1979 /*
1980  * Return a pointer to the next token, and update the current string
1981  * position.
1982  */
1983
1984 static char *
1985 GetToken(char *string, char **nexttoken, char argbuf[], char *nextargbuf[])
1986 {
1987     char *sp = string;
1988     char *ap = argbuf;
1989     int got_one = 0;
1990
1991   S0:
1992     switch (*sp) {
1993
1994     case '\0':
1995         goto OUTTOKEN;
1996
1997     case ' ':
1998     case '\t':
1999         sp++;
2000         goto S0;
2001
2002     default:
2003         goto S1;
2004     }
2005
2006   S1:
2007     switch (*sp) {
2008
2009     case ' ':
2010     case '\t':
2011     case '\0':
2012         goto OUTTOKEN;          /* End of our token */
2013
2014     case '\\':
2015         sp++;
2016         goto S2;                /* Get next character */
2017
2018     case '"':
2019         sp++;
2020         goto S3;                /* Get quoted string */
2021
2022     default:
2023         *ap++ = *sp++;          /* Add a character to our token */
2024         got_one = 1;
2025         goto S1;
2026     }
2027
2028   S2:
2029     switch (*sp) {
2030
2031     case '\0':
2032         goto OUTTOKEN;
2033
2034     default:
2035         *ap++ = *sp++;
2036         got_one = 1;
2037         goto S1;
2038     }
2039
2040   S3:
2041     switch (*sp) {
2042
2043     case '\0':
2044         goto OUTTOKEN;
2045
2046     case '"':
2047         sp++;
2048         goto S1;
2049
2050     default:
2051         *ap++ = *sp++;
2052         got_one = 1;
2053         goto S3;
2054     }
2055
2056   OUTTOKEN:
2057     if (got_one)
2058         *ap++ = '\0';
2059     *nextargbuf = ap;           /* Update storage pointer */
2060     *nexttoken = sp;            /* Update token pointer */
2061
2062     return got_one ? argbuf : NULL;
2063 }
2064
2065 /*
2066  * Insert vnodes into our hash table.
2067  */
2068
2069 static struct vnodeData *
2070 InsertVnode(unsigned int vnodeNumber, struct VnodeDiskObject *vnode)
2071 {
2072     struct VnodeDiskObject *nvnode;
2073     struct vnodeData *vdata;
2074     static int curSmallVnodeIndex = 0;
2075     static int curLargeVnodeIndex = 0;
2076     struct vnodeData ***vnodeIndex;
2077     int *curIndex;
2078
2079     nvnode = (struct VnodeDiskObject *)malloc(sizeof(struct VnodeDiskObject));
2080
2081     if (!nvnode) {
2082         if (verbose)
2083             fprintf(stderr, "Unable to allocate space for vnode\n");
2084         return NULL;
2085     }
2086
2087     memcpy((void *)nvnode, (void *)vnode, sizeof(struct VnodeDiskObject));
2088
2089     if (vnodeNumber & 1) {
2090         vnodeIndex = &LargeVnodeIndex;
2091         curIndex = &curLargeVnodeIndex;
2092     } else {
2093         vnodeIndex = &SmallVnodeIndex;
2094         curIndex = &curSmallVnodeIndex;
2095     }
2096
2097     vdata = (struct vnodeData *)malloc(sizeof(struct vnodeData));
2098
2099     vdata->vnode = nvnode;
2100     vdata->vnodeNumber = vnodeNumber;
2101     vdata->dumpdata = 0;
2102     vdata->filedata = 0;
2103     vdata->datalength = 0;
2104
2105     (*vnodeIndex)[(*curIndex)++] = vdata;
2106
2107     return vdata;
2108 }
2109
2110 /*
2111  * Routine to retrieve a vnode from the hash table.
2112  */
2113
2114 static struct vnodeData *
2115 GetVnode(unsigned int vnodeNumber)
2116 {
2117     struct vnodeData vnode, *vnodep, **tmp;
2118
2119     vnode.vnodeNumber = vnodeNumber;
2120     vnodep = &vnode;
2121
2122     tmp = (struct vnodeData **)
2123         bsearch((void *)&vnodep,
2124                 vnodeNumber & 1 ? LargeVnodeIndex : SmallVnodeIndex,
2125                 vnodeNumber & 1 ? numLargeVnodes : numSmallVnodes,
2126                 sizeof(struct vnodeData *), CompareVnode);
2127
2128     return tmp ? *tmp : NULL;
2129 }
2130
2131 /*
2132  * Our comparator function for bsearch
2133  */
2134
2135 static int
2136 CompareVnode(const void *node1, const void *node2)
2137 {
2138     struct vnodeData **vnode1 = (struct vnodeData **)node1;
2139     struct vnodeData **vnode2 = (struct vnodeData **)node2;
2140
2141     if ((*vnode1)->vnodeNumber == (*vnode2)->vnodeNumber)
2142         return 0;
2143     else if ((*vnode1)->vnodeNumber > (*vnode2)->vnodeNumber)
2144         return 1;
2145     else
2146         return -1;
2147 }
2148
2149 #ifdef RESIDENCY
2150 /*
2151  * Dump out the filename corresponding to a particular vnode.
2152  *
2153  * This routine has the following dependancies:
2154  *
2155  * - Only will work on UFS filesystems at this point
2156  * - Has to talk to the rsserver.
2157  * - Can only determine UFS algorithm type when run on the same machine
2158  *   as the residency (unless you manually specify algorithm information)
2159  */
2160
2161 static int
2162 DumpVnodeFile(FILE * f, struct VnodeDiskObject *vnode, VolumeDiskData * vol)
2163 {
2164     static int rscache = 0;
2165     static rsaccessinfoList rsnlist = { 0, 0 };
2166     char MountPoint[MAXPATHLEN + 1];
2167     char FileName[MAXPATHLEN + 1];
2168     unsigned int Size, Level[4];
2169     unsigned int DeviceTag, Algorithm;
2170     FileSystems *FSInfo;
2171     int i, found, FSType, rsindex;
2172
2173     /*
2174      * Maybe we found out something about this residency via the
2175      * command-line; check that first.
2176      */
2177
2178     rsindex = ffs(VLkp_Residencies(vnode)) - 1;
2179
2180     /*
2181      * We need to get information from the rsserver (so we can
2182      * find out the device tag for a given residency).  If we
2183      * haven't cached that, talk to the rsserver to get it.
2184      * If we have info about this already, then don't talk to
2185      * the rsserver (this lets us still do disaster recovery if
2186      * MR-AFS is completely hosed).
2187      */
2188
2189     if (!rscache && rscmdlineinfo[rsindex].DeviceTag == -1) {
2190         int code;
2191
2192         code = ServerInitResidencyConnection();
2193
2194         if (code) {
2195             fprintf(stderr,
2196                     "ServerInitResidencyConnection failed " "with code %d\n",
2197                     code);
2198             return -1;
2199         }
2200
2201         code = rs_GetResidencySummary(ServerRequestorId, &rsnlist);
2202
2203         if (code) {
2204             fprintf(stderr, "rs_GetResidencySummary failed " "with code %d\n",
2205                     code);
2206             return -1;
2207         }
2208
2209         rscache = 1;
2210     }
2211
2212     /*
2213      * For a given residency (as specified in the vnode),
2214      * find out it's device tag number, either via the rsserver
2215      * or via the command line.
2216      */
2217
2218     if (rscmdlineinfo[rsindex].DeviceTag != -1) {
2219         DeviceTag = rscmdlineinfo[rsindex].DeviceTag;
2220         found = 1;
2221     } else
2222         for (i = 0, found = 0; (i < rsnlist.rsaccessinfoList_len) && (!found);
2223              i++) {
2224             if (rsnlist.rsaccessinfoList_val[i].id.residency ==
2225                 VLkp_Residencies(vnode)) {
2226                 found = 1;
2227                 DeviceTag = rsnlist.rsaccessinfoList_val[i].devicetagnumber;
2228                 break;
2229             }
2230         }
2231
2232     if (!found) {
2233         if (verbose)
2234             fprintf(stderr,
2235                     "Unable to find residency %d in "
2236                     "rsserver database, aborting\n", VLkp_Residencies(vnode));
2237         return -1;
2238     }
2239
2240     /*
2241      * Okay, now we've got the DeviceTag ... which we can use to
2242      * lookup the on-disk configuration information (which we
2243      * assume is locally stored).  We also need the DeviceTag to
2244      * print out which partition we're using (but that comes later).
2245      *
2246      * We lookup the on-disk configuration information by calling
2247      * Ufs_GetFSInfo() to get the configuration information on the
2248      * filesystems specified by the given DeviceTag.
2249      *
2250      * Before we call Ufs_GetFSInfo, check the command-line cache;
2251      * if we got something via the command-line, don't go to disk.
2252      */
2253
2254     if (rscmdlineinfo[rsindex].FSType == -1
2255         && Ufs_GetFSInfo(&FSInfo, DeviceTag)) {
2256         if (verbose)
2257             fprintf(stderr,
2258                     "Ufs_GetFSInfo failed for DeviceTag "
2259                     "%d, Residency %d\n", DeviceTag, VLkp_Residencies(vnode));
2260         return -1;
2261     }
2262
2263     /*
2264      * The FSInfo structure has the last two things we need: the
2265      * FSType (ufs, slowufs, etc etc), and the usage algorithm (which
2266      * ends up being how many directories are being used on the
2267      * residency filesystem).
2268      *
2269      * With these last two parameters, use routines stolen from
2270      * ufsname to generate the filename.
2271      *
2272      * (Actually, I lied - we also need the "Size" parameter, which
2273      * we can also get from FSInfo);
2274      */
2275
2276     if (rscmdlineinfo[rsindex].FSType != -1) {
2277         FSType = rscmdlineinfo[rsindex].FSType;
2278         Algorithm = rscmdlineinfo[rsindex].Algorithm;
2279         Size = rscmdlineinfo[rsindex].Size;
2280     } else {
2281         FSType = FSInfo->FileSystems_u.UfsInterface.FSType;
2282         Algorithm = FSInfo->FileSystems_u.UfsInterface.Algorithm;
2283         if (FSInfo->FileSystems_u.UfsInterface.Directories[1] == 0)
2284             Size = 0;
2285         else if (FSInfo->FileSystems_u.UfsInterface.Directories[1] == 16)
2286             Size = 1;
2287         else if (FSInfo->FileSystems_u.UfsInterface.Directories[1] == 256)
2288             Size = 2;
2289         else {
2290             if (verbose)
2291                 fprintf(stderr, "Unknown directory size %d, " "aborting\n",
2292                         FSInfo->FileSystems_u.UfsInterface.Directories[1]);
2293             return -1;
2294         }
2295     }
2296
2297     /*
2298      * First, generate our mount point from the DeviceTag and
2299      * FSType.
2300      */
2301
2302     DEVICETAGNUMBERTOMOUNTPOINT(MountPoint, DeviceTag, FSType);
2303
2304     /*
2305      * Then, generate the "level" (directory bitmasks) from the
2306      * file tags, size, and algorithm
2307      */
2308
2309     UfsTagsToLevel(VLkp_FileTag1(vnode), VLkp_FileTag2(vnode), Algorithm,
2310                    Size, Level, VLkp_ParentVnodeId(vnode),
2311                    VLkp_ParentUniquifierId(vnode));
2312
2313     /*
2314      * Finally, take the above information and generate the
2315      * corresponding filename (this macro ends up being a
2316      * sprintf() call)
2317      */
2318
2319     TAGSTONAME(FileName, MountPoint, Level, Directories[Size][1],
2320                vol->parentId, VLkp_ParentVnodeId(vnode),
2321                VLkp_ParentUniquifierId(vnode), Algorithm);
2322
2323     fprintf(f, "%s\n", FileName);
2324
2325     return 0;
2326 }
2327 #endif
2328
2329 /*
2330  * Read a 16 bit integer in network order
2331  */
2332
2333 static int
2334 ReadInt16(FILE * f, unsigned short *s)
2335 {
2336     unsigned short in;
2337
2338     if (fread((void *)&in, sizeof(in), 1, f) != 1) {
2339         if (verbose)
2340             fprintf(stderr, "ReadInt16 failed!\n");
2341         return -1;
2342     }
2343
2344     *s = ntohs(in);
2345
2346     return 0;
2347 }
2348
2349
2350 /*
2351  * Read a 32 bit integer in network order
2352  */
2353
2354 static int
2355 ReadInt32(FILE * f, unsigned int *i)
2356 {
2357     unsigned int in;
2358
2359     if (fread((void *)&in, sizeof(in), 1, f) != 1) {
2360         if (verbose)
2361             fprintf(stderr, "ReadInt32 failed!\n");
2362         return -1;
2363     }
2364
2365     *i = ntohl((unsigned long)in);
2366
2367     return 0;
2368 }
2369
2370 /*
2371  * Read a string from a dump file
2372  */
2373
2374 static int
2375 ReadString(FILE * f, char *string, int maxlen)
2376 {
2377     int c;
2378
2379     while (maxlen--) {
2380         if ((*string++ = getc(f)) == 0)
2381             break;
2382     }
2383
2384     /*
2385      * I'm not sure what the _hell_ this is supposed to do ...
2386      * but it was in the original dump code
2387      */
2388
2389     if (string[-1]) {
2390         while ((c = getc(f)) && c != EOF);
2391         string[-1] = 0;
2392     }
2393
2394     return 0;
2395 }
2396
2397 static int
2398 ReadByteString(FILE * f, void *s, int size)
2399 {
2400     unsigned char *c = (unsigned char *)s;
2401
2402     while (size--)
2403         *c++ = getc(f);
2404
2405     return 0;
2406 }
2407
2408 /*
2409  * The directory hashing algorithm used by AFS
2410  */
2411
2412 DirHash(string)
2413      register char *string;
2414 {
2415     /* Hash a string to a number between 0 and NHASHENT. */
2416     register unsigned char tc;
2417     register int hval;
2418     register int tval;
2419     hval = 0;
2420     while (tc = (*string++)) {
2421         hval *= 173;
2422         hval += tc;
2423     }
2424     tval = hval & (NHASHENT - 1);
2425 #ifdef AFS_CRAY_ENV             /* actually, any > 32 bit environment */
2426     if (tval == 0)
2427         return tval;
2428     else if (hval & 0x80000000)
2429         tval = NHASHENT - tval;
2430 #else /* AFS_CRAY_ENV */
2431     if (tval == 0)
2432         return tval;
2433     else if (hval < 0)
2434         tval = NHASHENT - tval;
2435 #endif /* AFS_CRAY_ENV */
2436     return tval;
2437 }
2438
2439 #ifdef RESIDENCY
2440 /*
2441  * Sigh, we need this for the AFS libraries
2442  */
2443
2444 int
2445 LogErrors(int level, char *a, char *b, char *c, char *d, char *e, char *f,
2446           char *g, char *h, char *i, char *j, char *k)
2447 {
2448     if (level <= 0) {
2449         fprintf(stderr, a, b, c, d, e, f, g, h, i, j, k);
2450     }
2451     return 0;
2452 }
2453
2454 /*
2455  * These are routines taken from AFS libraries and programs.  Most of
2456  * them are from ufsname.c, but a few are from the dir library (the dir
2457  * library has a bunch of hidden dependancies, so it's not suitable to
2458  * include it outright).
2459  */
2460
2461 UfsEntropiesToTags(HighEntropy, LowEntropy, Algorithm, FileTag1, FileTag2)
2462      uint32_t HighEntropy;
2463      uint32_t LowEntropy;
2464      uint32_t Algorithm;
2465      uint32_t *FileTag1;
2466      uint32_t *FileTag2;
2467 {
2468     int i;
2469
2470     if ((Algorithm > UFS_ALGORITHMS) || (Algorithm <= 0))
2471         return -1;
2472     *FileTag1 = 0;
2473     *FileTag2 = 0;
2474     for (i = 0; i < 32; ++i) {
2475         if (UfsEntropy[Algorithm - 1][i] < 32)
2476             *FileTag1 |=
2477                 ((HighEntropy & (1 << i)) ==
2478                  0) ? 0 : 1 << UfsEntropy[Algorithm - 1][i];
2479         else
2480             *FileTag2 |=
2481                 ((HighEntropy & (1 << i)) ==
2482                  0) ? 0 : 1 << (UfsEntropy[Algorithm - 1][i] - 32);
2483     }
2484     for (i = 32; i < 64; ++i) {
2485         if (UfsEntropy[Algorithm - 1][i] < 32)
2486             *FileTag1 |=
2487                 ((LowEntropy & (1 << (i - 32))) ==
2488                  0) ? 0 : 1 << UfsEntropy[Algorithm - 1][i];
2489         else
2490             *FileTag2 |=
2491                 ((LowEntropy & (1 << (i - 32))) ==
2492                  0) ? 0 : 1 << (UfsEntropy[Algorithm - 1][i] - 32);
2493     }
2494     return 0;
2495 }
2496
2497 uint32_t
2498 UfsTagsToHighEntropy(FileTag1, FileTag2, Algorithm)
2499      uint32_t FileTag1;
2500      uint32_t FileTag2;
2501      uint32_t Algorithm;
2502 {
2503     int i;
2504     uint32_t Value;
2505
2506     Value = 0;
2507     for (i = 0; i < 32; ++i) {
2508         if (UfsEntropy[Algorithm - 1][i] < 32)
2509             Value |= ((FileTag1 & (1 << UfsEntropy[Algorithm - 1][i]))
2510                       == 0) ? 0 : 1 << i;
2511         else
2512             Value |=
2513                 ((FileTag2 & (1 << (UfsEntropy[Algorithm - 1][i] - 32))) ==
2514                  0) ? 0 : 1 << i;
2515     }
2516     return Value;
2517 }
2518
2519 uint32_t
2520 UfsTagsToLowEntropy(FileTag1, FileTag2, Algorithm)
2521      uint32_t FileTag1;
2522      uint32_t FileTag2;
2523      uint32_t Algorithm;
2524 {
2525     int i;
2526     uint32_t Value;
2527
2528     Value = 0;
2529     for (i = 32; i < 64; ++i) {
2530         if (UfsEntropy[Algorithm - 1][i] < 32)
2531             Value |= ((FileTag1 & (1 << UfsEntropy[Algorithm - 1][i]))
2532                       == 0) ? 0 : 1 << (i - 32);
2533         else
2534             Value |=
2535                 ((FileTag2 & (1 << (UfsEntropy[Algorithm - 1][i] - 32))) ==
2536                  0) ? 0 : 1 << (i - 32);
2537     }
2538     return Value;
2539 }
2540
2541 UfsTagsToLevel(FileTag1, FileTag2, Algorithm, Size, Sections, vnode,
2542                Uniquifier)
2543      uint32_t FileTag1;
2544      uint32_t FileTag2;
2545      uint32_t Algorithm;
2546      uint32_t Size;
2547      uint32_t Sections[4];
2548      uint32_t vnode;
2549      uint32_t Uniquifier;
2550 {
2551     uint32_t HighEntropy;
2552     uint32_t LowEntropy;
2553
2554     switch (Algorithm) {
2555     case 1:
2556         LowEntropy = UfsTagsToLowEntropy(FileTag1, FileTag2, Algorithm);
2557         HighEntropy = UfsTagsToHighEntropy(FileTag1, FileTag2, Algorithm);
2558         Sections[0] = HighEntropy % Directories[Size][0];
2559         HighEntropy /= Directories[Size][0];
2560         if (Directories[Size][1]) {
2561             Sections[1] = HighEntropy % Directories[Size][1];
2562             HighEntropy /= Directories[Size][1];
2563             Sections[2] = HighEntropy;
2564             Sections[3] = LowEntropy;
2565         } else {
2566             Sections[1] = HighEntropy;
2567             Sections[2] = LowEntropy;
2568         }
2569         break;
2570     case 2:
2571         Sections[0] = FileTag1 & 0xff;
2572         if (Directories[Size][1]) {
2573             Sections[1] = Uniquifier & 0xff;
2574             if (Directories[Size][1] == 16)
2575                 Sections[1] &= 0xf;
2576             Sections[2] = FileTag1;
2577             Sections[3] = FileTag2;
2578         } else {
2579             Sections[1] = FileTag1;
2580             Sections[2] = FileTag2;
2581         }
2582         break;
2583     case 3:
2584         Sections[0] = FileTag1 & 0xff;
2585         if (Directories[Size][1]) {
2586             Sections[1] = (vnode >> 1) & 0xff;
2587             if (Directories[Size][1] == 16)
2588                 Sections[1] &= 0xf;
2589             Sections[2] = FileTag1;
2590             Sections[3] = FileTag2;
2591         } else {
2592             Sections[1] = FileTag1;
2593             Sections[2] = FileTag2;
2594         }
2595         break;
2596     default:
2597         fprintf(stderr, "UfsTagsToLevel: bad algorithm %lu!\n", Algorithm);
2598         return -1;
2599     }
2600     return 0;
2601 }
2602
2603 #include <afs/afscbdummies.h>
2604 #endif /* RESIDENCY */