changeset 4866:34d9e5474e96

4294956 hsfs creates wrong inode numbers for hard links 6489267 off by one last_offset computation in hsfs_readdir leads to panic 6490818 Memory leak in hs_mountfs()
author frankho
date Wed, 15 Aug 2007 05:40:25 -0700
parents f99b3b9b2940
children dd3be85f40a2
files usr/src/uts/common/fs/hsfs/hsfs_node.c usr/src/uts/common/fs/hsfs/hsfs_rrip.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_node.h usr/src/uts/common/sys/fs/hsfs_rrip.h usr/src/uts/common/sys/fs/hsfs_susp.h
diffstat 10 files changed, 362 insertions(+), 207 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/fs/hsfs/hsfs_node.c	Tue Aug 14 19:57:00 2007 -0700
+++ b/usr/src/uts/common/fs/hsfs/hsfs_node.c	Wed Aug 15 05:40:25 2007 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -103,6 +103,12 @@
  */
 static int strict_iso9660_ordering = 0;
 
+/*
+ * This tunable allows us to ignore inode numbers from rrip-1.12.
+ * In this case, we fall back to our default inode algorithm.
+ */
+int use_rrip_inodes = 1;
+
 static void hs_hsnode_cache_reclaim(void *unused);
 static void hs_addfreeb(struct hsfs *fsp, struct hsnode *hp);
 static enum dirblock_result process_dirblock(struct fbuf *fbp, uint_t *offset,
@@ -306,7 +312,7 @@
 	mutex_exit(&fsp->hsfs_free_lock);
 
 	for (tp = &fsp->hsfs_hash[HS_HPASH(hp)]; *tp != NULL;
-		tp = &(*tp)->hs_hash) {
+	    tp = &(*tp)->hs_hash) {
 		if (*tp == hp) {
 			struct vnode *vp;
 
@@ -320,14 +326,15 @@
 				 * pvn_vplist_dirty will abort all old pages
 				 */
 				(void) pvn_vplist_dirty(vp, (u_offset_t)0,
-				hsfs_putapage, B_INVAL, (struct cred *)NULL);
+				    hsfs_putapage, B_INVAL,
+				    (struct cred *)NULL);
 			*tp = hp->hs_hash;
 			break;
 		}
 	}
 	if (hp->hs_dirent.sym_link != (char *)NULL) {
 		kmem_free(hp->hs_dirent.sym_link,
-			(size_t)(hp->hs_dirent.ext_size + 1));
+		    (size_t)(hp->hs_dirent.ext_size + 1));
 	}
 
 	mutex_destroy(&hp->hs_contents_lock);
@@ -362,12 +369,19 @@
 
 /*
  * Look for hsnode in hash list.
- * Check equality of fsid and nodeid.
+ * If the inode number is != HS_DUMMY_INO (16), then only the inode
+ * number is used for the check.
+ * If the inode number is == HS_DUMMY_INO, we additionally always
+ * check the directory offset for the file to avoid caching the
+ * meta data for all zero sized to the first zero sized file that
+ * was touched.
+ *
  * If found, reactivate it if inactive.
+ *
  * Must be entered with hsfs_hash_lock held.
  */
 struct vnode *
