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.
65 #include <sys/types.h>
66 #include <sys/param.h>
67 #include <netinet/in.h>
76 #include <afs/param.h>
77 #include <afs/afsint.h>
80 #if !defined(PRE_AFS_36) && !defined(RESIDENCY)
81 #include <afs/ihandle.h>
82 #endif /* !defined(PRE_AFS_36) && !defined(RESIDENCY) */
83 #include <afs/vnode.h>
84 #include <afs/volume.h>
87 #include <afs/rsdefs.h>
88 #include <afs/remioint.h>
89 #endif /* RESIDENCY */
94 * Sigh. Linux blows it again
102 * Stuff that is in private AFS header files, unfortunately
105 #define DUMPVERSION 1
106 #define DUMPENDMAGIC 0x3A214B6E
107 #define DUMPBEGINMAGIC 0xB3A11322
108 #define D_DUMPHEADER 1
109 #define D_VOLUMEHEADER 2
114 #define MAXDUMPTIMES 50
119 char volumeName[VNAMESIZE];
120 int nDumpTimes; /* Number of pairs */
123 } dumpTimes[MAXDUMPTIMES];
127 * Our command-line arguments
132 int Algorithm; /* Conversion algorithm */
133 int Size; /* Directory hierarchy size */
134 int FSType; /* File system type */
135 int DeviceTag; /* Device Tag */
136 } rscmdlineinfo[RS_MAXRESIDENCIES];
139 * This stuff comes from ufsname.c (which itself takes it from
143 /* There is an assumption that all of the prefixes will have exactly one '/' */
144 static char *Ufs_Prefixes[] = { "/ufs", "/slowufs", "/cdmf", "/sdmf" };
146 #define MAX_ITERATIONS 10
147 #define UFS_SUMMARYTREENAME "Summaries"
148 #define UFS_STAGINGTREENAME "Staging"
149 #define UFS_VOLUMEHEADERTREENAME "VolHeaders"
150 #define UFS_VOLUMETREENAME "Volumes"
151 #define UFS_ALGORITHMBASE 'A'
152 #define UFS_MOUNTPOINTBASE 'a'
153 #define UFS_ALGORITHMS 3
154 #define UFS_LINK_MAX 64 /* Arbitrary. */
155 #define HARD_LINKED_FILE -2
156 #define TAGSTONAME(FileName, MountPoint, Sections, Level1, RWVolume, Vnode, Uniquifier, Algorithm) \
159 sprintf(FileName,"%s/%lu/%lu/%c%lu.%lu.%lu.%lu.%lu", MountPoint, \
160 (Sections)[0], (Sections)[1], UFS_ALGORITHMBASE + Algorithm, \
161 (Sections)[2], (Sections)[3], RWVolume, Vnode, Uniquifier); \
163 sprintf(FileName,"%s/%lu/%c%lu.%lu.%lu.%lu.%lu", MountPoint, \
164 (Sections)[0], UFS_ALGORITHMBASE + Algorithm, \
165 (Sections)[1], (Sections)[2], RWVolume, Vnode, Uniquifier); \
167 #define TAGSTOSTAGINGNAME(FileName, MountPoint, RWVolume, Vnode, Uniquifier) \
168 sprintf(FileName,"%s/%s/%lu.%lu.%lu", MountPoint, \
169 UFS_STAGINGTREENAME, RWVolume, Vnode, Uniquifier)
170 #define TAGSTOVOLUMEHEADERNAME(FileName, MountPoint, FileTag1, FileTag2) \
171 sprintf(FileName,"%s/%s/%lu", MountPoint, UFS_VOLUMEHEADERTREENAME, \
173 #define TAGSTOVOLUMEINFONAME(FileName, MountPoint, FileTag1, FileTag2) \
174 sprintf(FileName,"%s/%s/%lu/%lu", MountPoint, \
175 UFS_VOLUMETREENAME, FileTag2, FileTag1)
176 #define TAGSTOVOLUMENAME(FileName, MountPoint, FileTag1, FileTag2, RWVolume) \
177 sprintf(FileName,"%s/%s/%lu/%lu.%lu", MountPoint, \
178 UFS_VOLUMETREENAME, FileTag2, FileTag1, RWVolume)
179 #define TAGSTOSUMMARYNAME(FileName, MountPoint, FileTag1, FileTag2, SummaryRequestor, Residency) \
180 sprintf(FileName,"%s/%s/%lu.%lu.%lu.%lu", MountPoint, \
181 UFS_SUMMARYTREENAME, FileTag1, FileTag2, SummaryRequestor, \
183 #define DEVICETAGNUMBERTOMOUNTPOINT(MountPoint, DeviceTagNumber, FSType) \
184 sprintf(MountPoint,"%s%c", Ufs_Prefixes[FSType], UFS_MOUNTPOINTBASE + \
186 #define MOUNTPOINTTODEVICETAGNUMBER(MountPoint) \
187 MountPoint[strlen(MountPoint) - 1] - UFS_MOUNTPOINTBASE
188 #define DEVICETAGNUMBERTOVOLUMEHEADERTREE(TreeName, MountPoint) \
189 sprintf(TreeName,"%s/%s", MountPoint, UFS_VOLUMEHEADERTREENAME)
190 #define UFS_RESIDENCIES_FILE "Residencies"
192 /* We don't ever want to map to uid/gid -1. fchown() takes that as a
193 don't change flag. We know however that volume number range from
194 0x2000000 to 0x20FFFFFF (see VAllocateVolumeId() in vol/vutil.c)
195 so we will use that to insure that -1 never appears. */
196 #define RWVolumeToUid(RWVolume) ((RWVolume >> 12) & 0xFFFF)
197 #define RWVolumeToGid(RWVolume) ((RWVolume & 0xFFF) | \
198 (((RWVolume >> 28) & 0xF) << 12))
199 #define UidGidToRWVolume(Uid, Gid) ((Gid & 0xFFF) | ((Uid & 0xFFFF) << 12) | \
200 ((Gid & 0xF000) << 16))
203 /* These routines generate a file name to correspond to the given tag
206 /* The following entropy array contains the order of bits from highest entropy
207 to lowest in the numbers FileTag1 and FileTag2. Bit numbers 32 and above
208 correspond to FileTag2. This ordering was determined by examining all read-
209 write volumes in the psc.edu cell. */
210 char UfsEntropy[1][64] = {
211 {1, 2, 3, 4, 33, 5, 6, 7, 44, 45, 46, 36, 8, 34, 42, 35,
212 9, 40, 38, 32, 43, 10, 39, 37, 11, 41, 12, 13, 14, 0,
213 15, 16, 61, 17, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51,
214 50, 49, 48, 47, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22,
215 21, 20, 19, 18, 62, 63},
218 uint32_t Directories[3][2] = { {256, 0}, {256, 16}, {256, 256}, };
219 #endif /* RESIDENCY */
221 static int verbose = 0;
222 static int numNoDirData = 0;
223 static int termsize = 0;
226 extern resid ServerRequestorId;
227 #endif /* RESIDENCY */
230 * We use this structure to hold vnode data in our hash table.
231 * It's indexed by vnode number.
235 struct VnodeDiskObject *vnode; /* A pointer to the disk vnode */
236 int vnodeNumber; /* The vnode number */
237 long dumpdata; /* File offset of dump data (if
239 unsigned char *filedata; /* A pointer to the actual file
240 * data itself (if available) */
241 unsigned int datalength; /* The length of the data */
245 * This contains the current location when we're doing a scan of a
250 int hashbucket; /* Current hash bucket */
251 int entry; /* Entry within hash bucket */
255 * Arrays to hold vnode data
258 struct vnodeData **LargeVnodeIndex;
259 struct vnodeData **SmallVnodeIndex;
260 int numLargeVnodes = 0;
261 int numSmallVnodes = 0;
264 * Crap for the libraries
267 int ShutdownInProgress = 0;
270 * Our local function prototypes
273 static int ReadDumpHeader(FILE *, struct DumpHeader *);
274 static int ReadVolumeHeader(FILE *, VolumeDiskData *);
275 static int ScanVnodes(FILE *, VolumeDiskData *, int);
276 static int DumpVnodeFile(FILE *, struct VnodeDiskObject *, VolumeDiskData *);
277 static struct vnodeData *InsertVnode(unsigned int, struct VnodeDiskObject *);
278 static struct vnodeData *GetVnode(unsigned int);
279 static int CompareVnode(const void *, const void *);
280 static void InteractiveRestore(FILE *, VolumeDiskData *);
281 static void DirectoryList(int, char **, struct vnodeData *, VolumeDiskData *);
282 static void DirListInternal(struct vnodeData *, char *[], int, int, int, int,
283 int, int, VolumeDiskData *, char *);
284 static int CompareDirEntry(const void *, const void *);
285 static struct vnodeData *ChangeDirectory(int, char **, struct vnodeData *);
286 static void CopyFile(int, char **, struct vnodeData *, FILE *);
287 static void CopyVnode(int, char **, FILE *);
288 static void DumpAllFiles(int, char **, struct vnodeData *, VolumeDiskData *);
289 static void DumpAllResidencies(FILE *, struct vnodeData *, VolumeDiskData *);
290 static struct vnodeData *FindFile(struct vnodeData *, char *);
291 static void ResetDirCursor(struct DirCursor *, struct vnodeData *);
292 static struct DirEntry *ReadNextDir(struct DirCursor *, struct vnodeData *);
293 static void MakeArgv(char *, int *, char ***);
294 static char *GetToken(char *, char **, char *, char *[]);
295 static int ReadInt16(FILE *, uint16_t *);
296 static int ReadInt32(FILE *, uint32_t *);
297 static int ReadString(FILE *, char *, int);
298 static int ReadByteString(FILE *, void *, int);
301 main(int argc, char *argv[])
303 int c, errflg = 0, dumpvnodes = 0, force = 0, inode = 0;
305 struct DumpHeader dheader;
308 int Res, Arg1, Arg2, Arg3, i;
314 for (i = 0; i < RS_MAXRESIDENCIES; i++) {
315 rscmdlineinfo[i].Algorithm = -1;
316 rscmdlineinfo[i].Size = -1;
317 rscmdlineinfo[i].DeviceTag = -1;
318 rscmdlineinfo[i].FSType = -1;
320 #endif /* RESIDENCY */
323 * Sigh, this is dumb, but we need the terminal window size
324 * to do intelligent things with "ls" later on.
327 if (isatty(STDOUT_FILENO)) {
328 if ((p = getenv("COLUMNS")) != NULL)
330 else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0
332 termsize = win.ws_col;
335 while ((c = getopt(argc, argv, "difr:t:v")) != EOF)
339 if (sscanf(optarg, "%d/%d", &Res, &Arg1) != 2) {
344 if (1 << (ffs(Res) - 1) != Res) {
345 fprintf(stderr, "Invalid residency %d\n", Res);
350 if (Arg1 < 0 || Arg1 > 26) {
351 fprintf(stderr, "Invalid device tag: %d\n", Arg1);
355 rscmdlineinfo[ffs(Res) - 1].DeviceTag = Arg1;
356 #else /* RESIDENCY */
357 fprintf(stderr, "-t not supported in non-MRAFS " "dumptool.\n");
359 #endif /* RESIDENCY */
364 if (sscanf(optarg, "%d/%d/%d/%d", &Res, &Arg1, &Arg2, &Arg3) != 4) {
369 if (Arg1 < 0 || Arg1 > 3) {
370 fprintf(stderr, "Invalid fstype: %d\n", Arg1);
375 if (Arg2 < 0 || Arg2 > 2) {
376 fprintf(stderr, "Invalid size: %d\n", Arg2);
381 if (Arg3 <= 0 || Arg3 > UFS_ALGORITHMS) {
382 fprintf(stderr, "Invalid algorithm: %d\n", Arg3);
386 rscmdlineinfo[ffs(Res) - 1].FSType = Arg1;
387 rscmdlineinfo[ffs(Res) - 1].Size = Arg2;
388 rscmdlineinfo[ffs(Res) - 1].Algorithm = Arg3;
389 #else /* RESIDENCY */
390 fprintf(stderr, "-r not supported in non-MRAFS " "dumptool.\n");
392 #endif /* RESIDENCY */
397 #else /* RESIDENCY */
398 fprintf(stderr, "-d not supported in non-MRAFS " "dumptool.\n");
400 #endif /* RESIDENCY */
416 if (errflg || optind == argc) {
417 fprintf(stderr, "Usage: %s\n\t[-v] [-f]\n\t"
419 "[-t Residency/Tag]\n\t"
420 "[-r Residency/Type/Size/Algorithm]\n\t"
421 "[-d] filename [file_in_dump [file in dump ...]]\n",
422 #else /* RESIDENCY */
424 #endif /* RESIDENCY */
430 * Try opening the dump file
433 if ((f = fopen(argv[optind], "rb")) == NULL) {
434 fprintf(stderr, "open of dumpfile %s failed: %s\n", argv[optind],
439 if (ReadDumpHeader(f, &dheader)) {
440 fprintf(stderr, "Failed to read dump header!\n");
445 printf("Dump is for volume %lu (%s)\n", dheader.volumeId,
448 if (getc(f) != D_VOLUMEHEADER) {
449 fprintf(stderr, "Volume header is missing from dump, aborting\n");
453 if (ReadVolumeHeader(f, &vol)) {
454 fprintf(stderr, "Unable to read volume header\n");
459 printf("Volume information:\n");
460 printf("\tid = %lu\n", vol.id);
461 printf("\tparent id = %lu\n", vol.parentId);
462 printf("\tname = %s\n", vol.name);
467 printf(" inService");
470 if (vol.needsSalvaged)
471 printf(" needsSalvaged");
473 printf("\tuniquifier = %lu\n", vol.uniquifier);
474 printf("\tCreation date = %s", ctime((time_t *) & vol.creationDate));
475 printf("\tLast access date = %s", ctime((time_t *) & vol.accessDate));
476 printf("\tLast update date = %s", ctime((time_t *) & vol.updateDate));
477 printf("\tVolume owner = %lu\n", vol.owner);
481 printf("Scanning vnodes (this may take a while)\n");
484 * We need to do two vnode scans; one to get the number of
485 * vnodes, the other to actually build the index.
490 if (ScanVnodes(f, &vol, 1)) {
491 fprintf(stderr, "First vnode scan failed, aborting\n");
495 fseek(f, offset, SEEK_SET);
497 if (ScanVnodes(f, &vol, 0)) {
498 fprintf(stderr, "Second vnode scan failed, aborting\n");
502 if (getc(f) != D_DUMPEND || ReadInt32(f, &magic) || magic != DUMPENDMAGIC) {
503 fprintf(stderr, "Couldn't find dump postamble, ");
505 fprintf(stderr, "aborting (use -f to override)\n");
508 fprintf(stderr, "continuing anyway\n");
509 fprintf(stderr, "WARNING: Dump may not be complete!\n");
514 * If we wanted to simply dump all vnodes, do it now
519 struct vnodeData *vdata;
521 for (i = 0; i < numLargeVnodes; i++) {
523 vdata = LargeVnodeIndex[i];
525 if (vdata->vnode->type == vFidLookup)
526 if (DumpVnodeFile(stdout, vdata->vnode, &vol)) {
527 fprintf(stderr, "DumpVnodeFile failed, " "aborting\n");
532 for (i = 0; i < numSmallVnodes; i++) {
534 vdata = SmallVnodeIndex[i];
536 if (vdata->vnode->type == vFidLookup)
537 if (DumpVnodeFile(stdout, vdata->vnode, &vol)) {
538 fprintf(stderr, "DumpVnodeFile failed, " "aborting\n");
544 #endif /* RESIDENCY */
547 * Dump out all filenames with their corresponding FID
550 struct vnodeData *rootvdata;
552 if ((rootvdata = GetVnode(1)) == NULL) {
554 "Can't get vnode data for root " "vnode! Aborting\n");
558 DirListInternal(rootvdata, NULL, 0, 0, 1, 0, 1, 0, &vol, "");
560 } else if (argc > optind + 1) {
563 * Dump out residencies of files given on the command line.
566 struct vnodeData *vdata, *rootvdata;
568 if ((rootvdata = GetVnode(1)) == NULL) {
570 "Can't get vnode data for root " "vnode! Aborting\n");
574 for (i = optind + 1; i < argc; i++) {
576 if ((vdata = FindFile(rootvdata, argv[i])) == NULL) {
577 fprintf(stderr, "Skipping file %s\n", argv[i]);
582 printf("Residency locations for %s:\n", argv[i]);
584 while (vdata->vnode->NextVnodeId != 0) {
586 vdata = GetVnode(vdata->vnode->NextVnodeId);
590 "We had a vnode chain " "pointer to a vnode that "
591 "doesn't exist, aborting!\n");
594 if (vdata->vnode->type == vFidLookup)
595 DumpVnodeFile(stdout, vdata->vnode, &vol);
598 #else /* RESIDENCY */
599 fprintf(stderr, "Extra arguments after dump filename: %s\n",
602 #endif /* RESIDENCY */
605 * Perform an interactive restore
608 InteractiveRestore(f, &vol);
615 * Read the dump header, which is at the beginning of every dump
619 ReadDumpHeader(FILE * f, struct DumpHeader *header)
624 if (getc(f) != D_DUMPHEADER || ReadInt32(f, &magic)
625 || ReadInt32(f, (unsigned int *)
626 &header->version) || magic != DUMPBEGINMAGIC) {
628 fprintf(stderr, "Couldn't find dump magic numbers\n");
632 header->volumeId = 0;
633 header->nDumpTimes = 0;
635 while ((tag = getc(f)) > D_MAX && tag != EOF) {
636 unsigned short length;
639 if (ReadInt32(f, &header->volumeId)) {
641 fprintf(stderr, "Failed to read " "volumeId\n");
646 if (ReadString(f, header->volumeName, sizeof(header->volumeName))) {
648 fprintf(stderr, "Failed to read " "volume name\n");
653 if (ReadInt16(f, &length)) {
656 "Failed to read " "dump time array length\n");
659 header->nDumpTimes = (length >> 1);
660 for (i = 0; i < header->nDumpTimes; i++)
661 if (ReadInt32(f, (unsigned int *)
662 &header->dumpTimes[i].from)
663 || ReadInt32(f, (unsigned int *)
664 &header->dumpTimes[i].to)) {
666 fprintf(stderr, "Failed to " "read dump times\n");
672 fprintf(stderr, "Unknown dump tag \"%c\"\n", tag);
677 if (!header->volumeId || !header->nDumpTimes) {
680 "We didn't get a volume Id or " "dump times listing\n");
689 * Read the volume header; this is the information stored in VolumeDiskData.
691 * I'm not sure we need all of this, but read it in just in case.
695 ReadVolumeHeader(FILE * f, VolumeDiskData * vol)
699 memset((void *)vol, 0, sizeof(*vol));
701 while ((tag = getc(f)) > D_MAX && tag != EOF) {
704 if (ReadInt32(f, &vol->id))
708 if (ReadInt32(f, &trash))
712 if (ReadString(f, vol->name, sizeof(vol->name)))
716 vol->inService = getc(f);
719 vol->blessed = getc(f);
722 if (ReadInt32(f, &vol->uniquifier))
729 if (ReadInt32(f, &vol->parentId))
733 if (ReadInt32(f, &vol->cloneId))
737 if (ReadInt32(f, (uint32_t *) & vol->maxquota))
741 if (ReadInt32(f, (uint32_t *) & vol->minquota))
745 if (ReadInt32(f, (uint32_t *) & vol->diskused))
749 if (ReadInt32(f, (uint32_t *) & vol->filecount))
753 if (ReadInt32(f, &vol->accountNumber))
757 if (ReadInt32(f, &vol->owner))
761 if (ReadInt32(f, &vol->creationDate))
765 if (ReadInt32(f, &vol->accessDate))
769 if (ReadInt32(f, &vol->updateDate))
773 if (ReadInt32(f, &vol->expirationDate))
777 if (ReadInt32(f, &vol->backupDate))
782 (f, vol->offlineMessage, sizeof(vol->offlineMessage)))
786 if (ReadString(f, (char *)vol->stat_reads, VMSGSIZE))
790 unsigned short length;
793 if (ReadInt16(f, &length))
795 for (i = 0; i < length; i++) {
796 if (ReadInt32(f, &data))
798 if (i < sizeof(vol->weekUse) / sizeof(vol->weekUse[0]))
799 vol->weekUse[i] = data;
804 if (ReadInt32(f, &vol->dayUseDate))
808 if (ReadInt32(f, (uint32_t *) & vol->dayUse))
813 unsigned short length;
817 if (ReadInt16(f, &length))
819 for (i = 0; i < length; i++) {
820 if (ReadInt32(f, &data))
823 sizeof(vol->DesiredInfo.DesiredResidencyWords) /
824 sizeof(vol->DesiredInfo.DesiredResidencyWords[0]))
825 vol->DesiredInfo.DesiredResidencyWords[i] = data;
830 unsigned short length;
834 if (ReadInt16(f, &length))
836 for (i = 0; i < length; i++) {
837 if (ReadInt32(f, &data))
840 sizeof(vol->UnDesiredInfo.UnDesiredResidencyWords) /
841 sizeof(vol->UnDesiredInfo.UnDesiredResidencyWords[0]))
842 vol->UnDesiredInfo.UnDesiredResidencyWords[i] = data;
849 fprintf(stderr, "Unknown dump tag \"%c\"\n", tag);
859 * Scan all our vnode entries, and build indexing information.
863 ScanVnodes(FILE * f, VolumeDiskData * vol, int sizescan)
867 int numFileVnodes = 0;
868 int numDirVnodes = 0;
869 unsigned char buf[SIZEOF_LARGEDISKVNODE];
870 struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)buf;
871 long offset, oldoffset;
872 struct vnodeData *vdata;
877 while (tag == D_VNODE) {
884 if (ReadInt32(f, (uint32_t *) & vnodeNumber)) {
885 fprintf(stderr, "failed int32 for 'vnodenum'\n");
889 if (ReadInt32(f, &vnode->uniquifier)) {
890 fprintf(stderr, "failed int32 for 'uniquifier'\n");
894 if (verbose > 1 && !sizescan)
895 printf("Got vnode %d\n", vnodeNumber);
897 while ((tag = getc(f)) > D_MAX && tag != EOF)
900 vnode->type = (VnodeType) getc(f);
905 if (ReadInt16(f, &tmp)) {
906 fprintf(stderr, "failed int16 for 'l'\n");
909 vnode->linkCount = tmp;
913 if (ReadInt32(f, &vnode->dataVersion)) {
914 fprintf(stderr, "failed int32 for 'v'\n");
919 if (ReadInt32(f, (uint32_t *) & vnode->unixModifyTime)) {
920 fprintf(stderr, "failed int32 for 'm'\n");
925 if (ReadInt32(f, (uint32_t *) & vnode->serverModifyTime)) {
926 fprintf(stderr, "failed int32 for 's'\n");
931 if (ReadInt32(f, &vnode->author)) {
932 fprintf(stderr, "failed int32 for 'a'\n");
937 if (ReadInt32(f, &vnode->owner)) {
938 fprintf(stderr, "failed int32 for 'o'\n");
943 if (ReadInt32(f, (uint32_t *) & vnode->group)) {
944 fprintf(stderr, "failed int32 for 'g'\n");
949 unsigned short modeBits;
950 if (ReadInt16(f, &modeBits))
952 vnode->modeBits = modeBits;
956 if (ReadInt32(f, &vnode->parent)) {
957 fprintf(stderr, "failed int32 for 'p'\n");
963 if (ReadInt32(f, &vnode->NextVnodeId)) {
964 fprintf(stderr, "failed int32 for 'N'\n");
969 if (ReadInt32(f, &VLkp_Residencies(vnode))) {
970 fprintf(stderr, "failed int32 for 'R'\n");
976 if (ReadInt32(f, &vnode->length)) {
977 fprintf(stderr, "failed int32 for 'S'\n");
982 if (ReadInt32(f, (uint32_t *) & vnode->vn_ino_lo))
987 (f, (void *)VVnodeDiskACL(vnode), VAclDiskSize(vnode))) {
988 fprintf(stderr, "failed readbystring for 'A'\n");
992 acl_NtohACL(VVnodeDiskACL(vnode));
997 if (ReadInt32(f, &vnode->length_hi)) {
998 fprintf(stderr, "failed int32 for 'h'\n");
1003 if (verbose > 1 && !sizescan)
1004 printf("We have file data!\n");
1005 if (ReadInt32(f, &length)) {
1006 fprintf(stderr, "failed int32 for 'f'\n");
1009 vnode->length = length;
1011 fseek(f, length, SEEK_CUR);
1015 fprintf(stderr, "Unknown dump tag \"%c\"\n", tag);
1020 * If we're doing an incremental restore, then vnodes
1021 * will be listed in the dump, but won't contain any
1022 * vnode information at all (I don't know why they're
1023 * included _at all_). If we get one of these vnodes, then
1024 * just skip it (because we can't do anything with it.
1027 if (vnode->type == -1)
1031 if (verbose > 1 && vnode->type == vFidLookup && !sizescan) {
1033 ("This is an auxiliary vnode (lookup) for vnode %d, residency %d\n",
1034 VLkp_ParentVnodeId(vnode), VLkp_Residencies(vnode));
1035 if (DumpVnodeFile(stdout, vnode, vol))
1039 if (verbose > 1 && vnode->type == vAccessHistory && !sizescan)
1040 printf("This is an auxiliary vnode (history) for vnode %d\n",
1041 VLkp_ParentVnodeId(vnode));
1044 if (vnode->type == vDirectory)
1050 * We know now all we would ever know about the vnode;
1051 * insert it into our hash table (but only if we're not
1052 * doing a vnode scan).
1057 vdata = InsertVnode(vnodeNumber, vnode);
1059 if (vdata == NULL) {
1062 "Failed to insert " "vnode into hash table");
1066 vdata->dumpdata = offset;
1067 vdata->datalength = length;
1070 * Save directory data, since we'll need it later.
1073 if (vnode->type == vDirectory && length) {
1075 vdata->filedata = malloc(length);
1077 if (!vdata->filedata) {
1080 "Unable to " "allocate space for "
1081 "file data (%d)\n", length);
1085 oldoffset = ftell(f);
1086 fseek(f, offset, SEEK_SET);
1088 if (fread(vdata->filedata, length, 1, f) != 1) {
1090 fprintf(stderr, "Unable to " "read in file data!\n");
1094 fseek(f, oldoffset, SEEK_SET);
1095 } else if (vnode->type == vDirectory)
1097 * Warn the user we may not have all directory
1108 numLargeVnodes = numDirVnodes;
1109 numSmallVnodes = numFileVnodes;
1112 LargeVnodeIndex = (struct vnodeData **)
1113 malloc(numDirVnodes * sizeof(struct vnodeData));
1114 SmallVnodeIndex = (struct vnodeData **)
1115 malloc(numFileVnodes * sizeof(struct vnodeData));
1117 if (LargeVnodeIndex == NULL || SmallVnodeIndex == NULL) {
1120 "Unable to allocate space " "for vnode tables\n");
1126 fprintf(stderr, "%s vnode scan completed\n",
1127 sizescan ? "Primary" : "Secondary");
1133 * Perform an interactive restore
1135 * Parsing the directory information is a pain, but other than that
1136 * we just use the other tools we already have in here.
1140 InteractiveRestore(FILE * f, VolumeDiskData * vol)
1142 struct vnodeData *vdatacwd; /* Vnode data for our current dir */
1148 * Let's see if we can at least get the data for our root directory.
1149 * If we can't, there's no way we can do an interactive restore.
1152 if ((vdatacwd = GetVnode(1)) == NULL) {
1153 fprintf(stderr, "No entry for our root vnode! Aborting\n");
1157 if (!vdatacwd->filedata) {
1159 "There is no directory data for the root "
1160 "vnode (1.1). An interactive\nrestore is not "
1166 * If you're doing a selective dump correctly, then you should get all
1167 * directory vnode data. But just in case you didn't, let the user
1168 * know there may be a problem.
1173 "WARNING: %d directory vnodes had no file "
1174 "data. An interactive restore\nmay not be possible\n",
1178 while (fgets(cmdbuf, 256, stdin)) {
1180 cmdbuf[strlen(cmdbuf) - 1] = '\0';
1182 if (strlen(cmdbuf) == 0) {
1187 MakeArgv(cmdbuf, &argc, &argv);
1189 if (strcmp(argv[0], "ls") == 0) {
1190 DirectoryList(argc, argv, vdatacwd, vol);
1191 } else if (strcmp(argv[0], "cd") == 0) {
1192 struct vnodeData *newvdata;
1194 newvdata = ChangeDirectory(argc, argv, vdatacwd);
1197 vdatacwd = newvdata;
1198 } else if (strcmp(argv[0], "file") == 0) {
1199 DumpAllFiles(argc, argv, vdatacwd, vol);
1200 } else if (strcmp(argv[0], "cp") == 0) {
1201 CopyFile(argc, argv, vdatacwd, f);
1202 } else if (strcmp(argv[0], "vcp") == 0) {
1203 CopyVnode(argc, argv, f);
1204 } else if (strcmp(argv[0], "quit") == 0
1205 || strcmp(argv[0], "exit") == 0)
1207 else if (strcmp(argv[0], "?") == 0 || strcmp(argv[0], "help") == 0) {
1208 printf("Valid commands are:\n");
1209 printf("\tls\t\tList current directory\n");
1210 printf("\tcd\t\tChange current directory\n");
1211 printf("\tcp\t\tCopy file from dump\n");
1212 printf("\tvcp\t\tCopy file from dump (via vnode)\n");
1214 printf("\tfile\t\tList residency filenames\n");
1215 #endif /* RESIDENCY */
1216 printf("\tquit | exit\tExit program\n");
1217 printf("\thelp | ?\tBrief help\n");
1220 "Unknown command, \"%s\", enter "
1221 "\"help\" for a list of commands.\n", argv[0]);
1230 * Do a listing of all files in a directory. Sigh, I wish this wasn't
1233 * With the reorganizing, this is just a front-end to DirListInternal()
1237 DirectoryList(int argc, char **argv, struct vnodeData *vdata,
1238 VolumeDiskData * vol)
1240 int errflg = 0, lflag = 0, iflag = 0, Fflag = 0, sflag = 0, Rflag = 0;
1245 while ((c = getopt(argc, argv, "liFRs")) != EOF)
1267 fprintf(stderr, "Usage: %s [-liFs] filename [filename ...]\n",
1272 DirListInternal(vdata, &(argv[optind]), argc - optind, lflag, iflag,
1273 Fflag, Rflag, 1, vol, NULL);
1279 * Function that does the REAL work in terms of directory listing
1283 DirListInternal(struct vnodeData *vdata, char *pathnames[], int numpathnames,
1284 int lflag, int iflag, int Fflag, int Rflag, int verbose,
1285 VolumeDiskData * vol, char *path)
1287 struct DirEntry *ep, **eplist = NULL, **eprecurse = NULL;
1288 struct DirCursor cursor;
1289 struct vnodeData *lvdata;
1291 int i, j, numentries = 0, longestname = 0, numcols, col, numrows;
1294 if (!vdata->filedata) {
1295 fprintf(stderr, "There is no vnode data for this " "directory!\n");
1299 ResetDirCursor(&cursor, vdata);
1302 * Scan through the whole directory
1305 while ((ep = ReadNextDir(&cursor, vdata)) != NULL) {
1308 * If we didn't get any filenames on the command line,
1312 if (numpathnames == 0) {
1314 realloc(eplist, sizeof(struct DirEntry *) * ++numentries);
1315 eplist[numentries - 1] = ep;
1316 if (strlen(ep->name) > longestname)
1317 longestname = strlen(ep->name);
1319 if ((lvdata = GetVnode(ntohl(ep->fid.vnode)))
1320 && lvdata->vnode->type == vDirectory
1321 && !(strcmp(ep->name, ".") == 0
1322 || strcmp(ep->name, "..") == 0)) {
1325 sizeof(struct DirEntry *) * ++numrecurse);
1326 eprecurse[numrecurse - 1] = ep;
1331 * Do glob matching via fnmatch()
1334 for (i = 0; i < numpathnames; i++)
1335 if (fnmatch(pathnames[i], ep->name, FNM_PATHNAME) == 0) {
1338 sizeof(struct DirEntry *) * ++numentries);
1339 eplist[numentries - 1] = ep;
1340 if (strlen(ep->name) > longestname)
1341 longestname = strlen(ep->name);
1343 if ((lvdata = GetVnode(ntohl(ep->fid.vnode)))
1344 && lvdata->vnode->type == vDirectory
1345 && !(strcmp(ep->name, ".") == 0
1346 || strcmp(ep->name, "..") == 0)) {
1349 sizeof(struct DirEntry *) *
1351 eprecurse[numrecurse - 1] = ep;
1358 qsort((void *)eplist, numentries, sizeof(struct DirEntry *),
1361 if (Rflag && eprecurse)
1362 qsort((void *)eprecurse, numrecurse, sizeof(struct DirEntry *),
1365 * We don't have to do column printing if we have the -l or the -i
1366 * options. Sigh, column printing is WAY TOO FUCKING COMPLICATED!
1369 if (!lflag && !iflag) {
1377 numcols = termsize / longestname ? termsize / longestname : 1;
1378 numrows = numentries / numcols + (numentries % numcols ? 1 : 0);
1380 for (i = 0; i < numrows; i++) {
1382 while (col < numcols && (i + col * numrows) < numentries) {
1383 ep = eplist[i + col++ * numrows];
1385 if (!(lvdata = GetVnode(ntohl(ep->fid.vnode))))
1387 else if (lvdata->vnode->type == vDirectory)
1389 else if (lvdata->vnode->type == vSymlink)
1391 else if (lvdata->vnode->modeBits & 0111 != 0)
1395 printf("%s%-*c", ep->name, longestname - strlen(ep->name),
1398 printf("%-*s", longestname, ep->name);
1404 for (i = 0; i < numentries; i++)
1405 if (!(lvdata = GetVnode(ntohl(eplist[i]->fid.vnode))))
1406 printf("%d.0.0\t%s\n",
1407 vol->parentId ? vol->parentId : vol->id,
1410 printf("%d.%d.%d\t%s/%s\n", vol->id,
1411 ntohl(eplist[i]->fid.vnode),
1412 ntohl(eplist[i]->fid.vunique), path, eplist[i]->name);
1414 printf("%d.%d.%d\t%s\n", vol->id, ntohl(eplist[i]->fid.vnode),
1415 ntohl(eplist[i]->fid.vunique), eplist[i]->name);
1417 for (i = 0; i < numentries; i++)
1418 if (!(lvdata = GetVnode(ntohl(eplist[i]->fid.vnode))))
1419 printf("---------- 0 0 " "0 0 %s\n",
1422 switch (lvdata->vnode->type) {
1433 for (j = 8; j >= 0; j--) {
1434 if (lvdata->vnode->modeBits & (1 << j))
1448 printf(" %-3d %-8d %-8d %10d %s\n", lvdata->vnode->linkCount,
1449 lvdata->vnode->owner, lvdata->vnode->group,
1450 lvdata->vnode->length, eplist[i]->name);
1456 if (Rflag && eprecurse) {
1459 for (i = 0; i < numrecurse; i++) {
1461 printf("\n%s:\n", eprecurse[i]->name);
1463 lpath = malloc(strlen(path) + strlen(eprecurse[i]->name) + 2);
1465 sprintf(lpath, "%s/%s", path, eprecurse[i]->name);
1467 DirListInternal(GetVnode(ntohl(eprecurse[i]->fid.vnode)), NULL, 0,
1468 lflag, iflag, Fflag, Rflag, verbose, vol, lpath);
1484 * Directory name comparison function, used by qsort
1488 CompareDirEntry(const void *e1, const void *e2)
1490 struct DirEntry **ep1 = (struct DirEntry **)e1;
1491 struct DirEntry **ep2 = (struct DirEntry **)e2;
1493 return strcmp((*ep1)->name, (*ep2)->name);
1497 * Change a directory. Return a pointer to our new vdata structure for
1501 static struct vnodeData *
1502 ChangeDirectory(int argc, char **argv, struct vnodeData *vdatacwd)
1504 struct vnodeData *newvdatacwd;
1507 fprintf(stderr, "Usage: %s directory\n", argv[0]);
1511 if ((newvdatacwd = FindFile(vdatacwd, argv[1])) == NULL)
1514 if (newvdatacwd->vnode->type != vDirectory) {
1515 fprintf(stderr, "%s: Not a directory\n", argv[1]);
1519 if (newvdatacwd->filedata == NULL) {
1520 fprintf(stderr, "%s: No directory data found.\n", argv[1]);
1528 * Copy a file from out of the dump file
1531 #define COPYBUFSIZE 8192
1534 CopyFile(int argc, char **argv, struct vnodeData *vdatacwd, FILE * f)
1536 struct vnodeData *vdata;
1540 char buffer[COPYBUFSIZE];
1543 fprintf(stderr, "Usage: %s dumpfile destfile\n", argv[0]);
1547 if ((vdata = FindFile(vdatacwd, argv[1])) == NULL)
1550 if (vdata->dumpdata == 0) {
1551 fprintf(stderr, "File %s has no data in dump file\n", argv[1]);
1555 if ((out = fopen(argv[2], "wb")) == NULL) {
1556 fprintf(stderr, "Open of %s failed: %s\n", argv[2], strerror(errno));
1560 if (fseek(f, vdata->dumpdata, SEEK_SET)) {
1561 fprintf(stderr, "Seek failed: %s\n", strerror(errno));
1566 while (cur < vdata->datalength) {
1570 vdata->datalength ? COPYBUFSIZE : vdata->datalength - cur;
1572 ret = fread(buffer, sizeof(char), bytes, f);
1575 fprintf(stderr, "Short read (expected %d, " "got %d)\n",
1578 fprintf(stderr, "Error during read: %s\n", strerror(errno));
1583 ret = fwrite(buffer, sizeof(char), bytes, out);
1586 fprintf(stderr, "Short write (expected %d, " "got %d)\n",
1589 fprintf(stderr, "Error during write: %s\n", strerror(errno));
1601 * Copy a file from out of the dump file, by using the vnode
1605 CopyVnode(int argc, char *argv[], FILE * f)
1607 struct vnodeData *vdata;
1611 char buffer[COPYBUFSIZE];
1612 unsigned int vnode, uniquifier = 0;
1615 fprintf(stderr, "Usage: %s vnode[.uniqifier] destfile\n", argv[0]);
1619 ret = sscanf(argv[1], "%d.%d", &vnode, &uniquifier);
1622 fprintf(stderr, "Invalid file identifier: %s\n", argv[1]);
1626 if (!(vdata = GetVnode(vnode))) {
1627 fprintf(stderr, "Vnode %d not in dump file\n", vnode);
1631 if (ret == 2 && vdata->vnode->uniquifier != uniquifier) {
1633 "Specified uniquifier %d did not match "
1634 "uniquifier %d found in dump file!\n", uniquifier,
1635 vdata->vnode->uniquifier);
1639 if (vdata->dumpdata == 0) {
1640 fprintf(stderr, "File %s has no data in dump file\n", argv[1]);
1644 if ((out = fopen(argv[2], "wb")) == NULL) {
1645 fprintf(stderr, "Open of %s failed: %s\n", argv[2], strerror(errno));
1649 if (fseek(f, vdata->dumpdata, SEEK_SET)) {
1650 fprintf(stderr, "Seek failed: %s\n", strerror(errno));
1655 while (cur < vdata->datalength) {
1659 vdata->datalength ? COPYBUFSIZE : vdata->datalength - cur;
1661 ret = fread(buffer, sizeof(char), bytes, f);
1664 fprintf(stderr, "Short read (expected %d, " "got %d)\n",
1667 fprintf(stderr, "Error during read: %s\n", strerror(errno));
1672 ret = fwrite(buffer, sizeof(char), bytes, out);
1675 fprintf(stderr, "Short write (expected %d, " "got %d)\n",
1678 fprintf(stderr, "Error during write: %s\n", strerror(errno));
1690 * Dump all residency filenames associated with a file, or all files
1691 * within a directory.
1695 DumpAllFiles(int argc, char **argv, struct vnodeData *vdatacwd,
1696 VolumeDiskData * vol)
1699 struct vnodeData *vdata, *nvdata;
1700 struct DirCursor cursor;
1701 struct DirEntry *ep;
1704 int dflag = 0, fflag = 0, errflg = 0;
1708 while ((c = getopt(argc, argv, "df:")) != EOF)
1714 if ((f = fopen(optarg, "a")) == NULL) {
1715 fprintf(stderr, "Cannot open \"%s\": %s\n", optarg,
1727 if (errflg || argc == optind) {
1728 fprintf(stderr, "Usage: %s [-d] [-f filename] file " "[file ...]\n",
1735 for (i = optind; i < argc; i++) {
1737 if ((vdata = FindFile(vdatacwd, argv[i])) == NULL)
1740 if (vdata->vnode->type == vDirectory && !dflag) {
1742 ResetDirCursor(&cursor, vdata);
1744 while ((ep = ReadNextDir(&cursor, vdata)) != NULL) {
1746 if (!(nvdata = GetVnode(ntohl(ep->fid.vnode)))) {
1748 "Cannot find vnode " "entry for %s (%d)\n",
1749 ep->name, ntohl(ep->fid.vnode));
1755 printf("Residency locations for %s:\n", ep->name);
1757 if (nvdata->dumpdata)
1758 printf("Local disk (in dump " "file)\n");
1761 DumpAllResidencies(f, nvdata, vol);
1767 printf("Residency locations for %s:\n", argv[i]);
1769 if (vdata->dumpdata)
1770 printf("Local disk (in dump file)\n");
1773 DumpAllResidencies(f, vdata, vol);
1779 #else /* RESIDENCY */
1781 "The \"file\" command is not available in the non-"
1782 "MRAFS version of dumptool.\n");
1783 #endif /* RESIDENCY */
1788 * Take a vnode, traverse the vnode chain, and dump out all files on
1789 * all residencies corresponding to that parent vnode.
1794 DumpAllResidencies(FILE * f, struct vnodeData *vdata,
1795 struct VolumeDiskData *vol)
1797 unsigned int nextVnodeNum;
1799 while (nextVnodeNum = vdata->vnode->NextVnodeId) {
1800 if ((vdata = GetVnode(nextVnodeNum)) == NULL) {
1802 "We had a pointer to %lu in it's "
1803 "vnode chain, but there\nisn't a record of "
1804 "it! The dump might be corrupt.\n", nextVnodeNum);
1808 if (vdata->vnode->type == vFidLookup)
1809 DumpVnodeFile(f, vdata->vnode, vol);
1818 * Given a directory vnode and a filename, return the vnode corresponding
1819 * to the file in that directory.
1821 * We now handle pathnames with directories in them.
1824 static struct vnodeData *
1825 FindFile(struct vnodeData *vdatacwd, char *filename)
1827 struct DirHeader *dhp;
1828 struct DirEntry *ep;
1830 struct vnodeData *vdata;
1831 char *c, newstr[MAXPATHLEN];
1833 if (!vdatacwd->filedata) {
1834 fprintf(stderr, "There is no vnode data for this " "directory!\n");
1839 * If we have a "/" in here, look up the vnode data for the
1840 * directory (everything before the "/") and use that as our
1841 * current directory. We automagically handle multiple directories
1842 * by using FindFile recursively.
1845 if ((c = strrchr(filename, '/')) != NULL) {
1847 strncpy(newstr, filename, c - filename);
1848 newstr[c - filename] = '\0';
1850 if ((vdatacwd = FindFile(vdatacwd, newstr)) == NULL)
1853 if (vdatacwd->vnode->type != vDirectory) {
1854 fprintf(stderr, "%s: Not a directory\n", newstr);
1861 dhp = (struct DirHeader *)vdatacwd->filedata;
1863 i = DirHash(filename);
1865 num = ntohs(dhp->hashTable[i]);
1868 ep = (struct DirEntry *)(vdatacwd->filedata + (num * 32));
1869 if (strcmp(ep->name, filename) == 0)
1871 num = ntohs(ep->next);
1875 fprintf(stderr, "%s: No such file or directory\n", filename);
1879 if ((vdata = GetVnode(ntohl(ep->fid.vnode))) == NULL) {
1880 fprintf(stderr, "%s: No vnode information for %lu found\n", filename,
1881 ntohl(ep->fid.vnode));
1889 * Reset a structure containing the current directory scan location
1893 ResetDirCursor(struct DirCursor *cursor, struct vnodeData *vdata)
1895 struct DirHeader *dhp;
1897 cursor->hashbucket = 0;
1899 dhp = (struct DirHeader *)vdata->filedata;
1901 cursor->entry = ntohs(dhp->hashTable[0]);
1905 * Given a cursor and a directory entry, return the next entry in the
1909 static struct DirEntry *
1910 ReadNextDir(struct DirCursor *cursor, struct vnodeData *vdata)
1912 struct DirHeader *dhp;
1913 struct DirEntry *ep;
1915 dhp = (struct DirHeader *)vdata->filedata;
1917 if (cursor->entry) {
1918 ep = (struct DirEntry *)(vdata->filedata + (cursor->entry * 32));
1919 cursor->entry = ntohs(ep->next);
1922 while (++(cursor->hashbucket) < NHASHENT) {
1923 cursor->entry = ntohs(dhp->hashTable[cursor->hashbucket]);
1924 if (cursor->entry) {
1925 ep = (struct DirEntry *)(vdata->filedata +
1926 (cursor->entry * 32));
1927 cursor->entry = ntohs(ep->next);
1937 * Given a string, split it up into components a la Unix argc/argv.
1939 * This code is most stolen from ftp.
1943 MakeArgv(char *string, int *argc, char ***argv)
1945 static char *largv[64];
1948 static char argbuf[256];
1954 while (*la++ = GetToken(s, &s, ap, &ap))
1959 * Return a pointer to the next token, and update the current string
1964 GetToken(char *string, char **nexttoken, char argbuf[], char *nextargbuf[])
1991 goto OUTTOKEN; /* End of our token */
1995 goto S2; /* Get next character */
1999 goto S3; /* Get quoted string */
2002 *ap++ = *sp++; /* Add a character to our token */
2038 *nextargbuf = ap; /* Update storage pointer */
2039 *nexttoken = sp; /* Update token pointer */
2041 return got_one ? argbuf : NULL;
2045 * Insert vnodes into our hash table.
2048 static struct vnodeData *
2049 InsertVnode(unsigned int vnodeNumber, struct VnodeDiskObject *vnode)
2051 struct VnodeDiskObject *nvnode;
2052 struct vnodeData *vdata;
2053 static int curSmallVnodeIndex = 0;
2054 static int curLargeVnodeIndex = 0;
2055 struct vnodeData ***vnodeIndex;
2058 nvnode = (struct VnodeDiskObject *)malloc(sizeof(struct VnodeDiskObject));
2062 fprintf(stderr, "Unable to allocate space for vnode\n");
2066 memcpy((void *)nvnode, (void *)vnode, sizeof(struct VnodeDiskObject));
2068 if (vnodeNumber & 1) {
2069 vnodeIndex = &LargeVnodeIndex;
2070 curIndex = &curLargeVnodeIndex;
2072 vnodeIndex = &SmallVnodeIndex;
2073 curIndex = &curSmallVnodeIndex;
2076 vdata = (struct vnodeData *)malloc(sizeof(struct vnodeData));
2078 vdata->vnode = nvnode;
2079 vdata->vnodeNumber = vnodeNumber;
2080 vdata->dumpdata = 0;
2081 vdata->filedata = 0;
2082 vdata->datalength = 0;
2084 (*vnodeIndex)[(*curIndex)++] = vdata;
2090 * Routine to retrieve a vnode from the hash table.
2093 static struct vnodeData *
2094 GetVnode(unsigned int vnodeNumber)
2096 struct vnodeData vnode, *vnodep, **tmp;
2098 vnode.vnodeNumber = vnodeNumber;
2101 tmp = (struct vnodeData **)
2102 bsearch((void *)&vnodep,
2103 vnodeNumber & 1 ? LargeVnodeIndex : SmallVnodeIndex,
2104 vnodeNumber & 1 ? numLargeVnodes : numSmallVnodes,
2105 sizeof(struct vnodeData *), CompareVnode);
2107 return tmp ? *tmp : NULL;
2111 * Our comparator function for bsearch
2115 CompareVnode(const void *node1, const void *node2)
2117 struct vnodeData **vnode1 = (struct vnodeData **)node1;
2118 struct vnodeData **vnode2 = (struct vnodeData **)node2;
2120 if ((*vnode1)->vnodeNumber == (*vnode2)->vnodeNumber)
2122 else if ((*vnode1)->vnodeNumber > (*vnode2)->vnodeNumber)
2130 * Dump out the filename corresponding to a particular vnode.
2132 * This routine has the following dependancies:
2134 * - Only will work on UFS filesystems at this point
2135 * - Has to talk to the rsserver.
2136 * - Can only determine UFS algorithm type when run on the same machine
2137 * as the residency (unless you manually specify algorithm information)
2141 DumpVnodeFile(FILE * f, struct VnodeDiskObject *vnode, VolumeDiskData * vol)
2143 static int rscache = 0;
2144 static rsaccessinfoList rsnlist = { 0, 0 };
2145 char MountPoint[MAXPATHLEN + 1];
2146 char FileName[MAXPATHLEN + 1];
2147 unsigned int Size, Level[4];
2148 unsigned int DeviceTag, Algorithm;
2149 FileSystems *FSInfo;
2150 int i, found, FSType, rsindex;
2153 * Maybe we found out something about this residency via the
2154 * command-line; check that first.
2157 rsindex = ffs(VLkp_Residencies(vnode)) - 1;
2160 * We need to get information from the rsserver (so we can
2161 * find out the device tag for a given residency). If we
2162 * haven't cached that, talk to the rsserver to get it.
2163 * If we have info about this already, then don't talk to
2164 * the rsserver (this lets us still do disaster recovery if
2165 * MR-AFS is completely hosed).
2168 if (!rscache && rscmdlineinfo[rsindex].DeviceTag == -1) {
2171 code = ServerInitResidencyConnection();
2175 "ServerInitResidencyConnection failed " "with code %d\n",
2180 code = rs_GetResidencySummary(ServerRequestorId, &rsnlist);
2183 fprintf(stderr, "rs_GetResidencySummary failed " "with code %d\n",
2192 * For a given residency (as specified in the vnode),
2193 * find out it's device tag number, either via the rsserver
2194 * or via the command line.
2197 if (rscmdlineinfo[rsindex].DeviceTag != -1) {
2198 DeviceTag = rscmdlineinfo[rsindex].DeviceTag;
2201 for (i = 0, found = 0; (i < rsnlist.rsaccessinfoList_len) && (!found);
2203 if (rsnlist.rsaccessinfoList_val[i].id.residency ==
2204 VLkp_Residencies(vnode)) {
2206 DeviceTag = rsnlist.rsaccessinfoList_val[i].devicetagnumber;
2214 "Unable to find residency %d in "
2215 "rsserver database, aborting\n", VLkp_Residencies(vnode));
2220 * Okay, now we've got the DeviceTag ... which we can use to
2221 * lookup the on-disk configuration information (which we
2222 * assume is locally stored). We also need the DeviceTag to
2223 * print out which partition we're using (but that comes later).
2225 * We lookup the on-disk configuration information by calling
2226 * Ufs_GetFSInfo() to get the configuration information on the
2227 * filesystems specified by the given DeviceTag.
2229 * Before we call Ufs_GetFSInfo, check the command-line cache;
2230 * if we got something via the command-line, don't go to disk.
2233 if (rscmdlineinfo[rsindex].FSType == -1
2234 && Ufs_GetFSInfo(&FSInfo, DeviceTag)) {
2237 "Ufs_GetFSInfo failed for DeviceTag "
2238 "%d, Residency %d\n", DeviceTag, VLkp_Residencies(vnode));
2243 * The FSInfo structure has the last two things we need: the
2244 * FSType (ufs, slowufs, etc etc), and the usage algorithm (which
2245 * ends up being how many directories are being used on the
2246 * residency filesystem).
2248 * With these last two parameters, use routines stolen from
2249 * ufsname to generate the filename.
2251 * (Actually, I lied - we also need the "Size" parameter, which
2252 * we can also get from FSInfo);
2255 if (rscmdlineinfo[rsindex].FSType != -1) {
2256 FSType = rscmdlineinfo[rsindex].FSType;
2257 Algorithm = rscmdlineinfo[rsindex].Algorithm;
2258 Size = rscmdlineinfo[rsindex].Size;
2260 FSType = FSInfo->FileSystems_u.UfsInterface.FSType;
2261 Algorithm = FSInfo->FileSystems_u.UfsInterface.Algorithm;
2262 if (FSInfo->FileSystems_u.UfsInterface.Directories[1] == 0)
2264 else if (FSInfo->FileSystems_u.UfsInterface.Directories[1] == 16)
2266 else if (FSInfo->FileSystems_u.UfsInterface.Directories[1] == 256)
2270 fprintf(stderr, "Unknown directory size %d, " "aborting\n",
2271 FSInfo->FileSystems_u.UfsInterface.Directories[1]);
2277 * First, generate our mount point from the DeviceTag and
2281 DEVICETAGNUMBERTOMOUNTPOINT(MountPoint, DeviceTag, FSType);
2284 * Then, generate the "level" (directory bitmasks) from the
2285 * file tags, size, and algorithm
2288 UfsTagsToLevel(VLkp_FileTag1(vnode), VLkp_FileTag2(vnode), Algorithm,
2289 Size, Level, VLkp_ParentVnodeId(vnode),
2290 VLkp_ParentUniquifierId(vnode));
2293 * Finally, take the above information and generate the
2294 * corresponding filename (this macro ends up being a
2298 TAGSTONAME(FileName, MountPoint, Level, Directories[Size][1],
2299 vol->parentId, VLkp_ParentVnodeId(vnode),
2300 VLkp_ParentUniquifierId(vnode), Algorithm);
2302 fprintf(f, "%s\n", FileName);
2309 * Read a 16 bit integer in network order
2313 ReadInt16(FILE * f, unsigned short *s)
2317 if (fread((void *)&in, sizeof(in), 1, f) != 1) {
2319 fprintf(stderr, "ReadInt16 failed!\n");
2330 * Read a 32 bit integer in network order
2334 ReadInt32(FILE * f, unsigned int *i)
2338 if (fread((void *)&in, sizeof(in), 1, f) != 1) {
2340 fprintf(stderr, "ReadInt32 failed!\n");
2344 *i = ntohl((unsigned long)in);
2350 * Read a string from a dump file
2354 ReadString(FILE * f, char *string, int maxlen)
2359 if ((*string++ = getc(f)) == 0)
2364 * I'm not sure what the _hell_ this is supposed to do ...
2365 * but it was in the original dump code
2369 while ((c = getc(f)) && c != EOF);
2377 ReadByteString(FILE * f, void *s, int size)
2379 unsigned char *c = (unsigned char *)s;
2388 * The directory hashing algorithm used by AFS
2392 register char *string;
2394 /* Hash a string to a number between 0 and NHASHENT. */
2395 register unsigned char tc;
2399 while (tc = (*string++)) {
2403 tval = hval & (NHASHENT - 1);
2404 #ifdef AFS_CRAY_ENV /* actually, any > 32 bit environment */
2407 else if (hval & 0x80000000)
2408 tval = NHASHENT - tval;
2409 #else /* AFS_CRAY_ENV */
2413 tval = NHASHENT - tval;
2414 #endif /* AFS_CRAY_ENV */
2420 * Sigh, we need this for the AFS libraries
2424 LogErrors(int level, char *a, char *b, char *c, char *d, char *e, char *f,
2425 char *g, char *h, char *i, char *j, char *k)
2428 fprintf(stderr, a, b, c, d, e, f, g, h, i, j, k);
2434 * These are routines taken from AFS libraries and programs. Most of
2435 * them are from ufsname.c, but a few are from the dir library (the dir
2436 * library has a bunch of hidden dependancies, so it's not suitable to
2437 * include it outright).
2440 UfsEntropiesToTags(HighEntropy, LowEntropy, Algorithm, FileTag1, FileTag2)
2441 uint32_t HighEntropy;
2442 uint32_t LowEntropy;
2449 if ((Algorithm > UFS_ALGORITHMS) || (Algorithm <= 0))
2453 for (i = 0; i < 32; ++i) {
2454 if (UfsEntropy[Algorithm - 1][i] < 32)
2456 ((HighEntropy & (1 << i)) ==
2457 0) ? 0 : 1 << UfsEntropy[Algorithm - 1][i];
2460 ((HighEntropy & (1 << i)) ==
2461 0) ? 0 : 1 << (UfsEntropy[Algorithm - 1][i] - 32);
2463 for (i = 32; i < 64; ++i) {
2464 if (UfsEntropy[Algorithm - 1][i] < 32)
2466 ((LowEntropy & (1 << (i - 32))) ==
2467 0) ? 0 : 1 << UfsEntropy[Algorithm - 1][i];
2470 ((LowEntropy & (1 << (i - 32))) ==
2471 0) ? 0 : 1 << (UfsEntropy[Algorithm - 1][i] - 32);
2477 UfsTagsToHighEntropy(FileTag1, FileTag2, Algorithm)
2486 for (i = 0; i < 32; ++i) {
2487 if (UfsEntropy[Algorithm - 1][i] < 32)
2488 Value |= ((FileTag1 & (1 << UfsEntropy[Algorithm - 1][i]))
2492 ((FileTag2 & (1 << (UfsEntropy[Algorithm - 1][i] - 32))) ==
2499 UfsTagsToLowEntropy(FileTag1, FileTag2, Algorithm)
2508 for (i = 32; i < 64; ++i) {
2509 if (UfsEntropy[Algorithm - 1][i] < 32)
2510 Value |= ((FileTag1 & (1 << UfsEntropy[Algorithm - 1][i]))
2511 == 0) ? 0 : 1 << (i - 32);
2514 ((FileTag2 & (1 << (UfsEntropy[Algorithm - 1][i] - 32))) ==
2515 0) ? 0 : 1 << (i - 32);
2520 UfsTagsToLevel(FileTag1, FileTag2, Algorithm, Size, Sections, vnode,
2526 uint32_t Sections[4];
2528 uint32_t Uniquifier;
2530 uint32_t HighEntropy;
2531 uint32_t LowEntropy;
2533 switch (Algorithm) {
2535 LowEntropy = UfsTagsToLowEntropy(FileTag1, FileTag2, Algorithm);
2536 HighEntropy = UfsTagsToHighEntropy(FileTag1, FileTag2, Algorithm);
2537 Sections[0] = HighEntropy % Directories[Size][0];
2538 HighEntropy /= Directories[Size][0];
2539 if (Directories[Size][1]) {
2540 Sections[1] = HighEntropy % Directories[Size][1];
2541 HighEntropy /= Directories[Size][1];
2542 Sections[2] = HighEntropy;
2543 Sections[3] = LowEntropy;
2545 Sections[1] = HighEntropy;
2546 Sections[2] = LowEntropy;
2550 Sections[0] = FileTag1 & 0xff;
2551 if (Directories[Size][1]) {
2552 Sections[1] = Uniquifier & 0xff;
2553 if (Directories[Size][1] == 16)
2555 Sections[2] = FileTag1;
2556 Sections[3] = FileTag2;
2558 Sections[1] = FileTag1;
2559 Sections[2] = FileTag2;
2563 Sections[0] = FileTag1 & 0xff;
2564 if (Directories[Size][1]) {
2565 Sections[1] = (vnode >> 1) & 0xff;
2566 if (Directories[Size][1] == 16)
2568 Sections[2] = FileTag1;
2569 Sections[3] = FileTag2;
2571 Sections[1] = FileTag1;
2572 Sections[2] = FileTag2;
2576 fprintf(stderr, "UfsTagsToLevel: bad algorithm %lu!\n", Algorithm);
2582 #include <afs/afscbdummies.h>
2583 #endif /* RESIDENCY */