4297d7075200e409a0defa6a0eb460cfa3fd151a
[openafs.git] / src / volser / dumpstuff.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 #include <afsconfig.h>
11 #include <afs/param.h>
12
13
14 #include <sys/types.h>
15 #include <ctype.h>
16 #include <stdio.h>
17 #include <errno.h>
18 #include <string.h>
19 #ifdef AFS_NT40_ENV
20 #include <fcntl.h>
21 #else
22 #include <sys/param.h>
23 #include <sys/file.h>
24 #include <sys/uio.h>
25 #include <netinet/in.h>
26 #include <unistd.h>
27 #endif
28 #include <sys/stat.h>
29 #include <afs/afs_assert.h>
30 #include <rx/xdr.h>
31 #include <rx/rx.h>
32 #include <afs/afsint.h>
33 #include <afs/nfs.h>
34 #include <afs/errors.h>
35 #include <lock.h>
36 #include <lwp.h>
37 #include <afs/ihandle.h>
38 #include <afs/vnode.h>
39 #include <afs/volume.h>
40 #include <afs/partition.h>
41 #include "dump.h"
42 #include <afs/daemon_com.h>
43 #include <afs/fssync.h>
44 #include <afs/acl.h>
45 #include <afs/com_err.h>
46 #include <afs/vol_prototypes.h>
47 #include "volser.h"
48 #include "volint.h"
49 #include "dumpstuff.h"
50
51 #ifndef AFS_NT40_ENV
52 #ifdef O_LARGEFILE
53 #define afs_stat        stat64
54 #define afs_fstat       fstat64
55 #else /* !O_LARGEFILE */
56 #define afs_stat        stat
57 #define afs_fstat       fstat
58 #endif /* !O_LARGEFILE */
59 #endif /* !AFS_NT40_ENV */
60
61 /*@printflike@*/ extern void Log(const char *format, ...);
62
63 extern int DoLogging;
64
65
66 /* Forward Declarations */
67 static int DumpDumpHeader(struct iod *iodp, Volume * vp,
68                           afs_int32 fromtime);
69 static int DumpPartial(struct iod *iodp, Volume * vp,
70                        afs_int32 fromtime, int dumpAllDirs);
71 static int DumpVnodeIndex(struct iod *iodp, Volume * vp,
72                           VnodeClass class, afs_int32 fromtime,
73                           int forcedump);
74 static int DumpVnode(struct iod *iodp, struct VnodeDiskObject *v,
75                      int volid, int vnodeNumber, int dumpEverything);
76 static int ReadDumpHeader(struct iod *iodp, struct DumpHeader *hp);
77 static int ReadVnodes(struct iod *iodp, Volume * vp, int incremental,
78                       afs_int32 * Lbuf, afs_int32 s1, afs_int32 * Sbuf,
79                       afs_int32 s2, afs_int32 delo);
80 static afs_fsize_t volser_WriteFile(int vn, struct iod *iodp,
81                                     FdHandle_t * handleP, int tag,
82                                     Error * status);
83
84 static int SizeDumpDumpHeader(struct iod *iodp, Volume * vp,
85                               afs_int32 fromtime,
86                               struct volintSize *size);
87 static int SizeDumpPartial(struct iod *iodp, Volume * vp,
88                            afs_int32 fromtime, int dumpAllDirs,
89                            struct volintSize *size);
90 static int SizeDumpVnodeIndex(struct iod *iodp, Volume * vp,
91                               VnodeClass class, afs_int32 fromtime,
92                               int forcedump,
93                               struct volintSize *size);
94 static int SizeDumpVnode(struct iod *iodp, struct VnodeDiskObject *v,
95                          int volid, int vnodeNumber, int dumpEverything,
96                          struct volintSize *size);
97
98 #define MAX_SECTIONS    3
99 #define MIN_TLV_TAG     5
100 #define MAX_TLV_TAG     0x60
101 #define MAX_STANDARD_TAG 0x7a
102 static afs_uint32 oldtags[MAX_SECTIONS][16];
103 int oldtagsInited = 0;
104
105 static void
106 RegisterTag(afs_int32 section, unsigned char tag)
107 {
108     afs_uint32 off = tag >> 5;
109     afs_uint32 mask = 1 << (tag & 0x1f);
110     oldtags[section][off] |= mask;
111 }
112
113 static void
114 initNonStandardTags(void)
115 {
116     RegisterTag(0, 'n');                /* volume name */
117     RegisterTag(0, 't');                /* fromtime, V_backupDate */
118     RegisterTag(1, 'A');                /* V_accessDate */
119     RegisterTag(1, 'C');                /* V_creationDate */
120     RegisterTag(1, 'D');                /* V_dayUseDate */
121     RegisterTag(1, 'E');                /* V_expirationDate */
122     RegisterTag(1, 'M');                /* nullstring (motd) */
123     RegisterTag(1, 'U');                /* V_updateDate */
124     RegisterTag(1, 'W');                /* V_weekUse */
125     RegisterTag(1, 'Z');                /* V_dayUse */
126     RegisterTag(1, 'O');                /* V_offlineMessage */
127     RegisterTag(1, 'b');                /* V_blessed */
128     RegisterTag(1, 'n');                /* V_name */
129     RegisterTag(1, 's');                /* V_inService */
130     RegisterTag(1, 't');                /* V_type */
131     RegisterTag(2, 'A');                /* VVnodeDiskACL */
132     RegisterTag(2, 'b');                /* modeBits */
133     RegisterTag(2, 'f');                /* small file */
134     RegisterTag(2, 'h');                /* large file */
135     RegisterTag(2, 'l');                /* linkcount */
136     RegisterTag(2, 't');                /* type */
137     oldtagsInited = 1;
138 }
139
140 static void
141 iod_Init(struct iod *iodp, struct rx_call *call)
142 {
143     iodp->call = call;
144     iodp->haveOldChar = 0;
145     iodp->ncalls = 1;
146     iodp->calls = (struct rx_call **)0;
147 }
148
149 static void
150 iod_InitMulti(struct iod *iodp, struct rx_call **calls, int ncalls,
151               int *codes)
152 {
153
154     iodp->calls = calls;
155     iodp->haveOldChar = 0;
156     iodp->ncalls = ncalls;
157     iodp->codes = codes;
158     iodp->call = (struct rx_call *)0;
159 }
160
161 /* N.B. iod_Read doesn't check for oldchar (see previous comment) */
162 #define iod_Read(iodp, buf, nbytes) rx_Read((iodp)->call, buf, nbytes)
163
164 /* For the single dump case, it's ok to just return the "bytes written"
165  * that rx_Write returns, since all the callers of iod_Write abort when
166  * the returned value is less than they expect.  For the multi dump case,
167  * I don't think we want half the replicas to go bad just because one
168  * connection timed out, but if they all time out, then we should give up.
169  */
170 static int
171 iod_Write(struct iod *iodp, char *buf, int nbytes)
172 {
173     int code, i;
174     int one_success = 0;
175
176     osi_Assert((iodp->call && iodp->ncalls == 1 && !iodp->calls)
177            || (!iodp->call && iodp->ncalls >= 1 && iodp->calls));
178
179     if (iodp->call) {
180         code = rx_Write(iodp->call, buf, nbytes);
181         return code;
182     }
183
184     for (i = 0; i < iodp->ncalls; i++) {
185         if (iodp->calls[i] && !iodp->codes[i]) {
186             code = rx_Write(iodp->calls[i], buf, nbytes);
187             if (code != nbytes) {       /* everything gets merged into a single error */
188                 iodp->codes[i] = VOLSERDUMPERROR;       /* but that's exactly what the */
189             } /* standard dump does, anyways */
190             else {
191                 one_success = TRUE;
192             }
193         }
194     }                           /* for all calls */
195
196     if (one_success)
197         return nbytes;
198     else
199         return 0;
200 }
201
202 static void
203 iod_ungetc(struct iod *iodp, int achar)
204 {
205     iodp->oldChar = achar;
206     iodp->haveOldChar = 1;
207 }
208
209 static int
210 iod_getc(struct iod *iodp)
211 {
212     unsigned char t;
213
214     if (iodp->haveOldChar) {
215         iodp->haveOldChar = 0;
216         return iodp->oldChar;
217     }
218     if (iod_Read(iodp, (char *) &t, 1) == 1)
219         return t;
220     return EOF;
221 }
222
223 static int
224 ReadShort(struct iod *iodp, unsigned short *sp)
225 {
226     int b1, b0;
227     b1 = iod_getc(iodp);
228     if (b1 == EOF)
229         return 0;
230     b0 = iod_getc(iodp);
231     if (b0 == EOF)
232         return 0;
233     *sp = (b1 << 8) | b0;
234     return 1;
235 }
236
237 static int
238 ReadInt32(struct iod *iodp, afs_uint32 * lp)
239 {
240     afs_uint32 b3, b2, b1, b0;
241     b3 = iod_getc(iodp);
242     if (b3 == EOF)
243         return 0;
244     b2 = iod_getc(iodp);
245     if (b2 == EOF)
246         return 0;
247     b1 = iod_getc(iodp);
248     if (b1 == EOF)
249         return 0;
250     b0 = iod_getc(iodp);
251     if (b0 == EOF)
252         return 0;
253     *lp = (((((b3 << 8) | b2) << 8) | b1) << 8) | b0;
254     return 1;
255 }
256
257 static void
258 ReadString(struct iod *iodp, char *to, int maxa)
259 {
260     int c;
261
262     *to = '\0';
263     if (maxa == 0)
264         return;
265
266     while (maxa--) {
267         if ((*to++ = c = iod_getc(iodp)) == 0 || c == EOF)
268             break;
269     }
270     if (to[-1]) {
271         while ((c = iod_getc(iodp)) && c != EOF);
272         to[-1] = '\0';
273     }
274 }
275
276 static void
277 ReadByteString(struct iod *iodp, byte * to,
278                int size)
279 {
280     while (size--)
281         *to++ = iod_getc(iodp);
282 }
283
284 /*
285  * returns 1 on success and 0 otherwise
286  */
287 static afs_int32
288 ReadStandardTagLen(struct iod *iodp, unsigned char tag, afs_int32 section,
289                         afs_size_t *length)
290 {
291     afs_int32 code, i;
292     afs_uint32 off = tag >> 5;
293     afs_uint32 mask = 1 << (tag & 0x1f);
294     unsigned char len, buf[8], *p;
295
296     if (!oldtagsInited)
297         initNonStandardTags();
298
299     if (tag < MIN_TLV_TAG
300       || tag > MAX_STANDARD_TAG
301       || section >= MAX_SECTIONS
302       || (oldtags[section][ off] & mask)) {
303         Log("Trying to use ReadStandardTag with tag 0x%02x for section %d, aborting\n", tag, section);
304         return 0;
305     }
306     if (tag <= MAX_TLV_TAG) {
307         len = iod_getc(iodp);
308         if (len < 128)
309             *length = len;
310         else {
311             len &= 0x7f;
312             if ((code = iod_Read(iodp, (char *)buf, len)) != len)
313                 return VOLSERDUMPERROR;
314             *length = 0;
315             p = (unsigned char *)&buf;
316             for (i=0; i<len; i++) {
317                 *length = ((*length) << 8) | *p++;
318             }
319         }
320     } else {
321         if (tag < MAX_STANDARD_TAG)
322             *length = 4;
323     }
324     return 1;
325 }
326
327 static char skipbuf[256];
328
329 static afs_int32
330 SkipData(struct iod *iodp, afs_size_t length)
331 {
332     while (length > 256) {
333         if (iod_Read(iodp, (char *)&skipbuf, 256) != 256)
334             return 0;
335         length -= 256;
336     }
337     if (iod_Read(iodp, (char *)&skipbuf, length) != length)
338         return 0;
339     return 1;
340 }
341
342 static char *secname[3] = {"ReadDumpHeader", "ReadVolumeHeader", "ReadVnodes"};
343
344 static int
345 HandleUnknownTag(struct iod *iodp, int tag, afs_int32 section,
346                 afs_int32 critical)
347 {
348     afs_size_t taglen = 0;
349     afs_uint32 trash;
350
351     if (critical) {
352         Log("%s: unknown critical tag x%02x, aborting\n",
353                 secname[section], tag);
354         return 0;
355     }
356     Log("%s: unknown tag x%02x found, skipping\n", secname[section], tag);
357     if (tag >= 0x06 && tag <= 0x60) {
358         if (!ReadStandardTagLen(iodp, tag, 1, &taglen)) {
359             Log("%s: error reading length field for tag x%02x, aborting\n",
360                 secname[section], tag);
361             return 0;
362         }
363         if (!SkipData(iodp, taglen)) {
364             Log("%s: error skipping %llu bytes for tag x%02x, aborting\n",
365                 secname[section], taglen, tag);
366             return 0;
367         }
368         return 1;
369     }
370     if (tag >= 0x61 && tag <= 0x7a) {
371         if (!ReadInt32(iodp, &trash)) {
372             Log("%s: error skipping int32 for tag x%02x, aborting\n",
373                 secname[section], tag);
374             return 0;
375         }
376         return 1;
377     }
378     if (tag >= 0x7b && tag < 0x80)      /* dataless tag */
379         return 1;
380     Log("%s: unknown invalid tag x%02x, aborting\n", secname[section], tag);
381     return 0;
382 }
383
384 static int
385 ReadVolumeHeader(struct iod *iodp, VolumeDiskData * vol)
386 {
387     int tag;
388     afs_uint32 trash;
389     afs_int32 critical = 0;
390     memset(vol, 0, sizeof(*vol));
391     while ((tag = iod_getc(iodp)) > D_MAX && tag != EOF) {
392         if (critical)
393             critical--;
394         switch (tag) {
395         case 'i':
396             if (!ReadInt32(iodp, &vol->id))
397                 return VOLSERREAD_DUMPERROR;
398             break;
399         case 'v':
400             if (!ReadInt32(iodp, &trash))
401                 return VOLSERREAD_DUMPERROR;
402             break;
403         case 'n':
404             ReadString(iodp, vol->name, sizeof(vol->name));
405             /*this means the name of the retsored volume could be possibly different. In conjunction with SAFSVolSignalRestore */
406             break;
407         case 's':
408             vol->inService = iod_getc(iodp);
409             break;
410         case 'b':
411             vol->blessed = iod_getc(iodp);
412             break;
413         case 'u':
414             if (!ReadInt32(iodp, &vol->uniquifier))
415                 return VOLSERREAD_DUMPERROR;
416             break;
417         case 't':
418             vol->type = iod_getc(iodp);
419             break;
420         case 'p':
421             if (!ReadInt32(iodp, &vol->parentId))
422                 return VOLSERREAD_DUMPERROR;
423             break;
424         case 'c':
425             if (!ReadInt32(iodp, &vol->cloneId))
426                 return VOLSERREAD_DUMPERROR;
427             break;
428         case 'q':
429             if (!ReadInt32(iodp, (afs_uint32 *) & vol->maxquota))
430                 return VOLSERREAD_DUMPERROR;
431             break;
432         case 'm':
433             if (!ReadInt32(iodp, (afs_uint32 *) & vol->minquota))
434                 return VOLSERREAD_DUMPERROR;
435             break;
436         case 'd':
437             if (!ReadInt32(iodp, (afs_uint32 *) & vol->diskused))
438                 return VOLSERREAD_DUMPERROR;    /* Bogus:  should calculate this */
439             break;
440         case 'f':
441             if (!ReadInt32(iodp, (afs_uint32 *) & vol->filecount))
442                 return VOLSERREAD_DUMPERROR;
443             break;
444         case 'a':
445             if (!ReadInt32(iodp, &vol->accountNumber))
446                 return VOLSERREAD_DUMPERROR;
447             break;
448         case 'o':
449             if (!ReadInt32(iodp, &vol->owner))
450                 return VOLSERREAD_DUMPERROR;
451             break;
452         case 'C':
453             if (!ReadInt32(iodp, &vol->creationDate))
454                 return VOLSERREAD_DUMPERROR;
455             break;
456         case 'A':
457             if (!ReadInt32(iodp, &vol->accessDate))
458                 return VOLSERREAD_DUMPERROR;
459             break;
460         case 'U':
461             if (!ReadInt32(iodp, &vol->updateDate))
462                 return VOLSERREAD_DUMPERROR;
463             break;
464         case 'E':
465             if (!ReadInt32(iodp, &vol->expirationDate))
466                 return VOLSERREAD_DUMPERROR;
467             break;
468         case 'B':
469             if (!ReadInt32(iodp, &vol->backupDate))
470                 return VOLSERREAD_DUMPERROR;
471             break;
472         case 'O':
473             ReadString(iodp, vol->offlineMessage,
474                        sizeof(vol->offlineMessage));
475             break;
476         case 'M':
477             /*
478              * Detailed volume statistics are never stored in dumps,
479              * so we just restore either the null string if this volume
480              * had already been set to store statistics, or the old motd
481              * contents otherwise.  It doesn't matter, since this field
482              * will soon get initialized anyway.
483              */
484             ReadString(iodp, (char *)(vol->stat_reads), VMSGSIZE);
485             break;
486         case 'W':{
487                 unsigned short length;
488                 int i;
489                 afs_uint32 data;
490                 if (!ReadShort(iodp, &length))
491                     return VOLSERREAD_DUMPERROR;
492                 for (i = 0; i < length; i++) {
493                     if (!ReadInt32(iodp, &data))
494                         return VOLSERREAD_DUMPERROR;
495                     if (i < sizeof(vol->weekUse) / sizeof(vol->weekUse[0]))
496                         vol->weekUse[i] = data;
497                 }
498                 break;
499             }
500         case 'D':
501             if (!ReadInt32(iodp, &vol->dayUseDate))
502                 return VOLSERREAD_DUMPERROR;
503             break;
504         case 'Z':
505             if (!ReadInt32(iodp, (afs_uint32 *) & vol->dayUse))
506                 return VOLSERREAD_DUMPERROR;
507             break;
508         case 'V':
509             if (!ReadInt32(iodp, (afs_uint32 *) &trash/*volUpdateCounter*/))
510                 return VOLSERREAD_DUMPERROR;
511             break;
512         case 0x7e:
513             critical = 2;
514             break;
515         default:
516             if (!HandleUnknownTag(iodp, tag, 1, critical))
517                 return VOLSERREAD_DUMPERROR;
518         }
519     }
520     iod_ungetc(iodp, tag);
521     return 0;
522 }
523
524 static int
525 DumpTag(struct iod *iodp, int tag)
526 {
527     char p;
528
529     p = tag;
530     return ((iod_Write(iodp, &p, 1) == 1) ? 0 : VOLSERDUMPERROR);
531
532 }
533
534 static int
535 DumpByte(struct iod *iodp, char tag, byte value)
536 {
537     char tbuffer[2];
538     byte *p = (unsigned char *)tbuffer;
539     *p++ = tag;
540     *p = value;
541     return ((iod_Write(iodp, tbuffer, 2) == 2) ? 0 : VOLSERDUMPERROR);
542 }
543
544 #define putint32(p, v)  *p++ = v>>24, *p++ = v>>16, *p++ = v>>8, *p++ = v
545 #define putshort(p, v) *p++ = v>>8, *p++ = v
546
547 static int
548 DumpDouble(struct iod *iodp, char tag, afs_uint32 value1,
549            afs_uint32 value2)
550 {
551     char tbuffer[9];
552     byte *p = (unsigned char *)tbuffer;
553     *p++ = tag;
554     putint32(p, value1);
555     putint32(p, value2);
556     return ((iod_Write(iodp, tbuffer, 9) == 9) ? 0 : VOLSERDUMPERROR);
557 }
558
559 static int
560 DumpInt32(struct iod *iodp, char tag, afs_uint32 value)
561 {
562     char tbuffer[5];
563     byte *p = (unsigned char *)tbuffer;
564     *p++ = tag;
565     putint32(p, value);
566     return ((iod_Write(iodp, tbuffer, 5) == 5) ? 0 : VOLSERDUMPERROR);
567 }
568
569 static int
570 DumpArrayInt32(struct iod *iodp, char tag,
571                afs_uint32 * array, int nelem)
572 {
573     char tbuffer[4];
574     afs_uint32 v;
575     int code = 0;
576     byte *p = (unsigned char *)tbuffer;
577     *p++ = tag;
578     putshort(p, nelem);
579     code = iod_Write(iodp, tbuffer, 3);
580     if (code != 3)
581         return VOLSERDUMPERROR;
582     while (nelem--) {
583         p = (unsigned char *)tbuffer;
584         v = *array++;           /*this was register */
585
586         putint32(p, v);
587         code = iod_Write(iodp, tbuffer, 4);
588         if (code != 4)
589             return VOLSERDUMPERROR;
590     }
591     return 0;
592 }
593
594 static int
595 DumpShort(struct iod *iodp, char tag, unsigned int value)
596 {
597     char tbuffer[3];
598     byte *p = (unsigned char *)tbuffer;
599     *p++ = tag;
600     *p++ = value >> 8;
601     *p = value;
602     return ((iod_Write(iodp, tbuffer, 3) == 3) ? 0 : VOLSERDUMPERROR);
603 }
604
605 static int
606 DumpBool(struct iod *iodp, char tag, unsigned int value)
607 {
608     char tbuffer[2];
609     byte *p = (unsigned char *)tbuffer;
610     *p++ = tag;
611     *p = value;
612     return ((iod_Write(iodp, tbuffer, 2) == 2) ? 0 : VOLSERDUMPERROR);
613 }
614
615 static int
616 DumpString(struct iod *iodp, char tag, char *s)
617 {
618     int n;
619     int code = 0;
620     code = iod_Write(iodp, &tag, 1);
621     if (code != 1)
622         return VOLSERDUMPERROR;
623     n = strlen(s) + 1;
624     code = iod_Write(iodp, s, n);
625     if (code != n)
626         return VOLSERDUMPERROR;
627     return 0;
628 }
629
630 static int
631 DumpByteString(struct iod *iodp, char tag, byte * bs,
632                int nbytes)
633 {
634     int code = 0;
635
636     code = iod_Write(iodp, &tag, 1);
637     if (code != 1)
638         return VOLSERDUMPERROR;
639     code = iod_Write(iodp, (char *)bs, nbytes);
640     if (code != nbytes)
641         return VOLSERDUMPERROR;
642     return 0;
643 }
644
645 static afs_int32
646 DumpStandardTag(struct iod *iodp, char tag, afs_uint32 section)
647 {
648     afs_int32 code;
649     afs_uint32 off = tag >> 5;
650     afs_uint32 mask = 1 << (tag & 0x1f);
651
652     if (!oldtagsInited)
653         initNonStandardTags();
654
655     if (tag < MIN_TLV_TAG
656       || tag > MAX_STANDARD_TAG
657       || section >= MAX_SECTIONS
658       || (oldtags[section][ off] & mask)) {
659         Log("Trying to use DumpStandardTag with tag 0x%02x for section %d, aborting\n", tag, section);
660         return VOLSERDUMPERROR;
661     }
662     code = iod_Write(iodp, &tag, 1);
663     if (code != 1)
664         return VOLSERDUMPERROR;
665     return 0;
666 }
667
668 AFS_UNUSED
669 static afs_int32
670 DumpStandardTagLen(struct iod *iodp, char tag, afs_uint32 section,
671                         afs_size_t length)
672 {
673     char buf[10];
674     char *p;
675     afs_int32 code, len;
676
677     if (tag < MIN_TLV_TAG || tag > MAX_TLV_TAG) {
678         Log("Trying to use DumpStandardTagLen with tag 0x%02x for section %d, aborting\n", tag, section);
679         return VOLSERDUMPERROR;
680     }
681     code = DumpStandardTag(iodp, tag, section);
682     if (code)
683         return code;
684     p = &buf[9];
685     if (length < 128) { /* byte after tag contains length */
686         *p-- = length;
687         len = 1;
688     } else {            /* byte after tag contains length of length field | 0x80 */
689         for (len=0; length; length=length >> 8) {
690             *p-- = length;
691             len++;
692         }
693         *p-- = len + 128;
694         len += 1;
695     }
696     p++;
697     code = iod_Write(iodp, p, len);
698     if (code != len)
699         return VOLSERDUMPERROR;
700     return 0;
701 }
702
703 static int
704 DumpFile(struct iod *iodp, int vnode, FdHandle_t * handleP)
705 {
706     int code = 0, error = 0;
707     afs_int32 pad = 0;
708     afs_int32 offset = 0;
709     afs_sfsize_t nbytes, howBig;
710     ssize_t n;
711     size_t howMany;
712     afs_foff_t howFar = 0;
713     byte *p;
714     afs_uint32 hi, lo;
715     afs_ino_str_t stmp;
716 #ifndef AFS_NT40_ENV
717     struct afs_stat status;
718 #endif
719     afs_sfsize_t size;
720 #ifdef  AFS_AIX_ENV
721 #include <sys/statfs.h>
722 #if defined(AFS_AIX52_ENV)
723     struct statfs64 tstatfs;
724 #else /* !AFS_AIX52_ENV */
725     struct statfs tstatfs;
726 #endif /* !AFS_AIX52_ENV */
727     int statfs_code;
728 #endif
729
730 #ifdef AFS_NT40_ENV
731     howBig = _filelength(handleP->fd_fd);
732     howMany = 4096;
733
734 #else
735     afs_fstat(handleP->fd_fd, &status);
736     howBig = status.st_size;
737
738 #ifdef  AFS_AIX_ENV
739     /* Unfortunately in AIX valuable fields such as st_blksize are
740      * gone from the stat structure.
741      */
742 #if defined(AFS_AIX52_ENV)
743     statfs_code = fstatfs64(handleP->fd_fd, &tstatfs);
744 #else /* !AFS_AIX52_ENV */
745     statfs_code = fstatfs(handleP->fd_fd, &tstatfs);
746 #endif /* !AFS_AIX52_ENV */
747     if (statfs_code != 0) {
748         Log("DumpFile: fstatfs returned error code %d on descriptor %d\n", errno, handleP->fd_fd);
749         return VOLSERDUMPERROR;
750     }
751     howMany = tstatfs.f_bsize;
752 #else
753     howMany = status.st_blksize;
754 #endif /* AFS_AIX_ENV */
755 #endif /* AFS_NT40_ENV */
756
757
758     size = FDH_SIZE(handleP);
759     SplitInt64(size, hi, lo);
760     if (hi == 0L) {
761         code = DumpInt32(iodp, 'f', lo);
762     } else {
763         code = DumpDouble(iodp, 'h', hi, lo);
764     }
765     if (code) {
766         return VOLSERDUMPERROR;
767     }
768
769     p = malloc(howMany);
770     if (!p) {
771         Log("1 Volser: DumpFile: not enough memory to allocate %u bytes\n", (unsigned)howMany);
772         return VOLSERDUMPERROR;
773     }
774
775     for (nbytes = size; (nbytes && !error); nbytes -= howMany) {
776         if (nbytes < howMany)
777             howMany = nbytes;
778
779         /* Read the data */
780         n = FDH_PREAD(handleP, p, howMany, howFar);
781         howFar += n;
782
783         /* If read any good data and we null padded previously, log the
784          * amount that we had null padded.
785          */
786         if ((n > 0) && pad) {
787             Log("1 Volser: DumpFile: Null padding file %d bytes at offset %u\n", pad, offset);
788             pad = 0;
789         }
790
791         /* If didn't read enough data, null padd the rest of the buffer. This
792          * can happen if, for instance, the media has some bad spots. We don't
793          * want to quit the dump, so we start null padding.
794          */
795         if (n < howMany) {
796             /* Record the read error */
797             if (n < 0) {
798                 n = 0;
799                 Log("1 Volser: DumpFile: Error reading inode %s for vnode %d: %s\n", PrintInode(stmp, handleP->fd_ih->ih_ino), vnode, afs_error_message(errno));
800             } else if (!pad) {
801                 Log("1 Volser: DumpFile: Error reading inode %s for vnode %d\n", PrintInode(stmp, handleP->fd_ih->ih_ino), vnode);
802             }
803
804             /* Pad the rest of the buffer with zeros. Remember offset we started
805              * padding. Keep total tally of padding.
806              */
807             memset(p + n, 0, howMany - n);
808             if (!pad)
809                 offset = (howBig - nbytes) + n;
810             pad += (howMany - n);
811
812             /* Now seek over the data we could not get. An error here means we
813              * can't do the next read.
814              */
815             howFar = (size_t)((size - nbytes) + howMany);
816         }
817
818         /* Now write the data out */
819         if (iod_Write(iodp, (char *)p, howMany) != howMany)
820             error = VOLSERDUMPERROR;
821 #ifndef AFS_PTHREAD_ENV
822         IOMGR_Poll();
823 #endif
824     }
825
826     if (pad) {                  /* Any padding we hadn't reported yet */
827         Log("1 Volser: DumpFile: Null padding file: %d bytes at offset %u\n",
828             pad, offset);
829     }
830
831     free(p);
832     return error;
833 }
834
835 static int
836 DumpVolumeHeader(struct iod *iodp, Volume * vp)
837 {
838     int code = 0;
839     static char nullString[1] = "";     /*The ``contents'' of motd */
840
841     if (!code)
842         code = DumpTag(iodp, D_VOLUMEHEADER);
843     if (!code) {
844         code = DumpInt32(iodp, 'i', V_id(vp));
845     }
846     if (!code)
847         code = DumpInt32(iodp, 'v', V_stamp(vp).version);
848     if (!code)
849         code = DumpString(iodp, 'n', V_name(vp));
850     if (!code)
851         code = DumpBool(iodp, 's', V_inService(vp));
852     if (!code)
853         code = DumpBool(iodp, 'b', V_blessed(vp));
854     if (!code)
855         code = DumpInt32(iodp, 'u', V_uniquifier(vp));
856     if (!code)
857         code = DumpByte(iodp, 't', (byte) V_type(vp));
858     if (!code) {
859         code = DumpInt32(iodp, 'p', V_parentId(vp));
860     }
861     if (!code)
862         code = DumpInt32(iodp, 'c', V_cloneId(vp));
863     if (!code)
864         code = DumpInt32(iodp, 'q', V_maxquota(vp));
865     if (!code)
866         code = DumpInt32(iodp, 'm', V_minquota(vp));
867     if (!code)
868         code = DumpInt32(iodp, 'd', V_diskused(vp));
869     if (!code)
870         code = DumpInt32(iodp, 'f', V_filecount(vp));
871     if (!code)
872         code = DumpInt32(iodp, 'a', V_accountNumber(vp));
873     if (!code)
874         code = DumpInt32(iodp, 'o', V_owner(vp));
875     if (!code)
876         code = DumpInt32(iodp, 'C', V_creationDate(vp));        /* Rw volume creation date */
877     if (!code)
878         code = DumpInt32(iodp, 'A', V_accessDate(vp));
879     if (!code)
880         code = DumpInt32(iodp, 'U', V_updateDate(vp));
881     if (!code)
882         code = DumpInt32(iodp, 'E', V_expirationDate(vp));
883     if (!code)
884         code = DumpInt32(iodp, 'B', V_backupDate(vp));  /* Rw volume backup clone date */
885     if (!code)
886         code = DumpString(iodp, 'O', V_offlineMessage(vp));
887     /*
888      * We do NOT dump the detailed volume statistics residing in the old
889      * motd field, since we cannot tell from the info in a dump whether
890      * statistics data has been put there.  Instead, we dump a null string,
891      * just as if that was what the motd contained.
892      */
893     if (!code)
894         code = DumpString(iodp, 'M', nullString);
895     if (!code)
896         code =
897             DumpArrayInt32(iodp, 'W', (afs_uint32 *) V_weekUse(vp),
898                            sizeof(V_weekUse(vp)) / sizeof(V_weekUse(vp)[0]));
899     if (!code)
900         code = DumpInt32(iodp, 'D', V_dayUseDate(vp));
901     if (!code)
902         code = DumpInt32(iodp, 'Z', V_dayUse(vp));
903     return code;
904 }
905
906 static int
907 DumpEnd(struct iod *iodp)
908 {
909     return (DumpInt32(iodp, D_DUMPEND, DUMPENDMAGIC));
910 }
911
912 /* Guts of the dump code */
913
914 /* Dump a whole volume */
915 int
916 DumpVolume(struct rx_call *call, Volume * vp,
917            afs_int32 fromtime, int dumpAllDirs)
918 {
919     struct iod iod;
920     int code = 0;
921     struct iod *iodp = &iod;
922     iod_Init(iodp, call);
923
924     if (!code)
925         code = DumpDumpHeader(iodp, vp, fromtime);
926
927     if (!code)
928         code = DumpPartial(iodp, vp, fromtime, dumpAllDirs);
929
930 /* hack follows.  Errors should be handled quite differently in this version of dump than they used to be.*/
931     if (rx_Error(iodp->call)) {
932         Log("1 Volser: DumpVolume: Rx call failed during dump, error %d\n",
933             rx_Error(iodp->call));
934         return VOLSERDUMPERROR;
935     }
936     if (!code)
937         code = DumpEnd(iodp);
938
939     return code;
940 }
941
942 /* Dump a volume to multiple places*/
943 int
944 DumpVolMulti(struct rx_call **calls, int ncalls, Volume * vp,
945              afs_int32 fromtime, int dumpAllDirs, int *codes)
946 {
947     struct iod iod;
948     int code = 0;
949     iod_InitMulti(&iod, calls, ncalls, codes);
950
951     if (!code)
952         code = DumpDumpHeader(&iod, vp, fromtime);
953     if (!code)
954         code = DumpPartial(&iod, vp, fromtime, dumpAllDirs);
955     if (!code)
956         code = DumpEnd(&iod);
957     return code;
958 }
959
960 /* A partial dump (no dump header) */
961 static int
962 DumpPartial(struct iod *iodp, Volume * vp,
963             afs_int32 fromtime, int dumpAllDirs)
964 {
965     int code = 0;
966     if (!code)
967         code = DumpVolumeHeader(iodp, vp);
968     if (!code)
969         code = DumpVnodeIndex(iodp, vp, vLarge, fromtime, dumpAllDirs);
970     if (!code)
971         code = DumpVnodeIndex(iodp, vp, vSmall, fromtime, 0);
972     return code;
973 }
974
975 static int
976 DumpVnodeIndex(struct iod *iodp, Volume * vp, VnodeClass class,
977                afs_int32 fromtime, int forcedump)
978 {
979     int code = 0;
980     struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
981     char buf[SIZEOF_LARGEDISKVNODE];
982     struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)buf;
983     StreamHandle_t *file;
984     FdHandle_t *fdP;
985     afs_sfsize_t size, nVnodes;
986     int flag;
987     int vnodeIndex;
988
989     fdP = IH_OPEN(vp->vnodeIndex[class].handle);
990     osi_Assert(fdP != NULL);
991     file = FDH_FDOPEN(fdP, "r+");
992     osi_Assert(file != NULL);
993     size = OS_SIZE(fdP->fd_fd);
994     osi_Assert(size != -1);
995     nVnodes = (size / vcp->diskSize) - 1;
996     if (nVnodes > 0) {
997         osi_Assert((nVnodes + 1) * vcp->diskSize == size);
998         osi_Assert(STREAM_ASEEK(file, vcp->diskSize) == 0);
999     } else
1000         nVnodes = 0;
1001     for (vnodeIndex = 0;
1002          nVnodes && STREAM_READ(vnode, vcp->diskSize, 1, file) == 1 && !code;
1003          nVnodes--, vnodeIndex++) {
1004         flag = forcedump || (vnode->serverModifyTime >= fromtime);
1005         /* Note:  the >= test is very important since some old volumes may not have
1006          * a serverModifyTime.  For an epoch dump, this results in 0>=0 test, which
1007          * does dump the file! */
1008         if (!code)
1009             code =
1010                 DumpVnode(iodp, vnode, V_id(vp),
1011                           bitNumberToVnodeNumber(vnodeIndex, class), flag);
1012 #ifndef AFS_PTHREAD_ENV
1013         if (!flag)
1014             IOMGR_Poll();       /* if we dont' xfr data, but scan instead, could lose conn */
1015 #endif
1016     }
1017     STREAM_CLOSE(file);
1018     FDH_CLOSE(fdP);
1019     return code;
1020 }
1021
1022 static int
1023 DumpDumpHeader(struct iod *iodp, Volume * vp,
1024                afs_int32 fromtime)
1025 {
1026     int code = 0;
1027     int UseLatestReadOnlyClone = 1;
1028     afs_int32 dumpTimes[2];
1029     iodp->device = vp->device;
1030     iodp->parentId = V_parentId(vp);
1031     iodp->dumpPartition = vp->partition;
1032     if (!code)
1033         code = DumpDouble(iodp, D_DUMPHEADER, DUMPBEGINMAGIC, DUMPVERSION);
1034     if (!code)
1035         code =
1036             DumpInt32(iodp, 'v',
1037                       UseLatestReadOnlyClone ? V_id(vp) : V_parentId(vp));
1038     if (!code)
1039         code = DumpString(iodp, 'n', V_name(vp));
1040     dumpTimes[0] = fromtime;
1041     dumpTimes[1] = V_backupDate(vp);    /* Until the time the clone was made */
1042     if (!code)
1043         code = DumpArrayInt32(iodp, 't', (afs_uint32 *) dumpTimes, 2);
1044     return code;
1045 }
1046
1047 static int
1048 DumpVnode(struct iod *iodp, struct VnodeDiskObject *v, int volid,
1049           int vnodeNumber, int dumpEverything)
1050 {
1051     int code = 0;
1052     IHandle_t *ihP;
1053     FdHandle_t *fdP;
1054
1055     if (!v || v->type == vNull)
1056         return code;
1057     if (!code)
1058         code = DumpDouble(iodp, D_VNODE, vnodeNumber, v->uniquifier);
1059     if (!dumpEverything)
1060         return code;
1061     if (!code)
1062         code = DumpByte(iodp, 't', (byte) v->type);
1063     if (!code)
1064         code = DumpShort(iodp, 'l', v->linkCount);      /* May not need this */
1065     if (!code)
1066         code = DumpInt32(iodp, 'v', v->dataVersion);
1067     if (!code)
1068         code = DumpInt32(iodp, 'm', v->unixModifyTime);
1069     if (!code)
1070         code = DumpInt32(iodp, 'a', v->author);
1071     if (!code)
1072         code = DumpInt32(iodp, 'o', v->owner);
1073     if (!code && v->group)
1074         code = DumpInt32(iodp, 'g', v->group);  /* default group is 0 */
1075     if (!code)
1076         code = DumpShort(iodp, 'b', v->modeBits);
1077     if (!code)
1078         code = DumpInt32(iodp, 'p', v->parent);
1079     if (!code)
1080         code = DumpInt32(iodp, 's', v->serverModifyTime);
1081     if (v->type == vDirectory) {
1082         acl_HtonACL(VVnodeDiskACL(v));
1083         if (!code)
1084             code =
1085                 DumpByteString(iodp, 'A', (byte *) VVnodeDiskACL(v),
1086                                VAclDiskSize(v));
1087     }
1088     if (VNDISK_GET_INO(v)) {
1089         IH_INIT(ihP, iodp->device, iodp->parentId, VNDISK_GET_INO(v));
1090         fdP = IH_OPEN(ihP);
1091         if (fdP == NULL) {
1092             Log("1 Volser: DumpVnode: dump: Unable to open inode %llu for vnode %u (volume %i); not dumped, error %d\n", (afs_uintmax_t) VNDISK_GET_INO(v), vnodeNumber, volid, errno);
1093             IH_RELEASE(ihP);
1094             return VOLSERREAD_DUMPERROR;
1095         }
1096         code = DumpFile(iodp, vnodeNumber, fdP);
1097         FDH_CLOSE(fdP);
1098         IH_RELEASE(ihP);
1099     }
1100     return code;
1101 }
1102
1103
1104 int
1105 ProcessIndex(Volume * vp, VnodeClass class, afs_int32 ** Bufp, int *sizep,
1106              int del)
1107 {
1108     int i, nVnodes, offset, code;
1109     afs_int32 *Buf;
1110     int cnt = 0;
1111     afs_sfsize_t size;
1112     StreamHandle_t *afile;
1113     FdHandle_t *fdP;
1114     struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
1115     char buf[SIZEOF_LARGEDISKVNODE], zero[SIZEOF_LARGEDISKVNODE];
1116     struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)buf;
1117
1118     memset(zero, 0, sizeof(zero));      /* zero out our proto-vnode */
1119     fdP = IH_OPEN(vp->vnodeIndex[class].handle);
1120     if (fdP == NULL)
1121         return -1;
1122     afile = FDH_FDOPEN(fdP, "r+");
1123     if (del) {
1124         int cnt1 = 0;
1125         Buf = *Bufp;
1126         for (i = 0; i < *sizep; i++) {
1127             if (Buf[i]) {
1128                 cnt++;
1129                 STREAM_ASEEK(afile, Buf[i]);
1130                 code = STREAM_READ(vnode, vcp->diskSize, 1, afile);
1131                 if (code == 1) {
1132                     if (vnode->type != vNull && VNDISK_GET_INO(vnode)) {
1133                         cnt1++;
1134                         if (DoLogging) {
1135                             Log("RestoreVolume %u Cleanup: Removing old vnode=%u inode=%llu size=unknown\n",
1136                      V_id(vp), bitNumberToVnodeNumber(i, class),
1137                      (afs_uintmax_t) VNDISK_GET_INO(vnode));
1138                         }
1139                         IH_DEC(V_linkHandle(vp), VNDISK_GET_INO(vnode),
1140                                V_parentId(vp));
1141                         DOPOLL;
1142                     }
1143                     STREAM_ASEEK(afile, Buf[i]);
1144                     (void)STREAM_WRITE(zero, vcp->diskSize, 1, afile);  /* Zero it out */
1145                 }
1146                 Buf[i] = 0;
1147             }
1148         }
1149         if (DoLogging) {
1150             Log("RestoreVolume Cleanup: Removed %d inodes for volume %d\n",
1151                 cnt1, V_id(vp));
1152         }
1153         STREAM_FLUSH(afile);    /* ensure 0s are on the disk */
1154         OS_SYNC(afile->str_fd);
1155     } else {
1156         size = OS_SIZE(fdP->fd_fd);
1157         osi_Assert(size != -1);
1158         nVnodes =
1159             (size <=
1160              vcp->diskSize ? 0 : size - vcp->diskSize) >> vcp->logSize;
1161         if (nVnodes > 0) {
1162             if (DoLogging) {
1163                 Log("RestoreVolume ProcessIndex: Set up %d inodes for volume %d\n",
1164                     nVnodes, V_id(vp));
1165             }
1166             Buf = (afs_int32 *) malloc(nVnodes * sizeof(afs_int32));
1167             if (Buf == NULL) {
1168                 STREAM_CLOSE(afile);
1169                 FDH_CLOSE(fdP);
1170                 return -1;
1171             }
1172             memset(Buf, 0, nVnodes * sizeof(afs_int32));
1173             STREAM_ASEEK(afile, offset = vcp->diskSize);
1174             while (1) {
1175                 code = STREAM_READ(vnode, vcp->diskSize, 1, afile);
1176                 if (code != 1) {
1177                     break;
1178                 }
1179                 if (vnode->type != vNull && VNDISK_GET_INO(vnode)) {
1180                     Buf[(offset >> vcp->logSize) - 1] = offset;
1181                     cnt++;
1182                 }
1183                 offset += vcp->diskSize;
1184             }
1185             if (DoLogging) {
1186                 Log("RestoreVolume ProcessIndex: found %d inodes\n", cnt);
1187             }
1188             *Bufp = Buf;
1189             *sizep = nVnodes;
1190         }
1191     }
1192     STREAM_CLOSE(afile);
1193     FDH_CLOSE(fdP);
1194     return 0;
1195 }
1196
1197
1198 int
1199 RestoreVolume(struct rx_call *call, Volume * avp, int incremental,
1200               struct restoreCookie *cookie)
1201 {
1202     VolumeDiskData vol;
1203     struct DumpHeader header;
1204     afs_uint32 endMagic;
1205     Error error = 0, vupdate;
1206     Volume *vp;
1207     struct iod iod;
1208     struct iod *iodp = &iod;
1209     afs_int32 *b1 = NULL, *b2 = NULL;
1210     int s1 = 0, s2 = 0, delo = 0, tdelo;
1211     int tag;
1212
1213     iod_Init(iodp, call);
1214
1215     vp = avp;
1216
1217     if (!ReadDumpHeader(iodp, &header)) {
1218         Log("1 Volser: RestoreVolume: Error reading header file for dump; aborted\n");
1219         return VOLSERREAD_DUMPERROR;
1220     }
1221     if (iod_getc(iodp) != D_VOLUMEHEADER) {
1222         Log("1 Volser: RestoreVolume: Volume header missing from dump; not restored\n");
1223         return VOLSERREAD_DUMPERROR;
1224     }
1225     if (ReadVolumeHeader(iodp, &vol) == VOLSERREAD_DUMPERROR)
1226         return VOLSERREAD_DUMPERROR;
1227
1228     if (!delo)
1229         delo = ProcessIndex(vp, vLarge, &b1, &s1, 0);
1230     if (!delo)
1231         delo = ProcessIndex(vp, vSmall, &b2, &s2, 0);
1232     if (delo < 0) {
1233         Log("1 Volser: RestoreVolume: ProcessIndex failed; not restored\n");
1234         error = VOLSERREAD_DUMPERROR;
1235         goto out;
1236     }
1237
1238     strncpy(vol.name, cookie->name, VOLSER_OLDMAXVOLNAME);
1239     vol.type = cookie->type;
1240     vol.cloneId = cookie->clone;
1241     vol.parentId = cookie->parent;
1242
1243     tdelo = delo;
1244     while (1) {
1245         if (ReadVnodes(iodp, vp, 0, b1, s1, b2, s2, tdelo)) {
1246             error = VOLSERREAD_DUMPERROR;
1247             goto clean;
1248         }
1249         tag = iod_getc(iodp);
1250         if (tag != D_VOLUMEHEADER)
1251             break;
1252
1253         if (ReadVolumeHeader(iodp, &vol) == VOLSERREAD_DUMPERROR) {
1254             error = VOLSERREAD_DUMPERROR;
1255             goto out;
1256         }
1257     }
1258     if (tag != D_DUMPEND || !ReadInt32(iodp, &endMagic)
1259         || endMagic != DUMPENDMAGIC) {
1260         Log("1 Volser: RestoreVolume: End of dump not found; restore aborted\n");
1261         error = VOLSERREAD_DUMPERROR;
1262         goto clean;
1263     }
1264
1265
1266     if (iod_getc(iodp) != EOF) {
1267         Log("1 Volser: RestoreVolume: Unrecognized postamble in dump; restore aborted\n");
1268         error = VOLSERREAD_DUMPERROR;
1269         goto clean;
1270     }
1271
1272     if (!delo) {
1273         delo = ProcessIndex(vp, vLarge, &b1, &s1, 1);
1274         if (!delo)
1275             delo = ProcessIndex(vp, vSmall, &b2, &s2, 1);
1276         if (delo < 0) {
1277             error = VOLSERREAD_DUMPERROR;
1278             goto clean;
1279         }
1280     }
1281
1282   clean:
1283     ClearVolumeStats(&vol);
1284     CopyVolumeHeader(&vol, &V_disk(vp));
1285     V_destroyMe(vp) = 0;
1286     VUpdateVolume(&vupdate, vp);
1287     if (vupdate) {
1288         Log("1 Volser: RestoreVolume: Unable to rewrite volume header; restore aborted\n");
1289         error = VOLSERREAD_DUMPERROR;
1290         goto out;
1291     }
1292   out:
1293     /* Free the malloced space above */
1294     if (b1)
1295         free((char *)b1);
1296     if (b2)
1297         free((char *)b2);
1298     return error;
1299 }
1300
1301 static int
1302 ReadVnodes(struct iod *iodp, Volume * vp, int incremental,
1303            afs_int32 * Lbuf, afs_int32 s1, afs_int32 * Sbuf, afs_int32 s2,
1304            afs_int32 delo)
1305 {
1306     afs_int32 vnodeNumber;
1307     char buf[SIZEOF_LARGEDISKVNODE];
1308     int tag;
1309     struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)buf;
1310     struct VnodeDiskObject oldvnode;
1311     int idx;
1312     VnodeClass class;
1313     struct VnodeClassInfo *vcp;
1314     IHandle_t *tmpH;
1315     FdHandle_t *fdP;
1316     Inode nearInode;
1317     afs_int32 critical = 0;
1318
1319     tag = iod_getc(iodp);
1320     V_pref(vp, nearInode);
1321     while (tag == D_VNODE) {
1322         int haveStuff = 0;
1323         int saw_f = 0;
1324         memset(buf, 0, sizeof(buf));
1325         if (!ReadInt32(iodp, (afs_uint32 *) & vnodeNumber))
1326             break;
1327
1328         if (!ReadInt32(iodp, &vnode->uniquifier))
1329             return VOLSERREAD_DUMPERROR;
1330
1331         if (DoLogging) {
1332             Log("ReadVnodes: setup %d/%d\n", vnodeNumber, vnode->uniquifier);
1333         }
1334         while ((tag = iod_getc(iodp)) > D_MAX && tag != EOF) {
1335             haveStuff = 1;
1336             if (critical)
1337                 critical--;
1338             switch (tag) {
1339             case 't':
1340                 vnode->type = (VnodeType) iod_getc(iodp);
1341                 break;
1342             case 'l':
1343                 {
1344                     unsigned short tlc;
1345                     if (!ReadShort(iodp, &tlc))
1346                         return VOLSERREAD_DUMPERROR;
1347                     vnode->linkCount = (signed int)tlc;
1348                 }
1349                 break;
1350             case 'v':
1351                 if (!ReadInt32(iodp, &vnode->dataVersion))
1352                     return VOLSERREAD_DUMPERROR;
1353                 break;
1354             case 'm':
1355                 if (!ReadInt32(iodp, &vnode->unixModifyTime))
1356                     return VOLSERREAD_DUMPERROR;
1357                 break;
1358             case 's':
1359                 if (!ReadInt32(iodp, &vnode->serverModifyTime))
1360                     return VOLSERREAD_DUMPERROR;
1361                 break;
1362             case 'a':
1363                 if (!ReadInt32(iodp, &vnode->author))
1364                     return VOLSERREAD_DUMPERROR;
1365                 break;
1366             case 'o':
1367                 if (!ReadInt32(iodp, &vnode->owner))
1368                     return VOLSERREAD_DUMPERROR;
1369                 break;
1370             case 'g':
1371                 if (!ReadInt32(iodp, (afs_uint32 *) & vnode->group))
1372                     return VOLSERREAD_DUMPERROR;
1373                 break;
1374             case 'b':{
1375                     unsigned short modeBits;
1376                     if (!ReadShort(iodp, &modeBits))
1377                         return VOLSERREAD_DUMPERROR;
1378                     vnode->modeBits = (unsigned int)modeBits;
1379                     break;
1380                 }
1381             case 'p':
1382                 if (!ReadInt32(iodp, &vnode->parent))
1383                     return VOLSERREAD_DUMPERROR;
1384                 break;
1385             case 'A':
1386                 ReadByteString(iodp, (byte *) VVnodeDiskACL(vnode),
1387                                VAclDiskSize(vnode));
1388                 acl_NtohACL(VVnodeDiskACL(vnode));
1389                 break;
1390             case 'h':
1391             case 'f':{
1392                     Inode ino;
1393                     Error error;
1394                     afs_fsize_t vnodeLength;
1395
1396                     if (saw_f) {
1397                         Log("Volser: ReadVnodes: warning: ignoring duplicate "
1398                             "file entries for vnode %lu in dump\n",
1399                             (unsigned long)vnodeNumber);
1400                         volser_WriteFile(vnodeNumber, iodp, NULL, tag, &error);
1401                         break;
1402                     }
1403                     saw_f = 1;
1404
1405                     ino =
1406                         IH_CREATE(V_linkHandle(vp), V_device(vp),
1407                                   VPartitionPath(V_partition(vp)), nearInode,
1408                                   V_parentId(vp), vnodeNumber,
1409                                   vnode->uniquifier, vnode->dataVersion);
1410                     if (!VALID_INO(ino)) {
1411                         Log("1 Volser: ReadVnodes: IH_CREATE: %s - restore aborted\n",
1412                             afs_error_message(errno));
1413                         return VOLSERREAD_DUMPERROR;
1414                     }
1415                     nearInode = ino;
1416                     VNDISK_SET_INO(vnode, ino);
1417                     IH_INIT(tmpH, vp->device, V_parentId(vp), ino);
1418                     fdP = IH_OPEN(tmpH);
1419                     if (fdP == NULL) {
1420                         Log("1 Volser: ReadVnodes: IH_OPEN: %s - restore aborted\n",
1421                             afs_error_message(errno));
1422                         IH_RELEASE(tmpH);
1423                         return VOLSERREAD_DUMPERROR;
1424                     }
1425                     vnodeLength =
1426                         volser_WriteFile(vnodeNumber, iodp, fdP, tag, &error);
1427                     VNDISK_SET_LEN(vnode, vnodeLength);
1428                     FDH_REALLYCLOSE(fdP);
1429                     IH_RELEASE(tmpH);
1430                     if (error) {
1431                         Log("1 Volser: ReadVnodes: IDEC inode %llu\n",
1432                             (afs_uintmax_t) ino);
1433                         IH_DEC(V_linkHandle(vp), ino, V_parentId(vp));
1434                         return VOLSERREAD_DUMPERROR;
1435                     }
1436                     break;
1437                 }
1438             case 0x7e:
1439                 critical = 2;
1440                 break;
1441             default:
1442                 if (!HandleUnknownTag(iodp, tag, 2, critical))
1443                     return VOLSERREAD_DUMPERROR;
1444             }
1445         }
1446
1447         class = vnodeIdToClass(vnodeNumber);
1448         vcp = &VnodeClassInfo[class];
1449
1450         /* Mark this vnode as in this dump - so we don't delete it later */
1451         if (!delo) {
1452             idx = (vnodeIndexOffset(vcp, vnodeNumber) >> vcp->logSize) - 1;
1453             if (class == vLarge) {
1454                 if (Lbuf && (idx < s1))
1455                     Lbuf[idx] = 0;
1456             } else {
1457                 if (Sbuf && (idx < s2))
1458                     Sbuf[idx] = 0;
1459             }
1460         }
1461
1462         if (haveStuff) {
1463             FdHandle_t *fdP = IH_OPEN(vp->vnodeIndex[class].handle);
1464             if (fdP == NULL) {
1465                 Log("1 Volser: ReadVnodes: Error opening vnode index: %s; restore aborted\n",
1466                     afs_error_message(errno));
1467                 return VOLSERREAD_DUMPERROR;
1468             }
1469             if (FDH_PREAD(fdP, &oldvnode, sizeof(oldvnode), vnodeIndexOffset(vcp, vnodeNumber)) ==
1470                 sizeof(oldvnode)) {
1471                 if (oldvnode.type != vNull && VNDISK_GET_INO(&oldvnode)) {
1472                     IH_DEC(V_linkHandle(vp), VNDISK_GET_INO(&oldvnode),
1473                            V_parentId(vp));
1474                 }
1475             }
1476             vnode->vnodeMagic = vcp->magic;
1477             if (FDH_PWRITE(fdP, vnode, vcp->diskSize, vnodeIndexOffset(vcp, vnodeNumber)) != vcp->diskSize) {
1478                 Log("1 Volser: ReadVnodes: Error writing vnode index: %s; restore aborted\n",
1479                     afs_error_message(errno));
1480                 FDH_REALLYCLOSE(fdP);
1481                 return VOLSERREAD_DUMPERROR;
1482             }
1483             FDH_CLOSE(fdP);
1484         }
1485     }
1486     iod_ungetc(iodp, tag);
1487
1488     return 0;
1489 }
1490
1491
1492 /* called with disk file only.  Note that we don't have to worry about rx_Read
1493  * needing to read an ungetc'd character, since the ReadInt32 will have read
1494  * it instead.
1495  *
1496  * if handleP == NULL, don't write the file anywhere; just read and discard
1497  * the file contents
1498  */
1499 static afs_fsize_t
1500 volser_WriteFile(int vn, struct iod *iodp, FdHandle_t * handleP, int tag,
1501                  Error * status)
1502 {
1503     afs_int32 code;
1504     ssize_t nBytes;
1505     afs_fsize_t filesize;
1506     afs_fsize_t written = 0;
1507     size_t size = 8192;
1508     afs_fsize_t nbytes;
1509     unsigned char *p;
1510
1511
1512     *status = 0;
1513     {
1514         afs_uint32 filesize_high = 0L, filesize_low = 0L;
1515         if (tag == 'h') {
1516             if (!ReadInt32(iodp, &filesize_high)) {
1517                 *status = 1;
1518                 return 0;
1519             }
1520         }
1521         if (!ReadInt32(iodp, &filesize_low)) {
1522             *status = 1;
1523             return 0;
1524         }
1525         FillInt64(filesize, filesize_high, filesize_low);
1526     }
1527     p = (unsigned char *)malloc(size);
1528     if (p == NULL) {
1529         *status = 2;
1530         return (0);
1531     }
1532     for (nbytes = filesize; nbytes; nbytes -= size) {
1533         if (nbytes < size)
1534             size = nbytes;
1535
1536         if ((code = iod_Read(iodp, (char *) p, size)) != size) {
1537             Log("1 Volser: WriteFile: Error reading dump file %d size=%llu nbytes=%u (%d of %u): %s; restore aborted\n", vn, (afs_uintmax_t) filesize, nbytes, code, (unsigned)size, afs_error_message(errno));
1538             *status = 3;
1539             break;
1540         }
1541         if (handleP) {
1542             nBytes = FDH_PWRITE(handleP, p, size, written);
1543             if (nBytes > 0)
1544                 written += nBytes;
1545             if (nBytes != size) {
1546                 Log("1 Volser: WriteFile: Error writing (%u) bytes to vnode %d; %s; restore aborted\n", (int)(nBytes & 0xffffffff), vn, afs_error_message(errno));
1547                 *status = 4;
1548                 break;
1549             }
1550         }
1551     }
1552     free(p);
1553     return (written);
1554 }
1555
1556 static int
1557 ReadDumpHeader(struct iod *iodp, struct DumpHeader *hp)
1558 {
1559     int tag;
1560     afs_uint32 beginMagic;
1561     afs_int32 critical = 0;
1562     if (iod_getc(iodp) != D_DUMPHEADER || !ReadInt32(iodp, &beginMagic)
1563         || !ReadInt32(iodp, (afs_uint32 *) & hp->version)
1564         || beginMagic != DUMPBEGINMAGIC)
1565         return 0;
1566     hp->volumeId = 0;
1567     hp->nDumpTimes = 0;
1568     while ((tag = iod_getc(iodp)) > D_MAX) {
1569         unsigned short arrayLength;
1570         int i;
1571         if (critical)
1572             critical--;
1573         switch (tag) {
1574         case 'v':
1575             if (!ReadInt32(iodp, &hp->volumeId))
1576                 return 0;
1577             break;
1578         case 'n':
1579             ReadString(iodp, hp->volumeName, sizeof(hp->volumeName));
1580             break;
1581         case 't':
1582             if (!ReadShort(iodp, &arrayLength))
1583                 return 0;
1584             hp->nDumpTimes = (arrayLength >> 1);
1585             for (i = 0; i < hp->nDumpTimes; i++)
1586                 if (!ReadInt32(iodp, (afs_uint32 *) & hp->dumpTimes[i].from)
1587                     || !ReadInt32(iodp, (afs_uint32 *) & hp->dumpTimes[i].to))
1588                     return 0;
1589             break;
1590         case 0x7e:
1591             critical = 2;
1592             break;
1593         default:
1594             if (!HandleUnknownTag(iodp, tag, 0, critical))
1595                 return VOLSERREAD_DUMPERROR;
1596         }
1597     }
1598     if (!hp->volumeId || !hp->nDumpTimes) {
1599         return 0;
1600     }
1601     iod_ungetc(iodp, tag);
1602     return 1;
1603 }
1604
1605
1606 /* ----- Below are the calls that calculate dump size ----- */
1607
1608 static int
1609 SizeDumpVolumeHeader(struct iod *iodp, Volume * vp,
1610                      struct volintSize *v_size)
1611 {
1612     int code = 0;
1613     static char nullString[1] = "";     /*The ``contents'' of motd */
1614     afs_uint64 addvar;
1615
1616 /*     if (!code) code = DumpTag(iodp, D_VOLUMEHEADER); */
1617     FillInt64(addvar,0, 1);
1618     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1619 /*     if (!code) {code = DumpInt32(iodp, 'i',V_id(vp));} */
1620     FillInt64(addvar,0, 5);
1621     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1622 /*     if (!code) code = DumpInt32(iodp, 'v',V_stamp(vp).version); */
1623     FillInt64(addvar,0, 5);
1624     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1625 /*     if (!code) code = DumpString(iodp, 'n',V_name(vp)); */
1626     FillInt64(addvar,0, (2 + strlen(V_name(vp))));
1627     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1628 /*     if (!code) code = DumpBool(iodp, 's',V_inService(vp)); */
1629     FillInt64(addvar,0, 2);
1630     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1631 /*     if (!code) code = DumpBool(iodp, 'b',V_blessed(vp)); */
1632     FillInt64(addvar,0, 2);
1633     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1634 /*     if (!code) code = DumpInt32(iodp, 'u',V_uniquifier(vp)); */
1635     FillInt64(addvar,0, 5);
1636     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1637 /*     if (!code) code = DumpByte(iodp, 't',(byte)V_type(vp)); */
1638     FillInt64(addvar,0, 2);
1639     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1640 /*     if (!code){ code = DumpInt32(iodp, 'p',V_parentId(vp));} */
1641     FillInt64(addvar,0, 5);
1642     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1643 /*     if (!code) code = DumpInt32(iodp, 'c',V_cloneId(vp)); */
1644     FillInt64(addvar,0, 5);
1645     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1646 /*     if (!code) code = DumpInt32(iodp, 'q',V_maxquota(vp)); */
1647     FillInt64(addvar,0, 5);
1648     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1649 /*     if (!code) code = DumpInt32(iodp, 'm',V_minquota(vp)); */
1650     FillInt64(addvar,0, 5);
1651     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1652 /*     if (!code) code = DumpInt32(iodp, 'd',V_diskused(vp)); */
1653     FillInt64(addvar,0, 5);
1654     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1655 /*     if (!code) code = DumpInt32(iodp, 'f',V_filecount(vp)); */
1656     FillInt64(addvar,0, 5);
1657     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1658 /*     if (!code) code = DumpInt32(iodp, 'a', V_accountNumber(vp)); */
1659     FillInt64(addvar,0, 5);
1660     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1661 /*     if (!code) code = DumpInt32(iodp, 'o', V_owner(vp)); */
1662     FillInt64(addvar,0, 5);
1663     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1664 /*     if (!code) code = DumpInt32(iodp, 'C',V_creationDate(vp));       /\* Rw volume creation date *\/ */
1665     FillInt64(addvar,0, 5);
1666     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1667 /*     if (!code) code = DumpInt32(iodp, 'A',V_accessDate(vp)); */
1668     FillInt64(addvar,0, 5);
1669     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1670 /*     if (!code) code = DumpInt32(iodp, 'U',V_updateDate(vp)); */
1671     FillInt64(addvar,0, 5);
1672     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1673 /*     if (!code) code = DumpInt32(iodp, 'E',V_expirationDate(vp)); */
1674     FillInt64(addvar,0, 5);
1675     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1676 /*     if (!code) code = DumpInt32(iodp, 'B',V_backupDate(vp));         /\* Rw volume backup clone date *\/ */
1677     FillInt64(addvar,0, 5);
1678     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1679 /*     if (!code) code = DumpString(iodp, 'O',V_offlineMessage(vp)); */
1680     FillInt64(addvar,0, (2 + strlen(V_offlineMessage(vp))));
1681     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1682 /*     /\* */
1683 /*      * We do NOT dump the detailed volume statistics residing in the old */
1684 /*      * motd field, since we cannot tell from the info in a dump whether */
1685 /*      * statistics data has been put there.  Instead, we dump a null string, */
1686 /*      * just as if that was what the motd contained. */
1687 /*      *\/ */
1688 /*     if (!code) code = DumpString(iodp, 'M', nullString); */
1689     FillInt64(addvar,0, (2 + strlen(nullString)));
1690     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1691 /*     if (!code) code = DumpArrayInt32(iodp, 'W', (afs_uint32 *)V_weekUse(vp), sizeof(V_weekUse(vp))/sizeof(V_weekUse(vp)[0])); */
1692     FillInt64(addvar,0, (3 + 4 * (sizeof(V_weekUse(vp)) / sizeof(V_weekUse(vp)[0]))));
1693     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1694 /*     if (!code) code = DumpInt32(iodp, 'D', V_dayUseDate(vp)); */
1695     FillInt64(addvar,0, 5);
1696     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1697 /*     if (!code) code = DumpInt32(iodp, 'Z', V_dayUse(vp)); */
1698     FillInt64(addvar,0, 5);
1699     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1700     return code;
1701 }
1702
1703 static int
1704 SizeDumpEnd(struct iod *iodp, struct volintSize *v_size)
1705 {
1706     int code = 0;
1707     afs_uint64 addvar;
1708     FillInt64(addvar,0, 5);
1709     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1710     return code;
1711 }
1712
1713 int
1714 SizeDumpVolume(struct rx_call *call, Volume * vp,
1715                afs_int32 fromtime, int dumpAllDirs,
1716                struct volintSize *v_size)
1717 {
1718     int code = 0;
1719     struct iod *iodp = (struct iod *)0;
1720 /*    iod_Init(iodp, call); */
1721
1722     if (!code)
1723         code = SizeDumpDumpHeader(iodp, vp, fromtime, v_size);
1724     if (!code)
1725         code = SizeDumpPartial(iodp, vp, fromtime, dumpAllDirs, v_size);
1726     if (!code)
1727         code = SizeDumpEnd(iodp, v_size);
1728
1729     return code;
1730 }
1731
1732 static int
1733 SizeDumpDumpHeader(struct iod *iodp, Volume * vp,
1734                    afs_int32 fromtime, struct volintSize *v_size)
1735 {
1736     int code = 0;
1737 /*    int UseLatestReadOnlyClone = 1; */
1738 /*    afs_int32 dumpTimes[2]; */
1739     afs_uint64 addvar;
1740 /*    iodp->device = vp->device; */
1741 /*    iodp->parentId = V_parentId(vp); */
1742 /*    iodp->dumpPartition = vp->partition; */
1743
1744     ZeroInt64(v_size->dump_size);       /* initialize the size */
1745 /*     if (!code) code = DumpDouble(iodp, D_DUMPHEADER, DUMPBEGINMAGIC, DUMPVERSION); */
1746     FillInt64(addvar,0, 9);
1747     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1748 /*     if (!code) code = DumpInt32(iodp, 'v', UseLatestReadOnlyClone? V_id(vp): V_parentId(vp)); */
1749     FillInt64(addvar,0, 5);
1750     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1751 /*     if (!code) code = DumpString(iodp, 'n',V_name(vp)); */
1752     FillInt64(addvar,0, (2 + strlen(V_name(vp))));
1753     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1754 /*     dumpTimes[0] = fromtime; */
1755 /*     dumpTimes[1] = V_backupDate(vp); /\* Until the time the clone was made *\/ */
1756 /*     if (!code) code = DumpArrayInt32(iodp, 't', (afs_uint32 *)dumpTimes, 2); */
1757     FillInt64(addvar,0, (3 + 4 * 2));
1758     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1759     return code;
1760 }
1761
1762 static int
1763 SizeDumpVnode(struct iod *iodp, struct VnodeDiskObject *v, int volid,
1764               int vnodeNumber, int dumpEverything,
1765               struct volintSize *v_size)
1766 {
1767     int code = 0;
1768     afs_uint64 addvar;
1769
1770     if (!v || v->type == vNull)
1771         return code;
1772 /*     if (!code) code = DumpDouble(iodp, D_VNODE, vnodeNumber, v->uniquifier); */
1773     FillInt64(addvar,0, 9);
1774     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1775     if (!dumpEverything)
1776         return code;
1777 /*     if (!code)  code = DumpByte(iodp, 't',(byte)v->type); */
1778     FillInt64(addvar,0, 2);
1779     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1780 /*     if (!code) code = DumpShort(iodp, 'l', v->linkCount); /\* May not need this *\/ */
1781     FillInt64(addvar,0, 3);
1782     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1783 /*     if (!code) code = DumpInt32(iodp, 'v', v->dataVersion); */
1784     FillInt64(addvar,0, 5);
1785     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1786 /*     if (!code) code = DumpInt32(iodp, 'm', v->unixModifyTime); */
1787     FillInt64(addvar,0, 5);
1788     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1789 /*     if (!code) code = DumpInt32(iodp, 'a', v->author); */
1790     FillInt64(addvar,0, 5);
1791     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1792 /*     if (!code) code = DumpInt32(iodp, 'o', v->owner); */
1793     FillInt64(addvar,0, 5);
1794     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1795 /*     if (!code && v->group) code = DumpInt32(iodp, 'g', v->group);    /\* default group is 0 *\/ */
1796     if (v->group) {
1797         FillInt64(addvar,0, 5);
1798         AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1799     }
1800 /*     if (!code) code = DumpShort(iodp, 'b', v->modeBits); */
1801     FillInt64(addvar,0, 3);
1802     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1803 /*     if (!code) code = DumpInt32(iodp, 'p', v->parent); */
1804     FillInt64(addvar,0, 5);
1805     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1806 /*     if (!code) code = DumpInt32(iodp, 's', v->serverModifyTime); */
1807     FillInt64(addvar,0, 5);
1808     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1809     if (v->type == vDirectory) {
1810 /*      acl_HtonACL(VVnodeDiskACL(v)); */
1811 /*      if (!code) code = DumpByteString(iodp, 'A', (byte *) VVnodeDiskACL(v), VAclDiskSize(v)); */
1812         FillInt64(addvar,0, (1 + VAclDiskSize(v)));
1813         AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1814     }
1815
1816     if (VNDISK_GET_INO(v)) {
1817         FillInt64(addvar,0, (v->length + 5));
1818         AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1819     }
1820     return code;
1821 }
1822
1823 /* A partial dump (no dump header) */
1824 static int
1825 SizeDumpPartial(struct iod *iodp, Volume * vp,
1826                 afs_int32 fromtime, int dumpAllDirs,
1827                 struct volintSize *v_size)
1828 {
1829     int code = 0;
1830     if (!code)
1831         code = SizeDumpVolumeHeader(iodp, vp, v_size);
1832     if (!code)
1833         code =
1834             SizeDumpVnodeIndex(iodp, vp, vLarge, fromtime, dumpAllDirs,
1835                                v_size);
1836     if (!code)
1837         code = SizeDumpVnodeIndex(iodp, vp, vSmall, fromtime, 0, v_size);
1838     return code;
1839 }
1840
1841 static int
1842 SizeDumpVnodeIndex(struct iod *iodp, Volume * vp, VnodeClass class,
1843                    afs_int32 fromtime, int forcedump,
1844                    struct volintSize *v_size)
1845 {
1846     int code = 0;
1847     struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
1848     char buf[SIZEOF_LARGEDISKVNODE];
1849     struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)buf;
1850     StreamHandle_t *file;
1851     FdHandle_t *fdP;
1852     afs_sfsize_t size, nVnodes;
1853     int flag;
1854     int vnodeIndex;
1855
1856     fdP = IH_OPEN(vp->vnodeIndex[class].handle);
1857     osi_Assert(fdP != NULL);
1858     file = FDH_FDOPEN(fdP, "r+");
1859     osi_Assert(file != NULL);
1860     size = OS_SIZE(fdP->fd_fd);
1861     osi_Assert(size != -1);
1862     nVnodes = (size / vcp->diskSize) - 1;
1863     if (nVnodes > 0) {
1864         osi_Assert((nVnodes + 1) * vcp->diskSize == size);
1865         osi_Assert(STREAM_ASEEK(file, vcp->diskSize) == 0);
1866     } else
1867         nVnodes = 0;
1868     for (vnodeIndex = 0;
1869          nVnodes && STREAM_READ(vnode, vcp->diskSize, 1, file) == 1 && !code;
1870          nVnodes--, vnodeIndex++) {
1871         flag = forcedump || (vnode->serverModifyTime >= fromtime);
1872         /* Note:  the >= test is very important since some old volumes may not have
1873          * a serverModifyTime.  For an epoch dump, this results in 0>=0 test, which
1874          * does dump the file! */
1875         if (!code)
1876             code =
1877                 SizeDumpVnode(iodp, vnode, V_id(vp),
1878                               bitNumberToVnodeNumber(vnodeIndex, class), flag,
1879                               v_size);
1880     }
1881     STREAM_CLOSE(file);
1882     FDH_CLOSE(fdP);
1883     return code;
1884 }