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>
77 #include <afs/param.h>
78 #include <afs/afsint.h>
81 #if !defined(PRE_AFS_36) && !defined(RESIDENCY)
82 #include <afs/ihandle.h>
83 #endif /* !defined(PRE_AFS_36) && !defined(RESIDENCY) */
84 #include <afs/vnode.h>
85 #include <afs/volume.h>
87 #ifdef AFS_LINUX24_ENV
88 #define _LARGEFILE64_SOURCE 1
91 #include <afs/rsdefs.h>
92 #include <afs/remioint.h>
93 #endif /* RESIDENCY */
98 * Sigh. Linux blows it again
106 * Stuff that is in private AFS header files, unfortunately
109 #define DUMPVERSION 1
110 #define DUMPENDMAGIC 0x3A214B6E
111 #define DUMPBEGINMAGIC 0xB3A11322
112 #define D_DUMPHEADER 1
113 #define D_VOLUMEHEADER 2
118 #define MAXDUMPTIMES 50
123 char volumeName[VNAMESIZE];
124 int nDumpTimes; /* Number of pairs */
127 } dumpTimes[MAXDUMPTIMES];
131 * Our command-line arguments
136 int Algorithm; /* Conversion algorithm */
137 int Size; /* Directory hierarchy size */
138 int FSType; /* File system type */
139 int DeviceTag; /* Device Tag */
140 } rscmdlineinfo[RS_MAXRESIDENCIES];
143 * This stuff comes from ufsname.c (which itself takes it from
147 /* There is an assumption that all of the prefixes will have exactly one '/' */
148 static char *Ufs_Prefixes[] = { "/ufs", "/slowufs", "/cdmf", "/sdmf" };
150 #define MAX_ITERATIONS 10
151 #define UFS_SUMMARYTREENAME "Summaries"
152 #define UFS_STAGINGTREENAME "Staging"
153 #define UFS_VOLUMEHEADERTREENAME "VolHeaders"
154 #define UFS_VOLUMETREENAME "Volumes"
155 #define UFS_ALGORITHMBASE 'A'
156 #define UFS_MOUNTPOINTBASE 'a'
157 #define UFS_ALGORITHMS 3
158 #define UFS_LINK_MAX 64 /* Arbitrary. */
159 #define HARD_LINKED_FILE -2
160 #define TAGSTONAME(FileName, MountPoint, Sections, Level1, RWVolume, Vnode, Uniquifier, Algorithm) \
163 sprintf(FileName,"%s/%lu/%lu/%c%lu.%lu.%lu.%lu.%lu", MountPoint, \
164 (Sections)[0], (Sections)[1], UFS_ALGORITHMBASE + Algorithm, \
165 (Sections)[2], (Sections)[3], RWVolume, Vnode, Uniquifier); \
167 sprintf(FileName,"%s/%lu/%c%lu.%lu.%lu.%lu.%lu", MountPoint, \
168 (Sections)[0], UFS_ALGORITHMBASE + Algorithm, \
169 (Sections)[1], (Sections)[2], RWVolume, Vnode, Uniquifier); \
171 #define TAGSTOSTAGINGNAME(FileName, MountPoint, RWVolume, Vnode, Uniquifier) \
172 sprintf(FileName,"%s/%s/%lu.%lu.%lu", MountPoint, \
173 UFS_STAGINGTREENAME, RWVolume, Vnode, Uniquifier)
174 #define TAGSTOVOLUMEHEADERNAME(FileName, MountPoint, FileTag1, FileTag2) \
175 sprintf(FileName,"%s/%s/%lu", MountPoint, UFS_VOLUMEHEADERTREENAME, \
177 #define TAGSTOVOLUMEINFONAME(FileName, MountPoint, FileTag1, FileTag2) \
178 sprintf(FileName,"%s/%s/%lu/%lu", MountPoint, \
179 UFS_VOLUMETREENAME, FileTag2, FileTag1)
180 #define TAGSTOVOLUMENAME(FileName, MountPoint, FileTag1, FileTag2, RWVolume) \
181 sprintf(FileName,"%s/%s/%lu/%lu.%lu", MountPoint, \
182 UFS_VOLUMETREENAME, FileTag2, FileTag1, RWVolume)
183 #define TAGSTOSUMMARYNAME(FileName, MountPoint, FileTag1, FileTag2, SummaryRequestor, Residency) \
184 sprintf(FileName,"%s/%s/%lu.%lu.%lu.%lu", MountPoint, \
185 UFS_SUMMARYTREENAME, FileTag1, FileTag2, SummaryRequestor, \
187 #define DEVICETAGNUMBERTOMOUNTPOINT(MountPoint, DeviceTagNumber, FSType) \
188 sprintf(MountPoint,"%s%c", Ufs_Prefixes[FSType], UFS_MOUNTPOINTBASE + \
190 #define MOUNTPOINTTODEVICETAGNUMBER(MountPoint) \
191 MountPoint[strlen(MountPoint) - 1] - UFS_MOUNTPOINTBASE
192 #define DEVICETAGNUMBERTOVOLUMEHEADERTREE(TreeName, MountPoint) \
193 sprintf(TreeName,"%s/%s", MountPoint, UFS_VOLUMEHEADERTREENAME)
194 #define UFS_RESIDENCIES_FILE "Residencies"
196 /* We don't ever want to map to uid/gid -1. fchown() takes that as a
197 don't change flag. We know however that volume number range from
198 0x2000000 to 0x20FFFFFF (see VAllocateVolumeId() in vol/vutil.c)
199 so we will use that to insure that -1 never appears. */
200 #define RWVolumeToUid(RWVolume) ((RWVolume >> 12) & 0xFFFF)
201 #define RWVolumeToGid(RWVolume) ((RWVolume & 0xFFF) | \
202 (((RWVolume >> 28) & 0xF) << 12))
203 #define UidGidToRWVolume(Uid, Gid) ((Gid & 0xFFF) | ((Uid & 0xFFFF) << 12) | \
204 ((Gid & 0xF000) << 16))
207 /* These routines generate a file name to correspond to the given tag
210 /* The following entropy array contains the order of bits from highest entropy
211 to lowest in the numbers FileTag1 and FileTag2. Bit numbers 32 and above
212 correspond to FileTag2. This ordering was determined by examining all read-
213 write volumes in the psc.edu cell. */
214 char UfsEntropy[1][64] = {
215 {1, 2, 3, 4, 33, 5, 6, 7, 44, 45, 46, 36, 8, 34, 42, 35,
216 9, 40, 38, 32, 43, 10, 39, 37, 11, 41, 12, 13, 14, 0,
217 15, 16, 61, 17, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51,
218 50, 49, 48, 47, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22,
219 21, 20, 19, 18, 62, 63},
222 uint32_t Directories[3][2] = { {256, 0}, {256, 16}, {256, 256}, };
223 #endif /* RESIDENCY */
225 static int verbose = 0;
226 static int numNoDirData = 0;
227 static int termsize = 0;
230 extern resid ServerRequestorId;
231 #endif /* RESIDENCY */
234 * We use this structure to hold vnode data in our hash table.
235 * It's indexed by vnode number.
239 struct VnodeDiskObject *vnode; /* A pointer to the disk vnode */
240 int vnodeNumber; /* The vnode number */
241 long dumpdata; /* File offset of dump data (if
243 unsigned char *filedata; /* A pointer to the actual file
244 * data itself (if available) */
245 unsigned int datalength; /* The length of the data */
249 * This contains the current location when we're doing a scan of a
254 int hashbucket; /* Current hash bucket */
255 int entry; /* Entry within hash bucket */
259 * Arrays to hold vnode data
262 struct vnodeData **LargeVnodeIndex;
263 struct vnodeData **SmallVnodeIndex;
264 int numLargeVnodes = 0;
265 int numSmallVnodes = 0;
268 * Crap for the libraries
271 int ShutdownInProgress = 0;
274 * Our local function prototypes
277 static int ReadDumpHeader(FILE *, struct DumpHeader *);
278 static int ReadVolumeHeader(FILE *, VolumeDiskData *);
279 static int ScanVnodes(FILE *, VolumeDiskData *, int);
280 static int DumpVnodeFile(FILE *, struct VnodeDiskObject *, VolumeDiskData *);
281 static struct vnodeData *InsertVnode(unsigned int, struct VnodeDiskObject *);
282 static struct vnodeData *GetVnode(unsigned int);
283 static int CompareVnode(const void *, const void *);
284 static void InteractiveRestore(FILE *, VolumeDiskData *);
285 static void DirectoryList(int, char **, struct vnodeData *, VolumeDiskData *);
286 static void DirListInternal(struct vnodeData *, char *[], int, int, int, int,
287 int, int, VolumeDiskData *, char *);
288 static int CompareDirEntry(const void *, const void *);
289 static struct vnodeData *ChangeDirectory(int, char **, struct vnodeData *);
290 static void CopyFile(int, char **, struct vnodeData *, FILE *);
291 static void CopyVnode(int, char **, FILE *);
292 static void DumpAllFiles(int, char **, struct vnodeData *, VolumeDiskData *);
293 static void DumpAllResidencies(FILE *, struct vnodeData *, VolumeDiskData *);
294 static struct vnodeData *FindFile(struct vnodeData *, char *);
295 static void ResetDirCursor(struct DirCursor *, struct vnodeData *);
296 static struct DirEntry *ReadNextDir(struct DirCursor *, struct vnodeData *);
297 static void MakeArgv(char *, int *, char ***);
298 static char *GetToken(char *, char **, char *, char *[]);
299 static int ReadInt16(FILE *, uint16_t *);
300 static int ReadInt32(FILE *, uint32_t *);
301 static int ReadString(FILE *, char *, int);
302 static int ReadByteString(FILE *, void *, int);
305 main(int argc, char *argv[])
307 int c, errflg = 0, dumpvnodes = 0, force = 0, inode = 0;
309 struct DumpHeader dheader;
312 int Res, Arg1, Arg2, Arg3, i;
319 for (i = 0; i < RS_MAXRESIDENCIES; i++) {
320 rscmdlineinfo[i].Algorithm = -1;
321 rscmdlineinfo[i].Size = -1;
322 rscmdlineinfo[i].DeviceTag = -1;
323 rscmdlineinfo[i].FSType = -1;
325 #endif /* RESIDENCY */
328 * Sigh, this is dumb, but we need the terminal window size
329 * to do intelligent things with "ls" later on.
332 if (isatty(STDOUT_FILENO)) {
333 if ((p = getenv("COLUMNS")) != NULL)
335 else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0
337 termsize = win.ws_col;
340 while ((c = getopt(argc, argv, "difr:t:v")) != EOF)
344 if (sscanf(optarg, "%d/%d", &Res, &Arg1) != 2) {
349 if (1 << (ffs(Res) - 1) != Res) {
350 fprintf(stderr, "Invalid residency %d\n", Res);
355 if (Arg1 < 0 || Arg1 > 26) {
356 fprintf(stderr, "Invalid device tag: %d\n", Arg1);
360 rscmdlineinfo[ffs(Res) - 1].DeviceTag = Arg1;
361 #else /* RESIDENCY */
362 fprintf(stderr, "-t not supported in non-MRAFS " "dumptool.\n");
364 #endif /* RESIDENCY */
369 if (sscanf(optarg, "%d/%d/%d/%d", &Res, &Arg1, &Arg2, &Arg3) != 4) {
374 if (Arg1 < 0 || Arg1 > 3) {
375 fprintf(stderr, "Invalid fstype: %d\n", Arg1);
380 if (Arg2 < 0 || Arg2 > 2) {
381 fprintf(stderr, "Invalid size: %d\n", Arg2);
386 if (Arg3 <= 0 || Arg3 > UFS_ALGORITHMS) {
387 fprintf(stderr, "Invalid algorithm: %d\n", Arg3);
391 rscmdlineinfo[ffs(Res) - 1].FSType = Arg1;
392 rscmdlineinfo[ffs(Res) - 1].Size = Arg2;
393 rscmdlineinfo[ffs(Res) - 1].Algorithm = Arg3;
394 #else /* RESIDENCY */
395 fprintf(stderr, "-r not supported in non-MRAFS " "dumptool.\n");
397 #endif /* RESIDENCY */
402 #else /* RESIDENCY */
403 fprintf(stderr, "-d not supported in non-MRAFS " "dumptool.\n");
405 #endif /* RESIDENCY */
421 if (errflg || optind == argc) {
422 fprintf(stderr, "Usage: %s\n\t[-v] [-f]\n\t"
424 "[-t Residency/Tag]\n\t"
425 "[-r Residency/Type/Size/Algorithm]\n\t"
426 "[-d] filename [file_in_dump [file in dump ...]]\n",
427 #else /* RESIDENCY */
429 #endif /* RESIDENCY */
435 * Try opening the dump file
439 if ((fd = open(argv[optind], O_RDONLY | O_LARGEFILE)) < 0) {
441 if ((fd = open(argv[optind], O_RDONLY)) < 0) {
443 fprintf(stderr, "open of dumpfile %s failed: %s\n", argv[optind],
448 if ((f = fdopen(fd, "rb")) == NULL) {
449 fprintf(stderr, "fdopen of dumpfile %s failed: %s\n", argv[optind],
454 if (ReadDumpHeader(f, &dheader)) {
455 fprintf(stderr, "Failed to read dump header!\n");
460 printf("Dump is for volume %lu (%s)\n", dheader.volumeId,
463 if (getc(f) != D_VOLUMEHEADER) {
464 fprintf(stderr, "Volume header is missing from dump, aborting\n");
468 if (ReadVolumeHeader(f, &vol)) {
469 fprintf(stderr, "Unable to read volume header\n");
474 printf("Volume information:\n");
475 printf("\tid = %lu\n", vol.id);
476 printf("\tparent id = %lu\n", vol.parentId);
477 printf("\tname = %s\n", vol.name);
482 printf(" inService");
485 if (vol.needsSalvaged)
486 printf(" needsSalvaged");
488 printf("\tuniquifier = %lu\n", vol.uniquifier);
489 printf("\tCreation date = %s", ctime((time_t *) & vol.creationDate));
490 printf("\tLast access date = %s", ctime((time_t *) & vol.accessDate));
491 printf("\tLast update date = %s", ctime((time_t *) & vol.updateDate));
492 printf("\tVolume owner = %lu\n", vol.owner);
496 printf("Scanning vnodes (this may take a while)\n");
499 * We need to do two vnode scans; one to get the number of
500 * vnodes, the other to actually build the index.
505 if (ScanVnodes(f, &vol, 1)) {
506 fprintf(stderr, "First vnode scan failed, aborting\n");
510 fseek(f, offset, SEEK_SET);
512 if (ScanVnodes(f, &vol, 0)) {
513 fprintf(stderr, "Second vnode scan failed, aborting\n");
517 if (getc(f) != D_DUMPEND || ReadInt32(f, &magic) || magic != DUMPENDMAGIC) {
518 fprintf(stderr, "Couldn't find dump postamble, ");
520 fprintf(stderr, "aborting (use -f to override)\n");
523 fprintf(stderr, "continuing anyway\n");
524 fprintf(stderr, "WARNING: Dump may not be complete!\n");
529 * If we wanted to simply dump all vnodes, do it now
534 struct vnodeData *vdata;
536 for (i = 0; i < numLargeVnodes; i++) {
538 vdata = LargeVnodeIndex[i];
540 if (vdata->vnode->type == vFidLookup)
541 if (DumpVnodeFile(stdout, vdata->vnode, &vol)) {
542 fprintf(stderr, "DumpVnodeFile failed, " "aborting\n");
547 for (i = 0; i < numSmallVnodes; i++) {
549 vdata = SmallVnodeIndex[i];
551 if (vdata->vnode->type == vFidLookup)
552 if (DumpVnodeFile(stdout, vdata->vnode, &vol)) {
553 fprintf(stderr, "DumpVnodeFile failed, " "aborting\n");
559 #endif /* RESIDENCY */
562 * Dump out all filenames with their corresponding FID
565 struct vnodeData *rootvdata;
567 if ((rootvdata = GetVnode(1)) == NULL) {
569 "Can't get vnode data for root " "vnode! Aborting\n");
573 DirListInternal(rootvdata, NULL, 0, 0, 1, 0, 1, 0, &vol, "");
575 } else if (argc > optind + 1) {
578 * Dump out residencies of files given on the command line.
581 struct vnodeData *vdata, *rootvdata;
583 if ((rootvdata = GetVnode(1)) == NULL) {
585 "Can't get vnode data for root " "vnode! Aborting\n");
589 for (i = optind + 1; i < argc; i++) {
591 if ((vdata = FindFile(rootvdata, argv[i])) == NULL) {
592 fprintf(stderr, "Skipping file %s\n", argv[i]);
597 printf("Residency locations for %s:\n", argv[i]);
599 while (vdata->vnode->NextVnodeId != 0) {
601 vdata = GetVnode(vdata->vnode->NextVnodeId);
605 "We had a vnode chain " "pointer to a vnode that "
606 "doesn't exist, aborting!\n");
609 if (vdata->vnode->type == vFidLookup)
610 DumpVnodeFile(stdout, vdata->vnode, &vol);
613 #else /* RESIDENCY */
614 fprintf(stderr, "Extra arguments after dump filename: %s\n",
617 #endif /* RESIDENCY */
620 * Perform an interactive restore
623 InteractiveRestore(f, &vol);
630 * Read the dump header, which is at the beginning of every dump
634 ReadDumpHeader(FILE * f, struct DumpHeader *header)
639 if (getc(f) != D_DUMPHEADER || ReadInt32(f, &magic)
640 || ReadInt32(f, (unsigned int *)
641 &header->version) || magic != DUMPBEGINMAGIC) {
643 fprintf(stderr, "Couldn't find dump magic numbers\n");
647 header->volumeId = 0;
648 header->nDumpTimes = 0;
650 while ((tag = getc(f)) > D_MAX && tag != EOF) {
651 unsigned short length;
654 if (ReadInt32(f, &header->volumeId)) {
656 fprintf(stderr, "Failed to read " "volumeId\n");
661 if (ReadString(f, header->volumeName, sizeof(header->volumeName))) {
663 fprintf(stderr, "Failed to read " "volume name\n");
668 if (ReadInt16(f, &length)) {
671 "Failed to read " "dump time array length\n");
674 header->nDumpTimes = (length >> 1);
675 for (i = 0; i < header->nDumpTimes; i++)
676 if (ReadInt32(f, (unsigned int *)
677 &header->dumpTimes[i].from)
678 || ReadInt32(f, (unsigned int *)
679 &header->dumpTimes[i].to)) {
681 fprintf(stderr, "Failed to " "read dump times\n");
687 fprintf(stderr, "Unknown dump tag \"%c\"\n", tag);
692 if (!header->volumeId || !header->nDumpTimes) {
695 "We didn't get a volume Id or " "dump times listing\n");
704 * Read the volume header; this is the information stored in VolumeDiskData.
706 * I'm not sure we need all of this, but read it in just in case.
710 ReadVolumeHeader(FILE * f, VolumeDiskData * vol)
714 memset((void *)vol, 0, sizeof(*vol));
716 while ((tag = getc(f)) > D_MAX && tag != EOF) {
719 if (ReadInt32(f, &vol->id))
723 if (ReadInt32(f, &trash))
727 if (ReadString(f, vol->name, sizeof(vol->name)))
731 vol->inService = getc(f);
734 vol->blessed = getc(f);
737 if (ReadInt32(f, &vol->uniquifier))
744 if (ReadInt32(f, &vol->parentId))
748 if (ReadInt32(f, &vol->cloneId))
752 if (ReadInt32(f, (uint32_t *) & vol->maxquota))
756 if (ReadInt32(f, (uint32_t *) & vol->minquota))
760 if (ReadInt32(f, (uint32_t *) & vol->diskused))
764 if (ReadInt32(f, (uint32_t *) & vol->filecount))
768 if (ReadInt32(f, &vol->accountNumber))
772 if (ReadInt32(f, &vol->owner))
776 if (ReadInt32(f, &vol->creationDate))
780 if (ReadInt32(f, &vol->accessDate))
784 if (ReadInt32(f, &vol->updateDate))
788 if (ReadInt32(f, &vol->expirationDate))
792 if (ReadInt32(f, &vol->backupDate))
797 (f, vol->offlineMessage, sizeof(vol->offlineMessage)))
801 if (ReadString(f, (char *)vol->stat_reads, VMSGSIZE))
805 unsigned short length;
808 if (ReadInt16(f, &length))
810 for (i = 0; i < length; i++) {
811 if (ReadInt32(f, &data))
813 if (i < sizeof(vol->weekUse) / sizeof(vol->weekUse[0]))
814 vol->weekUse[i] = data;
819 if (ReadInt32(f, &vol->dayUseDate))
823 if (ReadInt32(f, (uint32_t *) & vol->dayUse))
828 unsigned short length;
832 if (ReadInt16(f, &length))
834 for (i = 0; i < length; i++) {
835 if (ReadInt32(f, &data))
838 sizeof(vol->DesiredInfo.DesiredResidencyWords) /
839 sizeof(vol->DesiredInfo.DesiredResidencyWords[0]))
840 vol->DesiredInfo.DesiredResidencyWords[i] = data;
845 unsigned short length;
849 if (ReadInt16(f, &length))
851 for (i = 0; i < length; i++) {
852 if (ReadInt32(f, &data))
855 sizeof(vol->UnDesiredInfo.UnDesiredResidencyWords) /
856 sizeof(vol->UnDesiredInfo.UnDesiredResidencyWords[0]))
857 vol->UnDesiredInfo.UnDesiredResidencyWords[i] = data;
864 fprintf(stderr, "Unknown dump tag \"%c\"\n", tag);
874 * Scan all our vnode entries, and build indexing information.
878 ScanVnodes(FILE * f, VolumeDiskData * vol, int sizescan)
882 int numFileVnodes = 0;
883 int numDirVnodes = 0;
884 unsigned char buf[SIZEOF_LARGEDISKVNODE];
885 struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)buf;
886 long offset, oldoffset;
887 struct vnodeData *vdata;
892 while (tag == D_VNODE) {
899 if (ReadInt32(f, (uint32_t *) & vnodeNumber)) {
900 fprintf(stderr, "failed int32 for 'vnodenum'\n");
904 if (ReadInt32(f, &vnode->uniquifier)) {
905 fprintf(stderr, "failed int32 for 'uniquifier'\n");
909 if (verbose > 1 && !sizescan)
910 printf("Got vnode %d\n", vnodeNumber);
912 while ((tag = getc(f)) > D_MAX && tag != EOF)
915 vnode->type = (VnodeType) getc(f);
920 if (ReadInt16(f, &tmp)) {
921 fprintf(stderr, "failed int16 for 'l'\n");
924 vnode->linkCount = tmp;
928 if (ReadInt32(f, &vnode->dataVersion)) {
929 fprintf(stderr, "failed int32 for 'v'\n");
934 if (ReadInt32(f, (uint32_t *) & vnode->unixModifyTime)) {
935 fprintf(stderr, "failed int32 for 'm'\n");
940 if (ReadInt32(f, (uint32_t *) & vnode->serverModifyTime)) {
941 fprintf(stderr, "failed int32 for 's'\n");
946 if (ReadInt32(f, &vnode->author)) {
947 fprintf(stderr, "failed int32 for 'a'\n");
952 if (ReadInt32(f, &vnode->owner)) {
953 fprintf(stderr, "failed int32 for 'o'\n");
958 if (ReadInt32(f, (uint32_t *) & vnode->group)) {
959 fprintf(stderr, "failed int32 for 'g'\n");
964 unsigned short modeBits;
965 if (ReadInt16(f, &modeBits))
967 vnode->modeBits = modeBits;
971 if (ReadInt32(f, &vnode->parent)) {
972 fprintf(stderr, "failed int32 for 'p'\n");
978 if (ReadInt32(f, &vnode->NextVnodeId)) {
979 fprintf(stderr, "failed int32 for 'N'\n");
984 if (ReadInt32(f, &VLkp_Residencies(vnode))) {
985 fprintf(stderr, "failed int32 for 'R'\n");
991 if (ReadInt32(f, &vnode->length)) {
992 fprintf(stderr, "failed int32 for 'S'\n");
997 if (ReadInt32(f, (uint32_t *) & vnode->vn_ino_lo))
1002 (f, (void *)VVnodeDiskACL(vnode), VAclDiskSize(vnode))) {
1003 fprintf(stderr, "failed readbystring for 'A'\n");
1007 acl_NtohACL(VVnodeDiskACL(vnode));
1012 if (ReadInt32(f, &vnode->length_hi)) {
1013 fprintf(stderr, "failed int32 for 'h'\n");
1018 if (verbose > 1 && !sizescan)
1019 printf("We have file data!\n");
1020 if (ReadInt32(f, &length)) {
1021 fprintf(stderr, "failed int32 for 'f'\n");
1024 vnode->length = length;
1026 fseek(f, length, SEEK_CUR);
1030 fprintf(stderr, "Unknown dump tag \"%c\"\n", tag);
1035 * If we're doing an incremental restore, then vnodes
1036 * will be listed in the dump, but won't contain any
1037 * vnode information at all (I don't know why they're
1038 * included _at all_). If we get one of these vnodes, then
1039 * just skip it (because we can't do anything with it.
1042 if (vnode->type == -1)
1046 if (verbose > 1 && vnode->type == vFidLookup && !sizescan) {
1048 ("This is an auxiliary vnode (lookup) for vnode %d, residency %d\n",
1049 VLkp_ParentVnodeId(vnode), VLkp_Residencies(vnode));
1050 if (DumpVnodeFile(stdout, vnode, vol))
1054 if (verbose > 1 && vnode->type == vAccessHistory && !sizescan)
1055 printf("This is an auxiliary vnode (history) for vnode %d\n",
1056 VLkp_ParentVnodeId(vnode));
1059 if (vnode->type == vDirectory)
1065 * We know now all we would ever know about the vnode;
1066 * insert it into our hash table (but only if we're not
1067 * doing a vnode scan).
1072 vdata = InsertVnode(vnodeNumber, vnode);
1074 if (vdata == NULL) {
1077 "Failed to insert " "vnode into hash table");
1081 vdata->dumpdata = offset;
1082 vdata->datalength = length;
1085 * Save directory data, since we'll need it later.
1088 if (vnode->type == vDirectory && length) {
1090 vdata->filedata = malloc(length);
1092 if (!vdata->filedata) {
1095 "Unable to " "allocate space for "
1096 "file data (%d)\n", length);
1100 oldoffset = ftell(f);
1101 fseek(f, offset, SEEK_SET);
1103 if (fread(vdata->filedata, length, 1, f) != 1) {
1105 fprintf(stderr, "Unable to " "read in file data!\n");
1109 fseek(f, oldoffset, SEEK_SET);
1110 } else if (vnode->type == vDirectory)
1112 * Warn the user we may not have all directory
1123 numLargeVnodes = numDirVnodes;
1124 numSmallVnodes = numFileVnodes;
1127 LargeVnodeIndex = (struct vnodeData **)
1128 malloc(numDirVnodes * sizeof(struct vnodeData));
1129 SmallVnodeIndex = (struct vnodeData **)
1130 malloc(numFileVnodes * sizeof(struct vnodeData));
1132 if (LargeVnodeIndex == NULL || SmallVnodeIndex == NULL) {
1135 "Unable to allocate space " "for vnode tables\n");
1141 fprintf(stderr, "%s vnode scan completed\n",
1142 sizescan ? "Primary" : "Secondary");
1148 * Perform an interactive restore
1150 * Parsing the directory information is a pain, but other than that
1151 * we just use the other tools we already have in here.
1155 InteractiveRestore(FILE * f, VolumeDiskData * vol)
1157 struct vnodeData *vdatacwd; /* Vnode data for our current dir */
1163 * Let's see if we can at least get the data for our root directory.
1164 * If we can't, there's no way we can do an interactive restore.
1167 if ((vdatacwd = GetVnode(1)) == NULL) {
1168 fprintf(stderr, "No entry for our root vnode! Aborting\n");
1172 if (!vdatacwd->filedata) {
1174 "There is no directory data for the root "
1175 "vnode (1.1). An interactive\nrestore is not "
1181 * If you're doing a selective dump correctly, then you should get all
1182 * directory vnode data. But just in case you didn't, let the user
1183 * know there may be a problem.
1188 "WARNING: %d directory vnodes had no file "
1189 "data. An interactive restore\nmay not be possible\n",
1193 while (fgets(cmdbuf, 256, stdin)) {
1195 cmdbuf[strlen(cmdbuf) - 1] = '\0';
1197 if (strlen(cmdbuf) == 0) {
1202 MakeArgv(cmdbuf, &argc, &argv);
1204 if (strcmp(argv[0], "ls") == 0) {
1205 DirectoryList(argc, argv, vdatacwd, vol);
1206 } else if (strcmp(argv[0], "cd") == 0) {
1207 struct vnodeData *newvdata;
1209 newvdata = ChangeDirectory(argc, argv, vdatacwd);
1212 vdatacwd = newvdata;
1213 } else if (strcmp(argv[0], "file") == 0) {
1214 DumpAllFiles(argc, argv, vdatacwd, vol);
1215 } else if (strcmp(argv[0], "cp") == 0) {
1216 CopyFile(argc, argv, vdatacwd, f);
1217 } else if (strcmp(argv[0], "vcp") == 0) {
1218 CopyVnode(argc, argv, f);
1219 } else if (strcmp(argv[0], "quit") == 0
1220 || strcmp(argv[0], "exit") == 0)
1222 else if (strcmp(argv[0], "?") == 0 || strcmp(argv[0], "help") == 0) {
1223 printf("Valid commands are:\n");
1224 printf("\tls\t\tList current directory\n");
1225 printf("\tcd\t\tChange current directory\n");
1226 printf("\tcp\t\tCopy file from dump\n");
1227 printf("\tvcp\t\tCopy file from dump (via vnode)\n");
1229 printf("\tfile\t\tList residency filenames\n");
1230 #endif /* RESIDENCY */
1231 printf("\tquit | exit\tExit program\n");
1232 printf("\thelp | ?\tBrief help\n");
1235 "Unknown command, \"%s\", enter "
1236 "\"help\" for a list of commands.\n", argv[0]);
1245 * Do a listing of all files in a directory. Sigh, I wish this wasn't
1248 * With the reorganizing, this is just a front-end to DirListInternal()
1252 DirectoryList(int argc, char **argv, struct vnodeData *vdata,
1253 VolumeDiskData * vol)
1255 int errflg = 0, lflag = 0, iflag = 0, Fflag = 0, sflag = 0, Rflag = 0;
1260 while ((c = getopt(argc, argv, "liFRs")) != EOF)
1282 fprintf(stderr, "Usage: %s [-liFs] filename [filename ...]\n",
1287 DirListInternal(vdata, &(argv[optind]), argc - optind, lflag, iflag,
1288 Fflag, Rflag, 1, vol, NULL);
1294 * Function that does the REAL work in terms of directory listing
1298 DirListInternal(struct vnodeData *vdata, char *pathnames[], int numpathnames,
1299 int lflag, int iflag, int Fflag, int Rflag, int verbose,
1300 VolumeDiskData * vol, char *path)
1302 struct DirEntry *ep, **eplist = NULL, **eprecurse = NULL;
1303 struct DirCursor cursor;
1304 struct vnodeData *lvdata;
1306 int i, j, numentries = 0, longestname = 0, numcols, col, numrows;
1309 if (!vdata->filedata) {
1310 fprintf(stderr, "There is no vnode data for this " "directory!\n");
1314 ResetDirCursor(&cursor, vdata);
1317 * Scan through the whole directory
1320 while ((ep = ReadNextDir(&cursor, vdata)) != NULL) {
1323 * If we didn't get any filenames on the command line,
1327 if (numpathnames == 0) {
1329 realloc(eplist, sizeof(struct DirEntry *) * ++numentries);
1330 eplist[numentries - 1] = ep;
1331 if (strlen(ep->name) > longestname)
1332 longestname = strlen(ep->name);
1334 if ((lvdata = GetVnode(ntohl(ep->fid.vnode)))
1335 && lvdata->vnode->type == vDirectory
1336 && !(strcmp(ep->name, ".") == 0
1337 || strcmp(ep->name, "..") == 0)) {
1340 sizeof(struct DirEntry *) * ++numrecurse);
1341 eprecurse[numrecurse - 1] = ep;
1346 * Do glob matching via fnmatch()
1349 for (i = 0; i < numpathnames; i++)
1350 if (fnmatch(pathnames[i], ep->name, FNM_PATHNAME) == 0) {
1353 sizeof(struct DirEntry *) * ++numentries);
1354 eplist[numentries - 1] = ep;
1355 if (strlen(ep->name) > longestname)
1356 longestname = strlen(ep->name);
1358 if ((lvdata = GetVnode(ntohl(ep->fid.vnode)))
1359 && lvdata->vnode->type == vDirectory
1360 && !(strcmp(ep->name, ".") == 0
1361 || strcmp(ep->name, "..") == 0)) {
1364 sizeof(struct DirEntry *) *
1366 eprecurse[numrecurse - 1] = ep;
1373 qsort((void *)eplist, numentries, sizeof(struct DirEntry *),
1376 if (Rflag && eprecurse)
1377 qsort((void *)eprecurse, numrecurse, sizeof(struct DirEntry *),
1380 * We don't have to do column printing if we have the -l or the -i
1381 * options. Sigh, column printing is WAY TOO FUCKING COMPLICATED!
1384 if (!lflag && !iflag) {
1392 numcols = termsize / longestname ? termsize / longestname : 1;
1393 numrows = numentries / numcols + (numentries % numcols ? 1 : 0);
1395 for (i = 0; i < numrows; i++) {
1397 while (col < numcols && (i + col * numrows) < numentries) {
1398 ep = eplist[i + col++ * numrows];
1400 if (!(lvdata = GetVnode(ntohl(ep->fid.vnode))))
1402 else if (lvdata->vnode->type == vDirectory)
1404 else if (lvdata->vnode->type == vSymlink)
1406 else if (lvdata->vnode->modeBits & 0111 != 0)
1410 printf("%s%-*c", ep->name, longestname - strlen(ep->name),
1413 printf("%-*s", longestname, ep->name);
1419 for (i = 0; i < numentries; i++)
1420 if (!(lvdata = GetVnode(ntohl(eplist[i]->fid.vnode))))
1421 printf("%d.0.0\t%s\n",
1422 vol->parentId ? vol->parentId : vol->id,
1425 printf("%d.%d.%d\t%s/%s\n", vol->id,
1426 ntohl(eplist[i]->fid.vnode),
1427 ntohl(eplist[i]->fid.vunique), path, eplist[i]->name);
1429 printf("%d.%d.%d\t%s\n", vol->id, ntohl(eplist[i]->fid.vnode),
1430 ntohl(eplist[i]->fid.vunique), eplist[i]->name);
1432 for (i = 0; i < numentries; i++)
1433 if (!(lvdata = GetVnode(ntohl(eplist[i]->fid.vnode))))
1434 printf("---------- 0 0 " "0 0 %s\n",
1437 switch (lvdata->vnode->type) {
1448 for (j = 8; j >= 0; j--) {
1449 if (lvdata->vnode->modeBits & (1 << j))
1463 printf(" %-3d %-8d %-8d %10d %s\n", lvdata->vnode->linkCount,
1464 lvdata->vnode->owner, lvdata->vnode->group,
1465 lvdata->vnode->length, eplist[i]->name);
1471 if (Rflag && eprecurse) {
1474 for (i = 0; i < numrecurse; i++) {
1476 printf("\n%s:\n", eprecurse[i]->name);
1478 lpath = malloc(strlen(path) + strlen(eprecurse[i]->name) + 2);
1480 sprintf(lpath, "%s/%s", path, eprecurse[i]->name);
1482 DirListInternal(GetVnode(ntohl(eprecurse[i]->fid.vnode)), NULL, 0,
1483 lflag, iflag, Fflag, Rflag, verbose, vol, lpath);
1499 * Directory name comparison function, used by qsort
1503 CompareDirEntry(const void *e1, const void *e2)
1505 struct DirEntry **ep1 = (struct DirEntry **)e1;
1506 struct DirEntry **ep2 = (struct DirEntry **)e2;
1508 return strcmp((*ep1)->name, (*ep2)->name);
1512 * Change a directory. Return a pointer to our new vdata structure for
1516 static struct vnodeData *
1517 ChangeDirectory(int argc, char **argv, struct vnodeData *vdatacwd)
1519 struct vnodeData *newvdatacwd;
1522 fprintf(stderr, "Usage: %s directory\n", argv[0]);
1526 if ((newvdatacwd = FindFile(vdatacwd, argv[1])) == NULL)
1529 if (newvdatacwd->vnode->type != vDirectory) {
1530 fprintf(stderr, "%s: Not a directory\n", argv[1]);
1534 if (newvdatacwd->filedata == NULL) {
1535 fprintf(stderr, "%s: No directory data found.\n", argv[1]);
1543 * Copy a file from out of the dump file
1546 #define COPYBUFSIZE 8192
1549 CopyFile(int argc, char **argv, struct vnodeData *vdatacwd, FILE * f)
1551 struct vnodeData *vdata;
1555 char buffer[COPYBUFSIZE];
1558 fprintf(stderr, "Usage: %s dumpfile destfile\n", argv[0]);
1562 if ((vdata = FindFile(vdatacwd, argv[1])) == NULL)
1565 if (vdata->dumpdata == 0) {
1566 fprintf(stderr, "File %s has no data in dump file\n", argv[1]);
1570 if ((out = fopen(argv[2], "wb")) == NULL) {
1571 fprintf(stderr, "Open of %s failed: %s\n", argv[2], strerror(errno));
1575 if (fseek(f, vdata->dumpdata, SEEK_SET)) {
1576 fprintf(stderr, "Seek failed: %s\n", strerror(errno));
1581 while (cur < vdata->datalength) {
1585 vdata->datalength ? COPYBUFSIZE : vdata->datalength - cur;
1587 ret = fread(buffer, sizeof(char), bytes, f);
1590 fprintf(stderr, "Short read (expected %d, " "got %d)\n",
1593 fprintf(stderr, "Error during read: %s\n", strerror(errno));
1598 ret = fwrite(buffer, sizeof(char), bytes, out);
1601 fprintf(stderr, "Short write (expected %d, " "got %d)\n",
1604 fprintf(stderr, "Error during write: %s\n", strerror(errno));
1616 * Copy a file from out of the dump file, by using the vnode
1620 CopyVnode(int argc, char *argv[], FILE * f)
1622 struct vnodeData *vdata;
1626 char buffer[COPYBUFSIZE];
1627 unsigned int vnode, uniquifier = 0;
1630 fprintf(stderr, "Usage: %s vnode[.uniqifier] destfile\n", argv[0]);
1634 ret = sscanf(argv[1], "%d.%d", &vnode, &uniquifier);
1637 fprintf(stderr, "Invalid file identifier: %s\n", argv[1]);
1641 if (!(vdata = GetVnode(vnode))) {
1642 fprintf(stderr, "Vnode %d not in dump file\n", vnode);
1646 if (ret == 2 && vdata->vnode->uniquifier != uniquifier) {
1648 "Specified uniquifier %d did not match "
1649 "uniquifier %d found in dump file!\n", uniquifier,
1650 vdata->vnode->uniquifier);
1654 if (vdata->dumpdata == 0) {
1655 fprintf(stderr, "File %s has no data in dump file\n", argv[1]);
1659 if ((out = fopen(argv[2], "wb")) == NULL) {
1660 fprintf(stderr, "Open of %s failed: %s\n", argv[2], strerror(errno));
1664 if (fseek(f, vdata->dumpdata, SEEK_SET)) {
1665 fprintf(stderr, "Seek failed: %s\n", strerror(errno));
1670 while (cur < vdata->datalength) {
1674 vdata->datalength ? COPYBUFSIZE : vdata->datalength - cur;
1676 ret = fread(buffer, sizeof(char), bytes, f);
1679 fprintf(stderr, "Short read (expected %d, " "got %d)\n",
1682 fprintf(stderr, "Error during read: %s\n", strerror(errno));
1687 ret = fwrite(buffer, sizeof(char), bytes, out);
1690 fprintf(stderr, "Short write (expected %d, " "got %d)\n",
1693 fprintf(stderr, "Error during write: %s\n", strerror(errno));
1705 * Dump all residency filenames associated with a file, or all files
1706 * within a directory.
1710 DumpAllFiles(int argc, char **argv, struct vnodeData *vdatacwd,
1711 VolumeDiskData * vol)
1714 struct vnodeData *vdata, *nvdata;
1715 struct DirCursor cursor;
1716 struct DirEntry *ep;
1719 int dflag = 0, fflag = 0, errflg = 0;
1723 while ((c = getopt(argc, argv, "df:")) != EOF)
1729 if ((f = fopen(optarg, "a")) == NULL) {
1730 fprintf(stderr, "Cannot open \"%s\": %s\n", optarg,
1742 if (errflg || argc == optind) {
1743 fprintf(stderr, "Usage: %s [-d] [-f filename] file " "[file ...]\n",
1750 for (i = optind; i < argc; i++) {
1752 if ((vdata = FindFile(vdatacwd, argv[i])) == NULL)
1755 if (vdata->vnode->type == vDirectory && !dflag) {
1757 ResetDirCursor(&cursor, vdata);
1759 while ((ep = ReadNextDir(&cursor, vdata)) != NULL) {
1761 if (!(nvdata = GetVnode(ntohl(ep->fid.vnode)))) {
1763 "Cannot find vnode " "entry for %s (%d)\n",
1764 ep->name, ntohl(ep->fid.vnode));
1770 printf("Residency locations for %s:\n", ep->name);
1772 if (nvdata->dumpdata)
1773 printf("Local disk (in dump " "file)\n");
1776 DumpAllResidencies(f, nvdata, vol);
1782 printf("Residency locations for %s:\n", argv[i]);
1784 if (vdata->dumpdata)
1785 printf("Local disk (in dump file)\n");
1788 DumpAllResidencies(f, vdata, vol);
1794 #else /* RESIDENCY */
1796 "The \"file\" command is not available in the non-"
1797 "MRAFS version of dumptool.\n");
1798 #endif /* RESIDENCY */
1803 * Take a vnode, traverse the vnode chain, and dump out all files on
1804 * all residencies corresponding to that parent vnode.
1809 DumpAllResidencies(FILE * f, struct vnodeData *vdata,
1810 struct VolumeDiskData *vol)
1812 unsigned int nextVnodeNum;
1814 while (nextVnodeNum = vdata->vnode->NextVnodeId) {
1815 if ((vdata = GetVnode(nextVnodeNum)) == NULL) {
1817 "We had a pointer to %lu in it's "
1818 "vnode chain, but there\nisn't a record of "
1819 "it! The dump might be corrupt.\n", nextVnodeNum);
1823 if (vdata->vnode->type == vFidLookup)
1824 DumpVnodeFile(f, vdata->vnode, vol);
1833 * Given a directory vnode and a filename, return the vnode corresponding
1834 * to the file in that directory.
1836 * We now handle pathnames with directories in them.
1839 static struct vnodeData *
1840 FindFile(struct vnodeData *vdatacwd, char *filename)
1842 struct DirHeader *dhp;
1843 struct DirEntry *ep;
1845 struct vnodeData *vdata;
1846 char *c, newstr[MAXPATHLEN];
1848 if (!vdatacwd->filedata) {
1849 fprintf(stderr, "There is no vnode data for this " "directory!\n");
1854 * If we have a "/" in here, look up the vnode data for the
1855 * directory (everything before the "/") and use that as our
1856 * current directory. We automagically handle multiple directories
1857 * by using FindFile recursively.
1860 if ((c = strrchr(filename, '/')) != NULL) {
1862 strncpy(newstr, filename, c - filename);
1863 newstr[c - filename] = '\0';
1865 if ((vdatacwd = FindFile(vdatacwd, newstr)) == NULL)
1868 if (vdatacwd->vnode->type != vDirectory) {
1869 fprintf(stderr, "%s: Not a directory\n", newstr);
1876 dhp = (struct DirHeader *)vdatacwd->filedata;
1878 i = DirHash(filename);
1880 num = ntohs(dhp->hashTable[i]);
1883 ep = (struct DirEntry *)(vdatacwd->filedata + (num * 32));
1884 if (strcmp(ep->name, filename) == 0)
1886 num = ntohs(ep->next);
1890 fprintf(stderr, "%s: No such file or directory\n", filename);
1894 if ((vdata = GetVnode(ntohl(ep->fid.vnode))) == NULL) {
1895 fprintf(stderr, "%s: No vnode information for %lu found\n", filename,
1896 ntohl(ep->fid.vnode));
1904 * Reset a structure containing the current directory scan location
1908 ResetDirCursor(struct DirCursor *cursor, struct vnodeData *vdata)
1910 struct DirHeader *dhp;
1912 cursor->hashbucket = 0;
1914 dhp = (struct DirHeader *)vdata->filedata;
1916 cursor->entry = ntohs(dhp->hashTable[0]);
1920 * Given a cursor and a directory entry, return the next entry in the
1924 static struct DirEntry *
1925 ReadNextDir(struct DirCursor *cursor, struct vnodeData *vdata)
1927 struct DirHeader *dhp;
1928 struct DirEntry *ep;
1930 dhp = (struct DirHeader *)vdata->filedata;
1932 if (cursor->entry) {
1933 ep = (struct DirEntry *)(vdata->filedata + (cursor->entry * 32));
1934 cursor->entry = ntohs(ep->next);
1937 while (++(cursor->hashbucket) < NHASHENT) {
1938 cursor->entry = ntohs(dhp->hashTable[cursor->hashbucket]);
1939 if (cursor->entry) {
1940 ep = (struct DirEntry *)(vdata->filedata +
1941 (cursor->entry * 32));
1942 cursor->entry = ntohs(ep->next);
1952 * Given a string, split it up into components a la Unix argc/argv.
1954 * This code is most stolen from ftp.
1958 MakeArgv(char *string, int *argc, char ***argv)
1960 static char *largv[64];
1963 static char argbuf[256];
1969 while (*la++ = GetToken(s, &s, ap, &ap))
1974 * Return a pointer to the next token, and update the current string
1979 GetToken(char *string, char **nexttoken, char argbuf[], char *nextargbuf[])
2006 goto OUTTOKEN; /* End of our token */
2010 goto S2; /* Get next character */
2014 goto S3; /* Get quoted string */
2017 *ap++ = *sp++; /* Add a character to our token */
2053 *nextargbuf = ap; /* Update storage pointer */
2054 *nexttoken = sp; /* Update token pointer */
2056 return got_one ? argbuf : NULL;
2060 * Insert vnodes into our hash table.
2063 static struct vnodeData *
2064 InsertVnode(unsigned int vnodeNumber, struct VnodeDiskObject *vnode)
2066 struct VnodeDiskObject *nvnode;
2067 struct vnodeData *vdata;
2068 static int curSmallVnodeIndex = 0;
2069 static int curLargeVnodeIndex = 0;
2070 struct vnodeData ***vnodeIndex;
2073 nvnode = (struct VnodeDiskObject *)malloc(sizeof(struct VnodeDiskObject));
2077 fprintf(stderr, "Unable to allocate space for vnode\n");
2081 memcpy((void *)nvnode, (void *)vnode, sizeof(struct VnodeDiskObject));
2083 if (vnodeNumber & 1) {
2084 vnodeIndex = &LargeVnodeIndex;
2085 curIndex = &curLargeVnodeIndex;
2087 vnodeIndex = &SmallVnodeIndex;
2088 curIndex = &curSmallVnodeIndex;
2091 vdata = (struct vnodeData *)malloc(sizeof(struct vnodeData));
2093 vdata->vnode = nvnode;
2094 vdata->vnodeNumber = vnodeNumber;
2095 vdata->dumpdata = 0;
2096 vdata->filedata = 0;
2097 vdata->datalength = 0;
2099 (*vnodeIndex)[(*curIndex)++] = vdata;
2105 * Routine to retrieve a vnode from the hash table.
2108 static struct vnodeData *
2109 GetVnode(unsigned int vnodeNumber)
2111 struct vnodeData vnode, *vnodep, **tmp;
2113 vnode.vnodeNumber = vnodeNumber;
2116 tmp = (struct vnodeData **)
2117 bsearch((void *)&vnodep,
2118 vnodeNumber & 1 ? LargeVnodeIndex : SmallVnodeIndex,
2119 vnodeNumber & 1 ? numLargeVnodes : numSmallVnodes,
2120 sizeof(struct vnodeData *), CompareVnode);
2122 return tmp ? *tmp : NULL;
2126 * Our comparator function for bsearch
2130 CompareVnode(const void *node1, const void *node2)
2132 struct vnodeData **vnode1 = (struct vnodeData **)node1;
2133 struct vnodeData **vnode2 = (struct vnodeData **)node2;
2135 if ((*vnode1)->vnodeNumber == (*vnode2)->vnodeNumber)
2137 else if ((*vnode1)->vnodeNumber > (*vnode2)->vnodeNumber)
2145 * Dump out the filename corresponding to a particular vnode.
2147 * This routine has the following dependancies:
2149 * - Only will work on UFS filesystems at this point
2150 * - Has to talk to the rsserver.
2151 * - Can only determine UFS algorithm type when run on the same machine
2152 * as the residency (unless you manually specify algorithm information)
2156 DumpVnodeFile(FILE * f, struct VnodeDiskObject *vnode, VolumeDiskData * vol)
2158 static int rscache = 0;
2159 static rsaccessinfoList rsnlist = { 0, 0 };
2160 char MountPoint[MAXPATHLEN + 1];
2161 char FileName[MAXPATHLEN + 1];
2162 unsigned int Size, Level[4];
2163 unsigned int DeviceTag, Algorithm;
2164 FileSystems *FSInfo;
2165 int i, found, FSType, rsindex;
2168 * Maybe we found out something about this residency via the
2169 * command-line; check that first.
2172 rsindex = ffs(VLkp_Residencies(vnode)) - 1;
2175 * We need to get information from the rsserver (so we can
2176 * find out the device tag for a given residency). If we
2177 * haven't cached that, talk to the rsserver to get it.
2178 * If we have info about this already, then don't talk to
2179 * the rsserver (this lets us still do disaster recovery if
2180 * MR-AFS is completely hosed).
2183 if (!rscache && rscmdlineinfo[rsindex].DeviceTag == -1) {
2186 code = ServerInitResidencyConnection();
2190 "ServerInitResidencyConnection failed " "with code %d\n",
2195 code = rs_GetResidencySummary(ServerRequestorId, &rsnlist);
2198 fprintf(stderr, "rs_GetResidencySummary failed " "with code %d\n",
2207 * For a given residency (as specified in the vnode),
2208 * find out it's device tag number, either via the rsserver
2209 * or via the command line.
2212 if (rscmdlineinfo[rsindex].DeviceTag != -1) {
2213 DeviceTag = rscmdlineinfo[rsindex].DeviceTag;
2216 for (i = 0, found = 0; (i < rsnlist.rsaccessinfoList_len) && (!found);
2218 if (rsnlist.rsaccessinfoList_val[i].id.residency ==
2219 VLkp_Residencies(vnode)) {
2221 DeviceTag = rsnlist.rsaccessinfoList_val[i].devicetagnumber;
2229 "Unable to find residency %d in "
2230 "rsserver database, aborting\n", VLkp_Residencies(vnode));
2235 * Okay, now we've got the DeviceTag ... which we can use to
2236 * lookup the on-disk configuration information (which we
2237 * assume is locally stored). We also need the DeviceTag to
2238 * print out which partition we're using (but that comes later).
2240 * We lookup the on-disk configuration information by calling
2241 * Ufs_GetFSInfo() to get the configuration information on the
2242 * filesystems specified by the given DeviceTag.
2244 * Before we call Ufs_GetFSInfo, check the command-line cache;
2245 * if we got something via the command-line, don't go to disk.
2248 if (rscmdlineinfo[rsindex].FSType == -1
2249 && Ufs_GetFSInfo(&FSInfo, DeviceTag)) {
2252 "Ufs_GetFSInfo failed for DeviceTag "
2253 "%d, Residency %d\n", DeviceTag, VLkp_Residencies(vnode));
2258 * The FSInfo structure has the last two things we need: the
2259 * FSType (ufs, slowufs, etc etc), and the usage algorithm (which
2260 * ends up being how many directories are being used on the
2261 * residency filesystem).
2263 * With these last two parameters, use routines stolen from
2264 * ufsname to generate the filename.
2266 * (Actually, I lied - we also need the "Size" parameter, which
2267 * we can also get from FSInfo);
2270 if (rscmdlineinfo[rsindex].FSType != -1) {
2271 FSType = rscmdlineinfo[rsindex].FSType;
2272 Algorithm = rscmdlineinfo[rsindex].Algorithm;
2273 Size = rscmdlineinfo[rsindex].Size;
2275 FSType = FSInfo->FileSystems_u.UfsInterface.FSType;
2276 Algorithm = FSInfo->FileSystems_u.UfsInterface.Algorithm;
2277 if (FSInfo->FileSystems_u.UfsInterface.Directories[1] == 0)
2279 else if (FSInfo->FileSystems_u.UfsInterface.Directories[1] == 16)
2281 else if (FSInfo->FileSystems_u.UfsInterface.Directories[1] == 256)
2285 fprintf(stderr, "Unknown directory size %d, " "aborting\n",
2286 FSInfo->FileSystems_u.UfsInterface.Directories[1]);
2292 * First, generate our mount point from the DeviceTag and
2296 DEVICETAGNUMBERTOMOUNTPOINT(MountPoint, DeviceTag, FSType);
2299 * Then, generate the "level" (directory bitmasks) from the
2300 * file tags, size, and algorithm
2303 UfsTagsToLevel(VLkp_FileTag1(vnode), VLkp_FileTag2(vnode), Algorithm,
2304 Size, Level, VLkp_ParentVnodeId(vnode),
2305 VLkp_ParentUniquifierId(vnode));
2308 * Finally, take the above information and generate the
2309 * corresponding filename (this macro ends up being a
2313 TAGSTONAME(FileName, MountPoint, Level, Directories[Size][1],
2314 vol->parentId, VLkp_ParentVnodeId(vnode),
2315 VLkp_ParentUniquifierId(vnode), Algorithm);
2317 fprintf(f, "%s\n", FileName);
2324 * Read a 16 bit integer in network order
2328 ReadInt16(FILE * f, unsigned short *s)
2332 if (fread((void *)&in, sizeof(in), 1, f) != 1) {
2334 fprintf(stderr, "ReadInt16 failed!\n");
2345 * Read a 32 bit integer in network order
2349 ReadInt32(FILE * f, unsigned int *i)
2353 if (fread((void *)&in, sizeof(in), 1, f) != 1) {
2355 fprintf(stderr, "ReadInt32 failed!\n");
2359 *i = ntohl((unsigned long)in);
2365 * Read a string from a dump file
2369 ReadString(FILE * f, char *string, int maxlen)
2374 if ((*string++ = getc(f)) == 0)
2379 * I'm not sure what the _hell_ this is supposed to do ...
2380 * but it was in the original dump code
2384 while ((c = getc(f)) && c != EOF);
2392 ReadByteString(FILE * f, void *s, int size)
2394 unsigned char *c = (unsigned char *)s;
2403 * The directory hashing algorithm used by AFS
2407 register char *string;
2409 /* Hash a string to a number between 0 and NHASHENT. */
2410 register unsigned char tc;
2414 while (tc = (*string++)) {
2418 tval = hval & (NHASHENT - 1);
2419 #ifdef AFS_CRAY_ENV /* actually, any > 32 bit environment */
2422 else if (hval & 0x80000000)
2423 tval = NHASHENT - tval;
2424 #else /* AFS_CRAY_ENV */
2428 tval = NHASHENT - tval;
2429 #endif /* AFS_CRAY_ENV */
2435 * Sigh, we need this for the AFS libraries
2439 LogErrors(int level, char *a, char *b, char *c, char *d, char *e, char *f,
2440 char *g, char *h, char *i, char *j, char *k)
2443 fprintf(stderr, a, b, c, d, e, f, g, h, i, j, k);
2449 * These are routines taken from AFS libraries and programs. Most of
2450 * them are from ufsname.c, but a few are from the dir library (the dir
2451 * library has a bunch of hidden dependancies, so it's not suitable to
2452 * include it outright).
2455 UfsEntropiesToTags(HighEntropy, LowEntropy, Algorithm, FileTag1, FileTag2)
2456 uint32_t HighEntropy;
2457 uint32_t LowEntropy;
2464 if ((Algorithm > UFS_ALGORITHMS) || (Algorithm <= 0))
2468 for (i = 0; i < 32; ++i) {
2469 if (UfsEntropy[Algorithm - 1][i] < 32)
2471 ((HighEntropy & (1 << i)) ==
2472 0) ? 0 : 1 << UfsEntropy[Algorithm - 1][i];
2475 ((HighEntropy & (1 << i)) ==
2476 0) ? 0 : 1 << (UfsEntropy[Algorithm - 1][i] - 32);
2478 for (i = 32; i < 64; ++i) {
2479 if (UfsEntropy[Algorithm - 1][i] < 32)
2481 ((LowEntropy & (1 << (i - 32))) ==
2482 0) ? 0 : 1 << UfsEntropy[Algorithm - 1][i];
2485 ((LowEntropy & (1 << (i - 32))) ==
2486 0) ? 0 : 1 << (UfsEntropy[Algorithm - 1][i] - 32);
2492 UfsTagsToHighEntropy(FileTag1, FileTag2, Algorithm)
2501 for (i = 0; i < 32; ++i) {
2502 if (UfsEntropy[Algorithm - 1][i] < 32)
2503 Value |= ((FileTag1 & (1 << UfsEntropy[Algorithm - 1][i]))
2507 ((FileTag2 & (1 << (UfsEntropy[Algorithm - 1][i] - 32))) ==
2514 UfsTagsToLowEntropy(FileTag1, FileTag2, Algorithm)
2523 for (i = 32; i < 64; ++i) {
2524 if (UfsEntropy[Algorithm - 1][i] < 32)
2525 Value |= ((FileTag1 & (1 << UfsEntropy[Algorithm - 1][i]))
2526 == 0) ? 0 : 1 << (i - 32);
2529 ((FileTag2 & (1 << (UfsEntropy[Algorithm - 1][i] - 32))) ==
2530 0) ? 0 : 1 << (i - 32);
2535 UfsTagsToLevel(FileTag1, FileTag2, Algorithm, Size, Sections, vnode,
2541 uint32_t Sections[4];
2543 uint32_t Uniquifier;
2545 uint32_t HighEntropy;
2546 uint32_t LowEntropy;
2548 switch (Algorithm) {
2550 LowEntropy = UfsTagsToLowEntropy(FileTag1, FileTag2, Algorithm);
2551 HighEntropy = UfsTagsToHighEntropy(FileTag1, FileTag2, Algorithm);
2552 Sections[0] = HighEntropy % Directories[Size][0];
2553 HighEntropy /= Directories[Size][0];
2554 if (Directories[Size][1]) {
2555 Sections[1] = HighEntropy % Directories[Size][1];
2556 HighEntropy /= Directories[Size][1];
2557 Sections[2] = HighEntropy;
2558 Sections[3] = LowEntropy;
2560 Sections[1] = HighEntropy;
2561 Sections[2] = LowEntropy;
2565 Sections[0] = FileTag1 & 0xff;
2566 if (Directories[Size][1]) {
2567 Sections[1] = Uniquifier & 0xff;
2568 if (Directories[Size][1] == 16)
2570 Sections[2] = FileTag1;
2571 Sections[3] = FileTag2;
2573 Sections[1] = FileTag1;
2574 Sections[2] = FileTag2;
2578 Sections[0] = FileTag1 & 0xff;
2579 if (Directories[Size][1]) {
2580 Sections[1] = (vnode >> 1) & 0xff;
2581 if (Directories[Size][1] == 16)
2583 Sections[2] = FileTag1;
2584 Sections[3] = FileTag2;
2586 Sections[1] = FileTag1;
2587 Sections[2] = FileTag2;
2591 fprintf(stderr, "UfsTagsToLevel: bad algorithm %lu!\n", Algorithm);
2597 #include <afs/afscbdummies.h>
2598 #endif /* RESIDENCY */