ntfs_subr.c revision 230197
159191Skris/*	$NetBSD: ntfs_subr.c,v 1.23 1999/10/31 19:45:26 jdolecek Exp $	*/
259191Skris
359191Skris/*-
459191Skris * Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org)
559191Skris * All rights reserved.
659191Skris *
759191Skris * Redistribution and use in source and binary forms, with or without
859191Skris * modification, are permitted provided that the following conditions
959191Skris * are met:
1059191Skris * 1. Redistributions of source code must retain the above copyright
1159191Skris *    notice, this list of conditions and the following disclaimer.
1259191Skris * 2. Redistributions in binary form must reproduce the above copyright
1368651Skris *    notice, this list of conditions and the following disclaimer in the
1468651Skris *    documentation and/or other materials provided with the distribution.
1559191Skris *
1659191Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1759191Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1859191Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1959191Skris * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2059191Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2168651Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2259191Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2359191Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2468651Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2559191Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2668651Skris * SUCH DAMAGE.
2768651Skris *
2868651Skris * $FreeBSD: stable/9/sys/fs/ntfs/ntfs_subr.c 230197 2012-01-16 05:22:18Z kevlo $
2968651Skris */
3059191Skris
3159191Skris#include <sys/param.h>
3259191Skris#include <sys/types.h>
3359191Skris#include <sys/systm.h>
3459191Skris#include <sys/namei.h>
3568651Skris#include <sys/kernel.h>
3659191Skris#include <sys/vnode.h>
3759191Skris#include <sys/mount.h>
3859191Skris#include <sys/bio.h>
3959191Skris#include <sys/buf.h>
4059191Skris#include <sys/file.h>
4159191Skris#include <sys/malloc.h>
4259191Skris#include <sys/lock.h>
4359191Skris#include <sys/iconv.h>
4459191Skris
4559191Skris/* #define NTFS_DEBUG 1 */
4659191Skris#include <fs/ntfs/ntfs.h>
4759191Skris#include <fs/ntfs/ntfsmount.h>
4859191Skris#include <fs/ntfs/ntfs_inode.h>
4959191Skris#include <fs/ntfs/ntfs_vfsops.h>
5059191Skris#include <fs/ntfs/ntfs_subr.h>
5159191Skris#include <fs/ntfs/ntfs_compr.h>
5259191Skris#include <fs/ntfs/ntfs_ihash.h>
5359191Skris
5459191SkrisMALLOC_DEFINE(M_NTFSNTVATTR, "ntfs_vattr", "NTFS file attribute information");
5559191SkrisMALLOC_DEFINE(M_NTFSRDATA, "ntfsd_resdata", "NTFS resident data");
5659191SkrisMALLOC_DEFINE(M_NTFSRUN, "ntfs_vrun", "NTFS vrun storage");
5759191SkrisMALLOC_DEFINE(M_NTFSDECOMP, "ntfs_decomp", "NTFS decompression temporary");
5859191Skris
5959191Skrisstatic int ntfs_ntlookupattr(struct ntfsmount *, const char *, int, int *, char **);
6059191Skrisstatic int ntfs_findvattr(struct ntfsmount *, struct ntnode *, struct ntvattr **, struct ntvattr **, u_int32_t, const char *, size_t, cn_t);
6159191Skrisstatic int ntfs_uastricmp(struct ntfsmount *, const wchar *, size_t, const char *, size_t);
6259191Skrisstatic int ntfs_uastrcmp(struct ntfsmount *, const wchar *, size_t, const char *, size_t);
6359191Skris
6459191Skris/* table for mapping Unicode chars into uppercase; it's filled upon first
6559191Skris * ntfs mount, freed upon last ntfs umount */
6659191Skrisstatic wchar *ntfs_toupper_tab;
6759191Skris#define NTFS_TOUPPER(ch)	(ntfs_toupper_tab[(ch)])
6859191Skrisstatic struct lock ntfs_toupper_lock;
6959191Skrisstatic signed int ntfs_toupper_usecount;
7059191Skris
7159191Skrisstruct iconv_functions *ntfs_iconv = NULL;
7259191Skris
7359191Skris/* support macro for ntfs_ntvattrget() */
7459191Skris#define NTFS_AALPCMP(aalp,type,name,namelen) (				\
7559191Skris  (aalp->al_type == type) && (aalp->al_namelen == namelen) &&		\
7659191Skris  !NTFS_UASTRCMP(aalp->al_name,aalp->al_namelen,name,namelen) )
7759191Skris
7859191Skris/*
7959191Skris *
8059191Skris */
8159191Skrisint
8259191Skrisntfs_ntvattrrele(vap)
8359191Skris	struct ntvattr * vap;
8459191Skris{
8559191Skris	dprintf(("ntfs_ntvattrrele: ino: %d, type: 0x%x\n",
8659191Skris		 vap->va_ip->i_number, vap->va_type));
8759191Skris
8859191Skris	ntfs_ntrele(vap->va_ip);
8959191Skris
9059191Skris	return (0);
9159191Skris}
9259191Skris
9359191Skris/*
9459191Skris * find the attribute in the ntnode
9559191Skris */
9659191Skrisstatic int
9759191Skrisntfs_findvattr(ntmp, ip, lvapp, vapp, type, name, namelen, vcn)
9859191Skris	struct ntfsmount *ntmp;
9959191Skris	struct ntnode *ip;
10059191Skris	struct ntvattr **lvapp, **vapp;
10159191Skris	u_int32_t type;
10259191Skris	const char *name;
10359191Skris	size_t namelen;
10459191Skris	cn_t vcn;
10559191Skris{
10659191Skris	int error;
10759191Skris	struct ntvattr *vap;
10859191Skris
10959191Skris	if((ip->i_flag & IN_LOADED) == 0) {
11059191Skris		dprintf(("ntfs_findvattr: node not loaded, ino: %d\n",
11159191Skris		       ip->i_number));
11259191Skris		error = ntfs_loadntnode(ntmp,ip);
11359191Skris		if (error) {
11459191Skris			printf("ntfs_findvattr: FAILED TO LOAD INO: %d\n",
11559191Skris			       ip->i_number);
11659191Skris			return (error);
11759191Skris		}
11859191Skris	}
11959191Skris
12059191Skris	*lvapp = NULL;
12159191Skris	*vapp = NULL;
12259191Skris	LIST_FOREACH(vap, &ip->i_valist, va_list) {
12359191Skris		ddprintf(("ntfs_findvattr: type: 0x%x, vcn: %d - %d\n", \
12459191Skris			  vap->va_type, (u_int32_t) vap->va_vcnstart, \
12559191Skris			  (u_int32_t) vap->va_vcnend));
12659191Skris		if ((vap->va_type == type) &&
12759191Skris		    (vap->va_vcnstart <= vcn) && (vap->va_vcnend >= vcn) &&
12859191Skris		    (vap->va_namelen == namelen) &&
12959191Skris		    (strncmp(name, vap->va_name, namelen) == 0)) {
13059191Skris			*vapp = vap;
13159191Skris			ntfs_ntref(vap->va_ip);
13259191Skris			return (0);
13368651Skris		}
13468651Skris		if (vap->va_type == NTFS_A_ATTRLIST)
13568651Skris			*lvapp = vap;
13668651Skris	}
13768651Skris
13868651Skris	return (-1);
13959191Skris}
14068651Skris
14159191Skris/*
14259191Skris * Search attribute specifed in ntnode (load ntnode if nessecary).
14359191Skris * If not found but ATTR_A_ATTRLIST present, read it in and search throught.
14459191Skris * VOP_VGET node needed, and lookup througth it's ntnode (load if nessesary).
14559191Skris *
14659191Skris * ntnode should be locked
14759191Skris */
14859191Skrisint
14959191Skrisntfs_ntvattrget(
15059191Skris		struct ntfsmount * ntmp,
15159191Skris		struct ntnode * ip,
15259191Skris		u_int32_t type,
15359191Skris		const char *name,
15459191Skris		cn_t vcn,
15559191Skris		struct ntvattr ** vapp)
15659191Skris{
15759191Skris	struct ntvattr *lvap = NULL;
15859191Skris	struct attr_attrlist *aalp;
15959191Skris	struct attr_attrlist *nextaalp;
16059191Skris	struct vnode   *newvp;
16159191Skris	struct ntnode  *newip;
16259191Skris	caddr_t         alpool;
16359191Skris	size_t		namelen, len;
16459191Skris	int             error;
16559191Skris
16659191Skris	*vapp = NULL;
16759191Skris
16859191Skris	if (name) {
16959191Skris		dprintf(("ntfs_ntvattrget: " \
17059191Skris			 "ino: %d, type: 0x%x, name: %s, vcn: %d\n", \
17159191Skris			 ip->i_number, type, name, (u_int32_t) vcn));
17259191Skris		namelen = strlen(name);
17359191Skris	} else {
17459191Skris		dprintf(("ntfs_ntvattrget: " \
17559191Skris			 "ino: %d, type: 0x%x, vcn: %d\n", \
17659191Skris			 ip->i_number, type, (u_int32_t) vcn));
17759191Skris		name = "";
17859191Skris		namelen = 0;
17959191Skris	}
18059191Skris
18159191Skris	error = ntfs_findvattr(ntmp, ip, &lvap, vapp, type, name, namelen, vcn);
18259191Skris	if (error >= 0)
18359191Skris		return (error);
18459191Skris
18559191Skris	if (!lvap) {
18668651Skris		dprintf(("ntfs_ntvattrget: UNEXISTED ATTRIBUTE: " \
18768651Skris		       "ino: %d, type: 0x%x, name: %s, vcn: %d\n", \
18868651Skris		       ip->i_number, type, name, (u_int32_t) vcn));
18968651Skris		return (ENOENT);
19068651Skris	}
19168651Skris	/* Scan $ATTRIBUTE_LIST for requested attribute */
19268651Skris	len = lvap->va_datalen;
19368651Skris	alpool = malloc(len, M_TEMP, M_WAITOK);
19468651Skris	error = ntfs_readntvattr_plain(ntmp, ip, lvap, 0, len, alpool, &len,
19568651Skris			NULL);
19668651Skris	if (error)
19768651Skris		goto out;
19868651Skris
19968651Skris	aalp = (struct attr_attrlist *) alpool;
20068651Skris	nextaalp = NULL;
20168651Skris
20268651Skris	for(; len > 0; aalp = nextaalp) {
20368651Skris		dprintf(("ntfs_ntvattrget: " \
20468651Skris			 "attrlist: ino: %d, attr: 0x%x, vcn: %d\n", \
20568651Skris			 aalp->al_inumber, aalp->al_type, \
20668651Skris			 (u_int32_t) aalp->al_vcnstart));
20768651Skris
20868651Skris		if (len > aalp->reclen) {
20968651Skris			nextaalp = NTFS_NEXTREC(aalp, struct attr_attrlist *);
21068651Skris		} else {
21168651Skris			nextaalp = NULL;
21268651Skris		}
21368651Skris		len -= aalp->reclen;
21468651Skris
21568651Skris		if (!NTFS_AALPCMP(aalp, type, name, namelen) ||
21668651Skris		    (nextaalp && (nextaalp->al_vcnstart <= vcn) &&
21768651Skris		     NTFS_AALPCMP(nextaalp, type, name, namelen)))
21868651Skris			continue;
21968651Skris
22068651Skris		dprintf(("ntfs_ntvattrget: attribute in ino: %d\n",
22168651Skris				 aalp->al_inumber));
22268651Skris
22368651Skris		/* this is not a main record, so we can't use just plain
22468651Skris		   vget() */
22568651Skris		error = ntfs_vgetex(ntmp->ntm_mountp, aalp->al_inumber,
22668651Skris				NTFS_A_DATA, NULL, LK_EXCLUSIVE,
22768651Skris				VG_EXT, curthread, &newvp);
22868651Skris		if (error) {
22968651Skris			printf("ntfs_ntvattrget: CAN'T VGET INO: %d\n",
23068651Skris			       aalp->al_inumber);
23168651Skris			goto out;
23268651Skris		}
23368651Skris		newip = VTONT(newvp);
23459191Skris		/* XXX have to lock ntnode */
23559191Skris		error = ntfs_findvattr(ntmp, newip, &lvap, vapp,
23668651Skris				type, name, namelen, vcn);
23768651Skris		vput(newvp);
23859191Skris		if (error == 0)
23968651Skris			goto out;
24068651Skris		printf("ntfs_ntvattrget: ATTRLIST ERROR.\n");
24168651Skris		break;
24268651Skris	}
24359191Skris	error = ENOENT;
24459191Skris
24559191Skris	dprintf(("ntfs_ntvattrget: UNEXISTED ATTRIBUTE: " \
24659191Skris	       "ino: %d, type: 0x%x, name: %.*s, vcn: %d\n", \
24759191Skris	       ip->i_number, type, (int) namelen, name, (u_int32_t) vcn));
24859191Skrisout:
24959191Skris	free(alpool, M_TEMP);
25059191Skris	return (error);
25159191Skris}
25259191Skris
25359191Skris/*
25459191Skris * Read ntnode from disk, make ntvattr list.
25559191Skris *
25659191Skris * ntnode should be locked
25759191Skris */
25859191Skrisint
25959191Skrisntfs_loadntnode(
26059191Skris	      struct ntfsmount * ntmp,
26159191Skris	      struct ntnode * ip)
26259191Skris{
26359191Skris	struct filerec  *mfrp;
26459191Skris	daddr_t         bn;
26559191Skris	int		error,off;
26659191Skris	struct attr    *ap;
26759191Skris	struct ntvattr *nvap;
26859191Skris
26959191Skris	dprintf(("ntfs_loadntnode: loading ino: %d\n",ip->i_number));
27059191Skris
27159191Skris	mfrp = malloc(ntfs_bntob(ntmp->ntm_bpmftrec),
27259191Skris	       M_TEMP, M_WAITOK);
27359191Skris
27459191Skris	if (ip->i_number < NTFS_SYSNODESNUM) {
27559191Skris		struct buf     *bp;
27659191Skris
27759191Skris		dprintf(("ntfs_loadntnode: read system node\n"));
27859191Skris
27959191Skris		bn = ntfs_cntobn(ntmp->ntm_mftcn) +
28059191Skris			ntmp->ntm_bpmftrec * ip->i_number;
28159191Skris		bn *= ntmp->ntm_multiplier;
28259191Skris
28359191Skris		error = bread(ntmp->ntm_devvp,
28459191Skris			      bn, ntfs_bntob(ntmp->ntm_bpmftrec),
28559191Skris			      NOCRED, &bp);
28659191Skris		if (error) {
28759191Skris			printf("ntfs_loadntnode: BREAD FAILED\n");
28859191Skris			brelse(bp);
28959191Skris			goto out;
29059191Skris		}
29159191Skris		memcpy(mfrp, bp->b_data, ntfs_bntob(ntmp->ntm_bpmftrec));
29268651Skris		bqrelse(bp);
29368651Skris	} else {
29468651Skris		struct vnode   *vp;
29568651Skris
29668651Skris		vp = ntmp->ntm_sysvn[NTFS_MFTINO];
29768651Skris		error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL,
29868651Skris			       ip->i_number * ntfs_bntob(ntmp->ntm_bpmftrec),
29959191Skris			       ntfs_bntob(ntmp->ntm_bpmftrec), mfrp, NULL);
30059191Skris		if (error) {
30159191Skris			printf("ntfs_loadntnode: ntfs_readattr failed\n");
30259191Skris			goto out;
30359191Skris		}
30459191Skris	}
30559191Skris
30659191Skris	/* Check if magic and fixups are correct */
30759191Skris	error = ntfs_procfixups(ntmp, NTFS_FILEMAGIC, (caddr_t)mfrp,
30859191Skris				ntfs_bntob(ntmp->ntm_bpmftrec));
30968651Skris	if (error) {
31068651Skris		printf("ntfs_loadntnode: BAD MFT RECORD %d\n",
31168651Skris		       (u_int32_t) ip->i_number);
31268651Skris		goto out;
31368651Skris	}
31459191Skris
31559191Skris	dprintf(("ntfs_loadntnode: load attrs for ino: %d\n",ip->i_number));
31668651Skris	off = mfrp->fr_attroff;
31768651Skris	ap = (struct attr *) ((caddr_t)mfrp + off);
31868651Skris
31968651Skris	LIST_INIT(&ip->i_valist);
32068651Skris
32168651Skris	while (ap->a_hdr.a_type != -1) {
32268651Skris		error = ntfs_attrtontvattr(ntmp, &nvap, ap);
32368651Skris		if (error)
32459191Skris			break;
32559191Skris		nvap->va_ip = ip;
32659191Skris
32759191Skris		LIST_INSERT_HEAD(&ip->i_valist, nvap, va_list);
32859191Skris
32959191Skris		off += ap->a_hdr.reclen;
33059191Skris		ap = (struct attr *) ((caddr_t)mfrp + off);
33159191Skris	}
33259191Skris	if (error) {
33359191Skris		printf("ntfs_loadntnode: failed to load attr ino: %d\n",
33459191Skris		       ip->i_number);
33559191Skris		goto out;
33659191Skris	}
33759191Skris
33859191Skris	ip->i_mainrec = mfrp->fr_mainrec;
33959191Skris	ip->i_nlink = mfrp->fr_nlink;
34059191Skris	ip->i_frflag = mfrp->fr_flags;
34159191Skris
34259191Skris	ip->i_flag |= IN_LOADED;
34359191Skris
34459191Skrisout:
34559191Skris	free(mfrp, M_TEMP);
34659191Skris	return (error);
34759191Skris}
34859191Skris
34959191Skris/*
35059191Skris * Routine locks ntnode and increase usecount, just opposite of
35159191Skris * ntfs_ntput().
35259191Skris */
35359191Skrisint
35459191Skrisntfs_ntget(ip)
35559191Skris	struct ntnode *ip;
35659191Skris{
35759191Skris	dprintf(("ntfs_ntget: get ntnode %d: %p, usecount: %d\n",
35859191Skris		ip->i_number, ip, ip->i_usecount));
35959191Skris
36059191Skris	mtx_lock(&ip->i_interlock);
36159191Skris	ip->i_usecount++;
36259191Skris	lockmgr(&ip->i_lock, LK_EXCLUSIVE | LK_INTERLOCK, &ip->i_interlock);
36368651Skris
36468651Skris	return 0;
36568651Skris}
36668651Skris
36768651Skris/*
36868651Skris * Routine search ntnode in hash, if found: lock, inc usecount and return.
36968651Skris * If not in hash allocate structure for ntnode, prefill it, lock,
37068651Skris * inc count and return.
37168651Skris *
37268651Skris * ntnode returned locked
37368651Skris */
37468651Skrisint
37568651Skrisntfs_ntlookup(
37668651Skris	   struct ntfsmount * ntmp,
37768651Skris	   ino_t ino,
37868651Skris	   struct ntnode ** ipp)
37968651Skris{
38068651Skris	struct ntnode  *ip;
38168651Skris
38268651Skris	dprintf(("ntfs_ntlookup: looking for ntnode %d\n", ino));
38368651Skris
38468651Skris	do {
38568651Skris		ip = ntfs_nthashlookup(ntmp->ntm_devvp->v_rdev, ino);
38668651Skris		if (ip != NULL) {
38768651Skris			ntfs_ntget(ip);
38868651Skris			dprintf(("ntfs_ntlookup: ntnode %d: %p, usecount: %d\n",
38968651Skris				ino, ip, ip->i_usecount));
39068651Skris			*ipp = ip;
39168651Skris			return (0);
39268651Skris		}
39368651Skris	} while (lockmgr(&ntfs_hashlock, LK_EXCLUSIVE | LK_SLEEPFAIL, NULL));
39468651Skris
39568651Skris	ip = malloc(sizeof(struct ntnode), M_NTFSNTNODE,
39668651Skris		M_WAITOK | M_ZERO);
39768651Skris	ddprintf(("ntfs_ntlookup: allocating ntnode: %d: %p\n", ino, ip));
39868651Skris
39968651Skris	/* Generic initialization */
40068651Skris	ip->i_devvp = ntmp->ntm_devvp;
40168651Skris	ip->i_dev = ntmp->ntm_devvp->v_rdev;
40268651Skris	ip->i_number = ino;
40368651Skris	ip->i_mp = ntmp;
40468651Skris
40568651Skris	LIST_INIT(&ip->i_fnlist);
40668651Skris	VREF(ip->i_devvp);
40768651Skris
40868651Skris	/* init lock and lock the newborn ntnode */
40968651Skris	lockinit(&ip->i_lock, PINOD, "ntnode", 0, 0);
41068651Skris	mtx_init(&ip->i_interlock, "ntnode interlock", NULL, MTX_DEF);
41168651Skris	ntfs_ntget(ip);
41268651Skris
41368651Skris	ntfs_nthashins(ip);
41468651Skris
41568651Skris	lockmgr(&ntfs_hashlock, LK_RELEASE, NULL);
41668651Skris
41768651Skris	*ipp = ip;
41868651Skris
41968651Skris	dprintf(("ntfs_ntlookup: ntnode %d: %p, usecount: %d\n",
42068651Skris		ino, ip, ip->i_usecount));
42168651Skris
42268651Skris	return (0);
42368651Skris}
42468651Skris
42568651Skris/*
42668651Skris * Decrement usecount of ntnode and unlock it, if usecount reach zero,
42768651Skris * deallocate ntnode.
42868651Skris *
42968651Skris * ntnode should be locked on entry, and unlocked on return.
43068651Skris */
43168651Skrisvoid
43268651Skrisntfs_ntput(ip)
433	struct ntnode *ip;
434{
435	struct ntvattr *vap;
436
437	dprintf(("ntfs_ntput: rele ntnode %d: %p, usecount: %d\n",
438		ip->i_number, ip, ip->i_usecount));
439
440	mtx_lock(&ip->i_interlock);
441	ip->i_usecount--;
442
443#ifdef DIAGNOSTIC
444	if (ip->i_usecount < 0) {
445		panic("ntfs_ntput: ino: %d usecount: %d \n",
446		      ip->i_number,ip->i_usecount);
447	}
448#endif
449
450	if (ip->i_usecount > 0) {
451		lockmgr(&ip->i_lock, LK_RELEASE|LK_INTERLOCK, &ip->i_interlock);
452		return;
453	}
454
455	dprintf(("ntfs_ntput: deallocating ntnode: %d\n", ip->i_number));
456
457	if (LIST_FIRST(&ip->i_fnlist))
458		panic("ntfs_ntput: ntnode has fnodes\n");
459
460	ntfs_nthashrem(ip);
461
462	while ((vap = LIST_FIRST(&ip->i_valist)) != NULL) {
463		LIST_REMOVE(vap,va_list);
464		ntfs_freentvattr(vap);
465	}
466	lockmgr(&ip->i_lock, LK_RELEASE | LK_INTERLOCK, &ip->i_interlock);
467	mtx_destroy(&ip->i_interlock);
468	lockdestroy(&ip->i_lock);
469	vrele(ip->i_devvp);
470	free(ip, M_NTFSNTNODE);
471}
472
473/*
474 * increment usecount of ntnode
475 */
476void
477ntfs_ntref(ip)
478	struct ntnode *ip;
479{
480	mtx_lock(&ip->i_interlock);
481	ip->i_usecount++;
482	mtx_unlock(&ip->i_interlock);
483
484	dprintf(("ntfs_ntref: ino %d, usecount: %d\n",
485		ip->i_number, ip->i_usecount));
486
487}
488
489/*
490 * Decrement usecount of ntnode.
491 */
492void
493ntfs_ntrele(ip)
494	struct ntnode *ip;
495{
496	dprintf(("ntfs_ntrele: rele ntnode %d: %p, usecount: %d\n",
497		ip->i_number, ip, ip->i_usecount));
498
499	mtx_lock(&ip->i_interlock);
500	ip->i_usecount--;
501
502	if (ip->i_usecount < 0)
503		panic("ntfs_ntrele: ino: %d usecount: %d \n",
504		      ip->i_number,ip->i_usecount);
505	mtx_unlock(&ip->i_interlock);
506}
507
508/*
509 * Deallocate all memory allocated for ntvattr
510 */
511void
512ntfs_freentvattr(vap)
513	struct ntvattr * vap;
514{
515	if (vap->va_flag & NTFS_AF_INRUN) {
516		if (vap->va_vruncn)
517			free(vap->va_vruncn, M_NTFSRUN);
518		if (vap->va_vruncl)
519			free(vap->va_vruncl, M_NTFSRUN);
520	} else {
521		if (vap->va_datap)
522			free(vap->va_datap, M_NTFSRDATA);
523	}
524	free(vap, M_NTFSNTVATTR);
525}
526
527/*
528 * Convert disk image of attribute into ntvattr structure,
529 * runs are expanded also.
530 */
531int
532ntfs_attrtontvattr(
533		   struct ntfsmount * ntmp,
534		   struct ntvattr ** rvapp,
535		   struct attr * rap)
536{
537	int             error, i;
538	struct ntvattr *vap;
539
540	error = 0;
541	*rvapp = NULL;
542
543	vap = malloc(sizeof(struct ntvattr),
544		M_NTFSNTVATTR, M_WAITOK | M_ZERO);
545	vap->va_ip = NULL;
546	vap->va_flag = rap->a_hdr.a_flag;
547	vap->va_type = rap->a_hdr.a_type;
548	vap->va_compression = rap->a_hdr.a_compression;
549	vap->va_index = rap->a_hdr.a_index;
550
551	ddprintf(("type: 0x%x, index: %d", vap->va_type, vap->va_index));
552
553	vap->va_namelen = rap->a_hdr.a_namelen;
554	if (rap->a_hdr.a_namelen) {
555		wchar *unp = (wchar *) ((caddr_t) rap + rap->a_hdr.a_nameoff);
556		ddprintf((", name:["));
557		for (i = 0; i < vap->va_namelen; i++) {
558			vap->va_name[i] = unp[i];
559			ddprintf(("%c", vap->va_name[i]));
560		}
561		ddprintf(("]"));
562	}
563	if (vap->va_flag & NTFS_AF_INRUN) {
564		ddprintf((", nonres."));
565		vap->va_datalen = rap->a_nr.a_datalen;
566		vap->va_allocated = rap->a_nr.a_allocated;
567		vap->va_vcnstart = rap->a_nr.a_vcnstart;
568		vap->va_vcnend = rap->a_nr.a_vcnend;
569		vap->va_compressalg = rap->a_nr.a_compressalg;
570		error = ntfs_runtovrun(&(vap->va_vruncn), &(vap->va_vruncl),
571				       &(vap->va_vruncnt),
572				       (caddr_t) rap + rap->a_nr.a_dataoff);
573	} else {
574		vap->va_compressalg = 0;
575		ddprintf((", res."));
576		vap->va_datalen = rap->a_r.a_datalen;
577		vap->va_allocated = rap->a_r.a_datalen;
578		vap->va_vcnstart = 0;
579		vap->va_vcnend = ntfs_btocn(vap->va_allocated);
580		vap->va_datap = malloc(vap->va_datalen,
581		       M_NTFSRDATA, M_WAITOK);
582		memcpy(vap->va_datap, (caddr_t) rap + rap->a_r.a_dataoff,
583		       rap->a_r.a_datalen);
584	}
585	ddprintf((", len: %lld", vap->va_datalen));
586
587	if (error)
588		free(vap, M_NTFSNTVATTR);
589	else
590		*rvapp = vap;
591
592	ddprintf(("\n"));
593
594	return (error);
595}
596
597/*
598 * Expand run into more utilizable and more memory eating format.
599 */
600int
601ntfs_runtovrun(
602	       cn_t ** rcnp,
603	       cn_t ** rclp,
604	       u_long * rcntp,
605	       u_int8_t * run)
606{
607	u_int32_t       off;
608	u_int32_t       sz, i;
609	cn_t           *cn;
610	cn_t           *cl;
611	u_long		cnt;
612	cn_t		prev;
613	cn_t		tmp;
614
615	off = 0;
616	cnt = 0;
617	i = 0;
618	while (run[off]) {
619		off += (run[off] & 0xF) + ((run[off] >> 4) & 0xF) + 1;
620		cnt++;
621	}
622	cn = malloc(cnt * sizeof(cn_t), M_NTFSRUN, M_WAITOK);
623	cl = malloc(cnt * sizeof(cn_t), M_NTFSRUN, M_WAITOK);
624
625	off = 0;
626	cnt = 0;
627	prev = 0;
628	while (run[off]) {
629
630		sz = run[off++];
631		cl[cnt] = 0;
632
633		for (i = 0; i < (sz & 0xF); i++)
634			cl[cnt] += (u_int32_t) run[off++] << (i << 3);
635
636		sz >>= 4;
637		if (run[off + sz - 1] & 0x80) {
638			tmp = ((u_int64_t) - 1) << (sz << 3);
639			for (i = 0; i < sz; i++)
640				tmp |= (u_int64_t) run[off++] << (i << 3);
641		} else {
642			tmp = 0;
643			for (i = 0; i < sz; i++)
644				tmp |= (u_int64_t) run[off++] << (i << 3);
645		}
646		if (tmp)
647			prev = cn[cnt] = prev + tmp;
648		else
649			cn[cnt] = tmp;
650
651		cnt++;
652	}
653	*rcnp = cn;
654	*rclp = cl;
655	*rcntp = cnt;
656	return (0);
657}
658
659/*
660 * Compare unicode and ascii string case insens.
661 */
662static int
663ntfs_uastricmp(ntmp, ustr, ustrlen, astr, astrlen)
664	struct ntfsmount *ntmp;
665	const wchar *ustr;
666	size_t ustrlen;
667	const char *astr;
668	size_t astrlen;
669{
670	const char *astrp = astr;
671	char tmpbuf[5];
672	int len, res;
673	size_t i, j, mbstrlen = astrlen;
674
675	if (ntmp->ntm_ic_l2u) {
676		for (i = 0, j = 0; i < ustrlen && j < astrlen; i++) {
677			len = 4;
678			res = ((int) NTFS_TOUPPER(ustr[i])) -
679			    ((int)NTFS_TOUPPER(NTFS_82U(astrp, &len)));
680			astrp += len;
681			j += len;
682			mbstrlen -= len - 1;
683
684			if (res)
685				return res;
686		}
687	} else {
688		/*
689		 * We use NTFS_82U(NTFS_U28(c)) to get rid of unicode
690		 * symbols not covered by translation table
691		 */
692		for (i = 0; i < ustrlen && i < astrlen; i++) {
693			res = ((int) NTFS_TOUPPER(NTFS_82U(NTFS_U28(ustr[i]), &len))) -
694				((int)NTFS_TOUPPER(NTFS_82U(astrp, &len)));
695			astrp++;
696			if (res)
697				return res;
698		}
699	}
700	return (ustrlen - mbstrlen);
701}
702
703/*
704 * Compare unicode and ascii string case sens.
705 */
706static int
707ntfs_uastrcmp(ntmp, ustr, ustrlen, astr, astrlen)
708	struct ntfsmount *ntmp;
709	const wchar *ustr;
710	size_t ustrlen;
711	const char *astr;
712	size_t astrlen;
713{
714	char *c, tmpbuf[5];
715	size_t i, j, mbstrlen = astrlen;
716	int res;
717
718	for (i = 0, j = 0; (i < ustrlen) && (j < astrlen); i++, mbstrlen++) {
719		c = NTFS_U28(ustr[i]);
720		while (*c != '\0') {
721			res = (int) (*c++ - astr[j++]);
722			if (res)
723				return res;
724			mbstrlen--;
725		}
726	}
727	return (ustrlen - mbstrlen);
728}
729
730/*
731 * Search fnode in ntnode, if not found allocate and preinitialize.
732 *
733 * ntnode should be locked on entry.
734 */
735int
736ntfs_fget(
737	struct ntfsmount *ntmp,
738	struct ntnode *ip,
739	int attrtype,
740	char *attrname,
741	struct fnode **fpp)
742{
743	struct fnode *fp;
744
745	dprintf(("ntfs_fget: ino: %d, attrtype: 0x%x, attrname: %s\n",
746		ip->i_number,attrtype, attrname?attrname:""));
747	*fpp = NULL;
748	LIST_FOREACH(fp, &ip->i_fnlist, f_fnlist){
749		dprintf(("ntfs_fget: fnode: attrtype: %d, attrname: %s\n",
750			fp->f_attrtype, fp->f_attrname?fp->f_attrname:""));
751
752		if ((attrtype == fp->f_attrtype) &&
753		    ((!attrname && !fp->f_attrname) ||
754		     (attrname && fp->f_attrname &&
755		      !strcmp(attrname,fp->f_attrname)))){
756			dprintf(("ntfs_fget: found existed: %p\n",fp));
757			*fpp = fp;
758		}
759	}
760
761	if (*fpp)
762		return (0);
763
764	fp = malloc(sizeof(struct fnode), M_NTFSFNODE,
765		M_WAITOK | M_ZERO);
766	dprintf(("ntfs_fget: allocating fnode: %p\n",fp));
767
768	fp->f_ip = ip;
769	if (attrname) {
770		fp->f_flag |= FN_AATTRNAME;
771		fp->f_attrname = malloc(strlen(attrname)+1, M_TEMP, M_WAITOK);
772		strcpy(fp->f_attrname, attrname);
773	} else
774		fp->f_attrname = NULL;
775	fp->f_attrtype = attrtype;
776
777	ntfs_ntref(ip);
778
779	LIST_INSERT_HEAD(&ip->i_fnlist, fp, f_fnlist);
780
781	*fpp = fp;
782
783	return (0);
784}
785
786/*
787 * Deallocate fnode, remove it from ntnode's fnode list.
788 *
789 * ntnode should be locked.
790 */
791void
792ntfs_frele(
793	struct fnode *fp)
794{
795	struct ntnode *ip = FTONT(fp);
796
797	dprintf(("ntfs_frele: fnode: %p for %d: %p\n", fp, ip->i_number, ip));
798
799	dprintf(("ntfs_frele: deallocating fnode\n"));
800	LIST_REMOVE(fp,f_fnlist);
801	if (fp->f_flag & FN_AATTRNAME)
802		free(fp->f_attrname, M_TEMP);
803	if (fp->f_dirblbuf)
804		free(fp->f_dirblbuf, M_NTFSDIR);
805	free(fp, M_NTFSFNODE);
806	ntfs_ntrele(ip);
807}
808
809/*
810 * Lookup attribute name in format: [[:$ATTR_TYPE]:$ATTR_NAME],
811 * $ATTR_TYPE is searched in attrdefs read from $AttrDefs.
812 * If $ATTR_TYPE nott specifed, ATTR_A_DATA assumed.
813 */
814static int
815ntfs_ntlookupattr(
816		struct ntfsmount * ntmp,
817		const char * name,
818		int namelen,
819		int *attrtype,
820		char **attrname)
821{
822	const char *sys;
823	size_t syslen, i;
824	struct ntvattrdef *adp;
825
826	if (namelen == 0)
827		return (0);
828
829	if (name[0] == '$') {
830		sys = name;
831		for (syslen = 0; syslen < namelen; syslen++) {
832			if(sys[syslen] == ':') {
833				name++;
834				namelen--;
835				break;
836			}
837		}
838		name += syslen;
839		namelen -= syslen;
840
841		adp = ntmp->ntm_ad;
842		for (i = 0; i < ntmp->ntm_adnum; i++, adp++){
843			if (syslen != adp->ad_namelen ||
844			   strncmp(sys, adp->ad_name, syslen) != 0)
845				continue;
846
847			*attrtype = adp->ad_type;
848			goto out;
849		}
850		return (ENOENT);
851	} else
852		*attrtype = NTFS_A_DATA;
853
854    out:
855	if (namelen) {
856		(*attrname) = malloc(namelen, M_TEMP, M_WAITOK);
857		memcpy((*attrname), name, namelen);
858		(*attrname)[namelen] = '\0';
859	}
860
861	return (0);
862}
863
864/*
865 * Lookup specifed node for filename, matching cnp,
866 * return fnode filled.
867 */
868int
869ntfs_ntlookupfile(
870	      struct ntfsmount * ntmp,
871	      struct vnode * vp,
872	      struct componentname * cnp,
873	      struct vnode ** vpp)
874{
875	struct fnode   *fp = VTOF(vp);
876	struct ntnode  *ip = FTONT(fp);
877	struct ntvattr *vap;	/* Root attribute */
878	cn_t            cn;	/* VCN in current attribute */
879	caddr_t         rdbuf;	/* Buffer to read directory's blocks  */
880	u_int32_t       blsize;
881	u_int64_t       rdsize;	/* Length of data to read from current block */
882	struct attr_indexentry *iep;
883	int             error, res, anamelen, fnamelen;
884	const char     *fname,*aname;
885	u_int32_t       aoff;
886	int attrtype = NTFS_A_DATA;
887	char *attrname = NULL;
888	struct fnode   *nfp;
889	struct vnode   *nvp;
890	enum vtype	f_type;
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	blsize = vap->va_a_iroot->ir_size;
901	rdsize = vap->va_datalen;
902
903	/*
904	 * Divide file name into: foofilefoofilefoofile[:attrspec]
905	 * Store like this:       fname:fnamelen       [aname:anamelen]
906	 */
907	fname = cnp->cn_nameptr;
908	aname = NULL;
909	anamelen = 0;
910	for (fnamelen = 0; fnamelen < cnp->cn_namelen; fnamelen++)
911		if(fname[fnamelen] == ':') {
912			aname = fname + fnamelen + 1;
913			anamelen = cnp->cn_namelen - fnamelen - 1;
914			dprintf(("ntfs_ntlookupfile: %s (%d), attr: %s (%d)\n",
915				fname, fnamelen, aname, anamelen));
916			break;
917		}
918
919	dprintf(("ntfs_ntlookupfile: blksz: %d, rdsz: %jd\n", blsize, rdsize));
920
921	rdbuf = malloc(blsize, M_TEMP, M_WAITOK);
922
923	error = ntfs_readattr(ntmp, ip, NTFS_A_INDXROOT, "$I30",
924			       0, rdsize, rdbuf, NULL);
925	if (error)
926		goto fail;
927
928	aoff = sizeof(struct attr_indexroot);
929
930	do {
931		iep = (struct attr_indexentry *) (rdbuf + aoff);
932
933		for (; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (rdsize > aoff);
934			aoff += iep->reclen,
935			iep = (struct attr_indexentry *) (rdbuf + aoff))
936		{
937			ddprintf(("scan: %d, %d\n",
938				  (u_int32_t) iep->ie_number,
939				  (u_int32_t) iep->ie_fnametype));
940
941			/* check the name - the case-insensitible check
942			 * has to come first, to break from this for loop
943			 * if needed, so we can dive correctly */
944			res = NTFS_UASTRICMP(iep->ie_fname, iep->ie_fnamelen,
945				fname, fnamelen);
946			if (res > 0) break;
947			if (res < 0) continue;
948
949			if (iep->ie_fnametype == 0 ||
950			    !(ntmp->ntm_flag & NTFS_MFLAG_CASEINS))
951			{
952				res = NTFS_UASTRCMP(iep->ie_fname,
953					iep->ie_fnamelen, fname, fnamelen);
954				if (res != 0) continue;
955			}
956
957			if (aname) {
958				error = ntfs_ntlookupattr(ntmp,
959					aname, anamelen,
960					&attrtype, &attrname);
961				if (error)
962					goto fail;
963			}
964
965			/* Check if we've found ourself */
966			if ((iep->ie_number == ip->i_number) &&
967			    (attrtype == fp->f_attrtype) &&
968			    ((!attrname && !fp->f_attrname) ||
969			     (attrname && fp->f_attrname &&
970			      !strcmp(attrname, fp->f_attrname))))
971			{
972				VREF(vp);
973				*vpp = vp;
974				error = 0;
975				goto fail;
976			}
977
978			/* vget node, but don't load it */
979			error = ntfs_vgetex(ntmp->ntm_mountp,
980				   iep->ie_number, attrtype, attrname,
981				   LK_EXCLUSIVE, VG_DONTLOADIN | VG_DONTVALIDFN,
982				   curthread, &nvp);
983
984			/* free the buffer returned by ntfs_ntlookupattr() */
985			if (attrname) {
986				free(attrname, M_TEMP);
987				attrname = NULL;
988			}
989
990			if (error)
991				goto fail;
992
993			nfp = VTOF(nvp);
994
995			if (nfp->f_flag & FN_VALID) {
996				*vpp = nvp;
997				goto fail;
998			}
999
1000			nfp->f_fflag = iep->ie_fflag;
1001			nfp->f_pnumber = iep->ie_fpnumber;
1002			nfp->f_times = iep->ie_ftimes;
1003
1004			if((nfp->f_fflag & NTFS_FFLAG_DIR) &&
1005			   (nfp->f_attrtype == NTFS_A_DATA) &&
1006			   (nfp->f_attrname == NULL))
1007				f_type = VDIR;
1008			else
1009				f_type = VREG;
1010
1011			nvp->v_type = f_type;
1012
1013			if ((nfp->f_attrtype == NTFS_A_DATA) &&
1014			    (nfp->f_attrname == NULL))
1015			{
1016				/* Opening default attribute */
1017				nfp->f_size = iep->ie_fsize;
1018				nfp->f_allocated = iep->ie_fallocated;
1019				nfp->f_flag |= FN_PRELOADED;
1020			} else {
1021				error = ntfs_filesize(ntmp, nfp,
1022					    &nfp->f_size, &nfp->f_allocated);
1023				if (error) {
1024					vput(nvp);
1025					goto fail;
1026				}
1027			}
1028
1029			nfp->f_flag &= ~FN_VALID;
1030			*vpp = nvp;
1031			goto fail;
1032		}
1033
1034		/* Dive if possible */
1035		if (iep->ie_flag & NTFS_IEFLAG_SUBNODE) {
1036			dprintf(("ntfs_ntlookupfile: diving\n"));
1037
1038			cn = *(cn_t *) (rdbuf + aoff +
1039					iep->reclen - sizeof(cn_t));
1040			rdsize = blsize;
1041
1042			error = ntfs_readattr(ntmp, ip, NTFS_A_INDX, "$I30",
1043					ntfs_cntob(cn), rdsize, rdbuf, NULL);
1044			if (error)
1045				goto fail;
1046
1047			error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC,
1048						rdbuf, rdsize);
1049			if (error)
1050				goto fail;
1051
1052			aoff = (((struct attr_indexalloc *) rdbuf)->ia_hdrsize +
1053				0x18);
1054		} else {
1055			dprintf(("ntfs_ntlookupfile: nowhere to dive :-(\n"));
1056			error = ENOENT;
1057			break;
1058		}
1059	} while (1);
1060
1061	dprintf(("finish\n"));
1062
1063fail:
1064	if (attrname) free(attrname, M_TEMP);
1065	ntfs_ntvattrrele(vap);
1066	ntfs_ntput(ip);
1067	free(rdbuf, M_TEMP);
1068	return (error);
1069}
1070
1071/*
1072 * Check if name type is permitted to show.
1073 */
1074int
1075ntfs_isnamepermitted(
1076		     struct ntfsmount * ntmp,
1077		     struct attr_indexentry * iep)
1078{
1079	if (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES)
1080		return 1;
1081
1082	switch (iep->ie_fnametype) {
1083	case 2:
1084		ddprintf(("ntfs_isnamepermitted: skipped DOS name\n"));
1085		return 0;
1086	case 0: case 1: case 3:
1087		return 1;
1088	default:
1089		printf("ntfs_isnamepermitted: " \
1090		       "WARNING! Unknown file name type: %d\n",
1091		       iep->ie_fnametype);
1092		break;
1093	}
1094	return 0;
1095}
1096
1097/*
1098 * Read ntfs dir like stream of attr_indexentry, not like btree of them.
1099 * This is done by scaning $BITMAP:$I30 for busy clusters and reading them.
1100 * Ofcouse $INDEX_ROOT:$I30 is read before. Last read values are stored in
1101 * fnode, so we can skip toward record number num almost immediatly.
1102 * Anyway this is rather slow routine. The problem is that we don't know
1103 * how many records are there in $INDEX_ALLOCATION:$I30 block.
1104 */
1105int
1106ntfs_ntreaddir(
1107	       struct ntfsmount * ntmp,
1108	       struct fnode * fp,
1109	       u_int32_t num,
1110	       struct attr_indexentry ** riepp)
1111{
1112	struct ntnode  *ip = FTONT(fp);
1113	struct ntvattr *vap = NULL;	/* IndexRoot attribute */
1114	struct ntvattr *bmvap = NULL;	/* BitMap attribute */
1115	struct ntvattr *iavap = NULL;	/* IndexAllocation attribute */
1116	caddr_t         rdbuf;		/* Buffer to read directory's blocks  */
1117	u_int8_t       *bmp = NULL;	/* Bitmap */
1118	u_int32_t       blsize;		/* Index allocation size (2048) */
1119	u_int32_t       rdsize;		/* Length of data to read */
1120	u_int32_t       attrnum;	/* Current attribute type */
1121	u_int32_t       cpbl = 1;	/* Clusters per directory block */
1122	u_int32_t       blnum;
1123	struct attr_indexentry *iep;
1124	int             error = ENOENT;
1125	u_int32_t       aoff, cnum;
1126
1127	dprintf(("ntfs_ntreaddir: read ino: %d, num: %d\n", ip->i_number, num));
1128	error = ntfs_ntget(ip);
1129	if (error)
1130		return (error);
1131
1132	error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXROOT, "$I30", 0, &vap);
1133	if (error)
1134		return (ENOTDIR);
1135
1136	if (fp->f_dirblbuf == NULL) {
1137		fp->f_dirblsz = vap->va_a_iroot->ir_size;
1138		fp->f_dirblbuf = malloc(max(vap->va_datalen,fp->f_dirblsz),
1139		    M_NTFSDIR, M_WAITOK);
1140	}
1141
1142	blsize = fp->f_dirblsz;
1143	rdbuf = fp->f_dirblbuf;
1144
1145	dprintf(("ntfs_ntreaddir: rdbuf: %p, blsize: %d\n", rdbuf, blsize));
1146
1147	if (vap->va_a_iroot->ir_flag & NTFS_IRFLAG_INDXALLOC) {
1148		error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXBITMAP, "$I30",
1149					0, &bmvap);
1150		if (error) {
1151			error = ENOTDIR;
1152			goto fail;
1153		}
1154		bmp = malloc(bmvap->va_datalen, M_TEMP, M_WAITOK);
1155		error = ntfs_readattr(ntmp, ip, NTFS_A_INDXBITMAP, "$I30", 0,
1156				       bmvap->va_datalen, bmp, NULL);
1157		if (error)
1158			goto fail;
1159
1160		error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDX, "$I30",
1161					0, &iavap);
1162		if (error) {
1163			error = ENOTDIR;
1164			goto fail;
1165		}
1166		cpbl = ntfs_btocn(blsize + ntfs_cntob(1) - 1);
1167		dprintf(("ntfs_ntreaddir: indexalloc: %jd, cpbl: %d\n",
1168			 iavap->va_datalen, cpbl));
1169	} else {
1170		dprintf(("ntfs_ntreadidir: w/o BitMap and IndexAllocation\n"));
1171		iavap = bmvap = NULL;
1172		bmp = NULL;
1173	}
1174
1175	/* Try use previous values */
1176	if ((fp->f_lastdnum < num) && (fp->f_lastdnum != 0)) {
1177		attrnum = fp->f_lastdattr;
1178		aoff = fp->f_lastdoff;
1179		blnum = fp->f_lastdblnum;
1180		cnum = fp->f_lastdnum;
1181	} else {
1182		attrnum = NTFS_A_INDXROOT;
1183		aoff = sizeof(struct attr_indexroot);
1184		blnum = 0;
1185		cnum = 0;
1186	}
1187
1188	do {
1189		dprintf(("ntfs_ntreaddir: scan: 0x%x, %d, %d, %d, %d\n",
1190			 attrnum, (u_int32_t) blnum, cnum, num, aoff));
1191		rdsize = (attrnum == NTFS_A_INDXROOT) ? vap->va_datalen : blsize;
1192		error = ntfs_readattr(ntmp, ip, attrnum, "$I30",
1193				ntfs_cntob(blnum * cpbl), rdsize, rdbuf, NULL);
1194		if (error)
1195			goto fail;
1196
1197		if (attrnum == NTFS_A_INDX) {
1198			error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC,
1199						rdbuf, rdsize);
1200			if (error)
1201				goto fail;
1202		}
1203		if (aoff == 0)
1204			aoff = (attrnum == NTFS_A_INDX) ?
1205				(0x18 + ((struct attr_indexalloc *) rdbuf)->ia_hdrsize) :
1206				sizeof(struct attr_indexroot);
1207
1208		iep = (struct attr_indexentry *) (rdbuf + aoff);
1209		for (; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (rdsize > aoff);
1210			aoff += iep->reclen,
1211			iep = (struct attr_indexentry *) (rdbuf + aoff))
1212		{
1213			if (!ntfs_isnamepermitted(ntmp, iep)) continue;
1214
1215			if (cnum >= num) {
1216				fp->f_lastdnum = cnum;
1217				fp->f_lastdoff = aoff;
1218				fp->f_lastdblnum = blnum;
1219				fp->f_lastdattr = attrnum;
1220
1221				*riepp = iep;
1222
1223				error = 0;
1224				goto fail;
1225			}
1226			cnum++;
1227		}
1228
1229		if (iavap) {
1230			if (attrnum == NTFS_A_INDXROOT)
1231				blnum = 0;
1232			else
1233				blnum++;
1234
1235			while (ntfs_cntob(blnum * cpbl) < iavap->va_datalen) {
1236				if (bmp[blnum >> 3] & (1 << (blnum & 7)))
1237					break;
1238				blnum++;
1239			}
1240
1241			attrnum = NTFS_A_INDX;
1242			aoff = 0;
1243			if (ntfs_cntob(blnum * cpbl) >= iavap->va_datalen)
1244				break;
1245			dprintf(("ntfs_ntreaddir: blnum: %d\n", (u_int32_t) blnum));
1246		}
1247	} while (iavap);
1248
1249	*riepp = NULL;
1250	fp->f_lastdnum = 0;
1251
1252fail:
1253	if (vap)
1254		ntfs_ntvattrrele(vap);
1255	if (bmvap)
1256		ntfs_ntvattrrele(bmvap);
1257	if (iavap)
1258		ntfs_ntvattrrele(iavap);
1259	if (bmp)
1260		free(bmp, M_TEMP);
1261	ntfs_ntput(ip);
1262	return (error);
1263}
1264
1265/*
1266 * Convert NTFS times that are in 100 ns units and begins from
1267 * 1601 Jan 1 into unix times.
1268 */
1269struct timespec
1270ntfs_nttimetounix(
1271		  u_int64_t nt)
1272{
1273	struct timespec t;
1274
1275	/* WindowNT times are in 100 ns and from 1601 Jan 1 */
1276	t.tv_nsec = (nt % (1000 * 1000 * 10)) * 100;
1277	t.tv_sec = nt / (1000 * 1000 * 10) -
1278		369LL * 365LL * 24LL * 60LL * 60LL -
1279		89LL * 1LL * 24LL * 60LL * 60LL;
1280	return (t);
1281}
1282
1283/*
1284 * Get file times from NTFS_A_NAME attribute.
1285 */
1286int
1287ntfs_times(
1288	   struct ntfsmount * ntmp,
1289	   struct ntnode * ip,
1290	   ntfs_times_t * tm)
1291{
1292	struct ntvattr *vap;
1293	int             error;
1294
1295	dprintf(("ntfs_times: ino: %d...\n", ip->i_number));
1296
1297	error = ntfs_ntget(ip);
1298	if (error)
1299		return (error);
1300
1301	error = ntfs_ntvattrget(ntmp, ip, NTFS_A_NAME, NULL, 0, &vap);
1302	if (error) {
1303		ntfs_ntput(ip);
1304		return (error);
1305	}
1306	*tm = vap->va_a_name->n_times;
1307	ntfs_ntvattrrele(vap);
1308	ntfs_ntput(ip);
1309
1310	return (0);
1311}
1312
1313/*
1314 * Get file sizes from corresponding attribute.
1315 *
1316 * ntnode under fnode should be locked.
1317 */
1318int
1319ntfs_filesize(
1320	      struct ntfsmount * ntmp,
1321	      struct fnode * fp,
1322	      u_int64_t * size,
1323	      u_int64_t * bytes)
1324{
1325	struct ntvattr *vap;
1326	struct ntnode *ip = FTONT(fp);
1327	u_int64_t       sz, bn;
1328	int             error;
1329
1330	dprintf(("ntfs_filesize: ino: %d\n", ip->i_number));
1331
1332	error = ntfs_ntvattrget(ntmp, ip,
1333		fp->f_attrtype, fp->f_attrname, 0, &vap);
1334	if (error)
1335		return (error);
1336
1337	bn = vap->va_allocated;
1338	sz = vap->va_datalen;
1339
1340	dprintf(("ntfs_filesize: %d bytes (%d bytes allocated)\n",
1341		(u_int32_t) sz, (u_int32_t) bn));
1342
1343	if (size)
1344		*size = sz;
1345	if (bytes)
1346		*bytes = bn;
1347
1348	ntfs_ntvattrrele(vap);
1349
1350	return (0);
1351}
1352
1353/*
1354 * This is one of write routine.
1355 */
1356int
1357ntfs_writeattr_plain(
1358	struct ntfsmount * ntmp,
1359	struct ntnode * ip,
1360	u_int32_t attrnum,
1361	char *attrname,
1362	off_t roff,
1363	size_t rsize,
1364	void *rdata,
1365	size_t * initp,
1366	struct uio *uio)
1367{
1368	size_t          init;
1369	int             error = 0;
1370	off_t           off = roff, left = rsize, towrite;
1371	caddr_t         data = rdata;
1372	struct ntvattr *vap;
1373	*initp = 0;
1374
1375	while (left) {
1376		error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname,
1377					ntfs_btocn(off), &vap);
1378		if (error)
1379			return (error);
1380		towrite = MIN(left, ntfs_cntob(vap->va_vcnend + 1) - off);
1381		ddprintf(("ntfs_writeattr_plain: o: %d, s: %d (%d - %d)\n",
1382			 (u_int32_t) off, (u_int32_t) towrite,
1383			 (u_int32_t) vap->va_vcnstart,
1384			 (u_int32_t) vap->va_vcnend));
1385		error = ntfs_writentvattr_plain(ntmp, ip, vap,
1386					 off - ntfs_cntob(vap->va_vcnstart),
1387					 towrite, data, &init, uio);
1388		if (error) {
1389			printf("ntfs_writeattr_plain: " \
1390			       "ntfs_writentvattr_plain failed: o: %d, s: %d\n",
1391			       (u_int32_t) off, (u_int32_t) towrite);
1392			printf("ntfs_writeattr_plain: attrib: %d - %d\n",
1393			       (u_int32_t) vap->va_vcnstart,
1394			       (u_int32_t) vap->va_vcnend);
1395			ntfs_ntvattrrele(vap);
1396			break;
1397		}
1398		ntfs_ntvattrrele(vap);
1399		left -= towrite;
1400		off += towrite;
1401		data = data + towrite;
1402		*initp += init;
1403	}
1404
1405	return (error);
1406}
1407
1408/*
1409 * This is one of write routine.
1410 *
1411 * ntnode should be locked.
1412 */
1413int
1414ntfs_writentvattr_plain(
1415	struct ntfsmount * ntmp,
1416	struct ntnode * ip,
1417	struct ntvattr * vap,
1418	off_t roff,
1419	size_t rsize,
1420	void *rdata,
1421	size_t * initp,
1422	struct uio *uio)
1423{
1424	int             error = 0;
1425	off_t           off;
1426	int             cnt;
1427	cn_t            ccn, ccl, cn, left, cl;
1428	caddr_t         data = rdata;
1429	struct buf     *bp;
1430	size_t          tocopy;
1431
1432	*initp = 0;
1433
1434	if ((vap->va_flag & NTFS_AF_INRUN) == 0) {
1435		printf("ntfs_writevattr_plain: CAN'T WRITE RES. ATTRIBUTE\n");
1436		return ENOTTY;
1437	}
1438
1439	ddprintf(("ntfs_writentvattr_plain: data in run: %ld chains\n",
1440		 vap->va_vruncnt));
1441
1442	off = roff;
1443	left = rsize;
1444	ccl = 0;
1445	ccn = 0;
1446	cnt = 0;
1447	for (; left && (cnt < vap->va_vruncnt); cnt++) {
1448		ccn = vap->va_vruncn[cnt];
1449		ccl = vap->va_vruncl[cnt];
1450
1451		ddprintf(("ntfs_writentvattr_plain: " \
1452			 "left %d, cn: 0x%x, cl: %d, off: %d\n", \
1453			 (u_int32_t) left, (u_int32_t) ccn, \
1454			 (u_int32_t) ccl, (u_int32_t) off));
1455
1456		if (ntfs_cntob(ccl) < off) {
1457			off -= ntfs_cntob(ccl);
1458			cnt++;
1459			continue;
1460		}
1461		if (!ccn && ip->i_number != NTFS_BOOTINO)
1462			continue; /* XXX */
1463
1464		ccl -= ntfs_btocn(off);
1465		cn = ccn + ntfs_btocn(off);
1466		off = ntfs_btocnoff(off);
1467
1468		while (left && ccl) {
1469			/*
1470			 * Always read and write single clusters at a time -
1471			 * we need to avoid requesting differently-sized
1472			 * blocks at the same disk offsets to avoid
1473			 * confusing the buffer cache.
1474			 */
1475			tocopy = MIN(left, ntfs_cntob(1) - off);
1476			cl = ntfs_btocl(tocopy + off);
1477			KASSERT(cl == 1 && tocopy <= ntfs_cntob(1),
1478			    ("single cluster limit mistake"));
1479			ddprintf(("ntfs_writentvattr_plain: write: " \
1480				"cn: 0x%x cl: %d, off: %d len: %d, left: %d\n",
1481				(u_int32_t) cn, (u_int32_t) cl,
1482				(u_int32_t) off, (u_int32_t) tocopy,
1483				(u_int32_t) left));
1484			if ((off == 0) && (tocopy == ntfs_cntob(cl)))
1485			{
1486				bp = getblk(ntmp->ntm_devvp, ntfs_cntobn(cn)
1487					    * ntmp->ntm_multiplier,
1488					    ntfs_cntob(cl), 0, 0, 0);
1489				clrbuf(bp);
1490			} else {
1491				error = bread(ntmp->ntm_devvp, ntfs_cntobn(cn)
1492					      * ntmp->ntm_multiplier,
1493					      ntfs_cntob(cl), NOCRED, &bp);
1494				if (error) {
1495					brelse(bp);
1496					return (error);
1497				}
1498			}
1499			if (uio)
1500				uiomove(bp->b_data + off, tocopy, uio);
1501			else
1502				memcpy(bp->b_data + off, data, tocopy);
1503			bawrite(bp);
1504			data = data + tocopy;
1505			*initp += tocopy;
1506			off = 0;
1507			left -= tocopy;
1508			cn += cl;
1509			ccl -= cl;
1510		}
1511	}
1512
1513	if (left) {
1514		printf("ntfs_writentvattr_plain: POSSIBLE RUN ERROR\n");
1515		error = EINVAL;
1516	}
1517
1518	return (error);
1519}
1520
1521/*
1522 * This is one of read routines.
1523 *
1524 * ntnode should be locked.
1525 */
1526int
1527ntfs_readntvattr_plain(
1528	struct ntfsmount * ntmp,
1529	struct ntnode * ip,
1530	struct ntvattr * vap,
1531	off_t roff,
1532	size_t rsize,
1533	void *rdata,
1534	size_t * initp,
1535	struct uio *uio)
1536{
1537	int             error = 0;
1538	off_t           off;
1539
1540	*initp = 0;
1541	if (vap->va_flag & NTFS_AF_INRUN) {
1542		int             cnt;
1543		cn_t            ccn, ccl, cn, left, cl;
1544		caddr_t         data = rdata;
1545		struct buf     *bp;
1546		size_t          tocopy;
1547
1548		ddprintf(("ntfs_readntvattr_plain: data in run: %ld chains\n",
1549			 vap->va_vruncnt));
1550
1551		off = roff;
1552		left = rsize;
1553		ccl = 0;
1554		ccn = 0;
1555		cnt = 0;
1556		while (left && (cnt < vap->va_vruncnt)) {
1557			ccn = vap->va_vruncn[cnt];
1558			ccl = vap->va_vruncl[cnt];
1559
1560			ddprintf(("ntfs_readntvattr_plain: " \
1561				 "left %d, cn: 0x%x, cl: %d, off: %d\n", \
1562				 (u_int32_t) left, (u_int32_t) ccn, \
1563				 (u_int32_t) ccl, (u_int32_t) off));
1564
1565			if (ntfs_cntob(ccl) < off) {
1566				off -= ntfs_cntob(ccl);
1567				cnt++;
1568				continue;
1569			}
1570			if (ccn || ip->i_number == NTFS_BOOTINO) {
1571				ccl -= ntfs_btocn(off);
1572				cn = ccn + ntfs_btocn(off);
1573				off = ntfs_btocnoff(off);
1574
1575				while (left && ccl) {
1576					/*
1577					 * Always read single clusters at a
1578					 * time - we need to avoid reading
1579					 * differently-sized blocks at the
1580					 * same disk offsets to avoid
1581					 * confusing the buffer cache.
1582					 */
1583					tocopy = MIN(left,
1584					    ntfs_cntob(1) - off);
1585					cl = ntfs_btocl(tocopy + off);
1586					KASSERT(cl == 1 &&
1587					    tocopy <= ntfs_cntob(1),
1588					    ("single cluster limit mistake"));
1589
1590					ddprintf(("ntfs_readntvattr_plain: " \
1591						"read: cn: 0x%x cl: %d, " \
1592						"off: %d len: %d, left: %d\n",
1593						(u_int32_t) cn,
1594						(u_int32_t) cl,
1595						(u_int32_t) off,
1596						(u_int32_t) tocopy,
1597						(u_int32_t) left));
1598					error = bread(ntmp->ntm_devvp,
1599						      ntfs_cntobn(cn)
1600						      * ntmp->ntm_multiplier,
1601						      ntfs_cntob(cl),
1602						      NOCRED, &bp);
1603					if (error) {
1604						brelse(bp);
1605						return (error);
1606					}
1607					if (uio) {
1608						uiomove(bp->b_data + off,
1609							tocopy, uio);
1610					} else {
1611						memcpy(data, bp->b_data + off,
1612							tocopy);
1613					}
1614					brelse(bp);
1615					data = data + tocopy;
1616					*initp += tocopy;
1617					off = 0;
1618					left -= tocopy;
1619					cn += cl;
1620					ccl -= cl;
1621				}
1622			} else {
1623				tocopy = MIN(left, ntfs_cntob(ccl) - off);
1624				ddprintf(("ntfs_readntvattr_plain: "
1625					"hole: ccn: 0x%x ccl: %d, off: %d, " \
1626					" len: %d, left: %d\n",
1627					(u_int32_t) ccn, (u_int32_t) ccl,
1628					(u_int32_t) off, (u_int32_t) tocopy,
1629					(u_int32_t) left));
1630				left -= tocopy;
1631				off = 0;
1632				if (uio) {
1633					size_t remains = tocopy;
1634					for(; remains; remains--)
1635						uiomove("", 1, uio);
1636				} else
1637					bzero(data, tocopy);
1638				data = data + tocopy;
1639			}
1640			cnt++;
1641		}
1642		if (left) {
1643			printf("ntfs_readntvattr_plain: POSSIBLE RUN ERROR\n");
1644			error = E2BIG;
1645		}
1646	} else {
1647		ddprintf(("ntfs_readnvattr_plain: data is in mft record\n"));
1648		if (uio)
1649			uiomove(vap->va_datap + roff, rsize, uio);
1650		else
1651			memcpy(rdata, vap->va_datap + roff, rsize);
1652		*initp += rsize;
1653	}
1654
1655	return (error);
1656}
1657
1658/*
1659 * This is one of read routines.
1660 */
1661int
1662ntfs_readattr_plain(
1663	struct ntfsmount * ntmp,
1664	struct ntnode * ip,
1665	u_int32_t attrnum,
1666	char *attrname,
1667	off_t roff,
1668	size_t rsize,
1669	void *rdata,
1670	size_t * initp,
1671	struct uio *uio)
1672{
1673	size_t          init;
1674	int             error = 0;
1675	off_t           off = roff, left = rsize, toread;
1676	caddr_t         data = rdata;
1677	struct ntvattr *vap;
1678	*initp = 0;
1679
1680	while (left) {
1681		error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname,
1682					ntfs_btocn(off), &vap);
1683		if (error)
1684			return (error);
1685		toread = MIN(left, ntfs_cntob(vap->va_vcnend + 1) - off);
1686		ddprintf(("ntfs_readattr_plain: o: %d, s: %d (%d - %d)\n",
1687			 (u_int32_t) off, (u_int32_t) toread,
1688			 (u_int32_t) vap->va_vcnstart,
1689			 (u_int32_t) vap->va_vcnend));
1690		error = ntfs_readntvattr_plain(ntmp, ip, vap,
1691					 off - ntfs_cntob(vap->va_vcnstart),
1692					 toread, data, &init, uio);
1693		if (error) {
1694			printf("ntfs_readattr_plain: " \
1695			       "ntfs_readntvattr_plain failed: o: %d, s: %d\n",
1696			       (u_int32_t) off, (u_int32_t) toread);
1697			printf("ntfs_readattr_plain: attrib: %d - %d\n",
1698			       (u_int32_t) vap->va_vcnstart,
1699			       (u_int32_t) vap->va_vcnend);
1700			ntfs_ntvattrrele(vap);
1701			break;
1702		}
1703		ntfs_ntvattrrele(vap);
1704		left -= toread;
1705		off += toread;
1706		data = data + toread;
1707		*initp += init;
1708	}
1709
1710	return (error);
1711}
1712
1713/*
1714 * This is one of read routines.
1715 */
1716int
1717ntfs_readattr(
1718	struct ntfsmount * ntmp,
1719	struct ntnode * ip,
1720	u_int32_t attrnum,
1721	char *attrname,
1722	off_t roff,
1723	size_t rsize,
1724	void *rdata,
1725	struct uio *uio)
1726{
1727	int             error = 0;
1728	struct ntvattr *vap;
1729	size_t          init;
1730
1731	ddprintf(("ntfs_readattr: reading %d: 0x%x, from %d size %d bytes\n",
1732	       ip->i_number, attrnum, (u_int32_t) roff, (u_int32_t) rsize));
1733
1734	error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname, 0, &vap);
1735	if (error)
1736		return (error);
1737
1738	if ((roff > vap->va_datalen) ||
1739	    (roff + rsize > vap->va_datalen)) {
1740		ddprintf(("ntfs_readattr: offset too big\n"));
1741		ntfs_ntvattrrele(vap);
1742		return (E2BIG);
1743	}
1744	if (vap->va_compression && vap->va_compressalg) {
1745		u_int8_t       *cup;
1746		u_int8_t       *uup;
1747		off_t           off = roff, left = rsize, tocopy;
1748		caddr_t         data = rdata;
1749		cn_t            cn;
1750
1751		ddprintf(("ntfs_ntreadattr: compression: %d\n",
1752			 vap->va_compressalg));
1753
1754		cup = malloc(ntfs_cntob(NTFS_COMPUNIT_CL),
1755		       M_NTFSDECOMP, M_WAITOK);
1756		uup = malloc(ntfs_cntob(NTFS_COMPUNIT_CL),
1757		       M_NTFSDECOMP, M_WAITOK);
1758
1759		cn = (ntfs_btocn(roff)) & (~(NTFS_COMPUNIT_CL - 1));
1760		off = roff - ntfs_cntob(cn);
1761
1762		while (left) {
1763			error = ntfs_readattr_plain(ntmp, ip, attrnum,
1764						  attrname, ntfs_cntob(cn),
1765					          ntfs_cntob(NTFS_COMPUNIT_CL),
1766						  cup, &init, NULL);
1767			if (error)
1768				break;
1769
1770			tocopy = MIN(left, ntfs_cntob(NTFS_COMPUNIT_CL) - off);
1771
1772			if (init == ntfs_cntob(NTFS_COMPUNIT_CL)) {
1773				if (uio)
1774					uiomove(cup + off, tocopy, uio);
1775				else
1776					memcpy(data, cup + off, tocopy);
1777			} else if (init == 0) {
1778				if (uio) {
1779					size_t remains = tocopy;
1780					for(; remains; remains--)
1781						uiomove("", 1, uio);
1782				}
1783				else
1784					bzero(data, tocopy);
1785			} else {
1786				error = ntfs_uncompunit(ntmp, uup, cup);
1787				if (error)
1788					break;
1789				if (uio)
1790					uiomove(uup + off, tocopy, uio);
1791				else
1792					memcpy(data, uup + off, tocopy);
1793			}
1794
1795			left -= tocopy;
1796			data = data + tocopy;
1797			off += tocopy - ntfs_cntob(NTFS_COMPUNIT_CL);
1798			cn += NTFS_COMPUNIT_CL;
1799		}
1800
1801		free(uup, M_NTFSDECOMP);
1802		free(cup, M_NTFSDECOMP);
1803	} else
1804		error = ntfs_readattr_plain(ntmp, ip, attrnum, attrname,
1805					     roff, rsize, rdata, &init, uio);
1806	ntfs_ntvattrrele(vap);
1807	return (error);
1808}
1809
1810#if 0
1811int
1812ntfs_parserun(
1813	      cn_t * cn,
1814	      cn_t * cl,
1815	      u_int8_t * run,
1816	      u_long len,
1817	      u_long *off)
1818{
1819	u_int8_t        sz;
1820	int             i;
1821
1822	if (NULL == run) {
1823		printf("ntfs_parsetun: run == NULL\n");
1824		return (EINVAL);
1825	}
1826	sz = run[(*off)++];
1827	if (0 == sz) {
1828		printf("ntfs_parserun: trying to go out of run\n");
1829		return (E2BIG);
1830	}
1831	*cl = 0;
1832	if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) {
1833		printf("ntfs_parserun: " \
1834		       "bad run: length too big: sz: 0x%02x (%ld < %ld + sz)\n",
1835		       sz, len, *off);
1836		return (EINVAL);
1837	}
1838	for (i = 0; i < (sz & 0xF); i++)
1839		*cl += (u_int32_t) run[(*off)++] << (i << 3);
1840
1841	sz >>= 4;
1842	if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) {
1843		printf("ntfs_parserun: " \
1844		       "bad run: length too big: sz: 0x%02x (%ld < %ld + sz)\n",
1845		       sz, len, *off);
1846		return (EINVAL);
1847	}
1848	for (i = 0; i < (sz & 0xF); i++)
1849		*cn += (u_int32_t) run[(*off)++] << (i << 3);
1850
1851	return (0);
1852}
1853#endif
1854
1855/*
1856 * Process fixup routine on given buffer.
1857 */
1858int
1859ntfs_procfixups(
1860		struct ntfsmount * ntmp,
1861		u_int32_t magic,
1862		caddr_t buf,
1863		size_t len)
1864{
1865	struct fixuphdr *fhp = (struct fixuphdr *) buf;
1866	int             i;
1867	u_int16_t       fixup;
1868	u_int16_t      *fxp;
1869	u_int16_t      *cfxp;
1870
1871	if (fhp->fh_magic != magic) {
1872		printf("ntfs_procfixups: magic doesn't match: %08x != %08x\n",
1873		       fhp->fh_magic, magic);
1874		return (EINVAL);
1875	}
1876	if ((fhp->fh_fnum - 1) * NTFS_BLOCK_SIZE != len) {
1877		printf("ntfs_procfixups: " \
1878		       "bad fixups number: %d for %ld bytes block\n",
1879		       fhp->fh_fnum, (long)len);	/* XXX printf kludge */
1880		return (EINVAL);
1881	}
1882	if (fhp->fh_foff >= ntmp->ntm_spc * ntmp->ntm_mftrecsz * ntmp->ntm_bps) {
1883		printf("ntfs_procfixups: invalid offset: %x", fhp->fh_foff);
1884		return (EINVAL);
1885	}
1886	fxp = (u_int16_t *) (buf + fhp->fh_foff);
1887	cfxp = (u_int16_t *) (buf + NTFS_BLOCK_SIZE - 2);
1888	fixup = *fxp++;
1889	for (i = 1; i < fhp->fh_fnum; i++, fxp++) {
1890		if (*cfxp != fixup) {
1891			printf("ntfs_procfixups: fixup %d doesn't match\n", i);
1892			return (EINVAL);
1893		}
1894		*cfxp = *fxp;
1895		cfxp = (u_int16_t *) ((caddr_t) cfxp + NTFS_BLOCK_SIZE);
1896	}
1897	return (0);
1898}
1899
1900#if 0
1901int
1902ntfs_runtocn(
1903	     cn_t * cn,
1904	     struct ntfsmount * ntmp,
1905	     u_int8_t * run,
1906	     u_long len,
1907	     cn_t vcn)
1908{
1909	cn_t            ccn = 0;
1910	cn_t            ccl = 0;
1911	u_long          off = 0;
1912	int             error = 0;
1913
1914#if NTFS_DEBUG
1915	int             i;
1916	printf("ntfs_runtocn: run: %p, %ld bytes, vcn:%ld\n",
1917		run, len, (u_long) vcn);
1918	printf("ntfs_runtocn: run: ");
1919	for (i = 0; i < len; i++)
1920		printf("0x%02x ", run[i]);
1921	printf("\n");
1922#endif
1923
1924	if (NULL == run) {
1925		printf("ntfs_runtocn: run == NULL\n");
1926		return (EINVAL);
1927	}
1928	do {
1929		if (run[off] == 0) {
1930			printf("ntfs_runtocn: vcn too big\n");
1931			return (E2BIG);
1932		}
1933		vcn -= ccl;
1934		error = ntfs_parserun(&ccn, &ccl, run, len, &off);
1935		if (error) {
1936			printf("ntfs_runtocn: ntfs_parserun failed\n");
1937			return (error);
1938		}
1939	} while (ccl <= vcn);
1940	*cn = ccn + vcn;
1941	return (0);
1942}
1943#endif
1944
1945/*
1946 * this initializes toupper table & dependant variables to be ready for
1947 * later work
1948 */
1949void
1950ntfs_toupper_init()
1951{
1952	ntfs_toupper_tab = (wchar *) NULL;
1953	lockinit(&ntfs_toupper_lock, PVFS, "ntfs_toupper", 0, 0);
1954	ntfs_toupper_usecount = 0;
1955}
1956
1957void
1958ntfs_toupper_destroy(void)
1959{
1960
1961	lockdestroy(&ntfs_toupper_lock);
1962}
1963
1964/*
1965 * if the ntfs_toupper_tab[] is filled already, just raise use count;
1966 * otherwise read the data from the filesystem we are currently mounting
1967 */
1968int
1969ntfs_toupper_use(mp, ntmp)
1970	struct mount *mp;
1971	struct ntfsmount *ntmp;
1972{
1973	int error = 0;
1974	struct vnode *vp;
1975
1976	/* get exclusive access */
1977	lockmgr(&ntfs_toupper_lock, LK_EXCLUSIVE, NULL);
1978
1979	/* only read the translation data from a file if it hasn't been
1980	 * read already */
1981	if (ntfs_toupper_tab)
1982		goto out;
1983
1984	/*
1985	 * Read in Unicode lowercase -> uppercase translation file.
1986	 * XXX for now, just the first 256 entries are used anyway,
1987	 * so don't bother reading more
1988	 */
1989	ntfs_toupper_tab = malloc(65536 * sizeof(wchar),
1990		M_NTFSRDATA, M_WAITOK);
1991
1992	if ((error = VFS_VGET(mp, NTFS_UPCASEINO, LK_EXCLUSIVE, &vp)))
1993		goto out;
1994	error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL,
1995			0, 65536*sizeof(wchar), (char *) ntfs_toupper_tab, NULL);
1996	vput(vp);
1997
1998    out:
1999	ntfs_toupper_usecount++;
2000	lockmgr(&ntfs_toupper_lock, LK_RELEASE, NULL);
2001	return (error);
2002}
2003
2004/*
2005 * lower the use count and if it reaches zero, free the memory
2006 * tied by toupper table
2007 */
2008void
2009ntfs_toupper_unuse()
2010{
2011	/* get exclusive access */
2012	lockmgr(&ntfs_toupper_lock, LK_EXCLUSIVE, NULL);
2013
2014	ntfs_toupper_usecount--;
2015	if (ntfs_toupper_usecount == 0) {
2016		free(ntfs_toupper_tab, M_NTFSRDATA);
2017		ntfs_toupper_tab = NULL;
2018	}
2019#ifdef DIAGNOSTIC
2020	else if (ntfs_toupper_usecount < 0) {
2021		panic("ntfs_toupper_unuse(): use count negative: %d\n",
2022			ntfs_toupper_usecount);
2023	}
2024#endif
2025
2026	/* release the lock */
2027	lockmgr(&ntfs_toupper_lock, LK_RELEASE, NULL);
2028}
2029
2030int
2031ntfs_u28_init(
2032	struct ntfsmount *ntmp,
2033	wchar *u2w,
2034	char *cs_local,
2035	char *cs_ntfs)
2036{
2037	char ** u28;
2038	int i, j, h, l;
2039
2040	if (ntfs_iconv && cs_local) {
2041		ntfs_iconv->open(cs_local, cs_ntfs, &ntmp->ntm_ic_u2l);
2042		return (0);
2043	}
2044
2045	u28 = malloc(256 * sizeof(char*), M_TEMP, M_WAITOK | M_ZERO);
2046
2047	for (i=0; i<256; i++) {
2048		h = (u2w[i] >> 8) & 0xFF;
2049		l = (u2w[i]) &0xFF;
2050
2051		if (u28[h] == NULL) {
2052			u28[h] = malloc(256 * sizeof(char), M_TEMP, M_WAITOK);
2053			for (j=0; j<256; j++)
2054				u28[h][j] = '_';
2055		}
2056
2057		u28[h][l] = i & 0xFF;
2058	}
2059
2060	ntmp->ntm_u28 = u28;
2061
2062	return (0);
2063}
2064
2065int
2066ntfs_u28_uninit(struct ntfsmount *ntmp)
2067{
2068	char ** u28;
2069	int i;
2070
2071	if (ntmp->ntm_u28 == NULL) {
2072		if (ntfs_iconv && ntmp->ntm_ic_u2l) {
2073			ntfs_iconv->close(ntmp->ntm_ic_u2l);
2074		}
2075		return (0);
2076	}
2077
2078	u28 = ntmp->ntm_u28;
2079
2080	for (i=0; i<256; i++)
2081		if (u28[i] != NULL)
2082			free(u28[i], M_TEMP);
2083
2084	free(u28, M_TEMP);
2085
2086	return (0);
2087}
2088
2089int
2090ntfs_82u_init(
2091	struct ntfsmount *ntmp,
2092	char *cs_local,
2093	char *cs_ntfs)
2094{
2095	wchar * _82u;
2096	int i;
2097
2098	if (ntfs_iconv && cs_local) {
2099		ntfs_iconv->open(cs_ntfs, cs_local, &ntmp->ntm_ic_l2u);
2100		return (0);
2101	}
2102
2103	_82u = malloc(256 * sizeof(wchar), M_TEMP, M_WAITOK);
2104
2105	for (i=0; i<256; i++)
2106			_82u[i] = i;
2107
2108	ntmp->ntm_82u = _82u;
2109
2110	return (0);
2111}
2112
2113int
2114ntfs_82u_uninit(struct ntfsmount *ntmp)
2115{
2116
2117	if (ntmp->ntm_82u == NULL) {
2118		if (ntfs_iconv && ntmp->ntm_ic_l2u) {
2119			ntfs_iconv->close(ntmp->ntm_ic_l2u);
2120		}
2121		return (0);
2122	}
2123
2124	free(ntmp->ntm_82u, M_TEMP);
2125	return (0);
2126}
2127
2128/*
2129 * maps the Unicode char to local character
2130 */
2131char *
2132ntfs_u28(
2133	char *outbuf,
2134	struct ntfsmount *ntmp,
2135	wchar wc)
2136{
2137	char *p, *outp, inbuf[3];
2138	size_t ilen, olen;
2139
2140	outp = outbuf;
2141	if (ntfs_iconv && ntmp->ntm_ic_u2l) {
2142		ilen = 2;
2143		olen = 4;
2144
2145		inbuf[0] = (char)(wc>>8);
2146		inbuf[1] = (char)wc;
2147		inbuf[2] = '\0';
2148		p = inbuf;
2149		ntfs_iconv->convchr(ntmp->ntm_ic_u2l, (const char **)&p, &ilen,
2150				    &outp, &olen);
2151		if (olen == 4)
2152			*outp++ = '?';
2153		*outp = '\0';
2154		outp = outbuf;
2155		return (outp);
2156	}
2157
2158	p = ntmp->ntm_u28[(wc>>8)&0xFF];
2159	outbuf[0] = (p == NULL) ? '_' : p[wc&0xFF] & 0xFF;
2160	outbuf[1] = '\0';
2161	return (outp);
2162}
2163
2164wchar
2165ntfs_82u(
2166	struct ntfsmount *ntmp,
2167	const char *c,
2168	int *len)
2169{
2170	char *outp, outbuf[3];
2171	wchar uc;
2172	size_t ilen, olen;
2173
2174	if (ntfs_iconv && ntmp->ntm_ic_l2u) {
2175		ilen = (size_t)*len;
2176		olen = 2;
2177
2178		outp = outbuf;
2179		ntfs_iconv->convchr(ntmp->ntm_ic_l2u, &c, &ilen, &outp, &olen);
2180		*len -= (int)ilen;
2181		uc = (wchar)((outbuf[0]<<8) | (outbuf[1]&0xFF));
2182
2183		return (uc);
2184	}
2185
2186	if (ntmp->ntm_82u != NULL)
2187		return (ntmp->ntm_82u[*c&0xFF]);
2188
2189	return ('?');
2190}
2191
2192