Mercurial > illumos > illumos-gate
changeset 2900:8188e64c9073
PSARC 2006/509 HSFS extensions for Joliet/ISO9660:v2
4065963 RFE: Joliet Extension to ISO 9660 cdrom support
6321916 Request for supporting full-length (207 characters) ISO9660-1999 filenames
author | frankho |
---|---|
date | Wed, 11 Oct 2006 07:48:51 -0700 |
parents | 886fb919e004 |
children | 9d09da16c373 |
files | usr/src/uts/common/fs/hsfs/hsfs_node.c usr/src/uts/common/fs/hsfs/hsfs_subr.c usr/src/uts/common/fs/hsfs/hsfs_susp_subr.c usr/src/uts/common/fs/hsfs/hsfs_vfsops.c usr/src/uts/common/fs/hsfs/hsfs_vnops.c usr/src/uts/common/sys/fs/hsfs_impl.h usr/src/uts/common/sys/fs/hsfs_isospec.h usr/src/uts/common/sys/fs/hsfs_node.h usr/src/uts/common/sys/fs/hsfs_rrip.h |
diffstat | 9 files changed, 938 insertions(+), 174 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/uts/common/fs/hsfs/hsfs_node.c Wed Oct 11 06:38:28 2006 -0700 +++ b/usr/src/uts/common/fs/hsfs/hsfs_node.c Wed Oct 11 07:48:51 2006 -0700 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -106,13 +105,17 @@ static void hs_hsnode_cache_reclaim(void *unused); static void hs_addfreeb(struct hsfs *fsp, struct hsnode *hp); -static int nmcmp(char *a, char *b, int len, int is_rrip); static enum dirblock_result process_dirblock(struct fbuf *fbp, uint_t *offset, uint_t last_offset, char *nm, int nmlen, struct hsfs *fsp, struct hsnode *dhp, struct vnode *dvp, struct vnode **vpp, - int *error, int is_rrip); + int *error); static int strip_trailing(struct hsfs *fsp, char *nm, int len); +static int hs_namelen(struct hsfs *fsp, char *nm, int len); static int uppercase_cp(char *from, char *to, int size); +static void hs_log_bogus_joliet_warning(void); +static int hs_iso_copy(char *from, char *to, int size); +static int32_t hs_ucs2_2_utf8(uint16_t c_16, uint8_t *s_8); +static int hs_utf8_trunc(uint8_t *str, int len); /* * hs_access @@ -189,6 +192,15 @@ } /* + * Destroy the cache of free hsnodes. + */ +void +hs_fini_hsnode_cache(void) +{ + kmem_cache_destroy(hsnode_cache); +} + +/* * System is short on memory, free up as much as possible */ /*ARGSUSED*/ @@ -678,7 +690,8 @@ } dirp = (uchar_t *)secbp->b_un.b_addr; - error = hs_parsedir(fsp, &dirp[off], &hd, (char *)NULL, (int *)NULL); + error = hs_parsedir(fsp, &dirp[off], &hd, (char *)NULL, (int *)NULL, + HS_SECTOR_SIZE - off); if (!error) { *vpp = hs_makenode(&hd, lbn, off, vfsp); if (*vpp == NULL) @@ -732,12 +745,20 @@ dhp = VTOH(dvp); fsp = VFS_TO_HSFS(dvp->v_vfsp); + is_rrip = IS_RRIP_IMPLEMENTED(fsp); + + /* + * name == "^A" is illegal for ISO-9660 and Joliet as '..' is '\1' on + * disk. It is no problem for Rock Ridge as RR uses '.' and '..'. + * XXX It could be OK for Joliet also (because namelen == 1 is + * XXX impossible for UCS-2) but then we need a better compare algorith. + */ + if (!is_rrip && *name == '\1' && namlen == 1) + return (EINVAL); cmpname_size = (int)(fsp->hsfs_namemax + 1); cmpname = kmem_alloc((size_t)cmpname_size, KM_SLEEP); - is_rrip = IS_RRIP_IMPLEMENTED(fsp); - if (namlen >= cmpname_size) namlen = cmpname_size - 1; /* @@ -756,7 +777,12 @@ name[namlen-1] == '.' && CAN_TRUNCATE_DOT(name, namlen)) name[--namlen] = '\0'; - cmpnamelen = hs_uppercase_copy(name, cmpname, namlen); + if (fsp->hsfs_vol_type == HS_VOL_TYPE_ISO_V2 || + fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET) { + cmpnamelen = hs_iso_copy(name, cmpname, namlen); + } else { + cmpnamelen = hs_uppercase_copy(name, cmpname, namlen); + } } /* make sure dirent is filled up with all info */ @@ -787,8 +813,7 @@ last_offset = (offset & MAXBMASK) + fbp->fb_count; switch (process_dirblock(fbp, &offset, last_offset, - cmpname, cmpnamelen, fsp, dhp, dvp, vpp, &error, - is_rrip)) { + cmpname, cmpnamelen, fsp, dhp, dvp, vpp, &error)) { case FOUND_ENTRY: /* found an entry, either correct or not */ goto done; @@ -854,10 +879,12 @@ uchar_t *dirp, struct hs_direntry *hdp, char *dnp, - int *dnlen) + int *dnlen, + int last_offset) { char *on_disk_name; int on_disk_namelen; + int on_disk_dirlen; uchar_t flags; int namelen; int error; @@ -896,7 +923,10 @@ hdp->uid = fsp -> hsfs_vol.vol_uid; hdp->gid = fsp -> hsfs_vol.vol_gid; hdp->mode = hdp-> mode | (fsp -> hsfs_vol.vol_prot & 0777); - } else if (fsp->hsfs_vol_type == HS_VOL_TYPE_ISO) { + } else if ((fsp->hsfs_vol_type == HS_VOL_TYPE_ISO) || + (fsp->hsfs_vol_type == HS_VOL_TYPE_ISO_V2) || + (fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET)) { + flags = IDE_FLAGS(dirp); hs_parse_dirdate(IDE_cdate(dirp), &hdp->cdate); hs_parse_dirdate(IDE_cdate(dirp), &hdp->adate); @@ -989,14 +1019,54 @@ */ on_disk_name = (char *)HDE_name(dirp); on_disk_namelen = (int)HDE_NAME_LEN(dirp); + on_disk_dirlen = (int)HDE_DIR_LEN(dirp); - if (on_disk_namelen > ISO_FILE_NAMELEN) { - hs_log_bogus_disk_warning(fsp, HSFS_ERR_BAD_FILE_LEN, 0); - on_disk_namelen = ISO_FILE_NAMELEN; + if (on_disk_dirlen < HDE_ROOT_DIR_REC_SIZE || + ((on_disk_dirlen > last_offset) || + ((HDE_FDESIZE + on_disk_namelen) > on_disk_dirlen))) { + hs_log_bogus_disk_warning(fsp, + HSFS_ERR_BAD_DIR_ENTRY, 0); + return (EINVAL); + } + + if (on_disk_namelen > fsp->hsfs_namelen && + hs_namelen(fsp, on_disk_name, on_disk_namelen) > + fsp->hsfs_namelen) { + hs_log_bogus_disk_warning(fsp, + fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET ? + HSFS_ERR_BAD_JOLIET_FILE_LEN : + HSFS_ERR_BAD_FILE_LEN, + 0); } + if (on_disk_namelen > ISO_NAMELEN_V2_MAX) + on_disk_namelen = fsp->hsfs_namemax; /* Paranoia */ + if (dnp != NULL) { - namelen = hs_namecopy(on_disk_name, dnp, on_disk_namelen, - fsp->hsfs_flags); + if (fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET) { + namelen = hs_jnamecopy(on_disk_name, dnp, + on_disk_namelen, + fsp->hsfs_namemax, + fsp->hsfs_flags); + /* + * A negative return value means that the file name + * has been truncated to fsp->hsfs_namemax. + */ + if (namelen < 0) { + namelen = -namelen; + hs_log_bogus_disk_warning(fsp, + HSFS_ERR_TRUNC_JOLIET_FILE_LEN, + 0); + } + } else { + /* + * HS_VOL_TYPE_ISO && HS_VOL_TYPE_ISO_V2 + */ + namelen = hs_namecopy(on_disk_name, dnp, + on_disk_namelen, + fsp->hsfs_flags); + } + if (namelen == 0) + return (EINVAL); if ((fsp->hsfs_flags & HSFSMNT_NOTRAILDOT) && dnp[ namelen-1 ] == '.' && CAN_TRUNCATE_DOT(dnp, namelen)) dnp[ --namelen ] = '\0'; @@ -1014,6 +1084,8 @@ * Parse a file/directory name into UNIX form. * Delete trailing blanks, upper-to-lower case, add NULL terminator. * Returns the (possibly new) length. + * + * Called from hsfs_readdir() via hs_parsedir() */ int hs_namecopy(char *from, char *to, int size, ulong_t flags) @@ -1022,6 +1094,8 @@ uchar_t c; int lastspace; int maplc; + int trailspace; + int version; /* special handling for '.' and '..' */ if (size == 1) { @@ -1038,11 +1112,13 @@ } maplc = (flags & HSFSMNT_NOMAPLCASE) == 0; + trailspace = (flags & HSFSMNT_NOTRAILSPACE) == 0; + version = (flags & HSFSMNT_NOVERSION) == 0; for (i = 0, lastspace = -1; i < size; i++) { c = from[i]; - if (c == ';') + if (c == ';' && version) break; - if (c <= ' ') { + if (c <= ' ' && !trailspace) { if (lastspace == -1) lastspace = i; } else @@ -1058,8 +1134,77 @@ } /* + * hs_jnamecopy + * + * This is the Joliet variant of hs_namecopy() + * + * Parse a UCS-2 Joliet file/directory name into UNIX form. + * Add NULL terminator. + * Returns the new length. + * + * Called from hsfs_readdir() via hs_parsedir() + */ +int +hs_jnamecopy(char *from, char *to, int size, int maxsize, ulong_t flags) +{ + uint_t i; + uint_t len; + uint16_t c; + int amt; + int version; + + /* special handling for '.' and '..' */ + if (size == 1) { + if (*from == '\0') { + *to++ = '.'; + *to = '\0'; + return (1); + } else if (*from == '\1') { + *to++ = '.'; + *to++ = '.'; + *to = '\0'; + return (2); + } + } + + version = (flags & HSFSMNT_NOVERSION) == 0; + for (i = 0, len = 0; i < size; i++) { + c = (from[i++] & 0xFF) << 8; + c |= from[i] & 0xFF; + if (c == ';' && version) + break; + + if (len > (maxsize-3)) { + if (c < 0x80) + amt = 1; + else if (c < 0x800) + amt = 2; + else + amt = 3; + if ((len+amt) > maxsize) { + to[len] = '\0'; + return (-len); + } + } + amt = hs_ucs2_2_utf8(c, (uint8_t *)&to[len]); + if (amt == 0) { + hs_log_bogus_joliet_warning(); /* should never happen */ + return (0); + } + len += amt; + } + to[len] = '\0'; + return (len); +} + +/* * map a filename to upper case; * return 1 if found lowercase character + * + * Called from process_dirblock() + * via hsfs_lookup() -> hs_dirlook() -> process_dirblock() + * to create an intermedia name from on disk file names for + * comparing names. */ static int uppercase_cp(char *from, char *to, int size) @@ -1080,11 +1225,69 @@ } /* + * This is the Joliet variant of uppercase_cp() + * + * map a UCS-2 filename to UTF-8; + * return new length + * + * Called from process_dirblock() + * via hsfs_lookup() -> hs_dirlook() -> process_dirblock() + * to create an intermedia name from on disk file names for + * comparing names. + */ +int +hs_joliet_cp(char *from, char *to, int size) +{ + uint_t i; + uint16_t c; + int len = 0; + int amt; + + /* special handling for '\0' and '\1' */ + if (size == 1) { + *to = *from; + return (1); + } + for (i = 0; i < size; i += 2) { + c = (*from++ & 0xFF) << 8; + c |= *from++ & 0xFF; + + amt = hs_ucs2_2_utf8(c, (uint8_t *)to); + if (amt == 0) { + hs_log_bogus_joliet_warning(); /* should never happen */ + return (0); + } + + to += amt; + len += amt; + } + return (len); +} + +static void +hs_log_bogus_joliet_warning(void) +{ + static int warned = 0; + + if (warned) + return; + warned = 1; + cmn_err(CE_CONT, "hsfs: Warning: " + "file name contains bad UCS-2 chacarter\n"); +} + + +/* * hs_uppercase_copy * - * Convert a UNIX-style name into its HSFS equivalent. + * Convert a UNIX-style name into its HSFS equivalent + * replacing '.' and '..' with '\0' and '\1'. * Map to upper case. * Returns the (possibly new) length. + * + * Called from hs_dirlook() and rrip_namecopy() + * to create an intermediate name from the callers name from hsfs_lookup() + * XXX Is the call from rrip_namecopy() OK? */ int hs_uppercase_copy(char *from, char *to, int size) @@ -1111,6 +1314,41 @@ return (size); } +/* + * hs_iso_copy + * + * This is the Joliet/ISO-9660:1999 variant of hs_uppercase_copy() + * + * Convert a UTF-8 UNIX-style name into its UTF-8 Joliet/ISO equivalent + * replacing '.' and '..' with '\0' and '\1'. + * Returns the (possibly new) length. + * + * Called from hs_dirlook() + * to create an intermediate name from the callers name from hsfs_lookup() + */ +static int +hs_iso_copy(char *from, char *to, int size) +{ + uint_t i; + uchar_t c; + + /* special handling for '.' and '..' */ + + if (size == 1 && *from == '.') { + *to = '\0'; + return (1); + } else if (size == 2 && *from == '.' && *(from+1) == '.') { + *to = '\1'; + return (1); + } + + for (i = 0; i < size; i++) { + c = *from++; + *to++ = c; + } + return (size); +} + void hs_filldirent(struct vnode *vp, struct hs_direntry *hdp) { @@ -1145,7 +1383,8 @@ cmn_err(CE_NOTE, "hsfs_filldirent: dirent not match"); /* keep on going */ } - (void) hs_parsedir(fsp, &secp[secoff], hdp, (char *)NULL, (int *)NULL); + (void) hs_parsedir(fsp, &secp[secoff], hdp, (char *)NULL, + (int *)NULL, HS_SECTOR_SIZE - secoff); end: brelse(secbp); @@ -1166,8 +1405,7 @@ struct hsnode *dhp, struct vnode *dvp, struct vnode **vpp, - int *error, /* return value: errno */ - int is_rrip) /* 1 if rock ridge is implemented */ + int *error) /* return value: errno */ { uchar_t *blkp = (uchar_t *)fbp->fb_addr; /* dir block */ char *dname; /* name in directory entry */ @@ -1177,19 +1415,24 @@ uchar_t *dirp; /* the directory entry */ int res; int parsedir_res; + int is_rrip; size_t rrip_name_size; int rr_namelen = 0; char *rrip_name_str = NULL; char *rrip_tmp_name = NULL; enum dirblock_result err = 0; int did_fbrelse = 0; - char uppercase_name[ISO_FILE_NAMELEN]; + char uppercase_name[JOLIET_NAMELEN_MAX*3 + 1]; /* 331 */ #define PD_return(retval) \ { err = retval; goto do_ret; } /* return after cleanup */ #define rel_offset(offset) \ ((offset) & MAXBOFFSET) /* index into cur blk */ +#define RESTORE_NM(tmp, orig) \ + if (is_rrip && *(tmp) != '\0') \ + (void) strcpy((orig), (tmp)) + is_rrip = IS_RRIP_IMPLEMENTED(fsp); if (is_rrip) { rrip_name_size = RRIP_FILE_NAMELEN + 1; rrip_name_str = kmem_alloc(rrip_name_size, KM_SLEEP); @@ -1249,15 +1492,24 @@ dirp = &blkp[rel_offset(*offset)]; dname = (char *)HDE_name(dirp); dnamelen = (int)((uchar_t)HDE_NAME_LEN(dirp)); + /* + * If the directory entry extends beyond the end of the + * block, it must be invalid. Skip it. + */ if (dnamelen > hdlen - HDE_FDESIZE) { hs_log_bogus_disk_warning(fsp, - HSFS_ERR_BAD_FILE_LEN, 0); + HSFS_ERR_BAD_DIR_ENTRY, 0); goto skip_rec; - } else if (dnamelen > ISO_FILE_NAMELEN) { + } else if (dnamelen > fsp->hsfs_namelen && + hs_namelen(fsp, dname, dnamelen) > fsp->hsfs_namelen) { hs_log_bogus_disk_warning(fsp, - HSFS_ERR_BAD_FILE_LEN, 0); - dnamelen = ISO_FILE_NAMELEN; + fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET ? + HSFS_ERR_BAD_JOLIET_FILE_LEN : + HSFS_ERR_BAD_FILE_LEN, + 0); } + if (dnamelen > ISO_NAMELEN_V2_MAX) + dnamelen = fsp->hsfs_namemax; /* Paranoia */ /* * If the rock ridge is implemented, then we copy the name @@ -1285,28 +1537,51 @@ if (!is_rrip || rr_namelen == -1) { /* use iso name instead */ - int i; + int i = -1; /* * make sure that we get rid of ';' in the dname of * an iso direntry, as we should have no knowledge * of file versions. + * + * XXX This is done the wrong way: it does not take + * XXX care of the fact that the version string is + * XXX a decimal number in the range 1 to 32767. */ - - for (i = dnamelen - 1; - (dname[i] != ';') && (i > 0); - i--) - continue; + if ((fsp->hsfs_flags & HSFSMNT_NOVERSION) == 0) { + if (fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET) { + for (i = dnamelen - 1; i > 0; i -= 2) { + if (dname[i] == ';' && + dname[i-1] == '\0') { + --i; + break; + } + } + } else { + for (i = dnamelen - 1; i > 0; i--) { + if (dname[i] == ';') + break; + } + } + } + if (i > 0) { + dnamelen = i; + } else if (fsp->hsfs_vol_type != HS_VOL_TYPE_ISO_V2 && + fsp->hsfs_vol_type != HS_VOL_TYPE_JOLIET) { + dnamelen = strip_trailing(fsp, dname, dnamelen); + } - if (dname[i] == ';') - dnamelen = i; - else - dnamelen = strip_trailing(fsp, dname, dnamelen); + ASSERT(dnamelen < sizeof (uppercase_name)); - ASSERT(dnamelen <= ISO_FILE_NAMELEN); - - if (uppercase_cp(dname, uppercase_name, dnamelen)) + if (fsp->hsfs_vol_type == HS_VOL_TYPE_ISO_V2) { + (void) strncpy(uppercase_name, dname, dnamelen); + } else if (fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET) { + dnamelen = hs_joliet_cp(dname, uppercase_name, + dnamelen); + } else if (uppercase_cp(dname, uppercase_name, + dnamelen)) { hs_log_bogus_disk_warning(fsp, HSFS_ERR_LOWER_CASE_NM, 0); + } dname = uppercase_name; if (!is_rrip && (fsp->hsfs_flags & HSFSMNT_NOTRAILDOT) && @@ -1330,10 +1605,11 @@ if (*nm != *dname || nmlen != dnamelen) goto skip_rec; - if ((res = nmcmp(dname, nm, nmlen, is_rrip)) == 0) { + if ((res = bcmp(dname, nm, nmlen)) == 0) { /* name matches */ parsedir_res = hs_parsedir(fsp, dirp, &hd, - (char *)NULL, (int *)NULL); + (char *)NULL, (int *)NULL, + last_offset - rel_offset(*offset)); if (!parsedir_res) { uint_t lbn; /* logical block number */ @@ -1389,27 +1665,7 @@ fbrelse(fbp, S_READ); return (err); #undef PD_return -} - - -/* - * Compare the names, returning < 0 if a < b, - * 0 if a == b, and > 0 if a > b. - */ -static int -nmcmp(char *a, char *b, int len, int is_rrip) -{ - while (len--) { - if (*a == *b) { - b++; a++; - } else { - /* if file version, stop */ - if (! is_rrip && ((*a == ';') && (*b == '\0'))) - return (0); - return ((uchar_t)*b - (uchar_t)*a); - } - } - return (0); +#undef RESTORE_NM } /* @@ -1435,3 +1691,110 @@ return ((int)(c - nm + 1)); } + +static int +hs_namelen(struct hsfs *fsp, char *nm, int len) +{ + char *p = nm + len; + + if (fsp->hsfs_vol_type == HS_VOL_TYPE_ISO_V2) { + return (len); + } else if (fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET) { + uint16_t c; + + while (--p > &nm[1]) { + c = *p; + c |= *--p * 256; + if (c == ';') + return (p - nm); + if (c < '0' || c > '9') { + p++; + return (p - nm); + } + } + } else { + char c; + + while (--p > nm) { + c = *p; + if (c == ';') + return (p - nm); + if (c < '0' || c > '9') { + p++; + return (p - nm); + } + } + } + return (len); +} + +/* + * Take a UCS-2 character and convert + * it into a utf8 character. + * A 0 will be returned if the conversion fails + * + * See http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + * + * The code has been taken from udfs/udf_subr.c + */ +static uint8_t hs_first_byte_mark[7] = + { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; +static int32_t +hs_ucs2_2_utf8(uint16_t c_16, uint8_t *s_8) +{ + int32_t nc; + uint32_t c_32; + uint32_t byte_mask = 0xBF; + uint32_t byte_mark = 0x80; + + /* + * Convert the 16-bit character to a 32-bit character + */ + c_32 = c_16; + + /* + * By here the 16-bit character is converted + * to a 32-bit wide character + */ + if (c_32 < 0x80) { + nc = 1; + } else if (c_32 < 0x800) { + nc = 2; + } else if (c_32 < 0x10000) { + nc = 3; + } else if (c_32 < 0x200000) { + nc = 4; + } else if (c_32 < 0x4000000) { + nc = 5; + } else if (c_32 <= 0x7FFFFFFF) { /* avoid signed overflow */ + nc = 6; + } else { + nc = 0; + } + s_8 += nc; + switch (nc) { + case 6 : + *(--s_8) = (c_32 | byte_mark) & byte_mask; + c_32 >>= 6; + /* FALLTHROUGH */ + case 5 : + *(--s_8) = (c_32 | byte_mark) & byte_mask; + c_32 >>= 6; + /* FALLTHROUGH */ + case 4 : + *(--s_8) = (c_32 | byte_mark) & byte_mask; + c_32 >>= 6; + /* FALLTHROUGH */ + case 3 : + *(--s_8) = (c_32 | byte_mark) & byte_mask; + c_32 >>= 6; + /* FALLTHROUGH */ + case 2 : + *(--s_8) = (c_32 | byte_mark) & byte_mask; + c_32 >>= 6; + /* FALLTHROUGH */ + case 1 : + *(--s_8) = c_32 | hs_first_byte_mark[nc]; + } + return (nc); +}
--- a/usr/src/uts/common/fs/hsfs/hsfs_subr.c Wed Oct 11 06:38:28 2006 -0700 +++ b/usr/src/uts/common/fs/hsfs/hsfs_subr.c Wed Oct 11 07:48:51 2006 -0700 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -22,8 +21,8 @@ /* * Miscellaneous support subroutines for High Sierra filesystem * - * Copyright (c) 1990,2000,2001 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -77,29 +76,44 @@ uchar_t n_printf_args; /* if err_text printf-like, # addtl args */ } hsfs_error[] = { /* HSFS_ERR_TRAILING_JUNK */ - "hsfs: Warning: the file system mounted on %s\n" + "hsfs: Warning: the file system mounted on %s " "does not conform to the ISO-9660 specification:", - " trailing blanks or null characters in file or directory name.\n", + "trailing blanks or null characters in file or directory name.\n", 1, 0, /* HSFS_ERR_LOWER_CASE_NM */ - "hsfs: Warning: the file system mounted on %s\n" - "does not conform to the ISO-9660 specification: ", - " lower case characters in file or directory name.\n", + "hsfs: Warning: the file system mounted on %s " + "does not conform to the ISO-9660 specification:", + "lower case characters in file or directory name.\n", 1, 0, /* HSFS_ERR_BAD_ROOT_DIR */ - "hsfs: Warning: the file system mounted on %s\n" + "hsfs: Warning: the file system mounted on %s " "does not conform to the ISO-9660 specification:", - " invalid root directory.\n", + "invalid root directory.\n", 0, 0, /* HSFS_ERR_UNSUP_TYPE */ - "hsfs: Warning: the file system mounted on %s\n" + "hsfs: Warning: the file system mounted on %s " "contains a file or directory with an unsupported type:", " 0x%x.\n", 1, 1, /* HSFS_ERR_BAD_FILE_LEN */ - "hsfs: Warning: file system mounted on %s \n" + "hsfs: Warning: file system mounted on %s " "does not conform to the ISO-9660 specification:", - "file len greater than max allowed\n", + "file name length greater than max allowed\n", + 1, 0, + /* HSFS_ERR_BAD_JOLIET_FILE_LEN */ + "hsfs: Warning: file system mounted on %s " + "does not conform to the Joliet specification:", + "file name length greater than max allowed\n", + 1, 0, + /* HSFS_ERR_TRUNC_JOLIET_FILE_LEN */ + "hsfs: Warning: file system mounted on %s " + "does not conform to the Joliet specification:", + "file name length greater than MAXNAMELEN (truncated)\n", + 1, 0, + /* HSFS_ERR_BAD_DIR_ENTRY */ + "hsfs: Warning: file system mounted on %s " + "has inconsistent data:", + "invalid directory or file name length (ignored)\n", 1, 0, };
--- a/usr/src/uts/common/fs/hsfs/hsfs_susp_subr.c Wed Oct 11 06:38:28 2006 -0700 +++ b/usr/src/uts/common/fs/hsfs/hsfs_susp_subr.c Wed Oct 11 07:48:51 2006 -0700 @@ -20,8 +20,9 @@ */ /* * System Use Sharing protocol subroutines for High Sierra filesystem - * - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -423,7 +424,8 @@ } else goto end; - (void) hs_parsedir(fsp, root_ptr, hdp, (char *)NULL, (int *)NULL); + (void) hs_parsedir(fsp, root_ptr, hdp, (char *)NULL, (int *)NULL, + HS_SECTOR_SIZE - secoff); /* * If we did not get at least 1 extension, let's assume ISO and
--- a/usr/src/uts/common/fs/hsfs/hsfs_vfsops.c Wed Oct 11 06:38:28 2006 -0700 +++ b/usr/src/uts/common/fs/hsfs/hsfs_vfsops.c Wed Oct 11 07:48:51 2006 -0700 @@ -69,6 +69,8 @@ #include <sys/cmn_err.h> #include <sys/bootconf.h> +#include <sys/sdt.h> + /* * These are needed for the CDROMREADOFFSET Code */ @@ -90,6 +92,11 @@ #define HOPT_TRAILDOT "traildot" #define HOPT_NRR "nrr" #define HOPT_RR "rr" +#define HOPT_JOLIET "joliet" +#define HOPT_NOJOLIET "nojoliet" +#define HOPT_JOLIETLONG "jolietlong" +#define HOPT_VERS2 "vers2" +#define HOPT_NOVERS2 "novers2" #define HOPT_RO MNTOPT_RO static char *global_cancel[] = { HOPT_NOGLOBAL, NULL }; @@ -99,6 +106,10 @@ static char *ro_cancel[] = { MNTOPT_RW, NULL }; static char *rr_cancel[] = { HOPT_NRR, NULL }; static char *nrr_cancel[] = { HOPT_RR, NULL }; +static char *joliet_cancel[] = { HOPT_NOJOLIET, NULL }; +static char *nojoliet_cancel[] = { HOPT_JOLIET, NULL }; +static char *vers2_cancel[] = { HOPT_NOVERS2, NULL }; +static char *novers2_cancel[] = { HOPT_VERS2, NULL }; static char *trail_cancel[] = { HOPT_NOTRAILDOT, NULL }; static char *notrail_cancel[] = { HOPT_TRAILDOT, NULL }; @@ -110,8 +121,14 @@ { HOPT_RO, ro_cancel, NULL, MO_DEFAULT, NULL }, { HOPT_RR, rr_cancel, NULL, MO_DEFAULT, NULL }, { HOPT_NRR, nrr_cancel, NULL, 0, NULL }, + { HOPT_JOLIET, joliet_cancel, NULL, 0, NULL }, + { HOPT_NOJOLIET, nojoliet_cancel, NULL, 0, NULL }, + { HOPT_JOLIETLONG, NULL, NULL, 0, NULL }, + { HOPT_VERS2, vers2_cancel, NULL, 0, NULL }, + { HOPT_NOVERS2, novers2_cancel, NULL, 0, NULL }, { HOPT_TRAILDOT, trail_cancel, NULL, MO_DEFAULT, NULL }, { HOPT_NOTRAILDOT, notrail_cancel, NULL, 0, NULL }, + { "sector", NULL, "0", MO_HASVALUE, NULL}, }; static mntopts_t hsfs_proto_opttbl = { @@ -119,6 +136,7 @@ hsfs_options }; +static int hsfsfstype; static int hsfsinit(int, char *); static vfsdef_t vfw = { @@ -140,15 +158,33 @@ char _depends_on[] = "fs/specfs"; int -_init() +_init(void) { return (mod_install(&modlinkage)); } int -_fini() +_fini(void) { - return (EBUSY); + int error; + + error = mod_remove(&modlinkage); + + DTRACE_PROBE1(mod_remove, int, error); + + if (error) + return (error); + + mutex_destroy(&hs_mounttab_lock); + + /* + * Tear down the operations vectors + */ + (void) vfs_freevfsops_by_type(hsfsfstype); + vn_freevnodeops(hsfs_vnodeops); + + hs_fini_hsnode_cache(); + return (0); } int @@ -177,21 +213,23 @@ static int hs_mountfs(struct vfs *vfsp, dev_t dev, char *path, mode_t mode, int flags, struct cred *cr, int isroot); +static int hs_getrootvp(struct vfs *vfsp, struct hsfs *fsp, size_t pathsize); static int hs_findhsvol(struct hsfs *fsp, struct vnode *vp, struct hs_volume *hvp); static int hs_parsehsvol(struct hsfs *fsp, uchar_t *volp, struct hs_volume *hvp); static int hs_findisovol(struct hsfs *fsp, struct vnode *vp, - struct hs_volume *hvp); + struct hs_volume *hvp, + struct hs_volume *svp, + struct hs_volume *jvp); +static int hs_joliet_level(uchar_t *volp); static int hs_parseisovol(struct hsfs *fsp, uchar_t *volp, struct hs_volume *hvp); -static void hs_copylabel(struct hs_volume *, unsigned char *); +static void hs_copylabel(struct hs_volume *, unsigned char *, int); static int hs_getmdev(struct vfs *, char *fspec, int flags, dev_t *pdev, mode_t *mode, cred_t *cr); static int hs_findvoldesc(dev_t rdev, int desc_sec); -static int hsfsfstype; - static int hsfsinit(int fstype, char *name) { @@ -271,6 +309,12 @@ flags |= HSFSMNT_NOTRAILDOT; if (vfs_optionisset(vfsp, HOPT_NRR, NULL)) flags |= HSFSMNT_NORRIP; + if (vfs_optionisset(vfsp, HOPT_NOJOLIET, NULL)) + flags |= HSFSMNT_NOJOLIET; + if (vfs_optionisset(vfsp, HOPT_JOLIETLONG, NULL)) + flags |= HSFSMNT_JOLIETLONG; + if (vfs_optionisset(vfsp, HOPT_NOVERS2, NULL)) + flags |= HSFSMNT_NOVERS2; error = pn_get(uap->dir, (uap->flags & MS_SYSSPACE) ? UIO_SYSSPACE : UIO_USERSPACE, &dpn); @@ -516,7 +560,39 @@ int error; struct timeval tv; int fsid; - int use_rrip = (mount_flags & HSFSMNT_NORRIP) == 0; + int use_rrip; + int use_vers2; + int use_joliet; + int has_rrip = 0; + int has_vers2 = 0; + int has_joliet = 0; + int force_rrip_off; + int force_vers2_off; + int force_joliet_off; + size_t pathbufsz = strlen(path) + 1; + int redo_rootvp; + + struct hs_volume *svp; /* Supplemental VD for ISO-9660:1999 */ + struct hs_volume *jvp; /* Joliet VD */ + + /* + * The rules for which extension will be used are: + * 1. No specific mount options given: + * - use rrip if available + * - use ISO9660:1999 if available + * - use joliet if available. + * 2. rrip/ISO9660:1999/joliet explicitly disabled via mount option: + * - use next "lower" extension + * 3. joliet/ISO9660:1999/rrip explicitly requested via mount option: + * - disable rrip support even if available + * - disable IOS9660:1999 support even if available + * + * We need to adjust these flags as we discover the extensions + * present. See below. These are just the starting values. + */ + use_rrip = (mount_flags & HSFSMNT_NORRIP) == 0; + use_vers2 = (mount_flags & HSFSMNT_NOVERS2) == 0; + use_joliet = (mount_flags & HSFSMNT_NOJOLIET) == 0; /* * Open the device @@ -561,24 +637,43 @@ * Init a new hsfs structure. */ fsp = kmem_zalloc(sizeof (*fsp), KM_SLEEP); + svp = kmem_zalloc(sizeof (*svp), KM_SLEEP); + jvp = kmem_zalloc(sizeof (*jvp), KM_SLEEP); /* hardwire perms, uid, gid */ fsp->hsfs_vol.vol_uid = hsfs_default_uid; fsp->hsfs_vol.vol_gid = hsfs_default_gid; fsp->hsfs_vol.vol_prot = hsfs_default_mode; + svp->vol_uid = hsfs_default_uid; + svp->vol_gid = hsfs_default_gid; + svp->vol_prot = hsfs_default_mode; + jvp->vol_uid = hsfs_default_uid; + jvp->vol_gid = hsfs_default_gid; + jvp->vol_prot = hsfs_default_mode; /* * Look for a Standard File Structure Volume Descriptor, * of which there must be at least one. * If found, check for volume size consistency. + * + * If svp->lbn_size is != 0, we did find a ISO-9660:1999 SVD + * If jvp->lbn_size is != 0, we did find a Joliet SVD. */ - error = hs_findisovol(fsp, devvp, &fsp->hsfs_vol); + fsp->hsfs_namemax = ISO_FILE_NAMELEN; + fsp->hsfs_namelen = ISO_FILE_NAMELEN; + error = hs_findisovol(fsp, devvp, &fsp->hsfs_vol, svp, jvp); if (error == EINVAL) /* no iso 9660 - try high sierra ... */ error = hs_findhsvol(fsp, devvp, &fsp->hsfs_vol); if (error) goto cleanup; + DTRACE_PROBE4(findvol, + struct hsfs *, fsp, + struct hs_volume *, &fsp->hsfs_vol, + struct hs_volume *, svp, + struct hs_volume *, jvp); + /* * Generate a file system ID from the CD-ROM, * and check it for uniqueness. @@ -608,8 +703,8 @@ fsp->hsfs_devvp = devvp; fsp->hsfs_vfs = vfsp; - fsp->hsfs_fsmnt = kmem_alloc(strlen(path) + 1, KM_SLEEP); - (void) strcpy(fsp->hsfs_fsmnt, path); + fsp->hsfs_fsmnt = kmem_alloc(pathbufsz, KM_SLEEP); + (void) strlcpy(fsp->hsfs_fsmnt, path, pathbufsz); mutex_init(&fsp->hsfs_free_lock, NULL, MUTEX_DEFAULT, NULL); rw_init(&fsp->hsfs_hash_lock, NULL, RW_DEFAULT, NULL); @@ -621,6 +716,209 @@ vfsp->vfs_fsid.val[0] = fsid; vfsp->vfs_fsid.val[1] = hsfsfstype; + if (!hs_getrootvp(vfsp, fsp, pathbufsz)) { + DTRACE_PROBE1(rootvp__failed, struct hsfs *, fsp); + error = EINVAL; + goto cleanup; + } + DTRACE_PROBE1(rootvp, struct hsfs *, fsp); + + /* + * Attempt to discover a RR extension. + */ + if (use_rrip) { + hp = VTOH(fsp->hsfs_rootvp); + hs_check_root_dirent(fsp->hsfs_rootvp, &(hp->hs_dirent)); + } + + has_rrip = IS_RRIP_IMPLEMENTED(fsp); + has_vers2 = (svp->lbn_size != 0); + has_joliet = (jvp->lbn_size != 0); + + DTRACE_PROBE4(voltype__suggested, struct hsfs *, fsp, + int, use_rrip, int, use_vers2, int, use_joliet); + + DTRACE_PROBE4(voltype__actual, struct hsfs *, fsp, + int, has_rrip, int, has_vers2, int, has_joliet); + + DTRACE_PROBE4(findvol, + struct hsfs *, fsp, + struct hs_volume *, &fsp->hsfs_vol, + struct hs_volume *, svp, + struct hs_volume *, jvp); + + force_rrip_off = !use_rrip || + (vfs_optionisset(vfsp, HOPT_JOLIET, NULL) && has_joliet) || + (vfs_optionisset(vfsp, HOPT_VERS2, NULL) && has_vers2); + + force_vers2_off = !use_vers2 || + (vfs_optionisset(vfsp, HOPT_JOLIET, NULL) && has_joliet); + + force_joliet_off = !use_joliet; + + DTRACE_PROBE4(voltype__force_off, struct hsfs *, fsp, + int, force_rrip_off, int, force_vers2_off, int, force_joliet_off); + + /* + * At the moment, we have references of all three possible + * extensions (RR, ISO9660:1999/v2 and Joliet) if present. + * + * The "active" volume descriptor is RRIP (or ISO9660:1988). + * We now switch to the user-requested one. + */ + redo_rootvp = 0; + + if (force_rrip_off || !has_rrip) { + if (has_vers2 && !force_vers2_off) { + VN_RELE(fsp->hsfs_rootvp); + bcopy(svp, &fsp->hsfs_vol, sizeof (struct hs_volume)); + fsp->hsfs_vol_type = HS_VOL_TYPE_ISO_V2; + vfsp->vfs_bsize = fsp->hsfs_vol.lbn_size; + redo_rootvp = 1; + has_joliet = 0; + } else if (has_joliet && !force_joliet_off) { + VN_RELE(fsp->hsfs_rootvp); + bcopy(jvp, &fsp->hsfs_vol, sizeof (struct hs_volume)); + fsp->hsfs_vol_type = HS_VOL_TYPE_JOLIET; + vfsp->vfs_bsize = fsp->hsfs_vol.lbn_size; + redo_rootvp = 1; + has_vers2 = 0; + } + } + + if (redo_rootvp) { + /* + * Make sure not to use Rock Ridge. + */ + UNSET_IMPL_BIT(fsp, RRIP_BIT); + UNSET_SUSP_BIT(fsp); + has_rrip = 0; + + if (!hs_getrootvp(vfsp, fsp, pathbufsz)) { + DTRACE_PROBE1(rootvp__failed, struct hsfs *, fsp); + error = EINVAL; + goto cleanup; + } + DTRACE_PROBE1(rootvp, struct hsfs *, fsp); + } + if (IS_RRIP_IMPLEMENTED(fsp)) { + has_vers2 = 0; + has_joliet = 0; + } + if (force_vers2_off) + has_vers2 = 0; + if (force_joliet_off) + has_joliet = 0; + DTRACE_PROBE4(voltype__taken, struct hsfs *, fsp, + int, has_rrip, int, has_vers2, int, has_joliet); + + /* + * mark root node as VROOT + */ + fsp->hsfs_rootvp->v_flag |= VROOT; + + /* Here we take care of some special case stuff for mountroot */ + if (isroot) { + fsp->hsfs_rootvp->v_rdev = devvp->v_rdev; + rootvp = fsp->hsfs_rootvp; + } + + if (IS_RRIP_IMPLEMENTED(fsp)) { + /* + * if RRIP, don't copy NOMAPLCASE or NOTRAILDOT to hsfs_flags + */ + mount_flags &= ~(HSFSMNT_NOMAPLCASE | HSFSMNT_NOTRAILDOT); + + fsp->hsfs_namemax = RRIP_FILE_NAMELEN; + fsp->hsfs_namelen = RRIP_FILE_NAMELEN; + + ASSERT(vfs_optionisset(vfsp, HOPT_RR, NULL)); + vfs_clearmntopt(vfsp, HOPT_VERS2); + vfs_clearmntopt(vfsp, HOPT_JOLIET); + + } else switch (fsp->hsfs_vol_type) { + + case HS_VOL_TYPE_HS: + case HS_VOL_TYPE_ISO: + default: + /* + * if iso v1, don't allow trailing spaces in iso file names + */ + mount_flags |= HSFSMNT_NOTRAILSPACE; + fsp->hsfs_namemax = ISO_NAMELEN_V2_MAX; + fsp->hsfs_namelen = ISO_FILE_NAMELEN; + vfs_clearmntopt(vfsp, HOPT_RR); + vfs_clearmntopt(vfsp, HOPT_VERS2); + vfs_clearmntopt(vfsp, HOPT_JOLIET); + break; + + case HS_VOL_TYPE_ISO_V2: + /* + * if iso v2, don't copy NOTRAILDOT to hsfs_flags + */ + mount_flags &= ~HSFSMNT_NOTRAILDOT; + mount_flags |= HSFSMNT_NOMAPLCASE | HSFSMNT_NOVERSION; + fsp->hsfs_namemax = ISO_NAMELEN_V2_MAX; + fsp->hsfs_namelen = ISO_NAMELEN_V2; + vfs_setmntopt(vfsp, HOPT_VERS2, NULL, 0); + vfs_clearmntopt(vfsp, HOPT_RR); + vfs_clearmntopt(vfsp, HOPT_JOLIET); + break; + + case HS_VOL_TYPE_JOLIET: + /* + * if Joliet, don't copy NOMAPLCASE or NOTRAILDOT to hsfs_flags + */ + mount_flags &= ~(HSFSMNT_NOMAPLCASE | HSFSMNT_NOTRAILDOT); + mount_flags |= HSFSMNT_NOMAPLCASE; + if (mount_flags & HSFSMNT_JOLIETLONG) + fsp->hsfs_namemax = JOLIET_NAMELEN_MAX*3; /* UTF-8 */ + else + fsp->hsfs_namemax = MAXNAMELEN-1; + fsp->hsfs_namelen = JOLIET_NAMELEN*2; + vfs_setmntopt(vfsp, HOPT_JOLIET, NULL, 0); + vfs_clearmntopt(vfsp, HOPT_RR); + vfs_clearmntopt(vfsp, HOPT_VERS2); + break; + } + + fsp->hsfs_flags = mount_flags; + + DTRACE_PROBE1(mount__done, struct hsfs *, fsp); + + /* + * set the magic word + */ + fsp->hsfs_magic = HSFS_MAGIC; + mutex_exit(&hs_mounttab_lock); + + return (0); + +cleanup: + (void) VOP_CLOSE(devvp, FREAD, 1, (offset_t)0, cr); + VN_RELE(devvp); + if (fsp) + kmem_free(fsp, sizeof (*fsp)); + if (svp) + kmem_free(svp, sizeof (*svp)); + if (jvp) + kmem_free(jvp, sizeof (*jvp)); + return (error); +} + +/* + * Get the rootvp associated with fsp->hsfs_vol + */ +static int +hs_getrootvp( + struct vfs *vfsp, + struct hsfs *fsp, + size_t pathsize) +{ + struct hsnode *hp; + + ASSERT(pathsize == strlen(fsp->hsfs_fsmnt) + 1); + /* * If the root directory does not appear to be * valid, use what it points to as "." instead. @@ -631,59 +929,24 @@ hs_log_bogus_disk_warning(fsp, HSFS_ERR_BAD_ROOT_DIR, 0); if (hs_remakenode(fsp->hsfs_vol.root_dir.ext_lbn, (uint_t)0, vfsp, &fsp->hsfs_rootvp)) { - error = EINVAL; hs_mounttab = hs_mounttab->hsfs_next; mutex_destroy(&fsp->hsfs_free_lock); rw_destroy(&fsp->hsfs_hash_lock); - kmem_free(fsp->hsfs_fsmnt, strlen(path) + 1); + kmem_free(fsp->hsfs_fsmnt, pathsize); mutex_exit(&hs_mounttab_lock); - goto cleanup; + return (0); } } else { fsp->hsfs_rootvp = hs_makenode(&fsp->hsfs_vol.root_dir, fsp->hsfs_vol.root_dir.ext_lbn, 0, vfsp); } - /* mark vnode as VROOT */ - fsp->hsfs_rootvp->v_flag |= VROOT; - - /* Here we take care of some special case stuff for mountroot */ - if (isroot) { - fsp->hsfs_rootvp->v_rdev = devvp->v_rdev; - rootvp = fsp->hsfs_rootvp; - } - /* XXX - ignore the path table for now */ fsp->hsfs_ptbl = NULL; hp = VTOH(fsp->hsfs_rootvp); hp->hs_ptbl_idx = NULL; - if (use_rrip) - hs_check_root_dirent(fsp->hsfs_rootvp, &(hp->hs_dirent)); - - fsp->hsfs_namemax = IS_RRIP_IMPLEMENTED(fsp) - ? RRIP_FILE_NAMELEN - : ISO_FILE_NAMELEN; - /* - * if RRIP, don't copy NOMAPLCASE or NOTRAILDOT to hsfs_flags - */ - if (IS_RRIP_IMPLEMENTED(fsp)) - mount_flags &= ~(HSFSMNT_NOMAPLCASE | HSFSMNT_NOTRAILDOT); - - fsp->hsfs_flags = mount_flags; - - /* set the magic word */ - fsp->hsfs_magic = HSFS_MAGIC; - mutex_exit(&hs_mounttab_lock); - - return (0); - -cleanup: - (void) VOP_CLOSE(devvp, FREAD, 1, (offset_t)0, cr); - VN_RELE(devvp); - if (fsp) - kmem_free(fsp, sizeof (*fsp)); - return (error); + return (1); } /* @@ -789,7 +1052,7 @@ #else hvp->ptbl_lbn = HSV_PTBL_MAN_MS(volp); #endif - hs_copylabel(hvp, HSV_VOL_ID(volp)); + hs_copylabel(hvp, HSV_VOL_ID(volp), 0); /* * Make sure that lbn_size is a power of two and otherwise valid. @@ -801,7 +1064,7 @@ return (EINVAL); } return (hs_parsedir(fsp, HSV_ROOT_DIR(volp), &hvp->root_dir, - (char *)NULL, (int *)NULL)); + (char *)NULL, (int *)NULL, HDE_ROOT_DIR_REC_SIZE)); } /* @@ -810,11 +1073,16 @@ * Locate the Primary Volume Descriptor * parse it into an hs_volume structure. * - * XXX - Supplementary, Partition not yet done + * XXX - Partition not yet done + * + * Except for fsp->hsfs_vol_type, no fsp member may be modified. + * fsp->hsfs_vol is modified indirectly via the *hvp argument. */ static int hs_findisovol(struct hsfs *fsp, struct vnode *vp, - struct hs_volume *hvp) + struct hs_volume *hvp, + struct hs_volume *svp, + struct hs_volume *jvp) { struct buf *secbp; int i; @@ -822,6 +1090,8 @@ int error; uint_t secno; int foundpvd = 0; + int foundsvd = 0; + int foundjvd = 0; secno = hs_findvoldesc(vp->v_rdev, ISO_VOLDESC_SEC); secbp = bread(vp->v_rdev, secno * 4, ISO_SECTOR_SIZE); @@ -839,11 +1109,11 @@ for (i = 0; i < ISO_ID_STRLEN; i++) if (ISO_STD_ID(volp)[i] != ISO_ID_STRING[i]) goto cantfind; - if (ISO_STD_VER(volp) != ISO_ID_VER) - goto cantfind; switch (ISO_DESC_TYPE(volp)) { case ISO_VD_PVD: /* Standard File Structure */ + if (ISO_STD_VER(volp) != ISO_ID_VER) + goto cantfind; if (foundpvd != 1) { fsp->hsfs_vol_type = HS_VOL_TYPE_ISO; if (error = hs_parseisovol(fsp, volp, hvp)) { @@ -855,6 +1125,23 @@ break; case ISO_VD_SVD: /* Supplementary Volume Descriptor */ + if (ISO_STD_VER(volp) == ISO_ID_VER2 && + foundsvd != 1) { + fsp->hsfs_vol_type = HS_VOL_TYPE_ISO; + if (error = hs_parseisovol(fsp, volp, svp)) { + brelse(secbp); + return (error); + } + foundsvd = 1; + } + if (hs_joliet_level(volp) >= 1 && foundjvd != 1) { + fsp->hsfs_vol_type = HS_VOL_TYPE_ISO; + if (error = hs_parseisovol(fsp, volp, jvp)) { + brelse(secbp); + return (error); + } + foundjvd = 1; + } break; case ISO_VD_BOOT: break; @@ -886,6 +1173,31 @@ brelse(secbp); return (EINVAL); } + +/* + * Return 0 if no Joliet is found + * else return Joliet Level 1..3 + */ +static int +hs_joliet_level(uchar_t *volp) +{ + if (ISO_std_ver(volp)[0] == ISO_ID_VER && + ISO_svd_esc(volp)[0] == '%' && + ISO_svd_esc(volp)[1] == '/') { + + switch (ISO_svd_esc(volp)[2]) { + + case '@': + return (1); + case 'C': + return (2); + case 'E': + return (3); + } + } + return (0); +} + /* * hs_parseisovol * @@ -917,7 +1229,7 @@ #else hvp->ptbl_lbn = ISO_PTBL_MAN_MS(volp); #endif - hs_copylabel(hvp, ISO_VOL_ID(volp)); + hs_copylabel(hvp, ISO_VOL_ID(volp), hs_joliet_level(volp) >= 1); /* * Make sure that lbn_size is a power of two and otherwise valid. @@ -929,7 +1241,7 @@ return (EINVAL); } return (hs_parsedir(fsp, ISO_ROOT_DIR(volp), &hvp->root_dir, - (char *)NULL, (int *)NULL)); + (char *)NULL, (int *)NULL, IDE_ROOT_DIR_REC_SIZE)); } /* @@ -995,8 +1307,19 @@ } static void -hs_copylabel(struct hs_volume *hvp, unsigned char *label) +hs_copylabel(struct hs_volume *hvp, unsigned char *label, int isjoliet) { + char lbuf[64]; /* hs_joliet_cp() creates 48 bytes at most */ + + if (isjoliet) { + /* + * hs_joliet_cp() will output 16..48 bytes. + * We need to clear 'lbuf' to avoid junk chars past byte 15. + */ + bzero(lbuf, sizeof (lbuf)); + hs_joliet_cp((char *)label, lbuf, 32); + label = (unsigned char *)lbuf; + } /* cdrom volid is at most 32 bytes */ bcopy(label, hvp->vol_id, 32); hvp->vol_id[31] = NULL;
--- a/usr/src/uts/common/fs/hsfs/hsfs_vnops.c Wed Oct 11 06:38:28 2006 -0700 +++ b/usr/src/uts/common/fs/hsfs/hsfs_vnops.c Wed Oct 11 07:48:51 2006 -0700 @@ -445,7 +445,8 @@ * XXX - maybe hs_parsedir() will detect EXISTENCE bit */ if (!hs_parsedir(fsp, &blkp[rel_offset(offset)], - &hd, dname, &dnamelen)) { + &hd, dname, &dnamelen, + last_offset - rel_offset(offset))) { /* * Determine if there is enough room */ @@ -1301,6 +1302,34 @@ return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr)); } +/* ARGSUSED */ +static int +hsfs_pathconf(struct vnode *vp, int cmd, ulong_t *valp, struct cred *cr) +{ + struct hsfs *fsp; + + int error = 0; + + switch (cmd) { + + case _PC_NAME_MAX: + fsp = VFS_TO_HSFS(vp->v_vfsp); + *valp = fsp->hsfs_namemax; + break; + + case _PC_FILESIZEBITS: + *valp = 33; /* Without multi extent support: 4 GB - 2k */ + break; + + default: + error = fs_pathconf(vp, cmd, valp, cr); + } + + return (error); +} + + + const fs_operation_def_t hsfs_vnodeops_template[] = { VOPNAME_OPEN, hsfs_open, VOPNAME_CLOSE, hsfs_close, @@ -1320,6 +1349,7 @@ VOPNAME_MAP, (fs_generic_func_p) hsfs_map, VOPNAME_ADDMAP, (fs_generic_func_p) hsfs_addmap, VOPNAME_DELMAP, hsfs_delmap, + VOPNAME_PATHCONF, hsfs_pathconf, NULL, NULL };
--- a/usr/src/uts/common/sys/fs/hsfs_impl.h Wed Oct 11 06:38:28 2006 -0700 +++ b/usr/src/uts/common/sys/fs/hsfs_impl.h Wed Oct 11 07:48:51 2006 -0700 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -21,8 +20,10 @@ */ /* * High Sierra filesystem internal routine definitions. - * Copyright 1989,1990,1993,1997-1998,2000-2003 Sun Microsystems, Inc. - * All rights reserved. Use is subject to license terms. + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #ifndef _SYS_FS_HSFS_IMPL_H @@ -57,9 +58,12 @@ extern void hs_freenode(vnode_t *vp, struct hsfs *fsp, int nopage); /* parse a directory entry */ extern int hs_parsedir(struct hsfs *fsp, uchar_t *dirp, - struct hs_direntry *hdp, char *dnp, int *dnlen); + struct hs_direntry *hdp, char *dnp, int *dnlen, int last_offset); /* convert d-characters */ extern int hs_namecopy(char *from, char *to, int size, ulong_t flags); +extern int hs_jnamecopy(char *from, char *to, int size, int maxsize, + ulong_t flags); +extern int hs_joliet_cp(char *from, char *to, int size); /* destroy the incore hnode table */ extern void hs_filldirent(struct vnode *vp, struct hs_direntry *hdp); /* check vnode protection */ @@ -74,6 +78,7 @@ uint_t data); extern int hsfs_valid_dir(struct hs_direntry *hd); extern void hs_init_hsnode_cache(void); +extern void hs_fini_hsnode_cache(void); /* * Global data structures
--- a/usr/src/uts/common/sys/fs/hsfs_isospec.h Wed Oct 11 06:38:28 2006 -0700 +++ b/usr/src/uts/common/sys/fs/hsfs_isospec.h Wed Oct 11 07:48:51 2006 -0700 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -91,7 +91,8 @@ }; #define ISO_ID_STRING "CD001" /* ISO_std_id field */ #define ISO_ID_STRLEN 5 /* ISO_std_id field length */ -#define ISO_ID_VER 1 /* ISO_std_ver field */ +#define ISO_ID_VER 1 /* ISO_std_ver field ISO-9660:1988 */ +#define ISO_ID_VER2 2 /* ISO_std_ver field ISO-9660:1999 */ #define ISO_FILE_STRUCT_ID_VER 1 /* ISO_file structure version field */ #define ISO_SYS_ID_STRLEN 32 #define ISO_VOL_ID_STRLEN 32 @@ -113,6 +114,7 @@ #define ISO_sys_id(x) (&((uchar_t *)x)[8]) #define ISO_vol_id(x) (&((uchar_t *)x)[40]) #define ISO_vol_size(x) (&((uchar_t *)x)[80]) +#define ISO_svd_esc(x) (&((uchar_t *)x)[88]) /* Supplemental VD */ #define ISO_set_size(x) (&((uchar_t *)x)[120]) #define ISO_set_seq(x) (&((uchar_t *)x)[124]) #define ISO_blk_size(x) (&((uchar_t *)x)[128]) @@ -244,9 +246,26 @@ #define IDE_REGULAR_FILE(x) (((x) & IDE_PROHIBITED) == 0) #define IDE_REGULAR_DIR(x) (((x) & IDE_PROHIBITED) == IDE_DIRECTORY) +/* + * A ISO filename is: "ABCDE.EEE;1" -> <filename> '.' <ext> ';' <version #> + * + * The ISO-9660:1988 (Version 1) maximum needed string length is: + * 30 chars (filename + ext) + * + 2 chars ('.' + ';') + * + strlen("32767") + * + null byte + * ================================ + * = 38 chars + * + * ISO_DIR_NAMELEN counts 30 chars + '.' + */ #define ISO_DIR_NAMELEN 31 /* max length of a directory name */ #define ISO_FILE_NAMELEN 31 /* max length of a filename, */ /* excluding ";" and version num */ +#define ISO_NAMELEN_V2 207 /* ISOv2: 254 - 33 - 14 (XA Record) */ +#define ISO_NAMELEN_V2_MAX 221 /* max length, ignorig ISOv2 */ +#define JOLIET_NAMELEN 64 /* Joliet file name length (spec) */ +#define JOLIET_NAMELEN_MAX 110 /* max Joliet file name length */ /* Path table enry */ /* fix size of path table entry */
--- a/usr/src/uts/common/sys/fs/hsfs_node.h Wed Oct 11 06:38:28 2006 -0700 +++ b/usr/src/uts/common/sys/fs/hsfs_node.h Wed Oct 11 07:48:51 2006 -0700 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -21,8 +20,9 @@ */ /* * High Sierra filesystem structure definitions - * Copyright 2004 Sun Microsystems, Inc. - * All rights reserved. + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -156,7 +156,8 @@ * There is one of these for each mounted High Sierra filesystem. */ enum hs_vol_type { - HS_VOL_TYPE_HS = 0, HS_VOL_TYPE_ISO = 1 + HS_VOL_TYPE_HS = 0, HS_VOL_TYPE_ISO = 1, HS_VOL_TYPE_ISO_V2 = 2, + HS_VOL_TYPE_JOLIET = 3 }; #define HSFS_MAGIC 0x03095500 struct hsfs { @@ -165,7 +166,7 @@ struct vfs *hsfs_vfs; /* vfs for this fs */ struct vnode *hsfs_rootvp; /* vnode for root of filesystem */ struct vnode *hsfs_devvp; /* device mounted on */ - enum hs_vol_type hsfs_vol_type; /* 0 hsfs 1 iso 2 hsfs+sun 3 iso+sun */ + enum hs_vol_type hsfs_vol_type; /* see above */ struct hs_volume hsfs_vol; /* File Structure Volume Descriptor */ struct ptable *hsfs_ptbl; /* pointer to incore Path Table */ int hsfs_ptbl_size; /* size of incore path table */ @@ -174,6 +175,7 @@ ulong_t hsfs_ext_impl; /* ext. information bits */ ushort_t hsfs_sua_off; /* the SUA offset */ ushort_t hsfs_namemax; /* maximum file name length */ + ushort_t hsfs_namelen; /* "official" max. file name length */ ulong_t hsfs_err_flags; /* ways in which fs is non-conformant */ char *hsfs_fsmnt; /* name mounted on */ ulong_t hsfs_flags; /* hsfs-specific mount flags */ @@ -190,11 +192,14 @@ * Also serves as index into hsfs_error[], so must be * kept in sync with that data structure. */ -#define HSFS_ERR_TRAILING_JUNK 0 -#define HSFS_ERR_LOWER_CASE_NM 1 -#define HSFS_ERR_BAD_ROOT_DIR 2 -#define HSFS_ERR_UNSUP_TYPE 3 -#define HSFS_ERR_BAD_FILE_LEN 4 +#define HSFS_ERR_TRAILING_JUNK 0 +#define HSFS_ERR_LOWER_CASE_NM 1 +#define HSFS_ERR_BAD_ROOT_DIR 2 +#define HSFS_ERR_UNSUP_TYPE 3 +#define HSFS_ERR_BAD_FILE_LEN 4 +#define HSFS_ERR_BAD_JOLIET_FILE_LEN 5 +#define HSFS_ERR_TRUNC_JOLIET_FILE_LEN 6 +#define HSFS_ERR_BAD_DIR_ENTRY 7 #define HSFS_HAVE_LOWER_CASE(fsp) \ ((fsp)->hsfs_err_flags & (1 << HSFS_ERR_LOWER_CASE_NM))
--- a/usr/src/uts/common/sys/fs/hsfs_rrip.h Wed Oct 11 06:38:28 2006 -0700 +++ b/usr/src/uts/common/sys/fs/hsfs_rrip.h Wed Oct 11 07:48:51 2006 -0700 @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -21,8 +20,10 @@ */ /* * ISO 9660 RRIP extension filesystem specifications - * Copyright (c) 1991,1997-1998 by Sun Microsystems, Inc. - * All rights reserved. + */ +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ #ifndef _SYS_FS_HSFS_RRIP_H @@ -39,9 +40,14 @@ * This is not a good place for them; we should probably have a file * named hsfs_mount.h for such stuff. */ -#define HSFSMNT_NORRIP 0x1 -#define HSFSMNT_NOTRAILDOT 0x2 -#define HSFSMNT_NOMAPLCASE 0x4 +#define HSFSMNT_NORRIP 0x1 /* -nrr option found */ +#define HSFSMNT_NOTRAILDOT 0x2 /* ignore trailing '.' */ +#define HSFSMNT_NOMAPLCASE 0x4 /* do not map filenames to lcase */ +#define HSFSMNT_NOTRAILSPACE 0x8 /* no trailing space in iso 9660 */ +#define HSFSMNT_NOVERSION 0x10 /* no version info in iso 9660 */ +#define HSFSMNT_NOJOLIET 0x20 /* ignore Joliet even if present */ +#define HSFSMNT_JOLIETLONG 0x40 /* do not truncate Joliet filenames */ +#define HSFSMNT_NOVERS2 0x80 /* ignore ISO-9660:1999 */ /* * XXX: The following flag was used in the past to instruct the kernel to @@ -186,9 +192,6 @@ * "NM" alternate name and "SL" symbolic link macros... */ -#define RESTORE_NM(tmp, orig) if (is_rrip && *(tmp) != '\0') \ - (void) strcpy((orig), (tmp)) - #define SYM_LINK_LEN(x) (strlen(x) + 1) #define RRIP_NAME_LEN_BASE 5 #define RRIP_NAME_LEN(x) (SUF_LEN(x) - RRIP_NAME_LEN_BASE)