4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2016 PALO, Richard.
27 * Directory operations for High Sierra filesystem
30 #include <sys/types.h>
31 #include <sys/t_lock.h>
32 #include <sys/param.h>
33 #include <sys/systm.h>
38 #include <sys/vnode.h>
41 #include <sys/cmn_err.h>
44 #include <sys/policy.h>
45 #include <sys/sunddi.h>
50 #include <vm/seg_map.h>
51 #include <vm/seg_kmem.h>
54 #include <sys/fs/hsfs_spec.h>
55 #include <sys/fs/hsfs_isospec.h>
56 #include <sys/fs/hsfs_node.h>
57 #include <sys/fs/hsfs_impl.h>
58 #include <sys/fs/hsfs_susp.h>
59 #include <sys/fs/hsfs_rrip.h>
61 #include <sys/sysinfo.h>
62 #include <sys/sysmacros.h>
63 #include <sys/errno.h>
64 #include <sys/debug.h>
65 #include <sys/fs_subr.h>
68 * This macro expects a name that ends in '.' and returns TRUE if the
69 * name is not "." or ".."
71 #define CAN_TRUNCATE_DOT(name, namelen) \
72 (namelen > 1 && (namelen > 2 || name[0] != '.'))
74 enum dirblock_result
{ FOUND_ENTRY
, WENT_PAST
, HIT_END
};
77 * These values determine whether we will try to read a file or dir;
78 * they may be patched via /etc/system to allow users to read
79 * record-oriented files.
81 int ide_prohibited
= IDE_PROHIBITED
;
82 int hde_prohibited
= HDE_PROHIBITED
;
85 * This variable determines if the HSFS code will use the
86 * directory name lookup cache. The default is for the cache to be used.
88 static int hsfs_use_dnlc
= 1;
91 * This variable determines whether strict ISO-9660 directory ordering
92 * is to be assumed. If false (which it is by default), then when
93 * searching a directory of an ISO-9660 disk, we do not expect the
94 * entries to be sorted (as the spec requires), and so cannot terminate
95 * the search early. Unfortunately, some vendors are producing
96 * non-compliant disks. This variable exists to revert to the old
97 * behavior in case someone relies on this. This option is expected to be
98 * removed at some point in the future.
100 * Use "set hsfs:strict_iso9660_ordering = 1" in /etc/system to override.
102 static int strict_iso9660_ordering
= 0;
105 * This tunable allows us to ignore inode numbers from rrip-1.12.
106 * In this case, we fall back to our default inode algorithm.
108 int use_rrip_inodes
= 1;
110 static void hs_hsnode_cache_reclaim(void *unused
);
111 static void hs_addfreeb(struct hsfs
*fsp
, struct hsnode
*hp
);
112 static enum dirblock_result
process_dirblock(struct fbuf
*fbp
, uint_t
*offset
,
113 uint_t last_offset
, char *nm
, int nmlen
, struct hsfs
*fsp
,
114 struct hsnode
*dhp
, struct vnode
*dvp
, struct vnode
**vpp
,
116 static int strip_trailing(struct hsfs
*fsp
, char *nm
, int len
);
117 static int hs_namelen(struct hsfs
*fsp
, char *nm
, int len
);
118 static int uppercase_cp(char *from
, char *to
, int size
);
119 static void hs_log_bogus_joliet_warning(void);
120 static int hs_iso_copy(char *from
, char *to
, int size
);
121 static int32_t hs_ucs2_2_utf8(uint16_t c_16
, uint8_t *s_8
);
122 static int hs_utf8_trunc(uint8_t *str
, int len
);
126 * Return 0 if the desired access may be granted.
127 * Otherwise return error code.
130 hs_access(struct vnode
*vp
, mode_t m
, struct cred
*cred
)
136 * Write access cannot be granted for a read-only medium
138 if ((m
& VWRITE
) && !IS_DEVVP(vp
))
144 * XXX - For now, use volume protections.
145 * Also, always grant EXEC access for directories
146 * if READ access is granted.
148 if ((vp
->v_type
== VDIR
) && (m
& VEXEC
)) {
153 if (crgetuid(cred
) != hp
->hs_dirent
.uid
) {
155 if (!groupmember((uid_t
)hp
->hs_dirent
.gid
, cred
))
158 return (secpolicy_vnode_access2(cred
, vp
, hp
->hs_dirent
.uid
,
159 hp
->hs_dirent
.mode
<< shift
, m
));
162 #if ((HS_HASHSIZE & (HS_HASHSIZE - 1)) == 0)
163 #define HS_HASH(l) ((uint_t)(l) & (HS_HASHSIZE - 1))
165 #define HS_HASH(l) ((uint_t)(l) % HS_HASHSIZE)
167 #define HS_HPASH(hp) HS_HASH((hp)->hs_nodeid)
170 * The tunable nhsnode is now a threshold for a dynamically allocated
171 * pool of hsnodes, not the size of a statically allocated table.
172 * When the number of hsnodes for a particular file system exceeds
173 * nhsnode, the allocate and free logic will try to reduce the number
174 * of allocated nodes by returning unreferenced nodes to the kmem_cache
175 * instead of putting them on the file system's private free list.
177 int nhsnode
= HS_HSNODESPACE
/ sizeof (struct hsnode
);
179 struct kmem_cache
*hsnode_cache
; /* free hsnode cache */
182 * Initialize the cache of free hsnodes.
185 hs_init_hsnode_cache(void)
188 * A kmem_cache is used for the hsnodes
189 * No constructor because hsnodes are initialised by bzeroing.
191 hsnode_cache
= kmem_cache_create("hsfs_hsnode_cache",
192 sizeof (struct hsnode
), 0, NULL
,
193 NULL
, hs_hsnode_cache_reclaim
, NULL
, NULL
, 0);
197 * Destroy the cache of free hsnodes.
200 hs_fini_hsnode_cache(void)
202 kmem_cache_destroy(hsnode_cache
);
206 * System is short on memory, free up as much as possible
210 hs_hsnode_cache_reclaim(void *unused
)
216 * For each vfs in the hs_mounttab list
218 mutex_enter(&hs_mounttab_lock
);
219 for (fsp
= hs_mounttab
; fsp
!= NULL
; fsp
= fsp
->hsfs_next
) {
221 * Purge the dnlc of all hsfs entries
223 (void) dnlc_purge_vfsp(fsp
->hsfs_vfs
, 0);
226 * For each entry in the free chain
228 rw_enter(&fsp
->hsfs_hash_lock
, RW_WRITER
);
229 mutex_enter(&fsp
->hsfs_free_lock
);
230 for (hp
= fsp
->hsfs_free_f
; hp
!= NULL
; hp
= fsp
->hsfs_free_f
) {
234 fsp
->hsfs_free_f
= hp
->hs_freef
;
235 if (fsp
->hsfs_free_f
!= NULL
) {
236 fsp
->hsfs_free_f
->hs_freeb
= NULL
;
238 fsp
->hsfs_free_b
= NULL
;
241 * Free the node. Force it to be fully freed
242 * by setting the 3rd arg (nopage) to 1.
244 hs_freenode(HTOV(hp
), fsp
, 1);
246 mutex_exit(&fsp
->hsfs_free_lock
);
247 rw_exit(&fsp
->hsfs_hash_lock
);
249 mutex_exit(&hs_mounttab_lock
);
253 * Add an hsnode to the end of the free list.
256 hs_addfreeb(struct hsfs
*fsp
, struct hsnode
*hp
)
260 vn_invalid(HTOV(hp
));
261 mutex_enter(&fsp
->hsfs_free_lock
);
262 ep
= fsp
->hsfs_free_b
;
263 fsp
->hsfs_free_b
= hp
; /* hp is the last entry in free list */
265 hp
->hs_freeb
= ep
; /* point at previous last entry */
267 fsp
->hsfs_free_f
= hp
; /* hp is only entry in free list */
269 ep
->hs_freef
= hp
; /* point previous last entry at hp */
271 mutex_exit(&fsp
->hsfs_free_lock
);
275 * Get an hsnode from the front of the free list.
276 * Must be called with write hsfs_hash_lock held.
278 static struct hsnode
*
279 hs_getfree(struct hsfs
*fsp
)
281 struct hsnode
*hp
, **tp
;
283 ASSERT(RW_WRITE_HELD(&fsp
->hsfs_hash_lock
));
286 * If the number of currently-allocated hsnodes is less than
287 * the hsnode count threshold (nhsnode), or if there are no
288 * nodes on the file system's local free list (which acts as a
289 * cache), call kmem_cache_alloc to get a new hsnode from
292 mutex_enter(&fsp
->hsfs_free_lock
);
293 if ((fsp
->hsfs_nohsnode
< nhsnode
) || (fsp
->hsfs_free_f
== NULL
)) {
294 mutex_exit(&fsp
->hsfs_free_lock
);
295 hp
= kmem_cache_alloc(hsnode_cache
, KM_SLEEP
);
296 fsp
->hsfs_nohsnode
++;
297 bzero((caddr_t
)hp
, sizeof (*hp
));
298 hp
->hs_vnode
= vn_alloc(KM_SLEEP
);
301 hp
= fsp
->hsfs_free_f
;
302 /* hp cannot be NULL, since we already checked this above */
303 fsp
->hsfs_free_f
= hp
->hs_freef
;
304 if (fsp
->hsfs_free_f
!= NULL
)
305 fsp
->hsfs_free_f
->hs_freeb
= NULL
;
307 fsp
->hsfs_free_b
= NULL
;
308 mutex_exit(&fsp
->hsfs_free_lock
);
310 for (tp
= &fsp
->hsfs_hash
[HS_HPASH(hp
)]; *tp
!= NULL
;
311 tp
= &(*tp
)->hs_hash
) {
318 * file is no longer referenced, destroy all old pages
320 if (vn_has_cached_data(vp
))
322 * pvn_vplist_dirty will abort all old pages
324 (void) pvn_vplist_dirty(vp
, 0,
325 hsfs_putapage
, B_INVAL
, NULL
);
330 if (hp
->hs_dirent
.sym_link
!= NULL
) {
331 kmem_free(hp
->hs_dirent
.sym_link
,
332 (size_t)(hp
->hs_dirent
.ext_size
+ 1));
335 mutex_destroy(&hp
->hs_contents_lock
);
340 bzero((caddr_t
)hp
, sizeof (*hp
));
348 * Remove an hsnode from the free list.
351 hs_remfree(struct hsfs
*fsp
, struct hsnode
*hp
)
353 mutex_enter(&fsp
->hsfs_free_lock
);
354 if (hp
->hs_freef
!= NULL
)
355 hp
->hs_freef
->hs_freeb
= hp
->hs_freeb
;
357 fsp
->hsfs_free_b
= hp
->hs_freeb
;
358 if (hp
->hs_freeb
!= NULL
)
359 hp
->hs_freeb
->hs_freef
= hp
->hs_freef
;
361 fsp
->hsfs_free_f
= hp
->hs_freef
;
362 mutex_exit(&fsp
->hsfs_free_lock
);
366 * Look for hsnode in hash list.
367 * If the inode number is != HS_DUMMY_INO (16), then only the inode
368 * number is used for the check.
369 * If the inode number is == HS_DUMMY_INO, we additionally always
370 * check the directory offset for the file to avoid caching the
371 * meta data for all zero sized to the first zero sized file that
374 * If found, reactivate it if inactive.
376 * Must be entered with hsfs_hash_lock held.
379 hs_findhash(ino64_t nodeid
, uint_t lbn
, uint_t off
, struct vfs
*vfsp
)
384 fsp
= VFS_TO_HSFS(vfsp
);
386 ASSERT(RW_LOCK_HELD(&fsp
->hsfs_hash_lock
));
388 for (tp
= fsp
->hsfs_hash
[HS_HASH(nodeid
)]; tp
!= NULL
;
390 if (tp
->hs_nodeid
== nodeid
) {
393 if (nodeid
== HS_DUMMY_INO
) {
395 * If this is the dummy inode number, look for
396 * matching dir_lbn and dir_off.
398 for (; tp
!= NULL
; tp
= tp
->hs_hash
) {
399 if (tp
->hs_nodeid
== nodeid
&&
400 tp
->hs_dir_lbn
== lbn
&&
401 tp
->hs_dir_off
== off
)
408 mutex_enter(&tp
->hs_contents_lock
);
411 if ((tp
->hs_flags
& HREF
) == 0) {
412 tp
->hs_flags
|= HREF
;
414 * reactivating a free hsnode:
415 * remove from free list
419 mutex_exit(&tp
->hs_contents_lock
);
427 hs_addhash(struct hsfs
*fsp
, struct hsnode
*hp
)
431 ASSERT(RW_WRITE_HELD(&fsp
->hsfs_hash_lock
));
433 hashno
= HS_HPASH(hp
);
434 hp
->hs_hash
= fsp
->hsfs_hash
[hashno
];
435 fsp
->hsfs_hash
[hashno
] = hp
;
439 * Destroy all old pages and free the hsnodes
440 * Return 1 if busy (a hsnode is still referenced).
443 hs_synchash(struct vfs
*vfsp
)
447 struct hsnode
*hp
, *nhp
;
449 struct vnode
*vp
, *rvp
;
451 fsp
= VFS_TO_HSFS(vfsp
);
452 rvp
= fsp
->hsfs_rootvp
;
453 /* make sure no one can come in */
454 rw_enter(&fsp
->hsfs_hash_lock
, RW_WRITER
);
455 for (i
= 0; i
< HS_HASHSIZE
; i
++) {
456 for (hp
= fsp
->hsfs_hash
[i
]; hp
!= NULL
; hp
= hp
->hs_hash
) {
458 if ((hp
->hs_flags
& HREF
) && (vp
!= rvp
||
459 (vp
== rvp
&& vp
->v_count
> 1))) {
463 if (vn_has_cached_data(vp
))
464 (void) pvn_vplist_dirty(vp
, 0,
465 hsfs_putapage
, B_INVAL
, NULL
);
469 rw_exit(&fsp
->hsfs_hash_lock
);
473 /* now free the hsnodes */
474 for (i
= 0; i
< HS_HASHSIZE
; i
++) {
475 for (hp
= fsp
->hsfs_hash
[i
]; hp
!= NULL
; hp
= nhp
) {
478 * We know there are no pages associated with
479 * all the hsnodes (they've all been released
480 * above). So remove from free list and
481 * free the entry with nopage set.
486 hs_freenode(vp
, fsp
, 1);
491 ASSERT(fsp
->hsfs_nohsnode
== 1);
492 rw_exit(&fsp
->hsfs_hash_lock
);
493 /* release the root hsnode, this should free the final hsnode */
502 * Construct an hsnode.
503 * Caller specifies the directory entry, the block number and offset
504 * of the directory entry, and the vfs pointer.
505 * note: off is the sector offset, not lbn offset
506 * if NULL is returned implies file system hsnode table full
510 struct hs_direntry
*dp
,
517 struct hs_volume
*hvp
;
522 fsp
= VFS_TO_HSFS(vfsp
);
525 * Construct the data that allows us to re-read the meta data without
526 * knowing the name of the file: in the case of a directory
527 * entry, this should point to the canonical dirent, the "."
528 * directory entry for the directory. This dirent is pointed
529 * to by all directory entries for that dir (including the ".")
531 * In the case of a file, simply point to the dirent for that
532 * file (there are hard links in Rock Ridge, so we need to use
533 * different data to contruct the node id).
535 if (dp
->type
== VDIR
) {
541 * Normalize lbn and off before creating a nodeid
542 * and before storing them in a hs_node structure
544 hvp
= &fsp
->hsfs_vol
;
545 lbn
+= off
>> hvp
->lbn_shift
;
546 off
&= hvp
->lbn_maxoffset
;
548 * If the media carries rrip-v1.12 or newer, and we trust the inodes
549 * from the rrip data (use_rrip_inodes != 0), use that data. If the
550 * media has been created by a recent mkisofs version, we may trust
551 * all numbers in the starting extent number; otherwise, we cannot
552 * do this for zero sized files and symlinks, because if we did we'd
553 * end up mapping all of them to the same node.
554 * We use HS_DUMMY_INO in this case and make sure that we will not
555 * map all files to the same meta data.
557 if (dp
->inode
!= 0 && use_rrip_inodes
) {
559 } else if ((dp
->ext_size
== 0 || dp
->sym_link
!= NULL
) &&
560 (fsp
->hsfs_flags
& HSFSMNT_INODE
) == 0) {
561 nodeid
= HS_DUMMY_INO
;
563 nodeid
= dp
->ext_lbn
;
566 /* look for hsnode in cache first */
568 rw_enter(&fsp
->hsfs_hash_lock
, RW_READER
);
570 if ((vp
= hs_findhash(nodeid
, lbn
, off
, vfsp
)) == NULL
) {
573 * Not in cache. However, someone else may have come
574 * to the same conclusion and just put one in. Upgrade
575 * our lock to a write lock and look again.
577 rw_exit(&fsp
->hsfs_hash_lock
);
578 rw_enter(&fsp
->hsfs_hash_lock
, RW_WRITER
);
580 if ((vp
= hs_findhash(nodeid
, lbn
, off
, vfsp
)) == NULL
) {
582 * Now we are really sure that the hsnode is not
583 * in the cache. Get one off freelist or else
584 * allocate one. Either way get a bzeroed hsnode.
586 hp
= hs_getfree(fsp
);
588 bcopy((caddr_t
)dp
, (caddr_t
)&hp
->hs_dirent
,
591 * We've just copied this pointer into hs_dirent,
592 * and don't want 2 references to same symlink.
597 * No need to hold any lock because hsnode is not
598 * yet in the hash chain.
600 mutex_init(&hp
->hs_contents_lock
, NULL
, MUTEX_DEFAULT
,
602 hp
->hs_dir_lbn
= lbn
;
603 hp
->hs_dir_off
= off
;
604 hp
->hs_nodeid
= nodeid
;
606 hp
->hs_prev_offset
= 0;
607 hp
->hs_num_contig
= 0;
610 if (off
> HS_SECTOR_SIZE
)
611 cmn_err(CE_WARN
, "hs_makenode: bad offset");
615 vp
->v_type
= dp
->type
;
616 vp
->v_rdev
= dp
->r_dev
;
617 vn_setops(vp
, &hsfs_vnodeops
);
618 vp
->v_data
= (caddr_t
)hp
;
621 * if it's a device, call specvp
624 rw_exit(&fsp
->hsfs_hash_lock
);
625 newvp
= specvp(vp
, vp
->v_rdev
, vp
->v_type
,
629 "hs_makenode: specvp failed");
639 if (dp
->sym_link
!= NULL
) {
640 kmem_free(dp
->sym_link
, (size_t)(dp
->ext_size
+ 1));
644 rw_exit(&fsp
->hsfs_hash_lock
);
651 * Deactivate an hsnode.
652 * Leave it on the hash list but put it on the free list.
653 * If the vnode does not have any pages, release the hsnode to the
654 * kmem_cache using kmem_cache_free, else put in back of the free list.
656 * This function can be called with the hsfs_free_lock held, but only
657 * when the code is guaranteed to go through the path where the
658 * node is freed entirely, and not the path where the node could go back
659 * on the free list (and where the free lock would need to be acquired).
662 hs_freenode(vnode_t
*vp
, struct hsfs
*fsp
, int nopage
)
665 struct hsnode
*hp
= VTOH(vp
);
667 ASSERT(RW_LOCK_HELD(&fsp
->hsfs_hash_lock
));
669 if (nopage
|| (fsp
->hsfs_nohsnode
>= nhsnode
)) {
670 /* remove this node from the hash list, if it's there */
671 for (tp
= &fsp
->hsfs_hash
[HS_HPASH(hp
)]; *tp
!= NULL
;
672 tp
= &(*tp
)->hs_hash
) {
680 if (hp
->hs_dirent
.sym_link
!= NULL
) {
681 kmem_free(hp
->hs_dirent
.sym_link
,
682 (size_t)(hp
->hs_dirent
.ext_size
+ 1));
683 hp
->hs_dirent
.sym_link
= NULL
;
685 if (vn_has_cached_data(vp
)) {
686 /* clean all old pages */
687 (void) pvn_vplist_dirty(vp
, 0,
688 hsfs_putapage
, B_INVAL
, NULL
);
690 * XXX - can we remove pages by fiat like this???
691 * This really doesn't seem safe.
693 vp
->v_object
.list
.list_head
.list_next
=
694 vp
->v_object
.list
.list_head
.list_prev
=
695 &vp
->v_object
.list
.list_head
;
696 cmn_err(CE_WARN
, "%s: dropped vnode cached pages in a "
697 "questionable way", __func__
);
699 mutex_destroy(&hp
->hs_contents_lock
);
702 kmem_cache_free(hsnode_cache
, hp
);
703 fsp
->hsfs_nohsnode
--;
706 hs_addfreeb(fsp
, hp
); /* add to back of free list */
712 * Reconstruct a vnode given the location of its directory entry.
713 * Caller specifies the the block number and offset
714 * of the directory entry, and the vfs pointer.
715 * Returns an error code or 0.
718 hs_remakenode(uint_t lbn
, uint_t off
, struct vfs
*vfsp
,
725 struct hs_direntry hd
;
728 /* Convert to sector and offset */
729 fsp
= VFS_TO_HSFS(vfsp
);
730 if (off
> HS_SECTOR_SIZE
) {
731 cmn_err(CE_WARN
, "hs_remakenode: bad offset");
735 secno
= LBN_TO_SEC(lbn
, vfsp
);
736 secbp
= bread(fsp
->hsfs_devvp
->v_rdev
, secno
* 4, HS_SECTOR_SIZE
);
738 error
= geterror(secbp
);
740 cmn_err(CE_NOTE
, "hs_remakenode: bread: error=(%d)", error
);
744 dirp
= (uchar_t
*)secbp
->b_un
.b_addr
;
745 error
= hs_parsedir(fsp
, &dirp
[off
], &hd
, NULL
, NULL
,
746 HS_SECTOR_SIZE
- off
);
748 *vpp
= hs_makenode(&hd
, lbn
, off
, vfsp
);
762 * Look for a given name in a given directory.
763 * If found, construct an hsnode for it.
769 int namlen
, /* length of 'name' */
776 uint_t offset
; /* real offset in directory */
777 uint_t last_offset
; /* last index in directory */
778 char *cmpname
; /* case-folded name */
779 int cmpname_size
; /* how much memory we allocate for it */
781 int adhoc_search
; /* did we start at begin of dir? */
789 if (dvp
->v_type
!= VDIR
)
792 if (error
= hs_access(dvp
, (mode_t
)VEXEC
, cred
))
795 if (hsfs_use_dnlc
&& (*vpp
= dnlc_lookup(dvp
, name
)))
799 fsp
= VFS_TO_HSFS(dvp
->v_vfsp
);
800 is_rrip
= IS_RRIP_IMPLEMENTED(fsp
);
803 * name == "^A" is illegal for ISO-9660 and Joliet as '..' is '\1' on
804 * disk. It is no problem for Rock Ridge as RR uses '.' and '..'.
805 * XXX It could be OK for Joliet also (because namelen == 1 is
806 * XXX impossible for UCS-2) but then we need a better compare algorith.
808 if (!is_rrip
&& *name
== '\1' && namlen
== 1)
811 cmpname_size
= (int)(fsp
->hsfs_namemax
+ 1);
812 cmpname
= kmem_alloc((size_t)cmpname_size
, KM_SLEEP
);
814 if (namlen
>= cmpname_size
)
815 namlen
= cmpname_size
- 1;
817 * For the purposes of comparing the name against dir entries,
818 * fold it to upper case.
821 (void) strlcpy(cmpname
, name
, cmpname_size
);
825 * If we don't consider a trailing dot as part of the filename,
826 * remove it from the specified name
828 if ((fsp
->hsfs_flags
& HSFSMNT_NOTRAILDOT
) &&
829 name
[namlen
-1] == '.' &&
830 CAN_TRUNCATE_DOT(name
, namlen
))
831 name
[--namlen
] = '\0';
832 if (fsp
->hsfs_vol_type
== HS_VOL_TYPE_ISO_V2
||
833 fsp
->hsfs_vol_type
== HS_VOL_TYPE_JOLIET
) {
834 cmpnamelen
= hs_iso_copy(name
, cmpname
, namlen
);
836 cmpnamelen
= hs_uppercase_copy(name
, cmpname
, namlen
);
840 /* make sure dirent is filled up with all info */
841 if (dhp
->hs_dirent
.ext_size
== 0)
842 hs_filldirent(dvp
, &dhp
->hs_dirent
);
845 * No lock is needed - hs_offset is used as starting
846 * point for searching the directory.
848 offset
= dhp
->hs_offset
;
850 adhoc_search
= (offset
!= 0);
852 end
= dhp
->hs_dirent
.ext_size
;
857 while (offset
< end
) {
858 bytes_wanted
= MIN(MAXBSIZE
, dirsiz
- (offset
& MAXBMASK
));
860 error
= fbread(dvp
, (offset_t
)(offset
& MAXBMASK
),
861 (unsigned int)bytes_wanted
, S_READ
, &fbp
);
865 last_offset
= (offset
& MAXBMASK
) + fbp
->fb_count
;
867 switch (process_dirblock(fbp
, &offset
, last_offset
,
868 cmpname
, cmpnamelen
, fsp
, dhp
, dvp
, vpp
, &error
)) {
870 /* found an entry, either correct or not */
875 * If we get here we know we didn't find it on the
876 * first pass. If adhoc_search, then we started a
877 * bit into the dir, and need to wrap around and
878 * search the first entries. If not, then we started
879 * at the beginning and didn't find it.
895 * End of all dir blocks, didn't find entry.
906 * If we found the entry, add it to the DNLC
907 * If the entry is a device file (assuming we support Rock Ridge),
908 * we enter the device vnode to the cache since that is what
910 * That is ok since the CD-ROM is read-only, so (dvp,name) will
911 * always point to the same device.
913 if (hsfs_use_dnlc
&& !error
)
914 dnlc_enter(dvp
, name
, *vpp
);
916 kmem_free(cmpname
, (size_t)cmpname_size
);
924 * Parse a Directory Record into an hs_direntry structure.
925 * High Sierra and ISO directory are almost the same
926 * except the flag and date
932 struct hs_direntry
*hdp
,
935 int last_offset
) /* last offset in dirp */
943 int name_change_flag
= 0; /* set if name was gotten in SUA */
945 hdp
->ext_lbn
= HDE_EXT_LBN(dirp
);
946 hdp
->ext_size
= HDE_EXT_SIZE(dirp
);
947 hdp
->xar_len
= HDE_XAR_LEN(dirp
);
948 hdp
->intlf_sz
= HDE_INTRLV_SIZE(dirp
);
949 hdp
->intlf_sk
= HDE_INTRLV_SKIP(dirp
);
950 hdp
->sym_link
= NULL
;
952 if (fsp
->hsfs_vol_type
== HS_VOL_TYPE_HS
) {
953 flags
= HDE_FLAGS(dirp
);
954 hs_parse_dirdate(HDE_cdate(dirp
), &hdp
->cdate
);
955 hs_parse_dirdate(HDE_cdate(dirp
), &hdp
->adate
);
956 hs_parse_dirdate(HDE_cdate(dirp
), &hdp
->mdate
);
957 if ((flags
& hde_prohibited
) == 0) {
959 * Skip files with the associated bit set.
961 if (flags
& HDE_ASSOCIATED
)
966 } else if ((flags
& hde_prohibited
) == HDE_DIRECTORY
) {
971 hs_log_bogus_disk_warning(fsp
,
972 HSFS_ERR_UNSUP_TYPE
, flags
);
975 hdp
->uid
= fsp
-> hsfs_vol
.vol_uid
;
976 hdp
->gid
= fsp
-> hsfs_vol
.vol_gid
;
977 hdp
->mode
= hdp
-> mode
| (fsp
-> hsfs_vol
.vol_prot
& 0777);
978 } else if ((fsp
->hsfs_vol_type
== HS_VOL_TYPE_ISO
) ||
979 (fsp
->hsfs_vol_type
== HS_VOL_TYPE_ISO_V2
) ||
980 (fsp
->hsfs_vol_type
== HS_VOL_TYPE_JOLIET
)) {
982 flags
= IDE_FLAGS(dirp
);
983 hs_parse_dirdate(IDE_cdate(dirp
), &hdp
->cdate
);
984 hs_parse_dirdate(IDE_cdate(dirp
), &hdp
->adate
);
985 hs_parse_dirdate(IDE_cdate(dirp
), &hdp
->mdate
);
987 if ((flags
& ide_prohibited
) == 0) {
989 * Skip files with the associated bit set.
991 if (flags
& IDE_ASSOCIATED
)
996 } else if ((flags
& ide_prohibited
) == IDE_DIRECTORY
) {
1001 hs_log_bogus_disk_warning(fsp
,
1002 HSFS_ERR_UNSUP_TYPE
, flags
);
1005 hdp
->uid
= fsp
-> hsfs_vol
.vol_uid
;
1006 hdp
->gid
= fsp
-> hsfs_vol
.vol_gid
;
1007 hdp
->mode
= hdp
-> mode
| (fsp
-> hsfs_vol
.vol_prot
& 0777);
1008 hdp
->inode
= 0; /* initialize with 0, then check rrip */
1011 * Having this all filled in, let's see if we have any
1012 * SUA susp to look at.
1014 if (IS_SUSP_IMPLEMENTED(fsp
)) {
1015 error
= parse_sua((uchar_t
*)dnp
, dnlen
,
1016 &name_change_flag
, dirp
, last_offset
,
1019 if (hdp
->sym_link
) {
1020 kmem_free(hdp
->sym_link
,
1021 (size_t)(hdp
->ext_size
+ 1));
1022 hdp
->sym_link
= NULL
;
1028 hdp
->xar_prot
= (HDE_PROTECTION
& flags
) != 0;
1031 if (hdp
->xar_len
> 0) {
1032 cmn_err(CE_NOTE
, "hsfs: extended attributes not supported");
1037 /* check interleaf size and skip factor */
1038 /* must both be zero or non-zero */
1039 if (hdp
->intlf_sz
+ hdp
->intlf_sk
) {
1040 if ((hdp
->intlf_sz
== 0) || (hdp
->intlf_sk
== 0)) {
1042 "hsfs: interleaf size or skip factor error");
1045 if (hdp
->ext_size
== 0) {
1047 "hsfs: interleaving specified on zero length file");
1052 if (HDE_VOL_SET(dirp
) != 1) {
1053 if (fsp
->hsfs_vol
.vol_set_size
!= 1 &&
1054 fsp
->hsfs_vol
.vol_set_size
!= HDE_VOL_SET(dirp
)) {
1055 cmn_err(CE_NOTE
, "hsfs: multivolume file?");
1061 * If the name changed, then the NM field for RRIP was hit and
1062 * we should not copy the name again, just return.
1064 if (NAME_HAS_CHANGED(name_change_flag
))
1068 * Fall back to the ISO name. Note that as in process_dirblock,
1069 * the on-disk filename length must be validated against ISO
1070 * limits - which, in case of RR present but no RR name found,
1071 * are NOT identical to fsp->hsfs_namemax on this filesystem.
1073 on_disk_name
= (char *)HDE_name(dirp
);
1074 on_disk_namelen
= (int)HDE_NAME_LEN(dirp
);
1075 on_disk_dirlen
= (int)HDE_DIR_LEN(dirp
);
1077 if (on_disk_dirlen
< HDE_ROOT_DIR_REC_SIZE
||
1078 ((on_disk_dirlen
> last_offset
) ||
1079 ((HDE_FDESIZE
+ on_disk_namelen
) > on_disk_dirlen
))) {
1080 hs_log_bogus_disk_warning(fsp
,
1081 HSFS_ERR_BAD_DIR_ENTRY
, 0);
1085 if (on_disk_namelen
> fsp
->hsfs_namelen
&&
1086 hs_namelen(fsp
, on_disk_name
, on_disk_namelen
) >
1087 fsp
->hsfs_namelen
) {
1088 hs_log_bogus_disk_warning(fsp
,
1089 fsp
->hsfs_vol_type
== HS_VOL_TYPE_JOLIET
?
1090 HSFS_ERR_BAD_JOLIET_FILE_LEN
:
1091 HSFS_ERR_BAD_FILE_LEN
, 0);
1093 if (on_disk_namelen
> ISO_NAMELEN_V2_MAX
)
1094 on_disk_namelen
= fsp
->hsfs_namemax
; /* Paranoia */
1097 if (fsp
->hsfs_vol_type
== HS_VOL_TYPE_JOLIET
) {
1098 namelen
= hs_jnamecopy(on_disk_name
, dnp
,
1099 on_disk_namelen
, fsp
->hsfs_namemax
,
1102 * A negative return value means that the file name
1103 * has been truncated to fsp->hsfs_namemax.
1107 hs_log_bogus_disk_warning(fsp
,
1108 HSFS_ERR_TRUNC_JOLIET_FILE_LEN
, 0);
1112 * HS_VOL_TYPE_ISO && HS_VOL_TYPE_ISO_V2
1114 namelen
= hs_namecopy(on_disk_name
, dnp
,
1115 on_disk_namelen
, fsp
->hsfs_flags
);
1119 if ((fsp
->hsfs_flags
& HSFSMNT_NOTRAILDOT
) &&
1120 dnp
[ namelen
-1 ] == '.' && CAN_TRUNCATE_DOT(dnp
, namelen
))
1121 dnp
[ --namelen
] = '\0';
1123 namelen
= on_disk_namelen
;
1133 * Parse a file/directory name into UNIX form.
1134 * Delete trailing blanks, upper-to-lower case, add NULL terminator.
1135 * Returns the (possibly new) length.
1137 * Called from hsfs_readdir() via hs_parsedir()
1140 hs_namecopy(char *from
, char *to
, int size
, ulong_t flags
)
1149 /* special handling for '.' and '..' */
1151 if (*from
== '\0') {
1155 } else if (*from
== '\1') {
1163 maplc
= (flags
& HSFSMNT_NOMAPLCASE
) == 0;
1164 trailspace
= (flags
& HSFSMNT_NOTRAILSPACE
) == 0;
1165 version
= (flags
& HSFSMNT_NOVERSION
) == 0;
1166 for (i
= 0, lastspace
= -1; i
< size
; i
++) {
1168 if (c
== ';' && version
)
1170 if (c
<= ' ' && !trailspace
) {
1171 if (lastspace
== -1)
1175 if (maplc
&& (c
>= 'A') && (c
<= 'Z'))
1179 if (lastspace
!= -1)
1188 * This is the Joliet variant of hs_namecopy()
1190 * Parse a UCS-2 Joliet file/directory name into UNIX form.
1191 * Add NULL terminator.
1192 * Returns the new length.
1194 * Called from hsfs_readdir() via hs_parsedir()
1197 hs_jnamecopy(char *from
, char *to
, int size
, int maxsize
, ulong_t flags
)
1205 /* special handling for '.' and '..' */
1207 if (*from
== '\0') {
1211 } else if (*from
== '\1') {
1219 version
= (flags
& HSFSMNT_NOVERSION
) == 0;
1220 for (i
= 0, len
= 0; i
< size
; i
++) {
1221 c
= (from
[i
++] & 0xFF) << 8;
1222 c
|= from
[i
] & 0xFF;
1223 if (c
== ';' && version
)
1226 if (len
> (maxsize
-3)) {
1233 if ((len
+amt
) > maxsize
) {
1238 amt
= hs_ucs2_2_utf8(c
, (uint8_t *)&to
[len
]);
1240 hs_log_bogus_joliet_warning(); /* should never happen */
1250 * map a filename to upper case;
1251 * return 1 if found lowercase character
1253 * Called from process_dirblock()
1254 * via hsfs_lookup() -> hs_dirlook() -> process_dirblock()
1255 * to create an intermedia name from on disk file names for
1259 uppercase_cp(char *from
, char *to
, int size
)
1265 for (i
= 0; i
< size
; i
++) {
1267 if ((c
>= 'a') && (c
<= 'z')) {
1277 * This is the Joliet variant of uppercase_cp()
1279 * map a UCS-2 filename to UTF-8;
1282 * Called from process_dirblock()
1283 * via hsfs_lookup() -> hs_dirlook() -> process_dirblock()
1284 * to create an intermedia name from on disk file names for
1288 hs_joliet_cp(char *from
, char *to
, int size
)
1295 /* special handling for '\0' and '\1' */
1300 for (i
= 0; i
< size
; i
+= 2) {
1301 c
= (*from
++ & 0xFF) << 8;
1302 c
|= *from
++ & 0xFF;
1304 amt
= hs_ucs2_2_utf8(c
, (uint8_t *)to
);
1306 hs_log_bogus_joliet_warning(); /* should never happen */
1317 hs_log_bogus_joliet_warning(void)
1319 static int warned
= 0;
1324 cmn_err(CE_CONT
, "hsfs: Warning: "
1325 "file name contains bad UCS-2 chacarter\n");
1332 * Convert a UNIX-style name into its HSFS equivalent
1333 * replacing '.' and '..' with '\0' and '\1'.
1334 * Map to upper case.
1335 * Returns the (possibly new) length.
1337 * Called from hs_dirlook() and rrip_namecopy()
1338 * to create an intermediate name from the callers name from hsfs_lookup()
1339 * XXX Is the call from rrip_namecopy() OK?
1342 hs_uppercase_copy(char *from
, char *to
, int size
)
1347 /* special handling for '.' and '..' */
1349 if (size
== 1 && *from
== '.') {
1352 } else if (size
== 2 && *from
== '.' && *(from
+1) == '.') {
1357 for (i
= 0; i
< size
; i
++) {
1359 if ((c
>= 'a') && (c
<= 'z'))
1369 * This is the Joliet/ISO-9660:1999 variant of hs_uppercase_copy()
1371 * Convert a UTF-8 UNIX-style name into its UTF-8 Joliet/ISO equivalent
1372 * replacing '.' and '..' with '\0' and '\1'.
1373 * Returns the (possibly new) length.
1375 * Called from hs_dirlook()
1376 * to create an intermediate name from the callers name from hsfs_lookup()
1379 hs_iso_copy(char *from
, char *to
, int size
)
1384 /* special handling for '.' and '..' */
1386 if (size
== 1 && *from
== '.') {
1389 } else if (size
== 2 && *from
== '.' && *(from
+1) == '.') {
1394 for (i
= 0; i
< size
; i
++) {
1402 hs_filldirent(struct vnode
*vp
, struct hs_direntry
*hdp
)
1411 if (vp
->v_type
!= VDIR
) {
1412 cmn_err(CE_WARN
, "hsfs_filldirent: vp (0x%p) not a directory",
1417 fsp
= VFS_TO_HSFS(vp
->v_vfsp
);
1418 secno
= LBN_TO_SEC(hdp
->ext_lbn
+hdp
->xar_len
, vp
->v_vfsp
);
1419 secoff
= LBN_TO_BYTE(hdp
->ext_lbn
+hdp
->xar_len
, vp
->v_vfsp
) &
1421 secbp
= bread(fsp
->hsfs_devvp
->v_rdev
, secno
* 4, HS_SECTOR_SIZE
);
1422 error
= geterror(secbp
);
1424 cmn_err(CE_NOTE
, "hs_filldirent: bread: error=(%d)", error
);
1428 secp
= (uchar_t
*)secbp
->b_un
.b_addr
;
1431 if (hdp
->ext_lbn
!= HDE_EXT_LBN(&secp
[secoff
])) {
1432 cmn_err(CE_NOTE
, "hsfs_filldirent: dirent not match");
1435 (void) hs_parsedir(fsp
, &secp
[secoff
], hdp
, NULL
,
1436 NULL
, HS_SECTOR_SIZE
- secoff
);
1443 * Look through a directory block for a matching entry.
1444 * Note: this routine does an fbrelse() on the buffer passed in.
1446 static enum dirblock_result
1448 struct fbuf
*fbp
, /* buffer containing dirblk */
1449 uint_t
*offset
, /* lower index */
1450 uint_t last_offset
, /* upper index */
1451 char *nm
, /* upcase nm to compare against */
1452 int nmlen
, /* length of name */
1457 int *error
) /* return value: errno */
1459 uchar_t
*blkp
= (uchar_t
*)fbp
->fb_addr
; /* dir block */
1460 char *dname
; /* name in directory entry */
1461 int dnamelen
; /* length of name */
1462 struct hs_direntry hd
;
1464 uchar_t
*dirp
; /* the directory entry */
1468 size_t rrip_name_size
;
1470 char *rrip_name_str
= NULL
;
1471 char *rrip_tmp_name
= NULL
;
1472 enum dirblock_result err
= 0;
1473 int did_fbrelse
= 0;
1474 char uppercase_name
[JOLIET_NAMELEN_MAX
*3 + 1]; /* 331 */
1476 #define rel_offset(offset) \
1477 ((offset) & MAXBOFFSET) /* index into cur blk */
1478 #define RESTORE_NM(tmp, orig) \
1479 if (is_rrip && *(tmp) != '\0') \
1480 (void) strcpy((orig), (tmp))
1482 is_rrip
= IS_RRIP_IMPLEMENTED(fsp
);
1484 rrip_name_size
= RRIP_FILE_NAMELEN
+ 1;
1485 rrip_name_str
= kmem_alloc(rrip_name_size
, KM_SLEEP
);
1486 rrip_tmp_name
= kmem_alloc(rrip_name_size
, KM_SLEEP
);
1487 rrip_name_str
[0] = '\0';
1488 rrip_tmp_name
[0] = '\0';
1491 while (*offset
< last_offset
) {
1494 * Directory Entries cannot span sectors.
1496 * Unused bytes at the end of each sector are zeroed
1497 * according to ISO9660, but we cannot rely on this
1498 * since both media failures and maliciously corrupted
1499 * media may return arbitrary values.
1500 * We therefore have to check for consistency:
1501 * The size of a directory entry must be at least
1502 * 34 bytes (the size of the directory entry metadata),
1503 * or zero (indicating the end-of-sector condition).
1504 * For a non-zero directory entry size of less than
1505 * 34 Bytes, log a warning.
1506 * In any case, skip the rest of this sector and
1507 * continue with the next.
1509 hdlen
= (int)((uchar_t
)
1510 HDE_DIR_LEN(&blkp
[rel_offset(*offset
)]));
1512 if (hdlen
< HDE_ROOT_DIR_REC_SIZE
||
1513 *offset
+ hdlen
> last_offset
) {
1515 * Advance to the next sector boundary
1517 *offset
= roundup(*offset
+ 1, HS_SECTOR_SIZE
);
1519 hs_log_bogus_disk_warning(fsp
,
1520 HSFS_ERR_TRAILING_JUNK
, 0);
1524 bzero(&hd
, sizeof (hd
));
1527 * Check the filename length in the ISO record for
1528 * plausibility and reset it to a safe value, in case
1529 * the name length byte is out of range. Since the ISO
1530 * name will be used as fallback if the rockridge name
1531 * is invalid/nonexistant, we must make sure not to
1532 * blow the bounds and initialize dnamelen to a sensible
1533 * value within the limits of ISO9660.
1534 * In addition to that, the ISO filename is part of the
1535 * directory entry. If the filename length is too large
1536 * to fit, the record is invalid and we'll advance to
1539 dirp
= &blkp
[rel_offset(*offset
)];
1540 dname
= (char *)HDE_name(dirp
);
1541 dnamelen
= (int)((uchar_t
)HDE_NAME_LEN(dirp
));
1543 * If the directory entry extends beyond the end of the
1544 * block, it must be invalid. Skip it.
1546 if (dnamelen
> hdlen
- HDE_FDESIZE
) {
1547 hs_log_bogus_disk_warning(fsp
,
1548 HSFS_ERR_BAD_DIR_ENTRY
, 0);
1550 } else if (dnamelen
> fsp
->hsfs_namelen
&&
1551 hs_namelen(fsp
, dname
, dnamelen
) > fsp
->hsfs_namelen
) {
1552 hs_log_bogus_disk_warning(fsp
,
1553 fsp
->hsfs_vol_type
== HS_VOL_TYPE_JOLIET
?
1554 HSFS_ERR_BAD_JOLIET_FILE_LEN
:
1555 HSFS_ERR_BAD_FILE_LEN
, 0);
1557 if (dnamelen
> ISO_NAMELEN_V2_MAX
)
1558 dnamelen
= fsp
->hsfs_namemax
; /* Paranoia */
1561 * If the rock ridge is implemented, then we copy the name
1562 * from the SUA area to rrip_name_str. If no Alternate
1563 * name is found, then use the uppercase NM in the
1564 * rrip_name_str char array.
1568 rrip_name_str
[0] = '\0';
1569 rr_namelen
= rrip_namecopy(nm
, &rrip_name_str
[0],
1570 &rrip_tmp_name
[0], dirp
, last_offset
- *offset
,
1573 kmem_free(hd
.sym_link
,
1574 (size_t)(hd
.ext_size
+1));
1578 if (rr_namelen
!= -1) {
1579 dname
= (char *)&rrip_name_str
[0];
1580 dnamelen
= rr_namelen
;
1584 if (!is_rrip
|| rr_namelen
== -1) {
1585 /* use iso name instead */
1589 * make sure that we get rid of ';' in the dname of
1590 * an iso direntry, as we should have no knowledge
1593 * XXX This is done the wrong way: it does not take
1594 * XXX care of the fact that the version string is
1595 * XXX a decimal number in the range 1 to 32767.
1597 if ((fsp
->hsfs_flags
& HSFSMNT_NOVERSION
) == 0) {
1598 if (fsp
->hsfs_vol_type
== HS_VOL_TYPE_JOLIET
) {
1599 for (i
= dnamelen
- 1; i
> 0; i
-= 2) {
1600 if (dname
[i
] == ';' &&
1601 dname
[i
-1] == '\0') {
1607 for (i
= dnamelen
- 1; i
> 0; i
--) {
1608 if (dname
[i
] == ';')
1615 } else if (fsp
->hsfs_vol_type
!= HS_VOL_TYPE_ISO_V2
&&
1616 fsp
->hsfs_vol_type
!= HS_VOL_TYPE_JOLIET
) {
1617 dnamelen
= strip_trailing(fsp
, dname
, dnamelen
);
1620 ASSERT(dnamelen
< sizeof (uppercase_name
));
1622 if (fsp
->hsfs_vol_type
== HS_VOL_TYPE_ISO_V2
) {
1623 (void) strncpy(uppercase_name
, dname
, dnamelen
);
1624 } else if (fsp
->hsfs_vol_type
== HS_VOL_TYPE_JOLIET
) {
1625 dnamelen
= hs_joliet_cp(dname
, uppercase_name
,
1627 } else if (uppercase_cp(dname
, uppercase_name
,
1629 hs_log_bogus_disk_warning(fsp
,
1630 HSFS_ERR_LOWER_CASE_NM
, 0);
1632 dname
= uppercase_name
;
1634 (fsp
->hsfs_flags
& HSFSMNT_NOTRAILDOT
) &&
1635 dname
[dnamelen
- 1] == '.' &&
1636 CAN_TRUNCATE_DOT(dname
, dnamelen
))
1637 dname
[--dnamelen
] = '\0';
1641 * Quickly screen for a non-matching entry, but not for RRIP.
1642 * This test doesn't work for lowercase vs. uppercase names.
1645 /* if we saw a lower case name we can't do this test either */
1646 if (strict_iso9660_ordering
&& !is_rrip
&&
1647 !HSFS_HAVE_LOWER_CASE(fsp
) && *nm
< *dname
) {
1648 RESTORE_NM(rrip_tmp_name
, nm
);
1653 if (*nm
!= *dname
|| nmlen
!= dnamelen
)
1656 if ((res
= bcmp(dname
, nm
, nmlen
)) == 0) {
1658 parsedir_res
= hs_parsedir(fsp
, dirp
, &hd
, NULL
, NULL
,
1659 last_offset
- *offset
);
1660 if (!parsedir_res
) {
1661 uint_t lbn
; /* logical block number */
1663 lbn
= dhp
->hs_dirent
.ext_lbn
+
1664 dhp
->hs_dirent
.xar_len
;
1666 * Need to do an fbrelse() on the buffer,
1667 * as hs_makenode() may try to acquire
1668 * hs_hashlock, which may not be required
1669 * while a page is locked.
1671 fbrelse(fbp
, S_READ
);
1673 *vpp
= hs_makenode(&hd
, lbn
, *offset
,
1677 RESTORE_NM(rrip_tmp_name
, nm
);
1682 dhp
->hs_offset
= *offset
;
1683 RESTORE_NM(rrip_tmp_name
, nm
);
1686 } else if (parsedir_res
!= EAGAIN
) {
1687 /* improper dir entry */
1688 *error
= parsedir_res
;
1689 RESTORE_NM(rrip_tmp_name
, nm
);
1693 } else if (strict_iso9660_ordering
&& !is_rrip
&&
1694 !HSFS_HAVE_LOWER_CASE(fsp
) && res
< 0) {
1695 /* name < dir entry */
1696 RESTORE_NM(rrip_tmp_name
, nm
);
1706 RESTORE_NM(rrip_tmp_name
, nm
);
1711 kmem_free(rrip_name_str
, rrip_name_size
);
1713 kmem_free(rrip_tmp_name
, rrip_name_size
);
1715 fbrelse(fbp
, S_READ
);
1721 * Strip trailing nulls or spaces from the name;
1722 * return adjusted length. If we find such junk,
1723 * log a non-conformant disk message.
1726 strip_trailing(struct hsfs
*fsp
, char *nm
, int len
)
1729 int trailing_junk
= 0;
1731 for (c
= nm
+ len
- 1; c
> nm
; c
--) {
1732 if (*c
== ' ' || *c
== '\0')
1739 hs_log_bogus_disk_warning(fsp
, HSFS_ERR_TRAILING_JUNK
, 0);
1741 return ((int)(c
- nm
+ 1));
1745 hs_namelen(struct hsfs
*fsp
, char *nm
, int len
)
1749 if (fsp
->hsfs_vol_type
== HS_VOL_TYPE_ISO_V2
) {
1751 } else if (fsp
->hsfs_vol_type
== HS_VOL_TYPE_JOLIET
) {
1754 while (--p
> &nm
[1]) {
1759 if (c
< '0' || c
> '9') {
1771 if (c
< '0' || c
> '9') {
1781 * Take a UCS-2 character and convert
1782 * it into a utf8 character.
1783 * A 0 will be returned if the conversion fails
1785 * See http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
1787 * The code has been taken from udfs/udf_subr.c
1789 static uint8_t hs_first_byte_mark
[7] =
1790 { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
1792 hs_ucs2_2_utf8(uint16_t c_16
, uint8_t *s_8
)
1796 uint32_t byte_mask
= 0xBF;
1797 uint32_t byte_mark
= 0x80;
1800 * Convert the 16-bit character to a 32-bit character
1805 * By here the 16-bit character is converted
1806 * to a 32-bit wide character
1810 } else if (c_32
< 0x800) {
1812 } else if (c_32
< 0x10000) {
1814 } else if (c_32
< 0x200000) {
1816 } else if (c_32
< 0x4000000) {
1818 } else if (c_32
<= 0x7FFFFFFF) { /* avoid signed overflow */
1826 *(--s_8
) = (c_32
| byte_mark
) & byte_mask
;
1830 *(--s_8
) = (c_32
| byte_mark
) & byte_mask
;
1834 *(--s_8
) = (c_32
| byte_mark
) & byte_mask
;
1838 *(--s_8
) = (c_32
| byte_mark
) & byte_mask
;
1842 *(--s_8
) = (c_32
| byte_mark
) & byte_mask
;
1846 *(--s_8
) = c_32
| hs_first_byte_mark
[nc
];