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