-hs_findhash(ino64_t nodeid, struct vfs *vfsp)
+hs_findhash(ino64_t nodeid, uint_t lbn, uint_t off, struct vfs *vfsp)
 {
 	struct hsnode *tp;
 	struct hsfs *fsp;
@@ -381,6 +395,21 @@
 		if (tp->hs_nodeid == nodeid) {
 			struct vnode *vp;
 
+			if (nodeid == HS_DUMMY_INO) {
+				/*
+				 * If this is the dummy inode number, look for
+				 * matching dir_lbn and dir_off.
+				 */
+				for (; tp != NULL; tp = tp->hs_hash) {
+					if (tp->hs_nodeid == nodeid &&
+					    tp->hs_dir_lbn == lbn &&
+					    tp->hs_dir_off == off)
+						break;
+				}
+				if (tp == NULL)
+					return (NULL);
+			}
+
 			mutex_enter(&tp->hs_contents_lock);
 			vp = HTOV(tp);
 			VN_HOLD(vp);
@@ -432,13 +461,14 @@
 		for (hp = fsp->hsfs_hash[i]; hp != NULL; hp = hp->hs_hash) {
 			vp = HTOV(hp);
 			if ((hp->hs_flags & HREF) && (vp != rvp ||
-				(vp == rvp && vp->v_count > 1))) {
+			    (vp == rvp && vp->v_count > 1))) {
 				busy = 1;
 				continue;
 			}
 			if (vn_has_cached_data(vp))
 				(void) pvn_vplist_dirty(vp, (u_offset_t)0,
-				hsfs_putapage, B_INVAL, (struct cred *)NULL);
+				    hsfs_putapage, B_INVAL,
+				    (struct cred *)NULL);
 		}
 	}
 	if (busy) {
@@ -498,14 +528,15 @@
 	fsp = VFS_TO_HSFS(vfsp);
 
 	/*
-	 * Construct the nodeid: in the case of a directory
+	 * Construct the data that allows us to re-read the meta data without
+	 * knowing the name of the file: in the case of a directory
 	 * entry, this should point to the canonical dirent, the "."
 	 * directory entry for the directory.  This dirent is pointed
 	 * to by all directory entries for that dir (including the ".")
 	 * entry itself.
 	 * In the case of a file, simply point to the dirent for that
-	 * file (there are no hard links in Rock Ridge, so there's no
-	 * need to determine what the canonical dirent is.
+	 * file (there are hard links in Rock Ridge, so we need to use
+	 * different data to contruct the node id).
 	 */
 	if (dp->type == VDIR) {
 		lbn = dp->ext_lbn;
@@ -519,13 +550,30 @@
 	hvp = &fsp->hsfs_vol;
 	lbn += off >> hvp->lbn_shift;
 	off &= hvp->lbn_maxoffset;
-	nodeid = (ino64_t)MAKE_NODEID(lbn, off, vfsp);
+	/*
+	 * If the media carries rrip-v1.12 or newer, and we trust the inodes
+	 * from the rrip data (use_rrip_inodes != 0), use that data. If the
+	 * media has been created by a recent mkisofs version, we may trust
+	 * all numbers in the starting extent number; otherwise, we cannot
+	 * do this for zero sized files and symlinks, because if we did we'd
+	 * end up mapping all of them to the same node.
+	 * We use HS_DUMMY_INO in this case and make sure that we will not
+	 * map all files to the same meta data.
+	 */
+	if (dp->inode != 0 && use_rrip_inodes) {
+		nodeid = dp->inode;
+	} else if ((dp->ext_size == 0 || dp->sym_link != (char *)NULL) &&
+	    (fsp->hsfs_flags & HSFSMNT_INODE) == 0) {
+		nodeid = HS_DUMMY_INO;
+	} else {
+		nodeid = dp->ext_lbn;
+	}
 
 	/* look for hsnode in cache first */
 
 	rw_enter(&fsp->hsfs_hash_lock, RW_READER);
 
-	if ((vp = hs_findhash(nodeid, vfsp)) == NULL) {
+	if ((vp = hs_findhash(nodeid, lbn, off, vfsp)) == NULL) {
 
 		/*
 		 * Not in cache.  However, someone else may have come
@@ -535,7 +583,7 @@
 		rw_exit(&fsp->hsfs_hash_lock);
 		rw_enter(&fsp->hsfs_hash_lock, RW_WRITER);
 
-		if ((vp = hs_findhash(nodeid, vfsp)) == NULL) {
+		if ((vp = hs_findhash(nodeid, lbn, off, vfsp)) == NULL) {
 			/*
 			 * Now we are really sure that the hsnode is not
 			 * in the cache.  Get one off freelist or else
@@ -544,7 +592,7 @@
 			hp = hs_getfree(fsp);
 
 			bcopy((caddr_t)dp, (caddr_t)&hp->hs_dirent,
-				sizeof (*dp));
+			    sizeof (*dp));
 			/*
 			 * We've just copied this pointer into hs_dirent,
 			 * and don't want 2 references to same symlink.
@@ -578,10 +626,10 @@
 			if (IS_DEVVP(vp)) {
 				rw_exit(&fsp->hsfs_hash_lock);
 				newvp = specvp(vp, vp->v_rdev, vp->v_type,
-						CRED());
+				    CRED());
 				if (newvp == NULL)
-				    cmn_err(CE_NOTE,
-					"hs_makenode: specvp failed");
+					cmn_err(CE_NOTE,
+					    "hs_makenode: specvp failed");
 				VN_RELE(vp);
 				return (newvp);
 			}
@@ -624,7 +672,7 @@
 	if (nopage || (fsp->hsfs_nohsnode >= nhsnode)) {
 		/* remove this node from the hash list, if it's there */
 		for (tp = &fsp->hsfs_hash[HS_HPASH(hp)]; *tp != NULL;
-			tp = &(*tp)->hs_hash) {
+		    tp = &(*tp)->hs_hash) {
 
 			if (*tp == hp) {
 				*tp = hp->hs_hash;
@@ -634,7 +682,7 @@
 
 		if (hp->hs_dirent.sym_link != (char *)NULL) {
 			kmem_free(hp->hs_dirent.sym_link,
-				(size_t)(hp->hs_dirent.ext_size + 1));
+			    (size_t)(hp->hs_dirent.ext_size + 1));
 			hp->hs_dirent.sym_link = NULL;
 		}
 		if (vn_has_cached_data(vp)) {
@@ -691,7 +739,7 @@
 
 	dirp = (uchar_t *)secbp->b_un.b_addr;
 	error = hs_parsedir(fsp, &dirp[off], &hd, (char *)NULL, (int *)NULL,
-						HS_SECTOR_SIZE - off);
+	    HS_SECTOR_SIZE - off);
 	if (!error) {
 		*vpp = hs_makenode(&hd, lbn, off, vfsp);
 		if (*vpp == NULL)
@@ -722,7 +770,7 @@
 	struct hsfs	*fsp;
 	int		error = 0;
 	uint_t		offset;		/* real offset in directory */
-	uint_t		last_offset;	/* last index into current dir block */
+	uint_t		last_offset;	/* last index in directory */
 	char		*cmpname;	/* case-folded name */
 	int		cmpname_size;	/* how much memory we allocate for it */
 	int		cmpnamelen;
@@ -774,8 +822,8 @@
 		 * remove it from the specified name
 		 */
 		if ((fsp->hsfs_flags & HSFSMNT_NOTRAILDOT) &&
-			name[namlen-1] == '.' &&
-				CAN_TRUNCATE_DOT(name, namlen))
+		    name[namlen-1] == '.' &&
+		    CAN_TRUNCATE_DOT(name, namlen))
 			name[--namlen] = '\0';
 		if (fsp->hsfs_vol_type == HS_VOL_TYPE_ISO_V2 ||
 		    fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET) {
@@ -806,7 +854,7 @@
 		bytes_wanted = MIN(MAXBSIZE, dirsiz - (offset & MAXBMASK));
 
 		error = fbread(dvp, (offset_t)(offset & MAXBMASK),
-			(unsigned int)bytes_wanted, S_READ, &fbp);
+		    (unsigned int)bytes_wanted, S_READ, &fbp);
 		if (error)
 			goto done;
 
@@ -880,7 +928,7 @@
 	struct hs_direntry	*hdp,
 	char			*dnp,
 	int			*dnlen,
-	int			last_offset)
+	int			last_offset)	/* last offset in dirp */
 {
 	char	*on_disk_name;
 	int	on_disk_namelen;
@@ -924,8 +972,8 @@
 		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) ||
-		    (fsp->hsfs_vol_type == HS_VOL_TYPE_ISO_V2) ||
-		    (fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET)) {
+	    (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);
@@ -953,6 +1001,7 @@
 		hdp->uid = fsp -> hsfs_vol.vol_uid;
 		hdp->gid = fsp -> hsfs_vol.vol_gid;
 		hdp->mode = hdp-> mode | (fsp -> hsfs_vol.vol_prot & 0777);
+		hdp->inode = 0;		/* initialize with 0, then check rrip */
 
 		/*
 		 * Having this all filled in, let's see if we have any
@@ -960,12 +1009,13 @@
 		 */
 		if (IS_SUSP_IMPLEMENTED(fsp)) {
 			error = parse_sua((uchar_t *)dnp, dnlen,
-					&name_change_flag, dirp, hdp, fsp,
-					(uchar_t *)NULL, NULL);
+			    &name_change_flag, dirp, last_offset,
+			    hdp, fsp,
+			    (uchar_t *)NULL, NULL);
 			if (error) {
 				if (hdp->sym_link) {
 					kmem_free(hdp->sym_link,
-						(size_t)(hdp->ext_size + 1));
+					    (size_t)(hdp->ext_size + 1));
 					hdp->sym_link = (char *)NULL;
 				}
 				return (error);
@@ -986,7 +1036,7 @@
 	if (hdp->intlf_sz + hdp->intlf_sk) {
 		if ((hdp->intlf_sz == 0) || (hdp->intlf_sk == 0)) {
 			cmn_err(CE_NOTE,
-				"hsfs: interleaf size or skip factor error");
+			    "hsfs: interleaf size or skip factor error");
 			return (EINVAL);
 		}
 		if (hdp->ext_size == 0) {
@@ -1024,19 +1074,18 @@
 	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);
+		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) {
+	    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);
+		    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 */
@@ -1044,9 +1093,8 @@
 	if (dnp != NULL) {
 		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);
+			    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.
@@ -1054,16 +1102,14 @@
 			if (namelen < 0) {
 				namelen = -namelen;
 				hs_log_bogus_disk_warning(fsp,
-					HSFS_ERR_TRUNC_JOLIET_FILE_LEN,
-					0);
+				    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);
+			    on_disk_namelen, fsp->hsfs_flags);
 		}
 		if (namelen == 0)
 			return (EINVAL);
@@ -1273,7 +1319,7 @@
 		return;
 	warned = 1;
 	cmn_err(CE_CONT, "hsfs: Warning: "
-		"file name contains bad UCS-2 chacarter\n");
+	    "file name contains bad UCS-2 chacarter\n");
 }
 
 
@@ -1361,14 +1407,14 @@
 
 	if (vp->v_type != VDIR) {
 		cmn_err(CE_WARN, "hsfs_filldirent: vp (0x%p) not a directory",
-			(void *)vp);
+		    (void *)vp);
 		return;
 	}
 
 	fsp = VFS_TO_HSFS(vp ->v_vfsp);
 	secno = LBN_TO_SEC(hdp->ext_lbn+hdp->xar_len, vp->v_vfsp);
 	secoff = LBN_TO_BYTE(hdp->ext_lbn+hdp->xar_len, vp->v_vfsp) &
