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