ntfs_subr.c revision 44142
1/*-
2 * Copyright (c) 1998, 1999 Semen Ustimenko
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 *	$Id: ntfs_subr.c,v 1.9 1999/02/02 01:54:54 semen Exp $
27 */
28
29#include <sys/param.h>
30#include <sys/types.h>
31#include <sys/systm.h>
32#include <sys/namei.h>
33#include <sys/proc.h>
34#include <sys/kernel.h>
35#include <sys/vnode.h>
36#include <sys/mount.h>
37#include <sys/buf.h>
38#include <sys/file.h>
39#include <sys/malloc.h>
40#include <machine/clock.h>
41
42#include <miscfs/specfs/specdev.h>
43
44/* #define NTFS_DEBUG 1 */
45#include <ntfs/ntfs.h>
46#include <ntfs/ntfsmount.h>
47#include <ntfs/ntfs_inode.h>
48#include <ntfs/ntfs_vfsops.h>
49#include <ntfs/ntfs_extern.h>
50#include <ntfs/ntfs_subr.h>
51#include <ntfs/ntfs_compr.h>
52#include <ntfs/ntfs_ihash.h>
53
54#if __FreeBSD_version >= 300000
55MALLOC_DEFINE(M_NTFSNTVATTR, "NTFS vattr", "NTFS file attribute information");
56MALLOC_DEFINE(M_NTFSRDATA, "NTFS res data", "NTFS resident data");
57MALLOC_DEFINE(M_NTFSRUN, "NTFS vrun", "NTFS vrun storage");
58MALLOC_DEFINE(M_NTFSDECOMP, "NTFS decomp", "NTFS decompression temporary");
59#endif
60
61int
62ntfs_ntvattrrele(
63		 struct ntvattr * vap)
64{
65	dprintf(("ntfs_ntvattrrele: ino: %d, type: 0x%x\n",
66		 vap->va_ip->i_number, vap->va_type));
67
68	ntfs_ntrele(vap->va_ip);
69
70	return (0);
71}
72
73int
74ntfs_ntvattrget(
75		struct ntfsmount * ntmp,
76		struct ntnode * ip,
77		u_int32_t type,
78		char *name,
79		cn_t vcn,
80		struct ntvattr ** vapp)
81{
82	int             error;
83	struct ntvattr *vap;
84	struct ntvattr *lvap = NULL;
85	struct attr_attrlist *aalp;
86	struct attr_attrlist *nextaalp;
87	caddr_t         alpool;
88	int             len, namelen;
89
90	*vapp = NULL;
91
92	if (name) {
93		dprintf(("ntfs_ntvattrget: " \
94			 "ino: %d, type: 0x%x, name: %s, vcn: %d\n", \
95			 ip->i_number, type, name, (u_int32_t) vcn));
96		namelen = strlen(name);
97	} else {
98		dprintf(("ntfs_ntvattrget: " \
99			 "ino: %d, type: 0x%x, vcn: %d\n", \
100			 ip->i_number, type, (u_int32_t) vcn));
101		name = "";
102		namelen = 0;
103	}
104
105	if((ip->i_flag & IN_LOADED) == 0) {
106		dprintf(("ntfs_ntvattrget: node not loaded, ino: %d\n",
107		       ip->i_number));
108		error = ntfs_loadntnode(ntmp,ip);
109		if(error) {
110			printf("ntfs_ntvattrget: FAILED TO LOAD INO: %d\n",
111			       ip->i_number);
112			return (error);
113		}
114	}
115
116	for (vap = ip->i_vattrp; vap; vap = vap->va_nextp) {
117		ddprintf(("type: 0x%x, vcn: %d - %d\n", \
118			  vap->va_type, (u_int32_t) vap->va_vcnstart, \
119			  (u_int32_t) vap->va_vcnend));
120		if ((vap->va_type == type) &&
121		    (vap->va_vcnstart <= vcn) && (vap->va_vcnend >= vcn) &&
122		    (vap->va_namelen == namelen) &&
123		    (!strncmp(name, vap->va_name, namelen))) {
124			*vapp = vap;
125			ntfs_ntref(vap->va_ip);
126			return (0);
127		}
128		if (vap->va_type == NTFS_A_ATTRLIST)
129			lvap = vap;
130	}
131
132	if (!lvap) {
133		dprintf(("ntfs_ntvattrget: UNEXISTED ATTRIBUTE: " \
134		       "ino: %d, type: 0x%x, name: %s, vcn: %d\n", \
135		       ip->i_number, type, name, (u_int32_t) vcn));
136		return (ENOENT);
137	}
138	/* Scan $ATTRIBUTE_LIST for requested attribute */
139	len = lvap->va_datalen;
140	MALLOC(alpool, caddr_t, len, M_TEMP, M_WAITOK);
141	error = ntfs_readntvattr_plain(ntmp, ip, lvap, 0, len, alpool, &len);
142	if (error)
143		goto out;
144
145	aalp = (struct attr_attrlist *) alpool;
146	nextaalp = NULL;
147
148	while (len > 0) {
149		dprintf(("ntfs_ntvattrget: " \
150			 "attrlist: ino: %d, attr: 0x%x, vcn: %d\n", \
151			 aalp->al_inumber, aalp->al_type, \
152			 (u_int32_t) aalp->al_vcnstart));
153
154		if (len > aalp->reclen) {
155			nextaalp = NTFS_NEXTREC(aalp, struct attr_attrlist *);
156		} else {
157			nextaalp = NULL;
158		}
159		len -= aalp->reclen;
160
161#define AALPCMP(aalp,type,name,namelen) (				\
162  (aalp->al_type == type) && (aalp->al_namelen == namelen) &&		\
163  !uastrcmp(aalp->al_name,aalp->al_namelen,name,namelen) )
164
165		if (AALPCMP(aalp, type, name, namelen) &&
166		    (!nextaalp || (nextaalp->al_vcnstart > vcn) ||
167		     !AALPCMP(nextaalp, type, name, namelen))) {
168			struct vnode   *newvp;
169			struct ntnode  *newip;
170
171			dprintf(("ntfs_ntvattrget: attrbute in ino: %d\n",
172				 aalp->al_inumber));
173
174			error = VFS_VGET(ntmp->ntm_mountp, aalp->al_inumber,
175					 &newvp);
176			if (error) {
177				printf("ntfs_ntvattrget: CAN'T VGET INO: %d\n",
178				       aalp->al_inumber);
179				goto out;
180			}
181			newip = VTONT(newvp);
182			if(~newip->i_flag & IN_LOADED) {
183				dprintf(("ntfs_ntvattrget: node not loaded," \
184					 " ino: %d\n", newip->i_number));
185				error = ntfs_loadntnode(ntmp,ip);
186				if(error) {
187					printf("ntfs_ntvattrget: CAN'T LOAD " \
188					       "INO: %d\n", newip->i_number);
189					vput(newvp);
190					goto out;
191				}
192			}
193			for (vap = newip->i_vattrp; vap; vap = vap->va_nextp) {
194				if ((vap->va_type == type) &&
195				    (vap->va_vcnstart <= vcn) &&
196				    (vap->va_vcnend >= vcn) &&
197				    (vap->va_namelen == namelen) &&
198				  (!strncmp(name, vap->va_name, namelen))) {
199					*vapp = vap;
200					ntfs_ntref(vap->va_ip);
201					vput(newvp);
202					error = 0;
203					goto out;
204				}
205				if (vap->va_type == NTFS_A_ATTRLIST)
206					lvap = vap;
207			}
208			printf("ntfs_ntvattrget: ATTRLIST ERROR.\n");
209			vput(newvp);
210			break;
211		}
212#undef AALPCMP
213		aalp = nextaalp;
214	}
215	error = ENOENT;
216
217	dprintf(("ntfs_ntvattrget: UNEXISTED ATTRIBUTE: " \
218	       "ino: %d, type: 0x%x, name: %s, vcn: %d\n", \
219	       ip->i_number, type, name, (u_int32_t) vcn));
220out:
221	FREE(alpool, M_TEMP);
222
223	return (error);
224}
225
226int
227ntfs_loadntnode(
228	      struct ntfsmount * ntmp,
229	      struct ntnode * ip)
230{
231	struct filerec  *mfrp;
232	daddr_t         bn;
233	int		error,off;
234	struct attr    *ap;
235	struct ntvattr**vapp;
236
237	dprintf(("ntfs_loadnode: loading ino: %d\n",ip->i_number));
238
239	MALLOC(mfrp, struct filerec *, ntfs_bntob(ntmp->ntm_bpmftrec),
240	       M_TEMP, M_WAITOK);
241
242	if (ip->i_number < NTFS_SYSNODESNUM) {
243		struct buf     *bp;
244
245		dprintf(("ntfs_loadnode: read system node\n"));
246
247		bn = ntfs_cntobn(ntmp->ntm_mftcn) +
248			ntmp->ntm_bpmftrec * ip->i_number;
249
250		error = bread(ntmp->ntm_devvp,
251			      bn, ntfs_bntob(ntmp->ntm_bpmftrec),
252			      NOCRED, &bp);
253		if (error) {
254			printf("ntfs_loadnode: BREAD FAILED\n");
255			brelse(bp);
256			goto out;
257		}
258		memcpy(mfrp, bp->b_data, ntfs_bntob(ntmp->ntm_bpmftrec));
259		bqrelse(bp);
260	} else {
261		struct vnode   *vp;
262
263		vp = ntmp->ntm_sysvn[NTFS_MFTINO];
264		error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL,
265			       ip->i_number * ntfs_bntob(ntmp->ntm_bpmftrec),
266			       ntfs_bntob(ntmp->ntm_bpmftrec), mfrp);
267		if (error) {
268			printf("ntfs_loadnode: ntfs_readattr failed\n");
269			goto out;
270		}
271	}
272	/* Check if magic and fixups are correct */
273	error = ntfs_procfixups(ntmp, NTFS_FILEMAGIC, (caddr_t)mfrp,
274				ntfs_bntob(ntmp->ntm_bpmftrec));
275	if (error) {
276		printf("ntfs_loadnode: BAD MFT RECORD %d\n",
277		       (u_int32_t) ip->i_number);
278		goto out;
279	}
280
281	dprintf(("ntfs_loadnode: load attrs for ino: %d\n",ip->i_number));
282	off = mfrp->fr_attroff;
283	ap = (struct attr *) ((caddr_t)mfrp + off);
284	if (ip->i_vattrp)
285		printf("ntfs_ntloadnode: WARNING! already loaded?\n");
286
287	vapp = &ip->i_vattrp;
288	while (ap->a_hdr.a_type != -1) {
289		error = ntfs_attrtontvattr(ntmp, vapp, ap);
290		if (error)
291			break;
292		(*vapp)->va_ip = ip;
293		vapp = &((*vapp)->va_nextp);
294
295		off += ap->a_hdr.reclen;
296		ap = (struct attr *) ((caddr_t)mfrp + off);
297	}
298	if (error) {
299		printf("ntfs_loadnode: failed to load attr ino: %d\n",
300		       ip->i_number);
301		goto out;
302	}
303
304	ip->i_mainrec = mfrp->fr_mainrec;
305	ip->i_nlink = mfrp->fr_nlink;
306	ip->i_frflag = mfrp->fr_flags;
307
308	ip->i_flag |= IN_LOADED;
309
310out:
311	FREE(mfrp, M_TEMP);
312	return (error);
313}
314
315
316static int ntfs_ntnode_hash_lock;
317int
318ntfs_ntget(
319	   struct ntfsmount * ntmp,
320	   ino_t ino,
321	   struct ntnode ** ipp)
322{
323	struct ntnode  *ip;
324
325	dprintf(("ntfs_ntget: ntget ntnode %d\n", ino));
326	*ipp = NULL;
327
328restart:
329	ip = ntfs_nthashlookup(ntmp->ntm_dev, ino);
330	if (ip) {
331		ip->i_usecount++;
332		*ipp = ip;
333		dprintf(("ntfs_ntget: ntnode %d: %p, usecount: %d\n",
334			ino, ip, ip->i_usecount));
335
336		return (0);
337	}
338
339	if (ntfs_ntnode_hash_lock) {
340		printf("waiting for hash_lock to free...\n");
341		while(ntfs_ntnode_hash_lock) {
342			ntfs_ntnode_hash_lock = -1;
343			tsleep(&ntfs_ntnode_hash_lock, PVM, "ntfsntgt", 0);
344		}
345		printf("hash_lock freeed\n");
346		goto restart;
347	}
348	ntfs_ntnode_hash_lock = 1;
349
350	MALLOC(ip, struct ntnode *, sizeof(struct ntnode),
351	       M_NTFSNTNODE, M_WAITOK);
352	ddprintf(("ntfs_ntget: allocating ntnode: %d: %p\n", ino, ip));
353	bzero((caddr_t) ip, sizeof(struct ntnode));
354
355	/* Generic initialization */
356	ip->i_number = ino;
357	ip->i_mp = ntmp;
358	ip->i_dev = ntmp->ntm_dev;
359	ip->i_uid = ntmp->ntm_uid;
360	ip->i_gid = ntmp->ntm_gid;
361	ip->i_mode = ntmp->ntm_mode;
362	ip->i_usecount++;
363
364	LIST_INIT(&ip->i_fnlist);
365
366	ntfs_nthashins(ip);
367
368	if (ntfs_ntnode_hash_lock < 0)
369		wakeup(&ntfs_ntnode_hash_lock);
370	ntfs_ntnode_hash_lock = 0;
371
372	*ipp = ip;
373
374	dprintf(("ntfs_ntget: ntnode %d: %p, usecount: %d\n",
375		ino, ip, ip->i_usecount));
376
377	return (0);
378}
379
380void
381ntfs_ntrele(
382	    struct ntnode * ip)
383{
384	struct ntvattr *vap;
385
386	dprintf(("ntfs_ntrele: rele ntnode %d: %p, usecount: %d\n",
387		ip->i_number, ip, ip->i_usecount));
388
389	ip->i_usecount--;
390
391	if (ip->i_usecount < 0) {
392		panic("ntfs_ntrele: ino: %d usecount: %d \n",
393		      ip->i_number,ip->i_usecount);
394	} else if (ip->i_usecount == 0) {
395		dprintf(("ntfs_ntrele: deallocating ntnode: %d\n",
396			ip->i_number));
397
398		if (ip->i_fnlist.lh_first)
399			panic("ntfs_ntrele: ntnode has fnodes\n");
400
401		ntfs_nthashrem(ip);
402
403		while (ip->i_vattrp) {
404			vap = ip->i_vattrp;
405			ip->i_vattrp = vap->va_nextp;
406			ntfs_freentvattr(vap);
407		}
408		FREE(ip, M_NTFSNTNODE);
409	}
410	dprintf(("ntfs_ntrele: rele ok\n"));
411}
412
413void
414ntfs_freentvattr(
415		 struct ntvattr * vap)
416{
417	if (vap->va_flag & NTFS_AF_INRUN) {
418		if (vap->va_vruncn)
419			FREE(vap->va_vruncn, M_NTFSRUN);
420		if (vap->va_vruncl)
421			FREE(vap->va_vruncl, M_NTFSRUN);
422	} else {
423		if (vap->va_datap)
424			FREE(vap->va_datap, M_NTFSRDATA);
425	}
426	FREE(vap, M_NTFSNTVATTR);
427}
428
429int
430ntfs_attrtontvattr(
431		   struct ntfsmount * ntmp,
432		   struct ntvattr ** rvapp,
433		   struct attr * rap)
434{
435	int             error, i;
436	struct ntvattr *vap;
437
438	error = 0;
439	*rvapp = NULL;
440
441	MALLOC(vap, struct ntvattr *, sizeof(struct ntvattr),
442		M_NTFSNTVATTR, M_WAITOK);
443	bzero(vap, sizeof(struct ntvattr));
444	vap->va_ip = NULL;
445	vap->va_flag = rap->a_hdr.a_flag;
446	vap->va_type = rap->a_hdr.a_type;
447	vap->va_compression = rap->a_hdr.a_compression;
448	vap->va_index = rap->a_hdr.a_index;
449
450	ddprintf(("type: 0x%x, index: %d", vap->va_type, vap->va_index));
451
452	vap->va_namelen = rap->a_hdr.a_namelen;
453	if (rap->a_hdr.a_namelen) {
454		wchar *unp = (wchar *) ((caddr_t) rap + rap->a_hdr.a_nameoff);
455		ddprintf((", name:["));
456		for (i = 0; i < vap->va_namelen; i++) {
457			vap->va_name[i] = unp[i];
458			ddprintf(("%c", vap->va_name[i]));
459		}
460		ddprintf(("]"));
461	}
462	if (vap->va_flag & NTFS_AF_INRUN) {
463		ddprintf((", nonres."));
464		vap->va_datalen = rap->a_nr.a_datalen;
465		vap->va_allocated = rap->a_nr.a_allocated;
466		vap->va_vcnstart = rap->a_nr.a_vcnstart;
467		vap->va_vcnend = rap->a_nr.a_vcnend;
468		vap->va_compressalg = rap->a_nr.a_compressalg;
469		error = ntfs_runtovrun(&(vap->va_vruncn), &(vap->va_vruncl),
470				       &(vap->va_vruncnt),
471				       (caddr_t) rap + rap->a_nr.a_dataoff);
472	} else {
473		vap->va_compressalg = 0;
474		ddprintf((", res."));
475		vap->va_datalen = rap->a_r.a_datalen;
476		vap->va_allocated = rap->a_r.a_datalen;
477		vap->va_vcnstart = 0;
478		vap->va_vcnend = ntfs_btocn(vap->va_allocated);
479		MALLOC(vap->va_datap, caddr_t, vap->va_datalen,
480		       M_NTFSRDATA, M_WAITOK);
481		memcpy(vap->va_datap, (caddr_t) rap + rap->a_r.a_dataoff,
482		       rap->a_r.a_datalen);
483	}
484	ddprintf((", len: %d", vap->va_datalen));
485
486	if (error)
487		FREE(vap, M_NTFSNTVATTR);
488	else
489		*rvapp = vap;
490
491	ddprintf(("\n"));
492
493	return (error);
494}
495
496int
497ntfs_runtovrun(
498	       cn_t ** rcnp,
499	       cn_t ** rclp,
500	       u_long * rcntp,
501	       u_int8_t * run)
502{
503	u_int32_t       off;
504	u_int32_t       sz, i;
505	cn_t           *cn;
506	cn_t           *cl;
507	u_long		cnt;
508	cn_t		prev;
509	cn_t		tmp;
510
511	off = 0;
512	cnt = 0;
513	i = 0;
514	while (run[off]) {
515		off += (run[off] & 0xF) + ((run[off] >> 4) & 0xF) + 1;
516		cnt++;
517	}
518	MALLOC(cn, cn_t *, cnt * sizeof(cn_t), M_NTFSRUN, M_WAITOK);
519	MALLOC(cl, cn_t *, cnt * sizeof(cn_t), M_NTFSRUN, M_WAITOK);
520
521	off = 0;
522	cnt = 0;
523	prev = 0;
524	while (run[off]) {
525
526		sz = run[off++];
527		cl[cnt] = 0;
528
529		for (i = 0; i < (sz & 0xF); i++)
530			cl[cnt] += (u_int32_t) run[off++] << (i << 3);
531
532		sz >>= 4;
533		if (run[off + sz - 1] & 0x80) {
534			tmp = ((u_int64_t) - 1) << (sz << 3);
535			for (i = 0; i < sz; i++)
536				tmp |= (u_int64_t) run[off++] << (i << 3);
537		} else {
538			tmp = 0;
539			for (i = 0; i < sz; i++)
540				tmp |= (u_int64_t) run[off++] << (i << 3);
541		}
542		if (tmp)
543			prev = cn[cnt] = prev + tmp;
544		else
545			cn[cnt] = tmp;
546
547		cnt++;
548	}
549	*rcnp = cn;
550	*rclp = cl;
551	*rcntp = cnt;
552	return (0);
553}
554
555
556wchar
557ntfs_toupper(
558	     struct ntfsmount * ntmp,
559	     wchar wc)
560{
561	return (ntmp->ntm_upcase[wc & 0xFF]);
562}
563
564int
565ntfs_uustricmp(
566	       struct ntfsmount * ntmp,
567	       wchar * str1,
568	       int str1len,
569	       wchar * str2,
570	       int str2len)
571{
572	int             i;
573	int             res;
574
575	for (i = 0; i < str1len && i < str2len; i++) {
576		res = (int) ntfs_toupper(ntmp, str1[i]) -
577			(int) ntfs_toupper(ntmp, str2[i]);
578		if (res)
579			return res;
580	}
581	return (str1len - str2len);
582}
583
584int
585ntfs_uastricmp(
586	       struct ntfsmount * ntmp,
587	       wchar * str1,
588	       int str1len,
589	       char *str2,
590	       int str2len)
591{
592	int             i;
593	int             res;
594
595	for (i = 0; i < str1len && i < str2len; i++) {
596		res = (int) ntfs_toupper(ntmp, str1[i]) -
597			(int) ntfs_toupper(ntmp, (wchar) str2[i]);
598		if (res)
599			return res;
600	}
601	return (str1len - str2len);
602}
603
604int
605ntfs_uastrcmp(
606	      struct ntfsmount * ntmp,
607	      wchar * str1,
608	      int str1len,
609	      char *str2,
610	      int str2len)
611{
612	int             i;
613	int             res;
614
615	for (i = 0; (i < str1len) && (i < str2len); i++) {
616		res = ((int) str1[i]) - ((int) str2[i]);
617		if (res)
618			return res;
619	}
620	return (str1len - str2len);
621}
622
623int
624ntfs_fget(
625	struct ntfsmount *ntmp,
626	struct ntnode *ip,
627	int attrtype,
628	char *attrname,
629	struct fnode **fpp)
630{
631	int error;
632	struct fnode *fp;
633
634	dprintf(("ntfs_fget: ino: %d, attrtype: 0x%x, attrname: %s\n",
635		ip->i_number,attrtype, attrname?attrname:""));
636	*fpp = NULL;
637	for (fp = ip->i_fnlist.lh_first; fp != NULL; fp = fp->f_fnlist.le_next){
638		dprintf(("ntfs_fget: fnode: attrtype: %d, attrname: %s\n",
639			fp->f_attrtype, fp->f_attrname?fp->f_attrname:""));
640
641		if ((attrtype == fp->f_attrtype) &&
642		    ((!attrname && !fp->f_attrname) ||
643		     (attrname && fp->f_attrname &&
644		      !strcmp(attrname,fp->f_attrname)))){
645			dprintf(("ntfs_fget: found existed: %p\n",fp));
646			*fpp = fp;
647		}
648	}
649
650	if (*fpp)
651		return (0);
652
653	MALLOC(fp, struct fnode *, sizeof(struct fnode), M_NTFSFNODE, M_WAITOK);
654	bzero(fp, sizeof(struct fnode));
655	dprintf(("ntfs_fget: allocating fnode: %p\n",fp));
656
657	fp->f_devvp = ntmp->ntm_devvp;
658	fp->f_dev = ntmp->ntm_dev;
659	fp->f_mp = ntmp;
660
661	fp->f_ip = ip;
662	fp->f_attrname = attrname;
663	if (fp->f_attrname) fp->f_flag |= FN_AATTRNAME;
664	fp->f_attrtype = attrtype;
665	if ((fp->f_attrtype == NTFS_A_DATA) && (fp->f_attrname == NULL))
666		 fp->f_flag |= FN_DEFAULT;
667	else {
668		error = ntfs_filesize(ntmp, fp, &fp->f_size, &fp->f_allocated);
669		if (error) {
670			FREE(fp,M_NTFSFNODE);
671			return (error);
672		}
673	}
674
675	ntfs_ntref(ip);
676
677	LIST_INSERT_HEAD(&ip->i_fnlist, fp, f_fnlist);
678
679	*fpp = fp;
680
681	return (0);
682}
683
684void
685ntfs_frele(
686	struct fnode *fp)
687{
688	struct ntnode *ip = FTONT(fp);
689
690	dprintf(("ntfs_frele: fnode: %p for %d: %p\n", fp, ip->i_number, ip));
691
692	dprintf(("ntfs_frele: deallocating fnode\n"));
693	LIST_REMOVE(fp,f_fnlist);
694	if (fp->f_flag & FN_AATTRNAME)
695		FREE(fp->f_attrname, M_TEMP);
696	if (fp->f_dirblbuf)
697		FREE(fp->f_dirblbuf, M_NTFSDIR);
698	FREE(fp, M_NTFSFNODE);
699	ntfs_ntrele(ip);
700}
701
702int
703ntfs_ntlookupattr(
704		struct ntfsmount * ntmp,
705		char * name,
706		int namelen,
707		int *attrtype,
708		char **attrname)
709{
710	char *sys;
711	int syslen,i;
712	struct ntvattrdef *adp;
713
714	if (namelen == 0)
715		return (0);
716
717	if (name[0] == '$') {
718		sys = name;
719		for (syslen = 0; syslen < namelen; syslen++) {
720			if(sys[syslen] == ':') {
721				name++;
722				namelen--;
723				break;
724			}
725		}
726		name += syslen;
727		namelen -= syslen;
728
729		adp = ntmp->ntm_ad;
730		for (i = 0; i < ntmp->ntm_adnum; i++){
731			if((syslen == adp->ad_namelen) &&
732			   (!strncmp(sys,adp->ad_name,syslen))) {
733				*attrtype = adp->ad_type;
734				if(namelen) {
735					MALLOC((*attrname), char *, namelen,
736						M_TEMP, M_WAITOK);
737					memcpy((*attrname), name, namelen);
738					(*attrname)[namelen] = '\0';
739				}
740				return (0);
741			}
742			adp++;
743		}
744		return (ENOENT);
745	}
746
747	if(namelen) {
748		MALLOC((*attrname), char *, namelen, M_TEMP, M_WAITOK);
749		memcpy((*attrname), name, namelen);
750		(*attrname)[namelen] = '\0';
751		*attrtype = NTFS_A_DATA;
752	}
753
754	return (0);
755}
756/*
757 * Lookup specifed node for filename, matching cnp,
758 * return fnode filled.
759 */
760int
761ntfs_ntlookup(
762	      struct ntfsmount * ntmp,
763	      struct vnode * vp,
764	      struct componentname * cnp,
765	      struct vnode ** vpp)
766{
767	struct fnode   *fp = VTOF(vp);
768	struct ntnode  *ip = FTONT(fp);
769	struct ntvattr *vap;	/* Root attribute */
770	cn_t            cn;	/* VCN in current attribute */
771	caddr_t         rdbuf;	/* Buffer to read directory's blocks  */
772	u_int32_t       blsize;
773	u_int32_t       rdsize;	/* Length of data to read from current block */
774	struct attr_indexentry *iep;
775	int             error, res, anamelen, fnamelen;
776	char	       *fname,*aname;
777	u_int32_t       aoff;
778
779	error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXROOT, "$I30", 0, &vap);
780	if (error || (vap->va_flag & NTFS_AF_INRUN))
781		return (ENOTDIR);
782
783	blsize = vap->va_a_iroot->ir_size;
784	rdsize = vap->va_datalen;
785
786	fname = cnp->cn_nameptr;
787	aname = NULL;
788	anamelen = 0;
789	for (fnamelen = 0; fnamelen < cnp->cn_namelen; fnamelen++)
790		if(fname[fnamelen] == ':') {
791			aname = fname + fnamelen + 1;
792			anamelen = cnp->cn_namelen - fnamelen - 1;
793			dprintf(("ntfs_ntlookup: file %s (%d), attr: %s (%d)\n",
794				fname, fnamelen, aname, anamelen));
795			break;
796		}
797
798	dprintf(("ntfs_ntlookup: blocksize: %d, rdsize: %d\n", blsize, rdsize));
799
800	MALLOC(rdbuf, caddr_t, blsize, M_TEMP, M_WAITOK);
801
802	error = ntfs_readattr(ntmp, ip, NTFS_A_INDXROOT, "$I30",
803			       0, rdsize, rdbuf);
804	if (error)
805		goto fail;
806
807	aoff = sizeof(struct attr_indexroot);
808
809	do {
810		iep = (struct attr_indexentry *) (rdbuf + aoff);
811
812		while (!(iep->ie_flag & NTFS_IEFLAG_LAST) && (rdsize > aoff)) {
813			ddprintf(("scan: %d, %d\n",
814				  (u_int32_t) iep->ie_number,
815				  (u_int32_t) iep->ie_fnametype));
816			res = ntfs_uastricmp(ntmp, iep->ie_fname,
817					     iep->ie_fnamelen, fname,
818					     fnamelen);
819			if (res == 0) {
820				/* Matched something (case ins.) */
821				if (iep->ie_fnametype == 0 ||
822				    !(ntmp->ntm_flag & NTFS_MFLAG_CASEINS))
823					res = ntfs_uastrcmp(ntmp,
824							    iep->ie_fname,
825							    iep->ie_fnamelen,
826							    fname,
827							    fnamelen);
828				if (res == 0) {
829					int attrtype = NTFS_A_DATA;
830					char *attrname = NULL;
831					struct fnode   *nfp;
832					struct vnode   *nvp;
833
834					if (aname) {
835						error = ntfs_ntlookupattr(ntmp,
836							aname, anamelen,
837							&attrtype, &attrname);
838						if (error)
839							goto fail;
840					}
841
842					/* Check if we've found ourself */
843					if ((iep->ie_number == ip->i_number) &&
844					    (attrtype == fp->f_attrtype) &&
845					    ((!attrname && !fp->f_attrname) ||
846					     (attrname && fp->f_attrname &&
847					      !strcmp(attrname, fp->f_attrname)))) {
848						VREF(vp);
849						*vpp = vp;
850						goto fail;
851					}
852
853					/* vget node, but don't load it */
854					error = ntfs_vgetex(ntmp->ntm_mountp,
855							   iep->ie_number,
856							   attrtype,
857							   attrname,
858							   LK_EXCLUSIVE,
859							   VG_DONTLOAD,
860							   curproc,
861							   &nvp);
862					if(error)
863						goto fail;
864
865					nfp = VTOF(nvp);
866
867					nfp->f_fflag = iep->ie_fflag;
868					nfp->f_pnumber = iep->ie_fpnumber;
869					nfp->f_times = iep->ie_ftimes;
870
871					if((nfp->f_fflag & NTFS_FFLAG_DIR) &&
872					   (nfp->f_attrtype == NTFS_A_DATA) &&
873					   (nfp->f_attrname == NULL))
874						nfp->f_type = VDIR;
875					else
876						nfp->f_type = VREG;
877
878					nvp->v_type = nfp->f_type;
879
880					if ((nfp->f_attrtype == NTFS_A_DATA) &&
881					    (nfp->f_attrname == NULL)) {
882						/* Opening default attribute */
883						nfp->f_size = iep->ie_fsize;
884						nfp->f_allocated = iep->ie_fallocated;
885						nfp->f_flag |= FN_PRELOADED;
886					}
887					*vpp = nvp;
888					goto fail;
889				}
890			} else if (res > 0)
891				break;
892
893			aoff += iep->reclen;
894			iep = (struct attr_indexentry *) (rdbuf + aoff);
895		}
896
897		/* Dive if possible */
898		if (iep->ie_flag & NTFS_IEFLAG_SUBNODE) {
899			dprintf(("ntfs_ntlookup: diving\n"));
900
901			cn = *(cn_t *) (rdbuf + aoff +
902					iep->reclen - sizeof(cn_t));
903			rdsize = blsize;
904
905			error = ntfs_readattr(ntmp, ip, NTFS_A_INDX, "$I30",
906					     ntfs_cntob(cn), rdsize, rdbuf);
907			if (error)
908				goto fail;
909
910			error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC,
911						rdbuf, rdsize);
912			if (error)
913				goto fail;
914
915			aoff = (((struct attr_indexalloc *) rdbuf)->ia_hdrsize +
916				0x18);
917		} else {
918			dprintf(("ntfs_ntlookup: nowhere to dive :-(\n"));
919			error = ENOENT;
920			break;
921		}
922	} while (1);
923
924	dprintf(("finish\n"));
925
926fail:
927	ntfs_ntvattrrele(vap);
928	FREE(rdbuf, M_TEMP);
929	return (error);
930}
931
932int
933ntfs_isnamepermitted(
934		     struct ntfsmount * ntmp,
935		     struct attr_indexentry * iep)
936{
937
938	if (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES)
939		return 1;
940
941	switch (iep->ie_fnametype) {
942	case 2:
943		ddprintf(("ntfs_isnamepermitted: skiped DOS name\n"));
944		return 0;
945	case 0:
946	case 1:
947	case 3:
948		return 1;
949	default:
950		printf("ntfs_isnamepermitted: " \
951		       "WARNING! Unknown file name type: %d\n",
952		       iep->ie_fnametype);
953		break;
954	}
955	return 0;
956}
957
958int
959ntfs_ntreaddir(
960	       struct ntfsmount * ntmp,
961	       struct fnode * fp,
962	       u_int32_t num,
963	       struct attr_indexentry ** riepp)
964{
965	struct ntnode  *ip = FTONT(fp);
966	struct ntvattr *vap = NULL;	/* IndexRoot attribute */
967	struct ntvattr *bmvap = NULL;	/* BitMap attribute */
968	struct ntvattr *iavap = NULL;	/* IndexAllocation attribute */
969	caddr_t         rdbuf;		/* Buffer to read directory's blocks  */
970	u_char         *bmp = NULL;	/* Bitmap */
971	u_int32_t       blsize;		/* Index allocation size (2048) */
972	u_int32_t       rdsize;		/* Length of data to read */
973	u_int32_t       attrnum;	/* Current attribute type */
974	u_int32_t       cpbl = 1;	/* Clusters per directory block */
975	u_int32_t       blnum;
976	struct attr_indexentry *iep;
977	int             error = ENOENT;
978	u_int32_t       aoff, cnum;
979
980	dprintf(("ntfs_ntreaddir: read ino: %d, num: %d\n", ip->i_number, num));
981	error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXROOT, "$I30", 0, &vap);
982	if (error)
983		return (ENOTDIR);
984
985	if (fp->f_dirblbuf == NULL) {
986		fp->f_dirblsz = vap->va_a_iroot->ir_size;
987		MALLOC(fp->f_dirblbuf, caddr_t,
988		       max(vap->va_datalen,fp->f_dirblsz), M_NTFSDIR, M_WAITOK);
989	}
990
991	blsize = fp->f_dirblsz;
992	rdbuf = fp->f_dirblbuf;
993
994	dprintf(("ntfs_ntreaddir: rdbuf: 0x%p, blsize: %d\n", rdbuf, blsize));
995
996	if (vap->va_a_iroot->ir_flag & NTFS_IRFLAG_INDXALLOC) {
997		error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXBITMAP, "$I30",
998					0, &bmvap);
999		if (error) {
1000			error = ENOTDIR;
1001			goto fail;
1002		}
1003		MALLOC(bmp, u_char *, bmvap->va_datalen, M_TEMP, M_WAITOK);
1004		error = ntfs_readattr(ntmp, ip, NTFS_A_INDXBITMAP, "$I30", 0,
1005				       bmvap->va_datalen, bmp);
1006		if (error)
1007			goto fail;
1008
1009		error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDX, "$I30",
1010					0, &iavap);
1011		if (error) {
1012			error = ENOTDIR;
1013			goto fail;
1014		}
1015		cpbl = ntfs_btocn(blsize + ntfs_cntob(1) - 1);
1016		dprintf(("ntfs_ntreaddir: indexalloc: %d, cpbl: %d\n",
1017			 iavap->va_datalen, cpbl));
1018	} else {
1019		dprintf(("ntfs_ntreadidir: w/o BitMap and IndexAllocation\n"));
1020		iavap = bmvap = NULL;
1021		bmp = NULL;
1022	}
1023
1024	/* Try use previous values */
1025	if ((fp->f_lastdnum < num) && (fp->f_lastdnum != 0)) {
1026		attrnum = fp->f_lastdattr;
1027		aoff = fp->f_lastdoff;
1028		blnum = fp->f_lastdblnum;
1029		cnum = fp->f_lastdnum;
1030	} else {
1031		attrnum = NTFS_A_INDXROOT;
1032		aoff = sizeof(struct attr_indexroot);
1033		blnum = 0;
1034		cnum = 0;
1035	}
1036
1037	do {
1038		dprintf(("ntfs_ntreaddir: scan: 0x%x, %d, %d, %d, %d\n",
1039			 attrnum, (u_int32_t) blnum, cnum, num, aoff));
1040		rdsize = (attrnum == NTFS_A_INDXROOT) ? vap->va_datalen : blsize;
1041		error = ntfs_readattr(ntmp, ip, attrnum, "$I30",
1042				   ntfs_cntob(blnum * cpbl), rdsize, rdbuf);
1043		if (error)
1044			goto fail;
1045
1046		if (attrnum == NTFS_A_INDX) {
1047			error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC,
1048						rdbuf, rdsize);
1049			if (error)
1050				goto fail;
1051		}
1052		if (aoff == 0)
1053			aoff = (attrnum == NTFS_A_INDX) ?
1054				(0x18 + ((struct attr_indexalloc *) rdbuf)->ia_hdrsize) :
1055				sizeof(struct attr_indexroot);
1056
1057		iep = (struct attr_indexentry *) (rdbuf + aoff);
1058		while (!(iep->ie_flag & NTFS_IEFLAG_LAST) && (rdsize > aoff)) {
1059			if (ntfs_isnamepermitted(ntmp, iep)) {
1060				if (cnum >= num) {
1061					fp->f_lastdnum = cnum;
1062					fp->f_lastdoff = aoff;
1063					fp->f_lastdblnum = blnum;
1064					fp->f_lastdattr = attrnum;
1065
1066					*riepp = iep;
1067
1068					error = 0;
1069					goto fail;
1070				}
1071				cnum++;
1072			}
1073			aoff += iep->reclen;
1074			iep = (struct attr_indexentry *) (rdbuf + aoff);
1075		}
1076
1077		if (iavap) {
1078			if (attrnum == NTFS_A_INDXROOT)
1079				blnum = 0;
1080			else
1081				blnum++;
1082
1083			while (ntfs_cntob(blnum * cpbl) < iavap->va_datalen) {
1084				if (bmp[blnum >> 3] & (1 << (blnum & 3)))
1085					break;
1086				blnum++;
1087			}
1088
1089			attrnum = NTFS_A_INDX;
1090			aoff = 0;
1091			if (ntfs_cntob(blnum * cpbl) >= iavap->va_datalen)
1092				break;
1093			dprintf(("ntfs_ntreaddir: blnum: %d\n", (u_int32_t) blnum));
1094		}
1095	} while (iavap);
1096
1097	*riepp = NULL;
1098	fp->f_lastdnum = 0;
1099
1100fail:
1101	if (vap)
1102		ntfs_ntvattrrele(vap);
1103	if (bmvap)
1104		ntfs_ntvattrrele(bmvap);
1105	if (iavap)
1106		ntfs_ntvattrrele(iavap);
1107	if (bmp)
1108		FREE(bmp, M_TEMP);
1109	return (error);
1110}
1111/*
1112 * #undef dprintf #define dprintf(a)
1113 */
1114
1115struct timespec
1116ntfs_nttimetounix(
1117		  u_int64_t nt)
1118{
1119	struct timespec t;
1120
1121	/* WindowNT times are in 100 ns and from 1601 Jan 1 */
1122	t.tv_nsec = (nt % (1000 * 1000 * 10)) * 100;
1123	t.tv_sec = nt / (1000 * 1000 * 10) -
1124		369LL * 365LL * 24LL * 60LL * 60LL -
1125		89LL * 1LL * 24LL * 60LL * 60LL;
1126	return (t);
1127}
1128
1129int
1130ntfs_times(
1131	   struct ntfsmount * ntmp,
1132	   struct ntnode * ip,
1133	   ntfs_times_t * tm)
1134{
1135	struct ntvattr *vap;
1136	int             error;
1137
1138	dprintf(("ntfs_times: ino: %d...\n", ip->i_number));
1139	error = ntfs_ntvattrget(ntmp, ip, NTFS_A_NAME, NULL, 0, &vap);
1140	if (error)
1141		return (error);
1142	*tm = vap->va_a_name->n_times;
1143	ntfs_ntvattrrele(vap);
1144
1145	return (0);
1146}
1147
1148int
1149ntfs_filesize(
1150	      struct ntfsmount * ntmp,
1151	      struct fnode * fp,
1152	      u_int64_t * size,
1153	      u_int64_t * bytes)
1154{
1155	struct ntvattr *vap;
1156	struct ntnode *ip = FTONT(fp);
1157	u_int64_t       sz, bn;
1158	int             error;
1159
1160	dprintf(("ntfs_filesize: ino: %d\n", ip->i_number));
1161	if (fp->f_flag & FN_DEFAULT) {
1162		error = ntfs_ntvattrget(ntmp, ip,
1163			NTFS_A_DATA, NULL, 0, &vap);
1164	} else {
1165		error = ntfs_ntvattrget(ntmp, ip,
1166			fp->f_attrtype, fp->f_attrname, 0, &vap);
1167	}
1168	if (error)
1169		return (error);
1170	bn = vap->va_allocated;
1171	sz = vap->va_datalen;
1172
1173	dprintf(("ntfs_filesize: %d bytes (%d bytes allocated)\n",
1174		(u_int32_t) sz, (u_int32_t) bn));
1175
1176	if (size)
1177		*size = sz;
1178	if (bytes)
1179		*bytes = bn;
1180
1181	ntfs_ntvattrrele(vap);
1182
1183	return (0);
1184}
1185
1186int
1187ntfs_writeattr_plain(
1188		     struct ntfsmount * ntmp,
1189		     struct ntnode * ip,
1190		     u_int32_t attrnum,
1191		     char *attrname,
1192		     off_t roff,
1193		     size_t rsize,
1194		     void *rdata,
1195		     size_t * initp)
1196{
1197	size_t          init;
1198	int             error = 0;
1199	off_t           off = roff, left = rsize, towrite;
1200	caddr_t         data = rdata;
1201	struct ntvattr *vap;
1202	*initp = 0;
1203
1204	while (left) {
1205		error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname,
1206					ntfs_btocn(off), &vap);
1207		if (error)
1208			return (error);
1209		towrite = min(left, ntfs_cntob(vap->va_vcnend + 1) - off);
1210		ddprintf(("ntfs_writeattr_plain: o: %d, s: %d (%d - %d)\n",
1211			 (u_int32_t) off, (u_int32_t) towrite,
1212			 (u_int32_t) vap->va_vcnstart,
1213			 (u_int32_t) vap->va_vcnend));
1214		error = ntfs_writentvattr_plain(ntmp, ip, vap,
1215					 off - ntfs_cntob(vap->va_vcnstart),
1216					 towrite, data, &init);
1217		if (error) {
1218			printf("ntfs_writeattr_plain: " \
1219			       "ntfs_writentvattr_plain failed: o: %d, s: %d\n",
1220			       (u_int32_t) off, (u_int32_t) towrite);
1221			printf("ntfs_writeattr_plain: attrib: %d - %d\n",
1222			       (u_int32_t) vap->va_vcnstart,
1223			       (u_int32_t) vap->va_vcnend);
1224			ntfs_ntvattrrele(vap);
1225			break;
1226		}
1227		ntfs_ntvattrrele(vap);
1228		left -= towrite;
1229		off += towrite;
1230		data = data + towrite;
1231		*initp += init;
1232	}
1233
1234	return (error);
1235}
1236
1237int
1238ntfs_writentvattr_plain(
1239			struct ntfsmount * ntmp,
1240			struct ntnode * ip,
1241			struct ntvattr * vap,
1242			off_t roff,
1243			size_t rsize,
1244			void *rdata,
1245			size_t * initp)
1246{
1247	int             error = 0;
1248	int             off;
1249
1250	*initp = 0;
1251	if (vap->va_flag & NTFS_AF_INRUN) {
1252		int             cnt;
1253		cn_t            ccn, ccl, cn, left, cl;
1254		caddr_t         data = rdata;
1255		struct buf     *bp;
1256		size_t          tocopy;
1257
1258		ddprintf(("ntfs_writentvattr_plain: data in run: %d chains\n",
1259			 vap->va_vruncnt));
1260
1261		off = roff;
1262		left = rsize;
1263		ccl = 0;
1264		ccn = 0;
1265		cnt = 0;
1266		while (left && (cnt < vap->va_vruncnt)) {
1267			ccn = vap->va_vruncn[cnt];
1268			ccl = vap->va_vruncl[cnt];
1269
1270			ddprintf(("ntfs_writentvattr_plain: " \
1271				 "left %d, cn: 0x%x, cl: %d, off: %d\n", \
1272				 (u_int32_t) left, (u_int32_t) ccn, \
1273				 (u_int32_t) ccl, (u_int32_t) off));
1274
1275			if (ntfs_cntob(ccl) < off) {
1276				off -= ntfs_cntob(ccl);
1277				cnt++;
1278				continue;
1279			}
1280			if (ccn || ip->i_number == NTFS_BOOTINO) { /* XXX */
1281				ccl -= ntfs_btocn(off);
1282				cn = ccn + ntfs_btocn(off);
1283				off = ntfs_btocnoff(off);
1284
1285				while (left && ccl) {
1286					tocopy = min(left,
1287						  min(ntfs_cntob(ccl) - off,
1288						      MAXBSIZE - off));
1289					cl = ntfs_btocl(tocopy + off);
1290					ddprintf(("ntfs_writentvattr_plain: " \
1291						"write: cn: 0x%x cl: %d, " \
1292						"off: %d len: %d, left: %d\n",
1293						(u_int32_t) cn,
1294						(u_int32_t) cl,
1295						(u_int32_t) off,
1296						(u_int32_t) tocopy,
1297						(u_int32_t) left));
1298					if ((off == 0) &&
1299					    (tocopy == ntfs_cntob(cl))) {
1300						bp = getblk(ntmp->ntm_devvp,
1301							    ntfs_cntobn(cn),
1302							    ntfs_cntob(cl),
1303							    0, 0);
1304						clrbuf(bp);
1305					} else {
1306						error = bread(ntmp->ntm_devvp,
1307							      ntfs_cntobn(cn),
1308							      ntfs_cntob(cl),
1309							      NOCRED, &bp);
1310						if (error) {
1311							brelse(bp);
1312							return (error);
1313						}
1314					}
1315					memcpy(bp->b_data + off, data, tocopy);
1316					bwrite(bp);
1317					data = data + tocopy;
1318					*initp += tocopy;
1319					off = 0;
1320					left -= tocopy;
1321					cn += cl;
1322					ccl -= cl;
1323				}
1324			}
1325			cnt++;
1326		}
1327		if (left) {
1328			printf("ntfs_writentvattr_plain: POSSIBLE RUN ERROR\n");
1329			error = EINVAL;
1330		}
1331	} else {
1332		printf("ntfs_writevattr_plain: CAN'T WRITE RES. ATTRIBUTE\n");
1333		error = ENOTTY;
1334	}
1335
1336	return (error);
1337}
1338
1339int
1340ntfs_readntvattr_plain(
1341			struct ntfsmount * ntmp,
1342			struct ntnode * ip,
1343			struct ntvattr * vap,
1344			off_t roff,
1345			size_t rsize,
1346			void *rdata,
1347			size_t * initp)
1348{
1349	int             error = 0;
1350	int             off;
1351
1352	*initp = 0;
1353	if (vap->va_flag & NTFS_AF_INRUN) {
1354		int             cnt;
1355		cn_t            ccn, ccl, cn, left, cl;
1356		caddr_t         data = rdata;
1357		struct buf     *bp;
1358		size_t          tocopy;
1359
1360		ddprintf(("ntfs_readntvattr_plain: data in run: %d chains\n",
1361			 vap->va_vruncnt));
1362
1363		off = roff;
1364		left = rsize;
1365		ccl = 0;
1366		ccn = 0;
1367		cnt = 0;
1368		while (left && (cnt < vap->va_vruncnt)) {
1369			ccn = vap->va_vruncn[cnt];
1370			ccl = vap->va_vruncl[cnt];
1371
1372			ddprintf(("ntfs_readntvattr_plain: " \
1373				 "left %d, cn: 0x%x, cl: %d, off: %d\n", \
1374				 (u_int32_t) left, (u_int32_t) ccn, \
1375				 (u_int32_t) ccl, (u_int32_t) off));
1376
1377			if (ntfs_cntob(ccl) < off) {
1378				off -= ntfs_cntob(ccl);
1379				cnt++;
1380				continue;
1381			}
1382			if (ccn || ip->i_number == NTFS_BOOTINO) { /* XXX */
1383				ccl -= ntfs_btocn(off);
1384				cn = ccn + ntfs_btocn(off);
1385				off = ntfs_btocnoff(off);
1386
1387				while (left && ccl) {
1388					tocopy = min(left,
1389						  min(ntfs_cntob(ccl) - off,
1390						      MAXBSIZE - off));
1391					cl = ntfs_btocl(tocopy + off);
1392					ddprintf(("ntfs_readntvattr_plain: " \
1393						"read: cn: 0x%x cl: %d, " \
1394						"off: %d len: %d, left: %d\n",
1395						(u_int32_t) cn,
1396						(u_int32_t) cl,
1397						(u_int32_t) off,
1398						(u_int32_t) tocopy,
1399						(u_int32_t) left));
1400					error = bread(ntmp->ntm_devvp,
1401						      ntfs_cntobn(cn),
1402						      ntfs_cntob(cl),
1403						      NOCRED, &bp);
1404					if (error) {
1405						brelse(bp);
1406						return (error);
1407					}
1408					memcpy(data, bp->b_data + off, tocopy);
1409					brelse(bp);
1410					data = data + tocopy;
1411					*initp += tocopy;
1412					off = 0;
1413					left -= tocopy;
1414					cn += cl;
1415					ccl -= cl;
1416				}
1417			} else {
1418				tocopy = min(left, ntfs_cntob(ccl) - off);
1419				ddprintf(("ntfs_readntvattr_plain: "
1420					"sparce: ccn: 0x%x ccl: %d, off: %d, " \
1421					" len: %d, left: %d\n",
1422					(u_int32_t) ccn, (u_int32_t) ccl,
1423					(u_int32_t) off, (u_int32_t) tocopy,
1424					(u_int32_t) left));
1425				left -= tocopy;
1426				off = 0;
1427				bzero(data, tocopy);
1428				data = data + tocopy;
1429			}
1430			cnt++;
1431		}
1432		if (left) {
1433			printf("ntfs_readntvattr_plain: POSSIBLE RUN ERROR\n");
1434			error = E2BIG;
1435		}
1436	} else {
1437		ddprintf(("ntfs_readnvattr_plain: data is in mft record\n"));
1438		memcpy(rdata, vap->va_datap + roff, rsize);
1439		*initp += rsize;
1440	}
1441
1442	return (error);
1443}
1444
1445int
1446ntfs_readattr_plain(
1447		     struct ntfsmount * ntmp,
1448		     struct ntnode * ip,
1449		     u_int32_t attrnum,
1450		     char *attrname,
1451		     off_t roff,
1452		     size_t rsize,
1453		     void *rdata,
1454		     size_t * initp)
1455{
1456	size_t          init;
1457	int             error = 0;
1458	off_t           off = roff, left = rsize, toread;
1459	caddr_t         data = rdata;
1460	struct ntvattr *vap;
1461	*initp = 0;
1462
1463	while (left) {
1464		error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname,
1465					ntfs_btocn(off), &vap);
1466		if (error)
1467			return (error);
1468		toread = min(left, ntfs_cntob(vap->va_vcnend + 1) - off);
1469		ddprintf(("ntfs_readattr_plain: o: %d, s: %d (%d - %d)\n",
1470			 (u_int32_t) off, (u_int32_t) toread,
1471			 (u_int32_t) vap->va_vcnstart,
1472			 (u_int32_t) vap->va_vcnend));
1473		error = ntfs_readntvattr_plain(ntmp, ip, vap,
1474					 off - ntfs_cntob(vap->va_vcnstart),
1475					 toread, data, &init);
1476		if (error) {
1477			printf("ntfs_readattr_plain: " \
1478			       "ntfs_readntvattr_plain failed: o: %d, s: %d\n",
1479			       (u_int32_t) off, (u_int32_t) toread);
1480			printf("ntfs_readattr_plain: attrib: %d - %d\n",
1481			       (u_int32_t) vap->va_vcnstart,
1482			       (u_int32_t) vap->va_vcnend);
1483			ntfs_ntvattrrele(vap);
1484			break;
1485		}
1486		ntfs_ntvattrrele(vap);
1487		left -= toread;
1488		off += toread;
1489		data = data + toread;
1490		*initp += init;
1491	}
1492
1493	return (error);
1494}
1495
1496int
1497ntfs_readattr(
1498	       struct ntfsmount * ntmp,
1499	       struct ntnode * ip,
1500	       u_int32_t attrnum,
1501	       char *attrname,
1502	       off_t roff,
1503	       size_t rsize,
1504	       void *rdata)
1505{
1506	int             error = 0;
1507	struct ntvattr *vap;
1508	size_t          init;
1509
1510	ddprintf(("ntfs_readattr: reading %d: 0x%x, from %d size %d bytes\n",
1511	       ip->i_number, attrnum, (u_int32_t) roff, (u_int32_t) rsize));
1512
1513	error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname, 0, &vap);
1514	if (error)
1515		return (error);
1516
1517	if ((roff > vap->va_datalen) ||
1518	    (roff + rsize > vap->va_datalen)) {
1519		ddprintf(("ntfs_readattr: offset too big\n"));
1520		ntfs_ntvattrrele(vap);
1521		return (E2BIG);
1522	}
1523	if (vap->va_compression && vap->va_compressalg) {
1524		u_int8_t       *cup;
1525		u_int8_t       *uup;
1526		off_t           off = roff, left = rsize, tocopy;
1527		caddr_t         data = rdata;
1528		cn_t            cn;
1529
1530		ddprintf(("ntfs_ntreadattr: compression: %d\n",
1531			 vap->va_compressalg));
1532
1533		MALLOC(cup, u_int8_t *, ntfs_cntob(NTFS_COMPUNIT_CL),
1534		       M_NTFSDECOMP, M_WAITOK);
1535		MALLOC(uup, u_int8_t *, ntfs_cntob(NTFS_COMPUNIT_CL),
1536		       M_NTFSDECOMP, M_WAITOK);
1537
1538		cn = (ntfs_btocn(roff)) & (~(NTFS_COMPUNIT_CL - 1));
1539		off = roff - ntfs_cntob(cn);
1540
1541		while (left) {
1542			error = ntfs_readattr_plain(ntmp, ip, attrnum,
1543						  attrname, ntfs_cntob(cn),
1544					          ntfs_cntob(NTFS_COMPUNIT_CL),
1545						  cup, &init);
1546			if (error)
1547				break;
1548
1549			tocopy = min(left, ntfs_cntob(NTFS_COMPUNIT_CL) - off);
1550
1551			if (init == ntfs_cntob(NTFS_COMPUNIT_CL)) {
1552				memcpy(data, cup + off, tocopy);
1553			} else if (init == 0) {
1554				bzero(data, tocopy);
1555			} else {
1556				error = ntfs_uncompunit(ntmp, uup, cup);
1557				if (error)
1558					break;
1559				memcpy(data, uup + off, tocopy);
1560			}
1561
1562			left -= tocopy;
1563			data = data + tocopy;
1564			off += tocopy - ntfs_cntob(NTFS_COMPUNIT_CL);
1565			cn += NTFS_COMPUNIT_CL;
1566		}
1567
1568		FREE(uup, M_NTFSDECOMP);
1569		FREE(cup, M_NTFSDECOMP);
1570	} else
1571		error = ntfs_readattr_plain(ntmp, ip, attrnum, attrname,
1572					     roff, rsize, rdata, &init);
1573	ntfs_ntvattrrele(vap);
1574	return (error);
1575}
1576
1577int
1578ntfs_parserun(
1579	      cn_t * cn,
1580	      cn_t * cl,
1581	      u_int8_t * run,
1582	      u_long len,
1583	      u_long *off)
1584{
1585	u_int8_t        sz;
1586	int             i;
1587
1588	if (NULL == run) {
1589		printf("ntfs_parsetun: run == NULL\n");
1590		return (EINVAL);
1591	}
1592	sz = run[(*off)++];
1593	if (0 == sz) {
1594		printf("ntfs_parserun: trying to go out of run\n");
1595		return (E2BIG);
1596	}
1597	*cl = 0;
1598	if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) {
1599		printf("ntfs_parserun: " \
1600		       "bad run: length too big: sz: 0x%02x (%ld < %ld + sz)\n",
1601		       sz, len, *off);
1602		return (EINVAL);
1603	}
1604	for (i = 0; i < (sz & 0xF); i++)
1605		*cl += (u_int32_t) run[(*off)++] << (i << 3);
1606
1607	sz >>= 4;
1608	if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) {
1609		printf("ntfs_parserun: " \
1610		       "bad run: length too big: sz: 0x%02x (%ld < %ld + sz)\n",
1611		       sz, len, *off);
1612		return (EINVAL);
1613	}
1614	for (i = 0; i < (sz & 0xF); i++)
1615		*cn += (u_int32_t) run[(*off)++] << (i << 3);
1616
1617	return (0);
1618}
1619
1620int
1621ntfs_procfixups(
1622		struct ntfsmount * ntmp,
1623		u_int32_t magic,
1624		caddr_t buf,
1625		size_t len)
1626{
1627	struct fixuphdr *fhp = (struct fixuphdr *) buf;
1628	int             i;
1629	u_int16_t       fixup;
1630	u_int16_t      *fxp;
1631	u_int16_t      *cfxp;
1632
1633	if (fhp->fh_magic != magic) {
1634		printf("ntfs_procfixups: magic doesn't match: %08x != %08x\n",
1635		       fhp->fh_magic, magic);
1636		return (EINVAL);
1637	}
1638	if ((fhp->fh_fnum - 1) * ntmp->ntm_bps != len) {
1639		printf("ntfs_procfixups: " \
1640		       "bad fixups number: %d for %d bytes block\n",
1641		       fhp->fh_fnum, len);
1642		return (EINVAL);
1643	}
1644	if (fhp->fh_foff >= ntmp->ntm_spc * ntmp->ntm_mftrecsz * ntmp->ntm_bps) {
1645		printf("ntfs_procfixups: invalid offset: %x", fhp->fh_foff);
1646		return (EINVAL);
1647	}
1648	fxp = (u_int16_t *) (buf + fhp->fh_foff);
1649	cfxp = (u_int16_t *) (buf + ntmp->ntm_bps - 2);
1650	fixup = *fxp++;
1651	for (i = 1; i < fhp->fh_fnum; i++, fxp++) {
1652		if (*cfxp != fixup) {
1653			printf("ntfs_procfixups: fixup %d doesn't match\n", i);
1654			return (EINVAL);
1655		}
1656		*cfxp = *fxp;
1657		((caddr_t) cfxp) += ntmp->ntm_bps;
1658	}
1659	return (0);
1660}
1661
1662int
1663ntfs_runtocn(
1664	     cn_t * cn,
1665	     struct ntfsmount * ntmp,
1666	     u_int8_t * run,
1667	     u_long len,
1668	     cn_t vcn)
1669{
1670	cn_t            ccn = 0;
1671	cn_t            ccl = 0;
1672	u_long          off = 0;
1673	int             error = 0;
1674
1675#if NTFS_DEBUG
1676	int             i;
1677	printf("ntfs_runtocn: run: 0x%p, %ld bytes, vcn:%ld\n",
1678		run, len, (u_long) vcn);
1679	printf("ntfs_runtocn: run: ");
1680	for (i = 0; i < len; i++)
1681		printf("0x%02x ", run[i]);
1682	printf("\n");
1683#endif
1684
1685	if (NULL == run) {
1686		printf("ntfs_runtocn: run == NULL\n");
1687		return (EINVAL);
1688	}
1689	do {
1690		if (run[off] == 0) {
1691			printf("ntfs_runtocn: vcn too big\n");
1692			return (E2BIG);
1693		}
1694		vcn -= ccl;
1695		error = ntfs_parserun(&ccn, &ccl, run, len, &off);
1696		if (error) {
1697			printf("ntfs_runtocn: ntfs_parserun failed\n");
1698			return (error);
1699		}
1700	} while (ccl <= vcn);
1701	*cn = ccn + vcn;
1702	return (0);
1703}
1704