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