2 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
6 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
7 /* All Rights Reserved */
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.
16 /* undef MAXNAMLEN to prevent compiler warnings about redef in dirent.h */
21 static char *keyval(int);
22 static void removexattrs(struct entry
*);
23 static void movexattrs(char *, char *);
25 static char *keyval();
26 static void removexattrs();
27 static void movexattrs();
31 * This implements the 't' option.
32 * List entries on the tape.
35 listfile(name
, ino
, type
)
40 long descend
= hflag
? GOOD
: FAIL
;
42 if (BIT(ino
, dumpmap
) == 0) {
45 vprintf(stdout
, "%s", type
== LEAF
? gettext("leaf") : gettext("dir "));
46 (void) fprintf(stdout
, "%10lu\t%s\n", ino
, name
);
51 * This implements the 'x' option.
52 * Request that new entries be extracted.
55 addfile(name
, ino
, type
)
61 long descend
= hflag
? GOOD
: FAIL
;
64 /* Don't know if ino_t is long or long long, so be safe w/ *printf() */
66 if (BIT(ino
, dumpmap
) == 0) {
68 dprintf(stdout
, gettext(
69 "%s: not on the volume\n"), name
);
71 dprintf(stdout
, gettext(
72 "inode %llu: not on the volume\n"),
78 (void) snprintf(buf
, sizeof (buf
), "./%llu", (u_longlong_t
)ino
);
79 buf
[sizeof (buf
) - 1] = '\0';
82 (void) genliteraldir(name
, ino
);
88 if (strcmp(name
, myname(ep
)) == 0) {
89 /* LINTED: result fits into a short */
95 ep
= addentry(name
, ino
, type
);
98 /* LINTED: result fits into a short */
104 * This is used by the 'i' option to undo previous requests made by addfile.
105 * Delete entries from the request queue.
109 deletefile(name
, ino
, type
)
114 long descend
= hflag
? GOOD
: FAIL
;
117 if (BIT(ino
, dumpmap
) == 0) {
122 /* LINTED: result fits into a short */
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.
149 removeoldleaves(void)
157 vprintf(stdout
, gettext("Mark entries to be removed.\n"));
158 for (i
= ROOTINO
+ 1; i
< maxino
; i
++) {
165 dprintf(stdout
, gettext("%s: REMOVE\n"), myname(ep
));
166 removexattrs(ep
->e_xattrs
);
167 if (ep
->e_type
== LEAF
) {
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
;
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.
195 nodeupdates(name
, ino
, type
)
200 struct entry
*ep
, *np
, *ip
;
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
))
221 * Check to see if the name exists, and if the name is a link.
223 np
= lookupname(name
);
226 ip
= lookupino(np
->e_ino
);
228 (void) fprintf(stderr
,
229 gettext("corrupted symbol table\n"));
236 * Check to see if the inode exists, and if one of its links
237 * corresponds to the name (if one was found).
242 for (ep
= ip
->e_links
; ep
!= NIL
; ep
= ep
->e_links
) {
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
250 if (ip
->e_flags
& EXTRACT
) {
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
) {
284 gettext("name/inode conflict, mktempname %s\n"),
291 if ((key
& ONTAPE
) &&
292 (((key
& INOFND
) && ip
->e_type
!= type
) ||
293 ((key
& NAMEFND
) && np
->e_type
!= type
)))
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.
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.
311 /* LINTED: result fits into a short */
313 dprintf(stdout
, "[%s] %s: %s\n", keyval(key
), name
,
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.
329 case ONTAPE
|NAMEFND
|MODECHG
:
330 if (lookuptype
== LINK
|| key
== (ONTAPE
|NAMEFND
)) {
335 * Create a temporary node only if MODECHG.
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)
348 ep
= addentry(name
, ino
, type
);
351 /* LINTED: result fits into a short */
352 ep
->e_flags
|= NEW
|KEEP
;
353 dprintf(stdout
, "[%s] %s: %s\n", keyval(key
), name
,
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.
369 if (type
== LEAF
&& (ip
->e_flags
& KEEP
) == 0) {
370 /* LINTED: result fits into a short */
371 ip
->e_flags
|= EXTRACT
;
375 if ((ip
->e_flags
& KEEP
) == 0) {
376 renameit(myname(ip
), name
);
378 /* LINTED: result fits into a short */
380 dprintf(stdout
, "[%s] %s: %s\n", keyval(key
), name
,
384 if (ip
->e_type
== NODE
) {
386 (void) fprintf(stderr
, gettext(
387 "deleted hard link %s to directory %s\n"),
391 ep
= addentry(name
, ino
, type
|LINK
);
392 /* LINTED: result fits into a short */
394 dprintf(stdout
, "[%s] %s: %s|LINK\n", keyval(key
), name
,
399 * A previously known file which is to be updated.
401 case ONTAPE
|INOFND
|NAMEFND
:
403 * Extract leaf nodes.
406 /* LINTED: result fits into a short */
407 np
->e_flags
|= EXTRACT
;
409 /* LINTED: result fits into a short */
411 dprintf(stdout
, "[%s] %s: %s\n", keyval(key
), name
,
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
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"));
433 if (ip
->e_type
== LEAF
) {
434 /* changing from leaf to node */
437 ip
= addentry(name
, ino
, type
);
440 /* changing from node to leaf */
441 if ((ip
->e_flags
& TMPNAME
) == 0)
443 deleteino(ip
->e_ino
);
444 ip
->e_next
= removelist
;
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
,
455 * A hard link to a directory that has been removed.
459 dprintf(stdout
, gettext("[%s] %s: Extraneous name\n"),
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.
473 (void) fprintf(stderr
,
474 gettext("%s: (inode %lu) not found on volume\n"),
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
:
485 (void) fprintf(stderr
, "[%s] %s: %s\n",
486 keyval(key
), name
, gettext("inconsistent state"));
491 * These states "cannot" arise for any state of the symbol table.
496 (void) fprintf(stderr
, "[%s] %s: %s\n",
497 keyval(key
), name
, gettext("impossible state"));
505 * Calculate the active flags in a key.
511 static char keybuf
[32];
513 /* Note longest case is everything except |NIL */
515 (void) strcpy(keybuf
, "|NIL");
518 (void) strcat(keybuf
, "|ONTAPE");
520 (void) strcat(keybuf
, "|INOFND");
522 (void) strcat(keybuf
, "|NAMEFND");
524 (void) strcat(keybuf
, "|MODECHG");
529 * Find unreferenced link names.
538 struct entry
*ep
, *np
;
541 vprintf(stdout
, gettext("Find unreferenced names.\n"));
542 for (i
= ROOTINO
; i
< maxino
; i
++) {
544 if (ep
== NIL
|| ep
->e_type
== LEAF
|| BIT(i
, dumpmap
) == 0)
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"),
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"),
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
591 struct entry
*ep
, **prev
;
594 vprintf(stdout
, gettext("Remove old nodes (directories).\n"));
598 for (ep
= removelist
; ep
!= NIL
; ep
= *prev
) {
599 if (ep
->e_entries
!= NIL
) {
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.
618 createleaves(symtabfile
)
622 char name
[MAXCOMPLEXLEN
];
626 if (command
== 'R') {
627 vprintf(stdout
, gettext("Continue extraction of new leaves\n"));
629 vprintf(stdout
, gettext("Extract new leaves.\n"));
630 dumpsymtable(symtabfile
, volno
);
632 first
= lowerbnd(ROOTINO
);
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
);
650 (void) fprintf(stderr
,
651 gettext("%d: bad first\n"), first
);
654 (void) fprintf(stderr
,
655 gettext("%s: not found on volume\n"),
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"),
675 ep
= lookupino(curfile
.ino
);
677 (void) fprintf(stderr
,
678 gettext("unknown file on volume\n"));
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
691 if ((ep
->e_flags
& EXTRACT
) != 0) {
692 char *sname
= savename(ep
->e_name
);
693 complexcpy(name
, myname(ep
), MAXCOMPLEXLEN
);
695 (void) extractfile(name
);
696 movexattrs(myname(ep
), name
);
698 freename(ep
->e_name
);
700 ep
->e_namlen
= strlen(ep
->e_name
);
701 /* LINTED: result fits into a short */
702 ep
->e_flags
&= ~REMOVED
;
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
714 if (curvol
!= volno
) {
715 dumpsymtable(symtabfile
, 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.
733 ino_t first
, next
, last
;
737 vprintf(stdout
, gettext("Extract requested files\n"));
738 first
= lowerbnd(ROOTINO
);
739 last
= upperbnd(maxino
- 1);
740 nextvol
= volnumber(first
);
742 curfile
.action
= SKIP
;
748 first
= lowerbnd(first
);
749 last
= upperbnd(last
);
751 * Check to see if any files remain to be extracted
756 * If a map of inode numbers to tape volumes is
757 * available, then select the next volume to be read.
760 nextvol
= volnumber(first
);
761 if (nextvol
!= volno
) {
762 curfile
.action
= UNKNOWN
;
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
;
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
);
786 while (next
> curfile
.ino
&& volno
== curvol
)
790 } while (volno
== curvol
+ 1);
792 * If volume change out of order occurred the
793 * current state must be recalculated
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
);
810 (void) fprintf(stderr
,
811 gettext("corrupted symbol table\n"));
814 (void) fprintf(stderr
,
815 gettext("%s: not found on volume\n"),
817 /* LINTED: result fits into a short */
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
);
828 (void) fprintf(stderr
,
829 gettext("corrupted symbol table\n"));
832 (void) extractfile(myname(ep
));
833 /* LINTED: result fits into a short */
851 struct entry
*np
, *ep
;
857 vprintf(stdout
, gettext("Add links\n"));
858 for (i
= ROOTINO
; i
< maxino
; i
++) {
862 to
= savename(myname(ep
));
863 for (np
= ep
->e_links
; np
!= NIL
; np
= np
->e_links
) {
864 if ((np
->e_flags
& NEW
) == 0)
866 resolve(myname(np
), &dfd
, &from
);
867 if (dfd
!= AT_FDCWD
) {
868 if (fchdir(dfd
) < 0) {
870 (void) fprintf(stderr
,
871 gettext("%s->%s: link failed: %s\n"),
872 from
, to
, strerror(saverr
));
877 if (ep
->e_type
== NODE
) {
878 (void) lf_linkit(to
, from
, SYMLINK
);
880 (void) lf_linkit(to
, from
, HARDLINK
);
882 /* LINTED: result fits into a short */
884 if (dfd
!= AT_FDCWD
) {
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.
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.
928 verifyfile(name
, ino
, type
)
933 struct entry
*np
, *ep
;
936 ep
= lookupname(name
);
938 (void) fprintf(stderr
,
939 gettext("Warning: missing name %s\n"), name
);
945 for (; np
!= NIL
; np
= np
->e_links
)
949 (void) fprintf(stderr
, gettext("missing inumber %d\n"), ino
);
952 if (ep
->e_type
== LEAF
&& type
!= LEAF
)
953 badentry(ep
, gettext("type should be LEAF"));
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.
967 struct entry
*np
= ep
;
971 for (np
= ep
->e_entries
; np
!= NIL
; np
= np
->e_sibling
) {
972 if (np
->e_type
== NODE
) {
975 np
->e_flags
|= REMOVED
;
979 ep
->e_flags
|= REMOVED
;
984 * Move all the extended attributes associated with orig to
985 * the file named by the second argument (targ).
988 movexattrs(orig
, targ
)
993 int fromfd
, fromdir
, tofd
, todir
, tfd
;
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 */
1004 if ((fromfd
= openat64(tfd
, from
, O_RDONLY
|O_NONBLOCK
)) == -1) {
1005 fprintf(stderr
, gettext("%s: cannot move attributes: "), from
);
1007 if (tfd
!= AT_FDCWD
) (void) close(tfd
);
1011 if (fpathconf(fromfd
, _PC_XATTR_EXISTS
) != 1) {
1012 /* no attributes to move */
1013 if (tfd
!= AT_FDCWD
) (void) close(tfd
);
1016 if ((fromdir
= openat64(fromfd
, ".",
1017 O_RDONLY
|O_NONBLOCK
|O_XATTR
)) == -1) {
1018 fprintf(stderr
, gettext("%s: cannot access attributes: "),
1021 if (tfd
!= AT_FDCWD
) (void) close(tfd
);
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
);
1033 if (tfd
!= AT_FDCWD
) (void) close(tfd
);
1036 if ((tfd
= dup(fromdir
)) == -1 ||
1037 (dirp
= fdopendir(tfd
)) == NULL
) {
1039 gettext("%s: cannot allocate DIR structure to attribute directory: "),
1042 if (tfd
!= -1) (void) close(tfd
);
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'))
1051 if ((renameat(fromdir
, dp
->d_name
, todir
, dp
->d_name
)) == -1) {
1053 gettext("%s: cannot move attribute %s: "),
1060 (void) close(fromfd
);
1064 (void) closedir(dirp
);
1066 (void) close(fromdir
);
1068 (void) close(todir
);