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