Per-CPU VFS Namecache Effectiveness Statistics:
[dragonfly.git] / sys / vfs / hpfs / hpfs_subr.c
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