-			MAXHSOFFSET;
+	    MAXHSOFFSET;
 	secbp = bread(fsp->hsfs_devvp->v_rdev, secno * 4, HS_SECTOR_SIZE);
 	error = geterror(secbp);
 	if (error != 0) {
@@ -1384,7 +1430,7 @@
 		/* keep on going */
 	}
 	(void) hs_parsedir(fsp, &secp[secoff], hdp, (char *)NULL,
-				(int *)NULL, HS_SECTOR_SIZE - secoff);
+	    (int *)NULL, HS_SECTOR_SIZE - secoff);
 
 end:
 	brelse(secbp);
@@ -1412,7 +1458,7 @@
 	int		dnamelen;	/* length of name */
 	struct hs_direntry hd;
 	int		hdlen;
-	uchar_t		*dirp;	/* the directory entry */
+	uchar_t		*dirp;		/* the directory entry */
 	int		res;
 	int		parsedir_res;
 	int		is_rrip;
@@ -1501,12 +1547,11 @@
 			    HSFS_ERR_BAD_DIR_ENTRY, 0);
 			goto skip_rec;
 		} else if (dnamelen > fsp->hsfs_namelen &&
-			hs_namelen(fsp, dname, dnamelen) > fsp->hsfs_namelen) {
+		    hs_namelen(fsp, dname, dnamelen) > 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);
+			    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 */
@@ -1521,7 +1566,8 @@
 
 			rrip_name_str[0] = '\0';
 			rr_namelen = rrip_namecopy(nm, &rrip_name_str[0],
-			    &rrip_tmp_name[0], dirp, fsp, &hd);
+			    &rrip_tmp_name[0], dirp, last_offset - *offset,
+			    fsp, &hd);
 			if (hd.sym_link) {
 				kmem_free(hd.sym_link,
 				    (size_t)(hd.ext_size+1));
@@ -1566,7 +1612,7 @@
 			if (i > 0) {
 				dnamelen = i;
 			} else if (fsp->hsfs_vol_type != HS_VOL_TYPE_ISO_V2 &&
-				    fsp->hsfs_vol_type != HS_VOL_TYPE_JOLIET) {
+			    fsp->hsfs_vol_type != HS_VOL_TYPE_JOLIET) {
 				dnamelen = strip_trailing(fsp, dname, dnamelen);
 			}
 
@@ -1576,9 +1622,9 @@
 				(void) strncpy(uppercase_name, dname, dnamelen);
 			} else if (fsp->hsfs_vol_type == HS_VOL_TYPE_JOLIET) {
 				dnamelen = hs_joliet_cp(dname, uppercase_name,
-								dnamelen);
+				    dnamelen);
 			} else if (uppercase_cp(dname, uppercase_name,
-								dnamelen)) {
+			    dnamelen)) {
 				hs_log_bogus_disk_warning(fsp,
 				    HSFS_ERR_LOWER_CASE_NM, 0);
 			}
