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