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