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