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