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