4 * dumptool - A tool to manage MR-AFS dump files
6 * The dump file format ought to be documented _somewhere_, and
7 * this seems like a good as a place as any ...
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):
13 * DUMPHEADER (tag 0x01)
14 * VOLUMEHEADER (tag 0x02)
18 * Descriptions of the sections follow. Note that in all cases, data is
19 * stored in the dump in network byte order.
23 * DUMPHEADER contains two parts: the DUMPMAGIC magic number (32 bits)
24 * and the dump header itself.
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.
32 * VOLUMEHEADER is a series of tagged values corresponding to the elements
33 * of the VolumeDiskData structure. See ReadVolumeHeader for more
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).
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.
50 * The DUMPEND section consists of one part: the DUMPENDMAGIC magic
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).
60 * "vos dump" dumps the large vnode index, then the small vnode index,
61 * so directories will appear first in the VNODE section.
64 #include <afsconfig.h>
65 #include <afs/param.h>
68 #include <sys/types.h>
69 #include <sys/param.h>
70 #include <netinet/in.h>
78 #include <sys/ioctl.h>
80 #include <rx/rx_queue.h>
82 #include <afs/afsint.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>
91 #ifdef AFS_LINUX24_ENV
92 #define _LARGEFILE64_SOURCE 1
95 #include <afs/rsdefs.h>
96 #include <afs/remioint.h>
97 #endif /* RESIDENCY */
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 */
112 * Sigh. Linux blows it again
120 * Stuff that is in private AFS header files, unfortunately
123 #define DUMPVERSION 1
124 #define DUMPENDMAGIC 0x3A214B6E
125 #define DUMPBEGINMAGIC 0xB3A11322
126 #define D_DUMPHEADER 1
127 #define D_VOLUMEHEADER 2
132 #define MAXDUMPTIMES 50
137 char volumeName[VNAMESIZE];
138 int nDumpTimes; /* Number of pairs */
141 } dumpTimes[MAXDUMPTIMES];
145 * Our command-line arguments
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];
157 * This stuff comes from ufsname.c (which itself takes it from
161 /* There is an assumption that all of the prefixes will have exactly one '/' */
162 static char *Ufs_Prefixes[] = { "/ufs", "/slowufs", "/cdmf", "/sdmf" };
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) \
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); \
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); \
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, \
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, \
201 #define DEVICETAGNUMBERTOMOUNTPOINT(MountPoint, DeviceTagNumber, FSType) \
202 sprintf(MountPoint,"%s%c", Ufs_Prefixes[FSType], UFS_MOUNTPOINTBASE + \
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"
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))
221 /* These routines generate a file name to correspond to the given tag
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},
236 uint32_t Directories[3][2] = { {256, 0}, {256, 16}, {256, 256}, };
237 #endif /* RESIDENCY */
239 static int verbose = 0;
240 static int numNoDirData = 0;
241 static int termsize = 0;
244 extern resid ServerRequestorId;
245 #endif /* RESIDENCY */
248 * We use this structure to hold vnode data in our hash table.
249 * It's indexed by vnode number.
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
257 unsigned char *filedata; /* A pointer to the actual file
258 * data itself (if available) */
259 unsigned int datalength; /* The length of the data */
263 * This contains the current location when we're doing a scan of a
268 int hashbucket; /* Current hash bucket */
269 int entry; /* Entry within hash bucket */
273 * Arrays to hold vnode data
276 struct vnodeData **LargeVnodeIndex;
277 struct vnodeData **SmallVnodeIndex;
278 int numLargeVnodes = 0;
279 int numSmallVnodes = 0;
282 * Crap for the libraries
285 int ShutdownInProgress = 0;
288 * Our local function prototypes
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);
318 static int DumpVnodeFile(FILE *, struct VnodeDiskObject *, VolumeDiskData *);
319 static void DumpAllResidencies(FILE *, struct vnodeData *, VolumeDiskData *);
323 main(int argc, char *argv[])
325 int c, errflg = 0, force = 0, inode = 0;
327 struct DumpHeader dheader;
331 int Res, Arg1, Arg2, Arg3, i;
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;
347 #endif /* RESIDENCY */
350 * Sigh, this is dumb, but we need the terminal window size
351 * to do intelligent things with "ls" later on.
354 if (isatty(STDOUT_FILENO)) {
355 if ((p = getenv("COLUMNS")) != NULL)
357 else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0
359 termsize = win.ws_col;
362 while ((c = getopt(argc, argv, "difr:t:v")) != EOF)
366 if (sscanf(optarg, "%d/%d", &Res, &Arg1) != 2) {
371 if (1 << (ffs(Res) - 1) != Res) {
372 fprintf(stderr, "Invalid residency %d\n", Res);
377 if (Arg1 < 0 || Arg1 > 26) {
378 fprintf(stderr, "Invalid device tag: %d\n", Arg1);
382 rscmdlineinfo[ffs(Res) - 1].DeviceTag = Arg1;
383 #else /* RESIDENCY */
384 fprintf(stderr, "-t not supported in non-MRAFS " "dumptool.\n");
386 #endif /* RESIDENCY */
391 if (sscanf(optarg, "%d/%d/%d/%d", &Res, &Arg1, &Arg2, &Arg3) != 4) {
396 if (Arg1 < 0 || Arg1 > 3) {
397 fprintf(stderr, "Invalid fstype: %d\n", Arg1);
402 if (Arg2 < 0 || Arg2 > 2) {
403 fprintf(stderr, "Invalid size: %d\n", Arg2);
408 if (Arg3 <= 0 || Arg3 > UFS_ALGORITHMS) {
409 fprintf(stderr, "Invalid algorithm: %d\n", Arg3);
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");
419 #endif /* RESIDENCY */
424 #else /* RESIDENCY */
425 fprintf(stderr, "-d not supported in non-MRAFS " "dumptool.\n");
427 #endif /* RESIDENCY */
443 if (errflg || optind == argc) {
444 fprintf(stderr, "Usage: %s\n\t[-v] [-f]\n\t"
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 */
451 #endif /* RESIDENCY */
457 * Try opening the dump file
461 if ((fd = open(argv[optind], O_RDONLY | O_LARGEFILE)) < 0) {
463 if ((fd = open(argv[optind], O_RDONLY)) < 0) {
465 fprintf(stderr, "open of dumpfile %s failed: %s\n", argv[optind],
470 if ((f = fdopen(fd, "rb")) == NULL) {
471 fprintf(stderr, "fdopen of dumpfile %s failed: %s\n", argv[optind],
476 if (ReadDumpHeader(f, &dheader)) {
477 fprintf(stderr, "Failed to read dump header!\n");
482 printf("Dump is for volume %lu (%s)\n",
483 (unsigned long) dheader.volumeId, dheader.volumeName);
485 if (getc(f) != D_VOLUMEHEADER) {
486 fprintf(stderr, "Volume header is missing from dump, aborting\n");
490 if (ReadVolumeHeader(f, &vol)) {
491 fprintf(stderr, "Unable to read volume header\n");
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);
504 printf(" inService");
507 if (vol.needsSalvaged)
508 printf(" needsSalvaged");
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);
521 printf("Scanning vnodes (this may take a while)\n");
524 * We need to do two vnode scans; one to get the number of
525 * vnodes, the other to actually build the index.
528 offset = ftello64(f);
530 if (ScanVnodes(f, &vol, 1)) {
531 fprintf(stderr, "First vnode scan failed, aborting\n");
535 fseeko64(f, offset, SEEK_SET);
537 if (ScanVnodes(f, &vol, 0)) {
538 fprintf(stderr, "Second vnode scan failed, aborting\n");
542 if (getc(f) != D_DUMPEND || ReadInt32(f, &magic) || magic != DUMPENDMAGIC) {
543 fprintf(stderr, "Couldn't find dump postamble, ");
545 fprintf(stderr, "aborting (use -f to override)\n");
548 fprintf(stderr, "continuing anyway\n");
549 fprintf(stderr, "WARNING: Dump may not be complete!\n");
554 * If we wanted to simply dump all vnodes, do it now
559 struct vnodeData *vdata;
561 for (i = 0; i < numLargeVnodes; i++) {
563 vdata = LargeVnodeIndex[i];
565 if (vdata->vnode->type == vFidLookup)
566 if (DumpVnodeFile(stdout, vdata->vnode, &vol)) {
567 fprintf(stderr, "DumpVnodeFile failed, " "aborting\n");
572 for (i = 0; i < numSmallVnodes; i++) {
574 vdata = SmallVnodeIndex[i];
576 if (vdata->vnode->type == vFidLookup)
577 if (DumpVnodeFile(stdout, vdata->vnode, &vol)) {
578 fprintf(stderr, "DumpVnodeFile failed, " "aborting\n");
584 #endif /* RESIDENCY */
587 * Dump out all filenames with their corresponding FID
590 struct vnodeData *rootvdata;
592 if ((rootvdata = GetVnode(1)) == NULL) {
594 "Can't get vnode data for root " "vnode! Aborting\n");
598 DirListInternal(rootvdata, NULL, 0, 0, 1, 0, 1, 0, &vol, "");
600 } else if (argc > optind + 1) {
603 * Dump out residencies of files given on the command line.
606 struct vnodeData *vdata, *rootvdata;
608 if ((rootvdata = GetVnode(1)) == NULL) {
610 "Can't get vnode data for root " "vnode! Aborting\n");
614 for (i = optind + 1; i < argc; i++) {
616 if ((vdata = FindFile(rootvdata, argv[i])) == NULL) {
617 fprintf(stderr, "Skipping file %s\n", argv[i]);
622 printf("Residency locations for %s:\n", argv[i]);
624 while (vdata->vnode->NextVnodeId != 0) {
626 vdata = GetVnode(vdata->vnode->NextVnodeId);
630 "We had a vnode chain " "pointer to a vnode that "
631 "doesn't exist, aborting!\n");
634 if (vdata->vnode->type == vFidLookup)
635 DumpVnodeFile(stdout, vdata->vnode, &vol);
638 #else /* RESIDENCY */
639 fprintf(stderr, "Extra arguments after dump filename: %s\n",
642 #endif /* RESIDENCY */
645 * Perform an interactive restore
648 InteractiveRestore(f, &vol);
655 * Read the dump header, which is at the beginning of every dump
659 ReadDumpHeader(FILE * f, struct DumpHeader *header)
664 if (getc(f) != D_DUMPHEADER || ReadInt32(f, &magic)
665 || ReadInt32(f, (unsigned int *)
666 &header->version) || magic != DUMPBEGINMAGIC) {
668 fprintf(stderr, "Couldn't find dump magic numbers\n");
672 header->volumeId = 0;
673 header->nDumpTimes = 0;
675 while ((tag = getc(f)) > D_MAX && tag != EOF) {
676 unsigned short length;
679 if (ReadInt32(f, &header->volumeId)) {
681 fprintf(stderr, "Failed to read " "volumeId\n");
686 if (ReadString(f, header->volumeName, sizeof(header->volumeName))) {
688 fprintf(stderr, "Failed to read " "volume name\n");
693 if (ReadInt16(f, &length)) {
696 "Failed to read " "dump time array length\n");
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)) {
706 fprintf(stderr, "Failed to " "read dump times\n");
712 fprintf(stderr, "Unknown dump tag \"%c\"\n", tag);
717 if (!header->volumeId || !header->nDumpTimes) {
720 "We didn't get a volume Id or " "dump times listing\n");
729 * Read the volume header; this is the information stored in VolumeDiskData.
731 * I'm not sure we need all of this, but read it in just in case.
735 ReadVolumeHeader(FILE * f, VolumeDiskData * vol)
739 memset((void *)vol, 0, sizeof(*vol));
741 while ((tag = getc(f)) > D_MAX && tag != EOF) {
744 if (ReadInt32(f, &vol->id))
748 if (ReadInt32(f, &trash))
752 if (ReadString(f, vol->name, sizeof(vol->name)))
756 vol->inService = getc(f);
759 vol->blessed = getc(f);
762 if (ReadInt32(f, &vol->uniquifier))
769 if (ReadInt32(f, &vol->parentId))
773 if (ReadInt32(f, &vol->cloneId))
777 if (ReadInt32(f, (uint32_t *) & vol->maxquota))
781 if (ReadInt32(f, (uint32_t *) & vol->minquota))
785 if (ReadInt32(f, (uint32_t *) & vol->diskused))
789 if (ReadInt32(f, (uint32_t *) & vol->filecount))
793 if (ReadInt32(f, &vol->accountNumber))
797 if (ReadInt32(f, &vol->owner))
801 if (ReadInt32(f, &vol->creationDate))
805 if (ReadInt32(f, &vol->accessDate))
809 if (ReadInt32(f, &vol->updateDate))
813 if (ReadInt32(f, &vol->expirationDate))
817 if (ReadInt32(f, &vol->backupDate))
822 (f, vol->offlineMessage, sizeof(vol->offlineMessage)))
826 if (ReadString(f, (char *)vol->stat_reads, VMSGSIZE))
830 unsigned short length;
833 if (ReadInt16(f, &length))
835 for (i = 0; i < length; i++) {
836 if (ReadInt32(f, &data))
838 if (i < sizeof(vol->weekUse) / sizeof(vol->weekUse[0]))
839 vol->weekUse[i] = data;
844 if (ReadInt32(f, &vol->dayUseDate))
848 if (ReadInt32(f, (uint32_t *) & vol->dayUse))
853 unsigned short length;
857 if (ReadInt16(f, &length))
859 for (i = 0; i < length; i++) {
860 if (ReadInt32(f, &data))
863 sizeof(vol->DesiredInfo.DesiredResidencyWords) /
864 sizeof(vol->DesiredInfo.DesiredResidencyWords[0]))
865 vol->DesiredInfo.DesiredResidencyWords[i] = data;
870 unsigned short length;
874 if (ReadInt16(f, &length))
876 for (i = 0; i < length; i++) {
877 if (ReadInt32(f, &data))
880 sizeof(vol->UnDesiredInfo.UnDesiredResidencyWords) /
881 sizeof(vol->UnDesiredInfo.UnDesiredResidencyWords[0]))
882 vol->UnDesiredInfo.UnDesiredResidencyWords[i] = data;
889 fprintf(stderr, "Unknown dump tag \"%c\"\n", tag);
899 * Scan all our vnode entries, and build indexing information.
903 ScanVnodes(FILE * f, VolumeDiskData * vol, int sizescan)
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;
917 while (tag == D_VNODE) {
924 if (ReadInt32(f, (uint32_t *) & vnodeNumber)) {
925 fprintf(stderr, "failed int32 for 'vnodenum'\n");
929 if (ReadInt32(f, &vnode->uniquifier)) {
930 fprintf(stderr, "failed int32 for 'uniquifier'\n");
934 if (verbose > 1 && !sizescan)
935 printf("Got vnode %d\n", vnodeNumber);
937 while ((tag = getc(f)) > D_MAX && tag != EOF)
940 vnode->type = (VnodeType) getc(f);
945 if (ReadInt16(f, &tmp)) {
946 fprintf(stderr, "failed int16 for 'l'\n");
949 vnode->linkCount = tmp;
953 if (ReadInt32(f, &vnode->dataVersion)) {
954 fprintf(stderr, "failed int32 for 'v'\n");
959 if (ReadInt32(f, (uint32_t *) & vnode->unixModifyTime)) {
960 fprintf(stderr, "failed int32 for 'm'\n");
965 if (ReadInt32(f, (uint32_t *) & vnode->serverModifyTime)) {
966 fprintf(stderr, "failed int32 for 's'\n");
971 if (ReadInt32(f, &vnode->author)) {
972 fprintf(stderr, "failed int32 for 'a'\n");
977 if (ReadInt32(f, &vnode->owner)) {
978 fprintf(stderr, "failed int32 for 'o'\n");
983 if (ReadInt32(f, (uint32_t *) & vnode->group)) {
984 fprintf(stderr, "failed int32 for 'g'\n");
989 unsigned short modeBits;
990 if (ReadInt16(f, &modeBits))
992 vnode->modeBits = modeBits;
996 if (ReadInt32(f, &vnode->parent)) {
997 fprintf(stderr, "failed int32 for 'p'\n");
1003 if (ReadInt32(f, &vnode->NextVnodeId)) {
1004 fprintf(stderr, "failed int32 for 'N'\n");
1009 if (ReadInt32(f, &VLkp_Residencies(vnode))) {
1010 fprintf(stderr, "failed int32 for 'R'\n");
1016 if (ReadInt32(f, &vnode->length)) {
1017 fprintf(stderr, "failed int32 for 'S'\n");
1022 if (ReadInt32(f, (uint32_t *) & vnode->vn_ino_lo))
1027 (f, (void *)VVnodeDiskACL(vnode), VAclDiskSize(vnode))) {
1028 fprintf(stderr, "failed readbystring for 'A'\n");
1032 acl_NtohACL(VVnodeDiskACL(vnode));
1037 if (ReadInt32(f, &vnode->length_hi)) {
1038 fprintf(stderr, "failed int32 for 'h'\n");
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");
1049 vnode->length = length;
1050 offset = ftello64(f);
1051 fseeko64(f, length, SEEK_CUR);
1055 fprintf(stderr, "Unknown dump tag \"%c\"\n", tag);
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.
1067 if (vnode->type == -1)
1071 if (verbose > 1 && vnode->type == vFidLookup && !sizescan) {
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))
1079 if (verbose > 1 && vnode->type == vAccessHistory && !sizescan)
1080 printf("This is an auxiliary vnode (history) for vnode %d\n",
1081 VLkp_ParentVnodeId(vnode));
1084 if (vnode->type == vDirectory)
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).
1097 vdata = InsertVnode(vnodeNumber, vnode);
1099 if (vdata == NULL) {
1102 "Failed to insert " "vnode into hash table");
1106 vdata->dumpdata = offset;
1107 vdata->datalength = length;
1110 * Save directory data, since we'll need it later.
1113 if (vnode->type == vDirectory && length) {
1115 vdata->filedata = malloc(length);
1117 if (!vdata->filedata) {
1120 "Unable to " "allocate space for "
1121 "file data (%d)\n", length);
1125 oldoffset = ftello64(f);
1126 fseeko64(f, offset, SEEK_SET);
1128 if (fread(vdata->filedata, length, 1, f) != 1) {
1130 fprintf(stderr, "Unable to " "read in file data!\n");
1134 fseeko64(f, oldoffset, SEEK_SET);
1135 } else if (vnode->type == vDirectory)
1137 * Warn the user we may not have all directory
1148 numLargeVnodes = numDirVnodes;
1149 numSmallVnodes = numFileVnodes;
1152 if (numDirVnodes == 0)
1153 LargeVnodeIndex = NULL;
1155 LargeVnodeIndex = malloc(numDirVnodes
1156 * sizeof(struct vnodeData *));
1157 if (numFileVnodes == 0)
1158 SmallVnodeIndex = NULL;
1160 SmallVnodeIndex = malloc(numFileVnodes
1161 * sizeof(struct vnodeData *));
1163 if ((numDirVnodes != 0 && LargeVnodeIndex == NULL) ||
1164 (numFileVnodes != 0 && SmallVnodeIndex == NULL)) {
1167 "Unable to allocate space " "for vnode tables\n");
1173 fprintf(stderr, "%s vnode scan completed\n",
1174 sizescan ? "Primary" : "Secondary");
1180 * Perform an interactive restore
1182 * Parsing the directory information is a pain, but other than that
1183 * we just use the other tools we already have in here.
1185 #define CMDBUFSIZE (AFSPATHMAX * 2)
1187 InteractiveRestore(FILE * f, VolumeDiskData * vol)
1189 struct vnodeData *vdatacwd; /* Vnode data for our current dir */
1190 char cmdbuf[CMDBUFSIZE];
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.
1199 if ((vdatacwd = GetVnode(1)) == NULL) {
1200 fprintf(stderr, "No entry for our root vnode! Aborting\n");
1204 if (!vdatacwd->filedata) {
1206 "There is no directory data for the root "
1207 "vnode (1.1). An interactive\nrestore is not "
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.
1220 "WARNING: %d directory vnodes had no file "
1221 "data. An interactive restore\nmay not be possible\n",
1225 while (fgets(cmdbuf, CMDBUFSIZE, stdin)) {
1227 cmdbuf[strlen(cmdbuf) - 1] = '\0';
1229 if (strlen(cmdbuf) == 0) {
1234 MakeArgv(cmdbuf, &argc, &argv);
1236 if (strcmp(argv[0], "ls") == 0) {
1237 DirectoryList(argc, argv, vdatacwd, vol);
1238 } else if (strcmp(argv[0], "cd") == 0) {
1239 struct vnodeData *newvdata;
1241 newvdata = ChangeDirectory(argc, argv, vdatacwd);
1244 vdatacwd = newvdata;
1245 } else if (strcmp(argv[0], "file") == 0) {
1246 DumpAllFiles(argc, argv, vdatacwd, vol);
1247 } else if (strcmp(argv[0], "cp") == 0) {
1248 CopyFile(argc, argv, vdatacwd, f);
1249 } else if (strcmp(argv[0], "vcp") == 0) {
1250 CopyVnode(argc, argv, f);
1251 } else if (strcmp(argv[0], "quit") == 0
1252 || strcmp(argv[0], "exit") == 0)
1254 else if (strcmp(argv[0], "?") == 0 || strcmp(argv[0], "help") == 0) {
1255 printf("Valid commands are:\n");
1256 printf("\tls\t\tList current directory\n");
1257 printf("\tcd\t\tChange current directory\n");
1258 printf("\tcp\t\tCopy file from dump\n");
1259 printf("\tvcp\t\tCopy file from dump (via vnode)\n");
1261 printf("\tfile\t\tList residency filenames\n");
1262 #endif /* RESIDENCY */
1263 printf("\tquit | exit\tExit program\n");
1264 printf("\thelp | ?\tBrief help\n");
1267 "Unknown command, \"%s\", enter "
1268 "\"help\" for a list of commands.\n", argv[0]);
1277 * Do a listing of all files in a directory. Sigh, I wish this wasn't
1280 * With the reorganizing, this is just a front-end to DirListInternal()
1284 DirectoryList(int argc, char **argv, struct vnodeData *vdata,
1285 VolumeDiskData * vol)
1287 int errflg = 0, lflag = 0, iflag = 0, Fflag = 0, sflag = 0, Rflag = 0;
1292 while ((c = getopt(argc, argv, "liFRs")) != EOF)
1314 fprintf(stderr, "Usage: %s [-liFs] filename [filename ...]\n",
1319 DirListInternal(vdata, &(argv[optind]), argc - optind, lflag, iflag,
1320 Fflag, Rflag, 1, vol, NULL);
1326 * Function that does the REAL work in terms of directory listing
1330 DirListInternal(struct vnodeData *vdata, char *pathnames[], int numpathnames,
1331 int lflag, int iflag, int Fflag, int Rflag, int verbose,
1332 VolumeDiskData * vol, char *path)
1334 struct DirEntry *ep, **eplist = NULL, **eprecurse = NULL;
1335 struct DirCursor cursor;
1336 struct vnodeData *lvdata;
1338 int i, j, numentries = 0, longestname = 0, numcols, col, numrows;
1341 if (!vdata->filedata) {
1342 fprintf(stderr, "There is no vnode data for this " "directory!\n");
1346 ResetDirCursor(&cursor, vdata);
1349 * Scan through the whole directory
1352 while ((ep = ReadNextDir(&cursor, vdata)) != NULL) {
1355 * If we didn't get any filenames on the command line,
1359 if (numpathnames == 0) {
1361 realloc(eplist, sizeof(struct DirEntry *) * ++numentries);
1362 eplist[numentries - 1] = ep;
1363 if (strlen(ep->name) > longestname)
1364 longestname = strlen(ep->name);
1366 if ((lvdata = GetVnode(ntohl(ep->fid.vnode)))
1367 && lvdata->vnode->type == vDirectory
1368 && !(strcmp(ep->name, ".") == 0
1369 || strcmp(ep->name, "..") == 0)) {
1372 sizeof(struct DirEntry *) * ++numrecurse);
1373 eprecurse[numrecurse - 1] = ep;
1378 * Do glob matching via fnmatch()
1381 for (i = 0; i < numpathnames; i++)
1382 if (fnmatch(pathnames[i], ep->name, FNM_PATHNAME) == 0) {
1385 sizeof(struct DirEntry *) * ++numentries);
1386 eplist[numentries - 1] = ep;
1387 if (strlen(ep->name) > longestname)
1388 longestname = strlen(ep->name);
1390 if ((lvdata = GetVnode(ntohl(ep->fid.vnode)))
1391 && lvdata->vnode->type == vDirectory
1392 && !(strcmp(ep->name, ".") == 0
1393 || strcmp(ep->name, "..") == 0)) {
1396 sizeof(struct DirEntry *) *
1398 eprecurse[numrecurse - 1] = ep;
1405 qsort((void *)eplist, numentries, sizeof(struct DirEntry *),
1408 if (Rflag && eprecurse)
1409 qsort((void *)eprecurse, numrecurse, sizeof(struct DirEntry *),
1412 * We don't have to do column printing if we have the -l or the -i
1413 * options. Sigh, column printing is WAY TOO FUCKING COMPLICATED!
1416 if (!lflag && !iflag) {
1424 numcols = termsize / longestname ? termsize / longestname : 1;
1425 numrows = numentries / numcols + (numentries % numcols ? 1 : 0);
1427 for (i = 0; i < numrows; i++) {
1429 while (col < numcols && (i + col * numrows) < numentries) {
1430 ep = eplist[i + col++ * numrows];
1432 if (!(lvdata = GetVnode(ntohl(ep->fid.vnode))))
1434 else if (lvdata->vnode->type == vDirectory)
1436 else if (lvdata->vnode->type == vSymlink)
1438 else if ((lvdata->vnode->modeBits & 0111) != 0)
1442 printf("%s%-*c", ep->name, (int)(longestname -
1443 strlen(ep->name)), c);
1445 printf("%-*s", longestname, ep->name);
1451 for (i = 0; i < numentries; i++)
1452 if (!(lvdata = GetVnode(ntohl(eplist[i]->fid.vnode))))
1453 printf("%" AFS_VOLID_FMT ".0.0\t%s\n",
1454 vol->parentId ? afs_printable_VolumeId_lu(vol->parentId)
1455 : afs_printable_VolumeId_lu(vol->id),
1458 printf("%" AFS_VOLID_FMT ".%d.%d\t%s/%s\n",
1459 afs_printable_VolumeId_lu(vol->id),
1460 ntohl(eplist[i]->fid.vnode),
1461 ntohl(eplist[i]->fid.vunique), path, eplist[i]->name);
1463 printf("%" AFS_VOLID_FMT ".%d.%d\t%s\n",
1464 afs_printable_VolumeId_lu(vol->id),
1465 ntohl(eplist[i]->fid.vnode),
1466 ntohl(eplist[i]->fid.vunique), eplist[i]->name);
1468 for (i = 0; i < numentries; i++)
1469 if (!(lvdata = GetVnode(ntohl(eplist[i]->fid.vnode))))
1470 printf("---------- 0 0 " "0 0 %s\n",
1473 switch (lvdata->vnode->type) {
1484 for (j = 8; j >= 0; j--) {
1485 if (lvdata->vnode->modeBits & (1 << j))
1499 printf(" %-3d %-8d %-8d %10d %s\n", lvdata->vnode->linkCount,
1500 lvdata->vnode->owner, lvdata->vnode->group,
1501 lvdata->vnode->length, eplist[i]->name);
1507 if (Rflag && eprecurse) {
1510 for (i = 0; i < numrecurse; i++) {
1512 printf("\n%s:\n", eprecurse[i]->name);
1514 lpath = malloc(strlen(path) + strlen(eprecurse[i]->name) + 2);
1516 sprintf(lpath, "%s/%s", path, eprecurse[i]->name);
1518 DirListInternal(GetVnode(ntohl(eprecurse[i]->fid.vnode)), NULL, 0,
1519 lflag, iflag, Fflag, Rflag, verbose, vol, lpath);
1535 * Directory name comparison function, used by qsort
1539 CompareDirEntry(const void *e1, const void *e2)
1541 struct DirEntry **ep1 = (struct DirEntry **)e1;
1542 struct DirEntry **ep2 = (struct DirEntry **)e2;
1544 return strcmp((*ep1)->name, (*ep2)->name);
1548 * Change a directory. Return a pointer to our new vdata structure for
1552 static struct vnodeData *
1553 ChangeDirectory(int argc, char **argv, struct vnodeData *vdatacwd)
1555 struct vnodeData *newvdatacwd;
1558 fprintf(stderr, "Usage: %s directory\n", argv[0]);
1562 if ((newvdatacwd = FindFile(vdatacwd, argv[1])) == NULL)
1565 if (newvdatacwd->vnode->type != vDirectory) {
1566 fprintf(stderr, "%s: Not a directory\n", argv[1]);
1570 if (newvdatacwd->filedata == NULL) {
1571 fprintf(stderr, "%s: No directory data found.\n", argv[1]);
1579 * Copy a file from out of the dump file
1582 #define COPYBUFSIZE 8192
1585 CopyFile(int argc, char **argv, struct vnodeData *vdatacwd, FILE * f)
1587 struct vnodeData *vdata;
1591 char buffer[COPYBUFSIZE];
1594 fprintf(stderr, "Usage: %s dumpfile destfile\n", argv[0]);
1598 if ((vdata = FindFile(vdatacwd, argv[1])) == NULL)
1601 if (vdata->dumpdata == 0) {
1602 fprintf(stderr, "File %s has no data in dump file\n", argv[1]);
1606 if ((out = fopen(argv[2], "wb")) == NULL) {
1607 fprintf(stderr, "Open of %s failed: %s\n", argv[2], strerror(errno));
1611 if (fseeko64(f, vdata->dumpdata, SEEK_SET)) {
1612 fprintf(stderr, "Seek failed: %s\n", strerror(errno));
1617 while (cur < vdata->datalength) {
1621 vdata->datalength ? COPYBUFSIZE : vdata->datalength - cur;
1623 ret = fread(buffer, sizeof(char), bytes, f);
1626 fprintf(stderr, "Short read (expected %d, " "got %d)\n",
1629 fprintf(stderr, "Error during read: %s\n", strerror(errno));
1634 ret = fwrite(buffer, sizeof(char), bytes, out);
1637 fprintf(stderr, "Short write (expected %d, " "got %d)\n",
1640 fprintf(stderr, "Error during write: %s\n", strerror(errno));
1652 * Copy a file from out of the dump file, by using the vnode
1656 CopyVnode(int argc, char *argv[], FILE * f)
1658 struct vnodeData *vdata;
1662 char buffer[COPYBUFSIZE];
1663 unsigned int vnode, uniquifier = 0;
1666 fprintf(stderr, "Usage: %s vnode[.uniqifier] destfile\n", argv[0]);
1670 ret = sscanf(argv[1], "%d.%d", &vnode, &uniquifier);
1673 fprintf(stderr, "Invalid file identifier: %s\n", argv[1]);
1677 if (!(vdata = GetVnode(vnode))) {
1678 fprintf(stderr, "Vnode %d not in dump file\n", vnode);
1682 if (ret == 2 && vdata->vnode->uniquifier != uniquifier) {
1684 "Specified uniquifier %d did not match "
1685 "uniquifier %d found in dump file!\n", uniquifier,
1686 vdata->vnode->uniquifier);
1690 if (vdata->dumpdata == 0) {
1691 fprintf(stderr, "File %s has no data in dump file\n", argv[1]);
1695 if ((out = fopen(argv[2], "wb")) == NULL) {
1696 fprintf(stderr, "Open of %s failed: %s\n", argv[2], strerror(errno));
1700 if (fseeko64(f, vdata->dumpdata, SEEK_SET)) {
1701 fprintf(stderr, "Seek failed: %s\n", strerror(errno));
1706 while (cur < vdata->datalength) {
1710 vdata->datalength ? COPYBUFSIZE : vdata->datalength - cur;
1712 ret = fread(buffer, sizeof(char), bytes, f);
1715 fprintf(stderr, "Short read (expected %d, " "got %d)\n",
1718 fprintf(stderr, "Error during read: %s\n", strerror(errno));
1723 ret = fwrite(buffer, sizeof(char), bytes, out);
1726 fprintf(stderr, "Short write (expected %d, " "got %d)\n",
1729 fprintf(stderr, "Error during write: %s\n", strerror(errno));
1741 * Dump all residency filenames associated with a file, or all files
1742 * within a directory.
1746 DumpAllFiles(int argc, char **argv, struct vnodeData *vdatacwd,
1747 VolumeDiskData * vol)
1750 struct vnodeData *vdata, *nvdata;
1751 struct DirCursor cursor;
1752 struct DirEntry *ep;
1755 int dflag = 0, fflag = 0, errflg = 0;
1759 while ((c = getopt(argc, argv, "df:")) != EOF)
1765 if ((f = fopen(optarg, "a")) == NULL) {
1766 fprintf(stderr, "Cannot open \"%s\": %s\n", optarg,
1778 if (errflg || argc == optind) {
1779 fprintf(stderr, "Usage: %s [-d] [-f filename] file " "[file ...]\n",
1786 for (i = optind; i < argc; i++) {
1788 if ((vdata = FindFile(vdatacwd, argv[i])) == NULL)
1791 if (vdata->vnode->type == vDirectory && !dflag) {
1793 ResetDirCursor(&cursor, vdata);
1795 while ((ep = ReadNextDir(&cursor, vdata)) != NULL) {
1797 if (!(nvdata = GetVnode(ntohl(ep->fid.vnode)))) {
1799 "Cannot find vnode " "entry for %s (%d)\n",
1800 ep->name, ntohl(ep->fid.vnode));
1806 printf("Residency locations for %s:\n", ep->name);
1808 if (nvdata->dumpdata)
1809 printf("Local disk (in dump " "file)\n");
1812 DumpAllResidencies(f, nvdata, vol);
1818 printf("Residency locations for %s:\n", argv[i]);
1820 if (vdata->dumpdata)
1821 printf("Local disk (in dump file)\n");
1824 DumpAllResidencies(f, vdata, vol);
1830 #else /* RESIDENCY */
1832 "The \"file\" command is not available in the non-"
1833 "MRAFS version of dumptool.\n");
1834 #endif /* RESIDENCY */
1839 * Take a vnode, traverse the vnode chain, and dump out all files on
1840 * all residencies corresponding to that parent vnode.
1845 DumpAllResidencies(FILE * f, struct vnodeData *vdata,
1846 struct VolumeDiskData *vol)
1848 unsigned int nextVnodeNum;
1850 while (nextVnodeNum = vdata->vnode->NextVnodeId) {
1851 if ((vdata = GetVnode(nextVnodeNum)) == NULL) {
1853 "We had a pointer to %lu in it's "
1854 "vnode chain, but there\nisn't a record of "
1855 "it! The dump might be corrupt.\n", nextVnodeNum);
1859 if (vdata->vnode->type == vFidLookup)
1860 DumpVnodeFile(f, vdata->vnode, vol);
1869 * Given a directory vnode and a filename, return the vnode corresponding
1870 * to the file in that directory.
1872 * We now handle pathnames with directories in them.
1875 static struct vnodeData *
1876 FindFile(struct vnodeData *vdatacwd, char *filename)
1878 struct DirHeader *dhp;
1879 struct DirEntry *ep;
1881 struct vnodeData *vdata;
1882 char *c, newstr[MAXPATHLEN];
1884 if (!vdatacwd->filedata) {
1885 fprintf(stderr, "There is no vnode data for this " "directory!\n");
1890 * If we have a "/" in here, look up the vnode data for the
1891 * directory (everything before the "/") and use that as our
1892 * current directory. We automagically handle multiple directories
1893 * by using FindFile recursively.
1896 if ((c = strrchr(filename, '/')) != NULL) {
1898 strncpy(newstr, filename, c - filename);
1899 newstr[c - filename] = '\0';
1901 if ((vdatacwd = FindFile(vdatacwd, newstr)) == NULL)
1904 if (vdatacwd->vnode->type != vDirectory) {
1905 fprintf(stderr, "%s: Not a directory\n", newstr);
1912 dhp = (struct DirHeader *)vdatacwd->filedata;
1914 i = DirHash(filename);
1916 num = ntohs(dhp->hashTable[i]);
1919 ep = (struct DirEntry *)(vdatacwd->filedata + (num * 32));
1920 if (strcmp(ep->name, filename) == 0)
1922 num = ntohs(ep->next);
1926 fprintf(stderr, "%s: No such file or directory\n", filename);
1930 if ((vdata = GetVnode(ntohl(ep->fid.vnode))) == NULL) {
1931 fprintf(stderr, "%s: No vnode information for %u found\n", filename,
1932 ntohl(ep->fid.vnode));
1940 * Reset a structure containing the current directory scan location
1944 ResetDirCursor(struct DirCursor *cursor, struct vnodeData *vdata)
1946 struct DirHeader *dhp;
1948 cursor->hashbucket = 0;
1950 dhp = (struct DirHeader *)vdata->filedata;
1952 cursor->entry = ntohs(dhp->hashTable[0]);
1956 * Given a cursor and a directory entry, return the next entry in the
1960 static struct DirEntry *
1961 ReadNextDir(struct DirCursor *cursor, struct vnodeData *vdata)
1963 struct DirHeader *dhp;
1964 struct DirEntry *ep;
1966 dhp = (struct DirHeader *)vdata->filedata;
1968 if (cursor->entry) {
1969 ep = (struct DirEntry *)(vdata->filedata + (cursor->entry * 32));
1970 cursor->entry = ntohs(ep->next);
1973 while (++(cursor->hashbucket) < NHASHENT) {
1974 cursor->entry = ntohs(dhp->hashTable[cursor->hashbucket]);
1975 if (cursor->entry) {
1976 ep = (struct DirEntry *)(vdata->filedata +
1977 (cursor->entry * 32));
1978 cursor->entry = ntohs(ep->next);
1988 * Given a string, split it up into components a la Unix argc/argv.
1990 * This code is most stolen from ftp.
1994 MakeArgv(char *string, int *argc, char ***argv)
1996 static char *largv[64];
1999 static char argbuf[CMDBUFSIZE];
2005 while ((*la++ = GetToken(s, &s, ap, &ap)) != NULL)
2010 * Return a pointer to the next token, and update the current string
2015 GetToken(char *string, char **nexttoken, char argbuf[], char *nextargbuf[])
2042 goto OUTTOKEN; /* End of our token */
2046 goto S2; /* Get next character */
2050 goto S3; /* Get quoted string */
2053 *ap++ = *sp++; /* Add a character to our token */
2089 *nextargbuf = ap; /* Update storage pointer */
2090 *nexttoken = sp; /* Update token pointer */
2092 return got_one ? argbuf : NULL;
2096 * Insert vnodes into our hash table.
2099 static struct vnodeData *
2100 InsertVnode(unsigned int vnodeNumber, struct VnodeDiskObject *vnode)
2102 struct VnodeDiskObject *nvnode;
2103 struct vnodeData *vdata;
2104 static int curSmallVnodeIndex = 0;
2105 static int curLargeVnodeIndex = 0;
2106 struct vnodeData ***vnodeIndex;
2109 nvnode = (struct VnodeDiskObject *)malloc(sizeof(struct VnodeDiskObject));
2113 fprintf(stderr, "Unable to allocate space for vnode\n");
2117 memcpy((void *)nvnode, (void *)vnode, sizeof(struct VnodeDiskObject));
2119 if (vnodeNumber & 1) {
2120 vnodeIndex = &LargeVnodeIndex;
2121 curIndex = &curLargeVnodeIndex;
2123 vnodeIndex = &SmallVnodeIndex;
2124 curIndex = &curSmallVnodeIndex;
2127 vdata = (struct vnodeData *)malloc(sizeof(struct vnodeData));
2129 vdata->vnode = nvnode;
2130 vdata->vnodeNumber = vnodeNumber;
2131 vdata->dumpdata = 0;
2132 vdata->filedata = 0;
2133 vdata->datalength = 0;
2135 (*vnodeIndex)[(*curIndex)++] = vdata;
2141 * Routine to retrieve a vnode from the hash table.
2144 static struct vnodeData *
2145 GetVnode(unsigned int vnodeNumber)
2147 struct vnodeData vnode, *vnodep, **tmp;
2149 vnode.vnodeNumber = vnodeNumber;
2152 tmp = (struct vnodeData **)
2153 bsearch((void *)&vnodep,
2154 vnodeNumber & 1 ? LargeVnodeIndex : SmallVnodeIndex,
2155 vnodeNumber & 1 ? numLargeVnodes : numSmallVnodes,
2156 sizeof(struct vnodeData *), CompareVnode);
2158 return tmp ? *tmp : NULL;
2162 * Our comparator function for bsearch
2166 CompareVnode(const void *node1, const void *node2)
2168 struct vnodeData **vnode1 = (struct vnodeData **)node1;
2169 struct vnodeData **vnode2 = (struct vnodeData **)node2;
2171 if ((*vnode1)->vnodeNumber == (*vnode2)->vnodeNumber)
2173 else if ((*vnode1)->vnodeNumber > (*vnode2)->vnodeNumber)
2181 * Dump out the filename corresponding to a particular vnode.
2183 * This routine has the following dependancies:
2185 * - Only will work on UFS filesystems at this point
2186 * - Has to talk to the rsserver.
2187 * - Can only determine UFS algorithm type when run on the same machine
2188 * as the residency (unless you manually specify algorithm information)
2192 DumpVnodeFile(FILE * f, struct VnodeDiskObject *vnode, VolumeDiskData * vol)
2194 static int rscache = 0;
2195 static rsaccessinfoList rsnlist = { 0, 0 };
2196 char MountPoint[MAXPATHLEN + 1];
2197 char FileName[MAXPATHLEN + 1];
2198 unsigned int Size, Level[4];
2199 unsigned int DeviceTag, Algorithm;
2200 FileSystems *FSInfo;
2201 int i, found, FSType, rsindex;
2204 * Maybe we found out something about this residency via the
2205 * command-line; check that first.
2208 rsindex = ffs(VLkp_Residencies(vnode)) - 1;
2211 * We need to get information from the rsserver (so we can
2212 * find out the device tag for a given residency). If we
2213 * haven't cached that, talk to the rsserver to get it.
2214 * If we have info about this already, then don't talk to
2215 * the rsserver (this lets us still do disaster recovery if
2216 * MR-AFS is completely hosed).
2219 if (!rscache && rscmdlineinfo[rsindex].DeviceTag == -1) {
2222 code = ServerInitResidencyConnection();
2226 "ServerInitResidencyConnection failed " "with code %d\n",
2231 code = rs_GetResidencySummary(ServerRequestorId, &rsnlist);
2234 fprintf(stderr, "rs_GetResidencySummary failed " "with code %d\n",
2243 * For a given residency (as specified in the vnode),
2244 * find out it's device tag number, either via the rsserver
2245 * or via the command line.
2248 if (rscmdlineinfo[rsindex].DeviceTag != -1) {
2249 DeviceTag = rscmdlineinfo[rsindex].DeviceTag;
2252 for (i = 0, found = 0; (i < rsnlist.rsaccessinfoList_len) && (!found);
2254 if (rsnlist.rsaccessinfoList_val[i].id.residency ==
2255 VLkp_Residencies(vnode)) {
2257 DeviceTag = rsnlist.rsaccessinfoList_val[i].devicetagnumber;
2265 "Unable to find residency %d in "
2266 "rsserver database, aborting\n", VLkp_Residencies(vnode));
2271 * Okay, now we've got the DeviceTag ... which we can use to
2272 * lookup the on-disk configuration information (which we
2273 * assume is locally stored). We also need the DeviceTag to
2274 * print out which partition we're using (but that comes later).
2276 * We lookup the on-disk configuration information by calling
2277 * Ufs_GetFSInfo() to get the configuration information on the
2278 * filesystems specified by the given DeviceTag.
2280 * Before we call Ufs_GetFSInfo, check the command-line cache;
2281 * if we got something via the command-line, don't go to disk.
2284 if (rscmdlineinfo[rsindex].FSType == -1
2285 && Ufs_GetFSInfo(&FSInfo, DeviceTag)) {
2288 "Ufs_GetFSInfo failed for DeviceTag "
2289 "%d, Residency %d\n", DeviceTag, VLkp_Residencies(vnode));
2294 * The FSInfo structure has the last two things we need: the
2295 * FSType (ufs, slowufs, etc etc), and the usage algorithm (which
2296 * ends up being how many directories are being used on the
2297 * residency filesystem).
2299 * With these last two parameters, use routines stolen from
2300 * ufsname to generate the filename.
2302 * (Actually, I lied - we also need the "Size" parameter, which
2303 * we can also get from FSInfo);
2306 if (rscmdlineinfo[rsindex].FSType != -1) {
2307 FSType = rscmdlineinfo[rsindex].FSType;
2308 Algorithm = rscmdlineinfo[rsindex].Algorithm;
2309 Size = rscmdlineinfo[rsindex].Size;
2311 FSType = FSInfo->FileSystems_u.UfsInterface.FSType;
2312 Algorithm = FSInfo->FileSystems_u.UfsInterface.Algorithm;
2313 if (FSInfo->FileSystems_u.UfsInterface.Directories[1] == 0)
2315 else if (FSInfo->FileSystems_u.UfsInterface.Directories[1] == 16)
2317 else if (FSInfo->FileSystems_u.UfsInterface.Directories[1] == 256)
2321 fprintf(stderr, "Unknown directory size %d, " "aborting\n",
2322 FSInfo->FileSystems_u.UfsInterface.Directories[1]);
2328 * First, generate our mount point from the DeviceTag and
2332 DEVICETAGNUMBERTOMOUNTPOINT(MountPoint, DeviceTag, FSType);
2335 * Then, generate the "level" (directory bitmasks) from the
2336 * file tags, size, and algorithm
2339 UfsTagsToLevel(VLkp_FileTag1(vnode), VLkp_FileTag2(vnode), Algorithm,
2340 Size, Level, VLkp_ParentVnodeId(vnode),
2341 VLkp_ParentUniquifierId(vnode));
2344 * Finally, take the above information and generate the
2345 * corresponding filename (this macro ends up being a
2349 TAGSTONAME(FileName, MountPoint, Level, Directories[Size][1],
2350 vol->parentId, VLkp_ParentVnodeId(vnode),
2351 VLkp_ParentUniquifierId(vnode), Algorithm);
2353 fprintf(f, "%s\n", FileName);
2360 * Read a 16 bit integer in network order
2364 ReadInt16(FILE * f, unsigned short *s)
2368 if (fread((void *)&in, sizeof(in), 1, f) != 1) {
2370 fprintf(stderr, "ReadInt16 failed!\n");
2381 * Read a 32 bit integer in network order
2385 ReadInt32(FILE * f, unsigned int *i)
2389 if (fread((void *)&in, sizeof(in), 1, f) != 1) {
2391 fprintf(stderr, "ReadInt32 failed!\n");
2395 *i = ntohl((unsigned long)in);
2401 * Read a string from a dump file
2405 ReadString(FILE * f, char *string, int maxlen)
2410 if ((*string++ = getc(f)) == 0)
2415 * I'm not sure what the _hell_ this is supposed to do ...
2416 * but it was in the original dump code
2420 while ((c = getc(f)) && c != EOF);
2428 ReadByteString(FILE * f, void *s, int size)
2430 unsigned char *c = (unsigned char *)s;
2439 * The directory hashing algorithm used by AFS
2443 DirHash(char *string)
2445 /* Hash a string to a number between 0 and NHASHENT. */
2450 while ((tc = (*string++)) != '\0') {
2454 tval = hval & (NHASHENT - 1);
2455 #ifdef AFS_CRAY_ENV /* actually, any > 32 bit environment */
2458 else if (hval & 0x80000000)
2459 tval = NHASHENT - tval;
2460 #else /* AFS_CRAY_ENV */
2464 tval = NHASHENT - tval;
2465 #endif /* AFS_CRAY_ENV */
2471 * Sigh, we need this for the AFS libraries
2475 LogErrors(int level, char *a, char *b, char *c, char *d, char *e, char *f,
2476 char *g, char *h, char *i, char *j, char *k)
2479 fprintf(stderr, a, b, c, d, e, f, g, h, i, j, k);
2485 * These are routines taken from AFS libraries and programs. Most of
2486 * them are from ufsname.c, but a few are from the dir library (the dir
2487 * library has a bunch of hidden dependancies, so it's not suitable to
2488 * include it outright).
2491 UfsEntropiesToTags(HighEntropy, LowEntropy, Algorithm, FileTag1, FileTag2)
2492 uint32_t HighEntropy;
2493 uint32_t LowEntropy;
2500 if ((Algorithm > UFS_ALGORITHMS) || (Algorithm <= 0))
2504 for (i = 0; i < 32; ++i) {
2505 if (UfsEntropy[Algorithm - 1][i] < 32)
2507 ((HighEntropy & (1 << i)) ==
2508 0) ? 0 : 1 << UfsEntropy[Algorithm - 1][i];
2511 ((HighEntropy & (1 << i)) ==
2512 0) ? 0 : 1 << (UfsEntropy[Algorithm - 1][i] - 32);
2514 for (i = 32; i < 64; ++i) {
2515 if (UfsEntropy[Algorithm - 1][i] < 32)
2517 ((LowEntropy & (1 << (i - 32))) ==
2518 0) ? 0 : 1 << UfsEntropy[Algorithm - 1][i];
2521 ((LowEntropy & (1 << (i - 32))) ==
2522 0) ? 0 : 1 << (UfsEntropy[Algorithm - 1][i] - 32);
2528 UfsTagsToHighEntropy(FileTag1, FileTag2, Algorithm)
2537 for (i = 0; i < 32; ++i) {
2538 if (UfsEntropy[Algorithm - 1][i] < 32)
2539 Value |= ((FileTag1 & (1 << UfsEntropy[Algorithm - 1][i]))
2543 ((FileTag2 & (1 << (UfsEntropy[Algorithm - 1][i] - 32))) ==
2550 UfsTagsToLowEntropy(FileTag1, FileTag2, Algorithm)
2559 for (i = 32; i < 64; ++i) {
2560 if (UfsEntropy[Algorithm - 1][i] < 32)
2561 Value |= ((FileTag1 & (1 << UfsEntropy[Algorithm - 1][i]))
2562 == 0) ? 0 : 1 << (i - 32);
2565 ((FileTag2 & (1 << (UfsEntropy[Algorithm - 1][i] - 32))) ==
2566 0) ? 0 : 1 << (i - 32);
2571 UfsTagsToLevel(FileTag1, FileTag2, Algorithm, Size, Sections, vnode,
2577 uint32_t Sections[4];
2579 uint32_t Uniquifier;
2581 uint32_t HighEntropy;
2582 uint32_t LowEntropy;
2584 switch (Algorithm) {
2586 LowEntropy = UfsTagsToLowEntropy(FileTag1, FileTag2, Algorithm);
2587 HighEntropy = UfsTagsToHighEntropy(FileTag1, FileTag2, Algorithm);
2588 Sections[0] = HighEntropy % Directories[Size][0];
2589 HighEntropy /= Directories[Size][0];
2590 if (Directories[Size][1]) {
2591 Sections[1] = HighEntropy % Directories[Size][1];
2592 HighEntropy /= Directories[Size][1];
2593 Sections[2] = HighEntropy;
2594 Sections[3] = LowEntropy;
2596 Sections[1] = HighEntropy;
2597 Sections[2] = LowEntropy;
2601 Sections[0] = FileTag1 & 0xff;
2602 if (Directories[Size][1]) {
2603 Sections[1] = Uniquifier & 0xff;
2604 if (Directories[Size][1] == 16)
2606 Sections[2] = FileTag1;
2607 Sections[3] = FileTag2;
2609 Sections[1] = FileTag1;
2610 Sections[2] = FileTag2;
2614 Sections[0] = FileTag1 & 0xff;
2615 if (Directories[Size][1]) {
2616 Sections[1] = (vnode >> 1) & 0xff;
2617 if (Directories[Size][1] == 16)
2619 Sections[2] = FileTag1;
2620 Sections[3] = FileTag2;
2622 Sections[1] = FileTag1;
2623 Sections[2] = FileTag2;
2627 fprintf(stderr, "UfsTagsToLevel: bad algorithm %lu!\n", Algorithm);
2633 #include <afs/afscbdummies.h>
2634 #endif /* RESIDENCY */