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>
81 #include <afs/afsint.h>
84 #if !defined(PRE_AFS_36) && !defined(RESIDENCY)
85 #include <afs/ihandle.h>
86 #endif /* !defined(PRE_AFS_36) && !defined(RESIDENCY) */
87 #include <afs/vnode.h>
88 #include <afs/volume.h>
90 #ifdef AFS_LINUX24_ENV
91 #define _LARGEFILE64_SOURCE 1
94 #include <afs/rsdefs.h>
95 #include <afs/remioint.h>
96 #endif /* RESIDENCY */
101 typedef off_t off64_t;
102 #endif /* !HAVE_OFF64_T */
103 #ifndef HAVE_FSEEKO64
104 #define fseeko64 fseeko
105 #endif /* HAVE_FSEEKO64 */
106 #ifndef HAVE_FTELLO64
107 #define ftello64 ftello
108 #endif /* HAVE_FTELLO64 */
111 * Sigh. Linux blows it again
119 * Stuff that is in private AFS header files, unfortunately
122 #define DUMPVERSION 1
123 #define DUMPENDMAGIC 0x3A214B6E
124 #define DUMPBEGINMAGIC 0xB3A11322
125 #define D_DUMPHEADER 1
126 #define D_VOLUMEHEADER 2
131 #define MAXDUMPTIMES 50
136 char volumeName[VNAMESIZE];
137 int nDumpTimes; /* Number of pairs */
140 } dumpTimes[MAXDUMPTIMES];
144 * Our command-line arguments
149 int Algorithm; /* Conversion algorithm */
150 int Size; /* Directory hierarchy size */
151 int FSType; /* File system type */
152 int DeviceTag; /* Device Tag */
153 } rscmdlineinfo[RS_MAXRESIDENCIES];
156 * This stuff comes from ufsname.c (which itself takes it from
160 /* There is an assumption that all of the prefixes will have exactly one '/' */
161 static char *Ufs_Prefixes[] = { "/ufs", "/slowufs", "/cdmf", "/sdmf" };
163 #define MAX_ITERATIONS 10
164 #define UFS_SUMMARYTREENAME "Summaries"
165 #define UFS_STAGINGTREENAME "Staging"
166 #define UFS_VOLUMEHEADERTREENAME "VolHeaders"
167 #define UFS_VOLUMETREENAME "Volumes"
168 #define UFS_ALGORITHMBASE 'A'
169 #define UFS_MOUNTPOINTBASE 'a'
170 #define UFS_ALGORITHMS 3
171 #define UFS_LINK_MAX 64 /* Arbitrary. */
172 #define HARD_LINKED_FILE -2
173 #define TAGSTONAME(FileName, MountPoint, Sections, Level1, RWVolume, Vnode, Uniquifier, Algorithm) \
176 sprintf(FileName,"%s/%lu/%lu/%c%lu.%lu.%lu.%lu.%lu", MountPoint, \
177 (Sections)[0], (Sections)[1], UFS_ALGORITHMBASE + Algorithm, \
178 (Sections)[2], (Sections)[3], RWVolume, Vnode, Uniquifier); \
180 sprintf(FileName,"%s/%lu/%c%lu.%lu.%lu.%lu.%lu", MountPoint, \
181 (Sections)[0], UFS_ALGORITHMBASE + Algorithm, \
182 (Sections)[1], (Sections)[2], RWVolume, Vnode, Uniquifier); \
184 #define TAGSTOSTAGINGNAME(FileName, MountPoint, RWVolume, Vnode, Uniquifier) \
185 sprintf(FileName,"%s/%s/%lu.%lu.%lu", MountPoint, \
186 UFS_STAGINGTREENAME, RWVolume, Vnode, Uniquifier)
187 #define TAGSTOVOLUMEHEADERNAME(FileName, MountPoint, FileTag1, FileTag2) \
188 sprintf(FileName,"%s/%s/%lu", MountPoint, UFS_VOLUMEHEADERTREENAME, \
190 #define TAGSTOVOLUMEINFONAME(FileName, MountPoint, FileTag1, FileTag2) \
191 sprintf(FileName,"%s/%s/%lu/%lu", MountPoint, \
192 UFS_VOLUMETREENAME, FileTag2, FileTag1)
193 #define TAGSTOVOLUMENAME(FileName, MountPoint, FileTag1, FileTag2, RWVolume) \
194 sprintf(FileName,"%s/%s/%lu/%lu.%lu", MountPoint, \
195 UFS_VOLUMETREENAME, FileTag2, FileTag1, RWVolume)
196 #define TAGSTOSUMMARYNAME(FileName, MountPoint, FileTag1, FileTag2, SummaryRequestor, Residency) \
197 sprintf(FileName,"%s/%s/%lu.%lu.%lu.%lu", MountPoint, \
198 UFS_SUMMARYTREENAME, FileTag1, FileTag2, SummaryRequestor, \
200 #define DEVICETAGNUMBERTOMOUNTPOINT(MountPoint, DeviceTagNumber, FSType) \
201 sprintf(MountPoint,"%s%c", Ufs_Prefixes[FSType], UFS_MOUNTPOINTBASE + \
203 #define MOUNTPOINTTODEVICETAGNUMBER(MountPoint) \
204 MountPoint[strlen(MountPoint) - 1] - UFS_MOUNTPOINTBASE
205 #define DEVICETAGNUMBERTOVOLUMEHEADERTREE(TreeName, MountPoint) \
206 sprintf(TreeName,"%s/%s", MountPoint, UFS_VOLUMEHEADERTREENAME)
207 #define UFS_RESIDENCIES_FILE "Residencies"
209 /* We don't ever want to map to uid/gid -1. fchown() takes that as a
210 don't change flag. We know however that volume number range from
211 0x2000000 to 0x20FFFFFF (see VAllocateVolumeId() in vol/vutil.c)
212 so we will use that to insure that -1 never appears. */
213 #define RWVolumeToUid(RWVolume) ((RWVolume >> 12) & 0xFFFF)
214 #define RWVolumeToGid(RWVolume) ((RWVolume & 0xFFF) | \
215 (((RWVolume >> 28) & 0xF) << 12))
216 #define UidGidToRWVolume(Uid, Gid) ((Gid & 0xFFF) | ((Uid & 0xFFFF) << 12) | \
217 ((Gid & 0xF000) << 16))
220 /* These routines generate a file name to correspond to the given tag
223 /* The following entropy array contains the order of bits from highest entropy
224 to lowest in the numbers FileTag1 and FileTag2. Bit numbers 32 and above
225 correspond to FileTag2. This ordering was determined by examining all read-
226 write volumes in the psc.edu cell. */
227 char UfsEntropy[1][64] = {
228 {1, 2, 3, 4, 33, 5, 6, 7, 44, 45, 46, 36, 8, 34, 42, 35,
229 9, 40, 38, 32, 43, 10, 39, 37, 11, 41, 12, 13, 14, 0,
230 15, 16, 61, 17, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51,
231 50, 49, 48, 47, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22,
232 21, 20, 19, 18, 62, 63},
235 uint32_t Directories[3][2] = { {256, 0}, {256, 16}, {256, 256}, };
236 #endif /* RESIDENCY */
238 static int verbose = 0;
239 static int numNoDirData = 0;
240 static int termsize = 0;
243 extern resid ServerRequestorId;
244 #endif /* RESIDENCY */
247 * We use this structure to hold vnode data in our hash table.
248 * It's indexed by vnode number.
252 struct VnodeDiskObject *vnode; /* A pointer to the disk vnode */
253 int vnodeNumber; /* The vnode number */
254 off64_t dumpdata; /* File offset of dump data (if
256 unsigned char *filedata; /* A pointer to the actual file
257 * data itself (if available) */
258 unsigned int datalength; /* The length of the data */
262 * This contains the current location when we're doing a scan of a
267 int hashbucket; /* Current hash bucket */
268 int entry; /* Entry within hash bucket */
272 * Arrays to hold vnode data
275 struct vnodeData **LargeVnodeIndex;
276 struct vnodeData **SmallVnodeIndex;
277 int numLargeVnodes = 0;
278 int numSmallVnodes = 0;
281 * Crap for the libraries
284 int ShutdownInProgress = 0;
287 * Our local function prototypes
290 static int ReadDumpHeader(FILE *, struct DumpHeader *);
291 static int ReadVolumeHeader(FILE *, VolumeDiskData *);
292 static int ScanVnodes(FILE *, VolumeDiskData *, int);
293 static struct vnodeData *InsertVnode(unsigned int, struct VnodeDiskObject *);
294 static struct vnodeData *GetVnode(unsigned int);
295 static int CompareVnode(const void *, const void *);
296 static void InteractiveRestore(FILE *, VolumeDiskData *);
297 static void DirectoryList(int, char **, struct vnodeData *, VolumeDiskData *);
298 static void DirListInternal(struct vnodeData *, char *[], int, int, int, int,
299 int, int, VolumeDiskData *, char *);
300 static int CompareDirEntry(const void *, const void *);
301 static struct vnodeData *ChangeDirectory(int, char **, struct vnodeData *);
302 static void CopyFile(int, char **, struct vnodeData *, FILE *);
303 static void CopyVnode(int, char **, FILE *);
304 static void DumpAllFiles(int, char **, struct vnodeData *, VolumeDiskData *);
305 static struct vnodeData *FindFile(struct vnodeData *, char *);
306 static void ResetDirCursor(struct DirCursor *, struct vnodeData *);
307 static struct DirEntry *ReadNextDir(struct DirCursor *, struct vnodeData *);
308 static void MakeArgv(char *, int *, char ***);
309 static char *GetToken(char *, char **, char *, char *[]);
310 static int ReadInt16(FILE *, uint16_t *);
311 static int ReadInt32(FILE *, uint32_t *);
312 static int ReadString(FILE *, char *, int);
313 static int ReadByteString(FILE *, void *, int);
316 static int DumpVnodeFile(FILE *, struct VnodeDiskObject *, VolumeDiskData *);
317 static void DumpAllResidencies(FILE *, struct vnodeData *, VolumeDiskData *);
321 main(int argc, char *argv[])
323 int c, errflg = 0, force = 0, inode = 0;
325 struct DumpHeader dheader;
329 int Res, Arg1, Arg2, Arg3, i;
339 for (i = 0; i < RS_MAXRESIDENCIES; i++) {
340 rscmdlineinfo[i].Algorithm = -1;
341 rscmdlineinfo[i].Size = -1;
342 rscmdlineinfo[i].DeviceTag = -1;
343 rscmdlineinfo[i].FSType = -1;
345 #endif /* RESIDENCY */
348 * Sigh, this is dumb, but we need the terminal window size
349 * to do intelligent things with "ls" later on.
352 if (isatty(STDOUT_FILENO)) {
353 if ((p = getenv("COLUMNS")) != NULL)
355 else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0
357 termsize = win.ws_col;
360 while ((c = getopt(argc, argv, "difr:t:v")) != EOF)
364 if (sscanf(optarg, "%d/%d", &Res, &Arg1) != 2) {
369 if (1 << (ffs(Res) - 1) != Res) {
370 fprintf(stderr, "Invalid residency %d\n", Res);
375 if (Arg1 < 0 || Arg1 > 26) {
376 fprintf(stderr, "Invalid device tag: %d\n", Arg1);
380 rscmdlineinfo[ffs(Res) - 1].DeviceTag = Arg1;
381 #else /* RESIDENCY */
382 fprintf(stderr, "-t not supported in non-MRAFS " "dumptool.\n");
384 #endif /* RESIDENCY */
389 if (sscanf(optarg, "%d/%d/%d/%d", &Res, &Arg1, &Arg2, &Arg3) != 4) {
394 if (Arg1 < 0 || Arg1 > 3) {
395 fprintf(stderr, "Invalid fstype: %d\n", Arg1);
400 if (Arg2 < 0 || Arg2 > 2) {
401 fprintf(stderr, "Invalid size: %d\n", Arg2);
406 if (Arg3 <= 0 || Arg3 > UFS_ALGORITHMS) {
407 fprintf(stderr, "Invalid algorithm: %d\n", Arg3);
411 rscmdlineinfo[ffs(Res) - 1].FSType = Arg1;
412 rscmdlineinfo[ffs(Res) - 1].Size = Arg2;
413 rscmdlineinfo[ffs(Res) - 1].Algorithm = Arg3;
414 #else /* RESIDENCY */
415 fprintf(stderr, "-r not supported in non-MRAFS " "dumptool.\n");
417 #endif /* RESIDENCY */
422 #else /* RESIDENCY */
423 fprintf(stderr, "-d not supported in non-MRAFS " "dumptool.\n");
425 #endif /* RESIDENCY */
441 if (errflg || optind == argc) {
442 fprintf(stderr, "Usage: %s\n\t[-v] [-f]\n\t"
444 "[-t Residency/Tag]\n\t"
445 "[-r Residency/Type/Size/Algorithm]\n\t"
446 "[-d] filename [file_in_dump [file in dump ...]]\n",
447 #else /* RESIDENCY */
449 #endif /* RESIDENCY */
455 * Try opening the dump file
459 if ((fd = open(argv[optind], O_RDONLY | O_LARGEFILE)) < 0) {
461 if ((fd = open(argv[optind], O_RDONLY)) < 0) {
463 fprintf(stderr, "open of dumpfile %s failed: %s\n", argv[optind],
468 if ((f = fdopen(fd, "rb")) == NULL) {
469 fprintf(stderr, "fdopen of dumpfile %s failed: %s\n", argv[optind],
474 if (ReadDumpHeader(f, &dheader)) {
475 fprintf(stderr, "Failed to read dump header!\n");
480 printf("Dump is for volume %lu (%s)\n",
481 (unsigned long) dheader.volumeId, dheader.volumeName);
483 if (getc(f) != D_VOLUMEHEADER) {
484 fprintf(stderr, "Volume header is missing from dump, aborting\n");
488 if (ReadVolumeHeader(f, &vol)) {
489 fprintf(stderr, "Unable to read volume header\n");
494 printf("Volume information:\n");
495 printf("\tid = %lu\n", (unsigned long) vol.id);
496 printf("\tparent id = %lu\n", (unsigned long) vol.parentId);
497 printf("\tname = %s\n", vol.name);
502 printf(" inService");
505 if (vol.needsSalvaged)
506 printf(" needsSalvaged");
508 printf("\tuniquifier = %lu\n", (unsigned long) vol.uniquifier);
509 tmv = vol.creationDate;
510 printf("\tCreation date = %s", ctime(&tmv));
511 tmv = vol.accessDate;
512 printf("\tLast access date = %s", ctime(&tmv));
513 tmv = vol.updateDate;
514 printf("\tLast update date = %s", ctime(&tmv));
515 printf("\tVolume owner = %lu\n", (unsigned long) vol.owner);
519 printf("Scanning vnodes (this may take a while)\n");
522 * We need to do two vnode scans; one to get the number of
523 * vnodes, the other to actually build the index.
526 offset = ftello64(f);
528 if (ScanVnodes(f, &vol, 1)) {
529 fprintf(stderr, "First vnode scan failed, aborting\n");
533 fseeko64(f, offset, SEEK_SET);
535 if (ScanVnodes(f, &vol, 0)) {
536 fprintf(stderr, "Second vnode scan failed, aborting\n");
540 if (getc(f) != D_DUMPEND || ReadInt32(f, &magic) || magic != DUMPENDMAGIC) {
541 fprintf(stderr, "Couldn't find dump postamble, ");
543 fprintf(stderr, "aborting (use -f to override)\n");
546 fprintf(stderr, "continuing anyway\n");
547 fprintf(stderr, "WARNING: Dump may not be complete!\n");
552 * If we wanted to simply dump all vnodes, do it now
557 struct vnodeData *vdata;
559 for (i = 0; i < numLargeVnodes; i++) {
561 vdata = LargeVnodeIndex[i];
563 if (vdata->vnode->type == vFidLookup)
564 if (DumpVnodeFile(stdout, vdata->vnode, &vol)) {
565 fprintf(stderr, "DumpVnodeFile failed, " "aborting\n");
570 for (i = 0; i < numSmallVnodes; i++) {
572 vdata = SmallVnodeIndex[i];
574 if (vdata->vnode->type == vFidLookup)
575 if (DumpVnodeFile(stdout, vdata->vnode, &vol)) {
576 fprintf(stderr, "DumpVnodeFile failed, " "aborting\n");
582 #endif /* RESIDENCY */
585 * Dump out all filenames with their corresponding FID
588 struct vnodeData *rootvdata;
590 if ((rootvdata = GetVnode(1)) == NULL) {
592 "Can't get vnode data for root " "vnode! Aborting\n");
596 DirListInternal(rootvdata, NULL, 0, 0, 1, 0, 1, 0, &vol, "");
598 } else if (argc > optind + 1) {
601 * Dump out residencies of files given on the command line.
604 struct vnodeData *vdata, *rootvdata;
606 if ((rootvdata = GetVnode(1)) == NULL) {
608 "Can't get vnode data for root " "vnode! Aborting\n");
612 for (i = optind + 1; i < argc; i++) {
614 if ((vdata = FindFile(rootvdata, argv[i])) == NULL) {
615 fprintf(stderr, "Skipping file %s\n", argv[i]);
620 printf("Residency locations for %s:\n", argv[i]);
622 while (vdata->vnode->NextVnodeId != 0) {
624 vdata = GetVnode(vdata->vnode->NextVnodeId);
628 "We had a vnode chain " "pointer to a vnode that "
629 "doesn't exist, aborting!\n");
632 if (vdata->vnode->type == vFidLookup)
633 DumpVnodeFile(stdout, vdata->vnode, &vol);
636 #else /* RESIDENCY */
637 fprintf(stderr, "Extra arguments after dump filename: %s\n",
640 #endif /* RESIDENCY */
643 * Perform an interactive restore
646 InteractiveRestore(f, &vol);
653 * Read the dump header, which is at the beginning of every dump
657 ReadDumpHeader(FILE * f, struct DumpHeader *header)
662 if (getc(f) != D_DUMPHEADER || ReadInt32(f, &magic)
663 || ReadInt32(f, (unsigned int *)
664 &header->version) || magic != DUMPBEGINMAGIC) {
666 fprintf(stderr, "Couldn't find dump magic numbers\n");
670 header->volumeId = 0;
671 header->nDumpTimes = 0;
673 while ((tag = getc(f)) > D_MAX && tag != EOF) {
674 unsigned short length;
677 if (ReadInt32(f, &header->volumeId)) {
679 fprintf(stderr, "Failed to read " "volumeId\n");
684 if (ReadString(f, header->volumeName, sizeof(header->volumeName))) {
686 fprintf(stderr, "Failed to read " "volume name\n");
691 if (ReadInt16(f, &length)) {
694 "Failed to read " "dump time array length\n");
697 header->nDumpTimes = (length >> 1);
698 for (i = 0; i < header->nDumpTimes; i++)
699 if (ReadInt32(f, (unsigned int *)
700 &header->dumpTimes[i].from)
701 || ReadInt32(f, (unsigned int *)
702 &header->dumpTimes[i].to)) {
704 fprintf(stderr, "Failed to " "read dump times\n");
710 fprintf(stderr, "Unknown dump tag \"%c\"\n", tag);
715 if (!header->volumeId || !header->nDumpTimes) {
718 "We didn't get a volume Id or " "dump times listing\n");
727 * Read the volume header; this is the information stored in VolumeDiskData.
729 * I'm not sure we need all of this, but read it in just in case.
733 ReadVolumeHeader(FILE * f, VolumeDiskData * vol)
737 memset((void *)vol, 0, sizeof(*vol));
739 while ((tag = getc(f)) > D_MAX && tag != EOF) {
742 if (ReadInt32(f, &vol->id))
746 if (ReadInt32(f, &trash))
750 if (ReadString(f, vol->name, sizeof(vol->name)))
754 vol->inService = getc(f);
757 vol->blessed = getc(f);
760 if (ReadInt32(f, &vol->uniquifier))
767 if (ReadInt32(f, &vol->parentId))
771 if (ReadInt32(f, &vol->cloneId))
775 if (ReadInt32(f, (uint32_t *) & vol->maxquota))
779 if (ReadInt32(f, (uint32_t *) & vol->minquota))
783 if (ReadInt32(f, (uint32_t *) & vol->diskused))
787 if (ReadInt32(f, (uint32_t *) & vol->filecount))
791 if (ReadInt32(f, &vol->accountNumber))
795 if (ReadInt32(f, &vol->owner))
799 if (ReadInt32(f, &vol->creationDate))
803 if (ReadInt32(f, &vol->accessDate))
807 if (ReadInt32(f, &vol->updateDate))
811 if (ReadInt32(f, &vol->expirationDate))
815 if (ReadInt32(f, &vol->backupDate))
820 (f, vol->offlineMessage, sizeof(vol->offlineMessage)))
824 if (ReadString(f, (char *)vol->stat_reads, VMSGSIZE))
828 unsigned short length;
831 if (ReadInt16(f, &length))
833 for (i = 0; i < length; i++) {
834 if (ReadInt32(f, &data))
836 if (i < sizeof(vol->weekUse) / sizeof(vol->weekUse[0]))
837 vol->weekUse[i] = data;
842 if (ReadInt32(f, &vol->dayUseDate))
846 if (ReadInt32(f, (uint32_t *) & vol->dayUse))
851 unsigned short length;
855 if (ReadInt16(f, &length))
857 for (i = 0; i < length; i++) {
858 if (ReadInt32(f, &data))
861 sizeof(vol->DesiredInfo.DesiredResidencyWords) /
862 sizeof(vol->DesiredInfo.DesiredResidencyWords[0]))
863 vol->DesiredInfo.DesiredResidencyWords[i] = data;
868 unsigned short length;
872 if (ReadInt16(f, &length))
874 for (i = 0; i < length; i++) {
875 if (ReadInt32(f, &data))
878 sizeof(vol->UnDesiredInfo.UnDesiredResidencyWords) /
879 sizeof(vol->UnDesiredInfo.UnDesiredResidencyWords[0]))
880 vol->UnDesiredInfo.UnDesiredResidencyWords[i] = data;
887 fprintf(stderr, "Unknown dump tag \"%c\"\n", tag);
897 * Scan all our vnode entries, and build indexing information.
901 ScanVnodes(FILE * f, VolumeDiskData * vol, int sizescan)
905 int numFileVnodes = 0;
906 int numDirVnodes = 0;
907 unsigned char buf[SIZEOF_LARGEDISKVNODE];
908 struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)buf;
909 off64_t offset, oldoffset;
910 struct vnodeData *vdata;
915 while (tag == D_VNODE) {
922 if (ReadInt32(f, (uint32_t *) & vnodeNumber)) {
923 fprintf(stderr, "failed int32 for 'vnodenum'\n");
927 if (ReadInt32(f, &vnode->uniquifier)) {
928 fprintf(stderr, "failed int32 for 'uniquifier'\n");
932 if (verbose > 1 && !sizescan)
933 printf("Got vnode %d\n", vnodeNumber);
935 while ((tag = getc(f)) > D_MAX && tag != EOF)
938 vnode->type = (VnodeType) getc(f);
943 if (ReadInt16(f, &tmp)) {
944 fprintf(stderr, "failed int16 for 'l'\n");
947 vnode->linkCount = tmp;
951 if (ReadInt32(f, &vnode->dataVersion)) {
952 fprintf(stderr, "failed int32 for 'v'\n");
957 if (ReadInt32(f, (uint32_t *) & vnode->unixModifyTime)) {
958 fprintf(stderr, "failed int32 for 'm'\n");
963 if (ReadInt32(f, (uint32_t *) & vnode->serverModifyTime)) {
964 fprintf(stderr, "failed int32 for 's'\n");
969 if (ReadInt32(f, &vnode->author)) {
970 fprintf(stderr, "failed int32 for 'a'\n");
975 if (ReadInt32(f, &vnode->owner)) {
976 fprintf(stderr, "failed int32 for 'o'\n");
981 if (ReadInt32(f, (uint32_t *) & vnode->group)) {
982 fprintf(stderr, "failed int32 for 'g'\n");
987 unsigned short modeBits;
988 if (ReadInt16(f, &modeBits))
990 vnode->modeBits = modeBits;
994 if (ReadInt32(f, &vnode->parent)) {
995 fprintf(stderr, "failed int32 for 'p'\n");
1001 if (ReadInt32(f, &vnode->NextVnodeId)) {
1002 fprintf(stderr, "failed int32 for 'N'\n");
1007 if (ReadInt32(f, &VLkp_Residencies(vnode))) {
1008 fprintf(stderr, "failed int32 for 'R'\n");
1014 if (ReadInt32(f, &vnode->length)) {
1015 fprintf(stderr, "failed int32 for 'S'\n");
1020 if (ReadInt32(f, (uint32_t *) & vnode->vn_ino_lo))
1025 (f, (void *)VVnodeDiskACL(vnode), VAclDiskSize(vnode))) {
1026 fprintf(stderr, "failed readbystring for 'A'\n");
1030 acl_NtohACL(VVnodeDiskACL(vnode));
1035 if (ReadInt32(f, &vnode->length_hi)) {
1036 fprintf(stderr, "failed int32 for 'h'\n");
1041 if (verbose > 1 && !sizescan)
1042 printf("We have file data!\n");
1043 if (ReadInt32(f, &length)) {
1044 fprintf(stderr, "failed int32 for 'f'\n");
1047 vnode->length = length;
1048 offset = ftello64(f);
1049 fseeko64(f, length, SEEK_CUR);
1053 fprintf(stderr, "Unknown dump tag \"%c\"\n", tag);
1058 * If we're doing an incremental restore, then vnodes
1059 * will be listed in the dump, but won't contain any
1060 * vnode information at all (I don't know why they're
1061 * included _at all_). If we get one of these vnodes, then
1062 * just skip it (because we can't do anything with it.
1065 if (vnode->type == -1)
1069 if (verbose > 1 && vnode->type == vFidLookup && !sizescan) {
1071 ("This is an auxiliary vnode (lookup) for vnode %d, residency %d\n",
1072 VLkp_ParentVnodeId(vnode), VLkp_Residencies(vnode));
1073 if (DumpVnodeFile(stdout, vnode, vol))
1077 if (verbose > 1 && vnode->type == vAccessHistory && !sizescan)
1078 printf("This is an auxiliary vnode (history) for vnode %d\n",
1079 VLkp_ParentVnodeId(vnode));
1082 if (vnode->type == vDirectory)
1088 * We know now all we would ever know about the vnode;
1089 * insert it into our hash table (but only if we're not
1090 * doing a vnode scan).
1095 vdata = InsertVnode(vnodeNumber, vnode);
1097 if (vdata == NULL) {
1100 "Failed to insert " "vnode into hash table");
1104 vdata->dumpdata = offset;
1105 vdata->datalength = length;
1108 * Save directory data, since we'll need it later.
1111 if (vnode->type == vDirectory && length) {
1113 vdata->filedata = malloc(length);
1115 if (!vdata->filedata) {
1118 "Unable to " "allocate space for "
1119 "file data (%d)\n", length);
1123 oldoffset = ftello64(f);
1124 fseeko64(f, offset, SEEK_SET);
1126 if (fread(vdata->filedata, length, 1, f) != 1) {
1128 fprintf(stderr, "Unable to " "read in file data!\n");
1132 fseeko64(f, oldoffset, SEEK_SET);
1133 } else if (vnode->type == vDirectory)
1135 * Warn the user we may not have all directory
1146 numLargeVnodes = numDirVnodes;
1147 numSmallVnodes = numFileVnodes;
1150 LargeVnodeIndex = (struct vnodeData **)
1151 malloc(numDirVnodes * sizeof(struct vnodeData));
1152 SmallVnodeIndex = (struct vnodeData **)
1153 malloc(numFileVnodes * sizeof(struct vnodeData));
1155 if (LargeVnodeIndex == NULL || SmallVnodeIndex == NULL) {
1158 "Unable to allocate space " "for vnode tables\n");
1164 fprintf(stderr, "%s vnode scan completed\n",
1165 sizescan ? "Primary" : "Secondary");
1171 * Perform an interactive restore
1173 * Parsing the directory information is a pain, but other than that
1174 * we just use the other tools we already have in here.
1176 #define CMDBUFSIZE (AFSPATHMAX * 2)
1178 InteractiveRestore(FILE * f, VolumeDiskData * vol)
1180 struct vnodeData *vdatacwd; /* Vnode data for our current dir */
1181 char cmdbuf[CMDBUFSIZE];
1186 * Let's see if we can at least get the data for our root directory.
1187 * If we can't, there's no way we can do an interactive restore.
1190 if ((vdatacwd = GetVnode(1)) == NULL) {
1191 fprintf(stderr, "No entry for our root vnode! Aborting\n");
1195 if (!vdatacwd->filedata) {
1197 "There is no directory data for the root "
1198 "vnode (1.1). An interactive\nrestore is not "
1204 * If you're doing a selective dump correctly, then you should get all
1205 * directory vnode data. But just in case you didn't, let the user
1206 * know there may be a problem.
1211 "WARNING: %d directory vnodes had no file "
1212 "data. An interactive restore\nmay not be possible\n",
1216 while (fgets(cmdbuf, CMDBUFSIZE, stdin)) {
1218 cmdbuf[strlen(cmdbuf) - 1] = '\0';
1220 if (strlen(cmdbuf) == 0) {
1225 MakeArgv(cmdbuf, &argc, &argv);
1227 if (strcmp(argv[0], "ls") == 0) {
1228 DirectoryList(argc, argv, vdatacwd, vol);
1229 } else if (strcmp(argv[0], "cd") == 0) {
1230 struct vnodeData *newvdata;
1232 newvdata = ChangeDirectory(argc, argv, vdatacwd);
1235 vdatacwd = newvdata;
1236 } else if (strcmp(argv[0], "file") == 0) {
1237 DumpAllFiles(argc, argv, vdatacwd, vol);
1238 } else if (strcmp(argv[0], "cp") == 0) {
1239 CopyFile(argc, argv, vdatacwd, f);
1240 } else if (strcmp(argv[0], "vcp") == 0) {
1241 CopyVnode(argc, argv, f);
1242 } else if (strcmp(argv[0], "quit") == 0
1243 || strcmp(argv[0], "exit") == 0)
1245 else if (strcmp(argv[0], "?") == 0 || strcmp(argv[0], "help") == 0) {
1246 printf("Valid commands are:\n");
1247 printf("\tls\t\tList current directory\n");
1248 printf("\tcd\t\tChange current directory\n");
1249 printf("\tcp\t\tCopy file from dump\n");
1250 printf("\tvcp\t\tCopy file from dump (via vnode)\n");
1252 printf("\tfile\t\tList residency filenames\n");
1253 #endif /* RESIDENCY */
1254 printf("\tquit | exit\tExit program\n");
1255 printf("\thelp | ?\tBrief help\n");
1258 "Unknown command, \"%s\", enter "
1259 "\"help\" for a list of commands.\n", argv[0]);
1268 * Do a listing of all files in a directory. Sigh, I wish this wasn't
1271 * With the reorganizing, this is just a front-end to DirListInternal()
1275 DirectoryList(int argc, char **argv, struct vnodeData *vdata,
1276 VolumeDiskData * vol)
1278 int errflg = 0, lflag = 0, iflag = 0, Fflag = 0, sflag = 0, Rflag = 0;
1283 while ((c = getopt(argc, argv, "liFRs")) != EOF)
1305 fprintf(stderr, "Usage: %s [-liFs] filename [filename ...]\n",
1310 DirListInternal(vdata, &(argv[optind]), argc - optind, lflag, iflag,
1311 Fflag, Rflag, 1, vol, NULL);
1317 * Function that does the REAL work in terms of directory listing
1321 DirListInternal(struct vnodeData *vdata, char *pathnames[], int numpathnames,
1322 int lflag, int iflag, int Fflag, int Rflag, int verbose,
1323 VolumeDiskData * vol, char *path)
1325 struct DirEntry *ep, **eplist = NULL, **eprecurse = NULL;
1326 struct DirCursor cursor;
1327 struct vnodeData *lvdata;
1329 int i, j, numentries = 0, longestname = 0, numcols, col, numrows;
1332 if (!vdata->filedata) {
1333 fprintf(stderr, "There is no vnode data for this " "directory!\n");
1337 ResetDirCursor(&cursor, vdata);
1340 * Scan through the whole directory
1343 while ((ep = ReadNextDir(&cursor, vdata)) != NULL) {
1346 * If we didn't get any filenames on the command line,
1350 if (numpathnames == 0) {
1352 realloc(eplist, sizeof(struct DirEntry *) * ++numentries);
1353 eplist[numentries - 1] = ep;
1354 if (strlen(ep->name) > longestname)
1355 longestname = strlen(ep->name);
1357 if ((lvdata = GetVnode(ntohl(ep->fid.vnode)))
1358 && lvdata->vnode->type == vDirectory
1359 && !(strcmp(ep->name, ".") == 0
1360 || strcmp(ep->name, "..") == 0)) {
1363 sizeof(struct DirEntry *) * ++numrecurse);
1364 eprecurse[numrecurse - 1] = ep;
1369 * Do glob matching via fnmatch()
1372 for (i = 0; i < numpathnames; i++)
1373 if (fnmatch(pathnames[i], ep->name, FNM_PATHNAME) == 0) {
1376 sizeof(struct DirEntry *) * ++numentries);
1377 eplist[numentries - 1] = ep;
1378 if (strlen(ep->name) > longestname)
1379 longestname = strlen(ep->name);
1381 if ((lvdata = GetVnode(ntohl(ep->fid.vnode)))
1382 && lvdata->vnode->type == vDirectory
1383 && !(strcmp(ep->name, ".") == 0
1384 || strcmp(ep->name, "..") == 0)) {
1387 sizeof(struct DirEntry *) *
1389 eprecurse[numrecurse - 1] = ep;
1396 qsort((void *)eplist, numentries, sizeof(struct DirEntry *),
1399 if (Rflag && eprecurse)
1400 qsort((void *)eprecurse, numrecurse, sizeof(struct DirEntry *),
1403 * We don't have to do column printing if we have the -l or the -i
1404 * options. Sigh, column printing is WAY TOO FUCKING COMPLICATED!
1407 if (!lflag && !iflag) {
1415 numcols = termsize / longestname ? termsize / longestname : 1;
1416 numrows = numentries / numcols + (numentries % numcols ? 1 : 0);
1418 for (i = 0; i < numrows; i++) {
1420 while (col < numcols && (i + col * numrows) < numentries) {
1421 ep = eplist[i + col++ * numrows];
1423 if (!(lvdata = GetVnode(ntohl(ep->fid.vnode))))
1425 else if (lvdata->vnode->type == vDirectory)
1427 else if (lvdata->vnode->type == vSymlink)
1429 else if ((lvdata->vnode->modeBits & 0111) != 0)
1433 printf("%s%-*c", ep->name, (int)(longestname -
1434 strlen(ep->name)), c);
1436 printf("%-*s", longestname, ep->name);
1442 for (i = 0; i < numentries; i++)
1443 if (!(lvdata = GetVnode(ntohl(eplist[i]->fid.vnode))))
1444 printf("%d.0.0\t%s\n",
1445 vol->parentId ? vol->parentId : vol->id,
1448 printf("%d.%d.%d\t%s/%s\n", vol->id,
1449 ntohl(eplist[i]->fid.vnode),
1450 ntohl(eplist[i]->fid.vunique), path, eplist[i]->name);
1452 printf("%d.%d.%d\t%s\n", vol->id, ntohl(eplist[i]->fid.vnode),
1453 ntohl(eplist[i]->fid.vunique), eplist[i]->name);
1455 for (i = 0; i < numentries; i++)
1456 if (!(lvdata = GetVnode(ntohl(eplist[i]->fid.vnode))))
1457 printf("---------- 0 0 " "0 0 %s\n",
1460 switch (lvdata->vnode->type) {
1471 for (j = 8; j >= 0; j--) {
1472 if (lvdata->vnode->modeBits & (1 << j))
1486 printf(" %-3d %-8d %-8d %10d %s\n", lvdata->vnode->linkCount,
1487 lvdata->vnode->owner, lvdata->vnode->group,
1488 lvdata->vnode->length, eplist[i]->name);
1494 if (Rflag && eprecurse) {
1497 for (i = 0; i < numrecurse; i++) {
1499 printf("\n%s:\n", eprecurse[i]->name);
1501 lpath = malloc(strlen(path) + strlen(eprecurse[i]->name) + 2);
1503 sprintf(lpath, "%s/%s", path, eprecurse[i]->name);
1505 DirListInternal(GetVnode(ntohl(eprecurse[i]->fid.vnode)), NULL, 0,
1506 lflag, iflag, Fflag, Rflag, verbose, vol, lpath);
1522 * Directory name comparison function, used by qsort
1526 CompareDirEntry(const void *e1, const void *e2)
1528 struct DirEntry **ep1 = (struct DirEntry **)e1;
1529 struct DirEntry **ep2 = (struct DirEntry **)e2;
1531 return strcmp((*ep1)->name, (*ep2)->name);
1535 * Change a directory. Return a pointer to our new vdata structure for
1539 static struct vnodeData *
1540 ChangeDirectory(int argc, char **argv, struct vnodeData *vdatacwd)
1542 struct vnodeData *newvdatacwd;
1545 fprintf(stderr, "Usage: %s directory\n", argv[0]);
1549 if ((newvdatacwd = FindFile(vdatacwd, argv[1])) == NULL)
1552 if (newvdatacwd->vnode->type != vDirectory) {
1553 fprintf(stderr, "%s: Not a directory\n", argv[1]);
1557 if (newvdatacwd->filedata == NULL) {
1558 fprintf(stderr, "%s: No directory data found.\n", argv[1]);
1566 * Copy a file from out of the dump file
1569 #define COPYBUFSIZE 8192
1572 CopyFile(int argc, char **argv, struct vnodeData *vdatacwd, FILE * f)
1574 struct vnodeData *vdata;
1578 char buffer[COPYBUFSIZE];
1581 fprintf(stderr, "Usage: %s dumpfile destfile\n", argv[0]);
1585 if ((vdata = FindFile(vdatacwd, argv[1])) == NULL)
1588 if (vdata->dumpdata == 0) {
1589 fprintf(stderr, "File %s has no data in dump file\n", argv[1]);
1593 if ((out = fopen(argv[2], "wb")) == NULL) {
1594 fprintf(stderr, "Open of %s failed: %s\n", argv[2], strerror(errno));
1598 if (fseeko64(f, vdata->dumpdata, SEEK_SET)) {
1599 fprintf(stderr, "Seek failed: %s\n", strerror(errno));
1604 while (cur < vdata->datalength) {
1608 vdata->datalength ? COPYBUFSIZE : vdata->datalength - cur;
1610 ret = fread(buffer, sizeof(char), bytes, f);
1613 fprintf(stderr, "Short read (expected %d, " "got %d)\n",
1616 fprintf(stderr, "Error during read: %s\n", strerror(errno));
1621 ret = fwrite(buffer, sizeof(char), bytes, out);
1624 fprintf(stderr, "Short write (expected %d, " "got %d)\n",
1627 fprintf(stderr, "Error during write: %s\n", strerror(errno));
1639 * Copy a file from out of the dump file, by using the vnode
1643 CopyVnode(int argc, char *argv[], FILE * f)
1645 struct vnodeData *vdata;
1649 char buffer[COPYBUFSIZE];
1650 unsigned int vnode, uniquifier = 0;
1653 fprintf(stderr, "Usage: %s vnode[.uniqifier] destfile\n", argv[0]);
1657 ret = sscanf(argv[1], "%d.%d", &vnode, &uniquifier);
1660 fprintf(stderr, "Invalid file identifier: %s\n", argv[1]);
1664 if (!(vdata = GetVnode(vnode))) {
1665 fprintf(stderr, "Vnode %d not in dump file\n", vnode);
1669 if (ret == 2 && vdata->vnode->uniquifier != uniquifier) {
1671 "Specified uniquifier %d did not match "
1672 "uniquifier %d found in dump file!\n", uniquifier,
1673 vdata->vnode->uniquifier);
1677 if (vdata->dumpdata == 0) {
1678 fprintf(stderr, "File %s has no data in dump file\n", argv[1]);
1682 if ((out = fopen(argv[2], "wb")) == NULL) {
1683 fprintf(stderr, "Open of %s failed: %s\n", argv[2], strerror(errno));
1687 if (fseeko64(f, vdata->dumpdata, SEEK_SET)) {
1688 fprintf(stderr, "Seek failed: %s\n", strerror(errno));
1693 while (cur < vdata->datalength) {
1697 vdata->datalength ? COPYBUFSIZE : vdata->datalength - cur;
1699 ret = fread(buffer, sizeof(char), bytes, f);
1702 fprintf(stderr, "Short read (expected %d, " "got %d)\n",
1705 fprintf(stderr, "Error during read: %s\n", strerror(errno));
1710 ret = fwrite(buffer, sizeof(char), bytes, out);
1713 fprintf(stderr, "Short write (expected %d, " "got %d)\n",
1716 fprintf(stderr, "Error during write: %s\n", strerror(errno));
1728 * Dump all residency filenames associated with a file, or all files
1729 * within a directory.
1733 DumpAllFiles(int argc, char **argv, struct vnodeData *vdatacwd,
1734 VolumeDiskData * vol)
1737 struct vnodeData *vdata, *nvdata;
1738 struct DirCursor cursor;
1739 struct DirEntry *ep;
1742 int dflag = 0, fflag = 0, errflg = 0;
1746 while ((c = getopt(argc, argv, "df:")) != EOF)
1752 if ((f = fopen(optarg, "a")) == NULL) {
1753 fprintf(stderr, "Cannot open \"%s\": %s\n", optarg,
1765 if (errflg || argc == optind) {
1766 fprintf(stderr, "Usage: %s [-d] [-f filename] file " "[file ...]\n",
1773 for (i = optind; i < argc; i++) {
1775 if ((vdata = FindFile(vdatacwd, argv[i])) == NULL)
1778 if (vdata->vnode->type == vDirectory && !dflag) {
1780 ResetDirCursor(&cursor, vdata);
1782 while ((ep = ReadNextDir(&cursor, vdata)) != NULL) {
1784 if (!(nvdata = GetVnode(ntohl(ep->fid.vnode)))) {
1786 "Cannot find vnode " "entry for %s (%d)\n",
1787 ep->name, ntohl(ep->fid.vnode));
1793 printf("Residency locations for %s:\n", ep->name);
1795 if (nvdata->dumpdata)
1796 printf("Local disk (in dump " "file)\n");
1799 DumpAllResidencies(f, nvdata, vol);
1805 printf("Residency locations for %s:\n", argv[i]);
1807 if (vdata->dumpdata)
1808 printf("Local disk (in dump file)\n");
1811 DumpAllResidencies(f, vdata, vol);
1817 #else /* RESIDENCY */
1819 "The \"file\" command is not available in the non-"
1820 "MRAFS version of dumptool.\n");
1821 #endif /* RESIDENCY */
1826 * Take a vnode, traverse the vnode chain, and dump out all files on
1827 * all residencies corresponding to that parent vnode.
1832 DumpAllResidencies(FILE * f, struct vnodeData *vdata,
1833 struct VolumeDiskData *vol)
1835 unsigned int nextVnodeNum;
1837 while (nextVnodeNum = vdata->vnode->NextVnodeId) {
1838 if ((vdata = GetVnode(nextVnodeNum)) == NULL) {
1840 "We had a pointer to %lu in it's "
1841 "vnode chain, but there\nisn't a record of "
1842 "it! The dump might be corrupt.\n", nextVnodeNum);
1846 if (vdata->vnode->type == vFidLookup)
1847 DumpVnodeFile(f, vdata->vnode, vol);
1856 * Given a directory vnode and a filename, return the vnode corresponding
1857 * to the file in that directory.
1859 * We now handle pathnames with directories in them.
1862 static struct vnodeData *
1863 FindFile(struct vnodeData *vdatacwd, char *filename)
1865 struct DirHeader *dhp;
1866 struct DirEntry *ep;
1868 struct vnodeData *vdata;
1869 char *c, newstr[MAXPATHLEN];
1871 if (!vdatacwd->filedata) {
1872 fprintf(stderr, "There is no vnode data for this " "directory!\n");
1877 * If we have a "/" in here, look up the vnode data for the
1878 * directory (everything before the "/") and use that as our
1879 * current directory. We automagically handle multiple directories
1880 * by using FindFile recursively.
1883 if ((c = strrchr(filename, '/')) != NULL) {
1885 strncpy(newstr, filename, c - filename);
1886 newstr[c - filename] = '\0';
1888 if ((vdatacwd = FindFile(vdatacwd, newstr)) == NULL)
1891 if (vdatacwd->vnode->type != vDirectory) {
1892 fprintf(stderr, "%s: Not a directory\n", newstr);
1899 dhp = (struct DirHeader *)vdatacwd->filedata;
1901 i = DirHash(filename);
1903 num = ntohs(dhp->hashTable[i]);
1906 ep = (struct DirEntry *)(vdatacwd->filedata + (num * 32));
1907 if (strcmp(ep->name, filename) == 0)
1909 num = ntohs(ep->next);
1913 fprintf(stderr, "%s: No such file or directory\n", filename);
1917 if ((vdata = GetVnode(ntohl(ep->fid.vnode))) == NULL) {
1918 fprintf(stderr, "%s: No vnode information for %u found\n", filename,
1919 ntohl(ep->fid.vnode));
1927 * Reset a structure containing the current directory scan location
1931 ResetDirCursor(struct DirCursor *cursor, struct vnodeData *vdata)
1933 struct DirHeader *dhp;
1935 cursor->hashbucket = 0;
1937 dhp = (struct DirHeader *)vdata->filedata;
1939 cursor->entry = ntohs(dhp->hashTable[0]);
1943 * Given a cursor and a directory entry, return the next entry in the
1947 static struct DirEntry *
1948 ReadNextDir(struct DirCursor *cursor, struct vnodeData *vdata)
1950 struct DirHeader *dhp;
1951 struct DirEntry *ep;
1953 dhp = (struct DirHeader *)vdata->filedata;
1955 if (cursor->entry) {
1956 ep = (struct DirEntry *)(vdata->filedata + (cursor->entry * 32));
1957 cursor->entry = ntohs(ep->next);
1960 while (++(cursor->hashbucket) < NHASHENT) {
1961 cursor->entry = ntohs(dhp->hashTable[cursor->hashbucket]);
1962 if (cursor->entry) {
1963 ep = (struct DirEntry *)(vdata->filedata +
1964 (cursor->entry * 32));
1965 cursor->entry = ntohs(ep->next);
1975 * Given a string, split it up into components a la Unix argc/argv.
1977 * This code is most stolen from ftp.
1981 MakeArgv(char *string, int *argc, char ***argv)
1983 static char *largv[64];
1986 static char argbuf[CMDBUFSIZE];
1992 while ((*la++ = GetToken(s, &s, ap, &ap)) != NULL)
1997 * Return a pointer to the next token, and update the current string
2002 GetToken(char *string, char **nexttoken, char argbuf[], char *nextargbuf[])
2029 goto OUTTOKEN; /* End of our token */
2033 goto S2; /* Get next character */
2037 goto S3; /* Get quoted string */
2040 *ap++ = *sp++; /* Add a character to our token */
2076 *nextargbuf = ap; /* Update storage pointer */
2077 *nexttoken = sp; /* Update token pointer */
2079 return got_one ? argbuf : NULL;
2083 * Insert vnodes into our hash table.
2086 static struct vnodeData *
2087 InsertVnode(unsigned int vnodeNumber, struct VnodeDiskObject *vnode)
2089 struct VnodeDiskObject *nvnode;
2090 struct vnodeData *vdata;
2091 static int curSmallVnodeIndex = 0;
2092 static int curLargeVnodeIndex = 0;
2093 struct vnodeData ***vnodeIndex;
2096 nvnode = (struct VnodeDiskObject *)malloc(sizeof(struct VnodeDiskObject));
2100 fprintf(stderr, "Unable to allocate space for vnode\n");
2104 memcpy((void *)nvnode, (void *)vnode, sizeof(struct VnodeDiskObject));
2106 if (vnodeNumber & 1) {
2107 vnodeIndex = &LargeVnodeIndex;
2108 curIndex = &curLargeVnodeIndex;
2110 vnodeIndex = &SmallVnodeIndex;
2111 curIndex = &curSmallVnodeIndex;
2114 vdata = (struct vnodeData *)malloc(sizeof(struct vnodeData));
2116 vdata->vnode = nvnode;
2117 vdata->vnodeNumber = vnodeNumber;
2118 vdata->dumpdata = 0;
2119 vdata->filedata = 0;
2120 vdata->datalength = 0;
2122 (*vnodeIndex)[(*curIndex)++] = vdata;
2128 * Routine to retrieve a vnode from the hash table.
2131 static struct vnodeData *
2132 GetVnode(unsigned int vnodeNumber)
2134 struct vnodeData vnode, *vnodep, **tmp;
2136 vnode.vnodeNumber = vnodeNumber;
2139 tmp = (struct vnodeData **)
2140 bsearch((void *)&vnodep,
2141 vnodeNumber & 1 ? LargeVnodeIndex : SmallVnodeIndex,
2142 vnodeNumber & 1 ? numLargeVnodes : numSmallVnodes,
2143 sizeof(struct vnodeData *), CompareVnode);
2145 return tmp ? *tmp : NULL;
2149 * Our comparator function for bsearch
2153 CompareVnode(const void *node1, const void *node2)
2155 struct vnodeData **vnode1 = (struct vnodeData **)node1;
2156 struct vnodeData **vnode2 = (struct vnodeData **)node2;
2158 if ((*vnode1)->vnodeNumber == (*vnode2)->vnodeNumber)
2160 else if ((*vnode1)->vnodeNumber > (*vnode2)->vnodeNumber)
2168 * Dump out the filename corresponding to a particular vnode.
2170 * This routine has the following dependancies:
2172 * - Only will work on UFS filesystems at this point
2173 * - Has to talk to the rsserver.
2174 * - Can only determine UFS algorithm type when run on the same machine
2175 * as the residency (unless you manually specify algorithm information)
2179 DumpVnodeFile(FILE * f, struct VnodeDiskObject *vnode, VolumeDiskData * vol)
2181 static int rscache = 0;
2182 static rsaccessinfoList rsnlist = { 0, 0 };
2183 char MountPoint[MAXPATHLEN + 1];
2184 char FileName[MAXPATHLEN + 1];
2185 unsigned int Size, Level[4];
2186 unsigned int DeviceTag, Algorithm;
2187 FileSystems *FSInfo;
2188 int i, found, FSType, rsindex;
2191 * Maybe we found out something about this residency via the
2192 * command-line; check that first.
2195 rsindex = ffs(VLkp_Residencies(vnode)) - 1;
2198 * We need to get information from the rsserver (so we can
2199 * find out the device tag for a given residency). If we
2200 * haven't cached that, talk to the rsserver to get it.
2201 * If we have info about this already, then don't talk to
2202 * the rsserver (this lets us still do disaster recovery if
2203 * MR-AFS is completely hosed).
2206 if (!rscache && rscmdlineinfo[rsindex].DeviceTag == -1) {
2209 code = ServerInitResidencyConnection();
2213 "ServerInitResidencyConnection failed " "with code %d\n",
2218 code = rs_GetResidencySummary(ServerRequestorId, &rsnlist);
2221 fprintf(stderr, "rs_GetResidencySummary failed " "with code %d\n",
2230 * For a given residency (as specified in the vnode),
2231 * find out it's device tag number, either via the rsserver
2232 * or via the command line.
2235 if (rscmdlineinfo[rsindex].DeviceTag != -1) {
2236 DeviceTag = rscmdlineinfo[rsindex].DeviceTag;
2239 for (i = 0, found = 0; (i < rsnlist.rsaccessinfoList_len) && (!found);
2241 if (rsnlist.rsaccessinfoList_val[i].id.residency ==
2242 VLkp_Residencies(vnode)) {
2244 DeviceTag = rsnlist.rsaccessinfoList_val[i].devicetagnumber;
2252 "Unable to find residency %d in "
2253 "rsserver database, aborting\n", VLkp_Residencies(vnode));
2258 * Okay, now we've got the DeviceTag ... which we can use to
2259 * lookup the on-disk configuration information (which we
2260 * assume is locally stored). We also need the DeviceTag to
2261 * print out which partition we're using (but that comes later).
2263 * We lookup the on-disk configuration information by calling
2264 * Ufs_GetFSInfo() to get the configuration information on the
2265 * filesystems specified by the given DeviceTag.
2267 * Before we call Ufs_GetFSInfo, check the command-line cache;
2268 * if we got something via the command-line, don't go to disk.
2271 if (rscmdlineinfo[rsindex].FSType == -1
2272 && Ufs_GetFSInfo(&FSInfo, DeviceTag)) {
2275 "Ufs_GetFSInfo failed for DeviceTag "
2276 "%d, Residency %d\n", DeviceTag, VLkp_Residencies(vnode));
2281 * The FSInfo structure has the last two things we need: the
2282 * FSType (ufs, slowufs, etc etc), and the usage algorithm (which
2283 * ends up being how many directories are being used on the
2284 * residency filesystem).
2286 * With these last two parameters, use routines stolen from
2287 * ufsname to generate the filename.
2289 * (Actually, I lied - we also need the "Size" parameter, which
2290 * we can also get from FSInfo);
2293 if (rscmdlineinfo[rsindex].FSType != -1) {
2294 FSType = rscmdlineinfo[rsindex].FSType;
2295 Algorithm = rscmdlineinfo[rsindex].Algorithm;
2296 Size = rscmdlineinfo[rsindex].Size;
2298 FSType = FSInfo->FileSystems_u.UfsInterface.FSType;
2299 Algorithm = FSInfo->FileSystems_u.UfsInterface.Algorithm;
2300 if (FSInfo->FileSystems_u.UfsInterface.Directories[1] == 0)
2302 else if (FSInfo->FileSystems_u.UfsInterface.Directories[1] == 16)
2304 else if (FSInfo->FileSystems_u.UfsInterface.Directories[1] == 256)
2308 fprintf(stderr, "Unknown directory size %d, " "aborting\n",
2309 FSInfo->FileSystems_u.UfsInterface.Directories[1]);
2315 * First, generate our mount point from the DeviceTag and
2319 DEVICETAGNUMBERTOMOUNTPOINT(MountPoint, DeviceTag, FSType);
2322 * Then, generate the "level" (directory bitmasks) from the
2323 * file tags, size, and algorithm
2326 UfsTagsToLevel(VLkp_FileTag1(vnode), VLkp_FileTag2(vnode), Algorithm,
2327 Size, Level, VLkp_ParentVnodeId(vnode),
2328 VLkp_ParentUniquifierId(vnode));
2331 * Finally, take the above information and generate the
2332 * corresponding filename (this macro ends up being a
2336 TAGSTONAME(FileName, MountPoint, Level, Directories[Size][1],
2337 vol->parentId, VLkp_ParentVnodeId(vnode),
2338 VLkp_ParentUniquifierId(vnode), Algorithm);
2340 fprintf(f, "%s\n", FileName);
2347 * Read a 16 bit integer in network order
2351 ReadInt16(FILE * f, unsigned short *s)
2355 if (fread((void *)&in, sizeof(in), 1, f) != 1) {
2357 fprintf(stderr, "ReadInt16 failed!\n");
2368 * Read a 32 bit integer in network order
2372 ReadInt32(FILE * f, unsigned int *i)
2376 if (fread((void *)&in, sizeof(in), 1, f) != 1) {
2378 fprintf(stderr, "ReadInt32 failed!\n");
2382 *i = ntohl((unsigned long)in);
2388 * Read a string from a dump file
2392 ReadString(FILE * f, char *string, int maxlen)
2397 if ((*string++ = getc(f)) == 0)
2402 * I'm not sure what the _hell_ this is supposed to do ...
2403 * but it was in the original dump code
2407 while ((c = getc(f)) && c != EOF);
2415 ReadByteString(FILE * f, void *s, int size)
2417 unsigned char *c = (unsigned char *)s;
2426 * The directory hashing algorithm used by AFS
2430 DirHash(char *string)
2432 /* Hash a string to a number between 0 and NHASHENT. */
2433 register unsigned char tc;
2437 while ((tc = (*string++)) != '\0') {
2441 tval = hval & (NHASHENT - 1);
2442 #ifdef AFS_CRAY_ENV /* actually, any > 32 bit environment */
2445 else if (hval & 0x80000000)
2446 tval = NHASHENT - tval;
2447 #else /* AFS_CRAY_ENV */
2451 tval = NHASHENT - tval;
2452 #endif /* AFS_CRAY_ENV */
2458 * Sigh, we need this for the AFS libraries
2462 LogErrors(int level, char *a, char *b, char *c, char *d, char *e, char *f,
2463 char *g, char *h, char *i, char *j, char *k)
2466 fprintf(stderr, a, b, c, d, e, f, g, h, i, j, k);
2472 * These are routines taken from AFS libraries and programs. Most of
2473 * them are from ufsname.c, but a few are from the dir library (the dir
2474 * library has a bunch of hidden dependancies, so it's not suitable to
2475 * include it outright).
2478 UfsEntropiesToTags(HighEntropy, LowEntropy, Algorithm, FileTag1, FileTag2)
2479 uint32_t HighEntropy;
2480 uint32_t LowEntropy;
2487 if ((Algorithm > UFS_ALGORITHMS) || (Algorithm <= 0))
2491 for (i = 0; i < 32; ++i) {
2492 if (UfsEntropy[Algorithm - 1][i] < 32)
2494 ((HighEntropy & (1 << i)) ==
2495 0) ? 0 : 1 << UfsEntropy[Algorithm - 1][i];
2498 ((HighEntropy & (1 << i)) ==
2499 0) ? 0 : 1 << (UfsEntropy[Algorithm - 1][i] - 32);
2501 for (i = 32; i < 64; ++i) {
2502 if (UfsEntropy[Algorithm - 1][i] < 32)
2504 ((LowEntropy & (1 << (i - 32))) ==
2505 0) ? 0 : 1 << UfsEntropy[Algorithm - 1][i];
2508 ((LowEntropy & (1 << (i - 32))) ==
2509 0) ? 0 : 1 << (UfsEntropy[Algorithm - 1][i] - 32);
2515 UfsTagsToHighEntropy(FileTag1, FileTag2, Algorithm)
2524 for (i = 0; i < 32; ++i) {
2525 if (UfsEntropy[Algorithm - 1][i] < 32)
2526 Value |= ((FileTag1 & (1 << UfsEntropy[Algorithm - 1][i]))
2530 ((FileTag2 & (1 << (UfsEntropy[Algorithm - 1][i] - 32))) ==
2537 UfsTagsToLowEntropy(FileTag1, FileTag2, Algorithm)
2546 for (i = 32; i < 64; ++i) {
2547 if (UfsEntropy[Algorithm - 1][i] < 32)
2548 Value |= ((FileTag1 & (1 << UfsEntropy[Algorithm - 1][i]))
2549 == 0) ? 0 : 1 << (i - 32);
2552 ((FileTag2 & (1 << (UfsEntropy[Algorithm - 1][i] - 32))) ==
2553 0) ? 0 : 1 << (i - 32);
2558 UfsTagsToLevel(FileTag1, FileTag2, Algorithm, Size, Sections, vnode,
2564 uint32_t Sections[4];
2566 uint32_t Uniquifier;
2568 uint32_t HighEntropy;
2569 uint32_t LowEntropy;
2571 switch (Algorithm) {
2573 LowEntropy = UfsTagsToLowEntropy(FileTag1, FileTag2, Algorithm);
2574 HighEntropy = UfsTagsToHighEntropy(FileTag1, FileTag2, Algorithm);
2575 Sections[0] = HighEntropy % Directories[Size][0];
2576 HighEntropy /= Directories[Size][0];
2577 if (Directories[Size][1]) {
2578 Sections[1] = HighEntropy % Directories[Size][1];
2579 HighEntropy /= Directories[Size][1];
2580 Sections[2] = HighEntropy;
2581 Sections[3] = LowEntropy;
2583 Sections[1] = HighEntropy;
2584 Sections[2] = LowEntropy;
2588 Sections[0] = FileTag1 & 0xff;
2589 if (Directories[Size][1]) {
2590 Sections[1] = Uniquifier & 0xff;
2591 if (Directories[Size][1] == 16)
2593 Sections[2] = FileTag1;
2594 Sections[3] = FileTag2;
2596 Sections[1] = FileTag1;
2597 Sections[2] = FileTag2;
2601 Sections[0] = FileTag1 & 0xff;
2602 if (Directories[Size][1]) {
2603 Sections[1] = (vnode >> 1) & 0xff;
2604 if (Directories[Size][1] == 16)
2606 Sections[2] = FileTag1;
2607 Sections[3] = FileTag2;
2609 Sections[1] = FileTag1;
2610 Sections[2] = FileTag2;
2614 fprintf(stderr, "UfsTagsToLevel: bad algorithm %lu!\n", Algorithm);
2620 #include <afs/afscbdummies.h>
2621 #endif /* RESIDENCY */