@@ -1609,7 +1655,7 @@
 			/* name matches */
 			parsedir_res = hs_parsedir(fsp, dirp, &hd,
 			    (char *)NULL, (int *)NULL,
-					last_offset - rel_offset(*offset));
+			    last_offset - *offset);
 			if (!parsedir_res) {
 				uint_t lbn;	/* logical block number */
 
@@ -1641,7 +1687,7 @@
 				PD_return(FOUND_ENTRY)
 			}
 		} else if (strict_iso9660_ordering && !is_rrip &&
-			!HSFS_HAVE_LOWER_CASE(fsp) && res < 0) {
+		    !HSFS_HAVE_LOWER_CASE(fsp) && res < 0) {
 			/* name < dir entry */
 			RESTORE_NM(rrip_tmp_name, nm);
 			PD_return(WENT_PAST)
--- a/usr/src/uts/common/fs/hsfs/hsfs_rrip.c	Tue Aug 14 19:57:00 2007 -0700
+++ b/usr/src/uts/common/fs/hsfs/hsfs_rrip.c	Wed Aug 15 05:40:25 2007 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -129,6 +129,11 @@
 	hdp->uid   = RRIP_UID(px_ptr);
 	hdp->gid   = RRIP_GID(px_ptr);
 
+	if (SUF_LEN(px_ptr) >= RRIP_PX_SIZE)
+		hdp->inode = (ino64_t)RRIP_INO(px_ptr);
+	else
+		hdp->inode = 0;
+
 	hdp->type = IFTOVT(hdp->mode);
 
 	return (px_ptr + SUF_LEN(px_ptr));
@@ -211,6 +216,9 @@
 	int		dst_size)	/* limit dest string to */
 						/* this value */
 {
+	size_t	off;
+	size_t	len;
+
 	if (IS_NAME_BIT_SET(rrip_flags, RRIP_NAME_ROOT))
 		(void) strcpy((char *)dst, "/");
 
@@ -249,17 +257,21 @@
 	 * Unfortunately, strlcat() cannot deal with input strings
 	 * that are not NULL-terminated - like SUA_string can be in
 	 * our case here. So we can't use it :(
-	 * We therefore have to emulate its behaviour using strncat(),
-	 * which will never access more bytes from the input string
-	 * than specified. Since strncat() doesn't necessarily NULL-
-	 * terminate the result, make sure we've got space for the
-	 * Nullbyte at the end.
+	 * Now strncat() doesn't work either - because it doesn't deal
+	 * with strings for which the 'potential NULL-termination' isn't
+	 * accessible - strncat(dst, NULL, 0) crashes although it copies
+	 * nothing in any case. If the SUA ends on a mapping boundary,
+	 * then telling strncat() to copy no more than the remaining bytes
+	 * in the buffer is of no avail if there's no NULL byte in them.
+	 *
+	 * Hence - binary copy. What are all these str* funcs for ??
 	 */
 	dst_size--;	/* trailing '\0' */
 
-	(void) strncat((char *)dst, (char *)SUA_string,
-	    MIN(dst_size - strlen((char *)dst), SUA_string_len));
-	dst[dst_size] = '\0';
+	off = strlen((char *)dst);
+	len = MIN(dst_size - off, SUA_string_len);
+	bcopy((char *)SUA_string, (char *)(dst + off), len);
+	dst[off + len] = '\0';
 	*dst_lenp = strlen((char *)dst);
 
 	if (IS_NAME_BIT_SET(rrip_flags, RRIP_NAME_CONTINUE))
@@ -357,8 +369,8 @@
 
 	/* for all components */
 	for (comp_ptr = RRIP_sl_comp(sl_ptr);
-		comp_ptr < (sl_ptr + SUF_LEN(sl_ptr));
-		comp_ptr += RRIP_COMP_LEN(comp_ptr)) {
+	    comp_ptr < (sl_ptr + SUF_LEN(sl_ptr));
+	    comp_ptr += RRIP_COMP_LEN(comp_ptr)) {
 
 		name_parse((int)RRIP_COMP_FLAGS(comp_ptr),
 		    RRIP_comp(comp_ptr),
@@ -372,7 +384,7 @@
 		 * And avoid 2 '//' in a row, or if '/' was wanted
 		 */
 		if (IS_NAME_BIT_SET(RRIP_COMP_FLAGS(comp_ptr),
-				    RRIP_NAME_CONTINUE) ||
+		    RRIP_NAME_CONTINUE) ||
 		    (sym_link[sym_link_len - 1] == '/')) {
 
 			sym_link[sym_link_len] = '\0';
@@ -433,6 +445,7 @@
 	char 	*to,			/* string to copy "from" to */
 	char  	*tmp_name,		/* temp storage for original name */
 	uchar_t	*dirp,			/* directory entry pointer */
+	uint_t	last_offset,		/* last index into current dir block */
 	struct 	hsfs *fsp,		/* filesystem pointer */
 	struct 	hs_direntry *hdp)	/* directory entry pointer to put */
 					/* all that good info in */
@@ -460,7 +473,8 @@
 	}
 
 
-	ret_val = parse_sua((uchar_t *)to, &size, &change_flag, dirp,
+	ret_val = parse_sua((uchar_t *)to, &size, &change_flag,
+			dirp, last_offset,
 			hdp, fsp, (uchar_t *)NULL, NULL);
 
 	if (IS_NAME_BIT_SET(change_flag, RRIP_NAME_CHANGE) && !ret_val)
--- a/usr/src/uts/common/fs/hsfs/hsfs_subr.c	Tue Aug 14 19:57:00 2007 -0700
+++ b/usr/src/uts/common/fs/hsfs/hsfs_subr.c	Wed Aug 15 05:40:25 2007 -0700
@@ -21,7 +21,7 @@
 /*
  * Miscellaneous support subroutines for High Sierra filesystem
  *
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -115,6 +115,16 @@
 		"has inconsistent data:",
 	"invalid directory or file name length (ignored)\n",
 	1, 0,
+	/* HSFS_ERR_NEG_SUA_LEN */
+	"hsfs: Warning: file system mounted on %s "
+		"has inconsistent Rock Ridge data:",
+	"negative SUA len\n",
+	1, 0,
+	/* HSFS_ERR_BAD_SUA_LEN */
+	"hsfs: Warning: file system mounted on %s "
+		"has inconsistent Rock Ridge data:",
+	"SUA len too big\n",
+	1, 0,
 };
 
 
--- a/usr/src/uts/common/fs/hsfs/hsfs_susp_subr.c	Tue Aug 14 19:57:00 2007 -0700
+++ b/usr/src/uts/common/fs/hsfs/hsfs_susp_subr.c	Wed Aug 15 05:40:25 2007 -0700
@@ -22,7 +22,7 @@
  * System Use Sharing protocol subroutines for High Sierra filesystem
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -84,6 +84,7 @@
 	int			*name_len_p,	/* location to put name len */
 	int			*name_change_p,	/* flags to signal name chg */
 	uchar_t			*dirp,		/* pointer to ISO dir entry */
+	uint_t			last_offset,	/* last ind. in cur. dirblock */
 	struct hs_direntry	*hdp,		/* loc to store dir info */
 	struct hsfs		*fsp,		/* filesystem pointer */
 	uchar_t			*search_sig,	/* signature to search for */
@@ -110,8 +111,15 @@
 	 * between sizes of SUA and ISO directory entry. This entry
 	 * is corrupted, return an appropriate error.
 	 */
-	if (SUA_len < 0)
+	if (SUA_len < 0) {
+		hs_log_bogus_disk_warning(fsp, HSFS_ERR_NEG_SUA_LEN, 0);
 		return (SUA_EINVAL);
+	}
+
+	if ((tmp_SUA_p + tmp_SUA_len) > (dirp + last_offset)) {
+		hs_log_bogus_disk_warning(fsp, HSFS_ERR_BAD_SUA_LEN, 0);
+		return (SUA_EINVAL);
+	}
 
 	/*
 	 * Make sure that the continuation lenth is zero, as that is
@@ -141,7 +149,7 @@
 
 	while (ret_val == -1) {
 		switch (parse_signatures(&sig_args, tmp_SUA_len, search_sig,
-					search_num)) {
+		    search_num)) {
 		case END_OF_SUA :
 			if (cont_info.cont_len) {
 
@@ -150,8 +158,8 @@
 					goto clean_up;
 				}
 
-				sig_args.SUF_ptr = cont_p +
-					cont_info.cont_offset;
+				sig_args.SUF_ptr =
+				    cont_p + cont_info.cont_offset;
 
 				tmp_SUA_len = cont_info.cont_len;
 				cont_info.cont_len = 0;
@@ -373,13 +381,13 @@
 	fsp = VFS_TO_HSFS(vp->v_vfsp);
 	secno = LBN_TO_SEC(hdp->ext_lbn+hdp->xar_len, vp->v_vfsp);
 	secoff = LBN_TO_BYTE(hdp->ext_lbn+hdp->xar_len, vp->v_vfsp) &
-		MAXHSOFFSET;
+	    MAXHSOFFSET;
 	secbp = bread(fsp->hsfs_devvp->v_rdev, secno * 4, HS_SECTOR_SIZE);
 	error = geterror(secbp);
 
 	if (error != 0) {
 		cmn_err(CE_NOTE,
-			"hs_check_root_dirent: bread: error=(%d)", error);
+		    "hs_check_root_dirent: bread: error=(%d)", error);
 		goto end;
 	}
 
@@ -409,7 +417,7 @@
 		goto end;
 
 	if (strncmp(SUSP_SP, (char *)IDE_sys_use_area(root_ptr),
-		    SUF_SIG_LEN) == 0) {
+	    SUF_SIG_LEN) == 0) {
 		/*
 		 * We have a match of the sharing signature, so let's
 		 * call the sig_handler to do what is necessary. We can
@@ -421,11 +429,24 @@
 		if ((susp_sp->sig_handler)(&sig_args) == (uchar_t *)NULL) {
 			goto end;
 		}
-	} else
+	} else {
 		goto end;
+	}
 
-	(void) hs_parsedir(fsp, root_ptr, hdp, (char *)NULL, (int *)NULL,
-					HS_SECTOR_SIZE - secoff);
+	/*
+	 * If the "ER" signature in the root directory is past any non SU
+	 * signature, the Rock Ridge signatures will be ignored. This happens
+	 * e.g. for filesystems created by mkisofs. In this case,
+	 * IS_RRIP_IMPLEMENTED(fsp) will return 0 when the "ER" signature is
+	 * parsed. Unfortunately, the results of this run will be cached for
+	 * the root vnode. The solution is to run hs_parsedir() a second time
+	 * for the root directory.
+	 */
+	if (hs_parsedir(fsp, root_ptr, hdp, (char *)NULL, (int *)NULL,
+	    HS_SECTOR_SIZE - secoff) == 0) {
+		(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
@@ -503,21 +524,21 @@
 		bzero((char *)*buf_pp, HS_SECTOR_SIZE);
 		partial_size = HS_SECTOR_SIZE - cont_info_p->cont_offset;
 		bcopy(&secbp->b_un.b_addr[cont_info_p->cont_offset],
-			(char *)*buf_pp, partial_size);
+		    (char *)*buf_pp, partial_size);
 		cont_info_p->cont_offset = 0;
 		brelse(secbp);
 
 		secbp = bread(fsp->hsfs_devvp->v_rdev, (secno + 1) * 4,
-				HS_SECTOR_SIZE);
+		    HS_SECTOR_SIZE);
 		error = geterror(secbp);
 		if (error != 0) {
 			cmn_err(CE_NOTE, "get_cont_area: bread(2): error=(%d)",
-				error);
+			    error);
 			brelse(secbp);
 			return (1);
 		}
 		bcopy(secbp->b_un.b_addr, (char *)&(*buf_pp)[partial_size],
-			cont_info_p->cont_len - partial_size);
+		    cont_info_p->cont_len - partial_size);
 	}
 
 	brelse(secbp);
--- a/usr/src/uts/common/fs/hsfs/hsfs_vfsops.c	Tue Aug 14 19:57:00 2007 -0700
+++ b/usr/src/uts/common/fs/hsfs/hsfs_vfsops.c	Wed Aug 15 05:40:25 2007 -0700
@@ -305,25 +305,25 @@
 	 */
 	flags = 0;
 	if (vfs_optionisset(vfsp, HOPT_NOMAPLCASE, NULL))
