1 /* $NetBSD: ntfs_subr.c,v 1.44 2010/01/08 11:35:08 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.44 2010/01/08 11:35:08 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(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 uvm_vnp_setsize(nvp, iep->ie_fsize); 1040 } else { 1041 error = ntfs_filesize(ntmp, nfp, 1042 &nfp->f_size, &nfp->f_allocated); 1043 if (error) { 1044 vput(nvp); 1045 goto fail; 1046 } 1047 uvm_vnp_setsize(nvp, nfp->f_size); 1048 } 1049 1050 nfp->f_flag &= ~FN_VALID; 1051 *vpp = nvp; 1052 goto fail; 1053 } 1054 1055 /* Dive if possible */ 1056 if (iep->ie_flag & NTFS_IEFLAG_SUBNODE) { 1057 dprintf(("ntfs_ntlookupfile: diving\n")); 1058 1059 cn = *(cn_t *) ((char *)rdbuf + aoff + 1060 iep->reclen - sizeof(cn_t)); 1061 rdsize = blsize; 1062 1063 error = ntfs_readattr(ntmp, ip, NTFS_A_INDX, "$I30", 1064 ntfs_cntob(cn), rdsize, rdbuf, NULL); 1065 if (error) 1066 goto fail; 1067 1068 error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC, 1069 rdbuf, rdsize); 1070 if (error) 1071 goto fail; 1072 1073 aoff = (((struct attr_indexalloc *) rdbuf)->ia_hdrsize + 1074 0x18); 1075 } else if (fullscan && lookup_ctx) { 1076 cn = lookup_ctx->cn; 1077 aoff = lookup_ctx->aoff; 1078 rdsize = lookup_ctx->rdsize; 1079 1080 error = ntfs_readattr(ntmp, ip, 1081 (cn == 0) ? NTFS_A_INDXROOT : NTFS_A_INDX, 1082 "$I30", ntfs_cntob(cn), rdsize, rdbuf, NULL); 1083 if (error) 1084 goto fail; 1085 1086 if (cn != 0) { 1087 error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC, 1088 rdbuf, rdsize); 1089 if (error) 1090 goto fail; 1091 } 1092 1093 tctx = lookup_ctx; 1094 lookup_ctx = lookup_ctx->prev; 1095 free(tctx, M_TEMP); 1096 } else { 1097 dprintf(("ntfs_ntlookupfile: nowhere to dive :-(\n")); 1098 error = ENOENT; 1099 break; 1100 } 1101 } while (1); 1102 1103 /* perform full scan if no entry was found */ 1104 if (!fullscan && error == ENOENT) { 1105 fullscan = 1; 1106 cn = 0; /* need zero, used by lookup_ctx */ 1107 1108 ddprintf(("ntfs_ntlookupfile: fullscan performed for: %.*s\n", 1109 (int) fnamelen, fname)); 1110 goto loop; 1111 } 1112 1113 dprintf(("finish\n")); 1114 1115 fail: 1116 if (attrname) 1117 free(attrname, M_TEMP); 1118 if (lookup_ctx) { 1119 while(lookup_ctx) { 1120 tctx = lookup_ctx; 1121 lookup_ctx = lookup_ctx->prev; 1122 free(tctx, M_TEMP); 1123 } 1124 } 1125 ntfs_ntvattrrele(vap); 1126 ntfs_ntput(ip); 1127 free(rdbuf, M_TEMP); 1128 return (error); 1129 } 1130 1131 /* 1132 * Check if name type is permitted to show. 1133 */ 1134 int 1135 ntfs_isnamepermitted( 1136 struct ntfsmount * ntmp, 1137 struct attr_indexentry * iep) 1138 { 1139 if (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES) 1140 return 1; 1141 1142 switch (iep->ie_fnametype) { 1143 case 2: 1144 ddprintf(("ntfs_isnamepermitted: skipped DOS name\n")); 1145 return 0; 1146 case 0: case 1: case 3: 1147 return 1; 1148 default: 1149 printf("ntfs_isnamepermitted: " 1150 "WARNING! Unknown file name type: %d\n", 1151 iep->ie_fnametype); 1152 break; 1153 } 1154 return 0; 1155 } 1156 1157 /* 1158 * Read ntfs dir like stream of attr_indexentry, not like btree of them. 1159 * This is done by scanning $BITMAP:$I30 for busy clusters and reading them. 1160 * Of course $INDEX_ROOT:$I30 is read before. Last read values are stored in 1161 * fnode, so we can skip toward record number num almost immediately. 1162 * Anyway this is rather slow routine. The problem is that we don't know 1163 * how many records are there in $INDEX_ALLOCATION:$I30 block. 1164 */ 1165 int 1166 ntfs_ntreaddir( 1167 struct ntfsmount * ntmp, 1168 struct fnode * fp, 1169 u_int32_t num, 1170 struct attr_indexentry ** riepp) 1171 { 1172 struct ntnode *ip = FTONT(fp); 1173 struct ntvattr *vap = NULL; /* IndexRoot attribute */ 1174 struct ntvattr *bmvap = NULL; /* BitMap attribute */ 1175 struct ntvattr *iavap = NULL; /* IndexAllocation attribute */ 1176 void * rdbuf; /* Buffer to read directory's blocks */ 1177 u_char *bmp = NULL; /* Bitmap */ 1178 u_int32_t blsize; /* Index allocation size (2048) */ 1179 u_int32_t rdsize; /* Length of data to read */ 1180 u_int32_t attrnum; /* Current attribute type */ 1181 u_int32_t cpbl = 1; /* Clusters per directory block */ 1182 u_int32_t blnum; 1183 struct attr_indexentry *iep; 1184 int error = ENOENT; 1185 u_int32_t aoff, cnum; 1186 1187 dprintf(("ntfs_ntreaddir: read ino: %llu, num: %d\n", 1188 (unsigned long long)ip->i_number, num)); 1189 error = ntfs_ntget(ip); 1190 if (error) 1191 return (error); 1192 1193 error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXROOT, "$I30", 0, &vap); 1194 if (error) 1195 return (ENOTDIR); 1196 1197 if (fp->f_dirblbuf == NULL) { 1198 fp->f_dirblsz = vap->va_a_iroot->ir_size; 1199 fp->f_dirblbuf = (void *) malloc( 1200 MAX(vap->va_datalen,fp->f_dirblsz), M_NTFSDIR, M_WAITOK); 1201 } 1202 1203 blsize = fp->f_dirblsz; 1204 rdbuf = fp->f_dirblbuf; 1205 1206 dprintf(("ntfs_ntreaddir: rdbuf: %p, blsize: %d\n", rdbuf, blsize)); 1207 1208 if (vap->va_a_iroot->ir_flag & NTFS_IRFLAG_INDXALLOC) { 1209 error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXBITMAP, "$I30", 1210 0, &bmvap); 1211 if (error) { 1212 error = ENOTDIR; 1213 goto fail; 1214 } 1215 bmp = (u_char *) malloc(bmvap->va_datalen, M_TEMP, M_WAITOK); 1216 error = ntfs_readattr(ntmp, ip, NTFS_A_INDXBITMAP, "$I30", 0, 1217 bmvap->va_datalen, bmp, NULL); 1218 if (error) 1219 goto fail; 1220 1221 error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDX, "$I30", 1222 0, &iavap); 1223 if (error) { 1224 error = ENOTDIR; 1225 goto fail; 1226 } 1227 cpbl = ntfs_btocn(blsize + ntfs_cntob(1) - 1); 1228 dprintf(("ntfs_ntreaddir: indexalloc: %qu, cpbl: %d\n", 1229 (long long)iavap->va_datalen, cpbl)); 1230 } else { 1231 dprintf(("ntfs_ntreadidir: w/o BitMap and IndexAllocation\n")); 1232 iavap = bmvap = NULL; 1233 bmp = NULL; 1234 } 1235 1236 /* Try use previous values */ 1237 if ((fp->f_lastdnum < num) && (fp->f_lastdnum != 0)) { 1238 attrnum = fp->f_lastdattr; 1239 aoff = fp->f_lastdoff; 1240 blnum = fp->f_lastdblnum; 1241 cnum = fp->f_lastdnum; 1242 } else { 1243 attrnum = NTFS_A_INDXROOT; 1244 aoff = sizeof(struct attr_indexroot); 1245 blnum = 0; 1246 cnum = 0; 1247 } 1248 1249 do { 1250 dprintf(("ntfs_ntreaddir: scan: 0x%x, %d, %d, %d, %d\n", 1251 attrnum, (u_int32_t) blnum, cnum, num, aoff)); 1252 rdsize = (attrnum == NTFS_A_INDXROOT) ? vap->va_datalen : blsize; 1253 error = ntfs_readattr(ntmp, ip, attrnum, "$I30", 1254 ntfs_cntob(blnum * cpbl), rdsize, rdbuf, NULL); 1255 if (error) 1256 goto fail; 1257 1258 if (attrnum == NTFS_A_INDX) { 1259 error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC, 1260 rdbuf, rdsize); 1261 if (error) 1262 goto fail; 1263 } 1264 if (aoff == 0) 1265 aoff = (attrnum == NTFS_A_INDX) ? 1266 (0x18 + ((struct attr_indexalloc *) rdbuf)->ia_hdrsize) : 1267 sizeof(struct attr_indexroot); 1268 1269 iep = (struct attr_indexentry *) ((char *)rdbuf + aoff); 1270 for (; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (rdsize > aoff); 1271 aoff += iep->reclen, 1272 iep = (struct attr_indexentry *) ((char *)rdbuf + aoff)) 1273 { 1274 if (!ntfs_isnamepermitted(ntmp, iep)) continue; 1275 1276 if (cnum >= num) { 1277 fp->f_lastdnum = cnum; 1278 fp->f_lastdoff = aoff; 1279 fp->f_lastdblnum = blnum; 1280 fp->f_lastdattr = attrnum; 1281 1282 *riepp = iep; 1283 1284 error = 0; 1285 goto fail; 1286 } 1287 cnum++; 1288 } 1289 1290 if (iavap) { 1291 if (attrnum == NTFS_A_INDXROOT) 1292 blnum = 0; 1293 else 1294 blnum++; 1295 1296 while (ntfs_cntob(blnum * cpbl) < iavap->va_datalen) { 1297 if (bmp[blnum >> 3] & (1 << (blnum & 3))) 1298 break; 1299 blnum++; 1300 } 1301 1302 attrnum = NTFS_A_INDX; 1303 aoff = 0; 1304 if (ntfs_cntob(blnum * cpbl) >= iavap->va_datalen) 1305 break; 1306 dprintf(("ntfs_ntreaddir: blnum: %d\n", (u_int32_t) blnum)); 1307 } 1308 } while (iavap); 1309 1310 *riepp = NULL; 1311 fp->f_lastdnum = 0; 1312 1313 fail: 1314 if (vap) 1315 ntfs_ntvattrrele(vap); 1316 if (bmvap) 1317 ntfs_ntvattrrele(bmvap); 1318 if (iavap) 1319 ntfs_ntvattrrele(iavap); 1320 if (bmp) 1321 free(bmp, M_TEMP); 1322 ntfs_ntput(ip); 1323 return (error); 1324 } 1325 1326 /* 1327 * Convert NTFS times that are in 100 ns units and begins from 1328 * 1601 Jan 1 into unix times. 1329 */ 1330 struct timespec 1331 ntfs_nttimetounix( 1332 u_int64_t nt) 1333 { 1334 struct timespec t; 1335 1336 /* WindowNT times are in 100 ns and from 1601 Jan 1 */ 1337 t.tv_nsec = (nt % (1000 * 1000 * 10)) * 100; 1338 t.tv_sec = nt / (1000 * 1000 * 10) - 1339 369LL * 365LL * 24LL * 60LL * 60LL - 1340 89LL * 1LL * 24LL * 60LL * 60LL; 1341 return (t); 1342 } 1343 1344 /* 1345 * Get file times from NTFS_A_NAME attribute. 1346 */ 1347 int 1348 ntfs_times( 1349 struct ntfsmount * ntmp, 1350 struct ntnode * ip, 1351 ntfs_times_t * tm) 1352 { 1353 struct ntvattr *vap; 1354 int error; 1355 1356 dprintf(("ntfs_times: ino: %llu...\n", 1357 (unsigned long long)ip->i_number)); 1358 1359 error = ntfs_ntget(ip); 1360 if (error) 1361 return (error); 1362 1363 error = ntfs_ntvattrget(ntmp, ip, NTFS_A_NAME, NULL, 0, &vap); 1364 if (error) { 1365 ntfs_ntput(ip); 1366 return (error); 1367 } 1368 *tm = vap->va_a_name->n_times; 1369 ntfs_ntvattrrele(vap); 1370 ntfs_ntput(ip); 1371 1372 return (0); 1373 } 1374 1375 /* 1376 * Get file sizes from corresponding attribute. 1377 * 1378 * ntnode under fnode should be locked. 1379 */ 1380 int 1381 ntfs_filesize( 1382 struct ntfsmount * ntmp, 1383 struct fnode * fp, 1384 u_int64_t * size, 1385 u_int64_t * bytes) 1386 { 1387 struct ntvattr *vap; 1388 struct ntnode *ip = FTONT(fp); 1389 u_int64_t sz, bn; 1390 int error; 1391 1392 dprintf(("ntfs_filesize: ino: %llu\n", 1393 (unsigned long long)ip->i_number)); 1394 1395 error = ntfs_ntvattrget(ntmp, ip, 1396 fp->f_attrtype, fp->f_attrname, 0, &vap); 1397 if (error) 1398 return (error); 1399 1400 bn = vap->va_allocated; 1401 sz = vap->va_datalen; 1402 1403 dprintf(("ntfs_filesize: %d bytes (%d bytes allocated)\n", 1404 (u_int32_t) sz, (u_int32_t) bn)); 1405 1406 if (size) 1407 *size = sz; 1408 if (bytes) 1409 *bytes = bn; 1410 1411 ntfs_ntvattrrele(vap); 1412 1413 return (0); 1414 } 1415 1416 /* 1417 * This is one of write routine. 1418 */ 1419 int 1420 ntfs_writeattr_plain( 1421 struct ntfsmount * ntmp, 1422 struct ntnode * ip, 1423 u_int32_t attrnum, 1424 char *attrname, 1425 off_t roff, 1426 size_t rsize, 1427 void *rdata, 1428 size_t * initp, 1429 struct uio *uio) 1430 { 1431 size_t init; 1432 int error = 0; 1433 off_t off = roff, left = rsize, towrite; 1434 void * data = rdata; 1435 struct ntvattr *vap; 1436 *initp = 0; 1437 1438 while (left) { 1439 error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname, 1440 ntfs_btocn(off), &vap); 1441 if (error) 1442 return (error); 1443 towrite = MIN(left, ntfs_cntob(vap->va_vcnend + 1) - off); 1444 ddprintf(("ntfs_writeattr_plain: o: %qd, s: %qd (%qu - %qu)\n", 1445 (long long) off, (long long) towrite, 1446 (long long) vap->va_vcnstart, 1447 (long long) vap->va_vcnend)); 1448 error = ntfs_writentvattr_plain(ntmp, ip, vap, 1449 off - ntfs_cntob(vap->va_vcnstart), 1450 towrite, data, &init, uio); 1451 if (error) { 1452 dprintf(("ntfs_writeattr_plain: " 1453 "ntfs_writentvattr_plain failed: o: %qd, s: %qd\n", 1454 (long long) off, (long long) towrite)); 1455 dprintf(("ntfs_writeattr_plain: attrib: %qu - %qu\n", 1456 (long long) vap->va_vcnstart, 1457 (long long) vap->va_vcnend)); 1458 ntfs_ntvattrrele(vap); 1459 break; 1460 } 1461 ntfs_ntvattrrele(vap); 1462 left -= towrite; 1463 off += towrite; 1464 data = (char *)data + towrite; 1465 *initp += init; 1466 } 1467 1468 return (error); 1469 } 1470 1471 /* 1472 * This is one of write routine. 1473 * 1474 * ntnode should be locked. 1475 */ 1476 int 1477 ntfs_writentvattr_plain( 1478 struct ntfsmount * ntmp, 1479 struct ntnode * ip, 1480 struct ntvattr * vap, 1481 off_t roff, 1482 size_t rsize, 1483 void *rdata, 1484 size_t * initp, 1485 struct uio *uio) 1486 { 1487 int error = 0; 1488 off_t off; 1489 int cnt; 1490 cn_t ccn, ccl, cn, left, cl; 1491 void * data = rdata; 1492 daddr_t lbn; 1493 struct buf *bp; 1494 size_t tocopy; 1495 1496 *initp = 0; 1497 1498 if ((vap->va_flag & NTFS_AF_INRUN) == 0) { 1499 dprintf(("ntfs_writevattr_plain: CAN'T WRITE RES. ATTRIBUTE\n")); 1500 return ENOTTY; 1501 } 1502 1503 ddprintf(("ntfs_writentvattr_plain: data in run: %lu chains\n", 1504 vap->va_vruncnt)); 1505 1506 off = roff; 1507 left = rsize; 1508 ccl = 0; 1509 ccn = 0; 1510 cnt = 0; 1511 for (; left && (cnt < vap->va_vruncnt); cnt++) { 1512 ccn = vap->va_vruncn[cnt]; 1513 ccl = vap->va_vruncl[cnt]; 1514 1515 ddprintf(("ntfs_writentvattr_plain: " 1516 "left %qu, cn: 0x%qx, cl: %qu, off: %qd\n", 1517 (long long) left, (long long) ccn, 1518 (long long) ccl, (long long) off)); 1519 1520 if (ntfs_cntob(ccl) < off) { 1521 off -= ntfs_cntob(ccl); 1522 cnt++; 1523 continue; 1524 } 1525 if (!ccn && ip->i_number != NTFS_BOOTINO) 1526 continue; /* XXX */ 1527 1528 ccl -= ntfs_btocn(off); 1529 cn = ccn + ntfs_btocn(off); 1530 off = ntfs_btocnoff(off); 1531 1532 while (left && ccl) { 1533 /* 1534 * Always read and write single clusters at a time - 1535 * we need to avoid requesting differently-sized 1536 * blocks at the same disk offsets to avoid 1537 * confusing the buffer cache. 1538 */ 1539 tocopy = MIN(left, ntfs_cntob(1) - off); 1540 cl = ntfs_btocl(tocopy + off); 1541 KASSERT(cl == 1 && tocopy <= ntfs_cntob(1)); 1542 ddprintf(("ntfs_writentvattr_plain: write: " 1543 "cn: 0x%qx cl: %qu, off: %qd len: %qu, left: %qu\n", 1544 (long long) cn, (long long) cl, 1545 (long long) off, (long long) tocopy, 1546 (long long) left)); 1547 if ((off == 0) && (tocopy == ntfs_cntob(cl))) 1548 { 1549 lbn = ntfs_cntobn(cn); 1550 bp = getblk(ntmp->ntm_devvp, lbn, 1551 ntfs_cntob(cl), 0, 0); 1552 clrbuf(bp); 1553 } else { 1554 error = bread(ntmp->ntm_devvp, ntfs_cntobn(cn), 1555 ntfs_cntob(cl), NOCRED, B_MODIFY, &bp); 1556 if (error) { 1557 brelse(bp, 0); 1558 return (error); 1559 } 1560 } 1561 if (uio) 1562 uiomove((char *)bp->b_data + off, tocopy, uio); 1563 else 1564 memcpy((char *)bp->b_data + off, data, tocopy); 1565 bawrite(bp); 1566 data = (char *)data + tocopy; 1567 *initp += tocopy; 1568 off = 0; 1569 left -= tocopy; 1570 cn += cl; 1571 ccl -= cl; 1572 } 1573 } 1574 1575 if (left) { 1576 printf("ntfs_writentvattr_plain: POSSIBLE RUN ERROR\n"); 1577 error = EINVAL; 1578 } 1579 1580 return (error); 1581 } 1582 1583 /* 1584 * This is one of read routines. 1585 * 1586 * ntnode should be locked. 1587 */ 1588 int 1589 ntfs_readntvattr_plain( 1590 struct ntfsmount * ntmp, 1591 struct ntnode * ip, 1592 struct ntvattr * vap, 1593 off_t roff, 1594 size_t rsize, 1595 void *rdata, 1596 size_t * initp, 1597 struct uio *uio) 1598 { 1599 int error = 0; 1600 off_t off; 1601 1602 *initp = 0; 1603 if (vap->va_flag & NTFS_AF_INRUN) { 1604 int cnt; 1605 cn_t ccn, ccl, cn, left, cl; 1606 void * data = rdata; 1607 struct buf *bp; 1608 size_t tocopy; 1609 1610 ddprintf(("ntfs_readntvattr_plain: data in run: %lu chains\n", 1611 vap->va_vruncnt)); 1612 1613 off = roff; 1614 left = rsize; 1615 ccl = 0; 1616 ccn = 0; 1617 cnt = 0; 1618 while (left && (cnt < vap->va_vruncnt)) { 1619 ccn = vap->va_vruncn[cnt]; 1620 ccl = vap->va_vruncl[cnt]; 1621 1622 ddprintf(("ntfs_readntvattr_plain: " 1623 "left %qu, cn: 0x%qx, cl: %qu, off: %qd\n", 1624 (long long) left, (long long) ccn, 1625 (long long) ccl, (long long) off)); 1626 1627 if (ntfs_cntob(ccl) < off) { 1628 off -= ntfs_cntob(ccl); 1629 cnt++; 1630 continue; 1631 } 1632 if (ccn || ip->i_number == NTFS_BOOTINO) { 1633 ccl -= ntfs_btocn(off); 1634 cn = ccn + ntfs_btocn(off); 1635 off = ntfs_btocnoff(off); 1636 1637 while (left && ccl) { 1638 /* 1639 * Always read single clusters at a 1640 * time - we need to avoid reading 1641 * differently-sized blocks at the 1642 * same disk offsets to avoid 1643 * confusing the buffer cache. 1644 */ 1645 tocopy = MIN(left, 1646 ntfs_cntob(1) - off); 1647 cl = ntfs_btocl(tocopy + off); 1648 KASSERT(cl == 1 && 1649 tocopy <= ntfs_cntob(1)); 1650 1651 ddprintf(("ntfs_readntvattr_plain: " 1652 "read: cn: 0x%qx cl: %qu, " 1653 "off: %qd len: %qu, left: %qu\n", 1654 (long long) cn, 1655 (long long) cl, 1656 (long long) off, 1657 (long long) tocopy, 1658 (long long) left)); 1659 error = bread(ntmp->ntm_devvp, 1660 ntfs_cntobn(cn), 1661 ntfs_cntob(cl), 1662 NOCRED, 0, &bp); 1663 if (error) { 1664 brelse(bp, 0); 1665 return (error); 1666 } 1667 if (uio) { 1668 uiomove((char *)bp->b_data + off, 1669 tocopy, uio); 1670 } else { 1671 memcpy(data, (char *)bp->b_data + off, 1672 tocopy); 1673 } 1674 brelse(bp, 0); 1675 data = (char *)data + tocopy; 1676 *initp += tocopy; 1677 off = 0; 1678 left -= tocopy; 1679 cn += cl; 1680 ccl -= cl; 1681 } 1682 } else { 1683 tocopy = MIN(left, ntfs_cntob(ccl) - off); 1684 ddprintf(("ntfs_readntvattr_plain: " 1685 "hole: ccn: 0x%qx ccl: %qu, off: %qd, " 1686 " len: %qu, left: %qu\n", 1687 (long long) ccn, (long long) ccl, 1688 (long long) off, (long long) tocopy, 1689 (long long) left)); 1690 left -= tocopy; 1691 off = 0; 1692 if (uio) { 1693 char vbuf[] = ""; 1694 size_t remains = tocopy; 1695 for(; remains; remains--) 1696 uiomove(vbuf, 1, uio); 1697 } else 1698 memset(data, 0, tocopy); 1699 data = (char *)data + tocopy; 1700 } 1701 cnt++; 1702 } 1703 if (left) { 1704 printf("ntfs_readntvattr_plain: POSSIBLE RUN ERROR\n"); 1705 error = E2BIG; 1706 } 1707 } else { 1708 ddprintf(("ntfs_readnvattr_plain: data is in mft record\n")); 1709 if (uio) 1710 uiomove((char *)vap->va_datap + roff, rsize, uio); 1711 else 1712 memcpy(rdata, (char *)vap->va_datap + roff, rsize); 1713 *initp += rsize; 1714 } 1715 1716 return (error); 1717 } 1718 1719 /* 1720 * This is one of read routines. 1721 */ 1722 int 1723 ntfs_readattr_plain( 1724 struct ntfsmount * ntmp, 1725 struct ntnode * ip, 1726 u_int32_t attrnum, 1727 const char *attrname, 1728 off_t roff, 1729 size_t rsize, 1730 void *rdata, 1731 size_t * initp, 1732 struct uio *uio) 1733 { 1734 size_t init; 1735 int error = 0; 1736 off_t off = roff, left = rsize, toread; 1737 void * data = rdata; 1738 struct ntvattr *vap; 1739 *initp = 0; 1740 1741 while (left) { 1742 error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname, 1743 ntfs_btocn(off), &vap); 1744 if (error) 1745 return (error); 1746 toread = MIN(left, ntfs_cntob(vap->va_vcnend + 1) - off); 1747 ddprintf(("ntfs_readattr_plain: o: %qd, s: %qd (%qu - %qu)\n", 1748 (long long) off, (long long) toread, 1749 (long long) vap->va_vcnstart, 1750 (long long) vap->va_vcnend)); 1751 error = ntfs_readntvattr_plain(ntmp, ip, vap, 1752 off - ntfs_cntob(vap->va_vcnstart), 1753 toread, data, &init, uio); 1754 if (error) { 1755 printf("ntfs_readattr_plain: " 1756 "ntfs_readntvattr_plain failed: o: %qd, s: %qd\n", 1757 (long long) off, (long long) toread); 1758 printf("ntfs_readattr_plain: attrib: %qu - %qu\n", 1759 (long long) vap->va_vcnstart, 1760 (long long) vap->va_vcnend); 1761 ntfs_ntvattrrele(vap); 1762 break; 1763 } 1764 ntfs_ntvattrrele(vap); 1765 left -= toread; 1766 off += toread; 1767 data = (char *)data + toread; 1768 *initp += init; 1769 } 1770 1771 return (error); 1772 } 1773 1774 /* 1775 * This is one of read routines. 1776 */ 1777 int 1778 ntfs_readattr( 1779 struct ntfsmount * ntmp, 1780 struct ntnode * ip, 1781 u_int32_t attrnum, 1782 const char *attrname, 1783 off_t roff, 1784 size_t rsize, 1785 void *rdata, 1786 struct uio *uio) 1787 { 1788 int error = 0; 1789 struct ntvattr *vap; 1790 size_t init; 1791 1792 ddprintf(("ntfs_readattr: reading %llu: 0x%x, from %qd size %qu" 1793 " bytes\n", (unsigned long long)ip->i_number, attrnum, 1794 (long long)roff, (long long)rsize)); 1795 1796 error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname, 0, &vap); 1797 if (error) 1798 return (error); 1799 1800 if ((roff > vap->va_datalen) || 1801 (roff + rsize > vap->va_datalen)) { 1802 printf("ntfs_readattr: offset too big: %qd (%qd) > %qu\n", 1803 (long long) roff, (long long) (roff + rsize), 1804 (long long) vap->va_datalen); 1805 ntfs_ntvattrrele(vap); 1806 return (E2BIG); 1807 } 1808 if (vap->va_compression && vap->va_compressalg) { 1809 u_int8_t *cup; 1810 u_int8_t *uup; 1811 off_t off = roff, left = rsize, tocopy; 1812 void * data = rdata; 1813 cn_t cn; 1814 1815 ddprintf(("ntfs_ntreadattr: compression: %d\n", 1816 vap->va_compressalg)); 1817 1818 cup = malloc(ntfs_cntob(NTFS_COMPUNIT_CL), 1819 M_NTFSDECOMP, M_WAITOK); 1820 uup = malloc(ntfs_cntob(NTFS_COMPUNIT_CL), 1821 M_NTFSDECOMP, M_WAITOK); 1822 1823 cn = (ntfs_btocn(roff)) & (~(NTFS_COMPUNIT_CL - 1)); 1824 off = roff - ntfs_cntob(cn); 1825 1826 while (left) { 1827 error = ntfs_readattr_plain(ntmp, ip, attrnum, 1828 attrname, ntfs_cntob(cn), 1829 ntfs_cntob(NTFS_COMPUNIT_CL), 1830 cup, &init, NULL); 1831 if (error) 1832 break; 1833 1834 tocopy = MIN(left, ntfs_cntob(NTFS_COMPUNIT_CL) - off); 1835 1836 if (init == ntfs_cntob(NTFS_COMPUNIT_CL)) { 1837 if (uio) 1838 uiomove(cup + off, tocopy, uio); 1839 else 1840 memcpy(data, cup + off, tocopy); 1841 } else if (init == 0) { 1842 if (uio) { 1843 char vbuf[] = ""; 1844 size_t remains = tocopy; 1845 for(; remains; remains--) 1846 uiomove(vbuf, 1, uio); 1847 } 1848 else 1849 memset(data, 0, tocopy); 1850 } else { 1851 error = ntfs_uncompunit(ntmp, uup, cup); 1852 if (error) 1853 break; 1854 if (uio) 1855 uiomove(uup + off, tocopy, uio); 1856 else 1857 memcpy(data, uup + off, tocopy); 1858 } 1859 1860 left -= tocopy; 1861 data = (char *)data + tocopy; 1862 off += tocopy - ntfs_cntob(NTFS_COMPUNIT_CL); 1863 cn += NTFS_COMPUNIT_CL; 1864 } 1865 1866 free(uup, M_NTFSDECOMP); 1867 free(cup, M_NTFSDECOMP); 1868 } else 1869 error = ntfs_readattr_plain(ntmp, ip, attrnum, attrname, 1870 roff, rsize, rdata, &init, uio); 1871 ntfs_ntvattrrele(vap); 1872 return (error); 1873 } 1874 1875 #if UNUSED_CODE 1876 int 1877 ntfs_parserun( 1878 cn_t * cn, 1879 cn_t * cl, 1880 u_int8_t * run, 1881 u_long len, 1882 u_long *off) 1883 { 1884 u_int8_t sz; 1885 int i; 1886 1887 if (NULL == run) { 1888 printf("ntfs_parsetun: run == NULL\n"); 1889 return (EINVAL); 1890 } 1891 sz = run[(*off)++]; 1892 if (0 == sz) { 1893 printf("ntfs_parserun: trying to go out of run\n"); 1894 return (E2BIG); 1895 } 1896 *cl = 0; 1897 if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) { 1898 printf("ntfs_parserun: " 1899 "bad run: length too big: sz: 0x%02x (%ld < %ld + sz)\n", 1900 sz, len, *off); 1901 return (EINVAL); 1902 } 1903 for (i = 0; i < (sz & 0xF); i++) 1904 *cl += (u_int32_t) run[(*off)++] << (i << 3); 1905 1906 sz >>= 4; 1907 if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) { 1908 printf("ntfs_parserun: " 1909 "bad run: length too big: sz: 0x%02x (%ld < %ld + sz)\n", 1910 sz, len, *off); 1911 return (EINVAL); 1912 } 1913 for (i = 0; i < (sz & 0xF); i++) 1914 *cn += (u_int32_t) run[(*off)++] << (i << 3); 1915 1916 return (0); 1917 } 1918 #endif 1919 1920 /* 1921 * Process fixup routine on given buffer. 1922 */ 1923 int 1924 ntfs_procfixups( 1925 struct ntfsmount * ntmp, 1926 u_int32_t magic, 1927 void *xbufv, 1928 size_t len) 1929 { 1930 char *xbuf = xbufv; 1931 struct fixuphdr *fhp = (struct fixuphdr *) xbuf; 1932 int i; 1933 u_int16_t fixup; 1934 u_int16_t *fxp; 1935 u_int16_t *cfxp; 1936 1937 if (fhp->fh_magic != magic) { 1938 printf("ntfs_procfixups: magic doesn't match: %08x != %08x\n", 1939 fhp->fh_magic, magic); 1940 return (EINVAL); 1941 } 1942 if ((fhp->fh_fnum - 1) * ntmp->ntm_bps != len) { 1943 printf("ntfs_procfixups: " 1944 "bad fixups number: %d for %ld bytes block\n", 1945 fhp->fh_fnum, (long)len); /* XXX printf kludge */ 1946 return (EINVAL); 1947 } 1948 if (fhp->fh_foff >= ntmp->ntm_spc * ntmp->ntm_mftrecsz * ntmp->ntm_bps) { 1949 printf("ntfs_procfixups: invalid offset: %x", fhp->fh_foff); 1950 return (EINVAL); 1951 } 1952 fxp = (u_int16_t *) (xbuf + fhp->fh_foff); 1953 cfxp = (u_int16_t *) (xbuf + ntmp->ntm_bps - 2); 1954 fixup = *fxp++; 1955 for (i = 1; i < fhp->fh_fnum; i++, fxp++) { 1956 if (*cfxp != fixup) { 1957 printf("ntfs_procfixups: fixup %d doesn't match\n", i); 1958 return (EINVAL); 1959 } 1960 *cfxp = *fxp; 1961 cfxp = (u_int16_t *)((char *)cfxp + ntmp->ntm_bps); 1962 } 1963 return (0); 1964 } 1965 1966 #if UNUSED_CODE 1967 int 1968 ntfs_runtocn( 1969 cn_t * cn, 1970 struct ntfsmount * ntmp, 1971 u_int8_t * run, 1972 u_long len, 1973 cn_t vcn) 1974 { 1975 cn_t ccn = 0; 1976 cn_t ccl = 0; 1977 u_long off = 0; 1978 int error = 0; 1979 1980 #ifdef NTFS_DEBUG 1981 int i; 1982 printf("ntfs_runtocn: run: %p, %ld bytes, vcn:%ld\n", 1983 run, len, (u_long) vcn); 1984 printf("ntfs_runtocn: run: "); 1985 for (i = 0; i < len; i++) 1986 printf("0x%02x ", run[i]); 1987 printf("\n"); 1988 #endif 1989 1990 if (NULL == run) { 1991 printf("ntfs_runtocn: run == NULL\n"); 1992 return (EINVAL); 1993 } 1994 do { 1995 if (run[off] == 0) { 1996 printf("ntfs_runtocn: vcn too big\n"); 1997 return (E2BIG); 1998 } 1999 vcn -= ccl; 2000 error = ntfs_parserun(&ccn, &ccl, run, len, &off); 2001 if (error) { 2002 printf("ntfs_runtocn: ntfs_parserun failed\n"); 2003 return (error); 2004 } 2005 } while (ccl <= vcn); 2006 *cn = ccn + vcn; 2007 return (0); 2008 } 2009 #endif 2010 2011 /* 2012 * this initializes toupper table & dependant variables to be ready for 2013 * later work 2014 */ 2015 void 2016 ntfs_toupper_init(void) 2017 { 2018 ntfs_toupper_tab = (wchar *) NULL; 2019 mutex_init(&ntfs_toupper_lock, MUTEX_DEFAULT, IPL_NONE); 2020 ntfs_toupper_usecount = 0; 2021 } 2022 2023 /* 2024 * if the ntfs_toupper_tab[] is filled already, just raise use count; 2025 * otherwise read the data from the filesystem we are currently mounting 2026 */ 2027 int 2028 ntfs_toupper_use(struct mount *mp, struct ntfsmount *ntmp) 2029 { 2030 int error = 0; 2031 struct vnode *vp; 2032 2033 /* get exclusive access */ 2034 mutex_enter(&ntfs_toupper_lock); 2035 2036 /* only read the translation data from a file if it hasn't been 2037 * read already */ 2038 if (ntfs_toupper_tab) 2039 goto out; 2040 2041 /* 2042 * Read in Unicode lowercase -> uppercase translation file. 2043 * XXX for now, just the first 256 entries are used anyway, 2044 * so don't bother reading more 2045 */ 2046 ntfs_toupper_tab = malloc(256 * 256 * sizeof(wchar), 2047 M_NTFSRDATA, M_WAITOK); 2048 2049 if ((error = VFS_VGET(mp, NTFS_UPCASEINO, &vp))) 2050 goto out; 2051 error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL, 2052 0, 256*256*sizeof(wchar), (char *) ntfs_toupper_tab, 2053 NULL); 2054 vput(vp); 2055 2056 out: 2057 ntfs_toupper_usecount++; 2058 mutex_exit(&ntfs_toupper_lock); 2059 return (error); 2060 } 2061 2062 /* 2063 * lower the use count and if it reaches zero, free the memory 2064 * tied by toupper table 2065 */ 2066 void 2067 ntfs_toupper_unuse(void) 2068 { 2069 /* get exclusive access */ 2070 mutex_enter(&ntfs_toupper_lock); 2071 2072 ntfs_toupper_usecount--; 2073 if (ntfs_toupper_usecount == 0) { 2074 free(ntfs_toupper_tab, M_NTFSRDATA); 2075 ntfs_toupper_tab = NULL; 2076 } 2077 #ifdef DIAGNOSTIC 2078 else if (ntfs_toupper_usecount < 0) { 2079 panic("ntfs_toupper_unuse(): use count negative: %d", 2080 ntfs_toupper_usecount); 2081 } 2082 #endif 2083 2084 /* release the lock */ 2085 mutex_exit(&ntfs_toupper_lock); 2086 } 2087