1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Directory operations for High Sierra filesystem 30 */ 31 32 #include <sys/types.h> 33 #include <sys/t_lock.h> 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/cred.h> 37 #include <sys/user.h> 38 #include <sys/vfs.h> 39 #include <sys/stat.h> 40 #include <sys/vnode.h> 41 #include <sys/mode.h> 42 #include <sys/dnlc.h> 43 #include <sys/cmn_err.h> 44 #include <sys/fbuf.h> 45 #include <sys/kmem.h> 46 #include <sys/policy.h> 47 #include <sys/sunddi.h> 48 #include <vm/hat.h> 49 #include <vm/as.h> 50 #include <vm/pvn.h> 51 #include <vm/seg.h> 52 #include <vm/seg_map.h> 53 #include <vm/seg_kmem.h> 54 #include <vm/page.h> 55 56 #include <sys/fs/hsfs_spec.h> 57 #include <sys/fs/hsfs_isospec.h> 58 #include <sys/fs/hsfs_node.h> 59 #include <sys/fs/hsfs_impl.h> 60 #include <sys/fs/hsfs_susp.h> 61 #include <sys/fs/hsfs_rrip.h> 62 63 #include <sys/sysinfo.h> 64 #include <sys/sysmacros.h> 65 #include <sys/errno.h> 66 #include <sys/debug.h> 67 #include <fs/fs_subr.h> 68 69 /* 70 * This macro expects a name that ends in '.' and returns TRUE if the 71 * name is not "." or ".." 72 */ 73 #define CAN_TRUNCATE_DOT(name, namelen) \ 74 (namelen > 1 && (namelen > 2 || name[0] != '.')) 75 76 enum dirblock_result { FOUND_ENTRY, WENT_PAST, HIT_END }; 77 78 /* 79 * These values determine whether we will try to read a file or dir; 80 * they may be patched via /etc/system to allow users to read 81 * record-oriented files. 82 */ 83 int ide_prohibited = IDE_PROHIBITED; 84 int hde_prohibited = HDE_PROHIBITED; 85 86 /* 87 * This variable determines if the HSFS code will use the 88 * directory name lookup cache. The default is for the cache to be used. 89 */ 90 static int hsfs_use_dnlc = 1; 91 92 /* 93 * This variable determines whether strict ISO-9660 directory ordering 94 * is to be assumed. If false (which it is by default), then when 95 * searching a directory of an ISO-9660 disk, we do not expect the 96 * entries to be sorted (as the spec requires), and so cannot terminate 97 * the search early. Unfortunately, some vendors are producing 98 * non-compliant disks. This variable exists to revert to the old 99 * behavior in case someone relies on this. This option is expected to be 100 * removed at some point in the future. 101 * 102 * Use "set hsfs:strict_iso9660_ordering = 1" in /etc/system to override. 103 */ 104 static int strict_iso9660_ordering = 0; 105 106 static void hs_hsnode_cache_reclaim(void *unused); 107 static void hs_addfreeb(struct hsfs *fsp, struct hsnode *hp); 108 static enum dirblock_result process_dirblock(struct fbuf *fbp, uint_t *offset, 109 uint_t last_offset, char *nm, int nmlen, struct hsfs *fsp, 110 struct hsnode *dhp, struct vnode *dvp, struct vnode **vpp, 111 int *error); 112 static int strip_trailing(struct hsfs *fsp, char *nm, int len); 113 static int hs_namelen(struct hsfs *fsp, char *nm, int len); 114 static int uppercase_cp(char *from, char *to, int size); 115 static void hs_log_bogus_joliet_warning(void); 116 static int hs_iso_copy(char *from, char *to, int size); 117 static int32_t hs_ucs2_2_utf8(uint16_t c_16, uint8_t *s_8); 118 static int hs_utf8_trunc(uint8_t *str, int len); 119 120 /* 121 * hs_access 122 * Return 0 if the desired access may be granted. 123 * Otherwise return error code. 124 */ 125 int 126 hs_access(struct vnode *vp, mode_t m, struct cred *cred) 127 { 128 struct hsnode *hp; 129 int shift = 0; 130 131 /* 132 * Write access cannot be granted for a read-only medium 133 */ 134 if ((m & VWRITE) && !IS_DEVVP(vp)) 135 return (EROFS); 136 137 hp = VTOH(vp); 138 139 /* 140 * XXX - For now, use volume protections. 141 * Also, always grant EXEC access for directories 142 * if READ access is granted. 143 */ 144 if ((vp->v_type == VDIR) && (m & VEXEC)) { 145 m &= ~VEXEC; 146 m |= VREAD; 147 } 148 149 if (crgetuid(cred) != hp->hs_dirent.uid) { 150 shift += 3; 151 if (!groupmember((uid_t)hp->hs_dirent.gid, cred)) 152 shift += 3; 153 } 154 m &= ~(hp->hs_dirent.mode << shift); 155 if (m != 0) 156 return (secpolicy_vnode_access(cred, vp, hp->hs_dirent.uid, m)); 157 return (0); 158 } 159 160 #if ((HS_HASHSIZE & (HS_HASHSIZE - 1)) == 0) 161 #define HS_HASH(l) ((uint_t)(l) & (HS_HASHSIZE - 1)) 162 #else 163 #define HS_HASH(l) ((uint_t)(l) % HS_HASHSIZE) 164 #endif 165 #define HS_HPASH(hp) HS_HASH((hp)->hs_nodeid) 166 167 /* 168 * The tunable nhsnode is now a threshold for a dynamically allocated 169 * pool of hsnodes, not the size of a statically allocated table. 170 * When the number of hsnodes for a particular file system exceeds 171 * nhsnode, the allocate and free logic will try to reduce the number 172 * of allocated nodes by returning unreferenced nodes to the kmem_cache 173 * instead of putting them on the file system's private free list. 174 */ 175 int nhsnode = HS_HSNODESPACE / sizeof (struct hsnode); 176 177 struct kmem_cache *hsnode_cache; /* free hsnode cache */ 178 179 /* 180 * Initialize the cache of free hsnodes. 181 */ 182 void 183 hs_init_hsnode_cache(void) 184 { 185 /* 186 * A kmem_cache is used for the hsnodes 187 * No constructor because hsnodes are initialised by bzeroing. 188 */ 189 hsnode_cache = kmem_cache_create("hsfs_hsnode_cache", 190 sizeof (struct hsnode), 0, NULL, 191 NULL, hs_hsnode_cache_reclaim, NULL, NULL, 0); 192 } 193 194 /* 195 * Destroy the cache of free hsnodes. 196 */ 197 void 198 hs_fini_hsnode_cache(void) 199 { 200 kmem_cache_destroy(hsnode_cache); 201 } 202 203 /* 204 * System is short on memory, free up as much as possible 205 */ 206 /*ARGSUSED*/ 207 static void 208 hs_hsnode_cache_reclaim(void *unused) 209 { 210 struct hsfs *fsp; 211 struct hsnode *hp; 212 213 /* 214 * For each vfs in the hs_mounttab list 215 */ 216 mutex_enter(&hs_mounttab_lock); 217 for (fsp = hs_mounttab; fsp != NULL; fsp = fsp->hsfs_next) { 218 /* 219 * Purge the dnlc of all hsfs entries 220 */ 221 (void) dnlc_purge_vfsp(fsp->hsfs_vfs, 0); 222 223 /* 224 * For each entry in the free chain 225 */ 226 rw_enter(&fsp->hsfs_hash_lock, RW_WRITER); 227 mutex_enter(&fsp->hsfs_free_lock); 228 for (hp = fsp->hsfs_free_f; hp != NULL; hp = fsp->hsfs_free_f) { 229 /* 230 * Remove from chain 231 */ 232 fsp->hsfs_free_f = hp->hs_freef; 233 if (fsp->hsfs_free_f != NULL) { 234 fsp->hsfs_free_f->hs_freeb = NULL; 235 } else { 236 fsp->hsfs_free_b = NULL; 237 } 238 /* 239 * Free the node. Force it to be fully freed 240 * by setting the 3rd arg (nopage) to 1. 241 */ 242 hs_freenode(HTOV(hp), fsp, 1); 243 } 244 mutex_exit(&fsp->hsfs_free_lock); 245 rw_exit(&fsp->hsfs_hash_lock); 246 } 247 mutex_exit(&hs_mounttab_lock); 248 } 249 250 /* 251 * Add an hsnode to the end of the free list. 252 */ 253 static void 254 hs_addfreeb(struct hsfs *fsp, struct hsnode *hp) 255 { 256 struct hsnode *ep; 257 258 vn_invalid(HTOV(hp)); 259 mutex_enter(&fsp->hsfs_free_lock); 260 ep = fsp->hsfs_free_b; 261 fsp->hsfs_free_b = hp; /* hp is the last entry in free list */ 262 hp->hs_freef = NULL; 263 hp->hs_freeb = ep; /* point at previous last entry */ 264 if (ep == NULL) 265 fsp->hsfs_free_f = hp; /* hp is only entry in free list */ 266 else 267 ep->hs_freef = hp; /* point previous last entry at hp */ 268 269 mutex_exit(&fsp->hsfs_free_lock); 270 } 271 272 /* 273 * Get an hsnode from the front of the free list. 274 * Must be called with write hsfs_hash_lock held. 275 */ 276 static struct hsnode * 277 hs_getfree(struct hsfs *fsp) 278 { 279 struct hsnode *hp, **tp; 280 281 ASSERT(RW_WRITE_HELD(&fsp->hsfs_hash_lock)); 282 283 /* 284 * If the number of currently-allocated hsnodes is less than 285 * the hsnode count threshold (nhsnode), or if there are no 286 * nodes on the file system's local free list (which acts as a 287 * cache), call kmem_cache_alloc to get a new hsnode from 288 * kernel memory. 289 */ 290 mutex_enter(&fsp->hsfs_free_lock); 291 if ((fsp->hsfs_nohsnode < nhsnode) || (fsp->hsfs_free_f == NULL)) { 292 mutex_exit(&fsp->hsfs_free_lock); 293 hp = kmem_cache_alloc(hsnode_cache, KM_SLEEP); 294 fsp->hsfs_nohsnode++; 295 bzero((caddr_t)hp, sizeof (*hp)); 296 hp->hs_vnode = vn_alloc(KM_SLEEP); 297 return (hp); 298 } 299 hp = fsp->hsfs_free_f; 300 /* hp cannot be NULL, since we already checked this above */ 301 fsp->hsfs_free_f = hp->hs_freef; 302 if (fsp->hsfs_free_f != NULL) 303 fsp->hsfs_free_f->hs_freeb = NULL; 304 else 305 fsp->hsfs_free_b = NULL; 306 mutex_exit(&fsp->hsfs_free_lock); 307 308 for (tp = &fsp->hsfs_hash[HS_HPASH(hp)]; *tp != NULL; 309 tp = &(*tp)->hs_hash) { 310 if (*tp == hp) { 311 struct vnode *vp; 312 313 vp = HTOV(hp); 314 315 /* 316 * file is no longer referenced, destroy all old pages 317 */ 318 if (vn_has_cached_data(vp)) 319 /* 320 * pvn_vplist_dirty will abort all old pages 321 */ 322 (void) pvn_vplist_dirty(vp, (u_offset_t)0, 323 hsfs_putapage, B_INVAL, (struct cred *)NULL); 324 *tp = hp->hs_hash; 325 break; 326 } 327 } 328 if (hp->hs_dirent.sym_link != (char *)NULL) { 329 kmem_free(hp->hs_dirent.sym_link, 330 (size_t)(hp->hs_dirent.ext_size + 1)); 331 } 332 333 mutex_destroy(&hp->hs_contents_lock); 334 { 335 vnode_t *vp; 336 337 vp = hp->hs_vnode; 338 bzero((caddr_t)hp, sizeof (*hp)); 339 hp->hs_vnode = vp; 340 vn_reinit(vp); 341 } 342 return (hp); 343 } 344 345 /* 346 * Remove an hsnode from the free list. 347 */ 348 static void 349 hs_remfree(struct hsfs *fsp, struct hsnode *hp) 350 { 351 mutex_enter(&fsp->hsfs_free_lock); 352 if (hp->hs_freef != NULL) 353 hp->hs_freef->hs_freeb = hp->hs_freeb; 354 else 355 fsp->hsfs_free_b = hp->hs_freeb; 356 if (hp->hs_freeb != NULL) 357 hp->hs_freeb->hs_freef = hp->hs_freef; 358 else 359 fsp->hsfs_free_f = hp->hs_freef; 360 mutex_exit(&fsp->hsfs_free_lock); 361 } 362 363 /* 364 * Look for hsnode in hash list. 365 * Check equality of fsid and nodeid. 366 * If found, reactivate it if inactive. 367 * Must be entered with hsfs_hash_lock held. 368 */ 369 struct vnode * 370 hs_findhash(ino64_t nodeid, struct vfs *vfsp) 371 { 372 struct hsnode *tp; 373 struct hsfs *fsp; 374 375 fsp = VFS_TO_HSFS(vfsp); 376 377 ASSERT(RW_LOCK_HELD(&fsp->hsfs_hash_lock)); 378 379 for (tp = fsp->hsfs_hash[HS_HASH(nodeid)]; tp != NULL; 380 tp = tp->hs_hash) { 381 if (tp->hs_nodeid == nodeid) { 382 struct vnode *vp; 383 384 mutex_enter(&tp->hs_contents_lock); 385 vp = HTOV(tp); 386 VN_HOLD(vp); 387 if ((tp->hs_flags & HREF) == 0) { 388 tp->hs_flags |= HREF; 389 /* 390 * reactivating a free hsnode: 391 * remove from free list 392 */ 393 hs_remfree(fsp, tp); 394 } 395 mutex_exit(&tp->hs_contents_lock); 396 return (vp); 397 } 398 } 399 return (NULL); 400 } 401 402 static void 403 hs_addhash(struct hsfs *fsp, struct hsnode *hp) 404 { 405 ulong_t hashno; 406 407 ASSERT(RW_WRITE_HELD(&fsp->hsfs_hash_lock)); 408 409 hashno = HS_HPASH(hp); 410 hp->hs_hash = fsp->hsfs_hash[hashno]; 411 fsp->hsfs_hash[hashno] = hp; 412 } 413 414 /* 415 * Destroy all old pages and free the hsnodes 416 * Return 1 if busy (a hsnode is still referenced). 417 */ 418 int 419 hs_synchash(struct vfs *vfsp) 420 { 421 struct hsfs *fsp; 422 int i; 423 struct hsnode *hp, *nhp; 424 int busy = 0; 425 struct vnode *vp, *rvp; 426 427 fsp = VFS_TO_HSFS(vfsp); 428 rvp = fsp->hsfs_rootvp; 429 /* make sure no one can come in */ 430 rw_enter(&fsp->hsfs_hash_lock, RW_WRITER); 431 for (i = 0; i < HS_HASHSIZE; i++) { 432 for (hp = fsp->hsfs_hash[i]; hp != NULL; hp = hp->hs_hash) { 433 vp = HTOV(hp); 434 if ((hp->hs_flags & HREF) && (vp != rvp || 435 (vp == rvp && vp->v_count > 1))) { 436 busy = 1; 437 continue; 438 } 439 if (vn_has_cached_data(vp)) 440 (void) pvn_vplist_dirty(vp, (u_offset_t)0, 441 hsfs_putapage, B_INVAL, (struct cred *)NULL); 442 } 443 } 444 if (busy) { 445 rw_exit(&fsp->hsfs_hash_lock); 446 return (1); 447 } 448 449 /* now free the hsnodes */ 450 for (i = 0; i < HS_HASHSIZE; i++) { 451 for (hp = fsp->hsfs_hash[i]; hp != NULL; hp = nhp) { 452 nhp = hp->hs_hash; 453 /* 454 * We know there are no pages associated with 455 * all the hsnodes (they've all been released 456 * above). So remove from free list and 457 * free the entry with nopage set. 458 */ 459 vp = HTOV(hp); 460 if (vp != rvp) { 461 hs_remfree(fsp, hp); 462 hs_freenode(vp, fsp, 1); 463 } 464 } 465 } 466 467 ASSERT(fsp->hsfs_nohsnode == 1); 468 rw_exit(&fsp->hsfs_hash_lock); 469 /* release the root hsnode, this should free the final hsnode */ 470 VN_RELE(rvp); 471 472 return (0); 473 } 474 475 /* 476 * hs_makenode 477 * 478 * Construct an hsnode. 479 * Caller specifies the directory entry, the block number and offset 480 * of the directory entry, and the vfs pointer. 481 * note: off is the sector offset, not lbn offset 482 * if NULL is returned implies file system hsnode table full 483 */ 484 struct vnode * 485 hs_makenode( 486 struct hs_direntry *dp, 487 uint_t lbn, 488 uint_t off, 489 struct vfs *vfsp) 490 { 491 struct hsnode *hp; 492 struct vnode *vp; 493 struct hs_volume *hvp; 494 struct vnode *newvp; 495 struct hsfs *fsp; 496 ino64_t nodeid; 497 498 fsp = VFS_TO_HSFS(vfsp); 499 500 /* 501 * Construct the nodeid: in the case of a directory 502 * entry, this should point to the canonical dirent, the "." 503 * directory entry for the directory. This dirent is pointed 504 * to by all directory entries for that dir (including the ".") 505 * entry itself. 506 * In the case of a file, simply point to the dirent for that 507 * file (there are no hard links in Rock Ridge, so there's no 508 * need to determine what the canonical dirent is. 509 */ 510 if (dp->type == VDIR) { 511 lbn = dp->ext_lbn; 512 off = 0; 513 } 514 515 /* 516 * Normalize lbn and off before creating a nodeid 517 * and before storing them in a hs_node structure 518 */ 519 hvp = &fsp->hsfs_vol; 520 lbn += off >> hvp->lbn_shift; 521 off &= hvp->lbn_maxoffset; 522 nodeid = (ino64_t)MAKE_NODEID(lbn, off, vfsp); 523 524 /* look for hsnode in cache first */ 525 526 rw_enter(&fsp->hsfs_hash_lock, RW_READER); 527 528 if ((vp = hs_findhash(nodeid, vfsp)) == NULL) { 529 530 /* 531 * Not in cache. However, someone else may have come 532 * to the same conclusion and just put one in. Upgrade 533 * our lock to a write lock and look again. 534 */ 535 rw_exit(&fsp->hsfs_hash_lock); 536 rw_enter(&fsp->hsfs_hash_lock, RW_WRITER); 537 538 if ((vp = hs_findhash(nodeid, vfsp)) == NULL) { 539 /* 540 * Now we are really sure that the hsnode is not 541 * in the cache. Get one off freelist or else 542 * allocate one. Either way get a bzeroed hsnode. 543 */ 544 hp = hs_getfree(fsp); 545 546 bcopy((caddr_t)dp, (caddr_t)&hp->hs_dirent, 547 sizeof (*dp)); 548 /* 549 * We've just copied this pointer into hs_dirent, 550 * and don't want 2 references to same symlink. 551 */ 552 dp->sym_link = (char *)NULL; 553 554 /* 555 * No need to hold any lock because hsnode is not 556 * yet in the hash chain. 557 */ 558 mutex_init(&hp->hs_contents_lock, NULL, MUTEX_DEFAULT, 559 NULL); 560 hp->hs_dir_lbn = lbn; 561 hp->hs_dir_off = off; 562 hp->hs_nodeid = nodeid; 563 hp->hs_seq = 0; 564 hp->hs_flags = HREF; 565 if (off > HS_SECTOR_SIZE) 566 cmn_err(CE_WARN, "hs_makenode: bad offset"); 567 568 vp = HTOV(hp); 569 vp->v_vfsp = vfsp; 570 vp->v_type = dp->type; 571 vp->v_rdev = dp->r_dev; 572 vn_setops(vp, hsfs_vnodeops); 573 vp->v_data = (caddr_t)hp; 574 vn_exists(vp); 575 /* 576 * if it's a device, call specvp 577 */ 578 if (IS_DEVVP(vp)) { 579 rw_exit(&fsp->hsfs_hash_lock); 580 newvp = specvp(vp, vp->v_rdev, vp->v_type, 581 CRED()); 582 if (newvp == NULL) 583 cmn_err(CE_NOTE, 584 "hs_makenode: specvp failed"); 585 VN_RELE(vp); 586 return (newvp); 587 } 588 589 hs_addhash(fsp, hp); 590 591 } 592 } 593 594 if (dp->sym_link != (char *)NULL) { 595 kmem_free(dp->sym_link, (size_t)(dp->ext_size + 1)); 596 dp->sym_link = (char *)NULL; 597 } 598 599 rw_exit(&fsp->hsfs_hash_lock); 600 return (vp); 601 } 602 603 /* 604 * hs_freenode 605 * 606 * Deactivate an hsnode. 607 * Leave it on the hash list but put it on the free list. 608 * If the vnode does not have any pages, release the hsnode to the 609 * kmem_cache using kmem_cache_free, else put in back of the free list. 610 * 611 * This function can be called with the hsfs_free_lock held, but only 612 * when the code is guaranteed to go through the path where the 613 * node is freed entirely, and not the path where the node could go back 614 * on the free list (and where the free lock would need to be acquired). 615 */ 616 void 617 hs_freenode(vnode_t *vp, struct hsfs *fsp, int nopage) 618 { 619 struct hsnode **tp; 620 struct hsnode *hp = VTOH(vp); 621 622 ASSERT(RW_LOCK_HELD(&fsp->hsfs_hash_lock)); 623 624 if (nopage || (fsp->hsfs_nohsnode >= nhsnode)) { 625 /* remove this node from the hash list, if it's there */ 626 for (tp = &fsp->hsfs_hash[HS_HPASH(hp)]; *tp != NULL; 627 tp = &(*tp)->hs_hash) { 628 629 if (*tp == hp) { 630 *tp = hp->hs_hash; 631 break; 632 } 633 } 634 635 if (hp->hs_dirent.sym_link != (char *)NULL) { 636 kmem_free(hp->hs_dirent.sym_link, 637 (size_t)(hp->hs_dirent.ext_size + 1)); 638 hp->hs_dirent.sym_link = NULL; 639 } 640 if (vn_has_cached_data(vp)) { 641 /* clean all old pages */ 642 (void) pvn_vplist_dirty(vp, (u_offset_t)0, 643 hsfs_putapage, B_INVAL, (struct cred *)NULL); 644 /* XXX - can we remove pages by fiat like this??? */ 645 vp->v_pages = NULL; 646 } 647 mutex_destroy(&hp->hs_contents_lock); 648 vn_invalid(vp); 649 vn_free(vp); 650 kmem_cache_free(hsnode_cache, hp); 651 fsp->hsfs_nohsnode--; 652 return; 653 } 654 hs_addfreeb(fsp, hp); /* add to back of free list */ 655 } 656 657 /* 658 * hs_remakenode 659 * 660 * Reconstruct a vnode given the location of its directory entry. 661 * Caller specifies the the block number and offset 662 * of the directory entry, and the vfs pointer. 663 * Returns an error code or 0. 664 */ 665 int 666 hs_remakenode(uint_t lbn, uint_t off, struct vfs *vfsp, 667 struct vnode **vpp) 668 { 669 struct buf *secbp; 670 struct hsfs *fsp; 671 uint_t secno; 672 uchar_t *dirp; 673 struct hs_direntry hd; 674 int error; 675 676 /* Convert to sector and offset */ 677 fsp = VFS_TO_HSFS(vfsp); 678 if (off > HS_SECTOR_SIZE) { 679 cmn_err(CE_WARN, "hs_remakenode: bad offset"); 680 error = EINVAL; 681 goto end; 682 } 683 secno = LBN_TO_SEC(lbn, vfsp); 684 secbp = bread(fsp->hsfs_devvp->v_rdev, secno * 4, HS_SECTOR_SIZE); 685 686 error = geterror(secbp); 687 if (error != 0) { 688 cmn_err(CE_NOTE, "hs_remakenode: bread: error=(%d)", error); 689 goto end; 690 } 691 692 dirp = (uchar_t *)secbp->b_un.b_addr; 693 error = hs_parsedir(fsp, &dirp[off], &hd, (char *)NULL, (int *)NULL, 694 HS_SECTOR_SIZE - off); 695 if (!error) { 696 *vpp = hs_makenode(&hd, lbn, off, vfsp); 697 if (*vpp == NULL) 698 error = ENFILE; 699 } 700 701 end: 702 brelse(secbp); 703 return (error); 704 } 705 706 707 /* 708 * hs_dirlook 709 * 710 * Look for a given name in a given directory. 711 * If found, construct an hsnode for it. 712 */ 713 int 714 hs_dirlook( 715 struct vnode *dvp, 716 char *name, 717 int namlen, /* length of 'name' */ 718 struct vnode **vpp, 719 struct cred *cred) 720 { 721 struct hsnode *dhp; 722 struct hsfs *fsp; 723 int error = 0; 724 uint_t offset; /* real offset in directory */ 725 uint_t last_offset; /* last index into current dir block */ 726 char *cmpname; /* case-folded name */ 727 int cmpname_size; /* how much memory we allocate for it */ 728 int cmpnamelen; 729 int adhoc_search; /* did we start at begin of dir? */ 730 int end; 731 uint_t hsoffset; 732 struct fbuf *fbp; 733 int bytes_wanted; 734 int dirsiz; 735 int is_rrip; 736 737 if (dvp->v_type != VDIR) 738 return (ENOTDIR); 739 740 if (error = hs_access(dvp, (mode_t)VEXEC, cred)) 741 return (error); 742 743 if (hsfs_use_dnlc && (*vpp = dnlc_lookup(dvp, name))) 744 return (0); 745 746 dhp = VTOH(dvp); 747 fsp = VFS_TO_HSFS(dvp->v_vfsp); 748 is_rrip = IS_RRIP_IMPLEMENTED(fsp); 749 750 /* 751 * name == "^A" is illegal for ISO-9660 and Joliet as '..' is '\1' on 752 * disk. It is no problem for Rock Ridge as RR uses '.' and '..'. 753 * XXX It could be OK for Joliet also (because namelen == 1 is 754 * XXX impossible for UCS-2) but then we need a better compare algorith. 755 */ 756 if (!is_rrip && *name == '\1' && namlen == 1) 757 return (EINVAL); 758 759 cmpname_size = (int)(fsp->hsfs_namemax + 1); 760 cmpname = kmem_alloc((size_t)cmpname_size, KM_SLEEP); 761 762 if (namlen >= cmpname_size) 763 namlen = cmpname_size - 1; 764 /* 765 * For the purposes of comparing the name against dir entries, 766 * fold it to upper case. 767 */ 768 if (is_rrip) { 769 (void) strlcpy(cmpname, name, cmpname_size); 770 cmpnamelen = namlen; 771 } else { 772 /* 773 * If we don't consider a trailing dot as part of the filename, 774 * remove it from the specified name 775 */ 776 if ((fsp->hsfs_flags & HSFSMNT_NOTRAILDOT) && 777 name[namlen-1] == '.' && 778 CAN_TRUNCATE_DOT(name, namlen)) 779 name[--namlen] = '\0'; 780 if (fsp->hsfs_vol_type == HS_VOL_TYPE_ISO_V2 || 781 fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET) { 782 cmpnamelen = hs_iso_copy(name, cmpname, namlen); 783 } else { 784 cmpnamelen = hs_uppercase_copy(name, cmpname, namlen); 785 } 786 } 787 788 /* make sure dirent is filled up with all info */ 789 if (dhp->hs_dirent.ext_size == 0) 790 hs_filldirent(dvp, &dhp->hs_dirent); 791 792 /* 793 * No lock is needed - hs_offset is used as starting 794 * point for searching the directory. 795 */ 796 offset = dhp->hs_offset; 797 hsoffset = offset; 798 adhoc_search = (offset != 0); 799 800 end = dhp->hs_dirent.ext_size; 801 dirsiz = end; 802 803 tryagain: 804 805 while (offset < end) { 806 bytes_wanted = MIN(MAXBSIZE, dirsiz - (offset & MAXBMASK)); 807 808 error = fbread(dvp, (offset_t)(offset & MAXBMASK), 809 (unsigned int)bytes_wanted, S_READ, &fbp); 810 if (error) 811 goto done; 812 813 last_offset = (offset & MAXBMASK) + fbp->fb_count; 814 815 switch (process_dirblock(fbp, &offset, last_offset, 816 cmpname, cmpnamelen, fsp, dhp, dvp, vpp, &error)) { 817 case FOUND_ENTRY: 818 /* found an entry, either correct or not */ 819 goto done; 820 821 case WENT_PAST: 822 /* 823 * If we get here we know we didn't find it on the 824 * first pass. If adhoc_search, then we started a 825 * bit into the dir, and need to wrap around and 826 * search the first entries. If not, then we started 827 * at the beginning and didn't find it. 828 */ 829 if (adhoc_search) { 830 offset = 0; 831 end = hsoffset; 832 adhoc_search = 0; 833 goto tryagain; 834 } 835 error = ENOENT; 836 goto done; 837 838 case HIT_END: 839 goto tryagain; 840 } 841 } 842 /* 843 * End of all dir blocks, didn't find entry. 844 */ 845 if (adhoc_search) { 846 offset = 0; 847 end = hsoffset; 848 adhoc_search = 0; 849 goto tryagain; 850 } 851 error = ENOENT; 852 done: 853 /* 854 * If we found the entry, add it to the DNLC 855 * If the entry is a device file (assuming we support Rock Ridge), 856 * we enter the device vnode to the cache since that is what 857 * is in *vpp. 858 * That is ok since the CD-ROM is read-only, so (dvp,name) will 859 * always point to the same device. 860 */ 861 if (hsfs_use_dnlc && !error) 862 dnlc_enter(dvp, name, *vpp); 863 864 kmem_free(cmpname, (size_t)cmpname_size); 865 866 return (error); 867 } 868 869 /* 870 * hs_parsedir 871 * 872 * Parse a Directory Record into an hs_direntry structure. 873 * High Sierra and ISO directory are almost the same 874 * except the flag and date 875 */ 876 int 877 hs_parsedir( 878 struct hsfs *fsp, 879 uchar_t *dirp, 880 struct hs_direntry *hdp, 881 char *dnp, 882 int *dnlen, 883 int last_offset) 884 { 885 char *on_disk_name; 886 int on_disk_namelen; 887 int on_disk_dirlen; 888 uchar_t flags; 889 int namelen; 890 int error; 891 int name_change_flag = 0; /* set if name was gotten in SUA */ 892 893 hdp->ext_lbn = HDE_EXT_LBN(dirp); 894 hdp->ext_size = HDE_EXT_SIZE(dirp); 895 hdp->xar_len = HDE_XAR_LEN(dirp); 896 hdp->intlf_sz = HDE_INTRLV_SIZE(dirp); 897 hdp->intlf_sk = HDE_INTRLV_SKIP(dirp); 898 hdp->sym_link = (char *)NULL; 899 900 if (fsp->hsfs_vol_type == HS_VOL_TYPE_HS) { 901 flags = HDE_FLAGS(dirp); 902 hs_parse_dirdate(HDE_cdate(dirp), &hdp->cdate); 903 hs_parse_dirdate(HDE_cdate(dirp), &hdp->adate); 904 hs_parse_dirdate(HDE_cdate(dirp), &hdp->mdate); 905 if ((flags & hde_prohibited) == 0) { 906 /* 907 * Skip files with the associated bit set. 908 */ 909 if (flags & HDE_ASSOCIATED) 910 return (EAGAIN); 911 hdp->type = VREG; 912 hdp->mode = HFREG; 913 hdp->nlink = 1; 914 } else if ((flags & hde_prohibited) == HDE_DIRECTORY) { 915 hdp->type = VDIR; 916 hdp->mode = HFDIR; 917 hdp->nlink = 2; 918 } else { 919 hs_log_bogus_disk_warning(fsp, 920 HSFS_ERR_UNSUP_TYPE, flags); 921 return (EINVAL); 922 } 923 hdp->uid = fsp -> hsfs_vol.vol_uid; 924 hdp->gid = fsp -> hsfs_vol.vol_gid; 925 hdp->mode = hdp-> mode | (fsp -> hsfs_vol.vol_prot & 0777); 926 } else if ((fsp->hsfs_vol_type == HS_VOL_TYPE_ISO) || 927 (fsp->hsfs_vol_type == HS_VOL_TYPE_ISO_V2) || 928 (fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET)) { 929 930 flags = IDE_FLAGS(dirp); 931 hs_parse_dirdate(IDE_cdate(dirp), &hdp->cdate); 932 hs_parse_dirdate(IDE_cdate(dirp), &hdp->adate); 933 hs_parse_dirdate(IDE_cdate(dirp), &hdp->mdate); 934 935 if ((flags & ide_prohibited) == 0) { 936 /* 937 * Skip files with the associated bit set. 938 */ 939 if (flags & IDE_ASSOCIATED) 940 return (EAGAIN); 941 hdp->type = VREG; 942 hdp->mode = HFREG; 943 hdp->nlink = 1; 944 } else if ((flags & ide_prohibited) == IDE_DIRECTORY) { 945 hdp->type = VDIR; 946 hdp->mode = HFDIR; 947 hdp->nlink = 2; 948 } else { 949 hs_log_bogus_disk_warning(fsp, 950 HSFS_ERR_UNSUP_TYPE, flags); 951 return (EINVAL); 952 } 953 hdp->uid = fsp -> hsfs_vol.vol_uid; 954 hdp->gid = fsp -> hsfs_vol.vol_gid; 955 hdp->mode = hdp-> mode | (fsp -> hsfs_vol.vol_prot & 0777); 956 957 /* 958 * Having this all filled in, let's see if we have any 959 * SUA susp to look at. 960 */ 961 if (IS_SUSP_IMPLEMENTED(fsp)) { 962 error = parse_sua((uchar_t *)dnp, dnlen, 963 &name_change_flag, dirp, hdp, fsp, 964 (uchar_t *)NULL, NULL); 965 if (error) { 966 if (hdp->sym_link) { 967 kmem_free(hdp->sym_link, 968 (size_t)(hdp->ext_size + 1)); 969 hdp->sym_link = (char *)NULL; 970 } 971 return (error); 972 } 973 } 974 } 975 hdp->xar_prot = (HDE_PROTECTION & flags) != 0; 976 977 #if dontskip 978 if (hdp->xar_len > 0) { 979 cmn_err(CE_NOTE, "hsfs: extended attributes not supported"); 980 return (EINVAL); 981 } 982 #endif 983 984 /* check interleaf size and skip factor */ 985 /* must both be zero or non-zero */ 986 if (hdp->intlf_sz + hdp->intlf_sk) { 987 if ((hdp->intlf_sz == 0) || (hdp->intlf_sk == 0)) { 988 cmn_err(CE_NOTE, 989 "hsfs: interleaf size or skip factor error"); 990 return (EINVAL); 991 } 992 if (hdp->ext_size == 0) { 993 cmn_err(CE_NOTE, 994 "hsfs: interleaving specified on zero length file"); 995 return (EINVAL); 996 } 997 } 998 999 if (HDE_VOL_SET(dirp) != 1) { 1000 if (fsp->hsfs_vol.vol_set_size != 1 && 1001 fsp->hsfs_vol.vol_set_size != HDE_VOL_SET(dirp)) { 1002 cmn_err(CE_NOTE, "hsfs: multivolume file?"); 1003 return (EINVAL); 1004 } 1005 } 1006 1007 /* 1008 * If the name changed, then the NM field for RRIP was hit and 1009 * we should not copy the name again, just return. 1010 */ 1011 if (NAME_HAS_CHANGED(name_change_flag)) 1012 return (0); 1013 1014 /* 1015 * Fall back to the ISO name. Note that as in process_dirblock, 1016 * the on-disk filename length must be validated against ISO 1017 * limits - which, in case of RR present but no RR name found, 1018 * are NOT identical to fsp->hsfs_namemax on this filesystem. 1019 */ 1020 on_disk_name = (char *)HDE_name(dirp); 1021 on_disk_namelen = (int)HDE_NAME_LEN(dirp); 1022 on_disk_dirlen = (int)HDE_DIR_LEN(dirp); 1023 1024 if (on_disk_dirlen < HDE_ROOT_DIR_REC_SIZE || 1025 ((on_disk_dirlen > last_offset) || 1026 ((HDE_FDESIZE + on_disk_namelen) > on_disk_dirlen))) { 1027 hs_log_bogus_disk_warning(fsp, 1028 HSFS_ERR_BAD_DIR_ENTRY, 0); 1029 return (EINVAL); 1030 } 1031 1032 if (on_disk_namelen > fsp->hsfs_namelen && 1033 hs_namelen(fsp, on_disk_name, on_disk_namelen) > 1034 fsp->hsfs_namelen) { 1035 hs_log_bogus_disk_warning(fsp, 1036 fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET ? 1037 HSFS_ERR_BAD_JOLIET_FILE_LEN : 1038 HSFS_ERR_BAD_FILE_LEN, 1039 0); 1040 } 1041 if (on_disk_namelen > ISO_NAMELEN_V2_MAX) 1042 on_disk_namelen = fsp->hsfs_namemax; /* Paranoia */ 1043 1044 if (dnp != NULL) { 1045 if (fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET) { 1046 namelen = hs_jnamecopy(on_disk_name, dnp, 1047 on_disk_namelen, 1048 fsp->hsfs_namemax, 1049 fsp->hsfs_flags); 1050 /* 1051 * A negative return value means that the file name 1052 * has been truncated to fsp->hsfs_namemax. 1053 */ 1054 if (namelen < 0) { 1055 namelen = -namelen; 1056 hs_log_bogus_disk_warning(fsp, 1057 HSFS_ERR_TRUNC_JOLIET_FILE_LEN, 1058 0); 1059 } 1060 } else { 1061 /* 1062 * HS_VOL_TYPE_ISO && HS_VOL_TYPE_ISO_V2 1063 */ 1064 namelen = hs_namecopy(on_disk_name, dnp, 1065 on_disk_namelen, 1066 fsp->hsfs_flags); 1067 } 1068 if (namelen == 0) 1069 return (EINVAL); 1070 if ((fsp->hsfs_flags & HSFSMNT_NOTRAILDOT) && 1071 dnp[ namelen-1 ] == '.' && CAN_TRUNCATE_DOT(dnp, namelen)) 1072 dnp[ --namelen ] = '\0'; 1073 } else 1074 namelen = on_disk_namelen; 1075 if (dnlen != NULL) 1076 *dnlen = namelen; 1077 1078 return (0); 1079 } 1080 1081 /* 1082 * hs_namecopy 1083 * 1084 * Parse a file/directory name into UNIX form. 1085 * Delete trailing blanks, upper-to-lower case, add NULL terminator. 1086 * Returns the (possibly new) length. 1087 * 1088 * Called from hsfs_readdir() via hs_parsedir() 1089 */ 1090 int 1091 hs_namecopy(char *from, char *to, int size, ulong_t flags) 1092 { 1093 uint_t i; 1094 uchar_t c; 1095 int lastspace; 1096 int maplc; 1097 int trailspace; 1098 int version; 1099 1100 /* special handling for '.' and '..' */ 1101 if (size == 1) { 1102 if (*from == '\0') { 1103 *to++ = '.'; 1104 *to = '\0'; 1105 return (1); 1106 } else if (*from == '\1') { 1107 *to++ = '.'; 1108 *to++ = '.'; 1109 *to = '\0'; 1110 return (2); 1111 } 1112 } 1113 1114 maplc = (flags & HSFSMNT_NOMAPLCASE) == 0; 1115 trailspace = (flags & HSFSMNT_NOTRAILSPACE) == 0; 1116 version = (flags & HSFSMNT_NOVERSION) == 0; 1117 for (i = 0, lastspace = -1; i < size; i++) { 1118 c = from[i]; 1119 if (c == ';' && version) 1120 break; 1121 if (c <= ' ' && !trailspace) { 1122 if (lastspace == -1) 1123 lastspace = i; 1124 } else 1125 lastspace = -1; 1126 if (maplc && (c >= 'A') && (c <= 'Z')) 1127 c += 'a' - 'A'; 1128 to[i] = c; 1129 } 1130 if (lastspace != -1) 1131 i = lastspace; 1132 to[i] = '\0'; 1133 return (i); 1134 } 1135 1136 /* 1137 * hs_jnamecopy 1138 * 1139 * This is the Joliet variant of hs_namecopy() 1140 * 1141 * Parse a UCS-2 Joliet file/directory name into UNIX form. 1142 * Add NULL terminator. 1143 * Returns the new length. 1144 * 1145 * Called from hsfs_readdir() via hs_parsedir() 1146 */ 1147 int 1148 hs_jnamecopy(char *from, char *to, int size, int maxsize, ulong_t flags) 1149 { 1150 uint_t i; 1151 uint_t len; 1152 uint16_t c; 1153 int amt; 1154 int version; 1155 1156 /* special handling for '.' and '..' */ 1157 if (size == 1) { 1158 if (*from == '\0') { 1159 *to++ = '.'; 1160 *to = '\0'; 1161 return (1); 1162 } else if (*from == '\1') { 1163 *to++ = '.'; 1164 *to++ = '.'; 1165 *to = '\0'; 1166 return (2); 1167 } 1168 } 1169 1170 version = (flags & HSFSMNT_NOVERSION) == 0; 1171 for (i = 0, len = 0; i < size; i++) { 1172 c = (from[i++] & 0xFF) << 8; 1173 c |= from[i] & 0xFF; 1174 if (c == ';' && version) 1175 break; 1176 1177 if (len > (maxsize-3)) { 1178 if (c < 0x80) 1179 amt = 1; 1180 else if (c < 0x800) 1181 amt = 2; 1182 else 1183 amt = 3; 1184 if ((len+amt) > maxsize) { 1185 to[len] = '\0'; 1186 return (-len); 1187 } 1188 } 1189 amt = hs_ucs2_2_utf8(c, (uint8_t *)&to[len]); 1190 if (amt == 0) { 1191 hs_log_bogus_joliet_warning(); /* should never happen */ 1192 return (0); 1193 } 1194 len += amt; 1195 } 1196 to[len] = '\0'; 1197 return (len); 1198 } 1199 1200 /* 1201 * map a filename to upper case; 1202 * return 1 if found lowercase character 1203 * 1204 * Called from process_dirblock() 1205 * via hsfs_lookup() -> hs_dirlook() -> process_dirblock() 1206 * to create an intermedia name from on disk file names for 1207 * comparing names. 1208 */ 1209 static int 1210 uppercase_cp(char *from, char *to, int size) 1211 { 1212 uint_t i; 1213 uchar_t c; 1214 uchar_t had_lc = 0; 1215 1216 for (i = 0; i < size; i++) { 1217 c = *from++; 1218 if ((c >= 'a') && (c <= 'z')) { 1219 c -= ('a' - 'A'); 1220 had_lc = 1; 1221 } 1222 *to++ = c; 1223 } 1224 return (had_lc); 1225 } 1226 1227 /* 1228 * This is the Joliet variant of uppercase_cp() 1229 * 1230 * map a UCS-2 filename to UTF-8; 1231 * return new length 1232 * 1233 * Called from process_dirblock() 1234 * via hsfs_lookup() -> hs_dirlook() -> process_dirblock() 1235 * to create an intermedia name from on disk file names for 1236 * comparing names. 1237 */ 1238 int 1239 hs_joliet_cp(char *from, char *to, int size) 1240 { 1241 uint_t i; 1242 uint16_t c; 1243 int len = 0; 1244 int amt; 1245 1246 /* special handling for '\0' and '\1' */ 1247 if (size == 1) { 1248 *to = *from; 1249 return (1); 1250 } 1251 for (i = 0; i < size; i += 2) { 1252 c = (*from++ & 0xFF) << 8; 1253 c |= *from++ & 0xFF; 1254 1255 amt = hs_ucs2_2_utf8(c, (uint8_t *)to); 1256 if (amt == 0) { 1257 hs_log_bogus_joliet_warning(); /* should never happen */ 1258 return (0); 1259 } 1260 1261 to += amt; 1262 len += amt; 1263 } 1264 return (len); 1265 } 1266 1267 static void 1268 hs_log_bogus_joliet_warning(void) 1269 { 1270 static int warned = 0; 1271 1272 if (warned) 1273 return; 1274 warned = 1; 1275 cmn_err(CE_CONT, "hsfs: Warning: " 1276 "file name contains bad UCS-2 chacarter\n"); 1277 } 1278 1279 1280 /* 1281 * hs_uppercase_copy 1282 * 1283 * Convert a UNIX-style name into its HSFS equivalent 1284 * replacing '.' and '..' with '\0' and '\1'. 1285 * Map to upper case. 1286 * Returns the (possibly new) length. 1287 * 1288 * Called from hs_dirlook() and rrip_namecopy() 1289 * to create an intermediate name from the callers name from hsfs_lookup() 1290 * XXX Is the call from rrip_namecopy() OK? 1291 */ 1292 int 1293 hs_uppercase_copy(char *from, char *to, int size) 1294 { 1295 uint_t i; 1296 uchar_t c; 1297 1298 /* special handling for '.' and '..' */ 1299 1300 if (size == 1 && *from == '.') { 1301 *to = '\0'; 1302 return (1); 1303 } else if (size == 2 && *from == '.' && *(from+1) == '.') { 1304 *to = '\1'; 1305 return (1); 1306 } 1307 1308 for (i = 0; i < size; i++) { 1309 c = *from++; 1310 if ((c >= 'a') && (c <= 'z')) 1311 c = c - 'a' + 'A'; 1312 *to++ = c; 1313 } 1314 return (size); 1315 } 1316 1317 /* 1318 * hs_iso_copy 1319 * 1320 * This is the Joliet/ISO-9660:1999 variant of hs_uppercase_copy() 1321 * 1322 * Convert a UTF-8 UNIX-style name into its UTF-8 Joliet/ISO equivalent 1323 * replacing '.' and '..' with '\0' and '\1'. 1324 * Returns the (possibly new) length. 1325 * 1326 * Called from hs_dirlook() 1327 * to create an intermediate name from the callers name from hsfs_lookup() 1328 */ 1329 static int 1330 hs_iso_copy(char *from, char *to, int size) 1331 { 1332 uint_t i; 1333 uchar_t c; 1334 1335 /* special handling for '.' and '..' */ 1336 1337 if (size == 1 && *from == '.') { 1338 *to = '\0'; 1339 return (1); 1340 } else if (size == 2 && *from == '.' && *(from+1) == '.') { 1341 *to = '\1'; 1342 return (1); 1343 } 1344 1345 for (i = 0; i < size; i++) { 1346 c = *from++; 1347 *to++ = c; 1348 } 1349 return (size); 1350 } 1351 1352 void 1353 hs_filldirent(struct vnode *vp, struct hs_direntry *hdp) 1354 { 1355 struct buf *secbp; 1356 uint_t secno; 1357 offset_t secoff; 1358 struct hsfs *fsp; 1359 uchar_t *secp; 1360 int error; 1361 1362 if (vp->v_type != VDIR) { 1363 cmn_err(CE_WARN, "hsfs_filldirent: vp (0x%p) not a directory", 1364 (void *)vp); 1365 return; 1366 } 1367 1368 fsp = VFS_TO_HSFS(vp ->v_vfsp); 1369 secno = LBN_TO_SEC(hdp->ext_lbn+hdp->xar_len, vp->v_vfsp); 1370 secoff = LBN_TO_BYTE(hdp->ext_lbn+hdp->xar_len, vp->v_vfsp) & 1371 MAXHSOFFSET; 1372 secbp = bread(fsp->hsfs_devvp->v_rdev, secno * 4, HS_SECTOR_SIZE); 1373 error = geterror(secbp); 1374 if (error != 0) { 1375 cmn_err(CE_NOTE, "hs_filldirent: bread: error=(%d)", error); 1376 goto end; 1377 } 1378 1379 secp = (uchar_t *)secbp->b_un.b_addr; 1380 1381 /* quick check */ 1382 if (hdp->ext_lbn != HDE_EXT_LBN(&secp[secoff])) { 1383 cmn_err(CE_NOTE, "hsfs_filldirent: dirent not match"); 1384 /* keep on going */ 1385 } 1386 (void) hs_parsedir(fsp, &secp[secoff], hdp, (char *)NULL, 1387 (int *)NULL, HS_SECTOR_SIZE - secoff); 1388 1389 end: 1390 brelse(secbp); 1391 } 1392 1393 /* 1394 * Look through a directory block for a matching entry. 1395 * Note: this routine does an fbrelse() on the buffer passed in. 1396 */ 1397 static enum dirblock_result 1398 process_dirblock( 1399 struct fbuf *fbp, /* buffer containing dirblk */ 1400 uint_t *offset, /* lower index */ 1401 uint_t last_offset, /* upper index */ 1402 char *nm, /* upcase nm to compare against */ 1403 int nmlen, /* length of name */ 1404 struct hsfs *fsp, 1405 struct hsnode *dhp, 1406 struct vnode *dvp, 1407 struct vnode **vpp, 1408 int *error) /* return value: errno */ 1409 { 1410 uchar_t *blkp = (uchar_t *)fbp->fb_addr; /* dir block */ 1411 char *dname; /* name in directory entry */ 1412 int dnamelen; /* length of name */ 1413 struct hs_direntry hd; 1414 int hdlen; 1415 uchar_t *dirp; /* the directory entry */ 1416 int res; 1417 int parsedir_res; 1418 int is_rrip; 1419 size_t rrip_name_size; 1420 int rr_namelen = 0; 1421 char *rrip_name_str = NULL; 1422 char *rrip_tmp_name = NULL; 1423 enum dirblock_result err = 0; 1424 int did_fbrelse = 0; 1425 char uppercase_name[JOLIET_NAMELEN_MAX*3 + 1]; /* 331 */ 1426 1427 #define PD_return(retval) \ 1428 { err = retval; goto do_ret; } /* return after cleanup */ 1429 #define rel_offset(offset) \ 1430 ((offset) & MAXBOFFSET) /* index into cur blk */ 1431 #define RESTORE_NM(tmp, orig) \ 1432 if (is_rrip && *(tmp) != '\0') \ 1433 (void) strcpy((orig), (tmp)) 1434 1435 is_rrip = IS_RRIP_IMPLEMENTED(fsp); 1436 if (is_rrip) { 1437 rrip_name_size = RRIP_FILE_NAMELEN + 1; 1438 rrip_name_str = kmem_alloc(rrip_name_size, KM_SLEEP); 1439 rrip_tmp_name = kmem_alloc(rrip_name_size, KM_SLEEP); 1440 rrip_name_str[0] = '\0'; 1441 rrip_tmp_name[0] = '\0'; 1442 } 1443 1444 while (*offset < last_offset) { 1445 1446 /* 1447 * Directory Entries cannot span sectors. 1448 * 1449 * Unused bytes at the end of each sector are zeroed 1450 * according to ISO9660, but we cannot rely on this 1451 * since both media failures and maliciously corrupted 1452 * media may return arbitrary values. 1453 * We therefore have to check for consistency: 1454 * The size of a directory entry must be at least 1455 * 34 bytes (the size of the directory entry metadata), 1456 * or zero (indicating the end-of-sector condition). 1457 * For a non-zero directory entry size of less than 1458 * 34 Bytes, log a warning. 1459 * In any case, skip the rest of this sector and 1460 * continue with the next. 1461 */ 1462 hdlen = (int)((uchar_t) 1463 HDE_DIR_LEN(&blkp[rel_offset(*offset)])); 1464 1465 if (hdlen < HDE_ROOT_DIR_REC_SIZE || 1466 *offset + hdlen > last_offset) { 1467 /* 1468 * Advance to the next sector boundary 1469 */ 1470 *offset = roundup(*offset + 1, HS_SECTOR_SIZE); 1471 if (hdlen) 1472 hs_log_bogus_disk_warning(fsp, 1473 HSFS_ERR_TRAILING_JUNK, 0); 1474 continue; 1475 } 1476 1477 bzero(&hd, sizeof (hd)); 1478 1479 /* 1480 * Check the filename length in the ISO record for 1481 * plausibility and reset it to a safe value, in case 1482 * the name length byte is out of range. Since the ISO 1483 * name will be used as fallback if the rockridge name 1484 * is invalid/nonexistant, we must make sure not to 1485 * blow the bounds and initialize dnamelen to a sensible 1486 * value within the limits of ISO9660. 1487 * In addition to that, the ISO filename is part of the 1488 * directory entry. If the filename length is too large 1489 * to fit, the record is invalid and we'll advance to 1490 * the next. 1491 */ 1492 dirp = &blkp[rel_offset(*offset)]; 1493 dname = (char *)HDE_name(dirp); 1494 dnamelen = (int)((uchar_t)HDE_NAME_LEN(dirp)); 1495 /* 1496 * If the directory entry extends beyond the end of the 1497 * block, it must be invalid. Skip it. 1498 */ 1499 if (dnamelen > hdlen - HDE_FDESIZE) { 1500 hs_log_bogus_disk_warning(fsp, 1501 HSFS_ERR_BAD_DIR_ENTRY, 0); 1502 goto skip_rec; 1503 } else if (dnamelen > fsp->hsfs_namelen && 1504 hs_namelen(fsp, dname, dnamelen) > fsp->hsfs_namelen) { 1505 hs_log_bogus_disk_warning(fsp, 1506 fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET ? 1507 HSFS_ERR_BAD_JOLIET_FILE_LEN : 1508 HSFS_ERR_BAD_FILE_LEN, 1509 0); 1510 } 1511 if (dnamelen > ISO_NAMELEN_V2_MAX) 1512 dnamelen = fsp->hsfs_namemax; /* Paranoia */ 1513 1514 /* 1515 * If the rock ridge is implemented, then we copy the name 1516 * from the SUA area to rrip_name_str. If no Alternate 1517 * name is found, then use the uppercase NM in the 1518 * rrip_name_str char array. 1519 */ 1520 if (is_rrip) { 1521 1522 rrip_name_str[0] = '\0'; 1523 rr_namelen = rrip_namecopy(nm, &rrip_name_str[0], 1524 &rrip_tmp_name[0], dirp, fsp, &hd); 1525 if (hd.sym_link) { 1526 kmem_free(hd.sym_link, 1527 (size_t)(hd.ext_size+1)); 1528 hd.sym_link = (char *)NULL; 1529 } 1530 1531 if (rr_namelen != -1) { 1532 dname = (char *)&rrip_name_str[0]; 1533 dnamelen = rr_namelen; 1534 } 1535 } 1536 1537 if (!is_rrip || rr_namelen == -1) { 1538 /* use iso name instead */ 1539 1540 int i = -1; 1541 /* 1542 * make sure that we get rid of ';' in the dname of 1543 * an iso direntry, as we should have no knowledge 1544 * of file versions. 1545 * 1546 * XXX This is done the wrong way: it does not take 1547 * XXX care of the fact that the version string is 1548 * XXX a decimal number in the range 1 to 32767. 1549 */ 1550 if ((fsp->hsfs_flags & HSFSMNT_NOVERSION) == 0) { 1551 if (fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET) { 1552 for (i = dnamelen - 1; i > 0; i -= 2) { 1553 if (dname[i] == ';' && 1554 dname[i-1] == '\0') { 1555 --i; 1556 break; 1557 } 1558 } 1559 } else { 1560 for (i = dnamelen - 1; i > 0; i--) { 1561 if (dname[i] == ';') 1562 break; 1563 } 1564 } 1565 } 1566 if (i > 0) { 1567 dnamelen = i; 1568 } else if (fsp->hsfs_vol_type != HS_VOL_TYPE_ISO_V2 && 1569 fsp->hsfs_vol_type != HS_VOL_TYPE_JOLIET) { 1570 dnamelen = strip_trailing(fsp, dname, dnamelen); 1571 } 1572 1573 ASSERT(dnamelen < sizeof (uppercase_name)); 1574 1575 if (fsp->hsfs_vol_type == HS_VOL_TYPE_ISO_V2) { 1576 (void) strncpy(uppercase_name, dname, dnamelen); 1577 } else if (fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET) { 1578 dnamelen = hs_joliet_cp(dname, uppercase_name, 1579 dnamelen); 1580 } else if (uppercase_cp(dname, uppercase_name, 1581 dnamelen)) { 1582 hs_log_bogus_disk_warning(fsp, 1583 HSFS_ERR_LOWER_CASE_NM, 0); 1584 } 1585 dname = uppercase_name; 1586 if (!is_rrip && 1587 (fsp->hsfs_flags & HSFSMNT_NOTRAILDOT) && 1588 dname[dnamelen - 1] == '.' && 1589 CAN_TRUNCATE_DOT(dname, dnamelen)) 1590 dname[--dnamelen] = '\0'; 1591 } 1592 1593 /* 1594 * Quickly screen for a non-matching entry, but not for RRIP. 1595 * This test doesn't work for lowercase vs. uppercase names. 1596 */ 1597 1598 /* if we saw a lower case name we can't do this test either */ 1599 if (strict_iso9660_ordering && !is_rrip && 1600 !HSFS_HAVE_LOWER_CASE(fsp) && *nm < *dname) { 1601 RESTORE_NM(rrip_tmp_name, nm); 1602 PD_return(WENT_PAST) 1603 } 1604 1605 if (*nm != *dname || nmlen != dnamelen) 1606 goto skip_rec; 1607 1608 if ((res = bcmp(dname, nm, nmlen)) == 0) { 1609 /* name matches */ 1610 parsedir_res = hs_parsedir(fsp, dirp, &hd, 1611 (char *)NULL, (int *)NULL, 1612 last_offset - rel_offset(*offset)); 1613 if (!parsedir_res) { 1614 uint_t lbn; /* logical block number */ 1615 1616 lbn = dhp->hs_dirent.ext_lbn + 1617 dhp->hs_dirent.xar_len; 1618 /* 1619 * Need to do an fbrelse() on the buffer, 1620 * as hs_makenode() may try to acquire 1621 * hs_hashlock, which may not be required 1622 * while a page is locked. 1623 */ 1624 fbrelse(fbp, S_READ); 1625 did_fbrelse = 1; 1626 *vpp = hs_makenode(&hd, lbn, *offset, 1627 dvp->v_vfsp); 1628 if (*vpp == NULL) { 1629 *error = ENFILE; 1630 RESTORE_NM(rrip_tmp_name, nm); 1631 PD_return(FOUND_ENTRY) 1632 } 1633 1634 dhp->hs_offset = *offset; 1635 RESTORE_NM(rrip_tmp_name, nm); 1636 PD_return(FOUND_ENTRY) 1637 } else if (parsedir_res != EAGAIN) { 1638 /* improper dir entry */ 1639 *error = parsedir_res; 1640 RESTORE_NM(rrip_tmp_name, nm); 1641 PD_return(FOUND_ENTRY) 1642 } 1643 } else if (strict_iso9660_ordering && !is_rrip && 1644 !HSFS_HAVE_LOWER_CASE(fsp) && res < 0) { 1645 /* name < dir entry */ 1646 RESTORE_NM(rrip_tmp_name, nm); 1647 PD_return(WENT_PAST) 1648 } 1649 /* 1650 * name > dir entry, 1651 * look at next one. 1652 */ 1653 skip_rec: 1654 *offset += hdlen; 1655 RESTORE_NM(rrip_tmp_name, nm); 1656 } 1657 PD_return(HIT_END) 1658 1659 do_ret: 1660 if (rrip_name_str) 1661 kmem_free(rrip_name_str, rrip_name_size); 1662 if (rrip_tmp_name) 1663 kmem_free(rrip_tmp_name, rrip_name_size); 1664 if (!did_fbrelse) 1665 fbrelse(fbp, S_READ); 1666 return (err); 1667 #undef PD_return 1668 #undef RESTORE_NM 1669 } 1670 1671 /* 1672 * Strip trailing nulls or spaces from the name; 1673 * return adjusted length. If we find such junk, 1674 * log a non-conformant disk message. 1675 */ 1676 static int 1677 strip_trailing(struct hsfs *fsp, char *nm, int len) 1678 { 1679 char *c; 1680 int trailing_junk = 0; 1681 1682 for (c = nm + len - 1; c > nm; c--) { 1683 if (*c == ' ' || *c == '\0') 1684 trailing_junk = 1; 1685 else 1686 break; 1687 } 1688 1689 if (trailing_junk) 1690 hs_log_bogus_disk_warning(fsp, HSFS_ERR_TRAILING_JUNK, 0); 1691 1692 return ((int)(c - nm + 1)); 1693 } 1694 1695 static int 1696 hs_namelen(struct hsfs *fsp, char *nm, int len) 1697 { 1698 char *p = nm + len; 1699 1700 if (fsp->hsfs_vol_type == HS_VOL_TYPE_ISO_V2) { 1701 return (len); 1702 } else if (fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET) { 1703 uint16_t c; 1704 1705 while (--p > &nm[1]) { 1706 c = *p; 1707 c |= *--p * 256; 1708 if (c == ';') 1709 return (p - nm); 1710 if (c < '0' || c > '9') { 1711 p++; 1712 return (p - nm); 1713 } 1714 } 1715 } else { 1716 char c; 1717 1718 while (--p > nm) { 1719 c = *p; 1720 if (c == ';') 1721 return (p - nm); 1722 if (c < '0' || c > '9') { 1723 p++; 1724 return (p - nm); 1725 } 1726 } 1727 } 1728 return (len); 1729 } 1730 1731 /* 1732 * Take a UCS-2 character and convert 1733 * it into a utf8 character. 1734 * A 0 will be returned if the conversion fails 1735 * 1736 * See http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 1737 * 1738 * The code has been taken from udfs/udf_subr.c 1739 */ 1740 static uint8_t hs_first_byte_mark[7] = 1741 { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; 1742 static int32_t 1743 hs_ucs2_2_utf8(uint16_t c_16, uint8_t *s_8) 1744 { 1745 int32_t nc; 1746 uint32_t c_32; 1747 uint32_t byte_mask = 0xBF; 1748 uint32_t byte_mark = 0x80; 1749 1750 /* 1751 * Convert the 16-bit character to a 32-bit character 1752 */ 1753 c_32 = c_16; 1754 1755 /* 1756 * By here the 16-bit character is converted 1757 * to a 32-bit wide character 1758 */ 1759 if (c_32 < 0x80) { 1760 nc = 1; 1761 } else if (c_32 < 0x800) { 1762 nc = 2; 1763 } else if (c_32 < 0x10000) { 1764 nc = 3; 1765 } else if (c_32 < 0x200000) { 1766 nc = 4; 1767 } else if (c_32 < 0x4000000) { 1768 nc = 5; 1769 } else if (c_32 <= 0x7FFFFFFF) { /* avoid signed overflow */ 1770 nc = 6; 1771 } else { 1772 nc = 0; 1773 } 1774 s_8 += nc; 1775 switch (nc) { 1776 case 6 : 1777 *(--s_8) = (c_32 | byte_mark) & byte_mask; 1778 c_32 >>= 6; 1779 /* FALLTHROUGH */ 1780 case 5 : 1781 *(--s_8) = (c_32 | byte_mark) & byte_mask; 1782 c_32 >>= 6; 1783 /* FALLTHROUGH */ 1784 case 4 : 1785 *(--s_8) = (c_32 | byte_mark) & byte_mask; 1786 c_32 >>= 6; 1787 /* FALLTHROUGH */ 1788 case 3 : 1789 *(--s_8) = (c_32 | byte_mark) & byte_mask; 1790 c_32 >>= 6; 1791 /* FALLTHROUGH */ 1792 case 2 : 1793 *(--s_8) = (c_32 | byte_mark) & byte_mask; 1794 c_32 >>= 6; 1795 /* FALLTHROUGH */ 1796 case 1 : 1797 *(--s_8) = c_32 | hs_first_byte_mark[nc]; 1798 } 1799 return (nc); 1800 } 1801