1 /*
2 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
7 /* All Rights Reserved */
8
9 /*
10 * Copyright (c) 1983 Regents of the University of California.
11 * All rights reserved. The Berkeley software License Agreement
12 * specifies the terms and conditions for redistribution.
13 */
14
15 #pragma ident "%Z%%M% %I% %E% SMI"
16
17 #include "restore.h"
18 /* undef MAXNAMLEN to prevent compiler warnings about redef in dirent.h */
19 #undef MAXNAMLEN
20 #include <dirent.h>
21
22 #ifdef __STDC__
23 static char *keyval(int);
24 static void removexattrs(struct entry *);
25 static void movexattrs(char *, char *);
26 #else
27 static char *keyval();
28 static void removexattrs();
29 static void movexattrs();
30 #endif
31
32 /*
33 * This implements the 't' option.
34 * List entries on the tape.
35 */
36 long
listfile(name,ino,type)37 listfile(name, ino, type)
38 char *name;
39 ino_t ino;
40 int type;
41 {
42 long descend = hflag ? GOOD : FAIL;
43
44 if (BIT(ino, dumpmap) == 0) {
45 return (descend);
46 }
47 vprintf(stdout, "%s", type == LEAF ? gettext("leaf") : gettext("dir "));
48 (void) fprintf(stdout, "%10lu\t%s\n", ino, name);
49 return (descend);
50 }
51
52 /*
53 * This implements the 'x' option.
54 * Request that new entries be extracted.
55 */
56 long
addfile(name,ino,type)57 addfile(name, ino, type)
58 char *name;
59 ino_t ino;
60 int type;
61 {
62 struct entry *ep;
63 long descend = hflag ? GOOD : FAIL;
64 char buf[100];
65
66 /* Don't know if ino_t is long or long long, so be safe w/ *printf() */
67
68 if (BIT(ino, dumpmap) == 0) {
69 if (mflag) {
70 dprintf(stdout, gettext(
71 "%s: not on the volume\n"), name);
72 } else {
73 dprintf(stdout, gettext(
74 "inode %llu: not on the volume\n"),
75 (u_longlong_t)ino);
76 }
77 return (descend);
78 }
79 if (!mflag) {
80 (void) snprintf(buf, sizeof (buf), "./%llu", (u_longlong_t)ino);
81 buf[sizeof (buf) - 1] = '\0';
82 name = buf;
83 if (type == NODE) {
84 (void) genliteraldir(name, ino);
85 return (descend);
86 }
87 }
88 ep = lookupino(ino);
89 if (ep != NIL) {
90 if (strcmp(name, myname(ep)) == 0) {
91 /* LINTED: result fits into a short */
92 ep->e_flags |= NEW;
93 return (descend);
94 }
95 type |= LINK;
96 }
97 ep = addentry(name, ino, type);
98 if (type == NODE)
99 newnode(ep);
100 /* LINTED: result fits into a short */
101 ep->e_flags |= NEW;
102 return (descend);
103 }
104
105 /*
106 * This is used by the 'i' option to undo previous requests made by addfile.
107 * Delete entries from the request queue.
108 */
109 /* ARGSUSED */
110 long
deletefile(name,ino,type)111 deletefile(name, ino, type)
112 char *name;
113 ino_t ino;
114 int type;
115 {
116 long descend = hflag ? GOOD : FAIL;
117 struct entry *ep;
118
119 if (BIT(ino, dumpmap) == 0) {
120 return (descend);
121 }
122 ep = lookupino(ino);
123 if (ep != NIL) {
124 /* LINTED: result fits into a short */
125 ep->e_flags &= ~NEW;
126 }
127 return (descend);
128 }
129
130 /*
131 * The following four routines implement the incremental
132 * restore algorithm. The first removes old entries, the second
133 * does renames and calculates the extraction list, the third
134 * cleans up link names missed by the first two, and the final
135 * one deletes old directories.
136 *
137 * Directories cannot be immediately deleted, as they may have
138 * other files in them which need to be moved out first. As
139 * directories to be deleted are found, they are put on the
140 * following deletion list. After all deletions and renames
141 * are done, this list is actually deleted.
142 */
143 static struct entry *removelist;
144
145 /*
146 * Remove unneeded leaves from the old tree.
147 * Remove directories from the lookup chains.
148 */
149 void
150 #ifdef __STDC__
removeoldleaves(void)151 removeoldleaves(void)
152 #else
153 removeoldleaves()
154 #endif
155 {
156 struct entry *ep;
157 ino_t i;
158
159 vprintf(stdout, gettext("Mark entries to be removed.\n"));
160 for (i = ROOTINO + 1; i < maxino; i++) {
161 if (BIT(i, clrimap))
162 continue;
163 ep = lookupino(i);
164 if (ep == NIL)
165 continue;
166 while (ep != NIL) {
167 dprintf(stdout, gettext("%s: REMOVE\n"), myname(ep));
168 removexattrs(ep->e_xattrs);
169 if (ep->e_type == LEAF) {
170 removeleaf(ep);
171 freeentry(ep);
172 } else {
173 mktempname(ep);
174 deleteino(ep->e_ino);
175 /*
176 * once the inode is deleted from the symbol
177 * table, the e_next field is reusable
178 */
179 ep->e_next = removelist;
180 removelist = ep;
181 }
182 ep = ep->e_links;
183 }
184 }
185 }
186
187 /*
188 * For each directory entry on the incremental tape, determine which
189 * category it falls into as follows:
190 * KEEP - entries that are to be left alone.
191 * NEW - new entries to be added.
192 * EXTRACT - files that must be updated with new contents.
193 * LINK - new links to be added.
194 * Renames are done at the same time.
195 */
196 long
nodeupdates(name,ino,type)197 nodeupdates(name, ino, type)
198 char *name;
199 ino_t ino;
200 int type;
201 {
202 struct entry *ep, *np, *ip;
203 long descend = GOOD;
204 int lookuptype = 0;
205 int key = 0;
206 /* key values */
207 #define ONTAPE 0x1 /* inode is on the tape */
208 #define INOFND 0x2 /* inode already exists */
209 #define NAMEFND 0x4 /* name already exists */
210 #define MODECHG 0x8 /* mode of inode changed */
211
212 /*
213 * This routine is called once for each element in the
214 * directory hierarchy, with a full path name.
215 * The "type" value is incorrectly specified as LEAF for
216 * directories that are not on the dump tape.
217 *
218 * Check to see if the file is on the tape.
219 */
220 if (BIT(ino, dumpmap))
221 key |= ONTAPE;
222 /*
223 * Check to see if the name exists, and if the name is a link.
224 */
225 np = lookupname(name);
226 if (np != NIL) {
227 key |= NAMEFND;
228 ip = lookupino(np->e_ino);
229 if (ip == NULL) {
230 (void) fprintf(stderr,
231 gettext("corrupted symbol table\n"));
232 done(1);
233 }
234 if (ip != np)
235 lookuptype = LINK;
236 }
237 /*
238 * Check to see if the inode exists, and if one of its links
239 * corresponds to the name (if one was found).
240 */
241 ip = lookupino(ino);
242 if (ip != NIL) {
243 key |= INOFND;
244 for (ep = ip->e_links; ep != NIL; ep = ep->e_links) {
245 if (ep == np) {
246 /*
247 * Need to set the NEW flag on the hard link
248 * so it gets created because we extract the
249 * "parent". If the NAMEFND key is set, remove
250 * the leaf.
251 */
252 if (ip->e_flags & EXTRACT) {
253 if (key & NAMEFND) {
254 removeleaf(np);
255 freeentry(np);
256 np = NIL;
257 key &= ~NAMEFND;
258 }
259 ep->e_flags |= NEW;
260 } else {
261 ip = ep;
262 }
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,
286 gettext("name/inode conflict, mktempname %s\n"),
287 myname(np));
288 mktempname(np);
289 }
290 np = NIL;
291 key &= ~NAMEFND;
292 }
293 if ((key & ONTAPE) &&
294 (((key & INOFND) && ip->e_type != type) ||
295 ((key & NAMEFND) && np->e_type != type)))
296 key |= MODECHG;
297
298 /*
299 * Decide on the disposition of the file based on its flags.
300 * Note that we have already handled the case in which
301 * a name and inode are found that correspond to different files.
302 * Thus if both NAMEFND and INOFND are set then ip == np.
303 */
304 switch (key) {
305
306 /*
307 * A previously existing file has been found.
308 * Mark it as KEEP so that other links to the inode can be
309 * detected, and so that it will not be reclaimed by the search
310 * for unreferenced names.
311 */
312 case INOFND|NAMEFND:
313 /* LINTED: result fits into a short */
314 ip->e_flags |= KEEP;
315 dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
316 flagvalues(ip));
317 break;
318
319 /*
320 * A file on the tape has a name which is the same as a name
321 * corresponding to a different file in the previous dump.
322 * Since all files to be deleted have already been removed,
323 * this file is either a now-unneeded link, or it must live
324 * under a new name in this dump level. If it is a link, it
325 * can simply be removed. If it is not a link, it is given a
326 * temporary name in anticipation that it will be renamed
327 * when it is later found by inode number (see INOFND case
328 * below). The entry is then treated as a new file.
329 */
330 case ONTAPE|NAMEFND:
331 case ONTAPE|NAMEFND|MODECHG:
332 if (lookuptype == LINK || key == (ONTAPE|NAMEFND)) {
333 removeleaf(np);
334 freeentry(np);
335 } else {
336 /*
337 * Create a temporary node only if MODECHG.
338 */
339 mktempname(np);
340 }
341 /*FALLTHROUGH*/
342
343 /*
344 * A previously non-existent file.
345 * Add it to the file system, and request its extraction.
346 * If it is a directory, create it immediately.
347 * (Since the name is unused there can be no conflict)
348 */
349 case ONTAPE:
350 ep = addentry(name, ino, type);
351 if (type == NODE)
352 newnode(ep);
353 /* LINTED: result fits into a short */
354 ep->e_flags |= NEW|KEEP;
355 dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
356 flagvalues(ep));
357 break;
358
359 /*
360 * A file with the same inode number, but a different
361 * name has been found. If the other name has not already
362 * been found (indicated by the KEEP flag, see above) then
363 * this must be a new name for the file, and it is renamed.
364 * If the other name has been found then this must be a
365 * link to the file. Hard links to directories are not
366 * permitted, and are either deleted or converted to
367 * symbolic links. Finally, if the file is on the tape,
368 * a request is made to extract it.
369 */
370 case ONTAPE|INOFND:
371 if (type == LEAF && (ip->e_flags & KEEP) == 0) {
372 /* LINTED: result fits into a short */
373 ip->e_flags |= EXTRACT;
374 }
375 /*FALLTHROUGH*/
376 case INOFND:
377 if ((ip->e_flags & KEEP) == 0) {
378 renameit(myname(ip), name);
379 moveentry(ip, name);
380 /* LINTED: result fits into a short */
381 ip->e_flags |= KEEP;
382 dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
383 flagvalues(ip));
384 break;
385 }
386 if (ip->e_type == NODE) {
387 descend = FAIL;
388 (void) fprintf(stderr, gettext(
389 "deleted hard link %s to directory %s\n"),
390 name, myname(ip));
391 break;
392 }
393 ep = addentry(name, ino, type|LINK);
394 /* LINTED: result fits into a short */
395 ep->e_flags |= NEW;
396 dprintf(stdout, "[%s] %s: %s|LINK\n", keyval(key), name,
397 flagvalues(ep));
398 break;
399
400 /*
401 * A previously known file which is to be updated.
402 */
403 case ONTAPE|INOFND|NAMEFND:
404 /*
405 * Extract leaf nodes.
406 */
407 if (type == LEAF) {
408 /* LINTED: result fits into a short */
409 np->e_flags |= EXTRACT;
410 }
411 /* LINTED: result fits into a short */
412 np->e_flags |= KEEP;
413 dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
414 flagvalues(np));
415 break;
416
417 /*
418 * An inode is being reused in a completely different way.
419 * Normally an extract can simply do an "unlink" followed
420 * by a "creat". Here we must do effectively the same
421 * thing. The complications arise because we cannot really
422 * delete a directory since it may still contain files
423 * that we need to rename, so we delete it from the symbol
424 * table, and put it on the list to be deleted eventually.
425 * Conversely if a directory is to be created, it must be
426 * done immediately, rather than waiting until the
427 * extraction phase.
428 */
429 case ONTAPE|INOFND|MODECHG:
430 case ONTAPE|INOFND|NAMEFND|MODECHG:
431 if (ip->e_flags & KEEP) {
432 badentry(ip, gettext("cannot KEEP and change modes"));
433 break;
434 }
435 if (ip->e_type == LEAF) {
436 /* changing from leaf to node */
437 removeleaf(ip);
438 freeentry(ip);
439 ip = addentry(name, ino, type);
440 newnode(ip);
441 } else {
442 /* changing from node to leaf */
443 if ((ip->e_flags & TMPNAME) == 0)
444 mktempname(ip);
445 deleteino(ip->e_ino);
446 ip->e_next = removelist;
447 removelist = ip;
448 ip = addentry(name, ino, type);
449 }
450 /* LINTED: result fits into a short */
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, gettext("[%s] %s: Extraneous name\n"),
462 keyval(key),
463 name);
464 descend = FAIL;
465 break;
466
467 /*
468 * If we find a directory entry for a file that is not on
469 * the tape, then we must have found a file that was created
470 * while the dump was in progress. Since we have no contents
471 * for it, we discard the name knowing that it will be on the
472 * next incremental tape.
473 */
474 case 0:
475 (void) fprintf(stderr,
476 gettext("%s: (inode %lu) not found on volume\n"),
477 name, ino);
478 break;
479
480 /*
481 * If any of these arise, something is grievously wrong with
482 * the current state of the symbol table.
483 */
484 case INOFND|NAMEFND|MODECHG:
485 case NAMEFND|MODECHG:
486 case INOFND|MODECHG:
487 (void) fprintf(stderr, "[%s] %s: %s\n",
488 keyval(key), name, gettext("inconsistent state"));
489 done(1);
490 /*NOTREACHED*/
491
492 /*
493 * These states "cannot" arise for any state of the symbol table.
494 */
495 case ONTAPE|MODECHG:
496 case MODECHG:
497 default:
498 (void) fprintf(stderr, "[%s] %s: %s\n",
499 keyval(key), name, gettext("impossible state"));
500 done(1);
501 /*NOTREACHED*/
502 }
503 return (descend);
504 }
505
506 /*
507 * Calculate the active flags in a key.
508 */
509 static char *
keyval(key)510 keyval(key)
511 int key;
512 {
513 static char keybuf[32];
514
515 /* Note longest case is everything except |NIL */
516
517 (void) strcpy(keybuf, "|NIL");
518 keybuf[0] = '\0';
519 if (key & ONTAPE)
520 (void) strcat(keybuf, "|ONTAPE");
521 if (key & INOFND)
522 (void) strcat(keybuf, "|INOFND");
523 if (key & NAMEFND)
524 (void) strcat(keybuf, "|NAMEFND");
525 if (key & MODECHG)
526 (void) strcat(keybuf, "|MODECHG");
527 return (&keybuf[1]);
528 }
529
530 /*
531 * Find unreferenced link names.
532 */
533 void
534 #ifdef __STDC__
findunreflinks(void)535 findunreflinks(void)
536 #else
537 findunreflinks()
538 #endif
539 {
540 struct entry *ep, *np;
541 ino_t i;
542
543 vprintf(stdout, gettext("Find unreferenced names.\n"));
544 for (i = ROOTINO; i < maxino; i++) {
545 ep = lookupino(i);
546 if (ep == NIL || ep->e_type == LEAF || BIT(i, dumpmap) == 0)
547 continue;
548 for (np = ep->e_entries; np != NIL; np = np->e_sibling) {
549 if (np->e_flags == 0) {
550 dprintf(stdout, gettext(
551 "%s: remove unreferenced name\n"),
552 myname(np));
553 removeleaf(np);
554 freeentry(np);
555 }
556 }
557 }
558 /*
559 * Any leaves remaining in removed directories are unreferenced.
560 */
561 for (ep = removelist; ep != NIL; ep = ep->e_next) {
562 for (np = ep->e_entries; np != NIL; np = np->e_sibling) {
563 if (np->e_type == LEAF) {
564 if (np->e_flags != 0)
565 badentry(np, gettext(
566 "unreferenced with flags"));
567 dprintf(stdout, gettext(
568 "%s: remove unreferenced name\n"),
569 myname(np));
570 removeleaf(np);
571 freeentry(np);
572 }
573 }
574 }
575 }
576
577 /*
578 * Remove old nodes (directories).
579 * Note that this routine runs in O(N*D) where:
580 * N is the number of directory entries to be removed.
581 * D is the maximum depth of the tree.
582 * If N == D this can be quite slow. If the list were
583 * topologically sorted, the deletion could be done in
584 * time O(N).
585 */
586 void
587 #ifdef __STDC__
removeoldnodes(void)588 removeoldnodes(void)
589 #else
590 removeoldnodes()
591 #endif
592 {
593 struct entry *ep, **prev;
594 long change;
595
596 vprintf(stdout, gettext("Remove old nodes (directories).\n"));
597 do {
598 change = 0;
599 prev = &removelist;
600 for (ep = removelist; ep != NIL; ep = *prev) {
601 if (ep->e_entries != NIL) {
602 prev = &ep->e_next;
603 continue;
604 }
605 *prev = ep->e_next;
606 removenode(ep);
607 freeentry(ep);
608 change++;
609 }
610 } while (change);
611 for (ep = removelist; ep != NIL; ep = ep->e_next)
612 badentry(ep, gettext("cannot remove, non-empty"));
613 }
614
615 /*
616 * This is the routine used to extract files for the 'r' command.
617 * Extract new leaves.
618 */
619 void
createleaves(symtabfile)620 createleaves(symtabfile)
621 char *symtabfile;
622 {
623 struct entry *ep;
624 char name[MAXCOMPLEXLEN];
625 ino_t first;
626 int curvol;
627
628 if (command == 'R') {
629 vprintf(stdout, gettext("Continue extraction of new leaves\n"));
630 } else {
631 vprintf(stdout, gettext("Extract new leaves.\n"));
632 dumpsymtable(symtabfile, volno);
633 }
634 first = lowerbnd(ROOTINO);
635 curvol = volno;
636 while (curfile.ino < maxino) {
637 first = lowerbnd(first);
638 /*
639 * If the next available file is not the one which we
640 * expect then we have missed one or more files. Since
641 * we do not request files that were not on the tape,
642 * the lost files must have been due to a tape read error,
643 * or a file that was removed while the dump was in progress.
644 *
645 * The loop will terminate with first == maxino, if not
646 * sooner. Due to the e_flags manipulation, lowerbnd()
647 * will never return its argument.
648 */
649 while (first < curfile.ino) {
650 ep = lookupino(first);
651 if (ep == NIL) {
652 (void) fprintf(stderr,
653 gettext("%d: bad first\n"), first);
654 done(1);
655 }
656 (void) fprintf(stderr,
657 gettext("%s: not found on volume\n"),
658 myname(ep));
659 /* LINTED: result fits into a short */
660 ep->e_flags &= ~(NEW|EXTRACT);
661 first = lowerbnd(first);
662 }
663 /*
664 * If we find files on the tape that have no corresponding
665 * directory entries, then we must have found a file that
666 * was created while the dump was in progress. Since we have
667 * no name for it, we discard it knowing that it will be
668 * on the next incremental tape.
669 */
670 if (first != curfile.ino) {
671 (void) fprintf(stderr,
672 gettext("expected next file %d, got %d\n"),
673 first, curfile.ino);
674 skipfile();
675 goto next;
676 }
677 ep = lookupino(curfile.ino);
678 if (ep == NIL) {
679 (void) fprintf(stderr,
680 gettext("unknown file on volume\n"));
681 done(1);
682 }
683 if ((ep->e_flags & (NEW|EXTRACT)) == 0)
684 badentry(ep, gettext("unexpected file on volume"));
685 /*
686 * If the file is to be extracted, then the old file must
687 * be removed since its type may change from one leaf type
688 * to another (eg "file" to "character special"). But we
689 * also need to preserve any existing extended attributes;
690 * so first rename the file, then move its attributes, then
691 * remove it.
692 */
693 if ((ep->e_flags & EXTRACT) != 0) {
694 char *sname = savename(ep->e_name);
695 complexcpy(name, myname(ep), MAXCOMPLEXLEN);
696 mktempname(ep);
697 (void) extractfile(name);
698 movexattrs(myname(ep), name);
699 removeleaf(ep);
700 freename(ep->e_name);
701 ep->e_name = sname;
702 ep->e_namlen = strlen(ep->e_name);
703 /* LINTED: result fits into a short */
704 ep->e_flags &= ~REMOVED;
705 } else {
706 (void) extractfile(myname(ep));
707 }
708 /* LINTED: result fits into a short */
709 ep->e_flags &= ~(NEW|EXTRACT);
710 /*
711 * We checkpoint the restore after every tape reel, so
712 * as to simplify the amount of work required by the
713 * 'R' command.
714 */
715 next:
716 if (curvol != volno) {
717 dumpsymtable(symtabfile, volno);
718 skipmaps();
719 curvol = volno;
720 }
721 }
722 }
723
724 /*
725 * This is the routine used to extract files for the 'x' and 'i' commands.
726 * Efficiently extract a subset of the files on a tape.
727 */
728 void
729 #ifdef __STDC__
createfiles(void)730 createfiles(void)
731 #else
732 createfiles()
733 #endif
734 {
735 ino_t first, next, last;
736 struct entry *ep;
737 int curvol, nextvol;
738
739 vprintf(stdout, gettext("Extract requested files\n"));
740 first = lowerbnd(ROOTINO);
741 last = upperbnd(maxino - 1);
742 nextvol = volnumber(first);
743 if (nextvol == 0) {
744 curfile.action = SKIP;
745 getvol(1);
746 skipmaps();
747 skipdirs();
748 }
749 for (;;) {
750 first = lowerbnd(first);
751 last = upperbnd(last);
752 /*
753 * Check to see if any files remain to be extracted
754 */
755 if (first > last)
756 return;
757 /*
758 * If a map of inode numbers to tape volumes is
759 * available, then select the next volume to be read.
760 */
761 if (nextvol > 0) {
762 nextvol = volnumber(first);
763 if (nextvol != volno) {
764 curfile.action = UNKNOWN;
765 getvol(nextvol);
766 skipmaps();
767 }
768 }
769 /*
770 * Reject any volumes with inodes greater than
771 * the last one needed. This will only be true
772 * if the above code has not selected a volume.
773 */
774 while (curfile.ino > last) {
775 curfile.action = SKIP;
776 getvol(0);
777 skipmaps();
778 skipdirs();
779 }
780 /*
781 * Decide on the next inode needed.
782 * Skip across the inodes until it is found
783 * or an out of order volume change is encountered
784 */
785 next = lowerbnd(curfile.ino);
786 do {
787 curvol = volno;
788 while (next > curfile.ino && volno == curvol)
789 skipfile();
790 skipmaps();
791 skipdirs();
792 } while (volno == curvol + 1);
793 /*
794 * If volume change out of order occurred the
795 * current state must be recalculated
796 */
797 if (volno != curvol)
798 continue;
799 /*
800 * If the current inode is greater than the one we were
801 * looking for then we missed the one we were looking for.
802 * Since we only attempt to extract files listed in the
803 * dump map, the lost files must have been due to a tape
804 * read error, or a file that was removed while the dump
805 * was in progress. Thus we report all requested files
806 * between the one we were looking for, and the one we
807 * found as missing, and delete their request flags.
808 */
809 while (next < curfile.ino) {
810 ep = lookupino(next);
811 if (ep == NIL) {
812 (void) fprintf(stderr,
813 gettext("corrupted symbol table\n"));
814 done(1);
815 }
816 (void) fprintf(stderr,
817 gettext("%s: not found on volume\n"),
818 myname(ep));
819 /* LINTED: result fits into a short */
820 ep->e_flags &= ~NEW;
821 next = lowerbnd(next);
822 }
823 /*
824 * The current inode is the one that we are looking for,
825 * so extract it per its requested name.
826 */
827 if (next == curfile.ino && next <= last) {
828 ep = lookupino(next);
829 if (ep == NIL) {
830 (void) fprintf(stderr,
831 gettext("corrupted symbol table\n"));
832 done(1);
833 }
834 (void) extractfile(myname(ep));
835 /* LINTED: result fits into a short */
836 ep->e_flags &= ~NEW;
837 if (volno != curvol)
838 skipmaps();
839 }
840 }
841 }
842
843 /*
844 * Add links.
845 */
846 void
847 #ifdef __STDC__
createlinks(void)848 createlinks(void)
849 #else
850 createlinks()
851 #endif
852 {
853 struct entry *np, *ep;
854 ino_t i;
855 int dfd;
856 char *to, *from;
857 int saverr;
858
859 vprintf(stdout, gettext("Add links\n"));
860 for (i = ROOTINO; i < maxino; i++) {
861 ep = lookupino(i);
862 if (ep == NIL)
863 continue;
864 to = savename(myname(ep));
865 for (np = ep->e_links; np != NIL; np = np->e_links) {
866 if ((np->e_flags & NEW) == 0)
867 continue;
868 resolve(myname(np), &dfd, &from);
869 if (dfd != AT_FDCWD) {
870 if (fchdir(dfd) < 0) {
871 saverr = errno;
872 (void) fprintf(stderr,
873 gettext("%s->%s: link failed: %s\n"),
874 from, to, strerror(saverr));
875 (void) close(dfd);
876 continue;
877 }
878 }
879 if (ep->e_type == NODE) {
880 (void) lf_linkit(to, from, SYMLINK);
881 } else {
882 (void) lf_linkit(to, from, HARDLINK);
883 }
884 /* LINTED: result fits into a short */
885 np->e_flags &= ~NEW;
886 if (dfd != AT_FDCWD) {
887 fchdir(savepwd);
888 (void) close(dfd);
889 }
890 }
891 freename(to);
892 }
893 }
894
895 /*
896 * Check the symbol table.
897 * We do this to insure that all the requested work was done, and
898 * that no temporary names remain.
899 */
900 void
901 #ifdef __STDC__
checkrestore(void)902 checkrestore(void)
903 #else
904 checkrestore()
905 #endif
906 {
907 struct entry *ep;
908 ino_t i;
909
910 vprintf(stdout, gettext("Check the symbol table.\n"));
911 for (i = ROOTINO; i < maxino; i++) {
912 for (ep = lookupino(i); ep != NIL; ep = ep->e_links) {
913 /* LINTED: result fits into a short */
914 ep->e_flags &= ~KEEP;
915 if (ep->e_type == NODE) {
916 /* LINTED: result fits into a short */
917 ep->e_flags &= ~(NEW|EXISTED);
918 }
919 if ((ep->e_flags & ~(XATTR|XATTRROOT)) != 0)
920 badentry(ep, gettext("incomplete operations"));
921 }
922 }
923 }
924
925 /*
926 * Compare with the directory structure on the tape
927 * A paranoid check that things are as they should be.
928 */
929 long
verifyfile(name,ino,type)930 verifyfile(name, ino, type)
931 char *name;
932 ino_t ino;
933 int type;
934 {
935 struct entry *np, *ep;
936 long descend = GOOD;
937
938 ep = lookupname(name);
939 if (ep == NIL) {
940 (void) fprintf(stderr,
941 gettext("Warning: missing name %s\n"), name);
942 return (FAIL);
943 }
944 np = lookupino(ino);
945 if (np != ep)
946 descend = FAIL;
947 for (; np != NIL; np = np->e_links)
948 if (np == ep)
949 break;
950 if (np == NIL) {
951 (void) fprintf(stderr, gettext("missing inumber %d\n"), ino);
952 done(1);
953 }
954 if (ep->e_type == LEAF && type != LEAF)
955 badentry(ep, gettext("type should be LEAF"));
956 return (descend);
957 }
958
959 /*
960 * This routine does not actually remove any attribute files, it
961 * just removes entries from the symbol table. The attribute files
962 * themselves are assumed to be removed automatically when the
963 * parent file is removed.
964 */
965 static void
removexattrs(ep)966 removexattrs(ep)
967 struct entry *ep;
968 {
969 struct entry *np = ep;
970
971 if (ep == NIL)
972 return;
973 for (np = ep->e_entries; np != NIL; np = np->e_sibling) {
974 if (np->e_type == NODE) {
975 removexattrs(np);
976 } else {
977 np->e_flags |= REMOVED;
978 freeentry(np);
979 }
980 }
981 ep->e_flags |= REMOVED;
982 freeentry(ep);
983 }
984
985 /*
986 * Move all the extended attributes associated with orig to
987 * the file named by the second argument (targ).
988 */
989 static void
movexattrs(orig,targ)990 movexattrs(orig, targ)
991 char *orig;
992 char *targ;
993 {
994 char *to, *from;
995 int fromfd, fromdir, tofd, todir, tfd;
996 DIR *dirp = NULL;
997 struct dirent *dp = NULL;
998
999 fromfd = tofd = fromdir = todir = tfd = -1;
1000
1001 resolve(orig, &tfd, &from);
1002 if (tfd == AT_FDCWD && pathconf(orig, _PC_XATTR_EXISTS) != 1) {
1003 /* no attributes to move */
1004 return;
1005 }
1006 if ((fromfd = openat64(tfd, from, O_RDONLY|O_NONBLOCK)) == -1) {
1007 fprintf(stderr, gettext("%s: cannot move attributes: "), from);
1008 perror("");
1009 if (tfd != AT_FDCWD) (void) close(tfd);
1010 goto out;
1011 }
1012
1013 if (fpathconf(fromfd, _PC_XATTR_EXISTS) != 1) {
1014 /* no attributes to move */
1015 if (tfd != AT_FDCWD) (void) close(tfd);
1016 goto out;
1017 }
1018 if ((fromdir = openat64(fromfd, ".",
1019 O_RDONLY|O_NONBLOCK|O_XATTR)) == -1) {
1020 fprintf(stderr, gettext("%s: cannot access attributes: "),
1021 from);
1022 perror("");
1023 if (tfd != AT_FDCWD) (void) close(tfd);
1024 goto out;
1025 }
1026 if (tfd != AT_FDCWD) (void) close(tfd);
1027
1028 resolve(targ, &tfd, &to);
1029 if ((tofd = openat64(tfd, to, O_RDONLY|O_NONBLOCK)) == -1 ||
1030 (todir = openat64(tofd, ".", O_RDONLY|O_NONBLOCK|O_XATTR)) == -1) {
1031 fprintf(stderr, gettext("%s: cannot create attributes: "), to);
1032 perror("");
1033 goto out;
1034 }
1035 if (tfd != AT_FDCWD) (void) close(tfd);
1036 (void) close(tofd);
1037
1038 if ((tfd = dup(fromdir)) == -1 ||
1039 (dirp = fdopendir(tfd)) == NULL) {
1040 fprintf(stderr,
1041 gettext("%s: cannot allocate DIR structure to attribute directory: "),
1042 from);
1043 perror("");
1044 if (tfd != -1) (void) close(tfd);
1045 goto out;
1046 }
1047
1048 while ((dp = readdir(dirp)) != NULL) {
1049 if ((dp->d_name[0] == '.' && dp->d_name[1] == '\0') ||
1050 (dp->d_name[0] == '.' && dp->d_name[1] == '.' &&
1051 dp->d_name[2] == '\0'))
1052 continue;
1053 if ((renameat(fromdir, dp->d_name, todir, dp->d_name)) == -1) {
1054 fprintf(stderr,
1055 gettext("%s: cannot move attribute %s: "),
1056 from, dp->d_name);
1057 goto out;
1058 }
1059 }
1060 out:
1061 if (fromfd != -1)
1062 (void) close(fromfd);
1063 if (tofd != -1)
1064 (void) close(tofd);
1065 if (dirp != NULL)
1066 (void) closedir(dirp);
1067 if (fromdir != -1)
1068 (void) close(fromdir);
1069 if (todir != -1)
1070 (void) close(todir);
1071 }
1072