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