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