xref: /netbsd-src/sys/fs/ntfs/ntfs_subr.c (revision 618809e52267ddd672aaf19a3750b93e7206601b)
1*618809e5Shannken /*	$NetBSD: ntfs_subr.c,v 1.64 2021/05/13 08:57:29 hannken Exp $	*/
29accf4dfSjdolecek 
39accf4dfSjdolecek /*-
49accf4dfSjdolecek  * Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org)
59accf4dfSjdolecek  * All rights reserved.
69accf4dfSjdolecek  *
79accf4dfSjdolecek  * Redistribution and use in source and binary forms, with or without
89accf4dfSjdolecek  * modification, are permitted provided that the following conditions
99accf4dfSjdolecek  * are met:
109accf4dfSjdolecek  * 1. Redistributions of source code must retain the above copyright
119accf4dfSjdolecek  *    notice, this list of conditions and the following disclaimer.
129accf4dfSjdolecek  * 2. Redistributions in binary form must reproduce the above copyright
139accf4dfSjdolecek  *    notice, this list of conditions and the following disclaimer in the
149accf4dfSjdolecek  *    documentation and/or other materials provided with the distribution.
159accf4dfSjdolecek  *
169accf4dfSjdolecek  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
179accf4dfSjdolecek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
189accf4dfSjdolecek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
199accf4dfSjdolecek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
209accf4dfSjdolecek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
219accf4dfSjdolecek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
229accf4dfSjdolecek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
239accf4dfSjdolecek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
249accf4dfSjdolecek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
259accf4dfSjdolecek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
269accf4dfSjdolecek  * SUCH DAMAGE.
279accf4dfSjdolecek  *
289accf4dfSjdolecek  *	Id: ntfs_subr.c,v 1.4 1999/05/12 09:43:01 semenu Exp
299accf4dfSjdolecek  */
309accf4dfSjdolecek 
319accf4dfSjdolecek #include <sys/cdefs.h>
32*618809e5Shannken __KERNEL_RCSID(0, "$NetBSD: ntfs_subr.c,v 1.64 2021/05/13 08:57:29 hannken Exp $");
339accf4dfSjdolecek 
349accf4dfSjdolecek #include <sys/param.h>
359accf4dfSjdolecek #include <sys/systm.h>
369accf4dfSjdolecek #include <sys/namei.h>
379accf4dfSjdolecek #include <sys/proc.h>
389accf4dfSjdolecek #include <sys/kernel.h>
399accf4dfSjdolecek #include <sys/vnode.h>
409accf4dfSjdolecek #include <sys/mount.h>
419accf4dfSjdolecek #include <sys/buf.h>
429accf4dfSjdolecek #include <sys/file.h>
439accf4dfSjdolecek #include <sys/malloc.h>
449accf4dfSjdolecek #include <sys/lock.h>
45fc9422c9Selad #include <sys/kauth.h>
469accf4dfSjdolecek 
479accf4dfSjdolecek #include <miscfs/specfs/specdev.h>
489accf4dfSjdolecek 
499accf4dfSjdolecek #include <fs/ntfs/ntfs.h>
509accf4dfSjdolecek #include <fs/ntfs/ntfsmount.h>
519accf4dfSjdolecek #include <fs/ntfs/ntfs_inode.h>
529accf4dfSjdolecek #include <fs/ntfs/ntfs_vfsops.h>
539accf4dfSjdolecek #include <fs/ntfs/ntfs_subr.h>
549accf4dfSjdolecek #include <fs/ntfs/ntfs_compr.h>
559accf4dfSjdolecek #include <fs/ntfs/ntfs_ihash.h>
569accf4dfSjdolecek 
57f229ea7fSchristos #ifdef NTFS_DEBUG
589accf4dfSjdolecek int ntfs_debug = NTFS_DEBUG;
599accf4dfSjdolecek #endif
609accf4dfSjdolecek 
61835b0326Spooka MALLOC_JUSTDEFINE(M_NTFSNTVATTR, "NTFS vattr",
62835b0326Spooka     "NTFS file attribute information");
63835b0326Spooka MALLOC_JUSTDEFINE(M_NTFSRDATA, "NTFS res data", "NTFS resident data");
64835b0326Spooka MALLOC_JUSTDEFINE(M_NTFSRUN, "NTFS vrun", "NTFS vrun storage");
65835b0326Spooka MALLOC_JUSTDEFINE(M_NTFSDECOMP, "NTFS decomp", "NTFS decompression temporary");
669accf4dfSjdolecek 
679accf4dfSjdolecek /* Local struct used in ntfs_ntlookupfile() */
689accf4dfSjdolecek struct ntfs_lookup_ctx {
699accf4dfSjdolecek 	u_int32_t	aoff;
709accf4dfSjdolecek 	u_int32_t	rdsize;
719accf4dfSjdolecek 	cn_t		cn;
729accf4dfSjdolecek 	struct ntfs_lookup_ctx *prev;
739accf4dfSjdolecek };
749accf4dfSjdolecek 
7508fcacf4Sxtraeme static int ntfs_ntlookupattr(struct ntfsmount *, const char *, int,
7608fcacf4Sxtraeme 	int *, char **);
7708fcacf4Sxtraeme static int ntfs_findvattr(struct ntfsmount *, struct ntnode *,
7808fcacf4Sxtraeme 	struct ntvattr **, struct ntvattr **, u_int32_t, const char *,
7908fcacf4Sxtraeme 	size_t, cn_t);
8008fcacf4Sxtraeme static int ntfs_uastricmp(struct ntfsmount *, const wchar *, size_t,
8108fcacf4Sxtraeme 	const char *, size_t);
8208fcacf4Sxtraeme static int ntfs_uastrcmp(struct ntfsmount *, const wchar *, size_t,
8308fcacf4Sxtraeme 	const char *, size_t);
849accf4dfSjdolecek 
859accf4dfSjdolecek /* table for mapping Unicode chars into uppercase; it's filled upon first
869accf4dfSjdolecek  * ntfs mount, freed upon last ntfs umount */
879accf4dfSjdolecek static wchar *ntfs_toupper_tab;
889accf4dfSjdolecek #define NTFS_U28(ch)		((((ch) & 0xE0) == 0) ? '_' : (ch) & 0xFF)
899accf4dfSjdolecek #define NTFS_TOUPPER(ch)	(ntfs_toupper_tab[(unsigned char)(ch)])
909abeea58Sad static kmutex_t ntfs_toupper_lock;
919accf4dfSjdolecek static signed int ntfs_toupper_usecount;
929accf4dfSjdolecek 
939accf4dfSjdolecek /* support macro for ntfs_ntvattrget() */
949accf4dfSjdolecek #define NTFS_AALPCMP(aalp,type,name,namelen) (				\
959accf4dfSjdolecek   (aalp->al_type == type) && (aalp->al_namelen == namelen) &&		\
969accf4dfSjdolecek   !ntfs_uastrcmp(ntmp, aalp->al_name,aalp->al_namelen,name,namelen) )
979accf4dfSjdolecek 
989accf4dfSjdolecek int
ntfs_ntvattrrele(struct ntvattr * vap)99454af1c0Sdsl ntfs_ntvattrrele(struct ntvattr *vap)
1009accf4dfSjdolecek {
101fd460520Schristos 	dprintf(("%s: ino: %llu, type: 0x%x\n", __func__,
102f229ea7fSchristos 	    (unsigned long long)vap->va_ip->i_number, vap->va_type));
1039accf4dfSjdolecek 	ntfs_ntrele(vap->va_ip);
1049accf4dfSjdolecek 	return (0);
1059accf4dfSjdolecek }
1069accf4dfSjdolecek 
1079accf4dfSjdolecek /*
1089accf4dfSjdolecek  * find the attribute in the ntnode
1099accf4dfSjdolecek  */
1109accf4dfSjdolecek static int
ntfs_findvattr(struct ntfsmount * ntmp,struct ntnode * ip,struct ntvattr ** lvapp,struct ntvattr ** vapp,u_int32_t type,const char * name,size_t namelen,cn_t vcn)1116387e674Smaxv ntfs_findvattr(struct ntfsmount *ntmp, struct ntnode *ip, struct ntvattr **lvapp,
1126387e674Smaxv     struct ntvattr **vapp, u_int32_t type, const char *name, size_t namelen,
1136387e674Smaxv     cn_t vcn)
1149accf4dfSjdolecek {
1159accf4dfSjdolecek 	int error;
1169accf4dfSjdolecek 	struct ntvattr *vap;
1179accf4dfSjdolecek 
1189accf4dfSjdolecek 	if ((ip->i_flag & IN_LOADED) == 0) {
119fd460520Schristos 		dprintf(("%s: node not loaded, ino: %llu\n", __func__,
120f229ea7fSchristos 		    (unsigned long long)ip->i_number));
1219accf4dfSjdolecek 		error = ntfs_loadntnode(ntmp,ip);
1229accf4dfSjdolecek 		if (error) {
123fd460520Schristos 			printf("%s: FAILED TO LOAD INO: %llu\n", __func__,
124758a209dSchristos 			    (unsigned long long)ip->i_number);
1259accf4dfSjdolecek 			return (error);
1269accf4dfSjdolecek 		}
1279accf4dfSjdolecek 	}
1289accf4dfSjdolecek 
1299accf4dfSjdolecek 	*lvapp = NULL;
1309accf4dfSjdolecek 	*vapp = NULL;
1319accf4dfSjdolecek 	for (vap = ip->i_valist.lh_first; vap; vap = vap->va_list.le_next) {
132fd460520Schristos 		ddprintf(("%s: type: 0x%x, vcn: %qu - %qu\n", __func__,
133f229ea7fSchristos 		    vap->va_type, (long long) vap->va_vcnstart,
134aa112c89Schristos 		    (long long) vap->va_vcnend));
1359accf4dfSjdolecek 		if ((vap->va_type == type) &&
1369accf4dfSjdolecek 		    (vap->va_vcnstart <= vcn) && (vap->va_vcnend >= vcn) &&
1379accf4dfSjdolecek 		    (vap->va_namelen == namelen) &&
1389accf4dfSjdolecek 		    (strncmp(name, vap->va_name, namelen) == 0)) {
1399accf4dfSjdolecek 			*vapp = vap;
1409accf4dfSjdolecek 			ntfs_ntref(vap->va_ip);
1419accf4dfSjdolecek 			return (0);
1429accf4dfSjdolecek 		}
1439accf4dfSjdolecek 		if (vap->va_type == NTFS_A_ATTRLIST)
1449accf4dfSjdolecek 			*lvapp = vap;
1459accf4dfSjdolecek 	}
1469accf4dfSjdolecek 
1479accf4dfSjdolecek 	return (-1);
1489accf4dfSjdolecek }
1499accf4dfSjdolecek 
1509accf4dfSjdolecek /*
1516621e167Swiz  * Search attribute specified in ntnode (load ntnode if necessary).
1526621e167Swiz  * If not found but ATTR_A_ATTRLIST present, read it in and search through.
1539accf4dfSjdolecek  *
1549accf4dfSjdolecek  * ntnode should be locked
1559accf4dfSjdolecek  */
1569accf4dfSjdolecek int
ntfs_ntvattrget(struct ntfsmount * ntmp,struct ntnode * ip,u_int32_t type,const char * name,cn_t vcn,struct ntvattr ** vapp)1576387e674Smaxv ntfs_ntvattrget(struct ntfsmount *ntmp, struct ntnode *ip, u_int32_t type,
1586387e674Smaxv     const char *name, cn_t vcn, struct ntvattr **vapp)
1599accf4dfSjdolecek {
1609accf4dfSjdolecek 	struct ntvattr *lvap = NULL;
1619accf4dfSjdolecek 	struct attr_attrlist *aalp;
1629accf4dfSjdolecek 	struct attr_attrlist *nextaalp;
1639accf4dfSjdolecek 	struct ntnode *newip;
16453524e44Schristos 	void *alpool;
1659accf4dfSjdolecek 	size_t namelen, len;
1669accf4dfSjdolecek 	int error;
1679accf4dfSjdolecek 
1689accf4dfSjdolecek 	*vapp = NULL;
1699accf4dfSjdolecek 
1709accf4dfSjdolecek 	if (name) {
171fd460520Schristos 		dprintf(("%s: ino: %llu, type: 0x%x, name: %s, vcn: %qu\n",
172fd460520Schristos 		    __func__, (unsigned long long)ip->i_number, type, name,
173f229ea7fSchristos 		    (long long)vcn));
1749accf4dfSjdolecek 		namelen = strlen(name);
1759accf4dfSjdolecek 	} else {
176fd460520Schristos 		dprintf(("%s: ino: %llu, type: 0x%x, vcn: %qu\n", __func__,
177f229ea7fSchristos 		    (unsigned long long)ip->i_number, type, (long long)vcn));
1789accf4dfSjdolecek 		name = "";
1799accf4dfSjdolecek 		namelen = 0;
1809accf4dfSjdolecek 	}
1819accf4dfSjdolecek 
1829accf4dfSjdolecek 	error = ntfs_findvattr(ntmp, ip, &lvap, vapp, type, name, namelen, vcn);
1839accf4dfSjdolecek 	if (error >= 0)
1849accf4dfSjdolecek 		return (error);
1859accf4dfSjdolecek 
1869accf4dfSjdolecek 	if (!lvap) {
1870f13b9e4Smaxv 		dprintf(("%s: NON-EXISTENT ATTRIBUTE: "
188fd460520Schristos 		    "ino: %llu, type: 0x%x, name: %s, vcn: %qu\n", __func__,
189f229ea7fSchristos 		    (unsigned long long)ip->i_number, type, name,
190f229ea7fSchristos 		    (long long)vcn));
1919accf4dfSjdolecek 		return (ENOENT);
1929accf4dfSjdolecek 	}
1939accf4dfSjdolecek 	/* Scan $ATTRIBUTE_LIST for requested attribute */
1949accf4dfSjdolecek 	len = lvap->va_datalen;
195fd460520Schristos 	alpool = malloc(len, M_TEMP, M_WAITOK);
1969accf4dfSjdolecek 	error = ntfs_readntvattr_plain(ntmp, ip, lvap, 0, len, alpool, &len,
1979accf4dfSjdolecek 			NULL);
1989accf4dfSjdolecek 	if (error)
1999accf4dfSjdolecek 		goto out;
2009accf4dfSjdolecek 
2019accf4dfSjdolecek 	aalp = (struct attr_attrlist *) alpool;
2029accf4dfSjdolecek 	nextaalp = NULL;
2039accf4dfSjdolecek 
2049accf4dfSjdolecek 	for (; len > 0; aalp = nextaalp) {
2055da80a50Schristos 		KASSERT(aalp != NULL);
206fd460520Schristos 		dprintf(("%s: attrlist: ino: %d, attr: 0x%x, vcn: %qu\n",
207fd460520Schristos 		    __func__, aalp->al_inumber, aalp->al_type,
208aa112c89Schristos 		    (long long) aalp->al_vcnstart));
2099accf4dfSjdolecek 
2109accf4dfSjdolecek 		if (len > aalp->reclen) {
2119accf4dfSjdolecek 			nextaalp = NTFS_NEXTREC(aalp, struct attr_attrlist *);
2129accf4dfSjdolecek 		} else {
2139accf4dfSjdolecek 			nextaalp = NULL;
2149accf4dfSjdolecek 		}
2159accf4dfSjdolecek 		len -= aalp->reclen;
2169accf4dfSjdolecek 
2179accf4dfSjdolecek 		if (!NTFS_AALPCMP(aalp, type, name, namelen) ||
2189accf4dfSjdolecek 		    (nextaalp && (nextaalp->al_vcnstart <= vcn) &&
2199accf4dfSjdolecek 		     NTFS_AALPCMP(nextaalp, type, name, namelen)))
2209accf4dfSjdolecek 			continue;
2219accf4dfSjdolecek 
222fd460520Schristos 		dprintf(("%s: attribute in ino: %d\n", __func__,
2239accf4dfSjdolecek 				 aalp->al_inumber));
2249accf4dfSjdolecek 
2259e220db8Shannken 		error = ntfs_ntlookup(ntmp, aalp->al_inumber, &newip);
2269accf4dfSjdolecek 		if (error) {
2279e220db8Shannken 			printf("%s: can't lookup ino %d"
2289e220db8Shannken 			    " for %" PRId64 " attr %x: error %d\n", __func__,
2299e220db8Shannken 			    aalp->al_inumber, ip->i_number, type, error);
2309accf4dfSjdolecek 			goto out;
2319accf4dfSjdolecek 		}
2329accf4dfSjdolecek 		/* XXX have to lock ntnode */
2339accf4dfSjdolecek 		error = ntfs_findvattr(ntmp, newip, &lvap, vapp,
2349accf4dfSjdolecek 				type, name, namelen, vcn);
2359e220db8Shannken 		ntfs_ntput(newip);
2369accf4dfSjdolecek 		if (error == 0)
2379accf4dfSjdolecek 			goto out;
238fd460520Schristos 		printf("%s: ATTRLIST ERROR.\n", __func__);
2399accf4dfSjdolecek 		break;
2409accf4dfSjdolecek 	}
2419accf4dfSjdolecek 	error = ENOENT;
2429accf4dfSjdolecek 
2430f13b9e4Smaxv 	dprintf(("%s: NON-EXISTENT ATTRIBUTE: ino: %llu, type: 0x%x, "
244fd460520Schristos 	    "name: %.*s, vcn: %qu\n", __func__,
245f229ea7fSchristos 	    (unsigned long long)ip->i_number, type, (int)namelen,
246f229ea7fSchristos 	    name, (long long)vcn));
2479accf4dfSjdolecek out:
2489accf4dfSjdolecek 	free(alpool, M_TEMP);
2499accf4dfSjdolecek 	return (error);
2509accf4dfSjdolecek }
2519accf4dfSjdolecek 
2529accf4dfSjdolecek /*
2539accf4dfSjdolecek  * Read ntnode from disk, make ntvattr list.
2549accf4dfSjdolecek  *
2559accf4dfSjdolecek  * ntnode should be locked
2569accf4dfSjdolecek  */
2579accf4dfSjdolecek int
ntfs_loadntnode(struct ntfsmount * ntmp,struct ntnode * ip)2586387e674Smaxv ntfs_loadntnode(struct ntfsmount *ntmp, struct ntnode *ip)
2599accf4dfSjdolecek {
2609accf4dfSjdolecek 	struct filerec *mfrp;
2619accf4dfSjdolecek 	int error, off;
2629accf4dfSjdolecek 	struct attr *ap;
2639accf4dfSjdolecek 	struct ntvattr *nvap;
2649accf4dfSjdolecek 
265fd460520Schristos 	dprintf(("%s: loading ino: %llu\n", __func__,
266f229ea7fSchristos 	    (unsigned long long)ip->i_number));
2679accf4dfSjdolecek 
268fd460520Schristos 	mfrp = malloc(ntfs_bntob(ntmp->ntm_bpmftrec), M_TEMP, M_WAITOK);
2699accf4dfSjdolecek 
270*618809e5Shannken 	if (ip->i_number < NTFS_SYSNODESNUM ||
271*618809e5Shannken 	    ntmp->ntm_sysvn[NTFS_MFTINO] == NULL) {
2729accf4dfSjdolecek 		struct buf *bp;
2736f8e2ffeShannken 		daddr_t bn;
2746f8e2ffeShannken 		off_t boff;
27562dd7866Shannken 		size_t resid, l;
27662dd7866Shannken 		char *data;
2779accf4dfSjdolecek 
278fd460520Schristos 		dprintf(("%s: read system node\n", __func__));
2799accf4dfSjdolecek 
2806f8e2ffeShannken 		/*
2816f8e2ffeShannken 		 * Make sure we always read full cluster to
2826f8e2ffeShannken 		 * prevent buffer cache inconsistency.
2836f8e2ffeShannken 		 */
2846f8e2ffeShannken 		boff = ntfs_cntob(ntmp->ntm_mftcn) +
2856f8e2ffeShannken 		    ntfs_bntob(ntmp->ntm_bpmftrec) * ip->i_number;
2866f8e2ffeShannken 		bn = ntfs_cntobn(ntfs_btocn(boff));
28762dd7866Shannken 		boff = ntfs_btocnoff(boff);
28862dd7866Shannken 		resid = ntfs_bntob(ntmp->ntm_bpmftrec);
28962dd7866Shannken 		data = (char *)mfrp;
29062dd7866Shannken 		while (resid > 0) {
29162dd7866Shannken 			l = MIN(resid, ntfs_cntob(1) - boff);
2929accf4dfSjdolecek 
2936f8e2ffeShannken 			error = bread(ntmp->ntm_devvp, bn, ntfs_cntob(1),
2946e392401Smaxv 			    0, &bp);
2959accf4dfSjdolecek 			if (error) {
296fd460520Schristos 				printf("%s: BREAD FAILED\n", __func__);
2979accf4dfSjdolecek 				goto out;
2989accf4dfSjdolecek 			}
29962dd7866Shannken 			memcpy(data, (char *)bp->b_data + boff, l);
3007dad9f73Sad 			bqrelse(bp);
30162dd7866Shannken 
30262dd7866Shannken 			bn += ntfs_cntobn(1);
30362dd7866Shannken 			boff = 0;
30462dd7866Shannken 			data += l;
30562dd7866Shannken 			resid -= l;
30662dd7866Shannken 		}
3079accf4dfSjdolecek 	} else {
3089accf4dfSjdolecek 		struct vnode   *vp;
3099accf4dfSjdolecek 
3109accf4dfSjdolecek 		vp = ntmp->ntm_sysvn[NTFS_MFTINO];
3119accf4dfSjdolecek 		error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL,
3129accf4dfSjdolecek 		    ip->i_number * ntfs_bntob(ntmp->ntm_bpmftrec),
3139accf4dfSjdolecek 		    ntfs_bntob(ntmp->ntm_bpmftrec), mfrp, NULL);
3149accf4dfSjdolecek 		if (error) {
315fd460520Schristos 			printf("%s: ntfs_readattr failed\n", __func__);
3169accf4dfSjdolecek 			goto out;
3179accf4dfSjdolecek 		}
3189accf4dfSjdolecek 	}
3199accf4dfSjdolecek 
3209accf4dfSjdolecek 	/* Check if magic and fixups are correct */
32153524e44Schristos 	error = ntfs_procfixups(ntmp, NTFS_FILEMAGIC, (void *)mfrp,
3229accf4dfSjdolecek 				ntfs_bntob(ntmp->ntm_bpmftrec));
3239accf4dfSjdolecek 	if (error) {
324fd460520Schristos 		printf("%s: BAD MFT RECORD %d\n", __func__,
3259accf4dfSjdolecek 		    (u_int32_t) ip->i_number);
3269accf4dfSjdolecek 		goto out;
3279accf4dfSjdolecek 	}
3289accf4dfSjdolecek 
329fd460520Schristos 	dprintf(("%s: load attrs for ino: %llu\n", __func__,
330f229ea7fSchristos 	    (unsigned long long)ip->i_number));
3319accf4dfSjdolecek 	off = mfrp->fr_attroff;
33253524e44Schristos 	ap = (struct attr *) ((char *)mfrp + off);
3339accf4dfSjdolecek 
3349accf4dfSjdolecek 	LIST_INIT(&ip->i_valist);
3359accf4dfSjdolecek 
3369accf4dfSjdolecek 	while (ap->a_hdr.a_type != -1) {
3379accf4dfSjdolecek 		error = ntfs_attrtontvattr(ntmp, &nvap, ap);
3389accf4dfSjdolecek 		if (error)
3399accf4dfSjdolecek 			break;
3409accf4dfSjdolecek 		nvap->va_ip = ip;
3419accf4dfSjdolecek 
3429accf4dfSjdolecek 		LIST_INSERT_HEAD(&ip->i_valist, nvap, va_list);
3439accf4dfSjdolecek 
3449accf4dfSjdolecek 		off += ap->a_hdr.reclen;
34553524e44Schristos 		ap = (struct attr *) ((char *)mfrp + off);
3469accf4dfSjdolecek 	}
3479accf4dfSjdolecek 	if (error) {
348fd460520Schristos 		printf("%s: failed to load attr ino: %llu\n", __func__,
349758a209dSchristos 		    (unsigned long long)ip->i_number);
3509accf4dfSjdolecek 		goto out;
3519accf4dfSjdolecek 	}
3529accf4dfSjdolecek 
3539accf4dfSjdolecek 	ip->i_mainrec = mfrp->fr_mainrec;
3549accf4dfSjdolecek 	ip->i_nlink = mfrp->fr_nlink;
3559accf4dfSjdolecek 	ip->i_frflag = mfrp->fr_flags;
3569accf4dfSjdolecek 
3579accf4dfSjdolecek 	ip->i_flag |= IN_LOADED;
3589accf4dfSjdolecek 
3599accf4dfSjdolecek out:
3609accf4dfSjdolecek 	free(mfrp, M_TEMP);
3619accf4dfSjdolecek 	return (error);
3629accf4dfSjdolecek }
3639accf4dfSjdolecek 
3649accf4dfSjdolecek /*
3659accf4dfSjdolecek  * Routine locks ntnode and increase usecount, just opposite of
3669accf4dfSjdolecek  * ntfs_ntput().
3679accf4dfSjdolecek  */
3689accf4dfSjdolecek int
ntfs_ntget(struct ntnode * ip)369454af1c0Sdsl ntfs_ntget(struct ntnode *ip)
3709accf4dfSjdolecek {
371fd460520Schristos 	dprintf(("%s: get ntnode %llu: %p, usecount: %d\n", __func__,
372f229ea7fSchristos 	    (unsigned long long)ip->i_number, ip, ip->i_usecount));
3739accf4dfSjdolecek 
3744a780c9aSad 	mutex_enter(&ip->i_interlock);
3759accf4dfSjdolecek 	ip->i_usecount++;
376b9839de8Sad 	while (ip->i_busy != 0) {
377b9839de8Sad 		cv_wait(&ip->i_lock, &ip->i_interlock);
378b9839de8Sad 	}
379b9839de8Sad 	ip->i_busy = 1;
380b9839de8Sad 	mutex_exit(&ip->i_interlock);
3819accf4dfSjdolecek 
3829accf4dfSjdolecek 	return 0;
3839accf4dfSjdolecek }
3849accf4dfSjdolecek 
3859accf4dfSjdolecek /*
3869accf4dfSjdolecek  * Routine search ntnode in hash, if found: lock, inc usecount and return.
3879accf4dfSjdolecek  * If not in hash allocate structure for ntnode, prefill it, lock,
3889accf4dfSjdolecek  * inc count and return.
3899accf4dfSjdolecek  *
3909accf4dfSjdolecek  * ntnode returned locked
3919accf4dfSjdolecek  */
3929accf4dfSjdolecek int
ntfs_ntlookup(struct ntfsmount * ntmp,ino_t ino,struct ntnode ** ipp)3936387e674Smaxv ntfs_ntlookup(struct ntfsmount *ntmp, ino_t ino, struct ntnode **ipp)
3949accf4dfSjdolecek {
3959accf4dfSjdolecek 	struct ntnode *ip;
3969accf4dfSjdolecek 
397fd460520Schristos 	dprintf(("%s: looking for ntnode %llu\n", __func__,
398f229ea7fSchristos 	    (unsigned long long)ino));
3999accf4dfSjdolecek 
400f918a311Sad 	if ((*ipp = ntfs_nthashlookup(ntmp->ntm_dev, ino)) != NULL) {
401f918a311Sad 		ntfs_ntget(*ipp);
402fd460520Schristos 		dprintf(("%s: ntnode %llu: %p, usecount: %d\n", __func__,
403f918a311Sad 		    (unsigned long long)ino, *ipp, (*ipp)->i_usecount));
4049accf4dfSjdolecek 		return (0);
4059accf4dfSjdolecek 	}
4069accf4dfSjdolecek 
407fd460520Schristos 	ip = malloc(sizeof(*ip), M_NTFSNTNODE, M_WAITOK|M_ZERO);
408fd460520Schristos 	ddprintf(("%s: allocating ntnode: %llu: %p\n", __func__,
409f229ea7fSchristos 	    (unsigned long long)ino, ip));
4109accf4dfSjdolecek 
4119abeea58Sad 	mutex_enter(&ntfs_hashlock);
412f918a311Sad 	if ((*ipp = ntfs_nthashlookup(ntmp->ntm_dev, ino)) != NULL) {
4139abeea58Sad 		mutex_exit(&ntfs_hashlock);
414f918a311Sad 		ntfs_ntget(*ipp);
4159b87d582Scegger 		free(ip, M_NTFSNTNODE);
416fd460520Schristos 		dprintf(("%s: ntnode %llu: %p, usecount: %d\n", __func__,
417f918a311Sad 		    (unsigned long long)ino, *ipp, (*ipp)->i_usecount));
4189abeea58Sad 		return (0);
4199abeea58Sad 	}
4209abeea58Sad 
4219accf4dfSjdolecek 	/* Generic initialization */
4229accf4dfSjdolecek 	ip->i_devvp = ntmp->ntm_devvp;
4239accf4dfSjdolecek 	ip->i_dev = ntmp->ntm_dev;
4249accf4dfSjdolecek 	ip->i_number = ino;
4259accf4dfSjdolecek 	ip->i_mp = ntmp;
4269accf4dfSjdolecek 
4279accf4dfSjdolecek 	/* init lock and lock the newborn ntnode */
428b9839de8Sad 	cv_init(&ip->i_lock, "ntfslk");
4294a780c9aSad 	mutex_init(&ip->i_interlock, MUTEX_DEFAULT, IPL_NONE);
4309accf4dfSjdolecek 	ntfs_ntget(ip);
4319accf4dfSjdolecek 
4329accf4dfSjdolecek 	ntfs_nthashins(ip);
4339accf4dfSjdolecek 
4349abeea58Sad 	mutex_exit(&ntfs_hashlock);
4359accf4dfSjdolecek 
4369accf4dfSjdolecek 	*ipp = ip;
4379accf4dfSjdolecek 
438fd460520Schristos 	dprintf(("%s: ntnode %llu: %p, usecount: %d\n", __func__,
439f229ea7fSchristos 	    (unsigned long long)ino, ip, ip->i_usecount));
4409accf4dfSjdolecek 
4419accf4dfSjdolecek 	return (0);
4429accf4dfSjdolecek }
4439accf4dfSjdolecek 
4449accf4dfSjdolecek /*
4450f13b9e4Smaxv  * Decrement usecount of ntnode and unlock it, if usecount reaches zero,
4469accf4dfSjdolecek  * deallocate ntnode.
4479accf4dfSjdolecek  *
4489accf4dfSjdolecek  * ntnode should be locked on entry, and unlocked on return.
4499accf4dfSjdolecek  */
4509accf4dfSjdolecek void
ntfs_ntput(struct ntnode * ip)451454af1c0Sdsl ntfs_ntput(struct ntnode *ip)
4529accf4dfSjdolecek {
4539accf4dfSjdolecek 	struct ntvattr *vap;
4549accf4dfSjdolecek 
455fd460520Schristos 	dprintf(("%s: rele ntnode %llu: %p, usecount: %d\n", __func__,
456f229ea7fSchristos 	    (unsigned long long)ip->i_number, ip, ip->i_usecount));
4579accf4dfSjdolecek 
4584a780c9aSad 	mutex_enter(&ip->i_interlock);
4599accf4dfSjdolecek 	ip->i_usecount--;
4609accf4dfSjdolecek 
4619accf4dfSjdolecek #ifdef DIAGNOSTIC
4629accf4dfSjdolecek 	if (ip->i_usecount < 0) {
463758a209dSchristos 		panic("ntfs_ntput: ino: %llu usecount: %d ",
464758a209dSchristos 		    (unsigned long long)ip->i_number, ip->i_usecount);
4659accf4dfSjdolecek 	}
4669accf4dfSjdolecek #endif
4679accf4dfSjdolecek 
468b9839de8Sad 	ip->i_busy = 0;
469b9839de8Sad 	cv_signal(&ip->i_lock);
470b9839de8Sad 	mutex_exit(&ip->i_interlock);
4719accf4dfSjdolecek 
4729accf4dfSjdolecek 	if (ip->i_usecount == 0) {
473fd460520Schristos 		dprintf(("%s: deallocating ntnode: %llu\n", __func__,
474f229ea7fSchristos 		    (unsigned long long)ip->i_number));
4759accf4dfSjdolecek 
4769accf4dfSjdolecek 		ntfs_nthashrem(ip);
4779accf4dfSjdolecek 
4789accf4dfSjdolecek 		while (ip->i_valist.lh_first != NULL) {
4799accf4dfSjdolecek 			vap = ip->i_valist.lh_first;
4809accf4dfSjdolecek 			LIST_REMOVE(vap,va_list);
4819accf4dfSjdolecek 			ntfs_freentvattr(vap);
4829accf4dfSjdolecek 		}
4834a780c9aSad 		mutex_destroy(&ip->i_interlock);
484b9839de8Sad 		cv_destroy(&ip->i_lock);
4859b87d582Scegger 		free(ip, M_NTFSNTNODE);
4869accf4dfSjdolecek 	}
4879accf4dfSjdolecek }
4889accf4dfSjdolecek 
4899accf4dfSjdolecek /*
4909accf4dfSjdolecek  * increment usecount of ntnode
4919accf4dfSjdolecek  */
4929accf4dfSjdolecek void
ntfs_ntref(struct ntnode * ip)493454af1c0Sdsl ntfs_ntref(struct ntnode *ip)
4949accf4dfSjdolecek {
4954a780c9aSad 	mutex_enter(&ip->i_interlock);
4969accf4dfSjdolecek 	ip->i_usecount++;
4974a780c9aSad 	mutex_exit(&ip->i_interlock);
4989accf4dfSjdolecek 
499fd460520Schristos 	dprintf(("%s: ino %llu, usecount: %d\n", __func__,
500f229ea7fSchristos 	    (unsigned long long)ip->i_number, ip->i_usecount));
5019accf4dfSjdolecek }
5029accf4dfSjdolecek 
5039accf4dfSjdolecek /*
5049accf4dfSjdolecek  * Decrement usecount of ntnode.
5059accf4dfSjdolecek  */
5069accf4dfSjdolecek void
ntfs_ntrele(struct ntnode * ip)507454af1c0Sdsl ntfs_ntrele(struct ntnode *ip)
5089accf4dfSjdolecek {
509fd460520Schristos 	dprintf(("%s: rele ntnode %llu: %p, usecount: %d\n", __func__,
510f229ea7fSchristos 	    (unsigned long long)ip->i_number, ip, ip->i_usecount));
5119accf4dfSjdolecek 
5124a780c9aSad 	mutex_enter(&ip->i_interlock);
5139accf4dfSjdolecek 	ip->i_usecount--;
5149accf4dfSjdolecek 
5159accf4dfSjdolecek 	if (ip->i_usecount < 0)
516fd460520Schristos 		panic("%s: ino: %llu usecount: %d ", __func__,
517758a209dSchristos 		    (unsigned long long)ip->i_number, ip->i_usecount);
5184a780c9aSad 	mutex_exit(&ip->i_interlock);
5199accf4dfSjdolecek }
5209accf4dfSjdolecek 
5219accf4dfSjdolecek /*
5229accf4dfSjdolecek  * Deallocate all memory allocated for ntvattr
5239accf4dfSjdolecek  */
5249accf4dfSjdolecek void
ntfs_freentvattr(struct ntvattr * vap)525454af1c0Sdsl ntfs_freentvattr(struct ntvattr *vap)
5269accf4dfSjdolecek {
5279accf4dfSjdolecek 	if (vap->va_flag & NTFS_AF_INRUN) {
5289accf4dfSjdolecek 		if (vap->va_vruncn)
5299accf4dfSjdolecek 			free(vap->va_vruncn, M_NTFSRUN);
5309accf4dfSjdolecek 		if (vap->va_vruncl)
5319accf4dfSjdolecek 			free(vap->va_vruncl, M_NTFSRUN);
5329accf4dfSjdolecek 	} else {
5339accf4dfSjdolecek 		if (vap->va_datap)
5349accf4dfSjdolecek 			free(vap->va_datap, M_NTFSRDATA);
5359accf4dfSjdolecek 	}
5369b87d582Scegger 	free(vap, M_NTFSNTVATTR);
5379accf4dfSjdolecek }
5389accf4dfSjdolecek 
5399accf4dfSjdolecek /*
5409accf4dfSjdolecek  * Convert disk image of attribute into ntvattr structure,
5419accf4dfSjdolecek  * runs are expanded also.
5429accf4dfSjdolecek  */
5439accf4dfSjdolecek int
ntfs_attrtontvattr(struct ntfsmount * ntmp,struct ntvattr ** rvapp,struct attr * rap)5446387e674Smaxv ntfs_attrtontvattr(struct ntfsmount *ntmp, struct ntvattr **rvapp,
5459accf4dfSjdolecek    struct attr *rap)
5469accf4dfSjdolecek {
5479accf4dfSjdolecek 	int error, i;
5489accf4dfSjdolecek 	struct ntvattr *vap;
5499accf4dfSjdolecek 
5509accf4dfSjdolecek 	error = 0;
5519accf4dfSjdolecek 	*rvapp = NULL;
5529accf4dfSjdolecek 
553fd460520Schristos 	vap = malloc(sizeof(*vap), M_NTFSNTVATTR, M_WAITOK|M_ZERO);
5549accf4dfSjdolecek 	vap->va_ip = NULL;
5559accf4dfSjdolecek 	vap->va_flag = rap->a_hdr.a_flag;
5569accf4dfSjdolecek 	vap->va_type = rap->a_hdr.a_type;
5579accf4dfSjdolecek 	vap->va_compression = rap->a_hdr.a_compression;
5589accf4dfSjdolecek 	vap->va_index = rap->a_hdr.a_index;
5599accf4dfSjdolecek 
560fd460520Schristos 	ddprintf(("%s: type: 0x%x, index: %d", __func__,
561fd460520Schristos 	    vap->va_type, vap->va_index));
5629accf4dfSjdolecek 
5639accf4dfSjdolecek 	vap->va_namelen = rap->a_hdr.a_namelen;
5649accf4dfSjdolecek 	if (rap->a_hdr.a_namelen) {
56553524e44Schristos 		wchar *unp = (wchar *)((char *)rap + rap->a_hdr.a_nameoff);
5669accf4dfSjdolecek 		ddprintf((", name:["));
5679accf4dfSjdolecek 		for (i = 0; i < vap->va_namelen; i++) {
5689accf4dfSjdolecek 			vap->va_name[i] = unp[i];
5699accf4dfSjdolecek 			ddprintf(("%c", vap->va_name[i]));
5709accf4dfSjdolecek 		}
5719accf4dfSjdolecek 		ddprintf(("]"));
5729accf4dfSjdolecek 	}
5739accf4dfSjdolecek 	if (vap->va_flag & NTFS_AF_INRUN) {
5749accf4dfSjdolecek 		ddprintf((", nonres."));
5759accf4dfSjdolecek 		vap->va_datalen = rap->a_nr.a_datalen;
5769accf4dfSjdolecek 		vap->va_allocated = rap->a_nr.a_allocated;
5779accf4dfSjdolecek 		vap->va_vcnstart = rap->a_nr.a_vcnstart;
5789accf4dfSjdolecek 		vap->va_vcnend = rap->a_nr.a_vcnend;
5799accf4dfSjdolecek 		vap->va_compressalg = rap->a_nr.a_compressalg;
5809accf4dfSjdolecek 		error = ntfs_runtovrun(&(vap->va_vruncn), &(vap->va_vruncl),
5819accf4dfSjdolecek 		    &(vap->va_vruncnt),
58279652075Smrg 		    (u_int8_t *) rap + rap->a_nr.a_dataoff);
5839accf4dfSjdolecek 	} else {
5849accf4dfSjdolecek 		vap->va_compressalg = 0;
5859accf4dfSjdolecek 		ddprintf((", res."));
5869accf4dfSjdolecek 		vap->va_datalen = rap->a_r.a_datalen;
5879accf4dfSjdolecek 		vap->va_allocated = rap->a_r.a_datalen;
5889accf4dfSjdolecek 		vap->va_vcnstart = 0;
5899accf4dfSjdolecek 		vap->va_vcnend = ntfs_btocn(vap->va_allocated);
590fd460520Schristos 		vap->va_datap = malloc(vap->va_datalen, M_NTFSRDATA, M_WAITOK);
59153524e44Schristos 		memcpy(vap->va_datap, (char *)rap + rap->a_r.a_dataoff,
5929accf4dfSjdolecek 		    rap->a_r.a_datalen);
5939accf4dfSjdolecek 	}
594aa112c89Schristos 	ddprintf((", len: %qu", (long long)vap->va_datalen));
5959accf4dfSjdolecek 
5969accf4dfSjdolecek 	if (error)
5979b87d582Scegger 		free(vap, M_NTFSNTVATTR);
5989accf4dfSjdolecek 	else
5999accf4dfSjdolecek 		*rvapp = vap;
6009accf4dfSjdolecek 
6019accf4dfSjdolecek 	ddprintf(("\n"));
6029accf4dfSjdolecek 
6039accf4dfSjdolecek 	return (error);
6049accf4dfSjdolecek }
6059accf4dfSjdolecek 
6069accf4dfSjdolecek /*
6079accf4dfSjdolecek  * Expand run into more utilizable and more memory eating format.
6089accf4dfSjdolecek  */
6099accf4dfSjdolecek int
ntfs_runtovrun(cn_t ** rcnp,cn_t ** rclp,u_long * rcntp,u_int8_t * run)6106387e674Smaxv ntfs_runtovrun(cn_t **rcnp, cn_t **rclp, u_long *rcntp, u_int8_t *run)
6119accf4dfSjdolecek {
6126387e674Smaxv 	u_int32_t off, sz, i;
6136387e674Smaxv 	cn_t *cn, *cl;
6149accf4dfSjdolecek 	u_long cnt;
6156387e674Smaxv 	cn_t prev, tmp;
6169accf4dfSjdolecek 
6179accf4dfSjdolecek 	off = 0;
6189accf4dfSjdolecek 	cnt = 0;
6199accf4dfSjdolecek 	i = 0;
6209accf4dfSjdolecek 	while (run[off]) {
6219accf4dfSjdolecek 		off += (run[off] & 0xF) + ((run[off] >> 4) & 0xF) + 1;
6229accf4dfSjdolecek 		cnt++;
6239accf4dfSjdolecek 	}
624fd460520Schristos 	cn = malloc(cnt * sizeof(*cn), M_NTFSRUN, M_WAITOK);
625fd460520Schristos 	cl = malloc(cnt * sizeof(*cl), M_NTFSRUN, M_WAITOK);
6269accf4dfSjdolecek 
6279accf4dfSjdolecek 	off = 0;
6289accf4dfSjdolecek 	cnt = 0;
6299accf4dfSjdolecek 	prev = 0;
6309accf4dfSjdolecek 	while (run[off]) {
6319accf4dfSjdolecek 		sz = run[off++];
6329accf4dfSjdolecek 		cl[cnt] = 0;
6339accf4dfSjdolecek 
6349accf4dfSjdolecek 		for (i = 0; i < (sz & 0xF); i++)
6359accf4dfSjdolecek 			cl[cnt] += (u_int32_t) run[off++] << (i << 3);
6369accf4dfSjdolecek 
6379accf4dfSjdolecek 		sz >>= 4;
6389accf4dfSjdolecek 		if (run[off + sz - 1] & 0x80) {
6399accf4dfSjdolecek 			tmp = ((u_int64_t) - 1) << (sz << 3);
6409accf4dfSjdolecek 			for (i = 0; i < sz; i++)
6419accf4dfSjdolecek 				tmp |= (u_int64_t) run[off++] << (i << 3);
6429accf4dfSjdolecek 		} else {
6439accf4dfSjdolecek 			tmp = 0;
6449accf4dfSjdolecek 			for (i = 0; i < sz; i++)
6459accf4dfSjdolecek 				tmp |= (u_int64_t) run[off++] << (i << 3);
6469accf4dfSjdolecek 		}
6479accf4dfSjdolecek 		if (tmp)
6489accf4dfSjdolecek 			prev = cn[cnt] = prev + tmp;
6499accf4dfSjdolecek 		else
6509accf4dfSjdolecek 			cn[cnt] = tmp;
6519accf4dfSjdolecek 
6529accf4dfSjdolecek 		cnt++;
6539accf4dfSjdolecek 	}
6549accf4dfSjdolecek 	*rcnp = cn;
6559accf4dfSjdolecek 	*rclp = cl;
6569accf4dfSjdolecek 	*rcntp = cnt;
6579accf4dfSjdolecek 	return (0);
6589accf4dfSjdolecek }
6599accf4dfSjdolecek 
6609accf4dfSjdolecek /*
6619accf4dfSjdolecek  * Compare unicode and ascii string case insens.
6629accf4dfSjdolecek  */
6639accf4dfSjdolecek static int
ntfs_uastricmp(struct ntfsmount * ntmp,const wchar * ustr,size_t ustrlen,const char * astr,size_t astrlen)6646387e674Smaxv ntfs_uastricmp(struct ntfsmount *ntmp, const wchar *ustr, size_t ustrlen,
6656387e674Smaxv     const char *astr, size_t astrlen)
6669accf4dfSjdolecek {
6679accf4dfSjdolecek 	size_t i;
6689accf4dfSjdolecek 	int res;
6699accf4dfSjdolecek 
6702ce9f451Sjdolecek 	for (i = 0; i < ustrlen && astrlen > 0; i++) {
6719accf4dfSjdolecek 		res = (*ntmp->ntm_wcmp)(NTFS_TOUPPER(ustr[i]),
6722ce9f451Sjdolecek 		    NTFS_TOUPPER((*ntmp->ntm_wget)(&astr, &astrlen)) );
6739accf4dfSjdolecek 		if (res)
6749accf4dfSjdolecek 			return res;
6759accf4dfSjdolecek 	}
6769accf4dfSjdolecek 
6772ce9f451Sjdolecek 	if (i == ustrlen && astrlen == 0)
6789accf4dfSjdolecek 		return 0;
6799accf4dfSjdolecek 	else if (i == ustrlen)
6809accf4dfSjdolecek 		return -1;
6819accf4dfSjdolecek 	else
6829accf4dfSjdolecek 		return 1;
6839accf4dfSjdolecek }
6849accf4dfSjdolecek 
6859accf4dfSjdolecek /*
6869accf4dfSjdolecek  * Compare unicode and ascii string case sens.
6879accf4dfSjdolecek  */
6889accf4dfSjdolecek static int
ntfs_uastrcmp(struct ntfsmount * ntmp,const wchar * ustr,size_t ustrlen,const char * astr,size_t astrlen)6896387e674Smaxv ntfs_uastrcmp(struct ntfsmount *ntmp, const wchar *ustr, size_t ustrlen,
6906387e674Smaxv     const char *astr, size_t astrlen)
6919accf4dfSjdolecek {
6929accf4dfSjdolecek 	size_t i;
6939accf4dfSjdolecek 	int res;
6949accf4dfSjdolecek 
6952ce9f451Sjdolecek 	for (i = 0; (i < ustrlen) && astrlen > 0; i++) {
6962ce9f451Sjdolecek 		res = (*ntmp->ntm_wcmp)(ustr[i],
6972ce9f451Sjdolecek 		    (*ntmp->ntm_wget)(&astr, &astrlen));
6989accf4dfSjdolecek 		if (res)
6999accf4dfSjdolecek 			return res;
7009accf4dfSjdolecek 	}
7019accf4dfSjdolecek 
7022ce9f451Sjdolecek 	if (i == ustrlen && astrlen == 0)
7039accf4dfSjdolecek 		return 0;
7049accf4dfSjdolecek 	else if (i == ustrlen)
7059accf4dfSjdolecek 		return -1;
7069accf4dfSjdolecek 	else
7079accf4dfSjdolecek 		return 1;
7089accf4dfSjdolecek }
7099accf4dfSjdolecek 
7109accf4dfSjdolecek /*
7119accf4dfSjdolecek  * Lookup attribute name in format: [[:$ATTR_TYPE]:$ATTR_NAME],
7129accf4dfSjdolecek  * $ATTR_TYPE is searched in attrdefs read from $AttrDefs.
7136621e167Swiz  * If $ATTR_TYPE not specified, ATTR_A_DATA assumed.
7149accf4dfSjdolecek  */
7159accf4dfSjdolecek static int
ntfs_ntlookupattr(struct ntfsmount * ntmp,const char * name,int namelen,int * attrtype,char ** attrname)7166387e674Smaxv ntfs_ntlookupattr(struct ntfsmount *ntmp, const char *name, int namelen,
7176387e674Smaxv     int *attrtype, char **attrname)
7189accf4dfSjdolecek {
7199accf4dfSjdolecek 	const char *sys;
7209accf4dfSjdolecek 	size_t syslen, i;
7219accf4dfSjdolecek 	struct ntvattrdef *adp;
7229accf4dfSjdolecek 
7239accf4dfSjdolecek 	if (namelen == 0)
7249accf4dfSjdolecek 		return (0);
7259accf4dfSjdolecek 
7269accf4dfSjdolecek 	if (name[0] == '$') {
7279accf4dfSjdolecek 		sys = name;
7289accf4dfSjdolecek 		for (syslen = 0; syslen < namelen; syslen++) {
7299accf4dfSjdolecek 			if (sys[syslen] == ':') {
7309accf4dfSjdolecek 				name++;
7319accf4dfSjdolecek 				namelen--;
7329accf4dfSjdolecek 				break;
7339accf4dfSjdolecek 			}
7349accf4dfSjdolecek 		}
7359accf4dfSjdolecek 		name += syslen;
7369accf4dfSjdolecek 		namelen -= syslen;
7379accf4dfSjdolecek 
7389accf4dfSjdolecek 		adp = ntmp->ntm_ad;
7399accf4dfSjdolecek 		for (i = 0; i < ntmp->ntm_adnum; i++, adp++){
7409accf4dfSjdolecek 			if (syslen != adp->ad_namelen ||
7419accf4dfSjdolecek 			    strncmp(sys, adp->ad_name, syslen) != 0)
7429accf4dfSjdolecek 				continue;
7439accf4dfSjdolecek 
7449accf4dfSjdolecek 			*attrtype = adp->ad_type;
7459accf4dfSjdolecek 			goto out;
7469accf4dfSjdolecek 		}
7479accf4dfSjdolecek 		return (ENOENT);
7486f8e2ffeShannken 	} else
7496f8e2ffeShannken 		*attrtype = NTFS_A_DATA;
7509accf4dfSjdolecek 
7519accf4dfSjdolecek out:
7529accf4dfSjdolecek 	if (namelen) {
7536f8e2ffeShannken 		*attrname = malloc(namelen+1, M_TEMP, M_WAITOK);
7549accf4dfSjdolecek 		memcpy((*attrname), name, namelen);
7559accf4dfSjdolecek 		(*attrname)[namelen] = '\0';
7569accf4dfSjdolecek 	}
7579accf4dfSjdolecek 
7589accf4dfSjdolecek 	return (0);
7599accf4dfSjdolecek }
7609accf4dfSjdolecek 
7619accf4dfSjdolecek /*
7626621e167Swiz  * Lookup specified node for filename, matching cnp,
7630bac6265Shannken  * return referenced vnode with fnode filled.
7649accf4dfSjdolecek  */
7659accf4dfSjdolecek int
ntfs_ntlookupfile(struct ntfsmount * ntmp,struct vnode * vp,struct componentname * cnp,struct vnode ** vpp)7666387e674Smaxv ntfs_ntlookupfile(struct ntfsmount *ntmp, struct vnode *vp,
7676387e674Smaxv     struct componentname *cnp, struct vnode **vpp)
7689accf4dfSjdolecek {
7699accf4dfSjdolecek 	struct fnode   *fp = VTOF(vp);
7709accf4dfSjdolecek 	struct ntnode  *ip = FTONT(fp);
771ec1a3951Smaxv 	struct ntvattr *vap = NULL;	/* Root attribute */
7729accf4dfSjdolecek 	cn_t            cn = 0;	/* VCN in current attribute */
773ec1a3951Smaxv 	void *        rdbuf = NULL;	/* Buffer to read directory's blocks  */
7749accf4dfSjdolecek 	u_int32_t       blsize;
7759accf4dfSjdolecek 	u_int32_t       rdsize;	/* Length of data to read from current block */
7769accf4dfSjdolecek 	struct attr_indexentry *iep;
7779accf4dfSjdolecek 	int             error, res, anamelen, fnamelen;
7789accf4dfSjdolecek 	const char     *fname,*aname;
7799accf4dfSjdolecek 	u_int32_t       aoff;
7809accf4dfSjdolecek 	int attrtype = NTFS_A_DATA;
7819accf4dfSjdolecek 	char *attrname = NULL;
7829accf4dfSjdolecek 	struct vnode   *nvp;
7839accf4dfSjdolecek 	int fullscan = 0;
7849accf4dfSjdolecek 	struct ntfs_lookup_ctx *lookup_ctx = NULL, *tctx;
7859accf4dfSjdolecek 
7869accf4dfSjdolecek 	error = ntfs_ntget(ip);
7879accf4dfSjdolecek 	if (error)
7889accf4dfSjdolecek 		return (error);
7899accf4dfSjdolecek 
7909accf4dfSjdolecek 	error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXROOT, "$I30", 0, &vap);
791ec1a3951Smaxv 	if (error || (vap->va_flag & NTFS_AF_INRUN)) {
792ec1a3951Smaxv 		error = ENOTDIR;
793ec1a3951Smaxv 		goto fail;
794ec1a3951Smaxv 	}
7959accf4dfSjdolecek 
7969accf4dfSjdolecek 	/*
7979accf4dfSjdolecek 	 * Divide file name into: foofilefoofilefoofile[:attrspec]
7989accf4dfSjdolecek 	 * Store like this:       fname:fnamelen       [aname:anamelen]
7999accf4dfSjdolecek 	 */
8009accf4dfSjdolecek 	fname = cnp->cn_nameptr;
8019accf4dfSjdolecek 	aname = NULL;
8029accf4dfSjdolecek 	anamelen = 0;
8039accf4dfSjdolecek 	for (fnamelen = 0; fnamelen < cnp->cn_namelen; fnamelen++)
8049accf4dfSjdolecek 		if (fname[fnamelen] == ':') {
8059accf4dfSjdolecek 			aname = fname + fnamelen + 1;
8069accf4dfSjdolecek 			anamelen = cnp->cn_namelen - fnamelen - 1;
807fd460520Schristos 			dprintf(("%s: %s (%d), attr: %s (%d)\n", __func__,
8089accf4dfSjdolecek 				fname, fnamelen, aname, anamelen));
8099accf4dfSjdolecek 			break;
8109accf4dfSjdolecek 		}
8119accf4dfSjdolecek 
8129accf4dfSjdolecek 	blsize = vap->va_a_iroot->ir_size;
813fd460520Schristos 	dprintf(("%s: blksz: %d\n", __func__, blsize));
814fd460520Schristos 	rdbuf = malloc(blsize, M_TEMP, M_WAITOK);
8159accf4dfSjdolecek 
8169accf4dfSjdolecek loop:
8179accf4dfSjdolecek 	rdsize = vap->va_datalen;
818fd460520Schristos 	dprintf(("%s: rdsz: %d\n", __func__, rdsize));
8199accf4dfSjdolecek 
8209accf4dfSjdolecek 	error = ntfs_readattr(ntmp, ip, NTFS_A_INDXROOT, "$I30",
8219accf4dfSjdolecek 	    0, rdsize, rdbuf, NULL);
8229accf4dfSjdolecek 	if (error)
8239accf4dfSjdolecek 		goto fail;
8249accf4dfSjdolecek 
8259accf4dfSjdolecek 	aoff = sizeof(struct attr_indexroot);
8269accf4dfSjdolecek 
8279accf4dfSjdolecek 	do {
82853524e44Schristos 		iep = (struct attr_indexentry *) ((char *)rdbuf + aoff);
8299accf4dfSjdolecek 
8309accf4dfSjdolecek 		for (; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (rdsize > aoff);
8319accf4dfSjdolecek 			aoff += iep->reclen,
83253524e44Schristos 			iep = (struct attr_indexentry *) ((char *)rdbuf + aoff))
8339accf4dfSjdolecek 		{
834fd460520Schristos 			ddprintf(("%s: fscan: %d, %d\n", __func__,
8359accf4dfSjdolecek 				  (u_int32_t) iep->ie_number,
8369accf4dfSjdolecek 				  (u_int32_t) iep->ie_fnametype));
8379accf4dfSjdolecek 
8386621e167Swiz 			/* check the name - the case-insensitive check
8399accf4dfSjdolecek 			 * has to come first, to break from this for loop
8409accf4dfSjdolecek 			 * if needed, so we can dive correctly */
8419accf4dfSjdolecek 			res = ntfs_uastricmp(ntmp, iep->ie_fname,
8429accf4dfSjdolecek 				iep->ie_fnamelen, fname, fnamelen);
8439accf4dfSjdolecek 			if (!fullscan) {
8446387e674Smaxv 				if (res > 0)
8456387e674Smaxv 					break;
8466387e674Smaxv 				if (res < 0)
8476387e674Smaxv 					continue;
8489accf4dfSjdolecek 			}
8499accf4dfSjdolecek 
8509accf4dfSjdolecek 			if (iep->ie_fnametype == 0 ||
8519accf4dfSjdolecek 			    !(ntmp->ntm_flag & NTFS_MFLAG_CASEINS))
8529accf4dfSjdolecek 			{
8539accf4dfSjdolecek 				res = ntfs_uastrcmp(ntmp, iep->ie_fname,
8549accf4dfSjdolecek 					iep->ie_fnamelen, fname, fnamelen);
8556387e674Smaxv 				if (res != 0 && !fullscan)
8566387e674Smaxv 					continue;
8579accf4dfSjdolecek 			}
8589accf4dfSjdolecek 
8599accf4dfSjdolecek 			/* if we perform full scan, the file does not match
8609accf4dfSjdolecek 			 * and this is subnode, dive */
8619accf4dfSjdolecek 			if (fullscan && res != 0) {
8629accf4dfSjdolecek 				if (iep->ie_flag & NTFS_IEFLAG_SUBNODE) {
8636387e674Smaxv 					tctx = malloc(sizeof(*tctx), M_TEMP,
8646387e674Smaxv 					    M_WAITOK);
8659accf4dfSjdolecek 					tctx->aoff	= aoff + iep->reclen;
8669accf4dfSjdolecek 					tctx->rdsize	= rdsize;
8679accf4dfSjdolecek 					tctx->cn	= cn;
8689accf4dfSjdolecek 					tctx->prev	= lookup_ctx;
8699accf4dfSjdolecek 					lookup_ctx = tctx;
8709accf4dfSjdolecek 					break;
8719accf4dfSjdolecek 				} else
8729accf4dfSjdolecek 					continue;
8739accf4dfSjdolecek 			}
8749accf4dfSjdolecek 
8759accf4dfSjdolecek 			if (aname) {
8766387e674Smaxv 				error = ntfs_ntlookupattr(ntmp, aname, anamelen,
8779accf4dfSjdolecek 				    &attrtype, &attrname);
8789accf4dfSjdolecek 				if (error)
8799accf4dfSjdolecek 					goto fail;
8809accf4dfSjdolecek 			}
8819accf4dfSjdolecek 
8826621e167Swiz 			/* Check if we've found ourselves */
8839accf4dfSjdolecek 			if ((iep->ie_number == ip->i_number) &&
8849accf4dfSjdolecek 			    (attrtype == fp->f_attrtype) &&
8856f8e2ffeShannken 			    !strcmp(attrname ? attrname : "", fp->f_attrname))
8869accf4dfSjdolecek 			{
887c3183f32Spooka 				vref(vp);
8889accf4dfSjdolecek 				*vpp = vp;
8899accf4dfSjdolecek 				error = 0;
8909accf4dfSjdolecek 				goto fail;
8919accf4dfSjdolecek 			}
8929accf4dfSjdolecek 
893a26eea28Shannken 			/* vget node */
8946f8e2ffeShannken 			error = ntfs_vgetex(ntmp->ntm_mountp, iep->ie_number,
8956387e674Smaxv 			    attrtype, attrname ? attrname : "", 0, &nvp);
8966f8e2ffeShannken 
8979accf4dfSjdolecek 			/* free the buffer returned by ntfs_ntlookupattr() */
8989accf4dfSjdolecek 			if (attrname) {
8999b87d582Scegger 				free(attrname, M_TEMP);
9009accf4dfSjdolecek 				attrname = NULL;
9019accf4dfSjdolecek 			}
9029accf4dfSjdolecek 
9039accf4dfSjdolecek 			if (error)
9049accf4dfSjdolecek 				goto fail;
9059accf4dfSjdolecek 
9069accf4dfSjdolecek 			*vpp = nvp;
9079accf4dfSjdolecek 			goto fail;
9089accf4dfSjdolecek 		}
9099accf4dfSjdolecek 
9109accf4dfSjdolecek 		/* Dive if possible */
9119accf4dfSjdolecek 		if (iep->ie_flag & NTFS_IEFLAG_SUBNODE) {
912fd460520Schristos 			dprintf(("%s: diving\n", __func__));
9139accf4dfSjdolecek 
91453524e44Schristos 			cn = *(cn_t *) ((char *)rdbuf + aoff +
9159accf4dfSjdolecek 					iep->reclen - sizeof(cn_t));
9169accf4dfSjdolecek 			rdsize = blsize;
9179accf4dfSjdolecek 
9189accf4dfSjdolecek 			error = ntfs_readattr(ntmp, ip, NTFS_A_INDX, "$I30",
9199accf4dfSjdolecek 			    ntfs_cntob(cn), rdsize, rdbuf, NULL);
9209accf4dfSjdolecek 			if (error)
9219accf4dfSjdolecek 				goto fail;
9229accf4dfSjdolecek 
9239accf4dfSjdolecek 			error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC,
9249accf4dfSjdolecek 			    rdbuf, rdsize);
9259accf4dfSjdolecek 			if (error)
9269accf4dfSjdolecek 				goto fail;
9279accf4dfSjdolecek 
9289accf4dfSjdolecek 			aoff = (((struct attr_indexalloc *) rdbuf)->ia_hdrsize +
9299accf4dfSjdolecek 				0x18);
9309accf4dfSjdolecek 		} else if (fullscan && lookup_ctx) {
9319accf4dfSjdolecek 			cn = lookup_ctx->cn;
9329accf4dfSjdolecek 			aoff = lookup_ctx->aoff;
9339accf4dfSjdolecek 			rdsize = lookup_ctx->rdsize;
9349accf4dfSjdolecek 
9359accf4dfSjdolecek 			error = ntfs_readattr(ntmp, ip,
9369accf4dfSjdolecek 				(cn == 0) ? NTFS_A_INDXROOT : NTFS_A_INDX,
9379accf4dfSjdolecek 				"$I30", ntfs_cntob(cn), rdsize, rdbuf, NULL);
9389accf4dfSjdolecek 			if (error)
9399accf4dfSjdolecek 				goto fail;
9409accf4dfSjdolecek 
9419accf4dfSjdolecek 			if (cn != 0) {
9429accf4dfSjdolecek 				error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC,
9439accf4dfSjdolecek 				    rdbuf, rdsize);
9449accf4dfSjdolecek 				if (error)
9459accf4dfSjdolecek 					goto fail;
9469accf4dfSjdolecek 			}
9479accf4dfSjdolecek 
9489accf4dfSjdolecek 			tctx = lookup_ctx;
9499accf4dfSjdolecek 			lookup_ctx = lookup_ctx->prev;
9509b87d582Scegger 			free(tctx, M_TEMP);
9519accf4dfSjdolecek 		} else {
952fd460520Schristos 			dprintf(("%s: nowhere to dive :-(\n", __func__));
9539accf4dfSjdolecek 			error = ENOENT;
9549accf4dfSjdolecek 			break;
9559accf4dfSjdolecek 		}
9569accf4dfSjdolecek 	} while (1);
9579accf4dfSjdolecek 
9589accf4dfSjdolecek 	/* perform full scan if no entry was found */
9599accf4dfSjdolecek 	if (!fullscan && error == ENOENT) {
9609accf4dfSjdolecek 		fullscan = 1;
9619accf4dfSjdolecek 		cn = 0;		/* need zero, used by lookup_ctx */
9629accf4dfSjdolecek 
963fd460520Schristos 		ddprintf(("%s: fullscan performed for: %.*s\n", __func__,
9649accf4dfSjdolecek 		    (int) fnamelen, fname));
9659accf4dfSjdolecek 		goto loop;
9669accf4dfSjdolecek 	}
9679accf4dfSjdolecek 
9689accf4dfSjdolecek 	dprintf(("finish\n"));
9699accf4dfSjdolecek 
9709accf4dfSjdolecek fail:
9719accf4dfSjdolecek 	if (attrname)
9729b87d582Scegger 		free(attrname, M_TEMP);
9739accf4dfSjdolecek 	if (lookup_ctx) {
9749accf4dfSjdolecek 		while(lookup_ctx) {
9759accf4dfSjdolecek 			tctx = lookup_ctx;
9769accf4dfSjdolecek 			lookup_ctx = lookup_ctx->prev;
9779b87d582Scegger 			free(tctx, M_TEMP);
9789accf4dfSjdolecek 		}
9799accf4dfSjdolecek 	}
980ec1a3951Smaxv 	if (vap)
9819accf4dfSjdolecek 		ntfs_ntvattrrele(vap);
982ec1a3951Smaxv 	if (rdbuf)
9839accf4dfSjdolecek 		free(rdbuf, M_TEMP);
984ec1a3951Smaxv 	ntfs_ntput(ip);
9859accf4dfSjdolecek 	return (error);
9869accf4dfSjdolecek }
9879accf4dfSjdolecek 
9889accf4dfSjdolecek /*
9899accf4dfSjdolecek  * Check if name type is permitted to show.
9909accf4dfSjdolecek  */
9919accf4dfSjdolecek int
ntfs_isnamepermitted(struct ntfsmount * ntmp,struct attr_indexentry * iep)9926387e674Smaxv ntfs_isnamepermitted(struct ntfsmount *ntmp, struct attr_indexentry *iep)
9939accf4dfSjdolecek {
9949accf4dfSjdolecek 	if (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES)
9959accf4dfSjdolecek 		return 1;
9969accf4dfSjdolecek 
9979accf4dfSjdolecek 	switch (iep->ie_fnametype) {
9989accf4dfSjdolecek 	case 2:
999609d5cf3Sdsl 		ddprintf(("%s: skipped DOS name\n", __func__));
10009accf4dfSjdolecek 		return 0;
10019accf4dfSjdolecek 	case 0: case 1: case 3:
10029accf4dfSjdolecek 		return 1;
10039accf4dfSjdolecek 	default:
1004fd460520Schristos 		printf("%s: WARNING! Unknown file name type: %d\n", __func__,
10059accf4dfSjdolecek 		    iep->ie_fnametype);
10069accf4dfSjdolecek 		break;
10079accf4dfSjdolecek 	}
10089accf4dfSjdolecek 	return 0;
10099accf4dfSjdolecek }
10109accf4dfSjdolecek 
10119accf4dfSjdolecek /*
10129accf4dfSjdolecek  * Read ntfs dir like stream of attr_indexentry, not like btree of them.
10136621e167Swiz  * This is done by scanning $BITMAP:$I30 for busy clusters and reading them.
10146621e167Swiz  * Of course $INDEX_ROOT:$I30 is read before. Last read values are stored in
10156621e167Swiz  * fnode, so we can skip toward record number num almost immediately.
10169accf4dfSjdolecek  * Anyway this is rather slow routine. The problem is that we don't know
10179accf4dfSjdolecek  * how many records are there in $INDEX_ALLOCATION:$I30 block.
10189accf4dfSjdolecek  */
10199accf4dfSjdolecek int
ntfs_ntreaddir(struct ntfsmount * ntmp,struct fnode * fp,u_int32_t num,struct attr_indexentry ** riepp)10206387e674Smaxv ntfs_ntreaddir(struct ntfsmount *ntmp, struct fnode *fp, u_int32_t num,
10219accf4dfSjdolecek     struct attr_indexentry **riepp)
10229accf4dfSjdolecek {
10239accf4dfSjdolecek 	struct ntnode  *ip = FTONT(fp);
10249accf4dfSjdolecek 	struct ntvattr *vap = NULL;	/* IndexRoot attribute */
10259accf4dfSjdolecek 	struct ntvattr *bmvap = NULL;	/* BitMap attribute */
10269accf4dfSjdolecek 	struct ntvattr *iavap = NULL;	/* IndexAllocation attribute */
102753524e44Schristos 	void *        rdbuf;		/* Buffer to read directory's blocks  */
10289accf4dfSjdolecek 	u_char         *bmp = NULL;	/* Bitmap */
10299accf4dfSjdolecek 	u_int32_t       blsize;		/* Index allocation size (2048) */
10309accf4dfSjdolecek 	u_int32_t       rdsize;		/* Length of data to read */
10319accf4dfSjdolecek 	u_int32_t       attrnum;	/* Current attribute type */
10329accf4dfSjdolecek 	u_int32_t       cpbl = 1;	/* Clusters per directory block */
10339accf4dfSjdolecek 	u_int32_t       blnum;
10349accf4dfSjdolecek 	struct attr_indexentry *iep;
10359accf4dfSjdolecek 	int             error = ENOENT;
10369accf4dfSjdolecek 	u_int32_t       aoff, cnum;
10379accf4dfSjdolecek 
1038fd460520Schristos 	dprintf(("%s: read ino: %llu, num: %d\n", __func__,
1039f229ea7fSchristos 	    (unsigned long long)ip->i_number, num));
10409accf4dfSjdolecek 	error = ntfs_ntget(ip);
10419accf4dfSjdolecek 	if (error)
10429accf4dfSjdolecek 		return (error);
10439accf4dfSjdolecek 
10449accf4dfSjdolecek 	error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXROOT, "$I30", 0, &vap);
1045ec1a3951Smaxv 	if (error) {
1046ec1a3951Smaxv 		error = ENOTDIR;
1047ec1a3951Smaxv 		goto fail;
1048ec1a3951Smaxv 	}
10499accf4dfSjdolecek 
10509accf4dfSjdolecek 	if (fp->f_dirblbuf == NULL) {
10519accf4dfSjdolecek 		fp->f_dirblsz = vap->va_a_iroot->ir_size;
1052fd460520Schristos 		fp->f_dirblbuf = malloc(MAX(vap->va_datalen, fp->f_dirblsz),
1053fd460520Schristos 		    M_NTFSDIR, M_WAITOK);
10549accf4dfSjdolecek 	}
10559accf4dfSjdolecek 
10569accf4dfSjdolecek 	blsize = fp->f_dirblsz;
10579accf4dfSjdolecek 	rdbuf = fp->f_dirblbuf;
10589accf4dfSjdolecek 
1059fd460520Schristos 	dprintf(("%s: rdbuf: %p, blsize: %d\n", __func__, rdbuf, blsize));
10609accf4dfSjdolecek 
10619accf4dfSjdolecek 	if (vap->va_a_iroot->ir_flag & NTFS_IRFLAG_INDXALLOC) {
10629accf4dfSjdolecek 		error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXBITMAP, "$I30",
10639accf4dfSjdolecek 					0, &bmvap);
10649accf4dfSjdolecek 		if (error) {
10659accf4dfSjdolecek 			error = ENOTDIR;
10669accf4dfSjdolecek 			goto fail;
10679accf4dfSjdolecek 		}
10689accf4dfSjdolecek 		bmp = (u_char *) malloc(bmvap->va_datalen, M_TEMP, M_WAITOK);
10699accf4dfSjdolecek 		error = ntfs_readattr(ntmp, ip, NTFS_A_INDXBITMAP, "$I30", 0,
10709accf4dfSjdolecek 		    bmvap->va_datalen, bmp, NULL);
10719accf4dfSjdolecek 		if (error)
10729accf4dfSjdolecek 			goto fail;
10739accf4dfSjdolecek 
10749accf4dfSjdolecek 		error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDX, "$I30",
10759accf4dfSjdolecek 					0, &iavap);
10769accf4dfSjdolecek 		if (error) {
10779accf4dfSjdolecek 			error = ENOTDIR;
10789accf4dfSjdolecek 			goto fail;
10799accf4dfSjdolecek 		}
10809accf4dfSjdolecek 		cpbl = ntfs_btocn(blsize + ntfs_cntob(1) - 1);
1081fd460520Schristos 		dprintf(("%s: indexalloc: %qu, cpbl: %d\n", __func__,
1082aa112c89Schristos 		    (long long)iavap->va_datalen, cpbl));
10839accf4dfSjdolecek 	} else {
1084fd460520Schristos 		dprintf(("%s: w/o BitMap and IndexAllocation\n", __func__));
10859accf4dfSjdolecek 		iavap = bmvap = NULL;
10869accf4dfSjdolecek 		bmp = NULL;
10879accf4dfSjdolecek 	}
10889accf4dfSjdolecek 
10899accf4dfSjdolecek 	/* Try use previous values */
10909accf4dfSjdolecek 	if ((fp->f_lastdnum < num) && (fp->f_lastdnum != 0)) {
10919accf4dfSjdolecek 		attrnum = fp->f_lastdattr;
10929accf4dfSjdolecek 		aoff = fp->f_lastdoff;
10939accf4dfSjdolecek 		blnum = fp->f_lastdblnum;
10949accf4dfSjdolecek 		cnum = fp->f_lastdnum;
10959accf4dfSjdolecek 	} else {
10969accf4dfSjdolecek 		attrnum = NTFS_A_INDXROOT;
10979accf4dfSjdolecek 		aoff = sizeof(struct attr_indexroot);
10989accf4dfSjdolecek 		blnum = 0;
10999accf4dfSjdolecek 		cnum = 0;
11009accf4dfSjdolecek 	}
11019accf4dfSjdolecek 
11029accf4dfSjdolecek 	do {
1103fd460520Schristos 		dprintf(("%s: scan: 0x%x, %d, %d, %d, %d\n", __func__,
11049accf4dfSjdolecek 			 attrnum, (u_int32_t) blnum, cnum, num, aoff));
11059accf4dfSjdolecek 		rdsize = (attrnum == NTFS_A_INDXROOT) ? vap->va_datalen : blsize;
11069accf4dfSjdolecek 		error = ntfs_readattr(ntmp, ip, attrnum, "$I30",
11079accf4dfSjdolecek 				ntfs_cntob(blnum * cpbl), rdsize, rdbuf, NULL);
11089accf4dfSjdolecek 		if (error)
11099accf4dfSjdolecek 			goto fail;
11109accf4dfSjdolecek 
11119accf4dfSjdolecek 		if (attrnum == NTFS_A_INDX) {
11129accf4dfSjdolecek 			error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC,
11139accf4dfSjdolecek 						rdbuf, rdsize);
11149accf4dfSjdolecek 			if (error)
11159accf4dfSjdolecek 				goto fail;
11169accf4dfSjdolecek 		}
11179accf4dfSjdolecek 		if (aoff == 0)
11189accf4dfSjdolecek 			aoff = (attrnum == NTFS_A_INDX) ?
11199accf4dfSjdolecek 				(0x18 + ((struct attr_indexalloc *) rdbuf)->ia_hdrsize) :
11209accf4dfSjdolecek 				sizeof(struct attr_indexroot);
11219accf4dfSjdolecek 
112253524e44Schristos 		iep = (struct attr_indexentry *) ((char *)rdbuf + aoff);
11239accf4dfSjdolecek 		for (; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (rdsize > aoff);
11249accf4dfSjdolecek 			aoff += iep->reclen,
112553524e44Schristos 			iep = (struct attr_indexentry *) ((char *)rdbuf + aoff))
11269accf4dfSjdolecek 		{
11276387e674Smaxv 			if (!ntfs_isnamepermitted(ntmp, iep))
11286387e674Smaxv 				continue;
11299accf4dfSjdolecek 			if (cnum >= num) {
11309accf4dfSjdolecek 				fp->f_lastdnum = cnum;
11319accf4dfSjdolecek 				fp->f_lastdoff = aoff;
11329accf4dfSjdolecek 				fp->f_lastdblnum = blnum;
11339accf4dfSjdolecek 				fp->f_lastdattr = attrnum;
11349accf4dfSjdolecek 
11359accf4dfSjdolecek 				*riepp = iep;
11369accf4dfSjdolecek 
11379accf4dfSjdolecek 				error = 0;
11389accf4dfSjdolecek 				goto fail;
11399accf4dfSjdolecek 			}
11409accf4dfSjdolecek 			cnum++;
11419accf4dfSjdolecek 		}
11429accf4dfSjdolecek 
11439accf4dfSjdolecek 		if (iavap) {
11449accf4dfSjdolecek 			if (attrnum == NTFS_A_INDXROOT)
11459accf4dfSjdolecek 				blnum = 0;
11469accf4dfSjdolecek 			else
11479accf4dfSjdolecek 				blnum++;
11489accf4dfSjdolecek 
11499accf4dfSjdolecek 			while (ntfs_cntob(blnum * cpbl) < iavap->va_datalen) {
11509accf4dfSjdolecek 				if (bmp[blnum >> 3] & (1 << (blnum & 3)))
11519accf4dfSjdolecek 					break;
11529accf4dfSjdolecek 				blnum++;
11539accf4dfSjdolecek 			}
11549accf4dfSjdolecek 
11559accf4dfSjdolecek 			attrnum = NTFS_A_INDX;
11569accf4dfSjdolecek 			aoff = 0;
11579accf4dfSjdolecek 			if (ntfs_cntob(blnum * cpbl) >= iavap->va_datalen)
11589accf4dfSjdolecek 				break;
1159fd460520Schristos 			dprintf(("%s: blnum: %d\n", __func__,
1160fd460520Schristos 			    (u_int32_t) blnum));
11619accf4dfSjdolecek 		}
11629accf4dfSjdolecek 	} while (iavap);
11639accf4dfSjdolecek 
11649accf4dfSjdolecek 	*riepp = NULL;
11659accf4dfSjdolecek 	fp->f_lastdnum = 0;
11669accf4dfSjdolecek 
11679accf4dfSjdolecek fail:
11689accf4dfSjdolecek 	if (vap)
11699accf4dfSjdolecek 		ntfs_ntvattrrele(vap);
11709accf4dfSjdolecek 	if (bmvap)
11719accf4dfSjdolecek 		ntfs_ntvattrrele(bmvap);
11729accf4dfSjdolecek 	if (iavap)
11739accf4dfSjdolecek 		ntfs_ntvattrrele(iavap);
11749accf4dfSjdolecek 	if (bmp)
11759b87d582Scegger 		free(bmp, M_TEMP);
11769accf4dfSjdolecek 	ntfs_ntput(ip);
11779accf4dfSjdolecek 	return (error);
11789accf4dfSjdolecek }
11799accf4dfSjdolecek 
11809accf4dfSjdolecek /*
11819accf4dfSjdolecek  * Convert NTFS times that are in 100 ns units and begins from
11829accf4dfSjdolecek  * 1601 Jan 1 into unix times.
11839accf4dfSjdolecek  */
11849accf4dfSjdolecek struct timespec
ntfs_nttimetounix(u_int64_t nt)11856387e674Smaxv ntfs_nttimetounix(u_int64_t nt)
11869accf4dfSjdolecek {
11879accf4dfSjdolecek 	struct timespec t;
11889accf4dfSjdolecek 
11899accf4dfSjdolecek 	/* WindowNT times are in 100 ns and from 1601 Jan 1 */
11909accf4dfSjdolecek 	t.tv_nsec = (nt % (1000 * 1000 * 10)) * 100;
11919accf4dfSjdolecek 	t.tv_sec = nt / (1000 * 1000 * 10) -
11929accf4dfSjdolecek 		369LL * 365LL * 24LL * 60LL * 60LL -
11939accf4dfSjdolecek 		89LL * 1LL * 24LL * 60LL * 60LL;
11949accf4dfSjdolecek 	return (t);
11959accf4dfSjdolecek }
11969accf4dfSjdolecek 
11979accf4dfSjdolecek /*
119814c96698Smaxv  * This is one of the write routines.
11999accf4dfSjdolecek  */
12009accf4dfSjdolecek int
ntfs_writeattr_plain(struct ntfsmount * ntmp,struct ntnode * ip,u_int32_t attrnum,char * attrname,off_t roff,size_t rsize,void * rdata,size_t * initp,struct uio * uio)12016387e674Smaxv ntfs_writeattr_plain(struct ntfsmount *ntmp, struct ntnode *ip,
12026387e674Smaxv     u_int32_t attrnum, char *attrname, off_t roff, size_t rsize, void *rdata,
12036387e674Smaxv     size_t *initp, struct uio *uio)
12049accf4dfSjdolecek {
12059accf4dfSjdolecek 	size_t init;
12069accf4dfSjdolecek 	int error = 0;
12079accf4dfSjdolecek 	off_t off = roff, left = rsize, towrite;
120853524e44Schristos 	void *data = rdata;
12099accf4dfSjdolecek 	struct ntvattr *vap;
12109accf4dfSjdolecek 	*initp = 0;
12119accf4dfSjdolecek 
12129accf4dfSjdolecek 	while (left) {
12139accf4dfSjdolecek 		error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname,
12149accf4dfSjdolecek 					ntfs_btocn(off), &vap);
12159accf4dfSjdolecek 		if (error)
12169accf4dfSjdolecek 			return (error);
121728302c22Sjdolecek 		towrite = MIN(left, ntfs_cntob(vap->va_vcnend + 1) - off);
1218fd460520Schristos 		ddprintf(("%s: o: %qd, s: %qd (%qu - %qu)\n", __func__,
1219aa112c89Schristos 		    (long long) off, (long long) towrite,
1220aa112c89Schristos 		    (long long) vap->va_vcnstart,
1221aa112c89Schristos 		    (long long) vap->va_vcnend));
12229accf4dfSjdolecek 		error = ntfs_writentvattr_plain(ntmp, ip, vap,
12239accf4dfSjdolecek 		    off - ntfs_cntob(vap->va_vcnstart),
12249accf4dfSjdolecek 		    towrite, data, &init, uio);
12259accf4dfSjdolecek 		if (error) {
1226fd460520Schristos 			dprintf(("%s: "
1227aa112c89Schristos 			    "ntfs_writentvattr_plain failed: o: %qd, s: %qd\n",
1228fd460520Schristos 			    __func__, (long long) off, (long long) towrite));
1229fd460520Schristos 			dprintf(("%s: attrib: %qu - %qu\n", __func__,
1230aa112c89Schristos 			    (long long) vap->va_vcnstart,
1231aa112c89Schristos 			    (long long) vap->va_vcnend));
12329accf4dfSjdolecek 			ntfs_ntvattrrele(vap);
12339accf4dfSjdolecek 			break;
12349accf4dfSjdolecek 		}
12359accf4dfSjdolecek 		ntfs_ntvattrrele(vap);
12369accf4dfSjdolecek 		left -= towrite;
12379accf4dfSjdolecek 		off += towrite;
123853524e44Schristos 		data = (char *)data + towrite;
12399accf4dfSjdolecek 		*initp += init;
12409accf4dfSjdolecek 	}
12419accf4dfSjdolecek 
12429accf4dfSjdolecek 	return (error);
12439accf4dfSjdolecek }
12449accf4dfSjdolecek 
12459accf4dfSjdolecek /*
124614c96698Smaxv  * This is one of the write routines.
12479accf4dfSjdolecek  *
12489accf4dfSjdolecek  * ntnode should be locked.
12499accf4dfSjdolecek  */
12509accf4dfSjdolecek int
ntfs_writentvattr_plain(struct ntfsmount * ntmp,struct ntnode * ip,struct ntvattr * vap,off_t roff,size_t rsize,void * rdata,size_t * initp,struct uio * uio)12516387e674Smaxv ntfs_writentvattr_plain(struct ntfsmount *ntmp, struct ntnode *ip,
12526387e674Smaxv     struct ntvattr *vap, off_t roff, size_t rsize, void *rdata, size_t *initp,
12539accf4dfSjdolecek     struct uio *uio)
12549accf4dfSjdolecek {
12559accf4dfSjdolecek 	int error = 0;
1256aa112c89Schristos 	off_t off;
12579accf4dfSjdolecek 	int cnt;
12589accf4dfSjdolecek 	cn_t ccn, ccl, cn, left, cl;
125953524e44Schristos 	void *data = rdata;
12605d2bff06Shannken 	daddr_t lbn;
12619accf4dfSjdolecek 	struct buf *bp;
12629accf4dfSjdolecek 	size_t tocopy;
12639accf4dfSjdolecek 
12649accf4dfSjdolecek 	*initp = 0;
12659accf4dfSjdolecek 
12669accf4dfSjdolecek 	if ((vap->va_flag & NTFS_AF_INRUN) == 0) {
1267fd460520Schristos 		dprintf(("%s: CAN'T WRITE RES. ATTRIBUTE\n", __func__));
12689accf4dfSjdolecek 		return ENOTTY;
12699accf4dfSjdolecek 	}
12709accf4dfSjdolecek 
1271609d5cf3Sdsl 	ddprintf(("%s: data in run: %lu chains\n", __func__,
12729accf4dfSjdolecek 		 vap->va_vruncnt));
12739accf4dfSjdolecek 
12749accf4dfSjdolecek 	off = roff;
12759accf4dfSjdolecek 	left = rsize;
12769accf4dfSjdolecek 	ccl = 0;
12779accf4dfSjdolecek 	ccn = 0;
12789accf4dfSjdolecek 	cnt = 0;
12799accf4dfSjdolecek 	for (; left && (cnt < vap->va_vruncnt); cnt++) {
12809accf4dfSjdolecek 		ccn = vap->va_vruncn[cnt];
12819accf4dfSjdolecek 		ccl = vap->va_vruncl[cnt];
12829accf4dfSjdolecek 
1283fd460520Schristos 		ddprintf(("%s: left %qu, cn: 0x%qx, cl: %qu, off: %qd\n",
1284fd460520Schristos 		    __func__, (long long) left, (long long) ccn,
1285aa112c89Schristos 		    (long long) ccl, (long long) off));
12869accf4dfSjdolecek 
12879accf4dfSjdolecek 		if (ntfs_cntob(ccl) < off) {
12889accf4dfSjdolecek 			off -= ntfs_cntob(ccl);
12899accf4dfSjdolecek 			cnt++;
12909accf4dfSjdolecek 			continue;
12919accf4dfSjdolecek 		}
12929accf4dfSjdolecek 		if (!ccn && ip->i_number != NTFS_BOOTINO)
12939accf4dfSjdolecek 			continue; /* XXX */
12949accf4dfSjdolecek 
12959accf4dfSjdolecek 		ccl -= ntfs_btocn(off);
12969accf4dfSjdolecek 		cn = ccn + ntfs_btocn(off);
12979accf4dfSjdolecek 		off = ntfs_btocnoff(off);
12989accf4dfSjdolecek 
12999accf4dfSjdolecek 		while (left && ccl) {
1300877dee10Sjdolecek 			/*
1301877dee10Sjdolecek 			 * Always read and write single clusters at a time -
1302877dee10Sjdolecek 			 * we need to avoid requesting differently-sized
1303877dee10Sjdolecek 			 * blocks at the same disk offsets to avoid
1304877dee10Sjdolecek 			 * confusing the buffer cache.
1305877dee10Sjdolecek 			 */
130628302c22Sjdolecek 			tocopy = MIN(left, ntfs_cntob(1) - off);
13079accf4dfSjdolecek 			cl = ntfs_btocl(tocopy + off);
1308877dee10Sjdolecek 			KASSERT(cl == 1 && tocopy <= ntfs_cntob(1));
1309fd460520Schristos 			ddprintf(("%s: write: cn: 0x%qx cl: %qu, off: %qd "
1310fd460520Schristos 			    "len: %qu, left: %qu\n", __func__,
1311aa112c89Schristos 			    (long long) cn, (long long) cl,
1312aa112c89Schristos 			    (long long) off, (long long) tocopy,
1313aa112c89Schristos 			    (long long) left));
13146387e674Smaxv 			if ((off == 0) && (tocopy == ntfs_cntob(cl))) {
13155d2bff06Shannken 				lbn = ntfs_cntobn(cn);
13165d2bff06Shannken 				bp = getblk(ntmp->ntm_devvp, lbn,
13179accf4dfSjdolecek 					    ntfs_cntob(cl), 0, 0);
13189accf4dfSjdolecek 				clrbuf(bp);
13199accf4dfSjdolecek 			} else {
13209accf4dfSjdolecek 				error = bread(ntmp->ntm_devvp, ntfs_cntobn(cn),
13216e392401Smaxv 				    ntfs_cntob(cl), B_MODIFY, &bp);
13226387e674Smaxv 				if (error)
13239accf4dfSjdolecek 					return (error);
13249accf4dfSjdolecek 			}
13259accf4dfSjdolecek 			if (uio)
132653524e44Schristos 				uiomove((char *)bp->b_data + off, tocopy, uio);
13279accf4dfSjdolecek 			else
132853524e44Schristos 				memcpy((char *)bp->b_data + off, data, tocopy);
13299accf4dfSjdolecek 			bawrite(bp);
133053524e44Schristos 			data = (char *)data + tocopy;
13319accf4dfSjdolecek 			*initp += tocopy;
13329accf4dfSjdolecek 			off = 0;
13339accf4dfSjdolecek 			left -= tocopy;
13349accf4dfSjdolecek 			cn += cl;
13359accf4dfSjdolecek 			ccl -= cl;
13369accf4dfSjdolecek 		}
13379accf4dfSjdolecek 	}
13389accf4dfSjdolecek 
13399accf4dfSjdolecek 	if (left) {
1340fd460520Schristos 		printf("%s: POSSIBLE RUN ERROR\n", __func__);
13419accf4dfSjdolecek 		error = EINVAL;
13429accf4dfSjdolecek 	}
13439accf4dfSjdolecek 
13449accf4dfSjdolecek 	return (error);
13459accf4dfSjdolecek }
13469accf4dfSjdolecek 
13479accf4dfSjdolecek /*
134814c96698Smaxv  * This is one of the read routines.
13499accf4dfSjdolecek  *
13509accf4dfSjdolecek  * ntnode should be locked.
13519accf4dfSjdolecek  */
13529accf4dfSjdolecek int
ntfs_readntvattr_plain(struct ntfsmount * ntmp,struct ntnode * ip,struct ntvattr * vap,off_t roff,size_t rsize,void * rdata,size_t * initp,struct uio * uio)13536387e674Smaxv ntfs_readntvattr_plain(struct ntfsmount *ntmp, struct ntnode *ip,
13546387e674Smaxv     struct ntvattr *vap, off_t roff, size_t rsize, void *rdata, size_t *initp,
13559accf4dfSjdolecek     struct uio *uio)
13569accf4dfSjdolecek {
13579accf4dfSjdolecek 	int error = 0;
1358aa112c89Schristos 	off_t off;
13599accf4dfSjdolecek 
13609accf4dfSjdolecek 	*initp = 0;
13619accf4dfSjdolecek 	if (vap->va_flag & NTFS_AF_INRUN) {
13629accf4dfSjdolecek 		int cnt;
13639accf4dfSjdolecek 		cn_t ccn, ccl, cn, left, cl;
136453524e44Schristos 		void *data = rdata;
13659accf4dfSjdolecek 		struct buf *bp;
13669accf4dfSjdolecek 		size_t tocopy;
13679accf4dfSjdolecek 
1368fd460520Schristos 		ddprintf(("%s: data in run: %lu chains\n", __func__,
13699accf4dfSjdolecek 			 vap->va_vruncnt));
13709accf4dfSjdolecek 
13719accf4dfSjdolecek 		off = roff;
13729accf4dfSjdolecek 		left = rsize;
13739accf4dfSjdolecek 		ccl = 0;
13749accf4dfSjdolecek 		ccn = 0;
13759accf4dfSjdolecek 		cnt = 0;
13769accf4dfSjdolecek 		while (left && (cnt < vap->va_vruncnt)) {
13779accf4dfSjdolecek 			ccn = vap->va_vruncn[cnt];
13789accf4dfSjdolecek 			ccl = vap->va_vruncl[cnt];
13799accf4dfSjdolecek 
1380fd460520Schristos 			ddprintf(("%s: left %qu, cn: 0x%qx, cl: %qu, "
1381fd460520Schristos 			    "off: %qd\n", __func__,
1382aa112c89Schristos 			    (long long) left, (long long) ccn,
1383aa112c89Schristos 			    (long long) ccl, (long long) off));
13849accf4dfSjdolecek 
13859accf4dfSjdolecek 			if (ntfs_cntob(ccl) < off) {
13869accf4dfSjdolecek 				off -= ntfs_cntob(ccl);
13879accf4dfSjdolecek 				cnt++;
13889accf4dfSjdolecek 				continue;
13899accf4dfSjdolecek 			}
13909accf4dfSjdolecek 			if (ccn || ip->i_number == NTFS_BOOTINO) {
13919accf4dfSjdolecek 				ccl -= ntfs_btocn(off);
13929accf4dfSjdolecek 				cn = ccn + ntfs_btocn(off);
13939accf4dfSjdolecek 				off = ntfs_btocnoff(off);
13949accf4dfSjdolecek 
13959accf4dfSjdolecek 				while (left && ccl) {
13969accf4dfSjdolecek 					/*
1397877dee10Sjdolecek 					 * Always read single clusters at a
1398877dee10Sjdolecek 					 * time - we need to avoid reading
1399877dee10Sjdolecek 					 * differently-sized blocks at the
1400877dee10Sjdolecek 					 * same disk offsets to avoid
1401877dee10Sjdolecek 					 * confusing the buffer cache.
14029accf4dfSjdolecek 					 */
140328302c22Sjdolecek 					tocopy = MIN(left,
1404877dee10Sjdolecek 					    ntfs_cntob(1) - off);
1405877dee10Sjdolecek 					cl = ntfs_btocl(tocopy + off);
1406877dee10Sjdolecek 					KASSERT(cl == 1 &&
1407877dee10Sjdolecek 					    tocopy <= ntfs_cntob(1));
14089accf4dfSjdolecek 
1409fd460520Schristos 					ddprintf(("%s: read: cn: 0x%qx cl: %qu,"
1410aa112c89Schristos 					    " off: %qd len: %qu, left: %qu\n",
1411fd460520Schristos 					    __func__, (long long) cn,
1412aa112c89Schristos 					    (long long) cl,
1413aa112c89Schristos 					    (long long) off,
1414aa112c89Schristos 					    (long long) tocopy,
1415aa112c89Schristos 					    (long long) left));
14169accf4dfSjdolecek 					error = bread(ntmp->ntm_devvp,
14179accf4dfSjdolecek 						      ntfs_cntobn(cn),
14189accf4dfSjdolecek 						      ntfs_cntob(cl),
14196e392401Smaxv 						      0, &bp);
14209accf4dfSjdolecek 					if (error) {
14219accf4dfSjdolecek 						return (error);
14229accf4dfSjdolecek 					}
14239accf4dfSjdolecek 					if (uio) {
142453524e44Schristos 						uiomove((char *)bp->b_data + off,
14259accf4dfSjdolecek 							tocopy, uio);
14269accf4dfSjdolecek 					} else {
142753524e44Schristos 						memcpy(data, (char *)bp->b_data + off,
14289accf4dfSjdolecek 							tocopy);
14299accf4dfSjdolecek 					}
14309f56dfa5Sad 					brelse(bp, 0);
143153524e44Schristos 					data = (char *)data + tocopy;
14329accf4dfSjdolecek 					*initp += tocopy;
14339accf4dfSjdolecek 					off = 0;
14349accf4dfSjdolecek 					left -= tocopy;
14359accf4dfSjdolecek 					cn += cl;
14369accf4dfSjdolecek 					ccl -= cl;
14379accf4dfSjdolecek 				}
14389accf4dfSjdolecek 			} else {
143928302c22Sjdolecek 				tocopy = MIN(left, ntfs_cntob(ccl) - off);
1440fd460520Schristos 				ddprintf(("%s: hole: ccn: 0x%qx ccl: %qu, "
1441fd460520Schristos 				    "off: %qd, len: %qu, left: %qu\n", __func__,
1442aa112c89Schristos 				    (long long) ccn, (long long) ccl,
1443aa112c89Schristos 				    (long long) off, (long long) tocopy,
1444aa112c89Schristos 				    (long long) left));
14459accf4dfSjdolecek 				left -= tocopy;
14469accf4dfSjdolecek 				off = 0;
14479accf4dfSjdolecek 				if (uio) {
1448a29d4b25Schristos 					char vbuf[] = "";
14499accf4dfSjdolecek 					size_t remains = tocopy;
14509accf4dfSjdolecek 					for (; remains; remains--)
1451a29d4b25Schristos 						uiomove(vbuf, 1, uio);
14529accf4dfSjdolecek 				} else
1453c363a9cbScegger 					memset(data, 0, tocopy);
145453524e44Schristos 				data = (char *)data + tocopy;
14559accf4dfSjdolecek 			}
14569accf4dfSjdolecek 			cnt++;
14579accf4dfSjdolecek 		}
14589accf4dfSjdolecek 		if (left) {
1459fd460520Schristos 			printf("%s: POSSIBLE RUN ERROR\n", __func__);
14609accf4dfSjdolecek 			error = E2BIG;
14619accf4dfSjdolecek 		}
14629accf4dfSjdolecek 	} else {
1463fd460520Schristos 		ddprintf(("%s: data is in mft record\n", __func__));
14649accf4dfSjdolecek 		if (uio)
146553524e44Schristos 			uiomove((char *)vap->va_datap + roff, rsize, uio);
14669accf4dfSjdolecek 		else
146753524e44Schristos 			memcpy(rdata, (char *)vap->va_datap + roff, rsize);
14689accf4dfSjdolecek 		*initp += rsize;
14699accf4dfSjdolecek 	}
14709accf4dfSjdolecek 
14719accf4dfSjdolecek 	return (error);
14729accf4dfSjdolecek }
14739accf4dfSjdolecek 
14749accf4dfSjdolecek /*
147514c96698Smaxv  * This is one of the read routines.
14769accf4dfSjdolecek  */
14779accf4dfSjdolecek int
ntfs_readattr_plain(struct ntfsmount * ntmp,struct ntnode * ip,u_int32_t attrnum,const char * attrname,off_t roff,size_t rsize,void * rdata,size_t * initp,struct uio * uio)14786387e674Smaxv ntfs_readattr_plain(struct ntfsmount *ntmp, struct ntnode *ip,
14796387e674Smaxv     u_int32_t attrnum, const char *attrname, off_t roff, size_t rsize,
14806387e674Smaxv     void *rdata, size_t *initp, struct uio *uio)
14819accf4dfSjdolecek {
14829accf4dfSjdolecek 	size_t init;
14839accf4dfSjdolecek 	int error = 0;
14849accf4dfSjdolecek 	off_t off = roff, left = rsize, toread;
148553524e44Schristos 	void *data = rdata;
14869accf4dfSjdolecek 	struct ntvattr *vap;
14879accf4dfSjdolecek 	*initp = 0;
14889accf4dfSjdolecek 
14899accf4dfSjdolecek 	while (left) {
14909accf4dfSjdolecek 		error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname,
14919accf4dfSjdolecek 		    ntfs_btocn(off), &vap);
14929accf4dfSjdolecek 		if (error)
14939accf4dfSjdolecek 			return (error);
149428302c22Sjdolecek 		toread = MIN(left, ntfs_cntob(vap->va_vcnend + 1) - off);
1495fd460520Schristos 		ddprintf(("%s: o: %qd, s: %qd (%qu - %qu)\n", __func__,
1496aa112c89Schristos 		    (long long) off, (long long) toread,
1497aa112c89Schristos 		    (long long) vap->va_vcnstart,
1498aa112c89Schristos 		    (long long) vap->va_vcnend));
14999accf4dfSjdolecek 		error = ntfs_readntvattr_plain(ntmp, ip, vap,
15009accf4dfSjdolecek 		    off - ntfs_cntob(vap->va_vcnstart),
15019accf4dfSjdolecek 		    toread, data, &init, uio);
15029accf4dfSjdolecek 		if (error) {
1503fd460520Schristos 			printf("%s: ntfs_readntvattr_plain failed: o: %qd, "
1504fd460520Schristos 			    "s: %qd\n", __func__,
1505aa112c89Schristos 			    (long long) off, (long long) toread);
1506fd460520Schristos 			printf("%s: attrib: %qu - %qu\n", __func__,
1507aa112c89Schristos 			    (long long) vap->va_vcnstart,
1508aa112c89Schristos 			    (long long) vap->va_vcnend);
15099accf4dfSjdolecek 			ntfs_ntvattrrele(vap);
15109accf4dfSjdolecek 			break;
15119accf4dfSjdolecek 		}
15129accf4dfSjdolecek 		ntfs_ntvattrrele(vap);
15139accf4dfSjdolecek 		left -= toread;
15149accf4dfSjdolecek 		off += toread;
151553524e44Schristos 		data = (char *)data + toread;
15169accf4dfSjdolecek 		*initp += init;
15179accf4dfSjdolecek 	}
15189accf4dfSjdolecek 
15199accf4dfSjdolecek 	return (error);
15209accf4dfSjdolecek }
15219accf4dfSjdolecek 
15229accf4dfSjdolecek /*
152314c96698Smaxv  * This is one of the read routines.
15249accf4dfSjdolecek  */
15259accf4dfSjdolecek int
ntfs_readattr(struct ntfsmount * ntmp,struct ntnode * ip,u_int32_t attrnum,const char * attrname,off_t roff,size_t rsize,void * rdata,struct uio * uio)15266387e674Smaxv ntfs_readattr(struct ntfsmount *ntmp, struct ntnode *ip, u_int32_t attrnum,
15276387e674Smaxv     const char *attrname, off_t roff, size_t rsize, void *rdata,
15289accf4dfSjdolecek     struct uio *uio)
15299accf4dfSjdolecek {
15309accf4dfSjdolecek 	int error = 0;
15319accf4dfSjdolecek 	struct ntvattr *vap;
15329accf4dfSjdolecek 	size_t init;
15339accf4dfSjdolecek 
1534fd460520Schristos 	ddprintf(("%s: reading %llu: 0x%x, from %qd size %qu bytes\n",
1535fd460520Schristos 	    __func__, (unsigned long long)ip->i_number, attrnum,
1536f229ea7fSchristos 	    (long long)roff, (long long)rsize));
15379accf4dfSjdolecek 
15389accf4dfSjdolecek 	error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname, 0, &vap);
15399accf4dfSjdolecek 	if (error)
15409accf4dfSjdolecek 		return (error);
15419accf4dfSjdolecek 
15429accf4dfSjdolecek 	if ((roff > vap->va_datalen) ||
15439accf4dfSjdolecek 	    (roff + rsize > vap->va_datalen)) {
1544fd460520Schristos 		printf("%s: offset too big: %qd (%qd) > %qu\n", __func__,
1545aa112c89Schristos 		    (long long) roff, (long long) (roff + rsize),
1546aa112c89Schristos 		    (long long) vap->va_datalen);
15479accf4dfSjdolecek 		ntfs_ntvattrrele(vap);
15489accf4dfSjdolecek 		return (E2BIG);
15499accf4dfSjdolecek 	}
15509accf4dfSjdolecek 	if (vap->va_compression && vap->va_compressalg) {
15516387e674Smaxv 		u_int8_t *cup, *uup;
1552d2b8f70eSmatt 		off_t off, left, tocopy;
1553d2b8f70eSmatt 		void *data;
15549accf4dfSjdolecek 		cn_t cn;
15559accf4dfSjdolecek 
1556c22fbb82Schristos 		left = rsize;
1557c22fbb82Schristos 		data = rdata;
1558fd460520Schristos 		ddprintf(("%s: compression: %d\n", __func__,
15599accf4dfSjdolecek 		    vap->va_compressalg));
15609accf4dfSjdolecek 
15615a57baa4Schristos 		cup = malloc(ntfs_cntob(NTFS_COMPUNIT_CL),
15629accf4dfSjdolecek 		    M_NTFSDECOMP, M_WAITOK);
15635a57baa4Schristos 		uup = malloc(ntfs_cntob(NTFS_COMPUNIT_CL),
15649accf4dfSjdolecek 		    M_NTFSDECOMP, M_WAITOK);
15659accf4dfSjdolecek 
15669accf4dfSjdolecek 		cn = (ntfs_btocn(roff)) & (~(NTFS_COMPUNIT_CL - 1));
15679accf4dfSjdolecek 		off = roff - ntfs_cntob(cn);
15689accf4dfSjdolecek 
15699accf4dfSjdolecek 		while (left) {
15709accf4dfSjdolecek 			error = ntfs_readattr_plain(ntmp, ip, attrnum,
15719accf4dfSjdolecek 			    attrname, ntfs_cntob(cn),
15726387e674Smaxv 			    ntfs_cntob(NTFS_COMPUNIT_CL), cup, &init, NULL);
15739accf4dfSjdolecek 			if (error)
15749accf4dfSjdolecek 				break;
15759accf4dfSjdolecek 
157628302c22Sjdolecek 			tocopy = MIN(left, ntfs_cntob(NTFS_COMPUNIT_CL) - off);
15779accf4dfSjdolecek 
15789accf4dfSjdolecek 			if (init == ntfs_cntob(NTFS_COMPUNIT_CL)) {
15799accf4dfSjdolecek 				if (uio)
15809accf4dfSjdolecek 					uiomove(cup + off, tocopy, uio);
15819accf4dfSjdolecek 				else
15829accf4dfSjdolecek 					memcpy(data, cup + off, tocopy);
15839accf4dfSjdolecek 			} else if (init == 0) {
15849accf4dfSjdolecek 				if (uio) {
1585a29d4b25Schristos 					char vbuf[] = "";
15869accf4dfSjdolecek 					size_t remains = tocopy;
15879accf4dfSjdolecek 					for (; remains; remains--)
1588a29d4b25Schristos 						uiomove(vbuf, 1, uio);
15899accf4dfSjdolecek 				}
15909accf4dfSjdolecek 				else
1591c363a9cbScegger 					memset(data, 0, tocopy);
15929accf4dfSjdolecek 			} else {
15939accf4dfSjdolecek 				error = ntfs_uncompunit(ntmp, uup, cup);
15949accf4dfSjdolecek 				if (error)
15959accf4dfSjdolecek 					break;
15969accf4dfSjdolecek 				if (uio)
15979accf4dfSjdolecek 					uiomove(uup + off, tocopy, uio);
15989accf4dfSjdolecek 				else
15999accf4dfSjdolecek 					memcpy(data, uup + off, tocopy);
16009accf4dfSjdolecek 			}
16019accf4dfSjdolecek 
16029accf4dfSjdolecek 			left -= tocopy;
160353524e44Schristos 			data = (char *)data + tocopy;
16049accf4dfSjdolecek 			off += tocopy - ntfs_cntob(NTFS_COMPUNIT_CL);
16059accf4dfSjdolecek 			cn += NTFS_COMPUNIT_CL;
16069accf4dfSjdolecek 		}
16079accf4dfSjdolecek 
16089b87d582Scegger 		free(uup, M_NTFSDECOMP);
16099b87d582Scegger 		free(cup, M_NTFSDECOMP);
16109accf4dfSjdolecek 	} else
16119accf4dfSjdolecek 		error = ntfs_readattr_plain(ntmp, ip, attrnum, attrname,
16129accf4dfSjdolecek 		    roff, rsize, rdata, &init, uio);
16139accf4dfSjdolecek 	ntfs_ntvattrrele(vap);
16149accf4dfSjdolecek 	return (error);
16159accf4dfSjdolecek }
16169accf4dfSjdolecek 
16179accf4dfSjdolecek #if UNUSED_CODE
16189accf4dfSjdolecek int
ntfs_parserun(cn_t * cn,cn_t * cl,u_int8_t * run,u_long len,u_long * off)16196387e674Smaxv ntfs_parserun(cn_t *cn, cn_t *cl, u_int8_t *run, u_long len, u_long *off)
16209accf4dfSjdolecek {
16219accf4dfSjdolecek 	u_int8_t sz;
16229accf4dfSjdolecek 	int i;
16239accf4dfSjdolecek 
16249accf4dfSjdolecek 	if (NULL == run) {
1625fd460520Schristos 		printf("%s: run == NULL\n", __func__);
16269accf4dfSjdolecek 		return (EINVAL);
16279accf4dfSjdolecek 	}
16289accf4dfSjdolecek 	sz = run[(*off)++];
16299accf4dfSjdolecek 	if (0 == sz) {
1630fd460520Schristos 		printf("%s: trying to go out of run\n", __func__);
16319accf4dfSjdolecek 		return (E2BIG);
16329accf4dfSjdolecek 	}
16339accf4dfSjdolecek 	*cl = 0;
16349accf4dfSjdolecek 	if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) {
1635fd460520Schristos 		printf("%s: bad run: length too big: sz: 0x%02x "
1636fd460520Schristos 		    "(%ld < %ld + sz)\n", __func__, sz, len, *off);
16379accf4dfSjdolecek 		return (EINVAL);
16389accf4dfSjdolecek 	}
16399accf4dfSjdolecek 	for (i = 0; i < (sz & 0xF); i++)
16409accf4dfSjdolecek 		*cl += (u_int32_t) run[(*off)++] << (i << 3);
16419accf4dfSjdolecek 
16429accf4dfSjdolecek 	sz >>= 4;
16439accf4dfSjdolecek 	if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) {
1644fd460520Schristos 		printf("%s: bad run: length too big: sz: 0x%02x "
1645fd460520Schristos 		    "(%ld < %ld + sz)\n", __func__, sz, len, *off);
16469accf4dfSjdolecek 		return (EINVAL);
16479accf4dfSjdolecek 	}
16489accf4dfSjdolecek 	for (i = 0; i < (sz & 0xF); i++)
16499accf4dfSjdolecek 		*cn += (u_int32_t) run[(*off)++] << (i << 3);
16509accf4dfSjdolecek 
16519accf4dfSjdolecek 	return (0);
16529accf4dfSjdolecek }
16539accf4dfSjdolecek #endif
16549accf4dfSjdolecek 
16559accf4dfSjdolecek /*
16569accf4dfSjdolecek  * Process fixup routine on given buffer.
16579accf4dfSjdolecek  */
16589accf4dfSjdolecek int
ntfs_procfixups(struct ntfsmount * ntmp,u_int32_t magic,void * xbufv,size_t len)16596387e674Smaxv ntfs_procfixups(struct ntfsmount *ntmp, u_int32_t magic, void *xbufv,
16609accf4dfSjdolecek     size_t len)
16619accf4dfSjdolecek {
166253524e44Schristos 	char *xbuf = xbufv;
1663a29d4b25Schristos 	struct fixuphdr *fhp = (struct fixuphdr *) xbuf;
16649accf4dfSjdolecek 	int i;
16659accf4dfSjdolecek 	u_int16_t fixup;
16666387e674Smaxv 	u_int16_t *fxp, *cfxp;
16679accf4dfSjdolecek 
1668fd460520Schristos 	if (fhp->fh_magic == 0)
1669fd460520Schristos 		return (EINVAL);
16709accf4dfSjdolecek 	if (fhp->fh_magic != magic) {
1671fd460520Schristos 		printf("%s: magic doesn't match: %08x != %08x\n", __func__,
16729accf4dfSjdolecek 		    fhp->fh_magic, magic);
16739accf4dfSjdolecek 		return (EINVAL);
16749accf4dfSjdolecek 	}
16759accf4dfSjdolecek 	if ((fhp->fh_fnum - 1) * ntmp->ntm_bps != len) {
1676fd460520Schristos 		printf("%s: bad fixups number: %d for %ld bytes block\n",
1677fd460520Schristos 		    __func__, fhp->fh_fnum, (long)len);	/* XXX printf kludge */
16789accf4dfSjdolecek 		return (EINVAL);
16799accf4dfSjdolecek 	}
16809accf4dfSjdolecek 	if (fhp->fh_foff >= ntmp->ntm_spc * ntmp->ntm_mftrecsz * ntmp->ntm_bps) {
1681fd460520Schristos 		printf("%s: invalid offset: %x", __func__, fhp->fh_foff);
16829accf4dfSjdolecek 		return (EINVAL);
16839accf4dfSjdolecek 	}
1684a29d4b25Schristos 	fxp = (u_int16_t *) (xbuf + fhp->fh_foff);
1685a29d4b25Schristos 	cfxp = (u_int16_t *) (xbuf + ntmp->ntm_bps - 2);
16869accf4dfSjdolecek 	fixup = *fxp++;
16879accf4dfSjdolecek 	for (i = 1; i < fhp->fh_fnum; i++, fxp++) {
16889accf4dfSjdolecek 		if (*cfxp != fixup) {
1689fd460520Schristos 			printf("%s: fixup %d doesn't match\n", __func__, i);
16909accf4dfSjdolecek 			return (EINVAL);
16919accf4dfSjdolecek 		}
16929accf4dfSjdolecek 		*cfxp = *fxp;
169353524e44Schristos 		cfxp = (u_int16_t *)((char *)cfxp + ntmp->ntm_bps);
16949accf4dfSjdolecek 	}
16959accf4dfSjdolecek 	return (0);
16969accf4dfSjdolecek }
16979accf4dfSjdolecek 
16989accf4dfSjdolecek #if UNUSED_CODE
16999accf4dfSjdolecek int
ntfs_runtocn(cn_t * cn,struct ntfsmount * ntmp,u_int8_t * run,u_long len,cn_t vcn)17006387e674Smaxv ntfs_runtocn(cn_t *cn, struct ntfsmount *ntmp, u_int8_t *run, u_long len,
17019accf4dfSjdolecek     cn_t vcn)
17029accf4dfSjdolecek {
17036387e674Smaxv 	cn_t ccn = 0, ccl = 0;
17049accf4dfSjdolecek 	u_long off = 0;
17059accf4dfSjdolecek 	int error = 0;
17069accf4dfSjdolecek 
1707f229ea7fSchristos #ifdef NTFS_DEBUG
17089accf4dfSjdolecek 	int i;
1709fd460520Schristos 	printf("%s: run: %p, %ld bytes, vcn:%ld\n", __func__,
17109accf4dfSjdolecek 	    run, len, (u_long) vcn);
1711fd460520Schristos 	printf("%s: run: ", __func__);
17129accf4dfSjdolecek 	for (i = 0; i < len; i++)
17139accf4dfSjdolecek 		printf("0x%02x ", run[i]);
17149accf4dfSjdolecek 	printf("\n");
17159accf4dfSjdolecek #endif
17169accf4dfSjdolecek 
17179accf4dfSjdolecek 	if (NULL == run) {
1718fd460520Schristos 		printf("%s: run == NULL\n", __func__);
17199accf4dfSjdolecek 		return (EINVAL);
17209accf4dfSjdolecek 	}
17219accf4dfSjdolecek 	do {
17229accf4dfSjdolecek 		if (run[off] == 0) {
1723fd460520Schristos 			printf("%s: vcn too big\n", __func__);
17249accf4dfSjdolecek 			return (E2BIG);
17259accf4dfSjdolecek 		}
17269accf4dfSjdolecek 		vcn -= ccl;
17279accf4dfSjdolecek 		error = ntfs_parserun(&ccn, &ccl, run, len, &off);
17289accf4dfSjdolecek 		if (error) {
1729fd460520Schristos 			printf("%s: ntfs_parserun failed\n", __func__);
17309accf4dfSjdolecek 			return (error);
17319accf4dfSjdolecek 		}
17329accf4dfSjdolecek 	} while (ccl <= vcn);
17339accf4dfSjdolecek 	*cn = ccn + vcn;
17349accf4dfSjdolecek 	return (0);
17359accf4dfSjdolecek }
17369accf4dfSjdolecek #endif
17379accf4dfSjdolecek 
17389accf4dfSjdolecek /*
17394cbd24b2Swiz  * this initializes toupper table & dependent variables to be ready for
17409accf4dfSjdolecek  * later work
17419accf4dfSjdolecek  */
17429accf4dfSjdolecek void
ntfs_toupper_init(void)1743b8817e4aScegger ntfs_toupper_init(void)
17449accf4dfSjdolecek {
17457f3d4048Splunky 	ntfs_toupper_tab = NULL;
17469abeea58Sad 	mutex_init(&ntfs_toupper_lock, MUTEX_DEFAULT, IPL_NONE);
17479accf4dfSjdolecek 	ntfs_toupper_usecount = 0;
17489accf4dfSjdolecek }
17499accf4dfSjdolecek 
17509accf4dfSjdolecek /*
17519accf4dfSjdolecek  * if the ntfs_toupper_tab[] is filled already, just raise use count;
17529accf4dfSjdolecek  * otherwise read the data from the filesystem we are currently mounting
17539accf4dfSjdolecek  */
17549accf4dfSjdolecek int
ntfs_toupper_use(struct mount * mp,struct ntfsmount * ntmp)1755454af1c0Sdsl ntfs_toupper_use(struct mount *mp, struct ntfsmount *ntmp)
17569accf4dfSjdolecek {
17579accf4dfSjdolecek 	int error = 0;
17589accf4dfSjdolecek 	struct vnode *vp;
17599accf4dfSjdolecek 
17609accf4dfSjdolecek 	/* get exclusive access */
17619abeea58Sad 	mutex_enter(&ntfs_toupper_lock);
17629accf4dfSjdolecek 
17639accf4dfSjdolecek 	/* only read the translation data from a file if it hasn't been
17649accf4dfSjdolecek 	 * read already */
17659accf4dfSjdolecek 	if (ntfs_toupper_tab)
17669accf4dfSjdolecek 		goto out;
17679accf4dfSjdolecek 
17689accf4dfSjdolecek 	/*
17699accf4dfSjdolecek 	 * Read in Unicode lowercase -> uppercase translation file.
17709accf4dfSjdolecek 	 * XXX for now, just the first 256 entries are used anyway,
17719accf4dfSjdolecek 	 * so don't bother reading more
17729accf4dfSjdolecek 	 */
1773fd460520Schristos 	ntfs_toupper_tab = malloc(256 * 256 * sizeof(*ntfs_toupper_tab),
17749accf4dfSjdolecek 	    M_NTFSRDATA, M_WAITOK);
17759accf4dfSjdolecek 
1776c2e9cb94Sad 	if ((error = VFS_VGET(mp, NTFS_UPCASEINO, LK_EXCLUSIVE, &vp)))
17779accf4dfSjdolecek 		goto out;
17789accf4dfSjdolecek 	error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL,
1779fd460520Schristos 	    0, 256 * 256 * sizeof(*ntfs_toupper_tab), (char *)ntfs_toupper_tab,
17809accf4dfSjdolecek 	    NULL);
17819accf4dfSjdolecek 	vput(vp);
17829accf4dfSjdolecek 
17839accf4dfSjdolecek out:
17849accf4dfSjdolecek 	ntfs_toupper_usecount++;
17859abeea58Sad 	mutex_exit(&ntfs_toupper_lock);
17869accf4dfSjdolecek 	return (error);
17879accf4dfSjdolecek }
17889accf4dfSjdolecek 
17899accf4dfSjdolecek /*
17909accf4dfSjdolecek  * lower the use count and if it reaches zero, free the memory
17919accf4dfSjdolecek  * tied by toupper table
17929accf4dfSjdolecek  */
17939accf4dfSjdolecek void
ntfs_toupper_unuse(void)1794b8817e4aScegger ntfs_toupper_unuse(void)
17959accf4dfSjdolecek {
17969accf4dfSjdolecek 	/* get exclusive access */
17979abeea58Sad 	mutex_enter(&ntfs_toupper_lock);
17989accf4dfSjdolecek 
17999accf4dfSjdolecek 	ntfs_toupper_usecount--;
18009accf4dfSjdolecek 	if (ntfs_toupper_usecount == 0) {
18019b87d582Scegger 		free(ntfs_toupper_tab, M_NTFSRDATA);
18029accf4dfSjdolecek 		ntfs_toupper_tab = NULL;
18039accf4dfSjdolecek 	}
18049accf4dfSjdolecek #ifdef DIAGNOSTIC
18059accf4dfSjdolecek 	else if (ntfs_toupper_usecount < 0) {
18069accf4dfSjdolecek 		panic("ntfs_toupper_unuse(): use count negative: %d",
18079accf4dfSjdolecek 			ntfs_toupper_usecount);
18089accf4dfSjdolecek 	}
18099accf4dfSjdolecek #endif
18109accf4dfSjdolecek 
18119accf4dfSjdolecek 	/* release the lock */
18129abeea58Sad 	mutex_exit(&ntfs_toupper_lock);
18139accf4dfSjdolecek }
1814