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