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