1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright 1996, 1998, 2001, 2003 Sun Microsystems, Inc. All rights reserved. 3*0Sstevel@tonic-gate * Use is subject to license terms. 4*0Sstevel@tonic-gate */ 5*0Sstevel@tonic-gate 6*0Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 7*0Sstevel@tonic-gate /* All Rights Reserved */ 8*0Sstevel@tonic-gate 9*0Sstevel@tonic-gate /* 10*0Sstevel@tonic-gate * Copyright (c) 1983 Regents of the University of California. 11*0Sstevel@tonic-gate * All rights reserved. The Berkeley software License Agreement 12*0Sstevel@tonic-gate * specifies the terms and conditions for redistribution. 13*0Sstevel@tonic-gate */ 14*0Sstevel@tonic-gate 15*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 16*0Sstevel@tonic-gate 17*0Sstevel@tonic-gate #include "restore.h" 18*0Sstevel@tonic-gate /* undef MAXNAMLEN to prevent compiler warnings about redef in dirent.h */ 19*0Sstevel@tonic-gate #undef MAXNAMLEN 20*0Sstevel@tonic-gate #include <dirent.h> 21*0Sstevel@tonic-gate 22*0Sstevel@tonic-gate #ifdef __STDC__ 23*0Sstevel@tonic-gate static char *keyval(int); 24*0Sstevel@tonic-gate static void removexattrs(struct entry *); 25*0Sstevel@tonic-gate static void movexattrs(char *, char *); 26*0Sstevel@tonic-gate #else 27*0Sstevel@tonic-gate static char *keyval(); 28*0Sstevel@tonic-gate static void removexattrs(); 29*0Sstevel@tonic-gate static void movexattrs(); 30*0Sstevel@tonic-gate #endif 31*0Sstevel@tonic-gate 32*0Sstevel@tonic-gate /* 33*0Sstevel@tonic-gate * This implements the 't' option. 34*0Sstevel@tonic-gate * List entries on the tape. 35*0Sstevel@tonic-gate */ 36*0Sstevel@tonic-gate long 37*0Sstevel@tonic-gate listfile(name, ino, type) 38*0Sstevel@tonic-gate char *name; 39*0Sstevel@tonic-gate ino_t ino; 40*0Sstevel@tonic-gate int type; 41*0Sstevel@tonic-gate { 42*0Sstevel@tonic-gate long descend = hflag ? GOOD : FAIL; 43*0Sstevel@tonic-gate 44*0Sstevel@tonic-gate if (BIT(ino, dumpmap) == 0) { 45*0Sstevel@tonic-gate return (descend); 46*0Sstevel@tonic-gate } 47*0Sstevel@tonic-gate vprintf(stdout, "%s", type == LEAF ? gettext("leaf") : gettext("dir ")); 48*0Sstevel@tonic-gate (void) fprintf(stdout, "%10lu\t%s\n", ino, name); 49*0Sstevel@tonic-gate return (descend); 50*0Sstevel@tonic-gate } 51*0Sstevel@tonic-gate 52*0Sstevel@tonic-gate /* 53*0Sstevel@tonic-gate * This implements the 'x' option. 54*0Sstevel@tonic-gate * Request that new entries be extracted. 55*0Sstevel@tonic-gate */ 56*0Sstevel@tonic-gate long 57*0Sstevel@tonic-gate addfile(name, ino, type) 58*0Sstevel@tonic-gate char *name; 59*0Sstevel@tonic-gate ino_t ino; 60*0Sstevel@tonic-gate int type; 61*0Sstevel@tonic-gate { 62*0Sstevel@tonic-gate struct entry *ep; 63*0Sstevel@tonic-gate long descend = hflag ? GOOD : FAIL; 64*0Sstevel@tonic-gate char buf[100]; 65*0Sstevel@tonic-gate 66*0Sstevel@tonic-gate /* Don't know if ino_t is long or long long, so be safe w/ *printf() */ 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate if (BIT(ino, dumpmap) == 0) { 69*0Sstevel@tonic-gate if (mflag) { 70*0Sstevel@tonic-gate dprintf(stdout, gettext( 71*0Sstevel@tonic-gate "%s: not on the volume\n"), name); 72*0Sstevel@tonic-gate } else { 73*0Sstevel@tonic-gate dprintf(stdout, gettext( 74*0Sstevel@tonic-gate "inode %llu: not on the volume\n"), 75*0Sstevel@tonic-gate (u_longlong_t)ino); 76*0Sstevel@tonic-gate } 77*0Sstevel@tonic-gate return (descend); 78*0Sstevel@tonic-gate } 79*0Sstevel@tonic-gate if (!mflag) { 80*0Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "./%llu", (u_longlong_t)ino); 81*0Sstevel@tonic-gate buf[sizeof (buf) - 1] = '\0'; 82*0Sstevel@tonic-gate name = buf; 83*0Sstevel@tonic-gate if (type == NODE) { 84*0Sstevel@tonic-gate (void) genliteraldir(name, ino); 85*0Sstevel@tonic-gate return (descend); 86*0Sstevel@tonic-gate } 87*0Sstevel@tonic-gate } 88*0Sstevel@tonic-gate ep = lookupino(ino); 89*0Sstevel@tonic-gate if (ep != NIL) { 90*0Sstevel@tonic-gate if (strcmp(name, myname(ep)) == 0) { 91*0Sstevel@tonic-gate /* LINTED: result fits into a short */ 92*0Sstevel@tonic-gate ep->e_flags |= NEW; 93*0Sstevel@tonic-gate return (descend); 94*0Sstevel@tonic-gate } 95*0Sstevel@tonic-gate type |= LINK; 96*0Sstevel@tonic-gate } 97*0Sstevel@tonic-gate ep = addentry(name, ino, type); 98*0Sstevel@tonic-gate if (type == NODE) 99*0Sstevel@tonic-gate newnode(ep); 100*0Sstevel@tonic-gate /* LINTED: result fits into a short */ 101*0Sstevel@tonic-gate ep->e_flags |= NEW; 102*0Sstevel@tonic-gate return (descend); 103*0Sstevel@tonic-gate } 104*0Sstevel@tonic-gate 105*0Sstevel@tonic-gate /* 106*0Sstevel@tonic-gate * This is used by the 'i' option to undo previous requests made by addfile. 107*0Sstevel@tonic-gate * Delete entries from the request queue. 108*0Sstevel@tonic-gate */ 109*0Sstevel@tonic-gate /* ARGSUSED */ 110*0Sstevel@tonic-gate long 111*0Sstevel@tonic-gate deletefile(name, ino, type) 112*0Sstevel@tonic-gate char *name; 113*0Sstevel@tonic-gate ino_t ino; 114*0Sstevel@tonic-gate int type; 115*0Sstevel@tonic-gate { 116*0Sstevel@tonic-gate long descend = hflag ? GOOD : FAIL; 117*0Sstevel@tonic-gate struct entry *ep; 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate if (BIT(ino, dumpmap) == 0) { 120*0Sstevel@tonic-gate return (descend); 121*0Sstevel@tonic-gate } 122*0Sstevel@tonic-gate ep = lookupino(ino); 123*0Sstevel@tonic-gate if (ep != NIL) { 124*0Sstevel@tonic-gate /* LINTED: result fits into a short */ 125*0Sstevel@tonic-gate ep->e_flags &= ~NEW; 126*0Sstevel@tonic-gate } 127*0Sstevel@tonic-gate return (descend); 128*0Sstevel@tonic-gate } 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate /* 131*0Sstevel@tonic-gate * The following four routines implement the incremental 132*0Sstevel@tonic-gate * restore algorithm. The first removes old entries, the second 133*0Sstevel@tonic-gate * does renames and calculates the extraction list, the third 134*0Sstevel@tonic-gate * cleans up link names missed by the first two, and the final 135*0Sstevel@tonic-gate * one deletes old directories. 136*0Sstevel@tonic-gate * 137*0Sstevel@tonic-gate * Directories cannot be immediately deleted, as they may have 138*0Sstevel@tonic-gate * other files in them which need to be moved out first. As 139*0Sstevel@tonic-gate * directories to be deleted are found, they are put on the 140*0Sstevel@tonic-gate * following deletion list. After all deletions and renames 141*0Sstevel@tonic-gate * are done, this list is actually deleted. 142*0Sstevel@tonic-gate */ 143*0Sstevel@tonic-gate static struct entry *removelist; 144*0Sstevel@tonic-gate 145*0Sstevel@tonic-gate /* 146*0Sstevel@tonic-gate * Remove unneeded leaves from the old tree. 147*0Sstevel@tonic-gate * Remove directories from the lookup chains. 148*0Sstevel@tonic-gate */ 149*0Sstevel@tonic-gate void 150*0Sstevel@tonic-gate #ifdef __STDC__ 151*0Sstevel@tonic-gate removeoldleaves(void) 152*0Sstevel@tonic-gate #else 153*0Sstevel@tonic-gate removeoldleaves() 154*0Sstevel@tonic-gate #endif 155*0Sstevel@tonic-gate { 156*0Sstevel@tonic-gate struct entry *ep; 157*0Sstevel@tonic-gate ino_t i; 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate vprintf(stdout, gettext("Mark entries to be removed.\n")); 160*0Sstevel@tonic-gate for (i = ROOTINO + 1; i < maxino; i++) { 161*0Sstevel@tonic-gate if (BIT(i, clrimap)) 162*0Sstevel@tonic-gate continue; 163*0Sstevel@tonic-gate ep = lookupino(i); 164*0Sstevel@tonic-gate if (ep == NIL) 165*0Sstevel@tonic-gate continue; 166*0Sstevel@tonic-gate while (ep != NIL) { 167*0Sstevel@tonic-gate dprintf(stdout, gettext("%s: REMOVE\n"), myname(ep)); 168*0Sstevel@tonic-gate removexattrs(ep->e_xattrs); 169*0Sstevel@tonic-gate if (ep->e_type == LEAF) { 170*0Sstevel@tonic-gate removeleaf(ep); 171*0Sstevel@tonic-gate freeentry(ep); 172*0Sstevel@tonic-gate } else { 173*0Sstevel@tonic-gate mktempname(ep); 174*0Sstevel@tonic-gate deleteino(ep->e_ino); 175*0Sstevel@tonic-gate /* 176*0Sstevel@tonic-gate * once the inode is deleted from the symbol 177*0Sstevel@tonic-gate * table, the e_next field is reusable 178*0Sstevel@tonic-gate */ 179*0Sstevel@tonic-gate ep->e_next = removelist; 180*0Sstevel@tonic-gate removelist = ep; 181*0Sstevel@tonic-gate } 182*0Sstevel@tonic-gate ep = ep->e_links; 183*0Sstevel@tonic-gate } 184*0Sstevel@tonic-gate } 185*0Sstevel@tonic-gate } 186*0Sstevel@tonic-gate 187*0Sstevel@tonic-gate /* 188*0Sstevel@tonic-gate * For each directory entry on the incremental tape, determine which 189*0Sstevel@tonic-gate * category it falls into as follows: 190*0Sstevel@tonic-gate * KEEP - entries that are to be left alone. 191*0Sstevel@tonic-gate * NEW - new entries to be added. 192*0Sstevel@tonic-gate * EXTRACT - files that must be updated with new contents. 193*0Sstevel@tonic-gate * LINK - new links to be added. 194*0Sstevel@tonic-gate * Renames are done at the same time. 195*0Sstevel@tonic-gate */ 196*0Sstevel@tonic-gate long 197*0Sstevel@tonic-gate nodeupdates(name, ino, type) 198*0Sstevel@tonic-gate char *name; 199*0Sstevel@tonic-gate ino_t ino; 200*0Sstevel@tonic-gate int type; 201*0Sstevel@tonic-gate { 202*0Sstevel@tonic-gate struct entry *ep, *np, *ip; 203*0Sstevel@tonic-gate long descend = GOOD; 204*0Sstevel@tonic-gate int lookuptype = 0; 205*0Sstevel@tonic-gate int key = 0; 206*0Sstevel@tonic-gate /* key values */ 207*0Sstevel@tonic-gate #define ONTAPE 0x1 /* inode is on the tape */ 208*0Sstevel@tonic-gate #define INOFND 0x2 /* inode already exists */ 209*0Sstevel@tonic-gate #define NAMEFND 0x4 /* name already exists */ 210*0Sstevel@tonic-gate #define MODECHG 0x8 /* mode of inode changed */ 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate /* 213*0Sstevel@tonic-gate * This routine is called once for each element in the 214*0Sstevel@tonic-gate * directory hierarchy, with a full path name. 215*0Sstevel@tonic-gate * The "type" value is incorrectly specified as LEAF for 216*0Sstevel@tonic-gate * directories that are not on the dump tape. 217*0Sstevel@tonic-gate * 218*0Sstevel@tonic-gate * Check to see if the file is on the tape. 219*0Sstevel@tonic-gate */ 220*0Sstevel@tonic-gate if (BIT(ino, dumpmap)) 221*0Sstevel@tonic-gate key |= ONTAPE; 222*0Sstevel@tonic-gate /* 223*0Sstevel@tonic-gate * Check to see if the name exists, and if the name is a link. 224*0Sstevel@tonic-gate */ 225*0Sstevel@tonic-gate np = lookupname(name); 226*0Sstevel@tonic-gate if (np != NIL) { 227*0Sstevel@tonic-gate key |= NAMEFND; 228*0Sstevel@tonic-gate ip = lookupino(np->e_ino); 229*0Sstevel@tonic-gate if (ip == NULL) { 230*0Sstevel@tonic-gate (void) fprintf(stderr, 231*0Sstevel@tonic-gate gettext("corrupted symbol table\n")); 232*0Sstevel@tonic-gate done(1); 233*0Sstevel@tonic-gate } 234*0Sstevel@tonic-gate if (ip != np) 235*0Sstevel@tonic-gate lookuptype = LINK; 236*0Sstevel@tonic-gate } 237*0Sstevel@tonic-gate /* 238*0Sstevel@tonic-gate * Check to see if the inode exists, and if one of its links 239*0Sstevel@tonic-gate * corresponds to the name (if one was found). 240*0Sstevel@tonic-gate */ 241*0Sstevel@tonic-gate ip = lookupino(ino); 242*0Sstevel@tonic-gate if (ip != NIL) { 243*0Sstevel@tonic-gate key |= INOFND; 244*0Sstevel@tonic-gate for (ep = ip->e_links; ep != NIL; ep = ep->e_links) { 245*0Sstevel@tonic-gate if (ep == np) { 246*0Sstevel@tonic-gate ip = ep; 247*0Sstevel@tonic-gate break; 248*0Sstevel@tonic-gate } 249*0Sstevel@tonic-gate } 250*0Sstevel@tonic-gate } 251*0Sstevel@tonic-gate /* 252*0Sstevel@tonic-gate * If both a name and an inode are found, but they do not 253*0Sstevel@tonic-gate * correspond to the same file, then both the inode that has 254*0Sstevel@tonic-gate * been found and the inode corresponding to the name that 255*0Sstevel@tonic-gate * has been found need to be renamed. The current pathname 256*0Sstevel@tonic-gate * is the new name for the inode that has been found. Since 257*0Sstevel@tonic-gate * all files to be deleted have already been removed, the 258*0Sstevel@tonic-gate * named file is either a now-unneeded link, or it must live 259*0Sstevel@tonic-gate * under a new name in this dump level. If it is a link, it 260*0Sstevel@tonic-gate * can be removed. If it is not a link, it is given a 261*0Sstevel@tonic-gate * temporary name in anticipation that it will be renamed 262*0Sstevel@tonic-gate * when it is later found by inode number. 263*0Sstevel@tonic-gate */ 264*0Sstevel@tonic-gate if (((key & (INOFND|NAMEFND)) == (INOFND|NAMEFND)) && ip != np) { 265*0Sstevel@tonic-gate if (lookuptype == LINK) { 266*0Sstevel@tonic-gate removeleaf(np); 267*0Sstevel@tonic-gate freeentry(np); 268*0Sstevel@tonic-gate } else { 269*0Sstevel@tonic-gate dprintf(stdout, 270*0Sstevel@tonic-gate gettext("name/inode conflict, mktempname %s\n"), 271*0Sstevel@tonic-gate myname(np)); 272*0Sstevel@tonic-gate mktempname(np); 273*0Sstevel@tonic-gate } 274*0Sstevel@tonic-gate np = NIL; 275*0Sstevel@tonic-gate key &= ~NAMEFND; 276*0Sstevel@tonic-gate } 277*0Sstevel@tonic-gate if ((key & ONTAPE) && 278*0Sstevel@tonic-gate (((key & INOFND) && ip->e_type != type) || 279*0Sstevel@tonic-gate ((key & NAMEFND) && np->e_type != type))) 280*0Sstevel@tonic-gate key |= MODECHG; 281*0Sstevel@tonic-gate 282*0Sstevel@tonic-gate /* 283*0Sstevel@tonic-gate * Decide on the disposition of the file based on its flags. 284*0Sstevel@tonic-gate * Note that we have already handled the case in which 285*0Sstevel@tonic-gate * a name and inode are found that correspond to different files. 286*0Sstevel@tonic-gate * Thus if both NAMEFND and INOFND are set then ip == np. 287*0Sstevel@tonic-gate */ 288*0Sstevel@tonic-gate switch (key) { 289*0Sstevel@tonic-gate 290*0Sstevel@tonic-gate /* 291*0Sstevel@tonic-gate * A previously existing file has been found. 292*0Sstevel@tonic-gate * Mark it as KEEP so that other links to the inode can be 293*0Sstevel@tonic-gate * detected, and so that it will not be reclaimed by the search 294*0Sstevel@tonic-gate * for unreferenced names. 295*0Sstevel@tonic-gate */ 296*0Sstevel@tonic-gate case INOFND|NAMEFND: 297*0Sstevel@tonic-gate /* LINTED: result fits into a short */ 298*0Sstevel@tonic-gate ip->e_flags |= KEEP; 299*0Sstevel@tonic-gate dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, 300*0Sstevel@tonic-gate flagvalues(ip)); 301*0Sstevel@tonic-gate break; 302*0Sstevel@tonic-gate 303*0Sstevel@tonic-gate /* 304*0Sstevel@tonic-gate * A file on the tape has a name which is the same as a name 305*0Sstevel@tonic-gate * corresponding to a different file in the previous dump. 306*0Sstevel@tonic-gate * Since all files to be deleted have already been removed, 307*0Sstevel@tonic-gate * this file is either a now-unneeded link, or it must live 308*0Sstevel@tonic-gate * under a new name in this dump level. If it is a link, it 309*0Sstevel@tonic-gate * can simply be removed. If it is not a link, it is given a 310*0Sstevel@tonic-gate * temporary name in anticipation that it will be renamed 311*0Sstevel@tonic-gate * when it is later found by inode number (see INOFND case 312*0Sstevel@tonic-gate * below). The entry is then treated as a new file. 313*0Sstevel@tonic-gate */ 314*0Sstevel@tonic-gate case ONTAPE|NAMEFND: 315*0Sstevel@tonic-gate case ONTAPE|NAMEFND|MODECHG: 316*0Sstevel@tonic-gate if (lookuptype == LINK) { 317*0Sstevel@tonic-gate removeleaf(np); 318*0Sstevel@tonic-gate freeentry(np); 319*0Sstevel@tonic-gate } else { 320*0Sstevel@tonic-gate mktempname(np); 321*0Sstevel@tonic-gate } 322*0Sstevel@tonic-gate /*FALLTHROUGH*/ 323*0Sstevel@tonic-gate 324*0Sstevel@tonic-gate /* 325*0Sstevel@tonic-gate * A previously non-existent file. 326*0Sstevel@tonic-gate * Add it to the file system, and request its extraction. 327*0Sstevel@tonic-gate * If it is a directory, create it immediately. 328*0Sstevel@tonic-gate * (Since the name is unused there can be no conflict) 329*0Sstevel@tonic-gate */ 330*0Sstevel@tonic-gate case ONTAPE: 331*0Sstevel@tonic-gate ep = addentry(name, ino, type); 332*0Sstevel@tonic-gate if (type == NODE) 333*0Sstevel@tonic-gate newnode(ep); 334*0Sstevel@tonic-gate /* LINTED: result fits into a short */ 335*0Sstevel@tonic-gate ep->e_flags |= NEW|KEEP; 336*0Sstevel@tonic-gate dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, 337*0Sstevel@tonic-gate flagvalues(ep)); 338*0Sstevel@tonic-gate break; 339*0Sstevel@tonic-gate 340*0Sstevel@tonic-gate /* 341*0Sstevel@tonic-gate * A file with the same inode number, but a different 342*0Sstevel@tonic-gate * name has been found. If the other name has not already 343*0Sstevel@tonic-gate * been found (indicated by the KEEP flag, see above) then 344*0Sstevel@tonic-gate * this must be a new name for the file, and it is renamed. 345*0Sstevel@tonic-gate * If the other name has been found then this must be a 346*0Sstevel@tonic-gate * link to the file. Hard links to directories are not 347*0Sstevel@tonic-gate * permitted, and are either deleted or converted to 348*0Sstevel@tonic-gate * symbolic links. Finally, if the file is on the tape, 349*0Sstevel@tonic-gate * a request is made to extract it. 350*0Sstevel@tonic-gate */ 351*0Sstevel@tonic-gate case ONTAPE|INOFND: 352*0Sstevel@tonic-gate if (type == LEAF && (ip->e_flags & KEEP) == 0) { 353*0Sstevel@tonic-gate /* LINTED: result fits into a short */ 354*0Sstevel@tonic-gate ip->e_flags |= EXTRACT; 355*0Sstevel@tonic-gate } 356*0Sstevel@tonic-gate /*FALLTHROUGH*/ 357*0Sstevel@tonic-gate case INOFND: 358*0Sstevel@tonic-gate if ((ip->e_flags & KEEP) == 0) { 359*0Sstevel@tonic-gate renameit(myname(ip), name); 360*0Sstevel@tonic-gate moveentry(ip, name); 361*0Sstevel@tonic-gate /* LINTED: result fits into a short */ 362*0Sstevel@tonic-gate ip->e_flags |= KEEP; 363*0Sstevel@tonic-gate dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, 364*0Sstevel@tonic-gate flagvalues(ip)); 365*0Sstevel@tonic-gate break; 366*0Sstevel@tonic-gate } 367*0Sstevel@tonic-gate if (ip->e_type == NODE) { 368*0Sstevel@tonic-gate descend = FAIL; 369*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 370*0Sstevel@tonic-gate "deleted hard link %s to directory %s\n"), 371*0Sstevel@tonic-gate name, myname(ip)); 372*0Sstevel@tonic-gate break; 373*0Sstevel@tonic-gate } 374*0Sstevel@tonic-gate ep = addentry(name, ino, type|LINK); 375*0Sstevel@tonic-gate /* LINTED: result fits into a short */ 376*0Sstevel@tonic-gate ep->e_flags |= NEW; 377*0Sstevel@tonic-gate dprintf(stdout, "[%s] %s: %s|LINK\n", keyval(key), name, 378*0Sstevel@tonic-gate flagvalues(ep)); 379*0Sstevel@tonic-gate break; 380*0Sstevel@tonic-gate 381*0Sstevel@tonic-gate /* 382*0Sstevel@tonic-gate * A previously known file which is to be updated. 383*0Sstevel@tonic-gate */ 384*0Sstevel@tonic-gate case ONTAPE|INOFND|NAMEFND: 385*0Sstevel@tonic-gate if (type == LEAF && lookuptype != LINK) { 386*0Sstevel@tonic-gate /* LINTED: result fits into a short */ 387*0Sstevel@tonic-gate np->e_flags |= EXTRACT; 388*0Sstevel@tonic-gate } 389*0Sstevel@tonic-gate /* LINTED: result fits into a short */ 390*0Sstevel@tonic-gate np->e_flags |= KEEP; 391*0Sstevel@tonic-gate dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, 392*0Sstevel@tonic-gate flagvalues(np)); 393*0Sstevel@tonic-gate break; 394*0Sstevel@tonic-gate 395*0Sstevel@tonic-gate /* 396*0Sstevel@tonic-gate * An inode is being reused in a completely different way. 397*0Sstevel@tonic-gate * Normally an extract can simply do an "unlink" followed 398*0Sstevel@tonic-gate * by a "creat". Here we must do effectively the same 399*0Sstevel@tonic-gate * thing. The complications arise because we cannot really 400*0Sstevel@tonic-gate * delete a directory since it may still contain files 401*0Sstevel@tonic-gate * that we need to rename, so we delete it from the symbol 402*0Sstevel@tonic-gate * table, and put it on the list to be deleted eventually. 403*0Sstevel@tonic-gate * Conversely if a directory is to be created, it must be 404*0Sstevel@tonic-gate * done immediately, rather than waiting until the 405*0Sstevel@tonic-gate * extraction phase. 406*0Sstevel@tonic-gate */ 407*0Sstevel@tonic-gate case ONTAPE|INOFND|MODECHG: 408*0Sstevel@tonic-gate case ONTAPE|INOFND|NAMEFND|MODECHG: 409*0Sstevel@tonic-gate if (ip->e_flags & KEEP) { 410*0Sstevel@tonic-gate badentry(ip, gettext("cannot KEEP and change modes")); 411*0Sstevel@tonic-gate break; 412*0Sstevel@tonic-gate } 413*0Sstevel@tonic-gate if (ip->e_type == LEAF) { 414*0Sstevel@tonic-gate /* changing from leaf to node */ 415*0Sstevel@tonic-gate removeleaf(ip); 416*0Sstevel@tonic-gate freeentry(ip); 417*0Sstevel@tonic-gate ip = addentry(name, ino, type); 418*0Sstevel@tonic-gate newnode(ip); 419*0Sstevel@tonic-gate } else { 420*0Sstevel@tonic-gate /* changing from node to leaf */ 421*0Sstevel@tonic-gate if ((ip->e_flags & TMPNAME) == 0) 422*0Sstevel@tonic-gate mktempname(ip); 423*0Sstevel@tonic-gate deleteino(ip->e_ino); 424*0Sstevel@tonic-gate ip->e_next = removelist; 425*0Sstevel@tonic-gate removelist = ip; 426*0Sstevel@tonic-gate ip = addentry(name, ino, type); 427*0Sstevel@tonic-gate } 428*0Sstevel@tonic-gate /* LINTED: result fits into a short */ 429*0Sstevel@tonic-gate ip->e_flags |= NEW|KEEP; 430*0Sstevel@tonic-gate dprintf(stdout, "[%s] %s: %s\n", keyval(key), name, 431*0Sstevel@tonic-gate flagvalues(ip)); 432*0Sstevel@tonic-gate break; 433*0Sstevel@tonic-gate 434*0Sstevel@tonic-gate /* 435*0Sstevel@tonic-gate * A hard link to a directory that has been removed. 436*0Sstevel@tonic-gate * Ignore it. 437*0Sstevel@tonic-gate */ 438*0Sstevel@tonic-gate case NAMEFND: 439*0Sstevel@tonic-gate dprintf(stdout, gettext("[%s] %s: Extraneous name\n"), 440*0Sstevel@tonic-gate keyval(key), 441*0Sstevel@tonic-gate name); 442*0Sstevel@tonic-gate descend = FAIL; 443*0Sstevel@tonic-gate break; 444*0Sstevel@tonic-gate 445*0Sstevel@tonic-gate /* 446*0Sstevel@tonic-gate * If we find a directory entry for a file that is not on 447*0Sstevel@tonic-gate * the tape, then we must have found a file that was created 448*0Sstevel@tonic-gate * while the dump was in progress. Since we have no contents 449*0Sstevel@tonic-gate * for it, we discard the name knowing that it will be on the 450*0Sstevel@tonic-gate * next incremental tape. 451*0Sstevel@tonic-gate */ 452*0Sstevel@tonic-gate case 0: 453*0Sstevel@tonic-gate (void) fprintf(stderr, 454*0Sstevel@tonic-gate gettext("%s: (inode %lu) not found on volume\n"), 455*0Sstevel@tonic-gate name, ino); 456*0Sstevel@tonic-gate break; 457*0Sstevel@tonic-gate 458*0Sstevel@tonic-gate /* 459*0Sstevel@tonic-gate * If any of these arise, something is grievously wrong with 460*0Sstevel@tonic-gate * the current state of the symbol table. 461*0Sstevel@tonic-gate */ 462*0Sstevel@tonic-gate case INOFND|NAMEFND|MODECHG: 463*0Sstevel@tonic-gate case NAMEFND|MODECHG: 464*0Sstevel@tonic-gate case INOFND|MODECHG: 465*0Sstevel@tonic-gate (void) fprintf(stderr, "[%s] %s: %s\n", 466*0Sstevel@tonic-gate keyval(key), name, gettext("inconsistent state")); 467*0Sstevel@tonic-gate done(1); 468*0Sstevel@tonic-gate /*NOTREACHED*/ 469*0Sstevel@tonic-gate 470*0Sstevel@tonic-gate /* 471*0Sstevel@tonic-gate * These states "cannot" arise for any state of the symbol table. 472*0Sstevel@tonic-gate */ 473*0Sstevel@tonic-gate case ONTAPE|MODECHG: 474*0Sstevel@tonic-gate case MODECHG: 475*0Sstevel@tonic-gate default: 476*0Sstevel@tonic-gate (void) fprintf(stderr, "[%s] %s: %s\n", 477*0Sstevel@tonic-gate keyval(key), name, gettext("impossible state")); 478*0Sstevel@tonic-gate done(1); 479*0Sstevel@tonic-gate /*NOTREACHED*/ 480*0Sstevel@tonic-gate } 481*0Sstevel@tonic-gate return (descend); 482*0Sstevel@tonic-gate } 483*0Sstevel@tonic-gate 484*0Sstevel@tonic-gate /* 485*0Sstevel@tonic-gate * Calculate the active flags in a key. 486*0Sstevel@tonic-gate */ 487*0Sstevel@tonic-gate static char * 488*0Sstevel@tonic-gate keyval(key) 489*0Sstevel@tonic-gate int key; 490*0Sstevel@tonic-gate { 491*0Sstevel@tonic-gate static char keybuf[32]; 492*0Sstevel@tonic-gate 493*0Sstevel@tonic-gate /* Note longest case is everything except |NIL */ 494*0Sstevel@tonic-gate 495*0Sstevel@tonic-gate (void) strcpy(keybuf, "|NIL"); 496*0Sstevel@tonic-gate keybuf[0] = '\0'; 497*0Sstevel@tonic-gate if (key & ONTAPE) 498*0Sstevel@tonic-gate (void) strcat(keybuf, "|ONTAPE"); 499*0Sstevel@tonic-gate if (key & INOFND) 500*0Sstevel@tonic-gate (void) strcat(keybuf, "|INOFND"); 501*0Sstevel@tonic-gate if (key & NAMEFND) 502*0Sstevel@tonic-gate (void) strcat(keybuf, "|NAMEFND"); 503*0Sstevel@tonic-gate if (key & MODECHG) 504*0Sstevel@tonic-gate (void) strcat(keybuf, "|MODECHG"); 505*0Sstevel@tonic-gate return (&keybuf[1]); 506*0Sstevel@tonic-gate } 507*0Sstevel@tonic-gate 508*0Sstevel@tonic-gate /* 509*0Sstevel@tonic-gate * Find unreferenced link names. 510*0Sstevel@tonic-gate */ 511*0Sstevel@tonic-gate void 512*0Sstevel@tonic-gate #ifdef __STDC__ 513*0Sstevel@tonic-gate findunreflinks(void) 514*0Sstevel@tonic-gate #else 515*0Sstevel@tonic-gate findunreflinks() 516*0Sstevel@tonic-gate #endif 517*0Sstevel@tonic-gate { 518*0Sstevel@tonic-gate struct entry *ep, *np; 519*0Sstevel@tonic-gate ino_t i; 520*0Sstevel@tonic-gate 521*0Sstevel@tonic-gate vprintf(stdout, gettext("Find unreferenced names.\n")); 522*0Sstevel@tonic-gate for (i = ROOTINO; i < maxino; i++) { 523*0Sstevel@tonic-gate ep = lookupino(i); 524*0Sstevel@tonic-gate if (ep == NIL || ep->e_type == LEAF || BIT(i, dumpmap) == 0) 525*0Sstevel@tonic-gate continue; 526*0Sstevel@tonic-gate for (np = ep->e_entries; np != NIL; np = np->e_sibling) { 527*0Sstevel@tonic-gate if (np->e_flags == 0) { 528*0Sstevel@tonic-gate dprintf(stdout, gettext( 529*0Sstevel@tonic-gate "%s: remove unreferenced name\n"), 530*0Sstevel@tonic-gate myname(np)); 531*0Sstevel@tonic-gate removeleaf(np); 532*0Sstevel@tonic-gate freeentry(np); 533*0Sstevel@tonic-gate } 534*0Sstevel@tonic-gate } 535*0Sstevel@tonic-gate } 536*0Sstevel@tonic-gate /* 537*0Sstevel@tonic-gate * Any leaves remaining in removed directories are unreferenced. 538*0Sstevel@tonic-gate */ 539*0Sstevel@tonic-gate for (ep = removelist; ep != NIL; ep = ep->e_next) { 540*0Sstevel@tonic-gate for (np = ep->e_entries; np != NIL; np = np->e_sibling) { 541*0Sstevel@tonic-gate if (np->e_type == LEAF) { 542*0Sstevel@tonic-gate if (np->e_flags != 0) 543*0Sstevel@tonic-gate badentry(np, gettext( 544*0Sstevel@tonic-gate "unreferenced with flags")); 545*0Sstevel@tonic-gate dprintf(stdout, gettext( 546*0Sstevel@tonic-gate "%s: remove unreferenced name\n"), 547*0Sstevel@tonic-gate myname(np)); 548*0Sstevel@tonic-gate removeleaf(np); 549*0Sstevel@tonic-gate freeentry(np); 550*0Sstevel@tonic-gate } 551*0Sstevel@tonic-gate } 552*0Sstevel@tonic-gate } 553*0Sstevel@tonic-gate } 554*0Sstevel@tonic-gate 555*0Sstevel@tonic-gate /* 556*0Sstevel@tonic-gate * Remove old nodes (directories). 557*0Sstevel@tonic-gate * Note that this routine runs in O(N*D) where: 558*0Sstevel@tonic-gate * N is the number of directory entries to be removed. 559*0Sstevel@tonic-gate * D is the maximum depth of the tree. 560*0Sstevel@tonic-gate * If N == D this can be quite slow. If the list were 561*0Sstevel@tonic-gate * topologically sorted, the deletion could be done in 562*0Sstevel@tonic-gate * time O(N). 563*0Sstevel@tonic-gate */ 564*0Sstevel@tonic-gate void 565*0Sstevel@tonic-gate #ifdef __STDC__ 566*0Sstevel@tonic-gate removeoldnodes(void) 567*0Sstevel@tonic-gate #else 568*0Sstevel@tonic-gate removeoldnodes() 569*0Sstevel@tonic-gate #endif 570*0Sstevel@tonic-gate { 571*0Sstevel@tonic-gate struct entry *ep, **prev; 572*0Sstevel@tonic-gate long change; 573*0Sstevel@tonic-gate 574*0Sstevel@tonic-gate vprintf(stdout, gettext("Remove old nodes (directories).\n")); 575*0Sstevel@tonic-gate do { 576*0Sstevel@tonic-gate change = 0; 577*0Sstevel@tonic-gate prev = &removelist; 578*0Sstevel@tonic-gate for (ep = removelist; ep != NIL; ep = *prev) { 579*0Sstevel@tonic-gate if (ep->e_entries != NIL) { 580*0Sstevel@tonic-gate prev = &ep->e_next; 581*0Sstevel@tonic-gate continue; 582*0Sstevel@tonic-gate } 583*0Sstevel@tonic-gate *prev = ep->e_next; 584*0Sstevel@tonic-gate removenode(ep); 585*0Sstevel@tonic-gate freeentry(ep); 586*0Sstevel@tonic-gate change++; 587*0Sstevel@tonic-gate } 588*0Sstevel@tonic-gate } while (change); 589*0Sstevel@tonic-gate for (ep = removelist; ep != NIL; ep = ep->e_next) 590*0Sstevel@tonic-gate badentry(ep, gettext("cannot remove, non-empty")); 591*0Sstevel@tonic-gate } 592*0Sstevel@tonic-gate 593*0Sstevel@tonic-gate /* 594*0Sstevel@tonic-gate * This is the routine used to extract files for the 'r' command. 595*0Sstevel@tonic-gate * Extract new leaves. 596*0Sstevel@tonic-gate */ 597*0Sstevel@tonic-gate void 598*0Sstevel@tonic-gate createleaves(symtabfile) 599*0Sstevel@tonic-gate char *symtabfile; 600*0Sstevel@tonic-gate { 601*0Sstevel@tonic-gate struct entry *ep; 602*0Sstevel@tonic-gate char name[MAXCOMPLEXLEN]; 603*0Sstevel@tonic-gate ino_t first; 604*0Sstevel@tonic-gate int curvol; 605*0Sstevel@tonic-gate 606*0Sstevel@tonic-gate if (command == 'R') { 607*0Sstevel@tonic-gate vprintf(stdout, gettext("Continue extraction of new leaves\n")); 608*0Sstevel@tonic-gate } else { 609*0Sstevel@tonic-gate vprintf(stdout, gettext("Extract new leaves.\n")); 610*0Sstevel@tonic-gate dumpsymtable(symtabfile, volno); 611*0Sstevel@tonic-gate } 612*0Sstevel@tonic-gate first = lowerbnd(ROOTINO); 613*0Sstevel@tonic-gate curvol = volno; 614*0Sstevel@tonic-gate while (curfile.ino < maxino) { 615*0Sstevel@tonic-gate first = lowerbnd(first); 616*0Sstevel@tonic-gate /* 617*0Sstevel@tonic-gate * If the next available file is not the one which we 618*0Sstevel@tonic-gate * expect then we have missed one or more files. Since 619*0Sstevel@tonic-gate * we do not request files that were not on the tape, 620*0Sstevel@tonic-gate * the lost files must have been due to a tape read error, 621*0Sstevel@tonic-gate * or a file that was removed while the dump was in progress. 622*0Sstevel@tonic-gate * 623*0Sstevel@tonic-gate * The loop will terminate with first == maxino, if not 624*0Sstevel@tonic-gate * sooner. Due to the e_flags manipulation, lowerbnd() 625*0Sstevel@tonic-gate * will never return its argument. 626*0Sstevel@tonic-gate */ 627*0Sstevel@tonic-gate while (first < curfile.ino) { 628*0Sstevel@tonic-gate ep = lookupino(first); 629*0Sstevel@tonic-gate if (ep == NIL) { 630*0Sstevel@tonic-gate (void) fprintf(stderr, 631*0Sstevel@tonic-gate gettext("%d: bad first\n"), first); 632*0Sstevel@tonic-gate done(1); 633*0Sstevel@tonic-gate } 634*0Sstevel@tonic-gate (void) fprintf(stderr, 635*0Sstevel@tonic-gate gettext("%s: not found on volume\n"), 636*0Sstevel@tonic-gate myname(ep)); 637*0Sstevel@tonic-gate /* LINTED: result fits into a short */ 638*0Sstevel@tonic-gate ep->e_flags &= ~(NEW|EXTRACT); 639*0Sstevel@tonic-gate first = lowerbnd(first); 640*0Sstevel@tonic-gate } 641*0Sstevel@tonic-gate /* 642*0Sstevel@tonic-gate * If we find files on the tape that have no corresponding 643*0Sstevel@tonic-gate * directory entries, then we must have found a file that 644*0Sstevel@tonic-gate * was created while the dump was in progress. Since we have 645*0Sstevel@tonic-gate * no name for it, we discard it knowing that it will be 646*0Sstevel@tonic-gate * on the next incremental tape. 647*0Sstevel@tonic-gate */ 648*0Sstevel@tonic-gate if (first != curfile.ino) { 649*0Sstevel@tonic-gate (void) fprintf(stderr, 650*0Sstevel@tonic-gate gettext("expected next file %d, got %d\n"), 651*0Sstevel@tonic-gate first, curfile.ino); 652*0Sstevel@tonic-gate skipfile(); 653*0Sstevel@tonic-gate goto next; 654*0Sstevel@tonic-gate } 655*0Sstevel@tonic-gate ep = lookupino(curfile.ino); 656*0Sstevel@tonic-gate if (ep == NIL) { 657*0Sstevel@tonic-gate (void) fprintf(stderr, 658*0Sstevel@tonic-gate gettext("unknown file on volume\n")); 659*0Sstevel@tonic-gate done(1); 660*0Sstevel@tonic-gate } 661*0Sstevel@tonic-gate if ((ep->e_flags & (NEW|EXTRACT)) == 0) 662*0Sstevel@tonic-gate badentry(ep, gettext("unexpected file on volume")); 663*0Sstevel@tonic-gate /* 664*0Sstevel@tonic-gate * If the file is to be extracted, then the old file must 665*0Sstevel@tonic-gate * be removed since its type may change from one leaf type 666*0Sstevel@tonic-gate * to another (eg "file" to "character special"). But we 667*0Sstevel@tonic-gate * also need to preserve any existing extended attributes; 668*0Sstevel@tonic-gate * so first rename the file, then move its attributes, then 669*0Sstevel@tonic-gate * remove it. 670*0Sstevel@tonic-gate */ 671*0Sstevel@tonic-gate if ((ep->e_flags & EXTRACT) != 0) { 672*0Sstevel@tonic-gate char *sname = savename(ep->e_name); 673*0Sstevel@tonic-gate complexcpy(name, myname(ep), MAXCOMPLEXLEN); 674*0Sstevel@tonic-gate mktempname(ep); 675*0Sstevel@tonic-gate (void) extractfile(name); 676*0Sstevel@tonic-gate movexattrs(myname(ep), name); 677*0Sstevel@tonic-gate removeleaf(ep); 678*0Sstevel@tonic-gate freename(ep->e_name); 679*0Sstevel@tonic-gate ep->e_name = sname; 680*0Sstevel@tonic-gate ep->e_namlen = strlen(ep->e_name); 681*0Sstevel@tonic-gate /* LINTED: result fits into a short */ 682*0Sstevel@tonic-gate ep->e_flags &= ~REMOVED; 683*0Sstevel@tonic-gate } else { 684*0Sstevel@tonic-gate (void) extractfile(myname(ep)); 685*0Sstevel@tonic-gate } 686*0Sstevel@tonic-gate /* LINTED: result fits into a short */ 687*0Sstevel@tonic-gate ep->e_flags &= ~(NEW|EXTRACT); 688*0Sstevel@tonic-gate /* 689*0Sstevel@tonic-gate * We checkpoint the restore after every tape reel, so 690*0Sstevel@tonic-gate * as to simplify the amount of work required by the 691*0Sstevel@tonic-gate * 'R' command. 692*0Sstevel@tonic-gate */ 693*0Sstevel@tonic-gate next: 694*0Sstevel@tonic-gate if (curvol != volno) { 695*0Sstevel@tonic-gate dumpsymtable(symtabfile, volno); 696*0Sstevel@tonic-gate skipmaps(); 697*0Sstevel@tonic-gate curvol = volno; 698*0Sstevel@tonic-gate } 699*0Sstevel@tonic-gate } 700*0Sstevel@tonic-gate } 701*0Sstevel@tonic-gate 702*0Sstevel@tonic-gate /* 703*0Sstevel@tonic-gate * This is the routine used to extract files for the 'x' and 'i' commands. 704*0Sstevel@tonic-gate * Efficiently extract a subset of the files on a tape. 705*0Sstevel@tonic-gate */ 706*0Sstevel@tonic-gate void 707*0Sstevel@tonic-gate #ifdef __STDC__ 708*0Sstevel@tonic-gate createfiles(void) 709*0Sstevel@tonic-gate #else 710*0Sstevel@tonic-gate createfiles() 711*0Sstevel@tonic-gate #endif 712*0Sstevel@tonic-gate { 713*0Sstevel@tonic-gate ino_t first, next, last; 714*0Sstevel@tonic-gate struct entry *ep; 715*0Sstevel@tonic-gate int curvol, nextvol; 716*0Sstevel@tonic-gate 717*0Sstevel@tonic-gate vprintf(stdout, gettext("Extract requested files\n")); 718*0Sstevel@tonic-gate first = lowerbnd(ROOTINO); 719*0Sstevel@tonic-gate last = upperbnd(maxino - 1); 720*0Sstevel@tonic-gate nextvol = volnumber(first); 721*0Sstevel@tonic-gate if (nextvol == 0) { 722*0Sstevel@tonic-gate curfile.action = SKIP; 723*0Sstevel@tonic-gate getvol(1); 724*0Sstevel@tonic-gate skipmaps(); 725*0Sstevel@tonic-gate skipdirs(); 726*0Sstevel@tonic-gate } 727*0Sstevel@tonic-gate for (;;) { 728*0Sstevel@tonic-gate first = lowerbnd(first); 729*0Sstevel@tonic-gate last = upperbnd(last); 730*0Sstevel@tonic-gate /* 731*0Sstevel@tonic-gate * Check to see if any files remain to be extracted 732*0Sstevel@tonic-gate */ 733*0Sstevel@tonic-gate if (first > last) 734*0Sstevel@tonic-gate return; 735*0Sstevel@tonic-gate /* 736*0Sstevel@tonic-gate * If a map of inode numbers to tape volumes is 737*0Sstevel@tonic-gate * available, then select the next volume to be read. 738*0Sstevel@tonic-gate */ 739*0Sstevel@tonic-gate if (nextvol > 0) { 740*0Sstevel@tonic-gate nextvol = volnumber(first); 741*0Sstevel@tonic-gate if (nextvol != volno) { 742*0Sstevel@tonic-gate curfile.action = UNKNOWN; 743*0Sstevel@tonic-gate getvol(nextvol); 744*0Sstevel@tonic-gate skipmaps(); 745*0Sstevel@tonic-gate } 746*0Sstevel@tonic-gate } 747*0Sstevel@tonic-gate /* 748*0Sstevel@tonic-gate * Reject any volumes with inodes greater than 749*0Sstevel@tonic-gate * the last one needed. This will only be true 750*0Sstevel@tonic-gate * if the above code has not selected a volume. 751*0Sstevel@tonic-gate */ 752*0Sstevel@tonic-gate while (curfile.ino > last) { 753*0Sstevel@tonic-gate curfile.action = SKIP; 754*0Sstevel@tonic-gate getvol(0); 755*0Sstevel@tonic-gate skipmaps(); 756*0Sstevel@tonic-gate skipdirs(); 757*0Sstevel@tonic-gate } 758*0Sstevel@tonic-gate /* 759*0Sstevel@tonic-gate * Decide on the next inode needed. 760*0Sstevel@tonic-gate * Skip across the inodes until it is found 761*0Sstevel@tonic-gate * or an out of order volume change is encountered 762*0Sstevel@tonic-gate */ 763*0Sstevel@tonic-gate next = lowerbnd(curfile.ino); 764*0Sstevel@tonic-gate do { 765*0Sstevel@tonic-gate curvol = volno; 766*0Sstevel@tonic-gate while (next > curfile.ino && volno == curvol) 767*0Sstevel@tonic-gate skipfile(); 768*0Sstevel@tonic-gate skipmaps(); 769*0Sstevel@tonic-gate skipdirs(); 770*0Sstevel@tonic-gate } while (volno == curvol + 1); 771*0Sstevel@tonic-gate /* 772*0Sstevel@tonic-gate * If volume change out of order occurred the 773*0Sstevel@tonic-gate * current state must be recalculated 774*0Sstevel@tonic-gate */ 775*0Sstevel@tonic-gate if (volno != curvol) 776*0Sstevel@tonic-gate continue; 777*0Sstevel@tonic-gate /* 778*0Sstevel@tonic-gate * If the current inode is greater than the one we were 779*0Sstevel@tonic-gate * looking for then we missed the one we were looking for. 780*0Sstevel@tonic-gate * Since we only attempt to extract files listed in the 781*0Sstevel@tonic-gate * dump map, the lost files must have been due to a tape 782*0Sstevel@tonic-gate * read error, or a file that was removed while the dump 783*0Sstevel@tonic-gate * was in progress. Thus we report all requested files 784*0Sstevel@tonic-gate * between the one we were looking for, and the one we 785*0Sstevel@tonic-gate * found as missing, and delete their request flags. 786*0Sstevel@tonic-gate */ 787*0Sstevel@tonic-gate while (next < curfile.ino) { 788*0Sstevel@tonic-gate ep = lookupino(next); 789*0Sstevel@tonic-gate if (ep == NIL) { 790*0Sstevel@tonic-gate (void) fprintf(stderr, 791*0Sstevel@tonic-gate gettext("corrupted symbol table\n")); 792*0Sstevel@tonic-gate done(1); 793*0Sstevel@tonic-gate } 794*0Sstevel@tonic-gate (void) fprintf(stderr, 795*0Sstevel@tonic-gate gettext("%s: not found on volume\n"), 796*0Sstevel@tonic-gate myname(ep)); 797*0Sstevel@tonic-gate /* LINTED: result fits into a short */ 798*0Sstevel@tonic-gate ep->e_flags &= ~NEW; 799*0Sstevel@tonic-gate next = lowerbnd(next); 800*0Sstevel@tonic-gate } 801*0Sstevel@tonic-gate /* 802*0Sstevel@tonic-gate * The current inode is the one that we are looking for, 803*0Sstevel@tonic-gate * so extract it per its requested name. 804*0Sstevel@tonic-gate */ 805*0Sstevel@tonic-gate if (next == curfile.ino && next <= last) { 806*0Sstevel@tonic-gate ep = lookupino(next); 807*0Sstevel@tonic-gate if (ep == NIL) { 808*0Sstevel@tonic-gate (void) fprintf(stderr, 809*0Sstevel@tonic-gate gettext("corrupted symbol table\n")); 810*0Sstevel@tonic-gate done(1); 811*0Sstevel@tonic-gate } 812*0Sstevel@tonic-gate (void) extractfile(myname(ep)); 813*0Sstevel@tonic-gate /* LINTED: result fits into a short */ 814*0Sstevel@tonic-gate ep->e_flags &= ~NEW; 815*0Sstevel@tonic-gate if (volno != curvol) 816*0Sstevel@tonic-gate skipmaps(); 817*0Sstevel@tonic-gate } 818*0Sstevel@tonic-gate } 819*0Sstevel@tonic-gate } 820*0Sstevel@tonic-gate 821*0Sstevel@tonic-gate /* 822*0Sstevel@tonic-gate * Add links. 823*0Sstevel@tonic-gate */ 824*0Sstevel@tonic-gate void 825*0Sstevel@tonic-gate #ifdef __STDC__ 826*0Sstevel@tonic-gate createlinks(void) 827*0Sstevel@tonic-gate #else 828*0Sstevel@tonic-gate createlinks() 829*0Sstevel@tonic-gate #endif 830*0Sstevel@tonic-gate { 831*0Sstevel@tonic-gate struct entry *np, *ep; 832*0Sstevel@tonic-gate ino_t i; 833*0Sstevel@tonic-gate int dfd; 834*0Sstevel@tonic-gate char *to, *from; 835*0Sstevel@tonic-gate int saverr; 836*0Sstevel@tonic-gate 837*0Sstevel@tonic-gate vprintf(stdout, gettext("Add links\n")); 838*0Sstevel@tonic-gate for (i = ROOTINO; i < maxino; i++) { 839*0Sstevel@tonic-gate ep = lookupino(i); 840*0Sstevel@tonic-gate if (ep == NIL) 841*0Sstevel@tonic-gate continue; 842*0Sstevel@tonic-gate to = savename(myname(ep)); 843*0Sstevel@tonic-gate for (np = ep->e_links; np != NIL; np = np->e_links) { 844*0Sstevel@tonic-gate if ((np->e_flags & NEW) == 0) 845*0Sstevel@tonic-gate continue; 846*0Sstevel@tonic-gate resolve(myname(np), &dfd, &from); 847*0Sstevel@tonic-gate if (dfd != AT_FDCWD) { 848*0Sstevel@tonic-gate if (fchdir(dfd) < 0) { 849*0Sstevel@tonic-gate saverr = errno; 850*0Sstevel@tonic-gate (void) fprintf(stderr, 851*0Sstevel@tonic-gate gettext("%s->%s: link failed: %s\n"), 852*0Sstevel@tonic-gate from, to, strerror(saverr)); 853*0Sstevel@tonic-gate (void) close(dfd); 854*0Sstevel@tonic-gate continue; 855*0Sstevel@tonic-gate } 856*0Sstevel@tonic-gate } 857*0Sstevel@tonic-gate if (ep->e_type == NODE) { 858*0Sstevel@tonic-gate (void) lf_linkit(to, from, SYMLINK); 859*0Sstevel@tonic-gate } else { 860*0Sstevel@tonic-gate (void) lf_linkit(to, from, HARDLINK); 861*0Sstevel@tonic-gate } 862*0Sstevel@tonic-gate /* LINTED: result fits into a short */ 863*0Sstevel@tonic-gate np->e_flags &= ~NEW; 864*0Sstevel@tonic-gate if (dfd != AT_FDCWD) { 865*0Sstevel@tonic-gate fchdir(savepwd); 866*0Sstevel@tonic-gate (void) close(dfd); 867*0Sstevel@tonic-gate } 868*0Sstevel@tonic-gate } 869*0Sstevel@tonic-gate freename(to); 870*0Sstevel@tonic-gate } 871*0Sstevel@tonic-gate } 872*0Sstevel@tonic-gate 873*0Sstevel@tonic-gate /* 874*0Sstevel@tonic-gate * Check the symbol table. 875*0Sstevel@tonic-gate * We do this to insure that all the requested work was done, and 876*0Sstevel@tonic-gate * that no temporary names remain. 877*0Sstevel@tonic-gate */ 878*0Sstevel@tonic-gate void 879*0Sstevel@tonic-gate #ifdef __STDC__ 880*0Sstevel@tonic-gate checkrestore(void) 881*0Sstevel@tonic-gate #else 882*0Sstevel@tonic-gate checkrestore() 883*0Sstevel@tonic-gate #endif 884*0Sstevel@tonic-gate { 885*0Sstevel@tonic-gate struct entry *ep; 886*0Sstevel@tonic-gate ino_t i; 887*0Sstevel@tonic-gate 888*0Sstevel@tonic-gate vprintf(stdout, gettext("Check the symbol table.\n")); 889*0Sstevel@tonic-gate for (i = ROOTINO; i < maxino; i++) { 890*0Sstevel@tonic-gate for (ep = lookupino(i); ep != NIL; ep = ep->e_links) { 891*0Sstevel@tonic-gate /* LINTED: result fits into a short */ 892*0Sstevel@tonic-gate ep->e_flags &= ~KEEP; 893*0Sstevel@tonic-gate if (ep->e_type == NODE) { 894*0Sstevel@tonic-gate /* LINTED: result fits into a short */ 895*0Sstevel@tonic-gate ep->e_flags &= ~(NEW|EXISTED); 896*0Sstevel@tonic-gate } 897*0Sstevel@tonic-gate if ((ep->e_flags & ~(XATTR|XATTRROOT)) != 0) 898*0Sstevel@tonic-gate badentry(ep, gettext("incomplete operations")); 899*0Sstevel@tonic-gate } 900*0Sstevel@tonic-gate } 901*0Sstevel@tonic-gate } 902*0Sstevel@tonic-gate 903*0Sstevel@tonic-gate /* 904*0Sstevel@tonic-gate * Compare with the directory structure on the tape 905*0Sstevel@tonic-gate * A paranoid check that things are as they should be. 906*0Sstevel@tonic-gate */ 907*0Sstevel@tonic-gate long 908*0Sstevel@tonic-gate verifyfile(name, ino, type) 909*0Sstevel@tonic-gate char *name; 910*0Sstevel@tonic-gate ino_t ino; 911*0Sstevel@tonic-gate int type; 912*0Sstevel@tonic-gate { 913*0Sstevel@tonic-gate struct entry *np, *ep; 914*0Sstevel@tonic-gate long descend = GOOD; 915*0Sstevel@tonic-gate 916*0Sstevel@tonic-gate ep = lookupname(name); 917*0Sstevel@tonic-gate if (ep == NIL) { 918*0Sstevel@tonic-gate (void) fprintf(stderr, 919*0Sstevel@tonic-gate gettext("Warning: missing name %s\n"), name); 920*0Sstevel@tonic-gate return (FAIL); 921*0Sstevel@tonic-gate } 922*0Sstevel@tonic-gate np = lookupino(ino); 923*0Sstevel@tonic-gate if (np != ep) 924*0Sstevel@tonic-gate descend = FAIL; 925*0Sstevel@tonic-gate for (; np != NIL; np = np->e_links) 926*0Sstevel@tonic-gate if (np == ep) 927*0Sstevel@tonic-gate break; 928*0Sstevel@tonic-gate if (np == NIL) { 929*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("missing inumber %d\n"), ino); 930*0Sstevel@tonic-gate done(1); 931*0Sstevel@tonic-gate } 932*0Sstevel@tonic-gate if (ep->e_type == LEAF && type != LEAF) 933*0Sstevel@tonic-gate badentry(ep, gettext("type should be LEAF")); 934*0Sstevel@tonic-gate return (descend); 935*0Sstevel@tonic-gate } 936*0Sstevel@tonic-gate 937*0Sstevel@tonic-gate /* 938*0Sstevel@tonic-gate * This routine does not actually remove any attribute files, it 939*0Sstevel@tonic-gate * just removes entries from the symbol table. The attribute files 940*0Sstevel@tonic-gate * themselves are assumed to be removed automatically when the 941*0Sstevel@tonic-gate * parent file is removed. 942*0Sstevel@tonic-gate */ 943*0Sstevel@tonic-gate static void 944*0Sstevel@tonic-gate removexattrs(ep) 945*0Sstevel@tonic-gate struct entry *ep; 946*0Sstevel@tonic-gate { 947*0Sstevel@tonic-gate struct entry *np = ep; 948*0Sstevel@tonic-gate 949*0Sstevel@tonic-gate if (ep == NIL) 950*0Sstevel@tonic-gate return; 951*0Sstevel@tonic-gate for (np = ep->e_entries; np != NIL; np = np->e_sibling) { 952*0Sstevel@tonic-gate if (np->e_type == NODE) { 953*0Sstevel@tonic-gate removexattrs(np); 954*0Sstevel@tonic-gate } else { 955*0Sstevel@tonic-gate np->e_flags |= REMOVED; 956*0Sstevel@tonic-gate freeentry(np); 957*0Sstevel@tonic-gate } 958*0Sstevel@tonic-gate } 959*0Sstevel@tonic-gate ep->e_flags |= REMOVED; 960*0Sstevel@tonic-gate freeentry(ep); 961*0Sstevel@tonic-gate } 962*0Sstevel@tonic-gate 963*0Sstevel@tonic-gate /* 964*0Sstevel@tonic-gate * Move all the extended attributes associated with orig to 965*0Sstevel@tonic-gate * the file named by the second argument (targ). 966*0Sstevel@tonic-gate */ 967*0Sstevel@tonic-gate static void 968*0Sstevel@tonic-gate movexattrs(orig, targ) 969*0Sstevel@tonic-gate char *orig; 970*0Sstevel@tonic-gate char *targ; 971*0Sstevel@tonic-gate { 972*0Sstevel@tonic-gate char *to, *from; 973*0Sstevel@tonic-gate int fromfd, fromdir, tofd, todir, tfd; 974*0Sstevel@tonic-gate DIR *dirp = NULL; 975*0Sstevel@tonic-gate struct dirent *dp = NULL; 976*0Sstevel@tonic-gate 977*0Sstevel@tonic-gate fromfd = tofd = fromdir = todir = tfd = -1; 978*0Sstevel@tonic-gate 979*0Sstevel@tonic-gate resolve(orig, &tfd, &from); 980*0Sstevel@tonic-gate if (tfd == AT_FDCWD && pathconf(orig, _PC_XATTR_EXISTS) != 1) { 981*0Sstevel@tonic-gate /* no attributes to move */ 982*0Sstevel@tonic-gate return; 983*0Sstevel@tonic-gate } 984*0Sstevel@tonic-gate if ((fromfd = openat64(tfd, from, O_RDONLY|O_NONBLOCK)) == -1) { 985*0Sstevel@tonic-gate fprintf(stderr, gettext("%s: cannot move attributes: "), from); 986*0Sstevel@tonic-gate perror(""); 987*0Sstevel@tonic-gate if (tfd != AT_FDCWD) (void) close(tfd); 988*0Sstevel@tonic-gate goto out; 989*0Sstevel@tonic-gate } 990*0Sstevel@tonic-gate 991*0Sstevel@tonic-gate if (fpathconf(fromfd, _PC_XATTR_EXISTS) != 1) { 992*0Sstevel@tonic-gate /* no attributes to move */ 993*0Sstevel@tonic-gate if (tfd != AT_FDCWD) (void) close(tfd); 994*0Sstevel@tonic-gate goto out; 995*0Sstevel@tonic-gate } 996*0Sstevel@tonic-gate if ((fromdir = openat64(fromfd, ".", 997*0Sstevel@tonic-gate O_RDONLY|O_NONBLOCK|O_XATTR)) == -1) { 998*0Sstevel@tonic-gate fprintf(stderr, gettext("%s: cannot access attributes: "), 999*0Sstevel@tonic-gate from); 1000*0Sstevel@tonic-gate perror(""); 1001*0Sstevel@tonic-gate if (tfd != AT_FDCWD) (void) close(tfd); 1002*0Sstevel@tonic-gate goto out; 1003*0Sstevel@tonic-gate } 1004*0Sstevel@tonic-gate if (tfd != AT_FDCWD) (void) close(tfd); 1005*0Sstevel@tonic-gate 1006*0Sstevel@tonic-gate resolve(targ, &tfd, &to); 1007*0Sstevel@tonic-gate if ((tofd = openat64(tfd, to, O_RDONLY|O_NONBLOCK)) == -1 || 1008*0Sstevel@tonic-gate (todir = openat64(tofd, ".", O_RDONLY|O_NONBLOCK|O_XATTR)) == -1) { 1009*0Sstevel@tonic-gate fprintf(stderr, gettext("%s: cannot create attributes: "), to); 1010*0Sstevel@tonic-gate perror(""); 1011*0Sstevel@tonic-gate goto out; 1012*0Sstevel@tonic-gate } 1013*0Sstevel@tonic-gate if (tfd != AT_FDCWD) (void) close(tfd); 1014*0Sstevel@tonic-gate (void) close(tofd); 1015*0Sstevel@tonic-gate 1016*0Sstevel@tonic-gate if ((tfd = dup(fromdir)) == -1 || 1017*0Sstevel@tonic-gate (dirp = fdopendir(tfd)) == NULL) { 1018*0Sstevel@tonic-gate fprintf(stderr, 1019*0Sstevel@tonic-gate gettext("%s: cannot allocate DIR structure to attribute directory: "), 1020*0Sstevel@tonic-gate from); 1021*0Sstevel@tonic-gate perror(""); 1022*0Sstevel@tonic-gate if (tfd != -1) (void) close(tfd); 1023*0Sstevel@tonic-gate goto out; 1024*0Sstevel@tonic-gate } 1025*0Sstevel@tonic-gate 1026*0Sstevel@tonic-gate while ((dp = readdir(dirp)) != NULL) { 1027*0Sstevel@tonic-gate if ((dp->d_name[0] == '.' && dp->d_name[1] == '\0') || 1028*0Sstevel@tonic-gate (dp->d_name[0] == '.' && dp->d_name[1] == '.' && 1029*0Sstevel@tonic-gate dp->d_name[2] == '\0')) 1030*0Sstevel@tonic-gate continue; 1031*0Sstevel@tonic-gate if ((renameat(fromdir, dp->d_name, todir, dp->d_name)) == -1) { 1032*0Sstevel@tonic-gate fprintf(stderr, 1033*0Sstevel@tonic-gate gettext("%s: cannot move attribute %s: "), 1034*0Sstevel@tonic-gate from, dp->d_name); 1035*0Sstevel@tonic-gate goto out; 1036*0Sstevel@tonic-gate } 1037*0Sstevel@tonic-gate } 1038*0Sstevel@tonic-gate out: 1039*0Sstevel@tonic-gate if (fromfd != -1) 1040*0Sstevel@tonic-gate (void) close(fromfd); 1041*0Sstevel@tonic-gate if (tofd != -1) 1042*0Sstevel@tonic-gate (void) close(tofd); 1043*0Sstevel@tonic-gate if (dirp != NULL) 1044*0Sstevel@tonic-gate (void) closedir(dirp); 1045*0Sstevel@tonic-gate if (fromdir != -1) 1046*0Sstevel@tonic-gate (void) close(fromdir); 1047*0Sstevel@tonic-gate if (todir != -1) 1048*0Sstevel@tonic-gate (void) close(todir); 1049*0Sstevel@tonic-gate } 1050