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