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