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