xref: /illumos-gate/usr/src/cmd/fs.d/udfs/fsck/pass1.c (revision bfbf29e2)
1 /*
2  * Copyright 1999 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
7 /*	  All Rights Reserved	*/
8 
9 /*
10  * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
11  * All rights reserved.
12  *
13  * Redistribution and use in source and binary forms are permitted
14  * provided that: (1) source distributions retain this entire copyright
15  * notice and comment, and (2) distributions including binaries display
16  * the following acknowledgement:  ``This product includes software
17  * developed by the University of California, Berkeley and its contributors''
18  * in the documentation or other materials provided with the distribution
19  * and in all advertising materials mentioning features or use of this
20  * software. Neither the name of the University nor the names of its
21  * contributors may be used to endorse or promote products derived
22  * from this software without specific prior written permission.
23  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
25  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
26  */
27 
28 #include <stdio.h>
29 #include <strings.h>
30 #include <malloc.h>
31 #include <sys/param.h>
32 #include <sys/types.h>
33 #include <sys/sysmacros.h>
34 #include <sys/mntent.h>
35 #include <sys/vnode.h>
36 #include <sys/fs/udf_volume.h>
37 #include <sys/dkio.h>
38 #include <sys/vtoc.h>
39 #include "fsck.h"
40 #include "udfs.h"
41 #include <locale.h>
42 
43 uint64_t maxuniqid;	/* maximum unique id on medium */
44 
45 /*
46  * for each large file ( size > MAXOFF_T) this global counter
47  * gets incremented here.
48  */
49 
50 extern unsigned int largefile_count;
51 extern void	pwarn(char *, ...);
52 extern void	pfatal(char *, ...);
53 extern void	errexit(char *, ...);
54 
55 extern int32_t	verifytag(struct tag *, uint32_t, struct tag *, int);
56 extern char	*tagerrs[];
57 extern void	maketag(struct tag *, struct tag *);
58 extern void	flush(int32_t, struct bufarea *);
59 extern void	putfilentry(struct bufarea *);
60 extern int32_t	bread(int32_t, char *, daddr_t, long);
61 extern void	bwrite(int, char *, daddr_t, long);
62 extern int32_t	dofix(struct inodesc *, char *);
63 extern int32_t	reply(char *);
64 extern void	ud_swap_short_ad(short_ad_t *);
65 extern void	ud_swap_long_ad(long_ad_t *);
66 
67 extern void	dump16(char *, char *);
68 
69 static void	adjust(struct fileinfo *);
70 static void	opndir(struct file_entry *);
71 static int32_t	getdir(struct file_entry *, struct bufarea **,
72 	u_offset_t *, struct file_id **);
73 static void ckinode(struct file_entry *);
74 struct bufarea *getfilentry();
75 
76 /* Fields for traversing an allocation extent */
77 static uint32_t dir_adrsize;
78 static uint32_t dir_adrindx;
79 static uint32_t dir_naddrs;
80 static uint8_t *extbuf;
81 static uint8_t *dir_adrlist;
82 
83 /* Keep track of where we are in the directory */
84 static u_offset_t dir_baseoff;
85 static uint32_t dir_basesize;
86 static uint8_t *dirbuf;
87 static uint8_t *dir_fidp;
88 static uint32_t baseblock;
89 
90 #define	MAXFIDSIZE 2048
91 
92 static uint8_t fidbuf[MAXFIDSIZE];
93 
94 void
95 pass1()
96 {
97 	register struct file_entry *fp;
98 	register struct fileinfo *fip;
99 	register struct bufarea *bp;
100 	struct file_id *fidp;
101 	struct bufarea *fbp;
102 	int err;
103 
104 	(void) cachefile(rootblock, rootlen);
105 	fip = &inphead[0];		/* The root */
106 	fip->fe_lseen = 0;		/* Didn't get here through directory */
107 	n_files = n_dirs = 0;
108 	while (fip->fe_block) {
109 		u_offset_t offset, end;
110 
111 		markbusy(fip->fe_block, fip->fe_len);
112 		bp = getfilentry(fip->fe_block, fip->fe_len);
113 		if (bp == NULL) {
114 			pwarn(gettext("Unable to read file entry at %x\n"),
115 				fip->fe_block);
116 			goto next;
117 		}
118 		/* LINTED */
119 		fp = (struct file_entry *)bp->b_un.b_buf;
120 		fip->fe_lcount = fp->fe_lcount;
121 		fip->fe_type = fp->fe_icb_tag.itag_ftype;
122 		if (fp->fe_uniq_id >= maxuniqid)
123 			maxuniqid = fp->fe_uniq_id + 1;
124 
125 		if (fip->fe_block == rootblock &&
126 				fip->fe_type != FTYPE_DIRECTORY)
127 			errexit(gettext("Root file entry is not a "
128 				"directory\n"));
129 
130 		if (debug) {
131 			(void) printf("do %x len %d type %d lcount %d"
132 				" lseen %d end %llx\n",
133 				fip->fe_block, fip->fe_len,
134 				fip->fe_type, fip->fe_lcount,
135 				fip->fe_lseen, fp->fe_info_len);
136 		}
137 		switch (fip->fe_type) {
138 		case FTYPE_DIRECTORY:
139 			n_dirs++;
140 			offset = 0;
141 			end = fp->fe_info_len;
142 			fbp = NULL;
143 			opndir(fp);
144 			for (offset = 0; offset < end;
145 					offset += FID_LENGTH(fidp)) {
146 				err = getdir(fp, &fbp, &offset, &fidp);
147 				if (err) {
148 					pwarn(gettext("Bad directory entry in "
149 						"file %x at offset %llx\n"),
150 						fip->fe_block, offset);
151 					offset = end;
152 				}
153 				if (fidp->fid_flags & FID_DELETED)
154 					continue;
155 				(void) cachefile(fidp->fid_icb.lad_ext_loc,
156 					fidp->fid_icb.lad_ext_len);
157 			}
158 			if (dirbuf) {
159 				free(dirbuf);
160 				dirbuf = NULL;
161 			}
162 			if (fbp)
163 				fbp->b_flags &= ~B_INUSE;
164 			if (debug)
165 				(void) printf("Done %x\n", fip->fe_block);
166 			break;
167 
168 		case FTYPE_FILE:
169 		case FTYPE_SYMLINK:
170 			ckinode(fp);
171 			/* FALLTHROUGH */
172 		default:
173 			n_files++;
174 			break;
175 		}
176 		putfilentry(bp);
177 		bp->b_flags &= ~B_INUSE;
178 	next:
179 		/* At end of this set of fips, get the next set */
180 		if ((++fip)->fe_block == (uint32_t)-1)
181 			fip = fip->fe_nexthash;
182 	}
183 
184 	/* Find bad link counts */
185 	fip = &inphead[0];
186 	while (fip->fe_block) {
187 		if (fip->fe_lcount != fip->fe_lseen)
188 			adjust(fip);
189 		/* At end of this set of fips, get the next set */
190 		if ((++fip)->fe_block == (uint32_t)-1)
191 			fip = fip->fe_nexthash;
192 	}
193 }
194 
195 static void
196 opndir(struct file_entry *fp)
197 {
198 	if (dirbuf) {
199 		free(dirbuf);
200 		dirbuf = NULL;
201 	}
202 	if (extbuf) {
203 		free(extbuf);
204 		extbuf = NULL;
205 	}
206 
207 	dir_baseoff = 0;
208 	dir_basesize = 0;
209 	dir_adrindx = 0;
210 
211 	switch (fp->fe_icb_tag.itag_flags & 0x3) {
212 	case ICB_FLAG_SHORT_AD:
213 		dir_adrsize = sizeof (short_ad_t);
214 		dir_naddrs = fp->fe_len_adesc / sizeof (short_ad_t);
215 		dir_adrlist = (uint8_t *)(fp->fe_spec + fp->fe_len_ear);
216 		break;
217 	case ICB_FLAG_LONG_AD:
218 		dir_adrsize = sizeof (long_ad_t);
219 		dir_naddrs = fp->fe_len_adesc / sizeof (long_ad_t);
220 		dir_adrlist = (uint8_t *)(fp->fe_spec + fp->fe_len_ear);
221 		break;
222 	case ICB_FLAG_EXT_AD:
223 		errexit(gettext("Can't handle ext_ads in directories/n"));
224 		break;
225 	case ICB_FLAG_ONE_AD:
226 		dir_adrsize = 0;
227 		dir_naddrs = 0;
228 		dir_adrlist = NULL;
229 		dir_basesize = fp->fe_len_adesc;
230 		dir_fidp = (uint8_t *)(fp->fe_spec + fp->fe_len_ear);
231 		baseblock = fp->fe_tag.tag_loc;
232 		break;
233 	}
234 }
235 
236 /* Allocate and read in an allocation extent */
237 /* ARGSUSED */
238 int
239 getallocext(struct file_entry *fp, uint32_t loc, uint32_t len)
240 {
241 	uint32_t nb;
242 	uint8_t *ap;
243 	int i;
244 	int err;
245 	struct alloc_ext_desc *aep;
246 
247 	if (debug)
248 		(void) printf(" allocext loc %x len %x\n", loc, len);
249 	nb = roundup(len, secsize);
250 	if (extbuf)
251 		free(extbuf);
252 	extbuf = (uint8_t *)malloc(nb);
253 	if (extbuf == NULL)
254 		errexit(gettext("Can't allocate directory extent buffer\n"));
255 	if (bread(fsreadfd, (char *)extbuf,
256 			fsbtodb(loc + part_start), nb) != 0) {
257 		(void) fprintf(stderr,
258 			gettext("Can't read allocation extent\n"));
259 		return (1);
260 	}
261 	/* LINTED */
262 	aep = (struct alloc_ext_desc *)extbuf;
263 	err = verifytag(&aep->aed_tag, loc, &aep->aed_tag, UD_ALLOC_EXT_DESC);
264 	if (err) {
265 		(void) printf(
266 			gettext("Bad tag on alloc extent: %s\n"), tagerrs[err]);
267 		free(extbuf);
268 		return (1);
269 	}
270 	dir_adrlist = (uint8_t *)(aep + 1);
271 	dir_naddrs = aep->aed_len_aed / dir_adrsize;
272 	dir_adrindx = 0;
273 
274 	/* Swap the descriptors */
275 	for (i = 0, ap = dir_adrlist; i < dir_naddrs; i++, ap += dir_adrsize) {
276 		if (dir_adrsize == sizeof (short_ad_t)) {
277 			/* LINTED */
278 			ud_swap_short_ad((short_ad_t *)ap);
279 		} else if (dir_adrsize == sizeof (long_ad_t)) {
280 			/* LINTED */
281 			ud_swap_long_ad((long_ad_t *)ap);
282 		}
283 	}
284 
285 	return (0);
286 }
287 
288 /*
289  * Variables used in this function and their relationships:
290  *  *poffset - read pointer in the directory
291  *  dir_baseoff - offset at start of dirbuf
292  *  dir_baselen - length of valid data in current extent
293  *  dir_adrindx - index into current allocation extent for location of
294  *	dir_baseoff
295  *  dir_naddrs - number of entries in current allocation extent
296  *  dir_fidp - pointer to dirbuf or immediate data in file entry
297  *  baseblock - block address of dir_baseoff
298  *  newoff - *poffset - dir_baseoff
299  */
300 /* ARGSUSED1 */
301 static int32_t
302 getdir(struct file_entry *fp, struct bufarea **fbp,
303 	u_offset_t *poffset, struct file_id **fidpp)
304 {
305 	/* LINTED */
306 	register struct file_id *fidp = (struct file_id *)fidbuf;
307 	register struct short_ad *sap;
308 	register struct long_ad *lap;
309 	register int i, newoff, xoff = 0;
310 	uint32_t block = 0, nb, len, left;
311 	u_offset_t offset;
312 	int err, type;
313 
314 
315 again:
316 	offset = *poffset;
317 again2:
318 	if (debug)
319 		(void) printf("getdir %llx\n", offset);
320 	newoff = offset - dir_baseoff;
321 	if (newoff >= dir_basesize) {
322 		if (dirbuf) {
323 			free(dirbuf);
324 			dirbuf = NULL;
325 		}
326 	} else {
327 		if (block == 0)
328 			block = baseblock + (newoff / secsize);
329 		goto nextone;
330 	}
331 
332 again3:
333 	switch (fp->fe_icb_tag.itag_flags & 0x3) {
334 	case ICB_FLAG_SHORT_AD:
335 		/* LINTED */
336 		sap = &((short_ad_t *)dir_adrlist)[dir_adrindx];
337 		for (i = dir_adrindx; i < dir_naddrs; i++, sap++) {
338 			len = EXTLEN(sap->sad_ext_len);
339 			type = EXTYPE(sap->sad_ext_len);
340 			if (type == 3) {
341 				if (i < dir_naddrs - 1)
342 					errexit(gettext("Allocation extent not "
343 						"at end of list\n"));
344 				markbusy(sap->sad_ext_loc, len);
345 				if (getallocext(fp, sap->sad_ext_loc, len))
346 					return (1);
347 				goto again3;
348 			}
349 			if (newoff < len)
350 				break;
351 			newoff -= len;
352 			dir_baseoff += len;
353 			if (debug)
354 				(void) printf(
355 				    " loc %x len %x\n", sap->sad_ext_loc,
356 					len);
357 		}
358 		dir_adrindx = i;
359 		if (debug)
360 			(void) printf(" loc %x len %x\n", sap->sad_ext_loc,
361 				sap->sad_ext_len);
362 		baseblock = sap->sad_ext_loc;
363 		if (block == 0)
364 			block = baseblock;
365 		dir_basesize = len;
366 		if (type < 2)
367 			markbusy(sap->sad_ext_loc, len);
368 		if (type != 0) {
369 			*poffset += dir_basesize;
370 			goto again;
371 		}
372 		nb = roundup(len, secsize);
373 		dirbuf = (uint8_t *)malloc(nb);
374 		if (dirbuf == NULL)
375 			errexit(gettext("Can't allocate directory extent "
376 				"buffer\n"));
377 		if (bread(fsreadfd, (char *)dirbuf,
378 				fsbtodb(baseblock + part_start), nb) != 0) {
379 			errexit(gettext("Can't read directory extent\n"));
380 		}
381 		dir_fidp = dirbuf;
382 		break;
383 	case ICB_FLAG_LONG_AD:
384 		/* LINTED */
385 		lap = &((long_ad_t *)dir_adrlist)[dir_adrindx];
386 		for (i = dir_adrindx; i < dir_naddrs; i++, lap++) {
387 			len = EXTLEN(lap->lad_ext_len);
388 			type = EXTYPE(lap->lad_ext_len);
389 			if (type == 3) {
390 				if (i < dir_naddrs - 1)
391 					errexit(gettext("Allocation extent not "
392 						"at end of list\n"));
393 				markbusy(lap->lad_ext_loc, len);
394 				if (getallocext(fp, lap->lad_ext_loc, len))
395 					return (1);
396 				goto again3;
397 			}
398 			if (newoff < len)
399 				break;
400 			newoff -= len;
401 			dir_baseoff += len;
402 			if (debug)
403 				(void) printf(
404 				    " loc %x len %x\n", lap->lad_ext_loc,
405 					len);
406 		}
407 		dir_adrindx = i;
408 		if (debug)
409 			(void) printf(" loc %x len %x\n", lap->lad_ext_loc,
410 				lap->lad_ext_len);
411 		baseblock = lap->lad_ext_loc;
412 		if (block == 0)
413 			block = baseblock;
414 		dir_basesize = len;
415 		if (type < 2)
416 			markbusy(lap->lad_ext_loc, len);
417 		if (type != 0) {
418 			*poffset += dir_basesize;
419 			goto again;
420 		}
421 		nb = roundup(len, secsize);
422 		dirbuf = (uint8_t *)malloc(nb);
423 		if (dirbuf == NULL)
424 			errexit(gettext("Can't allocate directory extent "
425 				"buffer\n"));
426 		if (bread(fsreadfd, (char *)dirbuf,
427 				fsbtodb(baseblock + part_start), nb) != 0) {
428 			errexit(gettext("Can't read directory extent\n"));
429 		}
430 		dir_fidp = dirbuf;
431 		break;
432 	case ICB_FLAG_EXT_AD:
433 		break;
434 	case ICB_FLAG_ONE_AD:
435 		errexit(gettext("Logic error in getdir - at ICB_FLAG_ONE_AD "
436 			"case\n"));
437 		break;
438 	}
439 nextone:
440 	if (debug)
441 		(void) printf("getdirend blk %x dir_baseoff %llx newoff %x\n",
442 			block, dir_baseoff, newoff);
443 	left = dir_basesize - newoff;
444 	if (xoff + left > MAXFIDSIZE)
445 		left = MAXFIDSIZE - xoff;
446 	bcopy((char *)dir_fidp + newoff, (char *)fidbuf + xoff, left);
447 	xoff += left;
448 	/*
449 	 * If we have a fid that crosses an extent boundary, then force
450 	 * a read of the next extent, and fill up the rest of the fid.
451 	 */
452 	if (xoff < sizeof (fidp->fid_tag) ||
453 	    xoff < sizeof (fidp->fid_tag) + SWAP16(fidp->fid_tag.tag_crc_len)) {
454 		offset += left;
455 		if (debug)
456 			(void) printf("block crossing at offset %llx\n",
457 				offset);
458 		goto again2;
459 	}
460 	err = verifytag(&fidp->fid_tag, block, &fidp->fid_tag, UD_FILE_ID_DESC);
461 	if (debug) {
462 		dump16((char *)fidp, "\n");
463 	}
464 	if (err) {
465 		pwarn(gettext("Bad directory tag: %s\n"), tagerrs[err]);
466 		return (err);
467 	}
468 	*fidpp = fidp;
469 	return (0);
470 }
471 
472 static void
473 ckinode(struct file_entry *fp)
474 {
475 	register struct short_ad *sap;
476 	register struct long_ad *lap;
477 	register int i, type, len;
478 
479 	switch (fp->fe_icb_tag.itag_flags & 0x3) {
480 	case ICB_FLAG_SHORT_AD:
481 		dir_adrsize = sizeof (short_ad_t);
482 		dir_naddrs = fp->fe_len_adesc / sizeof (short_ad_t);
483 		/* LINTED */
484 		sap = (short_ad_t *)(fp->fe_spec + fp->fe_len_ear);
485 again1:
486 		for (i = 0; i < dir_naddrs; i++, sap++) {
487 			len = EXTLEN(sap->sad_ext_len);
488 			type = EXTYPE(sap->sad_ext_len);
489 			if (type < 2)
490 				markbusy(sap->sad_ext_loc, len);
491 			if (debug)
492 				(void) printf(
493 				    " loc %x len %x\n", sap->sad_ext_loc,
494 					sap->sad_ext_len);
495 			if (type == 3) {
496 				markbusy(sap->sad_ext_loc, len);
497 				/* This changes dir_naddrs and dir_adrlist */
498 				if (getallocext(fp, sap->sad_ext_loc, len))
499 					break;
500 				/* LINTED */
501 				sap = (short_ad_t *)dir_adrlist;
502 				goto again1;
503 			}
504 		}
505 		break;
506 	case ICB_FLAG_LONG_AD:
507 		dir_adrsize = sizeof (long_ad_t);
508 		dir_naddrs = fp->fe_len_adesc / sizeof (long_ad_t);
509 		/* LINTED */
510 		lap = (long_ad_t *)(fp->fe_spec + fp->fe_len_ear);
511 again2:
512 		for (i = 0; i < dir_naddrs; i++, lap++) {
513 			len = EXTLEN(lap->lad_ext_len);
514 			type = EXTYPE(lap->lad_ext_len);
515 			if (type < 2)
516 				markbusy(lap->lad_ext_loc, len);
517 			if (debug)
518 				(void) printf(
519 				    " loc %x len %x\n", lap->lad_ext_loc,
520 					lap->lad_ext_len);
521 			if (type == 3) {
522 				markbusy(sap->sad_ext_loc, len);
523 				/* This changes dir_naddrs and dir_adrlist */
524 				if (getallocext(fp, lap->lad_ext_loc, len))
525 					break;
526 				/* LINTED */
527 				lap = (long_ad_t *)dir_adrlist;
528 				goto again2;
529 			}
530 		}
531 		break;
532 	case ICB_FLAG_EXT_AD:
533 		break;
534 	case ICB_FLAG_ONE_AD:
535 		break;
536 	}
537 }
538 
539 static void
540 adjust(struct fileinfo *fip)
541 {
542 	register struct file_entry *fp;
543 	register struct bufarea *bp;
544 
545 	bp = getfilentry(fip->fe_block, fip->fe_len);
546 	if (bp == NULL)
547 		errexit(gettext("Unable to read file entry at %x\n"),
548 			fip->fe_block);
549 	/* LINTED */
550 	fp = (struct file_entry *)bp->b_un.b_buf;
551 	pwarn(gettext("LINK COUNT %s I=%x"),
552 		fip->fe_type == FTYPE_DIRECTORY ? "DIR" :
553 		fip->fe_type == FTYPE_SYMLINK ? "SYM" :
554 		fip->fe_type == FTYPE_FILE ? "FILE" : "???", fip->fe_block);
555 	(void) printf(gettext(" COUNT %d SHOULD BE %d"),
556 		fip->fe_lcount, fip->fe_lseen);
557 	if (preen) {
558 		if (fip->fe_lseen > fip->fe_lcount) {
559 			(void) printf("\n");
560 			pfatal(gettext("LINK COUNT INCREASING"));
561 		}
562 		(void) printf(gettext(" (ADJUSTED)\n"));
563 	}
564 	if (preen || reply(gettext("ADJUST")) == 1) {
565 		fp->fe_lcount = fip->fe_lseen;
566 		putfilentry(bp);
567 		dirty(bp);
568 		flush(fswritefd, bp);
569 	}
570 	bp->b_flags &= ~B_INUSE;
571 }
572 
573 void
574 dofreemap()
575 {
576 	register int i;
577 	register char *bp, *fp;
578 	struct inodesc idesc;
579 
580 	if (freemap == NULL)
581 		return;
582 
583 	/* Flip bits in the busy map */
584 	bp = busymap;
585 	for (i = 0, bp = busymap; i < part_bmp_bytes; i++, bp++)
586 		*bp = ~*bp;
587 
588 	/* Mark leftovers in byte as allocated */
589 	if (part_len % NBBY)
590 		bp[-1] &= (unsigned)0xff >> (NBBY - part_len % NBBY);
591 	bp = busymap;
592 	fp = freemap;
593 	bzero((char *)&idesc, sizeof (struct inodesc));
594 	idesc.id_type = ADDR;
595 	if (bcmp(bp, fp, part_bmp_bytes) != 0 &&
596 		dofix(&idesc, gettext("BLK(S) MISSING IN FREE BITMAP"))) {
597 		bcopy(bp, fp, part_bmp_bytes);
598 		maketag(&spacep->sbd_tag, &spacep->sbd_tag);
599 		bwrite(fswritefd, (char *)spacep, fsbtodb(part_bmp_loc),
600 			part_bmp_sectors * secsize);
601 	}
602 }
603 
604 void
605 dolvint()
606 {
607 	struct lvid_iu *lviup;
608 	struct inodesc idesc;
609 
610 	bzero((char *)&idesc, sizeof (struct inodesc));
611 	idesc.id_type = ADDR;
612 	lviup = (struct lvid_iu *)&lvintp->lvid_fst[2];
613 	if ((lvintp->lvid_fst[0] != part_len - n_blks ||
614 	    lvintp->lvid_int_type != LVI_CLOSE ||
615 	    lviup->lvidiu_nfiles != n_files ||
616 	    lviup->lvidiu_ndirs != n_dirs ||
617 	    lvintp->lvid_uniqid < maxuniqid) &&
618 	    dofix(&idesc, gettext("LOGICAL VOLUME INTEGRITY COUNTS WRONG"))) {
619 		lvintp->lvid_int_type = LVI_CLOSE;
620 		lvintp->lvid_fst[0] = part_len - n_blks;
621 		lviup->lvidiu_nfiles = n_files;
622 		lviup->lvidiu_ndirs = n_dirs;
623 		lvintp->lvid_uniqid = maxuniqid;
624 		maketag(&lvintp->lvid_tag, &lvintp->lvid_tag);
625 		bwrite(fswritefd, (char *)lvintp, fsbtodb(lvintblock),
626 			lvintlen);
627 	}
628 }
629