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