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