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