Index: trunk/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c
===================================================================
--- trunk/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c	(revision 39267)
+++ trunk/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.c	(revision 39270)
@@ -528,4 +528,15 @@
 }
 
+static void
+sfprov_stat_from_info(sffs_stat_t *stat, SHFLFSOBJINFO *info)
+{
+	sfprov_mode_from_fmode(&stat->sf_mode, info->Attr.fMode);
+	stat->sf_size  = info->cbObject;
+	stat->sf_alloc = info->cbAllocated;
+	sfprov_ftime_from_timespec(&stat->sf_atime, &info->AccessTime);
+	sfprov_ftime_from_timespec(&stat->sf_mtime, &info->ModificationTime);
+	sfprov_ftime_from_timespec(&stat->sf_ctime, &info->ChangeTime);
+}
+
 int
 sfprov_get_atime(sfp_mount_t *mnt, char *path, timestruc_t *time)
@@ -568,12 +579,5 @@
 
 int
-sfprov_get_attr(
-	sfp_mount_t *mnt,
-	char *path,
-	mode_t *mode,
-	uint64_t *size,
-	timestruc_t *atime,
-	timestruc_t *mtime,
-	timestruc_t *ctime)
+sfprov_get_attr(sfp_mount_t *mnt, char *path, sffs_stat_t *attr)
 {
 	int rc;
@@ -583,16 +587,5 @@
 	if (rc)
 		return (rc);
-
-	if (mode)
-		sfprov_mode_from_fmode(mode, info.Attr.fMode);
-	if (size != NULL)
-		*size = info.cbObject;
-	if (atime != NULL)
-		sfprov_ftime_from_timespec(atime, &info.AccessTime);
-	if (mtime != NULL)
-		sfprov_ftime_from_timespec(mtime, &info.ModificationTime);
-	if (ctime != NULL)
-		sfprov_ftime_from_timespec(ctime, &info.ChangeTime);
-
+	sfprov_stat_from_info(attr, &info);
 	return (0);
 }
@@ -800,5 +793,17 @@
 
 int
-sfprov_remove(sfp_mount_t *mnt, char *path)
+sfprov_set_show_symlinks(void)
+{
+	int rc;
+
+	rc = vboxCallSetSymlinks(&vbox_client);
+	if (RT_FAILURE(rc))
+		return (sfprov_vbox2errno(rc));
+
+	return (0);
+}
+
+int
+sfprov_remove(sfp_mount_t *mnt, char *path, uint_t is_link)
 {
 	int rc;
@@ -807,9 +812,63 @@
 
 	str = sfprov_string(path, &size);
-	rc = vboxCallRemove(&vbox_client, &mnt->map, str, SHFL_REMOVE_FILE);
+	rc = vboxCallRemove(&vbox_client, &mnt->map, str,
+		SHFL_REMOVE_FILE | (is_link ? SHFL_REMOVE_SYMLINK : 0));
 	kmem_free(str, size);
 	if (RT_FAILURE(rc))
 		return (sfprov_vbox2errno(rc));
 	return (0);
+}
+
+int
+sfprov_readlink(
+	sfp_mount_t *mnt,
+	char *path,
+	char *target,
+	size_t tgt_size)
+{
+	int rc;
+	SHFLSTRING *str;
+	int size;
+
+	str = sfprov_string(path, &size);
+
+	rc = vboxReadLink(&vbox_client, &mnt->map, str, (uint32_t) tgt_size,
+	    target);
+	if (RT_FAILURE(rc))
+		rc = sfprov_vbox2errno(rc);
+
+	kmem_free(str, size);
+	return (rc);
+}
+
+int
+sfprov_symlink(
+	sfp_mount_t *mnt,
+	char *linkname,
+	char *target,
+	sffs_stat_t *stat)
+{
+	int rc;
+	SHFLSTRING *lnk, *tgt;
+	int lnk_size, tgt_size;
+	SHFLFSOBJINFO info;
+
+	lnk = sfprov_string(linkname, &lnk_size);
+	tgt = sfprov_string(target, &tgt_size);
+
+	rc = vboxCallSymlink(&vbox_client, &mnt->map, lnk, tgt, &info);
+	if (RT_FAILURE(rc)) {
+		rc = sfprov_vbox2errno(rc);
+		goto done;
+	}
+
+	if (stat != NULL)
+		sfprov_stat_from_info(stat, &info);
+
+done:
+	kmem_free(lnk, lnk_size);
+	kmem_free(tgt, tgt_size);
+
+	return (rc);
 }
 
