1/*	$NetBSD: ntfs_subr.c,v 1.45 2011/06/30 20:09:41 wiz 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.45 2011/06/30 20:09:41 wiz 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
58int ntfs_debug = NTFS_DEBUG;
59#endif
60
61MALLOC_JUSTDEFINE(M_NTFSNTVATTR, "NTFS vattr",
62    "NTFS file attribute information");
63MALLOC_JUSTDEFINE(M_NTFSRDATA, "NTFS res data", "NTFS resident data");
64MALLOC_JUSTDEFINE(M_NTFSRUN, "NTFS vrun", "NTFS vrun storage");
65MALLOC_JUSTDEFINE(M_NTFSDECOMP, "NTFS decomp", "NTFS decompression temporary");
66
67/* Local struct used in ntfs_ntlookupfile() */
68struct 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
75static int ntfs_ntlookupattr(struct ntfsmount *, const char *, int,
76	int *, char **);
77static int ntfs_findvattr(struct ntfsmount *, struct ntnode *,
78	struct ntvattr **, struct ntvattr **, u_int32_t, const char *,
79	size_t, cn_t);
80static int ntfs_uastricmp(struct ntfsmount *, const wchar *, size_t,
81	const char *, size_t);
82static 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 */
87static 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)])
90static kmutex_t ntfs_toupper_lock;
91static 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 */
101int
102ntfs_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 */
115static int
116ntfs_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 */
160int
161ntfs_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));
264out:
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 */
274int
275ntfs_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
361out:
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 */
370int
371ntfs_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 */
394int
395ntfs_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 */
459void
460ntfs_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 */
504void
505ntfs_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 */
519void
520ntfs_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 */
537void
538ntfs_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 */
556int
557ntfs_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 */
624int
625ntfs_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 */
686static int
687ntfs_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 */
710static int
711ntfs_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 */
736int
737ntfs_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 */
788void
789ntfs_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 */
812static int
813ntfs_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 */
866int
867ntfs_ntlookupfile(
868	      struct ntfsmount * ntmp,
869	      struct vnode * vp,
870	      struct componentname * cnp,
871	      struct vnode ** vpp)
872{
873	struct fnode   *fp = VTOF(vp);
874	struct ntnode  *ip = FTONT(fp);
875	struct ntvattr *vap;	/* Root attribute */
876	cn_t            cn = 0;	/* VCN in current attribute */
877	void *        rdbuf;	/* Buffer to read directory's blocks  */
878	u_int32_t       blsize;
879	u_int32_t       rdsize;	/* Length of data to read from current block */
880	struct attr_indexentry *iep;
881	int             error, res, anamelen, fnamelen;
882	const char     *fname,*aname;
883	u_int32_t       aoff;
884	int attrtype = NTFS_A_DATA;
885	char *attrname = NULL;
886	struct fnode   *nfp;
887	struct vnode   *nvp;
888	enum vtype	f_type;
889	int fullscan = 0;
890	struct ntfs_lookup_ctx *lookup_ctx = NULL, *tctx;
891
892	error = ntfs_ntget(ip);
893	if (error)
894		return (error);
895
896	error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXROOT, "$I30", 0, &vap);
897	if (error || (vap->va_flag & NTFS_AF_INRUN))
898		return (ENOTDIR);
899
900	/*
901	 * Divide file name into: foofilefoofilefoofile[:attrspec]
902	 * Store like this:       fname:fnamelen       [aname:anamelen]
903	 */
904	fname = cnp->cn_nameptr;
905	aname = NULL;
906	anamelen = 0;
907	for (fnamelen = 0; fnamelen < cnp->cn_namelen; fnamelen++)
908		if(fname[fnamelen] == ':') {
909			aname = fname + fnamelen + 1;
910			anamelen = cnp->cn_namelen - fnamelen - 1;
911			dprintf(("ntfs_ntlookupfile: %s (%d), attr: %s (%d)\n",
912				fname, fnamelen, aname, anamelen));
913			break;
914		}
915
916	blsize = vap->va_a_iroot->ir_size;
917	dprintf(("ntfs_ntlookupfile: blksz: %d\n", blsize));
918
919	rdbuf = (void *) malloc(blsize, M_TEMP, M_WAITOK);
920
921    loop:
922	rdsize = vap->va_datalen;
923	dprintf(("ntfs_ntlookupfile: rdsz: %d\n", rdsize));
924
925	error = ntfs_readattr(ntmp, ip, NTFS_A_INDXROOT, "$I30",
926			       0, rdsize, rdbuf, NULL);
927	if (error)
928		goto fail;
929
930	aoff = sizeof(struct attr_indexroot);
931
932	do {
933		iep = (struct attr_indexentry *) ((char *)rdbuf + aoff);
934
935		for (; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (rdsize > aoff);
936			aoff += iep->reclen,
937			iep = (struct attr_indexentry *) ((char *)rdbuf + aoff))
938		{
939			ddprintf(("scan: %d, %d\n",
940				  (u_int32_t) iep->ie_number,
941				  (u_int32_t) iep->ie_fnametype));
942
943			/* check the name - the case-insensitive check
944			 * has to come first, to break from this for loop
945			 * if needed, so we can dive correctly */
946			res = ntfs_uastricmp(ntmp, iep->ie_fname,
947				iep->ie_fnamelen, fname, fnamelen);
948			if (!fullscan) {
949				if (res > 0) break;
950				if (res < 0) continue;
951			}
952
953			if (iep->ie_fnametype == 0 ||
954			    !(ntmp->ntm_flag & NTFS_MFLAG_CASEINS))
955			{
956				res = ntfs_uastrcmp(ntmp, iep->ie_fname,
957					iep->ie_fnamelen, fname, fnamelen);
958				if (res != 0 && !fullscan) continue;
959			}
960
961			/* if we perform full scan, the file does not match
962			 * and this is subnode, dive */
963			if (fullscan && res != 0) {
964			    if (iep->ie_flag & NTFS_IEFLAG_SUBNODE) {
965				tctx = malloc(sizeof(struct ntfs_lookup_ctx),
966					M_TEMP, M_WAITOK);
967				tctx->aoff	= aoff + iep->reclen;
968				tctx->rdsize	= rdsize;
969				tctx->cn	= cn;
970				tctx->prev	= lookup_ctx;
971				lookup_ctx = tctx;
972				break;
973			    } else
974				continue;
975			}
976
977			if (aname) {
978				error = ntfs_ntlookupattr(ntmp,
979					aname, anamelen,
980					&attrtype, &attrname);
981				if (error)
982					goto fail;
983			}
984
985			/* Check if we've found ourselves */
986			if ((iep->ie_number == ip->i_number) &&
987			    (attrtype == fp->f_attrtype) &&
988			    ((!attrname && !fp->f_attrname) ||
989			     (attrname && fp->f_attrname &&
990			      !strcmp(attrname, fp->f_attrname))))
991			{
992				vref(vp);
993				*vpp = vp;
994				error = 0;
995				goto fail;
996			}
997
998			/* free the buffer returned by ntfs_ntlookupattr() */
999			if (attrname) {
1000				free(attrname, M_TEMP);
1001				attrname = NULL;
1002			}
1003
1004			/* vget node, but don't load it */
1005			error = ntfs_vgetex(ntmp->ntm_mountp,
1006				   iep->ie_number, attrtype, attrname,
1007				   LK_EXCLUSIVE, VG_DONTLOADIN | VG_DONTVALIDFN,
1008				   &nvp);
1009			if (error)
1010				goto fail;
1011
1012			nfp = VTOF(nvp);
1013
1014			if (nfp->f_flag & FN_VALID) {
1015				*vpp = nvp;
1016				goto fail;
1017			}
1018
1019			nfp->f_fflag = iep->ie_fflag;
1020			nfp->f_pnumber = iep->ie_fpnumber;
1021			nfp->f_times = iep->ie_ftimes;
1022
1023			if((nfp->f_fflag & NTFS_FFLAG_DIR) &&
1024			   (nfp->f_attrtype == NTFS_A_DATA) &&
1025			   (nfp->f_attrname == NULL))
1026				f_type = VDIR;
1027			else
1028				f_type = VREG;
1029
1030			nvp->v_type = f_type;
1031
1032			if ((nfp->f_attrtype == NTFS_A_DATA) &&
1033			    (nfp->f_attrname == NULL))
1034			{
1035				/* Opening default attribute */
1036				nfp->f_size = iep->ie_fsize;
1037				nfp->f_allocated = iep->ie_fallocated;
1038				nfp->f_flag |= FN_PRELOADED;
1039				uvm_vnp_setsize(nvp, iep->ie_fsize);
1040			} else {
1041				error = ntfs_filesize(ntmp, nfp,
1042					    &nfp->f_size, &nfp->f_allocated);
1043				if (error) {
1044					vput(nvp);
1045					goto fail;
1046				}
1047				uvm_vnp_setsize(nvp, nfp->f_size);
1048			}
1049
1050			nfp->f_flag &= ~FN_VALID;
1051			*vpp = nvp;
1052			goto fail;
1053		}
1054
1055		/* Dive if possible */
1056		if (iep->ie_flag & NTFS_IEFLAG_SUBNODE) {
1057			dprintf(("ntfs_ntlookupfile: diving\n"));
1058
1059			cn = *(cn_t *) ((char *)rdbuf + aoff +
1060					iep->reclen - sizeof(cn_t));
1061			rdsize = blsize;
1062
1063			error = ntfs_readattr(ntmp, ip, NTFS_A_INDX, "$I30",
1064					ntfs_cntob(cn), rdsize, rdbuf, NULL);
1065			if (error)
1066				goto fail;
1067
1068			error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC,
1069						rdbuf, rdsize);
1070			if (error)
1071				goto fail;
1072
1073			aoff = (((struct attr_indexalloc *) rdbuf)->ia_hdrsize +
1074				0x18);
1075		} else if (fullscan && lookup_ctx) {
1076			cn = lookup_ctx->cn;
1077			aoff = lookup_ctx->aoff;
1078			rdsize = lookup_ctx->rdsize;
1079
1080			error = ntfs_readattr(ntmp, ip,
1081				(cn == 0) ? NTFS_A_INDXROOT : NTFS_A_INDX,
1082				"$I30", ntfs_cntob(cn), rdsize, rdbuf, NULL);
1083			if (error)
1084				goto fail;
1085
1086			if (cn != 0) {
1087				error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC,
1088						rdbuf, rdsize);
1089				if (error)
1090					goto fail;
1091			}
1092
1093			tctx = lookup_ctx;
1094			lookup_ctx = lookup_ctx->prev;
1095			free(tctx, M_TEMP);
1096		} else {
1097			dprintf(("ntfs_ntlookupfile: nowhere to dive :-(\n"));
1098			error = ENOENT;
1099			break;
1100		}
1101	} while (1);
1102
1103	/* perform full scan if no entry was found */
1104	if (!fullscan && error == ENOENT) {
1105		fullscan = 1;
1106		cn = 0;		/* need zero, used by lookup_ctx */
1107
1108		ddprintf(("ntfs_ntlookupfile: fullscan performed for: %.*s\n",
1109			(int) fnamelen, fname));
1110		goto loop;
1111	}
1112
1113	dprintf(("finish\n"));
1114
1115fail:
1116	if (attrname)
1117		free(attrname, M_TEMP);
1118	if (lookup_ctx) {
1119		while(lookup_ctx) {
1120			tctx = lookup_ctx;
1121			lookup_ctx = lookup_ctx->prev;
1122			free(tctx, M_TEMP);
1123		}
1124	}
1125	ntfs_ntvattrrele(vap);
1126	ntfs_ntput(ip);
1127	free(rdbuf, M_TEMP);
1128	return (error);
1129}
1130
1131/*
1132 * Check if name type is permitted to show.
1133 */
1134int
1135ntfs_isnamepermitted(
1136		     struct ntfsmount * ntmp,
1137		     struct attr_indexentry * iep)
1138{
1139	if (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES)
1140		return 1;
1141
1142	switch (iep->ie_fnametype) {
1143	case 2:
1144		ddprintf(("ntfs_isnamepermitted: skipped DOS name\n"));
1145		return 0;
1146	case 0: case 1: case 3:
1147		return 1;
1148	default:
1149		printf("ntfs_isnamepermitted: "
1150		    "WARNING! Unknown file name type: %d\n",
1151		    iep->ie_fnametype);
1152		break;
1153	}
1154	return 0;
1155}
1156
1157/*
1158 * Read ntfs dir like stream of attr_indexentry, not like btree of them.
1159 * This is done by scanning $BITMAP:$I30 for busy clusters and reading them.
1160 * Of course $INDEX_ROOT:$I30 is read before. Last read values are stored in
1161 * fnode, so we can skip toward record number num almost immediately.
1162 * Anyway this is rather slow routine. The problem is that we don't know
1163 * how many records are there in $INDEX_ALLOCATION:$I30 block.
1164 */
1165int
1166ntfs_ntreaddir(
1167	       struct ntfsmount * ntmp,
1168	       struct fnode * fp,
1169	       u_int32_t num,
1170	       struct attr_indexentry ** riepp)
1171{
1172	struct ntnode  *ip = FTONT(fp);
1173	struct ntvattr *vap = NULL;	/* IndexRoot attribute */
1174	struct ntvattr *bmvap = NULL;	/* BitMap attribute */
1175	struct ntvattr *iavap = NULL;	/* IndexAllocation attribute */
1176	void *        rdbuf;		/* Buffer to read directory's blocks  */
1177	u_char         *bmp = NULL;	/* Bitmap */
1178	u_int32_t       blsize;		/* Index allocation size (2048) */
1179	u_int32_t       rdsize;		/* Length of data to read */
1180	u_int32_t       attrnum;	/* Current attribute type */
1181	u_int32_t       cpbl = 1;	/* Clusters per directory block */
1182	u_int32_t       blnum;
1183	struct attr_indexentry *iep;
1184	int             error = ENOENT;
1185	u_int32_t       aoff, cnum;
1186
1187	dprintf(("ntfs_ntreaddir: read ino: %llu, num: %d\n",
1188	    (unsigned long long)ip->i_number, num));
1189	error = ntfs_ntget(ip);
1190	if (error)
1191		return (error);
1192
1193	error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXROOT, "$I30", 0, &vap);
1194	if (error)
1195		return (ENOTDIR);
1196
1197	if (fp->f_dirblbuf == NULL) {
1198		fp->f_dirblsz = vap->va_a_iroot->ir_size;
1199		fp->f_dirblbuf = (void *) malloc(
1200		       MAX(vap->va_datalen,fp->f_dirblsz), M_NTFSDIR, M_WAITOK);
1201	}
1202
1203	blsize = fp->f_dirblsz;
1204	rdbuf = fp->f_dirblbuf;
1205
1206	dprintf(("ntfs_ntreaddir: rdbuf: %p, blsize: %d\n", rdbuf, blsize));
1207
1208	if (vap->va_a_iroot->ir_flag & NTFS_IRFLAG_INDXALLOC) {
1209		error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXBITMAP, "$I30",
1210					0, &bmvap);
1211		if (error) {
1212			error = ENOTDIR;
1213			goto fail;
1214		}
1215		bmp = (u_char *) malloc(bmvap->va_datalen, M_TEMP, M_WAITOK);
1216		error = ntfs_readattr(ntmp, ip, NTFS_A_INDXBITMAP, "$I30", 0,
1217				       bmvap->va_datalen, bmp, NULL);
1218		if (error)
1219			goto fail;
1220
1221		error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDX, "$I30",
1222					0, &iavap);
1223		if (error) {
1224			error = ENOTDIR;
1225			goto fail;
1226		}
1227		cpbl = ntfs_btocn(blsize + ntfs_cntob(1) - 1);
1228		dprintf(("ntfs_ntreaddir: indexalloc: %qu, cpbl: %d\n",
1229			 (long long)iavap->va_datalen, cpbl));
1230	} else {
1231		dprintf(("ntfs_ntreadidir: w/o BitMap and IndexAllocation\n"));
1232		iavap = bmvap = NULL;
1233		bmp = NULL;
1234	}
1235
1236	/* Try use previous values */
1237	if ((fp->f_lastdnum < num) && (fp->f_lastdnum != 0)) {
1238		attrnum = fp->f_lastdattr;
1239		aoff = fp->f_lastdoff;
1240		blnum = fp->f_lastdblnum;
1241		cnum = fp->f_lastdnum;
1242	} else {
1243		attrnum = NTFS_A_INDXROOT;
1244		aoff = sizeof(struct attr_indexroot);
1245		blnum = 0;
1246		cnum = 0;
1247	}
1248
1249	do {
1250		dprintf(("ntfs_ntreaddir: scan: 0x%x, %d, %d, %d, %d\n",
1251			 attrnum, (u_int32_t) blnum, cnum, num, aoff));
1252		rdsize = (attrnum == NTFS_A_INDXROOT) ? vap->va_datalen : blsize;
1253		error = ntfs_readattr(ntmp, ip, attrnum, "$I30",
1254				ntfs_cntob(blnum * cpbl), rdsize, rdbuf, NULL);
1255		if (error)
1256			goto fail;
1257
1258		if (attrnum == NTFS_A_INDX) {
1259			error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC,
1260						rdbuf, rdsize);
1261			if (error)
1262				goto fail;
1263		}
1264		if (aoff == 0)
1265			aoff = (attrnum == NTFS_A_INDX) ?
1266				(0x18 + ((struct attr_indexalloc *) rdbuf)->ia_hdrsize) :
1267				sizeof(struct attr_indexroot);
1268
1269		iep = (struct attr_indexentry *) ((char *)rdbuf + aoff);
1270		for (; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (rdsize > aoff);
1271			aoff += iep->reclen,
1272			iep = (struct attr_indexentry *) ((char *)rdbuf + aoff))
1273		{
1274			if (!ntfs_isnamepermitted(ntmp, iep)) continue;
1275
1276			if (cnum >= num) {
1277				fp->f_lastdnum = cnum;
1278				fp->f_lastdoff = aoff;
1279				fp->f_lastdblnum = blnum;
1280				fp->f_lastdattr = attrnum;
1281
1282				*riepp = iep;
1283
1284				error = 0;
1285				goto fail;
1286			}
1287			cnum++;
1288		}
1289
1290		if (iavap) {
1291			if (attrnum == NTFS_A_INDXROOT)
1292				blnum = 0;
1293			else
1294				blnum++;
1295
1296			while (ntfs_cntob(blnum * cpbl) < iavap->va_datalen) {
1297				if (bmp[blnum >> 3] & (1 << (blnum & 3)))
1298					break;
1299				blnum++;
1300			}
1301
1302			attrnum = NTFS_A_INDX;
1303			aoff = 0;
1304			if (ntfs_cntob(blnum * cpbl) >= iavap->va_datalen)
1305				break;
1306			dprintf(("ntfs_ntreaddir: blnum: %d\n", (u_int32_t) blnum));
1307		}
1308	} while (iavap);
1309
1310	*riepp = NULL;
1311	fp->f_lastdnum = 0;
1312
1313fail:
1314	if (vap)
1315		ntfs_ntvattrrele(vap);
1316	if (bmvap)
1317		ntfs_ntvattrrele(bmvap);
1318	if (iavap)
1319		ntfs_ntvattrrele(iavap);
1320	if (bmp)
1321		free(bmp, M_TEMP);
1322	ntfs_ntput(ip);
1323	return (error);
1324}
1325
1326/*
1327 * Convert NTFS times that are in 100 ns units and begins from
1328 * 1601 Jan 1 into unix times.
1329 */
1330struct timespec
1331ntfs_nttimetounix(
1332		  u_int64_t nt)
1333{
1334	struct timespec t;
1335
1336	/* WindowNT times are in 100 ns and from 1601 Jan 1 */
1337	t.tv_nsec = (nt % (1000 * 1000 * 10)) * 100;
1338	t.tv_sec = nt / (1000 * 1000 * 10) -
1339		369LL * 365LL * 24LL * 60LL * 60LL -
1340		89LL * 1LL * 24LL * 60LL * 60LL;
1341	return (t);
1342}
1343
1344/*
1345 * Get file times from NTFS_A_NAME attribute.
1346 */
1347int
1348ntfs_times(
1349	   struct ntfsmount * ntmp,
1350	   struct ntnode * ip,
1351	   ntfs_times_t * tm)
1352{
1353	struct ntvattr *vap;
1354	int             error;
1355
1356	dprintf(("ntfs_times: ino: %llu...\n",
1357	    (unsigned long long)ip->i_number));
1358
1359	error = ntfs_ntget(ip);
1360	if (error)
1361		return (error);
1362
1363	error = ntfs_ntvattrget(ntmp, ip, NTFS_A_NAME, NULL, 0, &vap);
1364	if (error) {
1365		ntfs_ntput(ip);
1366		return (error);
1367	}
1368	*tm = vap->va_a_name->n_times;
1369	ntfs_ntvattrrele(vap);
1370	ntfs_ntput(ip);
1371
1372	return (0);
1373}
1374
1375/*
1376 * Get file sizes from corresponding attribute.
1377 *
1378 * ntnode under fnode should be locked.
1379 */
1380int
1381ntfs_filesize(
1382	      struct ntfsmount * ntmp,
1383	      struct fnode * fp,
1384	      u_int64_t * size,
1385	      u_int64_t * bytes)
1386{
1387	struct ntvattr *vap;
1388	struct ntnode *ip = FTONT(fp);
1389	u_int64_t       sz, bn;
1390	int             error;
1391
1392	dprintf(("ntfs_filesize: ino: %llu\n",
1393	    (unsigned long long)ip->i_number));
1394
1395	error = ntfs_ntvattrget(ntmp, ip,
1396		fp->f_attrtype, fp->f_attrname, 0, &vap);
1397	if (error)
1398		return (error);
1399
1400	bn = vap->va_allocated;
1401	sz = vap->va_datalen;
1402
1403	dprintf(("ntfs_filesize: %d bytes (%d bytes allocated)\n",
1404		(u_int32_t) sz, (u_int32_t) bn));
1405
1406	if (size)
1407		*size = sz;
1408	if (bytes)
1409		*bytes = bn;
1410
1411	ntfs_ntvattrrele(vap);
1412
1413	return (0);
1414}
1415
1416/*
1417 * This is one of write routine.
1418 */
1419int
1420ntfs_writeattr_plain(
1421	struct ntfsmount * ntmp,
1422	struct ntnode * ip,
1423	u_int32_t attrnum,
1424	char *attrname,
1425	off_t roff,
1426	size_t rsize,
1427	void *rdata,
1428	size_t * initp,
1429	struct uio *uio)
1430{
1431	size_t          init;
1432	int             error = 0;
1433	off_t           off = roff, left = rsize, towrite;
1434	void *        data = rdata;
1435	struct ntvattr *vap;
1436	*initp = 0;
1437
1438	while (left) {
1439		error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname,
1440					ntfs_btocn(off), &vap);
1441		if (error)
1442			return (error);
1443		towrite = MIN(left, ntfs_cntob(vap->va_vcnend + 1) - off);
1444		ddprintf(("ntfs_writeattr_plain: o: %qd, s: %qd (%qu - %qu)\n",
1445			 (long long) off, (long long) towrite,
1446			 (long long) vap->va_vcnstart,
1447			 (long long) vap->va_vcnend));
1448		error = ntfs_writentvattr_plain(ntmp, ip, vap,
1449					 off - ntfs_cntob(vap->va_vcnstart),
1450					 towrite, data, &init, uio);
1451		if (error) {
1452			dprintf(("ntfs_writeattr_plain: "
1453			    "ntfs_writentvattr_plain failed: o: %qd, s: %qd\n",
1454			    (long long) off, (long long) towrite));
1455			dprintf(("ntfs_writeattr_plain: attrib: %qu - %qu\n",
1456			       (long long) vap->va_vcnstart,
1457			       (long long) vap->va_vcnend));
1458			ntfs_ntvattrrele(vap);
1459			break;
1460		}
1461		ntfs_ntvattrrele(vap);
1462		left -= towrite;
1463		off += towrite;
1464		data = (char *)data + towrite;
1465		*initp += init;
1466	}
1467
1468	return (error);
1469}
1470
1471/*
1472 * This is one of write routine.
1473 *
1474 * ntnode should be locked.
1475 */
1476int
1477ntfs_writentvattr_plain(
1478	struct ntfsmount * ntmp,
1479	struct ntnode * ip,
1480	struct ntvattr * vap,
1481	off_t roff,
1482	size_t rsize,
1483	void *rdata,
1484	size_t * initp,
1485	struct uio *uio)
1486{
1487	int             error = 0;
1488	off_t           off;
1489	int             cnt;
1490	cn_t            ccn, ccl, cn, left, cl;
1491	void *        data = rdata;
1492	daddr_t		lbn;
1493	struct buf     *bp;
1494	size_t          tocopy;
1495
1496	*initp = 0;
1497
1498	if ((vap->va_flag & NTFS_AF_INRUN) == 0) {
1499		dprintf(("ntfs_writevattr_plain: CAN'T WRITE RES. ATTRIBUTE\n"));
1500		return ENOTTY;
1501	}
1502
1503	ddprintf(("ntfs_writentvattr_plain: data in run: %lu chains\n",
1504		 vap->va_vruncnt));
1505
1506	off = roff;
1507	left = rsize;
1508	ccl = 0;
1509	ccn = 0;
1510	cnt = 0;
1511	for (; left && (cnt < vap->va_vruncnt); cnt++) {
1512		ccn = vap->va_vruncn[cnt];
1513		ccl = vap->va_vruncl[cnt];
1514
1515		ddprintf(("ntfs_writentvattr_plain: "
1516		    "left %qu, cn: 0x%qx, cl: %qu, off: %qd\n",
1517		    (long long) left, (long long) ccn,
1518		    (long long) ccl, (long long) off));
1519
1520		if (ntfs_cntob(ccl) < off) {
1521			off -= ntfs_cntob(ccl);
1522			cnt++;
1523			continue;
1524		}
1525		if (!ccn && ip->i_number != NTFS_BOOTINO)
1526			continue; /* XXX */
1527
1528		ccl -= ntfs_btocn(off);
1529		cn = ccn + ntfs_btocn(off);
1530		off = ntfs_btocnoff(off);
1531
1532		while (left && ccl) {
1533			/*
1534			 * Always read and write single clusters at a time -
1535			 * we need to avoid requesting differently-sized
1536			 * blocks at the same disk offsets to avoid
1537			 * confusing the buffer cache.
1538			 */
1539			tocopy = MIN(left, ntfs_cntob(1) - off);
1540			cl = ntfs_btocl(tocopy + off);
1541			KASSERT(cl == 1 && tocopy <= ntfs_cntob(1));
1542			ddprintf(("ntfs_writentvattr_plain: write: "
1543				"cn: 0x%qx cl: %qu, off: %qd len: %qu, left: %qu\n",
1544				(long long) cn, (long long) cl,
1545				(long long) off, (long long) tocopy,
1546				(long long) left));
1547			if ((off == 0) && (tocopy == ntfs_cntob(cl)))
1548			{
1549				lbn = ntfs_cntobn(cn);
1550				bp = getblk(ntmp->ntm_devvp, lbn,
1551					    ntfs_cntob(cl), 0, 0);
1552				clrbuf(bp);
1553			} else {
1554				error = bread(ntmp->ntm_devvp, ntfs_cntobn(cn),
1555				    ntfs_cntob(cl), NOCRED, B_MODIFY, &bp);
1556				if (error) {
1557					brelse(bp, 0);
1558					return (error);
1559				}
1560			}
1561			if (uio)
1562				uiomove((char *)bp->b_data + off, tocopy, uio);
1563			else
1564				memcpy((char *)bp->b_data + off, data, tocopy);
1565			bawrite(bp);
1566			data = (char *)data + tocopy;
1567			*initp += tocopy;
1568			off = 0;
1569			left -= tocopy;
1570			cn += cl;
1571			ccl -= cl;
1572		}
1573	}
1574
1575	if (left) {
1576		printf("ntfs_writentvattr_plain: POSSIBLE RUN ERROR\n");
1577		error = EINVAL;
1578	}
1579
1580	return (error);
1581}
1582
1583/*
1584 * This is one of read routines.
1585 *
1586 * ntnode should be locked.
1587 */
1588int
1589ntfs_readntvattr_plain(
1590	struct ntfsmount * ntmp,
1591	struct ntnode * ip,
1592	struct ntvattr * vap,
1593	off_t roff,
1594	size_t rsize,
1595	void *rdata,
1596	size_t * initp,
1597	struct uio *uio)
1598{
1599	int             error = 0;
1600	off_t           off;
1601
1602	*initp = 0;
1603	if (vap->va_flag & NTFS_AF_INRUN) {
1604		int             cnt;
1605		cn_t            ccn, ccl, cn, left, cl;
1606		void *        data = rdata;
1607		struct buf     *bp;
1608		size_t          tocopy;
1609
1610		ddprintf(("ntfs_readntvattr_plain: data in run: %lu chains\n",
1611			 vap->va_vruncnt));
1612
1613		off = roff;
1614		left = rsize;
1615		ccl = 0;
1616		ccn = 0;
1617		cnt = 0;
1618		while (left && (cnt < vap->va_vruncnt)) {
1619			ccn = vap->va_vruncn[cnt];
1620			ccl = vap->va_vruncl[cnt];
1621
1622			ddprintf(("ntfs_readntvattr_plain: "
1623				 "left %qu, cn: 0x%qx, cl: %qu, off: %qd\n",
1624				 (long long) left, (long long) ccn,
1625				 (long long) ccl, (long long) off));
1626
1627			if (ntfs_cntob(ccl) < off) {
1628				off -= ntfs_cntob(ccl);
1629				cnt++;
1630				continue;
1631			}
1632			if (ccn || ip->i_number == NTFS_BOOTINO) {
1633				ccl -= ntfs_btocn(off);
1634				cn = ccn + ntfs_btocn(off);
1635				off = ntfs_btocnoff(off);
1636
1637				while (left && ccl) {
1638					/*
1639					 * Always read single clusters at a
1640					 * time - we need to avoid reading
1641					 * differently-sized blocks at the
1642					 * same disk offsets to avoid
1643					 * confusing the buffer cache.
1644					 */
1645					tocopy = MIN(left,
1646					    ntfs_cntob(1) - off);
1647					cl = ntfs_btocl(tocopy + off);
1648					KASSERT(cl == 1 &&
1649					    tocopy <= ntfs_cntob(1));
1650
1651					ddprintf(("ntfs_readntvattr_plain: "
1652						"read: cn: 0x%qx cl: %qu, "
1653						"off: %qd len: %qu, left: %qu\n",
1654						(long long) cn,
1655						(long long) cl,
1656						(long long) off,
1657						(long long) tocopy,
1658						(long long) left));
1659					error = bread(ntmp->ntm_devvp,
1660						      ntfs_cntobn(cn),
1661						      ntfs_cntob(cl),
1662						      NOCRED, 0, &bp);
1663					if (error) {
1664						brelse(bp, 0);
1665						return (error);
1666					}
1667					if (uio) {
1668						uiomove((char *)bp->b_data + off,
1669							tocopy, uio);
1670					} else {
1671						memcpy(data, (char *)bp->b_data + off,
1672							tocopy);
1673					}
1674					brelse(bp, 0);
1675					data = (char *)data + tocopy;
1676					*initp += tocopy;
1677					off = 0;
1678					left -= tocopy;
1679					cn += cl;
1680					ccl -= cl;
1681				}
1682			} else {
1683				tocopy = MIN(left, ntfs_cntob(ccl) - off);
1684				ddprintf(("ntfs_readntvattr_plain: "
1685					"hole: ccn: 0x%qx ccl: %qu, off: %qd, "
1686					" len: %qu, left: %qu\n",
1687					(long long) ccn, (long long) ccl,
1688					(long long) off, (long long) tocopy,
1689					(long long) left));
1690				left -= tocopy;
1691				off = 0;
1692				if (uio) {
1693					char vbuf[] = "";
1694					size_t remains = tocopy;
1695					for(; remains; remains--)
1696						uiomove(vbuf, 1, uio);
1697				} else
1698					memset(data, 0, tocopy);
1699				data = (char *)data + tocopy;
1700			}
1701			cnt++;
1702		}
1703		if (left) {
1704			printf("ntfs_readntvattr_plain: POSSIBLE RUN ERROR\n");
1705			error = E2BIG;
1706		}
1707	} else {
1708		ddprintf(("ntfs_readnvattr_plain: data is in mft record\n"));
1709		if (uio)
1710			uiomove((char *)vap->va_datap + roff, rsize, uio);
1711		else
1712			memcpy(rdata, (char *)vap->va_datap + roff, rsize);
1713		*initp += rsize;
1714	}
1715
1716	return (error);
1717}
1718
1719/*
1720 * This is one of read routines.
1721 */
1722int
1723ntfs_readattr_plain(
1724	struct ntfsmount * ntmp,
1725	struct ntnode * ip,
1726	u_int32_t attrnum,
1727	const char *attrname,
1728	off_t roff,
1729	size_t rsize,
1730	void *rdata,
1731	size_t * initp,
1732	struct uio *uio)
1733{
1734	size_t          init;
1735	int             error = 0;
1736	off_t           off = roff, left = rsize, toread;
1737	void *        data = rdata;
1738	struct ntvattr *vap;
1739	*initp = 0;
1740
1741	while (left) {
1742		error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname,
1743					ntfs_btocn(off), &vap);
1744		if (error)
1745			return (error);
1746		toread = MIN(left, ntfs_cntob(vap->va_vcnend + 1) - off);
1747		ddprintf(("ntfs_readattr_plain: o: %qd, s: %qd (%qu - %qu)\n",
1748			 (long long) off, (long long) toread,
1749			 (long long) vap->va_vcnstart,
1750			 (long long) vap->va_vcnend));
1751		error = ntfs_readntvattr_plain(ntmp, ip, vap,
1752					 off - ntfs_cntob(vap->va_vcnstart),
1753					 toread, data, &init, uio);
1754		if (error) {
1755			printf("ntfs_readattr_plain: "
1756			       "ntfs_readntvattr_plain failed: o: %qd, s: %qd\n",
1757			       (long long) off, (long long) toread);
1758			printf("ntfs_readattr_plain: attrib: %qu - %qu\n",
1759			       (long long) vap->va_vcnstart,
1760			       (long long) vap->va_vcnend);
1761			ntfs_ntvattrrele(vap);
1762			break;
1763		}
1764		ntfs_ntvattrrele(vap);
1765		left -= toread;
1766		off += toread;
1767		data = (char *)data + toread;
1768		*initp += init;
1769	}
1770
1771	return (error);
1772}
1773
1774/*
1775 * This is one of read routines.
1776 */
1777int
1778ntfs_readattr(
1779	struct ntfsmount * ntmp,
1780	struct ntnode * ip,
1781	u_int32_t attrnum,
1782	const char *attrname,
1783	off_t roff,
1784	size_t rsize,
1785	void *rdata,
1786	struct uio *uio)
1787{
1788	int             error = 0;
1789	struct ntvattr *vap;
1790	size_t          init;
1791
1792	ddprintf(("ntfs_readattr: reading %llu: 0x%x, from %qd size %qu"
1793	    " bytes\n", (unsigned long long)ip->i_number, attrnum,
1794	    (long long)roff, (long long)rsize));
1795
1796	error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname, 0, &vap);
1797	if (error)
1798		return (error);
1799
1800	if ((roff > vap->va_datalen) ||
1801	    (roff + rsize > vap->va_datalen)) {
1802		printf("ntfs_readattr: offset too big: %qd (%qd) > %qu\n",
1803			(long long) roff, (long long) (roff + rsize),
1804			(long long) vap->va_datalen);
1805		ntfs_ntvattrrele(vap);
1806		return (E2BIG);
1807	}
1808	if (vap->va_compression && vap->va_compressalg) {
1809		u_int8_t       *cup;
1810		u_int8_t       *uup;
1811		off_t           off = roff, left = rsize, tocopy;
1812		void *        data = rdata;
1813		cn_t            cn;
1814
1815		ddprintf(("ntfs_ntreadattr: compression: %d\n",
1816			 vap->va_compressalg));
1817
1818		cup = malloc(ntfs_cntob(NTFS_COMPUNIT_CL),
1819		       M_NTFSDECOMP, M_WAITOK);
1820		uup = malloc(ntfs_cntob(NTFS_COMPUNIT_CL),
1821		       M_NTFSDECOMP, M_WAITOK);
1822
1823		cn = (ntfs_btocn(roff)) & (~(NTFS_COMPUNIT_CL - 1));
1824		off = roff - ntfs_cntob(cn);
1825
1826		while (left) {
1827			error = ntfs_readattr_plain(ntmp, ip, attrnum,
1828						  attrname, ntfs_cntob(cn),
1829					          ntfs_cntob(NTFS_COMPUNIT_CL),
1830						  cup, &init, NULL);
1831			if (error)
1832				break;
1833
1834			tocopy = MIN(left, ntfs_cntob(NTFS_COMPUNIT_CL) - off);
1835
1836			if (init == ntfs_cntob(NTFS_COMPUNIT_CL)) {
1837				if (uio)
1838					uiomove(cup + off, tocopy, uio);
1839				else
1840					memcpy(data, cup + off, tocopy);
1841			} else if (init == 0) {
1842				if (uio) {
1843					char vbuf[] = "";
1844					size_t remains = tocopy;
1845					for(; remains; remains--)
1846						uiomove(vbuf, 1, uio);
1847				}
1848				else
1849					memset(data, 0, tocopy);
1850			} else {
1851				error = ntfs_uncompunit(ntmp, uup, cup);
1852				if (error)
1853					break;
1854				if (uio)
1855					uiomove(uup + off, tocopy, uio);
1856				else
1857					memcpy(data, uup + off, tocopy);
1858			}
1859
1860			left -= tocopy;
1861			data = (char *)data + tocopy;
1862			off += tocopy - ntfs_cntob(NTFS_COMPUNIT_CL);
1863			cn += NTFS_COMPUNIT_CL;
1864		}
1865
1866		free(uup, M_NTFSDECOMP);
1867		free(cup, M_NTFSDECOMP);
1868	} else
1869		error = ntfs_readattr_plain(ntmp, ip, attrnum, attrname,
1870					     roff, rsize, rdata, &init, uio);
1871	ntfs_ntvattrrele(vap);
1872	return (error);
1873}
1874
1875#if UNUSED_CODE
1876int
1877ntfs_parserun(
1878	      cn_t * cn,
1879	      cn_t * cl,
1880	      u_int8_t * run,
1881	      u_long len,
1882	      u_long *off)
1883{
1884	u_int8_t        sz;
1885	int             i;
1886
1887	if (NULL == run) {
1888		printf("ntfs_parsetun: run == NULL\n");
1889		return (EINVAL);
1890	}
1891	sz = run[(*off)++];
1892	if (0 == sz) {
1893		printf("ntfs_parserun: trying to go out of run\n");
1894		return (E2BIG);
1895	}
1896	*cl = 0;
1897	if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) {
1898		printf("ntfs_parserun: "
1899		       "bad run: length too big: sz: 0x%02x (%ld < %ld + sz)\n",
1900		       sz, len, *off);
1901		return (EINVAL);
1902	}
1903	for (i = 0; i < (sz & 0xF); i++)
1904		*cl += (u_int32_t) run[(*off)++] << (i << 3);
1905
1906	sz >>= 4;
1907	if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) {
1908		printf("ntfs_parserun: "
1909		       "bad run: length too big: sz: 0x%02x (%ld < %ld + sz)\n",
1910		       sz, len, *off);
1911		return (EINVAL);
1912	}
1913	for (i = 0; i < (sz & 0xF); i++)
1914		*cn += (u_int32_t) run[(*off)++] << (i << 3);
1915
1916	return (0);
1917}
1918#endif
1919
1920/*
1921 * Process fixup routine on given buffer.
1922 */
1923int
1924ntfs_procfixups(
1925		struct ntfsmount * ntmp,
1926		u_int32_t magic,
1927		void *xbufv,
1928		size_t len)
1929{
1930	char *xbuf = xbufv;
1931	struct fixuphdr *fhp = (struct fixuphdr *) xbuf;
1932	int             i;
1933	u_int16_t       fixup;
1934	u_int16_t      *fxp;
1935	u_int16_t      *cfxp;
1936
1937	if (fhp->fh_magic != magic) {
1938		printf("ntfs_procfixups: magic doesn't match: %08x != %08x\n",
1939		       fhp->fh_magic, magic);
1940		return (EINVAL);
1941	}
1942	if ((fhp->fh_fnum - 1) * ntmp->ntm_bps != len) {
1943		printf("ntfs_procfixups: "
1944		       "bad fixups number: %d for %ld bytes block\n",
1945		       fhp->fh_fnum, (long)len);	/* XXX printf kludge */
1946		return (EINVAL);
1947	}
1948	if (fhp->fh_foff >= ntmp->ntm_spc * ntmp->ntm_mftrecsz * ntmp->ntm_bps) {
1949		printf("ntfs_procfixups: invalid offset: %x", fhp->fh_foff);
1950		return (EINVAL);
1951	}
1952	fxp = (u_int16_t *) (xbuf + fhp->fh_foff);
1953	cfxp = (u_int16_t *) (xbuf + ntmp->ntm_bps - 2);
1954	fixup = *fxp++;
1955	for (i = 1; i < fhp->fh_fnum; i++, fxp++) {
1956		if (*cfxp != fixup) {
1957			printf("ntfs_procfixups: fixup %d doesn't match\n", i);
1958			return (EINVAL);
1959		}
1960		*cfxp = *fxp;
1961		cfxp = (u_int16_t *)((char *)cfxp + ntmp->ntm_bps);
1962	}
1963	return (0);
1964}
1965
1966#if UNUSED_CODE
1967int
1968ntfs_runtocn(
1969	     cn_t * cn,
1970	     struct ntfsmount * ntmp,
1971	     u_int8_t * run,
1972	     u_long len,
1973	     cn_t vcn)
1974{
1975	cn_t            ccn = 0;
1976	cn_t            ccl = 0;
1977	u_long          off = 0;
1978	int             error = 0;
1979
1980#ifdef NTFS_DEBUG
1981	int             i;
1982	printf("ntfs_runtocn: run: %p, %ld bytes, vcn:%ld\n",
1983		run, len, (u_long) vcn);
1984	printf("ntfs_runtocn: run: ");
1985	for (i = 0; i < len; i++)
1986		printf("0x%02x ", run[i]);
1987	printf("\n");
1988#endif
1989
1990	if (NULL == run) {
1991		printf("ntfs_runtocn: run == NULL\n");
1992		return (EINVAL);
1993	}
1994	do {
1995		if (run[off] == 0) {
1996			printf("ntfs_runtocn: vcn too big\n");
1997			return (E2BIG);
1998		}
1999		vcn -= ccl;
2000		error = ntfs_parserun(&ccn, &ccl, run, len, &off);
2001		if (error) {
2002			printf("ntfs_runtocn: ntfs_parserun failed\n");
2003			return (error);
2004		}
2005	} while (ccl <= vcn);
2006	*cn = ccn + vcn;
2007	return (0);
2008}
2009#endif
2010
2011/*
2012 * this initializes toupper table & dependent variables to be ready for
2013 * later work
2014 */
2015void
2016ntfs_toupper_init(void)
2017{
2018	ntfs_toupper_tab = NULL;
2019	mutex_init(&ntfs_toupper_lock, MUTEX_DEFAULT, IPL_NONE);
2020	ntfs_toupper_usecount = 0;
2021}
2022
2023/*
2024 * if the ntfs_toupper_tab[] is filled already, just raise use count;
2025 * otherwise read the data from the filesystem we are currently mounting
2026 */
2027int
2028ntfs_toupper_use(struct mount *mp, struct ntfsmount *ntmp)
2029{
2030	int error = 0;
2031	struct vnode *vp;
2032
2033	/* get exclusive access */
2034	mutex_enter(&ntfs_toupper_lock);
2035
2036	/* only read the translation data from a file if it hasn't been
2037	 * read already */
2038	if (ntfs_toupper_tab)
2039		goto out;
2040
2041	/*
2042	 * Read in Unicode lowercase -> uppercase translation file.
2043	 * XXX for now, just the first 256 entries are used anyway,
2044	 * so don't bother reading more
2045	 */
2046	ntfs_toupper_tab = malloc(256 * 256 * sizeof(wchar),
2047		M_NTFSRDATA, M_WAITOK);
2048
2049	if ((error = VFS_VGET(mp, NTFS_UPCASEINO, &vp)))
2050		goto out;
2051	error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL,
2052			0, 256*256*sizeof(wchar), (char *) ntfs_toupper_tab,
2053			NULL);
2054	vput(vp);
2055
2056    out:
2057	ntfs_toupper_usecount++;
2058	mutex_exit(&ntfs_toupper_lock);
2059	return (error);
2060}
2061
2062/*
2063 * lower the use count and if it reaches zero, free the memory
2064 * tied by toupper table
2065 */
2066void
2067ntfs_toupper_unuse(void)
2068{
2069	/* get exclusive access */
2070	mutex_enter(&ntfs_toupper_lock);
2071
2072	ntfs_toupper_usecount--;
2073	if (ntfs_toupper_usecount == 0) {
2074		free(ntfs_toupper_tab, M_NTFSRDATA);
2075		ntfs_toupper_tab = NULL;
2076	}
2077#ifdef DIAGNOSTIC
2078	else if (ntfs_toupper_usecount < 0) {
2079		panic("ntfs_toupper_unuse(): use count negative: %d",
2080			ntfs_toupper_usecount);
2081	}
2082#endif
2083
2084	/* release the lock */
2085	mutex_exit(&ntfs_toupper_lock);
2086}
2087