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