add UNLEASHED_OBJ to unleashed.mk
[unleashed/tickless.git] / usr / src / cmd / backup / restore / restore.c
blob2a0b67dfd4dc16f224a5d2dd497930494a8b2ed2
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 #pragma ident "%Z%%M% %I% %E% SMI"
17 #include "restore.h"
18 /* undef MAXNAMLEN to prevent compiler warnings about redef in dirent.h */
19 #undef MAXNAMLEN
20 #include <dirent.h>
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
33 * This implements the 't' option.
34 * List entries on the tape.
36 long
37 listfile(name, ino, type)
38 char *name;
39 ino_t ino;
40 int type;
42 long descend = hflag ? GOOD : FAIL;
44 if (BIT(ino, dumpmap) == 0) {
45 return (descend);
47 vprintf(stdout, "%s", type == LEAF ? gettext("leaf") : gettext("dir "));
48 (void) fprintf(stdout, "%10lu\t%s\n", ino, name);
49 return (descend);
53 * This implements the 'x' option.
54 * Request that new entries be extracted.
56 long
57 addfile(name, ino, type)
58 char *name;
59 ino_t ino;
60 int type;
62 struct entry *ep;
63 long descend = hflag ? GOOD : FAIL;
64 char buf[100];
66 /* Don't know if ino_t is long or long long, so be safe w/ *printf() */
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);
77 return (descend);
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);
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);
95 type |= LINK;
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);
106 * This is used by the 'i' option to undo previous requests made by addfile.
107 * Delete entries from the request queue.
109 /* ARGSUSED */
110 long
111 deletefile(name, ino, type)
112 char *name;
113 ino_t ino;
114 int type;
116 long descend = hflag ? GOOD : FAIL;
117 struct entry *ep;
119 if (BIT(ino, dumpmap) == 0) {
120 return (descend);
122 ep = lookupino(ino);
123 if (ep != NIL) {
124 /* LINTED: result fits into a short */
125 ep->e_flags &= ~NEW;
127 return (descend);
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.
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.
143 static struct entry *removelist;
146 * Remove unneeded leaves from the old tree.
147 * Remove directories from the lookup chains.
149 void
150 #ifdef __STDC__
151 removeoldleaves(void)
152 #else
153 removeoldleaves()
154 #endif
156 struct entry *ep;
157 ino_t i;
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);
176 * once the inode is deleted from the symbol
177 * table, the e_next field is reusable
179 ep->e_next = removelist;
180 removelist = ep;
182 ep = ep->e_links;
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.
196 long
197 nodeupdates(name, ino, type)
198 char *name;
199 ino_t ino;
200 int type;
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 */
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.
218 * Check to see if the file is on the tape.
220 if (BIT(ino, dumpmap))
221 key |= ONTAPE;
223 * Check to see if the name exists, and if the name is a link.
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);
234 if (ip != np)
235 lookuptype = LINK;
238 * Check to see if the inode exists, and if one of its links
239 * corresponds to the name (if one was found).
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) {
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.
252 if (ip->e_flags & EXTRACT) {
253 if (key & NAMEFND) {
254 removeleaf(np);
255 freeentry(np);
256 np = NIL;
257 key &= ~NAMEFND;
259 ep->e_flags |= NEW;
260 } else {
261 ip = ep;
263 break;
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.
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);
290 np = NIL;
291 key &= ~NAMEFND;
293 if ((key & ONTAPE) &&
294 (((key & INOFND) && ip->e_type != type) ||
295 ((key & NAMEFND) && np->e_type != type)))
296 key |= MODECHG;
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.
304 switch (key) {
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.
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;
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.
330 case ONTAPE|NAMEFND:
331 case ONTAPE|NAMEFND|MODECHG:
332 if (lookuptype == LINK || key == (ONTAPE|NAMEFND)) {
333 removeleaf(np);
334 freeentry(np);
335 } else {
337 * Create a temporary node only if MODECHG.
339 mktempname(np);
341 /*FALLTHROUGH*/
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)
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;
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.
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;
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;
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;
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;
401 * A previously known file which is to be updated.
403 case ONTAPE|INOFND|NAMEFND:
405 * Extract leaf nodes.
407 if (type == LEAF) {
408 /* LINTED: result fits into a short */
409 np->e_flags |= EXTRACT;
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;
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.
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;
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);
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;
457 * A hard link to a directory that has been removed.
458 * Ignore it.
460 case NAMEFND:
461 dprintf(stdout, gettext("[%s] %s: Extraneous name\n"),
462 keyval(key),
463 name);
464 descend = FAIL;
465 break;
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.
474 case 0:
475 (void) fprintf(stderr,
476 gettext("%s: (inode %lu) not found on volume\n"),
477 name, ino);
478 break;
481 * If any of these arise, something is grievously wrong with
482 * the current state of the symbol table.
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*/
493 * These states "cannot" arise for any state of the symbol table.
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*/
503 return (descend);
507 * Calculate the active flags in a key.
509 static char *
510 keyval(key)
511 int key;
513 static char keybuf[32];
515 /* Note longest case is everything except |NIL */
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]);
531 * Find unreferenced link names.
533 void
534 #ifdef __STDC__
535 findunreflinks(void)
536 #else
537 findunreflinks()
538 #endif
540 struct entry *ep, *np;
541 ino_t i;
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);
559 * Any leaves remaining in removed directories are unreferenced.
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);
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).
586 void
587 #ifdef __STDC__
588 removeoldnodes(void)
589 #else
590 removeoldnodes()
591 #endif
593 struct entry *ep, **prev;
594 long change;
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;
605 *prev = ep->e_next;
606 removenode(ep);
607 freeentry(ep);
608 change++;
610 } while (change);
611 for (ep = removelist; ep != NIL; ep = ep->e_next)
612 badentry(ep, gettext("cannot remove, non-empty"));
616 * This is the routine used to extract files for the 'r' command.
617 * Extract new leaves.
619 void
620 createleaves(symtabfile)
621 char *symtabfile;
623 struct entry *ep;
624 char name[MAXCOMPLEXLEN];
625 ino_t first;
626 int curvol;
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);
634 first = lowerbnd(ROOTINO);
635 curvol = volno;
636 while (curfile.ino < maxino) {
637 first = lowerbnd(first);
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.
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.
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);
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);
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.
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;
677 ep = lookupino(curfile.ino);
678 if (ep == NIL) {
679 (void) fprintf(stderr,
680 gettext("unknown file on volume\n"));
681 done(1);
683 if ((ep->e_flags & (NEW|EXTRACT)) == 0)
684 badentry(ep, gettext("unexpected file on volume"));
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.
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));
708 /* LINTED: result fits into a short */
709 ep->e_flags &= ~(NEW|EXTRACT);
711 * We checkpoint the restore after every tape reel, so
712 * as to simplify the amount of work required by the
713 * 'R' command.
715 next:
716 if (curvol != volno) {
717 dumpsymtable(symtabfile, volno);
718 skipmaps();
719 curvol = volno;
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.
728 void
729 #ifdef __STDC__
730 createfiles(void)
731 #else
732 createfiles()
733 #endif
735 ino_t first, next, last;
736 struct entry *ep;
737 int curvol, nextvol;
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();
749 for (;;) {
750 first = lowerbnd(first);
751 last = upperbnd(last);
753 * Check to see if any files remain to be extracted
755 if (first > last)
756 return;
758 * If a map of inode numbers to tape volumes is
759 * available, then select the next volume to be read.
761 if (nextvol > 0) {
762 nextvol = volnumber(first);
763 if (nextvol != volno) {
764 curfile.action = UNKNOWN;
765 getvol(nextvol);
766 skipmaps();
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.
774 while (curfile.ino > last) {
775 curfile.action = SKIP;
776 getvol(0);
777 skipmaps();
778 skipdirs();
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
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);
794 * If volume change out of order occurred the
795 * current state must be recalculated
797 if (volno != curvol)
798 continue;
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.
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);
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);
824 * The current inode is the one that we are looking for,
825 * so extract it per its requested name.
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);
834 (void) extractfile(myname(ep));
835 /* LINTED: result fits into a short */
836 ep->e_flags &= ~NEW;
837 if (volno != curvol)
838 skipmaps();
844 * Add links.
846 void
847 #ifdef __STDC__
848 createlinks(void)
849 #else
850 createlinks()
851 #endif
853 struct entry *np, *ep;
854 ino_t i;
855 int dfd;
856 char *to, *from;
857 int saverr;
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;
879 if (ep->e_type == NODE) {
880 (void) lf_linkit(to, from, SYMLINK);
881 } else {
882 (void) lf_linkit(to, from, HARDLINK);
884 /* LINTED: result fits into a short */
885 np->e_flags &= ~NEW;
886 if (dfd != AT_FDCWD) {
887 fchdir(savepwd);
888 (void) close(dfd);
891 freename(to);
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.
900 void
901 #ifdef __STDC__
902 checkrestore(void)
903 #else
904 checkrestore()
905 #endif
907 struct entry *ep;
908 ino_t i;
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);
919 if ((ep->e_flags & ~(XATTR|XATTRROOT)) != 0)
920 badentry(ep, gettext("incomplete operations"));
926 * Compare with the directory structure on the tape
927 * A paranoid check that things are as they should be.
929 long
930 verifyfile(name, ino, type)
931 char *name;
932 ino_t ino;
933 int type;
935 struct entry *np, *ep;
936 long descend = GOOD;
938 ep = lookupname(name);
939 if (ep == NIL) {
940 (void) fprintf(stderr,
941 gettext("Warning: missing name %s\n"), name);
942 return (FAIL);
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);
954 if (ep->e_type == LEAF && type != LEAF)
955 badentry(ep, gettext("type should be LEAF"));
956 return (descend);
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.
965 static void
966 removexattrs(ep)
967 struct entry *ep;
969 struct entry *np = ep;
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);
981 ep->e_flags |= REMOVED;
982 freeentry(ep);
986 * Move all the extended attributes associated with orig to
987 * the file named by the second argument (targ).
989 static void
990 movexattrs(orig, targ)
991 char *orig;
992 char *targ;
994 char *to, *from;
995 int fromfd, fromdir, tofd, todir, tfd;
996 DIR *dirp = NULL;
997 struct dirent *dp = NULL;
999 fromfd = tofd = fromdir = todir = tfd = -1;
1001 resolve(orig, &tfd, &from);
1002 if (tfd == AT_FDCWD && pathconf(orig, _PC_XATTR_EXISTS) != 1) {
1003 /* no attributes to move */
1004 return;
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;
1013 if (fpathconf(fromfd, _PC_XATTR_EXISTS) != 1) {
1014 /* no attributes to move */
1015 if (tfd != AT_FDCWD) (void) close(tfd);
1016 goto out;
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;
1026 if (tfd != AT_FDCWD) (void) close(tfd);
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;
1035 if (tfd != AT_FDCWD) (void) close(tfd);
1036 (void) close(tofd);
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;
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;
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);