aix-51-support-20030701
[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 RCSID("$Header$");
14
15 #include <sys/types.h>
16 #include <ctype.h>
17 #include <stdio.h>
18 #include <errno.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 #ifdef HAVE_STRING_H
29 #include <string.h>
30 #else
31 #ifdef HAVE_STRINGS_H
32 #include <strings.h>
33 #endif
34 #endif
35 #include <sys/stat.h>
36 #include <afs/assert.h>
37 #include <rx/xdr.h>
38 #include <rx/rx.h>
39 #include <afs/afsint.h>
40 #include <afs/nfs.h>
41 #include <afs/errors.h>
42 #include <lock.h>
43 #include <lwp.h>
44 #include <afs/ihandle.h>
45 #include <afs/vnode.h>
46 #include <afs/volume.h>
47 #include <afs/partition.h>
48 #include "dump.h"
49 #include <afs/fssync.h>
50 #include <afs/acl.h>
51 #include "volser.h"
52 #include "volint.h"
53
54 /*@printflike@*/ extern void Log(const char *format, ...);
55
56 extern int DoLogging;
57
58 /* This iod stuff is a silly little package to emulate the old qi_in stuff, which
59    emulated the stdio stuff.  There is a big assumption here, that the
60    rx_Read will never be called directly, by a routine like readFile, when
61    there is an old character that was pushed back with iod_ungetc.  This
62    is really bletchy, and is here for compatibility only.  Eventually,
63    we should define a volume format that doesn't require
64    the pushing back of characters (i.e. characters should not double both
65    as an end marker and a begin marker) */
66 struct iod {
67     struct rx_call *call;       /* call to which to write, might be an array */
68     int device;                 /* dump device ID for volume */
69     int parentId;               /* dump parent ID for volume */
70     struct DiskPartition *dumpPartition; /* Dump partition. */
71     struct rx_call **calls;      /* array of pointers to calls */
72     int ncalls;                 /* how many calls/codes in array */
73     int *codes;                 /* one return code for each call */
74     char haveOldChar;           /* state for pushing back a character */
75     char oldChar;
76 };
77
78
79 /* Forward Declarations */
80 static int DumpDumpHeader(register struct iod *iodp, register Volume *vp,
81                           afs_int32 fromtime);
82 static int DumpPartial(register struct iod *iodp, register Volume *vp,
83                        afs_int32 fromtime, int dumpAllDirs);
84 static int DumpVnodeIndex(register struct iod *iodp, Volume *vp,
85                           VnodeClass class, afs_int32 fromtime, int forcedump);
86 static int DumpVnode(register struct iod *iodp, struct VnodeDiskObject *v,
87                      int volid, int vnodeNumber, int dumpEverything);
88 static int ReadDumpHeader(register struct iod *iodp, struct DumpHeader *hp);
89 static int ReadVnodes(register struct iod *iodp, Volume *vp,
90                       int incremental, afs_int32 *Lbuf, afs_int32 s1,
91                       afs_int32 *Sbuf, afs_int32 s2, afs_int32 delo);
92 static bit32 volser_WriteFile(int vn, struct iod *iodp, FdHandle_t *handleP,
93                               Error *status);
94
95 static int SizeDumpDumpHeader(register struct iod *iodp, register Volume *vp,
96                               afs_int32 fromtime, register struct volintSize *size);
97 static int SizeDumpPartial(register struct iod *iodp, register Volume *vp,
98                            afs_int32 fromtime, int dumpAllDirs,
99                            register struct volintSize *size);
100 static int SizeDumpVnodeIndex(register struct iod *iodp, Volume *vp,
101                               VnodeClass class, afs_int32 fromtime, int forcedump,
102                               register struct volintSize *size);
103 static int SizeDumpVnode(register struct iod *iodp, struct VnodeDiskObject *v,
104                          int volid, int vnodeNumber, int dumpEverything,
105                          register struct volintSize *size);
106
107 static void iod_Init(register struct iod *iodp, register struct rx_call *call)
108 {
109     iodp->call = call;
110     iodp->haveOldChar = 0;
111     iodp->ncalls = 1;
112     iodp->calls = (struct rx_call **) 0;
113 }
114
115 static void iod_InitMulti(struct iod *iodp, struct rx_call **calls, int ncalls,
116                    int *codes)
117 {
118
119   iodp->calls = calls;
120   iodp->haveOldChar = 0;
121   iodp->ncalls = ncalls;
122   iodp->codes = codes;
123   iodp->call = (struct rx_call *) 0;
124 }
125
126 /* N.B. iod_Read doesn't check for oldchar (see previous comment) */
127 #define iod_Read(iodp, buf, nbytes) rx_Read((iodp)->call, buf, nbytes)
128
129 /* For the single dump case, it's ok to just return the "bytes written"
130  * that rx_Write returns, since all the callers of iod_Write abort when
131  * the returned value is less than they expect.  For the multi dump case,
132  * I don't think we want half the replicas to go bad just because one 
133  * connection timed out, but if they all time out, then we should give up. 
134  */
135 static int iod_Write(struct iod *iodp, char *buf, int nbytes)
136 {
137   int code, i;
138   int one_success = 0;
139
140   assert ((iodp->call && iodp->ncalls == 1 && !iodp->calls) ||
141           (!iodp->call && iodp->ncalls >= 1 && iodp->calls));
142
143   if (iodp->call) {
144     code = rx_Write(iodp->call, buf, nbytes); 
145     return code;     
146   }
147
148   for (i=0; i < iodp->ncalls; i++) {
149     if (iodp->calls[i] && !iodp->codes[i]) {
150       code = rx_Write(iodp->calls[i], buf, nbytes);
151       if (code != nbytes) { /* everything gets merged into a single error */
152         iodp->codes[i] = VOLSERDUMPERROR;  /* but that's exactly what the */
153       }                                    /* standard dump does, anyways */
154       else {
155         one_success = TRUE;
156       }
157     }
158   } /* for all calls */
159
160 if (one_success)
161   return nbytes;
162 else return 0;
163 }
164
165 static void iod_ungetc(struct iod *iodp, int achar)
166 {
167     iodp->oldChar = achar;
168     iodp->haveOldChar = 1;
169 }
170
171 static int iod_getc(register struct iod *iodp)
172 {
173     unsigned char t;
174    
175     if (iodp->haveOldChar) {
176         iodp->haveOldChar = 0;
177         return iodp->oldChar;
178     }
179     if (iod_Read(iodp, &t, 1) == 1) return t;
180     return EOF;
181 }
182
183 static int ReadShort(register struct iod *iodp, register unsigned short *sp)
184 {
185     register b1,b0;
186     b1 = iod_getc(iodp);
187     b0 = iod_getc(iodp);
188     *sp = (b1<<8) | b0;
189     return b0 != EOF;
190 }
191
192 static int ReadInt32(register struct iod *iodp, afs_uint32 *lp)
193 {
194     afs_uint32 register b3,b2,b1,b0;
195     b3 = iod_getc(iodp);
196     b2 = iod_getc(iodp);
197     b1 = iod_getc(iodp);
198     b0 = iod_getc(iodp);
199     *lp = (((((b3<<8)|b2)<<8)|b1)<<8)|b0;
200     return b0 != EOF;
201 }
202
203 static void ReadString(register struct iod *iodp, register char *to,
204                       register int maxa)
205 {
206     register int c;
207     while (maxa--) {
208         if ((*to++ = iod_getc(iodp)) == 0)
209             break;
210     }
211     if (to[-1]) {
212         while ((c = iod_getc(iodp)) && c != EOF);
213         to[-1] = 0;
214     }
215 }
216
217 static void ReadByteString(register struct iod *iodp, register byte *to,
218                    register int size)
219 {
220     while (size--)
221         *to++ = iod_getc(iodp);
222 }
223
224 static int ReadVolumeHeader(register struct iod *iodp, VolumeDiskData *vol)
225 {
226     register tag;
227     afs_uint32 trash;
228     memset(vol, 0, sizeof(*vol));
229     while ((tag = iod_getc(iodp)) > D_MAX && tag != EOF) {
230         switch (tag) {
231             case 'i':
232                 if(!ReadInt32(iodp, &vol->id)) return VOLSERREAD_DUMPERROR;
233                 break;
234             case 'v':
235                 if(!ReadInt32(iodp, &trash)) return VOLSERREAD_DUMPERROR;
236                 break;
237             case 'n':
238                  ReadString(iodp, vol->name, sizeof(vol->name));
239                 /*this means the name of the retsored volume could be possibly different. In conjunction with SAFSVolSignalRestore */
240                 break;
241             case 's':
242                 vol->inService = iod_getc(iodp );
243                 break;
244             case 'b':
245                 vol->blessed = iod_getc(iodp );
246                 break;
247             case 'u':
248                 if(!ReadInt32(iodp, &vol->uniquifier)) return VOLSERREAD_DUMPERROR;
249                 break;
250             case 't':
251                 vol->type = iod_getc(iodp );
252                 break;
253             case 'p':
254                 if(!ReadInt32(iodp, &vol->parentId)) return VOLSERREAD_DUMPERROR;
255                 break;
256             case 'c':
257                 if(!ReadInt32(iodp, &vol->cloneId)) return VOLSERREAD_DUMPERROR;
258                 break;
259             case 'q':
260                 if(!ReadInt32(iodp, (afs_uint32 *)&vol->maxquota)) return VOLSERREAD_DUMPERROR;
261                 break;
262             case 'm':
263                 if(!ReadInt32(iodp, (afs_uint32 *)&vol->minquota)) return VOLSERREAD_DUMPERROR;
264                 break;
265             case 'd':
266                 if(!ReadInt32(iodp, (afs_uint32 *)&vol->diskused)) return VOLSERREAD_DUMPERROR; /* Bogus:  should calculate this */
267                 break;
268             case 'f':
269                 if(!ReadInt32(iodp, (afs_uint32 *)&vol->filecount)) return VOLSERREAD_DUMPERROR;
270                 break;
271             case 'a':
272                 if(!ReadInt32(iodp, &vol->accountNumber)) return VOLSERREAD_DUMPERROR;
273                 break;
274             case 'o':
275                 if(!ReadInt32(iodp, &vol->owner)) return VOLSERREAD_DUMPERROR;
276                 break;
277             case 'C':
278                 if(!ReadInt32(iodp, &vol->creationDate)) return VOLSERREAD_DUMPERROR;
279                 break;
280             case 'A':
281                 if(!ReadInt32(iodp, &vol->accessDate)) return VOLSERREAD_DUMPERROR;
282                 break;
283             case 'U':
284                 if(!ReadInt32(iodp, &vol->updateDate)) return VOLSERREAD_DUMPERROR;
285                 break;
286             case 'E':
287                 if(!ReadInt32(iodp, &vol->expirationDate)) return VOLSERREAD_DUMPERROR;
288                 break;
289             case 'B':
290                 if(!ReadInt32(iodp, &vol->backupDate)) return VOLSERREAD_DUMPERROR;
291                 break;
292             case 'O':
293                 ReadString(iodp, vol->offlineMessage, sizeof(vol->offlineMessage));
294                 break;
295             case 'M':
296                 /*
297                  * Detailed volume statistics are never stored in dumps,
298                  * so we just restore either the null string if this volume
299                  * had already been set to store statistics, or the old motd
300                  * contents otherwise.  It doesn't matter, since this field
301                  * will soon get initialized anyway.
302                  */
303                 ReadString(iodp, (char *)(vol->stat_reads), VMSGSIZE);
304                 break;
305             case 'W': {
306                 unsigned short length;
307                 int i;
308                 afs_uint32 data;
309                 if(!ReadShort(iodp, &length)) return VOLSERREAD_DUMPERROR;
310                 for (i = 0; i<length; i++) {
311                     if(!ReadInt32(iodp, &data)) return VOLSERREAD_DUMPERROR;
312                     if (i < sizeof(vol->weekUse)/sizeof(vol->weekUse[0]))
313                         vol->weekUse[i] = data;
314                 }
315                 break;
316             }
317             case 'D':
318                 if(!ReadInt32(iodp, &vol->dayUseDate)) return VOLSERREAD_DUMPERROR;
319                 break;
320             case 'Z':
321                 if(!ReadInt32(iodp, (afs_uint32 *)&vol->dayUse)) return VOLSERREAD_DUMPERROR;
322                 break;
323         }
324     }
325     iod_ungetc(iodp, tag);
326     return 0;
327 }
328
329 static int DumpTag(register struct iod *iodp, register int tag)
330 {
331     char p;
332     
333     p = tag;
334     return((iod_Write(iodp, &p, 1) == 1)? 0 : VOLSERDUMPERROR);
335     
336 }
337
338 static int DumpByte(register struct iod *iodp, char tag, byte value)
339 {
340     char tbuffer[2];
341     register byte *p = (unsigned char *) tbuffer;
342     *p++ = tag;
343     *p = value;
344     return((iod_Write(iodp, tbuffer, 2) == 2)? 0: VOLSERDUMPERROR);
345 }
346
347 #define putint32(p, v)  *p++ = v>>24, *p++ = v>>16, *p++ = v>>8, *p++ = v
348 #define putshort(p, v) *p++ = v>>8, *p++ = v
349
350 static int DumpDouble(register struct iod *iodp, char tag,
351                       register afs_uint32 value1, register afs_uint32 value2)
352 {
353     char tbuffer[9];
354     register byte *p = (unsigned char *) tbuffer;
355     *p++ = tag;
356     putint32(p, value1);
357     putint32(p, value2);
358     return((iod_Write(iodp, tbuffer, 9) == 9)? 0: VOLSERDUMPERROR);
359 }
360
361 static int DumpInt32(register struct iod *iodp, char tag,
362                      register afs_uint32 value)
363 {
364     char tbuffer[5];
365     register byte *p = (unsigned char *) tbuffer;
366     *p++ = tag;
367     putint32(p, value);
368     return((iod_Write(iodp, tbuffer, 5) == 5)? 0: VOLSERDUMPERROR);
369 }
370
371 static int DumpArrayInt32(register struct iod *iodp, char tag,
372                           register afs_uint32 *array, register int nelem)
373 {
374     char tbuffer[4];
375     register afs_uint32 v ;
376     int code = 0;
377     register byte *p = (unsigned char *) tbuffer;
378     *p++ = tag;
379     putshort(p, nelem);
380     code = iod_Write(iodp, tbuffer, 3);
381     if (code != 3) return VOLSERDUMPERROR;
382     while (nelem--) {
383         p = (unsigned char *) tbuffer;
384         v = *array++;/*this was register */
385         
386         putint32(p, v);
387         code = iod_Write(iodp, tbuffer, 4);
388         if(code != 4) return VOLSERDUMPERROR;
389     }
390     return 0;
391 }
392
393 static int DumpShort(register struct iod *iodp, char tag, unsigned int value)
394 {
395     char tbuffer[3];
396     register byte *p = (unsigned char *) tbuffer;
397     *p++ = tag;
398     *p++ = value>>8;
399     *p = value;
400     return((iod_Write(iodp, tbuffer, 3) == 3)? 0: VOLSERDUMPERROR);
401 }
402
403 static int DumpBool(register struct iod *iodp, char tag, unsigned int value)
404 {
405     char tbuffer[2];
406     register byte *p = (unsigned char *) tbuffer;
407     *p++ = tag;
408     *p = value;
409     return((iod_Write(iodp, tbuffer, 2) == 2)? 0: VOLSERDUMPERROR);
410 }
411
412 static int DumpString(register struct iod *iodp, char tag, register char *s)
413 {
414     register n;
415     int code = 0;
416     code = iod_Write(iodp, &tag, 1);
417     if(code != 1) return VOLSERDUMPERROR;
418     n = strlen(s)+1;
419     code = iod_Write(iodp, s, n);
420     if(code != n) return VOLSERDUMPERROR;
421     return 0;
422 }
423
424 static int DumpByteString(register struct iod *iodp, char tag,
425                           register byte *bs, register int nbytes)
426 {
427     int code = 0;
428
429     code = iod_Write(iodp, &tag, 1);
430     if(code != 1) return VOLSERDUMPERROR;
431     code = iod_Write(iodp, (char *)bs, nbytes);
432     if(code != nbytes) return VOLSERDUMPERROR;
433     return 0;
434 }
435     
436 static int DumpFile(struct iod *iodp, char tag, int vnode, FdHandle_t *handleP)
437 {
438     int   code = 0, lcode = 0, error = 0;
439     afs_int32 pad = 0, offset;
440     int   n, nbytes, howMany, howBig;
441     byte  *p;
442     struct stat status;
443     int size;
444 #ifdef  AFS_AIX_ENV
445 #include <sys/statfs.h>
446     struct statfs tstatfs;
447 #endif
448
449 #ifdef AFS_NT40_ENV
450     howBig = _filelength(handleP->fd_fd);
451     howMany = 4096;
452
453 #else
454     fstat(handleP->fd_fd, &status);
455     howBig = status.st_size;
456
457 #ifdef  AFS_AIX_ENV
458     /* Unfortunately in AIX valuable fields such as st_blksize are 
459      * gone from the stat structure.
460      */
461     fstatfs(handleP->fd_fd, &tstatfs);
462     howMany = tstatfs.f_bsize;
463 #else
464     howMany = status.st_blksize;
465 #endif /* AFS_AIX_ENV */
466 #endif /* AFS_NT40_ENV */
467
468
469     size = FDH_SIZE(handleP);
470     code = DumpInt32(iodp, tag, size);
471     if (code) {
472        return VOLSERDUMPERROR;
473     }
474
475     p = (unsigned char *) malloc(howMany);
476     if (!p) {
477        Log("1 Volser: DumpFile: no memory");
478        return VOLSERDUMPERROR;
479     }
480
481     for (nbytes = size; (nbytes && !error); nbytes -= howMany) {
482         if (nbytes < howMany) 
483            howMany = nbytes;
484
485         /* Read the data - unless we know we can't */
486         n = (lcode ? 0 : FDH_READ(handleP, p, howMany));        
487
488         /* If read any good data and we null padded previously, log the
489          * amount that we had null padded.
490          */
491         if ((n > 0) && pad) {
492            Log("1 Volser: DumpFile: Null padding file %d bytes at offset %u\n",
493                pad, offset);
494            pad = 0;
495         }
496
497         /* If didn't read enough data, null padd the rest of the buffer. This
498          * can happen if, for instance, the media has some bad spots. We don't
499          * want to quit the dump, so we start null padding.
500          */
501         if (n < howMany) {
502            /* Record the read error */
503            if (n < 0) {
504               n = 0;
505               Log("1 Volser: DumpFile: Error %d reading inode %s for vnode %d\n", 
506                   errno, PrintInode(NULL, handleP->fd_ih->ih_ino), vnode);
507            }
508            else if (!pad) {
509               Log("1 Volser: DumpFile: Error reading inode %s for vnode %d\n",
510                   PrintInode(NULL, handleP->fd_ih->ih_ino), vnode);
511            }
512            
513            /* Pad the rest of the buffer with zeros. Remember offset we started 
514             * padding. Keep total tally of padding.
515             */
516            memset(p+n, 0, howMany-n);
517            if (!pad)
518               offset = (howBig - nbytes) + n;
519            pad += (howMany-n);
520            
521            /* Now seek over the data we could not get. An error here means we
522             * can't do the next read.
523             */
524            lcode = FDH_SEEK(handleP, ((size - nbytes) + howMany), SEEK_SET);
525            if (lcode != ((size - nbytes) + howMany)) {
526               if (lcode < 0) {
527                  Log("1 Volser: DumpFile: Error %d seeking in inode %s for vnode %d\n",
528                      errno, PrintInode(NULL, handleP->fd_ih->ih_ino), vnode);
529               }
530               else {
531                  Log("1 Volser: DumpFile: Error seeking in inode %s for vnode %d\n",
532                      PrintInode(NULL, handleP->fd_ih->ih_ino), vnode);
533                  lcode = -1;
534               }
535            }
536            else {
537              lcode = 0;
538            }
539         }
540
541         /* Now write the data out */
542         if (iod_Write(iodp, (char *)p, howMany) != howMany) 
543            error = VOLSERDUMPERROR;
544         IOMGR_Poll();
545     }
546
547     if (pad) {                     /* Any padding we hadn't reported yet */
548        Log("1 Volser: DumpFile: Null padding file: %d bytes at offset %u\n",
549            pad, offset);
550     }
551
552     free(p);
553     return error;
554 }
555
556 static int DumpVolumeHeader(register struct iod *iodp, register Volume *vp)
557 {
558     int code = 0;
559     static char nullString[1] = "";  /*The ``contents'' of motd*/
560
561     if (!code) code = DumpTag(iodp, D_VOLUMEHEADER);
562     if (!code) {code = DumpInt32(iodp, 'i',V_id(vp));}
563     if (!code) code = DumpInt32(iodp, 'v',V_stamp(vp).version);
564     if (!code) code = DumpString(iodp, 'n',V_name(vp));
565     if (!code) code = DumpBool(iodp, 's',V_inService(vp));
566     if (!code) code = DumpBool(iodp, 'b',V_blessed(vp));
567     if (!code) code = DumpInt32(iodp, 'u',V_uniquifier(vp));
568     if (!code) code = DumpByte(iodp, 't',(byte)V_type(vp));
569     if (!code){ code = DumpInt32(iodp, 'p',V_parentId(vp));}
570     if (!code) code = DumpInt32(iodp, 'c',V_cloneId(vp));
571     if (!code) code = DumpInt32(iodp, 'q',V_maxquota(vp));
572     if (!code) code = DumpInt32(iodp, 'm',V_minquota(vp));
573     if (!code) code = DumpInt32(iodp, 'd',V_diskused(vp));
574     if (!code) code = DumpInt32(iodp, 'f',V_filecount(vp));
575     if (!code) code = DumpInt32(iodp, 'a', V_accountNumber(vp));
576     if (!code) code = DumpInt32(iodp, 'o', V_owner(vp));
577     if (!code) code = DumpInt32(iodp, 'C',V_creationDate(vp));  /* Rw volume creation date */
578     if (!code) code = DumpInt32(iodp, 'A',V_accessDate(vp));
579     if (!code) code = DumpInt32(iodp, 'U',V_updateDate(vp));
580     if (!code) code = DumpInt32(iodp, 'E',V_expirationDate(vp));
581     if (!code) code = DumpInt32(iodp, 'B',V_backupDate(vp));            /* Rw volume backup clone date */
582     if (!code) code = DumpString(iodp, 'O',V_offlineMessage(vp));
583     /*
584      * We do NOT dump the detailed volume statistics residing in the old
585      * motd field, since we cannot tell from the info in a dump whether
586      * statistics data has been put there.  Instead, we dump a null string,
587      * just as if that was what the motd contained.
588      */
589     if (!code) code = DumpString(iodp, 'M', nullString);
590     if (!code) code = DumpArrayInt32(iodp, 'W', (afs_uint32 *)V_weekUse(vp), sizeof(V_weekUse(vp))/sizeof(V_weekUse(vp)[0]));
591     if (!code) code = DumpInt32(iodp, 'D', V_dayUseDate(vp));
592     if (!code) code = DumpInt32(iodp, 'Z', V_dayUse(vp));
593     return code;
594 }
595
596 static int DumpEnd(register struct iod *iodp)
597 {
598     return(DumpInt32(iodp, D_DUMPEND, DUMPENDMAGIC));
599 }
600
601 /* Guts of the dump code */
602
603 /* Dump a whole volume */
604 int DumpVolume(register struct rx_call *call, register Volume *vp,
605                       afs_int32 fromtime, int dumpAllDirs)
606 {
607     struct iod iod;
608     int code = 0;
609     register struct iod *iodp = &iod;
610     iod_Init(iodp, call);
611     
612     if (!code) code = DumpDumpHeader(iodp, vp, fromtime);
613     
614     if (!code) code = DumpPartial(iodp, vp, fromtime, dumpAllDirs);
615     
616 /* hack follows.  Errors should be handled quite differently in this version of dump than they used to be.*/
617     if (rx_Error(iodp->call)) {
618         Log("1 Volser: DumpVolume: Rx call failed during dump, error %d\n", rx_Error(iodp->call));
619         return VOLSERDUMPERROR;
620     }
621     if (!code) code = DumpEnd(iodp);
622     
623     return code;
624 }
625
626 /* Dump a volume to multiple places*/
627 int DumpVolMulti(struct rx_call **calls, int ncalls, Volume *vp,
628                  afs_int32 fromtime, int dumpAllDirs, int *codes)
629 {
630     struct iod iod;
631     int code = 0;
632     iod_InitMulti(&iod, calls, ncalls, codes);
633     
634     if (!code) code = DumpDumpHeader(&iod, vp, fromtime);
635     if (!code) code = DumpPartial(&iod, vp, fromtime, dumpAllDirs);
636     if (!code) code = DumpEnd(&iod);
637     return code;
638 }
639
640 /* A partial dump (no dump header) */
641 static int DumpPartial(register struct iod *iodp, register Volume *vp,
642                        afs_int32 fromtime, int dumpAllDirs)
643 {
644     int code = 0;
645     if (!code) code = DumpVolumeHeader(iodp, vp);
646     if (!code) code = DumpVnodeIndex(iodp, vp, vLarge, fromtime, dumpAllDirs);
647     if (!code) code = DumpVnodeIndex(iodp, vp, vSmall, fromtime, 0);
648     return code;
649 }
650
651 static int DumpVnodeIndex(register struct iod *iodp, Volume *vp,
652                           VnodeClass class, afs_int32 fromtime, int forcedump)
653 {
654     register int code = 0;
655     register struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
656     char buf[SIZEOF_LARGEDISKVNODE];
657     struct VnodeDiskObject *vnode = (struct VnodeDiskObject *) buf;
658     StreamHandle_t *file;
659     FdHandle_t *fdP;
660     int size;
661     int flag;
662     register int vnodeIndex, nVnodes;
663
664     fdP = IH_OPEN(vp->vnodeIndex[class].handle);
665     assert(fdP != NULL);
666     file = FDH_FDOPEN(fdP, "r+");
667     assert(file != NULL);
668     size = OS_SIZE(fdP->fd_fd);
669     assert(size != -1);
670     nVnodes = (size / vcp->diskSize) - 1;
671     if (nVnodes > 0) {
672         assert((nVnodes+1)*vcp->diskSize == size);
673         assert(STREAM_SEEK(file, vcp->diskSize, 0) == 0);
674     }
675     else nVnodes = 0;
676     for (vnodeIndex = 0; nVnodes && STREAM_READ(vnode, vcp->diskSize, 1, file) == 1 && !code;
677       nVnodes--, vnodeIndex++) {
678         flag = forcedump || (vnode->serverModifyTime >= fromtime);
679         /* Note:  the >= test is very important since some old volumes may not have
680            a serverModifyTime.  For an epoch dump, this results in 0>=0 test, which
681            does dump the file! */
682         if (!code) code = DumpVnode(iodp, vnode, V_id(vp), bitNumberToVnodeNumber(vnodeIndex, class), flag);
683         if (!flag) IOMGR_Poll(); /* if we dont' xfr data, but scan instead, could lose conn */
684     }
685     STREAM_CLOSE(file);
686     FDH_CLOSE(fdP);
687     return code;
688 }
689
690 static int DumpDumpHeader(register struct iod *iodp, register Volume *vp,
691                           afs_int32 fromtime)
692 {
693     int code = 0;
694     int UseLatestReadOnlyClone = 1;
695     afs_int32 dumpTimes[2];
696     iodp->device = vp->device;
697     iodp->parentId = V_parentId(vp);
698     iodp->dumpPartition = vp->partition;
699     if (!code) code = DumpDouble(iodp, D_DUMPHEADER, DUMPBEGINMAGIC, DUMPVERSION);
700     if (!code) code = DumpInt32(iodp, 'v', UseLatestReadOnlyClone? V_id(vp): V_parentId(vp));
701     if (!code) code = DumpString(iodp, 'n',V_name(vp));
702     dumpTimes[0] = fromtime;
703     dumpTimes[1] = V_backupDate(vp);    /* Until the time the clone was made */
704     if (!code) code = DumpArrayInt32(iodp, 't', (afs_uint32 *)dumpTimes, 2);
705     return code;
706 }
707
708 static int DumpVnode(register struct iod *iodp, struct VnodeDiskObject *v,
709                      int volid, int vnodeNumber, int dumpEverything)
710 {
711     int code = 0;
712     IHandle_t *ihP;
713     FdHandle_t *fdP;
714
715     if (!v || v->type == vNull)
716         return code;
717     if (!code) code = DumpDouble(iodp, D_VNODE, vnodeNumber, v->uniquifier);
718     if (!dumpEverything)
719         return code;
720     if (!code) code = DumpByte(iodp, 't',(byte)v->type);
721     if (!code) code = DumpShort(iodp, 'l', v->linkCount); /* May not need this */
722     if (!code) code = DumpInt32(iodp, 'v', v->dataVersion);
723     if (!code) code = DumpInt32(iodp, 'm', v->unixModifyTime);
724     if (!code) code = DumpInt32(iodp, 'a', v->author);
725     if (!code) code = DumpInt32(iodp, 'o', v->owner);
726     if (!code && v->group) code = DumpInt32(iodp, 'g', v->group);       /* default group is 0 */
727     if (!code) code = DumpShort(iodp, 'b', v->modeBits);
728     if (!code) code = DumpInt32(iodp, 'p', v->parent);
729     if (!code) code = DumpInt32(iodp, 's', v->serverModifyTime);
730     if (v->type == vDirectory) {
731         acl_HtonACL(VVnodeDiskACL(v));
732         if (!code) code = DumpByteString(iodp, 'A', (byte *) VVnodeDiskACL(v), VAclDiskSize(v));
733     }
734     if (VNDISK_GET_INO(v)) {
735         IH_INIT(ihP, iodp->device, iodp->parentId, VNDISK_GET_INO(v));
736         fdP = IH_OPEN(ihP);
737         if (fdP == NULL) {
738             Log("1 Volser: DumpVnode: dump: Unable to open inode %llu for vnode %u (volume %i); not dumped, error %d\n",
739                 (afs_uintmax_t)VNDISK_GET_INO(v), vnodeNumber, volid, errno);
740             IH_RELEASE(ihP);
741             return VOLSERREAD_DUMPERROR;
742         }
743         code = DumpFile(iodp, 'f', vnodeNumber, fdP);
744         FDH_CLOSE(fdP);
745         IH_RELEASE(ihP);
746     }
747     return code;
748 }
749
750
751 int ProcessIndex(Volume *vp, VnodeClass class, afs_int32 **Bufp, int *sizep,
752                  int del)
753 {
754     int i, nVnodes, offset, code, index=0;
755     afs_int32 *Buf;
756     int cnt=0;  
757     int size;
758     StreamHandle_t *afile;
759     FdHandle_t *fdP;
760     struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
761     char buf[SIZEOF_LARGEDISKVNODE], zero[SIZEOF_LARGEDISKVNODE];
762     register struct VnodeDiskObject *vnode = (struct VnodeDiskObject *) buf;
763     
764     memset(zero, 0, sizeof(zero));      /* zero out our proto-vnode */
765     fdP = IH_OPEN(vp->vnodeIndex[class].handle);
766     if (fdP == NULL)
767         return -1;
768     afile = FDH_FDOPEN(fdP, "r+");
769     if (del) {
770         int cnt1=0;
771         Buf = *Bufp;
772         for (i = 0; i<*sizep; i++) {
773             if (Buf[i]) {
774                 cnt++;
775                 STREAM_SEEK(afile, Buf[i], 0);    
776                 code = STREAM_READ(vnode, vcp->diskSize, 1, afile);
777                 if (code == 1) {
778                     if (vnode->type != vNull && VNDISK_GET_INO(vnode)) {
779                         cnt1++;
780                         if (DoLogging) {
781                            afs_fsize_t vnodeLength;
782                            Log("RestoreVolume %u Cleanup: Removing old vnode=%u inode=%llu size=%llu\n", 
783                                V_id(vp), bitNumberToVnodeNumber(i,class),
784                                (afs_uintmax_t)VNDISK_GET_INO(vnode),
785                                (afs_uintmax_t)vnodeLength);
786                         }
787                         IH_DEC(V_linkHandle(vp), VNDISK_GET_INO(vnode),
788                              V_parentId(vp));
789                         DOPOLL;
790                     }
791                     STREAM_SEEK(afile, Buf[i], 0);
792                     (void ) STREAM_WRITE(zero, vcp->diskSize, 1, afile);        /* Zero it out */
793                 }
794                 Buf[i] = 0;
795             }
796         }
797         if (DoLogging) {
798            Log("RestoreVolume Cleanup: Removed %d inodes for volume %d\n",
799                cnt1, V_id(vp));
800         }
801         STREAM_FLUSH(afile);            /* ensure 0s are on the disk */
802         OS_SYNC(afile->str_fd);
803     } else {
804         size = OS_SIZE(fdP->fd_fd);
805         assert(size != -1);
806         nVnodes = (size <= vcp->diskSize ? 0 :
807                    size-vcp->diskSize) >> vcp->logSize;
808         if (nVnodes > 0) {
809             Buf = (afs_int32 *) malloc(nVnodes * sizeof(afs_int32));
810             if (Buf == NULL) return 1;
811             memset((char *)Buf, 0, nVnodes * sizeof(afs_int32));
812             STREAM_SEEK(afile, offset = vcp->diskSize, 0);
813             while (1) {
814                 code = STREAM_READ(vnode, vcp->diskSize, 1, afile);
815                 if (code != 1) {
816                     break;
817                 }
818                 if (vnode->type != vNull && VNDISK_GET_INO(vnode)) {
819                     Buf[(offset >> vcp->logSize)-1] = offset;
820                     cnt++;
821                 }
822                 offset += vcp->diskSize;
823             }
824             *Bufp = Buf;
825             *sizep = nVnodes;
826         }
827     }
828     STREAM_CLOSE(afile);
829     FDH_CLOSE(fdP);
830     return 0;
831 }
832
833
834 int RestoreVolume(register struct rx_call *call, Volume *avp,
835                   int incremental, struct restoreCookie *cookie)
836 {
837     VolumeDiskData vol;
838     struct DumpHeader header;
839     afs_uint32 endMagic;
840     Error error = 0, vupdate;
841     register Volume *vp;
842     struct iod iod;
843     register struct iod *iodp = &iod;
844     afs_int32 *b1=0, *b2=0;
845     int s1=0, s2=0, delo=0, tdelo;
846     int tag;
847
848     iod_Init(iodp, call);
849     
850     vp = avp;
851     if (!ReadDumpHeader(iodp, &header)){
852         Log("1 Volser: RestoreVolume: Error reading header file for dump; aborted\n");
853         return VOLSERREAD_DUMPERROR;
854     }
855     if (iod_getc(iodp) != D_VOLUMEHEADER){
856         Log("1 Volser: RestoreVolume: Volume header missing from dump; not restored\n");
857         return VOLSERREAD_DUMPERROR;
858     }
859     if(ReadVolumeHeader(iodp, &vol) == VOLSERREAD_DUMPERROR) return VOLSERREAD_DUMPERROR;
860
861     delo = ProcessIndex(vp, vLarge, &b1, &s1, 0);
862     if (!delo) delo = ProcessIndex(vp, vSmall, &b2, &s2, 0);
863     if (delo) {
864        if (b1) free((char *)b1);
865        if (b2) free((char *)b2);
866        b1 = b2 = 0;
867     }
868
869     strncpy(vol.name,cookie->name,VOLSER_OLDMAXVOLNAME);
870     vol.type = cookie->type;
871     vol.cloneId = cookie->clone;
872     vol.parentId = cookie->parent;
873     
874
875     tdelo = delo;
876     while (1) {
877        if (ReadVnodes(iodp, vp, 0, b1, s1, b2, s2, tdelo)) {
878           error =  VOLSERREAD_DUMPERROR;
879           goto clean;
880        }
881        tag = iod_getc(iodp);
882        if (tag != D_VOLUMEHEADER)
883           break;
884        if (ReadVolumeHeader(iodp, &vol) == VOLSERREAD_DUMPERROR) {
885           error = VOLSERREAD_DUMPERROR;
886           goto out;
887        }
888        tdelo = -1;
889     }
890     if (tag != D_DUMPEND || !ReadInt32(iodp, &endMagic) || endMagic != DUMPENDMAGIC){
891        Log("1 Volser: RestoreVolume: End of dump not found; restore aborted\n");
892        error =  VOLSERREAD_DUMPERROR;
893        goto clean;
894     }
895
896
897     if (iod_getc(iodp) != EOF) {
898         Log("1 Volser: RestoreVolume: Unrecognized postamble in dump; restore aborted\n");
899         error = VOLSERREAD_DUMPERROR;
900         goto clean;
901     }
902
903     if (!delo) {
904         ProcessIndex(vp, vLarge, &b1, &s1, 1);
905         ProcessIndex(vp, vSmall, &b2, &s2, 1);
906     }
907
908  clean:
909     ClearVolumeStats(&vol);
910     CopyVolumeHeader(&vol, &V_disk(vp));
911     V_destroyMe(vp) = 0;
912     VUpdateVolume(&vupdate, vp);
913     if (vupdate) {
914         Log("1 Volser: RestoreVolume: Unable to rewrite volume header; restore aborted\n");
915         error = VOLSERREAD_DUMPERROR;
916         goto out;
917     }
918  out:
919     /* Free the malloced space above */
920     if (b1) free((char *)b1);
921     if (b2) free((char *)b2);
922     return error;
923 }
924
925 static int ReadVnodes(register struct iod *iodp, Volume *vp,
926                       int incremental, afs_int32 *Lbuf, afs_int32 s1,
927                       afs_int32 *Sbuf, afs_int32 s2, afs_int32 delo)
928 {
929     afs_int32 vnodeNumber;
930     char buf[SIZEOF_LARGEDISKVNODE];
931     register tag;
932     struct VnodeDiskObject *vnode = (struct VnodeDiskObject *) buf;
933     struct VnodeDiskObject oldvnode;
934     int idx;
935     VnodeClass class;
936     struct VnodeClassInfo *vcp;
937     IHandle_t *tmpH;
938     FdHandle_t *fdP;
939     Inode       nearInode;
940
941     tag = iod_getc(iodp);
942     V_pref(vp, nearInode);
943     while (tag == D_VNODE) {
944         int haveStuff = 0;
945         memset(buf, 0, sizeof (buf));
946         if (!ReadInt32(iodp, (afs_uint32 *)&vnodeNumber))
947             break;
948
949         ReadInt32(iodp, &vnode->uniquifier);
950         while ((tag = iod_getc(iodp)) > D_MAX && tag != EOF) {
951             haveStuff = 1;
952             switch (tag) {
953                 case 't':
954                     vnode->type = (VnodeType) iod_getc(iodp);
955                     break;
956                 case 'l':
957                     {
958                         unsigned short tlc;
959                         ReadShort(iodp, &tlc);
960                         vnode->linkCount = (signed int)tlc;
961                     }
962                     break;
963                 case 'v':
964                     ReadInt32(iodp, &vnode->dataVersion);
965                     break;
966                 case 'm':
967                     ReadInt32(iodp, &vnode->unixModifyTime);
968                     break;
969                 case 's':
970                     ReadInt32(iodp, &vnode->serverModifyTime);
971                     break;
972                 case 'a':
973                     ReadInt32(iodp, &vnode->author);
974                     break;
975                 case 'o':
976                     ReadInt32(iodp, &vnode->owner);
977                     break;
978                 case 'g':
979                     ReadInt32(iodp, (afs_uint32 *)&vnode->group);
980                     break;
981                 case 'b': {
982                     unsigned short modeBits;
983                     ReadShort(iodp, &modeBits);
984                     vnode->modeBits = (unsigned int)modeBits;
985                     break;
986                 }
987                 case 'p':
988                     ReadInt32(iodp, &vnode->parent);
989                     break;
990                 case 'A':
991                     ReadByteString(iodp, (byte *)VVnodeDiskACL(vnode),
992                                    VAclDiskSize(vnode));
993                     acl_NtohACL(VVnodeDiskACL(vnode));
994                     break;
995                 case 'f': {
996                     Inode ino;
997                     Error error;
998                     afs_fsize_t vnodeLength;
999
1000                     ino = IH_CREATE(V_linkHandle(vp),
1001                                     V_device(vp),
1002                                     VPartitionPath(V_partition(vp)),
1003                                     nearInode, V_parentId(vp), vnodeNumber,
1004                                     vnode->uniquifier,
1005                                     vnode->dataVersion);
1006                     if (!VALID_INO(ino)) {
1007                         perror("unable to allocate inode");
1008                         Log("1 Volser: ReadVnodes: Restore aborted\n");
1009                         return VOLSERREAD_DUMPERROR;
1010                     }
1011                     nearInode = ino;
1012                     VNDISK_SET_INO(vnode, ino);
1013                     IH_INIT(tmpH, vp->device, V_parentId(vp), ino);
1014                     fdP = IH_OPEN(tmpH);
1015                     if (fdP == NULL) {
1016                         IH_RELEASE(tmpH);
1017                         return VOLSERREAD_DUMPERROR;
1018                     }
1019                     vnodeLength = volser_WriteFile(vnodeNumber, iodp, fdP,
1020                                                    &error);
1021                     VNDISK_SET_LEN(vnode, vnodeLength);
1022                     FDH_REALLYCLOSE(fdP);
1023                     IH_RELEASE(tmpH);
1024                     if (error) {
1025                         Log("1 Volser: ReadVnodes: IDEC inode %llu\n",
1026                             (afs_uintmax_t)ino);
1027                         IH_DEC(V_linkHandle(vp), ino, V_parentId(vp));
1028                         return VOLSERREAD_DUMPERROR;
1029                     }
1030                     break;
1031                 }
1032             }
1033         }
1034
1035         class = vnodeIdToClass(vnodeNumber);
1036         vcp   = &VnodeClassInfo[class];
1037
1038         /* Mark this vnode as in this dump - so we don't delete it later */
1039         if (!delo) {
1040            idx = (vnodeIndexOffset(vcp,vnodeNumber) >> vcp->logSize) - 1;
1041            if (class == vLarge) {
1042               if (Lbuf && (idx < s1)) Lbuf[idx] = 0;
1043            } else {
1044               if (Sbuf && (idx < s2)) Sbuf[idx] = 0;
1045            }
1046         }
1047
1048         if (haveStuff) {
1049             FdHandle_t *fdP = IH_OPEN(vp->vnodeIndex[class].handle);
1050             if (fdP == NULL) {
1051                 Log("1 Volser: ReadVnodes: Error opening vnode index; restore aborted\n");
1052                 return VOLSERREAD_DUMPERROR;
1053             }
1054             if (FDH_SEEK(fdP, vnodeIndexOffset(vcp, vnodeNumber), SEEK_SET) < 0) {
1055                 Log("1 Volser: ReadVnodes: Error seeking into vnode index; restore aborted\n");
1056                 FDH_REALLYCLOSE(fdP);
1057                 return VOLSERREAD_DUMPERROR;
1058             }
1059             if (FDH_READ(fdP, &oldvnode, sizeof(oldvnode)) == sizeof(oldvnode)) {
1060                 if (oldvnode.type != vNull && VNDISK_GET_INO(&oldvnode)) {
1061                     IH_DEC(V_linkHandle(vp), VNDISK_GET_INO(&oldvnode),
1062                          V_parentId(vp));
1063                 }
1064             }
1065             vnode->vnodeMagic = vcp->magic;
1066             if (FDH_SEEK(fdP, vnodeIndexOffset(vcp, vnodeNumber), SEEK_SET) < 0) {
1067                 Log("1 Volser: ReadVnodes: Error seeking into vnode index; restore aborted\n");
1068                 FDH_REALLYCLOSE(fdP);
1069                 return VOLSERREAD_DUMPERROR;
1070             }
1071             if (FDH_WRITE(fdP, vnode, vcp->diskSize) != vcp->diskSize) {
1072                 Log("1 Volser: ReadVnodes: Error writing vnode index; restore aborted\n");
1073                 FDH_REALLYCLOSE(fdP);
1074                 return VOLSERREAD_DUMPERROR;
1075             }
1076             FDH_CLOSE(fdP);
1077         }
1078     }
1079     iod_ungetc(iodp, tag);
1080
1081
1082     return 0;
1083 }
1084
1085
1086 /* called with disk file only.  Note that we don't have to worry about rx_Read
1087  * needing to read an ungetc'd character, since the ReadInt32 will have read
1088  * it instead.
1089  */
1090 static bit32 volser_WriteFile(int vn, struct iod *iodp, FdHandle_t *handleP,
1091                               Error *status)
1092 {
1093     afs_int32 code;
1094     afs_uint32 filesize;
1095     bit32 written=0;
1096     register afs_uint32 size = 8192;
1097     register afs_uint32 nbytes;
1098     unsigned char *p;
1099
1100
1101     *status = 0;
1102     if (!ReadInt32(iodp, &filesize)) {
1103         *status = 1;
1104         return(0);
1105     }
1106     p = (unsigned char *) malloc(size);
1107     if (p == NULL) {
1108         *status = 2;
1109         return(0);
1110     }
1111     for (nbytes = filesize; nbytes; nbytes -= size) {
1112         if (nbytes < size)
1113             size = nbytes;
1114         
1115         if ((code = iod_Read(iodp, p, size)) != size) {
1116             Log("1 Volser: WriteFile: Error reading dump file %d size=%llu nbytes=%u (%d of %u); restore aborted\n", vn, (afs_uintmax_t)filesize, nbytes, code, size);
1117             *status = 3;
1118             break;
1119         }
1120         code = FDH_WRITE(handleP, p, size);
1121         if (code > 0) written += code;
1122         if (code != size) {
1123             Log("1 Volser: WriteFile: Error creating file in volume; restore aborted\n");
1124             *status = 4;
1125             break;
1126         }
1127     }
1128     free(p);
1129     return(written);
1130 }
1131
1132 static int ReadDumpHeader(register struct iod *iodp, struct DumpHeader *hp)
1133 {
1134     register tag;
1135     afs_uint32 beginMagic;
1136     if (iod_getc(iodp) != D_DUMPHEADER || !ReadInt32(iodp, &beginMagic)
1137        || !ReadInt32(iodp, (afs_uint32 *)&hp->version)
1138        || beginMagic != DUMPBEGINMAGIC
1139        ) return 0;
1140     hp->volumeId = 0;
1141     hp->nDumpTimes = 0;
1142     while ((tag = iod_getc(iodp)) > D_MAX) {
1143         unsigned short arrayLength;
1144         register int i;
1145         switch(tag) {
1146             case 'v':
1147                 if (!ReadInt32(iodp, &hp->volumeId))
1148                     return 0;
1149                 break;
1150             case 'n':
1151                 ReadString(iodp, hp->volumeName, sizeof(hp->volumeName));
1152                 break;
1153             case 't':
1154                 if (!ReadShort(iodp, &arrayLength))
1155                     return 0;
1156                 hp->nDumpTimes = (arrayLength >> 1);
1157                 for (i = 0; i<hp->nDumpTimes; i++)
1158                     if (!ReadInt32(iodp, (afs_uint32 *)&hp->dumpTimes[i].from)
1159                         || !ReadInt32(iodp, (afs_uint32 *)&hp->dumpTimes[i].to))
1160                         return 0;
1161                 break;
1162         }
1163     }
1164     if (!hp->volumeId || !hp->nDumpTimes) {
1165         return 0;
1166     }
1167     iod_ungetc(iodp, tag);
1168     return 1;
1169 }
1170
1171
1172 /* ----- Below are the calls that calculate dump size ----- */
1173
1174 static int SizeDumpVolumeHeader(register struct iod *iodp, register Volume *vp, register struct volintSize *v_size)
1175 {
1176     int code = 0;
1177     static char nullString[1] = "";  /*The ``contents'' of motd*/
1178
1179 /*     if (!code) code = DumpTag(iodp, D_VOLUMEHEADER); */
1180     v_size->dump_size += 1;
1181 /*     if (!code) {code = DumpInt32(iodp, 'i',V_id(vp));} */
1182     v_size->dump_size += 5;
1183 /*     if (!code) code = DumpInt32(iodp, 'v',V_stamp(vp).version); */
1184     v_size->dump_size += 5;
1185 /*     if (!code) code = DumpString(iodp, 'n',V_name(vp)); */
1186     v_size->dump_size += (2 + strlen(V_name(vp)));
1187 /*     if (!code) code = DumpBool(iodp, 's',V_inService(vp)); */
1188     v_size->dump_size += 2;
1189 /*     if (!code) code = DumpBool(iodp, 'b',V_blessed(vp)); */
1190     v_size->dump_size += 2;
1191 /*     if (!code) code = DumpInt32(iodp, 'u',V_uniquifier(vp)); */
1192     v_size->dump_size += 5;
1193 /*     if (!code) code = DumpByte(iodp, 't',(byte)V_type(vp)); */
1194     v_size->dump_size += 2;
1195 /*     if (!code){ code = DumpInt32(iodp, 'p',V_parentId(vp));} */
1196     v_size->dump_size += 5;
1197 /*     if (!code) code = DumpInt32(iodp, 'c',V_cloneId(vp)); */
1198     v_size->dump_size += 5;
1199 /*     if (!code) code = DumpInt32(iodp, 'q',V_maxquota(vp)); */
1200     v_size->dump_size += 5;
1201 /*     if (!code) code = DumpInt32(iodp, 'm',V_minquota(vp)); */
1202     v_size->dump_size += 5;
1203 /*     if (!code) code = DumpInt32(iodp, 'd',V_diskused(vp)); */
1204     v_size->dump_size += 5;
1205 /*     if (!code) code = DumpInt32(iodp, 'f',V_filecount(vp)); */
1206     v_size->dump_size += 5;
1207 /*     if (!code) code = DumpInt32(iodp, 'a', V_accountNumber(vp)); */
1208     v_size->dump_size += 5;
1209 /*     if (!code) code = DumpInt32(iodp, 'o', V_owner(vp)); */
1210     v_size->dump_size += 5;
1211 /*     if (!code) code = DumpInt32(iodp, 'C',V_creationDate(vp));       /\* Rw volume creation date *\/ */
1212     v_size->dump_size += 5;
1213 /*     if (!code) code = DumpInt32(iodp, 'A',V_accessDate(vp)); */
1214     v_size->dump_size += 5;
1215 /*     if (!code) code = DumpInt32(iodp, 'U',V_updateDate(vp)); */
1216     v_size->dump_size += 5;
1217 /*     if (!code) code = DumpInt32(iodp, 'E',V_expirationDate(vp)); */
1218     v_size->dump_size += 5;
1219 /*     if (!code) code = DumpInt32(iodp, 'B',V_backupDate(vp));         /\* Rw volume backup clone date *\/ */
1220     v_size->dump_size += 5;
1221 /*     if (!code) code = DumpString(iodp, 'O',V_offlineMessage(vp)); */
1222     v_size->dump_size += (2 + strlen(V_offlineMessage(vp)));
1223 /*     /\* */
1224 /*      * We do NOT dump the detailed volume statistics residing in the old */
1225 /*      * motd field, since we cannot tell from the info in a dump whether */
1226 /*      * statistics data has been put there.  Instead, we dump a null string, */
1227 /*      * just as if that was what the motd contained. */
1228 /*      *\/ */
1229 /*     if (!code) code = DumpString(iodp, 'M', nullString); */
1230     v_size->dump_size += (2 + strlen(nullString));
1231 /*     if (!code) code = DumpArrayInt32(iodp, 'W', (afs_uint32 *)V_weekUse(vp), sizeof(V_weekUse(vp))/sizeof(V_weekUse(vp)[0])); */
1232     v_size->dump_size += (3 + 4*(sizeof(V_weekUse(vp))/sizeof(V_weekUse(vp)[0])));
1233 /*     if (!code) code = DumpInt32(iodp, 'D', V_dayUseDate(vp)); */
1234     v_size->dump_size += 5;
1235 /*     if (!code) code = DumpInt32(iodp, 'Z', V_dayUse(vp)); */
1236     v_size->dump_size += 5;
1237     return code;
1238 }
1239
1240 static int SizeDumpEnd(register struct iod *iodp, register struct volintSize *v_size)
1241 {
1242     int code = 0;
1243     v_size->dump_size += 5;
1244     return code;
1245 }
1246
1247 int SizeDumpVolume(register struct rx_call *call, register Volume *vp, afs_int32 fromtime,
1248                    int dumpAllDirs, register struct volintSize *v_size)
1249 {
1250     struct iod iod;
1251     int code = 0;
1252     register struct iod *iodp = (struct iod *)0;
1253 /*    iod_Init(iodp, call); */
1254
1255     if (!code) code = SizeDumpDumpHeader(iodp, vp, fromtime, v_size);
1256     if (!code) code = SizeDumpPartial(iodp, vp, fromtime, dumpAllDirs, v_size);
1257     if (!code) code = SizeDumpEnd(iodp, v_size);
1258     
1259     return code;
1260 }
1261
1262 static int SizeDumpDumpHeader(register struct iod *iodp, register Volume *vp, afs_int32 fromtime,
1263                               register struct volintSize *v_size)
1264 {
1265     int code = 0;
1266     int UseLatestReadOnlyClone = 1;
1267     afs_int32 dumpTimes[2];
1268 /*    iodp->device = vp->device; */
1269 /*    iodp->parentId = V_parentId(vp); */
1270 /*    iodp->dumpPartition = vp->partition; */
1271
1272     v_size->dump_size = 0; /* initialize the size */
1273 /*     if (!code) code = DumpDouble(iodp, D_DUMPHEADER, DUMPBEGINMAGIC, DUMPVERSION); */
1274     v_size->dump_size += 9;
1275 /*     if (!code) code = DumpInt32(iodp, 'v', UseLatestReadOnlyClone? V_id(vp): V_parentId(vp)); */
1276     v_size->dump_size += 5;
1277 /*     if (!code) code = DumpString(iodp, 'n',V_name(vp)); */
1278     v_size->dump_size += (2 + strlen(V_name(vp)));
1279 /*     dumpTimes[0] = fromtime; */
1280 /*     dumpTimes[1] = V_backupDate(vp); /\* Until the time the clone was made *\/ */
1281 /*     if (!code) code = DumpArrayInt32(iodp, 't', (afs_uint32 *)dumpTimes, 2); */
1282     v_size->dump_size += (3 + 4*2);
1283     return code;
1284 }
1285
1286 static int SizeDumpVnode(register struct iod *iodp, struct VnodeDiskObject *v, int volid, int vnodeNumber, int dumpEverything,
1287                      register struct volintSize *v_size)
1288 {
1289     int code = 0;
1290
1291     if (!v || v->type == vNull)
1292         return code;
1293 /*     if (!code) code = DumpDouble(iodp, D_VNODE, vnodeNumber, v->uniquifier); */
1294     v_size->dump_size += 9;
1295     if (!dumpEverything)
1296         return code;
1297 /*     if (!code)  code = DumpByte(iodp, 't',(byte)v->type); */
1298     v_size->dump_size += 2;
1299 /*     if (!code) code = DumpShort(iodp, 'l', v->linkCount); /\* May not need this *\/ */
1300     v_size->dump_size += 3;
1301 /*     if (!code) code = DumpInt32(iodp, 'v', v->dataVersion); */
1302     v_size->dump_size += 5;
1303 /*     if (!code) code = DumpInt32(iodp, 'm', v->unixModifyTime); */
1304     v_size->dump_size += 5;
1305 /*     if (!code) code = DumpInt32(iodp, 'a', v->author); */
1306     v_size->dump_size += 5;
1307 /*     if (!code) code = DumpInt32(iodp, 'o', v->owner); */
1308     v_size->dump_size += 5;
1309 /*     if (!code && v->group) code = DumpInt32(iodp, 'g', v->group);    /\* default group is 0 *\/ */
1310     if(v->group)     v_size->dump_size += 5;
1311 /*     if (!code) code = DumpShort(iodp, 'b', v->modeBits); */
1312     v_size->dump_size += 3;
1313 /*     if (!code) code = DumpInt32(iodp, 'p', v->parent); */
1314     v_size->dump_size += 5;
1315 /*     if (!code) code = DumpInt32(iodp, 's', v->serverModifyTime); */
1316     v_size->dump_size += 5;
1317     if (v->type == vDirectory) {
1318 /*      acl_HtonACL(VVnodeDiskACL(v)); */
1319 /*      if (!code) code = DumpByteString(iodp, 'A', (byte *) VVnodeDiskACL(v), VAclDiskSize(v)); */
1320         v_size->dump_size += 1 + VAclDiskSize(v);
1321     }
1322
1323     if (VNDISK_GET_INO(v)) {
1324         v_size->dump_size += (v->length + 5);
1325     } 
1326     return code;
1327 }
1328
1329 /* A partial dump (no dump header) */
1330 static int SizeDumpPartial(register struct iod *iodp, register Volume *vp, afs_int32 fromtime, int dumpAllDirs,
1331                            register struct volintSize *v_size)
1332 {
1333     int code = 0;
1334     if (!code) code = SizeDumpVolumeHeader(iodp, vp, v_size);
1335     if (!code) code = SizeDumpVnodeIndex(iodp, vp, vLarge, fromtime, dumpAllDirs, v_size);
1336     if (!code) code = SizeDumpVnodeIndex(iodp, vp, vSmall, fromtime, 0, v_size);
1337     return code;
1338 }
1339
1340 static int SizeDumpVnodeIndex(register struct iod *iodp, Volume *vp, VnodeClass class, afs_int32 fromtime,
1341                               int forcedump, register struct volintSize *v_size)
1342 {
1343     register int code = 0;
1344     register struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
1345     char buf[SIZEOF_LARGEDISKVNODE];
1346     struct VnodeDiskObject *vnode = (struct VnodeDiskObject *) buf;
1347     StreamHandle_t *file;
1348     FdHandle_t *fdP;
1349     int size;
1350     int flag;
1351     register int vnodeIndex, nVnodes;
1352
1353     fdP = IH_OPEN(vp->vnodeIndex[class].handle);
1354     assert(fdP != NULL);
1355     file = FDH_FDOPEN(fdP, "r+");
1356     assert(file != NULL);
1357     size = OS_SIZE(fdP->fd_fd);
1358     assert(size != -1);
1359    nVnodes = (size / vcp->diskSize) - 1;
1360     if (nVnodes > 0) {
1361         assert((nVnodes+1)*vcp->diskSize == size);
1362         assert(STREAM_SEEK(file, vcp->diskSize, 0) == 0);
1363     }
1364     else nVnodes = 0;
1365     for (vnodeIndex = 0; nVnodes && STREAM_READ(vnode, vcp->diskSize, 1, file) == 1 && !code;
1366       nVnodes--, vnodeIndex++) {
1367         flag = forcedump || (vnode->serverModifyTime >= fromtime);
1368         /* Note:  the >= test is very important since some old volumes may not have
1369            a serverModifyTime.  For an epoch dump, this results in 0>=0 test, which
1370            does dump the file! */
1371         if (!code) code = SizeDumpVnode(iodp, vnode, V_id(vp), bitNumberToVnodeNumber(vnodeIndex, class), flag, v_size);
1372     }
1373     STREAM_CLOSE(file);
1374     FDH_CLOSE(fdP);
1375     return code;
1376 }
1377