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