10Sstevel@tonic-gate /* 2*426Srm88369 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3*426Srm88369 * Use is subject to license terms. 40Sstevel@tonic-gate */ 50Sstevel@tonic-gate 60Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 70Sstevel@tonic-gate /* All Rights Reserved */ 80Sstevel@tonic-gate 90Sstevel@tonic-gate /* 100Sstevel@tonic-gate * Copyright (c) 1983 Regents of the University of California. 110Sstevel@tonic-gate * All rights reserved. The Berkeley software License Agreement 120Sstevel@tonic-gate * specifies the terms and conditions for redistribution. 130Sstevel@tonic-gate */ 140Sstevel@tonic-gate 150Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 160Sstevel@tonic-gate 170Sstevel@tonic-gate #include "restore.h" 180Sstevel@tonic-gate #include <byteorder.h> 190Sstevel@tonic-gate #include <stdlib.h> 200Sstevel@tonic-gate #include <unistd.h> 210Sstevel@tonic-gate #include <utime.h> 220Sstevel@tonic-gate 230Sstevel@tonic-gate /* 240Sstevel@tonic-gate * Symbol table of directories read from tape. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate #define HASHSIZE 1000 270Sstevel@tonic-gate #define INOHASH(val) (val % HASHSIZE) 280Sstevel@tonic-gate struct inotab { 290Sstevel@tonic-gate struct inotab *t_next; 300Sstevel@tonic-gate ino_t t_ino; 310Sstevel@tonic-gate offset_t t_seekpt; 320Sstevel@tonic-gate offset_t t_size; 330Sstevel@tonic-gate struct inotab *t_xattr; 340Sstevel@tonic-gate }; 350Sstevel@tonic-gate static struct inotab *inotab[HASHSIZE]; 360Sstevel@tonic-gate static struct inotab *xattrlist = NULL; 370Sstevel@tonic-gate 380Sstevel@tonic-gate /* 390Sstevel@tonic-gate * Information retained about directories. 400Sstevel@tonic-gate */ 410Sstevel@tonic-gate static struct modeinfo { 420Sstevel@tonic-gate ino_t ino; 430Sstevel@tonic-gate time_t timep[2]; 440Sstevel@tonic-gate mode_t mode; 450Sstevel@tonic-gate uid_t uid; 460Sstevel@tonic-gate gid_t gid; 470Sstevel@tonic-gate size_t metasize; 480Sstevel@tonic-gate } node; 490Sstevel@tonic-gate 500Sstevel@tonic-gate /* 510Sstevel@tonic-gate * Global variables for this file. 520Sstevel@tonic-gate */ 530Sstevel@tonic-gate static off64_t g_seekpt; /* some people have a local seekpt */ 540Sstevel@tonic-gate static FILE *df, *mf; 550Sstevel@tonic-gate static char dirfile[MAXPATHLEN] = "#"; /* No file */ 560Sstevel@tonic-gate static char modefile[MAXPATHLEN] = "#"; /* No file */ 570Sstevel@tonic-gate 580Sstevel@tonic-gate static RST_DIR *dirp; 590Sstevel@tonic-gate 600Sstevel@tonic-gate #define INIT_TEMPFILE(name, type) \ 610Sstevel@tonic-gate if (name[0] == '#') { \ 620Sstevel@tonic-gate if (tmpdir == (char *)NULL) /* can't happen; be paranoid */ \ 630Sstevel@tonic-gate tmpdir = "/tmp"; \ 640Sstevel@tonic-gate (void) snprintf(name, sizeof (name), \ 650Sstevel@tonic-gate "%s/rst" type "%ld.XXXXXX", tmpdir, dumpdate); \ 660Sstevel@tonic-gate (void) mktemp(name); \ 670Sstevel@tonic-gate } 680Sstevel@tonic-gate 690Sstevel@tonic-gate #define INIT_DIRFILE() INIT_TEMPFILE(dirfile, "dir") 700Sstevel@tonic-gate #define INIT_MODEFILE() INIT_TEMPFILE(modefile, "mode") 710Sstevel@tonic-gate 720Sstevel@tonic-gate /* 730Sstevel@tonic-gate * Format of old style directories. 740Sstevel@tonic-gate */ 750Sstevel@tonic-gate #define ODIRSIZ 14 760Sstevel@tonic-gate struct odirect { 770Sstevel@tonic-gate ushort_t d_ino; 780Sstevel@tonic-gate char d_name[ODIRSIZ]; 790Sstevel@tonic-gate }; 800Sstevel@tonic-gate 810Sstevel@tonic-gate #ifdef __STDC__ 820Sstevel@tonic-gate static ino_t search(ino_t, char *); 830Sstevel@tonic-gate static void putdir(char *, size_t); 840Sstevel@tonic-gate static void putent(struct direct *); 850Sstevel@tonic-gate static void skipmetadata(FILE *, size_t); 860Sstevel@tonic-gate static void flushent(void); 870Sstevel@tonic-gate static void dcvt(struct odirect *, struct direct *); 880Sstevel@tonic-gate static RST_DIR *rst_initdirfile(char *); 890Sstevel@tonic-gate static offset_t rst_telldir(RST_DIR *); 900Sstevel@tonic-gate static void rst_seekdir(RST_DIR *, offset_t, offset_t); 910Sstevel@tonic-gate static struct inotab *allocinotab(ino_t, struct dinode *, off64_t); 920Sstevel@tonic-gate static void nodeflush(void); 930Sstevel@tonic-gate static struct inotab *inotablookup(ino_t); 940Sstevel@tonic-gate #else 950Sstevel@tonic-gate static ino_t search(); 960Sstevel@tonic-gate static void putdir(); 970Sstevel@tonic-gate static void putent(); 980Sstevel@tonic-gate static void skipmetadata(); 990Sstevel@tonic-gate static void flushent(); 1000Sstevel@tonic-gate static void dcvt(); 1010Sstevel@tonic-gate static RST_DIR *rst_initdirfile(); 1020Sstevel@tonic-gate static offset_t rst_telldir(); 1030Sstevel@tonic-gate static void rst_seekdir(); 1040Sstevel@tonic-gate static struct inotab *allocinotab(); 1050Sstevel@tonic-gate static void nodeflush(); 1060Sstevel@tonic-gate static struct inotab *inotablookup(); 1070Sstevel@tonic-gate #endif 1080Sstevel@tonic-gate 1090Sstevel@tonic-gate /* 1100Sstevel@tonic-gate * Extract directory contents, building up a directory structure 1110Sstevel@tonic-gate * on disk for extraction by name. 1120Sstevel@tonic-gate * If genmode is requested, save mode, owner, and times for all 1130Sstevel@tonic-gate * directories on the tape. 1140Sstevel@tonic-gate */ 1150Sstevel@tonic-gate void 1160Sstevel@tonic-gate extractdirs(genmode) 1170Sstevel@tonic-gate int genmode; 1180Sstevel@tonic-gate { 1190Sstevel@tonic-gate int ts; 1200Sstevel@tonic-gate struct dinode *ip; 1210Sstevel@tonic-gate int saverr; 1220Sstevel@tonic-gate struct inotab *itp; 1230Sstevel@tonic-gate struct direct nulldir; 1240Sstevel@tonic-gate static char dotname[] = "."; /* dirlookup/psearch writes to its arg */ 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate vprintf(stdout, gettext("Extract directories from tape\n")); 1270Sstevel@tonic-gate INIT_DIRFILE(); 1280Sstevel@tonic-gate if ((df = safe_fopen(dirfile, "w", 0600)) == (FILE *)NULL) { 1290Sstevel@tonic-gate saverr = errno; 1300Sstevel@tonic-gate (void) fprintf(stderr, 1310Sstevel@tonic-gate gettext("%s: %s - cannot create directory temporary\n"), 1320Sstevel@tonic-gate progname, dirfile); 1330Sstevel@tonic-gate errno = saverr; 1340Sstevel@tonic-gate perror("fopen"); 1350Sstevel@tonic-gate done(1); 1360Sstevel@tonic-gate } 1370Sstevel@tonic-gate if (genmode != 0) { 1380Sstevel@tonic-gate INIT_MODEFILE(); 1390Sstevel@tonic-gate if ((mf = safe_fopen(modefile, "w", 0600)) == (FILE *)NULL) { 1400Sstevel@tonic-gate saverr = errno; 1410Sstevel@tonic-gate (void) fprintf(stderr, 1420Sstevel@tonic-gate gettext("%s: %s - cannot create modefile \n"), 1430Sstevel@tonic-gate progname, modefile); 1440Sstevel@tonic-gate errno = saverr; 1450Sstevel@tonic-gate perror("fopen"); 1460Sstevel@tonic-gate done(1); 1470Sstevel@tonic-gate } 1480Sstevel@tonic-gate } 1490Sstevel@tonic-gate nulldir.d_ino = 0; 1500Sstevel@tonic-gate nulldir.d_namlen = 1; 1510Sstevel@tonic-gate (void) strcpy(nulldir.d_name, "/"); 1520Sstevel@tonic-gate /* LINTED DIRSIZ will always fit into a ushort_t */ 1530Sstevel@tonic-gate nulldir.d_reclen = (ushort_t)DIRSIZ(&nulldir); 1540Sstevel@tonic-gate /* LINTED sign extension ok in assert */ 1550Sstevel@tonic-gate assert(DIRSIZ(&nulldir) == (ulong_t)nulldir.d_reclen); 1560Sstevel@tonic-gate for (;;) { 1570Sstevel@tonic-gate curfile.name = gettext("<directory file - name unknown>"); 1580Sstevel@tonic-gate curfile.action = USING; 1590Sstevel@tonic-gate ip = curfile.dip; 1600Sstevel@tonic-gate ts = curfile.ts; 1610Sstevel@tonic-gate if (ts != TS_END && ts != TS_INODE) { 1620Sstevel@tonic-gate getfile(null, null); 1630Sstevel@tonic-gate continue; 1640Sstevel@tonic-gate } 1650Sstevel@tonic-gate if (ts == TS_INODE && ip == NULL) { 1660Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1670Sstevel@tonic-gate "%s: extractdirs: Failed internal consistency check, curfile.dip is NULL\n"), 1680Sstevel@tonic-gate progname); 1690Sstevel@tonic-gate done(1); 1700Sstevel@tonic-gate } 1710Sstevel@tonic-gate if ((ts == TS_INODE && (ip->di_mode & IFMT) != IFDIR && 1720Sstevel@tonic-gate (ip->di_mode & IFMT) != IFATTRDIR) || 1730Sstevel@tonic-gate (ts == TS_END)) { 1740Sstevel@tonic-gate (void) fflush(df); 1750Sstevel@tonic-gate /* XXX Legitimate error, bad complaint string */ 1760Sstevel@tonic-gate if (ferror(df)) 1770Sstevel@tonic-gate panic("%s: %s\n", dirfile, strerror(errno)); 1780Sstevel@tonic-gate (void) fclose(df); 1790Sstevel@tonic-gate rst_closedir(dirp); 1800Sstevel@tonic-gate dirp = rst_initdirfile(dirfile); 1810Sstevel@tonic-gate if (dirp == NULL) 1820Sstevel@tonic-gate perror("initdirfile"); 1830Sstevel@tonic-gate if (mf != NULL) { 1840Sstevel@tonic-gate (void) fflush(mf); 1850Sstevel@tonic-gate /* XXX Legitimate error, bad complaint string */ 1860Sstevel@tonic-gate if (ferror(mf)) 1870Sstevel@tonic-gate panic("%s: %s\n", 1880Sstevel@tonic-gate modefile, strerror(errno)); 1890Sstevel@tonic-gate (void) fclose(mf); 1900Sstevel@tonic-gate } 1910Sstevel@tonic-gate if (dirlookup(dotname) == 0) { 1920Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1930Sstevel@tonic-gate "Root directory is not on tape\n")); 1940Sstevel@tonic-gate done(1); 1950Sstevel@tonic-gate } 1960Sstevel@tonic-gate return; 1970Sstevel@tonic-gate } 1980Sstevel@tonic-gate itp = allocinotab(curfile.ino, ip, g_seekpt); 1990Sstevel@tonic-gate getfile(putdir, null); 2000Sstevel@tonic-gate if (mf != NULL) 2010Sstevel@tonic-gate nodeflush(); 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate putent(&nulldir); 2040Sstevel@tonic-gate flushent(); 2050Sstevel@tonic-gate itp->t_size = g_seekpt - itp->t_seekpt; 2060Sstevel@tonic-gate } 2070Sstevel@tonic-gate } 2080Sstevel@tonic-gate 2090Sstevel@tonic-gate /* 2100Sstevel@tonic-gate * skip over all the directories on the tape 2110Sstevel@tonic-gate */ 2120Sstevel@tonic-gate void 2130Sstevel@tonic-gate skipdirs() 2140Sstevel@tonic-gate { 2150Sstevel@tonic-gate while (curfile.dip != NULL && 2160Sstevel@tonic-gate ((curfile.dip->di_mode & IFMT) == IFDIR || 2170Sstevel@tonic-gate (curfile.dip->di_mode & IFMT) == IFATTRDIR)) { 2180Sstevel@tonic-gate skipfile(); 2190Sstevel@tonic-gate } 2200Sstevel@tonic-gate } 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate /* 2230Sstevel@tonic-gate * Recursively find names and inumbers of all files in subtree 2240Sstevel@tonic-gate * pname and pass them off to be processed. 2250Sstevel@tonic-gate */ 2260Sstevel@tonic-gate void 2270Sstevel@tonic-gate treescan(pname, ino, todo) 2280Sstevel@tonic-gate char *pname; 2290Sstevel@tonic-gate ino_t ino; 2300Sstevel@tonic-gate long (*todo)(); 2310Sstevel@tonic-gate { 2320Sstevel@tonic-gate struct inotab *itp; 2330Sstevel@tonic-gate struct direct *dp; 2340Sstevel@tonic-gate uint_t loclen; 2350Sstevel@tonic-gate offset_t bpt; 2360Sstevel@tonic-gate char locname[MAXCOMPLEXLEN]; 2370Sstevel@tonic-gate 2380Sstevel@tonic-gate itp = inotablookup(ino); 2390Sstevel@tonic-gate if (itp == NULL) { 2400Sstevel@tonic-gate /* 2410Sstevel@tonic-gate * Pname is name of a simple file or an unchanged directory. 2420Sstevel@tonic-gate */ 2430Sstevel@tonic-gate (void) (*todo)(pname, ino, LEAF); 2440Sstevel@tonic-gate return; 2450Sstevel@tonic-gate } 2460Sstevel@tonic-gate /* 2470Sstevel@tonic-gate * Pname is a dumped directory name. 2480Sstevel@tonic-gate */ 2490Sstevel@tonic-gate if ((*todo)(pname, ino, NODE) == FAIL) 2500Sstevel@tonic-gate return; 2510Sstevel@tonic-gate /* 2520Sstevel@tonic-gate * begin search through the directory 2530Sstevel@tonic-gate * skipping over "." and ".." 2540Sstevel@tonic-gate */ 2550Sstevel@tonic-gate loclen = complexcpy(locname, pname, MAXCOMPLEXLEN); 2560Sstevel@tonic-gate locname[loclen-1] = '/'; 2570Sstevel@tonic-gate rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 2580Sstevel@tonic-gate dp = rst_readdir(dirp); /* "." */ 2590Sstevel@tonic-gate 2600Sstevel@tonic-gate if (dp != NULL && strcmp(dp->d_name, ".") == 0) 2610Sstevel@tonic-gate dp = rst_readdir(dirp); /* ".." */ 2620Sstevel@tonic-gate else 2630Sstevel@tonic-gate (void) fprintf(stderr, 2640Sstevel@tonic-gate gettext("Warning: `.' missing from directory %s\n"), 2650Sstevel@tonic-gate pname); 2660Sstevel@tonic-gate if (dp != NULL && strcmp(dp->d_name, "..") == 0) 2670Sstevel@tonic-gate dp = rst_readdir(dirp); /* first real entry */ 2680Sstevel@tonic-gate else 2690Sstevel@tonic-gate (void) fprintf(stderr, 2700Sstevel@tonic-gate gettext("Warning: `..' missing from directory %s\n"), 2710Sstevel@tonic-gate pname); 2720Sstevel@tonic-gate bpt = rst_telldir(dirp); 2730Sstevel@tonic-gate /* 2740Sstevel@tonic-gate * a zero inode signals end of directory 2750Sstevel@tonic-gate */ 2760Sstevel@tonic-gate while (dp != NULL && dp->d_ino != 0) { 2770Sstevel@tonic-gate locname[loclen] = '\0'; 2780Sstevel@tonic-gate if ((loclen + dp->d_namlen) >= (sizeof (locname) - 2)) { 2790Sstevel@tonic-gate (void) fprintf(stderr, 2800Sstevel@tonic-gate gettext( 2810Sstevel@tonic-gate "%s%s: ignoring name that exceeds %d char\n"), 2820Sstevel@tonic-gate locname, dp->d_name, MAXCOMPLEXLEN); 2830Sstevel@tonic-gate } else { 2840Sstevel@tonic-gate /* Always fits by if() condition */ 2850Sstevel@tonic-gate (void) strcpy(locname + loclen, dp->d_name); 2860Sstevel@tonic-gate /* put a double null on string for lookupname() */ 2870Sstevel@tonic-gate locname[loclen+dp->d_namlen+1] = '\0'; 2880Sstevel@tonic-gate treescan(locname, dp->d_ino, todo); 2890Sstevel@tonic-gate rst_seekdir(dirp, bpt, itp->t_seekpt); 2900Sstevel@tonic-gate } 2910Sstevel@tonic-gate dp = rst_readdir(dirp); 2920Sstevel@tonic-gate bpt = rst_telldir(dirp); 2930Sstevel@tonic-gate } 2940Sstevel@tonic-gate if (dp == NULL) 2950Sstevel@tonic-gate (void) fprintf(stderr, 2960Sstevel@tonic-gate gettext("corrupted directory: %s.\n"), locname); 2970Sstevel@tonic-gate } 2980Sstevel@tonic-gate 2990Sstevel@tonic-gate /* 3000Sstevel@tonic-gate * Scan the directory table looking for extended attribute trees. 3010Sstevel@tonic-gate * Recursively find names and inumbers in each tree and pass them 3020Sstevel@tonic-gate * off to be processed. If the always parameter is not set, only 3030Sstevel@tonic-gate * process the attribute tree if the attribute tree parent is to 3040Sstevel@tonic-gate * be extracted. 3050Sstevel@tonic-gate */ 3060Sstevel@tonic-gate void 3070Sstevel@tonic-gate attrscan(always, todo) 3080Sstevel@tonic-gate int always; 3090Sstevel@tonic-gate long (*todo)(); 3100Sstevel@tonic-gate { 3110Sstevel@tonic-gate struct inotab *itp; 3120Sstevel@tonic-gate struct entry *ep, *parent; 3130Sstevel@tonic-gate struct direct *dp; 3140Sstevel@tonic-gate char name[MAXCOMPLEXLEN]; 3150Sstevel@tonic-gate int len; 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate for (itp = xattrlist; itp != NULL; itp = itp->t_xattr) { 3180Sstevel@tonic-gate rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 3190Sstevel@tonic-gate if ((dp = rst_readdir(dirp)) != NULL && /* "." */ 3200Sstevel@tonic-gate (dp = rst_readdir(dirp)) != NULL && /* ".." */ 3210Sstevel@tonic-gate strcmp(dp->d_name, "..") == 0) { 3220Sstevel@tonic-gate if ((parent = lookupino(dp->d_ino)) != NULL) { 3230Sstevel@tonic-gate if (!always && 3240Sstevel@tonic-gate (parent->e_flags & (NEW|EXTRACT)) == 0) 3250Sstevel@tonic-gate continue; 3260Sstevel@tonic-gate len = complexcpy(name, myname(parent), 3270Sstevel@tonic-gate MAXCOMPLEXLEN - 3); 3280Sstevel@tonic-gate name[len] = '.'; 3290Sstevel@tonic-gate name[len+1] = '\0'; 3300Sstevel@tonic-gate name[len+2] = '\0'; 3310Sstevel@tonic-gate inattrspace = 1; 3320Sstevel@tonic-gate if ((ep = lookupino(itp->t_ino)) == NULL) { 3330Sstevel@tonic-gate ep = addentry(name, itp->t_ino, 3340Sstevel@tonic-gate NODE|ROOT); 3350Sstevel@tonic-gate } 3360Sstevel@tonic-gate ep->e_flags |= XATTRROOT; 3370Sstevel@tonic-gate treescan(name, itp->t_ino, todo); 3380Sstevel@tonic-gate inattrspace = 0; 3390Sstevel@tonic-gate } else { 3400Sstevel@tonic-gate (void) fprintf(stderr, 3410Sstevel@tonic-gate gettext("Warning: orphaned attribute directory\n")); 3420Sstevel@tonic-gate } 3430Sstevel@tonic-gate } else { 3440Sstevel@tonic-gate (void) fprintf(stderr, 3450Sstevel@tonic-gate gettext("Warning: `..' missing from attribute directory\n")); 3460Sstevel@tonic-gate } 3470Sstevel@tonic-gate } 3480Sstevel@tonic-gate } 3490Sstevel@tonic-gate 3500Sstevel@tonic-gate /* 3510Sstevel@tonic-gate * Search the directory tree rooted at inode ROOTINO 3520Sstevel@tonic-gate * for the path pointed at by n. Note that n must be 3530Sstevel@tonic-gate * modifiable, although it is returned in the same 3540Sstevel@tonic-gate * condition it was given to us in. 3550Sstevel@tonic-gate */ 3560Sstevel@tonic-gate ino_t 3570Sstevel@tonic-gate psearch(n) 3580Sstevel@tonic-gate char *n; 3590Sstevel@tonic-gate { 3600Sstevel@tonic-gate char *cp, *cp1; 3610Sstevel@tonic-gate ino_t ino; 3620Sstevel@tonic-gate char c; 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate ino = ROOTINO; 3650Sstevel@tonic-gate if (*(cp = n) == '/') 3660Sstevel@tonic-gate cp++; 3670Sstevel@tonic-gate next: 3680Sstevel@tonic-gate cp1 = cp + 1; 3690Sstevel@tonic-gate while (*cp1 != '/' && *cp1) 3700Sstevel@tonic-gate cp1++; 3710Sstevel@tonic-gate c = *cp1; 3720Sstevel@tonic-gate *cp1 = 0; 3730Sstevel@tonic-gate ino = search(ino, cp); 3740Sstevel@tonic-gate if (ino == 0) { 3750Sstevel@tonic-gate *cp1 = c; 3760Sstevel@tonic-gate return (0); 3770Sstevel@tonic-gate } 3780Sstevel@tonic-gate *cp1 = c; 3790Sstevel@tonic-gate if (c == '/') { 3800Sstevel@tonic-gate cp = cp1+1; 3810Sstevel@tonic-gate goto next; 3820Sstevel@tonic-gate } 3830Sstevel@tonic-gate return (ino); 3840Sstevel@tonic-gate } 3850Sstevel@tonic-gate 3860Sstevel@tonic-gate /* 3870Sstevel@tonic-gate * search the directory inode ino 3880Sstevel@tonic-gate * looking for entry cp 3890Sstevel@tonic-gate */ 3900Sstevel@tonic-gate static ino_t 3910Sstevel@tonic-gate search(inum, cp) 3920Sstevel@tonic-gate ino_t inum; 3930Sstevel@tonic-gate char *cp; 3940Sstevel@tonic-gate { 3950Sstevel@tonic-gate struct direct *dp; 3960Sstevel@tonic-gate struct inotab *itp; 3970Sstevel@tonic-gate uint_t len; 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate itp = inotablookup(inum); 4000Sstevel@tonic-gate if (itp == NULL) 4010Sstevel@tonic-gate return (0); 4020Sstevel@tonic-gate rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 4030Sstevel@tonic-gate len = strlen(cp); 4040Sstevel@tonic-gate do { 4050Sstevel@tonic-gate dp = rst_readdir(dirp); 4060Sstevel@tonic-gate if (dp == NULL || dp->d_ino == 0) 4070Sstevel@tonic-gate return (0); 4080Sstevel@tonic-gate } while (dp->d_namlen != len || strncmp(dp->d_name, cp, len) != 0); 4090Sstevel@tonic-gate return (dp->d_ino); 4100Sstevel@tonic-gate } 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate /* 4130Sstevel@tonic-gate * Put the directory entries in the directory file 4140Sstevel@tonic-gate */ 4150Sstevel@tonic-gate static void 4160Sstevel@tonic-gate putdir(buf, size) 4170Sstevel@tonic-gate char *buf; 4180Sstevel@tonic-gate size_t size; 4190Sstevel@tonic-gate { 4200Sstevel@tonic-gate struct direct cvtbuf; 4210Sstevel@tonic-gate struct odirect *odp; 4220Sstevel@tonic-gate struct odirect *eodp; 4230Sstevel@tonic-gate struct direct *dp; 4240Sstevel@tonic-gate size_t loc, i; 4250Sstevel@tonic-gate 4260Sstevel@tonic-gate if (cvtflag) { 4270Sstevel@tonic-gate /*LINTED [buf is char[] in getfile, size % fs_fsize == 0]*/ 4280Sstevel@tonic-gate eodp = (struct odirect *)&buf[size]; 4290Sstevel@tonic-gate /*LINTED [buf is char[] in getfile]*/ 4300Sstevel@tonic-gate for (odp = (struct odirect *)buf; odp < eodp; odp++) 4310Sstevel@tonic-gate if (odp->d_ino != 0) { 4320Sstevel@tonic-gate dcvt(odp, &cvtbuf); 4330Sstevel@tonic-gate putent(&cvtbuf); 4340Sstevel@tonic-gate } 4350Sstevel@tonic-gate } else { 4360Sstevel@tonic-gate loc = 0; 4370Sstevel@tonic-gate while (loc < size) { 4380Sstevel@tonic-gate /*LINTED [buf is char[] in getfile, loc % 4 == 0]*/ 4390Sstevel@tonic-gate dp = (struct direct *)(buf + loc); 4400Sstevel@tonic-gate normdirect(byteorder, dp); 4410Sstevel@tonic-gate i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1)); 4420Sstevel@tonic-gate if (dp->d_reclen == 0 || (long)dp->d_reclen > i) { 4430Sstevel@tonic-gate loc += i; 4440Sstevel@tonic-gate continue; 4450Sstevel@tonic-gate } 4460Sstevel@tonic-gate loc += dp->d_reclen; 4470Sstevel@tonic-gate if (dp->d_ino != 0) { 4480Sstevel@tonic-gate putent(dp); 4490Sstevel@tonic-gate } 4500Sstevel@tonic-gate } 4510Sstevel@tonic-gate } 4520Sstevel@tonic-gate } 4530Sstevel@tonic-gate 4540Sstevel@tonic-gate /* 4550Sstevel@tonic-gate * These variables are "local" to the following two functions. 4560Sstevel@tonic-gate */ 4570Sstevel@tonic-gate static char dirbuf[DIRBLKSIZ]; 4580Sstevel@tonic-gate static int32_t dirloc = 0; 4590Sstevel@tonic-gate static int32_t prev = 0; 4600Sstevel@tonic-gate 4610Sstevel@tonic-gate /* 4620Sstevel@tonic-gate * add a new directory entry to a file. 4630Sstevel@tonic-gate */ 4640Sstevel@tonic-gate static void 4650Sstevel@tonic-gate putent(dp) 4660Sstevel@tonic-gate struct direct *dp; 4670Sstevel@tonic-gate { 4680Sstevel@tonic-gate /* LINTED DIRSIZ will always fit in a ushort_t */ 4690Sstevel@tonic-gate dp->d_reclen = (ushort_t)DIRSIZ(dp); 4700Sstevel@tonic-gate /* LINTED sign extension ok in assert */ 4710Sstevel@tonic-gate assert(DIRSIZ(dp) == (ulong_t)dp->d_reclen); 4720Sstevel@tonic-gate if (dirloc + (long)dp->d_reclen > DIRBLKSIZ) { 4730Sstevel@tonic-gate /*LINTED [prev += dp->d_reclen, prev % 4 == 0]*/ 4740Sstevel@tonic-gate ((struct direct *)(dirbuf + prev))->d_reclen = 4750Sstevel@tonic-gate DIRBLKSIZ - prev; 4760Sstevel@tonic-gate (void) fwrite(dirbuf, 1, DIRBLKSIZ, df); 4770Sstevel@tonic-gate if (ferror(df)) 4780Sstevel@tonic-gate panic("%s: %s\n", dirfile, strerror(errno)); 4790Sstevel@tonic-gate dirloc = 0; 4800Sstevel@tonic-gate } 4810Sstevel@tonic-gate bcopy((char *)dp, dirbuf + dirloc, (size_t)dp->d_reclen); 4820Sstevel@tonic-gate prev = dirloc; 4830Sstevel@tonic-gate dirloc += dp->d_reclen; 4840Sstevel@tonic-gate } 4850Sstevel@tonic-gate 4860Sstevel@tonic-gate /* 4870Sstevel@tonic-gate * flush out a directory that is finished. 4880Sstevel@tonic-gate */ 4890Sstevel@tonic-gate static void 4900Sstevel@tonic-gate #ifdef __STDC__ 4910Sstevel@tonic-gate flushent(void) 4920Sstevel@tonic-gate #else 4930Sstevel@tonic-gate flushent() 4940Sstevel@tonic-gate #endif 4950Sstevel@tonic-gate { 4960Sstevel@tonic-gate 4970Sstevel@tonic-gate /* LINTED prev += dp->d_reclen, prev % 4 == 0 */ 4980Sstevel@tonic-gate ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev; 4990Sstevel@tonic-gate (void) fwrite(dirbuf, (size_t)dirloc, 1, df); 5000Sstevel@tonic-gate if (ferror(df)) 5010Sstevel@tonic-gate panic("%s: %s\n", dirfile, strerror(errno)); 5020Sstevel@tonic-gate g_seekpt = ftello64(df); 5030Sstevel@tonic-gate dirloc = 0; 5040Sstevel@tonic-gate } 5050Sstevel@tonic-gate 5060Sstevel@tonic-gate static void 5070Sstevel@tonic-gate dcvt(odp, ndp) 5080Sstevel@tonic-gate struct odirect *odp; 5090Sstevel@tonic-gate struct direct *ndp; 5100Sstevel@tonic-gate { 5110Sstevel@tonic-gate 5120Sstevel@tonic-gate (void) bzero((char *)ndp, sizeof (*ndp)); 5130Sstevel@tonic-gate ndp->d_ino = odp->d_ino; 5140Sstevel@tonic-gate /* Note that odp->d_name may not be null-terminated */ 5150Sstevel@tonic-gate /* LINTED assertion always true */ 5160Sstevel@tonic-gate assert(sizeof (ndp->d_name) > sizeof (odp->d_name)); 5170Sstevel@tonic-gate (void) strncpy(ndp->d_name, odp->d_name, sizeof (odp->d_name)); 5180Sstevel@tonic-gate ndp->d_name[sizeof (odp->d_name)] = '\0'; 5190Sstevel@tonic-gate /* LINTED: strlen will fit into d_namlen */ 5200Sstevel@tonic-gate ndp->d_namlen = strlen(ndp->d_name); 5210Sstevel@tonic-gate 5220Sstevel@tonic-gate /* LINTED sign extension ok in assert */ 5230Sstevel@tonic-gate assert(DIRSIZ(ndp) == (ulong_t)ndp->d_reclen); 5240Sstevel@tonic-gate /* LINTED DIRSIZ always fits in ushort_t */ 5250Sstevel@tonic-gate ndp->d_reclen = (ushort_t)DIRSIZ(ndp); 5260Sstevel@tonic-gate } 5270Sstevel@tonic-gate 5280Sstevel@tonic-gate /* 5290Sstevel@tonic-gate * Initialize the directory file 5300Sstevel@tonic-gate */ 5310Sstevel@tonic-gate static RST_DIR * 5320Sstevel@tonic-gate rst_initdirfile(name) 5330Sstevel@tonic-gate char *name; 5340Sstevel@tonic-gate { 5350Sstevel@tonic-gate RST_DIR *dp; 5360Sstevel@tonic-gate int fd; 5370Sstevel@tonic-gate 5380Sstevel@tonic-gate if ((fd = open(name, O_RDONLY | O_LARGEFILE)) == -1) 5390Sstevel@tonic-gate return ((RST_DIR *)0); 5400Sstevel@tonic-gate if ((dp = (RST_DIR *)malloc(sizeof (*dp))) == NULL) { 5410Sstevel@tonic-gate (void) close(fd); 5420Sstevel@tonic-gate return ((RST_DIR *)0); 5430Sstevel@tonic-gate } 5440Sstevel@tonic-gate dp->dd_fd = fd; 5450Sstevel@tonic-gate dp->dd_loc = 0; 5460Sstevel@tonic-gate dp->dd_refcnt = 1; 5470Sstevel@tonic-gate return (dp); 5480Sstevel@tonic-gate } 5490Sstevel@tonic-gate 5500Sstevel@tonic-gate /* 5510Sstevel@tonic-gate * Simulate the opening of a directory 5520Sstevel@tonic-gate */ 5530Sstevel@tonic-gate RST_DIR * 5540Sstevel@tonic-gate rst_opendir(name) 5550Sstevel@tonic-gate char *name; 5560Sstevel@tonic-gate { 5570Sstevel@tonic-gate struct inotab *itp; 5580Sstevel@tonic-gate ino_t ino; 5590Sstevel@tonic-gate 5600Sstevel@tonic-gate if ((ino = dirlookup(name)) > 0 && 5610Sstevel@tonic-gate (itp = inotablookup(ino)) != NULL) { 5620Sstevel@tonic-gate rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 5630Sstevel@tonic-gate dirp->dd_refcnt++; 5640Sstevel@tonic-gate return (dirp); 5650Sstevel@tonic-gate } 5660Sstevel@tonic-gate return ((RST_DIR *)0); 5670Sstevel@tonic-gate } 5680Sstevel@tonic-gate 5690Sstevel@tonic-gate /* 5700Sstevel@tonic-gate * Releases the hidden state created by rst_opendir(). 5710Sstevel@tonic-gate * Specifically, the dirp it provided to the caller is malloc'd. 5720Sstevel@tonic-gate */ 5730Sstevel@tonic-gate void 5740Sstevel@tonic-gate rst_closedir(cdirp) 5750Sstevel@tonic-gate RST_DIR *cdirp; 5760Sstevel@tonic-gate { 5770Sstevel@tonic-gate if ((cdirp != NULL) && (--(cdirp->dd_refcnt) < 1)) 5780Sstevel@tonic-gate free(cdirp); 5790Sstevel@tonic-gate } 5800Sstevel@tonic-gate 5810Sstevel@tonic-gate /* 5820Sstevel@tonic-gate * return a pointer into a directory 5830Sstevel@tonic-gate */ 5840Sstevel@tonic-gate static offset_t 5850Sstevel@tonic-gate rst_telldir(tdirp) 5860Sstevel@tonic-gate RST_DIR *tdirp; 5870Sstevel@tonic-gate { 5880Sstevel@tonic-gate offset_t pos = llseek(tdirp->dd_fd, (offset_t)0, SEEK_CUR); 5890Sstevel@tonic-gate 5900Sstevel@tonic-gate if (pos == (offset_t)-1) { 5910Sstevel@tonic-gate perror("Could not determine position in directory file"); 5920Sstevel@tonic-gate done(1); 5930Sstevel@tonic-gate } 5940Sstevel@tonic-gate 5950Sstevel@tonic-gate return ((pos - tdirp->dd_size) + tdirp->dd_loc); 5960Sstevel@tonic-gate } 5970Sstevel@tonic-gate 5980Sstevel@tonic-gate /* 5990Sstevel@tonic-gate * Seek to an entry in a directory. 6000Sstevel@tonic-gate * Only values returned by ``rst_telldir'' should be passed to rst_seekdir. 6010Sstevel@tonic-gate * This routine handles many directories in a single file. 6020Sstevel@tonic-gate * It takes the base of the directory in the file, plus 6030Sstevel@tonic-gate * the desired seek offset into it. 6040Sstevel@tonic-gate */ 6050Sstevel@tonic-gate static void 6060Sstevel@tonic-gate rst_seekdir(sdirp, loc, base) 6070Sstevel@tonic-gate RST_DIR *sdirp; 6080Sstevel@tonic-gate offset_t loc, base; 6090Sstevel@tonic-gate { 6100Sstevel@tonic-gate 6110Sstevel@tonic-gate if (loc == rst_telldir(sdirp)) 6120Sstevel@tonic-gate return; 6130Sstevel@tonic-gate loc -= base; 6140Sstevel@tonic-gate if (loc < 0) 6150Sstevel@tonic-gate (void) fprintf(stderr, 6160Sstevel@tonic-gate gettext("bad seek pointer to rst_seekdir %d\n"), loc); 6170Sstevel@tonic-gate (void) llseek(sdirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), 0); 6180Sstevel@tonic-gate sdirp->dd_loc = loc & (DIRBLKSIZ - 1); 6190Sstevel@tonic-gate if (sdirp->dd_loc != 0) 6200Sstevel@tonic-gate sdirp->dd_size = read(sdirp->dd_fd, sdirp->dd_buf, DIRBLKSIZ); 6210Sstevel@tonic-gate } 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate /* 6240Sstevel@tonic-gate * get next entry in a directory. 6250Sstevel@tonic-gate */ 6260Sstevel@tonic-gate struct direct * 6270Sstevel@tonic-gate rst_readdir(rdirp) 6280Sstevel@tonic-gate RST_DIR *rdirp; 6290Sstevel@tonic-gate { 6300Sstevel@tonic-gate struct direct *dp; 6310Sstevel@tonic-gate 6320Sstevel@tonic-gate for (;;) { 6330Sstevel@tonic-gate if (rdirp->dd_loc == 0) { 6340Sstevel@tonic-gate rdirp->dd_size = read(rdirp->dd_fd, rdirp->dd_buf, 6350Sstevel@tonic-gate DIRBLKSIZ); 6360Sstevel@tonic-gate if (rdirp->dd_size <= 0) { 6370Sstevel@tonic-gate dprintf(stderr, 6380Sstevel@tonic-gate gettext("error reading directory\n")); 6390Sstevel@tonic-gate return ((struct direct *)0); 6400Sstevel@tonic-gate } 6410Sstevel@tonic-gate } 6420Sstevel@tonic-gate if (rdirp->dd_loc >= rdirp->dd_size) { 6430Sstevel@tonic-gate rdirp->dd_loc = 0; 6440Sstevel@tonic-gate continue; 6450Sstevel@tonic-gate } 6460Sstevel@tonic-gate /*LINTED [rvalue will be aligned on int boundary]*/ 6470Sstevel@tonic-gate dp = (struct direct *)(rdirp->dd_buf + rdirp->dd_loc); 6480Sstevel@tonic-gate if (dp->d_reclen == 0 || 6490Sstevel@tonic-gate (long)dp->d_reclen > (DIRBLKSIZ + 1 - rdirp->dd_loc)) { 6500Sstevel@tonic-gate dprintf(stderr, 6510Sstevel@tonic-gate gettext("corrupted directory: bad reclen %d\n"), 6520Sstevel@tonic-gate dp->d_reclen); 6530Sstevel@tonic-gate return ((struct direct *)0); 6540Sstevel@tonic-gate } 6550Sstevel@tonic-gate rdirp->dd_loc += dp->d_reclen; 6560Sstevel@tonic-gate if (dp->d_ino == 0 && strcmp(dp->d_name, "/") != 0) 6570Sstevel@tonic-gate continue; 6580Sstevel@tonic-gate if ((ino_t)(dp->d_ino) >= maxino) { 6590Sstevel@tonic-gate dprintf(stderr, 6600Sstevel@tonic-gate gettext("corrupted directory: bad inum %lu\n"), 6610Sstevel@tonic-gate dp->d_ino); 6620Sstevel@tonic-gate continue; 6630Sstevel@tonic-gate } 6640Sstevel@tonic-gate return (dp); 6650Sstevel@tonic-gate } 6660Sstevel@tonic-gate } 6670Sstevel@tonic-gate 6680Sstevel@tonic-gate /* 6690Sstevel@tonic-gate * Set the mode, owner, and times for all new or changed directories 6700Sstevel@tonic-gate */ 6710Sstevel@tonic-gate void 6720Sstevel@tonic-gate #ifdef __STDC__ 6730Sstevel@tonic-gate setdirmodes(void) 6740Sstevel@tonic-gate #else 6750Sstevel@tonic-gate setdirmodes() 6760Sstevel@tonic-gate #endif 6770Sstevel@tonic-gate { 6780Sstevel@tonic-gate FILE *smf; 6790Sstevel@tonic-gate struct entry *ep; 6800Sstevel@tonic-gate char *cp, *metadata = NULL; 6810Sstevel@tonic-gate size_t metasize = 0; 6820Sstevel@tonic-gate int override = -1; 6830Sstevel@tonic-gate int saverr; 6840Sstevel@tonic-gate static int complained_chown = 0; 6850Sstevel@tonic-gate static int complained_chmod = 0; 6860Sstevel@tonic-gate int dfd; 6870Sstevel@tonic-gate 6880Sstevel@tonic-gate vprintf(stdout, gettext("Set directory mode, owner, and times.\n")); 6890Sstevel@tonic-gate /* XXX if modefile[0] == '#', shouldn't we just bail here? */ 6900Sstevel@tonic-gate /* XXX why isn't it set already? */ 6910Sstevel@tonic-gate INIT_MODEFILE(); 6920Sstevel@tonic-gate smf = fopen64(modefile, "r"); 6930Sstevel@tonic-gate if (smf == NULL) { 6940Sstevel@tonic-gate perror("fopen"); 6950Sstevel@tonic-gate (void) fprintf(stderr, 6960Sstevel@tonic-gate gettext("cannot open mode file %s\n"), modefile); 6970Sstevel@tonic-gate (void) fprintf(stderr, 6980Sstevel@tonic-gate gettext("directory mode, owner, and times not set\n")); 6990Sstevel@tonic-gate return; 7000Sstevel@tonic-gate } 7010Sstevel@tonic-gate clearerr(smf); 7020Sstevel@tonic-gate for (;;) { 7030Sstevel@tonic-gate (void) fread((char *)&node, 1, sizeof (node), smf); 7040Sstevel@tonic-gate if (feof(smf)) 7050Sstevel@tonic-gate break; 7060Sstevel@tonic-gate ep = lookupino(node.ino); 7070Sstevel@tonic-gate if (command == 'i' || command == 'x') { 7080Sstevel@tonic-gate if (ep == NIL) { 7090Sstevel@tonic-gate skipmetadata(smf, node.metasize); 7100Sstevel@tonic-gate continue; 7110Sstevel@tonic-gate } 7120Sstevel@tonic-gate if (ep->e_flags & EXISTED) { 7130Sstevel@tonic-gate if (override < 0) { 7140Sstevel@tonic-gate if (reply(gettext( 7150Sstevel@tonic-gate "Directories already exist, set modes anyway")) 7160Sstevel@tonic-gate == FAIL) 7170Sstevel@tonic-gate override = 0; 7180Sstevel@tonic-gate else 7190Sstevel@tonic-gate override = 1; 7200Sstevel@tonic-gate } 7210Sstevel@tonic-gate if (override == 0) { 7220Sstevel@tonic-gate /* LINTED: result fits into short */ 7230Sstevel@tonic-gate ep->e_flags &= ~NEW; 7240Sstevel@tonic-gate skipmetadata(smf, node.metasize); 7250Sstevel@tonic-gate continue; 7260Sstevel@tonic-gate } 7270Sstevel@tonic-gate } 7280Sstevel@tonic-gate if (node.ino == ROOTINO && 7290Sstevel@tonic-gate reply(gettext("set owner/mode for '.'")) == FAIL) { 7300Sstevel@tonic-gate skipmetadata(smf, node.metasize); 7310Sstevel@tonic-gate continue; 7320Sstevel@tonic-gate } 7330Sstevel@tonic-gate } 7340Sstevel@tonic-gate if (ep == NIL) { 7350Sstevel@tonic-gate panic(gettext("cannot find directory inode %d\n"), 7360Sstevel@tonic-gate node.ino); 7370Sstevel@tonic-gate skipmetadata(smf, node.metasize); 7380Sstevel@tonic-gate continue; 7390Sstevel@tonic-gate } 7400Sstevel@tonic-gate cp = myname(ep); 7410Sstevel@tonic-gate resolve(myname(ep), &dfd, &cp); 7420Sstevel@tonic-gate if (dfd != AT_FDCWD) { 7430Sstevel@tonic-gate if (fchdir(dfd) < 0) { 7440Sstevel@tonic-gate saverr = errno; 7450Sstevel@tonic-gate (void) fprintf(stderr, 7460Sstevel@tonic-gate gettext("Can not set attribute context: %s\n"), 7470Sstevel@tonic-gate strerror(saverr)); 7480Sstevel@tonic-gate (void) close(dfd); 7490Sstevel@tonic-gate continue; 7500Sstevel@tonic-gate } 7510Sstevel@tonic-gate } 7520Sstevel@tonic-gate if (chmod(cp, node.mode) < 0 && !complained_chmod) { 7530Sstevel@tonic-gate saverr = errno; 7540Sstevel@tonic-gate (void) fprintf(stderr, 7550Sstevel@tonic-gate gettext("Can not set directory permissions: %s\n"), 7560Sstevel@tonic-gate strerror(saverr)); 7570Sstevel@tonic-gate complained_chmod = 1; 7580Sstevel@tonic-gate } 7590Sstevel@tonic-gate if (node.metasize != 0) { 7600Sstevel@tonic-gate if (node.metasize > metasize) 7610Sstevel@tonic-gate metadata = realloc(metadata, 7620Sstevel@tonic-gate metasize = node.metasize); 7630Sstevel@tonic-gate if (metadata == NULL) { 7640Sstevel@tonic-gate (void) fprintf(stderr, 7650Sstevel@tonic-gate gettext("Cannot malloc metadata\n")); 7660Sstevel@tonic-gate done(1); 7670Sstevel@tonic-gate } 7680Sstevel@tonic-gate (void) fread(metadata, 1, node.metasize, smf); 7690Sstevel@tonic-gate metaproc(cp, metadata, node.metasize); 7700Sstevel@tonic-gate } 7710Sstevel@tonic-gate 7720Sstevel@tonic-gate /* 7730Sstevel@tonic-gate * BUG 4302943 7740Sstevel@tonic-gate * Since the ACLs must be set before fixing the ownership, 7750Sstevel@tonic-gate * chown should be called only after metaproc 7760Sstevel@tonic-gate */ 7770Sstevel@tonic-gate if (chown(cp, node.uid, node.gid) < 0 && !complained_chown) { 7780Sstevel@tonic-gate saverr = errno; 7790Sstevel@tonic-gate (void) fprintf(stderr, 7800Sstevel@tonic-gate gettext("Can not set directory ownership: %s\n"), 7810Sstevel@tonic-gate strerror(saverr)); 7820Sstevel@tonic-gate complained_chown = 1; 7830Sstevel@tonic-gate } 7840Sstevel@tonic-gate utime(cp, (struct utimbuf *)node.timep); 7850Sstevel@tonic-gate /* LINTED: result fits into short */ 7860Sstevel@tonic-gate ep->e_flags &= ~NEW; 7870Sstevel@tonic-gate if (dfd != AT_FDCWD) { 7880Sstevel@tonic-gate fchdir(savepwd); 7890Sstevel@tonic-gate (void) close(dfd); 7900Sstevel@tonic-gate } 7910Sstevel@tonic-gate } 7920Sstevel@tonic-gate if (ferror(smf)) 7930Sstevel@tonic-gate panic(gettext("error setting directory modes\n")); 7940Sstevel@tonic-gate if (metadata != NULL) 7950Sstevel@tonic-gate (void) free(metadata); 7960Sstevel@tonic-gate (void) fclose(smf); 7970Sstevel@tonic-gate } 7980Sstevel@tonic-gate 7990Sstevel@tonic-gate void 8000Sstevel@tonic-gate skipmetadata(f, size) 8010Sstevel@tonic-gate FILE *f; 8020Sstevel@tonic-gate size_t size; 8030Sstevel@tonic-gate { 8040Sstevel@tonic-gate /* XXX should we bail if this doesn't work? */ 8050Sstevel@tonic-gate /* LINTED unsigned -> signed conversion ok here */ 8060Sstevel@tonic-gate (void) fseeko(f, (off_t)size, SEEK_CUR); 8070Sstevel@tonic-gate } 8080Sstevel@tonic-gate 8090Sstevel@tonic-gate /* 8100Sstevel@tonic-gate * Generate a literal copy of a directory. 8110Sstevel@tonic-gate */ 8120Sstevel@tonic-gate genliteraldir(name, ino) 8130Sstevel@tonic-gate char *name; 8140Sstevel@tonic-gate ino_t ino; 8150Sstevel@tonic-gate { 8160Sstevel@tonic-gate struct inotab *itp; 8170Sstevel@tonic-gate int ofile, dp; 8180Sstevel@tonic-gate off64_t i; 8190Sstevel@tonic-gate size_t size; 8200Sstevel@tonic-gate char buf[BUFSIZ]; 8210Sstevel@tonic-gate 8220Sstevel@tonic-gate itp = inotablookup(ino); 8230Sstevel@tonic-gate if (itp == NULL) { 8240Sstevel@tonic-gate (void) fprintf(stderr, 8250Sstevel@tonic-gate gettext("Cannot find directory inode %d named %s\n"), 8260Sstevel@tonic-gate ino, name); 8270Sstevel@tonic-gate return (FAIL); 8280Sstevel@tonic-gate } 8290Sstevel@tonic-gate if ((ofile = creat(name, 0666)) < 0) { 8300Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", name); 8310Sstevel@tonic-gate (void) fflush(stderr); 8320Sstevel@tonic-gate perror(gettext("cannot create file")); 8330Sstevel@tonic-gate return (FAIL); 8340Sstevel@tonic-gate } 8350Sstevel@tonic-gate rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 8360Sstevel@tonic-gate dp = dup(dirp->dd_fd); 8370Sstevel@tonic-gate if (dp < 0) { 8380Sstevel@tonic-gate perror(gettext("dup(2) failed")); 8390Sstevel@tonic-gate (void) close(ofile); 8400Sstevel@tonic-gate (void) unlink(name); 8410Sstevel@tonic-gate return (FAIL); 8420Sstevel@tonic-gate } 8430Sstevel@tonic-gate for (i = itp->t_size; i != 0; i -= size) { 8440Sstevel@tonic-gate /* LINTED cast is safe due to comparison */ 8450Sstevel@tonic-gate size = i < BUFSIZ ? (size_t)i : BUFSIZ; 8460Sstevel@tonic-gate /* XXX instead of done(), clean up and return FAIL? */ 8470Sstevel@tonic-gate if (read(dp, buf, size) == -1) { 8480Sstevel@tonic-gate (void) fprintf(stderr, gettext( 8490Sstevel@tonic-gate "read error extracting inode %d, name %s\n"), 8500Sstevel@tonic-gate curfile.ino, curfile.name); 8510Sstevel@tonic-gate perror("read"); 8520Sstevel@tonic-gate done(1); 8530Sstevel@tonic-gate } 8540Sstevel@tonic-gate if (write(ofile, buf, size) == -1) { 8550Sstevel@tonic-gate (void) fprintf(stderr, gettext( 8560Sstevel@tonic-gate "write error extracting inode %d, name %s\n"), 8570Sstevel@tonic-gate curfile.ino, curfile.name); 8580Sstevel@tonic-gate perror("write"); 8590Sstevel@tonic-gate done(1); 8600Sstevel@tonic-gate } 8610Sstevel@tonic-gate } 8620Sstevel@tonic-gate (void) close(dp); 8630Sstevel@tonic-gate (void) close(ofile); 8640Sstevel@tonic-gate return (GOOD); 8650Sstevel@tonic-gate } 8660Sstevel@tonic-gate 8670Sstevel@tonic-gate /* 8680Sstevel@tonic-gate * Determine the type of an inode 8690Sstevel@tonic-gate */ 8700Sstevel@tonic-gate inodetype(ino) 8710Sstevel@tonic-gate ino_t ino; 8720Sstevel@tonic-gate { 8730Sstevel@tonic-gate struct inotab *itp; 8740Sstevel@tonic-gate 8750Sstevel@tonic-gate itp = inotablookup(ino); 8760Sstevel@tonic-gate if (itp == NULL) 8770Sstevel@tonic-gate return (LEAF); 8780Sstevel@tonic-gate return (NODE); 8790Sstevel@tonic-gate } 8800Sstevel@tonic-gate 8810Sstevel@tonic-gate /* 8820Sstevel@tonic-gate * Allocate and initialize a directory inode entry. 8830Sstevel@tonic-gate * If requested, save its pertinent mode, owner, and time info. 8840Sstevel@tonic-gate */ 8850Sstevel@tonic-gate static struct inotab * 8860Sstevel@tonic-gate allocinotab(ino, dip, seekpt) 8870Sstevel@tonic-gate ino_t ino; 8880Sstevel@tonic-gate struct dinode *dip; 8890Sstevel@tonic-gate off64_t seekpt; 8900Sstevel@tonic-gate { 8910Sstevel@tonic-gate struct inotab *itp; 8920Sstevel@tonic-gate 8930Sstevel@tonic-gate itp = (struct inotab *)calloc(1, sizeof (*itp)); 8940Sstevel@tonic-gate if (itp == 0) { 8950Sstevel@tonic-gate (void) fprintf(stderr, 8960Sstevel@tonic-gate gettext("no memory for directory table\n")); 8970Sstevel@tonic-gate done(1); 8980Sstevel@tonic-gate } 8990Sstevel@tonic-gate itp->t_next = inotab[INOHASH(ino)]; 9000Sstevel@tonic-gate inotab[INOHASH(ino)] = itp; 9010Sstevel@tonic-gate itp->t_ino = ino; 9020Sstevel@tonic-gate itp->t_seekpt = seekpt; 9030Sstevel@tonic-gate if ((dip->di_mode & IFMT) == IFATTRDIR) { 9040Sstevel@tonic-gate itp->t_xattr = xattrlist; 9050Sstevel@tonic-gate xattrlist = itp; 9060Sstevel@tonic-gate } 9070Sstevel@tonic-gate if (mf == NULL) 9080Sstevel@tonic-gate return (itp); 9090Sstevel@tonic-gate node.ino = ino; 9100Sstevel@tonic-gate node.timep[0] = dip->di_atime; 9110Sstevel@tonic-gate node.timep[1] = dip->di_mtime; 9120Sstevel@tonic-gate node.mode = dip->di_mode; 9130Sstevel@tonic-gate node.uid = 9140Sstevel@tonic-gate dip->di_suid == UID_LONG ? dip->di_uid : (uid_t)dip->di_suid; 9150Sstevel@tonic-gate node.gid = 9160Sstevel@tonic-gate dip->di_sgid == GID_LONG ? dip->di_gid : (gid_t)dip->di_sgid; 9170Sstevel@tonic-gate return (itp); 9180Sstevel@tonic-gate } 9190Sstevel@tonic-gate 9200Sstevel@tonic-gate void 9210Sstevel@tonic-gate nodeflush() 9220Sstevel@tonic-gate { 9230Sstevel@tonic-gate char *metadata; 9240Sstevel@tonic-gate 9250Sstevel@tonic-gate if (mf == NULL) { 9260Sstevel@tonic-gate (void) fprintf(stderr, gettext( 9270Sstevel@tonic-gate "Inconsistency detected: modefile pointer is NULL\n")); 9280Sstevel@tonic-gate done(1); 9290Sstevel@tonic-gate } 9300Sstevel@tonic-gate metaget(&metadata, &(node.metasize)); 9310Sstevel@tonic-gate (void) fwrite((char *)&node, 1, sizeof (node), mf); 9320Sstevel@tonic-gate if (node.metasize != 0) 9330Sstevel@tonic-gate (void) fwrite(metadata, 1, node.metasize, mf); 9340Sstevel@tonic-gate if (ferror(mf)) 9350Sstevel@tonic-gate panic("%s: %s\n", modefile, strerror(errno)); 9360Sstevel@tonic-gate } 9370Sstevel@tonic-gate 9380Sstevel@tonic-gate /* 9390Sstevel@tonic-gate * Look up an inode in the table of directories 9400Sstevel@tonic-gate */ 9410Sstevel@tonic-gate static struct inotab * 9420Sstevel@tonic-gate inotablookup(ino) 9430Sstevel@tonic-gate ino_t ino; 9440Sstevel@tonic-gate { 9450Sstevel@tonic-gate struct inotab *itp; 9460Sstevel@tonic-gate 9470Sstevel@tonic-gate for (itp = inotab[INOHASH(ino)]; itp != NULL; itp = itp->t_next) 9480Sstevel@tonic-gate if (itp->t_ino == ino) 9490Sstevel@tonic-gate return (itp); 9500Sstevel@tonic-gate return ((struct inotab *)0); 9510Sstevel@tonic-gate } 9520Sstevel@tonic-gate 9530Sstevel@tonic-gate /* 9540Sstevel@tonic-gate * Clean up and exit 9550Sstevel@tonic-gate */ 9560Sstevel@tonic-gate void 9570Sstevel@tonic-gate done(exitcode) 9580Sstevel@tonic-gate int exitcode; 9590Sstevel@tonic-gate { 960*426Srm88369 closemt(ALLOW_OFFLINE); /* don't force offline on exit */ 9610Sstevel@tonic-gate if (modefile[0] != '#') 9620Sstevel@tonic-gate (void) unlink(modefile); 9630Sstevel@tonic-gate if (dirfile[0] != '#') 9640Sstevel@tonic-gate (void) unlink(dirfile); 9650Sstevel@tonic-gate exit(exitcode); 9660Sstevel@tonic-gate } 967