|
|
1.1 root 1: #ifndef lint
2: static char sccsid[] = "@(#)restore.c 3.17 (Berkeley) 83/08/11";
3: #endif
4:
5: /* Copyright (c) 1983 Regents of the University of California */
6:
7: #include "restore.h"
8:
9: /*
10: * This implements the 't' option.
11: * List entries on the tape.
12: */
13: long
14: listfile(name, ino, type)
15: char *name;
16: ino_t ino;
17: int type;
18: {
19: long descend = hflag ? GOOD : FAIL;
20:
21: if (BIT(ino, dumpmap) == 0) {
22: return (descend);
23: }
24: vprintf(stdout, "%s", type == LEAF ? "leaf" : "dir ");
25: fprintf(stdout, "%10d\t%s\n", ino, name);
26: return (descend);
27: }
28:
29: /*
30: * This implements the 'x' option.
31: * Request that new entries be extracted.
32: */
33: long
34: addfile(name, ino, type)
35: char *name;
36: ino_t ino;
37: int type;
38: {
39: register struct entry *ep;
40: long descend = hflag ? GOOD : FAIL;
41: char buf[100];
42:
43: if (BIT(ino, dumpmap) == 0) {
44: vprintf(stdout, "%s: not on the tape\n", name);
45: return (descend);
46: }
47: if (!mflag) {
48: (void) sprintf(buf, "./%u", ino);
49: name = buf;
50: if (type == NODE) {
51: (void) genliteraldir(name, ino);
52: return (descend);
53: }
54: }
55: ep = lookupino(ino);
56: if (ep != NIL) {
57: if (strcmp(name, myname(ep)) == 0) {
58: ep->e_flags |= NEW;
59: return (descend);
60: }
61: type |= LINK;
62: }
63: ep = addentry(name, ino, type);
64: if (type == NODE)
65: newnode(ep);
66: ep->e_flags |= NEW;
67: return (descend);
68: }
69:
70: /*
71: * This is used by the 'i' option to undo previous requests made by addfile.
72: * Delete entries from the request queue.
73: */
74: /* ARGSUSED */
75: long
76: deletefile(name, ino, type)
77: char *name;
78: ino_t ino;
79: int type;
80: {
81: long descend = hflag ? GOOD : FAIL;
82: struct entry *ep;
83:
84: if (BIT(ino, dumpmap) == 0) {
85: return (descend);
86: }
87: ep = lookupino(ino);
88: if (ep != NIL)
89: ep->e_flags &= ~NEW;
90: return (descend);
91: }
92:
93: /*
94: * The following four routines implement the incremental
95: * restore algorithm. The first removes old entries, the second
96: * does renames and calculates the extraction list, the third
97: * cleans up link names missed by the first two, and the final
98: * one deletes old directories.
99: *
100: * Directories cannot be immediately deleted, as they may have
101: * other files in them which need to be moved out first. As
102: * directories to be deleted are found, they are put on the
103: * following deletion list. After all deletions and renames
104: * are done, this list is actually deleted.
105: */
106: static struct entry *removelist;
107:
108: /*
109: * Remove unneeded leaves from the old tree.
110: * Remove directories from the lookup chains.
111: */
112: removeoldleaves()
113: {
114: register struct entry *ep;
115: register ino_t i;
116:
117: vprintf(stdout, "Mark entries to be removed.\n");
118: for (i = ROOTINO + 1; i < maxino; i++) {
119: ep = lookupino(i);
120: if (ep == NIL)
121: continue;
122: if (BIT(i, clrimap))
123: continue;
124: for ( ; ep != NIL; ep = ep->e_links) {
125: dprintf(stdout, "%s: REMOVE\n", myname(ep));
126: if (ep->e_type == LEAF) {
127: removeleaf(ep);
128: freeentry(ep);
129: } else {
130: mktempname(ep);
131: deleteino(ep->e_ino);
132: ep->e_next = removelist;
133: removelist = ep;
134: }
135: }
136: }
137: }
138:
139: /*
140: * For each directory entry on the incremental tape, determine which
141: * category it falls into as follows:
142: * KEEP - entries that are to be left alone.
143: * NEW - new entries to be added.
144: * EXTRACT - files that must be updated with new contents.
145: * LINK - new links to be added.
146: * Renames are done at the same time.
147: */
148: long
149: nodeupdates(name, ino, type)
150: char *name;
151: ino_t ino;
152: int type;
153: {
154: register struct entry *ep, *np, *ip;
155: long descend = GOOD;
156: int lookuptype = 0;
157: int key = 0;
158: /* key values */
159: # define ONTAPE 0x1 /* inode is on the tape */
160: # define INOFND 0x2 /* inode already exists */
161: # define NAMEFND 0x4 /* name already exists */
162: # define MODECHG 0x8 /* mode of inode changed */
163: extern char *keyval();
164:
165: /*
166: * This routine is called once for each element in the
167: * directory hierarchy, with a full path name.
168: * The "type" value is incorrectly specified as LEAF for
169: * directories that are not on the dump tape.
170: *
171: * Check to see if the file is on the tape.
172: */
173: if (BIT(ino, dumpmap))
174: key |= ONTAPE;
175: /*
176: * Check to see if the name exists, and if the name is a link.
177: */
178: np = lookupname(name);
179: if (np != NIL) {
180: key |= NAMEFND;
181: ip = lookupino(np->e_ino);
182: if (ip == NULL)
183: panic("corrupted symbol table\n");
184: if (ip != np)
185: lookuptype = LINK;
186: }
187: /*
188: * Check to see if the inode exists, and if one of its links
189: * corresponds to the name (if one was found).
190: */
191: ip = lookupino(ino);
192: if (ip != NIL) {
193: key |= INOFND;
194: for (ep = ip->e_links; ep != NIL; ep = ep->e_links) {
195: if (ep == np) {
196: ip = ep;
197: break;
198: }
199: }
200: }
201: /*
202: * If both a name and an inode are found, but they do not
203: * correspond to the same file, then both the inode that has
204: * been found and the inode corresponding to the name that
205: * has been found need to be renamed. The current pathname
206: * is the new name for the inode that has been found. Since
207: * all files to be deleted have already been removed, the
208: * named file is either a now unneeded link, or it must live
209: * under a new name in this dump level. If it is a link, it
210: * can be removed. If it is not a link, it is given a
211: * temporary name in anticipation that it will be renamed
212: * when it is later found by inode number.
213: */
214: if (((key & (INOFND|NAMEFND)) == (INOFND|NAMEFND)) && ip != np) {
215: if (lookuptype == LINK) {
216: removeleaf(np);
217: freeentry(np);
218: } else {
219: dprintf(stdout, "name/inode conflict, mktempname %s\n",
220: myname(np));
221: mktempname(np);
222: }
223: np = NIL;
224: key &= ~NAMEFND;
225: }
226: if ((key & ONTAPE) &&
227: (((key & INOFND) && ip->e_type != type) ||
228: ((key & NAMEFND) && np->e_type != type)))
229: key |= MODECHG;
230:
231: /*
232: * Decide on the disposition of the file based on its flags.
233: * Note that we have already handled the case in which
234: * a name and inode are found that correspond to different files.
235: * Thus if both NAMEFND and INOFND are set then ip == np.
236: */
237: switch (key) {
238:
239: /*
240: * A previously existing file has been found.
241: * Mark it as KEEP so that other links to the inode can be
242: * detected, and so that it will not be reclaimed by the search
243: * for unreferenced names.
244: */
245: case INOFND|NAMEFND:
246: ip->e_flags |= KEEP;
247: dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
248: flagvalues(ip));
249: break;
250:
251: /*
252: * A file on the tape has a name which is the same as a name
253: * corresponding to a different file in the previous dump.
254: * Since all files to be deleted have already been removed,
255: * this file is either a now unneeded link, or it must live
256: * under a new name in this dump level. If it is a link, it
257: * can simply be removed. If it is not a link, it is given a
258: * temporary name in anticipation that it will be renamed
259: * when it is later found by inode number (see INOFND case
260: * below). The entry is then treated as a new file.
261: */
262: case ONTAPE|NAMEFND:
263: case ONTAPE|NAMEFND|MODECHG:
264: if (lookuptype == LINK) {
265: removeleaf(np);
266: freeentry(np);
267: } else {
268: mktempname(np);
269: }
270: /* fall through */
271:
272: /*
273: * A previously non-existent file.
274: * Add it to the file system, and request its extraction.
275: * If it is a directory, create it immediately.
276: * (Since the name is unused there can be no conflict)
277: */
278: case ONTAPE:
279: ep = addentry(name, ino, type);
280: if (type == NODE)
281: newnode(ep);
282: ep->e_flags |= NEW|KEEP;
283: dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
284: flagvalues(ep));
285: break;
286:
287: /*
288: * A file with the same inode number, but a different
289: * name has been found. If the other name has not already
290: * been found (indicated by the KEEP flag, see above) then
291: * this must be a new name for the file, and it is renamed.
292: * If the other name has been found then this must be a
293: * link to the file. Hard links to directories are not
294: * permitted, and are either deleted or converted to
295: * symbolic links. Finally, if the file is on the tape,
296: * a request is made to extract it.
297: */
298: case ONTAPE|INOFND:
299: if (type == LEAF && (ip->e_flags & KEEP) == 0)
300: ip->e_flags |= EXTRACT;
301: /* fall through */
302: case INOFND:
303: if ((ip->e_flags & KEEP) == 0) {
304: renameit(myname(ip), name);
305: moveentry(ip, name);
306: ip->e_flags |= KEEP;
307: dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
308: flagvalues(ip));
309: break;
310: }
311: if (ip->e_type == NODE) {
312: descend = FAIL;
313: fprintf(stderr,
314: "deleted hard link %s to directory %s\n",
315: name, myname(ip));
316: break;
317: }
318: ep = addentry(name, ino, type|LINK);
319: ep->e_flags |= NEW;
320: dprintf(stdout, "[%s] %s: %s|LINK\n", keyval(key), name,
321: flagvalues(ep));
322: break;
323:
324: /*
325: * A previously known file which is to be updated.
326: */
327: case ONTAPE|INOFND|NAMEFND:
328: if (type == LEAF && lookuptype != LINK)
329: np->e_flags |= EXTRACT;
330: np->e_flags |= KEEP;
331: dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
332: flagvalues(np));
333: break;
334:
335: /*
336: * An inode is being reused in a completely different way.
337: * Normally an extract can simply do an "unlink" followed
338: * by a "creat". Here we must do effectively the same
339: * thing. The complications arise because we cannot really
340: * delete a directory since it may still contain files
341: * that we need to rename, so we delete it from the symbol
342: * table, and put it on the list to be deleted eventually.
343: * Conversely if a directory is to be created, it must be
344: * done immediately, rather than waiting until the
345: * extraction phase.
346: */
347: case ONTAPE|INOFND|MODECHG:
348: case ONTAPE|INOFND|NAMEFND|MODECHG:
349: if (ip->e_flags & KEEP) {
350: badentry(ip, "cannot KEEP and change modes");
351: break;
352: }
353: if (ip->e_type == LEAF) {
354: /* changing from leaf to node */
355: removeleaf(ip);
356: freeentry(ip);
357: ip = addentry(name, ino, type);
358: newnode(ip);
359: } else {
360: /* changing from node to leaf */
361: if ((ip->e_flags & TMPNAME) == 0)
362: mktempname(ip);
363: deleteino(ip->e_ino);
364: ip->e_next = removelist;
365: removelist = ip;
366: ip = addentry(name, ino, type);
367: }
368: ip->e_flags |= NEW|KEEP;
369: dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
370: flagvalues(ip));
371: break;
372:
373: /*
374: * A hard link to a diirectory that has been removed.
375: * Ignore it.
376: */
377: case NAMEFND:
378: dprintf(stdout, "[%s] %s: Extraneous name\n", keyval(key),
379: name);
380: descend = FAIL;
381: break;
382:
383: /*
384: * If any of these arise, something is grievously wrong with
385: * the current state of the symbol table.
386: */
387: case INOFND|NAMEFND|MODECHG:
388: case NAMEFND|MODECHG:
389: case INOFND|MODECHG:
390: case NIL:
391: panic("[%s] %s: inconsistent state\n", keyval(key), name);
392: break;
393:
394: /*
395: * These states "cannot" arise for any state of the symbol table.
396: */
397: case ONTAPE|MODECHG:
398: case MODECHG:
399: default:
400: panic("[%s] %s: impossible state\n", keyval(key), name);
401: break;
402: }
403: return (descend);
404: }
405:
406: /*
407: * Calculate the active flags in a key.
408: */
409: char *
410: keyval(key)
411: int key;
412: {
413: static char keybuf[32];
414:
415: (void) strcpy(keybuf, "|NIL");
416: keybuf[0] = '\0';
417: if (key & ONTAPE)
418: (void) strcat(keybuf, "|ONTAPE");
419: if (key & INOFND)
420: (void) strcat(keybuf, "|INOFND");
421: if (key & NAMEFND)
422: (void) strcat(keybuf, "|NAMEFND");
423: if (key & MODECHG)
424: (void) strcat(keybuf, "|MODECHG");
425: return (&keybuf[1]);
426: }
427:
428: /*
429: * Find unreferenced link names.
430: */
431: findunreflinks()
432: {
433: register struct entry *ep, *np;
434: register ino_t i;
435:
436: vprintf(stdout, "Find unreferenced names.\n");
437: for (i = ROOTINO; i < maxino; i++) {
438: ep = lookupino(i);
439: if (ep == NIL || ep->e_type == LEAF || BIT(i, dumpmap) == 0)
440: continue;
441: for (np = ep->e_entries; np != NIL; np = np->e_sibling) {
442: if (np->e_flags == 0) {
443: dprintf(stdout,
444: "%s: remove unreferenced name\n",
445: myname(np));
446: removeleaf(np);
447: freeentry(np);
448: }
449: }
450: }
451: /*
452: * Any leaves remaining in removed directories is unreferenced.
453: */
454: for (ep = removelist; ep != NIL; ep = ep->e_next) {
455: for (np = ep->e_entries; np != NIL; np = np->e_sibling) {
456: if (np->e_type == LEAF) {
457: if (np->e_flags != 0)
458: badentry(np, "unreferenced with flags");
459: dprintf(stdout,
460: "%s: remove unreferenced name\n",
461: myname(np));
462: removeleaf(np);
463: freeentry(np);
464: }
465: }
466: }
467: }
468:
469: /*
470: * Remove old nodes (directories).
471: * Note that this routine runs in O(N*D) where:
472: * N is the number of directory entries to be removed.
473: * D is the maximum depth of the tree.
474: * If N == D this can be quite slow. If the list were
475: * topologically sorted, the deletion could be done in
476: * time O(N).
477: */
478: removeoldnodes()
479: {
480: register struct entry *ep, **prev;
481: long change;
482:
483: vprintf(stdout, "Remove old nodes (directories).\n");
484: do {
485: change = 0;
486: prev = &removelist;
487: for (ep = removelist; ep != NIL; ep = *prev) {
488: if (ep->e_entries != NIL) {
489: prev = &ep->e_next;
490: continue;
491: }
492: *prev = ep->e_next;
493: removenode(ep);
494: freeentry(ep);
495: change++;
496: }
497: } while (change);
498: for (ep = removelist; ep != NIL; ep = ep->e_next)
499: badentry(ep, "cannot remove, non-empty");
500: }
501:
502: /*
503: * This is the routine used to extract files for the 'r' command.
504: * Extract new leaves.
505: */
506: createleaves(symtabfile)
507: char *symtabfile;
508: {
509: register struct entry *ep;
510: ino_t first;
511: long curvol;
512:
513: if (command == 'R') {
514: vprintf(stdout, "Continue extraction of new leaves\n");
515: } else {
516: vprintf(stdout, "Extract new leaves.\n");
517: dumpsymtable(symtabfile, volno);
518: }
519: first = lowerbnd(ROOTINO);
520: curvol = volno;
521: while (curfile.ino < maxino) {
522: first = lowerbnd(first);
523: /*
524: * If the next available file is not the one which we
525: * expect then we have missed one or more files. Since
526: * we do not request files that were not on the tape,
527: * the lost files must have been due to a tape read error,
528: * or a file that was removed while the dump was in progress.
529: */
530: while (first < curfile.ino) {
531: ep = lookupino(first);
532: if (ep == NIL)
533: panic("%d: bad first\n", first);
534: fprintf(stderr, "%s: not found on tape\n", myname(ep));
535: ep->e_flags &= ~(NEW|EXTRACT);
536: first = lowerbnd(first);
537: }
538: /*
539: * If we find files on the tape that have no corresponding
540: * directory entries, then we must have found a file that
541: * was created while the dump was in progress. Since we have
542: * no name for it, we discard it knowing that it will be
543: * on the next incremental tape.
544: */
545: if (first != curfile.ino) {
546: fprintf(stderr, "expected next file %d, got %d\n",
547: first, curfile.ino);
548: skipfile();
549: goto next;
550: }
551: ep = lookupino(curfile.ino);
552: if (ep == NIL)
553: panic("unknown file on tape\n");
554: if ((ep->e_flags & (NEW|EXTRACT)) == 0)
555: badentry(ep, "unexpected file on tape");
556: /*
557: * If the file is to be extracted, then the old file must
558: * be removed since its type may change from one leaf type
559: * to another (eg "file" to "character special").
560: */
561: if ((ep->e_flags & EXTRACT) != 0) {
562: removeleaf(ep);
563: ep->e_flags &= ~REMOVED;
564: }
565: (void) extractfile(myname(ep));
566: ep->e_flags &= ~(NEW|EXTRACT);
567: /*
568: * We checkpoint the restore after every tape reel, so
569: * as to simplify the amount of work re quired by the
570: * 'R' command.
571: */
572: next:
573: if (curvol != volno) {
574: dumpsymtable(symtabfile, volno);
575: skipmaps();
576: curvol = volno;
577: }
578: }
579: }
580:
581: /*
582: * This is the routine used to extract files for the 'x' and 'i' commands.
583: * Efficiently extract a subset of the files on a tape.
584: */
585: createfiles()
586: {
587: register ino_t first, next, last;
588: register struct entry *ep;
589: long curvol;
590:
591: vprintf(stdout, "Extract requested files\n");
592: curfile.action = SKIP;
593: getvol((long)1);
594: skipmaps();
595: skipdirs();
596: first = lowerbnd(ROOTINO);
597: last = upperbnd(maxino - 1);
598: for (;;) {
599: first = lowerbnd(first);
600: last = upperbnd(last);
601: /*
602: * Check to see if any files remain to be extracted
603: */
604: if (first > last)
605: return;
606: /*
607: * Reject any volumes with inodes greater
608: * than the last one needed
609: */
610: while (curfile.ino > last) {
611: curfile.action = SKIP;
612: getvol((long)0);
613: skipmaps();
614: skipdirs();
615: }
616: /*
617: * Decide on the next inode needed.
618: * Skip across the inodes until it is found
619: * or an out of order volume change is encountered
620: */
621: next = lowerbnd(curfile.ino);
622: do {
623: curvol = volno;
624: while (next > curfile.ino && volno == curvol)
625: skipfile();
626: skipmaps();
627: skipdirs();
628: } while (volno == curvol + 1);
629: /*
630: * If volume change out of order occurred the
631: * current state must be recalculated
632: */
633: if (volno != curvol)
634: continue;
635: /*
636: * If the current inode is greater than the one we were
637: * looking for then we missed the one we were looking for.
638: * Since we only attempt to extract files listed in the
639: * dump map, the lost files must have been due to a tape
640: * read error, or a file that was removed while the dump
641: * was in progress. Thus we report all requested files
642: * between the one we were looking for, and the one we
643: * found as missing, and delete their request flags.
644: */
645: while (next < curfile.ino) {
646: ep = lookupino(next);
647: if (ep == NIL)
648: panic("corrupted symbol table\n");
649: fprintf(stderr, "%s: not found on tape\n", myname(ep));
650: ep->e_flags &= ~NEW;
651: next = lowerbnd(next);
652: }
653: /*
654: * The current inode is the one that we are looking for,
655: * so extract it per its requested name.
656: */
657: if (next == curfile.ino && next <= last) {
658: ep = lookupino(next);
659: if (ep == NIL)
660: panic("corrupted symbol table\n");
661: (void) extractfile(myname(ep));
662: ep->e_flags &= ~NEW;
663: }
664: }
665: }
666:
667: /*
668: * Add links.
669: */
670: createlinks()
671: {
672: register struct entry *np, *ep;
673: register ino_t i;
674: char name[BUFSIZ];
675:
676: vprintf(stdout, "Add links\n");
677: for (i = ROOTINO; i < maxino; i++) {
678: ep = lookupino(i);
679: if (ep == NIL)
680: continue;
681: for (np = ep->e_links; np != NIL; np = np->e_links) {
682: if ((np->e_flags & NEW) == 0)
683: continue;
684: (void) strcpy(name, myname(ep));
685: if (ep->e_type == NODE) {
686: linkit(name, myname(np), SYMLINK);
687: } else {
688: linkit(name, myname(np), HARDLINK);
689: }
690: np->e_flags &= ~NEW;
691: }
692: }
693: }
694:
695: /*
696: * Check the symbol table.
697: * We do this to insure that all the requested work was done, and
698: * that no temporary names remain.
699: */
700: checkrestore()
701: {
702: register struct entry *ep;
703: register ino_t i;
704:
705: vprintf(stdout, "Check the symbol table.\n");
706: for (i = ROOTINO; i < maxino; i++) {
707: for (ep= lookupino(i); ep != NIL; ep = ep->e_links) {
708: ep->e_flags &= ~KEEP;
709: if (ep->e_type == NODE)
710: ep->e_flags &= ~NEW;
711: if (ep->e_flags != NULL)
712: badentry(ep, "incomplete operations");
713: }
714: }
715: }
716:
717: /*
718: * Compare with the directory structure on the tape
719: * A paranoid check that things are as they should be.
720: */
721: long
722: verifyfile(name, ino, type)
723: char *name;
724: ino_t ino;
725: int type;
726: {
727: struct entry *np, *ep;
728: long descend = GOOD;
729:
730: ep = lookupname(name);
731: if (ep == NIL) {
732: fprintf(stderr, "Warning: missing name %s\n", name);
733: return (FAIL);
734: }
735: np = lookupino(ino);
736: if (np != ep)
737: descend = FAIL;
738: for ( ; np != NIL; np = np->e_links)
739: if (np == ep)
740: break;
741: if (np == NIL)
742: panic("missing inumber %d\n", ino);
743: if (ep->e_type == LEAF && type != LEAF)
744: badentry(ep, "type should be LEAF");
745: return (descend);
746: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.