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