Use afs_foff_t for file offsets
[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_foff_t * Lbuf, afs_int32 s1, afs_foff_t * 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_foff_t 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 %lld\n", pad, (long long)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 %lld\n",
828             pad, (long long)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_foff_t ** Bufp, int *sizep,
1106              int del)
1107 {
1108     int i, nVnodes, code;
1109     afs_foff_t offset;
1110     afs_foff_t *Buf;
1111     int cnt = 0;
1112     afs_sfsize_t size;
1113     StreamHandle_t *afile;
1114     FdHandle_t *fdP;
1115     struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
1116     char buf[SIZEOF_LARGEDISKVNODE], zero[SIZEOF_LARGEDISKVNODE];
1117     struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)buf;
1118
1119     memset(zero, 0, sizeof(zero));      /* zero out our proto-vnode */
1120     fdP = IH_OPEN(vp->vnodeIndex[class].handle);
1121     if (fdP == NULL)
1122         return -1;
1123     afile = FDH_FDOPEN(fdP, "r+");
1124     if (del) {
1125         int cnt1 = 0;
1126         Buf = *Bufp;
1127         for (i = 0; i < *sizep; i++) {
1128             if (Buf[i]) {
1129                 cnt++;
1130                 STREAM_ASEEK(afile, Buf[i]);
1131                 code = STREAM_READ(vnode, vcp->diskSize, 1, afile);
1132                 if (code == 1) {
1133                     if (vnode->type != vNull && VNDISK_GET_INO(vnode)) {
1134                         cnt1++;
1135                         if (DoLogging) {
1136                             Log("RestoreVolume %u Cleanup: Removing old vnode=%u inode=%llu size=unknown\n",
1137                      V_id(vp), bitNumberToVnodeNumber(i, class),
1138                      (afs_uintmax_t) VNDISK_GET_INO(vnode));
1139                         }
1140                         IH_DEC(V_linkHandle(vp), VNDISK_GET_INO(vnode),
1141                                V_parentId(vp));
1142                         DOPOLL;
1143                     }
1144                     STREAM_ASEEK(afile, Buf[i]);
1145                     (void)STREAM_WRITE(zero, vcp->diskSize, 1, afile);  /* Zero it out */
1146                 }
1147                 Buf[i] = 0;
1148             }
1149         }
1150         if (DoLogging) {
1151             Log("RestoreVolume Cleanup: Removed %d inodes for volume %d\n",
1152                 cnt1, V_id(vp));
1153         }
1154         STREAM_FLUSH(afile);    /* ensure 0s are on the disk */
1155         OS_SYNC(afile->str_fd);
1156     } else {
1157         size = OS_SIZE(fdP->fd_fd);
1158         osi_Assert(size != -1);
1159         nVnodes =
1160             (size <=
1161              vcp->diskSize ? 0 : size - vcp->diskSize) >> vcp->logSize;
1162         if (nVnodes > 0) {
1163             if (DoLogging) {
1164                 Log("RestoreVolume ProcessIndex: Set up %d inodes for volume %d\n",
1165                     nVnodes, V_id(vp));
1166             }
1167             Buf = malloc(nVnodes * sizeof(afs_foff_t));
1168             if (Buf == NULL) {
1169                 STREAM_CLOSE(afile);
1170                 FDH_CLOSE(fdP);
1171                 return -1;
1172             }
1173             memset(Buf, 0, nVnodes * sizeof(afs_foff_t));
1174             STREAM_ASEEK(afile, offset = vcp->diskSize);
1175             while (1) {
1176                 code = STREAM_READ(vnode, vcp->diskSize, 1, afile);
1177                 if (code != 1) {
1178                     break;
1179                 }
1180                 if (vnode->type != vNull && VNDISK_GET_INO(vnode)) {
1181                     Buf[(offset >> vcp->logSize) - 1] = offset;
1182                     cnt++;
1183                 }
1184                 offset += vcp->diskSize;
1185             }
1186             if (DoLogging) {
1187                 Log("RestoreVolume ProcessIndex: found %d inodes\n", cnt);
1188             }
1189             *Bufp = Buf;
1190             *sizep = nVnodes;
1191         }
1192     }
1193     STREAM_CLOSE(afile);
1194     FDH_CLOSE(fdP);
1195     return 0;
1196 }
1197
1198
1199 int
1200 RestoreVolume(struct rx_call *call, Volume * avp, int incremental,
1201               struct restoreCookie *cookie)
1202 {
1203     VolumeDiskData vol;
1204     struct DumpHeader header;
1205     afs_uint32 endMagic;
1206     Error error = 0, vupdate;
1207     Volume *vp;
1208     struct iod iod;
1209     struct iod *iodp = &iod;
1210     afs_foff_t *b1 = NULL, *b2 = NULL;
1211     int s1 = 0, s2 = 0, delo = 0, tdelo;
1212     int tag;
1213
1214     iod_Init(iodp, call);
1215
1216     vp = avp;
1217
1218     if (!ReadDumpHeader(iodp, &header)) {
1219         Log("1 Volser: RestoreVolume: Error reading header file for dump; aborted\n");
1220         return VOLSERREAD_DUMPERROR;
1221     }
1222     if (iod_getc(iodp) != D_VOLUMEHEADER) {
1223         Log("1 Volser: RestoreVolume: Volume header missing from dump; not restored\n");
1224         return VOLSERREAD_DUMPERROR;
1225     }
1226     if (ReadVolumeHeader(iodp, &vol) == VOLSERREAD_DUMPERROR)
1227         return VOLSERREAD_DUMPERROR;
1228
1229     if (!delo)
1230         delo = ProcessIndex(vp, vLarge, &b1, &s1, 0);
1231     if (!delo)
1232         delo = ProcessIndex(vp, vSmall, &b2, &s2, 0);
1233     if (delo < 0) {
1234         Log("1 Volser: RestoreVolume: ProcessIndex failed; not restored\n");
1235         error = VOLSERREAD_DUMPERROR;
1236         goto out;
1237     }
1238
1239     strncpy(vol.name, cookie->name, VOLSER_OLDMAXVOLNAME);
1240     vol.type = cookie->type;
1241     vol.cloneId = cookie->clone;
1242     vol.parentId = cookie->parent;
1243
1244     tdelo = delo;
1245     while (1) {
1246         if (ReadVnodes(iodp, vp, 0, b1, s1, b2, s2, tdelo)) {
1247             error = VOLSERREAD_DUMPERROR;
1248             goto clean;
1249         }
1250         tag = iod_getc(iodp);
1251         if (tag != D_VOLUMEHEADER)
1252             break;
1253
1254         if (ReadVolumeHeader(iodp, &vol) == VOLSERREAD_DUMPERROR) {
1255             error = VOLSERREAD_DUMPERROR;
1256             goto out;
1257         }
1258     }
1259     if (tag != D_DUMPEND || !ReadInt32(iodp, &endMagic)
1260         || endMagic != DUMPENDMAGIC) {
1261         Log("1 Volser: RestoreVolume: End of dump not found; restore aborted\n");
1262         error = VOLSERREAD_DUMPERROR;
1263         goto clean;
1264     }
1265
1266
1267     if (iod_getc(iodp) != EOF) {
1268         Log("1 Volser: RestoreVolume: Unrecognized postamble in dump; restore aborted\n");
1269         error = VOLSERREAD_DUMPERROR;
1270         goto clean;
1271     }
1272
1273     if (!delo) {
1274         delo = ProcessIndex(vp, vLarge, &b1, &s1, 1);
1275         if (!delo)
1276             delo = ProcessIndex(vp, vSmall, &b2, &s2, 1);
1277         if (delo < 0) {
1278             error = VOLSERREAD_DUMPERROR;
1279             goto clean;
1280         }
1281     }
1282
1283   clean:
1284     ClearVolumeStats(&vol);
1285     CopyVolumeHeader(&vol, &V_disk(vp));
1286     V_destroyMe(vp) = 0;
1287     VUpdateVolume(&vupdate, vp);
1288     if (vupdate) {
1289         Log("1 Volser: RestoreVolume: Unable to rewrite volume header; restore aborted\n");
1290         error = VOLSERREAD_DUMPERROR;
1291         goto out;
1292     }
1293   out:
1294     /* Free the malloced space above */
1295     if (b1)
1296         free((char *)b1);
1297     if (b2)
1298         free((char *)b2);
1299     return error;
1300 }
1301
1302 static int
1303 ReadVnodes(struct iod *iodp, Volume * vp, int incremental,
1304            afs_foff_t * Lbuf, afs_int32 s1, afs_foff_t * Sbuf, afs_int32 s2,
1305            afs_int32 delo)
1306 {
1307     afs_int32 vnodeNumber;
1308     char buf[SIZEOF_LARGEDISKVNODE];
1309     int tag;
1310     struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)buf;
1311     struct VnodeDiskObject oldvnode;
1312     int idx;
1313     VnodeClass class;
1314     struct VnodeClassInfo *vcp;
1315     IHandle_t *tmpH;
1316     FdHandle_t *fdP;
1317     Inode nearInode;
1318     afs_int32 critical = 0;
1319
1320     tag = iod_getc(iodp);
1321     V_pref(vp, nearInode);
1322     while (tag == D_VNODE) {
1323         int haveStuff = 0;
1324         int saw_f = 0;
1325         memset(buf, 0, sizeof(buf));
1326         if (!ReadInt32(iodp, (afs_uint32 *) & vnodeNumber))
1327             break;
1328
1329         if (!ReadInt32(iodp, &vnode->uniquifier))
1330             return VOLSERREAD_DUMPERROR;
1331
1332         if (DoLogging) {
1333             Log("ReadVnodes: setup %d/%d\n", vnodeNumber, vnode->uniquifier);
1334         }
1335         while ((tag = iod_getc(iodp)) > D_MAX && tag != EOF) {
1336             haveStuff = 1;
1337             if (critical)
1338                 critical--;
1339             switch (tag) {
1340             case 't':
1341                 vnode->type = (VnodeType) iod_getc(iodp);
1342                 break;
1343             case 'l':
1344                 {
1345                     unsigned short tlc;
1346                     if (!ReadShort(iodp, &tlc))
1347                         return VOLSERREAD_DUMPERROR;
1348                     vnode->linkCount = (signed int)tlc;
1349                 }
1350                 break;
1351             case 'v':
1352                 if (!ReadInt32(iodp, &vnode->dataVersion))
1353                     return VOLSERREAD_DUMPERROR;
1354                 break;
1355             case 'm':
1356                 if (!ReadInt32(iodp, &vnode->unixModifyTime))
1357                     return VOLSERREAD_DUMPERROR;
1358                 break;
1359             case 's':
1360                 if (!ReadInt32(iodp, &vnode->serverModifyTime))
1361                     return VOLSERREAD_DUMPERROR;
1362                 break;
1363             case 'a':
1364                 if (!ReadInt32(iodp, &vnode->author))
1365                     return VOLSERREAD_DUMPERROR;
1366                 break;
1367             case 'o':
1368                 if (!ReadInt32(iodp, &vnode->owner))
1369                     return VOLSERREAD_DUMPERROR;
1370                 break;
1371             case 'g':
1372                 if (!ReadInt32(iodp, (afs_uint32 *) & vnode->group))
1373                     return VOLSERREAD_DUMPERROR;
1374                 break;
1375             case 'b':{
1376                     unsigned short modeBits;
1377                     if (!ReadShort(iodp, &modeBits))
1378                         return VOLSERREAD_DUMPERROR;
1379                     vnode->modeBits = (unsigned int)modeBits;
1380                     break;
1381                 }
1382             case 'p':
1383                 if (!ReadInt32(iodp, &vnode->parent))
1384                     return VOLSERREAD_DUMPERROR;
1385                 break;
1386             case 'A':
1387                 ReadByteString(iodp, (byte *) VVnodeDiskACL(vnode),
1388                                VAclDiskSize(vnode));
1389                 acl_NtohACL(VVnodeDiskACL(vnode));
1390                 break;
1391             case 'h':
1392             case 'f':{
1393                     Inode ino;
1394                     Error error;
1395                     afs_fsize_t vnodeLength;
1396
1397                     if (saw_f) {
1398                         Log("Volser: ReadVnodes: warning: ignoring duplicate "
1399                             "file entries for vnode %lu in dump\n",
1400                             (unsigned long)vnodeNumber);
1401                         volser_WriteFile(vnodeNumber, iodp, NULL, tag, &error);
1402                         break;
1403                     }
1404                     saw_f = 1;
1405
1406                     ino =
1407                         IH_CREATE(V_linkHandle(vp), V_device(vp),
1408                                   VPartitionPath(V_partition(vp)), nearInode,
1409                                   V_parentId(vp), vnodeNumber,
1410                                   vnode->uniquifier, vnode->dataVersion);
1411                     if (!VALID_INO(ino)) {
1412                         Log("1 Volser: ReadVnodes: IH_CREATE: %s - restore aborted\n",
1413                             afs_error_message(errno));
1414                         return VOLSERREAD_DUMPERROR;
1415                     }
1416                     nearInode = ino;
1417                     VNDISK_SET_INO(vnode, ino);
1418                     IH_INIT(tmpH, vp->device, V_parentId(vp), ino);
1419                     fdP = IH_OPEN(tmpH);
1420                     if (fdP == NULL) {
1421                         Log("1 Volser: ReadVnodes: IH_OPEN: %s - restore aborted\n",
1422                             afs_error_message(errno));
1423                         IH_RELEASE(tmpH);
1424                         return VOLSERREAD_DUMPERROR;
1425                     }
1426                     vnodeLength =
1427                         volser_WriteFile(vnodeNumber, iodp, fdP, tag, &error);
1428                     VNDISK_SET_LEN(vnode, vnodeLength);
1429                     FDH_REALLYCLOSE(fdP);
1430                     IH_RELEASE(tmpH);
1431                     if (error) {
1432                         Log("1 Volser: ReadVnodes: IDEC inode %llu\n",
1433                             (afs_uintmax_t) ino);
1434                         IH_DEC(V_linkHandle(vp), ino, V_parentId(vp));
1435                         return VOLSERREAD_DUMPERROR;
1436                     }
1437                     break;
1438                 }
1439             case 0x7e:
1440                 critical = 2;
1441                 break;
1442             default:
1443                 if (!HandleUnknownTag(iodp, tag, 2, critical))
1444                     return VOLSERREAD_DUMPERROR;
1445             }
1446         }
1447
1448         class = vnodeIdToClass(vnodeNumber);
1449         vcp = &VnodeClassInfo[class];
1450
1451         /* Mark this vnode as in this dump - so we don't delete it later */
1452         if (!delo) {
1453             idx = (vnodeIndexOffset(vcp, vnodeNumber) >> vcp->logSize) - 1;
1454             if (class == vLarge) {
1455                 if (Lbuf && (idx < s1))
1456                     Lbuf[idx] = 0;
1457             } else {
1458                 if (Sbuf && (idx < s2))
1459                     Sbuf[idx] = 0;
1460             }
1461         }
1462
1463         if (haveStuff) {
1464             FdHandle_t *fdP = IH_OPEN(vp->vnodeIndex[class].handle);
1465             if (fdP == NULL) {
1466                 Log("1 Volser: ReadVnodes: Error opening vnode index: %s; restore aborted\n",
1467                     afs_error_message(errno));
1468                 return VOLSERREAD_DUMPERROR;
1469             }
1470             if (FDH_PREAD(fdP, &oldvnode, sizeof(oldvnode), vnodeIndexOffset(vcp, vnodeNumber)) ==
1471                 sizeof(oldvnode)) {
1472                 if (oldvnode.type != vNull && VNDISK_GET_INO(&oldvnode)) {
1473                     IH_DEC(V_linkHandle(vp), VNDISK_GET_INO(&oldvnode),
1474                            V_parentId(vp));
1475                 }
1476             }
1477             vnode->vnodeMagic = vcp->magic;
1478             if (FDH_PWRITE(fdP, vnode, vcp->diskSize, vnodeIndexOffset(vcp, vnodeNumber)) != vcp->diskSize) {
1479                 Log("1 Volser: ReadVnodes: Error writing vnode index: %s; restore aborted\n",
1480                     afs_error_message(errno));
1481                 FDH_REALLYCLOSE(fdP);
1482                 return VOLSERREAD_DUMPERROR;
1483             }
1484             FDH_CLOSE(fdP);
1485         }
1486     }
1487     iod_ungetc(iodp, tag);
1488
1489     return 0;
1490 }
1491
1492
1493 /* called with disk file only.  Note that we don't have to worry about rx_Read
1494  * needing to read an ungetc'd character, since the ReadInt32 will have read
1495  * it instead.
1496  *
1497  * if handleP == NULL, don't write the file anywhere; just read and discard
1498  * the file contents
1499  */
1500 static afs_fsize_t
1501 volser_WriteFile(int vn, struct iod *iodp, FdHandle_t * handleP, int tag,
1502                  Error * status)
1503 {
1504     afs_int32 code;
1505     ssize_t nBytes;
1506     afs_fsize_t filesize;
1507     afs_fsize_t written = 0;
1508     size_t size = 8192;
1509     afs_fsize_t nbytes;
1510     unsigned char *p;
1511
1512
1513     *status = 0;
1514     {
1515         afs_uint32 filesize_high = 0L, filesize_low = 0L;
1516         if (tag == 'h') {
1517             if (!ReadInt32(iodp, &filesize_high)) {
1518                 *status = 1;
1519                 return 0;
1520             }
1521         }
1522         if (!ReadInt32(iodp, &filesize_low)) {
1523             *status = 1;
1524             return 0;
1525         }
1526         FillInt64(filesize, filesize_high, filesize_low);
1527     }
1528     p = (unsigned char *)malloc(size);
1529     if (p == NULL) {
1530         *status = 2;
1531         return (0);
1532     }
1533     for (nbytes = filesize; nbytes; nbytes -= size) {
1534         if (nbytes < size)
1535             size = nbytes;
1536
1537         if ((code = iod_Read(iodp, (char *) p, size)) != size) {
1538             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));
1539             *status = 3;
1540             break;
1541         }
1542         if (handleP) {
1543             nBytes = FDH_PWRITE(handleP, p, size, written);
1544             if (nBytes > 0)
1545                 written += nBytes;
1546             if (nBytes != size) {
1547                 Log("1 Volser: WriteFile: Error writing (%u) bytes to vnode %d; %s; restore aborted\n", (int)(nBytes & 0xffffffff), vn, afs_error_message(errno));
1548                 *status = 4;
1549                 break;
1550             }
1551         }
1552     }
1553     free(p);
1554     return (written);
1555 }
1556
1557 static int
1558 ReadDumpHeader(struct iod *iodp, struct DumpHeader *hp)
1559 {
1560     int tag;
1561     afs_uint32 beginMagic;
1562     afs_int32 critical = 0;
1563     if (iod_getc(iodp) != D_DUMPHEADER || !ReadInt32(iodp, &beginMagic)
1564         || !ReadInt32(iodp, (afs_uint32 *) & hp->version)
1565         || beginMagic != DUMPBEGINMAGIC)
1566         return 0;
1567     hp->volumeId = 0;
1568     hp->nDumpTimes = 0;
1569     while ((tag = iod_getc(iodp)) > D_MAX) {
1570         unsigned short arrayLength;
1571         int i;
1572         if (critical)
1573             critical--;
1574         switch (tag) {
1575         case 'v':
1576             if (!ReadInt32(iodp, &hp->volumeId))
1577                 return 0;
1578             break;
1579         case 'n':
1580             ReadString(iodp, hp->volumeName, sizeof(hp->volumeName));
1581             break;
1582         case 't':
1583             if (!ReadShort(iodp, &arrayLength))
1584                 return 0;
1585             hp->nDumpTimes = (arrayLength >> 1);
1586             for (i = 0; i < hp->nDumpTimes; i++)
1587                 if (!ReadInt32(iodp, (afs_uint32 *) & hp->dumpTimes[i].from)
1588                     || !ReadInt32(iodp, (afs_uint32 *) & hp->dumpTimes[i].to))
1589                     return 0;
1590             break;
1591         case 0x7e:
1592             critical = 2;
1593             break;
1594         default:
1595             if (!HandleUnknownTag(iodp, tag, 0, critical))
1596                 return VOLSERREAD_DUMPERROR;
1597         }
1598     }
1599     if (!hp->volumeId || !hp->nDumpTimes) {
1600         return 0;
1601     }
1602     iod_ungetc(iodp, tag);
1603     return 1;
1604 }
1605
1606
1607 /* ----- Below are the calls that calculate dump size ----- */
1608
1609 static int
1610 SizeDumpVolumeHeader(struct iod *iodp, Volume * vp,
1611                      struct volintSize *v_size)
1612 {
1613     int code = 0;
1614     static char nullString[1] = "";     /*The ``contents'' of motd */
1615     afs_uint64 addvar;
1616
1617 /*     if (!code) code = DumpTag(iodp, D_VOLUMEHEADER); */
1618     FillInt64(addvar,0, 1);
1619     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1620 /*     if (!code) {code = DumpInt32(iodp, 'i',V_id(vp));} */
1621     FillInt64(addvar,0, 5);
1622     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1623 /*     if (!code) code = DumpInt32(iodp, 'v',V_stamp(vp).version); */
1624     FillInt64(addvar,0, 5);
1625     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1626 /*     if (!code) code = DumpString(iodp, 'n',V_name(vp)); */
1627     FillInt64(addvar,0, (2 + strlen(V_name(vp))));
1628     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1629 /*     if (!code) code = DumpBool(iodp, 's',V_inService(vp)); */
1630     FillInt64(addvar,0, 2);
1631     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1632 /*     if (!code) code = DumpBool(iodp, 'b',V_blessed(vp)); */
1633     FillInt64(addvar,0, 2);
1634     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1635 /*     if (!code) code = DumpInt32(iodp, 'u',V_uniquifier(vp)); */
1636     FillInt64(addvar,0, 5);
1637     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1638 /*     if (!code) code = DumpByte(iodp, 't',(byte)V_type(vp)); */
1639     FillInt64(addvar,0, 2);
1640     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1641 /*     if (!code){ code = DumpInt32(iodp, 'p',V_parentId(vp));} */
1642     FillInt64(addvar,0, 5);
1643     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1644 /*     if (!code) code = DumpInt32(iodp, 'c',V_cloneId(vp)); */
1645     FillInt64(addvar,0, 5);
1646     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1647 /*     if (!code) code = DumpInt32(iodp, 'q',V_maxquota(vp)); */
1648     FillInt64(addvar,0, 5);
1649     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1650 /*     if (!code) code = DumpInt32(iodp, 'm',V_minquota(vp)); */
1651     FillInt64(addvar,0, 5);
1652     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1653 /*     if (!code) code = DumpInt32(iodp, 'd',V_diskused(vp)); */
1654     FillInt64(addvar,0, 5);
1655     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1656 /*     if (!code) code = DumpInt32(iodp, 'f',V_filecount(vp)); */
1657     FillInt64(addvar,0, 5);
1658     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1659 /*     if (!code) code = DumpInt32(iodp, 'a', V_accountNumber(vp)); */
1660     FillInt64(addvar,0, 5);
1661     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1662 /*     if (!code) code = DumpInt32(iodp, 'o', V_owner(vp)); */
1663     FillInt64(addvar,0, 5);
1664     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1665 /*     if (!code) code = DumpInt32(iodp, 'C',V_creationDate(vp));       /\* Rw volume creation date *\/ */
1666     FillInt64(addvar,0, 5);
1667     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1668 /*     if (!code) code = DumpInt32(iodp, 'A',V_accessDate(vp)); */
1669     FillInt64(addvar,0, 5);
1670     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1671 /*     if (!code) code = DumpInt32(iodp, 'U',V_updateDate(vp)); */
1672     FillInt64(addvar,0, 5);
1673     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1674 /*     if (!code) code = DumpInt32(iodp, 'E',V_expirationDate(vp)); */
1675     FillInt64(addvar,0, 5);
1676     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1677 /*     if (!code) code = DumpInt32(iodp, 'B',V_backupDate(vp));         /\* Rw volume backup clone date *\/ */
1678     FillInt64(addvar,0, 5);
1679     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1680 /*     if (!code) code = DumpString(iodp, 'O',V_offlineMessage(vp)); */
1681     FillInt64(addvar,0, (2 + strlen(V_offlineMessage(vp))));
1682     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1683 /*     /\* */
1684 /*      * We do NOT dump the detailed volume statistics residing in the old */
1685 /*      * motd field, since we cannot tell from the info in a dump whether */
1686 /*      * statistics data has been put there.  Instead, we dump a null string, */
1687 /*      * just as if that was what the motd contained. */
1688 /*      *\/ */
1689 /*     if (!code) code = DumpString(iodp, 'M', nullString); */
1690     FillInt64(addvar,0, (2 + strlen(nullString)));
1691     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1692 /*     if (!code) code = DumpArrayInt32(iodp, 'W', (afs_uint32 *)V_weekUse(vp), sizeof(V_weekUse(vp))/sizeof(V_weekUse(vp)[0])); */
1693     FillInt64(addvar,0, (3 + 4 * (sizeof(V_weekUse(vp)) / sizeof(V_weekUse(vp)[0]))));
1694     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1695 /*     if (!code) code = DumpInt32(iodp, 'D', V_dayUseDate(vp)); */
1696     FillInt64(addvar,0, 5);
1697     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1698 /*     if (!code) code = DumpInt32(iodp, 'Z', V_dayUse(vp)); */
1699     FillInt64(addvar,0, 5);
1700     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1701     return code;
1702 }
1703
1704 static int
1705 SizeDumpEnd(struct iod *iodp, struct volintSize *v_size)
1706 {
1707     int code = 0;
1708     afs_uint64 addvar;
1709     FillInt64(addvar,0, 5);
1710     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1711     return code;
1712 }
1713
1714 int
1715 SizeDumpVolume(struct rx_call *call, Volume * vp,
1716                afs_int32 fromtime, int dumpAllDirs,
1717                struct volintSize *v_size)
1718 {
1719     int code = 0;
1720     struct iod *iodp = (struct iod *)0;
1721 /*    iod_Init(iodp, call); */
1722
1723     if (!code)
1724         code = SizeDumpDumpHeader(iodp, vp, fromtime, v_size);
1725     if (!code)
1726         code = SizeDumpPartial(iodp, vp, fromtime, dumpAllDirs, v_size);
1727     if (!code)
1728         code = SizeDumpEnd(iodp, v_size);
1729
1730     return code;
1731 }
1732
1733 static int
1734 SizeDumpDumpHeader(struct iod *iodp, Volume * vp,
1735                    afs_int32 fromtime, struct volintSize *v_size)
1736 {
1737     int code = 0;
1738 /*    int UseLatestReadOnlyClone = 1; */
1739 /*    afs_int32 dumpTimes[2]; */
1740     afs_uint64 addvar;
1741 /*    iodp->device = vp->device; */
1742 /*    iodp->parentId = V_parentId(vp); */
1743 /*    iodp->dumpPartition = vp->partition; */
1744
1745     ZeroInt64(v_size->dump_size);       /* initialize the size */
1746 /*     if (!code) code = DumpDouble(iodp, D_DUMPHEADER, DUMPBEGINMAGIC, DUMPVERSION); */
1747     FillInt64(addvar,0, 9);
1748     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1749 /*     if (!code) code = DumpInt32(iodp, 'v', UseLatestReadOnlyClone? V_id(vp): V_parentId(vp)); */
1750     FillInt64(addvar,0, 5);
1751     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1752 /*     if (!code) code = DumpString(iodp, 'n',V_name(vp)); */
1753     FillInt64(addvar,0, (2 + strlen(V_name(vp))));
1754     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1755 /*     dumpTimes[0] = fromtime; */
1756 /*     dumpTimes[1] = V_backupDate(vp); /\* Until the time the clone was made *\/ */
1757 /*     if (!code) code = DumpArrayInt32(iodp, 't', (afs_uint32 *)dumpTimes, 2); */
1758     FillInt64(addvar,0, (3 + 4 * 2));
1759     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1760     return code;
1761 }
1762
1763 static int
1764 SizeDumpVnode(struct iod *iodp, struct VnodeDiskObject *v, int volid,
1765               int vnodeNumber, int dumpEverything,
1766               struct volintSize *v_size)
1767 {
1768     int code = 0;
1769     afs_uint64 addvar;
1770
1771     if (!v || v->type == vNull)
1772         return code;
1773 /*     if (!code) code = DumpDouble(iodp, D_VNODE, vnodeNumber, v->uniquifier); */
1774     FillInt64(addvar,0, 9);
1775     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1776     if (!dumpEverything)
1777         return code;
1778 /*     if (!code)  code = DumpByte(iodp, 't',(byte)v->type); */
1779     FillInt64(addvar,0, 2);
1780     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1781 /*     if (!code) code = DumpShort(iodp, 'l', v->linkCount); /\* May not need this *\/ */
1782     FillInt64(addvar,0, 3);
1783     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1784 /*     if (!code) code = DumpInt32(iodp, 'v', v->dataVersion); */
1785     FillInt64(addvar,0, 5);
1786     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1787 /*     if (!code) code = DumpInt32(iodp, 'm', v->unixModifyTime); */
1788     FillInt64(addvar,0, 5);
1789     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1790 /*     if (!code) code = DumpInt32(iodp, 'a', v->author); */
1791     FillInt64(addvar,0, 5);
1792     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1793 /*     if (!code) code = DumpInt32(iodp, 'o', v->owner); */
1794     FillInt64(addvar,0, 5);
1795     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1796 /*     if (!code && v->group) code = DumpInt32(iodp, 'g', v->group);    /\* default group is 0 *\/ */
1797     if (v->group) {
1798         FillInt64(addvar,0, 5);
1799         AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1800     }
1801 /*     if (!code) code = DumpShort(iodp, 'b', v->modeBits); */
1802     FillInt64(addvar,0, 3);
1803     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1804 /*     if (!code) code = DumpInt32(iodp, 'p', v->parent); */
1805     FillInt64(addvar,0, 5);
1806     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1807 /*     if (!code) code = DumpInt32(iodp, 's', v->serverModifyTime); */
1808     FillInt64(addvar,0, 5);
1809     AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1810     if (v->type == vDirectory) {
1811 /*      acl_HtonACL(VVnodeDiskACL(v)); */
1812 /*      if (!code) code = DumpByteString(iodp, 'A', (byte *) VVnodeDiskACL(v), VAclDiskSize(v)); */
1813         FillInt64(addvar,0, (1 + VAclDiskSize(v)));
1814         AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1815     }
1816
1817     if (VNDISK_GET_INO(v)) {
1818         FillInt64(addvar,0, (v->length + 5));
1819         AddUInt64(v_size->dump_size, addvar, &v_size->dump_size);
1820     }
1821     return code;
1822 }
1823
1824 /* A partial dump (no dump header) */
1825 static int
1826 SizeDumpPartial(struct iod *iodp, Volume * vp,
1827                 afs_int32 fromtime, int dumpAllDirs,
1828                 struct volintSize *v_size)
1829 {
1830     int code = 0;
1831     if (!code)
1832         code = SizeDumpVolumeHeader(iodp, vp, v_size);
1833     if (!code)
1834         code =
1835             SizeDumpVnodeIndex(iodp, vp, vLarge, fromtime, dumpAllDirs,
1836                                v_size);
1837     if (!code)
1838         code = SizeDumpVnodeIndex(iodp, vp, vSmall, fromtime, 0, v_size);
1839     return code;
1840 }
1841
1842 static int
1843 SizeDumpVnodeIndex(struct iod *iodp, Volume * vp, VnodeClass class,
1844                    afs_int32 fromtime, int forcedump,
1845                    struct volintSize *v_size)
1846 {
1847     int code = 0;
1848     struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
1849     char buf[SIZEOF_LARGEDISKVNODE];
1850     struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)buf;
1851     StreamHandle_t *file;
1852     FdHandle_t *fdP;
1853     afs_sfsize_t size, nVnodes;
1854     int flag;
1855     int vnodeIndex;
1856
1857     fdP = IH_OPEN(vp->vnodeIndex[class].handle);
1858     osi_Assert(fdP != NULL);
1859     file = FDH_FDOPEN(fdP, "r+");
1860     osi_Assert(file != NULL);
1861     size = OS_SIZE(fdP->fd_fd);
1862     osi_Assert(size != -1);
1863     nVnodes = (size / vcp->diskSize) - 1;
1864     if (nVnodes > 0) {
1865         osi_Assert((nVnodes + 1) * vcp->diskSize == size);
1866         osi_Assert(STREAM_ASEEK(file, vcp->diskSize) == 0);
1867     } else
1868         nVnodes = 0;
1869     for (vnodeIndex = 0;
1870          nVnodes && STREAM_READ(vnode, vcp->diskSize, 1, file) == 1 && !code;
1871          nVnodes--, vnodeIndex++) {
1872         flag = forcedump || (vnode->serverModifyTime >= fromtime);
1873         /* Note:  the >= test is very important since some old volumes may not have
1874          * a serverModifyTime.  For an epoch dump, this results in 0>=0 test, which
1875          * does dump the file! */
1876         if (!code)
1877             code =
1878                 SizeDumpVnode(iodp, vnode, V_id(vp),
1879                               bitNumberToVnodeNumber(vnodeIndex, class), flag,
1880                               v_size);
1881     }
1882     STREAM_CLOSE(file);
1883     FDH_CLOSE(fdP);
1884     return code;
1885 }