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