ntfs_subr.c revision 66615
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 66615 2000-10-04 01:29:17Z jasone $
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	mtx_enter(&ip->i_interlock, MTX_DEF);
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	mtx_init(&ip->i_interlock, "ntnode interlock", MTX_DEF);
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	mtx_enter(&ip->i_interlock, MTX_DEF);
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		mtx_exit(&ip->i_interlock, MTX_DEF);
468		mtx_destroy(&ip->i_interlock);
469		lockdestroy(&ip->i_lock);
470
471		FREE(ip, M_NTFSNTNODE);
472	} else {
473		LOCKMGR(&ip->i_lock, LK_RELEASE|LK_INTERLOCK, &ip->i_interlock);
474	}
475}
476
477/*
478 * increment usecount of ntnode
479 */
480void
481ntfs_ntref(ip)
482	struct ntnode *ip;
483{
484	mtx_enter(&ip->i_interlock, MTX_DEF);
485	ip->i_usecount++;
486	mtx_exit(&ip->i_interlock, MTX_DEF);
487
488	dprintf(("ntfs_ntref: ino %d, usecount: %d\n",
489		ip->i_number, ip->i_usecount));
490
491}
492
493/*
494 * Decrement usecount of ntnode.
495 */
496void
497ntfs_ntrele(ip)
498	struct ntnode *ip;
499{
500	dprintf(("ntfs_ntrele: rele ntnode %d: %p, usecount: %d\n",
501		ip->i_number, ip, ip->i_usecount));
502
503	mtx_enter(&ip->i_interlock, MTX_DEF);
504	ip->i_usecount--;
505
506	if (ip->i_usecount < 0)
507		panic("ntfs_ntrele: ino: %d usecount: %d \n",
508		      ip->i_number,ip->i_usecount);
509	mtx_exit(&ip->i_interlock, MTX_DEF);
510}
511
512/*
513 * Deallocate all memory allocated for ntvattr
514 */
515void
516ntfs_freentvattr(vap)
517	struct ntvattr * vap;
518{
519	if (vap->va_flag & NTFS_AF_INRUN) {
520		if (vap->va_vruncn)
521			FREE(vap->va_vruncn, M_NTFSRUN);
522		if (vap->va_vruncl)
523			FREE(vap->va_vruncl, M_NTFSRUN);
524	} else {
525		if (vap->va_datap)
526			FREE(vap->va_datap, M_NTFSRDATA);
527	}
528	FREE(vap, M_NTFSNTVATTR);
529}
530
531/*
532 * Convert disk image of attribute into ntvattr structure,
533 * runs are expanded also.
534 */
535int
536ntfs_attrtontvattr(
537		   struct ntfsmount * ntmp,
538		   struct ntvattr ** rvapp,
539		   struct attr * rap)
540{
541	int             error, i;
542	struct ntvattr *vap;
543
544	error = 0;
545	*rvapp = NULL;
546
547	MALLOC(vap, struct ntvattr *, sizeof(struct ntvattr),
548		M_NTFSNTVATTR, M_WAITOK);
549	bzero(vap, sizeof(struct ntvattr));
550	vap->va_ip = NULL;
551	vap->va_flag = rap->a_hdr.a_flag;
552	vap->va_type = rap->a_hdr.a_type;
553	vap->va_compression = rap->a_hdr.a_compression;
554	vap->va_index = rap->a_hdr.a_index;
555
556	ddprintf(("type: 0x%x, index: %d", vap->va_type, vap->va_index));
557
558	vap->va_namelen = rap->a_hdr.a_namelen;
559	if (rap->a_hdr.a_namelen) {
560		wchar *unp = (wchar *) ((caddr_t) rap + rap->a_hdr.a_nameoff);
561		ddprintf((", name:["));
562		for (i = 0; i < vap->va_namelen; i++) {
563			vap->va_name[i] = unp[i];
564			ddprintf(("%c", vap->va_name[i]));
565		}
566		ddprintf(("]"));
567	}
568	if (vap->va_flag & NTFS_AF_INRUN) {
569		ddprintf((", nonres."));
570		vap->va_datalen = rap->a_nr.a_datalen;
571		vap->va_allocated = rap->a_nr.a_allocated;
572		vap->va_vcnstart = rap->a_nr.a_vcnstart;
573		vap->va_vcnend = rap->a_nr.a_vcnend;
574		vap->va_compressalg = rap->a_nr.a_compressalg;
575		error = ntfs_runtovrun(&(vap->va_vruncn), &(vap->va_vruncl),
576				       &(vap->va_vruncnt),
577				       (caddr_t) rap + rap->a_nr.a_dataoff);
578	} else {
579		vap->va_compressalg = 0;
580		ddprintf((", res."));
581		vap->va_datalen = rap->a_r.a_datalen;
582		vap->va_allocated = rap->a_r.a_datalen;
583		vap->va_vcnstart = 0;
584		vap->va_vcnend = ntfs_btocn(vap->va_allocated);
585		MALLOC(vap->va_datap, caddr_t, vap->va_datalen,
586		       M_NTFSRDATA, M_WAITOK);
587		memcpy(vap->va_datap, (caddr_t) rap + rap->a_r.a_dataoff,
588		       rap->a_r.a_datalen);
589	}
590	ddprintf((", len: %d", vap->va_datalen));
591
592	if (error)
593		FREE(vap, M_NTFSNTVATTR);
594	else
595		*rvapp = vap;
596
597	ddprintf(("\n"));
598
599	return (error);
600}
601
602/*
603 * Expand run into more utilizable and more memory eating format.
604 */
605int
606ntfs_runtovrun(
607	       cn_t ** rcnp,
608	       cn_t ** rclp,
609	       u_long * rcntp,
610	       u_int8_t * run)
611{
612	u_int32_t       off;
613	u_int32_t       sz, i;
614	cn_t           *cn;
615	cn_t           *cl;
616	u_long		cnt;
617	cn_t		prev;
618	cn_t		tmp;
619
620	off = 0;
621	cnt = 0;
622	i = 0;
623	while (run[off]) {
624		off += (run[off] & 0xF) + ((run[off] >> 4) & 0xF) + 1;
625		cnt++;
626	}
627	MALLOC(cn, cn_t *, cnt * sizeof(cn_t), M_NTFSRUN, M_WAITOK);
628	MALLOC(cl, cn_t *, cnt * sizeof(cn_t), M_NTFSRUN, M_WAITOK);
629
630	off = 0;
631	cnt = 0;
632	prev = 0;
633	while (run[off]) {
634
635		sz = run[off++];
636		cl[cnt] = 0;
637
638		for (i = 0; i < (sz & 0xF); i++)
639			cl[cnt] += (u_int32_t) run[off++] << (i << 3);
640
641		sz >>= 4;
642		if (run[off + sz - 1] & 0x80) {
643			tmp = ((u_int64_t) - 1) << (sz << 3);
644			for (i = 0; i < sz; i++)
645				tmp |= (u_int64_t) run[off++] << (i << 3);
646		} else {
647			tmp = 0;
648			for (i = 0; i < sz; i++)
649				tmp |= (u_int64_t) run[off++] << (i << 3);
650		}
651		if (tmp)
652			prev = cn[cnt] = prev + tmp;
653		else
654			cn[cnt] = tmp;
655
656		cnt++;
657	}
658	*rcnp = cn;
659	*rclp = cl;
660	*rcntp = cnt;
661	return (0);
662}
663
664/*
665 * Compare unicode and ascii string case insens.
666 */
667static int
668ntfs_uastricmp(ustr, ustrlen, astr, astrlen)
669	const wchar *ustr;
670	size_t ustrlen;
671	const char *astr;
672	size_t astrlen;
673{
674	size_t             i;
675	int             res;
676
677	for (i = 0; i < ustrlen && i < astrlen; i++) {
678		res = ((int) NTFS_TOUPPER(NTFS_U28(ustr[i]))) -
679			((int)NTFS_TOUPPER(astr[i]));
680		if (res)
681			return res;
682	}
683	return (ustrlen - astrlen);
684}
685
686/*
687 * Compare unicode and ascii string case sens.
688 */
689static int
690ntfs_uastrcmp(ustr, ustrlen, astr, astrlen)
691	const wchar *ustr;
692	size_t ustrlen;
693	const char *astr;
694	size_t astrlen;
695{
696	size_t             i;
697	int             res;
698
699	for (i = 0; (i < ustrlen) && (i < astrlen); i++) {
700		res = (int) (((char)NTFS_U28(ustr[i])) - astr[i]);
701		if (res)
702			return res;
703	}
704	return (ustrlen - astrlen);
705}
706
707/*
708 * Search fnode in ntnode, if not found allocate and preinitialize.
709 *
710 * ntnode should be locked on entry.
711 */
712int
713ntfs_fget(
714	struct ntfsmount *ntmp,
715	struct ntnode *ip,
716	int attrtype,
717	char *attrname,
718	struct fnode **fpp)
719{
720	struct fnode *fp;
721
722	dprintf(("ntfs_fget: ino: %d, attrtype: 0x%x, attrname: %s\n",
723		ip->i_number,attrtype, attrname?attrname:""));
724	*fpp = NULL;
725	for (fp = ip->i_fnlist.lh_first; fp != NULL; fp = fp->f_fnlist.le_next){
726		dprintf(("ntfs_fget: fnode: attrtype: %d, attrname: %s\n",
727			fp->f_attrtype, fp->f_attrname?fp->f_attrname:""));
728
729		if ((attrtype == fp->f_attrtype) &&
730		    ((!attrname && !fp->f_attrname) ||
731		     (attrname && fp->f_attrname &&
732		      !strcmp(attrname,fp->f_attrname)))){
733			dprintf(("ntfs_fget: found existed: %p\n",fp));
734			*fpp = fp;
735		}
736	}
737
738	if (*fpp)
739		return (0);
740
741	MALLOC(fp, struct fnode *, sizeof(struct fnode), M_NTFSFNODE, M_WAITOK);
742	bzero(fp, sizeof(struct fnode));
743	dprintf(("ntfs_fget: allocating fnode: %p\n",fp));
744
745	fp->f_ip = ip;
746	fp->f_attrname = attrname;
747	if (fp->f_attrname) fp->f_flag |= FN_AATTRNAME;
748	fp->f_attrtype = attrtype;
749
750	ntfs_ntref(ip);
751
752	LIST_INSERT_HEAD(&ip->i_fnlist, fp, f_fnlist);
753
754	*fpp = fp;
755
756	return (0);
757}
758
759/*
760 * Deallocate fnode, remove it from ntnode's fnode list.
761 *
762 * ntnode should be locked.
763 */
764void
765ntfs_frele(
766	struct fnode *fp)
767{
768	struct ntnode *ip = FTONT(fp);
769
770	dprintf(("ntfs_frele: fnode: %p for %d: %p\n", fp, ip->i_number, ip));
771
772	dprintf(("ntfs_frele: deallocating fnode\n"));
773	LIST_REMOVE(fp,f_fnlist);
774	if (fp->f_flag & FN_AATTRNAME)
775		FREE(fp->f_attrname, M_TEMP);
776	if (fp->f_dirblbuf)
777		FREE(fp->f_dirblbuf, M_NTFSDIR);
778#ifdef __FreeBSD__
779	lockdestroy(&fp->f_lock);
780#endif
781	FREE(fp, M_NTFSFNODE);
782	ntfs_ntrele(ip);
783}
784
785/*
786 * Lookup attribute name in format: [[:$ATTR_TYPE]:$ATTR_NAME],
787 * $ATTR_TYPE is searched in attrdefs read from $AttrDefs.
788 * If $ATTR_TYPE nott specifed, ATTR_A_DATA assumed.
789 */
790static int
791ntfs_ntlookupattr(
792		struct ntfsmount * ntmp,
793		const char * name,
794		int namelen,
795		int *attrtype,
796		char **attrname)
797{
798	const char *sys;
799	size_t syslen, i;
800	struct ntvattrdef *adp;
801
802	if (namelen == 0)
803		return (0);
804
805	if (name[0] == '$') {
806		sys = name;
807		for (syslen = 0; syslen < namelen; syslen++) {
808			if(sys[syslen] == ':') {
809				name++;
810				namelen--;
811				break;
812			}
813		}
814		name += syslen;
815		namelen -= syslen;
816
817		adp = ntmp->ntm_ad;
818		for (i = 0; i < ntmp->ntm_adnum; i++, adp++){
819			if (syslen != adp->ad_namelen ||
820			   strncmp(sys, adp->ad_name, syslen) != 0)
821				continue;
822
823			*attrtype = adp->ad_type;
824			goto out;
825		}
826		return (ENOENT);
827	}
828
829    out:
830	if (namelen) {
831		MALLOC((*attrname), char *, namelen, M_TEMP, M_WAITOK);
832		memcpy((*attrname), name, namelen);
833		(*attrname)[namelen] = '\0';
834		*attrtype = NTFS_A_DATA;
835	}
836
837	return (0);
838}
839
840/*
841 * Lookup specifed node for filename, matching cnp,
842 * return fnode filled.
843 */
844int
845ntfs_ntlookupfile(
846	      struct ntfsmount * ntmp,
847	      struct vnode * vp,
848	      struct componentname * cnp,
849	      struct vnode ** vpp)
850{
851	struct fnode   *fp = VTOF(vp);
852	struct ntnode  *ip = FTONT(fp);
853	struct ntvattr *vap;	/* Root attribute */
854	cn_t            cn;	/* VCN in current attribute */
855	caddr_t         rdbuf;	/* Buffer to read directory's blocks  */
856	u_int32_t       blsize;
857	u_int32_t       rdsize;	/* Length of data to read from current block */
858	struct attr_indexentry *iep;
859	int             error, res, anamelen, fnamelen;
860	const char     *fname,*aname;
861	u_int32_t       aoff;
862	int attrtype = NTFS_A_DATA;
863	char *attrname = NULL;
864	struct fnode   *nfp;
865	struct vnode   *nvp;
866	enum vtype	f_type;
867
868	error = ntfs_ntget(ip);
869	if (error)
870		return (error);
871
872	error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXROOT, "$I30", 0, &vap);
873	if (error || (vap->va_flag & NTFS_AF_INRUN))
874		return (ENOTDIR);
875
876	blsize = vap->va_a_iroot->ir_size;
877	rdsize = vap->va_datalen;
878
879	/*
880	 * Divide file name into: foofilefoofilefoofile[:attrspec]
881	 * Store like this:       fname:fnamelen       [aname:anamelen]
882	 */
883	fname = cnp->cn_nameptr;
884	aname = NULL;
885	anamelen = 0;
886	for (fnamelen = 0; fnamelen < cnp->cn_namelen; fnamelen++)
887		if(fname[fnamelen] == ':') {
888			aname = fname + fnamelen + 1;
889			anamelen = cnp->cn_namelen - fnamelen - 1;
890			dprintf(("ntfs_ntlookupfile: %s (%d), attr: %s (%d)\n",
891				fname, fnamelen, aname, anamelen));
892			break;
893		}
894
895	dprintf(("ntfs_ntlookupfile: blksz: %d, rdsz: %d\n", blsize, rdsize));
896
897	MALLOC(rdbuf, caddr_t, blsize, M_TEMP, M_WAITOK);
898
899	error = ntfs_readattr(ntmp, ip, NTFS_A_INDXROOT, "$I30",
900			       0, rdsize, rdbuf, NULL);
901	if (error)
902		goto fail;
903
904	aoff = sizeof(struct attr_indexroot);
905
906	do {
907		iep = (struct attr_indexentry *) (rdbuf + aoff);
908
909		for (; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (rdsize > aoff);
910			aoff += iep->reclen,
911			iep = (struct attr_indexentry *) (rdbuf + aoff))
912		{
913			ddprintf(("scan: %d, %d\n",
914				  (u_int32_t) iep->ie_number,
915				  (u_int32_t) iep->ie_fnametype));
916
917			/* check the name - the case-insensitible check
918			 * has to come first, to break from this for loop
919			 * if needed, so we can dive correctly */
920			res = ntfs_uastricmp(iep->ie_fname, iep->ie_fnamelen,
921				fname, fnamelen);
922			if (res > 0) break;
923			if (res < 0) continue;
924
925			if (iep->ie_fnametype == 0 ||
926			    !(ntmp->ntm_flag & NTFS_MFLAG_CASEINS))
927			{
928				res = ntfs_uastrcmp(iep->ie_fname,
929					iep->ie_fnamelen, fname, fnamelen);
930				if (res != 0) continue;
931			}
932
933			if (aname) {
934				error = ntfs_ntlookupattr(ntmp,
935					aname, anamelen,
936					&attrtype, &attrname);
937				if (error)
938					goto fail;
939			}
940
941			/* Check if we've found ourself */
942			if ((iep->ie_number == ip->i_number) &&
943			    (attrtype == fp->f_attrtype) &&
944			    ((!attrname && !fp->f_attrname) ||
945			     (attrname && fp->f_attrname &&
946			      !strcmp(attrname, fp->f_attrname))))
947			{
948				VREF(vp);
949				*vpp = vp;
950				error = 0;
951				goto fail;
952			}
953
954			/* free the buffer returned by ntfs_ntlookupattr() */
955			if (attrname) {
956				FREE(attrname, M_TEMP);
957				attrname = NULL;
958			}
959
960			/* vget node, but don't load it */
961			error = ntfs_vgetex(ntmp->ntm_mountp,
962				   iep->ie_number, attrtype, attrname,
963				   LK_EXCLUSIVE, VG_DONTLOADIN | VG_DONTVALIDFN,
964				   curproc, &nvp);
965			if (error)
966				goto fail;
967
968			nfp = VTOF(nvp);
969
970			if (nfp->f_flag & FN_VALID) {
971				*vpp = nvp;
972				goto fail;
973			}
974
975			nfp->f_fflag = iep->ie_fflag;
976			nfp->f_pnumber = iep->ie_fpnumber;
977			nfp->f_times = iep->ie_ftimes;
978
979			if((nfp->f_fflag & NTFS_FFLAG_DIR) &&
980			   (nfp->f_attrtype == NTFS_A_DATA) &&
981			   (nfp->f_attrname == NULL))
982				f_type = VDIR;
983			else
984				f_type = VREG;
985
986			nvp->v_type = f_type;
987
988			if ((nfp->f_attrtype == NTFS_A_DATA) &&
989			    (nfp->f_attrname == NULL))
990			{
991				/* Opening default attribute */
992				nfp->f_size = iep->ie_fsize;
993				nfp->f_allocated = iep->ie_fallocated;
994				nfp->f_flag |= FN_PRELOADED;
995			} else {
996				error = ntfs_filesize(ntmp, nfp,
997					    &nfp->f_size, &nfp->f_allocated);
998				if (error) {
999					vput(nvp);
1000					goto fail;
1001				}
1002			}
1003
1004			nfp->f_flag &= ~FN_VALID;
1005			*vpp = nvp;
1006			goto fail;
1007		}
1008
1009		/* Dive if possible */
1010		if (iep->ie_flag & NTFS_IEFLAG_SUBNODE) {
1011			dprintf(("ntfs_ntlookupfile: diving\n"));
1012
1013			cn = *(cn_t *) (rdbuf + aoff +
1014					iep->reclen - sizeof(cn_t));
1015			rdsize = blsize;
1016
1017			error = ntfs_readattr(ntmp, ip, NTFS_A_INDX, "$I30",
1018					ntfs_cntob(cn), rdsize, rdbuf, NULL);
1019			if (error)
1020				goto fail;
1021
1022			error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC,
1023						rdbuf, rdsize);
1024			if (error)
1025				goto fail;
1026
1027			aoff = (((struct attr_indexalloc *) rdbuf)->ia_hdrsize +
1028				0x18);
1029		} else {
1030			dprintf(("ntfs_ntlookupfile: nowhere to dive :-(\n"));
1031			error = ENOENT;
1032			break;
1033		}
1034	} while (1);
1035
1036	dprintf(("finish\n"));
1037
1038fail:
1039	if (attrname) FREE(attrname, M_TEMP);
1040	ntfs_ntvattrrele(vap);
1041	ntfs_ntput(ip);
1042	FREE(rdbuf, M_TEMP);
1043	return (error);
1044}
1045
1046/*
1047 * Check if name type is permitted to show.
1048 */
1049int
1050ntfs_isnamepermitted(
1051		     struct ntfsmount * ntmp,
1052		     struct attr_indexentry * iep)
1053{
1054	if (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES)
1055		return 1;
1056
1057	switch (iep->ie_fnametype) {
1058	case 2:
1059		ddprintf(("ntfs_isnamepermitted: skiped DOS name\n"));
1060		return 0;
1061	case 0: case 1: case 3:
1062		return 1;
1063	default:
1064		printf("ntfs_isnamepermitted: " \
1065		       "WARNING! Unknown file name type: %d\n",
1066		       iep->ie_fnametype);
1067		break;
1068	}
1069	return 0;
1070}
1071
1072/*
1073 * Read ntfs dir like stream of attr_indexentry, not like btree of them.
1074 * This is done by scaning $BITMAP:$I30 for busy clusters and reading them.
1075 * Ofcouse $INDEX_ROOT:$I30 is read before. Last read values are stored in
1076 * fnode, so we can skip toward record number num almost immediatly.
1077 * Anyway this is rather slow routine. The problem is that we don't know
1078 * how many records are there in $INDEX_ALLOCATION:$I30 block.
1079 */
1080int
1081ntfs_ntreaddir(
1082	       struct ntfsmount * ntmp,
1083	       struct fnode * fp,
1084	       u_int32_t num,
1085	       struct attr_indexentry ** riepp)
1086{
1087	struct ntnode  *ip = FTONT(fp);
1088	struct ntvattr *vap = NULL;	/* IndexRoot attribute */
1089	struct ntvattr *bmvap = NULL;	/* BitMap attribute */
1090	struct ntvattr *iavap = NULL;	/* IndexAllocation attribute */
1091	caddr_t         rdbuf;		/* Buffer to read directory's blocks  */
1092	u_char         *bmp = NULL;	/* Bitmap */
1093	u_int32_t       blsize;		/* Index allocation size (2048) */
1094	u_int32_t       rdsize;		/* Length of data to read */
1095	u_int32_t       attrnum;	/* Current attribute type */
1096	u_int32_t       cpbl = 1;	/* Clusters per directory block */
1097	u_int32_t       blnum;
1098	struct attr_indexentry *iep;
1099	int             error = ENOENT;
1100	u_int32_t       aoff, cnum;
1101
1102	dprintf(("ntfs_ntreaddir: read ino: %d, num: %d\n", ip->i_number, num));
1103	error = ntfs_ntget(ip);
1104	if (error)
1105		return (error);
1106
1107	error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXROOT, "$I30", 0, &vap);
1108	if (error)
1109		return (ENOTDIR);
1110
1111	if (fp->f_dirblbuf == NULL) {
1112		fp->f_dirblsz = vap->va_a_iroot->ir_size;
1113		MALLOC(fp->f_dirblbuf, caddr_t,
1114		       max(vap->va_datalen,fp->f_dirblsz), M_NTFSDIR, M_WAITOK);
1115	}
1116
1117	blsize = fp->f_dirblsz;
1118	rdbuf = fp->f_dirblbuf;
1119
1120	dprintf(("ntfs_ntreaddir: rdbuf: 0x%p, blsize: %d\n", rdbuf, blsize));
1121
1122	if (vap->va_a_iroot->ir_flag & NTFS_IRFLAG_INDXALLOC) {
1123		error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXBITMAP, "$I30",
1124					0, &bmvap);
1125		if (error) {
1126			error = ENOTDIR;
1127			goto fail;
1128		}
1129		MALLOC(bmp, u_char *, bmvap->va_datalen, M_TEMP, M_WAITOK);
1130		error = ntfs_readattr(ntmp, ip, NTFS_A_INDXBITMAP, "$I30", 0,
1131				       bmvap->va_datalen, bmp, NULL);
1132		if (error)
1133			goto fail;
1134
1135		error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDX, "$I30",
1136					0, &iavap);
1137		if (error) {
1138			error = ENOTDIR;
1139			goto fail;
1140		}
1141		cpbl = ntfs_btocn(blsize + ntfs_cntob(1) - 1);
1142		dprintf(("ntfs_ntreaddir: indexalloc: %d, cpbl: %d\n",
1143			 iavap->va_datalen, cpbl));
1144	} else {
1145		dprintf(("ntfs_ntreadidir: w/o BitMap and IndexAllocation\n"));
1146		iavap = bmvap = NULL;
1147		bmp = NULL;
1148	}
1149
1150	/* Try use previous values */
1151	if ((fp->f_lastdnum < num) && (fp->f_lastdnum != 0)) {
1152		attrnum = fp->f_lastdattr;
1153		aoff = fp->f_lastdoff;
1154		blnum = fp->f_lastdblnum;
1155		cnum = fp->f_lastdnum;
1156	} else {
1157		attrnum = NTFS_A_INDXROOT;
1158		aoff = sizeof(struct attr_indexroot);
1159		blnum = 0;
1160		cnum = 0;
1161	}
1162
1163	do {
1164		dprintf(("ntfs_ntreaddir: scan: 0x%x, %d, %d, %d, %d\n",
1165			 attrnum, (u_int32_t) blnum, cnum, num, aoff));
1166		rdsize = (attrnum == NTFS_A_INDXROOT) ? vap->va_datalen : blsize;
1167		error = ntfs_readattr(ntmp, ip, attrnum, "$I30",
1168				ntfs_cntob(blnum * cpbl), rdsize, rdbuf, NULL);
1169		if (error)
1170			goto fail;
1171
1172		if (attrnum == NTFS_A_INDX) {
1173			error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC,
1174						rdbuf, rdsize);
1175			if (error)
1176				goto fail;
1177		}
1178		if (aoff == 0)
1179			aoff = (attrnum == NTFS_A_INDX) ?
1180				(0x18 + ((struct attr_indexalloc *) rdbuf)->ia_hdrsize) :
1181				sizeof(struct attr_indexroot);
1182
1183		iep = (struct attr_indexentry *) (rdbuf + aoff);
1184		for (; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (rdsize > aoff);
1185			aoff += iep->reclen,
1186			iep = (struct attr_indexentry *) (rdbuf + aoff))
1187		{
1188			if (!ntfs_isnamepermitted(ntmp, iep)) continue;
1189
1190			if (cnum >= num) {
1191				fp->f_lastdnum = cnum;
1192				fp->f_lastdoff = aoff;
1193				fp->f_lastdblnum = blnum;
1194				fp->f_lastdattr = attrnum;
1195
1196				*riepp = iep;
1197
1198				error = 0;
1199				goto fail;
1200			}
1201			cnum++;
1202		}
1203
1204		if (iavap) {
1205			if (attrnum == NTFS_A_INDXROOT)
1206				blnum = 0;
1207			else
1208				blnum++;
1209
1210			while (ntfs_cntob(blnum * cpbl) < iavap->va_datalen) {
1211				if (bmp[blnum >> 3] & (1 << (blnum & 3)))
1212					break;
1213				blnum++;
1214			}
1215
1216			attrnum = NTFS_A_INDX;
1217			aoff = 0;
1218			if (ntfs_cntob(blnum * cpbl) >= iavap->va_datalen)
1219				break;
1220			dprintf(("ntfs_ntreaddir: blnum: %d\n", (u_int32_t) blnum));
1221		}
1222	} while (iavap);
1223
1224	*riepp = NULL;
1225	fp->f_lastdnum = 0;
1226
1227fail:
1228	if (vap)
1229		ntfs_ntvattrrele(vap);
1230	if (bmvap)
1231		ntfs_ntvattrrele(bmvap);
1232	if (iavap)
1233		ntfs_ntvattrrele(iavap);
1234	if (bmp)
1235		FREE(bmp, M_TEMP);
1236	ntfs_ntput(ip);
1237	return (error);
1238}
1239
1240/*
1241 * Convert NTFS times that are in 100 ns units and begins from
1242 * 1601 Jan 1 into unix times.
1243 */
1244struct timespec
1245ntfs_nttimetounix(
1246		  u_int64_t nt)
1247{
1248	struct timespec t;
1249
1250	/* WindowNT times are in 100 ns and from 1601 Jan 1 */
1251	t.tv_nsec = (nt % (1000 * 1000 * 10)) * 100;
1252	t.tv_sec = nt / (1000 * 1000 * 10) -
1253		369LL * 365LL * 24LL * 60LL * 60LL -
1254		89LL * 1LL * 24LL * 60LL * 60LL;
1255	return (t);
1256}
1257
1258/*
1259 * Get file times from NTFS_A_NAME attribute.
1260 */
1261int
1262ntfs_times(
1263	   struct ntfsmount * ntmp,
1264	   struct ntnode * ip,
1265	   ntfs_times_t * tm)
1266{
1267	struct ntvattr *vap;
1268	int             error;
1269
1270	dprintf(("ntfs_times: ino: %d...\n", ip->i_number));
1271
1272	error = ntfs_ntget(ip);
1273	if (error)
1274		return (error);
1275
1276	error = ntfs_ntvattrget(ntmp, ip, NTFS_A_NAME, NULL, 0, &vap);
1277	if (error) {
1278		ntfs_ntput(ip);
1279		return (error);
1280	}
1281	*tm = vap->va_a_name->n_times;
1282	ntfs_ntvattrrele(vap);
1283	ntfs_ntput(ip);
1284
1285	return (0);
1286}
1287
1288/*
1289 * Get file sizes from corresponding attribute.
1290 *
1291 * ntnode under fnode should be locked.
1292 */
1293int
1294ntfs_filesize(
1295	      struct ntfsmount * ntmp,
1296	      struct fnode * fp,
1297	      u_int64_t * size,
1298	      u_int64_t * bytes)
1299{
1300	struct ntvattr *vap;
1301	struct ntnode *ip = FTONT(fp);
1302	u_int64_t       sz, bn;
1303	int             error;
1304
1305	dprintf(("ntfs_filesize: ino: %d\n", ip->i_number));
1306
1307	error = ntfs_ntvattrget(ntmp, ip,
1308		fp->f_attrtype, fp->f_attrname, 0, &vap);
1309	if (error)
1310		return (error);
1311
1312	bn = vap->va_allocated;
1313	sz = vap->va_datalen;
1314
1315	dprintf(("ntfs_filesize: %d bytes (%d bytes allocated)\n",
1316		(u_int32_t) sz, (u_int32_t) bn));
1317
1318	if (size)
1319		*size = sz;
1320	if (bytes)
1321		*bytes = bn;
1322
1323	ntfs_ntvattrrele(vap);
1324
1325	return (0);
1326}
1327
1328/*
1329 * This is one of write routine.
1330 */
1331int
1332ntfs_writeattr_plain(
1333	struct ntfsmount * ntmp,
1334	struct ntnode * ip,
1335	u_int32_t attrnum,
1336	char *attrname,
1337	off_t roff,
1338	size_t rsize,
1339	void *rdata,
1340	size_t * initp,
1341	struct uio *uio)
1342{
1343	size_t          init;
1344	int             error = 0;
1345	off_t           off = roff, left = rsize, towrite;
1346	caddr_t         data = rdata;
1347	struct ntvattr *vap;
1348	*initp = 0;
1349
1350	while (left) {
1351		error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname,
1352					ntfs_btocn(off), &vap);
1353		if (error)
1354			return (error);
1355		towrite = min(left, ntfs_cntob(vap->va_vcnend + 1) - off);
1356		ddprintf(("ntfs_writeattr_plain: o: %d, s: %d (%d - %d)\n",
1357			 (u_int32_t) off, (u_int32_t) towrite,
1358			 (u_int32_t) vap->va_vcnstart,
1359			 (u_int32_t) vap->va_vcnend));
1360		error = ntfs_writentvattr_plain(ntmp, ip, vap,
1361					 off - ntfs_cntob(vap->va_vcnstart),
1362					 towrite, data, &init, uio);
1363		if (error) {
1364			printf("ntfs_writeattr_plain: " \
1365			       "ntfs_writentvattr_plain failed: o: %d, s: %d\n",
1366			       (u_int32_t) off, (u_int32_t) towrite);
1367			printf("ntfs_writeattr_plain: attrib: %d - %d\n",
1368			       (u_int32_t) vap->va_vcnstart,
1369			       (u_int32_t) vap->va_vcnend);
1370			ntfs_ntvattrrele(vap);
1371			break;
1372		}
1373		ntfs_ntvattrrele(vap);
1374		left -= towrite;
1375		off += towrite;
1376		data = data + towrite;
1377		*initp += init;
1378	}
1379
1380	return (error);
1381}
1382
1383/*
1384 * This is one of write routine.
1385 *
1386 * ntnode should be locked.
1387 */
1388int
1389ntfs_writentvattr_plain(
1390	struct ntfsmount * ntmp,
1391	struct ntnode * ip,
1392	struct ntvattr * vap,
1393	off_t roff,
1394	size_t rsize,
1395	void *rdata,
1396	size_t * initp,
1397	struct uio *uio)
1398{
1399	int             error = 0;
1400	int             off;
1401	int             cnt;
1402	cn_t            ccn, ccl, cn, left, cl;
1403	caddr_t         data = rdata;
1404	struct buf     *bp;
1405	size_t          tocopy;
1406
1407	*initp = 0;
1408
1409	if ((vap->va_flag & NTFS_AF_INRUN) == 0) {
1410		printf("ntfs_writevattr_plain: CAN'T WRITE RES. ATTRIBUTE\n");
1411		return ENOTTY;
1412	}
1413
1414	ddprintf(("ntfs_writentvattr_plain: data in run: %d chains\n",
1415		 vap->va_vruncnt));
1416
1417	off = roff;
1418	left = rsize;
1419	ccl = 0;
1420	ccn = 0;
1421	cnt = 0;
1422	for (; left && (cnt < vap->va_vruncnt); cnt++) {
1423		ccn = vap->va_vruncn[cnt];
1424		ccl = vap->va_vruncl[cnt];
1425
1426		ddprintf(("ntfs_writentvattr_plain: " \
1427			 "left %d, cn: 0x%x, cl: %d, off: %d\n", \
1428			 (u_int32_t) left, (u_int32_t) ccn, \
1429			 (u_int32_t) ccl, (u_int32_t) off));
1430
1431		if (ntfs_cntob(ccl) < off) {
1432			off -= ntfs_cntob(ccl);
1433			cnt++;
1434			continue;
1435		}
1436		if (!ccn && ip->i_number != NTFS_BOOTINO)
1437			continue; /* XXX */
1438
1439		ccl -= ntfs_btocn(off);
1440		cn = ccn + ntfs_btocn(off);
1441		off = ntfs_btocnoff(off);
1442
1443		while (left && ccl) {
1444#if defined(__FreeBSD__)
1445			tocopy = min(left,
1446				  min(ntfs_cntob(ccl) - off, MAXBSIZE - off));
1447#else
1448			/* under NetBSD, bread() can read
1449			 * maximum one block worth of data */
1450			tocopy = min(left, ntmp->ntm_bps - off);
1451#endif
1452			cl = ntfs_btocl(tocopy + off);
1453			ddprintf(("ntfs_writentvattr_plain: write: " \
1454				"cn: 0x%x cl: %d, off: %d len: %d, left: %d\n",
1455				(u_int32_t) cn, (u_int32_t) cl,
1456				(u_int32_t) off, (u_int32_t) tocopy,
1457				(u_int32_t) left));
1458			if ((off == 0) && (tocopy == ntfs_cntob(cl)))
1459			{
1460				bp = getblk(ntmp->ntm_devvp, ntfs_cntobn(cn),
1461					    ntfs_cntob(cl), 0, 0);
1462				clrbuf(bp);
1463			} else {
1464				error = bread(ntmp->ntm_devvp, ntfs_cntobn(cn),
1465					      ntfs_cntob(cl), NOCRED, &bp);
1466				if (error) {
1467					brelse(bp);
1468					return (error);
1469				}
1470			}
1471			if (uio)
1472				uiomove(bp->b_data + off, tocopy, uio);
1473			else
1474				memcpy(bp->b_data + off, data, tocopy);
1475			bawrite(bp);
1476			data = data + tocopy;
1477			*initp += tocopy;
1478			off = 0;
1479			left -= tocopy;
1480			cn += cl;
1481			ccl -= cl;
1482		}
1483	}
1484
1485	if (left) {
1486		printf("ntfs_writentvattr_plain: POSSIBLE RUN ERROR\n");
1487		error = EINVAL;
1488	}
1489
1490	return (error);
1491}
1492
1493/*
1494 * This is one of read routines.
1495 *
1496 * ntnode should be locked.
1497 */
1498int
1499ntfs_readntvattr_plain(
1500	struct ntfsmount * ntmp,
1501	struct ntnode * ip,
1502	struct ntvattr * vap,
1503	off_t roff,
1504	size_t rsize,
1505	void *rdata,
1506	size_t * initp,
1507	struct uio *uio)
1508{
1509	int             error = 0;
1510	int             off;
1511
1512	*initp = 0;
1513	if (vap->va_flag & NTFS_AF_INRUN) {
1514		int             cnt;
1515		cn_t            ccn, ccl, cn, left, cl;
1516		caddr_t         data = rdata;
1517		struct buf     *bp;
1518		size_t          tocopy;
1519
1520		ddprintf(("ntfs_readntvattr_plain: data in run: %d chains\n",
1521			 vap->va_vruncnt));
1522
1523		off = roff;
1524		left = rsize;
1525		ccl = 0;
1526		ccn = 0;
1527		cnt = 0;
1528		while (left && (cnt < vap->va_vruncnt)) {
1529			ccn = vap->va_vruncn[cnt];
1530			ccl = vap->va_vruncl[cnt];
1531
1532			ddprintf(("ntfs_readntvattr_plain: " \
1533				 "left %d, cn: 0x%x, cl: %d, off: %d\n", \
1534				 (u_int32_t) left, (u_int32_t) ccn, \
1535				 (u_int32_t) ccl, (u_int32_t) off));
1536
1537			if (ntfs_cntob(ccl) < off) {
1538				off -= ntfs_cntob(ccl);
1539				cnt++;
1540				continue;
1541			}
1542			if (ccn || ip->i_number == NTFS_BOOTINO) {
1543				ccl -= ntfs_btocn(off);
1544				cn = ccn + ntfs_btocn(off);
1545				off = ntfs_btocnoff(off);
1546
1547				while (left && ccl) {
1548#if defined(__FreeBSD__)
1549					tocopy = min(left,
1550						  min(ntfs_cntob(ccl) - off,
1551						      MAXBSIZE - off));
1552#else
1553					/* under NetBSD, bread() can read
1554					 * maximum one block worth of data */
1555					tocopy = min(left,
1556						ntmp->ntm_bps - off);
1557#endif
1558					cl = ntfs_btocl(tocopy + off);
1559					ddprintf(("ntfs_readntvattr_plain: " \
1560						"read: cn: 0x%x cl: %d, " \
1561						"off: %d len: %d, left: %d\n",
1562						(u_int32_t) cn,
1563						(u_int32_t) cl,
1564						(u_int32_t) off,
1565						(u_int32_t) tocopy,
1566						(u_int32_t) left));
1567					error = bread(ntmp->ntm_devvp,
1568						      ntfs_cntobn(cn),
1569						      ntfs_cntob(cl),
1570						      NOCRED, &bp);
1571					if (error) {
1572						brelse(bp);
1573						return (error);
1574					}
1575					if (uio) {
1576						uiomove(bp->b_data + off,
1577							tocopy, uio);
1578					} else {
1579						memcpy(data, bp->b_data + off,
1580							tocopy);
1581					}
1582					brelse(bp);
1583					data = data + tocopy;
1584					*initp += tocopy;
1585					off = 0;
1586					left -= tocopy;
1587					cn += cl;
1588					ccl -= cl;
1589				}
1590			} else {
1591				tocopy = min(left, ntfs_cntob(ccl) - off);
1592				ddprintf(("ntfs_readntvattr_plain: "
1593					"hole: ccn: 0x%x ccl: %d, off: %d, " \
1594					" len: %d, left: %d\n",
1595					(u_int32_t) ccn, (u_int32_t) ccl,
1596					(u_int32_t) off, (u_int32_t) tocopy,
1597					(u_int32_t) left));
1598				left -= tocopy;
1599				off = 0;
1600				if (uio) {
1601					size_t remains = tocopy;
1602					for(; remains; remains++)
1603						uiomove("", 1, uio);
1604				} else
1605					bzero(data, tocopy);
1606				data = data + tocopy;
1607			}
1608			cnt++;
1609		}
1610		if (left) {
1611			printf("ntfs_readntvattr_plain: POSSIBLE RUN ERROR\n");
1612			error = E2BIG;
1613		}
1614	} else {
1615		ddprintf(("ntfs_readnvattr_plain: data is in mft record\n"));
1616		if (uio)
1617			uiomove(vap->va_datap + roff, rsize, uio);
1618		else
1619			memcpy(rdata, vap->va_datap + roff, rsize);
1620		*initp += rsize;
1621	}
1622
1623	return (error);
1624}
1625
1626/*
1627 * This is one of read routines.
1628 */
1629int
1630ntfs_readattr_plain(
1631	struct ntfsmount * ntmp,
1632	struct ntnode * ip,
1633	u_int32_t attrnum,
1634	char *attrname,
1635	off_t roff,
1636	size_t rsize,
1637	void *rdata,
1638	size_t * initp,
1639	struct uio *uio)
1640{
1641	size_t          init;
1642	int             error = 0;
1643	off_t           off = roff, left = rsize, toread;
1644	caddr_t         data = rdata;
1645	struct ntvattr *vap;
1646	*initp = 0;
1647
1648	while (left) {
1649		error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname,
1650					ntfs_btocn(off), &vap);
1651		if (error)
1652			return (error);
1653		toread = min(left, ntfs_cntob(vap->va_vcnend + 1) - off);
1654		ddprintf(("ntfs_readattr_plain: o: %d, s: %d (%d - %d)\n",
1655			 (u_int32_t) off, (u_int32_t) toread,
1656			 (u_int32_t) vap->va_vcnstart,
1657			 (u_int32_t) vap->va_vcnend));
1658		error = ntfs_readntvattr_plain(ntmp, ip, vap,
1659					 off - ntfs_cntob(vap->va_vcnstart),
1660					 toread, data, &init, uio);
1661		if (error) {
1662			printf("ntfs_readattr_plain: " \
1663			       "ntfs_readntvattr_plain failed: o: %d, s: %d\n",
1664			       (u_int32_t) off, (u_int32_t) toread);
1665			printf("ntfs_readattr_plain: attrib: %d - %d\n",
1666			       (u_int32_t) vap->va_vcnstart,
1667			       (u_int32_t) vap->va_vcnend);
1668			ntfs_ntvattrrele(vap);
1669			break;
1670		}
1671		ntfs_ntvattrrele(vap);
1672		left -= toread;
1673		off += toread;
1674		data = data + toread;
1675		*initp += init;
1676	}
1677
1678	return (error);
1679}
1680
1681/*
1682 * This is one of read routines.
1683 */
1684int
1685ntfs_readattr(
1686	struct ntfsmount * ntmp,
1687	struct ntnode * ip,
1688	u_int32_t attrnum,
1689	char *attrname,
1690	off_t roff,
1691	size_t rsize,
1692	void *rdata,
1693	struct uio *uio)
1694{
1695	int             error = 0;
1696	struct ntvattr *vap;
1697	size_t          init;
1698
1699	ddprintf(("ntfs_readattr: reading %d: 0x%x, from %d size %d bytes\n",
1700	       ip->i_number, attrnum, (u_int32_t) roff, (u_int32_t) rsize));
1701
1702	error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname, 0, &vap);
1703	if (error)
1704		return (error);
1705
1706	if ((roff > vap->va_datalen) ||
1707	    (roff + rsize > vap->va_datalen)) {
1708		ddprintf(("ntfs_readattr: offset too big\n"));
1709		ntfs_ntvattrrele(vap);
1710		return (E2BIG);
1711	}
1712	if (vap->va_compression && vap->va_compressalg) {
1713		u_int8_t       *cup;
1714		u_int8_t       *uup;
1715		off_t           off = roff, left = rsize, tocopy;
1716		caddr_t         data = rdata;
1717		cn_t            cn;
1718
1719		ddprintf(("ntfs_ntreadattr: compression: %d\n",
1720			 vap->va_compressalg));
1721
1722		MALLOC(cup, u_int8_t *, ntfs_cntob(NTFS_COMPUNIT_CL),
1723		       M_NTFSDECOMP, M_WAITOK);
1724		MALLOC(uup, u_int8_t *, ntfs_cntob(NTFS_COMPUNIT_CL),
1725		       M_NTFSDECOMP, M_WAITOK);
1726
1727		cn = (ntfs_btocn(roff)) & (~(NTFS_COMPUNIT_CL - 1));
1728		off = roff - ntfs_cntob(cn);
1729
1730		while (left) {
1731			error = ntfs_readattr_plain(ntmp, ip, attrnum,
1732						  attrname, ntfs_cntob(cn),
1733					          ntfs_cntob(NTFS_COMPUNIT_CL),
1734						  cup, &init, NULL);
1735			if (error)
1736				break;
1737
1738			tocopy = min(left, ntfs_cntob(NTFS_COMPUNIT_CL) - off);
1739
1740			if (init == ntfs_cntob(NTFS_COMPUNIT_CL)) {
1741				if (uio)
1742					uiomove(cup + off, tocopy, uio);
1743				else
1744					memcpy(data, cup + off, tocopy);
1745			} else if (init == 0) {
1746				if (uio) {
1747					size_t remains = tocopy;
1748					for(; remains; remains--)
1749						uiomove("", 1, uio);
1750				}
1751				else
1752					bzero(data, tocopy);
1753			} else {
1754				error = ntfs_uncompunit(ntmp, uup, cup);
1755				if (error)
1756					break;
1757				if (uio)
1758					uiomove(uup + off, tocopy, uio);
1759				else
1760					memcpy(data, uup + off, tocopy);
1761			}
1762
1763			left -= tocopy;
1764			data = data + tocopy;
1765			off += tocopy - ntfs_cntob(NTFS_COMPUNIT_CL);
1766			cn += NTFS_COMPUNIT_CL;
1767		}
1768
1769		FREE(uup, M_NTFSDECOMP);
1770		FREE(cup, M_NTFSDECOMP);
1771	} else
1772		error = ntfs_readattr_plain(ntmp, ip, attrnum, attrname,
1773					     roff, rsize, rdata, &init, uio);
1774	ntfs_ntvattrrele(vap);
1775	return (error);
1776}
1777
1778#if UNUSED_CODE
1779int
1780ntfs_parserun(
1781	      cn_t * cn,
1782	      cn_t * cl,
1783	      u_int8_t * run,
1784	      u_long len,
1785	      u_long *off)
1786{
1787	u_int8_t        sz;
1788	int             i;
1789
1790	if (NULL == run) {
1791		printf("ntfs_parsetun: run == NULL\n");
1792		return (EINVAL);
1793	}
1794	sz = run[(*off)++];
1795	if (0 == sz) {
1796		printf("ntfs_parserun: trying to go out of run\n");
1797		return (E2BIG);
1798	}
1799	*cl = 0;
1800	if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) {
1801		printf("ntfs_parserun: " \
1802		       "bad run: length too big: sz: 0x%02x (%ld < %ld + sz)\n",
1803		       sz, len, *off);
1804		return (EINVAL);
1805	}
1806	for (i = 0; i < (sz & 0xF); i++)
1807		*cl += (u_int32_t) run[(*off)++] << (i << 3);
1808
1809	sz >>= 4;
1810	if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) {
1811		printf("ntfs_parserun: " \
1812		       "bad run: length too big: sz: 0x%02x (%ld < %ld + sz)\n",
1813		       sz, len, *off);
1814		return (EINVAL);
1815	}
1816	for (i = 0; i < (sz & 0xF); i++)
1817		*cn += (u_int32_t) run[(*off)++] << (i << 3);
1818
1819	return (0);
1820}
1821#endif
1822
1823/*
1824 * Process fixup routine on given buffer.
1825 */
1826int
1827ntfs_procfixups(
1828		struct ntfsmount * ntmp,
1829		u_int32_t magic,
1830		caddr_t buf,
1831		size_t len)
1832{
1833	struct fixuphdr *fhp = (struct fixuphdr *) buf;
1834	int             i;
1835	u_int16_t       fixup;
1836	u_int16_t      *fxp;
1837	u_int16_t      *cfxp;
1838
1839	if (fhp->fh_magic != magic) {
1840		printf("ntfs_procfixups: magic doesn't match: %08x != %08x\n",
1841		       fhp->fh_magic, magic);
1842		return (EINVAL);
1843	}
1844	if ((fhp->fh_fnum - 1) * ntmp->ntm_bps != len) {
1845		printf("ntfs_procfixups: " \
1846		       "bad fixups number: %d for %ld bytes block\n",
1847		       fhp->fh_fnum, (long)len);	/* XXX printf kludge */
1848		return (EINVAL);
1849	}
1850	if (fhp->fh_foff >= ntmp->ntm_spc * ntmp->ntm_mftrecsz * ntmp->ntm_bps) {
1851		printf("ntfs_procfixups: invalid offset: %x", fhp->fh_foff);
1852		return (EINVAL);
1853	}
1854	fxp = (u_int16_t *) (buf + fhp->fh_foff);
1855	cfxp = (u_int16_t *) (buf + ntmp->ntm_bps - 2);
1856	fixup = *fxp++;
1857	for (i = 1; i < fhp->fh_fnum; i++, fxp++) {
1858		if (*cfxp != fixup) {
1859			printf("ntfs_procfixups: fixup %d doesn't match\n", i);
1860			return (EINVAL);
1861		}
1862		*cfxp = *fxp;
1863		((caddr_t) cfxp) += ntmp->ntm_bps;
1864	}
1865	return (0);
1866}
1867
1868#if UNUSED_CODE
1869int
1870ntfs_runtocn(
1871	     cn_t * cn,
1872	     struct ntfsmount * ntmp,
1873	     u_int8_t * run,
1874	     u_long len,
1875	     cn_t vcn)
1876{
1877	cn_t            ccn = 0;
1878	cn_t            ccl = 0;
1879	u_long          off = 0;
1880	int             error = 0;
1881
1882#if NTFS_DEBUG
1883	int             i;
1884	printf("ntfs_runtocn: run: 0x%p, %ld bytes, vcn:%ld\n",
1885		run, len, (u_long) vcn);
1886	printf("ntfs_runtocn: run: ");
1887	for (i = 0; i < len; i++)
1888		printf("0x%02x ", run[i]);
1889	printf("\n");
1890#endif
1891
1892	if (NULL == run) {
1893		printf("ntfs_runtocn: run == NULL\n");
1894		return (EINVAL);
1895	}
1896	do {
1897		if (run[off] == 0) {
1898			printf("ntfs_runtocn: vcn too big\n");
1899			return (E2BIG);
1900		}
1901		vcn -= ccl;
1902		error = ntfs_parserun(&ccn, &ccl, run, len, &off);
1903		if (error) {
1904			printf("ntfs_runtocn: ntfs_parserun failed\n");
1905			return (error);
1906		}
1907	} while (ccl <= vcn);
1908	*cn = ccn + vcn;
1909	return (0);
1910}
1911#endif
1912
1913/*
1914 * this initializes toupper table & dependant variables to be ready for
1915 * later work
1916 */
1917void
1918ntfs_toupper_init()
1919{
1920	ntfs_toupper_tab = (wchar *) NULL;
1921	lockinit(&ntfs_toupper_lock, PVFS, "ntfs_toupper", 0, 0);
1922	ntfs_toupper_usecount = 0;
1923}
1924
1925void
1926ntfs_toupper_destroy(void)
1927{
1928
1929	lockdestroy(&ntfs_toupper_lock);
1930}
1931
1932/*
1933 * if the ntfs_toupper_tab[] is filled already, just raise use count;
1934 * otherwise read the data from the filesystem we are currently mounting
1935 */
1936int
1937ntfs_toupper_use(mp, ntmp)
1938	struct mount *mp;
1939	struct ntfsmount *ntmp;
1940{
1941	int error = 0;
1942	struct vnode *vp;
1943
1944	/* get exclusive access */
1945	LOCKMGR(&ntfs_toupper_lock, LK_EXCLUSIVE, NULL);
1946
1947	/* only read the translation data from a file if it hasn't been
1948	 * read already */
1949	if (ntfs_toupper_tab)
1950		goto out;
1951
1952	/*
1953	 * Read in Unicode lowercase -> uppercase translation file.
1954	 * XXX for now, just the first 256 entries are used anyway,
1955	 * so don't bother reading more
1956	 */
1957	MALLOC(ntfs_toupper_tab, wchar *, 256 * sizeof(wchar),
1958		M_NTFSRDATA, M_WAITOK);
1959
1960	if ((error = VFS_VGET(mp, NTFS_UPCASEINO, &vp)))
1961		goto out;
1962	error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL,
1963			0, 256*sizeof(wchar), (char *) ntfs_toupper_tab, NULL);
1964	vput(vp);
1965
1966    out:
1967	ntfs_toupper_usecount++;
1968	LOCKMGR(&ntfs_toupper_lock, LK_RELEASE, NULL);
1969	return (error);
1970}
1971
1972/*
1973 * lower the use count and if it reaches zero, free the memory
1974 * tied by toupper table
1975 */
1976void
1977ntfs_toupper_unuse()
1978{
1979	/* get exclusive access */
1980	LOCKMGR(&ntfs_toupper_lock, LK_EXCLUSIVE, NULL);
1981
1982	ntfs_toupper_usecount--;
1983	if (ntfs_toupper_usecount == 0) {
1984		FREE(ntfs_toupper_tab, M_NTFSRDATA);
1985		ntfs_toupper_tab = NULL;
1986	}
1987#ifdef DIAGNOSTIC
1988	else if (ntfs_toupper_usecount < 0) {
1989		panic("ntfs_toupper_unuse(): use count negative: %d\n",
1990			ntfs_toupper_usecount);
1991	}
1992#endif
1993
1994	/* release the lock */
1995	LOCKMGR(&ntfs_toupper_lock, LK_RELEASE, NULL);
1996}
1997
1998/*
1999 * maps the Unicode char to 8bit equivalent
2000 * XXX currently only gets lower 8bit from the Unicode char
2001 * and substitutes a '_' for it if the result would be '\0';
2002 * something better has to be definitely though out
2003 */
2004char
2005ntfs_u28(unichar)
2006  wchar unichar;
2007{
2008	return (char) NTFS_U28(unichar);
2009}
2010
2011