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