File:  [DragonFly] / src / sys / vfs / ntfs / ntfs_subr.c
Revision 1.11: download - view: text, annotated - select for diffs
Mon Mar 1 06:33:22 2004 UTC (10 years, 4 months ago) by dillon
Branches: MAIN
CVS tags: HEAD
Newtoken commit.  Change the token implementation as follows:  (1) Obtaining
a token no longer enters a critical section.  (2) tokens can be held through
schedular switches and blocking conditions and are effectively released and
reacquired on resume.  Thus tokens serialize access only while the thread
is actually running.  Serialization is not broken by preemptive interrupts.
That is, interrupt threads which preempt do no release the preempted thread's
tokens.  (3) Unlike spl's, tokens will interlock w/ interrupt threads on
the same or on a different cpu.

The vnode interlock code has been rewritten and the API has changed.  The
mountlist vnode scanning code has been consolidated and all known races have
been fixed.  The vnode interlock is now a pool token.

The code that frees unreferenced vnodes whos last VM page has been freed has
been moved out of the low level vm_page_free() code and moved to the
periodic filesystem sycer code in vfs_msycn().

The SMP startup code and the IPI code has been cleaned up considerably.
Certain early token interactions on AP cpus have been moved to the BSP.

The LWKT rwlock API has been cleaned up and turned on.

Major testing by: David Rhodus

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