- Fix indentation in VarFind()
[dragonfly.git] / sys / vfs / ntfs / ntfs_subr.c
1 /*      $NetBSD: ntfs_subr.c,v 1.23 1999/10/31 19:45:26 jdolecek Exp $  */
2
3 /*-
4  * Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org)
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD: src/sys/ntfs/ntfs_subr.c,v 1.7.2.4 2001/10/12 22:08:49 semenu Exp $
29  * $DragonFly: src/sys/vfs/ntfs/ntfs_subr.c,v 1.14 2004/07/02 15:26:26 joerg Exp $
30  */
31
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/systm.h>
35 #include <sys/proc.h>
36 #include <sys/namei.h>
37 #include <sys/kernel.h>
38 #include <sys/vnode.h>
39 #include <sys/mount.h>
40 #include <sys/buf.h>
41 #include <sys/file.h>
42 #include <sys/malloc.h>
43 #include <sys/lock.h>
44
45 #if defined(__NetBSD__)
46 #include <miscfs/specfs/specdev.h>
47 #endif
48
49 /* #define NTFS_DEBUG 1 */
50 #include "ntfs.h"
51 #include "ntfsmount.h"
52 #include "ntfs_inode.h"
53 #include "ntfs_vfsops.h"
54 #include "ntfs_subr.h"
55 #include "ntfs_compr.h"
56 #include "ntfs_ihash.h"
57
58 #if defined(__DragonFly__)
59 MALLOC_DEFINE(M_NTFSNTVATTR, "NTFS vattr", "NTFS file attribute information");
60 MALLOC_DEFINE(M_NTFSRDATA, "NTFS res data", "NTFS resident data");
61 MALLOC_DEFINE(M_NTFSRUN, "NTFS vrun", "NTFS vrun storage");
62 MALLOC_DEFINE(M_NTFSDECOMP, "NTFS decomp", "NTFS decompression temporary");
63 #endif
64
65 static int ntfs_ntlookupattr (struct ntfsmount *, const char *, int, int *, char **);
66 static int ntfs_findvattr (struct ntfsmount *, struct ntnode *, struct ntvattr **, struct ntvattr **, u_int32_t, const char *, size_t, cn_t);
67 static int ntfs_uastricmp (struct ntfsmount *, const wchar *, size_t, const char *, size_t);
68 static int ntfs_uastrcmp (struct ntfsmount *, const wchar *, size_t, const char *, size_t);
69
70 /* table for mapping Unicode chars into uppercase; it's filled upon first
71  * ntfs mount, freed upon last ntfs umount */
72 static wchar *ntfs_toupper_tab;
73 #define NTFS_TOUPPER(ch)        (ntfs_toupper_tab[(ch)])
74 static struct lock ntfs_toupper_lock;
75 static signed int ntfs_toupper_usecount;
76
77 /* support macro for ntfs_ntvattrget() */
78 #define NTFS_AALPCMP(aalp,type,name,namelen) (                          \
79   (aalp->al_type == type) && (aalp->al_namelen == namelen) &&           \
80   !NTFS_UASTRCMP(aalp->al_name,aalp->al_namelen,name,namelen) )
81
82 /*
83  * 
84  */
85 int
86 ntfs_ntvattrrele(struct ntvattr *vap)
87 {
88         dprintf(("ntfs_ntvattrrele: ino: %d, type: 0x%x\n",
89                  vap->va_ip->i_number, vap->va_type));
90
91         ntfs_ntrele(vap->va_ip);
92
93         return (0);
94 }
95
96 /*
97  * find the attribute in the ntnode
98  */
99 static int
100 ntfs_findvattr(struct ntfsmount *ntmp, struct ntnode *ip,
101                struct ntvattr **lvapp, struct ntvattr **vapp, u_int32_t type,
102                const char *name, size_t namelen, cn_t vcn)
103 {
104         int error;
105         struct ntvattr *vap;
106
107         if((ip->i_flag & IN_LOADED) == 0) {
108                 dprintf(("ntfs_findvattr: node not loaded, ino: %d\n",
109                        ip->i_number));
110                 error = ntfs_loadntnode(ntmp,ip);
111                 if (error) {
112                         printf("ntfs_findvattr: FAILED TO LOAD INO: %d\n",
113                                ip->i_number);
114                         return (error);
115                 }
116         }
117
118         *lvapp = NULL;
119         *vapp = NULL;
120         for (vap = ip->i_valist.lh_first; vap; vap = vap->va_list.le_next) {
121                 ddprintf(("ntfs_findvattr: type: 0x%x, vcn: %d - %d\n", \
122                           vap->va_type, (u_int32_t) vap->va_vcnstart, \
123                           (u_int32_t) vap->va_vcnend));
124                 if ((vap->va_type == type) &&
125                     (vap->va_vcnstart <= vcn) && (vap->va_vcnend >= vcn) &&
126                     (vap->va_namelen == namelen) &&
127                     (strncmp(name, vap->va_name, namelen) == 0)) {
128                         *vapp = vap;
129                         ntfs_ntref(vap->va_ip);
130                         return (0);
131                 }
132                 if (vap->va_type == NTFS_A_ATTRLIST)
133                         *lvapp = vap;
134         }
135
136         return (-1);
137 }
138
139 /*
140  * Search attribute specifed in ntnode (load ntnode if nessecary).
141  * If not found but ATTR_A_ATTRLIST present, read it in and search throught.
142  * VOP_VGET node needed, and lookup througth it's ntnode (load if nessesary).
143  *
144  * ntnode should be locked
145  */
146 int
147 ntfs_ntvattrget(struct ntfsmount *ntmp, struct ntnode *ip, u_int32_t type,
148                 const char *name, cn_t vcn, struct ntvattr **vapp)
149 {
150         struct ntvattr *lvap = NULL;
151         struct attr_attrlist *aalp;
152         struct attr_attrlist *nextaalp;
153         struct vnode   *newvp;
154         struct ntnode  *newip;
155         caddr_t         alpool;
156         size_t          namelen, len;
157         int             error;
158
159         *vapp = NULL;
160
161         if (name) {
162                 dprintf(("ntfs_ntvattrget: " \
163                          "ino: %d, type: 0x%x, name: %s, vcn: %d\n", \
164                          ip->i_number, type, name, (u_int32_t) vcn));
165                 namelen = strlen(name);
166         } else {
167                 dprintf(("ntfs_ntvattrget: " \
168                          "ino: %d, type: 0x%x, vcn: %d\n", \
169                          ip->i_number, type, (u_int32_t) vcn));
170                 name = "";
171                 namelen = 0;
172         }
173
174         error = ntfs_findvattr(ntmp, ip, &lvap, vapp, type, name, namelen, vcn);
175         if (error >= 0)
176                 return (error);
177
178         if (!lvap) {
179                 dprintf(("ntfs_ntvattrget: UNEXISTED ATTRIBUTE: " \
180                        "ino: %d, type: 0x%x, name: %s, vcn: %d\n", \
181                        ip->i_number, type, name, (u_int32_t) vcn));
182                 return (ENOENT);
183         }
184         /* Scan $ATTRIBUTE_LIST for requested attribute */
185         len = lvap->va_datalen;
186         MALLOC(alpool, caddr_t, len, M_TEMP, M_WAITOK);
187         error = ntfs_readntvattr_plain(ntmp, ip, lvap, 0, len, alpool, &len,
188                         NULL);
189         if (error)
190                 goto out;
191
192         aalp = (struct attr_attrlist *) alpool;
193         nextaalp = NULL;
194
195         for(; len > 0; aalp = nextaalp) {
196                 dprintf(("ntfs_ntvattrget: " \
197                          "attrlist: ino: %d, attr: 0x%x, vcn: %d\n", \
198                          aalp->al_inumber, aalp->al_type, \
199                          (u_int32_t) aalp->al_vcnstart));
200
201                 if (len > aalp->reclen) {
202                         nextaalp = NTFS_NEXTREC(aalp, struct attr_attrlist *);
203                 } else {
204                         nextaalp = NULL;
205                 }
206                 len -= aalp->reclen;
207
208                 if (!NTFS_AALPCMP(aalp, type, name, namelen) ||
209                     (nextaalp && (nextaalp->al_vcnstart <= vcn) &&
210                      NTFS_AALPCMP(nextaalp, type, name, namelen)))
211                         continue;
212
213                 dprintf(("ntfs_ntvattrget: attribute in ino: %d\n",
214                                  aalp->al_inumber));
215
216                 /* this is not a main record, so we can't use just plain
217                    vget() */
218                 error = ntfs_vgetex(ntmp->ntm_mountp, aalp->al_inumber,
219                                 NTFS_A_DATA, NULL, LK_EXCLUSIVE,
220                                 VG_EXT, curthread, &newvp);
221                 if (error) {
222                         printf("ntfs_ntvattrget: CAN'T VGET INO: %d\n",
223                                aalp->al_inumber);
224                         goto out;
225                 }
226                 newip = VTONT(newvp);
227                 /* XXX have to lock ntnode */
228                 error = ntfs_findvattr(ntmp, newip, &lvap, vapp,
229                                 type, name, namelen, vcn);
230                 vput(newvp);
231                 if (error == 0)
232                         goto out;
233                 printf("ntfs_ntvattrget: ATTRLIST ERROR.\n");
234                 break;
235         }
236         error = ENOENT;
237
238         dprintf(("ntfs_ntvattrget: UNEXISTED ATTRIBUTE: " \
239                "ino: %d, type: 0x%x, name: %.*s, vcn: %d\n", \
240                ip->i_number, type, (int) namelen, name, (u_int32_t) vcn));
241 out:
242         FREE(alpool, M_TEMP);
243         return (error);
244 }
245
246 /*
247  * Read ntnode from disk, make ntvattr list.
248  *
249  * ntnode should be locked
250  */
251 int
252 ntfs_loadntnode(struct ntfsmount *ntmp, struct ntnode *ip)
253 {
254         struct filerec  *mfrp;
255         daddr_t         bn;
256         int             error,off;
257         struct attr    *ap;
258         struct ntvattr *nvap;
259
260         dprintf(("ntfs_loadntnode: loading ino: %d\n",ip->i_number));
261
262         MALLOC(mfrp, struct filerec *, ntfs_bntob(ntmp->ntm_bpmftrec),
263                M_TEMP, M_WAITOK);
264
265         if (ip->i_number < NTFS_SYSNODESNUM) {
266                 struct buf     *bp;
267
268                 dprintf(("ntfs_loadntnode: read system node\n"));
269
270                 bn = ntfs_cntobn(ntmp->ntm_mftcn) +
271                         ntmp->ntm_bpmftrec * ip->i_number;
272
273                 error = bread(ntmp->ntm_devvp,
274                               bn, ntfs_bntob(ntmp->ntm_bpmftrec), &bp);
275                 if (error) {
276                         printf("ntfs_loadntnode: BREAD FAILED\n");
277                         brelse(bp);
278                         goto out;
279                 }
280                 memcpy(mfrp, bp->b_data, ntfs_bntob(ntmp->ntm_bpmftrec));
281                 bqrelse(bp);
282         } else {
283                 struct vnode   *vp;
284
285                 vp = ntmp->ntm_sysvn[NTFS_MFTINO];
286                 error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL,
287                                ip->i_number * ntfs_bntob(ntmp->ntm_bpmftrec),
288                                ntfs_bntob(ntmp->ntm_bpmftrec), mfrp, NULL);
289                 if (error) {
290                         printf("ntfs_loadntnode: ntfs_readattr failed\n");
291                         goto out;
292                 }
293         }
294
295         /* Check if magic and fixups are correct */
296         error = ntfs_procfixups(ntmp, NTFS_FILEMAGIC, (caddr_t)mfrp,
297                                 ntfs_bntob(ntmp->ntm_bpmftrec));
298         if (error) {
299                 printf("ntfs_loadntnode: BAD MFT RECORD %d\n",
300                        (u_int32_t) ip->i_number);
301                 goto out;
302         }
303
304         dprintf(("ntfs_loadntnode: load attrs for ino: %d\n",ip->i_number));
305         off = mfrp->fr_attroff;
306         ap = (struct attr *) ((caddr_t)mfrp + off);
307
308         LIST_INIT(&ip->i_valist);
309         
310         while (ap->a_hdr.a_type != -1) {
311                 error = ntfs_attrtontvattr(ntmp, &nvap, ap);
312                 if (error)
313                         break;
314                 nvap->va_ip = ip;
315
316                 LIST_INSERT_HEAD(&ip->i_valist, nvap, va_list);
317
318                 off += ap->a_hdr.reclen;
319                 ap = (struct attr *) ((caddr_t)mfrp + off);
320         }
321         if (error) {
322                 printf("ntfs_loadntnode: failed to load attr ino: %d\n",
323                        ip->i_number);
324                 goto out;
325         }
326
327         ip->i_mainrec = mfrp->fr_mainrec;
328         ip->i_nlink = mfrp->fr_nlink;
329         ip->i_frflag = mfrp->fr_flags;
330
331         ip->i_flag |= IN_LOADED;
332
333 out:
334         FREE(mfrp, M_TEMP);
335         return (error);
336 }
337                 
338 /*
339  * Routine locks ntnode and increase usecount, just opposite of
340  * ntfs_ntput().
341  */
342 int
343 ntfs_ntget(struct ntnode *ip)
344 {
345         lwkt_tokref ilock;
346
347         dprintf(("ntfs_ntget: get ntnode %d: %p, usecount: %d\n",
348                 ip->i_number, ip, ip->i_usecount));
349
350         ip->i_usecount++;       /* ZZZ */
351         lwkt_gettoken(&ilock, &ip->i_interlock);
352         LOCKMGR(&ip->i_lock, LK_EXCLUSIVE | LK_INTERLOCK, &ilock);
353
354         return 0;
355 }
356
357 /*
358  * Routine search ntnode in hash, if found: lock, inc usecount and return.
359  * If not in hash allocate structure for ntnode, prefill it, lock,
360  * inc count and return.
361  *
362  * ntnode returned locked
363  */
364 int
365 ntfs_ntlookup(struct ntfsmount *ntmp, ino_t ino, struct ntnode **ipp)
366 {
367         struct ntnode  *ip;
368
369         dprintf(("ntfs_ntlookup: looking for ntnode %d\n", ino));
370
371         do {
372                 if ((ip = ntfs_nthashlookup(ntmp->ntm_dev, ino)) != NULL) {
373                         ntfs_ntget(ip);
374                         dprintf(("ntfs_ntlookup: ntnode %d: %p, usecount: %d\n",
375                                 ino, ip, ip->i_usecount));
376                         *ipp = ip;
377                         return (0);
378                 }
379         } while (LOCKMGR(&ntfs_hashlock, LK_EXCLUSIVE | LK_SLEEPFAIL, NULL));
380
381         MALLOC(ip, struct ntnode *, sizeof(struct ntnode),
382                M_NTFSNTNODE, M_WAITOK);
383         ddprintf(("ntfs_ntlookup: allocating ntnode: %d: %p\n", ino, ip));
384         bzero((caddr_t) ip, sizeof(struct ntnode));
385
386         /* Generic initialization */
387         ip->i_devvp = ntmp->ntm_devvp;
388         ip->i_dev = ntmp->ntm_dev;
389         ip->i_number = ino;
390         ip->i_mp = ntmp;
391
392         LIST_INIT(&ip->i_fnlist);
393         vref(ip->i_devvp);
394
395         /* init lock and lock the newborn ntnode */
396         lockinit(&ip->i_lock, 0, "ntnode", 0, LK_EXCLUSIVE);
397         lwkt_token_init(&ip->i_interlock);
398         ntfs_ntget(ip);
399
400         ntfs_nthashins(ip);
401
402         LOCKMGR(&ntfs_hashlock, LK_RELEASE, NULL);
403
404         *ipp = ip;
405
406         dprintf(("ntfs_ntlookup: ntnode %d: %p, usecount: %d\n",
407                 ino, ip, ip->i_usecount));
408
409         return (0);
410 }
411
412 /*
413  * Decrement usecount of ntnode and unlock it, if usecount reach zero,
414  * deallocate ntnode.
415  *
416  * ntnode should be locked on entry, and unlocked on return.
417  */
418 void
419 ntfs_ntput(struct ntnode *ip)
420 {
421         struct ntvattr *vap;
422         lwkt_tokref ilock;
423
424         dprintf(("ntfs_ntput: rele ntnode %d: %p, usecount: %d\n",
425                 ip->i_number, ip, ip->i_usecount));
426
427         lwkt_gettoken(&ilock, &ip->i_interlock);
428         ip->i_usecount--;
429
430 #ifdef DIAGNOSTIC
431         if (ip->i_usecount < 0) {
432                 panic("ntfs_ntput: ino: %d usecount: %d \n",
433                       ip->i_number,ip->i_usecount);
434         }
435 #endif
436
437         if (ip->i_usecount > 0) {
438                 LOCKMGR(&ip->i_lock, LK_RELEASE|LK_INTERLOCK, &ilock);
439                 return;
440         }
441
442         dprintf(("ntfs_ntput: deallocating ntnode: %d\n", ip->i_number));
443
444         if (ip->i_fnlist.lh_first)
445                 panic("ntfs_ntput: ntnode has fnodes\n");
446
447         ntfs_nthashrem(ip);
448
449         while ((vap = LIST_FIRST(&ip->i_valist)) != NULL) {
450                 LIST_REMOVE(vap,va_list);
451                 ntfs_freentvattr(vap);
452         }
453         lwkt_reltoken(&ilock);
454         vrele(ip->i_devvp);
455         FREE(ip, M_NTFSNTNODE);
456 }
457
458 /*
459  * increment usecount of ntnode 
460  */
461 void
462 ntfs_ntref(struct ntnode *ip)
463 {
464         ip->i_usecount++;
465
466         dprintf(("ntfs_ntref: ino %d, usecount: %d\n",
467                 ip->i_number, ip->i_usecount));
468                         
469 }
470
471 /*
472  * Decrement usecount of ntnode.
473  */
474 void
475 ntfs_ntrele(struct ntnode *ip)
476 {
477         lwkt_tokref ilock;
478
479         dprintf(("ntfs_ntrele: rele ntnode %d: %p, usecount: %d\n",
480                 ip->i_number, ip, ip->i_usecount));
481
482         lwkt_gettoken(&ilock, &ip->i_interlock);
483         ip->i_usecount--;
484
485         if (ip->i_usecount < 0) {
486                 panic("ntfs_ntrele: ino: %d usecount: %d \n",
487                       ip->i_number,ip->i_usecount);
488         }
489         lwkt_reltoken(&ilock);
490 }
491
492 /*
493  * Deallocate all memory allocated for ntvattr
494  */
495 void
496 ntfs_freentvattr(struct ntvattr *vap)
497 {
498         if (vap->va_flag & NTFS_AF_INRUN) {
499                 if (vap->va_vruncn)
500                         FREE(vap->va_vruncn, M_NTFSRUN);
501                 if (vap->va_vruncl)
502                         FREE(vap->va_vruncl, M_NTFSRUN);
503         } else {
504                 if (vap->va_datap)
505                         FREE(vap->va_datap, M_NTFSRDATA);
506         }
507         FREE(vap, M_NTFSNTVATTR);
508 }
509
510 /*
511  * Convert disk image of attribute into ntvattr structure,
512  * runs are expanded also.
513  */
514 int
515 ntfs_attrtontvattr(struct ntfsmount *ntmp, struct ntvattr **rvapp,
516                    struct attr *rap)
517 {
518         int             error, i;
519         struct ntvattr *vap;
520
521         error = 0;
522         *rvapp = NULL;
523
524         MALLOC(vap, struct ntvattr *, sizeof(struct ntvattr),
525                 M_NTFSNTVATTR, M_WAITOK);
526         bzero(vap, sizeof(struct ntvattr));
527         vap->va_ip = NULL;
528         vap->va_flag = rap->a_hdr.a_flag;
529         vap->va_type = rap->a_hdr.a_type;
530         vap->va_compression = rap->a_hdr.a_compression;
531         vap->va_index = rap->a_hdr.a_index;
532
533         ddprintf(("type: 0x%x, index: %d", vap->va_type, vap->va_index));
534
535         vap->va_namelen = rap->a_hdr.a_namelen;
536         if (rap->a_hdr.a_namelen) {
537                 wchar *unp = (wchar *) ((caddr_t) rap + rap->a_hdr.a_nameoff);
538                 ddprintf((", name:["));
539                 for (i = 0; i < vap->va_namelen; i++) {
540                         vap->va_name[i] = unp[i];
541                         ddprintf(("%c", vap->va_name[i]));
542                 }
543                 ddprintf(("]"));
544         }
545         if (vap->va_flag & NTFS_AF_INRUN) {
546                 ddprintf((", nonres."));
547                 vap->va_datalen = rap->a_nr.a_datalen;
548                 vap->va_allocated = rap->a_nr.a_allocated;
549                 vap->va_vcnstart = rap->a_nr.a_vcnstart;
550                 vap->va_vcnend = rap->a_nr.a_vcnend;
551                 vap->va_compressalg = rap->a_nr.a_compressalg;
552                 error = ntfs_runtovrun(&(vap->va_vruncn), &(vap->va_vruncl),
553                                        &(vap->va_vruncnt),
554                                        (caddr_t) rap + rap->a_nr.a_dataoff);
555         } else {
556                 vap->va_compressalg = 0;
557                 ddprintf((", res."));
558                 vap->va_datalen = rap->a_r.a_datalen;
559                 vap->va_allocated = rap->a_r.a_datalen;
560                 vap->va_vcnstart = 0;
561                 vap->va_vcnend = ntfs_btocn(vap->va_allocated);
562                 MALLOC(vap->va_datap, caddr_t, vap->va_datalen,
563                        M_NTFSRDATA, M_WAITOK);
564                 memcpy(vap->va_datap, (caddr_t) rap + rap->a_r.a_dataoff,
565                        rap->a_r.a_datalen);
566         }
567         ddprintf((", len: %d", vap->va_datalen));
568
569         if (error)
570                 FREE(vap, M_NTFSNTVATTR);
571         else
572                 *rvapp = vap;
573
574         ddprintf(("\n"));
575
576         return (error);
577 }
578
579 /*
580  * Expand run into more utilizable and more memory eating format.
581  */
582 int
583 ntfs_runtovrun(cn_t **rcnp, cn_t **rclp, u_long *rcntp, u_int8_t *run)
584 {
585         u_int32_t       off;
586         u_int32_t       sz, i;
587         cn_t           *cn;
588         cn_t           *cl;
589         u_long          cnt;
590         cn_t            prev;
591         cn_t            tmp;
592
593         off = 0;
594         cnt = 0;
595         i = 0;
596         while (run[off]) {
597                 off += (run[off] & 0xF) + ((run[off] >> 4) & 0xF) + 1;
598                 cnt++;
599         }
600         MALLOC(cn, cn_t *, cnt * sizeof(cn_t), M_NTFSRUN, M_WAITOK);
601         MALLOC(cl, cn_t *, cnt * sizeof(cn_t), M_NTFSRUN, M_WAITOK);
602
603         off = 0;
604         cnt = 0;
605         prev = 0;
606         while (run[off]) {
607
608                 sz = run[off++];
609                 cl[cnt] = 0;
610
611                 for (i = 0; i < (sz & 0xF); i++)
612                         cl[cnt] += (u_int32_t) run[off++] << (i << 3);
613
614                 sz >>= 4;
615                 if (run[off + sz - 1] & 0x80) {
616                         tmp = ((u_int64_t) - 1) << (sz << 3);
617                         for (i = 0; i < sz; i++)
618                                 tmp |= (u_int64_t) run[off++] << (i << 3);
619                 } else {
620                         tmp = 0;
621                         for (i = 0; i < sz; i++)
622                                 tmp |= (u_int64_t) run[off++] << (i << 3);
623                 }
624                 if (tmp)
625                         prev = cn[cnt] = prev + tmp;
626                 else
627                         cn[cnt] = tmp;
628
629                 cnt++;
630         }
631         *rcnp = cn;
632         *rclp = cl;
633         *rcntp = cnt;
634         return (0);
635 }
636
637 /*
638  * Compare unicode and ascii string case insens.
639  */
640 static int
641 ntfs_uastricmp(struct ntfsmount *ntmp, const wchar *ustr, size_t ustrlen,
642                const char *astr, size_t astrlen)
643 {
644         size_t             i;
645         int             res;
646
647         /*
648          * XXX We use NTFS_82U(NTFS_U28(c)) to get rid of unicode
649          * symbols not covered by translation table
650          */
651         for (i = 0; i < ustrlen && i < astrlen; i++) {
652                 res = ((int) NTFS_TOUPPER(NTFS_82U(NTFS_U28(ustr[i])))) -
653                         ((int)NTFS_TOUPPER(NTFS_82U(astr[i])));
654                 if (res)
655                         return res;
656         }
657         return (ustrlen - astrlen);
658 }
659
660 /*
661  * Compare unicode and ascii string case sens.
662  */
663 static int
664 ntfs_uastrcmp(struct ntfsmount *ntmp, const wchar *ustr, size_t ustrlen,
665               const char *astr, size_t astrlen)
666 {
667         size_t             i;
668         int             res;
669
670         for (i = 0; (i < ustrlen) && (i < astrlen); i++) {
671                 res = (int) (((char)NTFS_U28(ustr[i])) - astr[i]);
672                 if (res)
673                         return res;
674         }
675         return (ustrlen - astrlen);
676 }
677
678 /* 
679  * Search fnode in ntnode, if not found allocate and preinitialize.
680  *
681  * ntnode should be locked on entry.
682  */
683 int
684 ntfs_fget(struct ntfsmount *ntmp, struct ntnode *ip, int attrtype,
685           char *attrname, struct fnode **fpp)
686 {
687         struct fnode *fp;
688
689         dprintf(("ntfs_fget: ino: %d, attrtype: 0x%x, attrname: %s\n",
690                 ip->i_number,attrtype, attrname?attrname:""));
691         *fpp = NULL;
692         for (fp = ip->i_fnlist.lh_first; fp != NULL; fp = fp->f_fnlist.le_next){
693                 dprintf(("ntfs_fget: fnode: attrtype: %d, attrname: %s\n",
694                         fp->f_attrtype, fp->f_attrname?fp->f_attrname:""));
695
696                 if ((attrtype == fp->f_attrtype) && 
697                     ((!attrname && !fp->f_attrname) ||
698                      (attrname && fp->f_attrname &&
699                       !strcmp(attrname,fp->f_attrname)))){
700                         dprintf(("ntfs_fget: found existed: %p\n",fp));
701                         *fpp = fp;
702                 }
703         }
704
705         if (*fpp)
706                 return (0);
707
708         MALLOC(fp, struct fnode *, sizeof(struct fnode), M_NTFSFNODE, M_WAITOK);
709         bzero(fp, sizeof(struct fnode));
710         dprintf(("ntfs_fget: allocating fnode: %p\n",fp));
711
712         fp->f_ip = ip;
713         if (attrname) {
714                 fp->f_flag |= FN_AATTRNAME;
715                 MALLOC(fp->f_attrname, char *, strlen(attrname)+1, M_TEMP, M_WAITOK);
716                 strcpy(fp->f_attrname, attrname);
717         } else
718                 fp->f_attrname = NULL;
719         fp->f_attrtype = attrtype;
720
721         ntfs_ntref(ip);
722
723         LIST_INSERT_HEAD(&ip->i_fnlist, fp, f_fnlist);
724
725         *fpp = fp;
726
727         return (0);
728 }
729
730 /*
731  * Deallocate fnode, remove it from ntnode's fnode list.
732  *
733  * ntnode should be locked.
734  */
735 void
736 ntfs_frele(struct fnode *fp)
737 {
738         struct ntnode *ip = FTONT(fp);
739
740         dprintf(("ntfs_frele: fnode: %p for %d: %p\n", fp, ip->i_number, ip));
741
742         dprintf(("ntfs_frele: deallocating fnode\n"));
743         LIST_REMOVE(fp,f_fnlist);
744         if (fp->f_flag & FN_AATTRNAME)
745                 FREE(fp->f_attrname, M_TEMP);
746         if (fp->f_dirblbuf)
747                 FREE(fp->f_dirblbuf, M_NTFSDIR);
748         FREE(fp, M_NTFSFNODE);
749         ntfs_ntrele(ip);
750 }
751
752 /*
753  * Lookup attribute name in format: [[:$ATTR_TYPE]:$ATTR_NAME], 
754  * $ATTR_TYPE is searched in attrdefs read from $AttrDefs.
755  * If $ATTR_TYPE nott specifed, ATTR_A_DATA assumed.
756  */
757 static int
758 ntfs_ntlookupattr(struct ntfsmount *ntmp, const char *name, int namelen,
759                   int *attrtype, char **attrname)
760 {
761         const char *sys;
762         size_t syslen, i;
763         struct ntvattrdef *adp;
764
765         if (namelen == 0)
766                 return (0);
767
768         if (name[0] == '$') {
769                 sys = name;
770                 for (syslen = 0; syslen < namelen; syslen++) {
771                         if(sys[syslen] == ':') {
772                                 name++;
773                                 namelen--;
774                                 break;
775                         }
776                 }
777                 name += syslen;
778                 namelen -= syslen;
779
780                 adp = ntmp->ntm_ad;
781                 for (i = 0; i < ntmp->ntm_adnum; i++, adp++){
782                         if (syslen != adp->ad_namelen || 
783                            strncmp(sys, adp->ad_name, syslen) != 0)
784                                 continue;
785
786                         *attrtype = adp->ad_type;
787                         goto out;
788                 }
789                 return (ENOENT);
790         } else
791                 *attrtype = NTFS_A_DATA;
792
793     out:
794         if (namelen) {
795                 MALLOC((*attrname), char *, namelen, M_TEMP, M_WAITOK);
796                 memcpy((*attrname), name, namelen);
797                 (*attrname)[namelen] = '\0';
798         }
799
800         return (0);
801 }
802
803 /*
804  * Lookup specifed node for filename, matching cnp,
805  * return fnode filled.
806  */
807 int
808 ntfs_ntlookupfile(struct ntfsmount *ntmp, struct vnode *vp,
809                   struct componentname *cnp, struct vnode **vpp)
810 {
811         struct fnode   *fp = VTOF(vp);
812         struct ntnode  *ip = FTONT(fp);
813         struct ntvattr *vap;    /* Root attribute */
814         cn_t            cn;     /* VCN in current attribute */
815         caddr_t         rdbuf;  /* Buffer to read directory's blocks  */
816         u_int32_t       blsize;
817         u_int32_t       rdsize; /* Length of data to read from current block */
818         struct attr_indexentry *iep;
819         int             error, res, anamelen, fnamelen;
820         const char     *fname,*aname;
821         u_int32_t       aoff;
822         int attrtype = NTFS_A_DATA;
823         char *attrname = NULL;
824         struct fnode   *nfp;
825         struct vnode   *nvp;
826         enum vtype      f_type;
827
828         error = ntfs_ntget(ip);
829         if (error)
830                 return (error);
831
832         error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXROOT, "$I30", 0, &vap);
833         if (error || (vap->va_flag & NTFS_AF_INRUN))
834                 return (ENOTDIR);
835
836         blsize = vap->va_a_iroot->ir_size;
837         rdsize = vap->va_datalen;
838
839         /*
840          * Divide file name into: foofilefoofilefoofile[:attrspec]
841          * Store like this:       fname:fnamelen       [aname:anamelen]
842          */
843         fname = cnp->cn_nameptr;
844         aname = NULL;
845         anamelen = 0;
846         for (fnamelen = 0; fnamelen < cnp->cn_namelen; fnamelen++)
847                 if(fname[fnamelen] == ':') {
848                         aname = fname + fnamelen + 1;
849                         anamelen = cnp->cn_namelen - fnamelen - 1;
850                         dprintf(("ntfs_ntlookupfile: %s (%d), attr: %s (%d)\n",
851                                 fname, fnamelen, aname, anamelen));
852                         break;
853                 }
854
855         dprintf(("ntfs_ntlookupfile: blksz: %d, rdsz: %d\n", blsize, rdsize));
856
857         MALLOC(rdbuf, caddr_t, blsize, M_TEMP, M_WAITOK);
858
859         error = ntfs_readattr(ntmp, ip, NTFS_A_INDXROOT, "$I30",
860                                0, rdsize, rdbuf, NULL);
861         if (error)
862                 goto fail;
863
864         aoff = sizeof(struct attr_indexroot);
865
866         do {
867                 iep = (struct attr_indexentry *) (rdbuf + aoff);
868
869                 for (; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (rdsize > aoff);
870                         aoff += iep->reclen,
871                         iep = (struct attr_indexentry *) (rdbuf + aoff))
872                 {
873                         ddprintf(("scan: %d, %d\n",
874                                   (u_int32_t) iep->ie_number,
875                                   (u_int32_t) iep->ie_fnametype));
876
877                         /* check the name - the case-insensitible check
878                          * has to come first, to break from this for loop
879                          * if needed, so we can dive correctly */
880                         res = NTFS_UASTRICMP(iep->ie_fname, iep->ie_fnamelen,
881                                 fname, fnamelen);
882                         if (res > 0) break;
883                         if (res < 0) continue;
884
885                         if (iep->ie_fnametype == 0 ||
886                             !(ntmp->ntm_flag & NTFS_MFLAG_CASEINS))
887                         {
888                                 res = NTFS_UASTRCMP(iep->ie_fname,
889                                         iep->ie_fnamelen, fname, fnamelen);
890                                 if (res != 0) continue;
891                         }
892
893                         if (aname) {
894                                 error = ntfs_ntlookupattr(ntmp,
895                                         aname, anamelen,
896                                         &attrtype, &attrname);
897                                 if (error)
898                                         goto fail;
899                         }
900
901                         /* Check if we've found ourself */
902                         if ((iep->ie_number == ip->i_number) &&
903                             (attrtype == fp->f_attrtype) &&
904                             ((!attrname && !fp->f_attrname) ||
905                              (attrname && fp->f_attrname &&
906                               !strcmp(attrname, fp->f_attrname))))
907                         {
908                                 vref(vp);
909                                 *vpp = vp;
910                                 error = 0;
911                                 goto fail;
912                         }
913
914                         /* vget node, but don't load it */
915                         error = ntfs_vgetex(ntmp->ntm_mountp,
916                                    iep->ie_number, attrtype, attrname,
917                                    LK_EXCLUSIVE, VG_DONTLOADIN | VG_DONTVALIDFN,
918                                    curthread, &nvp);
919
920                         /* free the buffer returned by ntfs_ntlookupattr() */
921                         if (attrname) {
922                                 FREE(attrname, M_TEMP);
923                                 attrname = NULL;
924                         }
925
926                         if (error)
927                                 goto fail;
928
929                         nfp = VTOF(nvp);
930
931                         if (nfp->f_flag & FN_VALID) {
932                                 *vpp = nvp;
933                                 goto fail;
934                         }
935
936                         nfp->f_fflag = iep->ie_fflag;
937                         nfp->f_pnumber = iep->ie_fpnumber;
938                         nfp->f_times = iep->ie_ftimes;
939
940                         if((nfp->f_fflag & NTFS_FFLAG_DIR) &&
941                            (nfp->f_attrtype == NTFS_A_DATA) &&
942                            (nfp->f_attrname == NULL))
943                                 f_type = VDIR;  
944                         else
945                                 f_type = VREG;  
946
947                         nvp->v_type = f_type;
948
949                         if ((nfp->f_attrtype == NTFS_A_DATA) &&
950                             (nfp->f_attrname == NULL))
951                         {
952                                 /* Opening default attribute */
953                                 nfp->f_size = iep->ie_fsize;
954                                 nfp->f_allocated = iep->ie_fallocated;
955                                 nfp->f_flag |= FN_PRELOADED;
956                         } else {
957                                 error = ntfs_filesize(ntmp, nfp,
958                                             &nfp->f_size, &nfp->f_allocated);
959                                 if (error) {
960                                         vput(nvp);
961                                         goto fail;
962                                 }
963                         }
964
965                         nfp->f_flag &= ~FN_VALID;
966                         *vpp = nvp;
967                         goto fail;
968                 }
969
970                 /* Dive if possible */
971                 if (iep->ie_flag & NTFS_IEFLAG_SUBNODE) {
972                         dprintf(("ntfs_ntlookupfile: diving\n"));
973
974                         cn = *(cn_t *) (rdbuf + aoff +
975                                         iep->reclen - sizeof(cn_t));
976                         rdsize = blsize;
977
978                         error = ntfs_readattr(ntmp, ip, NTFS_A_INDX, "$I30",
979                                         ntfs_cntob(cn), rdsize, rdbuf, NULL);
980                         if (error)
981                                 goto fail;
982
983                         error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC,
984                                                 rdbuf, rdsize);
985                         if (error)
986                                 goto fail;
987
988                         aoff = (((struct attr_indexalloc *) rdbuf)->ia_hdrsize +
989                                 0x18);
990                 } else {
991                         dprintf(("ntfs_ntlookupfile: nowhere to dive :-(\n"));
992                         error = ENOENT;
993                         break;
994                 }
995         } while (1);
996
997         dprintf(("finish\n"));
998
999 fail:
1000         if (attrname) FREE(attrname, M_TEMP);
1001         ntfs_ntvattrrele(vap);
1002         ntfs_ntput(ip);
1003         FREE(rdbuf, M_TEMP);
1004         return (error);
1005 }
1006
1007 /*
1008  * Check if name type is permitted to show.
1009  */
1010 int
1011 ntfs_isnamepermitted(struct ntfsmount *ntmp, struct attr_indexentry *iep)
1012 {
1013         if (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES)
1014                 return 1;
1015
1016         switch (iep->ie_fnametype) {
1017         case 2:
1018                 ddprintf(("ntfs_isnamepermitted: skiped DOS name\n"));
1019                 return 0;
1020         case 0: case 1: case 3:
1021                 return 1;
1022         default:
1023                 printf("ntfs_isnamepermitted: " \
1024                        "WARNING! Unknown file name type: %d\n",
1025                        iep->ie_fnametype);
1026                 break;
1027         }
1028         return 0;
1029 }
1030
1031 /*
1032  * Read ntfs dir like stream of attr_indexentry, not like btree of them.
1033  * This is done by scaning $BITMAP:$I30 for busy clusters and reading them.
1034  * Ofcouse $INDEX_ROOT:$I30 is read before. Last read values are stored in
1035  * fnode, so we can skip toward record number num almost immediatly.
1036  * Anyway this is rather slow routine. The problem is that we don't know
1037  * how many records are there in $INDEX_ALLOCATION:$I30 block.
1038  */
1039 int
1040 ntfs_ntreaddir(struct ntfsmount *ntmp, struct fnode *fp,
1041                u_int32_t num, struct attr_indexentry **riepp)
1042 {
1043         struct ntnode  *ip = FTONT(fp);
1044         struct ntvattr *vap = NULL;     /* IndexRoot attribute */
1045         struct ntvattr *bmvap = NULL;   /* BitMap attribute */
1046         struct ntvattr *iavap = NULL;   /* IndexAllocation attribute */
1047         caddr_t         rdbuf;          /* Buffer to read directory's blocks  */
1048         u_char         *bmp = NULL;     /* Bitmap */
1049         u_int32_t       blsize;         /* Index allocation size (2048) */
1050         u_int32_t       rdsize;         /* Length of data to read */
1051         u_int32_t       attrnum;        /* Current attribute type */
1052         u_int32_t       cpbl = 1;       /* Clusters per directory block */
1053         u_int32_t       blnum;
1054         struct attr_indexentry *iep;
1055         int             error = ENOENT;
1056         u_int32_t       aoff, cnum;
1057
1058         dprintf(("ntfs_ntreaddir: read ino: %d, num: %d\n", ip->i_number, num));
1059         error = ntfs_ntget(ip);
1060         if (error)
1061                 return (error);
1062
1063         error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXROOT, "$I30", 0, &vap);
1064         if (error)
1065                 return (ENOTDIR);
1066
1067         if (fp->f_dirblbuf == NULL) {
1068                 fp->f_dirblsz = vap->va_a_iroot->ir_size;
1069                 MALLOC(fp->f_dirblbuf, caddr_t,
1070                        max(vap->va_datalen,fp->f_dirblsz), M_NTFSDIR, M_WAITOK);
1071         }
1072
1073         blsize = fp->f_dirblsz;
1074         rdbuf = fp->f_dirblbuf;
1075
1076         dprintf(("ntfs_ntreaddir: rdbuf: 0x%p, blsize: %d\n", rdbuf, blsize));
1077
1078         if (vap->va_a_iroot->ir_flag & NTFS_IRFLAG_INDXALLOC) {
1079                 error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXBITMAP, "$I30",
1080                                         0, &bmvap);
1081                 if (error) {
1082                         error = ENOTDIR;
1083                         goto fail;
1084                 }
1085                 MALLOC(bmp, u_char *, bmvap->va_datalen, M_TEMP, M_WAITOK);
1086                 error = ntfs_readattr(ntmp, ip, NTFS_A_INDXBITMAP, "$I30", 0,
1087                                        bmvap->va_datalen, bmp, NULL);
1088                 if (error)
1089                         goto fail;
1090
1091                 error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDX, "$I30",
1092                                         0, &iavap);
1093                 if (error) {
1094                         error = ENOTDIR;
1095                         goto fail;
1096                 }
1097                 cpbl = ntfs_btocn(blsize + ntfs_cntob(1) - 1);
1098                 dprintf(("ntfs_ntreaddir: indexalloc: %d, cpbl: %d\n",
1099                          iavap->va_datalen, cpbl));
1100         } else {
1101                 dprintf(("ntfs_ntreadidir: w/o BitMap and IndexAllocation\n"));
1102                 iavap = bmvap = NULL;
1103                 bmp = NULL;
1104         }
1105
1106         /* Try use previous values */
1107         if ((fp->f_lastdnum < num) && (fp->f_lastdnum != 0)) {
1108                 attrnum = fp->f_lastdattr;
1109                 aoff = fp->f_lastdoff;
1110                 blnum = fp->f_lastdblnum;
1111                 cnum = fp->f_lastdnum;
1112         } else {
1113                 attrnum = NTFS_A_INDXROOT;
1114                 aoff = sizeof(struct attr_indexroot);
1115                 blnum = 0;
1116                 cnum = 0;
1117         }
1118
1119         do {
1120                 dprintf(("ntfs_ntreaddir: scan: 0x%x, %d, %d, %d, %d\n",
1121                          attrnum, (u_int32_t) blnum, cnum, num, aoff));
1122                 rdsize = (attrnum == NTFS_A_INDXROOT) ? vap->va_datalen : blsize;
1123                 error = ntfs_readattr(ntmp, ip, attrnum, "$I30",
1124                                 ntfs_cntob(blnum * cpbl), rdsize, rdbuf, NULL);
1125                 if (error)
1126                         goto fail;
1127
1128                 if (attrnum == NTFS_A_INDX) {
1129                         error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC,
1130                                                 rdbuf, rdsize);
1131                         if (error)
1132                                 goto fail;
1133                 }
1134                 if (aoff == 0)
1135                         aoff = (attrnum == NTFS_A_INDX) ?
1136                                 (0x18 + ((struct attr_indexalloc *) rdbuf)->ia_hdrsize) :
1137                                 sizeof(struct attr_indexroot);
1138
1139                 iep = (struct attr_indexentry *) (rdbuf + aoff);
1140                 for (; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (rdsize > aoff);
1141                         aoff += iep->reclen,
1142                         iep = (struct attr_indexentry *) (rdbuf + aoff))
1143                 {
1144                         if (!ntfs_isnamepermitted(ntmp, iep)) continue;
1145
1146                         if (cnum >= num) {
1147                                 fp->f_lastdnum = cnum;
1148                                 fp->f_lastdoff = aoff;
1149                                 fp->f_lastdblnum = blnum;
1150                                 fp->f_lastdattr = attrnum;
1151
1152                                 *riepp = iep;
1153
1154                                 error = 0;
1155                                 goto fail;
1156                         }
1157                         cnum++;
1158                 }
1159
1160                 if (iavap) {
1161                         if (attrnum == NTFS_A_INDXROOT)
1162                                 blnum = 0;
1163                         else
1164                                 blnum++;
1165
1166                         while (ntfs_cntob(blnum * cpbl) < iavap->va_datalen) {
1167                                 if (bmp[blnum >> 3] & (1 << (blnum & 3)))
1168                                         break;
1169                                 blnum++;
1170                         }
1171
1172                         attrnum = NTFS_A_INDX;
1173                         aoff = 0;
1174                         if (ntfs_cntob(blnum * cpbl) >= iavap->va_datalen)
1175                                 break;
1176                         dprintf(("ntfs_ntreaddir: blnum: %d\n", (u_int32_t) blnum));
1177                 }
1178         } while (iavap);
1179
1180         *riepp = NULL;
1181         fp->f_lastdnum = 0;
1182
1183 fail:
1184         if (vap)
1185                 ntfs_ntvattrrele(vap);
1186         if (bmvap)
1187                 ntfs_ntvattrrele(bmvap);
1188         if (iavap)
1189                 ntfs_ntvattrrele(iavap);
1190         if (bmp)
1191                 FREE(bmp, M_TEMP);
1192         ntfs_ntput(ip);
1193         return (error);
1194 }
1195
1196 /*
1197  * Convert NTFS times that are in 100 ns units and begins from
1198  * 1601 Jan 1 into unix times.
1199  */
1200 struct timespec
1201 ntfs_nttimetounix(u_int64_t nt)
1202 {
1203         struct timespec t;
1204
1205         /* WindowNT times are in 100 ns and from 1601 Jan 1 */
1206         t.tv_nsec = (nt % (1000 * 1000 * 10)) * 100;
1207         t.tv_sec = nt / (1000 * 1000 * 10) -
1208                 369LL * 365LL * 24LL * 60LL * 60LL -
1209                 89LL * 1LL * 24LL * 60LL * 60LL;
1210         return (t);
1211 }
1212
1213 /*
1214  * Get file times from NTFS_A_NAME attribute.
1215  */
1216 int
1217 ntfs_times(struct ntfsmount *ntmp, struct ntnode *ip, ntfs_times_t *tm)
1218 {
1219         struct ntvattr *vap;
1220         int             error;
1221
1222         dprintf(("ntfs_times: ino: %d...\n", ip->i_number));
1223
1224         error = ntfs_ntget(ip);
1225         if (error)
1226                 return (error);
1227
1228         error = ntfs_ntvattrget(ntmp, ip, NTFS_A_NAME, NULL, 0, &vap);
1229         if (error) {
1230                 ntfs_ntput(ip);
1231                 return (error);
1232         }
1233         *tm = vap->va_a_name->n_times;
1234         ntfs_ntvattrrele(vap);
1235         ntfs_ntput(ip);
1236
1237         return (0);
1238 }
1239
1240 /*
1241  * Get file sizes from corresponding attribute. 
1242  * 
1243  * ntnode under fnode should be locked.
1244  */
1245 int
1246 ntfs_filesize(struct ntfsmount *ntmp, struct fnode *fp, u_int64_t *size,
1247               u_int64_t *bytes)
1248 {
1249         struct ntvattr *vap;
1250         struct ntnode *ip = FTONT(fp);
1251         u_int64_t       sz, bn;
1252         int             error;
1253
1254         dprintf(("ntfs_filesize: ino: %d\n", ip->i_number));
1255
1256         error = ntfs_ntvattrget(ntmp, ip,
1257                 fp->f_attrtype, fp->f_attrname, 0, &vap);
1258         if (error)
1259                 return (error);
1260
1261         bn = vap->va_allocated;
1262         sz = vap->va_datalen;
1263
1264         dprintf(("ntfs_filesize: %d bytes (%d bytes allocated)\n",
1265                 (u_int32_t) sz, (u_int32_t) bn));
1266
1267         if (size)
1268                 *size = sz;
1269         if (bytes)
1270                 *bytes = bn;
1271
1272         ntfs_ntvattrrele(vap);
1273
1274         return (0);
1275 }
1276
1277 /*
1278  * This is one of write routine.
1279  */
1280 int
1281 ntfs_writeattr_plain(struct ntfsmount *ntmp, struct ntnode *ip,
1282                      u_int32_t attrnum, char *attrname, off_t roff,
1283                      size_t rsize, void *rdata, size_t *initp,
1284                      struct uio *uio)
1285 {
1286         size_t          init;
1287         int             error = 0;
1288         off_t           off = roff, left = rsize, towrite;
1289         caddr_t         data = rdata;
1290         struct ntvattr *vap;
1291         *initp = 0;
1292
1293         while (left) {
1294                 error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname,
1295                                         ntfs_btocn(off), &vap);
1296                 if (error)
1297                         return (error);
1298                 towrite = min(left, ntfs_cntob(vap->va_vcnend + 1) - off);
1299                 ddprintf(("ntfs_writeattr_plain: o: %d, s: %d (%d - %d)\n",
1300                          (u_int32_t) off, (u_int32_t) towrite,
1301                          (u_int32_t) vap->va_vcnstart,
1302                          (u_int32_t) vap->va_vcnend));
1303                 error = ntfs_writentvattr_plain(ntmp, ip, vap,
1304                                          off - ntfs_cntob(vap->va_vcnstart),
1305                                          towrite, data, &init, uio);
1306                 if (error) {
1307                         printf("ntfs_writeattr_plain: " \
1308                                "ntfs_writentvattr_plain failed: o: %d, s: %d\n",
1309                                (u_int32_t) off, (u_int32_t) towrite);
1310                         printf("ntfs_writeattr_plain: attrib: %d - %d\n",
1311                                (u_int32_t) vap->va_vcnstart, 
1312                                (u_int32_t) vap->va_vcnend);
1313                         ntfs_ntvattrrele(vap);
1314                         break;
1315                 }
1316                 ntfs_ntvattrrele(vap);
1317                 left -= towrite;
1318                 off += towrite;
1319                 data = data + towrite;
1320                 *initp += init;
1321         }
1322
1323         return (error);
1324 }
1325
1326 /*
1327  * This is one of write routine.
1328  *
1329  * ntnode should be locked.
1330  */
1331 int
1332 ntfs_writentvattr_plain(struct ntfsmount *ntmp, struct ntnode *ip,
1333                         struct ntvattr *vap, off_t roff, size_t rsize,
1334                         void *rdata, size_t *initp, struct uio *uio)
1335 {
1336         int             error = 0;
1337         int             off;
1338         int             cnt;
1339         cn_t            ccn, ccl, cn, left, cl;
1340         caddr_t         data = rdata;
1341         struct buf     *bp;
1342         size_t          tocopy;
1343
1344         *initp = 0;
1345
1346         if ((vap->va_flag & NTFS_AF_INRUN) == 0) {
1347                 printf("ntfs_writevattr_plain: CAN'T WRITE RES. ATTRIBUTE\n");
1348                 return ENOTTY;
1349         }
1350
1351         ddprintf(("ntfs_writentvattr_plain: data in run: %ld chains\n",
1352                  vap->va_vruncnt));
1353
1354         off = roff;
1355         left = rsize;
1356         ccl = 0;
1357         ccn = 0;
1358         cnt = 0;
1359         for (; left && (cnt < vap->va_vruncnt); cnt++) {
1360                 ccn = vap->va_vruncn[cnt];
1361                 ccl = vap->va_vruncl[cnt];
1362
1363                 ddprintf(("ntfs_writentvattr_plain: " \
1364                          "left %d, cn: 0x%x, cl: %d, off: %d\n", \
1365                          (u_int32_t) left, (u_int32_t) ccn, \
1366                          (u_int32_t) ccl, (u_int32_t) off));
1367
1368                 if (ntfs_cntob(ccl) < off) {
1369                         off -= ntfs_cntob(ccl);
1370                         cnt++;
1371                         continue;
1372                 }
1373                 if (!ccn && ip->i_number != NTFS_BOOTINO)
1374                         continue; /* XXX */
1375
1376                 ccl -= ntfs_btocn(off);
1377                 cn = ccn + ntfs_btocn(off);
1378                 off = ntfs_btocnoff(off);
1379
1380                 while (left && ccl) {
1381 #if defined(__DragonFly__)
1382                         tocopy = min(left,
1383                                   min(ntfs_cntob(ccl) - off, MAXBSIZE - off));
1384 #else
1385                         /* under NetBSD, bread() can read
1386                          * maximum one block worth of data */
1387                         tocopy = min(left, ntmp->ntm_bps - off);
1388 #endif
1389                         cl = ntfs_btocl(tocopy + off);
1390                         ddprintf(("ntfs_writentvattr_plain: write: " \
1391                                 "cn: 0x%x cl: %d, off: %d len: %d, left: %d\n",
1392                                 (u_int32_t) cn, (u_int32_t) cl, 
1393                                 (u_int32_t) off, (u_int32_t) tocopy, 
1394                                 (u_int32_t) left));
1395                         if ((off == 0) && (tocopy == ntfs_cntob(cl)))
1396                         {
1397                                 bp = getblk(ntmp->ntm_devvp, ntfs_cntobn(cn),
1398                                             ntfs_cntob(cl), 0, 0);
1399                                 clrbuf(bp);
1400                         } else {
1401                                 error = bread(ntmp->ntm_devvp, ntfs_cntobn(cn),
1402                                               ntfs_cntob(cl), &bp);
1403                                 if (error) {
1404                                         brelse(bp);
1405                                         return (error);
1406                                 }
1407                         }
1408                         if (uio)
1409                                 uiomove(bp->b_data + off, tocopy, uio);
1410                         else
1411                                 memcpy(bp->b_data + off, data, tocopy);
1412                         bawrite(bp);
1413                         data = data + tocopy;
1414                         *initp += tocopy;
1415                         off = 0;
1416                         left -= tocopy;
1417                         cn += cl;
1418                         ccl -= cl;
1419                 }
1420         }
1421
1422         if (left) {
1423                 printf("ntfs_writentvattr_plain: POSSIBLE RUN ERROR\n");
1424                 error = EINVAL;
1425         }
1426
1427         return (error);
1428 }
1429
1430 /*
1431  * This is one of read routines.
1432  *
1433  * ntnode should be locked.
1434  */
1435 int
1436 ntfs_readntvattr_plain(struct ntfsmount *ntmp, struct ntnode *ip,
1437                        struct ntvattr *vap, off_t roff, size_t rsize,
1438                        void *rdata, size_t *initp, struct uio *uio)
1439 {
1440         int             error = 0;
1441         int             off;
1442
1443         *initp = 0;
1444         if (vap->va_flag & NTFS_AF_INRUN) {
1445                 int             cnt;
1446                 cn_t            ccn, ccl, cn, left, cl;
1447                 caddr_t         data = rdata;
1448                 struct buf     *bp;
1449                 size_t          tocopy;
1450
1451                 ddprintf(("ntfs_readntvattr_plain: data in run: %ld chains\n",
1452                          vap->va_vruncnt));
1453
1454                 off = roff;
1455                 left = rsize;
1456                 ccl = 0;
1457                 ccn = 0;
1458                 cnt = 0;
1459                 while (left && (cnt < vap->va_vruncnt)) {
1460                         ccn = vap->va_vruncn[cnt];
1461                         ccl = vap->va_vruncl[cnt];
1462
1463                         ddprintf(("ntfs_readntvattr_plain: " \
1464                                  "left %d, cn: 0x%x, cl: %d, off: %d\n", \
1465                                  (u_int32_t) left, (u_int32_t) ccn, \
1466                                  (u_int32_t) ccl, (u_int32_t) off));
1467
1468                         if (ntfs_cntob(ccl) < off) {
1469                                 off -= ntfs_cntob(ccl);
1470                                 cnt++;
1471                                 continue;
1472                         }
1473                         if (ccn || ip->i_number == NTFS_BOOTINO) {
1474                                 ccl -= ntfs_btocn(off);
1475                                 cn = ccn + ntfs_btocn(off);
1476                                 off = ntfs_btocnoff(off);
1477
1478                                 while (left && ccl) {
1479 #if defined(__DragonFly__)
1480                                         tocopy = min(left,
1481                                                   min(ntfs_cntob(ccl) - off,
1482                                                       MAXBSIZE - off));
1483 #else
1484                                         /* under NetBSD, bread() can read
1485                                          * maximum one block worth of data */
1486                                         tocopy = min(left,
1487                                                 ntmp->ntm_bps - off);
1488 #endif
1489                                         cl = ntfs_btocl(tocopy + off);
1490                                         ddprintf(("ntfs_readntvattr_plain: " \
1491                                                 "read: cn: 0x%x cl: %d, " \
1492                                                 "off: %d len: %d, left: %d\n",
1493                                                 (u_int32_t) cn, 
1494                                                 (u_int32_t) cl, 
1495                                                 (u_int32_t) off, 
1496                                                 (u_int32_t) tocopy, 
1497                                                 (u_int32_t) left));
1498                                         error = bread(ntmp->ntm_devvp,
1499                                                       ntfs_cntobn(cn),
1500                                                       ntfs_cntob(cl),
1501                                                       &bp);
1502                                         if (error) {
1503                                                 brelse(bp);
1504                                                 return (error);
1505                                         }
1506                                         if (uio) {
1507                                                 uiomove(bp->b_data + off,
1508                                                         tocopy, uio);
1509                                         } else {
1510                                                 memcpy(data, bp->b_data + off,
1511                                                         tocopy);
1512                                         }
1513                                         brelse(bp);
1514                                         data = data + tocopy;
1515                                         *initp += tocopy;
1516                                         off = 0;
1517                                         left -= tocopy;
1518                                         cn += cl;
1519                                         ccl -= cl;
1520                                 }
1521                         } else {
1522                                 tocopy = min(left, ntfs_cntob(ccl) - off);
1523                                 ddprintf(("ntfs_readntvattr_plain: "
1524                                         "hole: ccn: 0x%x ccl: %d, off: %d, " \
1525                                         " len: %d, left: %d\n", 
1526                                         (u_int32_t) ccn, (u_int32_t) ccl, 
1527                                         (u_int32_t) off, (u_int32_t) tocopy, 
1528                                         (u_int32_t) left));
1529                                 left -= tocopy;
1530                                 off = 0;
1531                                 if (uio) {
1532                                         size_t remains = tocopy;
1533                                         for(; remains; remains++)
1534                                                 uiomove("", 1, uio);
1535                                 } else 
1536                                         bzero(data, tocopy);
1537                                 data = data + tocopy;
1538                         }
1539                         cnt++;
1540                 }
1541                 if (left) {
1542                         printf("ntfs_readntvattr_plain: POSSIBLE RUN ERROR\n");
1543                         error = E2BIG;
1544                 }
1545         } else {
1546                 ddprintf(("ntfs_readnvattr_plain: data is in mft record\n"));
1547                 if (uio) 
1548                         uiomove(vap->va_datap + roff, rsize, uio);
1549                 else
1550                         memcpy(rdata, vap->va_datap + roff, rsize);
1551                 *initp += rsize;
1552         }
1553
1554         return (error);
1555 }
1556
1557 /*
1558  * This is one of read routines.
1559  */
1560 int
1561 ntfs_readattr_plain(struct ntfsmount *ntmp, struct ntnode *ip,
1562                     u_int32_t attrnum, char *attrname, off_t roff,
1563                     size_t rsize, void *rdata, size_t * initp,
1564                     struct uio *uio)
1565 {
1566         size_t          init;
1567         int             error = 0;
1568         off_t           off = roff, left = rsize, toread;
1569         caddr_t         data = rdata;
1570         struct ntvattr *vap;
1571         *initp = 0;
1572
1573         while (left) {
1574                 error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname,
1575                                         ntfs_btocn(off), &vap);
1576                 if (error)
1577                         return (error);
1578                 toread = min(left, ntfs_cntob(vap->va_vcnend + 1) - off);
1579                 ddprintf(("ntfs_readattr_plain: o: %d, s: %d (%d - %d)\n",
1580                          (u_int32_t) off, (u_int32_t) toread,
1581                          (u_int32_t) vap->va_vcnstart,
1582                          (u_int32_t) vap->va_vcnend));
1583                 error = ntfs_readntvattr_plain(ntmp, ip, vap,
1584                                          off - ntfs_cntob(vap->va_vcnstart),
1585                                          toread, data, &init, uio);
1586                 if (error) {
1587                         printf("ntfs_readattr_plain: " \
1588                                "ntfs_readntvattr_plain failed: o: %d, s: %d\n",
1589                                (u_int32_t) off, (u_int32_t) toread);
1590                         printf("ntfs_readattr_plain: attrib: %d - %d\n",
1591                                (u_int32_t) vap->va_vcnstart, 
1592                                (u_int32_t) vap->va_vcnend);
1593                         ntfs_ntvattrrele(vap);
1594                         break;
1595                 }
1596                 ntfs_ntvattrrele(vap);
1597                 left -= toread;
1598                 off += toread;
1599                 data = data + toread;
1600                 *initp += init;
1601         }
1602
1603         return (error);
1604 }
1605
1606 /*
1607  * This is one of read routines.
1608  */
1609 int
1610 ntfs_readattr(struct ntfsmount *ntmp, struct ntnode *ip, u_int32_t attrnum,
1611               char *attrname, off_t roff, size_t rsize, void *rdata,
1612               struct uio *uio)
1613 {
1614         int             error = 0;
1615         struct ntvattr *vap;
1616         size_t          init;
1617
1618         ddprintf(("ntfs_readattr: reading %d: 0x%x, from %d size %d bytes\n",
1619                ip->i_number, attrnum, (u_int32_t) roff, (u_int32_t) rsize));
1620
1621         error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname, 0, &vap);
1622         if (error)
1623                 return (error);
1624
1625         if ((roff > vap->va_datalen) ||
1626             (roff + rsize > vap->va_datalen)) {
1627                 ddprintf(("ntfs_readattr: offset too big\n"));
1628                 ntfs_ntvattrrele(vap);
1629                 return (E2BIG);
1630         }
1631         if (vap->va_compression && vap->va_compressalg) {
1632                 u_int8_t       *cup;
1633                 u_int8_t       *uup;
1634                 off_t           off = roff, left = rsize, tocopy;
1635                 caddr_t         data = rdata;
1636                 cn_t            cn;
1637
1638                 ddprintf(("ntfs_ntreadattr: compression: %d\n",
1639                          vap->va_compressalg));
1640
1641                 MALLOC(cup, u_int8_t *, ntfs_cntob(NTFS_COMPUNIT_CL),
1642                        M_NTFSDECOMP, M_WAITOK);
1643                 MALLOC(uup, u_int8_t *, ntfs_cntob(NTFS_COMPUNIT_CL),
1644                        M_NTFSDECOMP, M_WAITOK);
1645
1646                 cn = (ntfs_btocn(roff)) & (~(NTFS_COMPUNIT_CL - 1));
1647                 off = roff - ntfs_cntob(cn);
1648
1649                 while (left) {
1650                         error = ntfs_readattr_plain(ntmp, ip, attrnum,
1651                                                   attrname, ntfs_cntob(cn),
1652                                                   ntfs_cntob(NTFS_COMPUNIT_CL),
1653                                                   cup, &init, NULL);
1654                         if (error)
1655                                 break;
1656
1657                         tocopy = min(left, ntfs_cntob(NTFS_COMPUNIT_CL) - off);
1658
1659                         if (init == ntfs_cntob(NTFS_COMPUNIT_CL)) {
1660                                 if (uio)
1661                                         uiomove(cup + off, tocopy, uio);
1662                                 else
1663                                         memcpy(data, cup + off, tocopy);
1664                         } else if (init == 0) {
1665                                 if (uio) {
1666                                         size_t remains = tocopy;
1667                                         for(; remains; remains--)
1668                                                 uiomove("", 1, uio);
1669                                 }
1670                                 else
1671                                         bzero(data, tocopy);
1672                         } else {
1673                                 error = ntfs_uncompunit(ntmp, uup, cup);
1674                                 if (error)
1675                                         break;
1676                                 if (uio)
1677                                         uiomove(uup + off, tocopy, uio);
1678                                 else
1679                                         memcpy(data, uup + off, tocopy);
1680                         }
1681
1682                         left -= tocopy;
1683                         data = data + tocopy;
1684                         off += tocopy - ntfs_cntob(NTFS_COMPUNIT_CL);
1685                         cn += NTFS_COMPUNIT_CL;
1686                 }
1687
1688                 FREE(uup, M_NTFSDECOMP);
1689                 FREE(cup, M_NTFSDECOMP);
1690         } else
1691                 error = ntfs_readattr_plain(ntmp, ip, attrnum, attrname,
1692                                              roff, rsize, rdata, &init, uio);
1693         ntfs_ntvattrrele(vap);
1694         return (error);
1695 }
1696
1697 #if UNUSED_CODE
1698 int
1699 ntfs_parserun(cn_t *cn, cn_t *cl, u_int8_t *run, u_long len, u_long *off)
1700 {
1701         u_int8_t        sz;
1702         int             i;
1703
1704         if (NULL == run) {
1705                 printf("ntfs_parsetun: run == NULL\n");
1706                 return (EINVAL);
1707         }
1708         sz = run[(*off)++];
1709         if (0 == sz) {
1710                 printf("ntfs_parserun: trying to go out of run\n");
1711                 return (E2BIG);
1712         }
1713         *cl = 0;
1714         if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) {
1715                 printf("ntfs_parserun: " \
1716                        "bad run: length too big: sz: 0x%02x (%ld < %ld + sz)\n",
1717                        sz, len, *off);
1718                 return (EINVAL);
1719         }
1720         for (i = 0; i < (sz & 0xF); i++)
1721                 *cl += (u_int32_t) run[(*off)++] << (i << 3);
1722
1723         sz >>= 4;
1724         if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) {
1725                 printf("ntfs_parserun: " \
1726                        "bad run: length too big: sz: 0x%02x (%ld < %ld + sz)\n",
1727                        sz, len, *off);
1728                 return (EINVAL);
1729         }
1730         for (i = 0; i < (sz & 0xF); i++)
1731                 *cn += (u_int32_t) run[(*off)++] << (i << 3);
1732
1733         return (0);
1734 }
1735 #endif
1736
1737 /*
1738  * Process fixup routine on given buffer.
1739  */
1740 int
1741 ntfs_procfixups(struct ntfsmount *ntmp, u_int32_t magic, caddr_t buf,
1742                 size_t len)
1743 {
1744         struct fixuphdr *fhp = (struct fixuphdr *) buf;
1745         int             i;
1746         u_int16_t       fixup;
1747         u_int16_t      *fxp;
1748         u_int16_t      *cfxp;
1749
1750         if (fhp->fh_magic != magic) {
1751                 printf("ntfs_procfixups: magic doesn't match: %08x != %08x\n",
1752                        fhp->fh_magic, magic);
1753                 return (EINVAL);
1754         }
1755         if ((fhp->fh_fnum - 1) * ntmp->ntm_bps != len) {
1756                 printf("ntfs_procfixups: " \
1757                        "bad fixups number: %d for %ld bytes block\n", 
1758                        fhp->fh_fnum, (long)len);        /* XXX printf kludge */
1759                 return (EINVAL);
1760         }
1761         if (fhp->fh_foff >= ntmp->ntm_spc * ntmp->ntm_mftrecsz * ntmp->ntm_bps) {
1762                 printf("ntfs_procfixups: invalid offset: %x", fhp->fh_foff);
1763                 return (EINVAL);
1764         }
1765         fxp = (u_int16_t *) (buf + fhp->fh_foff);
1766         cfxp = (u_int16_t *) (buf + ntmp->ntm_bps - 2);
1767         fixup = *fxp++;
1768         for (i = 1; i < fhp->fh_fnum; i++, fxp++) {
1769                 if (*cfxp != fixup) {
1770                         printf("ntfs_procfixups: fixup %d doesn't match\n", i);
1771                         return (EINVAL);
1772                 }
1773                 *cfxp = *fxp;
1774                 cfxp = (u_int16_t *)(((caddr_t) cfxp) + ntmp->ntm_bps);
1775         }
1776         return (0);
1777 }
1778
1779 #if UNUSED_CODE
1780 int
1781 ntfs_runtocn(cn_t *cn,  struct ntfsmount *ntmp, u_int8_t *run, u_long len,
1782              cn_t vcn)
1783 {
1784         cn_t            ccn = 0;
1785         cn_t            ccl = 0;
1786         u_long          off = 0;
1787         int             error = 0;
1788
1789 #if NTFS_DEBUG
1790         int             i;
1791         printf("ntfs_runtocn: run: 0x%p, %ld bytes, vcn:%ld\n",
1792                 run, len, (u_long) vcn);
1793         printf("ntfs_runtocn: run: ");
1794         for (i = 0; i < len; i++)
1795                 printf("0x%02x ", run[i]);
1796         printf("\n");
1797 #endif
1798
1799         if (NULL == run) {
1800                 printf("ntfs_runtocn: run == NULL\n");
1801                 return (EINVAL);
1802         }
1803         do {
1804                 if (run[off] == 0) {
1805                         printf("ntfs_runtocn: vcn too big\n");
1806                         return (E2BIG);
1807                 }
1808                 vcn -= ccl;
1809                 error = ntfs_parserun(&ccn, &ccl, run, len, &off);
1810                 if (error) {
1811                         printf("ntfs_runtocn: ntfs_parserun failed\n");
1812                         return (error);
1813                 }
1814         } while (ccl <= vcn);
1815         *cn = ccn + vcn;
1816         return (0);
1817 }
1818 #endif
1819
1820 /*
1821  * this initializes toupper table & dependant variables to be ready for
1822  * later work
1823  */
1824 void
1825 ntfs_toupper_init(void)
1826 {
1827         ntfs_toupper_tab = (wchar *) NULL;
1828         lockinit(&ntfs_toupper_lock, 0, "ntfs_toupper", 0, 0);
1829         ntfs_toupper_usecount = 0;
1830 }
1831
1832 /*
1833  * if the ntfs_toupper_tab[] is filled already, just raise use count;
1834  * otherwise read the data from the filesystem we are currently mounting
1835  */
1836 int
1837 ntfs_toupper_use(struct mount *mp, struct ntfsmount *ntmp)
1838 {
1839         int error = 0;
1840         struct vnode *vp;
1841
1842         /* get exclusive access */
1843         LOCKMGR(&ntfs_toupper_lock, LK_EXCLUSIVE, NULL);
1844         
1845         /* only read the translation data from a file if it hasn't been
1846          * read already */
1847         if (ntfs_toupper_tab)
1848                 goto out;
1849
1850         /*
1851          * Read in Unicode lowercase -> uppercase translation file.
1852          * XXX for now, just the first 256 entries are used anyway,
1853          * so don't bother reading more
1854          */
1855         MALLOC(ntfs_toupper_tab, wchar *, 65536 * sizeof(wchar),
1856                 M_NTFSRDATA, M_WAITOK);
1857
1858         if ((error = VFS_VGET(mp, NTFS_UPCASEINO, &vp)))
1859                 goto out;
1860         error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL,
1861                         0, 65536*sizeof(wchar), (char *) ntfs_toupper_tab, NULL);
1862         vput(vp);
1863
1864     out:
1865         ntfs_toupper_usecount++;
1866         LOCKMGR(&ntfs_toupper_lock, LK_RELEASE, NULL);
1867         return (error);
1868 }
1869
1870 /*
1871  * lower the use count and if it reaches zero, free the memory
1872  * tied by toupper table
1873  */
1874 void
1875 ntfs_toupper_unuse(void)
1876 {
1877         /* get exclusive access */
1878         LOCKMGR(&ntfs_toupper_lock, LK_EXCLUSIVE, NULL);
1879
1880         ntfs_toupper_usecount--;
1881         if (ntfs_toupper_usecount == 0) {
1882                 FREE(ntfs_toupper_tab, M_NTFSRDATA);
1883                 ntfs_toupper_tab = NULL;
1884         }
1885 #ifdef DIAGNOSTIC
1886         else if (ntfs_toupper_usecount < 0) {
1887                 panic("ntfs_toupper_unuse(): use count negative: %d\n",
1888                         ntfs_toupper_usecount);
1889         }
1890 #endif
1891         
1892         /* release the lock */
1893         LOCKMGR(&ntfs_toupper_lock, LK_RELEASE, NULL);
1894
1895
1896 int
1897 ntfs_u28_init(struct ntfsmount *ntmp, wchar *u2w)
1898 {
1899         char ** u28;
1900         int i, j, h, l;
1901
1902         MALLOC(u28, char **, 256 * sizeof(char*), M_TEMP, M_WAITOK | M_ZERO);
1903
1904         for (i=0; i<256; i++) {
1905                 h = (u2w[i] >> 8) & 0xFF;
1906                 l = (u2w[i]) &0xFF;
1907
1908                 if (u28[h] == NULL) {
1909                         MALLOC(u28[h], char *, 256 * sizeof(char), M_TEMP, M_WAITOK);
1910                         for (j=0; j<256; j++)
1911                                 u28[h][j] = '_';
1912                 }
1913
1914                 u28[h][l] = i & 0xFF;
1915         }
1916
1917         ntmp->ntm_u28 = u28;
1918
1919         return (0);
1920 }
1921
1922 int
1923 ntfs_u28_uninit(struct ntfsmount *ntmp)
1924 {
1925         char ** u28;
1926         int i;
1927
1928         if (ntmp->ntm_u28 == NULL)
1929                 return (0);
1930
1931         u28 = ntmp->ntm_u28;
1932
1933         for (i=0; i<256; i++)
1934                 if (u28[i] != NULL)
1935                         FREE(u28[i], M_TEMP);
1936
1937         FREE(u28, M_TEMP);
1938
1939         return (0);
1940 }
1941
1942 int
1943 ntfs_82u_init(struct ntfsmount *ntmp, u_int16_t *u2w)
1944 {
1945         wchar * _82u;
1946         int i;
1947
1948         MALLOC(_82u, wchar *, 256 * sizeof(wchar), M_TEMP, M_WAITOK);
1949
1950         if (u2w == NULL) {
1951                 for (i=0; i<256; i++)
1952                         _82u[i] = i;
1953         } else {
1954                 for (i=0; i<128; i++)
1955                         _82u[i] = i;
1956                 for (i=0; i<128; i++)
1957                         _82u[i+128] = u2w[i];
1958         }
1959
1960         ntmp->ntm_82u = _82u;
1961
1962         return (0);
1963 }
1964
1965 int
1966 ntfs_82u_uninit(struct ntfsmount *ntmp)
1967 {
1968         FREE(ntmp->ntm_82u, M_TEMP);
1969         return (0);
1970 }
1971
1972 /*
1973  * maps the Unicode char to 8bit equivalent
1974  * XXX currently only gets lower 8bit from the Unicode char
1975  * and substitutes a '_' for it if the result would be '\0';
1976  * something better has to be definitely though out
1977  */
1978 char
1979 ntfs_u28(struct ntfsmount *ntmp, wchar wc)
1980 {
1981         char * p;
1982
1983         p = ntmp->ntm_u28[(wc>>8)&0xFF];
1984         if (p == NULL)
1985                 return ('_');
1986         return (p[wc&0xFF]);
1987 }
1988