@@ -880,5 +939,4 @@
 	sffs_dirents_t *cur_buf;
 	struct sffs_dirent *dirent;
-	sffs_stat_t *stat;
 	unsigned short reclen;
 	unsigned short entlen;
@@ -974,12 +1032,5 @@
 
 			/* save the stats */
-			stat = &dirent->sf_stat;
-
-			sfprov_mode_from_fmode(&stat->sf_mode, info->Info.Attr.fMode);
-			stat->sf_size = info->Info.cbObject;
-			stat->sf_alloc = info->Info.cbAllocated;
-			sfprov_ftime_from_timespec(&stat->sf_atime, &info->Info.AccessTime);
-			sfprov_ftime_from_timespec(&stat->sf_mtime, &info->Info.ModificationTime);
-			sfprov_ftime_from_timespec(&stat->sf_ctime, &info->Info.ChangeTime);
+			sfprov_stat_from_info(&dirent->sf_stat, &info->Info);
 
 			/* next info */
Index: trunk/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.h
===================================================================
--- trunk/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.h	(revision 39267)
+++ trunk/src/VBox/Additions/solaris/SharedFolders/vboxfs_prov.h	(revision 39270)
@@ -99,4 +99,13 @@
  * get/set information about a file (or directory) using pathname
  */
+typedef struct sffs_stat {
+	mode_t		sf_mode;
+	off_t		sf_size;
+	off_t		sf_alloc;
+	timestruc_t	sf_atime;
+	timestruc_t	sf_mtime;
+	timestruc_t	sf_ctime;
+} sffs_stat_t;
+
 extern int sfprov_get_mode(sfp_mount_t *, char *, mode_t *);
 extern int sfprov_get_size(sfp_mount_t *, char *, uint64_t *);
@@ -104,6 +113,5 @@
 extern int sfprov_get_mtime(sfp_mount_t *, char *, timestruc_t *);
 extern int sfprov_get_ctime(sfp_mount_t *, char *, timestruc_t *);
-extern int sfprov_get_attr(sfp_mount_t *, char *, mode_t *, uint64_t *,
-   timestruc_t *, timestruc_t *, timestruc_t *);
+extern int sfprov_get_attr(sfp_mount_t *, char *, sffs_stat_t *);
 extern int sfprov_set_attr(sfp_mount_t *, char *, uint_t, mode_t,
    timestruc_t, timestruc_t, timestruc_t);
@@ -115,17 +123,19 @@
  */
 extern int sfprov_trunc(sfp_mount_t *, char *);
-extern int sfprov_remove(sfp_mount_t *, char *path);
+extern int sfprov_remove(sfp_mount_t *, char *path, uint_t is_link);
 extern int sfprov_mkdir(sfp_mount_t *, char *path, sfp_file_t **fp);
 extern int sfprov_rmdir(sfp_mount_t *, char *path);
 extern int sfprov_rename(sfp_mount_t *, char *from, char *to, uint_t is_dir);
 
