121165Sdist /* 261536Sbostic * Copyright (c) 1983, 1993 361536Sbostic * The Regents of the University of California. All rights reserved. 4*65767Sbostic * (c) UNIX System Laboratories, Inc. 5*65767Sbostic * All or some portions of this file are derived from material licensed 6*65767Sbostic * to the University of California by American Telephone and Telegraph 7*65767Sbostic * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8*65767Sbostic * the permission of UNIX System Laboratories, Inc. 936105Sbostic * 1042708Sbostic * %sccs.include.redist.c% 1121165Sdist */ 1221165Sdist 1311127Smckusick #ifndef lint 14*65767Sbostic static char sccsid[] = "@(#)dirs.c 8.2 (Berkeley) 01/21/94"; 1536105Sbostic #endif /* not lint */ 1611127Smckusick 1756567Sbostic #include <sys/param.h> 1811309Smckusick #include <sys/file.h> 1956567Sbostic #include <sys/stat.h> 2056567Sbostic #include <sys/time.h> 2156567Sbostic 2256567Sbostic #include <ufs/ffs/fs.h> 2356567Sbostic #include <ufs/ufs/dinode.h> 2451625Sbostic #include <ufs/ufs/dir.h> 2556567Sbostic #include <protocols/dumprestore.h> 2656567Sbostic 2756567Sbostic #include <errno.h> 2856567Sbostic #include <stdio.h> 2956567Sbostic #include <stdlib.h> 3056567Sbostic #include <string.h> 3156567Sbostic #include <unistd.h> 3256567Sbostic 3337952Sbostic #include "pathnames.h" 3456567Sbostic #include "restore.h" 3556567Sbostic #include "extern.h" 3611127Smckusick 3711992Smckusick /* 3811992Smckusick * Symbol table of directories read from tape. 3911992Smckusick */ 4011127Smckusick #define HASHSIZE 1000 4111127Smckusick #define INOHASH(val) (val % HASHSIZE) 4211127Smckusick struct inotab { 4350662Smckusick struct inotab *t_next; 4411127Smckusick ino_t t_ino; 4550662Smckusick long t_seekpt; 4650662Smckusick long t_size; 4711309Smckusick }; 4811309Smckusick static struct inotab *inotab[HASHSIZE]; 4911127Smckusick 5011992Smckusick /* 5111992Smckusick * Information retained about directories. 5211992Smckusick */ 5311127Smckusick struct modeinfo { 5411127Smckusick ino_t ino; 5539471Smckusick struct timeval timep[2]; 5611127Smckusick short mode; 5711127Smckusick short uid; 5811127Smckusick short gid; 5911127Smckusick }; 6011127Smckusick 6111992Smckusick /* 6240094Smckusick * Definitions for library routines operating on directories. 6340094Smckusick */ 6446564Smckusick #undef DIRBLKSIZ 6546564Smckusick #define DIRBLKSIZ 1024 6650657Smckusick struct rstdirdesc { 6740094Smckusick int dd_fd; 6840094Smckusick long dd_loc; 6940094Smckusick long dd_size; 7040094Smckusick char dd_buf[DIRBLKSIZ]; 7140094Smckusick }; 7240094Smckusick 7340094Smckusick /* 7411992Smckusick * Global variables for this file. 7511992Smckusick */ 7650662Smckusick static long seekpt; 7711309Smckusick static FILE *df, *mf; 7850657Smckusick static RST_DIR *dirp; 7911992Smckusick static char dirfile[32] = "#"; /* No file */ 8011992Smckusick static char modefile[32] = "#"; /* No file */ 8146566Smckusick static char dot[2] = "."; /* So it can be modified */ 8211127Smckusick 8311992Smckusick /* 8411992Smckusick * Format of old style directories. 8511992Smckusick */ 8611127Smckusick #define ODIRSIZ 14 8711127Smckusick struct odirect { 8811127Smckusick u_short d_ino; 8911127Smckusick char d_name[ODIRSIZ]; 9011127Smckusick }; 9111127Smckusick 9256567Sbostic static struct inotab *allocinotab __P((ino_t, struct dinode *, long)); 9356567Sbostic static void dcvt __P((struct odirect *, struct direct *)); 9456567Sbostic static void flushent __P((void)); 9556567Sbostic static struct inotab *inotablookup __P((ino_t)); 9657896Sbostic static RST_DIR *opendirfile __P((const char *)); 9756567Sbostic static void putdir __P((char *, long)); 9856567Sbostic static void putent __P((struct direct *)); 9956567Sbostic static void rst_seekdir __P((RST_DIR *, long, long)); 10056567Sbostic static long rst_telldir __P((RST_DIR *)); 10156946Smckusick static struct direct *searchdir __P((ino_t, char *)); 10256567Sbostic 10311127Smckusick /* 10411127Smckusick * Extract directory contents, building up a directory structure 10511127Smckusick * on disk for extraction by name. 10611992Smckusick * If genmode is requested, save mode, owner, and times for all 10711127Smckusick * directories on the tape. 10811127Smckusick */ 10956567Sbostic void 11011992Smckusick extractdirs(genmode) 11111992Smckusick int genmode; 11211127Smckusick { 11311127Smckusick register int i; 11411127Smckusick register struct dinode *ip; 11511322Smckusick struct inotab *itp; 11611127Smckusick struct direct nulldir; 11711127Smckusick 11811127Smckusick vprintf(stdout, "Extract directories from tape\n"); 11937952Sbostic (void) sprintf(dirfile, "%s/rstdir%d", _PATH_TMP, dumpdate); 12011127Smckusick df = fopen(dirfile, "w"); 12157930Sbostic if (df == NULL) { 12211127Smckusick fprintf(stderr, 12315779Smckusick "restore: %s - cannot create directory temporary\n", 12411127Smckusick dirfile); 12556567Sbostic fprintf(stderr, "fopen: %s\n", strerror(errno)); 12611127Smckusick done(1); 12711127Smckusick } 12811992Smckusick if (genmode != 0) { 12937952Sbostic (void) sprintf(modefile, "%s/rstmode%d", _PATH_TMP, dumpdate); 13011127Smckusick mf = fopen(modefile, "w"); 13157930Sbostic if (mf == NULL) { 13211127Smckusick fprintf(stderr, 13315779Smckusick "restore: %s - cannot create modefile \n", 13411127Smckusick modefile); 13556567Sbostic fprintf(stderr, "fopen: %s\n", strerror(errno)); 13611127Smckusick done(1); 13711127Smckusick } 13811127Smckusick } 13911322Smckusick nulldir.d_ino = 0; 14054582Smckusick nulldir.d_type = DT_DIR; 14111127Smckusick nulldir.d_namlen = 1; 14212453Smckusick (void) strcpy(nulldir.d_name, "/"); 14354582Smckusick nulldir.d_reclen = DIRSIZ(0, &nulldir); 14411127Smckusick for (;;) { 14511127Smckusick curfile.name = "<directory file - name unknown>"; 14611127Smckusick curfile.action = USING; 14711127Smckusick ip = curfile.dip; 14817948Smckusick if (ip == NULL || (ip->di_mode & IFMT) != IFDIR) { 14911732Smckusick (void) fclose(df); 15040064Smckusick dirp = opendirfile(dirfile); 15111127Smckusick if (dirp == NULL) 15256567Sbostic fprintf(stderr, "opendirfile: %s\n", 15356567Sbostic strerror(errno)); 15411127Smckusick if (mf != NULL) 15511732Smckusick (void) fclose(mf); 15646566Smckusick i = dirlookup(dot); 15711992Smckusick if (i == 0) 15811421Smckusick panic("Root directory is not on tape\n"); 15911127Smckusick return; 16011127Smckusick } 16111322Smckusick itp = allocinotab(curfile.ino, ip, seekpt); 16256434Smckusick getfile(putdir, xtrnull); 16311127Smckusick putent(&nulldir); 16411127Smckusick flushent(); 16511322Smckusick itp->t_size = seekpt - itp->t_seekpt; 16611127Smckusick } 16711127Smckusick } 16811127Smckusick 16911127Smckusick /* 17011322Smckusick * skip over all the directories on the tape 17111322Smckusick */ 17256567Sbostic void 17311322Smckusick skipdirs() 17411322Smckusick { 17511322Smckusick 17611322Smckusick while ((curfile.dip->di_mode & IFMT) == IFDIR) { 17711322Smckusick skipfile(); 17811322Smckusick } 17911322Smckusick } 18011322Smckusick 18111322Smckusick /* 18211127Smckusick * Recursively find names and inumbers of all files in subtree 18311127Smckusick * pname and pass them off to be processed. 18411127Smckusick */ 18556567Sbostic void 18611127Smckusick treescan(pname, ino, todo) 18711127Smckusick char *pname; 18811127Smckusick ino_t ino; 18956567Sbostic long (*todo) __P((char *, ino_t, int)); 19011127Smckusick { 19111127Smckusick register struct inotab *itp; 19212453Smckusick register struct direct *dp; 19311127Smckusick int namelen; 19450662Smckusick long bpt; 19511644Smckusick char locname[MAXPATHLEN + 1]; 19611127Smckusick 19711127Smckusick itp = inotablookup(ino); 19811127Smckusick if (itp == NULL) { 19911127Smckusick /* 20011127Smckusick * Pname is name of a simple file or an unchanged directory. 20111127Smckusick */ 20211744Smckusick (void) (*todo)(pname, ino, LEAF); 20311127Smckusick return; 20411127Smckusick } 20511127Smckusick /* 20611127Smckusick * Pname is a dumped directory name. 20711127Smckusick */ 20811744Smckusick if ((*todo)(pname, ino, NODE) == FAIL) 20911744Smckusick return; 21011127Smckusick /* 21111127Smckusick * begin search through the directory 21211127Smckusick * skipping over "." and ".." 21311127Smckusick */ 21411992Smckusick (void) strncpy(locname, pname, MAXPATHLEN); 21511992Smckusick (void) strncat(locname, "/", MAXPATHLEN); 21611127Smckusick namelen = strlen(locname); 21712556Smckusick rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 21812556Smckusick dp = rst_readdir(dirp); /* "." */ 21927263Smckusick if (dp != NULL && strcmp(dp->d_name, ".") == 0) 22012556Smckusick dp = rst_readdir(dirp); /* ".." */ 22127263Smckusick else 22227263Smckusick fprintf(stderr, "Warning: `.' missing from directory %s\n", 22327263Smckusick pname); 22427263Smckusick if (dp != NULL && strcmp(dp->d_name, "..") == 0) 22512556Smckusick dp = rst_readdir(dirp); /* first real entry */ 22627263Smckusick else 22727263Smckusick fprintf(stderr, "Warning: `..' missing from directory %s\n", 22827263Smckusick pname); 22940064Smckusick bpt = rst_telldir(dirp); 23011127Smckusick /* 23112453Smckusick * a zero inode signals end of directory 23211127Smckusick */ 23312453Smckusick while (dp != NULL && dp->d_ino != 0) { 23411127Smckusick locname[namelen] = '\0'; 23511644Smckusick if (namelen + dp->d_namlen >= MAXPATHLEN) { 23611127Smckusick fprintf(stderr, "%s%s: name exceeds %d char\n", 23711644Smckusick locname, dp->d_name, MAXPATHLEN); 23811127Smckusick } else { 23911992Smckusick (void) strncat(locname, dp->d_name, (int)dp->d_namlen); 24011127Smckusick treescan(locname, dp->d_ino, todo); 24112556Smckusick rst_seekdir(dirp, bpt, itp->t_seekpt); 24211127Smckusick } 24312556Smckusick dp = rst_readdir(dirp); 24440064Smckusick bpt = rst_telldir(dirp); 24511127Smckusick } 24611127Smckusick if (dp == NULL) 24711127Smckusick fprintf(stderr, "corrupted directory: %s.\n", locname); 24811127Smckusick } 24911127Smckusick 25011127Smckusick /* 25156434Smckusick * Lookup a pathname which is always assumed to start from the ROOTINO. 25211127Smckusick */ 25356946Smckusick struct direct * 25456434Smckusick pathsearch(pathname) 25557896Sbostic const char *pathname; 25611127Smckusick { 25711127Smckusick ino_t ino; 25856946Smckusick struct direct *dp; 25957896Sbostic char *path, *name, buffer[MAXPATHLEN]; 26011127Smckusick 26156434Smckusick strcpy(buffer, pathname); 26257896Sbostic path = buffer; 26311127Smckusick ino = ROOTINO; 26457896Sbostic while (*path == '/') 26557896Sbostic path++; 26657930Sbostic dp = NULL; 26757896Sbostic while ((name = strsep(&path, "/")) != NULL && *name != NULL) { 26857930Sbostic if ((dp = searchdir(ino, name)) == NULL) 26956946Smckusick return (NULL); 27056946Smckusick ino = dp->d_ino; 27156946Smckusick } 27256946Smckusick return (dp); 27311127Smckusick } 27411127Smckusick 27511127Smckusick /* 27656434Smckusick * Lookup the requested name in directory inum. 27756434Smckusick * Return its inode number if found, zero if it does not exist. 27811127Smckusick */ 27956946Smckusick static struct direct * 28056434Smckusick searchdir(inum, name) 28111127Smckusick ino_t inum; 28256434Smckusick char *name; 28311127Smckusick { 28411127Smckusick register struct direct *dp; 28511127Smckusick register struct inotab *itp; 28611127Smckusick int len; 28711127Smckusick 28811127Smckusick itp = inotablookup(inum); 28911127Smckusick if (itp == NULL) 29057930Sbostic return (NULL); 29112556Smckusick rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 29256434Smckusick len = strlen(name); 29311127Smckusick do { 29412556Smckusick dp = rst_readdir(dirp); 29512453Smckusick if (dp == NULL || dp->d_ino == 0) 29656946Smckusick return (NULL); 29756434Smckusick } while (dp->d_namlen != len || strncmp(dp->d_name, name, len) != 0); 29856946Smckusick return (dp); 29911127Smckusick } 30011127Smckusick 30111127Smckusick /* 30211127Smckusick * Put the directory entries in the directory file 30311127Smckusick */ 30456567Sbostic static void 30511127Smckusick putdir(buf, size) 30611127Smckusick char *buf; 30756567Sbostic long size; 30811127Smckusick { 30911127Smckusick struct direct cvtbuf; 31011127Smckusick register struct odirect *odp; 31111127Smckusick struct odirect *eodp; 31211127Smckusick register struct direct *dp; 31311127Smckusick long loc, i; 31411127Smckusick 31511127Smckusick if (cvtflag) { 31611127Smckusick eodp = (struct odirect *)&buf[size]; 31711127Smckusick for (odp = (struct odirect *)buf; odp < eodp; odp++) 31811127Smckusick if (odp->d_ino != 0) { 31911127Smckusick dcvt(odp, &cvtbuf); 32011127Smckusick putent(&cvtbuf); 32111127Smckusick } 32211127Smckusick } else { 32311127Smckusick for (loc = 0; loc < size; ) { 32411127Smckusick dp = (struct direct *)(buf + loc); 32554582Smckusick if (oldinofmt) { 32654582Smckusick if (Bcvt) { 32756567Sbostic swabst((u_char *)"l2s", (u_char *) dp); 32854582Smckusick } 32954582Smckusick } else { 33054582Smckusick if (Bcvt) { 33156567Sbostic swabst((u_char *)"ls", (u_char *) dp); 33254582Smckusick } 33326941Ssklower } 33411127Smckusick i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1)); 33546564Smckusick if ((dp->d_reclen & 0x3) != 0 || 33646564Smckusick dp->d_reclen > i || 33754582Smckusick dp->d_reclen < DIRSIZ(0, dp) || 33850662Smckusick dp->d_namlen > NAME_MAX) { 33950662Smckusick vprintf(stdout, "Mangled directory: "); 34050662Smckusick if ((dp->d_reclen & 0x3) != 0) 34150662Smckusick vprintf(stdout, 34250662Smckusick "reclen not multiple of 4 "); 34354582Smckusick if (dp->d_reclen < DIRSIZ(0, dp)) 34450662Smckusick vprintf(stdout, 34550662Smckusick "reclen less than DIRSIZ (%d < %d) ", 34654582Smckusick dp->d_reclen, DIRSIZ(0, dp)); 34750662Smckusick if (dp->d_namlen > NAME_MAX) 34850662Smckusick vprintf(stdout, 34950662Smckusick "reclen name too big (%d > %d) ", 35050662Smckusick dp->d_namlen, NAME_MAX); 35150662Smckusick vprintf(stdout, "\n"); 35211127Smckusick loc += i; 35311127Smckusick continue; 35411127Smckusick } 35511127Smckusick loc += dp->d_reclen; 35611127Smckusick if (dp->d_ino != 0) { 35711127Smckusick putent(dp); 35811127Smckusick } 35911127Smckusick } 36011127Smckusick } 36111127Smckusick } 36211127Smckusick 36311127Smckusick /* 36411127Smckusick * These variables are "local" to the following two functions. 36511127Smckusick */ 36611127Smckusick char dirbuf[DIRBLKSIZ]; 36711127Smckusick long dirloc = 0; 36811127Smckusick long prev = 0; 36911127Smckusick 37011127Smckusick /* 37111127Smckusick * add a new directory entry to a file. 37211127Smckusick */ 37356567Sbostic static void 37411127Smckusick putent(dp) 37511127Smckusick struct direct *dp; 37611127Smckusick { 37754582Smckusick dp->d_reclen = DIRSIZ(0, dp); 37811127Smckusick if (dirloc + dp->d_reclen > DIRBLKSIZ) { 37911127Smckusick ((struct direct *)(dirbuf + prev))->d_reclen = 38011127Smckusick DIRBLKSIZ - prev; 38111732Smckusick (void) fwrite(dirbuf, 1, DIRBLKSIZ, df); 38211127Smckusick dirloc = 0; 38311127Smckusick } 38411127Smckusick bcopy((char *)dp, dirbuf + dirloc, (long)dp->d_reclen); 38511127Smckusick prev = dirloc; 38611127Smckusick dirloc += dp->d_reclen; 38711127Smckusick } 38811127Smckusick 38911127Smckusick /* 39011127Smckusick * flush out a directory that is finished. 39111127Smckusick */ 39256567Sbostic static void 39311127Smckusick flushent() 39411127Smckusick { 39511127Smckusick ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev; 39611732Smckusick (void) fwrite(dirbuf, (int)dirloc, 1, df); 39711127Smckusick seekpt = ftell(df); 39811127Smckusick dirloc = 0; 39911127Smckusick } 40011127Smckusick 40156567Sbostic static void 40211127Smckusick dcvt(odp, ndp) 40311127Smckusick register struct odirect *odp; 40411127Smckusick register struct direct *ndp; 40511127Smckusick { 40611127Smckusick 40711127Smckusick bzero((char *)ndp, (long)(sizeof *ndp)); 40811127Smckusick ndp->d_ino = odp->d_ino; 40954582Smckusick ndp->d_type = DT_UNKNOWN; 41011992Smckusick (void) strncpy(ndp->d_name, odp->d_name, ODIRSIZ); 41111127Smckusick ndp->d_namlen = strlen(ndp->d_name); 41254582Smckusick ndp->d_reclen = DIRSIZ(0, ndp); 41311127Smckusick } 41411127Smckusick 41511127Smckusick /* 41611127Smckusick * Seek to an entry in a directory. 41740064Smckusick * Only values returned by rst_telldir should be passed to rst_seekdir. 41811732Smckusick * This routine handles many directories in a single file. 41911732Smckusick * It takes the base of the directory in the file, plus 42011732Smckusick * the desired seek offset into it. 42111127Smckusick */ 42256567Sbostic static void 42312556Smckusick rst_seekdir(dirp, loc, base) 42450657Smckusick register RST_DIR *dirp; 42550662Smckusick long loc, base; 42611127Smckusick { 42711127Smckusick 42840064Smckusick if (loc == rst_telldir(dirp)) 42911127Smckusick return; 43011127Smckusick loc -= base; 43111127Smckusick if (loc < 0) 43212556Smckusick fprintf(stderr, "bad seek pointer to rst_seekdir %d\n", loc); 43356567Sbostic (void) lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), SEEK_SET); 43411127Smckusick dirp->dd_loc = loc & (DIRBLKSIZ - 1); 43511127Smckusick if (dirp->dd_loc != 0) 43611127Smckusick dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ); 43711127Smckusick } 43811127Smckusick 43911127Smckusick /* 44011127Smckusick * get next entry in a directory. 44111127Smckusick */ 44211127Smckusick struct direct * 44312556Smckusick rst_readdir(dirp) 44450657Smckusick register RST_DIR *dirp; 44511127Smckusick { 44611127Smckusick register struct direct *dp; 44711127Smckusick 44811127Smckusick for (;;) { 44911127Smckusick if (dirp->dd_loc == 0) { 45011127Smckusick dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, 45111127Smckusick DIRBLKSIZ); 45212453Smckusick if (dirp->dd_size <= 0) { 45312453Smckusick dprintf(stderr, "error reading directory\n"); 45456567Sbostic return (NULL); 45512453Smckusick } 45611127Smckusick } 45711127Smckusick if (dirp->dd_loc >= dirp->dd_size) { 45811127Smckusick dirp->dd_loc = 0; 45911127Smckusick continue; 46011127Smckusick } 46111127Smckusick dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc); 46211127Smckusick if (dp->d_reclen == 0 || 46312453Smckusick dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc) { 46412453Smckusick dprintf(stderr, "corrupted directory: bad reclen %d\n", 46512453Smckusick dp->d_reclen); 46656567Sbostic return (NULL); 46712453Smckusick } 46811127Smckusick dirp->dd_loc += dp->d_reclen; 46912453Smckusick if (dp->d_ino == 0 && strcmp(dp->d_name, "/") != 0) 47012453Smckusick continue; 47112556Smckusick if (dp->d_ino >= maxino) { 47212453Smckusick dprintf(stderr, "corrupted directory: bad inum %d\n", 47312453Smckusick dp->d_ino); 47412453Smckusick continue; 47512453Smckusick } 47611127Smckusick return (dp); 47711127Smckusick } 47811127Smckusick } 47911127Smckusick 48011127Smckusick /* 48117753Smckusick * Simulate the opening of a directory 48217753Smckusick */ 48350657Smckusick RST_DIR * 48417753Smckusick rst_opendir(name) 48557896Sbostic const char *name; 48617753Smckusick { 48717753Smckusick struct inotab *itp; 48856946Smckusick RST_DIR *dirp; 48917753Smckusick ino_t ino; 49017753Smckusick 49117753Smckusick if ((ino = dirlookup(name)) > 0 && 49217753Smckusick (itp = inotablookup(ino)) != NULL) { 49356946Smckusick dirp = opendirfile(dirfile); 49417753Smckusick rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 49517753Smckusick return (dirp); 49617753Smckusick } 49757930Sbostic return (NULL); 49817753Smckusick } 49917753Smckusick 50017753Smckusick /* 50156946Smckusick * In our case, there is nothing to do when closing a directory. 50256946Smckusick */ 50356946Smckusick void 50456946Smckusick rst_closedir(dirp) 50556946Smckusick RST_DIR *dirp; 50656946Smckusick { 50756946Smckusick 50857896Sbostic (void)close(dirp->dd_fd); 50956946Smckusick free(dirp); 51056946Smckusick return; 51156946Smckusick } 51256946Smckusick 51356946Smckusick /* 51440064Smckusick * Simulate finding the current offset in the directory. 51540064Smckusick */ 51656567Sbostic static long 51740064Smckusick rst_telldir(dirp) 51850657Smckusick RST_DIR *dirp; 51940064Smckusick { 52056567Sbostic return ((long)lseek(dirp->dd_fd, 52156567Sbostic (off_t)0, SEEK_CUR) - dirp->dd_size + dirp->dd_loc); 52240064Smckusick } 52340064Smckusick 52440064Smckusick /* 52540064Smckusick * Open a directory file. 52640064Smckusick */ 52756567Sbostic static RST_DIR * 52840064Smckusick opendirfile(name) 52957896Sbostic const char *name; 53040064Smckusick { 53150657Smckusick register RST_DIR *dirp; 53240064Smckusick register int fd; 53340064Smckusick 53456567Sbostic if ((fd = open(name, O_RDONLY)) == -1) 53556567Sbostic return (NULL); 53656567Sbostic if ((dirp = malloc(sizeof(RST_DIR))) == NULL) { 53756567Sbostic (void)close(fd); 53856567Sbostic return (NULL); 53940064Smckusick } 54040064Smckusick dirp->dd_fd = fd; 54140064Smckusick dirp->dd_loc = 0; 54256567Sbostic return (dirp); 54340064Smckusick } 54440064Smckusick 54540064Smckusick /* 54611127Smckusick * Set the mode, owner, and times for all new or changed directories 54711127Smckusick */ 54856567Sbostic void 54955880Smckusick setdirmodes(flags) 55055880Smckusick int flags; 55111127Smckusick { 55211127Smckusick FILE *mf; 55311127Smckusick struct modeinfo node; 55411127Smckusick struct entry *ep; 55511127Smckusick char *cp; 55611127Smckusick 55711127Smckusick vprintf(stdout, "Set directory mode, owner, and times.\n"); 55837952Sbostic (void) sprintf(modefile, "%s/rstmode%d", _PATH_TMP, dumpdate); 55911127Smckusick mf = fopen(modefile, "r"); 56011127Smckusick if (mf == NULL) { 56156567Sbostic fprintf(stderr, "fopen: %s\n", strerror(errno)); 56215779Smckusick fprintf(stderr, "cannot open mode file %s\n", modefile); 56315779Smckusick fprintf(stderr, "directory mode, owner, and times not set\n"); 56415779Smckusick return; 56511127Smckusick } 56611127Smckusick clearerr(mf); 56711309Smckusick for (;;) { 56811732Smckusick (void) fread((char *)&node, 1, sizeof(struct modeinfo), mf); 56911309Smckusick if (feof(mf)) 57011309Smckusick break; 57111127Smckusick ep = lookupino(node.ino); 57214453Smckusick if (command == 'i' || command == 'x') { 57356567Sbostic if (ep == NULL) 57411309Smckusick continue; 57555880Smckusick if ((flags & FORCE) == 0 && ep->e_flags & EXISTED) { 57618008Smckusick ep->e_flags &= ~NEW; 57718008Smckusick continue; 57818008Smckusick } 57914453Smckusick if (node.ino == ROOTINO && 58014453Smckusick reply("set owner/mode for '.'") == FAIL) 58114453Smckusick continue; 58214453Smckusick } 58356567Sbostic if (ep == NULL) { 58411127Smckusick panic("cannot find directory inode %d\n", node.ino); 58542862Smckusick } else { 58642862Smckusick cp = myname(ep); 58742862Smckusick (void) chown(cp, node.uid, node.gid); 58842862Smckusick (void) chmod(cp, node.mode); 58942862Smckusick utimes(cp, node.timep); 59042862Smckusick ep->e_flags &= ~NEW; 59142862Smckusick } 59211127Smckusick } 59311127Smckusick if (ferror(mf)) 59411127Smckusick panic("error setting directory modes\n"); 59511732Smckusick (void) fclose(mf); 59611127Smckusick } 59711127Smckusick 59811127Smckusick /* 59911127Smckusick * Generate a literal copy of a directory. 60011127Smckusick */ 60156567Sbostic int 60211127Smckusick genliteraldir(name, ino) 60311127Smckusick char *name; 60411127Smckusick ino_t ino; 60511127Smckusick { 60611127Smckusick register struct inotab *itp; 60711127Smckusick int ofile, dp, i, size; 60811127Smckusick char buf[BUFSIZ]; 60911127Smckusick 61011127Smckusick itp = inotablookup(ino); 61111127Smckusick if (itp == NULL) 61211322Smckusick panic("Cannot find directory inode %d named %s\n", ino, name); 61312893Ssam if ((ofile = creat(name, 0666)) < 0) { 61412556Smckusick fprintf(stderr, "%s: ", name); 61512556Smckusick (void) fflush(stderr); 61656567Sbostic fprintf(stderr, "cannot create file: %s\n", strerror(errno)); 61711127Smckusick return (FAIL); 61811127Smckusick } 61912556Smckusick rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt); 62011127Smckusick dp = dup(dirp->dd_fd); 62111127Smckusick for (i = itp->t_size; i > 0; i -= BUFSIZ) { 62211127Smckusick size = i < BUFSIZ ? i : BUFSIZ; 62311127Smckusick if (read(dp, buf, (int) size) == -1) { 62411127Smckusick fprintf(stderr, 62511127Smckusick "write error extracting inode %d, name %s\n", 62611127Smckusick curfile.ino, curfile.name); 62756567Sbostic fprintf(stderr, "read: %s\n", strerror(errno)); 62811127Smckusick done(1); 62911127Smckusick } 63034268Smckusick if (!Nflag && write(ofile, buf, (int) size) == -1) { 63111127Smckusick fprintf(stderr, 63211127Smckusick "write error extracting inode %d, name %s\n", 63311127Smckusick curfile.ino, curfile.name); 63456567Sbostic fprintf(stderr, "write: %s\n", strerror(errno)); 63511127Smckusick done(1); 63611127Smckusick } 63711127Smckusick } 63811732Smckusick (void) close(dp); 63911732Smckusick (void) close(ofile); 64011127Smckusick return (GOOD); 64111127Smckusick } 64211127Smckusick 64311127Smckusick /* 64411992Smckusick * Determine the type of an inode 64511992Smckusick */ 64656567Sbostic int 64711992Smckusick inodetype(ino) 64811992Smckusick ino_t ino; 64911992Smckusick { 65011992Smckusick struct inotab *itp; 65111992Smckusick 65211992Smckusick itp = inotablookup(ino); 65311992Smckusick if (itp == NULL) 65411992Smckusick return (LEAF); 65511992Smckusick return (NODE); 65611992Smckusick } 65711992Smckusick 65811992Smckusick /* 65911127Smckusick * Allocate and initialize a directory inode entry. 66011127Smckusick * If requested, save its pertinent mode, owner, and time info. 66111127Smckusick */ 66256567Sbostic static struct inotab * 66311127Smckusick allocinotab(ino, dip, seekpt) 66411127Smckusick ino_t ino; 66511127Smckusick struct dinode *dip; 66650662Smckusick long seekpt; 66711127Smckusick { 66811127Smckusick register struct inotab *itp; 66911127Smckusick struct modeinfo node; 67011127Smckusick 67156567Sbostic itp = calloc(1, sizeof(struct inotab)); 67256567Sbostic if (itp == NULL) 67313859Smckusick panic("no memory directory table\n"); 67411127Smckusick itp->t_next = inotab[INOHASH(ino)]; 67511127Smckusick inotab[INOHASH(ino)] = itp; 67611127Smckusick itp->t_ino = ino; 67711127Smckusick itp->t_seekpt = seekpt; 67811127Smckusick if (mf == NULL) 67957930Sbostic return (itp); 68011127Smckusick node.ino = ino; 68154156Smckusick node.timep[0].tv_sec = dip->di_atime.ts_sec; 68254156Smckusick node.timep[0].tv_usec = dip->di_atime.ts_nsec / 1000; 68354156Smckusick node.timep[1].tv_sec = dip->di_mtime.ts_sec; 68454156Smckusick node.timep[1].tv_usec = dip->di_mtime.ts_nsec / 1000; 68511127Smckusick node.mode = dip->di_mode; 68611127Smckusick node.uid = dip->di_uid; 68711127Smckusick node.gid = dip->di_gid; 68811732Smckusick (void) fwrite((char *)&node, 1, sizeof(struct modeinfo), mf); 68957930Sbostic return (itp); 69011127Smckusick } 69111127Smckusick 69211127Smckusick /* 69311127Smckusick * Look up an inode in the table of directories 69411127Smckusick */ 69556567Sbostic static struct inotab * 69611127Smckusick inotablookup(ino) 69711127Smckusick ino_t ino; 69811127Smckusick { 69911127Smckusick register struct inotab *itp; 70011127Smckusick 70111127Smckusick for (itp = inotab[INOHASH(ino)]; itp != NULL; itp = itp->t_next) 70211127Smckusick if (itp->t_ino == ino) 70357930Sbostic return (itp); 70456567Sbostic return (NULL); 70511127Smckusick } 70611127Smckusick 70711127Smckusick /* 70811127Smckusick * Clean up and exit 70911127Smckusick */ 71057930Sbostic __dead void 71111127Smckusick done(exitcode) 71211127Smckusick int exitcode; 71311127Smckusick { 71411127Smckusick 71511127Smckusick closemt(); 71611992Smckusick if (modefile[0] != '#') 71711992Smckusick (void) unlink(modefile); 71811992Smckusick if (dirfile[0] != '#') 71911992Smckusick (void) unlink(dirfile); 72011127Smckusick exit(exitcode); 72111127Smckusick } 722