Update NEWS for 1.6.22
[pkg-k5-afs_openafs.git] / src / volser / vol-dump.c
blobac7a76383d4565d6e1ed368c162fa29469a1b6e7
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 */
11 System: VICE-TWO
12 Module: vol-dump.c
13 Institution: The Information Technology Center, Carnegie-Mellon University
17 #include <afsconfig.h>
18 #include <afs/param.h>
20 #ifdef IGNORE_SOME_GCC_WARNINGS
21 # pragma GCC diagnostic warning "-Wformat"
22 #endif
24 #include <ctype.h>
25 #include <errno.h>
26 #include <sys/stat.h>
27 #include <stdio.h>
28 #include <string.h>
29 #ifdef AFS_NT40_ENV
30 #include <fcntl.h>
31 #include <time.h>
32 #include <io.h>
33 #else
34 #include <sys/param.h>
35 #include <sys/file.h>
36 #include <sys/time.h>
37 #endif
38 #include <afs/cmd.h>
40 #include <rx/xdr.h>
41 #include <afs/afsint.h>
42 #include <afs/nfs.h>
43 #include <afs/errors.h>
44 #include <lock.h>
45 #include <lwp.h>
46 #include <afs/afssyscalls.h>
47 #include <afs/ihandle.h>
48 #include <afs/vnode.h>
49 #include <afs/volume.h>
50 #include <afs/partition.h>
51 #include <afs/viceinode.h>
52 #include <afs/afssyscalls.h>
53 #include <afs/acl.h>
54 #include <afs/dir.h>
55 #include <afs/com_err.h>
57 #ifdef HAVE_UNISTD_H
58 #include <unistd.h>
59 #endif
61 #ifdef HAVE_STDLIB_H
62 #include <stdlib.h>
63 #endif
65 #ifdef HAVE_FCNTL_H
66 #include <fcntl.h>
67 #endif
69 #ifdef _AIX
70 #include <time.h>
71 #endif
73 #include <dirent.h>
75 #include "volser.h"
76 #include "volint.h"
77 #include "dump.h"
79 #define putint32(p, v) *p++ = v>>24, *p++ = v>>16, *p++ = v>>8, *p++ = v
80 #define putshort(p, v) *p++ = v>>8, *p++ = v
82 #ifdef O_LARGEFILE
83 #define afs_stat stat64
84 #define afs_fstat fstat64
85 #define afs_open open64
86 #else /* !O_LARGEFILE */
87 #define afs_stat stat
88 #define afs_fstat fstat
89 #define afs_open open
90 #endif /* !O_LARGEFILE */
92 int VolumeChanged; /* needed by physio - leave alone */
93 int verbose = 0;
95 /* Forward Declarations */
96 void HandleVolume(struct DiskPartition64 *partP, char *name, char *filename, int fromtime);
97 Volume *AttachVolume(struct DiskPartition64 *dp, char *volname,
98 struct VolumeHeader *header);
99 static void DoMyVolDump(Volume * vp, struct DiskPartition64 *dp,
100 char *dumpfile, int fromtime);
102 #ifndef AFS_NT40_ENV
103 #include "AFS_component_version_number.c"
104 #endif
106 char name[VMAXPATHLEN];
110 ReadHdr1(IHandle_t * ih, char *to, int size, u_int magic, u_int version)
112 int code;
114 code = IH_IREAD(ih, 0, to, size);
115 if (code != size)
116 return -1;
118 return 0;
122 Volume *
123 AttachVolume(struct DiskPartition64 * dp, char *volname,
124 struct VolumeHeader * header)
126 Volume *vp;
127 afs_int32 ec = 0;
129 vp = (Volume *) calloc(1, sizeof(Volume));
130 vp->specialStatus = 0;
131 vp->device = dp->device;
132 vp->partition = dp;
133 IH_INIT(vp->vnodeIndex[vLarge].handle, dp->device, header->parent,
134 header->largeVnodeIndex);
135 IH_INIT(vp->vnodeIndex[vSmall].handle, dp->device, header->parent,
136 header->smallVnodeIndex);
137 IH_INIT(vp->diskDataHandle, dp->device, header->parent,
138 header->volumeInfo);
139 IH_INIT(V_linkHandle(vp), dp->device, header->parent, header->linkTable);
140 vp->cacheCheck = 0; /* XXXX */
141 vp->shuttingDown = 0;
142 vp->goingOffline = 0;
143 vp->nUsers = 1;
144 vp->header = (struct volHeader *)calloc(1, sizeof(*vp->header));
145 ec = ReadHdr1(V_diskDataHandle(vp), (char *)&V_disk(vp),
146 sizeof(V_disk(vp)), VOLUMEINFOMAGIC, VOLUMEINFOVERSION);
147 if (!ec) {
148 struct IndexFileHeader iHead;
149 ec = ReadHdr1(vp->vnodeIndex[vSmall].handle, (char *)&iHead,
150 sizeof(iHead), SMALLINDEXMAGIC, SMALLINDEXVERSION);
152 if (!ec) {
153 struct IndexFileHeader iHead;
154 ec = ReadHdr1(vp->vnodeIndex[vLarge].handle, (char *)&iHead,
155 sizeof(iHead), LARGEINDEXMAGIC, LARGEINDEXVERSION);
157 #ifdef AFS_NAMEI_ENV
158 if (!ec) {
159 struct versionStamp stamp;
160 ec = ReadHdr1(V_linkHandle(vp), (char *)&stamp, sizeof(stamp),
161 LINKTABLEMAGIC, LINKTABLEVERSION);
163 #endif
164 if (ec)
165 return (Volume *) 0;
166 return vp;
170 static int
171 handleit(struct cmd_syndesc *as, void *arock)
173 struct cmd_item *ti;
174 int err = 0;
175 afs_uint32 volumeId = 0;
176 char *partName = 0;
177 char *fileName = NULL;
178 struct DiskPartition64 *partP = NULL;
179 char name1[128];
180 char tmpPartName[20];
181 int fromtime = 0;
182 afs_int32 code;
185 #ifndef AFS_NT40_ENV
186 #if 0
187 if (geteuid() != 0) {
188 fprintf(stderr, "voldump must be run as root; sorry\n");
189 exit(1);
191 #endif
192 #endif
194 if ((ti = as->parms[0].items))
195 partName = ti->data;
196 if ((ti = as->parms[1].items))
197 volumeId = (afs_uint32)atoi(ti->data);
198 if ((ti = as->parms[2].items))
199 fileName = ti->data;
200 if ((ti = as->parms[3].items))
201 verbose = 1;
202 if (as->parms[4].items && strcmp(as->parms[4].items->data, "0")) {
203 code = ktime_DateToInt32(as->parms[4].items->data, &fromtime);
204 if (code) {
205 fprintf(STDERR, "failed to parse date '%s' (error=%d))\n",
206 as->parms[4].items->data, code);
207 return code;
211 DInit(10);
213 err = VAttachPartitions();
214 if (err) {
215 fprintf(stderr, "%d partitions had errors during attach.\n", err);
218 if (partName) {
219 if (strlen(partName) == 1) {
220 if (partName[0] >= 'a' && partName[0] <= 'z') {
221 strcpy(tmpPartName, "/vicepa");
222 tmpPartName[6] = partName[0];
223 partP = VGetPartition(tmpPartName, 0);
225 } else {
226 partP = VGetPartition(partName, 0);
228 if (!partP) {
229 fprintf(stderr,
230 "%s is not an AFS partition name on this server.\n",
231 partName);
232 exit(1);
236 if (!volumeId) {
237 fprintf(stderr, "Must specify volume id!\n");
238 exit(1);
241 if (!partP) {
242 fprintf(stderr, "must specify vice partition.\n");
243 exit(1);
246 (void)afs_snprintf(name1, sizeof name1, VFORMAT, (unsigned long)volumeId);
247 HandleVolume(partP, name1, fileName, fromtime);
248 return 0;
251 void
252 HandleVolume(struct DiskPartition64 *dp, char *name, char *filename, int fromtime)
254 struct VolumeHeader header;
255 struct VolumeDiskHeader diskHeader;
256 struct afs_stat status;
257 int fd;
258 Volume *vp;
259 char headerName[1024];
261 afs_int32 n;
263 (void)afs_snprintf(headerName, sizeof headerName, "%s" OS_DIRSEP "%s",
264 VPartitionPath(dp), name);
265 if ((fd = afs_open(headerName, O_RDONLY)) == -1
266 || afs_fstat(fd, &status) == -1) {
267 fprintf(stderr, "Cannot read volume header %s\n", name);
268 close(fd);
269 exit(1);
271 n = read(fd, &diskHeader, sizeof(diskHeader));
273 if (n != sizeof(diskHeader)
274 || diskHeader.stamp.magic != VOLUMEHEADERMAGIC) {
275 fprintf(stderr, "Error reading volume header %s\n", name);
276 exit(1);
278 if (diskHeader.stamp.version != VOLUMEHEADERVERSION) {
279 fprintf(stderr,
280 "Volume %s, version number is incorrect; volume needs salvage\n",
281 name);
282 exit(1);
284 DiskToVolumeHeader(&header, &diskHeader);
286 close(fd);
287 vp = AttachVolume(dp, name, &header);
288 if (!vp) {
289 fprintf(stderr, "Error attaching volume header %s\n", name);
290 exit(1);
293 DoMyVolDump(vp, dp, filename, fromtime);
298 main(int argc, char **argv)
300 struct cmd_syndesc *ts;
301 afs_int32 code;
302 VolumePackageOptions opts;
304 VOptDefaults(volumeUtility, &opts);
305 if (VInitVolumePackage2(volumeUtility, &opts)) {
306 fprintf(stderr, "errors encountered initializing volume package, but "
307 "trying to continue anyway\n");
310 ts = cmd_CreateSyntax(NULL, handleit, NULL,
311 "Dump a volume to a 'vos dump' format file without using volserver");
312 cmd_AddParm(ts, "-part", CMD_LIST, CMD_OPTIONAL, "AFS partition name");
313 cmd_AddParm(ts, "-volumeid", CMD_LIST, CMD_OPTIONAL, "Volume id");
314 cmd_AddParm(ts, "-file", CMD_LIST, CMD_OPTIONAL, "Dump filename");
315 cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL,
316 "Trace dump progress (very verbose)");
317 cmd_AddParm(ts, "-time", CMD_SINGLE, CMD_OPTIONAL, "dump from time");
318 code = cmd_Dispatch(argc, argv);
319 return code;
325 static int
326 DumpDouble(int dumpfd, char tag, afs_uint32 value1,
327 afs_uint32 value2)
329 int res;
330 char tbuffer[9];
331 byte *p = (unsigned char *)tbuffer;
332 *p++ = tag;
333 putint32(p, value1);
334 putint32(p, value2);
336 res = write(dumpfd, tbuffer, 9);
337 return ((res == 9) ? 0 : VOLSERDUMPERROR);
340 static int
341 DumpInt32(int dumpfd, char tag, afs_uint32 value)
343 char tbuffer[5];
344 byte *p = (unsigned char *)tbuffer;
345 *p++ = tag;
346 putint32(p, value);
347 return ((write(dumpfd, tbuffer, 5) == 5) ? 0 : VOLSERDUMPERROR);
350 static int
351 DumpString(int dumpfd, char tag, char *s)
353 int n;
354 int code = 0;
355 code = write(dumpfd, &tag, 1);
356 if (code != 1)
357 return VOLSERDUMPERROR;
358 n = strlen(s) + 1;
359 code = write(dumpfd, s, n);
360 if (code != n)
361 return VOLSERDUMPERROR;
362 return 0;
366 static int
367 DumpArrayInt32(int dumpfd, char tag, afs_uint32 * array,
368 int nelem)
370 char tbuffer[4];
371 afs_uint32 v;
372 int code = 0;
373 byte *p = (unsigned char *)tbuffer;
374 *p++ = tag;
375 putshort(p, nelem);
376 code = write(dumpfd, tbuffer, 3);
377 if (code != 3)
378 return VOLSERDUMPERROR;
379 while (nelem--) {
380 p = (unsigned char *)tbuffer;
381 v = *array++; /*this was register */
383 putint32(p, v);
384 code = write(dumpfd, tbuffer, 4);
385 if (code != 4)
386 return VOLSERDUMPERROR;
388 return 0;
394 static int
395 DumpDumpHeader(int dumpfd, Volume * vp, afs_int32 fromtime)
397 int code = 0;
398 afs_int32 dumpTimes[2];
400 if (verbose)
401 fprintf(stderr, "dumping dump header\n");
403 if (!code)
404 code = DumpDouble(dumpfd, D_DUMPHEADER, DUMPBEGINMAGIC, DUMPVERSION);
406 if (!code)
407 code = DumpInt32(dumpfd, 'v', V_id(vp));
409 if (!code)
410 code = DumpString(dumpfd, 'n', V_name(vp));
412 dumpTimes[0] = fromtime;
413 switch (V_type(vp)) {
414 case readwriteVolume:
415 dumpTimes[1] = V_updateDate(vp); /* until last update */
416 break;
417 case readonlyVolume:
418 dumpTimes[1] = V_creationDate(vp); /* until clone was updated */
419 break;
420 case backupVolume:
421 /* until backup was made */
422 dumpTimes[1] = V_backupDate(vp) != 0 ? V_backupDate(vp) :
423 V_creationDate(vp);
424 break;
425 default:
426 code = EINVAL;
428 if (!code)
429 code = DumpArrayInt32(dumpfd, 't', (afs_uint32 *) dumpTimes, 2);
431 return code;
435 static int
436 DumpEnd(int dumpfd)
438 return (DumpInt32(dumpfd, D_DUMPEND, DUMPENDMAGIC));
441 static int
442 DumpByte(int dumpfd, char tag, byte value)
444 char tbuffer[2];
445 byte *p = (unsigned char *)tbuffer;
446 *p++ = tag;
447 *p = value;
448 return ((write(dumpfd, tbuffer, 2) == 2) ? 0 : VOLSERDUMPERROR);
451 static int
452 DumpTag(int dumpfd, int tag)
454 char p;
456 p = tag;
457 return ((write(dumpfd, &p, 1) == 1) ? 0 : VOLSERDUMPERROR);
461 static int
462 DumpBool(int dumpfd, char tag, unsigned int value)
464 char tbuffer[2];
465 byte *p = (unsigned char *)tbuffer;
466 *p++ = tag;
467 *p = value;
468 return ((write(dumpfd, tbuffer, 2) == 2) ? 0 : VOLSERDUMPERROR);
473 static int
474 DumpVolumeHeader(int dumpfd, Volume * vp)
476 int code = 0;
478 if (verbose)
479 fprintf(stderr, "dumping volume header\n");
481 if (!code)
482 code = DumpTag(dumpfd, D_VOLUMEHEADER);
483 if (!code)
484 code = DumpInt32(dumpfd, 'i', V_id(vp));
485 if (!code)
486 code = DumpInt32(dumpfd, 'v', V_stamp(vp).version);
487 if (!code)
488 code = DumpString(dumpfd, 'n', V_name(vp));
489 if (!code)
490 code = DumpBool(dumpfd, 's', V_inService(vp));
491 if (!code)
492 code = DumpBool(dumpfd, 'b', V_blessed(vp));
493 if (!code)
494 code = DumpInt32(dumpfd, 'u', V_uniquifier(vp));
495 if (!code)
496 code = DumpByte(dumpfd, 't', (byte) V_type(vp));
497 if (!code)
498 code = DumpInt32(dumpfd, 'p', V_parentId(vp));
499 if (!code)
500 code = DumpInt32(dumpfd, 'c', V_cloneId(vp));
501 if (!code)
502 code = DumpInt32(dumpfd, 'q', V_maxquota(vp));
503 if (!code)
504 code = DumpInt32(dumpfd, 'm', V_minquota(vp));
505 if (!code)
506 code = DumpInt32(dumpfd, 'd', V_diskused(vp));
507 if (!code)
508 code = DumpInt32(dumpfd, 'f', V_filecount(vp));
509 if (!code)
510 code = DumpInt32(dumpfd, 'a', V_accountNumber(vp));
511 if (!code)
512 code = DumpInt32(dumpfd, 'o', V_owner(vp));
513 if (!code)
514 code = DumpInt32(dumpfd, 'C', V_creationDate(vp)); /* Rw volume creation date */
515 if (!code)
516 code = DumpInt32(dumpfd, 'A', V_accessDate(vp));
517 if (!code)
518 code = DumpInt32(dumpfd, 'U', V_updateDate(vp));
519 if (!code)
520 code = DumpInt32(dumpfd, 'E', V_expirationDate(vp));
521 if (!code)
522 code = DumpInt32(dumpfd, 'B', V_backupDate(vp)); /* Rw volume backup clone date */
523 if (!code)
524 code = DumpString(dumpfd, 'O', V_offlineMessage(vp));
527 * We do NOT dump the detailed volume statistics residing in the old
528 * motd field, since we cannot tell from the info in a dump whether
529 * statistics data has been put there. Instead, we dump a null string,
530 * just as if that was what the motd contained.
532 if (!code)
533 code = DumpString(dumpfd, 'M', "");
534 if (!code)
535 code =
536 DumpArrayInt32(dumpfd, 'W', (afs_uint32 *) V_weekUse(vp),
537 sizeof(V_weekUse(vp)) / sizeof(V_weekUse(vp)[0]));
538 if (!code)
539 code = DumpInt32(dumpfd, 'D', V_dayUseDate(vp));
540 if (!code)
541 code = DumpInt32(dumpfd, 'Z', V_dayUse(vp));
542 return code;
545 static int
546 DumpShort(int dumpfd, char tag, unsigned int value)
548 char tbuffer[3];
549 byte *p = (unsigned char *)tbuffer;
550 *p++ = tag;
551 *p++ = value >> 8;
552 *p = value;
553 return ((write(dumpfd, tbuffer, 3) == 3) ? 0 : VOLSERDUMPERROR);
556 static int
557 DumpByteString(int dumpfd, char tag, byte * bs, int nbytes)
559 int code = 0;
561 code = write(dumpfd, &tag, 1);
562 if (code != 1)
563 return VOLSERDUMPERROR;
564 code = write(dumpfd, (char *)bs, nbytes);
565 if (code != nbytes)
566 return VOLSERDUMPERROR;
567 return 0;
571 static int
572 DumpFile(int dumpfd, int vnode, FdHandle_t * handleP, struct VnodeDiskObject *v)
574 int code = 0, failed_seek = 0, failed_write = 0;
575 afs_int32 pad = 0;
576 afs_foff_t offset = 0;
577 afs_sfsize_t nbytes, howBig;
578 ssize_t n;
579 size_t howMany;
580 afs_foff_t howFar = 0;
581 byte *p;
582 afs_uint32 hi, lo;
583 afs_ino_str_t stmp;
584 #ifndef AFS_NT40_ENV
585 struct afs_stat status;
586 #endif
587 afs_sfsize_t size;
588 #ifdef AFS_AIX_ENV
589 #include <sys/statfs.h>
590 struct statfs tstatfs;
591 #endif
593 if (verbose)
594 fprintf(stderr, "dumping file for vnode %d\n", vnode);
596 #ifdef AFS_NT40_ENV
597 howBig = _filelength(handleP->fd_fd);
598 howMany = 4096;
600 #else
601 afs_fstat(handleP->fd_fd, &status);
602 howBig = status.st_size;
604 #ifdef AFS_AIX_ENV
605 /* Unfortunately in AIX valuable fields such as st_blksize are
606 * gone from the stat structure.
608 fstatfs(handleP->fd_fd, &tstatfs);
609 howMany = tstatfs.f_bsize;
610 #else
611 howMany = status.st_blksize;
612 #endif /* AFS_AIX_ENV */
613 #endif /* AFS_NT40_ENV */
616 size = FDH_SIZE(handleP);
618 if (verbose)
619 fprintf(stderr, " howBig = %u, howMany = %u, fdh size = %u\n",
620 (unsigned int) howBig, (unsigned int) howMany,
621 (unsigned int) size);
623 SplitInt64(size, hi, lo);
624 if (hi == 0L) {
625 code = DumpInt32(dumpfd, 'f', lo);
626 } else {
627 code = DumpDouble(dumpfd, 'h', hi, lo);
630 if (code) {
631 return VOLSERDUMPERROR;
634 p = (unsigned char *)malloc(howMany);
635 if (!p) {
636 fprintf(stderr, "out of memory!\n");
637 return VOLSERDUMPERROR;
640 /* loop through whole file, while we still have bytes left, and no errors, in chunks of howMany bytes */
641 for (nbytes = size; (nbytes && !failed_write); nbytes -= howMany) {
642 if (nbytes < howMany)
643 howMany = nbytes;
645 /* Read the data - unless we know we can't */
646 n = (failed_seek ? 0 : FDH_PREAD(handleP, p, howMany, howFar));
647 howFar += n;
649 /* If read any good data and we null padded previously, log the
650 * amount that we had null padded.
652 if ((n > 0) && pad) {
653 fprintf(stderr, "Null padding file %d bytes at offset %lld\n", pad,
654 (long long)offset);
655 pad = 0;
658 /* If didn't read enough data, null padd the rest of the buffer. This
659 * can happen if, for instance, the media has some bad spots. We don't
660 * want to quit the dump, so we start null padding.
662 if (n < howMany) {
664 if (verbose) fprintf(stderr, " read %u instead of %u bytes.\n", (unsigned)n, (unsigned)howMany);
666 /* Record the read error */
667 if (n < 0) {
668 n = 0;
669 fprintf(stderr, "Error %d reading inode %s for vnode %d\n",
670 errno, PrintInode(stmp, handleP->fd_ih->ih_ino),
671 vnode);
672 } else if (!pad) {
673 fprintf(stderr, "Error reading inode %s for vnode %d\n",
674 PrintInode(stmp, handleP->fd_ih->ih_ino), vnode);
677 /* Pad the rest of the buffer with zeros. Remember offset we started
678 * padding. Keep total tally of padding.
680 memset(p + n, 0, howMany - n);
681 if (!pad)
682 offset = (howBig - nbytes) + n;
683 pad += (howMany - n);
685 /* Now seek over the data we could not get. An error here means we
686 * can't do the next read.
688 howFar = ((size - nbytes) + howMany);
691 /* Now write the data out */
692 if (write(dumpfd, (char *)p, howMany) != howMany)
693 failed_write = VOLSERDUMPERROR;
696 if (pad) { /* Any padding we hadn't reported yet */
697 fprintf(stderr, "Null padding file: %d bytes at offset %lld\n", pad,
698 (long long)offset);
701 free(p);
702 return failed_write;
706 static int
707 DumpVnode(int dumpfd, struct VnodeDiskObject *v, int volid, int vnodeNumber,
708 int dumpEverything, struct Volume *vp)
710 int code = 0;
711 IHandle_t *ihP;
712 FdHandle_t *fdP;
713 afs_ino_str_t stmp;
715 if (verbose)
716 fprintf(stderr, "dumping vnode %d\n", vnodeNumber);
718 if (!v || v->type == vNull)
719 return code;
720 if (!code)
721 code = DumpDouble(dumpfd, D_VNODE, vnodeNumber, v->uniquifier);
722 if (!dumpEverything)
723 return code;
724 if (!code)
725 code = DumpByte(dumpfd, 't', (byte) v->type);
726 if (!code)
727 code = DumpShort(dumpfd, 'l', v->linkCount); /* May not need this */
728 if (!code)
729 code = DumpInt32(dumpfd, 'v', v->dataVersion);
730 if (!code)
731 code = DumpInt32(dumpfd, 'm', v->unixModifyTime);
732 if (!code)
733 code = DumpInt32(dumpfd, 'a', v->author);
734 if (!code)
735 code = DumpInt32(dumpfd, 'o', v->owner);
736 if (!code && v->group)
737 code = DumpInt32(dumpfd, 'g', v->group); /* default group is 0 */
738 if (!code)
739 code = DumpShort(dumpfd, 'b', v->modeBits);
740 if (!code)
741 code = DumpInt32(dumpfd, 'p', v->parent);
742 if (!code)
743 code = DumpInt32(dumpfd, 's', v->serverModifyTime);
744 if (v->type == vDirectory) {
745 code = acl_HtonACL(VVnodeDiskACL(v));
746 if (code) {
747 fprintf(stderr, "Skipping invalid acl in vnode %u (volume %i)\n",
748 vnodeNumber, volid);
750 if (!code)
751 code =
752 DumpByteString(dumpfd, 'A', (byte *) VVnodeDiskACL(v),
753 VAclDiskSize(v));
756 if (VNDISK_GET_INO(v)) {
757 IH_INIT(ihP, V_device(vp), V_parentId(vp), VNDISK_GET_INO(v));
758 fdP = IH_OPEN(ihP);
759 if (fdP == NULL) {
760 fprintf(stderr,
761 "Unable to open inode %s for vnode %u (volume %i); not dumped, error %d\n",
762 PrintInode(stmp, VNDISK_GET_INO(v)), vnodeNumber, volid,
763 errno);
765 else
767 if (verbose)
768 fprintf(stderr, "about to dump inode %s for vnode %u\n",
769 PrintInode(stmp, VNDISK_GET_INO(v)), vnodeNumber);
770 code = DumpFile(dumpfd, vnodeNumber, fdP, v);
771 FDH_CLOSE(fdP);
773 IH_RELEASE(ihP);
776 if (verbose)
777 fprintf(stderr, "done dumping vnode %d\n", vnodeNumber);
778 return code;
782 static int
783 DumpVnodeIndex(int dumpfd, Volume * vp, VnodeClass class, afs_int32 fromtime,
784 int forcedump)
786 int code = 0;
787 struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
788 char buf[SIZEOF_LARGEDISKVNODE];
789 struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)buf;
790 StreamHandle_t *file;
791 FdHandle_t *fdP;
792 afs_sfsize_t size;
793 int flag;
794 afs_foff_t offset = 0;
795 int vnodeIndex, nVnodes = 0;
797 fdP = IH_OPEN(vp->vnodeIndex[class].handle);
798 file = FDH_FDOPEN(fdP, "r+");
799 size = OS_SIZE(fdP->fd_fd);
800 nVnodes = (size / vcp->diskSize) - 1;
802 if (nVnodes > 0) {
803 STREAM_ASEEK(file, vcp->diskSize);
804 } else
805 nVnodes = 0;
806 for (vnodeIndex = 0;
807 nVnodes && STREAM_READ(vnode, vcp->diskSize, 1, file) == 1 && !code;
808 nVnodes--, vnodeIndex++, offset += vcp->diskSize) {
809 flag = forcedump || (vnode->serverModifyTime >= fromtime);
810 /* Note: the >= test is very important since some old volumes may not have
811 * a serverModifyTime. For an epoch dump, this results in 0>=0 test, which
812 * does dump the file! */
813 if (verbose)
814 fprintf(stderr, "about to dump %s vnode %u (vnode offset = %lld)\n",
815 class == vSmall ? "vSmall" : "vLarge",
816 bitNumberToVnodeNumber(vnodeIndex, class), (long long)offset);
817 if (!code)
818 code =
819 DumpVnode(dumpfd, vnode, V_id(vp),
820 bitNumberToVnodeNumber(vnodeIndex, class), flag,
821 vp);
823 STREAM_CLOSE(file);
824 FDH_CLOSE(fdP);
825 return code;
830 /* A partial dump (no dump header) */
831 static int
832 DumpPartial(int dumpfd, Volume * vp, afs_int32 fromtime,
833 int dumpAllDirs)
835 int code = 0;
837 if (verbose)
838 fprintf(stderr, "about to dump the volume header\n");
839 if (!code)
840 code = DumpVolumeHeader(dumpfd, vp);
842 if (verbose)
843 fprintf(stderr, "about to dump the large vnode index\n");
844 if (!code)
845 code = DumpVnodeIndex(dumpfd, vp, vLarge, fromtime, dumpAllDirs);
847 if (verbose)
848 fprintf(stderr, "about to dump the small vnode index\n");
849 if (!code)
850 code = DumpVnodeIndex(dumpfd, vp, vSmall, fromtime, 0);
851 return code;
856 static void
857 DoMyVolDump(Volume * vp, struct DiskPartition64 *dp, char *dumpfile, int fromtime)
859 int code = 0;
860 int dumpAllDirs = 0;
861 int dumpfd = 0;
863 if (dumpfile) {
864 unlink(dumpfile);
865 dumpfd =
866 afs_open(dumpfile, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR);
867 if (dumpfd < 0) {
868 fprintf(stderr, "Failed to open dump file: %s. Exiting.\n",
869 afs_error_message(errno));
870 exit(1);
872 } else {
873 dumpfd = 1; /* stdout */
876 if (verbose)
877 fprintf(stderr, "about to dump the dump header\n");
878 if (!code)
879 code = DumpDumpHeader(dumpfd, vp, fromtime);
881 if (verbose)
882 fprintf(stderr, "about to dump volume contents\n");
883 if (!code)
884 code = DumpPartial(dumpfd, vp, fromtime, dumpAllDirs);
886 if (verbose)
887 fprintf(stderr, "about to dump the dump postamble\n");
888 if (!code)
889 code = DumpEnd(dumpfd);
891 if (verbose)
892 fprintf(stderr, "finished dump\n");
893 close(dumpfd); /* might be closing stdout, no harm */