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