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