17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5fc1c62b8Sfrankho * Common Development and Distribution License (the "License"). 6fc1c62b8Sfrankho * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*134a1f4eSCasper H.S. Dik * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved. 237c478bd9Sstevel@tonic-gate */ 247c478bd9Sstevel@tonic-gate 257c478bd9Sstevel@tonic-gate /* 267c478bd9Sstevel@tonic-gate * Directory operations for High Sierra filesystem 277c478bd9Sstevel@tonic-gate */ 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <sys/types.h> 307c478bd9Sstevel@tonic-gate #include <sys/t_lock.h> 317c478bd9Sstevel@tonic-gate #include <sys/param.h> 327c478bd9Sstevel@tonic-gate #include <sys/systm.h> 337c478bd9Sstevel@tonic-gate #include <sys/cred.h> 347c478bd9Sstevel@tonic-gate #include <sys/user.h> 357c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 367c478bd9Sstevel@tonic-gate #include <sys/stat.h> 377c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 387c478bd9Sstevel@tonic-gate #include <sys/mode.h> 397c478bd9Sstevel@tonic-gate #include <sys/dnlc.h> 407c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 417c478bd9Sstevel@tonic-gate #include <sys/fbuf.h> 427c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 437c478bd9Sstevel@tonic-gate #include <sys/policy.h> 44cf83459aSfrankho #include <sys/sunddi.h> 457c478bd9Sstevel@tonic-gate #include <vm/hat.h> 467c478bd9Sstevel@tonic-gate #include <vm/as.h> 477c478bd9Sstevel@tonic-gate #include <vm/pvn.h> 487c478bd9Sstevel@tonic-gate #include <vm/seg.h> 497c478bd9Sstevel@tonic-gate #include <vm/seg_map.h> 507c478bd9Sstevel@tonic-gate #include <vm/seg_kmem.h> 517c478bd9Sstevel@tonic-gate #include <vm/page.h> 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate #include <sys/fs/hsfs_spec.h> 547c478bd9Sstevel@tonic-gate #include <sys/fs/hsfs_isospec.h> 557c478bd9Sstevel@tonic-gate #include <sys/fs/hsfs_node.h> 567c478bd9Sstevel@tonic-gate #include <sys/fs/hsfs_impl.h> 577c478bd9Sstevel@tonic-gate #include <sys/fs/hsfs_susp.h> 587c478bd9Sstevel@tonic-gate #include <sys/fs/hsfs_rrip.h> 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate #include <sys/sysinfo.h> 617c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 627c478bd9Sstevel@tonic-gate #include <sys/errno.h> 637c478bd9Sstevel@tonic-gate #include <sys/debug.h> 647c478bd9Sstevel@tonic-gate #include <fs/fs_subr.h> 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate /* 677c478bd9Sstevel@tonic-gate * This macro expects a name that ends in '.' and returns TRUE if the 687c478bd9Sstevel@tonic-gate * name is not "." or ".." 697c478bd9Sstevel@tonic-gate */ 707c478bd9Sstevel@tonic-gate #define CAN_TRUNCATE_DOT(name, namelen) \ 717c478bd9Sstevel@tonic-gate (namelen > 1 && (namelen > 2 || name[0] != '.')) 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate enum dirblock_result { FOUND_ENTRY, WENT_PAST, HIT_END }; 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate /* 767c478bd9Sstevel@tonic-gate * These values determine whether we will try to read a file or dir; 777c478bd9Sstevel@tonic-gate * they may be patched via /etc/system to allow users to read 787c478bd9Sstevel@tonic-gate * record-oriented files. 797c478bd9Sstevel@tonic-gate */ 807c478bd9Sstevel@tonic-gate int ide_prohibited = IDE_PROHIBITED; 817c478bd9Sstevel@tonic-gate int hde_prohibited = HDE_PROHIBITED; 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate /* 847c478bd9Sstevel@tonic-gate * This variable determines if the HSFS code will use the 857c478bd9Sstevel@tonic-gate * directory name lookup cache. The default is for the cache to be used. 867c478bd9Sstevel@tonic-gate */ 877c478bd9Sstevel@tonic-gate static int hsfs_use_dnlc = 1; 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate /* 907c478bd9Sstevel@tonic-gate * This variable determines whether strict ISO-9660 directory ordering 917c478bd9Sstevel@tonic-gate * is to be assumed. If false (which it is by default), then when 927c478bd9Sstevel@tonic-gate * searching a directory of an ISO-9660 disk, we do not expect the 937c478bd9Sstevel@tonic-gate * entries to be sorted (as the spec requires), and so cannot terminate 947c478bd9Sstevel@tonic-gate * the search early. Unfortunately, some vendors are producing 957c478bd9Sstevel@tonic-gate * non-compliant disks. This variable exists to revert to the old 967c478bd9Sstevel@tonic-gate * behavior in case someone relies on this. This option is expected to be 977c478bd9Sstevel@tonic-gate * removed at some point in the future. 987c478bd9Sstevel@tonic-gate * 997c478bd9Sstevel@tonic-gate * Use "set hsfs:strict_iso9660_ordering = 1" in /etc/system to override. 1007c478bd9Sstevel@tonic-gate */ 1017c478bd9Sstevel@tonic-gate static int strict_iso9660_ordering = 0; 1027c478bd9Sstevel@tonic-gate 103d10b6702Sfrankho /* 104d10b6702Sfrankho * This tunable allows us to ignore inode numbers from rrip-1.12. 105d10b6702Sfrankho * In this case, we fall back to our default inode algorithm. 106d10b6702Sfrankho */ 107d10b6702Sfrankho int use_rrip_inodes = 1; 108d10b6702Sfrankho 1097c478bd9Sstevel@tonic-gate static void hs_hsnode_cache_reclaim(void *unused); 1107c478bd9Sstevel@tonic-gate static void hs_addfreeb(struct hsfs *fsp, struct hsnode *hp); 1117c478bd9Sstevel@tonic-gate static enum dirblock_result process_dirblock(struct fbuf *fbp, uint_t *offset, 1127c478bd9Sstevel@tonic-gate uint_t last_offset, char *nm, int nmlen, struct hsfs *fsp, 1137c478bd9Sstevel@tonic-gate struct hsnode *dhp, struct vnode *dvp, struct vnode **vpp, 114fc1c62b8Sfrankho int *error); 1157c478bd9Sstevel@tonic-gate static int strip_trailing(struct hsfs *fsp, char *nm, int len); 116fc1c62b8Sfrankho static int hs_namelen(struct hsfs *fsp, char *nm, int len); 1177c478bd9Sstevel@tonic-gate static int uppercase_cp(char *from, char *to, int size); 118fc1c62b8Sfrankho static void hs_log_bogus_joliet_warning(void); 119fc1c62b8Sfrankho static int hs_iso_copy(char *from, char *to, int size); 120fc1c62b8Sfrankho static int32_t hs_ucs2_2_utf8(uint16_t c_16, uint8_t *s_8); 121fc1c62b8Sfrankho static int hs_utf8_trunc(uint8_t *str, int len); 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate /* 1247c478bd9Sstevel@tonic-gate * hs_access 1257c478bd9Sstevel@tonic-gate * Return 0 if the desired access may be granted. 1267c478bd9Sstevel@tonic-gate * Otherwise return error code. 1277c478bd9Sstevel@tonic-gate */ 1287c478bd9Sstevel@tonic-gate int 1297c478bd9Sstevel@tonic-gate hs_access(struct vnode *vp, mode_t m, struct cred *cred) 1307c478bd9Sstevel@tonic-gate { 1317c478bd9Sstevel@tonic-gate struct hsnode *hp; 1327c478bd9Sstevel@tonic-gate int shift = 0; 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate /* 1357c478bd9Sstevel@tonic-gate * Write access cannot be granted for a read-only medium 1367c478bd9Sstevel@tonic-gate */ 1377c478bd9Sstevel@tonic-gate if ((m & VWRITE) && !IS_DEVVP(vp)) 1387c478bd9Sstevel@tonic-gate return (EROFS); 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate hp = VTOH(vp); 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate /* 1437c478bd9Sstevel@tonic-gate * XXX - For now, use volume protections. 1447c478bd9Sstevel@tonic-gate * Also, always grant EXEC access for directories 1457c478bd9Sstevel@tonic-gate * if READ access is granted. 1467c478bd9Sstevel@tonic-gate */ 1477c478bd9Sstevel@tonic-gate if ((vp->v_type == VDIR) && (m & VEXEC)) { 1487c478bd9Sstevel@tonic-gate m &= ~VEXEC; 1497c478bd9Sstevel@tonic-gate m |= VREAD; 1507c478bd9Sstevel@tonic-gate } 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate if (crgetuid(cred) != hp->hs_dirent.uid) { 1537c478bd9Sstevel@tonic-gate shift += 3; 1547c478bd9Sstevel@tonic-gate if (!groupmember((uid_t)hp->hs_dirent.gid, cred)) 1557c478bd9Sstevel@tonic-gate shift += 3; 1567c478bd9Sstevel@tonic-gate } 157*134a1f4eSCasper H.S. Dik return (secpolicy_vnode_access2(cred, vp, hp->hs_dirent.uid, 158*134a1f4eSCasper H.S. Dik hp->hs_dirent.mode << shift, m)); 1597c478bd9Sstevel@tonic-gate } 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate #if ((HS_HASHSIZE & (HS_HASHSIZE - 1)) == 0) 1627c478bd9Sstevel@tonic-gate #define HS_HASH(l) ((uint_t)(l) & (HS_HASHSIZE - 1)) 1637c478bd9Sstevel@tonic-gate #else 1647c478bd9Sstevel@tonic-gate #define HS_HASH(l) ((uint_t)(l) % HS_HASHSIZE) 1657c478bd9Sstevel@tonic-gate #endif 1667c478bd9Sstevel@tonic-gate #define HS_HPASH(hp) HS_HASH((hp)->hs_nodeid) 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate /* 1697c478bd9Sstevel@tonic-gate * The tunable nhsnode is now a threshold for a dynamically allocated 1707c478bd9Sstevel@tonic-gate * pool of hsnodes, not the size of a statically allocated table. 1717c478bd9Sstevel@tonic-gate * When the number of hsnodes for a particular file system exceeds 1727c478bd9Sstevel@tonic-gate * nhsnode, the allocate and free logic will try to reduce the number 1737c478bd9Sstevel@tonic-gate * of allocated nodes by returning unreferenced nodes to the kmem_cache 1747c478bd9Sstevel@tonic-gate * instead of putting them on the file system's private free list. 1757c478bd9Sstevel@tonic-gate */ 1767c478bd9Sstevel@tonic-gate int nhsnode = HS_HSNODESPACE / sizeof (struct hsnode); 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate struct kmem_cache *hsnode_cache; /* free hsnode cache */ 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate /* 1817c478bd9Sstevel@tonic-gate * Initialize the cache of free hsnodes. 1827c478bd9Sstevel@tonic-gate */ 1837c478bd9Sstevel@tonic-gate void 1847c478bd9Sstevel@tonic-gate hs_init_hsnode_cache(void) 1857c478bd9Sstevel@tonic-gate { 1867c478bd9Sstevel@tonic-gate /* 1877c478bd9Sstevel@tonic-gate * A kmem_cache is used for the hsnodes 1887c478bd9Sstevel@tonic-gate * No constructor because hsnodes are initialised by bzeroing. 1897c478bd9Sstevel@tonic-gate */ 1907c478bd9Sstevel@tonic-gate hsnode_cache = kmem_cache_create("hsfs_hsnode_cache", 1917c478bd9Sstevel@tonic-gate sizeof (struct hsnode), 0, NULL, 1927c478bd9Sstevel@tonic-gate NULL, hs_hsnode_cache_reclaim, NULL, NULL, 0); 1937c478bd9Sstevel@tonic-gate } 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate /* 196fc1c62b8Sfrankho * Destroy the cache of free hsnodes. 197fc1c62b8Sfrankho */ 198fc1c62b8Sfrankho void 199fc1c62b8Sfrankho hs_fini_hsnode_cache(void) 200fc1c62b8Sfrankho { 201fc1c62b8Sfrankho kmem_cache_destroy(hsnode_cache); 202fc1c62b8Sfrankho } 203fc1c62b8Sfrankho 204fc1c62b8Sfrankho /* 2057c478bd9Sstevel@tonic-gate * System is short on memory, free up as much as possible 2067c478bd9Sstevel@tonic-gate */ 2077c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2087c478bd9Sstevel@tonic-gate static void 2097c478bd9Sstevel@tonic-gate hs_hsnode_cache_reclaim(void *unused) 2107c478bd9Sstevel@tonic-gate { 2117c478bd9Sstevel@tonic-gate struct hsfs *fsp; 2127c478bd9Sstevel@tonic-gate struct hsnode *hp; 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate /* 2157c478bd9Sstevel@tonic-gate * For each vfs in the hs_mounttab list 2167c478bd9Sstevel@tonic-gate */ 2177c478bd9Sstevel@tonic-gate mutex_enter(&hs_mounttab_lock); 2187c478bd9Sstevel@tonic-gate for (fsp = hs_mounttab; fsp != NULL; fsp = fsp->hsfs_next) { 2197c478bd9Sstevel@tonic-gate /* 2207c478bd9Sstevel@tonic-gate * Purge the dnlc of all hsfs entries 2217c478bd9Sstevel@tonic-gate */ 2227c478bd9Sstevel@tonic-gate (void) dnlc_purge_vfsp(fsp->hsfs_vfs, 0); 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate /* 2257c478bd9Sstevel@tonic-gate * For each entry in the free chain 2267c478bd9Sstevel@tonic-gate */ 2277c478bd9Sstevel@tonic-gate rw_enter(&fsp->hsfs_hash_lock, RW_WRITER); 2287c478bd9Sstevel@tonic-gate mutex_enter(&fsp->hsfs_free_lock); 2297c478bd9Sstevel@tonic-gate for (hp = fsp->hsfs_free_f; hp != NULL; hp = fsp->hsfs_free_f) { 2307c478bd9Sstevel@tonic-gate /* 2317c478bd9Sstevel@tonic-gate * Remove from chain 2327c478bd9Sstevel@tonic-gate */ 2337c478bd9Sstevel@tonic-gate fsp->hsfs_free_f = hp->hs_freef; 2347c478bd9Sstevel@tonic-gate if (fsp->hsfs_free_f != NULL) { 2357c478bd9Sstevel@tonic-gate fsp->hsfs_free_f->hs_freeb = NULL; 2367c478bd9Sstevel@tonic-gate } else { 2377c478bd9Sstevel@tonic-gate fsp->hsfs_free_b = NULL; 2387c478bd9Sstevel@tonic-gate } 2397c478bd9Sstevel@tonic-gate /* 2407c478bd9Sstevel@tonic-gate * Free the node. Force it to be fully freed 2417c478bd9Sstevel@tonic-gate * by setting the 3rd arg (nopage) to 1. 2427c478bd9Sstevel@tonic-gate */ 2437c478bd9Sstevel@tonic-gate hs_freenode(HTOV(hp), fsp, 1); 2447c478bd9Sstevel@tonic-gate } 2457c478bd9Sstevel@tonic-gate mutex_exit(&fsp->hsfs_free_lock); 2467c478bd9Sstevel@tonic-gate rw_exit(&fsp->hsfs_hash_lock); 2477c478bd9Sstevel@tonic-gate } 2487c478bd9Sstevel@tonic-gate mutex_exit(&hs_mounttab_lock); 2497c478bd9Sstevel@tonic-gate } 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate /* 2527c478bd9Sstevel@tonic-gate * Add an hsnode to the end of the free list. 2537c478bd9Sstevel@tonic-gate */ 2547c478bd9Sstevel@tonic-gate static void 2557c478bd9Sstevel@tonic-gate hs_addfreeb(struct hsfs *fsp, struct hsnode *hp) 2567c478bd9Sstevel@tonic-gate { 2577c478bd9Sstevel@tonic-gate struct hsnode *ep; 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate vn_invalid(HTOV(hp)); 2607c478bd9Sstevel@tonic-gate mutex_enter(&fsp->hsfs_free_lock); 2617c478bd9Sstevel@tonic-gate ep = fsp->hsfs_free_b; 2627c478bd9Sstevel@tonic-gate fsp->hsfs_free_b = hp; /* hp is the last entry in free list */ 2637c478bd9Sstevel@tonic-gate hp->hs_freef = NULL; 2647c478bd9Sstevel@tonic-gate hp->hs_freeb = ep; /* point at previous last entry */ 2657c478bd9Sstevel@tonic-gate if (ep == NULL) 2667c478bd9Sstevel@tonic-gate fsp->hsfs_free_f = hp; /* hp is only entry in free list */ 2677c478bd9Sstevel@tonic-gate else 2687c478bd9Sstevel@tonic-gate ep->hs_freef = hp; /* point previous last entry at hp */ 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate mutex_exit(&fsp->hsfs_free_lock); 2717c478bd9Sstevel@tonic-gate } 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate /* 2747c478bd9Sstevel@tonic-gate * Get an hsnode from the front of the free list. 2757c478bd9Sstevel@tonic-gate * Must be called with write hsfs_hash_lock held. 2767c478bd9Sstevel@tonic-gate */ 2777c478bd9Sstevel@tonic-gate static struct hsnode * 2787c478bd9Sstevel@tonic-gate hs_getfree(struct hsfs *fsp) 2797c478bd9Sstevel@tonic-gate { 2807c478bd9Sstevel@tonic-gate struct hsnode *hp, **tp; 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate ASSERT(RW_WRITE_HELD(&fsp->hsfs_hash_lock)); 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate /* 2857c478bd9Sstevel@tonic-gate * If the number of currently-allocated hsnodes is less than 2867c478bd9Sstevel@tonic-gate * the hsnode count threshold (nhsnode), or if there are no 2877c478bd9Sstevel@tonic-gate * nodes on the file system's local free list (which acts as a 2887c478bd9Sstevel@tonic-gate * cache), call kmem_cache_alloc to get a new hsnode from 2897c478bd9Sstevel@tonic-gate * kernel memory. 2907c478bd9Sstevel@tonic-gate */ 2917c478bd9Sstevel@tonic-gate mutex_enter(&fsp->hsfs_free_lock); 2927c478bd9Sstevel@tonic-gate if ((fsp->hsfs_nohsnode < nhsnode) || (fsp->hsfs_free_f == NULL)) { 2937c478bd9Sstevel@tonic-gate mutex_exit(&fsp->hsfs_free_lock); 2947c478bd9Sstevel@tonic-gate hp = kmem_cache_alloc(hsnode_cache, KM_SLEEP); 2957c478bd9Sstevel@tonic-gate fsp->hsfs_nohsnode++; 2967c478bd9Sstevel@tonic-gate bzero((caddr_t)hp, sizeof (*hp)); 2977c478bd9Sstevel@tonic-gate hp->hs_vnode = vn_alloc(KM_SLEEP); 2987c478bd9Sstevel@tonic-gate return (hp); 2997c478bd9Sstevel@tonic-gate } 3007c478bd9Sstevel@tonic-gate hp = fsp->hsfs_free_f; 3017c478bd9Sstevel@tonic-gate /* hp cannot be NULL, since we already checked this above */ 3027c478bd9Sstevel@tonic-gate fsp->hsfs_free_f = hp->hs_freef; 3037c478bd9Sstevel@tonic-gate if (fsp->hsfs_free_f != NULL) 3047c478bd9Sstevel@tonic-gate fsp->hsfs_free_f->hs_freeb = NULL; 3057c478bd9Sstevel@tonic-gate else 3067c478bd9Sstevel@tonic-gate fsp->hsfs_free_b = NULL; 3077c478bd9Sstevel@tonic-gate mutex_exit(&fsp->hsfs_free_lock); 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate for (tp = &fsp->hsfs_hash[HS_HPASH(hp)]; *tp != NULL; 3107c478bd9Sstevel@tonic-gate tp = &(*tp)->hs_hash) { 3117c478bd9Sstevel@tonic-gate if (*tp == hp) { 3127c478bd9Sstevel@tonic-gate struct vnode *vp; 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate vp = HTOV(hp); 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate /* 3177c478bd9Sstevel@tonic-gate * file is no longer referenced, destroy all old pages 3187c478bd9Sstevel@tonic-gate */ 3197c478bd9Sstevel@tonic-gate if (vn_has_cached_data(vp)) 3207c478bd9Sstevel@tonic-gate /* 3217c478bd9Sstevel@tonic-gate * pvn_vplist_dirty will abort all old pages 3227c478bd9Sstevel@tonic-gate */ 3237c478bd9Sstevel@tonic-gate (void) pvn_vplist_dirty(vp, (u_offset_t)0, 324d10b6702Sfrankho hsfs_putapage, B_INVAL, 325d10b6702Sfrankho (struct cred *)NULL); 3267c478bd9Sstevel@tonic-gate *tp = hp->hs_hash; 3277c478bd9Sstevel@tonic-gate break; 3287c478bd9Sstevel@tonic-gate } 3297c478bd9Sstevel@tonic-gate } 3307c478bd9Sstevel@tonic-gate if (hp->hs_dirent.sym_link != (char *)NULL) { 3317c478bd9Sstevel@tonic-gate kmem_free(hp->hs_dirent.sym_link, 3327c478bd9Sstevel@tonic-gate (size_t)(hp->hs_dirent.ext_size + 1)); 3337c478bd9Sstevel@tonic-gate } 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate mutex_destroy(&hp->hs_contents_lock); 3367c478bd9Sstevel@tonic-gate { 3377c478bd9Sstevel@tonic-gate vnode_t *vp; 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate vp = hp->hs_vnode; 3407c478bd9Sstevel@tonic-gate bzero((caddr_t)hp, sizeof (*hp)); 3417c478bd9Sstevel@tonic-gate hp->hs_vnode = vp; 3427c478bd9Sstevel@tonic-gate vn_reinit(vp); 3437c478bd9Sstevel@tonic-gate } 3447c478bd9Sstevel@tonic-gate return (hp); 3457c478bd9Sstevel@tonic-gate } 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate /* 3487c478bd9Sstevel@tonic-gate * Remove an hsnode from the free list. 3497c478bd9Sstevel@tonic-gate */ 3507c478bd9Sstevel@tonic-gate static void 3517c478bd9Sstevel@tonic-gate hs_remfree(struct hsfs *fsp, struct hsnode *hp) 3527c478bd9Sstevel@tonic-gate { 3537c478bd9Sstevel@tonic-gate mutex_enter(&fsp->hsfs_free_lock); 3547c478bd9Sstevel@tonic-gate if (hp->hs_freef != NULL) 3557c478bd9Sstevel@tonic-gate hp->hs_freef->hs_freeb = hp->hs_freeb; 3567c478bd9Sstevel@tonic-gate else 3577c478bd9Sstevel@tonic-gate fsp->hsfs_free_b = hp->hs_freeb; 3587c478bd9Sstevel@tonic-gate if (hp->hs_freeb != NULL) 3597c478bd9Sstevel@tonic-gate hp->hs_freeb->hs_freef = hp->hs_freef; 3607c478bd9Sstevel@tonic-gate else 3617c478bd9Sstevel@tonic-gate fsp->hsfs_free_f = hp->hs_freef; 3627c478bd9Sstevel@tonic-gate mutex_exit(&fsp->hsfs_free_lock); 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate /* 3667c478bd9Sstevel@tonic-gate * Look for hsnode in hash list. 367d10b6702Sfrankho * If the inode number is != HS_DUMMY_INO (16), then only the inode 368d10b6702Sfrankho * number is used for the check. 369d10b6702Sfrankho * If the inode number is == HS_DUMMY_INO, we additionally always 370d10b6702Sfrankho * check the directory offset for the file to avoid caching the 371d10b6702Sfrankho * meta data for all zero sized to the first zero sized file that 372d10b6702Sfrankho * was touched. 373d10b6702Sfrankho * 3747c478bd9Sstevel@tonic-gate * If found, reactivate it if inactive. 375d10b6702Sfrankho * 3767c478bd9Sstevel@tonic-gate * Must be entered with hsfs_hash_lock held. 3777c478bd9Sstevel@tonic-gate */ 3787c478bd9Sstevel@tonic-gate struct vnode * 379d10b6702Sfrankho hs_findhash(ino64_t nodeid, uint_t lbn, uint_t off, struct vfs *vfsp) 3807c478bd9Sstevel@tonic-gate { 3817c478bd9Sstevel@tonic-gate struct hsnode *tp; 3827c478bd9Sstevel@tonic-gate struct hsfs *fsp; 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate fsp = VFS_TO_HSFS(vfsp); 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate ASSERT(RW_LOCK_HELD(&fsp->hsfs_hash_lock)); 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate for (tp = fsp->hsfs_hash[HS_HASH(nodeid)]; tp != NULL; 3897c478bd9Sstevel@tonic-gate tp = tp->hs_hash) { 3907c478bd9Sstevel@tonic-gate if (tp->hs_nodeid == nodeid) { 3917c478bd9Sstevel@tonic-gate struct vnode *vp; 3927c478bd9Sstevel@tonic-gate 393d10b6702Sfrankho if (nodeid == HS_DUMMY_INO) { 394d10b6702Sfrankho /* 395d10b6702Sfrankho * If this is the dummy inode number, look for 396d10b6702Sfrankho * matching dir_lbn and dir_off. 397d10b6702Sfrankho */ 398d10b6702Sfrankho for (; tp != NULL; tp = tp->hs_hash) { 399d10b6702Sfrankho if (tp->hs_nodeid == nodeid && 400d10b6702Sfrankho tp->hs_dir_lbn == lbn && 401d10b6702Sfrankho tp->hs_dir_off == off) 402d10b6702Sfrankho break; 403d10b6702Sfrankho } 404d10b6702Sfrankho if (tp == NULL) 405d10b6702Sfrankho return (NULL); 406d10b6702Sfrankho } 407d10b6702Sfrankho 4087c478bd9Sstevel@tonic-gate mutex_enter(&tp->hs_contents_lock); 4097c478bd9Sstevel@tonic-gate vp = HTOV(tp); 4107c478bd9Sstevel@tonic-gate VN_HOLD(vp); 4117c478bd9Sstevel@tonic-gate if ((tp->hs_flags & HREF) == 0) { 4127c478bd9Sstevel@tonic-gate tp->hs_flags |= HREF; 4137c478bd9Sstevel@tonic-gate /* 4147c478bd9Sstevel@tonic-gate * reactivating a free hsnode: 4157c478bd9Sstevel@tonic-gate * remove from free list 4167c478bd9Sstevel@tonic-gate */ 4177c478bd9Sstevel@tonic-gate hs_remfree(fsp, tp); 4187c478bd9Sstevel@tonic-gate } 4197c478bd9Sstevel@tonic-gate mutex_exit(&tp->hs_contents_lock); 4207c478bd9Sstevel@tonic-gate return (vp); 4217c478bd9Sstevel@tonic-gate } 4227c478bd9Sstevel@tonic-gate } 4237c478bd9Sstevel@tonic-gate return (NULL); 4247c478bd9Sstevel@tonic-gate } 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate static void 4277c478bd9Sstevel@tonic-gate hs_addhash(struct hsfs *fsp, struct hsnode *hp) 4287c478bd9Sstevel@tonic-gate { 4297c478bd9Sstevel@tonic-gate ulong_t hashno; 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate ASSERT(RW_WRITE_HELD(&fsp->hsfs_hash_lock)); 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate hashno = HS_HPASH(hp); 4347c478bd9Sstevel@tonic-gate hp->hs_hash = fsp->hsfs_hash[hashno]; 4357c478bd9Sstevel@tonic-gate fsp->hsfs_hash[hashno] = hp; 4367c478bd9Sstevel@tonic-gate } 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate /* 4397c478bd9Sstevel@tonic-gate * Destroy all old pages and free the hsnodes 4407c478bd9Sstevel@tonic-gate * Return 1 if busy (a hsnode is still referenced). 4417c478bd9Sstevel@tonic-gate */ 4427c478bd9Sstevel@tonic-gate int 4437c478bd9Sstevel@tonic-gate hs_synchash(struct vfs *vfsp) 4447c478bd9Sstevel@tonic-gate { 4457c478bd9Sstevel@tonic-gate struct hsfs *fsp; 4467c478bd9Sstevel@tonic-gate int i; 4477c478bd9Sstevel@tonic-gate struct hsnode *hp, *nhp; 4487c478bd9Sstevel@tonic-gate int busy = 0; 4497c478bd9Sstevel@tonic-gate struct vnode *vp, *rvp; 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate fsp = VFS_TO_HSFS(vfsp); 4527c478bd9Sstevel@tonic-gate rvp = fsp->hsfs_rootvp; 4537c478bd9Sstevel@tonic-gate /* make sure no one can come in */ 4547c478bd9Sstevel@tonic-gate rw_enter(&fsp->hsfs_hash_lock, RW_WRITER); 4557c478bd9Sstevel@tonic-gate for (i = 0; i < HS_HASHSIZE; i++) { 4567c478bd9Sstevel@tonic-gate for (hp = fsp->hsfs_hash[i]; hp != NULL; hp = hp->hs_hash) { 4577c478bd9Sstevel@tonic-gate vp = HTOV(hp); 4587c478bd9Sstevel@tonic-gate if ((hp->hs_flags & HREF) && (vp != rvp || 4597c478bd9Sstevel@tonic-gate (vp == rvp && vp->v_count > 1))) { 4607c478bd9Sstevel@tonic-gate busy = 1; 4617c478bd9Sstevel@tonic-gate continue; 4627c478bd9Sstevel@tonic-gate } 4637c478bd9Sstevel@tonic-gate if (vn_has_cached_data(vp)) 4647c478bd9Sstevel@tonic-gate (void) pvn_vplist_dirty(vp, (u_offset_t)0, 465d10b6702Sfrankho hsfs_putapage, B_INVAL, 466d10b6702Sfrankho (struct cred *)NULL); 4677c478bd9Sstevel@tonic-gate } 4687c478bd9Sstevel@tonic-gate } 4697c478bd9Sstevel@tonic-gate if (busy) { 4707c478bd9Sstevel@tonic-gate rw_exit(&fsp->hsfs_hash_lock); 4717c478bd9Sstevel@tonic-gate return (1); 4727c478bd9Sstevel@tonic-gate } 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate /* now free the hsnodes */ 4757c478bd9Sstevel@tonic-gate for (i = 0; i < HS_HASHSIZE; i++) { 4767c478bd9Sstevel@tonic-gate for (hp = fsp->hsfs_hash[i]; hp != NULL; hp = nhp) { 4777c478bd9Sstevel@tonic-gate nhp = hp->hs_hash; 4787c478bd9Sstevel@tonic-gate /* 4797c478bd9Sstevel@tonic-gate * We know there are no pages associated with 4807c478bd9Sstevel@tonic-gate * all the hsnodes (they've all been released 4817c478bd9Sstevel@tonic-gate * above). So remove from free list and 4827c478bd9Sstevel@tonic-gate * free the entry with nopage set. 4837c478bd9Sstevel@tonic-gate */ 4847c478bd9Sstevel@tonic-gate vp = HTOV(hp); 4857c478bd9Sstevel@tonic-gate if (vp != rvp) { 4867c478bd9Sstevel@tonic-gate hs_remfree(fsp, hp); 4877c478bd9Sstevel@tonic-gate hs_freenode(vp, fsp, 1); 4887c478bd9Sstevel@tonic-gate } 4897c478bd9Sstevel@tonic-gate } 4907c478bd9Sstevel@tonic-gate } 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate ASSERT(fsp->hsfs_nohsnode == 1); 4937c478bd9Sstevel@tonic-gate rw_exit(&fsp->hsfs_hash_lock); 4947c478bd9Sstevel@tonic-gate /* release the root hsnode, this should free the final hsnode */ 4957c478bd9Sstevel@tonic-gate VN_RELE(rvp); 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate return (0); 4987c478bd9Sstevel@tonic-gate } 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate /* 5017c478bd9Sstevel@tonic-gate * hs_makenode 5027c478bd9Sstevel@tonic-gate * 5037c478bd9Sstevel@tonic-gate * Construct an hsnode. 5047c478bd9Sstevel@tonic-gate * Caller specifies the directory entry, the block number and offset 5057c478bd9Sstevel@tonic-gate * of the directory entry, and the vfs pointer. 5067c478bd9Sstevel@tonic-gate * note: off is the sector offset, not lbn offset 5077c478bd9Sstevel@tonic-gate * if NULL is returned implies file system hsnode table full 5087c478bd9Sstevel@tonic-gate */ 5097c478bd9Sstevel@tonic-gate struct vnode * 5107c478bd9Sstevel@tonic-gate hs_makenode( 5117c478bd9Sstevel@tonic-gate struct hs_direntry *dp, 5127c478bd9Sstevel@tonic-gate uint_t lbn, 5137c478bd9Sstevel@tonic-gate uint_t off, 5147c478bd9Sstevel@tonic-gate struct vfs *vfsp) 5157c478bd9Sstevel@tonic-gate { 5167c478bd9Sstevel@tonic-gate struct hsnode *hp; 5177c478bd9Sstevel@tonic-gate struct vnode *vp; 5187c478bd9Sstevel@tonic-gate struct hs_volume *hvp; 5197c478bd9Sstevel@tonic-gate struct vnode *newvp; 5207c478bd9Sstevel@tonic-gate struct hsfs *fsp; 5217c478bd9Sstevel@tonic-gate ino64_t nodeid; 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate fsp = VFS_TO_HSFS(vfsp); 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate /* 526d10b6702Sfrankho * Construct the data that allows us to re-read the meta data without 527d10b6702Sfrankho * knowing the name of the file: in the case of a directory 5287c478bd9Sstevel@tonic-gate * entry, this should point to the canonical dirent, the "." 5297c478bd9Sstevel@tonic-gate * directory entry for the directory. This dirent is pointed 5307c478bd9Sstevel@tonic-gate * to by all directory entries for that dir (including the ".") 5317c478bd9Sstevel@tonic-gate * entry itself. 5327c478bd9Sstevel@tonic-gate * In the case of a file, simply point to the dirent for that 533d10b6702Sfrankho * file (there are hard links in Rock Ridge, so we need to use 534d10b6702Sfrankho * different data to contruct the node id). 5357c478bd9Sstevel@tonic-gate */ 5367c478bd9Sstevel@tonic-gate if (dp->type == VDIR) { 5377c478bd9Sstevel@tonic-gate lbn = dp->ext_lbn; 5387c478bd9Sstevel@tonic-gate off = 0; 5397c478bd9Sstevel@tonic-gate } 5407c478bd9Sstevel@tonic-gate 5417c478bd9Sstevel@tonic-gate /* 5427c478bd9Sstevel@tonic-gate * Normalize lbn and off before creating a nodeid 5437c478bd9Sstevel@tonic-gate * and before storing them in a hs_node structure 5447c478bd9Sstevel@tonic-gate */ 5457c478bd9Sstevel@tonic-gate hvp = &fsp->hsfs_vol; 5467c478bd9Sstevel@tonic-gate lbn += off >> hvp->lbn_shift; 5477c478bd9Sstevel@tonic-gate off &= hvp->lbn_maxoffset; 548d10b6702Sfrankho /* 549d10b6702Sfrankho * If the media carries rrip-v1.12 or newer, and we trust the inodes 550d10b6702Sfrankho * from the rrip data (use_rrip_inodes != 0), use that data. If the 551d10b6702Sfrankho * media has been created by a recent mkisofs version, we may trust 552d10b6702Sfrankho * all numbers in the starting extent number; otherwise, we cannot 553d10b6702Sfrankho * do this for zero sized files and symlinks, because if we did we'd 554d10b6702Sfrankho * end up mapping all of them to the same node. 555d10b6702Sfrankho * We use HS_DUMMY_INO in this case and make sure that we will not 556d10b6702Sfrankho * map all files to the same meta data. 557d10b6702Sfrankho */ 558d10b6702Sfrankho if (dp->inode != 0 && use_rrip_inodes) { 559d10b6702Sfrankho nodeid = dp->inode; 560d10b6702Sfrankho } else if ((dp->ext_size == 0 || dp->sym_link != (char *)NULL) && 561d10b6702Sfrankho (fsp->hsfs_flags & HSFSMNT_INODE) == 0) { 562d10b6702Sfrankho nodeid = HS_DUMMY_INO; 563d10b6702Sfrankho } else { 564d10b6702Sfrankho nodeid = dp->ext_lbn; 565d10b6702Sfrankho } 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate /* look for hsnode in cache first */ 5687c478bd9Sstevel@tonic-gate 5697c478bd9Sstevel@tonic-gate rw_enter(&fsp->hsfs_hash_lock, RW_READER); 5707c478bd9Sstevel@tonic-gate 571d10b6702Sfrankho if ((vp = hs_findhash(nodeid, lbn, off, vfsp)) == NULL) { 5727c478bd9Sstevel@tonic-gate 5737c478bd9Sstevel@tonic-gate /* 5747c478bd9Sstevel@tonic-gate * Not in cache. However, someone else may have come 5757c478bd9Sstevel@tonic-gate * to the same conclusion and just put one in. Upgrade 5767c478bd9Sstevel@tonic-gate * our lock to a write lock and look again. 5777c478bd9Sstevel@tonic-gate */ 5787c478bd9Sstevel@tonic-gate rw_exit(&fsp->hsfs_hash_lock); 5797c478bd9Sstevel@tonic-gate rw_enter(&fsp->hsfs_hash_lock, RW_WRITER); 5807c478bd9Sstevel@tonic-gate 581d10b6702Sfrankho if ((vp = hs_findhash(nodeid, lbn, off, vfsp)) == NULL) { 5827c478bd9Sstevel@tonic-gate /* 5837c478bd9Sstevel@tonic-gate * Now we are really sure that the hsnode is not 5847c478bd9Sstevel@tonic-gate * in the cache. Get one off freelist or else 5857c478bd9Sstevel@tonic-gate * allocate one. Either way get a bzeroed hsnode. 5867c478bd9Sstevel@tonic-gate */ 5877c478bd9Sstevel@tonic-gate hp = hs_getfree(fsp); 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate bcopy((caddr_t)dp, (caddr_t)&hp->hs_dirent, 5907c478bd9Sstevel@tonic-gate sizeof (*dp)); 5917c478bd9Sstevel@tonic-gate /* 5927c478bd9Sstevel@tonic-gate * We've just copied this pointer into hs_dirent, 5937c478bd9Sstevel@tonic-gate * and don't want 2 references to same symlink. 5947c478bd9Sstevel@tonic-gate */ 5957c478bd9Sstevel@tonic-gate dp->sym_link = (char *)NULL; 5967c478bd9Sstevel@tonic-gate 5977c478bd9Sstevel@tonic-gate /* 5987c478bd9Sstevel@tonic-gate * No need to hold any lock because hsnode is not 5997c478bd9Sstevel@tonic-gate * yet in the hash chain. 6007c478bd9Sstevel@tonic-gate */ 6017c478bd9Sstevel@tonic-gate mutex_init(&hp->hs_contents_lock, NULL, MUTEX_DEFAULT, 6027c478bd9Sstevel@tonic-gate NULL); 6037c478bd9Sstevel@tonic-gate hp->hs_dir_lbn = lbn; 6047c478bd9Sstevel@tonic-gate hp->hs_dir_off = off; 6057c478bd9Sstevel@tonic-gate hp->hs_nodeid = nodeid; 6067c478bd9Sstevel@tonic-gate hp->hs_seq = 0; 60784b82766Smg147109 hp->hs_prev_offset = 0; 60884b82766Smg147109 hp->hs_num_contig = 0; 60984b82766Smg147109 hp->hs_ra_bytes = 0; 6107c478bd9Sstevel@tonic-gate hp->hs_flags = HREF; 6117c478bd9Sstevel@tonic-gate if (off > HS_SECTOR_SIZE) 6127c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "hs_makenode: bad offset"); 6137c478bd9Sstevel@tonic-gate 6147c478bd9Sstevel@tonic-gate vp = HTOV(hp); 6157c478bd9Sstevel@tonic-gate vp->v_vfsp = vfsp; 6167c478bd9Sstevel@tonic-gate vp->v_type = dp->type; 6177c478bd9Sstevel@tonic-gate vp->v_rdev = dp->r_dev; 6187c478bd9Sstevel@tonic-gate vn_setops(vp, hsfs_vnodeops); 6197c478bd9Sstevel@tonic-gate vp->v_data = (caddr_t)hp; 6207c478bd9Sstevel@tonic-gate vn_exists(vp); 6217c478bd9Sstevel@tonic-gate /* 6227c478bd9Sstevel@tonic-gate * if it's a device, call specvp 6237c478bd9Sstevel@tonic-gate */ 6247c478bd9Sstevel@tonic-gate if (IS_DEVVP(vp)) { 6257c478bd9Sstevel@tonic-gate rw_exit(&fsp->hsfs_hash_lock); 6267c478bd9Sstevel@tonic-gate newvp = specvp(vp, vp->v_rdev, vp->v_type, 6277c478bd9Sstevel@tonic-gate CRED()); 6287c478bd9Sstevel@tonic-gate if (newvp == NULL) 6297c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, 6307c478bd9Sstevel@tonic-gate "hs_makenode: specvp failed"); 6317c478bd9Sstevel@tonic-gate VN_RELE(vp); 6327c478bd9Sstevel@tonic-gate return (newvp); 6337c478bd9Sstevel@tonic-gate } 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate hs_addhash(fsp, hp); 6367c478bd9Sstevel@tonic-gate 6377c478bd9Sstevel@tonic-gate } 6387c478bd9Sstevel@tonic-gate } 6397c478bd9Sstevel@tonic-gate 6407c478bd9Sstevel@tonic-gate if (dp->sym_link != (char *)NULL) { 6417c478bd9Sstevel@tonic-gate kmem_free(dp->sym_link, (size_t)(dp->ext_size + 1)); 6427c478bd9Sstevel@tonic-gate dp->sym_link = (char *)NULL; 6437c478bd9Sstevel@tonic-gate } 6447c478bd9Sstevel@tonic-gate 6457c478bd9Sstevel@tonic-gate rw_exit(&fsp->hsfs_hash_lock); 6467c478bd9Sstevel@tonic-gate return (vp); 6477c478bd9Sstevel@tonic-gate } 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate /* 6507c478bd9Sstevel@tonic-gate * hs_freenode 6517c478bd9Sstevel@tonic-gate * 6527c478bd9Sstevel@tonic-gate * Deactivate an hsnode. 6537c478bd9Sstevel@tonic-gate * Leave it on the hash list but put it on the free list. 6547c478bd9Sstevel@tonic-gate * If the vnode does not have any pages, release the hsnode to the 6557c478bd9Sstevel@tonic-gate * kmem_cache using kmem_cache_free, else put in back of the free list. 6567c478bd9Sstevel@tonic-gate * 6577c478bd9Sstevel@tonic-gate * This function can be called with the hsfs_free_lock held, but only 6587c478bd9Sstevel@tonic-gate * when the code is guaranteed to go through the path where the 6597c478bd9Sstevel@tonic-gate * node is freed entirely, and not the path where the node could go back 6607c478bd9Sstevel@tonic-gate * on the free list (and where the free lock would need to be acquired). 6617c478bd9Sstevel@tonic-gate */ 6627c478bd9Sstevel@tonic-gate void 6637c478bd9Sstevel@tonic-gate hs_freenode(vnode_t *vp, struct hsfs *fsp, int nopage) 6647c478bd9Sstevel@tonic-gate { 6657c478bd9Sstevel@tonic-gate struct hsnode **tp; 6667c478bd9Sstevel@tonic-gate struct hsnode *hp = VTOH(vp); 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate ASSERT(RW_LOCK_HELD(&fsp->hsfs_hash_lock)); 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate if (nopage || (fsp->hsfs_nohsnode >= nhsnode)) { 6717c478bd9Sstevel@tonic-gate /* remove this node from the hash list, if it's there */ 6727c478bd9Sstevel@tonic-gate for (tp = &fsp->hsfs_hash[HS_HPASH(hp)]; *tp != NULL; 6737c478bd9Sstevel@tonic-gate tp = &(*tp)->hs_hash) { 6747c478bd9Sstevel@tonic-gate 6757c478bd9Sstevel@tonic-gate if (*tp == hp) { 6767c478bd9Sstevel@tonic-gate *tp = hp->hs_hash; 6777c478bd9Sstevel@tonic-gate break; 6787c478bd9Sstevel@tonic-gate } 6797c478bd9Sstevel@tonic-gate } 6807c478bd9Sstevel@tonic-gate 6817c478bd9Sstevel@tonic-gate if (hp->hs_dirent.sym_link != (char *)NULL) { 6827c478bd9Sstevel@tonic-gate kmem_free(hp->hs_dirent.sym_link, 6837c478bd9Sstevel@tonic-gate (size_t)(hp->hs_dirent.ext_size + 1)); 6847c478bd9Sstevel@tonic-gate hp->hs_dirent.sym_link = NULL; 6857c478bd9Sstevel@tonic-gate } 6867c478bd9Sstevel@tonic-gate if (vn_has_cached_data(vp)) { 6877c478bd9Sstevel@tonic-gate /* clean all old pages */ 6887c478bd9Sstevel@tonic-gate (void) pvn_vplist_dirty(vp, (u_offset_t)0, 6897c478bd9Sstevel@tonic-gate hsfs_putapage, B_INVAL, (struct cred *)NULL); 6907c478bd9Sstevel@tonic-gate /* XXX - can we remove pages by fiat like this??? */ 6917c478bd9Sstevel@tonic-gate vp->v_pages = NULL; 6927c478bd9Sstevel@tonic-gate } 6937c478bd9Sstevel@tonic-gate mutex_destroy(&hp->hs_contents_lock); 6947c478bd9Sstevel@tonic-gate vn_invalid(vp); 6957c478bd9Sstevel@tonic-gate vn_free(vp); 6967c478bd9Sstevel@tonic-gate kmem_cache_free(hsnode_cache, hp); 6977c478bd9Sstevel@tonic-gate fsp->hsfs_nohsnode--; 6987c478bd9Sstevel@tonic-gate return; 6997c478bd9Sstevel@tonic-gate } 7007c478bd9Sstevel@tonic-gate hs_addfreeb(fsp, hp); /* add to back of free list */ 7017c478bd9Sstevel@tonic-gate } 7027c478bd9Sstevel@tonic-gate 7037c478bd9Sstevel@tonic-gate /* 7047c478bd9Sstevel@tonic-gate * hs_remakenode 7057c478bd9Sstevel@tonic-gate * 7067c478bd9Sstevel@tonic-gate * Reconstruct a vnode given the location of its directory entry. 7077c478bd9Sstevel@tonic-gate * Caller specifies the the block number and offset 7087c478bd9Sstevel@tonic-gate * of the directory entry, and the vfs pointer. 7097c478bd9Sstevel@tonic-gate * Returns an error code or 0. 7107c478bd9Sstevel@tonic-gate */ 7117c478bd9Sstevel@tonic-gate int 7127c478bd9Sstevel@tonic-gate hs_remakenode(uint_t lbn, uint_t off, struct vfs *vfsp, 7137c478bd9Sstevel@tonic-gate struct vnode **vpp) 7147c478bd9Sstevel@tonic-gate { 7157c478bd9Sstevel@tonic-gate struct buf *secbp; 7167c478bd9Sstevel@tonic-gate struct hsfs *fsp; 7177c478bd9Sstevel@tonic-gate uint_t secno; 7187c478bd9Sstevel@tonic-gate uchar_t *dirp; 7197c478bd9Sstevel@tonic-gate struct hs_direntry hd; 7207c478bd9Sstevel@tonic-gate int error; 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate /* Convert to sector and offset */ 7237c478bd9Sstevel@tonic-gate fsp = VFS_TO_HSFS(vfsp); 7247c478bd9Sstevel@tonic-gate if (off > HS_SECTOR_SIZE) { 7257c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "hs_remakenode: bad offset"); 7267c478bd9Sstevel@tonic-gate error = EINVAL; 7277c478bd9Sstevel@tonic-gate goto end; 7287c478bd9Sstevel@tonic-gate } 7297c478bd9Sstevel@tonic-gate secno = LBN_TO_SEC(lbn, vfsp); 7307c478bd9Sstevel@tonic-gate secbp = bread(fsp->hsfs_devvp->v_rdev, secno * 4, HS_SECTOR_SIZE); 7317c478bd9Sstevel@tonic-gate 7327c478bd9Sstevel@tonic-gate error = geterror(secbp); 7337c478bd9Sstevel@tonic-gate if (error != 0) { 7347c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "hs_remakenode: bread: error=(%d)", error); 7357c478bd9Sstevel@tonic-gate goto end; 7367c478bd9Sstevel@tonic-gate } 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate dirp = (uchar_t *)secbp->b_un.b_addr; 739fc1c62b8Sfrankho error = hs_parsedir(fsp, &dirp[off], &hd, (char *)NULL, (int *)NULL, 740fc1c62b8Sfrankho HS_SECTOR_SIZE - off); 7417c478bd9Sstevel@tonic-gate if (!error) { 7427c478bd9Sstevel@tonic-gate *vpp = hs_makenode(&hd, lbn, off, vfsp); 7437c478bd9Sstevel@tonic-gate if (*vpp == NULL) 7447c478bd9Sstevel@tonic-gate error = ENFILE; 7457c478bd9Sstevel@tonic-gate } 7467c478bd9Sstevel@tonic-gate 7477c478bd9Sstevel@tonic-gate end: 7487c478bd9Sstevel@tonic-gate brelse(secbp); 7497c478bd9Sstevel@tonic-gate return (error); 7507c478bd9Sstevel@tonic-gate } 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate /* 7547c478bd9Sstevel@tonic-gate * hs_dirlook 7557c478bd9Sstevel@tonic-gate * 7567c478bd9Sstevel@tonic-gate * Look for a given name in a given directory. 7577c478bd9Sstevel@tonic-gate * If found, construct an hsnode for it. 7587c478bd9Sstevel@tonic-gate */ 7597c478bd9Sstevel@tonic-gate int 7607c478bd9Sstevel@tonic-gate hs_dirlook( 7617c478bd9Sstevel@tonic-gate struct vnode *dvp, 7627c478bd9Sstevel@tonic-gate char *name, 7637c478bd9Sstevel@tonic-gate int namlen, /* length of 'name' */ 7647c478bd9Sstevel@tonic-gate struct vnode **vpp, 7657c478bd9Sstevel@tonic-gate struct cred *cred) 7667c478bd9Sstevel@tonic-gate { 7677c478bd9Sstevel@tonic-gate struct hsnode *dhp; 7687c478bd9Sstevel@tonic-gate struct hsfs *fsp; 7697c478bd9Sstevel@tonic-gate int error = 0; 7707c478bd9Sstevel@tonic-gate uint_t offset; /* real offset in directory */ 771d10b6702Sfrankho uint_t last_offset; /* last index in directory */ 7727c478bd9Sstevel@tonic-gate char *cmpname; /* case-folded name */ 7737c478bd9Sstevel@tonic-gate int cmpname_size; /* how much memory we allocate for it */ 7747c478bd9Sstevel@tonic-gate int cmpnamelen; 7757c478bd9Sstevel@tonic-gate int adhoc_search; /* did we start at begin of dir? */ 7767c478bd9Sstevel@tonic-gate int end; 7777c478bd9Sstevel@tonic-gate uint_t hsoffset; 7787c478bd9Sstevel@tonic-gate struct fbuf *fbp; 7797c478bd9Sstevel@tonic-gate int bytes_wanted; 7807c478bd9Sstevel@tonic-gate int dirsiz; 7817c478bd9Sstevel@tonic-gate int is_rrip; 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate if (dvp->v_type != VDIR) 7847c478bd9Sstevel@tonic-gate return (ENOTDIR); 7857c478bd9Sstevel@tonic-gate 7867c478bd9Sstevel@tonic-gate if (error = hs_access(dvp, (mode_t)VEXEC, cred)) 7877c478bd9Sstevel@tonic-gate return (error); 7887c478bd9Sstevel@tonic-gate 7897c478bd9Sstevel@tonic-gate if (hsfs_use_dnlc && (*vpp = dnlc_lookup(dvp, name))) 7907c478bd9Sstevel@tonic-gate return (0); 7917c478bd9Sstevel@tonic-gate 7927c478bd9Sstevel@tonic-gate dhp = VTOH(dvp); 7937c478bd9Sstevel@tonic-gate fsp = VFS_TO_HSFS(dvp->v_vfsp); 794fc1c62b8Sfrankho is_rrip = IS_RRIP_IMPLEMENTED(fsp); 795fc1c62b8Sfrankho 796fc1c62b8Sfrankho /* 797fc1c62b8Sfrankho * name == "^A" is illegal for ISO-9660 and Joliet as '..' is '\1' on 798fc1c62b8Sfrankho * disk. It is no problem for Rock Ridge as RR uses '.' and '..'. 799fc1c62b8Sfrankho * XXX It could be OK for Joliet also (because namelen == 1 is 800fc1c62b8Sfrankho * XXX impossible for UCS-2) but then we need a better compare algorith. 801fc1c62b8Sfrankho */ 802fc1c62b8Sfrankho if (!is_rrip && *name == '\1' && namlen == 1) 803fc1c62b8Sfrankho return (EINVAL); 8047c478bd9Sstevel@tonic-gate 8057c478bd9Sstevel@tonic-gate cmpname_size = (int)(fsp->hsfs_namemax + 1); 8067c478bd9Sstevel@tonic-gate cmpname = kmem_alloc((size_t)cmpname_size, KM_SLEEP); 8077c478bd9Sstevel@tonic-gate 8087c478bd9Sstevel@tonic-gate if (namlen >= cmpname_size) 8097c478bd9Sstevel@tonic-gate namlen = cmpname_size - 1; 8107c478bd9Sstevel@tonic-gate /* 8117c478bd9Sstevel@tonic-gate * For the purposes of comparing the name against dir entries, 8127c478bd9Sstevel@tonic-gate * fold it to upper case. 8137c478bd9Sstevel@tonic-gate */ 8147c478bd9Sstevel@tonic-gate if (is_rrip) { 815cf83459aSfrankho (void) strlcpy(cmpname, name, cmpname_size); 8167c478bd9Sstevel@tonic-gate cmpnamelen = namlen; 8177c478bd9Sstevel@tonic-gate } else { 8187c478bd9Sstevel@tonic-gate /* 8197c478bd9Sstevel@tonic-gate * If we don't consider a trailing dot as part of the filename, 8207c478bd9Sstevel@tonic-gate * remove it from the specified name 8217c478bd9Sstevel@tonic-gate */ 8227c478bd9Sstevel@tonic-gate if ((fsp->hsfs_flags & HSFSMNT_NOTRAILDOT) && 8237c478bd9Sstevel@tonic-gate name[namlen-1] == '.' && 8247c478bd9Sstevel@tonic-gate CAN_TRUNCATE_DOT(name, namlen)) 8257c478bd9Sstevel@tonic-gate name[--namlen] = '\0'; 826fc1c62b8Sfrankho if (fsp->hsfs_vol_type == HS_VOL_TYPE_ISO_V2 || 827fc1c62b8Sfrankho fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET) { 828fc1c62b8Sfrankho cmpnamelen = hs_iso_copy(name, cmpname, namlen); 829fc1c62b8Sfrankho } else { 8307c478bd9Sstevel@tonic-gate cmpnamelen = hs_uppercase_copy(name, cmpname, namlen); 8317c478bd9Sstevel@tonic-gate } 832fc1c62b8Sfrankho } 8337c478bd9Sstevel@tonic-gate 8347c478bd9Sstevel@tonic-gate /* make sure dirent is filled up with all info */ 8357c478bd9Sstevel@tonic-gate if (dhp->hs_dirent.ext_size == 0) 8367c478bd9Sstevel@tonic-gate hs_filldirent(dvp, &dhp->hs_dirent); 8377c478bd9Sstevel@tonic-gate 8387c478bd9Sstevel@tonic-gate /* 8397c478bd9Sstevel@tonic-gate * No lock is needed - hs_offset is used as starting 8407c478bd9Sstevel@tonic-gate * point for searching the directory. 8417c478bd9Sstevel@tonic-gate */ 8427c478bd9Sstevel@tonic-gate offset = dhp->hs_offset; 8437c478bd9Sstevel@tonic-gate hsoffset = offset; 8447c478bd9Sstevel@tonic-gate adhoc_search = (offset != 0); 8457c478bd9Sstevel@tonic-gate 8467c478bd9Sstevel@tonic-gate end = dhp->hs_dirent.ext_size; 8477c478bd9Sstevel@tonic-gate dirsiz = end; 8487c478bd9Sstevel@tonic-gate 8497c478bd9Sstevel@tonic-gate tryagain: 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate while (offset < end) { 852cf83459aSfrankho bytes_wanted = MIN(MAXBSIZE, dirsiz - (offset & MAXBMASK)); 8537c478bd9Sstevel@tonic-gate 8547c478bd9Sstevel@tonic-gate error = fbread(dvp, (offset_t)(offset & MAXBMASK), 8557c478bd9Sstevel@tonic-gate (unsigned int)bytes_wanted, S_READ, &fbp); 8567c478bd9Sstevel@tonic-gate if (error) 8577c478bd9Sstevel@tonic-gate goto done; 8587c478bd9Sstevel@tonic-gate 859cf83459aSfrankho last_offset = (offset & MAXBMASK) + fbp->fb_count; 8607c478bd9Sstevel@tonic-gate 861cf83459aSfrankho switch (process_dirblock(fbp, &offset, last_offset, 862fc1c62b8Sfrankho cmpname, cmpnamelen, fsp, dhp, dvp, vpp, &error)) { 8637c478bd9Sstevel@tonic-gate case FOUND_ENTRY: 8647c478bd9Sstevel@tonic-gate /* found an entry, either correct or not */ 8657c478bd9Sstevel@tonic-gate goto done; 8667c478bd9Sstevel@tonic-gate 8677c478bd9Sstevel@tonic-gate case WENT_PAST: 8687c478bd9Sstevel@tonic-gate /* 8697c478bd9Sstevel@tonic-gate * If we get here we know we didn't find it on the 8707c478bd9Sstevel@tonic-gate * first pass. If adhoc_search, then we started a 8717c478bd9Sstevel@tonic-gate * bit into the dir, and need to wrap around and 8727c478bd9Sstevel@tonic-gate * search the first entries. If not, then we started 8737c478bd9Sstevel@tonic-gate * at the beginning and didn't find it. 8747c478bd9Sstevel@tonic-gate */ 8757c478bd9Sstevel@tonic-gate if (adhoc_search) { 8767c478bd9Sstevel@tonic-gate offset = 0; 8777c478bd9Sstevel@tonic-gate end = hsoffset; 8787c478bd9Sstevel@tonic-gate adhoc_search = 0; 8797c478bd9Sstevel@tonic-gate goto tryagain; 8807c478bd9Sstevel@tonic-gate } 8817c478bd9Sstevel@tonic-gate error = ENOENT; 8827c478bd9Sstevel@tonic-gate goto done; 8837c478bd9Sstevel@tonic-gate 8847c478bd9Sstevel@tonic-gate case HIT_END: 8857c478bd9Sstevel@tonic-gate goto tryagain; 8867c478bd9Sstevel@tonic-gate } 8877c478bd9Sstevel@tonic-gate } 8887c478bd9Sstevel@tonic-gate /* 8897c478bd9Sstevel@tonic-gate * End of all dir blocks, didn't find entry. 8907c478bd9Sstevel@tonic-gate */ 8917c478bd9Sstevel@tonic-gate if (adhoc_search) { 8927c478bd9Sstevel@tonic-gate offset = 0; 8937c478bd9Sstevel@tonic-gate end = hsoffset; 8947c478bd9Sstevel@tonic-gate adhoc_search = 0; 8957c478bd9Sstevel@tonic-gate goto tryagain; 8967c478bd9Sstevel@tonic-gate } 8977c478bd9Sstevel@tonic-gate error = ENOENT; 8987c478bd9Sstevel@tonic-gate done: 8997c478bd9Sstevel@tonic-gate /* 9007c478bd9Sstevel@tonic-gate * If we found the entry, add it to the DNLC 9017c478bd9Sstevel@tonic-gate * If the entry is a device file (assuming we support Rock Ridge), 9027c478bd9Sstevel@tonic-gate * we enter the device vnode to the cache since that is what 9037c478bd9Sstevel@tonic-gate * is in *vpp. 9047c478bd9Sstevel@tonic-gate * That is ok since the CD-ROM is read-only, so (dvp,name) will 9057c478bd9Sstevel@tonic-gate * always point to the same device. 9067c478bd9Sstevel@tonic-gate */ 9077c478bd9Sstevel@tonic-gate if (hsfs_use_dnlc && !error) 9087c478bd9Sstevel@tonic-gate dnlc_enter(dvp, name, *vpp); 9097c478bd9Sstevel@tonic-gate 9107c478bd9Sstevel@tonic-gate kmem_free(cmpname, (size_t)cmpname_size); 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate return (error); 9137c478bd9Sstevel@tonic-gate } 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate /* 9167c478bd9Sstevel@tonic-gate * hs_parsedir 9177c478bd9Sstevel@tonic-gate * 9187c478bd9Sstevel@tonic-gate * Parse a Directory Record into an hs_direntry structure. 9197c478bd9Sstevel@tonic-gate * High Sierra and ISO directory are almost the same 9207c478bd9Sstevel@tonic-gate * except the flag and date 9217c478bd9Sstevel@tonic-gate */ 9227c478bd9Sstevel@tonic-gate int 9237c478bd9Sstevel@tonic-gate hs_parsedir( 9247c478bd9Sstevel@tonic-gate struct hsfs *fsp, 9257c478bd9Sstevel@tonic-gate uchar_t *dirp, 9267c478bd9Sstevel@tonic-gate struct hs_direntry *hdp, 9277c478bd9Sstevel@tonic-gate char *dnp, 928fc1c62b8Sfrankho int *dnlen, 929d10b6702Sfrankho int last_offset) /* last offset in dirp */ 9307c478bd9Sstevel@tonic-gate { 9317c478bd9Sstevel@tonic-gate char *on_disk_name; 9327c478bd9Sstevel@tonic-gate int on_disk_namelen; 933fc1c62b8Sfrankho int on_disk_dirlen; 9347c478bd9Sstevel@tonic-gate uchar_t flags; 9357c478bd9Sstevel@tonic-gate int namelen; 9367c478bd9Sstevel@tonic-gate int error; 9377c478bd9Sstevel@tonic-gate int name_change_flag = 0; /* set if name was gotten in SUA */ 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate hdp->ext_lbn = HDE_EXT_LBN(dirp); 9407c478bd9Sstevel@tonic-gate hdp->ext_size = HDE_EXT_SIZE(dirp); 9417c478bd9Sstevel@tonic-gate hdp->xar_len = HDE_XAR_LEN(dirp); 9427c478bd9Sstevel@tonic-gate hdp->intlf_sz = HDE_INTRLV_SIZE(dirp); 9437c478bd9Sstevel@tonic-gate hdp->intlf_sk = HDE_INTRLV_SKIP(dirp); 9447c478bd9Sstevel@tonic-gate hdp->sym_link = (char *)NULL; 9457c478bd9Sstevel@tonic-gate 9467c478bd9Sstevel@tonic-gate if (fsp->hsfs_vol_type == HS_VOL_TYPE_HS) { 9477c478bd9Sstevel@tonic-gate flags = HDE_FLAGS(dirp); 9487c478bd9Sstevel@tonic-gate hs_parse_dirdate(HDE_cdate(dirp), &hdp->cdate); 9497c478bd9Sstevel@tonic-gate hs_parse_dirdate(HDE_cdate(dirp), &hdp->adate); 9507c478bd9Sstevel@tonic-gate hs_parse_dirdate(HDE_cdate(dirp), &hdp->mdate); 9517c478bd9Sstevel@tonic-gate if ((flags & hde_prohibited) == 0) { 9527c478bd9Sstevel@tonic-gate /* 9537c478bd9Sstevel@tonic-gate * Skip files with the associated bit set. 9547c478bd9Sstevel@tonic-gate */ 9557c478bd9Sstevel@tonic-gate if (flags & HDE_ASSOCIATED) 9567c478bd9Sstevel@tonic-gate return (EAGAIN); 9577c478bd9Sstevel@tonic-gate hdp->type = VREG; 9587c478bd9Sstevel@tonic-gate hdp->mode = HFREG; 9597c478bd9Sstevel@tonic-gate hdp->nlink = 1; 9607c478bd9Sstevel@tonic-gate } else if ((flags & hde_prohibited) == HDE_DIRECTORY) { 9617c478bd9Sstevel@tonic-gate hdp->type = VDIR; 9627c478bd9Sstevel@tonic-gate hdp->mode = HFDIR; 9637c478bd9Sstevel@tonic-gate hdp->nlink = 2; 9647c478bd9Sstevel@tonic-gate } else { 9657c478bd9Sstevel@tonic-gate hs_log_bogus_disk_warning(fsp, 9667c478bd9Sstevel@tonic-gate HSFS_ERR_UNSUP_TYPE, flags); 9677c478bd9Sstevel@tonic-gate return (EINVAL); 9687c478bd9Sstevel@tonic-gate } 9697c478bd9Sstevel@tonic-gate hdp->uid = fsp -> hsfs_vol.vol_uid; 9707c478bd9Sstevel@tonic-gate hdp->gid = fsp -> hsfs_vol.vol_gid; 9717c478bd9Sstevel@tonic-gate hdp->mode = hdp-> mode | (fsp -> hsfs_vol.vol_prot & 0777); 972fc1c62b8Sfrankho } else if ((fsp->hsfs_vol_type == HS_VOL_TYPE_ISO) || 973fc1c62b8Sfrankho (fsp->hsfs_vol_type == HS_VOL_TYPE_ISO_V2) || 974fc1c62b8Sfrankho (fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET)) { 975fc1c62b8Sfrankho 9767c478bd9Sstevel@tonic-gate flags = IDE_FLAGS(dirp); 9777c478bd9Sstevel@tonic-gate hs_parse_dirdate(IDE_cdate(dirp), &hdp->cdate); 9787c478bd9Sstevel@tonic-gate hs_parse_dirdate(IDE_cdate(dirp), &hdp->adate); 9797c478bd9Sstevel@tonic-gate hs_parse_dirdate(IDE_cdate(dirp), &hdp->mdate); 9807c478bd9Sstevel@tonic-gate 9817c478bd9Sstevel@tonic-gate if ((flags & ide_prohibited) == 0) { 9827c478bd9Sstevel@tonic-gate /* 9837c478bd9Sstevel@tonic-gate * Skip files with the associated bit set. 9847c478bd9Sstevel@tonic-gate */ 9857c478bd9Sstevel@tonic-gate if (flags & IDE_ASSOCIATED) 9867c478bd9Sstevel@tonic-gate return (EAGAIN); 9877c478bd9Sstevel@tonic-gate hdp->type = VREG; 9887c478bd9Sstevel@tonic-gate hdp->mode = HFREG; 9897c478bd9Sstevel@tonic-gate hdp->nlink = 1; 9907c478bd9Sstevel@tonic-gate } else if ((flags & ide_prohibited) == IDE_DIRECTORY) { 9917c478bd9Sstevel@tonic-gate hdp->type = VDIR; 9927c478bd9Sstevel@tonic-gate hdp->mode = HFDIR; 9937c478bd9Sstevel@tonic-gate hdp->nlink = 2; 9947c478bd9Sstevel@tonic-gate } else { 9957c478bd9Sstevel@tonic-gate hs_log_bogus_disk_warning(fsp, 9967c478bd9Sstevel@tonic-gate HSFS_ERR_UNSUP_TYPE, flags); 9977c478bd9Sstevel@tonic-gate return (EINVAL); 9987c478bd9Sstevel@tonic-gate } 9997c478bd9Sstevel@tonic-gate hdp->uid = fsp -> hsfs_vol.vol_uid; 10007c478bd9Sstevel@tonic-gate hdp->gid = fsp -> hsfs_vol.vol_gid; 10017c478bd9Sstevel@tonic-gate hdp->mode = hdp-> mode | (fsp -> hsfs_vol.vol_prot & 0777); 1002d10b6702Sfrankho hdp->inode = 0; /* initialize with 0, then check rrip */ 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate /* 10057c478bd9Sstevel@tonic-gate * Having this all filled in, let's see if we have any 10067c478bd9Sstevel@tonic-gate * SUA susp to look at. 10077c478bd9Sstevel@tonic-gate */ 10087c478bd9Sstevel@tonic-gate if (IS_SUSP_IMPLEMENTED(fsp)) { 10097c478bd9Sstevel@tonic-gate error = parse_sua((uchar_t *)dnp, dnlen, 1010d10b6702Sfrankho &name_change_flag, dirp, last_offset, 1011d10b6702Sfrankho hdp, fsp, 10127c478bd9Sstevel@tonic-gate (uchar_t *)NULL, NULL); 10137c478bd9Sstevel@tonic-gate if (error) { 10147c478bd9Sstevel@tonic-gate if (hdp->sym_link) { 10157c478bd9Sstevel@tonic-gate kmem_free(hdp->sym_link, 10167c478bd9Sstevel@tonic-gate (size_t)(hdp->ext_size + 1)); 10177c478bd9Sstevel@tonic-gate hdp->sym_link = (char *)NULL; 10187c478bd9Sstevel@tonic-gate } 10197c478bd9Sstevel@tonic-gate return (error); 10207c478bd9Sstevel@tonic-gate } 10217c478bd9Sstevel@tonic-gate } 10227c478bd9Sstevel@tonic-gate } 10237c478bd9Sstevel@tonic-gate hdp->xar_prot = (HDE_PROTECTION & flags) != 0; 10247c478bd9Sstevel@tonic-gate 10257c478bd9Sstevel@tonic-gate #if dontskip 10267c478bd9Sstevel@tonic-gate if (hdp->xar_len > 0) { 10277c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "hsfs: extended attributes not supported"); 10287c478bd9Sstevel@tonic-gate return (EINVAL); 10297c478bd9Sstevel@tonic-gate } 10307c478bd9Sstevel@tonic-gate #endif 10317c478bd9Sstevel@tonic-gate 10327c478bd9Sstevel@tonic-gate /* check interleaf size and skip factor */ 10337c478bd9Sstevel@tonic-gate /* must both be zero or non-zero */ 10347c478bd9Sstevel@tonic-gate if (hdp->intlf_sz + hdp->intlf_sk) { 10357c478bd9Sstevel@tonic-gate if ((hdp->intlf_sz == 0) || (hdp->intlf_sk == 0)) { 10367c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, 10377c478bd9Sstevel@tonic-gate "hsfs: interleaf size or skip factor error"); 10387c478bd9Sstevel@tonic-gate return (EINVAL); 10397c478bd9Sstevel@tonic-gate } 10407c478bd9Sstevel@tonic-gate if (hdp->ext_size == 0) { 10417c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, 10427c478bd9Sstevel@tonic-gate "hsfs: interleaving specified on zero length file"); 10437c478bd9Sstevel@tonic-gate return (EINVAL); 10447c478bd9Sstevel@tonic-gate } 10457c478bd9Sstevel@tonic-gate } 10467c478bd9Sstevel@tonic-gate 10477c478bd9Sstevel@tonic-gate if (HDE_VOL_SET(dirp) != 1) { 10487c478bd9Sstevel@tonic-gate if (fsp->hsfs_vol.vol_set_size != 1 && 10497c478bd9Sstevel@tonic-gate fsp->hsfs_vol.vol_set_size != HDE_VOL_SET(dirp)) { 10507c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "hsfs: multivolume file?"); 10517c478bd9Sstevel@tonic-gate return (EINVAL); 10527c478bd9Sstevel@tonic-gate } 10537c478bd9Sstevel@tonic-gate } 10547c478bd9Sstevel@tonic-gate 10557c478bd9Sstevel@tonic-gate /* 10567c478bd9Sstevel@tonic-gate * If the name changed, then the NM field for RRIP was hit and 10577c478bd9Sstevel@tonic-gate * we should not copy the name again, just return. 10587c478bd9Sstevel@tonic-gate */ 10597c478bd9Sstevel@tonic-gate if (NAME_HAS_CHANGED(name_change_flag)) 10607c478bd9Sstevel@tonic-gate return (0); 10617c478bd9Sstevel@tonic-gate 1062cf83459aSfrankho /* 1063cf83459aSfrankho * Fall back to the ISO name. Note that as in process_dirblock, 1064cf83459aSfrankho * the on-disk filename length must be validated against ISO 1065cf83459aSfrankho * limits - which, in case of RR present but no RR name found, 1066cf83459aSfrankho * are NOT identical to fsp->hsfs_namemax on this filesystem. 1067cf83459aSfrankho */ 10687c478bd9Sstevel@tonic-gate on_disk_name = (char *)HDE_name(dirp); 10697c478bd9Sstevel@tonic-gate on_disk_namelen = (int)HDE_NAME_LEN(dirp); 1070fc1c62b8Sfrankho on_disk_dirlen = (int)HDE_DIR_LEN(dirp); 10717c478bd9Sstevel@tonic-gate 1072fc1c62b8Sfrankho if (on_disk_dirlen < HDE_ROOT_DIR_REC_SIZE || 1073fc1c62b8Sfrankho ((on_disk_dirlen > last_offset) || 1074fc1c62b8Sfrankho ((HDE_FDESIZE + on_disk_namelen) > on_disk_dirlen))) { 1075fc1c62b8Sfrankho hs_log_bogus_disk_warning(fsp, 1076fc1c62b8Sfrankho HSFS_ERR_BAD_DIR_ENTRY, 0); 1077fc1c62b8Sfrankho return (EINVAL); 10787c478bd9Sstevel@tonic-gate } 1079fc1c62b8Sfrankho 1080fc1c62b8Sfrankho if (on_disk_namelen > fsp->hsfs_namelen && 1081fc1c62b8Sfrankho hs_namelen(fsp, on_disk_name, on_disk_namelen) > 1082fc1c62b8Sfrankho fsp->hsfs_namelen) { 1083fc1c62b8Sfrankho hs_log_bogus_disk_warning(fsp, 1084fc1c62b8Sfrankho fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET ? 1085fc1c62b8Sfrankho HSFS_ERR_BAD_JOLIET_FILE_LEN : 1086d10b6702Sfrankho HSFS_ERR_BAD_FILE_LEN, 0); 1087fc1c62b8Sfrankho } 1088fc1c62b8Sfrankho if (on_disk_namelen > ISO_NAMELEN_V2_MAX) 1089fc1c62b8Sfrankho on_disk_namelen = fsp->hsfs_namemax; /* Paranoia */ 1090fc1c62b8Sfrankho 10917c478bd9Sstevel@tonic-gate if (dnp != NULL) { 1092fc1c62b8Sfrankho if (fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET) { 1093fc1c62b8Sfrankho namelen = hs_jnamecopy(on_disk_name, dnp, 1094d10b6702Sfrankho on_disk_namelen, fsp->hsfs_namemax, 10957c478bd9Sstevel@tonic-gate fsp->hsfs_flags); 1096fc1c62b8Sfrankho /* 1097fc1c62b8Sfrankho * A negative return value means that the file name 1098fc1c62b8Sfrankho * has been truncated to fsp->hsfs_namemax. 1099fc1c62b8Sfrankho */ 1100fc1c62b8Sfrankho if (namelen < 0) { 1101fc1c62b8Sfrankho namelen = -namelen; 1102fc1c62b8Sfrankho hs_log_bogus_disk_warning(fsp, 1103d10b6702Sfrankho HSFS_ERR_TRUNC_JOLIET_FILE_LEN, 0); 1104fc1c62b8Sfrankho } 1105fc1c62b8Sfrankho } else { 1106fc1c62b8Sfrankho /* 1107fc1c62b8Sfrankho * HS_VOL_TYPE_ISO && HS_VOL_TYPE_ISO_V2 1108fc1c62b8Sfrankho */ 1109fc1c62b8Sfrankho namelen = hs_namecopy(on_disk_name, dnp, 1110d10b6702Sfrankho on_disk_namelen, fsp->hsfs_flags); 1111fc1c62b8Sfrankho } 1112fc1c62b8Sfrankho if (namelen == 0) 1113fc1c62b8Sfrankho return (EINVAL); 11147c478bd9Sstevel@tonic-gate if ((fsp->hsfs_flags & HSFSMNT_NOTRAILDOT) && 11157c478bd9Sstevel@tonic-gate dnp[ namelen-1 ] == '.' && CAN_TRUNCATE_DOT(dnp, namelen)) 11167c478bd9Sstevel@tonic-gate dnp[ --namelen ] = '\0'; 11177c478bd9Sstevel@tonic-gate } else 11187c478bd9Sstevel@tonic-gate namelen = on_disk_namelen; 11197c478bd9Sstevel@tonic-gate if (dnlen != NULL) 11207c478bd9Sstevel@tonic-gate *dnlen = namelen; 11217c478bd9Sstevel@tonic-gate 11227c478bd9Sstevel@tonic-gate return (0); 11237c478bd9Sstevel@tonic-gate } 11247c478bd9Sstevel@tonic-gate 11257c478bd9Sstevel@tonic-gate /* 11267c478bd9Sstevel@tonic-gate * hs_namecopy 11277c478bd9Sstevel@tonic-gate * 11287c478bd9Sstevel@tonic-gate * Parse a file/directory name into UNIX form. 11297c478bd9Sstevel@tonic-gate * Delete trailing blanks, upper-to-lower case, add NULL terminator. 11307c478bd9Sstevel@tonic-gate * Returns the (possibly new) length. 1131fc1c62b8Sfrankho * 1132fc1c62b8Sfrankho * Called from hsfs_readdir() via hs_parsedir() 11337c478bd9Sstevel@tonic-gate */ 11347c478bd9Sstevel@tonic-gate int 11357c478bd9Sstevel@tonic-gate hs_namecopy(char *from, char *to, int size, ulong_t flags) 11367c478bd9Sstevel@tonic-gate { 11377c478bd9Sstevel@tonic-gate uint_t i; 11387c478bd9Sstevel@tonic-gate uchar_t c; 11397c478bd9Sstevel@tonic-gate int lastspace; 11407c478bd9Sstevel@tonic-gate int maplc; 1141fc1c62b8Sfrankho int trailspace; 1142fc1c62b8Sfrankho int version; 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate /* special handling for '.' and '..' */ 11457c478bd9Sstevel@tonic-gate if (size == 1) { 11467c478bd9Sstevel@tonic-gate if (*from == '\0') { 11477c478bd9Sstevel@tonic-gate *to++ = '.'; 11487c478bd9Sstevel@tonic-gate *to = '\0'; 11497c478bd9Sstevel@tonic-gate return (1); 11507c478bd9Sstevel@tonic-gate } else if (*from == '\1') { 11517c478bd9Sstevel@tonic-gate *to++ = '.'; 11527c478bd9Sstevel@tonic-gate *to++ = '.'; 11537c478bd9Sstevel@tonic-gate *to = '\0'; 11547c478bd9Sstevel@tonic-gate return (2); 11557c478bd9Sstevel@tonic-gate } 11567c478bd9Sstevel@tonic-gate } 11577c478bd9Sstevel@tonic-gate 11587c478bd9Sstevel@tonic-gate maplc = (flags & HSFSMNT_NOMAPLCASE) == 0; 1159fc1c62b8Sfrankho trailspace = (flags & HSFSMNT_NOTRAILSPACE) == 0; 1160fc1c62b8Sfrankho version = (flags & HSFSMNT_NOVERSION) == 0; 11617c478bd9Sstevel@tonic-gate for (i = 0, lastspace = -1; i < size; i++) { 11627c478bd9Sstevel@tonic-gate c = from[i]; 1163fc1c62b8Sfrankho if (c == ';' && version) 11647c478bd9Sstevel@tonic-gate break; 1165fc1c62b8Sfrankho if (c <= ' ' && !trailspace) { 11667c478bd9Sstevel@tonic-gate if (lastspace == -1) 11677c478bd9Sstevel@tonic-gate lastspace = i; 11687c478bd9Sstevel@tonic-gate } else 11697c478bd9Sstevel@tonic-gate lastspace = -1; 11707c478bd9Sstevel@tonic-gate if (maplc && (c >= 'A') && (c <= 'Z')) 11717c478bd9Sstevel@tonic-gate c += 'a' - 'A'; 11727c478bd9Sstevel@tonic-gate to[i] = c; 11737c478bd9Sstevel@tonic-gate } 11747c478bd9Sstevel@tonic-gate if (lastspace != -1) 11757c478bd9Sstevel@tonic-gate i = lastspace; 11767c478bd9Sstevel@tonic-gate to[i] = '\0'; 11777c478bd9Sstevel@tonic-gate return (i); 11787c478bd9Sstevel@tonic-gate } 11797c478bd9Sstevel@tonic-gate 11807c478bd9Sstevel@tonic-gate /* 1181fc1c62b8Sfrankho * hs_jnamecopy 1182fc1c62b8Sfrankho * 1183fc1c62b8Sfrankho * This is the Joliet variant of hs_namecopy() 1184fc1c62b8Sfrankho * 1185fc1c62b8Sfrankho * Parse a UCS-2 Joliet file/directory name into UNIX form. 1186fc1c62b8Sfrankho * Add NULL terminator. 1187fc1c62b8Sfrankho * Returns the new length. 1188fc1c62b8Sfrankho * 1189fc1c62b8Sfrankho * Called from hsfs_readdir() via hs_parsedir() 1190fc1c62b8Sfrankho */ 1191fc1c62b8Sfrankho int 1192fc1c62b8Sfrankho hs_jnamecopy(char *from, char *to, int size, int maxsize, ulong_t flags) 1193fc1c62b8Sfrankho { 1194fc1c62b8Sfrankho uint_t i; 1195fc1c62b8Sfrankho uint_t len; 1196fc1c62b8Sfrankho uint16_t c; 1197fc1c62b8Sfrankho int amt; 1198fc1c62b8Sfrankho int version; 1199fc1c62b8Sfrankho 1200fc1c62b8Sfrankho /* special handling for '.' and '..' */ 1201fc1c62b8Sfrankho if (size == 1) { 1202fc1c62b8Sfrankho if (*from == '\0') { 1203fc1c62b8Sfrankho *to++ = '.'; 1204fc1c62b8Sfrankho *to = '\0'; 1205fc1c62b8Sfrankho return (1); 1206fc1c62b8Sfrankho } else if (*from == '\1') { 1207fc1c62b8Sfrankho *to++ = '.'; 1208fc1c62b8Sfrankho *to++ = '.'; 1209fc1c62b8Sfrankho *to = '\0'; 1210fc1c62b8Sfrankho return (2); 1211fc1c62b8Sfrankho } 1212fc1c62b8Sfrankho } 1213fc1c62b8Sfrankho 1214fc1c62b8Sfrankho version = (flags & HSFSMNT_NOVERSION) == 0; 1215fc1c62b8Sfrankho for (i = 0, len = 0; i < size; i++) { 1216fc1c62b8Sfrankho c = (from[i++] & 0xFF) << 8; 1217fc1c62b8Sfrankho c |= from[i] & 0xFF; 1218fc1c62b8Sfrankho if (c == ';' && version) 1219fc1c62b8Sfrankho break; 1220fc1c62b8Sfrankho 1221fc1c62b8Sfrankho if (len > (maxsize-3)) { 1222fc1c62b8Sfrankho if (c < 0x80) 1223fc1c62b8Sfrankho amt = 1; 1224fc1c62b8Sfrankho else if (c < 0x800) 1225fc1c62b8Sfrankho amt = 2; 1226fc1c62b8Sfrankho else 1227fc1c62b8Sfrankho amt = 3; 1228fc1c62b8Sfrankho if ((len+amt) > maxsize) { 1229fc1c62b8Sfrankho to[len] = '\0'; 1230fc1c62b8Sfrankho return (-len); 1231fc1c62b8Sfrankho } 1232fc1c62b8Sfrankho } 1233fc1c62b8Sfrankho amt = hs_ucs2_2_utf8(c, (uint8_t *)&to[len]); 1234fc1c62b8Sfrankho if (amt == 0) { 1235fc1c62b8Sfrankho hs_log_bogus_joliet_warning(); /* should never happen */ 1236fc1c62b8Sfrankho return (0); 1237fc1c62b8Sfrankho } 1238fc1c62b8Sfrankho len += amt; 1239fc1c62b8Sfrankho } 1240fc1c62b8Sfrankho to[len] = '\0'; 1241fc1c62b8Sfrankho return (len); 1242fc1c62b8Sfrankho } 1243fc1c62b8Sfrankho 1244fc1c62b8Sfrankho /* 12457c478bd9Sstevel@tonic-gate * map a filename to upper case; 12467c478bd9Sstevel@tonic-gate * return 1 if found lowercase character 1247fc1c62b8Sfrankho * 1248fc1c62b8Sfrankho * Called from process_dirblock() 1249fc1c62b8Sfrankho * via hsfs_lookup() -> hs_dirlook() -> process_dirblock() 1250fc1c62b8Sfrankho * to create an intermedia name from on disk file names for 1251fc1c62b8Sfrankho * comparing names. 12527c478bd9Sstevel@tonic-gate */ 12537c478bd9Sstevel@tonic-gate static int 12547c478bd9Sstevel@tonic-gate uppercase_cp(char *from, char *to, int size) 12557c478bd9Sstevel@tonic-gate { 12567c478bd9Sstevel@tonic-gate uint_t i; 12577c478bd9Sstevel@tonic-gate uchar_t c; 12587c478bd9Sstevel@tonic-gate uchar_t had_lc = 0; 12597c478bd9Sstevel@tonic-gate 12607c478bd9Sstevel@tonic-gate for (i = 0; i < size; i++) { 12617c478bd9Sstevel@tonic-gate c = *from++; 12627c478bd9Sstevel@tonic-gate if ((c >= 'a') && (c <= 'z')) { 12637c478bd9Sstevel@tonic-gate c -= ('a' - 'A'); 12647c478bd9Sstevel@tonic-gate had_lc = 1; 12657c478bd9Sstevel@tonic-gate } 12667c478bd9Sstevel@tonic-gate *to++ = c; 12677c478bd9Sstevel@tonic-gate } 12687c478bd9Sstevel@tonic-gate return (had_lc); 12697c478bd9Sstevel@tonic-gate } 12707c478bd9Sstevel@tonic-gate 12717c478bd9Sstevel@tonic-gate /* 1272fc1c62b8Sfrankho * This is the Joliet variant of uppercase_cp() 1273fc1c62b8Sfrankho * 1274fc1c62b8Sfrankho * map a UCS-2 filename to UTF-8; 1275fc1c62b8Sfrankho * return new length 1276fc1c62b8Sfrankho * 1277fc1c62b8Sfrankho * Called from process_dirblock() 1278fc1c62b8Sfrankho * via hsfs_lookup() -> hs_dirlook() -> process_dirblock() 1279fc1c62b8Sfrankho * to create an intermedia name from on disk file names for 1280fc1c62b8Sfrankho * comparing names. 1281fc1c62b8Sfrankho */ 1282fc1c62b8Sfrankho int 1283fc1c62b8Sfrankho hs_joliet_cp(char *from, char *to, int size) 1284fc1c62b8Sfrankho { 1285fc1c62b8Sfrankho uint_t i; 1286fc1c62b8Sfrankho uint16_t c; 1287fc1c62b8Sfrankho int len = 0; 1288fc1c62b8Sfrankho int amt; 1289fc1c62b8Sfrankho 1290fc1c62b8Sfrankho /* special handling for '\0' and '\1' */ 1291fc1c62b8Sfrankho if (size == 1) { 1292fc1c62b8Sfrankho *to = *from; 1293fc1c62b8Sfrankho return (1); 1294fc1c62b8Sfrankho } 1295fc1c62b8Sfrankho for (i = 0; i < size; i += 2) { 1296fc1c62b8Sfrankho c = (*from++ & 0xFF) << 8; 1297fc1c62b8Sfrankho c |= *from++ & 0xFF; 1298fc1c62b8Sfrankho 1299fc1c62b8Sfrankho amt = hs_ucs2_2_utf8(c, (uint8_t *)to); 1300fc1c62b8Sfrankho if (amt == 0) { 1301fc1c62b8Sfrankho hs_log_bogus_joliet_warning(); /* should never happen */ 1302fc1c62b8Sfrankho return (0); 1303fc1c62b8Sfrankho } 1304fc1c62b8Sfrankho 1305fc1c62b8Sfrankho to += amt; 1306fc1c62b8Sfrankho len += amt; 1307fc1c62b8Sfrankho } 1308fc1c62b8Sfrankho return (len); 1309fc1c62b8Sfrankho } 1310fc1c62b8Sfrankho 1311fc1c62b8Sfrankho static void 1312fc1c62b8Sfrankho hs_log_bogus_joliet_warning(void) 1313fc1c62b8Sfrankho { 1314fc1c62b8Sfrankho static int warned = 0; 1315fc1c62b8Sfrankho 1316fc1c62b8Sfrankho if (warned) 1317fc1c62b8Sfrankho return; 1318fc1c62b8Sfrankho warned = 1; 1319fc1c62b8Sfrankho cmn_err(CE_CONT, "hsfs: Warning: " 1320fc1c62b8Sfrankho "file name contains bad UCS-2 chacarter\n"); 1321fc1c62b8Sfrankho } 1322fc1c62b8Sfrankho 1323fc1c62b8Sfrankho 1324fc1c62b8Sfrankho /* 13257c478bd9Sstevel@tonic-gate * hs_uppercase_copy 13267c478bd9Sstevel@tonic-gate * 1327fc1c62b8Sfrankho * Convert a UNIX-style name into its HSFS equivalent 1328fc1c62b8Sfrankho * replacing '.' and '..' with '\0' and '\1'. 13297c478bd9Sstevel@tonic-gate * Map to upper case. 13307c478bd9Sstevel@tonic-gate * Returns the (possibly new) length. 1331fc1c62b8Sfrankho * 1332fc1c62b8Sfrankho * Called from hs_dirlook() and rrip_namecopy() 1333fc1c62b8Sfrankho * to create an intermediate name from the callers name from hsfs_lookup() 1334fc1c62b8Sfrankho * XXX Is the call from rrip_namecopy() OK? 13357c478bd9Sstevel@tonic-gate */ 13367c478bd9Sstevel@tonic-gate int 13377c478bd9Sstevel@tonic-gate hs_uppercase_copy(char *from, char *to, int size) 13387c478bd9Sstevel@tonic-gate { 13397c478bd9Sstevel@tonic-gate uint_t i; 13407c478bd9Sstevel@tonic-gate uchar_t c; 13417c478bd9Sstevel@tonic-gate 13427c478bd9Sstevel@tonic-gate /* special handling for '.' and '..' */ 13437c478bd9Sstevel@tonic-gate 13447c478bd9Sstevel@tonic-gate if (size == 1 && *from == '.') { 13457c478bd9Sstevel@tonic-gate *to = '\0'; 13467c478bd9Sstevel@tonic-gate return (1); 13477c478bd9Sstevel@tonic-gate } else if (size == 2 && *from == '.' && *(from+1) == '.') { 13487c478bd9Sstevel@tonic-gate *to = '\1'; 13497c478bd9Sstevel@tonic-gate return (1); 13507c478bd9Sstevel@tonic-gate } 13517c478bd9Sstevel@tonic-gate 13527c478bd9Sstevel@tonic-gate for (i = 0; i < size; i++) { 13537c478bd9Sstevel@tonic-gate c = *from++; 13547c478bd9Sstevel@tonic-gate if ((c >= 'a') && (c <= 'z')) 13557c478bd9Sstevel@tonic-gate c = c - 'a' + 'A'; 13567c478bd9Sstevel@tonic-gate *to++ = c; 13577c478bd9Sstevel@tonic-gate } 13587c478bd9Sstevel@tonic-gate return (size); 13597c478bd9Sstevel@tonic-gate } 13607c478bd9Sstevel@tonic-gate 1361fc1c62b8Sfrankho /* 1362fc1c62b8Sfrankho * hs_iso_copy 1363fc1c62b8Sfrankho * 1364fc1c62b8Sfrankho * This is the Joliet/ISO-9660:1999 variant of hs_uppercase_copy() 1365fc1c62b8Sfrankho * 1366fc1c62b8Sfrankho * Convert a UTF-8 UNIX-style name into its UTF-8 Joliet/ISO equivalent 1367fc1c62b8Sfrankho * replacing '.' and '..' with '\0' and '\1'. 1368fc1c62b8Sfrankho * Returns the (possibly new) length. 1369fc1c62b8Sfrankho * 1370fc1c62b8Sfrankho * Called from hs_dirlook() 1371fc1c62b8Sfrankho * to create an intermediate name from the callers name from hsfs_lookup() 1372fc1c62b8Sfrankho */ 1373fc1c62b8Sfrankho static int 1374fc1c62b8Sfrankho hs_iso_copy(char *from, char *to, int size) 1375fc1c62b8Sfrankho { 1376fc1c62b8Sfrankho uint_t i; 1377fc1c62b8Sfrankho uchar_t c; 1378fc1c62b8Sfrankho 1379fc1c62b8Sfrankho /* special handling for '.' and '..' */ 1380fc1c62b8Sfrankho 1381fc1c62b8Sfrankho if (size == 1 && *from == '.') { 1382fc1c62b8Sfrankho *to = '\0'; 1383fc1c62b8Sfrankho return (1); 1384fc1c62b8Sfrankho } else if (size == 2 && *from == '.' && *(from+1) == '.') { 1385fc1c62b8Sfrankho *to = '\1'; 1386fc1c62b8Sfrankho return (1); 1387fc1c62b8Sfrankho } 1388fc1c62b8Sfrankho 1389fc1c62b8Sfrankho for (i = 0; i < size; i++) { 1390fc1c62b8Sfrankho c = *from++; 1391fc1c62b8Sfrankho *to++ = c; 1392fc1c62b8Sfrankho } 1393fc1c62b8Sfrankho return (size); 1394fc1c62b8Sfrankho } 1395fc1c62b8Sfrankho 13967c478bd9Sstevel@tonic-gate void 13977c478bd9Sstevel@tonic-gate hs_filldirent(struct vnode *vp, struct hs_direntry *hdp) 13987c478bd9Sstevel@tonic-gate { 13997c478bd9Sstevel@tonic-gate struct buf *secbp; 14007c478bd9Sstevel@tonic-gate uint_t secno; 14017c478bd9Sstevel@tonic-gate offset_t secoff; 14027c478bd9Sstevel@tonic-gate struct hsfs *fsp; 14037c478bd9Sstevel@tonic-gate uchar_t *secp; 14047c478bd9Sstevel@tonic-gate int error; 14057c478bd9Sstevel@tonic-gate 14067c478bd9Sstevel@tonic-gate if (vp->v_type != VDIR) { 14077c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "hsfs_filldirent: vp (0x%p) not a directory", 14087c478bd9Sstevel@tonic-gate (void *)vp); 14097c478bd9Sstevel@tonic-gate return; 14107c478bd9Sstevel@tonic-gate } 14117c478bd9Sstevel@tonic-gate 14127c478bd9Sstevel@tonic-gate fsp = VFS_TO_HSFS(vp ->v_vfsp); 14137c478bd9Sstevel@tonic-gate secno = LBN_TO_SEC(hdp->ext_lbn+hdp->xar_len, vp->v_vfsp); 14147c478bd9Sstevel@tonic-gate secoff = LBN_TO_BYTE(hdp->ext_lbn+hdp->xar_len, vp->v_vfsp) & 14157c478bd9Sstevel@tonic-gate MAXHSOFFSET; 14167c478bd9Sstevel@tonic-gate secbp = bread(fsp->hsfs_devvp->v_rdev, secno * 4, HS_SECTOR_SIZE); 14177c478bd9Sstevel@tonic-gate error = geterror(secbp); 14187c478bd9Sstevel@tonic-gate if (error != 0) { 14197c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "hs_filldirent: bread: error=(%d)", error); 14207c478bd9Sstevel@tonic-gate goto end; 14217c478bd9Sstevel@tonic-gate } 14227c478bd9Sstevel@tonic-gate 14237c478bd9Sstevel@tonic-gate secp = (uchar_t *)secbp->b_un.b_addr; 14247c478bd9Sstevel@tonic-gate 14257c478bd9Sstevel@tonic-gate /* quick check */ 14267c478bd9Sstevel@tonic-gate if (hdp->ext_lbn != HDE_EXT_LBN(&secp[secoff])) { 14277c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "hsfs_filldirent: dirent not match"); 14287c478bd9Sstevel@tonic-gate /* keep on going */ 14297c478bd9Sstevel@tonic-gate } 1430fc1c62b8Sfrankho (void) hs_parsedir(fsp, &secp[secoff], hdp, (char *)NULL, 1431fc1c62b8Sfrankho (int *)NULL, HS_SECTOR_SIZE - secoff); 14327c478bd9Sstevel@tonic-gate 14337c478bd9Sstevel@tonic-gate end: 14347c478bd9Sstevel@tonic-gate brelse(secbp); 14357c478bd9Sstevel@tonic-gate } 14367c478bd9Sstevel@tonic-gate 14377c478bd9Sstevel@tonic-gate /* 14387c478bd9Sstevel@tonic-gate * Look through a directory block for a matching entry. 14397c478bd9Sstevel@tonic-gate * Note: this routine does an fbrelse() on the buffer passed in. 14407c478bd9Sstevel@tonic-gate */ 14417c478bd9Sstevel@tonic-gate static enum dirblock_result 14427c478bd9Sstevel@tonic-gate process_dirblock( 14437c478bd9Sstevel@tonic-gate struct fbuf *fbp, /* buffer containing dirblk */ 14447c478bd9Sstevel@tonic-gate uint_t *offset, /* lower index */ 14457c478bd9Sstevel@tonic-gate uint_t last_offset, /* upper index */ 14467c478bd9Sstevel@tonic-gate char *nm, /* upcase nm to compare against */ 14477c478bd9Sstevel@tonic-gate int nmlen, /* length of name */ 14487c478bd9Sstevel@tonic-gate struct hsfs *fsp, 14497c478bd9Sstevel@tonic-gate struct hsnode *dhp, 14507c478bd9Sstevel@tonic-gate struct vnode *dvp, 14517c478bd9Sstevel@tonic-gate struct vnode **vpp, 1452fc1c62b8Sfrankho int *error) /* return value: errno */ 14537c478bd9Sstevel@tonic-gate { 14547c478bd9Sstevel@tonic-gate uchar_t *blkp = (uchar_t *)fbp->fb_addr; /* dir block */ 14557c478bd9Sstevel@tonic-gate char *dname; /* name in directory entry */ 14567c478bd9Sstevel@tonic-gate int dnamelen; /* length of name */ 14577c478bd9Sstevel@tonic-gate struct hs_direntry hd; 14587c478bd9Sstevel@tonic-gate int hdlen; 14597c478bd9Sstevel@tonic-gate uchar_t *dirp; /* the directory entry */ 14607c478bd9Sstevel@tonic-gate int res; 14617c478bd9Sstevel@tonic-gate int parsedir_res; 1462fc1c62b8Sfrankho int is_rrip; 14637c478bd9Sstevel@tonic-gate size_t rrip_name_size; 1464cf83459aSfrankho int rr_namelen = 0; 14657c478bd9Sstevel@tonic-gate char *rrip_name_str = NULL; 14667c478bd9Sstevel@tonic-gate char *rrip_tmp_name = NULL; 14677c478bd9Sstevel@tonic-gate enum dirblock_result err = 0; 14687c478bd9Sstevel@tonic-gate int did_fbrelse = 0; 1469fc1c62b8Sfrankho char uppercase_name[JOLIET_NAMELEN_MAX*3 + 1]; /* 331 */ 14707c478bd9Sstevel@tonic-gate 1471cf83459aSfrankho #define PD_return(retval) \ 1472cf83459aSfrankho { err = retval; goto do_ret; } /* return after cleanup */ 1473cf83459aSfrankho #define rel_offset(offset) \ 1474cf83459aSfrankho ((offset) & MAXBOFFSET) /* index into cur blk */ 1475fc1c62b8Sfrankho #define RESTORE_NM(tmp, orig) \ 1476fc1c62b8Sfrankho if (is_rrip && *(tmp) != '\0') \ 1477fc1c62b8Sfrankho (void) strcpy((orig), (tmp)) 14787c478bd9Sstevel@tonic-gate 1479fc1c62b8Sfrankho is_rrip = IS_RRIP_IMPLEMENTED(fsp); 14807c478bd9Sstevel@tonic-gate if (is_rrip) { 14817c478bd9Sstevel@tonic-gate rrip_name_size = RRIP_FILE_NAMELEN + 1; 14827c478bd9Sstevel@tonic-gate rrip_name_str = kmem_alloc(rrip_name_size, KM_SLEEP); 14837c478bd9Sstevel@tonic-gate rrip_tmp_name = kmem_alloc(rrip_name_size, KM_SLEEP); 14847c478bd9Sstevel@tonic-gate rrip_name_str[0] = '\0'; 14857c478bd9Sstevel@tonic-gate rrip_tmp_name[0] = '\0'; 14867c478bd9Sstevel@tonic-gate } 14877c478bd9Sstevel@tonic-gate 14887c478bd9Sstevel@tonic-gate while (*offset < last_offset) { 14897c478bd9Sstevel@tonic-gate 14907c478bd9Sstevel@tonic-gate /* 14917c478bd9Sstevel@tonic-gate * Directory Entries cannot span sectors. 1492cf83459aSfrankho * 1493cf83459aSfrankho * Unused bytes at the end of each sector are zeroed 1494cf83459aSfrankho * according to ISO9660, but we cannot rely on this 1495cf83459aSfrankho * since both media failures and maliciously corrupted 1496cf83459aSfrankho * media may return arbitrary values. 1497cf83459aSfrankho * We therefore have to check for consistency: 1498cf83459aSfrankho * The size of a directory entry must be at least 1499cf83459aSfrankho * 34 bytes (the size of the directory entry metadata), 1500cf83459aSfrankho * or zero (indicating the end-of-sector condition). 1501cf83459aSfrankho * For a non-zero directory entry size of less than 1502cf83459aSfrankho * 34 Bytes, log a warning. 1503cf83459aSfrankho * In any case, skip the rest of this sector and 1504cf83459aSfrankho * continue with the next. 15057c478bd9Sstevel@tonic-gate */ 15067c478bd9Sstevel@tonic-gate hdlen = (int)((uchar_t) 15077c478bd9Sstevel@tonic-gate HDE_DIR_LEN(&blkp[rel_offset(*offset)])); 15087c478bd9Sstevel@tonic-gate 1509cf83459aSfrankho if (hdlen < HDE_ROOT_DIR_REC_SIZE || 1510cf83459aSfrankho *offset + hdlen > last_offset) { 1511cf83459aSfrankho /* 1512cf83459aSfrankho * Advance to the next sector boundary 1513cf83459aSfrankho */ 1514cf83459aSfrankho *offset = roundup(*offset + 1, HS_SECTOR_SIZE); 1515cf83459aSfrankho if (hdlen) 1516cf83459aSfrankho hs_log_bogus_disk_warning(fsp, 1517cf83459aSfrankho HSFS_ERR_TRAILING_JUNK, 0); 15187c478bd9Sstevel@tonic-gate continue; 15197c478bd9Sstevel@tonic-gate } 15207c478bd9Sstevel@tonic-gate 15217c478bd9Sstevel@tonic-gate bzero(&hd, sizeof (hd)); 15227c478bd9Sstevel@tonic-gate 15237c478bd9Sstevel@tonic-gate /* 1524cf83459aSfrankho * Check the filename length in the ISO record for 1525cf83459aSfrankho * plausibility and reset it to a safe value, in case 1526cf83459aSfrankho * the name length byte is out of range. Since the ISO 1527cf83459aSfrankho * name will be used as fallback if the rockridge name 1528cf83459aSfrankho * is invalid/nonexistant, we must make sure not to 1529cf83459aSfrankho * blow the bounds and initialize dnamelen to a sensible 1530cf83459aSfrankho * value within the limits of ISO9660. 1531cf83459aSfrankho * In addition to that, the ISO filename is part of the 1532cf83459aSfrankho * directory entry. If the filename length is too large 1533cf83459aSfrankho * to fit, the record is invalid and we'll advance to 1534cf83459aSfrankho * the next. 15357c478bd9Sstevel@tonic-gate */ 15367c478bd9Sstevel@tonic-gate dirp = &blkp[rel_offset(*offset)]; 15377c478bd9Sstevel@tonic-gate dname = (char *)HDE_name(dirp); 15387c478bd9Sstevel@tonic-gate dnamelen = (int)((uchar_t)HDE_NAME_LEN(dirp)); 1539fc1c62b8Sfrankho /* 1540fc1c62b8Sfrankho * If the directory entry extends beyond the end of the 1541fc1c62b8Sfrankho * block, it must be invalid. Skip it. 1542fc1c62b8Sfrankho */ 1543cf83459aSfrankho if (dnamelen > hdlen - HDE_FDESIZE) { 15447c478bd9Sstevel@tonic-gate hs_log_bogus_disk_warning(fsp, 1545fc1c62b8Sfrankho HSFS_ERR_BAD_DIR_ENTRY, 0); 1546cf83459aSfrankho goto skip_rec; 1547fc1c62b8Sfrankho } else if (dnamelen > fsp->hsfs_namelen && 1548fc1c62b8Sfrankho hs_namelen(fsp, dname, dnamelen) > fsp->hsfs_namelen) { 1549cf83459aSfrankho hs_log_bogus_disk_warning(fsp, 1550fc1c62b8Sfrankho fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET ? 1551fc1c62b8Sfrankho HSFS_ERR_BAD_JOLIET_FILE_LEN : 1552d10b6702Sfrankho HSFS_ERR_BAD_FILE_LEN, 0); 15537c478bd9Sstevel@tonic-gate } 1554fc1c62b8Sfrankho if (dnamelen > ISO_NAMELEN_V2_MAX) 1555fc1c62b8Sfrankho dnamelen = fsp->hsfs_namemax; /* Paranoia */ 15567c478bd9Sstevel@tonic-gate 15577c478bd9Sstevel@tonic-gate /* 15587c478bd9Sstevel@tonic-gate * If the rock ridge is implemented, then we copy the name 15597c478bd9Sstevel@tonic-gate * from the SUA area to rrip_name_str. If no Alternate 15607c478bd9Sstevel@tonic-gate * name is found, then use the uppercase NM in the 15617c478bd9Sstevel@tonic-gate * rrip_name_str char array. 15627c478bd9Sstevel@tonic-gate */ 15637c478bd9Sstevel@tonic-gate if (is_rrip) { 15647c478bd9Sstevel@tonic-gate 15657c478bd9Sstevel@tonic-gate rrip_name_str[0] = '\0'; 15667c478bd9Sstevel@tonic-gate rr_namelen = rrip_namecopy(nm, &rrip_name_str[0], 1567d10b6702Sfrankho &rrip_tmp_name[0], dirp, last_offset - *offset, 1568d10b6702Sfrankho fsp, &hd); 15697c478bd9Sstevel@tonic-gate if (hd.sym_link) { 15707c478bd9Sstevel@tonic-gate kmem_free(hd.sym_link, 15717c478bd9Sstevel@tonic-gate (size_t)(hd.ext_size+1)); 15727c478bd9Sstevel@tonic-gate hd.sym_link = (char *)NULL; 15737c478bd9Sstevel@tonic-gate } 15747c478bd9Sstevel@tonic-gate 15757c478bd9Sstevel@tonic-gate if (rr_namelen != -1) { 15767c478bd9Sstevel@tonic-gate dname = (char *)&rrip_name_str[0]; 15777c478bd9Sstevel@tonic-gate dnamelen = rr_namelen; 15787c478bd9Sstevel@tonic-gate } 15797c478bd9Sstevel@tonic-gate } 15807c478bd9Sstevel@tonic-gate 15817c478bd9Sstevel@tonic-gate if (!is_rrip || rr_namelen == -1) { 15827c478bd9Sstevel@tonic-gate /* use iso name instead */ 15837c478bd9Sstevel@tonic-gate 1584fc1c62b8Sfrankho int i = -1; 15857c478bd9Sstevel@tonic-gate /* 15867c478bd9Sstevel@tonic-gate * make sure that we get rid of ';' in the dname of 15877c478bd9Sstevel@tonic-gate * an iso direntry, as we should have no knowledge 15887c478bd9Sstevel@tonic-gate * of file versions. 1589fc1c62b8Sfrankho * 1590fc1c62b8Sfrankho * XXX This is done the wrong way: it does not take 1591fc1c62b8Sfrankho * XXX care of the fact that the version string is 1592fc1c62b8Sfrankho * XXX a decimal number in the range 1 to 32767. 15937c478bd9Sstevel@tonic-gate */ 1594fc1c62b8Sfrankho if ((fsp->hsfs_flags & HSFSMNT_NOVERSION) == 0) { 1595fc1c62b8Sfrankho if (fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET) { 1596fc1c62b8Sfrankho for (i = dnamelen - 1; i > 0; i -= 2) { 1597fc1c62b8Sfrankho if (dname[i] == ';' && 1598fc1c62b8Sfrankho dname[i-1] == '\0') { 1599fc1c62b8Sfrankho --i; 1600fc1c62b8Sfrankho break; 1601fc1c62b8Sfrankho } 1602fc1c62b8Sfrankho } 1603fc1c62b8Sfrankho } else { 1604fc1c62b8Sfrankho for (i = dnamelen - 1; i > 0; i--) { 16057c478bd9Sstevel@tonic-gate if (dname[i] == ';') 1606fc1c62b8Sfrankho break; 1607fc1c62b8Sfrankho } 1608fc1c62b8Sfrankho } 1609fc1c62b8Sfrankho } 1610fc1c62b8Sfrankho if (i > 0) { 16117c478bd9Sstevel@tonic-gate dnamelen = i; 1612fc1c62b8Sfrankho } else if (fsp->hsfs_vol_type != HS_VOL_TYPE_ISO_V2 && 1613fc1c62b8Sfrankho fsp->hsfs_vol_type != HS_VOL_TYPE_JOLIET) { 16147c478bd9Sstevel@tonic-gate dnamelen = strip_trailing(fsp, dname, dnamelen); 1615fc1c62b8Sfrankho } 16167c478bd9Sstevel@tonic-gate 1617fc1c62b8Sfrankho ASSERT(dnamelen < sizeof (uppercase_name)); 1618cf83459aSfrankho 1619fc1c62b8Sfrankho if (fsp->hsfs_vol_type == HS_VOL_TYPE_ISO_V2) { 1620fc1c62b8Sfrankho (void) strncpy(uppercase_name, dname, dnamelen); 1621fc1c62b8Sfrankho } else if (fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET) { 1622fc1c62b8Sfrankho dnamelen = hs_joliet_cp(dname, uppercase_name, 1623fc1c62b8Sfrankho dnamelen); 1624fc1c62b8Sfrankho } else if (uppercase_cp(dname, uppercase_name, 1625fc1c62b8Sfrankho dnamelen)) { 16267c478bd9Sstevel@tonic-gate hs_log_bogus_disk_warning(fsp, 16277c478bd9Sstevel@tonic-gate HSFS_ERR_LOWER_CASE_NM, 0); 1628fc1c62b8Sfrankho } 16297c478bd9Sstevel@tonic-gate dname = uppercase_name; 16307c478bd9Sstevel@tonic-gate if (!is_rrip && 16317c478bd9Sstevel@tonic-gate (fsp->hsfs_flags & HSFSMNT_NOTRAILDOT) && 16327c478bd9Sstevel@tonic-gate dname[dnamelen - 1] == '.' && 16337c478bd9Sstevel@tonic-gate CAN_TRUNCATE_DOT(dname, dnamelen)) 16347c478bd9Sstevel@tonic-gate dname[--dnamelen] = '\0'; 16357c478bd9Sstevel@tonic-gate } 16367c478bd9Sstevel@tonic-gate 16377c478bd9Sstevel@tonic-gate /* 16387c478bd9Sstevel@tonic-gate * Quickly screen for a non-matching entry, but not for RRIP. 16397c478bd9Sstevel@tonic-gate * This test doesn't work for lowercase vs. uppercase names. 16407c478bd9Sstevel@tonic-gate */ 16417c478bd9Sstevel@tonic-gate 16427c478bd9Sstevel@tonic-gate /* if we saw a lower case name we can't do this test either */ 16437c478bd9Sstevel@tonic-gate if (strict_iso9660_ordering && !is_rrip && 16447c478bd9Sstevel@tonic-gate !HSFS_HAVE_LOWER_CASE(fsp) && *nm < *dname) { 16457c478bd9Sstevel@tonic-gate RESTORE_NM(rrip_tmp_name, nm); 16467c478bd9Sstevel@tonic-gate PD_return(WENT_PAST) 16477c478bd9Sstevel@tonic-gate } 16487c478bd9Sstevel@tonic-gate 1649cf83459aSfrankho if (*nm != *dname || nmlen != dnamelen) 1650cf83459aSfrankho goto skip_rec; 16517c478bd9Sstevel@tonic-gate 1652fc1c62b8Sfrankho if ((res = bcmp(dname, nm, nmlen)) == 0) { 16537c478bd9Sstevel@tonic-gate /* name matches */ 1654cf83459aSfrankho parsedir_res = hs_parsedir(fsp, dirp, &hd, 1655fc1c62b8Sfrankho (char *)NULL, (int *)NULL, 1656d10b6702Sfrankho last_offset - *offset); 16577c478bd9Sstevel@tonic-gate if (!parsedir_res) { 16587c478bd9Sstevel@tonic-gate uint_t lbn; /* logical block number */ 16597c478bd9Sstevel@tonic-gate 16607c478bd9Sstevel@tonic-gate lbn = dhp->hs_dirent.ext_lbn + 16617c478bd9Sstevel@tonic-gate dhp->hs_dirent.xar_len; 16627c478bd9Sstevel@tonic-gate /* 16637c478bd9Sstevel@tonic-gate * Need to do an fbrelse() on the buffer, 16647c478bd9Sstevel@tonic-gate * as hs_makenode() may try to acquire 16657c478bd9Sstevel@tonic-gate * hs_hashlock, which may not be required 16667c478bd9Sstevel@tonic-gate * while a page is locked. 16677c478bd9Sstevel@tonic-gate */ 16687c478bd9Sstevel@tonic-gate fbrelse(fbp, S_READ); 16697c478bd9Sstevel@tonic-gate did_fbrelse = 1; 1670cf83459aSfrankho *vpp = hs_makenode(&hd, lbn, *offset, 1671cf83459aSfrankho dvp->v_vfsp); 16727c478bd9Sstevel@tonic-gate if (*vpp == NULL) { 16737c478bd9Sstevel@tonic-gate *error = ENFILE; 16747c478bd9Sstevel@tonic-gate RESTORE_NM(rrip_tmp_name, nm); 16757c478bd9Sstevel@tonic-gate PD_return(FOUND_ENTRY) 16767c478bd9Sstevel@tonic-gate } 16777c478bd9Sstevel@tonic-gate 16787c478bd9Sstevel@tonic-gate dhp->hs_offset = *offset; 16797c478bd9Sstevel@tonic-gate RESTORE_NM(rrip_tmp_name, nm); 16807c478bd9Sstevel@tonic-gate PD_return(FOUND_ENTRY) 16817c478bd9Sstevel@tonic-gate } else if (parsedir_res != EAGAIN) { 16827c478bd9Sstevel@tonic-gate /* improper dir entry */ 16837c478bd9Sstevel@tonic-gate *error = parsedir_res; 16847c478bd9Sstevel@tonic-gate RESTORE_NM(rrip_tmp_name, nm); 16857c478bd9Sstevel@tonic-gate PD_return(FOUND_ENTRY) 16867c478bd9Sstevel@tonic-gate } 16877c478bd9Sstevel@tonic-gate } else if (strict_iso9660_ordering && !is_rrip && 16887c478bd9Sstevel@tonic-gate !HSFS_HAVE_LOWER_CASE(fsp) && res < 0) { 16897c478bd9Sstevel@tonic-gate /* name < dir entry */ 16907c478bd9Sstevel@tonic-gate RESTORE_NM(rrip_tmp_name, nm); 16917c478bd9Sstevel@tonic-gate PD_return(WENT_PAST) 16927c478bd9Sstevel@tonic-gate } 16937c478bd9Sstevel@tonic-gate /* 16947c478bd9Sstevel@tonic-gate * name > dir entry, 16957c478bd9Sstevel@tonic-gate * look at next one. 16967c478bd9Sstevel@tonic-gate */ 1697cf83459aSfrankho skip_rec: 16987c478bd9Sstevel@tonic-gate *offset += hdlen; 16997c478bd9Sstevel@tonic-gate RESTORE_NM(rrip_tmp_name, nm); 17007c478bd9Sstevel@tonic-gate } 17017c478bd9Sstevel@tonic-gate PD_return(HIT_END) 17027c478bd9Sstevel@tonic-gate 17037c478bd9Sstevel@tonic-gate do_ret: 17047c478bd9Sstevel@tonic-gate if (rrip_name_str) 17057c478bd9Sstevel@tonic-gate kmem_free(rrip_name_str, rrip_name_size); 17067c478bd9Sstevel@tonic-gate if (rrip_tmp_name) 17077c478bd9Sstevel@tonic-gate kmem_free(rrip_tmp_name, rrip_name_size); 17087c478bd9Sstevel@tonic-gate if (!did_fbrelse) 17097c478bd9Sstevel@tonic-gate fbrelse(fbp, S_READ); 17107c478bd9Sstevel@tonic-gate return (err); 17117c478bd9Sstevel@tonic-gate #undef PD_return 1712fc1c62b8Sfrankho #undef RESTORE_NM 17137c478bd9Sstevel@tonic-gate } 17147c478bd9Sstevel@tonic-gate 17157c478bd9Sstevel@tonic-gate /* 17167c478bd9Sstevel@tonic-gate * Strip trailing nulls or spaces from the name; 17177c478bd9Sstevel@tonic-gate * return adjusted length. If we find such junk, 17187c478bd9Sstevel@tonic-gate * log a non-conformant disk message. 17197c478bd9Sstevel@tonic-gate */ 17207c478bd9Sstevel@tonic-gate static int 17217c478bd9Sstevel@tonic-gate strip_trailing(struct hsfs *fsp, char *nm, int len) 17227c478bd9Sstevel@tonic-gate { 17237c478bd9Sstevel@tonic-gate char *c; 17247c478bd9Sstevel@tonic-gate int trailing_junk = 0; 17257c478bd9Sstevel@tonic-gate 17267c478bd9Sstevel@tonic-gate for (c = nm + len - 1; c > nm; c--) { 17277c478bd9Sstevel@tonic-gate if (*c == ' ' || *c == '\0') 17287c478bd9Sstevel@tonic-gate trailing_junk = 1; 17297c478bd9Sstevel@tonic-gate else 17307c478bd9Sstevel@tonic-gate break; 17317c478bd9Sstevel@tonic-gate } 17327c478bd9Sstevel@tonic-gate 17337c478bd9Sstevel@tonic-gate if (trailing_junk) 17347c478bd9Sstevel@tonic-gate hs_log_bogus_disk_warning(fsp, HSFS_ERR_TRAILING_JUNK, 0); 17357c478bd9Sstevel@tonic-gate 17367c478bd9Sstevel@tonic-gate return ((int)(c - nm + 1)); 17377c478bd9Sstevel@tonic-gate } 1738fc1c62b8Sfrankho 1739fc1c62b8Sfrankho static int 1740fc1c62b8Sfrankho hs_namelen(struct hsfs *fsp, char *nm, int len) 1741fc1c62b8Sfrankho { 1742fc1c62b8Sfrankho char *p = nm + len; 1743fc1c62b8Sfrankho 1744fc1c62b8Sfrankho if (fsp->hsfs_vol_type == HS_VOL_TYPE_ISO_V2) { 1745fc1c62b8Sfrankho return (len); 1746fc1c62b8Sfrankho } else if (fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET) { 1747fc1c62b8Sfrankho uint16_t c; 1748fc1c62b8Sfrankho 1749fc1c62b8Sfrankho while (--p > &nm[1]) { 1750fc1c62b8Sfrankho c = *p; 1751fc1c62b8Sfrankho c |= *--p * 256; 1752fc1c62b8Sfrankho if (c == ';') 1753fc1c62b8Sfrankho return (p - nm); 1754fc1c62b8Sfrankho if (c < '0' || c > '9') { 1755fc1c62b8Sfrankho p++; 1756fc1c62b8Sfrankho return (p - nm); 1757fc1c62b8Sfrankho } 1758fc1c62b8Sfrankho } 1759fc1c62b8Sfrankho } else { 1760fc1c62b8Sfrankho char c; 1761fc1c62b8Sfrankho 1762fc1c62b8Sfrankho while (--p > nm) { 1763fc1c62b8Sfrankho c = *p; 1764fc1c62b8Sfrankho if (c == ';') 1765fc1c62b8Sfrankho return (p - nm); 1766fc1c62b8Sfrankho if (c < '0' || c > '9') { 1767fc1c62b8Sfrankho p++; 1768fc1c62b8Sfrankho return (p - nm); 1769fc1c62b8Sfrankho } 1770fc1c62b8Sfrankho } 1771fc1c62b8Sfrankho } 1772fc1c62b8Sfrankho return (len); 1773fc1c62b8Sfrankho } 1774fc1c62b8Sfrankho 1775fc1c62b8Sfrankho /* 1776fc1c62b8Sfrankho * Take a UCS-2 character and convert 1777fc1c62b8Sfrankho * it into a utf8 character. 1778fc1c62b8Sfrankho * A 0 will be returned if the conversion fails 1779fc1c62b8Sfrankho * 1780fc1c62b8Sfrankho * See http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 1781fc1c62b8Sfrankho * 1782fc1c62b8Sfrankho * The code has been taken from udfs/udf_subr.c 1783fc1c62b8Sfrankho */ 1784fc1c62b8Sfrankho static uint8_t hs_first_byte_mark[7] = 1785fc1c62b8Sfrankho { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; 1786fc1c62b8Sfrankho static int32_t 1787fc1c62b8Sfrankho hs_ucs2_2_utf8(uint16_t c_16, uint8_t *s_8) 1788fc1c62b8Sfrankho { 1789fc1c62b8Sfrankho int32_t nc; 1790fc1c62b8Sfrankho uint32_t c_32; 1791fc1c62b8Sfrankho uint32_t byte_mask = 0xBF; 1792fc1c62b8Sfrankho uint32_t byte_mark = 0x80; 1793fc1c62b8Sfrankho 1794fc1c62b8Sfrankho /* 1795fc1c62b8Sfrankho * Convert the 16-bit character to a 32-bit character 1796fc1c62b8Sfrankho */ 1797fc1c62b8Sfrankho c_32 = c_16; 1798fc1c62b8Sfrankho 1799fc1c62b8Sfrankho /* 1800fc1c62b8Sfrankho * By here the 16-bit character is converted 1801fc1c62b8Sfrankho * to a 32-bit wide character 1802fc1c62b8Sfrankho */ 1803fc1c62b8Sfrankho if (c_32 < 0x80) { 1804fc1c62b8Sfrankho nc = 1; 1805fc1c62b8Sfrankho } else if (c_32 < 0x800) { 1806fc1c62b8Sfrankho nc = 2; 1807fc1c62b8Sfrankho } else if (c_32 < 0x10000) { 1808fc1c62b8Sfrankho nc = 3; 1809fc1c62b8Sfrankho } else if (c_32 < 0x200000) { 1810fc1c62b8Sfrankho nc = 4; 1811fc1c62b8Sfrankho } else if (c_32 < 0x4000000) { 1812fc1c62b8Sfrankho nc = 5; 1813fc1c62b8Sfrankho } else if (c_32 <= 0x7FFFFFFF) { /* avoid signed overflow */ 1814fc1c62b8Sfrankho nc = 6; 1815fc1c62b8Sfrankho } else { 1816fc1c62b8Sfrankho nc = 0; 1817fc1c62b8Sfrankho } 1818fc1c62b8Sfrankho s_8 += nc; 1819fc1c62b8Sfrankho switch (nc) { 1820fc1c62b8Sfrankho case 6 : 1821fc1c62b8Sfrankho *(--s_8) = (c_32 | byte_mark) & byte_mask; 1822fc1c62b8Sfrankho c_32 >>= 6; 1823fc1c62b8Sfrankho /* FALLTHROUGH */ 1824fc1c62b8Sfrankho case 5 : 1825fc1c62b8Sfrankho *(--s_8) = (c_32 | byte_mark) & byte_mask; 1826fc1c62b8Sfrankho c_32 >>= 6; 1827fc1c62b8Sfrankho /* FALLTHROUGH */ 1828fc1c62b8Sfrankho case 4 : 1829fc1c62b8Sfrankho *(--s_8) = (c_32 | byte_mark) & byte_mask; 1830fc1c62b8Sfrankho c_32 >>= 6; 1831fc1c62b8Sfrankho /* FALLTHROUGH */ 1832fc1c62b8Sfrankho case 3 : 1833fc1c62b8Sfrankho *(--s_8) = (c_32 | byte_mark) & byte_mask; 1834fc1c62b8Sfrankho c_32 >>= 6; 1835fc1c62b8Sfrankho /* FALLTHROUGH */ 1836fc1c62b8Sfrankho case 2 : 1837fc1c62b8Sfrankho *(--s_8) = (c_32 | byte_mark) & byte_mask; 1838fc1c62b8Sfrankho c_32 >>= 6; 1839fc1c62b8Sfrankho /* FALLTHROUGH */ 1840fc1c62b8Sfrankho case 1 : 1841fc1c62b8Sfrankho *(--s_8) = c_32 | hs_first_byte_mark[nc]; 1842fc1c62b8Sfrankho } 1843fc1c62b8Sfrankho return (nc); 1844fc1c62b8Sfrankho } 1845