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