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$
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/bio.h>
41#include <sys/buf.h>
42
43#include <fs/hpfs/hpfs.h>
44#include <fs/hpfs/hpfsmount.h>
45#include <fs/hpfs/hpfs_subr.h>
46
47u_long
48hpfs_checksum(
49	u_int8_t *object,
50	int size)
51{
52	register 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
61void
62hpfs_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, 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 */
98int
99hpfs_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	hpmp->hpm_bmind = malloc(hpmp->hpm_dbnum * sizeof(lsn_t),
113		M_HPFSMNT, M_WAITOK);
114
115	hpmp->hpm_bitmap = malloc(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, NOCRED, &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, NOCRED, &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		register 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
167int
168hpfs_cmpfname (
169	struct hpfsmount *hpmp,
170	char * uname,
171	int ulen,
172	char * dname,
173	int dlen,
174	u_int16_t cp)
175{
176	register 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
187int
188hpfs_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
209int
210hpfs_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, NOCRED, &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 */
248int
249hpfs_cpinit (
250	struct mount *mp,
251	struct hpfsmount *hpmp)
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	error = vfs_copyopt(mp->mnt_optnew, "d2u", hpmp->hpm_d2u,
264	    sizeof hpmp->hpm_d2u);
265	if (error == ENOENT)
266		for (i=0x0; i<0x80;i++)
267			hpmp->hpm_d2u[i] = i + 0x80;
268	else if (error)
269		return (error);
270
271	error = vfs_copyopt(mp->mnt_optnew, "u2d", hpmp->hpm_u2d,
272	    sizeof hpmp->hpm_u2d);
273	if (error == ENOENT)
274		for (i=0x0; i<0x80;i++)
275			hpmp->hpm_u2d[i] = i + 0x80;
276	else if (error)
277		return (error);
278
279	cpicnt = hpmp->hpm_sp.sp_cpinum;
280
281	hpmp->hpm_cpdblk = malloc(cpicnt * sizeof(struct cpdblk),
282	    M_HPFSMNT, M_WAITOK);
283
284	cpdbp = hpmp->hpm_cpdblk;
285	lsn = hpmp->hpm_sp.sp_cpi;
286
287	while (cpicnt > 0) {
288		error = bread(hpmp->hpm_devvp, lsn, DEV_BSIZE, NOCRED, &bp);
289		if (error) {
290			brelse(bp);
291			return (error);
292		}
293
294		cpisp = (struct cpisec *)bp->b_data;
295
296		cpibp = cpisp->s_cpi;
297		for (i=0; i<cpisp->s_cpicnt; i++, cpicnt --, cpdbp++, cpibp++) {
298			dprintf(("hpfs_cpinit: Country: %d, CP: %d (%d)\n",
299				 cpibp->b_country, cpibp->b_cpid,
300				 cpibp->b_vcpid));
301
302			error = hpfs_cpload(hpmp, cpibp, cpdbp);
303			if (error) {
304				brelse(bp);
305				return (error);
306			}
307		}
308		lsn = cpisp->s_next;
309		brelse(bp);
310	}
311
312	return (0);
313}
314
315int
316hpfs_cpdeinit (
317	struct hpfsmount *hpmp)
318{
319	dprintf(("hpmp_cpdeinit: "));
320	free(hpmp->hpm_cpdblk,M_HPFSMNT);
321	return (0);
322}
323
324/*
325 * Lookup for a run of blocks.
326 */
327int
328hpfs_bmlookup (
329	struct hpfsmount *hpmp,
330	u_long flags,	/* 1 means we want right len blocks in run, not less */
331	lsn_t lsn,		/* We want near this one */
332	u_long len,		/* We want such long */
333	lsn_t *lsnp,	/* We got here */
334	u_long *lenp)	/* We got this long */
335{
336	u_int32_t * bitmap;
337	register u_int32_t mask;
338	int i,k;
339	int cband, vcband;
340	u_int bandsz;
341	int count;
342
343	dprintf(("hpfs_bmlookup: lsn: 0x%x, len 0x%lx | Step1\n", lsn, len));
344
345	if (lsn > hpmp->hpm_su.su_btotal) {
346		printf("hpfs_bmlookup: OUT OF VOLUME\n");
347		return ENOSPC;
348	}
349	if (len > hpmp->hpm_bavail) {
350		printf("hpfs_bmlookup: OUT OF SPACE\n");
351		return ENOSPC;
352	}
353 	i = lsn >> 5;
354	k = lsn & 0x1F;
355	mask = 1 << k;
356	bitmap = (u_int32_t *)hpmp->hpm_bitmap + i;
357
358	if (*bitmap & mask) {
359		*lsnp = lsn;
360		*lenp = 0;
361		for (; k < 32; k++, mask<<=1) {
362			if (*bitmap & mask)
363				(*lenp) ++;
364			else {
365				if (flags & 1)
366					goto step2;
367				else
368					return (0);
369			}
370
371			if (*lenp == len)
372				return (0);
373		}
374
375		bitmap++;
376		i++;
377		for (; i < hpmp->hpm_su.su_btotal >> 5; i++, bitmap++) {
378			for (k=0, mask=1; k < 32; k++, mask<<=1) {
379				if (*bitmap & mask)
380					(*lenp) ++;
381				else {
382					if (flags & 1)
383						goto step2;
384					else
385						return (0);
386				}
387
388				if (*lenp == len)
389					return (0);
390			}
391		}
392		return (0);
393	}
394
395step2:
396	/*
397	 * Lookup all bands begining from cband, lookup for first block
398	 */
399	cband = (lsn >> 14);
400	dprintf(("hpfs_bmlookup: Step2: band 0x%x (0x%lx)\n",
401		 cband, hpmp->hpm_dbnum));
402	for (vcband = 0; vcband < hpmp->hpm_dbnum; vcband ++, cband++) {
403		cband = cband % hpmp->hpm_dbnum;
404		bandsz = min (hpmp->hpm_su.su_btotal - (cband << 14), 0x4000);
405		dprintf(("hpfs_bmlookup: band: %d, sz: 0x%x\n", cband, bandsz));
406
407		bitmap = (u_int32_t *)hpmp->hpm_bitmap + (cband << 9);
408		*lsnp = cband << 14;
409		*lenp = 0;
410		count = 0;
411		for (i=0; i < bandsz >> 5; i++, bitmap++) {
412			for (k=0, mask=1; k < 32; k++, mask<<=1) {
413				if (*bitmap & mask) {
414					if (count) {
415						(*lenp) ++;
416					} else {
417						count = 1;
418						*lsnp = (cband << 14) + (i << 5) + k;
419						*lenp = 1;
420					}
421				} else {
422					if ((*lenp) && !(flags & 1)) {
423						return (0);
424					} else {
425						count = 0;
426					}
427				}
428
429				if (*lenp == len)
430					return (0);
431			}
432		}
433		if (cband == hpmp->hpm_dbnum - 1)  {
434			if ((*lenp) && !(flags & 1)) {
435				return (0);
436			} else {
437				count = 0;
438			}
439		}
440	}
441
442	return (ENOSPC);
443}
444
445/*
446 * Lookup a single free block.	XXX Need locking on BitMap operations
447 * VERY STUPID ROUTINE!!!
448 */
449int
450hpfs_bmfblookup (
451	struct hpfsmount *hpmp,
452	lsn_t *lp)
453{
454	u_int32_t * bitmap;
455	int i,k;
456
457	dprintf(("hpfs_bmfblookup: "));
458
459	bitmap = (u_int32_t *)hpmp->hpm_bitmap;
460	for (i=0; i < hpmp->hpm_su.su_btotal >> 5; i++, bitmap++) {
461		k = ffs(*bitmap);
462		if (k) {
463			*lp = (i << 5) + k - 1;
464			dprintf((" found: 0x%x\n",*lp));
465			return (0);
466		}
467	}
468
469	return (ENOSPC);
470}
471
472/*
473 * Mark contignous block of blocks.
474 */
475int
476hpfs_bmmark (
477	struct hpfsmount *hpmp,
478	lsn_t bn,
479	u_long bl,
480	int state)
481{
482	u_int32_t * bitmap;
483	int i, didprint = 0;
484
485	dprintf(("hpfs_bmmark(0x%x, 0x%lx, %d): \n",bn,bl, state));
486
487	if ((bn > hpmp->hpm_su.su_btotal) || (bn+bl > hpmp->hpm_su.su_btotal)) {
488		printf("hpfs_bmmark: MARKING OUT OF VOLUME\n");
489		return 0;
490	}
491	bitmap = (u_int32_t *)hpmp->hpm_bitmap;
492	bitmap += bn >> 5;
493
494	while (bl > 0) {
495		for (i = bn & 0x1F; (i < 0x20) && (bl > 0) ; i++, bl--) {
496			if (state) {
497				if ( *bitmap & (1 << i)) {
498					if (!didprint) {
499						printf("hpfs_bmmark: ALREADY FREE\n");
500						didprint = 1;
501					}
502				} else
503					hpmp->hpm_bavail++;
504
505				*bitmap |= (1 << i);
506			} else {
507				if ((~(*bitmap)) & (1 << i)) {
508					if (!didprint) {
509						printf("hpfs_bmmark: ALREADY BUSY\n");
510						didprint = 1;
511					}
512				} else
513					hpmp->hpm_bavail--;
514
515				*bitmap &= ~(1 << i);
516			}
517		}
518		bn = 0;
519		bitmap++;
520	}
521
522	return (0);
523}
524
525
526int
527hpfs_validateparent (
528	struct hpfsnode *hp)
529{
530	struct hpfsnode *dhp;
531	struct vnode *dvp;
532	struct hpfsmount *hpmp = hp->h_hpmp;
533	struct buf *bp;
534	struct dirblk *dp;
535	struct hpfsdirent *dep;
536	lsn_t lsn, olsn;
537	int level, error;
538
539	dprintf(("hpfs_validatetimes(0x%x): [parent: 0x%x] ",
540		hp->h_no, hp->h_fn.fn_parent));
541
542	if (hp->h_no == hp->h_fn.fn_parent) {
543		dhp = hp;
544	} else {
545		error = VFS_VGET(hpmp->hpm_mp, hp->h_fn.fn_parent,
546				 LK_EXCLUSIVE, &dvp);
547		if (error)
548			return (error);
549		dhp = VTOHP(dvp);
550	}
551
552	lsn = ((alleaf_t *)dhp->h_fn.fn_abd)->al_lsn;
553
554	olsn = 0;
555	level = 1;
556	bp = NULL;
557
558dive:
559	dprintf(("[dive 0x%x] ", lsn));
560	if (bp != NULL)
561		brelse(bp);
562	error = bread(dhp->h_devvp, lsn, D_BSIZE, NOCRED, &bp);
563	if (error)
564		goto failed;
565
566	dp = (struct dirblk *) bp->b_data;
567	if (dp->d_magic != D_MAGIC) {
568		printf("hpfs_validatetimes: magic doesn't match\n");
569		error = EINVAL;
570		goto failed;
571	}
572
573	dep = D_DIRENT(dp);
574
575	if (olsn) {
576		dprintf(("[restore 0x%x] ", olsn));
577
578		while(!(dep->de_flag & DE_END) ) {
579			if((dep->de_flag & DE_DOWN) &&
580			   (olsn == DE_DOWNLSN(dep)))
581					 break;
582			dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen);
583		}
584
585		if((dep->de_flag & DE_DOWN) && (olsn == DE_DOWNLSN(dep))) {
586			if (dep->de_flag & DE_END)
587				goto blockdone;
588
589			if (hp->h_no == dep->de_fnode) {
590				dprintf(("[found] "));
591				goto readdone;
592			}
593
594			dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen);
595		} else {
596			printf("hpfs_validatetimes: ERROR! oLSN not found\n");
597			error = EINVAL;
598			goto failed;
599		}
600	}
601
602	olsn = 0;
603
604	while(!(dep->de_flag & DE_END)) {
605		if(dep->de_flag & DE_DOWN) {
606			lsn = DE_DOWNLSN(dep);
607			level++;
608			goto dive;
609		}
610
611		if (hp->h_no == dep->de_fnode) {
612			dprintf(("[found] "));
613			goto readdone;
614		}
615
616		dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen);
617	}
618
619	if(dep->de_flag & DE_DOWN) {
620		dprintf(("[enddive] "));
621		lsn = DE_DOWNLSN(dep);
622		level++;
623		goto dive;
624	}
625
626blockdone:
627	dprintf(("[EOB] "));
628	olsn = lsn;
629	lsn = dp->d_parent;
630	level--;
631	dprintf(("[level %d] ", level));
632	if (level > 0)
633		goto dive;	/* undive really */
634
635	goto failed;
636
637readdone:
638	bcopy(dep->de_name,hp->h_name,dep->de_namelen);
639	hp->h_name[dep->de_namelen] = '\0';
640	hp->h_namelen = dep->de_namelen;
641	hp->h_ctime = dep->de_ctime;
642	hp->h_atime = dep->de_atime;
643	hp->h_mtime = dep->de_mtime;
644	hp->h_flag |= H_PARVALID;
645
646	dprintf(("[readdone]"));
647
648failed:
649	dprintf(("\n"));
650	if (bp != NULL)
651		brelse(bp);
652	if (hp != dhp)
653		vput(dvp);
654
655	return (error);
656}
657
658struct timespec
659hpfstimetounix (
660	u_long hptime)
661{
662	struct timespec t;
663
664	t.tv_nsec = 0;
665	t.tv_sec = hptime;
666
667	return t;
668}
669
670/*
671 * Write down changes done to parent dir, these are only times for now.
672 * hpfsnode have to be locked.
673 */
674int
675hpfs_updateparent (
676	struct hpfsnode *hp)
677{
678	struct hpfsnode *dhp;
679	struct vnode *dvp;
680	struct hpfsdirent *dep;
681	struct buf * bp;
682	int error;
683
684	dprintf(("hpfs_updateparent(0x%x): \n", hp->h_no));
685
686	if (!(hp->h_flag & H_PARCHANGE))
687		return (0);
688
689	if (!(hp->h_flag & H_PARVALID)) {
690		error = hpfs_validateparent (hp);
691		if (error)
692			return (error);
693	}
694
695	if (hp->h_no == hp->h_fn.fn_parent) {
696		dhp = hp;
697	} else {
698		error = VFS_VGET(hp->h_hpmp->hpm_mp, hp->h_fn.fn_parent,
699				 LK_EXCLUSIVE, &dvp);
700		if (error)
701			return (error);
702		dhp = VTOHP(dvp);
703	}
704
705	error = hpfs_genlookupbyname (dhp, hp->h_name, hp->h_namelen,
706					&bp, &dep);
707	if (error) {
708		goto failed;
709	}
710
711	dep->de_atime = hp->h_atime;
712	dep->de_mtime = hp->h_mtime;
713	dep->de_size = hp->h_fn.fn_size;
714
715	bdwrite (bp);
716
717	hp->h_flag &= ~H_PARCHANGE;
718
719	error = 0;
720failed:
721	if (hp != dhp)
722		vput(dvp);
723
724	return (0);
725}
726
727/*
728 * Write down on disk changes done to fnode. hpfsnode have to be locked.
729 */
730int
731hpfs_update (
732	struct hpfsnode *hp)
733{
734	struct buf * bp;
735
736	dprintf(("hpfs_update(0x%x): \n", hp->h_no));
737
738	if (!(hp->h_flag & H_CHANGE))
739		return (0);
740
741	bp = getblk(hp->h_devvp, hp->h_no, FNODESIZE, 0, 0, 0);
742	clrbuf(bp);
743
744	bcopy (&hp->h_fn, bp->b_data, sizeof(struct fnode));
745	bdwrite (bp);
746
747	hp->h_flag &= ~H_CHANGE;
748
749	if (hp->h_flag & H_PARCHANGE)
750		return (hpfs_updateparent(hp));
751
752	return (0);
753}
754
755/*
756 * Truncate file to specifed size. hpfsnode have to be locked.
757 */
758int
759hpfs_truncate (
760	struct hpfsnode *hp,
761	u_long size)
762{
763	struct hpfsmount *hpmp = hp->h_hpmp;
764	lsn_t newblen, oldblen;
765	int error, pf;
766
767	dprintf(("hpfs_truncate(0x%x, 0x%x -> 0x%lx): ",
768		hp->h_no, hp->h_fn.fn_size, size));
769
770	newblen = (size + DEV_BSIZE - 1) >> DEV_BSHIFT;
771	oldblen = (hp->h_fn.fn_size + DEV_BSIZE - 1) >> DEV_BSHIFT;
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 */
797int
798hpfs_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		printf("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 */
836int
837hpfs_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, lsn, len, NOCRED, &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		printf("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