121168Sdist /* 2*36105Sbostic * Copyright (c) 1983 The Regents of the University of California. 3*36105Sbostic * All rights reserved. 4*36105Sbostic * 5*36105Sbostic * Redistribution and use in source and binary forms are permitted 6*36105Sbostic * provided that the above copyright notice and this paragraph are 7*36105Sbostic * duplicated in all such forms and that any documentation, 8*36105Sbostic * advertising materials, and other materials related to such 9*36105Sbostic * distribution and use acknowledge that the software was developed 10*36105Sbostic * by the University of California, Berkeley. The name of the 11*36105Sbostic * University may not be used to endorse or promote products derived 12*36105Sbostic * from this software without specific prior written permission. 13*36105Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*36105Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*36105Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1621168Sdist */ 1721168Sdist 1810313Smckusick #ifndef lint 19*36105Sbostic static char sccsid[] = "@(#)restore.c 5.5 (Berkeley) 10/24/88"; 20*36105Sbostic #endif /* not lint */ 2110313Smckusick 2210313Smckusick #include "restore.h" 2310313Smckusick 2410313Smckusick /* 2511742Smckusick * This implements the 't' option. 2611742Smckusick * List entries on the tape. 2710313Smckusick */ 2811742Smckusick long 2910313Smckusick listfile(name, ino, type) 3010313Smckusick char *name; 3110313Smckusick ino_t ino; 3210313Smckusick int type; 3310313Smckusick { 3411742Smckusick long descend = hflag ? GOOD : FAIL; 3510313Smckusick 3610313Smckusick if (BIT(ino, dumpmap) == 0) { 3711742Smckusick return (descend); 3810313Smckusick } 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 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 5810313Smckusick if (BIT(ino, dumpmap) == 0) { 5934426Smckusick dprintf(stdout, "%s: not on the tape\n", name); 6011742Smckusick return (descend); 6110313Smckusick } 6211323Smckusick if (!mflag) { 6311742Smckusick (void) sprintf(buf, "./%u", ino); 6411323Smckusick name = buf; 6511323Smckusick if (type == NODE) { 6611439Smckusick (void) genliteraldir(name, ino); 6711742Smckusick return (descend); 6811323Smckusick } 6910313Smckusick } 7011323Smckusick ep = lookupino(ino); 7111323Smckusick if (ep != NIL) { 7211994Smckusick if (strcmp(name, myname(ep)) == 0) { 7311994Smckusick ep->e_flags |= NEW; 7411742Smckusick return (descend); 7511994Smckusick } 7611323Smckusick type |= LINK; 7711323Smckusick } 7811323Smckusick ep = addentry(name, ino, type); 7911994Smckusick if (type == NODE) 8011323Smckusick newnode(ep); 8111994Smckusick ep->e_flags |= NEW; 8211994Smckusick return (descend); 8311994Smckusick } 8411994Smckusick 8511994Smckusick /* 8611994Smckusick * This is used by the 'i' option to undo previous requests made by addfile. 8711994Smckusick * Delete entries from the request queue. 8811994Smckusick */ 8911994Smckusick /* ARGSUSED */ 9011994Smckusick long 9111994Smckusick deletefile(name, ino, type) 9211994Smckusick char *name; 9311994Smckusick ino_t ino; 9411994Smckusick int type; 9511994Smckusick { 9611994Smckusick long descend = hflag ? GOOD : FAIL; 9711994Smckusick struct entry *ep; 9811994Smckusick 9911994Smckusick if (BIT(ino, dumpmap) == 0) { 10011742Smckusick return (descend); 10111323Smckusick } 10211994Smckusick ep = lookupino(ino); 10311994Smckusick if (ep != NIL) 10411994Smckusick ep->e_flags &= ~NEW; 10511742Smckusick return (descend); 10610313Smckusick } 10710313Smckusick 10811742Smckusick /* 10911742Smckusick * The following four routines implement the incremental 11011742Smckusick * restore algorithm. The first removes old entries, the second 11111742Smckusick * does renames and calculates the extraction list, the third 11211742Smckusick * cleans up link names missed by the first two, and the final 11311742Smckusick * one deletes old directories. 11411742Smckusick * 11511742Smckusick * Directories cannot be immediately deleted, as they may have 11611742Smckusick * other files in them which need to be moved out first. As 11711742Smckusick * directories to be deleted are found, they are put on the 11811742Smckusick * following deletion list. After all deletions and renames 11911742Smckusick * are done, this list is actually deleted. 12011742Smckusick */ 12111742Smckusick static struct entry *removelist; 12211742Smckusick 12310313Smckusick /* 12411742Smckusick * Remove unneeded leaves from the old tree. 12511742Smckusick * Remove directories from the lookup chains. 12611742Smckusick */ 12711742Smckusick removeoldleaves() 12811742Smckusick { 12911742Smckusick register struct entry *ep; 13011742Smckusick register ino_t i; 13111742Smckusick 13211742Smckusick vprintf(stdout, "Mark entries to be removed.\n"); 13311742Smckusick for (i = ROOTINO + 1; i < maxino; i++) { 13411742Smckusick ep = lookupino(i); 13511742Smckusick if (ep == NIL) 13611742Smckusick continue; 13711742Smckusick if (BIT(i, clrimap)) 13811742Smckusick continue; 13911742Smckusick for ( ; ep != NIL; ep = ep->e_links) { 14011742Smckusick dprintf(stdout, "%s: REMOVE\n", myname(ep)); 14111742Smckusick if (ep->e_type == LEAF) { 14211742Smckusick removeleaf(ep); 14311742Smckusick freeentry(ep); 14411742Smckusick } else { 14511742Smckusick mktempname(ep); 14611742Smckusick deleteino(ep->e_ino); 14711742Smckusick ep->e_next = removelist; 14811742Smckusick removelist = ep; 14911742Smckusick } 15011742Smckusick } 15111742Smckusick } 15211742Smckusick } 15311742Smckusick 15411742Smckusick /* 15511439Smckusick * For each directory entry on the incremental tape, determine which 15611439Smckusick * category it falls into as follows: 15710313Smckusick * KEEP - entries that are to be left alone. 15810313Smckusick * NEW - new entries to be added. 15910313Smckusick * EXTRACT - files that must be updated with new contents. 16011439Smckusick * LINK - new links to be added. 16111439Smckusick * Renames are done at the same time. 16210313Smckusick */ 16311742Smckusick long 16411439Smckusick nodeupdates(name, ino, type) 16510313Smckusick char *name; 16610313Smckusick ino_t ino; 16710313Smckusick int type; 16810313Smckusick { 16910313Smckusick register struct entry *ep, *np, *ip; 17011742Smckusick long descend = GOOD; 17112454Smckusick int lookuptype = 0; 17210313Smckusick int key = 0; 17310313Smckusick /* key values */ 17411742Smckusick # define ONTAPE 0x1 /* inode is on the tape */ 17511742Smckusick # define INOFND 0x2 /* inode already exists */ 17611742Smckusick # define NAMEFND 0x4 /* name already exists */ 17711742Smckusick # define MODECHG 0x8 /* mode of inode changed */ 17811898Smckusick extern char *keyval(); 17910313Smckusick 18010313Smckusick /* 18110313Smckusick * This routine is called once for each element in the 18211402Smckusick * directory hierarchy, with a full path name. 18310313Smckusick * The "type" value is incorrectly specified as LEAF for 18410313Smckusick * directories that are not on the dump tape. 18512454Smckusick * 18612454Smckusick * Check to see if the file is on the tape. 18710313Smckusick */ 18811898Smckusick if (BIT(ino, dumpmap)) 18910313Smckusick key |= ONTAPE; 19012454Smckusick /* 19112454Smckusick * Check to see if the name exists, and if the name is a link. 19212454Smckusick */ 19310313Smckusick np = lookupname(name); 19412454Smckusick if (np != NIL) { 19510313Smckusick key |= NAMEFND; 19612454Smckusick ip = lookupino(np->e_ino); 19712454Smckusick if (ip == NULL) 19812454Smckusick panic("corrupted symbol table\n"); 19912454Smckusick if (ip != np) 20012454Smckusick lookuptype = LINK; 20112454Smckusick } 20212454Smckusick /* 20312454Smckusick * Check to see if the inode exists, and if one of its links 20412454Smckusick * corresponds to the name (if one was found). 20512454Smckusick */ 20610313Smckusick ip = lookupino(ino); 20710313Smckusick if (ip != NIL) { 20810313Smckusick key |= INOFND; 20912454Smckusick for (ep = ip->e_links; ep != NIL; ep = ep->e_links) { 21010313Smckusick if (ep == np) { 21110313Smckusick ip = ep; 21210313Smckusick break; 21310313Smckusick } 21412454Smckusick } 21510313Smckusick } 21611742Smckusick /* 21712454Smckusick * If both a name and an inode are found, but they do not 21812454Smckusick * correspond to the same file, then both the inode that has 21912454Smckusick * been found and the inode corresponding to the name that 22012454Smckusick * has been found need to be renamed. The current pathname 22112454Smckusick * is the new name for the inode that has been found. Since 22212454Smckusick * all files to be deleted have already been removed, the 22312454Smckusick * named file is either a now unneeded link, or it must live 22412454Smckusick * under a new name in this dump level. If it is a link, it 22512454Smckusick * can be removed. If it is not a link, it is given a 22612454Smckusick * temporary name in anticipation that it will be renamed 22712454Smckusick * when it is later found by inode number. 22811742Smckusick */ 22911439Smckusick if (((key & (INOFND|NAMEFND)) == (INOFND|NAMEFND)) && ip != np) { 23012454Smckusick if (lookuptype == LINK) { 23112454Smckusick removeleaf(np); 23212454Smckusick freeentry(np); 23312454Smckusick } else { 23412454Smckusick dprintf(stdout, "name/inode conflict, mktempname %s\n", 23512454Smckusick myname(np)); 23612454Smckusick mktempname(np); 23712454Smckusick } 23810313Smckusick np = NIL; 23910313Smckusick key &= ~NAMEFND; 24010313Smckusick } 24110313Smckusick if ((key & ONTAPE) && 24210313Smckusick (((key & INOFND) && ip->e_type != type) || 24311898Smckusick ((key & NAMEFND) && np->e_type != type))) 24410313Smckusick key |= MODECHG; 24511742Smckusick 24611742Smckusick /* 24711742Smckusick * Decide on the disposition of the file based on its flags. 24811742Smckusick * Note that we have already handled the case in which 24911742Smckusick * a name and inode are found that correspond to different files. 25011742Smckusick * Thus if both NAMEFND and INOFND are set then ip == np. 25111742Smckusick */ 25210313Smckusick switch (key) { 25310313Smckusick 25411742Smckusick /* 25511742Smckusick * A previously existing file has been found. 25611742Smckusick * Mark it as KEEP so that other links to the inode can be 25711742Smckusick * detected, and so that it will not be reclaimed by the search 25811742Smckusick * for unreferenced names. 25911742Smckusick */ 26010313Smckusick case INOFND|NAMEFND: 26110313Smckusick ip->e_flags |= KEEP; 26211898Smckusick dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, 26311898Smckusick flagvalues(ip)); 26410313Smckusick break; 26510313Smckusick 26611742Smckusick /* 26712445Smckusick * A file on the tape has a name which is the same as a name 26812445Smckusick * corresponding to a different file in the previous dump. 26912445Smckusick * Since all files to be deleted have already been removed, 27012454Smckusick * this file is either a now unneeded link, or it must live 27112454Smckusick * under a new name in this dump level. If it is a link, it 27212454Smckusick * can simply be removed. If it is not a link, it is given a 27312454Smckusick * temporary name in anticipation that it will be renamed 27412454Smckusick * when it is later found by inode number (see INOFND case 27512454Smckusick * below). The entry is then treated as a new file. 27612445Smckusick */ 27712445Smckusick case ONTAPE|NAMEFND: 27812445Smckusick case ONTAPE|NAMEFND|MODECHG: 27912454Smckusick if (lookuptype == LINK) { 28012454Smckusick removeleaf(np); 28112454Smckusick freeentry(np); 28212454Smckusick } else { 28312454Smckusick mktempname(np); 28412454Smckusick } 28512445Smckusick /* fall through */ 28612445Smckusick 28712445Smckusick /* 28811742Smckusick * A previously non-existent file. 28911742Smckusick * Add it to the file system, and request its extraction. 29011742Smckusick * If it is a directory, create it immediately. 29111742Smckusick * (Since the name is unused there can be no conflict) 29211742Smckusick */ 29310313Smckusick case ONTAPE: 29410313Smckusick ep = addentry(name, ino, type); 29511439Smckusick if (type == NODE) 29611439Smckusick newnode(ep); 29711994Smckusick ep->e_flags |= NEW|KEEP; 29811898Smckusick dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, 29911898Smckusick flagvalues(ep)); 30010313Smckusick break; 30110313Smckusick 30211742Smckusick /* 30311742Smckusick * A file with the same inode number, but a different 30411742Smckusick * name has been found. If the other name has not already 30511742Smckusick * been found (indicated by the KEEP flag, see above) then 30611742Smckusick * this must be a new name for the file, and it is renamed. 30711742Smckusick * If the other name has been found then this must be a 30811742Smckusick * link to the file. Hard links to directories are not 30911742Smckusick * permitted, and are either deleted or converted to 31011742Smckusick * symbolic links. Finally, if the file is on the tape, 31111742Smckusick * a request is made to extract it. 31211742Smckusick */ 31310313Smckusick case ONTAPE|INOFND: 31411898Smckusick if (type == LEAF && (ip->e_flags & KEEP) == 0) 31511439Smckusick ip->e_flags |= EXTRACT; 31610313Smckusick /* fall through */ 31710313Smckusick case INOFND: 31811742Smckusick if ((ip->e_flags & KEEP) == 0) { 31911742Smckusick renameit(myname(ip), name); 32011742Smckusick moveentry(ip, name); 32111742Smckusick ip->e_flags |= KEEP; 32212220Smckusick dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, 32311898Smckusick flagvalues(ip)); 32410313Smckusick break; 32510313Smckusick } 32611742Smckusick if (ip->e_type == NODE) { 32711742Smckusick descend = FAIL; 32811742Smckusick fprintf(stderr, 32911742Smckusick "deleted hard link %s to directory %s\n", 33011742Smckusick name, myname(ip)); 33111742Smckusick break; 33211742Smckusick } 33311742Smckusick ep = addentry(name, ino, type|LINK); 33411742Smckusick ep->e_flags |= NEW; 33511898Smckusick dprintf(stdout, "[%s] %s: %s|LINK\n", keyval(key), name, 33611898Smckusick flagvalues(ep)); 33710313Smckusick break; 33810313Smckusick 33911742Smckusick /* 34012445Smckusick * A previously known file which is to be updated. 34111742Smckusick */ 34210313Smckusick case ONTAPE|INOFND|NAMEFND: 34312454Smckusick if (type == LEAF && lookuptype != LINK) 34411439Smckusick np->e_flags |= EXTRACT; 34511439Smckusick np->e_flags |= KEEP; 34611898Smckusick dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, 34711898Smckusick flagvalues(np)); 34810313Smckusick break; 34910313Smckusick 35011742Smckusick /* 35111742Smckusick * An inode is being reused in a completely different way. 35211742Smckusick * Normally an extract can simply do an "unlink" followed 35311742Smckusick * by a "creat". Here we must do effectively the same 35411742Smckusick * thing. The complications arise because we cannot really 35511742Smckusick * delete a directory since it may still contain files 35611742Smckusick * that we need to rename, so we delete it from the symbol 35711742Smckusick * table, and put it on the list to be deleted eventually. 35811742Smckusick * Conversely if a directory is to be created, it must be 35911742Smckusick * done immediately, rather than waiting until the 36011742Smckusick * extraction phase. 36111742Smckusick */ 36210313Smckusick case ONTAPE|INOFND|MODECHG: 36310313Smckusick case ONTAPE|INOFND|NAMEFND|MODECHG: 36411439Smckusick if (ip->e_flags & KEEP) { 36511439Smckusick badentry(ip, "cannot KEEP and change modes"); 36611439Smckusick break; 36711439Smckusick } 36811439Smckusick if (ip->e_type == LEAF) { 36911439Smckusick /* changing from leaf to node */ 37011439Smckusick removeleaf(ip); 37111439Smckusick freeentry(ip); 37211439Smckusick ip = addentry(name, ino, type); 37311439Smckusick newnode(ip); 37411439Smckusick } else { 37511439Smckusick /* changing from node to leaf */ 37612457Smckusick if ((ip->e_flags & TMPNAME) == 0) 37712457Smckusick mktempname(ip); 37811439Smckusick deleteino(ip->e_ino); 37911439Smckusick ip->e_next = removelist; 38011439Smckusick removelist = ip; 38111439Smckusick ip = addentry(name, ino, type); 38211439Smckusick } 38311994Smckusick ip->e_flags |= NEW|KEEP; 38411898Smckusick dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, 38511898Smckusick flagvalues(ip)); 38610313Smckusick break; 38710313Smckusick 38811742Smckusick /* 38911742Smckusick * A hard link to a diirectory that has been removed. 39011742Smckusick * Ignore it. 39111742Smckusick */ 39211742Smckusick case NAMEFND: 39311898Smckusick dprintf(stdout, "[%s] %s: Extraneous name\n", keyval(key), 39411898Smckusick name); 39511742Smckusick descend = FAIL; 39611742Smckusick break; 39711742Smckusick 39811742Smckusick /* 39926487Smckusick * If we find a directory entry for a file that is not on 40026487Smckusick * the tape, then we must have found a file that was created 40126487Smckusick * while the dump was in progress. Since we have no contents 40226487Smckusick * for it, we discard the name knowing that it will be on the 40326487Smckusick * next incremental tape. 40426487Smckusick */ 40526487Smckusick case NIL: 40631541Smckusick fprintf(stderr, "%s: (inode %d) not found on tape\n", 40731541Smckusick name, ino); 40826487Smckusick break; 40926487Smckusick 41026487Smckusick /* 41111742Smckusick * If any of these arise, something is grievously wrong with 41211742Smckusick * the current state of the symbol table. 41311742Smckusick */ 41410313Smckusick case INOFND|NAMEFND|MODECHG: 41510313Smckusick case NAMEFND|MODECHG: 41610313Smckusick case INOFND|MODECHG: 41711898Smckusick panic("[%s] %s: inconsistent state\n", keyval(key), name); 41810313Smckusick break; 41910313Smckusick 42011742Smckusick /* 42111742Smckusick * These states "cannot" arise for any state of the symbol table. 42211742Smckusick */ 42310313Smckusick case ONTAPE|MODECHG: 42410313Smckusick case MODECHG: 42510313Smckusick default: 42611898Smckusick panic("[%s] %s: impossible state\n", keyval(key), name); 42710313Smckusick break; 42810313Smckusick } 42911742Smckusick return (descend); 43010313Smckusick } 43110313Smckusick 43210313Smckusick /* 43311898Smckusick * Calculate the active flags in a key. 43411898Smckusick */ 43511898Smckusick char * 43611898Smckusick keyval(key) 43711898Smckusick int key; 43811898Smckusick { 43911898Smckusick static char keybuf[32]; 44011898Smckusick 44111994Smckusick (void) strcpy(keybuf, "|NIL"); 44211898Smckusick keybuf[0] = '\0'; 44311898Smckusick if (key & ONTAPE) 44411898Smckusick (void) strcat(keybuf, "|ONTAPE"); 44511898Smckusick if (key & INOFND) 44611898Smckusick (void) strcat(keybuf, "|INOFND"); 44711898Smckusick if (key & NAMEFND) 44811898Smckusick (void) strcat(keybuf, "|NAMEFND"); 44911898Smckusick if (key & MODECHG) 45011898Smckusick (void) strcat(keybuf, "|MODECHG"); 45111898Smckusick return (&keybuf[1]); 45211898Smckusick } 45311898Smckusick 45411898Smckusick /* 45511742Smckusick * Find unreferenced link names. 45610313Smckusick */ 45711439Smckusick findunreflinks() 45810313Smckusick { 45910313Smckusick register struct entry *ep, *np; 46011439Smckusick register ino_t i; 46110313Smckusick 46210313Smckusick vprintf(stdout, "Find unreferenced names.\n"); 46310313Smckusick for (i = ROOTINO; i < maxino; i++) { 46410313Smckusick ep = lookupino(i); 46512220Smckusick if (ep == NIL || ep->e_type == LEAF || BIT(i, dumpmap) == 0) 46610313Smckusick continue; 46710313Smckusick for (np = ep->e_entries; np != NIL; np = np->e_sibling) { 46810313Smckusick if (np->e_flags == 0) { 46911439Smckusick dprintf(stdout, 47011439Smckusick "%s: remove unreferenced name\n", 47111439Smckusick myname(np)); 47211439Smckusick removeleaf(np); 47311439Smckusick freeentry(np); 47410313Smckusick } 47510313Smckusick } 47610313Smckusick } 47712457Smckusick /* 47812457Smckusick * Any leaves remaining in removed directories is unreferenced. 47912457Smckusick */ 48012457Smckusick for (ep = removelist; ep != NIL; ep = ep->e_next) { 48112457Smckusick for (np = ep->e_entries; np != NIL; np = np->e_sibling) { 48212457Smckusick if (np->e_type == LEAF) { 48312457Smckusick if (np->e_flags != 0) 48412457Smckusick badentry(np, "unreferenced with flags"); 48512457Smckusick dprintf(stdout, 48612457Smckusick "%s: remove unreferenced name\n", 48712457Smckusick myname(np)); 48812457Smckusick removeleaf(np); 48912457Smckusick freeentry(np); 49012457Smckusick } 49112457Smckusick } 49212457Smckusick } 49310313Smckusick } 49410313Smckusick 49510313Smckusick /* 49611742Smckusick * Remove old nodes (directories). 49711742Smckusick * Note that this routine runs in O(N*D) where: 49811742Smckusick * N is the number of directory entries to be removed. 49911742Smckusick * D is the maximum depth of the tree. 50011742Smckusick * If N == D this can be quite slow. If the list were 50111742Smckusick * topologically sorted, the deletion could be done in 50211742Smckusick * time O(N). 50310313Smckusick */ 50411439Smckusick removeoldnodes() 50510313Smckusick { 50611439Smckusick register struct entry *ep, **prev; 50711439Smckusick long change; 50810313Smckusick 50911439Smckusick vprintf(stdout, "Remove old nodes (directories).\n"); 51011439Smckusick do { 51111439Smckusick change = 0; 51211439Smckusick prev = &removelist; 51311439Smckusick for (ep = removelist; ep != NIL; ep = *prev) { 51411439Smckusick if (ep->e_entries != NIL) { 51511439Smckusick prev = &ep->e_next; 51611128Smckusick continue; 51710313Smckusick } 51811439Smckusick *prev = ep->e_next; 51911439Smckusick removenode(ep); 52011439Smckusick freeentry(ep); 52111439Smckusick change++; 52210313Smckusick } 52311439Smckusick } while (change); 52411439Smckusick for (ep = removelist; ep != NIL; ep = ep->e_next) 52511439Smckusick badentry(ep, "cannot remove, non-empty"); 52610313Smckusick } 52710313Smckusick 52810313Smckusick /* 52911742Smckusick * This is the routine used to extract files for the 'r' command. 53011742Smckusick * Extract new leaves. 53110313Smckusick */ 53210313Smckusick createleaves(symtabfile) 53310313Smckusick char *symtabfile; 53410313Smckusick { 53510313Smckusick register struct entry *ep; 53610313Smckusick ino_t first; 53710313Smckusick long curvol; 53810313Smckusick 53911439Smckusick if (command == 'R') { 54010313Smckusick vprintf(stdout, "Continue extraction of new leaves\n"); 54111439Smckusick } else { 54210313Smckusick vprintf(stdout, "Extract new leaves.\n"); 54311439Smckusick dumpsymtable(symtabfile, volno); 54411439Smckusick } 54510313Smckusick first = lowerbnd(ROOTINO); 54610313Smckusick curvol = volno; 54710313Smckusick while (curfile.ino < maxino) { 54811439Smckusick first = lowerbnd(first); 54911742Smckusick /* 55011742Smckusick * If the next available file is not the one which we 55111742Smckusick * expect then we have missed one or more files. Since 55211742Smckusick * we do not request files that were not on the tape, 55311924Smckusick * the lost files must have been due to a tape read error, 55411924Smckusick * or a file that was removed while the dump was in progress. 55511742Smckusick */ 55610313Smckusick while (first < curfile.ino) { 55710313Smckusick ep = lookupino(first); 55810313Smckusick if (ep == NIL) 55910313Smckusick panic("%d: bad first\n", first); 56010313Smckusick fprintf(stderr, "%s: not found on tape\n", myname(ep)); 56111439Smckusick ep->e_flags &= ~(NEW|EXTRACT); 56211439Smckusick first = lowerbnd(first); 56310313Smckusick } 56411924Smckusick /* 56511924Smckusick * If we find files on the tape that have no corresponding 56611924Smckusick * directory entries, then we must have found a file that 56711924Smckusick * was created while the dump was in progress. Since we have 56811924Smckusick * no name for it, we discard it knowing that it will be 56911924Smckusick * on the next incremental tape. 57011924Smckusick */ 57111922Smckusick if (first != curfile.ino) { 57211922Smckusick fprintf(stderr, "expected next file %d, got %d\n", 57310313Smckusick first, curfile.ino); 57411922Smckusick skipfile(); 57511922Smckusick goto next; 57611922Smckusick } 57710313Smckusick ep = lookupino(curfile.ino); 57810313Smckusick if (ep == NIL) 57910313Smckusick panic("unknown file on tape\n"); 58011439Smckusick if ((ep->e_flags & (NEW|EXTRACT)) == 0) 58110313Smckusick badentry(ep, "unexpected file on tape"); 58211742Smckusick /* 58311742Smckusick * If the file is to be extracted, then the old file must 58411742Smckusick * be removed since its type may change from one leaf type 58511742Smckusick * to another (eg "file" to "character special"). 58611742Smckusick */ 58711439Smckusick if ((ep->e_flags & EXTRACT) != 0) { 58811439Smckusick removeleaf(ep); 58911439Smckusick ep->e_flags &= ~REMOVED; 59011439Smckusick } 59111742Smckusick (void) extractfile(myname(ep)); 59211439Smckusick ep->e_flags &= ~(NEW|EXTRACT); 59311742Smckusick /* 59411742Smckusick * We checkpoint the restore after every tape reel, so 59511742Smckusick * as to simplify the amount of work re quired by the 59611742Smckusick * 'R' command. 59711742Smckusick */ 59811922Smckusick next: 59910313Smckusick if (curvol != volno) { 60010313Smckusick dumpsymtable(symtabfile, volno); 60111439Smckusick skipmaps(); 60210313Smckusick curvol = volno; 60310313Smckusick } 60410313Smckusick } 60510313Smckusick } 60610313Smckusick 60710313Smckusick /* 60812454Smckusick * This is the routine used to extract files for the 'x' and 'i' commands. 60912454Smckusick * Efficiently extract a subset of the files on a tape. 61010313Smckusick */ 61110313Smckusick createfiles() 61210313Smckusick { 61310313Smckusick register ino_t first, next, last; 61410313Smckusick register struct entry *ep; 61510313Smckusick long curvol; 61610313Smckusick 61710313Smckusick vprintf(stdout, "Extract requested files\n"); 61811310Smckusick curfile.action = SKIP; 61911313Smckusick getvol((long)1); 62011402Smckusick skipmaps(); 62111402Smckusick skipdirs(); 62210313Smckusick first = lowerbnd(ROOTINO); 62311310Smckusick last = upperbnd(maxino - 1); 62410313Smckusick for (;;) { 62510313Smckusick first = lowerbnd(first); 62610313Smckusick last = upperbnd(last); 62711402Smckusick /* 62811402Smckusick * Check to see if any files remain to be extracted 62911402Smckusick */ 63010313Smckusick if (first > last) 63110313Smckusick return; 63211402Smckusick /* 63311402Smckusick * Reject any volumes with inodes greater 63411402Smckusick * than the last one needed 63511402Smckusick */ 63610313Smckusick while (curfile.ino > last) { 63710313Smckusick curfile.action = SKIP; 63810313Smckusick getvol((long)0); 63911402Smckusick skipmaps(); 64011402Smckusick skipdirs(); 64110313Smckusick } 64211402Smckusick /* 64311402Smckusick * Decide on the next inode needed. 64411402Smckusick * Skip across the inodes until it is found 64511402Smckusick * or an out of order volume change is encountered 64611402Smckusick */ 64710313Smckusick next = lowerbnd(curfile.ino); 64810313Smckusick do { 64910313Smckusick curvol = volno; 65010313Smckusick while (next > curfile.ino && volno == curvol) 65110313Smckusick skipfile(); 65211402Smckusick skipmaps(); 65311402Smckusick skipdirs(); 65410313Smckusick } while (volno == curvol + 1); 65511402Smckusick /* 65611402Smckusick * If volume change out of order occurred the 65711994Smckusick * current state must be recalculated 65811402Smckusick */ 65910313Smckusick if (volno != curvol) 66010313Smckusick continue; 66111402Smckusick /* 66211402Smckusick * If the current inode is greater than the one we were 66311402Smckusick * looking for then we missed the one we were looking for. 66411402Smckusick * Since we only attempt to extract files listed in the 66511994Smckusick * dump map, the lost files must have been due to a tape 66611994Smckusick * read error, or a file that was removed while the dump 66711994Smckusick * was in progress. Thus we report all requested files 66811994Smckusick * between the one we were looking for, and the one we 66911994Smckusick * found as missing, and delete their request flags. 67011402Smckusick */ 67110313Smckusick while (next < curfile.ino) { 67210313Smckusick ep = lookupino(next); 67310313Smckusick if (ep == NIL) 67410313Smckusick panic("corrupted symbol table\n"); 67510313Smckusick fprintf(stderr, "%s: not found on tape\n", myname(ep)); 67610313Smckusick ep->e_flags &= ~NEW; 67711402Smckusick next = lowerbnd(next); 67810313Smckusick } 67911402Smckusick /* 68011402Smckusick * The current inode is the one that we are looking for, 68111402Smckusick * so extract it per its requested name. 68211402Smckusick */ 68311313Smckusick if (next == curfile.ino && next <= last) { 68410313Smckusick ep = lookupino(next); 68510313Smckusick if (ep == NIL) 68610313Smckusick panic("corrupted symbol table\n"); 68711742Smckusick (void) extractfile(myname(ep)); 68810313Smckusick ep->e_flags &= ~NEW; 68916228Smckusick if (volno != curvol) 69016228Smckusick skipmaps(); 69110313Smckusick } 69210313Smckusick } 69310313Smckusick } 69410313Smckusick 69510313Smckusick /* 69611742Smckusick * Add links. 69710313Smckusick */ 69810313Smckusick createlinks() 69910313Smckusick { 70010313Smckusick register struct entry *np, *ep; 70111439Smckusick register ino_t i; 70210313Smckusick char name[BUFSIZ]; 70310313Smckusick 70410313Smckusick vprintf(stdout, "Add links\n"); 70510313Smckusick for (i = ROOTINO; i < maxino; i++) { 70610313Smckusick ep = lookupino(i); 70710313Smckusick if (ep == NIL) 70810313Smckusick continue; 70910313Smckusick for (np = ep->e_links; np != NIL; np = np->e_links) { 71011924Smckusick if ((np->e_flags & NEW) == 0) 71111924Smckusick continue; 71211439Smckusick (void) strcpy(name, myname(ep)); 71310313Smckusick if (ep->e_type == NODE) { 71415780Smckusick (void) linkit(name, myname(np), SYMLINK); 71510313Smckusick } else { 71615780Smckusick (void) linkit(name, myname(np), HARDLINK); 71710313Smckusick } 71811310Smckusick np->e_flags &= ~NEW; 71910313Smckusick } 72010313Smckusick } 72110313Smckusick } 72210313Smckusick 72310313Smckusick /* 72411742Smckusick * Check the symbol table. 72511742Smckusick * We do this to insure that all the requested work was done, and 72611742Smckusick * that no temporary names remain. 72710313Smckusick */ 72810313Smckusick checkrestore() 72910313Smckusick { 73010313Smckusick register struct entry *ep; 73111439Smckusick register ino_t i; 73210313Smckusick 73310313Smckusick vprintf(stdout, "Check the symbol table.\n"); 73410313Smckusick for (i = ROOTINO; i < maxino; i++) { 73518007Smckusick for (ep = lookupino(i); ep != NIL; ep = ep->e_links) { 73610313Smckusick ep->e_flags &= ~KEEP; 73712454Smckusick if (ep->e_type == NODE) 73818007Smckusick ep->e_flags &= ~(NEW|EXISTED); 73910313Smckusick if (ep->e_flags != NULL) 74010313Smckusick badentry(ep, "incomplete operations"); 74110313Smckusick } 74210313Smckusick } 74310313Smckusick } 74410313Smckusick 74510313Smckusick /* 74611742Smckusick * Compare with the directory structure on the tape 74711742Smckusick * A paranoid check that things are as they should be. 74810313Smckusick */ 74911742Smckusick long 75010313Smckusick verifyfile(name, ino, type) 75110313Smckusick char *name; 75210313Smckusick ino_t ino; 75310313Smckusick int type; 75410313Smckusick { 75510313Smckusick struct entry *np, *ep; 75611742Smckusick long descend = GOOD; 75710313Smckusick 75810313Smckusick ep = lookupname(name); 75911742Smckusick if (ep == NIL) { 76011742Smckusick fprintf(stderr, "Warning: missing name %s\n", name); 76111742Smckusick return (FAIL); 76211742Smckusick } 76311742Smckusick np = lookupino(ino); 76411742Smckusick if (np != ep) 76511742Smckusick descend = FAIL; 76611742Smckusick for ( ; np != NIL; np = np->e_links) 76710313Smckusick if (np == ep) 76810313Smckusick break; 76910313Smckusick if (np == NIL) 77010313Smckusick panic("missing inumber %d\n", ino); 77110313Smckusick if (ep->e_type == LEAF && type != LEAF) 77210313Smckusick badentry(ep, "type should be LEAF"); 77311742Smckusick return (descend); 77410313Smckusick } 775