1 /* $NetBSD: ntfs_subr.c,v 1.36 2008/01/29 18:21:10 pooka 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.36 2008/01/29 18:21:10 pooka 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, &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 struct buf *bp; 1520 size_t tocopy; 1521 1522 *initp = 0; 1523 1524 if ((vap->va_flag & NTFS_AF_INRUN) == 0) { 1525 dprintf(("ntfs_writevattr_plain: CAN'T WRITE RES. ATTRIBUTE\n")); 1526 return ENOTTY; 1527 } 1528 1529 ddprintf(("ntfs_writentvattr_plain: data in run: %lu chains\n", 1530 vap->va_vruncnt)); 1531 1532 off = roff; 1533 left = rsize; 1534 ccl = 0; 1535 ccn = 0; 1536 cnt = 0; 1537 for (; left && (cnt < vap->va_vruncnt); cnt++) { 1538 ccn = vap->va_vruncn[cnt]; 1539 ccl = vap->va_vruncl[cnt]; 1540 1541 ddprintf(("ntfs_writentvattr_plain: " 1542 "left %qu, cn: 0x%qx, cl: %qu, off: %qd\n", 1543 (long long) left, (long long) ccn, 1544 (long long) ccl, (long long) off)); 1545 1546 if (ntfs_cntob(ccl) < off) { 1547 off -= ntfs_cntob(ccl); 1548 cnt++; 1549 continue; 1550 } 1551 if (!ccn && ip->i_number != NTFS_BOOTINO) 1552 continue; /* XXX */ 1553 1554 ccl -= ntfs_btocn(off); 1555 cn = ccn + ntfs_btocn(off); 1556 off = ntfs_btocnoff(off); 1557 1558 while (left && ccl) { 1559 /* 1560 * Always read and write single clusters at a time - 1561 * we need to avoid requesting differently-sized 1562 * blocks at the same disk offsets to avoid 1563 * confusing the buffer cache. 1564 */ 1565 tocopy = MIN(left, ntfs_cntob(1) - off); 1566 cl = ntfs_btocl(tocopy + off); 1567 KASSERT(cl == 1 && tocopy <= ntfs_cntob(1)); 1568 ddprintf(("ntfs_writentvattr_plain: write: " 1569 "cn: 0x%qx cl: %qu, off: %qd len: %qu, left: %qu\n", 1570 (long long) cn, (long long) cl, 1571 (long long) off, (long long) tocopy, 1572 (long long) left)); 1573 if ((off == 0) && (tocopy == ntfs_cntob(cl))) 1574 { 1575 bp = getblk(ntmp->ntm_devvp, ntfs_cntobn(cn), 1576 ntfs_cntob(cl), 0, 0); 1577 clrbuf(bp); 1578 } else { 1579 error = bread(ntmp->ntm_devvp, ntfs_cntobn(cn), 1580 ntfs_cntob(cl), NOCRED, &bp); 1581 if (error) { 1582 brelse(bp, 0); 1583 return (error); 1584 } 1585 } 1586 if (uio) 1587 uiomove((char *)bp->b_data + off, tocopy, uio); 1588 else 1589 memcpy((char *)bp->b_data + off, data, tocopy); 1590 bawrite(bp); 1591 data = (char *)data + tocopy; 1592 *initp += tocopy; 1593 off = 0; 1594 left -= tocopy; 1595 cn += cl; 1596 ccl -= cl; 1597 } 1598 } 1599 1600 if (left) { 1601 printf("ntfs_writentvattr_plain: POSSIBLE RUN ERROR\n"); 1602 error = EINVAL; 1603 } 1604 1605 return (error); 1606 } 1607 1608 /* 1609 * This is one of read routines. 1610 * 1611 * ntnode should be locked. 1612 */ 1613 int 1614 ntfs_readntvattr_plain( 1615 struct ntfsmount * ntmp, 1616 struct ntnode * ip, 1617 struct ntvattr * vap, 1618 off_t roff, 1619 size_t rsize, 1620 void *rdata, 1621 size_t * initp, 1622 struct uio *uio) 1623 { 1624 int error = 0; 1625 off_t off; 1626 1627 *initp = 0; 1628 if (vap->va_flag & NTFS_AF_INRUN) { 1629 int cnt; 1630 cn_t ccn, ccl, cn, left, cl; 1631 void * data = rdata; 1632 struct buf *bp; 1633 size_t tocopy; 1634 1635 ddprintf(("ntfs_readntvattr_plain: data in run: %lu chains\n", 1636 vap->va_vruncnt)); 1637 1638 off = roff; 1639 left = rsize; 1640 ccl = 0; 1641 ccn = 0; 1642 cnt = 0; 1643 while (left && (cnt < vap->va_vruncnt)) { 1644 ccn = vap->va_vruncn[cnt]; 1645 ccl = vap->va_vruncl[cnt]; 1646 1647 ddprintf(("ntfs_readntvattr_plain: " 1648 "left %qu, cn: 0x%qx, cl: %qu, off: %qd\n", 1649 (long long) left, (long long) ccn, 1650 (long long) ccl, (long long) off)); 1651 1652 if (ntfs_cntob(ccl) < off) { 1653 off -= ntfs_cntob(ccl); 1654 cnt++; 1655 continue; 1656 } 1657 if (ccn || ip->i_number == NTFS_BOOTINO) { 1658 ccl -= ntfs_btocn(off); 1659 cn = ccn + ntfs_btocn(off); 1660 off = ntfs_btocnoff(off); 1661 1662 while (left && ccl) { 1663 /* 1664 * Always read single clusters at a 1665 * time - we need to avoid reading 1666 * differently-sized blocks at the 1667 * same disk offsets to avoid 1668 * confusing the buffer cache. 1669 */ 1670 tocopy = MIN(left, 1671 ntfs_cntob(1) - off); 1672 cl = ntfs_btocl(tocopy + off); 1673 KASSERT(cl == 1 && 1674 tocopy <= ntfs_cntob(1)); 1675 1676 ddprintf(("ntfs_readntvattr_plain: " 1677 "read: cn: 0x%qx cl: %qu, " 1678 "off: %qd len: %qu, left: %qu\n", 1679 (long long) cn, 1680 (long long) cl, 1681 (long long) off, 1682 (long long) tocopy, 1683 (long long) left)); 1684 error = bread(ntmp->ntm_devvp, 1685 ntfs_cntobn(cn), 1686 ntfs_cntob(cl), 1687 NOCRED, &bp); 1688 if (error) { 1689 brelse(bp, 0); 1690 return (error); 1691 } 1692 if (uio) { 1693 uiomove((char *)bp->b_data + off, 1694 tocopy, uio); 1695 } else { 1696 memcpy(data, (char *)bp->b_data + off, 1697 tocopy); 1698 } 1699 brelse(bp, 0); 1700 data = (char *)data + tocopy; 1701 *initp += tocopy; 1702 off = 0; 1703 left -= tocopy; 1704 cn += cl; 1705 ccl -= cl; 1706 } 1707 } else { 1708 tocopy = MIN(left, ntfs_cntob(ccl) - off); 1709 ddprintf(("ntfs_readntvattr_plain: " 1710 "hole: ccn: 0x%qx ccl: %qu, off: %qd, " 1711 " len: %qu, left: %qu\n", 1712 (long long) ccn, (long long) ccl, 1713 (long long) off, (long long) tocopy, 1714 (long long) left)); 1715 left -= tocopy; 1716 off = 0; 1717 if (uio) { 1718 char vbuf[] = ""; 1719 size_t remains = tocopy; 1720 for(; remains; remains--) 1721 uiomove(vbuf, 1, uio); 1722 } else 1723 bzero(data, tocopy); 1724 data = (char *)data + tocopy; 1725 } 1726 cnt++; 1727 } 1728 if (left) { 1729 printf("ntfs_readntvattr_plain: POSSIBLE RUN ERROR\n"); 1730 error = E2BIG; 1731 } 1732 } else { 1733 ddprintf(("ntfs_readnvattr_plain: data is in mft record\n")); 1734 if (uio) 1735 uiomove((char *)vap->va_datap + roff, rsize, uio); 1736 else 1737 memcpy(rdata, (char *)vap->va_datap + roff, rsize); 1738 *initp += rsize; 1739 } 1740 1741 return (error); 1742 } 1743 1744 /* 1745 * This is one of read routines. 1746 */ 1747 int 1748 ntfs_readattr_plain( 1749 struct ntfsmount * ntmp, 1750 struct ntnode * ip, 1751 u_int32_t attrnum, 1752 const char *attrname, 1753 off_t roff, 1754 size_t rsize, 1755 void *rdata, 1756 size_t * initp, 1757 struct uio *uio) 1758 { 1759 size_t init; 1760 int error = 0; 1761 off_t off = roff, left = rsize, toread; 1762 void * data = rdata; 1763 struct ntvattr *vap; 1764 *initp = 0; 1765 1766 while (left) { 1767 error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname, 1768 ntfs_btocn(off), &vap); 1769 if (error) 1770 return (error); 1771 toread = MIN(left, ntfs_cntob(vap->va_vcnend + 1) - off); 1772 ddprintf(("ntfs_readattr_plain: o: %qd, s: %qd (%qu - %qu)\n", 1773 (long long) off, (long long) toread, 1774 (long long) vap->va_vcnstart, 1775 (long long) vap->va_vcnend)); 1776 error = ntfs_readntvattr_plain(ntmp, ip, vap, 1777 off - ntfs_cntob(vap->va_vcnstart), 1778 toread, data, &init, uio); 1779 if (error) { 1780 printf("ntfs_readattr_plain: " 1781 "ntfs_readntvattr_plain failed: o: %qd, s: %qd\n", 1782 (long long) off, (long long) toread); 1783 printf("ntfs_readattr_plain: attrib: %qu - %qu\n", 1784 (long long) vap->va_vcnstart, 1785 (long long) vap->va_vcnend); 1786 ntfs_ntvattrrele(vap); 1787 break; 1788 } 1789 ntfs_ntvattrrele(vap); 1790 left -= toread; 1791 off += toread; 1792 data = (char *)data + toread; 1793 *initp += init; 1794 } 1795 1796 return (error); 1797 } 1798 1799 /* 1800 * This is one of read routines. 1801 */ 1802 int 1803 ntfs_readattr( 1804 struct ntfsmount * ntmp, 1805 struct ntnode * ip, 1806 u_int32_t attrnum, 1807 const char *attrname, 1808 off_t roff, 1809 size_t rsize, 1810 void *rdata, 1811 struct uio *uio) 1812 { 1813 int error = 0; 1814 struct ntvattr *vap; 1815 size_t init; 1816 1817 ddprintf(("ntfs_readattr: reading %llu: 0x%x, from %qd size %qu" 1818 " bytes\n", (unsigned long long)ip->i_number, attrnum, 1819 (long long)roff, (long long)rsize)); 1820 1821 error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname, 0, &vap); 1822 if (error) 1823 return (error); 1824 1825 if ((roff > vap->va_datalen) || 1826 (roff + rsize > vap->va_datalen)) { 1827 printf("ntfs_readattr: offset too big: %qd (%qd) > %qu\n", 1828 (long long) roff, (long long) (roff + rsize), 1829 (long long) vap->va_datalen); 1830 ntfs_ntvattrrele(vap); 1831 return (E2BIG); 1832 } 1833 if (vap->va_compression && vap->va_compressalg) { 1834 u_int8_t *cup; 1835 u_int8_t *uup; 1836 off_t off = roff, left = rsize, tocopy; 1837 void * data = rdata; 1838 cn_t cn; 1839 1840 ddprintf(("ntfs_ntreadattr: compression: %d\n", 1841 vap->va_compressalg)); 1842 1843 cup = malloc(ntfs_cntob(NTFS_COMPUNIT_CL), 1844 M_NTFSDECOMP, M_WAITOK); 1845 uup = malloc(ntfs_cntob(NTFS_COMPUNIT_CL), 1846 M_NTFSDECOMP, M_WAITOK); 1847 1848 cn = (ntfs_btocn(roff)) & (~(NTFS_COMPUNIT_CL - 1)); 1849 off = roff - ntfs_cntob(cn); 1850 1851 while (left) { 1852 error = ntfs_readattr_plain(ntmp, ip, attrnum, 1853 attrname, ntfs_cntob(cn), 1854 ntfs_cntob(NTFS_COMPUNIT_CL), 1855 cup, &init, NULL); 1856 if (error) 1857 break; 1858 1859 tocopy = MIN(left, ntfs_cntob(NTFS_COMPUNIT_CL) - off); 1860 1861 if (init == ntfs_cntob(NTFS_COMPUNIT_CL)) { 1862 if (uio) 1863 uiomove(cup + off, tocopy, uio); 1864 else 1865 memcpy(data, cup + off, tocopy); 1866 } else if (init == 0) { 1867 if (uio) { 1868 char vbuf[] = ""; 1869 size_t remains = tocopy; 1870 for(; remains; remains--) 1871 uiomove(vbuf, 1, uio); 1872 } 1873 else 1874 bzero(data, tocopy); 1875 } else { 1876 error = ntfs_uncompunit(ntmp, uup, cup); 1877 if (error) 1878 break; 1879 if (uio) 1880 uiomove(uup + off, tocopy, uio); 1881 else 1882 memcpy(data, uup + off, tocopy); 1883 } 1884 1885 left -= tocopy; 1886 data = (char *)data + tocopy; 1887 off += tocopy - ntfs_cntob(NTFS_COMPUNIT_CL); 1888 cn += NTFS_COMPUNIT_CL; 1889 } 1890 1891 FREE(uup, M_NTFSDECOMP); 1892 FREE(cup, M_NTFSDECOMP); 1893 } else 1894 error = ntfs_readattr_plain(ntmp, ip, attrnum, attrname, 1895 roff, rsize, rdata, &init, uio); 1896 ntfs_ntvattrrele(vap); 1897 return (error); 1898 } 1899 1900 #if UNUSED_CODE 1901 int 1902 ntfs_parserun( 1903 cn_t * cn, 1904 cn_t * cl, 1905 u_int8_t * run, 1906 u_long len, 1907 u_long *off) 1908 { 1909 u_int8_t sz; 1910 int i; 1911 1912 if (NULL == run) { 1913 printf("ntfs_parsetun: run == NULL\n"); 1914 return (EINVAL); 1915 } 1916 sz = run[(*off)++]; 1917 if (0 == sz) { 1918 printf("ntfs_parserun: trying to go out of run\n"); 1919 return (E2BIG); 1920 } 1921 *cl = 0; 1922 if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) { 1923 printf("ntfs_parserun: " 1924 "bad run: length too big: sz: 0x%02x (%ld < %ld + sz)\n", 1925 sz, len, *off); 1926 return (EINVAL); 1927 } 1928 for (i = 0; i < (sz & 0xF); i++) 1929 *cl += (u_int32_t) run[(*off)++] << (i << 3); 1930 1931 sz >>= 4; 1932 if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) { 1933 printf("ntfs_parserun: " 1934 "bad run: length too big: sz: 0x%02x (%ld < %ld + sz)\n", 1935 sz, len, *off); 1936 return (EINVAL); 1937 } 1938 for (i = 0; i < (sz & 0xF); i++) 1939 *cn += (u_int32_t) run[(*off)++] << (i << 3); 1940 1941 return (0); 1942 } 1943 #endif 1944 1945 /* 1946 * Process fixup routine on given buffer. 1947 */ 1948 int 1949 ntfs_procfixups( 1950 struct ntfsmount * ntmp, 1951 u_int32_t magic, 1952 void *xbufv, 1953 size_t len) 1954 { 1955 char *xbuf = xbufv; 1956 struct fixuphdr *fhp = (struct fixuphdr *) xbuf; 1957 int i; 1958 u_int16_t fixup; 1959 u_int16_t *fxp; 1960 u_int16_t *cfxp; 1961 1962 if (fhp->fh_magic != magic) { 1963 printf("ntfs_procfixups: magic doesn't match: %08x != %08x\n", 1964 fhp->fh_magic, magic); 1965 return (EINVAL); 1966 } 1967 if ((fhp->fh_fnum - 1) * ntmp->ntm_bps != len) { 1968 printf("ntfs_procfixups: " 1969 "bad fixups number: %d for %ld bytes block\n", 1970 fhp->fh_fnum, (long)len); /* XXX printf kludge */ 1971 return (EINVAL); 1972 } 1973 if (fhp->fh_foff >= ntmp->ntm_spc * ntmp->ntm_mftrecsz * ntmp->ntm_bps) { 1974 printf("ntfs_procfixups: invalid offset: %x", fhp->fh_foff); 1975 return (EINVAL); 1976 } 1977 fxp = (u_int16_t *) (xbuf + fhp->fh_foff); 1978 cfxp = (u_int16_t *) (xbuf + ntmp->ntm_bps - 2); 1979 fixup = *fxp++; 1980 for (i = 1; i < fhp->fh_fnum; i++, fxp++) { 1981 if (*cfxp != fixup) { 1982 printf("ntfs_procfixups: fixup %d doesn't match\n", i); 1983 return (EINVAL); 1984 } 1985 *cfxp = *fxp; 1986 cfxp = (u_int16_t *)((char *)cfxp + ntmp->ntm_bps); 1987 } 1988 return (0); 1989 } 1990 1991 #if UNUSED_CODE 1992 int 1993 ntfs_runtocn( 1994 cn_t * cn, 1995 struct ntfsmount * ntmp, 1996 u_int8_t * run, 1997 u_long len, 1998 cn_t vcn) 1999 { 2000 cn_t ccn = 0; 2001 cn_t ccl = 0; 2002 u_long off = 0; 2003 int error = 0; 2004 2005 #ifdef NTFS_DEBUG 2006 int i; 2007 printf("ntfs_runtocn: run: %p, %ld bytes, vcn:%ld\n", 2008 run, len, (u_long) vcn); 2009 printf("ntfs_runtocn: run: "); 2010 for (i = 0; i < len; i++) 2011 printf("0x%02x ", run[i]); 2012 printf("\n"); 2013 #endif 2014 2015 if (NULL == run) { 2016 printf("ntfs_runtocn: run == NULL\n"); 2017 return (EINVAL); 2018 } 2019 do { 2020 if (run[off] == 0) { 2021 printf("ntfs_runtocn: vcn too big\n"); 2022 return (E2BIG); 2023 } 2024 vcn -= ccl; 2025 error = ntfs_parserun(&ccn, &ccl, run, len, &off); 2026 if (error) { 2027 printf("ntfs_runtocn: ntfs_parserun failed\n"); 2028 return (error); 2029 } 2030 } while (ccl <= vcn); 2031 *cn = ccn + vcn; 2032 return (0); 2033 } 2034 #endif 2035 2036 /* 2037 * this initializes toupper table & dependant variables to be ready for 2038 * later work 2039 */ 2040 void 2041 ntfs_toupper_init() 2042 { 2043 ntfs_toupper_tab = (wchar *) NULL; 2044 mutex_init(&ntfs_toupper_lock, MUTEX_DEFAULT, IPL_NONE); 2045 ntfs_toupper_usecount = 0; 2046 } 2047 2048 /* 2049 * if the ntfs_toupper_tab[] is filled already, just raise use count; 2050 * otherwise read the data from the filesystem we are currently mounting 2051 */ 2052 int 2053 ntfs_toupper_use(mp, ntmp) 2054 struct mount *mp; 2055 struct ntfsmount *ntmp; 2056 { 2057 int error = 0; 2058 struct vnode *vp; 2059 2060 /* get exclusive access */ 2061 mutex_enter(&ntfs_toupper_lock); 2062 2063 /* only read the translation data from a file if it hasn't been 2064 * read already */ 2065 if (ntfs_toupper_tab) 2066 goto out; 2067 2068 /* 2069 * Read in Unicode lowercase -> uppercase translation file. 2070 * XXX for now, just the first 256 entries are used anyway, 2071 * so don't bother reading more 2072 */ 2073 MALLOC(ntfs_toupper_tab, wchar *, 256 * 256 * sizeof(wchar), 2074 M_NTFSRDATA, M_WAITOK); 2075 2076 if ((error = VFS_VGET(mp, NTFS_UPCASEINO, &vp))) 2077 goto out; 2078 error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL, 2079 0, 256*256*sizeof(wchar), (char *) ntfs_toupper_tab, 2080 NULL); 2081 vput(vp); 2082 2083 out: 2084 ntfs_toupper_usecount++; 2085 mutex_exit(&ntfs_toupper_lock); 2086 return (error); 2087 } 2088 2089 /* 2090 * lower the use count and if it reaches zero, free the memory 2091 * tied by toupper table 2092 */ 2093 void 2094 ntfs_toupper_unuse() 2095 { 2096 /* get exclusive access */ 2097 mutex_enter(&ntfs_toupper_lock); 2098 2099 ntfs_toupper_usecount--; 2100 if (ntfs_toupper_usecount == 0) { 2101 FREE(ntfs_toupper_tab, M_NTFSRDATA); 2102 ntfs_toupper_tab = NULL; 2103 } 2104 #ifdef DIAGNOSTIC 2105 else if (ntfs_toupper_usecount < 0) { 2106 panic("ntfs_toupper_unuse(): use count negative: %d", 2107 ntfs_toupper_usecount); 2108 } 2109 #endif 2110 2111 /* release the lock */ 2112 mutex_exit(&ntfs_toupper_lock); 2113 } 2114