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