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.
26 * Directory operations for High Sierra filesystem
29 #include <sys/types.h>
30 #include <sys/t_lock.h>
31 #include <sys/param.h>
32 #include <sys/systm.h>
37 #include <sys/vnode.h>
40 #include <sys/cmn_err.h>
43 #include <sys/policy.h>
44 #include <sys/sunddi.h>
49 #include <vm/seg_map.h>
50 #include <vm/seg_kmem.h>
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>
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>
67 * This macro expects a name that ends in '.' and returns TRUE if the
68 * name is not "." or ".."
70 #define CAN_TRUNCATE_DOT(name, namelen) \
71 (namelen > 1 && (namelen > 2 || name[0] != '.'))
73 enum dirblock_result
{ FOUND_ENTRY
, WENT_PAST
, HIT_END
};
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.
80 int ide_prohibited
= IDE_PROHIBITED
;
81 int hde_prohibited
= HDE_PROHIBITED
;
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.
87 static int hsfs_use_dnlc
= 1;
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.
99 * Use "set hsfs:strict_iso9660_ordering = 1" in /etc/system to override.
101 static int strict_iso9660_ordering
= 0;
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.
107 int use_rrip_inodes
= 1;
109 static void hs_hsnode_cache_reclaim(void *unused
);
110 static void hs_addfreeb(struct hsfs
*fsp
, struct hsnode
*hp
);
111 static 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
,
115 static int strip_trailing(struct hsfs
*fsp
, char *nm
, int len
);
116 static int hs_namelen(struct hsfs
*fsp
, char *nm
, int len
);
117 static int uppercase_cp(char *from
, char *to
, int size
);
118 static void hs_log_bogus_joliet_warning(void);
119 static int hs_iso_copy(char *from
, char *to
, int size
);
120 static int32_t hs_ucs2_2_utf8(uint16_t c_16
, uint8_t *s_8
);
121 static int hs_utf8_trunc(uint8_t *str
, int len
);
125 * Return 0 if the desired access may be granted.
126 * Otherwise return error code.
129 hs_access(struct vnode
*vp
, mode_t m
, struct cred
*cred
)
135 * Write access cannot be granted for a read-only medium
137 if ((m
& VWRITE
) && !IS_DEVVP(vp
))
143 * XXX - For now, use volume protections.
144 * Also, always grant EXEC access for directories
145 * if READ access is granted.
147 if ((vp
->v_type
== VDIR
) && (m
& VEXEC
)) {
152 if (crgetuid(cred
) != hp
->hs_dirent
.uid
) {
154 if (!groupmember((uid_t
)hp
->hs_dirent
.gid
, cred
))
157 return (secpolicy_vnode_access2(cred
, vp
, hp
->hs_dirent
.uid
,
158 hp
->hs_dirent
.mode
<< shift
, m
));
161 #if ((HS_HASHSIZE & (HS_HASHSIZE - 1)) == 0)
162 #define HS_HASH(l) ((uint_t)(l) & (HS_HASHSIZE - 1))
164 #define HS_HASH(l) ((uint_t)(l) % HS_HASHSIZE)
166 #define HS_HPASH(hp) HS_HASH((hp)->hs_nodeid)
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.
176 int nhsnode
= HS_HSNODESPACE
/ sizeof (struct hsnode
);
178 struct kmem_cache
*hsnode_cache
; /* free hsnode cache */
181 * Initialize the cache of free hsnodes.
184 hs_init_hsnode_cache(void)
187 * A kmem_cache is used for the hsnodes
188 * No constructor because hsnodes are initialised by bzeroing.
190 hsnode_cache
= kmem_cache_create("hsfs_hsnode_cache",
191 sizeof (struct hsnode
), 0, NULL
,
192 NULL
, hs_hsnode_cache_reclaim
, NULL
, NULL
, 0);
196 * Destroy the cache of free hsnodes.
199 hs_fini_hsnode_cache(void)
201 kmem_cache_destroy(hsnode_cache
);
205 * System is short on memory, free up as much as possible
209 hs_hsnode_cache_reclaim(void *unused
)
215 * For each vfs in the hs_mounttab list
217 mutex_enter(&hs_mounttab_lock
);
218 for (fsp
= hs_mounttab
; fsp
!= NULL
; fsp
= fsp
->hsfs_next
) {
220 * Purge the dnlc of all hsfs entries
222 (void) dnlc_purge_vfsp(fsp
->hsfs_vfs
, 0);
225 * For each entry in the free chain
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
) {
233 fsp
->hsfs_free_f
= hp
->hs_freef
;
234 if (fsp
->hsfs_free_f
!= NULL
) {
235 fsp
->hsfs_free_f
->hs_freeb
= NULL
;
237 fsp
->hsfs_free_b
= NULL
;
240 * Free the node. Force it to be fully freed
241 * by setting the 3rd arg (nopage) to 1.
243 hs_freenode(HTOV(hp
), fsp
, 1);
245 mutex_exit(&fsp
->hsfs_free_lock
);
246 rw_exit(&fsp
->hsfs_hash_lock
);
248 mutex_exit(&hs_mounttab_lock
);
252 * Add an hsnode to the end of the free list.
255 hs_addfreeb(struct hsfs
*fsp
, struct hsnode
*hp
)
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 */
264 hp
->hs_freeb
= ep
; /* point at previous last entry */
266 fsp
->hsfs_free_f
= hp
; /* hp is only entry in free list */
268 ep
->hs_freef
= hp
; /* point previous last entry at hp */
270 mutex_exit(&fsp
->hsfs_free_lock
);
274 * Get an hsnode from the front of the free list.
275 * Must be called with write hsfs_hash_lock held.
277 static struct hsnode
*
278 hs_getfree(struct hsfs
*fsp
)
280 struct hsnode
*hp
, **tp
;
282 ASSERT(RW_WRITE_HELD(&fsp
->hsfs_hash_lock
));
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
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
);
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
;
306 fsp
->hsfs_free_b
= NULL
;
307 mutex_exit(&fsp
->hsfs_free_lock
);
309 for (tp
= &fsp
->hsfs_hash
[HS_HPASH(hp
)]; *tp
!= NULL
;
310 tp
= &(*tp
)->hs_hash
) {
317 * file is no longer referenced, destroy all old pages
319 if (vn_has_cached_data(vp
))
321 * pvn_vplist_dirty will abort all old pages
323 (void) pvn_vplist_dirty(vp
, (u_offset_t
)0,
324 hsfs_putapage
, B_INVAL
,
325 (struct cred
*)NULL
);
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));
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
, (u_offset_t
)0,
465 hsfs_putapage
, B_INVAL
,
466 (struct cred
*)NULL
);
470 rw_exit(&fsp
->hsfs_hash_lock
);
474 /* now free the hsnodes */
475 for (i
= 0; i
< HS_HASHSIZE
; i
++) {
476 for (hp
= fsp
->hsfs_hash
[i
]; hp
!= NULL
; hp
= nhp
) {
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.
487 hs_freenode(vp
, fsp
, 1);
492 ASSERT(fsp
->hsfs_nohsnode
== 1);
493 rw_exit(&fsp
->hsfs_hash_lock
);
494 /* release the root hsnode, this should free the final hsnode */
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
511 struct hs_direntry
*dp
,
518 struct hs_volume
*hvp
;
523 fsp
= VFS_TO_HSFS(vfsp
);
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 ".")
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).
536 if (dp
->type
== VDIR
) {
542 * Normalize lbn and off before creating a nodeid
543 * and before storing them in a hs_node structure
545 hvp
= &fsp
->hsfs_vol
;
546 lbn
+= off
>> hvp
->lbn_shift
;
547 off
&= hvp
->lbn_maxoffset
;
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.
558 if (dp
->inode
!= 0 && use_rrip_inodes
) {
560 } else if ((dp
->ext_size
== 0 || dp
->sym_link
!= (char *)NULL
) &&
561 (fsp
->hsfs_flags
& HSFSMNT_INODE
) == 0) {
562 nodeid
= HS_DUMMY_INO
;
564 nodeid
= dp
->ext_lbn
;
567 /* look for hsnode in cache first */
569 rw_enter(&fsp
->hsfs_hash_lock
, RW_READER
);
571 if ((vp
= hs_findhash(nodeid
, lbn
, off
, vfsp
)) == NULL
) {
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.
578 rw_exit(&fsp
->hsfs_hash_lock
);
579 rw_enter(&fsp
->hsfs_hash_lock
, RW_WRITER
);
581 if ((vp
= hs_findhash(nodeid
, lbn
, off
, vfsp
)) == NULL
) {
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.
587 hp
= hs_getfree(fsp
);
589 bcopy((caddr_t
)dp
, (caddr_t
)&hp
->hs_dirent
,
592 * We've just copied this pointer into hs_dirent,
593 * and don't want 2 references to same symlink.
595 dp
->sym_link
= (char *)NULL
;
598 * No need to hold any lock because hsnode is not
599 * yet in the hash chain.
601 mutex_init(&hp
->hs_contents_lock
, NULL
, MUTEX_DEFAULT
,
603 hp
->hs_dir_lbn
= lbn
;
604 hp
->hs_dir_off
= off
;
605 hp
->hs_nodeid
= nodeid
;
607 hp
->hs_prev_offset
= 0;
608 hp
->hs_num_contig
= 0;
611 if (off
> HS_SECTOR_SIZE
)
612 cmn_err(CE_WARN
, "hs_makenode: bad offset");
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
;
622 * if it's a device, call specvp
625 rw_exit(&fsp
->hsfs_hash_lock
);
626 newvp
= specvp(vp
, vp
->v_rdev
, vp
->v_type
,
630 "hs_makenode: specvp failed");
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
;
645 rw_exit(&fsp
->hsfs_hash_lock
);
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.
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).
663 hs_freenode(vnode_t
*vp
, struct hsfs
*fsp
, int nopage
)
666 struct hsnode
*hp
= VTOH(vp
);
668 ASSERT(RW_LOCK_HELD(&fsp
->hsfs_hash_lock
));
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
) {
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
;
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??? */
693 mutex_destroy(&hp
->hs_contents_lock
);
696 kmem_cache_free(hsnode_cache
, hp
);
697 fsp
->hsfs_nohsnode
--;
700 hs_addfreeb(fsp
, hp
); /* add to back of free list */
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.
712 hs_remakenode(uint_t lbn
, uint_t off
, struct vfs
*vfsp
,
719 struct hs_direntry hd
;
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");
729 secno
= LBN_TO_SEC(lbn
, vfsp
);
730 secbp
= bread(fsp
->hsfs_devvp
->v_rdev
, secno
* 4, HS_SECTOR_SIZE
);
732 error
= geterror(secbp
);
734 cmn_err(CE_NOTE
, "hs_remakenode: bread: error=(%d)", error
);
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
);
742 *vpp
= hs_makenode(&hd
, lbn
, off
, vfsp
);
756 * Look for a given name in a given directory.
757 * If found, construct an hsnode for it.
763 int namlen
, /* length of 'name' */
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 */
775 int adhoc_search
; /* did we start at begin of dir? */
783 if (dvp
->v_type
!= VDIR
)
786 if (error
= hs_access(dvp
, (mode_t
)VEXEC
, cred
))
789 if (hsfs_use_dnlc
&& (*vpp
= dnlc_lookup(dvp
, name
)))
793 fsp
= VFS_TO_HSFS(dvp
->v_vfsp
);
794 is_rrip
= IS_RRIP_IMPLEMENTED(fsp
);
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.
802 if (!is_rrip
&& *name
== '\1' && namlen
== 1)
805 cmpname_size
= (int)(fsp
->hsfs_namemax
+ 1);
806 cmpname
= kmem_alloc((size_t)cmpname_size
, KM_SLEEP
);
808 if (namlen
>= cmpname_size
)
809 namlen
= cmpname_size
- 1;
811 * For the purposes of comparing the name against dir entries,
812 * fold it to upper case.
815 (void) strlcpy(cmpname
, name
, cmpname_size
);
819 * If we don't consider a trailing dot as part of the filename,
820 * remove it from the specified name
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
);
830 cmpnamelen
= hs_uppercase_copy(name
, cmpname
, namlen
);
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
);
839 * No lock is needed - hs_offset is used as starting
840 * point for searching the directory.
842 offset
= dhp
->hs_offset
;
844 adhoc_search
= (offset
!= 0);
846 end
= dhp
->hs_dirent
.ext_size
;
851 while (offset
< end
) {
852 bytes_wanted
= MIN(MAXBSIZE
, dirsiz
- (offset
& MAXBMASK
));
854 error
= fbread(dvp
, (offset_t
)(offset
& MAXBMASK
),
855 (unsigned int)bytes_wanted
, S_READ
, &fbp
);
859 last_offset
= (offset
& MAXBMASK
) + fbp
->fb_count
;
861 switch (process_dirblock(fbp
, &offset
, last_offset
,
862 cmpname
, cmpnamelen
, fsp
, dhp
, dvp
, vpp
, &error
)) {
864 /* found an entry, either correct or not */
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.
889 * End of all dir blocks, didn't find entry.
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
904 * That is ok since the CD-ROM is read-only, so (dvp,name) will
905 * always point to the same device.
907 if (hsfs_use_dnlc
&& !error
)
908 dnlc_enter(dvp
, name
, *vpp
);
910 kmem_free(cmpname
, (size_t)cmpname_size
);
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
926 struct hs_direntry
*hdp
,
929 int last_offset
) /* last offset in dirp */
937 int name_change_flag
= 0; /* set if name was gotten in SUA */
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
;
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) {
953 * Skip files with the associated bit set.
955 if (flags
& HDE_ASSOCIATED
)
960 } else if ((flags
& hde_prohibited
) == HDE_DIRECTORY
) {
965 hs_log_bogus_disk_warning(fsp
,
966 HSFS_ERR_UNSUP_TYPE
, flags
);
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
)) {
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
);
981 if ((flags
& ide_prohibited
) == 0) {
983 * Skip files with the associated bit set.
985 if (flags
& IDE_ASSOCIATED
)
990 } else if ((flags
& ide_prohibited
) == IDE_DIRECTORY
) {
995 hs_log_bogus_disk_warning(fsp
,
996 HSFS_ERR_UNSUP_TYPE
, flags
);
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 */
1005 * Having this all filled in, let's see if we have any
1006 * SUA susp to look at.
1008 if (IS_SUSP_IMPLEMENTED(fsp
)) {
1009 error
= parse_sua((uchar_t
*)dnp
, dnlen
,
1010 &name_change_flag
, dirp
, last_offset
,
1012 (uchar_t
*)NULL
, NULL
);
1014 if (hdp
->sym_link
) {
1015 kmem_free(hdp
->sym_link
,
1016 (size_t)(hdp
->ext_size
+ 1));
1017 hdp
->sym_link
= (char *)NULL
;
1023 hdp
->xar_prot
= (HDE_PROTECTION
& flags
) != 0;
1026 if (hdp
->xar_len
> 0) {
1027 cmn_err(CE_NOTE
, "hsfs: extended attributes not supported");
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)) {
1037 "hsfs: interleaf size or skip factor error");
1040 if (hdp
->ext_size
== 0) {
1042 "hsfs: interleaving specified on zero length file");
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?");
1056 * If the name changed, then the NM field for RRIP was hit and
1057 * we should not copy the name again, just return.
1059 if (NAME_HAS_CHANGED(name_change_flag
))
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.
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
);
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);
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);
1088 if (on_disk_namelen
> ISO_NAMELEN_V2_MAX
)
1089 on_disk_namelen
= fsp
->hsfs_namemax
; /* Paranoia */
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
,
1097 * A negative return value means that the file name
1098 * has been truncated to fsp->hsfs_namemax.
1102 hs_log_bogus_disk_warning(fsp
,
1103 HSFS_ERR_TRUNC_JOLIET_FILE_LEN
, 0);
1107 * HS_VOL_TYPE_ISO && HS_VOL_TYPE_ISO_V2
1109 namelen
= hs_namecopy(on_disk_name
, dnp
,
1110 on_disk_namelen
, fsp
->hsfs_flags
);
1114 if ((fsp
->hsfs_flags
& HSFSMNT_NOTRAILDOT
) &&
1115 dnp
[ namelen
-1 ] == '.' && CAN_TRUNCATE_DOT(dnp
, namelen
))
1116 dnp
[ --namelen
] = '\0';
1118 namelen
= on_disk_namelen
;
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.
1132 * Called from hsfs_readdir() via hs_parsedir()
1135 hs_namecopy(char *from
, char *to
, int size
, ulong_t flags
)
1144 /* special handling for '.' and '..' */
1146 if (*from
== '\0') {
1150 } else if (*from
== '\1') {
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
++) {
1163 if (c
== ';' && version
)
1165 if (c
<= ' ' && !trailspace
) {
1166 if (lastspace
== -1)
1170 if (maplc
&& (c
>= 'A') && (c
<= 'Z'))
1174 if (lastspace
!= -1)
1183 * This is the Joliet variant of hs_namecopy()
1185 * Parse a UCS-2 Joliet file/directory name into UNIX form.
1186 * Add NULL terminator.
1187 * Returns the new length.
1189 * Called from hsfs_readdir() via hs_parsedir()
1192 hs_jnamecopy(char *from
, char *to
, int size
, int maxsize
, ulong_t flags
)
1200 /* special handling for '.' and '..' */
1202 if (*from
== '\0') {
1206 } else if (*from
== '\1') {
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
)
1221 if (len
> (maxsize
-3)) {
1228 if ((len
+amt
) > maxsize
) {
1233 amt
= hs_ucs2_2_utf8(c
, (uint8_t *)&to
[len
]);
1235 hs_log_bogus_joliet_warning(); /* should never happen */
1245 * map a filename to upper case;
1246 * return 1 if found lowercase character
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
1254 uppercase_cp(char *from
, char *to
, int size
)
1260 for (i
= 0; i
< size
; i
++) {
1262 if ((c
>= 'a') && (c
<= 'z')) {
1272 * This is the Joliet variant of uppercase_cp()
1274 * map a UCS-2 filename to UTF-8;
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
1283 hs_joliet_cp(char *from
, char *to
, int size
)
1290 /* special handling for '\0' and '\1' */
1295 for (i
= 0; i
< size
; i
+= 2) {
1296 c
= (*from
++ & 0xFF) << 8;
1297 c
|= *from
++ & 0xFF;
1299 amt
= hs_ucs2_2_utf8(c
, (uint8_t *)to
);
1301 hs_log_bogus_joliet_warning(); /* should never happen */
1312 hs_log_bogus_joliet_warning(void)
1314 static int warned
= 0;
1319 cmn_err(CE_CONT
, "hsfs: Warning: "
1320 "file name contains bad UCS-2 chacarter\n");
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.
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?
1337 hs_uppercase_copy(char *from
, char *to
, int size
)
1342 /* special handling for '.' and '..' */
1344 if (size
== 1 && *from
== '.') {
1347 } else if (size
== 2 && *from
== '.' && *(from
+1) == '.') {
1352 for (i
= 0; i
< size
; i
++) {
1354 if ((c
>= 'a') && (c
<= 'z'))
1364 * This is the Joliet/ISO-9660:1999 variant of hs_uppercase_copy()
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.
1370 * Called from hs_dirlook()
1371 * to create an intermediate name from the callers name from hsfs_lookup()
1374 hs_iso_copy(char *from
, char *to
, int size
)
1379 /* special handling for '.' and '..' */
1381 if (size
== 1 && *from
== '.') {
1384 } else if (size
== 2 && *from
== '.' && *(from
+1) == '.') {
1389 for (i
= 0; i
< size
; i
++) {
1397 hs_filldirent(struct vnode
*vp
, struct hs_direntry
*hdp
)
1406 if (vp
->v_type
!= VDIR
) {
1407 cmn_err(CE_WARN
, "hsfs_filldirent: vp (0x%p) not a directory",
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
) &
1416 secbp
= bread(fsp
->hsfs_devvp
->v_rdev
, secno
* 4, HS_SECTOR_SIZE
);
1417 error
= geterror(secbp
);
1419 cmn_err(CE_NOTE
, "hs_filldirent: bread: error=(%d)", error
);
1423 secp
= (uchar_t
*)secbp
->b_un
.b_addr
;
1426 if (hdp
->ext_lbn
!= HDE_EXT_LBN(&secp
[secoff
])) {
1427 cmn_err(CE_NOTE
, "hsfs_filldirent: dirent not match");
1430 (void) hs_parsedir(fsp
, &secp
[secoff
], hdp
, (char *)NULL
,
1431 (int *)NULL
, HS_SECTOR_SIZE
- secoff
);
1438 * Look through a directory block for a matching entry.
1439 * Note: this routine does an fbrelse() on the buffer passed in.
1441 static enum dirblock_result
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 */
1452 int *error
) /* return value: errno */
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
;
1459 uchar_t
*dirp
; /* the directory entry */
1463 size_t rrip_name_size
;
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 */
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))
1479 is_rrip
= IS_RRIP_IMPLEMENTED(fsp
);
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';
1488 while (*offset
< last_offset
) {
1491 * Directory Entries cannot span sectors.
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.
1506 hdlen
= (int)((uchar_t
)
1507 HDE_DIR_LEN(&blkp
[rel_offset(*offset
)]));
1509 if (hdlen
< HDE_ROOT_DIR_REC_SIZE
||
1510 *offset
+ hdlen
> last_offset
) {
1512 * Advance to the next sector boundary
1514 *offset
= roundup(*offset
+ 1, HS_SECTOR_SIZE
);
1516 hs_log_bogus_disk_warning(fsp
,
1517 HSFS_ERR_TRAILING_JUNK
, 0);
1521 bzero(&hd
, sizeof (hd
));
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
1536 dirp
= &blkp
[rel_offset(*offset
)];
1537 dname
= (char *)HDE_name(dirp
);
1538 dnamelen
= (int)((uchar_t
)HDE_NAME_LEN(dirp
));
1540 * If the directory entry extends beyond the end of the
1541 * block, it must be invalid. Skip it.
1543 if (dnamelen
> hdlen
- HDE_FDESIZE
) {
1544 hs_log_bogus_disk_warning(fsp
,
1545 HSFS_ERR_BAD_DIR_ENTRY
, 0);
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);
1554 if (dnamelen
> ISO_NAMELEN_V2_MAX
)
1555 dnamelen
= fsp
->hsfs_namemax
; /* Paranoia */
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.
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
,
1570 kmem_free(hd
.sym_link
,
1571 (size_t)(hd
.ext_size
+1));
1572 hd
.sym_link
= (char *)NULL
;
1575 if (rr_namelen
!= -1) {
1576 dname
= (char *)&rrip_name_str
[0];
1577 dnamelen
= rr_namelen
;
1581 if (!is_rrip
|| rr_namelen
== -1) {
1582 /* use iso name instead */
1586 * make sure that we get rid of ';' in the dname of
1587 * an iso direntry, as we should have no knowledge
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.
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') {
1604 for (i
= dnamelen
- 1; i
> 0; i
--) {
1605 if (dname
[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
);
1617 ASSERT(dnamelen
< sizeof (uppercase_name
));
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
,
1624 } else if (uppercase_cp(dname
, uppercase_name
,
1626 hs_log_bogus_disk_warning(fsp
,
1627 HSFS_ERR_LOWER_CASE_NM
, 0);
1629 dname
= uppercase_name
;
1631 (fsp
->hsfs_flags
& HSFSMNT_NOTRAILDOT
) &&
1632 dname
[dnamelen
- 1] == '.' &&
1633 CAN_TRUNCATE_DOT(dname
, dnamelen
))
1634 dname
[--dnamelen
] = '\0';
1638 * Quickly screen for a non-matching entry, but not for RRIP.
1639 * This test doesn't work for lowercase vs. uppercase names.
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
)
1649 if (*nm
!= *dname
|| nmlen
!= dnamelen
)
1652 if ((res
= bcmp(dname
, nm
, nmlen
)) == 0) {
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 */
1660 lbn
= dhp
->hs_dirent
.ext_lbn
+
1661 dhp
->hs_dirent
.xar_len
;
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.
1668 fbrelse(fbp
, S_READ
);
1670 *vpp
= hs_makenode(&hd
, lbn
, *offset
,
1674 RESTORE_NM(rrip_tmp_name
, nm
);
1675 PD_return(FOUND_ENTRY
)
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
)
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
)
1699 RESTORE_NM(rrip_tmp_name
, nm
);
1705 kmem_free(rrip_name_str
, rrip_name_size
);
1707 kmem_free(rrip_tmp_name
, rrip_name_size
);
1709 fbrelse(fbp
, S_READ
);
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.
1721 strip_trailing(struct hsfs
*fsp
, char *nm
, int len
)
1724 int trailing_junk
= 0;
1726 for (c
= nm
+ len
- 1; c
> nm
; c
--) {
1727 if (*c
== ' ' || *c
== '\0')
1734 hs_log_bogus_disk_warning(fsp
, HSFS_ERR_TRAILING_JUNK
, 0);
1736 return ((int)(c
- nm
+ 1));
1740 hs_namelen(struct hsfs
*fsp
, char *nm
, int len
)
1744 if (fsp
->hsfs_vol_type
== HS_VOL_TYPE_ISO_V2
) {
1746 } else if (fsp
->hsfs_vol_type
== HS_VOL_TYPE_JOLIET
) {
1749 while (--p
> &nm
[1]) {
1754 if (c
< '0' || c
> '9') {
1766 if (c
< '0' || c
> '9') {
1776 * Take a UCS-2 character and convert
1777 * it into a utf8 character.
1778 * A 0 will be returned if the conversion fails
1780 * See http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
1782 * The code has been taken from udfs/udf_subr.c
1784 static uint8_t hs_first_byte_mark
[7] =
1785 { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
1787 hs_ucs2_2_utf8(uint16_t c_16
, uint8_t *s_8
)
1791 uint32_t byte_mask
= 0xBF;
1792 uint32_t byte_mark
= 0x80;
1795 * Convert the 16-bit character to a 32-bit character
1800 * By here the 16-bit character is converted
1801 * to a 32-bit wide character
1805 } else if (c_32
< 0x800) {
1807 } else if (c_32
< 0x10000) {
1809 } else if (c_32
< 0x200000) {
1811 } else if (c_32
< 0x4000000) {
1813 } else if (c_32
<= 0x7FFFFFFF) { /* avoid signed overflow */
1821 *(--s_8
) = (c_32
| byte_mark
) & byte_mask
;
1825 *(--s_8
) = (c_32
| byte_mark
) & byte_mask
;
1829 *(--s_8
) = (c_32
| byte_mark
) & byte_mask
;
1833 *(--s_8
) = (c_32
| byte_mark
) & byte_mask
;
1837 *(--s_8
) = (c_32
| byte_mark
) & byte_mask
;
1841 *(--s_8
) = c_32
| hs_first_byte_mark
[nc
];