155860Sbostic /*-
255860Sbostic  * Copyright (c) 1992 The Regents of the University of California.
355860Sbostic  * All rights reserved.
455860Sbostic  *
555860Sbostic  * %sccs.include.redist.c%
655860Sbostic  */
755860Sbostic 
855860Sbostic #ifndef lint
9*61416Scgd static char sccsid[] = "@(#)library.c	5.11 (Berkeley) 06/04/93";
1055860Sbostic #endif /* not lint */
1155860Sbostic 
1255491Sbostic #include <sys/param.h>
1355491Sbostic #include <sys/time.h>
1455491Sbostic #include <sys/stat.h>
1555491Sbostic #include <sys/mount.h>
1657201Smargo #include <sys/types.h>
1757201Smargo #include <sys/mman.h>
1855491Sbostic 
1955491Sbostic #include <ufs/ufs/dinode.h>
2055491Sbostic #include <ufs/lfs/lfs.h>
2155491Sbostic 
2255491Sbostic #include <fcntl.h>
2355491Sbostic #include <stdio.h>
2455856Sbostic #include <stdlib.h>
2555856Sbostic #include <string.h>
2660095Sbostic #include <unistd.h>
2760095Sbostic 
2855491Sbostic #include "clean.h"
2955491Sbostic 
3055856Sbostic void	 add_blocks __P((FS_INFO *, BLOCK_INFO *, int *, SEGSUM *, caddr_t,
3155856Sbostic 	     daddr_t, daddr_t));
3255930Sbostic void	 add_inodes __P((FS_INFO *, BLOCK_INFO *, int *, SEGSUM *, caddr_t,
3355856Sbostic 	     daddr_t));
3455856Sbostic int	 bi_compare __P((const void *, const void *));
3555856Sbostic int	 bi_toss __P((const void *, const void *, const void *));
3657201Smargo void	 get_ifile __P((FS_INFO *, int));
3755856Sbostic int	 get_superblock __P((FS_INFO *, struct lfs *));
3855856Sbostic int	 pseg_valid __P((FS_INFO *, SEGSUM *));
3955856Sbostic 
4055491Sbostic /*
4161373Scgd  * This function will get information on a a filesystem which matches
4261373Scgd  * the name and type given.  If a "name" is in a filesystem of the given
4361373Scgd  * type, then buf is filled with that filesystem's info, and the
4461373Scgd  * a non-zero value is returned.
4555491Sbostic  */
4655491Sbostic int
4761373Scgd fs_getmntinfo(buf, name, type)
4855491Sbostic 	struct	statfs	**buf;
4961373Scgd 	char	*name;
5055491Sbostic 	int	type;
5155491Sbostic {
5261373Scgd 	/* allocate space for the filesystem info */
5361373Scgd 	*buf = (struct statfs *)malloc(sizeof(struct statfs));
5461373Scgd 	if (*buf == NULL)
5561373Scgd 		return 0;
5655491Sbostic 
5761373Scgd 	/* grab the filesystem info */
5861373Scgd 	if (statfs(name, *buf) < 0) {
5961373Scgd 		free(*buf);
6061373Scgd 		return 0;
6161373Scgd 	}
6255491Sbostic 
6361373Scgd 	/* check to see if it's the one we want */
6461373Scgd 	if (((*buf)->f_type != type) ||
6561373Scgd 	    strncmp(name, (*buf)->f_mntonname, MNAMELEN)) {
6661373Scgd 		/* "this is not the filesystem you're looking for */
6761373Scgd 		free(*buf);
6861373Scgd 		return 0;
6955491Sbostic 	}
7055491Sbostic 
7161373Scgd 	return 1;
7255491Sbostic }
7355491Sbostic 
7455491Sbostic /*
7555856Sbostic  * Get all the information available on an LFS file system.
7661373Scgd  * Returns an pointer to an FS_INFO structure, NULL on error.
7755491Sbostic  */
7855856Sbostic FS_INFO *
7961373Scgd get_fs_info (lstatfsp, use_mmap)
8061373Scgd 	struct statfs *lstatfsp;	/* IN: pointer to statfs struct */
8157201Smargo 	int use_mmap;			/* IN: mmap or read */
8255491Sbostic {
8361373Scgd 	FS_INFO	*fsp;
8455491Sbostic 	int	i;
8555491Sbostic 
8661373Scgd 	fsp = (FS_INFO *)malloc(sizeof(FS_INFO));
8761373Scgd 	if (fsp == NULL)
8861373Scgd 		return NULL;
8961373Scgd 	bzero(fsp, sizeof(FS_INFO));
9055491Sbostic 
9161373Scgd 	fsp->fi_statfsp = lstatfsp;
9261373Scgd 	if (get_superblock (fsp, &fsp->fi_lfs))
9361373Scgd 		err(1, "get_fs_info: get_superblock failed");
9461373Scgd 	fsp->fi_daddr_shift =
9561373Scgd 	     fsp->fi_lfs.lfs_bshift - fsp->fi_lfs.lfs_fsbtodb;
9661373Scgd 	get_ifile (fsp, use_mmap);
9755856Sbostic 	return (fsp);
9855491Sbostic }
9955491Sbostic 
10055856Sbostic /*
10155856Sbostic  * If we are reading the ifile then we need to refresh it.  Even if
10255856Sbostic  * we are mmapping it, it might have grown.  Finally, we need to
10355856Sbostic  * refresh the file system information (statfs) info.
10455856Sbostic  */
10555491Sbostic void
10661373Scgd reread_fs_info(fsp, use_mmap)
10761373Scgd 	FS_INFO *fsp;	/* IN: prointer fs_infos to reread */
10860095Sbostic 	int use_mmap;
10955491Sbostic {
11055856Sbostic 	int i;
11155491Sbostic 
11261373Scgd 	if (statfs(fsp->fi_statfsp->f_mntonname, fsp->fi_statfsp))
113*61416Scgd 		err(1, "reread_fs_info: statfs failed");
11461373Scgd 	get_ifile (fsp, use_mmap);
11555491Sbostic }
11655491Sbostic 
11755491Sbostic /*
11855856Sbostic  * Gets the superblock from disk (possibly in face of errors)
11955491Sbostic  */
12055491Sbostic int
12155491Sbostic get_superblock (fsp, sbp)
12255856Sbostic 	FS_INFO *fsp;		/* local file system info structure */
12355856Sbostic 	struct lfs *sbp;
12455491Sbostic {
12555856Sbostic 	char mntfromname[MNAMELEN+1];
12655856Sbostic         int fid;
12755491Sbostic 
12855491Sbostic 	strcpy(mntfromname, "/dev/r");
12955856Sbostic 	strcat(mntfromname, fsp->fi_statfsp->f_mntfromname+5);
13055491Sbostic 
13155491Sbostic 	if ((fid = open(mntfromname, O_RDONLY, (mode_t)0)) < 0) {
13255856Sbostic 		err(0, "get_superblock: bad open");
13355856Sbostic 		return (-1);
13455491Sbostic 	}
13555491Sbostic 
13655856Sbostic 	get(fid, LFS_LABELPAD, sbp, sizeof(struct lfs));
13755491Sbostic 	close (fid);
13855491Sbostic 
13955856Sbostic 	return (0);
14055491Sbostic }
14155491Sbostic 
14255491Sbostic /*
14355856Sbostic  * This function will map the ifile into memory.  It causes a
14455856Sbostic  * fatal error on failure.
14555491Sbostic  */
14655856Sbostic void
14757201Smargo get_ifile (fsp, use_mmap)
14855491Sbostic 	FS_INFO	*fsp;
14957201Smargo 	int use_mmap;
15057201Smargo 
15155491Sbostic {
15255856Sbostic 	struct stat file_stat;
15355856Sbostic 	caddr_t ifp;
15455856Sbostic 	char *ifile_name;
15555856Sbostic 	int count, fid;
15655491Sbostic 
15755856Sbostic 	ifp = NULL;
15855856Sbostic 	ifile_name = malloc(strlen(fsp->fi_statfsp->f_mntonname) +
15955856Sbostic 	    strlen(IFILE_NAME)+2);
16055856Sbostic 	strcat(strcat(strcpy(ifile_name, fsp->fi_statfsp->f_mntonname), "/"),
16155856Sbostic 	    IFILE_NAME);
16255491Sbostic 
16355856Sbostic 	if ((fid = open(ifile_name, O_RDWR, (mode_t)0)) < 0)
16455856Sbostic 		err(1, "get_ifile: bad open");
16555491Sbostic 
16655856Sbostic 	if (fstat (fid, &file_stat))
16755856Sbostic 		err(1, "get_ifile: fstat failed");
16855491Sbostic 
16957201Smargo 	if (use_mmap && file_stat.st_size == fsp->fi_ifile_length) {
17057201Smargo 		(void) close(fid);
17157201Smargo 		return;
17257201Smargo 	}
17355856Sbostic 
17455491Sbostic 	/* get the ifile */
17557201Smargo 	if (use_mmap) {
17657201Smargo 		if (fsp->fi_cip)
17757201Smargo 			munmap((caddr_t)fsp->fi_cip, fsp->fi_ifile_length);
17857201Smargo 		ifp = mmap ((caddr_t)0, file_stat.st_size,
17957201Smargo 		    PROT_READ|PROT_WRITE, 0, fid, (off_t)0);
18057201Smargo 		if (ifp ==  (caddr_t)(-1))
18157201Smargo 			err(1, "get_ifile: mmap failed");
18257201Smargo 	} else {
18357201Smargo 		if (fsp->fi_cip)
18457201Smargo 			free(fsp->fi_cip);
18557201Smargo 		if (!(ifp = malloc (file_stat.st_size)))
18657201Smargo 			err (1, "get_ifile: malloc failed");
18755856Sbostic redo_read:
18857201Smargo 		count = read (fid, ifp, (size_t) file_stat.st_size);
18955491Sbostic 
19057201Smargo 		if (count < 0)
19157201Smargo 			err(1, "get_ifile: bad ifile read");
19257201Smargo 		else if (count < file_stat.st_size) {
19357201Smargo 			err(0, "get_ifile");
19457201Smargo 			if (lseek(fid, 0, SEEK_SET) < 0)
19557201Smargo 				err(1, "get_ifile: bad ifile lseek");
19657201Smargo 			goto redo_read;
19757201Smargo 		}
19855491Sbostic 	}
19957201Smargo 	fsp->fi_ifile_length = file_stat.st_size;
20055491Sbostic 	close (fid);
20155491Sbostic 
20255856Sbostic 	fsp->fi_cip = (CLEANERINFO *)ifp;
20355856Sbostic 	fsp->fi_segusep = (SEGUSE *)(ifp + CLEANSIZE(fsp));
20455856Sbostic 	fsp->fi_ifilep  = (IFILE *)((caddr_t)fsp->fi_segusep + SEGTABSIZE(fsp));
20555856Sbostic 
20655856Sbostic 	/*
20755856Sbostic 	 * The number of ifile entries is equal to the number of blocks
20855856Sbostic 	 * blocks in the ifile minus the ones allocated to cleaner info
20955856Sbostic 	 * and segment usage table multiplied by the number of ifile
21055856Sbostic 	 * entries per page.
21155856Sbostic 	 */
21255856Sbostic 	fsp->fi_ifile_count = (fsp->fi_ifile_length >> fsp->fi_lfs.lfs_bshift -
21355856Sbostic 	    fsp->fi_lfs.lfs_cleansz - fsp->fi_lfs.lfs_segtabsz) *
21455856Sbostic 	    fsp->fi_lfs.lfs_ifpb;
21555856Sbostic 
21655491Sbostic 	free (ifile_name);
21755491Sbostic }
21855491Sbostic 
21955491Sbostic /*
22055856Sbostic  * This function will scan a segment and return a list of
22155491Sbostic  * <inode, blocknum> pairs which indicate which blocks were
22255856Sbostic  * contained as live data within the segment when the segment
22355856Sbostic  * summary was read (it may have "died" since then).  Any given
22455856Sbostic  * pair will be listed at most once.
22555491Sbostic  */
22655491Sbostic int
22755930Sbostic lfs_segmapv(fsp, seg, seg_buf, blocks, bcount)
22855856Sbostic 	FS_INFO *fsp;		/* pointer to local file system information */
22955856Sbostic 	int seg;		/* the segment number */
23055856Sbostic 	caddr_t seg_buf;	/* the buffer containing the segment's data */
23155856Sbostic 	BLOCK_INFO **blocks;	/* OUT: array of block_info for live blocks */
23255856Sbostic 	int *bcount;		/* OUT: number of active blocks in segment */
23355491Sbostic {
23455856Sbostic 	BLOCK_INFO *bip;
23555856Sbostic 	SEGSUM *sp;
23655856Sbostic 	SEGUSE *sup;
23756623Smargo 	FINFO *fip;
23855856Sbostic 	struct lfs *lfsp;
23955856Sbostic 	caddr_t s, segend;
24055856Sbostic 	daddr_t pseg_addr, seg_addr;
24156623Smargo 	int i, nelem, nblocks, sumsize;
24255856Sbostic 	time_t timestamp;
24355491Sbostic 
24455856Sbostic 	lfsp = &fsp->fi_lfs;
24555930Sbostic 	nelem = 2 * lfsp->lfs_ssize;
24655930Sbostic 	if (!(bip = malloc(nelem * sizeof(BLOCK_INFO))))
24755856Sbostic 		goto err0;
24855491Sbostic 
24955856Sbostic 	sup = SEGUSE_ENTRY(lfsp, fsp->fi_segusep, seg);
25055856Sbostic 	s = seg_buf + (sup->su_flags & SEGUSE_SUPERBLOCK ? LFS_SBPAD : 0);
25155856Sbostic 	seg_addr = sntoda(lfsp, seg);
25255856Sbostic 	pseg_addr = seg_addr + (sup->su_flags & SEGUSE_SUPERBLOCK ? btodb(LFS_SBPAD) : 0);
25355856Sbostic #ifdef VERBOSE
25455856Sbostic 		printf("\tsegment buffer at: 0x%x\tseg_addr 0x%x\n", s, seg_addr);
25555856Sbostic #endif /* VERBOSE */
25655491Sbostic 
25755856Sbostic 	*bcount = 0;
25855856Sbostic 	for (segend = seg_buf + seg_size(lfsp), timestamp = 0; s < segend; ) {
25955856Sbostic 		sp = (SEGSUM *)s;
26056623Smargo 
26155491Sbostic #ifdef VERBOSE
26255856Sbostic 		printf("\tpartial at: 0x%x\n", pseg_addr);
26355856Sbostic 		print_SEGSUM(lfsp, sp);
26455491Sbostic 		fflush(stdout);
26555491Sbostic #endif /* VERBOSE */
26655491Sbostic 
26755856Sbostic 		nblocks = pseg_valid(fsp, sp);
26855856Sbostic 		if (nblocks <= 0)
26955856Sbostic 			break;
27055491Sbostic 
27155856Sbostic 		/* Check if we have hit old data */
27255856Sbostic 		if (timestamp > ((SEGSUM*)s)->ss_create)
27355856Sbostic 			break;
27455491Sbostic 		timestamp = ((SEGSUM*)s)->ss_create;
27555491Sbostic 
27656623Smargo #ifdef DIAGNOSTIC
27756623Smargo 		/* Verfiy size of summary block */
27856623Smargo 		sumsize = sizeof(SEGSUM) +
27956623Smargo 		    (sp->ss_ninos + INOPB(lfsp) - 1) / INOPB(lfsp);
28056623Smargo 		for (fip = (FINFO *)(sp + 1); i < sp->ss_nfinfo; ++i) {
28156623Smargo 			sumsize += sizeof(FINFO) +
28256623Smargo 			    (fip->fi_nblocks - 1) * sizeof(daddr_t);
28356623Smargo 			fip = (FINFO *)(&fip->fi_blocks[fip->fi_nblocks]);
28456623Smargo 		}
28556623Smargo 		if (sumsize > LFS_SUMMARY_SIZE) {
28656623Smargo 			fprintf(stderr,
28756623Smargo 			    "Segment %d summary block too big: %d\n",
28856623Smargo 			    seg, sumsize);
28956623Smargo 			exit(1);
29056623Smargo 		}
29156623Smargo #endif
29256623Smargo 
29355930Sbostic 		if (*bcount + nblocks + sp->ss_ninos > nelem) {
29455930Sbostic 			nelem = *bcount + nblocks + sp->ss_ninos;
29555930Sbostic 			bip = realloc (bip, nelem * sizeof(BLOCK_INFO));
29655930Sbostic 			if (!bip)
29755930Sbostic 				goto err0;
29855856Sbostic 		}
29955856Sbostic 		add_blocks(fsp, bip, bcount, sp, seg_buf, seg_addr, pseg_addr);
30055930Sbostic 		add_inodes(fsp, bip, bcount, sp, seg_buf, seg_addr);
30155856Sbostic 		pseg_addr += fsbtodb(lfsp, nblocks) +
30255856Sbostic 		    bytetoda(fsp, LFS_SUMMARY_SIZE);
30355856Sbostic 		s += (nblocks << lfsp->lfs_bshift) + LFS_SUMMARY_SIZE;
30455856Sbostic 	}
30555856Sbostic 	qsort(bip, *bcount, sizeof(BLOCK_INFO), bi_compare);
30655856Sbostic 	toss(bip, bcount, sizeof(BLOCK_INFO), bi_toss, NULL);
30755856Sbostic #ifdef VERBOSE
30855856Sbostic 	{
30955856Sbostic 		BLOCK_INFO *_bip;
31055856Sbostic 		int i;
31155491Sbostic 
31255856Sbostic 		printf("BLOCK INFOS\n");
31355856Sbostic 		for (_bip = bip, i=0; i < *bcount; ++_bip, ++i)
31455856Sbostic 			PRINT_BINFO(_bip);
31555491Sbostic 	}
31655856Sbostic #endif
31755856Sbostic 	*blocks = bip;
31855856Sbostic 	return (0);
31955856Sbostic 
32055856Sbostic err0:	*bcount = 0;
32155856Sbostic 	return (-1);
32255491Sbostic 
32355491Sbostic }
32455491Sbostic 
32555491Sbostic /*
32655856Sbostic  * This will parse a partial segment and fill in BLOCK_INFO structures
32755856Sbostic  * for each block described in the segment summary.  It will not include
32855856Sbostic  * blocks or inodes from files with new version numbers.
32955491Sbostic  */
33055491Sbostic void
33155856Sbostic add_blocks (fsp, bip, countp, sp, seg_buf, segaddr, psegaddr)
33255491Sbostic 	FS_INFO *fsp;		/* pointer to super block */
33355856Sbostic 	BLOCK_INFO *bip;	/* Block info array */
33455856Sbostic 	int *countp;		/* IN/OUT: number of blocks in array */
33555856Sbostic 	SEGSUM	*sp;		/* segment summmary pointer */
33655856Sbostic 	caddr_t seg_buf;	/* buffer containing segment */
33755856Sbostic 	daddr_t segaddr;	/* address of this segment */
33855856Sbostic 	daddr_t psegaddr;	/* address of this partial segment */
33955491Sbostic {
34055856Sbostic 	IFILE	*ifp;
34155856Sbostic 	FINFO	*fip;
34255856Sbostic 	caddr_t	bp;
34355930Sbostic 	daddr_t	*dp, *iaddrp;
34455856Sbostic 	int db_per_block, i, j;
34555856Sbostic 	u_long page_size;
34655491Sbostic 
34755491Sbostic #ifdef VERBOSE
34855856Sbostic 	printf("FILE INFOS\n");
34955491Sbostic #endif
35055856Sbostic 	db_per_block = fsbtodb(&fsp->fi_lfs, 1);
35155856Sbostic 	page_size = fsp->fi_lfs.lfs_bsize;
35255856Sbostic 	bp = seg_buf + datobyte(fsp, psegaddr - segaddr) + LFS_SUMMARY_SIZE;
35355856Sbostic 	bip += *countp;
35455856Sbostic 	psegaddr += bytetoda(fsp, LFS_SUMMARY_SIZE);
35555856Sbostic 	iaddrp = (daddr_t *)((caddr_t)sp + LFS_SUMMARY_SIZE);
35655856Sbostic 	--iaddrp;
35755856Sbostic 	for (fip = (FINFO *)(sp + 1), i = 0; i < sp->ss_nfinfo;
35855856Sbostic 	    ++i, fip = (FINFO *)(&fip->fi_blocks[fip->fi_nblocks])) {
35955491Sbostic 
36055856Sbostic 		ifp = IFILE_ENTRY(&fsp->fi_lfs, fsp->fi_ifilep, fip->fi_ino);
36155856Sbostic 		PRINT_FINFO(fip, ifp);
36255856Sbostic 		if (ifp->if_version > fip->fi_version)
36355491Sbostic 			continue;
36455856Sbostic 		dp = &(fip->fi_blocks[0]);
36555856Sbostic 		for (j = 0; j < fip->fi_nblocks; j++, dp++) {
36655856Sbostic 			while (psegaddr == *iaddrp) {
36755856Sbostic 				psegaddr += db_per_block;
36855856Sbostic 				bp += page_size;
36955856Sbostic 				--iaddrp;
37055491Sbostic 			}
37155856Sbostic 			bip->bi_inode = fip->fi_ino;
37255856Sbostic 			bip->bi_lbn = *dp;
37355856Sbostic 			bip->bi_daddr = psegaddr;
37455856Sbostic 			bip->bi_segcreate = (time_t)(sp->ss_create);
37555856Sbostic 			bip->bi_bp = bp;
37656193Smargo 			bip->bi_version = ifp->if_version;
37755856Sbostic 			psegaddr += db_per_block;
37855856Sbostic 			bp += page_size;
37955856Sbostic 			++bip;
38055856Sbostic 			++(*countp);
38155491Sbostic 		}
38255491Sbostic 	}
38355491Sbostic }
38455491Sbostic 
38555856Sbostic /*
38655856Sbostic  * For a particular segment summary, reads the inode blocks and adds
38755856Sbostic  * INODE_INFO structures to the array.  Returns the number of inodes
38855856Sbostic  * actually added.
38955856Sbostic  */
39055491Sbostic void
39155930Sbostic add_inodes (fsp, bip, countp, sp, seg_buf, seg_addr)
39255491Sbostic 	FS_INFO *fsp;		/* pointer to super block */
39355930Sbostic 	BLOCK_INFO *bip;	/* block info array */
39455856Sbostic 	int *countp;		/* pointer to current number of inodes */
39555856Sbostic 	SEGSUM *sp;		/* segsum pointer */
39655491Sbostic 	caddr_t	seg_buf;	/* the buffer containing the segment's data */
39755856Sbostic 	daddr_t	seg_addr;	/* disk address of seg_buf */
39855491Sbostic {
39955856Sbostic 	struct dinode *di;
40055856Sbostic 	struct lfs *lfsp;
40155856Sbostic 	IFILE *ifp;
40255930Sbostic 	BLOCK_INFO *bp;
40355856Sbostic 	daddr_t	*daddrp;
40455856Sbostic 	ino_t inum;
40555856Sbostic 	int i;
40655491Sbostic 
40755856Sbostic 	if (sp->ss_ninos <= 0)
40855856Sbostic 		return;
40955491Sbostic 
41055930Sbostic 	bp = bip + *countp;
41155856Sbostic 	lfsp = &fsp->fi_lfs;
41255491Sbostic #ifdef VERBOSE
41355930Sbostic 	(void) printf("INODES:\n");
41455491Sbostic #endif
41555856Sbostic 	daddrp = (daddr_t *)((caddr_t)sp + LFS_SUMMARY_SIZE);
41655856Sbostic 	for (i = 0; i < sp->ss_ninos; ++i) {
41755491Sbostic 		if (i % INOPB(lfsp) == 0) {
41855856Sbostic 			--daddrp;
41955856Sbostic 			di = (struct dinode *)(seg_buf +
42055856Sbostic 			    ((*daddrp - seg_addr) << fsp->fi_daddr_shift));
42155491Sbostic 		} else
42255491Sbostic 			++di;
42355491Sbostic 
42457201Smargo 		inum = di->di_inumber;
42555930Sbostic 		bp->bi_lbn = LFS_UNUSED_LBN;
42655930Sbostic 		bp->bi_inode = inum;
42755930Sbostic 		bp->bi_daddr = *daddrp;
42855930Sbostic 		bp->bi_bp = di;
42955930Sbostic 		bp->bi_segcreate = sp->ss_create;
43055491Sbostic 
43156036Sbostic 		if (inum == LFS_IFILE_INUM) {
43256193Smargo 			bp->bi_version = 1;	/* Ifile version should be 1 */
43355930Sbostic 			bp++;
43455856Sbostic 			++(*countp);
43556036Sbostic 			PRINT_INODE(1, bp);
43656036Sbostic 		} else {
43756036Sbostic 			ifp = IFILE_ENTRY(lfsp, fsp->fi_ifilep, inum);
43856036Sbostic 			PRINT_INODE(ifp->if_daddr == *daddrp, bp);
43956193Smargo 			bp->bi_version = ifp->if_version;
44056036Sbostic 			if (ifp->if_daddr == *daddrp) {
44156036Sbostic 				bp++;
44256036Sbostic 				++(*countp);
44356036Sbostic 			}
44456036Sbostic 		}
44555491Sbostic 	}
44655491Sbostic }
44755491Sbostic 
44855491Sbostic /*
44955856Sbostic  * Checks the summary checksum and the data checksum to determine if the
45055856Sbostic  * segment is valid or not.  Returns the size of the partial segment if it
45155856Sbostic  * is valid, * and 0 otherwise.  Use dump_summary to figure out size of the
45255856Sbostic  * the partial as well as whether or not the checksum is valid.
45355491Sbostic  */
45455491Sbostic int
45555491Sbostic pseg_valid (fsp, ssp)
45655491Sbostic 	FS_INFO *fsp;   /* pointer to file system info */
45755856Sbostic 	SEGSUM *ssp;	/* pointer to segment summary block */
45855491Sbostic {
45955491Sbostic 	caddr_t	p;
46055856Sbostic 	int i, nblocks;
46155856Sbostic 	u_long *datap;
46255491Sbostic 
46356655Sbostic 	if ((nblocks = dump_summary(&fsp->fi_lfs, ssp, 0, NULL)) <= 0 ||
46456655Sbostic 	    nblocks > fsp->fi_lfs.lfs_ssize - 1)
46555856Sbostic 		return(0);
46655491Sbostic 
46755856Sbostic 	/* check data/inode block(s) checksum too */
46855856Sbostic 	datap = (u_long *)malloc(nblocks * sizeof(u_long));
46955491Sbostic 	p = (caddr_t)ssp + LFS_SUMMARY_SIZE;
47055856Sbostic 	for (i = 0; i < nblocks; ++i) {
47155491Sbostic 		datap[i] = *((u_long *)p);
47255856Sbostic 		p += fsp->fi_lfs.lfs_bsize;
47355491Sbostic 	}
47455856Sbostic 	if (cksum ((void *)datap, nblocks * sizeof(u_long)) != ssp->ss_datasum)
47555856Sbostic 		return (0);
47655491Sbostic 
47755856Sbostic 	return (nblocks);
47855491Sbostic }
47955491Sbostic 
48055491Sbostic 
48155491Sbostic /* #define MMAP_SEGMENT */
48255491Sbostic /*
48355491Sbostic  * read a segment into a memory buffer
48455491Sbostic  */
48555491Sbostic int
48657201Smargo mmap_segment (fsp, segment, segbuf, use_mmap)
48755856Sbostic 	FS_INFO *fsp;		/* file system information */
48855856Sbostic 	int segment;		/* segment number */
48955856Sbostic 	caddr_t *segbuf;	/* pointer to buffer area */
49057201Smargo 	int use_mmap;		/* mmap instead of read */
49155491Sbostic {
49255856Sbostic 	struct lfs *lfsp;
49355856Sbostic 	int fid;		/* fildes for file system device */
49455856Sbostic 	daddr_t seg_daddr;	/* base disk address of segment */
49555856Sbostic 	off_t seg_byte;
49655856Sbostic 	size_t ssize;
49755856Sbostic 	char mntfromname[MNAMELEN+2];
49855491Sbostic 
49955856Sbostic 	lfsp = &fsp->fi_lfs;
50055856Sbostic 
50155491Sbostic 	/* get the disk address of the beginning of the segment */
50255491Sbostic 	seg_daddr = sntoda(lfsp, segment);
50355856Sbostic 	seg_byte = datobyte(fsp, seg_daddr);
50455856Sbostic 	ssize = seg_size(lfsp);
50555491Sbostic 
50655491Sbostic 	strcpy(mntfromname, "/dev/r");
50755856Sbostic 	strcat(mntfromname, fsp->fi_statfsp->f_mntfromname+5);
50855491Sbostic 
50955491Sbostic 	if ((fid = open(mntfromname, O_RDONLY, (mode_t)0)) < 0) {
51055856Sbostic 		err(0, "mmap_segment: bad open");
51155856Sbostic 		return (-1);
51255491Sbostic 	}
51355491Sbostic 
51457201Smargo 	if (use_mmap) {
51557201Smargo 		*segbuf = mmap ((caddr_t)0, seg_size(lfsp), PROT_READ,
51657201Smargo 		    0, fid, seg_byte);
51757201Smargo 		if (*(long *)segbuf < 0) {
51857201Smargo 			err(0, "mmap_segment: mmap failed");
51957201Smargo 			return (NULL);
52057201Smargo 		}
52157201Smargo 	} else {
52255856Sbostic #ifdef VERBOSE
52357201Smargo 		printf("mmap_segment\tseg_daddr: %lu\tseg_size: %lu\tseg_offset: %qu\n",
52457201Smargo 		    seg_daddr, ssize, seg_byte);
52555856Sbostic #endif
52657201Smargo 		/* malloc the space for the buffer */
52757201Smargo 		*segbuf = malloc(ssize);
52857201Smargo 		if (!*segbuf) {
52957201Smargo 			err(0, "mmap_segment: malloc failed");
53057201Smargo 			return(NULL);
53157201Smargo 		}
53255491Sbostic 
53357201Smargo 		/* read the segment data into the buffer */
53457201Smargo 		if (lseek (fid, seg_byte, SEEK_SET) != seg_byte) {
53557201Smargo 			err (0, "mmap_segment: bad lseek");
53657201Smargo 			free(*segbuf);
53757201Smargo 			return (-1);
53857201Smargo 		}
53957201Smargo 
54057201Smargo 		if (read (fid, *segbuf, ssize) != ssize) {
54157201Smargo 			err (0, "mmap_segment: bad read");
54257201Smargo 			free(*segbuf);
54357201Smargo 			return (-1);
54457201Smargo 		}
54555491Sbostic 	}
54655491Sbostic 	close (fid);
54755491Sbostic 
54855856Sbostic 	return (0);
54955491Sbostic }
55055491Sbostic 
55155491Sbostic void
55257201Smargo munmap_segment (fsp, seg_buf, use_mmap)
55355856Sbostic 	FS_INFO *fsp;		/* file system information */
55455856Sbostic 	caddr_t seg_buf;	/* pointer to buffer area */
55557201Smargo 	int use_mmap;		/* mmap instead of read/write */
55655491Sbostic {
55757201Smargo 	if (use_mmap)
55857201Smargo 		munmap (seg_buf, seg_size(&fsp->fi_lfs));
55957201Smargo 	else
56057201Smargo 		free (seg_buf);
56155491Sbostic }
56255491Sbostic 
56355491Sbostic 
56455491Sbostic /*
56555491Sbostic  * USEFUL DEBUGGING TOOLS:
56655491Sbostic  */
56755491Sbostic void
56855856Sbostic print_SEGSUM (lfsp, p)
56955856Sbostic 	struct lfs *lfsp;
57055856Sbostic 	SEGSUM	*p;
57155491Sbostic {
57255856Sbostic 	if (p)
57355856Sbostic 		(void) dump_summary(lfsp, p, DUMP_ALL, NULL);
57455491Sbostic 	else printf("0x0");
57555491Sbostic 	fflush(stdout);
57655491Sbostic }
57755491Sbostic 
57855856Sbostic int
57955856Sbostic bi_compare(a, b)
58055856Sbostic 	const void *a;
58155856Sbostic 	const void *b;
58255491Sbostic {
58355856Sbostic 	const BLOCK_INFO *ba, *bb;
58455856Sbostic 	int diff;
58555491Sbostic 
58655856Sbostic 	ba = a;
58755856Sbostic 	bb = b;
58855491Sbostic 
58955856Sbostic 	if (diff = (int)(ba->bi_inode - bb->bi_inode))
59055856Sbostic 		return (diff);
59155930Sbostic 	if (diff = (int)(ba->bi_lbn - bb->bi_lbn)) {
59255930Sbostic 		if (ba->bi_lbn == LFS_UNUSED_LBN)
59355930Sbostic 			return(-1);
59455930Sbostic 		else if (bb->bi_lbn == LFS_UNUSED_LBN)
59555930Sbostic 			return(1);
59656623Smargo 		else if (ba->bi_lbn < 0 && bb->bi_lbn >= 0)
59755930Sbostic 			return(1);
59856623Smargo 		else if (bb->bi_lbn < 0 && ba->bi_lbn >= 0)
59956623Smargo 			return(-1);
60055930Sbostic 		else
60155930Sbostic 			return (diff);
60255930Sbostic 	}
60355856Sbostic 	if (diff = (int)(ba->bi_segcreate - bb->bi_segcreate))
60455856Sbostic 		return (diff);
60555856Sbostic 	diff = (int)(ba->bi_daddr - bb->bi_daddr);
60655856Sbostic 	return (diff);
60755856Sbostic }
60855491Sbostic 
60955856Sbostic int
61055856Sbostic bi_toss(dummy, a, b)
61155856Sbostic 	const void *dummy;
61255856Sbostic 	const void *a;
61355856Sbostic 	const void *b;
61455491Sbostic {
61555856Sbostic 	const BLOCK_INFO *ba, *bb;
61655491Sbostic 
61755856Sbostic 	ba = a;
61855856Sbostic 	bb = b;
61955856Sbostic 
62055856Sbostic 	return(ba->bi_inode == bb->bi_inode && ba->bi_lbn == bb->bi_lbn);
62155491Sbostic }
62255491Sbostic 
62355491Sbostic void
62455856Sbostic toss(p, nump, size, dotoss, client)
62555856Sbostic 	void *p;
62655856Sbostic 	int *nump;
62755856Sbostic 	size_t size;
62855856Sbostic 	int (*dotoss) __P((const void *, const void *, const void *));
62955856Sbostic 	void *client;
63055491Sbostic {
63155856Sbostic 	int i;
63255856Sbostic 	void *p1;
63355491Sbostic 
63455856Sbostic 	if (*nump == 0)
63555856Sbostic 		return;
63655491Sbostic 
63755856Sbostic 	for (i = *nump; --i > 0;) {
63855856Sbostic 		p1 = p + size;
63955856Sbostic 		if (dotoss(client, p, p1)) {
64060095Sbostic 			memmove(p, p1, i * size);
64155856Sbostic 			--(*nump);
64255856Sbostic 		} else
64355856Sbostic 			p += size;
64455491Sbostic 	}
64555491Sbostic }
646