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