1 #include <sys/param.h>
2 #include <sys/time.h>
3 #include <sys/stat.h>
4 #include <sys/mount.h>
5 
6 #include <ufs/ufs/dinode.h>
7 #include <ufs/lfs/lfs.h>
8 
9 #include <fcntl.h>
10 #include <stdio.h>
11 #include <unistd.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include "clean.h"
15 
16 void	 add_blocks __P((FS_INFO *, BLOCK_INFO *, int *, SEGSUM *, caddr_t,
17 	     daddr_t, daddr_t));
18 void	 add_inodes __P((FS_INFO *, INODE_INFO *, int *, SEGSUM *, caddr_t,
19 	     daddr_t));
20 int	 bi_compare __P((const void *, const void *));
21 int	 bi_toss __P((const void *, const void *, const void *));
22 void	 get_ifile __P((FS_INFO *));
23 int	 get_superblock __P((FS_INFO *, struct lfs *));
24 int	 ii_compare __P((const void *, const void *));
25 int	 ii_toss __P((const void *, const void *, const void *));
26 int	 pseg_valid __P((FS_INFO *, SEGSUM *));
27 
28 /*
29  * This function will get information on all mounted file systems
30  * of a given type.
31  */
32 int
33 fs_getmntinfo(buf, type)
34 	struct	statfs	**buf;
35 	int	type;
36 {
37 	struct statfs *tstatfsp;
38 	struct statfs *sbp;
39 	int count, i, tcount;
40 
41 	tcount = getmntinfo(&tstatfsp, 0);
42 
43 	if (tcount < 0) {
44 		err(0, "getmntinfo failed");
45 		return (-1);
46 	}
47 
48 	for (count = 0, i = 0; i < tcount ; ++i)
49 		if (tstatfsp[i].f_type == type)
50 			++count;
51 
52 	if (count) {
53 		if (!(*buf = (struct statfs *)
54 			malloc(count * sizeof(struct statfs))))
55 			err(1, "fs_getmntinfo: out of space");
56 		for (i = 0, sbp = *buf; i < tcount ; ++i) {
57 			if (tstatfsp[i].f_type == type) {
58 				*sbp = tstatfsp[i];
59 				++sbp;
60 			}
61 		}
62 	}
63 	return (count);
64 }
65 
66 /*
67  * Get all the information available on an LFS file system.
68  * Returns an array of FS_INFO structures, NULL on error.
69  */
70 FS_INFO *
71 get_fs_info (lstatfsp, count)
72 	struct statfs *lstatfsp;	/* IN: array of statfs structs */
73 	int count;			/* IN: number of file systems */
74 {
75 	FS_INFO	*fp, *fsp;
76 	int	i;
77 
78 	fsp = (FS_INFO *)malloc(count * sizeof(FS_INFO));
79 
80 	for (fp = fsp, i = 0; i < count; ++i, ++fp) {
81 		fp->fi_statfsp = lstatfsp++;
82 		if (get_superblock (fp, &fp->fi_lfs))
83 			err(1, "get_fs_info: get_superblock failed");
84 		fp->fi_daddr_shift =
85 		     fp->fi_lfs.lfs_bshift - fp->fi_lfs.lfs_fsbtodb;
86 		get_ifile (fp);
87 	}
88 	return (fsp);
89 }
90 
91 /*
92  * If we are reading the ifile then we need to refresh it.  Even if
93  * we are mmapping it, it might have grown.  Finally, we need to
94  * refresh the file system information (statfs) info.
95  */
96 void
97 reread_fs_info(fsp, count)
98 	FS_INFO *fsp;	/* IN: array of fs_infos to free */
99 	int count;	/* IN: number of file systems */
100 {
101 	int i;
102 
103 	for (i = 0; i < count; ++i, ++fsp) {
104 		if (statfs(fsp->fi_statfsp->f_mntonname, fsp->fi_statfsp))
105 			err(0, "reread_fs_info: statfs failed");
106 #ifdef MMAP_WORKS
107 		if (munmap(fsp->fi_cip, fsp->fi_ifile_length) < 0)
108 			err(0, "reread_fs_info: munmap failed");
109 #else
110 		free (fsp->fi_cip);
111 #endif /* MMAP_WORKS */
112 		get_ifile (fsp);
113 	}
114 }
115 
116 /*
117  * Gets the superblock from disk (possibly in face of errors)
118  */
119 int
120 get_superblock (fsp, sbp)
121 	FS_INFO *fsp;		/* local file system info structure */
122 	struct lfs *sbp;
123 {
124 	char mntfromname[MNAMELEN+1];
125         int fid;
126 
127 	strcpy(mntfromname, "/dev/r");
128 	strcat(mntfromname, fsp->fi_statfsp->f_mntfromname+5);
129 
130 	if ((fid = open(mntfromname, O_RDONLY, (mode_t)0)) < 0) {
131 		err(0, "get_superblock: bad open");
132 		return (-1);
133 	}
134 
135 	get(fid, LFS_LABELPAD, sbp, sizeof(struct lfs));
136 	close (fid);
137 
138 	return (0);
139 }
140 
141 /*
142  * This function will map the ifile into memory.  It causes a
143  * fatal error on failure.
144  */
145 void
146 get_ifile (fsp)
147 	FS_INFO	*fsp;
148 {
149 	struct stat file_stat;
150 	caddr_t ifp;
151 	char *ifile_name;
152 	int count, fid;
153 
154 	ifp = NULL;
155 	sync();
156 	ifile_name = malloc(strlen(fsp->fi_statfsp->f_mntonname) +
157 	    strlen(IFILE_NAME)+2);
158 	strcat(strcat(strcpy(ifile_name, fsp->fi_statfsp->f_mntonname), "/"),
159 	    IFILE_NAME);
160 
161 	if ((fid = open(ifile_name, O_RDWR, (mode_t)0)) < 0)
162 		err(1, "get_ifile: bad open");
163 
164 	if (fstat (fid, &file_stat))
165 		err(1, "get_ifile: fstat failed");
166 
167 	fsp->fi_ifile_length = file_stat.st_size;
168 
169 	/* get the ifile */
170 #ifndef MMAP_WORKS
171 	if (!(ifp = malloc ((size_t)fsp->fi_ifile_length)))
172 		err (1, "get_ifile: malloc failed");
173 redo_read:
174 	count = read (fid, ifp, (size_t) fsp->fi_ifile_length);
175 
176 	if (count < 0)
177 		err(1, "get_ifile: bad ifile read");
178 	else if (count < (int)fsp->fi_ifile_length) {
179 		err(0, "get_ifile");
180 		if (lseek(fid, 0, SEEK_SET) < 0)
181 			err(1, "get_ifile: bad ifile lseek");
182 		goto redo_read;
183 	}
184 #else	/* MMAP_WORKS */
185 	ifp = mmap ((caddr_t)0, (size_t) fsp->fi_ifile_length, PROT_READ|PROT_WRITE,
186 		MAP_FILE|MAP_SHARED, fid, (off_t)0);
187 	if (ifp < 0)
188 		err(1, "get_ifile: mmap failed");
189 #endif	/* MMAP_WORKS */
190 
191 	close (fid);
192 
193 	fsp->fi_cip = (CLEANERINFO *)ifp;
194 	fsp->fi_segusep = (SEGUSE *)(ifp + CLEANSIZE(fsp));
195 	fsp->fi_ifilep  = (IFILE *)((caddr_t)fsp->fi_segusep + SEGTABSIZE(fsp));
196 
197 	/*
198 	 * The number of ifile entries is equal to the number of blocks
199 	 * blocks in the ifile minus the ones allocated to cleaner info
200 	 * and segment usage table multiplied by the number of ifile
201 	 * entries per page.
202 	 */
203 	fsp->fi_ifile_count = (fsp->fi_ifile_length >> fsp->fi_lfs.lfs_bshift -
204 	    fsp->fi_lfs.lfs_cleansz - fsp->fi_lfs.lfs_segtabsz) *
205 	    fsp->fi_lfs.lfs_ifpb;
206 
207 	free (ifile_name);
208 }
209 
210 /*
211  * This function will scan a segment and return a list of
212  * <inode, blocknum> pairs which indicate which blocks were
213  * contained as live data within the segment when the segment
214  * summary was read (it may have "died" since then).  Any given
215  * pair will be listed at most once.
216  */
217 int
218 lfs_segmapv(fsp, seg, seg_buf, blocks, bcount, inodes, icount)
219 	FS_INFO *fsp;		/* pointer to local file system information */
220 	int seg;		/* the segment number */
221 	caddr_t seg_buf;	/* the buffer containing the segment's data */
222 	BLOCK_INFO **blocks;	/* OUT: array of block_info for live blocks */
223 	int *bcount;		/* OUT: number of active blocks in segment */
224 	INODE_INFO **inodes;	/* OUT: array of inode_info for live inodes */
225 	int *icount; 		/* OUT: number of active inodes in segment */
226 {
227 	BLOCK_INFO *bip;
228 	INODE_INFO *iip;
229 	SEGSUM *sp;
230 	SEGUSE *sup;
231 	struct lfs *lfsp;
232 	caddr_t s, segend;
233 	daddr_t pseg_addr, seg_addr;
234 	int nblocks, num_iblocks;
235 	time_t timestamp;
236 
237 	lfsp = &fsp->fi_lfs;
238 	num_iblocks = lfsp->lfs_ssize;
239 	if (!(bip = malloc(lfsp->lfs_ssize * sizeof(BLOCK_INFO))))
240 		goto err0;
241 	if (!(iip = malloc(lfsp->lfs_ssize * sizeof(INODE_INFO))))
242 		goto err1;
243 
244 	sup = SEGUSE_ENTRY(lfsp, fsp->fi_segusep, seg);
245 	s = seg_buf + (sup->su_flags & SEGUSE_SUPERBLOCK ? LFS_SBPAD : 0);
246 	seg_addr = sntoda(lfsp, seg);
247 	pseg_addr = seg_addr + (sup->su_flags & SEGUSE_SUPERBLOCK ? btodb(LFS_SBPAD) : 0);
248 #ifdef VERBOSE
249 		printf("\tsegment buffer at: 0x%x\tseg_addr 0x%x\n", s, seg_addr);
250 #endif /* VERBOSE */
251 
252 	*bcount = 0;
253 	*icount = 0;
254 	for (segend = seg_buf + seg_size(lfsp), timestamp = 0; s < segend; ) {
255 		sp = (SEGSUM *)s;
256 #ifdef VERBOSE
257 		printf("\tpartial at: 0x%x\n", pseg_addr);
258 		print_SEGSUM(lfsp, sp);
259 		fflush(stdout);
260 #endif /* VERBOSE */
261 
262 		nblocks = pseg_valid(fsp, sp);
263 		if (nblocks <= 0)
264 			break;
265 
266 		/* Check if we have hit old data */
267 		if (timestamp > ((SEGSUM*)s)->ss_create)
268 			break;
269 		timestamp = ((SEGSUM*)s)->ss_create;
270 
271 		/*
272 		 * Right now we die if we run out of room, we could probably
273 		 * recover if we were smart.
274 		 */
275 		if (*icount + sp->ss_ninos > num_iblocks) {
276 			num_iblocks = *icount + sp->ss_ninos;
277 			iip = realloc (iip, num_iblocks * sizeof(INODE_INFO));
278 			if (!iip)
279 				goto err1;
280 		}
281 		add_inodes(fsp, iip, icount, sp, seg_buf, seg_addr);
282 		add_blocks(fsp, bip, bcount, sp, seg_buf, seg_addr, pseg_addr);
283 		pseg_addr += fsbtodb(lfsp, nblocks) +
284 		    bytetoda(fsp, LFS_SUMMARY_SIZE);
285 		s += (nblocks << lfsp->lfs_bshift) + LFS_SUMMARY_SIZE;
286 	}
287 	qsort(iip, *icount, sizeof(INODE_INFO), ii_compare);
288 	qsort(bip, *bcount, sizeof(BLOCK_INFO), bi_compare);
289 	toss(iip, icount, sizeof(INODE_INFO), ii_toss, NULL);
290 	toss(bip, bcount, sizeof(BLOCK_INFO), bi_toss, NULL);
291 #ifdef VERBOSE
292 	{
293 		BLOCK_INFO *_bip;
294 		INODE_INFO *_iip;
295 		int i;
296 
297 		printf("BLOCK INFOS\n");
298 		for (_bip = bip, i=0; i < *bcount; ++_bip, ++i)
299 			PRINT_BINFO(_bip);
300 		printf("INODE INFOS\n");
301 		for (_iip = iip, i=0; i < *icount; ++_iip, ++i)
302 			PRINT_IINFO(1, _iip);
303 	}
304 #endif
305 	*blocks = bip;
306 	*inodes = iip;
307 	return (0);
308 
309 err1:	free(bip);
310 err0:	*bcount = 0;
311 	*icount = 0;
312 	return (-1);
313 
314 }
315 
316 /*
317  * This will parse a partial segment and fill in BLOCK_INFO structures
318  * for each block described in the segment summary.  It will not include
319  * blocks or inodes from files with new version numbers.
320  */
321 void
322 add_blocks (fsp, bip, countp, sp, seg_buf, segaddr, psegaddr)
323 	FS_INFO *fsp;		/* pointer to super block */
324 	BLOCK_INFO *bip;	/* Block info array */
325 	int *countp;		/* IN/OUT: number of blocks in array */
326 	SEGSUM	*sp;		/* segment summmary pointer */
327 	caddr_t seg_buf;	/* buffer containing segment */
328 	daddr_t segaddr;	/* address of this segment */
329 	daddr_t psegaddr;	/* address of this partial segment */
330 {
331 	IFILE	*ifp;
332 	FINFO	*fip;
333 	caddr_t	bp;
334 	daddr_t	*dp;
335 	daddr_t *iaddrp;	/* pointer to current inode block */
336 	int db_per_block, i, j;
337 	u_long page_size;
338 
339 #ifdef VERBOSE
340 	printf("FILE INFOS\n");
341 #endif
342 	db_per_block = fsbtodb(&fsp->fi_lfs, 1);
343 	page_size = fsp->fi_lfs.lfs_bsize;
344 	bp = seg_buf + datobyte(fsp, psegaddr - segaddr) + LFS_SUMMARY_SIZE;
345 	bip += *countp;
346 	psegaddr += bytetoda(fsp, LFS_SUMMARY_SIZE);
347 	iaddrp = (daddr_t *)((caddr_t)sp + LFS_SUMMARY_SIZE);
348 	--iaddrp;
349 	for (fip = (FINFO *)(sp + 1), i = 0; i < sp->ss_nfinfo;
350 	    ++i, fip = (FINFO *)(&fip->fi_blocks[fip->fi_nblocks])) {
351 
352 		ifp = IFILE_ENTRY(&fsp->fi_lfs, fsp->fi_ifilep, fip->fi_ino);
353 		PRINT_FINFO(fip, ifp);
354 		if (ifp->if_version > fip->fi_version)
355 			continue;
356 		dp = &(fip->fi_blocks[0]);
357 		for (j = 0; j < fip->fi_nblocks; j++, dp++) {
358 			while (psegaddr == *iaddrp) {
359 				psegaddr += db_per_block;
360 				bp += page_size;
361 				--iaddrp;
362 			}
363 			bip->bi_inode = fip->fi_ino;
364 			bip->bi_lbn = *dp;
365 			bip->bi_daddr = psegaddr;
366 			bip->bi_segcreate = (time_t)(sp->ss_create);
367 			bip->bi_bp = bp;
368 			psegaddr += db_per_block;
369 			bp += page_size;
370 			++bip;
371 			++(*countp);
372 		}
373 	}
374 }
375 
376 /*
377  * For a particular segment summary, reads the inode blocks and adds
378  * INODE_INFO structures to the array.  Returns the number of inodes
379  * actually added.
380  */
381 void
382 add_inodes (fsp, iip, countp, sp, seg_buf, seg_addr)
383 	FS_INFO *fsp;		/* pointer to super block */
384 	INODE_INFO *iip;
385 	int *countp;		/* pointer to current number of inodes */
386 	SEGSUM *sp;		/* segsum pointer */
387 	caddr_t	seg_buf;	/* the buffer containing the segment's data */
388 	daddr_t	seg_addr;	/* disk address of seg_buf */
389 {
390 	struct dinode *di;
391 	struct lfs *lfsp;
392 	IFILE *ifp;
393 	INODE_INFO *ip;
394 	daddr_t	*daddrp;
395 	ino_t inum;
396 	int i;
397 
398 	if (sp->ss_ninos <= 0)
399 		return;
400 
401 	ip = iip + *countp;
402 	lfsp = &fsp->fi_lfs;
403 #ifdef VERBOSE
404 	(void) printf("INODE_INFOS:\n");
405 #endif
406 	daddrp = (daddr_t *)((caddr_t)sp + LFS_SUMMARY_SIZE);
407 	for (i = 0; i < sp->ss_ninos; ++i) {
408 		if (i % INOPB(lfsp) == 0) {
409 			--daddrp;
410 			di = (struct dinode *)(seg_buf +
411 			    ((*daddrp - seg_addr) << fsp->fi_daddr_shift));
412 		} else
413 			++di;
414 
415 		inum = di->di_inum;
416 		ip->ii_daddr = *daddrp;
417 		ip->ii_inode = inum;
418 		ip->ii_dinode = di;
419 		ip->ii_segcreate = sp->ss_create;
420 
421 		ifp = IFILE_ENTRY(lfsp, fsp->fi_ifilep, inum);
422 		PRINT_IINFO(ifp->if_daddr == *daddrp, ip);
423 		if (ifp->if_daddr == *daddrp) {
424 			ip++;
425 			++(*countp);
426 		}
427 	}
428 }
429 
430 /*
431  * Checks the summary checksum and the data checksum to determine if the
432  * segment is valid or not.  Returns the size of the partial segment if it
433  * is valid, * and 0 otherwise.  Use dump_summary to figure out size of the
434  * the partial as well as whether or not the checksum is valid.
435  */
436 int
437 pseg_valid (fsp, ssp)
438 	FS_INFO *fsp;   /* pointer to file system info */
439 	SEGSUM *ssp;	/* pointer to segment summary block */
440 {
441 	caddr_t	p;
442 	int i, nblocks;
443 	u_long *datap;
444 
445 	if ((nblocks = dump_summary(&fsp->fi_lfs, ssp, 0, NULL)) <= 0)
446 		return(0);
447 
448 	/* check data/inode block(s) checksum too */
449 	datap = (u_long *)malloc(nblocks * sizeof(u_long));
450 	p = (caddr_t)ssp + LFS_SUMMARY_SIZE;
451 	for (i = 0; i < nblocks; ++i) {
452 		datap[i] = *((u_long *)p);
453 		p += fsp->fi_lfs.lfs_bsize;
454 	}
455 	if (cksum ((void *)datap, nblocks * sizeof(u_long)) != ssp->ss_datasum)
456 		return (0);
457 
458 	return (nblocks);
459 }
460 
461 
462 /* #define MMAP_SEGMENT */
463 /*
464  * read a segment into a memory buffer
465  */
466 int
467 mmap_segment (fsp, segment, segbuf)
468 	FS_INFO *fsp;		/* file system information */
469 	int segment;		/* segment number */
470 	caddr_t *segbuf;	/* pointer to buffer area */
471 {
472 	struct lfs *lfsp;
473 	int fid;		/* fildes for file system device */
474 	daddr_t seg_daddr;	/* base disk address of segment */
475 	off_t seg_byte;
476 	size_t ssize;
477 	char mntfromname[MNAMELEN+2];
478 
479 	lfsp = &fsp->fi_lfs;
480 
481 	/* get the disk address of the beginning of the segment */
482 	seg_daddr = sntoda(lfsp, segment);
483 	seg_byte = datobyte(fsp, seg_daddr);
484 	ssize = seg_size(lfsp);
485 
486 	strcpy(mntfromname, "/dev/r");
487 	strcat(mntfromname, fsp->fi_statfsp->f_mntfromname+5);
488 
489 	if ((fid = open(mntfromname, O_RDONLY, (mode_t)0)) < 0) {
490 		err(0, "mmap_segment: bad open");
491 		return (-1);
492 	}
493 
494 #ifdef MMAP_SEGMENT
495 	*segbuf = mmap ((caddr_t)0, seg_size(lfsp), PROT_READ,
496 	    MAP_FILE, fid, seg_byte);
497 	if (*(long *)segbuf < 0) {
498 		err(0, "mmap_segment: mmap failed");
499 		return (NULL);
500 	}
501 #else /* MMAP_SEGMENT */
502 #ifdef VERBOSE
503 	printf("mmap_segment\tseg_daddr: %lu\tseg_size: %lu\tseg_offset: %qu\n",
504 	    seg_daddr, ssize, seg_byte);
505 #endif
506 	/* malloc the space for the buffer */
507 	*segbuf = malloc(ssize);
508 	if (!*segbuf) {
509 		err(0, "mmap_segment: malloc failed");
510 		return(NULL);
511 	}
512 
513 	/* read the segment data into the buffer */
514 	if (lseek (fid, seg_byte, SEEK_SET) != seg_byte) {
515 		err (0, "mmap_segment: bad lseek");
516 		free(*segbuf);
517 		return (-1);
518 	}
519 
520 	if (read (fid, *segbuf, ssize) != ssize) {
521 		err (0, "mmap_segment: bad read");
522 		free(*segbuf);
523 		return (-1);
524 	}
525 #endif /* MMAP_SEGMENT */
526 	close (fid);
527 
528 	return (0);
529 }
530 
531 void
532 munmap_segment (fsp, seg_buf)
533 	FS_INFO *fsp;		/* file system information */
534 	caddr_t seg_buf;	/* pointer to buffer area */
535 {
536 #ifdef MMAP_SEGMENT
537 	munmap (seg_buf, seg_size(&fsp->fi_lfs));
538 #else /* MMAP_SEGMENT */
539 	free (seg_buf);
540 #endif /* MMAP_SEGMENT */
541 }
542 
543 
544 /*
545  * USEFUL DEBUGGING TOOLS:
546  */
547 void
548 print_SEGSUM (lfsp, p)
549 	struct lfs *lfsp;
550 	SEGSUM	*p;
551 {
552 	if (p)
553 		(void) dump_summary(lfsp, p, DUMP_ALL, NULL);
554 	else printf("0x0");
555 	fflush(stdout);
556 }
557 
558 int
559 bi_compare(a, b)
560 	const void *a;
561 	const void *b;
562 {
563 	const BLOCK_INFO *ba, *bb;
564 	int diff;
565 
566 	ba = a;
567 	bb = b;
568 
569 	if (diff = (int)(ba->bi_inode - bb->bi_inode))
570 		return (diff);
571 	if (diff = (int)(ba->bi_lbn - bb->bi_lbn))
572 		return (diff);
573 	if (diff = (int)(ba->bi_segcreate - bb->bi_segcreate))
574 		return (diff);
575 	diff = (int)(ba->bi_daddr - bb->bi_daddr);
576 	return (diff);
577 }
578 
579 int
580 bi_toss(dummy, a, b)
581 	const void *dummy;
582 	const void *a;
583 	const void *b;
584 {
585 	const BLOCK_INFO *ba, *bb;
586 
587 	ba = a;
588 	bb = b;
589 
590 	return(ba->bi_inode == bb->bi_inode && ba->bi_lbn == bb->bi_lbn);
591 }
592 
593 /*
594  * Right now, we never look at the actually data being
595  * passed to the kernel in iip->ii_dinode.  Therefore,
596  * if the same inode appears twice in the same block
597  * (i.e.  has the same disk address), it doesn't matter
598  * which entry we pass.  However, if we get the kernel
599  * to start looking at the dinode, then we will care
600  * and we'll need some way to distinguish which inode
601  * is the more recent one.
602  */
603 int
604 ii_compare(a, b)
605 	const void *a;
606 	const void *b;
607 {
608 	const INODE_INFO *ia, *ib;
609 	int diff;
610 
611 	ia = a;
612 	ib = b;
613 
614 	if (diff = (int)(ia->ii_inode - ib->ii_inode))
615 		return (diff);
616 	if (diff = (int)(ia->ii_segcreate - ib->ii_segcreate))
617 		return (diff);
618 	diff = (int)(ia->ii_daddr - ib->ii_daddr);
619 	return (diff);
620 }
621 
622 int
623 ii_toss(dummy, a, b)
624 	const void *dummy;
625 	const void *a;
626 	const void *b;
627 {
628 	const INODE_INFO *ia, *ib;
629 
630 	ia = a;
631 	ib = b;
632 
633 	return(ia->ii_inode == ib->ii_inode);
634 }
635 
636 void
637 toss(p, nump, size, dotoss, client)
638 	void *p;
639 	int *nump;
640 	size_t size;
641 	int (*dotoss) __P((const void *, const void *, const void *));
642 	void *client;
643 {
644 	int i;
645 	void *p1;
646 
647 	if (*nump == 0)
648 		return;
649 
650 	for (i = *nump; --i > 0;) {
651 		p1 = p + size;
652 		if (dotoss(client, p, p1)) {
653 			bcopy(p1, p, i * size);
654 			--(*nump);
655 		} else
656 			p += size;
657 	}
658 }
659