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