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