-typedef struct sffs_stat {
-	mode_t		sf_mode;
-	off_t		sf_size;
-	off_t       sf_alloc;
-	timestruc_t	sf_atime;
-	timestruc_t	sf_mtime;
-	timestruc_t	sf_ctime;
-} sffs_stat_t;
+
+/*
+ * Symbolic link operations
+ */
+extern int sfprov_set_show_symlinks(void);
+extern int sfprov_readlink(sfp_mount_t *, char *path, char *target,
+    size_t tgt_size);
+extern int sfprov_symlink(sfp_mount_t *, char *linkname, char *target,
+    sffs_stat_t *stat);
+
 
 /*
Index: trunk/src/VBox/Additions/solaris/SharedFolders/vboxfs_vfs.c
===================================================================
--- trunk/src/VBox/Additions/solaris/SharedFolders/vboxfs_vfs.c	(revision 39267)
+++ trunk/src/VBox/Additions/solaris/SharedFolders/vboxfs_vfs.c	(revision 39270)
@@ -187,6 +187,12 @@
 	sfprov = sfprov_connect(SFPROV_VERSION);
 	if (sfprov == NULL) {
-		cmn_err(CE_WARN, "sffs_init(): couldn't init sffs provider");
+		cmn_err(CE_WARN, "sffs_init: couldn't init sffs provider");
 		return (ENODEV);
+	}
+
+	error = sfprov_set_show_symlinks();
+	if (error != 0) {
+		cmn_err(CE_WARN,  "sffs_init: host unable to show symlinks, "
+						  "rc=%d\n", error);
 	}
 
Index: trunk/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c
===================================================================
--- trunk/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c	(revision 39267)
+++ trunk/src/VBox/Additions/solaris/SharedFolders/vboxfs_vnode.c	(revision 39270)
@@ -405,11 +405,4 @@
 }
 
-static int
-sfnode_get_stat(sfp_mount_t *mnt, char *path, sffs_stat_t *stat)
-{
-	return sfprov_get_attr(mnt, path, &stat->sf_mode, &stat->sf_size,
-	    &stat->sf_atime, &stat->sf_mtime, &stat->sf_ctime);
-}
-
 static void
 sfnode_invalidate_stat_cache(sfnode_t *node)
@@ -423,5 +416,5 @@
 	int error;
 
-	error = sfnode_get_stat(node->sf_sffs->sf_handle, node->sf_path,
+	error = sfprov_get_attr(node->sf_sffs->sf_handle, node->sf_path,
 	    &node->sf_stat);
 	if (error == ENOENT)
@@ -604,5 +597,5 @@
 		if (stat == NULL) {
 			stat = &tmp_stat;
-			error = sfnode_get_stat(dir->sf_sffs->sf_handle,
+			error = sfprov_get_attr(dir->sf_sffs->sf_handle,
 			    fullpath, stat);
 			stat_time = sfnode_cur_time_usec();
@@ -617,4 +610,6 @@
 		else if (S_ISREG(m))
 			type = VREG;
+		else if (S_ISLNK(m))
+			type = VLNK;
 	}
 
@@ -1891,4 +1886,116 @@
 /*ARGSUSED*/
 static int
