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