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