ntfs_subr.c revision 43552
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/systm.h> 31#include <sys/namei.h> 32#include <sys/proc.h> 33#include <sys/kernel.h> 34#include <sys/vnode.h> 35#include <sys/mount.h> 36#include <sys/buf.h> 37#include <sys/file.h> 38#include <sys/malloc.h> 39#include <machine/clock.h> 40 41#include <miscfs/specfs/specdev.h> 42 43/* #define NTFS_DEBUG 1 */ 44#include <ntfs/ntfs.h> 45#include <ntfs/ntfsmount.h> 46#include <ntfs/ntfs_inode.h> 47#include <ntfs/ntfs_subr.h> 48#include <ntfs/ntfs_compr.h> 49 50#if __FreeBSD_version >= 300000 51MALLOC_DEFINE(M_NTFSNTVATTR, "NTFS vattr", "NTFS file attribute information"); 52MALLOC_DEFINE(M_NTFSRDATA, "NTFS res data", "NTFS resident data"); 53MALLOC_DEFINE(M_NTFSRUN, "NTFS vrun", "NTFS vrun storage"); 54MALLOC_DEFINE(M_NTFSDECOMP, "NTFS decomp", "NTFS decompression temporary"); 55#endif 56 57int 58ntfs_ntvattrrele( 59 struct ntvattr * vap) 60{ 61 dprintf(("ntfs_ntvattrrele: ino: %d, type: 0x%x\n", 62 vap->va_ip->i_number, vap->va_type)); 63 64 vrele(NTTOV(vap->va_ip)); 65 66 return (0); 67} 68 69int 70ntfs_ntvattrget( 71 struct ntfsmount * ntmp, 72 struct ntnode * ip, 73 u_int32_t type, 74 char *name, 75 cn_t vcn, 76 struct ntvattr ** vapp) 77{ 78 int error; 79 struct ntvattr *vap; 80 struct ntvattr *lvap = NULL; 81 struct attr_attrlist *aalp; 82 struct attr_attrlist *nextaalp; 83 caddr_t alpool; 84 int len, namelen; 85 86 *vapp = NULL; 87 88 if (name) { 89 dprintf(("ntfs_ntvattrget: " \ 90 "ino: %d, type: 0x%x, name: %s, vcn: %d\n", \ 91 ip->i_number, type, name, (u_int32_t) vcn)); 92 namelen = strlen(name); 93 } else { 94 dprintf(("ntfs_ntvattrget: " \ 95 "ino: %d, type: 0x%x, vcn: %d\n", \ 96 ip->i_number, type, (u_int32_t) vcn)); 97 name = ""; 98 namelen = 0; 99 } 100 101 if((ip->i_flag & IN_LOADED) == 0) { 102 dprintf(("ntfs_ntvattrget: node not loaded, ino: %d\n", 103 ip->i_number)); 104 error = ntfs_loadnode(ntmp,ip); 105 if(error) { 106 printf("ntfs_ntvattrget: FAILED TO LOAD INO: %d\n", 107 ip->i_number); 108 return (error); 109 } 110 } 111 112 for (vap = ip->i_vattrp; vap; vap = vap->va_nextp) { 113 ddprintf(("type: 0x%x, vcn: %d - %d\n", \ 114 vap->va_type, (u_int32_t) vap->va_vcnstart, \ 115 (u_int32_t) vap->va_vcnend)); 116 if ((vap->va_type == type) && 117 (vap->va_vcnstart <= vcn) && (vap->va_vcnend >= vcn) && 118 (vap->va_namelen == namelen) && 119 (!strncmp(name, vap->va_name, namelen))) { 120 *vapp = vap; 121#if __FreeBSD_version >= 300000 122 VREF(NTTOV(vap->va_ip)); 123#else 124 /* 125 * In RELENG_2_2 vref can call vfs_object_create(...) 126 * who calls vgetattr, who calls ntfs_getattr, who 127 * calls ntfs_ntvattrget, who calls vref... :-( This 128 * hack is to avoid it. XXX 129 */ 130 NTTOV(vap->va_ip)->v_usecount++; 131#endif 132 return (0); 133 } 134 if (vap->va_type == NTFS_A_ATTRLIST) 135 lvap = vap; 136 } 137 138 if (!lvap) { 139 dprintf(("ntfs_ntvattrget: UNEXISTED ATTRIBUTE: " \ 140 "ino: %d, type: 0x%x, name: %s, vcn: %d\n", \ 141 ip->i_number, type, name, (u_int32_t) vcn)); 142 return (ENOENT); 143 } 144 /* Scan $ATTRIBUTE_LIST for requested attribute */ 145 len = lvap->va_datalen; 146 MALLOC(alpool, caddr_t, len, M_TEMP, M_WAITOK); 147 error = ntfs_breadntvattr_plain(ntmp, ip, lvap, 0, len, alpool, &len); 148 if (error) 149 goto out; 150 151 aalp = (struct attr_attrlist *) alpool; 152 nextaalp = NULL; 153 154 while (len > 0) { 155 dprintf(("ntfs_ntvattrget: " \ 156 "attrlist: ino: %d, attr: 0x%x, vcn: %d\n", \ 157 aalp->al_inumber, aalp->al_type, \ 158 (u_int32_t) aalp->al_vcnstart)); 159 160 if (len > aalp->reclen) { 161 nextaalp = NTFS_NEXTREC(aalp, struct attr_attrlist *); 162 } else { 163 nextaalp = NULL; 164 } 165 len -= aalp->reclen; 166 167#define AALPCMP(aalp,type,name,namelen) ( \ 168 (aalp->al_type == type) && (aalp->al_namelen == namelen) && \ 169 !uastrcmp(aalp->al_name,aalp->al_namelen,name,namelen) ) 170 171 if (AALPCMP(aalp, type, name, namelen) && 172 (!nextaalp || (nextaalp->al_vcnstart > vcn) || 173 !AALPCMP(nextaalp, type, name, namelen))) { 174 struct vnode *newvp; 175 struct ntnode *newip; 176 177 dprintf(("ntfs_ntvattrget: attrbute in ino: %d\n", 178 aalp->al_inumber)); 179 180 error = VFS_VGET(ntmp->ntm_mountp, aalp->al_inumber, 181 &newvp); 182 if (error) { 183 printf("ntfs_ntvattrget: CAN'T VGET INO: %d\n", 184 aalp->al_inumber); 185 goto out; 186 } 187 newip = VTONT(newvp); 188 if(~newip->i_flag & IN_LOADED) { 189 dprintf(("ntfs_ntvattrget: node not loaded," \ 190 " ino: %d\n", newip->i_number)); 191 error = ntfs_loadnode(ntmp,ip); 192 if(error) { 193 printf("ntfs_ntvattrget: CAN'T LOAD " \ 194 "INO: %d\n", newip->i_number); 195 vput(newvp); 196 goto out; 197 } 198 } 199 for (vap = newip->i_vattrp; vap; vap = vap->va_nextp) { 200 if ((vap->va_type == type) && 201 (vap->va_vcnstart <= vcn) && 202 (vap->va_vcnend >= vcn) && 203 (vap->va_namelen == namelen) && 204 (!strncmp(name, vap->va_name, namelen))) { 205 *vapp = vap; 206#if __FreeBSD_version >= 300000 207 VREF(NTTOV(vap->va_ip)); 208#else 209 /* See comment above */ 210 NTTOV(vap->va_ip)->v_usecount++; 211#endif 212 vput(newvp); 213 error = 0; 214 goto out; 215 } 216 if (vap->va_type == NTFS_A_ATTRLIST) 217 lvap = vap; 218 } 219 printf("ntfs_ntvattrget: ATTRLIST ERROR.\n"); 220 vput(newvp); 221 break; 222 } 223#undef AALPCMP 224 aalp = nextaalp; 225 } 226 error = ENOENT; 227 228 dprintf(("ntfs_ntvattrget: UNEXISTED ATTRIBUTE: " \ 229 "ino: %d, type: 0x%x, name: %s, vcn: %d\n", \ 230 ip->i_number, type, name, (u_int32_t) vcn)); 231out: 232 FREE(alpool, M_TEMP); 233 234 return (error); 235} 236 237int 238ntfs_loadnode( 239 struct ntfsmount * ntmp, 240 struct ntnode * ip) 241{ 242 struct filerec *mfrp; 243 daddr_t bn; 244 int error,off; 245 struct attr *ap; 246 struct ntvattr**vapp; 247 248 dprintf(("ntfs_loadnode: loading ino: %d\n",ip->i_number)); 249 250 MALLOC(mfrp, struct filerec *, ntfs_bntob(ntmp->ntm_bpmftrec), 251 M_TEMP, M_WAITOK); 252 253 if (ip->i_number < NTFS_SYSNODESNUM) { 254 struct buf *bp; 255 256 dprintf(("ntfs_loadnode: read system node\n")); 257 258 bn = ntfs_cntobn(ntmp->ntm_mftcn) + 259 ntmp->ntm_bpmftrec * ip->i_number; 260 261 error = bread(ntmp->ntm_devvp, 262 bn, ntfs_bntob(ntmp->ntm_bpmftrec), 263 NOCRED, &bp); 264 if (error) { 265 printf("ntfs_loadnode: BREAD FAILED\n"); 266 brelse(bp); 267 goto out; 268 } 269 memcpy(mfrp, bp->b_data, ntfs_bntob(ntmp->ntm_bpmftrec)); 270 bqrelse(bp); 271 } else { 272 struct vnode *vp; 273 274 vp = ntmp->ntm_sysvn[NTFS_MFTINO]; 275 error = ntfs_breadattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL, 276 ip->i_number * ntfs_bntob(ntmp->ntm_bpmftrec), 277 ntfs_bntob(ntmp->ntm_bpmftrec), mfrp); 278 if (error) { 279 printf("ntfs_loadnode: ntfs_breadattr failed\n"); 280 goto out; 281 } 282 } 283 /* Check if magic and fixups are correct */ 284 error = ntfs_procfixups(ntmp, NTFS_FILEMAGIC, (caddr_t)mfrp, 285 ntfs_bntob(ntmp->ntm_bpmftrec)); 286 if (error) { 287 printf("ntfs_loadnode: BAD MFT RECORD %d\n", 288 (u_int32_t) ip->i_number); 289 goto out; 290 } 291 292 dprintf(("ntfs_loadnode: load attrs for ino: %d\n",ip->i_number)); 293 off = mfrp->fr_attroff; 294 ap = (struct attr *) ((caddr_t)mfrp + off); 295 vapp = &ip->i_vattrp; 296 while (ap->a_hdr.a_type != -1) { 297 error = ntfs_attrtontvattr(ntmp, vapp, ap); 298 if (error) 299 break; 300 (*vapp)->va_ip = ip; 301 vapp = &((*vapp)->va_nextp); 302 303 off += ap->a_hdr.reclen; 304 ap = (struct attr *) ((caddr_t)mfrp + off); 305 } 306 if (error) { 307 printf("ntfs_loadnode: failed to load attr ino: %d\n", 308 ip->i_number); 309 goto out; 310 } 311 312 ip->i_mainrec = mfrp->fr_mainrec; 313 ip->i_nlink = mfrp->fr_nlink; 314 ip->i_frflag = mfrp->fr_flags; 315 316 ip->i_flag |= IN_LOADED; 317 318 if (ip->i_mainrec == 0) { 319 struct ntvattr *vap; 320 321 if (ntfs_ntvattrget(ntmp, ip, NTFS_A_NAME, NULL, 0, &vap) == 0){ 322 ip->i_times = vap->va_a_name->n_times; 323 ip->i_pnumber = vap->va_a_name->n_pnumber; 324 ip->i_fflag = vap->va_a_name->n_flag; 325 326 ntfs_ntvattrrele(vap); 327 } 328 329 if ((ip->i_fflag & NTFS_FFLAG_DIR) && (ip->i_defattr == 0)) { 330 struct ntvattr *irvap; 331 332 ip->i_type = VDIR; 333 ip->i_defattr = NTFS_A_INDXROOT; 334 ip->i_defattrname = "$I30"; 335 error = ntfs_ntvattrget(ntmp, ip, 336 NTFS_A_INDXROOT, "$I30", 337 0, &irvap); 338 if(error == 0) { 339 ip->i_dirblsz = irvap->va_a_iroot->ir_size; 340 MALLOC(ip->i_dirblbuf, caddr_t, 341 max(irvap->va_datalen,ip->i_dirblsz), 342 M_NTFSDIR, M_WAITOK); 343 344 ntfs_ntvattrrele(irvap); 345 } 346 ip->i_size = 0; 347 ip->i_allocated = 0; 348 error = 0; 349 } else { 350 ip->i_type = VREG; 351 if(ip->i_defattr == 0) { 352 ip->i_defattr = NTFS_A_DATA; 353 ip->i_defattrname = NULL; 354 } 355 356 ntfs_filesize(ntmp, ip, &ip->i_size, &ip->i_allocated); 357 } 358 } 359 360 if (NTTOV(ip)) { 361 if (ip->i_number == NTFS_ROOTINO) 362 NTTOV(ip)->v_flag |= VROOT; 363 if (ip->i_number < NTFS_SYSNODESNUM) 364 NTTOV(ip)->v_flag |= VSYSTEM; 365 NTTOV(ip)->v_type = ip->i_type; 366 } 367out: 368 FREE(mfrp, M_TEMP); 369 return (error); 370} 371 372 373int 374ntfs_ntget( 375 struct ntfsmount * ntmp, 376 ino_t ino, 377 struct ntnode ** ipp) 378{ 379 struct ntnode *ip; 380 381 dprintf(("ntfs_ntget: allocate ntnode %d\n", ino)); 382 *ipp = NULL; 383 384 MALLOC(ip, struct ntnode *, sizeof(struct ntnode), 385 M_NTFSNODE, M_WAITOK); 386 bzero((caddr_t) ip, sizeof(struct ntnode)); 387 388 /* Generic initialization */ 389 ip->i_mp = ntmp; 390 ip->i_number = ino; 391 ip->i_dev = ntmp->ntm_dev; 392 ip->i_uid = ntmp->ntm_uid; 393 ip->i_gid = ntmp->ntm_gid; 394 ip->i_mode = ntmp->ntm_mode; 395 396 /* Setup internal pointers */ 397 ip->i_vattrp = NULL; 398 ip->i_devvp = ntmp->ntm_devvp; 399 400 *ipp = ip; 401 dprintf(("ntfs_ntget: allocated ntnode %d ok\n", ino)); 402 403 return (0); 404} 405 406void 407ntfs_ntrele( 408 struct ntnode * ip) 409{ 410 struct ntvattr *vap; 411 412 dprintf(("ntfs_ntrele: rele ntnode %d\n", ip->i_number)); 413 while (ip->i_vattrp) { 414 vap = ip->i_vattrp; 415 ip->i_vattrp = vap->va_nextp; 416 ntfs_freentvattr(vap); 417 } 418 if(ip->i_flag & IN_AATTRNAME) FREE(ip->i_defattrname,M_TEMP); 419 dprintf(("ntfs_ntrele: rele ntnode %d ok\n", ip->i_number)); 420 FREE(ip, M_NTFSNODE); 421} 422 423void 424ntfs_freentvattr( 425 struct ntvattr * vap) 426{ 427 if (vap->va_flag & NTFS_AF_INRUN) { 428 if (vap->va_vruncn) 429 FREE(vap->va_vruncn, M_NTFSRUN); 430 if (vap->va_vruncl) 431 FREE(vap->va_vruncl, M_NTFSRUN); 432 } else { 433 if (vap->va_datap) 434 FREE(vap->va_datap, M_NTFSRDATA); 435 } 436 FREE(vap, M_NTFSNTVATTR); 437} 438 439int 440ntfs_attrtontvattr( 441 struct ntfsmount * ntmp, 442 struct ntvattr ** rvapp, 443 struct attr * rap) 444{ 445 int error, i; 446 struct ntvattr *vap; 447 448 error = 0; 449 *rvapp = NULL; 450 451 MALLOC(vap, struct ntvattr *, sizeof(*vap), M_NTFSNTVATTR, M_WAITOK); 452 vap->va_ip = NULL; 453 vap->va_flag = rap->a_hdr.a_flag; 454 vap->va_type = rap->a_hdr.a_type; 455 vap->va_compression = rap->a_hdr.a_compression; 456 vap->va_nextp = NULL; 457 vap->va_index = rap->a_hdr.a_index; 458 459 ddprintf(("type: 0x%x, index: %d", vap->va_type, vap->va_index)); 460 461 vap->va_namelen = rap->a_hdr.a_namelen; 462 if (rap->a_hdr.a_namelen) { 463 wchar *unp = (wchar *) ((caddr_t) rap + rap->a_hdr.a_nameoff); 464 ddprintf((", name:[")); 465 for (i = 0; i < vap->va_namelen; i++) { 466 vap->va_name[i] = unp[i]; 467 ddprintf(("%c", vap->va_name[i])); 468 } 469 ddprintf(("]")); 470 } 471 if (vap->va_flag & NTFS_AF_INRUN) { 472 ddprintf((", nonres.")); 473 vap->va_datalen = rap->a_nr.a_datalen; 474 vap->va_allocated = rap->a_nr.a_allocated; 475 vap->va_vcnstart = rap->a_nr.a_vcnstart; 476 vap->va_vcnend = rap->a_nr.a_vcnend; 477 vap->va_compressalg = rap->a_nr.a_compressalg; 478 error = ntfs_runtovrun(&(vap->va_vruncn), &(vap->va_vruncl), 479 &(vap->va_vruncnt), 480 (caddr_t) rap + rap->a_nr.a_dataoff); 481 } else { 482 vap->va_compressalg = 0; 483 ddprintf((", res.")); 484 vap->va_datalen = rap->a_r.a_datalen; 485 vap->va_allocated = rap->a_r.a_datalen; 486 vap->va_vcnstart = 0; 487 vap->va_vcnend = ntfs_btocn(vap->va_allocated); 488 MALLOC(vap->va_datap, caddr_t, vap->va_datalen, 489 M_NTFSRDATA, M_WAITOK); 490 memcpy(vap->va_datap, (caddr_t) rap + rap->a_r.a_dataoff, 491 rap->a_r.a_datalen); 492 } 493 ddprintf((", len: %d", vap->va_datalen)); 494 495 if (error) 496 FREE(vap, M_NTFSNTVATTR); 497 else 498 *rvapp = vap; 499 500 ddprintf(("\n")); 501 502 return (error); 503} 504 505int 506ntfs_runtovrun( 507 cn_t ** rcnp, 508 cn_t ** rclp, 509 u_int32_t * rcntp, 510 u_int8_t * run) 511{ 512 u_int32_t off; 513 u_int32_t sz, i; 514 cn_t *cn; 515 cn_t *cl; 516 u_int32_t cnt; 517 u_int64_t prev; 518 519 off = 0; 520 cnt = 0; 521 i = 0; 522 while (run[off]) { 523 off += (run[off] & 0xF) + ((run[off] >> 4) & 0xF) + 1; 524 cnt++; 525 } 526 MALLOC(cn, cn_t *, cnt * sizeof(cn_t), M_NTFSRUN, M_WAITOK); 527 MALLOC(cl, cn_t *, cnt * sizeof(cn_t), M_NTFSRUN, M_WAITOK); 528 529 off = 0; 530 cnt = 0; 531 prev = 0; 532 while (run[off]) { 533 u_int64_t tmp; 534 535 sz = run[off++]; 536 cl[cnt] = 0; 537 538 for (i = 0; i < (sz & 0xF); i++) 539 cl[cnt] += (u_int32_t) run[off++] << (i << 3); 540 541 sz >>= 4; 542 if (run[off + sz - 1] & 0x80) { 543 tmp = ((u_int64_t) - 1) << (sz << 3); 544 for (i = 0; i < sz; i++) 545 tmp |= (u_int64_t) run[off++] << (i << 3); 546 } else { 547 tmp = 0; 548 for (i = 0; i < sz; i++) 549 tmp |= (u_int64_t) run[off++] << (i << 3); 550 } 551 if (tmp) 552 prev = cn[cnt] = prev + tmp; 553 else 554 cn[cnt] = tmp; 555 556 cnt++; 557 } 558 *rcnp = cn; 559 *rclp = cl; 560 *rcntp = cnt; 561 return (0); 562} 563 564 565wchar 566ntfs_toupper( 567 struct ntfsmount * ntmp, 568 wchar wc) 569{ 570 return (ntmp->ntm_upcase[wc & 0xFF]); 571} 572 573int 574ntfs_uustricmp( 575 struct ntfsmount * ntmp, 576 wchar * str1, 577 int str1len, 578 wchar * str2, 579 int str2len) 580{ 581 int i; 582 int res; 583 584 for (i = 0; i < str1len && i < str2len; i++) { 585 res = (int) ntfs_toupper(ntmp, str1[i]) - 586 (int) ntfs_toupper(ntmp, str2[i]); 587 if (res) 588 return res; 589 } 590 return (str1len - str2len); 591} 592 593int 594ntfs_uastricmp( 595 struct ntfsmount * ntmp, 596 wchar * str1, 597 int str1len, 598 char *str2, 599 int str2len) 600{ 601 int i; 602 int res; 603 604 for (i = 0; i < str1len && i < str2len; i++) { 605 res = (int) ntfs_toupper(ntmp, str1[i]) - 606 (int) ntfs_toupper(ntmp, (wchar) str2[i]); 607 if (res) 608 return res; 609 } 610 return (str1len - str2len); 611} 612 613int 614ntfs_uastrcmp( 615 struct ntfsmount * ntmp, 616 wchar * str1, 617 int str1len, 618 char *str2, 619 int str2len) 620{ 621 int i; 622 int res; 623 624 for (i = 0; (i < str1len) && (i < str2len); i++) { 625 res = ((int) str1[i]) - ((int) str2[i]); 626 if (res) 627 return res; 628 } 629 return (str1len - str2len); 630} 631 632int 633ntfs_ntlookupattr( 634 struct ntfsmount * ntmp, 635 char * name, 636 int namelen, 637 int *type, 638 char **attrname) 639{ 640 char *sys; 641 int syslen,i; 642 struct ntvattrdef *adp; 643 644 if (namelen == 0) 645 return (0); 646 647 if (name[0] == '$') { 648 sys = name; 649 for (syslen = 0; syslen < namelen; syslen++) { 650 if(sys[syslen] == ':') { 651 name++; 652 namelen--; 653 break; 654 } 655 } 656 name += syslen; 657 namelen -= syslen; 658 659 adp = ntmp->ntm_ad; 660 for (i = 0; i < ntmp->ntm_adnum; i++){ 661 if((syslen == adp->ad_namelen) && 662 (!strncmp(sys,adp->ad_name,syslen))) { 663 *type = adp->ad_type; 664 if(namelen) { 665 MALLOC((*attrname), char *, namelen, 666 M_TEMP, M_WAITOK); 667 memcpy((*attrname), name, namelen); 668 (*attrname)[namelen] = '\0'; 669 }/* else 670 (*attrname) = NULL;*/ 671 return (0); 672 } 673 adp++; 674 } 675 return (ENOENT); 676 } 677 678 if(namelen) { 679 MALLOC((*attrname), char *, namelen, M_TEMP, M_WAITOK); 680 memcpy((*attrname), name, namelen); 681 (*attrname)[namelen] = '\0'; 682 } 683 684 return (0); 685} 686/* 687 * Lookup specifed node for filename, matching cnp, return filled ntnode. 688 */ 689int 690ntfs_ntlookup( 691 struct ntfsmount * ntmp, 692 struct ntnode * ip, 693 struct componentname * cnp, 694 struct ntnode ** ipp) 695{ 696 struct ntvattr *vap; /* Root attribute */ 697 cn_t cn; /* VCN in current attribute */ 698 caddr_t rdbuf; /* Buffer to read directory's blocks */ 699 u_int32_t blsize; 700 u_int32_t rdsize; /* Length of data to read from current block */ 701 struct attr_indexentry *iep; 702 int error, res, anamelen, fnamelen; 703 char *fname,*aname; 704 u_int32_t aoff; 705 struct ntnode *nip; 706 707 error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXROOT, "$I30", 0, &vap); 708 if (error || (vap->va_flag & NTFS_AF_INRUN)) 709 return (ENOTDIR); 710 711 blsize = vap->va_a_iroot->ir_size; 712 rdsize = vap->va_datalen; 713 714 fname = cnp->cn_nameptr; 715 aname = NULL; 716 anamelen = 0; 717 for (fnamelen = 0; fnamelen < cnp->cn_namelen; fnamelen++) 718 if(fname[fnamelen] == ':') { 719 aname = fname + fnamelen + 1; 720 anamelen = cnp->cn_namelen - fnamelen - 1; 721 dprintf(("ntfs_ntlookup: file %s (%d), attr: %s (%d)\n", 722 fname, fnamelen, aname, anamelen)); 723 break; 724 } 725 726 dprintf(("ntfs_ntlookup: blocksize: %d, rdsize: %d\n", blsize, rdsize)); 727 728 MALLOC(rdbuf, caddr_t, blsize, M_TEMP, M_WAITOK); 729 730 error = ntfs_breadattr(ntmp, ip, NTFS_A_INDXROOT, "$I30", 731 0, rdsize, rdbuf); 732 if (error) 733 goto fail; 734 735 aoff = sizeof(struct attr_indexroot); 736 737 do { 738 iep = (struct attr_indexentry *) (rdbuf + aoff); 739 740 while (!(iep->ie_flag & NTFS_IEFLAG_LAST) && (rdsize > aoff)) { 741 ddprintf(("scan: %d, %d\n", 742 (u_int32_t) iep->ie_number, 743 (u_int32_t) iep->ie_fnametype)); 744 res = ntfs_uastricmp(ntmp, iep->ie_fname, 745 iep->ie_fnamelen, fname, 746 fnamelen); 747 if (res == 0) { 748 /* Matched something (case ins.) */ 749 if (iep->ie_fnametype == 0 || 750 !(ntmp->ntm_flag & NTFS_MFLAG_CASEINS)) 751 res = ntfs_uastrcmp(ntmp, 752 iep->ie_fname, 753 iep->ie_fnamelen, 754 fname, 755 fnamelen); 756 if (res == 0) { 757 error = ntfs_ntget(ntmp, 758 iep->ie_number, 759 &nip); 760 if(error) 761 goto fail; 762 763 nip->i_fflag = iep->ie_fflag; 764 nip->i_pnumber = iep->ie_fpnumber; 765 nip->i_times = iep->ie_ftimes; 766 767 if(nip->i_fflag & NTFS_FFLAG_DIR) { 768 nip->i_type = VDIR; 769 nip->i_defattr = 0; 770 nip->i_defattrname = NULL; 771 } else { 772 nip->i_type = VREG; 773 nip->i_defattr = NTFS_A_DATA; 774 nip->i_defattrname = NULL; 775 } 776 if (aname) { 777 error = ntfs_ntlookupattr(ntmp, 778 aname, anamelen, 779 &nip->i_defattr, 780 &nip->i_defattrname); 781 if (error) { 782 ntfs_ntrele(nip); 783 goto fail; 784 } 785 786 nip->i_type = VREG; 787 788 if (nip->i_defattrname) 789 nip->i_flag |= IN_AATTRNAME; 790 } else { 791 /* Opening default attribute */ 792 nip->i_size = iep->ie_fsize; 793 nip->i_allocated = 794 iep->ie_fallocated; 795 nip->i_flag |= IN_PRELOADED; 796 } 797 *ipp = nip; 798 goto fail; 799 } 800 } else if (res > 0) 801 break; 802 803 aoff += iep->reclen; 804 iep = (struct attr_indexentry *) (rdbuf + aoff); 805 } 806 807 /* Dive if possible */ 808 if (iep->ie_flag & NTFS_IEFLAG_SUBNODE) { 809 dprintf(("ntfs_ntlookup: diving\n")); 810 811 cn = *(cn_t *) (rdbuf + aoff + 812 iep->reclen - sizeof(cn_t)); 813 rdsize = blsize; 814 815 error = ntfs_breadattr(ntmp, ip, NTFS_A_INDX, "$I30", 816 ntfs_cntob(cn), rdsize, rdbuf); 817 if (error) 818 goto fail; 819 820 error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC, 821 rdbuf, rdsize); 822 if (error) 823 goto fail; 824 825 aoff = (((struct attr_indexalloc *) rdbuf)->ia_hdrsize + 826 0x18); 827 } else { 828 dprintf(("ntfs_ntlookup: nowhere to dive :-(\n")); 829 error = ENOENT; 830 break; 831 } 832 } while (1); 833 834 dprintf(("finish\n")); 835 836fail: 837 ntfs_ntvattrrele(vap); 838 FREE(rdbuf, M_TEMP); 839 return (error); 840} 841 842int 843ntfs_isnamepermitted( 844 struct ntfsmount * ntmp, 845 struct attr_indexentry * iep) 846{ 847 848 if (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES) 849 return 1; 850 851 switch (iep->ie_fnametype) { 852 case 2: 853 ddprintf(("ntfs_isnamepermitted: skiped DOS name\n")); 854 return 0; 855 case 0: 856 case 1: 857 case 3: 858 return 1; 859 default: 860 printf("ntfs_isnamepermitted: " \ 861 "WARNING! Unknown file name type: %d\n", 862 iep->ie_fnametype); 863 break; 864 } 865 return 0; 866} 867 868/* 869 * #undef dprintf #define dprintf(a) printf a 870 */ 871int 872ntfs_ntreaddir( 873 struct ntfsmount * ntmp, 874 struct ntnode * ip, 875 u_int32_t num, 876 struct attr_indexentry ** riepp) 877{ 878 struct ntvattr *vap = NULL; /* IndexRoot attribute */ 879 struct ntvattr *bmvap = NULL; /* BitMap attribute */ 880 struct ntvattr *iavap = NULL; /* IndexAllocation attribute */ 881 caddr_t rdbuf; /* Buffer to read directory's blocks */ 882 u_char *bmp = NULL; /* Bitmap */ 883 u_int32_t blsize; /* Index allocation size (2048) */ 884 u_int32_t rdsize; /* Length of data to read */ 885 u_int32_t attrnum; /* Current attribute type */ 886 u_int32_t cpbl = 1; /* Clusters per directory block */ 887 u_int32_t blnum; 888 struct attr_indexentry *iep; 889 int error = ENOENT; 890 u_int32_t aoff, cnum; 891 892 dprintf(("ntfs_ntreaddir: read ino: %d, num: %d\n", ip->i_number, num)); 893 error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXROOT, "$I30", 0, &vap); 894 if (error) 895 return (ENOTDIR); 896 897 blsize = ip->i_dirblsz; 898 rdbuf = ip->i_dirblbuf; 899 900 dprintf(("ntfs_ntreaddir: rdbuf: 0x%p, blsize: %d\n", rdbuf, blsize)); 901 902 if (vap->va_a_iroot->ir_flag & NTFS_IRFLAG_INDXALLOC) { 903 error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDXBITMAP, "$I30", 904 0, &bmvap); 905 if (error) { 906 error = ENOTDIR; 907 goto fail; 908 } 909 MALLOC(bmp, u_char *, bmvap->va_datalen, M_TEMP, M_WAITOK); 910 error = ntfs_breadattr(ntmp, ip, NTFS_A_INDXBITMAP, "$I30", 0, 911 bmvap->va_datalen, bmp); 912 if (error) 913 goto fail; 914 915 error = ntfs_ntvattrget(ntmp, ip, NTFS_A_INDX, "$I30", 916 0, &iavap); 917 if (error) { 918 error = ENOTDIR; 919 goto fail; 920 } 921 cpbl = ntfs_btocn(blsize + ntfs_cntob(1) - 1); 922 dprintf(("ntfs_ntreaddir: indexalloc: %d, cpbl: %d\n", 923 iavap->va_datalen, cpbl)); 924 } else { 925 dprintf(("ntfs_ntreadidir: w/o BitMap and IndexAllocation\n")); 926 iavap = bmvap = NULL; 927 bmp = NULL; 928 } 929 930 /* Try use previous values */ 931 if ((ip->i_lastdnum < num) && (ip->i_lastdnum != 0)) { 932 attrnum = ip->i_lastdattr; 933 aoff = ip->i_lastdoff; 934 blnum = ip->i_lastdblnum; 935 cnum = ip->i_lastdnum; 936 } else { 937 attrnum = NTFS_A_INDXROOT; 938 aoff = sizeof(struct attr_indexroot); 939 blnum = 0; 940 cnum = 0; 941 } 942 943 do { 944 dprintf(("ntfs_ntreaddir: scan: 0x%x, %d, %d, %d, %d\n", 945 attrnum, (u_int32_t) blnum, cnum, num, aoff)); 946 rdsize = (attrnum == NTFS_A_INDXROOT) ? vap->va_datalen : blsize; 947 error = ntfs_breadattr(ntmp, ip, attrnum, "$I30", 948 ntfs_cntob(blnum * cpbl), rdsize, rdbuf); 949 if (error) 950 goto fail; 951 952 if (attrnum == NTFS_A_INDX) { 953 error = ntfs_procfixups(ntmp, NTFS_INDXMAGIC, 954 rdbuf, rdsize); 955 if (error) 956 goto fail; 957 } 958 if (aoff == 0) 959 aoff = (attrnum == NTFS_A_INDX) ? 960 (0x18 + ((struct attr_indexalloc *) rdbuf)->ia_hdrsize) : 961 sizeof(struct attr_indexroot); 962 963 iep = (struct attr_indexentry *) (rdbuf + aoff); 964 while (!(iep->ie_flag & NTFS_IEFLAG_LAST) && (rdsize > aoff)) { 965 if (ntfs_isnamepermitted(ntmp, iep)) { 966 if (cnum >= num) { 967 ip->i_lastdnum = cnum; 968 ip->i_lastdoff = aoff; 969 ip->i_lastdblnum = blnum; 970 ip->i_lastdattr = attrnum; 971 972 *riepp = iep; 973 974 error = 0; 975 goto fail; 976 } 977 cnum++; 978 } 979 aoff += iep->reclen; 980 iep = (struct attr_indexentry *) (rdbuf + aoff); 981 } 982 983 if (iavap) { 984 if (attrnum == NTFS_A_INDXROOT) 985 blnum = 0; 986 else 987 blnum++; 988 989 while (ntfs_cntob(blnum * cpbl) < iavap->va_datalen) { 990 if (bmp[blnum >> 3] & (1 << (blnum & 3))) 991 break; 992 blnum++; 993 } 994 995 attrnum = NTFS_A_INDX; 996 aoff = 0; 997 if (ntfs_cntob(blnum * cpbl) >= iavap->va_datalen) 998 break; 999 dprintf(("ntfs_ntreaddir: blnum: %d\n", (u_int32_t) blnum)); 1000 } 1001 } while (iavap); 1002 1003 *riepp = NULL; 1004 ip->i_lastdnum = 0; 1005 1006fail: 1007 if (vap) 1008 ntfs_ntvattrrele(vap); 1009 if (bmvap) 1010 ntfs_ntvattrrele(bmvap); 1011 if (iavap) 1012 ntfs_ntvattrrele(iavap); 1013 if (bmp) 1014 FREE(bmp, M_TEMP); 1015 return (error); 1016} 1017/* 1018 * #undef dprintf #define dprintf(a) 1019 */ 1020 1021struct timespec 1022ntfs_nttimetounix( 1023 u_int64_t nt) 1024{ 1025 struct timespec t; 1026 1027 /* WindowNT times are in 100 ns and from 1601 Jan 1 */ 1028 t.tv_nsec = (nt % (1000 * 1000 * 10)) * 100; 1029 t.tv_sec = nt / (1000 * 1000 * 10) - 1030 369LL * 365LL * 24LL * 60LL * 60LL - 1031 89LL * 1LL * 24LL * 60LL * 60LL; 1032 return (t); 1033} 1034 1035int 1036ntfs_times( 1037 struct ntfsmount * ntmp, 1038 struct ntnode * ip, 1039 ntfs_times_t * tm) 1040{ 1041 struct ntvattr *vap; 1042 int error; 1043 1044 dprintf(("ntfs_times: ino: %d...\n", ip->i_number)); 1045 error = ntfs_ntvattrget(ntmp, ip, NTFS_A_NAME, NULL, 0, &vap); 1046 if (error) 1047 return (error); 1048 *tm = vap->va_a_name->n_times; 1049 ntfs_ntvattrrele(vap); 1050 1051 return (0); 1052} 1053 1054int 1055ntfs_filesize( 1056 struct ntfsmount * ntmp, 1057 struct ntnode * ip, 1058 u_int64_t * size, 1059 u_int64_t * bytes) 1060{ 1061 struct ntvattr *vap; 1062 u_int64_t sz, bn; 1063 int error; 1064 1065 dprintf(("ntfs_filesize: ino: %d\n", ip->i_number)); 1066 error = ntfs_ntvattrget(ntmp, ip, ip->i_defattr, ip->i_defattrname, 1067 0, &vap); 1068 if (error) 1069 return (error); 1070 bn = vap->va_allocated; 1071 sz = vap->va_datalen; 1072 1073 dprintf(("ntfs_filesize: %d bytes (%d bytes allocated)\n", 1074 (u_int32_t) sz, (u_int32_t) bn)); 1075 1076 if (size) 1077 *size = sz; 1078 if (bytes) 1079 *bytes = bn; 1080 1081 ntfs_ntvattrrele(vap); 1082 1083 return (0); 1084} 1085 1086int 1087ntfs_breadntvattr_plain( 1088 struct ntfsmount * ntmp, 1089 struct ntnode * ip, 1090 struct ntvattr * vap, 1091 off_t roff, 1092 size_t rsize, 1093 void *rdata, 1094 size_t * initp) 1095{ 1096 int error = 0; 1097 int off; 1098 1099 *initp = 0; 1100 if (vap->va_flag & NTFS_AF_INRUN) { 1101 int cnt; 1102 cn_t ccn, ccl, cn, left, cl; 1103 caddr_t data = rdata; 1104 struct buf *bp; 1105 size_t tocopy; 1106 1107 ddprintf(("ntfs_breadntvattr_plain: data in run: %d chains\n", 1108 vap->va_vruncnt)); 1109 1110 off = roff; 1111 left = rsize; 1112 ccl = 0; 1113 ccn = 0; 1114 cnt = 0; 1115 while (left && (cnt < vap->va_vruncnt)) { 1116 ccn = vap->va_vruncn[cnt]; 1117 ccl = vap->va_vruncl[cnt]; 1118 1119 ddprintf(("ntfs_breadntvattr_plain: " \ 1120 "left %d, cn: 0x%x, cl: %d, off: %d\n", \ 1121 (u_int32_t) left, (u_int32_t) ccn, \ 1122 (u_int32_t) ccl, (u_int32_t) off)); 1123 1124 if (ntfs_cntob(ccl) < off) { 1125 off -= ntfs_cntob(ccl); 1126 cnt++; 1127 continue; 1128 } 1129 if (ccn || ip->i_number == NTFS_BOOTINO) { /* XXX */ 1130 ccl -= ntfs_btocn(off); 1131 cn = ccn + ntfs_btocn(off); 1132 off = ntfs_btocnoff(off); 1133 1134 while (left && ccl) { 1135 tocopy = min(left, 1136 min(ntfs_cntob(ccl) - off, 1137 MAXBSIZE - off)); 1138 cl = ntfs_btocl(tocopy + off); 1139 ddprintf(("ntfs_breadntvattr_plain: " \ 1140 "read: cn: 0x%x cl: %d, " \ 1141 "off: %d len: %d, left: %d\n", 1142 (u_int32_t) cn, 1143 (u_int32_t) cl, 1144 (u_int32_t) off, 1145 (u_int32_t) tocopy, 1146 (u_int32_t) left)); 1147 error = bread(ntmp->ntm_devvp, 1148 ntfs_cntobn(cn), 1149 ntfs_cntob(cl), 1150 NOCRED, &bp); 1151 if (error) { 1152 brelse(bp); 1153 return (error); 1154 } 1155 memcpy(data, bp->b_data + off, tocopy); 1156 brelse(bp); 1157 data = data + tocopy; 1158 *initp += tocopy; 1159 off = 0; 1160 left -= tocopy; 1161 cn += cl; 1162 ccl -= cl; 1163 } 1164 } else { 1165 tocopy = min(left, ntfs_cntob(ccl) - off); 1166 ddprintf(("ntfs_breadntvattr_plain: " 1167 "sparce: ccn: 0x%x ccl: %d, off: %d, " \ 1168 " len: %d, left: %d\n", 1169 (u_int32_t) ccn, (u_int32_t) ccl, 1170 (u_int32_t) off, (u_int32_t) tocopy, 1171 (u_int32_t) left)); 1172 left -= tocopy; 1173 off = 0; 1174 bzero(data, tocopy); 1175 data = data + tocopy; 1176 } 1177 cnt++; 1178 } 1179 if (left) { 1180 printf("ntfs_breadntvattr_plain: POSSIBLE RUN ERROR\n"); 1181 error = E2BIG; 1182 } 1183 } else { 1184 ddprintf(("ntfs_breadnvattr_plain: data is in mft record\n")); 1185 memcpy(rdata, vap->va_datap + roff, rsize); 1186 *initp += rsize; 1187 } 1188 1189 return (error); 1190} 1191 1192int 1193ntfs_breadattr_plain( 1194 struct ntfsmount * ntmp, 1195 struct ntnode * ip, 1196 u_int32_t attrnum, 1197 char *attrname, 1198 off_t roff, 1199 size_t rsize, 1200 void *rdata, 1201 size_t * initp) 1202{ 1203 size_t init; 1204 int error = 0; 1205 off_t off = roff, left = rsize, toread; 1206 caddr_t data = rdata; 1207 struct ntvattr *vap; 1208 *initp = 0; 1209 1210 while (left) { 1211 error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname, 1212 ntfs_btocn(off), &vap); 1213 if (error) 1214 return (error); 1215 toread = min(left, ntfs_cntob(vap->va_vcnend + 1) - off); 1216 ddprintf(("ntfs_breadattr_plain: o: %d, s: %d (%d - %d)\n", 1217 (u_int32_t) off, (u_int32_t) toread, 1218 (u_int32_t) vap->va_vcnstart, 1219 (u_int32_t) vap->va_vcnend)); 1220 error = ntfs_breadntvattr_plain(ntmp, ip, vap, 1221 off - ntfs_cntob(vap->va_vcnstart), 1222 toread, data, &init); 1223 if (error) { 1224 printf("ntfs_breadattr_plain: " \ 1225 "ntfs_breadntvattr_plain failed: o: %d, s: %d\n", 1226 (u_int32_t) off, (u_int32_t) toread); 1227 printf("ntfs_breadattr_plain: attrib: %d - %d\n", 1228 (u_int32_t) vap->va_vcnstart, 1229 (u_int32_t) vap->va_vcnend); 1230 ntfs_ntvattrrele(vap); 1231 break; 1232 } 1233 ntfs_ntvattrrele(vap); 1234 left -= toread; 1235 off += toread; 1236 data = data + toread; 1237 *initp += init; 1238 } 1239 1240 return (error); 1241} 1242 1243int 1244ntfs_breadattr( 1245 struct ntfsmount * ntmp, 1246 struct ntnode * ip, 1247 u_int32_t attrnum, 1248 char *attrname, 1249 off_t roff, 1250 size_t rsize, 1251 void *rdata) 1252{ 1253 int error = 0; 1254 struct ntvattr *vap; 1255 size_t init; 1256 1257 ddprintf(("ntfs_breadattr: reading %d: 0x%x, from %d size %d bytes\n", 1258 ip->i_number, attrnum, (u_int32_t) roff, (u_int32_t) rsize)); 1259 1260 error = ntfs_ntvattrget(ntmp, ip, attrnum, attrname, 0, &vap); 1261 if (error) 1262 return (error); 1263 1264 if ((roff > vap->va_datalen) || 1265 (roff + rsize > vap->va_datalen)) { 1266 ddprintf(("ntfs_breadattr: offset too big\n")); 1267 ntfs_ntvattrrele(vap); 1268 return (E2BIG); 1269 } 1270 if (vap->va_compression && vap->va_compressalg) { 1271 u_int8_t *cup; 1272 u_int8_t *uup; 1273 off_t off = roff, left = rsize, tocopy; 1274 caddr_t data = rdata; 1275 cn_t cn; 1276 1277 ddprintf(("ntfs_ntreadattr: compression: %d\n", 1278 vap->va_compressalg)); 1279 1280 MALLOC(cup, u_int8_t *, ntfs_cntob(NTFS_COMPUNIT_CL), 1281 M_NTFSDECOMP, M_WAITOK); 1282 MALLOC(uup, u_int8_t *, ntfs_cntob(NTFS_COMPUNIT_CL), 1283 M_NTFSDECOMP, M_WAITOK); 1284 1285 cn = (ntfs_btocn(roff)) & (~(NTFS_COMPUNIT_CL - 1)); 1286 off = roff - ntfs_cntob(cn); 1287 1288 while (left) { 1289 error = ntfs_breadattr_plain(ntmp, ip, attrnum, 1290 attrname, ntfs_cntob(cn), 1291 ntfs_cntob(NTFS_COMPUNIT_CL), 1292 cup, &init); 1293 if (error) 1294 break; 1295 1296 tocopy = min(left, ntfs_cntob(NTFS_COMPUNIT_CL) - off); 1297 1298 if (init == ntfs_cntob(NTFS_COMPUNIT_CL)) { 1299 memcpy(data, cup + off, tocopy); 1300 } else if (init == 0) { 1301 bzero(data, tocopy); 1302 } else { 1303 error = ntfs_uncompunit(ntmp, uup, cup); 1304 if (error) 1305 break; 1306 memcpy(data, uup + off, tocopy); 1307 } 1308 1309 left -= tocopy; 1310 data = data + tocopy; 1311 off += tocopy - ntfs_cntob(NTFS_COMPUNIT_CL); 1312 cn += NTFS_COMPUNIT_CL; 1313 } 1314 1315 FREE(uup, M_NTFSDECOMP); 1316 FREE(cup, M_NTFSDECOMP); 1317 } else 1318 error = ntfs_breadattr_plain(ntmp, ip, attrnum, attrname, 1319 roff, rsize, rdata, &init); 1320 ntfs_ntvattrrele(vap); 1321 return (error); 1322} 1323 1324int 1325ntfs_parserun( 1326 cn_t * cn, 1327 cn_t * cl, 1328 u_int8_t * run, 1329 size_t len, 1330 int *off) 1331{ 1332 u_int8_t sz; 1333 int i; 1334 1335 if (NULL == run) { 1336 printf("ntfs_runtocn: run == NULL\n"); 1337 return (EINVAL); 1338 } 1339 sz = run[(*off)++]; 1340 if (0 == sz) { 1341 printf("ntfs_parserun: trying to go out of run\n"); 1342 return (E2BIG); 1343 } 1344 *cl = 0; 1345 if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) { 1346 printf("ntfs_parserun: " \ 1347 "bad run: length too big: %02x (%x < %x + sz)\n", 1348 sz, len, *off); 1349 return (EINVAL); 1350 } 1351 for (i = 0; i < (sz & 0xF); i++) 1352 *cl += (u_int32_t) run[(*off)++] << (i << 3); 1353 1354 sz >>= 4; 1355 if ((sz & 0xF) > 8 || (*off) + (sz & 0xF) > len) { 1356 printf("ntfs_parserun: " \ 1357 "bad run: offset too big: %02x (%x < %x + sz)\n", 1358 sz, len, *off); 1359 return (EINVAL); 1360 } 1361 for (i = 0; i < (sz & 0xF); i++) 1362 *cn += (u_int32_t) run[(*off)++] << (i << 3); 1363 1364 return (0); 1365} 1366 1367int 1368ntfs_procfixups( 1369 struct ntfsmount * ntmp, 1370 u_int32_t magic, 1371 caddr_t buf, 1372 size_t len) 1373{ 1374 struct fixuphdr *fhp = (struct fixuphdr *) buf; 1375 int i; 1376 u_int16_t fixup; 1377 u_int16_t *fxp; 1378 u_int16_t *cfxp; 1379 1380 if (fhp->fh_magic != magic) { 1381 printf("ntfs_procfixups: magic doesn't match: %08x != %08x\n", 1382 fhp->fh_magic, magic); 1383 return (EINVAL); 1384 } 1385 if ((fhp->fh_fnum - 1) * ntmp->ntm_bps != len) { 1386 printf("ntfs_procfixups: " \ 1387 "bad fixups number: %d for %d bytes block\n", 1388 fhp->fh_fnum, len); 1389 return (EINVAL); 1390 } 1391 if (fhp->fh_foff >= ntmp->ntm_spc * ntmp->ntm_mftrecsz * ntmp->ntm_bps) { 1392 printf("ntfs_procfixups: invalid offset: %x", fhp->fh_foff); 1393 return (EINVAL); 1394 } 1395 fxp = (u_int16_t *) (buf + fhp->fh_foff); 1396 cfxp = (u_int16_t *) (buf + ntmp->ntm_bps - 2); 1397 fixup = *fxp++; 1398 for (i = 1; i < fhp->fh_fnum; i++, fxp++) { 1399 if (*cfxp != fixup) { 1400 printf("ntfs_procfixups: fixup %d doesn't match\n", i); 1401 return (EINVAL); 1402 } 1403 *cfxp = *fxp; 1404 ((caddr_t) cfxp) += ntmp->ntm_bps; 1405 } 1406 return (0); 1407} 1408 1409int 1410ntfs_runtocn( 1411 cn_t * cn, 1412 struct ntfsmount * ntmp, 1413 u_int8_t * run, 1414 size_t len, 1415 cn_t vcn) 1416{ 1417 cn_t ccn = 0; 1418 cn_t ccl = 0; 1419 int off = 0; 1420 int error = 0; 1421 1422#if NTFS_DEBUG 1423 int i; 1424 printf("ntfs_runtocn: " \ 1425 "run: 0x%p, %d bytes, vcn:%d\n", run, len, (u_int32_t) vcn); 1426 printf("ntfs_runtocn: run: "); 1427 for (i = 0; i < len; i++) 1428 printf("0x%02x ", run[i]); 1429 printf("\n"); 1430#endif 1431 1432 if (NULL == run) { 1433 printf("ntfs_runtocn: run == NULL\n"); 1434 return (EINVAL); 1435 } 1436 do { 1437 if (run[off] == 0) { 1438 printf("ntfs_runtocn: vcn too big\n"); 1439 return (E2BIG); 1440 } 1441 vcn -= ccl; 1442 error = ntfs_parserun(&ccn, &ccl, run, len, &off); 1443 if (error) { 1444 printf("ntfs_runtocn: ntfs_parserun failed\n"); 1445 return (error); 1446 } 1447 } while (ccl <= vcn); 1448 *cn = ccn + vcn; 1449 return (0); 1450} 1451