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