1 /* $NetBSD: ntfs_subr.c,v 1.25 2006/05/14 21:31:52 elad 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.25 2006/05/14 21:31:52 elad 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, 752 struct ntnode *ip, 753 int attrtype, 754 char *attrname, 755 struct fnode **fpp) 756 { 757 struct fnode *fp; 758 759 dprintf(("ntfs_fget: ino: %llu, attrtype: 0x%x, attrname: %s\n", 760 (unsigned long long)ip->i_number, attrtype, attrname?attrname:"")); 761 *fpp = NULL; 762 for (fp = ip->i_fnlist.lh_first; fp != NULL; fp = fp->f_fnlist.le_next){ 763 dprintf(("ntfs_fget: fnode: attrtype: %d, attrname: %s\n", 764 fp->f_attrtype, fp->f_attrname?fp->f_attrname:"")); 765 766 if ((attrtype == fp->f_attrtype) && 767 ((!attrname && !fp->f_attrname) || 768 (attrname && fp->f_attrname && 769 !strcmp(attrname,fp->f_attrname)))){ 770 dprintf(("ntfs_fget: found existed: %p\n",fp)); 771 *fpp = fp; 772 } 773 } 774 775 if (*fpp) 776 return (0); 777 778 MALLOC(fp, struct fnode *, sizeof(struct fnode), M_NTFSFNODE, M_WAITOK); 779 bzero(fp, sizeof(struct fnode)); 780 dprintf(("ntfs_fget: allocating fnode: %p\n",fp)); 781 782 fp->f_ip = ip; 783 fp->f_attrname = attrname; 784 if (fp->f_attrname) fp->f_flag |= FN_AATTRNAME; 785 fp->f_attrtype = attrtype; 786 787 ntfs_ntref(ip); 788 789 LIST_INSERT_HEAD(&ip->i_fnlist, fp, f_fnlist); 790 791 *fpp = fp; 792 793 return (0); 794 } 795 796 /* 797 * Deallocate fnode, remove it from ntnode's fnode list. 798 * 799 * ntnode should be locked. 800 */ 801 void 802 ntfs_frele( 803 struct fnode *fp) 804 { 805 struct ntnode *ip = FTONT(fp); 806 807 dprintf(("ntfs_frele: fnode: %p for %llu: %p\n", fp, 808 (unsigned long long)ip->i_number, ip)); 809 810 dprintf(("ntfs_frele: deallocating fnode\n")); 811 LIST_REMOVE(fp,f_fnlist); 812 if (fp->f_flag & FN_AATTRNAME) 813 FREE(fp->f_attrname, M_TEMP); 814 if (fp->f_dirblbuf) 815 FREE(fp->f_dirblbuf, M_NTFSDIR); 816 FREE(fp, M_NTFSFNODE); 817 ntfs_ntrele(ip); 818 } 819 820 /* 821 * Lookup attribute name in format: [[:$ATTR_TYPE]:$ATTR_NAME], 822 * $ATTR_TYPE is searched in attrdefs read from $AttrDefs. 823 * If $ATTR_TYPE not specified, ATTR_A_DATA assumed. 824 */ 825 static int 826 ntfs_ntlookupattr( 827 struct ntfsmount * ntmp, 828 const char * name, 829 int namelen, 830 int *attrtype, 831 char **attrname) 832 { 833 const char *sys; 834 size_t syslen, i; 835 struct ntvattrdef *adp; 836 837 if (namelen == 0) 838 return (0); 839 840 if (name[0] == '$') { 841 sys = name; 842 for (syslen = 0; syslen < namelen; syslen++) { 843 if(sys[syslen] == ':') { 844 name++; 845 namelen--; 846 break; 847 } 848 } 849 name += syslen; 850 namelen -= syslen; 851 852 adp = ntmp->ntm_ad; 853 for (i = 0; i < ntmp->ntm_adnum; i++, adp++){ 854 if (syslen != adp->ad_namelen || 855 strncmp(sys, adp->ad_name, syslen) != 0) 856 continue; 857 858 *attrtype = adp->ad_type; 859 goto out; 860 } 861 return (ENOENT); 862 } 863 864 out: 865 if (namelen) { 866 *attrname = (char *) malloc(namelen, M_TEMP, M_WAITOK); 867 memcpy((*attrname), name, namelen); 868 (*attrname)[namelen] = '\0'; 869 *attrtype = NTFS_A_DATA; 870 } 871 872 return (0); 873 } 874 875 /* 876 * Lookup specified node for filename, matching cnp, 877 * return fnode filled. 878 */ 879 int 880 ntfs_ntlookupfile( 881 struct ntfsmount * ntmp, 882 struct vnode * vp, 883 struct componentname * cnp, 884 struct vnode ** vpp) 885 { 886 struct fnode *fp = VTOF(vp); 887 struct ntnode *ip = FTONT(fp); 888 struct ntvattr *vap; /* Root attribute */ 889 cn_t cn = 0; /* VCN in current attribute */ 890 caddr_t rdbuf; /* Buffer to read directory's blocks */ 891 u_int32_t blsize; 892 u_int32_t rdsize; /* Length of data to read from current block */ 893 struct attr_indexentry *iep; 894 int error, res, anamelen, fnamelen; 895 const char *fname,*aname; 896 u_int32_t aoff; 897 int attrtype = NTFS_A_DATA; 898 char *attrname = NULL; 899 struct fnode *nfp; 900 struct vnode *nvp; 901 enum vtype f_type; 902 int fullscan = 0; 903 struct ntfs_lookup_ctx *lookup_ctx = NULL, *tctx; 904 905 error = ntfs_ntget(ip); 906 if (error) 907 return (error); 908 909 error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXROOT, "$I30", 0, &vap); 910 if (error || (vap->va_flag & NTFS_AF_INRUN)) 911 return (ENOTDIR); 912 913 /* 914 * Divide file name into: foofilefoofilefoofile[:attrspec] 915 * Store like this: fname:fnamelen [aname:anamelen] 916 */ 917 fname = cnp->cn_nameptr; 918 aname = NULL; 919 anamelen = 0; 920 for (fnamelen = 0; fnamelen < cnp->cn_namelen; fnamelen++) 921 if(fname[fnamelen] == ':') { 922 aname = fname + fnamelen + 1; 923 anamelen = cnp->cn_namelen - fnamelen - 1; 924 dprintf(("ntfs_ntlookupfile: %s (%d), attr: %s (%d)\n", 925 fname, fnamelen, aname, anamelen)); 926 break; 927 } 928 929 blsize = vap->va_a_iroot->ir_size; 930 dprintf(("ntfs_ntlookupfile: blksz: %d\n", blsize)); 931 932 rdbuf = (caddr_t) malloc(blsize, M_TEMP, M_WAITOK); 933 934 loop: 935 rdsize = vap->va_datalen; 936 dprintf(("ntfs_ntlookupfile: rdsz: %d\n", rdsize)); 937 938 error = ntfs_readattr(ntmp, ip, NTFS_A_INDXROOT, "$I30", 939 0, rdsize, rdbuf, NULL); 940 if (error) 941 goto fail; 942 943 aoff = sizeof(struct attr_indexroot); 944 945 do { 946 iep = (struct attr_indexentry *) (rdbuf + aoff); 947 948 for (; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (rdsize > aoff); 949 aoff += iep->reclen, 950 iep = (struct attr_indexentry *) (rdbuf + aoff)) 951 { 952 ddprintf(("scan: %d, %d\n", 953 (u_int32_t) iep->ie_number, 954 (u_int32_t) iep->ie_fnametype)); 955 956 /* check the name - the case-insensitive check 957 * has to come first, to break from this for loop 958 * if needed, so we can dive correctly */ 959 res = ntfs_uastricmp(ntmp, iep->ie_fname, 960 iep->ie_fnamelen, fname, fnamelen); 961 if (!fullscan) { 962 if (res > 0) break; 963 if (res < 0) continue; 964 } 965 966 if (iep->ie_fnametype == 0 || 967 !(ntmp->ntm_flag & NTFS_MFLAG_CASEINS)) 968 { 969 res = ntfs_uastrcmp(ntmp, iep->ie_fname, 970 iep->ie_fnamelen, fname, fnamelen); 971 if (res != 0 && !fullscan) continue; 972 } 973 974 /* if we perform full scan, the file does not match 975 * and this is subnode, dive */ 976 if (fullscan && res != 0) { 977 if (iep->ie_flag & NTFS_IEFLAG_SUBNODE) { 978 MALLOC(tctx, struct ntfs_lookup_ctx *, 979 sizeof(struct ntfs_lookup_ctx), 980 M_TEMP, M_WAITOK); 981 tctx->aoff = aoff + iep->reclen; 982 tctx->rdsize = rdsize; 983 tctx->cn = cn; 984 tctx->prev = lookup_ctx; 985 lookup_ctx = tctx; 986 break; 987 } else 988 continue; 989 } 990 991 if (aname) { 992 error = ntfs_ntlookupattr(ntmp, 993 aname, anamelen, 994 &attrtype, &attrname); 995 if (error) 996 goto fail; 997 } 998 999 /* Check if we've found ourselves */ 1000 if ((iep->ie_number == ip->i_number) && 1001 (attrtype == fp->f_attrtype) && 1002 ((!attrname && !fp->f_attrname) || 1003 (attrname && fp->f_attrname && 1004 !strcmp(attrname, fp->f_attrname)))) 1005 { 1006 VREF(vp); 1007 *vpp = vp; 1008 error = 0; 1009 goto fail; 1010 } 1011 1012 /* free the buffer returned by ntfs_ntlookupattr() */ 1013 if (attrname) { 1014 FREE(attrname, M_TEMP); 1015 attrname = NULL; 1016 } 1017 1018 /* vget node, but don't load it */ 1019 error = ntfs_vgetex(ntmp->ntm_mountp, 1020 iep->ie_number, attrtype, attrname, 1021 LK_EXCLUSIVE, VG_DONTLOADIN | VG_DONTVALIDFN, 1022 &nvp); 1023 if (error) 1024 goto fail; 1025 1026 nfp = VTOF(nvp); 1027 1028 if (nfp->f_flag & FN_VALID) { 1029 *vpp = nvp; 1030 goto fail; 1031 } 1032 1033 nfp->f_fflag = iep->ie_fflag; 1034 nfp->f_pnumber = iep->ie_fpnumber; 1035 nfp->f_times = iep->ie_ftimes; 1036 1037 if((nfp->f_fflag & NTFS_FFLAG_DIR) && 1038 (nfp->f_attrtype == NTFS_A_DATA) && 1039 (nfp->f_attrname == NULL)) 1040 f_type = VDIR; 1041 else 1042 f_type = VREG; 1043 1044 nvp->v_type = f_type; 1045 1046 if ((nfp->f_attrtype == NTFS_A_DATA) && 1047 (nfp->f_attrname == NULL)) 1048 { 1049 /* Opening default attribute */ 1050 nfp->f_size = iep->ie_fsize; 1051 nfp->f_allocated = iep->ie_fallocated; 1052 nfp->f_flag |= FN_PRELOADED; 1053 } else { 1054 error = ntfs_filesize(ntmp, nfp, 1055 &nfp->f_size, &nfp->f_allocated); 1056 if (error) { 1057 vput(nvp); 1058 goto fail; 1059 } 1060 } 1061 1062 nfp->f_flag &= ~FN_VALID; 1063 *vpp = nvp; 1064 goto fail; 1065 } 1066 1067 /* Dive if possible */ 1068 if (iep->ie_flag & NTFS_IEFLAG_SUBNODE) { 1069 dprintf(("ntfs_ntlookupfile: diving\n")); 1070 1071 cn = *(cn_t *) (rdbuf + aoff + 1072 iep->reclen - sizeof(cn_t)); 1073 rdsize = blsize; 1074 1075 error = ntfs_readattr(ntmp, ip, NTFS_A_INDX, "$I30", 1076 ntfs_cntob(cn), rdsize, rdbuf, NULL); 1077 if (error) 1078 goto fail; 1079 1080 error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC, 1081 rdbuf, rdsize); 1082 if (error) 1083 goto fail; 1084 1085 aoff = (((struct attr_indexalloc *) rdbuf)->ia_hdrsize + 1086 0x18); 1087 } else if (fullscan && lookup_ctx) { 1088 cn = lookup_ctx->cn; 1089 aoff = lookup_ctx->aoff; 1090 rdsize = lookup_ctx->rdsize; 1091 1092 error = ntfs_readattr(ntmp, ip, 1093 (cn == 0) ? NTFS_A_INDXROOT : NTFS_A_INDX, 1094 "$I30", ntfs_cntob(cn), rdsize, rdbuf, NULL); 1095 if (error) 1096 goto fail; 1097 1098 if (cn != 0) { 1099 error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC, 1100 rdbuf, rdsize); 1101 if (error) 1102 goto fail; 1103 } 1104 1105 tctx = lookup_ctx; 1106 lookup_ctx = lookup_ctx->prev; 1107 FREE(tctx, M_TEMP); 1108 } else { 1109 dprintf(("ntfs_ntlookupfile: nowhere to dive :-(\n")); 1110 error = ENOENT; 1111 break; 1112 } 1113 } while (1); 1114 1115 /* perform full scan if no entry was found */ 1116 if (!fullscan && error == ENOENT) { 1117 fullscan = 1; 1118 cn = 0; /* need zero, used by lookup_ctx */ 1119 1120 ddprintf(("ntfs_ntlookupfile: fullscan performed for: %.*s\n", 1121 (int) fnamelen, fname)); 1122 goto loop; 1123 } 1124 1125 dprintf(("finish\n")); 1126 1127 fail: 1128 if (attrname) 1129 FREE(attrname, M_TEMP); 1130 if (lookup_ctx) { 1131 while(lookup_ctx) { 1132 tctx = lookup_ctx; 1133 lookup_ctx = lookup_ctx->prev; 1134 FREE(tctx, M_TEMP); 1135 } 1136 } 1137 ntfs_ntvattrrele(vap); 1138 ntfs_ntput(ip); 1139 free(rdbuf, M_TEMP); 1140 return (error); 1141 } 1142 1143 /* 1144 * Check if name type is permitted to show. 1145 */ 1146 int 1147 ntfs_isnamepermitted( 1148 struct ntfsmount * ntmp, 1149 struct attr_indexentry * iep) 1150 { 1151 if (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES) 1152 return 1; 1153 1154 switch (iep->ie_fnametype) { 1155 case 2: 1156 ddprintf(("ntfs_isnamepermitted: skipped DOS name\n")); 1157 return 0; 1158 case 0: case 1: case 3: 1159 return 1; 1160 default: 1161 printf("ntfs_isnamepermitted: " 1162 "WARNING! Unknown file name type: %d\n", 1163 iep->ie_fnametype); 1164 break; 1165 } 1166 return 0; 1167 } 1168 1169 /* 1170 * Read ntfs dir like stream of attr_indexentry, not like btree of them. 1171 * This is done by scanning $BITMAP:$I30 for busy clusters and reading them. 1172 * Of course $INDEX_ROOT:$I30 is read before. Last read values are stored in 1173 * fnode, so we can skip toward record number num almost immediately. 1174 * Anyway this is rather slow routine. The problem is that we don't know 1175 * how many records are there in $INDEX_ALLOCATION:$I30 block. 1176 */ 1177 int 1178 ntfs_ntreaddir( 1179 struct ntfsmount * ntmp, 1180 struct fnode * fp, 1181 u_int32_t num, 1182 struct attr_indexentry ** riepp) 1183 { 1184 struct ntnode *ip = FTONT(fp); 1185 struct ntvattr *vap = NULL; /* IndexRoot attribute */ 1186 struct ntvattr *bmvap = NULL; /* BitMap attribute */ 1187 struct ntvattr *iavap = NULL; /* IndexAllocation attribute */ 1188 caddr_t rdbuf; /* Buffer to read directory's blocks */ 1189 u_char *bmp = NULL; /* Bitmap */ 1190 u_int32_t blsize; /* Index allocation size (2048) */ 1191 u_int32_t rdsize; /* Length of data to read */ 1192 u_int32_t attrnum; /* Current attribute type */ 1193 u_int32_t cpbl = 1; /* Clusters per directory block */ 1194 u_int32_t blnum; 1195 struct attr_indexentry *iep; 1196 int error = ENOENT; 1197 u_int32_t aoff, cnum; 1198 1199 dprintf(("ntfs_ntreaddir: read ino: %llu, num: %d\n", 1200 (unsigned long long)ip->i_number, num)); 1201 error = ntfs_ntget(ip); 1202 if (error) 1203 return (error); 1204 1205 error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXROOT, "$I30", 0, &vap); 1206 if (error) 1207 return (ENOTDIR); 1208 1209 if (fp->f_dirblbuf == NULL) { 1210 fp->f_dirblsz = vap->va_a_iroot->ir_size; 1211 fp->f_dirblbuf = (caddr_t) malloc( 1212 MAX(vap->va_datalen,fp->f_dirblsz), M_NTFSDIR, M_WAITOK); 1213 } 1214 1215 blsize = fp->f_dirblsz; 1216 rdbuf = fp->f_dirblbuf; 1217 1218 dprintf(("ntfs_ntreaddir: rdbuf: %p, blsize: %d\n", rdbuf, blsize)); 1219 1220 if (vap->va_a_iroot->ir_flag & NTFS_IRFLAG_INDXALLOC) { 1221 error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXBITMAP, "$I30", 1222 0, &bmvap); 1223 if (error) { 1224 error = ENOTDIR; 1225 goto fail; 1226 } 1227 bmp = (u_char *) malloc(bmvap->va_datalen, M_TEMP, M_WAITOK); 1228 error = ntfs_readattr(ntmp, ip, NTFS_A_INDXBITMAP, "$I30", 0, 1229 bmvap->va_datalen, bmp, NULL); 1230 if (error) 1231 goto fail; 1232 1233 error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDX, "$I30", 1234 0, &iavap); 1235 if (error) { 1236 error = ENOTDIR; 1237 goto fail; 1238 } 1239 cpbl = ntfs_btocn(blsize + ntfs_cntob(1) - 1); 1240 dprintf(("ntfs_ntreaddir: indexalloc: %qu, cpbl: %d\n", 1241 (long long)iavap->va_datalen, cpbl)); 1242 } else { 1243 dprintf(("ntfs_ntreadidir: w/o BitMap and IndexAllocation\n")); 1244 iavap = bmvap = NULL; 1245 bmp = NULL; 1246 } 1247 1248 /* Try use previous values */ 1249 if ((fp->f_lastdnum < num) && (fp->f_lastdnum != 0)) { 1250 attrnum = fp->f_lastdattr; 1251 aoff = fp->f_lastdoff; 1252 blnum = fp->f_lastdblnum; 1253 cnum = fp->f_lastdnum; 1254 } else { 1255 attrnum = NTFS_A_INDXROOT; 1256 aoff = sizeof(struct attr_indexroot); 1257 blnum = 0; 1258 cnum = 0; 1259 } 1260 1261 do { 1262 dprintf(("ntfs_ntreaddir: scan: 0x%x, %d, %d, %d, %d\n", 1263 attrnum, (u_int32_t) blnum, cnum, num, aoff)); 1264 rdsize = (attrnum == NTFS_A_INDXROOT) ? vap->va_datalen : blsize; 1265 error = ntfs_readattr(ntmp, ip, attrnum, "$I30", 1266 ntfs_cntob(blnum * cpbl), rdsize, rdbuf, NULL); 1267 if (error) 1268 goto fail; 1269 1270 if (attrnum == NTFS_A_INDX) { 1271 error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC, 1272 rdbuf, rdsize); 1273 if (error) 1274 goto fail; 1275 } 1276 if (aoff == 0) 1277 aoff = (attrnum == NTFS_A_INDX) ? 1278 (0x18 + ((struct attr_indexalloc *) rdbuf)->ia_hdrsize) : 1279 sizeof(struct attr_indexroot); 1280 1281 iep = (struct attr_indexentry *) (rdbuf + aoff); 1282 for (; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (rdsize > aoff); 1283 aoff += iep->reclen, 1284 iep = (struct attr_indexentry *) (rdbuf + aoff)) 1285 { 1286 if (!ntfs_isnamepermitted(ntmp, iep)) continue; 1287 1288 if (cnum >= num) { 1289 fp->f_lastdnum = cnum; 1290 fp->f_lastdoff = aoff; 1291 fp->f_lastdblnum = blnum; 1292 fp->f_lastdattr = attrnum; 1293 1294 *riepp = iep; 1295 1296 error = 0; 1297 goto fail; 1298 } 1299 cnum++; 1300 } 1301 1302 if (iavap) { 1303 if (attrnum == NTFS_A_INDXROOT) 1304 blnum = 0; 1305 else 1306 blnum++; 1307 1308 while (ntfs_cntob(blnum * cpbl) < iavap->va_datalen) { 1309 if (bmp[blnum >> 3] & (1 << (blnum & 3))) 1310 break; 1311 blnum++; 1312 } 1313 1314 attrnum = NTFS_A_INDX; 1315 aoff = 0; 1316 if (ntfs_cntob(blnum * cpbl) >= iavap->va_datalen) 1317 break; 1318 dprintf(("ntfs_ntreaddir: blnum: %d\n", (u_int32_t) blnum)); 1319 } 1320 } while (iavap); 1321 1322 *riepp = NULL; 1323 fp->f_lastdnum = 0; 1324 1325 fail: 1326 if (vap) 1327 ntfs_ntvattrrele(vap); 1328 if (bmvap) 1329 ntfs_ntvattrrele(bmvap); 1330 if (iavap) 1331 ntfs_ntvattrrele(iavap); 1332 if (bmp) 1333 FREE(bmp, M_TEMP); 1334 ntfs_ntput(ip); 1335 return (error); 1336 } 1337 1338 /* 1339 * Convert NTFS times that are in 100 ns units and begins from 1340 * 1601 Jan 1 into unix times. 1341 */ 1342 struct timespec 1343 ntfs_nttimetounix( 1344 u_int64_t nt) 1345 { 1346 struct timespec t; 1347 1348 /* WindowNT times are in 100 ns and from 1601 Jan 1 */ 1349 t.tv_nsec = (nt % (1000 * 1000 * 10)) * 100; 1350 t.tv_sec = nt / (1000 * 1000 * 10) - 1351 369LL * 365LL * 24LL * 60LL * 60LL - 1352 89LL * 1LL * 24LL * 60LL * 60LL; 1353 return (t); 1354 } 1355 1356 /* 1357 * Get file times from NTFS_A_NAME attribute. 1358 */ 1359 int 1360 ntfs_times( 1361 struct ntfsmount * ntmp, 1362 struct ntnode * ip, 1363 ntfs_times_t * tm) 1364 { 1365 struct ntvattr *vap; 1366 int error; 1367 1368 dprintf(("ntfs_times: ino: %llu...\n", 1369 (unsigned long long)ip->i_number)); 1370 1371 error = ntfs_ntget(ip); 1372 if (error) 1373 return (error); 1374 1375 error = ntfs_ntvattrget(ntmp, ip, NTFS_A_NAME, NULL, 0, &vap); 1376 if (error) { 1377 ntfs_ntput(ip); 1378 return (error); 1379 } 1380 *tm = vap->va_a_name->n_times; 1381 ntfs_ntvattrrele(vap); 1382 ntfs_ntput(ip); 1383 1384 return (0); 1385 } 1386 1387 /* 1388 * Get file sizes from corresponding attribute. 1389 * 1390 * ntnode under fnode should be locked. 1391 */ 1392 int 1393 ntfs_filesize( 1394 struct ntfsmount * ntmp, 1395 struct fnode * fp, 1396 u_int64_t * size, 1397 u_int64_t * bytes) 1398 { 1399 struct ntvattr *vap; 1400 struct ntnode *ip = FTONT(fp); 1401 u_int64_t sz, bn; 1402 int error; 1403 1404 dprintf(("ntfs_filesize: ino: %llu\n", 1405 (unsigned long long)ip->i_number)); 1406 1407 error = ntfs_ntvattrget(ntmp, ip, 1408 fp->f_attrtype, fp->f_attrname, 0, &vap); 1409 if (error) 1410 return (error); 1411 1412 bn = vap->va_allocated; 1413 sz = vap->va_datalen; 1414 1415 dprintf(("ntfs_filesize: %d bytes (%d bytes allocated)\n", 1416 (u_int32_t) sz, (u_int32_t) bn)); 1417 1418 if (size) 1419 *size = sz; 1420 if (bytes) 1421 *bytes = bn; 1422 1423 ntfs_ntvattrrele(vap); 1424 1425 return (0); 1426 } 1427 1428 /* 1429 * This is one of write routine. 1430 */ 1431 int 1432 ntfs_writeattr_plain( 1433 struct ntfsmount * ntmp, 1434 struct ntnode * ip, 1435 u_int32_t attrnum, 1436 char *attrname, 1437 off_t roff, 1438 size_t rsize, 1439 void *rdata, 1440 size_t * initp, 1441 struct uio *uio) 1442 { 1443 size_t init; 1444 int error = 0; 1445 off_t off = roff, left = rsize, towrite; 1446 caddr_t data = rdata; 1447 struct ntvattr *vap; 1448 *initp = 0; 1449 1450 while (left) { 1451 error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname, 1452 ntfs_btocn(off), &vap); 1453 if (error) 1454 return (error); 1455 towrite = MIN(left, ntfs_cntob(vap->va_vcnend + 1) - off); 1456 ddprintf(("ntfs_writeattr_plain: o: %qd, s: %qd (%qu - %qu)\n", 1457 (long long) off, (long long) towrite, 1458 (long long) vap->va_vcnstart, 1459 (long long) vap->va_vcnend)); 1460 error = ntfs_writentvattr_plain(ntmp, ip, vap, 1461 off - ntfs_cntob(vap->va_vcnstart), 1462 towrite, data, &init, uio); 1463 if (error) { 1464 dprintf(("ntfs_writeattr_plain: " 1465 "ntfs_writentvattr_plain failed: o: %qd, s: %qd\n", 1466 (long long) off, (long long) towrite)); 1467 dprintf(("ntfs_writeattr_plain: attrib: %qu - %qu\n", 1468 (long long) vap->va_vcnstart, 1469 (long long) vap->va_vcnend)); 1470 ntfs_ntvattrrele(vap); 1471 break; 1472 } 1473 ntfs_ntvattrrele(vap); 1474 left -= towrite; 1475 off += towrite; 1476 data = data + towrite; 1477 *initp += init; 1478 } 1479 1480 return (error); 1481 } 1482 1483 /* 1484 * This is one of write routine. 1485 * 1486 * ntnode should be locked. 1487 */ 1488 int 1489 ntfs_writentvattr_plain( 1490 struct ntfsmount * ntmp, 1491 struct ntnode * ip, 1492 struct ntvattr * vap, 1493 off_t roff, 1494 size_t rsize, 1495 void *rdata, 1496 size_t * initp, 1497 struct uio *uio) 1498 { 1499 int error = 0; 1500 off_t off; 1501 int cnt; 1502 cn_t ccn, ccl, cn, left, cl; 1503 caddr_t data = rdata; 1504 struct buf *bp; 1505 size_t tocopy; 1506 1507 *initp = 0; 1508 1509 if ((vap->va_flag & NTFS_AF_INRUN) == 0) { 1510 dprintf(("ntfs_writevattr_plain: CAN'T WRITE RES. ATTRIBUTE\n")); 1511 return ENOTTY; 1512 } 1513 1514 ddprintf(("ntfs_writentvattr_plain: data in run: %lu chains\n", 1515 vap->va_vruncnt)); 1516 1517 off = roff; 1518 left = rsize; 1519 ccl = 0; 1520 ccn = 0; 1521 cnt = 0; 1522 for (; left && (cnt < vap->va_vruncnt); cnt++) { 1523 ccn = vap->va_vruncn[cnt]; 1524 ccl = vap->va_vruncl[cnt]; 1525 1526 ddprintf(("ntfs_writentvattr_plain: " 1527 "left %qu, cn: 0x%qx, cl: %qu, off: %qd\n", 1528 (long long) left, (long long) ccn, 1529 (long long) ccl, (long long) off)); 1530 1531 if (ntfs_cntob(ccl) < off) { 1532 off -= ntfs_cntob(ccl); 1533 cnt++; 1534 continue; 1535 } 1536 if (!ccn && ip->i_number != NTFS_BOOTINO) 1537 continue; /* XXX */ 1538 1539 ccl -= ntfs_btocn(off); 1540 cn = ccn + ntfs_btocn(off); 1541 off = ntfs_btocnoff(off); 1542 1543 while (left && ccl) { 1544 /* 1545 * Always read and write single clusters at a time - 1546 * we need to avoid requesting differently-sized 1547 * blocks at the same disk offsets to avoid 1548 * confusing the buffer cache. 1549 */ 1550 tocopy = MIN(left, ntfs_cntob(1) - off); 1551 cl = ntfs_btocl(tocopy + off); 1552 KASSERT(cl == 1 && tocopy <= ntfs_cntob(1)); 1553 ddprintf(("ntfs_writentvattr_plain: write: " 1554 "cn: 0x%qx cl: %qu, off: %qd len: %qu, left: %qu\n", 1555 (long long) cn, (long long) cl, 1556 (long long) off, (long long) tocopy, 1557 (long long) left)); 1558 if ((off == 0) && (tocopy == ntfs_cntob(cl))) 1559 { 1560 bp = getblk(ntmp->ntm_devvp, ntfs_cntobn(cn), 1561 ntfs_cntob(cl), 0, 0); 1562 clrbuf(bp); 1563 } else { 1564 error = bread(ntmp->ntm_devvp, ntfs_cntobn(cn), 1565 ntfs_cntob(cl), NOCRED, &bp); 1566 if (error) { 1567 brelse(bp); 1568 return (error); 1569 } 1570 } 1571 if (uio) 1572 uiomove(bp->b_data + off, tocopy, uio); 1573 else 1574 memcpy(bp->b_data + off, data, tocopy); 1575 bawrite(bp); 1576 data = data + tocopy; 1577 *initp += tocopy; 1578 off = 0; 1579 left -= tocopy; 1580 cn += cl; 1581 ccl -= cl; 1582 } 1583 } 1584 1585 if (left) { 1586 printf("ntfs_writentvattr_plain: POSSIBLE RUN ERROR\n"); 1587 error = EINVAL; 1588 } 1589 1590 return (error); 1591 } 1592 1593 /* 1594 * This is one of read routines. 1595 * 1596 * ntnode should be locked. 1597 */ 1598 int 1599 ntfs_readntvattr_plain( 1600 struct ntfsmount * ntmp, 1601 struct ntnode * ip, 1602 struct ntvattr * vap, 1603 off_t roff, 1604 size_t rsize, 1605 void *rdata, 1606 size_t * initp, 1607 struct uio *uio) 1608 { 1609 int error = 0; 1610 off_t off; 1611 1612 *initp = 0; 1613 if (vap->va_flag & NTFS_AF_INRUN) { 1614 int cnt; 1615 cn_t ccn, ccl, cn, left, cl; 1616 caddr_t data = rdata; 1617 struct buf *bp; 1618 size_t tocopy; 1619 1620 ddprintf(("ntfs_readntvattr_plain: data in run: %lu chains\n", 1621 vap->va_vruncnt)); 1622 1623 off = roff; 1624 left = rsize; 1625 ccl = 0; 1626 ccn = 0; 1627 cnt = 0; 1628 while (left && (cnt < vap->va_vruncnt)) { 1629 ccn = vap->va_vruncn[cnt]; 1630 ccl = vap->va_vruncl[cnt]; 1631 1632 ddprintf(("ntfs_readntvattr_plain: " 1633 "left %qu, cn: 0x%qx, cl: %qu, off: %qd\n", 1634 (long long) left, (long long) ccn, 1635 (long long) ccl, (long long) off)); 1636 1637 if (ntfs_cntob(ccl) < off) { 1638 off -= ntfs_cntob(ccl); 1639 cnt++; 1640 continue; 1641 } 1642 if (ccn || ip->i_number == NTFS_BOOTINO) { 1643 ccl -= ntfs_btocn(off); 1644 cn = ccn + ntfs_btocn(off); 1645 off = ntfs_btocnoff(off); 1646 1647 while (left && ccl) { 1648 /* 1649 * Always read single clusters at a 1650 * time - we need to avoid reading 1651 * differently-sized blocks at the 1652 * same disk offsets to avoid 1653 * confusing the buffer cache. 1654 */ 1655 tocopy = MIN(left, 1656 ntfs_cntob(1) - off); 1657 cl = ntfs_btocl(tocopy + off); 1658 KASSERT(cl == 1 && 1659 tocopy <= ntfs_cntob(1)); 1660 1661 ddprintf(("ntfs_readntvattr_plain: " 1662 "read: cn: 0x%qx cl: %qu, " 1663 "off: %qd len: %qu, left: %qu\n", 1664 (long long) cn, 1665 (long long) cl, 1666 (long long) off, 1667 (long long) tocopy, 1668 (long long) left)); 1669 error = bread(ntmp->ntm_devvp, 1670 ntfs_cntobn(cn), 1671 ntfs_cntob(cl), 1672 NOCRED, &bp); 1673 if (error) { 1674 brelse(bp); 1675 return (error); 1676 } 1677 if (uio) { 1678 uiomove(bp->b_data + off, 1679 tocopy, uio); 1680 } else { 1681 memcpy(data, bp->b_data + off, 1682 tocopy); 1683 } 1684 brelse(bp); 1685 data = data + tocopy; 1686 *initp += tocopy; 1687 off = 0; 1688 left -= tocopy; 1689 cn += cl; 1690 ccl -= cl; 1691 } 1692 } else { 1693 tocopy = MIN(left, ntfs_cntob(ccl) - off); 1694 ddprintf(("ntfs_readntvattr_plain: " 1695 "hole: ccn: 0x%qx ccl: %qu, off: %qd, " 1696 " len: %qu, left: %qu\n", 1697 (long long) ccn, (long long) ccl, 1698 (long long) off, (long long) tocopy, 1699 (long long) left)); 1700 left -= tocopy; 1701 off = 0; 1702 if (uio) { 1703 char vbuf[] = ""; 1704 size_t remains = tocopy; 1705 for(; remains; remains--) 1706 uiomove(vbuf, 1, uio); 1707 } else 1708 bzero(data, tocopy); 1709 data = data + tocopy; 1710 } 1711 cnt++; 1712 } 1713 if (left) { 1714 printf("ntfs_readntvattr_plain: POSSIBLE RUN ERROR\n"); 1715 error = E2BIG; 1716 } 1717 } else { 1718 ddprintf(("ntfs_readnvattr_plain: data is in mft record\n")); 1719 if (uio) 1720 uiomove(vap->va_datap + roff, rsize, uio); 1721 else 1722 memcpy(rdata, vap->va_datap + roff, rsize); 1723 *initp += rsize; 1724 } 1725 1726 return (error); 1727 } 1728 1729 /* 1730 * This is one of read routines. 1731 */ 1732 int 1733 ntfs_readattr_plain( 1734 struct ntfsmount * ntmp, 1735 struct ntnode * ip, 1736 u_int32_t attrnum, 1737 const char *attrname, 1738 off_t roff, 1739 size_t rsize, 1740 void *rdata, 1741 size_t * initp, 1742 struct uio *uio) 1743 { 1744 size_t init; 1745 int error = 0; 1746 off_t off = roff, left = rsize, toread; 1747 caddr_t data = rdata; 1748 struct ntvattr *vap; 1749 *initp = 0; 1750 1751 while (left) { 1752 error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname, 1753 ntfs_btocn(off), &vap); 1754 if (error) 1755 return (error); 1756 toread = MIN(left, ntfs_cntob(vap->va_vcnend + 1) - off); 1757 ddprintf(("ntfs_readattr_plain: o: %qd, s: %qd (%qu - %qu)\n", 1758 (long long) off, (long long) toread, 1759 (long long) vap->va_vcnstart, 1760 (long long) vap->va_vcnend)); 1761 error = ntfs_readntvattr_plain(ntmp, ip, vap, 1762 off - ntfs_cntob(vap->va_vcnstart), 1763 toread, data, &init, uio); 1764 if (error) { 1765 printf("ntfs_readattr_plain: " 1766 "ntfs_readntvattr_plain failed: o: %qd, s: %qd\n", 1767 (long long) off, (long long) toread); 1768 printf("ntfs_readattr_plain: attrib: %qu - %qu\n", 1769 (long long) vap->va_vcnstart, 1770 (long long) vap->va_vcnend); 1771 ntfs_ntvattrrele(vap); 1772 break; 1773 } 1774 ntfs_ntvattrrele(vap); 1775 left -= toread; 1776 off += toread; 1777 data = data + toread; 1778 *initp += init; 1779 } 1780 1781 return (error); 1782 } 1783 1784 /* 1785 * This is one of read routines. 1786 */ 1787 int 1788 ntfs_readattr( 1789 struct ntfsmount * ntmp, 1790 struct ntnode * ip, 1791 u_int32_t attrnum, 1792 const char *attrname, 1793 off_t roff, 1794 size_t rsize, 1795 void *rdata, 1796 struct uio *uio) 1797 { 1798 int error = 0; 1799 struct ntvattr *vap; 1800 size_t init; 1801 1802 ddprintf(("ntfs_readattr: reading %llu: 0x%x, from %qd size %qu" 1803 " bytes\n", (unsigned long long)ip->i_number, attrnum, 1804 (long long)roff, (long long)rsize)); 1805 1806 error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname, 0, &vap); 1807 if (error) 1808 return (error); 1809 1810 if ((roff > vap->va_datalen) || 1811 (roff + rsize > vap->va_datalen)) { 1812 printf("ntfs_readattr: offset too big: %qd (%qd) > %qu\n", 1813 (long long) roff, (long long) (roff + rsize), 1814 (long long) vap->va_datalen); 1815 ntfs_ntvattrrele(vap); 1816 return (E2BIG); 1817 } 1818 if (vap->va_compression && vap->va_compressalg) { 1819 u_int8_t *cup; 1820 u_int8_t *uup; 1821 off_t off = roff, left = rsize, tocopy; 1822 caddr_t data = rdata; 1823 cn_t cn; 1824 1825 ddprintf(("ntfs_ntreadattr: compression: %d\n", 1826 vap->va_compressalg)); 1827 1828 cup = malloc(ntfs_cntob(NTFS_COMPUNIT_CL), 1829 M_NTFSDECOMP, M_WAITOK); 1830 uup = malloc(ntfs_cntob(NTFS_COMPUNIT_CL), 1831 M_NTFSDECOMP, M_WAITOK); 1832 1833 cn = (ntfs_btocn(roff)) & (~(NTFS_COMPUNIT_CL - 1)); 1834 off = roff - ntfs_cntob(cn); 1835 1836 while (left) { 1837 error = ntfs_readattr_plain(ntmp, ip, attrnum, 1838 attrname, ntfs_cntob(cn), 1839 ntfs_cntob(NTFS_COMPUNIT_CL), 1840 cup, &init, NULL); 1841 if (error) 1842 break; 1843 1844 tocopy = MIN(left, ntfs_cntob(NTFS_COMPUNIT_CL) - off); 1845 1846 if (init == ntfs_cntob(NTFS_COMPUNIT_CL)) { 1847 if (uio) 1848 uiomove(cup + off, tocopy, uio); 1849 else 1850 memcpy(data, cup + off, tocopy); 1851 } else if (init == 0) { 1852 if (uio) { 1853 char vbuf[] = ""; 1854 size_t remains = tocopy; 1855 for(; remains; remains--) 1856 uiomove(vbuf, 1, uio); 1857 } 1858 else 1859 bzero(data, tocopy); 1860 } else { 1861 error = ntfs_uncompunit(ntmp, uup, cup); 1862 if (error) 1863 break; 1864 if (uio) 1865 uiomove(uup + off, tocopy, uio); 1866 else 1867 memcpy(data, uup + off, tocopy); 1868 } 1869 1870 left -= tocopy; 1871 data = data + tocopy; 1872 off += tocopy - ntfs_cntob(NTFS_COMPUNIT_CL); 1873 cn += NTFS_COMPUNIT_CL; 1874 } 1875 1876 FREE(uup, M_NTFSDECOMP); 1877 FREE(cup, M_NTFSDECOMP); 1878 } else 1879 error = ntfs_readattr_plain(ntmp, ip, attrnum, attrname, 1880 roff, rsize, rdata, &init, uio); 1881 ntfs_ntvattrrele(vap); 1882 return (error); 1883 } 1884 1885 #if UNUSED_CODE 1886 int 1887 ntfs_parserun( 1888 cn_t * cn, 1889 cn_t * cl, 1890 u_int8_t * run, 1891 u_long len, 1892 u_long *off) 1893 { 1894 u_int8_t sz; 1895 int i; 1896 1897 if (NULL == run) { 1898 printf("ntfs_parsetun: run == NULL\n"); 1899 return (EINVAL); 1900 } 1901 sz = run[(*off)++]; 1902 if (0 == sz) { 1903 printf("ntfs_parserun: trying to go out of run\n"); 1904 return (E2BIG); 1905 } 1906 *cl = 0; 1907 if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) { 1908 printf("ntfs_parserun: " 1909 "bad run: length too big: sz: 0x%02x (%ld < %ld + sz)\n", 1910 sz, len, *off); 1911 return (EINVAL); 1912 } 1913 for (i = 0; i < (sz & 0xF); i++) 1914 *cl += (u_int32_t) run[(*off)++] << (i << 3); 1915 1916 sz >>= 4; 1917 if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) { 1918 printf("ntfs_parserun: " 1919 "bad run: length too big: sz: 0x%02x (%ld < %ld + sz)\n", 1920 sz, len, *off); 1921 return (EINVAL); 1922 } 1923 for (i = 0; i < (sz & 0xF); i++) 1924 *cn += (u_int32_t) run[(*off)++] << (i << 3); 1925 1926 return (0); 1927 } 1928 #endif 1929 1930 /* 1931 * Process fixup routine on given buffer. 1932 */ 1933 int 1934 ntfs_procfixups( 1935 struct ntfsmount * ntmp, 1936 u_int32_t magic, 1937 caddr_t xbuf, 1938 size_t len) 1939 { 1940 struct fixuphdr *fhp = (struct fixuphdr *) xbuf; 1941 int i; 1942 u_int16_t fixup; 1943 u_int16_t *fxp; 1944 u_int16_t *cfxp; 1945 1946 if (fhp->fh_magic != magic) { 1947 printf("ntfs_procfixups: magic doesn't match: %08x != %08x\n", 1948 fhp->fh_magic, magic); 1949 return (EINVAL); 1950 } 1951 if ((fhp->fh_fnum - 1) * ntmp->ntm_bps != len) { 1952 printf("ntfs_procfixups: " 1953 "bad fixups number: %d for %ld bytes block\n", 1954 fhp->fh_fnum, (long)len); /* XXX printf kludge */ 1955 return (EINVAL); 1956 } 1957 if (fhp->fh_foff >= ntmp->ntm_spc * ntmp->ntm_mftrecsz * ntmp->ntm_bps) { 1958 printf("ntfs_procfixups: invalid offset: %x", fhp->fh_foff); 1959 return (EINVAL); 1960 } 1961 fxp = (u_int16_t *) (xbuf + fhp->fh_foff); 1962 cfxp = (u_int16_t *) (xbuf + ntmp->ntm_bps - 2); 1963 fixup = *fxp++; 1964 for (i = 1; i < fhp->fh_fnum; i++, fxp++) { 1965 if (*cfxp != fixup) { 1966 printf("ntfs_procfixups: fixup %d doesn't match\n", i); 1967 return (EINVAL); 1968 } 1969 *cfxp = *fxp; 1970 cfxp = (u_int16_t *)((caddr_t)cfxp + ntmp->ntm_bps); 1971 } 1972 return (0); 1973 } 1974 1975 #if UNUSED_CODE 1976 int 1977 ntfs_runtocn( 1978 cn_t * cn, 1979 struct ntfsmount * ntmp, 1980 u_int8_t * run, 1981 u_long len, 1982 cn_t vcn) 1983 { 1984 cn_t ccn = 0; 1985 cn_t ccl = 0; 1986 u_long off = 0; 1987 int error = 0; 1988 1989 #ifdef NTFS_DEBUG 1990 int i; 1991 printf("ntfs_runtocn: run: %p, %ld bytes, vcn:%ld\n", 1992 run, len, (u_long) vcn); 1993 printf("ntfs_runtocn: run: "); 1994 for (i = 0; i < len; i++) 1995 printf("0x%02x ", run[i]); 1996 printf("\n"); 1997 #endif 1998 1999 if (NULL == run) { 2000 printf("ntfs_runtocn: run == NULL\n"); 2001 return (EINVAL); 2002 } 2003 do { 2004 if (run[off] == 0) { 2005 printf("ntfs_runtocn: vcn too big\n"); 2006 return (E2BIG); 2007 } 2008 vcn -= ccl; 2009 error = ntfs_parserun(&ccn, &ccl, run, len, &off); 2010 if (error) { 2011 printf("ntfs_runtocn: ntfs_parserun failed\n"); 2012 return (error); 2013 } 2014 } while (ccl <= vcn); 2015 *cn = ccn + vcn; 2016 return (0); 2017 } 2018 #endif 2019 2020 /* 2021 * this initializes toupper table & dependant variables to be ready for 2022 * later work 2023 */ 2024 void 2025 ntfs_toupper_init() 2026 { 2027 ntfs_toupper_tab = (wchar *) NULL; 2028 lockinit(&ntfs_toupper_lock, PVFS, "ntfs_toupper", 0, 0); 2029 ntfs_toupper_usecount = 0; 2030 } 2031 2032 /* 2033 * if the ntfs_toupper_tab[] is filled already, just raise use count; 2034 * otherwise read the data from the filesystem we are currently mounting 2035 */ 2036 int 2037 ntfs_toupper_use(mp, ntmp) 2038 struct mount *mp; 2039 struct ntfsmount *ntmp; 2040 { 2041 int error = 0; 2042 struct vnode *vp; 2043 2044 /* get exclusive access */ 2045 lockmgr(&ntfs_toupper_lock, LK_EXCLUSIVE, NULL); 2046 2047 /* only read the translation data from a file if it hasn't been 2048 * read already */ 2049 if (ntfs_toupper_tab) 2050 goto out; 2051 2052 /* 2053 * Read in Unicode lowercase -> uppercase translation file. 2054 * XXX for now, just the first 256 entries are used anyway, 2055 * so don't bother reading more 2056 */ 2057 MALLOC(ntfs_toupper_tab, wchar *, 256 * 256 * sizeof(wchar), 2058 M_NTFSRDATA, M_WAITOK); 2059 2060 if ((error = VFS_VGET(mp, NTFS_UPCASEINO, &vp))) 2061 goto out; 2062 error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL, 2063 0, 256*256*sizeof(wchar), (char *) ntfs_toupper_tab, 2064 NULL); 2065 vput(vp); 2066 2067 out: 2068 ntfs_toupper_usecount++; 2069 lockmgr(&ntfs_toupper_lock, LK_RELEASE, NULL); 2070 return (error); 2071 } 2072 2073 /* 2074 * lower the use count and if it reaches zero, free the memory 2075 * tied by toupper table 2076 */ 2077 void 2078 ntfs_toupper_unuse() 2079 { 2080 /* get exclusive access */ 2081 lockmgr(&ntfs_toupper_lock, LK_EXCLUSIVE, NULL); 2082 2083 ntfs_toupper_usecount--; 2084 if (ntfs_toupper_usecount == 0) { 2085 FREE(ntfs_toupper_tab, M_NTFSRDATA); 2086 ntfs_toupper_tab = NULL; 2087 } 2088 #ifdef DIAGNOSTIC 2089 else if (ntfs_toupper_usecount < 0) { 2090 panic("ntfs_toupper_unuse(): use count negative: %d", 2091 ntfs_toupper_usecount); 2092 } 2093 #endif 2094 2095 /* release the lock */ 2096 lockmgr(&ntfs_toupper_lock, LK_RELEASE, NULL); 2097 } 2098