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