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