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