Home | History | Annotate | Line # | Download | only in restore
dirs.c revision 1.9
      1  1.6      cgd /*
      2  1.7  mycroft  * Copyright (c) 1983, 1993
      3  1.7  mycroft  *	The Regents of the University of California.  All rights reserved.
      4  1.6      cgd  * (c) UNIX System Laboratories, Inc.
      5  1.6      cgd  * All or some portions of this file are derived from material licensed
      6  1.6      cgd  * to the University of California by American Telephone and Telegraph
      7  1.6      cgd  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
      8  1.6      cgd  * the permission of UNIX System Laboratories, Inc.
      9  1.6      cgd  *
     10  1.6      cgd  * Redistribution and use in source and binary forms, with or without
     11  1.6      cgd  * modification, are permitted provided that the following conditions
     12  1.6      cgd  * are met:
     13  1.6      cgd  * 1. Redistributions of source code must retain the above copyright
     14  1.6      cgd  *    notice, this list of conditions and the following disclaimer.
     15  1.6      cgd  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.6      cgd  *    notice, this list of conditions and the following disclaimer in the
     17  1.6      cgd  *    documentation and/or other materials provided with the distribution.
     18  1.6      cgd  * 3. All advertising materials mentioning features or use of this software
     19  1.6      cgd  *    must display the following acknowledgement:
     20  1.6      cgd  *	This product includes software developed by the University of
     21  1.6      cgd  *	California, Berkeley and its contributors.
     22  1.6      cgd  * 4. Neither the name of the University nor the names of its contributors
     23  1.6      cgd  *    may be used to endorse or promote products derived from this software
     24  1.6      cgd  *    without specific prior written permission.
     25  1.6      cgd  *
     26  1.6      cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     27  1.6      cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     28  1.6      cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     29  1.6      cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     30  1.6      cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     31  1.6      cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     32  1.6      cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     33  1.6      cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     34  1.6      cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     35  1.6      cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     36  1.6      cgd  * SUCH DAMAGE.
     37  1.6      cgd  */
     38  1.6      cgd 
     39  1.6      cgd #ifndef lint
     40  1.7  mycroft /*static char sccsid[] = "from: @(#)dirs.c	8.2 (Berkeley) 1/21/94";*/
     41  1.9  mycroft static char *rcsid = "$Id: dirs.c,v 1.9 1994/06/18 18:20:46 mycroft Exp $";
     42  1.6      cgd #endif /* not lint */
     43  1.6      cgd 
     44  1.6      cgd #include <sys/param.h>
     45  1.6      cgd #include <sys/file.h>
     46  1.6      cgd #include <sys/stat.h>
     47  1.6      cgd #include <sys/time.h>
     48  1.6      cgd 
     49  1.7  mycroft #include <ufs/ffs/fs.h>
     50  1.7  mycroft #include <ufs/ufs/dinode.h>
     51  1.7  mycroft #include <ufs/ufs/dir.h>
     52  1.6      cgd #include <protocols/dumprestore.h>
     53  1.6      cgd 
     54  1.6      cgd #include <errno.h>
     55  1.6      cgd #include <stdio.h>
     56  1.6      cgd #include <stdlib.h>
     57  1.6      cgd #include <string.h>
     58  1.6      cgd #include <unistd.h>
     59  1.6      cgd 
     60  1.8  mycroft #include <machine/endian.h>
     61  1.8  mycroft 
     62  1.6      cgd #include "pathnames.h"
     63  1.6      cgd #include "restore.h"
     64  1.6      cgd #include "extern.h"
     65  1.6      cgd 
     66  1.6      cgd /*
     67  1.6      cgd  * Symbol table of directories read from tape.
     68  1.6      cgd  */
     69  1.6      cgd #define HASHSIZE	1000
     70  1.6      cgd #define INOHASH(val) (val % HASHSIZE)
     71  1.6      cgd struct inotab {
     72  1.6      cgd 	struct	inotab *t_next;
     73  1.6      cgd 	ino_t	t_ino;
     74  1.6      cgd 	long	t_seekpt;
     75  1.6      cgd 	long	t_size;
     76  1.6      cgd };
     77  1.6      cgd static struct inotab *inotab[HASHSIZE];
     78  1.6      cgd 
     79  1.6      cgd /*
     80  1.6      cgd  * Information retained about directories.
     81  1.6      cgd  */
     82  1.6      cgd struct modeinfo {
     83  1.6      cgd 	ino_t ino;
     84  1.6      cgd 	struct timeval timep[2];
     85  1.6      cgd 	short mode;
     86  1.6      cgd 	short uid;
     87  1.6      cgd 	short gid;
     88  1.6      cgd };
     89  1.6      cgd 
     90  1.6      cgd /*
     91  1.6      cgd  * Definitions for library routines operating on directories.
     92  1.6      cgd  */
     93  1.6      cgd #undef DIRBLKSIZ
     94  1.6      cgd #define DIRBLKSIZ 1024
     95  1.6      cgd struct rstdirdesc {
     96  1.6      cgd 	int	dd_fd;
     97  1.6      cgd 	long	dd_loc;
     98  1.6      cgd 	long	dd_size;
     99  1.6      cgd 	char	dd_buf[DIRBLKSIZ];
    100  1.6      cgd };
    101  1.6      cgd 
    102  1.6      cgd /*
    103  1.6      cgd  * Global variables for this file.
    104  1.6      cgd  */
    105  1.6      cgd static long	seekpt;
    106  1.6      cgd static FILE	*df, *mf;
    107  1.6      cgd static RST_DIR	*dirp;
    108  1.6      cgd static char	dirfile[32] = "#";	/* No file */
    109  1.6      cgd static char	modefile[32] = "#";	/* No file */
    110  1.6      cgd static char	dot[2] = ".";		/* So it can be modified */
    111  1.6      cgd 
    112  1.6      cgd /*
    113  1.6      cgd  * Format of old style directories.
    114  1.6      cgd  */
    115  1.6      cgd #define ODIRSIZ 14
    116  1.6      cgd struct odirect {
    117  1.6      cgd 	u_short	d_ino;
    118  1.6      cgd 	char	d_name[ODIRSIZ];
    119  1.6      cgd };
    120  1.6      cgd 
    121  1.6      cgd static struct inotab	*allocinotab __P((ino_t, struct dinode *, long));
    122  1.6      cgd static void		 dcvt __P((struct odirect *, struct direct *));
    123  1.6      cgd static void		 flushent __P((void));
    124  1.6      cgd static struct inotab	*inotablookup __P((ino_t));
    125  1.7  mycroft static RST_DIR		*opendirfile __P((const char *));
    126  1.6      cgd static void		 putdir __P((char *, long));
    127  1.6      cgd static void		 putent __P((struct direct *));
    128  1.6      cgd static void		 rst_seekdir __P((RST_DIR *, long, long));
    129  1.6      cgd static long		 rst_telldir __P((RST_DIR *));
    130  1.6      cgd static struct direct	*searchdir __P((ino_t, char *));
    131  1.6      cgd 
    132  1.6      cgd /*
    133  1.6      cgd  *	Extract directory contents, building up a directory structure
    134  1.6      cgd  *	on disk for extraction by name.
    135  1.6      cgd  *	If genmode is requested, save mode, owner, and times for all
    136  1.6      cgd  *	directories on the tape.
    137  1.6      cgd  */
    138  1.6      cgd void
    139  1.6      cgd extractdirs(genmode)
    140  1.6      cgd 	int genmode;
    141  1.6      cgd {
    142  1.6      cgd 	register int i;
    143  1.6      cgd 	register struct dinode *ip;
    144  1.6      cgd 	struct inotab *itp;
    145  1.6      cgd 	struct direct nulldir;
    146  1.6      cgd 
    147  1.6      cgd 	vprintf(stdout, "Extract directories from tape\n");
    148  1.6      cgd 	(void) sprintf(dirfile, "%s/rstdir%d", _PATH_TMP, dumpdate);
    149  1.6      cgd 	df = fopen(dirfile, "w");
    150  1.7  mycroft 	if (df == NULL) {
    151  1.6      cgd 		fprintf(stderr,
    152  1.6      cgd 		    "restore: %s - cannot create directory temporary\n",
    153  1.6      cgd 		    dirfile);
    154  1.6      cgd 		fprintf(stderr, "fopen: %s\n", strerror(errno));
    155  1.6      cgd 		done(1);
    156  1.6      cgd 	}
    157  1.6      cgd 	if (genmode != 0) {
    158  1.6      cgd 		(void) sprintf(modefile, "%s/rstmode%d", _PATH_TMP, dumpdate);
    159  1.6      cgd 		mf = fopen(modefile, "w");
    160  1.7  mycroft 		if (mf == NULL) {
    161  1.6      cgd 			fprintf(stderr,
    162  1.6      cgd 			    "restore: %s - cannot create modefile \n",
    163  1.6      cgd 			    modefile);
    164  1.6      cgd 			fprintf(stderr, "fopen: %s\n", strerror(errno));
    165  1.6      cgd 			done(1);
    166  1.6      cgd 		}
    167  1.6      cgd 	}
    168  1.6      cgd 	nulldir.d_ino = 0;
    169  1.6      cgd 	nulldir.d_type = DT_DIR;
    170  1.6      cgd 	nulldir.d_namlen = 1;
    171  1.6      cgd 	(void) strcpy(nulldir.d_name, "/");
    172  1.6      cgd 	nulldir.d_reclen = DIRSIZ(0, &nulldir);
    173  1.6      cgd 	for (;;) {
    174  1.6      cgd 		curfile.name = "<directory file - name unknown>";
    175  1.6      cgd 		curfile.action = USING;
    176  1.6      cgd 		ip = curfile.dip;
    177  1.6      cgd 		if (ip == NULL || (ip->di_mode & IFMT) != IFDIR) {
    178  1.6      cgd 			(void) fclose(df);
    179  1.6      cgd 			dirp = opendirfile(dirfile);
    180  1.6      cgd 			if (dirp == NULL)
    181  1.6      cgd 				fprintf(stderr, "opendirfile: %s\n",
    182  1.6      cgd 				    strerror(errno));
    183  1.6      cgd 			if (mf != NULL)
    184  1.6      cgd 				(void) fclose(mf);
    185  1.6      cgd 			i = dirlookup(dot);
    186  1.6      cgd 			if (i == 0)
    187  1.6      cgd 				panic("Root directory is not on tape\n");
    188  1.6      cgd 			return;
    189  1.6      cgd 		}
    190  1.6      cgd 		itp = allocinotab(curfile.ino, ip, seekpt);
    191  1.6      cgd 		getfile(putdir, xtrnull);
    192  1.6      cgd 		putent(&nulldir);
    193  1.6      cgd 		flushent();
    194  1.6      cgd 		itp->t_size = seekpt - itp->t_seekpt;
    195  1.6      cgd 	}
    196  1.6      cgd }
    197  1.6      cgd 
    198  1.6      cgd /*
    199  1.6      cgd  * skip over all the directories on the tape
    200  1.6      cgd  */
    201  1.6      cgd void
    202  1.6      cgd skipdirs()
    203  1.6      cgd {
    204  1.6      cgd 
    205  1.6      cgd 	while ((curfile.dip->di_mode & IFMT) == IFDIR) {
    206  1.6      cgd 		skipfile();
    207  1.6      cgd 	}
    208  1.6      cgd }
    209  1.6      cgd 
    210  1.6      cgd /*
    211  1.6      cgd  *	Recursively find names and inumbers of all files in subtree
    212  1.6      cgd  *	pname and pass them off to be processed.
    213  1.6      cgd  */
    214  1.6      cgd void
    215  1.6      cgd treescan(pname, ino, todo)
    216  1.6      cgd 	char *pname;
    217  1.6      cgd 	ino_t ino;
    218  1.6      cgd 	long (*todo) __P((char *, ino_t, int));
    219  1.6      cgd {
    220  1.6      cgd 	register struct inotab *itp;
    221  1.6      cgd 	register struct direct *dp;
    222  1.6      cgd 	int namelen;
    223  1.6      cgd 	long bpt;
    224  1.6      cgd 	char locname[MAXPATHLEN + 1];
    225  1.6      cgd 
    226  1.6      cgd 	itp = inotablookup(ino);
    227  1.6      cgd 	if (itp == NULL) {
    228  1.6      cgd 		/*
    229  1.6      cgd 		 * Pname is name of a simple file or an unchanged directory.
    230  1.6      cgd 		 */
    231  1.6      cgd 		(void) (*todo)(pname, ino, LEAF);
    232  1.6      cgd 		return;
    233  1.6      cgd 	}
    234  1.6      cgd 	/*
    235  1.6      cgd 	 * Pname is a dumped directory name.
    236  1.6      cgd 	 */
    237  1.6      cgd 	if ((*todo)(pname, ino, NODE) == FAIL)
    238  1.6      cgd 		return;
    239  1.6      cgd 	/*
    240  1.6      cgd 	 * begin search through the directory
    241  1.6      cgd 	 * skipping over "." and ".."
    242  1.6      cgd 	 */
    243  1.6      cgd 	(void) strncpy(locname, pname, MAXPATHLEN);
    244  1.6      cgd 	(void) strncat(locname, "/", MAXPATHLEN);
    245  1.6      cgd 	namelen = strlen(locname);
    246  1.6      cgd 	rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
    247  1.6      cgd 	dp = rst_readdir(dirp); /* "." */
    248  1.6      cgd 	if (dp != NULL && strcmp(dp->d_name, ".") == 0)
    249  1.6      cgd 		dp = rst_readdir(dirp); /* ".." */
    250  1.6      cgd 	else
    251  1.6      cgd 		fprintf(stderr, "Warning: `.' missing from directory %s\n",
    252  1.6      cgd 			pname);
    253  1.6      cgd 	if (dp != NULL && strcmp(dp->d_name, "..") == 0)
    254  1.6      cgd 		dp = rst_readdir(dirp); /* first real entry */
    255  1.6      cgd 	else
    256  1.6      cgd 		fprintf(stderr, "Warning: `..' missing from directory %s\n",
    257  1.6      cgd 			pname);
    258  1.6      cgd 	bpt = rst_telldir(dirp);
    259  1.6      cgd 	/*
    260  1.6      cgd 	 * a zero inode signals end of directory
    261  1.6      cgd 	 */
    262  1.6      cgd 	while (dp != NULL && dp->d_ino != 0) {
    263  1.6      cgd 		locname[namelen] = '\0';
    264  1.6      cgd 		if (namelen + dp->d_namlen >= MAXPATHLEN) {
    265  1.6      cgd 			fprintf(stderr, "%s%s: name exceeds %d char\n",
    266  1.6      cgd 				locname, dp->d_name, MAXPATHLEN);
    267  1.6      cgd 		} else {
    268  1.6      cgd 			(void) strncat(locname, dp->d_name, (int)dp->d_namlen);
    269  1.6      cgd 			treescan(locname, dp->d_ino, todo);
    270  1.6      cgd 			rst_seekdir(dirp, bpt, itp->t_seekpt);
    271  1.6      cgd 		}
    272  1.6      cgd 		dp = rst_readdir(dirp);
    273  1.6      cgd 		bpt = rst_telldir(dirp);
    274  1.6      cgd 	}
    275  1.6      cgd 	if (dp == NULL)
    276  1.6      cgd 		fprintf(stderr, "corrupted directory: %s.\n", locname);
    277  1.6      cgd }
    278  1.6      cgd 
    279  1.6      cgd /*
    280  1.6      cgd  * Lookup a pathname which is always assumed to start from the ROOTINO.
    281  1.6      cgd  */
    282  1.6      cgd struct direct *
    283  1.6      cgd pathsearch(pathname)
    284  1.6      cgd 	const char *pathname;
    285  1.6      cgd {
    286  1.6      cgd 	ino_t ino;
    287  1.6      cgd 	struct direct *dp;
    288  1.6      cgd 	char *path, *name, buffer[MAXPATHLEN];
    289  1.6      cgd 
    290  1.6      cgd 	strcpy(buffer, pathname);
    291  1.6      cgd 	path = buffer;
    292  1.6      cgd 	ino = ROOTINO;
    293  1.6      cgd 	while (*path == '/')
    294  1.6      cgd 		path++;
    295  1.7  mycroft 	dp = NULL;
    296  1.6      cgd 	while ((name = strsep(&path, "/")) != NULL && *name != NULL) {
    297  1.7  mycroft 		if ((dp = searchdir(ino, name)) == NULL)
    298  1.6      cgd 			return (NULL);
    299  1.6      cgd 		ino = dp->d_ino;
    300  1.6      cgd 	}
    301  1.6      cgd 	return (dp);
    302  1.6      cgd }
    303  1.6      cgd 
    304  1.6      cgd /*
    305  1.6      cgd  * Lookup the requested name in directory inum.
    306  1.6      cgd  * Return its inode number if found, zero if it does not exist.
    307  1.6      cgd  */
    308  1.6      cgd static struct direct *
    309  1.6      cgd searchdir(inum, name)
    310  1.6      cgd 	ino_t	inum;
    311  1.6      cgd 	char	*name;
    312  1.6      cgd {
    313  1.6      cgd 	register struct direct *dp;
    314  1.6      cgd 	register struct inotab *itp;
    315  1.6      cgd 	int len;
    316  1.6      cgd 
    317  1.6      cgd 	itp = inotablookup(inum);
    318  1.6      cgd 	if (itp == NULL)
    319  1.7  mycroft 		return (NULL);
    320  1.6      cgd 	rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
    321  1.6      cgd 	len = strlen(name);
    322  1.6      cgd 	do {
    323  1.6      cgd 		dp = rst_readdir(dirp);
    324  1.6      cgd 		if (dp == NULL || dp->d_ino == 0)
    325  1.6      cgd 			return (NULL);
    326  1.6      cgd 	} while (dp->d_namlen != len || strncmp(dp->d_name, name, len) != 0);
    327  1.6      cgd 	return (dp);
    328  1.6      cgd }
    329  1.6      cgd 
    330  1.6      cgd /*
    331  1.6      cgd  * Put the directory entries in the directory file
    332  1.6      cgd  */
    333  1.6      cgd static void
    334  1.6      cgd putdir(buf, size)
    335  1.6      cgd 	char *buf;
    336  1.6      cgd 	long size;
    337  1.6      cgd {
    338  1.6      cgd 	struct direct cvtbuf;
    339  1.6      cgd 	register struct odirect *odp;
    340  1.6      cgd 	struct odirect *eodp;
    341  1.6      cgd 	register struct direct *dp;
    342  1.6      cgd 	long loc, i;
    343  1.6      cgd 
    344  1.6      cgd 	if (cvtflag) {
    345  1.6      cgd 		eodp = (struct odirect *)&buf[size];
    346  1.6      cgd 		for (odp = (struct odirect *)buf; odp < eodp; odp++)
    347  1.6      cgd 			if (odp->d_ino != 0) {
    348  1.6      cgd 				dcvt(odp, &cvtbuf);
    349  1.6      cgd 				putent(&cvtbuf);
    350  1.6      cgd 			}
    351  1.6      cgd 	} else {
    352  1.6      cgd 		for (loc = 0; loc < size; ) {
    353  1.6      cgd 			dp = (struct direct *)(buf + loc);
    354  1.9  mycroft 			if (Bcvt)
    355  1.9  mycroft 				swabst((u_char *)"ls", (u_char *) dp);
    356  1.9  mycroft 			if (oldinofmt && dp->d_ino != 0) {
    357  1.8  mycroft #if BYTE_ORDER == BIG_ENDIAN
    358  1.9  mycroft 				if (Bcvt)
    359  1.8  mycroft #else
    360  1.9  mycroft 				if (!Bcvt)
    361  1.8  mycroft #endif
    362  1.9  mycroft 					dp->d_namlen = dp->d_type;
    363  1.9  mycroft 				dp->d_type = DT_UNKNOWN;
    364  1.6      cgd 			}
    365  1.6      cgd 			i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1));
    366  1.6      cgd 			if ((dp->d_reclen & 0x3) != 0 ||
    367  1.6      cgd 			    dp->d_reclen > i ||
    368  1.6      cgd 			    dp->d_reclen < DIRSIZ(0, dp) ||
    369  1.6      cgd 			    dp->d_namlen > NAME_MAX) {
    370  1.6      cgd 				vprintf(stdout, "Mangled directory: ");
    371  1.6      cgd 				if ((dp->d_reclen & 0x3) != 0)
    372  1.6      cgd 					vprintf(stdout,
    373  1.6      cgd 					   "reclen not multiple of 4 ");
    374  1.6      cgd 				if (dp->d_reclen < DIRSIZ(0, dp))
    375  1.6      cgd 					vprintf(stdout,
    376  1.6      cgd 					   "reclen less than DIRSIZ (%d < %d) ",
    377  1.6      cgd 					   dp->d_reclen, DIRSIZ(0, dp));
    378  1.6      cgd 				if (dp->d_namlen > NAME_MAX)
    379  1.6      cgd 					vprintf(stdout,
    380  1.6      cgd 					   "reclen name too big (%d > %d) ",
    381  1.6      cgd 					   dp->d_namlen, NAME_MAX);
    382  1.6      cgd 				vprintf(stdout, "\n");
    383  1.6      cgd 				loc += i;
    384  1.6      cgd 				continue;
    385  1.6      cgd 			}
    386  1.6      cgd 			loc += dp->d_reclen;
    387  1.6      cgd 			if (dp->d_ino != 0) {
    388  1.6      cgd 				putent(dp);
    389  1.6      cgd 			}
    390  1.6      cgd 		}
    391  1.6      cgd 	}
    392  1.6      cgd }
    393  1.6      cgd 
    394  1.6      cgd /*
    395  1.6      cgd  * These variables are "local" to the following two functions.
    396  1.6      cgd  */
    397  1.6      cgd char dirbuf[DIRBLKSIZ];
    398  1.6      cgd long dirloc = 0;
    399  1.6      cgd long prev = 0;
    400  1.6      cgd 
    401  1.6      cgd /*
    402  1.6      cgd  * add a new directory entry to a file.
    403  1.6      cgd  */
    404  1.6      cgd static void
    405  1.6      cgd putent(dp)
    406  1.6      cgd 	struct direct *dp;
    407  1.6      cgd {
    408  1.6      cgd 	dp->d_reclen = DIRSIZ(0, dp);
    409  1.6      cgd 	if (dirloc + dp->d_reclen > DIRBLKSIZ) {
    410  1.6      cgd 		((struct direct *)(dirbuf + prev))->d_reclen =
    411  1.6      cgd 		    DIRBLKSIZ - prev;
    412  1.6      cgd 		(void) fwrite(dirbuf, 1, DIRBLKSIZ, df);
    413  1.6      cgd 		dirloc = 0;
    414  1.6      cgd 	}
    415  1.6      cgd 	bcopy((char *)dp, dirbuf + dirloc, (long)dp->d_reclen);
    416  1.6      cgd 	prev = dirloc;
    417  1.6      cgd 	dirloc += dp->d_reclen;
    418  1.6      cgd }
    419  1.6      cgd 
    420  1.6      cgd /*
    421  1.6      cgd  * flush out a directory that is finished.
    422  1.6      cgd  */
    423  1.6      cgd static void
    424  1.6      cgd flushent()
    425  1.6      cgd {
    426  1.6      cgd 	((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev;
    427  1.6      cgd 	(void) fwrite(dirbuf, (int)dirloc, 1, df);
    428  1.6      cgd 	seekpt = ftell(df);
    429  1.6      cgd 	dirloc = 0;
    430  1.6      cgd }
    431  1.6      cgd 
    432  1.6      cgd static void
    433  1.6      cgd dcvt(odp, ndp)
    434  1.6      cgd 	register struct odirect *odp;
    435  1.6      cgd 	register struct direct *ndp;
    436  1.6      cgd {
    437  1.6      cgd 
    438  1.6      cgd 	bzero((char *)ndp, (long)(sizeof *ndp));
    439  1.6      cgd 	ndp->d_ino =  odp->d_ino;
    440  1.6      cgd 	ndp->d_type = DT_UNKNOWN;
    441  1.6      cgd 	(void) strncpy(ndp->d_name, odp->d_name, ODIRSIZ);
    442  1.6      cgd 	ndp->d_namlen = strlen(ndp->d_name);
    443  1.6      cgd 	ndp->d_reclen = DIRSIZ(0, ndp);
    444  1.6      cgd }
    445  1.6      cgd 
    446  1.6      cgd /*
    447  1.6      cgd  * Seek to an entry in a directory.
    448  1.6      cgd  * Only values returned by rst_telldir should be passed to rst_seekdir.
    449  1.6      cgd  * This routine handles many directories in a single file.
    450  1.6      cgd  * It takes the base of the directory in the file, plus
    451  1.6      cgd  * the desired seek offset into it.
    452  1.6      cgd  */
    453  1.6      cgd static void
    454  1.6      cgd rst_seekdir(dirp, loc, base)
    455  1.6      cgd 	register RST_DIR *dirp;
    456  1.6      cgd 	long loc, base;
    457  1.6      cgd {
    458  1.6      cgd 
    459  1.6      cgd 	if (loc == rst_telldir(dirp))
    460  1.6      cgd 		return;
    461  1.6      cgd 	loc -= base;
    462  1.6      cgd 	if (loc < 0)
    463  1.6      cgd 		fprintf(stderr, "bad seek pointer to rst_seekdir %d\n", loc);
    464  1.6      cgd 	(void) lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), SEEK_SET);
    465  1.6      cgd 	dirp->dd_loc = loc & (DIRBLKSIZ - 1);
    466  1.6      cgd 	if (dirp->dd_loc != 0)
    467  1.6      cgd 		dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ);
    468  1.6      cgd }
    469  1.6      cgd 
    470  1.6      cgd /*
    471  1.6      cgd  * get next entry in a directory.
    472  1.6      cgd  */
    473  1.6      cgd struct direct *
    474  1.6      cgd rst_readdir(dirp)
    475  1.6      cgd 	register RST_DIR *dirp;
    476  1.6      cgd {
    477  1.6      cgd 	register struct direct *dp;
    478  1.6      cgd 
    479  1.6      cgd 	for (;;) {
    480  1.6      cgd 		if (dirp->dd_loc == 0) {
    481  1.6      cgd 			dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf,
    482  1.6      cgd 			    DIRBLKSIZ);
    483  1.6      cgd 			if (dirp->dd_size <= 0) {
    484  1.6      cgd 				dprintf(stderr, "error reading directory\n");
    485  1.6      cgd 				return (NULL);
    486  1.6      cgd 			}
    487  1.6      cgd 		}
    488  1.6      cgd 		if (dirp->dd_loc >= dirp->dd_size) {
    489  1.6      cgd 			dirp->dd_loc = 0;
    490  1.6      cgd 			continue;
    491  1.6      cgd 		}
    492  1.6      cgd 		dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc);
    493  1.6      cgd 		if (dp->d_reclen == 0 ||
    494  1.6      cgd 		    dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc) {
    495  1.6      cgd 			dprintf(stderr, "corrupted directory: bad reclen %d\n",
    496  1.6      cgd 				dp->d_reclen);
    497  1.6      cgd 			return (NULL);
    498  1.6      cgd 		}
    499  1.6      cgd 		dirp->dd_loc += dp->d_reclen;
    500  1.6      cgd 		if (dp->d_ino == 0 && strcmp(dp->d_name, "/") != 0)
    501  1.6      cgd 			continue;
    502  1.6      cgd 		if (dp->d_ino >= maxino) {
    503  1.6      cgd 			dprintf(stderr, "corrupted directory: bad inum %d\n",
    504  1.6      cgd 				dp->d_ino);
    505  1.6      cgd 			continue;
    506  1.6      cgd 		}
    507  1.6      cgd 		return (dp);
    508  1.6      cgd 	}
    509  1.6      cgd }
    510  1.6      cgd 
    511  1.6      cgd /*
    512  1.6      cgd  * Simulate the opening of a directory
    513  1.6      cgd  */
    514  1.6      cgd RST_DIR *
    515  1.6      cgd rst_opendir(name)
    516  1.7  mycroft 	const char *name;
    517  1.6      cgd {
    518  1.6      cgd 	struct inotab *itp;
    519  1.6      cgd 	RST_DIR *dirp;
    520  1.6      cgd 	ino_t ino;
    521  1.6      cgd 
    522  1.6      cgd 	if ((ino = dirlookup(name)) > 0 &&
    523  1.6      cgd 	    (itp = inotablookup(ino)) != NULL) {
    524  1.6      cgd 		dirp = opendirfile(dirfile);
    525  1.6      cgd 		rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
    526  1.6      cgd 		return (dirp);
    527  1.6      cgd 	}
    528  1.7  mycroft 	return (NULL);
    529  1.6      cgd }
    530  1.6      cgd 
    531  1.6      cgd /*
    532  1.6      cgd  * In our case, there is nothing to do when closing a directory.
    533  1.6      cgd  */
    534  1.6      cgd void
    535  1.6      cgd rst_closedir(dirp)
    536  1.6      cgd 	RST_DIR *dirp;
    537  1.6      cgd {
    538  1.6      cgd 
    539  1.7  mycroft 	(void)close(dirp->dd_fd);
    540  1.6      cgd 	free(dirp);
    541  1.6      cgd 	return;
    542  1.6      cgd }
    543  1.6      cgd 
    544  1.6      cgd /*
    545  1.6      cgd  * Simulate finding the current offset in the directory.
    546  1.6      cgd  */
    547  1.6      cgd static long
    548  1.6      cgd rst_telldir(dirp)
    549  1.6      cgd 	RST_DIR *dirp;
    550  1.6      cgd {
    551  1.6      cgd 	return ((long)lseek(dirp->dd_fd,
    552  1.6      cgd 	    (off_t)0, SEEK_CUR) - dirp->dd_size + dirp->dd_loc);
    553  1.6      cgd }
    554  1.6      cgd 
    555  1.6      cgd /*
    556  1.6      cgd  * Open a directory file.
    557  1.6      cgd  */
    558  1.6      cgd static RST_DIR *
    559  1.6      cgd opendirfile(name)
    560  1.7  mycroft 	const char *name;
    561  1.6      cgd {
    562  1.6      cgd 	register RST_DIR *dirp;
    563  1.6      cgd 	register int fd;
    564  1.6      cgd 
    565  1.6      cgd 	if ((fd = open(name, O_RDONLY)) == -1)
    566  1.6      cgd 		return (NULL);
    567  1.6      cgd 	if ((dirp = malloc(sizeof(RST_DIR))) == NULL) {
    568  1.6      cgd 		(void)close(fd);
    569  1.6      cgd 		return (NULL);
    570  1.6      cgd 	}
    571  1.6      cgd 	dirp->dd_fd = fd;
    572  1.6      cgd 	dirp->dd_loc = 0;
    573  1.6      cgd 	return (dirp);
    574  1.6      cgd }
    575  1.6      cgd 
    576  1.6      cgd /*
    577  1.6      cgd  * Set the mode, owner, and times for all new or changed directories
    578  1.6      cgd  */
    579  1.6      cgd void
    580  1.6      cgd setdirmodes(flags)
    581  1.6      cgd 	int flags;
    582  1.6      cgd {
    583  1.6      cgd 	FILE *mf;
    584  1.6      cgd 	struct modeinfo node;
    585  1.6      cgd 	struct entry *ep;
    586  1.6      cgd 	char *cp;
    587  1.6      cgd 
    588  1.6      cgd 	vprintf(stdout, "Set directory mode, owner, and times.\n");
    589  1.6      cgd 	(void) sprintf(modefile, "%s/rstmode%d", _PATH_TMP, dumpdate);
    590  1.6      cgd 	mf = fopen(modefile, "r");
    591  1.6      cgd 	if (mf == NULL) {
    592  1.6      cgd 		fprintf(stderr, "fopen: %s\n", strerror(errno));
    593  1.6      cgd 		fprintf(stderr, "cannot open mode file %s\n", modefile);
    594  1.6      cgd 		fprintf(stderr, "directory mode, owner, and times not set\n");
    595  1.6      cgd 		return;
    596  1.6      cgd 	}
    597  1.6      cgd 	clearerr(mf);
    598  1.6      cgd 	for (;;) {
    599  1.6      cgd 		(void) fread((char *)&node, 1, sizeof(struct modeinfo), mf);
    600  1.6      cgd 		if (feof(mf))
    601  1.6      cgd 			break;
    602  1.6      cgd 		ep = lookupino(node.ino);
    603  1.6      cgd 		if (command == 'i' || command == 'x') {
    604  1.6      cgd 			if (ep == NULL)
    605  1.6      cgd 				continue;
    606  1.6      cgd 			if ((flags & FORCE) == 0 && ep->e_flags & EXISTED) {
    607  1.6      cgd 				ep->e_flags &= ~NEW;
    608  1.6      cgd 				continue;
    609  1.6      cgd 			}
    610  1.6      cgd 			if (node.ino == ROOTINO &&
    611  1.6      cgd 		   	    reply("set owner/mode for '.'") == FAIL)
    612  1.6      cgd 				continue;
    613  1.6      cgd 		}
    614  1.6      cgd 		if (ep == NULL) {
    615  1.6      cgd 			panic("cannot find directory inode %d\n", node.ino);
    616  1.6      cgd 		} else {
    617  1.6      cgd 			cp = myname(ep);
    618  1.6      cgd 			(void) chown(cp, node.uid, node.gid);
    619  1.6      cgd 			(void) chmod(cp, node.mode);
    620  1.6      cgd 			utimes(cp, node.timep);
    621  1.6      cgd 			ep->e_flags &= ~NEW;
    622  1.6      cgd 		}
    623  1.6      cgd 	}
    624  1.6      cgd 	if (ferror(mf))
    625  1.6      cgd 		panic("error setting directory modes\n");
    626  1.6      cgd 	(void) fclose(mf);
    627  1.6      cgd }
    628  1.6      cgd 
    629  1.6      cgd /*
    630  1.6      cgd  * Generate a literal copy of a directory.
    631  1.6      cgd  */
    632  1.6      cgd int
    633  1.6      cgd genliteraldir(name, ino)
    634  1.6      cgd 	char *name;
    635  1.6      cgd 	ino_t ino;
    636  1.6      cgd {
    637  1.6      cgd 	register struct inotab *itp;
    638  1.6      cgd 	int ofile, dp, i, size;
    639  1.6      cgd 	char buf[BUFSIZ];
    640  1.6      cgd 
    641  1.6      cgd 	itp = inotablookup(ino);
    642  1.6      cgd 	if (itp == NULL)
    643  1.6      cgd 		panic("Cannot find directory inode %d named %s\n", ino, name);
    644  1.6      cgd 	if ((ofile = creat(name, 0666)) < 0) {
    645  1.6      cgd 		fprintf(stderr, "%s: ", name);
    646  1.6      cgd 		(void) fflush(stderr);
    647  1.6      cgd 		fprintf(stderr, "cannot create file: %s\n", strerror(errno));
    648  1.6      cgd 		return (FAIL);
    649  1.6      cgd 	}
    650  1.6      cgd 	rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
    651  1.6      cgd 	dp = dup(dirp->dd_fd);
    652  1.6      cgd 	for (i = itp->t_size; i > 0; i -= BUFSIZ) {
    653  1.6      cgd 		size = i < BUFSIZ ? i : BUFSIZ;
    654  1.6      cgd 		if (read(dp, buf, (int) size) == -1) {
    655  1.6      cgd 			fprintf(stderr,
    656  1.6      cgd 				"write error extracting inode %d, name %s\n",
    657  1.6      cgd 				curfile.ino, curfile.name);
    658  1.6      cgd 			fprintf(stderr, "read: %s\n", strerror(errno));
    659  1.6      cgd 			done(1);
    660  1.6      cgd 		}
    661  1.6      cgd 		if (!Nflag && write(ofile, buf, (int) size) == -1) {
    662  1.6      cgd 			fprintf(stderr,
    663  1.6      cgd 				"write error extracting inode %d, name %s\n",
    664  1.6      cgd 				curfile.ino, curfile.name);
    665  1.6      cgd 			fprintf(stderr, "write: %s\n", strerror(errno));
    666  1.6      cgd 			done(1);
    667  1.6      cgd 		}
    668  1.6      cgd 	}
    669  1.6      cgd 	(void) close(dp);
    670  1.6      cgd 	(void) close(ofile);
    671  1.6      cgd 	return (GOOD);
    672  1.6      cgd }
    673  1.6      cgd 
    674  1.6      cgd /*
    675  1.6      cgd  * Determine the type of an inode
    676  1.6      cgd  */
    677  1.6      cgd int
    678  1.6      cgd inodetype(ino)
    679  1.6      cgd 	ino_t ino;
    680  1.6      cgd {
    681  1.6      cgd 	struct inotab *itp;
    682  1.6      cgd 
    683  1.6      cgd 	itp = inotablookup(ino);
    684  1.6      cgd 	if (itp == NULL)
    685  1.6      cgd 		return (LEAF);
    686  1.6      cgd 	return (NODE);
    687  1.6      cgd }
    688  1.6      cgd 
    689  1.6      cgd /*
    690  1.6      cgd  * Allocate and initialize a directory inode entry.
    691  1.6      cgd  * If requested, save its pertinent mode, owner, and time info.
    692  1.6      cgd  */
    693  1.6      cgd static struct inotab *
    694  1.6      cgd allocinotab(ino, dip, seekpt)
    695  1.6      cgd 	ino_t ino;
    696  1.6      cgd 	struct dinode *dip;
    697  1.6      cgd 	long seekpt;
    698  1.6      cgd {
    699  1.6      cgd 	register struct inotab	*itp;
    700  1.6      cgd 	struct modeinfo node;
    701  1.6      cgd 
    702  1.6      cgd 	itp = calloc(1, sizeof(struct inotab));
    703  1.6      cgd 	if (itp == NULL)
    704  1.6      cgd 		panic("no memory directory table\n");
    705  1.6      cgd 	itp->t_next = inotab[INOHASH(ino)];
    706  1.6      cgd 	inotab[INOHASH(ino)] = itp;
    707  1.6      cgd 	itp->t_ino = ino;
    708  1.6      cgd 	itp->t_seekpt = seekpt;
    709  1.6      cgd 	if (mf == NULL)
    710  1.7  mycroft 		return (itp);
    711  1.6      cgd 	node.ino = ino;
    712  1.6      cgd 	node.timep[0].tv_sec = dip->di_atime.ts_sec;
    713  1.6      cgd 	node.timep[0].tv_usec = dip->di_atime.ts_nsec / 1000;
    714  1.6      cgd 	node.timep[1].tv_sec = dip->di_mtime.ts_sec;
    715  1.6      cgd 	node.timep[1].tv_usec = dip->di_mtime.ts_nsec / 1000;
    716  1.6      cgd 	node.mode = dip->di_mode;
    717  1.6      cgd 	node.uid = dip->di_uid;
    718  1.6      cgd 	node.gid = dip->di_gid;
    719  1.6      cgd 	(void) fwrite((char *)&node, 1, sizeof(struct modeinfo), mf);
    720  1.7  mycroft 	return (itp);
    721  1.6      cgd }
    722  1.6      cgd 
    723  1.6      cgd /*
    724  1.6      cgd  * Look up an inode in the table of directories
    725  1.6      cgd  */
    726  1.6      cgd static struct inotab *
    727  1.6      cgd inotablookup(ino)
    728  1.6      cgd 	ino_t	ino;
    729  1.6      cgd {
    730  1.6      cgd 	register struct inotab *itp;
    731  1.6      cgd 
    732  1.6      cgd 	for (itp = inotab[INOHASH(ino)]; itp != NULL; itp = itp->t_next)
    733  1.6      cgd 		if (itp->t_ino == ino)
    734  1.7  mycroft 			return (itp);
    735  1.6      cgd 	return (NULL);
    736  1.6      cgd }
    737  1.6      cgd 
    738  1.6      cgd /*
    739  1.6      cgd  * Clean up and exit
    740  1.6      cgd  */
    741  1.7  mycroft __dead void
    742  1.6      cgd done(exitcode)
    743  1.6      cgd 	int exitcode;
    744  1.6      cgd {
    745  1.6      cgd 
    746  1.6      cgd 	closemt();
    747  1.6      cgd 	if (modefile[0] != '#')
    748  1.6      cgd 		(void) unlink(modefile);
    749  1.6      cgd 	if (dirfile[0] != '#')
    750  1.6      cgd 		(void) unlink(dirfile);
    751  1.6      cgd 	exit(exitcode);
    752  1.6      cgd }
    753