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