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 LargeVnodeIndex = (struct vnodeData **)
1153 malloc(numDirVnodes * sizeof(struct vnodeData));
1154 SmallVnodeIndex = (struct vnodeData **)
1155 malloc(numFileVnodes * sizeof(struct vnodeData));
1157 if (LargeVnodeIndex == NULL || SmallVnodeIndex == NULL) {
1160 "Unable to allocate space " "for vnode tables\n");
1166 fprintf(stderr, "%s vnode scan completed\n",
1167 sizescan ? "Primary" : "Secondary");
1173 * Perform an interactive restore
1175 * Parsing the directory information is a pain, but other than that
1176 * we just use the other tools we already have in here.
1178 #define CMDBUFSIZE (AFSPATHMAX * 2)
1180 InteractiveRestore(FILE * f, VolumeDiskData * vol)
1182 struct vnodeData *vdatacwd; /* Vnode data for our current dir */
1183 char cmdbuf[CMDBUFSIZE];
1188 * Let's see if we can at least get the data for our root directory.
1189 * If we can't, there's no way we can do an interactive restore.
1192 if ((vdatacwd = GetVnode(1)) == NULL) {
1193 fprintf(stderr, "No entry for our root vnode! Aborting\n");
1197 if (!vdatacwd->filedata) {
1199 "There is no directory data for the root "
1200 "vnode (1.1). An interactive\nrestore is not "
1206 * If you're doing a selective dump correctly, then you should get all
1207 * directory vnode data. But just in case you didn't, let the user
1208 * know there may be a problem.
1213 "WARNING: %d directory vnodes had no file "
1214 "data. An interactive restore\nmay not be possible\n",
1218 while (fgets(cmdbuf, CMDBUFSIZE, stdin)) {
1220 cmdbuf[strlen(cmdbuf) - 1] = '\0';
1222 if (strlen(cmdbuf) == 0) {
1227 MakeArgv(cmdbuf, &argc, &argv);
1229 if (strcmp(argv[0], "ls") == 0) {
1230 DirectoryList(argc, argv, vdatacwd, vol);
1231 } else if (strcmp(argv[0], "cd") == 0) {
1232 struct vnodeData *newvdata;
1234 newvdata = ChangeDirectory(argc, argv, vdatacwd);
1237 vdatacwd = newvdata;
1238 } else if (strcmp(argv[0], "file") == 0) {
1239 DumpAllFiles(argc, argv, vdatacwd, vol);
1240 } else if (strcmp(argv[0], "cp") == 0) {
1241 CopyFile(argc, argv, vdatacwd, f);
1242 } else if (strcmp(argv[0], "vcp") == 0) {
1243 CopyVnode(argc, argv, f);
1244 } else if (strcmp(argv[0], "quit") == 0
1245 || strcmp(argv[0], "exit") == 0)
1247 else if (strcmp(argv[0], "?") == 0 || strcmp(argv[0], "help") == 0) {
1248 printf("Valid commands are:\n");
1249 printf("\tls\t\tList current directory\n");
1250 printf("\tcd\t\tChange current directory\n");
1251 printf("\tcp\t\tCopy file from dump\n");
1252 printf("\tvcp\t\tCopy file from dump (via vnode)\n");
1254 printf("\tfile\t\tList residency filenames\n");
1255 #endif /* RESIDENCY */
1256 printf("\tquit | exit\tExit program\n");
1257 printf("\thelp | ?\tBrief help\n");
1260 "Unknown command, \"%s\", enter "
1261 "\"help\" for a list of commands.\n", argv[0]);
1270 * Do a listing of all files in a directory. Sigh, I wish this wasn't
1273 * With the reorganizing, this is just a front-end to DirListInternal()
1277 DirectoryList(int argc, char **argv, struct vnodeData *vdata,
1278 VolumeDiskData * vol)
1280 int errflg = 0, lflag = 0, iflag = 0, Fflag = 0, sflag = 0, Rflag = 0;
1285 while ((c = getopt(argc, argv, "liFRs")) != EOF)
1307 fprintf(stderr, "Usage: %s [-liFs] filename [filename ...]\n",
1312 DirListInternal(vdata, &(argv[optind]), argc - optind, lflag, iflag,
1313 Fflag, Rflag, 1, vol, NULL);
1319 * Function that does the REAL work in terms of directory listing
1323 DirListInternal(struct vnodeData *vdata, char *pathnames[], int numpathnames,
1324 int lflag, int iflag, int Fflag, int Rflag, int verbose,
1325 VolumeDiskData * vol, char *path)
1327 struct DirEntry *ep, **eplist = NULL, **eprecurse = NULL;
1328 struct DirCursor cursor;
1329 struct vnodeData *lvdata;
1331 int i, j, numentries = 0, longestname = 0, numcols, col, numrows;
1334 if (!vdata->filedata) {
1335 fprintf(stderr, "There is no vnode data for this " "directory!\n");
1339 ResetDirCursor(&cursor, vdata);
1342 * Scan through the whole directory
1345 while ((ep = ReadNextDir(&cursor, vdata)) != NULL) {
1348 * If we didn't get any filenames on the command line,
1352 if (numpathnames == 0) {
1354 realloc(eplist, sizeof(struct DirEntry *) * ++numentries);
1355 eplist[numentries - 1] = ep;
1356 if (strlen(ep->name) > longestname)
1357 longestname = strlen(ep->name);
1359 if ((lvdata = GetVnode(ntohl(ep->fid.vnode)))
1360 && lvdata->vnode->type == vDirectory
1361 && !(strcmp(ep->name, ".") == 0
1362 || strcmp(ep->name, "..") == 0)) {
1365 sizeof(struct DirEntry *) * ++numrecurse);
1366 eprecurse[numrecurse - 1] = ep;
1371 * Do glob matching via fnmatch()
1374 for (i = 0; i < numpathnames; i++)
1375 if (fnmatch(pathnames[i], ep->name, FNM_PATHNAME) == 0) {
1378 sizeof(struct DirEntry *) * ++numentries);
1379 eplist[numentries - 1] = ep;
1380 if (strlen(ep->name) > longestname)
1381 longestname = strlen(ep->name);
1383 if ((lvdata = GetVnode(ntohl(ep->fid.vnode)))
1384 && lvdata->vnode->type == vDirectory
1385 && !(strcmp(ep->name, ".") == 0
1386 || strcmp(ep->name, "..") == 0)) {
1389 sizeof(struct DirEntry *) *
1391 eprecurse[numrecurse - 1] = ep;
1398 qsort((void *)eplist, numentries, sizeof(struct DirEntry *),
1401 if (Rflag && eprecurse)
1402 qsort((void *)eprecurse, numrecurse, sizeof(struct DirEntry *),
1405 * We don't have to do column printing if we have the -l or the -i
1406 * options. Sigh, column printing is WAY TOO FUCKING COMPLICATED!
1409 if (!lflag && !iflag) {
1417 numcols = termsize / longestname ? termsize / longestname : 1;
1418 numrows = numentries / numcols + (numentries % numcols ? 1 : 0);
1420 for (i = 0; i < numrows; i++) {
1422 while (col < numcols && (i + col * numrows) < numentries) {
1423 ep = eplist[i + col++ * numrows];
1425 if (!(lvdata = GetVnode(ntohl(ep->fid.vnode))))
1427 else if (lvdata->vnode->type == vDirectory)
1429 else if (lvdata->vnode->type == vSymlink)
1431 else if ((lvdata->vnode->modeBits & 0111) != 0)
1435 printf("%s%-*c", ep->name, (int)(longestname -
1436 strlen(ep->name)), c);
1438 printf("%-*s", longestname, ep->name);
1444 for (i = 0; i < numentries; i++)
1445 if (!(lvdata = GetVnode(ntohl(eplist[i]->fid.vnode))))
1446 printf("%" AFS_VOLID_FMT ".0.0\t%s\n",
1447 vol->parentId ? afs_printable_VolumeId_lu(vol->parentId)
1448 : afs_printable_VolumeId_lu(vol->id),
1451 printf("%" AFS_VOLID_FMT ".%d.%d\t%s/%s\n",
1452 afs_printable_VolumeId_lu(vol->id),
1453 ntohl(eplist[i]->fid.vnode),
1454 ntohl(eplist[i]->fid.vunique), path, eplist[i]->name);
1456 printf("%" AFS_VOLID_FMT ".%d.%d\t%s\n",
1457 afs_printable_VolumeId_lu(vol->id),
1458 ntohl(eplist[i]->fid.vnode),
1459 ntohl(eplist[i]->fid.vunique), eplist[i]->name);
1461 for (i = 0; i < numentries; i++)
1462 if (!(lvdata = GetVnode(ntohl(eplist[i]->fid.vnode))))
1463 printf("---------- 0 0 " "0 0 %s\n",
1466 switch (lvdata->vnode->type) {
1477 for (j = 8; j >= 0; j--) {
1478 if (lvdata->vnode->modeBits & (1 << j))
1492 printf(" %-3d %-8d %-8d %10d %s\n", lvdata->vnode->linkCount,
1493 lvdata->vnode->owner, lvdata->vnode->group,
1494 lvdata->vnode->length, eplist[i]->name);
1500 if (Rflag && eprecurse) {
1503 for (i = 0; i < numrecurse; i++) {
1505 printf("\n%s:\n", eprecurse[i]->name);
1507 lpath = malloc(strlen(path) + strlen(eprecurse[i]->name) + 2);
1509 sprintf(lpath, "%s/%s", path, eprecurse[i]->name);
1511 DirListInternal(GetVnode(ntohl(eprecurse[i]->fid.vnode)), NULL, 0,
1512 lflag, iflag, Fflag, Rflag, verbose, vol, lpath);
1528 * Directory name comparison function, used by qsort
1532 CompareDirEntry(const void *e1, const void *e2)
1534 struct DirEntry **ep1 = (struct DirEntry **)e1;
1535 struct DirEntry **ep2 = (struct DirEntry **)e2;
1537 return strcmp((*ep1)->name, (*ep2)->name);
1541 * Change a directory. Return a pointer to our new vdata structure for
1545 static struct vnodeData *
1546 ChangeDirectory(int argc, char **argv, struct vnodeData *vdatacwd)
1548 struct vnodeData *newvdatacwd;
1551 fprintf(stderr, "Usage: %s directory\n", argv[0]);
1555 if ((newvdatacwd = FindFile(vdatacwd, argv[1])) == NULL)
1558 if (newvdatacwd->vnode->type != vDirectory) {
1559 fprintf(stderr, "%s: Not a directory\n", argv[1]);
1563 if (newvdatacwd->filedata == NULL) {
1564 fprintf(stderr, "%s: No directory data found.\n", argv[1]);
1572 * Copy a file from out of the dump file
1575 #define COPYBUFSIZE 8192
1578 CopyFile(int argc, char **argv, struct vnodeData *vdatacwd, FILE * f)
1580 struct vnodeData *vdata;
1584 char buffer[COPYBUFSIZE];
1587 fprintf(stderr, "Usage: %s dumpfile destfile\n", argv[0]);
1591 if ((vdata = FindFile(vdatacwd, argv[1])) == NULL)
1594 if (vdata->dumpdata == 0) {
1595 fprintf(stderr, "File %s has no data in dump file\n", argv[1]);
1599 if ((out = fopen(argv[2], "wb")) == NULL) {
1600 fprintf(stderr, "Open of %s failed: %s\n", argv[2], strerror(errno));
1604 if (fseeko64(f, vdata->dumpdata, SEEK_SET)) {
1605 fprintf(stderr, "Seek failed: %s\n", strerror(errno));
1610 while (cur < vdata->datalength) {
1614 vdata->datalength ? COPYBUFSIZE : vdata->datalength - cur;
1616 ret = fread(buffer, sizeof(char), bytes, f);
1619 fprintf(stderr, "Short read (expected %d, " "got %d)\n",
1622 fprintf(stderr, "Error during read: %s\n", strerror(errno));
1627 ret = fwrite(buffer, sizeof(char), bytes, out);
1630 fprintf(stderr, "Short write (expected %d, " "got %d)\n",
1633 fprintf(stderr, "Error during write: %s\n", strerror(errno));
1645 * Copy a file from out of the dump file, by using the vnode
1649 CopyVnode(int argc, char *argv[], FILE * f)
1651 struct vnodeData *vdata;
1655 char buffer[COPYBUFSIZE];
1656 unsigned int vnode, uniquifier = 0;
1659 fprintf(stderr, "Usage: %s vnode[.uniqifier] destfile\n", argv[0]);
1663 ret = sscanf(argv[1], "%d.%d", &vnode, &uniquifier);
1666 fprintf(stderr, "Invalid file identifier: %s\n", argv[1]);
1670 if (!(vdata = GetVnode(vnode))) {
1671 fprintf(stderr, "Vnode %d not in dump file\n", vnode);
1675 if (ret == 2 && vdata->vnode->uniquifier != uniquifier) {
1677 "Specified uniquifier %d did not match "
1678 "uniquifier %d found in dump file!\n", uniquifier,
1679 vdata->vnode->uniquifier);
1683 if (vdata->dumpdata == 0) {
1684 fprintf(stderr, "File %s has no data in dump file\n", argv[1]);
1688 if ((out = fopen(argv[2], "wb")) == NULL) {
1689 fprintf(stderr, "Open of %s failed: %s\n", argv[2], strerror(errno));
1693 if (fseeko64(f, vdata->dumpdata, SEEK_SET)) {
1694 fprintf(stderr, "Seek failed: %s\n", strerror(errno));
1699 while (cur < vdata->datalength) {
1703 vdata->datalength ? COPYBUFSIZE : vdata->datalength - cur;
1705 ret = fread(buffer, sizeof(char), bytes, f);
1708 fprintf(stderr, "Short read (expected %d, " "got %d)\n",
1711 fprintf(stderr, "Error during read: %s\n", strerror(errno));
1716 ret = fwrite(buffer, sizeof(char), bytes, out);
1719 fprintf(stderr, "Short write (expected %d, " "got %d)\n",
1722 fprintf(stderr, "Error during write: %s\n", strerror(errno));
1734 * Dump all residency filenames associated with a file, or all files
1735 * within a directory.
1739 DumpAllFiles(int argc, char **argv, struct vnodeData *vdatacwd,
1740 VolumeDiskData * vol)
1743 struct vnodeData *vdata, *nvdata;
1744 struct DirCursor cursor;
1745 struct DirEntry *ep;
1748 int dflag = 0, fflag = 0, errflg = 0;
1752 while ((c = getopt(argc, argv, "df:")) != EOF)
1758 if ((f = fopen(optarg, "a")) == NULL) {
1759 fprintf(stderr, "Cannot open \"%s\": %s\n", optarg,
1771 if (errflg || argc == optind) {
1772 fprintf(stderr, "Usage: %s [-d] [-f filename] file " "[file ...]\n",
1779 for (i = optind; i < argc; i++) {
1781 if ((vdata = FindFile(vdatacwd, argv[i])) == NULL)
1784 if (vdata->vnode->type == vDirectory && !dflag) {
1786 ResetDirCursor(&cursor, vdata);
1788 while ((ep = ReadNextDir(&cursor, vdata)) != NULL) {
1790 if (!(nvdata = GetVnode(ntohl(ep->fid.vnode)))) {
1792 "Cannot find vnode " "entry for %s (%d)\n",
1793 ep->name, ntohl(ep->fid.vnode));
1799 printf("Residency locations for %s:\n", ep->name);
1801 if (nvdata->dumpdata)
1802 printf("Local disk (in dump " "file)\n");
1805 DumpAllResidencies(f, nvdata, vol);
1811 printf("Residency locations for %s:\n", argv[i]);
1813 if (vdata->dumpdata)
1814 printf("Local disk (in dump file)\n");
1817 DumpAllResidencies(f, vdata, vol);
1823 #else /* RESIDENCY */
1825 "The \"file\" command is not available in the non-"
1826 "MRAFS version of dumptool.\n");
1827 #endif /* RESIDENCY */
1832 * Take a vnode, traverse the vnode chain, and dump out all files on
1833 * all residencies corresponding to that parent vnode.
1838 DumpAllResidencies(FILE * f, struct vnodeData *vdata,
1839 struct VolumeDiskData *vol)
1841 unsigned int nextVnodeNum;
1843 while (nextVnodeNum = vdata->vnode->NextVnodeId) {
1844 if ((vdata = GetVnode(nextVnodeNum)) == NULL) {
1846 "We had a pointer to %lu in it's "
1847 "vnode chain, but there\nisn't a record of "
1848 "it! The dump might be corrupt.\n", nextVnodeNum);
1852 if (vdata->vnode->type == vFidLookup)
1853 DumpVnodeFile(f, vdata->vnode, vol);
1862 * Given a directory vnode and a filename, return the vnode corresponding
1863 * to the file in that directory.
1865 * We now handle pathnames with directories in them.
1868 static struct vnodeData *
1869 FindFile(struct vnodeData *vdatacwd, char *filename)
1871 struct DirHeader *dhp;
1872 struct DirEntry *ep;
1874 struct vnodeData *vdata;
1875 char *c, newstr[MAXPATHLEN];
1877 if (!vdatacwd->filedata) {
1878 fprintf(stderr, "There is no vnode data for this " "directory!\n");
1883 * If we have a "/" in here, look up the vnode data for the
1884 * directory (everything before the "/") and use that as our
1885 * current directory. We automagically handle multiple directories
1886 * by using FindFile recursively.
1889 if ((c = strrchr(filename, '/')) != NULL) {
1891 strncpy(newstr, filename, c - filename);
1892 newstr[c - filename] = '\0';
1894 if ((vdatacwd = FindFile(vdatacwd, newstr)) == NULL)
1897 if (vdatacwd->vnode->type != vDirectory) {
1898 fprintf(stderr, "%s: Not a directory\n", newstr);
1905 dhp = (struct DirHeader *)vdatacwd->filedata;
1907 i = DirHash(filename);
1909 num = ntohs(dhp->hashTable[i]);
1912 ep = (struct DirEntry *)(vdatacwd->filedata + (num * 32));
1913 if (strcmp(ep->name, filename) == 0)
1915 num = ntohs(ep->next);
1919 fprintf(stderr, "%s: No such file or directory\n", filename);
1923 if ((vdata = GetVnode(ntohl(ep->fid.vnode))) == NULL) {
1924 fprintf(stderr, "%s: No vnode information for %u found\n", filename,
1925 ntohl(ep->fid.vnode));
1933 * Reset a structure containing the current directory scan location
1937 ResetDirCursor(struct DirCursor *cursor, struct vnodeData *vdata)
1939 struct DirHeader *dhp;
1941 cursor->hashbucket = 0;
1943 dhp = (struct DirHeader *)vdata->filedata;
1945 cursor->entry = ntohs(dhp->hashTable[0]);
1949 * Given a cursor and a directory entry, return the next entry in the
1953 static struct DirEntry *
1954 ReadNextDir(struct DirCursor *cursor, struct vnodeData *vdata)
1956 struct DirHeader *dhp;
1957 struct DirEntry *ep;
1959 dhp = (struct DirHeader *)vdata->filedata;
1961 if (cursor->entry) {
1962 ep = (struct DirEntry *)(vdata->filedata + (cursor->entry * 32));
1963 cursor->entry = ntohs(ep->next);
1966 while (++(cursor->hashbucket) < NHASHENT) {
1967 cursor->entry = ntohs(dhp->hashTable[cursor->hashbucket]);
1968 if (cursor->entry) {
1969 ep = (struct DirEntry *)(vdata->filedata +
1970 (cursor->entry * 32));
1971 cursor->entry = ntohs(ep->next);
1981 * Given a string, split it up into components a la Unix argc/argv.
1983 * This code is most stolen from ftp.
1987 MakeArgv(char *string, int *argc, char ***argv)
1989 static char *largv[64];
1992 static char argbuf[CMDBUFSIZE];
1998 while ((*la++ = GetToken(s, &s, ap, &ap)) != NULL)
2003 * Return a pointer to the next token, and update the current string
2008 GetToken(char *string, char **nexttoken, char argbuf[], char *nextargbuf[])
2035 goto OUTTOKEN; /* End of our token */
2039 goto S2; /* Get next character */
2043 goto S3; /* Get quoted string */
2046 *ap++ = *sp++; /* Add a character to our token */
2082 *nextargbuf = ap; /* Update storage pointer */
2083 *nexttoken = sp; /* Update token pointer */
2085 return got_one ? argbuf : NULL;
2089 * Insert vnodes into our hash table.
2092 static struct vnodeData *
2093 InsertVnode(unsigned int vnodeNumber, struct VnodeDiskObject *vnode)
2095 struct VnodeDiskObject *nvnode;
2096 struct vnodeData *vdata;
2097 static int curSmallVnodeIndex = 0;
2098 static int curLargeVnodeIndex = 0;
2099 struct vnodeData ***vnodeIndex;
2102 nvnode = (struct VnodeDiskObject *)malloc(sizeof(struct VnodeDiskObject));
2106 fprintf(stderr, "Unable to allocate space for vnode\n");
2110 memcpy((void *)nvnode, (void *)vnode, sizeof(struct VnodeDiskObject));
2112 if (vnodeNumber & 1) {
2113 vnodeIndex = &LargeVnodeIndex;
2114 curIndex = &curLargeVnodeIndex;
2116 vnodeIndex = &SmallVnodeIndex;
2117 curIndex = &curSmallVnodeIndex;
2120 vdata = (struct vnodeData *)malloc(sizeof(struct vnodeData));
2122 vdata->vnode = nvnode;
2123 vdata->vnodeNumber = vnodeNumber;
2124 vdata->dumpdata = 0;
2125 vdata->filedata = 0;
2126 vdata->datalength = 0;
2128 (*vnodeIndex)[(*curIndex)++] = vdata;
2134 * Routine to retrieve a vnode from the hash table.
2137 static struct vnodeData *
2138 GetVnode(unsigned int vnodeNumber)
2140 struct vnodeData vnode, *vnodep, **tmp;
2142 vnode.vnodeNumber = vnodeNumber;
2145 tmp = (struct vnodeData **)
2146 bsearch((void *)&vnodep,
2147 vnodeNumber & 1 ? LargeVnodeIndex : SmallVnodeIndex,
2148 vnodeNumber & 1 ? numLargeVnodes : numSmallVnodes,
2149 sizeof(struct vnodeData *), CompareVnode);
2151 return tmp ? *tmp : NULL;
2155 * Our comparator function for bsearch
2159 CompareVnode(const void *node1, const void *node2)
2161 struct vnodeData **vnode1 = (struct vnodeData **)node1;
2162 struct vnodeData **vnode2 = (struct vnodeData **)node2;
2164 if ((*vnode1)->vnodeNumber == (*vnode2)->vnodeNumber)
2166 else if ((*vnode1)->vnodeNumber > (*vnode2)->vnodeNumber)
2174 * Dump out the filename corresponding to a particular vnode.
2176 * This routine has the following dependancies:
2178 * - Only will work on UFS filesystems at this point
2179 * - Has to talk to the rsserver.
2180 * - Can only determine UFS algorithm type when run on the same machine
2181 * as the residency (unless you manually specify algorithm information)
2185 DumpVnodeFile(FILE * f, struct VnodeDiskObject *vnode, VolumeDiskData * vol)
2187 static int rscache = 0;
2188 static rsaccessinfoList rsnlist = { 0, 0 };
2189 char MountPoint[MAXPATHLEN + 1];
2190 char FileName[MAXPATHLEN + 1];
2191 unsigned int Size, Level[4];
2192 unsigned int DeviceTag, Algorithm;
2193 FileSystems *FSInfo;
2194 int i, found, FSType, rsindex;
2197 * Maybe we found out something about this residency via the
2198 * command-line; check that first.
2201 rsindex = ffs(VLkp_Residencies(vnode)) - 1;
2204 * We need to get information from the rsserver (so we can
2205 * find out the device tag for a given residency). If we
2206 * haven't cached that, talk to the rsserver to get it.
2207 * If we have info about this already, then don't talk to
2208 * the rsserver (this lets us still do disaster recovery if
2209 * MR-AFS is completely hosed).
2212 if (!rscache && rscmdlineinfo[rsindex].DeviceTag == -1) {
2215 code = ServerInitResidencyConnection();
2219 "ServerInitResidencyConnection failed " "with code %d\n",
2224 code = rs_GetResidencySummary(ServerRequestorId, &rsnlist);
2227 fprintf(stderr, "rs_GetResidencySummary failed " "with code %d\n",
2236 * For a given residency (as specified in the vnode),
2237 * find out it's device tag number, either via the rsserver
2238 * or via the command line.
2241 if (rscmdlineinfo[rsindex].DeviceTag != -1) {
2242 DeviceTag = rscmdlineinfo[rsindex].DeviceTag;
2245 for (i = 0, found = 0; (i < rsnlist.rsaccessinfoList_len) && (!found);
2247 if (rsnlist.rsaccessinfoList_val[i].id.residency ==
2248 VLkp_Residencies(vnode)) {
2250 DeviceTag = rsnlist.rsaccessinfoList_val[i].devicetagnumber;
2258 "Unable to find residency %d in "
2259 "rsserver database, aborting\n", VLkp_Residencies(vnode));
2264 * Okay, now we've got the DeviceTag ... which we can use to
2265 * lookup the on-disk configuration information (which we
2266 * assume is locally stored). We also need the DeviceTag to
2267 * print out which partition we're using (but that comes later).
2269 * We lookup the on-disk configuration information by calling
2270 * Ufs_GetFSInfo() to get the configuration information on the
2271 * filesystems specified by the given DeviceTag.
2273 * Before we call Ufs_GetFSInfo, check the command-line cache;
2274 * if we got something via the command-line, don't go to disk.
2277 if (rscmdlineinfo[rsindex].FSType == -1
2278 && Ufs_GetFSInfo(&FSInfo, DeviceTag)) {
2281 "Ufs_GetFSInfo failed for DeviceTag "
2282 "%d, Residency %d\n", DeviceTag, VLkp_Residencies(vnode));
2287 * The FSInfo structure has the last two things we need: the
2288 * FSType (ufs, slowufs, etc etc), and the usage algorithm (which
2289 * ends up being how many directories are being used on the
2290 * residency filesystem).
2292 * With these last two parameters, use routines stolen from
2293 * ufsname to generate the filename.
2295 * (Actually, I lied - we also need the "Size" parameter, which
2296 * we can also get from FSInfo);
2299 if (rscmdlineinfo[rsindex].FSType != -1) {
2300 FSType = rscmdlineinfo[rsindex].FSType;
2301 Algorithm = rscmdlineinfo[rsindex].Algorithm;
2302 Size = rscmdlineinfo[rsindex].Size;
2304 FSType = FSInfo->FileSystems_u.UfsInterface.FSType;
2305 Algorithm = FSInfo->FileSystems_u.UfsInterface.Algorithm;
2306 if (FSInfo->FileSystems_u.UfsInterface.Directories[1] == 0)
2308 else if (FSInfo->FileSystems_u.UfsInterface.Directories[1] == 16)
2310 else if (FSInfo->FileSystems_u.UfsInterface.Directories[1] == 256)
2314 fprintf(stderr, "Unknown directory size %d, " "aborting\n",
2315 FSInfo->FileSystems_u.UfsInterface.Directories[1]);
2321 * First, generate our mount point from the DeviceTag and
2325 DEVICETAGNUMBERTOMOUNTPOINT(MountPoint, DeviceTag, FSType);
2328 * Then, generate the "level" (directory bitmasks) from the
2329 * file tags, size, and algorithm
2332 UfsTagsToLevel(VLkp_FileTag1(vnode), VLkp_FileTag2(vnode), Algorithm,
2333 Size, Level, VLkp_ParentVnodeId(vnode),
2334 VLkp_ParentUniquifierId(vnode));
2337 * Finally, take the above information and generate the
2338 * corresponding filename (this macro ends up being a
2342 TAGSTONAME(FileName, MountPoint, Level, Directories[Size][1],
2343 vol->parentId, VLkp_ParentVnodeId(vnode),
2344 VLkp_ParentUniquifierId(vnode), Algorithm);
2346 fprintf(f, "%s\n", FileName);
2353 * Read a 16 bit integer in network order
2357 ReadInt16(FILE * f, unsigned short *s)
2361 if (fread((void *)&in, sizeof(in), 1, f) != 1) {
2363 fprintf(stderr, "ReadInt16 failed!\n");
2374 * Read a 32 bit integer in network order
2378 ReadInt32(FILE * f, unsigned int *i)
2382 if (fread((void *)&in, sizeof(in), 1, f) != 1) {
2384 fprintf(stderr, "ReadInt32 failed!\n");
2388 *i = ntohl((unsigned long)in);
2394 * Read a string from a dump file
2398 ReadString(FILE * f, char *string, int maxlen)
2403 if ((*string++ = getc(f)) == 0)
2408 * I'm not sure what the _hell_ this is supposed to do ...
2409 * but it was in the original dump code
2413 while ((c = getc(f)) && c != EOF);
2421 ReadByteString(FILE * f, void *s, int size)
2423 unsigned char *c = (unsigned char *)s;
2432 * The directory hashing algorithm used by AFS
2436 DirHash(char *string)
2438 /* Hash a string to a number between 0 and NHASHENT. */
2443 while ((tc = (*string++)) != '\0') {
2447 tval = hval & (NHASHENT - 1);
2448 #ifdef AFS_CRAY_ENV /* actually, any > 32 bit environment */
2451 else if (hval & 0x80000000)
2452 tval = NHASHENT - tval;
2453 #else /* AFS_CRAY_ENV */
2457 tval = NHASHENT - tval;
2458 #endif /* AFS_CRAY_ENV */
2464 * Sigh, we need this for the AFS libraries
2468 LogErrors(int level, char *a, char *b, char *c, char *d, char *e, char *f,
2469 char *g, char *h, char *i, char *j, char *k)
2472 fprintf(stderr, a, b, c, d, e, f, g, h, i, j, k);
2478 * These are routines taken from AFS libraries and programs. Most of
2479 * them are from ufsname.c, but a few are from the dir library (the dir
2480 * library has a bunch of hidden dependancies, so it's not suitable to
2481 * include it outright).
2484 UfsEntropiesToTags(HighEntropy, LowEntropy, Algorithm, FileTag1, FileTag2)
2485 uint32_t HighEntropy;
2486 uint32_t LowEntropy;
2493 if ((Algorithm > UFS_ALGORITHMS) || (Algorithm <= 0))
2497 for (i = 0; i < 32; ++i) {
2498 if (UfsEntropy[Algorithm - 1][i] < 32)
2500 ((HighEntropy & (1 << i)) ==
2501 0) ? 0 : 1 << UfsEntropy[Algorithm - 1][i];
2504 ((HighEntropy & (1 << i)) ==
2505 0) ? 0 : 1 << (UfsEntropy[Algorithm - 1][i] - 32);
2507 for (i = 32; i < 64; ++i) {
2508 if (UfsEntropy[Algorithm - 1][i] < 32)
2510 ((LowEntropy & (1 << (i - 32))) ==
2511 0) ? 0 : 1 << UfsEntropy[Algorithm - 1][i];
2514 ((LowEntropy & (1 << (i - 32))) ==
2515 0) ? 0 : 1 << (UfsEntropy[Algorithm - 1][i] - 32);
2521 UfsTagsToHighEntropy(FileTag1, FileTag2, Algorithm)
2530 for (i = 0; i < 32; ++i) {
2531 if (UfsEntropy[Algorithm - 1][i] < 32)
2532 Value |= ((FileTag1 & (1 << UfsEntropy[Algorithm - 1][i]))
2536 ((FileTag2 & (1 << (UfsEntropy[Algorithm - 1][i] - 32))) ==
2543 UfsTagsToLowEntropy(FileTag1, FileTag2, Algorithm)
2552 for (i = 32; i < 64; ++i) {
2553 if (UfsEntropy[Algorithm - 1][i] < 32)
2554 Value |= ((FileTag1 & (1 << UfsEntropy[Algorithm - 1][i]))
2555 == 0) ? 0 : 1 << (i - 32);
2558 ((FileTag2 & (1 << (UfsEntropy[Algorithm - 1][i] - 32))) ==
2559 0) ? 0 : 1 << (i - 32);
2564 UfsTagsToLevel(FileTag1, FileTag2, Algorithm, Size, Sections, vnode,
2570 uint32_t Sections[4];
2572 uint32_t Uniquifier;
2574 uint32_t HighEntropy;
2575 uint32_t LowEntropy;
2577 switch (Algorithm) {
2579 LowEntropy = UfsTagsToLowEntropy(FileTag1, FileTag2, Algorithm);
2580 HighEntropy = UfsTagsToHighEntropy(FileTag1, FileTag2, Algorithm);
2581 Sections[0] = HighEntropy % Directories[Size][0];
2582 HighEntropy /= Directories[Size][0];
2583 if (Directories[Size][1]) {
2584 Sections[1] = HighEntropy % Directories[Size][1];
2585 HighEntropy /= Directories[Size][1];
2586 Sections[2] = HighEntropy;
2587 Sections[3] = LowEntropy;
2589 Sections[1] = HighEntropy;
2590 Sections[2] = LowEntropy;
2594 Sections[0] = FileTag1 & 0xff;
2595 if (Directories[Size][1]) {
2596 Sections[1] = Uniquifier & 0xff;
2597 if (Directories[Size][1] == 16)
2599 Sections[2] = FileTag1;
2600 Sections[3] = FileTag2;
2602 Sections[1] = FileTag1;
2603 Sections[2] = FileTag2;
2607 Sections[0] = FileTag1 & 0xff;
2608 if (Directories[Size][1]) {
2609 Sections[1] = (vnode >> 1) & 0xff;
2610 if (Directories[Size][1] == 16)
2612 Sections[2] = FileTag1;
2613 Sections[3] = FileTag2;
2615 Sections[1] = FileTag1;
2616 Sections[2] = FileTag2;
2620 fprintf(stderr, "UfsTagsToLevel: bad algorithm %lu!\n", Algorithm);
2626 #include <afs/afscbdummies.h>
2627 #endif /* RESIDENCY */