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