4 * dumptool - A tool to manage MR-AFS dump files
6 * The dump file format ought to be documented _somewhere_, and
7 * this seems like a good as a place as any ...
9 * A AFS dump file is marked off into a series of sections. Each
10 * section marked by a dump tag. A tag is a single byte who's value
11 * corresponds with the next section. The sections are (in order):
13 * DUMPHEADER (tag 0x01)
14 * VOLUMEHEADER (tag 0x02)
18 * Descriptions of the sections follow. Note that in all cases, data is
19 * stored in the dump in network byte order.
23 * DUMPHEADER contains two parts: the DUMPMAGIC magic number (32 bits)
24 * and the dump header itself.
26 * The dump header itself consists of a series of tagged values,
27 * each tag marking out members of the DumpHeader structure. The
28 * routine ReadDumpHeader explains the specifics of these tags.
32 * VOLUMEHEADER is a series of tagged values corresponding to the elements
33 * of the VolumeDiskData structure. See ReadVolumeHeader for more
38 * The VNODE section is all vnodes contained in the volume (each vnode
39 * itself is marked with the VNODE tag, so it's really a sequence of
40 * VNODE tags, unlike other sections).
42 * Each vnode consists of three parts: the vnode number (32 bits), the
43 * uniqifier (32 bits), and a tagged list of elements corresponding to
44 * the elements of the VnodeDiskData structure. See ScanVnodes for
45 * more information. Note that if file data is associated with a vnode,
46 * it will be contained here.
50 * The DUMPEND section consists of one part: the DUMPENDMAGIC magic
55 * The tagged elements are all ASCII letters, as opposed to the section
56 * headers (which are 0x01, 0x02, ...). Thus, an easy way to tell when
57 * you've reached the end of an element sequence is to check to see if
58 * the next tag is a printable character (this code tests for < 20).
60 * "vos dump" dumps the large vnode index, then the small vnode index,
61 * so directories will appear first in the VNODE section.
64 #include <afsconfig.h>
65 #include <afs/param.h>
68 #include <sys/types.h>
69 #include <sys/param.h>
70 #include <netinet/in.h>
78 #include <sys/ioctl.h>
80 #include <rx/rx_queue.h>
82 #include <afs/afsint.h>
85 #if !defined(PRE_AFS_36) && !defined(RESIDENCY)
86 #include <afs/ihandle.h>
87 #endif /* !defined(PRE_AFS_36) && !defined(RESIDENCY) */
88 #include <afs/vnode.h>
89 #include <afs/volume.h>
91 #ifdef AFS_LINUX24_ENV
92 #define _LARGEFILE64_SOURCE 1
95 #include <afs/rsdefs.h>
96 #include <afs/remioint.h>
97 #endif /* RESIDENCY */
102 typedef off_t off64_t;
103 #endif /* !HAVE_OFF64_T */
104 #ifndef HAVE_FSEEKO64
105 #define fseeko64 fseeko
106 #endif /* HAVE_FSEEKO64 */
107 #ifndef HAVE_FTELLO64
108 #define ftello64 ftello
109 #endif /* HAVE_FTELLO64 */
112 * Sigh. Linux blows it again
120 * Stuff that is in private AFS header files, unfortunately
123 #define DUMPVERSION 1
124 #define DUMPENDMAGIC 0x3A214B6E
125 #define DUMPBEGINMAGIC 0xB3A11322
126 #define D_DUMPHEADER 1
127 #define D_VOLUMEHEADER 2
132 #define MAXDUMPTIMES 50
137 char volumeName[VNAMESIZE];
138 int nDumpTimes; /* Number of pairs */
141 } dumpTimes[MAXDUMPTIMES];
145 * Our command-line arguments
150 int Algorithm; /* Conversion algorithm */
151 int Size; /* Directory hierarchy size */
152 int FSType; /* File system type */
153 int DeviceTag; /* Device Tag */
154 } rscmdlineinfo[RS_MAXRESIDENCIES];
157 * This stuff comes from ufsname.c (which itself takes it from
161 /* There is an assumption that all of the prefixes will have exactly one '/' */
162 static char *Ufs_Prefixes[] = { "/ufs", "/slowufs", "/cdmf", "/sdmf" };
164 #define MAX_ITERATIONS 10
165 #define UFS_SUMMARYTREENAME "Summaries"
166 #define UFS_STAGINGTREENAME "Staging"
167 #define UFS_VOLUMEHEADERTREENAME "VolHeaders"
168 #define UFS_VOLUMETREENAME "Volumes"
169 #define UFS_ALGORITHMBASE 'A'
170 #define UFS_MOUNTPOINTBASE 'a'
171 #define UFS_ALGORITHMS 3
172 #define UFS_LINK_MAX 64 /* Arbitrary. */
173 #define HARD_LINKED_FILE -2
174 #define TAGSTONAME(FileName, MountPoint, Sections, Level1, RWVolume, Vnode, Uniquifier, Algorithm) \
177 sprintf(FileName,"%s/%lu/%lu/%c%lu.%lu.%lu.%lu.%lu", MountPoint, \
178 (Sections)[0], (Sections)[1], UFS_ALGORITHMBASE + Algorithm, \
179 (Sections)[2], (Sections)[3], RWVolume, Vnode, Uniquifier); \
181 sprintf(FileName,"%s/%lu/%c%lu.%lu.%lu.%lu.%lu", MountPoint, \
182 (Sections)[0], UFS_ALGORITHMBASE + Algorithm, \
183 (Sections)[1], (Sections)[2], RWVolume, Vnode, Uniquifier); \
185 #define TAGSTOSTAGINGNAME(FileName, MountPoint, RWVolume, Vnode, Uniquifier) \
186 sprintf(FileName,"%s/%s/%lu.%lu.%lu", MountPoint, \
187 UFS_STAGINGTREENAME, RWVolume, Vnode, Uniquifier)
188 #define TAGSTOVOLUMEHEADERNAME(FileName, MountPoint, FileTag1, FileTag2) \
189 sprintf(FileName,"%s/%s/%lu", MountPoint, UFS_VOLUMEHEADERTREENAME, \
191 #define TAGSTOVOLUMEINFONAME(FileName, MountPoint, FileTag1, FileTag2) \
192 sprintf(FileName,"%s/%s/%lu/%lu", MountPoint, \
193 UFS_VOLUMETREENAME, FileTag2, FileTag1)
194 #define TAGSTOVOLUMENAME(FileName, MountPoint, FileTag1, FileTag2, RWVolume) \
195 sprintf(FileName,"%s/%s/%lu/%lu.%lu", MountPoint, \
196 UFS_VOLUMETREENAME, FileTag2, FileTag1, RWVolume)
197 #define TAGSTOSUMMARYNAME(FileName, MountPoint, FileTag1, FileTag2, SummaryRequestor, Residency) \
198 sprintf(FileName,"%s/%s/%lu.%lu.%lu.%lu", MountPoint, \
199 UFS_SUMMARYTREENAME, FileTag1, FileTag2, SummaryRequestor, \
201 #define DEVICETAGNUMBERTOMOUNTPOINT(MountPoint, DeviceTagNumber, FSType) \
202 sprintf(MountPoint,"%s%c", Ufs_Prefixes[FSType], UFS_MOUNTPOINTBASE + \
204 #define MOUNTPOINTTODEVICETAGNUMBER(MountPoint) \
205 MountPoint[strlen(MountPoint) - 1] - UFS_MOUNTPOINTBASE
206 #define DEVICETAGNUMBERTOVOLUMEHEADERTREE(TreeName, MountPoint) \
207 sprintf(TreeName,"%s/%s", MountPoint, UFS_VOLUMEHEADERTREENAME)
208 #define UFS_RESIDENCIES_FILE "Residencies"
210 /* We don't ever want to map to uid/gid -1. fchown() takes that as a
211 don't change flag. We know however that volume number range from
212 0x2000000 to 0x20FFFFFF (see VAllocateVolumeId() in vol/vutil.c)
213 so we will use that to insure that -1 never appears. */
214 #define RWVolumeToUid(RWVolume) ((RWVolume >> 12) & 0xFFFF)
215 #define RWVolumeToGid(RWVolume) ((RWVolume & 0xFFF) | \
216 (((RWVolume >> 28) & 0xF) << 12))
217 #define UidGidToRWVolume(Uid, Gid) ((Gid & 0xFFF) | ((Uid & 0xFFFF) << 12) | \
218 ((Gid & 0xF000) << 16))
221 /* These routines generate a file name to correspond to the given tag
224 /* The following entropy array contains the order of bits from highest entropy
225 to lowest in the numbers FileTag1 and FileTag2. Bit numbers 32 and above
226 correspond to FileTag2. This ordering was determined by examining all read-
227 write volumes in the psc.edu cell. */
228 char UfsEntropy[1][64] = {
229 {1, 2, 3, 4, 33, 5, 6, 7, 44, 45, 46, 36, 8, 34, 42, 35,
230 9, 40, 38, 32, 43, 10, 39, 37, 11, 41, 12, 13, 14, 0,
231 15, 16, 61, 17, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51,
232 50, 49, 48, 47, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22,
233 21, 20, 19, 18, 62, 63},
236 uint32_t Directories[3][2] = { {256, 0}, {256, 16}, {256, 256}, };
237 #endif /* RESIDENCY */
239 static int verbose = 0;
240 static int numNoDirData = 0;
241 static int termsize = 0;
244 extern resid ServerRequestorId;
245 #endif /* RESIDENCY */
248 * We use this structure to hold vnode data in our hash table.
249 * It's indexed by vnode number.
253 struct VnodeDiskObject *vnode; /* A pointer to the disk vnode */
254 int vnodeNumber; /* The vnode number */
255 off64_t dumpdata; /* File offset of dump data (if
257 unsigned char *filedata; /* A pointer to the actual file
258 * data itself (if available) */
259 unsigned int datalength; /* The length of the data */
263 * This contains the current location when we're doing a scan of a
268 int hashbucket; /* Current hash bucket */
269 int entry; /* Entry within hash bucket */
273 * Arrays to hold vnode data
276 struct vnodeData **LargeVnodeIndex;
277 struct vnodeData **SmallVnodeIndex;
278 int numLargeVnodes = 0;
279 int numSmallVnodes = 0;
282 * Crap for the libraries
285 int ShutdownInProgress = 0;
288 * Our local function prototypes
291 static int DirHash(char *string);
292 static int ReadDumpHeader(FILE *, struct DumpHeader *);
293 static int ReadVolumeHeader(FILE *, VolumeDiskData *);
294 static int ScanVnodes(FILE *, VolumeDiskData *, int);
295 static struct vnodeData *InsertVnode(unsigned int, struct VnodeDiskObject *);
296 static struct vnodeData *GetVnode(unsigned int);
297 static int CompareVnode(const void *, const void *);
298 static void InteractiveRestore(FILE *, VolumeDiskData *);
299 static void DirectoryList(int, char **, struct vnodeData *, VolumeDiskData *);
300 static void DirListInternal(struct vnodeData *, char *[], int, int, int, int,
301 int, int, VolumeDiskData *, char *);
302 static int CompareDirEntry(const void *, const void *);
303 static struct vnodeData *ChangeDirectory(int, char **, struct vnodeData *);
304 static void CopyFile(int, char **, struct vnodeData *, FILE *);
305 static void CopyVnode(int, char **, FILE *);
306 static void DumpAllFiles(int, char **, struct vnodeData *, VolumeDiskData *);
307 static struct vnodeData *FindFile(struct vnodeData *, char *);
308 static void ResetDirCursor(struct DirCursor *, struct vnodeData *);
309 static struct DirEntry *ReadNextDir(struct DirCursor *, struct vnodeData *);
310 static void MakeArgv(char *, int *, char ***);
311 static char *GetToken(char *, char **, char *, char *[]);
312 static int ReadInt16(FILE *, uint16_t *);
313 static int ReadInt32(FILE *, uint32_t *);
314 static int ReadString(FILE *, char *, int);
315 static int ReadByteString(FILE *, void *, int);
318 static int DumpVnodeFile(FILE *, struct VnodeDiskObject *, VolumeDiskData *);
319 static void DumpAllResidencies(FILE *, struct vnodeData *, VolumeDiskData *);
323 main(int argc, char *argv[])
325 int c, errflg = 0, force = 0, inode = 0;
327 struct DumpHeader dheader;
331 int Res, Arg1, Arg2, Arg3, i;
341 for (i = 0; i < RS_MAXRESIDENCIES; i++) {
342 rscmdlineinfo[i].Algorithm = -1;
343 rscmdlineinfo[i].Size = -1;
344 rscmdlineinfo[i].DeviceTag = -1;
345 rscmdlineinfo[i].FSType = -1;
347 #endif /* RESIDENCY */
350 * Sigh, this is dumb, but we need the terminal window size
351 * to do intelligent things with "ls" later on.
354 if (isatty(STDOUT_FILENO)) {
355 if ((p = getenv("COLUMNS")) != NULL)
357 else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0
359 termsize = win.ws_col;
362 while ((c = getopt(argc, argv, "difr:t:v")) != EOF)
366 if (sscanf(optarg, "%d/%d", &Res, &Arg1) != 2) {
371 if (1 << (ffs(Res) - 1) != Res) {
372 fprintf(stderr, "Invalid residency %d\n", Res);
377 if (Arg1 < 0 || Arg1 > 26) {
378 fprintf(stderr, "Invalid device tag: %d\n", Arg1);
382 rscmdlineinfo[ffs(Res) - 1].DeviceTag = Arg1;
383 #else /* RESIDENCY */
384 fprintf(stderr, "-t not supported in non-MRAFS " "dumptool.\n");
386 #endif /* RESIDENCY */
391 if (sscanf(optarg, "%d/%d/%d/%d", &Res, &Arg1, &Arg2, &Arg3) != 4) {
396 if (Arg1 < 0 || Arg1 > 3) {
397 fprintf(stderr, "Invalid fstype: %d\n", Arg1);
402 if (Arg2 < 0 || Arg2 > 2) {
403 fprintf(stderr, "Invalid size: %d\n", Arg2);
408 if (Arg3 <= 0 || Arg3 > UFS_ALGORITHMS) {
409 fprintf(stderr, "Invalid algorithm: %d\n", Arg3);
413 rscmdlineinfo[ffs(Res) - 1].FSType = Arg1;
414 rscmdlineinfo[ffs(Res) - 1].Size = Arg2;
415 rscmdlineinfo[ffs(Res) - 1].Algorithm = Arg3;
416 #else /* RESIDENCY */
417 fprintf(stderr, "-r not supported in non-MRAFS " "dumptool.\n");
419 #endif /* RESIDENCY */
424 #else /* RESIDENCY */
425 fprintf(stderr, "-d not supported in non-MRAFS " "dumptool.\n");
427 #endif /* RESIDENCY */
443 if (errflg || optind == argc) {
444 fprintf(stderr, "Usage: %s\n\t[-v] [-f]\n\t"
446 "[-t Residency/Tag]\n\t"
447 "[-r Residency/Type/Size/Algorithm]\n\t"
448 "[-d] filename [file_in_dump [file in dump ...]]\n",
449 #else /* RESIDENCY */
451 #endif /* RESIDENCY */
457 * Try opening the dump file
461 if ((fd = open(argv[optind], O_RDONLY | O_LARGEFILE)) < 0) {
463 if ((fd = open(argv[optind], O_RDONLY)) < 0) {
465 fprintf(stderr, "open of dumpfile %s failed: %s\n", argv[optind],
470 if ((f = fdopen(fd, "rb")) == NULL) {
471 fprintf(stderr, "fdopen of dumpfile %s failed: %s\n", argv[optind],
476 if (ReadDumpHeader(f, &dheader)) {
477 fprintf(stderr, "Failed to read dump header!\n");
482 printf("Dump is for volume %lu (%s)\n",
483 (unsigned long) dheader.volumeId, dheader.volumeName);
485 if (getc(f) != D_VOLUMEHEADER) {
486 fprintf(stderr, "Volume header is missing from dump, aborting\n");
490 if (ReadVolumeHeader(f, &vol)) {
491 fprintf(stderr, "Unable to read volume header\n");
496 printf("Volume information:\n");
497 printf("\tid = %lu\n", (unsigned long) vol.id);
498 printf("\tparent id = %lu\n", (unsigned long) vol.parentId);
499 printf("\tname = %s\n", vol.name);
504 printf(" inService");
507 if (vol.needsSalvaged)
508 printf(" needsSalvaged");
510 printf("\tuniquifier = %lu\n", (unsigned long) vol.uniquifier);
511 tmv = vol.creationDate;
512 printf("\tCreation date = %s", ctime(&tmv));
513 tmv = vol.accessDate;
514 printf("\tLast access date = %s", ctime(&tmv));
515 tmv = vol.updateDate;
516 printf("\tLast update date = %s", ctime(&tmv));
517 printf("\tVolume owner = %lu\n", (unsigned long) vol.owner);
521 printf("Scanning vnodes (this may take a while)\n");
524 * We need to do two vnode scans; one to get the number of
525 * vnodes, the other to actually build the index.
528 offset = ftello64(f);
530 if (ScanVnodes(f, &vol, 1)) {
531 fprintf(stderr, "First vnode scan failed, aborting\n");
535 fseeko64(f, offset, SEEK_SET);
537 if (ScanVnodes(f, &vol, 0)) {
538 fprintf(stderr, "Second vnode scan failed, aborting\n");
542 if (getc(f) != D_DUMPEND || ReadInt32(f, &magic) || magic != DUMPENDMAGIC) {
543 fprintf(stderr, "Couldn't find dump postamble, ");
545 fprintf(stderr, "aborting (use -f to override)\n");
548 fprintf(stderr, "continuing anyway\n");
549 fprintf(stderr, "WARNING: Dump may not be complete!\n");
554 * If we wanted to simply dump all vnodes, do it now
559 struct vnodeData *vdata;
561 for (i = 0; i < numLargeVnodes; i++) {
563 vdata = LargeVnodeIndex[i];
565 if (vdata->vnode->type == vFidLookup)
566 if (DumpVnodeFile(stdout, vdata->vnode, &vol)) {
567 fprintf(stderr, "DumpVnodeFile failed, " "aborting\n");
572 for (i = 0; i < numSmallVnodes; i++) {
574 vdata = SmallVnodeIndex[i];
576 if (vdata->vnode->type == vFidLookup)
577 if (DumpVnodeFile(stdout, vdata->vnode, &vol)) {
578 fprintf(stderr, "DumpVnodeFile failed, " "aborting\n");
584 #endif /* RESIDENCY */
587 * Dump out all filenames with their corresponding FID
590 struct vnodeData *rootvdata;
592 if ((rootvdata = GetVnode(1)) == NULL) {
594 "Can't get vnode data for root " "vnode! Aborting\n");
598 DirListInternal(rootvdata, NULL, 0, 0, 1, 0, 1, 0, &vol, "");
600 } else if (argc > optind + 1) {
603 * Dump out residencies of files given on the command line.
606 struct vnodeData *vdata, *rootvdata;
608 if ((rootvdata = GetVnode(1)) == NULL) {
610 "Can't get vnode data for root " "vnode! Aborting\n");
614 for (i = optind + 1; i < argc; i++) {
616 if ((vdata = FindFile(rootvdata, argv[i])) == NULL) {
617 fprintf(stderr, "Skipping file %s\n", argv[i]);
622 printf("Residency locations for %s:\n", argv[i]);
624 while (vdata->vnode->NextVnodeId != 0) {
626 vdata = GetVnode(vdata->vnode->NextVnodeId);
630 "We had a vnode chain " "pointer to a vnode that "
631 "doesn't exist, aborting!\n");
634 if (vdata->vnode->type == vFidLookup)
635 DumpVnodeFile(stdout, vdata->vnode, &vol);
638 #else /* RESIDENCY */
639 fprintf(stderr, "Extra arguments after dump filename: %s\n",
642 #endif /* RESIDENCY */
645 * Perform an interactive restore
648 InteractiveRestore(f, &vol);
655 * Read the dump header, which is at the beginning of every dump
659 ReadDumpHeader(FILE * f, struct DumpHeader *header)
664 if (getc(f) != D_DUMPHEADER || ReadInt32(f, &magic)
665 || ReadInt32(f, (unsigned int *)
666 &header->version) || magic != DUMPBEGINMAGIC) {
668 fprintf(stderr, "Couldn't find dump magic numbers\n");
672 header->volumeId = 0;
673 header->nDumpTimes = 0;
675 while ((tag = getc(f)) > D_MAX && tag != EOF) {
676 unsigned short length;
679 if (ReadInt32(f, &header->volumeId)) {
681 fprintf(stderr, "Failed to read " "volumeId\n");
686 if (ReadString(f, header->volumeName, sizeof(header->volumeName))) {
688 fprintf(stderr, "Failed to read " "volume name\n");
693 if (ReadInt16(f, &length)) {
696 "Failed to read " "dump time array length\n");
699 header->nDumpTimes = (length >> 1);
700 for (i = 0; i < header->nDumpTimes; i++)
701 if (ReadInt32(f, (unsigned int *)
702 &header->dumpTimes[i].from)
703 || ReadInt32(f, (unsigned int *)
704 &header->dumpTimes[i].to)) {
706 fprintf(stderr, "Failed to " "read dump times\n");
712 fprintf(stderr, "Unknown dump tag \"%c\"\n", tag);
717 if (!header->volumeId || !header->nDumpTimes) {
720 "We didn't get a volume Id or " "dump times listing\n");
729 * Read the volume header; this is the information stored in VolumeDiskData.
731 * I'm not sure we need all of this, but read it in just in case.
735 ReadVolumeHeader(FILE * f, VolumeDiskData * vol)
739 memset((void *)vol, 0, sizeof(*vol));
741 while ((tag = getc(f)) > D_MAX && tag != EOF) {
744 if (ReadInt32(f, &vol->id))
748 if (ReadInt32(f, &trash))
752 if (ReadString(f, vol->name, sizeof(vol->name)))
756 vol->inService = getc(f);
759 vol->blessed = getc(f);
762 if (ReadInt32(f, &vol->uniquifier))
769 if (ReadInt32(f, &vol->parentId))
773 if (ReadInt32(f, &vol->cloneId))
777 if (ReadInt32(f, (uint32_t *) & vol->maxquota))
781 if (ReadInt32(f, (uint32_t *) & vol->minquota))
785 if (ReadInt32(f, (uint32_t *) & vol->diskused))
789 if (ReadInt32(f, (uint32_t *) & vol->filecount))
793 if (ReadInt32(f, &vol->accountNumber))
797 if (ReadInt32(f, &vol->owner))
801 if (ReadInt32(f, &vol->creationDate))
805 if (ReadInt32(f, &vol->accessDate))
809 if (ReadInt32(f, &vol->updateDate))
813 if (ReadInt32(f, &vol->expirationDate))
817 if (ReadInt32(f, &vol->backupDate))
822 (f, vol->offlineMessage, sizeof(vol->offlineMessage)))
826 if (ReadString(f, (char *)vol->stat_reads, VMSGSIZE))
830 unsigned short length;
833 if (ReadInt16(f, &length))
835 for (i = 0; i < length; i++) {
836 if (ReadInt32(f, &data))
838 if (i < sizeof(vol->weekUse) / sizeof(vol->weekUse[0]))
839 vol->weekUse[i] = data;
844 if (ReadInt32(f, &vol->dayUseDate))
848 if (ReadInt32(f, (uint32_t *) & vol->dayUse))
853 unsigned short length;
857 if (ReadInt16(f, &length))
859 for (i = 0; i < length; i++) {
860 if (ReadInt32(f, &data))
863 sizeof(vol->DesiredInfo.DesiredResidencyWords) /
864 sizeof(vol->DesiredInfo.DesiredResidencyWords[0]))
865 vol->DesiredInfo.DesiredResidencyWords[i] = data;
870 unsigned short length;
874 if (ReadInt16(f, &length))
876 for (i = 0; i < length; i++) {
877 if (ReadInt32(f, &data))
880 sizeof(vol->UnDesiredInfo.UnDesiredResidencyWords) /
881 sizeof(vol->UnDesiredInfo.UnDesiredResidencyWords[0]))
882 vol->UnDesiredInfo.UnDesiredResidencyWords[i] = data;
889 fprintf(stderr, "Unknown dump tag \"%c\"\n", tag);
899 * Scan all our vnode entries, and build indexing information.
903 ScanVnodes(FILE * f, VolumeDiskData * vol, int sizescan)
907 int numFileVnodes = 0;
908 int numDirVnodes = 0;
909 unsigned char buf[SIZEOF_LARGEDISKVNODE];
910 struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)buf;
911 off64_t offset, oldoffset;
912 struct vnodeData *vdata;
917 while (tag == D_VNODE) {
924 if (ReadInt32(f, (uint32_t *) & vnodeNumber)) {
925 fprintf(stderr, "failed int32 for 'vnodenum'\n");
929 if (ReadInt32(f, &vnode->uniquifier)) {
930 fprintf(stderr, "failed int32 for 'uniquifier'\n");
934 if (verbose > 1 && !sizescan)
935 printf("Got vnode %d\n", vnodeNumber);
937 while ((tag = getc(f)) > D_MAX && tag != EOF)
940 vnode->type = (VnodeType) getc(f);
945 if (ReadInt16(f, &tmp)) {
946 fprintf(stderr, "failed int16 for 'l'\n");
949 vnode->linkCount = tmp;
953 if (ReadInt32(f, &vnode->dataVersion)) {
954 fprintf(stderr, "failed int32 for 'v'\n");
959 if (ReadInt32(f, (uint32_t *) & vnode->unixModifyTime)) {
960 fprintf(stderr, "failed int32 for 'm'\n");
965 if (ReadInt32(f, (uint32_t *) & vnode->serverModifyTime)) {
966 fprintf(stderr, "failed int32 for 's'\n");
971 if (ReadInt32(f, &vnode->author)) {
972 fprintf(stderr, "failed int32 for 'a'\n");
977 if (ReadInt32(f, &vnode->owner)) {
978 fprintf(stderr, "failed int32 for 'o'\n");
983 if (ReadInt32(f, (uint32_t *) & vnode->group)) {
984 fprintf(stderr, "failed int32 for 'g'\n");
989 unsigned short modeBits;
990 if (ReadInt16(f, &modeBits))
992 vnode->modeBits = modeBits;
996 if (ReadInt32(f, &vnode->parent)) {
997 fprintf(stderr, "failed int32 for 'p'\n");
1003 if (ReadInt32(f, &vnode->NextVnodeId)) {
1004 fprintf(stderr, "failed int32 for 'N'\n");
1009 if (ReadInt32(f, &VLkp_Residencies(vnode))) {
1010 fprintf(stderr, "failed int32 for 'R'\n");
1016 if (ReadInt32(f, &vnode->length)) {
1017 fprintf(stderr, "failed int32 for 'S'\n");
1022 if (ReadInt32(f, (uint32_t *) & vnode->vn_ino_lo))
1027 (f, (void *)VVnodeDiskACL(vnode), VAclDiskSize(vnode))) {
1028 fprintf(stderr, "failed readbystring for 'A'\n");
1032 acl_NtohACL(VVnodeDiskACL(vnode));
1037 if (ReadInt32(f, &vnode->length_hi)) {
1038 fprintf(stderr, "failed int32 for 'h'\n");
1043 if (verbose > 1 && !sizescan)
1044 printf("We have file data!\n");
1045 if (ReadInt32(f, &length)) {
1046 fprintf(stderr, "failed int32 for 'f'\n");
1049 vnode->length = length;
1050 offset = ftello64(f);
1051 fseeko64(f, length, SEEK_CUR);
1055 fprintf(stderr, "Unknown dump tag \"%c\"\n", tag);
1060 * If we're doing an incremental restore, then vnodes
1061 * will be listed in the dump, but won't contain any
1062 * vnode information at all (I don't know why they're
1063 * included _at all_). If we get one of these vnodes, then
1064 * just skip it (because we can't do anything with it.
1067 if (vnode->type == -1)
1071 if (verbose > 1 && vnode->type == vFidLookup && !sizescan) {
1073 ("This is an auxiliary vnode (lookup) for vnode %d, residency %d\n",
1074 VLkp_ParentVnodeId(vnode), VLkp_Residencies(vnode));
1075 if (DumpVnodeFile(stdout, vnode, vol))
1079 if (verbose > 1 && vnode->type == vAccessHistory && !sizescan)
1080 printf("This is an auxiliary vnode (history) for vnode %d\n",
1081 VLkp_ParentVnodeId(vnode));
1084 if (vnode->type == vDirectory)
1090 * We know now all we would ever know about the vnode;
1091 * insert it into our hash table (but only if we're not
1092 * doing a vnode scan).
1097 vdata = InsertVnode(vnodeNumber, vnode);
1099 if (vdata == NULL) {
1102 "Failed to insert " "vnode into hash table");
1106 vdata->dumpdata = offset;
1107 vdata->datalength = length;
1110 * Save directory data, since we'll need it later.
1113 if (vnode->type == vDirectory && length) {
1115 vdata->filedata = malloc(length);
1117 if (!vdata->filedata) {
1120 "Unable to " "allocate space for "
1121 "file data (%d)\n", length);
1125 oldoffset = ftello64(f);
1126 fseeko64(f, offset, SEEK_SET);
1128 if (fread(vdata->filedata, length, 1, f) != 1) {
1130 fprintf(stderr, "Unable to " "read in file data!\n");
1134 fseeko64(f, oldoffset, SEEK_SET);
1135 } else if (vnode->type == vDirectory)
1137 * Warn the user we may not have all directory
1148 numLargeVnodes = numDirVnodes;
1149 numSmallVnodes = numFileVnodes;
1152 if (numDirVnodes == 0)
1153 LargeVnodeIndex = NULL;
1155 LargeVnodeIndex = malloc(numDirVnodes
1156 * sizeof(struct vnodeData *));
1157 if (numFileVnodes == 0)
1158 SmallVnodeIndex = NULL;
1160 SmallVnodeIndex = malloc(numFileVnodes
1161 * sizeof(struct vnodeData *));
1163 if ((numDirVnodes != 0 && LargeVnodeIndex == NULL) ||
1164 (numFileVnodes != 0 && SmallVnodeIndex == NULL)) {
1167 "Unable to allocate space " "for vnode tables\n");
1173 fprintf(stderr, "%s vnode scan completed\n",
1174 sizescan ? "Primary" : "Secondary");
1180 * Perform an interactive restore
1182 * Parsing the directory information is a pain, but other than that
1183 * we just use the other tools we already have in here.
1185 #define CMDBUFSIZE (AFSPATHMAX * 2)
1187 InteractiveRestore(FILE * f, VolumeDiskData * vol)
1189 struct vnodeData *vdatacwd; /* Vnode data for our current dir */
1190 char cmdbuf[CMDBUFSIZE];
1195 * Let's see if we can at least get the data for our root directory.
1196 * If we can't, there's no way we can do an interactive restore.
1199 if ((vdatacwd = GetVnode(1)) == NULL) {
1200 fprintf(stderr, "No entry for our root vnode! Aborting\n");
1204 if (!vdatacwd->filedata) {
1206 "There is no directory data for the root "
1207 "vnode (1.1). An interactive\nrestore is not "
1213 * If you're doing a selective dump correctly, then you should get all
1214 * directory vnode data. But just in case you didn't, let the user
1215 * know there may be a problem.
1220 "WARNING: %d directory vnodes had no file "
1221 "data. An interactive restore\nmay not be possible\n",
1225 while (fgets(cmdbuf, CMDBUFSIZE, stdin)) {
1227 if (strlen(cmdbuf) > 0 && cmdbuf[strlen(cmdbuf) - 1] == '\n')
1228 cmdbuf[strlen(cmdbuf) - 1] = '\0';
1230 if (strlen(cmdbuf) == 0) {
1235 MakeArgv(cmdbuf, &argc, &argv);
1237 if (strcmp(argv[0], "ls") == 0) {
1238 DirectoryList(argc, argv, vdatacwd, vol);
1239 } else if (strcmp(argv[0], "cd") == 0) {
1240 struct vnodeData *newvdata;
1242 newvdata = ChangeDirectory(argc, argv, vdatacwd);
1245 vdatacwd = newvdata;
1246 } else if (strcmp(argv[0], "file") == 0) {
1247 DumpAllFiles(argc, argv, vdatacwd, vol);
1248 } else if (strcmp(argv[0], "cp") == 0) {
1249 CopyFile(argc, argv, vdatacwd, f);
1250 } else if (strcmp(argv[0], "vcp") == 0) {
1251 CopyVnode(argc, argv, f);
1252 } else if (strcmp(argv[0], "quit") == 0
1253 || strcmp(argv[0], "exit") == 0)
1255 else if (strcmp(argv[0], "?") == 0 || strcmp(argv[0], "help") == 0) {
1256 printf("Valid commands are:\n");
1257 printf("\tls\t\tList current directory\n");
1258 printf("\tcd\t\tChange current directory\n");
1259 printf("\tcp\t\tCopy file from dump\n");
1260 printf("\tvcp\t\tCopy file from dump (via vnode)\n");
1262 printf("\tfile\t\tList residency filenames\n");
1263 #endif /* RESIDENCY */
1264 printf("\tquit | exit\tExit program\n");
1265 printf("\thelp | ?\tBrief help\n");
1268 "Unknown command, \"%s\", enter "
1269 "\"help\" for a list of commands.\n", argv[0]);
1278 * Do a listing of all files in a directory. Sigh, I wish this wasn't
1281 * With the reorganizing, this is just a front-end to DirListInternal()
1285 DirectoryList(int argc, char **argv, struct vnodeData *vdata,
1286 VolumeDiskData * vol)
1288 int errflg = 0, lflag = 0, iflag = 0, Fflag = 0, sflag = 0, Rflag = 0;
1293 while ((c = getopt(argc, argv, "liFRs")) != EOF)
1315 fprintf(stderr, "Usage: %s [-liFs] filename [filename ...]\n",
1320 DirListInternal(vdata, &(argv[optind]), argc - optind, lflag, iflag,
1321 Fflag, Rflag, 1, vol, NULL);
1327 * Function that does the REAL work in terms of directory listing
1331 DirListInternal(struct vnodeData *vdata, char *pathnames[], int numpathnames,
1332 int lflag, int iflag, int Fflag, int Rflag, int verbose,
1333 VolumeDiskData * vol, char *path)
1335 struct DirEntry *ep, **eplist = NULL, **eprecurse = NULL;
1336 struct DirCursor cursor;
1337 struct vnodeData *lvdata;
1339 int i, j, numentries = 0, longestname = 0, numcols, col, numrows;
1342 if (!vdata->filedata) {
1343 fprintf(stderr, "There is no vnode data for this " "directory!\n");
1347 ResetDirCursor(&cursor, vdata);
1350 * Scan through the whole directory
1353 while ((ep = ReadNextDir(&cursor, vdata)) != NULL) {
1356 * If we didn't get any filenames on the command line,
1360 if (numpathnames == 0) {
1362 realloc(eplist, sizeof(struct DirEntry *) * ++numentries);
1363 eplist[numentries - 1] = ep;
1364 if (strlen(ep->name) > longestname)
1365 longestname = strlen(ep->name);
1367 if ((lvdata = GetVnode(ntohl(ep->fid.vnode)))
1368 && lvdata->vnode->type == vDirectory
1369 && !(strcmp(ep->name, ".") == 0
1370 || strcmp(ep->name, "..") == 0)) {
1373 sizeof(struct DirEntry *) * ++numrecurse);
1374 eprecurse[numrecurse - 1] = ep;
1379 * Do glob matching via fnmatch()
1382 for (i = 0; i < numpathnames; i++)
1383 if (fnmatch(pathnames[i], ep->name, FNM_PATHNAME) == 0) {
1386 sizeof(struct DirEntry *) * ++numentries);
1387 eplist[numentries - 1] = ep;
1388 if (strlen(ep->name) > longestname)
1389 longestname = strlen(ep->name);
1391 if ((lvdata = GetVnode(ntohl(ep->fid.vnode)))
1392 && lvdata->vnode->type == vDirectory
1393 && !(strcmp(ep->name, ".") == 0
1394 || strcmp(ep->name, "..") == 0)) {
1397 sizeof(struct DirEntry *) *
1399 eprecurse[numrecurse - 1] = ep;
1406 qsort((void *)eplist, numentries, sizeof(struct DirEntry *),
1409 if (Rflag && eprecurse)
1410 qsort((void *)eprecurse, numrecurse, sizeof(struct DirEntry *),
1413 * We don't have to do column printing if we have the -l or the -i
1414 * options. Sigh, column printing is WAY TOO FUCKING COMPLICATED!
1417 if (!lflag && !iflag) {
1425 numcols = termsize / longestname ? termsize / longestname : 1;
1426 numrows = numentries / numcols + (numentries % numcols ? 1 : 0);
1428 for (i = 0; i < numrows; i++) {
1430 while (col < numcols && (i + col * numrows) < numentries) {
1431 ep = eplist[i + col++ * numrows];
1433 if (!(lvdata = GetVnode(ntohl(ep->fid.vnode))))
1435 else if (lvdata->vnode->type == vDirectory)
1437 else if (lvdata->vnode->type == vSymlink)
1439 else if ((lvdata->vnode->modeBits & 0111) != 0)
1443 printf("%s%-*c", ep->name, (int)(longestname -
1444 strlen(ep->name)), c);
1446 printf("%-*s", longestname, ep->name);
1452 for (i = 0; i < numentries; i++)
1453 if (!(lvdata = GetVnode(ntohl(eplist[i]->fid.vnode))))
1454 printf("%" AFS_VOLID_FMT ".0.0\t%s\n",
1455 vol->parentId ? afs_printable_VolumeId_lu(vol->parentId)
1456 : afs_printable_VolumeId_lu(vol->id),
1459 printf("%" AFS_VOLID_FMT ".%d.%d\t%s/%s\n",
1460 afs_printable_VolumeId_lu(vol->id),
1461 ntohl(eplist[i]->fid.vnode),
1462 ntohl(eplist[i]->fid.vunique), path, eplist[i]->name);
1464 printf("%" AFS_VOLID_FMT ".%d.%d\t%s\n",
1465 afs_printable_VolumeId_lu(vol->id),
1466 ntohl(eplist[i]->fid.vnode),
1467 ntohl(eplist[i]->fid.vunique), eplist[i]->name);
1469 for (i = 0; i < numentries; i++)
1470 if (!(lvdata = GetVnode(ntohl(eplist[i]->fid.vnode))))
1471 printf("---------- 0 0 " "0 0 %s\n",
1474 switch (lvdata->vnode->type) {
1485 for (j = 8; j >= 0; j--) {
1486 if (lvdata->vnode->modeBits & (1 << j))
1500 printf(" %-3d %-8d %-8d %10d %s\n", lvdata->vnode->linkCount,
1501 lvdata->vnode->owner, lvdata->vnode->group,
1502 lvdata->vnode->length, eplist[i]->name);
1508 if (Rflag && eprecurse) {
1511 for (i = 0; i < numrecurse; i++) {
1513 printf("\n%s:\n", eprecurse[i]->name);
1515 lpath = malloc(strlen(path) + strlen(eprecurse[i]->name) + 2);
1517 sprintf(lpath, "%s/%s", path, eprecurse[i]->name);
1519 DirListInternal(GetVnode(ntohl(eprecurse[i]->fid.vnode)), NULL, 0,
1520 lflag, iflag, Fflag, Rflag, verbose, vol, lpath);
1536 * Directory name comparison function, used by qsort
1540 CompareDirEntry(const void *e1, const void *e2)
1542 struct DirEntry **ep1 = (struct DirEntry **)e1;
1543 struct DirEntry **ep2 = (struct DirEntry **)e2;
1545 return strcmp((*ep1)->name, (*ep2)->name);
1549 * Change a directory. Return a pointer to our new vdata structure for
1553 static struct vnodeData *
1554 ChangeDirectory(int argc, char **argv, struct vnodeData *vdatacwd)
1556 struct vnodeData *newvdatacwd;
1559 fprintf(stderr, "Usage: %s directory\n", argv[0]);
1563 if ((newvdatacwd = FindFile(vdatacwd, argv[1])) == NULL)
1566 if (newvdatacwd->vnode->type != vDirectory) {
1567 fprintf(stderr, "%s: Not a directory\n", argv[1]);
1571 if (newvdatacwd->filedata == NULL) {
1572 fprintf(stderr, "%s: No directory data found.\n", argv[1]);
1580 * Copy a file from out of the dump file
1583 #define COPYBUFSIZE 8192
1586 CopyFile(int argc, char **argv, struct vnodeData *vdatacwd, FILE * f)
1588 struct vnodeData *vdata;
1592 char buffer[COPYBUFSIZE];
1595 fprintf(stderr, "Usage: %s dumpfile destfile\n", argv[0]);
1599 if ((vdata = FindFile(vdatacwd, argv[1])) == NULL)
1602 if (vdata->dumpdata == 0) {
1603 fprintf(stderr, "File %s has no data in dump file\n", argv[1]);
1607 if ((out = fopen(argv[2], "wb")) == NULL) {
1608 fprintf(stderr, "Open of %s failed: %s\n", argv[2], strerror(errno));
1612 if (fseeko64(f, vdata->dumpdata, SEEK_SET)) {
1613 fprintf(stderr, "Seek failed: %s\n", strerror(errno));
1618 while (cur < vdata->datalength) {
1622 vdata->datalength ? COPYBUFSIZE : vdata->datalength - cur;
1624 ret = fread(buffer, sizeof(char), bytes, f);
1627 fprintf(stderr, "Short read (expected %d, " "got %d)\n",
1630 fprintf(stderr, "Error during read: %s\n", strerror(errno));
1635 ret = fwrite(buffer, sizeof(char), bytes, out);
1638 fprintf(stderr, "Short write (expected %d, " "got %d)\n",
1641 fprintf(stderr, "Error during write: %s\n", strerror(errno));
1653 * Copy a file from out of the dump file, by using the vnode
1657 CopyVnode(int argc, char *argv[], FILE * f)
1659 struct vnodeData *vdata;
1663 char buffer[COPYBUFSIZE];
1664 unsigned int vnode, uniquifier = 0;
1667 fprintf(stderr, "Usage: %s vnode[.uniqifier] destfile\n", argv[0]);
1671 ret = sscanf(argv[1], "%d.%d", &vnode, &uniquifier);
1674 fprintf(stderr, "Invalid file identifier: %s\n", argv[1]);
1678 if (!(vdata = GetVnode(vnode))) {
1679 fprintf(stderr, "Vnode %d not in dump file\n", vnode);
1683 if (ret == 2 && vdata->vnode->uniquifier != uniquifier) {
1685 "Specified uniquifier %d did not match "
1686 "uniquifier %d found in dump file!\n", uniquifier,
1687 vdata->vnode->uniquifier);
1691 if (vdata->dumpdata == 0) {
1692 fprintf(stderr, "File %s has no data in dump file\n", argv[1]);
1696 if ((out = fopen(argv[2], "wb")) == NULL) {
1697 fprintf(stderr, "Open of %s failed: %s\n", argv[2], strerror(errno));
1701 if (fseeko64(f, vdata->dumpdata, SEEK_SET)) {
1702 fprintf(stderr, "Seek failed: %s\n", strerror(errno));
1707 while (cur < vdata->datalength) {
1711 vdata->datalength ? COPYBUFSIZE : vdata->datalength - cur;
1713 ret = fread(buffer, sizeof(char), bytes, f);
1716 fprintf(stderr, "Short read (expected %d, " "got %d)\n",
1719 fprintf(stderr, "Error during read: %s\n", strerror(errno));
1724 ret = fwrite(buffer, sizeof(char), bytes, out);
1727 fprintf(stderr, "Short write (expected %d, " "got %d)\n",
1730 fprintf(stderr, "Error during write: %s\n", strerror(errno));
1742 * Dump all residency filenames associated with a file, or all files
1743 * within a directory.
1747 DumpAllFiles(int argc, char **argv, struct vnodeData *vdatacwd,
1748 VolumeDiskData * vol)
1751 struct vnodeData *vdata, *nvdata;
1752 struct DirCursor cursor;
1753 struct DirEntry *ep;
1756 int dflag = 0, fflag = 0, errflg = 0;
1760 while ((c = getopt(argc, argv, "df:")) != EOF)
1766 if ((f = fopen(optarg, "a")) == NULL) {
1767 fprintf(stderr, "Cannot open \"%s\": %s\n", optarg,
1779 if (errflg || argc == optind) {
1780 fprintf(stderr, "Usage: %s [-d] [-f filename] file " "[file ...]\n",
1787 for (i = optind; i < argc; i++) {
1789 if ((vdata = FindFile(vdatacwd, argv[i])) == NULL)
1792 if (vdata->vnode->type == vDirectory && !dflag) {
1794 ResetDirCursor(&cursor, vdata);
1796 while ((ep = ReadNextDir(&cursor, vdata)) != NULL) {
1798 if (!(nvdata = GetVnode(ntohl(ep->fid.vnode)))) {
1800 "Cannot find vnode " "entry for %s (%d)\n",
1801 ep->name, ntohl(ep->fid.vnode));
1807 printf("Residency locations for %s:\n", ep->name);
1809 if (nvdata->dumpdata)
1810 printf("Local disk (in dump " "file)\n");
1813 DumpAllResidencies(f, nvdata, vol);
1819 printf("Residency locations for %s:\n", argv[i]);
1821 if (vdata->dumpdata)
1822 printf("Local disk (in dump file)\n");
1825 DumpAllResidencies(f, vdata, vol);
1831 #else /* RESIDENCY */
1833 "The \"file\" command is not available in the non-"
1834 "MRAFS version of dumptool.\n");
1835 #endif /* RESIDENCY */
1840 * Take a vnode, traverse the vnode chain, and dump out all files on
1841 * all residencies corresponding to that parent vnode.
1846 DumpAllResidencies(FILE * f, struct vnodeData *vdata,
1847 struct VolumeDiskData *vol)
1849 unsigned int nextVnodeNum;
1851 while (nextVnodeNum = vdata->vnode->NextVnodeId) {
1852 if ((vdata = GetVnode(nextVnodeNum)) == NULL) {
1854 "We had a pointer to %lu in it's "
1855 "vnode chain, but there\nisn't a record of "
1856 "it! The dump might be corrupt.\n", nextVnodeNum);
1860 if (vdata->vnode->type == vFidLookup)
1861 DumpVnodeFile(f, vdata->vnode, vol);
1870 * Given a directory vnode and a filename, return the vnode corresponding
1871 * to the file in that directory.
1873 * We now handle pathnames with directories in them.
1876 static struct vnodeData *
1877 FindFile(struct vnodeData *vdatacwd, char *filename)
1879 struct DirHeader *dhp;
1880 struct DirEntry *ep;
1882 struct vnodeData *vdata;
1883 char *c, newstr[MAXPATHLEN];
1885 if (!vdatacwd->filedata) {
1886 fprintf(stderr, "There is no vnode data for this " "directory!\n");
1891 * If we have a "/" in here, look up the vnode data for the
1892 * directory (everything before the "/") and use that as our
1893 * current directory. We automagically handle multiple directories
1894 * by using FindFile recursively.
1897 if ((c = strrchr(filename, '/')) != NULL) {
1899 strncpy(newstr, filename, c - filename);
1900 newstr[c - filename] = '\0';
1902 if ((vdatacwd = FindFile(vdatacwd, newstr)) == NULL)
1905 if (vdatacwd->vnode->type != vDirectory) {
1906 fprintf(stderr, "%s: Not a directory\n", newstr);
1913 dhp = (struct DirHeader *)vdatacwd->filedata;
1915 i = DirHash(filename);
1917 num = ntohs(dhp->hashTable[i]);
1920 ep = (struct DirEntry *)(vdatacwd->filedata + (num * 32));
1921 if (strcmp(ep->name, filename) == 0)
1923 num = ntohs(ep->next);
1927 fprintf(stderr, "%s: No such file or directory\n", filename);
1931 if ((vdata = GetVnode(ntohl(ep->fid.vnode))) == NULL) {
1932 fprintf(stderr, "%s: No vnode information for %u found\n", filename,
1933 ntohl(ep->fid.vnode));
1941 * Reset a structure containing the current directory scan location
1945 ResetDirCursor(struct DirCursor *cursor, struct vnodeData *vdata)
1947 struct DirHeader *dhp;
1949 cursor->hashbucket = 0;
1951 dhp = (struct DirHeader *)vdata->filedata;
1953 cursor->entry = ntohs(dhp->hashTable[0]);
1957 * Given a cursor and a directory entry, return the next entry in the
1961 static struct DirEntry *
1962 ReadNextDir(struct DirCursor *cursor, struct vnodeData *vdata)
1964 struct DirHeader *dhp;
1965 struct DirEntry *ep;
1967 dhp = (struct DirHeader *)vdata->filedata;
1969 if (cursor->entry) {
1970 ep = (struct DirEntry *)(vdata->filedata + (cursor->entry * 32));
1971 cursor->entry = ntohs(ep->next);
1974 while (++(cursor->hashbucket) < NHASHENT) {
1975 cursor->entry = ntohs(dhp->hashTable[cursor->hashbucket]);
1976 if (cursor->entry) {
1977 ep = (struct DirEntry *)(vdata->filedata +
1978 (cursor->entry * 32));
1979 cursor->entry = ntohs(ep->next);
1989 * Given a string, split it up into components a la Unix argc/argv.
1991 * This code is most stolen from ftp.
1995 MakeArgv(char *string, int *argc, char ***argv)
1997 static char *largv[64];
2000 static char argbuf[CMDBUFSIZE];
2006 while ((*la++ = GetToken(s, &s, ap, &ap)) != NULL)
2011 * Return a pointer to the next token, and update the current string
2016 GetToken(char *string, char **nexttoken, char argbuf[], char *nextargbuf[])
2043 goto OUTTOKEN; /* End of our token */
2047 goto S2; /* Get next character */
2051 goto S3; /* Get quoted string */
2054 *ap++ = *sp++; /* Add a character to our token */
2090 *nextargbuf = ap; /* Update storage pointer */
2091 *nexttoken = sp; /* Update token pointer */
2093 return got_one ? argbuf : NULL;
2097 * Insert vnodes into our hash table.
2100 static struct vnodeData *
2101 InsertVnode(unsigned int vnodeNumber, struct VnodeDiskObject *vnode)
2103 struct VnodeDiskObject *nvnode;
2104 struct vnodeData *vdata;
2105 static int curSmallVnodeIndex = 0;
2106 static int curLargeVnodeIndex = 0;
2107 struct vnodeData ***vnodeIndex;
2110 nvnode = (struct VnodeDiskObject *)malloc(sizeof(struct VnodeDiskObject));
2114 fprintf(stderr, "Unable to allocate space for vnode\n");
2118 memcpy((void *)nvnode, (void *)vnode, sizeof(struct VnodeDiskObject));
2120 if (vnodeNumber & 1) {
2121 vnodeIndex = &LargeVnodeIndex;
2122 curIndex = &curLargeVnodeIndex;
2124 vnodeIndex = &SmallVnodeIndex;
2125 curIndex = &curSmallVnodeIndex;
2128 vdata = (struct vnodeData *)malloc(sizeof(struct vnodeData));
2130 vdata->vnode = nvnode;
2131 vdata->vnodeNumber = vnodeNumber;
2132 vdata->dumpdata = 0;
2133 vdata->filedata = 0;
2134 vdata->datalength = 0;
2136 (*vnodeIndex)[(*curIndex)++] = vdata;
2142 * Routine to retrieve a vnode from the hash table.
2145 static struct vnodeData *
2146 GetVnode(unsigned int vnodeNumber)
2148 struct vnodeData vnode, *vnodep, **tmp;
2150 vnode.vnodeNumber = vnodeNumber;
2153 tmp = (struct vnodeData **)
2154 bsearch((void *)&vnodep,
2155 vnodeNumber & 1 ? LargeVnodeIndex : SmallVnodeIndex,
2156 vnodeNumber & 1 ? numLargeVnodes : numSmallVnodes,
2157 sizeof(struct vnodeData *), CompareVnode);
2159 return tmp ? *tmp : NULL;
2163 * Our comparator function for bsearch
2167 CompareVnode(const void *node1, const void *node2)
2169 struct vnodeData **vnode1 = (struct vnodeData **)node1;
2170 struct vnodeData **vnode2 = (struct vnodeData **)node2;
2172 if ((*vnode1)->vnodeNumber == (*vnode2)->vnodeNumber)
2174 else if ((*vnode1)->vnodeNumber > (*vnode2)->vnodeNumber)
2182 * Dump out the filename corresponding to a particular vnode.
2184 * This routine has the following dependancies:
2186 * - Only will work on UFS filesystems at this point
2187 * - Has to talk to the rsserver.
2188 * - Can only determine UFS algorithm type when run on the same machine
2189 * as the residency (unless you manually specify algorithm information)
2193 DumpVnodeFile(FILE * f, struct VnodeDiskObject *vnode, VolumeDiskData * vol)
2195 static int rscache = 0;
2196 static rsaccessinfoList rsnlist = { 0, 0 };
2197 char MountPoint[MAXPATHLEN + 1];
2198 char FileName[MAXPATHLEN + 1];
2199 unsigned int Size, Level[4];
2200 unsigned int DeviceTag, Algorithm;
2201 FileSystems *FSInfo;
2202 int i, found, FSType, rsindex;
2205 * Maybe we found out something about this residency via the
2206 * command-line; check that first.
2209 rsindex = ffs(VLkp_Residencies(vnode)) - 1;
2212 * We need to get information from the rsserver (so we can
2213 * find out the device tag for a given residency). If we
2214 * haven't cached that, talk to the rsserver to get it.
2215 * If we have info about this already, then don't talk to
2216 * the rsserver (this lets us still do disaster recovery if
2217 * MR-AFS is completely hosed).
2220 if (!rscache && rscmdlineinfo[rsindex].DeviceTag == -1) {
2223 code = ServerInitResidencyConnection();
2227 "ServerInitResidencyConnection failed " "with code %d\n",
2232 code = rs_GetResidencySummary(ServerRequestorId, &rsnlist);
2235 fprintf(stderr, "rs_GetResidencySummary failed " "with code %d\n",
2244 * For a given residency (as specified in the vnode),
2245 * find out it's device tag number, either via the rsserver
2246 * or via the command line.
2249 if (rscmdlineinfo[rsindex].DeviceTag != -1) {
2250 DeviceTag = rscmdlineinfo[rsindex].DeviceTag;
2253 for (i = 0, found = 0; (i < rsnlist.rsaccessinfoList_len) && (!found);
2255 if (rsnlist.rsaccessinfoList_val[i].id.residency ==
2256 VLkp_Residencies(vnode)) {
2258 DeviceTag = rsnlist.rsaccessinfoList_val[i].devicetagnumber;
2266 "Unable to find residency %d in "
2267 "rsserver database, aborting\n", VLkp_Residencies(vnode));
2272 * Okay, now we've got the DeviceTag ... which we can use to
2273 * lookup the on-disk configuration information (which we
2274 * assume is locally stored). We also need the DeviceTag to
2275 * print out which partition we're using (but that comes later).
2277 * We lookup the on-disk configuration information by calling
2278 * Ufs_GetFSInfo() to get the configuration information on the
2279 * filesystems specified by the given DeviceTag.
2281 * Before we call Ufs_GetFSInfo, check the command-line cache;
2282 * if we got something via the command-line, don't go to disk.
2285 if (rscmdlineinfo[rsindex].FSType == -1
2286 && Ufs_GetFSInfo(&FSInfo, DeviceTag)) {
2289 "Ufs_GetFSInfo failed for DeviceTag "
2290 "%d, Residency %d\n", DeviceTag, VLkp_Residencies(vnode));
2295 * The FSInfo structure has the last two things we need: the
2296 * FSType (ufs, slowufs, etc etc), and the usage algorithm (which
2297 * ends up being how many directories are being used on the
2298 * residency filesystem).
2300 * With these last two parameters, use routines stolen from
2301 * ufsname to generate the filename.
2303 * (Actually, I lied - we also need the "Size" parameter, which
2304 * we can also get from FSInfo);
2307 if (rscmdlineinfo[rsindex].FSType != -1) {
2308 FSType = rscmdlineinfo[rsindex].FSType;
2309 Algorithm = rscmdlineinfo[rsindex].Algorithm;
2310 Size = rscmdlineinfo[rsindex].Size;
2312 FSType = FSInfo->FileSystems_u.UfsInterface.FSType;
2313 Algorithm = FSInfo->FileSystems_u.UfsInterface.Algorithm;
2314 if (FSInfo->FileSystems_u.UfsInterface.Directories[1] == 0)
2316 else if (FSInfo->FileSystems_u.UfsInterface.Directories[1] == 16)
2318 else if (FSInfo->FileSystems_u.UfsInterface.Directories[1] == 256)
2322 fprintf(stderr, "Unknown directory size %d, " "aborting\n",
2323 FSInfo->FileSystems_u.UfsInterface.Directories[1]);
2329 * First, generate our mount point from the DeviceTag and
2333 DEVICETAGNUMBERTOMOUNTPOINT(MountPoint, DeviceTag, FSType);
2336 * Then, generate the "level" (directory bitmasks) from the
2337 * file tags, size, and algorithm
2340 UfsTagsToLevel(VLkp_FileTag1(vnode), VLkp_FileTag2(vnode), Algorithm,
2341 Size, Level, VLkp_ParentVnodeId(vnode),
2342 VLkp_ParentUniquifierId(vnode));
2345 * Finally, take the above information and generate the
2346 * corresponding filename (this macro ends up being a
2350 TAGSTONAME(FileName, MountPoint, Level, Directories[Size][1],
2351 vol->parentId, VLkp_ParentVnodeId(vnode),
2352 VLkp_ParentUniquifierId(vnode), Algorithm);
2354 fprintf(f, "%s\n", FileName);
2361 * Read a 16 bit integer in network order
2365 ReadInt16(FILE * f, unsigned short *s)
2369 if (fread((void *)&in, sizeof(in), 1, f) != 1) {
2371 fprintf(stderr, "ReadInt16 failed!\n");
2382 * Read a 32 bit integer in network order
2386 ReadInt32(FILE * f, unsigned int *i)
2390 if (fread((void *)&in, sizeof(in), 1, f) != 1) {
2392 fprintf(stderr, "ReadInt32 failed!\n");
2396 *i = ntohl((unsigned long)in);
2402 * Read a string from a dump file
2406 ReadString(FILE * f, char *string, int maxlen)
2411 if ((*string++ = getc(f)) == 0)
2416 * I'm not sure what the _hell_ this is supposed to do ...
2417 * but it was in the original dump code
2421 while ((c = getc(f)) && c != EOF);
2429 ReadByteString(FILE * f, void *s, int size)
2431 unsigned char *c = (unsigned char *)s;
2440 * The directory hashing algorithm used by AFS
2444 DirHash(char *string)
2446 /* Hash a string to a number between 0 and NHASHENT. */
2451 while ((tc = (*string++)) != '\0') {
2455 tval = hval & (NHASHENT - 1);
2456 #ifdef AFS_CRAY_ENV /* actually, any > 32 bit environment */
2459 else if (hval & 0x80000000)
2460 tval = NHASHENT - tval;
2461 #else /* AFS_CRAY_ENV */
2465 tval = NHASHENT - tval;
2466 #endif /* AFS_CRAY_ENV */
2472 * Sigh, we need this for the AFS libraries
2476 LogErrors(int level, char *a, char *b, char *c, char *d, char *e, char *f,
2477 char *g, char *h, char *i, char *j, char *k)
2480 fprintf(stderr, a, b, c, d, e, f, g, h, i, j, k);
2486 * These are routines taken from AFS libraries and programs. Most of
2487 * them are from ufsname.c, but a few are from the dir library (the dir
2488 * library has a bunch of hidden dependancies, so it's not suitable to
2489 * include it outright).
2492 UfsEntropiesToTags(HighEntropy, LowEntropy, Algorithm, FileTag1, FileTag2)
2493 uint32_t HighEntropy;
2494 uint32_t LowEntropy;
2501 if ((Algorithm > UFS_ALGORITHMS) || (Algorithm <= 0))
2505 for (i = 0; i < 32; ++i) {
2506 if (UfsEntropy[Algorithm - 1][i] < 32)
2508 ((HighEntropy & (1 << i)) ==
2509 0) ? 0 : 1 << UfsEntropy[Algorithm - 1][i];
2512 ((HighEntropy & (1 << i)) ==
2513 0) ? 0 : 1 << (UfsEntropy[Algorithm - 1][i] - 32);
2515 for (i = 32; i < 64; ++i) {
2516 if (UfsEntropy[Algorithm - 1][i] < 32)
2518 ((LowEntropy & (1 << (i - 32))) ==
2519 0) ? 0 : 1 << UfsEntropy[Algorithm - 1][i];
2522 ((LowEntropy & (1 << (i - 32))) ==
2523 0) ? 0 : 1 << (UfsEntropy[Algorithm - 1][i] - 32);
2529 UfsTagsToHighEntropy(FileTag1, FileTag2, Algorithm)
2538 for (i = 0; i < 32; ++i) {
2539 if (UfsEntropy[Algorithm - 1][i] < 32)
2540 Value |= ((FileTag1 & (1 << UfsEntropy[Algorithm - 1][i]))
2544 ((FileTag2 & (1 << (UfsEntropy[Algorithm - 1][i] - 32))) ==
2551 UfsTagsToLowEntropy(FileTag1, FileTag2, Algorithm)
2560 for (i = 32; i < 64; ++i) {
2561 if (UfsEntropy[Algorithm - 1][i] < 32)
2562 Value |= ((FileTag1 & (1 << UfsEntropy[Algorithm - 1][i]))
2563 == 0) ? 0 : 1 << (i - 32);
2566 ((FileTag2 & (1 << (UfsEntropy[Algorithm - 1][i] - 32))) ==
2567 0) ? 0 : 1 << (i - 32);
2572 UfsTagsToLevel(FileTag1, FileTag2, Algorithm, Size, Sections, vnode,
2578 uint32_t Sections[4];
2580 uint32_t Uniquifier;
2582 uint32_t HighEntropy;
2583 uint32_t LowEntropy;
2585 switch (Algorithm) {
2587 LowEntropy = UfsTagsToLowEntropy(FileTag1, FileTag2, Algorithm);
2588 HighEntropy = UfsTagsToHighEntropy(FileTag1, FileTag2, Algorithm);
2589 Sections[0] = HighEntropy % Directories[Size][0];
2590 HighEntropy /= Directories[Size][0];
2591 if (Directories[Size][1]) {
2592 Sections[1] = HighEntropy % Directories[Size][1];
2593 HighEntropy /= Directories[Size][1];
2594 Sections[2] = HighEntropy;
2595 Sections[3] = LowEntropy;
2597 Sections[1] = HighEntropy;
2598 Sections[2] = LowEntropy;
2602 Sections[0] = FileTag1 & 0xff;
2603 if (Directories[Size][1]) {
2604 Sections[1] = Uniquifier & 0xff;
2605 if (Directories[Size][1] == 16)
2607 Sections[2] = FileTag1;
2608 Sections[3] = FileTag2;
2610 Sections[1] = FileTag1;
2611 Sections[2] = FileTag2;
2615 Sections[0] = FileTag1 & 0xff;
2616 if (Directories[Size][1]) {
2617 Sections[1] = (vnode >> 1) & 0xff;
2618 if (Directories[Size][1] == 16)
2620 Sections[2] = FileTag1;
2621 Sections[3] = FileTag2;
2623 Sections[1] = FileTag1;
2624 Sections[2] = FileTag2;
2628 fprintf(stderr, "UfsTagsToLevel: bad algorithm %lu!\n", Algorithm);
2634 #include <afs/afscbdummies.h>
2635 #endif /* RESIDENCY */