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