restore.c revision 1.6 1 /* $NetBSD: restore.c,v 1.6 1995/03/18 14:59:51 cgd 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.6 1995/03/18 14:59:51 cgd 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 register 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) sprintf(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 register struct entry *ep, *nextep;
169 register ino_t i, mydirino;
170
171 vprintf(stdout, "Mark entries to be removed.\n");
172 if (ep = lookupino(WINO)) {
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 register 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 removeleaf(ip);
438 freeentry(ip);
439 ip = addentry(name, ino, type);
440 newnode(ip);
441 } else {
442 /* changing from node to leaf */
443 if ((ip->e_flags & TMPNAME) == 0)
444 mktempname(ip);
445 deleteino(ip->e_ino);
446 ip->e_next = removelist;
447 removelist = ip;
448 ip = addentry(name, ino, type);
449 }
450 ip->e_flags |= NEW|KEEP;
451 dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
452 flagvalues(ip));
453 break;
454
455 /*
456 * A hard link to a diirectory that has been removed.
457 * Ignore it.
458 */
459 case NAMEFND:
460 dprintf(stdout, "[%s] %s: Extraneous name\n", keyval(key),
461 name);
462 descend = FAIL;
463 break;
464
465 /*
466 * If we find a directory entry for a file that is not on
467 * the tape, then we must have found a file that was created
468 * while the dump was in progress. Since we have no contents
469 * for it, we discard the name knowing that it will be on the
470 * next incremental tape.
471 */
472 case NULL:
473 fprintf(stderr, "%s: (inode %d) not found on tape\n",
474 name, ino);
475 break;
476
477 /*
478 * If any of these arise, something is grievously wrong with
479 * the current state of the symbol table.
480 */
481 case INOFND|NAMEFND|MODECHG:
482 case NAMEFND|MODECHG:
483 case INOFND|MODECHG:
484 fprintf(stderr, "[%s] %s: inconsistent state\n", keyval(key),
485 name);
486 break;
487
488 /*
489 * These states "cannot" arise for any state of the symbol table.
490 */
491 case ONTAPE|MODECHG:
492 case MODECHG:
493 default:
494 panic("[%s] %s: impossible state\n", keyval(key), name);
495 break;
496 }
497 return (descend);
498 }
499
500 /*
501 * Calculate the active flags in a key.
502 */
503 static char *
504 keyval(key)
505 int key;
506 {
507 static char keybuf[32];
508
509 (void) strcpy(keybuf, "|NIL");
510 keybuf[0] = '\0';
511 if (key & ONTAPE)
512 (void) strcat(keybuf, "|ONTAPE");
513 if (key & INOFND)
514 (void) strcat(keybuf, "|INOFND");
515 if (key & NAMEFND)
516 (void) strcat(keybuf, "|NAMEFND");
517 if (key & MODECHG)
518 (void) strcat(keybuf, "|MODECHG");
519 return (&keybuf[1]);
520 }
521
522 /*
523 * Find unreferenced link names.
524 */
525 void
526 findunreflinks()
527 {
528 register struct entry *ep, *np;
529 register ino_t i;
530
531 vprintf(stdout, "Find unreferenced names.\n");
532 for (i = ROOTINO; i < maxino; i++) {
533 ep = lookupino(i);
534 if (ep == NULL || ep->e_type == LEAF || TSTINO(i, dumpmap) == 0)
535 continue;
536 for (np = ep->e_entries; np != NULL; np = np->e_sibling) {
537 if (np->e_flags == 0) {
538 dprintf(stdout,
539 "%s: remove unreferenced name\n",
540 myname(np));
541 removeleaf(np);
542 freeentry(np);
543 }
544 }
545 }
546 /*
547 * Any leaves remaining in removed directories is unreferenced.
548 */
549 for (ep = removelist; ep != NULL; ep = ep->e_next) {
550 for (np = ep->e_entries; np != NULL; np = np->e_sibling) {
551 if (np->e_type == LEAF) {
552 if (np->e_flags != 0)
553 badentry(np, "unreferenced with flags");
554 dprintf(stdout,
555 "%s: remove unreferenced name\n",
556 myname(np));
557 removeleaf(np);
558 freeentry(np);
559 }
560 }
561 }
562 }
563
564 /*
565 * Remove old nodes (directories).
566 * Note that this routine runs in O(N*D) where:
567 * N is the number of directory entries to be removed.
568 * D is the maximum depth of the tree.
569 * If N == D this can be quite slow. If the list were
570 * topologically sorted, the deletion could be done in
571 * time O(N).
572 */
573 void
574 removeoldnodes()
575 {
576 register struct entry *ep, **prev;
577 long change;
578
579 vprintf(stdout, "Remove old nodes (directories).\n");
580 do {
581 change = 0;
582 prev = &removelist;
583 for (ep = removelist; ep != NULL; ep = *prev) {
584 if (ep->e_entries != NULL) {
585 prev = &ep->e_next;
586 continue;
587 }
588 *prev = ep->e_next;
589 removenode(ep);
590 freeentry(ep);
591 change++;
592 }
593 } while (change);
594 for (ep = removelist; ep != NULL; ep = ep->e_next)
595 badentry(ep, "cannot remove, non-empty");
596 }
597
598 /*
599 * This is the routine used to extract files for the 'r' command.
600 * Extract new leaves.
601 */
602 void
603 createleaves(symtabfile)
604 char *symtabfile;
605 {
606 register struct entry *ep;
607 ino_t first;
608 long curvol;
609
610 if (command == 'R') {
611 vprintf(stdout, "Continue extraction of new leaves\n");
612 } else {
613 vprintf(stdout, "Extract new leaves.\n");
614 dumpsymtable(symtabfile, volno);
615 }
616 first = lowerbnd(ROOTINO);
617 curvol = volno;
618 while (curfile.ino < maxino) {
619 first = lowerbnd(first);
620 /*
621 * If the next available file is not the one which we
622 * expect then we have missed one or more files. Since
623 * we do not request files that were not on the tape,
624 * the lost files must have been due to a tape read error,
625 * or a file that was removed while the dump was in progress.
626 */
627 while (first < curfile.ino) {
628 ep = lookupino(first);
629 if (ep == NULL)
630 panic("%d: bad first\n", first);
631 fprintf(stderr, "%s: not found on tape\n", myname(ep));
632 ep->e_flags &= ~(NEW|EXTRACT);
633 first = lowerbnd(first);
634 }
635 /*
636 * If we find files on the tape that have no corresponding
637 * directory entries, then we must have found a file that
638 * was created while the dump was in progress. Since we have
639 * no name for it, we discard it knowing that it will be
640 * on the next incremental tape.
641 */
642 if (first != curfile.ino) {
643 fprintf(stderr, "expected next file %d, got %d\n",
644 first, curfile.ino);
645 skipfile();
646 goto next;
647 }
648 ep = lookupino(curfile.ino);
649 if (ep == NULL)
650 panic("unknown file on tape\n");
651 if ((ep->e_flags & (NEW|EXTRACT)) == 0)
652 badentry(ep, "unexpected file on tape");
653 /*
654 * If the file is to be extracted, then the old file must
655 * be removed since its type may change from one leaf type
656 * to another (eg "file" to "character special").
657 */
658 if ((ep->e_flags & EXTRACT) != 0) {
659 removeleaf(ep);
660 ep->e_flags &= ~REMOVED;
661 }
662 (void) extractfile(myname(ep));
663 ep->e_flags &= ~(NEW|EXTRACT);
664 /*
665 * We checkpoint the restore after every tape reel, so
666 * as to simplify the amount of work re quired by the
667 * 'R' command.
668 */
669 next:
670 if (curvol != volno) {
671 dumpsymtable(symtabfile, volno);
672 skipmaps();
673 curvol = volno;
674 }
675 }
676 }
677
678 /*
679 * This is the routine used to extract files for the 'x' and 'i' commands.
680 * Efficiently extract a subset of the files on a tape.
681 */
682 void
683 createfiles()
684 {
685 register ino_t first, next, last;
686 register struct entry *ep;
687 long curvol;
688
689 vprintf(stdout, "Extract requested files\n");
690 curfile.action = SKIP;
691 getvol((long)1);
692 skipmaps();
693 skipdirs();
694 first = lowerbnd(ROOTINO);
695 last = upperbnd(maxino - 1);
696 for (;;) {
697 first = lowerbnd(first);
698 last = upperbnd(last);
699 /*
700 * Check to see if any files remain to be extracted
701 */
702 if (first > last)
703 return;
704 /*
705 * Reject any volumes with inodes greater
706 * than the last one needed
707 */
708 while (curfile.ino > last) {
709 curfile.action = SKIP;
710 getvol((long)0);
711 skipmaps();
712 skipdirs();
713 }
714 /*
715 * Decide on the next inode needed.
716 * Skip across the inodes until it is found
717 * or an out of order volume change is encountered
718 */
719 next = lowerbnd(curfile.ino);
720 do {
721 curvol = volno;
722 while (next > curfile.ino && volno == curvol)
723 skipfile();
724 skipmaps();
725 skipdirs();
726 } while (volno == curvol + 1);
727 /*
728 * If volume change out of order occurred the
729 * current state must be recalculated
730 */
731 if (volno != curvol)
732 continue;
733 /*
734 * If the current inode is greater than the one we were
735 * looking for then we missed the one we were looking for.
736 * Since we only attempt to extract files listed in the
737 * dump map, the lost files must have been due to a tape
738 * read error, or a file that was removed while the dump
739 * was in progress. Thus we report all requested files
740 * between the one we were looking for, and the one we
741 * found as missing, and delete their request flags.
742 */
743 while (next < curfile.ino) {
744 ep = lookupino(next);
745 if (ep == NULL)
746 panic("corrupted symbol table\n");
747 fprintf(stderr, "%s: not found on tape\n", myname(ep));
748 ep->e_flags &= ~NEW;
749 next = lowerbnd(next);
750 }
751 /*
752 * The current inode is the one that we are looking for,
753 * so extract it per its requested name.
754 */
755 if (next == curfile.ino && next <= last) {
756 ep = lookupino(next);
757 if (ep == NULL)
758 panic("corrupted symbol table\n");
759 (void) extractfile(myname(ep));
760 ep->e_flags &= ~NEW;
761 if (volno != curvol)
762 skipmaps();
763 }
764 }
765 }
766
767 /*
768 * Add links.
769 */
770 void
771 createlinks()
772 {
773 register struct entry *np, *ep;
774 register ino_t i;
775 char name[BUFSIZ];
776
777 if (ep = lookupino(WINO)) {
778 vprintf(stdout, "Add whiteouts\n");
779 for ( ; ep != NULL; ep = ep->e_links) {
780 if ((ep->e_flags & NEW) == 0)
781 continue;
782 (void) addwhiteout(myname(ep));
783 ep->e_flags &= ~NEW;
784 }
785 }
786 vprintf(stdout, "Add links\n");
787 for (i = ROOTINO; i < maxino; i++) {
788 ep = lookupino(i);
789 if (ep == NULL)
790 continue;
791 for (np = ep->e_links; np != NULL; np = np->e_links) {
792 if ((np->e_flags & NEW) == 0)
793 continue;
794 (void) strcpy(name, myname(ep));
795 if (ep->e_type == NODE) {
796 (void) linkit(name, myname(np), SYMLINK);
797 } else {
798 (void) linkit(name, myname(np), HARDLINK);
799 }
800 np->e_flags &= ~NEW;
801 }
802 }
803 }
804
805 /*
806 * Check the symbol table.
807 * We do this to insure that all the requested work was done, and
808 * that no temporary names remain.
809 */
810 void
811 checkrestore()
812 {
813 register struct entry *ep;
814 register ino_t i;
815
816 vprintf(stdout, "Check the symbol table.\n");
817 for (i = WINO; i < maxino; i++) {
818 for (ep = lookupino(i); ep != NULL; ep = ep->e_links) {
819 ep->e_flags &= ~KEEP;
820 if (ep->e_type == NODE)
821 ep->e_flags &= ~(NEW|EXISTED);
822 if (ep->e_flags != NULL)
823 badentry(ep, "incomplete operations");
824 }
825 }
826 }
827
828 /*
829 * Compare with the directory structure on the tape
830 * A paranoid check that things are as they should be.
831 */
832 long
833 verifyfile(name, ino, type)
834 char *name;
835 ino_t ino;
836 int type;
837 {
838 struct entry *np, *ep;
839 long descend = GOOD;
840
841 ep = lookupname(name);
842 if (ep == NULL) {
843 fprintf(stderr, "Warning: missing name %s\n", name);
844 return (FAIL);
845 }
846 np = lookupino(ino);
847 if (np != ep)
848 descend = FAIL;
849 for ( ; np != NULL; np = np->e_links)
850 if (np == ep)
851 break;
852 if (np == NULL)
853 panic("missing inumber %d\n", ino);
854 if (ep->e_type == LEAF && type != LEAF)
855 badentry(ep, "type should be LEAF");
856 return (descend);
857 }
858