132021Spc /*
232021Spc * Copyright (c) 1983 Regents of the University of California.
332021Spc * All rights reserved. The Berkeley software License Agreement
432021Spc * specifies the terms and conditions for redistribution.
532021Spc */
632021Spc
732021Spc #ifndef lint
8*32024Spc static char sccsid[] = "@(#)restore.c 5.3 (Berkeley) 6/18/87";
932021Spc #endif not lint
1032021Spc
1132021Spc #include "restore.h"
1232021Spc
1332021Spc /*
1432021Spc * This implements the 't' option.
1532021Spc * List entries on the tape.
1632021Spc */
1732021Spc long
listfile(name,ino,type)1832021Spc listfile(name, ino, type)
1932021Spc char *name;
2032021Spc ino_t ino;
2132021Spc int type;
2232021Spc {
2332021Spc long descend = hflag ? GOOD : FAIL;
2432021Spc
2532021Spc if (BIT(ino, dumpmap) == 0) {
2632021Spc return (descend);
2732021Spc }
2832021Spc vprintf(stdout, "%s", type == LEAF ? "leaf" : "dir ");
2932021Spc fprintf(stdout, "%10d\t%s\n", ino, name);
3032021Spc return (descend);
3132021Spc }
3232021Spc
3332021Spc /*
3432021Spc * This implements the 'x' option.
3532021Spc * Request that new entries be extracted.
3632021Spc */
3732021Spc long
addfile(name,ino,type)3832021Spc addfile(name, ino, type)
3932021Spc char *name;
4032021Spc ino_t ino;
4132021Spc int type;
4232021Spc {
4332021Spc register struct entry *ep;
4432021Spc long descend = hflag ? GOOD : FAIL;
4532021Spc char buf[100];
4632021Spc
4732021Spc if (BIT(ino, dumpmap) == 0) {
4832021Spc vprintf(stdout, "%s: not on the tape\n", name);
4932021Spc return (descend);
5032021Spc }
5132021Spc if (!mflag) {
5232021Spc (void) sprintf(buf, "./%u", ino);
5332021Spc name = buf;
5432021Spc if (type == NODE) {
5532021Spc (void) genliteraldir(name, ino);
5632021Spc return (descend);
5732021Spc }
5832021Spc }
5932021Spc ep = lookupino(ino);
6032021Spc if (ep != NIL) {
6132021Spc if (strcmp(name, myname(ep)) == 0) {
6232021Spc ep->e_flags |= NEW;
6332021Spc return (descend);
6432021Spc }
6532021Spc type |= LINK;
6632021Spc }
6732021Spc ep = addentry(name, ino, type);
6832021Spc if (type == NODE)
6932021Spc newnode(ep);
7032021Spc ep->e_flags |= NEW;
7132021Spc return (descend);
7232021Spc }
7332021Spc
7432021Spc /*
7532021Spc * This is used by the 'i' option to undo previous requests made by addfile.
7632021Spc * Delete entries from the request queue.
7732021Spc */
7832021Spc /* ARGSUSED */
7932021Spc long
deletefile(name,ino,type)8032021Spc deletefile(name, ino, type)
8132021Spc char *name;
8232021Spc ino_t ino;
8332021Spc int type;
8432021Spc {
8532021Spc long descend = hflag ? GOOD : FAIL;
8632021Spc struct entry *ep;
8732021Spc
8832021Spc if (BIT(ino, dumpmap) == 0) {
8932021Spc return (descend);
9032021Spc }
9132021Spc ep = lookupino(ino);
9232021Spc if (ep != NIL)
9332021Spc ep->e_flags &= ~NEW;
9432021Spc return (descend);
9532021Spc }
9632021Spc
9732021Spc /*
9832021Spc * The following four routines implement the incremental
9932021Spc * restore algorithm. The first removes old entries, the second
10032021Spc * does renames and calculates the extraction list, the third
10132021Spc * cleans up link names missed by the first two, and the final
10232021Spc * one deletes old directories.
10332021Spc *
10432021Spc * Directories cannot be immediately deleted, as they may have
10532021Spc * other files in them which need to be moved out first. As
10632021Spc * directories to be deleted are found, they are put on the
10732021Spc * following deletion list. After all deletions and renames
10832021Spc * are done, this list is actually deleted.
10932021Spc */
11032021Spc static struct entry *removelist;
11132021Spc
11232021Spc /*
11332021Spc * Remove unneeded leaves from the old tree.
11432021Spc * Remove directories from the lookup chains.
11532021Spc */
removeoldleaves()11632021Spc removeoldleaves()
11732021Spc {
11832021Spc register struct entry *ep;
11932021Spc register ino_t i;
12032021Spc
12132021Spc vprintf(stdout, "Mark entries to be removed.\n");
12232021Spc for (i = ROOTINO + 1; i < maxino; i++) {
12332021Spc ep = lookupino(i);
12432021Spc if (ep == NIL)
12532021Spc continue;
12632021Spc if (BIT(i, clrimap))
12732021Spc continue;
12832021Spc for ( ; ep != NIL; ep = ep->e_links) {
12932021Spc dprintf(stdout, "%s: REMOVE\n", myname(ep));
13032021Spc if (ep->e_type == LEAF) {
13132021Spc removeleaf(ep);
13232021Spc freeentry(ep);
13332021Spc } else {
13432021Spc mktempname(ep);
13532021Spc deleteino(ep->e_ino);
13632021Spc ep->e_next = removelist;
13732021Spc removelist = ep;
13832021Spc }
13932021Spc }
14032021Spc }
14132021Spc }
14232021Spc
14332021Spc /*
14432021Spc * For each directory entry on the incremental tape, determine which
14532021Spc * category it falls into as follows:
14632021Spc * KEEP - entries that are to be left alone.
14732021Spc * NEW - new entries to be added.
14832021Spc * EXTRACT - files that must be updated with new contents.
14932021Spc * LINK - new links to be added.
15032021Spc * Renames are done at the same time.
15132021Spc */
15232021Spc long
nodeupdates(name,ino,type)15332021Spc nodeupdates(name, ino, type)
15432021Spc char *name;
15532021Spc ino_t ino;
15632021Spc int type;
15732021Spc {
15832021Spc register struct entry *ep, *np, *ip;
15932021Spc long descend = GOOD;
16032021Spc int lookuptype = 0;
16132021Spc int key = 0;
16232021Spc /* key values */
16332021Spc # define ONTAPE 0x1 /* inode is on the tape */
16432021Spc # define INOFND 0x2 /* inode already exists */
16532021Spc # define NAMEFND 0x4 /* name already exists */
16632021Spc # define MODECHG 0x8 /* mode of inode changed */
16732021Spc extern char *keyval();
16832021Spc
16932021Spc /*
17032021Spc * This routine is called once for each element in the
17132021Spc * directory hierarchy, with a full path name.
17232021Spc * The "type" value is incorrectly specified as LEAF for
17332021Spc * directories that are not on the dump tape.
17432021Spc *
17532021Spc * Check to see if the file is on the tape.
17632021Spc */
17732021Spc if (BIT(ino, dumpmap))
17832021Spc key |= ONTAPE;
17932021Spc /*
18032021Spc * Check to see if the name exists, and if the name is a link.
18132021Spc */
18232021Spc np = lookupname(name);
18332021Spc if (np != NIL) {
18432021Spc key |= NAMEFND;
18532021Spc ip = lookupino(np->e_ino);
18632021Spc if (ip == NULL)
18732021Spc panic("corrupted symbol table\n");
18832021Spc if (ip != np)
18932021Spc lookuptype = LINK;
19032021Spc }
19132021Spc /*
19232021Spc * Check to see if the inode exists, and if one of its links
19332021Spc * corresponds to the name (if one was found).
19432021Spc */
19532021Spc ip = lookupino(ino);
19632021Spc if (ip != NIL) {
19732021Spc key |= INOFND;
19832021Spc for (ep = ip->e_links; ep != NIL; ep = ep->e_links) {
19932021Spc if (ep == np) {
20032021Spc ip = ep;
20132021Spc break;
20232021Spc }
20332021Spc }
20432021Spc }
20532021Spc /*
20632021Spc * If both a name and an inode are found, but they do not
20732021Spc * correspond to the same file, then both the inode that has
20832021Spc * been found and the inode corresponding to the name that
20932021Spc * has been found need to be renamed. The current pathname
21032021Spc * is the new name for the inode that has been found. Since
21132021Spc * all files to be deleted have already been removed, the
21232021Spc * named file is either a now unneeded link, or it must live
21332021Spc * under a new name in this dump level. If it is a link, it
21432021Spc * can be removed. If it is not a link, it is given a
21532021Spc * temporary name in anticipation that it will be renamed
21632021Spc * when it is later found by inode number.
21732021Spc */
21832021Spc if (((key & (INOFND|NAMEFND)) == (INOFND|NAMEFND)) && ip != np) {
21932021Spc if (lookuptype == LINK) {
22032021Spc removeleaf(np);
22132021Spc freeentry(np);
22232021Spc } else {
22332021Spc dprintf(stdout, "name/inode conflict, mktempname %s\n",
22432021Spc myname(np));
22532021Spc mktempname(np);
22632021Spc }
22732021Spc np = NIL;
22832021Spc key &= ~NAMEFND;
22932021Spc }
23032021Spc if ((key & ONTAPE) &&
23132021Spc (((key & INOFND) && ip->e_type != type) ||
23232021Spc ((key & NAMEFND) && np->e_type != type)))
23332021Spc key |= MODECHG;
23432021Spc
23532021Spc /*
23632021Spc * Decide on the disposition of the file based on its flags.
23732021Spc * Note that we have already handled the case in which
23832021Spc * a name and inode are found that correspond to different files.
23932021Spc * Thus if both NAMEFND and INOFND are set then ip == np.
24032021Spc */
24132021Spc switch (key) {
24232021Spc
24332021Spc /*
24432021Spc * A previously existing file has been found.
24532021Spc * Mark it as KEEP so that other links to the inode can be
24632021Spc * detected, and so that it will not be reclaimed by the search
24732021Spc * for unreferenced names.
24832021Spc */
24932021Spc case INOFND|NAMEFND:
25032021Spc ip->e_flags |= KEEP;
25132021Spc dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
25232021Spc flagvalues(ip));
25332021Spc break;
25432021Spc
25532021Spc /*
25632021Spc * A file on the tape has a name which is the same as a name
25732021Spc * corresponding to a different file in the previous dump.
25832021Spc * Since all files to be deleted have already been removed,
25932021Spc * this file is either a now unneeded link, or it must live
26032021Spc * under a new name in this dump level. If it is a link, it
26132021Spc * can simply be removed. If it is not a link, it is given a
26232021Spc * temporary name in anticipation that it will be renamed
26332021Spc * when it is later found by inode number (see INOFND case
26432021Spc * below). The entry is then treated as a new file.
26532021Spc */
26632021Spc case ONTAPE|NAMEFND:
26732021Spc case ONTAPE|NAMEFND|MODECHG:
26832021Spc if (lookuptype == LINK) {
26932021Spc removeleaf(np);
27032021Spc freeentry(np);
27132021Spc } else {
27232021Spc mktempname(np);
27332021Spc }
27432021Spc /* fall through */
27532021Spc
27632021Spc /*
27732021Spc * A previously non-existent file.
27832021Spc * Add it to the file system, and request its extraction.
27932021Spc * If it is a directory, create it immediately.
28032021Spc * (Since the name is unused there can be no conflict)
28132021Spc */
28232021Spc case ONTAPE:
28332021Spc ep = addentry(name, ino, type);
28432021Spc if (type == NODE)
28532021Spc newnode(ep);
28632021Spc ep->e_flags |= NEW|KEEP;
28732021Spc dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
28832021Spc flagvalues(ep));
28932021Spc break;
29032021Spc
29132021Spc /*
29232021Spc * A file with the same inode number, but a different
29332021Spc * name has been found. If the other name has not already
29432021Spc * been found (indicated by the KEEP flag, see above) then
29532021Spc * this must be a new name for the file, and it is renamed.
29632021Spc * If the other name has been found then this must be a
29732021Spc * link to the file. Hard links to directories are not
29832021Spc * permitted, and are either deleted or converted to
29932021Spc * symbolic links. Finally, if the file is on the tape,
30032021Spc * a request is made to extract it.
30132021Spc */
30232021Spc case ONTAPE|INOFND:
30332021Spc if (type == LEAF && (ip->e_flags & KEEP) == 0)
30432021Spc ip->e_flags |= EXTRACT;
30532021Spc /* fall through */
30632021Spc case INOFND:
30732021Spc if ((ip->e_flags & KEEP) == 0) {
30832021Spc renameit(myname(ip), name);
30932021Spc moveentry(ip, name);
31032021Spc ip->e_flags |= KEEP;
31132021Spc dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
31232021Spc flagvalues(ip));
31332021Spc break;
31432021Spc }
31532021Spc if (ip->e_type == NODE) {
31632021Spc descend = FAIL;
31732021Spc fprintf(stderr,
31832021Spc "deleted hard link %s to directory %s\n",
31932021Spc name, myname(ip));
32032021Spc break;
32132021Spc }
32232021Spc ep = addentry(name, ino, type|LINK);
32332021Spc ep->e_flags |= NEW;
32432021Spc dprintf(stdout, "[%s] %s: %s|LINK\n", keyval(key), name,
32532021Spc flagvalues(ep));
32632021Spc break;
32732021Spc
32832021Spc /*
32932021Spc * A previously known file which is to be updated.
33032021Spc */
33132021Spc case ONTAPE|INOFND|NAMEFND:
33232021Spc if (type == LEAF && lookuptype != LINK)
33332021Spc np->e_flags |= EXTRACT;
33432021Spc np->e_flags |= KEEP;
33532021Spc dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
33632021Spc flagvalues(np));
33732021Spc break;
33832021Spc
33932021Spc /*
34032021Spc * An inode is being reused in a completely different way.
34132021Spc * Normally an extract can simply do an "unlink" followed
34232021Spc * by a "creat". Here we must do effectively the same
34332021Spc * thing. The complications arise because we cannot really
34432021Spc * delete a directory since it may still contain files
34532021Spc * that we need to rename, so we delete it from the symbol
34632021Spc * table, and put it on the list to be deleted eventually.
34732021Spc * Conversely if a directory is to be created, it must be
34832021Spc * done immediately, rather than waiting until the
34932021Spc * extraction phase.
35032021Spc */
35132021Spc case ONTAPE|INOFND|MODECHG:
35232021Spc case ONTAPE|INOFND|NAMEFND|MODECHG:
35332021Spc if (ip->e_flags & KEEP) {
35432021Spc badentry(ip, "cannot KEEP and change modes");
35532021Spc break;
35632021Spc }
35732021Spc if (ip->e_type == LEAF) {
35832021Spc /* changing from leaf to node */
35932021Spc removeleaf(ip);
36032021Spc freeentry(ip);
36132021Spc ip = addentry(name, ino, type);
36232021Spc newnode(ip);
36332021Spc } else {
36432021Spc /* changing from node to leaf */
36532021Spc if ((ip->e_flags & TMPNAME) == 0)
36632021Spc mktempname(ip);
36732021Spc deleteino(ip->e_ino);
36832021Spc ip->e_next = removelist;
36932021Spc removelist = ip;
37032021Spc ip = addentry(name, ino, type);
37132021Spc }
37232021Spc ip->e_flags |= NEW|KEEP;
37332021Spc dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
37432021Spc flagvalues(ip));
37532021Spc break;
37632021Spc
37732021Spc /*
37832021Spc * A hard link to a diirectory that has been removed.
37932021Spc * Ignore it.
38032021Spc */
38132021Spc case NAMEFND:
38232021Spc dprintf(stdout, "[%s] %s: Extraneous name\n", keyval(key),
38332021Spc name);
38432021Spc descend = FAIL;
38532021Spc break;
38632021Spc
38732021Spc /*
38832021Spc * If we find a directory entry for a file that is not on
38932021Spc * the tape, then we must have found a file that was created
39032021Spc * while the dump was in progress. Since we have no contents
39132021Spc * for it, we discard the name knowing that it will be on the
39232021Spc * next incremental tape.
39332021Spc */
39432021Spc case NIL:
395*32024Spc fprintf(stderr, "%s: (inode %d) not found on tape\n",
396*32024Spc name, ino);
39732021Spc break;
39832021Spc
39932021Spc /*
40032021Spc * If any of these arise, something is grievously wrong with
40132021Spc * the current state of the symbol table.
40232021Spc */
40332021Spc case INOFND|NAMEFND|MODECHG:
40432021Spc case NAMEFND|MODECHG:
40532021Spc case INOFND|MODECHG:
40632021Spc panic("[%s] %s: inconsistent state\n", keyval(key), name);
40732021Spc break;
40832021Spc
40932021Spc /*
41032021Spc * These states "cannot" arise for any state of the symbol table.
41132021Spc */
41232021Spc case ONTAPE|MODECHG:
41332021Spc case MODECHG:
41432021Spc default:
41532021Spc panic("[%s] %s: impossible state\n", keyval(key), name);
41632021Spc break;
41732021Spc }
41832021Spc return (descend);
41932021Spc }
42032021Spc
42132021Spc /*
42232021Spc * Calculate the active flags in a key.
42332021Spc */
42432021Spc char *
keyval(key)42532021Spc keyval(key)
42632021Spc int key;
42732021Spc {
42832021Spc static char keybuf[32];
42932021Spc
43032021Spc (void) strcpy(keybuf, "|NIL");
43132021Spc keybuf[0] = '\0';
43232021Spc if (key & ONTAPE)
43332021Spc (void) strcat(keybuf, "|ONTAPE");
43432021Spc if (key & INOFND)
43532021Spc (void) strcat(keybuf, "|INOFND");
43632021Spc if (key & NAMEFND)
43732021Spc (void) strcat(keybuf, "|NAMEFND");
43832021Spc if (key & MODECHG)
43932021Spc (void) strcat(keybuf, "|MODECHG");
44032021Spc return (&keybuf[1]);
44132021Spc }
44232021Spc
44332021Spc /*
44432021Spc * Find unreferenced link names.
44532021Spc */
findunreflinks()44632021Spc findunreflinks()
44732021Spc {
44832021Spc register struct entry *ep, *np;
44932021Spc register ino_t i;
45032021Spc
45132021Spc vprintf(stdout, "Find unreferenced names.\n");
45232021Spc for (i = ROOTINO; i < maxino; i++) {
45332021Spc ep = lookupino(i);
45432021Spc if (ep == NIL || ep->e_type == LEAF || BIT(i, dumpmap) == 0)
45532021Spc continue;
45632021Spc for (np = ep->e_entries; np != NIL; np = np->e_sibling) {
45732021Spc if (np->e_flags == 0) {
45832021Spc dprintf(stdout,
45932021Spc "%s: remove unreferenced name\n",
46032021Spc myname(np));
46132021Spc removeleaf(np);
46232021Spc freeentry(np);
46332021Spc }
46432021Spc }
46532021Spc }
46632021Spc /*
46732021Spc * Any leaves remaining in removed directories is unreferenced.
46832021Spc */
46932021Spc for (ep = removelist; ep != NIL; ep = ep->e_next) {
47032021Spc for (np = ep->e_entries; np != NIL; np = np->e_sibling) {
47132021Spc if (np->e_type == LEAF) {
47232021Spc if (np->e_flags != 0)
47332021Spc badentry(np, "unreferenced with flags");
47432021Spc dprintf(stdout,
47532021Spc "%s: remove unreferenced name\n",
47632021Spc myname(np));
47732021Spc removeleaf(np);
47832021Spc freeentry(np);
47932021Spc }
48032021Spc }
48132021Spc }
48232021Spc }
48332021Spc
48432021Spc /*
48532021Spc * Remove old nodes (directories).
48632021Spc * Note that this routine runs in O(N*D) where:
48732021Spc * N is the number of directory entries to be removed.
48832021Spc * D is the maximum depth of the tree.
48932021Spc * If N == D this can be quite slow. If the list were
49032021Spc * topologically sorted, the deletion could be done in
49132021Spc * time O(N).
49232021Spc */
removeoldnodes()49332021Spc removeoldnodes()
49432021Spc {
49532021Spc register struct entry *ep, **prev;
49632021Spc long change;
49732021Spc
49832021Spc vprintf(stdout, "Remove old nodes (directories).\n");
49932021Spc do {
50032021Spc change = 0;
50132021Spc prev = &removelist;
50232021Spc for (ep = removelist; ep != NIL; ep = *prev) {
50332021Spc if (ep->e_entries != NIL) {
50432021Spc prev = &ep->e_next;
50532021Spc continue;
50632021Spc }
50732021Spc *prev = ep->e_next;
50832021Spc removenode(ep);
50932021Spc freeentry(ep);
51032021Spc change++;
51132021Spc }
51232021Spc } while (change);
51332021Spc for (ep = removelist; ep != NIL; ep = ep->e_next)
51432021Spc badentry(ep, "cannot remove, non-empty");
51532021Spc }
51632021Spc
51732021Spc /*
51832021Spc * This is the routine used to extract files for the 'r' command.
51932021Spc * Extract new leaves.
52032021Spc */
createleaves(symtabfile)52132021Spc createleaves(symtabfile)
52232021Spc char *symtabfile;
52332021Spc {
52432021Spc register struct entry *ep;
52532021Spc ino_t first;
52632021Spc long curvol;
52732021Spc
52832021Spc if (command == 'R') {
52932021Spc vprintf(stdout, "Continue extraction of new leaves\n");
53032021Spc } else {
53132021Spc vprintf(stdout, "Extract new leaves.\n");
53232021Spc dumpsymtable(symtabfile, volno);
53332021Spc }
53432021Spc first = lowerbnd(ROOTINO);
53532021Spc curvol = volno;
53632021Spc while (curfile.ino < maxino) {
53732021Spc first = lowerbnd(first);
53832021Spc /*
53932021Spc * If the next available file is not the one which we
54032021Spc * expect then we have missed one or more files. Since
54132021Spc * we do not request files that were not on the tape,
54232021Spc * the lost files must have been due to a tape read error,
54332021Spc * or a file that was removed while the dump was in progress.
54432021Spc */
54532021Spc while (first < curfile.ino) {
54632021Spc ep = lookupino(first);
54732021Spc if (ep == NIL)
54832021Spc panic("%d: bad first\n", first);
54932021Spc fprintf(stderr, "%s: not found on tape\n", myname(ep));
55032021Spc ep->e_flags &= ~(NEW|EXTRACT);
55132021Spc first = lowerbnd(first);
55232021Spc }
55332021Spc /*
55432021Spc * If we find files on the tape that have no corresponding
55532021Spc * directory entries, then we must have found a file that
55632021Spc * was created while the dump was in progress. Since we have
55732021Spc * no name for it, we discard it knowing that it will be
55832021Spc * on the next incremental tape.
55932021Spc */
56032021Spc if (first != curfile.ino) {
56132021Spc fprintf(stderr, "expected next file %d, got %d\n",
56232021Spc first, curfile.ino);
56332021Spc skipfile();
56432021Spc goto next;
56532021Spc }
56632021Spc ep = lookupino(curfile.ino);
56732021Spc if (ep == NIL)
56832021Spc panic("unknown file on tape\n");
56932021Spc if ((ep->e_flags & (NEW|EXTRACT)) == 0)
57032021Spc badentry(ep, "unexpected file on tape");
57132021Spc /*
57232021Spc * If the file is to be extracted, then the old file must
57332021Spc * be removed since its type may change from one leaf type
57432021Spc * to another (eg "file" to "character special").
57532021Spc */
57632021Spc if ((ep->e_flags & EXTRACT) != 0) {
57732021Spc removeleaf(ep);
57832021Spc ep->e_flags &= ~REMOVED;
57932021Spc }
58032021Spc (void) extractfile(myname(ep));
58132021Spc ep->e_flags &= ~(NEW|EXTRACT);
58232021Spc /*
58332021Spc * We checkpoint the restore after every tape reel, so
58432021Spc * as to simplify the amount of work re quired by the
58532021Spc * 'R' command.
58632021Spc */
58732021Spc next:
58832021Spc if (curvol != volno) {
58932021Spc dumpsymtable(symtabfile, volno);
59032021Spc skipmaps();
59132021Spc curvol = volno;
59232021Spc }
59332021Spc }
59432021Spc }
59532021Spc
59632021Spc /*
59732021Spc * This is the routine used to extract files for the 'x' and 'i' commands.
59832021Spc * Efficiently extract a subset of the files on a tape.
59932021Spc */
createfiles()60032021Spc createfiles()
60132021Spc {
60232021Spc register ino_t first, next, last;
60332021Spc register struct entry *ep;
60432021Spc long curvol;
60532021Spc
60632021Spc vprintf(stdout, "Extract requested files\n");
60732021Spc curfile.action = SKIP;
60832021Spc getvol((long)1);
60932021Spc skipmaps();
61032021Spc skipdirs();
61132021Spc first = lowerbnd(ROOTINO);
61232021Spc last = upperbnd(maxino - 1);
61332021Spc for (;;) {
61432021Spc first = lowerbnd(first);
61532021Spc last = upperbnd(last);
61632021Spc /*
61732021Spc * Check to see if any files remain to be extracted
61832021Spc */
61932021Spc if (first > last)
62032021Spc return;
62132021Spc /*
62232021Spc * Reject any volumes with inodes greater
62332021Spc * than the last one needed
62432021Spc */
62532021Spc while (curfile.ino > last) {
62632021Spc curfile.action = SKIP;
62732021Spc getvol((long)0);
62832021Spc skipmaps();
62932021Spc skipdirs();
63032021Spc }
63132021Spc /*
63232021Spc * Decide on the next inode needed.
63332021Spc * Skip across the inodes until it is found
63432021Spc * or an out of order volume change is encountered
63532021Spc */
63632021Spc next = lowerbnd(curfile.ino);
63732021Spc do {
63832021Spc curvol = volno;
63932021Spc while (next > curfile.ino && volno == curvol)
64032021Spc skipfile();
64132021Spc skipmaps();
64232021Spc skipdirs();
64332021Spc } while (volno == curvol + 1);
64432021Spc /*
64532021Spc * If volume change out of order occurred the
64632021Spc * current state must be recalculated
64732021Spc */
64832021Spc if (volno != curvol)
64932021Spc continue;
65032021Spc /*
65132021Spc * If the current inode is greater than the one we were
65232021Spc * looking for then we missed the one we were looking for.
65332021Spc * Since we only attempt to extract files listed in the
65432021Spc * dump map, the lost files must have been due to a tape
65532021Spc * read error, or a file that was removed while the dump
65632021Spc * was in progress. Thus we report all requested files
65732021Spc * between the one we were looking for, and the one we
65832021Spc * found as missing, and delete their request flags.
65932021Spc */
66032021Spc while (next < curfile.ino) {
66132021Spc ep = lookupino(next);
66232021Spc if (ep == NIL)
66332021Spc panic("corrupted symbol table\n");
66432021Spc fprintf(stderr, "%s: not found on tape\n", myname(ep));
66532021Spc ep->e_flags &= ~NEW;
66632021Spc next = lowerbnd(next);
66732021Spc }
66832021Spc /*
66932021Spc * The current inode is the one that we are looking for,
67032021Spc * so extract it per its requested name.
67132021Spc */
67232021Spc if (next == curfile.ino && next <= last) {
67332021Spc ep = lookupino(next);
67432021Spc if (ep == NIL)
67532021Spc panic("corrupted symbol table\n");
67632021Spc (void) extractfile(myname(ep));
67732021Spc ep->e_flags &= ~NEW;
67832021Spc if (volno != curvol)
67932021Spc skipmaps();
68032021Spc }
68132021Spc }
68232021Spc }
68332021Spc
68432021Spc /*
68532021Spc * Add links.
68632021Spc */
createlinks()68732021Spc createlinks()
68832021Spc {
68932021Spc register struct entry *np, *ep;
69032021Spc register ino_t i;
69132021Spc char name[BUFSIZ];
69232021Spc
69332021Spc vprintf(stdout, "Add links\n");
69432021Spc for (i = ROOTINO; i < maxino; i++) {
69532021Spc ep = lookupino(i);
69632021Spc if (ep == NIL)
69732021Spc continue;
69832021Spc for (np = ep->e_links; np != NIL; np = np->e_links) {
69932021Spc if ((np->e_flags & NEW) == 0)
70032021Spc continue;
70132021Spc (void) strcpy(name, myname(ep));
70232021Spc if (ep->e_type == NODE) {
70332021Spc (void) linkit(name, myname(np), SYMLINK);
70432021Spc } else {
70532021Spc (void) linkit(name, myname(np), HARDLINK);
70632021Spc }
70732021Spc np->e_flags &= ~NEW;
70832021Spc }
70932021Spc }
71032021Spc }
71132021Spc
71232021Spc /*
71332021Spc * Check the symbol table.
71432021Spc * We do this to insure that all the requested work was done, and
71532021Spc * that no temporary names remain.
71632021Spc */
checkrestore()71732021Spc checkrestore()
71832021Spc {
71932021Spc register struct entry *ep;
72032021Spc register ino_t i;
72132021Spc
72232021Spc vprintf(stdout, "Check the symbol table.\n");
72332021Spc for (i = ROOTINO; i < maxino; i++) {
72432021Spc for (ep = lookupino(i); ep != NIL; ep = ep->e_links) {
72532021Spc ep->e_flags &= ~KEEP;
72632021Spc if (ep->e_type == NODE)
72732021Spc ep->e_flags &= ~(NEW|EXISTED);
72832021Spc if (ep->e_flags != NULL)
72932021Spc badentry(ep, "incomplete operations");
73032021Spc }
73132021Spc }
73232021Spc }
73332021Spc
73432021Spc /*
73532021Spc * Compare with the directory structure on the tape
73632021Spc * A paranoid check that things are as they should be.
73732021Spc */
73832021Spc long
verifyfile(name,ino,type)73932021Spc verifyfile(name, ino, type)
74032021Spc char *name;
74132021Spc ino_t ino;
74232021Spc int type;
74332021Spc {
74432021Spc struct entry *np, *ep;
74532021Spc long descend = GOOD;
74632021Spc
74732021Spc ep = lookupname(name);
74832021Spc if (ep == NIL) {
74932021Spc fprintf(stderr, "Warning: missing name %s\n", name);
75032021Spc return (FAIL);
75132021Spc }
75232021Spc np = lookupino(ino);
75332021Spc if (np != ep)
75432021Spc descend = FAIL;
75532021Spc for ( ; np != NIL; np = np->e_links)
75632021Spc if (np == ep)
75732021Spc break;
75832021Spc if (np == NIL)
75932021Spc panic("missing inumber %d\n", ino);
76032021Spc if (ep->e_type == LEAF && type != LEAF)
76132021Spc badentry(ep, "type should be LEAF");
76232021Spc return (descend);
76332021Spc }
764