-	    flags |= HSFSMNT_NOMAPLCASE;
+		flags |= HSFSMNT_NOMAPLCASE;
 	if (vfs_optionisset(vfsp, HOPT_NOTRAILDOT, NULL))
-	    flags |= HSFSMNT_NOTRAILDOT;
+		flags |= HSFSMNT_NOTRAILDOT;
 	if (vfs_optionisset(vfsp, HOPT_NRR, NULL))
-	    flags |= HSFSMNT_NORRIP;
+		flags |= HSFSMNT_NORRIP;
 	if (vfs_optionisset(vfsp, HOPT_NOJOLIET, NULL))
-	    flags |= HSFSMNT_NOJOLIET;
+		flags |= HSFSMNT_NOJOLIET;
 	if (vfs_optionisset(vfsp, HOPT_JOLIETLONG, NULL))
-	    flags |= HSFSMNT_JOLIETLONG;
+		flags |= HSFSMNT_JOLIETLONG;
 	if (vfs_optionisset(vfsp, HOPT_NOVERS2, NULL))
-	    flags |= HSFSMNT_NOVERS2;
+		flags |= HSFSMNT_NOVERS2;
 
 	error = pn_get(uap->dir, (uap->flags & MS_SYSSPACE) ?
 	    UIO_SYSSPACE : UIO_USERSPACE, &dpn);
 	if (error)
 		return (error);
 
-	if ((error = hs_getmdev(vfsp, uap->spec, uap->flags, &dev,
-		&mode, cr)) != 0) {
+	error = hs_getmdev(vfsp, uap->spec, uap->flags, &dev, &mode, cr);
+	if (error != 0) {
 		pn_free(&dpn);
 		return (error);
 	}
@@ -392,12 +392,11 @@
 	VN_RELE(fsp->hsfs_devvp);
 	/* free path table space */
 	if (fsp->hsfs_ptbl != NULL)
-		kmem_free(fsp->hsfs_ptbl,
-			(size_t)fsp->hsfs_vol.ptbl_len);
+		kmem_free(fsp->hsfs_ptbl, (size_t)fsp->hsfs_vol.ptbl_len);
 	/* free path table index table */
 	if (fsp->hsfs_ptbl_idx != NULL)
 		kmem_free(fsp->hsfs_ptbl_idx, (size_t)
-			(fsp->hsfs_ptbl_idx_size * sizeof (struct ptable_idx)));
+		    (fsp->hsfs_ptbl_idx_size * sizeof (struct ptable_idx)));
 
 	/* free "mounted on" pathame */
 	if (fsp->hsfs_fsmnt != NULL)
@@ -476,9 +475,10 @@
 
 	rw_enter(&fsp->hsfs_hash_lock, RW_READER);
 
-	nodeid = (ino64_t)MAKE_NODEID(fid->hf_dir_lbn, fid->hf_dir_off, vfsp);
+	nodeid = fid->hf_ino;
 
-	if ((*vpp = hs_findhash(nodeid, vfsp)) == NULL) {
+	if ((*vpp = hs_findhash(nodeid, fid->hf_dir_lbn,
+	    (uint_t)fid->hf_dir_off, vfsp)) == NULL) {
 		/*
 		 * Not in cache, so we need to remake it.
 		 * hs_remakenode() will read the directory entry
@@ -883,7 +883,10 @@
 		break;
 	}
 
-	fsp->hsfs_flags = mount_flags;
+	/*
+	 * Add the HSFSMNT_INODE pseudo mount flag to the current mount flags.
+	 */
+	fsp->hsfs_flags = mount_flags | (fsp->hsfs_flags & HSFSMNT_INODE);
 
 	DTRACE_PROBE1(mount__done, struct hsfs *, fsp);
 
@@ -893,6 +896,9 @@
 	fsp->hsfs_magic = HSFS_MAGIC;
 	mutex_exit(&hs_mounttab_lock);
 
+	kmem_free(svp, sizeof (*svp));
+	kmem_free(jvp, sizeof (*jvp));
+
 	return (0);
 
 cleanup:
@@ -929,7 +935,7 @@
 	if (!hsfs_valid_dir(&fsp->hsfs_vol.root_dir)) {
 		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)) {
+		    (uint_t)0, vfsp, &fsp->hsfs_rootvp)) {
 			hs_mounttab = hs_mounttab->hsfs_next;
 			mutex_destroy(&fsp->hsfs_free_lock);
 			rw_destroy(&fsp->hsfs_hash_lock);
@@ -939,7 +945,7 @@
 		}
 	} else {
 		fsp->hsfs_rootvp = hs_makenode(&fsp->hsfs_vol.root_dir,
-			fsp->hsfs_vol.root_dir.ext_lbn, 0, vfsp);
+		    fsp->hsfs_vol.root_dir.ext_lbn, 0, vfsp);
 	}
 
 	/* XXX - ignore the path table for now */
@@ -963,6 +969,7 @@
 {
 	struct buf *secbp;
 	int i;
+	int n;
 	uchar_t *volp;
 	int error;
 	uint_t secno;
@@ -979,7 +986,12 @@
 
 	volp = (uchar_t *)secbp->b_un.b_addr;
 
-	while (HSV_DESC_TYPE(volp) != VD_EOV) {
+	/*
+	 * To avoid that we read the whole medium in case that someone prepares
+	 * a malicious "fs image", we read at most 32 blocks.
+	 */
+	for (n = 0; n < 32 &&
+	    HSV_DESC_TYPE(volp) != VD_EOV; n++) {
 		for (i = 0; i < HSV_ID_STRLEN; i++)
 			if (HSV_STD_ID(volp)[i] != HSV_ID_STRING[i])
 				goto cantfind;
@@ -1008,7 +1020,7 @@
 
 		if (error != 0) {
 			cmn_err(CE_NOTE, "hs_findhsvol: bread: error=(%d)",
-				error);
+			    error);
 			brelse(secbp);
 			return (error);
 		}
@@ -1035,12 +1047,12 @@
 	hvp->lbn_size = HSV_BLK_SIZE(volp);
 	if (hvp->lbn_size == 0) {
 		cmn_err(CE_NOTE, "hs_parsehsvol: logical block size in the "
-			"SFSVD is zero");
+		    "SFSVD is zero");
 		return (EINVAL);
 	}
 	hvp->lbn_shift = ffs((long)hvp->lbn_size) - 1;
-	hvp->lbn_secshift = ffs((long)howmany(HS_SECTOR_SIZE,
-				(int)hvp->lbn_size)) - 1;
+	hvp->lbn_secshift =
+	    ffs((long)howmany(HS_SECTOR_SIZE, (int)hvp->lbn_size)) - 1;
 	hvp->lbn_maxoffset = hvp->lbn_size - 1;
 	hs_parse_longdate(HSV_cre_date(volp), &hvp->cre_date);
 	hs_parse_longdate(HSV_mod_date(volp), &hvp->mod_date);
@@ -1060,12 +1072,12 @@
 	 */
 	if (hvp->lbn_size & ~(1 << hvp->lbn_shift)) {
 		cmn_err(CE_NOTE,
-			"hsfs: %d-byte logical block size not supported",
-			hvp->lbn_size);
+		    "hsfs: %d-byte logical block size not supported",
+		    hvp->lbn_size);
 		return (EINVAL);
 	}
 	return (hs_parsedir(fsp, HSV_ROOT_DIR(volp), &hvp->root_dir,
-			(char *)NULL, (int *)NULL, HDE_ROOT_DIR_REC_SIZE));
+	    (char *)NULL, (int *)NULL, HDE_ROOT_DIR_REC_SIZE));
 }
 
 /*
@@ -1087,12 +1099,14 @@
 {
 	struct buf *secbp;
 	int i;
+	int n;
 	uchar_t *volp;
 	int error;
 	uint_t secno;
 	int foundpvd = 0;
 	int foundsvd = 0;
 	int foundjvd = 0;
+	int pvd_sum = 0;
 
 	secno = hs_findvoldesc(vp->v_rdev, ISO_VOLDESC_SEC);
 	secbp = bread(vp->v_rdev, secno * 4, ISO_SECTOR_SIZE);
@@ -1106,7 +1120,12 @@
 
 	volp = (uchar_t *)secbp->b_un.b_addr;
 
-	while ((enum iso_voldesc_type) ISO_DESC_TYPE(volp) != ISO_VD_EOV) {
+	/*
+	 * To avoid that we read the whole medium in case that someone prepares
+	 * a malicious "fs image", we read at most 32 blocks.
+	 */
+	for (n = 0; n < 32 &&
+	    (enum iso_voldesc_type) ISO_DESC_TYPE(volp) != ISO_VD_EOV; n++) {
 		for (i = 0; i < ISO_ID_STRLEN; i++)
 			if (ISO_STD_ID(volp)[i] != ISO_ID_STRING[i])
 				goto cantfind;
@@ -1122,6 +1141,8 @@
 					return (error);
 				}
 				foundpvd = 1;
