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