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.
15 #pragma ident "%Z%%M% %I% %E% SMI"
18 /* undef MAXNAMLEN to prevent compiler warnings about redef in dirent.h */
23 static char *keyval(int);
24 static void removexattrs(struct entry
*);
25 static void movexattrs(char *, char *);
27 static char *keyval();
28 static void removexattrs();
29 static void movexattrs();
33 * This implements the 't' option.
34 * List entries on the tape.
37 listfile(name
, ino
, type
)
42 long descend
= hflag
? GOOD
: FAIL
;
44 if (BIT(ino
, dumpmap
) == 0) {
47 vprintf(stdout
, "%s", type
== LEAF
? gettext("leaf") : gettext("dir "));
48 (void) fprintf(stdout
, "%10lu\t%s\n", ino
, name
);
53 * This implements the 'x' option.
54 * Request that new entries be extracted.
57 addfile(name
, ino
, type
)
63 long descend
= hflag
? GOOD
: FAIL
;
66 /* Don't know if ino_t is long or long long, so be safe w/ *printf() */
68 if (BIT(ino
, dumpmap
) == 0) {
70 dprintf(stdout
, gettext(
71 "%s: not on the volume\n"), name
);
73 dprintf(stdout
, gettext(
74 "inode %llu: not on the volume\n"),
80 (void) snprintf(buf
, sizeof (buf
), "./%llu", (u_longlong_t
)ino
);
81 buf
[sizeof (buf
) - 1] = '\0';
84 (void) genliteraldir(name
, ino
);
90 if (strcmp(name
, myname(ep
)) == 0) {
91 /* LINTED: result fits into a short */
97 ep
= addentry(name
, ino
, type
);
100 /* LINTED: result fits into a short */
106 * This is used by the 'i' option to undo previous requests made by addfile.
107 * Delete entries from the request queue.
111 deletefile(name
, ino
, type
)
116 long descend
= hflag
? GOOD
: FAIL
;
119 if (BIT(ino
, dumpmap
) == 0) {
124 /* LINTED: result fits into a short */
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.
151 removeoldleaves(void)
159 vprintf(stdout
, gettext("Mark entries to be removed.\n"));
160 for (i
= ROOTINO
+ 1; i
< maxino
; i
++) {
167 dprintf(stdout
, gettext("%s: REMOVE\n"), myname(ep
));
168 removexattrs(ep
->e_xattrs
);
169 if (ep
->e_type
== LEAF
) {
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
;
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.
197 nodeupdates(name
, ino
, type
)
202 struct entry
*ep
, *np
, *ip
;
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
))
223 * Check to see if the name exists, and if the name is a link.
225 np
= lookupname(name
);
228 ip
= lookupino(np
->e_ino
);
230 (void) fprintf(stderr
,
231 gettext("corrupted symbol table\n"));
238 * Check to see if the inode exists, and if one of its links
239 * corresponds to the name (if one was found).
244 for (ep
= ip
->e_links
; ep
!= NIL
; ep
= ep
->e_links
) {
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
252 if (ip
->e_flags
& EXTRACT
) {
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
) {
286 gettext("name/inode conflict, mktempname %s\n"),
293 if ((key
& ONTAPE
) &&
294 (((key
& INOFND
) && ip
->e_type
!= type
) ||
295 ((key
& NAMEFND
) && np
->e_type
!= type
)))
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.
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.
313 /* LINTED: result fits into a short */
315 dprintf(stdout
, "[%s] %s: %s\n", keyval(key
), name
,
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.
331 case ONTAPE
|NAMEFND
|MODECHG
:
332 if (lookuptype
== LINK
|| key
== (ONTAPE
|NAMEFND
)) {
337 * Create a temporary node only if MODECHG.
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)
350 ep
= addentry(name
, ino
, type
);
353 /* LINTED: result fits into a short */
354 ep
->e_flags
|= NEW
|KEEP
;
355 dprintf(stdout
, "[%s] %s: %s\n", keyval(key
), name
,
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.
371 if (type
== LEAF
&& (ip
->e_flags
& KEEP
) == 0) {
372 /* LINTED: result fits into a short */
373 ip
->e_flags
|= EXTRACT
;
377 if ((ip
->e_flags
& KEEP
) == 0) {
378 renameit(myname(ip
), name
);
380 /* LINTED: result fits into a short */
382 dprintf(stdout
, "[%s] %s: %s\n", keyval(key
), name
,
386 if (ip
->e_type
== NODE
) {
388 (void) fprintf(stderr
, gettext(
389 "deleted hard link %s to directory %s\n"),
393 ep
= addentry(name
, ino
, type
|LINK
);
394 /* LINTED: result fits into a short */
396 dprintf(stdout
, "[%s] %s: %s|LINK\n", keyval(key
), name
,
401 * A previously known file which is to be updated.
403 case ONTAPE
|INOFND
|NAMEFND
:
405 * Extract leaf nodes.
408 /* LINTED: result fits into a short */
409 np
->e_flags
|= EXTRACT
;
411 /* LINTED: result fits into a short */
413 dprintf(stdout
, "[%s] %s: %s\n", keyval(key
), name
,
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
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"));
435 if (ip
->e_type
== LEAF
) {
436 /* changing from leaf to node */
439 ip
= addentry(name
, ino
, type
);
442 /* changing from node to leaf */
443 if ((ip
->e_flags
& TMPNAME
) == 0)
445 deleteino(ip
->e_ino
);
446 ip
->e_next
= removelist
;
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
,
457 * A hard link to a directory that has been removed.
461 dprintf(stdout
, gettext("[%s] %s: Extraneous name\n"),
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.
475 (void) fprintf(stderr
,
476 gettext("%s: (inode %lu) not found on volume\n"),
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
:
487 (void) fprintf(stderr
, "[%s] %s: %s\n",
488 keyval(key
), name
, gettext("inconsistent state"));
493 * These states "cannot" arise for any state of the symbol table.
498 (void) fprintf(stderr
, "[%s] %s: %s\n",
499 keyval(key
), name
, gettext("impossible state"));
507 * Calculate the active flags in a key.
513 static char keybuf
[32];
515 /* Note longest case is everything except |NIL */
517 (void) strcpy(keybuf
, "|NIL");
520 (void) strcat(keybuf
, "|ONTAPE");
522 (void) strcat(keybuf
, "|INOFND");
524 (void) strcat(keybuf
, "|NAMEFND");
526 (void) strcat(keybuf
, "|MODECHG");
531 * Find unreferenced link names.
540 struct entry
*ep
, *np
;
543 vprintf(stdout
, gettext("Find unreferenced names.\n"));
544 for (i
= ROOTINO
; i
< maxino
; i
++) {
546 if (ep
== NIL
|| ep
->e_type
== LEAF
|| BIT(i
, dumpmap
) == 0)
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"),
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"),
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
593 struct entry
*ep
, **prev
;
596 vprintf(stdout
, gettext("Remove old nodes (directories).\n"));
600 for (ep
= removelist
; ep
!= NIL
; ep
= *prev
) {
601 if (ep
->e_entries
!= NIL
) {
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.
620 createleaves(symtabfile
)
624 char name
[MAXCOMPLEXLEN
];
628 if (command
== 'R') {
629 vprintf(stdout
, gettext("Continue extraction of new leaves\n"));
631 vprintf(stdout
, gettext("Extract new leaves.\n"));
632 dumpsymtable(symtabfile
, volno
);
634 first
= lowerbnd(ROOTINO
);
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
);
652 (void) fprintf(stderr
,
653 gettext("%d: bad first\n"), first
);
656 (void) fprintf(stderr
,
657 gettext("%s: not found on volume\n"),
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"),
677 ep
= lookupino(curfile
.ino
);
679 (void) fprintf(stderr
,
680 gettext("unknown file on volume\n"));
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
693 if ((ep
->e_flags
& EXTRACT
) != 0) {
694 char *sname
= savename(ep
->e_name
);
695 complexcpy(name
, myname(ep
), MAXCOMPLEXLEN
);
697 (void) extractfile(name
);
698 movexattrs(myname(ep
), name
);
700 freename(ep
->e_name
);
702 ep
->e_namlen
= strlen(ep
->e_name
);
703 /* LINTED: result fits into a short */
704 ep
->e_flags
&= ~REMOVED
;
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
716 if (curvol
!= volno
) {
717 dumpsymtable(symtabfile
, 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.
735 ino_t first
, next
, last
;
739 vprintf(stdout
, gettext("Extract requested files\n"));
740 first
= lowerbnd(ROOTINO
);
741 last
= upperbnd(maxino
- 1);
742 nextvol
= volnumber(first
);
744 curfile
.action
= SKIP
;
750 first
= lowerbnd(first
);
751 last
= upperbnd(last
);
753 * Check to see if any files remain to be extracted
758 * If a map of inode numbers to tape volumes is
759 * available, then select the next volume to be read.
762 nextvol
= volnumber(first
);
763 if (nextvol
!= volno
) {
764 curfile
.action
= UNKNOWN
;
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
;
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
);
788 while (next
> curfile
.ino
&& volno
== curvol
)
792 } while (volno
== curvol
+ 1);
794 * If volume change out of order occurred the
795 * current state must be recalculated
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
);
812 (void) fprintf(stderr
,
813 gettext("corrupted symbol table\n"));
816 (void) fprintf(stderr
,
817 gettext("%s: not found on volume\n"),
819 /* LINTED: result fits into a short */
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
);
830 (void) fprintf(stderr
,
831 gettext("corrupted symbol table\n"));
834 (void) extractfile(myname(ep
));
835 /* LINTED: result fits into a short */
853 struct entry
*np
, *ep
;
859 vprintf(stdout
, gettext("Add links\n"));
860 for (i
= ROOTINO
; i
< maxino
; i
++) {
864 to
= savename(myname(ep
));
865 for (np
= ep
->e_links
; np
!= NIL
; np
= np
->e_links
) {
866 if ((np
->e_flags
& NEW
) == 0)
868 resolve(myname(np
), &dfd
, &from
);
869 if (dfd
!= AT_FDCWD
) {
870 if (fchdir(dfd
) < 0) {
872 (void) fprintf(stderr
,
873 gettext("%s->%s: link failed: %s\n"),
874 from
, to
, strerror(saverr
));
879 if (ep
->e_type
== NODE
) {
880 (void) lf_linkit(to
, from
, SYMLINK
);
882 (void) lf_linkit(to
, from
, HARDLINK
);
884 /* LINTED: result fits into a short */
886 if (dfd
!= AT_FDCWD
) {
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.
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.
930 verifyfile(name
, ino
, type
)
935 struct entry
*np
, *ep
;
938 ep
= lookupname(name
);
940 (void) fprintf(stderr
,
941 gettext("Warning: missing name %s\n"), name
);
947 for (; np
!= NIL
; np
= np
->e_links
)
951 (void) fprintf(stderr
, gettext("missing inumber %d\n"), ino
);
954 if (ep
->e_type
== LEAF
&& type
!= LEAF
)
955 badentry(ep
, gettext("type should be LEAF"));
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.
969 struct entry
*np
= ep
;
973 for (np
= ep
->e_entries
; np
!= NIL
; np
= np
->e_sibling
) {
974 if (np
->e_type
== NODE
) {
977 np
->e_flags
|= REMOVED
;
981 ep
->e_flags
|= REMOVED
;
986 * Move all the extended attributes associated with orig to
987 * the file named by the second argument (targ).
990 movexattrs(orig
, targ
)
995 int fromfd
, fromdir
, tofd
, todir
, tfd
;
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 */
1006 if ((fromfd
= openat64(tfd
, from
, O_RDONLY
|O_NONBLOCK
)) == -1) {
1007 fprintf(stderr
, gettext("%s: cannot move attributes: "), from
);
1009 if (tfd
!= AT_FDCWD
) (void) close(tfd
);
1013 if (fpathconf(fromfd
, _PC_XATTR_EXISTS
) != 1) {
1014 /* no attributes to move */
1015 if (tfd
!= AT_FDCWD
) (void) close(tfd
);
1018 if ((fromdir
= openat64(fromfd
, ".",
1019 O_RDONLY
|O_NONBLOCK
|O_XATTR
)) == -1) {
1020 fprintf(stderr
, gettext("%s: cannot access attributes: "),
1023 if (tfd
!= AT_FDCWD
) (void) close(tfd
);
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
);
1035 if (tfd
!= AT_FDCWD
) (void) close(tfd
);
1038 if ((tfd
= dup(fromdir
)) == -1 ||
1039 (dirp
= fdopendir(tfd
)) == NULL
) {
1041 gettext("%s: cannot allocate DIR structure to attribute directory: "),
1044 if (tfd
!= -1) (void) close(tfd
);
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'))
1053 if ((renameat(fromdir
, dp
->d_name
, todir
, dp
->d_name
)) == -1) {
1055 gettext("%s: cannot move attribute %s: "),
1062 (void) close(fromfd
);
1066 (void) closedir(dirp
);
1068 (void) close(fromdir
);
1070 (void) close(todir
);