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