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