+				for (i = 0; i < ISO_SECTOR_SIZE; i++)
+					pvd_sum += volp[i];
 			}
 			break;
 		case ISO_VD_SVD:
@@ -1159,13 +1180,45 @@
 
 		if (error != 0) {
 			cmn_err(CE_NOTE, "hs_findisovol: bread: error=(%d)",
-				    error);
+			    error);
 			brelse(secbp);
 			return (error);
 		}
 
 		volp = (uchar_t *)secbp->b_un.b_addr;
 	}
+	for (n = 0; n < 16; n++) {
+		brelse(secbp);
+		++secno;
+		secbp = bread(vp->v_rdev, secno * 4, HS_SECTOR_SIZE);
+		error = geterror(secbp);
+
+		if (error != 0) {
+			cmn_err(CE_NOTE, "hs_findisovol: bread: error=(%d)",
+			    error);
+			brelse(secbp);
+			return (error);
+		}
+
+		/*
+		 * Check for the signature from mkisofs that grants that
+		 * the current filesystem allows to use the extent lbn as
+		 * inode number even in pure ISO9660 mode.
+		 */
+		volp = (uchar_t *)secbp->b_un.b_addr;
+		if (strncmp((char *)volp, "MKI ", 4) == 0) {
+			int	sum;
+
+			sum  = volp[2045];
+			sum *= 256;
+			sum += volp[2046];
+			sum *= 256;
+			sum += volp[2047];
+			if (sum == pvd_sum)
+				fsp->hsfs_flags |= HSFSMNT_INODE;
+			break;
+		}
+	}
 	if (foundpvd) {
 		brelse(secbp);
 		return (0);
@@ -1212,12 +1265,12 @@
 	hvp->lbn_size = ISO_BLK_SIZE(volp);
 	if (hvp->lbn_size == 0) {
 		cmn_err(CE_NOTE, "hs_parseisovol: logical block size in the "
-			"PVD is zero");
+		    "PVD is zero");
 		return (EINVAL);
 	}
 	hvp->lbn_shift = ffs((long)hvp->lbn_size) - 1;
-	hvp->lbn_secshift = ffs((long)howmany(ISO_SECTOR_SIZE,
-				(int)hvp->lbn_size)) - 1;
+	hvp->lbn_secshift =
+	    ffs((long)howmany(ISO_SECTOR_SIZE, (int)hvp->lbn_size)) - 1;
 	hvp->lbn_maxoffset = hvp->lbn_size - 1;
 	hs_parse_longdate(ISO_cre_date(volp), &hvp->cre_date);
 	hs_parse_longdate(ISO_mod_date(volp), &hvp->mod_date);
@@ -1237,12 +1290,12 @@
 	 */
 	if (hvp->lbn_size & ~(1 << hvp->lbn_shift)) {
 		cmn_err(CE_NOTE,
-			"hsfs: %d-byte logical block size not supported",
-			hvp->lbn_size);
+		    "hsfs: %d-byte logical block size not supported",
+		    hvp->lbn_size);
 		return (EINVAL);
 	}
 	return (hs_parsedir(fsp, ISO_ROOT_DIR(volp), &hvp->root_dir,
-			(char *)NULL, (int *)NULL, IDE_ROOT_DIR_REC_SIZE));
+	    (char *)NULL, (int *)NULL, IDE_ROOT_DIR_REC_SIZE));
 }
 
 /*
@@ -1393,15 +1446,18 @@
 	fvolp = &fsp->hsfs_vol;
 #ifdef HSFS_CLKSET
 	if (fvolp->cre_date.tv_sec == 0) {
-	    cmn_err(CE_NOTE, "hsfs_mountroot: cre_date.tv_sec == 0");
-	    if (fvolp->mod_date.tv_sec == 0) {
-		cmn_err(CE_NOTE, "hsfs_mountroot: mod_date.tv_sec == 0");
-		cmn_err(CE_NOTE, "hsfs_mountroot: clkset(-1L)");
-		clkset(-1L);
-	    } else
+		cmn_err(CE_NOTE, "hsfs_mountroot: cre_date.tv_sec == 0");
+		if (fvolp->mod_date.tv_sec == 0) {
+			cmn_err(CE_NOTE,
+			    "hsfs_mountroot: mod_date.tv_sec == 0");
+			cmn_err(CE_NOTE, "hsfs_mountroot: clkset(-1L)");
+			clkset(-1L);
+		} else {
+			clkset(fvolp->mod_date.tv_sec);
+		}
+	} else {
 		clkset(fvolp->mod_date.tv_sec);
-	} else
-	    clkset(fvolp->mod_date.tv_sec);
+	}
 #else	/* HSFS_CLKSET */
 	clkset(-1L);
 #endif	/* HSFS_CLKSET */
--- a/usr/src/uts/common/fs/hsfs/hsfs_vnops.c	Tue Aug 14 19:57:00 2007 -0700
+++ b/usr/src/uts/common/fs/hsfs/hsfs_vnops.c	Wed Aug 15 05:40:25 2007 -0700
@@ -83,6 +83,13 @@
 
 #include <fs/fs_subr.h>
 
+/*
+ * This tunable allows us to ignore inode numbers from rrip-1.12.
+ * In this case, we fall back to our default inode algorithm.
+ */
+extern int use_rrip_inodes;
+
+
 /* ARGSUSED */
 static int
 hsfs_fsync(vnode_t *cp, int syncflag, cred_t *cred)
@@ -376,7 +383,6 @@
 	size_t		dname_size;
 	struct fbuf	*fbp;
 	uint_t		last_offset;	/* last index into current dir block */
-	ulong_t		dir_lbn;	/* lbn of directory */
 	ino64_t		dirino;	/* temporary storage before storing in dirent */
 	off_t		diroff;
 
@@ -385,7 +391,6 @@
 	if (dhp->hs_dirent.ext_size == 0)
 		hs_filldirent(vp, &dhp->hs_dirent);
 	dirsiz = dhp->hs_dirent.ext_size;
