dirs.c revision 23685
12311Sjkh/* 22311Sjkh * Copyright (c) 1983, 1993 32311Sjkh * The Regents of the University of California. All rights reserved. 42311Sjkh * (c) UNIX System Laboratories, Inc. 52311Sjkh * All or some portions of this file are derived from material licensed 62311Sjkh * to the University of California by American Telephone and Telegraph 72311Sjkh * Co. or Unix System Laboratories, Inc. and are reproduced herein with 82311Sjkh * the permission of UNIX System Laboratories, Inc. 92311Sjkh * 102311Sjkh * Redistribution and use in source and binary forms, with or without 112311Sjkh * modification, are permitted provided that the following conditions 122311Sjkh * are met: 132311Sjkh * 1. Redistributions of source code must retain the above copyright 142311Sjkh * notice, this list of conditions and the following disclaimer. 152311Sjkh * 2. Redistributions in binary form must reproduce the above copyright 165176Sache * notice, this list of conditions and the following disclaimer in the 172311Sjkh * documentation and/or other materials provided with the distribution. 182311Sjkh * 3. All advertising materials mentioning features or use of this software 192311Sjkh * must display the following acknowledgement: 2029452Scharnier * This product includes software developed by the University of 2150479Speter * California, Berkeley and its contributors. 222311Sjkh * 4. Neither the name of the University nor the names of its contributors 232311Sjkh * may be used to endorse or promote products derived from this software 242311Sjkh * without specific prior written permission. 252311Sjkh * 262311Sjkh * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 272311Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 282311Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 292311Sjkh * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 302311Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 312311Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 322311Sjkh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 332311Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34135242Sdds * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3569793Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 362311Sjkh * SUCH DAMAGE. 372311Sjkh */ 382311Sjkh 392311Sjkh#ifndef lint 402311Sjkhstatic char sccsid[] = "@(#)dirs.c 8.7 (Berkeley) 5/1/95"; 412311Sjkh#endif /* not lint */ 422311Sjkh 432311Sjkh#include <sys/param.h> 442311Sjkh#include <sys/file.h> 452311Sjkh#include <sys/stat.h> 462311Sjkh#include <sys/time.h> 472311Sjkh 48135242Sdds#include <ufs/ufs/dinode.h> 492311Sjkh#include <ufs/ufs/dir.h> 502311Sjkh#include <ufs/ffs/fs.h> 512311Sjkh#include <protocols/dumprestore.h> 522311Sjkh 532311Sjkh#include <errno.h> 542311Sjkh#include <stdio.h> 552311Sjkh#include <stdlib.h> 562311Sjkh#include <string.h> 572311Sjkh#include <unistd.h> 582311Sjkh 592311Sjkh#include <machine/endian.h> 602311Sjkh 612311Sjkh#include "pathnames.h" 622311Sjkh#include "restore.h" 632311Sjkh#include "extern.h" 642311Sjkh 652311Sjkh/* 662311Sjkh * Symbol table of directories read from tape. 672311Sjkh */ 682311Sjkh#define HASHSIZE 1000 692311Sjkh#define INOHASH(val) (val % HASHSIZE) 702311Sjkhstruct inotab { 712311Sjkh struct inotab *t_next; 722311Sjkh ino_t t_ino; 732311Sjkh long t_seekpt; 742311Sjkh long t_size; 752311Sjkh}; 762311Sjkhstatic struct inotab *inotab[HASHSIZE]; 772311Sjkh 782311Sjkh/* 7929452Scharnier * Information retained about directories. 8029452Scharnier */ 8129452Scharnierstruct modeinfo { 8229452Scharnier ino_t ino; 832311Sjkh struct timeval timep[2]; 842311Sjkh mode_t mode; 852311Sjkh uid_t uid; 862311Sjkh gid_t gid; 872311Sjkh int flags; 882311Sjkh}; 892311Sjkh 902311Sjkh/* 912311Sjkh * Definitions for library routines operating on directories. 922311Sjkh */ 932311Sjkh#undef DIRBLKSIZ 942311Sjkh#define DIRBLKSIZ 1024 952311Sjkhstruct rstdirdesc { 962311Sjkh int dd_fd; 972311Sjkh long dd_loc; 982311Sjkh long dd_size; 992311Sjkh char dd_buf[DIRBLKSIZ]; 1002311Sjkh}; 1012311Sjkh 1022311Sjkh/* 1032311Sjkh * Global variables for this file. 1042311Sjkh */ 1052311Sjkhstatic long seekpt; 1062311Sjkhstatic FILE *df, *mf; 1072311Sjkhstatic RST_DIR *dirp; 10829452Scharnierstatic char dirfile[MAXPATHLEN] = "#"; /* No file */ 1092311Sjkhstatic char modefile[MAXPATHLEN] = "#"; /* No file */ 1102311Sjkhstatic char dot[2] = "."; /* So it can be modified */ 1112311Sjkh 1122311Sjkh/* 1132311Sjkh * Format of old style directories. 1142311Sjkh */ 1152311Sjkh#define ODIRSIZ 14 1162311Sjkhstruct odirect { 1172311Sjkh u_short d_ino; 1182311Sjkh char d_name[ODIRSIZ]; 1192311Sjkh}; 1202311Sjkh 1212311Sjkhstatic struct inotab *allocinotab __P((ino_t, struct dinode *, long)); 1222311Sjkhstatic void dcvt __P((struct odirect *, struct direct *)); 12329452Scharnierstatic void flushent __P((void)); 12429452Scharnierstatic struct inotab *inotablookup __P((ino_t)); 1252311Sjkhstatic RST_DIR *opendirfile __P((const char *)); 126104326Sddstatic void putdir __P((char *, long)); 1272311Sjkhstatic void putent __P((struct direct *)); 1282311Sjkhstatic void rst_seekdir __P((RST_DIR *, long, long)); 1292311Sjkhstatic long rst_telldir __P((RST_DIR *)); 1308857Srgrimesstatic struct direct *searchdir __P((ino_t, char *)); 1312311Sjkh 1322311Sjkh/* 1332311Sjkh * Extract directory contents, building up a directory structure 1342311Sjkh * on disk for extraction by name. 1352311Sjkh * If genmode is requested, save mode, owner, and times for all 1362311Sjkh * directories on the tape. 1372311Sjkh */ 13829452Scharniervoid 13929452Scharnierextractdirs(genmode) 14020573Spst int genmode; 14120573Spst{ 1422311Sjkh register int i; 1432311Sjkh register struct dinode *ip; 1442311Sjkh struct inotab *itp; 14524428Simp struct direct nulldir; 1462311Sjkh int fd; 1472311Sjkh 1482311Sjkh vprintf(stdout, "Extract directories from tape\n"); 1492311Sjkh (void) sprintf(dirfile, "%srstdir%d", _PATH_TMP, dumpdate); 1502311Sjkh if (command != 'r' && command != 'R') { 1512311Sjkh (void *) strcat(dirfile, "-XXXXXX"); 1522311Sjkh fd = mkstemp(dirfile); 15329452Scharnier } else 1542311Sjkh fd = open(dirfile, O_RDWR|O_CREAT|O_EXCL, 0666); 15529452Scharnier if (fd == -1 || (df = fdopen(fd, "w")) == NULL) { 15620573Spst if (fd != -1) 15720573Spst close(fd); 1582311Sjkh fprintf(stderr, 1592311Sjkh "restore: %s - cannot create directory temporary\n", 1602311Sjkh dirfile); 1612311Sjkh fprintf(stderr, "fopen: %s\n", strerror(errno)); 1622311Sjkh done(1); 1632311Sjkh } 1642311Sjkh if (genmode != 0) { 1652311Sjkh (void) sprintf(modefile, "%srstmode%d", _PATH_TMP, dumpdate); 1662311Sjkh if (command != 'r' && command != 'R') { 1672311Sjkh (void *) strcat(modefile, "-XXXXXX"); 1682311Sjkh fd = mkstemp(modefile); 1692311Sjkh } else 1702311Sjkh fd = open(modefile, O_RDWR|O_CREAT|O_EXCL, 0666); 1712311Sjkh if (fd == -1 || (mf = fdopen(fd, "w")) == NULL) { 1722311Sjkh if (fd != -1) 1732311Sjkh close(fd); 1742311Sjkh fprintf(stderr, 1752311Sjkh "restore: %s - cannot create modefile \n", 1762311Sjkh modefile); 1772311Sjkh fprintf(stderr, "fopen: %s\n", strerror(errno)); 1782311Sjkh done(1); 1792311Sjkh } 1802311Sjkh } 1812311Sjkh nulldir.d_ino = 0; 1822311Sjkh nulldir.d_type = DT_DIR; 1832311Sjkh nulldir.d_namlen = 1; 1842311Sjkh (void) strcpy(nulldir.d_name, "/"); 1852311Sjkh nulldir.d_reclen = DIRSIZ(0, &nulldir); 1862311Sjkh for (;;) { 1872311Sjkh curfile.name = "<directory file - name unknown>"; 18820573Spst curfile.action = USING; 18920573Spst ip = curfile.dip; 19020573Spst if (ip == NULL || (ip->di_mode & IFMT) != IFDIR) { 1912311Sjkh (void) fclose(df); 1922311Sjkh dirp = opendirfile(dirfile); 1932311Sjkh if (dirp == NULL) 1942311Sjkh fprintf(stderr, "opendirfile: %s\n", 1952311Sjkh strerror(errno)); 1962311Sjkh if (mf != NULL) 1972311Sjkh (void) fclose(mf); 1982311Sjkh i = dirlookup(dot); 1992311Sjkh if (i == 0) 2002311Sjkh panic("Root directory is not on tape\n"); 2012311Sjkh return; 2022311Sjkh } 2032311Sjkh itp = allocinotab(curfile.ino, ip, seekpt); 2042311Sjkh getfile(putdir, xtrnull); 2052311Sjkh putent(&nulldir); 2062311Sjkh flushent(); 2072311Sjkh itp->t_size = seekpt - itp->t_seekpt; 2082311Sjkh } 2092311Sjkh} 2102311Sjkh 2112311Sjkh/* 21229452Scharnier * skip over all the directories on the tape 21329452Scharnier */ 21429452Scharniervoid 21529452Scharnierskipdirs() 21629452Scharnier{ 21729452Scharnier 2182311Sjkh while (curfile.dip && (curfile.dip->di_mode & IFMT) == IFDIR) { 2192311Sjkh skipfile(); 2202311Sjkh } 2212311Sjkh} 2222311Sjkh 2232311Sjkh/* 2242311Sjkh * Recursively find names and inumbers of all files in subtree 225135174Sdds * pname and pass them off to be processed. 226135174Sdds */ 227135174Sddsvoid 2282311Sjkhtreescan(pname, ino, todo) 229135174Sdds char *pname; 230135174Sdds ino_t ino; 231135174Sdds long (*todo) __P((char *, ino_t, int)); 232135174Sdds{ 233135174Sdds register struct inotab *itp; 234135174Sdds register struct direct *dp; 235135174Sdds int namelen; 236135174Sdds long bpt; 237135174Sdds char locname[MAXPATHLEN + 1]; 238135174Sdds 239135174Sdds itp = inotablookup(ino); 240135174Sdds if (itp == NULL) { 241135174Sdds /* 242135174Sdds * Pname is name of a simple file or an unchanged directory. 243135174Sdds */ 244135174Sdds (void) (*todo)(pname, ino, LEAF); 245135174Sdds return; 246135174Sdds } 247135174Sdds /* 248135174Sdds * Pname is a dumped directory name. 249135174Sdds */ 250135174Sdds if ((*todo)(pname, ino, NODE) == FAIL) 251135174Sdds return; 252135174Sdds /* 253135174Sdds * begin search through the directory 2542311Sjkh * skipping over "." and ".." 2552311Sjkh */ 2562311Sjkh (void) strncpy(locname, pname, sizeof(locname) - 1); 2572311Sjkh locname[sizeof(locname) - 1] = '\0'; 2582311Sjkh (void) strncat(locname, "/", sizeof(locname) - strlen(locname)); 2592311Sjkh namelen = strlen(locname); 2602311Sjkh rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 2612311Sjkh dp = rst_readdir(dirp); /* "." */ 2622311Sjkh if (dp != NULL && strcmp(dp->d_name, ".") == 0) 26329452Scharnier dp = rst_readdir(dirp); /* ".." */ 2642311Sjkh else 26529452Scharnier fprintf(stderr, "Warning: `.' missing from directory %s\n", 2662311Sjkh pname); 2672311Sjkh if (dp != NULL && strcmp(dp->d_name, "..") == 0) 2682311Sjkh dp = rst_readdir(dirp); /* first real entry */ 2692311Sjkh else 270135174Sdds fprintf(stderr, "Warning: `..' missing from directory %s\n", 2712311Sjkh pname); 2722311Sjkh bpt = rst_telldir(dirp); 2732311Sjkh /* 2742311Sjkh * a zero inode signals end of directory 2752311Sjkh */ 2762311Sjkh while (dp != NULL) { 2772311Sjkh locname[namelen] = '\0'; 27867127Spaul if (namelen + dp->d_namlen >= sizeof(locname)) { 2792311Sjkh fprintf(stderr, "%s%s: name exceeds %d char\n", 28067127Spaul locname, dp->d_name, sizeof(locname) - 1); 28167127Spaul } else { 28267127Spaul (void) strncat(locname, dp->d_name, (int)dp->d_namlen); 28367127Spaul treescan(locname, dp->d_ino, todo); 28467127Spaul rst_seekdir(dirp, bpt, itp->t_seekpt); 28567127Spaul } 28667127Spaul dp = rst_readdir(dirp); 28767127Spaul bpt = rst_telldir(dirp); 28867127Spaul } 2892311Sjkh} 2902311Sjkh 2912311Sjkh/* 2922311Sjkh * Lookup a pathname which is always assumed to start from the ROOTINO. 29329452Scharnier */ 2942311Sjkhstruct direct * 29529452Scharnierpathsearch(pathname) 2962311Sjkh const char *pathname; 2972311Sjkh{ 2982311Sjkh ino_t ino; 2992311Sjkh struct direct *dp; 3002311Sjkh char *path, *name, buffer[MAXPATHLEN]; 3012311Sjkh 3022311Sjkh strcpy(buffer, pathname); 3032311Sjkh path = buffer; 3042311Sjkh ino = ROOTINO; 3052311Sjkh while (*path == '/') 3062311Sjkh path++; 3072311Sjkh dp = NULL; 3082311Sjkh while ((name = strsep(&path, "/")) != NULL && *name != NULL) { 3092311Sjkh if ((dp = searchdir(ino, name)) == NULL) 3102311Sjkh return (NULL); 3112311Sjkh ino = dp->d_ino; 3122311Sjkh } 3132311Sjkh return (dp); 314135174Sdds} 31568388Sdwmalone 3162311Sjkh/* 3172311Sjkh * Lookup the requested name in directory inum. 31820573Spst * Return its inode number if found, zero if it does not exist. 319135165Sdds */ 320135242Sddsstatic struct direct * 321135242Sddssearchdir(inum, name) 3222311Sjkh ino_t inum; 3232311Sjkh char *name; 3242311Sjkh{ 3252311Sjkh register struct direct *dp; 32629452Scharnier register struct inotab *itp; 32729452Scharnier int len; 32829452Scharnier 32969793Sobrien itp = inotablookup(inum); 33069793Sobrien if (itp == NULL) 3312311Sjkh return (NULL); 3322311Sjkh rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 33320573Spst len = strlen(name); 33420573Spst do { 33520573Spst dp = rst_readdir(dirp); 33629452Scharnier if (dp == NULL) 33720573Spst return (NULL); 3382311Sjkh } while (dp->d_namlen != len || strncmp(dp->d_name, name, len) != 0); 3392311Sjkh return (dp); 34020573Spst} 3412311Sjkh 3422311Sjkh/* 3432311Sjkh * Put the directory entries in the directory file 3442311Sjkh */ 3452311Sjkhstatic void 34629452Scharnierputdir(buf, size) 3472311Sjkh char *buf; 3482311Sjkh long size; 34968388Sdwmalone{ 35029452Scharnier struct direct cvtbuf; 3512311Sjkh register struct odirect *odp; 3522311Sjkh struct odirect *eodp; 3532311Sjkh register struct direct *dp; 354135174Sdds long loc, i; 3552311Sjkh 35668388Sdwmalone if (cvtflag) { 35729452Scharnier eodp = (struct odirect *)&buf[size]; 35868388Sdwmalone for (odp = (struct odirect *)buf; odp < eodp; odp++) 35968388Sdwmalone if (odp->d_ino != 0) { 36068388Sdwmalone dcvt(odp, &cvtbuf); 36168388Sdwmalone putent(&cvtbuf); 3622311Sjkh } 3635176Sache } else { 36429452Scharnier for (loc = 0; loc < size; ) { 3652311Sjkh dp = (struct direct *)(buf + loc); 3662311Sjkh if (Bcvt) 3672311Sjkh swabst((u_char *)"ls", (u_char *) dp); 36868388Sdwmalone if (oldinofmt && dp->d_ino != 0) { 36968388Sdwmalone# if BYTE_ORDER == BIG_ENDIAN 370135242Sdds if (Bcvt) 371135242Sdds dp->d_namlen = dp->d_type; 372135242Sdds# else 373135242Sdds if (!Bcvt) 3742311Sjkh dp->d_namlen = dp->d_type; 3752311Sjkh# endif 3762311Sjkh dp->d_type = DT_UNKNOWN; 3772311Sjkh } 3782311Sjkh i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1)); 3792311Sjkh if ((dp->d_reclen & 0x3) != 0 || 3802311Sjkh dp->d_reclen > i || 3812311Sjkh dp->d_reclen < DIRSIZ(0, dp) || 3822311Sjkh dp->d_namlen > NAME_MAX) { 3832311Sjkh vprintf(stdout, "Mangled directory: "); 3842311Sjkh if ((dp->d_reclen & 0x3) != 0) 3852311Sjkh vprintf(stdout, 3862311Sjkh "reclen not multiple of 4 "); 3872311Sjkh if (dp->d_reclen < DIRSIZ(0, dp)) 3882311Sjkh vprintf(stdout, 3892311Sjkh "reclen less than DIRSIZ (%d < %d) ", 3902311Sjkh dp->d_reclen, DIRSIZ(0, dp)); 39129452Scharnier if (dp->d_namlen > NAME_MAX) 3922311Sjkh vprintf(stdout, 3932311Sjkh "reclen name too big (%d > %d) ", 3942311Sjkh dp->d_namlen, NAME_MAX); 39529452Scharnier vprintf(stdout, "\n"); 39629452Scharnier loc += i; 39729452Scharnier continue; 39829452Scharnier } 39929452Scharnier loc += dp->d_reclen; 40029452Scharnier if (dp->d_ino != 0) { 40179452Sbrian putent(dp); 40229452Scharnier } 4032311Sjkh } 4042311Sjkh } 4052311Sjkh} 4062311Sjkh 4072311Sjkh/* 4082311Sjkh * These variables are "local" to the following two functions. 4092311Sjkh */ 41015161Sscrappychar dirbuf[DIRBLKSIZ]; 41115161Sscrappylong dirloc = 0; 41215161Sscrappylong prev = 0; 41315161Sscrappy 41415161Sscrappy/* 4152311Sjkh * add a new directory entry to a file. 41615161Sscrappy */ 41715161Sscrappystatic void 41815161Sscrappyputent(dp) 41915161Sscrappy struct direct *dp; 4202311Sjkh{ 42129452Scharnier dp->d_reclen = DIRSIZ(0, dp); 4222311Sjkh if (dirloc + dp->d_reclen > DIRBLKSIZ) { 4232311Sjkh ((struct direct *)(dirbuf + prev))->d_reclen = 4242311Sjkh DIRBLKSIZ - prev; 42529452Scharnier (void) fwrite(dirbuf, 1, DIRBLKSIZ, df); 4262311Sjkh dirloc = 0; 4272311Sjkh } 4282311Sjkh memmove(dirbuf + dirloc, dp, (long)dp->d_reclen); 42929452Scharnier prev = dirloc; 43029452Scharnier dirloc += dp->d_reclen; 4312311Sjkh} 4322311Sjkh 4335176Sache/* 43429452Scharnier * flush out a directory that is finished. 4352311Sjkh */ 4362311Sjkhstatic void 43768388Sdwmaloneflushent() 43868388Sdwmalone{ 439135242Sdds ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev; 440135242Sdds (void) fwrite(dirbuf, (int)dirloc, 1, df); 441135242Sdds seekpt = ftell(df); 442135242Sdds dirloc = 0; 443135242Sdds} 44429452Scharnier 4452311Sjkhstatic void 4462311Sjkhdcvt(odp, ndp) 44729452Scharnier register struct odirect *odp; 4482311Sjkh register struct direct *ndp; 449135165Sdds{ 4502311Sjkh 451135165Sdds memset(ndp, 0, (long)(sizeof *ndp)); 4522311Sjkh ndp->d_ino = odp->d_ino; 4532311Sjkh ndp->d_type = DT_UNKNOWN; 4542311Sjkh (void) strncpy(ndp->d_name, odp->d_name, ODIRSIZ); 4552311Sjkh ndp->d_namlen = strlen(ndp->d_name); 4562311Sjkh ndp->d_reclen = DIRSIZ(0, ndp); 4572311Sjkh} 4582311Sjkh 459135165Sdds/* 4602311Sjkh * Seek to an entry in a directory. 4612311Sjkh * Only values returned by rst_telldir should be passed to rst_seekdir. 4622311Sjkh * This routine handles many directories in a single file. 4632311Sjkh * It takes the base of the directory in the file, plus 4642311Sjkh * the desired seek offset into it. 4652311Sjkh */ 4662311Sjkhstatic void 4672311Sjkhrst_seekdir(dirp, loc, base) 468135165Sdds register RST_DIR *dirp; 4692311Sjkh long loc, base; 47029452Scharnier{ 4712311Sjkh 4722311Sjkh if (loc == rst_telldir(dirp)) 47329452Scharnier return; 4742311Sjkh loc -= base; 4752311Sjkh if (loc < 0) 4762311Sjkh fprintf(stderr, "bad seek pointer to rst_seekdir %d\n", loc); 4772311Sjkh (void) lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), SEEK_SET); 4782311Sjkh dirp->dd_loc = loc & (DIRBLKSIZ - 1); 4792311Sjkh if (dirp->dd_loc != 0) 4802311Sjkh dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ); 4812311Sjkh} 4828857Srgrimes 4832311Sjkh/* 4842311Sjkh * get next entry in a directory. 4852311Sjkh */ 4862311Sjkhstruct direct * 4872311Sjkhrst_readdir(dirp) 4882311Sjkh register RST_DIR *dirp; 4892311Sjkh{ 4902311Sjkh register struct direct *dp; 4912311Sjkh 4922311Sjkh for (;;) { 4932311Sjkh if (dirp->dd_loc == 0) { 4942311Sjkh dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, 4952311Sjkh DIRBLKSIZ); 49620573Spst if (dirp->dd_size <= 0) { 49729452Scharnier dprintf(stderr, "error reading directory\n"); 49820573Spst return (NULL); 49920573Spst } 50020573Spst } 5012311Sjkh if (dirp->dd_loc >= dirp->dd_size) { 5022311Sjkh dirp->dd_loc = 0; 5032311Sjkh continue; 50429452Scharnier } 5052311Sjkh dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc); 5062311Sjkh if (dp->d_reclen == 0 || 5072311Sjkh dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc) { 5082311Sjkh dprintf(stderr, "corrupted directory: bad reclen %d\n", 5092311Sjkh dp->d_reclen); 5102311Sjkh return (NULL); 5112311Sjkh } 5122311Sjkh dirp->dd_loc += dp->d_reclen; 5132311Sjkh if (dp->d_ino == 0 && strcmp(dp->d_name, "/") == 0) 5142311Sjkh return (NULL); 5152311Sjkh if (dp->d_ino >= maxino) { 5162311Sjkh dprintf(stderr, "corrupted directory: bad inum %d\n", 5172311Sjkh dp->d_ino); 51868388Sdwmalone continue; 5192311Sjkh } 5202311Sjkh return (dp); 5212311Sjkh } 5222311Sjkh} 5232311Sjkh 5242311Sjkh/* 5252311Sjkh * Simulate the opening of a directory 52629452Scharnier */ 5272311SjkhRST_DIR * 5282311Sjkhrst_opendir(name) 5292311Sjkh const char *name; 5302311Sjkh{ 5312311Sjkh struct inotab *itp; 5322311Sjkh RST_DIR *dirp; 5332311Sjkh ino_t ino; 5342311Sjkh 5352311Sjkh if ((ino = dirlookup(name)) > 0 && 5362311Sjkh (itp = inotablookup(ino)) != NULL) { 5372311Sjkh dirp = opendirfile(dirfile); 5382311Sjkh rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 5392311Sjkh return (dirp); 5402311Sjkh } 5412311Sjkh return (NULL); 5422311Sjkh} 5432311Sjkh 5442311Sjkh/* 5452311Sjkh * In our case, there is nothing to do when closing a directory. 5462311Sjkh */ 5472311Sjkhvoid 5482311Sjkhrst_closedir(dirp) 5492311Sjkh RST_DIR *dirp; 5502311Sjkh{ 5512311Sjkh 5522311Sjkh (void)close(dirp->dd_fd); 5532311Sjkh free(dirp); 5542311Sjkh return; 5552311Sjkh} 55629452Scharnier 5572311Sjkh/* 5582311Sjkh * Simulate finding the current offset in the directory. 5592311Sjkh */ 5602311Sjkhstatic long 5612311Sjkhrst_telldir(dirp) 5622311Sjkh RST_DIR *dirp; 5632311Sjkh{ 5642311Sjkh return ((long)lseek(dirp->dd_fd, 5652311Sjkh (off_t)0, SEEK_CUR) - dirp->dd_size + dirp->dd_loc); 5662311Sjkh} 56729452Scharnier 5682311Sjkh/* 5692311Sjkh * Open a directory file. 5702311Sjkh */ 5712311Sjkhstatic RST_DIR * 5722311Sjkhopendirfile(name) 5732311Sjkh const char *name; 5742311Sjkh{ 5752311Sjkh register RST_DIR *dirp; 5762311Sjkh register int fd; 5772311Sjkh 57829452Scharnier if ((fd = open(name, O_RDONLY)) == -1) 5792311Sjkh return (NULL); 5802311Sjkh if ((dirp = malloc(sizeof(RST_DIR))) == NULL) { 5812311Sjkh (void)close(fd); 5822311Sjkh return (NULL); 5832311Sjkh } 58429452Scharnier dirp->dd_fd = fd; 5852311Sjkh dirp->dd_loc = 0; 5862311Sjkh return (dirp); 5872311Sjkh} 5882311Sjkh 5892311Sjkh/* 5902311Sjkh * Set the mode, owner, and times for all new or changed directories 59129452Scharnier */ 5922311Sjkhvoid 5932311Sjkhsetdirmodes(flags) 5942311Sjkh int flags; 5952311Sjkh{ 5962311Sjkh FILE *mf; 5972311Sjkh struct modeinfo node; 5982311Sjkh struct entry *ep; 5992311Sjkh char *cp; 6002311Sjkh 6012311Sjkh vprintf(stdout, "Set directory mode, owner, and times.\n"); 6022311Sjkh if (command == 'r' || command == 'R') 6032311Sjkh (void) sprintf(modefile, "%srstmode%d", _PATH_TMP, dumpdate); 6042311Sjkh if (modefile[0] == '#') { 6052311Sjkh panic("modefile not defined\n"); 6062311Sjkh fprintf(stderr, "directory mode, owner, and times not set\n"); 6072311Sjkh return; 6082311Sjkh } 6092311Sjkh mf = fopen(modefile, "r"); 6102311Sjkh if (mf == NULL) { 6112311Sjkh fprintf(stderr, "fopen: %s\n", strerror(errno)); 61229452Scharnier fprintf(stderr, "cannot open mode file %s\n", modefile); 6132311Sjkh fprintf(stderr, "directory mode, owner, and times not set\n"); 6142311Sjkh return; 6152311Sjkh } 6162311Sjkh clearerr(mf); 61729452Scharnier for (;;) { 6182311Sjkh (void) fread((char *)&node, 1, sizeof(struct modeinfo), mf); 6192311Sjkh if (feof(mf)) 6202311Sjkh break; 6212311Sjkh ep = lookupino(node.ino); 622 if (command == 'i' || command == 'x') { 623 if (ep == NULL) 624 continue; 625 if ((flags & FORCE) == 0 && ep->e_flags & EXISTED) { 626 ep->e_flags &= ~NEW; 627 continue; 628 } 629 if (node.ino == ROOTINO && 630 reply("set owner/mode for '.'") == FAIL) 631 continue; 632 } 633 if (ep == NULL) { 634 panic("cannot find directory inode %d\n", node.ino); 635 } else { 636 cp = myname(ep); 637 (void) chown(cp, node.uid, node.gid); 638 (void) chmod(cp, node.mode); 639 (void) chflags(cp, node.flags); 640 utimes(cp, node.timep); 641 ep->e_flags &= ~NEW; 642 } 643 } 644 if (ferror(mf)) 645 panic("error setting directory modes\n"); 646 (void) fclose(mf); 647} 648 649/* 650 * Generate a literal copy of a directory. 651 */ 652int 653genliteraldir(name, ino) 654 char *name; 655 ino_t ino; 656{ 657 register struct inotab *itp; 658 int ofile, dp, i, size; 659 char buf[BUFSIZ]; 660 661 itp = inotablookup(ino); 662 if (itp == NULL) 663 panic("Cannot find directory inode %d named %s\n", ino, name); 664 if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) { 665 fprintf(stderr, "%s: ", name); 666 (void) fflush(stderr); 667 fprintf(stderr, "cannot create file: %s\n", strerror(errno)); 668 return (FAIL); 669 } 670 rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 671 dp = dup(dirp->dd_fd); 672 for (i = itp->t_size; i > 0; i -= BUFSIZ) { 673 size = i < BUFSIZ ? i : BUFSIZ; 674 if (read(dp, buf, (int) size) == -1) { 675 fprintf(stderr, 676 "write error extracting inode %d, name %s\n", 677 curfile.ino, curfile.name); 678 fprintf(stderr, "read: %s\n", strerror(errno)); 679 done(1); 680 } 681 if (!Nflag && write(ofile, buf, (int) size) == -1) { 682 fprintf(stderr, 683 "write error extracting inode %d, name %s\n", 684 curfile.ino, curfile.name); 685 fprintf(stderr, "write: %s\n", strerror(errno)); 686 done(1); 687 } 688 } 689 (void) close(dp); 690 (void) close(ofile); 691 return (GOOD); 692} 693 694/* 695 * Determine the type of an inode 696 */ 697int 698inodetype(ino) 699 ino_t ino; 700{ 701 struct inotab *itp; 702 703 itp = inotablookup(ino); 704 if (itp == NULL) 705 return (LEAF); 706 return (NODE); 707} 708 709/* 710 * Allocate and initialize a directory inode entry. 711 * If requested, save its pertinent mode, owner, and time info. 712 */ 713static struct inotab * 714allocinotab(ino, dip, seekpt) 715 ino_t ino; 716 struct dinode *dip; 717 long seekpt; 718{ 719 register struct inotab *itp; 720 struct modeinfo node; 721 722 itp = calloc(1, sizeof(struct inotab)); 723 if (itp == NULL) 724 panic("no memory directory table\n"); 725 itp->t_next = inotab[INOHASH(ino)]; 726 inotab[INOHASH(ino)] = itp; 727 itp->t_ino = ino; 728 itp->t_seekpt = seekpt; 729 if (mf == NULL) 730 return (itp); 731 node.ino = ino; 732 node.timep[0].tv_sec = dip->di_atime; 733 node.timep[0].tv_usec = dip->di_atimensec / 1000; 734 node.timep[1].tv_sec = dip->di_mtime; 735 node.timep[1].tv_usec = dip->di_mtimensec / 1000; 736 node.mode = dip->di_mode; 737 node.flags = dip->di_flags; 738 node.uid = dip->di_uid; 739 node.gid = dip->di_gid; 740 (void) fwrite((char *)&node, 1, sizeof(struct modeinfo), mf); 741 return (itp); 742} 743 744/* 745 * Look up an inode in the table of directories 746 */ 747static struct inotab * 748inotablookup(ino) 749 ino_t ino; 750{ 751 register struct inotab *itp; 752 753 for (itp = inotab[INOHASH(ino)]; itp != NULL; itp = itp->t_next) 754 if (itp->t_ino == ino) 755 return (itp); 756 return (NULL); 757} 758 759/* 760 * Clean up and exit 761 */ 762void 763done(exitcode) 764 int exitcode; 765{ 766 767 closemt(); 768 if (modefile[0] != '#') 769 (void) unlink(modefile); 770 if (dirfile[0] != '#') 771 (void) unlink(dirfile); 772 exit(exitcode); 773} 774