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