ntfs_subr.c revision 120492
118334Speter/*	$NetBSD: ntfs_subr.c,v 1.23 1999/10/31 19:45:26 jdolecek Exp $	*/
250397Sobrien
318334Speter/*-
418334Speter * Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org)
518334Speter * All rights reserved.
618334Speter *
718334Speter * Redistribution and use in source and binary forms, with or without
818334Speter * modification, are permitted provided that the following conditions
918334Speter * are met:
1018334Speter * 1. Redistributions of source code must retain the above copyright
1118334Speter *    notice, this list of conditions and the following disclaimer.
1218334Speter * 2. Redistributions in binary form must reproduce the above copyright
1318334Speter *    notice, this list of conditions and the following disclaimer in the
1418334Speter *    documentation and/or other materials provided with the distribution.
1518334Speter *
1618334Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1718334Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1818334Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1918334Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2018334Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2118334Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2218334Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2318334Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2418334Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2518334Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2618334Speter * SUCH DAMAGE.
2718334Speter *
2818334Speter * $FreeBSD: head/sys/fs/ntfs/ntfs_subr.c 120492 2003-09-26 20:26:25Z fjoe $
2918334Speter */
3018334Speter
3118334Speter#include <sys/param.h>
3250397Sobrien#include <sys/types.h>
3318334Speter#include <sys/systm.h>
3418334Speter#include <sys/namei.h>
3518334Speter#include <sys/kernel.h>
3618334Speter#include <sys/vnode.h>
3750397Sobrien#include <sys/mount.h>
3850397Sobrien#include <sys/bio.h>
3950397Sobrien#include <sys/buf.h>
4018334Speter#include <sys/file.h>
4118334Speter#include <sys/malloc.h>
4218334Speter#include <sys/lock.h>
4318334Speter#include <sys/iconv.h>
4418334Speter
4550397Sobrien/* #define NTFS_DEBUG 1 */
4618334Speter#include <fs/ntfs/ntfs.h>
4718334Speter#include <fs/ntfs/ntfsmount.h>
4818334Speter#include <fs/ntfs/ntfs_inode.h>
4918334Speter#include <fs/ntfs/ntfs_vfsops.h>
5018334Speter#include <fs/ntfs/ntfs_subr.h>
5118334Speter#include <fs/ntfs/ntfs_compr.h>
5218334Speter#include <fs/ntfs/ntfs_ihash.h>
5318334Speter
5418334SpeterMALLOC_DEFINE(M_NTFSNTVATTR, "NTFS vattr", "NTFS file attribute information");
5518334SpeterMALLOC_DEFINE(M_NTFSRDATA, "NTFS res data", "NTFS resident data");
5618334SpeterMALLOC_DEFINE(M_NTFSRUN, "NTFS vrun", "NTFS vrun storage");
5718334SpeterMALLOC_DEFINE(M_NTFSDECOMP, "NTFS decomp", "NTFS decompression temporary");
5818334Speter
5918334Speterstatic int ntfs_ntlookupattr(struct ntfsmount *, const char *, int, int *, char **);
6018334Speterstatic int ntfs_findvattr(struct ntfsmount *, struct ntnode *, struct ntvattr **, struct ntvattr **, u_int32_t, const char *, size_t, cn_t);
6118334Speterstatic int ntfs_uastricmp(struct ntfsmount *, const wchar *, size_t, const char *, size_t);
6218334Speterstatic int ntfs_uastrcmp(struct ntfsmount *, const wchar *, size_t, const char *, size_t);
6318334Speter
6418334Speter/* table for mapping Unicode chars into uppercase; it's filled upon first
6518334Speter * ntfs mount, freed upon last ntfs umount */
6618334Speterstatic wchar *ntfs_toupper_tab;
6718334Speter#define NTFS_TOUPPER(ch)	(ntfs_toupper_tab[(ch)])
6818334Speterstatic struct lock ntfs_toupper_lock;
6918334Speterstatic signed int ntfs_toupper_usecount;
7018334Speter
7118334Speterstruct iconv_functions *ntfs_iconv = NULL;
7218334Speter
7318334Speter/* support macro for ntfs_ntvattrget() */
7450397Sobrien#define NTFS_AALPCMP(aalp,type,name,namelen) (				\
7550397Sobrien  (aalp->al_type == type) && (aalp->al_namelen == namelen) &&		\
7618334Speter  !NTFS_UASTRCMP(aalp->al_name,aalp->al_namelen,name,namelen) )
7718334Speter
7818334Speter/*
7918334Speter *
8018334Speter */
8118334Speterint
8218334Speterntfs_ntvattrrele(vap)
8318334Speter	struct ntvattr * vap;
8418334Speter{
8518334Speter	dprintf(("ntfs_ntvattrrele: ino: %d, type: 0x%x\n",
8618334Speter		 vap->va_ip->i_number, vap->va_type));
8718334Speter
8818334Speter	ntfs_ntrele(vap->va_ip);
8918334Speter
9018334Speter	return (0);
9118334Speter}
9218334Speter
9318334Speter/*
9418334Speter * find the attribute in the ntnode
9518334Speter */
9618334Speterstatic int
9718334Speterntfs_findvattr(ntmp, ip, lvapp, vapp, type, name, namelen, vcn)
9818334Speter	struct ntfsmount *ntmp;
9918334Speter	struct ntnode *ip;
10018334Speter	struct ntvattr **lvapp, **vapp;
10118334Speter	u_int32_t type;
10218334Speter	const char *name;
10318334Speter	size_t namelen;
10418334Speter	cn_t vcn;
10518334Speter{
10618334Speter	int error;
10718334Speter	struct ntvattr *vap;
10818334Speter
10918334Speter	if((ip->i_flag & IN_LOADED) == 0) {
11018334Speter		dprintf(("ntfs_findvattr: node not loaded, ino: %d\n",
11118334Speter		       ip->i_number));
11218334Speter		error = ntfs_loadntnode(ntmp,ip);
11318334Speter		if (error) {
11418334Speter			printf("ntfs_findvattr: FAILED TO LOAD INO: %d\n",
11518334Speter			       ip->i_number);
11618334Speter			return (error);
11718334Speter		}
11818334Speter	}
11918334Speter
12018334Speter	*lvapp = NULL;
12118334Speter	*vapp = NULL;
12218334Speter	LIST_FOREACH(vap, &ip->i_valist, va_list) {
12318334Speter		ddprintf(("ntfs_findvattr: type: 0x%x, vcn: %d - %d\n", \
12418334Speter			  vap->va_type, (u_int32_t) vap->va_vcnstart, \
12518334Speter			  (u_int32_t) vap->va_vcnend));
12618334Speter		if ((vap->va_type == type) &&
12718334Speter		    (vap->va_vcnstart <= vcn) && (vap->va_vcnend >= vcn) &&
12818334Speter		    (vap->va_namelen == namelen) &&
12918334Speter		    (strncmp(name, vap->va_name, namelen) == 0)) {
13018334Speter			*vapp = vap;
13118334Speter			ntfs_ntref(vap->va_ip);
13218334Speter			return (0);
13318334Speter		}
13418334Speter		if (vap->va_type == NTFS_A_ATTRLIST)
13518334Speter			*lvapp = vap;
13618334Speter	}
13718334Speter
13818334Speter	return (-1);
13918334Speter}
14018334Speter
14118334Speter/*
14218334Speter * Search attribute specifed in ntnode (load ntnode if nessecary).
14318334Speter * If not found but ATTR_A_ATTRLIST present, read it in and search throught.
14418334Speter * VOP_VGET node needed, and lookup througth it's ntnode (load if nessesary).
14518334Speter *
14618334Speter * ntnode should be locked
14718334Speter */
14818334Speterint
14918334Speterntfs_ntvattrget(
15018334Speter		struct ntfsmount * ntmp,
15118334Speter		struct ntnode * ip,
15218334Speter		u_int32_t type,
15318334Speter		const char *name,
15418334Speter		cn_t vcn,
15518334Speter		struct ntvattr ** vapp)
15618334Speter{
15718334Speter	struct ntvattr *lvap = NULL;
15818334Speter	struct attr_attrlist *aalp;
15918334Speter	struct attr_attrlist *nextaalp;
16018334Speter	struct vnode   *newvp;
16118334Speter	struct ntnode  *newip;
16218334Speter	caddr_t         alpool;
16318334Speter	size_t		namelen, len;
16418334Speter	int             error;
16518334Speter
16618334Speter	*vapp = NULL;
16718334Speter
16818334Speter	if (name) {
16918334Speter		dprintf(("ntfs_ntvattrget: " \
17018334Speter			 "ino: %d, type: 0x%x, name: %s, vcn: %d\n", \
17118334Speter			 ip->i_number, type, name, (u_int32_t) vcn));
17218334Speter		namelen = strlen(name);
17318334Speter	} else {
17418334Speter		dprintf(("ntfs_ntvattrget: " \
17518334Speter			 "ino: %d, type: 0x%x, vcn: %d\n", \
17618334Speter			 ip->i_number, type, (u_int32_t) vcn));
17718334Speter		name = "";
17818334Speter		namelen = 0;
17918334Speter	}
18018334Speter
18118334Speter	error = ntfs_findvattr(ntmp, ip, &lvap, vapp, type, name, namelen, vcn);
18218334Speter	if (error >= 0)
18318334Speter		return (error);
18418334Speter
18518334Speter	if (!lvap) {
18618334Speter		dprintf(("ntfs_ntvattrget: UNEXISTED ATTRIBUTE: " \
18718334Speter		       "ino: %d, type: 0x%x, name: %s, vcn: %d\n", \
18818334Speter		       ip->i_number, type, name, (u_int32_t) vcn));
18918334Speter		return (ENOENT);
19018334Speter	}
19118334Speter	/* Scan $ATTRIBUTE_LIST for requested attribute */
19218334Speter	len = lvap->va_datalen;
19318334Speter	MALLOC(alpool, caddr_t, len, M_TEMP, M_WAITOK);
19418334Speter	error = ntfs_readntvattr_plain(ntmp, ip, lvap, 0, len, alpool, &len,
19518334Speter			NULL);
19618334Speter	if (error)
19750397Sobrien		goto out;
19850397Sobrien
19918334Speter	aalp = (struct attr_attrlist *) alpool;
20018334Speter	nextaalp = NULL;
20118334Speter
20218334Speter	for(; len > 0; aalp = nextaalp) {
20318334Speter		dprintf(("ntfs_ntvattrget: " \
20418334Speter			 "attrlist: ino: %d, attr: 0x%x, vcn: %d\n", \
20518334Speter			 aalp->al_inumber, aalp->al_type, \
20618334Speter			 (u_int32_t) aalp->al_vcnstart));
20718334Speter
20818334Speter		if (len > aalp->reclen) {
20918334Speter			nextaalp = NTFS_NEXTREC(aalp, struct attr_attrlist *);
21018334Speter		} else {
21118334Speter			nextaalp = NULL;
21218334Speter		}
21318334Speter		len -= aalp->reclen;
21418334Speter
21518334Speter		if (!NTFS_AALPCMP(aalp, type, name, namelen) ||
21618334Speter		    (nextaalp && (nextaalp->al_vcnstart <= vcn) &&
21718334Speter		     NTFS_AALPCMP(nextaalp, type, name, namelen)))
21818334Speter			continue;
21918334Speter
22018334Speter		dprintf(("ntfs_ntvattrget: attribute in ino: %d\n",
22118334Speter				 aalp->al_inumber));
22218334Speter
22318334Speter		/* this is not a main record, so we can't use just plain
22418334Speter		   vget() */
22518334Speter		error = ntfs_vgetex(ntmp->ntm_mountp, aalp->al_inumber,
22618334Speter				NTFS_A_DATA, NULL, LK_EXCLUSIVE,
22718334Speter				VG_EXT, curthread, &newvp);
22818334Speter		if (error) {
22918334Speter			printf("ntfs_ntvattrget: CAN'T VGET INO: %d\n",
23018334Speter			       aalp->al_inumber);
23118334Speter			goto out;
23218334Speter		}
23318334Speter		newip = VTONT(newvp);
23418334Speter		/* XXX have to lock ntnode */
23518334Speter		error = ntfs_findvattr(ntmp, newip, &lvap, vapp,
23618334Speter				type, name, namelen, vcn);
23718334Speter		vput(newvp);
23818334Speter		if (error == 0)
23918334Speter			goto out;
24018334Speter		printf("ntfs_ntvattrget: ATTRLIST ERROR.\n");
24118334Speter		break;
24218334Speter	}
24318334Speter	error = ENOENT;
24418334Speter
24518334Speter	dprintf(("ntfs_ntvattrget: UNEXISTED ATTRIBUTE: " \
24618334Speter	       "ino: %d, type: 0x%x, name: %.*s, vcn: %d\n", \
24718334Speter	       ip->i_number, type, (int) namelen, name, (u_int32_t) vcn));
24818334Speterout:
24918334Speter	FREE(alpool, M_TEMP);
25018334Speter	return (error);
25118334Speter}
25218334Speter
25318334Speter/*
25418334Speter * Read ntnode from disk, make ntvattr list.
25518334Speter *
25618334Speter * ntnode should be locked
25718334Speter */
25818334Speterint
25918334Speterntfs_loadntnode(
26018334Speter	      struct ntfsmount * ntmp,
26118334Speter	      struct ntnode * ip)
26218334Speter{
26318334Speter	struct filerec  *mfrp;
26418334Speter	daddr_t         bn;
26518334Speter	int		error,off;
26650397Sobrien	struct attr    *ap;
26750397Sobrien	struct ntvattr *nvap;
26850397Sobrien
26950397Sobrien	dprintf(("ntfs_loadntnode: loading ino: %d\n",ip->i_number));
27050397Sobrien
27150397Sobrien	MALLOC(mfrp, struct filerec *, ntfs_bntob(ntmp->ntm_bpmftrec),
27218334Speter	       M_TEMP, M_WAITOK);
27318334Speter
27418334Speter	if (ip->i_number < NTFS_SYSNODESNUM) {
27518334Speter		struct buf     *bp;
27618334Speter
27718334Speter		dprintf(("ntfs_loadntnode: read system node\n"));
27818334Speter
27918334Speter		bn = ntfs_cntobn(ntmp->ntm_mftcn) +
28018334Speter			ntmp->ntm_bpmftrec * ip->i_number;
28118334Speter
28218334Speter		error = bread(ntmp->ntm_devvp,
28318334Speter			      bn, ntfs_bntob(ntmp->ntm_bpmftrec),
28418334Speter			      NOCRED, &bp);
28518334Speter		if (error) {
28618334Speter			printf("ntfs_loadntnode: BREAD FAILED\n");
28718334Speter			brelse(bp);
28818334Speter			goto out;
28918334Speter		}
29018334Speter		memcpy(mfrp, bp->b_data, ntfs_bntob(ntmp->ntm_bpmftrec));
29118334Speter		bqrelse(bp);
29218334Speter	} else {
29318334Speter		struct vnode   *vp;
29418334Speter
29518334Speter		vp = ntmp->ntm_sysvn[NTFS_MFTINO];
29618334Speter		error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL,
29718334Speter			       ip->i_number * ntfs_bntob(ntmp->ntm_bpmftrec),
29818334Speter			       ntfs_bntob(ntmp->ntm_bpmftrec), mfrp, NULL);
29918334Speter		if (error) {
30018334Speter			printf("ntfs_loadntnode: ntfs_readattr failed\n");
30118334Speter			goto out;
30218334Speter		}
30318334Speter	}
30418334Speter
30518334Speter	/* Check if magic and fixups are correct */
30618334Speter	error = ntfs_procfixups(ntmp, NTFS_FILEMAGIC, (caddr_t)mfrp,
30718334Speter				ntfs_bntob(ntmp->ntm_bpmftrec));
30818334Speter	if (error) {
30918334Speter		printf("ntfs_loadntnode: BAD MFT RECORD %d\n",
31018334Speter		       (u_int32_t) ip->i_number);
31118334Speter		goto out;
31218334Speter	}
31318334Speter
31418334Speter	dprintf(("ntfs_loadntnode: load attrs for ino: %d\n",ip->i_number));
31518334Speter	off = mfrp->fr_attroff;
31618334Speter	ap = (struct attr *) ((caddr_t)mfrp + off);
31718334Speter
31818334Speter	LIST_INIT(&ip->i_valist);
31918334Speter
32018334Speter	while (ap->a_hdr.a_type != -1) {
32118334Speter		error = ntfs_attrtontvattr(ntmp, &nvap, ap);
32218334Speter		if (error)
32318334Speter			break;
32418334Speter		nvap->va_ip = ip;
32518334Speter
32618334Speter		LIST_INSERT_HEAD(&ip->i_valist, nvap, va_list);
32718334Speter
32818334Speter		off += ap->a_hdr.reclen;
32918334Speter		ap = (struct attr *) ((caddr_t)mfrp + off);
33018334Speter	}
33118334Speter	if (error) {
33218334Speter		printf("ntfs_loadntnode: failed to load attr ino: %d\n",
33318334Speter		       ip->i_number);
33418334Speter		goto out;
33518334Speter	}
33618334Speter
33718334Speter	ip->i_mainrec = mfrp->fr_mainrec;
33818334Speter	ip->i_nlink = mfrp->fr_nlink;
33918334Speter	ip->i_frflag = mfrp->fr_flags;
34018334Speter
34118334Speter	ip->i_flag |= IN_LOADED;
34218334Speter
34318334Speterout:
34418334Speter	FREE(mfrp, M_TEMP);
34518334Speter	return (error);
34618334Speter}
34718334Speter
34818334Speter/*
34918334Speter * Routine locks ntnode and increase usecount, just opposite of
35018334Speter * ntfs_ntput().
35118334Speter */
35218334Speterint
35318334Speterntfs_ntget(ip)
35418334Speter	struct ntnode *ip;
35518334Speter{
35618334Speter	dprintf(("ntfs_ntget: get ntnode %d: %p, usecount: %d\n",
35718334Speter		ip->i_number, ip, ip->i_usecount));
35818334Speter
35918334Speter	mtx_lock(&ip->i_interlock);
36018334Speter	ip->i_usecount++;
36118334Speter	lockmgr(&ip->i_lock, LK_EXCLUSIVE | LK_INTERLOCK, &ip->i_interlock,
36218334Speter	    NULL);
36318334Speter
36418334Speter	return 0;
36518334Speter}
36618334Speter
36718334Speter/*
36818334Speter * Routine search ntnode in hash, if found: lock, inc usecount and return.
36918334Speter * If not in hash allocate structure for ntnode, prefill it, lock,
37018334Speter * inc count and return.
37118334Speter *
37218334Speter * ntnode returned locked
37318334Speter */
37418334Speterint
37518334Speterntfs_ntlookup(
37618334Speter	   struct ntfsmount * ntmp,
37718334Speter	   ino_t ino,
37818334Speter	   struct ntnode ** ipp)
37918334Speter{
38018334Speter	struct ntnode  *ip;
38118334Speter
38218334Speter	dprintf(("ntfs_ntlookup: looking for ntnode %d\n", ino));
38318334Speter
38418334Speter	do {
38518334Speter		if ((ip = ntfs_nthashlookup(ntmp->ntm_dev, ino)) != NULL) {
38618334Speter			ntfs_ntget(ip);
38718334Speter			dprintf(("ntfs_ntlookup: ntnode %d: %p, usecount: %d\n",
38818334Speter				ino, ip, ip->i_usecount));
38918334Speter			*ipp = ip;
39018334Speter			return (0);
39118334Speter		}
39218334Speter	} while (lockmgr(&ntfs_hashlock, LK_EXCLUSIVE | LK_SLEEPFAIL, NULL,
39318334Speter	    NULL));
39418334Speter
39518334Speter	MALLOC(ip, struct ntnode *, sizeof(struct ntnode), M_NTFSNTNODE,
39618334Speter		M_WAITOK | M_ZERO);
39718334Speter	ddprintf(("ntfs_ntlookup: allocating ntnode: %d: %p\n", ino, ip));
39818334Speter
39918334Speter	/* Generic initialization */
40018334Speter	ip->i_devvp = ntmp->ntm_devvp;
40118334Speter	ip->i_dev = ntmp->ntm_dev;
40218334Speter	ip->i_number = ino;
40318334Speter	ip->i_mp = ntmp;
40418334Speter
40518334Speter	LIST_INIT(&ip->i_fnlist);
40650397Sobrien	VREF(ip->i_devvp);
40718334Speter
40818334Speter	/* init lock and lock the newborn ntnode */
40918334Speter	lockinit(&ip->i_lock, PINOD, "ntnode", 0, LK_EXCLUSIVE);
41018334Speter	mtx_init(&ip->i_interlock, "ntnode interlock", NULL, MTX_DEF);
41118334Speter	ntfs_ntget(ip);
41218334Speter
41318334Speter	ntfs_nthashins(ip);
41418334Speter
41518334Speter	lockmgr(&ntfs_hashlock, LK_RELEASE, NULL, NULL);
41618334Speter
41718334Speter	*ipp = ip;
41818334Speter
41918334Speter	dprintf(("ntfs_ntlookup: ntnode %d: %p, usecount: %d\n",
42018334Speter		ino, ip, ip->i_usecount));
42118334Speter
42218334Speter	return (0);
42318334Speter}
42418334Speter
42518334Speter/*
42618334Speter * Decrement usecount of ntnode and unlock it, if usecount reach zero,
42718334Speter * deallocate ntnode.
42818334Speter *
42950397Sobrien * ntnode should be locked on entry, and unlocked on return.
43050397Sobrien */
43118334Spetervoid
43218334Speterntfs_ntput(ip)
43318334Speter	struct ntnode *ip;
43418334Speter{
43518334Speter	struct ntvattr *vap;
43618334Speter
43718334Speter	dprintf(("ntfs_ntput: rele ntnode %d: %p, usecount: %d\n",
43818334Speter		ip->i_number, ip, ip->i_usecount));
43918334Speter
44018334Speter	mtx_lock(&ip->i_interlock);
44118334Speter	ip->i_usecount--;
44218334Speter
44318334Speter#ifdef DIAGNOSTIC
44418334Speter	if (ip->i_usecount < 0) {
44518334Speter		panic("ntfs_ntput: ino: %d usecount: %d \n",
44618334Speter		      ip->i_number,ip->i_usecount);
44718334Speter	}
44818334Speter#endif
44918334Speter
45018334Speter	if (ip->i_usecount > 0) {
45118334Speter		lockmgr(&ip->i_lock, LK_RELEASE|LK_INTERLOCK, &ip->i_interlock,
45218334Speter		    NULL);
45318334Speter		return;
45418334Speter	}
45518334Speter
45618334Speter	dprintf(("ntfs_ntput: deallocating ntnode: %d\n", ip->i_number));
45750397Sobrien
45818334Speter	if (LIST_FIRST(&ip->i_fnlist))
45918334Speter		panic("ntfs_ntput: ntnode has fnodes\n");
46018334Speter
46118334Speter	ntfs_nthashrem(ip);
46218334Speter
46318334Speter	while ((vap = LIST_FIRST(&ip->i_valist)) != NULL) {
46418334Speter		LIST_REMOVE(vap,va_list);
46518334Speter		ntfs_freentvattr(vap);
46618334Speter	}
46718334Speter	mtx_unlock(&ip->i_interlock);
46818334Speter	mtx_destroy(&ip->i_interlock);
46918334Speter	lockdestroy(&ip->i_lock);
47018334Speter	vrele(ip->i_devvp);
47118334Speter	FREE(ip, M_NTFSNTNODE);
47218334Speter}
47318334Speter
47418334Speter/*
47518334Speter * increment usecount of ntnode
47618334Speter */
47718334Spetervoid
47818334Speterntfs_ntref(ip)
47918334Speter	struct ntnode *ip;
48018334Speter{
48118334Speter	mtx_lock(&ip->i_interlock);
48218334Speter	ip->i_usecount++;
48318334Speter	mtx_unlock(&ip->i_interlock);
48418334Speter
48518334Speter	dprintf(("ntfs_ntref: ino %d, usecount: %d\n",
48618334Speter		ip->i_number, ip->i_usecount));
48718334Speter
48818334Speter}
48918334Speter
49018334Speter/*
49118334Speter * Decrement usecount of ntnode.
49218334Speter */
49318334Spetervoid
49418334Speterntfs_ntrele(ip)
49518334Speter	struct ntnode *ip;
49618334Speter{
49718334Speter	dprintf(("ntfs_ntrele: rele ntnode %d: %p, usecount: %d\n",
49818334Speter		ip->i_number, ip, ip->i_usecount));
49918334Speter
50018334Speter	mtx_lock(&ip->i_interlock);
50118334Speter	ip->i_usecount--;
50218334Speter
50318334Speter	if (ip->i_usecount < 0)
50418334Speter		panic("ntfs_ntrele: ino: %d usecount: %d \n",
50518334Speter		      ip->i_number,ip->i_usecount);
50618334Speter	mtx_unlock(&ip->i_interlock);
50718334Speter}
50818334Speter
50918334Speter/*
51018334Speter * Deallocate all memory allocated for ntvattr
51118334Speter */
51218334Spetervoid
51318334Speterntfs_freentvattr(vap)
51418334Speter	struct ntvattr * vap;
51518334Speter{
51618334Speter	if (vap->va_flag & NTFS_AF_INRUN) {
51718334Speter		if (vap->va_vruncn)
51818334Speter			FREE(vap->va_vruncn, M_NTFSRUN);
51950397Sobrien		if (vap->va_vruncl)
52050397Sobrien			FREE(vap->va_vruncl, M_NTFSRUN);
52150397Sobrien	} else {
52218334Speter		if (vap->va_datap)
52318334Speter			FREE(vap->va_datap, M_NTFSRDATA);
52418334Speter	}
52518334Speter	FREE(vap, M_NTFSNTVATTR);
52618334Speter}
52718334Speter
52818334Speter/*
52918334Speter * Convert disk image of attribute into ntvattr structure,
53018334Speter * runs are expanded also.
53118334Speter */
53218334Speterint
53318334Speterntfs_attrtontvattr(
53418334Speter		   struct ntfsmount * ntmp,
53518334Speter		   struct ntvattr ** rvapp,
53650397Sobrien		   struct attr * rap)
53718334Speter{
53818334Speter	int             error, i;
53918334Speter	struct ntvattr *vap;
54018334Speter
54118334Speter	error = 0;
54218334Speter	*rvapp = NULL;
54318334Speter
54418334Speter	MALLOC(vap, struct ntvattr *, sizeof(struct ntvattr),
54518334Speter		M_NTFSNTVATTR, M_WAITOK | M_ZERO);
54618334Speter	vap->va_ip = NULL;
54718334Speter	vap->va_flag = rap->a_hdr.a_flag;
54818334Speter	vap->va_type = rap->a_hdr.a_type;
54918334Speter	vap->va_compression = rap->a_hdr.a_compression;
55018334Speter	vap->va_index = rap->a_hdr.a_index;
55118334Speter
55218334Speter	ddprintf(("type: 0x%x, index: %d", vap->va_type, vap->va_index));
55318334Speter
55418334Speter	vap->va_namelen = rap->a_hdr.a_namelen;
55518334Speter	if (rap->a_hdr.a_namelen) {
55618334Speter		wchar *unp = (wchar *) ((caddr_t) rap + rap->a_hdr.a_nameoff);
55718334Speter		ddprintf((", name:["));
55818334Speter		for (i = 0; i < vap->va_namelen; i++) {
55918334Speter			vap->va_name[i] = unp[i];
56018334Speter			ddprintf(("%c", vap->va_name[i]));
56118334Speter		}
56218334Speter		ddprintf(("]"));
56318334Speter	}
56418334Speter	if (vap->va_flag & NTFS_AF_INRUN) {
56518334Speter		ddprintf((", nonres."));
56618334Speter		vap->va_datalen = rap->a_nr.a_datalen;
56718334Speter		vap->va_allocated = rap->a_nr.a_allocated;
56818334Speter		vap->va_vcnstart = rap->a_nr.a_vcnstart;
56918334Speter		vap->va_vcnend = rap->a_nr.a_vcnend;
57018334Speter		vap->va_compressalg = rap->a_nr.a_compressalg;
57118334Speter		error = ntfs_runtovrun(&(vap->va_vruncn), &(vap->va_vruncl),
57218334Speter				       &(vap->va_vruncnt),
57318334Speter				       (caddr_t) rap + rap->a_nr.a_dataoff);
57418334Speter	} else {
57518334Speter		vap->va_compressalg = 0;
57618334Speter		ddprintf((", res."));
57718334Speter		vap->va_datalen = rap->a_r.a_datalen;
57818334Speter		vap->va_allocated = rap->a_r.a_datalen;
57918334Speter		vap->va_vcnstart = 0;
58018334Speter		vap->va_vcnend = ntfs_btocn(vap->va_allocated);
58118334Speter		MALLOC(vap->va_datap, caddr_t, vap->va_datalen,
58218334Speter		       M_NTFSRDATA, M_WAITOK);
58318334Speter		memcpy(vap->va_datap, (caddr_t) rap + rap->a_r.a_dataoff,
58418334Speter		       rap->a_r.a_datalen);
58518334Speter	}
58618334Speter	ddprintf((", len: %d", vap->va_datalen));
58718334Speter
58818334Speter	if (error)
58918334Speter		FREE(vap, M_NTFSNTVATTR);
59018334Speter	else
59118334Speter		*rvapp = vap;
59218334Speter
59318334Speter	ddprintf(("\n"));
59418334Speter
59518334Speter	return (error);
59618334Speter}
59718334Speter
59818334Speter/*
59918334Speter * Expand run into more utilizable and more memory eating format.
60018334Speter */
60118334Speterint
60218334Speterntfs_runtovrun(
60318334Speter	       cn_t ** rcnp,
60418334Speter	       cn_t ** rclp,
60518334Speter	       u_long * rcntp,
60618334Speter	       u_int8_t * run)
60718334Speter{
60818334Speter	u_int32_t       off;
60918334Speter	u_int32_t       sz, i;
61018334Speter	cn_t           *cn;
61118334Speter	cn_t           *cl;
61218334Speter	u_long		cnt;
61318334Speter	cn_t		prev;
61418334Speter	cn_t		tmp;
61518334Speter
61618334Speter	off = 0;
61718334Speter	cnt = 0;
61818334Speter	i = 0;
61918334Speter	while (run[off]) {
62018334Speter		off += (run[off] & 0xF) + ((run[off] >> 4) & 0xF) + 1;
62118334Speter		cnt++;
62218334Speter	}
62318334Speter	MALLOC(cn, cn_t *, cnt * sizeof(cn_t), M_NTFSRUN, M_WAITOK);
62418334Speter	MALLOC(cl, cn_t *, cnt * sizeof(cn_t), M_NTFSRUN, M_WAITOK);
62518334Speter
62618334Speter	off = 0;
62718334Speter	cnt = 0;
62818334Speter	prev = 0;
62918334Speter	while (run[off]) {
63018334Speter
63118334Speter		sz = run[off++];
63218334Speter		cl[cnt] = 0;
63318334Speter
63418334Speter		for (i = 0; i < (sz & 0xF); i++)
63518334Speter			cl[cnt] += (u_int32_t) run[off++] << (i << 3);
63618334Speter
63718334Speter		sz >>= 4;
63818334Speter		if (run[off + sz - 1] & 0x80) {
63918334Speter			tmp = ((u_int64_t) - 1) << (sz << 3);
64018334Speter			for (i = 0; i < sz; i++)
64118334Speter				tmp |= (u_int64_t) run[off++] << (i << 3);
64218334Speter		} else {
64318334Speter			tmp = 0;
64418334Speter			for (i = 0; i < sz; i++)
64518334Speter				tmp |= (u_int64_t) run[off++] << (i << 3);
64618334Speter		}
64718334Speter		if (tmp)
64818334Speter			prev = cn[cnt] = prev + tmp;
64918334Speter		else
65018334Speter			cn[cnt] = tmp;
65118334Speter
65218334Speter		cnt++;
65318334Speter	}
65418334Speter	*rcnp = cn;
65518334Speter	*rclp = cl;
65618334Speter	*rcntp = cnt;
65718334Speter	return (0);
65818334Speter}
65918334Speter
66018334Speter/*
66118334Speter * Compare unicode and ascii string case insens.
66218334Speter */
66318334Speterstatic int
66418334Speterntfs_uastricmp(ntmp, ustr, ustrlen, astr, astrlen)
66518334Speter	struct ntfsmount *ntmp;
66618334Speter	const wchar *ustr;
66718334Speter	size_t ustrlen;
66818334Speter	const char *astr;
66918334Speter	size_t astrlen;
67018334Speter{
67118334Speter	int len;
67218334Speter	size_t i, j, mbstrlen = astrlen;
67318334Speter	int res;
67418334Speter	wchar wc;
67518334Speter
67618334Speter	if (ntmp->ntm_ic_l2u) {
67718334Speter		for (i = 0, j = 0; i < ustrlen && j < astrlen; i++, j++) {
67818334Speter			if (j < astrlen -1) {
67918334Speter				wc = (wchar)astr[j]<<8 | (astr[j+1]&0xFF);
68018334Speter				len = 2;
68118334Speter			} else {
68218334Speter				wc = (wchar)astr[j]<<8 & 0xFF00;
68318334Speter				len = 1;
68418334Speter			}
68518334Speter			res = ((int) NTFS_TOUPPER(ustr[i])) -
68618334Speter				((int)NTFS_TOUPPER(NTFS_82U(wc, &len)));
68718334Speter			j += len - 1;
68818334Speter			mbstrlen -= len - 1;
68918334Speter
69018334Speter			if (res)
69118334Speter				return res;
69218334Speter		}
69318334Speter	} else {
69418334Speter		/*
69518334Speter		 * We use NTFS_82U(NTFS_U28(c)) to get rid of unicode
69618334Speter		 * symbols not covered by translation table
69718334Speter		 */
69818334Speter		for (i = 0; i < ustrlen && i < astrlen; i++) {
69918334Speter			res = ((int) NTFS_TOUPPER(NTFS_82U(NTFS_U28(ustr[i]), &len))) -
70018334Speter				((int)NTFS_TOUPPER(NTFS_82U((wchar)astr[i], &len)));
70118334Speter			if (res)
70218334Speter				return res;
70318334Speter		}
70418334Speter	}
70518334Speter	return (ustrlen - mbstrlen);
70618334Speter}
70718334Speter
70818334Speter/*
70918334Speter * Compare unicode and ascii string case sens.
71018334Speter */
71118334Speterstatic int
71218334Speterntfs_uastrcmp(ntmp, ustr, ustrlen, astr, astrlen)
71318334Speter	struct ntfsmount *ntmp;
71418334Speter	const wchar *ustr;
71518334Speter	size_t ustrlen;
71618334Speter	const char *astr;
71718334Speter	size_t astrlen;
71818334Speter{
71918334Speter	char u, l;
72018334Speter	size_t i, j, mbstrlen = astrlen;
72118334Speter	int res;
72218334Speter	wchar wc;
72318334Speter
72418334Speter	for (i = 0, j = 0; (i < ustrlen) && (j < astrlen); i++, j++) {
72518334Speter		res = 0;
72618334Speter		wc = NTFS_U28(ustr[i]);
72718334Speter		u = (char)(wc>>8);
72818334Speter		l = (char)wc;
72918334Speter		if (u != '\0' && j < astrlen -1) {
73018334Speter			res = (int) (u - astr[j++]);
73118334Speter			mbstrlen--;
73218334Speter		}
73318334Speter		res = (res<<8) + (int) (l - astr[j]);
73418334Speter		if (res)
73518334Speter			return res;
73618334Speter	}
73718334Speter	return (ustrlen - mbstrlen);
73818334Speter}
73918334Speter
74018334Speter/*
74118334Speter * Search fnode in ntnode, if not found allocate and preinitialize.
74218334Speter *
74318334Speter * ntnode should be locked on entry.
74418334Speter */
74518334Speterint
74618334Speterntfs_fget(
74718334Speter	struct ntfsmount *ntmp,
74818334Speter	struct ntnode *ip,
74918334Speter	int attrtype,
75050397Sobrien	char *attrname,
75150397Sobrien	struct fnode **fpp)
75218334Speter{
75318334Speter	struct fnode *fp;
75418334Speter
75518334Speter	dprintf(("ntfs_fget: ino: %d, attrtype: 0x%x, attrname: %s\n",
75618334Speter		ip->i_number,attrtype, attrname?attrname:""));
75718334Speter	*fpp = NULL;
75818334Speter	LIST_FOREACH(fp, &ip->i_fnlist, f_fnlist){
75918334Speter		dprintf(("ntfs_fget: fnode: attrtype: %d, attrname: %s\n",
76018334Speter			fp->f_attrtype, fp->f_attrname?fp->f_attrname:""));
76118334Speter
76218334Speter		if ((attrtype == fp->f_attrtype) &&
76318334Speter		    ((!attrname && !fp->f_attrname) ||
76418334Speter		     (attrname && fp->f_attrname &&
76518334Speter		      !strcmp(attrname,fp->f_attrname)))){
76618334Speter			dprintf(("ntfs_fget: found existed: %p\n",fp));
76718334Speter			*fpp = fp;
76818334Speter		}
76918334Speter	}
77018334Speter
77118334Speter	if (*fpp)
77218334Speter		return (0);
77318334Speter
77418334Speter	MALLOC(fp, struct fnode *, sizeof(struct fnode), M_NTFSFNODE,
77518334Speter		M_WAITOK | M_ZERO);
77618334Speter	dprintf(("ntfs_fget: allocating fnode: %p\n",fp));
77718334Speter
77818334Speter	fp->f_ip = ip;
77950397Sobrien	if (attrname) {
78050397Sobrien		fp->f_flag |= FN_AATTRNAME;
78118334Speter		MALLOC(fp->f_attrname, char *, strlen(attrname)+1, M_TEMP, M_WAITOK);
78218334Speter		strcpy(fp->f_attrname, attrname);
78318334Speter	} else
78418334Speter		fp->f_attrname = NULL;
78518334Speter	fp->f_attrtype = attrtype;
78618334Speter
78718334Speter	ntfs_ntref(ip);
78818334Speter
78918334Speter	LIST_INSERT_HEAD(&ip->i_fnlist, fp, f_fnlist);
79018334Speter
79150397Sobrien	*fpp = fp;
79250397Sobrien
79318334Speter	return (0);
79418334Speter}
79518334Speter
79618334Speter/*
79718334Speter * Deallocate fnode, remove it from ntnode's fnode list.
79818334Speter *
79918334Speter * ntnode should be locked.
80018334Speter */
80118334Spetervoid
80218334Speterntfs_frele(
80318334Speter	struct fnode *fp)
80418334Speter{
80518334Speter	struct ntnode *ip = FTONT(fp);
80618334Speter
80718334Speter	dprintf(("ntfs_frele: fnode: %p for %d: %p\n", fp, ip->i_number, ip));
80818334Speter
80918334Speter	dprintf(("ntfs_frele: deallocating fnode\n"));
81018334Speter	LIST_REMOVE(fp,f_fnlist);
81118334Speter	if (fp->f_flag & FN_AATTRNAME)
81218334Speter		FREE(fp->f_attrname, M_TEMP);
81318334Speter	if (fp->f_dirblbuf)
81418334Speter		FREE(fp->f_dirblbuf, M_NTFSDIR);
81518334Speter	FREE(fp, M_NTFSFNODE);
81618334Speter	ntfs_ntrele(ip);
81718334Speter}
81818334Speter
81918334Speter/*
82018334Speter * Lookup attribute name in format: [[:$ATTR_TYPE]:$ATTR_NAME],
82118334Speter * $ATTR_TYPE is searched in attrdefs read from $AttrDefs.
82218334Speter * If $ATTR_TYPE nott specifed, ATTR_A_DATA assumed.
82318334Speter */
82418334Speterstatic int
82518334Speterntfs_ntlookupattr(
82618334Speter		struct ntfsmount * ntmp,
82718334Speter		const char * name,
82818334Speter		int namelen,
82918334Speter		int *attrtype,
83018334Speter		char **attrname)
83118334Speter{
83218334Speter	const char *sys;
83318334Speter	size_t syslen, i;
83418334Speter	struct ntvattrdef *adp;
83518334Speter
83618334Speter	if (namelen == 0)
83718334Speter		return (0);
83818334Speter
83918334Speter	if (name[0] == '$') {
84050397Sobrien		sys = name;
84118334Speter		for (syslen = 0; syslen < namelen; syslen++) {
84218334Speter			if(sys[syslen] == ':') {
84318334Speter				name++;
84418334Speter				namelen--;
84518334Speter				break;
84618334Speter			}
84718334Speter		}
84818334Speter		name += syslen;
84918334Speter		namelen -= syslen;
85018334Speter
85118334Speter		adp = ntmp->ntm_ad;
85218334Speter		for (i = 0; i < ntmp->ntm_adnum; i++, adp++){
85318334Speter			if (syslen != adp->ad_namelen ||
85418334Speter			   strncmp(sys, adp->ad_name, syslen) != 0)
85518334Speter				continue;
85618334Speter
85718334Speter			*attrtype = adp->ad_type;
85818334Speter			goto out;
85918334Speter		}
86018334Speter		return (ENOENT);
86118334Speter	} else
86218334Speter		*attrtype = NTFS_A_DATA;
86318334Speter
86450397Sobrien    out:
86518334Speter	if (namelen) {
86618334Speter		MALLOC((*attrname), char *, namelen, M_TEMP, M_WAITOK);
86718334Speter		memcpy((*attrname), name, namelen);
86818334Speter		(*attrname)[namelen] = '\0';
86918334Speter	}
87018334Speter
87118334Speter	return (0);
87218334Speter}
87318334Speter
87418334Speter/*
87518334Speter * Lookup specifed node for filename, matching cnp,
87618334Speter * return fnode filled.
87718334Speter */
87818334Speterint
87918334Speterntfs_ntlookupfile(
88018334Speter	      struct ntfsmount * ntmp,
88118334Speter	      struct vnode * vp,
88218334Speter	      struct componentname * cnp,
88318334Speter	      struct vnode ** vpp)
88418334Speter{
88518334Speter	struct fnode   *fp = VTOF(vp);
88618334Speter	struct ntnode  *ip = FTONT(fp);
88718334Speter	struct ntvattr *vap;	/* Root attribute */
88818334Speter	cn_t            cn;	/* VCN in current attribute */
88918334Speter	caddr_t         rdbuf;	/* Buffer to read directory's blocks  */
89018334Speter	u_int32_t       blsize;
89118334Speter	u_int32_t       rdsize;	/* Length of data to read from current block */
89218334Speter	struct attr_indexentry *iep;
89350397Sobrien	int             error, res, anamelen, fnamelen;
89418334Speter	const char     *fname,*aname;
89518334Speter	u_int32_t       aoff;
89618334Speter	int attrtype = NTFS_A_DATA;
89718334Speter	char *attrname = NULL;
89818334Speter	struct fnode   *nfp;
89918334Speter	struct vnode   *nvp;
90018334Speter	enum vtype	f_type;
90118334Speter
90218334Speter	error = ntfs_ntget(ip);
90318334Speter	if (error)
90418334Speter		return (error);
90518334Speter
90618334Speter	error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXROOT, "$I30", 0, &vap);
90718334Speter	if (error || (vap->va_flag & NTFS_AF_INRUN))
90818334Speter		return (ENOTDIR);
90918334Speter
91018334Speter	blsize = vap->va_a_iroot->ir_size;
91118334Speter	rdsize = vap->va_datalen;
91218334Speter
91318334Speter	/*
91418334Speter	 * Divide file name into: foofilefoofilefoofile[:attrspec]
91518334Speter	 * Store like this:       fname:fnamelen       [aname:anamelen]
91618334Speter	 */
91718334Speter	fname = cnp->cn_nameptr;
91818334Speter	aname = NULL;
91918334Speter	anamelen = 0;
92018334Speter	for (fnamelen = 0; fnamelen < cnp->cn_namelen; fnamelen++)
92118334Speter		if(fname[fnamelen] == ':') {
92218334Speter			aname = fname + fnamelen + 1;
92318334Speter			anamelen = cnp->cn_namelen - fnamelen - 1;
92418334Speter			dprintf(("ntfs_ntlookupfile: %s (%d), attr: %s (%d)\n",
92518334Speter				fname, fnamelen, aname, anamelen));
92618334Speter			break;
92718334Speter		}
92818334Speter
92950397Sobrien	dprintf(("ntfs_ntlookupfile: blksz: %d, rdsz: %d\n", blsize, rdsize));
93018334Speter
93118334Speter	MALLOC(rdbuf, caddr_t, blsize, M_TEMP, M_WAITOK);
93218334Speter
93318334Speter	error = ntfs_readattr(ntmp, ip, NTFS_A_INDXROOT, "$I30",
93418334Speter			       0, rdsize, rdbuf, NULL);
93518334Speter	if (error)
93618334Speter		goto fail;
93718334Speter
93818334Speter	aoff = sizeof(struct attr_indexroot);
93918334Speter
94018334Speter	do {
94118334Speter		iep = (struct attr_indexentry *) (rdbuf + aoff);
94218334Speter
94318334Speter		for (; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (rdsize > aoff);
94418334Speter			aoff += iep->reclen,
94518334Speter			iep = (struct attr_indexentry *) (rdbuf + aoff))
94618334Speter		{
94718334Speter			ddprintf(("scan: %d, %d\n",
94818334Speter				  (u_int32_t) iep->ie_number,
94918334Speter				  (u_int32_t) iep->ie_fnametype));
95018334Speter
95118334Speter			/* check the name - the case-insensitible check
95218334Speter			 * has to come first, to break from this for loop
95318334Speter			 * if needed, so we can dive correctly */
95418334Speter			res = NTFS_UASTRICMP(iep->ie_fname, iep->ie_fnamelen,
95518334Speter				fname, fnamelen);
95618334Speter			if (res > 0) break;
95718334Speter			if (res < 0) continue;
95818334Speter
95950397Sobrien			if (iep->ie_fnametype == 0 ||
96018334Speter			    !(ntmp->ntm_flag & NTFS_MFLAG_CASEINS))
96118334Speter			{
96218334Speter				res = NTFS_UASTRCMP(iep->ie_fname,
96318334Speter					iep->ie_fnamelen, fname, fnamelen);
96418334Speter				if (res != 0) continue;
96518334Speter			}
96650397Sobrien
96718334Speter			if (aname) {
96850397Sobrien				error = ntfs_ntlookupattr(ntmp,
96918334Speter					aname, anamelen,
97018334Speter					&attrtype, &attrname);
97118334Speter				if (error)
97218334Speter					goto fail;
97318334Speter			}
97418334Speter
97518334Speter			/* Check if we've found ourself */
97618334Speter			if ((iep->ie_number == ip->i_number) &&
97718334Speter			    (attrtype == fp->f_attrtype) &&
97818334Speter			    ((!attrname && !fp->f_attrname) ||
97918334Speter			     (attrname && fp->f_attrname &&
98018334Speter			      !strcmp(attrname, fp->f_attrname))))
98118334Speter			{
98218334Speter				VREF(vp);
98318334Speter				*vpp = vp;
98418334Speter				error = 0;
98518334Speter				goto fail;
98618334Speter			}
98718334Speter
98818334Speter			/* vget node, but don't load it */
98918334Speter			error = ntfs_vgetex(ntmp->ntm_mountp,
99018334Speter				   iep->ie_number, attrtype, attrname,
99118334Speter				   LK_EXCLUSIVE, VG_DONTLOADIN | VG_DONTVALIDFN,
99218334Speter				   curthread, &nvp);
99318334Speter
99418334Speter			/* free the buffer returned by ntfs_ntlookupattr() */
99518334Speter			if (attrname) {
99618334Speter				FREE(attrname, M_TEMP);
99718334Speter				attrname = NULL;
99818334Speter			}
99918334Speter
100018334Speter			if (error)
100118334Speter				goto fail;
100218334Speter
100318334Speter			nfp = VTOF(nvp);
100418334Speter
100518334Speter			if (nfp->f_flag & FN_VALID) {
100618334Speter				*vpp = nvp;
100718334Speter				goto fail;
100818334Speter			}
100918334Speter
101018334Speter			nfp->f_fflag = iep->ie_fflag;
101118334Speter			nfp->f_pnumber = iep->ie_fpnumber;
101218334Speter			nfp->f_times = iep->ie_ftimes;
101318334Speter
101418334Speter			if((nfp->f_fflag & NTFS_FFLAG_DIR) &&
101518334Speter			   (nfp->f_attrtype == NTFS_A_DATA) &&
101618334Speter			   (nfp->f_attrname == NULL))
101718334Speter				f_type = VDIR;
101818334Speter			else
101918334Speter				f_type = VREG;
102018334Speter
102118334Speter			nvp->v_type = f_type;
102218334Speter
102318334Speter			if ((nfp->f_attrtype == NTFS_A_DATA) &&
102418334Speter			    (nfp->f_attrname == NULL))
102518334Speter			{
102650397Sobrien				/* Opening default attribute */
102750397Sobrien				nfp->f_size = iep->ie_fsize;
102818334Speter				nfp->f_allocated = iep->ie_fallocated;
102918334Speter				nfp->f_flag |= FN_PRELOADED;
103018334Speter			} else {
103118334Speter				error = ntfs_filesize(ntmp, nfp,
103250397Sobrien					    &nfp->f_size, &nfp->f_allocated);
103350397Sobrien				if (error) {
103450397Sobrien					vput(nvp);
103550397Sobrien					goto fail;
103650397Sobrien				}
103750397Sobrien			}
103850397Sobrien
103950397Sobrien			nfp->f_flag &= ~FN_VALID;
104050397Sobrien			*vpp = nvp;
104150397Sobrien			goto fail;
104250397Sobrien		}
104350397Sobrien
104450397Sobrien		/* Dive if possible */
104550397Sobrien		if (iep->ie_flag & NTFS_IEFLAG_SUBNODE) {
104650397Sobrien			dprintf(("ntfs_ntlookupfile: diving\n"));
104750397Sobrien
104850397Sobrien			cn = *(cn_t *) (rdbuf + aoff +
104950397Sobrien					iep->reclen - sizeof(cn_t));
105018334Speter			rdsize = blsize;
105118334Speter
105218334Speter			error = ntfs_readattr(ntmp, ip, NTFS_A_INDX, "$I30",
105318334Speter					ntfs_cntob(cn), rdsize, rdbuf, NULL);
105418334Speter			if (error)
105518334Speter				goto fail;
105618334Speter
105718334Speter			error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC,
105818334Speter						rdbuf, rdsize);
105918334Speter			if (error)
106018334Speter				goto fail;
106118334Speter
106218334Speter			aoff = (((struct attr_indexalloc *) rdbuf)->ia_hdrsize +
106318334Speter				0x18);
106418334Speter		} else {
106518334Speter			dprintf(("ntfs_ntlookupfile: nowhere to dive :-(\n"));
106618334Speter			error = ENOENT;
106718334Speter			break;
106818334Speter		}
106918334Speter	} while (1);
107018334Speter
107118334Speter	dprintf(("finish\n"));
107218334Speter
107318334Speterfail:
107418334Speter	if (attrname) FREE(attrname, M_TEMP);
107518334Speter	ntfs_ntvattrrele(vap);
107618334Speter	ntfs_ntput(ip);
107718334Speter	FREE(rdbuf, M_TEMP);
107818334Speter	return (error);
107918334Speter}
108018334Speter
108118334Speter/*
108218334Speter * Check if name type is permitted to show.
108318334Speter */
108418334Speterint
108518334Speterntfs_isnamepermitted(
108618334Speter		     struct ntfsmount * ntmp,
108718334Speter		     struct attr_indexentry * iep)
108818334Speter{
108918334Speter	if (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES)
109018334Speter		return 1;
109118334Speter
109218334Speter	switch (iep->ie_fnametype) {
109318334Speter	case 2:
109418334Speter		ddprintf(("ntfs_isnamepermitted: skiped DOS name\n"));
109518334Speter		return 0;
109618334Speter	case 0: case 1: case 3:
109718334Speter		return 1;
109818334Speter	default:
109918334Speter		printf("ntfs_isnamepermitted: " \
110018334Speter		       "WARNING! Unknown file name type: %d\n",
110118334Speter		       iep->ie_fnametype);
110218334Speter		break;
110318334Speter	}
110450397Sobrien	return 0;
110518334Speter}
110618334Speter
110718334Speter/*
110818334Speter * Read ntfs dir like stream of attr_indexentry, not like btree of them.
110918334Speter * This is done by scaning $BITMAP:$I30 for busy clusters and reading them.
111018334Speter * Ofcouse $INDEX_ROOT:$I30 is read before. Last read values are stored in
111118334Speter * fnode, so we can skip toward record number num almost immediatly.
111218334Speter * Anyway this is rather slow routine. The problem is that we don't know
111318334Speter * how many records are there in $INDEX_ALLOCATION:$I30 block.
111418334Speter */
111518334Speterint
111618334Speterntfs_ntreaddir(
111718334Speter	       struct ntfsmount * ntmp,
111818334Speter	       struct fnode * fp,
111918334Speter	       u_int32_t num,
112018334Speter	       struct attr_indexentry ** riepp)
112118334Speter{
112218334Speter	struct ntnode  *ip = FTONT(fp);
112318334Speter	struct ntvattr *vap = NULL;	/* IndexRoot attribute */
112418334Speter	struct ntvattr *bmvap = NULL;	/* BitMap attribute */
112518334Speter	struct ntvattr *iavap = NULL;	/* IndexAllocation attribute */
112618334Speter	caddr_t         rdbuf;		/* Buffer to read directory's blocks  */
112718334Speter	u_char         *bmp = NULL;	/* Bitmap */
112818334Speter	u_int32_t       blsize;		/* Index allocation size (2048) */
112918334Speter	u_int32_t       rdsize;		/* Length of data to read */
113018334Speter	u_int32_t       attrnum;	/* Current attribute type */
113118334Speter	u_int32_t       cpbl = 1;	/* Clusters per directory block */
113218334Speter	u_int32_t       blnum;
113318334Speter	struct attr_indexentry *iep;
113418334Speter	int             error = ENOENT;
113518334Speter	u_int32_t       aoff, cnum;
113618334Speter
113718334Speter	dprintf(("ntfs_ntreaddir: read ino: %d, num: %d\n", ip->i_number, num));
113818334Speter	error = ntfs_ntget(ip);
113918334Speter	if (error)
114018334Speter		return (error);
114118334Speter
114218334Speter	error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXROOT, "$I30", 0, &vap);
114318334Speter	if (error)
114418334Speter		return (ENOTDIR);
114518334Speter
114618334Speter	if (fp->f_dirblbuf == NULL) {
114718334Speter		fp->f_dirblsz = vap->va_a_iroot->ir_size;
114818334Speter		MALLOC(fp->f_dirblbuf, caddr_t,
114918334Speter		       max(vap->va_datalen,fp->f_dirblsz), M_NTFSDIR, M_WAITOK);
115018334Speter	}
115118334Speter
115218334Speter	blsize = fp->f_dirblsz;
115318334Speter	rdbuf = fp->f_dirblbuf;
115418334Speter
115518334Speter	dprintf(("ntfs_ntreaddir: rdbuf: 0x%p, blsize: %d\n", rdbuf, blsize));
115618334Speter
115718334Speter	if (vap->va_a_iroot->ir_flag & NTFS_IRFLAG_INDXALLOC) {
115818334Speter		error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXBITMAP, "$I30",
115918334Speter					0, &bmvap);
116018334Speter		if (error) {
116118334Speter			error = ENOTDIR;
116218334Speter			goto fail;
116318334Speter		}
116418334Speter		MALLOC(bmp, u_char *, bmvap->va_datalen, M_TEMP, M_WAITOK);
116518334Speter		error = ntfs_readattr(ntmp, ip, NTFS_A_INDXBITMAP, "$I30", 0,
116618334Speter				       bmvap->va_datalen, bmp, NULL);
116718334Speter		if (error)
116818334Speter			goto fail;
116918334Speter
117050397Sobrien		error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDX, "$I30",
117118334Speter					0, &iavap);
117218334Speter		if (error) {
117350397Sobrien			error = ENOTDIR;
117450397Sobrien			goto fail;
117550397Sobrien		}
117650397Sobrien		cpbl = ntfs_btocn(blsize + ntfs_cntob(1) - 1);
117718334Speter		dprintf(("ntfs_ntreaddir: indexalloc: %d, cpbl: %d\n",
117818334Speter			 iavap->va_datalen, cpbl));
117918334Speter	} else {
118018334Speter		dprintf(("ntfs_ntreadidir: w/o BitMap and IndexAllocation\n"));
118118334Speter		iavap = bmvap = NULL;
118218334Speter		bmp = NULL;
118318334Speter	}
118418334Speter
118518334Speter	/* Try use previous values */
118618334Speter	if ((fp->f_lastdnum < num) && (fp->f_lastdnum != 0)) {
118718334Speter		attrnum = fp->f_lastdattr;
118818334Speter		aoff = fp->f_lastdoff;
118918334Speter		blnum = fp->f_lastdblnum;
119018334Speter		cnum = fp->f_lastdnum;
119118334Speter	} else {
119218334Speter		attrnum = NTFS_A_INDXROOT;
119318334Speter		aoff = sizeof(struct attr_indexroot);
119418334Speter		blnum = 0;
119518334Speter		cnum = 0;
119618334Speter	}
119718334Speter
119818334Speter	do {
119918334Speter		dprintf(("ntfs_ntreaddir: scan: 0x%x, %d, %d, %d, %d\n",
120018334Speter			 attrnum, (u_int32_t) blnum, cnum, num, aoff));
120118334Speter		rdsize = (attrnum == NTFS_A_INDXROOT) ? vap->va_datalen : blsize;
120218334Speter		error = ntfs_readattr(ntmp, ip, attrnum, "$I30",
120318334Speter				ntfs_cntob(blnum * cpbl), rdsize, rdbuf, NULL);
120418334Speter		if (error)
120518334Speter			goto fail;
120618334Speter
120718334Speter		if (attrnum == NTFS_A_INDX) {
120818334Speter			error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC,
120918334Speter						rdbuf, rdsize);
121018334Speter			if (error)
121118334Speter				goto fail;
121250397Sobrien		}
121350397Sobrien		if (aoff == 0)
121450397Sobrien			aoff = (attrnum == NTFS_A_INDX) ?
121550397Sobrien				(0x18 + ((struct attr_indexalloc *) rdbuf)->ia_hdrsize) :
121650397Sobrien				sizeof(struct attr_indexroot);
121750397Sobrien
121818334Speter		iep = (struct attr_indexentry *) (rdbuf + aoff);
121918334Speter		for (; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (rdsize > aoff);
122018334Speter			aoff += iep->reclen,
122118334Speter			iep = (struct attr_indexentry *) (rdbuf + aoff))
122218334Speter		{
122318334Speter			if (!ntfs_isnamepermitted(ntmp, iep)) continue;
122418334Speter
122518334Speter			if (cnum >= num) {
122618334Speter				fp->f_lastdnum = cnum;
122718334Speter				fp->f_lastdoff = aoff;
122818334Speter				fp->f_lastdblnum = blnum;
122918334Speter				fp->f_lastdattr = attrnum;
123018334Speter
123118334Speter				*riepp = iep;
123218334Speter
123318334Speter				error = 0;
123418334Speter				goto fail;
123518334Speter			}
123618334Speter			cnum++;
123718334Speter		}
123818334Speter
123918334Speter		if (iavap) {
124018334Speter			if (attrnum == NTFS_A_INDXROOT)
124118334Speter				blnum = 0;
124218334Speter			else
124318334Speter				blnum++;
124418334Speter
124518334Speter			while (ntfs_cntob(blnum * cpbl) < iavap->va_datalen) {
124618334Speter				if (bmp[blnum >> 3] & (1 << (blnum & 3)))
124718334Speter					break;
124818334Speter				blnum++;
124918334Speter			}
125018334Speter
125118334Speter			attrnum = NTFS_A_INDX;
125218334Speter			aoff = 0;
125318334Speter			if (ntfs_cntob(blnum * cpbl) >= iavap->va_datalen)
125418334Speter				break;
125518334Speter			dprintf(("ntfs_ntreaddir: blnum: %d\n", (u_int32_t) blnum));
125618334Speter		}
125718334Speter	} while (iavap);
125818334Speter
125918334Speter	*riepp = NULL;
126018334Speter	fp->f_lastdnum = 0;
126150397Sobrien
126250397Sobrienfail:
126350397Sobrien	if (vap)
126418334Speter		ntfs_ntvattrrele(vap);
126518334Speter	if (bmvap)
126618334Speter		ntfs_ntvattrrele(bmvap);
126718334Speter	if (iavap)
126818334Speter		ntfs_ntvattrrele(iavap);
126918334Speter	if (bmp)
127018334Speter		FREE(bmp, M_TEMP);
127118334Speter	ntfs_ntput(ip);
127218334Speter	return (error);
127318334Speter}
127418334Speter
127518334Speter/*
127618334Speter * Convert NTFS times that are in 100 ns units and begins from
127718334Speter * 1601 Jan 1 into unix times.
127818334Speter */
127918334Speterstruct timespec
128018334Speterntfs_nttimetounix(
128118334Speter		  u_int64_t nt)
128218334Speter{
128318334Speter	struct timespec t;
128418334Speter
128518334Speter	/* WindowNT times are in 100 ns and from 1601 Jan 1 */
128618334Speter	t.tv_nsec = (nt % (1000 * 1000 * 10)) * 100;
128718334Speter	t.tv_sec = nt / (1000 * 1000 * 10) -
128818334Speter		369LL * 365LL * 24LL * 60LL * 60LL -
128918334Speter		89LL * 1LL * 24LL * 60LL * 60LL;
129018334Speter	return (t);
129118334Speter}
129218334Speter
129318334Speter/*
129418334Speter * Get file times from NTFS_A_NAME attribute.
129518334Speter */
129618334Speterint
129718334Speterntfs_times(
129818334Speter	   struct ntfsmount * ntmp,
129918334Speter	   struct ntnode * ip,
130018334Speter	   ntfs_times_t * tm)
130118334Speter{
130218334Speter	struct ntvattr *vap;
130318334Speter	int             error;
130418334Speter
130518334Speter	dprintf(("ntfs_times: ino: %d...\n", ip->i_number));
130618334Speter
130718334Speter	error = ntfs_ntget(ip);
130818334Speter	if (error)
130918334Speter		return (error);
131018334Speter
131118334Speter	error = ntfs_ntvattrget(ntmp, ip, NTFS_A_NAME, NULL, 0, &vap);
131218334Speter	if (error) {
131318334Speter		ntfs_ntput(ip);
131418334Speter		return (error);
131518334Speter	}
131618334Speter	*tm = vap->va_a_name->n_times;
131718334Speter	ntfs_ntvattrrele(vap);
131818334Speter	ntfs_ntput(ip);
131918334Speter
132018334Speter	return (0);
132118334Speter}
132218334Speter
132318334Speter/*
132418334Speter * Get file sizes from corresponding attribute.
132518334Speter *
132618334Speter * ntnode under fnode should be locked.
132718334Speter */
132818334Speterint
132918334Speterntfs_filesize(
133018334Speter	      struct ntfsmount * ntmp,
133118334Speter	      struct fnode * fp,
133218334Speter	      u_int64_t * size,
133318334Speter	      u_int64_t * bytes)
133418334Speter{
133518334Speter	struct ntvattr *vap;
133618334Speter	struct ntnode *ip = FTONT(fp);
133718334Speter	u_int64_t       sz, bn;
133818334Speter	int             error;
133918334Speter
134018334Speter	dprintf(("ntfs_filesize: ino: %d\n", ip->i_number));
134118334Speter
134218334Speter	error = ntfs_ntvattrget(ntmp, ip,
134318334Speter		fp->f_attrtype, fp->f_attrname, 0, &vap);
134418334Speter	if (error)
134518334Speter		return (error);
134618334Speter
134718334Speter	bn = vap->va_allocated;
134818334Speter	sz = vap->va_datalen;
134918334Speter
135050397Sobrien	dprintf(("ntfs_filesize: %d bytes (%d bytes allocated)\n",
135118334Speter		(u_int32_t) sz, (u_int32_t) bn));
135218334Speter
135318334Speter	if (size)
135418334Speter		*size = sz;
135518334Speter	if (bytes)
135618334Speter		*bytes = bn;
135718334Speter
135818334Speter	ntfs_ntvattrrele(vap);
135918334Speter
136018334Speter	return (0);
136118334Speter}
136218334Speter
136318334Speter/*
136418334Speter * This is one of write routine.
136518334Speter */
136618334Speterint
136718334Speterntfs_writeattr_plain(
136818334Speter	struct ntfsmount * ntmp,
136918334Speter	struct ntnode * ip,
137018334Speter	u_int32_t attrnum,
137118334Speter	char *attrname,
137218334Speter	off_t roff,
137318334Speter	size_t rsize,
137418334Speter	void *rdata,
137518334Speter	size_t * initp,
137618334Speter	struct uio *uio)
137718334Speter{
137818334Speter	size_t          init;
137918334Speter	int             error = 0;
138018334Speter	off_t           off = roff, left = rsize, towrite;
138118334Speter	caddr_t         data = rdata;
138218334Speter	struct ntvattr *vap;
138318334Speter	*initp = 0;
138418334Speter
138518334Speter	while (left) {
138618334Speter		error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname,
138718334Speter					ntfs_btocn(off), &vap);
138818334Speter		if (error)
138918334Speter			return (error);
139018334Speter		towrite = min(left, ntfs_cntob(vap->va_vcnend + 1) - off);
139118334Speter		ddprintf(("ntfs_writeattr_plain: o: %d, s: %d (%d - %d)\n",
139218334Speter			 (u_int32_t) off, (u_int32_t) towrite,
139318334Speter			 (u_int32_t) vap->va_vcnstart,
139418334Speter			 (u_int32_t) vap->va_vcnend));
139518334Speter		error = ntfs_writentvattr_plain(ntmp, ip, vap,
139618334Speter					 off - ntfs_cntob(vap->va_vcnstart),
139718334Speter					 towrite, data, &init, uio);
139818334Speter		if (error) {
139918334Speter			printf("ntfs_writeattr_plain: " \
140018334Speter			       "ntfs_writentvattr_plain failed: o: %d, s: %d\n",
140118334Speter			       (u_int32_t) off, (u_int32_t) towrite);
140218334Speter			printf("ntfs_writeattr_plain: attrib: %d - %d\n",
140318334Speter			       (u_int32_t) vap->va_vcnstart,
140418334Speter			       (u_int32_t) vap->va_vcnend);
140518334Speter			ntfs_ntvattrrele(vap);
140618334Speter			break;
140718334Speter		}
140818334Speter		ntfs_ntvattrrele(vap);
140918334Speter		left -= towrite;
141018334Speter		off += towrite;
141118334Speter		data = data + towrite;
141218334Speter		*initp += init;
141318334Speter	}
141418334Speter
141518334Speter	return (error);
141618334Speter}
141718334Speter
141818334Speter/*
141918334Speter * This is one of write routine.
142018334Speter *
142118334Speter * ntnode should be locked.
142218334Speter */
142318334Speterint
142418334Speterntfs_writentvattr_plain(
142518334Speter	struct ntfsmount * ntmp,
142618334Speter	struct ntnode * ip,
142718334Speter	struct ntvattr * vap,
142818334Speter	off_t roff,
142918334Speter	size_t rsize,
143018334Speter	void *rdata,
143118334Speter	size_t * initp,
143218334Speter	struct uio *uio)
143318334Speter{
143418334Speter	int             error = 0;
143518334Speter	int             off;
143618334Speter	int             cnt;
143718334Speter	cn_t            ccn, ccl, cn, left, cl;
143818334Speter	caddr_t         data = rdata;
143918334Speter	struct buf     *bp;
144018334Speter	size_t          tocopy;
144118334Speter
144218334Speter	*initp = 0;
144318334Speter
144418334Speter	if ((vap->va_flag & NTFS_AF_INRUN) == 0) {
144518334Speter		printf("ntfs_writevattr_plain: CAN'T WRITE RES. ATTRIBUTE\n");
144618334Speter		return ENOTTY;
144718334Speter	}
144818334Speter
144918334Speter	ddprintf(("ntfs_writentvattr_plain: data in run: %ld chains\n",
145018334Speter		 vap->va_vruncnt));
145118334Speter
145218334Speter	off = roff;
145318334Speter	left = rsize;
145418334Speter	ccl = 0;
145518334Speter	ccn = 0;
145618334Speter	cnt = 0;
145718334Speter	for (; left && (cnt < vap->va_vruncnt); cnt++) {
145818334Speter		ccn = vap->va_vruncn[cnt];
145918334Speter		ccl = vap->va_vruncl[cnt];
146018334Speter
146118334Speter		ddprintf(("ntfs_writentvattr_plain: " \
146218334Speter			 "left %d, cn: 0x%x, cl: %d, off: %d\n", \
146318334Speter			 (u_int32_t) left, (u_int32_t) ccn, \
146418334Speter			 (u_int32_t) ccl, (u_int32_t) off));
146518334Speter
146618334Speter		if (ntfs_cntob(ccl) < off) {
146718334Speter			off -= ntfs_cntob(ccl);
146818334Speter			cnt++;
146918334Speter			continue;
147018334Speter		}
147118334Speter		if (!ccn && ip->i_number != NTFS_BOOTINO)
147218334Speter			continue; /* XXX */
147318334Speter
147418334Speter		ccl -= ntfs_btocn(off);
147518334Speter		cn = ccn + ntfs_btocn(off);
147618334Speter		off = ntfs_btocnoff(off);
147718334Speter
147818334Speter		while (left && ccl) {
147918334Speter			/*
148018334Speter			 * Always read and write single clusters at a time -
148118334Speter			 * we need to avoid requesting differently-sized
148218334Speter			 * blocks at the same disk offsets to avoid
148318334Speter			 * confusing the buffer cache.
148450397Sobrien			 */
148550397Sobrien			tocopy = min(left, ntfs_cntob(1) - off);
148650397Sobrien			cl = ntfs_btocl(tocopy + off);
148750397Sobrien			KASSERT(cl == 1 && tocopy <= ntfs_cntob(1),
148850397Sobrien			    ("single cluster limit mistake"));
148950397Sobrien			ddprintf(("ntfs_writentvattr_plain: write: " \
149050397Sobrien				"cn: 0x%x cl: %d, off: %d len: %d, left: %d\n",
149150397Sobrien				(u_int32_t) cn, (u_int32_t) cl,
149218334Speter				(u_int32_t) off, (u_int32_t) tocopy,
149318334Speter				(u_int32_t) left));
149418334Speter			if ((off == 0) && (tocopy == ntfs_cntob(cl)))
149518334Speter			{
149618334Speter				bp = getblk(ntmp->ntm_devvp, ntfs_cntobn(cn),
149718334Speter					    ntfs_cntob(cl), 0, 0, 0);
149818334Speter				clrbuf(bp);
149918334Speter			} else {
150018334Speter				error = bread(ntmp->ntm_devvp, ntfs_cntobn(cn),
150118334Speter					      ntfs_cntob(cl), NOCRED, &bp);
150218334Speter				if (error) {
150350397Sobrien					brelse(bp);
150450397Sobrien					return (error);
150518334Speter				}
150618334Speter			}
150718334Speter			if (uio)
150818334Speter				uiomove(bp->b_data + off, tocopy, uio);
150918334Speter			else
151018334Speter				memcpy(bp->b_data + off, data, tocopy);
151118334Speter			bawrite(bp);
151218334Speter			data = data + tocopy;
151318334Speter			*initp += tocopy;
151418334Speter			off = 0;
151518334Speter			left -= tocopy;
151618334Speter			cn += cl;
151718334Speter			ccl -= cl;
151818334Speter		}
151918334Speter	}
152018334Speter
152118334Speter	if (left) {
152218334Speter		printf("ntfs_writentvattr_plain: POSSIBLE RUN ERROR\n");
152318334Speter		error = EINVAL;
152418334Speter	}
152518334Speter
152618334Speter	return (error);
152718334Speter}
152818334Speter
152918334Speter/*
153018334Speter * This is one of read routines.
153118334Speter *
153218334Speter * ntnode should be locked.
153318334Speter */
153418334Speterint
153518334Speterntfs_readntvattr_plain(
153618334Speter	struct ntfsmount * ntmp,
153718334Speter	struct ntnode * ip,
153818334Speter	struct ntvattr * vap,
153918334Speter	off_t roff,
154018334Speter	size_t rsize,
154118334Speter	void *rdata,
154218334Speter	size_t * initp,
154318334Speter	struct uio *uio)
154418334Speter{
154518334Speter	int             error = 0;
154618334Speter	int             off;
154718334Speter
154818334Speter	*initp = 0;
154918334Speter	if (vap->va_flag & NTFS_AF_INRUN) {
155018334Speter		int             cnt;
155118334Speter		cn_t            ccn, ccl, cn, left, cl;
155218334Speter		caddr_t         data = rdata;
155318334Speter		struct buf     *bp;
155418334Speter		size_t          tocopy;
155518334Speter
155618334Speter		ddprintf(("ntfs_readntvattr_plain: data in run: %ld chains\n",
155718334Speter			 vap->va_vruncnt));
155818334Speter
155918334Speter		off = roff;
156018334Speter		left = rsize;
156118334Speter		ccl = 0;
156218334Speter		ccn = 0;
156318334Speter		cnt = 0;
156418334Speter		while (left && (cnt < vap->va_vruncnt)) {
156518334Speter			ccn = vap->va_vruncn[cnt];
156618334Speter			ccl = vap->va_vruncl[cnt];
156718334Speter
156818334Speter			ddprintf(("ntfs_readntvattr_plain: " \
156918334Speter				 "left %d, cn: 0x%x, cl: %d, off: %d\n", \
157018334Speter				 (u_int32_t) left, (u_int32_t) ccn, \
157118334Speter				 (u_int32_t) ccl, (u_int32_t) off));
157218334Speter
157318334Speter			if (ntfs_cntob(ccl) < off) {
157418334Speter				off -= ntfs_cntob(ccl);
157518334Speter				cnt++;
157618334Speter				continue;
157718334Speter			}
157818334Speter			if (ccn || ip->i_number == NTFS_BOOTINO) {
157918334Speter				ccl -= ntfs_btocn(off);
158018334Speter				cn = ccn + ntfs_btocn(off);
158118334Speter				off = ntfs_btocnoff(off);
158218334Speter
158318334Speter				while (left && ccl) {
158418334Speter					/*
158518334Speter					 * Always read single clusters at a
158618334Speter					 * time - we need to avoid reading
158718334Speter					 * differently-sized blocks at the
158818334Speter					 * same disk offsets to avoid
158918334Speter					 * confusing the buffer cache.
159018334Speter					 */
159118334Speter					tocopy = min(left,
159218334Speter					    ntfs_cntob(1) - off);
159318334Speter					cl = ntfs_btocl(tocopy + off);
159418334Speter					KASSERT(cl == 1 &&
159550397Sobrien					    tocopy <= ntfs_cntob(1),
159650397Sobrien					    ("single cluster limit mistake"));
159718334Speter
159818334Speter					ddprintf(("ntfs_readntvattr_plain: " \
159918334Speter						"read: cn: 0x%x cl: %d, " \
160018334Speter						"off: %d len: %d, left: %d\n",
160118334Speter						(u_int32_t) cn,
160218334Speter						(u_int32_t) cl,
160318334Speter						(u_int32_t) off,
160418334Speter						(u_int32_t) tocopy,
160518334Speter						(u_int32_t) left));
160618334Speter					error = bread(ntmp->ntm_devvp,
160718334Speter						      ntfs_cntobn(cn),
160818334Speter						      ntfs_cntob(cl),
160918334Speter						      NOCRED, &bp);
161018334Speter					if (error) {
161118334Speter						brelse(bp);
161218334Speter						return (error);
161318334Speter					}
161418334Speter					if (uio) {
161518334Speter						uiomove(bp->b_data + off,
161618334Speter							tocopy, uio);
161718334Speter					} else {
161818334Speter						memcpy(data, bp->b_data + off,
161918334Speter							tocopy);
162018334Speter					}
162118334Speter					brelse(bp);
162218334Speter					data = data + tocopy;
162318334Speter					*initp += tocopy;
162418334Speter					off = 0;
162518334Speter					left -= tocopy;
162618334Speter					cn += cl;
162718334Speter					ccl -= cl;
162818334Speter				}
162918334Speter			} else {
163018334Speter				tocopy = min(left, ntfs_cntob(ccl) - off);
163118334Speter				ddprintf(("ntfs_readntvattr_plain: "
163218334Speter					"hole: ccn: 0x%x ccl: %d, off: %d, " \
163318334Speter					" len: %d, left: %d\n",
163418334Speter					(u_int32_t) ccn, (u_int32_t) ccl,
163518334Speter					(u_int32_t) off, (u_int32_t) tocopy,
163618334Speter					(u_int32_t) left));
163718334Speter				left -= tocopy;
163818334Speter				off = 0;
163918334Speter				if (uio) {
164018334Speter					size_t remains = tocopy;
164118334Speter					for(; remains; remains--)
164218334Speter						uiomove("", 1, uio);
164318334Speter				} else
164418334Speter					bzero(data, tocopy);
164518334Speter				data = data + tocopy;
164618334Speter			}
164718334Speter			cnt++;
164818334Speter		}
164918334Speter		if (left) {
165018334Speter			printf("ntfs_readntvattr_plain: POSSIBLE RUN ERROR\n");
165118334Speter			error = E2BIG;
165218334Speter		}
165318334Speter	} else {
165418334Speter		ddprintf(("ntfs_readnvattr_plain: data is in mft record\n"));
165518334Speter		if (uio)
165618334Speter			uiomove(vap->va_datap + roff, rsize, uio);
165718334Speter		else
165818334Speter			memcpy(rdata, vap->va_datap + roff, rsize);
165918334Speter		*initp += rsize;
166018334Speter	}
166118334Speter
166218334Speter	return (error);
166318334Speter}
166418334Speter
166518334Speter/*
166618334Speter * This is one of read routines.
166718334Speter */
166818334Speterint
166918334Speterntfs_readattr_plain(
167018334Speter	struct ntfsmount * ntmp,
167118334Speter	struct ntnode * ip,
167218334Speter	u_int32_t attrnum,
167318334Speter	char *attrname,
167418334Speter	off_t roff,
167518334Speter	size_t rsize,
167618334Speter	void *rdata,
167718334Speter	size_t * initp,
167818334Speter	struct uio *uio)
167918334Speter{
168018334Speter	size_t          init;
168118334Speter	int             error = 0;
168218334Speter	off_t           off = roff, left = rsize, toread;
168318334Speter	caddr_t         data = rdata;
168418334Speter	struct ntvattr *vap;
168518334Speter	*initp = 0;
168618334Speter
168718334Speter	while (left) {
168818334Speter		error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname,
168918334Speter					ntfs_btocn(off), &vap);
169018334Speter		if (error)
169118334Speter			return (error);
169218334Speter		toread = min(left, ntfs_cntob(vap->va_vcnend + 1) - off);
169318334Speter		ddprintf(("ntfs_readattr_plain: o: %d, s: %d (%d - %d)\n",
169418334Speter			 (u_int32_t) off, (u_int32_t) toread,
169518334Speter			 (u_int32_t) vap->va_vcnstart,
169618334Speter			 (u_int32_t) vap->va_vcnend));
169718334Speter		error = ntfs_readntvattr_plain(ntmp, ip, vap,
169818334Speter					 off - ntfs_cntob(vap->va_vcnstart),
169918334Speter					 toread, data, &init, uio);
170018334Speter		if (error) {
170118334Speter			printf("ntfs_readattr_plain: " \
170218334Speter			       "ntfs_readntvattr_plain failed: o: %d, s: %d\n",
170318334Speter			       (u_int32_t) off, (u_int32_t) toread);
170418334Speter			printf("ntfs_readattr_plain: attrib: %d - %d\n",
170518334Speter			       (u_int32_t) vap->va_vcnstart,
170618334Speter			       (u_int32_t) vap->va_vcnend);
170718334Speter			ntfs_ntvattrrele(vap);
170818334Speter			break;
170918334Speter		}
171018334Speter		ntfs_ntvattrrele(vap);
171118334Speter		left -= toread;
171218334Speter		off += toread;
171318334Speter		data = data + toread;
171418334Speter		*initp += init;
171518334Speter	}
171618334Speter
171718334Speter	return (error);
171818334Speter}
171918334Speter
172018334Speter/*
172118334Speter * This is one of read routines.
172218334Speter */
172318334Speterint
172418334Speterntfs_readattr(
172518334Speter	struct ntfsmount * ntmp,
172618334Speter	struct ntnode * ip,
172718334Speter	u_int32_t attrnum,
172818334Speter	char *attrname,
172918334Speter	off_t roff,
173018334Speter	size_t rsize,
173118334Speter	void *rdata,
173218334Speter	struct uio *uio)
173318334Speter{
173418334Speter	int             error = 0;
173518334Speter	struct ntvattr *vap;
173618334Speter	size_t          init;
173718334Speter
173818334Speter	ddprintf(("ntfs_readattr: reading %d: 0x%x, from %d size %d bytes\n",
173918334Speter	       ip->i_number, attrnum, (u_int32_t) roff, (u_int32_t) rsize));
174018334Speter
174118334Speter	error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname, 0, &vap);
174218334Speter	if (error)
174318334Speter		return (error);
174418334Speter
174518334Speter	if ((roff > vap->va_datalen) ||
174618334Speter	    (roff + rsize > vap->va_datalen)) {
174718334Speter		ddprintf(("ntfs_readattr: offset too big\n"));
174818334Speter		ntfs_ntvattrrele(vap);
174918334Speter		return (E2BIG);
175018334Speter	}
175118334Speter	if (vap->va_compression && vap->va_compressalg) {
175218334Speter		u_int8_t       *cup;
175318334Speter		u_int8_t       *uup;
175418334Speter		off_t           off = roff, left = rsize, tocopy;
175518334Speter		caddr_t         data = rdata;
175618334Speter		cn_t            cn;
175718334Speter
175818334Speter		ddprintf(("ntfs_ntreadattr: compression: %d\n",
175918334Speter			 vap->va_compressalg));
176018334Speter
176118334Speter		MALLOC(cup, u_int8_t *, ntfs_cntob(NTFS_COMPUNIT_CL),
176218334Speter		       M_NTFSDECOMP, M_WAITOK);
176318334Speter		MALLOC(uup, u_int8_t *, ntfs_cntob(NTFS_COMPUNIT_CL),
176450397Sobrien		       M_NTFSDECOMP, M_WAITOK);
176518334Speter
176618334Speter		cn = (ntfs_btocn(roff)) & (~(NTFS_COMPUNIT_CL - 1));
176718334Speter		off = roff - ntfs_cntob(cn);
176818334Speter
176918334Speter		while (left) {
177018334Speter			error = ntfs_readattr_plain(ntmp, ip, attrnum,
177118334Speter						  attrname, ntfs_cntob(cn),
177218334Speter					          ntfs_cntob(NTFS_COMPUNIT_CL),
177318334Speter						  cup, &init, NULL);
177418334Speter			if (error)
177518334Speter				break;
177618334Speter
177718334Speter			tocopy = min(left, ntfs_cntob(NTFS_COMPUNIT_CL) - off);
177818334Speter
177918334Speter			if (init == ntfs_cntob(NTFS_COMPUNIT_CL)) {
178018334Speter				if (uio)
178118334Speter					uiomove(cup + off, tocopy, uio);
178218334Speter				else
178318334Speter					memcpy(data, cup + off, tocopy);
178418334Speter			} else if (init == 0) {
178518334Speter				if (uio) {
178618334Speter					size_t remains = tocopy;
178718334Speter					for(; remains; remains--)
178818334Speter						uiomove("", 1, uio);
178918334Speter				}
179018334Speter				else
179118334Speter					bzero(data, tocopy);
179218334Speter			} else {
179318334Speter				error = ntfs_uncompunit(ntmp, uup, cup);
179418334Speter				if (error)
179518334Speter					break;
179618334Speter				if (uio)
179718334Speter					uiomove(uup + off, tocopy, uio);
179818334Speter				else
179918334Speter					memcpy(data, uup + off, tocopy);
180018334Speter			}
180118334Speter
180218334Speter			left -= tocopy;
180318334Speter			data = data + tocopy;
180418334Speter			off += tocopy - ntfs_cntob(NTFS_COMPUNIT_CL);
180518334Speter			cn += NTFS_COMPUNIT_CL;
180618334Speter		}
180718334Speter
180818334Speter		FREE(uup, M_NTFSDECOMP);
180918334Speter		FREE(cup, M_NTFSDECOMP);
181018334Speter	} else
181118334Speter		error = ntfs_readattr_plain(ntmp, ip, attrnum, attrname,
181218334Speter					     roff, rsize, rdata, &init, uio);
181318334Speter	ntfs_ntvattrrele(vap);
181418334Speter	return (error);
181518334Speter}
181618334Speter
181718334Speter#if UNUSED_CODE
181818334Speterint
181918334Speterntfs_parserun(
182018334Speter	      cn_t * cn,
182118334Speter	      cn_t * cl,
182218334Speter	      u_int8_t * run,
182318334Speter	      u_long len,
182418334Speter	      u_long *off)
182518334Speter{
182618334Speter	u_int8_t        sz;
182718334Speter	int             i;
182818334Speter
182918334Speter	if (NULL == run) {
183018334Speter		printf("ntfs_parsetun: run == NULL\n");
183118334Speter		return (EINVAL);
183218334Speter	}
183318334Speter	sz = run[(*off)++];
183418334Speter	if (0 == sz) {
183518334Speter		printf("ntfs_parserun: trying to go out of run\n");
183618334Speter		return (E2BIG);
183718334Speter	}
183818334Speter	*cl = 0;
183918334Speter	if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) {
184018334Speter		printf("ntfs_parserun: " \
184118334Speter		       "bad run: length too big: sz: 0x%02x (%ld < %ld + sz)\n",
184218334Speter		       sz, len, *off);
184318334Speter		return (EINVAL);
184418334Speter	}
184518334Speter	for (i = 0; i < (sz & 0xF); i++)
184618334Speter		*cl += (u_int32_t) run[(*off)++] << (i << 3);
184718334Speter
184818334Speter	sz >>= 4;
184918334Speter	if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) {
185018334Speter		printf("ntfs_parserun: " \
185118334Speter		       "bad run: length too big: sz: 0x%02x (%ld < %ld + sz)\n",
185218334Speter		       sz, len, *off);
185318334Speter		return (EINVAL);
185418334Speter	}
185518334Speter	for (i = 0; i < (sz & 0xF); i++)
185618334Speter		*cn += (u_int32_t) run[(*off)++] << (i << 3);
185718334Speter
185818334Speter	return (0);
185918334Speter}
186018334Speter#endif
186118334Speter
186218334Speter/*
186318334Speter * Process fixup routine on given buffer.
186418334Speter */
186518334Speterint
186618334Speterntfs_procfixups(
186718334Speter		struct ntfsmount * ntmp,
186818334Speter		u_int32_t magic,
186918334Speter		caddr_t buf,
187018334Speter		size_t len)
187118334Speter{
187218334Speter	struct fixuphdr *fhp = (struct fixuphdr *) buf;
187318334Speter	int             i;
187418334Speter	u_int16_t       fixup;
187518334Speter	u_int16_t      *fxp;
187618334Speter	u_int16_t      *cfxp;
187718334Speter
187818334Speter	if (fhp->fh_magic != magic) {
187918334Speter		printf("ntfs_procfixups: magic doesn't match: %08x != %08x\n",
188018334Speter		       fhp->fh_magic, magic);
188118334Speter		return (EINVAL);
188218334Speter	}
188318334Speter	if ((fhp->fh_fnum - 1) * ntmp->ntm_bps != len) {
188418334Speter		printf("ntfs_procfixups: " \
188518334Speter		       "bad fixups number: %d for %ld bytes block\n",
188618334Speter		       fhp->fh_fnum, (long)len);	/* XXX printf kludge */
188718334Speter		return (EINVAL);
188818334Speter	}
188918334Speter	if (fhp->fh_foff >= ntmp->ntm_spc * ntmp->ntm_mftrecsz * ntmp->ntm_bps) {
189018334Speter		printf("ntfs_procfixups: invalid offset: %x", fhp->fh_foff);
189118334Speter		return (EINVAL);
189218334Speter	}
189318334Speter	fxp = (u_int16_t *) (buf + fhp->fh_foff);
189418334Speter	cfxp = (u_int16_t *) (buf + ntmp->ntm_bps - 2);
189518334Speter	fixup = *fxp++;
189618334Speter	for (i = 1; i < fhp->fh_fnum; i++, fxp++) {
189718334Speter		if (*cfxp != fixup) {
189818334Speter			printf("ntfs_procfixups: fixup %d doesn't match\n", i);
189918334Speter			return (EINVAL);
190018334Speter		}
190118334Speter		*cfxp = *fxp;
190218334Speter		((caddr_t) cfxp) += ntmp->ntm_bps;
190318334Speter	}
190418334Speter	return (0);
190518334Speter}
190618334Speter
190718334Speter#if UNUSED_CODE
190818334Speterint
190918334Speterntfs_runtocn(
191018334Speter	     cn_t * cn,
191118334Speter	     struct ntfsmount * ntmp,
191218334Speter	     u_int8_t * run,
191318334Speter	     u_long len,
191418334Speter	     cn_t vcn)
191518334Speter{
191618334Speter	cn_t            ccn = 0;
191718334Speter	cn_t            ccl = 0;
191818334Speter	u_long          off = 0;
191918334Speter	int             error = 0;
192018334Speter
192118334Speter#if NTFS_DEBUG
192218334Speter	int             i;
192318334Speter	printf("ntfs_runtocn: run: 0x%p, %ld bytes, vcn:%ld\n",
192418334Speter		run, len, (u_long) vcn);
192518334Speter	printf("ntfs_runtocn: run: ");
192618334Speter	for (i = 0; i < len; i++)
192718334Speter		printf("0x%02x ", run[i]);
192818334Speter	printf("\n");
192918334Speter#endif
193018334Speter
193118334Speter	if (NULL == run) {
193218334Speter		printf("ntfs_runtocn: run == NULL\n");
193318334Speter		return (EINVAL);
193418334Speter	}
193518334Speter	do {
193618334Speter		if (run[off] == 0) {
193718334Speter			printf("ntfs_runtocn: vcn too big\n");
193818334Speter			return (E2BIG);
193918334Speter		}
194018334Speter		vcn -= ccl;
194118334Speter		error = ntfs_parserun(&ccn, &ccl, run, len, &off);
194218334Speter		if (error) {
194318334Speter			printf("ntfs_runtocn: ntfs_parserun failed\n");
194418334Speter			return (error);
194518334Speter		}
194618334Speter	} while (ccl <= vcn);
194718334Speter	*cn = ccn + vcn;
194818334Speter	return (0);
194918334Speter}
195018334Speter#endif
195118334Speter
195218334Speter/*
195318334Speter * this initializes toupper table & dependant variables to be ready for
195418334Speter * later work
195518334Speter */
195618334Spetervoid
195718334Speterntfs_toupper_init()
195818334Speter{
195918334Speter	ntfs_toupper_tab = (wchar *) NULL;
196018334Speter	lockinit(&ntfs_toupper_lock, PVFS, "ntfs_toupper", 0, 0);
196118334Speter	ntfs_toupper_usecount = 0;
196218334Speter}
196318334Speter
196418334Spetervoid
196518334Speterntfs_toupper_destroy(void)
196618334Speter{
196718334Speter
196818334Speter	lockdestroy(&ntfs_toupper_lock);
196918334Speter}
197018334Speter
197118334Speter/*
197218334Speter * if the ntfs_toupper_tab[] is filled already, just raise use count;
197318334Speter * otherwise read the data from the filesystem we are currently mounting
197418334Speter */
197518334Speterint
197618334Speterntfs_toupper_use(mp, ntmp)
197718334Speter	struct mount *mp;
197818334Speter	struct ntfsmount *ntmp;
197918334Speter{
198018334Speter	int error = 0;
198118334Speter	struct vnode *vp;
198218334Speter
198318334Speter	/* get exclusive access */
198418334Speter	lockmgr(&ntfs_toupper_lock, LK_EXCLUSIVE, NULL, NULL);
198518334Speter
198618334Speter	/* only read the translation data from a file if it hasn't been
198718334Speter	 * read already */
198818334Speter	if (ntfs_toupper_tab)
198918334Speter		goto out;
199018334Speter
199118334Speter	/*
199218334Speter	 * Read in Unicode lowercase -> uppercase translation file.
199318334Speter	 * XXX for now, just the first 256 entries are used anyway,
199418334Speter	 * so don't bother reading more
199518334Speter	 */
199618334Speter	MALLOC(ntfs_toupper_tab, wchar *, 65536 * sizeof(wchar),
199718334Speter		M_NTFSRDATA, M_WAITOK);
199818334Speter
199918334Speter	if ((error = VFS_VGET(mp, NTFS_UPCASEINO, LK_EXCLUSIVE, &vp)))
200018334Speter		goto out;
200118334Speter	error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL,
200218334Speter			0, 65536*sizeof(wchar), (char *) ntfs_toupper_tab, NULL);
200318334Speter	vput(vp);
200418334Speter
200518334Speter    out:
200618334Speter	ntfs_toupper_usecount++;
200718334Speter	lockmgr(&ntfs_toupper_lock, LK_RELEASE, NULL, NULL);
200818334Speter	return (error);
200918334Speter}
201018334Speter
201118334Speter/*
201218334Speter * lower the use count and if it reaches zero, free the memory
201318334Speter * tied by toupper table
201418334Speter */
201518334Spetervoid
201618334Speterntfs_toupper_unuse()
201718334Speter{
201818334Speter	/* get exclusive access */
201918334Speter	lockmgr(&ntfs_toupper_lock, LK_EXCLUSIVE, NULL, NULL);
202018334Speter
202118334Speter	ntfs_toupper_usecount--;
202218334Speter	if (ntfs_toupper_usecount == 0) {
202318334Speter		FREE(ntfs_toupper_tab, M_NTFSRDATA);
202418334Speter		ntfs_toupper_tab = NULL;
202518334Speter	}
202618334Speter#ifdef DIAGNOSTIC
202718334Speter	else if (ntfs_toupper_usecount < 0) {
202818334Speter		panic("ntfs_toupper_unuse(): use count negative: %d\n",
202918334Speter			ntfs_toupper_usecount);
203018334Speter	}
203118334Speter#endif
203218334Speter
203318334Speter	/* release the lock */
203418334Speter	lockmgr(&ntfs_toupper_lock, LK_RELEASE, NULL, NULL);
203518334Speter}
203618334Speter
203718334Speterint
203818334Speterntfs_u28_init(
203918334Speter	struct ntfsmount *ntmp,
204018334Speter	wchar *u2w,
204118334Speter	char *cs_local,
204218334Speter	char *cs_ntfs)
204318334Speter{
204418334Speter	char ** u28;
204518334Speter	int i, j, h, l;
204618334Speter
204718334Speter	if (ntfs_iconv && cs_local) {
204818334Speter		ntfs_iconv->open(cs_local, cs_ntfs, &ntmp->ntm_ic_u2l);
204918334Speter		return (0);
205018334Speter	}
205118334Speter
205218334Speter	MALLOC(u28, char **, 256 * sizeof(char*), M_TEMP, M_WAITOK | M_ZERO);
205318334Speter
205418334Speter	for (i=0; i<256; i++) {
205518334Speter		h = (u2w[i] >> 8) & 0xFF;
205618334Speter		l = (u2w[i]) &0xFF;
205718334Speter
205818334Speter		if (u28[h] == NULL) {
205918334Speter			MALLOC(u28[h], char *, 256 * sizeof(char), M_TEMP, M_WAITOK);
206018334Speter			for (j=0; j<256; j++)
206118334Speter				u28[h][j] = '_';
206218334Speter		}
206318334Speter
206418334Speter		u28[h][l] = i & 0xFF;
206518334Speter	}
206618334Speter
206718334Speter	ntmp->ntm_u28 = u28;
206818334Speter
206918334Speter	return (0);
207018334Speter}
207118334Speter
207218334Speterint
207318334Speterntfs_u28_uninit(struct ntfsmount *ntmp)
207418334Speter{
207518334Speter	char ** u28;
207618334Speter	int i;
207718334Speter
207818334Speter	if (ntmp->ntm_u28 == NULL) {
207918334Speter		if (ntfs_iconv && ntmp->ntm_ic_u2l) {
208018334Speter			ntfs_iconv->close(ntmp->ntm_ic_u2l);
208118334Speter		}
208218334Speter		return (0);
208318334Speter	}
208418334Speter
208518334Speter	u28 = ntmp->ntm_u28;
208618334Speter
208718334Speter	for (i=0; i<256; i++)
208818334Speter		if (u28[i] != NULL)
208918334Speter			FREE(u28[i], M_TEMP);
209018334Speter
209118334Speter	FREE(u28, M_TEMP);
209218334Speter
209318334Speter	return (0);
209418334Speter}
209518334Speter
209618334Speterint
209718334Speterntfs_82u_init(
209818334Speter	struct ntfsmount *ntmp,
209918334Speter	char *cs_local,
210018334Speter	char *cs_ntfs)
210118334Speter{
210218334Speter	wchar * _82u;
210318334Speter	int i;
210418334Speter
210518334Speter	if (ntfs_iconv && cs_local) {
210618334Speter		ntfs_iconv->open(cs_ntfs, cs_local, &ntmp->ntm_ic_l2u);
210718334Speter		return (0);
210818334Speter	}
210918334Speter
211018334Speter	MALLOC(_82u, wchar *, 256 * sizeof(wchar), M_TEMP, M_WAITOK);
211118334Speter
211218334Speter	for (i=0; i<256; i++)
211318334Speter			_82u[i] = i;
211418334Speter
211518334Speter	ntmp->ntm_82u = _82u;
211618334Speter
211718334Speter	return (0);
211818334Speter}
211918334Speter
212018334Speterint
212118334Speterntfs_82u_uninit(struct ntfsmount *ntmp)
212218334Speter{
212318334Speter
212418334Speter	if (ntmp->ntm_82u == NULL) {
212518334Speter		if (ntfs_iconv && ntmp->ntm_ic_l2u) {
212618334Speter			ntfs_iconv->close(ntmp->ntm_ic_l2u);
212718334Speter		}
212818334Speter		return (0);
212918334Speter	}
213018334Speter
213118334Speter	FREE(ntmp->ntm_82u, M_TEMP);
213218334Speter	return (0);
213318334Speter}
213418334Speter
213518334Speter/*
213618334Speter * maps the Unicode char to 8bit equivalent
213718334Speter * XXX currently only gets lower 8bit from the Unicode char
213818334Speter * and substitutes a '_' for it if the result would be '\0';
213950397Sobrien * something better has to be definitely though out
214018334Speter */
214118334Speterwchar
214218334Speterntfs_u28(
214318334Speter	struct ntfsmount *ntmp,
214418334Speter	wchar wc)
214518334Speter{
214618334Speter	char *p, *outp, inbuf[3], outbuf[3];
214718334Speter	size_t ilen, olen;
214818334Speter
214918334Speter	if (ntfs_iconv && ntmp->ntm_ic_u2l) {
215018334Speter		ilen = olen = 2;
215118334Speter
215218334Speter		inbuf[0] = (char)(wc>>8);
215318334Speter		inbuf[1] = (char)wc;
215418334Speter		inbuf[2] = '\0';
215518334Speter		p = inbuf;
215618334Speter		outp = outbuf;
215718334Speter		ntfs_iconv->convchr(ntmp->ntm_ic_u2l, (const char **)&p, &ilen,
215818334Speter				    &outp, &olen);
215918334Speter		if (olen == 1) {
216018334Speter			return ((wchar)(outbuf[0]));
216118334Speter		} else if (olen == 0) {
216218334Speter			return ((wchar)((outbuf[0]<<8) | (outbuf[1]&0xFF)));
216318334Speter		}
216418334Speter		return ('?');
216518334Speter	}
216618334Speter
216718334Speter	p = ntmp->ntm_u28[(wc>>8)&0xFF];
216818334Speter	if (p == NULL)
216918334Speter		return ('_');
217018334Speter	return (p[wc&0xFF]);
217150397Sobrien}
217218334Speter
217318334Speterwchar
217418334Speterntfs_82u(
217518334Speter	struct ntfsmount *ntmp,
217618334Speter	wchar wc,
217718334Speter	int *len)
217818334Speter{
217918334Speter	char *p, *outp, inbuf[3], outbuf[3];
218018334Speter	wchar uc;
218118334Speter	size_t ilen, olen;
218218334Speter
218318334Speter	if (ntfs_iconv && ntmp->ntm_ic_l2u) {
218418334Speter		ilen = (size_t)*len;
218518334Speter		olen = 2;
218618334Speter
218718334Speter		inbuf[0] = (char)(wc>>8);
218818334Speter		inbuf[1] = (char)wc;
218918334Speter		inbuf[2] = '\0';
219018334Speter		p = inbuf;
219118334Speter		outp = outbuf;
219218334Speter		ntfs_iconv->convchr(ntmp->ntm_ic_l2u, (const char **)&p, &ilen,
219318334Speter				    &outp, &olen);
219418334Speter		*len -= (int)ilen;
219518334Speter		uc = (wchar)((outbuf[0]<<8) | (outbuf[1]&0xFF));
219618334Speter
219718334Speter		return (uc);
219818334Speter	}
219950397Sobrien
220018334Speter	if (ntmp->ntm_82u != NULL)
220118334Speter		return (ntmp->ntm_82u[wc&0xFF]);
220218334Speter
220318334Speter	return ('?');
220418334Speter}
220518334Speter
220618334Speter