-	dir_lbn = dhp->hs_dirent.ext_lbn;
 	if (uiop->uio_loffset >= dirsiz) {	/* at or beyond EOF */
 		if (eofp)
 			*eofp = 1;
@@ -405,7 +410,7 @@
 		bytes_wanted = MIN(MAXBSIZE, dirsiz - (offset & MAXBMASK));
 
 		error = fbread(vp, (offset_t)(offset & MAXBMASK),
-			(unsigned int)bytes_wanted, S_READ, &fbp);
+		    (unsigned int)bytes_wanted, S_READ, &fbp);
 		if (error)
 			goto done;
 
@@ -425,7 +430,7 @@
 			 * a single utility function.
 			 */
 			hdlen = (int)((uchar_t)
-				HDE_DIR_LEN(&blkp[rel_offset(offset)]));
+			    HDE_DIR_LEN(&blkp[rel_offset(offset)]));
 			if (hdlen < HDE_ROOT_DIR_REC_SIZE ||
 			    offset + hdlen > last_offset) {
 				/*
@@ -446,8 +451,7 @@
 			 * XXX - maybe hs_parsedir() will detect EXISTENCE bit
 			 */
 			if (!hs_parsedir(fsp, &blkp[rel_offset(offset)],
-				&hd, dname, &dnamelen,
-					last_offset - rel_offset(offset))) {
+			    &hd, dname, &dnamelen, last_offset - offset)) {
 				/*
 				 * Determine if there is enough room
 				 */
@@ -461,34 +465,28 @@
 
 				diroff = offset + hdlen;
 				/*
-				 * Generate nodeid.
-				 * If a directory, nodeid points to the
-				 * canonical dirent describing the directory:
-				 * the dirent of the "." entry for the
-				 * directory, which is pointed to by all
-				 * dirents for that directory.
-				 * Otherwise, nodeid points to dirent of file.
+				 * If the media carries rrip-v1.12 or newer,
+				 * and we trust the inodes from the rrip data
+				 * (use_rrip_inodes != 0), use that data. If the
+				 * media has been created by a recent mkisofs
+				 * version, we may trust all numbers in the
+				 * starting extent number; otherwise, we cannot
+				 * do this for zero sized files and symlinks,
+				 * because if we did we'd end up mapping all of
+				 * them to the same node. We use HS_DUMMY_INO
+				 * in this case and make sure that we will not
+				 * map all files to the same meta data.
 				 */
-				if (hd.type == VDIR) {
-					dirino = (ino64_t)
-					    MAKE_NODEID(hd.ext_lbn, 0,
-					    vp->v_vfsp);
+				if (hd.inode != 0 && use_rrip_inodes) {
+					dirino = hd.inode;
+				} else if ((hd.ext_size == 0 ||
+				    hd.sym_link != (char *)NULL) &&
+				    (fsp->hsfs_flags & HSFSMNT_INODE) == 0) {
+					dirino = HS_DUMMY_INO;
 				} else {
-					struct hs_volume *hvp;
-					offset_t lbn, off;
-
-					/*
-					 * Normalize lbn and off
-					 */
-					hvp = &fsp->hsfs_vol;
-					lbn = dir_lbn +
-					    (offset >> hvp->lbn_shift);
-					off = offset & hvp->lbn_maxoffset;
-					dirino = (ino64_t)MAKE_NODEID(lbn,
-					    off, vp->v_vfsp);
+					dirino = hd.ext_lbn;
 				}
 
-
 				/* strncpy(9f) will zero uninitialized bytes */
 
 				ASSERT(strlen(dname) + 1 <=
@@ -557,6 +555,7 @@
 	mutex_enter(&hp->hs_contents_lock);
 	fid->hf_dir_lbn = hp->hs_dir_lbn;
 	fid->hf_dir_off = (ushort_t)hp->hs_dir_off;
+	fid->hf_ino = hp->hs_nodeid;
 	mutex_exit(&hp->hs_contents_lock);
 	return (0);
 }
@@ -717,8 +716,8 @@
 	if (hp->hs_dirent.intlf_sz == 0) {
 		chunk_data_bytes = LBN_TO_BYTE(1, vp->v_vfsp);
 	} else {
-		chunk_data_bytes = LBN_TO_BYTE(hp->hs_dirent.intlf_sz,
-			vp->v_vfsp);
+		chunk_data_bytes =
+		    LBN_TO_BYTE(hp->hs_dirent.intlf_sz, vp->v_vfsp);
 	}
 
 reread:
@@ -824,8 +823,7 @@
 		searchp = pp;
 		io_end = io_off + io_len;
 		for (count = 0, byte_offset = io_off;
-			byte_offset < io_end;
-			count++) {
+		    byte_offset < io_end; count++) {
 			ASSERT(count < bufcnt);
 
 			/* Compute disk address for interleaving. */
@@ -843,14 +841,13 @@
 			offset_extra = byte_offset % chunk_data_bytes;
 
 			/* get virtual block number for driver */
-			driver_block = lbtodb(bof + xarsiz
-				+ offset_bytes + offset_extra);
+			driver_block =
+			    lbtodb(bof + xarsiz + offset_bytes + offset_extra);
 
 			if (lastp != searchp) {
 				/* this branch taken first time through loop */
-				va = vas[count]
-					= ppmapin(searchp, PROT_WRITE,
-						(caddr_t)-1);
+				va = vas[count] =
+				    ppmapin(searchp, PROT_WRITE, (caddr_t)-1);
 				/* ppmapin() guarantees not to return NULL */
 			} else {
 				vas[count] = NULL;
@@ -868,9 +865,9 @@
 
 			bufs[count].b_lblkno = driver_block;
 
-			remaining_bytes = ((which_chunk_lbn + 1)
-				* chunk_data_bytes)
-				- byte_offset;
+			remaining_bytes =
+			    ((which_chunk_lbn + 1) * chunk_data_bytes)
+			    - byte_offset;
 
 			/*
 			 * remaining_bytes can't be zero, as we derived
@@ -905,7 +902,7 @@
 
 			bufs[count].b_bufsize = bufs[count].b_bcount;
 			if (((offset_t)byte_offset + bufs[count].b_bcount) >
-				HS_MAXFILEOFF) {
+			    HS_MAXFILEOFF) {
 				break;
 			}
 			byte_offset += bufs[count].b_bcount;
@@ -976,7 +973,7 @@
 		for (soff = off + PAGESIZE; plsz > 0;
 		    soff += PAGESIZE, plsz -= PAGESIZE) {
 			pp = page_lookup_nowait(vp, (u_offset_t)soff,
-					SE_SHARED);
+			    SE_SHARED);
 			if (pp == NULL)
 				break;
 			pl[index++] = pp;
@@ -1100,10 +1097,9 @@
 	if (!vn_has_cached_data(vp))	/* no pages mapped */
 		return (0);
 
-	if (len == 0)		/* from 'off' to EOF */
-		error = pvn_vplist_dirty(vp, off,
-					hsfs_putapage, flags, cr);
-	else {
+	if (len == 0) {		/* from 'off' to EOF */
+		error = pvn_vplist_dirty(vp, off, hsfs_putapage, flags, cr);
+	} else {
 		offset_t end_off = off + len;
 		offset_t file_size = VTOH(vp)->hs_dirent.ext_size;
 		offset_t io_off;
@@ -1122,11 +1118,11 @@
 			 */
 			if ((flags & B_INVAL) || ((flags & B_ASYNC) == 0)) {
 				pp = page_lookup(vp, io_off,
-					(flags & (B_INVAL | B_FREE)) ?
-					    SE_EXCL : SE_SHARED);
+				    (flags & (B_INVAL | B_FREE)) ?
+				    SE_EXCL : SE_SHARED);
 			} else {
 				pp = page_lookup_nowait(vp, io_off,
-					(flags & B_FREE) ? SE_EXCL : SE_SHARED);
+				    (flags & B_FREE) ? SE_EXCL : SE_SHARED);
 			}
 
 			if (pp == NULL)
@@ -1142,7 +1138,7 @@
 			 */
 			if (pvn_getdirty(pp, flags) == 1) {
 				cmn_err(CE_NOTE,
-					"hsfs_putpage: dirty HSFS page");
+				    "hsfs_putpage: dirty HSFS page");
 				pvn_write_done(pp, flags |
 				    B_ERROR | B_WRITE | B_INVAL | B_FORCE);
 			}
--- a/usr/src/uts/common/sys/fs/hsfs_impl.h	Tue Aug 14 19:57:00 2007 -0700
+++ b/usr/src/uts/common/sys/fs/hsfs_impl.h	Wed Aug 15 05:40:25 2007 -0700
@@ -22,7 +22,7 @@
  * High Sierra filesystem internal routine definitions.
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -53,7 +53,8 @@
 extern int hs_dirlook(struct vnode *dvp, char *name, int namlen,
 	struct vnode **vpp, struct cred *cred);
 /* find an hsnode in the hash list */
-extern struct vnode *hs_findhash(ino64_t nodeid, struct vfs *vfsp);
+extern struct vnode *hs_findhash(ino64_t nodeid, uint_t lbn, uint_t off,
+	struct vfs *vfsp);
 /* destroy an hsnode */
 extern void hs_freenode(vnode_t *vp, struct hsfs *fsp, int nopage);
 /* parse a directory entry */
--- a/usr/src/uts/common/sys/fs/hsfs_node.h	Tue Aug 14 19:57:00 2007 -0700
+++ b/usr/src/uts/common/sys/fs/hsfs_node.h	Wed Aug 15 05:40:25 2007 -0700
@@ -22,7 +22,7 @@
  * High Sierra filesystem structure definitions
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -46,6 +46,7 @@
 	uint_t		nlink;		/* no. of links to file */
 	uid_t		uid;		/* owner's user id */
 	gid_t		gid;		/* owner's group id */
+	ino64_t		inode;		/* inode number from rrip data */
 	dev_t		r_dev;		/* major/minor device numbers */
 	uint_t		xar_prot :1;	/* 1 if protection in XAR */
 	uchar_t		xar_len;	/* no. of Logical blocks in XAR */
@@ -114,6 +115,7 @@
 	ushort_t	hf_len;		/* length of fid */
 	ushort_t	hf_dir_off;	/* offset in LBN of directory entry */
 	uint_t		hf_dir_lbn;	/* LBN of directory */
+	uint32_t	hf_ino;		/* The inode number or HS_DUMMY_INO */
 };
 
 
@@ -152,6 +154,17 @@
 #define	HS_HSNODESPACE	16384		/* approx. space used for hsnodes */
 
 /*
+ * We usually use the starting extent LBA for the inode numbers of files and
+ * directories. As this will not work for zero sized files, we assign a dummy
+ * inode number to all zero sized files. We use the number 16 as this is the
+ * LBA for the PVD, this number cannot be a valid starting extent LBA for a
+ * file. In case that the node number is the HS_DUMMY_INO, we use the LBA and
+ * offset of the directory entry of this file (which is what we used before
+ * we started to support correct hard links).
+ */
+#define	HS_DUMMY_INO	16	/* dummy inode number for empty files */
+
+/*
  * High Sierra filesystem structure.
  * There is one of these for each mounted High Sierra filesystem.
  */
@@ -200,6 +213,8 @@
 #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_ERR_NEG_SUA_LEN		8
+#define	HSFS_ERR_BAD_SUA_LEN		9
 
 #define	HSFS_HAVE_LOWER_CASE(fsp) \
 	((fsp)->hsfs_err_flags & (1 << HSFS_ERR_LOWER_CASE_NM))
@@ -241,18 +256,6 @@
 #define	BYTE_TO_LBN(boff, vfsp)	((boff)>>((struct hsfs *)((vfsp)->vfs_data))-> \
 				hsfs_vol.lbn_shift)
 
-/*
- * Create a nodeid.
- * We construct the nodeid from the location of the directory
- * entry which points to the file.  We divide by 32 to
- * compress the range of nodeids; we know that the minimum size
- * for an ISO9660 dirent is 34, so we will never have adjacent
- * dirents with the same nodeid.
- */
-#define	HSFS_MIN_DL_SHFT	5
-#define	MAKE_NODEID(lbn, off, vfsp) \
-		((LBN_TO_BYTE((lbn), (vfsp)) + (off)) >> HSFS_MIN_DL_SHFT)
-
 #ifdef	__cplusplus
 }
 #endif
