dirs.c revision 8871
1187706Sgonzo/*
2187706Sgonzo * Copyright (c) 1983, 1993
3187706Sgonzo *	The Regents of the University of California.  All rights reserved.
4187706Sgonzo * (c) UNIX System Laboratories, Inc.
5187706Sgonzo * All or some portions of this file are derived from material licensed
6187706Sgonzo * to the University of California by American Telephone and Telegraph
7187706Sgonzo * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8187706Sgonzo * the permission of UNIX System Laboratories, Inc.
9187706Sgonzo *
10187706Sgonzo * Redistribution and use in source and binary forms, with or without
11187706Sgonzo * modification, are permitted provided that the following conditions
12187706Sgonzo * are met:
13187706Sgonzo * 1. Redistributions of source code must retain the above copyright
14187706Sgonzo *    notice, this list of conditions and the following disclaimer.
15187706Sgonzo * 2. Redistributions in binary form must reproduce the above copyright
16187706Sgonzo *    notice, this list of conditions and the following disclaimer in the
17187706Sgonzo *    documentation and/or other materials provided with the distribution.
18187706Sgonzo * 3. All advertising materials mentioning features or use of this software
19187706Sgonzo *    must display the following acknowledgement:
20187706Sgonzo *	This product includes software developed by the University of
21187706Sgonzo *	California, Berkeley and its contributors.
22187706Sgonzo * 4. Neither the name of the University nor the names of its contributors
23187706Sgonzo *    may be used to endorse or promote products derived from this software
24187706Sgonzo *    without specific prior written permission.
25187706Sgonzo *
26187706Sgonzo * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27187706Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28187706Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29187706Sgonzo * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30187706Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31187706Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32187706Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33187706Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34187706Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35187706Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36187706Sgonzo * SUCH DAMAGE.
37187706Sgonzo */
38187706Sgonzo
39187706Sgonzo#ifndef lint
40187706Sgonzostatic char sccsid[] = "@(#)dirs.c	8.2 (Berkeley) 1/21/94";
41187706Sgonzo#endif /* not lint */
42187706Sgonzo
43187706Sgonzo#include <sys/param.h>
44187706Sgonzo#include <sys/file.h>
45187706Sgonzo#include <sys/stat.h>
46187706Sgonzo#include <sys/time.h>
47210900Sgonzo
48187706Sgonzo#include <ufs/ffs/fs.h>
49187706Sgonzo#include <ufs/ufs/dinode.h>
50187706Sgonzo#include <ufs/ufs/dir.h>
51187706Sgonzo#include <protocols/dumprestore.h>
52187706Sgonzo
53187706Sgonzo#include <errno.h>
54187706Sgonzo#include <stdio.h>
55187706Sgonzo#include <stdlib.h>
56192161Sgonzo#include <string.h>
57192161Sgonzo#include <unistd.h>
58187706Sgonzo
59211478Sadrian#include <machine/endian.h>
60211478Sadrian
61187706Sgonzo#include "pathnames.h"
62187706Sgonzo#include "restore.h"
63187706Sgonzo#include "extern.h"
64187706Sgonzo
65187706Sgonzo/*
66187706Sgonzo * Symbol table of directories read from tape.
67187706Sgonzo */
68187706Sgonzo#define HASHSIZE	1000
69187706Sgonzo#define INOHASH(val) (val % HASHSIZE)
70187706Sgonzostruct inotab {
71187706Sgonzo	struct	inotab *t_next;
72187706Sgonzo	ino_t	t_ino;
73187706Sgonzo	long	t_seekpt;
74187706Sgonzo	long	t_size;
75191872Sgonzo};
76210900Sgonzostatic struct inotab *inotab[HASHSIZE];
77187706Sgonzo
78187706Sgonzo/*
79187706Sgonzo * Information retained about directories.
80187706Sgonzo */
81191872Sgonzostruct modeinfo {
82191872Sgonzo	ino_t ino;
83191872Sgonzo	struct timeval timep[2];
84191872Sgonzo	short mode;
85191872Sgonzo	short uid;
86191872Sgonzo	short gid;
87192822Sgonzo};
88192822Sgonzo
89191872Sgonzo/*
90191872Sgonzo * Definitions for library routines operating on directories.
91192822Sgonzo */
92191872Sgonzo#undef DIRBLKSIZ
93191872Sgonzo#define DIRBLKSIZ 1024
94194273Sgonzostruct rstdirdesc {
95194273Sgonzo	int	dd_fd;
96191872Sgonzo	long	dd_loc;
97191872Sgonzo	long	dd_size;
98191872Sgonzo	char	dd_buf[DIRBLKSIZ];
99192822Sgonzo};
100192822Sgonzo
101191872Sgonzo/*
102191872Sgonzo * Global variables for this file.
103192822Sgonzo */
104191872Sgonzostatic long	seekpt;
105191872Sgonzostatic FILE	*df, *mf;
106191872Sgonzostatic RST_DIR	*dirp;
107194273Sgonzostatic char	dirfile[32] = "#";	/* No file */
108194273Sgonzostatic char	modefile[32] = "#";	/* No file */
109191872Sgonzostatic char	dot[2] = ".";		/* So it can be modified */
110191872Sgonzo
111187706Sgonzo/*
112187706Sgonzo * Format of old style directories.
113187706Sgonzo */
114187706Sgonzo#define ODIRSIZ 14
115187706Sgonzostruct odirect {
116187706Sgonzo	u_short	d_ino;
117187706Sgonzo	char	d_name[ODIRSIZ];
118187706Sgonzo};
119187706Sgonzo
120187706Sgonzostatic struct inotab	*allocinotab __P((ino_t, struct dinode *, long));
121187706Sgonzostatic void		 dcvt __P((struct odirect *, struct direct *));
122187706Sgonzostatic void		 flushent __P((void));
123187706Sgonzostatic struct inotab	*inotablookup __P((ino_t));
124187706Sgonzostatic RST_DIR		*opendirfile __P((const char *));
125187706Sgonzostatic void		 putdir __P((char *, long));
126187706Sgonzostatic void		 putent __P((struct direct *));
127187706Sgonzostatic void		 rst_seekdir __P((RST_DIR *, long, long));
128187706Sgonzostatic long		 rst_telldir __P((RST_DIR *));
129187706Sgonzostatic struct direct	*searchdir __P((ino_t, char *));
130187706Sgonzo
131187706Sgonzo/*
132187706Sgonzo *	Extract directory contents, building up a directory structure
133187706Sgonzo *	on disk for extraction by name.
134187706Sgonzo *	If genmode is requested, save mode, owner, and times for all
135187706Sgonzo *	directories on the tape.
136187706Sgonzo */
137187706Sgonzovoid
138187706Sgonzoextractdirs(genmode)
139187706Sgonzo	int genmode;
140187706Sgonzo{
141187706Sgonzo	register int i;
142187706Sgonzo	register struct dinode *ip;
143187706Sgonzo	struct inotab *itp;
144187706Sgonzo	struct direct nulldir;
145187706Sgonzo
146187706Sgonzo	vprintf(stdout, "Extract directories from tape\n");
147187706Sgonzo	(void) sprintf(dirfile, "%s/rstdir%d", _PATH_TMP, dumpdate);
148187706Sgonzo	df = fopen(dirfile, "w");
149187706Sgonzo	if (df == NULL) {
150187706Sgonzo		fprintf(stderr,
151187706Sgonzo		    "restore: %s - cannot create directory temporary\n",
152187706Sgonzo		    dirfile);
153187706Sgonzo		fprintf(stderr, "fopen: %s\n", strerror(errno));
154187706Sgonzo		done(1);
155187706Sgonzo	}
156187706Sgonzo	if (genmode != 0) {
157187706Sgonzo		(void) sprintf(modefile, "%s/rstmode%d", _PATH_TMP, dumpdate);
158187706Sgonzo		mf = fopen(modefile, "w");
159187706Sgonzo		if (mf == NULL) {
160187706Sgonzo			fprintf(stderr,
161187706Sgonzo			    "restore: %s - cannot create modefile \n",
162187706Sgonzo			    modefile);
163187706Sgonzo			fprintf(stderr, "fopen: %s\n", strerror(errno));
164187706Sgonzo			done(1);
165187706Sgonzo		}
166187706Sgonzo	}
167187706Sgonzo	nulldir.d_ino = 0;
168187706Sgonzo	nulldir.d_type = DT_DIR;
169187706Sgonzo	nulldir.d_namlen = 1;
170187706Sgonzo	(void) strcpy(nulldir.d_name, "/");
171187706Sgonzo	nulldir.d_reclen = DIRSIZ(0, &nulldir);
172187706Sgonzo	for (;;) {
173187706Sgonzo		curfile.name = "<directory file - name unknown>";
174187706Sgonzo		curfile.action = USING;
175187706Sgonzo		ip = curfile.dip;
176187706Sgonzo		if (ip == NULL || (ip->di_mode & IFMT) != IFDIR) {
177187706Sgonzo			(void) fclose(df);
178187706Sgonzo			dirp = opendirfile(dirfile);
179187706Sgonzo			if (dirp == NULL)
180187706Sgonzo				fprintf(stderr, "opendirfile: %s\n",
181187706Sgonzo				    strerror(errno));
182187706Sgonzo			if (mf != NULL)
183187706Sgonzo				(void) fclose(mf);
184187706Sgonzo			i = dirlookup(dot);
185187706Sgonzo			if (i == 0)
186187706Sgonzo				panic("Root directory is not on tape\n");
187187706Sgonzo			return;
188187706Sgonzo		}
189187706Sgonzo		itp = allocinotab(curfile.ino, ip, seekpt);
190187706Sgonzo		getfile(putdir, xtrnull);
191187706Sgonzo		putent(&nulldir);
192194059Sgonzo		flushent();
193194059Sgonzo		itp->t_size = seekpt - itp->t_seekpt;
194187706Sgonzo	}
195187706Sgonzo}
196187706Sgonzo
197187706Sgonzo/*
198187706Sgonzo * skip over all the directories on the tape
199187706Sgonzo */
200187706Sgonzovoid
201187706Sgonzoskipdirs()
202187706Sgonzo{
203187706Sgonzo
204187706Sgonzo	while ((curfile.dip->di_mode & IFMT) == IFDIR) {
205187706Sgonzo		skipfile();
206187706Sgonzo	}
207187706Sgonzo}
208187706Sgonzo
209187706Sgonzo/*
210187706Sgonzo *	Recursively find names and inumbers of all files in subtree
211187706Sgonzo *	pname and pass them off to be processed.
212187706Sgonzo */
213187706Sgonzovoid
214187706Sgonzotreescan(pname, ino, todo)
215187706Sgonzo	char *pname;
216187706Sgonzo	ino_t ino;
217187706Sgonzo	long (*todo) __P((char *, ino_t, int));
218187706Sgonzo{
219187706Sgonzo	register struct inotab *itp;
220187706Sgonzo	register struct direct *dp;
221187706Sgonzo	int namelen;
222187706Sgonzo	long bpt;
223187706Sgonzo	char locname[MAXPATHLEN + 1];
224187706Sgonzo
225187706Sgonzo	itp = inotablookup(ino);
226187706Sgonzo	if (itp == NULL) {
227187706Sgonzo		/*
228187706Sgonzo		 * Pname is name of a simple file or an unchanged directory.
229194059Sgonzo		 */
230194059Sgonzo		(void) (*todo)(pname, ino, LEAF);
231187706Sgonzo		return;
232187706Sgonzo	}
233187706Sgonzo	/*
234187706Sgonzo	 * Pname is a dumped directory name.
235187706Sgonzo	 */
236187706Sgonzo	if ((*todo)(pname, ino, NODE) == FAIL)
237187706Sgonzo		return;
238187706Sgonzo	/*
239187706Sgonzo	 * begin search through the directory
240187706Sgonzo	 * skipping over "." and ".."
241187706Sgonzo	 */
242187706Sgonzo	(void) strncpy(locname, pname, MAXPATHLEN);
243187706Sgonzo	(void) strncat(locname, "/", MAXPATHLEN);
244187706Sgonzo	namelen = strlen(locname);
245187706Sgonzo	rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
246187706Sgonzo	dp = rst_readdir(dirp); /* "." */
247187706Sgonzo	if (dp != NULL && strcmp(dp->d_name, ".") == 0)
248187706Sgonzo		dp = rst_readdir(dirp); /* ".." */
249187706Sgonzo	else
250187706Sgonzo		fprintf(stderr, "Warning: `.' missing from directory %s\n",
251187706Sgonzo			pname);
252187706Sgonzo	if (dp != NULL && strcmp(dp->d_name, "..") == 0)
253187706Sgonzo		dp = rst_readdir(dirp); /* first real entry */
254187706Sgonzo	else
255187706Sgonzo		fprintf(stderr, "Warning: `..' missing from directory %s\n",
256187706Sgonzo			pname);
257187706Sgonzo	bpt = rst_telldir(dirp);
258187706Sgonzo	/*
259187706Sgonzo	 * a zero inode signals end of directory
260187706Sgonzo	 */
261187706Sgonzo	while (dp != NULL && dp->d_ino != 0) {
262187706Sgonzo		locname[namelen] = '\0';
263187706Sgonzo		if (namelen + dp->d_namlen >= MAXPATHLEN) {
264187706Sgonzo			fprintf(stderr, "%s%s: name exceeds %d char\n",
265187706Sgonzo				locname, dp->d_name, MAXPATHLEN);
266187706Sgonzo		} else {
267187706Sgonzo			(void) strncat(locname, dp->d_name, (int)dp->d_namlen);
268187706Sgonzo			treescan(locname, dp->d_ino, todo);
269187706Sgonzo			rst_seekdir(dirp, bpt, itp->t_seekpt);
270187706Sgonzo		}
271187706Sgonzo		dp = rst_readdir(dirp);
272187706Sgonzo		bpt = rst_telldir(dirp);
273187706Sgonzo	}
274187706Sgonzo	if (dp == NULL)
275187706Sgonzo		fprintf(stderr, "corrupted directory: %s.\n", locname);
276187706Sgonzo}
277187706Sgonzo
278187706Sgonzo/*
279187706Sgonzo * Lookup a pathname which is always assumed to start from the ROOTINO.
280187706Sgonzo */
281187706Sgonzostruct direct *
282187706Sgonzopathsearch(pathname)
283187706Sgonzo	const char *pathname;
284187706Sgonzo{
285187706Sgonzo	ino_t ino;
286187706Sgonzo	struct direct *dp;
287187706Sgonzo	char *path, *name, buffer[MAXPATHLEN];
288187706Sgonzo
289187706Sgonzo	strcpy(buffer, pathname);
290187706Sgonzo	path = buffer;
291187706Sgonzo	ino = ROOTINO;
292191872Sgonzo	while (*path == '/')
293187706Sgonzo		path++;
294187706Sgonzo	dp = NULL;
295187706Sgonzo	while ((name = strsep(&path, "/")) != NULL && *name != NULL) {
296187706Sgonzo		if ((dp = searchdir(ino, name)) == NULL)
297187706Sgonzo			return (NULL);
298187706Sgonzo		ino = dp->d_ino;
299211478Sadrian	}
300203132Sgonzo	return (dp);
301187706Sgonzo}
302211478Sadrian
303203132Sgonzo/*
304187706Sgonzo * Lookup the requested name in directory inum.
305187706Sgonzo * Return its inode number if found, zero if it does not exist.
306187706Sgonzo */
307187706Sgonzostatic struct direct *
308187706Sgonzosearchdir(inum, name)
309187706Sgonzo	ino_t	inum;
310187706Sgonzo	char	*name;
311187706Sgonzo{
312187706Sgonzo	register struct direct *dp;
313187706Sgonzo	register struct inotab *itp;
314203132Sgonzo	int len;
315187706Sgonzo
316187706Sgonzo	itp = inotablookup(inum);
317187706Sgonzo	if (itp == NULL)
318187706Sgonzo		return (NULL);
319187706Sgonzo	rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
320187706Sgonzo	len = strlen(name);
321187706Sgonzo	do {
322187706Sgonzo		dp = rst_readdir(dirp);
323187706Sgonzo		if (dp == NULL || dp->d_ino == 0)
324187706Sgonzo			return (NULL);
325187706Sgonzo	} while (dp->d_namlen != len || strncmp(dp->d_name, name, len) != 0);
326187706Sgonzo	return (dp);
327187706Sgonzo}
328187706Sgonzo
329187706Sgonzo/*
330187706Sgonzo * Put the directory entries in the directory file
331187706Sgonzo */
332187706Sgonzostatic void
333187706Sgonzoputdir(buf, size)
334187706Sgonzo	char *buf;
335187706Sgonzo	long size;
336187706Sgonzo{
337187706Sgonzo	struct direct cvtbuf;
338187706Sgonzo	register struct odirect *odp;
339187706Sgonzo	struct odirect *eodp;
340187706Sgonzo	register struct direct *dp;
341187706Sgonzo	long loc, i;
342187706Sgonzo
343187706Sgonzo	if (cvtflag) {
344187706Sgonzo		eodp = (struct odirect *)&buf[size];
345187706Sgonzo		for (odp = (struct odirect *)buf; odp < eodp; odp++)
346187706Sgonzo			if (odp->d_ino != 0) {
347187706Sgonzo				dcvt(odp, &cvtbuf);
348187706Sgonzo				putent(&cvtbuf);
349187706Sgonzo			}
350187706Sgonzo	} else {
351187706Sgonzo		for (loc = 0; loc < size; ) {
352187706Sgonzo			dp = (struct direct *)(buf + loc);
353187706Sgonzo			if (Bcvt)
354187706Sgonzo				swabst((u_char *)"ls", (u_char *) dp);
355187706Sgonzo			if (oldinofmt && dp->d_ino != 0) {
356187706Sgonzo#if BYTE_ORDER == BIG_ENDIAN
357187706Sgonzo				if (Bcvt)
358187706Sgonzo#else
359187706Sgonzo				if (!Bcvt)
360187706Sgonzo#endif
361187706Sgonzo					dp->d_namlen = dp->d_type;
362187706Sgonzo				dp->d_type = DT_UNKNOWN;
363187706Sgonzo			}
364187706Sgonzo			i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1));
365192161Sgonzo			if ((dp->d_reclen & 0x3) != 0 ||
366187706Sgonzo			    dp->d_reclen > i ||
367187706Sgonzo			    dp->d_reclen < DIRSIZ(0, dp) ||
368187706Sgonzo			    dp->d_namlen > NAME_MAX) {
369187706Sgonzo				vprintf(stdout, "Mangled directory: ");
370187706Sgonzo				if ((dp->d_reclen & 0x3) != 0)
371187706Sgonzo					vprintf(stdout,
372187706Sgonzo					   "reclen not multiple of 4 ");
373187706Sgonzo				if (dp->d_reclen < DIRSIZ(0, dp))
374187706Sgonzo					vprintf(stdout,
375187706Sgonzo					   "reclen less than DIRSIZ (%d < %d) ",
376187706Sgonzo					   dp->d_reclen, DIRSIZ(0, dp));
377187706Sgonzo				if (dp->d_namlen > NAME_MAX)
378187706Sgonzo					vprintf(stdout,
379187706Sgonzo					   "reclen name too big (%d > %d) ",
380187706Sgonzo					   dp->d_namlen, NAME_MAX);
381187706Sgonzo				vprintf(stdout, "\n");
382187706Sgonzo				loc += i;
383187706Sgonzo				continue;
384187706Sgonzo			}
385187706Sgonzo			loc += dp->d_reclen;
386187706Sgonzo			if (dp->d_ino != 0) {
387187706Sgonzo				putent(dp);
388187706Sgonzo			}
389187706Sgonzo		}
390187706Sgonzo	}
391187706Sgonzo}
392187706Sgonzo
393192161Sgonzo/*
394187706Sgonzo * These variables are "local" to the following two functions.
395187706Sgonzo */
396187706Sgonzochar dirbuf[DIRBLKSIZ];
397192161Sgonzolong dirloc = 0;
398187706Sgonzolong prev = 0;
399192161Sgonzo
400192161Sgonzo/*
401192161Sgonzo * add a new directory entry to a file.
402192161Sgonzo */
403192161Sgonzostatic void
404192161Sgonzoputent(dp)
405192161Sgonzo	struct direct *dp;
406192161Sgonzo{
407192161Sgonzo	dp->d_reclen = DIRSIZ(0, dp);
408192161Sgonzo	if (dirloc + dp->d_reclen > DIRBLKSIZ) {
409192161Sgonzo		((struct direct *)(dirbuf + prev))->d_reclen =
410192161Sgonzo		    DIRBLKSIZ - prev;
411192161Sgonzo		(void) fwrite(dirbuf, 1, DIRBLKSIZ, df);
412192161Sgonzo		dirloc = 0;
413192161Sgonzo	}
414192161Sgonzo	bcopy((char *)dp, dirbuf + dirloc, (long)dp->d_reclen);
415192161Sgonzo	prev = dirloc;
416192161Sgonzo	dirloc += dp->d_reclen;
417192161Sgonzo}
418192161Sgonzo
419192161Sgonzo/*
420191872Sgonzo * flush out a directory that is finished.
421191872Sgonzo */
422191872Sgonzostatic void
423191872Sgonzoflushent()
424191872Sgonzo{
425191872Sgonzo	((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev;
426191872Sgonzo	(void) fwrite(dirbuf, (int)dirloc, 1, df);
427191872Sgonzo	seekpt = ftell(df);
428191872Sgonzo	dirloc = 0;
429191872Sgonzo}
430191872Sgonzo
431191872Sgonzostatic void
432191872Sgonzodcvt(odp, ndp)
433191872Sgonzo	register struct odirect *odp;
434191872Sgonzo	register struct direct *ndp;
435191872Sgonzo{
436192822Sgonzo
437210900Sgonzo	bzero((char *)ndp, (long)(sizeof *ndp));
438191872Sgonzo	ndp->d_ino =  odp->d_ino;
439210900Sgonzo	ndp->d_type = DT_UNKNOWN;
440210900Sgonzo	(void) strncpy(ndp->d_name, odp->d_name, ODIRSIZ);
441210900Sgonzo	ndp->d_namlen = strlen(ndp->d_name);
442210900Sgonzo	ndp->d_reclen = DIRSIZ(0, ndp);
443210900Sgonzo}
444210900Sgonzo
445210900Sgonzo/*
446191872Sgonzo * Seek to an entry in a directory.
447191872Sgonzo * Only values returned by rst_telldir should be passed to rst_seekdir.
448191872Sgonzo * This routine handles many directories in a single file.
449191872Sgonzo * It takes the base of the directory in the file, plus
450210900Sgonzo * the desired seek offset into it.
451191872Sgonzo */
452192822Sgonzostatic void
453191872Sgonzorst_seekdir(dirp, loc, base)
454191872Sgonzo	register RST_DIR *dirp;
455191872Sgonzo	long loc, base;
456191872Sgonzo{
457191872Sgonzo
458191872Sgonzo	if (loc == rst_telldir(dirp))
459187706Sgonzo		return;
460187706Sgonzo	loc -= base;
461191872Sgonzo	if (loc < 0)
462191872Sgonzo		fprintf(stderr, "bad seek pointer to rst_seekdir %d\n", loc);
463187706Sgonzo	(void) lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), SEEK_SET);
464191872Sgonzo	dirp->dd_loc = loc & (DIRBLKSIZ - 1);
465191872Sgonzo	if (dirp->dd_loc != 0)
466191872Sgonzo		dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ);
467191872Sgonzo}
468191872Sgonzo
469191872Sgonzo/*
470191872Sgonzo * get next entry in a directory.
471192822Sgonzo */
472191872Sgonzostruct direct *
473191872Sgonzorst_readdir(dirp)
474191872Sgonzo	register RST_DIR *dirp;
475191872Sgonzo{
476191872Sgonzo	register struct direct *dp;
477191872Sgonzo
478187706Sgonzo	for (;;) {
479187706Sgonzo		if (dirp->dd_loc == 0) {
480187706Sgonzo			dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf,
481191872Sgonzo			    DIRBLKSIZ);
482191872Sgonzo			if (dirp->dd_size <= 0) {
483191872Sgonzo				dprintf(stderr, "error reading directory\n");
484191872Sgonzo				return (NULL);
485194273Sgonzo			}
486191872Sgonzo		}
487191872Sgonzo		if (dirp->dd_loc >= dirp->dd_size) {
488194273Sgonzo			dirp->dd_loc = 0;
489194273Sgonzo			continue;
490194273Sgonzo		}
491194273Sgonzo		dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc);
492194273Sgonzo		if (dp->d_reclen == 0 ||
493191872Sgonzo		    dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc) {
494191872Sgonzo			dprintf(stderr, "corrupted directory: bad reclen %d\n",
495191872Sgonzo				dp->d_reclen);
496191872Sgonzo			return (NULL);
497191872Sgonzo		}
498191872Sgonzo		dirp->dd_loc += dp->d_reclen;
499191872Sgonzo		if (dp->d_ino == 0 && strcmp(dp->d_name, "/") != 0)
500191872Sgonzo			continue;
501191872Sgonzo		if (dp->d_ino >= maxino) {
502191872Sgonzo			dprintf(stderr, "corrupted directory: bad inum %d\n",
503221256Sadrian				dp->d_ino);
504221256Sadrian			continue;
505221256Sadrian		}
506191872Sgonzo		return (dp);
507191872Sgonzo	}
508210900Sgonzo}
509191872Sgonzo
510191872Sgonzo/*
511191872Sgonzo * Simulate the opening of a directory
512191872Sgonzo */
513191872SgonzoRST_DIR *
514191872Sgonzorst_opendir(name)
515191872Sgonzo	const char *name;
516187706Sgonzo{
517187706Sgonzo	struct inotab *itp;
518187706Sgonzo	RST_DIR *dirp;
519187706Sgonzo	ino_t ino;
520187706Sgonzo
521187706Sgonzo	if ((ino = dirlookup(name)) > 0 &&
522187706Sgonzo	    (itp = inotablookup(ino)) != NULL) {
523187706Sgonzo		dirp = opendirfile(dirfile);
524187706Sgonzo		rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
525195474Sgonzo		return (dirp);
526195474Sgonzo	}
527195474Sgonzo	return (NULL);
528187706Sgonzo}
529195474Sgonzo
530187706Sgonzo/*
531187706Sgonzo * In our case, there is nothing to do when closing a directory.
532187706Sgonzo */
533187706Sgonzovoid
534187706Sgonzorst_closedir(dirp)
535187706Sgonzo	RST_DIR *dirp;
536187706Sgonzo{
537187706Sgonzo
538187706Sgonzo	(void)close(dirp->dd_fd);
539187706Sgonzo	free(dirp);
540187706Sgonzo	return;
541187706Sgonzo}
542187706Sgonzo
543187706Sgonzo/*
544187706Sgonzo * Simulate finding the current offset in the directory.
545187706Sgonzo */
546192161Sgonzostatic long
547187706Sgonzorst_telldir(dirp)
548191872Sgonzo	RST_DIR *dirp;
549187706Sgonzo{
550187706Sgonzo	return ((long)lseek(dirp->dd_fd,
551187706Sgonzo	    (off_t)0, SEEK_CUR) - dirp->dd_size + dirp->dd_loc);
552187706Sgonzo}
553187706Sgonzo
554187706Sgonzo/*
555187706Sgonzo * Open a directory file.
556187706Sgonzo */
557187706Sgonzostatic RST_DIR *
558187706Sgonzoopendirfile(name)
559187706Sgonzo	const char *name;
560187706Sgonzo{
561187706Sgonzo	register RST_DIR *dirp;
562187706Sgonzo	register int fd;
563187706Sgonzo
564187706Sgonzo	if ((fd = open(name, O_RDONLY)) == -1)
565187706Sgonzo		return (NULL);
566187706Sgonzo	if ((dirp = malloc(sizeof(RST_DIR))) == NULL) {
567187706Sgonzo		(void)close(fd);
568187706Sgonzo		return (NULL);
569	}
570	dirp->dd_fd = fd;
571	dirp->dd_loc = 0;
572	return (dirp);
573}
574
575/*
576 * Set the mode, owner, and times for all new or changed directories
577 */
578void
579setdirmodes(flags)
580	int flags;
581{
582	FILE *mf;
583	struct modeinfo node;
584	struct entry *ep;
585	char *cp;
586
587	vprintf(stdout, "Set directory mode, owner, and times.\n");
588	(void) sprintf(modefile, "%s/rstmode%d", _PATH_TMP, dumpdate);
589	mf = fopen(modefile, "r");
590	if (mf == NULL) {
591		fprintf(stderr, "fopen: %s\n", strerror(errno));
592		fprintf(stderr, "cannot open mode file %s\n", modefile);
593		fprintf(stderr, "directory mode, owner, and times not set\n");
594		return;
595	}
596	clearerr(mf);
597	for (;;) {
598		(void) fread((char *)&node, 1, sizeof(struct modeinfo), mf);
599		if (feof(mf))
600			break;
601		ep = lookupino(node.ino);
602		if (command == 'i' || command == 'x') {
603			if (ep == NULL)
604				continue;
605			if ((flags & FORCE) == 0 && ep->e_flags & EXISTED) {
606				ep->e_flags &= ~NEW;
607				continue;
608			}
609			if (node.ino == ROOTINO &&
610		   	    reply("set owner/mode for '.'") == FAIL)
611				continue;
612		}
613		if (ep == NULL) {
614			panic("cannot find directory inode %d\n", node.ino);
615		} else {
616			cp = myname(ep);
617			(void) chown(cp, node.uid, node.gid);
618			(void) chmod(cp, node.mode);
619			utimes(cp, node.timep);
620			ep->e_flags &= ~NEW;
621		}
622	}
623	if (ferror(mf))
624		panic("error setting directory modes\n");
625	(void) fclose(mf);
626}
627
628/*
629 * Generate a literal copy of a directory.
630 */
631int
632genliteraldir(name, ino)
633	char *name;
634	ino_t ino;
635{
636	register struct inotab *itp;
637	int ofile, dp, i, size;
638	char buf[BUFSIZ];
639
640	itp = inotablookup(ino);
641	if (itp == NULL)
642		panic("Cannot find directory inode %d named %s\n", ino, name);
643	if ((ofile = creat(name, 0666)) < 0) {
644		fprintf(stderr, "%s: ", name);
645		(void) fflush(stderr);
646		fprintf(stderr, "cannot create file: %s\n", strerror(errno));
647		return (FAIL);
648	}
649	rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
650	dp = dup(dirp->dd_fd);
651	for (i = itp->t_size; i > 0; i -= BUFSIZ) {
652		size = i < BUFSIZ ? i : BUFSIZ;
653		if (read(dp, buf, (int) size) == -1) {
654			fprintf(stderr,
655				"write error extracting inode %d, name %s\n",
656				curfile.ino, curfile.name);
657			fprintf(stderr, "read: %s\n", strerror(errno));
658			done(1);
659		}
660		if (!Nflag && write(ofile, buf, (int) size) == -1) {
661			fprintf(stderr,
662				"write error extracting inode %d, name %s\n",
663				curfile.ino, curfile.name);
664			fprintf(stderr, "write: %s\n", strerror(errno));
665			done(1);
666		}
667	}
668	(void) close(dp);
669	(void) close(ofile);
670	return (GOOD);
671}
672
673/*
674 * Determine the type of an inode
675 */
676int
677inodetype(ino)
678	ino_t ino;
679{
680	struct inotab *itp;
681
682	itp = inotablookup(ino);
683	if (itp == NULL)
684		return (LEAF);
685	return (NODE);
686}
687
688/*
689 * Allocate and initialize a directory inode entry.
690 * If requested, save its pertinent mode, owner, and time info.
691 */
692static struct inotab *
693allocinotab(ino, dip, seekpt)
694	ino_t ino;
695	struct dinode *dip;
696	long seekpt;
697{
698	register struct inotab	*itp;
699	struct modeinfo node;
700
701	itp = calloc(1, sizeof(struct inotab));
702	if (itp == NULL)
703		panic("no memory directory table\n");
704	itp->t_next = inotab[INOHASH(ino)];
705	inotab[INOHASH(ino)] = itp;
706	itp->t_ino = ino;
707	itp->t_seekpt = seekpt;
708	if (mf == NULL)
709		return (itp);
710	node.ino = ino;
711	node.timep[0].tv_sec = dip->di_atime.ts_sec;
712	node.timep[0].tv_usec = dip->di_atime.ts_nsec / 1000;
713	node.timep[1].tv_sec = dip->di_mtime.ts_sec;
714	node.timep[1].tv_usec = dip->di_mtime.ts_nsec / 1000;
715	node.mode = dip->di_mode;
716	node.uid = dip->di_uid;
717	node.gid = dip->di_gid;
718	(void) fwrite((char *)&node, 1, sizeof(struct modeinfo), mf);
719	return (itp);
720}
721
722/*
723 * Look up an inode in the table of directories
724 */
725static struct inotab *
726inotablookup(ino)
727	ino_t	ino;
728{
729	register struct inotab *itp;
730
731	for (itp = inotab[INOHASH(ino)]; itp != NULL; itp = itp->t_next)
732		if (itp->t_ino == ino)
733			return (itp);
734	return (NULL);
735}
736
737/*
738 * Clean up and exit
739 */
740__dead void
741done(exitcode)
742	int exitcode;
743{
744
745	closemt();
746	if (modefile[0] != '#')
747		(void) unlink(modefile);
748	if (dirfile[0] != '#')
749		(void) unlink(dirfile);
750	exit(exitcode);
751}
752