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