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