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