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