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