]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/fs/hpfs/hpfs_subr.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / fs / 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$
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
47 u_long
48 hpfs_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
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, 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         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
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         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
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, 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  */
248 int
249 hpfs_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
315 int
316 hpfs_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  */
327 int
328 hpfs_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
395 step2:
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  */
449 int
450 hpfs_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  */
475 int
476 hpfs_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
526 int
527 hpfs_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
558 dive:
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
626 blockdone:
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
637 readdone:
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
648 failed:
649         dprintf(("\n"));
650         if (bp != NULL)
651                 brelse(bp);
652         if (hp != dhp)
653                 vput(dvp);
654
655         return (error);
656 }
657
658 struct timespec
659 hpfstimetounix (
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  */
674 int
675 hpfs_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;
720 failed:
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  */
730 int
731 hpfs_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  */
758 int
759 hpfs_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  */
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                 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  */
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, 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