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