xref: /dragonfly/sys/vfs/hpfs/hpfs_subr.c (revision 0bb9290e)
1 /*-
2  * Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD: src/sys/fs/hpfs/hpfs_subr.c,v 1.1 1999/12/09 19:09:59 semenu Exp $
27  * $DragonFly: src/sys/vfs/hpfs/hpfs_subr.c,v 1.7 2006/03/24 18:35:33 dillon Exp $
28  */
29 
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/proc.h>
34 #include <sys/time.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <sys/vnode.h>
38 #include <sys/mount.h>
39 #include <sys/namei.h>
40 #include <sys/malloc.h>
41 #include <sys/buf.h>
42 
43 #include "hpfs.h"
44 #include "hpfsmount.h"
45 #include "hpfs_subr.h"
46 
47 u_long
48 hpfs_checksum(
49 	u_int8_t *object,
50 	int size)
51 {
52 	int i;
53 	u_long csum=0L;
54 	for (i=0; i < size; i++) {
55 		csum += (u_long) *object++;
56 		csum = (csum << 7) + (csum >> (25));
57 	}
58 	return (csum);
59 }
60 
61 void
62 hpfs_bmdeinit(
63 	struct hpfsmount *hpmp)
64 {
65 	struct buf *bp;
66 	int i;
67 
68 	dprintf(("hpmp_bmdeinit: "));
69 
70 	if (!(hpmp->hpm_mp->mnt_flag & MNT_RDONLY)) {
71 		/*
72 		 * Write down BitMap.
73 		 */
74 		for (i=0; i<hpmp->hpm_dbnum; i++) {
75 			dprintf(("[%d: 0x%x] ", i, hpmp->hpm_bmind[i]));
76 
77 			bp = getblk(hpmp->hpm_devvp,
78 				    dbtodoff(hpmp->hpm_bmind[i]),
79 				    BMSIZE, 0, 0);
80 			clrbuf(bp);
81 
82 			bcopy(hpmp->hpm_bitmap + BMSIZE * i, bp->b_data,
83 			      BMSIZE);
84 
85 			bwrite(bp);
86 		}
87 	}
88 
89 	FREE(hpmp->hpm_bitmap,M_HPFSMNT);
90 	FREE(hpmp->hpm_bmind,M_HPFSMNT);
91 
92 	dprintf(("\n"));
93 }
94 
95 /*
96  * Initialize BitMap management, includes calculation of
97  * available blocks number.
98  */
99 int
100 hpfs_bminit(
101 	struct hpfsmount *hpmp)
102 {
103 	struct buf *bp;
104 	int error, i, k;
105 	u_long dbavail;
106 
107 	dprintf(("hpfs_bminit: "));
108 
109 	hpmp->hpm_dbnum = (hpmp->hpm_su.su_btotal + 0x3FFF) / 0x4000;
110 
111 	dprintf(("0x%lx data bands, ", hpmp->hpm_dbnum));
112 
113 	MALLOC(hpmp->hpm_bmind, lsn_t *, hpmp->hpm_dbnum * sizeof(lsn_t),
114 		M_HPFSMNT, M_WAITOK);
115 
116 	MALLOC(hpmp->hpm_bitmap, u_int8_t *, hpmp->hpm_dbnum * BMSIZE,
117 		M_HPFSMNT, M_WAITOK);
118 
119 	error = bread(hpmp->hpm_devvp, dbtodoff(hpmp->hpm_su.su_bitmap.lsn1),
120 		((hpmp->hpm_dbnum + 0x7F) & ~(0x7F)) << 2, &bp);
121 	if (error) {
122 		brelse(bp);
123 		FREE(hpmp->hpm_bitmap, M_HPFSMNT);
124 		FREE(hpmp->hpm_bmind, M_HPFSMNT);
125 		dprintf((" error %d\n", error));
126 		return (error);
127 	}
128 	bcopy(bp->b_data, hpmp->hpm_bmind, hpmp->hpm_dbnum * sizeof(lsn_t));
129 
130 	brelse(bp);
131 
132 	/*
133 	 * Read in all BitMap
134 	 */
135 	for (i=0; i<hpmp->hpm_dbnum; i++) {
136 		dprintf(("[%d: 0x%x] ", i, hpmp->hpm_bmind[i]));
137 
138 		error = bread(hpmp->hpm_devvp, dbtodoff(hpmp->hpm_bmind[i]),
139 				BMSIZE, &bp);
140 		if (error) {
141 			brelse(bp);
142 			FREE(hpmp->hpm_bitmap, M_HPFSMNT);
143 			FREE(hpmp->hpm_bmind, M_HPFSMNT);
144 			dprintf((" error %d\n", error));
145 			return (error);
146 		}
147 		bcopy(bp->b_data, hpmp->hpm_bitmap + BMSIZE * i, BMSIZE);
148 
149 		brelse(bp);
150 	}
151 
152 	/*
153 	 * Look througth BitMap	and count free bits
154 	 */
155 	dbavail = 0;
156 	for (i=0; i < hpmp->hpm_su.su_btotal >> 5; i++) {
157 		u_int32_t mask;
158 		for (k=0, mask=1; k < 32; k++, mask<<=1)
159 			if(((u_int32_t *)hpmp->hpm_bitmap)[i] & mask)
160 				dbavail ++;
161 
162 	}
163 	hpmp->hpm_bavail = dbavail;
164 
165 	return (0);
166 }
167 
168 int
169 hpfs_cmpfname (
170 	struct hpfsmount *hpmp,
171 	char * uname,
172 	int ulen,
173 	char * dname,
174 	int dlen,
175 	u_int16_t cp)
176 {
177 	int i, res;
178 
179 	for (i = 0; i < ulen && i < dlen; i++) {
180 		res = hpfs_toupper(hpmp, hpfs_u2d(hpmp, uname[i]), cp) -
181 		      hpfs_toupper(hpmp, dname[i], cp);
182 		if (res)
183 			return res;
184 	}
185 	return (ulen - dlen);
186 }
187 
188 int
189 hpfs_cpstrnnicmp (
190 	struct hpfsmount *hpmp,
191 	char * str1,
192 	int str1len,
193 	u_int16_t str1cp,
194 	char * str2,
195 	int str2len,
196 	u_int16_t str2cp)
197 {
198 	int i, res;
199 
200 	for (i = 0; i < str1len && i < str2len; i++) {
201 		res = (int)hpfs_toupper(hpmp, ((u_char *)str1)[i], str1cp) -
202 		      (int)hpfs_toupper(hpmp, ((u_char *)str2)[i], str2cp);
203 		if (res)
204 			return res;
205 	}
206 	return (str1len - str2len);
207 }
208 
209 
210 int
211 hpfs_cpload (
212 	struct hpfsmount *hpmp,
213 	struct cpiblk *cpibp,
214 	struct cpdblk *cpdbp)
215 {
216 	struct buf *bp;
217 	struct cpdsec * cpdsp;
218 	int error, i;
219 
220 	error = bread(hpmp->hpm_devvp, dbtodoff(cpibp->b_cpdsec), DEV_BSIZE, &bp);
221 	if (error) {
222 		brelse(bp);
223 		return (error);
224 	}
225 
226 	cpdsp = (struct cpdsec *)bp->b_data;
227 
228 	for (i=cpdsp->d_cpfirst; i<cpdsp->d_cpcnt; i++) {
229 		if (cpdsp->d_cpdblk[i].b_cpid == cpibp->b_cpid) {
230 			bcopy(cpdsp->d_cpdblk + i, cpdbp,
231 			      sizeof(struct cpdblk));
232 
233 			brelse(bp);
234 
235 			return (0);
236 		}
237 	}
238 
239 	brelse(bp);
240 
241 	return (ENOENT);
242 }
243 
244 
245 /*
246  * Initialize Code Page information management.
247  * Load all copdepages in memory.
248  */
249 int
250 hpfs_cpinit (
251 	struct hpfsmount *hpmp,
252 	struct hpfs_args *argsp)
253 {
254 	struct buf *bp;
255 	int error, i;
256 	lsn_t lsn;
257 	int cpicnt;
258 	struct cpisec * cpisp;
259 	struct cpiblk * cpibp;
260 	struct cpdblk * cpdbp;
261 
262 	dprintf(("hpfs_cpinit: \n"));
263 
264 	if (argsp->flags & HPFSMNT_TABLES) {
265 		bcopy(argsp->d2u, hpmp->hpm_d2u, sizeof(u_char) * 0x80);
266 		bcopy(argsp->u2d, hpmp->hpm_u2d, sizeof(u_char) * 0x80);
267 	} else {
268 		for (i=0x0; i<0x80;i++) {
269 			hpmp->hpm_d2u[i] = i + 0x80;
270 			hpmp->hpm_u2d[i] = i + 0x80;
271 		}
272 	}
273 
274 	cpicnt = hpmp->hpm_sp.sp_cpinum;
275 
276 	MALLOC(hpmp->hpm_cpdblk, struct cpdblk *,
277 		cpicnt * sizeof(struct cpdblk), M_HPFSMNT, M_WAITOK);
278 
279 	cpdbp = hpmp->hpm_cpdblk;
280 	lsn = hpmp->hpm_sp.sp_cpi;
281 
282 	while (cpicnt > 0) {
283 		error = bread(hpmp->hpm_devvp, dbtodoff(lsn), DEV_BSIZE, &bp);
284 		if (error) {
285 			brelse(bp);
286 			return (error);
287 		}
288 
289 		cpisp = (struct cpisec *)bp->b_data;
290 
291 		cpibp = cpisp->s_cpi;
292 		for (i=0; i<cpisp->s_cpicnt; i++, cpicnt --, cpdbp++, cpibp++) {
293 			dprintf(("hpfs_cpinit: Country: %d, CP: %d (%d)\n",
294 				 cpibp->b_country, cpibp->b_cpid,
295 				 cpibp->b_vcpid));
296 
297 			error = hpfs_cpload(hpmp, cpibp, cpdbp);
298 			if (error) {
299 				brelse(bp);
300 				return (error);
301 			}
302 		}
303 		lsn = cpisp->s_next;
304 		brelse(bp);
305 	}
306 
307 	return (0);
308 }
309 
310 int
311 hpfs_cpdeinit (
312 	struct hpfsmount *hpmp)
313 {
314 	dprintf(("hpmp_cpdeinit: "));
315 	FREE(hpmp->hpm_cpdblk,M_HPFSMNT);
316 	return (0);
317 }
318 
319 /*
320  * Lookup for a run of blocks.
321  */
322 int
323 hpfs_bmlookup (
324 	struct hpfsmount *hpmp,
325 	u_long flags,	/* 1 means we want right len blocks in run, not less */
326 	lsn_t lsn,		/* We want near this one */
327 	u_long len,		/* We want such long */
328 	lsn_t *lsnp,	/* We got here */
329 	u_long *lenp)	/* We got this long */
330 {
331 	u_int32_t * bitmap;
332 	u_int32_t mask;
333 	int i,k;
334 	int cband, vcband;
335 	u_int bandsz;
336 	int count;
337 
338 	dprintf(("hpfs_bmlookup: lsn: 0x%x, len 0x%lx | Step1\n", lsn, len));
339 
340 	if (lsn > hpmp->hpm_su.su_btotal) {
341 		printf("hpfs_bmlookup: OUT OF VOLUME\n");
342 		return ENOSPC;
343 	}
344 	if (len > hpmp->hpm_bavail) {
345 		printf("hpfs_bmlookup: OUT OF SPACE\n");
346 		return ENOSPC;
347 	}
348  	i = lsn >> 5;
349 	k = lsn & 0x1F;
350 	mask = 1 << k;
351 	bitmap = (u_int32_t *)hpmp->hpm_bitmap + i;
352 
353 	if (*bitmap & mask) {
354 		*lsnp = lsn;
355 		*lenp = 0;
356 		for (; k < 32; k++, mask<<=1) {
357 			if (*bitmap & mask)
358 				(*lenp) ++;
359 			else {
360 				if (flags & 1)
361 					goto step2;
362 				else
363 					return (0);
364 			}
365 
366 			if (*lenp == len)
367 				return (0);
368 		}
369 
370 		bitmap++;
371 		i++;
372 		for (; i < hpmp->hpm_su.su_btotal >> 5; i++, bitmap++) {
373 			for (k=0, mask=1; k < 32; k++, mask<<=1) {
374 				if (*bitmap & mask)
375 					(*lenp) ++;
376 				else {
377 					if (flags & 1)
378 						goto step2;
379 					else
380 						return (0);
381 				}
382 
383 				if (*lenp == len)
384 					return (0);
385 			}
386 		}
387 		return (0);
388 	}
389 
390 step2:
391 	/*
392 	 * Lookup all bands begining from cband, lookup for first block
393 	 */
394 	cband = (lsn >> 14);
395 	dprintf(("hpfs_bmlookup: Step2: band 0x%x (0x%lx)\n",
396 		 cband, hpmp->hpm_dbnum));
397 	for (vcband = 0; vcband < hpmp->hpm_dbnum; vcband ++, cband++) {
398 		cband = cband % hpmp->hpm_dbnum;
399 		bandsz = min (hpmp->hpm_su.su_btotal - (cband << 14), 0x4000);
400 		dprintf(("hpfs_bmlookup: band: %d, sz: 0x%x\n", cband, bandsz));
401 
402 		bitmap = (u_int32_t *)hpmp->hpm_bitmap + (cband << 9);
403 		*lsnp = cband << 14;
404 		*lenp = 0;
405 		count = 0;
406 		for (i=0; i < bandsz >> 5; i++, bitmap++) {
407 			for (k=0, mask=1; k < 32; k++, mask<<=1) {
408 				if (*bitmap & mask) {
409 					if (count) {
410 						(*lenp) ++;
411 					} else {
412 						count = 1;
413 						*lsnp = (cband << 14) + (i << 5) + k;
414 						*lenp = 1;
415 					}
416 				} else {
417 					if ((*lenp) && !(flags & 1)) {
418 						return (0);
419 					} else {
420 						count = 0;
421 					}
422 				}
423 
424 				if (*lenp == len)
425 					return (0);
426 			}
427 		}
428 		if (cband == hpmp->hpm_dbnum - 1)  {
429 			if ((*lenp) && !(flags & 1)) {
430 				return (0);
431 			} else {
432 				count = 0;
433 			}
434 		}
435 	}
436 
437 	return (ENOSPC);
438 }
439 
440 /*
441  * Lookup a single free block.	XXX Need locking on BitMap operations
442  * VERY STUPID ROUTINE!!!
443  */
444 int
445 hpfs_bmfblookup (
446 	struct hpfsmount *hpmp,
447 	lsn_t *lp)
448 {
449 	u_int32_t * bitmap;
450 	int i,k;
451 
452 	dprintf(("hpfs_bmfblookup: "));
453 
454 	bitmap = (u_int32_t *)hpmp->hpm_bitmap;
455 	for (i=0; i < hpmp->hpm_su.su_btotal >> 5; i++, bitmap++) {
456 		k = ffs(*bitmap);
457 		if (k) {
458 			*lp = (i << 5) + k - 1;
459 			dprintf((" found: 0x%x\n",*lp));
460 			return (0);
461 		}
462 	}
463 
464 	return (ENOSPC);
465 }
466 
467 /*
468  * Mark contignous block of blocks.
469  */
470 int
471 hpfs_bmmark (
472 	struct hpfsmount *hpmp,
473 	lsn_t bn,
474 	u_long bl,
475 	int state)
476 {
477 	u_int32_t * bitmap;
478 	int i, didprint = 0;
479 
480 	dprintf(("hpfs_bmmark(0x%x, 0x%lx, %d): \n",bn,bl, state));
481 
482 	if ((bn > hpmp->hpm_su.su_btotal) || (bn+bl > hpmp->hpm_su.su_btotal)) {
483 		printf("hpfs_bmmark: MARKING OUT OF VOLUME\n");
484 		return 0;
485 	}
486 	bitmap = (u_int32_t *)hpmp->hpm_bitmap;
487 	bitmap += bn >> 5;
488 
489 	while (bl > 0) {
490 		for (i = bn & 0x1F; (i < 0x20) && (bl > 0) ; i++, bl--) {
491 			if (state) {
492 				if ( *bitmap & (1 << i)) {
493 					if (!didprint) {
494 						printf("hpfs_bmmark: ALREADY FREE\n");
495 						didprint = 1;
496 					}
497 				} else
498 					hpmp->hpm_bavail++;
499 
500 				*bitmap |= (1 << i);
501 			} else {
502 				if ((~(*bitmap)) & (1 << i)) {
503 					if (!didprint) {
504 						printf("hpfs_bmmark: ALREADY BUSY\n");
505 						didprint = 1;
506 					}
507 				} else
508 					hpmp->hpm_bavail--;
509 
510 				*bitmap &= ~(1 << i);
511 			}
512 		}
513 		bn = 0;
514 		bitmap++;
515 	}
516 
517 	return (0);
518 }
519 
520 
521 int
522 hpfs_validateparent (
523 	struct hpfsnode *hp)
524 {
525 	struct hpfsnode *dhp;
526 	struct vnode *dvp;
527 	struct hpfsmount *hpmp = hp->h_hpmp;
528 	struct buf *bp;
529 	struct dirblk *dp;
530 	struct hpfsdirent *dep;
531 	lsn_t lsn, olsn;
532 	int level, error;
533 
534 	dprintf(("hpfs_validatetimes(0x%x): [parent: 0x%x] ",
535 		hp->h_no, hp->h_fn.fn_parent));
536 
537 	if (hp->h_no == hp->h_fn.fn_parent) {
538 		dhp = hp;
539 	} else {
540 		error = VFS_VGET(hpmp->hpm_mp, hp->h_fn.fn_parent, &dvp);
541 		if (error)
542 			return (error);
543 		dhp = VTOHP(dvp);
544 	}
545 
546 	lsn = ((alleaf_t *)dhp->h_fn.fn_abd)->al_lsn;
547 
548 	olsn = 0;
549 	level = 1;
550 	bp = NULL;
551 
552 dive:
553 	dprintf(("[dive 0x%x] ", lsn));
554 	if (bp != NULL)
555 		brelse(bp);
556 	error = bread(dhp->h_devvp, dbtodoff(lsn), D_BSIZE, &bp);
557 	if (error)
558 		goto failed;
559 
560 	dp = (struct dirblk *) bp->b_data;
561 	if (dp->d_magic != D_MAGIC) {
562 		printf("hpfs_validatetimes: magic doesn't match\n");
563 		error = EINVAL;
564 		goto failed;
565 	}
566 
567 	dep = D_DIRENT(dp);
568 
569 	if (olsn) {
570 		dprintf(("[restore 0x%x] ", olsn));
571 
572 		while(!(dep->de_flag & DE_END) ) {
573 			if((dep->de_flag & DE_DOWN) &&
574 			   (olsn == DE_DOWNLSN(dep)))
575 					 break;
576 			dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen);
577 		}
578 
579 		if((dep->de_flag & DE_DOWN) && (olsn == DE_DOWNLSN(dep))) {
580 			if (dep->de_flag & DE_END)
581 				goto blockdone;
582 
583 			if (hp->h_no == dep->de_fnode) {
584 				dprintf(("[found] "));
585 				goto readdone;
586 			}
587 
588 			dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen);
589 		} else {
590 			printf("hpfs_validatetimes: ERROR! oLSN not found\n");
591 			error = EINVAL;
592 			goto failed;
593 		}
594 	}
595 
596 	olsn = 0;
597 
598 	while(!(dep->de_flag & DE_END)) {
599 		if(dep->de_flag & DE_DOWN) {
600 			lsn = DE_DOWNLSN(dep);
601 			level++;
602 			goto dive;
603 		}
604 
605 		if (hp->h_no == dep->de_fnode) {
606 			dprintf(("[found] "));
607 			goto readdone;
608 		}
609 
610 		dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen);
611 	}
612 
613 	if(dep->de_flag & DE_DOWN) {
614 		dprintf(("[enddive] "));
615 		lsn = DE_DOWNLSN(dep);
616 		level++;
617 		goto dive;
618 	}
619 
620 blockdone:
621 	dprintf(("[EOB] "));
622 	olsn = lsn;
623 	lsn = dp->d_parent;
624 	level--;
625 	dprintf(("[level %d] ", level));
626 	if (level > 0)
627 		goto dive;	/* undive really */
628 
629 	goto failed;
630 
631 readdone:
632 	bcopy(dep->de_name,hp->h_name,dep->de_namelen);
633 	hp->h_name[dep->de_namelen] = '\0';
634 	hp->h_namelen = dep->de_namelen;
635 	hp->h_ctime = dep->de_ctime;
636 	hp->h_atime = dep->de_atime;
637 	hp->h_mtime = dep->de_mtime;
638 	hp->h_flag |= H_PARVALID;
639 
640 	dprintf(("[readdone]"));
641 
642 failed:
643 	dprintf(("\n"));
644 	if (bp != NULL)
645 		brelse(bp);
646 	if (hp != dhp)
647 		vput(dvp);
648 
649 	return (error);
650 }
651 
652 struct timespec
653 hpfstimetounix (
654 	u_long hptime)
655 {
656 	struct timespec t;
657 
658 	t.tv_nsec = 0;
659 	t.tv_sec = hptime;
660 
661 	return t;
662 }
663 
664 /*
665  * Write down changes done to parent dir, these are only times for now.
666  * hpfsnode have to be locked.
667  */
668 int
669 hpfs_updateparent (
670 	struct hpfsnode *hp)
671 {
672 	struct hpfsnode *dhp;
673 	struct vnode *dvp;
674 	struct hpfsdirent *dep;
675 	struct buf * bp;
676 	int error;
677 
678 	dprintf(("hpfs_updateparent(0x%x): \n", hp->h_no));
679 
680 	if (!(hp->h_flag & H_PARCHANGE))
681 		return (0);
682 
683 	if (!(hp->h_flag & H_PARVALID)) {
684 		error = hpfs_validateparent (hp);
685 		if (error)
686 			return (error);
687 	}
688 
689 	if (hp->h_no == hp->h_fn.fn_parent) {
690 		dhp = hp;
691 	} else {
692 		error = VFS_VGET(hp->h_hpmp->hpm_mp, hp->h_fn.fn_parent,
693 				 &dvp);
694 		if (error)
695 			return (error);
696 		dhp = VTOHP(dvp);
697 	}
698 
699 	error = hpfs_genlookupbyname (dhp, hp->h_name, hp->h_namelen,
700 					&bp, &dep);
701 	if (error) {
702 		goto failed;
703 	}
704 
705 	dep->de_atime = hp->h_atime;
706 	dep->de_mtime = hp->h_mtime;
707 	dep->de_size = hp->h_fn.fn_size;
708 
709 	bdwrite (bp);
710 
711 	hp->h_flag &= ~H_PARCHANGE;
712 
713 	error = 0;
714 failed:
715 	if (hp != dhp)
716 		vput(dvp);
717 
718 	return (0);
719 }
720 
721 /*
722  * Write down on disk changes done to fnode. hpfsnode have to be locked.
723  */
724 int
725 hpfs_update (
726 	struct hpfsnode *hp)
727 {
728 	struct buf * bp;
729 
730 	dprintf(("hpfs_update(0x%x): \n", hp->h_no));
731 
732 	if (!(hp->h_flag & H_CHANGE))
733 		return (0);
734 
735 	bp = getblk(hp->h_devvp, dbtodoff(hp->h_no), FNODESIZE, 0, 0);
736 	clrbuf(bp);
737 
738 	bcopy (&hp->h_fn, bp->b_data, sizeof(struct fnode));
739 	bdwrite (bp);
740 
741 	hp->h_flag &= ~H_CHANGE;
742 
743 	if (hp->h_flag & H_PARCHANGE)
744 		return (hpfs_updateparent(hp));
745 
746 	return (0);
747 }
748 
749 /*
750  * Truncate file to specifed size. hpfsnode have to be locked.
751  */
752 int
753 hpfs_truncate (
754 	struct hpfsnode *hp,
755 	u_long size)
756 {
757 	struct hpfsmount *hpmp = hp->h_hpmp;
758 	lsn_t newblen, oldblen;
759 	int error, pf;
760 
761 	dprintf(("hpfs_truncate(0x%x, 0x%x -> 0x%lx): ",
762 		hp->h_no, hp->h_fn.fn_size, size));
763 
764 	newblen = (size + DEV_BSIZE - 1) >> DEV_BSHIFT;
765 	oldblen = (hp->h_fn.fn_size + DEV_BSIZE - 1) >> DEV_BSHIFT;
766 
767 	dprintf(("blen: 0x%x -> 0x%x\n", oldblen, newblen));
768 
769 	error = hpfs_truncatealblk (hpmp, &hp->h_fn.fn_ab, newblen, &pf);
770 	if (error)
771 		return (error);
772 	if (pf) {
773 		hp->h_fn.fn_ab.ab_flag = 0;
774 		hp->h_fn.fn_ab.ab_freecnt = 0x8;
775 		hp->h_fn.fn_ab.ab_busycnt = 0x0;
776 		hp->h_fn.fn_ab.ab_freeoff = sizeof(alblk_t);
777 	}
778 
779 	hp->h_fn.fn_size = size;
780 
781 	hp->h_flag |= (H_CHANGE | H_PARCHANGE);
782 
783 	dprintf(("hpfs_truncate: successful\n"));
784 
785 	return (0);
786 }
787 
788 /*
789  * Enlarge file to specifed size. hpfsnode have to be locked.
790  */
791 int
792 hpfs_extend (
793 	struct hpfsnode *hp,
794 	u_long size)
795 {
796 	struct hpfsmount *hpmp = hp->h_hpmp;
797 	lsn_t newblen, oldblen;
798 	int error;
799 
800 	dprintf(("hpfs_extend(0x%x, 0x%x -> 0x%lx): ",
801 		hp->h_no, hp->h_fn.fn_size, size));
802 
803 	if (hpmp->hpm_bavail < 0x10)
804 		return (ENOSPC);
805 
806 	newblen = (size + DEV_BSIZE - 1) >> DEV_BSHIFT;
807 	oldblen = (hp->h_fn.fn_size + DEV_BSIZE - 1) >> DEV_BSHIFT;
808 
809 	dprintf(("blen: 0x%x -> 0x%x\n", oldblen, newblen));
810 
811 	error = hpfs_addextent(hpmp, hp, newblen - oldblen);
812 	if (error) {
813 		printf("hpfs_extend: FAILED TO ADD EXTENT %d\n", error);
814 		return (error);
815 	}
816 
817 	hp->h_fn.fn_size = size;
818 
819 	hp->h_flag |= (H_CHANGE | H_PARCHANGE);
820 
821 	dprintf(("hpfs_extend: successful\n"));
822 
823 	return (0);
824 }
825 
826 /*
827  * Read AlSec structure, and check if magic is valid.
828  * You don't need to brelse buf on error.
829  */
830 int
831 hpfs_breadstruct (
832 	struct hpfsmount *hpmp,
833 	lsn_t lsn,
834 	u_int len,
835 	u_int32_t magic,
836 	struct buf **bpp)
837 {
838 	struct buf *bp;
839 	u_int32_t *mp;
840 	int error;
841 
842 	dprintf(("hpfs_breadstruct: reading at 0x%x\n", lsn));
843 
844 	*bpp = NULL;
845 
846 	error = bread(hpmp->hpm_devvp, dbtodoff(lsn), len, &bp);
847 	if (error) {
848 		brelse(bp);
849 		return (error);
850 	}
851 	mp = (u_int32_t *) bp->b_data;
852 	if (*mp != magic) {
853 		brelse(bp);
854 		printf("hpfs_breadstruct: MAGIC DOESN'T MATCH (0x%08x != 0x%08x)\n",
855 			*mp, magic);
856 		return (EINVAL);
857 	}
858 
859 	*bpp = bp;
860 
861 	return (0);
862 }
863 
864