4 * dumptool - A tool to manage MR-AFS dump files
6 * The dump file format ought to be documented _somewhere_, and
7 * this seems like a good as a place as any ...
9 * A AFS dump file is marked off into a series of sections. Each
10 * section marked by a dump tag. A tag is a single byte who's value
11 * corresponds with the next section. The sections are (in order):
13 * DUMPHEADER (tag 0x01)
14 * VOLUMEHEADER (tag 0x02)
18 * Descriptions of the sections follow. Note that in all cases, data is
19 * stored in the dump in network byte order.
23 * DUMPHEADER contains two parts: the DUMPMAGIC magic number (32 bits)
24 * and the dump header itself.
26 * The dump header itself consists of a series of tagged values,
27 * each tag marking out members of the DumpHeader structure. The
28 * routine ReadDumpHeader explains the specifics of these tags.
32 * VOLUMEHEADER is a series of tagged values corresponding to the elements
33 * of the VolumeDiskData structure. See ReadVolumeHeader for more
38 * The VNODE section is all vnodes contained in the volume (each vnode
39 * itself is marked with the VNODE tag, so it's really a sequence of
40 * VNODE tags, unlike other sections).
42 * Each vnode consists of three parts: the vnode number (32 bits), the
43 * uniqifier (32 bits), and a tagged list of elements corresponding to
44 * the elements of the VnodeDiskData structure. See ScanVnodes for
45 * more information. Note that if file data is associated with a vnode,
46 * it will be contained here.
50 * The DUMPEND section consists of one part: the DUMPENDMAGIC magic
55 * The tagged elements are all ASCII letters, as opposed to the section
56 * headers (which are 0x01, 0x02, ...). Thus, an easy way to tell when
57 * you've reached the end of an element sequence is to check to see if
58 * the next tag is a printable character (this code tests for < 20).
60 * "vos dump" dumps the large vnode index, then the small vnode index,
61 * so directories will appear first in the VNODE section.
64 #include <afsconfig.h>
65 #include <afs/param.h>
68 #include <sys/types.h>
69 #include <sys/param.h>
70 #include <netinet/in.h>
78 #include <sys/ioctl.h>
81 #include <afs/afsint.h>
84 #if !defined(PRE_AFS_36) && !defined(RESIDENCY)
85 #include <afs/ihandle.h>
86 #endif /* !defined(PRE_AFS_36) && !defined(RESIDENCY) */
87 #include <afs/vnode.h>
88 #include <afs/volume.h>
90 #ifdef AFS_LINUX24_ENV
91 #define _LARGEFILE64_SOURCE 1
94 #include <afs/rsdefs.h>
95 #include <afs/remioint.h>
96 #endif /* RESIDENCY */
101 typedef off_t off64_t;
102 #endif /* !HAVE_OFF64_T */
103 #ifndef HAVE_FSEEKO64
104 #define fseeko64 fseeko
105 #endif /* HAVE_FSEEKO64 */
106 #ifndef HAVE_FTELLO64
107 #define ftello64 ftello
108 #endif /* HAVE_FTELLO64 */
111 * Sigh. Linux blows it again
119 * Stuff that is in private AFS header files, unfortunately
122 #define DUMPVERSION 1
123 #define DUMPENDMAGIC 0x3A214B6E
124 #define DUMPBEGINMAGIC 0xB3A11322
125 #define D_DUMPHEADER 1
126 #define D_VOLUMEHEADER 2
131 #define MAXDUMPTIMES 50
136 char volumeName[VNAMESIZE];
137 int nDumpTimes; /* Number of pairs */
140 } dumpTimes[MAXDUMPTIMES];
144 * Our command-line arguments
149 int Algorithm; /* Conversion algorithm */
150 int Size; /* Directory hierarchy size */
151 int FSType; /* File system type */
152 int DeviceTag; /* Device Tag */
153 } rscmdlineinfo[RS_MAXRESIDENCIES];
156 * This stuff comes from ufsname.c (which itself takes it from
160 /* There is an assumption that all of the prefixes will have exactly one '/' */
161 static char *Ufs_Prefixes[] = { "/ufs", "/slowufs", "/cdmf", "/sdmf" };
163 #define MAX_ITERATIONS 10
164 #define UFS_SUMMARYTREENAME "Summaries"
165 #define UFS_STAGINGTREENAME "Staging"
166 #define UFS_VOLUMEHEADERTREENAME "VolHeaders"
167 #define UFS_VOLUMETREENAME "Volumes"
168 #define UFS_ALGORITHMBASE 'A'
169 #define UFS_MOUNTPOINTBASE 'a'
170 #define UFS_ALGORITHMS 3
171 #define UFS_LINK_MAX 64 /* Arbitrary. */
172 #define HARD_LINKED_FILE -2
173 #define TAGSTONAME(FileName, MountPoint, Sections, Level1, RWVolume, Vnode, Uniquifier, Algorithm) \
176 sprintf(FileName,"%s/%lu/%lu/%c%lu.%lu.%lu.%lu.%lu", MountPoint, \
177 (Sections)[0], (Sections)[1], UFS_ALGORITHMBASE + Algorithm, \
178 (Sections)[2], (Sections)[3], RWVolume, Vnode, Uniquifier); \
180 sprintf(FileName,"%s/%lu/%c%lu.%lu.%lu.%lu.%lu", MountPoint, \
181 (Sections)[0], UFS_ALGORITHMBASE + Algorithm, \
182 (Sections)[1], (Sections)[2], RWVolume, Vnode, Uniquifier); \
184 #define TAGSTOSTAGINGNAME(FileName, MountPoint, RWVolume, Vnode, Uniquifier) \
185 sprintf(FileName,"%s/%s/%lu.%lu.%lu", MountPoint, \
186 UFS_STAGINGTREENAME, RWVolume, Vnode, Uniquifier)
187 #define TAGSTOVOLUMEHEADERNAME(FileName, MountPoint, FileTag1, FileTag2) \
188 sprintf(FileName,"%s/%s/%lu", MountPoint, UFS_VOLUMEHEADERTREENAME, \
190 #define TAGSTOVOLUMEINFONAME(FileName, MountPoint, FileTag1, FileTag2) \
191 sprintf(FileName,"%s/%s/%lu/%lu", MountPoint, \
192 UFS_VOLUMETREENAME, FileTag2, FileTag1)
193 #define TAGSTOVOLUMENAME(FileName, MountPoint, FileTag1, FileTag2, RWVolume) \
194 sprintf(FileName,"%s/%s/%lu/%lu.%lu", MountPoint, \
195 UFS_VOLUMETREENAME, FileTag2, FileTag1, RWVolume)
196 #define TAGSTOSUMMARYNAME(FileName, MountPoint, FileTag1, FileTag2, SummaryRequestor, Residency) \
197 sprintf(FileName,"%s/%s/%lu.%lu.%lu.%lu", MountPoint, \
198 UFS_SUMMARYTREENAME, FileTag1, FileTag2, SummaryRequestor, \
200 #define DEVICETAGNUMBERTOMOUNTPOINT(MountPoint, DeviceTagNumber, FSType) \
201 sprintf(MountPoint,"%s%c", Ufs_Prefixes[FSType], UFS_MOUNTPOINTBASE + \
203 #define MOUNTPOINTTODEVICETAGNUMBER(MountPoint) \
204 MountPoint[strlen(MountPoint) - 1] - UFS_MOUNTPOINTBASE
205 #define DEVICETAGNUMBERTOVOLUMEHEADERTREE(TreeName, MountPoint) \
206 sprintf(TreeName,"%s/%s", MountPoint, UFS_VOLUMEHEADERTREENAME)
207 #define UFS_RESIDENCIES_FILE "Residencies"
209 /* We don't ever want to map to uid/gid -1. fchown() takes that as a
210 don't change flag. We know however that volume number range from
211 0x2000000 to 0x20FFFFFF (see VAllocateVolumeId() in vol/vutil.c)
212 so we will use that to insure that -1 never appears. */
213 #define RWVolumeToUid(RWVolume) ((RWVolume >> 12) & 0xFFFF)
214 #define RWVolumeToGid(RWVolume) ((RWVolume & 0xFFF) | \
215 (((RWVolume >> 28) & 0xF) << 12))
216 #define UidGidToRWVolume(Uid, Gid) ((Gid & 0xFFF) | ((Uid & 0xFFFF) << 12) | \
217 ((Gid & 0xF000) << 16))
220 /* These routines generate a file name to correspond to the given tag
223 /* The following entropy array contains the order of bits from highest entropy
224 to lowest in the numbers FileTag1 and FileTag2. Bit numbers 32 and above
225 correspond to FileTag2. This ordering was determined by examining all read-
226 write volumes in the psc.edu cell. */
227 char UfsEntropy[1][64] = {
228 {1, 2, 3, 4, 33, 5, 6, 7, 44, 45, 46, 36, 8, 34, 42, 35,
229 9, 40, 38, 32, 43, 10, 39, 37, 11, 41, 12, 13, 14, 0,
230 15, 16, 61, 17, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51,
231 50, 49, 48, 47, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22,
232 21, 20, 19, 18, 62, 63},
235 uint32_t Directories[3][2] = { {256, 0}, {256, 16}, {256, 256}, };
236 #endif /* RESIDENCY */
238 static int verbose = 0;
239 static int numNoDirData = 0;
240 static int termsize = 0;
243 extern resid ServerRequestorId;
244 #endif /* RESIDENCY */
247 * We use this structure to hold vnode data in our hash table.
248 * It's indexed by vnode number.
252 struct VnodeDiskObject *vnode; /* A pointer to the disk vnode */
253 int vnodeNumber; /* The vnode number */
254 off64_t dumpdata; /* File offset of dump data (if
256 unsigned char *filedata; /* A pointer to the actual file
257 * data itself (if available) */
258 unsigned int datalength; /* The length of the data */
262 * This contains the current location when we're doing a scan of a
267 int hashbucket; /* Current hash bucket */
268 int entry; /* Entry within hash bucket */
272 * Arrays to hold vnode data
275 struct vnodeData **LargeVnodeIndex;
276 struct vnodeData **SmallVnodeIndex;
277 int numLargeVnodes = 0;
278 int numSmallVnodes = 0;
281 * Crap for the libraries
284 int ShutdownInProgress = 0;
287 * Our local function prototypes
290 static int DirHash(char *string);
291 static int ReadDumpHeader(FILE *, struct DumpHeader *);
292 static int ReadVolumeHeader(FILE *, VolumeDiskData *);
293 static int ScanVnodes(FILE *, VolumeDiskData *, int);
294 static struct vnodeData *InsertVnode(unsigned int, struct VnodeDiskObject *);
295 static struct vnodeData *GetVnode(unsigned int);
296 static int CompareVnode(const void *, const void *);
297 static void InteractiveRestore(FILE *, VolumeDiskData *);
298 static void DirectoryList(int, char **, struct vnodeData *, VolumeDiskData *);
299 static void DirListInternal(struct vnodeData *, char *[], int, int, int, int,
300 int, int, VolumeDiskData *, char *);
301 static int CompareDirEntry(const void *, const void *);
302 static struct vnodeData *ChangeDirectory(int, char **, struct vnodeData *);
303 static void CopyFile(int, char **, struct vnodeData *, FILE *);
304 static void CopyVnode(int, char **, FILE *);
305 static void DumpAllFiles(int, char **, struct vnodeData *, VolumeDiskData *);
306 static struct vnodeData *FindFile(struct vnodeData *, char *);
307 static void ResetDirCursor(struct DirCursor *, struct vnodeData *);
308 static struct DirEntry *ReadNextDir(struct DirCursor *, struct vnodeData *);
309 static void MakeArgv(char *, int *, char ***);
310 static char *GetToken(char *, char **, char *, char *[]);
311 static int ReadInt16(FILE *, uint16_t *);
312 static int ReadInt32(FILE *, uint32_t *);
313 static int ReadString(FILE *, char *, int);
314 static int ReadByteString(FILE *, void *, int);
317 static int DumpVnodeFile(FILE *, struct VnodeDiskObject *, VolumeDiskData *);
318 static void DumpAllResidencies(FILE *, struct vnodeData *, VolumeDiskData *);
322 main(int argc, char *argv[])
324 int c, errflg = 0, force = 0, inode = 0;
326 struct DumpHeader dheader;
330 int Res, Arg1, Arg2, Arg3, i;
340 for (i = 0; i < RS_MAXRESIDENCIES; i++) {
341 rscmdlineinfo[i].Algorithm = -1;
342 rscmdlineinfo[i].Size = -1;
343 rscmdlineinfo[i].DeviceTag = -1;
344 rscmdlineinfo[i].FSType = -1;
346 #endif /* RESIDENCY */
349 * Sigh, this is dumb, but we need the terminal window size
350 * to do intelligent things with "ls" later on.
353 if (isatty(STDOUT_FILENO)) {
354 if ((p = getenv("COLUMNS")) != NULL)
356 else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0
358 termsize = win.ws_col;
361 while ((c = getopt(argc, argv, "difr:t:v")) != EOF)
365 if (sscanf(optarg, "%d/%d", &Res, &Arg1) != 2) {
370 if (1 << (ffs(Res) - 1) != Res) {
371 fprintf(stderr, "Invalid residency %d\n", Res);
376 if (Arg1 < 0 || Arg1 > 26) {
377 fprintf(stderr, "Invalid device tag: %d\n", Arg1);
381 rscmdlineinfo[ffs(Res) - 1].DeviceTag = Arg1;
382 #else /* RESIDENCY */
383 fprintf(stderr, "-t not supported in non-MRAFS " "dumptool.\n");
385 #endif /* RESIDENCY */
390 if (sscanf(optarg, "%d/%d/%d/%d", &Res, &Arg1, &Arg2, &Arg3) != 4) {
395 if (Arg1 < 0 || Arg1 > 3) {
396 fprintf(stderr, "Invalid fstype: %d\n", Arg1);
401 if (Arg2 < 0 || Arg2 > 2) {
402 fprintf(stderr, "Invalid size: %d\n", Arg2);
407 if (Arg3 <= 0 || Arg3 > UFS_ALGORITHMS) {
408 fprintf(stderr, "Invalid algorithm: %d\n", Arg3);
412 rscmdlineinfo[ffs(Res) - 1].FSType = Arg1;
413 rscmdlineinfo[ffs(Res) - 1].Size = Arg2;
414 rscmdlineinfo[ffs(Res) - 1].Algorithm = Arg3;
415 #else /* RESIDENCY */
416 fprintf(stderr, "-r not supported in non-MRAFS " "dumptool.\n");
418 #endif /* RESIDENCY */
423 #else /* RESIDENCY */
424 fprintf(stderr, "-d not supported in non-MRAFS " "dumptool.\n");
426 #endif /* RESIDENCY */
442 if (errflg || optind == argc) {
443 fprintf(stderr, "Usage: %s\n\t[-v] [-f]\n\t"
445 "[-t Residency/Tag]\n\t"
446 "[-r Residency/Type/Size/Algorithm]\n\t"
447 "[-d] filename [file_in_dump [file in dump ...]]\n",
448 #else /* RESIDENCY */
450 #endif /* RESIDENCY */
456 * Try opening the dump file
460 if ((fd = open(argv[optind], O_RDONLY | O_LARGEFILE)) < 0) {
462 if ((fd = open(argv[optind], O_RDONLY)) < 0) {
464 fprintf(stderr, "open of dumpfile %s failed: %s\n", argv[optind],
469 if ((f = fdopen(fd, "rb")) == NULL) {
470 fprintf(stderr, "fdopen of dumpfile %s failed: %s\n", argv[optind],
475 if (ReadDumpHeader(f, &dheader)) {
476 fprintf(stderr, "Failed to read dump header!\n");
481 printf("Dump is for volume %lu (%s)\n",
482 (unsigned long) dheader.volumeId, dheader.volumeName);
484 if (getc(f) != D_VOLUMEHEADER) {
485 fprintf(stderr, "Volume header is missing from dump, aborting\n");
489 if (ReadVolumeHeader(f, &vol)) {
490 fprintf(stderr, "Unable to read volume header\n");
495 printf("Volume information:\n");
496 printf("\tid = %lu\n", (unsigned long) vol.id);
497 printf("\tparent id = %lu\n", (unsigned long) vol.parentId);
498 printf("\tname = %s\n", vol.name);
503 printf(" inService");
506 if (vol.needsSalvaged)
507 printf(" needsSalvaged");
509 printf("\tuniquifier = %lu\n", (unsigned long) vol.uniquifier);
510 tmv = vol.creationDate;
511 printf("\tCreation date = %s", ctime(&tmv));
512 tmv = vol.accessDate;
513 printf("\tLast access date = %s", ctime(&tmv));
514 tmv = vol.updateDate;
515 printf("\tLast update date = %s", ctime(&tmv));
516 printf("\tVolume owner = %lu\n", (unsigned long) vol.owner);
520 printf("Scanning vnodes (this may take a while)\n");
523 * We need to do two vnode scans; one to get the number of
524 * vnodes, the other to actually build the index.
527 offset = ftello64(f);
529 if (ScanVnodes(f, &vol, 1)) {
530 fprintf(stderr, "First vnode scan failed, aborting\n");
534 fseeko64(f, offset, SEEK_SET);
536 if (ScanVnodes(f, &vol, 0)) {
537 fprintf(stderr, "Second vnode scan failed, aborting\n");
541 if (getc(f) != D_DUMPEND || ReadInt32(f, &magic) || magic != DUMPENDMAGIC) {
542 fprintf(stderr, "Couldn't find dump postamble, ");
544 fprintf(stderr, "aborting (use -f to override)\n");
547 fprintf(stderr, "continuing anyway\n");
548 fprintf(stderr, "WARNING: Dump may not be complete!\n");
553 * If we wanted to simply dump all vnodes, do it now
558 struct vnodeData *vdata;
560 for (i = 0; i < numLargeVnodes; i++) {
562 vdata = LargeVnodeIndex[i];
564 if (vdata->vnode->type == vFidLookup)
565 if (DumpVnodeFile(stdout, vdata->vnode, &vol)) {
566 fprintf(stderr, "DumpVnodeFile failed, " "aborting\n");
571 for (i = 0; i < numSmallVnodes; i++) {
573 vdata = SmallVnodeIndex[i];
575 if (vdata->vnode->type == vFidLookup)
576 if (DumpVnodeFile(stdout, vdata->vnode, &vol)) {
577 fprintf(stderr, "DumpVnodeFile failed, " "aborting\n");
583 #endif /* RESIDENCY */
586 * Dump out all filenames with their corresponding FID
589 struct vnodeData *rootvdata;
591 if ((rootvdata = GetVnode(1)) == NULL) {
593 "Can't get vnode data for root " "vnode! Aborting\n");
597 DirListInternal(rootvdata, NULL, 0, 0, 1, 0, 1, 0, &vol, "");
599 } else if (argc > optind + 1) {
602 * Dump out residencies of files given on the command line.
605 struct vnodeData *vdata, *rootvdata;
607 if ((rootvdata = GetVnode(1)) == NULL) {
609 "Can't get vnode data for root " "vnode! Aborting\n");
613 for (i = optind + 1; i < argc; i++) {
615 if ((vdata = FindFile(rootvdata, argv[i])) == NULL) {
616 fprintf(stderr, "Skipping file %s\n", argv[i]);
621 printf("Residency locations for %s:\n", argv[i]);
623 while (vdata->vnode->NextVnodeId != 0) {
625 vdata = GetVnode(vdata->vnode->NextVnodeId);
629 "We had a vnode chain " "pointer to a vnode that "
630 "doesn't exist, aborting!\n");
633 if (vdata->vnode->type == vFidLookup)
634 DumpVnodeFile(stdout, vdata->vnode, &vol);
637 #else /* RESIDENCY */
638 fprintf(stderr, "Extra arguments after dump filename: %s\n",
641 #endif /* RESIDENCY */
644 * Perform an interactive restore
647 InteractiveRestore(f, &vol);
654 * Read the dump header, which is at the beginning of every dump
658 ReadDumpHeader(FILE * f, struct DumpHeader *header)
663 if (getc(f) != D_DUMPHEADER || ReadInt32(f, &magic)
664 || ReadInt32(f, (unsigned int *)
665 &header->version) || magic != DUMPBEGINMAGIC) {
667 fprintf(stderr, "Couldn't find dump magic numbers\n");
671 header->volumeId = 0;
672 header->nDumpTimes = 0;
674 while ((tag = getc(f)) > D_MAX && tag != EOF) {
675 unsigned short length;
678 if (ReadInt32(f, &header->volumeId)) {
680 fprintf(stderr, "Failed to read " "volumeId\n");
685 if (ReadString(f, header->volumeName, sizeof(header->volumeName))) {
687 fprintf(stderr, "Failed to read " "volume name\n");
692 if (ReadInt16(f, &length)) {
695 "Failed to read " "dump time array length\n");
698 header->nDumpTimes = (length >> 1);
699 for (i = 0; i < header->nDumpTimes; i++)
700 if (ReadInt32(f, (unsigned int *)
701 &header->dumpTimes[i].from)
702 || ReadInt32(f, (unsigned int *)
703 &header->dumpTimes[i].to)) {
705 fprintf(stderr, "Failed to " "read dump times\n");
711 fprintf(stderr, "Unknown dump tag \"%c\"\n", tag);
716 if (!header->volumeId || !header->nDumpTimes) {
719 "We didn't get a volume Id or " "dump times listing\n");
728 * Read the volume header; this is the information stored in VolumeDiskData.
730 * I'm not sure we need all of this, but read it in just in case.
734 ReadVolumeHeader(FILE * f, VolumeDiskData * vol)
738 memset((void *)vol, 0, sizeof(*vol));
740 while ((tag = getc(f)) > D_MAX && tag != EOF) {
743 if (ReadInt32(f, &vol->id))
747 if (ReadInt32(f, &trash))
751 if (ReadString(f, vol->name, sizeof(vol->name)))
755 vol->inService = getc(f);
758 vol->blessed = getc(f);
761 if (ReadInt32(f, &vol->uniquifier))
768 if (ReadInt32(f, &vol->parentId))
772 if (ReadInt32(f, &vol->cloneId))
776 if (ReadInt32(f, (uint32_t *) & vol->maxquota))
780 if (ReadInt32(f, (uint32_t *) & vol->minquota))
784 if (ReadInt32(f, (uint32_t *) & vol->diskused))
788 if (ReadInt32(f, (uint32_t *) & vol->filecount))
792 if (ReadInt32(f, &vol->accountNumber))
796 if (ReadInt32(f, &vol->owner))
800 if (ReadInt32(f, &vol->creationDate))
804 if (ReadInt32(f, &vol->accessDate))
808 if (ReadInt32(f, &vol->updateDate))
812 if (ReadInt32(f, &vol->expirationDate))
816 if (ReadInt32(f, &vol->backupDate))
821 (f, vol->offlineMessage, sizeof(vol->offlineMessage)))
825 if (ReadString(f, (char *)vol->stat_reads, VMSGSIZE))
829 unsigned short length;
832 if (ReadInt16(f, &length))
834 for (i = 0; i < length; i++) {
835 if (ReadInt32(f, &data))
837 if (i < sizeof(vol->weekUse) / sizeof(vol->weekUse[0]))
838 vol->weekUse[i] = data;
843 if (ReadInt32(f, &vol->dayUseDate))
847 if (ReadInt32(f, (uint32_t *) & vol->dayUse))
852 unsigned short length;
856 if (ReadInt16(f, &length))
858 for (i = 0; i < length; i++) {
859 if (ReadInt32(f, &data))
862 sizeof(vol->DesiredInfo.DesiredResidencyWords) /
863 sizeof(vol->DesiredInfo.DesiredResidencyWords[0]))
864 vol->DesiredInfo.DesiredResidencyWords[i] = data;
869 unsigned short length;
873 if (ReadInt16(f, &length))
875 for (i = 0; i < length; i++) {
876 if (ReadInt32(f, &data))
879 sizeof(vol->UnDesiredInfo.UnDesiredResidencyWords) /
880 sizeof(vol->UnDesiredInfo.UnDesiredResidencyWords[0]))
881 vol->UnDesiredInfo.UnDesiredResidencyWords[i] = data;
888 fprintf(stderr, "Unknown dump tag \"%c\"\n", tag);
898 * Scan all our vnode entries, and build indexing information.
902 ScanVnodes(FILE * f, VolumeDiskData * vol, int sizescan)
906 int numFileVnodes = 0;
907 int numDirVnodes = 0;
908 unsigned char buf[SIZEOF_LARGEDISKVNODE];
909 struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)buf;
910 off64_t offset, oldoffset;
911 struct vnodeData *vdata;
916 while (tag == D_VNODE) {
923 if (ReadInt32(f, (uint32_t *) & vnodeNumber)) {
924 fprintf(stderr, "failed int32 for 'vnodenum'\n");
928 if (ReadInt32(f, &vnode->uniquifier)) {
929 fprintf(stderr, "failed int32 for 'uniquifier'\n");
933 if (verbose > 1 && !sizescan)
934 printf("Got vnode %d\n", vnodeNumber);
936 while ((tag = getc(f)) > D_MAX && tag != EOF)
939 vnode->type = (VnodeType) getc(f);
944 if (ReadInt16(f, &tmp)) {
945 fprintf(stderr, "failed int16 for 'l'\n");
948 vnode->linkCount = tmp;
952 if (ReadInt32(f, &vnode->dataVersion)) {
953 fprintf(stderr, "failed int32 for 'v'\n");
958 if (ReadInt32(f, (uint32_t *) & vnode->unixModifyTime)) {
959 fprintf(stderr, "failed int32 for 'm'\n");
964 if (ReadInt32(f, (uint32_t *) & vnode->serverModifyTime)) {
965 fprintf(stderr, "failed int32 for 's'\n");
970 if (ReadInt32(f, &vnode->author)) {
971 fprintf(stderr, "failed int32 for 'a'\n");
976 if (ReadInt32(f, &vnode->owner)) {
977 fprintf(stderr, "failed int32 for 'o'\n");
982 if (ReadInt32(f, (uint32_t *) & vnode->group)) {
983 fprintf(stderr, "failed int32 for 'g'\n");
988 unsigned short modeBits;
989 if (ReadInt16(f, &modeBits))
991 vnode->modeBits = modeBits;
995 if (ReadInt32(f, &vnode->parent)) {
996 fprintf(stderr, "failed int32 for 'p'\n");
1002 if (ReadInt32(f, &vnode->NextVnodeId)) {
1003 fprintf(stderr, "failed int32 for 'N'\n");
1008 if (ReadInt32(f, &VLkp_Residencies(vnode))) {
1009 fprintf(stderr, "failed int32 for 'R'\n");
1015 if (ReadInt32(f, &vnode->length)) {
1016 fprintf(stderr, "failed int32 for 'S'\n");
1021 if (ReadInt32(f, (uint32_t *) & vnode->vn_ino_lo))
1026 (f, (void *)VVnodeDiskACL(vnode), VAclDiskSize(vnode))) {
1027 fprintf(stderr, "failed readbystring for 'A'\n");
1031 acl_NtohACL(VVnodeDiskACL(vnode));
1036 if (ReadInt32(f, &vnode->length_hi)) {
1037 fprintf(stderr, "failed int32 for 'h'\n");
1042 if (verbose > 1 && !sizescan)
1043 printf("We have file data!\n");
1044 if (ReadInt32(f, &length)) {
1045 fprintf(stderr, "failed int32 for 'f'\n");
1048 vnode->length = length;
1049 offset = ftello64(f);
1050 fseeko64(f, length, SEEK_CUR);
1054 fprintf(stderr, "Unknown dump tag \"%c\"\n", tag);
1059 * If we're doing an incremental restore, then vnodes
1060 * will be listed in the dump, but won't contain any
1061 * vnode information at all (I don't know why they're
1062 * included _at all_). If we get one of these vnodes, then
1063 * just skip it (because we can't do anything with it.
1066 if (vnode->type == -1)
1070 if (verbose > 1 && vnode->type == vFidLookup && !sizescan) {
1072 ("This is an auxiliary vnode (lookup) for vnode %d, residency %d\n",
1073 VLkp_ParentVnodeId(vnode), VLkp_Residencies(vnode));
1074 if (DumpVnodeFile(stdout, vnode, vol))
1078 if (verbose > 1 && vnode->type == vAccessHistory && !sizescan)
1079 printf("This is an auxiliary vnode (history) for vnode %d\n",
1080 VLkp_ParentVnodeId(vnode));
1083 if (vnode->type == vDirectory)
1089 * We know now all we would ever know about the vnode;
1090 * insert it into our hash table (but only if we're not
1091 * doing a vnode scan).
1096 vdata = InsertVnode(vnodeNumber, vnode);
1098 if (vdata == NULL) {
1101 "Failed to insert " "vnode into hash table");
1105 vdata->dumpdata = offset;
1106 vdata->datalength = length;
1109 * Save directory data, since we'll need it later.
1112 if (vnode->type == vDirectory && length) {
1114 vdata->filedata = malloc(length);
1116 if (!vdata->filedata) {
1119 "Unable to " "allocate space for "
1120 "file data (%d)\n", length);
1124 oldoffset = ftello64(f);
1125 fseeko64(f, offset, SEEK_SET);
1127 if (fread(vdata->filedata, length, 1, f) != 1) {
1129 fprintf(stderr, "Unable to " "read in file data!\n");
1133 fseeko64(f, oldoffset, SEEK_SET);
1134 } else if (vnode->type == vDirectory)
1136 * Warn the user we may not have all directory
1147 numLargeVnodes = numDirVnodes;
1148 numSmallVnodes = numFileVnodes;
1151 LargeVnodeIndex = (struct vnodeData **)
1152 malloc(numDirVnodes * sizeof(struct vnodeData));
1153 SmallVnodeIndex = (struct vnodeData **)
1154 malloc(numFileVnodes * sizeof(struct vnodeData));
1156 if (LargeVnodeIndex == NULL || SmallVnodeIndex == NULL) {
1159 "Unable to allocate space " "for vnode tables\n");
1165 fprintf(stderr, "%s vnode scan completed\n",
1166 sizescan ? "Primary" : "Secondary");
1172 * Perform an interactive restore
1174 * Parsing the directory information is a pain, but other than that
1175 * we just use the other tools we already have in here.
1177 #define CMDBUFSIZE (AFSPATHMAX * 2)
1179 InteractiveRestore(FILE * f, VolumeDiskData * vol)
1181 struct vnodeData *vdatacwd; /* Vnode data for our current dir */
1182 char cmdbuf[CMDBUFSIZE];
1187 * Let's see if we can at least get the data for our root directory.
1188 * If we can't, there's no way we can do an interactive restore.
1191 if ((vdatacwd = GetVnode(1)) == NULL) {
1192 fprintf(stderr, "No entry for our root vnode! Aborting\n");
1196 if (!vdatacwd->filedata) {
1198 "There is no directory data for the root "
1199 "vnode (1.1). An interactive\nrestore is not "
1205 * If you're doing a selective dump correctly, then you should get all
1206 * directory vnode data. But just in case you didn't, let the user
1207 * know there may be a problem.
1212 "WARNING: %d directory vnodes had no file "
1213 "data. An interactive restore\nmay not be possible\n",
1217 while (fgets(cmdbuf, CMDBUFSIZE, stdin)) {
1219 cmdbuf[strlen(cmdbuf) - 1] = '\0';
1221 if (strlen(cmdbuf) == 0) {
1226 MakeArgv(cmdbuf, &argc, &argv);
1228 if (strcmp(argv[0], "ls") == 0) {
1229 DirectoryList(argc, argv, vdatacwd, vol);
1230 } else if (strcmp(argv[0], "cd") == 0) {
1231 struct vnodeData *newvdata;
1233 newvdata = ChangeDirectory(argc, argv, vdatacwd);
1236 vdatacwd = newvdata;
1237 } else if (strcmp(argv[0], "file") == 0) {
1238 DumpAllFiles(argc, argv, vdatacwd, vol);
1239 } else if (strcmp(argv[0], "cp") == 0) {
1240 CopyFile(argc, argv, vdatacwd, f);
1241 } else if (strcmp(argv[0], "vcp") == 0) {
1242 CopyVnode(argc, argv, f);
1243 } else if (strcmp(argv[0], "quit") == 0
1244 || strcmp(argv[0], "exit") == 0)
1246 else if (strcmp(argv[0], "?") == 0 || strcmp(argv[0], "help") == 0) {
1247 printf("Valid commands are:\n");
1248 printf("\tls\t\tList current directory\n");
1249 printf("\tcd\t\tChange current directory\n");
1250 printf("\tcp\t\tCopy file from dump\n");
1251 printf("\tvcp\t\tCopy file from dump (via vnode)\n");
1253 printf("\tfile\t\tList residency filenames\n");
1254 #endif /* RESIDENCY */
1255 printf("\tquit | exit\tExit program\n");
1256 printf("\thelp | ?\tBrief help\n");
1259 "Unknown command, \"%s\", enter "
1260 "\"help\" for a list of commands.\n", argv[0]);
1269 * Do a listing of all files in a directory. Sigh, I wish this wasn't
1272 * With the reorganizing, this is just a front-end to DirListInternal()
1276 DirectoryList(int argc, char **argv, struct vnodeData *vdata,
1277 VolumeDiskData * vol)
1279 int errflg = 0, lflag = 0, iflag = 0, Fflag = 0, sflag = 0, Rflag = 0;
1284 while ((c = getopt(argc, argv, "liFRs")) != EOF)
1306 fprintf(stderr, "Usage: %s [-liFs] filename [filename ...]\n",
1311 DirListInternal(vdata, &(argv[optind]), argc - optind, lflag, iflag,
1312 Fflag, Rflag, 1, vol, NULL);
1318 * Function that does the REAL work in terms of directory listing
1322 DirListInternal(struct vnodeData *vdata, char *pathnames[], int numpathnames,
1323 int lflag, int iflag, int Fflag, int Rflag, int verbose,
1324 VolumeDiskData * vol, char *path)
1326 struct DirEntry *ep, **eplist = NULL, **eprecurse = NULL;
1327 struct DirCursor cursor;
1328 struct vnodeData *lvdata;
1330 int i, j, numentries = 0, longestname = 0, numcols, col, numrows;
1333 if (!vdata->filedata) {
1334 fprintf(stderr, "There is no vnode data for this " "directory!\n");
1338 ResetDirCursor(&cursor, vdata);
1341 * Scan through the whole directory
1344 while ((ep = ReadNextDir(&cursor, vdata)) != NULL) {
1347 * If we didn't get any filenames on the command line,
1351 if (numpathnames == 0) {
1353 realloc(eplist, 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 *) * ++numrecurse);
1365 eprecurse[numrecurse - 1] = ep;
1370 * Do glob matching via fnmatch()
1373 for (i = 0; i < numpathnames; i++)
1374 if (fnmatch(pathnames[i], ep->name, FNM_PATHNAME) == 0) {
1377 sizeof(struct DirEntry *) * ++numentries);
1378 eplist[numentries - 1] = ep;
1379 if (strlen(ep->name) > longestname)
1380 longestname = strlen(ep->name);
1382 if ((lvdata = GetVnode(ntohl(ep->fid.vnode)))
1383 && lvdata->vnode->type == vDirectory
1384 && !(strcmp(ep->name, ".") == 0
1385 || strcmp(ep->name, "..") == 0)) {
1388 sizeof(struct DirEntry *) *
1390 eprecurse[numrecurse - 1] = ep;
1397 qsort((void *)eplist, numentries, sizeof(struct DirEntry *),
1400 if (Rflag && eprecurse)
1401 qsort((void *)eprecurse, numrecurse, sizeof(struct DirEntry *),
1404 * We don't have to do column printing if we have the -l or the -i
1405 * options. Sigh, column printing is WAY TOO FUCKING COMPLICATED!
1408 if (!lflag && !iflag) {
1416 numcols = termsize / longestname ? termsize / longestname : 1;
1417 numrows = numentries / numcols + (numentries % numcols ? 1 : 0);
1419 for (i = 0; i < numrows; i++) {
1421 while (col < numcols && (i + col * numrows) < numentries) {
1422 ep = eplist[i + col++ * numrows];
1424 if (!(lvdata = GetVnode(ntohl(ep->fid.vnode))))
1426 else if (lvdata->vnode->type == vDirectory)
1428 else if (lvdata->vnode->type == vSymlink)
1430 else if ((lvdata->vnode->modeBits & 0111) != 0)
1434 printf("%s%-*c", ep->name, (int)(longestname -
1435 strlen(ep->name)), c);
1437 printf("%-*s", longestname, ep->name);
1443 for (i = 0; i < numentries; i++)
1444 if (!(lvdata = GetVnode(ntohl(eplist[i]->fid.vnode))))
1445 printf("%d.0.0\t%s\n",
1446 vol->parentId ? vol->parentId : vol->id,
1449 printf("%d.%d.%d\t%s/%s\n", vol->id,
1450 ntohl(eplist[i]->fid.vnode),
1451 ntohl(eplist[i]->fid.vunique), path, eplist[i]->name);
1453 printf("%d.%d.%d\t%s\n", vol->id, ntohl(eplist[i]->fid.vnode),
1454 ntohl(eplist[i]->fid.vunique), eplist[i]->name);
1456 for (i = 0; i < numentries; i++)
1457 if (!(lvdata = GetVnode(ntohl(eplist[i]->fid.vnode))))
1458 printf("---------- 0 0 " "0 0 %s\n",
1461 switch (lvdata->vnode->type) {
1472 for (j = 8; j >= 0; j--) {
1473 if (lvdata->vnode->modeBits & (1 << j))
1487 printf(" %-3d %-8d %-8d %10d %s\n", lvdata->vnode->linkCount,
1488 lvdata->vnode->owner, lvdata->vnode->group,
1489 lvdata->vnode->length, eplist[i]->name);
1495 if (Rflag && eprecurse) {
1498 for (i = 0; i < numrecurse; i++) {
1500 printf("\n%s:\n", eprecurse[i]->name);
1502 lpath = malloc(strlen(path) + strlen(eprecurse[i]->name) + 2);
1504 sprintf(lpath, "%s/%s", path, eprecurse[i]->name);
1506 DirListInternal(GetVnode(ntohl(eprecurse[i]->fid.vnode)), NULL, 0,
1507 lflag, iflag, Fflag, Rflag, verbose, vol, lpath);
1523 * Directory name comparison function, used by qsort
1527 CompareDirEntry(const void *e1, const void *e2)
1529 struct DirEntry **ep1 = (struct DirEntry **)e1;
1530 struct DirEntry **ep2 = (struct DirEntry **)e2;
1532 return strcmp((*ep1)->name, (*ep2)->name);
1536 * Change a directory. Return a pointer to our new vdata structure for
1540 static struct vnodeData *
1541 ChangeDirectory(int argc, char **argv, struct vnodeData *vdatacwd)
1543 struct vnodeData *newvdatacwd;
1546 fprintf(stderr, "Usage: %s directory\n", argv[0]);
1550 if ((newvdatacwd = FindFile(vdatacwd, argv[1])) == NULL)
1553 if (newvdatacwd->vnode->type != vDirectory) {
1554 fprintf(stderr, "%s: Not a directory\n", argv[1]);
1558 if (newvdatacwd->filedata == NULL) {
1559 fprintf(stderr, "%s: No directory data found.\n", argv[1]);
1567 * Copy a file from out of the dump file
1570 #define COPYBUFSIZE 8192
1573 CopyFile(int argc, char **argv, struct vnodeData *vdatacwd, FILE * f)
1575 struct vnodeData *vdata;
1579 char buffer[COPYBUFSIZE];
1582 fprintf(stderr, "Usage: %s dumpfile destfile\n", argv[0]);
1586 if ((vdata = FindFile(vdatacwd, argv[1])) == NULL)
1589 if (vdata->dumpdata == 0) {
1590 fprintf(stderr, "File %s has no data in dump file\n", argv[1]);
1594 if ((out = fopen(argv[2], "wb")) == NULL) {
1595 fprintf(stderr, "Open of %s failed: %s\n", argv[2], strerror(errno));
1599 if (fseeko64(f, vdata->dumpdata, SEEK_SET)) {
1600 fprintf(stderr, "Seek failed: %s\n", strerror(errno));
1605 while (cur < vdata->datalength) {
1609 vdata->datalength ? COPYBUFSIZE : vdata->datalength - cur;
1611 ret = fread(buffer, sizeof(char), bytes, f);
1614 fprintf(stderr, "Short read (expected %d, " "got %d)\n",
1617 fprintf(stderr, "Error during read: %s\n", strerror(errno));
1622 ret = fwrite(buffer, sizeof(char), bytes, out);
1625 fprintf(stderr, "Short write (expected %d, " "got %d)\n",
1628 fprintf(stderr, "Error during write: %s\n", strerror(errno));
1640 * Copy a file from out of the dump file, by using the vnode
1644 CopyVnode(int argc, char *argv[], FILE * f)
1646 struct vnodeData *vdata;
1650 char buffer[COPYBUFSIZE];
1651 unsigned int vnode, uniquifier = 0;
1654 fprintf(stderr, "Usage: %s vnode[.uniqifier] destfile\n", argv[0]);
1658 ret = sscanf(argv[1], "%d.%d", &vnode, &uniquifier);
1661 fprintf(stderr, "Invalid file identifier: %s\n", argv[1]);
1665 if (!(vdata = GetVnode(vnode))) {
1666 fprintf(stderr, "Vnode %d not in dump file\n", vnode);
1670 if (ret == 2 && vdata->vnode->uniquifier != uniquifier) {
1672 "Specified uniquifier %d did not match "
1673 "uniquifier %d found in dump file!\n", uniquifier,
1674 vdata->vnode->uniquifier);
1678 if (vdata->dumpdata == 0) {
1679 fprintf(stderr, "File %s has no data in dump file\n", argv[1]);
1683 if ((out = fopen(argv[2], "wb")) == NULL) {
1684 fprintf(stderr, "Open of %s failed: %s\n", argv[2], strerror(errno));
1688 if (fseeko64(f, vdata->dumpdata, SEEK_SET)) {
1689 fprintf(stderr, "Seek failed: %s\n", strerror(errno));
1694 while (cur < vdata->datalength) {
1698 vdata->datalength ? COPYBUFSIZE : vdata->datalength - cur;
1700 ret = fread(buffer, sizeof(char), bytes, f);
1703 fprintf(stderr, "Short read (expected %d, " "got %d)\n",
1706 fprintf(stderr, "Error during read: %s\n", strerror(errno));
1711 ret = fwrite(buffer, sizeof(char), bytes, out);
1714 fprintf(stderr, "Short write (expected %d, " "got %d)\n",
1717 fprintf(stderr, "Error during write: %s\n", strerror(errno));
1729 * Dump all residency filenames associated with a file, or all files
1730 * within a directory.
1734 DumpAllFiles(int argc, char **argv, struct vnodeData *vdatacwd,
1735 VolumeDiskData * vol)
1738 struct vnodeData *vdata, *nvdata;
1739 struct DirCursor cursor;
1740 struct DirEntry *ep;
1743 int dflag = 0, fflag = 0, errflg = 0;
1747 while ((c = getopt(argc, argv, "df:")) != EOF)
1753 if ((f = fopen(optarg, "a")) == NULL) {
1754 fprintf(stderr, "Cannot open \"%s\": %s\n", optarg,
1766 if (errflg || argc == optind) {
1767 fprintf(stderr, "Usage: %s [-d] [-f filename] file " "[file ...]\n",
1774 for (i = optind; i < argc; i++) {
1776 if ((vdata = FindFile(vdatacwd, argv[i])) == NULL)
1779 if (vdata->vnode->type == vDirectory && !dflag) {
1781 ResetDirCursor(&cursor, vdata);
1783 while ((ep = ReadNextDir(&cursor, vdata)) != NULL) {
1785 if (!(nvdata = GetVnode(ntohl(ep->fid.vnode)))) {
1787 "Cannot find vnode " "entry for %s (%d)\n",
1788 ep->name, ntohl(ep->fid.vnode));
1794 printf("Residency locations for %s:\n", ep->name);
1796 if (nvdata->dumpdata)
1797 printf("Local disk (in dump " "file)\n");
1800 DumpAllResidencies(f, nvdata, vol);
1806 printf("Residency locations for %s:\n", argv[i]);
1808 if (vdata->dumpdata)
1809 printf("Local disk (in dump file)\n");
1812 DumpAllResidencies(f, vdata, vol);
1818 #else /* RESIDENCY */
1820 "The \"file\" command is not available in the non-"
1821 "MRAFS version of dumptool.\n");
1822 #endif /* RESIDENCY */
1827 * Take a vnode, traverse the vnode chain, and dump out all files on
1828 * all residencies corresponding to that parent vnode.
1833 DumpAllResidencies(FILE * f, struct vnodeData *vdata,
1834 struct VolumeDiskData *vol)
1836 unsigned int nextVnodeNum;
1838 while (nextVnodeNum = vdata->vnode->NextVnodeId) {
1839 if ((vdata = GetVnode(nextVnodeNum)) == NULL) {
1841 "We had a pointer to %lu in it's "
1842 "vnode chain, but there\nisn't a record of "
1843 "it! The dump might be corrupt.\n", nextVnodeNum);
1847 if (vdata->vnode->type == vFidLookup)
1848 DumpVnodeFile(f, vdata->vnode, vol);
1857 * Given a directory vnode and a filename, return the vnode corresponding
1858 * to the file in that directory.
1860 * We now handle pathnames with directories in them.
1863 static struct vnodeData *
1864 FindFile(struct vnodeData *vdatacwd, char *filename)
1866 struct DirHeader *dhp;
1867 struct DirEntry *ep;
1869 struct vnodeData *vdata;
1870 char *c, newstr[MAXPATHLEN];
1872 if (!vdatacwd->filedata) {
1873 fprintf(stderr, "There is no vnode data for this " "directory!\n");
1878 * If we have a "/" in here, look up the vnode data for the
1879 * directory (everything before the "/") and use that as our
1880 * current directory. We automagically handle multiple directories
1881 * by using FindFile recursively.
1884 if ((c = strrchr(filename, '/')) != NULL) {
1886 strncpy(newstr, filename, c - filename);
1887 newstr[c - filename] = '\0';
1889 if ((vdatacwd = FindFile(vdatacwd, newstr)) == NULL)
1892 if (vdatacwd->vnode->type != vDirectory) {
1893 fprintf(stderr, "%s: Not a directory\n", newstr);
1900 dhp = (struct DirHeader *)vdatacwd->filedata;
1902 i = DirHash(filename);
1904 num = ntohs(dhp->hashTable[i]);
1907 ep = (struct DirEntry *)(vdatacwd->filedata + (num * 32));
1908 if (strcmp(ep->name, filename) == 0)
1910 num = ntohs(ep->next);
1914 fprintf(stderr, "%s: No such file or directory\n", filename);
1918 if ((vdata = GetVnode(ntohl(ep->fid.vnode))) == NULL) {
1919 fprintf(stderr, "%s: No vnode information for %u found\n", filename,
1920 ntohl(ep->fid.vnode));
1928 * Reset a structure containing the current directory scan location
1932 ResetDirCursor(struct DirCursor *cursor, struct vnodeData *vdata)
1934 struct DirHeader *dhp;
1936 cursor->hashbucket = 0;
1938 dhp = (struct DirHeader *)vdata->filedata;
1940 cursor->entry = ntohs(dhp->hashTable[0]);
1944 * Given a cursor and a directory entry, return the next entry in the
1948 static struct DirEntry *
1949 ReadNextDir(struct DirCursor *cursor, struct vnodeData *vdata)
1951 struct DirHeader *dhp;
1952 struct DirEntry *ep;
1954 dhp = (struct DirHeader *)vdata->filedata;
1956 if (cursor->entry) {
1957 ep = (struct DirEntry *)(vdata->filedata + (cursor->entry * 32));
1958 cursor->entry = ntohs(ep->next);
1961 while (++(cursor->hashbucket) < NHASHENT) {
1962 cursor->entry = ntohs(dhp->hashTable[cursor->hashbucket]);
1963 if (cursor->entry) {
1964 ep = (struct DirEntry *)(vdata->filedata +
1965 (cursor->entry * 32));
1966 cursor->entry = ntohs(ep->next);
1976 * Given a string, split it up into components a la Unix argc/argv.
1978 * This code is most stolen from ftp.
1982 MakeArgv(char *string, int *argc, char ***argv)
1984 static char *largv[64];
1987 static char argbuf[CMDBUFSIZE];
1993 while ((*la++ = GetToken(s, &s, ap, &ap)) != NULL)
1998 * Return a pointer to the next token, and update the current string
2003 GetToken(char *string, char **nexttoken, char argbuf[], char *nextargbuf[])
2030 goto OUTTOKEN; /* End of our token */
2034 goto S2; /* Get next character */
2038 goto S3; /* Get quoted string */
2041 *ap++ = *sp++; /* Add a character to our token */
2077 *nextargbuf = ap; /* Update storage pointer */
2078 *nexttoken = sp; /* Update token pointer */
2080 return got_one ? argbuf : NULL;
2084 * Insert vnodes into our hash table.
2087 static struct vnodeData *
2088 InsertVnode(unsigned int vnodeNumber, struct VnodeDiskObject *vnode)
2090 struct VnodeDiskObject *nvnode;
2091 struct vnodeData *vdata;
2092 static int curSmallVnodeIndex = 0;
2093 static int curLargeVnodeIndex = 0;
2094 struct vnodeData ***vnodeIndex;
2097 nvnode = (struct VnodeDiskObject *)malloc(sizeof(struct VnodeDiskObject));
2101 fprintf(stderr, "Unable to allocate space for vnode\n");
2105 memcpy((void *)nvnode, (void *)vnode, sizeof(struct VnodeDiskObject));
2107 if (vnodeNumber & 1) {
2108 vnodeIndex = &LargeVnodeIndex;
2109 curIndex = &curLargeVnodeIndex;
2111 vnodeIndex = &SmallVnodeIndex;
2112 curIndex = &curSmallVnodeIndex;
2115 vdata = (struct vnodeData *)malloc(sizeof(struct vnodeData));
2117 vdata->vnode = nvnode;
2118 vdata->vnodeNumber = vnodeNumber;
2119 vdata->dumpdata = 0;
2120 vdata->filedata = 0;
2121 vdata->datalength = 0;
2123 (*vnodeIndex)[(*curIndex)++] = vdata;
2129 * Routine to retrieve a vnode from the hash table.
2132 static struct vnodeData *
2133 GetVnode(unsigned int vnodeNumber)
2135 struct vnodeData vnode, *vnodep, **tmp;
2137 vnode.vnodeNumber = vnodeNumber;
2140 tmp = (struct vnodeData **)
2141 bsearch((void *)&vnodep,
2142 vnodeNumber & 1 ? LargeVnodeIndex : SmallVnodeIndex,
2143 vnodeNumber & 1 ? numLargeVnodes : numSmallVnodes,
2144 sizeof(struct vnodeData *), CompareVnode);
2146 return tmp ? *tmp : NULL;
2150 * Our comparator function for bsearch
2154 CompareVnode(const void *node1, const void *node2)
2156 struct vnodeData **vnode1 = (struct vnodeData **)node1;
2157 struct vnodeData **vnode2 = (struct vnodeData **)node2;
2159 if ((*vnode1)->vnodeNumber == (*vnode2)->vnodeNumber)
2161 else if ((*vnode1)->vnodeNumber > (*vnode2)->vnodeNumber)
2169 * Dump out the filename corresponding to a particular vnode.
2171 * This routine has the following dependancies:
2173 * - Only will work on UFS filesystems at this point
2174 * - Has to talk to the rsserver.
2175 * - Can only determine UFS algorithm type when run on the same machine
2176 * as the residency (unless you manually specify algorithm information)
2180 DumpVnodeFile(FILE * f, struct VnodeDiskObject *vnode, VolumeDiskData * vol)
2182 static int rscache = 0;
2183 static rsaccessinfoList rsnlist = { 0, 0 };
2184 char MountPoint[MAXPATHLEN + 1];
2185 char FileName[MAXPATHLEN + 1];
2186 unsigned int Size, Level[4];
2187 unsigned int DeviceTag, Algorithm;
2188 FileSystems *FSInfo;
2189 int i, found, FSType, rsindex;
2192 * Maybe we found out something about this residency via the
2193 * command-line; check that first.
2196 rsindex = ffs(VLkp_Residencies(vnode)) - 1;
2199 * We need to get information from the rsserver (so we can
2200 * find out the device tag for a given residency). If we
2201 * haven't cached that, talk to the rsserver to get it.
2202 * If we have info about this already, then don't talk to
2203 * the rsserver (this lets us still do disaster recovery if
2204 * MR-AFS is completely hosed).
2207 if (!rscache && rscmdlineinfo[rsindex].DeviceTag == -1) {
2210 code = ServerInitResidencyConnection();
2214 "ServerInitResidencyConnection failed " "with code %d\n",
2219 code = rs_GetResidencySummary(ServerRequestorId, &rsnlist);
2222 fprintf(stderr, "rs_GetResidencySummary failed " "with code %d\n",
2231 * For a given residency (as specified in the vnode),
2232 * find out it's device tag number, either via the rsserver
2233 * or via the command line.
2236 if (rscmdlineinfo[rsindex].DeviceTag != -1) {
2237 DeviceTag = rscmdlineinfo[rsindex].DeviceTag;
2240 for (i = 0, found = 0; (i < rsnlist.rsaccessinfoList_len) && (!found);
2242 if (rsnlist.rsaccessinfoList_val[i].id.residency ==
2243 VLkp_Residencies(vnode)) {
2245 DeviceTag = rsnlist.rsaccessinfoList_val[i].devicetagnumber;
2253 "Unable to find residency %d in "
2254 "rsserver database, aborting\n", VLkp_Residencies(vnode));
2259 * Okay, now we've got the DeviceTag ... which we can use to
2260 * lookup the on-disk configuration information (which we
2261 * assume is locally stored). We also need the DeviceTag to
2262 * print out which partition we're using (but that comes later).
2264 * We lookup the on-disk configuration information by calling
2265 * Ufs_GetFSInfo() to get the configuration information on the
2266 * filesystems specified by the given DeviceTag.
2268 * Before we call Ufs_GetFSInfo, check the command-line cache;
2269 * if we got something via the command-line, don't go to disk.
2272 if (rscmdlineinfo[rsindex].FSType == -1
2273 && Ufs_GetFSInfo(&FSInfo, DeviceTag)) {
2276 "Ufs_GetFSInfo failed for DeviceTag "
2277 "%d, Residency %d\n", DeviceTag, VLkp_Residencies(vnode));
2282 * The FSInfo structure has the last two things we need: the
2283 * FSType (ufs, slowufs, etc etc), and the usage algorithm (which
2284 * ends up being how many directories are being used on the
2285 * residency filesystem).
2287 * With these last two parameters, use routines stolen from
2288 * ufsname to generate the filename.
2290 * (Actually, I lied - we also need the "Size" parameter, which
2291 * we can also get from FSInfo);
2294 if (rscmdlineinfo[rsindex].FSType != -1) {
2295 FSType = rscmdlineinfo[rsindex].FSType;
2296 Algorithm = rscmdlineinfo[rsindex].Algorithm;
2297 Size = rscmdlineinfo[rsindex].Size;
2299 FSType = FSInfo->FileSystems_u.UfsInterface.FSType;
2300 Algorithm = FSInfo->FileSystems_u.UfsInterface.Algorithm;
2301 if (FSInfo->FileSystems_u.UfsInterface.Directories[1] == 0)
2303 else if (FSInfo->FileSystems_u.UfsInterface.Directories[1] == 16)
2305 else if (FSInfo->FileSystems_u.UfsInterface.Directories[1] == 256)
2309 fprintf(stderr, "Unknown directory size %d, " "aborting\n",
2310 FSInfo->FileSystems_u.UfsInterface.Directories[1]);
2316 * First, generate our mount point from the DeviceTag and
2320 DEVICETAGNUMBERTOMOUNTPOINT(MountPoint, DeviceTag, FSType);
2323 * Then, generate the "level" (directory bitmasks) from the
2324 * file tags, size, and algorithm
2327 UfsTagsToLevel(VLkp_FileTag1(vnode), VLkp_FileTag2(vnode), Algorithm,
2328 Size, Level, VLkp_ParentVnodeId(vnode),
2329 VLkp_ParentUniquifierId(vnode));
2332 * Finally, take the above information and generate the
2333 * corresponding filename (this macro ends up being a
2337 TAGSTONAME(FileName, MountPoint, Level, Directories[Size][1],
2338 vol->parentId, VLkp_ParentVnodeId(vnode),
2339 VLkp_ParentUniquifierId(vnode), Algorithm);
2341 fprintf(f, "%s\n", FileName);
2348 * Read a 16 bit integer in network order
2352 ReadInt16(FILE * f, unsigned short *s)
2356 if (fread((void *)&in, sizeof(in), 1, f) != 1) {
2358 fprintf(stderr, "ReadInt16 failed!\n");
2369 * Read a 32 bit integer in network order
2373 ReadInt32(FILE * f, unsigned int *i)
2377 if (fread((void *)&in, sizeof(in), 1, f) != 1) {
2379 fprintf(stderr, "ReadInt32 failed!\n");
2383 *i = ntohl((unsigned long)in);
2389 * Read a string from a dump file
2393 ReadString(FILE * f, char *string, int maxlen)
2398 if ((*string++ = getc(f)) == 0)
2403 * I'm not sure what the _hell_ this is supposed to do ...
2404 * but it was in the original dump code
2408 while ((c = getc(f)) && c != EOF);
2416 ReadByteString(FILE * f, void *s, int size)
2418 unsigned char *c = (unsigned char *)s;
2427 * The directory hashing algorithm used by AFS
2431 DirHash(char *string)
2433 /* Hash a string to a number between 0 and NHASHENT. */
2438 while ((tc = (*string++)) != '\0') {
2442 tval = hval & (NHASHENT - 1);
2443 #ifdef AFS_CRAY_ENV /* actually, any > 32 bit environment */
2446 else if (hval & 0x80000000)
2447 tval = NHASHENT - tval;
2448 #else /* AFS_CRAY_ENV */
2452 tval = NHASHENT - tval;
2453 #endif /* AFS_CRAY_ENV */
2459 * Sigh, we need this for the AFS libraries
2463 LogErrors(int level, char *a, char *b, char *c, char *d, char *e, char *f,
2464 char *g, char *h, char *i, char *j, char *k)
2467 fprintf(stderr, a, b, c, d, e, f, g, h, i, j, k);
2473 * These are routines taken from AFS libraries and programs. Most of
2474 * them are from ufsname.c, but a few are from the dir library (the dir
2475 * library has a bunch of hidden dependancies, so it's not suitable to
2476 * include it outright).
2479 UfsEntropiesToTags(HighEntropy, LowEntropy, Algorithm, FileTag1, FileTag2)
2480 uint32_t HighEntropy;
2481 uint32_t LowEntropy;
2488 if ((Algorithm > UFS_ALGORITHMS) || (Algorithm <= 0))
2492 for (i = 0; i < 32; ++i) {
2493 if (UfsEntropy[Algorithm - 1][i] < 32)
2495 ((HighEntropy & (1 << i)) ==
2496 0) ? 0 : 1 << UfsEntropy[Algorithm - 1][i];
2499 ((HighEntropy & (1 << i)) ==
2500 0) ? 0 : 1 << (UfsEntropy[Algorithm - 1][i] - 32);
2502 for (i = 32; i < 64; ++i) {
2503 if (UfsEntropy[Algorithm - 1][i] < 32)
2505 ((LowEntropy & (1 << (i - 32))) ==
2506 0) ? 0 : 1 << UfsEntropy[Algorithm - 1][i];
2509 ((LowEntropy & (1 << (i - 32))) ==
2510 0) ? 0 : 1 << (UfsEntropy[Algorithm - 1][i] - 32);
2516 UfsTagsToHighEntropy(FileTag1, FileTag2, Algorithm)
2525 for (i = 0; i < 32; ++i) {
2526 if (UfsEntropy[Algorithm - 1][i] < 32)
2527 Value |= ((FileTag1 & (1 << UfsEntropy[Algorithm - 1][i]))
2531 ((FileTag2 & (1 << (UfsEntropy[Algorithm - 1][i] - 32))) ==
2538 UfsTagsToLowEntropy(FileTag1, FileTag2, Algorithm)
2547 for (i = 32; i < 64; ++i) {
2548 if (UfsEntropy[Algorithm - 1][i] < 32)
2549 Value |= ((FileTag1 & (1 << UfsEntropy[Algorithm - 1][i]))
2550 == 0) ? 0 : 1 << (i - 32);
2553 ((FileTag2 & (1 << (UfsEntropy[Algorithm - 1][i] - 32))) ==
2554 0) ? 0 : 1 << (i - 32);
2559 UfsTagsToLevel(FileTag1, FileTag2, Algorithm, Size, Sections, vnode,
2565 uint32_t Sections[4];
2567 uint32_t Uniquifier;
2569 uint32_t HighEntropy;
2570 uint32_t LowEntropy;
2572 switch (Algorithm) {
2574 LowEntropy = UfsTagsToLowEntropy(FileTag1, FileTag2, Algorithm);
2575 HighEntropy = UfsTagsToHighEntropy(FileTag1, FileTag2, Algorithm);
2576 Sections[0] = HighEntropy % Directories[Size][0];
2577 HighEntropy /= Directories[Size][0];
2578 if (Directories[Size][1]) {
2579 Sections[1] = HighEntropy % Directories[Size][1];
2580 HighEntropy /= Directories[Size][1];
2581 Sections[2] = HighEntropy;
2582 Sections[3] = LowEntropy;
2584 Sections[1] = HighEntropy;
2585 Sections[2] = LowEntropy;
2589 Sections[0] = FileTag1 & 0xff;
2590 if (Directories[Size][1]) {
2591 Sections[1] = Uniquifier & 0xff;
2592 if (Directories[Size][1] == 16)
2594 Sections[2] = FileTag1;
2595 Sections[3] = FileTag2;
2597 Sections[1] = FileTag1;
2598 Sections[2] = FileTag2;
2602 Sections[0] = FileTag1 & 0xff;
2603 if (Directories[Size][1]) {
2604 Sections[1] = (vnode >> 1) & 0xff;
2605 if (Directories[Size][1] == 16)
2607 Sections[2] = FileTag1;
2608 Sections[3] = FileTag2;
2610 Sections[1] = FileTag1;
2611 Sections[2] = FileTag2;
2615 fprintf(stderr, "UfsTagsToLevel: bad algorithm %lu!\n", Algorithm);
2621 #include <afs/afscbdummies.h>
2622 #endif /* RESIDENCY */