+sffs_readlink(
+	vnode_t		*vp,
+	uio_t		*uiop,
+	cred_t		*cred
+#if !defined(VBOX_VFS_SOLARIS_10U6)
+	,
+	caller_context_t *ct
+#endif
+	)
+{
+	sfnode_t	*node;
+	int			error = 0;
+	char		*target = NULL;
+
+	if (uiop->uio_iovcnt != 1)
+		return (EINVAL);
+
+	if (vp->v_type != VLNK)
+		return (EINVAL);
+
+	mutex_enter(&sffs_lock);
+	node = VN2SFN(vp);
+
+	target = kmem_alloc(MAXPATHLEN, KM_SLEEP);
+
+	error = sfprov_readlink(node->sf_sffs->sf_handle, node->sf_path, target,
+	    MAXPATHLEN);
+	if (error)
+		goto done;
+
+	error = uiomove(target, strlen(target), UIO_READ, uiop);
+
+done:
+	mutex_exit(&sffs_lock);
+	if (target)
+		kmem_free(target, MAXPATHLEN);
+	return (error);
+}
+
+
+/*ARGSUSED*/
+static int
+sffs_symlink(
+	vnode_t		*dvp,
+	char		*linkname,
+	vattr_t		*vap,
+	char		*target,
+	cred_t		*cred
+#if !defined(VBOX_VFS_SOLARIS_10U6)
+	,
+	caller_context_t *ct,
+	int		flags
+#endif
+	)
+{
+	sfnode_t	*dir;
+	sfnode_t	*node;
+	sffs_stat_t  stat;
+	int			 error = 0;
+	char		*fullpath;
+
+	/*
+	 * These should never happen
+	 */
+	ASSERT(linkname != NULL);
+	ASSERT(strcmp(linkname, "") != 0);
+	ASSERT(strcmp(linkname, ".") != 0);
+	ASSERT(strcmp(linkname, "..") != 0);
+
+	/*
+	 * Basic checks.
+	 */
+	if (vap->va_type != VLNK)
+		return (EINVAL);
+
+	mutex_enter(&sffs_lock);
+
+	if (sfnode_lookup(VN2SFN(dvp), linkname, VNON, NULL, 0, NULL) != NULL) {
+		error = EEXIST;
+		goto done;
+	}
+
+	dir = VN2SFN(dvp);
+	error = sfnode_access(dir, VWRITE, cred);
+	if (error)
+		goto done;
+
+	/*
+	 * Create symlink. Note that we ignore vap->va_mode because generally
+	 * we can't change the attributes of the symlink itself.
+	 */
+	fullpath = sfnode_construct_path(dir, linkname);
+	error = sfprov_symlink(dir->sf_sffs->sf_handle, fullpath, target,
+	    &stat);
+	kmem_free(fullpath, strlen(fullpath) + 1);
+	if (error)
+		goto done;
+
+	node = sfnode_lookup(dir, linkname, VLNK, &stat, sfnode_cur_time_usec(),
+	    NULL);
+
+	sfnode_invalidate_stat_cache(dir);
+	sfnode_clear_dir_list(dir);
+
+done:
+	mutex_exit(&sffs_lock);
+	return (error);
+}
+
+
+/*ARGSUSED*/
+static int
 sffs_remove(
 	vnode_t		*dvp,
@@ -1940,5 +2047,6 @@
 	sfnode_invalidate_stat_cache(VN2SFN(dvp));
 
-	error = sfprov_remove(node->sf_sffs->sf_handle, node->sf_path);
+	error = sfprov_remove(node->sf_sffs->sf_handle, node->sf_path,
+		node->sf_type == VLNK);
 	if (error == ENOENT || error == 0)
 		sfnode_make_stale(node);
@@ -2229,4 +2337,5 @@
 	VOPNAME_READ,		sffs_read,
 	VOPNAME_READDIR,	sffs_readdir,
+	VOPNAME_READLINK,	sffs_readlink,
 	VOPNAME_REMOVE,		sffs_remove,
 	VOPNAME_RENAME,		sffs_rename,
@@ -2235,4 +2344,5 @@
 	VOPNAME_SETATTR,	sffs_setattr,
 	VOPNAME_SPACE,		sffs_space,
+	VOPNAME_SYMLINK,	sffs_symlink,
 	VOPNAME_WRITE,		sffs_write,
 
@@ -2260,4 +2370,5 @@
 	VOPNAME_READ,		{ .vop_read = sffs_read },
 	VOPNAME_READDIR,	{ .vop_readdir = sffs_readdir },
+	VOPNAME_READLINK,	{ .vop_readlink = sffs_readlink },
 	VOPNAME_REMOVE,		{ .vop_remove = sffs_remove },
 	VOPNAME_RENAME,		{ .vop_rename = sffs_rename },
@@ -2266,4 +2377,5 @@
 	VOPNAME_SETATTR,	{ .vop_setattr = sffs_setattr },
 	VOPNAME_SPACE,		{ .vop_space = sffs_space },
+	VOPNAME_SYMLINK,	{ .vop_symlink = sffs_symlink },
 	VOPNAME_WRITE,		{ .vop_write = sffs_write },
 
@@ -2378,4 +2490,5 @@
 	    node->sf_type == VDIR ? "VDIR" :
 	    node->sf_type == VNON ? "VNON" :
+		node->sf_type == VLNK ? "VLNK" :
 	    node->sf_type == VREG ? "VREG" : "other", node->sf_type));
 	Log((" ino=%d", (uint_t)node->sf_ino));
