c78f1c5d450cb681eac49e408fa818f766472a5b
[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         dumpTimes[1] = V_backupDate(vp);        /* until backup was made */
387         break;
388     default:
389         code = EINVAL;
390     }
391     if (!code)
392         code = DumpArrayInt32(dumpfd, 't', (afs_uint32 *) dumpTimes, 2);
393
394     return code;
395 }
396
397
398 static int
399 DumpEnd(int dumpfd)
400 {
401     return (DumpInt32(dumpfd, D_DUMPEND, DUMPENDMAGIC));
402 }
403
404 static int
405 DumpByte(int dumpfd, char tag, byte value)
406 {
407     char tbuffer[2];
408     byte *p = (unsigned char *)tbuffer;
409     *p++ = tag;
410     *p = value;
411     return ((write(dumpfd, tbuffer, 2) == 2) ? 0 : VOLSERDUMPERROR);
412 }
413
414 static int
415 DumpTag(int dumpfd, int tag)
416 {
417     char p;
418
419     p = tag;
420     return ((write(dumpfd, &p, 1) == 1) ? 0 : VOLSERDUMPERROR);
421
422 }
423
424 static int
425 DumpBool(int dumpfd, char tag, unsigned int value)
426 {
427     char tbuffer[2];
428     byte *p = (unsigned char *)tbuffer;
429     *p++ = tag;
430     *p = value;
431     return ((write(dumpfd, tbuffer, 2) == 2) ? 0 : VOLSERDUMPERROR);
432 }
433
434
435
436 static int
437 DumpVolumeHeader(int dumpfd, Volume * vp)
438 {
439     int code = 0;
440
441     if (verbose)
442         fprintf(stderr, "dumping volume header\n");
443
444     if (!code)
445         code = DumpTag(dumpfd, D_VOLUMEHEADER);
446     if (!code)
447         code = DumpInt32(dumpfd, 'i', V_id(vp));
448     if (!code)
449         code = DumpInt32(dumpfd, 'v', V_stamp(vp).version);
450     if (!code)
451         code = DumpString(dumpfd, 'n', V_name(vp));
452     if (!code)
453         code = DumpBool(dumpfd, 's', V_inService(vp));
454     if (!code)
455         code = DumpBool(dumpfd, 'b', V_blessed(vp));
456     if (!code)
457         code = DumpInt32(dumpfd, 'u', V_uniquifier(vp));
458     if (!code)
459         code = DumpByte(dumpfd, 't', (byte) V_type(vp));
460     if (!code)
461         code = DumpInt32(dumpfd, 'p', V_parentId(vp));
462     if (!code)
463         code = DumpInt32(dumpfd, 'c', V_cloneId(vp));
464     if (!code)
465         code = DumpInt32(dumpfd, 'q', V_maxquota(vp));
466     if (!code)
467         code = DumpInt32(dumpfd, 'm', V_minquota(vp));
468     if (!code)
469         code = DumpInt32(dumpfd, 'd', V_diskused(vp));
470     if (!code)
471         code = DumpInt32(dumpfd, 'f', V_filecount(vp));
472     if (!code)
473         code = DumpInt32(dumpfd, 'a', V_accountNumber(vp));
474     if (!code)
475         code = DumpInt32(dumpfd, 'o', V_owner(vp));
476     if (!code)
477         code = DumpInt32(dumpfd, 'C', V_creationDate(vp));      /* Rw volume creation date */
478     if (!code)
479         code = DumpInt32(dumpfd, 'A', V_accessDate(vp));
480     if (!code)
481         code = DumpInt32(dumpfd, 'U', V_updateDate(vp));
482     if (!code)
483         code = DumpInt32(dumpfd, 'E', V_expirationDate(vp));
484     if (!code)
485         code = DumpInt32(dumpfd, 'B', V_backupDate(vp));        /* Rw volume backup clone date */
486     if (!code)
487         code = DumpString(dumpfd, 'O', V_offlineMessage(vp));
488
489     /*
490      * We do NOT dump the detailed volume statistics residing in the old
491      * motd field, since we cannot tell from the info in a dump whether
492      * statistics data has been put there.  Instead, we dump a null string,
493      * just as if that was what the motd contained.
494      */
495     if (!code)
496         code = DumpString(dumpfd, 'M', "");
497     if (!code)
498         code =
499             DumpArrayInt32(dumpfd, 'W', (afs_uint32 *) V_weekUse(vp),
500                            sizeof(V_weekUse(vp)) / sizeof(V_weekUse(vp)[0]));
501     if (!code)
502         code = DumpInt32(dumpfd, 'D', V_dayUseDate(vp));
503     if (!code)
504         code = DumpInt32(dumpfd, 'Z', V_dayUse(vp));
505     return code;
506 }
507
508 static int
509 DumpShort(int dumpfd, char tag, unsigned int value)
510 {
511     char tbuffer[3];
512     byte *p = (unsigned char *)tbuffer;
513     *p++ = tag;
514     *p++ = value >> 8;
515     *p = value;
516     return ((write(dumpfd, tbuffer, 3) == 3) ? 0 : VOLSERDUMPERROR);
517 }
518
519 static int
520 DumpByteString(int dumpfd, char tag, byte * bs, int nbytes)
521 {
522     int code = 0;
523
524     code = write(dumpfd, &tag, 1);
525     if (code != 1)
526         return VOLSERDUMPERROR;
527     code = write(dumpfd, (char *)bs, nbytes);
528     if (code != nbytes)
529         return VOLSERDUMPERROR;
530     return 0;
531 }
532
533
534 static int
535 DumpFile(int dumpfd, int vnode, FdHandle_t * handleP,  struct VnodeDiskObject *v)
536 {
537     int code = 0, failed_seek = 0, failed_write = 0;
538     afs_int32 pad = 0;
539     afs_foff_t offset = 0;
540     afs_sfsize_t nbytes, howBig;
541     ssize_t n;
542     size_t howMany;
543     afs_foff_t howFar = 0;
544     byte *p;
545     afs_uint32 hi, lo;
546     afs_ino_str_t stmp;
547 #ifndef AFS_NT40_ENV
548     struct afs_stat status;
549 #else
550     LARGE_INTEGER fileSize;
551 #endif
552     afs_sfsize_t size;
553 #ifdef  AFS_AIX_ENV
554 #include <sys/statfs.h>
555     struct statfs tstatfs;
556 #endif
557
558     if (verbose)
559         fprintf(stderr, "dumping file for vnode %d\n", vnode);
560
561 #ifdef AFS_NT40_ENV
562     if (!GetFileSizeEx(handleP->fd_fd, &fileSize)) {
563         Log("DumpFile: GetFileSizeEx returned error code %d on descriptor %d\n", GetLastError(), handleP->fd_fd);
564             return VOLSERDUMPERROR;
565     }
566     howBig = fileSize.QuadPart;
567     howMany = 4096;
568
569 #else
570     afs_fstat(handleP->fd_fd, &status);
571     howBig = status.st_size;
572
573 #ifdef  AFS_AIX_ENV
574     /* Unfortunately in AIX valuable fields such as st_blksize are
575      * gone from the stat structure.
576      */
577     fstatfs(handleP->fd_fd, &tstatfs);
578     howMany = tstatfs.f_bsize;
579 #else
580     howMany = status.st_blksize;
581 #endif /* AFS_AIX_ENV */
582 #endif /* AFS_NT40_ENV */
583
584
585     size = FDH_SIZE(handleP);
586
587     if (verbose)
588         fprintf(stderr, "  howBig = %u, howMany = %u, fdh size = %u\n",
589                 (unsigned int) howBig, (unsigned int) howMany,
590                 (unsigned int) size);
591
592     SplitInt64(size, hi, lo);
593     if (hi == 0L) {
594         code = DumpInt32(dumpfd, 'f', lo);
595     } else {
596         code = DumpDouble(dumpfd, 'h', hi, lo);
597     }
598
599     if (code) {
600         return VOLSERDUMPERROR;
601     }
602
603     p = malloc(howMany);
604     if (!p) {
605         fprintf(stderr, "out of memory!\n");
606         return VOLSERDUMPERROR;
607     }
608
609     /* loop through whole file, while we still have bytes left, and no errors, in chunks of howMany bytes */
610     for (nbytes = size; (nbytes && !failed_write); nbytes -= howMany) {
611         if (nbytes < howMany)
612             howMany = nbytes;
613
614         /* Read the data - unless we know we can't */
615         n = (failed_seek ? 0 : FDH_PREAD(handleP, p, howMany, howFar));
616         howFar += n;
617
618         /* If read any good data and we null padded previously, log the
619          * amount that we had null padded.
620          */
621         if ((n > 0) && pad) {
622             fprintf(stderr, "Null padding file %d bytes at offset %lld\n", pad,
623                     (long long)offset);
624             pad = 0;
625         }
626
627         /* If didn't read enough data, null padd the rest of the buffer. This
628          * can happen if, for instance, the media has some bad spots. We don't
629          * want to quit the dump, so we start null padding.
630          */
631         if (n < howMany) {
632
633                 if (verbose) fprintf(stderr, "  read %u instead of %u bytes.\n", (unsigned)n, (unsigned)howMany);
634
635             /* Record the read error */
636             if (n < 0) {
637                 n = 0;
638                 fprintf(stderr, "Error %d reading inode %s for vnode %d\n",
639                         errno, PrintInode(stmp, handleP->fd_ih->ih_ino),
640                         vnode);
641             } else if (!pad) {
642                 fprintf(stderr, "Error reading inode %s for vnode %d\n",
643                         PrintInode(stmp, handleP->fd_ih->ih_ino), vnode);
644             }
645
646             /* Pad the rest of the buffer with zeros. Remember offset we started
647              * padding. Keep total tally of padding.
648              */
649             memset(p + n, 0, howMany - n);
650             if (!pad)
651                 offset = (howBig - nbytes) + n;
652             pad += (howMany - n);
653
654             /* Now seek over the data we could not get. An error here means we
655              * can't do the next read.
656              */
657             howFar = ((size - nbytes) + howMany);
658         }
659
660         /* Now write the data out */
661         if (write(dumpfd, (char *)p, howMany) != howMany)
662             failed_write = VOLSERDUMPERROR;
663     }
664
665     if (pad) {                  /* Any padding we hadn't reported yet */
666         fprintf(stderr, "Null padding file: %d bytes at offset %lld\n", pad,
667                 (long long)offset);
668     }
669
670     free(p);
671     return failed_write;
672 }
673
674
675 static int
676 DumpVnode(int dumpfd, struct VnodeDiskObject *v, int volid, int vnodeNumber,
677           int dumpEverything, struct Volume *vp)
678 {
679     int code = 0;
680     IHandle_t *ihP;
681     FdHandle_t *fdP;
682     afs_ino_str_t stmp;
683
684     if (verbose)
685         fprintf(stderr, "dumping vnode %d\n", vnodeNumber);
686
687     if (!v || v->type == vNull)
688         return code;
689     if (!code)
690         code = DumpDouble(dumpfd, D_VNODE, vnodeNumber, v->uniquifier);
691     if (!dumpEverything)
692         return code;
693     if (!code)
694         code = DumpByte(dumpfd, 't', (byte) v->type);
695     if (!code)
696         code = DumpShort(dumpfd, 'l', v->linkCount);    /* May not need this */
697     if (!code)
698         code = DumpInt32(dumpfd, 'v', v->dataVersion);
699     if (!code)
700         code = DumpInt32(dumpfd, 'm', v->unixModifyTime);
701     if (!code)
702         code = DumpInt32(dumpfd, 'a', v->author);
703     if (!code)
704         code = DumpInt32(dumpfd, 'o', v->owner);
705     if (!code && v->group)
706         code = DumpInt32(dumpfd, 'g', v->group);        /* default group is 0 */
707     if (!code)
708         code = DumpShort(dumpfd, 'b', v->modeBits);
709     if (!code)
710         code = DumpInt32(dumpfd, 'p', v->parent);
711     if (!code)
712         code = DumpInt32(dumpfd, 's', v->serverModifyTime);
713     if (v->type == vDirectory) {
714         acl_HtonACL(VVnodeDiskACL(v));
715         if (!code)
716             code =
717                 DumpByteString(dumpfd, 'A', (byte *) VVnodeDiskACL(v),
718                                VAclDiskSize(v));
719     }
720
721     if (VNDISK_GET_INO(v)) {
722         IH_INIT(ihP, V_device(vp), V_parentId(vp), VNDISK_GET_INO(v));
723         fdP = IH_OPEN(ihP);
724         if (fdP == NULL) {
725             fprintf(stderr,
726                     "Unable to open inode %s for vnode %u (volume %i); not dumped, error %d\n",
727                     PrintInode(stmp, VNDISK_GET_INO(v)), vnodeNumber, volid,
728                     errno);
729         }
730         else
731         {
732                 if (verbose)
733                     fprintf(stderr, "about to dump inode %s for vnode %u\n",
734                             PrintInode(stmp, VNDISK_GET_INO(v)), vnodeNumber);
735                 code = DumpFile(dumpfd, vnodeNumber, fdP, v);
736                 FDH_CLOSE(fdP);
737         }
738         IH_RELEASE(ihP);
739     }
740
741     if (verbose)
742         fprintf(stderr, "done dumping vnode %d\n", vnodeNumber);
743     return code;
744 }
745
746
747 static int
748 DumpVnodeIndex(int dumpfd, Volume * vp, VnodeClass class, afs_int32 fromtime,
749                int forcedump)
750 {
751     int code = 0;
752     struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
753     char buf[SIZEOF_LARGEDISKVNODE];
754     struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)buf;
755     StreamHandle_t *file;
756     FdHandle_t *fdP;
757     afs_sfsize_t size;
758     int flag;
759     afs_foff_t offset = 0;
760     int vnodeIndex, nVnodes = 0;
761
762     fdP = IH_OPEN(vp->vnodeIndex[class].handle);
763     file = FDH_FDOPEN(fdP, "r+");
764     size = OS_SIZE(fdP->fd_fd);
765     nVnodes = (size / vcp->diskSize) - 1;
766
767     if (nVnodes > 0) {
768         STREAM_ASEEK(file, vcp->diskSize);
769     } else
770         nVnodes = 0;
771     for (vnodeIndex = 0;
772          nVnodes && STREAM_READ(vnode, vcp->diskSize, 1, file) == 1 && !code;
773          nVnodes--, vnodeIndex++, offset += vcp->diskSize) {
774         flag = forcedump || (vnode->serverModifyTime >= fromtime);
775         /* Note:  the >= test is very important since some old volumes may not have
776          * a serverModifyTime.  For an epoch dump, this results in 0>=0 test, which
777          * does dump the file! */
778         if (verbose)
779             fprintf(stderr, "about to dump %s vnode %u (vnode offset = %lld)\n",
780                         class == vSmall ? "vSmall" : "vLarge",
781                     bitNumberToVnodeNumber(vnodeIndex, class), (long long)offset);
782         if (!code)
783             code =
784                 DumpVnode(dumpfd, vnode, V_id(vp),
785                           bitNumberToVnodeNumber(vnodeIndex, class), flag,
786                           vp);
787     }
788     STREAM_CLOSE(file);
789     FDH_CLOSE(fdP);
790     return code;
791 }
792
793
794
795 /* A partial dump (no dump header) */
796 static int
797 DumpPartial(int dumpfd, Volume * vp, afs_int32 fromtime,
798             int dumpAllDirs)
799 {
800     int code = 0;
801
802     if (verbose)
803         fprintf(stderr, "about to dump the volume header\n");
804     if (!code)
805         code = DumpVolumeHeader(dumpfd, vp);
806
807     if (verbose)
808         fprintf(stderr, "about to dump the large vnode index\n");
809     if (!code)
810         code = DumpVnodeIndex(dumpfd, vp, vLarge, fromtime, dumpAllDirs);
811
812     if (verbose)
813         fprintf(stderr, "about to dump the small vnode index\n");
814     if (!code)
815         code = DumpVnodeIndex(dumpfd, vp, vSmall, fromtime, 0);
816     return code;
817 }
818
819
820
821 static void
822 DoMyVolDump(Volume * vp, struct DiskPartition64 *dp, char *dumpfile, int fromtime)
823 {
824     int code = 0;
825     int dumpAllDirs = 0;
826     int dumpfd = 0;
827
828     if (dumpfile) {
829         unlink(dumpfile);
830         dumpfd =
831             afs_open(dumpfile, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR);
832         if (dumpfd < 0) {
833             fprintf(stderr, "Failed to open dump file: %s. Exiting.\n",
834                     afs_error_message(errno));
835             exit(1);
836         }
837     } else {
838         dumpfd = 1;             /* stdout */
839     }
840
841     if (verbose)
842         fprintf(stderr, "about to dump the dump header\n");
843     if (!code)
844         code = DumpDumpHeader(dumpfd, vp, fromtime);
845
846     if (verbose)
847         fprintf(stderr, "about to dump volume contents\n");
848     if (!code)
849         code = DumpPartial(dumpfd, vp, fromtime, dumpAllDirs);
850
851     if (verbose)
852         fprintf(stderr, "about to dump the dump postamble\n");
853     if (!code)
854         code = DumpEnd(dumpfd);
855
856     if (verbose)
857         fprintf(stderr, "finished dump\n");
858     close(dumpfd);              /* might be closing stdout, no harm */
859 }