xref: /csrg-svn/sbin/restore/dirs.c (revision 11992)
111127Smckusick /* Copyright (c) 1983 Regents of the University of California */
211127Smckusick 
311127Smckusick #ifndef lint
4*11992Smckusick static char sccsid[] = "@(#)dirs.c	3.8	(Berkeley)	83/04/19";
511127Smckusick #endif
611127Smckusick 
711127Smckusick #include "restore.h"
811127Smckusick #include <dumprestor.h>
911309Smckusick #include <sys/file.h>
1011127Smckusick #include <dir.h>
1111127Smckusick 
12*11992Smckusick /*
13*11992Smckusick  * Symbol table of directories read from tape.
14*11992Smckusick  */
1511127Smckusick #define HASHSIZE	1000
1611127Smckusick #define INOHASH(val) (val % HASHSIZE)
1711127Smckusick struct inotab {
1811127Smckusick 	struct inotab *t_next;
1911127Smckusick 	ino_t	t_ino;
2011127Smckusick 	daddr_t	t_seekpt;
2111127Smckusick 	long t_size;
2211309Smckusick };
2311309Smckusick static struct inotab *inotab[HASHSIZE];
2411309Smckusick extern struct inotab *inotablookup();
2511322Smckusick extern struct inotab *allocinotab();
2611127Smckusick 
27*11992Smckusick /*
28*11992Smckusick  * Information retained about directories.
29*11992Smckusick  */
3011127Smckusick struct modeinfo {
3111127Smckusick 	ino_t ino;
3211127Smckusick 	time_t timep[2];
3311127Smckusick 	short mode;
3411127Smckusick 	short uid;
3511127Smckusick 	short gid;
3611127Smckusick };
3711127Smckusick 
38*11992Smckusick /*
39*11992Smckusick  * Global variables for this file.
40*11992Smckusick  */
4111309Smckusick static daddr_t	seekpt;
4211309Smckusick static FILE	*df, *mf;
4311309Smckusick static DIR	*dirp;
44*11992Smckusick static char	dirfile[32] = "#";	/* No file */
45*11992Smckusick static char	modefile[32] = "#";	/* No file */
4611309Smckusick extern ino_t	search();
4711127Smckusick 
48*11992Smckusick /*
49*11992Smckusick  * Format of old style directories.
50*11992Smckusick  */
5111127Smckusick #define ODIRSIZ 14
5211127Smckusick struct odirect {
5311127Smckusick 	u_short	d_ino;
5411127Smckusick 	char	d_name[ODIRSIZ];
5511127Smckusick };
5611127Smckusick 
5711127Smckusick /*
58*11992Smckusick  * Structure and routines associated with listing directories.
59*11992Smckusick  */
60*11992Smckusick struct afile {
61*11992Smckusick 	ino_t	fnum;		/* inode number of file */
62*11992Smckusick 	char	*fname;		/* file name */
63*11992Smckusick 	short	fflags;		/* extraction flags, if any */
64*11992Smckusick 	char	ftype;		/* file type, e.g. LEAF or NODE */
65*11992Smckusick };
66*11992Smckusick extern int fcmp();
67*11992Smckusick extern char *fmtentry();
68*11992Smckusick 
69*11992Smckusick /*
7011127Smckusick  *	Extract directory contents, building up a directory structure
7111127Smckusick  *	on disk for extraction by name.
72*11992Smckusick  *	If genmode is requested, save mode, owner, and times for all
7311127Smckusick  *	directories on the tape.
7411127Smckusick  */
75*11992Smckusick extractdirs(genmode)
76*11992Smckusick 	int genmode;
7711127Smckusick {
7811127Smckusick 	register int i;
7911127Smckusick 	register struct dinode *ip;
8011322Smckusick 	struct inotab *itp;
8111127Smckusick 	struct direct nulldir;
8211127Smckusick 	int putdir(), null();
8311127Smckusick 
8411127Smckusick 	vprintf(stdout, "Extract directories from tape\n");
85*11992Smckusick 	(void) sprintf(dirfile, "/tmp/rstdir%d", dumpdate);
8611127Smckusick 	df = fopen(dirfile, "w");
8711127Smckusick 	if (df == 0) {
8811127Smckusick 		fprintf(stderr,
8911127Smckusick 		    "restor: %s - cannot create directory temporary\n",
9011127Smckusick 		    dirfile);
9111127Smckusick 		perror("fopen");
9211127Smckusick 		done(1);
9311127Smckusick 	}
94*11992Smckusick 	if (genmode != 0) {
95*11992Smckusick 		(void) sprintf(modefile, "/tmp/rstmode%d", dumpdate);
9611127Smckusick 		mf = fopen(modefile, "w");
9711309Smckusick 		if (mf == 0) {
9811127Smckusick 			fprintf(stderr,
9911127Smckusick 			    "restor: %s - cannot create modefile \n",
10011127Smckusick 			    modefile);
10111127Smckusick 			perror("fopen");
10211127Smckusick 			done(1);
10311127Smckusick 		}
10411127Smckusick 	}
10511322Smckusick 	nulldir.d_ino = 0;
10611127Smckusick 	nulldir.d_namlen = 1;
107*11992Smckusick 	(void) strncpy(nulldir.d_name, "/", (int)nulldir.d_namlen);
10811127Smckusick 	nulldir.d_reclen = DIRSIZ(&nulldir);
10911127Smckusick 	for (;;) {
11011127Smckusick 		curfile.name = "<directory file - name unknown>";
11111127Smckusick 		curfile.action = USING;
11211127Smckusick 		ip = curfile.dip;
11311127Smckusick 		i = ip->di_mode & IFMT;
11411127Smckusick 		if (i != IFDIR) {
11511732Smckusick 			(void) fclose(df);
11611127Smckusick 			dirp = opendir(dirfile);
11711127Smckusick 			if (dirp == NULL)
11811127Smckusick 				perror("opendir");
11911127Smckusick 			if (mf != NULL)
12011732Smckusick 				(void) fclose(mf);
121*11992Smckusick 			i = dirlookup(".");
122*11992Smckusick 			if (i == 0)
12311421Smckusick 				panic("Root directory is not on tape\n");
12411127Smckusick 			return;
12511127Smckusick 		}
12611322Smckusick 		itp = allocinotab(curfile.ino, ip, seekpt);
12711127Smckusick 		getfile(putdir, null);
12811127Smckusick 		putent(&nulldir);
12911127Smckusick 		flushent();
13011322Smckusick 		itp->t_size = seekpt - itp->t_seekpt;
13111127Smckusick 	}
13211127Smckusick }
13311127Smckusick 
13411127Smckusick /*
13511322Smckusick  * skip over all the directories on the tape
13611322Smckusick  */
13711322Smckusick skipdirs()
13811322Smckusick {
13911322Smckusick 
14011322Smckusick 	while ((curfile.dip->di_mode & IFMT) == IFDIR) {
14111322Smckusick 		skipfile();
14211322Smckusick 	}
14311322Smckusick }
14411322Smckusick 
14511322Smckusick /*
14611127Smckusick  *	Recursively find names and inumbers of all files in subtree
14711127Smckusick  *	pname and pass them off to be processed.
14811127Smckusick  */
14911127Smckusick treescan(pname, ino, todo)
15011127Smckusick 	char *pname;
15111127Smckusick 	ino_t ino;
15211744Smckusick 	long (*todo)();
15311127Smckusick {
15411127Smckusick 	register struct inotab *itp;
15511127Smckusick 	int namelen;
15611127Smckusick 	daddr_t bpt;
15711127Smckusick 	register struct direct *dp;
15811644Smckusick 	char locname[MAXPATHLEN + 1];
15911127Smckusick 
16011127Smckusick 	itp = inotablookup(ino);
16111127Smckusick 	if (itp == NULL) {
16211127Smckusick 		/*
16311127Smckusick 		 * Pname is name of a simple file or an unchanged directory.
16411127Smckusick 		 */
16511744Smckusick 		(void) (*todo)(pname, ino, LEAF);
16611127Smckusick 		return;
16711127Smckusick 	}
16811127Smckusick 	/*
16911127Smckusick 	 * Pname is a dumped directory name.
17011127Smckusick 	 */
17111744Smckusick 	if ((*todo)(pname, ino, NODE) == FAIL)
17211744Smckusick 		return;
17311127Smckusick 	/*
17411127Smckusick 	 * begin search through the directory
17511127Smckusick 	 * skipping over "." and ".."
17611127Smckusick 	 */
177*11992Smckusick 	(void) strncpy(locname, pname, MAXPATHLEN);
178*11992Smckusick 	(void) strncat(locname, "/", MAXPATHLEN);
17911127Smckusick 	namelen = strlen(locname);
18011127Smckusick 	seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
18111127Smckusick 	dp = readdir(dirp); /* "." */
18211127Smckusick 	dp = readdir(dirp); /* ".." */
18311127Smckusick 	dp = readdir(dirp); /* first real entry */
18411127Smckusick 	bpt = telldir(dirp);
18511127Smckusick 	/*
18611127Smckusick 	 * "/" signals end of directory
18711127Smckusick 	 */
18811127Smckusick 	while (dp != NULL && !(dp->d_namlen == 1 && dp->d_name[0] == '/')) {
18911127Smckusick 		locname[namelen] = '\0';
19011644Smckusick 		if (namelen + dp->d_namlen >= MAXPATHLEN) {
19111127Smckusick 			fprintf(stderr, "%s%s: name exceeds %d char\n",
19211644Smckusick 				locname, dp->d_name, MAXPATHLEN);
19311127Smckusick 		} else {
194*11992Smckusick 			(void) strncat(locname, dp->d_name, (int)dp->d_namlen);
19511127Smckusick 			treescan(locname, dp->d_ino, todo);
19611127Smckusick 			seekdir(dirp, bpt, itp->t_seekpt);
19711127Smckusick 		}
19811127Smckusick 		dp = readdir(dirp);
19911127Smckusick 		bpt = telldir(dirp);
20011127Smckusick 	}
20111127Smckusick 	if (dp == NULL)
20211127Smckusick 		fprintf(stderr, "corrupted directory: %s.\n", locname);
20311127Smckusick }
20411127Smckusick 
20511127Smckusick /*
20611127Smckusick  * Search the directory tree rooted at inode ROOTINO
20711127Smckusick  * for the path pointed at by n
20811127Smckusick  */
20911127Smckusick ino_t
21011127Smckusick psearch(n)
21111127Smckusick 	char	*n;
21211127Smckusick {
21311127Smckusick 	register char *cp, *cp1;
21411127Smckusick 	ino_t ino;
21511127Smckusick 	char c;
21611127Smckusick 
21711127Smckusick 	ino = ROOTINO;
21811127Smckusick 	if (*(cp = n) == '/')
21911127Smckusick 		cp++;
22011127Smckusick next:
22111127Smckusick 	cp1 = cp + 1;
22211127Smckusick 	while (*cp1 != '/' && *cp1)
22311127Smckusick 		cp1++;
22411127Smckusick 	c = *cp1;
22511127Smckusick 	*cp1 = 0;
22611127Smckusick 	ino = search(ino, cp);
22711127Smckusick 	if (ino == 0) {
22811127Smckusick 		*cp1 = c;
22911127Smckusick 		return(0);
23011127Smckusick 	}
23111127Smckusick 	*cp1 = c;
23211127Smckusick 	if (c == '/') {
23311127Smckusick 		cp = cp1+1;
23411127Smckusick 		goto next;
23511127Smckusick 	}
23611127Smckusick 	return(ino);
23711127Smckusick }
23811127Smckusick 
23911127Smckusick /*
24011127Smckusick  * search the directory inode ino
24111127Smckusick  * looking for entry cp
24211127Smckusick  */
24311127Smckusick ino_t
24411127Smckusick search(inum, cp)
24511127Smckusick 	ino_t	inum;
24611127Smckusick 	char	*cp;
24711127Smckusick {
24811127Smckusick 	register struct direct *dp;
24911127Smckusick 	register struct inotab *itp;
25011127Smckusick 	int len;
25111127Smckusick 
25211127Smckusick 	itp = inotablookup(inum);
25311127Smckusick 	if (itp == NULL)
25411127Smckusick 		return(0);
25511127Smckusick 	seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
25611127Smckusick 	len = strlen(cp);
25711127Smckusick 	do {
25811127Smckusick 		dp = readdir(dirp);
25911127Smckusick 		if (dp->d_namlen == 1 && dp->d_name[0] == '/')
26011127Smckusick 			return(0);
261*11992Smckusick 	} while (dp->d_namlen != len || strncmp(dp->d_name, cp, len) != 0);
26211127Smckusick 	return(dp->d_ino);
26311127Smckusick }
26411127Smckusick 
26511127Smckusick /*
26611127Smckusick  * Put the directory entries in the directory file
26711127Smckusick  */
26811127Smckusick putdir(buf, size)
26911127Smckusick 	char *buf;
27011127Smckusick 	int size;
27111127Smckusick {
27211127Smckusick 	struct direct cvtbuf;
27311127Smckusick 	register struct odirect *odp;
27411127Smckusick 	struct odirect *eodp;
27511127Smckusick 	register struct direct *dp;
27611127Smckusick 	long loc, i;
27711127Smckusick 
27811127Smckusick 	if (cvtflag) {
27911127Smckusick 		eodp = (struct odirect *)&buf[size];
28011127Smckusick 		for (odp = (struct odirect *)buf; odp < eodp; odp++)
28111127Smckusick 			if (odp->d_ino != 0) {
28211127Smckusick 				dcvt(odp, &cvtbuf);
28311127Smckusick 				putent(&cvtbuf);
28411127Smckusick 			}
28511127Smckusick 	} else {
28611127Smckusick 		for (loc = 0; loc < size; ) {
28711127Smckusick 			dp = (struct direct *)(buf + loc);
28811127Smckusick 			i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1));
28911127Smckusick 			if (dp->d_reclen == 0 || dp->d_reclen > i) {
29011127Smckusick 				loc += i;
29111127Smckusick 				continue;
29211127Smckusick 			}
29311127Smckusick 			loc += dp->d_reclen;
29411127Smckusick 			if (dp->d_ino != 0) {
29511127Smckusick 				putent(dp);
29611127Smckusick 			}
29711127Smckusick 		}
29811127Smckusick 	}
29911127Smckusick }
30011127Smckusick 
30111127Smckusick /*
30211127Smckusick  * These variables are "local" to the following two functions.
30311127Smckusick  */
30411127Smckusick char dirbuf[DIRBLKSIZ];
30511127Smckusick long dirloc = 0;
30611127Smckusick long prev = 0;
30711127Smckusick 
30811127Smckusick /*
30911127Smckusick  * add a new directory entry to a file.
31011127Smckusick  */
31111127Smckusick putent(dp)
31211127Smckusick 	struct direct *dp;
31311127Smckusick {
31411322Smckusick 	dp->d_reclen = DIRSIZ(dp);
31511127Smckusick 	if (dirloc + dp->d_reclen > DIRBLKSIZ) {
31611127Smckusick 		((struct direct *)(dirbuf + prev))->d_reclen =
31711127Smckusick 		    DIRBLKSIZ - prev;
31811732Smckusick 		(void) fwrite(dirbuf, 1, DIRBLKSIZ, df);
31911127Smckusick 		dirloc = 0;
32011127Smckusick 	}
32111127Smckusick 	bcopy((char *)dp, dirbuf + dirloc, (long)dp->d_reclen);
32211127Smckusick 	prev = dirloc;
32311127Smckusick 	dirloc += dp->d_reclen;
32411127Smckusick }
32511127Smckusick 
32611127Smckusick /*
32711127Smckusick  * flush out a directory that is finished.
32811127Smckusick  */
32911127Smckusick flushent()
33011127Smckusick {
33111127Smckusick 
33211127Smckusick 	((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev;
33311732Smckusick 	(void) fwrite(dirbuf, (int)dirloc, 1, df);
33411127Smckusick 	seekpt = ftell(df);
33511127Smckusick 	dirloc = 0;
33611127Smckusick }
33711127Smckusick 
33811127Smckusick dcvt(odp, ndp)
33911127Smckusick 	register struct odirect *odp;
34011127Smckusick 	register struct direct *ndp;
34111127Smckusick {
34211127Smckusick 
34311127Smckusick 	bzero((char *)ndp, (long)(sizeof *ndp));
34411127Smckusick 	ndp->d_ino =  odp->d_ino;
345*11992Smckusick 	(void) strncpy(ndp->d_name, odp->d_name, ODIRSIZ);
34611127Smckusick 	ndp->d_namlen = strlen(ndp->d_name);
34711127Smckusick 	ndp->d_reclen = DIRSIZ(ndp);
34811127Smckusick }
34911127Smckusick 
35011127Smckusick /*
35111127Smckusick  * Seek to an entry in a directory.
35211127Smckusick  * Only values returned by ``telldir'' should be passed to seekdir.
35311732Smckusick  * This routine handles many directories in a single file.
35411732Smckusick  * It takes the base of the directory in the file, plus
35511732Smckusick  * the desired seek offset into it.
35611127Smckusick  */
35711127Smckusick void
35811127Smckusick seekdir(dirp, loc, base)
35911127Smckusick 	register DIR *dirp;
36011127Smckusick 	daddr_t loc, base;
36111127Smckusick {
36211127Smckusick 
36311127Smckusick 	if (loc == telldir(dirp))
36411127Smckusick 		return;
36511127Smckusick 	loc -= base;
36611127Smckusick 	if (loc < 0)
36711127Smckusick 		fprintf(stderr, "bad seek pointer to seekdir %d\n", loc);
36811127Smckusick 	(void) lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), 0);
36911127Smckusick 	dirp->dd_loc = loc & (DIRBLKSIZ - 1);
37011127Smckusick 	if (dirp->dd_loc != 0)
37111127Smckusick 		dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ);
37211127Smckusick }
37311127Smckusick 
37411127Smckusick /*
37511127Smckusick  * get next entry in a directory.
37611127Smckusick  */
37711127Smckusick struct direct *
37811127Smckusick readdir(dirp)
37911127Smckusick 	register DIR *dirp;
38011127Smckusick {
38111127Smckusick 	register struct direct *dp;
38211127Smckusick 
38311127Smckusick 	for (;;) {
38411127Smckusick 		if (dirp->dd_loc == 0) {
38511127Smckusick 			dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf,
38611127Smckusick 			    DIRBLKSIZ);
38711127Smckusick 			if (dirp->dd_size <= 0)
38811127Smckusick 				return NULL;
38911127Smckusick 		}
39011127Smckusick 		if (dirp->dd_loc >= dirp->dd_size) {
39111127Smckusick 			dirp->dd_loc = 0;
39211127Smckusick 			continue;
39311127Smckusick 		}
39411127Smckusick 		dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc);
39511127Smckusick 		if (dp->d_reclen == 0 ||
39611127Smckusick 		    dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc)
39711127Smckusick 			return NULL;
39811127Smckusick 		dirp->dd_loc += dp->d_reclen;
39911127Smckusick 		return (dp);
40011127Smckusick 	}
40111127Smckusick }
40211127Smckusick 
40311127Smckusick /*
40411127Smckusick  * Set the mode, owner, and times for all new or changed directories
40511127Smckusick  */
406*11992Smckusick setdirmodes()
40711127Smckusick {
40811127Smckusick 	FILE *mf;
40911127Smckusick 	struct modeinfo node;
41011127Smckusick 	struct entry *ep;
41111127Smckusick 	char *cp;
41211127Smckusick 
41311127Smckusick 	vprintf(stdout, "Set directory mode, owner, and times.\n");
41411127Smckusick 	mf = fopen(modefile, "r");
41511127Smckusick 	if (mf == NULL) {
41611127Smckusick 		perror("fopen");
41711127Smckusick 		panic("cannot open mode file %s\n", modefile);
41811127Smckusick 	}
41911127Smckusick 	clearerr(mf);
42011309Smckusick 	for (;;) {
42111732Smckusick 		(void) fread((char *)&node, 1, sizeof(struct modeinfo), mf);
42211309Smckusick 		if (feof(mf))
42311309Smckusick 			break;
42411127Smckusick 		ep = lookupino(node.ino);
425*11992Smckusick 		if (ep == NIL || (ep->e_flags & NEW) == 0) {
426*11992Smckusick 			if (command != 'r' && command != 'R')
42711309Smckusick 				continue;
42811127Smckusick 			panic("cannot find directory inode %d\n", node.ino);
42911309Smckusick 		}
43011127Smckusick 		cp = myname(ep);
43111732Smckusick 		(void) chown(cp, node.uid, node.gid);
43211732Smckusick 		(void) chmod(cp, node.mode);
43311127Smckusick 		utime(cp, node.timep);
434*11992Smckusick 		ep->e_flags &= ~NEW;
43511127Smckusick 	}
43611127Smckusick 	if (ferror(mf))
43711127Smckusick 		panic("error setting directory modes\n");
43811732Smckusick 	(void) fclose(mf);
43911127Smckusick }
44011127Smckusick 
44111127Smckusick /*
44211127Smckusick  * Generate a literal copy of a directory.
44311127Smckusick  */
44411127Smckusick genliteraldir(name, ino)
44511127Smckusick 	char *name;
44611127Smckusick 	ino_t ino;
44711127Smckusick {
44811127Smckusick 	register struct inotab *itp;
44911127Smckusick 	int ofile, dp, i, size;
45011127Smckusick 	char buf[BUFSIZ];
45111127Smckusick 
45211127Smckusick 	itp = inotablookup(ino);
45311127Smckusick 	if (itp == NULL)
45411322Smckusick 		panic("Cannot find directory inode %d named %s\n", ino, name);
45511127Smckusick 	if ((ofile = open(name, FWRONLY|FCREATE, 0666)) < 0) {
45611127Smckusick 		fprintf(stderr, "%s: cannot create file\n", name);
45711127Smckusick 		return (FAIL);
45811127Smckusick 	}
45911127Smckusick 	seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
46011127Smckusick 	dp = dup(dirp->dd_fd);
46111127Smckusick 	for (i = itp->t_size; i > 0; i -= BUFSIZ) {
46211127Smckusick 		size = i < BUFSIZ ? i : BUFSIZ;
46311127Smckusick 		if (read(dp, buf, (int) size) == -1) {
46411127Smckusick 			fprintf(stderr,
46511127Smckusick 				"write error extracting inode %d, name %s\n",
46611127Smckusick 				curfile.ino, curfile.name);
46711127Smckusick 			perror("read");
46811127Smckusick 			done(1);
46911127Smckusick 		}
47011127Smckusick 		if (write(ofile, buf, (int) size) == -1) {
47111127Smckusick 			fprintf(stderr,
47211127Smckusick 				"write error extracting inode %d, name %s\n",
47311127Smckusick 				curfile.ino, curfile.name);
47411127Smckusick 			perror("write");
47511127Smckusick 			done(1);
47611127Smckusick 		}
47711127Smckusick 	}
47811732Smckusick 	(void) close(dp);
47911732Smckusick 	(void) close(ofile);
48011127Smckusick 	return (GOOD);
48111127Smckusick }
48211127Smckusick 
48311127Smckusick /*
484*11992Smckusick  * Do an "ls" style listing of a directory
485*11992Smckusick  */
486*11992Smckusick printlist(name, ino)
487*11992Smckusick 	char *name;
488*11992Smckusick 	ino_t ino;
489*11992Smckusick {
490*11992Smckusick 	register struct afile *fp;
491*11992Smckusick 	register struct inotab *itp;
492*11992Smckusick 	struct afile *dfp0, *dfplast;
493*11992Smckusick 	struct afile single;
494*11992Smckusick 
495*11992Smckusick 	itp = inotablookup(ino);
496*11992Smckusick 	if (itp == NULL) {
497*11992Smckusick 		single.fnum = ino;
498*11992Smckusick 		single.fname = savename(rindex(name, '/') + 1);
499*11992Smckusick 		dfp0 = &single;
500*11992Smckusick 		dfplast = dfp0 + 1;
501*11992Smckusick 	} else {
502*11992Smckusick 		seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
503*11992Smckusick 		if (getdir(dirp, &dfp0, &dfplast) == FAIL)
504*11992Smckusick 			return;
505*11992Smckusick 	}
506*11992Smckusick 	qsort((char *)dfp0, dfplast - dfp0, sizeof (struct afile), fcmp);
507*11992Smckusick 	formatf(dfp0, dfplast);
508*11992Smckusick 	for (fp = dfp0; fp < dfplast; fp++)
509*11992Smckusick 		freename(fp->fname);
510*11992Smckusick }
511*11992Smckusick 
512*11992Smckusick /*
513*11992Smckusick  * Read the contents of a directory.
514*11992Smckusick  */
515*11992Smckusick getdir(dirp, pfp0, pfplast)
516*11992Smckusick 	DIR *dirp;
517*11992Smckusick 	struct afile **pfp0, **pfplast;
518*11992Smckusick {
519*11992Smckusick 	register struct afile *fp;
520*11992Smckusick 	register struct direct *dp;
521*11992Smckusick 	static struct afile *basefp = NULL;
522*11992Smckusick 	static long nent = 20;
523*11992Smckusick 
524*11992Smckusick 	if (basefp == NULL)
525*11992Smckusick 		basefp = (struct afile *)calloc((unsigned)nent,
526*11992Smckusick 			sizeof (struct afile));
527*11992Smckusick 	fp = *pfp0 = basefp;
528*11992Smckusick 	*pfplast = *pfp0 + nent;
529*11992Smckusick 	while (dp = readdir(dirp)) {
530*11992Smckusick 		if (dp->d_ino == 0 && strcmp(dp->d_name, "/") == 0)
531*11992Smckusick 			break;
532*11992Smckusick 		if (BIT(dp->d_ino, dumpmap) == 0)
533*11992Smckusick 			continue;
534*11992Smckusick 		if (vflag == 0 &&
535*11992Smckusick 		    (strcmp(dp->d_name, ".") == 0 ||
536*11992Smckusick 		     strcmp(dp->d_name, "..") == 0))
537*11992Smckusick 			continue;
538*11992Smckusick 		fp->fnum = dp->d_ino;
539*11992Smckusick 		fp->fname = savename(dp->d_name);
540*11992Smckusick 		fp++;
541*11992Smckusick 		if (fp == *pfplast) {
542*11992Smckusick 			basefp = (struct afile *)realloc((char *)basefp,
543*11992Smckusick 			    (unsigned)(2 * nent * sizeof (struct afile)));
544*11992Smckusick 			if (basefp == 0) {
545*11992Smckusick 				fprintf(stderr, "ls: out of memory\n");
546*11992Smckusick 				return (FAIL);
547*11992Smckusick 			}
548*11992Smckusick 			*pfp0 = basefp;
549*11992Smckusick 			fp = *pfp0 + nent;
550*11992Smckusick 			*pfplast = fp + nent;
551*11992Smckusick 			nent *= 2;
552*11992Smckusick 		}
553*11992Smckusick 	}
554*11992Smckusick 	*pfplast = fp;
555*11992Smckusick 	return (GOOD);
556*11992Smckusick }
557*11992Smckusick 
558*11992Smckusick /*
559*11992Smckusick  * Print out a pretty listing of a directory
560*11992Smckusick  */
561*11992Smckusick formatf(fp0, fplast)
562*11992Smckusick 	struct afile *fp0, *fplast;
563*11992Smckusick {
564*11992Smckusick 	register struct afile *fp;
565*11992Smckusick 	struct entry *np;
566*11992Smckusick 	int width = 0, w, nentry = fplast - fp0;
567*11992Smckusick 	int i, j, len, columns, lines;
568*11992Smckusick 	char *cp;
569*11992Smckusick 
570*11992Smckusick 	if (fp0 == fplast)
571*11992Smckusick 		return;
572*11992Smckusick 	for (fp = fp0; fp < fplast; fp++) {
573*11992Smckusick 		fp->ftype = inodetype(fp->fnum);
574*11992Smckusick 		np = lookupino(fp->fnum);
575*11992Smckusick 		if (np != NIL)
576*11992Smckusick 			fp->fflags = np->e_flags;
577*11992Smckusick 		else
578*11992Smckusick 			fp->fflags = 0;
579*11992Smckusick 		len = strlen(fmtentry(fp));
580*11992Smckusick 		if (len > width)
581*11992Smckusick 			width = len;
582*11992Smckusick 	}
583*11992Smckusick 	width += 2;
584*11992Smckusick 	columns = 80 / width;
585*11992Smckusick 	if (columns == 0)
586*11992Smckusick 		columns = 1;
587*11992Smckusick 	lines = (nentry + columns - 1) / columns;
588*11992Smckusick 	for (i = 0; i < lines; i++) {
589*11992Smckusick 		for (j = 0; j < columns; j++) {
590*11992Smckusick 			fp = fp0 + j * lines + i;
591*11992Smckusick 			cp = fmtentry(fp);
592*11992Smckusick 			fprintf(stderr, "%s", cp);
593*11992Smckusick 			if (fp + lines >= fplast) {
594*11992Smckusick 				fprintf(stderr, "\n");
595*11992Smckusick 				break;
596*11992Smckusick 			}
597*11992Smckusick 			w = strlen(cp);
598*11992Smckusick 			while (w < width) {
599*11992Smckusick 				w++;
600*11992Smckusick 				fprintf(stderr, " ");
601*11992Smckusick 			}
602*11992Smckusick 		}
603*11992Smckusick 	}
604*11992Smckusick }
605*11992Smckusick 
606*11992Smckusick /*
607*11992Smckusick  * Comparison routine for qsort.
608*11992Smckusick  */
609*11992Smckusick fcmp(f1, f2)
610*11992Smckusick 	register struct afile *f1, *f2;
611*11992Smckusick {
612*11992Smckusick 
613*11992Smckusick 	return (strcmp(f1->fname, f2->fname));
614*11992Smckusick }
615*11992Smckusick 
616*11992Smckusick /*
617*11992Smckusick  * Format a directory entry.
618*11992Smckusick  */
619*11992Smckusick char *
620*11992Smckusick fmtentry(fp)
621*11992Smckusick 	register struct afile *fp;
622*11992Smckusick {
623*11992Smckusick 	static char fmtres[BUFSIZ];
624*11992Smckusick 	register char *cp, *dp;
625*11992Smckusick 
626*11992Smckusick 	if (vflag)
627*11992Smckusick 		(void) sprintf(fmtres, "%5d ", fp->fnum);
628*11992Smckusick 	else
629*11992Smckusick 		fmtres[0] = '\0';
630*11992Smckusick 	dp = &fmtres[strlen(fmtres)];
631*11992Smckusick 	if ((fp->fflags & NEW) != 0)
632*11992Smckusick 		*dp++ = '*';
633*11992Smckusick 	else
634*11992Smckusick 		*dp++ = ' ';
635*11992Smckusick 	for (cp = fp->fname; *cp; cp++)
636*11992Smckusick 		if (!vflag && (*cp < ' ' || *cp >= 0177))
637*11992Smckusick 			*dp++ = '?';
638*11992Smckusick 		else
639*11992Smckusick 			*dp++ = *cp;
640*11992Smckusick 	if (fp->ftype == NODE)
641*11992Smckusick 		*dp++ = '/';
642*11992Smckusick 	*dp++ = 0;
643*11992Smckusick 	return (fmtres);
644*11992Smckusick }
645*11992Smckusick 
646*11992Smckusick /*
647*11992Smckusick  * Determine the type of an inode
648*11992Smckusick  */
649*11992Smckusick inodetype(ino)
650*11992Smckusick 	ino_t ino;
651*11992Smckusick {
652*11992Smckusick 	struct inotab *itp;
653*11992Smckusick 
654*11992Smckusick 	itp = inotablookup(ino);
655*11992Smckusick 	if (itp == NULL)
656*11992Smckusick 		return (LEAF);
657*11992Smckusick 	return (NODE);
658*11992Smckusick }
659*11992Smckusick 
660*11992Smckusick /*
66111127Smckusick  * Allocate and initialize a directory inode entry.
66211127Smckusick  * If requested, save its pertinent mode, owner, and time info.
66311127Smckusick  */
66411322Smckusick struct inotab *
66511127Smckusick allocinotab(ino, dip, seekpt)
66611127Smckusick 	ino_t ino;
66711127Smckusick 	struct dinode *dip;
66811127Smckusick 	daddr_t seekpt;
66911127Smckusick {
67011127Smckusick 	register struct inotab	*itp;
67111127Smckusick 	struct modeinfo node;
67211127Smckusick 
67311127Smckusick 	itp = (struct inotab *)calloc(1, sizeof(struct inotab));
67411127Smckusick 	itp->t_next = inotab[INOHASH(ino)];
67511127Smckusick 	inotab[INOHASH(ino)] = itp;
67611127Smckusick 	itp->t_ino = ino;
67711127Smckusick 	itp->t_seekpt = seekpt;
67811127Smckusick 	if (mf == NULL)
67911322Smckusick 		return(itp);
68011127Smckusick 	node.ino = ino;
68111127Smckusick 	node.timep[0] = dip->di_atime;
68211127Smckusick 	node.timep[1] = dip->di_mtime;
68311127Smckusick 	node.mode = dip->di_mode;
68411127Smckusick 	node.uid = dip->di_uid;
68511127Smckusick 	node.gid = dip->di_gid;
68611732Smckusick 	(void) fwrite((char *)&node, 1, sizeof(struct modeinfo), mf);
68711322Smckusick 	return(itp);
68811127Smckusick }
68911127Smckusick 
69011127Smckusick /*
69111127Smckusick  * Look up an inode in the table of directories
69211127Smckusick  */
69311127Smckusick struct inotab *
69411127Smckusick inotablookup(ino)
69511127Smckusick 	ino_t	ino;
69611127Smckusick {
69711127Smckusick 	register struct inotab *itp;
69811127Smckusick 
69911127Smckusick 	for (itp = inotab[INOHASH(ino)]; itp != NULL; itp = itp->t_next)
70011127Smckusick 		if (itp->t_ino == ino)
70111127Smckusick 			return(itp);
70211127Smckusick 	return ((struct inotab *)0);
70311127Smckusick }
70411127Smckusick 
70511127Smckusick /*
70611127Smckusick  * Clean up and exit
70711127Smckusick  */
70811127Smckusick done(exitcode)
70911127Smckusick 	int exitcode;
71011127Smckusick {
71111127Smckusick 
71211127Smckusick 	closemt();
713*11992Smckusick 	if (modefile[0] != '#')
714*11992Smckusick 		(void) unlink(modefile);
715*11992Smckusick 	if (dirfile[0] != '#')
716*11992Smckusick 		(void) unlink(dirfile);
71711127Smckusick 	exit(exitcode);
71811127Smckusick }
719