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