121168Sdist /*
261536Sbostic * Copyright (c) 1983, 1993
361536Sbostic * The Regents of the University of California. All rights reserved.
436105Sbostic *
542709Sbostic * %sccs.include.redist.c%
621168Sdist */
721168Sdist
810313Smckusick #ifndef lint
9*67777Smckusick static char sccsid[] = "@(#)restore.c 8.3 (Berkeley) 09/13/94";
1036105Sbostic #endif /* not lint */
1110313Smckusick
1256567Sbostic #include <sys/types.h>
1356567Sbostic #include <sys/stat.h>
1456567Sbostic
1556567Sbostic #include <ufs/ufs/dinode.h>
1656567Sbostic
1756567Sbostic #include <stdio.h>
1856567Sbostic #include <string.h>
1956567Sbostic
2010313Smckusick #include "restore.h"
2156567Sbostic #include "extern.h"
2210313Smckusick
2356567Sbostic static char *keyval __P((int));
2456567Sbostic
2510313Smckusick /*
2611742Smckusick * This implements the 't' option.
2711742Smckusick * List entries on the tape.
2810313Smckusick */
2911742Smckusick long
listfile(name,ino,type)3010313Smckusick listfile(name, ino, type)
3110313Smckusick char *name;
3210313Smckusick ino_t ino;
3310313Smckusick int type;
3410313Smckusick {
3511742Smckusick long descend = hflag ? GOOD : FAIL;
3610313Smckusick
3756427Smckusick if (TSTINO(ino, dumpmap) == 0)
3811742Smckusick return (descend);
3911439Smckusick vprintf(stdout, "%s", type == LEAF ? "leaf" : "dir ");
4010313Smckusick fprintf(stdout, "%10d\t%s\n", ino, name);
4111742Smckusick return (descend);
4210313Smckusick }
4310313Smckusick
4410313Smckusick /*
4511742Smckusick * This implements the 'x' option.
4611742Smckusick * Request that new entries be extracted.
4710313Smckusick */
4811742Smckusick long
addfile(name,ino,type)4910313Smckusick addfile(name, ino, type)
5010313Smckusick char *name;
5110313Smckusick ino_t ino;
5210313Smckusick int type;
5310313Smckusick {
5410313Smckusick register struct entry *ep;
5511742Smckusick long descend = hflag ? GOOD : FAIL;
5610313Smckusick char buf[100];
5710313Smckusick
5856427Smckusick if (TSTINO(ino, dumpmap) == 0) {
5934426Smckusick dprintf(stdout, "%s: not on the tape\n", name);
6011742Smckusick return (descend);
6110313Smckusick }
62*67777Smckusick if (ino == WINO && command == 'i' && !vflag)
63*67777Smckusick return (descend);
6411323Smckusick if (!mflag) {
6511742Smckusick (void) sprintf(buf, "./%u", ino);
6611323Smckusick name = buf;
6711323Smckusick if (type == NODE) {
6811439Smckusick (void) genliteraldir(name, ino);
6911742Smckusick return (descend);
7011323Smckusick }
7110313Smckusick }
7211323Smckusick ep = lookupino(ino);
7356567Sbostic if (ep != NULL) {
7411994Smckusick if (strcmp(name, myname(ep)) == 0) {
7511994Smckusick ep->e_flags |= NEW;
7611742Smckusick return (descend);
7711994Smckusick }
7811323Smckusick type |= LINK;
7911323Smckusick }
8011323Smckusick ep = addentry(name, ino, type);
8111994Smckusick if (type == NODE)
8211323Smckusick newnode(ep);
8311994Smckusick ep->e_flags |= NEW;
8411994Smckusick return (descend);
8511994Smckusick }
8611994Smckusick
8711994Smckusick /*
8811994Smckusick * This is used by the 'i' option to undo previous requests made by addfile.
8911994Smckusick * Delete entries from the request queue.
9011994Smckusick */
9111994Smckusick /* ARGSUSED */
9211994Smckusick long
deletefile(name,ino,type)9311994Smckusick deletefile(name, ino, type)
9411994Smckusick char *name;
9511994Smckusick ino_t ino;
9611994Smckusick int type;
9711994Smckusick {
9811994Smckusick long descend = hflag ? GOOD : FAIL;
9911994Smckusick struct entry *ep;
10011994Smckusick
10156427Smckusick if (TSTINO(ino, dumpmap) == 0)
10211742Smckusick return (descend);
10367756Smckusick ep = lookupname(name);
10467756Smckusick if (ep != NULL) {
10511994Smckusick ep->e_flags &= ~NEW;
10667756Smckusick ep->e_flags |= REMOVED;
10767756Smckusick if (ep->e_type != NODE)
10867756Smckusick freeentry(ep);
10967756Smckusick }
11011742Smckusick return (descend);
11110313Smckusick }
11210313Smckusick
11311742Smckusick /*
11411742Smckusick * The following four routines implement the incremental
11511742Smckusick * restore algorithm. The first removes old entries, the second
11611742Smckusick * does renames and calculates the extraction list, the third
11711742Smckusick * cleans up link names missed by the first two, and the final
11811742Smckusick * one deletes old directories.
11911742Smckusick *
12011742Smckusick * Directories cannot be immediately deleted, as they may have
12111742Smckusick * other files in them which need to be moved out first. As
12211742Smckusick * directories to be deleted are found, they are put on the
12311742Smckusick * following deletion list. After all deletions and renames
12411742Smckusick * are done, this list is actually deleted.
12511742Smckusick */
12611742Smckusick static struct entry *removelist;
12711742Smckusick
12810313Smckusick /*
129*67777Smckusick * Remove invalid whiteouts from the old tree.
13011742Smckusick * Remove unneeded leaves from the old tree.
13111742Smckusick * Remove directories from the lookup chains.
13211742Smckusick */
13356567Sbostic void
removeoldleaves()13411742Smckusick removeoldleaves()
13511742Smckusick {
136*67777Smckusick register struct entry *ep, *nextep;
137*67777Smckusick register ino_t i, mydirino;
13811742Smckusick
13911742Smckusick vprintf(stdout, "Mark entries to be removed.\n");
140*67777Smckusick if (ep = lookupino(WINO)) {
141*67777Smckusick vprintf(stdout, "Delete whiteouts\n");
142*67777Smckusick for ( ; ep != NULL; ep = nextep) {
143*67777Smckusick nextep = ep->e_links;
144*67777Smckusick mydirino = ep->e_parent->e_ino;
145*67777Smckusick /*
146*67777Smckusick * We remove all whiteouts that are in directories
147*67777Smckusick * that have been removed or that have been dumped.
148*67777Smckusick */
149*67777Smckusick if (TSTINO(mydirino, usedinomap) &&
150*67777Smckusick !TSTINO(mydirino, dumpmap))
151*67777Smckusick continue;
152*67777Smckusick delwhiteout(ep);
153*67777Smckusick freeentry(ep);
154*67777Smckusick }
155*67777Smckusick }
15611742Smckusick for (i = ROOTINO + 1; i < maxino; i++) {
15711742Smckusick ep = lookupino(i);
15856567Sbostic if (ep == NULL)
15911742Smckusick continue;
160*67777Smckusick if (TSTINO(i, usedinomap))
16111742Smckusick continue;
16256567Sbostic for ( ; ep != NULL; ep = ep->e_links) {
16311742Smckusick dprintf(stdout, "%s: REMOVE\n", myname(ep));
16411742Smckusick if (ep->e_type == LEAF) {
16511742Smckusick removeleaf(ep);
16611742Smckusick freeentry(ep);
16711742Smckusick } else {
16811742Smckusick mktempname(ep);
16911742Smckusick deleteino(ep->e_ino);
17011742Smckusick ep->e_next = removelist;
17111742Smckusick removelist = ep;
17211742Smckusick }
17311742Smckusick }
17411742Smckusick }
17511742Smckusick }
17611742Smckusick
17711742Smckusick /*
17811439Smckusick * For each directory entry on the incremental tape, determine which
17911439Smckusick * category it falls into as follows:
18010313Smckusick * KEEP - entries that are to be left alone.
18110313Smckusick * NEW - new entries to be added.
18210313Smckusick * EXTRACT - files that must be updated with new contents.
18311439Smckusick * LINK - new links to be added.
18411439Smckusick * Renames are done at the same time.
18510313Smckusick */
18611742Smckusick long
nodeupdates(name,ino,type)18711439Smckusick nodeupdates(name, ino, type)
18810313Smckusick char *name;
18910313Smckusick ino_t ino;
19010313Smckusick int type;
19110313Smckusick {
19210313Smckusick register struct entry *ep, *np, *ip;
19311742Smckusick long descend = GOOD;
19412454Smckusick int lookuptype = 0;
19510313Smckusick int key = 0;
19610313Smckusick /* key values */
19711742Smckusick # define ONTAPE 0x1 /* inode is on the tape */
19811742Smckusick # define INOFND 0x2 /* inode already exists */
19911742Smckusick # define NAMEFND 0x4 /* name already exists */
20011742Smckusick # define MODECHG 0x8 /* mode of inode changed */
20110313Smckusick
20210313Smckusick /*
20310313Smckusick * This routine is called once for each element in the
20411402Smckusick * directory hierarchy, with a full path name.
20510313Smckusick * The "type" value is incorrectly specified as LEAF for
20610313Smckusick * directories that are not on the dump tape.
20712454Smckusick *
20812454Smckusick * Check to see if the file is on the tape.
20910313Smckusick */
21056427Smckusick if (TSTINO(ino, dumpmap))
21110313Smckusick key |= ONTAPE;
21212454Smckusick /*
21312454Smckusick * Check to see if the name exists, and if the name is a link.
21412454Smckusick */
21510313Smckusick np = lookupname(name);
21656567Sbostic if (np != NULL) {
21710313Smckusick key |= NAMEFND;
21812454Smckusick ip = lookupino(np->e_ino);
21912454Smckusick if (ip == NULL)
22012454Smckusick panic("corrupted symbol table\n");
22112454Smckusick if (ip != np)
22212454Smckusick lookuptype = LINK;
22312454Smckusick }
22412454Smckusick /*
22555368Smckusick * Check to see if the inode exists, and if one of its links
22655368Smckusick * corresponds to the name (if one was found).
22712454Smckusick */
22810313Smckusick ip = lookupino(ino);
22956567Sbostic if (ip != NULL) {
23010313Smckusick key |= INOFND;
23156567Sbostic for (ep = ip->e_links; ep != NULL; ep = ep->e_links) {
23255368Smckusick if (ep == np) {
23355368Smckusick ip = ep;
23455368Smckusick break;
23555368Smckusick }
23655368Smckusick }
23755368Smckusick }
23811742Smckusick /*
23912454Smckusick * If both a name and an inode are found, but they do not
24012454Smckusick * correspond to the same file, then both the inode that has
24112454Smckusick * been found and the inode corresponding to the name that
24212454Smckusick * has been found need to be renamed. The current pathname
24312454Smckusick * is the new name for the inode that has been found. Since
24412454Smckusick * all files to be deleted have already been removed, the
24512454Smckusick * named file is either a now unneeded link, or it must live
24612454Smckusick * under a new name in this dump level. If it is a link, it
24712454Smckusick * can be removed. If it is not a link, it is given a
24812454Smckusick * temporary name in anticipation that it will be renamed
24912454Smckusick * when it is later found by inode number.
25011742Smckusick */
25111439Smckusick if (((key & (INOFND|NAMEFND)) == (INOFND|NAMEFND)) && ip != np) {
25212454Smckusick if (lookuptype == LINK) {
25312454Smckusick removeleaf(np);
25412454Smckusick freeentry(np);
25512454Smckusick } else {
25612454Smckusick dprintf(stdout, "name/inode conflict, mktempname %s\n",
25712454Smckusick myname(np));
25812454Smckusick mktempname(np);
25912454Smckusick }
26056567Sbostic np = NULL;
26110313Smckusick key &= ~NAMEFND;
26210313Smckusick }
26310313Smckusick if ((key & ONTAPE) &&
26410313Smckusick (((key & INOFND) && ip->e_type != type) ||
26511898Smckusick ((key & NAMEFND) && np->e_type != type)))
26610313Smckusick key |= MODECHG;
26711742Smckusick
26811742Smckusick /*
26911742Smckusick * Decide on the disposition of the file based on its flags.
27011742Smckusick * Note that we have already handled the case in which
27111742Smckusick * a name and inode are found that correspond to different files.
27211742Smckusick * Thus if both NAMEFND and INOFND are set then ip == np.
27311742Smckusick */
27410313Smckusick switch (key) {
27510313Smckusick
27611742Smckusick /*
27711742Smckusick * A previously existing file has been found.
27811742Smckusick * Mark it as KEEP so that other links to the inode can be
27911742Smckusick * detected, and so that it will not be reclaimed by the search
28011742Smckusick * for unreferenced names.
28111742Smckusick */
28210313Smckusick case INOFND|NAMEFND:
28310313Smckusick ip->e_flags |= KEEP;
28411898Smckusick dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
28511898Smckusick flagvalues(ip));
28610313Smckusick break;
28710313Smckusick
28811742Smckusick /*
28912445Smckusick * A file on the tape has a name which is the same as a name
29012445Smckusick * corresponding to a different file in the previous dump.
29112445Smckusick * Since all files to be deleted have already been removed,
29212454Smckusick * this file is either a now unneeded link, or it must live
29312454Smckusick * under a new name in this dump level. If it is a link, it
29412454Smckusick * can simply be removed. If it is not a link, it is given a
29512454Smckusick * temporary name in anticipation that it will be renamed
29612454Smckusick * when it is later found by inode number (see INOFND case
29712454Smckusick * below). The entry is then treated as a new file.
29812445Smckusick */
29912445Smckusick case ONTAPE|NAMEFND:
30012445Smckusick case ONTAPE|NAMEFND|MODECHG:
30112454Smckusick if (lookuptype == LINK) {
30212454Smckusick removeleaf(np);
30312454Smckusick freeentry(np);
30412454Smckusick } else {
30512454Smckusick mktempname(np);
30612454Smckusick }
30712445Smckusick /* fall through */
30812445Smckusick
30912445Smckusick /*
31011742Smckusick * A previously non-existent file.
31111742Smckusick * Add it to the file system, and request its extraction.
31211742Smckusick * If it is a directory, create it immediately.
31311742Smckusick * (Since the name is unused there can be no conflict)
31411742Smckusick */
31510313Smckusick case ONTAPE:
31610313Smckusick ep = addentry(name, ino, type);
31711439Smckusick if (type == NODE)
31811439Smckusick newnode(ep);
31911994Smckusick ep->e_flags |= NEW|KEEP;
32011898Smckusick dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
32111898Smckusick flagvalues(ep));
32210313Smckusick break;
32310313Smckusick
32411742Smckusick /*
32511742Smckusick * A file with the same inode number, but a different
32611742Smckusick * name has been found. If the other name has not already
32711742Smckusick * been found (indicated by the KEEP flag, see above) then
32811742Smckusick * this must be a new name for the file, and it is renamed.
32911742Smckusick * If the other name has been found then this must be a
33011742Smckusick * link to the file. Hard links to directories are not
33111742Smckusick * permitted, and are either deleted or converted to
33211742Smckusick * symbolic links. Finally, if the file is on the tape,
33311742Smckusick * a request is made to extract it.
33411742Smckusick */
33510313Smckusick case ONTAPE|INOFND:
33611898Smckusick if (type == LEAF && (ip->e_flags & KEEP) == 0)
33711439Smckusick ip->e_flags |= EXTRACT;
33810313Smckusick /* fall through */
33910313Smckusick case INOFND:
34011742Smckusick if ((ip->e_flags & KEEP) == 0) {
34111742Smckusick renameit(myname(ip), name);
34211742Smckusick moveentry(ip, name);
34311742Smckusick ip->e_flags |= KEEP;
34412220Smckusick dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
34511898Smckusick flagvalues(ip));
34610313Smckusick break;
34710313Smckusick }
34811742Smckusick if (ip->e_type == NODE) {
34911742Smckusick descend = FAIL;
35011742Smckusick fprintf(stderr,
35111742Smckusick "deleted hard link %s to directory %s\n",
35211742Smckusick name, myname(ip));
35311742Smckusick break;
35411742Smckusick }
35511742Smckusick ep = addentry(name, ino, type|LINK);
35611742Smckusick ep->e_flags |= NEW;
35711898Smckusick dprintf(stdout, "[%s] %s: %s|LINK\n", keyval(key), name,
35811898Smckusick flagvalues(ep));
35910313Smckusick break;
36010313Smckusick
36111742Smckusick /*
36255368Smckusick * A previously known file which is to be updated. If it is a link,
36355368Smckusick * then all names referring to the previous file must be removed
36455368Smckusick * so that the subset of them that remain can be recreated.
36511742Smckusick */
36610313Smckusick case ONTAPE|INOFND|NAMEFND:
36755368Smckusick if (lookuptype == LINK) {
36855368Smckusick removeleaf(np);
36955368Smckusick freeentry(np);
37055368Smckusick ep = addentry(name, ino, type|LINK);
37155368Smckusick if (type == NODE)
37255368Smckusick newnode(ep);
37355368Smckusick ep->e_flags |= NEW|KEEP;
37455368Smckusick dprintf(stdout, "[%s] %s: %s|LINK\n", keyval(key), name,
37555368Smckusick flagvalues(ep));
37655368Smckusick break;
37755368Smckusick }
37812454Smckusick if (type == LEAF && lookuptype != LINK)
37911439Smckusick np->e_flags |= EXTRACT;
38011439Smckusick np->e_flags |= KEEP;
38111898Smckusick dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
38211898Smckusick flagvalues(np));
38310313Smckusick break;
38410313Smckusick
38511742Smckusick /*
38611742Smckusick * An inode is being reused in a completely different way.
38711742Smckusick * Normally an extract can simply do an "unlink" followed
38811742Smckusick * by a "creat". Here we must do effectively the same
38911742Smckusick * thing. The complications arise because we cannot really
39011742Smckusick * delete a directory since it may still contain files
39111742Smckusick * that we need to rename, so we delete it from the symbol
39211742Smckusick * table, and put it on the list to be deleted eventually.
39311742Smckusick * Conversely if a directory is to be created, it must be
39411742Smckusick * done immediately, rather than waiting until the
39511742Smckusick * extraction phase.
39611742Smckusick */
39710313Smckusick case ONTAPE|INOFND|MODECHG:
39810313Smckusick case ONTAPE|INOFND|NAMEFND|MODECHG:
39911439Smckusick if (ip->e_flags & KEEP) {
40011439Smckusick badentry(ip, "cannot KEEP and change modes");
40111439Smckusick break;
40211439Smckusick }
40311439Smckusick if (ip->e_type == LEAF) {
40411439Smckusick /* changing from leaf to node */
40511439Smckusick removeleaf(ip);
40611439Smckusick freeentry(ip);
40711439Smckusick ip = addentry(name, ino, type);
40811439Smckusick newnode(ip);
40911439Smckusick } else {
41011439Smckusick /* changing from node to leaf */
41112457Smckusick if ((ip->e_flags & TMPNAME) == 0)
41212457Smckusick mktempname(ip);
41311439Smckusick deleteino(ip->e_ino);
41411439Smckusick ip->e_next = removelist;
41511439Smckusick removelist = ip;
41611439Smckusick ip = addentry(name, ino, type);
41711439Smckusick }
41811994Smckusick ip->e_flags |= NEW|KEEP;
41911898Smckusick dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
42011898Smckusick flagvalues(ip));
42110313Smckusick break;
42210313Smckusick
42311742Smckusick /*
42411742Smckusick * A hard link to a diirectory that has been removed.
42511742Smckusick * Ignore it.
42611742Smckusick */
42711742Smckusick case NAMEFND:
42811898Smckusick dprintf(stdout, "[%s] %s: Extraneous name\n", keyval(key),
42911898Smckusick name);
43011742Smckusick descend = FAIL;
43111742Smckusick break;
43211742Smckusick
43311742Smckusick /*
43426487Smckusick * If we find a directory entry for a file that is not on
43526487Smckusick * the tape, then we must have found a file that was created
43626487Smckusick * while the dump was in progress. Since we have no contents
43726487Smckusick * for it, we discard the name knowing that it will be on the
43826487Smckusick * next incremental tape.
43926487Smckusick */
44056567Sbostic case NULL:
44131541Smckusick fprintf(stderr, "%s: (inode %d) not found on tape\n",
44231541Smckusick name, ino);
44326487Smckusick break;
44426487Smckusick
44526487Smckusick /*
44611742Smckusick * If any of these arise, something is grievously wrong with
44711742Smckusick * the current state of the symbol table.
44811742Smckusick */
44910313Smckusick case INOFND|NAMEFND|MODECHG:
45010313Smckusick case NAMEFND|MODECHG:
45110313Smckusick case INOFND|MODECHG:
45239941Sbostic fprintf(stderr, "[%s] %s: inconsistent state\n", keyval(key),
45339941Sbostic name);
45410313Smckusick break;
45510313Smckusick
45611742Smckusick /*
45711742Smckusick * These states "cannot" arise for any state of the symbol table.
45811742Smckusick */
45910313Smckusick case ONTAPE|MODECHG:
46010313Smckusick case MODECHG:
46110313Smckusick default:
46211898Smckusick panic("[%s] %s: impossible state\n", keyval(key), name);
46310313Smckusick break;
46410313Smckusick }
46511742Smckusick return (descend);
46610313Smckusick }
46710313Smckusick
46810313Smckusick /*
46911898Smckusick * Calculate the active flags in a key.
47011898Smckusick */
47156567Sbostic static char *
keyval(key)47211898Smckusick keyval(key)
47311898Smckusick int key;
47411898Smckusick {
47511898Smckusick static char keybuf[32];
47611898Smckusick
47711994Smckusick (void) strcpy(keybuf, "|NIL");
47811898Smckusick keybuf[0] = '\0';
47911898Smckusick if (key & ONTAPE)
48011898Smckusick (void) strcat(keybuf, "|ONTAPE");
48111898Smckusick if (key & INOFND)
48211898Smckusick (void) strcat(keybuf, "|INOFND");
48311898Smckusick if (key & NAMEFND)
48411898Smckusick (void) strcat(keybuf, "|NAMEFND");
48511898Smckusick if (key & MODECHG)
48611898Smckusick (void) strcat(keybuf, "|MODECHG");
48711898Smckusick return (&keybuf[1]);
48811898Smckusick }
48911898Smckusick
49011898Smckusick /*
49111742Smckusick * Find unreferenced link names.
49210313Smckusick */
49356567Sbostic void
findunreflinks()49411439Smckusick findunreflinks()
49510313Smckusick {
49610313Smckusick register struct entry *ep, *np;
49711439Smckusick register ino_t i;
49810313Smckusick
49910313Smckusick vprintf(stdout, "Find unreferenced names.\n");
50010313Smckusick for (i = ROOTINO; i < maxino; i++) {
50110313Smckusick ep = lookupino(i);
50256567Sbostic if (ep == NULL || ep->e_type == LEAF || TSTINO(i, dumpmap) == 0)
50310313Smckusick continue;
50456567Sbostic for (np = ep->e_entries; np != NULL; np = np->e_sibling) {
50510313Smckusick if (np->e_flags == 0) {
50611439Smckusick dprintf(stdout,
50711439Smckusick "%s: remove unreferenced name\n",
50811439Smckusick myname(np));
50911439Smckusick removeleaf(np);
51011439Smckusick freeentry(np);
51110313Smckusick }
51210313Smckusick }
51310313Smckusick }
51412457Smckusick /*
51512457Smckusick * Any leaves remaining in removed directories is unreferenced.
51612457Smckusick */
51756567Sbostic for (ep = removelist; ep != NULL; ep = ep->e_next) {
51856567Sbostic for (np = ep->e_entries; np != NULL; np = np->e_sibling) {
51912457Smckusick if (np->e_type == LEAF) {
52012457Smckusick if (np->e_flags != 0)
52112457Smckusick badentry(np, "unreferenced with flags");
52212457Smckusick dprintf(stdout,
52312457Smckusick "%s: remove unreferenced name\n",
52412457Smckusick myname(np));
52512457Smckusick removeleaf(np);
52612457Smckusick freeentry(np);
52712457Smckusick }
52812457Smckusick }
52912457Smckusick }
53010313Smckusick }
53110313Smckusick
53210313Smckusick /*
53311742Smckusick * Remove old nodes (directories).
53411742Smckusick * Note that this routine runs in O(N*D) where:
53511742Smckusick * N is the number of directory entries to be removed.
53611742Smckusick * D is the maximum depth of the tree.
53711742Smckusick * If N == D this can be quite slow. If the list were
53811742Smckusick * topologically sorted, the deletion could be done in
53911742Smckusick * time O(N).
54010313Smckusick */
54156567Sbostic void
removeoldnodes()54211439Smckusick removeoldnodes()
54310313Smckusick {
54411439Smckusick register struct entry *ep, **prev;
54511439Smckusick long change;
54610313Smckusick
54711439Smckusick vprintf(stdout, "Remove old nodes (directories).\n");
54811439Smckusick do {
54911439Smckusick change = 0;
55011439Smckusick prev = &removelist;
55156567Sbostic for (ep = removelist; ep != NULL; ep = *prev) {
55256567Sbostic if (ep->e_entries != NULL) {
55311439Smckusick prev = &ep->e_next;
55411128Smckusick continue;
55510313Smckusick }
55611439Smckusick *prev = ep->e_next;
55711439Smckusick removenode(ep);
55811439Smckusick freeentry(ep);
55911439Smckusick change++;
56010313Smckusick }
56111439Smckusick } while (change);
56256567Sbostic for (ep = removelist; ep != NULL; ep = ep->e_next)
56311439Smckusick badentry(ep, "cannot remove, non-empty");
56410313Smckusick }
56510313Smckusick
56610313Smckusick /*
56711742Smckusick * This is the routine used to extract files for the 'r' command.
56811742Smckusick * Extract new leaves.
56910313Smckusick */
57056567Sbostic void
createleaves(symtabfile)57110313Smckusick createleaves(symtabfile)
57210313Smckusick char *symtabfile;
57310313Smckusick {
57410313Smckusick register struct entry *ep;
57510313Smckusick ino_t first;
57610313Smckusick long curvol;
57710313Smckusick
57811439Smckusick if (command == 'R') {
57910313Smckusick vprintf(stdout, "Continue extraction of new leaves\n");
58011439Smckusick } else {
58110313Smckusick vprintf(stdout, "Extract new leaves.\n");
58211439Smckusick dumpsymtable(symtabfile, volno);
58311439Smckusick }
58410313Smckusick first = lowerbnd(ROOTINO);
58510313Smckusick curvol = volno;
58610313Smckusick while (curfile.ino < maxino) {
58711439Smckusick first = lowerbnd(first);
58811742Smckusick /*
58911742Smckusick * If the next available file is not the one which we
59011742Smckusick * expect then we have missed one or more files. Since
59111742Smckusick * we do not request files that were not on the tape,
59211924Smckusick * the lost files must have been due to a tape read error,
59311924Smckusick * or a file that was removed while the dump was in progress.
59411742Smckusick */
59510313Smckusick while (first < curfile.ino) {
59610313Smckusick ep = lookupino(first);
59756567Sbostic if (ep == NULL)
59810313Smckusick panic("%d: bad first\n", first);
59910313Smckusick fprintf(stderr, "%s: not found on tape\n", myname(ep));
60011439Smckusick ep->e_flags &= ~(NEW|EXTRACT);
60111439Smckusick first = lowerbnd(first);
60210313Smckusick }
60311924Smckusick /*
60411924Smckusick * If we find files on the tape that have no corresponding
60511924Smckusick * directory entries, then we must have found a file that
60611924Smckusick * was created while the dump was in progress. Since we have
60711924Smckusick * no name for it, we discard it knowing that it will be
60811924Smckusick * on the next incremental tape.
60911924Smckusick */
61011922Smckusick if (first != curfile.ino) {
61111922Smckusick fprintf(stderr, "expected next file %d, got %d\n",
61210313Smckusick first, curfile.ino);
61311922Smckusick skipfile();
61411922Smckusick goto next;
61511922Smckusick }
61610313Smckusick ep = lookupino(curfile.ino);
61756567Sbostic if (ep == NULL)
61810313Smckusick panic("unknown file on tape\n");
61911439Smckusick if ((ep->e_flags & (NEW|EXTRACT)) == 0)
62010313Smckusick badentry(ep, "unexpected file on tape");
62111742Smckusick /*
62211742Smckusick * If the file is to be extracted, then the old file must
62311742Smckusick * be removed since its type may change from one leaf type
62411742Smckusick * to another (eg "file" to "character special").
62511742Smckusick */
62611439Smckusick if ((ep->e_flags & EXTRACT) != 0) {
62711439Smckusick removeleaf(ep);
62811439Smckusick ep->e_flags &= ~REMOVED;
62911439Smckusick }
63011742Smckusick (void) extractfile(myname(ep));
63111439Smckusick ep->e_flags &= ~(NEW|EXTRACT);
63211742Smckusick /*
63311742Smckusick * We checkpoint the restore after every tape reel, so
63411742Smckusick * as to simplify the amount of work re quired by the
63511742Smckusick * 'R' command.
63611742Smckusick */
63711922Smckusick next:
63810313Smckusick if (curvol != volno) {
63910313Smckusick dumpsymtable(symtabfile, volno);
64011439Smckusick skipmaps();
64110313Smckusick curvol = volno;
64210313Smckusick }
64310313Smckusick }
64410313Smckusick }
64510313Smckusick
64610313Smckusick /*
64712454Smckusick * This is the routine used to extract files for the 'x' and 'i' commands.
64812454Smckusick * Efficiently extract a subset of the files on a tape.
64910313Smckusick */
65056567Sbostic void
createfiles()65110313Smckusick createfiles()
65210313Smckusick {
65310313Smckusick register ino_t first, next, last;
65410313Smckusick register struct entry *ep;
65510313Smckusick long curvol;
65610313Smckusick
65710313Smckusick vprintf(stdout, "Extract requested files\n");
65811310Smckusick curfile.action = SKIP;
65911313Smckusick getvol((long)1);
66011402Smckusick skipmaps();
66111402Smckusick skipdirs();
66210313Smckusick first = lowerbnd(ROOTINO);
66311310Smckusick last = upperbnd(maxino - 1);
66410313Smckusick for (;;) {
66510313Smckusick first = lowerbnd(first);
66610313Smckusick last = upperbnd(last);
66711402Smckusick /*
66811402Smckusick * Check to see if any files remain to be extracted
66911402Smckusick */
67010313Smckusick if (first > last)
67110313Smckusick return;
67211402Smckusick /*
67311402Smckusick * Reject any volumes with inodes greater
67411402Smckusick * than the last one needed
67511402Smckusick */
67610313Smckusick while (curfile.ino > last) {
67710313Smckusick curfile.action = SKIP;
67810313Smckusick getvol((long)0);
67911402Smckusick skipmaps();
68011402Smckusick skipdirs();
68110313Smckusick }
68211402Smckusick /*
68311402Smckusick * Decide on the next inode needed.
68411402Smckusick * Skip across the inodes until it is found
68511402Smckusick * or an out of order volume change is encountered
68611402Smckusick */
68710313Smckusick next = lowerbnd(curfile.ino);
68810313Smckusick do {
68910313Smckusick curvol = volno;
69010313Smckusick while (next > curfile.ino && volno == curvol)
69110313Smckusick skipfile();
69211402Smckusick skipmaps();
69311402Smckusick skipdirs();
69410313Smckusick } while (volno == curvol + 1);
69511402Smckusick /*
69611402Smckusick * If volume change out of order occurred the
69711994Smckusick * current state must be recalculated
69811402Smckusick */
69910313Smckusick if (volno != curvol)
70010313Smckusick continue;
70111402Smckusick /*
70211402Smckusick * If the current inode is greater than the one we were
70311402Smckusick * looking for then we missed the one we were looking for.
70411402Smckusick * Since we only attempt to extract files listed in the
70511994Smckusick * dump map, the lost files must have been due to a tape
70611994Smckusick * read error, or a file that was removed while the dump
70711994Smckusick * was in progress. Thus we report all requested files
70811994Smckusick * between the one we were looking for, and the one we
70911994Smckusick * found as missing, and delete their request flags.
71011402Smckusick */
71110313Smckusick while (next < curfile.ino) {
71210313Smckusick ep = lookupino(next);
71356567Sbostic if (ep == NULL)
71410313Smckusick panic("corrupted symbol table\n");
71510313Smckusick fprintf(stderr, "%s: not found on tape\n", myname(ep));
71610313Smckusick ep->e_flags &= ~NEW;
71711402Smckusick next = lowerbnd(next);
71810313Smckusick }
71911402Smckusick /*
72011402Smckusick * The current inode is the one that we are looking for,
72111402Smckusick * so extract it per its requested name.
72211402Smckusick */
72311313Smckusick if (next == curfile.ino && next <= last) {
72410313Smckusick ep = lookupino(next);
72556567Sbostic if (ep == NULL)
72610313Smckusick panic("corrupted symbol table\n");
72711742Smckusick (void) extractfile(myname(ep));
72810313Smckusick ep->e_flags &= ~NEW;
72916228Smckusick if (volno != curvol)
73016228Smckusick skipmaps();
73110313Smckusick }
73210313Smckusick }
73310313Smckusick }
73410313Smckusick
73510313Smckusick /*
73611742Smckusick * Add links.
73710313Smckusick */
73856567Sbostic void
createlinks()73910313Smckusick createlinks()
74010313Smckusick {
74110313Smckusick register struct entry *np, *ep;
74211439Smckusick register ino_t i;
74310313Smckusick char name[BUFSIZ];
74410313Smckusick
745*67777Smckusick if (ep = lookupino(WINO)) {
746*67777Smckusick vprintf(stdout, "Add whiteouts\n");
747*67777Smckusick for ( ; ep != NULL; ep = ep->e_links) {
748*67777Smckusick if ((ep->e_flags & NEW) == 0)
749*67777Smckusick continue;
750*67777Smckusick (void) addwhiteout(myname(ep));
751*67777Smckusick ep->e_flags &= ~NEW;
752*67777Smckusick }
753*67777Smckusick }
75410313Smckusick vprintf(stdout, "Add links\n");
75510313Smckusick for (i = ROOTINO; i < maxino; i++) {
75610313Smckusick ep = lookupino(i);
75756567Sbostic if (ep == NULL)
75810313Smckusick continue;
75956567Sbostic for (np = ep->e_links; np != NULL; np = np->e_links) {
76011924Smckusick if ((np->e_flags & NEW) == 0)
76111924Smckusick continue;
76211439Smckusick (void) strcpy(name, myname(ep));
76310313Smckusick if (ep->e_type == NODE) {
76415780Smckusick (void) linkit(name, myname(np), SYMLINK);
76510313Smckusick } else {
76615780Smckusick (void) linkit(name, myname(np), HARDLINK);
76710313Smckusick }
76811310Smckusick np->e_flags &= ~NEW;
76910313Smckusick }
77010313Smckusick }
77110313Smckusick }
77210313Smckusick
77310313Smckusick /*
77411742Smckusick * Check the symbol table.
77511742Smckusick * We do this to insure that all the requested work was done, and
77611742Smckusick * that no temporary names remain.
77710313Smckusick */
77856567Sbostic void
checkrestore()77910313Smckusick checkrestore()
78010313Smckusick {
78110313Smckusick register struct entry *ep;
78211439Smckusick register ino_t i;
78310313Smckusick
78410313Smckusick vprintf(stdout, "Check the symbol table.\n");
785*67777Smckusick for (i = WINO; i < maxino; i++) {
78656567Sbostic for (ep = lookupino(i); ep != NULL; ep = ep->e_links) {
78710313Smckusick ep->e_flags &= ~KEEP;
78812454Smckusick if (ep->e_type == NODE)
78918007Smckusick ep->e_flags &= ~(NEW|EXISTED);
79010313Smckusick if (ep->e_flags != NULL)
79110313Smckusick badentry(ep, "incomplete operations");
79210313Smckusick }
79310313Smckusick }
79410313Smckusick }
79510313Smckusick
79610313Smckusick /*
79711742Smckusick * Compare with the directory structure on the tape
79811742Smckusick * A paranoid check that things are as they should be.
79910313Smckusick */
80011742Smckusick long
verifyfile(name,ino,type)80110313Smckusick verifyfile(name, ino, type)
80210313Smckusick char *name;
80310313Smckusick ino_t ino;
80410313Smckusick int type;
80510313Smckusick {
80610313Smckusick struct entry *np, *ep;
80711742Smckusick long descend = GOOD;
80810313Smckusick
80910313Smckusick ep = lookupname(name);
81056567Sbostic if (ep == NULL) {
81111742Smckusick fprintf(stderr, "Warning: missing name %s\n", name);
81211742Smckusick return (FAIL);
81311742Smckusick }
81411742Smckusick np = lookupino(ino);
81511742Smckusick if (np != ep)
81611742Smckusick descend = FAIL;
81756567Sbostic for ( ; np != NULL; np = np->e_links)
81810313Smckusick if (np == ep)
81910313Smckusick break;
82056567Sbostic if (np == NULL)
82110313Smckusick panic("missing inumber %d\n", ino);
82210313Smckusick if (ep->e_type == LEAF && type != LEAF)
82310313Smckusick badentry(ep, "type should be LEAF");
82411742Smckusick return (descend);
82510313Smckusick }
826