drop net-snmp dep
[unleashed.git] / kernel / fs / hsfs / hsfs_node.c
blob4ed1f4f929deefd5c75fe61bfe9afc4e571ace42
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2016 PALO, Richard.
27 * Directory operations for High Sierra filesystem
30 #include <sys/types.h>
31 #include <sys/t_lock.h>
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/cred.h>
35 #include <sys/user.h>
36 #include <sys/vfs.h>
37 #include <sys/stat.h>
38 #include <sys/vnode.h>
39 #include <sys/mode.h>
40 #include <sys/dnlc.h>
41 #include <sys/cmn_err.h>
42 #include <sys/fbuf.h>
43 #include <sys/kmem.h>
44 #include <sys/policy.h>
45 #include <sys/sunddi.h>
46 #include <vm/hat.h>
47 #include <vm/as.h>
48 #include <vm/pvn.h>
49 #include <vm/seg.h>
50 #include <vm/seg_map.h>
51 #include <vm/seg_kmem.h>
52 #include <vm/page.h>
54 #include <sys/fs/hsfs_spec.h>
55 #include <sys/fs/hsfs_isospec.h>
56 #include <sys/fs/hsfs_node.h>
57 #include <sys/fs/hsfs_impl.h>
58 #include <sys/fs/hsfs_susp.h>
59 #include <sys/fs/hsfs_rrip.h>
61 #include <sys/sysinfo.h>
62 #include <sys/sysmacros.h>
63 #include <sys/errno.h>
64 #include <sys/debug.h>
65 #include <sys/fs_subr.h>
68 * This macro expects a name that ends in '.' and returns TRUE if the
69 * name is not "." or ".."
71 #define CAN_TRUNCATE_DOT(name, namelen) \
72 (namelen > 1 && (namelen > 2 || name[0] != '.'))
74 enum dirblock_result { FOUND_ENTRY, WENT_PAST, HIT_END };
77 * These values determine whether we will try to read a file or dir;
78 * they may be patched via /etc/system to allow users to read
79 * record-oriented files.
81 int ide_prohibited = IDE_PROHIBITED;
82 int hde_prohibited = HDE_PROHIBITED;
85 * This variable determines if the HSFS code will use the
86 * directory name lookup cache. The default is for the cache to be used.
88 static int hsfs_use_dnlc = 1;
91 * This variable determines whether strict ISO-9660 directory ordering
92 * is to be assumed. If false (which it is by default), then when
93 * searching a directory of an ISO-9660 disk, we do not expect the
94 * entries to be sorted (as the spec requires), and so cannot terminate
95 * the search early. Unfortunately, some vendors are producing
96 * non-compliant disks. This variable exists to revert to the old
97 * behavior in case someone relies on this. This option is expected to be
98 * removed at some point in the future.
100 * Use "set hsfs:strict_iso9660_ordering = 1" in /etc/system to override.
102 static int strict_iso9660_ordering = 0;
105 * This tunable allows us to ignore inode numbers from rrip-1.12.
106 * In this case, we fall back to our default inode algorithm.
108 int use_rrip_inodes = 1;
110 static void hs_hsnode_cache_reclaim(void *unused);
111 static void hs_addfreeb(struct hsfs *fsp, struct hsnode *hp);
112 static enum dirblock_result process_dirblock(struct fbuf *fbp, uint_t *offset,
113 uint_t last_offset, char *nm, int nmlen, struct hsfs *fsp,
114 struct hsnode *dhp, struct vnode *dvp, struct vnode **vpp,
115 int *error);
116 static int strip_trailing(struct hsfs *fsp, char *nm, int len);
117 static int hs_namelen(struct hsfs *fsp, char *nm, int len);
118 static int uppercase_cp(char *from, char *to, int size);
119 static void hs_log_bogus_joliet_warning(void);
120 static int hs_iso_copy(char *from, char *to, int size);
121 static int32_t hs_ucs2_2_utf8(uint16_t c_16, uint8_t *s_8);
122 static int hs_utf8_trunc(uint8_t *str, int len);
125 * hs_access
126 * Return 0 if the desired access may be granted.
127 * Otherwise return error code.
130 hs_access(struct vnode *vp, mode_t m, struct cred *cred)
132 struct hsnode *hp;
133 int shift = 0;
136 * Write access cannot be granted for a read-only medium
138 if ((m & VWRITE) && !IS_DEVVP(vp))
139 return (EROFS);
141 hp = VTOH(vp);
144 * XXX - For now, use volume protections.
145 * Also, always grant EXEC access for directories
146 * if READ access is granted.
148 if ((vp->v_type == VDIR) && (m & VEXEC)) {
149 m &= ~VEXEC;
150 m |= VREAD;
153 if (crgetuid(cred) != hp->hs_dirent.uid) {
154 shift += 3;
155 if (!groupmember((uid_t)hp->hs_dirent.gid, cred))
156 shift += 3;
158 return (secpolicy_vnode_access2(cred, vp, hp->hs_dirent.uid,
159 hp->hs_dirent.mode << shift, m));
162 #if ((HS_HASHSIZE & (HS_HASHSIZE - 1)) == 0)
163 #define HS_HASH(l) ((uint_t)(l) & (HS_HASHSIZE - 1))
164 #else
165 #define HS_HASH(l) ((uint_t)(l) % HS_HASHSIZE)
166 #endif
167 #define HS_HPASH(hp) HS_HASH((hp)->hs_nodeid)
170 * The tunable nhsnode is now a threshold for a dynamically allocated
171 * pool of hsnodes, not the size of a statically allocated table.
172 * When the number of hsnodes for a particular file system exceeds
173 * nhsnode, the allocate and free logic will try to reduce the number
174 * of allocated nodes by returning unreferenced nodes to the kmem_cache
175 * instead of putting them on the file system's private free list.
177 int nhsnode = HS_HSNODESPACE / sizeof (struct hsnode);
179 struct kmem_cache *hsnode_cache; /* free hsnode cache */
182 * Initialize the cache of free hsnodes.
184 void
185 hs_init_hsnode_cache(void)
188 * A kmem_cache is used for the hsnodes
189 * No constructor because hsnodes are initialised by bzeroing.
191 hsnode_cache = kmem_cache_create("hsfs_hsnode_cache",
192 sizeof (struct hsnode), 0, NULL,
193 NULL, hs_hsnode_cache_reclaim, NULL, NULL, 0);
197 * Destroy the cache of free hsnodes.
199 void
200 hs_fini_hsnode_cache(void)
202 kmem_cache_destroy(hsnode_cache);
206 * System is short on memory, free up as much as possible
208 /*ARGSUSED*/
209 static void
210 hs_hsnode_cache_reclaim(void *unused)
212 struct hsfs *fsp;
213 struct hsnode *hp;
216 * For each vfs in the hs_mounttab list
218 mutex_enter(&hs_mounttab_lock);
219 for (fsp = hs_mounttab; fsp != NULL; fsp = fsp->hsfs_next) {
221 * Purge the dnlc of all hsfs entries
223 (void) dnlc_purge_vfsp(fsp->hsfs_vfs, 0);
226 * For each entry in the free chain
228 rw_enter(&fsp->hsfs_hash_lock, RW_WRITER);
229 mutex_enter(&fsp->hsfs_free_lock);
230 for (hp = fsp->hsfs_free_f; hp != NULL; hp = fsp->hsfs_free_f) {
232 * Remove from chain
234 fsp->hsfs_free_f = hp->hs_freef;
235 if (fsp->hsfs_free_f != NULL) {
236 fsp->hsfs_free_f->hs_freeb = NULL;
237 } else {
238 fsp->hsfs_free_b = NULL;
241 * Free the node. Force it to be fully freed
242 * by setting the 3rd arg (nopage) to 1.
244 hs_freenode(HTOV(hp), fsp, 1);
246 mutex_exit(&fsp->hsfs_free_lock);
247 rw_exit(&fsp->hsfs_hash_lock);
249 mutex_exit(&hs_mounttab_lock);
253 * Add an hsnode to the end of the free list.
255 static void
256 hs_addfreeb(struct hsfs *fsp, struct hsnode *hp)
258 struct hsnode *ep;
260 vn_invalid(HTOV(hp));
261 mutex_enter(&fsp->hsfs_free_lock);
262 ep = fsp->hsfs_free_b;
263 fsp->hsfs_free_b = hp; /* hp is the last entry in free list */
264 hp->hs_freef = NULL;
265 hp->hs_freeb = ep; /* point at previous last entry */
266 if (ep == NULL)
267 fsp->hsfs_free_f = hp; /* hp is only entry in free list */
268 else
269 ep->hs_freef = hp; /* point previous last entry at hp */
271 mutex_exit(&fsp->hsfs_free_lock);
275 * Get an hsnode from the front of the free list.
276 * Must be called with write hsfs_hash_lock held.
278 static struct hsnode *
279 hs_getfree(struct hsfs *fsp)
281 struct hsnode *hp, **tp;
283 ASSERT(RW_WRITE_HELD(&fsp->hsfs_hash_lock));
286 * If the number of currently-allocated hsnodes is less than
287 * the hsnode count threshold (nhsnode), or if there are no
288 * nodes on the file system's local free list (which acts as a
289 * cache), call kmem_cache_alloc to get a new hsnode from
290 * kernel memory.
292 mutex_enter(&fsp->hsfs_free_lock);
293 if ((fsp->hsfs_nohsnode < nhsnode) || (fsp->hsfs_free_f == NULL)) {
294 mutex_exit(&fsp->hsfs_free_lock);
295 hp = kmem_cache_alloc(hsnode_cache, KM_SLEEP);
296 fsp->hsfs_nohsnode++;
297 bzero((caddr_t)hp, sizeof (*hp));
298 hp->hs_vnode = vn_alloc(KM_SLEEP);
299 return (hp);
301 hp = fsp->hsfs_free_f;
302 /* hp cannot be NULL, since we already checked this above */
303 fsp->hsfs_free_f = hp->hs_freef;
304 if (fsp->hsfs_free_f != NULL)
305 fsp->hsfs_free_f->hs_freeb = NULL;
306 else
307 fsp->hsfs_free_b = NULL;
308 mutex_exit(&fsp->hsfs_free_lock);
310 for (tp = &fsp->hsfs_hash[HS_HPASH(hp)]; *tp != NULL;
311 tp = &(*tp)->hs_hash) {
312 if (*tp == hp) {
313 struct vnode *vp;
315 vp = HTOV(hp);
318 * file is no longer referenced, destroy all old pages
320 if (vn_has_cached_data(vp))
322 * pvn_vplist_dirty will abort all old pages
324 (void) pvn_vplist_dirty(vp, 0,
325 hsfs_putapage, B_INVAL, NULL);
326 *tp = hp->hs_hash;
327 break;
330 if (hp->hs_dirent.sym_link != NULL) {
331 kmem_free(hp->hs_dirent.sym_link,
332 (size_t)(hp->hs_dirent.ext_size + 1));
335 mutex_destroy(&hp->hs_contents_lock);
337 vnode_t *vp;
339 vp = hp->hs_vnode;
340 bzero((caddr_t)hp, sizeof (*hp));
341 hp->hs_vnode = vp;
342 vn_reinit(vp);
344 return (hp);
348 * Remove an hsnode from the free list.
350 static void
351 hs_remfree(struct hsfs *fsp, struct hsnode *hp)
353 mutex_enter(&fsp->hsfs_free_lock);
354 if (hp->hs_freef != NULL)
355 hp->hs_freef->hs_freeb = hp->hs_freeb;
356 else
357 fsp->hsfs_free_b = hp->hs_freeb;
358 if (hp->hs_freeb != NULL)
359 hp->hs_freeb->hs_freef = hp->hs_freef;
360 else
361 fsp->hsfs_free_f = hp->hs_freef;
362 mutex_exit(&fsp->hsfs_free_lock);
366 * Look for hsnode in hash list.
367 * If the inode number is != HS_DUMMY_INO (16), then only the inode
368 * number is used for the check.
369 * If the inode number is == HS_DUMMY_INO, we additionally always
370 * check the directory offset for the file to avoid caching the
371 * meta data for all zero sized to the first zero sized file that
372 * was touched.
374 * If found, reactivate it if inactive.
376 * Must be entered with hsfs_hash_lock held.
378 struct vnode *
379 hs_findhash(ino64_t nodeid, uint_t lbn, uint_t off, struct vfs *vfsp)
381 struct hsnode *tp;
382 struct hsfs *fsp;
384 fsp = VFS_TO_HSFS(vfsp);
386 ASSERT(RW_LOCK_HELD(&fsp->hsfs_hash_lock));
388 for (tp = fsp->hsfs_hash[HS_HASH(nodeid)]; tp != NULL;
389 tp = tp->hs_hash) {
390 if (tp->hs_nodeid == nodeid) {
391 struct vnode *vp;
393 if (nodeid == HS_DUMMY_INO) {
395 * If this is the dummy inode number, look for
396 * matching dir_lbn and dir_off.
398 for (; tp != NULL; tp = tp->hs_hash) {
399 if (tp->hs_nodeid == nodeid &&
400 tp->hs_dir_lbn == lbn &&
401 tp->hs_dir_off == off)
402 break;
404 if (tp == NULL)
405 return (NULL);
408 mutex_enter(&tp->hs_contents_lock);
409 vp = HTOV(tp);
410 VN_HOLD(vp);
411 if ((tp->hs_flags & HREF) == 0) {
412 tp->hs_flags |= HREF;
414 * reactivating a free hsnode:
415 * remove from free list
417 hs_remfree(fsp, tp);
419 mutex_exit(&tp->hs_contents_lock);
420 return (vp);
423 return (NULL);
426 static void
427 hs_addhash(struct hsfs *fsp, struct hsnode *hp)
429 ulong_t hashno;
431 ASSERT(RW_WRITE_HELD(&fsp->hsfs_hash_lock));
433 hashno = HS_HPASH(hp);
434 hp->hs_hash = fsp->hsfs_hash[hashno];
435 fsp->hsfs_hash[hashno] = hp;
439 * Destroy all old pages and free the hsnodes
440 * Return 1 if busy (a hsnode is still referenced).
443 hs_synchash(struct vfs *vfsp)
445 struct hsfs *fsp;
446 int i;
447 struct hsnode *hp, *nhp;
448 int busy = 0;
449 struct vnode *vp, *rvp;
451 fsp = VFS_TO_HSFS(vfsp);
452 rvp = fsp->hsfs_rootvp;
453 /* make sure no one can come in */
454 rw_enter(&fsp->hsfs_hash_lock, RW_WRITER);
455 for (i = 0; i < HS_HASHSIZE; i++) {
456 for (hp = fsp->hsfs_hash[i]; hp != NULL; hp = hp->hs_hash) {
457 vp = HTOV(hp);
458 if ((hp->hs_flags & HREF) && (vp != rvp ||
459 (vp == rvp && vp->v_count > 1))) {
460 busy = 1;
461 continue;
463 if (vn_has_cached_data(vp))
464 (void) pvn_vplist_dirty(vp, 0,
465 hsfs_putapage, B_INVAL, NULL);
468 if (busy) {
469 rw_exit(&fsp->hsfs_hash_lock);
470 return (1);
473 /* now free the hsnodes */
474 for (i = 0; i < HS_HASHSIZE; i++) {
475 for (hp = fsp->hsfs_hash[i]; hp != NULL; hp = nhp) {
476 nhp = hp->hs_hash;
478 * We know there are no pages associated with
479 * all the hsnodes (they've all been released
480 * above). So remove from free list and
481 * free the entry with nopage set.
483 vp = HTOV(hp);
484 if (vp != rvp) {
485 hs_remfree(fsp, hp);
486 hs_freenode(vp, fsp, 1);
491 ASSERT(fsp->hsfs_nohsnode == 1);
492 rw_exit(&fsp->hsfs_hash_lock);
493 /* release the root hsnode, this should free the final hsnode */
494 VN_RELE(rvp);
496 return (0);
500 * hs_makenode
502 * Construct an hsnode.
503 * Caller specifies the directory entry, the block number and offset
504 * of the directory entry, and the vfs pointer.
505 * note: off is the sector offset, not lbn offset
506 * if NULL is returned implies file system hsnode table full
508 struct vnode *
509 hs_makenode(
510 struct hs_direntry *dp,
511 uint_t lbn,
512 uint_t off,
513 struct vfs *vfsp)
515 struct hsnode *hp;
516 struct vnode *vp;
517 struct hs_volume *hvp;
518 struct vnode *newvp;
519 struct hsfs *fsp;
520 ino64_t nodeid;
522 fsp = VFS_TO_HSFS(vfsp);
525 * Construct the data that allows us to re-read the meta data without
526 * knowing the name of the file: in the case of a directory
527 * entry, this should point to the canonical dirent, the "."
528 * directory entry for the directory. This dirent is pointed
529 * to by all directory entries for that dir (including the ".")
530 * entry itself.
531 * In the case of a file, simply point to the dirent for that
532 * file (there are hard links in Rock Ridge, so we need to use
533 * different data to contruct the node id).
535 if (dp->type == VDIR) {
536 lbn = dp->ext_lbn;
537 off = 0;
541 * Normalize lbn and off before creating a nodeid
542 * and before storing them in a hs_node structure
544 hvp = &fsp->hsfs_vol;
545 lbn += off >> hvp->lbn_shift;
546 off &= hvp->lbn_maxoffset;
548 * If the media carries rrip-v1.12 or newer, and we trust the inodes
549 * from the rrip data (use_rrip_inodes != 0), use that data. If the
550 * media has been created by a recent mkisofs version, we may trust
551 * all numbers in the starting extent number; otherwise, we cannot
552 * do this for zero sized files and symlinks, because if we did we'd
553 * end up mapping all of them to the same node.
554 * We use HS_DUMMY_INO in this case and make sure that we will not
555 * map all files to the same meta data.
557 if (dp->inode != 0 && use_rrip_inodes) {
558 nodeid = dp->inode;
559 } else if ((dp->ext_size == 0 || dp->sym_link != NULL) &&
560 (fsp->hsfs_flags & HSFSMNT_INODE) == 0) {
561 nodeid = HS_DUMMY_INO;
562 } else {
563 nodeid = dp->ext_lbn;
566 /* look for hsnode in cache first */
568 rw_enter(&fsp->hsfs_hash_lock, RW_READER);
570 if ((vp = hs_findhash(nodeid, lbn, off, vfsp)) == NULL) {
573 * Not in cache. However, someone else may have come
574 * to the same conclusion and just put one in. Upgrade
575 * our lock to a write lock and look again.
577 rw_exit(&fsp->hsfs_hash_lock);
578 rw_enter(&fsp->hsfs_hash_lock, RW_WRITER);
580 if ((vp = hs_findhash(nodeid, lbn, off, vfsp)) == NULL) {
582 * Now we are really sure that the hsnode is not
583 * in the cache. Get one off freelist or else
584 * allocate one. Either way get a bzeroed hsnode.
586 hp = hs_getfree(fsp);
588 bcopy((caddr_t)dp, (caddr_t)&hp->hs_dirent,
589 sizeof (*dp));
591 * We've just copied this pointer into hs_dirent,
592 * and don't want 2 references to same symlink.
594 dp->sym_link = NULL;
597 * No need to hold any lock because hsnode is not
598 * yet in the hash chain.
600 mutex_init(&hp->hs_contents_lock, NULL, MUTEX_DEFAULT,
601 NULL);
602 hp->hs_dir_lbn = lbn;
603 hp->hs_dir_off = off;
604 hp->hs_nodeid = nodeid;
605 hp->hs_seq = 0;
606 hp->hs_prev_offset = 0;
607 hp->hs_num_contig = 0;
608 hp->hs_ra_bytes = 0;
609 hp->hs_flags = HREF;
610 if (off > HS_SECTOR_SIZE)
611 cmn_err(CE_WARN, "hs_makenode: bad offset");
613 vp = HTOV(hp);
614 vp->v_vfsp = vfsp;
615 vp->v_type = dp->type;
616 vp->v_rdev = dp->r_dev;
617 vn_setops(vp, &hsfs_vnodeops);
618 vp->v_data = (caddr_t)hp;
619 vn_exists(vp);
621 * if it's a device, call specvp
623 if (IS_DEVVP(vp)) {
624 rw_exit(&fsp->hsfs_hash_lock);
625 newvp = specvp(vp, vp->v_rdev, vp->v_type,
626 CRED());
627 if (newvp == NULL)
628 cmn_err(CE_NOTE,
629 "hs_makenode: specvp failed");
630 VN_RELE(vp);
631 return (newvp);
634 hs_addhash(fsp, hp);
639 if (dp->sym_link != NULL) {
640 kmem_free(dp->sym_link, (size_t)(dp->ext_size + 1));
641 dp->sym_link = NULL;
644 rw_exit(&fsp->hsfs_hash_lock);
645 return (vp);
649 * hs_freenode
651 * Deactivate an hsnode.
652 * Leave it on the hash list but put it on the free list.
653 * If the vnode does not have any pages, release the hsnode to the
654 * kmem_cache using kmem_cache_free, else put in back of the free list.
656 * This function can be called with the hsfs_free_lock held, but only
657 * when the code is guaranteed to go through the path where the
658 * node is freed entirely, and not the path where the node could go back
659 * on the free list (and where the free lock would need to be acquired).
661 void
662 hs_freenode(vnode_t *vp, struct hsfs *fsp, int nopage)
664 struct hsnode **tp;
665 struct hsnode *hp = VTOH(vp);
667 ASSERT(RW_LOCK_HELD(&fsp->hsfs_hash_lock));
669 if (nopage || (fsp->hsfs_nohsnode >= nhsnode)) {
670 /* remove this node from the hash list, if it's there */
671 for (tp = &fsp->hsfs_hash[HS_HPASH(hp)]; *tp != NULL;
672 tp = &(*tp)->hs_hash) {
674 if (*tp == hp) {
675 *tp = hp->hs_hash;
676 break;
680 if (hp->hs_dirent.sym_link != NULL) {
681 kmem_free(hp->hs_dirent.sym_link,
682 (size_t)(hp->hs_dirent.ext_size + 1));
683 hp->hs_dirent.sym_link = NULL;
685 if (vn_has_cached_data(vp)) {
686 /* clean all old pages */
687 (void) pvn_vplist_dirty(vp, 0,
688 hsfs_putapage, B_INVAL, NULL);
690 * XXX - can we remove pages by fiat like this???
691 * This really doesn't seem safe.
693 vp->v_object.list.list_head.list_next =
694 vp->v_object.list.list_head.list_prev =
695 &vp->v_object.list.list_head;
696 cmn_err(CE_WARN, "%s: dropped vnode cached pages in a "
697 "questionable way", __func__);
699 mutex_destroy(&hp->hs_contents_lock);
700 vn_invalid(vp);
701 vn_free(vp);
702 kmem_cache_free(hsnode_cache, hp);
703 fsp->hsfs_nohsnode--;
704 return;
706 hs_addfreeb(fsp, hp); /* add to back of free list */
710 * hs_remakenode
712 * Reconstruct a vnode given the location of its directory entry.
713 * Caller specifies the the block number and offset
714 * of the directory entry, and the vfs pointer.
715 * Returns an error code or 0.
718 hs_remakenode(uint_t lbn, uint_t off, struct vfs *vfsp,
719 struct vnode **vpp)
721 struct buf *secbp;
722 struct hsfs *fsp;
723 uint_t secno;
724 uchar_t *dirp;
725 struct hs_direntry hd;
726 int error;
728 /* Convert to sector and offset */
729 fsp = VFS_TO_HSFS(vfsp);
730 if (off > HS_SECTOR_SIZE) {
731 cmn_err(CE_WARN, "hs_remakenode: bad offset");
732 error = EINVAL;
733 goto end;
735 secno = LBN_TO_SEC(lbn, vfsp);
736 secbp = bread(fsp->hsfs_devvp->v_rdev, secno * 4, HS_SECTOR_SIZE);
738 error = geterror(secbp);
739 if (error != 0) {
740 cmn_err(CE_NOTE, "hs_remakenode: bread: error=(%d)", error);
741 goto end;
744 dirp = (uchar_t *)secbp->b_un.b_addr;
745 error = hs_parsedir(fsp, &dirp[off], &hd, NULL, NULL,
746 HS_SECTOR_SIZE - off);
747 if (!error) {
748 *vpp = hs_makenode(&hd, lbn, off, vfsp);
749 if (*vpp == NULL)
750 error = ENFILE;
753 end:
754 brelse(secbp);
755 return (error);
760 * hs_dirlook
762 * Look for a given name in a given directory.
763 * If found, construct an hsnode for it.
766 hs_dirlook(
767 struct vnode *dvp,
768 char *name,
769 int namlen, /* length of 'name' */
770 struct vnode **vpp,
771 struct cred *cred)
773 struct hsnode *dhp;
774 struct hsfs *fsp;
775 int error = 0;
776 uint_t offset; /* real offset in directory */
777 uint_t last_offset; /* last index in directory */
778 char *cmpname; /* case-folded name */
779 int cmpname_size; /* how much memory we allocate for it */
780 int cmpnamelen;
781 int adhoc_search; /* did we start at begin of dir? */
782 int end;
783 uint_t hsoffset;
784 struct fbuf *fbp;
785 int bytes_wanted;
786 int dirsiz;
787 int is_rrip;
789 if (dvp->v_type != VDIR)
790 return (ENOTDIR);
792 if (error = hs_access(dvp, (mode_t)VEXEC, cred))
793 return (error);
795 if (hsfs_use_dnlc && (*vpp = dnlc_lookup(dvp, name)))
796 return (0);
798 dhp = VTOH(dvp);
799 fsp = VFS_TO_HSFS(dvp->v_vfsp);
800 is_rrip = IS_RRIP_IMPLEMENTED(fsp);
803 * name == "^A" is illegal for ISO-9660 and Joliet as '..' is '\1' on
804 * disk. It is no problem for Rock Ridge as RR uses '.' and '..'.
805 * XXX It could be OK for Joliet also (because namelen == 1 is
806 * XXX impossible for UCS-2) but then we need a better compare algorith.
808 if (!is_rrip && *name == '\1' && namlen == 1)
809 return (EINVAL);
811 cmpname_size = (int)(fsp->hsfs_namemax + 1);
812 cmpname = kmem_alloc((size_t)cmpname_size, KM_SLEEP);
814 if (namlen >= cmpname_size)
815 namlen = cmpname_size - 1;
817 * For the purposes of comparing the name against dir entries,
818 * fold it to upper case.
820 if (is_rrip) {
821 (void) strlcpy(cmpname, name, cmpname_size);
822 cmpnamelen = namlen;
823 } else {
825 * If we don't consider a trailing dot as part of the filename,
826 * remove it from the specified name
828 if ((fsp->hsfs_flags & HSFSMNT_NOTRAILDOT) &&
829 name[namlen-1] == '.' &&
830 CAN_TRUNCATE_DOT(name, namlen))
831 name[--namlen] = '\0';
832 if (fsp->hsfs_vol_type == HS_VOL_TYPE_ISO_V2 ||
833 fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET) {
834 cmpnamelen = hs_iso_copy(name, cmpname, namlen);
835 } else {
836 cmpnamelen = hs_uppercase_copy(name, cmpname, namlen);
840 /* make sure dirent is filled up with all info */
841 if (dhp->hs_dirent.ext_size == 0)
842 hs_filldirent(dvp, &dhp->hs_dirent);
845 * No lock is needed - hs_offset is used as starting
846 * point for searching the directory.
848 offset = dhp->hs_offset;
849 hsoffset = offset;
850 adhoc_search = (offset != 0);
852 end = dhp->hs_dirent.ext_size;
853 dirsiz = end;
855 tryagain:
857 while (offset < end) {
858 bytes_wanted = MIN(MAXBSIZE, dirsiz - (offset & MAXBMASK));
860 error = fbread(dvp, (offset_t)(offset & MAXBMASK),
861 (unsigned int)bytes_wanted, S_READ, &fbp);
862 if (error)
863 goto done;
865 last_offset = (offset & MAXBMASK) + fbp->fb_count;
867 switch (process_dirblock(fbp, &offset, last_offset,
868 cmpname, cmpnamelen, fsp, dhp, dvp, vpp, &error)) {
869 case FOUND_ENTRY:
870 /* found an entry, either correct or not */
871 goto done;
873 case WENT_PAST:
875 * If we get here we know we didn't find it on the
876 * first pass. If adhoc_search, then we started a
877 * bit into the dir, and need to wrap around and
878 * search the first entries. If not, then we started
879 * at the beginning and didn't find it.
881 if (adhoc_search) {
882 offset = 0;
883 end = hsoffset;
884 adhoc_search = 0;
885 goto tryagain;
887 error = ENOENT;
888 goto done;
890 case HIT_END:
891 goto tryagain;
895 * End of all dir blocks, didn't find entry.
897 if (adhoc_search) {
898 offset = 0;
899 end = hsoffset;
900 adhoc_search = 0;
901 goto tryagain;
903 error = ENOENT;
904 done:
906 * If we found the entry, add it to the DNLC
907 * If the entry is a device file (assuming we support Rock Ridge),
908 * we enter the device vnode to the cache since that is what
909 * is in *vpp.
910 * That is ok since the CD-ROM is read-only, so (dvp,name) will
911 * always point to the same device.
913 if (hsfs_use_dnlc && !error)
914 dnlc_enter(dvp, name, *vpp);
916 kmem_free(cmpname, (size_t)cmpname_size);
918 return (error);
922 * hs_parsedir
924 * Parse a Directory Record into an hs_direntry structure.
925 * High Sierra and ISO directory are almost the same
926 * except the flag and date
929 hs_parsedir(
930 struct hsfs *fsp,
931 uchar_t *dirp,
932 struct hs_direntry *hdp,
933 char *dnp,
934 int *dnlen,
935 int last_offset) /* last offset in dirp */
937 char *on_disk_name;
938 int on_disk_namelen;
939 int on_disk_dirlen;
940 uchar_t flags;
941 int namelen;
942 int error;
943 int name_change_flag = 0; /* set if name was gotten in SUA */
945 hdp->ext_lbn = HDE_EXT_LBN(dirp);
946 hdp->ext_size = HDE_EXT_SIZE(dirp);
947 hdp->xar_len = HDE_XAR_LEN(dirp);
948 hdp->intlf_sz = HDE_INTRLV_SIZE(dirp);
949 hdp->intlf_sk = HDE_INTRLV_SKIP(dirp);
950 hdp->sym_link = NULL;
952 if (fsp->hsfs_vol_type == HS_VOL_TYPE_HS) {
953 flags = HDE_FLAGS(dirp);
954 hs_parse_dirdate(HDE_cdate(dirp), &hdp->cdate);
955 hs_parse_dirdate(HDE_cdate(dirp), &hdp->adate);
956 hs_parse_dirdate(HDE_cdate(dirp), &hdp->mdate);
957 if ((flags & hde_prohibited) == 0) {
959 * Skip files with the associated bit set.
961 if (flags & HDE_ASSOCIATED)
962 return (EAGAIN);
963 hdp->type = VREG;
964 hdp->mode = HFREG;
965 hdp->nlink = 1;
966 } else if ((flags & hde_prohibited) == HDE_DIRECTORY) {
967 hdp->type = VDIR;
968 hdp->mode = HFDIR;
969 hdp->nlink = 2;
970 } else {
971 hs_log_bogus_disk_warning(fsp,
972 HSFS_ERR_UNSUP_TYPE, flags);
973 return (EINVAL);
975 hdp->uid = fsp -> hsfs_vol.vol_uid;
976 hdp->gid = fsp -> hsfs_vol.vol_gid;
977 hdp->mode = hdp-> mode | (fsp -> hsfs_vol.vol_prot & 0777);
978 } else if ((fsp->hsfs_vol_type == HS_VOL_TYPE_ISO) ||
979 (fsp->hsfs_vol_type == HS_VOL_TYPE_ISO_V2) ||
980 (fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET)) {
982 flags = IDE_FLAGS(dirp);
983 hs_parse_dirdate(IDE_cdate(dirp), &hdp->cdate);
984 hs_parse_dirdate(IDE_cdate(dirp), &hdp->adate);
985 hs_parse_dirdate(IDE_cdate(dirp), &hdp->mdate);
987 if ((flags & ide_prohibited) == 0) {
989 * Skip files with the associated bit set.
991 if (flags & IDE_ASSOCIATED)
992 return (EAGAIN);
993 hdp->type = VREG;
994 hdp->mode = HFREG;
995 hdp->nlink = 1;
996 } else if ((flags & ide_prohibited) == IDE_DIRECTORY) {
997 hdp->type = VDIR;
998 hdp->mode = HFDIR;
999 hdp->nlink = 2;
1000 } else {
1001 hs_log_bogus_disk_warning(fsp,
1002 HSFS_ERR_UNSUP_TYPE, flags);
1003 return (EINVAL);
1005 hdp->uid = fsp -> hsfs_vol.vol_uid;
1006 hdp->gid = fsp -> hsfs_vol.vol_gid;
1007 hdp->mode = hdp-> mode | (fsp -> hsfs_vol.vol_prot & 0777);
1008 hdp->inode = 0; /* initialize with 0, then check rrip */
1011 * Having this all filled in, let's see if we have any
1012 * SUA susp to look at.
1014 if (IS_SUSP_IMPLEMENTED(fsp)) {
1015 error = parse_sua((uchar_t *)dnp, dnlen,
1016 &name_change_flag, dirp, last_offset,
1017 hdp, fsp, NULL, 0);
1018 if (error) {
1019 if (hdp->sym_link) {
1020 kmem_free(hdp->sym_link,
1021 (size_t)(hdp->ext_size + 1));
1022 hdp->sym_link = NULL;
1024 return (error);
1028 hdp->xar_prot = (HDE_PROTECTION & flags) != 0;
1030 #if dontskip
1031 if (hdp->xar_len > 0) {
1032 cmn_err(CE_NOTE, "hsfs: extended attributes not supported");
1033 return (EINVAL);
1035 #endif
1037 /* check interleaf size and skip factor */
1038 /* must both be zero or non-zero */
1039 if (hdp->intlf_sz + hdp->intlf_sk) {
1040 if ((hdp->intlf_sz == 0) || (hdp->intlf_sk == 0)) {
1041 cmn_err(CE_NOTE,
1042 "hsfs: interleaf size or skip factor error");
1043 return (EINVAL);
1045 if (hdp->ext_size == 0) {
1046 cmn_err(CE_NOTE,
1047 "hsfs: interleaving specified on zero length file");
1048 return (EINVAL);
1052 if (HDE_VOL_SET(dirp) != 1) {
1053 if (fsp->hsfs_vol.vol_set_size != 1 &&
1054 fsp->hsfs_vol.vol_set_size != HDE_VOL_SET(dirp)) {
1055 cmn_err(CE_NOTE, "hsfs: multivolume file?");
1056 return (EINVAL);
1061 * If the name changed, then the NM field for RRIP was hit and
1062 * we should not copy the name again, just return.
1064 if (NAME_HAS_CHANGED(name_change_flag))
1065 return (0);
1068 * Fall back to the ISO name. Note that as in process_dirblock,
1069 * the on-disk filename length must be validated against ISO
1070 * limits - which, in case of RR present but no RR name found,
1071 * are NOT identical to fsp->hsfs_namemax on this filesystem.
1073 on_disk_name = (char *)HDE_name(dirp);
1074 on_disk_namelen = (int)HDE_NAME_LEN(dirp);
1075 on_disk_dirlen = (int)HDE_DIR_LEN(dirp);
1077 if (on_disk_dirlen < HDE_ROOT_DIR_REC_SIZE ||
1078 ((on_disk_dirlen > last_offset) ||
1079 ((HDE_FDESIZE + on_disk_namelen) > on_disk_dirlen))) {
1080 hs_log_bogus_disk_warning(fsp,
1081 HSFS_ERR_BAD_DIR_ENTRY, 0);
1082 return (EINVAL);
1085 if (on_disk_namelen > fsp->hsfs_namelen &&
1086 hs_namelen(fsp, on_disk_name, on_disk_namelen) >
1087 fsp->hsfs_namelen) {
1088 hs_log_bogus_disk_warning(fsp,
1089 fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET ?
1090 HSFS_ERR_BAD_JOLIET_FILE_LEN :
1091 HSFS_ERR_BAD_FILE_LEN, 0);
1093 if (on_disk_namelen > ISO_NAMELEN_V2_MAX)
1094 on_disk_namelen = fsp->hsfs_namemax; /* Paranoia */
1096 if (dnp != NULL) {
1097 if (fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET) {
1098 namelen = hs_jnamecopy(on_disk_name, dnp,
1099 on_disk_namelen, fsp->hsfs_namemax,
1100 fsp->hsfs_flags);
1102 * A negative return value means that the file name
1103 * has been truncated to fsp->hsfs_namemax.
1105 if (namelen < 0) {
1106 namelen = -namelen;
1107 hs_log_bogus_disk_warning(fsp,
1108 HSFS_ERR_TRUNC_JOLIET_FILE_LEN, 0);
1110 } else {
1112 * HS_VOL_TYPE_ISO && HS_VOL_TYPE_ISO_V2
1114 namelen = hs_namecopy(on_disk_name, dnp,
1115 on_disk_namelen, fsp->hsfs_flags);
1117 if (namelen == 0)
1118 return (EINVAL);
1119 if ((fsp->hsfs_flags & HSFSMNT_NOTRAILDOT) &&
1120 dnp[ namelen-1 ] == '.' && CAN_TRUNCATE_DOT(dnp, namelen))
1121 dnp[ --namelen ] = '\0';
1122 } else
1123 namelen = on_disk_namelen;
1124 if (dnlen != NULL)
1125 *dnlen = namelen;
1127 return (0);
1131 * hs_namecopy
1133 * Parse a file/directory name into UNIX form.
1134 * Delete trailing blanks, upper-to-lower case, add NULL terminator.
1135 * Returns the (possibly new) length.
1137 * Called from hsfs_readdir() via hs_parsedir()
1140 hs_namecopy(char *from, char *to, int size, ulong_t flags)
1142 uint_t i;
1143 uchar_t c;
1144 int lastspace;
1145 int maplc;
1146 int trailspace;
1147 int version;
1149 /* special handling for '.' and '..' */
1150 if (size == 1) {
1151 if (*from == '\0') {
1152 *to++ = '.';
1153 *to = '\0';
1154 return (1);
1155 } else if (*from == '\1') {
1156 *to++ = '.';
1157 *to++ = '.';
1158 *to = '\0';
1159 return (2);
1163 maplc = (flags & HSFSMNT_NOMAPLCASE) == 0;
1164 trailspace = (flags & HSFSMNT_NOTRAILSPACE) == 0;
1165 version = (flags & HSFSMNT_NOVERSION) == 0;
1166 for (i = 0, lastspace = -1; i < size; i++) {
1167 c = from[i];
1168 if (c == ';' && version)
1169 break;
1170 if (c <= ' ' && !trailspace) {
1171 if (lastspace == -1)
1172 lastspace = i;
1173 } else
1174 lastspace = -1;
1175 if (maplc && (c >= 'A') && (c <= 'Z'))
1176 c += 'a' - 'A';
1177 to[i] = c;
1179 if (lastspace != -1)
1180 i = lastspace;
1181 to[i] = '\0';
1182 return (i);
1186 * hs_jnamecopy
1188 * This is the Joliet variant of hs_namecopy()
1190 * Parse a UCS-2 Joliet file/directory name into UNIX form.
1191 * Add NULL terminator.
1192 * Returns the new length.
1194 * Called from hsfs_readdir() via hs_parsedir()
1197 hs_jnamecopy(char *from, char *to, int size, int maxsize, ulong_t flags)
1199 uint_t i;
1200 uint_t len;
1201 uint16_t c;
1202 int amt;
1203 int version;
1205 /* special handling for '.' and '..' */
1206 if (size == 1) {
1207 if (*from == '\0') {
1208 *to++ = '.';
1209 *to = '\0';
1210 return (1);
1211 } else if (*from == '\1') {
1212 *to++ = '.';
1213 *to++ = '.';
1214 *to = '\0';
1215 return (2);
1219 version = (flags & HSFSMNT_NOVERSION) == 0;
1220 for (i = 0, len = 0; i < size; i++) {
1221 c = (from[i++] & 0xFF) << 8;
1222 c |= from[i] & 0xFF;
1223 if (c == ';' && version)
1224 break;
1226 if (len > (maxsize-3)) {
1227 if (c < 0x80)
1228 amt = 1;
1229 else if (c < 0x800)
1230 amt = 2;
1231 else
1232 amt = 3;
1233 if ((len+amt) > maxsize) {
1234 to[len] = '\0';
1235 return (-len);
1238 amt = hs_ucs2_2_utf8(c, (uint8_t *)&to[len]);
1239 if (amt == 0) {
1240 hs_log_bogus_joliet_warning(); /* should never happen */
1241 return (0);
1243 len += amt;
1245 to[len] = '\0';
1246 return (len);
1250 * map a filename to upper case;
1251 * return 1 if found lowercase character
1253 * Called from process_dirblock()
1254 * via hsfs_lookup() -> hs_dirlook() -> process_dirblock()
1255 * to create an intermedia name from on disk file names for
1256 * comparing names.
1258 static int
1259 uppercase_cp(char *from, char *to, int size)
1261 uint_t i;
1262 uchar_t c;
1263 uchar_t had_lc = 0;
1265 for (i = 0; i < size; i++) {
1266 c = *from++;
1267 if ((c >= 'a') && (c <= 'z')) {
1268 c -= ('a' - 'A');
1269 had_lc = 1;
1271 *to++ = c;
1273 return (had_lc);
1277 * This is the Joliet variant of uppercase_cp()
1279 * map a UCS-2 filename to UTF-8;
1280 * return new length
1282 * Called from process_dirblock()
1283 * via hsfs_lookup() -> hs_dirlook() -> process_dirblock()
1284 * to create an intermedia name from on disk file names for
1285 * comparing names.
1288 hs_joliet_cp(char *from, char *to, int size)
1290 uint_t i;
1291 uint16_t c;
1292 int len = 0;
1293 int amt;
1295 /* special handling for '\0' and '\1' */
1296 if (size == 1) {
1297 *to = *from;
1298 return (1);
1300 for (i = 0; i < size; i += 2) {
1301 c = (*from++ & 0xFF) << 8;
1302 c |= *from++ & 0xFF;
1304 amt = hs_ucs2_2_utf8(c, (uint8_t *)to);
1305 if (amt == 0) {
1306 hs_log_bogus_joliet_warning(); /* should never happen */
1307 return (0);
1310 to += amt;
1311 len += amt;
1313 return (len);
1316 static void
1317 hs_log_bogus_joliet_warning(void)
1319 static int warned = 0;
1321 if (warned)
1322 return;
1323 warned = 1;
1324 cmn_err(CE_CONT, "hsfs: Warning: "
1325 "file name contains bad UCS-2 chacarter\n");
1330 * hs_uppercase_copy
1332 * Convert a UNIX-style name into its HSFS equivalent
1333 * replacing '.' and '..' with '\0' and '\1'.
1334 * Map to upper case.
1335 * Returns the (possibly new) length.
1337 * Called from hs_dirlook() and rrip_namecopy()
1338 * to create an intermediate name from the callers name from hsfs_lookup()
1339 * XXX Is the call from rrip_namecopy() OK?
1342 hs_uppercase_copy(char *from, char *to, int size)
1344 uint_t i;
1345 uchar_t c;
1347 /* special handling for '.' and '..' */
1349 if (size == 1 && *from == '.') {
1350 *to = '\0';
1351 return (1);
1352 } else if (size == 2 && *from == '.' && *(from+1) == '.') {
1353 *to = '\1';
1354 return (1);
1357 for (i = 0; i < size; i++) {
1358 c = *from++;
1359 if ((c >= 'a') && (c <= 'z'))
1360 c = c - 'a' + 'A';
1361 *to++ = c;
1363 return (size);
1367 * hs_iso_copy
1369 * This is the Joliet/ISO-9660:1999 variant of hs_uppercase_copy()
1371 * Convert a UTF-8 UNIX-style name into its UTF-8 Joliet/ISO equivalent
1372 * replacing '.' and '..' with '\0' and '\1'.
1373 * Returns the (possibly new) length.
1375 * Called from hs_dirlook()
1376 * to create an intermediate name from the callers name from hsfs_lookup()
1378 static int
1379 hs_iso_copy(char *from, char *to, int size)
1381 uint_t i;
1382 uchar_t c;
1384 /* special handling for '.' and '..' */
1386 if (size == 1 && *from == '.') {
1387 *to = '\0';
1388 return (1);
1389 } else if (size == 2 && *from == '.' && *(from+1) == '.') {
1390 *to = '\1';
1391 return (1);
1394 for (i = 0; i < size; i++) {
1395 c = *from++;
1396 *to++ = c;
1398 return (size);
1401 void
1402 hs_filldirent(struct vnode *vp, struct hs_direntry *hdp)
1404 struct buf *secbp;
1405 uint_t secno;
1406 offset_t secoff;
1407 struct hsfs *fsp;
1408 uchar_t *secp;
1409 int error;
1411 if (vp->v_type != VDIR) {
1412 cmn_err(CE_WARN, "hsfs_filldirent: vp (0x%p) not a directory",
1413 (void *)vp);
1414 return;
1417 fsp = VFS_TO_HSFS(vp ->v_vfsp);
1418 secno = LBN_TO_SEC(hdp->ext_lbn+hdp->xar_len, vp->v_vfsp);
1419 secoff = LBN_TO_BYTE(hdp->ext_lbn+hdp->xar_len, vp->v_vfsp) &
1420 MAXHSOFFSET;
1421 secbp = bread(fsp->hsfs_devvp->v_rdev, secno * 4, HS_SECTOR_SIZE);
1422 error = geterror(secbp);
1423 if (error != 0) {
1424 cmn_err(CE_NOTE, "hs_filldirent: bread: error=(%d)", error);
1425 goto end;
1428 secp = (uchar_t *)secbp->b_un.b_addr;
1430 /* quick check */
1431 if (hdp->ext_lbn != HDE_EXT_LBN(&secp[secoff])) {
1432 cmn_err(CE_NOTE, "hsfs_filldirent: dirent not match");
1433 /* keep on going */
1435 (void) hs_parsedir(fsp, &secp[secoff], hdp, NULL,
1436 NULL, HS_SECTOR_SIZE - secoff);
1438 end:
1439 brelse(secbp);
1443 * Look through a directory block for a matching entry.
1444 * Note: this routine does an fbrelse() on the buffer passed in.
1446 static enum dirblock_result
1447 process_dirblock(
1448 struct fbuf *fbp, /* buffer containing dirblk */
1449 uint_t *offset, /* lower index */
1450 uint_t last_offset, /* upper index */
1451 char *nm, /* upcase nm to compare against */
1452 int nmlen, /* length of name */
1453 struct hsfs *fsp,
1454 struct hsnode *dhp,
1455 struct vnode *dvp,
1456 struct vnode **vpp,
1457 int *error) /* return value: errno */
1459 uchar_t *blkp = (uchar_t *)fbp->fb_addr; /* dir block */
1460 char *dname; /* name in directory entry */
1461 int dnamelen; /* length of name */
1462 struct hs_direntry hd;
1463 int hdlen;
1464 uchar_t *dirp; /* the directory entry */
1465 int res;
1466 int parsedir_res;
1467 int is_rrip;
1468 size_t rrip_name_size;
1469 int rr_namelen = 0;
1470 char *rrip_name_str = NULL;
1471 char *rrip_tmp_name = NULL;
1472 enum dirblock_result err = 0;
1473 int did_fbrelse = 0;
1474 char uppercase_name[JOLIET_NAMELEN_MAX*3 + 1]; /* 331 */
1476 #define rel_offset(offset) \
1477 ((offset) & MAXBOFFSET) /* index into cur blk */
1478 #define RESTORE_NM(tmp, orig) \
1479 if (is_rrip && *(tmp) != '\0') \
1480 (void) strcpy((orig), (tmp))
1482 is_rrip = IS_RRIP_IMPLEMENTED(fsp);
1483 if (is_rrip) {
1484 rrip_name_size = RRIP_FILE_NAMELEN + 1;
1485 rrip_name_str = kmem_alloc(rrip_name_size, KM_SLEEP);
1486 rrip_tmp_name = kmem_alloc(rrip_name_size, KM_SLEEP);
1487 rrip_name_str[0] = '\0';
1488 rrip_tmp_name[0] = '\0';
1491 while (*offset < last_offset) {
1494 * Directory Entries cannot span sectors.
1496 * Unused bytes at the end of each sector are zeroed
1497 * according to ISO9660, but we cannot rely on this
1498 * since both media failures and maliciously corrupted
1499 * media may return arbitrary values.
1500 * We therefore have to check for consistency:
1501 * The size of a directory entry must be at least
1502 * 34 bytes (the size of the directory entry metadata),
1503 * or zero (indicating the end-of-sector condition).
1504 * For a non-zero directory entry size of less than
1505 * 34 Bytes, log a warning.
1506 * In any case, skip the rest of this sector and
1507 * continue with the next.
1509 hdlen = (int)((uchar_t)
1510 HDE_DIR_LEN(&blkp[rel_offset(*offset)]));
1512 if (hdlen < HDE_ROOT_DIR_REC_SIZE ||
1513 *offset + hdlen > last_offset) {
1515 * Advance to the next sector boundary
1517 *offset = roundup(*offset + 1, HS_SECTOR_SIZE);
1518 if (hdlen)
1519 hs_log_bogus_disk_warning(fsp,
1520 HSFS_ERR_TRAILING_JUNK, 0);
1521 continue;
1524 bzero(&hd, sizeof (hd));
1527 * Check the filename length in the ISO record for
1528 * plausibility and reset it to a safe value, in case
1529 * the name length byte is out of range. Since the ISO
1530 * name will be used as fallback if the rockridge name
1531 * is invalid/nonexistant, we must make sure not to
1532 * blow the bounds and initialize dnamelen to a sensible
1533 * value within the limits of ISO9660.
1534 * In addition to that, the ISO filename is part of the
1535 * directory entry. If the filename length is too large
1536 * to fit, the record is invalid and we'll advance to
1537 * the next.
1539 dirp = &blkp[rel_offset(*offset)];
1540 dname = (char *)HDE_name(dirp);
1541 dnamelen = (int)((uchar_t)HDE_NAME_LEN(dirp));
1543 * If the directory entry extends beyond the end of the
1544 * block, it must be invalid. Skip it.
1546 if (dnamelen > hdlen - HDE_FDESIZE) {
1547 hs_log_bogus_disk_warning(fsp,
1548 HSFS_ERR_BAD_DIR_ENTRY, 0);
1549 goto skip_rec;
1550 } else if (dnamelen > fsp->hsfs_namelen &&
1551 hs_namelen(fsp, dname, dnamelen) > fsp->hsfs_namelen) {
1552 hs_log_bogus_disk_warning(fsp,
1553 fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET ?
1554 HSFS_ERR_BAD_JOLIET_FILE_LEN :
1555 HSFS_ERR_BAD_FILE_LEN, 0);
1557 if (dnamelen > ISO_NAMELEN_V2_MAX)
1558 dnamelen = fsp->hsfs_namemax; /* Paranoia */
1561 * If the rock ridge is implemented, then we copy the name
1562 * from the SUA area to rrip_name_str. If no Alternate
1563 * name is found, then use the uppercase NM in the
1564 * rrip_name_str char array.
1566 if (is_rrip) {
1568 rrip_name_str[0] = '\0';
1569 rr_namelen = rrip_namecopy(nm, &rrip_name_str[0],
1570 &rrip_tmp_name[0], dirp, last_offset - *offset,
1571 fsp, &hd);
1572 if (hd.sym_link) {
1573 kmem_free(hd.sym_link,
1574 (size_t)(hd.ext_size+1));
1575 hd.sym_link = NULL;
1578 if (rr_namelen != -1) {
1579 dname = (char *)&rrip_name_str[0];
1580 dnamelen = rr_namelen;
1584 if (!is_rrip || rr_namelen == -1) {
1585 /* use iso name instead */
1587 int i = -1;
1589 * make sure that we get rid of ';' in the dname of
1590 * an iso direntry, as we should have no knowledge
1591 * of file versions.
1593 * XXX This is done the wrong way: it does not take
1594 * XXX care of the fact that the version string is
1595 * XXX a decimal number in the range 1 to 32767.
1597 if ((fsp->hsfs_flags & HSFSMNT_NOVERSION) == 0) {
1598 if (fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET) {
1599 for (i = dnamelen - 1; i > 0; i -= 2) {
1600 if (dname[i] == ';' &&
1601 dname[i-1] == '\0') {
1602 --i;
1603 break;
1606 } else {
1607 for (i = dnamelen - 1; i > 0; i--) {
1608 if (dname[i] == ';')
1609 break;
1613 if (i > 0) {
1614 dnamelen = i;
1615 } else if (fsp->hsfs_vol_type != HS_VOL_TYPE_ISO_V2 &&
1616 fsp->hsfs_vol_type != HS_VOL_TYPE_JOLIET) {
1617 dnamelen = strip_trailing(fsp, dname, dnamelen);
1620 ASSERT(dnamelen < sizeof (uppercase_name));
1622 if (fsp->hsfs_vol_type == HS_VOL_TYPE_ISO_V2) {
1623 (void) strncpy(uppercase_name, dname, dnamelen);
1624 } else if (fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET) {
1625 dnamelen = hs_joliet_cp(dname, uppercase_name,
1626 dnamelen);
1627 } else if (uppercase_cp(dname, uppercase_name,
1628 dnamelen)) {
1629 hs_log_bogus_disk_warning(fsp,
1630 HSFS_ERR_LOWER_CASE_NM, 0);
1632 dname = uppercase_name;
1633 if (!is_rrip &&
1634 (fsp->hsfs_flags & HSFSMNT_NOTRAILDOT) &&
1635 dname[dnamelen - 1] == '.' &&
1636 CAN_TRUNCATE_DOT(dname, dnamelen))
1637 dname[--dnamelen] = '\0';
1641 * Quickly screen for a non-matching entry, but not for RRIP.
1642 * This test doesn't work for lowercase vs. uppercase names.
1645 /* if we saw a lower case name we can't do this test either */
1646 if (strict_iso9660_ordering && !is_rrip &&
1647 !HSFS_HAVE_LOWER_CASE(fsp) && *nm < *dname) {
1648 RESTORE_NM(rrip_tmp_name, nm);
1649 err = WENT_PAST;
1650 goto do_ret;
1653 if (*nm != *dname || nmlen != dnamelen)
1654 goto skip_rec;
1656 if ((res = bcmp(dname, nm, nmlen)) == 0) {
1657 /* name matches */
1658 parsedir_res = hs_parsedir(fsp, dirp, &hd, NULL, NULL,
1659 last_offset - *offset);
1660 if (!parsedir_res) {
1661 uint_t lbn; /* logical block number */
1663 lbn = dhp->hs_dirent.ext_lbn +
1664 dhp->hs_dirent.xar_len;
1666 * Need to do an fbrelse() on the buffer,
1667 * as hs_makenode() may try to acquire
1668 * hs_hashlock, which may not be required
1669 * while a page is locked.
1671 fbrelse(fbp, S_READ);
1672 did_fbrelse = 1;
1673 *vpp = hs_makenode(&hd, lbn, *offset,
1674 dvp->v_vfsp);
1675 if (*vpp == NULL) {
1676 *error = ENFILE;
1677 RESTORE_NM(rrip_tmp_name, nm);
1678 err = FOUND_ENTRY;
1679 goto do_ret;
1682 dhp->hs_offset = *offset;
1683 RESTORE_NM(rrip_tmp_name, nm);
1684 err = FOUND_ENTRY;
1685 goto do_ret;
1686 } else if (parsedir_res != EAGAIN) {
1687 /* improper dir entry */
1688 *error = parsedir_res;
1689 RESTORE_NM(rrip_tmp_name, nm);
1690 err = FOUND_ENTRY;
1691 goto do_ret;
1693 } else if (strict_iso9660_ordering && !is_rrip &&
1694 !HSFS_HAVE_LOWER_CASE(fsp) && res < 0) {
1695 /* name < dir entry */
1696 RESTORE_NM(rrip_tmp_name, nm);
1697 err = WENT_PAST;
1698 goto do_ret;
1701 * name > dir entry,
1702 * look at next one.
1704 skip_rec:
1705 *offset += hdlen;
1706 RESTORE_NM(rrip_tmp_name, nm);
1708 err = HIT_END;
1709 do_ret:
1710 if (rrip_name_str)
1711 kmem_free(rrip_name_str, rrip_name_size);
1712 if (rrip_tmp_name)
1713 kmem_free(rrip_tmp_name, rrip_name_size);
1714 if (!did_fbrelse)
1715 fbrelse(fbp, S_READ);
1716 return (err);
1717 #undef RESTORE_NM
1721 * Strip trailing nulls or spaces from the name;
1722 * return adjusted length. If we find such junk,
1723 * log a non-conformant disk message.
1725 static int
1726 strip_trailing(struct hsfs *fsp, char *nm, int len)
1728 char *c;
1729 int trailing_junk = 0;
1731 for (c = nm + len - 1; c > nm; c--) {
1732 if (*c == ' ' || *c == '\0')
1733 trailing_junk = 1;
1734 else
1735 break;
1738 if (trailing_junk)
1739 hs_log_bogus_disk_warning(fsp, HSFS_ERR_TRAILING_JUNK, 0);
1741 return ((int)(c - nm + 1));
1744 static int
1745 hs_namelen(struct hsfs *fsp, char *nm, int len)
1747 char *p = nm + len;
1749 if (fsp->hsfs_vol_type == HS_VOL_TYPE_ISO_V2) {
1750 return (len);
1751 } else if (fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET) {
1752 uint16_t c;
1754 while (--p > &nm[1]) {
1755 c = *p;
1756 c |= *--p * 256;
1757 if (c == ';')
1758 return (p - nm);
1759 if (c < '0' || c > '9') {
1760 p++;
1761 return (p - nm);
1764 } else {
1765 char c;
1767 while (--p > nm) {
1768 c = *p;
1769 if (c == ';')
1770 return (p - nm);
1771 if (c < '0' || c > '9') {
1772 p++;
1773 return (p - nm);
1777 return (len);
1781 * Take a UCS-2 character and convert
1782 * it into a utf8 character.
1783 * A 0 will be returned if the conversion fails
1785 * See http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
1787 * The code has been taken from udfs/udf_subr.c
1789 static uint8_t hs_first_byte_mark[7] =
1790 { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
1791 static int32_t
1792 hs_ucs2_2_utf8(uint16_t c_16, uint8_t *s_8)
1794 int32_t nc;
1795 uint32_t c_32;
1796 uint32_t byte_mask = 0xBF;
1797 uint32_t byte_mark = 0x80;
1800 * Convert the 16-bit character to a 32-bit character
1802 c_32 = c_16;
1805 * By here the 16-bit character is converted
1806 * to a 32-bit wide character
1808 if (c_32 < 0x80) {
1809 nc = 1;
1810 } else if (c_32 < 0x800) {
1811 nc = 2;
1812 } else if (c_32 < 0x10000) {
1813 nc = 3;
1814 } else if (c_32 < 0x200000) {
1815 nc = 4;
1816 } else if (c_32 < 0x4000000) {
1817 nc = 5;
1818 } else if (c_32 <= 0x7FFFFFFF) { /* avoid signed overflow */
1819 nc = 6;
1820 } else {
1821 nc = 0;
1823 s_8 += nc;
1824 switch (nc) {
1825 case 6 :
1826 *(--s_8) = (c_32 | byte_mark) & byte_mask;
1827 c_32 >>= 6;
1828 /* FALLTHROUGH */
1829 case 5 :
1830 *(--s_8) = (c_32 | byte_mark) & byte_mask;
1831 c_32 >>= 6;
1832 /* FALLTHROUGH */
1833 case 4 :
1834 *(--s_8) = (c_32 | byte_mark) & byte_mask;
1835 c_32 >>= 6;
1836 /* FALLTHROUGH */
1837 case 3 :
1838 *(--s_8) = (c_32 | byte_mark) & byte_mask;
1839 c_32 >>= 6;
1840 /* FALLTHROUGH */
1841 case 2 :
1842 *(--s_8) = (c_32 | byte_mark) & byte_mask;
1843 c_32 >>= 6;
1844 /* FALLTHROUGH */
1845 case 1 :
1846 *(--s_8) = c_32 | hs_first_byte_mark[nc];
1848 return (nc);