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