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