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