ntfs_subr.c revision 50477
118334Speter/*	$NetBSD: ntfs_subr.c,v 1.2 1999/05/06 15:43:19 christos Exp $	*/
290075Sobrien
3169689Skan/*-
4169689Skan * Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org)
518334Speter * All rights reserved.
690075Sobrien *
718334Speter * Redistribution and use in source and binary forms, with or without
890075Sobrien * modification, are permitted provided that the following conditions
990075Sobrien * are met:
1090075Sobrien * 1. Redistributions of source code must retain the above copyright
1190075Sobrien *    notice, this list of conditions and the following disclaimer.
1218334Speter * 2. Redistributions in binary form must reproduce the above copyright
1390075Sobrien *    notice, this list of conditions and the following disclaimer in the
1490075Sobrien *    documentation and/or other materials provided with the distribution.
1590075Sobrien *
1690075Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1718334Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1818334Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1990075Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20169689Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21169689Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2218334Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2318334Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2418334Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2518334Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2618334Speter * SUCH DAMAGE.
2718334Speter *
2818334Speter * $FreeBSD: head/sys/fs/ntfs/ntfs_subr.c 50477 1999-08-28 01:08:13Z peter $
2918334Speter */
3018334Speter
31117395Skan#include <sys/param.h>
3218334Speter#include <sys/types.h>
3318334Speter#include <sys/systm.h>
3450397Sobrien#include <sys/namei.h>
35132718Skan#include <sys/proc.h>
36132718Skan#include <sys/kernel.h>
3750397Sobrien#include <sys/vnode.h>
3850397Sobrien#include <sys/mount.h>
39117395Skan#include <sys/buf.h>
4090075Sobrien#include <sys/file.h>
4150397Sobrien#include <sys/malloc.h>
4250397Sobrien#if defined(__FreeBSD__)
4350397Sobrien#include <machine/clock.h>
4490075Sobrien#endif
4590075Sobrien
4690075Sobrien/* #define NTFS_DEBUG 1 */
4790075Sobrien#include <ntfs/ntfs.h>
4890075Sobrien#include <ntfs/ntfsmount.h>
49169689Skan#include <ntfs/ntfs_inode.h>
50169689Skan#include <ntfs/ntfs_vfsops.h>
51169689Skan#include <ntfs/ntfs_extern.h>
52169689Skan#include <ntfs/ntfs_subr.h>
53169689Skan#include <ntfs/ntfs_compr.h>
5418334Speter#include <ntfs/ntfs_ihash.h>
55169689Skan
56169689Skan#if defined(__FreeBSD__)
57169689SkanMALLOC_DEFINE(M_NTFSNTVATTR, "NTFS vattr", "NTFS file attribute information");
58169689SkanMALLOC_DEFINE(M_NTFSRDATA, "NTFS res data", "NTFS resident data");
59169689SkanMALLOC_DEFINE(M_NTFSRUN, "NTFS vrun", "NTFS vrun storage");
60169689SkanMALLOC_DEFINE(M_NTFSDECOMP, "NTFS decomp", "NTFS decompression temporary");
61169689Skan#endif
62169689Skan
63169689Skan/*
64169689Skan *
65169689Skan */
66169689Skanint
67169689Skanntfs_ntvattrrele(
68169689Skan		 struct ntvattr * vap)
69169689Skan{
70169689Skan	dprintf(("ntfs_ntvattrrele: ino: %d, type: 0x%x\n",
71169689Skan		 vap->va_ip->i_number, vap->va_type));
72260311Spfg
73260311Spfg	ntfs_ntrele(vap->va_ip);
74260311Spfg
75260311Spfg	return (0);
7690075Sobrien}
77132718Skan
7818334Speter/*
79117395Skan * Search attribute specifed in ntnode (load ntnode if nessecary).
8018334Speter * If not found but ATTR_A_ATTRLIST present, read it in and search throught.
8118334Speter * VOP_VGET node needed, and lookup througth it's ntnode (load if nessesary).
8290075Sobrien *
8390075Sobrien * ntnode should be locked
8418334Speter */
85132718Skanint
8690075Sobrienntfs_ntvattrget(
8718334Speter		struct ntfsmount * ntmp,
8818334Speter		struct ntnode * ip,
8918334Speter		u_int32_t type,
9018334Speter		char *name,
9118334Speter		cn_t vcn,
9218334Speter		struct ntvattr ** vapp)
9318334Speter{
9418334Speter	int             error;
9518334Speter	struct ntvattr *vap;
9618334Speter	struct ntvattr *lvap = NULL;
9718334Speter	struct attr_attrlist *aalp;
98169689Skan	struct attr_attrlist *nextaalp;
99169689Skan	caddr_t         alpool;
100169689Skan	int             len, namelen;
101169689Skan
10218334Speter	*vapp = NULL;
10318334Speter
104169689Skan	if (name) {
105169689Skan		dprintf(("ntfs_ntvattrget: " \
10618334Speter			 "ino: %d, type: 0x%x, name: %s, vcn: %d\n", \
107117395Skan			 ip->i_number, type, name, (u_int32_t) vcn));
10818334Speter		namelen = strlen(name);
10918334Speter	} else {
110132718Skan		dprintf(("ntfs_ntvattrget: " \
11118334Speter			 "ino: %d, type: 0x%x, vcn: %d\n", \
112132718Skan			 ip->i_number, type, (u_int32_t) vcn));
11318334Speter		name = "";
11490075Sobrien		namelen = 0;
11590075Sobrien	}
11650397Sobrien
117117395Skan	if((ip->i_flag & IN_LOADED) == 0) {
11818334Speter		dprintf(("ntfs_ntvattrget: node not loaded, ino: %d\n",
11990075Sobrien		       ip->i_number));
12090075Sobrien		error = ntfs_loadntnode(ntmp,ip);
12190075Sobrien		if(error) {
12218334Speter			printf("ntfs_ntvattrget: FAILED TO LOAD INO: %d\n",
12390075Sobrien			       ip->i_number);
12490075Sobrien			return (error);
12518334Speter		}
12690075Sobrien	}
12790075Sobrien
12890075Sobrien	for (vap = ip->i_valist.lh_first; vap; vap = vap->va_list.le_next) {
12990075Sobrien		ddprintf(("type: 0x%x, vcn: %d - %d\n", \
13090075Sobrien			  vap->va_type, (u_int32_t) vap->va_vcnstart, \
13190075Sobrien			  (u_int32_t) vap->va_vcnend));
13218334Speter		if ((vap->va_type == type) &&
133117395Skan		    (vap->va_vcnstart <= vcn) && (vap->va_vcnend >= vcn) &&
134117395Skan		    (vap->va_namelen == namelen) &&
13518334Speter		    (!strncmp(name, vap->va_name, namelen))) {
136169689Skan			*vapp = vap;
137169689Skan			ntfs_ntref(vap->va_ip);
138169689Skan			return (0);
139169689Skan		}
140169689Skan		if (vap->va_type == NTFS_A_ATTRLIST)
141169689Skan			lvap = vap;
142169689Skan	}
143169689Skan
144169689Skan	if (!lvap) {
145169689Skan		dprintf(("ntfs_ntvattrget: UNEXISTED ATTRIBUTE: " \
146169689Skan		       "ino: %d, type: 0x%x, name: %s, vcn: %d\n", \
147169689Skan		       ip->i_number, type, name, (u_int32_t) vcn));
148169689Skan		return (ENOENT);
149169689Skan	}
150169689Skan	/* Scan $ATTRIBUTE_LIST for requested attribute */
151169689Skan	len = lvap->va_datalen;
152169689Skan	MALLOC(alpool, caddr_t, len, M_TEMP, M_WAITOK);
153169689Skan	error = ntfs_readntvattr_plain(ntmp, ip, lvap, 0, len, alpool, &len);
154169689Skan	if (error)
155169689Skan		goto out;
156169689Skan
157169689Skan	aalp = (struct attr_attrlist *) alpool;
158169689Skan	nextaalp = NULL;
159169689Skan
160169689Skan	while (len > 0) {
161169689Skan		dprintf(("ntfs_ntvattrget: " \
162169689Skan			 "attrlist: ino: %d, attr: 0x%x, vcn: %d\n", \
163169689Skan			 aalp->al_inumber, aalp->al_type, \
164132718Skan			 (u_int32_t) aalp->al_vcnstart));
165132718Skan
166132718Skan		if (len > aalp->reclen) {
167169689Skan			nextaalp = NTFS_NEXTREC(aalp, struct attr_attrlist *);
168169689Skan		} else {
169132718Skan			nextaalp = NULL;
170169689Skan		}
171169689Skan		len -= aalp->reclen;
172132718Skan
173169689Skan#define AALPCMP(aalp,type,name,namelen) (				\
174169689Skan  (aalp->al_type == type) && (aalp->al_namelen == namelen) &&		\
17518334Speter  !uastrcmp(aalp->al_name,aalp->al_namelen,name,namelen) )
17690075Sobrien
17790075Sobrien		if (AALPCMP(aalp, type, name, namelen) &&
178169689Skan		    (!nextaalp || (nextaalp->al_vcnstart > vcn) ||
179169689Skan		     !AALPCMP(nextaalp, type, name, namelen))) {
180169689Skan			struct vnode   *newvp;
181169689Skan			struct ntnode  *newip;
182169689Skan
183169689Skan			dprintf(("ntfs_ntvattrget: attrbute in ino: %d\n",
184169689Skan				 aalp->al_inumber));
185169689Skan
186169689Skan/*
187169689Skan			error = VFS_VGET(ntmp->ntm_mountp, aalp->al_inumber,
188169689Skan					 &newvp);
189169689Skan*/
190169689Skan			error = ntfs_vgetex(ntmp->ntm_mountp, aalp->al_inumber,
191169689Skan					NTFS_A_DATA, NULL, LK_EXCLUSIVE,
192169689Skan					VG_EXT, curproc, &newvp);
193169689Skan			if (error) {
194169689Skan				printf("ntfs_ntvattrget: CAN'T VGET INO: %d\n",
195169689Skan				       aalp->al_inumber);
196169689Skan				goto out;
197169689Skan			}
198169689Skan			newip = VTONT(newvp);
199169689Skan			/* XXX have to lock ntnode */
200169689Skan			if(~newip->i_flag & IN_LOADED) {
201169689Skan				dprintf(("ntfs_ntvattrget: node not loaded," \
202169689Skan					 " ino: %d\n", newip->i_number));
203169689Skan				error = ntfs_loadntnode(ntmp,ip);
204169689Skan				if(error) {
205169689Skan					printf("ntfs_ntvattrget: CAN'T LOAD " \
206169689Skan					       "INO: %d\n", newip->i_number);
207169689Skan					vput(newvp);
208169689Skan					goto out;
209169689Skan				}
210169689Skan			}
211169689Skan			for (vap = newip->i_valist.lh_first; vap; vap = vap->va_list.le_next) {
212169689Skan				if ((vap->va_type == type) &&
213169689Skan				    (vap->va_vcnstart <= vcn) &&
214169689Skan				    (vap->va_vcnend >= vcn) &&
215169689Skan				    (vap->va_namelen == namelen) &&
216169689Skan				  (!strncmp(name, vap->va_name, namelen))) {
21790075Sobrien					*vapp = vap;
218117395Skan					ntfs_ntref(vap->va_ip);
21918334Speter					vput(newvp);
22018334Speter					error = 0;
221132718Skan					goto out;
22218334Speter				}
22390075Sobrien				if (vap->va_type == NTFS_A_ATTRLIST)
224132718Skan					lvap = vap;
225132718Skan			}
226169689Skan			printf("ntfs_ntvattrget: ATTRLIST ERROR.\n");
227169689Skan			vput(newvp);
228169689Skan			break;
229169689Skan		}
230169689Skan#undef AALPCMP
231169689Skan		aalp = nextaalp;
232169689Skan	}
233169689Skan	error = ENOENT;
234169689Skan
235169689Skan	dprintf(("ntfs_ntvattrget: UNEXISTED ATTRIBUTE: " \
236169689Skan	       "ino: %d, type: 0x%x, name: %s, vcn: %d\n", \
237169689Skan	       ip->i_number, type, name, (u_int32_t) vcn));
238169689Skanout:
239169689Skan	FREE(alpool, M_TEMP);
240169689Skan	return (error);
241169689Skan}
242169689Skan
243169689Skan/*
244169689Skan * Read ntnode from disk, make ntvattr list.
245169689Skan *
246169689Skan * ntnode should be locked
247169689Skan */
248169689Skanint
249169689Skanntfs_loadntnode(
250169689Skan	      struct ntfsmount * ntmp,
251169689Skan	      struct ntnode * ip)
252169689Skan{
253169689Skan	struct filerec  *mfrp;
254169689Skan	daddr_t         bn;
255169689Skan	int		error,off;
256169689Skan	struct attr    *ap;
257169689Skan	struct ntvattr *nvap;
258169689Skan
259169689Skan	dprintf(("ntfs_loadnode: loading ino: %d\n",ip->i_number));
260169689Skan
261169689Skan	MALLOC(mfrp, struct filerec *, ntfs_bntob(ntmp->ntm_bpmftrec),
262169689Skan	       M_TEMP, M_WAITOK);
263169689Skan
264169689Skan	if (ip->i_number < NTFS_SYSNODESNUM) {
265169689Skan		struct buf     *bp;
266169689Skan
267169689Skan		dprintf(("ntfs_loadnode: read system node\n"));
268169689Skan
269169689Skan		bn = ntfs_cntobn(ntmp->ntm_mftcn) +
270169689Skan			ntmp->ntm_bpmftrec * ip->i_number;
271169689Skan
272169689Skan		error = bread(ntmp->ntm_devvp,
273169689Skan			      bn, ntfs_bntob(ntmp->ntm_bpmftrec),
274169689Skan			      NOCRED, &bp);
275169689Skan		if (error) {
276169689Skan			printf("ntfs_loadnode: BREAD FAILED\n");
277169689Skan			brelse(bp);
278169689Skan			goto out;
279169689Skan		}
280169689Skan		memcpy(mfrp, bp->b_data, ntfs_bntob(ntmp->ntm_bpmftrec));
281169689Skan		bqrelse(bp);
282169689Skan	} else {
283169689Skan		struct vnode   *vp;
284169689Skan
285169689Skan		vp = ntmp->ntm_sysvn[NTFS_MFTINO];
286169689Skan		error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL,
287169689Skan			       ip->i_number * ntfs_bntob(ntmp->ntm_bpmftrec),
288169689Skan			       ntfs_bntob(ntmp->ntm_bpmftrec), mfrp);
289169689Skan		if (error) {
290169689Skan			printf("ntfs_loadnode: ntfs_readattr failed\n");
291169689Skan			goto out;
292169689Skan		}
293169689Skan	}
294169689Skan
295169689Skan	/* Check if magic and fixups are correct */
296169689Skan	error = ntfs_procfixups(ntmp, NTFS_FILEMAGIC, (caddr_t)mfrp,
297169689Skan				ntfs_bntob(ntmp->ntm_bpmftrec));
298169689Skan	if (error) {
29918334Speter		printf("ntfs_loadnode: BAD MFT RECORD %d\n",
30018334Speter		       (u_int32_t) ip->i_number);
30118334Speter		goto out;
302117395Skan	}
303117395Skan
304117395Skan	dprintf(("ntfs_loadnode: load attrs for ino: %d\n",ip->i_number));
305117395Skan	off = mfrp->fr_attroff;
306132718Skan	ap = (struct attr *) ((caddr_t)mfrp + off);
30718334Speter
308117395Skan	LIST_INIT(&ip->i_valist);
309169689Skan
310169689Skan	while (ap->a_hdr.a_type != -1) {
31118334Speter		error = ntfs_attrtontvattr(ntmp, &nvap, ap);
31218334Speter		if (error)
313169689Skan			break;
314169689Skan		nvap->va_ip = ip;
315169689Skan
31690075Sobrien		LIST_INSERT_HEAD(&ip->i_valist, nvap, va_list);
317169689Skan
31818334Speter		off += ap->a_hdr.reclen;
31990075Sobrien		ap = (struct attr *) ((caddr_t)mfrp + off);
32090075Sobrien	}
321169689Skan	if (error) {
322169689Skan		printf("ntfs_loadnode: failed to load attr ino: %d\n",
323169689Skan		       ip->i_number);
324169689Skan		goto out;
325169689Skan	}
326169689Skan
327169689Skan	ip->i_mainrec = mfrp->fr_mainrec;
328169689Skan	ip->i_nlink = mfrp->fr_nlink;
329169689Skan	ip->i_frflag = mfrp->fr_flags;
330169689Skan
331169689Skan	ip->i_flag |= IN_LOADED;
332169689Skan
333169689Skanout:
334169689Skan	FREE(mfrp, M_TEMP);
335169689Skan	return (error);
336169689Skan}
337169689Skan
338169689Skan/*
339169689Skan * Routine locks ntnode and increase usecount, just opposite of
340169689Skan * ntfs_ntput.
341169689Skan */
342169689Skanint
343169689Skanntfs_ntget(
344169689Skan	   struct ntnode *ip)
345169689Skan{
346169689Skan	dprintf(("ntfs_ntget: get ntnode %d: %p, usecount: %d\n",
347169689Skan		ip->i_number, ip, ip->i_usecount));
348169689Skan
349169689Skan	ip->i_usecount++;
35050397Sobrien
351169689Skanrestart:
35290075Sobrien	if (ip->i_lock) {
35318334Speter		while (ip->i_lock) {
354169689Skan			ip->i_lock = -1;
355169689Skan			tsleep(&ip->i_lock, PVM, "ntnode", 0);
356169689Skan		}
357169689Skan		goto restart;
358169689Skan	}
359169689Skan	ip->i_lock = 1;
36090075Sobrien
361169689Skan	return 0;
36218334Speter}
363169689Skan
364132718Skan/*
365132718Skan * Routine search ntnode in hash, if found: lock, inc usecount and return.
366132718Skan * If not in hash allocate structure for ntnode, prefill it, lock,
367132718Skan * inc count and return.
368132718Skan *
369132718Skan * ntnode returned locked
370169689Skan */
371132718Skanstatic int ntfs_ntnode_hash_lock;
372169689Skanint
373132718Skanntfs_ntlookup(
37418334Speter	   struct ntfsmount * ntmp,
375169689Skan	   ino_t ino,
376132718Skan	   struct ntnode ** ipp)
377132718Skan{
378132718Skan	struct ntnode  *ip;
379132718Skan
38018334Speter	dprintf(("ntfs_ntlookup: for ntnode %d\n", ino));
381132718Skan	*ipp = NULL;
382132718Skan
383132718Skanrestart:
384169689Skan	ip = ntfs_nthashlookup(ntmp->ntm_dev, ino); /* XXX */
385169689Skan	if (ip) {
386169689Skan		ntfs_ntget(ip);
387169689Skan		*ipp = ip;
388169689Skan		dprintf(("ntfs_ntlookup: ntnode %d: %p, usecount: %d\n",
389169689Skan			ino, ip, ip->i_usecount));
390169689Skan
391169689Skan		return (0);
392169689Skan	}
393169689Skan
394169689Skan	if (ntfs_ntnode_hash_lock) {
395132718Skan		while(ntfs_ntnode_hash_lock) {
396169689Skan			ntfs_ntnode_hash_lock = -1;
397132718Skan			tsleep(&ntfs_ntnode_hash_lock, PVM, "ntfsntgt", 0);
398132718Skan		}
39990075Sobrien		goto restart;
400169689Skan	}
40190075Sobrien	ntfs_ntnode_hash_lock = 1;
40218334Speter
40318334Speter	MALLOC(ip, struct ntnode *, sizeof(struct ntnode),
404169689Skan	       M_NTFSNTNODE, M_WAITOK);
405169689Skan	ddprintf(("ntfs_ntlookup: allocating ntnode: %d: %p\n", ino, ip));
406169689Skan	bzero((caddr_t) ip, sizeof(struct ntnode));
407169689Skan
408169689Skan	/* Generic initialization */
409169689Skan	ip->i_number = ino;
410169689Skan	ip->i_mp = ntmp;
411169689Skan	ip->i_dev = ntmp->ntm_dev;
412169689Skan	ip->i_uid = ntmp->ntm_uid;
413169689Skan	ip->i_gid = ntmp->ntm_gid;
414169689Skan	ip->i_mode = ntmp->ntm_mode;
41518334Speter	ip->i_usecount++;
416169689Skan
417169689Skan	ip->i_lock = 1;
418169689Skan
419169689Skan	LIST_INIT(&ip->i_fnlist);
420169689Skan
421169689Skan	ntfs_nthashins(ip);
422169689Skan
423169689Skan	if (ntfs_ntnode_hash_lock < 0)
424169689Skan		wakeup(&ntfs_ntnode_hash_lock);
425169689Skan	ntfs_ntnode_hash_lock = 0;
426169689Skan
427169689Skan	*ipp = ip;
428169689Skan
429169689Skan	dprintf(("ntfs_ntlookup: ntnode %d: %p, usecount: %d\n",
430169689Skan		ino, ip, ip->i_usecount));
431169689Skan
432169689Skan	return (0);
433169689Skan}
434169689Skan
435169689Skan/*
436169689Skan * Decrement usecount of ntnode and unlock it, if usecount reach zero,
437169689Skan * deallocate ntnode.
438169689Skan *
439169689Skan * ntnode should be locked on entry, and unlocked on return.
440169689Skan */
441169689Skanvoid
442169689Skanntfs_ntput(
44318334Speter	   struct ntnode *ip)
44418334Speter{
44518334Speter	struct ntvattr *vap;
446169689Skan
44718334Speter	if (!ip->i_lock) printf("ntfs_ntput: NOT LOCKED");
44890075Sobrien
449169689Skan	dprintf(("ntfs_ntput: rele ntnode %d: %p, usecount: %d\n",
450169689Skan		ip->i_number, ip, ip->i_usecount));
45150397Sobrien
45290075Sobrien	ip->i_usecount--;
453117395Skan
45418334Speter	if (ip->i_usecount < 0) {
45518334Speter		panic("ntfs_ntput: ino: %d usecount: %d \n",
456169689Skan		      ip->i_number,ip->i_usecount);
45718334Speter	} else if (ip->i_usecount == 0) {
45818334Speter		dprintf(("ntfs_ntput: deallocating ntnode: %d\n",
45918334Speter			ip->i_number));
460169689Skan
46118334Speter		if (ip->i_fnlist.lh_first)
46218334Speter			panic("ntfs_ntput: ntnode has fnodes\n");
46318334Speter
464169689Skan		ntfs_nthashrem(ip);
46518334Speter
46690075Sobrien		while (ip->i_valist.lh_first != NULL) {
46790075Sobrien			vap = ip->i_valist.lh_first;
468169689Skan			LIST_REMOVE(vap,va_list);
46918334Speter			ntfs_freentvattr(vap);
47090075Sobrien		}
47190075Sobrien		FREE(ip, M_NTFSNTNODE);
472169689Skan	} else {
473169689Skan		if (ip->i_lock < 0)
474169689Skan			wakeup(&ip->i_lock);
475169689Skan		ip->i_lock = 0;
47618334Speter	}
47718334Speter}
47818334Speter
479169689Skan/*
48018334Speter * Decrement usecount of ntnode.
48118334Speter */
48218334Spetervoid
483169689Skanntfs_ntrele(
484169689Skan	    struct ntnode * ip)
485169689Skan{
486169689Skan	dprintf(("ntfs_ntrele: rele ntnode %d: %p, usecount: %d\n",
487169689Skan		ip->i_number, ip, ip->i_usecount));
488169689Skan
489169689Skan	ip->i_usecount--;
490169689Skan
491169689Skan	if (ip->i_usecount < 0)
492169689Skan		panic("ntfs_ntrele: ino: %d usecount: %d \n",
493169689Skan		      ip->i_number,ip->i_usecount);
494169689Skan}
495169689Skan
496169689Skan/*
497169689Skan * Deallocate all memory allocated for ntvattr by call to
498169689Skan * ntfs_attrtontvattr and some other functions.
499169689Skan */
500169689Skanvoid
501169689Skanntfs_freentvattr(
502169689Skan		 struct ntvattr * vap)
503169689Skan{
504169689Skan	if (vap->va_flag & NTFS_AF_INRUN) {
505169689Skan		if (vap->va_vruncn)
506169689Skan			FREE(vap->va_vruncn, M_NTFSRUN);
507169689Skan		if (vap->va_vruncl)
508169689Skan			FREE(vap->va_vruncl, M_NTFSRUN);
509169689Skan	} else {
510169689Skan		if (vap->va_datap)
511169689Skan			FREE(vap->va_datap, M_NTFSRDATA);
512169689Skan	}
513169689Skan	FREE(vap, M_NTFSNTVATTR);
514169689Skan}
515169689Skan
516169689Skan/*
517169689Skan * Convert disk image of attribute into ntvattr structure,
51818334Speter * runs are expanded also.
519169689Skan */
52018334Speterint
521169689Skanntfs_attrtontvattr(
52218334Speter		   struct ntfsmount * ntmp,
52318334Speter		   struct ntvattr ** rvapp,
52490075Sobrien		   struct attr * rap)
52590075Sobrien{
52618334Speter	int             error, i;
52718334Speter	struct ntvattr *vap;
528169689Skan
529169689Skan	error = 0;
530169689Skan	*rvapp = NULL;
531169689Skan
53290075Sobrien	MALLOC(vap, struct ntvattr *, sizeof(struct ntvattr),
533132718Skan		M_NTFSNTVATTR, M_WAITOK);
53490075Sobrien	bzero(vap, sizeof(struct ntvattr));
53518334Speter	vap->va_ip = NULL;
53618334Speter	vap->va_flag = rap->a_hdr.a_flag;
53718334Speter	vap->va_type = rap->a_hdr.a_type;
53818334Speter	vap->va_compression = rap->a_hdr.a_compression;
539169689Skan	vap->va_index = rap->a_hdr.a_index;
54018334Speter
54118334Speter	ddprintf(("type: 0x%x, index: %d", vap->va_type, vap->va_index));
54218334Speter
543169689Skan	vap->va_namelen = rap->a_hdr.a_namelen;
544169689Skan	if (rap->a_hdr.a_namelen) {
545169689Skan		wchar *unp = (wchar *) ((caddr_t) rap + rap->a_hdr.a_nameoff);
546169689Skan		ddprintf((", name:["));
547169689Skan		for (i = 0; i < vap->va_namelen; i++) {
548258748Spfg			vap->va_name[i] = unp[i];
549258748Spfg			ddprintf(("%c", vap->va_name[i]));
550258748Spfg		}
551258748Spfg		ddprintf(("]"));
552258748Spfg	}
553258748Spfg	if (vap->va_flag & NTFS_AF_INRUN) {
554169689Skan		ddprintf((", nonres."));
555169689Skan		vap->va_datalen = rap->a_nr.a_datalen;
556169689Skan		vap->va_allocated = rap->a_nr.a_allocated;
557169689Skan		vap->va_vcnstart = rap->a_nr.a_vcnstart;
558132718Skan		vap->va_vcnend = rap->a_nr.a_vcnend;
55918334Speter		vap->va_compressalg = rap->a_nr.a_compressalg;
56090075Sobrien		error = ntfs_runtovrun(&(vap->va_vruncn), &(vap->va_vruncl),
56118334Speter				       &(vap->va_vruncnt),
56218334Speter				       (caddr_t) rap + rap->a_nr.a_dataoff);
563169689Skan	} else {
56418334Speter		vap->va_compressalg = 0;
565169689Skan		ddprintf((", res."));
56690075Sobrien		vap->va_datalen = rap->a_r.a_datalen;
56718334Speter		vap->va_allocated = rap->a_r.a_datalen;
56890075Sobrien		vap->va_vcnstart = 0;
56990075Sobrien		vap->va_vcnend = ntfs_btocn(vap->va_allocated);
57018334Speter		MALLOC(vap->va_datap, caddr_t, vap->va_datalen,
571169689Skan		       M_NTFSRDATA, M_WAITOK);
57290075Sobrien		memcpy(vap->va_datap, (caddr_t) rap + rap->a_r.a_dataoff,
57390075Sobrien		       rap->a_r.a_datalen);
57450397Sobrien	}
57518334Speter	ddprintf((", len: %d", vap->va_datalen));
57618334Speter
577169689Skan	if (error)
57818334Speter		FREE(vap, M_NTFSNTVATTR);
579169689Skan	else
58018334Speter		*rvapp = vap;
58172562Sobrien
582169689Skan	ddprintf(("\n"));
58372562Sobrien
58472562Sobrien	return (error);
58572562Sobrien}
58672562Sobrien
58790075Sobrien/*
58872562Sobrien * Expand run into more utilizable and more memory eating format.
58972562Sobrien */
59072562Sobrienint
59172562Sobrienntfs_runtovrun(
59272562Sobrien	       cn_t ** rcnp,
59372562Sobrien	       cn_t ** rclp,
59472562Sobrien	       u_long * rcntp,
59572562Sobrien	       u_int8_t * run)
59672562Sobrien{
59772562Sobrien	u_int32_t       off;
59872562Sobrien	u_int32_t       sz, i;
59972562Sobrien	cn_t           *cn;
60072562Sobrien	cn_t           *cl;
601169689Skan	u_long		cnt;
602169689Skan	cn_t		prev;
603169689Skan	cn_t		tmp;
604169689Skan
60518334Speter	off = 0;
60618334Speter	cnt = 0;
60718334Speter	i = 0;
60818334Speter	while (run[off]) {
60918334Speter		off += (run[off] & 0xF) + ((run[off] >> 4) & 0xF) + 1;
61090075Sobrien		cnt++;
61190075Sobrien	}
61218334Speter	MALLOC(cn, cn_t *, cnt * sizeof(cn_t), M_NTFSRUN, M_WAITOK);
61318334Speter	MALLOC(cl, cn_t *, cnt * sizeof(cn_t), M_NTFSRUN, M_WAITOK);
614169689Skan
61518334Speter	off = 0;
61690075Sobrien	cnt = 0;
61790075Sobrien	prev = 0;
61890075Sobrien	while (run[off]) {
61918334Speter
620169689Skan		sz = run[off++];
621169689Skan		cl[cnt] = 0;
62290075Sobrien
623169689Skan		for (i = 0; i < (sz & 0xF); i++)
62452284Sobrien			cl[cnt] += (u_int32_t) run[off++] << (i << 3);
62518334Speter
62690075Sobrien		sz >>= 4;
62750397Sobrien		if (run[off + sz - 1] & 0x80) {
628169689Skan			tmp = ((u_int64_t) - 1) << (sz << 3);
629169689Skan			for (i = 0; i < sz; i++)
63018334Speter				tmp |= (u_int64_t) run[off++] << (i << 3);
631169689Skan		} else {
63218334Speter			tmp = 0;
633169689Skan			for (i = 0; i < sz; i++)
634169689Skan				tmp |= (u_int64_t) run[off++] << (i << 3);
635169689Skan		}
636169689Skan		if (tmp)
637169689Skan			prev = cn[cnt] = prev + tmp;
638169689Skan		else
639169689Skan			cn[cnt] = tmp;
640169689Skan
641169689Skan		cnt++;
642169689Skan	}
643169689Skan	*rcnp = cn;
644169689Skan	*rclp = cl;
645169689Skan	*rcntp = cnt;
646169689Skan	return (0);
647169689Skan}
648169689Skan
649169689Skan/*
650169689Skan * Convert wchar to uppercase wchar, should be macros?
651169689Skan */
652169689Skanwchar
65318334Speterntfs_toupper(
65450397Sobrien	     struct ntfsmount * ntmp,
65550397Sobrien	     wchar wc)
65650397Sobrien{
65750397Sobrien	return (ntmp->ntm_upcase[wc & 0xFF]);
65850397Sobrien}
65950397Sobrien
66050397Sobrien/*
661169689Skan * Compare to unicode strings case insensible.
662169689Skan */
663169689Skanint
664169689Skanntfs_uustricmp(
665169689Skan	       struct ntfsmount * ntmp,
666169689Skan	       wchar * str1,
667169689Skan	       int str1len,
66818334Speter	       wchar * str2,
66918334Speter	       int str2len)
67018334Speter{
67118334Speter	int             i;
67218334Speter	int             res;
67318334Speter
67418334Speter	for (i = 0; i < str1len && i < str2len; i++) {
67518334Speter		res = (int) ntfs_toupper(ntmp, str1[i]) -
67618334Speter			(int) ntfs_toupper(ntmp, str2[i]);
677132718Skan		if (res)
67818334Speter			return res;
67918334Speter	}
68090075Sobrien	return (str1len - str2len);
68118334Speter}
68218334Speter
68318334Speter/*
68418334Speter * Compare unicode and ascii string case insens.
68518334Speter */
68618334Speterint
68718334Speterntfs_uastricmp(
68818334Speter	       struct ntfsmount * ntmp,
68918334Speter	       const wchar *str1,
69018334Speter	       int str1len,
69118334Speter	       const char *str2,
69218334Speter	       int str2len)
69318334Speter{
69418334Speter	int             i;
69518334Speter	int             res;
69618334Speter
697169689Skan	for (i = 0; i < str1len && i < str2len; i++) {
69818334Speter		res = (int) ntfs_toupper(ntmp, str1[i]) -
699169689Skan			(int) ntfs_toupper(ntmp, (wchar) str2[i]);
700169689Skan		if (res)
701169689Skan			return res;
702169689Skan	}
703169689Skan	return (str1len - str2len);
70418334Speter}
705169689Skan
706169689Skan/*
70718334Speter * Compare unicode and ascii string case sens.
708169689Skan */
70918334Speterint
710169689Skanntfs_uastrcmp(
711169689Skan	      struct ntfsmount *ntmp,
71290075Sobrien	      const wchar *str1,
713169689Skan	      int str1len,
714169689Skan	      const char *str2,
715169689Skan	      int str2len)
716169689Skan{
717169689Skan	int             i;
718169689Skan	int             res;
719169689Skan
720169689Skan	for (i = 0; (i < str1len) && (i < str2len); i++) {
721169689Skan		res = ((int) str1[i]) - ((int) str2[i]);
722169689Skan		if (res)
723169689Skan			return res;
724169689Skan	}
725169689Skan	return (str1len - str2len);
726169689Skan}
727169689Skan
728169689Skan/*
729169689Skan * Search fnode in ntnode, if not found allocate and preinitialize.
730169689Skan *
731169689Skan * ntnode should be locked on entry.
732169689Skan */
733169689Skanint
734169689Skanntfs_fget(
735169689Skan	struct ntfsmount *ntmp,
736169689Skan	struct ntnode *ip,
737169689Skan	int attrtype,
738169689Skan	char *attrname,
739169689Skan	struct fnode **fpp)
740169689Skan{
741169689Skan	struct fnode *fp;
742169689Skan
743169689Skan	dprintf(("ntfs_fget: ino: %d, attrtype: 0x%x, attrname: %s\n",
744169689Skan		ip->i_number,attrtype, attrname?attrname:""));
745169689Skan	*fpp = NULL;
746169689Skan	for (fp = ip->i_fnlist.lh_first; fp != NULL; fp = fp->f_fnlist.le_next){
747169689Skan		dprintf(("ntfs_fget: fnode: attrtype: %d, attrname: %s\n",
748169689Skan			fp->f_attrtype, fp->f_attrname?fp->f_attrname:""));
749169689Skan
750169689Skan		if ((attrtype == fp->f_attrtype) &&
751169689Skan		    ((!attrname && !fp->f_attrname) ||
752169689Skan		     (attrname && fp->f_attrname &&
753169689Skan		      !strcmp(attrname,fp->f_attrname)))){
754169689Skan			dprintf(("ntfs_fget: found existed: %p\n",fp));
755169689Skan			*fpp = fp;
756169689Skan		}
757169689Skan	}
758169689Skan
759169689Skan	if (*fpp)
760169689Skan		return (0);
761169689Skan
762169689Skan	MALLOC(fp, struct fnode *, sizeof(struct fnode), M_NTFSFNODE, M_WAITOK);
763169689Skan	bzero(fp, sizeof(struct fnode));
764169689Skan	dprintf(("ntfs_fget: allocating fnode: %p\n",fp));
765169689Skan
766169689Skan	fp->f_devvp = ntmp->ntm_devvp;
767169689Skan	fp->f_dev = ntmp->ntm_dev;
768169689Skan	fp->f_mp = ntmp;
769169689Skan
770169689Skan	fp->f_ip = ip;
771169689Skan	fp->f_attrname = attrname;
772169689Skan	if (fp->f_attrname) fp->f_flag |= FN_AATTRNAME;
773169689Skan	fp->f_attrtype = attrtype;
774169689Skan
775169689Skan	ntfs_ntref(ip);
776169689Skan
777169689Skan	LIST_INSERT_HEAD(&ip->i_fnlist, fp, f_fnlist);
778169689Skan
779169689Skan	*fpp = fp;
780169689Skan
781169689Skan	return (0);
782169689Skan}
783169689Skan
784169689Skan/*
785169689Skan * Deallocate fnode, remove it from ntnode's fnode list.
786169689Skan *
787169689Skan * ntnode should be locked.
788169689Skan */
789169689Skanvoid
790169689Skanntfs_frele(
791169689Skan	struct fnode *fp)
792169689Skan{
793169689Skan	struct ntnode *ip = FTONT(fp);
794169689Skan
795169689Skan	dprintf(("ntfs_frele: fnode: %p for %d: %p\n", fp, ip->i_number, ip));
796169689Skan
797169689Skan	dprintf(("ntfs_frele: deallocating fnode\n"));
798169689Skan	LIST_REMOVE(fp,f_fnlist);
799169689Skan	if (fp->f_flag & FN_AATTRNAME)
800169689Skan		FREE(fp->f_attrname, M_TEMP);
801169689Skan	if (fp->f_dirblbuf)
802169689Skan		FREE(fp->f_dirblbuf, M_NTFSDIR);
803169689Skan	FREE(fp, M_NTFSFNODE);
804169689Skan	ntfs_ntrele(ip);
805169689Skan}
806169689Skan
807169689Skan/*
808169689Skan * Lookup attribute name in format: [[:$ATTR_TYPE]:$ATTR_NAME],
809169689Skan * $ATTR_TYPE is searched in attrdefs read from $AttrDefs.
810169689Skan * If $ATTR_TYPE nott specifed, ATTR_A_DATA assumed.
811169689Skan */
812169689Skanint
813169689Skanntfs_ntlookupattr(
814169689Skan		struct ntfsmount * ntmp,
815169689Skan		const char * name,
816169689Skan		int namelen,
817169689Skan		int *attrtype,
818169689Skan		char **attrname)
819169689Skan{
820169689Skan	const char *sys;
821169689Skan	size_t syslen, i;
822169689Skan	struct ntvattrdef *adp;
823169689Skan
824169689Skan	if (namelen == 0)
825169689Skan		return (0);
826169689Skan
827169689Skan	if (name[0] == '$') {
828169689Skan		sys = name;
829169689Skan		for (syslen = 0; syslen < namelen; syslen++) {
830169689Skan			if(sys[syslen] == ':') {
831169689Skan				name++;
832169689Skan				namelen--;
833169689Skan				break;
834169689Skan			}
835169689Skan		}
836169689Skan		name += syslen;
837169689Skan		namelen -= syslen;
838169689Skan
839169689Skan		adp = ntmp->ntm_ad;
840169689Skan		for (i = 0; i < ntmp->ntm_adnum; i++){
841169689Skan			if((syslen == adp->ad_namelen) &&
842169689Skan			   (!strncmp(sys,adp->ad_name,syslen))) {
843169689Skan				*attrtype = adp->ad_type;
844169689Skan				if(namelen) {
845169689Skan					MALLOC((*attrname), char *, namelen,
846169689Skan						M_TEMP, M_WAITOK);
847169689Skan					memcpy((*attrname), name, namelen);
848169689Skan					(*attrname)[namelen] = '\0';
849169689Skan				}
850169689Skan				return (0);
851169689Skan			}
852169689Skan			adp++;
853169689Skan		}
854169689Skan		return (ENOENT);
855169689Skan	}
856169689Skan
857169689Skan	if(namelen) {
858169689Skan		MALLOC((*attrname), char *, namelen, M_TEMP, M_WAITOK);
859169689Skan		memcpy((*attrname), name, namelen);
860169689Skan		(*attrname)[namelen] = '\0';
861169689Skan		*attrtype = NTFS_A_DATA;
862169689Skan	}
863169689Skan
864169689Skan	return (0);
865169689Skan}
866169689Skan
867169689Skan/*
868169689Skan * Lookup specifed node for filename, matching cnp,
869169689Skan * return fnode filled.
870169689Skan */
871169689Skanint
872169689Skanntfs_ntlookupfile(
873169689Skan	      struct ntfsmount * ntmp,
874169689Skan	      struct vnode * vp,
875169689Skan	      struct componentname * cnp,
876169689Skan	      struct vnode ** vpp)
877169689Skan{
878169689Skan	struct fnode   *fp = VTOF(vp);
879169689Skan	struct ntnode  *ip = FTONT(fp);
880169689Skan	struct ntvattr *vap;	/* Root attribute */
881169689Skan	cn_t            cn;	/* VCN in current attribute */
882169689Skan	caddr_t         rdbuf;	/* Buffer to read directory's blocks  */
883169689Skan	u_int32_t       blsize;
884169689Skan	u_int32_t       rdsize;	/* Length of data to read from current block */
885169689Skan	struct attr_indexentry *iep;
886169689Skan	int             error, res, anamelen, fnamelen;
887169689Skan	const char     *fname,*aname;
888169689Skan	u_int32_t       aoff;
889169689Skan
890169689Skan	error = ntfs_ntget(ip);
891169689Skan	if (error)
892169689Skan		return (error);
893169689Skan
894169689Skan	error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXROOT, "$I30", 0, &vap);
895169689Skan	if (error || (vap->va_flag & NTFS_AF_INRUN))
896169689Skan		return (ENOTDIR);
897169689Skan
898169689Skan	blsize = vap->va_a_iroot->ir_size;
899169689Skan	rdsize = vap->va_datalen;
900169689Skan
901169689Skan	/*
902169689Skan	 * Divide file name into: foofilefoofilefoofile[:attrspec]
903169689Skan	 * Store like this:       fname:fnamelen       [aname:anamelen]
904169689Skan	 */
905169689Skan	fname = cnp->cn_nameptr;
906169689Skan	aname = NULL;
907169689Skan	anamelen = 0;
908169689Skan	for (fnamelen = 0; fnamelen < cnp->cn_namelen; fnamelen++)
90918334Speter		if(fname[fnamelen] == ':') {
91018334Speter			aname = fname + fnamelen + 1;
91118334Speter			anamelen = cnp->cn_namelen - fnamelen - 1;
912169689Skan			dprintf(("ntfs_ntlookupfile: %s (%d), attr: %s (%d)\n",
913169689Skan				fname, fnamelen, aname, anamelen));
914169689Skan			break;
915169689Skan		}
916169689Skan
917169689Skan	dprintf(("ntfs_ntlookupfile: blksz: %d, rdsz: %d\n", blsize, rdsize));
918169689Skan
919169689Skan	MALLOC(rdbuf, caddr_t, blsize, M_TEMP, M_WAITOK);
920169689Skan
921169689Skan	error = ntfs_readattr(ntmp, ip, NTFS_A_INDXROOT, "$I30",
922169689Skan			       0, rdsize, rdbuf);
923169689Skan	if (error)
924169689Skan		goto fail;
925169689Skan
926169689Skan	aoff = sizeof(struct attr_indexroot);
927169689Skan
928169689Skan	do {
929169689Skan		iep = (struct attr_indexentry *) (rdbuf + aoff);
930169689Skan
931169689Skan		while (!(iep->ie_flag & NTFS_IEFLAG_LAST) && (rdsize > aoff)) {
932169689Skan			ddprintf(("scan: %d, %d\n",
933169689Skan				  (u_int32_t) iep->ie_number,
934169689Skan				  (u_int32_t) iep->ie_fnametype));
935169689Skan			res = ntfs_uastricmp(ntmp, iep->ie_fname,
936169689Skan					     iep->ie_fnamelen, fname,
937169689Skan					     fnamelen);
938169689Skan			if (res == 0) {
939169689Skan				/* Matched something (case ins.) */
940169689Skan				if (iep->ie_fnametype == 0 ||
941169689Skan				    !(ntmp->ntm_flag & NTFS_MFLAG_CASEINS))
942169689Skan					res = ntfs_uastrcmp(ntmp,
943169689Skan							    iep->ie_fname,
944169689Skan							    iep->ie_fnamelen,
945169689Skan							    fname,
946169689Skan							    fnamelen);
947169689Skan				if (res == 0) {
948169689Skan					int attrtype = NTFS_A_DATA;
949169689Skan					char *attrname = NULL;
950169689Skan					struct fnode   *nfp;
951169689Skan					struct vnode   *nvp;
952169689Skan
953169689Skan					if (aname) {
954169689Skan						error = ntfs_ntlookupattr(ntmp,
955169689Skan							aname, anamelen,
956169689Skan							&attrtype, &attrname);
957169689Skan						if (error)
958169689Skan							goto fail;
959169689Skan					}
960169689Skan
961169689Skan					/* Check if we've found ourself */
96296263Sobrien					if ((iep->ie_number == ip->i_number) &&
963169689Skan					    (attrtype == fp->f_attrtype) &&
96496263Sobrien					    ((!attrname && !fp->f_attrname) ||
96596263Sobrien					     (attrname && fp->f_attrname &&
966132718Skan					      !strcmp(attrname, fp->f_attrname)))) {
96796263Sobrien						VREF(vp);
96896263Sobrien						*vpp = vp;
96996263Sobrien						goto fail;
97096263Sobrien					}
97196263Sobrien
97296263Sobrien					/* vget node, but don't load it */
97396263Sobrien					error = ntfs_vgetex(ntmp->ntm_mountp,
97496263Sobrien							   iep->ie_number,
97596263Sobrien							   attrtype,
97696263Sobrien							   attrname,
97796263Sobrien							   LK_EXCLUSIVE,
97896263Sobrien							   VG_DONTLOADIN |
97996263Sobrien							    VG_DONTVALIDFN,
980169689Skan							   curproc,
981169689Skan							   &nvp);
982169689Skan					if(error)
983169689Skan						goto fail;
98496263Sobrien
98596263Sobrien					nfp = VTOF(nvp);
98696263Sobrien
987117395Skan					if (nfp->f_flag & FN_VALID) {
98896263Sobrien						*vpp = nvp;
98996263Sobrien						goto fail;
99096263Sobrien					}
99196263Sobrien
99296263Sobrien					nfp->f_fflag = iep->ie_fflag;
99396263Sobrien					nfp->f_pnumber = iep->ie_fpnumber;
994169689Skan					nfp->f_times = iep->ie_ftimes;
995169689Skan
996169689Skan					if((nfp->f_fflag & NTFS_FFLAG_DIR) &&
997169689Skan					   (nfp->f_attrtype == NTFS_A_DATA) &&
998169689Skan					   (nfp->f_attrname == NULL))
999169689Skan						nfp->f_type = VDIR;
1000169689Skan					else
1001169689Skan						nfp->f_type = VREG;
1002169689Skan
1003169689Skan					nvp->v_type = nfp->f_type;
1004169689Skan
1005169689Skan					if ((nfp->f_attrtype == NTFS_A_DATA) &&
1006169689Skan					    (nfp->f_attrname == NULL)) {
1007169689Skan						/* Opening default attribute */
1008169689Skan						nfp->f_size = iep->ie_fsize;
1009132718Skan						nfp->f_allocated = iep->ie_fallocated;
1010169689Skan						nfp->f_flag |= FN_PRELOADED;
1011132718Skan					} else {
1012169689Skan						error = ntfs_filesize(ntmp, nfp,
1013132718Skan							    &nfp->f_size,
1014132718Skan							    &nfp->f_allocated);
1015132718Skan						if (error) {
1016132718Skan							vput(nvp);
1017169689Skan							goto fail;
1018169689Skan						}
1019132718Skan					}
1020169689Skan
1021169689Skan					nfp->f_flag &= ~FN_VALID;
1022169689Skan					*vpp = nvp;
1023169689Skan					goto fail;
1024169689Skan				}
1025169689Skan			} else if (res > 0)
1026169689Skan				break;
1027169689Skan
1028169689Skan			aoff += iep->reclen;
1029169689Skan			iep = (struct attr_indexentry *) (rdbuf + aoff);
1030169689Skan		}
1031169689Skan
1032169689Skan		/* Dive if possible */
1033169689Skan		if (iep->ie_flag & NTFS_IEFLAG_SUBNODE) {
1034169689Skan			dprintf(("ntfs_ntlookupfile: diving\n"));
1035169689Skan
1036169689Skan			cn = *(cn_t *) (rdbuf + aoff +
1037169689Skan					iep->reclen - sizeof(cn_t));
1038169689Skan			rdsize = blsize;
1039169689Skan
1040169689Skan			error = ntfs_readattr(ntmp, ip, NTFS_A_INDX, "$I30",
1041169689Skan					     ntfs_cntob(cn), rdsize, rdbuf);
1042169689Skan			if (error)
1043169689Skan				goto fail;
1044169689Skan
1045169689Skan			error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC,
1046169689Skan						rdbuf, rdsize);
1047169689Skan			if (error)
1048169689Skan				goto fail;
1049132718Skan
1050132718Skan			aoff = (((struct attr_indexalloc *) rdbuf)->ia_hdrsize +
1051169689Skan				0x18);
1052169689Skan		} else {
1053169689Skan			dprintf(("ntfs_ntlookupfile: nowhere to dive :-(\n"));
1054169689Skan			error = ENOENT;
1055169689Skan			break;
1056169689Skan		}
1057169689Skan	} while (1);
1058169689Skan
1059169689Skan	dprintf(("finish\n"));
1060169689Skan
1061132718Skanfail:
1062132718Skan	ntfs_ntvattrrele(vap);
1063169689Skan	ntfs_ntput(ip);
1064169689Skan	FREE(rdbuf, M_TEMP);
1065169689Skan	return (error);
1066132718Skan}
1067132718Skan
1068169689Skan/*
106918334Speter * Check if name type is permitted to show.
107018334Speter */
107118334Speterint
1072132718Skanntfs_isnamepermitted(
107318334Speter		     struct ntfsmount * ntmp,
107418334Speter		     struct attr_indexentry * iep)
1075117395Skan{
107618334Speter
107718334Speter	if (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES)
1078117395Skan		return 1;
1079117395Skan
108018334Speter	switch (iep->ie_fnametype) {
108118334Speter	case 2:
1082117395Skan		ddprintf(("ntfs_isnamepermitted: skiped DOS name\n"));
1083117395Skan		return 0;
1084117395Skan	case 0: case 1: case 3:
108518334Speter		return 1;
1086117395Skan	default:
108718334Speter		printf("ntfs_isnamepermitted: " \
108818334Speter		       "WARNING! Unknown file name type: %d\n",
108918334Speter		       iep->ie_fnametype);
109018334Speter		break;
109118334Speter	}
109218334Speter	return 0;
109318334Speter}
109418334Speter
1095132718Skan/*
109618334Speter * Read ntfs dir like stream of attr_indexentry, not like btree of them.
109718334Speter * This is done by scaning $BITMAP:$I30 for busy clusters and reading them.
109818334Speter * Ofcouse $INDEX_ROOT:$I30 is read before. Last read values are stored in
109990075Sobrien * fnode, so we can skip toward record number num almost immediatly.
110090075Sobrien * Anyway this is rather slow routine. The problem is that we don't know
1101132718Skan * how many records are there in $INDEX_ALLOCATION:$I30 block.
110290075Sobrien */
1103132718Skanint
1104132718Skanntfs_ntreaddir(
1105169689Skan	       struct ntfsmount * ntmp,
110618334Speter	       struct fnode * fp,
110718334Speter	       u_int32_t num,
110818334Speter	       struct attr_indexentry ** riepp)
110990075Sobrien{
1110117395Skan	struct ntnode  *ip = FTONT(fp);
111118334Speter	struct ntvattr *vap = NULL;	/* IndexRoot attribute */
111218334Speter	struct ntvattr *bmvap = NULL;	/* BitMap attribute */
1113132718Skan	struct ntvattr *iavap = NULL;	/* IndexAllocation attribute */
111418334Speter	caddr_t         rdbuf;		/* Buffer to read directory's blocks  */
111518334Speter	u_char         *bmp = NULL;	/* Bitmap */
111618334Speter	u_int32_t       blsize;		/* Index allocation size (2048) */
111718334Speter	u_int32_t       rdsize;		/* Length of data to read */
1118117395Skan	u_int32_t       attrnum;	/* Current attribute type */
111918334Speter	u_int32_t       cpbl = 1;	/* Clusters per directory block */
1120117395Skan	u_int32_t       blnum;
1121117395Skan	struct attr_indexentry *iep;
112218334Speter	int             error = ENOENT;
112318334Speter	u_int32_t       aoff, cnum;
112418334Speter
112518334Speter	dprintf(("ntfs_ntreaddir: read ino: %d, num: %d\n", ip->i_number, num));
112618334Speter	error = ntfs_ntget(ip);
112718334Speter	if (error)
112818334Speter		return (error);
112918334Speter
1130132718Skan	error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXROOT, "$I30", 0, &vap);
113118334Speter	if (error)
1132169689Skan		return (ENOTDIR);
1133169689Skan
113418334Speter	if (fp->f_dirblbuf == NULL) {
1135169689Skan		fp->f_dirblsz = vap->va_a_iroot->ir_size;
1136169689Skan		MALLOC(fp->f_dirblbuf, caddr_t,
1137169689Skan		       max(vap->va_datalen,fp->f_dirblsz), M_NTFSDIR, M_WAITOK);
1138169689Skan	}
1139169689Skan
1140169689Skan	blsize = fp->f_dirblsz;
1141169689Skan	rdbuf = fp->f_dirblbuf;
1142169689Skan
1143169689Skan	dprintf(("ntfs_ntreaddir: rdbuf: 0x%p, blsize: %d\n", rdbuf, blsize));
1144169689Skan
1145169689Skan	if (vap->va_a_iroot->ir_flag & NTFS_IRFLAG_INDXALLOC) {
1146169689Skan		error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXBITMAP, "$I30",
1147169689Skan					0, &bmvap);
1148169689Skan		if (error) {
114918334Speter			error = ENOTDIR;
1150169689Skan			goto fail;
1151169689Skan		}
115290075Sobrien		MALLOC(bmp, u_char *, bmvap->va_datalen, M_TEMP, M_WAITOK);
115318334Speter		error = ntfs_readattr(ntmp, ip, NTFS_A_INDXBITMAP, "$I30", 0,
115418334Speter				       bmvap->va_datalen, bmp);
115518334Speter		if (error)
115618334Speter			goto fail;
115718334Speter
115850397Sobrien		error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDX, "$I30",
115950397Sobrien					0, &iavap);
116018334Speter		if (error) {
116118334Speter			error = ENOTDIR;
1162132718Skan			goto fail;
116318334Speter		}
116490075Sobrien		cpbl = ntfs_btocn(blsize + ntfs_cntob(1) - 1);
116518334Speter		dprintf(("ntfs_ntreaddir: indexalloc: %d, cpbl: %d\n",
116618334Speter			 iavap->va_datalen, cpbl));
116718334Speter	} else {
116850397Sobrien		dprintf(("ntfs_ntreadidir: w/o BitMap and IndexAllocation\n"));
116918334Speter		iavap = bmvap = NULL;
117018334Speter		bmp = NULL;
117118334Speter	}
117218334Speter
117318334Speter	/* Try use previous values */
117418334Speter	if ((fp->f_lastdnum < num) && (fp->f_lastdnum != 0)) {
1175169689Skan		attrnum = fp->f_lastdattr;
1176169689Skan		aoff = fp->f_lastdoff;
1177169689Skan		blnum = fp->f_lastdblnum;
1178169689Skan		cnum = fp->f_lastdnum;
1179169689Skan	} else {
1180169689Skan		attrnum = NTFS_A_INDXROOT;
1181169689Skan		aoff = sizeof(struct attr_indexroot);
1182169689Skan		blnum = 0;
1183169689Skan		cnum = 0;
1184169689Skan	}
1185169689Skan
1186169689Skan	do {
1187169689Skan		dprintf(("ntfs_ntreaddir: scan: 0x%x, %d, %d, %d, %d\n",
1188169689Skan			 attrnum, (u_int32_t) blnum, cnum, num, aoff));
1189169689Skan		rdsize = (attrnum == NTFS_A_INDXROOT) ? vap->va_datalen : blsize;
1190169689Skan		error = ntfs_readattr(ntmp, ip, attrnum, "$I30",
1191169689Skan				   ntfs_cntob(blnum * cpbl), rdsize, rdbuf);
1192169689Skan		if (error)
1193169689Skan			goto fail;
1194169689Skan
1195169689Skan		if (attrnum == NTFS_A_INDX) {
1196169689Skan			error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC,
1197169689Skan						rdbuf, rdsize);
1198169689Skan			if (error)
1199169689Skan				goto fail;
1200169689Skan		}
1201169689Skan		if (aoff == 0)
1202169689Skan			aoff = (attrnum == NTFS_A_INDX) ?
1203169689Skan				(0x18 + ((struct attr_indexalloc *) rdbuf)->ia_hdrsize) :
1204169689Skan				sizeof(struct attr_indexroot);
1205169689Skan
1206169689Skan		iep = (struct attr_indexentry *) (rdbuf + aoff);
1207169689Skan		while (!(iep->ie_flag & NTFS_IEFLAG_LAST) && (rdsize > aoff)) {
1208169689Skan			if (ntfs_isnamepermitted(ntmp, iep)) {
1209169689Skan				if (cnum >= num) {
1210169689Skan					fp->f_lastdnum = cnum;
1211169689Skan					fp->f_lastdoff = aoff;
1212169689Skan					fp->f_lastdblnum = blnum;
1213169689Skan					fp->f_lastdattr = attrnum;
1214169689Skan
1215169689Skan					*riepp = iep;
1216169689Skan
1217169689Skan					error = 0;
1218169689Skan					goto fail;
1219169689Skan				}
1220169689Skan				cnum++;
1221169689Skan			}
1222169689Skan			aoff += iep->reclen;
1223169689Skan			iep = (struct attr_indexentry *) (rdbuf + aoff);
1224169689Skan		}
1225169689Skan
1226169689Skan		if (iavap) {
1227169689Skan			if (attrnum == NTFS_A_INDXROOT)
1228169689Skan				blnum = 0;
1229169689Skan			else
1230169689Skan				blnum++;
1231169689Skan
1232169689Skan			while (ntfs_cntob(blnum * cpbl) < iavap->va_datalen) {
1233169689Skan				if (bmp[blnum >> 3] & (1 << (blnum & 3)))
1234169689Skan					break;
1235169689Skan				blnum++;
1236169689Skan			}
1237169689Skan
1238169689Skan			attrnum = NTFS_A_INDX;
1239169689Skan			aoff = 0;
1240169689Skan			if (ntfs_cntob(blnum * cpbl) >= iavap->va_datalen)
1241169689Skan				break;
124218334Speter			dprintf(("ntfs_ntreaddir: blnum: %d\n", (u_int32_t) blnum));
124350397Sobrien		}
124418334Speter	} while (iavap);
1245169689Skan
124618334Speter	*riepp = NULL;
124790075Sobrien	fp->f_lastdnum = 0;
1248117395Skan
124918334Speterfail:
125018334Speter	if (vap)
1251117395Skan		ntfs_ntvattrrele(vap);
1252117395Skan	if (bmvap)
125318334Speter		ntfs_ntvattrrele(bmvap);
125418334Speter	if (iavap)
1255169689Skan		ntfs_ntvattrrele(iavap);
125618334Speter	if (bmp)
1257132718Skan		FREE(bmp, M_TEMP);
1258169689Skan	ntfs_ntput(ip);
125918334Speter	return (error);
126018334Speter}
126118334Speter
126218334Speter/*
126318334Speter * Convert NTFS times that are in 100 ns units and begins from
126418334Speter * 1601 Jan 1 into unix times.
126518334Speter */
126618334Speterstruct timespec
126718334Speterntfs_nttimetounix(
126818334Speter		  u_int64_t nt)
1269132718Skan{
127018334Speter	struct timespec t;
127118334Speter
127218334Speter	/* WindowNT times are in 100 ns and from 1601 Jan 1 */
127318334Speter	t.tv_nsec = (nt % (1000 * 1000 * 10)) * 100;
127418334Speter	t.tv_sec = nt / (1000 * 1000 * 10) -
127518334Speter		369LL * 365LL * 24LL * 60LL * 60LL -
127618334Speter		89LL * 1LL * 24LL * 60LL * 60LL;
127718334Speter	return (t);
127818334Speter}
127918334Speter
128018334Speter/*
128118334Speter * Get file times from NTFS_A_NAME attribute.
128218334Speter */
128318334Speterint
128418334Speterntfs_times(
1285132718Skan	   struct ntfsmount * ntmp,
128618334Speter	   struct ntnode * ip,
128718334Speter	   ntfs_times_t * tm)
128818334Speter{
128918334Speter	struct ntvattr *vap;
129018334Speter	int             error;
129118334Speter
129218334Speter	dprintf(("ntfs_times: ino: %d...\n", ip->i_number));
129318334Speter
129418334Speter	error = ntfs_ntget(ip);
129518334Speter	if (error)
129618334Speter		return (error);
129718334Speter
129818334Speter	error = ntfs_ntvattrget(ntmp, ip, NTFS_A_NAME, NULL, 0, &vap);
129918334Speter	if (error) {
130018334Speter		ntfs_ntput(ip);
1301132718Skan		return (error);
130218334Speter	}
130390075Sobrien	*tm = vap->va_a_name->n_times;
130490075Sobrien	ntfs_ntvattrrele(vap);
130518334Speter	ntfs_ntput(ip);
130618334Speter
130718334Speter	return (0);
130818334Speter}
130918334Speter
131018334Speter/*
131118334Speter * Get file sizes from corresponding attribute.
131218334Speter *
1313169689Skan * ntnode under fnode should be locked.
131418334Speter */
131518334Speterint
1316169689Skanntfs_filesize(
1317169689Skan	      struct ntfsmount * ntmp,
1318169689Skan	      struct fnode * fp,
1319169689Skan	      u_int64_t * size,
132018334Speter	      u_int64_t * bytes)
1321169689Skan{
132218334Speter	struct ntvattr *vap;
132318334Speter	struct ntnode *ip = FTONT(fp);
132418334Speter	u_int64_t       sz, bn;
132518334Speter	int             error;
132618334Speter
132718334Speter	dprintf(("ntfs_filesize: ino: %d\n", ip->i_number));
132890075Sobrien
132990075Sobrien	error = ntfs_ntvattrget(ntmp, ip,
133018334Speter		fp->f_attrtype, fp->f_attrname, 0, &vap);
133118334Speter	if (error)
133218334Speter		return (error);
1333169689Skan
1334169689Skan	bn = vap->va_allocated;
1335169689Skan	sz = vap->va_datalen;
133618334Speter
133718334Speter	dprintf(("ntfs_filesize: %d bytes (%d bytes allocated)\n",
133818334Speter		(u_int32_t) sz, (u_int32_t) bn));
133918334Speter
134018334Speter	if (size)
134118334Speter		*size = sz;
134290075Sobrien	if (bytes)
134390075Sobrien		*bytes = bn;
134418334Speter
134518334Speter	ntfs_ntvattrrele(vap);
134690075Sobrien
134718334Speter	return (0);
134818334Speter}
134918334Speter
135018334Speter/*
135118334Speter * This is one of write routine.
135218334Speter *
1353132718Skan * ntnode should be locked.
135418334Speter */
135550397Sobrienint
135618334Speterntfs_writeattr_plain(
135718334Speter		     struct ntfsmount * ntmp,
135818334Speter		     struct ntnode * ip,
135918334Speter		     u_int32_t attrnum,
136018334Speter		     char *attrname,
136118334Speter		     off_t roff,
136218334Speter		     size_t rsize,
136318334Speter		     void *rdata,
136418334Speter		     size_t * initp)
1365169689Skan{
136618334Speter	size_t          init;
136718334Speter	int             error = 0;
136850397Sobrien	off_t           off = roff, left = rsize, towrite;
136950397Sobrien	caddr_t         data = rdata;
137018334Speter	struct ntvattr *vap;
137118334Speter	*initp = 0;
137218334Speter
137350397Sobrien	while (left) {
137450397Sobrien		error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname,
137550397Sobrien					ntfs_btocn(off), &vap);
137650397Sobrien		if (error)
137750397Sobrien			return (error);
137850397Sobrien		towrite = min(left, ntfs_cntob(vap->va_vcnend + 1) - off);
137950397Sobrien		ddprintf(("ntfs_writeattr_plain: o: %d, s: %d (%d - %d)\n",
138050397Sobrien			 (u_int32_t) off, (u_int32_t) towrite,
138150397Sobrien			 (u_int32_t) vap->va_vcnstart,
138250397Sobrien			 (u_int32_t) vap->va_vcnend));
138350397Sobrien		error = ntfs_writentvattr_plain(ntmp, ip, vap,
138450397Sobrien					 off - ntfs_cntob(vap->va_vcnstart),
138550397Sobrien					 towrite, data, &init);
138650397Sobrien		if (error) {
138718334Speter			printf("ntfs_writeattr_plain: " \
138818334Speter			       "ntfs_writentvattr_plain failed: o: %d, s: %d\n",
138918334Speter			       (u_int32_t) off, (u_int32_t) towrite);
139018334Speter			printf("ntfs_writeattr_plain: attrib: %d - %d\n",
139118334Speter			       (u_int32_t) vap->va_vcnstart,
139218334Speter			       (u_int32_t) vap->va_vcnend);
139318334Speter			ntfs_ntvattrrele(vap);
1394132718Skan			break;
1395132718Skan		}
1396132718Skan		ntfs_ntvattrrele(vap);
1397132718Skan		left -= towrite;
1398132718Skan		off += towrite;
1399132718Skan		data = data + towrite;
1400132718Skan		*initp += init;
1401132718Skan	}
1402132718Skan
1403132718Skan	return (error);
1404132718Skan}
1405132718Skan
1406132718Skan/*
1407132718Skan * This is one of write routine.
1408132718Skan *
1409132718Skan * ntnode should be locked.
141050397Sobrien */
141150397Sobrienint
141250397Sobrienntfs_writentvattr_plain(
141350397Sobrien			struct ntfsmount * ntmp,
1414132718Skan			struct ntnode * ip,
141550397Sobrien			struct ntvattr * vap,
141650397Sobrien			off_t roff,
141750397Sobrien			size_t rsize,
141850397Sobrien			void *rdata,
141950397Sobrien			size_t * initp)
142050397Sobrien{
142150397Sobrien	int             error = 0;
142250397Sobrien	int             off;
142350397Sobrien
142450397Sobrien	*initp = 0;
142550397Sobrien	if (vap->va_flag & NTFS_AF_INRUN) {
142650397Sobrien		int             cnt;
142750397Sobrien		cn_t            ccn, ccl, cn, left, cl;
142850397Sobrien		caddr_t         data = rdata;
142950397Sobrien		struct buf     *bp;
143050397Sobrien		size_t          tocopy;
143150397Sobrien
143250397Sobrien		ddprintf(("ntfs_writentvattr_plain: data in run: %d chains\n",
143350397Sobrien			 vap->va_vruncnt));
143450397Sobrien
143550397Sobrien		off = roff;
143650397Sobrien		left = rsize;
143750397Sobrien		ccl = 0;
143850397Sobrien		ccn = 0;
143950397Sobrien		cnt = 0;
144050397Sobrien		while (left && (cnt < vap->va_vruncnt)) {
144150397Sobrien			ccn = vap->va_vruncn[cnt];
144250397Sobrien			ccl = vap->va_vruncl[cnt];
144350397Sobrien
144450397Sobrien			ddprintf(("ntfs_writentvattr_plain: " \
144590075Sobrien				 "left %d, cn: 0x%x, cl: %d, off: %d\n", \
144650397Sobrien				 (u_int32_t) left, (u_int32_t) ccn, \
144750397Sobrien				 (u_int32_t) ccl, (u_int32_t) off));
144890075Sobrien
144990075Sobrien			if (ntfs_cntob(ccl) < off) {
145090075Sobrien				off -= ntfs_cntob(ccl);
145190075Sobrien				cnt++;
1452132718Skan				continue;
145390075Sobrien			}
145490075Sobrien			if (ccn || ip->i_number == NTFS_BOOTINO) { /* XXX */
145590075Sobrien				ccl -= ntfs_btocn(off);
145690075Sobrien				cn = ccn + ntfs_btocn(off);
145790075Sobrien				off = ntfs_btocnoff(off);
145890075Sobrien
145990075Sobrien				while (left && ccl) {
146090075Sobrien					tocopy = min(left,
146190075Sobrien						  min(ntfs_cntob(ccl) - off,
146290075Sobrien						      MAXBSIZE - off));
146390075Sobrien					cl = ntfs_btocl(tocopy + off);
146490075Sobrien					ddprintf(("ntfs_writentvattr_plain: " \
146590075Sobrien						"write: cn: 0x%x cl: %d, " \
146690075Sobrien						"off: %d len: %d, left: %d\n",
146790075Sobrien						(u_int32_t) cn,
146890075Sobrien						(u_int32_t) cl,
146990075Sobrien						(u_int32_t) off,
147090075Sobrien						(u_int32_t) tocopy,
147190075Sobrien						(u_int32_t) left));
147290075Sobrien					if ((off == 0) &&
147390075Sobrien					    (tocopy == ntfs_cntob(cl))) {
147490075Sobrien						bp = getblk(ntmp->ntm_devvp,
147590075Sobrien							    ntfs_cntobn(cn),
147690075Sobrien							    ntfs_cntob(cl),
147790075Sobrien							    0, 0);
147890075Sobrien						clrbuf(bp);
147990075Sobrien					} else {
148090075Sobrien						error = bread(ntmp->ntm_devvp,
148190075Sobrien							      ntfs_cntobn(cn),
148290075Sobrien							      ntfs_cntob(cl),
148390075Sobrien							      NOCRED, &bp);
148490075Sobrien						if (error) {
148590075Sobrien							brelse(bp);
148690075Sobrien							return (error);
148718334Speter						}
148818334Speter					}
148918334Speter					memcpy(bp->b_data + off, data, tocopy);
1490132718Skan					bawrite(bp);
149118334Speter					data = data + tocopy;
149218334Speter					*initp += tocopy;
149318334Speter					off = 0;
149418334Speter					left -= tocopy;
149518334Speter					cn += cl;
149618334Speter					ccl -= cl;
149718334Speter				}
149818334Speter			}
149918334Speter			cnt++;
150018334Speter		}
150118334Speter		if (left) {
150218334Speter			printf("ntfs_writentvattr_plain: POSSIBLE RUN ERROR\n");
150318334Speter			error = EINVAL;
1504132718Skan		}
150518334Speter	} else {
150618334Speter		printf("ntfs_writevattr_plain: CAN'T WRITE RES. ATTRIBUTE\n");
150718334Speter		error = ENOTTY;
150818334Speter	}
150918334Speter
151018334Speter	return (error);
151118334Speter}
151218334Speter
151318334Speter/*
151418334Speter * This is one of read routines.
151518334Speter *
151618334Speter * ntnode should be locked.
151718334Speter */
1518132718Skanint
151918334Speterntfs_readntvattr_plain(
152018334Speter			struct ntfsmount * ntmp,
152118334Speter			struct ntnode * ip,
152218334Speter			struct ntvattr * vap,
152318334Speter			off_t roff,
152418334Speter			size_t rsize,
152518334Speter			void *rdata,
152618334Speter			size_t * initp)
152718334Speter{
152818334Speter	int             error = 0;
1529117395Skan	int             off;
1530117395Skan
1531117395Skan	*initp = 0;
1532132718Skan	if (vap->va_flag & NTFS_AF_INRUN) {
1533117395Skan		int             cnt;
1534117395Skan		cn_t            ccn, ccl, cn, left, cl;
1535117395Skan		caddr_t         data = rdata;
1536117395Skan		struct buf     *bp;
1537117395Skan		size_t          tocopy;
1538117395Skan
1539117395Skan		ddprintf(("ntfs_readntvattr_plain: data in run: %d chains\n",
1540117395Skan			 vap->va_vruncnt));
1541117395Skan
1542117395Skan		off = roff;
154318334Speter		left = rsize;
154490075Sobrien		ccl = 0;
154518334Speter		ccn = 0;
1546132718Skan		cnt = 0;
154718334Speter		while (left && (cnt < vap->va_vruncnt)) {
154818334Speter			ccn = vap->va_vruncn[cnt];
154918334Speter			ccl = vap->va_vruncl[cnt];
155018334Speter
155118334Speter			ddprintf(("ntfs_readntvattr_plain: " \
155218334Speter				 "left %d, cn: 0x%x, cl: %d, off: %d\n", \
155318334Speter				 (u_int32_t) left, (u_int32_t) ccn, \
155418334Speter				 (u_int32_t) ccl, (u_int32_t) off));
155518334Speter
155618334Speter			if (ntfs_cntob(ccl) < off) {
155718334Speter				off -= ntfs_cntob(ccl);
155818334Speter				cnt++;
155918334Speter				continue;
1560132718Skan			}
156118334Speter			if (ccn || ip->i_number == NTFS_BOOTINO) {
156218334Speter				ccl -= ntfs_btocn(off);
156318334Speter				cn = ccn + ntfs_btocn(off);
156418334Speter				off = ntfs_btocnoff(off);
156518334Speter
156618334Speter				while (left && ccl) {
156718334Speter					tocopy = min(left,
156818334Speter						  min(ntfs_cntob(ccl) - off,
156918334Speter						      MAXBSIZE - off));
157018334Speter					cl = ntfs_btocl(tocopy + off);
157118334Speter					ddprintf(("ntfs_readntvattr_plain: " \
157218334Speter						"read: cn: 0x%x cl: %d, " \
157318334Speter						"off: %d len: %d, left: %d\n",
157418334Speter						(u_int32_t) cn,
1575132718Skan						(u_int32_t) cl,
157618334Speter						(u_int32_t) off,
157718334Speter						(u_int32_t) tocopy,
157818334Speter						(u_int32_t) left));
157918334Speter					error = bread(ntmp->ntm_devvp,
158018334Speter						      ntfs_cntobn(cn),
158118334Speter						      ntfs_cntob(cl),
158218334Speter						      NOCRED, &bp);
158318334Speter					if (error) {
158418334Speter						brelse(bp);
158518334Speter						return (error);
158650397Sobrien					}
158718334Speter					memcpy(data, bp->b_data + off, tocopy);
158818334Speter					brelse(bp);
1589132718Skan					data = data + tocopy;
159018334Speter					*initp += tocopy;
159118334Speter					off = 0;
159218334Speter					left -= tocopy;
159318334Speter					cn += cl;
159418334Speter					ccl -= cl;
159518334Speter				}
159618334Speter			} else {
159718334Speter				tocopy = min(left, ntfs_cntob(ccl) - off);
159818334Speter				ddprintf(("ntfs_readntvattr_plain: "
159918334Speter					"sparce: ccn: 0x%x ccl: %d, off: %d, " \
160018334Speter					" len: %d, left: %d\n",
160118334Speter					(u_int32_t) ccn, (u_int32_t) ccl,
160218334Speter					(u_int32_t) off, (u_int32_t) tocopy,
160318334Speter					(u_int32_t) left));
160418334Speter				left -= tocopy;
160518334Speter				off = 0;
1606132718Skan				bzero(data, tocopy);
160718334Speter				data = data + tocopy;
1608169689Skan			}
1609169689Skan			cnt++;
1610169689Skan		}
1611169689Skan		if (left) {
161290075Sobrien			printf("ntfs_readntvattr_plain: POSSIBLE RUN ERROR\n");
161318334Speter			error = E2BIG;
1614169689Skan		}
1615169689Skan	} else {
1616169689Skan		ddprintf(("ntfs_readnvattr_plain: data is in mft record\n"));
1617169689Skan		memcpy(rdata, vap->va_datap + roff, rsize);
1618169689Skan		*initp += rsize;
1619169689Skan	}
1620169689Skan
1621169689Skan	return (error);
1622169689Skan}
1623169689Skan
162418334Speter/*
162518334Speter * This is one of read routines.
162618334Speter *
162718334Speter * ntnode should be locked.
162890075Sobrien */
162990075Sobrienint
163090075Sobrienntfs_readattr_plain(
1631132718Skan		     struct ntfsmount * ntmp,
163290075Sobrien		     struct ntnode * ip,
163390075Sobrien		     u_int32_t attrnum,
163490075Sobrien		     char *attrname,
163590075Sobrien		     off_t roff,
163690075Sobrien		     size_t rsize,
163790075Sobrien		     void *rdata,
163890075Sobrien		     size_t * initp)
163990075Sobrien{
164090075Sobrien	size_t          init;
164190075Sobrien	int             error = 0;
164290075Sobrien	off_t           off = roff, left = rsize, toread;
164318334Speter	caddr_t         data = rdata;
164418334Speter	struct ntvattr *vap;
164518334Speter	*initp = 0;
164618334Speter
164718334Speter	while (left) {
1648132718Skan		error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname,
164918334Speter					ntfs_btocn(off), &vap);
1650132718Skan		if (error)
165118334Speter			return (error);
1652132718Skan		toread = min(left, ntfs_cntob(vap->va_vcnend + 1) - off);
1653132718Skan		ddprintf(("ntfs_readattr_plain: o: %d, s: %d (%d - %d)\n",
1654132718Skan			 (u_int32_t) off, (u_int32_t) toread,
1655132718Skan			 (u_int32_t) vap->va_vcnstart,
1656132718Skan			 (u_int32_t) vap->va_vcnend));
1657132718Skan		error = ntfs_readntvattr_plain(ntmp, ip, vap,
1658132718Skan					 off - ntfs_cntob(vap->va_vcnstart),
1659132718Skan					 toread, data, &init);
1660132718Skan		if (error) {
166190075Sobrien			printf("ntfs_readattr_plain: " \
1662132718Skan			       "ntfs_readntvattr_plain failed: o: %d, s: %d\n",
1663132718Skan			       (u_int32_t) off, (u_int32_t) toread);
1664132718Skan			printf("ntfs_readattr_plain: attrib: %d - %d\n",
1665169689Skan			       (u_int32_t) vap->va_vcnstart,
1666132718Skan			       (u_int32_t) vap->va_vcnend);
166790075Sobrien			ntfs_ntvattrrele(vap);
166818334Speter			break;
1669132718Skan		}
167018334Speter		ntfs_ntvattrrele(vap);
167118334Speter		left -= toread;
167218334Speter		off += toread;
167318334Speter		data = data + toread;
167418334Speter		*initp += init;
1675132718Skan	}
167618334Speter
167790075Sobrien	return (error);
167818334Speter}
167950397Sobrien
168018334Speter/*
168118334Speter * This is one of read routines.
168218334Speter *
168318334Speter * ntnode should be locked.
168418334Speter */
168518334Speterint
168618334Speterntfs_readattr(
168718334Speter	       struct ntfsmount * ntmp,
1688132718Skan	       struct ntnode * ip,
168918334Speter	       u_int32_t attrnum,
169090075Sobrien	       char *attrname,
169118334Speter	       off_t roff,
169218334Speter	       size_t rsize,
169318334Speter	       void *rdata)
169418334Speter{
169518334Speter	int             error = 0;
169618334Speter	struct ntvattr *vap;
169718334Speter	size_t          init;
169818334Speter
169918334Speter	ddprintf(("ntfs_readattr: reading %d: 0x%x, from %d size %d bytes\n",
170018334Speter	       ip->i_number, attrnum, (u_int32_t) roff, (u_int32_t) rsize));
170118334Speter
170218334Speter	error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname, 0, &vap);
170318334Speter	if (error)
1704169689Skan		return (error);
170518334Speter
1706169689Skan	if ((roff > vap->va_datalen) ||
170718334Speter	    (roff + rsize > vap->va_datalen)) {
170818334Speter		ddprintf(("ntfs_readattr: offset too big\n"));
170918334Speter		ntfs_ntvattrrele(vap);
171018334Speter		return (E2BIG);
171118334Speter	}
171218334Speter	if (vap->va_compression && vap->va_compressalg) {
1713132718Skan		u_int8_t       *cup;
171418334Speter		u_int8_t       *uup;
171518334Speter		off_t           off = roff, left = rsize, tocopy;
171618334Speter		caddr_t         data = rdata;
1717169689Skan		cn_t            cn;
171818334Speter
171990075Sobrien		ddprintf(("ntfs_ntreadattr: compression: %d\n",
172090075Sobrien			 vap->va_compressalg));
1721169689Skan
172290075Sobrien		MALLOC(cup, u_int8_t *, ntfs_cntob(NTFS_COMPUNIT_CL),
172390075Sobrien		       M_NTFSDECOMP, M_WAITOK);
172490075Sobrien		MALLOC(uup, u_int8_t *, ntfs_cntob(NTFS_COMPUNIT_CL),
172518334Speter		       M_NTFSDECOMP, M_WAITOK);
172690075Sobrien
172790075Sobrien		cn = (ntfs_btocn(roff)) & (~(NTFS_COMPUNIT_CL - 1));
172818334Speter		off = roff - ntfs_cntob(cn);
172918334Speter
173018334Speter		while (left) {
173118334Speter			error = ntfs_readattr_plain(ntmp, ip, attrnum,
173218334Speter						  attrname, ntfs_cntob(cn),
173318334Speter					          ntfs_cntob(NTFS_COMPUNIT_CL),
173418334Speter						  cup, &init);
173518334Speter			if (error)
173618334Speter				break;
173718334Speter
173818334Speter			tocopy = min(left, ntfs_cntob(NTFS_COMPUNIT_CL) - off);
173918334Speter
174018334Speter			if (init == ntfs_cntob(NTFS_COMPUNIT_CL)) {
174118334Speter				memcpy(data, cup + off, tocopy);
174218334Speter			} else if (init == 0) {
174318334Speter				bzero(data, tocopy);
174418334Speter			} else {
1745132718Skan				error = ntfs_uncompunit(ntmp, uup, cup);
174618334Speter				if (error)
174718334Speter					break;
174818334Speter				memcpy(data, uup + off, tocopy);
174918334Speter			}
175018334Speter
175150397Sobrien			left -= tocopy;
175218334Speter			data = data + tocopy;
175350397Sobrien			off += tocopy - ntfs_cntob(NTFS_COMPUNIT_CL);
175490075Sobrien			cn += NTFS_COMPUNIT_CL;
175550397Sobrien		}
175618334Speter
1757169689Skan		FREE(uup, M_NTFSDECOMP);
175890075Sobrien		FREE(cup, M_NTFSDECOMP);
175918334Speter	} else
176090075Sobrien		error = ntfs_readattr_plain(ntmp, ip, attrnum, attrname,
176118334Speter					     roff, rsize, rdata, &init);
1762169689Skan	ntfs_ntvattrrele(vap);
176350397Sobrien	return (error);
176418334Speter}
176518334Speter
176618334Speter#if UNUSED_CODE
176750397Sobrienint
176850397Sobrienntfs_parserun(
176918334Speter	      cn_t * cn,
177050397Sobrien	      cn_t * cl,
1771132718Skan	      u_int8_t * run,
177218334Speter	      u_long len,
177350397Sobrien	      u_long *off)
177450397Sobrien{
177518334Speter	u_int8_t        sz;
177618334Speter	int             i;
177750397Sobrien
177818334Speter	if (NULL == run) {
177950397Sobrien		printf("ntfs_parsetun: run == NULL\n");
178050397Sobrien		return (EINVAL);
178150397Sobrien	}
178290075Sobrien	sz = run[(*off)++];
178390075Sobrien	if (0 == sz) {
178490075Sobrien		printf("ntfs_parserun: trying to go out of run\n");
178518334Speter		return (E2BIG);
178650397Sobrien	}
178750397Sobrien	*cl = 0;
178818334Speter	if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) {
1789169689Skan		printf("ntfs_parserun: " \
1790169689Skan		       "bad run: length too big: sz: 0x%02x (%ld < %ld + sz)\n",
1791169689Skan		       sz, len, *off);
1792169689Skan		return (EINVAL);
1793169689Skan	}
1794169689Skan	for (i = 0; i < (sz & 0xF); i++)
1795169689Skan		*cl += (u_int32_t) run[(*off)++] << (i << 3);
1796169689Skan
1797169689Skan	sz >>= 4;
1798169689Skan	if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) {
1799169689Skan		printf("ntfs_parserun: " \
1800169689Skan		       "bad run: length too big: sz: 0x%02x (%ld < %ld + sz)\n",
1801169689Skan		       sz, len, *off);
1802169689Skan		return (EINVAL);
1803169689Skan	}
1804169689Skan	for (i = 0; i < (sz & 0xF); i++)
1805169689Skan		*cn += (u_int32_t) run[(*off)++] << (i << 3);
1806169689Skan
1807169689Skan	return (0);
1808169689Skan}
1809169689Skan#endif
1810169689Skan
1811169689Skan/*
1812169689Skan * Process fixup routine on given buffer.
1813169689Skan */
1814169689Skanint
1815169689Skanntfs_procfixups(
1816169689Skan		struct ntfsmount * ntmp,
1817169689Skan		u_int32_t magic,
1818169689Skan		caddr_t buf,
1819169689Skan		size_t len)
1820169689Skan{
1821169689Skan	struct fixuphdr *fhp = (struct fixuphdr *) buf;
182218334Speter	int             i;
182390075Sobrien	u_int16_t       fixup;
182490075Sobrien	u_int16_t      *fxp;
182518334Speter	u_int16_t      *cfxp;
182690075Sobrien
1827132718Skan	if (fhp->fh_magic != magic) {
182890075Sobrien		printf("ntfs_procfixups: magic doesn't match: %08x != %08x\n",
182990075Sobrien		       fhp->fh_magic, magic);
183090075Sobrien		return (EINVAL);
183190075Sobrien	}
183290075Sobrien	if ((fhp->fh_fnum - 1) * ntmp->ntm_bps != len) {
1833169689Skan		printf("ntfs_procfixups: " \
1834169689Skan		       "bad fixups number: %d for %d bytes block\n",
1835169689Skan		       fhp->fh_fnum, len);
183690075Sobrien		return (EINVAL);
183790075Sobrien	}
1838132718Skan	if (fhp->fh_foff >= ntmp->ntm_spc * ntmp->ntm_mftrecsz * ntmp->ntm_bps) {
183990075Sobrien		printf("ntfs_procfixups: invalid offset: %x", fhp->fh_foff);
184090075Sobrien		return (EINVAL);
184190075Sobrien	}
184290075Sobrien	fxp = (u_int16_t *) (buf + fhp->fh_foff);
184390075Sobrien	cfxp = (u_int16_t *) (buf + ntmp->ntm_bps - 2);
184490075Sobrien	fixup = *fxp++;
184590075Sobrien	for (i = 1; i < fhp->fh_fnum; i++, fxp++) {
184618334Speter		if (*cfxp != fixup) {
1847132718Skan			printf("ntfs_procfixups: fixup %d doesn't match\n", i);
184890075Sobrien			return (EINVAL);
184990075Sobrien		}
185090075Sobrien		*cfxp = *fxp;
185190075Sobrien		((caddr_t) cfxp) += ntmp->ntm_bps;
185290075Sobrien	}
1853169689Skan	return (0);
1854169689Skan}
1855169689Skan
185690075Sobrien#if UNUSED_CODE
185790075Sobrienint
1858132718Skanntfs_runtocn(
185990075Sobrien	     cn_t * cn,
186090075Sobrien	     struct ntfsmount * ntmp,
186190075Sobrien	     u_int8_t * run,
186290075Sobrien	     u_long len,
186390075Sobrien	     cn_t vcn)
186490075Sobrien{
186590075Sobrien	cn_t            ccn = 0;
1866132718Skan	cn_t            ccl = 0;
186790075Sobrien	u_long          off = 0;
186890075Sobrien	int             error = 0;
186990075Sobrien
187090075Sobrien#if NTFS_DEBUG
187190075Sobrien	int             i;
187290075Sobrien	printf("ntfs_runtocn: run: 0x%p, %ld bytes, vcn:%ld\n",
187390075Sobrien		run, len, (u_long) vcn);
187490075Sobrien	printf("ntfs_runtocn: run: ");
187590075Sobrien	for (i = 0; i < len; i++)
187690075Sobrien		printf("0x%02x ", run[i]);
187790075Sobrien	printf("\n");
187890075Sobrien#endif
187990075Sobrien
188090075Sobrien	if (NULL == run) {
1881169689Skan		printf("ntfs_runtocn: run == NULL\n");
188290075Sobrien		return (EINVAL);
188390075Sobrien	}
188490075Sobrien	do {
188590075Sobrien		if (run[off] == 0) {
188690075Sobrien			printf("ntfs_runtocn: vcn too big\n");
188790075Sobrien			return (E2BIG);
188890075Sobrien		}
188990075Sobrien		vcn -= ccl;
189090075Sobrien		error = ntfs_parserun(&ccn, &ccl, run, len, &off);
189190075Sobrien		if (error) {
1892258748Spfg			printf("ntfs_runtocn: ntfs_parserun failed\n");
1893258748Spfg			return (error);
189490075Sobrien		}
189590075Sobrien	} while (ccl <= vcn);
189690075Sobrien	*cn = ccn + vcn;
1897258748Spfg	return (0);
1898258748Spfg}
189990075Sobrien#endif
190090075Sobrien