Update NEWS for 1.6.22
[pkg-k5-afs_openafs.git] / src / volser / restorevol.c
blobe21668a8c59e34182b2ed03b228e77054aef9c7f
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
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 */
11 * Read a vos dump and recreate the tree.
13 * restorevol [-file <dump file>]
14 * [-dir <restore dir>]
15 * [-extension <name extension>]
16 * [-mountpoint <mount point root>]
17 * [-umask <mode mask>]
19 * 1. The dump file will be restored within the current or that specified with -dir.
20 * 2. Within this dir, a subdir is created. It's name is the RW volume name
21 * that was dumped. An extension can be appended to this directory name
22 * with -extension.
23 * 3. All mountpoints will appear as symbolic links to the volume. The
24 * pathname to the volume will be either that in -mountpoint, or -dir.
25 * Symbolic links remain untouched.
26 * 4. You can change your umask during the restore with -umask. Otherwise, it
27 * uses your current umask. Mode bits for directories are 0777 (then
28 * AND'ed with the umask). Mode bits for files are the owner mode bits
29 * duplicated accross group and user (then AND'ed with the umask).
30 * 5. For restores of full dumps, if a directory says it has a file and
31 * the file is not found, then a symbolic link "AFSFile-<#>" will
32 * appear in that restored tree. Restores of incremental dumps remove
33 * all these files at the end (expensive because it is a tree search).
34 * 6. If a file or directory was found in the dump but found not to be
35 * connected to the hierarchical tree, then the file or directory
36 * will be connected at the root of the tree as "__ORPHANEDIR__.<#>"
37 * or "__ORPHANFILE__.<#>".
38 * 7. ACLs are not restored.
42 #include <afsconfig.h>
43 #include <afs/param.h>
46 #include <afs/afsint.h>
47 #include <afs/nfs.h>
48 #include <lock.h>
49 #include <afs/ihandle.h>
50 #include <afs/vnode.h>
51 #include <afs/volume.h>
52 #include "volint.h"
53 #include "dump.h"
54 #include <afs/cmd.h>
56 #include <sys/param.h>
57 #include <sys/types.h>
58 #include <sys/uio.h>
59 #include <stdio.h>
60 #include <errno.h>
61 #include <netinet/in.h>
62 #include <sys/stat.h>
63 #include <fcntl.h>
64 #include <dirent.h>
65 #include <string.h>
68 char rootdir[MAXPATHLEN];
69 char mntroot[MAXPATHLEN];
70 #define ADIR "AFSDir-"
71 #define AFILE "AFSFile-"
72 #define ODIR "__ORPHANEDIR__."
73 #define OFILE "__ORPHANFILE__."
75 int inc_dump = 0;
76 FILE *dumpfile;
78 afs_int32
79 readvalue(int size)
81 afs_int32 value, s;
82 int code;
83 char *ptr;
85 value = 0;
86 ptr = (char *)&value;
88 s = sizeof(value) - size;
89 if (size < 0) {
90 fprintf(stderr, "Too much data in afs_int32\n");
91 return 0;
94 code = fread(&ptr[s], 1, size, dumpfile);
95 if (code != size)
96 fprintf(stderr, "Code = %d; Errno = %d\n", code, errno);
98 return (value);
101 char
102 readchar(void)
104 char value;
105 int code;
107 value = '\0';
108 code = fread(&value, 1, 1, dumpfile);
109 if (code != 1)
110 fprintf(stderr, "Code = %d; Errno = %d\n", code, errno);
112 return (value);
115 #define BUFSIZE 16384
116 char buf[BUFSIZE];
118 void
119 readdata(char *buffer, afs_sfsize_t size)
121 int code;
122 afs_int32 s;
124 if (!buffer) {
125 while (size > 0) {
126 s = (afs_int32) ((size > BUFSIZE) ? BUFSIZE : size);
127 code = fread(buf, 1, s, dumpfile);
128 if (code != s)
129 fprintf(stderr, "Code = %d; Errno = %d\n", code, errno);
130 size -= s;
132 } else {
133 code = fread(buffer, 1, size, dumpfile);
134 if (code != size) {
135 if (code < 0)
136 fprintf(stderr, "Code = %d; Errno = %d\n", code, errno);
137 else
138 fprintf(stderr, "Read %d bytes out of %" AFS_INT64_FMT "\n", code, (afs_uintmax_t)size);
140 if ((code >= 0) && (code < BUFSIZE))
141 buffer[size] = 0; /* Add null char at end */
145 afs_int32
146 ReadDumpHeader(struct DumpHeader *dh)
148 int i, done;
149 char tag, c;
150 afs_int32 magic AFS_UNUSED;
152 /* memset(&dh, 0, sizeof(dh)); */
154 magic = ntohl(readvalue(4));
155 dh->version = ntohl(readvalue(4));
157 done = 0;
158 while (!done) {
159 tag = readchar();
160 switch (tag) {
161 case 'v':
162 dh->volumeId = ntohl(readvalue(4));
163 break;
165 case 'n':
166 for (i = 0, c = 'a'; c != '\0'; i++) {
167 dh->volumeName[i] = c = readchar();
169 dh->volumeName[i] = c;
170 break;
172 case 't':
173 dh->nDumpTimes = ntohl(readvalue(2)) >> 1;
174 if (dh->nDumpTimes > MAXDUMPTIMES) {
175 fprintf(stderr, "Too many dump times in header (%d > %d)\n",
176 dh->nDumpTimes, MAXDUMPTIMES);
177 dh->nDumpTimes = MAXDUMPTIMES;
179 for (i = 0; i < dh->nDumpTimes; i++) {
180 dh->dumpTimes[i].from = ntohl(readvalue(4));
181 dh->dumpTimes[i].to = ntohl(readvalue(4));
183 break;
185 default:
186 done = 1;
187 break;
191 return ((afs_int32) tag);
194 struct volumeHeader {
195 afs_int32 volumeId;
196 char volumeName[100];
197 afs_int32 volType;
198 afs_int32 uniquifier;
199 afs_int32 parentVol;
200 afs_int32 cloneId;
201 afs_int32 maxQuota;
202 afs_int32 minQuota;
203 afs_int32 diskUsed;
204 afs_int32 fileCount;
205 afs_int32 accountNumber;
206 afs_int32 owner;
207 afs_int32 creationDate;
208 afs_int32 accessDate;
209 afs_int32 updateDate;
210 afs_int32 expirationDate;
211 afs_int32 backupDate;
212 afs_int32 dayUseDate;
213 afs_int32 dayUse;
214 afs_int32 weekCount;
215 afs_int32 weekUse[100]; /* weekCount of these */
216 char motd[1024];
217 int inService;
218 int blessed;
219 char message[1024];
220 afs_int32 volUpdateCounter;
223 afs_int32
224 ReadVolumeHeader(afs_int32 count)
226 struct volumeHeader vh;
227 int i, done;
228 char tag, c;
230 /* memset(&vh, 0, sizeof(vh)); */
232 done = 0;
233 while (!done) {
234 tag = readchar();
235 switch (tag) {
236 case 'i':
237 vh.volumeId = ntohl(readvalue(4));
238 break;
240 case 'v':
241 (void)ntohl(readvalue(4)); /* version stamp - ignore */
242 break;
244 case 'n':
245 for (i = 0, c = 'a'; c != '\0'; i++) {
246 vh.volumeName[i] = c = readchar();
248 vh.volumeName[i] = c;
249 break;
251 case 's':
252 vh.inService = ntohl(readvalue(1));
253 break;
255 case 'b':
256 vh.blessed = ntohl(readvalue(1));
257 break;
259 case 'u':
260 vh.uniquifier = ntohl(readvalue(4));
261 break;
263 case 't':
264 vh.volType = ntohl(readvalue(1));
265 break;
267 case 'p':
268 vh.parentVol = ntohl(readvalue(4));
269 break;
271 case 'c':
272 vh.cloneId = ntohl(readvalue(4));
273 break;
275 case 'q':
276 vh.maxQuota = ntohl(readvalue(4));
277 break;
279 case 'm':
280 vh.minQuota = ntohl(readvalue(4));
281 break;
283 case 'd':
284 vh.diskUsed = ntohl(readvalue(4));
285 break;
287 case 'f':
288 vh.fileCount = ntohl(readvalue(4));
289 break;
291 case 'a':
292 vh.accountNumber = ntohl(readvalue(4));
293 break;
295 case 'o':
296 vh.owner = ntohl(readvalue(4));
297 break;
299 case 'C':
300 vh.creationDate = ntohl(readvalue(4));
301 break;
303 case 'A':
304 vh.accessDate = ntohl(readvalue(4));
305 break;
307 case 'U':
308 vh.updateDate = ntohl(readvalue(4));
309 break;
311 case 'E':
312 vh.expirationDate = ntohl(readvalue(4));
313 break;
315 case 'B':
316 vh.backupDate = ntohl(readvalue(4));
317 break;
319 case 'O':
320 for (i = 0, c = 'a'; c != '\0'; i++) {
321 vh.message[i] = c = readchar();
323 vh.volumeName[i] = c;
324 break;
326 case 'W':
327 vh.weekCount = ntohl(readvalue(2));
328 for (i = 0; i < vh.weekCount; i++) {
329 vh.weekUse[i] = ntohl(readvalue(4));
331 break;
333 case 'M':
334 for (i = 0, c = 'a'; c != '\0'; i++) {
335 vh.motd[i] = c = readchar();
337 break;
339 case 'D':
340 vh.dayUseDate = ntohl(readvalue(4));
341 break;
343 case 'Z':
344 vh.dayUse = ntohl(readvalue(4));
345 break;
347 case 'V':
348 readvalue(4); /*volUpCounter*/
349 break;
351 default:
352 done = 1;
353 break;
357 return ((afs_int32) tag);
360 struct vNode {
361 afs_int32 vnode;
362 afs_int32 uniquifier;
363 afs_int32 type;
364 afs_int32 linkCount;
365 afs_int32 dataVersion;
366 afs_int32 unixModTime;
367 afs_int32 servModTime;
368 afs_int32 author;
369 afs_int32 owner;
370 afs_int32 group;
371 afs_int32 modebits;
372 afs_int32 parent;
373 char acl[192];
374 #ifdef notdef
375 struct acl_accessList {
376 int size; /*size of this access list in bytes, including MySize itself */
377 int version; /*to deal with upward compatibility ; <= ACL_ACLVERSION */
378 int total;
379 int positive; /* number of positive entries */
380 int negative; /* number of minus entries */
381 struct acl_accessEntry {
382 int id; /*internally-used ID of user or group */
383 int rights; /*mask */
384 } entries[100];
385 } acl;
386 #endif
387 afs_sfsize_t dataSize;
390 #define MAXNAMELEN 256
392 afs_int32
393 ReadVNode(afs_int32 count)
395 struct vNode vn;
396 int code, i, done;
397 char tag;
398 char dirname[MAXNAMELEN], linkname[MAXNAMELEN], lname[MAXNAMELEN];
399 char parentdir[MAXNAMELEN], vflink[MAXNAMELEN];
400 char filename[MAXNAMELEN], fname[MAXNAMELEN];
401 int len;
402 afs_int32 vnode;
403 afs_int32 mode = 0;
404 afs_uint32 hi, lo;
406 /* memset(&vn, 0, sizeof(vn)); */
407 vn.dataSize = 0;
408 vn.vnode = 0;
409 vn.parent = 0;
410 vn.type = 0;
412 vn.vnode = ntohl(readvalue(4));
413 vn.uniquifier = ntohl(readvalue(4));
415 done = 0;
416 while (!done) {
417 tag = readchar();
418 switch (tag) {
419 case 't':
420 vn.type = ntohl(readvalue(1));
421 break;
423 case 'l':
424 vn.linkCount = ntohl(readvalue(2));
425 break;
427 case 'v':
428 vn.dataVersion = ntohl(readvalue(4));
429 break;
431 case 'm':
432 vn.unixModTime = ntohl(readvalue(4));
433 break;
435 case 's':
436 vn.servModTime = ntohl(readvalue(4));
437 break;
439 case 'a':
440 vn.author = ntohl(readvalue(4));
441 break;
443 case 'o':
444 vn.owner = ntohl(readvalue(4));
445 break;
447 case 'g':
448 vn.group = ntohl(readvalue(4));
449 break;
451 case 'b':
452 vn.modebits = ntohl(readvalue(2));
453 break;
455 case 'p':
456 vn.parent = ntohl(readvalue(4));
457 break;
459 case 'A':
460 readdata(vn.acl, 192); /* Skip ACL data */
461 break;
463 case 'h':
464 hi = ntohl(readvalue(4));
465 lo = ntohl(readvalue(4));
466 FillInt64(vn.dataSize, hi, lo);
467 goto common_vnode;
469 case 'f':
470 vn.dataSize = ntohl(readvalue(4));
472 common_vnode:
473 /* parentdir is the name of this dir's vnode-file-link
474 * or this file's parent vnode-file-link.
475 * "./AFSDir-<#>". It's a symbolic link to its real dir.
476 * The parent dir and symbolic link to it must exist.
478 vnode = ((vn.type == 2) ? vn.vnode : vn.parent);
479 if (vnode == 1)
480 strncpy(parentdir, rootdir, sizeof parentdir);
481 else {
482 afs_snprintf(parentdir, sizeof parentdir, "%s" OS_DIRSEP "%s%d", rootdir,
483 ADIR, vnode);
485 len = readlink(parentdir, linkname, MAXNAMELEN);
486 if (len < 0) {
487 /* parentdir does not exist. So create an orphan dir.
488 * and then link the parentdir to the orphaned dir.
490 afs_snprintf(linkname, sizeof linkname, "%s" OS_DIRSEP "%s%d",
491 rootdir, ODIR, vnode);
492 code = mkdir(linkname, 0777);
493 if ((code < 0) && (errno != EEXIST)) {
494 fprintf(stderr,
495 "Error creating directory %s code=%d;%d\n",
496 linkname, code, errno);
499 /* Link the parentdir to it - now parentdir exists */
500 afs_snprintf(linkname, sizeof linkname, "%s%d/", ODIR,
501 vnode);
502 code = symlink(linkname, parentdir);
503 if (code) {
504 fprintf(stderr,
505 "Error creating symlink %s -> %s code=%d;%d\n",
506 parentdir, linkname, code, errno);
511 if (vn.type == 2) {
512 /*ITSADIR*/
513 /* We read the directory entries. If the entry is a
514 * directory, the subdir is created and the root dir
515 * will contain a link to it. If its a file, we only
516 * create a symlink in the dir to the file name.
518 char *buffer;
519 unsigned short j;
520 afs_int32 this_vn;
521 char *this_name;
523 struct DirEntry {
524 char flag;
525 char length;
526 unsigned short next;
527 struct MKFid {
528 afs_int32 vnode;
529 afs_int32 vunique;
530 } fid;
531 char name[20];
534 struct Pageheader {
535 unsigned short pgcount;
536 unsigned short tag;
537 char freecount;
538 char freebitmap[8];
539 char padding[19];
542 struct DirHeader {
543 struct Pageheader header;
544 char alloMap[128];
545 unsigned short hashTable[128];
548 struct Page0 {
549 struct DirHeader header;
550 struct DirEntry entry[1];
551 } *page0;
554 buffer = NULL;
555 buffer = (char *)malloc(vn.dataSize);
557 readdata(buffer, vn.dataSize);
558 page0 = (struct Page0 *)buffer;
560 /* Step through each bucket in the hash table, i,
561 * and follow each element in the hash chain, j.
562 * This gives us each entry of the dir.
564 for (i = 0; i < 128; i++) {
565 for (j = ntohs(page0->header.hashTable[i]); j;
566 j = ntohs(page0->entry[j].next)) {
567 j -= 13;
568 this_vn = ntohl(page0->entry[j].fid.vnode);
569 this_name = page0->entry[j].name;
571 if ((strcmp(this_name, ".") == 0)
572 || (strcmp(this_name, "..") == 0))
573 continue; /* Skip these */
575 /* For a directory entry, create it. Then create the
576 * link (from the rootdir) to this directory.
578 if (this_vn & 1) {
579 /*ADIRENTRY*/
580 /* dirname is the directory to create.
581 * vflink is what will link to it.
583 afs_snprintf(dirname, sizeof dirname, "%s" OS_DIRSEP "%s",
584 parentdir, this_name);
585 afs_snprintf(vflink, sizeof vflink, "%s" OS_DIRSEP "%s%d",
586 rootdir, ADIR, this_vn);
588 /* The link and directory may already exist */
589 len = readlink(vflink, linkname, MAXNAMELEN);
590 if (len < 0) {
591 /* Doesn't already exist - so create the directory.
592 * umask will pare the mode bits down.
594 code = mkdir(dirname, 0777);
595 if ((code < 0) && (errno != EEXIST)) {
596 fprintf(stderr,
597 "Error creating directory %s code=%d;%d\n",
598 dirname, code, errno);
600 } else {
601 /* Does already exist - so move the directory.
602 * It was created originally as orphaned.
604 linkname[len - 1] = '\0'; /* remove '/' at end */
605 afs_snprintf(lname, sizeof lname, "%s" OS_DIRSEP "%s",
606 rootdir, linkname);
607 code = rename(lname, dirname);
608 if (code) {
609 fprintf(stderr,
610 "Error renaming %s to %s code=%d;%d\n",
611 lname, dirname, code, errno);
615 /* Now create/update the link to the new/moved directory */
616 if (vn.vnode == 1)
617 afs_snprintf(dirname, sizeof dirname, "%s/",
618 this_name);
619 else
620 afs_snprintf(dirname, sizeof dirname,
621 "%s%d/%s/", ADIR, vn.vnode,
622 this_name);
623 unlink(vflink);
624 code = symlink(dirname, vflink);
625 if (code) {
626 fprintf(stderr,
627 "Error creating symlink %s -> %s code=%d;%d\n",
628 vflink, dirname, code, errno);
631 /*ADIRENTRY*/
632 /* For a file entry, we remember the name of the file
633 * by creating a link within the directory. Restoring
634 * the file will later remove the link.
636 else {
637 /*AFILEENTRY*/ afs_snprintf(vflink,
638 sizeof vflink,
639 "%s" OS_DIRSEP "%s%d", parentdir,
640 AFILE, this_vn);
642 code = symlink(this_name, vflink);
643 if ((code < 0) && (errno != EEXIST)) {
644 fprintf(stderr,
645 "Error creating symlink %s -> %s code=%d;%d\n",
646 vflink, page0->entry[j].name, code,
647 errno);
650 /*AFILEENTRY*/}
652 free(buffer);
654 /*ITSADIR*/
655 else if (vn.type == 1) {
656 /*ITSAFILE*/
657 /* A file vnode. So create it into the desired directory. A
658 * link should exist in the directory naming the file.
660 int fid;
661 int lfile;
662 afs_sfsize_t size, s;
663 ssize_t count;
665 /* Check if its vnode-file-link exists. If not,
666 * then the file will be an orphaned file.
668 lfile = 1;
669 afs_snprintf(filename, sizeof filename, "%s" OS_DIRSEP "%s%d", parentdir,
670 AFILE, vn.vnode);
671 len = readlink(filename, fname, MAXNAMELEN);
672 if (len < 0) {
673 afs_snprintf(filename, sizeof filename, "%s" OS_DIRSEP "%s%d",
674 rootdir, OFILE, vn.vnode);
675 lfile = 0; /* no longer a linked file; a direct path */
678 /* Create a mode for the file. Use the owner bits and
679 * duplicate them across group and other. The umask
680 * will remove what we don't want.
682 mode = (vn.modebits >> 6) & 0x7;
683 mode |= (mode << 6) | (mode << 3);
685 /* Write the file out */
686 fid = open(filename, (O_CREAT | O_WRONLY | O_TRUNC), mode);
687 if (fid < 0) {
688 fprintf(stderr, "Open %s: Errno = %d\n", filename, errno);
689 goto open_fail;
691 size = vn.dataSize;
692 while (size > 0) {
693 s = (afs_int32) ((size > BUFSIZE) ? BUFSIZE : size);
694 code = fread(buf, 1, s, dumpfile);
695 if (code != s) {
696 if (code < 0)
697 fprintf(stderr, "Code = %d; Errno = %d\n", code,
698 errno);
699 else {
700 char tmp[100];
701 (void)afs_snprintf(tmp, sizeof tmp,
702 "Read %llu bytes out of %llu",
703 (afs_uintmax_t) (vn.dataSize -
704 size),
705 (afs_uintmax_t) vn.dataSize);
706 fprintf(stderr, "%s\n", tmp);
708 break;
710 if (code > 0) {
711 count = write(fid, buf, code);
712 if (count < 0) {
713 fprintf(stderr, "Count = %ld, Errno = %d\n",
714 (long)count, errno);
715 break;
716 } else if (count != code) {
717 fprintf(stderr, "Wrote %llu bytes out of %llu\n",
718 (afs_uintmax_t) count,
719 (afs_uintmax_t) code);
720 break;
722 size -= code;
725 close(fid);
726 if (size != 0) {
727 fprintf(stderr, " File %s (%s) is incomplete\n",
728 filename, fname);
731 open_fail:
732 /* Remove the link to the file */
733 if (lfile) {
734 unlink(filename);
737 /*ITSAFILE*/
738 else if (vn.type == 3) {
739 /*ITSASYMLINK*/
740 /* A symlink vnode. So read it into the desired directory. This could
741 * also be a mount point. If the volume is being restored to AFS, this
742 * will become a mountpoint. If not, it becomes a symlink to no-where.
744 afs_int32 s;
746 /* Check if its vnode-file-link exists and create pathname
747 * of the symbolic link. If it doesn't exist,
748 * then the link will be an orphaned link.
750 afs_snprintf(linkname, sizeof linkname, "%s" OS_DIRSEP "%s%d", parentdir,
751 AFILE, vn.vnode);
752 len = readlink(linkname, fname, MAXNAMELEN - 1);
753 if (len < 0) {
754 afs_snprintf(filename, sizeof filename, "%s" OS_DIRSEP "%s%d",
755 rootdir, OFILE, vn.vnode);
756 } else {
757 fname[len] = '\0';
758 afs_snprintf(filename, sizeof filename, "%s" OS_DIRSEP "%s",
759 parentdir, fname);
762 /* Read the link in, delete it, and then create it */
763 readdata(buf, vn.dataSize);
765 /* If a mountpoint, change its link path to mountroot */
766 s = strlen(buf);
767 if (((buf[0] == '%') || (buf[0] == '#'))
768 && (buf[s - 1] == '.')) {
769 /* This is a symbolic link */
770 buf[s - 1] = 0; /* Remove prefix '.' */
771 strcpy(lname, &buf[1]); /* Remove postfix '#' or '%' */
772 strcpy(buf, mntroot);
773 strcat(buf, lname);
776 unlink(filename);
777 code = symlink(buf, filename);
778 if (code) {
779 fprintf(stderr,
780 "Error creating symlink %s -> %s code=%d;%d\n",
781 filename, buf, code, errno);
784 /* Remove the symbolic link */
785 unlink(linkname);
787 /*ITSASYMLINK*/
788 else {
789 fprintf(stderr, "Unknown Vnode block\n");
791 break;
793 default:
794 done = 1;
795 break;
798 if (vn.type == 0)
799 inc_dump = 1;
801 return ((afs_int32) tag);
804 static int
805 WorkerBee(struct cmd_syndesc *as, void *arock)
807 int code = 0, len;
808 afs_int32 type, count, vcount;
809 DIR *dirP, *dirQ;
810 struct dirent *dirE, *dirF;
811 char name[MAXNAMELEN];
812 char thisdir[MAXPATHLEN], *t;
813 struct DumpHeader dh; /* Defined in dump.h */
814 #if 0/*ndef HAVE_GETCWD*/ /* XXX enable when autoconf happens */
815 extern char *getwd();
816 #define getcwd(x,y) getwd(x)
817 #endif
819 if (as->parms[0].items) { /* -file <dumpfile> */
820 dumpfile = fopen(as->parms[0].items->data, "r");
821 if (!dumpfile) {
822 fprintf(stderr, "Cannot open '%s'. Code = %d\n",
823 as->parms[0].items->data, errno);
824 goto cleanup;
826 } else {
827 dumpfile = (FILE *) stdin; /* use stdin */
830 /* Read the dump header. From it we get the volume name */
831 type = ntohl(readvalue(1));
832 if (type != 1) {
833 fprintf(stderr, "Expected DumpHeader\n");
834 code = -1;
835 goto cleanup;
837 type = ReadDumpHeader(&dh);
839 /* Get the root directory we restore to */
840 if (as->parms[1].items) { /* -dir <rootdir> */
841 strcpy(rootdir, as->parms[1].items->data);
842 } else {
843 strcpy(rootdir, ".");
845 strcat(rootdir, "/");
847 /* Append the RW volume name to the root directory */
848 strcat(rootdir, dh.volumeName);
849 len = strlen(rootdir);
850 if (strcmp(".backup", rootdir + len - 7) == 0) {
851 rootdir[len - 7] = 0;
852 } else if (strcmp(".readonly", rootdir + len - 9) == 0) {
853 rootdir[len - 9] = 0;
856 /* Append the extension we asked for */
857 if (as->parms[2].items) {
858 strcat(rootdir, as->parms[2].items->data); /* -extension <ext> */
861 /* The mountpoint root is either specifid in -mountpoint
862 * or -dir or the current working dir.
864 if ((as->parms[3].items) || (as->parms[1].items)) { /* -mountpoint or -dir */
865 t = (char *)getcwd(thisdir, MAXPATHLEN); /* remember current dir */
866 if (!t) {
867 fprintf(stderr,
868 "Cannot get pathname of current working directory: %s\n",
869 thisdir);
870 code = -1;
871 goto cleanup;
873 /* Change to the mount point dir */
874 code =
875 chdir((as->parms[3].items ? as->parms[3].items->data : as->
876 parms[1].items->data));
877 if (code) {
878 fprintf(stderr, "Mount point directory not found: Error = %d\n",
879 errno);
880 goto cleanup;
882 t = (char *)getcwd(mntroot, MAXPATHLEN); /* get its full pathname */
883 if (!t) {
884 fprintf(stderr,
885 "Cannot determine pathname of mount point root directory: %s\n",
886 mntroot);
887 code = -1;
888 goto cleanup;
890 strcat(mntroot, "/"); /* append '/' to end of it */
891 code = chdir(thisdir); /* return to original working dir */
892 if (code) {
893 fprintf(stderr, "Cannot find working directory: Error = %d\n",
894 errno);
895 goto cleanup;
897 } else { /* use current directory */
898 t = (char *)getcwd(mntroot, MAXPATHLEN); /* get full pathname of current dir */
899 if (!t) {
900 fprintf(stderr,
901 "Cannot determine pathname of current working directory: %s\n",
902 mntroot);
903 code = -1;
904 goto cleanup;
907 strcat(mntroot, "/"); /* append '/' to end of it */
909 /* Set the umask for the restore */
910 if (as->parms[4].items) { /* -umask */
911 afs_int32 mask;
912 mask = strtol(as->parms[4].items->data, 0, 8);
913 fprintf(stderr, "Umask set to 0%03o\n", mask);
914 umask(mask);
917 fprintf(stderr, "Restoring volume dump of '%s' to directory '%s'.\n",
918 dh.volumeName, rootdir);
919 code = mkdir(rootdir, 0777);
920 if ((code < 0) && (errno != EEXIST)) {
921 fprintf(stderr, "Error creating directory %s code=%d;%d\n", rootdir,
922 code, errno);
925 for (count = 1; type == 2; count++) {
926 type = ReadVolumeHeader(count);
927 for (vcount = 1; type == 3; vcount++)
928 type = ReadVNode(vcount);
931 if (type != 4) {
932 fprintf(stderr, "Expected End-of-Dump\n");
933 code = -1;
934 goto cleanup;
937 cleanup:
938 /* For incremental restores, Follow each directory link and
939 * remove an "AFSFile" links.
941 if (inc_dump) {
942 fprintf(stderr, "An incremental dump.\n");
943 dirP = opendir(rootdir);
944 while (dirP && (dirE = readdir(dirP))) {
945 if (strncmp(dirE->d_name, ADIR, strlen(ADIR)) == 0) {
946 afs_snprintf(name, sizeof name, "%s" OS_DIRSEP "%s", rootdir,
947 dirE->d_name);
948 dirQ = opendir(name);
949 while (dirQ && (dirF = readdir(dirQ))) {
950 if (strncmp(dirF->d_name, AFILE, strlen(AFILE)) == 0) {
951 afs_snprintf(name, sizeof name, "%s" OS_DIRSEP "%s/%s", rootdir,
952 dirE->d_name, dirF->d_name);
953 unlink(name);
956 closedir(dirQ);
957 } else if (strncmp(dirE->d_name, AFILE, strlen(AFILE)) == 0) {
958 afs_snprintf(name, sizeof name, "%s" OS_DIRSEP "%s", rootdir,
959 dirE->d_name);
960 unlink(name);
963 closedir(dirP);
966 /* Now go through and remove all the directory links */
967 dirP = opendir(rootdir);
968 while (dirP && (dirE = readdir(dirP))) {
969 if (strncmp(dirE->d_name, ADIR, strlen(ADIR)) == 0) {
970 afs_snprintf(name, sizeof name, "%s" OS_DIRSEP "%s", rootdir, dirE->d_name);
971 unlink(name);
974 closedir(dirP);
976 return (code);
980 main(int argc, char **argv)
982 struct cmd_syndesc *ts;
984 setlinebuf(stdout);
986 ts = cmd_CreateSyntax(NULL, WorkerBee, NULL, "vldb check");
987 cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_OPTIONAL, "dump file");
988 cmd_AddParm(ts, "-dir", CMD_SINGLE, CMD_OPTIONAL, "restore dir");
989 cmd_AddParm(ts, "-extension", CMD_SINGLE, CMD_OPTIONAL, "name extension");
990 cmd_AddParm(ts, "-mountpoint", CMD_SINGLE, CMD_OPTIONAL,
991 "mount point root");
992 cmd_AddParm(ts, "-umask", CMD_SINGLE, CMD_OPTIONAL, "mode mask");
994 return cmd_Dispatch(argc, argv);