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