--- a/usr/src/uts/common/sys/fs/hsfs_rrip.h	Tue Aug 14 19:57:00 2007 -0700
+++ b/usr/src/uts/common/sys/fs/hsfs_rrip.h	Wed Aug 15 05:40:25 2007 -0700
@@ -22,7 +22,7 @@
  * ISO 9660 RRIP extension filesystem specifications
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -48,6 +48,8 @@
 #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		 */
+#define	HSFSMNT_INODE		0x1000	/* May use ext_lbn as inode #, */
+					/* FS is from a recent mkisofs */
 
 /*
  * XXX: The following flag was used in the past to instruct the kernel to
@@ -177,6 +179,12 @@
 #define	RRIP_gid(x)		(&((uchar_t *)x)[28])
 #define	RRIP_GID(x)		(gid_t)BOTH_INT(RRIP_gid(x))
 
+#define	RRIP_ino(x)		(&((uchar_t *)x)[36])
+#define	RRIP_INO(x)		(uint32_t)BOTH_INT(RRIP_ino(x))
+
+#define	RRIP_PX_OLD_SIZE	36
+#define	RRIP_PX_SIZE		44
+
 /*
  * "PN" Posix major/minor numbers
  */
@@ -290,7 +298,8 @@
 extern uchar_t *rrip_reloc_dir(sig_args_t *);
 extern uchar_t *rrip_rock_ridge(sig_args_t *);
 extern void hs_check_root_dirent(struct vnode *vp, struct hs_direntry *hdp);
-extern int rrip_namecopy(char *from, char *to, char *tmp_name, uchar_t *dirp,
+extern int rrip_namecopy(char *from, char *to, char *tmp_name,
+				uchar_t *dirp, uint_t last_offset,
 				struct hsfs *fsp, struct hs_direntry *hdp);
 #endif	/* _KERNEL */
 
--- a/usr/src/uts/common/sys/fs/hsfs_susp.h	Tue Aug 14 19:57:00 2007 -0700
+++ b/usr/src/uts/common/sys/fs/hsfs_susp.h	Wed Aug 15 05:40:25 2007 -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,8 @@
  */
 /*
  * ISO 9660 RRIP extension filesystem specifications
- * Copyright (c) 1991,1997-1998,2000 by Sun Microsystems, Inc.
- * All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
  */
 
 #ifndef	_SYS_FS_HSFS_SUSP_H
@@ -249,8 +248,8 @@
 
 extern ext_signature_t		*susp_sp;
 
-extern int parse_sua(uchar_t *, int *name_len_p, int *, uchar_t *, struct
-	hs_direntry *,	struct hsfs *,	uchar_t	*, int search_num);
+extern int parse_sua(uchar_t *, int *name_len_p, int *, uchar_t *, uint_t,
+	struct hs_direntry *,	struct hsfs *,	uchar_t	*, int search_num);
 
 #endif	/* _KERNEL */