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