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