]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
2009.01.21-142982 2009.01.21-142982
authorMarcelo Vanzin <mvanzin@mvanzin-dev1.eng.vmware.com>
Wed, 21 Jan 2009 19:07:22 +0000 (11:07 -0800)
committerMarcelo Vanzin <mvanzin@mvanzin-dev1.eng.vmware.com>
Wed, 21 Jan 2009 19:07:22 +0000 (11:07 -0800)
172 files changed:
open-vm-tools/ChangeLog
open-vm-tools/Makefile.am
open-vm-tools/NEWS
open-vm-tools/configure.ac
open-vm-tools/guestd/toolsDaemon.c
open-vm-tools/lib/file/fileIOPosix.c
open-vm-tools/lib/file/filePosix.c
open-vm-tools/lib/ghIntegration/ghIntegrationX11.c
open-vm-tools/lib/guestInfo/guestInfo.c
open-vm-tools/lib/guestInfo/guestInfoPosix.c
open-vm-tools/lib/guestRpc/Makefile.am
open-vm-tools/lib/guestRpc/guestlibV3.x [new file with mode: 0644]
open-vm-tools/lib/include/buildNumber.h
open-vm-tools/lib/include/compat/compat_stdarg.h [changed mode: 0755->0644]
open-vm-tools/lib/include/dnd.h
open-vm-tools/lib/include/dynarray.h
open-vm-tools/lib/include/dynbuf.h
open-vm-tools/lib/include/file.h
open-vm-tools/lib/include/fileIO.h
open-vm-tools/lib/include/hostinfo.h
open-vm-tools/lib/include/imageUtil.h
open-vm-tools/lib/include/msg.h
open-vm-tools/lib/include/region.h
open-vm-tools/lib/include/strutil.h
open-vm-tools/lib/include/unityCommon.h
open-vm-tools/lib/include/uuid.h
open-vm-tools/lib/include/vmGuestLib.h
open-vm-tools/lib/include/vm_basic_defs.h
open-vm-tools/lib/include/vm_legal.h
open-vm-tools/lib/include/vm_product.h
open-vm-tools/lib/include/vm_tools_version.h
open-vm-tools/lib/include/vm_version.h
open-vm-tools/lib/include/vmbackup_def.h
open-vm-tools/lib/misc/Makefile.am
open-vm-tools/lib/misc/dynarray.c
open-vm-tools/lib/misc/dynbuf.c
open-vm-tools/lib/misc/hostinfoPosix.c [moved from open-vm-tools/lib/misc/hostinfo_misc.c with 67% similarity]
open-vm-tools/lib/misc/strutil.c
open-vm-tools/lib/misc/util_misc.c
open-vm-tools/lib/panic/panic.c
open-vm-tools/lib/unity/unityPlatformX11.c
open-vm-tools/lib/vixTools/vixTools.c
open-vm-tools/libguestlib/Makefile.am
open-vm-tools/libguestlib/vmGuestLib.c
open-vm-tools/libguestlib/vmGuestLibInt.h
open-vm-tools/libvmtools/vmtoolsLog.c
open-vm-tools/modules/Makefile.am [changed mode: 0755->0644]
open-vm-tools/modules/freebsd/vmblock/vm_basic_defs.h
open-vm-tools/modules/freebsd/vmhgfs/Makefile
open-vm-tools/modules/freebsd/vmhgfs/state.c
open-vm-tools/modules/freebsd/vmhgfs/state.h
open-vm-tools/modules/freebsd/vmhgfs/transport.c [new file with mode: 0644]
open-vm-tools/modules/freebsd/vmhgfs/transport.h [new file with mode: 0644]
open-vm-tools/modules/freebsd/vmhgfs/vm_basic_defs.h
open-vm-tools/modules/freebsd/vmhgfs/vnops.c
open-vm-tools/modules/freebsd/vmhgfs/vnopscommon.c
open-vm-tools/modules/freebsd/vmmemctl/vm_basic_defs.h
open-vm-tools/modules/freebsd/vmxnet/net_sg.h
open-vm-tools/modules/linux/dkms.conf
open-vm-tools/modules/linux/pvscsi/Makefile
open-vm-tools/modules/linux/pvscsi/pvscsi.c
open-vm-tools/modules/linux/pvscsi/pvscsi_defs.h
open-vm-tools/modules/linux/pvscsi/scsi_defs.h
open-vm-tools/modules/linux/pvscsi/vm_basic_defs.h
open-vm-tools/modules/linux/vmblock/Makefile
open-vm-tools/modules/linux/vmblock/include/vm_basic_defs.h
open-vm-tools/modules/linux/vmblock/linux/module.c
open-vm-tools/modules/linux/vmci/Makefile
open-vm-tools/modules/linux/vmci/vm_basic_defs.h
open-vm-tools/modules/linux/vmci/vmciDatagram.c
open-vm-tools/modules/linux/vmci/vmciDatagram.h
open-vm-tools/modules/linux/vmci/vmciEvent.c
open-vm-tools/modules/linux/vmci/vmciEvent.h
open-vm-tools/modules/linux/vmci/vmciGuestDs.c
open-vm-tools/modules/linux/vmci/vmciGuestKernelAPI.h
open-vm-tools/modules/linux/vmci/vmciGuestKernelIf.h
open-vm-tools/modules/linux/vmci/vmciKernelIf.c
open-vm-tools/modules/linux/vmci/vmciQueuePair.c
open-vm-tools/modules/linux/vmci/vmciUtil.c
open-vm-tools/modules/linux/vmci/vmci_drv.c
open-vm-tools/modules/linux/vmci/vmci_handle_array.h
open-vm-tools/modules/linux/vmci/vmci_iocontrols.h
open-vm-tools/modules/linux/vmci/vmci_kernel_if.h
open-vm-tools/modules/linux/vmci/vmci_queue_pair.h
open-vm-tools/modules/linux/vmhgfs/Makefile
open-vm-tools/modules/linux/vmhgfs/module.c
open-vm-tools/modules/linux/vmhgfs/vm_basic_defs.h
open-vm-tools/modules/linux/vmmemctl/Makefile
open-vm-tools/modules/linux/vmmemctl/os.c
open-vm-tools/modules/linux/vmmemctl/vm_basic_defs.h
open-vm-tools/modules/linux/vmsync/Makefile
open-vm-tools/modules/linux/vmsync/sync.c
open-vm-tools/modules/linux/vmxnet/Makefile
open-vm-tools/modules/linux/vmxnet/net_sg.h
open-vm-tools/modules/linux/vmxnet/vmxnet.c
open-vm-tools/modules/linux/vmxnet3/Makefile
open-vm-tools/modules/linux/vmxnet3/vmxnet3.c
open-vm-tools/modules/linux/vsock/Makefile
open-vm-tools/modules/linux/vsock/include/vm_basic_defs.h
open-vm-tools/modules/linux/vsock/include/vmciGuestKernelAPI.h
open-vm-tools/modules/linux/vsock/include/vmci_iocontrols.h
open-vm-tools/modules/linux/vsock/include/vmci_kernel_if.h
open-vm-tools/modules/linux/vsock/include/vmci_queue_pair.h
open-vm-tools/modules/linux/vsock/linux/af_vsock.c
open-vm-tools/modules/linux/vsock/linux/vmci_sockets.h
open-vm-tools/modules/linux/vsock/linux/vsockAddr.c
open-vm-tools/modules/linux/vsock/linux/vsockCommon.h
open-vm-tools/modules/linux/vsock/linux/vsockSocketWrapper.h
open-vm-tools/modules/solaris/vmhgfs/COPYING.CDDL [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/Makefile [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/cpName.c [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/cpName.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/cpNameInt.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/cpNameLinux.c [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/dbllnklst.c [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/dbllnklst.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/debug.c [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/debug.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/device.c [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/device.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/docs/BUILD [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/docs/FILES [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/docs/append-to-devlink.tab [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/docs/hgfs-9-to-10.txt [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/docs/hgfs.conf [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/docs/kadb.txt [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/docs/request-lifecycle.txt [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/docs/synchronization.txt [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/filesystem.c [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/filesystem.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/hgfs.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/hgfsEscape.c [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/hgfsEscape.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/hgfsProto.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/hgfsSolaris.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/hgfsState.c [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/hgfsState.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/hgfsUtil.c [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/hgfsUtil.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/includeCheck.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/module.c [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/module.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/request.c [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/request.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/sha1.c [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/sha1.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/vm_assert.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/vm_basic_asm.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/vm_basic_asm_x86.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/vm_basic_asm_x86_64.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/vm_basic_defs.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/vm_basic_types.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/vmware.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/vmware_pack_begin.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/vmware_pack_end.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/vmware_pack_init.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/vnode.c [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/vnode.h [new file with mode: 0644]
open-vm-tools/modules/solaris/vmhgfs/x86cpuid.h [new file with mode: 0644]
open-vm-tools/vmblock-fuse/COPYING [new file with mode: 0644]
open-vm-tools/vmblock-fuse/Makefile.am [new file with mode: 0644]
open-vm-tools/vmblock-fuse/block.c [new file with mode: 0644]
open-vm-tools/vmblock-fuse/block.h [new file with mode: 0644]
open-vm-tools/vmblock-fuse/design.txt [new file with mode: 0644]
open-vm-tools/vmblock-fuse/fsops.c [new file with mode: 0644]
open-vm-tools/vmblock-fuse/fsops.h [new file with mode: 0644]
open-vm-tools/vmblock-fuse/main.c [new file with mode: 0644]
open-vm-tools/vmblock-fuse/os.h [new file with mode: 0644]
open-vm-tools/vmblock-fuse/stubs.c [new file with mode: 0644]
open-vm-tools/vmblock-fuse/stubs.h [new file with mode: 0644]
open-vm-tools/vmblock-fuse/util.c [new file with mode: 0644]
open-vm-tools/vmware-user/copyPasteV3.h [new file with mode: 0644]

index b988b58aa1f42f3f867acc35a176ee34e7032308..27847cde40b4aec5cd4d50850c198bfef0d8c2eb 100644 (file)
@@ -1,3 +1,76 @@
+2009-01-21  Marcelo Vanzin  <mvanzin@vmware.com>
+   * Resync with internal trunk (2009.01.19)
+
+   * configure.ac: detect the presence of FUSE libraries.
+
+   * configure.ac, Makefile.am: compile kernel modules for Solaris, and
+     vmblock-fuse module if FUSE is available.
+
+   * lib/ghIntegration/ghIntegrationX11.c: retrieved localized application
+     names.
+
+   * lib/guestInfo/guestInfo.c, lib/guestInfo/guestInfoPosix.c,
+     lib/include/hostinfo.h, lib/misc/hostinfo_misc.c, lib/misc/hostinfoPosic.c,
+     lib/vixTools/vixTools.c: refactoring to move code shared with other VMware
+     products to a common library.
+
+   * lib/guestRpc/guestlibV3.x, lib/guestRpc/Makefile.am,
+     lib/include/vmGuestLib.h, libguestlib/*: add new iteration of the
+     "guestlib" protocol. This is a more extensible solution than the current
+     protocol, and should make it easier to add new information when needed.
+
+   * lib/include/dynarray.h, lib/include/dynbuf.h, lib/misc/dynarray.c,
+     lib/misc/dynbuf.c: make some DynArray/DynBuf functions inline for speed.
+
+   * lib/include/unityCommon.h: more documentation about the Unity protocol.
+
+   * lib/unity/unityPlatformX11.c: fix Unity<->guest desktop ID mappings.
+
+   * libvmtools/vmtoolsLog.c: change the way log domains are configured; now
+     sub-domains inherit the default handler for the app if no handler is
+     specified.
+
+   * modules/freebsd/vmhgfs/state.c, modules/freebsd/vmhgfs/state.h,
+     modules/freebsd/vmhgfs/vnopscommon.{c,h}: implement support for mmap on
+     the Mac OS driver, which allows running executables from an HGFS
+     share. The FreeBSD module still does not support this functionality.
+
+   * modules/freebsd/vmhgfs/transport.{c,h}: refactoring for sharing structure
+     definitions.
+
+   * modules/linux/pvscsi/pvscsi.c, modules/linux/vmblock/linux/module.c,
+     modules/linux/vmci/vmci_drv.c, modules/linux/hgfs/module.c,
+     modules/linux/vmmemctl/os.c, modules/linux/vmsync/sync.c,
+     modules/linux/vmxnet/vmxnet.c, modules/linux/vmxnet3/vmxnet3.c: add support
+     for Novell's proprietary module info tag ("supported").
+
+   * modules/linux/vmci/vmciKernelIf.c: add support for VMCI queue pairs on
+     the host. This does not affect the driver when it runs inside virtual
+     machines.
+
+   * modules/linux/vmci/*.h, modules/linux/vsock/*.h: some changes in the common
+     code to support Mac OS X, and also queue pairs on the Solaris VMCI module.
+
+   * modules/linux/vsock/af_vsock.{c,h}: add functions for registering with
+     the vsock driver from within the kernel.
+
+   * modules/linux/*/Makefile: add $(LINUXINCLUDE) to the compiler flags; this
+     allows compiling the modules against recent kernels which removed that
+     from $(KBUILD_CPPFLAGS).
+
+   * modules/Makefile.am: add support for compiling Solaris kernel modules.
+
+   * modules/solaris/vmhgfs/*: initial release of the Solaris HGFS driver in
+     open-vm-tools. Driver is licensed under the CDDL 1.0.
+
+   * vmblock-fuse/*: add the user-level implementation of the vmblock driver,
+     which is build on top of FUSE, to open-vm-tools. vmware-user hasn't yet
+     been modified to use this version of vmblock.
+
+   * vmware-user/copyPaseV3.h: new header introduced during development of the
+     next version of copy paste / DnD for X11 platforms.
+
+
 2008-11-23  Marcelo Vanzin  <mvanzin@vmware.com>
        * Resync with internal trunk (2008.12.19)
 
index 85dc196ed801a1389a83d47fa7ad384fdf13f29f..4563b0d1e7c659b6798fe8250f62a3087475d43e 100644 (file)
@@ -42,11 +42,12 @@ SUBDIRS += libguestlib
 if ENABLE_CORE_SERVICES
    SUBDIRS += libvmtools
 endif
+if HAVE_FUSE
+   SUBDIRS += vmblock-fuse
+endif
 SUBDIRS += xferlogs
 SUBDIRS += scripts
 SUBDIRS += toolbox
-if !SOLARIS
 if WITH_KERNEL_MODULES
-SUBDIRS += modules
-endif
+   SUBDIRS += modules
 endif
index e3b42425eefd99898caa6a060937d90feadba443..b92a81a5100016cc62048a555a2353daf55739ba 100644 (file)
@@ -1,4 +1,17 @@
-open-vm-tools 2009.12.23 changes:
+open-vm-tools 2009.01.21 changes:
+   * First open source release of the HGFS module for Solaris, under the CDDL.
+   Other modules are expected to be added in the upcoming releases.
+
+   * Added an implementation of vmblock on top of FUSE; vmware-user still
+   doesn't use this module even if it is available, though.
+
+   * Linux modules now add the "supported" tag used by Novell in their
+   SLES 10 SP2 release when loading modules.
+
+   * Fix compilation of modules in newer Linux kernels which don't include
+   $(LINUXINCLUDE) in the compiler flags anymore.
+
+open-vm-tools 2008.12.23 changes:
        * Lots of makefile cleanup with the switch to using libtool archives.
 
        * Automatically disable Unity if multimon support is disabled.
index 9294c438f50d0378929cd2396d4f74f5a65548a1..8572cc7e402a7d0f8a62388cd84a4f3109d9bbdc 100644 (file)
@@ -22,6 +22,8 @@
 # In addition to the usual environment variables and command line
 # arguments that a configure script usually takes (CFLAGS, LDFLAGS,
 # etc.), this script also accepts:
+# $CUSTOM_FUSE_CPPFLAGS - compile-time flags to find FUSE headers.
+# $CUSTOM_FUSE_LIBS - link-time flags to find FUSE libraries.
 # $CUSTOM_GLIB2_CPPFLAGS - compile-time flags to find Glib headers.
 # $CUSTOM_GLIB2_LIBS - link-time flags to find Glib libraries.
 # $CUSTOM_GTK_CPPFLAGS - compile-time flags to find Gtk headers.
@@ -39,7 +41,7 @@
 
 AC_INIT(
    [open-vm-tools],
-   [2008.12.23-137496],
+   [2009.01.21-142982],
    [open-vm-tools-devel@lists.sourceforge.net])
 
 # In order to make this configure script auto-detect situations where
@@ -269,6 +271,49 @@ else
    fi
 fi
 
+#
+# Check for fuse.
+#
+if test "$HAVE_PKG_CONFIG" = "yes"; then
+   AC_MSG_CHECKING([for fuse (via pkg-config)])
+   if pkg-config --exists 'fuse'; then
+      FUSE_CPPFLAGS="`pkg-config --cflags fuse`"
+      FUSE_LIBS="`pkg-config --libs fuse`"
+      have_fuse="yes"
+      AC_MSG_RESULT([yes])
+  else
+      have_fuse="no"
+      AC_MSG_RESULT([no])
+  fi
+else
+   ORIGINAL_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$CUSTOM_FUSE_LIBS $LDFLAGS"
+   AC_CHECK_LIB(
+      [fuse],
+      [fuse_main],
+      [have_fuse="yes";
+       if test -n "$CUSTOM_FUSE_LIBS"; then
+          FUSE_LIBS="$CUSTOM_FUSE_LIBS"
+       else
+          FUSE_LIBS="-lfuse"
+       fi],
+      [have_fuse="no"; AC_MSG_WARN([Fuse is missing, vmblock-fuse will be disabled.])])
+   LDFLAGS="$ORIGINAL_LDFLAGS"
+
+   if test "$have_fuse" = "yes"; then
+      ORIGINAL_CPPFLAGS="$CPPFLAGS"
+      CPPFLAGS="$CUSTOM_FUSE_CPPFLAGS $CPPFLAGS"
+      AC_CHECK_HEADER(
+         [fuse.h],
+         [if test -n "$CUSTOM_FUSE_CPPFLAGS"; then
+             FUSE_CPPFLAGS="$CUSTOM_FUSE_CPPFLAGS"
+         else
+            FUSE_CPPFLAGS="-I/usr/include"
+          fi],
+         [have_fuse="no"; AC_MSG_WARN([Can't locate fuse headers, vmblock-fuse will be disabled.])])
+      CPPFLAGS="$ORIGINAL_CPPFLAGS"
+   fi
+fi
 
 # If the user explicitly disables X11, then don't try to detect the X-related libraries
 if test "$have_x" = "disabled"; then
@@ -970,6 +1015,7 @@ if test "$os" = "solaris"; then
    # uname -r on Solaris 10 reports "5.10"
    if test "$osVersion" -ge 510000; then
       CPPFLAGS="$CPPFLAGS -DSOL10"
+      MODULES="$MODULES vmhgfs"
    fi
 fi
 
@@ -985,6 +1031,8 @@ AM_CONDITIONAL(PAMD, test -d /etc/pam.d)
 AM_CONDITIONAL(ENABLE_UNITY, test "$enable_unity" = "yes")
 AM_CONDITIONAL(WITH_ROOT_PRIVILEGES, test "$with_root_privileges" = "yes")
 AM_CONDITIONAL(ENABLE_CORE_SERVICES, test "$have_glib_26" = "yes")
+AM_CONDITIONAL(HAVE_FUSE, test "$have_fuse" = "yes")
+AM_CONDITIONAL(HAVE_GNU_LD, test "$with_gnu_ld" = "yes")
 
 ### Feature-specific flags / actions
 # Combine where possible
@@ -1054,6 +1102,8 @@ AC_SUBST([VMTOOLS_CPPFLAGS])
 AC_SUBST([VMTOOLS_LIBS])
 AC_SUBST([ZLIB_CPPFLAGS])
 AC_SUBST([ZLIB_LIBS])
+AC_SUBST([FUSE_CPPFLAGS])
+AC_SUBST([FUSE_LIBS])
 
 ### Lib substs
 
@@ -1148,6 +1198,7 @@ AC_CONFIG_FILES([                      \
    libvmtools/Makefile                 \
    xferlogs/Makefile                   \
    modules/Makefile                    \
+   vmblock-fuse/Makefile               \
    scripts/Makefile                   \
 ])
 
index 62b0bc7d5c8311653c1bd0a942ccbe46e76d7473..d12f51f5199cd84385622c22461f756908f17b6f 100644 (file)
@@ -41,6 +41,7 @@ extern "C" {
 #   include <windows.h>
 #   include "win32u.h"
 #   include "hgfsUsabilityLib.h"
+#   include "rescaps.h"
 #   include "ServiceHelpers.h"
 #endif
 
@@ -837,6 +838,13 @@ ToolsDaemonStateChangeDone(Bool status,  // IN
     */
    if (status || data->lastFailedStateChg == data->stateChgInProgress) {
       status = TRUE;
+#ifdef _WIN32
+      if (data->stateChgInProgress == GUESTOS_STATECHANGE_REBOOT || data->stateChgInProgress == GUESTOS_STATECHANGE_HALT) {
+         if (System_GetOSType() >= OS_VISTA) {
+            DISABLE_RES_CAPS();
+         }
+      }
+#endif
       if (data->stateChgInProgress == GUESTOS_STATECHANGE_REBOOT) {
          Debug("Initiating reboot\n");
          status = data->rebootCB(data->rebootCBData);
index abcea4a1b41e78ddaecf052ce906359adeba6ae7..65475b8e7eff5261f5d96bca2367418e781f1b4a 100644 (file)
@@ -1809,6 +1809,88 @@ FileIO_GetSize(const FileIODescriptor *fd)  // IN:
 }
 
 
+/*
+ *----------------------------------------------------------------------
+ *
+ * FileIO_GetAllocSize --
+ *
+ *      Get allocated size of file.
+ *
+ * Results:
+ *      Size of file or -1.
+ *
+ * Side effects:
+ *      None
+ *
+ *----------------------------------------------------------------------
+ */
+
+int64
+FileIO_GetAllocSize(const FileIODescriptor *fd)  // IN
+{
+   struct stat s;
+
+   ASSERT(fd);
+
+#if __linux__ && defined(N_PLAT_NLM)
+   /* Netware doesn't have st_blocks.  Just fall back to GetSize. */ 
+   return FileIO_GetSize(fd);
+#else
+   /*
+    * If you don't like the magic number 512, yell at the people
+    * who wrote sys/stat.h and tell them to add a #define for it.
+    */
+   return (fstat(fd->posix, &s) == -1) ? -1 : s.st_blocks * 512;
+#endif
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * FileIO_SetAllocSize --
+ *
+ *      Set allocated size of file, allocating new blocks if needed.
+ *      It is an error for size to be less than the current size.
+ *
+ * Results:
+ *      TRUE on success.  Sets errno on failure.
+ *
+ * Side effects:
+ *      None
+ *
+ *----------------------------------------------------------------------
+ */
+
+Bool
+FileIO_SetAllocSize(const FileIODescriptor *fd,  // IN
+                    uint64 size)                 // IN
+{
+#ifdef __APPLE__
+   fstore_t prealloc;
+   uint64 curSize;
+
+   curSize = FileIO_GetAllocSize(fd);
+
+   if (curSize > size) {
+      errno = EINVAL;
+      return FALSE;
+   }
+
+   prealloc.fst_flags = 0;
+   prealloc.fst_posmode = F_PEOFPOSMODE;
+   prealloc.fst_offset = 0;
+   prealloc.fst_length = size - curSize;
+   prealloc.fst_bytesalloc = 0;
+
+   return fcntl(fd->posix, F_PREALLOCATE, &prealloc) != -1;
+#else
+   errno = EINVAL;
+   return FALSE;
+#endif
+}
+
+
 /*
  *----------------------------------------------------------------------
  *
index 09d348d625591535d37432e15fad40623be29e72..5745fc5eefa42a86916e9097b77382f688a8b9b7 100644 (file)
@@ -874,7 +874,9 @@ FilePosixGetParent(Unicode *canPath)  // IN/OUT: Canonical file path
  *
  * FileGetStats --
  *
- *      Calls statfs on a full path (eg. something returned from File_FullPath)
+ *      Calls statfs on a full path (eg. something returned from File_FullPath).
+ *      If doNotAscend is FALSE, climb up the directory chain and call statfs
+ *      on each level until it succeeds.
  *
  * Results:
  *      TRUE   statfs succeeded
@@ -888,6 +890,7 @@ FilePosixGetParent(Unicode *canPath)  // IN/OUT: Canonical file path
 
 static Bool
 FileGetStats(ConstUnicode pathName,      // IN:
+             Bool doNotAscend,           // IN:
              struct statfs *pstatfsbuf)  // OUT:
 {
    Bool retval = TRUE;
@@ -895,7 +898,7 @@ FileGetStats(ConstUnicode pathName,      // IN:
 
    while (Posix_Statfs(dupPath ? dupPath : pathName,
                              pstatfsbuf) == -1) {
-      if (errno != ENOENT) {
+      if (errno != ENOENT || doNotAscend) {
          retval = FALSE;
          break;
       }
@@ -920,7 +923,9 @@ FileGetStats(ConstUnicode pathName,      // IN:
  * File_GetFreeSpace --
  *
  *      Return the free space (in bytes) available to the user on a disk where
- *      a file is or would be
+ *      a file is or would be.  If doNotAscend is FALSE, the helper function
+ *      ascends the directory chain on system call errors in order to obtain
+ *      the file system information.
  *
  * Results:
  *      -1 if error (reported to the user)
@@ -932,7 +937,8 @@ FileGetStats(ConstUnicode pathName,      // IN:
  */
 
 uint64
-File_GetFreeSpace(ConstUnicode pathName)  // IN: File name
+File_GetFreeSpace(ConstUnicode pathName,  // IN: File name
+                  Bool doNotAscend)       // IN: Do not ascend dir chain
 {
    uint64 ret;
    Unicode fullPath;
@@ -944,8 +950,8 @@ File_GetFreeSpace(ConstUnicode pathName)  // IN: File name
       goto end;
    }
 
-   if (!FileGetStats(fullPath, &statfsbuf)) {
-      Warning("%s: Couldn't statfs\n", __func__);
+   if (!FileGetStats(fullPath, doNotAscend, &statfsbuf)) {
+      Warning("%s: Couldn't statfs %s\n", __func__, fullPath);
       ret = -1;
       goto end;
    }
@@ -1238,7 +1244,7 @@ File_OnVMFS(ConstUnicode pathName)
          goto end;
       }
 
-      err = FileGetStats(fullPath, &statfsbuf);
+      err = FileGetStats(fullPath, FALSE, &statfsbuf);
 
       Unicode_Free(fullPath);
 
@@ -1290,7 +1296,7 @@ File_GetCapacity(ConstUnicode pathName)  // IN: Path name
       goto end;
    }
 
-   if (!FileGetStats(fullPath, &statfsbuf)) {
+   if (!FileGetStats(fullPath, FALSE, &statfsbuf)) {
       Warning(LGPFX" %s: Couldn't statfs\n", __func__);
       ret = -1;
       goto end;
index a80afab7889c8ddcb6a7936a55c1053ba1532d01..a3fff9a6e0d2be231b35b19df06eb221ae904bab 100644 (file)
 #include <sys/stat.h>
 #include <unistd.h>
 
+#ifndef GTK2
+#error "Gtk 2.0 is required"
+#endif
+
+#include <glib.h>
+#include <gdk-pixbuf/gdk-pixbuf-core.h>
+
+// gdkx.h includes Xlib.h, which #defines Bool.
+#include <gdk/gdkx.h>
+#undef Bool
+
 #include "vmware.h"
 #include "base64.h"
 #include "rpcin.h"
    (((textrange).afterLast - (textrange).first) == strlen((str))        \
     && !strncmp((textrange).first, (str), (textrange).afterLast - (textrange).first))
 
-#ifndef GTK2
-#error "Gtk 2.0 is required"
-#endif
-
 #include "appUtil.h"
 
-#include <glib.h>
-#include <gdk-pixbuf/gdk-pixbuf-core.h>
-#include <gdk/gdkx.h>
-
 /*
  * The following defines appear in newer versions of glib 2.x, so
  * we define them for backwards compat.
@@ -829,8 +832,8 @@ GHIPlatformGetBinaryInfo(GHIPlatform *ghip,         // IN: platform-specific sta
     * Stick the app name into 'buf'.
     */
    if (ghm) {
-      ctmp = g_key_file_get_string(ghm->keyfile, G_KEY_FILE_DESKTOP_GROUP,
-                                   G_KEY_FILE_DESKTOP_KEY_NAME, NULL);
+      ctmp = g_key_file_get_locale_string(ghm->keyfile, G_KEY_FILE_DESKTOP_GROUP,
+                                   G_KEY_FILE_DESKTOP_KEY_NAME, NULL, NULL);
       if (!ctmp) {
          ctmp = g_path_get_basename(realCmd);
       }
@@ -1781,14 +1784,10 @@ GHIPlatformGetStartMenuItem(GHIPlatform *ghip, // IN: platform-specific state
 
          gmi = g_ptr_array_index(gmh->gmd->items, itemIndex);
 
-         /*
-          * XXX I should get_locale_string here for the localizedItemName, if there's a
-          * way to do it in the guest user's current language.
-          */
-         localizedItemName = g_key_file_get_string(gmi->keyfile,
-                                                   G_KEY_FILE_DESKTOP_GROUP,
-                                                   G_KEY_FILE_DESKTOP_KEY_NAME,
-                                                   NULL);
+         localizedItemName = g_key_file_get_locale_string(gmi->keyfile,
+                                                          G_KEY_FILE_DESKTOP_GROUP,
+                                                          G_KEY_FILE_DESKTOP_KEY_NAME,
+                                                          NULL, NULL);
          freeLocalItemName = TRUE;
          itemName = g_strdup_printf("%s/%s/%s", UNITY_START_MENU_LAUNCH_FOLDER,
                                     gmh->gmd->dirname, localizedItemName);
@@ -2303,12 +2302,11 @@ GHIPlatformCombineArgs(GHIPlatform *ghip,            // IN
                switch (thisarg[1]) {
                case 'c': // %c expands to the .desktop's Name=
                   {
-                     // XXX Should use the translated version
                      char *ctmp =
-                        g_key_file_get_string(ghm->keyfile,
-                                              G_KEY_FILE_DESKTOP_GROUP,
-                                              G_KEY_FILE_DESKTOP_KEY_NAME,
-                                              NULL);
+                        g_key_file_get_locale_string(ghm->keyfile,
+                                                     G_KEY_FILE_DESKTOP_GROUP,
+                                                     G_KEY_FILE_DESKTOP_KEY_NAME,
+                                                     NULL, NULL);
                      if (ctmp) {
                         g_ptr_array_add(fullargs, ctmp);
                      }
index db77f3b9bb770ca0b6183e1441970290aceaa61e..7f28c68ee5d74f6d69f10aadb1c2c4441ea4c356 100644 (file)
@@ -200,32 +200,6 @@ GuestInfo_GetOSName(unsigned int outBufFullLen, // IN
 }
 
 
-#if defined(N_PLAT_NLM)
-/*
- *----------------------------------------------------------------------------
- *
- * GuestInfo_GetSystemBitness --
- *
- *      Determines the operating system's bitness.
- *
- * Return value:
- *      32 or 64 on success, negative value on failure. Check errno for more
- *      details of error.
- *
- * Side effects:
- *      None.
- *
- *----------------------------------------------------------------------------
- */
-
-int
-GuestInfo_GetSystemBitness(void)
-{
-   return 32;
-}
-#endif // defined(N_PLAT_NLM)
-
-
 /**
  * Add a NIC into the given list. The macAddress of the new GuestNic is
  * initialized with the given address.
index 0250cbc491a62a92ec2e061d0f106e1c6c39915c..43ddcd813a938789df05c256e925095cad993541 100644 (file)
@@ -55,6 +55,7 @@
 #include "sys/utsname.h"
 #include "sys/ioctl.h"
 #include "vmware.h"
+#include "hostinfo.h"
 #include "guestInfoInt.h"
 #include "debug.h"
 #include "str.h"
 
 #define DISTRO_BUF_SIZE 255
 
-#define SYSINFO_STRING_32       "i386"
-#define SYSINFO_STRING_64       "amd64"
-#define MAX_ARCH_NAME_LEN       sizeof SYSINFO_STRING_32 > sizeof SYSINFO_STRING_64 ? \
-                                   sizeof SYSINFO_STRING_32 : \
-                                   sizeof SYSINFO_STRING_64
-
 typedef struct lsb_distro_info {
    char *name;
    char *scanstring;
@@ -758,7 +753,7 @@ GuestInfoGetOSName(unsigned int outBufFullLen,      // IN: length of osNameFull
       }
    }
 
-   if (GuestInfo_GetSystemBitness() == 64) {
+   if (Hostinfo_GetSystemBitness() == 64) {
       if (strlen(osName) + sizeof STR_OS_64BIT_SUFFIX > outBufLen) {
          Debug("GuestInfoGetOSName: Error: buffer too small\n");
          return FALSE;
@@ -777,73 +772,3 @@ GuestInfoGetOSName(unsigned int outBufFullLen,      // IN: length of osNameFull
 
    return TRUE;
 }
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * GuestInfo_GetSystemBitness --
- *
- *      Determines the operating system's bitness.
- *
- * Return value:
- *      32 or 64 on success, negative value on failure. Check errno for more
- *      details of error.
- *
- * Side effects:
- *      None.
- *
- *----------------------------------------------------------------------------
- */
-
-int
-GuestInfo_GetSystemBitness(void)
-{
-   char buf[MAX_ARCH_NAME_LEN] = { 0 };
-#if defined(__FreeBSD__) || defined(__APPLE__)
-   int mib[2];
-   size_t len;
-
-   len = sizeof buf;
-   mib[0] = CTL_HW;
-   mib[1] = HW_MACHINE;
-
-   if (sysctl(mib, ARRAYSIZE(mib), buf, &len, NULL, 0) < 0) {
-      return -1;
-   }
-#elif defined(sun)
-# if !defined(SOL10)
-   /*
-    * XXX: This is bad.  We define SI_ARCHITECTURE_K to what it is on Solaris
-    * 10 so that we can use a single guestd build for Solaris 9 and 10.  In the
-    * future we should have the Solaris 9 build just return 32 -- since it did
-    * not support 64-bit x86 -- and let the Solaris 10 headers define
-    * SI_ARCHITECTURE_K, then have the installer symlink to the correct binary.
-    * For now, though, we'll share a single build for both versions.
-    */
-#  define SI_ARCHITECTURE_K  518
-# endif
-   if (sysinfo(SI_ARCHITECTURE_K, buf, sizeof buf) < 0) {
-      return -1;
-   }
-#elif defined(linux)
-   struct utsname u;
-
-   if (uname(&u) < 0) {
-      return -1;
-   }
-   if (strstr(u.machine, "x86_64")) {
-      return 64;
-   } else {
-      return 32;
-   }
-#endif
-
-   if (strcmp(buf, SYSINFO_STRING_32) == 0) {
-      return 32;
-   } else if (strcmp(buf, SYSINFO_STRING_64) == 0) {
-      return 64;
-   }
-
-   return -1;
-}
index 2867be720038a2cafcadf2fcb0f8fad127ce822b..27cde3ca3bec6b37310d5af083d8ec57ec95a2ea 100644 (file)
@@ -20,6 +20,7 @@ noinst_LTLIBRARIES = libGuestRpc.la
 libGuestRpc_la_SOURCES =
 libGuestRpc_la_SOURCES += ghiGetBinaryHandlers_xdr.c
 libGuestRpc_la_SOURCES += ghiProtocolHandler_xdr.c
+libGuestRpc_la_SOURCES += guestlibV3_xdr.c
 libGuestRpc_la_SOURCES += nicinfo_xdr.c
 libGuestRpc_la_SOURCES += unityActive_xdr.c
 
@@ -33,6 +34,8 @@ CLEANFILES += ghiGetBinaryHandlers.h
 CLEANFILES += ghiGetBinaryHandlers_xdr.c
 CLEANFILES += ghiProtocolHandler.h
 CLEANFILES += ghiProtocolHandler_xdr.c
+CLEANFILES += guestlibV3.h
+CLEANFILES += guestlibV3_xdr.c
 CLEANFILES += nicinfo.h
 CLEANFILES += nicinfo_xdr.c
 CLEANFILES += unityActive.h
@@ -41,6 +44,7 @@ CLEANFILES += unityActive_xdr.c
 EXTRA_DIST =
 EXTRA_DIST += ghiGetBinaryHandlers.x
 EXTRA_DIST += ghiProtocolHandler.x
+EXTRA_DIST += guestlibV3.x
 EXTRA_DIST += nicinfo.x
 EXTRA_DIST += unityActive.x
 
@@ -85,7 +89,17 @@ nicinfo.h: nicinfo.x
        if [ $(top_builddir) != $(top_srcdir) ]; then            \
           cp $(top_srcdir)/lib/guestRpc/nicinfo.x $(builddir);  \
        fi
-       $(RPCGEN) -h -o $@ nicinfo.x
+       $(RPCGEN) -h -o $@ $<
+       $(SED) 's,rpc/rpc\.h,vmxrpc.h,' $@ > $@.tmp
+       mv $@.tmp $@
+       $(MKDIR_P) $(top_builddir)/lib/include/guestrpc
+       cp $@ $(top_builddir)/lib/include/guestrpc
+
+guestlibV3.h: guestlibV3.x
+       if [ $(top_builddir) != $(top_srcdir) ]; then               \
+          cp $(top_srcdir)/lib/guestRpc/guestlibV3.x $(builddir);  \
+       fi
+       $(RPCGEN) -h -o $@ $<
        $(SED) 's,rpc/rpc\.h,vmxrpc.h,' $@ > $@.tmp
        mv $@.tmp $@
        $(MKDIR_P) $(top_builddir)/lib/include/guestrpc
@@ -94,6 +108,9 @@ nicinfo.h: nicinfo.x
 nicinfo_xdr.c: nicinfo.x nicinfo.h
        $(RPCGEN) -c -o $@ nicinfo.x
 
+guestlibV3_xdr.c: guestlibV3.x guestlibV3.h
+       $(RPCGEN) -c -o $@ guestlibV3.x
+
 unityActive.h: unityActive.x
        if [ $(top_builddir) != $(top_srcdir) ]; then               \
           cp $(top_srcdir)/lib/guestRpc/unityActive.x $(builddir); \
diff --git a/open-vm-tools/lib/guestRpc/guestlibV3.x b/open-vm-tools/lib/guestRpc/guestlibV3.x
new file mode 100644 (file)
index 0000000..dbf5c6f
--- /dev/null
@@ -0,0 +1,117 @@
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *********************************************************/
+
+
+/*
+ * guestlibV3.x --
+ *
+ *    Data structures that encode the information sent from VMX to Guest upon a
+ *    Guestlib protocol v3 request.
+ */
+
+struct GuestLibV3StatUint32 {
+   Bool valid;
+   uint32 value;
+};
+
+struct GuestLibV3StatUint64 {
+   Bool valid;
+   uint64 value;
+};
+
+struct GuestLibV3String {
+   Bool valid;
+   string value<512>;
+};
+
+typedef uint32 GuestLibV3StatCount;
+
+enum GuestLibV3TypeIds {
+   /* V2 statistics */
+   GUESTLIB_TYPE_RESERVED         = 0,
+   GUESTLIB_CPU_RESERVATION_MHZ   = 1,
+   GUESTLIB_CPU_LIMIT_MHZ         = 2,
+   GUESTLIB_CPU_SHARES            = 3,
+   GUESTLIB_CPU_USED_MS           = 4,
+
+   GUESTLIB_HOST_MHZ              = 5,
+
+   GUESTLIB_MEM_RESERVATION_MB    = 6,
+   GUESTLIB_MEM_LIMIT_MB          = 7,
+   GUESTLIB_MEM_SHARES            = 8,
+   GUESTLIB_MEM_MAPPED_MB         = 9,
+   GUESTLIB_MEM_ACTIVE_MB         = 10,
+   GUESTLIB_MEM_OVERHEAD_MB       = 11,
+   GUESTLIB_MEM_BALLOONED_MB      = 12,
+   GUESTLIB_MEM_SWAPPED_MB        = 13,
+   GUESTLIB_MEM_SHARED_MB         = 14,
+   GUESTLIB_MEM_SHARED_SAVED_MB   = 15,
+   GUESTLIB_MEM_USED_MB           = 16,
+
+   GUESTLIB_ELAPSED_MS            = 17,
+   GUESTLIB_RESOURCE_POOL_PATH    = 18,
+
+   /*------ Add any new statistics above this line. ------- */
+
+   /*------ Bump this when adding to this list. -------*/
+   GUESTLIB_MAX_STATISTIC_ID      = 19
+};
+
+union GuestLibV3Stat switch (GuestLibV3TypeIds d) {
+   case GUESTLIB_CPU_RESERVATION_MHZ:
+      struct GuestLibV3StatUint32 cpuReservationMHz;
+   case GUESTLIB_CPU_LIMIT_MHZ:
+      struct GuestLibV3StatUint32 cpuLimitMHz;
+   case GUESTLIB_CPU_SHARES:
+      struct GuestLibV3StatUint32 cpuShares;
+   case GUESTLIB_CPU_USED_MS:
+      struct GuestLibV3StatUint64 cpuUsedMs;
+
+   case GUESTLIB_HOST_MHZ:
+      struct GuestLibV3StatUint32 hostMHz;
+
+   case GUESTLIB_MEM_RESERVATION_MB:
+      struct GuestLibV3StatUint32 memReservationMB;
+   case GUESTLIB_MEM_LIMIT_MB:
+      struct GuestLibV3StatUint32 memLimitMB;
+   case GUESTLIB_MEM_SHARES:
+      struct GuestLibV3StatUint32 memShares;
+   case GUESTLIB_MEM_MAPPED_MB:
+      struct GuestLibV3StatUint32 memMappedMB;
+   case GUESTLIB_MEM_ACTIVE_MB:
+      struct GuestLibV3StatUint32 memActiveMB;
+   case GUESTLIB_MEM_OVERHEAD_MB:
+      struct GuestLibV3StatUint32 memOverheadMB;
+   case GUESTLIB_MEM_BALLOONED_MB:
+      struct GuestLibV3StatUint32 memBalloonedMB;
+   case GUESTLIB_MEM_SWAPPED_MB:
+      struct GuestLibV3StatUint32 memSwappedMB;
+   case GUESTLIB_MEM_SHARED_MB:
+      struct GuestLibV3StatUint32 memSharedMB;
+   case GUESTLIB_MEM_SHARED_SAVED_MB:
+      struct GuestLibV3StatUint32 memSharedSavedMB;
+   case GUESTLIB_MEM_USED_MB:
+      struct GuestLibV3StatUint32 memUsedMB;
+
+   case GUESTLIB_ELAPSED_MS:
+      struct GuestLibV3StatUint64 elapsedMs;
+
+   case GUESTLIB_RESOURCE_POOL_PATH:
+      struct GuestLibV3String resourcePoolPath;
+};
+
index 74ee06e38e02b34798c0d1551bed80347166bf0e..343be2ca8947c4215fd7f59f7e5c58ce2adceaca 100644 (file)
@@ -1,12 +1,12 @@
 #define BUILD_NUMBER \
-       "build-137496"
+       "build-142982"
 #define BUILD_NUMBER_NUMERIC \
-       137496
+       142982
 #define BUILD_NUMBER_NUMERIC_STRING \
-       "137496"
+       "142982"
 #define PRODUCT_BUILD_NUMBER \
-       "product-build-416"
+       "product-build-444"
 #define PRODUCT_BUILD_NUMBER_NUMERIC \
-       416
+       444
 #define PRODUCT_BUILD_NUMBER_NUMERIC_STRING \
-       "416"
+       "444"
index 94dec95b8a1205f88e24835cbea7b77e3adc6677..cec0cabd14788d987bda36a65b217e15f985c296 100644 (file)
@@ -92,6 +92,7 @@ typedef enum
    CPFORMAT_RTF,
    CPFORMAT_FILELIST_URI,
    CPFORMAT_FILECONTENTS,
+   CPFORMAT_IMG_PNG,
    CPFORMAT_MAX,
 } DND_CPFORMAT;
 
@@ -175,6 +176,17 @@ EXTERN Bool DnD_SetCPClipboardFromLocalText(CPClipboard *clip,
                                             utf16_t *bufIn);
 EXTERN Bool DnD_SetCPClipboardFromLocalRtf(CPClipboard *clip,
                                            char *bufIn);
+EXTERN Bool DnD_SetCPClipboardFromBMPInfo(CPClipboard *clip,
+                                          const LPBITMAPINFOHEADER bmi,
+                                          DND_CPFORMAT fmt);
+EXTERN Bool DnD_SetCPClipboardFromHBITMAP(CPClipboard *clip,
+                                          HBITMAP hBitmap,
+                                          DND_CPFORMAT fmt);
+EXTERN Bool DnD_PNGToLocalFormat(const unsigned char *pngData,
+                                 unsigned int pngDataLen,
+                                 int pngReadFlags,
+                                 DynBuf *bmpData,
+                                 HBITMAP *hBitmap);
 EXTERN Bool DnD_FakeMouseEvent(DWORD flag);
 EXTERN Bool DnD_FakeMouseState(DWORD key, Bool isDown);
 EXTERN Bool DnD_FakeEscapeKey(void);
index 41e536175bc1a65e2549cd7016ea2f4f545fe701..4caffe12c3c5355ceb31d4ad01ef00555c684013 100644 (file)
@@ -29,6 +29,9 @@
 #define _DYNARRAY_H_
 
 #include "dynbuf.h"
+#include "vm_basic_types.h"
+#include "vm_assert.h"
+
 
 typedef struct DynArray {
    DynBuf buf;
@@ -55,26 +58,166 @@ DynArray_Init(DynArray *a, unsigned int count, size_t width);
 void
 DynArray_Destroy(DynArray *a);
 
-void *
-DynArray_AddressOf(const DynArray *a, unsigned int i);
-
-unsigned int
-DynArray_Count(const DynArray *a);
-
 Bool
 DynArray_SetCount(DynArray *a, unsigned int c);
 
+void
+DynArray_QSort(DynArray *a, DynArrayCmp compare);
+
 unsigned int
 DynArray_AllocCount(const DynArray *a);
 
-Bool
-DynArray_Trim(DynArray *a);
 
-void
-DynArray_QSort(DynArray *a, DynArrayCmp compare);
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DynArray_Trim --
+ *
+ *      Resize the array to fit exactly DynArray_Count() elements.
+ *
+ * Results:
+ *      TRUE on success
+ *      FALSE on failure (why?  who knows...)
+ *
+ * Side effects:
+ *      Resizes the array
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE Bool
+DynArray_Trim(DynArray *a)    // IN/OUT
+{
+   ASSERT(a);
+
+   return DynBuf_Trim(&a->buf);
+}
+
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DynArray_AddressOf --
+ *
+ *      Fetch a pointer to the address of the ith element.
+ *
+ * Results:
+ *      The pointer to the ith element or NULL if the index is out of
+ *      bounds.
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE void *
+DynArray_AddressOf(const DynArray *a,   // IN
+                   unsigned int i)      // IN
+{
+   uintptr_t offset = i * a->width;
+
+   ASSERT(a);
+
+   if (offset + a->width <= DynBuf_GetSize(&a->buf)) {
+      return offset + (uint8 *)DynBuf_Get(&a->buf);
+   }
+
+   return NULL;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DynArray_AddressOfUnsafe --
+ *
+ *      Fetch a pointer to the address of the ith element. Only call
+ *      this if you already know that 'i' is valid. The index is not
+ *      checked against the size of the array.
+ *
+ * Results:
+ *      Always returns a pointer to the ith element.
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE void *
+DynArray_AddressOfUnsafe(const DynArray *a,   // IN
+                         unsigned int i)      // IN
+{
+   uintptr_t offset = i * a->width;
+
+   ASSERT(a);
+   ASSERT(offset + a->width <= DynBuf_GetSize(&a->buf));
+
+   return offset + (uint8 *)DynBuf_Get(&a->buf);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DynArray_Count --
+ *
+ *      Returns the number of elements in the array.
+ *
+ *      XXX: This is relatively slow, since we do an integer division.
+ *           Avoid calling this in inner loops.
+ *
+ * Results:
+ *      See above.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE unsigned int
+DynArray_Count(const DynArray *a)       // IN
+{
+   ASSERT(a);
+
+   return (unsigned int) (DynBuf_GetSize(&a->buf) / a->width);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DynArray_Copy --
+ *
+ *      Copies all data and metadata from src Dynarray to dest DynArray.
+ *
+ *      Dest should be an initialized DynArray of size zero.
+ *
+ * Results:
+ *      TRUE on success, FALSE on failure.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE Bool
+DynArray_Copy(DynArray *src,        // IN
+              DynArray *dest)       // OUT
+{
+   ASSERT(src);
+   ASSERT(dest);
+   ASSERT(dest->width);
+   ASSERT(dest->width == src->width);
+   ASSERT(DynArray_AllocCount(dest) == 0);
+
+   return DynBuf_Copy(&src->buf, &dest->buf);
+}
 
-Bool
-DynArray_Copy(DynArray *src, DynArray *dest);
 
 /*
  * Use the following macros to define your own DynArray type to
index ebe0b7b1a3289660f6418ce528f24b633bc494ac..f6a3776d2bc2bd56699c63b54d45f8c996ee1eee 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <string.h>
 #include "vm_basic_types.h"
+#include "vm_assert.h"
 
 
 typedef struct DynBuf {
@@ -42,9 +43,6 @@ DynBuf_Init(DynBuf *b); // IN
 void
 DynBuf_Destroy(DynBuf *b); // IN
 
-void *
-DynBuf_Get(DynBuf const *b); // IN
-
 void *
 DynBuf_AllocGet(DynBuf const *b); // IN
 
@@ -68,21 +66,113 @@ DynBuf_Append(DynBuf *b,        // IN
 Bool
 DynBuf_Trim(DynBuf *b); // IN
 
-size_t
-DynBuf_GetSize(DynBuf const *b); // IN
-
-void
-DynBuf_SetSize(DynBuf *b,    // IN
-               size_t size); // IN
-
-size_t
-DynBuf_GetAllocatedSize(DynBuf const *b); // IN
-
 Bool
 DynBuf_Copy(DynBuf *src,    // IN
             DynBuf *dest);  // OUT
 
 
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DynBuf_Get --
+ *
+ *      Retrieve a pointer to the data contained in a dynamic buffer --hpreg
+ *
+ * Results:
+ *      The pointer to the data
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE void *
+DynBuf_Get(DynBuf const *b) // IN
+{
+   ASSERT(b);
+
+   return b->data;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DynBuf_GetSize --
+ *
+ *      Returns the current size of the dynamic buffer --hpreg
+ *
+ * Results:
+ *      The current size of the dynamic buffer
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE size_t
+DynBuf_GetSize(DynBuf const *b) // IN
+{
+   ASSERT(b);
+
+   return b->size;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DynBuf_SetSize --
+ *
+ *      Set the current size of a dynamic buffer --hpreg
+ *
+ * Results:
+ *      None
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE void
+DynBuf_SetSize(DynBuf *b,   // IN
+               size_t size) // IN
+{
+   ASSERT(b);
+   ASSERT(size <= b->allocated);
+
+   b->size = size;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * DynBuf_GetAllocatedSize --
+ *
+ *      Returns the current allocated size of the dynamic buffer --hpreg
+ *
+ * Results:
+ *      The current allocated size of the dynamic buffer
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE size_t
+DynBuf_GetAllocatedSize(DynBuf const *b) // IN
+{
+   ASSERT(b);
+
+   return b->allocated;
+}
+
+
 /*
  *----------------------------------------------------------------------------
  *
index 0b7a5ece42c6fd4ca6f955dd77e067956d1fb23a..90ce9a647d0fe19fc424d3a55e2b05420ed089cb 100644 (file)
@@ -152,7 +152,8 @@ EXTERN Unicode File_FullPath(ConstUnicode pathName);
 
 EXTERN Bool File_IsFullPath(ConstUnicode pathName);
 
-EXTERN uint64 File_GetFreeSpace(ConstUnicode pathName);
+EXTERN uint64 File_GetFreeSpace(ConstUnicode pathName,
+                                Bool doNotAscend);
 
 EXTERN uint64 File_GetCapacity(ConstUnicode pathName);
 
index c3597b7c196c2c69a8a31825eb490f07b4156ee6..eb94bde52eb3b306025104d41b4fe0546d73a25f 100644 (file)
@@ -323,6 +323,10 @@ int     FileIO_Sync(const FileIODescriptor *file);
 
 int64   FileIO_GetSize(const FileIODescriptor *fd);
 
+int64   FileIO_GetAllocSize(const FileIODescriptor *fd);
+
+Bool    FileIO_SetAllocSize(const FileIODescriptor *fd, uint64 size);
+
 int64   FileIO_GetSizeByPath(ConstUnicode pathName);
 
 int     FileIO_Close(FileIODescriptor *file);
index 12dc0d65018da52b1564934860e5caf30c89b7c0..11bc7a5ac2998c835e6bf20950a30c9aea74f24c 100644 (file)
@@ -54,12 +54,13 @@ extern Bool Hostinfo_GetCOSMemoryInfoInPages(unsigned int *minSize,
 #endif
 extern Bool Hostinfo_GetRatedCpuMhz(int32 cpuNumber,
                                     uint32 *mHz);
-extern charHostinfo_GetCpuDescription(uint32 cpuNumber);
+extern char *Hostinfo_GetCpuDescription(uint32 cpuNumber);
 extern void Hostinfo_GetTimeOfDay(VmTimeType *time);
 extern VmTimeType Hostinfo_SystemUpTime(void);
 extern VmTimeType Hostinfo_RawSystemTimerUS(void);
 extern VmTimeType Hostinfo_SystemTimerUS(void);
 extern int Hostinfo_OSVersion(int i);
+extern int Hostinfo_GetSystemBitness(void);
 extern const char *Hostinfo_OSVersionString(void);
 extern Bool Hostinfo_OSIsSMP(void);
 #if defined(_WIN32)
index 63b1eb88fe3c2609fb32571233655a6ed6d49119..590c6e13be7e3b709e14ab0e0302b1f272891a4b 100644 (file)
 /*
  * imageUtil.h --
  *
+ *      Image manipulation routines.
  */
 
 #ifndef _IMAGEUTIL_H_
 #define _IMAGEUTIL_H_
 
+#include "vmware.h"
 #include "imageUtilTypes.h"
 #include "dynbuf.h"
 #include "unicodeTypes.h"
 
 #ifdef _WIN32
-
-typedef char Bool;
-
-typedef struct tagDIBINFOHEADER {
-   BITMAPINFOHEADER  bmiHeader;
-   RGBQUAD           bmiColors[256];
-   LPBYTE            bitmapBits;
-} DIBINFOHEADER, FAR *LPDIBINFOHEADER, *PDIBINFOHEADER;
-
-BOOL ImageUtil_SavePNG(LPDIBINFOHEADER image, ConstUnicode fileName);
-EXTERN HBITMAP ImageUtil_LoadPNG(ConstUnicode fileName, int pngReadFlags);
-EXTERN HBITMAP ImageUtil_LoadPNGFromBuffer(const unsigned char *imageData,
-                                           unsigned int dataLen, int pngReadFlags);
-EXTERN HBITMAP ImageUtil_LoadImage(ConstUnicode filename, unsigned int width,
-                                                          unsigned int height);
-
-#else
-#ifndef NO_X11_XLIB_H    /* XXX Carbon and X both define 'Cursor'
-                          * but we don't use ImgUtil_SavePNG in mksQuartz.h
-                          * Remove after we have implemeted imageUtil with
-                          * Quartz.
-                          */
-#include <X11/Xlib.h>
-#undef Bool                            // XXX conflict with vm_basic_types.h
-#define XBool int
-#undef Cursor
-
-Bool ImageUtil_SavePNG(const XImage *image,
-                       unsigned int numColors, unsigned short colors[256][3],
-                       const char *fileName);
-#endif //USE_IMAGE_UTIL_H
+#include "imageUtilWin32.h"
 #endif
 
-#define DWORD_ALIGN(x)             ((((x)+3) >> 2) << 2)
-
 EXTERN Bool ImageUtil_ReadPNG(ImageInfo *image,
                               ConstUnicode pathName,
                               int pngReadFlags);
index d192dc660206103b69b2d38a67e6a2d01650b3fb..e7ef448e1439cd0e62e3fbbb105887441b4833cf 100644 (file)
@@ -191,7 +191,7 @@ EXTERN const char *Msg_GetMessagesAndReset(void);
 EXTERN Msg_List *Msg_GetMsgList(void);
 EXTERN Msg_List *Msg_GetMsgListAndReset(void);
 EXTERN void Msg_FreeMsgList(Msg_List *messages);
-EXTERN char *Msg_LocalizeList(Msg_List *messages);
+EXTERN char *Msg_LocalizeList(const Msg_List *messages);
 EXTERN void Msg_Reset(Bool log);
 EXTERN Bool Msg_Present(void);
 EXTERN void Msg_Exit(void);
index 890ed0d0a90d8f2608fd75b2b8cb7a1c530254d2..3f00239cceaff1b24c4c87f8f4c87a31bf8753d4 100644 (file)
@@ -200,6 +200,9 @@ extern RegDataRec miBrokenData;
   RECT_SETBOX((r), (rx1), (ry1), ((rx2) - (rx1)), ((ry2) - (ry1))); \
 } while (FALSE)
 
+#define RECT_SETVMRECT(r, vmr) \
+  RECT_SETRECT((r), (vmr)->left,  (vmr)->top,  (vmr)->right,  (vmr)->bottom)
+
 /*
  * This will only work if the intersection is not empty.
  */
index 89ec20a716d4e91415de163b6874bad3231ab8db..61e637d6d183d4f4f592fa03063fee89cd9f04df 100644 (file)
@@ -39,11 +39,13 @@ Bool StrUtil_GetNextUintToken(uint32 *out, unsigned int *index, const char *str,
                               const char *delimiters);
 Bool StrUtil_GetNextInt64Token(int64 *out, unsigned int *index, const char *str,
                               const char *delimiters);
+Bool StrUtil_DecimalStrToUint(unsigned int *out, const char **str);
 Bool StrUtil_StrToInt(int32 *out, const char *str);
 Bool StrUtil_StrToUint(uint32 *out, const char *str);
 Bool StrUtil_StrToInt64(int64 *out, const char *str);
 Bool StrUtil_StrToSizet(size_t *out, const char *str);
-Bool StrUtil_DecimalStrToUint(unsigned int *out, const char **str);
+Bool StrUtil_CapacityToSectorType(SectorType *out, const char *str,
+                                  unsigned int bytes);
 char * StrUtil_FormatSizeInBytesUnlocalized(uint64 size);
 
 size_t StrUtil_GetLongestLineLength(const char *buf, size_t bufLength);
index 571d601d8b5f2b5c878b8ae6743f672a4ae13903..1194e9b4fc941f3df45b8993e440986ddf6d9722 100644 (file)
@@ -323,40 +323,43 @@ typedef int32 UnityDesktopId;
  * Unity window attributes are boolean flags that can be set in combination on a window.
  * If they are not set by the guest, it is up to the host to decide on a reasonable
  * default.
- *
- * @attention
- * If you add attributes here, please also update unityAttributeNames in
- * unityWindowTracker.c.
  */
 typedef enum {
-   UNITY_WINDOW_ATTR_BORDERLESS = 0,
-   UNITY_WINDOW_ATTR_MINIMIZABLE = 1,
-   UNITY_WINDOW_ATTR_MAXIMIZABLE = 2,
-   UNITY_WINDOW_ATTR_MAXIMIZED = 3,
-   UNITY_WINDOW_ATTR_CLOSABLE = 5,
-   UNITY_WINDOW_ATTR_HAS_TITLEBAR = 6,
-   UNITY_WINDOW_ATTR_VISIBLE = 7,
-   UNITY_WINDOW_ATTR_CHILD_WINDOW = 8,
-   UNITY_WINDOW_ATTR_HAS_TOOLBAR_BTN = 9,
-   UNITY_WINDOW_ATTR_BELONGS_TO_APP = 10,
-   UNITY_WINDOW_ATTR_DROPSHADOWED = 11,
-   UNITY_WINDOW_ATTR_ALWAYS_ABOVE = 12,
-   UNITY_WINDOW_ATTR_ALWAYS_BELOW = 13,
-   UNITY_WINDOW_ATTR_DISABLED = 14,
-   UNITY_WINDOW_ATTR_NOACTIVATE = 15,
-   UNITY_WINDOW_ATTR_SYSMENU = 16,
+   UNITY_WINDOW_ATTR_BORDERLESS = 0,        ///< @deprecated
+   UNITY_WINDOW_ATTR_MINIMIZABLE = 1,       ///< Can be minimized.
+   UNITY_WINDOW_ATTR_MAXIMIZABLE = 2,       ///< Can be maximized.
+   UNITY_WINDOW_ATTR_MAXIMIZED = 3,         /**< Is maximized.  @note Not mutually exclusive
+                                                 with @ref UNITY_WINDOW_STATE_MINIMIZED. */
+   UNITY_WINDOW_ATTR_CLOSABLE = 5,          ///< Supports closing.
+   UNITY_WINDOW_ATTR_HAS_TITLEBAR = 6,      ///< @deprecated 
+   UNITY_WINDOW_ATTR_VISIBLE = 7,           ///< @deprecated 
+   UNITY_WINDOW_ATTR_CHILD_WINDOW = 8,      ///< @deprecated 
+   UNITY_WINDOW_ATTR_HAS_TASKBAR_BTN = 9,   /**< Should appear in the taskbar.
+                                                 @todo Consider deprecation? */
+   UNITY_WINDOW_ATTR_MOVABLE = 10,          ///< Can be moved around the desktop. 
+   UNITY_WINDOW_ATTR_RESIZABLE = 11,        ///< Can be resized. 
+   UNITY_WINDOW_ATTR_ALWAYS_ABOVE = 12,     ///< Should stay on top of stack. 
+   UNITY_WINDOW_ATTR_ALWAYS_BELOW = 13,     ///< Should stay at bottom of stack. 
+   UNITY_WINDOW_ATTR_DISABLED = 14,         ///< Keyboard, mouse input is disabled.
+   UNITY_WINDOW_ATTR_NOACTIVATE = 15,       /**< Does not raise to foreground via mouse
+                                                 click, alt-tab, etc. */
+   UNITY_WINDOW_ATTR_SYSMENU = 16,          /**< Window includes system menu (e.g., on
+                                                 Windows, right-click the taskbar
+                                                 button). */
    UNITY_WINDOW_ATTR_TOOLWINDOW = 17,
-   UNITY_WINDOW_ATTR_APPWINDOW = 18,
-   UNITY_WINDOW_ATTR_FULLSCREENABLE = 19,
-   UNITY_WINDOW_ATTR_FULLSCREENED = 20,
-   UNITY_WINDOW_ATTR_ATTN_WANTED = 21,
-   UNITY_WINDOW_ATTR_SHADEABLE = 22,
-   UNITY_WINDOW_ATTR_SHADED = 23,
-   UNITY_WINDOW_ATTR_STICKABLE = 24,
-   UNITY_WINDOW_ATTR_STICKY = 25,
-   UNITY_WINDOW_ATTR_MODAL = 26,
-
-   UNITY_MAX_ATTRIBUTES // Not a valid attribute
+   UNITY_WINDOW_ATTR_APPWINDOW = 18,        /**< Application window.  Should appear in
+                                                 task switchers, etc. */
+   UNITY_WINDOW_ATTR_FULLSCREENABLE = 19,   ///< @deprecated
+   UNITY_WINDOW_ATTR_FULLSCREENED = 20,     ///< @deprecated
+   UNITY_WINDOW_ATTR_ATTN_WANTED = 21,      ///< Application wants user's attention.
+   UNITY_WINDOW_ATTR_SHADEABLE = 22,        ///< @deprecated 
+   UNITY_WINDOW_ATTR_SHADED = 23,           ///< @deprecated 
+   UNITY_WINDOW_ATTR_STICKABLE = 24,        ///< Can be made sticky.
+   UNITY_WINDOW_ATTR_STICKY = 25,           ///< Window should appear on all desktops.
+   UNITY_WINDOW_ATTR_MODAL = 26,            /**< Modal window.
+                                                 @todo But relative to which app? */
+
+   UNITY_MAX_ATTRIBUTES                     ///< Final, sentinel attribute entry.
 } UnityWindowAttribute;
 
 typedef enum {
index 47c703fa19de90478ada3570083b9a58145c8d2c..785593e6482212cb6f3789af1afab84fff81ad44 100644 (file)
@@ -31,6 +31,7 @@
 
 #define UUID_SIZE 16
 #define UUID_STRSIZE (2*UUID_SIZE + 1)
+#define        UUID_MAXLEN 48
 
 Bool UUID_ConvertToBin(uint8 dest_id[UUID_SIZE], const char *text);
 char *UUID_ConvertToText(const uint8 id[UUID_SIZE]);
index 20c24047400eb88873598602920d8cf6253ec2ea..809ed0e643d909f1e5dc00354d591506e593873e 100644 (file)
@@ -50,7 +50,8 @@ typedef enum {
    VMGUESTLIB_ERROR_MEMORY,                      // Not enough memory
    VMGUESTLIB_ERROR_BUFFER_TOO_SMALL,            // Buffer too small
    VMGUESTLIB_ERROR_INVALID_HANDLE,              // Handle is invalid
-   VMGUESTLIB_ERROR_INVALID_ARG                  // One or more arguments were invalid
+   VMGUESTLIB_ERROR_INVALID_ARG,                 // One or more arguments were invalid
+   VMGUESTLIB_ERROR_UNSUPPORTED_VERSION          // The host doesn't support this request
 } VMGuestLibError;
 
 
index 105616d410d0e0437836c7d17e992219f86daa1e..e0d28d8e6524e0fa28c805efcfb653a2dfd44e80 100644 (file)
     (!defined KERNEL && !defined _KERNEL && !defined VMKERNEL && !defined __KERNEL__)
 #   include <stddef.h>
 #else
-// XXX the __cplusplus one matches that of VC++, to prevent redefinition warning
+// XXX the _WIN32 one matches that of VC++, to prevent redefinition warning
 // XXX the other one matches that of gcc3.3.3/glibc2.2.4 to prevent redefinition warnings
 #ifndef offsetof
-#ifdef __cplusplus
+#ifdef _WIN32
 #define offsetof(s,m)   (size_t)&(((s *)0)->m)
 #else
 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
index e499e9848b71d65c82a1e1c18e71fc02a4ffeee4..317e25d20f60629e5e788016974f36af6bfa8121 100644 (file)
@@ -49,7 +49,7 @@
  * Use PATENTS_STRING for showing the patents string in plaintext form.
  * PATENTS_FMT_STRING can be used with PATENTS_URL for creating hyperlinks.
  */
-#define PATENTS_STRING_BASE "This product is protected by U.S. and international copyright and\nintellectual property laws. This product is covered by one or more\npatents listed at "
+#define PATENTS_STRING_BASE "This product is protected by U.S. and international copyright and\nintellectual property laws. VMware products are covered by one or\nmore patents listed at "
 #define PATENTS_STRING PATENTS_STRING_BASE "<" PATENTS_URL ">."
 #define PATENTS_FMT_STRING PATENTS_STRING_BASE "%s."
 #define PATENTS_URL "http://www.vmware.com/go/patents"
index aa57c46e6e613c2fd9661319422142740c6edc39..83b69eb201fb9772e68945a442ee1d898100ec0e 100644 (file)
 #define PRODUCT_VDM_SHORT_NAME "VDM"
 #define PRODUCT_VDM_NAME MAKE_NAME("Virtual Desktop Manager")
 
+#define PRODUCT_VDDK_SHORT_NAME "VDDK"
+#define PRODUCT_VDDK_NAME MAKE_NAME("VMware Virtual Disk Development Kit")
+
 #define PRODUCT_VDM_CLIENT_NAME MAKE_NAME("VDM Client")
 #define PRODUCT_VDM_CLIENT_NAME_FOR_LICENSE PRODUCT_VDM_CLIENT_NAME
 
       || defined(VMX86_VMLS)     \
       || defined(VMX86_VLICENSE) \
       || defined(VMX86_P2V)      \
-      || defined(VMX86_DDK))
+      || defined(VMX86_DDK)      \
+      || defined(VMX86_VDDK))
 #   if defined(_WIN32)
       /*
        * XXX Make the product be Workstation by default if none of the defines
 # define PRODUCT_SHORT_NAME PRODUCT_VLICENSE_NAME
 #elif defined(VMX86_DDK)
 # define PRODUCT_SHORT_NAME PRODUCT_DDK_NAME
+#elif defined(VMX86_VDDK)
+# define PRODUCT_SHORT_NAME PRODUCT_VDDK_NAME
 #endif
 
 
index 112304e37e53f839d05fd1ad133dc16bc4e208c4..41ccb668b0fe544ca6b05bd5045f00319635e572 100644 (file)
@@ -855,6 +855,13 @@ typedef uint32 ToolsVersion;
 #define   TOOLS_VERSION_FUSION15_UPDATE1_V_MNR      9
 #define   TOOLS_VERSION_FUSION15_UPDATE1_V_BASE     4
 
+#ifndef RC_INVOKED
+#define   TOOLS_VERSION_FUSION15_UPDATE2    TOOLS_VERSION_TO_UINT(TOOLS_VERSION_FUSION15_UPDATE2_V)
+#endif /* RC_INVOKED */
+#define   TOOLS_VERSION_FUSION15_UPDATE2_V_MJR      7
+#define   TOOLS_VERSION_FUSION15_UPDATE2_V_MNR      9
+#define   TOOLS_VERSION_FUSION15_UPDATE2_V_BASE     5
+
 /*
  * At the request of CPD, ESX 4.0 receives its own major version (8.0.0).
  */
index 03f16f88d7c7eb283dbe5c3aeab10b7407c345d2..eaefc1caa6db1fc3b0f947b0ab2e1fa2a3fc9ec1 100644 (file)
 #define VIPERL_VERSION "1.1.0"
 #define RCLI_VERSION "4.0.0"
 #define VDM_VERSION "e.x.p"
+#define VMSAFE_VERSION "e.x.p"
+#define VDDK_VERSION          "1.1.0"
+#define VDDK_FILE_VERSION      1,1,0,PRODUCT_BUILD_NUMBER_NUMERIC
+#define OVFTOOL_VERSION "1.0.0"
 #define VDM_CLIENT_VERSION "e.x.p"
+#define OVFTOOL_VERSION "1.0.0"
 
 // VMRC_PLUGIN_VERSION should match PLAYER_VERSION but can't be e.x.p
 #ifndef MAKESTR
 /*
  * The current Tools version, derived from vm_tools_version.h. Do not modify this.
  */
-#define TOOLS_VERSION "2008.12.23"
+#define TOOLS_VERSION "2009.01.21"
 
 #ifdef VMX86_VPX
 #define VIM_API_TYPE "VirtualCenter"
 #  define PRODUCT_VERSION_NUMBER DDK_VERSION
 #elif defined(VMX86_TOOLS)
 #  define PRODUCT_VERSION_NUMBER TOOLS_VERSION
+#elif defined(VMX86_VDDK)
+#  define PRODUCT_VERSION_NUMBER VDDK_VERSION
 #endif
 
 /*
index 87ae2dbc1852a2a8054ed4d990de635fac3dd9b6..55665470f73555c27cc4751f2bd3d088b6f8ddd7 100644 (file)
@@ -53,7 +53,6 @@
 #define VMBACKUP_PROTOCOL_ABORT           VMBACKUP_PROTOCOL_PREFIX"abort"
 #define VMBACKUP_PROTOCOL_SNAPSHOT_DONE   VMBACKUP_PROTOCOL_PREFIX"snapshotDone"
 #define VMBACKUP_PROTOCOL_EVENT_SET       VMBACKUP_PROTOCOL_PREFIX"eventSet"
-#define VMBACKUP_PROTOCOL_EVENT_GET       VMBACKUP_PROTOCOL_PREFIX"eventGet"
 
 /* These are responses to messages sent to the guest. */
 #define VMBACKUP_PROTOCOL_ERROR           "protocol.error"
index b04abaf9bd02a83d88778ec4ed12072691d6f212..b4954b82c0f5f2b03aa41d72fd3fb30497e71f83 100644 (file)
@@ -26,7 +26,7 @@ libMisc_la_SOURCES += dynarray.c
 libMisc_la_SOURCES += dynbuf.c
 libMisc_la_SOURCES += escape.c
 libMisc_la_SOURCES += hashTable.c
-libMisc_la_SOURCES += hostinfo_misc.c
+libMisc_la_SOURCES += hostinfoPosix.c
 libMisc_la_SOURCES += hostname.c
 libMisc_la_SOURCES += idLinux.c
 libMisc_la_SOURCES += iovector.c
index 02b73155b1f5e4d395d38619f3f5bd7dda9a94fc..9a73045d558f6616fc5bbd0600b988a5b8c566b6 100644 (file)
@@ -82,63 +82,6 @@ DynArray_Destroy(DynArray *a)    // IN/OUT
 }
 
 
-/*
- *-----------------------------------------------------------------------------
- *
- * DynArray_AddressOf --
- *
- *      Fetch a pointer to the address of the ith element.
- *
- * Results:
- *      The pointer to the ith element or NULL if the index is out of
- *      bounds.
- *
- * Side effects:
- *      None
- *
- *-----------------------------------------------------------------------------
- */
-
-void *
-DynArray_AddressOf(const DynArray *a,   // IN
-                   unsigned int i)      // IN
-{
-   uint8 *result = NULL;
-
-   ASSERT(a);
-
-   if (i < DynArray_Count(a)) {
-      result = ((uint8 *)DynBuf_Get(&a->buf)) + (i * a->width);
-   }
-   return result;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * DynArray_Count --
- *
- *      Returns the number of elements in the array.
- *
- * Results:
- *      See above.
- *
- * Side effects:
- *      None.
- *
- *-----------------------------------------------------------------------------
- */
-
-unsigned int
-DynArray_Count(const DynArray *a)       // IN
-{
-   ASSERT(a);
-
-   return (unsigned int) (DynBuf_GetSize(&a->buf) / a->width);
-}
-
-
 /*
  *-----------------------------------------------------------------------------
  *
@@ -190,6 +133,9 @@ DynArray_SetCount(DynArray *a,          // IN/OUT
  *      DynArray_AllocCount is within some threshold of DynArray_Count.
  *      It won't buy you much).
  *
+ *      XXX: This is relatively slow, since we do an integer division.
+ *           Avoid calling this in inner loops.
+ *
  * Results:
  *      See above.
  *
@@ -208,32 +154,6 @@ DynArray_AllocCount(const DynArray *a)  // IN
 }
 
 
-/*
- *-----------------------------------------------------------------------------
- *
- * DynArray_Trim --
- *
- *      Resize the array to fit exactly DynArray_Count() elements.
- *
- * Results:
- *      TRUE on success
- *      FALSE on failure (why?  who knows...)
- *
- * Side effects:
- *      Resizes the array
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-DynArray_Trim(DynArray *a)    // IN/OUT
-{
-   ASSERT(a);
-
-   return DynBuf_Trim(&a->buf);
-}
-
-
 /*
  *-----------------------------------------------------------------------------
  *
@@ -263,36 +183,3 @@ DynArray_QSort(DynArray *a,             // IN/OUT
    arrayBuf = DynBuf_Get(&a->buf);
    qsort(arrayBuf, DynArray_Count(a), a->width, compare);
 }
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * DynArray_Copy --
- *
- *      Copies all data and metadata from src Dynarray to dest DynArray.
- *      
- *      Dest should be an initialized DynArray of size zero.
- *
- * Results:
- *      TRUE on success, FALSE on failure.
- *
- * Side effects:
- *      None.
- *
- *-----------------------------------------------------------------------------
- */
-
-Bool
-DynArray_Copy(DynArray *src,        // IN
-              DynArray *dest)       // OUT
-{
-   ASSERT(src);
-   ASSERT(dest);
-   ASSERT(dest->width);
-   ASSERT(dest->width == src->width);
-   ASSERT(DynArray_AllocCount(dest) == 0);
-
-   return DynBuf_Copy(&src->buf, &dest->buf);
-}
-
index 730d22389af0e2f62df7dc465e06f2ea4bb6f386..57c7e8439008e324209f1f26579c4f480d4acf89 100644 (file)
@@ -85,31 +85,6 @@ DynBuf_Destroy(DynBuf *b) // IN
 }
 
 
-/*
- *-----------------------------------------------------------------------------
- *
- * DynBuf_Get --
- *
- *      Retrieve a pointer to the data contained in a dynamic buffer --hpreg
- *
- * Results:
- *      The pointer to the data
- *
- * Side effects:
- *      None
- *
- *-----------------------------------------------------------------------------
- */
-
-void *
-DynBuf_Get(DynBuf const *b) // IN
-{
-   ASSERT(b);
-
-   return b->data;
-}
-
-
 /*
  *-----------------------------------------------------------------------------
  *
@@ -340,7 +315,7 @@ DynBuf_Append(DynBuf *b,        // IN
               size_t size)      // IN
 {
    size_t new_size;
-   
+
    ASSERT(b);
 
    if (size <= 0) {
@@ -390,83 +365,6 @@ DynBuf_Trim(DynBuf *b) // IN
 }
 
 
-/*
- *-----------------------------------------------------------------------------
- *
- * DynBuf_GetSize --
- *
- *      Returns the current size of the dynamic buffer --hpreg
- *
- * Results:
- *      The current size of the dynamic buffer
- *
- * Side effects:
- *      None
- *
- *-----------------------------------------------------------------------------
- */
-
-size_t
-DynBuf_GetSize(DynBuf const *b) // IN
-{
-   ASSERT(b);
-
-   return b->size;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * DynBuf_SetSize --
- *
- *      Set the current size of a dynamic buffer --hpreg
- *
- * Results:
- *      None
- *
- * Side effects:
- *      None
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-DynBuf_SetSize(DynBuf *b,   // IN
-               size_t size) // IN
-{
-   ASSERT(b);
-   ASSERT(size <= b->allocated);
-
-   b->size = size;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * DynBuf_GetAllocatedSize --
- *
- *      Returns the current allocated size of the dynamic buffer --hpreg
- *
- * Results:
- *      The current allocated size of the dynamic buffer
- *
- * Side effects:
- *      None
- *
- *-----------------------------------------------------------------------------
- */
-
-size_t
-DynBuf_GetAllocatedSize(DynBuf const *b) // IN
-{
-   ASSERT(b);
-
-   return b->allocated;
-}
-
-
 /*
  *-----------------------------------------------------------------------------
  *
@@ -503,6 +401,6 @@ DynBuf_Copy(DynBuf *src,   // IN
    }
 
    memcpy(dest->data, src->data, src->size);
-   
+
    return TRUE;
 }
similarity index 67%
rename from open-vm-tools/lib/misc/hostinfo_misc.c
rename to open-vm-tools/lib/misc/hostinfoPosix.c
index d8fbea6f05f95b90d760bee514f86d0a9faa651c..cd26d0aa183eca6ce6429839a85cfc2eddac414f 100644 (file)
 
 #include <stdio.h>
 #include <stdlib.h>
-
-#if defined(_WIN32)
-#include <windows.h>
-#include <winbase.h>
-#else
 #include <string.h>
 #include <errno.h>
 #include <sys/time.h>
 #include <sys/utsname.h>
+#include <fcntl.h>
+#if defined(sun)
+#include <sys/systeminfo.h>
+#endif
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <errno.h>
+#if defined(__FreeBSD__) || defined(__APPLE__)
+# include <sys/sysctl.h>
 #endif
 
 #include "vmware.h"
 #include "safetime.h"
 #include "str.h"
 
+#define SYSINFO_STRING_32       "i386"
+#define SYSINFO_STRING_64       "amd64"
+#define MAX_ARCH_NAME_LEN       sizeof SYSINFO_STRING_32 > sizeof SYSINFO_STRING_64 ? \
+                                   sizeof SYSINFO_STRING_32 : \
+                                   sizeof SYSINFO_STRING_64
+
 static Bool hostinfoOSVersionInitialized;
 
-#if defined(_WIN32)
-static int hostinfoOSVersion[4];
-static DWORD hostinfoOSPlatform;
-#else
 #if defined(__APPLE__)
 #define SYS_NMLN _SYS_NAMELEN
 #endif
 static int hostinfoOSVersion[3];
 static char hostinfoOSVersionString[SYS_NMLN];
-#endif
-
-
-#if defined(_WIN32)
-/*
- *----------------------------------------------------------------------
- *
- * HostinfoOSVersionInit --
- *
- *      Compute the OS version information
- *
- * Results:
- *      None.
- *
- * Side effects:
- *      hostinfoOS* variables are filled in.
- *
- *----------------------------------------------------------------------
- */
-
-void
-HostinfoOSVersionInit(void)
-{
-   OSVERSIONINFO info;
-   OSVERSIONINFOEX infoEx;
-
-   if (hostinfoOSVersionInitialized) {
-      return;
-   }
-
-   info.dwOSVersionInfoSize = sizeof (info);
-   if (!GetVersionEx(&info)) {
-      Warning("Unable to get OS version.\n");
-      NOT_IMPLEMENTED();
-   }
-   ASSERT(ARRAYSIZE(hostinfoOSVersion) >= 4);
-   hostinfoOSVersion[0] = info.dwMajorVersion;
-   hostinfoOSVersion[1] = info.dwMinorVersion;
-   hostinfoOSVersion[2] = info.dwBuildNumber & 0xffff;
-   /*
-    * Get the service pack number. We don't care much about NT4 hosts
-    * so we can use OSVERSIONINFOEX without checking for Windows NT 4.0 SP6 
-    * or later versions.
-    */
-   infoEx.dwOSVersionInfoSize = sizeof infoEx;
-   if (GetVersionEx((OSVERSIONINFO*)&infoEx)) {
-      hostinfoOSVersion[3] = infoEx.wServicePackMajor;
-   }
-   hostinfoOSPlatform = info.dwPlatformId;
-
-   hostinfoOSVersionInitialized = TRUE;
-}
-
-
-/*
- *----------------------------------------------------------------------
- *
- * Hostinfo_OSIsWinNT --
- *
- *      This is Windows NT or descendant.
- *
- * Results:
- *      TRUE if Windows NT or descendant.
- *
- * Side effects:
- *      None.
- *
- *----------------------------------------------------------------------
- */
-
-Bool
-Hostinfo_OSIsWinNT(void)
-{
-   HostinfoOSVersionInit();
-   return hostinfoOSPlatform == VER_PLATFORM_WIN32_NT;
-}
-#else
 
 
 /*
@@ -192,9 +123,9 @@ const char *
 Hostinfo_OSVersionString(void)
 {
    HostinfoOSVersionInit();
+
    return hostinfoOSVersionString;
 }
-#endif
 
 
 /*
@@ -218,6 +149,7 @@ int
 Hostinfo_OSVersion(int i)
 {
    HostinfoOSVersionInit();
+
    return i < ARRAYSIZE(hostinfoOSVersion) ? hostinfoOSVersion[i] : 0;
 }
 
@@ -242,17 +174,85 @@ Hostinfo_OSVersion(int i)
 void 
 Hostinfo_GetTimeOfDay(VmTimeType *time)
 {
-#if defined(_WIN32)
-   struct _timeb t;
-
-   _ftime(&t);
-
-   *time = (t.time * 1000000) + t.millitm * 1000;
-#else  // assume POSIX
    struct timeval tv;
 
    gettimeofday(&tv, NULL);
 
    *time = ((int64)tv.tv_sec * 1000000) + tv.tv_usec;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * Hostinfo_GetSystemBitness --
+ *
+ *      Determines the operating system's bitness.
+ *
+ * Return value:
+ *      32 or 64 on success, negative value on failure. Check errno for more
+ *      details of error.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+Hostinfo_GetSystemBitness(void)
+{
+#if defined(linux)
+   struct utsname u;
+
+   if (uname(&u) < 0) {
+      return -1;
+   }
+   if (strstr(u.machine, "x86_64")) {
+      return 64;
+   } else {
+      return 32;
+   }
+#elif defined(N_PLAT_NLM)
+   return 32;
+#else
+   char buf[MAX_ARCH_NAME_LEN] = { 0 };
+
+#if defined(__FreeBSD__) || defined(__APPLE__)
+   int mib[2];
+   size_t len;
+
+   len = sizeof buf;
+   mib[0] = CTL_HW;
+   mib[1] = HW_MACHINE;
+
+   if (sysctl(mib, ARRAYSIZE(mib), buf, &len, NULL, 0) < 0) {
+      return -1;
+   }
+#elif defined(sun)
+#if !defined(SOL10)
+   /*
+    * XXX: This is bad.  We define SI_ARCHITECTURE_K to what it is on Solaris
+    * 10 so that we can use a single guestd build for Solaris 9 and 10.  In the
+    * future we should have the Solaris 9 build just return 32 -- since it did
+    * not support 64-bit x86 -- and let the Solaris 10 headers define
+    * SI_ARCHITECTURE_K, then have the installer symlink to the correct binary.
+    * For now, though, we'll share a single build for both versions.
+    */
+#  define SI_ARCHITECTURE_K  518
+# endif
+
+   if (sysinfo(SI_ARCHITECTURE_K, buf, sizeof buf) < 0) {
+      return -1;
+   }
+
+   if (strcmp(buf, SYSINFO_STRING_32) == 0) {
+      return 32;
+   } else if (strcmp(buf, SYSINFO_STRING_64) == 0) {
+      return 64;
+   }
+#endif
+
+   return -1;
 #endif
 }
index 25987ca1905556decf3e335b46457ffc3326dc72..45e78a0453c3883cfa1d5ef60bbeee8679cc26e9 100644 (file)
@@ -438,6 +438,92 @@ StrUtil_StrToSizet(size_t *out,     // OUT: The output value
 }
 
 
+#ifndef N_PLAT_NLM // NetWare Tools ask for unresolved _GLOBAL_OFFSET_TABLE...
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * StrUtil_CapacityToSectorType --
+ *
+ *      Converts a string containing a measure of disk capacity (such as
+ *      "100MB" or "1.5k") into an unadorned and primitive quantity of sector
+ *      capacity. The comment before the switch statement describes the kinds of
+ *      disk capacity expressible.
+ *
+ * Results:
+ *      TRUE if conversion was successful, FALSE otherwise.
+ *      Value is stored in 'out', which is left undefined in the FALSE case.
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+StrUtil_CapacityToSectorType(SectorType *out,    // OUT: The output value
+                             const char *str,    // IN: String to parse
+                             unsigned int bytes) // IN: Bytes per unit in an
+                                                 //     unadorned string
+
+{
+   double quantity;
+   char *rest;
+
+   ASSERT(out);
+   ASSERT(str);
+
+   errno = 0;
+   quantity = strtod(str, &rest);
+   if (errno == ERANGE) {
+      return FALSE;
+   }
+
+   /* Skip over any whitespace in the suffix. */
+   while (*rest == ' ' || *rest == '\t') {
+      rest++;
+   }
+   if (*rest != '\0') {
+      uint64 shift;
+
+      /*
+       * [kK], [mM], [gG], and [tT] represent kilo, mega, giga, and tera
+       * byte quantities respectively. [bB] represents a singular byte
+       * quantity. [sS] represents a sector quantity. 
+       *
+       * All other suffixes are ignored, which also means a suffix like
+       * "MB" will be treated as 'M'.
+       */
+      switch (*rest) {
+      case 's': case 'S':          shift = 9;  break;
+      case 'k': case 'K':          shift = 10; break;
+      case 'm': case 'M':          shift = 20; break;
+      case 'g': case 'G':          shift = 30; break;
+      case 't': case 'T':          shift = 40; break;
+      case 'b': case 'B': default: shift = 0;  break;
+      }
+      quantity *= (double)(1 << shift);
+   } else {
+      /*
+       * No suffix, so multiply by the number of bytes per unit as specified by
+       * the caller.
+       */
+      quantity *= (double)bytes;
+   }
+
+   /*
+    * Convert from "number of bytes" to "number of sectors", rounding up or down
+    * appropriately.
+    *
+    * XXX: We should use DISKLIB_SECTOR_SIZE, but do we really want the disklib
+    * header dependencies in this file?
+    *
+    */
+   *out = (SectorType)((quantity + 256) / 512);
+   return TRUE;
+}
+#endif
+                
+
 /*
  *-----------------------------------------------------------------------------
  *
index b1ee527a1f4fe3b6be2908905ebc11b1995111fd..d3fd0d98b86b209f97e1ef184e4ad26744b0d195 100644 (file)
@@ -455,16 +455,19 @@ Util_GetCurrentThreadId(void)
     */
 
    static int useTid = 1;
+#if defined(VMX86_SERVER) && defined(VMX86_VMX) // ESX with userworld VMX
+   static __thread pid_t tid = -1;
+#else
    pid_t tid;
-
-   // ESX with userworld VMX
-#if defined(VMX86_SERVER)
-   if (HostType_OSIsVMK()) {
-      return User_GetTid();
-   }
 #endif
 
+
    if (useTid) {
+#if defined(VMX86_SERVER) && defined(VMX86_VMX) // ESX with userworld VMX
+      if (tid != -1) {
+         return tid;
+      }
+#endif
       tid = gettid();
       if (tid != (pid_t)-1) {
          return tid;
index d859f05efbf0ffeb3ac78cc0f38d2fac78b7add6..e29b8be3ee966aeccf95c1b14b2d848b21995fdc 100644 (file)
@@ -478,7 +478,16 @@ Panic_Panic(const char *format,
 
    fputs(buf, stderr);
 #ifdef _WIN32
-   Win32U_OutputDebugString(buf);
+   /*
+    * This would nominally be Win32U_OutputDebugString.  However,
+    * OutputDebugString is unusual in that the W version converts
+    * to local encoding and calls the A version.
+    *
+    * Since any such conversion is risky (read: can Panic) and
+    * we haven't yet hit the loop detection, we will conservatively
+    * dump UTF-8 via the A version.
+    */
+   OutputDebugStringA(buf);
 #endif
 
    /*
@@ -505,6 +514,15 @@ Panic_Panic(const char *format,
       NOT_REACHED();
    }
 
+#ifdef _WIN32
+   /*
+    * Output again, in a way that we hope localizes correctly.  Since
+    * we are converting, this can Panic, so it must run after loop
+    * detection.
+    */
+   Win32U_OutputDebugString(buf);
+#endif
+
    /*
     * Log panic information, and make sure we don't remove
     * the log file on exit.
index 509f419a83734ef02a9bc4cbbd8b5a240f5c679c..27a71f7e416bd9a6d645285dd4e36da275abbc48 100644 (file)
@@ -2929,7 +2929,7 @@ UnityPlatformSetDesktopConfig(UnityPlatform *up,                             //
     */
    i = 0;
    memset(guestDesktopLayout, 0xFF, sizeof guestDesktopLayout); // Set all entries to -1
-   if (up->desktopInfo.layoutData[0] == _NET_WM_ORIENTATION_VERT) {
+   if (up->desktopInfo.layoutData[0] == _NET_WM_ORIENTATION_HORZ) {
       for (y = 0; y <= desktopSpread.y; y++) {
          for (x = 0; x <= desktopSpread.x; x++) {
             if (unityDesktopLayout[x][y] >= 0) {
index dc9382768452381e3a08b300738c053aefea434d..87df639f99ef56a4f5f7823887861e947243a93b 100644 (file)
@@ -71,6 +71,7 @@
 #include "vixCommands.h"
 #include "base64.h"
 #include "guestInfo.h"
+#include "hostinfo.h"
 #include "hgfsServer.h"
 #include "hgfs.h"
 #include "system.h"
@@ -814,7 +815,7 @@ VixTools_GetToolsPropertiesImpl(GuestApp_Dict **confDictRef,      // IN
       osNameFull[0] = 0;
       osName[0] = 0;
    }
-   wordSize = GuestInfo_GetSystemBitness();
+   wordSize = Hostinfo_GetSystemBitness();
    if (wordSize <= 0) {
       wordSize = 32;
    }
index 1858665ecc15179f1f747c0dd1f91729f0e2d94e..0824fe64a79c3b9d32d7e69901e2f2ce78f1ed81 100644 (file)
@@ -17,6 +17,9 @@
 
 lib_LTLIBRARIES = libguestlib.la
 
+AM_CFLAGS =
+AM_CFLAGS += -I$(top_builddir)/include
+
 libguestlib_la_LIBADD =
 libguestlib_la_LIBADD += ../lib/rpcOut/libRpcOut.la
 libguestlib_la_LIBADD += ../lib/string/libString.la
@@ -26,6 +29,7 @@ libguestlib_la_LIBADD += ../lib/stubs/libStubs.la
 # order so their symbols are properly resolved.
 libguestlib_la_LIBADD += ../lib/message/libMessage.la
 libguestlib_la_LIBADD += ../lib/backdoor/libBackdoor.la
+libguestlib_la_LIBADD += ../lib/guestRpc/libGuestRpc.la
 
 libguestlib_la_SOURCES =
 libguestlib_la_SOURCES += vmGuestLib.c
index 5edeca6fe621ee8e3762bc167cd6f2c891bdd24b..d9cbf1c4fb04511f76d1ea79cf736233a927d2cf 100644 (file)
 #include "rpcout.h"
 #include "vmcheck.h"
 #include "guestApp.h" // for ALLOW_TOOLS_IN_FOREIGN_VM
-
-#define GUESTLIB_NAME "VMware Guest API"
-
-
-// XXX For testing only. As a real "library", this should not be here.
+#include "util.h"
 #include "debug.h"
+#include "strutil.h"
+#include "guestrpc/guestlibV3.h"
 
+#define GUESTLIB_NAME "VMware Guest API"
 
-
-#if 0
-/*
- *-----------------------------------------------------------------------------
- *
- * VMGuestLibDumpData --
- *
- *      Debugging routine to print a data struct.
- *
- * Results:
- *      None
- *
- * Side effects:
- *      None
- *
- *-----------------------------------------------------------------------------
+/* 
+ * These are client side data structures, separate from the wire data formats
+ * (VMGuestLibDataV[23]).
  */
 
-static void
-VMGuestLibDumpData(VMGuestLibDataV2 *data) // IN
-{
-   ASSERT(data);
+/* Layout of the buffer holding the variable length array of V3 statistics. */
+typedef struct {
+   GuestLibV3StatCount   numStats;
+   GuestLibV3Stat        stats[0];
+} VMGuestLibStatisticsV3;
 
-   printf("version: %u\n"
-          "sessionId: %"FMT64"u\n"
-          "cpuReservationMHz: %u\n"
-          "cpuLimitMHz: %u\n"
-          "cpuShares: %u\n"
-          "cpuUsedMs: %"FMT64"u\n"
-          "hostMHz: %u\n"
-          "memReservationMB: %u\n"
-          "memLimitMB: %u\n"
-          "memShares: %u\n"
-          "memMappedMB: %u\n"
-          "memActiveMB: %u\n"
-          "memOverheadMB: %u\n"
-          "memBalloonedMB: %u\n"
-          "memSwappedMB: %u\n"
-          "memSharedMB: %u\n"
-          "memSharedSavedMB: %u\n"
-          "memUsedMB: %u\n"
-          "elapsedMs: %"FMT64"u\n"
-          "resourcePoolPath: '%s'\n"
-          "last character: '%c'\n",
-          data->version, data->sessionId,
-          data->cpuReservationMHz.value, data->cpuLimitMHz.value,
-          data->cpuShares.value, data->cpuUsedMs.value,
-          data->hostMHz.value, data->memReservationMB.value,
-          data->memLimitMB.value, data->memShares.value,
-          data->memMappedMB.value, data->memActiveMB.value,
-          data->memOverheadMB.value, data->memBalloonedMB.value,
-          data->memSwappedMB.value, data->memSharedMB.value, 
-          data->memSharedSavedMB.value, data->memUsedMB.value,
-          data->elapsedMs.value, data->resourcePoolPath.value,
-          data->resourcePoolPath.value[sizeof data->resourcePoolPath.value - 2]);
-}
-#endif
+/* Layout of the handle that holds information about the statistics. */
+typedef struct {
+   uint32 version;
+   VMSessionId sessionId;
+
+   /*
+    * Statistics.
+    *
+    * dataSize is the size of the buffer pointed to by 'data'.
+    * For v2 protocol: 
+    *   - 'data' points to VMGuestLibDataV2 struct,
+    * For v3 protocol:
+    *   - 'data' points to VMGuestLibStatisticsV3 struct.
+    */
+   size_t dataSize;
+   void *data;
+} VMGuestLibHandleType;
+
+#define HANDLE_VERSION(h)     (((VMGuestLibHandleType *)(h))->version)
+#define HANDLE_SESSIONID(h)   (((VMGuestLibHandleType *)(h))->sessionId)
+#define HANDLE_DATA(h)        (((VMGuestLibHandleType *)(h))->data)
+#define HANDLE_DATASIZE(h)    (((VMGuestLibHandleType *)(h))->dataSize)
+
+#define VMGUESTLIB_GETSTAT_V2(HANDLE, ERROR, OUTPTR, FIELDNAME)      \
+   do {                                                              \
+      VMGuestLibDataV2 *_dataV2 = HANDLE_DATA(HANDLE);               \
+      ASSERT(HANDLE_VERSION(HANDLE) == 2);                           \
+      if (!_dataV2->FIELDNAME.valid) {                               \
+         (ERROR) = VMGUESTLIB_ERROR_NOT_AVAILABLE;                   \
+         break;                                                      \
+      }                                                              \
+      *(OUTPTR) = _dataV2->FIELDNAME.value;                          \
+      (ERROR) = VMGUESTLIB_ERROR_SUCCESS;                            \
+   } while (0)
+
+#define VMGUESTLIB_GETSTAT_V3(HANDLE, ERROR, OUTPTR, FIELDNAME, STATID)         \
+   do {                                                                         \
+      void *_data;                                                              \
+      GuestLibV3Stat _stat;                                                     \
+                                                                                \
+      ASSERT(HANDLE_VERSION(HANDLE) == 3);                                      \
+      (ERROR) = VMGuestLibCheckArgs((HANDLE), (OUTPTR), &_data);                \
+      if (VMGUESTLIB_ERROR_SUCCESS != (ERROR)) {                                \
+         break;                                                                 \
+      }                                                                         \
+      (ERROR) = VMGuestLibGetStatisticsV3((HANDLE), (STATID), &_stat);          \
+      if ((ERROR) != VMGUESTLIB_ERROR_SUCCESS) {                                \
+         break;                                                                 \
+      }                                                                         \
+      if (!_stat.GuestLibV3Stat_u.FIELDNAME.valid) {                            \
+         (ERROR) = VMGUESTLIB_ERROR_NOT_AVAILABLE;                              \
+         break;                                                                 \
+      }                                                                         \
+      ASSERT(_stat.d == (STATID));                                              \
+      if (sizeof *(OUTPTR) < sizeof _stat.GuestLibV3Stat_u.FIELDNAME.value) {   \
+         (ERROR) = VMGUESTLIB_ERROR_BUFFER_TOO_SMALL;                           \
+      }                                                                         \
+      *(OUTPTR) = _stat.GuestLibV3Stat_u.FIELDNAME.value;                       \
+      (ERROR) = VMGUESTLIB_ERROR_SUCCESS;                                       \
+   } while (0)
+
+/* Handle extraction of integral type statistics. */
+#define VMGUESTLIB_GETFN_BODY(HANDLE, ERROR, OUTPTR, FIELDNAME, STATID)         \
+   do {                                                                         \
+      void *_data;                                                              \
+                                                                                \
+      (ERROR) = VMGuestLibCheckArgs((HANDLE), (OUTPTR), &_data);                \
+      if (VMGUESTLIB_ERROR_SUCCESS != (ERROR)) {                                \
+         break;                                                                 \
+      }                                                                         \
+      if (HANDLE_VERSION(HANDLE) == 2) {                                        \
+         VMGUESTLIB_GETSTAT_V2(HANDLE, ERROR, OUTPTR, FIELDNAME);               \
+      } else if (HANDLE_VERSION(HANDLE) == 3) {                                 \
+         VMGUESTLIB_GETSTAT_V3(HANDLE, ERROR, OUTPTR, FIELDNAME, STATID);       \
+      }                                                                         \
+   } while (0)
 
 
 /*
@@ -147,6 +176,9 @@ VMGuestLib_GetErrorText(VMGuestLibError error) // IN: Error code
    case VMGUESTLIB_ERROR_OTHER:
       return "Other error";
 
+   case VMGUESTLIB_ERROR_UNSUPPORTED_VERSION:
+      return "Host does not support this request.";
+
    default:
       ASSERT(FALSE); // We want to catch this case in debug builds.
       return "Other error";
@@ -178,7 +210,7 @@ VMGuestLib_GetErrorText(VMGuestLibError error) // IN: Error code
 static VMGuestLibError
 VMGuestLibCheckArgs(VMGuestLibHandle handle, // IN
                     void *outArg,            // IN
-                    VMGuestLibDataV2 **data) // OUT
+                    void **data)             // OUT
 {
    ASSERT(data);
 
@@ -190,9 +222,9 @@ VMGuestLibCheckArgs(VMGuestLibHandle handle, // IN
       return VMGUESTLIB_ERROR_INVALID_ARG;
    }
 
-   *data = (VMGuestLibDataV2 *)handle;
+   *data = HANDLE_DATA(handle);
 
-   if (0 == (*data)->sessionId) {
+   if (0 == HANDLE_SESSIONID(handle)) {
       return VMGUESTLIB_ERROR_NO_INFO;
    }
 
@@ -221,7 +253,7 @@ VMGuestLibCheckArgs(VMGuestLibHandle handle, // IN
 VMGuestLibError
 VMGuestLib_OpenHandle(VMGuestLibHandle *handle) // OUT
 {
-   VMGuestLibDataV2 *data;
+   VMGuestLibHandleType *data;
 
 #ifndef ALLOW_TOOLS_IN_FOREIGN_VM
    if (!VmCheck_IsVirtualWorld()) {
@@ -234,7 +266,7 @@ VMGuestLib_OpenHandle(VMGuestLibHandle *handle) // OUT
       return VMGUESTLIB_ERROR_INVALID_ARG;
    }
 
-   data = calloc(1, sizeof *data);
+   data = Util_SafeCalloc(1, sizeof *data);
    if (!data) {
       Debug("VMGuestLib_OpenHandle: Unable to allocate memory\n");
       return VMGUESTLIB_ERROR_MEMORY;
@@ -251,7 +283,8 @@ VMGuestLib_OpenHandle(VMGuestLibHandle *handle) // OUT
  * VMGuestLib_CloseHandle --
  *
  *      Release resources associated with a handle obtained from
- *      VMGuestLib_OpenHandle().
+ *      VMGuestLib_OpenHandle(). Handle is invalid after return
+ *      from this call.
  *
  * Results:
  *      VMGuestLibError
@@ -265,15 +298,29 @@ VMGuestLib_OpenHandle(VMGuestLibHandle *handle) // OUT
 VMGuestLibError
 VMGuestLib_CloseHandle(VMGuestLibHandle handle) // IN
 {
-   VMGuestLibDataV2 *data;
+   void *data;
 
    if (NULL == handle) {
       return VMGUESTLIB_ERROR_INVALID_HANDLE;
    }
 
-   data = (VMGuestLibDataV2 *)handle;
+   data = HANDLE_DATA(handle);
+   if (data != NULL &&
+       HANDLE_SESSIONID(handle) != 0 &&
+       HANDLE_VERSION(handle) == 3) {
+      VMGuestLibStatisticsV3 *v3stats = data;
+      GuestLibV3StatCount count;
+
+      for (count = 0; count < v3stats->numStats; count++) {
+         VMX_XDR_FREE(xdr_GuestLibV3Stat, &v3stats->stats[count]);
+      }
+   }
    free(data);
 
+   /* Be paranoid. */
+   HANDLE_DATA(handle) = NULL;
+   free(handle);
+
    return VMGUESTLIB_ERROR_SUCCESS;
 }
 
@@ -283,7 +330,8 @@ VMGuestLib_CloseHandle(VMGuestLibHandle handle) // IN
  *
  * VMGuestLibUpdateInfo --
  *
- *      Retrieve the bundle of stats over the backdoor.
+ *      Retrieve the bundle of stats over the backdoor and update the pointer to
+ *      the Guestlib info in the handle.
  *
  * Results:
  *      TRUE on success
@@ -296,51 +344,228 @@ VMGuestLib_CloseHandle(VMGuestLibHandle handle) // IN
  */
 
 static VMGuestLibError
-VMGuestLibUpdateInfo(VMGuestLibDataV2 *data) // IN
+VMGuestLibUpdateInfo(VMGuestLibHandle handle) // IN
 {
-   char commandBuf[64];
-   char *reply;
+   char *reply = NULL;
    size_t replyLen;
-   VMGuestLibDataV2 *newData;
+   VMGuestLibError ret = VMGUESTLIB_ERROR_INVALID_ARG;
+   uint32 hostVersion = HANDLE_VERSION(handle);
 
-   /*
-    * Construct command string with the command name and the version
-    * of the data struct that we want.
+   /* 
+    * Starting with the highest supported protocol (major) version, negotiate
+    * down to the highest host supported version. Host supports minimum version
+    * 2.
     */
-   Str_Sprintf(commandBuf, sizeof commandBuf, "%s %d",
-               VMGUESTLIB_BACKDOOR_COMMAND_STRING,
-               VMGUESTLIB_DATA_VERSION);
+   if (hostVersion == 0) {
+      hostVersion = VMGUESTLIB_DATA_VERSION;
+   }
 
-   /* Actually send the request. */
-   if (!RpcOut_sendOne(&reply, &replyLen, commandBuf)) {
-      Debug("Failed to retrieve info: %s\n", reply ? reply : "NULL");
+   do {
+      char commandBuf[64];
+      unsigned int index = 0;
+
+      /* Free the last reply when retrying. */
       free(reply);
-      return VMGUESTLIB_ERROR_NOT_ENABLED;
+      reply = NULL;
+
+      /*
+       * Construct command string with the command name and the version
+       * of the data struct that we want.
+       */
+      Str_Sprintf(commandBuf, sizeof commandBuf, "%s %d",
+                  VMGUESTLIB_BACKDOOR_COMMAND_STRING,
+                  hostVersion);
+
+      /* Send the request. */
+      if (RpcOut_sendOne(&reply, &replyLen, commandBuf)) {
+         VMGuestLibDataV2 *v2reply = (VMGuestLibDataV2 *)reply;
+         VMSessionId sessionId = HANDLE_SESSIONID(handle);
+
+         ASSERT(hostVersion == v2reply->hdr.version);
+
+         if (sessionId != 0 && sessionId != v2reply->hdr.sessionId) {
+            /* Renegotiate protocol if sessionId changed. */
+            hostVersion = VMGUESTLIB_DATA_VERSION;
+            HANDLE_SESSIONID(handle) = 0;
+            continue;
+         }
+         ret = VMGUESTLIB_ERROR_SUCCESS;
+         break;
+      }
+
+      /* 
+       * Host is older and doesn't support the requested protocol version.
+       * Request the highest version the host supports.
+       */
+      Debug("Failed to retrieve info: %s\n", reply ? reply : "NULL");
+
+      if (hostVersion == 2 ||
+          Str_Strncmp(reply, "Unknown command", sizeof "Unknown command") == 0) {
+         /* 
+          * Host does not support this feature. Older (v2) host would return
+          * "Unsupported version" if it doesn't recognize the requested version.
+          *
+          * XXX: Maybe use another error code for this case where the host
+          * product doesn't support this feature?
+          */
+         ret = VMGUESTLIB_ERROR_UNSUPPORTED_VERSION;
+         break;
+      } else if (hostVersion == 3) {
+         /*
+          * Host supports v2 at a minimum. If request for v3 fails, then just use
+          * v2, since v2 host does not send the highest supported version in the
+          * reply.
+          */
+         hostVersion = 2;
+         HANDLE_SESSIONID(handle) = 0;
+         continue;
+      } else if (!StrUtil_GetNextUintToken(&hostVersion, &index, reply, ":")) {
+         /*
+          * v3 and onwards, the host returns the highest major version it supports,
+          * if the requested version is not supported. So parse out the host
+          * version from the reply and return error if it didn't.
+          */
+         Debug("Bad reply received from host.\n");
+         ret = VMGUESTLIB_ERROR_OTHER;
+         break;
+      }
+      ASSERT(hostVersion < VMGUESTLIB_DATA_VERSION);
+   } while (ret != VMGUESTLIB_ERROR_SUCCESS);
+
+   if (ret != VMGUESTLIB_ERROR_SUCCESS) {
+      goto done;
    }
 
    /* Sanity check the results. */
-   if (replyLen < sizeof data->version) {
+   if (replyLen < sizeof hostVersion) {
       Debug("Unable to retrieve version\n");
-      return VMGUESTLIB_ERROR_OTHER;
-   }
-   newData = (VMGuestLibDataV2 *)reply;
-   if (newData->version != VMGUESTLIB_DATA_VERSION) {
-      Debug("Incorrect version returned\n");
-      return VMGUESTLIB_ERROR_OTHER;
+      ret = VMGUESTLIB_ERROR_OTHER;
+      goto done;
    }
-   if (replyLen != sizeof *data) {
-      Debug("Incorrect data size returned\n");
-      return VMGUESTLIB_ERROR_OTHER;
+
+   if (hostVersion == 2) {
+      VMGuestLibDataV2 *v2reply = (VMGuestLibDataV2 *)reply;
+      size_t dataSize = sizeof *v2reply;
+
+      /* More sanity checks. */
+      if (v2reply->hdr.version != hostVersion) {
+         Debug("Incorrect data version returned\n");
+         ret = VMGUESTLIB_ERROR_OTHER;
+         goto done;
+      }
+      if (replyLen != dataSize) {
+         Debug("Incorrect data size returned\n");
+         ret = VMGUESTLIB_ERROR_OTHER;
+         goto done;
+      }
+
+      /* Store the reply in the handle. */
+      HANDLE_VERSION(handle) = v2reply->hdr.version;
+      HANDLE_SESSIONID(handle) = v2reply->hdr.sessionId;
+      if (HANDLE_DATASIZE(handle) < dataSize) {
+         /* [Re]alloc if the local handle buffer is not big enough. */
+         free(HANDLE_DATA(handle));
+         HANDLE_DATA(handle) = Util_SafeCalloc(1, dataSize);
+         HANDLE_DATASIZE(handle) = dataSize;
+      }
+      memcpy(HANDLE_DATA(handle), reply, replyLen);
+
+      /* Make sure resourcePoolPath is NUL terminated. */
+      v2reply = HANDLE_DATA(handle);
+      v2reply->resourcePoolPath.value[sizeof v2reply->resourcePoolPath.value - 1] = '\0';
+      ret = VMGUESTLIB_ERROR_SUCCESS;
+   } else if (hostVersion == 3) {
+      VMGuestLibDataV3 *v3reply = (VMGuestLibDataV3 *)reply;
+      size_t dataSize;
+      XDR xdrs;
+      GuestLibV3StatCount count;
+      VMGuestLibStatisticsV3 *v3stats;
+
+      /* More sanity checks. */
+      if (v3reply->hdr.version != hostVersion) {
+         Debug("Incorrect data version returned\n");
+         ret = VMGUESTLIB_ERROR_OTHER;
+         goto done;
+      }
+      if (replyLen < sizeof *v3reply) {
+         Debug("Incorrect data size returned\n");
+         ret = VMGUESTLIB_ERROR_OTHER;
+         goto done;
+      }
+
+      /* 0. Copy the reply version and sessionId to the handle. */
+      HANDLE_VERSION(handle) = v3reply->hdr.version;
+      HANDLE_SESSIONID(handle) = v3reply->hdr.sessionId;
+
+      /* 
+       * 1. Retrieve the length of the statistics array from the XDR encoded
+       * part of the reply.
+       */
+      xdrmem_create(&xdrs, v3reply->data, v3reply->dataSize, XDR_DECODE);
+
+      if (!xdr_GuestLibV3StatCount(&xdrs, &count)) {
+         xdr_destroy(&xdrs);
+         goto done;
+      }
+      if (count >= GUESTLIB_MAX_STATISTIC_ID) {
+         /* 
+          * Host has more than we can process. So process only what this side
+          * can.
+          */
+         count = GUESTLIB_MAX_STATISTIC_ID - 1;
+      }
+
+      /* 2. [Re]alloc if the local handle buffer is not big enough. */
+      dataSize = sizeof *v3stats + (count * sizeof (GuestLibV3Stat));
+      if (HANDLE_DATASIZE(handle) < dataSize) {
+         free(HANDLE_DATA(handle));
+         HANDLE_DATA(handle) = Util_SafeCalloc(1, dataSize);
+         HANDLE_DATASIZE(handle) = dataSize;
+      }
+
+      /* 3. Unmarshal the array of statistics. */
+      v3stats = HANDLE_DATA(handle);
+      v3stats->numStats = count;
+      for (count = 0; count < v3stats->numStats; count++) {
+         GuestLibV3TypeIds statId = count + 1;
+
+         /* Unmarshal the statistic. */
+         if (!xdr_GuestLibV3Stat(&xdrs, &v3stats->stats[count])) {
+            break;
+         }
+
+         /* Host sends all the V3 statistics it supports, in order. */
+         if (v3stats->stats[count].d != statId) {
+            break;
+         }
+      }
+      if (count >= v3stats->numStats) {
+         ret = VMGUESTLIB_ERROR_SUCCESS;
+      } else {
+         /* 
+          * Error while unmarshalling. Deep-free already unmarshalled
+          * statistics and invalidate the data in the handle.
+          */
+         GuestLibV3StatCount c;
+
+         for (c = 0; c < count; c++) {
+            VMX_XDR_FREE(xdr_GuestLibV3Stat, &v3stats->stats[c]);
+         }
+         HANDLE_SESSIONID(handle) = 0;
+      }
+
+      /* 4. Free resources. */
+      xdr_destroy(&xdrs);
+   } else {
+      /*
+       * Host should never reply with a higher version protocol than requested.
+       */
+      ret = VMGUESTLIB_ERROR_OTHER;
    }
 
-   /* Copy stats to struct, free buffer. */
-   memcpy(data, newData, sizeof *data);
+done:
    free(reply);
-
-   /* Make sure resourcePoolPath is NUL terminated. */
-   data->resourcePoolPath.value[sizeof data->resourcePoolPath.value - 1] = '\0';
-
-   return VMGUESTLIB_ERROR_SUCCESS;
+   return ret;
 }
 
 
@@ -374,7 +599,7 @@ VMGuestLib_UpdateInfo(VMGuestLibHandle handle) // IN
     * need to do the test again here.
     */
 
-   error = VMGuestLibUpdateInfo((VMGuestLibDataV2 *)handle);
+   error = VMGuestLibUpdateInfo(handle);
    if (error != VMGUESTLIB_ERROR_SUCCESS) {
       Debug("VMGuestLibUpdateInfo failed: %d\n", error);
       return error;
@@ -404,7 +629,7 @@ VMGuestLibError
 VMGuestLib_GetSessionId(VMGuestLibHandle handle, // IN
                         VMSessionId *id)         // OUT
 {
-   VMGuestLibDataV2 *data;
+   void *data;
    VMGuestLibError error;
 
    error = VMGuestLibCheckArgs(handle, id, &data);
@@ -412,8 +637,47 @@ VMGuestLib_GetSessionId(VMGuestLibHandle handle, // IN
       return error;
    }
 
-   *id = data->sessionId;
+   *id = HANDLE_SESSIONID(handle);
+
+   return VMGUESTLIB_ERROR_SUCCESS;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMGuestLibGetStatisticsV3 --
+ *
+ *      Accessor helper to retrieve the requested V3 statistic.
+ *
+ * Results:
+ *      VMGuestLibError
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static VMGuestLibError
+VMGuestLibGetStatisticsV3(VMGuestLibHandle handle,   // IN
+                          GuestLibV3TypeIds statId,  // IN
+                          GuestLibV3Stat *outStat)   // OUT
+{
+   VMGuestLibStatisticsV3 *stats = HANDLE_DATA(handle);
+   uint32 statIdx = statId - 1;
+
+   /* 
+    * Check that the requested statistic is supported by the host. V3 host sends
+    * all the available statistics, in order. So any statistics that were added
+    * to this version of guestlib, but unsupported by the host, would not be
+    * sent by the host.
+    */
+   if (statIdx >= stats->numStats) {
+      return VMGUESTLIB_ERROR_UNSUPPORTED_VERSION;
+   }
 
+   memcpy(outStat, &stats->stats[statIdx], sizeof *outStat);
    return VMGUESTLIB_ERROR_SUCCESS;
 }
 
@@ -438,21 +702,11 @@ VMGuestLibError
 VMGuestLib_GetCpuReservationMHz(VMGuestLibHandle handle,   // IN
                                 uint32 *cpuReservationMHz) // OUT
 {
-   VMGuestLibDataV2 *data;
-   VMGuestLibError error;
-
-   error = VMGuestLibCheckArgs(handle, cpuReservationMHz, &data);
-   if (VMGUESTLIB_ERROR_SUCCESS != error) {
-      return error;
-   }
-
-   if (!data->cpuReservationMHz.valid) {
-      return VMGUESTLIB_ERROR_NOT_AVAILABLE;
-   }
-
-   *cpuReservationMHz = data->cpuReservationMHz.value;
-
-   return VMGUESTLIB_ERROR_SUCCESS;
+   VMGuestLibError error = VMGUESTLIB_ERROR_OTHER;
+   VMGUESTLIB_GETFN_BODY(handle, error,
+                         cpuReservationMHz, cpuReservationMHz,
+                         GUESTLIB_CPU_RESERVATION_MHZ);
+   return error;
 }
 
 
@@ -476,21 +730,11 @@ VMGuestLibError
 VMGuestLib_GetCpuLimitMHz(VMGuestLibHandle handle, // IN
                           uint32 *cpuLimitMHz)     // OUT
 {
-   VMGuestLibDataV2 *data;
-   VMGuestLibError error;
-
-   error = VMGuestLibCheckArgs(handle, cpuLimitMHz, &data);
-   if (VMGUESTLIB_ERROR_SUCCESS != error) {
-      return error;
-   }
-
-   if (!data->cpuLimitMHz.valid) {
-      return VMGUESTLIB_ERROR_NOT_AVAILABLE;
-   }
-
-   *cpuLimitMHz = data->cpuLimitMHz.value;
-
-   return VMGUESTLIB_ERROR_SUCCESS;
+   VMGuestLibError error = VMGUESTLIB_ERROR_OTHER;
+   VMGUESTLIB_GETFN_BODY(handle, error,
+                         cpuLimitMHz, cpuLimitMHz,
+                         GUESTLIB_CPU_LIMIT_MHZ);
+   return error;
 }
 
 
@@ -514,21 +758,11 @@ VMGuestLibError
 VMGuestLib_GetCpuShares(VMGuestLibHandle handle, // IN
                         uint32 *cpuShares)       // OUT
 {
-   VMGuestLibDataV2 *data;
-   VMGuestLibError error;
-
-   error = VMGuestLibCheckArgs(handle, cpuShares, &data);
-   if (VMGUESTLIB_ERROR_SUCCESS != error) {
-      return error;
-   }
-
-   if (!data->cpuShares.valid) {
-      return VMGUESTLIB_ERROR_NOT_AVAILABLE;
-   }
-
-   *cpuShares = data->cpuShares.value;
-
-   return VMGUESTLIB_ERROR_SUCCESS;
+   VMGuestLibError error = VMGUESTLIB_ERROR_OTHER;
+   VMGUESTLIB_GETFN_BODY(handle, error,
+                         cpuShares, cpuShares,
+                         GUESTLIB_CPU_SHARES);
+   return error;
 }
 
 
@@ -552,21 +786,11 @@ VMGuestLibError
 VMGuestLib_GetCpuUsedMs(VMGuestLibHandle handle, // IN
                         uint64 *cpuUsedMs)       // OUT
 {
-   VMGuestLibDataV2 *data;
-   VMGuestLibError error;
-
-   error = VMGuestLibCheckArgs(handle, cpuUsedMs, &data);
-   if (VMGUESTLIB_ERROR_SUCCESS != error) {
-      return error;
-   }
-
-   if (!data->cpuUsedMs.valid) {
-      return VMGUESTLIB_ERROR_NOT_AVAILABLE;
-   }
-
-   *cpuUsedMs = data->cpuUsedMs.value;
-
-   return VMGUESTLIB_ERROR_SUCCESS;
+   VMGuestLibError error = VMGUESTLIB_ERROR_OTHER;
+   VMGUESTLIB_GETFN_BODY(handle, error,
+                         cpuUsedMs, cpuUsedMs,
+                         GUESTLIB_CPU_USED_MS);
+   return error;
 }
 
 
@@ -592,21 +816,11 @@ VMGuestLibError
 VMGuestLib_GetHostProcessorSpeed(VMGuestLibHandle handle, // IN
                                  uint32 *mhz)             // OUT
 {
-   VMGuestLibDataV2 *data;
-   VMGuestLibError error;
-
-   error = VMGuestLibCheckArgs(handle, mhz, &data);
-   if (VMGUESTLIB_ERROR_SUCCESS != error) {
-      return error;
-   }
-
-   if (!data->hostMHz.valid) {
-      return VMGUESTLIB_ERROR_NOT_AVAILABLE;
-   }
-
-   *mhz = data->hostMHz.value;
-
-   return VMGUESTLIB_ERROR_SUCCESS;
+   VMGuestLibError error = VMGUESTLIB_ERROR_OTHER;
+   VMGUESTLIB_GETFN_BODY(handle, error,
+                                mhz, hostMHz,
+                                GUESTLIB_HOST_MHZ);
+   return error;
 }
 
 
@@ -630,21 +844,11 @@ VMGuestLibError
 VMGuestLib_GetMemReservationMB(VMGuestLibHandle handle,  // IN
                                uint32 *memReservationMB) // OUT
 {
-   VMGuestLibDataV2 *data;
-   VMGuestLibError error;
-
-   error = VMGuestLibCheckArgs(handle, memReservationMB, &data);
-   if (VMGUESTLIB_ERROR_SUCCESS != error) {
-      return error;
-   }
-
-   if (!data->memReservationMB.valid) {
-      return VMGUESTLIB_ERROR_NOT_AVAILABLE;
-   }
-
-   *memReservationMB = data->memReservationMB.value;
-
-   return VMGUESTLIB_ERROR_SUCCESS;
+   VMGuestLibError error = VMGUESTLIB_ERROR_OTHER;
+   VMGUESTLIB_GETFN_BODY(handle, error,
+                                memReservationMB, memReservationMB,
+                                GUESTLIB_MEM_RESERVATION_MB);
+   return error;
 }
 
 
@@ -668,21 +872,11 @@ VMGuestLibError
 VMGuestLib_GetMemLimitMB(VMGuestLibHandle handle, // IN
                          uint32 *memLimitMB)      // OUT
 {
-   VMGuestLibDataV2 *data;
-   VMGuestLibError error;
-
-   error = VMGuestLibCheckArgs(handle, memLimitMB, &data);
-   if (VMGUESTLIB_ERROR_SUCCESS != error) {
-      return error;
-   }
-
-   if (!data->memLimitMB.valid) {
-      return VMGUESTLIB_ERROR_NOT_AVAILABLE;
-   }
-
-   *memLimitMB = data->memLimitMB.value;
-
-   return VMGUESTLIB_ERROR_SUCCESS;
+   VMGuestLibError error = VMGUESTLIB_ERROR_OTHER;
+   VMGUESTLIB_GETFN_BODY(handle, error,
+                                memLimitMB, memLimitMB,
+                                GUESTLIB_MEM_LIMIT_MB);
+   return error;
 }
 
 
@@ -706,21 +900,11 @@ VMGuestLibError
 VMGuestLib_GetMemShares(VMGuestLibHandle handle, // IN
                         uint32 *memShares)       // OUT
 {
-   VMGuestLibDataV2 *data;
-   VMGuestLibError error;
-
-   error = VMGuestLibCheckArgs(handle, memShares, &data);
-   if (VMGUESTLIB_ERROR_SUCCESS != error) {
-      return error;
-   }
-
-   if (!data->memShares.valid) {
-      return VMGUESTLIB_ERROR_NOT_AVAILABLE;
-   }
-
-   *memShares = data->memShares.value;
-
-   return VMGUESTLIB_ERROR_SUCCESS;
+   VMGuestLibError error = VMGUESTLIB_ERROR_OTHER;
+   VMGUESTLIB_GETFN_BODY(handle, error,
+                                memShares, memShares,
+                                GUESTLIB_MEM_SHARES);
+   return error;
 }
 
 
@@ -744,21 +928,11 @@ VMGuestLibError
 VMGuestLib_GetMemMappedMB(VMGuestLibHandle handle,  // IN
                           uint32 *memMappedMB)      // OUT
 {
-   VMGuestLibDataV2 *data;
-   VMGuestLibError error;
-
-   error = VMGuestLibCheckArgs(handle, memMappedMB, &data);
-   if (VMGUESTLIB_ERROR_SUCCESS != error) {
-      return error;
-   }
-
-   if (!data->memMappedMB.valid) {
-      return VMGUESTLIB_ERROR_NOT_AVAILABLE;
-   }
-
-   *memMappedMB = data->memMappedMB.value;
-
-   return VMGUESTLIB_ERROR_SUCCESS;
+   VMGuestLibError error = VMGUESTLIB_ERROR_OTHER;
+   VMGUESTLIB_GETFN_BODY(handle, error,
+                                memMappedMB, memMappedMB,
+                                GUESTLIB_MEM_MAPPED_MB);
+   return error;
 }
 
 
@@ -782,21 +956,11 @@ VMGuestLibError
 VMGuestLib_GetMemActiveMB(VMGuestLibHandle handle, // IN
                           uint32 *memActiveMB)     // OUT
 {
-   VMGuestLibDataV2 *data;
-   VMGuestLibError error;
-
-   error = VMGuestLibCheckArgs(handle, memActiveMB, &data);
-   if (VMGUESTLIB_ERROR_SUCCESS != error) {
-      return error;
-   }
-
-   if (!data->memActiveMB.valid) {
-      return VMGUESTLIB_ERROR_NOT_AVAILABLE;
-   }
-
-   *memActiveMB = data->memActiveMB.value;
-
-   return VMGUESTLIB_ERROR_SUCCESS;
+   VMGuestLibError error = VMGUESTLIB_ERROR_OTHER;
+   VMGUESTLIB_GETFN_BODY(handle, error,
+                                memActiveMB, memActiveMB,
+                                GUESTLIB_MEM_ACTIVE_MB);
+   return error;
 }
 
 
@@ -820,21 +984,11 @@ VMGuestLibError
 VMGuestLib_GetMemOverheadMB(VMGuestLibHandle handle, // IN
                             uint32 *memOverheadMB)   // OUT
 {
-   VMGuestLibDataV2 *data;
-   VMGuestLibError error;
-
-   error = VMGuestLibCheckArgs(handle, memOverheadMB, &data);
-   if (VMGUESTLIB_ERROR_SUCCESS != error) {
-      return error;
-   }
-
-   if (!data->memOverheadMB.valid) {
-      return VMGUESTLIB_ERROR_NOT_AVAILABLE;
-   }
-
-   *memOverheadMB = data->memOverheadMB.value;
-
-   return VMGUESTLIB_ERROR_SUCCESS;
+   VMGuestLibError error = VMGUESTLIB_ERROR_OTHER;
+   VMGUESTLIB_GETFN_BODY(handle, error,
+                                memOverheadMB, memOverheadMB,
+                                GUESTLIB_MEM_OVERHEAD_MB);
+   return error;
 }
 
 
@@ -858,21 +1012,11 @@ VMGuestLibError
 VMGuestLib_GetMemBalloonedMB(VMGuestLibHandle handle, // IN
                              uint32 *memBalloonedMB)  // OUT
 {
-   VMGuestLibDataV2 *data;
-   VMGuestLibError error;
-
-   error = VMGuestLibCheckArgs(handle, memBalloonedMB, &data);
-   if (VMGUESTLIB_ERROR_SUCCESS != error) {
-      return error;
-   }
-
-   if (!data->memBalloonedMB.valid) {
-      return VMGUESTLIB_ERROR_NOT_AVAILABLE;
-   }
-
-   *memBalloonedMB = data->memBalloonedMB.value;
-
-   return VMGUESTLIB_ERROR_SUCCESS;
+   VMGuestLibError error = VMGUESTLIB_ERROR_OTHER;
+   VMGUESTLIB_GETFN_BODY(handle, error,
+                                memBalloonedMB, memBalloonedMB,
+                                GUESTLIB_MEM_BALLOONED_MB);
+   return error;
 }
 
 
@@ -896,21 +1040,11 @@ VMGuestLibError
 VMGuestLib_GetMemSwappedMB(VMGuestLibHandle handle, // IN
                            uint32 *memSwappedMB)    // OUT
 {
-   VMGuestLibDataV2 *data;
-   VMGuestLibError error;
-
-   error = VMGuestLibCheckArgs(handle, memSwappedMB, &data);
-   if (VMGUESTLIB_ERROR_SUCCESS != error) {
-      return error;
-   }
-
-   if (!data->memSwappedMB.valid) {
-      return VMGUESTLIB_ERROR_NOT_AVAILABLE;
-   }
-
-   *memSwappedMB = data->memSwappedMB.value;
-
-   return VMGUESTLIB_ERROR_SUCCESS;
+   VMGuestLibError error = VMGUESTLIB_ERROR_OTHER;
+   VMGUESTLIB_GETFN_BODY(handle, error,
+                                memSwappedMB, memSwappedMB,
+                                GUESTLIB_MEM_SWAPPED_MB);
+   return error;
 }
 
 
@@ -934,21 +1068,11 @@ VMGuestLibError
 VMGuestLib_GetMemSharedMB(VMGuestLibHandle handle, // IN
                           uint32 *memSharedMB)     // OUT
 {
-   VMGuestLibDataV2 *data;
-   VMGuestLibError error;
-
-   error = VMGuestLibCheckArgs(handle, memSharedMB, &data);
-   if (VMGUESTLIB_ERROR_SUCCESS != error) {
-      return error;
-   }
-
-   if (!data->memSharedMB.valid) {
-      return VMGUESTLIB_ERROR_NOT_AVAILABLE;
-   }
-
-   *memSharedMB = data->memSharedMB.value;
-
-   return VMGUESTLIB_ERROR_SUCCESS;
+   VMGuestLibError error = VMGUESTLIB_ERROR_OTHER;
+   VMGUESTLIB_GETFN_BODY(handle, error,
+                                memSharedMB, memSharedMB,
+                                GUESTLIB_MEM_SHARED_MB);
+   return error;
 }
 
 
@@ -972,21 +1096,11 @@ VMGuestLibError
 VMGuestLib_GetMemSharedSavedMB(VMGuestLibHandle handle,  // IN
                                uint32 *memSharedSavedMB) // OUT
 {
-   VMGuestLibDataV2 *data;
-   VMGuestLibError error;
-
-   error = VMGuestLibCheckArgs(handle, memSharedSavedMB, &data);
-   if (VMGUESTLIB_ERROR_SUCCESS != error) {
-      return error;
-   }
-
-   if (!data->memSharedSavedMB.valid) {
-      return VMGUESTLIB_ERROR_NOT_AVAILABLE;
-   }
-
-   *memSharedSavedMB = data->memSharedSavedMB.value;
-
-   return VMGUESTLIB_ERROR_SUCCESS;
+   VMGuestLibError error = VMGUESTLIB_ERROR_OTHER;
+   VMGUESTLIB_GETFN_BODY(handle, error,
+                                memSharedSavedMB, memSharedSavedMB,
+                                GUESTLIB_MEM_SHARED_SAVED_MB);
+   return error;
 }
 
 
@@ -1010,21 +1124,11 @@ VMGuestLibError
 VMGuestLib_GetMemUsedMB(VMGuestLibHandle handle, // IN
                         uint32 *memUsedMB)       // OUT
 {
-   VMGuestLibDataV2 *data;
-   VMGuestLibError error;
-
-   error = VMGuestLibCheckArgs(handle, memUsedMB, &data);
-   if (VMGUESTLIB_ERROR_SUCCESS != error) {
-      return error;
-   }
-
-   if (!data->memUsedMB.valid) {
-      return VMGUESTLIB_ERROR_NOT_AVAILABLE;
-   }
-
-   *memUsedMB = data->memUsedMB.value;
-
-   return VMGUESTLIB_ERROR_SUCCESS;
+   VMGuestLibError error = VMGUESTLIB_ERROR_OTHER;
+   VMGUESTLIB_GETFN_BODY(handle, error,
+                                memUsedMB, memUsedMB,
+                                GUESTLIB_MEM_USED_MB);
+   return error;
 }
 
 
@@ -1048,21 +1152,11 @@ VMGuestLibError
 VMGuestLib_GetElapsedMs(VMGuestLibHandle handle, // IN
                         uint64 *elapsedMs)       // OUT
 {
-   VMGuestLibDataV2 *data;
-   VMGuestLibError error;
-
-   error = VMGuestLibCheckArgs(handle, elapsedMs, &data);
-   if (VMGUESTLIB_ERROR_SUCCESS != error) {
-      return error;
-   }
-
-   if (!data->elapsedMs.valid) {
-      return VMGUESTLIB_ERROR_NOT_AVAILABLE;
-   }
-
-   *elapsedMs = data->elapsedMs.value;
-
-   return VMGUESTLIB_ERROR_SUCCESS;
+   VMGuestLibError error = VMGUESTLIB_ERROR_OTHER;
+   VMGUESTLIB_GETFN_BODY(handle, error,
+                                elapsedMs, elapsedMs,
+                                GUESTLIB_ELAPSED_MS);
+   return error;
 }
 
 
@@ -1094,38 +1188,67 @@ VMGuestLib_GetResourcePoolPath(VMGuestLibHandle handle, // IN
                                size_t *bufferSize,      // IN/OUT
                                char *pathBuffer)        // OUT
 {
-   size_t size;
-   VMGuestLibDataV2 *data;
-
-   if (NULL == handle) {
-      return VMGUESTLIB_ERROR_INVALID_HANDLE;
-   }
-
-   if (NULL == bufferSize || NULL == pathBuffer) {
-      return VMGUESTLIB_ERROR_INVALID_ARG;
-   }
-
-   data = (VMGuestLibDataV2 *)handle;
-
-   if (0 == data->sessionId) {
-      return VMGUESTLIB_ERROR_NO_INFO;
-   }
-
-   if (!data->resourcePoolPath.valid) {
-      return VMGUESTLIB_ERROR_NOT_AVAILABLE;
-   }
-
-   /*
-    * Check buffer size. It's safe to use strlen because we squash the
-    * final byte of resourcePoolPath in VMGuestLibUpdateInfo.
-    */
-   size = strlen(data->resourcePoolPath.value) + 1;
-   if (*bufferSize < size) {
-      *bufferSize = size;
-      return VMGUESTLIB_ERROR_BUFFER_TOO_SMALL;
-   }
-
-   memcpy(pathBuffer, data->resourcePoolPath.value, *bufferSize);
-
-   return VMGUESTLIB_ERROR_SUCCESS;
+   VMGuestLibError error = VMGUESTLIB_ERROR_OTHER;
+
+   do {
+      size_t size;
+      if (NULL == handle) {
+         error = VMGUESTLIB_ERROR_INVALID_HANDLE;
+         break;
+      }
+
+      if (NULL == bufferSize || NULL == pathBuffer) {
+         error = VMGUESTLIB_ERROR_INVALID_ARG;
+         break;
+      }
+
+      if (0 == HANDLE_SESSIONID(handle)) {
+         error = VMGUESTLIB_ERROR_NO_INFO;
+         break;
+      }
+
+      if (HANDLE_VERSION(handle) == 2) {
+         VMGuestLibDataV2 *dataV2;
+
+         dataV2 = (VMGuestLibDataV2 *)HANDLE_DATA(handle);
+
+         if (!dataV2->resourcePoolPath.valid) {
+            error = VMGUESTLIB_ERROR_NOT_AVAILABLE;
+            break;
+         }
+
+         /*
+          * Check buffer size. It's safe to use strlen because we squash the
+          * final byte of resourcePoolPath in VMGuestLibUpdateInfo.
+          */
+         size = strlen(dataV2->resourcePoolPath.value) + 1;
+         if (*bufferSize < size) {
+            *bufferSize = size;
+            error = VMGUESTLIB_ERROR_BUFFER_TOO_SMALL;
+            break;
+         }
+
+         memcpy(pathBuffer, dataV2->resourcePoolPath.value, size);
+         error = VMGUESTLIB_ERROR_SUCCESS;
+      } else if (HANDLE_VERSION(handle) == 3) {
+         VMGuestLibStatisticsV3 *stats = HANDLE_DATA(handle);
+         GuestLibV3Stat *stat = &stats->stats[GUESTLIB_RESOURCE_POOL_PATH - 1];
+
+         if (!stat->GuestLibV3Stat_u.resourcePoolPath.valid) {
+            error = VMGUESTLIB_ERROR_NOT_AVAILABLE;
+            break;
+         }
+
+         size = strlen(stat->GuestLibV3Stat_u.resourcePoolPath.value) + 1;
+         if (*bufferSize < size) {
+            *bufferSize = size;
+            error = VMGUESTLIB_ERROR_BUFFER_TOO_SMALL;
+            break;
+         }
+         memcpy(pathBuffer, stat->GuestLibV3Stat_u.resourcePoolPath.value, size);
+         error = VMGUESTLIB_ERROR_SUCCESS;
+      }
+   } while (0);
+
+   return error;
 }
index f836ece1733c8148bd0eeece2f83b052647ddce1..d5dcd789b2448602c3e329a2c3c95ccb4e1e1fb6 100644 (file)
@@ -38,7 +38,7 @@
  * Current version of the VMGuestLibData structure
  */
 
-#define   VMGUESTLIB_DATA_VERSION 2
+#define   VMGUESTLIB_DATA_VERSION 3
 
 
 /* Stat types with a valid bit per stat. */
@@ -115,6 +115,14 @@ VMGuestLibDataV1;
 
 #endif // #if 0
 
+typedef
+#include "vmware_pack_begin.h"
+struct {
+   uint32 version;
+   VMSessionId sessionId;
+}
+#include "vmware_pack_end.h"
+VMGuestLibHeader;
 
 /*
  * This is version 2 of the data structure GuestLib uses to obtain
@@ -125,8 +133,8 @@ VMGuestLibDataV1;
 typedef
 #include "vmware_pack_begin.h"
 struct VMGuestLibDataV2 {
-   uint32 version;
-   VMSessionId sessionId;
+   /* Header */
+   VMGuestLibHeader hdr;
 
    /* Statistics */
 
@@ -169,4 +177,36 @@ struct VMGuestLibDataV2 {
 VMGuestLibDataV2;
 
 
+/*
+ * This is version 3 of the data structure GuestLib uses to obtain stats over
+ * the backdoor from the VMX/VMKernel. It is not exposed to users of the
+ * GuestLib API. This struct is sent on the wire.
+ *
+ * The buffer contains a variable length array of statistics, that are
+ * marshalled from XDR spec generated code. Each data field has a discriminant
+ * preceding the payload, which enables the client to detect fields that it
+ * doesn't recognize.
+ *
+ * V3 is a superset of V2 and a major protocol change. Any extensions to the
+ * wire protocol that just add statistics, can do so within V3. Just update the
+ * .x file to add a new discriminant for the union, at the end of the list. V3
+ * clients may assume that the fields are ordered on the wire in increasing order 
+ * of the discriminant list. So, a client may stop processing at the first 
+ * unrecognized field. V3 payload contains all available guestlib statistics
+ * supported by the host.
+ */
+
+typedef
+#include "vmware_pack_begin.h"
+struct VMGuestLibDataV3 {
+   /* Header */
+   VMGuestLibHeader hdr;
+
+   /* Statistics */
+   uint32 dataSize;
+   char data[0];
+}
+#include "vmware_pack_end.h"
+VMGuestLibDataV3;
+
 #endif /* _VM_GUEST_LIB_INT_H_ */
index 83b4b33d7547fdf5bee110e12b941df5a181dc21..b4bbcb25d6ad7abce88b0f6fe1bc0b198c4d19db 100644 (file)
@@ -47,6 +47,7 @@
 #  define  DEFAULT_HANDLER    VMToolsLogFile
 #endif
 
+#define LOGGING_GROUP         "logging"
 #define MAX_DOMAIN_LEN        64
 
 /*
                                  (gLogEnabled && ((data)->mask & (level))))
 
 
+static void
+VMToolsLogFile(const gchar *domain,
+               GLogLevelFlags level,
+               const gchar *message,
+               gpointer _data);
+
+#if defined(G_PLATFORM_WIN32)
+static void
+VMToolsLogOutputDebugString(const gchar *domain,
+                            GLogLevelFlags level,
+                            const gchar *message,
+                            gpointer _data);
+#endif
+
+
 typedef struct LogHandlerData {
    GLogLevelFlags    mask;
    FILE             *file;
@@ -85,6 +101,7 @@ static gboolean gEnableCoreDump = TRUE;
 static gboolean gLogEnabled = FALSE;
 static guint gPanicCount = 0;
 static LogHandlerData *gDefaultData = NULL;
+static GLogFunc gDefaultLogFunc = DEFAULT_HANDLER;
 
 /* Internal functions. */
 
@@ -309,6 +326,147 @@ VMTools_InitLogging(void)
 }
 
 
+/**
+ * Configures the given log domain based on the data provided in the given
+ * dictionary. If the log domain being configured doesn't match the default
+ * (@see VMTools_GetDefaultLogDomain()), and no specific handler is defined
+ * for the domain, the handler is inherited from the default domain, instead
+ * of using the default handler. This allows reusing the same log file, for
+ * example, while maintaining the ability to enable different log levels
+ * for different domains.
+ *
+ * For the above to properly work, the default log domain has to be configured
+ * before any other domains.
+ *
+ * @param[in]  domain      Name of domain being configured.
+ * @param[in]  cfg         Dictionary with config data.
+ */
+
+static void
+VMToolsConfigLogDomain(const gchar *domain,
+                       GKeyFile *cfg)
+{
+   gchar *handler = NULL;
+   gchar *level = NULL;
+   gchar *logpath = NULL;
+   gchar key[128];
+
+   GLogFunc handlerFn = NULL;
+   GLogLevelFlags levelsMask;
+   LogHandlerData *data;
+   FILE *logfile = NULL;
+
+   /* Arbitrary limit. */
+   if (strlen(domain) > MAX_DOMAIN_LEN) {
+      g_warning("Domain name too long: %s\n", domain);
+      goto exit;
+   } else if (strlen(domain) == 0) {
+      g_warning("Invalid domain declaration, missing name.\n");
+      goto exit;
+   }
+
+   Str_Sprintf(key, sizeof key, "%s.level", domain);
+   level = g_key_file_get_string(cfg, LOGGING_GROUP, key, NULL);
+   if (level == NULL) {
+#ifdef VMX86_DEBUG
+      level = g_strdup("message");
+#else
+      level = g_strdup("warning");
+#endif
+   }
+
+   /* Parse the handler information. */
+   Str_Sprintf(key, sizeof key, "%s.handler", domain);
+   handler = g_key_file_get_string(cfg, LOGGING_GROUP, key, NULL);
+
+   if (handler == NULL) {
+      if (strcmp(domain, VMTools_GetDefaultLogDomain()) == 0) {
+         handlerFn = DEFAULT_HANDLER;
+      } else {
+         handlerFn = gDefaultLogFunc;
+      }
+   } else if (strcmp(handler, "std") == 0) {
+      handlerFn = VMToolsLogFile;
+   } else if (strcmp(handler, "file") == 0) {
+      /* Don't set up the file sink if logging is disabled. */
+      if (strcmp(level, "none") != 0) {
+         handlerFn = VMToolsLogFile;
+         Str_Sprintf(key, sizeof key, "%s.data", domain);
+         logpath = g_key_file_get_string(cfg, LOGGING_GROUP, key, NULL);
+         if (logpath == NULL) {
+            g_warning("Missing log path for file handler (%s).\n", domain);
+            goto exit;
+         }
+      }
+#if defined(G_PLATFORM_WIN32)
+   } else if (strcmp(handler, "outputdebugstring") == 0) {
+      handlerFn = VMToolsLogOutputDebugString;
+#endif
+   } else {
+      g_warning("Unknown log handler: %s\n", handler);
+      goto exit;
+   }
+
+   /* Parse the log level configuration, and build the mask. */
+   if (strcmp(level, "error") == 0) {
+      levelsMask = G_LOG_LEVEL_ERROR;
+   } else if (strcmp(level, "critical") == 0) {
+      levelsMask = G_LOG_LEVEL_ERROR |
+                   G_LOG_LEVEL_CRITICAL;
+   } else if (strcmp(level, "warning") == 0) {
+      levelsMask = G_LOG_LEVEL_ERROR |
+                   G_LOG_LEVEL_CRITICAL |
+                   G_LOG_LEVEL_WARNING;
+   } else if (strcmp(level, "message") == 0) {
+      levelsMask = G_LOG_LEVEL_ERROR |
+                   G_LOG_LEVEL_CRITICAL |
+                   G_LOG_LEVEL_WARNING |
+                   G_LOG_LEVEL_MESSAGE;
+   } else if (strcmp(level, "info") == 0) {
+      levelsMask = G_LOG_LEVEL_ERROR |
+                   G_LOG_LEVEL_CRITICAL |
+                   G_LOG_LEVEL_WARNING |
+                   G_LOG_LEVEL_MESSAGE |
+                   G_LOG_LEVEL_INFO;
+   } else if (strcmp(level, "debug") == 0) {
+      levelsMask = ALL_LOG_LEVELS;
+   } else if (strcmp(level, "none") == 0) {
+      levelsMask = 0;
+   } else {
+      g_warning("Unknown log level (%s): %s\n", domain, level);
+      goto exit;
+   }
+
+   /* Initialize the log file, if using the "file" handler. */
+   if (logpath != NULL) {
+      logfile = VMToolsLogOpenFile(logpath);
+      if (logfile == NULL) {
+         g_warning("Couldn't open log file (%s): %s\n", domain, logpath);
+         goto exit;
+      }
+   }
+
+   data = g_malloc0(sizeof *data);
+   data->mask = levelsMask;
+   data->file = logfile;
+
+   if (strcmp(domain, VMTools_GetDefaultLogDomain()) == 0) {
+      g_free(gDefaultData);
+      gDefaultData = data;
+      gDefaultLogFunc = handlerFn;
+      g_log_set_default_handler(handlerFn, data);
+   } else if (handler == NULL) {
+      data->file = gDefaultData->file;
+   }
+
+   g_log_set_handler(domain, ALL_LOG_LEVELS, handlerFn, data);
+
+exit:
+   g_free(handler);
+   g_free(logpath);
+   g_free(level);
+}
+
 
 /* Public API. */
 
@@ -353,137 +511,46 @@ VMTools_SetDefaultLogDomain(const gchar *domain)
 void
 VMTools_ConfigLogging(GKeyFile *cfg)
 {
-   const gchar *group = "logging";
    gchar **list;
    gchar **curr;
 
-   if (!g_key_file_has_group(cfg, group)) {
+   if (!g_key_file_has_group(cfg, LOGGING_GROUP)) {
       return;
    }
 
-   list = g_key_file_get_keys(cfg, group, NULL, NULL);
+   /*
+    * Configure the default domain first. See function documentation for
+    * VMToolsConfigLogDomain() for the reason.
+    */
+   VMToolsConfigLogDomain(VMTools_GetDefaultLogDomain(), cfg);
+
+   list = g_key_file_get_keys(cfg, LOGGING_GROUP, NULL, NULL);
 
    for (curr = list; curr != NULL && *curr != NULL; curr++) {
       gchar *domain = *curr;
-      gchar *handler;
-      gchar *level = NULL;
-      gchar *logpath = NULL;
-      gchar key[128];
-      guint handlerId;
-
-      GLogFunc handlerFn = NULL;
-      GLogLevelFlags levelsMask;
-      LogHandlerData *data;
-      FILE *logfile = NULL;
 
       /* Check whether it's a domain "declaration". */
       if (!g_str_has_suffix(domain, ".level")) {
          continue;
       }
 
-      level = g_key_file_get_string(cfg, group, domain, NULL);
-
       /* Trims ".level" from the key to get the domain name. */
       domain[strlen(domain) - 6] = '\0';
 
-      /* Arbitrary limit. */
-      if (strlen(domain) > MAX_DOMAIN_LEN) {
-         g_warning("Domain name too long: %s\n", domain);
-         continue;
-      } else if (strlen(domain) == 0) {
-         g_warning("Invalid domain declaration, missing name.\n");
-         continue;
-      }
-
-      /* Parse the handler information. */
-      Str_Sprintf(key, sizeof key, "%s.handler", domain);
-      handler = g_key_file_get_string(cfg, group, key, NULL);
-
-      if (handler == NULL) {
-         handlerFn = DEFAULT_HANDLER;
-      } else if (strcmp(handler, "std") == 0) {
-         handlerFn = VMToolsLogFile;
-      } else if (strcmp(handler, "file") == 0) {
-         /* Don't set up the file sink if logging is disabled. */
-         if (strcmp(level, "none") != 0) {
-            handlerFn = VMToolsLogFile;
-            Str_Sprintf(key, sizeof key, "%s.data", domain);
-            logpath = g_key_file_get_string(cfg, group, key, NULL);
-            if (logpath == NULL) {
-               g_warning("Missing log path for file handler (%s).\n", domain);
-               goto next;
-            }
-         }
-#if defined(G_PLATFORM_WIN32)
-      } else if (strcmp(handler, "outputdebugstring") == 0) {
-         handlerFn = VMToolsLogOutputDebugString;
-#endif
-      } else {
-         g_warning("Unknown log handler: %s\n", handler);
-         goto next;
-      }
-
-      /* Parse the log level configuration, and build the mask. */
-      if (strcmp(level, "error") == 0) {
-         levelsMask = G_LOG_LEVEL_ERROR;
-      } else if (strcmp(level, "critical") == 0) {
-         levelsMask = G_LOG_LEVEL_ERROR |
-                      G_LOG_LEVEL_CRITICAL;
-      } else if (strcmp(level, "warning") == 0) {
-         levelsMask = G_LOG_LEVEL_ERROR |
-                      G_LOG_LEVEL_CRITICAL |
-                      G_LOG_LEVEL_WARNING;
-      } else if (strcmp(level, "message") == 0) {
-         levelsMask = G_LOG_LEVEL_ERROR |
-                      G_LOG_LEVEL_CRITICAL |
-                      G_LOG_LEVEL_WARNING |
-                      G_LOG_LEVEL_MESSAGE;
-      } else if (strcmp(level, "info") == 0) {
-         levelsMask = G_LOG_LEVEL_ERROR |
-                      G_LOG_LEVEL_CRITICAL |
-                      G_LOG_LEVEL_WARNING |
-                      G_LOG_LEVEL_MESSAGE |
-                      G_LOG_LEVEL_INFO;
-      } else if (strcmp(level, "debug") == 0) {
-         levelsMask = ALL_LOG_LEVELS;
-      } else if (strcmp(level, "none") == 0) {
-         levelsMask = 0;
-      } else {
-         g_warning("Unknown log level (%s): %s\n", domain, level);
-         goto next;
-      }
-
-      /* Initialize the log file, if using the "file" handler. */
-      if (logpath != NULL) {
-         logfile = VMToolsLogOpenFile(logpath);
-         if (logfile == NULL) {
-            g_warning("Couldn't open log file (%s): %s\n", domain, logpath);
-            goto next;
-         }
-      }
-
-      data = g_malloc0(sizeof *data);
-      data->mask = levelsMask;
-      data->file = logfile;
-
+      /* Skip the default domain. */
       if (strcmp(domain, VMTools_GetDefaultLogDomain()) == 0) {
-         g_free(gDefaultData);
-         gDefaultData = NULL;
-         g_log_set_default_handler(handlerFn, data);
+         continue;
       }
-      handlerId = g_log_set_handler(domain, ALL_LOG_LEVELS, handlerFn, data);
 
-   next:
-      g_free(handler);
-      g_free(logpath);
-      g_free(level);
+      VMToolsConfigLogDomain(domain, cfg);
    }
 
    g_strfreev(list);
 
-   gLogEnabled = g_key_file_get_boolean(cfg, group, "log", NULL);
-   if (g_key_file_has_key(cfg, group, "enableCoreDump", NULL)) {
-      gEnableCoreDump = g_key_file_get_boolean(cfg, group, "enableCoreDump", NULL);
+   gLogEnabled = g_key_file_get_boolean(cfg, LOGGING_GROUP, "log", NULL);
+   if (g_key_file_has_key(cfg, LOGGING_GROUP, "enableCoreDump", NULL)) {
+      gEnableCoreDump = g_key_file_get_boolean(cfg, LOGGING_GROUP,
+                                               "enableCoreDump", NULL);
    }
 }
 
old mode 100755 (executable)
new mode 100644 (file)
index b8b72a4..41e1658
@@ -6,7 +6,7 @@ modules: $(MODULES)
 modulesrc = $(top_srcdir)/modules
 
 $(MODULES):
-       $(MAKE) VM_UNAME=$(KERNEL_RELEASE) -C "$(modulesrc)/$(MODULES_OS)/$@"
+       $(MAKE) VM_UNAME=$(KERNEL_RELEASE) $(EXTRA_ARGS) -C "$(modulesrc)/$(MODULES_OS)/$@"
 
 if LINUX
 export pvscsidir := $(MODULES_DIR)/drivers/scsi
@@ -31,24 +31,46 @@ export vmsyncdir := $(MODULES_DIR)
 export vmxnetdir := $(MODULES_DIR)
 endif FREEBSD
 
+if SOLARIS
+export vmhgfsdir := $(MODULES_DIR)
+# Solaris does not have Kbuild-like system so we need to supply
+# compiler and linker and other items discovered by configure
+# script.
+EXTRA_ARGS =
+EXTRA_ARGS += "CC=$(CC)"
+EXTRA_ARGS += "CC_WARNINGS=$(CC_WARNINGS)"
+EXTRA_ARGS += "GLOBAL_DEFS=$(GLOBAL_DEFS)"
+EXTRA_ARGS += "LD=$(LD)"
+EXTRA_ARGS += "HAVE_GNU_LD=$(HAVE_GNU_LD)"
+endif
+
 ## Automake will supplement its own "clean" targets with this.
 clean-local:
-       for MOD in $(MODULES); do                                                                                                                       \
-          if [ -d "$(modulesrc)/$(MODULES_OS)/$$MOD" ]; then                                           \
-             $(MAKE) -C "$(modulesrc)/$(MODULES_OS)/$$MOD" clean || exit 1; \
-          fi                                                                                                                                                                           \
+       for MOD in $(MODULES); do                                              \
+          if [ -d "$(modulesrc)/$(MODULES_OS)/$$MOD" ]; then                  \
+             $(MAKE) VM_UNAME=$(KERNEL_RELEASE)                               \
+                    -C "$(modulesrc)/$(MODULES_OS)/$$MOD" clean || exit 1;    \
+          fi                                                                  \
        done
        $(RM) -f $(modulesrc)/$(MODULES_OS)/*.o $(modulesrc)/$(MODULES_OS)/*.ko
 
 install-exec-hook:
-       for MOD in $(MODULES); do                                                                                                       \
-          $(INSTALL) -d $(DESTDIR)`eval echo '$$'$${MOD}dir`;                  \
-          $(INSTALL) -m644 $(modulesrc)/$(MODULES_OS)/$$MOD/$$MOD.ko   \
-             $(DESTDIR)`eval echo '$$'$${MOD}dir`;                                                     \
+if SOLARIS
+       for MOD in $(MODULES); do                                              \
+          $(MAKE) VM_UNAME=$(KERNEL_RELEASE)                                  \
+             -C "$(modulesrc)/$(MODULES_OS)/$$MOD" install || exit 1;         \
+       done
+else
+       for MOD in $(MODULES); do                                              \
+          $(INSTALL) -d $(DESTDIR)`eval echo '$$'$${MOD}dir`;                 \
+          $(INSTALL) -m644 $(modulesrc)/$(MODULES_OS)/$$MOD/$$MOD.ko          \
+             $(DESTDIR)`eval echo '$$'$${MOD}dir`;                            \
        done
        eval "$$DEPMOD"
+endif
+
 uninstall-hook:
-       for MOD in $(MODULES); do \
-          $(RM) -f $(DESTDIR)`eval echo '$$'$${MOD}dir`/$$MOD.ko &> /dev/null; \
+       for MOD in $(MODULES); do                                              \
+          $(RM) -f $(DESTDIR)`eval echo '$$'$${MOD}dir`/$$MOD.ko &> /dev/null;\
        done
        eval "$$DEPMOD"
index 2fd620d0db3952e1a283217add65700b30fec77d..3fa1894d06ef0e96efbf5200d8a6b69ba838ac62 100644 (file)
     (!defined KERNEL && !defined _KERNEL && !defined VMKERNEL && !defined __KERNEL__)
 #   include <stddef.h>
 #else
-// XXX the __cplusplus one matches that of VC++, to prevent redefinition warning
+// XXX the _WIN32 one matches that of VC++, to prevent redefinition warning
 // XXX the other one matches that of gcc3.3.3/glibc2.2.4 to prevent redefinition warnings
 #ifndef offsetof
-#ifdef __cplusplus
+#ifdef _WIN32
 #define offsetof(s,m)   (size_t)&(((s *)0)->m)
 #else
 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
index 0bb6c0a98d576ab35864bc6bf6fc77a714836fbe..fddea6bf2b5d1cfe05c06b4abb63df6b3dc949e0 100644 (file)
@@ -30,6 +30,7 @@ HEADERS += os.h
 HEADERS += compat_freebsd.h
 HEADERS += compat_vop.h
 HEADERS += vfsopscommon.h
+HEADERS += transport.h
 
 COMMON_SRCS := cpName.c
 COMMON_SRCS += cpNameLinux.c
@@ -55,6 +56,7 @@ COMMON_HGFS_SRCS += fsutil.c
 COMMON_HGFS_SRCS += vnopscommon.c
 COMMON_HGFS_SRCS += state.c
 COMMON_HGFS_SRCS += vfsopscommon.c
+COMMON_HGFS_SRCS += transport.c
 
 MODULE_SRCS := vnops.c
 MODULE_SRCS += vfsops.c
index e803269cf7aaee5e3c321ece50ee2216118aa90d..64ae6727121061ba554ce75129c2087e4c071c0c 100644 (file)
@@ -19,7 +19,7 @@
 /*
  * state.c --
  *
- *     Vnode, HgfsOpenFile, and HgfsFile state manipulation routines.
+ *     Vnode and HgfsFile state manipulation routines.
  */
 
 #include <sys/param.h>
@@ -32,6 +32,9 @@
 #  include <sys/malloc.h>
 #  include "sha1.h"
 #  include "compat_freebsd.h"
+#define vnode_get(vnode) vget(vnode, LK_SHARED, curthread)
+#define vnode_rele(vnode) vrele(vnode)
+#define vnode_ref(vnode) vref(vnode)
 #elif defined(__APPLE__)
 #  include <string.h>
 /*
 #define HGFS_FILE_HT_BUCKET(ht, index)  (&ht->hashTable[index])
 
 #define HGFS_IS_ROOT_FILE(sip, file)    (HGFS_VP_TO_FP(sip->rootVnode) == file)
+#define LCK_MTX_ASSERT(mutex)
 
 #if defined(__APPLE__)
 #  define SHA1_HASH_LEN SHA_DIGEST_LENGTH
+
+#if defined(VMX86_DEVEL)
+#undef LCK_MTX_ASSERT
+#define LCK_MTX_ASSERT(mutex) lck_mtx_assert(mutex, LCK_MTX_ASSERT_OWNED)
+#endif
+
 #endif
 
 /*
  */
 
 static int HgfsVnodeGetInt(struct vnode **vpp,
-                          struct HgfsSuperInfo *sip,
-                          struct mount *vfsp,
-                          const char *fileName,
-                          HgfsFileType fileType,
-                          HgfsFileHashTable *htp,
-                          Bool rootVnode);
+                           struct vnode *dvp,
+                           struct HgfsSuperInfo *sip,
+                           struct mount *vfsp,
+                           const char *fileName,
+                           HgfsFileType fileType,
+                           HgfsFileHashTable *htp,
+                           Bool rootVnode,
+                           Bool createFile,
+                           int permissions);
 
 /* Allocation/initialization/free of open file state */
-static HgfsOpenFile *HgfsAllocOpenFile(const char *fileName, HgfsFileType fileType,
-                                       HgfsFileHashTable *htp);
-static void HgfsFreeOpenFile(HgfsOpenFile *ofp, HgfsFileHashTable *htp);
+static HgfsFile *HgfsAllocFile(const char *fileName, HgfsFileType fileType,
+                               struct vnode *dvp, HgfsFileHashTable *htp,
+                               int permissions);
 
 /* Acquiring/releasing file state */
-static HgfsFile *HgfsGetFile(const char *fileName, HgfsFileType fileType,
-                            HgfsFileHashTable *htp);
+static HgfsFile *HgfsInsertFile(const char *fileName,
+                                HgfsFile *fp,
+                                HgfsFileHashTable *htp);
 static void HgfsReleaseFile(HgfsFile *fp, HgfsFileHashTable *htp);
-static int HgfsInitFile(HgfsFile *fp, const char *fileName, HgfsFileType fileType);
+static int HgfsInitFile(HgfsFile *fp, struct vnode *dvp, const char *fileName,
+                        HgfsFileType fileType, int permissions);
+static void HgfsFreeFile(HgfsFile *fp);
 
 /* Adding/finding/removing file state from hash table */
 static void HgfsAddFile(HgfsFile *fp, HgfsFileHashTable *htp);
@@ -91,6 +107,7 @@ static HgfsFile *HgfsFindFile(const char *fileName, HgfsFileHashTable *htp);
 static unsigned int HgfsFileNameHash(const char *fileName);
 static void HgfsNodeIdHash(const char *fileName, uint32_t fileNameLength,
                            ino_t *outHash);
+static Bool HgfsIsModeCompatible(HgfsMode requestedMode, HgfsMode existingMode);
 /*
  * Global functions
  */
@@ -102,7 +119,7 @@ static void HgfsNodeIdHash(const char *fileName, uint32_t fileNameLength,
  *
  *      Creates a vnode for the provided filename.
  *
- *      This will always allocate a vnode and HgfsOpenFile.  If a HgfsFile
+ *      This will always allocate a vnode and HgfsFile.  If a HgfsFile
  *      already exists for this filename then that is used, if a HgfsFile doesn't
  *      exist, one is created.
  *
@@ -111,21 +128,27 @@ static void HgfsNodeIdHash(const char *fileName, uint32_t fileNameLength,
  *      vnode is returned locked.
  *
  * Side effects:
- *      If the HgfsFile already exists, its reference count is incremented;
- *      otherwise a HgfsFile is created.
+ *      If the HgfsFile already exists and createFile is TRUE then the EEXIST error
+ *      is returned. Otherwise if the HgfsFile already exists its reference count
+ *      is incremented.
+ *      If HgfsFile with the given name does not exist then HgfsFile is created.
  *
  *----------------------------------------------------------------------------
  */
 
 int
 HgfsVnodeGet(struct vnode **vpp,        // OUT: Filled with address of created vnode
+             struct vnode *dvp,         // IN:  Parent directory vnode
              HgfsSuperInfo *sip,        // IN:  Superinfo
              struct mount *vfsp,        // IN:  Filesystem structure
              const char *fileName,      // IN:  Name of this file
              HgfsFileType fileType,     // IN:  Type of file
-             HgfsFileHashTable *htp)    // IN:  File hash table
+             HgfsFileHashTable *htp,    // IN:  File hash table
+             Bool createFile,           // IN:  Creating a new file or open existing?
+             int permissions)           // IN: Permissions for the created file
 {
-   return HgfsVnodeGetInt(vpp, sip, vfsp, fileName, fileType, htp, FALSE);
+   return HgfsVnodeGetInt(vpp, dvp, sip, vfsp, fileName, fileType, htp, FALSE,
+                          createFile, permissions);
 }
 
 
@@ -155,19 +178,18 @@ HgfsVnodeGetRoot(struct vnode **vpp,      // OUT: Filled with address of created
                 HgfsFileType fileType,   // IN:  Type of file
                 HgfsFileHashTable *htp)  // IN:  File hash table
 {
-   return HgfsVnodeGetInt(vpp, sip, vfsp, fileName, fileType, htp, TRUE);
+   return HgfsVnodeGetInt(vpp, NULL, sip, vfsp, fileName, fileType, htp, TRUE, FALSE, 0);
 }
 
 
 /*
  *----------------------------------------------------------------------------
  *
- * HgfsVnodePut --
+ * HgfsReleaseVnodeContext --
  *
- *      Releases the provided vnode.
+ *      Releases context for the provided vnode.
  *
- *      This will free the associated vnode.
- *      The HgfsFile's reference count is decremented and, if 0, freed.
+ *      This will free the context information associated vnode.
  *
  * Results:
  *      Returns 0 on success and a non-zero error code on failure.
@@ -179,10 +201,10 @@ HgfsVnodeGetRoot(struct vnode **vpp,      // OUT: Filled with address of created
  */
 
 int
-HgfsVnodePut(struct vnode *vp,          // IN: Vnode to release
-             HgfsFileHashTable *htp)    // IN: Hash table pointer
+HgfsReleaseVnodeContext(struct vnode *vp,          // IN: Vnode to release
+                        HgfsFileHashTable *htp)    // IN: Hash table pointer
 {
-   HgfsOpenFile *ofp;
+   HgfsFile *fp;
 
    ASSERT(vp);
    ASSERT(htp);
@@ -190,17 +212,11 @@ HgfsVnodePut(struct vnode *vp,          // IN: Vnode to release
    DEBUG(VM_DEBUG_ENTRY, "Entering HgfsVnodePut\n");
 
    /* Get our private open-file state. */
-   ofp = HGFS_VP_TO_OFP(vp);
-   if (!ofp) {
-      return HGFS_ERR;
-   }
+   fp = HGFS_VP_TO_FP(vp);
+   ASSERT(fp);
 
-   /*
-    * We need to free the open file structure.  This takes care of releasing
-    * our reference on the underlying file structure (and freeing it if
-    * necessary).
-    */
-   HgfsFreeOpenFile(ofp, htp);
+   /* We need to release private HGFS information asosiated with the vnode. */
+   HgfsReleaseFile(fp, htp);
 
    return 0;
 }
@@ -216,22 +232,6 @@ HgfsVnodePut(struct vnode *vp,          // IN: Vnode to release
  *      file.  (This situation exists on a readdir since dentries are filled in
  *      rather than creating vnodes.)
  *
- *      In Solaris, node ids are provided in vnodes and inode numbers are
- *      provided in dentries.  For applications to work correctly, we must make
- *      sure that the inode number of a file's dentry and the node id in a file's
- *      vnode match one another.  This poses a problem since vnodes typically do
- *      not exist when dentries need to be created, and once a dentry is created
- *      we have no reference to it since it is copied to the user and freed from
- *      kernel space.  An example of a program that breaks when these values
- *      don't match is /usr/bin/pwd.  This program first acquires the node id of
- *      "." from its vnode, then traverses backwards to ".." and looks for the
- *      dentry in that directory with the inode number matching the node id.
- *      (This is how it obtains the name of the directory it was just in.)
- *      /usr/bin/pwd repeats this until it reaches the root directory, at which
- *      point it concatenates the filenames it acquired along the way and
- *      displays them to the user.  When inode numbers don't match the node id,
- *      /usr/bin/pwd displays an error saying it cannot determine the directory.
- *
  *      The Hgfs protocol does not provide us with unique identifiers for files
  *      since it must support filesystems that do not have the concept of inode
  *      numbers.  Therefore, we must maintain a mapping from filename to node id/
@@ -397,7 +397,7 @@ HgfsFileHashTableIsEmpty(HgfsSuperInfo *sip,            // IN: Superinfo
             }
 
             DEBUG(VM_DEBUG_FAIL, "HgfsFileHashTableIsEmpty: %s is in use.\n",
-                 currFile->fileName);
+                  currFile->fileName);
 
             HGFS_VP_VI_UNLOCK(sip->rootVnode);
             /* Fall through to failure case */
@@ -405,9 +405,8 @@ HgfsFileHashTableIsEmpty(HgfsSuperInfo *sip,            // IN: Superinfo
 
          /* Fail if a file is found. */
          os_mutex_unlock(htp->mutex);
-         DEBUG(VM_DEBUG_FAIL, "HgfsFileHashTableIsEmpty: %s "
-               "still in use (file count=%d).\n",
-               currFile->fileName, currFile->refCount);
+         DEBUG(VM_DEBUG_FAIL, "HgfsFileHashTableIsEmpty: %s still in use.\n",
+               currFile->fileName);
          return FALSE;
       }
    }
@@ -421,13 +420,17 @@ HgfsFileHashTableIsEmpty(HgfsSuperInfo *sip,            // IN: Superinfo
 /*
  *----------------------------------------------------------------------------
  *
- * HgfsHandleIsSet --
+ * HgfsCheckAndReferenceHandle --
  *
  *      Determines whether one of vnode's open file handles is currently set.
+ *      If the handle is set the function increments its reference count.
+ *      The function must be called while holding handleLock from the correspondent
+ *      HgfsFile structure.  
  *
  * Results:
- *      Returns TRUE if the handle is set, FALSE if the handle is not set.
- *      HGFS_ERR is returned on error.
+ *      Returns 0 if the handle is set and had been referenced,
+ *              EACCES if the handle is set but has an incompatible open mode,
+ *              ENOENT if no hadnle is set for the vnode
  *
  * Side effects:
  *      None.
@@ -435,67 +438,29 @@ HgfsFileHashTableIsEmpty(HgfsSuperInfo *sip,            // IN: Superinfo
  *----------------------------------------------------------------------------
  */
 
-Bool
-HgfsHandleIsSet(struct vnode *vp)            // IN: Vnode to check handle of
+int
+HgfsCheckAndReferenceHandle(struct vnode *vp,       // IN: Vnode to check handle of
+                            int requestedOpenMode)  // IN: Requested open mode
 {
-   HgfsOpenFile *ofp;
+   HgfsFile *fp;
    Bool ret;
 
    ASSERT(vp);
 
-   ofp = HGFS_VP_TO_OFP(vp);
-   if (!ofp) {
-      return HGFS_ERR;
-   }
-
-   os_mutex_lock(ofp->handleMutex);
-
-   ret = ofp->handleRefCount ? TRUE : FALSE;
-
-   os_mutex_unlock(ofp->handleMutex);
-
-   return ret;
- }
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * HgfsHandleIncrementRefCount --
- *
- *      Increments the reference count of the specified handle associated with
- *      the vnode (vp).
- *
- * Results:
- *      Returns 0 on success and HGFS_ERR on error.
- *
- * Side effects:
- *      None.
- *
- *----------------------------------------------------------------------------
- */
-
-int
-HgfsHandleIncrementRefCount(struct vnode *vp)           // IN
-{
-   int ret = 0;
-   HgfsOpenFile *ofp;
-
-   ASSERT(vp);
+   fp = HGFS_VP_TO_FP(vp);
+   ASSERT(fp);
 
-   ofp = HGFS_VP_TO_OFP(vp);
-   if (!ofp) {
-      return HGFS_ERR;
+   ret = fp->handleRefCount ? 0 : ENOENT;
+   if (ret == 0) {
+      if (HgfsIsModeCompatible(requestedOpenMode, fp->mode)) {
+         fp->handleRefCount++;
+      } else {
+         ret = EACCES;
+      }
    }
 
-   os_mutex_lock(ofp->handleMutex);
-
-   ++ofp->handleRefCount;
-
-   os_mutex_unlock(ofp->handleMutex);
-
    return ret;
-}
+ }
 
 
 /*
@@ -505,10 +470,11 @@ HgfsHandleIncrementRefCount(struct vnode *vp)           // IN
  *
  *      Sets the file handle for the provided vnode if it has reference count
  *      equal to zero. The reference count of the handle must be increased when
- *      the handle is set. This is done with HgfsHandleIsSet.
+ *      the handle is set. This is done with HgfsCheckAndReferenceHandle.
+ *      Caller must hold handleLock when invoking the function.
  *
  * Results:
- *      Returns 0 on success and a non-zero error code on failure.
+ *      None.
  *
  * Side effects:
  *      The handle may not be set again until it is cleared.
@@ -516,41 +482,24 @@ HgfsHandleIncrementRefCount(struct vnode *vp)           // IN
  *----------------------------------------------------------------------------
  */
 
-int
+void
 HgfsSetOpenFileHandle(struct vnode *vp,          // IN: Vnode to set handle for
-                     HgfsHandle handle)         // IN: Value of handle
+                      HgfsHandle handle,         // IN: Value of handle
+                      HgfsMode openMode)         // IN: Mode assosiated with the handle
 {
-   int ret = 0;
-   HgfsOpenFile *ofp;
+   HgfsFile *fp;
 
    ASSERT(vp);
 
-   ofp = HGFS_VP_TO_OFP(vp);
-   if (!ofp) {
-      return HGFS_ERR;
-   }
-
-   os_mutex_lock(ofp->handleMutex);
+   fp = HGFS_VP_TO_FP(vp);
+   ASSERT(fp);
 
-   if (ofp->handleRefCount != 0) {
-      ret = HGFS_ERR;
-      goto out;
-   }
-   ++ofp->handleRefCount;
-   ofp->handle = handle;
+   fp->handle = handle;
+   fp->mode = openMode;
+   fp->handleRefCount = 1;
 
    DEBUG(VM_DEBUG_STATE, "HgfsSetOpenFileHandle: set handle for %s to %d\n",
-         HGFS_VP_TO_FILENAME(vp), ofp->handle);
-
-out:
-   os_mutex_unlock(ofp->handleMutex);
-
-   if (ret) {
-      DEBUG(VM_DEBUG_FAIL, "could not set file handle for %s\n",
-           HGFS_VP_TO_FILENAME(vp));
-   }
-
-   return ret;
+         HGFS_VP_TO_FILENAME(vp), fp->handle);
 }
 
 
@@ -573,29 +522,26 @@ out:
 
 int
 HgfsGetOpenFileHandle(struct vnode *vp,          // IN:  Vnode to get handle for
-                     HgfsHandle *outHandle)     // OUT: Filled with value of handle
+                      HgfsHandle *outHandle)     // OUT: Filled with value of handle
 {
-   HgfsOpenFile *ofp;
+   HgfsFile *fp;
    int ret = 0;
 
    ASSERT(vp);
    ASSERT(outHandle);
 
-   ofp = HGFS_VP_TO_OFP(vp);
-   if (!ofp) {
-      return HGFS_ERR;
-   }
+   fp = HGFS_VP_TO_FP(vp);
+   ASSERT(fp);
 
-   os_mutex_lock(ofp->handleMutex);
+   os_rw_lock_lock_shared(fp->handleLock);
 
-   if (ofp->handleRefCount == 0) {
-      os_mutex_unlock(ofp->handleMutex);
+   if (fp->handleRefCount == 0) {
       ret = HGFS_ERR;
+   } else {
+      *outHandle = fp->handle;
    }
 
-   *outHandle = ofp->handle;
-
-   os_mutex_unlock(ofp->handleMutex);
+   os_rw_lock_unlock_shared(fp->handleLock);
 
    return ret;
 }
@@ -607,51 +553,51 @@ HgfsGetOpenFileHandle(struct vnode *vp,          // IN:  Vnode to get handle for
  * HgfsReleaseOpenFileHandle --
  *
  *      Decrements the reference count of one of the handles for the provided
- *      vnode. If the reference count becomes zero, then the handle is cleared.
+ *      vnode. If the reference count becomes zero, then the handle is cleared and
+ *      the original handle is retruned to the caller.
  *
  * Results:
- *      Returns 0 on success and a non-zero error code on failure.
+ *      Returns new handle reference count.
+ *      When the returned value is 0 returns the file handle which need to be closed
+ *      on the host.
  *
  * Side effects:
- *      The handle may be cleared.
+ *      None.
  *
  *----------------------------------------------------------------------------
  */
 
 int
-HgfsReleaseOpenFileHandle(struct vnode *vp,          // IN
-                         Bool *closed)              // OUT
+HgfsReleaseOpenFileHandle(struct vnode *vp,            // IN
+                          HgfsHandle *handleToClose)   // OUT
 {
-   int ret = 0;
-   HgfsOpenFile *ofp;
+   int ret;
+   HgfsFile *fp;
 
    ASSERT(vp);
 
-   ofp = HGFS_VP_TO_OFP(vp);
-   if (!ofp) {
-      return HGFS_ERR;
-   }
-
-   *closed = FALSE;
+   fp = HGFS_VP_TO_FP(vp);
+   ASSERT(fp);
 
-   os_mutex_lock(ofp->handleMutex);
+   os_rw_lock_lock_exclusive(fp->handleLock);
 
    /* Make sure the reference count is not going negative! */
-   ASSERT(ofp->handleRefCount > 0);
+   ASSERT(fp->handleRefCount > 0);
 
-   --ofp->handleRefCount;
+   --fp->handleRefCount;
+   ret = fp->handleRefCount;
 
    /* If the reference count has gone to zero, clear the handle. */
-   if (ofp->handleRefCount == 0) {
+   if (ret == 0) {
       DEBUG(VM_DEBUG_LOG, "closing directory handle\n");
-      ofp->handle = 0;
-      *closed = TRUE;
+      *handleToClose = fp->handle;
+      fp->handle = 0;
    } else {
       DEBUG(VM_DEBUG_LOG, "ReleaseOpenFileHandle with a refcount of: %d\n",
-           ofp->handleRefCount);
+                fp->handleRefCount);
    }
 
-   os_mutex_unlock(ofp->handleMutex);
+   os_rw_lock_unlock_exclusive(fp->handleLock);
 
    return ret;
 }
@@ -660,15 +606,19 @@ HgfsReleaseOpenFileHandle(struct vnode *vp,          // IN
 /*
  *----------------------------------------------------------------------------
  *
- * HgfsShouldCloseOpenFileHandle --
+ * HgfsLookupExistingVnode --
  *
- *      Checks to see if the next call to HgfsReleaseOpenFileHandle will result in
- *      the file handle being cleared.
+ *      Locates existing vnode in the hash table that matches given file name.
+ *      If a vnode that corresponds the given name does not exists then the function
+ *      returns ENOENT.
+ *      If the vnode exists the function behavior depends on failIfExist parameter.
+ *      When failIfExist is true then the function return EEXIST, otherwise 
+ *      function references the vnode, assigns vnode pointer to vpp and return 0.
  *
  * Results:
- *      Returns TRUE if the file handle will be cleared on the next
- *      HgfsReleaseOpenFileHandle call and FALSE otherwise.
- *      Returns HGFS_ERR if an error was encountered.
+ *      
+ *      Returns 0 if existing vnode is found and its address is returned in vpp or
+ *      an error code otherwise.
  *
  * Side effects:
  *      None.
@@ -676,668 +626,326 @@ HgfsReleaseOpenFileHandle(struct vnode *vp,          // IN
  *----------------------------------------------------------------------------
  */
 
-Bool
-HgfsShouldCloseOpenFileHandle(struct vnode *vp)  // IN: Vnode to clear handle for
+static int
+HgfsLookupExistingVnode(const char* fileName,
+                        HgfsFileHashTable *htp,
+                        Bool failIfExist,
+                        struct vnode **vpp)
 {
-   HgfsOpenFile *ofp;
-
-   ASSERT(vp);
-
-   ofp = HGFS_VP_TO_OFP(vp);
-   if (!ofp) {
-      return HGFS_ERR;
-   }
-
-   os_mutex_lock(ofp->handleMutex);
-
-   if (ofp->handleRefCount == 1) {
-      os_mutex_unlock(ofp->handleMutex);
-      return TRUE;
+   HgfsFile* existingFp;
+   int err = ENOENT;
+   os_mutex_lock(htp->mutex);
+   /* First verify if a vnode for the filename is already allocated. */
+   existingFp = HgfsFindFile(fileName, htp);
+   if (existingFp != NULL) {
+      if (failIfExist) {
+         err = EEXIST;
+      } else {
+         err = vnode_get(existingFp->vnodep);
+         if (err == 0) {
+            *vpp = existingFp->vnodep;
+         } else {
+            /* vnode exists but unusable, remove HGFS context assosiated with it. */
+            DEBUG(VM_DEBUG_FAIL, "Removing HgfsFile assosiated with an unusable vnode\n");
+            HgfsRemoveFile(existingFp, htp);
+            err = ENOENT;
+         }
+      }
    }
-
-   os_mutex_unlock(ofp->handleMutex);
-
-   return FALSE;
+   os_mutex_unlock(htp->mutex);
+   return err;
 }
 
+/*
+ * Local functions (definitions)
+ */
+
+/* Internal versions of public functions to allow bypassing htp locking */
 
 /*
  *----------------------------------------------------------------------------
  *
- * HgfsSetOpenFileMode --
+ * HgfsVnodeGetInt --
+ *
+ *      Creates a vnode for the provided filename.
  *
- *      Sets the mode of the open file for the provided vnode.
+ *      If a HgfsFile already exists for this filename then it is used and the associated
+ *      vnode is referenced and returned.
+ *      if a HgfsFile doesn't exist, a new vnode and HgfsFile structure is created.
  *
  * Results:
- *      Returns 0 on success and a non-zero error code on failure.
+ *      Returns 0 on success and a non-zero error code on failure.  The new
+ *      vnode is returned locked.
  *
  * Side effects:
- *      The mode may not be set again until cleared.
+ *      None.
  *
  *----------------------------------------------------------------------------
  */
 
-int
-HgfsSetOpenFileMode(struct vnode *vp,   // IN: Vnode to set mode for
-                    HgfsMode mode)      // IN: Mode to set to
+#if defined(__FreeBSD__)
+static int
+HgfsVnodeGetInt(struct vnode **vpp,        // OUT:  Filled with address of created vnode
+                struct vnode *dvp,         // IN:   Parent directory vnode
+                HgfsSuperInfo *sip,        // IN:   Superinfo
+                struct mount *vfsp,        // IN:   Filesystem structure
+                const char *fileName,      // IN:   Name of this file
+                HgfsFileType fileType,     // IN:   Tyoe of file
+                HgfsFileHashTable *htp,    // IN:   File hash
+                Bool rootVnode,            // IN:   Is this a root vnode?
+                Bool fileCreate,           // IN:   Is it a new file creation?
+                int permissions)           // IN:   Permissions for new files
 {
-   HgfsOpenFile *ofp;
-
-   ASSERT(vp);
+   struct vnode *vp;
+   int ret;
 
-   ofp = HGFS_VP_TO_OFP(vp);
-   if (!ofp) {
-      return HGFS_ERR;
-   }
+   HgfsFile *fp;
+   HgfsFile *existingFp;
 
-   os_mutex_lock(ofp->modeMutex);
+   ASSERT(vpp);
+   ASSERT(sip);
+   ASSERT(vfsp);
+   ASSERT(fileName);
+   ASSERT(htp);
+   ASSERT(dvp != NULL || rootVnode);
 
-   if (ofp->modeIsSet) {
-      DEBUG(VM_DEBUG_FAIL, "**HgfsSetOpenFileMode: mode for %s already set to %d; "
-            "cannot set to %d\n", HGFS_VP_TO_FILENAME(vp), ofp->mode, mode);
-      os_mutex_unlock(ofp->modeMutex);
-      return HGFS_ERR;
+   /* First verify if a vnode for the filename is already allocated. */
+   ret = HgfsLookupExistingVnode(fileName, htp, fileCreate, vpp);
+   if (ret != ENOENT) {
+      return ret;
    }
 
-   ofp->mode = mode;
-   ofp->modeIsSet = TRUE;
-
-   DEBUG(VM_DEBUG_STATE, "HgfsSetOpenFileMode: set mode for %s to %d\n",
-         HGFS_VP_TO_FILENAME(vp), ofp->mode);
+   /*
+    * Here we need to construct the vnode for the kernel as well as our
+    * internal file system state.  Our internal state described by
+    * HgfsFile structure which is kept per-file. There is no state information assosiated
+    * with file descriptor. The reason is that when OS invokes vnode methods
+    * it does not provide information about file descriptor that was used to initiate the
+    * IO. We have a one-to-one mapping between vnodes and HgfsFiles.
+    */
+   if ((ret = getnewvnode(HGFS_FS_NAME, vfsp, &HgfsVnodeOps, &vp)) != 0) {
+      return ret;
+   }
 
-   os_mutex_unlock(ofp->modeMutex);
+   /*
+    * Return a locked vnode to the caller.
+    */
+   ret = compat_lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL, curthread);
+   if (ret) {
+      DEBUG(VM_DEBUG_FAIL, "Fatal: could not acquire lock on vnode\n");
+      goto destroyVnode;
+   }
 
-   return 0;
-}
+   /*
+    * Now we'll initialize the vnode.  We need to set the file type, vnode
+    * operations, flags, filesystem pointer, reference count, and device.
+    * After that we'll create our private structures and hang them from the
+    * vnode's v_data pointer.
+    */
+   switch (fileType) {
+   case HGFS_FILE_TYPE_REGULAR:
+      vp->v_type = VREG;
+      break;
 
+   case HGFS_FILE_TYPE_DIRECTORY:
+      vp->v_type = VDIR;
+      break;
 
-/*
- *----------------------------------------------------------------------------
- *
- * HgfsGetOpenFileMode --
- *
- *      Gets the mode of the file for the provided vnode.
- *
- * Results:
- *      Returns 0 on success and a non-zero error code on failure.
- *
- * Side effects:
- *      None.
- *
- *----------------------------------------------------------------------------
- */
+   case HGFS_FILE_TYPE_SYMLINK:
+      vp->v_type = VLNK;
+      break;
 
-int
-HgfsGetOpenFileMode(struct vnode *vp,   // IN:  Vnode to get mode for
-                    HgfsMode *outMode)  // OUT: Filled with mode
-{
-   HgfsOpenFile *ofp;
+   default:
+      /* Hgfs only supports directories and regular files */
+      ret = EPERM;
+      goto destroyOut;
+   }
 
-   ASSERT(vp);
-   ASSERT(outMode);
+   /* We now allocate our private open file structure.    */
+   fp = (void *)HgfsAllocFile(fileName, fileType, dvp, htp, permissions);
+   if (fp == NULL) {
+      ret = ENOMEM;
+      goto destroyOut;
+   }
 
-   ofp = HGFS_VP_TO_OFP(vp);
-   if (!ofp) {
-      return HGFS_ERR;
+   fp->vnodep = vp;
+   vp->v_data = fp;
+   /* If this is going to be the root vnode, we have to mark it as such. */
+   if (rootVnode) {
+      vp->v_vflag |= VV_ROOT;
    }
 
-   os_mutex_lock(ofp->modeMutex);
+   existingFp = HgfsInsertFile(fileName, fp, htp);
 
-   if (!ofp->modeIsSet) {
-      os_mutex_unlock(ofp->modeMutex);
-      return HGFS_ERR;
+   if (existingFp != NULL) { // Race occured, another thread inserted a node ahead of us
+      if (fileCreate) {
+         ret = EEXIST;
+         goto destroyOut;
+      }
+      compat_lockmgr(vp->v_vnlock, LK_RELEASE, NULL, curthread);
+      vput(vp);
+      vp = existingFp->vnodep;
+      /*
+       * Return a locked vnode to the caller.
+       */
+      ret = compat_lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL, curthread);
+      if (ret) {
+         DEBUG(VM_DEBUG_FAIL, "Fatal: could not acquire lock on vnode\n");
+         goto destroyVnode;
+      }
+      HgfsFreeFile(fp);
    }
 
-   *outMode = ofp->mode;
-
-   os_mutex_unlock(ofp->modeMutex);
+   /* Fill in the provided address with the new vnode. */
+   *vpp = vp;
 
+   /* Return success */
    return 0;
-}
 
+   /* Cleanup points for errors. */
+destroyOut:
+   compat_lockmgr(vp->v_vnlock, LK_RELEASE, NULL, curthread);
+destroyVnode:
+   vput(vp);
+   return ret;
+}
 
-/*
- *----------------------------------------------------------------------------
- *
- * HgfsClearOpenFileMode --
- *
- *      Clears the mode of the file for the provided vnode.
- *
- * Results:
- *      Returns 0 on success and a non-zero error code on failure.
- *
- * Side effects:
- *      The mode may be set again.
- *
- *----------------------------------------------------------------------------
- */
-
-int
-HgfsClearOpenFileMode(struct vnode *vp) // IN: Vnode to clear mode for
+#elif defined(__APPLE__)
+static int
+HgfsVnodeGetInt(struct vnode **vpp,        // OUT
+                struct vnode *dvp,         // IN
+                HgfsSuperInfo *sip,        // IN
+                struct mount *vfsp,        // IN
+                const char *fileName,      // IN
+                HgfsFileType fileType,     // IN
+                HgfsFileHashTable *htp,    // IN
+                Bool rootVnode,            // IN
+                Bool fileCreate,           // IN
+                int permissions)           // IN
 {
-   HgfsOpenFile *ofp;
+   struct vnode *vp;
+   struct vnode_fsparam params;
+   int ret;
+   HgfsFile *fp = NULL;
+   HgfsFile *existingFp;
 
-   ASSERT(vp);
+   ASSERT(vpp);
+   ASSERT(sip);
+   ASSERT(vfsp);
+   ASSERT(fileName);
+   ASSERT(htp);
 
-   ofp = HGFS_VP_TO_OFP(vp);
-   if (!ofp) {
-      return HGFS_ERR;
+   /* First verify if a vnode for the filename is already allocated. */
+   ret = HgfsLookupExistingVnode(fileName, htp, fileCreate, vpp);
+   if (ret != ENOENT) {
+      return ret;
    }
 
-   os_mutex_lock(ofp->modeMutex);
-
-   ofp->mode = 0;
-   ofp->modeIsSet = FALSE;
-
-   DEBUG(VM_DEBUG_STATE, "HgfsClearOpenOpenFileMode: cleared %s's mode\n",
-         HGFS_VP_TO_FILENAME(vp));
-
-   os_mutex_unlock(ofp->modeMutex);
+   params.vnfs_mp         = vfsp;
+   params.vnfs_str        = NULL;
+   params.vnfs_dvp        = NULL;
+   params.vnfs_fsnode     = NULL;
+   params.vnfs_vops       = HgfsVnodeOps;
+   params.vnfs_marksystem = FALSE;
+   params.vnfs_rdev       = 0;
+   params.vnfs_filesize   = 0;
+   params.vnfs_cnp        = NULL;
+   /* Do not let OS X cache vnodes for us. */
+   params.vnfs_flags      = VNFS_NOCACHE | VNFS_CANTCACHE;
 
-   return 0;
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * HgfsFileLock --
- *
- *      Locks the HgfsFile associated with the vnode (vp). The type specifies is
- *      we are locking for reads or writes. We only lock the HgfsFile on OS X
- *      because FreeBSD vnodes are locked when handed to the VFS layer and there
- *      is a 1:1 mapping between vnodes and HgfsFile objects so no extra locking
- *      is required.
- *
- * Results:
- *      Returns 0 on success and an error code on error.
- *
- * Side effects:
- *      None.
- *
- *----------------------------------------------------------------------------
- */
-
-int
-HgfsFileLock(struct vnode *vp,  // IN: Vnode to lock
-            HgfsLockType type) // IN: Reader or Writer lock?
-{
-#if defined(__APPLE__)
-   HgfsOpenFile *ofp;
-
-   ASSERT(vp);
-
-   ofp = HGFS_VP_TO_OFP(vp);
-   if (!ofp) {
-      return HGFS_ERR;
-   }
-
-   return HgfsFileLockOfp(ofp, type);
-#else
-   NOT_IMPLEMENTED();
-#endif
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * HgfsFileUnlock --
- *
- *      Unlocks the HgfsFile associated with the vnode (vp). Results are
- *      undefined the type of lock specified is different than the one that the
- *      vnode was locked with originally.
- *
- * Results:
- *      Returns 0 on success and an error code on error.
- *
- * Side effects:
- *      None.
- *
- *----------------------------------------------------------------------------
- */
-
-int
-HgfsFileUnlock(struct vnode *vp,  // IN: Vnode to unlock
-              HgfsLockType type) // IN: Reader or Writer lock?
-{
-#if defined(__APPLE__)
-   HgfsOpenFile *ofp;
-
-   ASSERT(vp);
-
-   ofp = HGFS_VP_TO_OFP(vp);
-   if (!ofp) {
-      return HGFS_ERR;
-   }
-
-   return HgfsFileUnlockOfp(ofp, type);
-#else
-   NOT_IMPLEMENTED();
-#endif
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * HgfsFileLockOfp --
- *
- *      Locks the HgfsFile associated with the HgfsOpenFile. This funciton should
- *      only be called by HgfsFileLock
- *
- * Results:
- *      Returns 0 on success and an error code on error.
- *
- * Side effects:
- *      None.
- *
- *----------------------------------------------------------------------------
- */
-
-int
-HgfsFileLockOfp(HgfsOpenFile *ofp, // IN: HgfsOpenFile to lcok
-               HgfsLockType type) // IN: Reader or Writer lock?
-{
-#if defined(__APPLE__)
-   ASSERT(ofp);
-
-   if (type == HGFS_READER_LOCK) {
-      os_rw_lock_lock_shared(ofp->rwFileLock);
-   } else if (type == HGFS_WRITER_LOCK) {
-      os_rw_lock_lock_exclusive(ofp->rwFileLock);
-   } else {
-      return HGFS_ERR;
-   }
-   return 0;
-#else
-   NOT_IMPLEMENTED();
-#endif
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * HgfsFileUnlockOfp --
- *
- *      Unlocks the HgfsFile associated with the HgfsOpenFile. This funciton should
- *      only be called by inactive, reclaim and the HgfsFileUnlock routine.
- *
- * Results:
- *      Returns 0 on success and an error code on error.
- *
- * Side effects:
- *      None.
- *
- *----------------------------------------------------------------------------
- */
-
-int
-HgfsFileUnlockOfp(HgfsOpenFile *ofp, // IN: HgfsOpenFile to unlcok
-                 HgfsLockType type) // IN: Reader or Writer lock?
-{
-#if defined(__APPLE__)
-   ASSERT(ofp);
-
-   if (type == HGFS_READER_LOCK) {
-      os_rw_lock_unlock_shared(ofp->rwFileLock);
-   } else if (type == HGFS_WRITER_LOCK) {
-      os_rw_lock_unlock_exclusive(ofp->rwFileLock);
-   } else {
-      return HGFS_ERR;
-   }
-   return 0;
-#else
-   NOT_IMPLEMENTED();
-#endif
-}
-
-
-/*
- * Local functions (definitions)
- */
-
-/* Internal versions of public functions to allow bypassing htp locking */
-
-/*
- *----------------------------------------------------------------------------
- *
- * HgfsVnodeGetInt --
- *
- *      Creates a vnode for the provided filename.
- *
- *      This will always allocate a vnode and HgfsOpenFile.  If a HgfsFile
- *      already exists for this filename then that is used, if a HgfsFile doesn't
- *      exist, one is created.
- *
- * Results:
- *      Returns 0 on success and a non-zero error code on failure.  The new
- *      vnode is returned locked.
- *
- * Side effects:
- *      None.
- *
- *----------------------------------------------------------------------------
- */
-
-#if defined(__FreeBSD__)
-static int
-HgfsVnodeGetInt(struct vnode **vpp,        // OUT:  Filled with address of created vnode
-                HgfsSuperInfo *sip,        // IN:   Superinfo
-                struct mount *vfsp,        // IN:   Filesystem structure
-                const char *fileName,      // IN:   Name of this file
-                HgfsFileType fileType,     // IN:   Tyoe of file
-                HgfsFileHashTable *htp,    // IN:   File hash
-               Bool rootVnode)            // IN:   Is this a root vnode?
-{
-   struct vnode *vp;
-   int ret = 0;
-
-   ASSERT(vpp);
-   ASSERT(sip);
-   ASSERT(vfsp);
-   ASSERT(fileName);
-   ASSERT(htp);
-
-   /*
-    * Here we need to construct the vnode for the kernel as well as our
-    * internal file system state.  Our internal state consists of
-    * a HgfsOpenFile and a HgfsFile.  The HgfsOpenFile is state kept per-open
-    * file; the HgfsFile state is kept per-file.  We have a one-to-one mapping
-    * between vnodes and HgfsOpenFiles, and a many-to-one mapping from each of
-    * those to a HgfsFile.
-    *
-    * Note that it appears the vnode is intended to be used as a per-file
-    * structure, but we are using it as a per-open-file. The sole exception
-    * for this is the root vnode because it is returned by HgfsRoot().  This
-    * also means that reference counts for all vnodes except the root should
-    * be one; the reference count in our HgfsFile takes on the role of the
-    * vnode reference count.
-    */
-   if ((ret = getnewvnode(HGFS_FS_NAME, vfsp, &HgfsVnodeOps, &vp)) != 0) {
-      return ret;
-   }
-
-   /*
-    * Return a locked vnode to the caller.
-    */
-   ret = compat_lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL, curthread);
-   if (ret) {
-      DEBUG(VM_DEBUG_FAIL, "Fatal: could not acquire lock on vnode\n");
-      goto destroyVnode;
-   }
-
-   /*
-    * Now we'll initialize the vnode.  We need to set the file type, vnode
-    * operations, flags, filesystem pointer, reference count, and device.
-    * After that we'll create our private structures and hang them from the
-    * vnode's v_data pointer.
-    */
-   switch (fileType) {
-   case HGFS_FILE_TYPE_REGULAR:
-      vp->v_type = VREG;
-      break;
-
-   case HGFS_FILE_TYPE_DIRECTORY:
-      vp->v_type = VDIR;
-      break;
-
-   case HGFS_FILE_TYPE_SYMLINK:
-      vp->v_type = VLNK;
-      break;
-
-   default:
-      /* Hgfs only supports directories and regular files */
-      ret = EPERM;
-      goto destroyOut;
-   }
-
-   /*
-    * We now allocate our private open file structure.  This will correctly
-    * initialize the per-open-file state, as well as locate (or create if
-    * necessary) the per-file state.
-    */
-   vp->v_data = (void *)HgfsAllocOpenFile(fileName, fileType, htp);
-   if (vp->v_data == NULL) {
-      ret = ENOMEM;
-      goto destroyOut;
-   }
-
-   /* If this is going to be the root vnode, we have to mark it as such. */
-   if (rootVnode) {
-      vp->v_vflag |= VV_ROOT;
-   }
-
-   /* Fill in the provided address with the new vnode. */
-   *vpp = vp;
-
-   /* Return success */
-   return 0;
-
-   /* Cleanup points for errors. */
-destroyOut:
-   compat_lockmgr(vp->v_vnlock, LK_RELEASE, NULL, curthread);
-destroyVnode:
-   vrele(vp);
-   return ret;
-}
-
-#elif defined(__APPLE__)
-static int
-HgfsVnodeGetInt(struct vnode **vpp,        // OUT
-               HgfsSuperInfo *sip,        // IN
-               struct mount *vfsp,        // IN
-               const char *fileName,      // IN
-               HgfsFileType fileType,     // IN
-               HgfsFileHashTable *htp,    // IN
-               Bool rootVnode)            // IN
-{
-   struct vnode *vp;
-   struct vnode_fsparam params;
-   int ret = 0;
-   HgfsOpenFile *ofp;
-
-   ASSERT(vpp);
-   ASSERT(sip);
-   ASSERT(vfsp);
-   ASSERT(fileName);
-   ASSERT(htp);
-
-   params.vnfs_mp         = vfsp;
-   params.vnfs_str        = NULL;
-   params.vnfs_dvp        = NULL;
-   params.vnfs_fsnode     = NULL;
-   params.vnfs_vops       = HgfsVnodeOps;
-   params.vnfs_marksystem = FALSE;
-   params.vnfs_rdev       = 0;
-   params.vnfs_filesize   = 0;
-   params.vnfs_cnp        = NULL;
-   /* Do not let OS X cache vnodes for us. */
-   params.vnfs_flags      = VNFS_NOCACHE | VNFS_CANTCACHE;
-
-   if (rootVnode) {
-      params.vnfs_markroot = TRUE;
-   } else {
-      params.vnfs_markroot   = FALSE;
-   }
+   if (rootVnode) {
+      params.vnfs_markroot = TRUE;
+   } else {
+      params.vnfs_markroot   = FALSE;
+   }
 
    /*
     * Now we'll initialize the vnode.  We need to set the file type, vnode
     * operations, flags, filesystem pointer, reference count, and device.
     * After that we'll create our private structures and hang them from the
-    * vnode's v_data pointer.
-    */
-   switch (fileType) {
-   case HGFS_FILE_TYPE_REGULAR:
-      params.vnfs_vtype = VREG;
-      break;
-
-   case HGFS_FILE_TYPE_DIRECTORY:
-      params.vnfs_vtype = VDIR;
-      break;
-
-   case HGFS_FILE_TYPE_SYMLINK:
-      params.vnfs_vtype = VLNK;
-      break;
-
-   default:
-      /* Hgfs only supports directories and regular files */
-      ret = EINVAL;
-      goto out;
-   }
-
-   /*
-    * We now allocate our private open file structure.  This will correctly
-    * initialize the per-open-file state, as well as locate (or create if
-    * necessary) the per-file state.
-    */
-
-   ofp = HgfsAllocOpenFile(fileName, fileType, htp);
-
-   params.vnfs_fsnode = (void *)ofp;
-   if (params.vnfs_fsnode == NULL) {
-      ret = ENOMEM;
-      goto out;
-   }
-
-
-   ret = vnode_create(VNCREATE_FLAVOR, sizeof(params), &params, &vp);
-   ofp->vnodep = vp;
-
-   /* Get a soft FS reference to the vnode. This tells the system that the vnode
-    * has data associated with it. It is considered a weak reference though, in that
-    * it does not prevent the system from reusing the vnode.
-    */
-   vnode_addfsref(vp);
-
-   if (ret != 0) {
-      DEBUG(VM_DEBUG_FAIL, "Failed to create vnode");
-      ret = EINVAL;
-      goto destroyVnode;
-   }
-
-   /* Fill in the provided address with the new vnode. */
-   *vpp = vp;
-
-   /* Return success */
-   return 0;
-
-   /* Cleanup points for errors. */
-destroyVnode:
-   vnode_put(vp);
-out:
-   return ret;
-}
-#else
-   NOT_IMPLEMENTED();
-#endif
-
-/* Allocation/initialization/free of open file state */
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * HgfsAllocOpenFile --
- *
- *      Allocates and initializes an open file structure.  Also finds or, if
- *      necessary, creates the underlying HgfsFile per-file state.
- *
- * Results:
- *      Returns a pointer to the open file on success, NULL on error.
- *
- * Side effects:
- *      None.
- *
- *----------------------------------------------------------------------------
- */
-
-static HgfsOpenFile *
-HgfsAllocOpenFile(const char *fileName,         // IN: Name of file
-                  HgfsFileType fileType,        // IN: Type of file
-                  HgfsFileHashTable *htp)       // IN: Hash table
-{
-   HgfsOpenFile *ofp;
-
-   ASSERT(fileName);
-   ASSERT(htp);
-
-   /*
-    * We allocate and initialize our open-file state.
+    * vnode's v_data pointer.
     */
-   ofp = os_malloc(sizeof *ofp, M_ZERO | M_WAITOK);
-   if (!ofp) {
-      DEBUG(VM_DEBUG_FAIL, "Failed to allocate memory");
-      return NULL;
-   }
+   switch (fileType) {
+   case HGFS_FILE_TYPE_REGULAR:
+      params.vnfs_vtype = VREG;
+      break;
 
-   ofp->mode = 0;
-   ofp->modeIsSet = FALSE;
+   case HGFS_FILE_TYPE_DIRECTORY:
+      params.vnfs_vtype = VDIR;
+      break;
 
-   ofp->handleRefCount = 0;
-   ofp->handle = 0;
+   case HGFS_FILE_TYPE_SYMLINK:
+      params.vnfs_vtype = VLNK;
+      break;
 
-   ofp->handleMutex = os_mutex_alloc_init("hgfs_mtx_handle");
-   if (!ofp->handleMutex) {
-      goto destroyOut;
+   default:
+      /* Hgfs only supports directories and regular files */
+      ret = EINVAL;
+      goto out;
    }
 
-   ofp->modeMutex = os_mutex_alloc_init("hgfs_mtx_mode");
-   if (!ofp->modeMutex) {
-      goto destroyOut;
-   }
+   fp = HgfsAllocFile(fileName, fileType, dvp, htp, permissions);
 
-#if defined(__APPLE__)
-   ofp->rwFileLock = os_rw_lock_alloc_init("hgfs_rw_file_lock");
-   if (!ofp->rwFileLock) {
-      goto destroyOut;
+   params.vnfs_fsnode = (void *)fp;
+   if (params.vnfs_fsnode == NULL) {
+      ret = ENOMEM;
+      goto out;
    }
-#endif
 
-   /*
-    * Now we get a reference to the underlying per-file state.
-    */
-   ofp->hgfsFile = HgfsGetFile(fileName, fileType, htp);
-   if (!ofp->hgfsFile) {
-      goto destroyOut;
+   ret = vnode_create(VNCREATE_FLAVOR, sizeof(params), &params, &vp);
+   if (ret != 0) {
+      DEBUG(VM_DEBUG_FAIL, "Failed to create vnode");
+      goto out;
    }
 
-   /* Success */
-   return ofp;
+   fp->vnodep = vp;
 
-destroyOut:
-   ASSERT(ofp);
+   existingFp = HgfsInsertFile(fileName, fp, htp);
 
-   if (ofp->handleMutex) {
-      os_mutex_free(ofp->handleMutex);
+   if (existingFp != NULL) { // Race occured, another thread inserted a node ahead of us
+      vnode_put(vp);
+      if (fileCreate) {
+         ret = EEXIST;
+         goto out;
+      }
+      vp = existingFp->vnodep;
+      HgfsFreeFile(fp);
+   } else {
+      /* Get a soft FS reference to the vnode. This tells the system that the vnode
+       * has data associated with it. It is considered a weak reference though, in that
+       * it does not prevent the system from reusing the vnode.
+       */
+      vnode_addfsref(vp);
    }
 
-   if (ofp->modeMutex) {
-      os_mutex_free(ofp->modeMutex);
-   }
+   /* Fill in the provided address with the new vnode. */
+   *vpp = vp;
 
-#if defined(__APPLE__)
-   if (ofp->rwFileLock) {
-      os_rw_lock_free(ofp->rwFileLock);
+   /* Return success */
+   return 0;
+
+out:
+   if (fp) {
+      HgfsFreeFile(fp);
    }
+   return ret;
+}
+#else
+   NOT_IMPLEMENTED();
 #endif
 
-   os_free(ofp, sizeof *ofp);
-   return NULL;
-
-}
+/* Allocation/initialization/free of open file state */
 
 
 /*
  *----------------------------------------------------------------------------
  *
- * HgfsFreeOpenFile --
+ * HgfsAllocFile --
  *
- *      Frees the provided open file.
+ *      Allocates and initializes a file structure.
  *
  * Results:
- *      Returns 0 on success and a non-zero error code on failure.
+ *      Returns a pointer to the open file on success, NULL on error.
  *
  * Side effects:
  *      None.
@@ -1345,57 +953,57 @@ destroyOut:
  *----------------------------------------------------------------------------
  */
 
-static void
-HgfsFreeOpenFile(HgfsOpenFile *ofp,             // IN: Open file to free
-                 HgfsFileHashTable *htp)        // IN: File hash table
+static HgfsFile *
+HgfsAllocFile(const char *fileName,         // IN: Name of file
+              HgfsFileType fileType,        // IN: Type of file
+              struct vnode *dvp,            // IN: Parent directory vnode
+              HgfsFileHashTable *htp,       // IN: Hash table
+              int permissions)              // IN: permissions for creating new files
 {
-   ASSERT(ofp);
-   ASSERT(htp);
-
-   /*
-   * First we release our reference to the underlying per-file state.
-   */
-   HgfsReleaseFile(ofp->hgfsFile, htp);
+   HgfsFile *fp;
+   fp = os_malloc(sizeof *fp, M_ZERO | M_WAITOK);
 
-   /*
-    * Then we destroy anything initialized and free the open file.
-    */
-#if defined(__APPLE__)
-   os_rw_lock_free(ofp->rwFileLock);
-#endif
-   os_mutex_free(ofp->handleMutex);
-   os_mutex_free(ofp->modeMutex);
+   if (fp != NULL) {
+      DEBUG(VM_DEBUG_INFO, "HgfsGetFile: allocated HgfsFile for %s.\n", fileName);
 
-   os_free(ofp, sizeof *ofp);
+      if (HgfsInitFile(fp, dvp, fileName, fileType, permissions) != 0) {
+         DEBUG(VM_DEBUG_FAIL, "Failed to initialize HgfsFile");
+         os_free(fp, sizeof(*fp));
+         fp = NULL;
+      }
+   } else {
+      DEBUG(VM_DEBUG_FAIL, "Failed to allocate memory");
+   }
+   return fp;
 }
 
-
 /* Acquiring/releasing file state */
 
 /*
  *----------------------------------------------------------------------------
  *
- * HgfsGetFile --
+ * HgfsInsertFile --
  *
- *      Gets the file for the provided filename.
+ *      Inserts a HgfsFile object into the hash table if the table does not
+ *      contain an object with the same name. 
+ *      If an object with the same name already exists in the hash table
+ *      then does nothing and just returns pointer to the existing object.
  *
  * Results:
- *      Returns a pointer to the file on success, NULL on error.
+ *      Returns a pointer to the file if there is a name collision, NULL otherwise.
  *
  * Side effects:
- *      None.
+ *      If there is a name collision adds reference to vnode IOrefcount.
  *
  *----------------------------------------------------------------------------
  */
 
 static HgfsFile *
-HgfsGetFile(const char *fileName,       // IN: Filename to get file for
-           HgfsFileType fileType,      // IN: Type of file
-           HgfsFileHashTable *htp)     // IN: Hash table to look in
+HgfsInsertFile(const char *fileName,       // IN: Filename to get file for
+               HgfsFile *fp,               // IN: HgfsFile object to insert
+                   HgfsFileHashTable *htp)     // IN: Hash table to look in
 {
-   HgfsFile *fp;
-   HgfsFile *newfp;
-   int err;
+   HgfsFile *existingFp = NULL;
 
    ASSERT(fileName);
    ASSERT(htp);
@@ -1406,71 +1014,27 @@ HgfsGetFile(const char *fileName,       // IN: Filename to get file for
     */
    os_mutex_lock(htp->mutex);
 
-   fp = HgfsFindFile(fileName, htp);
-   if (fp) {
-      /* Signify our reference to this file. */
-      os_mutex_lock(fp->mutex);
-      fp->refCount++;
-      os_mutex_unlock(fp->mutex);
-      goto out;
-   }
-
-   /* Drop the lock here, since we can block on os_malloc */
-   os_mutex_unlock(htp->mutex);
-
-   /*
-    * If it doesn't exist we create one. Ideally this should never fail, since 
-    * we are ready to block till we get memory. Note that while we are creating
-    * HgfsFile, other thread(s) could also be creating HgfsFile at the same time.
-    * Thus once we get memory, we acquire the lock and check hash table to detect
-    * any race condition.     
-    */
-   newfp = os_malloc(sizeof *newfp, M_ZERO | M_WAITOK);
-
-   if (!newfp) {
-      /* newfp is NULL already */
-      DEBUG(VM_DEBUG_FAIL, "Failed to allocate memory");
-      return NULL;
-   }
-
-   /* Acquire the lock and check for races */
-   os_mutex_lock(htp->mutex);
-
-   fp = HgfsFindFile(fileName, htp);
-   if (fp) {
-      /* 
-       * Some other thread allocated HgfsFile before us. Free newfp 
-       * and get the reference on this file.
-       */
-      os_free(newfp, sizeof(*newfp));
-      os_mutex_lock(fp->mutex);
-      fp->refCount++;
-      os_mutex_unlock(fp->mutex);
-      goto out;
+   existingFp = HgfsFindFile(fileName, htp);
+   if (existingFp) { // HgfsFile with this name alrady exists
+      int ret = vnode_get(existingFp->vnodep);
+      if (ret != 0) {
+         /*
+          * It is not clear why vnode_get may fail while there is HgfsFile in
+          * our hash table. Most likely it will never happen.
+          * However if this ever occur the safest approach is to remove
+          * the HgsfFle structure from the hash table but do dont free it.
+          * It should be freed later on when the vnode is recycled.
+          */
+         DblLnkLst_Unlink1(&existingFp->listNode);
+         existingFp = NULL;
+      }
    }
-
-   DEBUG(VM_DEBUG_INFO, "HgfsGetFile: allocated HgfsFile for %s.\n", fileName);
-
-   err = HgfsInitFile(newfp, fileName, fileType);
-   if (err) {
-      os_free(newfp, sizeof(*newfp));
-      newfp = NULL;
-      goto out;
+   if (existingFp) {
+      HgfsAddFile(fp, htp);
    }
 
-   /*
-    * This is guaranteed to not add a duplicate since after acquiring the lock on the 
-    * hash table, we rechecked above to detect if the file was present and have held 
-    * the lock until now.
-    */
-   HgfsAddFile(newfp, htp);
-   fp = newfp;
-
-out:
    os_mutex_unlock(htp->mutex);
-
-   DEBUG(VM_DEBUG_DONE, "HgfsGetFile: done\n");
-   return fp;
+   return existingFp;
 }
 
 
@@ -1479,12 +1043,10 @@ out:
  *
  * HgfsReleaseFile --
  *
- *      Releases a reference to the provided file.  If the reference count of
- *      this file becomes zero, the file structure is removed from the hash table
- *      and freed.
+ * Removes HgfsFile structure from the hash table and releases it.
  *
  * Results:
- *      Returns 0 on success and a non-zero error code on failure.
+ *      None.
  *
  * Side effects:
  *      None.
@@ -1499,30 +1061,15 @@ HgfsReleaseFile(HgfsFile *fp,           // IN: File to release
    ASSERT(fp);
    ASSERT(htp);
 
-   /*
-    * Decrement this file's reference count.  If it becomes zero, then we
-    * remove it from the hash table and free it.
-    */
-   os_mutex_lock(fp->mutex);
-
-   if ( !(--fp->refCount) ) {
-      os_mutex_unlock(fp->mutex);
-
-      /* Remove file from hash table, then clean up. */
-      HgfsRemoveFile(fp, htp);
-
-      DEBUG(VM_DEBUG_INFO, "HgfsReleaseFile: freeing HgfsFile for %s.\n",
-            fp->fileName);
-
-      os_mutex_free(fp->mutex);
-      os_free(fp, sizeof *fp);
-      return;
-   }
+   os_mutex_lock(htp->mutex);
 
-   DEBUG(VM_DEBUG_INFO, "HgfsReleaseFile: %s has %d references.\n",
-         fp->fileName, fp->refCount);
+   DEBUG(VM_DEBUG_INFO, "HgfsReleaseFile: freeing HgfsFile for %s.\n",
+         fp->fileName);
+   /* Take this file off its list */
+   DblLnkLst_Unlink1(&fp->listNode);
+   HgfsFreeFile(fp);
 
-   os_mutex_unlock(fp->mutex);
+   os_mutex_unlock(htp->mutex);
 }
 
 
@@ -1550,8 +1097,10 @@ HgfsReleaseFile(HgfsFile *fp,           // IN: File to release
 
 static int
 HgfsInitFile(HgfsFile *fp,              // IN: File to initialize
+             struct vnode *dvp,         // IN: Paretn directory vnode
              const char *fileName,      // IN: Name of file
-             HgfsFileType fileType)     // IN: Type of file
+             HgfsFileType fileType,     // IN: Type of file
+             int permissions)           // IN: Permissions for new files
 {
    int len;
 
@@ -1564,11 +1113,6 @@ HgfsInitFile(HgfsFile *fp,              // IN: File to initialize
       return HGFS_ERR;
    }
 
-   fp->mutex = os_mutex_alloc_init("hgfs_file_mutex_lock");
-   if (!fp->mutex) {
-      return HGFS_ERR;
-   }
-
    fp->fileNameLength = len;
    memcpy(fp->fileName, fileName, len + 1);
    fp->fileName[fp->fileNameLength] = '\0';
@@ -1577,7 +1121,7 @@ HgfsInitFile(HgfsFile *fp,              // IN: File to initialize
     * We save the file type so we can recreate a vnode for the HgfsFile without
     * sending a request to the Hgfs Server.
     */
-   fp->fileType = fileType;
+   fp->permissions = permissions;
 
    /* Initialize the links to place this file in our hash table. */
    DblLnkLst_Init(&fp->listNode);
@@ -1588,30 +1132,71 @@ HgfsInitFile(HgfsFile *fp,              // IN: File to initialize
     */
    HgfsNodeIdHash(fp->fileName, fp->fileNameLength, &fp->nodeId);
 
-   /* The caller is the single reference. */
-   fp->refCount = 1;
+   fp->mode = 0;
+   fp->modeIsSet = FALSE;
+
+   fp->handleRefCount = 0;
+   fp->handle = 0;
+
+   fp->handleLock = os_rw_lock_alloc_init("hgfs_rw_handle_lock");
+   if (!fp->handleLock) {
+      goto destroyOut;
+   }
+
+   fp->modeMutex = os_mutex_alloc_init("hgfs_mtx_mode");
+   if (!fp->modeMutex) {
+      goto destroyOut;
+   }
+
+#if defined(__APPLE__)
+   fp->rwFileLock = os_rw_lock_alloc_init("hgfs_rw_file_lock");
+   if (!fp->rwFileLock) {
+      goto destroyOut;
+   }
+   DEBUG(VM_DEBUG_LOG, "fp = %p, Lock = %p .\n", fp, fp->rwFileLock);
+
+#endif
+
+   fp->parent = dvp;
+   if (dvp != NULL) {
+      vnode_ref(dvp);
+   }
 
+   /* Success */
    return 0;
-}
 
+destroyOut:
+   ASSERT(fp);
+
+   if (fp->handleLock) {
+      os_rw_lock_free(fp->handleLock);
+   }
 
-/* Adding/finding/removing file state from hash table */
+   if (fp->modeMutex) {
+      os_mutex_free(fp->modeMutex);
+   }
+
+#if defined(__APPLE__)
+   if (fp->rwFileLock) {
+      os_rw_lock_free(fp->rwFileLock);
+   }
+   DEBUG(VM_DEBUG_LOG, "Destroying fp = %p, Lock = %p .\n", fp, fp->rwFileLock);
+#endif
+
+   os_free(fp, sizeof *fp);
+   return HGFS_ERR;
+}
 
 
 /*
  *----------------------------------------------------------------------------
  *
- * HgfsAddFile --
- *
- *      Adds the file to the hash table.
+ * HgfsFreeFile --
  *
- *      This function must be called with the hash table lock held.  This is done
- *      so adding the file in the hash table can be made with any other
- *      operations (such as previously finding out that this file wasn't in the
- *      hash table).
+ *      Preforms necessary cleanup and frees the memory allocated for HgfsFile.
  *
  * Results:
- *      Returns 0 on success and a non-zero error code on failure.
+ *      None.
  *
  * Side effects:
  *      None.
@@ -1619,33 +1204,36 @@ HgfsInitFile(HgfsFile *fp,              // IN: File to initialize
  *----------------------------------------------------------------------------
  */
 
-static void
-HgfsAddFile(HgfsFile *fp,               // IN: File to add
-            HgfsFileHashTable *htp)     // IN: Hash table to add to
+void
+HgfsFreeFile(HgfsFile *fp)
 {
-   unsigned int index;
-
    ASSERT(fp);
-   ASSERT(htp);
-
-   index = HgfsFileNameHash(fp->fileName);
-
-   /* Add this file to the end of the bucket's list */
-   DblLnkLst_LinkLast(HGFS_FILE_HT_HEAD(htp, index), &fp->listNode);
+   os_rw_lock_free(fp->handleLock);
+   os_mutex_free(fp->modeMutex);
+#if defined(__APPLE__)
+   DEBUG(VM_DEBUG_LOG, "Trace enter, fp = %p, Lock = %p .\n", fp, fp->rwFileLock);
+   os_rw_lock_free(fp->rwFileLock);
+#endif
+   if (fp->parent != NULL) {
+      vnode_rele(fp->parent);
+   }
+   os_free(fp, sizeof *fp);
 }
 
+/* Adding/finding/removing file state from hash table */
+
 
 /*
  *----------------------------------------------------------------------------
  *
- * HgfsRemoveFile --
+ * HgfsAddFile --
  *
- *      Removes file from the hash table.
+ *      Adds the file to the hash table.
  *
- *      Note that unlike the other two hash functions, this one performs its own
- *      locking since the removal doesn't need to be atomic with other
- *      operations.  (This could change in the future if the functions that use
- *      this one are reorganized.)
+ *      This function must be called with the hash table lock held.  This is done
+ *      so adding the file in the hash table can be made with any other
+ *      operations (such as previously finding out that this file wasn't in the
+ *      hash table).
  *
  * Results:
  *      Returns 0 on success and a non-zero error code on failure.
@@ -1657,18 +1245,19 @@ HgfsAddFile(HgfsFile *fp,               // IN: File to add
  */
 
 static void
-HgfsRemoveFile(HgfsFile *fp,            // IN: File to remove
-               HgfsFileHashTable *htp)  // IN: Hash table to remove from
+HgfsAddFile(HgfsFile *fp,               // IN: File to add
+            HgfsFileHashTable *htp)     // IN: Hash table to add to
 {
+   unsigned int index;
+
    ASSERT(fp);
    ASSERT(htp);
 
-   os_mutex_lock(htp->mutex);
-
-   /* Take this file off its list */
-   DblLnkLst_Unlink1(&fp->listNode);
+   LCK_MTX_ASSERT(htp->mutex);
+   index = HgfsFileNameHash(fp->fileName);
 
-   os_mutex_unlock(htp->mutex);
+   /* Add this file to the end of the bucket's list */
+   DblLnkLst_LinkLast(HGFS_FILE_HT_HEAD(htp, index), &fp->listNode);
 }
 
 
@@ -1702,6 +1291,7 @@ HgfsFindFile(const char *fileName,      // IN: Filename to look for
 
    ASSERT(fileName);
    ASSERT(htp);
+   LCK_MTX_ASSERT(htp->mutex);
 
    /* Determine which bucket. */
    index = HgfsFileNameHash(fileName);
@@ -1725,6 +1315,43 @@ HgfsFindFile(const char *fileName,      // IN: Filename to look for
 }
 
 
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsRemoveFile --
+ *
+ *      Removes file from the hash table.
+ *
+ *      Note that unlike the other two hash functions, this one performs its own
+ *      locking since the removal doesn't need to be atomic with other
+ *      operations.  (This could change in the future if the functions that use
+ *      this one are reorganized.)
+ *
+ * Results:
+ *      Returns 0 on success and a non-zero error code on failure.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+HgfsRemoveFile(HgfsFile *fp,            // IN: File to remove
+               HgfsFileHashTable *htp)  // IN: Hash table to remove from
+{
+   ASSERT(fp);
+   ASSERT(htp);
+
+   os_mutex_lock(htp->mutex);
+
+   /* Take this file off its list */
+   DblLnkLst_Unlink1(&fp->listNode);
+
+   os_mutex_unlock(htp->mutex);
+}
+
+
 /* Other utility functions */
 
 
@@ -1850,3 +1477,30 @@ HgfsNodeIdHash(const char *fileName,    // IN:  Filename to hash
    return;
 }
 
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsIsModeCompatible --
+ *
+ *      Verifies if the requested open mode for the file is compatible
+ *      with already assigned open mode.
+ *
+ * Results:
+ *      Returns zero on success and an error code on error.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsIsModeCompatible(HgfsMode requestedMode,   // IN: Requested open mode
+                     HgfsMode existingMode)    // IN: Existing open mode
+{
+   DEBUG(VM_DEBUG_LOG, "Compare mode %d with %d.\n", requestedMode, existingMode);
+   return (existingMode == HGFS_OPEN_MODE_READ_WRITE ||
+           requestedMode == existingMode);
+}
+
index 12624795c5533764a82574fce149f7ae1890c0ba..f897437ca6a372c49f3a2cc3f4a469b56ccd5546 100644 (file)
 
 /* Conversion between different state structures */
 #if defined(__FreeBSD__)
-#  define HGFS_VP_TO_OFP(vp)                            \
-           ((HgfsOpenFile *)(vp)->v_data)
+#  define HGFS_VP_TO_FP(vp)                            \
+           ((HgfsFile *)(vp)->v_data)
 #elif defined(__APPLE__)
-#  define HGFS_VP_TO_OFP(vp)                            \
-           ((HgfsOpenFile *)vnode_fsnode(vp))
+#  define HGFS_VP_TO_FP(vp)                            \
+           ((HgfsFile *)vnode_fsnode(vp))
 #endif
 
-#define HGFS_VP_TO_FP(vp)                               \
-         ((HgfsFile *)(HGFS_VP_TO_OFP(vp))->hgfsFile)
-
 #define HGFS_FP_TO_VP(fp)                               \
          (fp)->vnodep
 
 #define HGFS_VP_TO_RWLOCKP(vp)                          \
          &(HGFS_VP_TO_RWLOCK(vp))
 
-#define HGFS_VP_TO_HGFSFILETYPE(vp)                     \
-         HGFS_VP_TO_FP(vp)->fileType
+#define HGFS_VP_TO_PERMISSIONS(vp)                      \
+         HGFS_VP_TO_FP(vp)->permissions
 
-#define HGFS_OFP_TO_FP(ofp)                             \
-         (ofp)->hgfsFile
 
 /*
  * Types
@@ -109,39 +104,26 @@ typedef struct HgfsFile {
    char fileName[MAXPATHLEN + 1];
    uint32_t fileNameLength;
    ino_t nodeId;
-   /*
-    * The file type is saved so additional per-open-file vnodes can be
-    * recreated from a Hgfs file without sending a request to the Hgfs server.
-    */
-   HgfsFileType fileType;
-
-   OS_MUTEX_T *mutex;
-   uint32_t refCount;
-} HgfsFile;
 
-/*
- * State kept per vnode, which implies per open file within a process.
- *
- * Once created, the hgfsFile and vnode/vnodep values are read-only.  The
- * handle and mode will change throughout this structure's existence.
- */
-typedef struct HgfsOpenFile {
    /*
-    * Pointer to the single Hgfs file state structure shared amongst all open
-    * instances of this file.
+    * A pointer back to the vnode this HgfsFile is for.
     */
-   HgfsFile *hgfsFile;
+   struct vnode *vnodep;
 
    /*
-    * A pointer back to the vnode this open-file state is for.
+    * A pointer back to the parent directory vnode.
     */
-   struct vnode *vnodep;
+   struct vnode *parent;
 
    /*
-    * Mode specified for this file to be created with.  This is necessary
+    * Mode (permissions) specified for this file to be created with.  This is necessary
     * because create is called with the mode then open is called without it.
     * We save this value in create and access it in open.
+    * This field is set during initialization of HGFS and is never changed.
     */
+   int permissions;
+
+   /* Mode that was used to open the handle on the host */
    HgfsMode mode;
    Bool modeIsSet;
    OS_MUTEX_T *modeMutex;
@@ -152,7 +134,7 @@ typedef struct HgfsOpenFile {
     */
    uint32_t handleRefCount;
    HgfsHandle handle;
-   OS_MUTEX_T *handleMutex;
+   OS_RWLOCK_T *handleLock;
 
    /*
     * One big difference between the OS X and FreeBSD VFS layers is that the
@@ -164,7 +146,7 @@ typedef struct HgfsOpenFile {
    OS_RWLOCK_T *rwFileLock;
 #endif
 
-} HgfsOpenFile;
+} HgfsFile;
 
 /* The hash table for file state. */
 typedef struct HgfsFileHashTable {
@@ -175,11 +157,12 @@ typedef struct HgfsFileHashTable {
 /* Forward declaration to prevent circular dependency between this and hgfsbsd.h. */
 struct HgfsSuperInfo;
 
-int HgfsVnodeGet(struct vnode **vpp, struct HgfsSuperInfo *sip, struct mount *vfsp,
-                const char *fileName, HgfsFileType fileType, HgfsFileHashTable *htp);
+int HgfsVnodeGet(struct vnode **vpp, struct vnode *dp, struct HgfsSuperInfo *sip,
+                 struct mount *vfsp, const char *fileName, HgfsFileType fileType,
+                 HgfsFileHashTable *htp, Bool createFile, int permissions);
 int HgfsVnodeGetRoot(struct vnode **vpp, struct HgfsSuperInfo *sip, struct mount *vfsp,
                     const char *fileName, HgfsFileType fileType, HgfsFileHashTable *htp);
-int HgfsVnodePut(struct vnode *vp, HgfsFileHashTable *htp);
+int HgfsReleaseVnodeContext(struct vnode *vp, HgfsFileHashTable *htp);
 void HgfsNodeIdGet(HgfsFileHashTable *ht, const char *fileName,
                    uint32_t fileNameLength, ino_t *outNodeId);
 int HgfsInitFileHashTable(HgfsFileHashTable *htp);
@@ -187,22 +170,10 @@ void HgfsDestroyFileHashTable(HgfsFileHashTable *htp);
 Bool HgfsFileHashTableIsEmpty(struct HgfsSuperInfo *sip, HgfsFileHashTable *htp);
 
 /* Handle get/set/clear functions */
-int HgfsSetOpenFileHandle(struct vnode *vp, HgfsHandle handle);
+void HgfsSetOpenFileHandle(struct vnode *vp, HgfsHandle handle, HgfsMode openMode);
 int HgfsGetOpenFileHandle(struct vnode *vp, HgfsHandle *outHandle);
-int HgfsReleaseOpenFileHandle(struct vnode *vp, Bool *closed);
-Bool HgfsShouldCloseOpenFileHandle(struct vnode *vp);
-Bool HgfsHandleIsSet(struct vnode *vp);
+int HgfsReleaseOpenFileHandle(struct vnode *vp, HgfsHandle *handleToClose);
+int HgfsCheckAndReferenceHandle(struct vnode *vp, int requestedOpenMode);
 int HgfsHandleIncrementRefCount(struct vnode *vp);
 
-/* Mode get/set/clear functions */
-int HgfsSetOpenFileMode(struct vnode *vp, HgfsMode mode);
-int HgfsGetOpenFileMode(struct vnode *vp, HgfsMode *outMode);
-int HgfsClearOpenFileMode(struct vnode *);
-
-/* HgfsFile locking functions */
-int HgfsFileLock(struct vnode *vp, HgfsLockType type);
-int HgfsFileLockOfp(HgfsOpenFile *ofp, HgfsLockType type);
-int HgfsFileUnlock(struct vnode *vp, HgfsLockType type);
-int HgfsFileUnlockOfp(HgfsOpenFile *ofp, HgfsLockType type);
-
 #endif /* _STATE_H_ */
diff --git a/open-vm-tools/modules/freebsd/vmhgfs/transport.c b/open-vm-tools/modules/freebsd/vmhgfs/transport.c
new file mode 100644 (file)
index 0000000..cc09e34
--- /dev/null
@@ -0,0 +1,389 @@
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ *********************************************************/
+
+/*
+ * transport.c --
+ *
+ * Functions that prepare HGFS packages and send them to the host.
+ * Implementations are shared between both OS X and FreeBSD.
+ */
+
+#include <sys/param.h>          // for everything
+#include <sys/vnode.h>          // for struct vnode
+#include <sys/dirent.h>         // for struct dirent
+
+#include "fsutil.h"
+#include "debug.h"
+#include "transport.h"
+#include "cpName.h"
+#include "os.h"
+
+#define HGFS_FILE_OPEN_MASK (HGFS_OPEN_VALID_MODE | \
+                             HGFS_OPEN_VALID_FLAGS | \
+                             HGFS_OPEN_VALID_SPECIAL_PERMS | \
+                             HGFS_OPEN_VALID_OWNER_PERMS | \
+                             HGFS_OPEN_VALID_GROUP_PERMS | \
+                             HGFS_OPEN_VALID_OTHER_PERMS | \
+                             HGFS_OPEN_VALID_FILE_NAME)
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsSendOpenDirRequest --
+ *
+ *       Sends a SEARCH_OPEN request to the Hgfs server.
+ *
+ * Results:
+ *      Returns zero on success and an error code on error.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsSendOpenDirRequest(HgfsSuperInfo *sip,   // IN: Superinfo pointer
+                       char *fullPath,       // IN: Full path for the file
+                       uint32 fullPathLen,   // IN: Length of the full path
+                       HgfsHandle *handle)   // OUT: HGFS handle for the opened file
+{
+   HgfsKReqHandle req;
+   HgfsRequest *requestHeader;
+   HgfsReply *replyHeader;
+   HgfsRequestSearchOpenV3 *request;
+   HgfsReplySearchOpenV3 *reply;
+   uint32 reqSize;
+   uint32 repSize;
+   uint32 reqBufferSize;
+   int ret;
+
+   req = HgfsKReq_AllocateRequest(sip->reqs);
+   if (!req) {
+      return ENOMEM;
+   }
+
+   /* Set the correct header values */
+   requestHeader = (HgfsRequest *)HgfsKReq_GetPayload(req);
+   request = (HgfsRequestSearchOpenV3 *)HGFS_REQ_GET_PAYLOAD_V3(requestHeader);
+
+   HGFS_INIT_REQUEST_HDR(requestHeader, req, HGFS_OP_SEARCH_OPEN_V3);
+
+   request->dirName.flags = 0;
+   request->dirName.caseType = HGFS_FILE_NAME_CASE_SENSITIVE;
+   request->dirName.fid = HGFS_INVALID_HANDLE;
+   request->reserved = 0;
+
+   reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request);
+   reqBufferSize = HGFS_NAME_BUFFER_SIZET(reqSize);
+
+   /*
+    * Convert an input string to utf8 precomposed form, convert it to
+    * the cross platform name format and finally unescape any illegal
+    * filesystem characters.
+    */
+   ret = HgfsNameToWireEncoding(fullPath, fullPathLen + 1,
+                                request->dirName.name,
+                                reqBufferSize);
+
+   if (ret < 0) {
+      DEBUG(VM_DEBUG_FAIL, "Could not encode to wire format");
+      HgfsKReq_ReleaseRequest(sip->reqs, req);
+      return -ret;
+   }
+
+   request->dirName.length = ret;
+   reqSize += ret;
+
+   HgfsKReq_SetPayloadSize(req, reqSize);
+
+   /* Submit the request to the Hgfs server */
+   ret = HgfsSubmitRequest(sip, req);
+   if (ret == 0) {
+
+      /* Our reply is in the request packet */
+      replyHeader = (HgfsReply *)HgfsKReq_GetPayload(req);
+      reply = (HgfsReplySearchOpenV3 *)HGFS_REP_GET_PAYLOAD_V3(replyHeader);
+
+      repSize = HGFS_REP_PAYLOAD_SIZE_V3(reply);
+
+      ret = HgfsGetStatus(req, repSize);
+      if (ret == 0) {
+         *handle = reply->search;
+      } else {
+         DEBUG(VM_DEBUG_FAIL, "Error encountered with ret = %d\n", ret);
+      }
+
+      DEBUG(VM_DEBUG_COMM, "received reply for ID %d\n", replyHeader->id);
+      DEBUG(VM_DEBUG_COMM, " status: %d (see hgfsProto.h)\n", replyHeader->status);
+      DEBUG(VM_DEBUG_COMM, " handle: %d\n", reply->search);
+
+      HgfsKReq_ReleaseRequest(sip->reqs, req);
+   }
+   return ret;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsSendOpenRequest --
+ *
+ *      Sends an OPEN request to the Hgfs server to open an existing file.
+ *
+ * Results:
+ *      Returns zero on success and an error code on error.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsSendOpenRequest(HgfsSuperInfo *sip,   // IN: Superinfo pointer
+                    int openMode,         // IN: HGFS mode of open
+                    int openFlags,        // IN: HGFS open flags
+                    int permissions,      // IN: Permissions of open (only when creating)
+                    char *fullPath,       // IN: Full path for the file
+                    uint32 fullPathLen,   // IN: Length of the full path
+                    HgfsHandle *handle)   // OUT: HGFS handle for the opened file
+{
+   HgfsKReqHandle req;
+   HgfsRequest *requestHeader;
+   HgfsReply *replyHeader;
+   HgfsRequestOpenV3 *request;
+   HgfsReplyOpenV3 *reply;
+   int ret;
+   uint32 reqSize;
+   uint32 repSize;
+   uint32 reqBufferSize;
+
+   DEBUG(VM_DEBUG_LOG, "Trace enter.\n");
+   req = HgfsKReq_AllocateRequest(sip->reqs);
+   if (!req) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsKReq_AllocateRequest failed.\n");
+      return ENOMEM;
+   }
+
+   requestHeader = (HgfsRequest *)HgfsKReq_GetPayload(req);
+   request = (HgfsRequestOpenV3 *)HGFS_REQ_GET_PAYLOAD_V3(requestHeader);
+
+   HGFS_INIT_REQUEST_HDR(requestHeader, req, HGFS_OP_OPEN_V3);
+
+   request->mask = HGFS_FILE_OPEN_MASK;
+   request->reserved1 = 0;
+   request->reserved2 = 0;
+
+   reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request);
+   reqBufferSize = HGFS_NAME_BUFFER_SIZET(reqSize);
+   request->mode = openMode;
+   request->flags = openFlags;
+   DEBUG(VM_DEBUG_COMM, "open flags are %x\n", request->flags);
+
+   request->specialPerms = (permissions & (S_ISUID | S_ISGID | S_ISVTX)) >>
+                              HGFS_ATTR_SPECIAL_PERM_SHIFT;
+   request->ownerPerms = (permissions & S_IRWXU) >> HGFS_ATTR_OWNER_PERM_SHIFT;
+   request->groupPerms = (permissions & S_IRWXG) >> HGFS_ATTR_GROUP_PERM_SHIFT;
+   request->otherPerms = permissions & S_IRWXO;
+   DEBUG(VM_DEBUG_COMM, "permissions are %o\n", permissions);
+
+   request->fileName.flags = 0;
+   request->fileName.caseType = HGFS_FILE_NAME_CASE_SENSITIVE;
+   request->fileName.fid = HGFS_INVALID_HANDLE;
+
+   /*
+    * Convert an input string to utf8 precomposed form, convert it to
+    * the cross platform name format and finally unescape any illegal
+    * filesystem characters.
+    */
+   ret = HgfsNameToWireEncoding(fullPath, fullPathLen + 1,
+                                request->fileName.name,
+                                reqBufferSize);
+
+   if (ret < 0) {
+      DEBUG(VM_DEBUG_FAIL, "Could not encode to wire format");
+      ret = -ret;
+      goto out;
+   }
+   request->fileName.length = ret;
+   reqSize += ret;
+
+   /* Packet size includes the request and its payload. */
+   HgfsKReq_SetPayloadSize(req, reqSize);
+
+   ret = HgfsSubmitRequest(sip, req);
+   if (ret) {
+      /* HgfsSubmitRequest will destroy the request if necessary. */
+      DEBUG(VM_DEBUG_FAIL, "could not submit request.\n");
+      req = NULL; // Request has been deallocated by SubmitRequest
+   } else {
+      replyHeader = (HgfsReply *)HgfsKReq_GetPayload(req);
+      reply = (HgfsReplyOpenV3 *)HGFS_REP_GET_PAYLOAD_V3(replyHeader);
+      repSize = HGFS_REP_PAYLOAD_SIZE_V3(reply);
+      ret = HgfsGetStatus(req, repSize);
+      if (ret == 0) {
+         *handle = reply->file;
+      }
+   }
+out:
+   if (req != NULL) {
+      HgfsKReq_ReleaseRequest(sip->reqs, req);
+   }
+   return ret;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsCloseServerDirHandle --
+ *
+ *      Prepares close handle request and sends it to the HGFS server
+ *
+ * Results:
+ *      Returns zero on success and an error code on error.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsCloseServerDirHandle(HgfsSuperInfo *sip,         // IN: Superinfo pointer
+                         HgfsHandle handle)          // IN: Handle to close
+{
+   HgfsKReqHandle req;
+   HgfsRequest *requestHeader;
+   HgfsReply *replyHeader;
+   HgfsRequestSearchCloseV3 *request;
+   HgfsReplySearchCloseV3 *reply;
+   uint32 reqSize;
+   uint32 repSize;
+   int ret;
+
+   req = HgfsKReq_AllocateRequest(sip->reqs);
+   if (!req) {
+      return ENOMEM;
+   }
+
+   /*
+    * Prepare the request structure.  Of note here is that the request is
+    * always the same size so we just set the packetSize to that.
+    */
+   requestHeader = (HgfsRequest *)HgfsKReq_GetPayload(req);
+   request = (HgfsRequestSearchCloseV3 *)HGFS_REQ_GET_PAYLOAD_V3(requestHeader);
+
+   HGFS_INIT_REQUEST_HDR(requestHeader, req, HGFS_OP_SEARCH_CLOSE_V3);
+
+   request->search = handle;
+   request->reserved = 0;
+   reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request);
+
+   HgfsKReq_SetPayloadSize(req, reqSize);
+
+   /* Submit the request to the Hgfs server */
+   ret = HgfsSubmitRequest(sip, req);
+   if (ret == 0) {
+      replyHeader = (HgfsReply *)HgfsKReq_GetPayload(req);
+      repSize = HGFS_REP_PAYLOAD_SIZE_V3(reply);
+      DEBUG(VM_DEBUG_COMM, "received reply for ID %d\n", replyHeader->id);
+      DEBUG(VM_DEBUG_COMM, " status: %d (see hgfsProto.h)\n", replyHeader->status);
+
+      ret = HgfsGetStatus(req, repSize);
+      if (ret) {
+         DEBUG(VM_DEBUG_FAIL, "Error encountered with ret = %d\n", ret);
+         if (ret != EPROTO) {
+            ret = EFAULT;
+         }
+      }
+
+      HgfsKReq_ReleaseRequest(sip->reqs, req);
+   }
+   return ret;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsCloseServerFileHandle --
+ *
+ *      Prepares close handle request and sends it to the HGFS server
+ *
+ * Results:
+ *      Returns zero on success and an error code on error.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsCloseServerFileHandle(HgfsSuperInfo *sip,         // IN: Superinfo pointer
+                          HgfsHandle handle)          // IN: Handle to close
+{
+   HgfsKReqHandle req;
+   HgfsRequest *requestHeader;
+   HgfsReply *replyHeader;
+   HgfsRequestCloseV3 *request;
+   HgfsReplyCloseV3 *reply;
+   uint32 reqSize;
+   uint32 repSize;
+   int ret;
+
+   req = HgfsKReq_AllocateRequest(sip->reqs);
+   if (!req) {
+      return ENOMEM;
+   }
+
+   /*
+    * Prepare the request structure.  Of note here is that the request is
+    * always the same size so we just set the packetSize to that.
+    */
+   requestHeader = (HgfsRequest *)HgfsKReq_GetPayload(req);
+   request = (HgfsRequestCloseV3 *)HGFS_REQ_GET_PAYLOAD_V3(requestHeader);
+
+   HGFS_INIT_REQUEST_HDR(requestHeader, req, HGFS_OP_CLOSE_V3);
+
+   request->file = handle;
+   request->reserved = 0;
+   reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request);
+
+   HgfsKReq_SetPayloadSize(req, reqSize);
+
+   /* Submit the request to the Hgfs server */
+   ret = HgfsSubmitRequest(sip, req);
+   if (ret == 0) {
+      replyHeader = (HgfsReply *)HgfsKReq_GetPayload(req);
+      repSize = HGFS_REP_PAYLOAD_SIZE_V3(reply);
+      DEBUG(VM_DEBUG_COMM, "received reply for ID %d\n", replyHeader->id);
+      DEBUG(VM_DEBUG_COMM, " status: %d (see hgfsProto.h)\n", replyHeader->status);
+
+      ret = HgfsGetStatus(req, repSize);
+      if (ret) {
+         DEBUG(VM_DEBUG_FAIL, "Error encountered with ret = %d\n", ret);
+         if (ret != EPROTO) {
+            ret = EFAULT;
+         }
+      }
+
+      HgfsKReq_ReleaseRequest(sip->reqs, req);
+   }
+   return ret;
+}
diff --git a/open-vm-tools/modules/freebsd/vmhgfs/transport.h b/open-vm-tools/modules/freebsd/vmhgfs/transport.h
new file mode 100644 (file)
index 0000000..31ac7ba
--- /dev/null
@@ -0,0 +1,39 @@
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ *********************************************************/
+
+/*
+ * transport.h --
+ *
+ * Communication with HGFS server.
+ */
+
+#ifndef _HGFS_TRANSPORT_COMMON_H_
+#define _HGFS_TRANSPORT_COMMON_H_
+
+#include "hgfs_kernel.h"
+
+/* Internal transport functions used by both FreeBSD and Mac OS */
+int HgfsSendOpenRequest(HgfsSuperInfo *sip, int openMode, int openFlags,
+                        int permissions, char *fullPath,
+                        uint32 fullPathLen, HgfsHandle *handle);
+int HgfsSendOpenDirRequest(HgfsSuperInfo *sip, char *fullPath,
+                           uint32 fullPathLen, HgfsHandle *handle);
+int HgfsCloseServerDirHandle(HgfsSuperInfo *sip, HgfsHandle handleToClose);
+int HgfsCloseServerFileHandle(HgfsSuperInfo *sip, HgfsHandle handleToClose);
+
+#endif // _HGFS_TRANSPORT_COMMON_H_
index c307fa7b75cd6cea087bd9599c41914563dfbfce..c8ac82d2c3bbf42050fdc1a53ee3dee2f012c592 100644 (file)
     (!defined KERNEL && !defined _KERNEL && !defined VMKERNEL && !defined __KERNEL__)
 #   include <stddef.h>
 #else
-// XXX the __cplusplus one matches that of VC++, to prevent redefinition warning
+// XXX the _WIN32 one matches that of VC++, to prevent redefinition warning
 // XXX the other one matches that of gcc3.3.3/glibc2.2.4 to prevent redefinition warnings
 #ifndef offsetof
-#ifdef __cplusplus
+#ifdef _WIN32
 #define offsetof(s,m)   (size_t)&(((s *)0)->m)
 #else
 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
index 983c7841b2b9991855bfb43658ff0f9d4442ac58..a958b58aeeb15fe911e9612f90592d2898ef5548 100644 (file)
@@ -707,12 +707,6 @@ struct vop_inactive_args {
 };
 */
 {
-   /*
-    * On FreeBSD we can always call vgone because there is no possibility that the
-    * vnode is being shared by more than one open file.
-    */
-   vgone(ap->a_vp);
-
    return 0;
 }
 
@@ -746,7 +740,7 @@ struct vop_reclaim_args {
 
    HgfsSuperInfo *sip = HGFS_VP_TO_SIP(vp);
 
-   HgfsVnodePut(vp, &sip->fileHashTable);
+   HgfsReleaseVnodeContext(vp, &sip->fileHashTable);
    vp->v_data = NULL;
 
    return 0;
index cecd33f5058e7bf84c9741eef61f3befc78c08b0..072359a3fe61a753f87d64b8dd4146856f5b3456 100644 (file)
@@ -17,7 +17,7 @@
  *********************************************************/
 
 /*
- * vnopscommon.h --
+ * vnopscommon.c --
  *
  * Common VFS vnop implementations that are shared between both OS X and FreeBSD.
  */
@@ -29,6 +29,7 @@
 #include "fsutil.h"
 #include "debug.h"
 #include "vnopscommon.h"
+#include "transport.h"
 #include "cpName.h"
 #include "os.h"
 
@@ -56,14 +57,6 @@ static int HgfsQueryAttrInt(const char *path, HgfsHandle handle, HgfsSuperInfo *
 static int HgfsDoGetattrByHandle(HgfsHandle handle, HgfsSuperInfo *sip, HgfsAttrV2 *hgfsAttrV2);
 #endif
 
-#define HGFS_FILE_OPEN_MASK (HGFS_OPEN_VALID_MODE | \
-                             HGFS_OPEN_VALID_FLAGS | \
-                             HGFS_OPEN_VALID_SPECIAL_PERMS | \
-                             HGFS_OPEN_VALID_OWNER_PERMS | \
-                             HGFS_OPEN_VALID_GROUP_PERMS | \
-                             HGFS_OPEN_VALID_OTHER_PERMS | \
-                             HGFS_OPEN_VALID_FILE_NAME)
-
 #define HGFS_CREATE_DIR_MASK (HGFS_CREATE_DIR_VALID_FILE_NAME | \
                               HGFS_CREATE_DIR_VALID_SPECIAL_PERMS | \
                               HGFS_CREATE_DIR_VALID_OWNER_PERMS | \
@@ -109,6 +102,7 @@ HgfsRenameInt(struct vnode *fvp,          // IN: "from" file
    uint32 repSize;
    int ret;
 
+   DEBUG(VM_DEBUG_LOG, "Trace enter.\n");
    /* No cross-device renaming. */
    if (HGFS_VP_TO_MP(fvp) != HGFS_VP_TO_MP(tdvp)) {
       return EXDEV;
@@ -271,6 +265,7 @@ HgfsReaddirInt(struct vnode *vp, // IN    : Directory vnode to get entries from.
    char *fullName = NULL;       /* Hashed to generate inode number */
    int ret = 0;
 
+   DEBUG(VM_DEBUG_LOG, "Enter %s.\n",  HGFS_VP_TO_FILENAME(vp));
    /* uio_offset is a signed quantity. */
    if (HGFS_UIOP_TO_OFFSET(uiop) < 0) {
       DEBUG(VM_DEBUG_FAIL, "fed negative offset.\n");
@@ -427,7 +422,7 @@ out:
    if (fullName != NULL) {
       os_free(fullName, MAXPATHLEN);
    }
-   DEBUG(VM_DEBUG_ENTRY, "exiting.\n");
+   DEBUG(VM_DEBUG_ENTRY, "exiting %s.\n", HGFS_VP_TO_FILENAME(vp));
    return ret;
 }
 
@@ -457,6 +452,7 @@ HgfsGetattrInt(struct vnode *vp,      // IN : vnode of the file
    HgfsAttrV2 hgfsAttrV2;
    int ret = 0;
 
+   DEBUG(VM_DEBUG_LOG, "Enter %s.\n",  HGFS_VP_TO_FILENAME(vp));
    /* XXX It would be nice to do a GetattrByHandle when possible here. */
    ret = HgfsDoGetattrByName(HGFS_VP_TO_FILENAME(vp), sip, &hgfsAttrV2);
 
@@ -469,6 +465,7 @@ HgfsGetattrInt(struct vnode *vp,      // IN : vnode of the file
       HgfsAttrToBSD(vp, &hgfsAttrV2, vap);
    }
 
+   DEBUG(VM_DEBUG_LOG, "Exit %s.\n",  HGFS_VP_TO_FILENAME(vp));
    return ret;
 }
 
@@ -507,6 +504,7 @@ HgfsSetattrInt(struct vnode *vp,     // IN : vnode of the file
    uint32 fullPathLen;
    int ret;
 
+   DEBUG(VM_DEBUG_LOG, "Enter %s.\n",  HGFS_VP_TO_FILENAME(vp));
    ASSERT(vp);
    ASSERT(vap);
 
@@ -589,6 +587,7 @@ destroyOut:
    DEBUG(VM_DEBUG_DONE, "done with ret = %d\n", ret);
    HgfsKReq_ReleaseRequest(sip->reqs, req);
 out:
+   DEBUG(VM_DEBUG_LOG, "Exit %s.\n",  HGFS_VP_TO_FILENAME(vp));
    return ret;
 }
 
@@ -622,6 +621,7 @@ HgfsRmdirInt(struct vnode *dvp,          // IN: parent directory
    int ret = 0;
 
    HgfsSuperInfo *sip = HGFS_VP_TO_SIP(dvp);
+   DEBUG(VM_DEBUG_LOG, "Enter %s.\n",  HGFS_VP_TO_FILENAME(vp));
 
    DEBUG(VM_DEBUG_ENTRY, "HgfsRmdir().\n");
 
@@ -631,6 +631,7 @@ HgfsRmdirInt(struct vnode *dvp,          // IN: parent directory
          (HGFS_VP_TO_FP(vp)) ? HGFS_VP_TO_FILENAME(vp) : "vp->v_data null");
 
    ret = HgfsDelete(sip, HGFS_VP_TO_FILENAME(vp), HGFS_OP_DELETE_DIR_V3);
+   DEBUG(VM_DEBUG_LOG, "Exit %s.\n",  HGFS_VP_TO_FILENAME(vp));
    return ret;
 }
 
@@ -662,6 +663,7 @@ int HgfsRemoveInt(struct vnode *vp) // IN: Vnode to delete
 
    HgfsSuperInfo *sip = HGFS_VP_TO_SIP(vp);
 
+   DEBUG(VM_DEBUG_LOG, "Enter %s.\n",  HGFS_VP_TO_FILENAME(vp));
    DEBUG(VM_DEBUG_ENTRY, "HgfsRemove().\n");
 
    /* Removing directories is a no-no; save that for VNOP_RMDIR. */
@@ -674,6 +676,7 @@ int HgfsRemoveInt(struct vnode *vp) // IN: Vnode to delete
    ret = HgfsDelete(sip, HGFS_VP_TO_FILENAME(vp), HGFS_OP_DELETE_FILE_V3);
 
 out:
+   DEBUG(VM_DEBUG_LOG, "Exit %s.\n",  HGFS_VP_TO_FILENAME(vp));
    return ret;
 }
 
@@ -706,6 +709,7 @@ HgfsCloseInt(struct vnode *vp, // IN: Vnode to close.
 {
    int ret = 0;
    HgfsSuperInfo *sip = HGFS_VP_TO_SIP(vp);
+   DEBUG(VM_DEBUG_LOG, "Enter %s.\n",  HGFS_VP_TO_FILENAME(vp));
 
    /*
     * If we are closing a directory we need to send a SEARCH_CLOSE request,
@@ -728,6 +732,7 @@ HgfsCloseInt(struct vnode *vp, // IN: Vnode to close.
       ret = EINVAL;
       break;
    }
+   DEBUG(VM_DEBUG_LOG, "Exit %s.\n",  HGFS_VP_TO_FILENAME(vp));
    return 0;
 }
 
@@ -761,6 +766,7 @@ HgfsOpenInt(struct vnode *vp, // IN: Vnode to open.
            int mode)         // IN: Mode of vnode being opened.
 {
    HgfsSuperInfo *sip = HGFS_VP_TO_SIP(vp);
+   DEBUG(VM_DEBUG_LOG, "Enter %s.\n",  HGFS_VP_TO_FILENAME(vp));
 
    switch(HGFS_VP_TO_VTYPE(vp)) {
    case VDIR:
@@ -769,17 +775,14 @@ HgfsOpenInt(struct vnode *vp, // IN: Vnode to open.
 
    case VREG:
       {
-         HgfsMode hmode = 0;
-
          /*
-          * If HgfsCreate() was called prior to this, this fills in the mode we
-          * saved there.  It's okay if this fails since often HgfsCreate()
-          * won't have been called.
+          * If HgfsCreate() was called prior to this then is would set permissions
+          * in HgfsFile that we need to pass to HgfsFileOpen.
+          * If HgfsCreate has not been called then file already exists and permissions
+          * are ignored by HgfsFileOpen.
           */
-         HgfsGetOpenFileMode(vp, &hmode);
-
          DEBUG(VM_DEBUG_COMM, "opening a file with flag %x\n", mode);
-         return HgfsFileOpen(sip, vp, mode, hmode);
+         return HgfsFileOpen(sip, vp, mode, HGFS_VP_TO_PERMISSIONS(vp));
       }
 
    default:
@@ -788,7 +791,8 @@ HgfsOpenInt(struct vnode *vp, // IN: Vnode to open.
       return EINVAL;
    }
 
-    return 0;
+   DEBUG(VM_DEBUG_LOG, "Exit %s.\n",  HGFS_VP_TO_FILENAME(vp));
+   return 0;
 }
 
 
@@ -825,6 +829,8 @@ HgfsLookupInt(struct vnode *dvp,         // IN : directory vnode
    int ret = 0;
    int len = 0;
 
+   DEBUG(VM_DEBUG_LOG, "Enter %s.\n",  HGFS_VP_TO_FILENAME(dvp));
+
    ASSERT(dvp);
    ASSERT(vpp);
    ASSERT(cnp);
@@ -833,6 +839,31 @@ HgfsLookupInt(struct vnode *dvp,         // IN : directory vnode
          HGFS_VP_TO_FILENAME_LENGTH(dvp), HGFS_VP_TO_FILENAME(dvp),
          (int)cnp->cn_namelen, cnp->cn_nameptr);
 
+   if (cnp->cn_flags & ISDOTDOT) {
+      HgfsFile *fp = HGFS_VP_TO_FP(dvp);
+      ASSERT(fp);
+      if (fp->parent == NULL) {
+         return EIO; // dvp is root directory
+      } else {
+#if defined(__FreeBSD__)
+         vref(fp->parent);
+#else
+         vnode_get(fp->parent);
+#endif
+         *vpp = fp->parent;
+         return 0;
+      }
+   }
+   if (cnp->cn_namelen == 1 && *cnp->cn_nameptr == '.') {
+#if defined(__FreeBSD__)
+      vref(dvp);
+#else
+      vnode_get(dvp);
+#endif
+      *vpp = dvp;
+      return 0;
+   }
+   
    /*
     * Get pointer to the superinfo.  If the device is not attached,
     * hgfsInstance will not be valid and we immediately return an error.
@@ -897,12 +928,15 @@ HgfsLookupInt(struct vnode *dvp,         // IN : directory vnode
       goto out;
    }
 
-   ret = HgfsVnodeGet(vpp,                     // Location to write vnode's address
-                     sip,                     // Superinfo
-                     HGFS_VP_TO_MP(dvp),      // VFS for our filesystem
-                     path,                    // Full name of the file
-                     attrV2.type,             // Type of file
-                     &sip->fileHashTable);    // File hash table
+   ret = HgfsVnodeGet(vpp,           // Location to write vnode's address
+                      dvp,                     // Parent vnode
+                      sip,                     // Superinfo
+                      HGFS_VP_TO_MP(dvp),      // VFS for our filesystem
+                      path,                    // Full name of the file
+                      attrV2.type,             // Type of file
+                      &sip->fileHashTable,     // File hash table
+                      FALSE,                   // Not a new file creation
+                      0);                      // No permissions - not a new file
 
    if (ret) {
       DEBUG(VM_DEBUG_FAIL, "couldn't create vnode for \"%s\".\n", path);
@@ -923,6 +957,7 @@ out:
    if (path != NULL) {
       os_free(path, MAXPATHLEN);
    }
+   DEBUG(VM_DEBUG_LOG, "Exit %s.\n",  HGFS_VP_TO_FILENAME(dvp));
    return ret;
 }
 
@@ -959,6 +994,8 @@ int HgfsCreateInt(struct vnode *dvp,         // IN : Directory vnode
    char *fullname = NULL;       // allocated from M_TEMP; free when done.
    int ret = 0;
 
+   DEBUG(VM_DEBUG_LOG, "Enter %s.\n",  HGFS_VP_TO_FILENAME(dvp));
+
    if (*vpp != NULL) {
       DEBUG(VM_DEBUG_ALWAYS, "vpp (%p) not null\n", vpp);
       return EEXIST;
@@ -980,29 +1017,21 @@ int HgfsCreateInt(struct vnode *dvp,         // IN : Directory vnode
                           fullname,                  // Buffer to write full name
                           MAXPATHLEN);               // Size of this buffer
 
-   if (ret < 0) {
+   if (ret >= 0) {
+      /* Create the vnode for this file. */
+      ret = HgfsVnodeGet(vpp, dvp, sip, HGFS_VP_TO_MP(dvp), fullname,
+                         HGFS_FILE_TYPE_REGULAR, &sip->fileHashTable, FALSE, mode);
+      /* HgfsVnodeGet() guarantees this. */
+      ASSERT(ret != 0 || *vpp);
+   } else {
       DEBUG(VM_DEBUG_FAIL, "couldn't create full path name.\n");
       ret = ENAMETOOLONG;
-      goto out;
-   }
-
-   /* Create the vnode for this file. */
-   ret = HgfsVnodeGet(vpp, sip, HGFS_VP_TO_MP(dvp), fullname,
-                      HGFS_FILE_TYPE_REGULAR, &sip->fileHashTable);
-   if (ret) {
-      goto out;
    }
 
-   /* HgfsVnodeGet() guarantees this. */
-   ASSERT(*vpp);
-
-   /* Save the mode so when open is called we can reference it. */
-   HgfsSetOpenFileMode(*vpp, mode);
-
-out:
    if (fullname != NULL) {
       os_free(fullname, MAXPATHLEN);
    }
+   DEBUG(VM_DEBUG_LOG, "Exit %s.\n",  HGFS_VP_TO_FILENAME(dvp));
    return ret;
 }
 
@@ -1041,7 +1070,7 @@ HgfsReadInt(struct vnode *vp, // IN    : Vnode to read from
    uint64_t offset;
    int ret;
 
-   DEBUG(VM_DEBUG_ENTRY, "entry.\n");
+   DEBUG(VM_DEBUG_ENTRY, "entry %s.\n",  HGFS_VP_TO_FILENAME(vp));
 
    /* We can't read from directories, that's what readdir() is for. */
    if (HGFS_VP_TO_VTYPE(vp) == VDIR) {
@@ -1114,7 +1143,7 @@ HgfsReadInt(struct vnode *vp, // IN    : Vnode to read from
    } while (HGFS_UIOP_TO_RESID(uiop));
 
    /* We fulfilled the user's read request, so return success. */
-   DEBUG(VM_DEBUG_DONE, "done.\n");
+   DEBUG(VM_DEBUG_LOG, "Exit %s.\n",  HGFS_VP_TO_FILENAME(vp));
    return 0;
 }
 
@@ -1213,7 +1242,7 @@ HgfsWriteInt(struct vnode *vp, // IN    : the vnode of the file
    } while (HGFS_UIOP_TO_RESID(uiop));
 
    /* We have completed the user's write request, so return success. */
-   DEBUG(VM_DEBUG_DONE, "done.\n");
+   DEBUG(VM_DEBUG_LOG, "Exit %s.\n",  HGFS_VP_TO_FILENAME(vp));
 
    return 0;
 }
@@ -1349,8 +1378,8 @@ HgfsMkdirInt(struct vnode *dvp,         // IN : directory vnode
       goto destroyOut;
    }
 
-   ret = HgfsVnodeGet(vpp, sip, HGFS_VP_TO_MP(dvp), fullName,
-                      HGFS_FILE_TYPE_DIRECTORY, &sip->fileHashTable);
+   ret = HgfsVnodeGet(vpp, dvp, sip, HGFS_VP_TO_MP(dvp), fullName,
+                      HGFS_FILE_TYPE_DIRECTORY, &sip->fileHashTable, TRUE, mode);
    if (ret) {
       ret = EIO;
       goto destroyOut;
@@ -1365,6 +1394,7 @@ out:
    if (fullName != NULL) {
       os_free(fullName, MAXPATHLEN);
    }
+   DEBUG(VM_DEBUG_LOG, "Exit %s.\n",  HGFS_VP_TO_FILENAME(dvp));
    return ret;
 }
 
@@ -1391,152 +1421,48 @@ int
 HgfsDirOpen(HgfsSuperInfo *sip, // IN: Superinfo pointer
             struct vnode *vp)   // IN: Vnode of directory to open
 {
-   HgfsKReqHandle req;
-   HgfsRequest *requestHeader;
-   HgfsReply *replyHeader;
-   HgfsRequestSearchOpenV3 *request;
-   HgfsReplySearchOpenV3 *reply;
-   uint32 reqSize;
-   uint32 repSize;
-   uint32 reqBufferSize;
    char *fullPath;
    uint32 fullPathLen;
    int ret;
+   HgfsFile *fp;
+   HgfsHandle handle;
 
    ASSERT(sip);
    ASSERT(vp);
 
-   DEBUG(VM_DEBUG_ENTRY, "opening \"%s\"\n", HGFS_VP_TO_FILENAME(vp));
+   fp = HGFS_VP_TO_FP(vp);
+   ASSERT(fp);
 
-   if (HgfsHandleIsSet(vp)) {
-      /*
-       * We already have a handle. Idealy this would never happen, but it
-       * does on OS X when trying to open "." or ".." (because HgfsLookupInt
-       * is never called by the VFS layer in that specific case.). If that
-       * happens, then the "per-open-file" HgfsOpenFile associated with this
-       * vnode will now be shared between two separate opens. At the open
-       * level, there is no way to insert a new vnode so the exist handle
-       * is shared. Since this can only happen for directories and directory
-       * entries are read off of the server at the time of the
-       * HGFS_OP_SEARCH_OPEN in HgfsServerScandir, there is nothing to do
-       * here. The worst that could happen is that a process gets stale
-       * entries and there isn't really any way to avoid that.
-       * The root vnode directory handle is also shared on both FreeBSD and
-       * OS X.
-       */
-
-#if defined(__FreeBSD__)
-      /*
-       * XXX It looks like the FreeBSD open call asks for a shared vnode lock.
-       * It would be nice to allow handle sharing for the root vnode. However,
-       * until the following is answered, I'm going to leave the behavior as is
-       * (strict one vnode per open file) for FreeBSD until the implications of
-       * I have time to think through the behavior of two racing open calls (If this
-       * can really happen then the open call could try to acquire two handles and
-       * one would be lost (the HgfsSetOpenFileHandle call would fail) and never be
-       * closed. I don't think this can actually happen because each open syscall first
-       * calls namei and then lookup. I think the right solution is to make the open call
-       * send a close call on the handle if it cannot set the handle later on. This would
-       * make it so that its fine to share the root vnode and would protect us against
-       * future changes to how open is called by the FreeBSD kernel. Then again, this
-       * might be overkill.
-       * This does not happen on OS X becasue the macos function that called HgfsOpenInt
-       * first acquired a writer lock on the HgfsOpenFile.
-       */
-      return EIO;
-#endif
-
-      DEBUG(VM_DEBUG_LOG, "Not doing an open because we have a handle\n");
-      HgfsHandleIncrementRefCount(vp);
-      return 0;
-   }
-
-   req = HgfsKReq_AllocateRequest(sip->reqs);
-   if (!req) {
-          return ENOMEM;
-   }
-
-   /* Set the correct header values */
-   requestHeader = (HgfsRequest *)HgfsKReq_GetPayload(req);
-   request = (HgfsRequestSearchOpenV3 *)HGFS_REQ_GET_PAYLOAD_V3(requestHeader);
-
-   HGFS_INIT_REQUEST_HDR(requestHeader, req, HGFS_OP_SEARCH_OPEN_V3);
-
-   request->dirName.flags = 0;
-   request->dirName.caseType = HGFS_FILE_NAME_CASE_SENSITIVE;
-   request->dirName.fid = HGFS_INVALID_HANDLE;
-   request->reserved = 0;
-
-   reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request);
-   reqBufferSize = HGFS_NAME_BUFFER_SIZET(reqSize);
-
-   if (HGFS_IS_ROOT_VNODE(sip, vp)) {
-      fullPath = "";
-      fullPathLen = 0;
-   } else {
-      fullPath = HGFS_VP_TO_FILENAME(vp);
-      fullPathLen = HGFS_VP_TO_FILENAME_LENGTH(vp);
-   }
+   DEBUG(VM_DEBUG_ENTRY, "opening \"%s\"\n", HGFS_VP_TO_FILENAME(vp));
 
    /*
-    * Convert an input string to utf8 precomposed form, convert it to
-    * the cross platform name format and finally unescape any illegal
-    * filesystem characters.
+    *  If the directory is already opened then we are done.
+    *  There is no different open modes for directories thus the handle is compatible.
     */
-   ret = HgfsNameToWireEncoding(fullPath, fullPathLen + 1,
-                                request->dirName.name,
-                                reqBufferSize);
-
-   if (ret < 0) {
-      DEBUG(VM_DEBUG_FAIL, "Could not encode to wire format");
-      ret = -ret;
-      goto destroyOut;
-   }
-
-   request->dirName.length = ret;
-   reqSize += ret;
+   os_rw_lock_lock_exclusive(fp->handleLock);
+   ret = HgfsCheckAndReferenceHandle(vp, 0);
+   if (ret ==  ENOENT) {  // Handle is not set, need to get one from the host
 
-   HgfsKReq_SetPayloadSize(req, reqSize);
-
-   /* Submit the request to the Hgfs server */
-   ret = HgfsSubmitRequest(sip, req);
-   if (ret) {
-      /* HgfsSubmitRequest destroys the request if necessary */
-
-      goto out;
-   }
-
-   /* Our reply is in the request packet */
-   replyHeader = (HgfsReply *)HgfsKReq_GetPayload(req);
-   reply = (HgfsReplySearchOpenV3 *)HGFS_REP_GET_PAYLOAD_V3(replyHeader);
-
-   repSize = HGFS_REP_PAYLOAD_SIZE_V3(reply);
-
-   ret = HgfsGetStatus(req, repSize);
-   if (ret) {
-      DEBUG(VM_DEBUG_FAIL, "Error encountered with ret = %d\n", ret);
-      goto destroyOut;
-   }
-
-   DEBUG(VM_DEBUG_COMM, "received reply for ID %d\n", replyHeader->id);
-   DEBUG(VM_DEBUG_COMM, " status: %d (see hgfsProto.h)\n", replyHeader->status);
-   DEBUG(VM_DEBUG_COMM, " handle: %d\n", reply->search);
+      if (HGFS_IS_ROOT_VNODE(sip, vp)) {
+         fullPath = "";
+         fullPathLen = 0;
+      } else {
+         fullPath = HGFS_VP_TO_FILENAME(vp);
+         fullPathLen = HGFS_VP_TO_FILENAME_LENGTH(vp);
+      }
 
-   /* Set the search open handle for use in HgfsReaddir() */
-   ret = HgfsSetOpenFileHandle(vp, reply->search);
-   if (ret) {
-      ret = EINVAL;
-      goto destroyOut;
+      ret = HgfsSendOpenDirRequest(sip, fullPath, fullPathLen, &handle);
+      if (ret == 0) {
+         /*
+          * We successfully received a reply, so we need to save the handle in
+          * this file's HgfsOpenFile and return success.
+          */
+         HgfsSetOpenFileHandle(vp, handle, 0);
+      }
    }
+   os_rw_lock_unlock_exclusive(fp->handleLock);
 
-   ret = 0;     /* Return success */
-
-destroyOut:
-   /* Make sure we put the request back on the list */
-   HgfsKReq_ReleaseRequest(sip->reqs, req);
-
-out:
-   DEBUG(VM_DEBUG_DONE, "done\n");
+   DEBUG(VM_DEBUG_LOG, "Exit %s.\n",  HGFS_VP_TO_FILENAME(vp));
    return ret;
 }
 
@@ -1567,21 +1493,20 @@ HgfsFileOpen(HgfsSuperInfo *sip,        // IN: Superinfo pointer
              int flag,                  // IN: Flags of open
              int permissions)           // IN: Permissions of open (only when creating)
 {
-   HgfsKReqHandle req;
-   HgfsRequest *requestHeader;
-   HgfsReply *replyHeader;
-   HgfsRequestOpenV3 *request;
-   HgfsReplyOpenV3 *reply;
-   uint32 reqSize;
-   uint32 repSize;
-   uint32 reqBufferSize;
    char *fullPath = NULL;
    uint32 fullPathLen;
    int ret;
+   int openMode;
+   int openFlags;
+   HgfsHandle handle;
+   HgfsFile *fp;
 
    ASSERT(sip);
    ASSERT(vp);
 
+   fp = HGFS_VP_TO_FP(vp);
+   ASSERT(fp);
+
    DEBUG(VM_DEBUG_ENTRY, "opening \"%s\"\n", HGFS_VP_TO_FILENAME(vp));
 
    /*
@@ -1601,123 +1526,69 @@ HgfsFileOpen(HgfsSuperInfo *sip,        // IN: Superinfo pointer
       return EPERM;
    }
 
-   if (HgfsHandleIsSet(vp)) {
-      DEBUG(VM_DEBUG_FAIL, "Trying to share a file handle for an already open !file! handle\n");
-      return EIO;
-   }
-
-   req = HgfsKReq_AllocateRequest(sip->reqs);
-   if (!req) {
-      DEBUG(VM_DEBUG_FAIL, "HgfsKReq_AllocateRequest failed.\n");
-      return ENOMEM;
-   }
-
-   requestHeader = (HgfsRequest *)HgfsKReq_GetPayload(req);
-   request = (HgfsRequestOpenV3 *)HGFS_REQ_GET_PAYLOAD_V3(requestHeader);
-
-   HGFS_INIT_REQUEST_HDR(requestHeader, req, HGFS_OP_OPEN_V3);
-
-   request->mask = HGFS_FILE_OPEN_MASK;
-   request->reserved1 = 0;
-   request->reserved2 = 0;
-
-   reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request);
-   reqBufferSize = HGFS_NAME_BUFFER_SIZET(reqSize);
-
    /* Convert FreeBSD modes to Hgfs modes */
-   ret = HgfsGetOpenMode((uint32_t)flag);
-   if (ret < 0) {
+   openMode = HgfsGetOpenMode((uint32_t)flag);
+   if (openMode < 0) {
       DEBUG(VM_DEBUG_FAIL, "HgfsGetOpenMode failed.\n");
       ret = EINVAL;
-      goto destroyOut;
+      goto out;
    }
-
-   request->mode = ret;
-   DEBUG(VM_DEBUG_COMM, "open mode is %x\n", request->mode);
+   DEBUG(VM_DEBUG_COMM, "open mode is %x\n", openMode);
 
    /* Convert FreeBSD flags to Hgfs flags */
-   ret = HgfsGetOpenFlags((uint32_t)flag);
-   if (ret < 0) {
+   openFlags = HgfsGetOpenFlags((uint32_t)flag);
+   if (openFlags < 0) {
       DEBUG(VM_DEBUG_FAIL, "HgfsGetOpenFlags failed.\n");
       ret = EINVAL;
-      goto destroyOut;
+      goto out;
    }
 
-   request->flags = ret;
-   DEBUG(VM_DEBUG_COMM, "open flags are %x\n", request->flags);
-
-   request->specialPerms = (permissions & (S_ISUID | S_ISGID | S_ISVTX)) >>
-                              HGFS_ATTR_SPECIAL_PERM_SHIFT;
-   request->ownerPerms = (permissions & S_IRWXU) >> HGFS_ATTR_OWNER_PERM_SHIFT;
-   request->groupPerms = (permissions & S_IRWXG) >> HGFS_ATTR_GROUP_PERM_SHIFT;
-   request->otherPerms = permissions & S_IRWXO;
-
-   fullPath = HGFS_VP_TO_FILENAME(vp);
-   fullPathLen = HGFS_VP_TO_FILENAME_LENGTH(vp);
-
-   DEBUG(VM_DEBUG_COMM, "permissions are %o\n", permissions);
-
-   request->fileName.flags = 0;
-   request->fileName.caseType = HGFS_FILE_NAME_CASE_SENSITIVE;
-   request->fileName.fid = HGFS_INVALID_HANDLE;
-
+   os_rw_lock_lock_exclusive(fp->handleLock);
    /*
-    * Convert an input string to utf8 precomposed form, convert it to
-    * the cross platform name format and finally unescape any illegal
-    * filesystem characters.
+    *  If the file is already opened, verify that it is opened in a compatible mode.
+    *  If it is true then add reference to vnode and grant the access, otherwise
+    *  deny the access.
     */
-   ret = HgfsNameToWireEncoding(fullPath, fullPathLen + 1,
-                                request->fileName.name,
-                                reqBufferSize);
-
-   if (ret < 0) {
-      DEBUG(VM_DEBUG_FAIL, "Could not encode to wire format");
-      ret = -ret;
-      goto destroyOut;
-   }
-   request->fileName.length = ret;
-   reqSize += ret;
-
-   /* Packet size includes the request and its payload. */
-   HgfsKReq_SetPayloadSize(req, reqSize);
-
-   ret = HgfsSubmitRequest(sip, req);
-   if (ret) {
-      /* HgfsSubmitRequest will destroy the request if necessary. */
-      DEBUG(VM_DEBUG_FAIL, "could not submit request.\n");
-      goto out;
-   }
+   ret = HgfsCheckAndReferenceHandle(vp, openMode);
+   if (ret == ENOENT) {  // Handle is not set, need to get one from the host
 
-   replyHeader = (HgfsReply *)HgfsKReq_GetPayload(req);
-   reply = (HgfsReplyOpenV3 *)HGFS_REP_GET_PAYLOAD_V3(replyHeader);
+      int requestedMode = HGFS_OPEN_MODE_READ_WRITE;
+      fullPath = HGFS_VP_TO_FILENAME(vp);
+      fullPathLen = HGFS_VP_TO_FILENAME_LENGTH(vp);
 
-   repSize = HGFS_REP_PAYLOAD_SIZE_V3(reply);
+      /* First see if we can get the most permissive read/write open mode */
+      ret = HgfsSendOpenRequest(sip, requestedMode, openFlags,
+                                permissions, fullPath, fullPathLen, &handle);
+      if (ret) {
+         if (ret == EACCES && HGFS_OPEN_MODE_READ_WRITE != openMode) {
+           /*
+            * Failed to open in read/write open mode because of denied access.
+            * It means file's permissions do not allow opening for read/write.
+            * However caller does not need this mode and may be satisfied with
+            * less permissive mode.
+            * Try exact open mode now.
+            */
+           DEBUG(VM_DEBUG_FAIL, "RW mode failed, re-submitting original mode = %d.\n",
+                 ret);
+           requestedMode = openMode;
+           ret = HgfsSendOpenRequest(sip, requestedMode, openFlags,
+                                     permissions, fullPath, fullPathLen, &handle);
+         }
+      }
 
-   ret = HgfsGetStatus(req, repSize);
-   if (ret) {
-      DEBUG(VM_DEBUG_FAIL, "Error encountered with ret = %d.\n", ret);
-      goto destroyOut;
+      /*
+       * We successfully received a reply, so we need to save the handle in
+       * this file's HgfsOpenFile and return success.
+       */
+      if (ret == 0) {
+         HgfsSetOpenFileHandle(vp, handle, requestedMode);
+      }
    }
 
-   /*
-    * We successfully received a reply, so we need to save the handle in
-    * this file's HgfsOpenFile and return success.
-    */
-   ret = HgfsSetOpenFileHandle(vp, reply->file);
-   if (ret) {
-      DEBUG(VM_DEBUG_FAIL, "couldn't assign handle %d (%s)\n",
-            reply->file, HGFS_VP_TO_FILENAME(vp));
-      ret = EINVAL;
-      goto destroyOut;
-   }
-
-   ret = 0;
-
-destroyOut:
-   HgfsKReq_ReleaseRequest(sip->reqs, req);
+   os_rw_lock_unlock_exclusive(fp->handleLock);
 
 out:
-   DEBUG(VM_DEBUG_DONE, "returning %d\n", ret);
+   DEBUG(VM_DEBUG_LOG, "Exit %s.\n",  HGFS_VP_TO_FILENAME(vp));
    return ret;
 }
 
@@ -1744,15 +1615,8 @@ int
 HgfsDirClose(HgfsSuperInfo *sip,        // IN: Superinfo pointer
              struct vnode *vp)          // IN: Vnode of directory to close
 {
-   HgfsKReqHandle req;
-   HgfsRequest *requestHeader;
-   HgfsReply *replyHeader;
-   HgfsRequestSearchCloseV3 *request;
-   HgfsReplySearchCloseV3 *reply;
-   uint32 reqSize;
-   uint32 repSize;
-   int ret;
-   Bool closed;
+   int ret = 0;
+   HgfsHandle handleToClose;
 
    ASSERT(sip);
    ASSERT(vp);
@@ -1760,85 +1624,13 @@ HgfsDirClose(HgfsSuperInfo *sip,        // IN: Superinfo pointer
    DEBUG(VM_DEBUG_ENTRY, "closing \"%s\"\n", HGFS_VP_TO_FILENAME(vp));
 
    /*
-    * Check to see if we should close the file handle ( which will happen when
-    * the reference count of the current handle is 1 and will become 0 after
-    * this close.
+    * Check to see if we should close the file handle on the host ( which happen when
+    * the reference count of the current handle become 0.
     */
-   if (!HgfsShouldCloseOpenFileHandle(vp)) {
-      ret = HgfsReleaseOpenFileHandle(vp, &closed);
-      if (ret || (closed == TRUE)) {
-         DEBUG(VM_DEBUG_FAIL, "Dirclose\n");
-        return EINVAL;
-      }
-      return 0;
-   }
-
-   req = HgfsKReq_AllocateRequest(sip->reqs);
-   if (!req) {
-      return ENOMEM;
+   if (HgfsReleaseOpenFileHandle(vp, &handleToClose) == 0) {
+      ret = HgfsCloseServerDirHandle(sip, handleToClose);
    }
-
-   /*
-    * Prepare the request structure.  Of note here is that the request is
-    * always the same size so we just set the packetSize to that.
-    */
-   requestHeader = (HgfsRequest *)HgfsKReq_GetPayload(req);
-   request = (HgfsRequestSearchCloseV3 *)HGFS_REQ_GET_PAYLOAD_V3(requestHeader);
-
-   HGFS_INIT_REQUEST_HDR(requestHeader, req, HGFS_OP_SEARCH_CLOSE_V3);
-
-   request->reserved = 0;
-   reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request);
-
-   /* Get this open file's handle, since that is what we want to close. */
-   ret = HgfsGetOpenFileHandle(vp, &request->search);
-   if (ret) {
-      DEBUG(VM_DEBUG_FAIL, "couldn't get handle for %s\n",
-            HGFS_VP_TO_FILENAME(vp));
-      ret = EINVAL;
-      goto destroyOut;
-   }
-
-   HgfsKReq_SetPayloadSize(req, reqSize);
-
-   /* Submit the request to the Hgfs server */
-   ret = HgfsSubmitRequest(sip, req);
-   if (ret) {
-      /* HgfsSubmitRequest destroys the request if necessary */
-      goto out;
-   }
-
-   replyHeader = (HgfsReply *)HgfsKReq_GetPayload(req);
-   repSize = HGFS_REP_PAYLOAD_SIZE_V3(reply);
-
-   ret = HgfsGetStatus(req, repSize);
-   if (ret) {
-      DEBUG(VM_DEBUG_FAIL, "Error encountered with ret = %d\n", ret);
-      if (ret != EPROTO) {
-         ret = EFAULT;
-      }
-      goto destroyOut;
-   }
-
-   DEBUG(VM_DEBUG_COMM, "received reply for ID %d\n", replyHeader->id);
-   DEBUG(VM_DEBUG_COMM, " status: %d (see hgfsProto.h)\n", replyHeader->status);
-
-   /* Now clear this open file's handle for future use. */
-   ret = HgfsReleaseOpenFileHandle(vp, &closed);
-   if (ret || (closed == FALSE)) {
-      DEBUG(VM_DEBUG_FAIL, "couldn't clear handle.\n");
-      ret = EINVAL;
-      goto destroyOut;
-   }
-
-   DEBUG(VM_DEBUG_LOG, "cleared file handle\n");
-
-   /* The directory was closed successfully so we return success. */
-   ret = 0;
-
-destroyOut:
-   HgfsKReq_ReleaseRequest(sip->reqs, req);
-out:
+   DEBUG(VM_DEBUG_LOG, "Exit %s.\n",  HGFS_VP_TO_FILENAME(vp));
    return ret;
 }
 
@@ -1866,88 +1658,22 @@ HgfsFileClose(HgfsSuperInfo *sip,       // IN: Superinfo pointer
               struct vnode *vp,         // IN: Vnode of file to close
               int flags)                // IN: The mode flags for the close
 {
-   HgfsKReqHandle req;
-   HgfsRequest *requestHeader;
-   HgfsRequestCloseV3 *request;
-   HgfsReplyCloseV3 *reply;
-   uint32 reqSize;
-   uint32 repSize;
-   int ret;
-   Bool closed;
+   int ret = 0;
+   HgfsHandle handleToClose;
 
    ASSERT(sip);
    ASSERT(vp);
 
-   DEBUG(VM_DEBUG_ENTRY, "closing \"%s\"\n", HGFS_VP_TO_FILENAME(vp));
-
-   /*
-    * Check to see if we should close the file handle ( which will happen when
-    * the reference count of the current handle is 1 and will become 0 after
-    * this close.
-    */
-   if (!HgfsShouldCloseOpenFileHandle(vp)) {
-      ret = HgfsReleaseOpenFileHandle(vp, &closed);
-      if (ret || (closed == TRUE)) {
-         DEBUG(VM_DEBUG_FAIL, " HgfsFileClose: The handle is closed!\n");
-        return EINVAL;
-      }
-      return 0;
-   }
-
-   req = HgfsKReq_AllocateRequest(sip->reqs);
-   if (!req) {
-      ret = ENOMEM;
-      goto out;
-   }
-
-   requestHeader = (HgfsRequest *)HgfsKReq_GetPayload(req);
-   request = (HgfsRequestCloseV3 *)HGFS_REQ_GET_PAYLOAD_V3(requestHeader);
-
-   HGFS_INIT_REQUEST_HDR(requestHeader, req, HGFS_OP_CLOSE_V3);
-
-   request->reserved = 0;
-   reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request);
-
-   /* Tell the Hgfs server which handle to close */
-   ret = HgfsGetOpenFileHandle(vp, &request->file);
-   if (ret) {
-      DEBUG(VM_DEBUG_FAIL, "couldn't get handle.\n");
-      ret = EINVAL;
-      goto destroyOut;
-   }
-
-   HgfsKReq_SetPayloadSize(req, reqSize);
-
-   ret = HgfsSubmitRequest(sip, req);
-   if (ret) {
-      /* HgfsSubmitRequest will destroy the request if necessary. */
-      DEBUG(VM_DEBUG_FAIL, "submit request failed.\n");
-      goto out;
-   }
-
-   repSize = HGFS_REP_PAYLOAD_SIZE_V3(reply);
-
-   ret = HgfsGetStatus(req, repSize);
-   if (ret) {
-      DEBUG(VM_DEBUG_FAIL, "Error encountered with ret = %d\n", ret);
-      goto destroyOut;
-   }
+   DEBUG(VM_DEBUG_ENTRY, "closing file \"%s\"\n", HGFS_VP_TO_FILENAME(vp));
 
    /*
-    * We already verified the size of the reply above since this reply type
-    * only contains a header, so we just clear the handle and return success.
+    * Check to see if we should close the file handle on the host ( which happen when
+    * the reference count of the current handle become 0.
     */
-   ret = HgfsReleaseOpenFileHandle(vp, &closed);
-   if (ret || (closed == FALSE)) {
-      DEBUG(VM_DEBUG_FAIL, "couldn't clear handle.\n");
-      ret = EINVAL;
-      goto destroyOut;
+   if (HgfsReleaseOpenFileHandle(vp, &handleToClose) == 0) {
+      ret = HgfsCloseServerFileHandle(sip, handleToClose);
    }
-
-destroyOut:
-   HgfsKReq_ReleaseRequest(sip->reqs, req);
-out:
-   DEBUG(VM_DEBUG_DONE, "returning %d\n", ret);
+   DEBUG(VM_DEBUG_LOG, "Exit %s.\n",  HGFS_VP_TO_FILENAME(vp));
    return ret;
 }
 
@@ -2126,6 +1852,7 @@ HgfsDoWrite(HgfsSuperInfo *sip, // IN: Superinfo pointer
    uint32 repSize;
    int ret;
 
+   DEBUG(VM_DEBUG_LOG, "Trace enter.\n");
    ASSERT(sip);
    ASSERT(uiop);
    ASSERT(size <= HGFS_IO_MAX); // HgfsWrite() guarantees this
@@ -2477,6 +2204,7 @@ HgfsReadlinkInt(struct vnode *vp,   // IN : File vnode
    HgfsKReqHandle req;
    int ret = 0;
    HgfsSuperInfo *sip = HGFS_VP_TO_SIP(vp);
+   DEBUG(VM_DEBUG_LOG, "Enter %s.\n",  HGFS_VP_TO_FILENAME(vp));
    /* This operation is valid only for symbolic links. */
    if (HGFS_VP_TO_VTYPE(vp) != VLNK) {
       DEBUG(VM_DEBUG_FAIL, "Must be a symbolic link.\n");
@@ -2526,6 +2254,7 @@ HgfsReadlinkInt(struct vnode *vp,   // IN : File vnode
    } else {
       DEBUG(VM_DEBUG_FAIL, "Error %d reading symlink name.\n", ret);
    }
+   DEBUG(VM_DEBUG_LOG, "Exit %s.\n",  HGFS_VP_TO_FILENAME(vp));
    return ret;
 }
 
@@ -2567,6 +2296,7 @@ HgfsSymlinkInt(struct vnode *dvp,         // IN : directory vnode
    HgfsFileNameV3 *fileNameP;
    int nameOffset;
 
+   DEBUG(VM_DEBUG_LOG, "Enter %s.\n",  HGFS_VP_TO_FILENAME(dvp));
    DEBUG(VM_DEBUG_ENTRY, "dvp=%p (%s), dirname=%s, vpp=%p\n",
                          dvp, HGFS_VP_TO_FILENAME(dvp), cnp->cn_nameptr,
                          *vpp);
@@ -2690,8 +2420,8 @@ HgfsSymlinkInt(struct vnode *dvp,         // IN : directory vnode
    repSize = HGFS_REP_PAYLOAD_SIZE_V3(reply);
    ret = HgfsGetStatus(req, repSize);
    if (ret == 0) {
-      ret = HgfsVnodeGet(vpp, sip, HGFS_VP_TO_MP(dvp), fullName,
-                         HGFS_FILE_TYPE_SYMLINK, &sip->fileHashTable);
+      ret = HgfsVnodeGet(vpp, dvp, sip, HGFS_VP_TO_MP(dvp), fullName,
+                         HGFS_FILE_TYPE_SYMLINK, &sip->fileHashTable, TRUE, 0);
       if (ret) {
          ret = EIO;
       }
@@ -2708,6 +2438,7 @@ out:
    if (fullName != NULL) {
       os_free(fullName, MAXPATHLEN);
    }
+   DEBUG(VM_DEBUG_LOG, "Exit %s.\n",  HGFS_VP_TO_FILENAME(dvp));
    return ret;
 }
 
@@ -2735,6 +2466,7 @@ HgfsDoGetattrByName(const char *path,       // IN : Path to get attributes for
                    HgfsSuperInfo *sip,     // IN : SuperInfo block of hgfs mount.
                    HgfsAttrV2 *hgfsAttrV2) // OUT: Attributes from hgfs server
 {
+   DEBUG(VM_DEBUG_LOG, "Trace enter.\n");
    return HgfsDoGetattrInt(path, 0, sip, hgfsAttrV2);
 }
 
@@ -2798,6 +2530,7 @@ HgfsDoGetattrInt(const char *path,       // IN : Path to get attributes for
    HgfsKReqHandle req;
    int ret = 0;
 
+   DEBUG(VM_DEBUG_LOG, "Trace enter, %s.\n", path);
    ASSERT(hgfsAttrV2);
 
    req = HgfsKReq_AllocateRequest(sip->reqs);
@@ -2856,6 +2589,7 @@ HgfsQueryAttrInt(const char *path,       // IN : Path to get attributes for
    uint32 reqBufferSize;
    int ret = 0;
 
+   DEBUG(VM_DEBUG_LOG, "Trace enter.\n");
    requestHeader = (HgfsRequest *)HgfsKReq_GetPayload(req);
    request = (HgfsRequestGetattrV3 *)HGFS_REQ_GET_PAYLOAD_V3(requestHeader);
 
@@ -2984,7 +2718,7 @@ HgfsAccessInt(struct vnode *vp, // IN: Vnode to check access for
    HgfsVnodeAttr va;
    int ret = 0;
 
-   DEBUG(VM_DEBUG_FAIL, "HgfsAccessInt is called\n");
+   DEBUG(VM_DEBUG_LOG, "Enter %s.\n",  HGFS_VP_TO_FILENAME(vp));
 
    /* Get the attributes for this file from the Hgfs server. */
    ret = HgfsGetattrInt(vp, &va);
index c307fa7b75cd6cea087bd9599c41914563dfbfce..c8ac82d2c3bbf42050fdc1a53ee3dee2f012c592 100644 (file)
     (!defined KERNEL && !defined _KERNEL && !defined VMKERNEL && !defined __KERNEL__)
 #   include <stddef.h>
 #else
-// XXX the __cplusplus one matches that of VC++, to prevent redefinition warning
+// XXX the _WIN32 one matches that of VC++, to prevent redefinition warning
 // XXX the other one matches that of gcc3.3.3/glibc2.2.4 to prevent redefinition warnings
 #ifndef offsetof
-#ifdef __cplusplus
+#ifdef _WIN32
 #define offsetof(s,m)   (size_t)&(((s *)0)->m)
 #else
 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
index daf8a14d95bdb3b2383bf7a43d29da5af43c050b..f4211e8ef479be4dc6b93ec2e44e3f8f5e3c919d 100644 (file)
@@ -66,8 +66,7 @@ typedef struct NetSG_Array {
 
 #define NET_SG_SIZE(len) (sizeof(NetSG_Array) + (len - NET_SG_DEFAULT_LENGTH) * sizeof(NetSG_Elem))
 
-#define NET_SG_MAKE_PA(elem) (((PA)elem.addrHi << 32) | (PA)elem.addrLow)
-#define NET_SG_MAKE_PTR(elem) \
-             ((char*)(uintptr_t)(((uint64)elem.addrHi << 32) | elem.addrLow))
+#define NET_SG_MAKE_PA(elem)                 (PA)QWORD(elem.addrHi, elem.addrLow)
+#define NET_SG_MAKE_PTR(elem) (char *)(uintptr_t)QWORD(elem.addrHi, elem.addrLow)
 
 #endif
index 92c038c229898f3999f7feb0d3eb004993a8c4a7..eaf6fbe592c9ca8bfb0450f6d4756e13b08efe09 100644 (file)
@@ -1,5 +1,5 @@
 PACKAGE_NAME=open-vm-tools
-PACKAGE_VERSION=2008.12.23
+PACKAGE_VERSION=2009.01.21
 MAKE[0]="make -C pvscsi VM_UNAME=\$kernelver;   \
          make -C vmblock VM_UNAME=\$kernelver;  \
          make -C vmhgfs VM_UNAME=\$kernelver;   \
index 650fd67d2ade0d11c1d9a5d162e31d5adabfb5c5..31103fbade99f02ff7ec01fd3a672ad6fddbbd42 100644 (file)
@@ -121,7 +121,7 @@ endif
 endif
 
 vm_check_build = $(shell if $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) \
-       $(CPPFLAGS) $(CFLAGS) $(CFLAGS_KERNEL) \
+       $(CPPFLAGS) $(CFLAGS) $(CFLAGS_KERNEL) $(LINUXINCLUDE) \
        $(EXTRA_CFLAGS) -Iinclude2/asm/mach-default \
        -DKBUILD_BASENAME=\"$(DRIVER)\" \
        -Werror -S -o /dev/null -xc $(1) \
index 8411a4d310d1ead2ab33fbd7d027e15a0a39bd59..e026d0dafc6023528e3d76dfa0d09b94f966fffd 100644 (file)
@@ -66,6 +66,13 @@ MODULE_DESCRIPTION(PVSCSI_LINUX_DRIVER_DESC);
 MODULE_AUTHOR("VMware, Inc.");
 MODULE_LICENSE("GPL v2");
 MODULE_VERSION(PVSCSI_DRIVER_VERSION_STRING);
+/*
+ * Starting with SLE10sp2, Novell requires that IHVs sign a support agreement
+ * with them and mark their kernel modules as externally supported via a
+ * change to the module header. If this isn't done, the module will not load
+ * by default (i.e., neither mkinitrd nor modprobe will accept it).
+ */
+MODULE_INFO(supported, "external");
 
 #define PVSCSI_DRIVER_VECTORS_USED     1
 #define DEFAULT_PAGES_PER_RING         8
@@ -375,11 +382,14 @@ static int __devinit pvscsi_allocate_rings(struct pvscsi_adapter *adapter)
  */
 static int __devinit pvscsi_allocate_sg(struct pvscsi_adapter *adapter)
 {
-       unsigned i, max;
-       struct pvscsi_ctx *ctx = adapter->cmd_map;
+       struct pvscsi_ctx *ctx;
+       unsigned max;
+       int i;
 
+        ctx = adapter->cmd_map;
        max = adapter->req_depth;
        ASSERT_ON_COMPILE(sizeof(struct PVSCSISGList) <= PAGE_SIZE);
+
        for (i = 0; i < max; ++i, ++ctx) {
                ctx->sgl = kmalloc(PAGE_SIZE, GFP_KERNEL);
                BUG_ON((long)ctx->sgl & ~PAGE_MASK);
index 3fa81f5eec29ab38558c42635e6e0c069c6daf1c..5117d8dacef6c2e01b9ece716bdbdf636ce2b18c 100644 (file)
@@ -40,7 +40,7 @@ enum PVSCSIRegOffset {
    PVSCSI_REG_OFFSET_LAST_STS_0     =  0x100,
    PVSCSI_REG_OFFSET_LAST_STS_1     =  0x104,
    PVSCSI_REG_OFFSET_LAST_STS_2     =  0x108,
-   PVSCSI_REG_OFFSET_LAST_STS_3     =  0x10C,
+   PVSCSI_REG_OFFSET_LAST_STS_3     =  0x10c,
    PVSCSI_REG_OFFSET_INTR_STATUS    = 0x100c,
    PVSCSI_REG_OFFSET_INTR_MASK      = 0x2010,
    PVSCSI_REG_OFFSET_KICK_NON_RW_IO = 0x3014,
@@ -194,6 +194,13 @@ struct CmdDescAbortCmd {
    uint32 _pad;
 };
 
+/*
+ * Note:
+ * - reqRingNumPages and cmpRingNumPages need to be power of two.
+ * - reqRingNumPages and cmpRingNumPages need to be different from 0,
+ * - reqRingNumPages and cmpRingNumPages need to be inferior to
+ *   PVSCSI_SETUP_RINGS_MAX_NUM_PAGES.
+ */
 
 #define PVSCSI_SETUP_RINGS_MAX_NUM_PAGES        32
 struct CmdDescSetupRings {
index 66bb714d75a4ce0b8a4271b017c41a37eaf29cdc..324674dfda77544edef8074bb4fa063058675156 100644 (file)
@@ -36,6 +36,8 @@
 
 #include "vm_basic_defs.h"  // for offsetof()
 
+#define SCSI_MAX_CMD_LEN   16
+
 /*
  * Non-exhaustive list of SCSI operation codes.  Note that
  * some codes are defined differently according to the target
 #define SCSI_SENSE_KEY_UNIT_ATTENTION  0x6   // the LUN has been reset (bus reset of medium change)
 #define SCSI_SENSE_KEY_DATA_PROTECT    0x7   // access to the data is blocked
 #define SCSI_SENSE_KEY_BLANK_CHECK     0x8   // reached an unexpected written or unwritten region of the medium
+#define SCSI_SENSE_KEY_VENDOR_SPECIFIC 0x9   // report vendor specific condition
 #define SCSI_SENSE_KEY_COPY_ABORTED    0xa   // COPY, COMPARE, or COPY AND VERIFY was aborted
 #define SCSI_SENSE_KEY_ABORTED_CMD     0xb   // the target aborted the command
 #define SCSI_SENSE_KEY_EQUAL          0xc   // comparison for SEARCH DATA was unsuccessful
index c307fa7b75cd6cea087bd9599c41914563dfbfce..c8ac82d2c3bbf42050fdc1a53ee3dee2f012c592 100644 (file)
     (!defined KERNEL && !defined _KERNEL && !defined VMKERNEL && !defined __KERNEL__)
 #   include <stddef.h>
 #else
-// XXX the __cplusplus one matches that of VC++, to prevent redefinition warning
+// XXX the _WIN32 one matches that of VC++, to prevent redefinition warning
 // XXX the other one matches that of gcc3.3.3/glibc2.2.4 to prevent redefinition warnings
 #ifndef offsetof
-#ifdef __cplusplus
+#ifdef _WIN32
 #define offsetof(s,m)   (size_t)&(((s *)0)->m)
 #else
 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
index 7ac20e2f9ede5c793aabb2a71a4c3d94afc4ff6e..452e9a435b945165b05cad1f71d5a7bcbec0f162 100644 (file)
@@ -121,7 +121,7 @@ endif
 endif
 
 vm_check_build = $(shell if $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) \
-       $(CPPFLAGS) $(CFLAGS) $(CFLAGS_KERNEL) \
+       $(CPPFLAGS) $(CFLAGS) $(CFLAGS_KERNEL) $(LINUXINCLUDE) \
        $(EXTRA_CFLAGS) -Iinclude2/asm/mach-default \
        -DKBUILD_BASENAME=\"$(DRIVER)\" \
        -Werror -S -o /dev/null -xc $(1) \
index c307fa7b75cd6cea087bd9599c41914563dfbfce..c8ac82d2c3bbf42050fdc1a53ee3dee2f012c592 100644 (file)
     (!defined KERNEL && !defined _KERNEL && !defined VMKERNEL && !defined __KERNEL__)
 #   include <stddef.h>
 #else
-// XXX the __cplusplus one matches that of VC++, to prevent redefinition warning
+// XXX the _WIN32 one matches that of VC++, to prevent redefinition warning
 // XXX the other one matches that of gcc3.3.3/glibc2.2.4 to prevent redefinition warnings
 #ifndef offsetof
-#ifdef __cplusplus
+#ifdef _WIN32
 #define offsetof(s,m)   (size_t)&(((s *)0)->m)
 #else
 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
index 8285cdfd54a5a8a7938f8ceeb25188436240b9eb..c24f2efc180aa6225cb696d880e07b7711a2d996 100644 (file)
@@ -59,6 +59,13 @@ MODULE_AUTHOR("VMware, Inc.");
 MODULE_DESCRIPTION("VMware Blocking File System");
 MODULE_LICENSE("GPL v2");
 MODULE_VERSION(VMBLOCK_DRIVER_VERSION_STRING);
+/*
+ * Starting with SLE10sp2, Novell requires that IHVs sign a support agreement
+ * with them and mark their kernel modules as externally supported via a
+ * change to the module header. If this isn't done, the module will not load
+ * by default (i.e., neither mkinitrd nor modprobe will accept it).
+ */
+MODULE_INFO(supported, "external");
 
 /* Functions */
 static int VMBlockInit(void);
index ceda2411af16da350f9db16261ac50b5f3d3120c..90ee132165d27fb4da01a085e2d1e87b851288e9 100644 (file)
@@ -121,7 +121,7 @@ endif
 endif
 
 vm_check_build = $(shell if $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) \
-       $(CPPFLAGS) $(CFLAGS) $(CFLAGS_KERNEL) \
+       $(CPPFLAGS) $(CFLAGS) $(CFLAGS_KERNEL) $(LINUXINCLUDE) \
        $(EXTRA_CFLAGS) -Iinclude2/asm/mach-default \
        -DKBUILD_BASENAME=\"$(DRIVER)\" \
        -Werror -S -o /dev/null -xc $(1) \
index c307fa7b75cd6cea087bd9599c41914563dfbfce..c8ac82d2c3bbf42050fdc1a53ee3dee2f012c592 100644 (file)
     (!defined KERNEL && !defined _KERNEL && !defined VMKERNEL && !defined __KERNEL__)
 #   include <stddef.h>
 #else
-// XXX the __cplusplus one matches that of VC++, to prevent redefinition warning
+// XXX the _WIN32 one matches that of VC++, to prevent redefinition warning
 // XXX the other one matches that of gcc3.3.3/glibc2.2.4 to prevent redefinition warnings
 #ifndef offsetof
-#ifdef __cplusplus
+#ifdef _WIN32
 #define offsetof(s,m)   (size_t)&(((s *)0)->m)
 #else
 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
index db7ad91de4ea2ae04ad7bae3e545e6c2db84d2e7..1bc9cbd28bd255fe6d3cb107e29ff887e697c96c 100644 (file)
@@ -335,7 +335,7 @@ DatagramHandleUniqueLocked(VMCIHandle handle)
 /*
  *-----------------------------------------------------------------------------
  *
- * VMCIDatagram_CreateHnd --
+ * VMCIDatagramCreateHndInt --
  *
  *      Creates a datagram endpoint and returns a handle to it.
  *
@@ -348,17 +348,12 @@ DatagramHandleUniqueLocked(VMCIHandle handle)
  *-----------------------------------------------------------------------------
  */
 
-#ifdef __linux__
-EXPORT_SYMBOL(VMCIDatagram_CreateHnd);
-#endif
-
 int
-VMCIDatagram_CreateHnd(VMCIId resourceID,          // IN:
-                       uint32 flags,               // IN:
-                       VMCIDatagramRecvCB recvCB,  // IN:
-                       void *clientData,           // IN:
-                       VMCIHandle *outHandle)      // OUT:
-   
+VMCIDatagramCreateHndInt(VMCIId resourceID,          // IN:
+                         uint32 flags,               // IN:
+                         VMCIDatagramRecvCB recvCB,  // IN:
+                         void *clientData,           // IN:
+                         VMCIHandle *outHandle)      // OUT:
 {
    int result;
    DatagramHashEntry *entry;
@@ -375,7 +370,7 @@ VMCIDatagram_CreateHnd(VMCIId resourceID,          // IN:
    }
 
    if ((flags & VMCI_FLAG_WELLKNOWN_DG_HND) != 0) {
-      VMCIDatagramWellKnownMapMsg wkMsg;  
+      VMCIDatagramWellKnownMapMsg wkMsg;
       if (resourceID == VMCI_INVALID_ID) {
         return VMCI_ERROR_INVALID_ARGS;
       }
@@ -405,7 +400,7 @@ VMCIDatagram_CreateHnd(VMCIId resourceID,          // IN:
    if (entry == NULL) {
       return VMCI_ERROR_NO_MEM;
    }
-   
+
    entry->handle = handle;
    entry->flags = flags;
    entry->recvCB = recvCB;
@@ -426,35 +421,62 @@ VMCIDatagram_CreateHnd(VMCIId resourceID,          // IN:
    return VMCI_SUCCESS;
 }
 
-                     
+
 /*
  *-----------------------------------------------------------------------------
  *
- * VMCIDatagram_DestroyHnd --
+ * VMCIDatagram_CreateHnd --
  *
- *      Destroys a handle.
+ *      Creates a datagram endpoint and returns a handle to it.
  *
  * Results:
- *      VMCI_SUCCESS or error code.
+ *      Returns handle if success, negative errno value otherwise.
  *
  * Side effects:
- *      Host and guest state is cleaned up.
+ *      Datagram endpoint is created both in guest and on host.
  *
  *-----------------------------------------------------------------------------
  */
 
 #ifdef __linux__
-EXPORT_SYMBOL(VMCIDatagram_DestroyHnd);
+EXPORT_SYMBOL(VMCIDatagram_CreateHnd);
 #endif
 
 int
-VMCIDatagram_DestroyHnd(VMCIHandle handle)       // IN
+VMCIDatagram_CreateHnd(VMCIId resourceID,          // IN:
+                       uint32 flags,               // IN:
+                       VMCIDatagramRecvCB recvCB,  // IN:
+                       void *clientData,           // IN:
+                       VMCIHandle *outHandle)      // OUT:
+{
+   return VMCIDatagramCreateHndInt(resourceID, flags, recvCB, clientData, outHandle);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIDatagramDestroyHndInt --
+ *
+ *      Destroys a handle.
+ *
+ * Results:
+ *      VMCI_SUCCESS or error code.
+ *
+ * Side effects:
+ *      Host and guest state is cleaned up.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+VMCIDatagramDestroyHndInt(VMCIHandle handle)       // IN
 {
    DatagramHashEntry *entry = DatagramHashGetEntry(handle);
    if (entry == NULL) {
       return VMCI_ERROR_NOT_FOUND;
    }
-   
+
    DatagramHashRemoveEntry(entry->handle);
 
    /*
@@ -463,7 +485,7 @@ VMCIDatagram_DestroyHnd(VMCIHandle handle)       // IN
     */
    VMCI_WaitOnEvent(&entry->destroyEvent, DatagramReleaseCB, entry);
 
-   
+
    if ((entry->flags & VMCI_FLAG_WELLKNOWN_DG_HND) != 0) {
       int result;
       VMCIDatagramWellKnownMapMsg wkMsg;
@@ -479,7 +501,7 @@ VMCIDatagram_DestroyHnd(VMCIHandle handle)       // IN
                   entry->handle.resource));
       }
    }
-   
+
    /* We know we are now holding the last reference so we can free the entry. */
    VMCI_DestroyEvent(&entry->destroyEvent);
    VMCI_FreeKernelMem(entry, sizeof *entry);
@@ -488,6 +510,33 @@ VMCIDatagram_DestroyHnd(VMCIHandle handle)       // IN
 }
 
 
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIDatagram_DestroyHnd --
+ *
+ *      Destroys a handle.
+ *
+ * Results:
+ *      VMCI_SUCCESS or error code.
+ *
+ * Side effects:
+ *      Host and guest state is cleaned up.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+#ifdef __linux__
+EXPORT_SYMBOL(VMCIDatagram_DestroyHnd);
+#endif
+
+int
+VMCIDatagram_DestroyHnd(VMCIHandle handle)       // IN
+{
+   return VMCIDatagramDestroyHndInt(handle);
+}
+
+
 /*
  *-----------------------------------------------------------------------------
  *
index 5dd4797e21fd0bd5233ed56e2aaa3b8f8394de2f..79840d553d769401ca15a88e76a3f638cc2d66a0 100644 (file)
@@ -41,10 +41,17 @@ void VMCIDatagram_Init(void);
 Bool VMCIDatagram_CheckHostCapabilities(void);
 int VMCIDatagram_Dispatch(VMCIId contextID, VMCIDatagram *msg);
 
+int VMCIDatagramCreateHndInt(VMCIId resourceID,
+                             uint32 flags,
+                             VMCIDatagramRecvCB recvCB,
+                             void *clientData,
+                             VMCIHandle *outHandle);
+int VMCIDatagramDestroyHndInt(VMCIHandle handle);
+
 int VMCIDatagramProcess_Create(VMCIDatagramProcess **outDgmProc,
                                VMCIDatagramCreateInfo *createInfo);
 void VMCIDatagramProcess_Destroy(VMCIDatagramProcess *dgmProc);
 int VMCIDatagramProcess_ReadCall(VMCIDatagramProcess *dgmProc,
                                 size_t maxSize, VMCIDatagram **dg);
-               
+
 #endif //__VMCI_DATAGRAM_H__
index 87a71e1ea541b780db3287d8b665472fc9dd0862..3bea8fac0a75bf0556d340fc022e5a817566978f 100644 (file)
@@ -380,7 +380,7 @@ VMCIEventUnregisterSubscription(VMCIId subID)    // IN
 /*
  *----------------------------------------------------------------------
  *
- * VMCIEvent_Subscribe --
+ * VMCIEventSubscribe --
  *
  *      Subscribe to given event.
  *
@@ -393,19 +393,15 @@ VMCIEventUnregisterSubscription(VMCIId subID)    // IN
  *----------------------------------------------------------------------
  */
 
-#if defined(__linux__) && !defined(VMKERNEL)
-EXPORT_SYMBOL(VMCIEvent_Subscribe);
-#endif
-
 int
-VMCIEvent_Subscribe(VMCI_Event event,        // IN
-                    VMCI_EventCB callback,   // IN
-                    void *callbackData,      // IN
-                    VMCIId *subscriptionID)  // OUT
+VMCIEventSubscribe(VMCI_Event event,        // IN
+                   VMCI_EventCB callback,   // IN
+                   void *callbackData,      // IN
+                   VMCIId *subscriptionID)  // OUT
 {
    int retval;
-   VMCISubscription *s = NULL;  
-   
+   VMCISubscription *s = NULL;
+
    if (subscriptionID == NULL) {
       VMCI_LOG(("VMCIEvent: Invalid arguments.\n"));
       return VMCI_ERROR_INVALID_ARGS;
@@ -415,7 +411,7 @@ VMCIEvent_Subscribe(VMCI_Event event,        // IN
    if (s == NULL) {
       return VMCI_ERROR_NO_MEM;
    }
-   
+
    retval = VMCIEventRegisterSubscription(s, event, callback, callbackData);
    if (retval < VMCI_SUCCESS) {
       VMCI_FreeKernelMem(s, sizeof *s);
@@ -430,10 +426,9 @@ VMCIEvent_Subscribe(VMCI_Event event,        // IN
 /*
  *----------------------------------------------------------------------
  *
- * VMCIEvent_Unsubscribe --
+ * VMCIEvent_Subscribe --
  *
- *      Unsubscribe to given event. Removes it from list and frees it. 
- *      Will return callbackData if requested by caller.
+ *      Subscribe to given event.
  *
  * Results:
  *      VMCI_SUCCESS on success, error code otherwise.
@@ -445,17 +440,44 @@ VMCIEvent_Subscribe(VMCI_Event event,        // IN
  */
 
 #if defined(__linux__) && !defined(VMKERNEL)
-EXPORT_SYMBOL(VMCIEvent_Unsubscribe);
+EXPORT_SYMBOL(VMCIEvent_Subscribe);
 #endif
 
 int
-VMCIEvent_Unsubscribe(VMCIId subID)   // IN
+VMCIEvent_Subscribe(VMCI_Event event,        // IN
+                    VMCI_EventCB callback,   // IN
+                    void *callbackData,      // IN
+                    VMCIId *subscriptionID)  // OUT
+{
+   return VMCIEventSubscribe(event, callback, callbackData, subscriptionID);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMCIEventUnsubscribe --
+ *
+ *      Unsubscribe to given event. Removes it from list and frees it. 
+ *      Will return callbackData if requested by caller.
+ *
+ * Results:
+ *      VMCI_SUCCESS on success, error code otherwise.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+VMCIEventUnsubscribe(VMCIId subID)   // IN
 {
    VMCISubscription *s;
 
-   /* 
+   /*
     * Return subscription. At this point we know noone else is accessing
-    * the subscription so we can free it. 
+    * the subscription so we can free it.
     */
    s = VMCIEventUnregisterSubscription(subID);
    if (s == NULL) {
@@ -466,3 +488,31 @@ VMCIEvent_Unsubscribe(VMCIId subID)   // IN
 
    return VMCI_SUCCESS;
 }
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * VMCIEvent_Unsubscribe --
+ *
+ *      Unsubscribe to given event. Removes it from list and frees it.
+ *      Will return callbackData if requested by caller.
+ *
+ * Results:
+ *      VMCI_SUCCESS on success, error code otherwise.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+#if defined(__linux__) && !defined(VMKERNEL)
+EXPORT_SYMBOL(VMCIEvent_Unsubscribe);
+#endif
+
+int
+VMCIEvent_Unsubscribe(VMCIId subID)   // IN
+{
+   return VMCIEventUnsubscribe(subID);
+}
index 83183c903c53adc0b8e6972de4c63e11661087e8..908e27583cd0c0f25166c0529d512405ad219de3 100644 (file)
 
 #include "vmci_defs.h"
 #include "vmci_call_defs.h"
+#include "vmciGuestKernelAPI.h"
 
 void VMCIEvent_Init(void);
 void VMCIEvent_Exit(void);
 int  VMCIEvent_Dispatch(VMCIDatagram *msg);
 #ifdef VMX86_TOOLS
 Bool VMCIEvent_CheckHostCapabilities(void);
-#else
+#endif
 
-/* 
- * Public VMCI Event API for host kernel.
- */
 
-typedef void (*VMCI_EventCB)(VMCIId subID, VMCI_EventData *ed,
-                            void *clientData);
+/*
+ * Non-public VMCI Event API for guest kernel.
+ */
 
-int VMCIEvent_Subscribe(VMCI_Event event, VMCI_EventCB callback, 
+int VMCIEventSubscribe(VMCI_Event event, VMCI_EventCB callback,
                         void *callbackData, VMCIId *subID);
-int VMCIEvent_Unsubscribe(VMCIId subID);
-#endif
+int VMCIEventUnsubscribe(VMCIId subID);
+
 
 #endif //__VMCI_EVENT_H__
index 182d4e477f67da92e8a2e18e6db1ab7eb1a8e95b..0c34b664cff9927b6b4992246a1a965680b111a0 100644 (file)
@@ -37,6 +37,8 @@
 #elif defined(SOLARIS)
 #  include <sys/ddi.h>
 #  include <sys/sunddi.h>
+#elif defined(__APPLE__)
+#  include <IOKit/IOLib.h>
 #else
 #  error "Platform not support by VMCI datagram API."
 #endif // linux
index 0f254340a79268cf2cda07f567fc5409f0dc84cd..5c36b1ede97a7b1ff508d731a981c45ed2923941 100644 (file)
@@ -38,7 +38,7 @@
 #include "vmci_defs.h"
 #include "vmci_call_defs.h"
 
-#if defined(__linux__) || defined(_WIN32)
+#if defined(__linux__) || defined(_WIN32) || defined(SOLARIS)
    /* XXX TODO for other guests. */
 #  include "vmci_queue_pair.h"
 #endif
@@ -70,7 +70,7 @@ int VMCIEvent_Unsubscribe(VMCIId subID);
 /* VMCI Discovery Service API. */
 int VMCIDs_Lookup(const char *name, VMCIHandle *out);
 
-#if defined(__linux__) || defined(_WIN32)
+#if defined(__linux__) || defined(_WIN32) || defined(SOLARIS)
 /* VMCI QueuePair API.  XXX TODO for other guests. */
 int VMCIQueuePair_Alloc(VMCIHandle *handle, VMCIQueue **produceQ,
                         uint64 produceSize, VMCIQueue **consumeQ,
index 12a874c60f472767e7ad6c41beb0038b8a70da42..737008d5c51d5bc573bd2e55ca5c317e843c93ab 100644 (file)
 #ifndef _VMCI_GUEST_KERNEL_IF_H_
 #define _VMCI_GUEST_KERNEL_IF_H_
 
-#if !defined(linux) && !defined(_WIN32) && !defined(SOLARIS)
-#error "Platform not supported."
-#endif
-
 #if defined(_WIN32)
 #include <ntddk.h>
 #endif 
@@ -54,6 +50,9 @@
 #elif defined(SOLARIS)
   typedef uint8_t * VMCIIoPort;
   typedef ddi_acc_handle_t VMCIIoHandle;
+#elif defined(__APPLE__)
+  typedef unsigned short int VMCIIoPort;
+  typedef void *VMCIIoHandle;
 #endif // VMKERNEL
 
 void VMCI_ReadPortBytes(VMCIIoHandle handle, VMCIIoPort port, uint8 *buffer,
index c7c6427f1d601343425ca6ac3cbffd490a69b17f..11fa129138741ff5efe271a2779319ee6e0eb368 100644 (file)
 #include "pgtbl.h"
 #include <linux/vmalloc.h>
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
-#  include <linux/mm.h>         /* For vmalloc_to_page() */
+#  include <linux/mm.h>         /* For vmalloc_to_page() and get_user_pages()*/
+#else
+#  include <linux/iobuf.h>      /* For map_user_kiobuf() and unmap_kiobuf() */
 #endif
 #include <linux/socket.h>       /* For memcpy_{to,from}iovec(). */
+#include <linux/pagemap.h>      /* For page_cache_release() */
 #include "vm_assert.h"
 #include "vmci_kernel_if.h"
+#ifndef VMX86_TOOLS
+#  include "vmciQueuePair.h"
+#endif
+
 #include "vmci_queue_pair.h"
+#include "vmci_iocontrols.h"
 
 /*
  * In Linux 2.6.25 kernels and onwards, the symbol init_mm is no
@@ -693,11 +701,38 @@ void
 VMCI_WaitOnEvent(VMCIEvent *event,              // IN:
                 VMCIEventReleaseCB releaseCB,  // IN:
                 void *clientData)              // IN:
+{
+   /*
+    * XXX Should this be a TASK_UNINTERRUPTIBLE wait? I'm leaving it
+    * as it was for now.
+    */
+   VMCI_WaitOnEventInterruptible(event, releaseCB, clientData);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCI_WaitOnEventInterruptible --
+ *
+ * Results:
+ *      True if the wait was interrupted by a signal, false otherwise.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+VMCI_WaitOnEventInterruptible(VMCIEvent *event,              // IN:
+                              VMCIEventReleaseCB releaseCB,  // IN:
+                              void *clientData)              // IN:
 {
    DECLARE_WAITQUEUE(wait, current);
 
    if (event == NULL || releaseCB == NULL) {
-      return;
+      return FALSE;
    }
 
    add_wait_queue(event, &wait);
@@ -715,6 +750,8 @@ VMCI_WaitOnEvent(VMCIEvent *event,              // IN:
    schedule();
    current->state = TASK_RUNNING;
    remove_wait_queue(event, &wait);
+
+   return signal_pending(current);
 }
 
 
@@ -810,6 +847,7 @@ VMCIMutex_Release(VMCIMutex *mutex) // IN:
 }
 
 
+#ifdef VMX86_TOOLS
 /*
  *-----------------------------------------------------------------------------
  *
@@ -1059,6 +1097,7 @@ VMCI_PopulatePPNList(uint8 *callBuf,       // OUT:
 
    return VMCI_SUCCESS;
 }
+#endif
 
 
 #ifdef __KERNEL__
@@ -1352,3 +1391,291 @@ VMCIWellKnownID_AllowMap(VMCIId wellKnownID,           // IN:
    }
    return TRUE;
 }
+
+
+
+#ifndef VMX86_TOOLS
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIHost_FinishAttach --
+ *       Finish the "attach" operation by update the queues to be
+ *       backed by the shared memory represented by the "attach"
+ *       structure.
+ *
+ * Results:
+ *       VMCI_SUCCESS on success or negative error on failure.
+ *
+ * Side Effects:
+ *       None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+VMCIHost_FinishAttach(PageStoreAttachInfo *attach,      // IN
+                      VMCIQueue *produceQ,              // OUT
+                      VMCIQueue *consumeQ)              // OUT
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+   produceQ->queueHeaderPtr = kmap(attach->producePages[0]);
+   produceQ->page = &attach->producePages[1];
+   consumeQ->queueHeaderPtr = kmap(attach->consumePages[0]);
+   consumeQ->page = &attach->consumePages[1];
+#else
+   produceQ->queueHeaderPtr = kmap(attach->produceIoBuf->maplist[0]);
+   produceQ->page = &attach->produceIoBuf->maplist[1];
+   consumeQ->queueHeaderPtr = kmap(attach->consumeIoBuf->maplist[0]);
+   consumeQ->page = &attach->consumeIoBuf->maplist[1];
+#endif
+
+   return VMCI_SUCCESS;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIHost_DetachMappings --
+ *       Remove any local mappings of memory referenced in 'attach' in
+ *       preparation for releasing the shared memory region entirely.
+ *
+ * Results:
+ *       None.
+ *
+ * Side Effects:
+ *       None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+VMCIHost_DetachMappings(PageStoreAttachInfo *attach)    // IN
+{
+   /*
+    * Unmap the header pages
+    */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+   kunmap(attach->producePages[0]);
+   kunmap(attach->consumePages[0]);
+#else
+   kunmap(attach->produceIoBuf->maplist[0]);
+   kunmap(attach->consumeIoBuf->maplist[0]);
+#endif
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIHost_GetUserMemory --
+ *       Lock the user pages referenced by the {produce,consume}Buffer
+ *       struct into memory and populate the {produce,consume}Pages
+ *       arrays in the attach structure with them.
+ *
+ * Results:
+ *       VMCI_SUCCESS on sucess, negative error code on failure.
+ *
+ * Side Effects:
+ *       None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+VMCIHost_GetUserMemory(PageStoreAttachInfo *attach)         // IN/OUT
+{
+   int retval;
+   int err = VMCI_SUCCESS;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+
+   attach->producePages =
+      VMCI_AllocKernelMem(attach->numProducePages * sizeof attach->producePages[0],
+                          VMCI_MEMORY_NORMAL);
+   if (attach->producePages == NULL) {
+      return VMCI_ERROR_NO_MEM;
+   }
+   attach->consumePages =
+      VMCI_AllocKernelMem(attach->numConsumePages * sizeof attach->consumePages[0],
+                          VMCI_MEMORY_NORMAL);
+   if (attach->consumePages == NULL) {
+      err = VMCI_ERROR_NO_MEM;
+      goto errorDealloc;
+   }
+
+   down_write(&current->mm->mmap_sem);
+   retval = get_user_pages(current,
+                           current->mm,
+                           (VA)attach->produceBuffer,
+                           attach->numProducePages,
+                           1, 0,
+                           attach->producePages,
+                           NULL);
+   if (retval < attach->numProducePages) {
+      Log("get_user_pages(produce) failed: %d\n", retval);
+      if (retval > 0) {
+         int i;
+         for (i = 0; i < retval; i++) {
+            page_cache_release(attach->producePages[i]);
+         }
+      }
+      err = VMCI_ERROR_NO_MEM;
+      goto out;
+   }
+
+   retval = get_user_pages(current,
+                           current->mm,
+                           (VA)attach->consumeBuffer,
+                           attach->numConsumePages,
+                           1, 0,
+                           attach->consumePages,
+                           NULL);
+   if (retval < attach->numConsumePages) {
+      int i;
+      Log("get_user_pages(consume) failed: %d\n", retval);
+      if (retval > 0) {
+         for (i = 0; i < retval; i++) {
+            page_cache_release(attach->consumePages[i]);
+         }
+      }
+      for (i = 0; i < attach->numProducePages; i++) {
+         page_cache_release(attach->producePages[i]);
+      }
+      err = VMCI_ERROR_NO_MEM;
+   }
+
+out:
+   up_write(&current->mm->mmap_sem);
+
+errorDealloc:
+   if (err < VMCI_SUCCESS) {
+      if (attach->producePages != NULL) {
+         VMCI_FreeKernelMem(attach->producePages,
+                            attach->numProducePages *
+                            sizeof attach->producePages[0]);
+      }
+      if (attach->consumePages != NULL) {
+         VMCI_FreeKernelMem(attach->consumePages,
+                            attach->numConsumePages *
+                            sizeof attach->consumePages[0]);
+      }
+   }
+
+   return err;
+
+#else
+
+   attach->produceIoBuf = VMCI_AllocKernelMem(sizeof *attach->produceIoBuf,
+                                              VMCI_MEMORY_NORMAL);
+   if (attach->produceIoBuf == NULL) {
+      return VMCI_ERROR_NO_MEM;
+   }
+
+   attach->consumeIoBuf = VMCI_AllocKernelMem(sizeof *attach->consumeIoBuf,
+                                              VMCI_MEMORY_NORMAL);
+   if (attach->consumeIoBuf == NULL) {
+      VMCI_FreeKernelMem(attach->produceIoBuf,
+                         sizeof *attach->produceIoBuf);
+      return VMCI_ERROR_NO_MEM;
+   }
+
+   retval = map_user_kiobuf(WRITE, attach->produceIoBuf,
+                            (VA)attach->produceBuffer,
+                            attach->numProducePages * PAGE_SIZE);
+   if (retval < 0) {
+      err = VMCI_ERROR_NO_ACCESS;
+      goto out;
+   }
+
+   retval = map_user_kiobuf(WRITE, attach->consumeIoBuf,
+                            (VA)attach->consumeBuffer,
+                            attach->numConsumePages * PAGE_SIZE);
+   if (retval < 0) {
+      unmap_kiobuf(attach->produceIoBuf);
+      err = VMCI_ERROR_NO_ACCESS;
+   }
+
+out:
+
+   if (err < VMCI_SUCCESS) {
+      if (attach->produceIoBuf != NULL) {
+         VMCI_FreeKernelMem(attach->produceIoBuf,
+                            sizeof *attach->produceIoBuf);
+      }
+      if (attach->consumeIoBuf != NULL) {
+         VMCI_FreeKernelMem(attach->consumeIoBuf,
+                            sizeof *attach->consumeIoBuf);
+      }
+   }
+   return err;
+
+#endif
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIHost_ReleaseUserMemory --
+ *       Release the reference to user pages stored in the attach
+ *       struct
+ *
+ * Results:
+ *       None
+ *
+ * Side Effects:
+ *       Pages are released from the page cache and may become
+ *       swappable again.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+VMCIHost_ReleaseUserMemory(PageStoreAttachInfo *attach)         // IN
+{
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+   int i;
+
+   ASSERT(attach->producePages);
+   ASSERT(attach->consumePages);
+   for (i = 0; i < attach->numProducePages; i++) {
+      ASSERT(attach->producePages[i]);
+
+      set_page_dirty(attach->producePages[i]);
+      page_cache_release(attach->producePages[i]);
+   }
+
+   for (i = 0; i < attach->numConsumePages; i++) {
+      ASSERT(attach->consumePages[i]);
+
+      set_page_dirty(attach->consumePages[i]);
+      page_cache_release(attach->consumePages[i]);
+   }
+
+   VMCI_FreeKernelMem(attach->producePages,
+                      attach->numProducePages *
+                      sizeof attach->producePages[0]);
+   VMCI_FreeKernelMem(attach->consumePages,
+                      attach->numConsumePages *
+                      sizeof attach->consumePages[0]);
+#else
+   mark_dirty_kiobuf(attach->produceIoBuf,
+                     attach->numProducePages * PAGE_SIZE);
+   unmap_kiobuf(attach->produceIoBuf);
+
+   mark_dirty_kiobuf(attach->consumeIoBuf,
+                     attach->numConsumePages * PAGE_SIZE);
+   unmap_kiobuf(attach->consumeIoBuf);
+
+   VMCI_FreeKernelMem(attach->produceIoBuf,
+                      sizeof *attach->produceIoBuf);
+   VMCI_FreeKernelMem(attach->consumeIoBuf,
+                      sizeof *attach->consumeIoBuf);
+#endif
+}
+
+#endif
index bc8665936a51396f91cebb9594c6c977f7808503..63e90bb05a2758b35874aa3c6756a021e393b49b 100644 (file)
@@ -29,6 +29,8 @@
 #  include <linux/module.h>
 #elif defined(_WIN32)
 #  include <wdm.h>
+#elif defined(__APPLE__)
+#  include <IOKit/IOLib.h>
 #endif /* __linux__ */
 
 #include "vm_assert.h"
@@ -404,7 +406,7 @@ VMCIQueuePair_Alloc(VMCIHandle *handle,     // IN/OUT:
 #  define VMCIQP_OFFSET_OF(Struct, field) ((uintptr_t)&(((Struct *)0)->field))
 #ifdef __linux__
    ASSERT_ON_COMPILE(VMCIQP_OFFSET_OF(VMCIQueue, page) == PAGE_SIZE);
-#else
+#elif !defined(SOLARIS)
    ASSERT_ON_COMPILE(VMCIQP_OFFSET_OF(VMCIQueue, buffer) == PAGE_SIZE);
 #endif
 #  undef VMCIQP_OFFSET_OF
index 9d81e2f06dfe1143b64b30b6e3128d118d5e6fd8..e0fa1427bf562bf7e7b7f458cf66b7d35664af12 100644 (file)
@@ -43,6 +43,8 @@
 #  include <sys/ddi.h>
 #  include <sys/sunddi.h>
 #  include <sys/disp.h>
+#elif defined(__APPLE__)
+#  include <IOKit/IOLib.h>
 #else 
 #error "platform not supported."
 #endif //linux
@@ -336,6 +338,12 @@ VMCI_InInterrupt()
    return in_interrupt();
 #elif defined(SOLARIS)
    return servicing_interrupt();   /* servicing_interrupt is not part of DDI. */
+#elif defined(__APPLE__)
+   /*
+    * All interrupt servicing is handled by IOKit functions, by the time the IOService
+    * interrupt handler is called we're no longer in an interrupt dispatch level.
+    */
+   return false;
 #endif //
 }
 
index fae5e0554ff8c97e0082c9969eba942cc3d102c0..80a383c77aa88816e7b9d4436a6883fade3d4a2e 100644 (file)
@@ -914,3 +914,10 @@ MODULE_AUTHOR("VMware, Inc.");
 MODULE_DESCRIPTION("VMware Virtual Machine Communication Interface");
 MODULE_VERSION(VMCI_DRIVER_VERSION_STRING);
 MODULE_LICENSE("GPL v2");
+/*
+ * Starting with SLE10sp2, Novell requires that IHVs sign a support agreement
+ * with them and mark their kernel modules as externally supported via a
+ * change to the module header. If this isn't done, the module will not load
+ * by default (i.e., neither mkinitrd nor modprobe will accept it).
+ */
+MODULE_INFO(supported, "external");
index 7829db894bc7a328544d02c403440e2ad4ee964f..36172f1fa0120f4be9274fabe8c5e7ac3e58ce9b 100644 (file)
@@ -143,7 +143,7 @@ VMCIHandleArray_AppendEntry(VMCIHandleArray **arrayPtr,
       /* reallocate. */
       uint32 arraySize = sizeof array->capacity + sizeof array->size +
          array->capacity * sizeof(VMCIHandle);
-      VMCIHandleArray *newArray = 
+      VMCIHandleArray *newArray = (VMCIHandleArray *)
              VMCI_AllocKernelMem(arraySize + array->capacity * sizeof(VMCIHandle),
                              VMCI_MEMORY_NONPAGED);
       if (newArray == NULL) {
@@ -178,7 +178,7 @@ static INLINE VMCIHandle
 VMCIHandleArray_RemoveEntry(VMCIHandleArray *array,
                             VMCIHandle entryHandle)
 {
-   int i;
+   uint32 i;
    VMCIHandle handle = VMCI_INVALID_HANDLE;
 
    ASSERT(array);
@@ -293,7 +293,7 @@ static INLINE Bool
 VMCIHandleArray_HasEntry(const VMCIHandleArray *array,
                          VMCIHandle entryHandle)
 {
-   int i;
+   uint32 i;
 
    ASSERT(array);
    for (i = 0; i < array->size; i++) {
index 5a906210dd619f6b12b2826e65e195f385915d30..da092770b49ff0f2970c8088a907f35f469e9700 100644 (file)
@@ -137,6 +137,7 @@ enum IOCTLCmd_VMCI {
    IOCTLCMD(SOCKETS_GET_SOCK_NAME),
    IOCTLCMD(SOCKETS_GET_SOCK_OPT),
    IOCTLCMD(SOCKETS_GET_VM_BY_NAME),
+   IOCTLCMD(SOCKETS_IOCTL),
    IOCTLCMD(SOCKETS_LISTEN),
    IOCTLCMD(SOCKETS_RECV),
    IOCTLCMD(SOCKETS_RECV_FROM),
@@ -145,27 +146,28 @@ enum IOCTLCmd_VMCI {
    IOCTLCMD(SOCKETS_SEND_TO),
    IOCTLCMD(SOCKETS_SET_SOCK_OPT),
    IOCTLCMD(SOCKETS_SHUTDOWN),
-   IOCTLCMD(SOCKETS_SOCKET), /* 1989 on Linux. */
+   IOCTLCMD(SOCKETS_SOCKET), /* 1990 on Linux. */
    /* END VMCI SOCKETS */
 
    /*
-    * We reserve a range of 5 ioctls for VMCI Sockets to grow.  We cannot
+    * We reserve a range of 4 ioctls for VMCI Sockets to grow.  We cannot
     * reserve many ioctls here since we are close to overlapping with vmmon
     * ioctls.  Define a meta-ioctl if running out of this binary space.
     */
    // Must be last.
-   IOCTLCMD(SOCKETS_LAST) = IOCTLCMD(SOCKETS_SOCKET) + 5, /* 1994 on Linux. */
+   IOCTLCMD(SOCKETS_LAST) = IOCTLCMD(SOCKETS_SOCKET) + 4, /* 1994 on Linux. */
 
    /*
     * The VSockets ioctls occupy the block above.  We define a new range of
     * VMCI ioctls to maintain binary compatibility between the user land and
     * the kernel driver.  Careful, vmmon ioctls start from 2001, so this means
-    * we can add only 5 new VMCI ioctls.  Define a meta-ioctl if running out of
+    * we can add only 4 new VMCI ioctls.  Define a meta-ioctl if running out of
     * this binary space.
     */
 
    IOCTLCMD(FIRST2),
    IOCTLCMD(SET_NOTIFY) = IOCTLCMD(FIRST2), /* 1995 on Linux. */
+   IOCTLCMD(VMCID_RPC),
    IOCTLCMD(LAST2),
 };
 
@@ -175,6 +177,14 @@ enum IOCTLCmd_VMCI {
  * Windows VMCI ioctl definitions.
  */
 
+/*
+ * The first is the device name in user-mode.  The next two are for registering
+ * or opening the device in kernel-mode, and are always in UNICODE.
+ */
+#define VMCI_DEVICE_NAME         TEXT("\\\\.\\VMCI")
+#define VMCI_DEVICE_NAME_PATH    L"\\Device\\vmci"
+#define VMCI_DEVICE_LINK_PATH    L"\\DosDevices\\vmci"
+
 /* These values cannot be changed since some of the ioctl values are public. */
 #define FILE_DEVICE_VMCI         0x8103
 #define VMCI_IOCTL_BASE_INDEX    0x801
@@ -246,6 +256,8 @@ enum IOCTLCmd_VMCI {
                VMCIIOCTL_BUFFERED(SOCKETS_GET_SOCK_OPT)
 #define IOCTL_VMCI_SOCKETS_GET_VM_BY_NAME \
                VMCIIOCTL_BUFFERED(SOCKETS_GET_VM_BY_NAME)
+#define IOCTL_VMCI_SOCKETS_IOCTL \
+               VMCIIOCTL_BUFFERED(SOCKETS_IOCTL)
 #define IOCTL_VMCI_SOCKETS_LISTEN \
                VMCIIOCTL_BUFFERED(SOCKETS_LISTEN)
 #define IOCTL_VMCI_SOCKETS_RECV \
@@ -266,6 +278,11 @@ enum IOCTLCmd_VMCI {
                VMCIIOCTL_BUFFERED(SOCKETS_SOCKET)
 /* END VMCI SOCKETS */
 
+/* BEGIN VMCI USER SPACE DAEMON */
+#define IOCTL_VMCI_VMCID_RPC \
+               VMCIIOCTL_BUFFERED(VMCID_RPC)
+/* END VMCI USER SPACE DAEMON */
+
 #endif // _WIN32
 
 
@@ -364,6 +381,32 @@ typedef struct VMCISetNotifyInfo {
    uint32      _pad;
 } VMCISetNotifyInfo;
 
+/* User space daemon command numbers. */
+typedef enum VMCIDRequestType {
+    VMCID_REQ_NEW_PAGE_STORE,
+    VMCID_REQ_FREE_PAGE_STORE,
+    VMCID_REQ_ATTACH_PAGE_STORE,
+    VMCID_REQ_DETACH_PAGE_STORE,
+} VMCIDRequestType;
+
+#define VMCI_VMCID_INVALID_REQ  CONST64U(-1)
+
+/* Used to pass requests/responses to the user space daemon. */
+typedef struct VMCIDRpc {
+    uint64           reqId;
+    uint32           reqType;
+    uint32           reqResult;
+    /* Passing page file names */
+    VA64             producePageFile; /* User VA. */
+    VA64             consumePageFile; /* User VA. */
+    uint64           producePageFileSize; /* Size of the file name array. */
+    uint64           consumePageFileSize; /* Size of the file name array. */
+    /* Used for attach/detach */
+    VA64             produceVA;
+    VA64             consumeVA;
+    uint64           numProducePages;
+    uint64           numConsumePages;
+} VMCIDRpc;
 
 #ifdef __APPLE__
 /*
index 3838305f963d785f013771188b67d9535b5a4356..ad48d8ad1922c0ebe741861771cf09229f7cc628 100644 (file)
@@ -58,6 +58,7 @@
 #  include <sys/mutex.h>
 #  include <sys/poll.h>
 #  include <sys/semaphore.h>
+#  include <sys/kmem.h>
 #endif
 
 #include "vm_basic_types.h"
@@ -86,6 +87,7 @@
   typedef unsigned long VMCILockFlags;
   typedef semaphore_t VMCIEvent;
   typedef IOLock *VMCIMutex;
+  typedef void *VMCIPpnList; /* Actually a pointer to the C++ Object IOMemoryDescriptor */
 #elif defined(_WIN32)
   typedef KSPIN_LOCK VMCILock;
   typedef KIRQL VMCILockFlags;
@@ -96,6 +98,8 @@
   typedef kmutex_t VMCILock;
   typedef unsigned long VMCILockFlags;
   typedef ksema_t VMCIEvent;
+  typedef kmutex_t VMCIMutex;
+  typedef PPN *VMCIPpnList; /* List of PPNs in produce/consume queue. */
 #endif // VMKERNEL
 
 /* Callback needed for correctly waiting on events. */
@@ -231,22 +235,29 @@ void VMCI_DestroyEvent(VMCIEvent *event);
 void VMCI_SignalEvent(VMCIEvent *event);
 void VMCI_WaitOnEvent(VMCIEvent *event, VMCIEventReleaseCB releaseCB, 
                      void *clientData);
+#if (defined(__linux__) || defined(_WIN32)) && !defined(VMKERNEL)
+Bool VMCI_WaitOnEventInterruptible(VMCIEvent *event,
+                                   VMCIEventReleaseCB releaseCB,
+                                   void *clientData);
+#endif
 
-/* XXX TODO for VMKERNEL (host) and Solaris (guest). */
 #if !defined(VMKERNEL) && (defined(__linux__) || defined(_WIN32) || \
-                           defined(__APPLE__))
+                           defined(__APPLE__) || defined(SOLARIS))
 int VMCI_CopyFromUser(void *dst, const void *src, size_t len);
 #endif
 
-#if !defined(SOLARIS)
 int VMCIMutex_Init(VMCIMutex *mutex);
 void VMCIMutex_Destroy(VMCIMutex *mutex);
 void VMCIMutex_Acquire(VMCIMutex *mutex);
 void VMCIMutex_Release(VMCIMutex *mutex);
-#endif
 
-/* XXX TODO for Solaris (guest). */
-#if !defined(VMKERNEL) && (defined(__linux__) || defined(_WIN32))
+#if defined(SOLARIS)
+int VMCIKernelIf_Init(void);
+void VMCIKernelIf_Exit(void);
+#endif         /* SOLARIS  */
+
+#if !defined(VMKERNEL) && (defined(__linux__) || defined(_WIN32) || \
+                           defined(SOLARIS) || defined(__APPLE__))
 VA VMCI_AllocQueueKVA(uint64 size);
 void VMCI_FreeQueueKVA(VA va, uint64 size);
 typedef struct PPNSet {
@@ -262,5 +273,18 @@ void VMCI_FreePPNSet(PPNSet *ppnSet);
 int VMCI_PopulatePPNList(uint8 *callBuf, const PPNSet *ppnSet);
 #endif
 
+#if (defined(_WIN32) || defined(__linux__)) && !defined(VMKERNEL) && \
+   !defined(VMX86_TOOLS)
+struct PageStoreAttachInfo;
+struct VMCIQueue;
+
+int VMCIHost_GetUserMemory(struct PageStoreAttachInfo *attach);
+void VMCIHost_ReleaseUserMemory(struct PageStoreAttachInfo *attach);
+int VMCIHost_FinishAttach(struct PageStoreAttachInfo *attach,
+                          struct VMCIQueue *produceQ,
+                         struct VMCIQueue *detachQ);
+void VMCIHost_DetachMappings(struct PageStoreAttachInfo *attach);
+#endif
+
 #endif // _VMCI_KERNEL_IF_H_
 
index 315bb6e60364fa07286a5f90d358a3007315a7c7..05884f5c8860d784f6773eabf756975d36dce715 100644 (file)
@@ -16,8 +16,8 @@
  *
  *********************************************************/
 
-#ifndef _VMCI_QUEUE_PAIR_H_
-#define _VMCI_QUEUE_PAIR_H_
+#ifndef _PUBLIC_VMCI_QUEUE_PAIR_H_
+#define _PUBLIC_VMCI_QUEUE_PAIR_H_
 
 /*
  *
 #define INCLUDE_ALLOW_VMX
 #include "includeCheck.h"
 
+#if defined(__APPLE__) && defined(KERNEL)
+#  include "vmci_kernel_if.h"
+#endif // __APPLE__
+
 #include "vm_basic_defs.h"
 #include "vm_basic_types.h"
 #include "vm_atomic.h"
 #include "vmci_defs.h"
 #include "vm_assert.h"
-#if defined(__linux__) && defined(__KERNEL__)
-#  include "vmci_kernel_if.h"
+#if defined(SOLARIS)
+#include <sys/uio.h>
+#endif
+
+#if (defined(__linux__) && defined(__KERNEL__)) || defined(SOLARIS)
+#include "vmci_kernel_if.h"
 #endif
 
 
@@ -58,17 +66,334 @@ typedef struct VMCIQueueHeader {
    Atomic_uint64 consumerHead; /* Offset in peer queue. */
 } VMCIQueueHeader;
 
-typedef struct VMCIQueue {
-   VMCIQueueHeader queueHeader;
-   uint8 _padding[PAGE_SIZE - sizeof(VMCIQueueHeader)];
-#if defined(__linux__) && defined(__KERNEL__)
-   struct page *page[0]; /* List of pages containing queue data. */
+
+/*
+ * If one client of a QueuePair is a 32bit entity, we restrict the QueuePair
+ * size to be less than 4GB, and use 32bit atomic operations on the head and
+ * tail pointers. 64bit atomic read on a 32bit entity involves cmpxchg8b which
+ * is an atomic read-modify-write. This will cause traces to fire when a 32bit
+ * consumer tries to read the producer's tail pointer, for example, because the
+ * consumer has read-only access to the producer's tail pointer.
+ *
+ * We provide the following macros to invoke 32bit or 64bit atomic operations
+ * based on the architecture the code is being compiled on.
+ */
+
+/* Architecture independent maximum queue size. */
+#define QP_MAX_QUEUE_SIZE_ARCH_ANY  CONST64U(0xffffffff)
+
+#ifdef __x86_64__
+#  define QP_MAX_QUEUE_SIZE_ARCH  CONST64U(0xffffffffffffffff)
+#  define QPAtomic_ReadOffset(x)  Atomic_Read64(x)
+#  define QPAtomic_WriteOffset(x, y) Atomic_Write64(x, y)
 #else
-   uint8 buffer[0]; /* Buffer containing data. */
+   /*
+    * Wrappers below are being used to call Atomic_Read32 because of the
+    * 'type punned' compilation warning received when Atomic_Read32 is
+    * called with a Atomic_uint64 pointer typecasted to Atomic_uint32 
+    * pointer from QPAtomic_ReadOffset. Ditto with QPAtomic_WriteOffset.
+    */
+
+   static INLINE uint32
+   TypeSafe_Atomic_Read32(void *var)                // IN:
+   {
+      return Atomic_Read32((Atomic_uint32 *)(var));
+   }
+
+   static INLINE void
+   TypeSafe_Atomic_Write32(void *var, uint32 val)   // IN:
+   {
+      Atomic_Write32((Atomic_uint32 *)(var), (uint32)(val));
+   }
+   
+#  define QP_MAX_QUEUE_SIZE_ARCH  CONST64U(0xffffffff)
+#  define QPAtomic_ReadOffset(x)  TypeSafe_Atomic_Read32((void *)(x))
+#  define QPAtomic_WriteOffset(x, y) \
+          TypeSafe_Atomic_Write32((void *)(x), (uint32)(y))
+#endif /* __x86_64__  */
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * AddPointer --
+ *
+ *      Helper to add a given offset to a head or tail pointer. Wraps the value
+ *      of the pointer around the max size of the queue.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE void
+AddPointer(Atomic_uint64 *var, // IN:
+           size_t add,         // IN:
+           uint64 size)        // IN:
+{
+   uint64 newVal = QPAtomic_ReadOffset(var);
+
+   if (newVal >= size - add) {
+      newVal -= size;
+   }
+   newVal += add;
+
+   QPAtomic_WriteOffset(var, newVal);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueue
+ *
+ * This data type contains the information about a queue.
+ *
+ * There are two queues (hence, queue pairs) per transaction model
+ * between a pair of end points, A & B.  One queue is used by end
+ * point A to transmit commands and responses to B.  The other queue
+ * is used by B to transmit commands and responses.
+ *
+ * There are six distinct definitions of the VMCIQueue structure.
+ * Five are found below along with descriptions of under what build
+ * type the VMCIQueue structure type is compiled.  The sixth is
+ * located in a separate file and is used in the VMKernel context.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+#if defined(VMX86_TOOLS) || defined(VMX86_VMX)
+#  if defined(__linux__) && defined(__KERNEL__)
+      /*
+       * Linux Kernel Guest.
+       *
+       * The VMCIQueue is two or more machine pages where the first
+       * contains the queue header and the second and subsequent pages
+       * contain an array of struct page pointers to the actual pages
+       * that contain the queue data.
+       */
+      typedef struct VMCIQueue {
+        VMCIQueueHeader queueHeader;
+        uint8 _padding[PAGE_SIZE - sizeof(VMCIQueueHeader)];
+        struct page *page[0];
+      } VMCIQueue;
+#  elif defined(SOLARIS)
+      /*
+       * Solaris Kernel Guest.
+       *
+       * kmem_cache_alloc with object size of one page is being used to get
+       * page aligned memory for queueHeader. VMCIQueue stores a pointer to 
+       * the queueHeader and the array of virtual addresses of actual pages 
+       * that contain the queue data.
+       */
+      typedef struct VMCIQueue {
+         VMCIQueueHeader *queueHeaderPtr;
+         void *vaddr[0];
+      } VMCIQueue;
+
+#  else
+      /*
+       * VMX App and Windows Kernel Guest
+       *
+       * The VMCIQueue is two or more machine pages where the first
+       * contains the queue header and the second and subsequent pages
+       * contain the actual queue buffer data.
+       */
+      typedef struct VMCIQueue {
+        VMCIQueueHeader queueHeader;
+        uint8 _padding[PAGE_SIZE - sizeof(VMCIQueueHeader)];
+        uint8 buffer[0];  // VMX doesn't use this today
+      } VMCIQueue;
+#  endif
+#else
+#  if defined(__linux__) && defined(__KERNEL__)
+      /*
+       * Linux Kernel Host
+       *
+       * The VMCIQueueHeader has been created elsewhere and this
+       * structure (VMCIQueue) needs a pointer to that
+       * VMCIQueueHeader.
+       *
+       * Also, the queue contents are managed by an array of struct
+       * pages which are managed elsewhere.  So, this structure simply
+       * contains the address of that array of struct pages.
+       */
+      typedef struct VMCIQueue {
+        VMCIQueueHeader *queueHeaderPtr;
+        struct page **page;
+      } VMCIQueue;
+#  else
+      /*
+       * Windows Host
+       *
+       * The VMCIQueueHeader has been created elsewhere and this
+       * structure (VMCIQueue) needs a pointer to that
+       * VMCIQueueHeader.
+       *
+       * Also, the queue contents are managed by an array of bytes
+       * which are managed elsewhere.  So, this structure simply
+       * contains the address of that array of bytes.
+       */
+      typedef struct VMCIQueue {
+        VMCIQueueHeader *queueHeaderPtr;
+        uint8 *buffer;
+      } VMCIQueue;
+#  endif
+#endif
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueue_GetHeader() --
+ *
+ *      Helper routine to get the address of the VMCIQueueHeader.
+ *      Note that this routine is useful because there are two ways
+ *      queues are declared (at least as far as the queue header is
+ *      concerned, anyway).  In one way, the queue contains the header
+ *      in the other the queue contains a pointer to the header.  This
+ *      helper hides that ambiguity from users of queues who need
+ *      access to the header.
+ *
+ * Results:
+ *      The address of the queue header.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE VMCIQueueHeader *
+VMCIQueue_GetHeader(const VMCIQueue *q)
+{
+#if defined(VMX86_TOOLS) || defined(VMX86_VMX)
+   /*
+    * All guest variants except Solaris have a complete queue header
+    */
+#if defined (SOLARIS)
+   return (VMCIQueueHeader *)q->queueHeaderPtr;
+#else
+   return (VMCIQueueHeader *)&q->queueHeader;
+#endif /* SOLARIS  */
+#else
+   /*
+    * All host variants have a pointer to the queue header
+    */
+   return (VMCIQueueHeader *)q->queueHeaderPtr;
 #endif
-} VMCIQueue;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueue_ProducerTail() --
+ *
+ *      Helper routine to get the Producer Tail from the supplied queue.
+ *
+ * Results:
+ *      The contents of the queue's producer tail.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
 
+static INLINE uint64
+VMCIQueue_ProducerTail(const VMCIQueue *queue)
+{
+   return QPAtomic_ReadOffset(&VMCIQueue_GetHeader(queue)->producerTail);
+}
 
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueue_ConsumerHead() --
+ *
+ *      Helper routine to get the Consumer Head from the supplied queue.
+ *
+ * Results:
+ *      The contents of the queue's consumer tail.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE uint64
+VMCIQueue_ConsumerHead(const VMCIQueue *queue)
+{
+   return QPAtomic_ReadOffset(&VMCIQueue_GetHeader(queue)->consumerHead);
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueue_AddProducerTail() --
+ *
+ *      Helper routine to increment the Producer Tail.  Fundamentally,
+ *      AddPointer() is used to manipulate the tail itself.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE void
+VMCIQueue_AddProducerTail(VMCIQueue *queue,
+                          size_t add,
+                          uint64 queueSize)
+{
+   AddPointer(&VMCIQueue_GetHeader(queue)->producerTail, add, queueSize);
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueue_AddConsumerHead() --
+ *
+ *      Helper routine to increment the Consumer Head.  Fundamentally,
+ *      AddPointer() is used to manipulate the head itself.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE void
+VMCIQueue_AddConsumerHead(VMCIQueue *queue,
+                          size_t add,
+                          uint64 queueSize)
+{
+   AddPointer(&VMCIQueue_GetHeader(queue)->consumerHead, add, queueSize);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIMemcpy{To,From}QueueFunc() prototypes.  Functions of these
+ * types are passed around to enqueue and dequeue routines.  Note that
+ * often the functions passed are simply wrappers around memcpy
+ * itself.
+ *
+ *-----------------------------------------------------------------------------
+ */
 typedef int VMCIMemcpyToQueueFunc(VMCIQueue *queue, uint64 queueOffset,
                                   const void *src, size_t srcOffset,
                                   size_t size);
@@ -76,7 +401,16 @@ typedef int VMCIMemcpyFromQueueFunc(void *dest, size_t destOffset,
                                     const VMCIQueue *queue, uint64 queueOffset,
                                     size_t size);
 
-#if defined(__linux__) && defined(__KERNEL__)
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIMemcpy{To,From}Queue[v]() prototypes (and, in some cases, an
+ * inline version).
+ * 
+ *-----------------------------------------------------------------------------
+ */
+
+#if defined (SOLARIS) || (defined(__linux__) && defined(__KERNEL__))
 int VMCIMemcpyToQueue(VMCIQueue *queue, uint64 queueOffset, const void *src,
                       size_t srcOffset, size_t size);
 int VMCIMemcpyFromQueue(void *dest, size_t destOffset, const VMCIQueue *queue,
@@ -152,39 +486,13 @@ VMCIMemcpyFromQueue(void *dest,             // OUT:
 #endif /* __linux__ && __KERNEL__ */
 
 
-/*
- * If one client of a QueuePair is a 32bit entity, we restrict the QueuePair
- * size to be less than 4GB, and use 32bit atomic operations on the head and
- * tail pointers. 64bit atomic read on a 32bit entity involves cmpxchg8b which
- * is an atomic read-modify-write. This will cause traces to fire when a 32bit
- * consumer tries to read the producer's tail pointer, for example, because the
- * consumer has read-only access to the producer's tail pointer.
- *
- * We provide the following macros to invoke 32bit or 64bit atomic operations
- * based on the architecture the code is being compiled on.
- */
-
-/* Architecture independent maximum queue size. */
-#define QP_MAX_QUEUE_SIZE_ARCH_ANY  CONST64U(0xffffffff)
-
-#ifdef __x86_64__
-#  define QP_MAX_QUEUE_SIZE_ARCH  CONST64U(0xffffffffffffffff)
-#  define QPAtomic_ReadOffset(x)  Atomic_Read64(x)
-#  define QPAtomic_WriteOffset(x, y) Atomic_Write64(x, y)
-#else
-#  define QP_MAX_QUEUE_SIZE_ARCH  CONST64U(0xffffffff)
-#  define QPAtomic_ReadOffset(x)  Atomic_Read32((Atomic_uint32 *)(x))
-#  define QPAtomic_WriteOffset(x, y) \
-            Atomic_Write32((Atomic_uint32 *)(x), (uint32)(y))
-#endif
-
-
 /*
  *-----------------------------------------------------------------------------
  *
  * VMCIQueue_CheckAlignment --
  *
- *      Checks if the given queue is aligned to page boundary.
+ *      Checks if the given queue is aligned to page boundary.  Returns TRUE if
+ *      the alignment is good.
  *
  * Results:
  *      TRUE or FALSE.
@@ -198,18 +506,38 @@ VMCIMemcpyFromQueue(void *dest,             // OUT:
 static INLINE Bool
 VMCIQueue_CheckAlignment(const VMCIQueue *queue) // IN:
 {
-   return ((uintptr_t)queue & (PAGE_SIZE - 1)) == 0;
+   /*
+    * Checks if header of the queue is page aligned.
+    */
+   return ((uintptr_t)VMCIQueue_GetHeader(queue) & (PAGE_SIZE - 1)) == 0;
 }
 
 
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueue_GetPointers --
+ *
+ *      Helper routine for getting the head and the tail pointer for a queue.
+ *     Both the VMCIQueues are needed to get both the pointers for one queue.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
 static INLINE void
 VMCIQueue_GetPointers(const VMCIQueue *produceQ,
                       const VMCIQueue *consumeQ,
                       uint64 *producerTail,
                       uint64 *consumerHead)
 {
-   *producerTail = QPAtomic_ReadOffset(&produceQ->queueHeader.producerTail);
-   *consumerHead = QPAtomic_ReadOffset(&consumeQ->queueHeader.consumerHead);
+   *producerTail = VMCIQueue_ProducerTail(produceQ);
+   *consumerHead = VMCIQueue_ConsumerHead(consumeQ);
 }
 
 
@@ -233,8 +561,8 @@ VMCIQueue_GetPointers(const VMCIQueue *produceQ,
 static INLINE void
 VMCIQueue_ResetPointers(VMCIQueue *queue) // IN:
 {
-   QPAtomic_WriteOffset(&queue->queueHeader.producerTail, CONST64U(0));
-   QPAtomic_WriteOffset(&queue->queueHeader.consumerHead, CONST64U(0));
+   QPAtomic_WriteOffset(&VMCIQueue_GetHeader(queue)->producerTail, CONST64U(0));
+   QPAtomic_WriteOffset(&VMCIQueue_GetHeader(queue)->consumerHead, CONST64U(0));
 }
 
 
@@ -259,7 +587,7 @@ VMCIQueue_Init(const VMCIHandle handle, // IN:
                VMCIQueue *queue)        // IN:
 {
    ASSERT_NOT_IMPLEMENTED(VMCIQueue_CheckAlignment(queue));
-   queue->queueHeader.handle = handle;
+   VMCIQueue_GetHeader(queue)->handle = handle;
    VMCIQueue_ResetPointers(queue);
 }
 
@@ -287,10 +615,8 @@ VMCIQueueFreeSpaceInt(const VMCIQueue *produceQueue, // IN:
                       const uint64 produceQSize,     // IN:
                       uint64 *freeSpace)             // OUT:
 {
-   const uint64 tail =
-      QPAtomic_ReadOffset(&produceQueue->queueHeader.producerTail);
-   const uint64 head =
-      QPAtomic_ReadOffset(&consumeQueue->queueHeader.consumerHead);
+   const uint64 tail = VMCIQueue_ProducerTail(produceQueue);
+   const uint64 head = VMCIQueue_ConsumerHead(consumeQueue);
 
    ASSERT(freeSpace);
 
@@ -384,39 +710,6 @@ VMCIQueue_BufReady(const VMCIQueue *consumeQueue, // IN:
 }
 
 
-/*
- *-----------------------------------------------------------------------------
- *
- * AddPointer --
- *
- *      Helper to add a given offset to a head or tail pointer. Wraps the value
- *      of the pointer around the max size of the queue.
- *
- * Results:
- *      None.
- *
- * Side effects:
- *      None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static INLINE void
-AddPointer(Atomic_uint64 *var, // IN:
-           size_t add,         // IN:
-           uint64 max)         // IN:
-{
-   uint64 newVal = QPAtomic_ReadOffset(var);
-
-   if (newVal >= max - add) {
-      newVal -= max;
-   }
-   newVal += add;
-
-   QPAtomic_WriteOffset(var, newVal);
-}
-
-
 /*
  *-----------------------------------------------------------------------------
  *
@@ -448,8 +741,7 @@ __VMCIQueue_Enqueue(VMCIQueue *produceQueue,               // IN:
 {
    const int64 freeSpace = VMCIQueue_FreeSpace(produceQueue, consumeQueue,
                                                produceQSize);
-   const uint64 tail =
-      QPAtomic_ReadOffset(&produceQueue->queueHeader.producerTail);
+   const uint64 tail = VMCIQueue_ProducerTail(produceQueue);
    size_t written;
 
    if (!freeSpace) {
@@ -469,7 +761,7 @@ __VMCIQueue_Enqueue(VMCIQueue *produceQueue,               // IN:
       memcpyToQueue(produceQueue, tail, buf, 0, tmp);
       memcpyToQueue(produceQueue, 0, buf, tmp, written - tmp);
    }
-   AddPointer(&produceQueue->queueHeader.producerTail, written, produceQSize);
+   AddPointer(&VMCIQueue_GetHeader(produceQueue)->producerTail, written, produceQSize);
    return written;
 }
 
@@ -507,7 +799,7 @@ VMCIQueue_Enqueue(VMCIQueue *produceQueue,       // IN:
 }
 
 
-#if defined(__linux__) && defined(__KERNEL__)
+#if defined (SOLARIS) || (defined(__linux__) && defined(__KERNEL__))
 /*
  *-----------------------------------------------------------------------------
  *
@@ -572,8 +864,7 @@ __VMCIQueue_Dequeue(VMCIQueue *produceQueue,                    // IN:
 {
    const int64 bufReady = VMCIQueue_BufReady(consumeQueue, produceQueue,
                                              consumeQSize);
-   const uint64 head =
-      QPAtomic_ReadOffset(&produceQueue->queueHeader.consumerHead);
+   const uint64 head = VMCIQueue_ConsumerHead(produceQueue);
    size_t written;
 
    if (!bufReady) {
@@ -593,7 +884,7 @@ __VMCIQueue_Dequeue(VMCIQueue *produceQueue,                    // IN:
       memcpyFromQueue(buf, 0, consumeQueue, head, tmp);
       memcpyFromQueue(buf, tmp, consumeQueue, 0, written - tmp);
    }
-   AddPointer(&produceQueue->queueHeader.consumerHead, written, consumeQSize);
+   AddPointer(&VMCIQueue_GetHeader(produceQueue)->consumerHead, written, consumeQSize);
    return written;
 }
 
@@ -631,7 +922,7 @@ VMCIQueue_Dequeue(VMCIQueue *produceQueue,       // IN:
 }
 
 
-#if defined(__linux__) && defined(__KERNEL__)
+#if defined(SOLARIS) || (defined(__linux__) && defined(__KERNEL__))
 /*
  *-----------------------------------------------------------------------------
  *
@@ -665,4 +956,4 @@ VMCIQueue_DequeueV(VMCIQueue *produceQueue,       // IN:
 }
 #endif
 
-#endif /* !_VMCI_QUEUE_PAIR_H_ */
+#endif /* !_PUBLIC_VMCI_QUEUE_PAIR_H_ */
index f4dc9a20aaef0484029bdf4bc5ef06804d5cac20..257fdfe1395ceade89f2e214869b5ed7d34e11d9 100644 (file)
@@ -121,7 +121,7 @@ endif
 endif
 
 vm_check_build = $(shell if $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) \
-       $(CPPFLAGS) $(CFLAGS) $(CFLAGS_KERNEL) \
+       $(CPPFLAGS) $(CFLAGS) $(CFLAGS_KERNEL) $(LINUXINCLUDE) \
        $(EXTRA_CFLAGS) -Iinclude2/asm/mach-default \
        -DKBUILD_BASENAME=\"$(DRIVER)\" \
        -Werror -S -o /dev/null -xc $(1) \
index 35cb2aabe8fc0825b698d8f686d7123831683793..b7c2fe3e2155e363c6b7883a798d67a01e71a7cd 100644 (file)
@@ -53,6 +53,13 @@ MODULE_AUTHOR("VMware, Inc.");
 MODULE_DESCRIPTION("VMware Host/Guest File System");
 MODULE_VERSION(VMHGFS_DRIVER_VERSION_STRING);
 MODULE_LICENSE("GPL v2");
+/*
+ * Starting with SLE10sp2, Novell requires that IHVs sign a support agreement
+ * with them and mark their kernel modules as externally supported via a
+ * change to the module header. If this isn't done, the module will not load
+ * by default (i.e., neither mkinitrd nor modprobe will accept it).
+ */
+MODULE_INFO(supported, "external");
 
 
 /*
index c307fa7b75cd6cea087bd9599c41914563dfbfce..c8ac82d2c3bbf42050fdc1a53ee3dee2f012c592 100644 (file)
     (!defined KERNEL && !defined _KERNEL && !defined VMKERNEL && !defined __KERNEL__)
 #   include <stddef.h>
 #else
-// XXX the __cplusplus one matches that of VC++, to prevent redefinition warning
+// XXX the _WIN32 one matches that of VC++, to prevent redefinition warning
 // XXX the other one matches that of gcc3.3.3/glibc2.2.4 to prevent redefinition warnings
 #ifndef offsetof
-#ifdef __cplusplus
+#ifdef _WIN32
 #define offsetof(s,m)   (size_t)&(((s *)0)->m)
 #else
 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
index f3c6f1dba188bd8089b5f85503dd85b25adddc08..7da9af69ab29acf114e5f9e150c152b401364d72 100644 (file)
@@ -121,7 +121,7 @@ endif
 endif
 
 vm_check_build = $(shell if $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) \
-       $(CPPFLAGS) $(CFLAGS) $(CFLAGS_KERNEL) \
+       $(CPPFLAGS) $(CFLAGS) $(CFLAGS_KERNEL) $(LINUXINCLUDE) \
        $(EXTRA_CFLAGS) -Iinclude2/asm/mach-default \
        -DKBUILD_BASENAME=\"$(DRIVER)\" \
        -Werror -S -o /dev/null -xc $(1) \
index b065c63ef8dcd5308f6c98a22891eebcdf833d5c..bf88e39281a9b53b72104d24c1ebbf8927c6e2e4 100644 (file)
@@ -652,3 +652,10 @@ MODULE_AUTHOR("VMware, Inc.");
 MODULE_DESCRIPTION("VMware Memory Control Driver");
 MODULE_LICENSE("GPL v2");
 MODULE_VERSION(VMMEMCTL_DRIVER_VERSION_STRING);
+/*
+ * Starting with SLE10sp2, Novell requires that IHVs sign a support agreement
+ * with them and mark their kernel modules as externally supported via a
+ * change to the module header. If this isn't done, the module will not load
+ * by default (i.e., neither mkinitrd nor modprobe will accept it).
+ */
+MODULE_INFO(supported, "external");
index c307fa7b75cd6cea087bd9599c41914563dfbfce..c8ac82d2c3bbf42050fdc1a53ee3dee2f012c592 100644 (file)
     (!defined KERNEL && !defined _KERNEL && !defined VMKERNEL && !defined __KERNEL__)
 #   include <stddef.h>
 #else
-// XXX the __cplusplus one matches that of VC++, to prevent redefinition warning
+// XXX the _WIN32 one matches that of VC++, to prevent redefinition warning
 // XXX the other one matches that of gcc3.3.3/glibc2.2.4 to prevent redefinition warnings
 #ifndef offsetof
-#ifdef __cplusplus
+#ifdef _WIN32
 #define offsetof(s,m)   (size_t)&(((s *)0)->m)
 #else
 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
index 1c2a277eb183136b05747ca3102401dd3700ff35..7c07608bcad556bd409b25dd8a8fd6c727d9ff1b 100644 (file)
@@ -121,7 +121,7 @@ endif
 endif
 
 vm_check_build = $(shell if $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) \
-       $(CPPFLAGS) $(CFLAGS) $(CFLAGS_KERNEL) \
+       $(CPPFLAGS) $(CFLAGS) $(CFLAGS_KERNEL) $(LINUXINCLUDE) \
        $(EXTRA_CFLAGS) -Iinclude2/asm/mach-default \
        -DKBUILD_BASENAME=\"$(DRIVER)\" \
        -Werror -S -o /dev/null -xc $(1) \
index d6fac3b77858e5b7a04582693e4f7c87140e8b87..c43ff6b491b504a834970fc755f86adf4cc707d5 100644 (file)
@@ -65,6 +65,13 @@ MODULE_AUTHOR("VMware, Inc.");
 MODULE_DESCRIPTION("VMware Sync Driver");
 MODULE_VERSION(VMSYNC_DRIVER_VERSION_STRING);
 MODULE_LICENSE("GPL v2");
+/*
+ * Starting with SLE10sp2, Novell requires that IHVs sign a support agreement
+ * with them and mark their kernel modules as externally supported via a
+ * change to the module header. If this isn't done, the module will not load
+ * by default (i.e., neither mkinitrd nor modprobe will accept it).
+ */
+MODULE_INFO(supported, "external");
 
 static int VmSyncRelease(struct inode* inode,
                          struct file *file);
index 635d98cee3105a612fdfb1c1c5ecebfb9f489c5f..9e55b7b83ac3961ea21668d7d1bc1dba588e0aff 100644 (file)
@@ -121,7 +121,7 @@ endif
 endif
 
 vm_check_build = $(shell if $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) \
-       $(CPPFLAGS) $(CFLAGS) $(CFLAGS_KERNEL) \
+       $(CPPFLAGS) $(CFLAGS) $(CFLAGS_KERNEL) $(LINUXINCLUDE) \
        $(EXTRA_CFLAGS) -Iinclude2/asm/mach-default \
        -DKBUILD_BASENAME=\"$(DRIVER)\" \
        -Werror -S -o /dev/null -xc $(1) \
index daf8a14d95bdb3b2383bf7a43d29da5af43c050b..f4211e8ef479be4dc6b93ec2e44e3f8f5e3c919d 100644 (file)
@@ -66,8 +66,7 @@ typedef struct NetSG_Array {
 
 #define NET_SG_SIZE(len) (sizeof(NetSG_Array) + (len - NET_SG_DEFAULT_LENGTH) * sizeof(NetSG_Elem))
 
-#define NET_SG_MAKE_PA(elem) (((PA)elem.addrHi << 32) | (PA)elem.addrLow)
-#define NET_SG_MAKE_PTR(elem) \
-             ((char*)(uintptr_t)(((uint64)elem.addrHi << 32) | elem.addrLow))
+#define NET_SG_MAKE_PA(elem)                 (PA)QWORD(elem.addrHi, elem.addrLow)
+#define NET_SG_MAKE_PTR(elem) (char *)(uintptr_t)QWORD(elem.addrHi, elem.addrLow)
 
 #endif
index 1c25a0c2a21026e679a2ce31bda44ab76d369fdb..9917c1e9db310c5d8076aaae0ba2c6c1cafd3c9f 100644 (file)
@@ -2492,3 +2492,10 @@ MODULE_AUTHOR("VMware, Inc.");
 MODULE_DESCRIPTION("VMware Virtual Ethernet driver");
 MODULE_LICENSE("GPL v2");
 MODULE_VERSION(VMXNET_DRIVER_VERSION_STRING);
+/*
+ * Starting with SLE10sp2, Novell requires that IHVs sign a support agreement
+ * with them and mark their kernel modules as externally supported via a
+ * change to the module header. If this isn't done, the module will not load
+ * by default (i.e., neither mkinitrd nor modprobe will accept it).
+ */
+MODULE_INFO(supported, "external");
index fd89c04677899b827689dcdf7fe4852d1506eed4..81bb2b7c92ddcec103d27d37688683413fce6753 100644 (file)
@@ -121,7 +121,7 @@ endif
 endif
 
 vm_check_build = $(shell if $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) \
-       $(CPPFLAGS) $(CFLAGS) $(CFLAGS_KERNEL) \
+       $(CPPFLAGS) $(CFLAGS) $(CFLAGS_KERNEL) $(LINUXINCLUDE) \
        $(EXTRA_CFLAGS) -Iinclude2/asm/mach-default \
        -DKBUILD_BASENAME=\"$(DRIVER)\" \
        -Werror -S -o /dev/null -xc $(1) \
index 246cd552cda44ed52aab3cef8c6472dde3dd66a2..52e2d0e8e0e0c7bc465bd54b83538c143b5cc9b1 100644 (file)
@@ -4551,5 +4551,12 @@ MODULE_AUTHOR("VMware, Inc.");
 MODULE_DESCRIPTION(VMXNET3_DRIVER_DESC);
 MODULE_LICENSE("GPL v2");
 MODULE_VERSION(VMXNET3_DRIVER_VERSION_STRING);
+/*
+ * Starting with SLE10sp2, Novell requires that IHVs sign a support agreement
+ * with them and mark their kernel modules as externally supported via a
+ * change to the module header. If this isn't done, the module will not load
+ * by default (i.e., neither mkinitrd nor modprobe will accept it).
+ */
+MODULE_INFO(supported, "external");
 
 
index 293ebb0bdf9478adec998be2d4cbda3858bdb55d..e3f86640bbfb85bf2bb722084aae49e9e9444e42 100644 (file)
@@ -121,7 +121,7 @@ endif
 endif
 
 vm_check_build = $(shell if $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) \
-       $(CPPFLAGS) $(CFLAGS) $(CFLAGS_KERNEL) \
+       $(CPPFLAGS) $(CFLAGS) $(CFLAGS_KERNEL) $(LINUXINCLUDE) \
        $(EXTRA_CFLAGS) -Iinclude2/asm/mach-default \
        -DKBUILD_BASENAME=\"$(DRIVER)\" \
        -Werror -S -o /dev/null -xc $(1) \
index c307fa7b75cd6cea087bd9599c41914563dfbfce..c8ac82d2c3bbf42050fdc1a53ee3dee2f012c592 100644 (file)
     (!defined KERNEL && !defined _KERNEL && !defined VMKERNEL && !defined __KERNEL__)
 #   include <stddef.h>
 #else
-// XXX the __cplusplus one matches that of VC++, to prevent redefinition warning
+// XXX the _WIN32 one matches that of VC++, to prevent redefinition warning
 // XXX the other one matches that of gcc3.3.3/glibc2.2.4 to prevent redefinition warnings
 #ifndef offsetof
-#ifdef __cplusplus
+#ifdef _WIN32
 #define offsetof(s,m)   (size_t)&(((s *)0)->m)
 #else
 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
index 0f254340a79268cf2cda07f567fc5409f0dc84cd..5c36b1ede97a7b1ff508d731a981c45ed2923941 100644 (file)
@@ -38,7 +38,7 @@
 #include "vmci_defs.h"
 #include "vmci_call_defs.h"
 
-#if defined(__linux__) || defined(_WIN32)
+#if defined(__linux__) || defined(_WIN32) || defined(SOLARIS)
    /* XXX TODO for other guests. */
 #  include "vmci_queue_pair.h"
 #endif
@@ -70,7 +70,7 @@ int VMCIEvent_Unsubscribe(VMCIId subID);
 /* VMCI Discovery Service API. */
 int VMCIDs_Lookup(const char *name, VMCIHandle *out);
 
-#if defined(__linux__) || defined(_WIN32)
+#if defined(__linux__) || defined(_WIN32) || defined(SOLARIS)
 /* VMCI QueuePair API.  XXX TODO for other guests. */
 int VMCIQueuePair_Alloc(VMCIHandle *handle, VMCIQueue **produceQ,
                         uint64 produceSize, VMCIQueue **consumeQ,
index 5a906210dd619f6b12b2826e65e195f385915d30..da092770b49ff0f2970c8088a907f35f469e9700 100644 (file)
@@ -137,6 +137,7 @@ enum IOCTLCmd_VMCI {
    IOCTLCMD(SOCKETS_GET_SOCK_NAME),
    IOCTLCMD(SOCKETS_GET_SOCK_OPT),
    IOCTLCMD(SOCKETS_GET_VM_BY_NAME),
+   IOCTLCMD(SOCKETS_IOCTL),
    IOCTLCMD(SOCKETS_LISTEN),
    IOCTLCMD(SOCKETS_RECV),
    IOCTLCMD(SOCKETS_RECV_FROM),
@@ -145,27 +146,28 @@ enum IOCTLCmd_VMCI {
    IOCTLCMD(SOCKETS_SEND_TO),
    IOCTLCMD(SOCKETS_SET_SOCK_OPT),
    IOCTLCMD(SOCKETS_SHUTDOWN),
-   IOCTLCMD(SOCKETS_SOCKET), /* 1989 on Linux. */
+   IOCTLCMD(SOCKETS_SOCKET), /* 1990 on Linux. */
    /* END VMCI SOCKETS */
 
    /*
-    * We reserve a range of 5 ioctls for VMCI Sockets to grow.  We cannot
+    * We reserve a range of 4 ioctls for VMCI Sockets to grow.  We cannot
     * reserve many ioctls here since we are close to overlapping with vmmon
     * ioctls.  Define a meta-ioctl if running out of this binary space.
     */
    // Must be last.
-   IOCTLCMD(SOCKETS_LAST) = IOCTLCMD(SOCKETS_SOCKET) + 5, /* 1994 on Linux. */
+   IOCTLCMD(SOCKETS_LAST) = IOCTLCMD(SOCKETS_SOCKET) + 4, /* 1994 on Linux. */
 
    /*
     * The VSockets ioctls occupy the block above.  We define a new range of
     * VMCI ioctls to maintain binary compatibility between the user land and
     * the kernel driver.  Careful, vmmon ioctls start from 2001, so this means
-    * we can add only 5 new VMCI ioctls.  Define a meta-ioctl if running out of
+    * we can add only 4 new VMCI ioctls.  Define a meta-ioctl if running out of
     * this binary space.
     */
 
    IOCTLCMD(FIRST2),
    IOCTLCMD(SET_NOTIFY) = IOCTLCMD(FIRST2), /* 1995 on Linux. */
+   IOCTLCMD(VMCID_RPC),
    IOCTLCMD(LAST2),
 };
 
@@ -175,6 +177,14 @@ enum IOCTLCmd_VMCI {
  * Windows VMCI ioctl definitions.
  */
 
+/*
+ * The first is the device name in user-mode.  The next two are for registering
+ * or opening the device in kernel-mode, and are always in UNICODE.
+ */
+#define VMCI_DEVICE_NAME         TEXT("\\\\.\\VMCI")
+#define VMCI_DEVICE_NAME_PATH    L"\\Device\\vmci"
+#define VMCI_DEVICE_LINK_PATH    L"\\DosDevices\\vmci"
+
 /* These values cannot be changed since some of the ioctl values are public. */
 #define FILE_DEVICE_VMCI         0x8103
 #define VMCI_IOCTL_BASE_INDEX    0x801
@@ -246,6 +256,8 @@ enum IOCTLCmd_VMCI {
                VMCIIOCTL_BUFFERED(SOCKETS_GET_SOCK_OPT)
 #define IOCTL_VMCI_SOCKETS_GET_VM_BY_NAME \
                VMCIIOCTL_BUFFERED(SOCKETS_GET_VM_BY_NAME)
+#define IOCTL_VMCI_SOCKETS_IOCTL \
+               VMCIIOCTL_BUFFERED(SOCKETS_IOCTL)
 #define IOCTL_VMCI_SOCKETS_LISTEN \
                VMCIIOCTL_BUFFERED(SOCKETS_LISTEN)
 #define IOCTL_VMCI_SOCKETS_RECV \
@@ -266,6 +278,11 @@ enum IOCTLCmd_VMCI {
                VMCIIOCTL_BUFFERED(SOCKETS_SOCKET)
 /* END VMCI SOCKETS */
 
+/* BEGIN VMCI USER SPACE DAEMON */
+#define IOCTL_VMCI_VMCID_RPC \
+               VMCIIOCTL_BUFFERED(VMCID_RPC)
+/* END VMCI USER SPACE DAEMON */
+
 #endif // _WIN32
 
 
@@ -364,6 +381,32 @@ typedef struct VMCISetNotifyInfo {
    uint32      _pad;
 } VMCISetNotifyInfo;
 
+/* User space daemon command numbers. */
+typedef enum VMCIDRequestType {
+    VMCID_REQ_NEW_PAGE_STORE,
+    VMCID_REQ_FREE_PAGE_STORE,
+    VMCID_REQ_ATTACH_PAGE_STORE,
+    VMCID_REQ_DETACH_PAGE_STORE,
+} VMCIDRequestType;
+
+#define VMCI_VMCID_INVALID_REQ  CONST64U(-1)
+
+/* Used to pass requests/responses to the user space daemon. */
+typedef struct VMCIDRpc {
+    uint64           reqId;
+    uint32           reqType;
+    uint32           reqResult;
+    /* Passing page file names */
+    VA64             producePageFile; /* User VA. */
+    VA64             consumePageFile; /* User VA. */
+    uint64           producePageFileSize; /* Size of the file name array. */
+    uint64           consumePageFileSize; /* Size of the file name array. */
+    /* Used for attach/detach */
+    VA64             produceVA;
+    VA64             consumeVA;
+    uint64           numProducePages;
+    uint64           numConsumePages;
+} VMCIDRpc;
 
 #ifdef __APPLE__
 /*
index 3838305f963d785f013771188b67d9535b5a4356..ad48d8ad1922c0ebe741861771cf09229f7cc628 100644 (file)
@@ -58,6 +58,7 @@
 #  include <sys/mutex.h>
 #  include <sys/poll.h>
 #  include <sys/semaphore.h>
+#  include <sys/kmem.h>
 #endif
 
 #include "vm_basic_types.h"
@@ -86,6 +87,7 @@
   typedef unsigned long VMCILockFlags;
   typedef semaphore_t VMCIEvent;
   typedef IOLock *VMCIMutex;
+  typedef void *VMCIPpnList; /* Actually a pointer to the C++ Object IOMemoryDescriptor */
 #elif defined(_WIN32)
   typedef KSPIN_LOCK VMCILock;
   typedef KIRQL VMCILockFlags;
@@ -96,6 +98,8 @@
   typedef kmutex_t VMCILock;
   typedef unsigned long VMCILockFlags;
   typedef ksema_t VMCIEvent;
+  typedef kmutex_t VMCIMutex;
+  typedef PPN *VMCIPpnList; /* List of PPNs in produce/consume queue. */
 #endif // VMKERNEL
 
 /* Callback needed for correctly waiting on events. */
@@ -231,22 +235,29 @@ void VMCI_DestroyEvent(VMCIEvent *event);
 void VMCI_SignalEvent(VMCIEvent *event);
 void VMCI_WaitOnEvent(VMCIEvent *event, VMCIEventReleaseCB releaseCB, 
                      void *clientData);
+#if (defined(__linux__) || defined(_WIN32)) && !defined(VMKERNEL)
+Bool VMCI_WaitOnEventInterruptible(VMCIEvent *event,
+                                   VMCIEventReleaseCB releaseCB,
+                                   void *clientData);
+#endif
 
-/* XXX TODO for VMKERNEL (host) and Solaris (guest). */
 #if !defined(VMKERNEL) && (defined(__linux__) || defined(_WIN32) || \
-                           defined(__APPLE__))
+                           defined(__APPLE__) || defined(SOLARIS))
 int VMCI_CopyFromUser(void *dst, const void *src, size_t len);
 #endif
 
-#if !defined(SOLARIS)
 int VMCIMutex_Init(VMCIMutex *mutex);
 void VMCIMutex_Destroy(VMCIMutex *mutex);
 void VMCIMutex_Acquire(VMCIMutex *mutex);
 void VMCIMutex_Release(VMCIMutex *mutex);
-#endif
 
-/* XXX TODO for Solaris (guest). */
-#if !defined(VMKERNEL) && (defined(__linux__) || defined(_WIN32))
+#if defined(SOLARIS)
+int VMCIKernelIf_Init(void);
+void VMCIKernelIf_Exit(void);
+#endif         /* SOLARIS  */
+
+#if !defined(VMKERNEL) && (defined(__linux__) || defined(_WIN32) || \
+                           defined(SOLARIS) || defined(__APPLE__))
 VA VMCI_AllocQueueKVA(uint64 size);
 void VMCI_FreeQueueKVA(VA va, uint64 size);
 typedef struct PPNSet {
@@ -262,5 +273,18 @@ void VMCI_FreePPNSet(PPNSet *ppnSet);
 int VMCI_PopulatePPNList(uint8 *callBuf, const PPNSet *ppnSet);
 #endif
 
+#if (defined(_WIN32) || defined(__linux__)) && !defined(VMKERNEL) && \
+   !defined(VMX86_TOOLS)
+struct PageStoreAttachInfo;
+struct VMCIQueue;
+
+int VMCIHost_GetUserMemory(struct PageStoreAttachInfo *attach);
+void VMCIHost_ReleaseUserMemory(struct PageStoreAttachInfo *attach);
+int VMCIHost_FinishAttach(struct PageStoreAttachInfo *attach,
+                          struct VMCIQueue *produceQ,
+                         struct VMCIQueue *detachQ);
+void VMCIHost_DetachMappings(struct PageStoreAttachInfo *attach);
+#endif
+
 #endif // _VMCI_KERNEL_IF_H_
 
index 315bb6e60364fa07286a5f90d358a3007315a7c7..05884f5c8860d784f6773eabf756975d36dce715 100644 (file)
@@ -16,8 +16,8 @@
  *
  *********************************************************/
 
-#ifndef _VMCI_QUEUE_PAIR_H_
-#define _VMCI_QUEUE_PAIR_H_
+#ifndef _PUBLIC_VMCI_QUEUE_PAIR_H_
+#define _PUBLIC_VMCI_QUEUE_PAIR_H_
 
 /*
  *
 #define INCLUDE_ALLOW_VMX
 #include "includeCheck.h"
 
+#if defined(__APPLE__) && defined(KERNEL)
+#  include "vmci_kernel_if.h"
+#endif // __APPLE__
+
 #include "vm_basic_defs.h"
 #include "vm_basic_types.h"
 #include "vm_atomic.h"
 #include "vmci_defs.h"
 #include "vm_assert.h"
-#if defined(__linux__) && defined(__KERNEL__)
-#  include "vmci_kernel_if.h"
+#if defined(SOLARIS)
+#include <sys/uio.h>
+#endif
+
+#if (defined(__linux__) && defined(__KERNEL__)) || defined(SOLARIS)
+#include "vmci_kernel_if.h"
 #endif
 
 
@@ -58,17 +66,334 @@ typedef struct VMCIQueueHeader {
    Atomic_uint64 consumerHead; /* Offset in peer queue. */
 } VMCIQueueHeader;
 
-typedef struct VMCIQueue {
-   VMCIQueueHeader queueHeader;
-   uint8 _padding[PAGE_SIZE - sizeof(VMCIQueueHeader)];
-#if defined(__linux__) && defined(__KERNEL__)
-   struct page *page[0]; /* List of pages containing queue data. */
+
+/*
+ * If one client of a QueuePair is a 32bit entity, we restrict the QueuePair
+ * size to be less than 4GB, and use 32bit atomic operations on the head and
+ * tail pointers. 64bit atomic read on a 32bit entity involves cmpxchg8b which
+ * is an atomic read-modify-write. This will cause traces to fire when a 32bit
+ * consumer tries to read the producer's tail pointer, for example, because the
+ * consumer has read-only access to the producer's tail pointer.
+ *
+ * We provide the following macros to invoke 32bit or 64bit atomic operations
+ * based on the architecture the code is being compiled on.
+ */
+
+/* Architecture independent maximum queue size. */
+#define QP_MAX_QUEUE_SIZE_ARCH_ANY  CONST64U(0xffffffff)
+
+#ifdef __x86_64__
+#  define QP_MAX_QUEUE_SIZE_ARCH  CONST64U(0xffffffffffffffff)
+#  define QPAtomic_ReadOffset(x)  Atomic_Read64(x)
+#  define QPAtomic_WriteOffset(x, y) Atomic_Write64(x, y)
 #else
-   uint8 buffer[0]; /* Buffer containing data. */
+   /*
+    * Wrappers below are being used to call Atomic_Read32 because of the
+    * 'type punned' compilation warning received when Atomic_Read32 is
+    * called with a Atomic_uint64 pointer typecasted to Atomic_uint32 
+    * pointer from QPAtomic_ReadOffset. Ditto with QPAtomic_WriteOffset.
+    */
+
+   static INLINE uint32
+   TypeSafe_Atomic_Read32(void *var)                // IN:
+   {
+      return Atomic_Read32((Atomic_uint32 *)(var));
+   }
+
+   static INLINE void
+   TypeSafe_Atomic_Write32(void *var, uint32 val)   // IN:
+   {
+      Atomic_Write32((Atomic_uint32 *)(var), (uint32)(val));
+   }
+   
+#  define QP_MAX_QUEUE_SIZE_ARCH  CONST64U(0xffffffff)
+#  define QPAtomic_ReadOffset(x)  TypeSafe_Atomic_Read32((void *)(x))
+#  define QPAtomic_WriteOffset(x, y) \
+          TypeSafe_Atomic_Write32((void *)(x), (uint32)(y))
+#endif /* __x86_64__  */
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * AddPointer --
+ *
+ *      Helper to add a given offset to a head or tail pointer. Wraps the value
+ *      of the pointer around the max size of the queue.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE void
+AddPointer(Atomic_uint64 *var, // IN:
+           size_t add,         // IN:
+           uint64 size)        // IN:
+{
+   uint64 newVal = QPAtomic_ReadOffset(var);
+
+   if (newVal >= size - add) {
+      newVal -= size;
+   }
+   newVal += add;
+
+   QPAtomic_WriteOffset(var, newVal);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueue
+ *
+ * This data type contains the information about a queue.
+ *
+ * There are two queues (hence, queue pairs) per transaction model
+ * between a pair of end points, A & B.  One queue is used by end
+ * point A to transmit commands and responses to B.  The other queue
+ * is used by B to transmit commands and responses.
+ *
+ * There are six distinct definitions of the VMCIQueue structure.
+ * Five are found below along with descriptions of under what build
+ * type the VMCIQueue structure type is compiled.  The sixth is
+ * located in a separate file and is used in the VMKernel context.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+#if defined(VMX86_TOOLS) || defined(VMX86_VMX)
+#  if defined(__linux__) && defined(__KERNEL__)
+      /*
+       * Linux Kernel Guest.
+       *
+       * The VMCIQueue is two or more machine pages where the first
+       * contains the queue header and the second and subsequent pages
+       * contain an array of struct page pointers to the actual pages
+       * that contain the queue data.
+       */
+      typedef struct VMCIQueue {
+        VMCIQueueHeader queueHeader;
+        uint8 _padding[PAGE_SIZE - sizeof(VMCIQueueHeader)];
+        struct page *page[0];
+      } VMCIQueue;
+#  elif defined(SOLARIS)
+      /*
+       * Solaris Kernel Guest.
+       *
+       * kmem_cache_alloc with object size of one page is being used to get
+       * page aligned memory for queueHeader. VMCIQueue stores a pointer to 
+       * the queueHeader and the array of virtual addresses of actual pages 
+       * that contain the queue data.
+       */
+      typedef struct VMCIQueue {
+         VMCIQueueHeader *queueHeaderPtr;
+         void *vaddr[0];
+      } VMCIQueue;
+
+#  else
+      /*
+       * VMX App and Windows Kernel Guest
+       *
+       * The VMCIQueue is two or more machine pages where the first
+       * contains the queue header and the second and subsequent pages
+       * contain the actual queue buffer data.
+       */
+      typedef struct VMCIQueue {
+        VMCIQueueHeader queueHeader;
+        uint8 _padding[PAGE_SIZE - sizeof(VMCIQueueHeader)];
+        uint8 buffer[0];  // VMX doesn't use this today
+      } VMCIQueue;
+#  endif
+#else
+#  if defined(__linux__) && defined(__KERNEL__)
+      /*
+       * Linux Kernel Host
+       *
+       * The VMCIQueueHeader has been created elsewhere and this
+       * structure (VMCIQueue) needs a pointer to that
+       * VMCIQueueHeader.
+       *
+       * Also, the queue contents are managed by an array of struct
+       * pages which are managed elsewhere.  So, this structure simply
+       * contains the address of that array of struct pages.
+       */
+      typedef struct VMCIQueue {
+        VMCIQueueHeader *queueHeaderPtr;
+        struct page **page;
+      } VMCIQueue;
+#  else
+      /*
+       * Windows Host
+       *
+       * The VMCIQueueHeader has been created elsewhere and this
+       * structure (VMCIQueue) needs a pointer to that
+       * VMCIQueueHeader.
+       *
+       * Also, the queue contents are managed by an array of bytes
+       * which are managed elsewhere.  So, this structure simply
+       * contains the address of that array of bytes.
+       */
+      typedef struct VMCIQueue {
+        VMCIQueueHeader *queueHeaderPtr;
+        uint8 *buffer;
+      } VMCIQueue;
+#  endif
+#endif
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueue_GetHeader() --
+ *
+ *      Helper routine to get the address of the VMCIQueueHeader.
+ *      Note that this routine is useful because there are two ways
+ *      queues are declared (at least as far as the queue header is
+ *      concerned, anyway).  In one way, the queue contains the header
+ *      in the other the queue contains a pointer to the header.  This
+ *      helper hides that ambiguity from users of queues who need
+ *      access to the header.
+ *
+ * Results:
+ *      The address of the queue header.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE VMCIQueueHeader *
+VMCIQueue_GetHeader(const VMCIQueue *q)
+{
+#if defined(VMX86_TOOLS) || defined(VMX86_VMX)
+   /*
+    * All guest variants except Solaris have a complete queue header
+    */
+#if defined (SOLARIS)
+   return (VMCIQueueHeader *)q->queueHeaderPtr;
+#else
+   return (VMCIQueueHeader *)&q->queueHeader;
+#endif /* SOLARIS  */
+#else
+   /*
+    * All host variants have a pointer to the queue header
+    */
+   return (VMCIQueueHeader *)q->queueHeaderPtr;
 #endif
-} VMCIQueue;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueue_ProducerTail() --
+ *
+ *      Helper routine to get the Producer Tail from the supplied queue.
+ *
+ * Results:
+ *      The contents of the queue's producer tail.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
 
+static INLINE uint64
+VMCIQueue_ProducerTail(const VMCIQueue *queue)
+{
+   return QPAtomic_ReadOffset(&VMCIQueue_GetHeader(queue)->producerTail);
+}
 
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueue_ConsumerHead() --
+ *
+ *      Helper routine to get the Consumer Head from the supplied queue.
+ *
+ * Results:
+ *      The contents of the queue's consumer tail.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE uint64
+VMCIQueue_ConsumerHead(const VMCIQueue *queue)
+{
+   return QPAtomic_ReadOffset(&VMCIQueue_GetHeader(queue)->consumerHead);
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueue_AddProducerTail() --
+ *
+ *      Helper routine to increment the Producer Tail.  Fundamentally,
+ *      AddPointer() is used to manipulate the tail itself.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE void
+VMCIQueue_AddProducerTail(VMCIQueue *queue,
+                          size_t add,
+                          uint64 queueSize)
+{
+   AddPointer(&VMCIQueue_GetHeader(queue)->producerTail, add, queueSize);
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueue_AddConsumerHead() --
+ *
+ *      Helper routine to increment the Consumer Head.  Fundamentally,
+ *      AddPointer() is used to manipulate the head itself.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE void
+VMCIQueue_AddConsumerHead(VMCIQueue *queue,
+                          size_t add,
+                          uint64 queueSize)
+{
+   AddPointer(&VMCIQueue_GetHeader(queue)->consumerHead, add, queueSize);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIMemcpy{To,From}QueueFunc() prototypes.  Functions of these
+ * types are passed around to enqueue and dequeue routines.  Note that
+ * often the functions passed are simply wrappers around memcpy
+ * itself.
+ *
+ *-----------------------------------------------------------------------------
+ */
 typedef int VMCIMemcpyToQueueFunc(VMCIQueue *queue, uint64 queueOffset,
                                   const void *src, size_t srcOffset,
                                   size_t size);
@@ -76,7 +401,16 @@ typedef int VMCIMemcpyFromQueueFunc(void *dest, size_t destOffset,
                                     const VMCIQueue *queue, uint64 queueOffset,
                                     size_t size);
 
-#if defined(__linux__) && defined(__KERNEL__)
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIMemcpy{To,From}Queue[v]() prototypes (and, in some cases, an
+ * inline version).
+ * 
+ *-----------------------------------------------------------------------------
+ */
+
+#if defined (SOLARIS) || (defined(__linux__) && defined(__KERNEL__))
 int VMCIMemcpyToQueue(VMCIQueue *queue, uint64 queueOffset, const void *src,
                       size_t srcOffset, size_t size);
 int VMCIMemcpyFromQueue(void *dest, size_t destOffset, const VMCIQueue *queue,
@@ -152,39 +486,13 @@ VMCIMemcpyFromQueue(void *dest,             // OUT:
 #endif /* __linux__ && __KERNEL__ */
 
 
-/*
- * If one client of a QueuePair is a 32bit entity, we restrict the QueuePair
- * size to be less than 4GB, and use 32bit atomic operations on the head and
- * tail pointers. 64bit atomic read on a 32bit entity involves cmpxchg8b which
- * is an atomic read-modify-write. This will cause traces to fire when a 32bit
- * consumer tries to read the producer's tail pointer, for example, because the
- * consumer has read-only access to the producer's tail pointer.
- *
- * We provide the following macros to invoke 32bit or 64bit atomic operations
- * based on the architecture the code is being compiled on.
- */
-
-/* Architecture independent maximum queue size. */
-#define QP_MAX_QUEUE_SIZE_ARCH_ANY  CONST64U(0xffffffff)
-
-#ifdef __x86_64__
-#  define QP_MAX_QUEUE_SIZE_ARCH  CONST64U(0xffffffffffffffff)
-#  define QPAtomic_ReadOffset(x)  Atomic_Read64(x)
-#  define QPAtomic_WriteOffset(x, y) Atomic_Write64(x, y)
-#else
-#  define QP_MAX_QUEUE_SIZE_ARCH  CONST64U(0xffffffff)
-#  define QPAtomic_ReadOffset(x)  Atomic_Read32((Atomic_uint32 *)(x))
-#  define QPAtomic_WriteOffset(x, y) \
-            Atomic_Write32((Atomic_uint32 *)(x), (uint32)(y))
-#endif
-
-
 /*
  *-----------------------------------------------------------------------------
  *
  * VMCIQueue_CheckAlignment --
  *
- *      Checks if the given queue is aligned to page boundary.
+ *      Checks if the given queue is aligned to page boundary.  Returns TRUE if
+ *      the alignment is good.
  *
  * Results:
  *      TRUE or FALSE.
@@ -198,18 +506,38 @@ VMCIMemcpyFromQueue(void *dest,             // OUT:
 static INLINE Bool
 VMCIQueue_CheckAlignment(const VMCIQueue *queue) // IN:
 {
-   return ((uintptr_t)queue & (PAGE_SIZE - 1)) == 0;
+   /*
+    * Checks if header of the queue is page aligned.
+    */
+   return ((uintptr_t)VMCIQueue_GetHeader(queue) & (PAGE_SIZE - 1)) == 0;
 }
 
 
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQueue_GetPointers --
+ *
+ *      Helper routine for getting the head and the tail pointer for a queue.
+ *     Both the VMCIQueues are needed to get both the pointers for one queue.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
 static INLINE void
 VMCIQueue_GetPointers(const VMCIQueue *produceQ,
                       const VMCIQueue *consumeQ,
                       uint64 *producerTail,
                       uint64 *consumerHead)
 {
-   *producerTail = QPAtomic_ReadOffset(&produceQ->queueHeader.producerTail);
-   *consumerHead = QPAtomic_ReadOffset(&consumeQ->queueHeader.consumerHead);
+   *producerTail = VMCIQueue_ProducerTail(produceQ);
+   *consumerHead = VMCIQueue_ConsumerHead(consumeQ);
 }
 
 
@@ -233,8 +561,8 @@ VMCIQueue_GetPointers(const VMCIQueue *produceQ,
 static INLINE void
 VMCIQueue_ResetPointers(VMCIQueue *queue) // IN:
 {
-   QPAtomic_WriteOffset(&queue->queueHeader.producerTail, CONST64U(0));
-   QPAtomic_WriteOffset(&queue->queueHeader.consumerHead, CONST64U(0));
+   QPAtomic_WriteOffset(&VMCIQueue_GetHeader(queue)->producerTail, CONST64U(0));
+   QPAtomic_WriteOffset(&VMCIQueue_GetHeader(queue)->consumerHead, CONST64U(0));
 }
 
 
@@ -259,7 +587,7 @@ VMCIQueue_Init(const VMCIHandle handle, // IN:
                VMCIQueue *queue)        // IN:
 {
    ASSERT_NOT_IMPLEMENTED(VMCIQueue_CheckAlignment(queue));
-   queue->queueHeader.handle = handle;
+   VMCIQueue_GetHeader(queue)->handle = handle;
    VMCIQueue_ResetPointers(queue);
 }
 
@@ -287,10 +615,8 @@ VMCIQueueFreeSpaceInt(const VMCIQueue *produceQueue, // IN:
                       const uint64 produceQSize,     // IN:
                       uint64 *freeSpace)             // OUT:
 {
-   const uint64 tail =
-      QPAtomic_ReadOffset(&produceQueue->queueHeader.producerTail);
-   const uint64 head =
-      QPAtomic_ReadOffset(&consumeQueue->queueHeader.consumerHead);
+   const uint64 tail = VMCIQueue_ProducerTail(produceQueue);
+   const uint64 head = VMCIQueue_ConsumerHead(consumeQueue);
 
    ASSERT(freeSpace);
 
@@ -384,39 +710,6 @@ VMCIQueue_BufReady(const VMCIQueue *consumeQueue, // IN:
 }
 
 
-/*
- *-----------------------------------------------------------------------------
- *
- * AddPointer --
- *
- *      Helper to add a given offset to a head or tail pointer. Wraps the value
- *      of the pointer around the max size of the queue.
- *
- * Results:
- *      None.
- *
- * Side effects:
- *      None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static INLINE void
-AddPointer(Atomic_uint64 *var, // IN:
-           size_t add,         // IN:
-           uint64 max)         // IN:
-{
-   uint64 newVal = QPAtomic_ReadOffset(var);
-
-   if (newVal >= max - add) {
-      newVal -= max;
-   }
-   newVal += add;
-
-   QPAtomic_WriteOffset(var, newVal);
-}
-
-
 /*
  *-----------------------------------------------------------------------------
  *
@@ -448,8 +741,7 @@ __VMCIQueue_Enqueue(VMCIQueue *produceQueue,               // IN:
 {
    const int64 freeSpace = VMCIQueue_FreeSpace(produceQueue, consumeQueue,
                                                produceQSize);
-   const uint64 tail =
-      QPAtomic_ReadOffset(&produceQueue->queueHeader.producerTail);
+   const uint64 tail = VMCIQueue_ProducerTail(produceQueue);
    size_t written;
 
    if (!freeSpace) {
@@ -469,7 +761,7 @@ __VMCIQueue_Enqueue(VMCIQueue *produceQueue,               // IN:
       memcpyToQueue(produceQueue, tail, buf, 0, tmp);
       memcpyToQueue(produceQueue, 0, buf, tmp, written - tmp);
    }
-   AddPointer(&produceQueue->queueHeader.producerTail, written, produceQSize);
+   AddPointer(&VMCIQueue_GetHeader(produceQueue)->producerTail, written, produceQSize);
    return written;
 }
 
@@ -507,7 +799,7 @@ VMCIQueue_Enqueue(VMCIQueue *produceQueue,       // IN:
 }
 
 
-#if defined(__linux__) && defined(__KERNEL__)
+#if defined (SOLARIS) || (defined(__linux__) && defined(__KERNEL__))
 /*
  *-----------------------------------------------------------------------------
  *
@@ -572,8 +864,7 @@ __VMCIQueue_Dequeue(VMCIQueue *produceQueue,                    // IN:
 {
    const int64 bufReady = VMCIQueue_BufReady(consumeQueue, produceQueue,
                                              consumeQSize);
-   const uint64 head =
-      QPAtomic_ReadOffset(&produceQueue->queueHeader.consumerHead);
+   const uint64 head = VMCIQueue_ConsumerHead(produceQueue);
    size_t written;
 
    if (!bufReady) {
@@ -593,7 +884,7 @@ __VMCIQueue_Dequeue(VMCIQueue *produceQueue,                    // IN:
       memcpyFromQueue(buf, 0, consumeQueue, head, tmp);
       memcpyFromQueue(buf, tmp, consumeQueue, 0, written - tmp);
    }
-   AddPointer(&produceQueue->queueHeader.consumerHead, written, consumeQSize);
+   AddPointer(&VMCIQueue_GetHeader(produceQueue)->consumerHead, written, consumeQSize);
    return written;
 }
 
@@ -631,7 +922,7 @@ VMCIQueue_Dequeue(VMCIQueue *produceQueue,       // IN:
 }
 
 
-#if defined(__linux__) && defined(__KERNEL__)
+#if defined(SOLARIS) || (defined(__linux__) && defined(__KERNEL__))
 /*
  *-----------------------------------------------------------------------------
  *
@@ -665,4 +956,4 @@ VMCIQueue_DequeueV(VMCIQueue *produceQueue,       // IN:
 }
 #endif
 
-#endif /* !_VMCI_QUEUE_PAIR_H_ */
+#endif /* !_PUBLIC_VMCI_QUEUE_PAIR_H_ */
index 2b5c1ad62e5ba1ce9b3ca87b14a8022d31c7f6c6..1facc055adc3d8f689e519585140ec87d0ca5e1f 100644 (file)
@@ -165,10 +165,10 @@ sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
 /*
  * Prototypes
  */
-
 int VSockVmci_GetAFValue(void);
 
 /* Internal functions. */
+static int VSockVmciGetAFValue(void);
 static int VSockVmciRecvDgramCB(void *data, VMCIDatagram *dg);
 #ifdef VMX86_TOOLS
 static int VSockVmciRecvStreamCB(void *data, VMCIDatagram *dg);
@@ -207,6 +207,7 @@ static struct sock *__VSockVmciCreate(struct net *net,
                                       struct socket *sock, gfp_t priority,
                                       unsigned short type);
 #endif
+static inline void VSockVmciTestUnregister(void);
 static int VSockVmciRegisterAddressFamily(void);
 static void VSockVmciUnregisterAddressFamily(void);
 
@@ -428,6 +429,7 @@ typedef struct VSockRecvPktInfo {
 static DECLARE_MUTEX(registrationMutex);
 static int devOpenCount = 0;
 static int vsockVmciSocketCount = 0;
+static int vsockVmciKernClientCount = 0;
 #ifdef VMX86_TOOLS
 static VMCIHandle vmciStreamHandle = { VMCI_INVALID_ID, VMCI_INVALID_ID };
 static Bool vmciDevicePresent = FALSE;
@@ -530,9 +532,12 @@ kmem_cache_t *vsockCachep;
 /*
  *----------------------------------------------------------------------------
  *
- * VSockVmci_GetAFValue --
+ * VMCISock_GetAFValue --
  *
- *      Returns the address family value being used.
+ *      Kernel interface that allows external kernel modules to get the current
+ *      VMCI Sockets address family.
+ *      This version of the function is exported to kernel clients and should not
+ *      change.
  *
  * Results:
  *      The address family on success, a negative error on failure.
@@ -544,18 +549,141 @@ kmem_cache_t *vsockCachep;
  */
 
 int
-VSockVmci_GetAFValue(void)
+VMCISock_GetAFValue(void)
 {
    int afvalue;
 
    down(&registrationMutex);
 
+   /*
+    * Kernel clients are required to explicitly register themselves before they
+    * can use VMCI Sockets.
+    */
+   if (vsockVmciKernClientCount <= 0) {
+      afvalue = -1;
+      goto exit;
+   }
+
+   afvalue = VSockVmciGetAFValue();
+
+exit:
+   up(&registrationMutex);
+   return afvalue;
+
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VMCISock_KernelRegister --
+ *
+ *      Allows a kernel client to register with VMCI Sockets. Must be called
+ *      before VMCISock_GetAFValue within a kernel module. Note that we don't
+ *      actually register the address family until the first time the module
+ *      needs to use it.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+VMCISock_KernelRegister(void)
+{
+   down(&registrationMutex);
+   vsockVmciKernClientCount++;
+   up(&registrationMutex);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VMCISock_KernelDeregister --
+ *
+ *      Allows a kernel client to unregister with VMCI Sockets. Every call
+ *      to VMCISock_KernRegister must be matched with a call to
+ *      VMCISock_KernUnregister.
+ *
+ * Results:
+        None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+VMCISock_KernelDeregister(void)
+{
+   down(&registrationMutex);
+   vsockVmciKernClientCount--;
+   VSockVmciTestUnregister();
+   up(&registrationMutex);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciGetAFValue --
+ *
+ *      Returns the address family value being used.
+ *      Note: The registration mutex must be held when calling this function.
+ *
+ * Results:
+ *      The address family on success, a negative error on failure.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+VSockVmciGetAFValue(void)
+{
+   int afvalue;
+
    afvalue = vsockVmciFamilyOps.family;
    if (!VSOCK_AF_IS_REGISTERED(afvalue)) {
       afvalue = VSockVmciRegisterAddressFamily();
    }
 
+   return afvalue;
+}
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmci_GetAFValue --
+ *
+ *      Returns the address family value being used.
+ *
+ * Results:
+ *      The address family on success, a negative error on failure.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+VSockVmci_GetAFValue(void)
+{
+   int afvalue;
+
+   down(&registrationMutex);
+   afvalue = VSockVmciGetAFValue();
    up(&registrationMutex);
+
    return afvalue;
 }
 
@@ -586,7 +714,8 @@ VSockVmci_GetAFValue(void)
 static inline void
 VSockVmciTestUnregister(void)
 {
-   if (devOpenCount <= 0 && vsockVmciSocketCount <= 0) {
+   if (devOpenCount <= 0 && vsockVmciSocketCount <= 0 &&
+       vsockVmciKernClientCount <= 0) {
       if (VSOCK_AF_IS_REGISTERED(vsockVmciFamilyOps.family)) {
          VSockVmciUnregisterAddressFamily();
       }
@@ -5273,3 +5402,10 @@ MODULE_AUTHOR("VMware, Inc.");
 MODULE_DESCRIPTION("VMware Virtual Socket Family");
 MODULE_VERSION(VSOCK_DRIVER_VERSION_STRING);
 MODULE_LICENSE("GPL v2");
+/*
+ * Starting with SLE10sp2, Novell requires that IHVs sign a support agreement
+ * with them and mark their kernel modules as externally supported via a
+ * change to the module header. If this isn't done, the module will not load
+ * by default (i.e., neither mkinitrd nor modprobe will accept it).
+ */
+MODULE_INFO(supported, "external");
index bdc13fe30d8ace7767775ac10a26a224299efa36..36256142699463f397798a2183aa215efc7261e3 100644 (file)
 
 /*
  * Address structure for VSockets VMCI sockets. The address family should be
- * set to AF_VMCI.
+ * set to AF_VMCI. The structure members should all align on their natural
+ * boundaries without resorting to compiler packing directives.
  */
+
 struct sockaddr_vm {
+#if defined(__APPLE__)
+   unsigned char svm_len;                           // Mac OS has the length first.
+#endif // __APPLE__
    sa_family_t svm_family;                          // AF_VMCI.
    unsigned short svm_reserved1;                    // Reserved.
    unsigned int svm_port;                           // Port.
    unsigned int svm_cid;                            // Context id.
    unsigned char svm_zero[sizeof(struct sockaddr) - // Same size as sockaddr.
-                          sizeof(sa_family_t) -
-                          sizeof(unsigned short) -
-                          sizeof(unsigned int) -
-                          sizeof(unsigned int)];
+#if defined(__APPLE__)
+                             sizeof(unsigned char) -
+#endif // __APPLE__
+                             sizeof(sa_family_t) -
+                             sizeof(unsigned short) -
+                             sizeof(unsigned int) -
+                             sizeof(unsigned int)];
 };
 
 
@@ -135,7 +143,11 @@ struct sockaddr_vm {
 #  endif // WINNT_DDK
 #else // _WIN32
 #if defined(linux) && !defined(VMKERNEL)
-#  ifndef __KERNEL__
+#  ifdef __KERNEL__
+   void VMCISock_KernelRegister(void);
+   void VMCISock_KernelDeregister(void);
+   int VMCISock_GetAFValue(void);
+#  else // __KERNEL__
 #  include <sys/types.h>
 #  include <sys/stat.h>
 #  include <fcntl.h>
@@ -145,6 +157,7 @@ struct sockaddr_vm {
 #  include <stdio.h>
 
 #  define VMCI_SOCKETS_DEFAULT_DEVICE      "/dev/vsock"
+#  define VMCI_SOCKETS_CLASSIC_ESX_DEVICE  "/vmfs/devices/char/vsock/vsock"
 #  define IOCTL_VMCI_SOCKETS_GET_AF_VALUE  1976
 #  define IOCTL_VMCI_SOCKETS_GET_LOCAL_CID 1977
 
@@ -187,7 +200,10 @@ struct sockaddr_vm {
 
       fd = open(VMCI_SOCKETS_DEFAULT_DEVICE, O_RDWR);
       if (fd < 0) {
-         return -1;
+         fd = open(VMCI_SOCKETS_CLASSIC_ESX_DEVICE, O_RDWR);
+         if (fd < 0) {
+            return -1;
+         }
       }
 
       if (ioctl(fd, IOCTL_VMCI_SOCKETS_GET_AF_VALUE, &family) < 0) {
@@ -223,7 +239,10 @@ struct sockaddr_vm {
 
       fd = open(VMCI_SOCKETS_DEFAULT_DEVICE, O_RDWR);
       if (fd < 0) {
-         return VMADDR_CID_ANY;
+         fd = open(VMCI_SOCKETS_CLASSIC_ESX_DEVICE, O_RDWR);
+         if (fd < 0) {
+            return VMADDR_CID_ANY;
+         }
       }
 
       if (ioctl(fd, IOCTL_VMCI_SOCKETS_GET_LOCAL_CID, &contextId) < 0) {
index c86a09a5825d28b06566557567df2cddf3b05e3e..d99018d71c6818e4dfd6998e77745c75de6c0805 100644 (file)
@@ -69,7 +69,7 @@ VSockAddr_Init(struct sockaddr_vm *addr, // OUT
    ASSERT(addr);
    memset(addr, 0, sizeof *addr);
    VSockAddr_InitNoFamily(addr, cid, port);
-   addr->svm_family = VMCISock_GetAFValue();
+   addr->svm_family = VMCISockGetAFValueInt();
    VSOCK_ADDR_ASSERT(addr);
 }
 
@@ -137,7 +137,7 @@ VSockAddr_Validate(const struct sockaddr_vm *addr) // IN
       goto exit;
    }
 
-   if (VMCISock_GetAFValue() != addr->svm_family) {
+   if (VMCISockGetAFValueInt() != addr->svm_family) {
       err = EAFNOSUPPORT;
       goto exit;
    }
index e4a091d520f517d3369fd061392ff5a5e07a2bd6..c60f3bcf02905b694beb9e4dc1e1a4f6a72ba7a8 100644 (file)
 #ifndef _VSOCK_COMMON_H_
 #define _VSOCK_COMMON_H_
 
+/*
+ * VMCISockGetAFValueInt is defined separately from VMCISock_GetAFValue because
+ * it is used in several different contexts. In particular it is called from
+ * vsockAddr.c which gets compiled into both our kernel modules as well as
+ * the user level vsock library. In the linux kernel we need different behavior
+ * than external kernel modules using VMCI Sockets api inside the kernel.
+ */
 
 #if defined(_WIN32)
 #  define VMCI_SOCKETS_AF_VALUE 28
 #     define _INC_WINDOWS
 #     include "vmci_queue_pair.h"
       /* In the kernel we can't call into the provider. */
-#     define VMCISock_GetAFValue() VMCI_SOCKETS_AF_VALUE
+#     define VMCISockGetAFValueInt() VMCI_SOCKETS_AF_VALUE
 #  else // WINNT_DDK
+      /* In userland, just use the normal exported userlevel api. */
+#     define VMCISockGetAFValueInt() VMCISock_GetAFValue()
 #     include <windows.h>
 #  endif // WINNT_DDK
 #  define Uint64ToPtr(_ui) ((void *)(uint64)(_ui))
@@ -62,7 +71,7 @@
 #  include "uwvmkAPI.h"
 #  define VMCI_SOCKETS_AF_VALUE AF_VMCI /* Defined in uwvmkAPI.h. */
    /* The address family is fixed in the vmkernel. */
-#  define VMCISock_GetAFValue() VMCI_SOCKETS_AF_VALUE
+#  define VMCISockGetAFValueInt() VMCI_SOCKETS_AF_VALUE
 #  include "vmciHostKernelAPI.h"
 #  define Uint64ToPtr(_ui) ((void *)(uint64)(_ui))
 #  define PtrToUint64(_p)  ((uint64)(_p))
 #     if defined(VMX86_TOOLS)
 #        include "vmci_queue_pair.h"
 #     endif
-      /*
-       * In the kernel we call back into af_vsock.c to get the address family
-       * being used.  Otherwise an ioctl(2) is performed (see vmci_sockets.h).
-       */
+    /*
+     * In the kernel we call back into af_vsock.c to get the address family
+     * being used.  Otherwise an ioctl(2) is performed (see vmci_sockets.h).
+     */
       extern int VSockVmci_GetAFValue(void);
-#     define VMCISock_GetAFValue() VSockVmci_GetAFValue()
+#     define VMCISockGetAFValueInt() VSockVmci_GetAFValue()
+#  else // __KERNEL__
+      /* In userland, just use the normal exported userlevel api. */
+#     define VMCISockGetAFValueInt() VMCISock_GetAFValue()
 #  endif
 #endif // linux
 #endif // VMKERNEL
index b138a28ac94c863f2a69f1fb737fd178e229687f..86bb3a6dab355f3c8f5029808ed581db937f92a1 100644 (file)
 
 
 /*
- * Socket states and flags.  Note that MSG_WAITALL is only supported on 2K3,
+ * Socket states and flags.  Note that MSG_WAITALL is only defined on 2K3,
  * XP-SP2 and above.  Since we currently build for 2K to maintain backwards
- * compatibility, it will always be 0.
+ * compatibility, we pull the value from the newer header.
  */
 #if defined(_WIN32)
 #  define MSG_DONTWAIT        0
 #  define MSG_NOSIGNAL        0
 #  if (_WIN32_WINNT < 0x0502)
-#     define MSG_WAITALL      0
+#     define MSG_WAITALL      0x8
 #  endif
 #endif
 
diff --git a/open-vm-tools/modules/solaris/vmhgfs/COPYING.CDDL b/open-vm-tools/modules/solaris/vmhgfs/COPYING.CDDL
new file mode 100644 (file)
index 0000000..883d599
--- /dev/null
@@ -0,0 +1,365 @@
+
+COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
+
+1. Definitions.
+
+    1.1. "Contributor" means each individual or entity that creates
+         or contributes to the creation of Modifications.
+
+    1.2. "Contributor Version" means the combination of the Original
+         Software, prior Modifications used by a Contributor (if any),
+         and the Modifications made by that particular Contributor.
+
+    1.3. "Covered Software" means (a) the Original Software, or (b)
+         Modifications, or (c) the combination of files containing
+         Original Software with files containing Modifications, in
+         each case including portions thereof.
+
+    1.4. "Executable" means the Covered Software in any form other
+         than Source Code.
+
+    1.5. "Initial Developer" means the individual or entity that first
+         makes Original Software available under this License.
+
+    1.6. "Larger Work" means a work which combines Covered Software or
+         portions thereof with code not governed by the terms of this
+         License.
+
+    1.7. "License" means this document.
+
+    1.8. "Licensable" means having the right to grant, to the maximum
+         extent possible, whether at the time of the initial grant or
+         subsequently acquired, any and all of the rights conveyed
+         herein.
+
+    1.9. "Modifications" means the Source Code and Executable form of
+         any of the following:
+
+        A. Any file that results from an addition to, deletion from or
+           modification of the contents of a file containing Original
+           Software or previous Modifications;
+
+        B. Any new file that contains any part of the Original
+           Software or previous Modifications; or
+
+        C. Any new file that is contributed or otherwise made
+           available under the terms of this License.
+
+    1.10. "Original Software" means the Source Code and Executable
+          form of computer software code that is originally released
+          under this License.
+
+    1.11. "Patent Claims" means any patent claim(s), now owned or
+          hereafter acquired, including without limitation, method,
+          process, and apparatus claims, in any patent Licensable by
+          grantor.
+
+    1.12. "Source Code" means (a) the common form of computer software
+          code in which modifications are made and (b) associated
+          documentation included in or with such code.
+
+    1.13. "You" (or "Your") means an individual or a legal entity
+          exercising rights under, and complying with all of the terms
+          of, this License.  For legal entities, "You" includes any
+          entity which controls, is controlled by, or is under common
+          control with You.  For purposes of this definition,
+          "control" means (a) the power, direct or indirect, to cause
+          the direction or management of such entity, whether by
+          contract or otherwise, or (b) ownership of more than fifty
+          percent (50%) of the outstanding shares or beneficial
+          ownership of such entity.
+
+2. License Grants.
+
+    2.1. The Initial Developer Grant.
+
+    Conditioned upon Your compliance with Section 3.1 below and
+    subject to third party intellectual property claims, the Initial
+    Developer hereby grants You a world-wide, royalty-free,
+    non-exclusive license:
+
+        (a) under intellectual property rights (other than patent or
+            trademark) Licensable by Initial Developer, to use,
+            reproduce, modify, display, perform, sublicense and
+            distribute the Original Software (or portions thereof),
+            with or without Modifications, and/or as part of a Larger
+            Work; and
+
+        (b) under Patent Claims infringed by the making, using or
+            selling of Original Software, to make, have made, use,
+            practice, sell, and offer for sale, and/or otherwise
+            dispose of the Original Software (or portions thereof).
+
+        (c) The licenses granted in Sections 2.1(a) and (b) are
+            effective on the date Initial Developer first distributes
+            or otherwise makes the Original Software available to a
+            third party under the terms of this License.
+
+        (d) Notwithstanding Section 2.1(b) above, no patent license is
+            granted: (1) for code that You delete from the Original
+            Software, or (2) for infringements caused by: (i) the
+            modification of the Original Software, or (ii) the
+            combination of the Original Software with other software
+            or devices.
+
+    2.2. Contributor Grant.
+
+    Conditioned upon Your compliance with Section 3.1 below and
+    subject to third party intellectual property claims, each
+    Contributor hereby grants You a world-wide, royalty-free,
+    non-exclusive license:
+
+        (a) under intellectual property rights (other than patent or
+            trademark) Licensable by Contributor to use, reproduce,
+            modify, display, perform, sublicense and distribute the
+            Modifications created by such Contributor (or portions
+            thereof), either on an unmodified basis, with other
+            Modifications, as Covered Software and/or as part of a
+            Larger Work; and
+
+        (b) under Patent Claims infringed by the making, using, or
+            selling of Modifications made by that Contributor either
+            alone and/or in combination with its Contributor Version
+            (or portions of such combination), to make, use, sell,
+            offer for sale, have made, and/or otherwise dispose of:
+            (1) Modifications made by that Contributor (or portions
+            thereof); and (2) the combination of Modifications made by
+            that Contributor with its Contributor Version (or portions
+            of such combination).
+
+        (c) The licenses granted in Sections 2.2(a) and 2.2(b) are
+            effective on the date Contributor first distributes or
+            otherwise makes the Modifications available to a third
+            party.
+
+        (d) Notwithstanding Section 2.2(b) above, no patent license is
+            granted: (1) for any code that Contributor has deleted
+            from the Contributor Version; (2) for infringements caused
+            by: (i) third party modifications of Contributor Version,
+            or (ii) the combination of Modifications made by that
+            Contributor with other software (except as part of the
+            Contributor Version) or other devices; or (3) under Patent
+            Claims infringed by Covered Software in the absence of
+            Modifications made by that Contributor.
+
+3. Distribution Obligations.
+
+    3.1. Availability of Source Code.
+
+    Any Covered Software that You distribute or otherwise make
+    available in Executable form must also be made available in Source
+    Code form and that Source Code form must be distributed only under
+    the terms of this License.  You must include a copy of this
+    License with every copy of the Source Code form of the Covered
+    Software You distribute or otherwise make available.  You must
+    inform recipients of any such Covered Software in Executable form
+    as to how they can obtain such Covered Software in Source Code
+    form in a reasonable manner on or through a medium customarily
+    used for software exchange.
+
+    3.2. Modifications.
+
+    The Modifications that You create or to which You contribute are
+    governed by the terms of this License.  You represent that You
+    believe Your Modifications are Your original creation(s) and/or
+    You have sufficient rights to grant the rights conveyed by this
+    License.
+
+    3.3. Required Notices.
+
+    You must include a notice in each of Your Modifications that
+    identifies You as the Contributor of the Modification.  You may
+    not remove or alter any copyright, patent or trademark notices
+    contained within the Covered Software, or any notices of licensing
+    or any descriptive text giving attribution to any Contributor or
+    the Initial Developer.
+
+    3.4. Application of Additional Terms.
+
+    You may not offer or impose any terms on any Covered Software in
+    Source Code form that alters or restricts the applicable version
+    of this License or the recipients' rights hereunder.  You may
+    choose to offer, and to charge a fee for, warranty, support,
+    indemnity or liability obligations to one or more recipients of
+    Covered Software.  However, you may do so only on Your own behalf,
+    and not on behalf of the Initial Developer or any Contributor.
+    You must make it absolutely clear that any such warranty, support,
+    indemnity or liability obligation is offered by You alone, and You
+    hereby agree to indemnify the Initial Developer and every
+    Contributor for any liability incurred by the Initial Developer or
+    such Contributor as a result of warranty, support, indemnity or
+    liability terms You offer.
+
+    3.5. Distribution of Executable Versions.
+
+    You may distribute the Executable form of the Covered Software
+    under the terms of this License or under the terms of a license of
+    Your choice, which may contain terms different from this License,
+    provided that You are in compliance with the terms of this License
+    and that the license for the Executable form does not attempt to
+    limit or alter the recipient's rights in the Source Code form from
+    the rights set forth in this License.  If You distribute the
+    Covered Software in Executable form under a different license, You
+    must make it absolutely clear that any terms which differ from
+    this License are offered by You alone, not by the Initial
+    Developer or Contributor.  You hereby agree to indemnify the
+    Initial Developer and every Contributor for any liability incurred
+    by the Initial Developer or such Contributor as a result of any
+    such terms You offer.
+
+    3.6. Larger Works.
+
+    You may create a Larger Work by combining Covered Software with
+    other code not governed by the terms of this License and
+    distribute the Larger Work as a single product.  In such a case,
+    You must make sure the requirements of this License are fulfilled
+    for the Covered Software.
+
+4. Versions of the License.
+
+    4.1. New Versions.
+
+    Sun Microsystems, Inc. is the initial license steward and may
+    publish revised and/or new versions of this License from time to
+    time.  Each version will be given a distinguishing version number.
+    Except as provided in Section 4.3, no one other than the license
+    steward has the right to modify this License.
+
+    4.2. Effect of New Versions.
+
+    You may always continue to use, distribute or otherwise make the
+    Covered Software available under the terms of the version of the
+    License under which You originally received the Covered Software.
+    If the Initial Developer includes a notice in the Original
+    Software prohibiting it from being distributed or otherwise made
+    available under any subsequent version of the License, You must
+    distribute and make the Covered Software available under the terms
+    of the version of the License under which You originally received
+    the Covered Software.  Otherwise, You may also choose to use,
+    distribute or otherwise make the Covered Software available under
+    the terms of any subsequent version of the License published by
+    the license steward.
+
+    4.3. Modified Versions.
+
+    When You are an Initial Developer and You want to create a new
+    license for Your Original Software, You may create and use a
+    modified version of this License if You: (a) rename the license
+    and remove any references to the name of the license steward
+    (except to note that the license differs from this License); and
+    (b) otherwise make it clear that the license contains terms which
+    differ from this License.
+
+5. DISCLAIMER OF WARRANTY.
+
+    COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS"
+    BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+    INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED
+    SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR
+    PURPOSE OR NON-INFRINGING.  THE ENTIRE RISK AS TO THE QUALITY AND
+    PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU.  SHOULD ANY
+    COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE
+    INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY
+    NECESSARY SERVICING, REPAIR OR CORRECTION.  THIS DISCLAIMER OF
+    WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE.  NO USE OF
+    ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS
+    DISCLAIMER.
+
+6. TERMINATION.
+
+    6.1. This License and the rights granted hereunder will terminate
+    automatically if You fail to comply with terms herein and fail to
+    cure such breach within 30 days of becoming aware of the breach.
+    Provisions which, by their nature, must remain in effect beyond
+    the termination of this License shall survive.
+
+    6.2. If You assert a patent infringement claim (excluding
+    declaratory judgment actions) against Initial Developer or a
+    Contributor (the Initial Developer or Contributor against whom You
+    assert such claim is referred to as "Participant") alleging that
+    the Participant Software (meaning the Contributor Version where
+    the Participant is a Contributor or the Original Software where
+    the Participant is the Initial Developer) directly or indirectly
+    infringes any patent, then any and all rights granted directly or
+    indirectly to You by such Participant, the Initial Developer (if
+    the Initial Developer is not the Participant) and all Contributors
+    under Sections 2.1 and/or 2.2 of this License shall, upon 60 days
+    notice from Participant terminate prospectively and automatically
+    at the expiration of such 60 day notice period, unless if within
+    such 60 day period You withdraw Your claim with respect to the
+    Participant Software against such Participant either unilaterally
+    or pursuant to a written agreement with Participant.
+
+    6.3. In the event of termination under Sections 6.1 or 6.2 above,
+    all end user licenses that have been validly granted by You or any
+    distributor hereunder prior to termination (excluding licenses
+    granted to You by any distributor) shall survive termination.
+
+7. LIMITATION OF LIABILITY.
+
+    UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+    (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE
+    INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF
+    COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE
+    LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR
+    CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT
+    LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, WORK
+    STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+    COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+    INFORMED OF THE POSSIBILITY OF SUCH DAMAGES.  THIS LIMITATION OF
+    LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL
+    INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT
+    APPLICABLE LAW PROHIBITS SUCH LIMITATION.  SOME JURISDICTIONS DO
+    NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR
+    CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT
+    APPLY TO YOU.
+
+8. U.S. GOVERNMENT END USERS.
+
+    The Covered Software is a "commercial item," as that term is
+    defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial
+    computer software" (as that term is defined at 48
+    C.F.R. 252.227-7014(a)(1)) and "commercial computer software
+    documentation" as such terms are used in 48 C.F.R. 12.212
+    (Sept. 1995).  Consistent with 48 C.F.R. 12.212 and 48
+    C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all
+    U.S. Government End Users acquire Covered Software with only those
+    rights set forth herein.  This U.S. Government Rights clause is in
+    lieu of, and supersedes, any other FAR, DFAR, or other clause or
+    provision that addresses Government rights in computer software
+    under this License.
+
+9. MISCELLANEOUS.
+
+    This License represents the complete agreement concerning subject
+    matter hereof.  If any provision of this License is held to be
+    unenforceable, such provision shall be reformed only to the extent
+    necessary to make it enforceable.  This License shall be governed
+    by the law of the jurisdiction specified in a notice contained
+    within the Original Software (except to the extent applicable law,
+    if any, provides otherwise), excluding such jurisdiction's
+    conflict-of-law provisions.  Any litigation relating to this
+    License shall be subject to the jurisdiction of the courts located
+    in the jurisdiction and venue specified in a notice contained
+    within the Original Software, with the losing party responsible
+    for costs, including, without limitation, court costs and
+    reasonable attorneys' fees and expenses.  The application of the
+    United Nations Convention on Contracts for the International Sale
+    of Goods is expressly excluded.  Any law or regulation which
+    provides that the language of a contract shall be construed
+    against the drafter shall not apply to this License.  You agree
+    that You alone are responsible for compliance with the United
+    States export administration regulations (and the export control
+    laws and regulation of any other countries) when You use,
+    distribute or otherwise make available any Covered Software.
+
+10. RESPONSIBILITY FOR CLAIMS.
+
+    As between Initial Developer and the Contributors, each party is
+    responsible for claims and damages arising, directly or
+    indirectly, out of its utilization of rights under this License
+    and You agree to work with Initial Developer and Contributors to
+    distribute such responsibility on an equitable basis.  Nothing
+    herein is intended or shall be deemed to constitute any admission
+    of liability.
+
diff --git a/open-vm-tools/modules/solaris/vmhgfs/Makefile b/open-vm-tools/modules/solaris/vmhgfs/Makefile
new file mode 100644 (file)
index 0000000..bf48b94
--- /dev/null
@@ -0,0 +1,145 @@
+#!/usr/bin/make -f
+##########################################################
+# Copyright (C) 2008 VMware, Inc. All rights reserved.
+#
+# The contents of this file are subject to the terms of the Common
+# Development and Distribution License (the "License") version 1.0
+# and no later version.  You may not use this file except in
+# compliance with the License.
+#
+# You can obtain a copy of the License at
+#         http://www.opensource.org/licenses/cddl1.php
+#
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+##########################################################
+
+##
+## General build locations and variables
+##
+
+MODULE   := vmhgfs
+CFLAGS   :=
+LDFLAGS  :=
+
+# Solaris version defines for in-code #ifdefs (default to Solaris 9)
+ifeq ($(shell echo "$(VM_UNAME)" | cut -c-4),5.11)
+CFLAGS   += -DSOL11
+else
+ifeq ($(shell echo "$(VM_UNAME)" | cut -c-4),5.10)
+CFLAGS   += -DSOL10
+else
+CFLAGS   += -DSOL9
+# we don't support Solaris 9 (we could but we use memcpy/memset
+# and we'd need stubs to get the module to load into the kernel).
+$(error "This makefile is only used for Solaris 10 and 11")
+endif
+endif
+
+CFLAGS   += -ffreestanding
+CFLAGS   += -nodefaultlibs
+
+CFLAGS   += -O2
+CFLAGS   += -Wall -Werror
+CFLAGS   += $(GLOBAL_DEFS)
+CFLAGS   += $(CC_WARNINGS)
+CFLAGS   += -DVMX86_TOOLS
+CFLAGS   += -D_KERNEL
+
+ifdef VMX86_DEVEL
+CFLAGS   += -DVMX86_DEVEL
+endif
+ifdef VMX86_DEBUG              # For assertions
+CFLAGS   += -DVMX86_DEBUG
+endif
+ifdef VMX86_LOG                        # For debug logging
+CFLAGS   += -DVM_DEBUGGING_ON
+endif
+
+##
+## Objects needed to build the HGFS kernel module
+##
+SOLHGFS_OBJS := debug.o
+SOLHGFS_OBJS += device.o
+SOLHGFS_OBJS += filesystem.o
+SOLHGFS_OBJS += hgfsState.o
+SOLHGFS_OBJS += module.o
+SOLHGFS_OBJS += request.o
+SOLHGFS_OBJS += vnode.o
+SOLHGFS_OBJS += cpName.o
+SOLHGFS_OBJS += cpNameLinux.o
+SOLHGFS_OBJS += dbllnklst.o
+SOLHGFS_OBJS += hgfsEscape.o
+SOLHGFS_OBJS += hgfsUtil.o
+SOLHGFS_OBJS += sha1.o
+
+SOLHGFS_32_OBJS := $(addprefix i386/, $(SOLHGFS_OBJS))
+SOLHGFS_64_OBJS := $(addprefix amd64/, $(SOLHGFS_OBJS))
+
+MODULE_32 := i386/$(MODULE)
+MODULE_64 := amd64/$(MODULE)
+
+CFLAGS_32  := $(CFLAGS)
+CFLAGS_32  += -m32
+LDFLAGS_32 := $(LDFLAGS)
+
+CFLAGS_64  := $(CFLAGS)
+CFLAGS_64  += -m64
+CFLAGS_64  += -mcmodel=kernel
+CFLAGS_64  += -mno-red-zone
+LDFLAGS_64 := $(LDFLAGS)
+ifdef HAVE_GNU_LD
+LDFLAGS_64 += -m elf_x86_64
+else
+LDFLAGS_64 += -64
+endif
+
+##
+## Building targets
+##
+.PHONY: all prepare_dirs clean install
+
+all: prepare_dirs $(MODULE_32) $(MODULE_64)
+
+prepare_dirs:
+       @echo "Creating build directories"
+       mkdir -p i386
+       mkdir -p amd64
+
+# Build just the module for 32 bits kernel
+$(MODULE_32): $(SOLHGFS_32_OBJS)
+       @echo "Linking          $(MODULE_32)"
+       $(LD) $(LDFLAGS_32) -r -o $(MODULE_32) $(SOLHGFS_32_OBJS)
+
+$(SOLHGFS_32_OBJS): i386/%.o: %.c
+       @echo "Compiling        $(<F)"
+       $(CC) $(CFLAGS_32) -c $< -o $@
+
+# Now the same for 64 bits kernel
+$(MODULE_64): $(SOLHGFS_64_OBJS)
+       @echo "Linking          $(MODULE_64)"
+       $(LD) $(LDFLAGS_64) -r -o $(MODULE_64) $(SOLHGFS_64_OBJS)
+
+$(SOLHGFS_64_OBJS): amd64/%.o: %.c
+       @echo "Compiling        $(<F)"
+       $(CC) $(CFLAGS_64) -c $< -o $@
+
+clean:
+       @echo "Cleaning directories"
+       @rm -f $(MODULE_32) $(SOLHGFS_32_OBJS) i386
+       @rm -r $(MODULE_64) $(SOLHGFS_32_OBJS) amd64
+
+install:
+       @echo "Installing modules"
+       cp $(MODULE_32) /kernel/drv/
+       chmod 755 /kernel/drv/$(MODULE)
+       cp $(MODULE_64) /kernel/drv/amd64
+       chmod 755 /kernel/drv/amd64/$(MODULE)
+       cp docs/hgfs.conf /kernel/drv/vmhgfs.conf
+       chmod 644 /kernel/drv/vmhgfs.conf
+       grep $(MODULE) /etc/name_to_major > /dev/null 2>&1; \
+       if [ ! $$? = 0 ]; then \
+          cat docs/append-to-devlink.tab >> /etc/devlink.tab; \
+          /usr/sbin/add_drv -m "* 0644 root sys" vmhgfs; \
+       fi
diff --git a/open-vm-tools/modules/solaris/vmhgfs/cpName.c b/open-vm-tools/modules/solaris/vmhgfs/cpName.c
new file mode 100644 (file)
index 0000000..5fdac8a
--- /dev/null
@@ -0,0 +1,445 @@
+/*********************************************************
+ * Copyright (C) 1998 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * cpName.c --
+ *
+ *    Shared portions of cross-platform name conversion routines used
+ *    by hgfs. [bac]
+ *
+ */
+
+#ifdef sun
+#include <string.h>
+#endif
+
+#include "cpName.h"
+#include "cpNameInt.h"
+#include "vm_assert.h"
+#include "hgfsEscape.h"
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CPName_GetComponent --
+ *
+ *    Get the next component of the CP name.
+ *
+ *    Returns the length of the component starting with the begin
+ *    pointer, and a pointer to the next component in the buffer, if
+ *    any. The "next" pointer is set to "end" if there is no next
+ *    component.
+ *
+ * Results:
+ *    length (not including NUL termination) >= 0 of next
+ *    component on success.
+ *    error < 0 on failure (invalid component).
+ *
+ * Side effects:
+ *    None
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+CPName_GetComponent(char const *begin,   // IN: Beginning of buffer
+                    char const *end,     // IN: End of buffer
+                    char const **next)   // OUT: Start of next component
+{
+   char const *walk;
+   char const *myNext;
+   size_t len;
+
+   ASSERT(begin);
+   ASSERT(end);
+   ASSERT(next);
+   ASSERT(begin <= end);
+
+   for (walk = begin; ; walk++) {
+      if (walk == end) {
+         /* End of buffer. No NUL was found */
+
+         myNext = end;
+         break;
+      }
+
+      if (*walk == '\0') {
+         /* Found a NUL */
+
+         if (walk == begin) {
+            Log("CPName_GetComponent: error: first char can't be NUL\n");
+            return -1;
+         }
+
+         myNext = walk + 1;
+         if (myNext == end) {
+            /* Last character in the buffer is not allowed to be NUL */
+            return -1;
+         }
+
+         break;
+      }
+   }
+
+   len = walk - begin;
+
+   *next = myNext;
+   return ((int) len);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CPNameEscapeAndConvertFrom --
+ *
+ *    Converts a cross-platform name representation into a string for
+ *    use in the local filesystem.
+ *    Escapes illegal characters as a part of convertion.
+ *    This is a cross-platform implementation and takes the path separator
+ *    argument as an argument. The path separator is prepended before each
+ *    additional path component, so this function never adds a trailing path
+ *    separator.
+ *
+ * Results:
+ *    0 on success.
+ *    error < 0 on failure (the converted string did not fit in
+ *    the buffer provided or the input was invalid).
+ *
+ * Side effects:
+ *    None
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+CPNameEscapeAndConvertFrom(char const **bufIn, // IN/OUT: Input to convert
+                           size_t *inSize,     // IN/OUT: Size of input
+                           size_t *outSize,    // IN/OUT: Size of output buffer
+                           char **bufOut,      // IN/OUT: Output buffer
+                           char pathSep)       // IN: Path separator character
+{
+   int result;
+   size_t inputSize;
+   inputSize = HgfsEscape_GetSize(*bufIn, *inSize);
+   if (inputSize != 0) {
+      char *savedBufOut = *bufOut;
+      char const *savedOutConst = savedBufOut;
+      size_t savedOutSize = *outSize;
+      if (inputSize > *outSize) {
+         Log("CPNameEscapeAndConvertFrom: error: not enough room for escaping\n");
+         return -1;
+      }
+
+      /* Leaving space for the leading path separator, thus output to savedBufOut + 1. */
+      *inSize = HgfsEscape_Do(*bufIn, *inSize, savedOutSize, savedBufOut + 1);
+      result = CPNameConvertFrom(&savedOutConst, inSize, outSize, bufOut, pathSep);
+      *bufIn += *inSize;
+      *inSize = 0;
+   } else {
+      result = CPNameConvertFrom(bufIn, inSize, outSize, bufOut, pathSep);
+   }
+   return result;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CPNameConvertFrom --
+ *
+ *    Converts a cross-platform name representation into a string for
+ *    use in the local filesystem. This is a cross-platform
+ *    implementation and takes the path separator argument as an
+ *    argument. The path separator is prepended before each additional
+ *    path component, so this function never adds a trailing path
+ *    separator.
+ *
+ * Results:
+ *    0 on success.
+ *    error < 0 on failure (the converted string did not fit in
+ *    the buffer provided or the input was invalid).
+ *
+ * Side effects:
+ *    None
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+CPNameConvertFrom(char const **bufIn, // IN/OUT: Input to convert
+                  size_t *inSize,     // IN/OUT: Size of input
+                  size_t *outSize,    // IN/OUT: Size of output buffer
+                  char **bufOut,      // IN/OUT: Output buffer
+                  char pathSep)       // IN: Path separator character
+{
+   char const *in;
+   char const *inEnd;
+   size_t myOutSize;
+   char *out;
+   Bool inPlaceConvertion = (*bufIn == *bufOut);
+
+   ASSERT(bufIn);
+   ASSERT(inSize);
+   ASSERT(outSize);
+   ASSERT(bufOut);
+
+   in = *bufIn;
+   if (inPlaceConvertion) {
+      in++; // Skip place for the leading path separator.
+   }
+   inEnd = in + *inSize;
+   myOutSize = *outSize;
+   out = *bufOut;
+
+   for (;;) {
+      char const *next;
+      int len;
+      int newLen;
+
+      len = CPName_GetComponent(in, inEnd, &next);
+      if (len < 0) {
+         Log("CPNameConvertFrom: error: get next component failed\n");
+         return len;
+      }
+
+      /* Bug 27926 - preventing escaping from shared folder. */
+      if ((len == 1 && *in == '.') ||
+          (len == 2 && in[0] == '.' && in[1] == '.')) {
+         Log("CPNameConvertFrom: error: found dot/dotdot\n");
+         return -1;
+      }
+
+      if (len == 0) {
+         /* No more component */
+         break;
+      }
+
+      newLen = ((int) myOutSize) - len - 1;
+      if (newLen < 0) {
+         Log("CPNameConvertFrom: error: not enough room\n");
+         return -1;
+      }
+      myOutSize = (size_t) newLen;
+
+      *out++ = pathSep;
+      if (!inPlaceConvertion) {
+         memcpy(out, in, len);
+      }
+      out += len;
+
+      in = next;
+   }
+
+   /* NUL terminate */
+   if (myOutSize < 1) {
+      Log("CPNameConvertFrom: error: not enough room\n");
+      return -1;
+   }
+   *out = '\0';
+
+   /* Path name size should not require more than 4 bytes. */
+   ASSERT((in - *bufIn) <= 0xFFFFFFFF);
+
+   /* Update pointers. */
+   *inSize -= (in - *bufIn);
+   *outSize = myOutSize;
+   *bufIn = in;
+   *bufOut = out;
+
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CPName_Print --
+ *
+ *    Converts a CPName formatted string to a valid, NUL-terminated string by
+ *    replacing all embedded NUL characters with '|'.
+ *
+ * Results:
+ *    Pointer to a static buffer containing the converted string.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+char const *
+CPName_Print(char const *in, // IN: Name to print
+             size_t size)    // IN: Size of name
+{
+   /* Static so it does not go on a kernel stack --hpreg */
+   static char out[128];
+   size_t i;
+
+   ASSERT(in);
+
+   ASSERT(sizeof out >= 4);
+   if (size > sizeof out - 1) {
+      size = sizeof out - 4;
+      out[size] = '.';
+      out[size + 1] = '.';
+      out[size + 2] = '.';
+      out[size + 3] = '\0';
+   } else {
+      out[size] = '\0';
+   }
+
+   for (i = 0; i < size; i++) {
+      out[i] = in[i] != '\0' ? in[i] : '|';
+   }
+
+   return out;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CPName_LinuxConvertTo --
+ *
+ *    Wrapper function that calls CPNameConvertTo() with the correct arguments
+ *    for Linux path conversions.
+ *
+ *    Makes a cross-platform name representation from the Linux path input
+ *    string and writes it into the output buffer.
+ *
+ * Results:
+ *    On success, returns the number of bytes used in the cross-platform name,
+ *    NOT including the final terminating NUL character.  On failure, returns
+ *    a negative error.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+CPName_LinuxConvertTo(char const *nameIn, // IN:  Buf to convert
+                      size_t bufOutSize,  // IN:  Size of the output buffer
+                      char *bufOut)       // OUT: Output buffer
+{
+   return CPNameConvertTo(nameIn, bufOutSize, bufOut, '/');
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CPName_WindowsConvertTo --
+ *
+ *    Wrapper function that calls CPNameConvertTo() with the correct arguments
+ *    for Windows path conversions.
+ *
+ *    Makes a cross-platform name representation from the Linux path input
+ *    string and writes it into the output buffer.
+ *
+ * Results:
+ *    On success, returns the number of bytes used in the cross-platform name,
+ *    NOT including the final terminating NUL character.  On failure, returns
+ *    a negative error.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+CPName_WindowsConvertTo(char const *nameIn, // IN:  Buf to convert
+                        size_t bufOutSize,  // IN:  Size of the output buffer
+                        char *bufOut)       // OUT: Output buffer
+{
+   return CPNameConvertTo(nameIn, bufOutSize, bufOut, '\\');
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CPNameConvertTo --
+ *
+ *    Makes a cross-platform name representation from the input string
+ *    and writes it into the output buffer.
+ *    HGFS convention is to echange names between guest and host in uescaped form.
+ *    Both ends perform necessary name escaping according to its own rules
+ *    to avoid presenitng invalid file names to OS. Thus the name needs to be unescaped
+ *    as a part of conversion to host-independent format.
+ *
+ * Results:
+ *    On success, returns the number of bytes used in the
+ *    cross-platform name, NOT including the final terminating NUL
+ *    character. On failure, returns a negative error.
+ *
+ * Side effects:
+ *    None
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+CPNameConvertTo(char const *nameIn, // IN:  Buf to convert
+                size_t bufOutSize,  // IN:  Size of the output buffer
+                char *bufOut,       // OUT: Output buffer
+                char pathSep)       // IN:  path separator to use
+{
+   char *origOut = bufOut;
+   char const *endOut = bufOut + bufOutSize;
+   size_t cpNameLength = 0;
+
+   ASSERT(nameIn);
+   ASSERT(bufOut);
+
+   /* Skip any path separators at the beginning of the input string */
+   while (*nameIn == pathSep) {
+      nameIn++;
+   }
+
+    /* Copy the string to the output buf, converting all path separators into '\0'. */
+   for (; *nameIn != '\0' && bufOut < endOut; nameIn++) {
+      *bufOut = (*nameIn == pathSep) ? '\0' : *nameIn;
+      bufOut++;
+   }
+
+   /*
+    * NUL terminate. XXX This should go away.
+    *
+    * When we get rid of NUL termination here, this test should
+    * also change to "if (*nameIn != '\0')".
+    */
+   if (bufOut == endOut) {
+      return -1;
+   }
+   *bufOut = '\0';
+
+   /* Path name size should not require more than 4 bytes. */
+   ASSERT((bufOut - origOut) <= 0xFFFFFFFF);
+
+   /* If there were any trailing path separators, dont count them [krishnan] */
+   cpNameLength = bufOut - origOut;
+   while ((cpNameLength >= 1) && (origOut[cpNameLength - 1] == 0)) {
+      cpNameLength--;
+   }
+   cpNameLength = HgfsEscape_Undo(origOut, cpNameLength);
+
+   /* Return number of bytes used */
+   return (int) cpNameLength;
+}
diff --git a/open-vm-tools/modules/solaris/vmhgfs/cpName.h b/open-vm-tools/modules/solaris/vmhgfs/cpName.h
new file mode 100644 (file)
index 0000000..23d5b15
--- /dev/null
@@ -0,0 +1,102 @@
+/*********************************************************
+ * Copyright (C) 1998 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * cpName.h --
+ *
+ *    Cross-platform name format used by hgfs.
+ *
+ */
+
+#ifndef __CP_NAME_H__
+#define __CP_NAME_H__
+
+
+#ifdef __KERNEL__
+#  include "driver-config.h"
+#  include <linux/string.h>
+#elif defined(__FreeBSD__)
+#   if defined(_KERNEL)
+#      include <sys/libkern.h>
+#      define strchr(s,c)       index(s,c)
+#   else
+#      include <string.h>
+#   endif
+#elif defined(__APPLE__) && defined(KERNEL)
+#  include <string.h>
+#elif !defined(sun)
+#  include <stdlib.h>
+#  include <string.h>
+#endif
+
+#include "vm_basic_types.h"
+
+
+/* Status codes for processing share names */
+typedef enum {
+   HGFS_NAME_STATUS_COMPLETE,            /* Name is complete */
+   HGFS_NAME_STATUS_FAILURE,             /* Name processing failed */
+   HGFS_NAME_STATUS_INCOMPLETE_BASE,     /* Name is base of namespace */
+   HGFS_NAME_STATUS_INCOMPLETE_ROOT,     /* Name is "root" only */
+   HGFS_NAME_STATUS_INCOMPLETE_DRIVE,    /* Name is "root drive" only */
+   HGFS_NAME_STATUS_INCOMPLETE_UNC,      /* Name is "root unc" only */
+   HGFS_NAME_STATUS_INCOMPLETE_UNC_MACH, /* Name is "root unc <x>" only */
+   HGFS_NAME_STATUS_DOES_NOT_EXIST,      /* Name does not exist */
+   HGFS_NAME_STATUS_ACCESS_DENIED,       /* Desired access to share denied */
+   HGFS_NAME_STATUS_SYMBOLIC_LINK,       /* Name contains a symbolic link */
+   HGFS_NAME_STATUS_OUT_OF_MEMORY,       /* Out of memory while processing */
+   HGFS_NAME_STATUS_TOO_LONG,            /* Name has overly long component */
+} HgfsNameStatus;
+
+
+int
+CPName_ConvertTo(char const *nameIn, // IN:  The buf to convert
+                 size_t bufOutSize,  // IN:  The size of the output buffer
+                 char *bufOut);      // OUT: The output buffer
+
+int
+CPName_LinuxConvertTo(char const *nameIn, // IN:  buf to convert
+                      size_t bufOutSize,  // IN:  size of the output buffer
+                      char *bufOut);      // OUT: output buffer
+
+int
+CPName_WindowsConvertTo(char const *nameIn, // IN:  buf to convert
+                        size_t bufOutSize,  // IN:  size of the output buffer
+                        char *bufOut);      // OUT: output buffer
+
+int
+CPName_ConvertFrom(char const **bufIn, // IN/OUT: Input to convert
+                   size_t *inSize,     // IN/OUT: Size of input buffer
+                   size_t *outSize,    // IN/OUT: Size of output buffer
+                   char **bufOut);     // IN/OUT: Output buffer
+
+HgfsNameStatus
+CPName_ConvertFromRoot(char const **bufIn, // IN/OUT: Input to convert
+                       size_t *inSize,     // IN/OUT: Size of input
+                       size_t *outSize,    // IN/OUT: Size of output buf
+                       char **bufOut);     // IN/OUT: Output buffer
+
+int
+CPName_GetComponent(char const *begin,  // IN: Beginning of buffer
+                    char const *end,    // IN: End of buffer
+                    char const **next); // OUT: Next component
+
+char const *
+CPName_Print(char const *in, // IN: Name to print
+             size_t size);   // IN: Size of name
+
+
+#endif /* __CP_NAME_H__ */
diff --git a/open-vm-tools/modules/solaris/vmhgfs/cpNameInt.h b/open-vm-tools/modules/solaris/vmhgfs/cpNameInt.h
new file mode 100644 (file)
index 0000000..e95d1fb
--- /dev/null
@@ -0,0 +1,57 @@
+/*********************************************************
+ * Copyright (C) 1998 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * cpNameInt.h --
+ *
+ *    Cross-platform name format used by hgfs.
+ *
+ */
+
+
+#ifndef __CP_NAME_INT_H__
+#define __CP_NAME_INT_H__
+
+
+#include "vm_basic_types.h"
+
+/*
+ * Used by CPName_ConvertFrom
+ */
+int
+CPNameConvertFrom(char const **bufIn, // IN/OUT: Input to convert
+                  size_t *inSize,     // IN/OUT: Size of input
+                  size_t *outSize,    // IN/OUT: Size of output buffer
+                  char **bufOut,      // IN/OUT: Output buffer
+                  char pathSep);      // IN: Path separator character
+
+int
+CPNameEscapeAndConvertFrom(char const **bufIn, // IN/OUT: Input to convert
+                           size_t *inSize,     // IN/OUT: Size of input
+                           size_t *outSize,    // IN/OUT: Size of output buffer
+                           char **bufOut,      // IN/OUT: Output buffer
+                           char pathSep);      // IN: Path separator character
+
+/*
+ * Common code for CPName_ConvertTo
+ */
+int
+CPNameConvertTo(char const *nameIn, // IN:  Buf to convert
+                size_t bufOutSize,  // IN:  Size of the output buffer
+                char *bufOut,       // OUT: Output buffer
+                char pathSep);      // IN:  path separator to use
+
+#endif /* __CP_NAME_INT_H__ */
diff --git a/open-vm-tools/modules/solaris/vmhgfs/cpNameLinux.c b/open-vm-tools/modules/solaris/vmhgfs/cpNameLinux.c
new file mode 100644 (file)
index 0000000..f04d200
--- /dev/null
@@ -0,0 +1,177 @@
+/*********************************************************
+ * Copyright (C) 1998 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * cpNameLinux.c --
+ *
+ *    Linux implementation of cross-platform name conversion
+ *    routines used by hgfs. [bac]
+ *
+ */
+
+#if defined(sun) && !defined(SOL9)
+#include <memory.h>
+#endif
+
+#include "cpName.h"
+#include "cpNameInt.h"
+#include "vm_assert.h"
+#include "hgfsEscape.h"
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CPName_ConvertFrom --
+ *
+ *    Converts a cross-platform name representation into a string for
+ *    use in the local filesystem.
+ *
+ * Results:
+ *    Length (not including NUL termination) >= 0 of resulting
+ *    string on success.
+ *    Negative error on failure (the converted string did not fit in
+ *    the buffer provided or the input was invalid).
+ *
+ * Side effects:
+ *    None
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+CPName_ConvertFrom(char const **bufIn, // IN/OUT: Input to convert
+                   size_t *inSize,     // IN/OUT: Size of input
+                   size_t *outSize,    // IN/OUT: Size of output buffer
+                   char **bufOut)      // IN/OUT: Output buffer
+{
+   ASSERT(bufIn);
+   ASSERT(inSize);
+   ASSERT(outSize);
+   ASSERT(bufOut);
+
+   return CPNameEscapeAndConvertFrom(bufIn, inSize, outSize, bufOut, '/');
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CPName_ConvertFromRoot --
+ *
+ *    Append the appropriate prefix to the output buffer for accessing
+ *    the root of the local filesystem. CPName_ConvertFrom prepends
+ *    leading path separators before each path component, but only
+ *    when the next component has nonzero length, so we still need to
+ *    special case this for Linux.
+ *
+ *    The pointers and sizes are updated appropriately.
+ *
+ * Results:
+ *    Status of name conversion
+ *
+ * Side effects:
+ *    None
+ *
+ *----------------------------------------------------------------------
+ */
+
+HgfsNameStatus
+CPName_ConvertFromRoot(char const **bufIn, // IN/OUT: Input to convert
+                       size_t *inSize,     // IN/OUT: Size of input
+                       size_t *outSize,    // IN/OUT: Size of output buffer
+                       char **bufOut)      // IN/OUT: Output buffer
+{
+   char const *next;
+   char *out;
+   int len;
+
+   ASSERT(bufIn);
+   ASSERT(inSize);
+   ASSERT(outSize);
+   ASSERT(bufOut);
+
+   out = *bufOut;
+
+   /*
+    * Get first component
+    */
+   len = CPName_GetComponent(*bufIn, *bufIn + *inSize, &next);
+   if (len < 0) {
+      Log("CPName_ConvertFromRoot: get first component failed\n");
+      return HGFS_NAME_STATUS_FAILURE;
+   }
+
+   /* Space for leading '/' plus NUL termination */
+   if (*outSize < len + 2) {
+      return HGFS_NAME_STATUS_FAILURE;
+   }
+
+   /* Put a leading '/' in the output buffer either way */
+   *out++ = '/';
+
+   memcpy(out, *bufIn, len);
+   out += len;
+
+   /* NUL terminate */
+   *out = '\0';
+
+   *inSize -= next - *bufIn;
+   *outSize -= out - *bufOut;
+   *bufIn = next;
+   *bufOut = out;
+
+   return HGFS_NAME_STATUS_COMPLETE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * CPName_ConvertTo --
+ *
+ *    Wrapper function that calls the Linux implementation of _ConvertTo().
+ *
+ *    Makes a cross-platform name representation from the Linux path input
+ *    string and writes it into the output buffer.
+ *    If the name being converter may be a result a of name escaping the
+ *    function performs unescaping. HGFS convention is to always exchange
+ *    unescaped names between guest and host and to perform necessary
+ *    name escaping on both ends.
+ *
+ * Results:
+ *    On success, returns the number of bytes used in the
+ *    cross-platform name, NOT including the final terminating NUL
+ *    character. On failure, returns a negative error.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+CPName_ConvertTo(char const *nameIn, // IN:  Buf to convert
+                 size_t bufOutSize,  // IN:  Size of the output buffer
+                 char *bufOut)       // OUT: Output buffer
+{
+   int result;
+   result = CPName_LinuxConvertTo(nameIn, bufOutSize, bufOut);
+   if (result > 0) {
+      result = HgfsEscape_Undo(bufOut, result);
+   }
+   return result;
+}
diff --git a/open-vm-tools/modules/solaris/vmhgfs/dbllnklst.c b/open-vm-tools/modules/solaris/vmhgfs/dbllnklst.c
new file mode 100644 (file)
index 0000000..31ff042
--- /dev/null
@@ -0,0 +1,397 @@
+/*********************************************************
+ * Copyright (C) 1998 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+#include "vmware.h"
+#include "dbllnklst.h"
+
+/*
+ * dbllnklst.c --
+ *
+ *    Light (but nonetheless powerful) implementation of doubly linked lists
+ */
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DblLnkLst_Init --
+ *
+ *    Initialize a member of a doubly linked list
+ *
+ * Result
+ *    None
+ *
+ * Side effects:
+ *    None
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+DblLnkLst_Init(DblLnkLst_Links *l) // IN
+{
+   ASSERT(l);
+
+   l->prev = l->next = l;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DblLnkLst_Link --
+ *
+ *    Merge two doubly linked lists into one
+ *
+ *    The operation is commutative
+ *    The operation is inversible (its inverse is DblLnkLst_Unlink)
+ *
+ * Result
+ *    None
+ *
+ * Side effects:
+ *    None
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+DblLnkLst_Link(DblLnkLst_Links *l1, // IN
+               DblLnkLst_Links *l2) // IN
+{
+   DblLnkLst_Links *tmp;
+
+   ASSERT(l1);
+   ASSERT(l2);
+
+   (tmp      = l1->prev)->next = l2;
+   (l1->prev = l2->prev)->next = l1;
+    l2->prev = tmp                 ;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DblLnkLst_Unlink --
+ *
+ *    Split one doubly linked list into two
+ *
+ *    No check is performed: the caller must ensure that both members
+ *    belong to the same doubly linked list
+ *
+ *    The operation is commutative
+ *    The operation is inversible (its inverse is DblLnkLst_Link)
+ *
+ * Result
+ *    None
+ *
+ * Side effects:
+ *    None
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+DblLnkLst_Unlink(DblLnkLst_Links *l1, // IN
+                 DblLnkLst_Links *l2) // IN
+{
+   DblLnkLst_Links *tmp;
+
+   ASSERT(l1);
+   ASSERT(l2);
+
+   tmp       = l1->prev            ;
+   (l1->prev = l2->prev)->next = l1;
+   (l2->prev = tmp     )->next = l2;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DblLnkLst_Unlink1 --
+ *
+ *    Unlink an element from its list.
+ *
+ * Result
+ *    None
+ *
+ * Side effects:
+ *    None
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+DblLnkLst_Unlink1(DblLnkLst_Links *l) // IN
+{
+   ASSERT(l);
+
+   DblLnkLst_Unlink(l, l->next);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * DblLnkLst_IsLinked --
+ *
+ *    Determines whether an element is linked with any other elements.
+ *
+ * Results:
+ *    TRUE if link is linked, FALSE otherwise.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+Bool
+DblLnkLst_IsLinked(DblLnkLst_Links const *l) // IN
+{
+   ASSERT(l);
+
+   ASSERT((l->prev == l && l->next == l) ||
+          (l->prev != l && l->next != l));
+
+   /*
+    * A DblLnkLst_Links is either linked to itself (not linked) or linked to
+    * other elements in a list (linked).
+    */
+   return l->prev != l;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DblLnkLst_LinkFirst --
+ *
+ *    Insert 'l' at the beginning of the list anchored at 'head'
+ *
+ * Result
+ *    None
+ *
+ * Side effects:
+ *    None
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+DblLnkLst_LinkFirst(DblLnkLst_Links *head, // IN
+                    DblLnkLst_Links *l)    // IN
+{
+   ASSERT(head);
+   ASSERT(l);
+
+   DblLnkLst_Link(head->next, l);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DblLnkLst_LinkLast --
+ *
+ *    Insert 'l' at the end of the list anchored at 'head'
+ *
+ * Result
+ *    None
+ *
+ * Side effects:
+ *    None
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+DblLnkLst_LinkLast(DblLnkLst_Links *head, // IN
+                   DblLnkLst_Links *l)    // IN
+{
+   ASSERT(head);
+   ASSERT(l);
+
+   DblLnkLst_Link(head, l);
+}
+
+
+#if 0
+/*
+ * Test code (which also demonstrates how to use this library)
+ */
+
+/*
+ * Add the double linked list capability to any of your data structure just by
+ * adding a DblLnkLst_Links field inside it. It is not required that the field
+ * comes first, but if it does, the execution will be slighly faster.
+ *
+ * Here we create a doubly linked list of integers
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+typedef struct member {
+   int i;
+   DblLnkLst_Links l;
+} member;
+
+
+/* Member constructor */
+member *
+make_member(int i)
+{
+   member *m;
+
+   m = malloc(sizeof(*m));
+   DblLnkLst_Init(&m->l);
+   m->i = i;
+
+   return m;
+}
+
+
+/* Dump a circular list */
+void
+dump_circular(const member *c) // IN
+{
+   const member *current;
+
+   printf("forward: ");
+   current = c;
+   do {
+      printf("%d ", current->i);
+      current = DblLnkLst_Container(current->l.next, member, l);
+   } while (current != c);
+   printf("backward: ");
+   do {
+      printf("%d ", current->i);
+      current = DblLnkLst_Container(current->l.prev, member, l);
+   } while (current != c);
+   printf("\n");
+}
+
+
+/* Dump an anchored list */
+void
+dump_anchored(const DblLnkLst_Links *h) // IN
+{
+   DblLnkLst_Links *cur_l;
+
+   printf("forward: ");
+   for (cur_l = h->next; cur_l != h; cur_l = cur_l->next) {
+      member *current;
+
+      current = DblLnkLst_Container(cur_l, member, l);
+      printf("%d ", current->i);
+   }
+   printf("backward: ");
+   for (cur_l = h->prev; cur_l != h; cur_l = cur_l->prev) {
+      member *current;
+
+      current = DblLnkLst_Container(cur_l, member, l);
+      printf("%d ", current->i);
+   }
+   printf("\n");
+}
+
+
+/* Test code entry point */
+int
+main(int argc,    // IN
+     char **argv) // IN
+{
+   member *c1;
+   member *c2;
+   member *c3;
+   member *c4;
+
+   DblLnkLst_Links h;
+   member *a1;
+   member *a2;
+   member *a3;
+
+   printf("Circular list: there is no origin\n");
+
+   /* Create the 1st member */
+   c1 = make_member(1);
+   /* Special case: there is no list to merge with, initially */
+
+   /* Add the 2nd member _after_ the 1st one */
+   c2 = make_member(2);
+   DblLnkLst_Link(&c1->l, &c2->l);
+
+   /* Add the 3rd member _after_ the 2nd one */
+   c3 = make_member(3);
+   DblLnkLst_Link(&c1->l, &c3->l);
+
+   /* Add the 4th member _before_ the 3rd one */
+   c4 = make_member(4);
+   DblLnkLst_Link(&c3->l, &c4->l);
+
+   printf("See it from this member...\n");
+   dump_circular(c1);
+   printf("...Or from this one\n");
+   dump_circular(c4);
+
+   printf("\n");
+   printf("Anchored (linear) list: it has a beginning and an end\n");
+
+   /* Create the 'head' of the list */
+   DblLnkLst_Init(&h);
+
+   /* Add the 1st member at the _end_ */
+   a1 = make_member(5);
+   DblLnkLst_LinkLast(&h, &a1->l);
+
+   /* Add the 2nd member at the _beginning_ */
+   a2 = make_member(6);
+   DblLnkLst_LinkFirst(&h, &a2->l);
+
+   /* Add the 3rd member _before_ the 1st one */
+   a3 = make_member(7);
+   DblLnkLst_Link(&a1->l, &a3->l);
+
+   dump_anchored(&h);
+
+   printf("\n");
+   printf("Merge both lists: the result is an anchored list\n");
+
+   DblLnkLst_Link(&h, &c4->l);
+
+   dump_anchored(&h);
+
+   printf("\n");
+   printf("Remove a member\n");
+
+   DblLnkLst_Unlink1(&c3->l);
+
+   dump_anchored(&h);
+
+   printf("\n");
+   printf("Split the result in two lists: an anchored one and a circular "
+          "one\n");
+   DblLnkLst_Unlink(&h, &a1->l);
+
+   dump_anchored(&h);
+   dump_circular(a1);
+
+   return 0;
+}
+#endif
diff --git a/open-vm-tools/modules/solaris/vmhgfs/dbllnklst.h b/open-vm-tools/modules/solaris/vmhgfs/dbllnklst.h
new file mode 100644 (file)
index 0000000..305f64e
--- /dev/null
@@ -0,0 +1,67 @@
+/*********************************************************
+ * Copyright (C) 1998 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * dbllnklst.h --
+ *
+ *    Double linked lists
+ */
+
+#ifndef _DBLLNKLST_H_
+#define _DBLLNKLST_H_
+
+#include "vm_basic_types.h"
+
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_USERLEVEL
+#include "includeCheck.h"
+
+
+#define DblLnkLst_OffsetOf(type, field) ((intptr_t)&((type *)0)->field)
+
+#define DblLnkLst_Container(addr, type, field) \
+   ((type *)((char *)addr - DblLnkLst_OffsetOf(type, field)))
+
+#define DblLnkLst_ForEach(curr, head)                   \
+      for (curr = (head)->next; curr != (head); curr = (curr)->next)
+
+/* Safe from list element removal within loop body. */
+#define DblLnkLst_ForEachSafe(curr, nextElem, head)             \
+      for (curr = (head)->next, nextElem = (curr)->next;        \
+           curr != (head);                                      \
+           curr = nextElem, nextElem = (curr)->next)
+
+typedef struct DblLnkLst_Links {
+   struct DblLnkLst_Links *prev;
+   struct DblLnkLst_Links *next;
+} DblLnkLst_Links;
+
+
+/* Functions for both circular and anchored lists. --hpreg */
+
+void DblLnkLst_Init(DblLnkLst_Links *l);
+void DblLnkLst_Link(DblLnkLst_Links *l1, DblLnkLst_Links *l2);
+void DblLnkLst_Unlink(DblLnkLst_Links *l1, DblLnkLst_Links *l2);
+void DblLnkLst_Unlink1(DblLnkLst_Links *l);
+Bool DblLnkLst_IsLinked(DblLnkLst_Links const *l);
+
+/* Functions specific to anchored lists. --hpreg */
+
+void DblLnkLst_LinkFirst(DblLnkLst_Links *head, DblLnkLst_Links *l);
+void DblLnkLst_LinkLast(DblLnkLst_Links *head, DblLnkLst_Links *l);
+
+
+#endif /* _DBLLNKLST_H_ */
diff --git a/open-vm-tools/modules/solaris/vmhgfs/debug.c b/open-vm-tools/modules/solaris/vmhgfs/debug.c
new file mode 100644 (file)
index 0000000..0e6be24
--- /dev/null
@@ -0,0 +1,483 @@
+/*********************************************************
+ * Copyright (C) 2004 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+
+/*
+ * debug.c --
+ *
+ * Routines for debugging Solaris kernel module.
+ *
+ */
+
+
+#include "debug.h"
+#include "filesystem.h"
+#ifndef SOL9
+#include <sys/cred_impl.h>
+#endif
+
+
+/*
+ * Functions
+ */
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsDebugPrintVfssw --
+ *
+ *    Prints the provided VFS Switch structure.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+INLINE void
+HgfsDebugPrintVfssw(char *str, struct vfssw *vfsswp)
+{
+   ASSERT(str);
+   ASSERT(vfsswp);
+
+   DEBUG(VM_DEBUG_STRUCT, "struct vfssw from %s\n", str);
+   DEBUG(VM_DEBUG_STRUCT, " vsw_name    : %s\n",
+        (vfsswp->vsw_name) ? vfsswp->vsw_name : "NULL");
+   DEBUG(VM_DEBUG_STRUCT, " vsw_init    : %p\n", vfsswp->vsw_init);
+   DEBUG(VM_DEBUG_STRUCT, " vsw_flag    : %x\n", vfsswp->vsw_flag);
+#  ifdef SOL9
+   DEBUG(VM_DEBUG_STRUCT, " vsw_vfsops  : %x\n", vfsswp->vsw_vfsops);
+   DEBUG(VM_DEBUG_STRUCT, " vsw_optproto: %x\n", vfsswp->vsw_optproto);
+#  endif
+   DEBUG(VM_DEBUG_STRUCT, " vsw_count   : %d\n", vfsswp->vsw_count);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsDebugPrintVfs --
+ *
+ *    Prints the provided VFS structure.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+INLINE void
+HgfsDebugPrintVfs(char *str, struct vfs *vfsp)
+{
+   ASSERT(str);
+   ASSERT(vfsp);
+
+   DEBUG(VM_DEBUG_STRUCT, "struct vfs from %s\n", str);
+   DEBUG(VM_DEBUG_STRUCT, " vfs_next        : %p\n", vfsp->vfs_next);
+   DEBUG(VM_DEBUG_STRUCT, " vfs_op          : %p\n", vfsp->vfs_op);
+   DEBUG(VM_DEBUG_STRUCT, " vfs_vnodecovered: %p\n", vfsp->vfs_vnodecovered);
+   DEBUG(VM_DEBUG_STRUCT, " vfs_flag        : %d\n", vfsp->vfs_flag);
+   DEBUG(VM_DEBUG_STRUCT, " vfs_bsize       : %d\n", vfsp->vfs_bsize);
+   DEBUG(VM_DEBUG_STRUCT, " vfs_fstype      : %d\n", vfsp->vfs_fstype);
+#  ifdef SOL9
+   DEBUG(VM_DEBUG_STRUCT, " vfs_fsid        : %d\n", vfsp->vfs_fsid);
+#  else
+   DEBUG(VM_DEBUG_STRUCT, " vfs_fsid.val[0] : %d\n", vfsp->vfs_fsid.val[0]);
+   DEBUG(VM_DEBUG_STRUCT, " vfs_fsid.val[1] : %d\n", vfsp->vfs_fsid.val[1]);
+#  endif
+   DEBUG(VM_DEBUG_STRUCT, " vfs_vadata      : %p\n", vfsp->vfs_data);
+   DEBUG(VM_DEBUG_STRUCT, " vfs_dev         : %lu\n", vfsp->vfs_dev);
+   DEBUG(VM_DEBUG_STRUCT, " vfs_bcount      : %lu\n", vfsp->vfs_bcount);
+#  ifdef SOL9
+   DEBUG(VM_DEBUG_STRUCT, " vfs_nsubmounts  : %d\n", vfsp->vfs_nsubmounts);
+#  endif
+   DEBUG(VM_DEBUG_STRUCT, " vfs_list        : %p\n", vfsp->vfs_list);
+   DEBUG(VM_DEBUG_STRUCT, " vfs_hash        : %p\n", vfsp->vfs_hash);
+   DEBUG(VM_DEBUG_STRUCT, " vfs_reflock     : %p\n", &vfsp->vfs_reflock);
+   DEBUG(VM_DEBUG_STRUCT, " vfs_count       : %d\n", vfsp->vfs_count);
+#  ifdef SOL9
+   DEBUG(VM_DEBUG_STRUCT, " vfs_mntopts     : %x\n", vfsp->vfs_mntopts);
+   DEBUG(VM_DEBUG_STRUCT, " vfs_resource    : %s\n",
+        (vfsp->vfs_resource) ? vfsp->vfs_resource : "NULL");
+#  endif
+   DEBUG(VM_DEBUG_STRUCT, " vfs_mtime       : %ld\n", vfsp->vfs_mtime);
+
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsDebugPrintVnode --
+ *
+ *    Prints the provided vnode structure.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+INLINE void
+HgfsDebugPrintVnode(uint32 level, char *str, struct vnode *vnodep)
+{
+   ASSERT(str);
+   ASSERT(vnodep);
+
+   DEBUG(level, "struct vnode from %s located at %p\n", str, vnodep);
+   DEBUG(level, " v_lock          : %p\n", &vnodep->v_lock);
+   DEBUG(level, " v_flag          : %d\n", vnodep->v_flag);
+   DEBUG(level, " v_count         : %d\n", vnodep->v_count);
+   DEBUG(level, " v_vfsmountedhere: %p\n", vnodep->v_vfsmountedhere);
+   DEBUG(level, " v_op            : %p\n", vnodep->v_op);
+   DEBUG(level, " v_vfsp          : %p\n", vnodep->v_vfsp);
+   DEBUG(level, " v_stream        : %p\n", vnodep->v_stream);
+   DEBUG(level, " v_pages         : %p\n", vnodep->v_pages);
+#  ifdef SOL9
+   DEBUG(level, " v_next          : %p\n", vnodep->v_next);
+   DEBUG(level, " v_prev          : %p\n", vnodep->v_prev);
+#  endif
+   DEBUG(level, " v_type          : %d\n", vnodep->v_type);
+   DEBUG(level, " v_rdev          : %lu\n", vnodep->v_rdev);
+   DEBUG(level, " v_data          : %p\n", vnodep->v_data);
+   DEBUG(level, " v_filocks       : %p\n", vnodep->v_filocks);
+   DEBUG(level, " v_shrlocks      : %p\n", vnodep->v_shrlocks);
+   DEBUG(level, " v_cv            : %p\n", &vnodep->v_cv);
+   DEBUG(level, " v_locality      : %p\n", vnodep->v_locality);
+   DEBUG(level, " v_nbllock       : %p\n", &vnodep->v_nbllock);
+
+   if (HGFS_VP_TO_OFP(vnodep) && HGFS_VP_TO_FP(vnodep)) {
+      DEBUG(level, " filename        : %s\n", HGFS_VP_TO_FILENAME(vnodep));
+   }
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsDebugPrintCred --
+ *
+ *    Prints the provided cred structure the describes the credentials of the
+ *    caller.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+INLINE void
+HgfsDebugPrintCred(char *str, struct cred *credp)
+{
+   DEBUG(VM_DEBUG_STRUCT, "struct cred from %s\n", str);
+   DEBUG(VM_DEBUG_STRUCT, " cr_ref    : %d\n", credp->cr_ref);
+   DEBUG(VM_DEBUG_STRUCT, " cr_uid    : %d\n", credp->cr_uid);
+   DEBUG(VM_DEBUG_STRUCT, " cr_gid    : %d\n", credp->cr_gid);
+   DEBUG(VM_DEBUG_STRUCT, " cr_ruid   : %d\n", credp->cr_ruid);
+   DEBUG(VM_DEBUG_STRUCT, " cr_rgid   : %d\n", credp->cr_rgid);
+   DEBUG(VM_DEBUG_STRUCT, " cr_suid   : %d\n", credp->cr_suid);
+   DEBUG(VM_DEBUG_STRUCT, " cr_sgid   : %d\n", credp->cr_sgid);
+   DEBUG(VM_DEBUG_STRUCT, " cr_ngroups: %d\n", credp->cr_ngroups);
+   DEBUG(VM_DEBUG_STRUCT, " cr_groups : %p\n", credp->cr_groups);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsDebugMounta --
+ *
+ *    Prints the provided mounta structure that describes the arguments
+ *    provided to users.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+INLINE void
+HgfsDebugPrintMounta(char *str, struct mounta *mntp)
+{
+   ASSERT(str);
+   ASSERT(mntp);
+
+   DEBUG(VM_DEBUG_STRUCT, "struct mounta from %s\n", str);
+   DEBUG(VM_DEBUG_STRUCT, " spec    : %s\n",
+        (mntp->spec) ? mntp->spec : "NULL");
+   DEBUG(VM_DEBUG_STRUCT, " dir     : %s\n",
+        (mntp->dir) ? mntp->dir : "NULL");
+   DEBUG(VM_DEBUG_STRUCT, " flags   : %x\n", mntp->flags);
+   DEBUG(VM_DEBUG_STRUCT, " fstype  : %s\n",
+        (mntp->fstype) ? mntp->fstype : "NULL");
+   DEBUG(VM_DEBUG_STRUCT, " dataptr : %p\n", mntp->dataptr);
+   DEBUG(VM_DEBUG_STRUCT, " datalen : %d\n", mntp->datalen);
+   DEBUG(VM_DEBUG_STRUCT, " optptr  : %p\n", mntp->optptr);
+   DEBUG(VM_DEBUG_STRUCT, " optlen  : %d\n", mntp->optlen);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsDebugPrintVattr --
+ *
+ *    Prints the contents of an attributes structure.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+INLINE void
+HgfsDebugPrintVattr(const struct vattr *vap)
+{
+   DEBUG(VM_DEBUG_STRUCT, " va_mask: %x\n", vap->va_mask);
+   DEBUG(VM_DEBUG_STRUCT, " va_type: %d\n", vap->va_type);
+   DEBUG(VM_DEBUG_STRUCT, " va_mode: %x\n", vap->va_mode);
+   DEBUG(VM_DEBUG_STRUCT, " va_uid:  %u\n", vap->va_uid);
+   DEBUG(VM_DEBUG_STRUCT, " va_gid: %u\n", vap->va_gid);
+   DEBUG(VM_DEBUG_STRUCT, " va_fsid: %lu\n", vap->va_fsid);
+   DEBUG(VM_DEBUG_STRUCT, " va_nodeid: %llu\n", vap->va_nodeid);
+   DEBUG(VM_DEBUG_STRUCT, " va_nlink: %x\n", vap->va_nlink);
+   DEBUG(VM_DEBUG_STRUCT, " va_size: %llu\n", vap->va_size);
+   DEBUG(VM_DEBUG_STRUCT, " va_atime.tv_sec: %ld\n", vap->va_atime.tv_sec);
+   DEBUG(VM_DEBUG_STRUCT, " va_atime.tv_nsec: %ld\n", vap->va_atime.tv_nsec);
+   DEBUG(VM_DEBUG_STRUCT, " va_mtime.tv_sec: %ld\n", vap->va_mtime.tv_sec);
+   DEBUG(VM_DEBUG_STRUCT, " va_mtime.tv_nsec: %ld\n", vap->va_mtime.tv_nsec);
+   DEBUG(VM_DEBUG_STRUCT, " va_ctime.tv_sec: %ld\n", vap->va_ctime.tv_sec);
+   DEBUG(VM_DEBUG_STRUCT, " va_ctime.tv_nsec: %ld\n", vap->va_ctime.tv_nsec);
+   DEBUG(VM_DEBUG_STRUCT, " va_rdev: %lu\n", vap->va_rdev);
+   DEBUG(VM_DEBUG_STRUCT, " va_blksize: %u\n", vap->va_blksize);
+   DEBUG(VM_DEBUG_STRUCT, " va_nblocks: %llu\n", vap->va_nblocks);
+#ifdef SOL9
+   DEBUG(VM_DEBUG_STRUCT, " va_vcode: %u\n", vap->va_vcode);
+#else
+   DEBUG(VM_DEBUG_STRUCT, " va_seq: %u\n", vap->va_seq);
+#endif
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsDebugPrintReqList --
+ *
+ *    For debugging.  Prints out the request list for the provided list
+ *    anchor.
+ *    Note: Assumes called with the list lock held.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+HgfsDebugPrintReqList(DblLnkLst_Links *listAnchor)   // IN: Anchor of list to print
+{
+   DblLnkLst_Links *currNode;
+   HgfsReq *currReq;
+
+   ASSERT(listAnchor);
+
+   DEBUG(VM_DEBUG_STRUCT, "Request List:\n");
+   DEBUG(VM_DEBUG_STRUCT, " anchor: %p\n", listAnchor);
+
+   for (currNode = listAnchor->next; currNode != listAnchor; currNode = currNode->next)
+   {
+      currReq = DblLnkLst_Container(currNode, HgfsReq, listNode);
+      DEBUG(VM_DEBUG_STRUCT, " address: %p (id=%d)\n",
+            currReq, currReq->id);
+   }
+
+   DEBUG(VM_DEBUG_STRUCT, "--DONE--\n");
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsDebugPrintReq --
+ *
+ *    Prints the relevant portions of the provided HgfsReq structure.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+HgfsDebugPrintReq(const char *str,
+                  HgfsReq *req)
+{
+   ASSERT(str);
+   ASSERT(req);
+
+   DEBUG(VM_DEBUG_STRUCT, "struct HgfsReq from %s\n", str);
+   DEBUG(VM_DEBUG_STRUCT, " id: %d\n", req->id);
+   DEBUG(VM_DEBUG_STRUCT, " listNode: %p\n", &req->listNode);
+   DEBUG(VM_DEBUG_STRUCT, "  next=%p\n", req->listNode.next);
+   DEBUG(VM_DEBUG_STRUCT, "  prev=%p\n", req->listNode.prev);
+   DEBUG(VM_DEBUG_STRUCT, " packetSize: %d\n", req->packetSize);
+   DEBUG(VM_DEBUG_STRUCT, " state: %d (see hgfsSolaris.h)\n", req->state);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsDebugPrintReqPool --
+ *
+ *    Prints the contents if the request pool.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+HgfsDebugPrintReqPool(const char *str)
+{
+   int i;
+
+   ASSERT(str);
+
+   DEBUG(VM_DEBUG_STRUCT, "Request pool from %s\n", str);
+
+   for (i = 0; i < ARRAYSIZE(requestPool); i++) {
+      DEBUG(VM_DEBUG_STRUCT, " Index: %d, ID: %d\n", i, requestPool[i].id);
+      DEBUG(VM_DEBUG_STRUCT, " listNode: %p\n", &requestPool[i].listNode);
+      DEBUG(VM_DEBUG_STRUCT, "  next=%p\n", requestPool[i].listNode.next);
+      DEBUG(VM_DEBUG_STRUCT, "  prev=%p\n", requestPool[i].listNode.prev);
+      DEBUG(VM_DEBUG_STRUCT, " packetSize: %d\n", requestPool[i].packetSize);
+      DEBUG(VM_DEBUG_STRUCT, " state: %d (see hgfsSolaris.h)\n", requestPool[i].state);
+   }
+
+   DEBUG(VM_DEBUG_STRUCT, "--request pool done--\n");
+}
+
+
+/*
+ * Gotta have Panic. Stolen from vmnix.
+ * (Then stolen from hgfs/driver/linux/main.c and tweaked for Solaris)
+ */
+
+/*
+ * There is a problem in Solaris 9's header files when using the va_start
+ * and va_end macros, so we manually do what the preprocessor would have
+ * done here.
+ *
+ * Note, the line using __builtin_next_arg is equivalent to:
+ * args = ((char *)(&fmt) + sizeof (char *));
+ *
+ * That is, it just provides a pointer to the unnamed first variable
+ * argument.
+ */
+#ifdef SOL9
+# define compat_va_list char *
+# define compat_va_start(arg, fmt) arg = ((char *)__builtin_next_arg(fmt))
+# define compat_va_end(arg)
+#else
+# define compat_va_list  va_list
+# define compat_va_start(arg, fmt) va_start(arg, fmt)
+# define compat_va_end(arg)        va_end(arg)
+#endif
+
+void
+Panic(const char *fmt, ...) // IN
+{
+   compat_va_list args;
+   char buffer[1024];
+   volatile char *p = NULL;
+
+   compat_va_start(args, fmt);
+   vsprintf(buffer, fmt, args);
+   compat_va_end(args);
+
+   cmn_err(HGFS_ERROR, "%s", buffer);
+
+   /* force segfault */
+   buffer[0] = *p;
+   while (1) ; // avoid compiler warning
+}
+
+
+/*
+ * For compatibility with existing code.
+ */
+void
+Log(const char *fmt, ...)
+{
+#ifdef VM_DEBUG_LEV
+   compat_va_list args;
+   char buffer[1024];
+
+   /*
+    * We check this here to avoid unnecessarily manipulating buffer if we
+    * aren't even going to print the log.
+    */
+   if (VM_DEBUG_LOG & VM_DEBUG_LEV) {
+      compat_va_start(args, fmt);
+      vsprintf(buffer, fmt, args);
+      compat_va_end(args);
+
+      cmn_err(HGFS_DEBUG, "%s", buffer);
+   }
+#endif
+}
+
+#undef compat_va_list
+#undef compat_va_start
+#undef compat_va_end
diff --git a/open-vm-tools/modules/solaris/vmhgfs/debug.h b/open-vm-tools/modules/solaris/vmhgfs/debug.h
new file mode 100644 (file)
index 0000000..9811fd0
--- /dev/null
@@ -0,0 +1,100 @@
+/*********************************************************
+ * Copyright (C) 2004 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+
+/*
+ * debug.h --
+ *
+ * Macros and includes for debugging.
+ *
+ */
+
+#ifndef __DEBUG_H_
+#define __DEBUG_H_
+
+#include <sys/vnode.h>
+#include <sys/vfs.h>
+
+#include "hgfsSolaris.h"
+#include "filesystem.h"
+
+
+/*
+ * Debugging
+ */
+#define HGFS_DEBUG             (CE_NOTE)
+
+#define VM_DEBUG_ALWAYS         (1)
+#define VM_DEBUG_FAIL          VM_DEBUG_ALWAYS
+#define VM_DEBUG_NOTSUP         VM_DEBUG_ALWAYS
+#define VM_DEBUG_ENTRY          (1 << 1)
+#define VM_DEBUG_DONE          (1 << 2)
+#define VM_DEBUG_LOAD          (1 << 3)
+#define VM_DEBUG_INFO           (1 << 4)
+#define VM_DEBUG_STRUCT         (1 << 5)
+#define VM_DEBUG_LIST           (1 << 6)
+#define VM_DEBUG_CHPOLL         (1 << 7)
+#define VM_DEBUG_RARE           (1 << 8)
+#define VM_DEBUG_COMM           (1 << 9)
+#define VM_DEBUG_REQUEST        (1 << 10)
+#define VM_DEBUG_LOG            (1 << 11)
+#define VM_DEBUG_ATTR           (1 << 12)
+#define VM_DEBUG_DEVENTRY       (1 << 13)
+#define VM_DEBUG_DEVDONE        (1 << 14)
+#define VM_DEBUG_SIG            (1 << 15)
+#define VM_DEBUG_ERROR          (1 << 16)
+#define VM_DEBUG_HSHTBL         (1 << 17)
+#define VM_DEBUG_HANDLE         (1 << 18)
+#define VM_DEBUG_STATE          (1 << 19)
+
+#ifdef VM_DEBUGGING_ON
+/*#define VM_DEBUG_LEV    (VM_DEBUG_ALWAYS | VM_DEBUG_ENTRY | VM_DEBUG_DONE |     \
+                         VM_DEBUG_LOAD | VM_DEBUG_COMM |                        \
+                         VM_DEBUG_LOG | VM_DEBUG_ATTR)
+*/
+/*#define VM_DEBUG_LEV    (VM_DEBUG_ALWAYS | VM_DEBUG_FAIL | VM_DEBUG_ERROR |  \
+                        VM_DEBUG_COMM | VM_DEBUG_DONE)
+*/
+#define VM_DEBUG_LEV    (VM_DEBUG_ALWAYS | VM_DEBUG_FAIL)
+#endif
+
+
+#ifdef VM_DEBUG_LEV
+#define DEBUG(type, args...)    \
+             ((type & VM_DEBUG_LEV) ? (cmn_err(HGFS_DEBUG, args)) : 0)
+#else
+#define DEBUG(type, args...)
+#endif
+
+
+/*
+ * Prototypes
+ */
+INLINE void HgfsDebugPrintVfssw(char *str, struct vfssw *vfsswp);
+INLINE void HgfsDebugPrintVfs(char *str, struct vfs *vfsp);
+INLINE void HgfsDebugPrintVnode(uint32 level, char *str, struct vnode *vnodep);
+INLINE void HgfsDebugPrintCred(char *str, struct cred *credp);
+INLINE void HgfsDebugPrintMounta(char *str, struct mounta *mntp);
+INLINE void HgfsDebugPrintVattr(const struct vattr *vap);
+void HgfsDebugPrintReqList(DblLnkLst_Links *listAnchor);
+void HgfsDebugPrintReq(const char *str, HgfsReq *req);
+void HgfsDebugPrintReqPool(const char *str);
+void Panic(const char *fmt, ...);
+void Log(const char *fmt, ...);
+
+
+
+#endif /* __DEBUG_H_ */
diff --git a/open-vm-tools/modules/solaris/vmhgfs/device.c b/open-vm-tools/modules/solaris/vmhgfs/device.c
new file mode 100644 (file)
index 0000000..3948f68
--- /dev/null
@@ -0,0 +1,1111 @@
+/*********************************************************
+ * Copyright (C) 2004 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+
+/*
+ * device.c --
+ *
+ * HGFS device driver for Solaris.
+ *
+ * Implements a device driver that creates a device in /dev that can be
+ * interacted with through standard file IO syscalls.  Implements open(),
+ * close(), read(), write(), and poll().
+ *
+ * read() provides requests from the filesystem to the caller and is
+ * synchronized with the HgfsSubmitRequest() function in the filesystem.
+ * write() receives replies to those requests and provides them to the
+ * filesystem by waking up processes waiting in HgfsSubmitRequest().
+ *
+ */
+
+#include "hgfsSolaris.h"
+#include "device.h"
+#include "request.h"
+#include "filesystem.h"
+
+/*
+ * Local variables
+ */
+static Bool hgfsAttached;        /* Flag to tell whether device is attached */
+
+/*
+ * Function Prototypes
+ */
+static int HgfsSendRequestToUser(HgfsReq *req, uio_t *uiop);
+static INLINE int HgfsGetReplyHeaderFromUser(HgfsReplyHeader *reply, uio_t *uiop);
+static int HgfsGetReplyPacketFromUser(HgfsReq *req, ssize_t offset, uio_t *uiop);
+
+/* Local utility functions */
+static INLINE HgfsSuperInfo *HgfsDevToSuperInfo(dev_t dev);
+static INLINE HgfsSuperInfo *HgfsDevinfoToSuperInfo(dev_info_t *dip);
+static INLINE HgfsReq *HgfsReplyToRequest(HgfsReplyHeader *reply);
+
+/*
+ * Driver "configuration" functions
+ */
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsDevGetinfo --
+ *
+ *    The entry point for getinfo(9E).  Carries out commands requested by the
+ *    kernel that either return the device information structure or the
+ *    instance number.
+ *
+ * Results:
+ *    Returns DDI_SUCCESS on success and DDI_FAILURE on failure.
+ *    When infocmd is DDI_INFO_DEVT2DEVINFO, a pointer to the device's
+ *    information structure is returned in result.
+ *    When infocmd is DDI_INFO_DEVT2INSTANCE, the device's instance number is
+ *    returned in result.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsDevGetinfo(dev_info_t *dip,         // IN: Device info for this device
+               ddi_info_cmd_t infocmd,  // IN: Command to carry out
+               void *arg,               // IN: Device number (as dev_t) for this device
+               void **result)           // OUT: Result of command
+{
+   minor_t instance;    /* getminor() returns minor_t */
+   HgfsSuperInfo *sip;
+
+   DEBUG(VM_DEBUG_DEVENTRY, "HgfsDevGetinfo().\n");
+
+   ASSERT(arg);
+   ASSERT(result);
+
+   /* These indicate a kernel error */
+   if ((!arg) || (!result)) {
+      cmn_err(HGFS_ERROR, "NULL input from Kernel in HgfsDevGetinfo().\n");
+      return EINVAL;
+   }
+
+
+   switch (infocmd) {
+
+   /* This wants a dev_info_t from the dev_t: get it from the superinfo */
+   case DDI_INFO_DEVT2DEVINFO:
+      sip = HgfsDevToSuperInfo((dev_t)arg);
+      if (!sip) {
+         goto error;
+      }
+
+      *result = sip->dip;
+      DEBUG(VM_DEBUG_DEVDONE, "HgfsDevGetinfo() done.\n");
+      return DDI_SUCCESS;
+
+   /*
+    * This wants the instance number, which is the minor number since we set
+    * it to be that in HgfsDevAttach()'s call to ddi_create_minor_node().
+    */
+   case DDI_INFO_DEVT2INSTANCE:
+      instance = getminor((dev_t)arg);
+      *result = (void *)((uintptr_t)instance);
+      DEBUG(VM_DEBUG_DEVDONE, "HgfsDevGetinfo() done.\n");
+      return DDI_SUCCESS;
+
+   /* Unrecognized command */
+   default:
+      goto error;
+   }
+
+error:
+   *result = NULL;
+   DEBUG(VM_DEBUG_FAIL, "HgfsDevGetinfo() done (FAIL).\n");
+   return DDI_FAILURE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsDevAttach --
+ *
+ *    The entry point for attach(9E) that is invoked when the driver is loaded
+ *    into the kernel.  This allocates and initializes a super info structure
+ *    and creates the device entry ('minor node') in the file system.
+ *    XXX: do we need to handle suspend and resume commands also?
+ *
+ * Results:
+ *    Returns zero on success, and an appropriate error code on failure.
+ *
+ * Side effects:
+ *    The device entry appears in the filesystem (/devices).
+ *    The hgfsAttaches flag is set.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsDevAttach(dev_info_t *dip,             // IN: Device info for this device
+              ddi_attach_cmd_t cmd)        // IN: Command to carry out
+{
+   int instance; /* ddi_get_instance() returns int */
+   HgfsSuperInfo *sip;
+
+   DEBUG(VM_DEBUG_DEVENTRY, "HgfsDevAttach().\n");
+
+   ASSERT(dip);
+
+   /* This indicates a kernel error */
+   if (!dip) {
+      cmn_err(HGFS_ERROR, "NULL input from Kernel in HgfsDevAttach().\n");
+      return EINVAL;
+   }
+
+   if (hgfsAttached) {
+      cmn_err(HGFS_ERROR, "Device already attached.\n");
+      return EIO;
+   }
+
+   switch (cmd) {
+
+   /* Attach this device */
+   case DDI_ATTACH:
+      /* hgfsInstance is used by the filesystem side to get superinfo pointer */
+      instance = hgfsInstance = ddi_get_instance(dip);
+
+      /*
+       * Here we allocate state for this instance of the driver (see comment
+       * in _init() for more information on Solaris' DDI Soft State interface).
+       *
+       * Once we have the pointer to the state we just allocated, we'll
+       * initialize its fields.  In particular:
+       * - a pointer to the dev_info_t is stored because HgfsGetInfo() will
+       *   need it.
+       * - clear the flag indicating whether the device is open.
+       * - the request list, along with its mutex and condition variable, are
+       *   initialized.
+       */
+      if (ddi_soft_state_zalloc(superInfoHead, instance) != DDI_SUCCESS) {
+         cmn_err(HGFS_ERROR,
+                 "could not zalloc state for this instance (%d).\n", instance);
+         goto error;
+      }
+
+      sip = (HgfsSuperInfo *)ddi_get_soft_state(superInfoHead, instance);
+      if (!sip) {
+         goto error_free;
+      }
+
+      sip->dip = dip;
+      sip->devOpen = 0;
+
+      HgfsInitRequestList(sip);
+
+      /*
+       * Create the minor node (the /devices entry)
+       */
+      if (ddi_create_minor_node(dip,            /* device info ptr */
+                                HGFS_DEV_NAME,  /* name of device */
+                                S_IFCHR,        /* type of device (character) */
+                                instance,       /* minor number */
+                                DDI_PSEUDO,     /* pseudo device b/c not backed
+                                                   by physical device */
+                                0               /* flag: not a clone device */
+                                ) != DDI_SUCCESS) {
+
+         cmn_err(HGFS_ERROR, "could not create minor node (/devices entry).\n");
+         goto error_free;
+      }
+
+      /* Report presence of device to system log (syslog/dmesg) */
+      ddi_report_dev(dip);
+
+      /*
+       * We only want one instance of this driver to ever be running, so set a
+       * flag stating the device is attached
+       */
+      hgfsAttached = TRUE;
+
+      DEBUG(VM_DEBUG_DEVDONE, "HgfsDevAttach() done.\n");
+      return DDI_SUCCESS;
+
+   /* Unsupported commands: DDI_PM_RESUME and DDI_RESUME  */
+   default:
+      goto error;
+   }
+
+error_free:
+   ddi_soft_state_free(sip, instance);
+error:
+   DEBUG(VM_DEBUG_FAIL, "HgfsDevAttach() done (FAIL).\n");
+   return DDI_FAILURE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsDevDetach --
+ *
+ *    The detach(9E) entry point that is invoked when the driver is
+ *    unloaded from the kernel.  This cleans up all state allocated in
+ *    HgfsDevAttach() and removes the device entry ('minor node').
+ *
+ * Results:
+ *    Returns zero on success, and an appropriate error code on failure.
+ *
+ * Side effects:
+ *    The super info structure for this driver is deallocated.
+ *    The device entry (/devices) is no longer valid.
+ *    The hgfsAttached flag is cleared.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsDevDetach(dev_info_t *dip,             // IN: Device info for this device
+              ddi_detach_cmd_t cmd)        // IN: Command to carry out
+{
+   int instance;
+   HgfsSuperInfo *sip;
+
+   DEBUG(VM_DEBUG_DEVENTRY, "HgfsDevDetach().\n");
+
+   ASSERT(dip);
+
+   /* This indicates a kernel error */
+   if (!dip) {
+      cmn_err(HGFS_ERROR, "NULL input from Kernel in HgfsDevDetach().\n");
+      return EINVAL;
+   }
+
+   switch(cmd) {
+
+   /* Detach this device */
+   case DDI_DETACH:
+     /*
+      * Clean up the state allocated for this instance of the driver:
+      *  - Get a pointer to the super info structure,
+      *  - Remove the device entry (minor node) from the system,
+      *  - Free the super info structure.
+      */
+     instance = ddi_get_instance(dip);
+     sip = (HgfsSuperInfo *)ddi_get_soft_state(superInfoHead, instance);
+     if (!sip) {
+        cmn_err(HGFS_ERROR, "could not find HgfsSuperInfo on detach.\n");
+        goto error;
+     }
+
+     ddi_remove_minor_node(dip, NULL); /* NULL means remove all for this dev_info_t */
+     ddi_soft_state_free(superInfoHead, instance);
+
+     /* Indicate driver is no longer attached */
+     hgfsAttached = 0;
+
+     DEBUG(VM_DEBUG_DEVDONE, "HgfsDevDetach() done.\n");
+     return DDI_SUCCESS;
+
+   /* Unsupported commands: DDI_PM_SUSPEND and DDI_SUSPEND */
+   default:
+     goto error;
+   }
+
+error:
+   DEBUG(VM_DEBUG_FAIL, "HgfsDevDetach() done (FAIL).\n");
+   return DDI_FAILURE;
+}
+
+
+
+/*
+ * Device functions
+ */
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsDevOpen --
+ *    The entry point for open(9E) that is invoked when a user process calls
+ *    open(2) on the device.  This checks that the specified device and open
+ *    type are valid.
+ *
+ * Results:
+ *    Returns zero on success, and an appropriate error code on failure.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsDevOpen(dev_t *devp,   // IN: Pointer to device number
+            int flag,      // IN: Indicates open mode
+                           //     (FREAD, FWRITE, FEXCL, FNDELAY)
+            int otyp,      // IN: Type of open (OTYP_CHR, OTYP_BLK, OTYP_LYR)
+            cred_t *credp) // IN: Pointer to credentials of caller
+{
+   HgfsSuperInfo *sip;
+
+   DEBUG(VM_DEBUG_DEVENTRY, "HgfsDevOpen().\n");
+
+   ASSERT(devp);
+   ASSERT(credp);
+
+   /* These indicate a kernel error */
+   if ((!devp) || (!credp)) {
+      cmn_err(HGFS_ERROR, "NULL input from Kernel in HgfsDevOpen().\n");
+      return EINVAL;
+   }
+
+   /*
+    * Here we do a few checks to ensure that this open is valid.  First, our
+    * device is a character device so we ensure that the type of open
+    * indicates this.  Next we ensure that the caller is root.  Finally, we
+    * make sure that the device number specified is valid by attempting to
+    * retrieve its state that was allocated in HgfsDevDetach().
+    */
+
+   if (otyp != OTYP_CHR) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsDevOpen() done (FAIL).\n");
+      return EINVAL;
+   }
+
+   if (!HgfsSuser(credp)) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsDevOpen() done (FAIL).\n");
+      return EINVAL;
+   }
+
+   sip = HgfsDevToSuperInfo(*devp);
+   if (!sip) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsDevOpen() done (FAIL).\n");
+      return ENXIO;
+   }
+
+   /* Make sure device isn't opened more than once */
+   if (sip->devOpen) {
+      return ENXIO;
+   }
+
+   sip->devOpen = TRUE;
+
+   DEBUG(VM_DEBUG_DEVDONE, "HgfsDevOpen() done.\n");
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsDevClose --
+ *    The entry point for close(9E), which is invoked when a user process
+ *    calls close(2) on the device.  This ensures that the specified device
+ *    number is valid (by trying to find its state structure).
+ *
+ * Results:
+ *    Returns zero on success, and an appropriate error code on failure.
+ *
+ * Side effects:
+ *    All pending requests are cancelled.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsDevClose(dev_t dev,            // IN: Device number
+             int flag,             // IN: Mode opened with (see HgfsOpen() comment)
+             int otyp,             // IN: Type of open (see HgfsOpen() comment)
+             cred_t *credp)        // IN: Pointer to credentials of caller
+{
+   HgfsSuperInfo *sip;
+
+   DEBUG(VM_DEBUG_DEVENTRY, "HgfsDevClose().\n");
+
+   ASSERT(credp);
+
+   /* This indicates a kernel error */
+   if (!credp) {
+      cmn_err(HGFS_ERROR, "NULL input from Kernel in HgfsDevClose().\n");
+      return EINVAL;
+   }
+
+   /*
+    * We only allow root to open and close the device.
+    */
+   if (!HgfsSuser(credp)) {
+      return EINVAL;
+   }
+
+
+   /* Just make sure this instance is valid, state is freed in HgfsDevDetach() */
+   sip = HgfsDevToSuperInfo(dev);
+   if (!sip) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsDevClose() done (FAIL).\n");
+      return ENXIO;
+   }
+
+   /*
+    * This will signify to the filesystem that the device half is no longer
+    * present.
+    */
+   sip->devOpen = 0;
+
+   /*
+    * Each submitted request must be told an error has occurred.
+    */
+   HgfsCancelAllRequests(sip);
+
+
+   DEBUG(VM_DEBUG_DEVDONE, "HgfsDevClose() done.\n");
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsDevRead --
+ *
+ *    Entry point for read(9E) that is invoked when a user process calls
+ *    read(2) on the device.
+ *
+ *    This checks the pending request list for any outstanding requests.  If
+ *    the list is empty, this blocks on a condition variable that is signaled
+ *    each time a request is enqueued.  The request is removed from the list
+ *    and copied to the user's buffer.
+ *
+ * Results:
+ *    Returns zero on success, an appropriate error code on failure.
+ *
+ * Side effects:
+ *    Blocks if the list is empty.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsDevRead(dev_t dev,          // IN: Device number
+            uio_t *uiop,        // IN: Ptr to structure defining read request
+            cred_t *credp)      // IN: Ptr to caller's credentials
+{
+   int ret;
+   HgfsSuperInfo *sip;
+   HgfsReq *nextReq = NULL;
+
+   DEBUG(VM_DEBUG_DEVENTRY, "HgfsDevRead().\n");
+
+   ASSERT(uiop);
+   ASSERT(credp);
+
+   /* These indicate a kernel error */
+   if ((!uiop) || (!credp)) {
+      cmn_err(HGFS_ERROR, "NULL input from Kernel in HgfsDevRead().\n");
+      return EINVAL;
+   }
+
+   sip = HgfsDevToSuperInfo(dev);
+   if (!sip) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsDevRead() done (FAIL).\n");
+      return ENXIO;
+   }
+
+   /*
+    * We need to check the request list to see if there is anything to read.
+    * If not, wait on the list's condition variable so we will be
+    * cv_signal()'ed when a request is placed onto the request list (by the
+    * filesystem half).  Once a request is there we can remove it from
+    * the list and copy it to user space.
+    */
+   mutex_enter(&sip->reqMutex);
+
+   for (;;) {
+      /*
+       * The cv_wait_sig(9F) man page says the cv_wait*() functions can return
+       * prematurely in certain situations, typically when job control or
+       * debugging is used, so it is required that we loop around cv_wait_sig().
+       */
+      while (HgfsListIsEmpty(&sip->reqList)) {
+         DEBUG(VM_DEBUG_COMM, "HgfsDevRead: blocking ...\n");
+         if (cv_wait_sig(&sip->reqCondVar, &sip->reqMutex) == 0) {
+            /*
+             * We received a system signal (e.g., SIGKILL) while waiting for the
+             * cv_signal().  Release mutex and return appropriate error code.
+             */
+            mutex_exit(&sip->reqMutex);
+            DEBUG(VM_DEBUG_FAIL,
+                  "cv_wait_sig() interrupted by signal in HgfsDevRead().\n");
+            return EINTR;
+         }
+      }
+
+      /*
+       * We hold the lock so the next request is guaranteed to be there.  If
+       * the next request is still in the submitted state then we process it;
+       * otherwise the request must be in the abandoned state and we destroy it
+       * and wait for the next one.
+       */
+      nextReq = HgfsDequeueRequest(sip);
+      ASSERT(nextReq);
+      if (HgfsReqGetState(nextReq) == HGFS_REQ_SUBMITTED) {
+         break;
+      }
+
+      ASSERT(HgfsReqGetState(nextReq) == HGFS_REQ_ABANDONED);
+      HgfsDestroyReq(sip, nextReq);
+   }
+
+   DEBUG(VM_DEBUG_LIST, "HgfsDevRead received request for ID %d", nextReq->id);
+   mutex_exit(&sip->reqMutex);
+
+   /*
+    * Filesystem ensures that requests are small enough to fit in a packet sent
+    * through the backdoor.
+    */
+   ret = HgfsSendRequestToUser(nextReq, uiop);
+   /*
+    * If we couldn't copy the request to guestd, set the request's state to
+    * error and wake up the client.  The filesystem will have to clean up.
+    */
+   if (ret) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsDevRead: could not copy request to user (FAIL).\n");
+      HgfsReqSetState(nextReq, HGFS_REQ_ERROR);
+      HgfsWakeWaitingClient(sip, nextReq);
+   }
+
+   DEBUG(VM_DEBUG_INFO, "resid=%ld\n", uiop->uio_resid);
+   DEBUG(VM_DEBUG_DEVDONE, "HgfsDevRead() done.\n");
+   return ret;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsDevWrite --
+ *
+ *    Entry point for write(9E), which is invoked when a user process calls
+ *    write(2) on the device.
+ *
+ *    This copies in a reply header, finds the associated request, then copies
+ *    the reply packet into the request packet.  It handles cleaning up
+ *    requests that have been abandoned.
+ *
+ * Results:
+ *    Returns zero on success, an appropriate error code on failure.
+ *
+ * Side effects:
+ *    The state of the request corresponding to this reply is modified.
+ *    The process waiting for this reply is woken up (if it is still waiting).
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsDevWrite(dev_t dev,         // IN: Device number
+             uio_t *uiop,       // IN: Ptr to structure defining write request
+             cred_t *credp)     // IN: Ptr to caller's credentials
+{
+   int ret;
+   uint32_t writeSize;
+   HgfsSuperInfo *sip;
+   HgfsReq *request;
+   HgfsReplyHeader reply;
+
+   DEBUG(VM_DEBUG_DEVENTRY, "HgfsDevWrite().\n");
+
+   ASSERT(uiop);
+   ASSERT(credp);
+
+   /* These indicate a kernel error */
+   if (!uiop || !credp) {
+      cmn_err(HGFS_ERROR, "NULL input from kernel in HgfsDevWrite().\n");
+      return EINVAL;
+   }
+
+   sip = HgfsDevToSuperInfo(dev);
+   if (!sip) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsDevWrite(): couldn't get superinfo (FAIL)\n");
+      return ENXIO;
+   }
+
+   /* We need at least the reply structure to do anything useful. */
+   if (uiop->uio_resid < sizeof reply) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsDevWrite(): too little data written (FAIL).\n");
+      return ERANGE;
+   }
+
+   /*
+    * If this fails there is a problem with guestd or the filesystem isn't
+    * splitting requests properly.  This also allows writeSize to be a uint32
+    * despite uiop->uio_resid being a ssize_t (which can be a long).
+    */
+   if (uiop->uio_resid > HGFS_PACKET_MAX) {
+      return EINVAL;
+   }
+
+   /* Needed to set packet size upon successful receipt of packet. */
+   writeSize = uiop->uio_resid;
+
+   /*
+    * Copy in just the reply header that will tell us what request this is
+    * for and what the status of the reply is.
+    */
+   ret = HgfsGetReplyHeaderFromUser(&reply, uiop);
+   if (ret) {
+      DEBUG(VM_DEBUG_FAIL,
+            "HgfsDevWrite(): couldn't copy header from user (FAIL).\n");
+      return EIO;
+   }
+
+   DEBUG(VM_DEBUG_COMM, "HgfsDevWrite: Reply for %d with status %d.\n",
+         reply.id, reply.status);
+
+   /*
+    * Here we need to determine which request this reply is for, then determine
+    * if that requester is still waiting.  If so we copy the contents of the
+    * reply into the request's packet and wake up the client; otherwise we
+    * destroy the abandoned request and return an error.
+    */
+   request = HgfsReplyToRequest(&reply);
+   if (!request) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsDevWrite(): invalid id in reply (FAIL).\n");
+      return EINVAL;
+   }
+
+   /*
+    * Acquiring this mutex makes the checking of whether the request has been
+    * ABANDONED and setting the request to COMPLETED or ERROR atomic.  It is
+    * also acquired in HgfsSubmitRequest().
+    */
+   mutex_enter(&sip->reqMutex);
+
+   if (HgfsReqGetState(request) == HGFS_REQ_ABANDONED) {
+      /* The requesting process is gone so we don't need to wake it up */
+      HgfsDestroyReq(sip, request);
+      mutex_exit(&sip->reqMutex);
+      DEBUG(VM_DEBUG_FAIL, "HgfsDevWrite(): request was abandoned (FAIL).\n");
+      return EINTR;  /* XXX: Does guestd need to know this? */
+   }
+
+   /*
+    * Now that we know which request this reply is for, zero out its packet and
+    * copy in the reply header.
+    */
+   bzero(request->packet, sizeof request->packet);
+   memcpy(request->packet, &reply, sizeof reply);
+
+   /* Copy rest of reply into request packet after the header */
+   ret = HgfsGetReplyPacketFromUser(request, sizeof reply, uiop);
+   if (ret < 0) {
+      /*
+       * If there was an error while copying the reply packet, we set the state
+       * to error and return an error code (in case guestd cares).
+       */
+      HgfsReqSetState(request, HGFS_REQ_ERROR);
+      ret = EIO;
+   } else {
+      /* ... otherwise we set the packet size and set the state to completed. */
+      request->packetSize = writeSize - uiop->uio_resid;
+      HgfsReqSetState(request, HGFS_REQ_COMPLETED);
+      ret = 0;
+   }
+
+   /*
+    * Wake up the client waiting on the request (Note we don't call
+    * HgfsWakeWaitingClient() since we already hold the lock.)
+    */
+   cv_signal(&request->condVar);
+   mutex_exit(&sip->reqMutex);
+
+   DEBUG(VM_DEBUG_DEVDONE, "HgfsDevWrite() done.\n");
+   return ret;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsDevChpoll --
+ *
+ *    Entry point for chpoll(9E), which is invoked (potentially more than
+ *    once) when either poll(2) or select(3C) is called by a user process.
+ *    This examines the state of the device and returns information indicating
+ *    which operations are ready to be performed.
+ *
+ * Results:
+ *    Returns 0 on success, or an error code if an error occurs.
+ *    If any of the events polled have occurred, this is specified by filling
+ *    in reventsp with the appropriate bits.
+ *    If none of the events polled have occurred, reventsp is cleared.  phpp
+ *    is also set to point to a pollhead structure if no other file
+ *    descriptors polled have had events.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsDevChpoll(dev_t dev,                // IN: Device number
+              short int events,         // IN: Events that could occur
+                                        //     (see man -s 9E chpoll for all
+                                        //     events)
+              int anyyet,               // IN: Flag (set if other fds have events pending)
+              short int *reventsp,      // OUT: Ptr to bitmask of events satisfied
+              struct pollhead **phpp)   // OUT: Ptr to a pollhead structure
+{
+   short revents;
+   HgfsSuperInfo *sip;
+
+   DEBUG(VM_DEBUG_DEVENTRY, "HgfsDevChPoll(). (events=%x)\n", events);
+
+   ASSERT(reventsp);
+   ASSERT(phpp);
+
+   /* These indicate a kernel error */
+   if ((!reventsp) || (!phpp)) {
+      cmn_err(HGFS_ERROR, "NULL input from Kernel in HgfsDevChpoll().\n");
+      return EINVAL;
+   }
+
+   sip = HgfsDevToSuperInfo(dev);
+   if (!sip) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsDevChPoll() done (FAIL).\n");
+      return ENXIO;
+   }
+
+   /*
+    * This comment is for reference, can remove in future:
+    *
+    * Algorithm to implement (chpoll(9E) and p195 DDK docs):
+    *
+    * if (events are satisfied now) {
+    *   *reventsp = (mask of satisfied events);
+    * } else {
+    *   *reventsp = 0;
+    *   if (!anyyet) {
+    *           *phpp = &(local pollhead structure);
+    *   }
+    * }
+    * return 0;
+    *
+    * The pollhead structure should not be referenced by the driver.
+    */
+
+   revents = 0;
+   /* Clear flag indicating the need to call pollwakeup() on write() */
+   sip->pollwakeupOnWrite = FALSE;
+
+   /*
+    * Caller asked to read: if the request list is not empty then they can
+    * read without blocking.
+    */
+   if (events & HGFS_POLL_READ) {
+      mutex_enter(&sip->reqMutex);
+
+      if ( !HgfsListIsEmpty(&sip->reqList) ) {
+         /* Set just those bits the caller asked for */
+         revents |= (events & HGFS_POLL_READ);
+      }
+      DEBUG(VM_DEBUG_CHPOLL, "HgfsChpoll(): HGFS_POLL_READ, revents=%d", revents);
+
+      mutex_exit(&sip->reqMutex);
+   }
+
+   /*
+    * Caller asked to write: they can always write.
+    */
+   if (events & HGFS_POLL_WRITE) {
+      revents |= (events & HGFS_POLL_WRITE);
+      DEBUG(VM_DEBUG_CHPOLL, "HgfsChpoll(): HGFS_POLL_WRITE, revent=%d\n", revents);
+   }
+
+   /*
+    * No events have occurred
+    */
+   if (revents == 0) {
+      DEBUG(VM_DEBUG_CHPOLL, "HgfsChpoll(): no events\n");
+      *reventsp = 0;
+      if (anyyet == 0) {
+         /*
+          * No other file descriptors have had events, so we set the pollhead
+          * structure and a flag indicating the need to call pollwakeup() on
+          * a successful completion of a write().
+          */
+         *phpp = &sip->hgfsPollhead;
+         DEBUG(VM_DEBUG_CHPOLL, "HgfsChpoll(): setting pollwakeupOnWrite.\n");
+         sip->pollwakeupOnWrite = TRUE;
+      }
+   }
+
+   *reventsp = revents;
+
+   DEBUG(VM_DEBUG_DEVDONE, "HgfsDevChPoll() done. (revents=%x)\n", revents);
+   return 0;
+}
+
+
+/*
+ * Functions to copy to and from user space.
+ */
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsSendRequestToUser --
+ *
+ *    Sends a requst to the user.
+ *
+ * Results:
+ *    Returns zero on success, and non-zero on error.
+ *
+ * Side effects:
+ *    The uio_resid field of uiop will be decremented by the number of bytes
+ *    read.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+HgfsSendRequestToUser(HgfsReq *req,     // IN: Request to send
+                      uio_t *uiop)      // IN: User's read request
+{
+   int ret;
+
+   DEBUG(VM_DEBUG_DEVENTRY, "HgfsSendRequestToUser().\n");
+
+   ASSERT(req);
+   ASSERT(uiop);
+
+   /*
+    * If the buffer provided by guestd is not large enough to hold the largest
+    * packet, then either the filesystem or guestd is doing something wrong.
+    * (uio_resid is the number of bytes we can write to the user's buffer.)
+    */
+   ASSERT(req->packetSize <= HGFS_PACKET_MAX);
+   ASSERT(uiop->uio_resid >= req->packetSize);
+
+   DEBUG(VM_DEBUG_INFO, "HgfsSendRequestToUser: uiomove(%p, %d, UIO_READ, %p)\n",
+           req->packet, req->packetSize, uiop);
+
+   /*
+    * uiomove(9F) will handle copying of data from kernel buffer to user buffer
+    * for us.  It understands the format of the uio_t that describes the
+    * user's read request and verifies user address is valid.  It returns zero
+    * on success and an error code otherwise.
+    */
+   ret = uiomove(req->packet,       // Kernel src address
+                 req->packetSize,   // Number of bytes to transfer
+                 UIO_READ,          // rwflag: READ
+                 uiop);             // Pointer to user's read request
+
+   DEBUG(VM_DEBUG_DEVDONE,
+         "HgfsSendRequestToUser() sent %d bytes in request (ret=%d).\n",
+         req->packetSize, ret);
+
+   return ret;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsGetReplyHeaderFromUser --
+ *
+ *    Copies the reply header from the user into the provided reply
+ *
+ * Results:
+ *    Returns zero on success, non-zero on error.
+ *
+ * Side effects:
+ *    uiop's uio_resid is decremented by the number of bytes that were copied.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static INLINE int
+HgfsGetReplyHeaderFromUser(HgfsReplyHeader *header,  // OUT: Header to copy into
+                           uio_t *uiop)              // IN: User's write request
+{
+   ASSERT(header);
+   ASSERT(uiop);
+
+   DEBUG(VM_DEBUG_COMM,
+         "HgfsGetReplyHeaderFromUser(): writing %"FMTSZ"u bytes"
+         " into request packet's header.\n", sizeof *header);
+
+   /* Only copy in the header, uio_resid decremented for us by uiomove() */
+   return uiomove(header, sizeof *header, UIO_WRITE, uiop);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsGetReplyPacketFromUser --
+ *
+ *    Copies the rest of the user's reply into the offset of the request's
+ *    packet.
+ *
+ * Results:
+ *    Returns zero on success, non-zero on error.
+ *
+ * Side effects:
+ *    None.
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+HgfsGetReplyPacketFromUser(HgfsReq *req,        // IN/OUT: Request to copy into
+                           ssize_t offset,      // IN: Offset in packet to
+                                                //     start copying at
+                           uio_t *uiop)         // IN: User's write request
+{
+   ASSERT(req);
+   ASSERT(uiop);
+
+
+   /*
+    * If guestd has more to write than the max room left in the packet then it
+    * is doing something wrong.
+    */
+   ASSERT(uiop->uio_resid <= HGFS_PACKET_MAX - offset);
+
+   DEBUG(VM_DEBUG_COMM,
+         "HgfsGetReplyPacketFromUser(): writing %ld bytes into request packet.\n",
+         uiop->uio_resid);
+
+   /* Write the reply into the specified buffer */
+   return uiomove(req->packet + offset, uiop->uio_resid, UIO_WRITE, uiop);
+}
+
+
+
+/*
+ * Utility functions
+ */
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsDevToSuperInfo --
+ *
+ *    Gets a pointer to the super info structure from a device number (dev_t).
+ *
+ * Results:
+ *    Returns a pointer to the super info struct, or NULL if it cannot be
+ *    found.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static INLINE HgfsSuperInfo *
+HgfsDevToSuperInfo(dev_t dev)         // IN: Device number
+{
+   minor_t instance;
+
+   DEBUG(VM_DEBUG_DEVENTRY, "HgfsDevToSuperInfo().\n");
+
+   instance = getminor(dev);
+
+   DEBUG(VM_DEBUG_RARE,
+         "HgfsDevToSuperInfo: getting ptr to instance %d's state.\n", instance);
+
+   return (HgfsSuperInfo *)ddi_get_soft_state(superInfoHead, (int)instance);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ *  HgfsDevinfoToSuperInfo --
+ *
+ *    Gets a pointer to the super info from a device information struct.
+ *    XXX: currently unused since HgfsDevDetach needs value of instance
+ *    itself.
+ *
+ * Results:
+ *    Returns a pointer to the super info structure, or NULL if it cannot be
+ *    found.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static INLINE HgfsSuperInfo *
+HgfsDevinfoToSuperInfo(dev_info_t *dip) // IN: Device information structure
+{
+   int instance;
+
+   ASSERT(dip);
+
+   instance = ddi_get_instance(dip);
+
+   DEBUG(VM_DEBUG_RARE,
+         "HgfsDevinfoToSuperInfo: getting ptr to instance %d's state.\n", instance);
+
+   return (HgfsSuperInfo *)ddi_get_soft_state(superInfoHead, instance);
+}
+
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsReplyToRequest --
+ *
+ *    Determines the request that corresponds with the provided reply.
+ *
+ * Results:
+ *    Returns a pointer to the request, or NULL if it cannot be located.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static INLINE HgfsReq *
+HgfsReplyToRequest(HgfsReplyHeader *reply)      // IN: Reply to find request of
+{
+   ASSERT(reply);
+
+   if (reply->id > HGFS_MAX_OUTSTANDING_REQS) {
+      return NULL;
+   }
+
+   /*
+    * When this function is called, the request should only be in the
+    * SUBMITTED, ABANDONED, or ERROR states.
+    */
+   ASSERT((HgfsReqGetState(&requestPool[reply->id]) == HGFS_REQ_SUBMITTED) ||
+          (HgfsReqGetState(&requestPool[reply->id]) == HGFS_REQ_ABANDONED) ||
+          (HgfsReqGetState(&requestPool[reply->id]) == HGFS_REQ_ERROR));
+
+   DEBUG(VM_DEBUG_INFO, "HgfsRequestToReply: reply for request id %d\n", reply->id);
+
+   return &requestPool[reply->id];
+}
diff --git a/open-vm-tools/modules/solaris/vmhgfs/device.h b/open-vm-tools/modules/solaris/vmhgfs/device.h
new file mode 100644 (file)
index 0000000..f9403f0
--- /dev/null
@@ -0,0 +1,46 @@
+/*********************************************************
+ * Copyright (C) 2004 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+
+/*
+ * device.h --
+ *
+ * Definitions and includes for device driver code.
+ *
+ */
+
+
+#ifndef __DEVICE_H_
+#define __DEVICE_H_
+
+#include <sys/open.h>           /* OTYP_CHR */
+#include <sys/stat.h>           /* S_IFCHR */
+#include <sys/ddi.h>            /* Device Driver Interface */
+#include <sys/sunddi.h>         /* Sun DDI defines (DDI_PSEUDO) */
+#include <sys/ksynch.h>         /* mutex and condition variables */
+
+#include "debug.h"
+
+/*
+ * Macros
+ */
+
+/* Flags for chpoll(): we don't distinguish between these priorities of data */
+#define HGFS_POLL_READ          (POLLIN | POLLRDNORM | POLLRDBAND)
+#define HGFS_POLL_WRITE         (POLLOUT | POLLWRNORM | POLLWRBAND)
+
+
+#endif /* __DEVICE_H_ */
diff --git a/open-vm-tools/modules/solaris/vmhgfs/docs/BUILD b/open-vm-tools/modules/solaris/vmhgfs/docs/BUILD
new file mode 100644 (file)
index 0000000..e7e8e99
--- /dev/null
@@ -0,0 +1,251 @@
+Solaris Hgfs Build Instructions
+===============================
+
+Last Updated: 11/22/2005 (biggadike@vmware.com)
+
+Hgfs Kernel Module
+------------------
+0. One-time Guest Operations
+1. Building with the Linux cross-compiler (Solaris 9)
+2. Building from the Guest (Solaris 10)
+
+Tools
+-----
+0. Building guestd and the toolbox
+1. Running guestd
+2. Running the toolbox
+
+
+Hgfs Kernel Module
+------------------
+
+ 0. One-time Guest Operations
+ -------------------------
+ Requirements: just a Solaris 9 or 10 guest
+
+ o First, to build you'll need to make sure gmake, gcc, and binutils are
+   installed.  The easiest way to install these is to use the pkg-get script
+   from http://www.blastwave.org/pkg-get.php.  Follow the instructions there
+   then do:
+
+   # pkg-get -U
+   # pkg-get -i gmake gcc2 binutils   
+   # export PATH=$PATH:/opt/csw/bin     (for Bash)
+   # alias make='gmake'                 (for Bash)
+
+ o You'll need to add an entry to the device link table so that when the driver
+   is loaded a symlink called /dev/vmware-hgfs is created that points to the
+   entry in the Kernel's device tree (/devices).
+
+   # cat docs/append-to-devlink.tab >> /etc/devlink.tab
+
+ o You'll also need a copy of the driver's configuration file where the kernel
+   looks for it.
+
+   # cp docs/hgfs.conf /usr/kernel/drv
+
+ o You also need to create the directory where guestd will mount the
+   filesystem:
+
+   # mkdir -p /mnt/hgfs
+
+ These only need to be done once.
+
+
+ 1. Building with the Linux cross-compiler (Solaris 9)
+ -----------------------------------------------------
+ Note that the cross-compiler is currently only for Solaris 9.
+
+ o From top of bora-vmsoft:
+   
+   # make tools-for-solaris
+
+ o Respected build variables:
+   VMX86_DEVEL : gets passed on to code
+   VMX86_DEBUG : enables assertion checking
+   VMX86_LOG   : enables logging
+   SOL_VERSION : defaults to 9 because the Solaris 10 cross-compiler doesn't
+                 exist yet
+
+ o Installing Targets (run these from the guest):
+   rem         : removes the driver from the system
+   install     : installs the driver and driver config file to the proper
+                 directories
+   add         : adds the driver to the system
+   rotate      : invokes rem, install, then add.
+
+ Note that most of the time rotate will take care of everything for you, but if
+ guestd is running this may cause problems because the driver will be added
+ even if the module cannot be removed.  Just kill guestd then make rotate.
+
+
+ 2. Building from the Guest (Solaris 10)
+ ---------------------------------------
+
+ Note that this is currently the only way to build in Solaris 10.
+
+ o Make sure the BORA, BUILD, and BUILDROOT variables are set properly in the
+   Makefile.guest.
+
+   It's likely all you need know is:
+    make -f Makefile.guest module
+    make -f Makefile.guest install add
+
+   If you want to disable debugging, use:
+    make -f Makefile.guest module DEBUG=OFF
+
+   If you get a "module already loaded" error, try:
+    make -f Makefile.guest rotate
+ o Building targets:
+   module      : builds only the Kernel module (current default)
+   clean       : cleans build files
+   
+ o Building variables:
+   DEBUG=OFF  : turns off all debugging output from the module (faster!)
+   ASSERT=OFF  : turns off ASSERT()s
+   SOL_VERSION : defaults to 10 and automatically determines which build number
+                 this is with uname -v (52 and 58 are the only builds tested)
+
+ o Installing Targets (run these from the guest):
+   rem         : removes the driver from the system
+   install     : installs the driver and driver config file to the proper
+                 directories
+   add         : adds the driver to the system
+   rotate      : invokes rem, install, then add.
+   once        : appends necessary lines to /etc/devlink.tab (only needed once)
+   initbuilddir: creates the build directory
+
+Tools
+-----
+
+ 0. Building guestd and the toolbox
+ ------------------------------
+
+ o guestd has been ported to Solaris and is built using the Solaris 9 cross
+   compiler mentioned above.  The toolbox has not been ported to Solaris and is
+   run using lxrun.  Building both is handled by the Makefiles in bora-vmsoft:
+
+   # cd /path/to/bora-vmsoft
+   # make tools-for-solaris
+
+   The binaries will be located at $(BUILD)/obj/ws/tools-for-solaris/guestd/guestd
+   and $(BUILD)/obj/ws/tools-for-solaris/toolbox/toolbox.
+
+ 1. Running guestd
+ -----------------
+
+ o guestd runs natively on Solaris 9.  It will mount Hgfs at /mnt/hgfs and your
+   "Shared Folders" will be visible there.
+
+ o I have not been able to use the bora-vmsoft Makefile infrastructure from
+   within a Solaris 10 guest, so it is not currently possible to build guestd
+   for Solaris 10.  Porting the Makefiles to run inside the guest should not be
+   too difficult and a Solaris 10 cross compiler would allow guestd to be built
+   for Solaris 10.
+   
+ 2. Running the toolbox
+ ----------------------
+
+ o It is first necessary to set up lxrun on the guestd
+
+   Setting up lxrun
+   ----------------
+
+   o lxrun enables you to run Linux binaries in Solaris by catching and
+     translating all of their system calls.  This works relatively well for
+     running guestd and toolbox, but you must install lxrun and build versions of
+     the programs that have been "ported" to lxrun.
+
+   o Install lxrun on the guest:
+  
+     The easiest way is to see if ~biggadike/public_html/lxrun/lxrun-environ.tgz
+     exists.  If so, extract this to the root of your guest's filesystem:
+
+     # cd /
+     # gunzip /path/to/lxrun-environ.tgz
+     # tar xvf /path/to/lxrun-environ.tar
+
+     This will create two directories: /lx and /usr/local/lxrun.  /lx contains
+     a linux environment (circa Red Hat 6.2) and the lxrun executable.
+     /usr/local/lxrun contains a file called PATHMAP which tells lxrun where to
+     get its environment files from (/lx).
+
+     If the precompiled environment doesn't work, you'll need to get lxrun
+     0.9.6pre1, compile it, and then use a Red Hat 6.2 Installation CD with the
+     INSTALL-RH6 script in the lxrun directory.
+
+     o Try ~biggadike/public_html/lxrun/lxrun-0.9.6pre1.tar.gz or
+       http://www.ugcs.caltech.edu/~steven/lxrun/ for the lxrun source
+     o Try exit15:/home/ISO-Images/vol1/redhat/RedHat6.2.iso for the Red Hat disc
+
+     **Note that it is not necessary to patch lxrun for the toolbox.  The patch
+       in the directory mentioned above is to enable lxrun to run guestd, which
+       is no longer necessary since it has been ported.  The lxrun binary in
+       the lxrun-environ.tgz file is a patched version, but this does also work
+       for running the toolbox.
+
+   o Set necessary environment variables:
+
+     You will also need a few environment variables set.  For bash, add these
+     lines to your .bashrc:
+   
+     export LXRUN_ROOT=/lx
+     export PATH=$PATH:/lx
+
+ o The following steps outline running the toolbox with lxrun
+
+    Running the toolbox
+    -------------------
+
+    o Just copy (or make available) the above binaries on your guest and invoke
+      them with lxrun:
+
+      # lxrun /path/to/toolbox &
+
+      (It is usually best to background this process.)
+
+    o lxrun can also log the system calls it translates using its trace feature:
+
+      # lxrun -t all /path/to/toolbox
+
+      This will trace all the system calls guestd makes.  The output file is always
+      placed in /tmp/lxrun.<pid>.  You can also restrict the system calls that are
+      traced to a particular subset, run lxrun without any options to see the usage.
+
+      It also appears possible to chroot the running process with -r, to specify the
+      linux root directory with -R, and specify the uname of the emulated Linux
+      system with -U.  I haven't ever needed to use these options.
+
+ o Mouse grab/ungrab and device connection/disconnection are both known to work.
+
+
+
+
+Notes from the old BUILD file that may still be helpful
+-------------------------------------------------------
+   
+ o You can verify the module is installed with:
+
+   # modinfo | grep hgfs
+
+   This should output text of this format:
+   <id#> <loadaddr> <size> <info> <revision#> hgfs (HGFS Device Interface)
+   <id#> <loadaddr> <size> <info> <revision#> hgfs (Host/Guest Filesystem)
+
+   There are two entries for the same ID number because we've placed both the
+   device driver and the filesystem in a single loadable kernel module.
+
+ o You can load the driver into the Kernel by hand with:
+   # /usr/sbin/add_drv -v -m '* 0644 root sys' hgfs
+
+   This should output something similar to:
+   devfsadm[1032]: verbose: mknod /devices/pseudo/hgfs@0:vmware-hgfs 0l/3l/20644
+   devfsadm[1032]: verbose: symlink /dev/vmware-hgfs -> ../devices/pseudo/hgfs@0:vmware-hgfs
+
+ o You can remove the driver from the system by hand with:
+
+   # /usr/sbin/rem_drv hgfs
diff --git a/open-vm-tools/modules/solaris/vmhgfs/docs/FILES b/open-vm-tools/modules/solaris/vmhgfs/docs/FILES
new file mode 100644 (file)
index 0000000..952d961
--- /dev/null
@@ -0,0 +1,30 @@
+Files
+=====
+
+Driver (hgfs/solaris/)
+----------------------------------
+hgfsSolaris.h    - definitions global to all parts of module
+module.{c,h}     - module initialization routines (_init(), _fini()) and
+                   structures (struct modlinkage, struct modlfs, ...)
+filesystem.{c,h} - filesystem level functions (mount(), unmount())
+hgfsState.{c,h}  - maintains internal state of filesystem (HgfsOpenFile, HgfsFile)
+vnode.c          - file level functions (open(), read(), close())
+device.{c,h}     - device interface (attach(), detach(), open(), read(),
+                   close())
+request.{c,h}    - functions that initialize, allocate, and manipulate requests
+                   and the lists that they are on
+debug.{c,h}      - debugging routines and macros
+
+Misc (hgfs/solaris/docs)
+------------------------------------
+hgfs.conf             - must be place in /usr/kernel/drv/
+append-to-devlink.tab - must append this text to /etc/devlink.tab to generate
+                        symlink /dev/vmware-hgfs
+
+Docs (hgfs/solaris/docs)
+------------------------------------
+BUILD                 - build instructions
+synchronization.txt   - outline of how components are synchronized
+request-lifecycle.txt - outline of how requests travel through driver
+kadb.txt              - cheat sheet for Solaris' kernel debugger
+hgfs-9-to-10.txt      - notes for porting from Solaris 9 to 10
diff --git a/open-vm-tools/modules/solaris/vmhgfs/docs/append-to-devlink.tab b/open-vm-tools/modules/solaris/vmhgfs/docs/append-to-devlink.tab
new file mode 100644 (file)
index 0000000..06268af
--- /dev/null
@@ -0,0 +1 @@
+type=ddi_pseudo;name=vmhgfs;addr=0;minor=vmware-hgfs   \M0
diff --git a/open-vm-tools/modules/solaris/vmhgfs/docs/hgfs-9-to-10.txt b/open-vm-tools/modules/solaris/vmhgfs/docs/hgfs-9-to-10.txt
new file mode 100644 (file)
index 0000000..45428e1
--- /dev/null
@@ -0,0 +1,145 @@
+Notes for porting Hgfs from Solaris 9 to 10
+===========================================
+
+Note that Solaris 10 is a beta and still in development, so these notes may
+become outdated.  They are based on the headers in build 52.
+
+vnode.h
+-------
+o Now use vn_make_ops() to create vnodeops
+   int vn_make_ops(const char *, const fs_operation_def_t *, vnodeops_t **);
+   void vn_freevnodeops(vnodeops_t *);
+
+o Now use vfs_makefsops()/vfs_setfsops() to create vfsops
+   (see vfs.h notes)
+
+o There is a new structure struct fs_operation_def_t:
+  
+   typedef int (*fs_generic_func_p) ();
+   
+   typedef struct fs_operation_def {
+      char *name;                /* name of operation (NUL terminated) */
+      fs_generic_func_p func;    /* function implementing operation */
+   } fs_operation_def_t;
+
+  The name is likely one of the VOPNAME_* macros.
+
+o vnodes should only be created by calls to vn_alloc(); they may not be embedded
+  in fs-specific structures; vnodes may change size.  Definitions for related
+  vnode allocation/freeing functions are:
+   vnode_t *vn_alloc(int);
+   void    vn_reinit(vnode_t *);
+   void    vn_free(vnode_t *);
+
+  Note that the vn_free() function destroys the vnode's mutex so doing so
+  yourself will crash the system.
+
+o There are a quite a few new vnode manipulation functions; see vnode.h.
+  
+o v_vfsmountedhere member of struct vnode is private, perhaps we shouldn't touch
+  it; it is also protected by vn_vfswlock in vnode.c
+
+o A number of private members were added to struct vnode -- shouldn't affect us
+
+o New structure struct caller_context contains PID of caller, system ID, and
+  a caller identifier.  This structure is now passed in as the last argument to:
+   o vop_read
+   o vop_write
+   o vop_setattr
+   o vop_rwlock
+   o vop_rwunlock
+   o vop_space
+
+o vop_shrlock now takes an additional cred_t * argument as its last argument
+
+o A new vnodeop was added:
+   int (*vop_vnevent)(vnode_t *, vnevent_t);
+  
+  This likely has to do "something" to the vnode depending on the value of
+  vnevent_t.  It is likely that this is required since the vnode now stores the
+  cached path of the file in its private char *v_path member.  Can we use
+  vnevent_*() for help, or do these call us?  How about the new vn_setpath*(),
+  vn_path(), and vn_copypath() functions?  (We should use the VN_SETPATH() macro
+  instead of calling vn_setpath() directly.)
+
+o vnevent_t is a new enum with the following definition:
+   typedef enum vnevent {
+      VE_SUPPORT     = 0,        /* Query */
+      VE_RENAME_SRC  = 1,        /* Rename, with vnode as source */
+      VE_RENAME_DEST = 2,        /* Rename, with vnode as target/dest */
+      VE_REMOVE      = 3,        /* Remove of vnode's name */
+      VE_RMDIR       = 4         /* Remove of directory vnode's name */
+   } vnevent_t;
+
+o A new macro VN_SET_VFS_TYPE_DEV(vp, vfsp, type, dev) was created, but it is
+  trivial.
+
+o VN_CMP() now calls vn_getops() rather than dereferencing the vnode's vn_ops
+  member.  (We should use this to access that variable too, it seems.)
+
+o There is no more VN_INIT() macro, but it was trivial anyhow.
+
+
+vfs.h
+-----
+o Filesystems now must supply their list of vfs operations using:
+   int vfs_setfsops(int, const fs_operation_def_t *, vfsops_t **);
+
+o There are also functions for filesystems to make, free, etc vfs operation
+  structures:
+   int  vfs_makefsops(const fs_operation_def_t *, vfsops_t **);
+   void vfs_freevfsops(vfsops_t *);
+   int  vfs_freevfsops_by_type(int);
+   void vfs_setops(vfs_t *, vfsops_t *);
+   vfsops_t *vfs_getops(vfs_t *vfsp);
+   <there are some more: see vfs.h>
+
+  The names placed in fs_operation_def_t->name are likely one of the VFSNAME_*
+  macros.
+
+o This isn't relevant to our layer, but the vfs now keeps filesystems in
+  a double linked circular list rather than a singly linked list.  There are
+  also issues with zones: each zone has a list of its own mounts.
+
+o The vfs_op member of struct vfs should never be directly accessed; use the
+  accessor functions described above.
+
+o There is a new function in struct vfsops:
+   int (*vfs_vnstate)(vfs_t *, vnode_t *, vntrans_t);
+
+o vntrans_t is a new enum that is either VNTRANS_EXISTS, VNTRANS_IDLED,
+  VNTRANS_RECLAIMED, or VNTRANS_DESTROYED.
+
+o The function pointer vsw_init member of struct vfssw now has the definition:
+   int (*vsw_init)(int, char *)
+
+  Also, the vsw_optproto and vsw_vfsops members are no longer pointers.
+
+  Since we will not be directly including this structure in our modlfs anymore
+  (see modctl.h notes), these differences probably don't matter.
+
+o There is a new structure (that will be used in our modlfs now instead of
+  struct vfssw).
+  
+  typedef struct vfsdef_v2 {
+     int       def_version;             /* structure version, must be first */
+     char      *name;                   /* filesystem type name */
+     int       (*init) (int, char *);   /* init routine */
+     int       flags;                   /* fs flags */
+     mntopts_t *optproto;               /* mount options table prototype */
+  } vfsdef_v2;
+
+  Note that build 58 contains the same structure but it is called vfsdef_v3.
+
+o There are a few other additional macros and functions that likely won't matter
+  to us.
+  
+modctl.h
+--------
+o struct modlfs now has a struct vfsdef_v3 instead of a struct vfssw
+o other changes don't seem relevant
+
+devops.h
+--------
+o There are no changes to struct cb_ops, struct dev_ops, or any of the command
+  enums taken by these functions.
diff --git a/open-vm-tools/modules/solaris/vmhgfs/docs/hgfs.conf b/open-vm-tools/modules/solaris/vmhgfs/docs/hgfs.conf
new file mode 100644 (file)
index 0000000..b456e24
--- /dev/null
@@ -0,0 +1,3 @@
+# name=<driver name> parent="pseudo" instance=0;
+name="vmhgfs" parent="pseudo" instance=0;
+
diff --git a/open-vm-tools/modules/solaris/vmhgfs/docs/kadb.txt b/open-vm-tools/modules/solaris/vmhgfs/docs/kadb.txt
new file mode 100644 (file)
index 0000000..beb668b
--- /dev/null
@@ -0,0 +1,78 @@
+Solaris kadb cheat sheet
+=========================
+
+Setting up
+----------
+ See Chapter 18 of Solaris' 9 "Writing Device Drivers"
+ (http://docs.sun.com/db/doc/806-5222)
+
+ If using a tip connection, boot with 'b kadb -d' and at the break for __start,
+ create a deferred breakpoint with this command: hgfs# HgfsDevAttach:b
+
+Breakpoints
+-----------
+ Deferred: <module># <symbol>:b
+ Regular : <symbol>:b
+ - Regular will complain if symbol isn't found.
+
+ Examples:
+  hgfs# HgfsDevAttach:b  --> deferred breakpoint for HgfsDevAttach
+                             takes effect when hgfs module is loaded
+  HgfsGetNewReq:b        --> breakpoint for HgfsGetNewReq
+  Commands at breakpoints:
+  :c : continue
+  :s : single step
+  :e : single step over function calls
+  :u : stop after return to caller of current function
+  :d : delete breakpoint
+  :z : delete allbreakpoints
+  
+
+Viewing
+-------
+
+ <symbol>,<count>/<modifier>
+
+ <symbol>  : symbol name, as in HgfsDevAttach, or address
+ <count>   : number of items to show
+ <modifier>: see pg. 348 "Writing Device Drivers" for complete list
+             Common:
+              d,D : 2,4-byte decimal
+              x,X : 2,4-byte hex
+              K   : 4-byte hex for 32 bit progs (use this for pointers)
+              u,U : 2,4-byte unsigned decimal
+              c,C : character, without or with ^escape notation
+              s,S : string, without or with ^escape notation
+              i   : instructions
+              a   : prints address in symbolic form
+              w,W : 2,4-byte write
+
+ Examples:
+  HgfsGetNewReq,24/ai --> see first 24 instructions of HgfsGetNewReq
+  0x01234567,24/X     --> see 24 4-byte words at that address in hex
+  *0x1234567,24/X     --> see the 24 4-byte words at memory address
+                          specified in 0x1234567
+  
+Macros
+------
+$r : view registers
+$c : stack trace
+$b : display breakpoints
+
+
+Pager (pause after <lines> lines)
+-----
+ 0t<lines>::more
+
+
+Registers
+---------
+
+ Display a single register: <(register)=K
+ Set value of a register  : (value)>(register)
+
+ Examples:
+  <eip=K          Display the current contents of eip
+  0xdf78b1f8>eip  Set the value of eip to 0xdf78b1f8
diff --git a/open-vm-tools/modules/solaris/vmhgfs/docs/request-lifecycle.txt b/open-vm-tools/modules/solaris/vmhgfs/docs/request-lifecycle.txt
new file mode 100644 (file)
index 0000000..265bb3f
--- /dev/null
@@ -0,0 +1,132 @@
+The lifecycle of a request in the Solaris HGFS code
+===================================================
+
+Note that this design is based almost entirely on the Linux HGFS code.
+
+Data Structures
+---------------
+- A preallocated request pool array. (requestPool[])
+- A list of the current free requests. (reqFreeList)
+- A list of the currently pending requests (reqList)
+
+Request States
+--------------
+- Unused:
+   This is a request's initial state and it guarantees that the
+   request is on the free request list.  Requests are placed back in
+   this state after the Abandoned, Error, or Completed states.
+   
+- Allocated: 
+   The request has been allocated to a client and is not on any of
+   the lists.
+   
+- Submitted:
+   The request has been filled out and has been placed on the pending
+   request list.  The request may leave the pending request list while
+   still in this state.
+   
+- Abandoned:
+   The client was interrupted while waiting for the reply and has
+   left the request to be cleaned up when a reply comes.  The request 
+   is either still on the pending list or is not on any list, and will
+   be accessed by its index into the requestPool array.
+   
+- Error:
+   An error occurred while submitting the request or awaiting the
+   reply.  The request is not on any lists.
+
+- Completed: 
+   The reply for this request has been received correctly.  The
+   request is not on any lists.
+             
+
+State Transition
+-----------------
+
+Each request starts as Unused and is then Allocated and Submitted.  After the
+request is submitted, the request can be Abandoned, can have an Error occur, or
+can Complete successfully.  Each of these states transitions back to the Unused
+state.
+
+--> Unused --> Allocated --> Submitted ---> Abandoned ------> Unused
+                                       \                   /
+                                        --> Error -------->
+                                        \                /
+                                         -> Completed -->
+
+Functions
+---------
+These functions will affect the state of requests and their locations on the
+lists.
+
+- HgfsInitRequestList():
+   This will initialize each request's state to UNUSED and ID to its index into
+   the requestPool array.  Each request will also be added to the free request
+   list (reqFreeList).
+
+- HgfsCancelAllRequests():
+   Iterates over the pending request list and the request pool and cancels each
+   request.  If a request is abandoned it must clean up for the interrupted
+   process; if the requester is waiting, set the request state to error and wake
+   up the client.
+
+- HgfsGetNewReq():
+   Takes an UNUSED request off the free list (reqFreeList) and sets its state
+   to ALLOCATED.  The request will not be on any lists after this function is
+   completed.
+
+- HgfsEnqueueRequest():
+   Puts an ALLOCATED request on to the pending request list (reqList) and sets
+   its state to SUBMITTED.  The request should not be on any of the lists when
+   this function is called.  This function will also assume that the list lock
+   is held since most callers of this function will need to enqueue and do
+   other operations atomically.
+
+- HgfsDequeueRequest():
+   Takes a SUBMITTED or ERROR request from the pending request list (reqList).
+   The request will not be on any lists after this function is completed.  For
+   the reason noted above, this function also assumes the list lock is held by
+   the caller.
+
+- HgfsDestroyReq():
+   Puts a COMPLETED, ERROR, or ABANDONED request on to the free list
+   (reqFreeList) and sets its state to UNUSED.  The request should not be on
+   any lists when this function is called.
+
+- HgfsReqSetState():
+   Will set the state of the specified request to the specified value.  This
+   abstraction is to help prevent forgetting to lock the state's mutex.
+
+- HgfsReqGetState():
+   Will return the state of the specified request.  This abstraction is to help
+   prevent forgetting to lock the state's mutex.
+
+
+Submitting a request
+--------------------
+
+{
+   request = HgfsGetNewReq(superinfo);
+   if (request is NULL) {
+      return error
+   }
+
+   Fill in specific request information in request->packet
+      - header.id and header.op of specific request struct
+        should be set
+      - request specific information should be filled in
+      - request->packetSize should be set
+   
+   if (HgfsSubmitRequest(superinfo, request) fails) {
+      return error
+   }
+
+   if (HgfsValidateReply(request, minimum size) fails) {
+      HgfsDestroyReq(superinfo, request);
+      return error
+   }
+
+   Process reply and give to client
+
+   HgfsDestroyReq(superinfo, request);
+}
diff --git a/open-vm-tools/modules/solaris/vmhgfs/docs/synchronization.txt b/open-vm-tools/modules/solaris/vmhgfs/docs/synchronization.txt
new file mode 100644 (file)
index 0000000..5699135
--- /dev/null
@@ -0,0 +1,101 @@
+Solaris HGFS Synchronization
+============================
+
+The Solaris synchronization primitives that will be used are mutexes and
+condition variables.  Mutexes will protect access to shared resources
+and condition variables will synchronize the order of the operations by
+those accessing these resources.
+
+Synchronization must be achieved in two directions.  First, a client
+that requests an operation on a HGFS file must wait for the reply from
+the HGFS server.  Second, guestd must wait for requests to be made when
+it queries the HGFS device and there are no pending requests.
+
+To enable this synchronization, the superinfo structure will contain
+these elements:
+- a list of outgoing requests (reqList)
+- a condition variable for waiting until and signaling when requests are put
+  on an empty list (reqCondVar)
+- a flag which indicates whether guestd is waiting for a request
+  (guestdWaiting)
+- a mutex to protect access to these components (reqMutex)
+
+Additionally, each request structure should contain:
+- a condition variable for waiting for and signaling of replies to
+  /this/ request (condVar)
+- a flag indicating whether the requesting thread has been interrupted
+  and is no longer waiting for the reply (abandoned)
+
+The filesystem half of the driver will place requests onto reqList with
+the following pseudocode:
+{
+ Acquire and initialize request structure from free request list
+ mutex_enter(superinfo's reqMutex)
+ HgfsEnqueueRequest(request list, request)
+ if (superinfo's guestdWaiting is set) {
+   cv_signal(superinfo's reqCondVar)
+ }
+ cv_wait_sig(request's condVar, superinfo's reqMutex)
+ if (cv_wait_sig() was interrupted) {
+   request's abandoned = TRUE
+   release mutex and return EINTR
+ }
+ mutex_exit(superinfo's reqMutex)
+ Read reply in request's packet
+ When done, put request structure back on free list
+}
+
+Note that the calls to cv_signal() and cv_wait_sig() above must be atomic,
+otherwise a reply could come and incur a signal before cv_wait_sig() is
+called.  Therefore, the superinfo's reqMutex must also be passed to the
+cv_wait_sig() on the request structure's condition variable.
+
+The device half of the driver will check for and take requests of the
+request list with the following pseudocode (HgfsDevRead()):
+{
+   mutex_enter(superinfo's reqMutex)
+   
+   if (request list is empty) {
+      superinfo's guestdWaiting = TRUE
+      cv_wait_sig(superinfo's reqCondVar, superinfo's reqMutex)
+      if (cv_wait_sig() was interrupted) {
+         superinfo's guestdWaiting = FALSE
+         release mutex and return EINTR
+      }
+      superinfo's guestdWaiting = FALSE
+   }
+
+   Take next request off request list
+   
+   mutex_exit(superinfo's reqMutex)
+
+   Submit request to guestd
+}
+
+When a reply is received, the device half of the driver will handle it
+with the following pseudocode (HgfsDevWrite()):
+{
+   Read in and verify the reply from guestd
+   Get pointer to the request structure from the handle in reply
+   Copy reply payload to the request packet
+
+   mutex_enter(superinfo's reqMutex)
+   if (request's abandoned is set) {
+      Clean up on behalf of interrupted thread
+      - place request back on free list
+      return <guestd doesn't care about this "error">
+   }
+   cv_signal(request's condVar)
+   mutex_exit(superinfo's reqMutex)
+}
+
+
+
+
+
+
diff --git a/open-vm-tools/modules/solaris/vmhgfs/filesystem.c b/open-vm-tools/modules/solaris/vmhgfs/filesystem.c
new file mode 100644 (file)
index 0000000..c8d38de
--- /dev/null
@@ -0,0 +1,841 @@
+/*********************************************************
+ * Copyright (C) 2004 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+
+/*
+ * filesystem.c --
+ *
+ * Implementation of the filesystem level routines.  These include functions
+ * that intialize, mount, unmount, and provide other various filesystem
+ * information.
+ */
+
+#include <sys/param.h>          /* MAXNAMELEN */
+
+#include "hgfsSolaris.h"
+#include "hgfsState.h"
+#include "filesystem.h"
+#include "vnode.h"
+#include "request.h"
+#include "debug.h"
+
+/*
+ * Prototypes
+ *
+ * These are only needed because Solaris 10 requires that we create the vfsops
+ * structure through their provided interface (vfs_setfsops()).
+ */
+#if HGFS_VFS_VERSION > 2
+int HgfsMount(struct vfs *vfsp, struct vnode *vnodep,
+              struct mounta *mntp, struct cred *credp);
+int HgfsUnmount(struct vfs *vfsp, int mflag, struct cred *credp);
+int HgfsRoot(struct vfs *vfsp, struct vnode **vnodepp);
+int HgfsStatvfs(struct vfs *vfsp, struct statvfs64 *stats);
+int HgfsSync(struct vfs *vfsp, short flags, struct cred *credp);
+int HgfsVget(struct vfs *vfsp, struct vnode **vnodepp, struct fid *fidp);
+int HgfsMountroot(struct vfs *vfsp, enum whymountroot reason);
+int HgfsVnstate(vfs_t *vfsp, vnode_t *vp, vntrans_t trans);
+#if HGFS_VFS_VERSION == 3
+int HgfsFreevfs(struct vfs *vfsp);
+#else
+void HgfsFreevfs(struct vfs *vfsp);
+#endif
+#endif
+
+
+#if HGFS_VFS_VERSION == 2
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsInit --
+ *
+ *    This is the filesystem initialization routine which is run when the
+ *    filesystem is placed in the VFS switch table.
+ *
+ * Results:
+ *    Returns zero on success.
+ *
+ * Side effects:
+ *    The filesystem type (index number) is set to the provided value.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsInit(struct vfssw *vfsswp,  // IN: VFS Switch table struct
+         int fstype)            // IN: Index into the vfssw table for this filesystem
+{
+   if (!vfsswp) {
+      cmn_err(HGFS_ERROR, "HgfsInit: received NULL input from Kernel.\n");
+      return EINVAL;
+   }
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsInit().\n");
+
+   /*
+    * Hook VFS operations into switch table and save
+    * filesystem type number and pointer to vfsswp.
+    */
+   vfsswp->vsw_vfsops = &HgfsVfsOps;
+   hgfsType = fstype;
+
+   mutex_init(&vfsswp->vsw_lock, NULL, MUTEX_DRIVER, NULL);
+
+   DEBUG(VM_DEBUG_LOAD, "fstype: %d\n", hgfsType);
+   HgfsDebugPrintVfssw("HgfsInit()", vfsswp);
+
+   DEBUG(VM_DEBUG_DONE, "HgfsInit() done.\n");
+
+   return 0;
+}
+
+#else   /* Implies Solaris > 9 */
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsInit --
+ *
+ *    This is the filesystem initialization routine for Solaris 10.  It creates
+ *    an array of fs_operation_def_t for all the vfs operations, then calls
+ *    vfs_setfsops() to assign them to the filesystem properly.
+ *
+ * Results:
+ *    Returns 0 on success and a non-zero error code on error.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsInit(int fstype,    // IN: Filesystem type
+         char *name)    // IN: Name of the filesystem
+{
+   int ret;
+
+   /* Construct the VFS operations array to give to vfs_setfsops() */
+   fs_operation_def_t vfsOpsArr[] = {
+      HGFS_VOP(VFSNAME_MOUNT, vfs_mount, HgfsMount),
+      HGFS_VOP(VFSNAME_UNMOUNT, vfs_unmount, HgfsUnmount),
+      HGFS_VOP(VFSNAME_ROOT, vfs_root, HgfsRoot),
+      HGFS_VOP(VFSNAME_STATVFS, vfs_statvfs, HgfsStatvfs),
+      HGFS_VOP(VFSNAME_VGET, vfs_vget, HgfsVget),
+      HGFS_VOP(VFSNAME_MOUNTROOT, vfs_mountroot, HgfsMountroot),
+      HGFS_VOP(VFSNAME_FREEVFS, vfs_freevfs, HgfsFreevfs),
+      HGFS_VOP(VFSNAME_VNSTATE, vfs_vnstate, HgfsVnstate),
+#if HGFS_VFS_VERSION <= 3
+      HGFS_VOP(VFSNAME_SYNC,  vfs_vnstate, (fs_generic_func_p)HgfsSync),
+      { NULL,               NULL                        }
+#else
+      HGFS_VOP(VFSNAME_SYNC, vfs_sync, HgfsSync),
+      { NULL,               { NULL }},
+#endif
+   };
+
+   if (!name) {
+      cmn_err(HGFS_ERROR, "HgfsInit: received NULL input from Kernel.\n");
+      return EINVAL;
+   }
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsInit: fstype=%d, name=\"%s\"\n", fstype, name);
+
+   /* Set our filesystem type. */
+   hgfsType = fstype;
+
+   /* Assign VFS operations to our filesystem. */
+   ret = vfs_setfsops(hgfsType, vfsOpsArr, NULL);
+   if (ret) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsInit: vfs_setfsops returned %d\n", ret);
+      return ret;
+   }
+
+   DEBUG(VM_DEBUG_DONE, "HgfsInit: done. (fstype=%d)\n", hgfsType);
+
+   return 0;
+}
+
+#endif
+
+
+/*
+ * VFS Entry Points
+ */
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsMount --
+ *
+ *   This function is invoked when mount(2) is called on our filesystem.
+ *   The filesystem is mounted on the supplied vnode.
+ *
+ * Results:
+ *   Returns zero on success and an appropriate error code on error.
+ *
+ * Side effects:
+ *   The filesystem is mounted on top of vnodep.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsMount(struct vfs *vfsp,     // IN: Filesystem to mount
+          struct vnode *vnodep, // IN: Vnode that we are mounting on
+          struct mounta *mntp,  // IN: Arguments to mount(2) from user
+          struct cred *credp)   // IN: Credentials of caller
+{
+   HgfsSuperInfo *sip;
+   HgfsMountData *mountData;
+   int ret;
+   dev_t dev;
+
+   if (!vfsp || !vnodep || !mntp || !credp) {
+      cmn_err(HGFS_ERROR, "HgfsMount: NULL input from Kernel.\n");
+      return EINVAL;
+   }
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsMount().\n");
+
+   //HgfsDebugPrintVfs("HgfsMount", vfsp);
+   //HgfsDebugPrintVnode(VM_DEBUG_STRUCT, "HgfsMount", vnodep);
+   //HgfsDebugPrintMounta("HgfsMount", mntp);
+   //HgfsDebugPrintCred("HgfsMount", credp);
+
+   /*
+    * Initial sanity checks to ensure that:
+    * - device side has allocated our superinfo struct (see HgfsDevAttach())
+    * - the device has been sucecssfully opened
+    * - caller is root
+    * - data provided by caller is the expected size
+    *
+    * Note that this is the one place in the filesystem that we call
+    * ddi_get_soft_state() directly to get the superinfo pointer.  All other
+    * places use the HgfsGetSuperInfo() wrapper which only returns the
+    * superinfo if the filesystem is in fact mounted.
+    */
+   sip = (HgfsSuperInfo *)ddi_get_soft_state(superInfoHead, hgfsInstance);
+   if (!sip) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsMount: superinfo has not been allocated/set\n");
+      return ENXIO;
+   }
+
+   if (!sip->devOpen) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsMount: device has not been opened\n");
+      return ENXIO;
+   }
+
+   if (!HgfsSuser(credp)) {
+      return EPERM;
+   }
+
+   if (mntp->datalen != sizeof *mountData) {
+      return EINVAL;
+   }
+
+   /*
+    * If mount data is in kernel space, just cast pointer; otherwise we need
+    * to safely copy it from user space.
+    */
+   if (mntp->flags & MS_SYSSPACE) {
+      mountData = (HgfsMountData *)mntp->dataptr;
+      DEBUG(VM_DEBUG_LOAD, "HgfsMount(): mount data was in kernel space.\n");
+   } else {
+      mountData = (HgfsMountData *)kmem_zalloc(sizeof *mountData, HGFS_ALLOC_FLAG);
+#     if HGFS_ALLOC_FLAG != KM_SLEEP
+      /* This check is not needed if HGFS_ALLOC_FLAG == KM_SLEEP */
+      if (!mountData) {
+         return ENOMEM;
+      }
+#     endif
+
+      if (ddi_copyin(mntp->dataptr, mountData,
+                     sizeof *mountData, HGFS_COPYIN_FLAGS) == -1) {
+         DEBUG(VM_DEBUG_FAIL, "HgfsMount: couldn't copy in mount data.\n");
+         ret = EFAULT;
+         goto out;
+      }
+   }
+
+   /*
+    * Make sure mount data matches what guestd will send us.
+    */
+   if (mountData->magic != HGFS_MAGIC) {
+        DEBUG(VM_DEBUG_FAIL, "HgfsMount: received invalid magic value: %x\n",
+             mountData->magic);
+        ret = EINVAL;
+        goto out;
+   }
+
+   /*
+    * We need to find a unique device number for this VFS that will be used to
+    * construct the filesystem id.
+    */
+   if ((dev = getudev()) == -1) {
+        DEBUG(VM_DEBUG_FAIL, "HgfsMount(): getudev() failed.\n");
+        ret = ENXIO;
+        goto out;
+   }
+
+   DEBUG(VM_DEBUG_LOAD, "HgfsMount: dev=%lu\n", dev);
+
+   if (vfs_devismounted(dev)) {
+      DEBUG(VM_DEBUG_FAIL,
+            "HgfsMount(): dev is not unique. We should loop on this.\n");
+      ret = ENXIO;
+      goto out;
+   }
+
+   /*
+    * Fill in values of the VFS structure for the kernel.
+    *
+    * There are several important values that must be set.  In particular, we
+    * need to create a chain of pointers so the Kernel can easily move between
+    * the various filesystems mounted on the system.
+    *
+    *  o Each filesystem must set its vfs_vnodecovered to the vnode of the
+    *    directory it is mounted upon.
+    *  o Each directory that is a mount point must set v_vfsmountedhere to
+    *    point to the vfs struct of the filesystem mounted there.
+    *  o The root vnode of each filesystem must have the VROOT flag set in its
+    *    vnode's v_flag so that the Kernel knows to consult the two previously
+    *    mentioned pointers.
+    */
+   vfsp->vfs_vnodecovered = vnodep;
+   vfsp->vfs_flag &= ~VFS_UNMOUNTED;
+   vfsp->vfs_flag |= HGFS_VFS_FLAGS;
+   vfsp->vfs_bsize = HGFS_VFS_BSIZE;
+   vfsp->vfs_fstype = hgfsType;
+   vfsp->vfs_bcount = 0;
+   /* If we had mount options, we'd call vfs_setmntopt with vfsp->vfs_mntopts */
+
+   vfsp->vfs_dev = dev;
+   vfs_make_fsid(&vfsp->vfs_fsid, vfsp->vfs_dev, hgfsType);
+
+   /*
+    * Fill in value(s) of the vnode structure we are mounted on top of.  We
+    * aren't allowed to modify this ourselves in Solaris 10.
+    */
+#  if HGFS_VFS_VERSION == 2
+   vnodep->v_vfsmountedhere = vfsp;
+#  endif
+
+   /* We need to initialize the File hash table before getting our first vnode. */
+   ret = HgfsInitFileHashTable(&sip->fileHashTable);
+   if (ret) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsMount: couldn't initialize hash table.\n");
+      ret = EIO;
+      goto out;
+   }
+
+   /*
+    * Now create the root vnode of the filesystem.
+    *
+    * Note: do not change the name from "/" here without first checking that
+    * HgfsMakeFullName() in vnode.c will still do the right thing.  (See the
+    * comment for the ".." special case.)
+    */
+   ret = HgfsVnodeGet(&sip->rootVnode,                  // vnode to fill in
+                      sip,                              // Superinfo
+                      vfsp,                             // This filesystem
+                      "/",                              // File name
+                      HGFS_FILE_TYPE_DIRECTORY,         // File type
+                      &sip->fileHashTable);             // File hash table
+   if (ret) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsMount: couldn't get root vnode.\n");
+      ret = EIO;
+      goto out;
+   }
+
+   /* We must signify that this is the root of our filesystem. */
+   mutex_enter(&sip->rootVnode->v_lock);
+   sip->rootVnode->v_flag |= VROOT;
+   mutex_exit(&sip->rootVnode->v_lock);
+
+   /*
+    * Fill in value(s) for the HGFS superinfo structure and link it to this
+    * filesystem's VFS structure.
+    */
+   sip->vfsp = vfsp;
+
+   vfsp->vfs_data = (caddr_t)sip;
+
+   /* XXX do this? */
+   VN_HOLD(vnodep);
+
+   ret = 0;     /* Return success */
+
+   DEBUG(VM_DEBUG_DONE, "HgfsMount() done.\n");
+
+out:
+   if (!(mntp->flags & MS_SYSSPACE)) {
+      kmem_free(mountData, sizeof *mountData);
+   }
+   return ret;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsUnmount --
+ *
+ *    This function is invoked when umount(2) is called on our filesystem.
+ *
+ * Results:
+ *    Returns 0 on success and an error code on error.
+ *
+ * Side effects:
+ *    The root vnode will be freed.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsUnmount(struct vfs *vfsp,   // IN: This filesystem
+            int mflag,          // IN: Unmount flags
+            struct cred *credp) // IN: Credentials of caller
+{
+   HgfsSuperInfo *sip;
+
+   if (!vfsp || !credp) {
+      cmn_err(HGFS_ERROR, "HgfsUnmount: NULL input from Kernel.\n");
+      return EINVAL;
+   }
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsUnmount().\n");
+   HgfsDebugPrintVnode(VM_DEBUG_STRUCT, "HgfsUnmount", vfsp->vfs_vnodecovered);
+
+   /*
+    * Initial check to ensure caller is root.
+    */
+   if (!HgfsSuser(credp)) {
+      return EPERM;
+   }
+
+   sip = HgfsGetSuperInfo();
+   if (!sip) {
+      return EINVAL;
+   }
+
+   if (vfsp != sip->vfsp) {
+      DEBUG(VM_DEBUG_ALWAYS, "HgfsUnmount: vfsp != sip->vfsp.\n");
+   }
+
+   /*
+    * Make sure there are no active files (besides the root vnode which we
+    * release at the end of the function).
+    */
+   HgfsDebugPrintFileHashTable(&sip->fileHashTable, VM_DEBUG_STATE);
+   if (!HgfsFileHashTableIsEmpty(sip, &sip->fileHashTable)) {
+      /*
+       * If the force flag was specified, we'll cancel all requests and perform
+       * the unmount.  Otherwise, we'll just return EBUSY.
+       */
+      if (mflag & MS_FORCE) {
+         HgfsCancelAllRequests(sip);
+      } else {
+         DEBUG(VM_DEBUG_FAIL, "HgfsUnmount: there are still active files.\n");
+         return EBUSY;
+      }
+   }
+
+   /* Send an unclean unmount warning to syslog. */
+   if (!sip->devOpen) {
+      cmn_err(HGFS_ERROR, "HgfsUnmount: unclean unmount; device was closed.\n");
+   }
+
+   /*
+    * Set unmounted flag in vfs structure.
+    */
+   vfsp->vfs_flag |= VFS_UNMOUNTED;
+
+   /*
+    * Clean up fields in vnode structure of mount point and release hold on
+    * vnodes for mount.
+    */
+#  if HGFS_VFS_VERSION == 2
+   (vfsp->vfs_vnodecovered)->v_vfsmountedhere = NULL;
+#  endif
+   VN_RELE(vfsp->vfs_vnodecovered);
+   VN_RELE( HGFS_ROOT_VNODE(sip) );
+
+   /*
+    * Signify to the device half that the filesystem has been unmounted.
+    */
+   sip->vfsp = NULL;
+   HGFS_ROOT_VNODE(sip) = NULL;
+
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsRoot --
+ *
+ *    This supplies the root vnode for the filesystem.
+ *
+ * Results:
+ *    Returns zero on success and an error code on error.  On success vnodepp
+ *    is set to the pointer of the root vnode.
+ *
+ * Side effects:
+ *    The root vnode's reference count is incremented by one.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsRoot(struct vfs *vfsp,              // IN: Filesystem to find root vnode of
+         struct vnode **vnodepp)        // OUT: Set to pointer to root vnode of this fs
+{
+   HgfsSuperInfo *sip;
+
+   if (!vfsp || !vnodepp) {
+      cmn_err(HGFS_ERROR, "HgfsRoot: NULL input from Kernel.\n");
+      return EINVAL;
+   }
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsRoot().\n");
+
+   /*
+    * Get the root vnode from the superinfo structure.
+    */
+   sip = HgfsGetSuperInfo();
+   if (!sip) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsRoot() failed to find superinfo.\n");
+      return EIO;
+   }
+
+   if (vfsp != sip->vfsp) {
+      DEBUG(VM_DEBUG_ALWAYS, "HgfsRoot: vfsp != sip->vfsp.\n");
+   }
+
+   VN_HOLD( HGFS_ROOT_VNODE(sip) );
+   *vnodepp = HGFS_ROOT_VNODE(sip);
+
+   DEBUG(VM_DEBUG_LOAD, " rootvnode=%p", HGFS_ROOT_VNODE(sip));
+
+   DEBUG(VM_DEBUG_DONE, "HgfsRoot() done.\n");
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsStatvfs --
+ *
+ *    Provides statistics for the provided filesystem.  The values provided
+ *    by this function are fake.
+ *
+ * Results:
+ *    Returns 0 on success and a non-zero error code on exit.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsStatvfs(struct vfs *vfsp,           // IN: Filesystem to get statistics for
+            struct statvfs64 *stats)    // OUT: Statistics are placed into this struct
+{
+   dev32_t dev32;
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsStatvfs().\n");
+
+   if (!stats) {
+      cmn_err(HGFS_ERROR, "HgfsStatvfs: NULL input from Kernel.\n");
+      return EINVAL;
+   }
+
+   /* Clear stats struct, then fill it in with our values. */
+   memset(stats, 0, sizeof *stats);
+
+   /*
+    * Macros in case we need these elsewhere later.
+    *
+    * These were selected pretty randomly: the numbers should be large enough
+    * so a user can attempt to create any reasonably sized file, but small
+    * enough to be so the Kernel doesn't give callers who are using statvfs32
+    * an EOVERFLOW.
+    */
+   #define HGFS_BLOCKS_TOTAL    0x00ffffff
+   #define HGFS_BLOCKS_FREE     0x00ffefff
+   #define HGFS_BLOCKS_AVAIL    0x00ffef00
+   #define HGFS_FILES_TOTAL     0x00ffffff
+   #define HGFS_FILES_FREE      0x00ffefff
+   #define HGFS_FILES_AVAIL     0x00ffef00
+
+   /* Compress the device number to 32-bits for consistency on 64-bit systems. */
+   cmpldev(&dev32, vfsp->vfs_dev);
+
+   stats->f_bsize   = HGFS_BLOCKSIZE;           /* Preferred fs block size */
+   stats->f_frsize  = HGFS_BLOCKSIZE;           /* Fundamental fs block size */
+   /* Next six are u_longlong_t */
+   stats->f_blocks  = HGFS_BLOCKS_TOTAL;        /* Total blocks on fs */
+   stats->f_bfree   = HGFS_BLOCKS_FREE;         /* Total free blocks */
+   stats->f_bavail  = HGFS_BLOCKS_AVAIL;        /* Total blocks avail to non-root */
+   stats->f_files   = HGFS_FILES_TOTAL;         /* Total files (inodes) */
+   stats->f_ffree   = HGFS_FILES_FREE;          /* Total files free */
+   stats->f_favail  = HGFS_FILES_AVAIL;         /* Total files avail to non-root */
+   stats->f_fsid    = dev32;                    /* Filesystem id */
+   stats->f_flag   &= ST_NOSUID;                /* Flags: we don't support setuid. */
+   stats->f_namemax = MAXNAMELEN;               /* Max filename; use Solaris default. */
+
+   /* Memset above and -1 of array size as n below ensure NUL termination. */
+   strncpy(stats->f_basetype, HGFS_FS_NAME, sizeof stats->f_basetype - 1);
+   strncpy(stats->f_fstr, HGFS_FS_NAME, sizeof stats->f_fstr - 1);
+
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsSync --
+ *
+ *    Flushes the filesystem cache.
+ *
+ * Results:
+ *    Returns zero on success and an error code on failure.  Currently this
+ *    always succeeds.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsSync(struct vfs *vfsp,      // IN: Filesystem to flush
+         short flags,           // XXX: ?
+         struct cred *credp)    // IN: Credentials of caller
+{
+   //DEBUG(VM_DEBUG_ENTRY, "HgfsSync().\n");
+
+   /*
+    * We just return success and hope the host OS calls its filesystem sync
+    * operation periodically as well.
+    */
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsVget --
+ *
+ *    Finds the vnode that matches the unique file identifier.
+ *
+ *    XXX: Come back to this when figure out how/if to store fidp to vnode
+ *    mappings.
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsVget(struct vfs *vfsp,              // IN: Filesystem to operate on
+         struct vnode **vnodepp,        // OUT: Set to pointer of found vnode
+         struct fid *fidp)              // IN: Unique file identifier for vnode
+{
+   DEBUG(VM_DEBUG_NOTSUP, "HgfsVget() NOTSUP.\n");
+
+   return ENOTSUP;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsMountroot --
+ *
+ *    Mounts the file system on the root directory.
+ *
+ *    XXX: Still need to figure out when this is invoked.
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsMountroot(struct vfs *vfsp,         // IN: Filesystem to mount
+              enum whymountroot reason) // IN: Reason why mounting on root
+{
+   DEBUG(VM_DEBUG_NOTSUP, "HgfsMountroot() NOTSUP.\n");
+
+   return ENOTSUP;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsReserved --
+ *
+ *    XXX: Is this a placeholder function in the struct?
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsReserved(struct vfs *vfsp,
+             struct vnode **vnodepp,
+             char *charp)
+{
+   DEBUG(VM_DEBUG_NOTSUP, "HgfsReserved() NOTSUP.\n");
+
+   return ENOTSUP;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsFreevfs --
+ *
+ *    Called when a filesystem is unmounted to free the resources held by the
+ *    filesystem.
+ *
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION > 2
+#if HGFS_VFS_VERSION == 3
+int
+#else
+void
+#endif
+HgfsFreevfs(struct vfs *vfsp)
+{
+   DEBUG(VM_DEBUG_ENTRY, "HgfsFreevfs().\n");
+
+   /*
+    * The only allocation to undo here is call mutex_destroy() on the vsw_lock
+    * for our filesystem's struct vfssw.  Doing this causes a system crash,
+    * from a call to a mutex free function within the Kernel (that is, not from
+    * our code), so we are assured that the Kernel cleans this up for us.
+    *
+    * In Solaris 10 it seemed that we needed to free the vnode and vfs
+    * operations we had made earlier (vn_freevnodeops() and
+    * vfs_freevfsops_by_type()), but this is not so.  Freeing these prevents
+    * 1) multiple mounts without first reloading the module, and 2) unloading
+    * the module from the Kernel.  The combination of these two meant that
+    * the guest would have to be rebooted to remount the filesystem.  Because
+    * of all this, the assumption is made that the Kernel takes care of
+    * removing these structures for us.
+    */
+
+#if HGFS_VFS_VERSION == 3
+   return 0;
+#endif
+}
+#endif
+
+
+#if HGFS_VFS_VERSION > 2
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsVnstate --
+ *
+ *    Performs the necessary operations on the provided vnode given the state
+ *    transfer that has occurred.
+ *
+ *    The possible transfers are VNTRANS_EXISTS, VNTRANS_IDLED,
+ *    VNTRANS_RECLAIMED, and VNTRANS_DESTROYED (see <sys/vfs.h>).
+ *
+ * Results:
+ *    Returns 0 on success and a non-zero error code on error.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsVnstate(vfs_t *vfsp,        // IN: Pointer to our filesystem
+            vnode_t *vp,        // IN: Vnode to change state of
+            vntrans_t trans)    // IN: Type of state transfer
+{
+   DEBUG(VM_DEBUG_NOTSUP, "HgfsVnstate: entry.\n");
+
+   return ENOTSUP;
+}
+#endif
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsSuser --
+ *
+ *    Correctly implements the superuser check depending on the version of
+ *    Solaris.
+ *
+ * Results:
+ *    Returns zero if this user is not superuser, returns non-zero otherwise.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsSuser(struct cred *cr)      // IN: Credentials of the caller
+{
+   ASSERT(cr);
+#if HGFS_VFS_VERSION == 2
+   return suser(cr);
+#else
+   /*
+    * I am assuming the crgetuid() is the effective uid, since the other two
+    * related functions are crgetruid() and crgetsuid().
+    */
+   return (crgetuid(cr) == 0);
+#endif
+}
+
diff --git a/open-vm-tools/modules/solaris/vmhgfs/filesystem.h b/open-vm-tools/modules/solaris/vmhgfs/filesystem.h
new file mode 100644 (file)
index 0000000..704903a
--- /dev/null
@@ -0,0 +1,118 @@
+/*********************************************************
+ * Copyright (C) 2004 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * filesystem.h --
+ *
+ * Includes and definitions for filesystem code.
+ *
+ */
+
+
+
+#ifndef __FILESYSTEM_H_
+#define __FILESYSTEM_H_
+
+
+/*
+ * Solaris includes
+ */
+#include <sys/mntent.h>                /* mount flags */
+#include <sys/mount.h>
+
+/*
+ * Kernel only includes
+ */
+#ifdef _KERNEL
+
+#include <sys/modctl.h>         /* mod_fsops, ... */
+#include <sys/cmn_err.h>        /* cmn_err() */
+#include <sys/ddi.h>            /* cmn_err() */
+#include <sys/sunddi.h>         /* cmn_err() */
+#include <sys/vfs.h>            /* struct vfs, ... */
+#include <sys/vnode.h>          /* struct vnode, ... */
+
+#if SOL11
+#include <sys/vfs_opreg.h>      /* fs_operation_def_t, ... */
+#endif
+
+#endif /* _KERNEL */
+
+#include "hgfsSolaris.h"
+
+/*
+ * Macros
+ */
+#define HGFS_MAGIC           (0xbacbacbc)
+#define HGFS_FSTYPE          HGFS_FS_NAME
+
+/*
+ * Struct passed from user (guestd) to kernel (fs module)
+ */
+typedef struct HgfsMountData {
+   uint32_t magic;
+   uint32_t version;
+   uint32_t fd;
+} HgfsMountData;
+
+
+#ifdef _KERNEL
+/*
+ * Macros
+ */
+#ifdef SOL9
+ #define HGFS_VFS_FLAGS         VFS_NOSUID
+#else
+ #define HGFS_VFS_FLAGS         VFS_NOSETUID
+#endif
+
+#ifdef SOL9
+ #define HGFS_VFS_VERSION       2
+#elif defined(SOL10)
+ #define HGFS_VFS_VERSION       3
+#else
+ #define HGFS_VFS_VERSION       5
+#endif
+
+#define HGFS_VFS_BSIZE          HGFS_PACKET_MAX
+#define HGFS_COPYIN_FLAGS      (0)
+#define HGFS_VFS_TO_SI(vfsp)   ((HgfsSuperInfo *)vfsp->vfs_data)
+
+/* This macro is used for both vnode ops and vfs ops. */
+#if defined(SOL9) || defined(SOL10)
+#define HGFS_VOP(vopName, vopFn, hgfsFn) { vopName, hgfsFn }
+#else
+#define HGFS_VOP(vopName, vopFn, hgfsFn) { vopName, { .vopFn = hgfsFn } }
+#endif
+
+/*
+ * Functions
+ */
+/* To abstract Solaris 9 and 10 differences in suser() calls */
+int HgfsSuser(struct cred *cr);
+
+
+/*
+ * Extern variables
+ */
+#ifdef SOL9
+EXTERN struct vfsops HgfsVfsOps;
+#endif
+
+#endif /* _KERNEL */
+
+
+#endif /* __FILESYSTEM_H_ */
diff --git a/open-vm-tools/modules/solaris/vmhgfs/hgfs.h b/open-vm-tools/modules/solaris/vmhgfs/hgfs.h
new file mode 100644 (file)
index 0000000..0500bbb
--- /dev/null
@@ -0,0 +1,202 @@
+/*********************************************************
+ * Copyright (C) 1998 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+
+
+/*
+ * hgfs.h --
+ *
+ * Header file for public common data types used in the VMware
+ * Host/Guest File System (hgfs).
+ *
+ * This file is included by hgfsProto.h, which defines message formats
+ * used in the hgfs protocol, and by hgfsDev.h, which defines the
+ * interface between the kernel and the hgfs pserver. [bac]
+ */
+
+
+#ifndef _HGFS_H_
+# define _HGFS_H_
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_DISTRIBUTE
+#include "includeCheck.h"
+#include "vm_assert.h"
+
+/*
+ * Maximum number of pages to transfer to/from the HGFS server for V3 protocol
+ * operations that support large requests/replies, e.g. reads and writes.
+ */
+#define HGFS_LARGE_IO_MAX_PAGES  15
+
+/*
+ * Maximum allowed packet size in bytes. All hgfs code should be made
+ * safe with respect to this limit.
+ */
+#define HGFS_PACKET_MAX 6144
+
+/*
+ * The HGFS_LARGE_PACKET_MAX size is used to allow guests to make
+ * read / write requests of sizes larger than HGFS_PACKET_MAX. The larger size
+ * can only be used with server operations that are specified to be large packet
+ * capable in hgfsProto.h.
+ */
+#define HGFS_LARGE_PACKET_MAX ((4096 * HGFS_LARGE_IO_MAX_PAGES) + 2048)
+
+/* Maximum number of bytes to read or write to a hgfs server in a single packet. */
+#define HGFS_IO_MAX 4096
+
+/* Maximum number of bytes to read or write to a V3 server in a single hgfs packet. */
+#define HGFS_LARGE_IO_MAX (HGFS_LARGE_IO_MAX_PAGES * 4096)
+
+/*
+ * Open mode
+ *
+ * These are equivalent to the O_RDONLY, O_WRONLY, O_RDWR open flags
+ * in Unix; they specify which type of access is being requested.  These three
+ * modes are mutually exclusive and one is required; all other flags are
+ * modifiers to the mode and must come afterwards as a bitmask.  Beware that
+ * HGFS_OPEN_MODE_READ_ONLY contains the value 0 so simply masking another
+ * variable with it to detect its presence is not safe.  The _ACCMODES entry in
+ * the enum serves as a bitmask for the others.
+ *
+ * Changing the order of this enum will break stuff.
+ *
+ * This definition is used in some places that don't include
+ * hgfsProto.h, which is why it is here instead of there.
+ */
+typedef enum {
+   HGFS_OPEN_MODE_READ_ONLY,
+   HGFS_OPEN_MODE_WRITE_ONLY,
+   HGFS_OPEN_MODE_READ_WRITE,
+   HGFS_OPEN_MODE_ACCMODES,
+   /* You cannot add anything else here.  Really. */
+} HgfsOpenMode;
+
+/*
+ * Open flags.
+ *
+ * Each should be shifted left by HGFS_OPEN_MODE_READ_WRITE plus whatever flag
+ * number they are, starting with zero.
+ *
+ * The sequential flag indicates that reads and writes on this handle should
+ * not seek on each operation; instead, the system's file pointer will be used
+ * so each operation is performed where the last one finished.  This flag is
+ * necessary when reading from or writing to non-seekable files (such as procfs
+ * nodes on Linux) but can also lead to inconsistent results if a client shares
+ * a handle amongst several of its callers.  This flag should only be used when
+ * the client knows the file is non-seekable and the burden of ensuring file
+ * handles aren't shared falls upon the hgfs client, not the server.
+ */
+#define HGFS_OPEN_SEQUENTIAL    (1 << HGFS_OPEN_MODE_READ_WRITE)
+
+/* Masking helpers. */
+#define HGFS_OPEN_MODE_ACCMODE(mode)    (mode & HGFS_OPEN_MODE_ACCMODES)
+#define HGFS_OPEN_MODE_FLAGS(mode)      (mode & ~HGFS_OPEN_MODE_ACCMODES)
+
+#define HGFS_OPEN_MODE_IS_VALID_MODE(mode)      \
+   (HGFS_OPEN_MODE_ACCMODE(mode) == HGFS_OPEN_MODE_READ_ONLY  ||   \
+    HGFS_OPEN_MODE_ACCMODE(mode) == HGFS_OPEN_MODE_WRITE_ONLY ||   \
+    HGFS_OPEN_MODE_ACCMODE(mode) == HGFS_OPEN_MODE_READ_WRITE)
+
+
+/*
+ * Return status for replies from the server.
+ *
+ * Changing the order of this enum will break the protocol; new status
+ * types should be added at the end.
+ *
+ * This definition is used in some places that don't include
+ * hgfsProto.h, which is why it is here instead of there.
+ *
+ * XXX: So we have a problem here. At some point, HGFS_STATUS_INVALID_NAME was
+ * added to the list of errors. Later, HGFS_STATUS_GENERIC_ERROR was added, but
+ * it was added /before/ HGFS_STATUS_INVALID_NAME. Nobody noticed because the
+ * error codes travelled from hgfsProto.h to hgfs.h in that same change. Worse,
+ * we GA'ed a product (Server 1.0) this way.
+ *
+ * XXX: I've reversed the order because otherwise new HGFS clients working
+ * against WS55-era HGFS servers will think they got HGFS_STATUS_GENERIC_ERROR
+ * when the server sent them HGFS_STATUS_INVALID_NAME. This was a problem
+ * the Linux client converts HGFS_STATUS_GENERIC_ERROR to -EIO, which causes
+ * HgfsLookup to fail unexpectedly (normally HGFS_STATUS_INVALID_NAME is
+ * converted to -ENOENT, an expected result in HgfsLookup).
+ */
+typedef enum {
+   HGFS_STATUS_SUCCESS,
+   HGFS_STATUS_NO_SUCH_FILE_OR_DIR,
+   HGFS_STATUS_INVALID_HANDLE,
+   HGFS_STATUS_OPERATION_NOT_PERMITTED,
+   HGFS_STATUS_FILE_EXISTS,
+   HGFS_STATUS_NOT_DIRECTORY,
+   HGFS_STATUS_DIR_NOT_EMPTY,
+   HGFS_STATUS_PROTOCOL_ERROR,
+   HGFS_STATUS_ACCESS_DENIED,
+   HGFS_STATUS_INVALID_NAME,
+   HGFS_STATUS_GENERIC_ERROR,
+   HGFS_STATUS_SHARING_VIOLATION,
+   HGFS_STATUS_NO_SPACE,
+   HGFS_STATUS_OPERATION_NOT_SUPPORTED,
+   HGFS_STATUS_NAME_TOO_LONG,
+   HGFS_STATUS_INVALID_PARAMETER,
+} HgfsStatus;
+
+/*
+ * HGFS RPC commands
+ *
+ * HGFS servers can run in a variety of places across several different
+ * transport layers. These definitions constitute all known RPC commands.
+ *
+ * For each definition, there is both the server string (the command itself)
+ * as well as a client "prefix", which is the command followed by a space.
+ * This is provided for convenience, since clients will need to copy both
+ * the command and the space into some buffer that is then sent over the
+ * backdoor.
+ *
+ * In Host --> Guest RPC traffic, the host endpoint is TCLO and the guest
+ * endpoint is RpcIn. TCLO is a particularly confusing name choice which dates
+ * back to when the host was to send raw TCL code to the guest (TCL Out ==
+ * TCLO).
+ *
+ * In Guest --> Host RPC traffic, the guest endpoint is RpcOut and the host
+ * endpoint is RPCI.
+ */
+
+/*
+ * When an RPCI listener registers for this command, HGFS requests are expected
+ * to be synchronously sent from the guest and replies are expected to be
+ * synchronously returned.
+ *
+ * When an RpcIn listener registers for this command, requests are expected to
+ * be asynchronously sent from the host and synchronously returned from the
+ * guest.
+ *
+ * In short, an endpoint sending this command is sending a request whose reply
+ * should be returned synchronously.
+ */
+#define HGFS_SYNC_REQREP_CMD "f"
+#define HGFS_SYNC_REQREP_CLIENT_CMD HGFS_SYNC_REQREP_CMD " "
+#define HGFS_SYNC_REQREP_CLIENT_CMD_LEN (sizeof HGFS_SYNC_REQREP_CLIENT_CMD - 1)
+
+/*
+ * This is just for the sake of macro naming. Since we are guaranteed
+ * equal command lengths, defining command length via a generalized macro name
+ * will prevent confusion.
+ */
+#define HGFS_CLIENT_CMD_LEN HGFS_SYNC_REQREP_CLIENT_CMD_LEN
+
+#endif // _HGFS_H_
diff --git a/open-vm-tools/modules/solaris/vmhgfs/hgfsEscape.c b/open-vm-tools/modules/solaris/vmhgfs/hgfsEscape.c
new file mode 100644 (file)
index 0000000..972b58c
--- /dev/null
@@ -0,0 +1,940 @@
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * hgfsEscape.c --
+ *
+ *    Escape and unescape illegal filenames for different platforms.
+ *
+ */
+
+#ifdef __KERNEL__
+#  include "driver-config.h"
+#  include <linux/string.h>
+#elif defined(__FreeBSD__)
+#   if defined(_KERNEL)
+#      include <sys/libkern.h>
+#      define strchr(s,c)       index(s,c)
+#   else
+#      include <string.h>
+#   endif
+#   define memmove(s1,s2,n) bcopy(s2,s1,n) 
+#elif defined(__APPLE__) && defined(KERNEL)
+#  include <string.h>
+#elif !defined(sun)
+#  include <stdlib.h>
+#  include <string.h>
+#else
+#  include <string.h>
+#endif
+
+#include "vmware.h"
+#include "hgfsEscape.h"
+#include "cpName.h"
+
+#ifdef _WIN32
+
+#define UNREFERENCED_PARAMETER(P) (P)
+
+/* These characters are illegal in Windows file names. */
+const char* HGFS_ILLEGAL_CHARS = "/\\*?:\"<>|";
+const char* HGFS_SUBSTITUTE_CHARS = "!@#$^&(){}";
+/* Last character of a file name in Windows can be neither dot nor space. */
+const char* HGFS_ILLEGAL_LAST_CHARS = ". ";
+
+/* http://msdn.microsoft.com/en-us/library/aa365247.aspx */
+char *HgfsReservedNames[] = {"CON", "PRN", "AUX", "NUL"};
+char *HgfsReservedNamesWithNumber[] = {"COM", "LPT"};
+
+#define HGFS_RESERVED_NAME_CHARS_LENGTH 3
+#define HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH (HGFS_RESERVED_NAME_CHARS_LENGTH + 1)
+/* Check for special escaping cases - reserved names and illegal last characters. */
+#define IS_SPECIAL_CASE_ESCAPE(b,o,l) HgfsIsSpecialCaseEscape(b,o,l)
+/* Process Windows reserved names. */
+#define PROCESS_RESERVED_NAME(b,s,p,o,c) \
+if (!HgfsProcessReservedName(b,s,p,o,c)) \
+{ \
+ return FALSE; \
+}
+/* Process Windows reserved names. */
+#define PROCESS_LAST_CHARACTER(b,s,p,c) \
+if (!HgfsProcessLastCharacter(b,s,p,c)) \
+{ \
+ return FALSE; \
+}
+
+#else // _WIN32
+
+#define UNREFERENCED_PARAMETER(P)
+/* There is no special escape sequences on other than Windows platforms. */
+#define IS_SPECIAL_CASE_ESCAPE(b,o,l) FALSE
+/* There is no reserved names on other then Windows platforms. */
+#define PROCESS_RESERVED_NAME(b,s,p,o,c)
+/* There is no special processing for the last character on non-Windows platforms. */
+#define PROCESS_LAST_CHARACTER(b,s,p,c)
+
+#if defined(__APPLE__)
+/* These characters are illegal in MAC OS file names. */
+const char* HGFS_ILLEGAL_CHARS = "/:";
+const char* HGFS_SUBSTITUTE_CHARS = "!&";
+#else   // __APPLE__
+/* These characters are illegal in Linux file names. */
+const char* HGFS_ILLEGAL_CHARS = "/";
+const char* HGFS_SUBSTITUTE_CHARS = "!";
+#endif  // __APPLE__
+
+#endif  // _WIN32
+
+#define HGFS_ESCAPE_CHAR '%'
+#define HGFS_ESCAPE_SUBSTITUE_CHAR ']'
+
+typedef enum {
+   HGFS_ESCAPE_ILLEGAL_CHARACTER,
+   HGFS_ESCAPE_RESERVED_NAME,
+   HGFS_ESCAPE_ILLEGAL_LAST_CHARACTER,
+   HGFS_ESCAPE_ESCAPE_SEQUENCE,
+   HGFS_ESCAPE_COMPLETE
+} HgfsEscapeReason;
+
+
+typedef Bool (*HgfsEnumCallback)(char const *bufIn,
+                                 uint32 offset,
+                                 HgfsEscapeReason reason,
+                                 void* context);
+
+/*
+ * The structure is used by HgfsAddEscapeCharacter to keep context information between
+ * invocations
+ * All offsets defined in this structure are in characters, not bytes
+ */
+typedef  struct {
+   uint32   processedOffset;     // Offset of the first unprocessed input character
+   uint32   outputBufferLength;  // Number of characters in the output buffer
+   uint32   outputOffset;        // Number of characters that are already in the output
+   char    *outputBuffer;        // Pointer to the output buffer
+} HgfsEscapeContext;
+
+static void HgfsEscapeUndoComponent(char *bufIn, uint32 *totalLength);
+static int HgfsEscapeGetComponentSize(char const *bufIn, uint32 sizeIn);
+static int HgfsEscapeDoComponent(char const *bufIn, uint32 sizeIn, uint32 sizeBufOut,
+                                 char *bufOut);
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsAddEscapeCharacter --
+ *
+ *    Callback function that is called by HgfsEnumerate to insert an escape sequence
+ *    into the input name.
+ *
+ * Results:
+ *    TRUE if successful, FALSE if there is an error like the output buffer is
+ *    too small.
+ *
+ * Side effects:
+ *    Updates the output buffer pointer (stored in the context variable).
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsAddEscapeCharacter(char const * bufIn,      // IN: input name
+                       uint32 offset,           // IN: offset that requires escaping
+                       HgfsEscapeReason reason, // IN: reason for esaping
+                       void *context)           // IN/OUT: convertion context
+{
+   HgfsEscapeContext *escapeContext = (HgfsEscapeContext *)context;
+   uint32 charactersToCopy;
+   uint32 outputSpace;
+   char* illegal;
+   Bool result = TRUE;
+
+   ASSERT(offset >= escapeContext->processedOffset); // Scanning forward
+   charactersToCopy = offset - escapeContext->processedOffset;
+
+   if (escapeContext->outputOffset + charactersToCopy >
+       escapeContext->outputBufferLength) {
+      return FALSE;
+   }
+
+   memcpy(escapeContext->outputBuffer + escapeContext->outputOffset,
+          bufIn + escapeContext->processedOffset, charactersToCopy * sizeof *bufIn);
+   escapeContext->outputOffset += charactersToCopy;
+   escapeContext->processedOffset += charactersToCopy;
+
+   outputSpace = escapeContext->outputBufferLength - escapeContext->outputOffset;
+
+   switch(reason) {
+   case HGFS_ESCAPE_ILLEGAL_CHARACTER:
+      if (outputSpace < 2) {
+         return FALSE;
+      }
+      illegal = strchr(HGFS_ILLEGAL_CHARS, bufIn[escapeContext->processedOffset]);
+      escapeContext->processedOffset++;  // Skip illegal input character
+      ASSERT(illegal != NULL);
+      escapeContext->outputBuffer[escapeContext->outputOffset] =
+         HGFS_SUBSTITUTE_CHARS[illegal - HGFS_ILLEGAL_CHARS];
+      escapeContext->outputOffset++;
+      escapeContext->outputBuffer[escapeContext->outputOffset] = HGFS_ESCAPE_CHAR;
+      escapeContext->outputOffset++;
+      break;
+
+   case HGFS_ESCAPE_RESERVED_NAME:
+      if (outputSpace < 1) {
+         return FALSE;
+      }
+      escapeContext->outputBuffer[escapeContext->outputOffset] = HGFS_ESCAPE_CHAR;
+      escapeContext->outputOffset++;
+      break;
+
+   case HGFS_ESCAPE_ILLEGAL_LAST_CHARACTER:
+      if (outputSpace < 1) {
+         return FALSE;
+      }
+      escapeContext->outputBuffer[escapeContext->outputOffset] = HGFS_ESCAPE_CHAR;
+      escapeContext->outputOffset++;
+      break;
+
+   case HGFS_ESCAPE_ESCAPE_SEQUENCE:
+      if (outputSpace < 2) {
+         return FALSE;
+      }
+      escapeContext->processedOffset++; // Skip input esape character
+      escapeContext->outputBuffer[escapeContext->outputOffset] = HGFS_ESCAPE_SUBSTITUE_CHAR;
+      escapeContext->outputOffset++;
+      escapeContext->outputBuffer[escapeContext->outputOffset] = HGFS_ESCAPE_CHAR;
+      escapeContext->outputOffset++;
+      break;
+
+   case HGFS_ESCAPE_COMPLETE:
+      if (outputSpace < 1) {
+         return FALSE;
+      }
+      escapeContext->outputBuffer[escapeContext->outputOffset] = '\0';
+      break;
+
+   default:
+      result = FALSE;
+      ASSERT(FALSE);
+   }
+   return result;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsCountEscapeChars --
+ *
+ *    Callback function that is called by HgfsEnumerate to count additional characters
+ *    that need to be inserted in the input name.
+ *
+ * Results:
+ *    TRUE since it never fails.
+ *
+ * Side effects:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsCountEscapeChars(char const *bufIn,       // IN: input name
+                     uint32 offset,           // IN: offset where escape is needed
+                     HgfsEscapeReason reason, // IN: reason for escaping
+                     void *context)           // IN/OUT: context info
+{
+   UNREFERENCED_PARAMETER(bufIn);
+   UNREFERENCED_PARAMETER(offset);
+   if (reason != HGFS_ESCAPE_COMPLETE) {
+      uint32 *counter = (uint32*)context;
+      (*counter)++;
+   }
+   return TRUE;
+}
+
+
+#ifdef _WIN32
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsLetterToUpper --
+ *
+ *    Converts lowercase English letters to uppercase.
+ *    If the symbol is not a lowercase English letter returns the original character.
+ *
+ * Results:
+ *    Converted character.
+ *
+ * Side effects:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static char
+HgfsLetterToUpper(char letter)
+{
+   if (letter >= 'a' && letter <= 'z') {
+      return letter - ('a' - 'A');
+   }
+   return letter;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsIsEqualPrefix --
+ *
+ *    Verifies if the string prefix is equal to the given prefix.
+ *    It assumes that the prefix includes only uppercase English letters or numbers
+ *    and it does not have any international characters.
+ *    The string must be either NULL terminated or not shorter then the prefix.
+ *
+ * Results:
+ *    TRUE if the uppcased string starts with the given prefix. False otherwise.
+ *
+ * Side effects:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsIsEqualPrefix(char const *prefix,  // IN: prefix to check
+                  char const *string,  // IN: input string
+                  uint32 prefixLength) // IN: length of the prefix in characters
+{
+   int i;
+   for (i = 0; i < prefixLength; i++) {
+      ASSERT(prefix[i] > 0 && (prefix[i] < 'a' || prefix[i] > 'z' ));
+      if (prefix[i] != HgfsLetterToUpper(string[i])) {
+         return FALSE;
+      }
+   }
+   return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsIsReservedPrefix --
+ *
+ *    Verifies if the name's prefix is one of the reserved names.
+ *
+ * Results:
+ *    TRUE if the name's prefix is one of the reserved names.
+ *
+ * Side effects:
+ *    None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsIsReservedPrefix(char const *bufIn)  // IN: input name
+{
+   uint32 i;
+   for (i = 0; i < ARRAYSIZE(HgfsReservedNames); i++) {
+      if (HgfsIsEqualPrefix(HgfsReservedNames[i], bufIn,
+                            HGFS_RESERVED_NAME_CHARS_LENGTH)) {
+         return TRUE;
+      }
+   }
+   return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsIsReservedPrefixWithNumber --
+ *
+ *    Verifies if the name's prefix is one of the reserved names with number:
+ *    COM1-9 or LPT1-9.
+ *
+ * Results:
+ *    TRUE if the name's prefix is one of the reserved names with number.
+ *
+ * Side effects:
+ *    None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsIsReservedPrefixWithNumber(char const *bufIn)   // IN: input name
+{
+   uint32 i;
+   for (i = 0; i < ARRAYSIZE(HgfsReservedNamesWithNumber); i++) {
+      if (HgfsIsEqualPrefix(HgfsReservedNamesWithNumber[i], bufIn,
+                            HGFS_RESERVED_NAME_CHARS_LENGTH) &&
+          bufIn[HGFS_RESERVED_NAME_CHARS_LENGTH] >= '1' &&
+          bufIn[HGFS_RESERVED_NAME_CHARS_LENGTH] <= '9') {
+         return TRUE;
+      }
+   }
+   return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsIsSpecialCaseEscape --
+ *
+ *    Verifies if the escape character is a part of special case escape sequence
+ *    that exists only in Windows - escaped reserved name or escaped illegal last
+ *    character.
+ *
+ * Results:
+ *    TRUE if the name's prefix is one of the reserved names with number.
+ *
+ * Side effects:
+ *    None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsIsSpecialCaseEscape(char const *bufIn,   // IN: input name
+                        uint32 offset,       // IN: offset of the escape character
+                        uint32 length)       // IN: length of the name in characters
+{
+   if (offset + 1 == length &&
+      strchr(HGFS_ILLEGAL_LAST_CHARS, bufIn[offset - 1]) != NULL) {
+      return TRUE;
+   }
+   if (offset == HGFS_RESERVED_NAME_CHARS_LENGTH &&
+      (length == HGFS_RESERVED_NAME_CHARS_LENGTH + 1 || bufIn[offset+1] == '.')) {
+      return HgfsIsReservedPrefix(bufIn);
+   }
+   if (offset == HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH &&
+      (length == HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH + 1 ||
+      bufIn[offset+1] == '.')) {
+      return HgfsIsReservedPrefixWithNumber(bufIn);
+   }
+   return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsProcessReservedName --
+ *
+ *    Verifies if the name is one of reserved Windows file names.
+ *    If it is a reserved name invokes callback that performs required
+ *    processing.
+ *
+ * Results:
+ *    TRUE if no processing is required of if processing succeeded,
+ *    FALSE if processing failed.
+ *
+ * Side effects:
+ *    None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsProcessReservedName(char const *bufIn,              // IN:  Unescaped input buffer
+                        uint32 sizeIn,                  // IN:  Length of the input
+                        HgfsEnumCallback processEscape, // IN:  Callack that is invoked
+                                                        //      if input is reserved name
+                        uint32 *offset,                 // OUT: New offset in the input
+                        void *context)                  // IN/OUT: Context for callback
+{
+   /*  Look reserved names: CON, PRN, AUX, NUL. */
+   if (sizeIn >= HGFS_RESERVED_NAME_CHARS_LENGTH && HgfsIsReservedPrefix(bufIn)) {
+      if (HGFS_RESERVED_NAME_CHARS_LENGTH == sizeIn ||
+         bufIn[HGFS_RESERVED_NAME_CHARS_LENGTH] == '.') {
+         if (!processEscape(bufIn, HGFS_RESERVED_NAME_CHARS_LENGTH,
+                            HGFS_ESCAPE_RESERVED_NAME, context)) {
+            return FALSE;
+         }
+         *offset = HGFS_RESERVED_NAME_CHARS_LENGTH;
+      }
+   }
+
+   /*  Look reserved names with numbers: COM1-9 and LPT1-9. */
+   if (sizeIn >= HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH &&
+       HgfsIsReservedPrefixWithNumber(bufIn)) {
+      if (HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH == sizeIn ||
+         bufIn[HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH] == '.') {
+         if (!processEscape(bufIn, HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH,
+                            HGFS_ESCAPE_RESERVED_NAME, context)) {
+            return FALSE;
+         }
+         *offset = HGFS_RESERVED_NAME_WITH_NUMBER_CHARS_LENGTH;
+      }
+   }
+   return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsProcessLastCharacter --
+ *
+ *    Verifies if the trailing character in the name is a valid last character.
+ *    In Windows it is illegal to have a file name that ends with dot ('.') or
+ *    space (' '). The only exception is "." and ".." directory names.
+ *    If the last character is invalid the function invokes a callback to process it.
+ *
+ * Results:
+ *    TRUE if no processing is required of if processing succeeded,
+ *    FALSE if processing failed.
+ *
+ * Side effects:
+ *    None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsProcessLastCharacter(char const *bufIn,              // IN:  Unescaped input buffer
+                         uint32 sizeIn,                  // IN:  Length of the input
+                         HgfsEnumCallback processEscape, // IN:  Callack that is invoked
+                                                         //      when escaping is needed
+                         void *context)                  // IN/OUT: Callback context
+{
+
+   /* If the filename is '.' or '..' we shouldn't escape it. */
+   if ((sizeIn == 1 && bufIn[0] == '.') ||
+       (sizeIn == 2 && bufIn[0] == '.' && bufIn[1] == '.')) {
+      return TRUE;
+   }
+
+   /* Invoke the callback if the last character is illegal. */
+   if (strchr(HGFS_ILLEGAL_LAST_CHARS, bufIn[sizeIn - 1]) != NULL) {
+      if (!processEscape(bufIn, sizeIn, HGFS_ESCAPE_ILLEGAL_LAST_CHARACTER, context)) {
+         return FALSE;
+      }
+   }
+   return TRUE;
+}
+
+#endif //  WIN32
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsIsEscapeSequence --
+ *
+ *    Verifies if input buffer has an escape sequence at the position
+ *    defined by offset.
+ *
+ * Results:
+ *    TRUE if there is an escape sequence at the position defined by offset.
+ *
+ * Side effects:
+ *    None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsIsEscapeSequence(char const *bufIn,   // IN: input name
+                     uint32 offset,       // IN: offset of the escape character
+                     uint32 length)       // IN: length of the name in characters
+{
+   if (bufIn[offset] == HGFS_ESCAPE_CHAR && offset > 0) {
+      char *substitute;
+      if (bufIn[offset - 1] == HGFS_ESCAPE_SUBSTITUE_CHAR) {
+         return TRUE;
+      }
+      substitute = strchr(HGFS_SUBSTITUTE_CHARS, bufIn[offset - 1]);
+      if (substitute != NULL) {
+         return TRUE;
+      }
+      return IS_SPECIAL_CASE_ESCAPE(bufIn,offset,length);
+   }
+   return FALSE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsEscapeEnumerate --
+ *
+ *    The function scans the input buffer and calls processEscape callback for every
+ *    place in the input buffer which require escaping.
+ *
+ *    Callback does the required processing. There are two different callbacks -
+ *    one counts extra symbols that are needed for escaping and another produces
+ *    escaped output name based on input name.
+ *
+ *    1. The first function calculates number of extra characters. It just increments
+ *    a counter which is passed to it in context variable every time it is called
+ *    for the reason different from "complete processing" assuming that
+ *    exactly one extra  character is required to escape any invalid input.
+ *
+ *    2. The second function produces output name by copying everything from input
+ *    name into the output name up to the place which require escaping and
+ *    then inserts appropriate escape sequence into the output. It keeps track of its
+ *    progress and keeps pointer to the output buffer in the context variable.
+ *    HgfsEscapeEnumerate calls calback function one more time at the end of the
+ *    input buffer to let callback finish processing of the input (for example copy
+ *    the rest of the name after the last escape sequence from input buffer to
+ *    output buffer).
+ *
+ * Results:
+ *    TRUE if the input has been processed successfully by the callback, false otherwise.
+ *
+ * Side effects:
+ *    None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsEscapeEnumerate(char const *bufIn,              // IN:  Buffer with unescaped input
+                    uint32 sizeIn,                  // IN:  Number of input *characters*
+                    HgfsEnumCallback processEscape, // IN: Callack that is invoked every
+                                                    //     time escaping is required
+                    void *context)                  // IN/OUT: Context for processEscape
+{
+   /*  First look for invalid characters in the input name. */
+   uint32 i, offset = 0;
+   if (sizeIn == 0) {
+      return TRUE;
+   }
+
+   ASSERT(processEscape);
+
+   PROCESS_RESERVED_NAME(bufIn, sizeIn, processEscape, &offset, context);
+
+   for (i = offset; i < sizeIn; i++) {
+      if (strchr(HGFS_ILLEGAL_CHARS, bufIn[i]) != NULL) {
+         if (!processEscape(bufIn, i, HGFS_ESCAPE_ILLEGAL_CHARACTER, context)) {
+            return FALSE;
+         }
+      } else if (HgfsIsEscapeSequence(bufIn, i, sizeIn)) {
+         if (!processEscape(bufIn, i, HGFS_ESCAPE_ESCAPE_SEQUENCE, context)) {
+            return FALSE;
+         }
+      }
+   }
+
+   PROCESS_LAST_CHARACTER(bufIn, sizeIn, processEscape, context);
+
+   if (!processEscape(bufIn, sizeIn, HGFS_ESCAPE_COMPLETE, context)) {
+      return FALSE;
+   }
+
+   return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsEscape_Do --
+ *
+ *    Escape any characters that are not legal in a windows filename.
+ *    Escape reserved file names that can't be used in Windows.
+ *    We also of course have to escape the escape character, which is "%",
+ *    when it is part of a character sequence that would require unescaping
+ *
+ *    sizeBufOut must account for the NUL terminator.
+ *
+ * Results:
+ *    On success, the size (excluding the NUL terminator) of the
+ *    escaped, NUL terminated buffer.
+ *    On failure (bufOut not big enough to hold result), negative value.
+ *
+ * Side effects:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+HgfsEscape_Do(char const *bufIn, // IN:  Buffer with unescaped input
+                  uint32 sizeIn,     // IN:  Size of input buffer
+                  uint32 sizeBufOut, // IN:  Size of output buffer
+                  char *bufOut)      // OUT: Buffer for escaped output
+{
+   const char *currentComponent = bufIn;
+   uint32 sizeLeft = sizeBufOut;
+   char *outPointer = bufOut;
+   const char *end = bufIn + sizeIn;
+   const char *next;
+   ASSERT(sizeIn > 0);
+   if (bufIn[sizeIn - 1] == '\0') {
+      /*
+       * In some cases a NUL terminated string is passed to HgfsEscape_Do
+       * so it make sense to support such input even if CPName_GetComponent
+       * does not. Detect this case and make the input compliant with
+       * CPName_GetComponent by removing terminating NUL.
+       */
+      end--;
+      sizeIn--;
+   }
+   /*
+    * Absolute symbolic link name starts with the '\0'. HgfsEscapeDo needs to work
+    * with such names. Leading NULL symbols should be skipped here since
+    * CPName_GetComponent does not support such names.
+    */
+   while (*currentComponent == '\0' && currentComponent - bufIn < sizeIn) {
+      currentComponent++;
+      sizeLeft--;
+      *outPointer++ = '\0';
+   }
+   while (currentComponent - bufIn < sizeIn) {
+      int escapedLength;
+      uint32 componentSize = CPName_GetComponent(currentComponent, end, &next);
+
+      escapedLength = HgfsEscapeDoComponent(currentComponent, componentSize,
+                                            sizeLeft, outPointer);
+      if (escapedLength < 0) {
+         return escapedLength;
+      }
+      currentComponent = next;
+      sizeLeft -= escapedLength + 1;
+      outPointer += escapedLength + 1;
+   }
+   return (int) (outPointer - bufOut) - 1; // Do not count the last NUL terminator
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsEscape_GetSize --
+ *
+ *    Calculates required size in bytes for the buffer that is needed to hold escaped
+ *    cross platform path name. Returns 0 if no escaping is required.
+ *
+ * Results:
+ *    On success, the size (excluding the NUL terminator) of the
+ *    escaped, NUL terminated buffer.
+ *    Returns 0 if the name is a valid Windows file name.
+ *
+ * Side effects:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+HgfsEscape_GetSize(char const *bufIn,    // IN:  Buffer with unescaped input
+                   uint32 sizeIn)        // IN:  Size of the input buffer
+{
+   uint32 result = 0;
+   const char *currentComponent = bufIn;
+   const char *end = bufIn + sizeIn;
+   const char *next;
+
+   if (sizeIn == 0) { // No need toescape empty name.
+      return 0;
+   }
+   if (bufIn[sizeIn - 1] == '\0') {
+      /*
+       * In some cases a NUL terminated string is passed to HgfsEscape_GeSize
+       * so it make sense to support such input even if CPName_GetComponent
+       * does not. Detect this case and make the input compliant with
+       * CPName_GetComponent by removing terminating NUL.
+       */
+      end--;
+      sizeIn--;
+   }
+   /* Skip leading NULs to keep CPName_GetComponent happy. */
+   while (*currentComponent == '\0' && currentComponent - bufIn < sizeIn) {
+      currentComponent++;
+   }
+   while (currentComponent - bufIn < sizeIn) {
+      uint32 componentSize = CPName_GetComponent(currentComponent, end, &next);
+      result += HgfsEscapeGetComponentSize(currentComponent, componentSize);
+      currentComponent = next;
+   }
+   return (result == 0) ? 0 : result + sizeIn;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsEscape_Undo --
+ *
+ *    Unescape a buffer that was escaped using HgfsEscapeBuffer.
+ *
+ *    The unescaping is done in place in the input buffer, and
+ *    can not fail.
+ *
+ * Results:
+ *    The size (excluding the NUL terminator) of the unescaped, NUL
+ *    terminated buffer.
+ *
+ * Side effects:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+HgfsEscape_Undo(char *bufIn,       // IN: Characters to be unescaped
+                uint32 sizeIn)     // IN: Number of characters in bufIn
+{
+   uint32 componentSize = strlen(bufIn) + 1;
+   uint32 unprocessedSize = sizeIn + 1;
+   uint32 result = 0;
+   char *currentComponent = bufIn;
+   while (currentComponent != NULL) {
+      HgfsEscapeUndoComponent(currentComponent, &unprocessedSize);
+      componentSize = strlen(currentComponent) + 1; // Unescaped size
+      result += componentSize;
+      if (unprocessedSize > 1) {
+         currentComponent = currentComponent + componentSize;
+         componentSize = strlen(currentComponent) + 1; // Size of the next component
+      } else {
+         currentComponent = NULL;
+      }
+   }
+   return result - 1;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsEscapeUndoComponent --
+ *
+ *    Unescape a buffer that was escaped using HgfsEscapeBuffer.
+ *
+ *    The unescaping is done in place in the input buffer, and
+ *    can not fail.
+ *
+ * Results:
+ *    None
+ *
+ * Side effects:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HgfsEscapeUndoComponent(char   *bufIn,             // IN: Characters to be unescaped
+                        uint32 *unprocessedLength) // IN: Unprocessed characters
+                                                   //     in the whole name
+{
+   size_t offset;
+   size_t sizeIn = strlen(bufIn);
+   char* curOutBuffer = bufIn;
+   char* escapePointer;
+   ASSERT(bufIn);
+
+   escapePointer = strchr(curOutBuffer, HGFS_ESCAPE_CHAR);
+   while (escapePointer != NULL) {
+      offset = escapePointer - bufIn;
+      if (HgfsIsEscapeSequence(bufIn, offset, sizeIn)) {
+         char* substitute = strchr(HGFS_SUBSTITUTE_CHARS, bufIn[offset - 1]);
+         if (substitute != NULL) {
+            bufIn[offset - 1] = HGFS_ILLEGAL_CHARS[substitute - HGFS_SUBSTITUTE_CHARS];
+         } else if (bufIn[offset - 1] == HGFS_ESCAPE_SUBSTITUE_CHAR) {
+            bufIn[offset - 1] = HGFS_ESCAPE_CHAR;
+         }
+         memmove(escapePointer, escapePointer + 1, (*unprocessedLength) - offset - 1);
+         (*unprocessedLength)--;
+         sizeIn--;
+         if (sizeIn > 0) {
+            escapePointer = strchr(escapePointer, HGFS_ESCAPE_CHAR);
+         } else {
+            escapePointer = NULL;
+         }
+      } else {
+         escapePointer = strchr(escapePointer + 1, HGFS_ESCAPE_CHAR);
+      }
+   }
+   ASSERT((*unprocessedLength) > sizeIn);
+   (*unprocessedLength) -= sizeIn + 1;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsEscapeDoComponent --
+ *
+ *    Escape any characters that are not legal in a windows filename.
+ *    Escape reserved file names that can't be used in Windows.
+ *    We also of course have to escape the escape character, which is "%",
+ *    when it is part of a character sequence that would require unescaping
+ *
+ *    sizeBufOut must account for the NUL terminator.
+ *
+ * Results:
+ *    On success, the size (excluding the NUL terminator) of the
+ *    escaped, NUL terminated buffer.
+ *    On failure (bufOut not big enough to hold result), negative value.
+ *
+ * Side effects:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+HgfsEscapeDoComponent(char const *bufIn, // IN:  Buffer with unescaped input
+                          uint32 sizeIn,     // IN:  Size of input buffer
+                          uint32 sizeBufOut, // IN:  Size of output buffer
+                          char *bufOut)      // OUT: Buffer for escaped output
+{
+   HgfsEscapeContext conversionContext;
+   conversionContext.processedOffset = 0;
+   conversionContext.outputBufferLength = sizeBufOut / sizeof *bufOut;
+   conversionContext.outputOffset = 0;
+   conversionContext.outputBuffer = bufOut;
+
+   if (!HgfsEscapeEnumerate(bufIn, sizeIn, HgfsAddEscapeCharacter, &conversionContext)) {
+      return -1;
+   }
+   return conversionContext.outputOffset * sizeof *bufOut;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsEscapeGetComponentSize --
+ *
+ *    Calculates number of addtitional characters that are needed to escape
+ *    name for one NUL terminated component of the path.
+ *
+ * Results:
+ *    Number of additional escape characters needed to escape the name.
+ *    Returns 0 if no escaping is required.
+ *
+ * Side effects:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+HgfsEscapeGetComponentSize(char const *bufIn, // IN:  Buffer with unescaped input
+                           uint32 sizeIn)     // IN:  Size of the in input buffer
+{
+   int result = 0;
+   HgfsEscapeEnumerate(bufIn, sizeIn, HgfsCountEscapeChars, &result);
+   return result;
+}
diff --git a/open-vm-tools/modules/solaris/vmhgfs/hgfsEscape.h b/open-vm-tools/modules/solaris/vmhgfs/hgfsEscape.h
new file mode 100644 (file)
index 0000000..a57e22a
--- /dev/null
@@ -0,0 +1,38 @@
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * hgfsEscape.h --
+ *
+ *    Escape and unescape filenames that are not legal on a particular
+ *    platform.
+ *
+ */
+
+#ifndef __HGFS_ESCAPE_H__
+#define __HGFS_ESCAPE_H__
+
+int HgfsEscape_GetSize(char const *bufIn, // IN
+                       uint32 sizeIn);    // IN
+int HgfsEscape_Do(char const *bufIn, // IN
+                  uint32 sizeIn,     // IN
+                  uint32 sizeBufOut, // IN
+                  char *bufOut);     // OUT
+
+int HgfsEscape_Undo(char *bufIn,    // IN
+                    uint32 sizeIn); // IN
+
+#endif // __HGFS_ESCAPE_H__
diff --git a/open-vm-tools/modules/solaris/vmhgfs/hgfsProto.h b/open-vm-tools/modules/solaris/vmhgfs/hgfsProto.h
new file mode 100644 (file)
index 0000000..637306a
--- /dev/null
@@ -0,0 +1,1486 @@
+/*********************************************************
+ * Copyright (C) 1998 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+
+/*
+ * hgfsProto.h --
+ *
+ * Header file for data types and message formats used in the
+ * Host/Guest File System (hgfs) protocol.
+ */
+
+
+#ifndef _HGFS_PROTO_H_
+# define _HGFS_PROTO_H_
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_DISTRIBUTE
+#include "includeCheck.h"
+
+#include "vm_basic_types.h"
+#include "hgfs.h"
+
+/*
+ * Handle used by the server to identify files and searches. Used
+ * by the driver to match server replies with pending requests.
+ */
+
+typedef uint32 HgfsHandle;
+#define HGFS_INVALID_HANDLE         ((HgfsHandle)~((HgfsHandle)0))
+
+/*
+ * Opcodes for server operations.
+ *
+ * Changing the ordering of this enum will break the protocol; new ops
+ * should be added at the end (but before HGFS_OP_MAX).
+ */
+
+typedef enum {
+   HGFS_OP_OPEN,               /* Open file */
+   HGFS_OP_READ,               /* Read from file */
+   HGFS_OP_WRITE,              /* Write to file */
+   HGFS_OP_CLOSE,              /* Close file */
+   HGFS_OP_SEARCH_OPEN,        /* Start new search */
+   HGFS_OP_SEARCH_READ,        /* Get next search response */
+   HGFS_OP_SEARCH_CLOSE,       /* End a search */
+   HGFS_OP_GETATTR,            /* Get file attributes */
+   HGFS_OP_SETATTR,            /* Set file attributes */
+   HGFS_OP_CREATE_DIR,         /* Create new directory */
+   HGFS_OP_DELETE_FILE,        /* Delete a file */
+   HGFS_OP_DELETE_DIR,         /* Delete a directory */
+   HGFS_OP_RENAME,             /* Rename a file or directory */
+   HGFS_OP_QUERY_VOLUME_INFO,  /* Query volume information */
+
+   /*
+    * The following operations are only available in version 2 of the hgfs
+    * protocol. The corresponding version 1 opcodes above are deprecated.
+    */
+
+   HGFS_OP_OPEN_V2,            /* Open file */
+   HGFS_OP_GETATTR_V2,         /* Get file attributes */
+   HGFS_OP_SETATTR_V2,         /* Set file attributes */
+   HGFS_OP_SEARCH_READ_V2,     /* Get next search response */
+   HGFS_OP_CREATE_SYMLINK,     /* Create a symlink */
+   HGFS_OP_SERVER_LOCK_CHANGE, /* Change the oplock on a file */
+   HGFS_OP_CREATE_DIR_V2,      /* Create a directory */
+   HGFS_OP_DELETE_FILE_V2,     /* Delete a file */
+   HGFS_OP_DELETE_DIR_V2,      /* Delete a directory */
+   HGFS_OP_RENAME_V2,          /* Rename a file or directory */
+
+   /*
+    * Operations for version 3, deprecating version 2 operations.
+    */
+
+   HGFS_OP_OPEN_V3,               /* Open file */
+   HGFS_OP_READ_V3,               /* Read from file */
+   HGFS_OP_WRITE_V3,              /* Write to file */
+   HGFS_OP_CLOSE_V3,              /* Close file */
+   HGFS_OP_SEARCH_OPEN_V3,        /* Start new search */
+   HGFS_OP_SEARCH_READ_V3,        /* Start new search */
+   HGFS_OP_SEARCH_CLOSE_V3,       /* End a search */
+   HGFS_OP_GETATTR_V3,            /* Get file attributes */
+   HGFS_OP_SETATTR_V3,            /* Set file attributes */
+   HGFS_OP_CREATE_DIR_V3,         /* Create new directory */
+   HGFS_OP_DELETE_FILE_V3,        /* Delete a file */
+   HGFS_OP_DELETE_DIR_V3,         /* Delete a directory */
+   HGFS_OP_RENAME_V3,             /* Rename a file or directory */
+   HGFS_OP_QUERY_VOLUME_INFO_V3,  /* Query volume information */
+   HGFS_OP_CREATE_SYMLINK_V3,     /* Create a symlink */
+   HGFS_OP_SERVER_LOCK_CHANGE_V3, /* Change the oplock on a file */
+
+   HGFS_OP_MAX,                   /* Dummy op, must be last in enum */
+} HgfsOp;
+
+
+/* HGFS protocol versions. */
+#define HGFS_VERSION_OLD           (1 << 0)
+#define HGFS_VERSION_3             (1 << 1)
+
+/* XXX: Needs change when VMCI is supported. */
+#define HGFS_REQ_PAYLOAD_SIZE_V3(hgfsReq) (sizeof *hgfsReq + sizeof(HgfsRequest))
+#define HGFS_REP_PAYLOAD_SIZE_V3(hgfsRep) (sizeof *hgfsRep + sizeof(HgfsReply))
+
+/* XXX: Needs change when VMCI is supported. */
+#define HGFS_REQ_GET_PAYLOAD_V3(hgfsReq) ((char *)(hgfsReq) + sizeof(HgfsRequest))
+#define HGFS_REP_GET_PAYLOAD_V3(hgfsRep) ((char *)(hgfsRep) + sizeof(HgfsReply))
+
+
+/*
+ * File types, used in HgfsAttr. We support regular files,
+ * directories, and symlinks.
+ *
+ * Changing the order of this enum will break the protocol; new types
+ * should be added at the end.
+ */
+
+typedef enum {
+   HGFS_FILE_TYPE_REGULAR,
+   HGFS_FILE_TYPE_DIRECTORY,
+   HGFS_FILE_TYPE_SYMLINK,
+} HgfsFileType;
+
+
+/*
+ * Open flags.
+ *
+ * Changing the order of this enum will break stuff.  Do not add any flags to
+ * this enum: it has been frozen and all new flags should be added to
+ * HgfsOpenMode.  This was done because HgfsOpenMode could still be converted
+ * to a bitmask (so that it's easier to add flags to) whereas this enum was
+ * already too large.
+ */
+
+typedef enum {             //  File doesn't exist   File exists
+   HGFS_OPEN,              //  error
+   HGFS_OPEN_EMPTY,        //  error               size = 0
+   HGFS_OPEN_CREATE,       //  create
+   HGFS_OPEN_CREATE_SAFE,  //  create              error
+   HGFS_OPEN_CREATE_EMPTY, //  create              size = 0
+} HgfsOpenFlags;
+
+
+/*
+ * Write flags.
+ */
+
+typedef uint8 HgfsWriteFlags;
+
+#define HGFS_WRITE_APPEND 1
+
+
+/*
+ * Permissions bits.
+ *
+ * These are intentionally similar to Unix permissions bits, and we
+ * convert to/from Unix permissions using simple shift operations, so
+ * don't change these or you will break things.
+ */
+
+typedef uint8 HgfsPermissions;
+
+#define HGFS_PERM_READ  4
+#define HGFS_PERM_WRITE 2
+#define HGFS_PERM_EXEC  1
+
+
+/*
+ * Server-side locking (oplocks and leases).
+ *
+ * The client can ask the server to acquire opportunistic locking/leasing
+ * from the host FS on its behalf. This is communicated as part of an open request.
+ *
+ * HGFS_LOCK_OPPORTUNISTIC means that the client trusts the server
+ * to decide what kind of locking to request from the host FS.
+ * All other values tell the server explicitly the type of lock to
+ * request.
+ *
+ * The server will attempt to acquire the desired lock and will notify the client
+ * which type of lock was acquired as part of the reply to the open request.
+ * Note that HGFS_LOCK_OPPORTUNISTIC should not be specified as the type of
+ * lock acquired by the server, since HGFS_LOCK_OPPORTUNISTIC is not an
+ * actual lock.
+ */
+
+typedef enum {
+   HGFS_LOCK_NONE,
+   HGFS_LOCK_OPPORTUNISTIC,
+   HGFS_LOCK_EXCLUSIVE,
+   HGFS_LOCK_SHARED,
+} HgfsServerLock;
+
+
+/*
+ * Flags to indicate in a setattr request which fields should be
+ * updated. Deprecated.
+ */
+
+typedef uint8 HgfsAttrChanges;
+
+#define HGFS_ATTR_SIZE                  (1 << 0)
+#define HGFS_ATTR_CREATE_TIME           (1 << 1)
+#define HGFS_ATTR_ACCESS_TIME           (1 << 2)
+#define HGFS_ATTR_WRITE_TIME            (1 << 3)
+#define HGFS_ATTR_CHANGE_TIME           (1 << 4)
+#define HGFS_ATTR_PERMISSIONS           (1 << 5)
+#define HGFS_ATTR_ACCESS_TIME_SET       (1 << 6)
+#define HGFS_ATTR_WRITE_TIME_SET        (1 << 7)
+
+
+/*
+ * Hints to indicate in a getattr or setattr which attributes
+ * are valid for the request.
+ * For setattr only, attributes should be set by host even if
+ * no valid values are specified by the guest.
+ */
+
+typedef uint64 HgfsAttrHint;
+
+#define HGFS_ATTR_HINT_SET_ACCESS_TIME   (1 << 0)
+#define HGFS_ATTR_HINT_SET_WRITE_TIME    (1 << 1)
+#define HGFS_ATTR_HINT_USE_FILE_DESC     (1 << 2)
+
+/*
+ * Hint to determine using a name or a handle to determine
+ * what to delete.
+ */
+
+typedef uint64 HgfsDeleteHint;
+
+#define HGFS_DELETE_HINT_USE_FILE_DESC   (1 << 0)
+
+/*
+ * Hint to determine using a name or a handle to determine
+ * what to renames.
+ */
+
+typedef uint64 HgfsRenameHint;
+
+#define HGFS_RENAME_HINT_USE_SRCFILE_DESC       (1 << 0)
+#define HGFS_RENAME_HINT_USE_TARGETFILE_DESC    (1 << 1)
+#define HGFS_RENAME_HINT_NO_REPLACE_EXISTING    (1 << 2)
+#define HGFS_RENAME_HINT_NO_COPY_ALLOWED        (1 << 3)
+
+/*
+ * File attributes.
+ *
+ * The four time fields below are in Windows NT format, which is in
+ * units of 100ns since Jan 1, 1601, UTC.
+ */
+
+/*
+ * Version 1 attributes. Deprecated.
+ * Version 2 should be using HgfsAttrV2.
+ */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsAttr {
+   HgfsFileType type;            /* File type */
+   uint64 size;                  /* File size (in bytes) */
+   uint64 creationTime;          /* Creation time. Ignored by POSIX */
+   uint64 accessTime;            /* Time of last access */
+   uint64 writeTime;             /* Time of last write */
+   uint64 attrChangeTime;        /* Time file attributess were last
+                                  * changed. Ignored by Windows */
+   HgfsPermissions permissions;  /* Permissions bits */
+}
+#include "vmware_pack_end.h"
+HgfsAttr;
+
+
+/* Various flags and Windows attributes. */
+
+typedef uint64 HgfsAttrFlags;
+
+#define HGFS_ATTR_HIDDEN      (1 << 0)
+#define HGFS_ATTR_SYSTEM      (1 << 1)
+#define HGFS_ATTR_ARCHIVE     (1 << 2)
+#define HGFS_ATTR_HIDDEN_FORCED (1 << 3)
+
+
+/*
+ * Specifies which open request fields contain
+ * valid values.
+ */
+
+typedef uint64 HgfsOpenValid;
+
+#define HGFS_OPEN_VALID_NONE              0
+#define HGFS_OPEN_VALID_MODE              (1 << 0)
+#define HGFS_OPEN_VALID_FLAGS             (1 << 1)
+#define HGFS_OPEN_VALID_SPECIAL_PERMS     (1 << 2)
+#define HGFS_OPEN_VALID_OWNER_PERMS       (1 << 3)
+#define HGFS_OPEN_VALID_GROUP_PERMS       (1 << 4)
+#define HGFS_OPEN_VALID_OTHER_PERMS       (1 << 5)
+#define HGFS_OPEN_VALID_FILE_ATTR         (1 << 6)
+#define HGFS_OPEN_VALID_ALLOCATION_SIZE   (1 << 7)
+#define HGFS_OPEN_VALID_DESIRED_ACCESS    (1 << 8)
+#define HGFS_OPEN_VALID_SHARE_ACCESS      (1 << 9)
+#define HGFS_OPEN_VALID_SERVER_LOCK       (1 << 10)
+#define HGFS_OPEN_VALID_FILE_NAME         (1 << 11)
+
+
+/*
+ * Specifies which attribute fields contain
+ * valid values.
+ */
+
+typedef uint64 HgfsAttrValid;
+
+#define HGFS_ATTR_VALID_NONE              0
+#define HGFS_ATTR_VALID_TYPE              (1 << 0)
+#define HGFS_ATTR_VALID_SIZE              (1 << 1)
+#define HGFS_ATTR_VALID_CREATE_TIME       (1 << 2)
+#define HGFS_ATTR_VALID_ACCESS_TIME       (1 << 3)
+#define HGFS_ATTR_VALID_WRITE_TIME        (1 << 4)
+#define HGFS_ATTR_VALID_CHANGE_TIME       (1 << 5)
+#define HGFS_ATTR_VALID_SPECIAL_PERMS     (1 << 6)
+#define HGFS_ATTR_VALID_OWNER_PERMS       (1 << 7)
+#define HGFS_ATTR_VALID_GROUP_PERMS       (1 << 8)
+#define HGFS_ATTR_VALID_OTHER_PERMS       (1 << 9)
+#define HGFS_ATTR_VALID_FLAGS             (1 << 10)
+#define HGFS_ATTR_VALID_ALLOCATION_SIZE   (1 << 11)
+#define HGFS_ATTR_VALID_USERID            (1 << 12)
+#define HGFS_ATTR_VALID_GROUPID           (1 << 13)
+#define HGFS_ATTR_VALID_FILEID            (1 << 14)
+#define HGFS_ATTR_VALID_VOLID             (1 << 15)
+/* 
+ * Add our file and volume identifiers.
+ * NOTE: On Windows hosts, the file identifier is not guaranteed to be valid
+ *       particularly with FAT. A defrag operation could cause it to change.
+ *       Therefore, to not confuse older clients, and non-Windows
+ *       clients we have added a separate flag.
+ *       The Windows client will check for both flags for the
+ *       file ID, and return the information to the guest application.
+ *       However, it will use the ID internally, when it has an open
+ *       handle on the server.
+ *       Non-Windows clients need the file ID to be always guaranteed,
+ *       which is to say, that the ID remains constant over the course of the
+ *       file's lifetime, and will use the HGFS_ATTR_VALID_FILEID flag
+ *       only to determine if the ID is valid.
+ */
+#define HGFS_ATTR_VALID_NON_STATIC_FILEID (1 << 16)
+
+
+/*
+ * Specifies which create dir request fields contain
+ * valid values.
+ */
+
+typedef uint64 HgfsCreateDirValid;
+
+#define HGFS_CREATE_DIR_VALID_NONE              0
+#define HGFS_CREATE_DIR_VALID_SPECIAL_PERMS     (1 << 0)
+#define HGFS_CREATE_DIR_VALID_OWNER_PERMS       (1 << 1)
+#define HGFS_CREATE_DIR_VALID_GROUP_PERMS       (1 << 2)
+#define HGFS_CREATE_DIR_VALID_OTHER_PERMS       (1 << 3)
+#define HGFS_CREATE_DIR_VALID_FILE_NAME         (1 << 4)
+
+/*
+ *  Version 2 of HgfsAttr
+ */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsAttrV2 {
+   HgfsAttrValid mask;           /* A bit mask to determine valid attribute fields */
+   HgfsFileType type;            /* File type */
+   uint64 size;                  /* File size (in bytes) */
+   uint64 creationTime;          /* Creation time. Ignored by POSIX */
+   uint64 accessTime;            /* Time of last access */
+   uint64 writeTime;             /* Time of last write */
+   uint64 attrChangeTime;        /* Time file attributes were last
+                                  * changed. Ignored by Windows */
+   HgfsPermissions specialPerms; /* Special permissions bits (suid, etc.).
+                                  * Ignored by Windows */
+   HgfsPermissions ownerPerms;   /* Owner permissions bits */
+   HgfsPermissions groupPerms;   /* Group permissions bits. Ignored by
+                                  * Windows */
+   HgfsPermissions otherPerms;   /* Other permissions bits. Ignored by
+                                  * Windows */
+   HgfsAttrFlags flags;          /* Various flags and Windows 'attributes' */
+   uint64 allocationSize;        /* Actual size of file on disk */
+   uint32 userId;                /* User identifier, ignored by Windows */
+   uint32 groupId;               /* group identifier, ignored by Windows */
+   uint64 hostFileId;            /* File Id of the file on host: inode_t on Linux */
+   uint32 volumeId;              /* volume identifier, non-zero is valid. */
+   uint32 reserved1;             /* Reserved for future use */
+   uint64 reserved2;             /* Reserved for future use */
+}
+#include "vmware_pack_end.h"
+HgfsAttrV2;
+
+
+/*
+ * Cross-platform filename representation
+ *
+ * Cross-platform (CP) names are represented by a string with each
+ * path component separated by NULs, and terminated with a final NUL,
+ * but with no leading path separator.
+ *
+ * For example, the representations of a POSIX and Windows name
+ * are as follows, with "0" meaning NUL.
+ *
+ * Original name             Cross-platform name
+ * -----------------------------------------------------
+ * "/home/bac/temp"    ->    "home0bac0temp0"
+ * "C:\temp\file.txt"  ->    "C0temp0file.txt0"
+ *
+ * Note that as in the example above, Windows should strip the colon
+ * off of drive letters as part of the conversion. Aside from that,
+ * all characters in each path component should be left unescaped and
+ * unmodified. Each OS is responsible for escaping any characters that
+ * are not legal in its filenames when converting FROM the CP name
+ * format, and unescaping them when converting TO the CP name format.
+ *
+ * In some requests (OPEN, GETATTR, SETATTR, DELETE, CREATE_DIR) the
+ * CP name is used to represent a particular file, but it is also used
+ * to represent a search pattern for looking up files using
+ * SEARCH_OPEN.
+ *
+ * In the current HGFS server implementation, each request has a minimum packet
+ * size that must be met for it to be considered valid. This minimum is simply
+ * the sizeof the particular request, which includes the solitary byte from the
+ * HgfsFileName struct. For these particular requests, clients add an extra
+ * byte to their payload size, without that byte being present anywhere.
+ *
+ * It isn't clear that this behavior is correct, but the end result is that
+ * neither end malfunctions, as an extra byte gets sent by the client and is
+ * ignored by the server. Unfortunately, it cannot be easily fixed. The
+ * server's minimum packet size can be changed, but the client should continue
+ * to send an extra byte, otherwise older servers with a slightly longer
+ * minimum packet size may consider the new client's packets to be too short.
+ *
+ * UTF-8 representation
+ * --------------------
+ * XXX: It is expected that file names in the HGFS protocol will be a valid UTF-8
+ * encoding.
+ * See RFC 3629 (http://tools.ietf.org/html/rfc3629)
+ *
+ * Unicode Format
+ * --------------
+ * HGFS protocol requests that contain file names as in the structure below,
+ * should contain unicode normal form C (precomposed see explanation below)
+ * characters therefore hosts such as Mac OS X which
+ * use HFS+ and unicode form D should convert names before
+ * processing or sending HGFS requests.
+ *
+ * Precomposed (normal form C) versus Decomposed (normal form D)
+ * -------------------------------------------------------------
+ * Certain Unicode characters can be encoded in more than one way.
+ * For example, an (A acute) can be encoded either precomposed,
+ * as U+00C1 (LATIN CAPITAL LETTER A WITH ACUTE), or decomposed,
+ * as U+0041 U+0301 (LATIN CAPITAL LETTER A followed by a COMBINING ACUTE ACCENT).
+ * Precomposed characters are more common in the Windows world,
+ * whereas decomposed characters are more common on the Mac.
+ *
+ * See UAX 15 (http://unicode.org/reports/tr15/)
+ */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsFileName {
+   uint32 length; /* Does NOT include terminating NUL */
+   char name[1];
+}
+#include "vmware_pack_end.h"
+HgfsFileName;
+
+
+/*
+ * Case-sensitiviy flags are only used when any lookup is
+ * involved on the server side.
+ */
+
+typedef enum {
+   HGFS_FILE_NAME_DEFAULT_CASE,
+   HGFS_FILE_NAME_CASE_SENSITIVE,
+   HGFS_FILE_NAME_CASE_INSENSITIVE,
+} HgfsCaseType;
+
+
+/*
+ * HgfsFileNameV3 - new header to incorporate case-sensitivity flags along with
+ * Hgfs file handle.
+ */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsFileNameV3 {
+   uint32 length;           /* Does NOT include terminating NUL */
+   uint32 flags;            /* Flags described below. */
+   HgfsCaseType caseType;   /* Case-sensitivity type. */
+   HgfsHandle fid;
+   char name[1];
+}
+#include "vmware_pack_end.h"
+HgfsFileNameV3;
+
+
+/*
+ * HgfsFileNameV3 flags. Case-sensitiviy flags are only used when any lookup is
+ * involved on the server side.
+ */
+#define HGFS_FILE_NAME_USE_FILE_DESC     (1 << 0)  /* Case type ignored if set. */
+
+
+/*
+ * Request/reply structs. These are the first members of all
+ * operation request and reply messages, respectively.
+ */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequest {
+   HgfsHandle id;        /* Opaque request ID used by the requestor */
+   HgfsOp op;
+}
+#include "vmware_pack_end.h"
+HgfsRequest;
+
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReply {
+   HgfsHandle id;        /* Opaque request ID used by the requestor */
+   HgfsStatus status;
+}
+#include "vmware_pack_end.h"
+HgfsReply;
+
+
+/*
+ * Messages for our file operations.
+ */
+
+/* Deprecated */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestOpen {
+   HgfsRequest header;
+   HgfsOpenMode mode;            /* Which type of access is requested */
+   HgfsOpenFlags flags;          /* Which flags to open the file with */
+   HgfsPermissions permissions;  /* Which permissions to *create* a new file with */
+   HgfsFileName fileName;
+}
+#include "vmware_pack_end.h"
+HgfsRequestOpen;
+
+
+/* Version 2 of HgfsRequestOpen */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestOpenV2 {
+   HgfsRequest header;
+   HgfsOpenValid mask;           /* Bitmask that specified which fields are valid. */
+   HgfsOpenMode mode;            /* Which type of access requested. See desiredAccess */
+   HgfsOpenFlags flags;          /* Which flags to open the file with */
+   HgfsPermissions specialPerms; /* Desired 'special' permissions for file creation */
+   HgfsPermissions ownerPerms;   /* Desired 'owner' permissions for file creation */
+   HgfsPermissions groupPerms;   /* Desired 'group' permissions for file creation */
+   HgfsPermissions otherPerms;   /* Desired 'other' permissions for file creation */
+   HgfsAttrFlags attr;           /* Attributes, if any, for file creation */
+   uint64 allocationSize;        /* How much space to pre-allocate during creation */
+   uint32 desiredAccess;         /* Extended support for windows access modes */
+   uint32 shareAccess;           /* Windows only, share access modes */
+   HgfsServerLock desiredLock;   /* The type of lock desired by the client */
+   uint64 reserved1;             /* Reserved for future use */
+   uint64 reserved2;             /* Reserved for future use */
+   HgfsFileName fileName;
+}
+#include "vmware_pack_end.h"
+HgfsRequestOpenV2;
+
+
+/* Version 3 of HgfsRequestOpen */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestOpenV3 {
+   HgfsOpenValid mask;           /* Bitmask that specified which fields are valid. */
+   HgfsOpenMode mode;            /* Which type of access requested. See desiredAccess */
+   HgfsOpenFlags flags;          /* Which flags to open the file with */
+   HgfsPermissions specialPerms; /* Desired 'special' permissions for file creation */
+   HgfsPermissions ownerPerms;   /* Desired 'owner' permissions for file creation */
+   HgfsPermissions groupPerms;   /* Desired 'group' permissions for file creation */
+   HgfsPermissions otherPerms;   /* Desired 'other' permissions for file creation */
+   HgfsAttrFlags attr;           /* Attributes, if any, for file creation */
+   uint64 allocationSize;        /* How much space to pre-allocate during creation */
+   uint32 desiredAccess;         /* Extended support for windows access modes */
+   uint32 shareAccess;           /* Windows only, share access modes */
+   HgfsServerLock desiredLock;   /* The type of lock desired by the client */
+   uint64 reserved1;             /* Reserved for future use */
+   uint64 reserved2;             /* Reserved for future use */
+   HgfsFileNameV3 fileName;
+}
+#include "vmware_pack_end.h"
+HgfsRequestOpenV3;
+
+
+/* Deprecated */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyOpen {
+   HgfsReply header;
+   HgfsHandle file;      /* Opaque file ID used by the server */
+}
+#include "vmware_pack_end.h"
+HgfsReplyOpen;
+
+
+/* Version 2 of HgfsReplyOpen */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyOpenV2 {
+   HgfsReply header;
+   HgfsHandle file;                  /* Opaque file ID used by the server */
+   HgfsServerLock acquiredLock;      /* The type of lock acquired by the server */
+}
+#include "vmware_pack_end.h"
+HgfsReplyOpenV2;
+
+
+/* Version 3 of HgfsReplyOpen */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyOpenV3 {
+   HgfsHandle file;                  /* Opaque file ID used by the server */
+   HgfsServerLock acquiredLock;      /* The type of lock acquired by the server */
+   uint64 reserved;                  /* Reserved for future use */
+}
+#include "vmware_pack_end.h"
+HgfsReplyOpenV3;
+
+
+/* Deprecated */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestRead {
+   HgfsRequest header;
+   HgfsHandle file;      /* Opaque file ID used by the server */
+   uint64 offset;
+   uint32 requiredSize;
+}
+#include "vmware_pack_end.h"
+HgfsRequestRead;
+
+/* Deprecated */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyRead {
+   HgfsReply header;
+   uint32 actualSize;
+   char payload[1];
+}
+#include "vmware_pack_end.h"
+HgfsReplyRead;
+
+
+/*
+ * Version 3 of HgfsRequestRead.
+ * Server must support HGFS_LARGE_PACKET_MAX to implement this op.
+ */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestReadV3 {
+   HgfsHandle file;      /* Opaque file ID used by the server */
+   uint64 offset;
+   uint32 requiredSize;
+   uint64 reserved;      /* Reserved for future use */
+}
+#include "vmware_pack_end.h"
+HgfsRequestReadV3;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyReadV3 {
+   uint32 actualSize;
+   uint64 reserved;      /* Reserved for future use */
+   char payload[1];
+}
+#include "vmware_pack_end.h"
+HgfsReplyReadV3;
+
+
+/* Deprecated */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestWrite {
+   HgfsRequest header;
+   HgfsHandle file;      /* Opaque file ID used by the server */
+   HgfsWriteFlags flags;
+   uint64 offset;
+   uint32 requiredSize;
+   char payload[1];
+}
+#include "vmware_pack_end.h"
+HgfsRequestWrite;
+
+
+/* Deprecated */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyWrite {
+   HgfsReply header;
+   uint32 actualSize;
+}
+#include "vmware_pack_end.h"
+HgfsReplyWrite;
+
+/*
+ * Version 3 of HgfsRequestWrite.
+ * Server must support HGFS_LARGE_PACKET_MAX to implement this op.
+ */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestWriteV3 {
+   HgfsHandle file;      /* Opaque file ID used by the server */
+   HgfsWriteFlags flags;
+   uint64 offset;
+   uint32 requiredSize;
+   uint64 reserved;      /* Reserved for future use */
+   char payload[1];
+}
+#include "vmware_pack_end.h"
+HgfsRequestWriteV3;
+
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyWriteV3 {
+   uint32 actualSize;
+   uint64 reserved;      /* Reserved for future use */
+}
+#include "vmware_pack_end.h"
+HgfsReplyWriteV3;
+
+
+/* Deprecated */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestClose {
+   HgfsRequest header;
+   HgfsHandle file;      /* Opaque file ID used by the server */
+}
+#include "vmware_pack_end.h"
+HgfsRequestClose;
+
+
+/* Deprecated */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyClose {
+   HgfsReply header;
+}
+#include "vmware_pack_end.h"
+HgfsReplyClose;
+
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestCloseV3 {
+   HgfsHandle file;      /* Opaque file ID used by the server */
+   uint64 reserved;      /* Reserved for future use */
+}
+#include "vmware_pack_end.h"
+HgfsRequestCloseV3;
+
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyCloseV3 {
+   uint64 reserved;
+}
+#include "vmware_pack_end.h"
+HgfsReplyCloseV3;
+
+
+/* Deprecated */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestSearchOpen {
+   HgfsRequest header;
+   HgfsFileName dirName;
+}
+#include "vmware_pack_end.h"
+HgfsRequestSearchOpen;
+
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestSearchOpenV3 {
+   uint64 reserved;      /* Reserved for future use */
+   HgfsFileNameV3 dirName;
+}
+#include "vmware_pack_end.h"
+HgfsRequestSearchOpenV3;
+
+
+/* Deprecated */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplySearchOpen {
+   HgfsReply header;
+   HgfsHandle search;    /* Opaque search ID used by the server */
+}
+#include "vmware_pack_end.h"
+HgfsReplySearchOpen;
+
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplySearchOpenV3 {
+   HgfsHandle search;    /* Opaque search ID used by the server */
+   uint64 reserved;      /* Reserved for future use */
+}
+#include "vmware_pack_end.h"
+HgfsReplySearchOpenV3;
+
+
+/* Deprecated */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestSearchRead {
+   HgfsRequest header;
+   HgfsHandle search;    /* Opaque search ID used by the server */
+   uint32 offset;        /* The first result is offset 0 */
+}
+#include "vmware_pack_end.h"
+HgfsRequestSearchRead;
+
+
+/* Version 2 of HgfsRequestSearchRead */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestSearchReadV2 {
+   HgfsRequest header;
+   HgfsHandle search;    /* Opaque search ID used by the server */
+   uint32 offset;        /* The first result is offset 0 */
+}
+#include "vmware_pack_end.h"
+HgfsRequestSearchReadV2;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestSearchReadV3 {
+   HgfsHandle search;    /* Opaque search ID used by the server */
+   uint32 offset;        /* The first result is offset 0 */
+   uint32 flags;         /* Reserved for reading multiple directory entries. */
+   uint64 reserved;      /* Reserved for future use */
+}
+#include "vmware_pack_end.h"
+HgfsRequestSearchReadV3;
+
+
+/* Deprecated */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplySearchRead {
+   HgfsReply header;
+   HgfsAttr attr;
+   HgfsFileName fileName;
+   /* fileName.length = 0 means "no entry at this offset" */
+}
+#include "vmware_pack_end.h"
+HgfsReplySearchRead;
+
+
+/* Version 2 of HgfsReplySearchRead */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplySearchReadV2 {
+   HgfsReply header;
+   HgfsAttrV2 attr;
+
+   /*
+    * fileName.length = 0 means "no entry at this offset"
+    * If the file is a symlink (as specified in attr)
+    * this name is the name of the symlink, not the target.
+    */
+   HgfsFileName fileName;
+}
+#include "vmware_pack_end.h"
+HgfsReplySearchReadV2;
+
+
+/* Directory entry structure. */
+
+typedef struct HgfsDirEntry {
+   uint32 nextEntry;
+   HgfsAttrV2 attr;
+
+   /*
+    * fileName.length = 0 means "no entry at this offset"
+    * If the file is a symlink (as specified in attr)
+    * this name is the name of the symlink, not the target.
+    */
+   HgfsFileNameV3 fileName;
+} HgfsDirEntry;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplySearchReadV3 {
+   uint64 count;         /* Number of directory entries. */
+   uint64 reserved;      /* Reserved for future use. */
+   char payload[1];      /* Directory entries. */
+}
+#include "vmware_pack_end.h"
+HgfsReplySearchReadV3;
+
+
+/* Deprecated */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestSearchClose {
+   HgfsRequest header;
+   HgfsHandle search;    /* Opaque search ID used by the server */
+}
+#include "vmware_pack_end.h"
+HgfsRequestSearchClose;
+
+
+/* Deprecated */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplySearchClose {
+   HgfsReply header;
+}
+#include "vmware_pack_end.h"
+HgfsReplySearchClose;
+
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestSearchCloseV3 {
+   HgfsHandle search;    /* Opaque search ID used by the server */
+   uint64 reserved;      /* Reserved for future use */
+}
+#include "vmware_pack_end.h"
+HgfsRequestSearchCloseV3;
+
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplySearchCloseV3 {
+   uint64 reserved;      /* Reserved for future use */
+}
+#include "vmware_pack_end.h"
+HgfsReplySearchCloseV3;
+
+
+/* Deprecated */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestGetattr {
+   HgfsRequest header;
+   HgfsFileName fileName;
+}
+#include "vmware_pack_end.h"
+HgfsRequestGetattr;
+
+
+/* Version 2 of HgfsRequestGetattr */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestGetattrV2 {
+   HgfsRequest header;
+   HgfsAttrHint hints;     /* Flags for file handle valid. */
+   HgfsHandle file;        /* Opaque file ID used by the server. */
+   HgfsFileName fileName;  /* Filename used when file handle invalid. */
+}
+#include "vmware_pack_end.h"
+HgfsRequestGetattrV2;
+
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestGetattrV3 {
+   HgfsAttrHint hints;       /* Flags for file handle valid. */
+   uint64 reserved;          /* Reserved for future use */
+   HgfsFileNameV3 fileName;  /* Filename used when file handle invalid. */
+}
+#include "vmware_pack_end.h"
+HgfsRequestGetattrV3;
+
+
+/* Deprecated */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyGetattr {
+   HgfsReply header;
+   HgfsAttr attr;
+}
+#include "vmware_pack_end.h"
+HgfsReplyGetattr;
+
+
+/* Version 2 of HgfsReplyGetattr */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyGetattrV2 {
+   HgfsReply header;
+   HgfsAttrV2 attr;
+
+   /*
+    * If the file is a symlink, as specified in attr.type, then this is
+    * the target for the symlink. If the file is not a symlink, this should
+    * be ignored.
+    *
+    * This filename is in "CPNameLite" format. See CPNameLite.c for details.
+    */
+   HgfsFileName symlinkTarget;
+}
+#include "vmware_pack_end.h"
+HgfsReplyGetattrV2;
+
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyGetattrV3 {
+   HgfsAttrV2 attr;
+
+   /*
+    * If the file is a symlink, as specified in attr.type, then this is
+    * the target for the symlink. If the file is not a symlink, this should
+    * be ignored.
+    *
+    * This filename is in "CPNameLite" format. See CPNameLite.c for details.
+    */
+   uint64 reserved;          /* Reserved for future use */
+   HgfsFileNameV3 symlinkTarget;
+}
+#include "vmware_pack_end.h"
+HgfsReplyGetattrV3;
+
+
+/* Deprecated */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestSetattr {
+   HgfsRequest header;
+   HgfsAttrChanges update;  /* Which fields need to be updated */
+   HgfsAttr attr;
+   HgfsFileName fileName;
+}
+#include "vmware_pack_end.h"
+HgfsRequestSetattr;
+
+
+/* Version 2 of HgfsRequestSetattr */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestSetattrV2 {
+   HgfsRequest header;
+   HgfsAttrHint hints;
+   HgfsAttrV2 attr;
+   HgfsHandle file;        /* Opaque file ID used by the server. */
+   HgfsFileName fileName;  /* Filename used when file handle invalid. */
+}
+#include "vmware_pack_end.h"
+HgfsRequestSetattrV2;
+
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestSetattrV3 {
+   HgfsAttrHint hints;
+   HgfsAttrV2 attr;
+   uint64 reserved;          /* Reserved for future use */
+   HgfsFileNameV3 fileName;  /* Filename used when file handle invalid. */
+}
+#include "vmware_pack_end.h"
+HgfsRequestSetattrV3;
+
+/* Deprecated */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplySetattr {
+   HgfsReply header;
+}
+#include "vmware_pack_end.h"
+HgfsReplySetattr;
+
+
+/* Version 2 of HgfsReplySetattr */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplySetattrV2 {
+   HgfsReply header;
+}
+#include "vmware_pack_end.h"
+HgfsReplySetattrV2;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplySetattrV3 {
+   uint64 reserved;          /* Reserved for future use */
+}
+#include "vmware_pack_end.h"
+HgfsReplySetattrV3;
+
+
+/* Deprecated */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestCreateDir {
+   HgfsRequest header;
+   HgfsPermissions permissions;
+   HgfsFileName fileName;
+}
+#include "vmware_pack_end.h"
+HgfsRequestCreateDir;
+
+
+/* Version 2 of HgfsRequestCreateDir */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestCreateDirV2 {
+   HgfsRequest header;
+   HgfsCreateDirValid mask;
+   HgfsPermissions specialPerms;
+   HgfsPermissions ownerPerms;
+   HgfsPermissions groupPerms;
+   HgfsPermissions otherPerms;
+   HgfsFileName fileName;
+}
+#include "vmware_pack_end.h"
+HgfsRequestCreateDirV2;
+
+
+/* Version 3 of HgfsRequestCreateDir */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestCreateDirV3 {
+   HgfsCreateDirValid mask;
+   HgfsPermissions specialPerms;
+   HgfsPermissions ownerPerms;
+   HgfsPermissions groupPerms;
+   HgfsPermissions otherPerms;
+   uint64 reserved;              /* Reserved for future use */
+   HgfsFileNameV3 fileName;
+}
+#include "vmware_pack_end.h"
+HgfsRequestCreateDirV3;
+
+
+/* Deprecated */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyCreateDir {
+   HgfsReply header;
+}
+#include "vmware_pack_end.h"
+HgfsReplyCreateDir;
+
+
+/* Version 2 of HgfsReplyCreateDir */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyCreateDirV2 {
+   HgfsReply header;
+}
+#include "vmware_pack_end.h"
+HgfsReplyCreateDirV2;
+
+
+/* Version 3 of HgfsReplyCreateDir */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyCreateDirV3 {
+   uint64 reserved;              /* Reserved for future use */
+}
+#include "vmware_pack_end.h"
+HgfsReplyCreateDirV3;
+
+
+/* Deprecated */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestDelete {
+   HgfsRequest header;
+   HgfsFileName fileName;
+}
+#include "vmware_pack_end.h"
+HgfsRequestDelete;
+
+
+/* Version 2 of HgfsRequestDelete */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestDeleteV2 {
+   HgfsRequest header;
+   HgfsDeleteHint hints;
+   HgfsHandle file;        /* Opaque file ID used by the server. */
+   HgfsFileName fileName;  /* Name used if the file is HGFS_HANDLE_INVALID */
+}
+#include "vmware_pack_end.h"
+HgfsRequestDeleteV2;
+
+
+/* Version 3 of HgfsRequestDelete */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestDeleteV3 {
+   HgfsDeleteHint hints;
+   uint64 reserved;              /* Reserved for future use */
+   HgfsFileNameV3 fileName;      /* Name used if the file is HGFS_HANDLE_INVALID */
+}
+#include "vmware_pack_end.h"
+HgfsRequestDeleteV3;
+
+
+/* Deprecated */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyDelete {
+   HgfsReply header;
+}
+#include "vmware_pack_end.h"
+HgfsReplyDelete;
+
+/* Version 2 of HgfsReplyDelete */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyDeleteV2 {
+   HgfsReply header;
+}
+#include "vmware_pack_end.h"
+HgfsReplyDeleteV2;
+
+
+/* Version 2 of HgfsReplyDelete */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyDeleteV3 {
+   uint64 reserved;              /* Reserved for future use */
+}
+#include "vmware_pack_end.h"
+HgfsReplyDeleteV3;
+
+
+/*
+ * The size of the HgfsFileName struct is variable depending on the
+ * length of the name, so you can't use request->newName to get the
+ * actual address of the new name, because where it starts is
+ * dependant on how long the oldName is. To get the address of
+ * newName, use this:
+ *
+ *          &oldName + sizeof(HgfsFileName) + oldName.length
+ */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestRename {
+   HgfsRequest header;
+   HgfsFileName oldName;
+   HgfsFileName newName;
+}
+#include "vmware_pack_end.h"
+HgfsRequestRename;
+
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyRename {
+   HgfsReply header;
+}
+#include "vmware_pack_end.h"
+HgfsReplyRename;
+
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestRenameV2 {
+   HgfsRequest header;
+   HgfsRenameHint hints;
+   HgfsHandle srcFile;           /* Opaque file ID to "old name" used by the server. */
+   HgfsHandle targetFile;        /* Opaque file ID to "old name" used by the server. */
+   HgfsFileName oldName;
+   HgfsFileName newName;
+}
+#include "vmware_pack_end.h"
+HgfsRequestRenameV2;
+
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyRenameV2 {
+   HgfsReply header;
+}
+#include "vmware_pack_end.h"
+HgfsReplyRenameV2;
+
+
+/* HgfsRequestRename and HgfsReplyRename for v3. */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestRenameV3 {
+   HgfsRenameHint hints;
+   uint64 reserved;              /* Reserved for future use */
+   HgfsFileNameV3 oldName;
+   HgfsFileNameV3 newName;
+}
+#include "vmware_pack_end.h"
+HgfsRequestRenameV3;
+
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyRenameV3 {
+   uint64 reserved;              /* Reserved for future use */
+}
+#include "vmware_pack_end.h"
+HgfsReplyRenameV3;
+
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestQueryVolume {
+   HgfsRequest header;
+   HgfsFileName fileName;
+}
+#include "vmware_pack_end.h"
+HgfsRequestQueryVolume;
+
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyQueryVolume {
+   HgfsReply header;
+   uint64 freeBytes;
+   uint64 totalBytes;
+}
+#include "vmware_pack_end.h"
+HgfsReplyQueryVolume;
+
+
+/* HgfsRequestQueryVolume and HgfsReplyQueryVolume for v3. */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestQueryVolumeV3 {
+   uint64 reserved;              /* Reserved for future use */
+   HgfsFileNameV3 fileName;
+}
+#include "vmware_pack_end.h"
+HgfsRequestQueryVolumeV3;
+
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyQueryVolumeV3 {
+   uint64 freeBytes;
+   uint64 totalBytes;
+   uint64 reserved;              /* Reserved for future use */
+}
+#include "vmware_pack_end.h"
+HgfsReplyQueryVolumeV3;
+
+
+
+/* New operations for Version 2 */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestServerLockChange {
+   HgfsRequest header;
+   HgfsHandle file;
+   HgfsServerLock newServerLock;
+}
+#include "vmware_pack_end.h"
+HgfsRequestServerLockChange;
+
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyServerLockChange {
+   HgfsReply header;
+   HgfsServerLock serverLock;
+}
+#include "vmware_pack_end.h"
+HgfsReplyServerLockChange;
+
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestSymlinkCreate {
+   HgfsRequest header;
+   HgfsFileName symlinkName;
+
+   /* This filename is in "CPNameLite" format. See CPNameLite.c for details. */
+   HgfsFileName targetName;
+}
+#include "vmware_pack_end.h"
+HgfsRequestSymlinkCreate;
+
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplySymlinkCreate {
+   HgfsReply header;
+}
+#include "vmware_pack_end.h"
+HgfsReplySymlinkCreate;
+
+
+/* HgfsRequestSymlinkCreate and HgfsReplySymlinkCreate for v3. */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestSymlinkCreateV3 {
+   uint64 reserved;              /* Reserved for future use */
+   HgfsFileNameV3 symlinkName;
+
+   /* This filename is in "CPNameLite" format. See CPNameLite.c for details. */
+   HgfsFileNameV3 targetName;
+}
+#include "vmware_pack_end.h"
+HgfsRequestSymlinkCreateV3;
+
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplySymlinkCreateV3 {
+   uint64 reserved;              /* Reserved for future use */
+}
+#include "vmware_pack_end.h"
+HgfsReplySymlinkCreateV3;
+
+
+#endif /* _HGFS_PROTO_H_ */
diff --git a/open-vm-tools/modules/solaris/vmhgfs/hgfsSolaris.h b/open-vm-tools/modules/solaris/vmhgfs/hgfsSolaris.h
new file mode 100644 (file)
index 0000000..c32d579
--- /dev/null
@@ -0,0 +1,236 @@
+/*********************************************************
+ * Copyright (C) 2004 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+
+/*
+ * hgfsSolaris.h --
+ *
+ * Contains declarations needed in entire Solaris HGFS module.
+ *
+ */
+
+/* XXX: Split the non-kernel parts off into another header */
+
+#ifndef __HGFS_H_
+#define __HGFS_H_
+
+/*
+ * System includes
+ */
+
+/*
+ * Kernel system includes
+ */
+#ifdef _KERNEL
+
+/*
+ * These must be in this order, so we include them here, and only here, so
+ * that this ordering is guaranteed.
+ *
+ * <sys/types.h> defines min and max macros (that shouldn't be used because
+ * they're broken) and <sys/conf.h> includes <sys/systm.h> which defines
+ * functions named min and max.  The function definitions must come first.
+ */
+#include <sys/conf.h>           /* D_NEW flag and other includes */
+#include <sys/types.h>          /* various typedefs */
+
+#endif /* _KERNEL */
+
+/*
+ * VMware includes
+ */
+#include "hgfsProto.h"
+#include "hgfsState.h"
+#include "filesystem.h"
+
+/*
+ * Kernel VMware includes
+ */
+#ifdef _KERNEL
+
+#include "dbllnklst.h"
+#include "vm_assert.h"
+
+#endif /* _KERNEL */
+
+
+/*
+ * Macros
+ */
+
+#define HGFS_PAYLOAD_MAX(reply)         (HGFS_PACKET_MAX - sizeof *reply)
+#define HGFS_FS_NAME                    "vmhgfs"
+#define HGFS_BLOCKSIZE                  1024
+
+
+/*
+ * Kernel only macros
+ */
+#ifdef _KERNEL
+
+/* Determines size of request pool */
+#define HGFS_MAX_OUTSTANDING_REQS       4
+
+/* For ddi_soft_state_init() call in _init() */
+#define HGFS_EXPECTED_INSTANCES         23
+
+/* HGFS cmn_err() levels */
+#define HGFS_ERROR                      (CE_WARN)
+
+/* Internal error code(s) */
+#define HGFS_ERR                        (-1)
+#define HGFS_ERR_NULL_INPUT             (-50)
+#define HGFS_ERR_NODEV                  (-51)
+#define HGFS_ERR_INVAL                  (-52)
+
+/* This is what shows up after the ':' in the /devices entry */
+#define HGFS_DEV_NAME                   "vmware-hgfs"
+
+/*
+ * Don't change this to KM_NOSLEEP without first making sure that we handle
+ * the possibility of kmem_zalloc() failing: KM_SLEEP guarantees it won't fail
+ */
+#define HGFS_ALLOC_FLAG                 (KM_SLEEP)
+
+/*
+ * hgfsInstance is uninitialized when device is not open and hgfsType is
+ * uninitialized before the file system initialization routine is called.
+ */
+#define HGFS_INSTANCE_UNINITIALIZED     (-1)
+#define HGFS_TYPE_UNINITIALIZED         (-1)
+
+/* Accessing root inode and vnode */
+#define HGFS_ROOT_VNODE(sip)            (sip->rootVnode)
+
+
+#endif /* _KERNEL */
+
+
+/*
+ * Structures
+ */
+
+/* We call them *Header in the Solaris code for clarity. */
+typedef HgfsReply HgfsReplyHeader;
+typedef HgfsRequest HgfsRequestHeader;
+
+/*
+ * Kernel only structures and variables
+ */
+#ifdef _KERNEL
+
+/*
+ * The global state structure for the entire module.  This is allocated in
+ * HgfsDevAttach() and deallocated in HgfsDevDetach().
+ *
+ * Note that reqMutex and reqFreeList are also used for synchronization between
+ * the filesystem and driver.  See docs/synchronization.txt for details.
+ */
+typedef struct HgfsSuperInfo {
+   dev_info_t *dip;                     /* Device information pointer */
+   Bool devOpen;                        /* Flag indicating whether device is open */
+   /* Poll */
+   struct pollhead hgfsPollhead;        /* Needed for chpoll() implementation */
+   Bool pollwakeupOnWrite;              /* Flag which indicates need to call
+                                           pollwakeup() on write() -- no mutex
+                                           since only modified in chpoll() */
+   /* Request list */
+   DblLnkLst_Links reqList;             /* Anchor for pending request list */
+   kmutex_t reqMutex;                   /* For protection of request list */
+   kcondvar_t reqCondVar;               /* For waiting on request list */
+   /* Free request list */
+   DblLnkLst_Links reqFreeList;         /* Anchor for free request list */
+   kmutex_t reqFreeMutex;               /* For protection of reqFreeList */
+   kcondvar_t reqFreeCondVar;           /* For waiting on free request list */
+   /* For filesystem */
+   struct vfs *vfsp;                    /* Our filesystem structure */
+   struct vnode *rootVnode;             /* Root vnode of the filesystem */
+   HgfsFileHashTable fileHashTable;     /* File hash table */
+#  if HGFS_VFS_VERSION > 2
+   /* We keep a pointer to the vnodeops the Kernel created for us in Sol 10 */
+   struct vnodeops *vnodeOps;           /* Operations on files */
+#  endif
+} HgfsSuperInfo;
+
+/*
+ * Each request will traverse through this set of states.  See
+ * docs/request-lifecycle.txt for an explanation of these and the API for
+ * interacting with requests.
+ */
+typedef enum {
+   HGFS_REQ_UNUSED = 1,
+   HGFS_REQ_ALLOCATED,
+   HGFS_REQ_SUBMITTED,
+   HGFS_REQ_ABANDONED,
+   HGFS_REQ_ERROR,
+   HGFS_REQ_COMPLETED
+} HgfsReqState;
+
+
+/*
+ * General request structure.  Specific requests and replies are placed in the
+ * packet of this structure.
+ */
+typedef struct HgfsReq {
+   DblLnkLst_Links listNode;            /* Node to connect the request to one of
+                                         * the lists (free or pending) */
+   kcondvar_t condVar;                  /* Condition variable to wait for and
+                                           signal presence of reply. Used with
+                                           the reqMutex in HgfsSuperInfo. */
+   HgfsReqState state;                  /* Indicates state of request */
+   kmutex_t stateLock;                  /* Protects state: only used in
+                                           HgfsReq{S,G}etState() */
+
+   uint32_t id;                         /* The unique identifier of this request */
+
+   uint32_t packetSize;                 /* Total size of packet */
+   char packet[HGFS_PACKET_MAX];        /* Contains both requests and replies */
+} HgfsReq;
+
+
+/*
+ * Global Variables
+ */
+
+/* Pool of request structures */
+HgfsReq requestPool[HGFS_MAX_OUTSTANDING_REQS];
+
+/*
+ * Fileystem type number.
+ *
+ * This needs to be stored here rather than in the Superinfo because the soft
+ * state is not guaranteed to have been allocated when HgfsInit() is called.
+ */
+int hgfsType;
+
+/*
+ * Used to access shared state of driver and filesystem.  superInfoHead is
+ * a pointer to state managed by Solaris, hgfsInstance is the index into this state
+ * list, and is set in HgfsDevAttach().
+ *
+ * Note that both the driver and filesystem use ddi_get_soft_state() to get
+ * a pointer to the superinfo.  Both use superInfoHead, but the device uses the
+ * instance number derived from passed in arguments and the filesystem uses
+ * hgfsInstance.  This is not a problem as long as the instance number cannot
+ * change, which /should/ be guaranteed, and there is only a single instance,
+ * which cannot happen.
+ */
+void *superInfoHead;
+int hgfsInstance;
+
+#endif /* _KERNEL */
+
+#endif /* __HGFS_H_ */
diff --git a/open-vm-tools/modules/solaris/vmhgfs/hgfsState.c b/open-vm-tools/modules/solaris/vmhgfs/hgfsState.c
new file mode 100644 (file)
index 0000000..9b00809
--- /dev/null
@@ -0,0 +1,1529 @@
+/*********************************************************
+ * Copyright (C) 2004 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+
+/*
+ * hgfsState.c --
+ *
+ * This implements the functions that provide all the filesystem specific state
+ * that is placed underneath the vnodes.
+ *
+ */
+
+
+/*
+ * Includes
+ */
+
+#include "vnode.h"
+#include "hgfsState.h"
+#include "debug.h"
+
+#include "vm_assert.h"
+#include "vm_basic_types.h"
+#include "sha1.h"               /* SHA-1 for Node ID calculation */
+
+
+/*
+ * Macros
+ */
+#define HGFS_VNODE_INIT_FLAG    VNOMAP  /* So we don't have to implement mmap() */
+#define HGFS_VNODE_INIT_COUNT   1
+#define HGFS_VNODE_INIT_RDEV    VBLK    /* We pretend to be a block device */
+
+#define HGFS_FILE_HT_HEAD(ht, index)    (ht->hashTable[index]).next
+#define HGFS_FILE_HT_BUCKET(ht, index)  (&ht->hashTable[index])
+
+#define HGFS_IS_ROOT_FILE(sip, file)    (HGFS_VP_TO_FP(sip->rootVnode) == file)
+
+/*
+ * Prototypes for internal functions
+ */
+
+/* Allocation/initialization/free of open file state */
+static HgfsOpenFile *HgfsAllocOpenFile(const char *fileName, HgfsFileType fileType,
+                                       HgfsFileHashTable *htp);
+static void HgfsFreeOpenFile(HgfsOpenFile *ofp, HgfsFileHashTable *htp);
+
+/* Acquiring/releasing file state */
+static HgfsFile *HgfsGetFile(const char *fileName, HgfsFileType fileType,
+                             HgfsFileHashTable *htp);
+static void HgfsReleaseFile(HgfsFile *fp, HgfsFileHashTable *htp);
+static int HgfsInitFile(HgfsFile *fp, const char *fileName, HgfsFileType fileType);
+
+/* Adding/finding/removing file state from hash table */
+static inline void HgfsAddFile(HgfsFile *fp, HgfsFileHashTable *htp);
+static inline void HgfsRemoveFile(HgfsFile *fp, HgfsFileHashTable *htp);
+static HgfsFile *HgfsFindFile(const char *fileName, HgfsFileHashTable *htp);
+
+/* Other utility functions */
+static unsigned int HgfsFileNameHash(const char *fileName);
+static void HgfsNodeIdHash(const char *fileName, uint32_t fileNameLength,
+                           ino64_t *outHash);
+
+
+/*
+ * Public functions
+ */
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsVnodeGet --
+ *
+ *    Creates a vnode for the provided filename.
+ *
+ *    This will always allocate a vnode and HgfsOpenFile.  If a HgfsFile
+ *    already exists for this filename then that is used, if a HgfsFile doesn't
+ *    exist, one is created.
+ *
+ * Results:
+ *    Returns 0 on success and a non-zero error code on failure.
+ *
+ * Side effects:
+ *    If the HgfsFile already exists, its reference count is incremented;
+ *    otherwise a HgfsFile is created.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsVnodeGet(struct vnode **vpp,        // OUT: Filled with address of created vnode
+             HgfsSuperInfo *sip,        // IN:  Superinfo
+             struct vfs *vfsp,          // IN:  Filesystem structure
+             const char *fileName,      // IN:  Name of this file
+             HgfsFileType fileType,     // IN:  Type of file
+             HgfsFileHashTable *htp)    // IN:  File hash table
+{
+   struct vnode *vp;
+
+   ASSERT(vpp);
+   ASSERT(sip);
+   ASSERT(vfsp);
+   ASSERT(fileName);
+   ASSERT(htp);
+
+   /*
+    * Here we need to construct the vnode for the kernel as well as our
+    * internal file system state.  Our internal state consists of
+    * a HgfsOpenFile and a HgfsFile.  The HgfsOpenFile is state kept per-open
+    * file; the HgfsFile state is kept per-file.  We have a one-to-one mapping
+    * between vnodes and HgfsOpenFiles, and a many-to-one mapping from each of
+    * those to a HgfsFile.
+    *
+    * Note that it appears the vnode is intended to be used as a per-file
+    * structure, but we are using it as a per-open-file. The sole exception
+    * for this is the root vnode because it is returned by HgfsRoot().  This
+    * also means that reference counts for all vnodes except the root should
+    * be one; the reference count in our HgfsFile takes on the role of the
+    * vnode reference count.
+    */
+   /*
+    * Note that we no longer embed the vnode in our private structure in
+    * Solaris 9.  This was done to simplify this code path and decrease the
+    * differences between Solaris 9 and 10.
+    */
+#  ifdef SOL9
+   vp = kmem_zalloc(sizeof *vp, HGFS_ALLOC_FLAG);
+#  else
+   vp = vn_alloc(HGFS_ALLOC_FLAG);
+#  endif
+   if (!vp) {
+      return HGFS_ERR;
+   }
+
+   /*
+    * Now we'll initialize the vnode.  We need to set the file type, vnode
+    * operations, flags, filesystem pointer, reference count, and device.
+    * After that we'll create our private structures and hang them from the
+    * vnode's v_data pointer.
+    */
+   switch (fileType) {
+   case HGFS_FILE_TYPE_REGULAR:
+      vp->v_type = VREG;
+      break;
+
+   case HGFS_FILE_TYPE_DIRECTORY:
+      vp->v_type = VDIR;
+      break;
+
+   default:
+      /* Hgfs only supports directories and regular files */
+      goto vnode_error;
+   }
+
+   /*
+    * Now set the vnode operations.  This is handled differently on Solaris
+    * 9 and 10, and we call HgfsSetVnodeOps() to take care of this for us.
+    */
+   if (HgfsSetVnodeOps(sip, vp) != 0) {
+      goto vnode_error;
+   }
+
+   /*
+    * The vnode cache constructor will have initialized the mutex for us on
+    * Solaris 10, so we only do it ourselves on Solaris 9.
+    */
+#  ifdef SOL9
+   mutex_init(&vp->v_lock, NULL, MUTEX_DRIVER, NULL);
+#  endif
+
+   vp->v_flag  = HGFS_VNODE_INIT_FLAG;
+   vp->v_count = HGFS_VNODE_INIT_COUNT;
+   vp->v_vfsp  = vfsp;
+   vp->v_rdev  = HGFS_VNODE_INIT_RDEV;
+
+   /*
+    * We now allocate our private open file structure.  This will correctly
+    * initialize the per-open-file state, as well as locate (or create if
+    * necessary) the per-file state.
+    */
+   vp->v_data = (void *)HgfsAllocOpenFile(fileName, fileType, htp);
+   if (!vp->v_data) {
+      goto openfile_error;
+   }
+
+   /* Fill in the provided address with the new vnode. */
+   *vpp = vp;
+
+   /* Return success */
+   return 0;
+
+   /* Cleanup points for errors. */
+openfile_error:
+#  ifdef SOL9
+   mutex_destroy(&vp->v_lock);
+#  endif
+vnode_error:
+#  ifdef SOL9
+   kmem_free(vp, sizeof *vp);
+#  else
+   vn_free(vp);
+#  endif
+   return HGFS_ERR;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsVnodePut --
+ *
+ *    Releases the provided vnode.
+ *
+ *    This will always free both the vnode and its associated HgfsOpenFile.
+ *    The HgfsFile's reference count is decremented and, if 0, freed.
+ *
+ * Results:
+ *    Returns 0 on success and a non-zero error code on failure.
+ *
+ * Side effects:
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsVnodePut(struct vnode *vp,          // IN: Vnode to release
+             HgfsFileHashTable *htp)    // IN: Hash table pointer
+{
+   HgfsOpenFile *ofp;
+
+   ASSERT(vp);
+   ASSERT(htp);
+
+   /* Get our private open-file state. */
+   ofp = HGFS_VP_TO_OFP(vp);
+   if (!ofp) {          // XXX Maybe ASSERT() this?
+      return HGFS_ERR;
+   }
+
+   /*
+    * We need to free the open file structure.  This takes care of releasing
+    * our reference on the underlying file structure (and freeing it if
+    * necessary).
+    */
+   HgfsFreeOpenFile(ofp, htp);
+
+   /*
+    * Now we clean up the vnode.
+    */
+#  ifdef SOL9
+   mutex_destroy(&vp->v_lock);
+#  endif
+
+#  ifdef SOL9
+   kmem_free(vp, sizeof *vp);
+#  else
+   vn_free(vp);
+#  endif
+
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsVnodeDup --
+ *
+ *    Duplicates the vnode and HgfsOpenFile (per-open state) of a file and
+ *    increments the reference count of the underlying HgfsFile.  This function
+ *    just calls HgfsVnodeGet with the right arguments.
+ *
+ * Results:
+ *    Returns 0 on success and a non-zero error code on failure.  On success
+ *    the address of the duplicated vnode is written to newVpp.
+ *
+ * Side effects:
+ *    The HgfsFile for origVp will have an additional reference.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsVnodeDup(struct vnode **newVpp,             // OUT: Given address of new vnode
+             struct vnode *origVp,              // IN:  Vnode to duplicate
+             struct HgfsSuperInfo *sip,         // IN:  Superinfo pointer
+             HgfsFileHashTable *htp)            // IN:  File hash table
+{
+   ASSERT(newVpp);
+   ASSERT(origVp);
+   ASSERT(sip);
+   ASSERT(htp);
+
+   DEBUG(VM_DEBUG_ALWAYS, "HgfsVnodeDup: duping %s\n", HGFS_VP_TO_FILENAME(origVp));
+
+   return HgfsVnodeGet(newVpp, sip, origVp->v_vfsp, HGFS_VP_TO_FILENAME(origVp),
+                       HGFS_VP_TO_HGFSFILETYPE(origVp), &sip->fileHashTable);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsFileNameToVnode --
+ *
+ *    Allocates new per-open-file state if a HgfsFile for fileName exists in
+ *    the provided file hash table.
+ *
+ * Results:
+ *    Returns 0 on success or a non-zero error code on failure.  On success,
+ *    vpp is filled with the address of the new per-open state.
+ *
+ * Side effects:
+ *    The reference count of the HgfsFile for fileName is incremented if it
+ *    exists.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsFileNameToVnode(const char *fileName,
+                    struct vnode **vpp,
+                    struct HgfsSuperInfo *sip,
+                    struct vfs *vfsp,
+                    HgfsFileHashTable *htp)
+{
+   HgfsFile *fp;
+   HgfsFileType fileType;
+
+   ASSERT(vpp);
+   ASSERT(sip);
+   ASSERT(vfsp);
+   ASSERT(fileName);
+   ASSERT(htp);
+
+   /*
+    * XXX: This locking here is not totally correct.  Because we are calling
+    * HgfsVnodeGet(), which does its own locking on the hash table, we must
+    * make finding out the file is in the hash table and then creating our
+    * internal state that increments that file's reference count non-atomic.
+    *
+    * Because of this, it is possible for the file to be in the hash table when
+    * we look, then be removed by the time we look for it again.  As
+    * a consquence, we will add the file to the hash table then.  This is
+    * partially correct in the fact that the file was in the hash table when we
+    * looked, but it is partially incorrect since it wasn't in the hash table
+    * when we looked again.  In practice this shouldn't cause any problems, but
+    * it is possible for a file that is deleted on the host to remain in our
+    * hash table longer than it should.
+    *
+    * A more correct locking scheme was not used because the complexity of
+    * doing so outweighed the problems that can occur from this more simple
+    * approach.  This approach was also left as is because it provides an
+    * optimization to the filesystem by decreasing the number of requests that
+    * must be sent significantly.  This optimization can be easily turned off
+    * by commenting out the single call to this function in HgfsLookup() in
+    * vnode.c.
+    *
+    * Possible solutions to this are: 1) adding new locks to the top-level
+    * public functions (HgfsVnodeGet(), FileNameToVnode(), and NodeIdGet()), 2)
+    * bringing the hash table locking up to those same functions, or 3)
+    * reimplementing much of the call sequence down to the calls to FindFile()
+    * and AddFile() in HgfsGetFile() that is specific to this function.  1 is
+    * likely the best option as 2 uses hash table locks for an incorrect
+    * purpose and 3 will create a significant amount of repeated code.
+    */
+
+   DEBUG(VM_DEBUG_ALWAYS, "HgfsFileNameToVnode: looking for %s\n", fileName);
+
+   mutex_enter(&htp->mutex);
+
+   fp = HgfsFindFile(fileName, htp);
+   if (!fp) {
+      mutex_exit(&htp->mutex);
+      return HGFS_ERR;
+   }
+
+   /* Guaranteed by HgfsFindFile(). */
+   ASSERT(strcmp(fileName, fp->fileName) == 0);
+
+   /*
+    * We save the type of this file with the lock held in case it goes away:
+    * see the above comment about locking.
+    */
+   fileType = fp->fileType;
+
+   mutex_exit(&htp->mutex);
+
+   DEBUG(VM_DEBUG_ALWAYS, "HgfsFileNameToVnode: found %s\n", fileName);
+
+   return HgfsVnodeGet(vpp, sip, vfsp, fileName, fileType, htp);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsNodeIdGet --
+ *
+ *    Gets the node id for the provided file.  This will only calculate the
+ *    node id again if a per-file state structure doesn't yet exist for this
+ *    file.  (This situation exists on a readdir since dentries are filled in
+ *    rather than creating vnodes.)
+ *
+ *    In Solaris, node ids are provided in vnodes and inode numbers are
+ *    provided in dentries.  For applications to work correctly, we must make
+ *    sure that the inode number of a file's dentry and the node id in a file's
+ *    vnode match one another.  This poses a problem since vnodes typically do
+ *    not exist when dentries need to be created, and once a dentry is created
+ *    we have no reference to it since it is copied to the user and freed from
+ *    kernel space.  An example of a program that breaks when these values
+ *    don't match is /usr/bin/pwd.  This program first acquires the node id of
+ *    "." from its vnode, then traverses backwards to ".." and looks for the
+ *    dentry in that directory with the inode number matching the node id.
+ *    (This is how it obtains the name of the directory it was just in.)
+ *    /usr/bin/pwd repeats this until it reaches the root directory, at which
+ *    point it concatenates the filenames it acquired along the way and
+ *    displays them to the user.  When inode numbers don't match the node id,
+ *    /usr/bin/pwd displays an error saying it cannot determine the directory.
+ *
+ *    The Hgfs protocol does not provide us with unique identifiers for files
+ *    since it must support filesystems that do not have the concept of inode
+ *    numbers.  Therefore, we must maintain a mapping from filename to node id/
+ *    inode numbers.  This is done in a stateless manner by calculating the
+ *    SHA-1 hash of the filename.  All points in the Hgfs code that need a node
+ *    id/inode number obtain it by either calling this function or directly
+ *    referencing the saved node id value in the vnode, if one is available.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+HgfsNodeIdGet(HgfsFileHashTable *htp,   // IN:  File hash table
+              const char *fileName,     // IN:  Filename to get node id for
+              uint32_t fileNameLength,  // IN:  Length of filename
+              ino64_t *outNodeId)       // OUT: Destination for nodeid
+{
+   HgfsFile *fp;
+
+   ASSERT(htp);
+   ASSERT(fileName);
+   ASSERT(outNodeId);
+
+   mutex_enter(&htp->mutex);
+
+   fp = HgfsFindFile(fileName, htp);
+   if (fp) {
+      *outNodeId = fp->nodeId;
+   } else {
+      HgfsNodeIdHash(fileName, fileNameLength, outNodeId);
+   }
+
+   mutex_exit(&htp->mutex);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsInitFileHashTable --
+ *
+ *    Initializes the hash table used to track per-file state.
+ *
+ * Results:
+ *    Returns 0 on success and a non-zero error code on failure.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsInitFileHashTable(HgfsFileHashTable *htp)   // IN: Hash table to initialize
+{
+   int i;
+
+   ASSERT(htp);
+
+   mutex_init(&htp->mutex, NULL, MUTEX_DRIVER, NULL);
+
+   for (i = 0; i < ARRAYSIZE(htp->hashTable); i++) {
+      DblLnkLst_Init(&htp->hashTable[i]);
+   }
+
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsFileHashTableIsEmpty --
+ *
+ *    Determines whether the hash table is in an acceptable state to unmount
+ *    the file system.
+ *
+ *    Note that this is not strictly empty: if the only file in the table is
+ *    the root of the filesystem and its reference count is 1, this is
+ *    considered empty since this is part of the operation of unmounting the
+ *    filesystem.
+ *
+ * Results:
+ *    Returns 0 on success and a non-zero error code on failure.
+ *
+ * Side effects:
+ *    None.
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsFileHashTableIsEmpty(HgfsSuperInfo *sip,            // IN: Superinfo
+                         HgfsFileHashTable *htp)        // IN: File hash table
+{
+   int i;
+
+   ASSERT(sip);
+   ASSERT(htp);
+
+   mutex_enter(&htp->mutex);
+
+   /* Traverse each bucket. */
+   for (i = 0; i < ARRAYSIZE(htp->hashTable); i++) {
+      DblLnkLst_Links *currNode = HGFS_FILE_HT_HEAD(htp, i);
+
+      /* Visit each file in this bucket */
+      while (currNode != HGFS_FILE_HT_BUCKET(htp, i)) {
+         HgfsFile *currFile = DblLnkLst_Container(currNode, HgfsFile, listNode);
+
+         /*
+          * Here we special case the root of our filesystem.  In a correct
+          * unmount, the root vnode of the filesystem will have an entry in the
+          * hash table and will have a reference count of 1.  We check if the
+          * current entry is the root file, and if so, make sure its vnode's
+          * reference count is not > 1.  Note that we are not mapping from file
+          * to vnode here (which is not possible), we are using the root vnode
+          * stored in the superinfo structure.  This is the only vnode that
+          * should have multiple references associated with it because whenever
+          * someone calls HgfsRoot(), we return that vnode.
+          */
+         if (HGFS_IS_ROOT_FILE(sip, currFile)) {
+            mutex_enter(&HGFS_ROOT_VNODE(sip)->v_lock);
+            if (HGFS_ROOT_VNODE(sip)->v_count <= 1) {
+               mutex_exit(&HGFS_ROOT_VNODE(sip)->v_lock);
+
+               /* This file is okay; skip to the next one. */
+               currNode = currNode->next;
+               continue;
+            }
+
+            DEBUG(VM_DEBUG_FAIL, "HgfsFileHashTableIsEmpty: %s has count of %d.\n",
+                  currFile->fileName, HGFS_ROOT_VNODE(sip)->v_count);
+
+            mutex_exit(&HGFS_ROOT_VNODE(sip)->v_lock);
+            /* Fall through to failure case */
+         }
+
+         /* Fail if a file is found. */
+         mutex_exit(&htp->mutex);
+         DEBUG(VM_DEBUG_FAIL, "HgfsFileHashTableIsEmpty: %s "
+               "still in use (file count=%d).\n",
+               currFile->fileName, currFile->refCount);
+         return FALSE;
+      }
+   }
+
+   mutex_exit(&htp->mutex);
+
+   return TRUE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsDebugPrintFileHashTable --
+ *
+ *    This will print out all the HgfsFiles that we have in the hash table, as
+ *    well as the HgfsFile reference count.  This should help finding places
+ *    where there may be loose references on files that prevent an unmount
+ *    (EBUSY) when it should be allowed.
+ *
+ * Results:
+ *    Void.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+HgfsDebugPrintFileHashTable(HgfsFileHashTable *htp,     // IN: Hash table to print
+                            int level)                  // IN: Debugging level
+{
+   int bucket;
+
+   ASSERT(htp);
+
+   mutex_enter(&htp->mutex);
+
+   for (bucket = 0; bucket < ARRAYSIZE(htp->hashTable); bucket++) {
+      DblLnkLst_Links *currNode = HGFS_FILE_HT_HEAD(htp, bucket);
+
+      while (currNode != HGFS_FILE_HT_BUCKET(htp, bucket)) {
+         HgfsFile *currFile = DblLnkLst_Container(currNode, HgfsFile, listNode);
+
+         mutex_enter(&currFile->mutex);
+         DEBUG(level, "HgfsDebugPrintFileHashTable: "
+               "file: %s, count: %d (bucket %d)\n",
+               currFile->fileName, currFile->refCount, bucket);
+         mutex_exit(&currFile->mutex);
+
+         currNode = currNode->next;
+      }
+   }
+
+   mutex_exit(&htp->mutex);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsHandleIsSet --
+ *
+ *    Determines whether handle of the vnode's open file is currently set.
+ *
+ * Results:
+ *    Returns TRUE if the handle is set, FALSE if the handle is not set.
+ *    HGFS_ERR is returned on error.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsHandleIsSet(struct vnode *vp)       // IN: Vnode to check handle of
+{
+   HgfsOpenFile *ofp;
+   Bool isSet;
+
+   ASSERT(vp);
+
+   ofp = HGFS_VP_TO_OFP(vp);
+   if (!ofp) {
+      return HGFS_ERR;
+   }
+
+   mutex_enter(&ofp->handleMutex);
+   isSet = ofp->handleIsSet;
+   mutex_exit(&ofp->handleMutex);
+
+   return isSet;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsSetOpenFileHandle --
+ *
+ *    Sets the open file handle for the provided vnode.
+ *
+ * Results:
+ *    Returns 0 on success and a non-zero error code on failure.
+ *
+ * Side effects:
+ *    The handle may not be set again until it is cleared.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsSetOpenFileHandle(struct vnode *vp,         // IN: Vnode to set handle for
+                      HgfsHandle handle)        // IN: Value of handle
+{
+   HgfsOpenFile *ofp;
+
+   ASSERT(vp);
+
+   ofp = HGFS_VP_TO_OFP(vp);
+   if (!ofp) {
+      return HGFS_ERR;
+   }
+
+   mutex_enter(&ofp->handleMutex);
+
+   if (ofp->handleIsSet) {
+      DEBUG(VM_DEBUG_FAIL, "**HgfsSetOpenFileHandle: handle for %s already set to %d; "
+            "cannot set to %d\n", HGFS_VP_TO_FILENAME(vp), ofp->handle, handle);
+      mutex_exit(&ofp->handleMutex);
+      return HGFS_ERR;
+   }
+
+   ofp->handle = handle;
+   ofp->handleIsSet = TRUE;
+
+   DEBUG(VM_DEBUG_STATE, "HgfsSetOpenFileHandle: set handle for %s to %d\n",
+         HGFS_VP_TO_FILENAME(vp), ofp->handle);
+
+   mutex_exit(&ofp->handleMutex);
+
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsGetOpenFileHandle --
+ *
+ *    Gets the open file handle for the provided vnode.
+ *
+ * Results:
+ *    Returns 0 on success and a non-zero error code on failure.  On success,
+ *    the value of the vnode's handle is placed in outHandle.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsGetOpenFileHandle(struct vnode *vp,         // IN:  Vnode to get handle for
+                      HgfsHandle *outHandle)    // OUT: Filled with value of handle
+{
+   HgfsOpenFile *ofp;
+
+   ASSERT(vp);
+   ASSERT(outHandle);
+
+   ofp = HGFS_VP_TO_OFP(vp);
+   if (!ofp) {
+      return HGFS_ERR;
+   }
+
+   mutex_enter(&ofp->handleMutex);
+
+   if (!ofp->handleIsSet) {
+      DEBUG(VM_DEBUG_FAIL, "**HgfsGetOpenFileHandle: handle for %s is not set.\n",
+            HGFS_VP_TO_FILENAME(vp));
+      mutex_exit(&ofp->handleMutex);
+      return HGFS_ERR;
+   }
+
+   *outHandle = ofp->handle;
+
+   mutex_exit(&ofp->handleMutex);
+
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsClearOpenFileHandle --
+ *
+ *    Clears the open file handle for the provided vnode.
+ *
+ * Results:
+ *    Returns 0 on success and a non-zero error code on failure.
+ *
+ * Side effects:
+ *    The handle may be set.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsClearOpenFileHandle(struct vnode *vp)       // IN: Vnode to clear handle for
+{
+   HgfsOpenFile *ofp;
+
+   ASSERT(vp);
+
+   ofp = HGFS_VP_TO_OFP(vp);
+   if (!ofp) {
+      return HGFS_ERR;
+   }
+
+   mutex_enter(&ofp->handleMutex);
+
+   ofp->handle = 0;
+   ofp->handleIsSet = FALSE;
+
+   DEBUG(VM_DEBUG_STATE, "HgfsClearOpenFileHandle: cleared %s's handle\n",
+         HGFS_VP_TO_FILENAME(vp));
+
+   mutex_exit(&ofp->handleMutex);
+
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsSetOpenFileMode --
+ *
+ *    Sets the mode of the open file for the provided vnode.
+ *
+ * Results:
+ *    Returns 0 on success and a non-zero error code on failure.
+ *
+ * Side effects:
+ *    The mode may not be set again until cleared.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsSetOpenFileMode(struct vnode *vp,   // IN: Vnode to set mode for
+                    HgfsMode mode)      // IN: Mode to set to
+{
+   HgfsOpenFile *ofp;
+
+   ASSERT(vp);
+
+   ofp = HGFS_VP_TO_OFP(vp);
+   if (!ofp) {
+      return HGFS_ERR;
+   }
+
+   mutex_enter(&ofp->modeMutex);
+
+   if (ofp->modeIsSet) {
+      DEBUG(VM_DEBUG_FAIL, "**HgfsSetOpenFileMode: mode for %s already set to %d; "
+            "cannot set to %d\n", HGFS_VP_TO_FILENAME(vp), ofp->mode, mode);
+      mutex_exit(&ofp->modeMutex);
+      return HGFS_ERR;
+   }
+
+   ofp->mode = mode;
+   ofp->modeIsSet = TRUE;
+
+   DEBUG(VM_DEBUG_STATE, "HgfsSetOpenFileMode: set mode for %s to %d\n",
+         HGFS_VP_TO_FILENAME(vp), ofp->mode);
+
+   mutex_exit(&ofp->modeMutex);
+
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsGetOpenFileMode --
+ *
+ *    Gets the mode of the open file for the provided vnode.
+ *
+ * Results:
+ *    Returns 0 on success and a non-zero error code on failure.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsGetOpenFileMode(struct vnode *vp,   // IN:  Vnode to get mode for
+                    HgfsMode *outMode)  // OUT: Filled with mode
+{
+   HgfsOpenFile *ofp;
+
+   ASSERT(vp);
+   ASSERT(outMode);
+
+   ofp = HGFS_VP_TO_OFP(vp);
+   if (!ofp) {
+      return HGFS_ERR;
+   }
+
+   mutex_enter(&ofp->modeMutex);
+
+   if (!ofp->modeIsSet) {
+//      DEBUG(VM_DEBUG_FAIL, "**HgfsGetOpenFileMode: mode for %s is not set.\n",
+//            HGFS_VP_TO_FILENAME(vp));
+      mutex_exit(&ofp->modeMutex);
+      return HGFS_ERR;
+   }
+
+   *outMode = ofp->mode;
+
+   mutex_exit(&ofp->modeMutex);
+
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsClearOpenFileMode --
+ *
+ *    Clears the mode of the open file for the provided vnode.
+ *
+ * Results:
+ *    Returns 0 on success and a non-zero error code on failure.
+ *
+ * Side effects:
+ *    The mode may be set again.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsClearOpenFileMode(struct vnode *vp) // IN: Vnode to clear mode for
+{
+   HgfsOpenFile *ofp;
+
+   ASSERT(vp);
+
+   ofp = HGFS_VP_TO_OFP(vp);
+   if (!ofp) {
+      return HGFS_ERR;
+   }
+
+   mutex_enter(&ofp->modeMutex);
+
+   ofp->mode = 0;
+   ofp->modeIsSet = FALSE;
+   
+   DEBUG(VM_DEBUG_STATE, "HgfsClearOpenFileMode: cleared %s's mode\n",
+         HGFS_VP_TO_FILENAME(vp));
+
+   mutex_exit(&ofp->modeMutex);
+
+   return 0;
+}
+
+
+/*
+ * Internal functions
+ */
+
+
+/* Allocation/initialization/free of open file state */
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsAllocOpenFile --
+ *
+ *    Allocates and initializes an open file structure.  Also finds or, if
+ *    necessary, creates the underlying HgfsFile per-file state.
+ *
+ * Results:
+ *    Returns a pointer to the open file on success, NULL on error.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static HgfsOpenFile *
+HgfsAllocOpenFile(const char *fileName,         // IN: Name of file
+                  HgfsFileType fileType,        // IN: Type of file
+                  HgfsFileHashTable *htp)       // IN: Hash table
+{
+   HgfsOpenFile *ofp;
+
+   ASSERT(fileName);
+   ASSERT(htp);
+
+   /*
+    * We allocate and initialize our open-file state.
+    */
+   ofp = (HgfsOpenFile *)kmem_zalloc(sizeof *ofp, HGFS_ALLOC_FLAG);
+   /* kmem_zalloc() cannot fail if given KM_SLEEP; check otherwise */
+#  if HGFS_ALLOC_FLAG != KM_SLEEP
+   if (!ofp) {
+      return NULL;
+   }
+#  endif
+
+   /* Manually set these since the public functions need the lock. */
+   ofp->handle = 0;
+   ofp->handleIsSet = FALSE;
+
+   ofp->mode = 0;
+   ofp->modeIsSet = FALSE;
+
+   mutex_init(&ofp->handleMutex, NULL, MUTEX_DRIVER, NULL);
+   mutex_init(&ofp->handleMutex, NULL, MUTEX_DRIVER, NULL);
+
+   /*
+    * Now we get a reference to the underlying per-file state.
+    */
+   ofp->hgfsFile = HgfsGetFile(fileName, fileType, htp);
+   if (!ofp->hgfsFile) {
+      kmem_free(ofp, sizeof *ofp);
+      return NULL;
+   }
+
+   return ofp;
+
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsFreeOpenFile --
+ *
+ *    Frees the provided open file.
+ *
+ * Results:
+ *    Returns 0 on success and a non-zero error code on failure.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+HgfsFreeOpenFile(HgfsOpenFile *ofp,             // IN: Open file to free
+                 HgfsFileHashTable *htp)        // IN: File hash table
+{
+   ASSERT(ofp);
+   ASSERT(htp);
+
+   /*
+    * First we release our reference to the underlying per-file state.
+    */
+   HgfsReleaseFile(ofp->hgfsFile, htp);
+
+   /*
+    * Then we destroy anything initialized and free the open file.
+    */
+   mutex_destroy(&ofp->handleMutex);
+   mutex_destroy(&ofp->modeMutex);
+
+   kmem_free(ofp, sizeof *ofp);
+}
+
+
+/* Acquiring/releasing file state */
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsGetFile --
+ *
+ *    Gets the file for the provided filename.
+ *
+ *    If no file structure exists for this filename, one is created and added
+ *    to the hash table.
+ *
+ * Results:
+ *    Returns a pointer to the file on success, NULL on error.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static HgfsFile *
+HgfsGetFile(const char *fileName,       // IN: Filename to get file for
+            HgfsFileType fileType,      // IN: Type of file
+            HgfsFileHashTable *htp)     // IN: Hash table to look in
+{
+   HgfsFile *fp;
+   int err;
+
+   ASSERT(fileName);
+   ASSERT(htp);
+
+   /*
+    * We try to find the file in the hash table.  If it exists we increment its
+    * reference count and return it.
+    */
+   mutex_enter(&htp->mutex);
+
+   fp = HgfsFindFile(fileName, htp);
+   if (fp) {
+      /* Signify our reference to this file. */
+      mutex_enter(&fp->mutex);
+      fp->refCount++;
+      mutex_exit(&fp->mutex);
+
+      mutex_exit(&htp->mutex);
+      return fp;
+   }
+
+   DEBUG(VM_DEBUG_ALWAYS, "HgfsGetFile: allocated HgfsFile for %s.\n", fileName);
+
+   /*
+    * If it doesn't exist we create one, initialize it, and add it to the hash
+    * table.
+    */
+   fp = (HgfsFile *)kmem_zalloc(sizeof *fp, HGFS_ALLOC_FLAG);
+#  if HGFS_ALLOC_FLAG != KM_SLEEP
+   if (!fp) {
+      /* fp is NULL already */
+      goto out;
+   }
+#  endif
+
+   err = HgfsInitFile(fp, fileName, fileType);
+   if (err) {
+      kmem_free(fp, sizeof *fp);
+      fp = NULL;
+      goto out;
+   }
+
+   /*
+    * This is guaranteed to not add a duplicate since we checked above and have
+    * held the lock until now.
+    */
+   HgfsAddFile(fp, htp);
+
+out:
+   mutex_exit(&htp->mutex);
+   DEBUG(VM_DEBUG_DONE, "HgfsGetFile: done\n");
+   return fp;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsReleaseFile --
+ *
+ *    Releases a reference to the provided file.  If the reference count of
+ *    this file becomes zero, the file structure is removed from the hash table
+ *    and freed.
+ *
+ * Results:
+ *    Returns 0 on success and a non-zero error code on failure.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+HgfsReleaseFile(HgfsFile *fp,           // IN: File to release
+                HgfsFileHashTable *htp) // IN: Hash table to look in/remove from
+{
+   ASSERT(fp);
+   ASSERT(htp);
+
+   /*
+    * Decrement this file's reference count.  If it becomes zero, then we
+    * remove it from the hash table and free it.
+    */
+   mutex_enter(&fp->mutex);
+
+   if ( !(--fp->refCount) ) {
+      mutex_exit(&fp->mutex);
+
+      /* Remove file from hash table, then clean up. */
+      HgfsRemoveFile(fp, htp);
+
+      DEBUG(VM_DEBUG_ALWAYS, "HgfsReleaseFile: freeing HgfsFile for %s.\n",
+            fp->fileName);
+
+      rw_destroy(&fp->rwlock);
+      mutex_destroy(&fp->mutex);
+      kmem_free(fp, sizeof *fp);
+      return;
+   }
+
+   DEBUG(VM_DEBUG_ALWAYS, "HgfsReleaseFile: %s has %d references.\n",
+         fp->fileName, fp->refCount);
+
+   mutex_exit(&fp->mutex);
+}
+
+
+/* Allocation/initialization/free of file state */
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsInitFile --
+ *
+ *    Initializes a file structure.
+ *
+ *    This sets the filename of the file and initializes other structure
+ *    elements.
+ *
+ * Results:
+ *    Returns 0 on success and a non-zero error code on failure.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+HgfsInitFile(HgfsFile *fp,              // IN: File to initialize
+             const char *fileName,      // IN: Name of file
+             HgfsFileType fileType)     // IN: Type of file
+{
+   int len;
+
+   ASSERT(fp);
+   ASSERT(fileName);
+
+   /* Make sure the filename will fit. */
+   len = strlen(fileName);
+   if (len > sizeof fp->fileName - 1) {
+      return HGFS_ERR;
+   }
+
+   fp->fileNameLength = len;
+   memcpy(fp->fileName, fileName, len + 1);
+   fp->fileName[fp->fileNameLength] = '\0';
+
+   /*
+    * We save the file type so we can recreate a vnode for the HgfsFile without
+    * sending a request to the Hgfs Server.
+    */
+   fp->fileType = fileType;
+
+   /* Initialize the links to place this file in our hash table. */
+   DblLnkLst_Init(&fp->listNode);
+
+   /*
+    * Fill in the node id.  This serves as the inode number in directory
+    * entries and the node id in vnode attributes.
+    */
+   HgfsNodeIdHash(fp->fileName, fp->fileNameLength, &fp->nodeId);
+
+   /*
+    * The reader/write lock is for the rwlock/rwunlock vnode entry points and
+    * the mutex is to protect the reference count on this structure.
+    */
+   rw_init(&fp->rwlock, NULL, RW_DRIVER, NULL);
+   mutex_init(&fp->mutex, NULL, MUTEX_DRIVER, NULL);
+
+   /* The caller is the single reference. */
+   fp->refCount = 1;
+
+   return 0;
+}
+
+
+/* Adding/finding/removing file state from hash table */
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsAddFile --
+ *
+ *    Adds the file to the hash table.
+ *
+ *    This function must be called with the hash table lock held.  This is done
+ *    so adding the file in the hash table can be made with any other
+ *    operations (such as previously finding out that this file wasn't in the
+ *    hash table).
+ *
+ * Results:
+ *    Returns 0 on success and a non-zero error code on failure.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static inline void
+HgfsAddFile(HgfsFile *fp,               // IN: File to add
+            HgfsFileHashTable *htp)     // IN: Hash table to add to
+{
+   unsigned int index;
+
+   ASSERT(fp);
+   ASSERT(htp);
+
+   index = HgfsFileNameHash(fp->fileName);
+
+   /* Add this file to the end of the bucket's list */
+   DblLnkLst_LinkLast(HGFS_FILE_HT_HEAD(htp, index), &fp->listNode);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsRemoveFile --
+ *
+ *    Removes file from the hash table.
+ *
+ *    Note that unlike the other two hash functions, this one performs its own
+ *    locking since the removal doesn't need to be atomic with other
+ *    operations.  (This could change in the future if the functions that use
+ *    this one are reorganized.)
+ *
+ * Results:
+ *    Returns 0 on success and a non-zero error code on failure.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static inline void
+HgfsRemoveFile(HgfsFile *fp,            // IN: File to remove
+               HgfsFileHashTable *htp)  // IN: Hash table to remove from
+{
+   ASSERT(fp);
+   ASSERT(htp);
+
+   mutex_enter(&htp->mutex);
+
+   /* Take this file off its list */
+   DblLnkLst_Unlink1(&fp->listNode);
+
+   mutex_exit(&htp->mutex);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsFindFile --
+ *
+ *    Looks for a filename in the hash table.
+ *
+ *    This function must be called with the hash table lock held.  This is done
+ *    so finding the file in the hash table and using it (after this function
+ *    returns) can be atomic.
+ *
+ * Results:
+ *    Returns a pointer to the file if found, NULL otherwise.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static HgfsFile *
+HgfsFindFile(const char *fileName,      // IN: Filename to look for
+             HgfsFileHashTable *htp)    // IN: Hash table to look in
+{
+   HgfsFile *found = NULL;
+   DblLnkLst_Links *currNode;
+   unsigned int index;
+
+   ASSERT(fileName);
+   ASSERT(htp);
+
+   /* Determine which bucket. */
+   index = HgfsFileNameHash(fileName);
+
+   /* Traverse the bucket's list. */
+   for (currNode = HGFS_FILE_HT_HEAD(htp, index);
+        currNode != HGFS_FILE_HT_BUCKET(htp, index);
+        currNode = currNode->next) {
+      HgfsFile *curr;
+      curr = DblLnkLst_Container(currNode, HgfsFile, listNode);
+
+      if (strcmp(curr->fileName, fileName) == 0) {
+         /* We found the file we want. */
+         found = curr;
+         break;
+      }
+   }
+
+   /* Return file if found. */
+   return found;
+}
+
+
+/* Other utility functions */
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsFileNameHash --
+ *
+ *    Hashes the filename to get an index into the hash table.  This is known
+ *    as the PJW string hash function and it was taken from "Mastering
+ *    Algorithms in C".
+ *
+ * Results:
+ *    Returns an index between 0 and HGFS_HT_NR_BUCKETS.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static unsigned int
+HgfsFileNameHash(const char *fileName)  // IN: Filename to hash
+{
+   unsigned int val = 0;
+
+   ASSERT(fileName);
+
+   while (*fileName != '\0') {
+      unsigned int tmp;
+
+      val = (val << 4) + (*fileName);
+      if ((tmp = (val & 0xf0000000))) {
+        val = val ^ (tmp >> 24);
+        val = val ^ tmp;
+      }
+
+      fileName++;
+   }
+
+   return val % HGFS_HT_NR_BUCKETS;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsNodeIdHash --
+ *
+ *    Hashes the provided filename to generate a node id.
+ *
+ * Results:
+ *    None.  The value of the hash is filled into outHash.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+HgfsNodeIdHash(const char *fileName,    // IN:  Filename to hash
+               uint32_t fileNameLength, // IN:  Length of the filename
+               ino64_t *outHash)   // OUT: Location to write hash to
+{
+   SHA1_CTX hashContext;
+   unsigned char digest[SHA1_HASH_LEN];
+   int i;
+
+   ASSERT(fileName);
+   ASSERT(outHash);
+
+   /* Make sure we start at a consistent state. */
+   memset(&hashContext, 0, sizeof hashContext);
+   memset(digest, 0, sizeof digest);
+   memset(outHash, 0, sizeof *outHash);
+
+   /* Generate a SHA1 hash of the filename */
+   SHA1Init(&hashContext);
+   SHA1Update(&hashContext, (unsigned char *)fileName, fileNameLength);
+   SHA1Final(digest, &hashContext);
+
+   /*
+    * Fold the digest into the allowable size of our hash.
+    *
+    * For each group of bytes the same size as our output hash, xor the
+    * contents of the digest together.  If there are less than that many bytes
+    * left in the digest, xor each byte that's left.
+    */
+   for(i = 0; i < sizeof digest; i += sizeof *outHash) {
+      int bytesLeft = sizeof digest - i;
+
+      /* Do a byte-by-byte xor if there aren't enough bytes left in the digest */
+      if (bytesLeft < sizeof *outHash) {
+         int j;
+
+         for (j = 0; j < bytesLeft; j++) {
+            uint8 *outByte = (uint8 *)outHash + j;
+            uint8 *inByte = (uint8 *)((u_longlong_t *)(digest + i)) + j;
+            *outByte ^= *inByte;
+         }
+         break;
+      }
+
+      /* Block xor */
+      *outHash ^= *((u_longlong_t *)(digest + i));
+   }
+
+   /*
+    * Clear the most significant byte so that user space apps depending on
+    * a node id/inode number that's only 32 bits won't break.  (For example,
+    * gedit's call to stat(2) returns EOVERFLOW if we don't do this.)
+    */
+#  ifndef HGFS_BREAK_32BIT_USER_APPS
+   *((uint32_t *)outHash) ^= *((uint32_t *)outHash + 1);
+   *((uint32_t *)outHash + 1) = 0;
+#  endif
+
+   DEBUG(VM_DEBUG_INFO, "Hash of: %s (%d) is %"FMT64"u\n", fileName, fileNameLength, *outHash);
+
+   return;
+}
diff --git a/open-vm-tools/modules/solaris/vmhgfs/hgfsState.h b/open-vm-tools/modules/solaris/vmhgfs/hgfsState.h
new file mode 100644 (file)
index 0000000..337e7e4
--- /dev/null
@@ -0,0 +1,192 @@
+/*********************************************************
+ * Copyright (C) 2004 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * hgfsState.h --
+ *
+ * Public functions, types, and macros for Hgfs state that is attached to
+ * vnodes.
+ */
+
+#ifndef __HGFS_STATE_H_
+#define __HGFS_STATE_H_
+
+/*
+ * Includes
+ */
+#include <sys/param.h>          /* MAXPATHLEN */
+#include <sys/rwlock.h>         /* krwlock_t */
+#include <sys/ksynch.h>         /* kmutex_t */
+#include <sys/vnode.h>          /* struct vnode */
+
+#include "hgfsProto.h"
+#include "dbllnklst.h"
+
+
+/*
+ * Macros
+ */
+/* Number of buckets for the HgfsInode hash table */
+#define HGFS_HT_NR_BUCKETS             5
+
+/* Conversion between different state structures */
+#define HGFS_VP_TO_OFP(vp)      ((HgfsOpenFile *)(vp)->v_data)
+#define HGFS_VP_TO_FP(vp)       ((HgfsFile *)(HGFS_VP_TO_OFP(vp))->hgfsFile)
+#define HGFS_OFP_TO_VP(ofp)     (ofp)->vnodep
+
+#define HGFS_VP_TO_FILENAME(vp)                         \
+         HGFS_VP_TO_FP(vp)->fileName
+
+#define HGFS_VP_TO_FILENAME_LENGTH(vp)                  \
+         HGFS_VP_TO_FP(vp)->fileNameLength
+
+#define HGFS_VP_TO_NODEID(vp)                           \
+         HGFS_VP_TO_FP(vp)->nodeId
+
+#define HGFS_VP_TO_RWLOCK(vp)                           \
+         HGFS_VP_TO_FP(vp)->rwlock
+
+#define HGFS_VP_TO_RWLOCKP(vp)  &(HGFS_VP_TO_RWLOCK(vp))
+
+#define HGFS_VP_TO_HGFSFILETYPE(vp)                     \
+         HGFS_VP_TO_FP(vp)->fileType
+
+/*
+ * This macro is used for sanity checking the fact that Solaris won't ever call
+ * one of our vnode operations without first calling lookup(), which is the
+ * place where we acquire the filename.  I have never seen a function fail
+ * because of this, so it is likely that we can kill this macro and the checks
+ * on it throughout vnode.c.
+ */
+#define HGFS_KNOW_FILENAME(vp)                          \
+         (                                              \
+          vp &&                                         \
+          HGFS_VP_TO_FP(vp) &&                          \
+          HGFS_VP_TO_FP(vp)->fileName[0] != '\0'        \
+         )
+
+/*
+ * Types
+ */
+
+typedef uint32_t HgfsMode;
+
+/*
+ * State kept per shared file from the host.
+ *
+ * All fields are read-only after initialization except reference count, which
+ * is protected by the mutex.
+ */
+typedef struct HgfsFile {
+   /* Link to place this state on the file state hash table */
+   DblLnkLst_Links listNode;
+   /*
+    * Full path of file within the filesystem (that is, taking /mnt/hgfs as /).
+    * These are built from / in HgfsMount() and appending names as provided to
+    * HgfsLookup(). Saving the length in HgfsIget() saves having to calculate
+    * it in each HgfsMakeFullName().
+    */
+   char fileName[MAXPATHLEN + 1];
+   uint32_t fileNameLength;
+   ino64_t nodeId;
+   /*
+    * The file type is saved so additional per-open-file vnodes can be
+    * recreated from a Hgfs file without sending a request to the Hgfs server.
+    */
+   HgfsFileType fileType;
+   /*
+    * Readers/writers lock for this file.  Needed by rwlock() and rwunlock()
+    * entry points.
+    */
+   krwlock_t rwlock;
+   /* Lock to protect the reference count of this file state. */
+   kmutex_t mutex;
+   uint32_t refCount;
+} HgfsFile;
+
+
+/*
+ * State kept per vnode, which implies per open file within a process.
+ *
+ * Once created, the hgfsFile and vnode/vnodep values are read-only.  The
+ * handle and mode will change throughout this structure's existence, and are
+ * both protected by their own mutex.
+ */
+typedef struct HgfsOpenFile {
+   /* Handle provided by reply to a request */
+   HgfsHandle handle;
+   Bool handleIsSet;
+   kmutex_t handleMutex;
+   /*
+    * Mode specified for this file to be created with.  This is necessary
+    * because create is called with the mode then open is called without it.
+    * We save this value in create and access it in open.
+    */
+   HgfsMode mode;
+   Bool modeIsSet;
+   kmutex_t modeMutex;
+   /*
+    * Pointer to the single Hgfs file state structure shared amongst all open
+    * instances of this file.
+    */
+   HgfsFile *hgfsFile;
+   /*
+    * A pointer back to the vnode this open-file state is for.
+    */
+   struct vnode *vnodep;
+} HgfsOpenFile;
+
+/* The hash table for file state. */
+typedef struct HgfsFileHashTable {
+   kmutex_t mutex;
+   DblLnkLst_Links hashTable[HGFS_HT_NR_BUCKETS];
+} HgfsFileHashTable;
+
+/* Forward declaration to prevent circular dependency between this and hgfs.h. */
+struct HgfsSuperInfo;
+
+
+/*
+ * Functions
+ */
+int HgfsVnodeGet(struct vnode **vpp, struct HgfsSuperInfo *sip, struct vfs *vfsp,
+                 const char *fileName, HgfsFileType fileType, HgfsFileHashTable *htp);
+int HgfsVnodePut(struct vnode *vp, HgfsFileHashTable *ht);
+int HgfsVnodeDup(struct vnode **newVpp, struct vnode *origVp, struct HgfsSuperInfo *sip,
+                 HgfsFileHashTable *htp);
+int HgfsFileNameToVnode(const char *fileName, struct vnode **vpp,
+                        struct HgfsSuperInfo *sip, struct vfs *vfsp,
+                        HgfsFileHashTable *htp);
+void HgfsNodeIdGet(HgfsFileHashTable *ht, const char *fileName,
+                   uint32_t fileNameLength, ino64_t *outNodeId);
+int HgfsInitFileHashTable(HgfsFileHashTable *htp);
+Bool HgfsFileHashTableIsEmpty(struct HgfsSuperInfo *sip, HgfsFileHashTable *htp);
+
+/* Handle get/set/clear functions */
+int HgfsSetOpenFileHandle(struct vnode *vp, HgfsHandle handle);
+int HgfsGetOpenFileHandle(struct vnode *vp, HgfsHandle *outHandle);
+int HgfsClearOpenFileHandle(struct vnode *vp);
+Bool HgfsHandleIsSet(struct vnode *vp);
+
+/* Mode get/set/clear functions */
+int HgfsSetOpenFileMode(struct vnode *vp, HgfsMode mode);
+int HgfsGetOpenFileMode(struct vnode *vp, HgfsMode *outMode);
+int HgfsClearOpenFileMode(struct vnode *vp);
+
+/* Debugging function */
+void HgfsDebugPrintFileHashTable(HgfsFileHashTable *htp, int level);
+
+#endif /* __HGFS_STATE_H_ */
diff --git a/open-vm-tools/modules/solaris/vmhgfs/hgfsUtil.c b/open-vm-tools/modules/solaris/vmhgfs/hgfsUtil.c
new file mode 100644 (file)
index 0000000..b9e395c
--- /dev/null
@@ -0,0 +1,263 @@
+/*********************************************************
+ * Copyright (C) 1998 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * hgfsUtil.c --
+ *
+ *    Utility routines used by both HGFS servers and clients, such as
+ *    conversion routines between Unix time and Windows NT time.
+ *    The former is in units of seconds since midnight 1/1/1970, while the
+ *    latter is in units of 100 nanoseconds since midnight 1/1/1601.
+ */
+
+/*
+ * hgfsUtil.h must be included before vm_basic_asm.h, as hgfsUtil.h
+ * includes kernel headers on Linux.  That is, vmware.h must come after
+ * hgfsUtil.h.
+ */
+#include "hgfsUtil.h"
+#include "vmware.h"
+#include "vm_basic_asm.h"
+
+#ifndef _WIN32
+/*
+ * NT time of the Unix epoch:
+ * midnight January 1, 1970 UTC
+ */
+#define UNIX_EPOCH ((((uint64)369 * 365) + 89) * 24 * 3600 * 10000000)
+
+/*
+ * NT time of the Unix 32 bit signed time_t wraparound:
+ * 03:14:07 January 19, 2038 UTC
+ */
+#define UNIX_S32_MAX (UNIX_EPOCH + (uint64)0x80000000 * 10000000)
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsConvertToNtTime --
+ *
+ *    Convert from Unix time to Windows NT time.
+ *
+ * Results:
+ *    The time in Windows NT format.
+ *
+ * Side effects:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+uint64
+HgfsConvertToNtTime(time_t unixTime, // IN: Time in Unix format (seconds)
+                   long   nsec)     // IN: nanoseconds
+{
+   return (uint64)unixTime * 10000000 + nsec / 100 + UNIX_EPOCH;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsConvertFromNtTimeNsec --
+ *
+ *    Convert from Windows NT time to Unix time. If NT time is outside of
+ *    UNIX time range (1970-2038), returned time is nearest time valid in
+ *    UNIX.
+ *
+ * Results:
+ *    0        on success
+ *    non-zero if NT time is outside of valid range for UNIX
+ *
+ * Side effects:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+HgfsConvertFromNtTimeNsec(struct timespec *unixTime, // OUT: Time in UNIX format
+                         uint64 ntTime) // IN: Time in Windows NT format
+{
+#ifndef VM_X86_64
+   uint32 sec;
+   uint32 nsec;
+
+   ASSERT(unixTime);
+   /* We assume that time_t is 32bit */
+   ASSERT_ON_COMPILE(sizeof (unixTime->tv_sec) == 4);
+
+   /* Cap NT time values that are outside of Unix time's range */
+
+   if (ntTime >= UNIX_S32_MAX) {
+      unixTime->tv_sec = 0x7FFFFFFF;
+      unixTime->tv_nsec = 0;
+      return 1;
+   }
+#else
+   ASSERT(unixTime);
+#endif
+
+   if (ntTime < UNIX_EPOCH) {
+      unixTime->tv_sec = 0;
+      unixTime->tv_nsec = 0;
+      return -1;
+   }
+
+#ifndef VM_X86_64
+   Div643232(ntTime - UNIX_EPOCH, 10000000, &sec, &nsec);
+   unixTime->tv_sec = sec;
+   unixTime->tv_nsec = nsec * 100;
+#else
+   unixTime->tv_sec = (ntTime - UNIX_EPOCH) / 10000000;
+   unixTime->tv_nsec = ((ntTime - UNIX_EPOCH) % 10000000) * 100;
+#endif
+
+   return 0;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsConvertFromNtTime --
+ *
+ *    Convert from Windows NT time to Unix time.
+ *
+ * Results:
+ *    0       on success
+ *    nonzero if time is not representable on UNIX
+ *
+ * Side effects:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+HgfsConvertFromNtTime(time_t *unixTime, // OUT: Time in UNIX format
+                     uint64 ntTime) // IN: Time in Windows NT format
+{
+   struct timespec tm;
+   int ret;
+
+   ret = HgfsConvertFromNtTimeNsec(&tm, ntTime);
+   *unixTime = tm.tv_sec;
+   return ret;
+}
+#endif /* !def(_WIN32) */
+
+
+#undef UNIX_EPOCH
+#undef UNIX_S32_MAX
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsConvertFromInternalStatus --
+ *
+ *    This function converts between a platform-specific status code and a
+ *    cross-platform status code to be sent down the wire.
+ *
+ * Results:
+ *    Converted status code.
+ *
+ * Side effects:
+ *    None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+#ifdef _WIN32
+HgfsStatus
+HgfsConvertFromInternalStatus(HgfsInternalStatus status) // IN
+{
+   switch(status) {
+   case ERROR_SUCCESS:
+      return HGFS_STATUS_SUCCESS;
+   case ERROR_FILE_NOT_FOUND:
+   case ERROR_PATH_NOT_FOUND:
+      return HGFS_STATUS_NO_SUCH_FILE_OR_DIR;
+   case ERROR_INVALID_HANDLE:
+      return HGFS_STATUS_INVALID_HANDLE;
+   case ERROR_ALREADY_EXISTS:
+   case ERROR_FILE_EXISTS:
+      return HGFS_STATUS_FILE_EXISTS;
+   case ERROR_DIR_NOT_EMPTY:
+      return HGFS_STATUS_DIR_NOT_EMPTY;
+   case RPC_S_PROTOCOL_ERROR:
+      return HGFS_STATUS_PROTOCOL_ERROR;
+   case ERROR_ACCESS_DENIED:
+      return HGFS_STATUS_ACCESS_DENIED;
+   case ERROR_INVALID_NAME:
+      return HGFS_STATUS_INVALID_NAME;
+   case ERROR_SHARING_VIOLATION:
+      return HGFS_STATUS_SHARING_VIOLATION;
+   case ERROR_DISK_FULL:
+   case ERROR_HANDLE_DISK_FULL:
+      return HGFS_STATUS_NO_SPACE;
+   case ERROR_NOT_SUPPORTED:
+      return HGFS_STATUS_OPERATION_NOT_SUPPORTED;
+   case ERROR_INVALID_PARAMETER:
+      return HGFS_STATUS_INVALID_PARAMETER;
+   case HGFS_INTERNAL_STATUS_ERROR:
+   default:
+      return HGFS_STATUS_GENERIC_ERROR;
+   }
+}
+
+#else /* Win32 */
+
+HgfsStatus
+HgfsConvertFromInternalStatus(HgfsInternalStatus status) // IN
+{
+   switch(status) {
+   case 0:
+      return HGFS_STATUS_SUCCESS;
+   case ENOENT:
+      return HGFS_STATUS_NO_SUCH_FILE_OR_DIR;
+   case EBADF:
+      return HGFS_STATUS_INVALID_HANDLE;
+   case EPERM:
+      return HGFS_STATUS_OPERATION_NOT_PERMITTED;
+   case EEXIST:
+      return HGFS_STATUS_FILE_EXISTS;
+   case ENOTDIR:
+      return HGFS_STATUS_NOT_DIRECTORY;
+   case ENOTEMPTY:
+      return HGFS_STATUS_DIR_NOT_EMPTY;
+   case EPROTO:
+      return HGFS_STATUS_PROTOCOL_ERROR;
+   case EACCES:
+      return HGFS_STATUS_ACCESS_DENIED;
+   case EINVAL:
+      return HGFS_STATUS_INVALID_NAME;
+   case ENOSPC:
+      return HGFS_STATUS_NO_SPACE;
+   case EOPNOTSUPP:
+      return HGFS_STATUS_OPERATION_NOT_SUPPORTED;
+   case ENAMETOOLONG:
+      return HGFS_STATUS_NAME_TOO_LONG;
+   case EPARAMETERNOTSUPPORTED:
+      return HGFS_STATUS_INVALID_PARAMETER;
+   case HGFS_INTERNAL_STATUS_ERROR:
+   default:
+      return HGFS_STATUS_GENERIC_ERROR;
+   }
+}
+#endif
diff --git a/open-vm-tools/modules/solaris/vmhgfs/hgfsUtil.h b/open-vm-tools/modules/solaris/vmhgfs/hgfsUtil.h
new file mode 100644 (file)
index 0000000..c60040c
--- /dev/null
@@ -0,0 +1,128 @@
+/*********************************************************
+ * Copyright (C) 1998 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+
+/*
+ * hgfsUtil.h --
+ *
+ *    Utility functions and macros used by hgfs.
+ */
+
+
+#ifndef _HGFSUTIL_H_
+#   define _HGFSUTIL_H_
+
+#   if defined(__linux__) && defined(__KERNEL__)
+#      include "driver-config.h"
+#      include <linux/time.h> // for time_t and timespec
+    /* Include time.h in userspace code, but not in Solaris kernel code. */
+#   elif defined(__FreeBSD__) && defined(_KERNEL)
+    /* Do nothing. */
+#   elif defined(__APPLE__) && defined(KERNEL)
+#      include <sys/time.h>
+#   else
+#      include <time.h>
+#   endif
+#   include "vm_basic_types.h"
+#   if !defined(_STRUCT_TIMESPEC) &&   \
+       !defined(_TIMESPEC_DECLARED) && \
+       !defined(__timespec_defined) && \
+       !defined(sun) && \
+       !defined(__FreeBSD__) && \
+       !__APPLE__ && \
+       !defined(_WIN32)
+struct timespec {
+   time_t tv_sec;
+   long   tv_nsec;
+};
+#   endif
+
+#   include "hgfs.h"
+
+/* Cross-platform representation of a platform-specific error code. */
+#ifndef _WIN32
+#   if defined(__KERNEL__) || defined(_KERNEL) || defined(KERNEL)
+#      if defined(__linux__)
+#         include <linux/errno.h>
+#      elif defined(sun) || defined(__FreeBSD__) || defined(__APPLE__)
+#         include <sys/errno.h>
+#      endif
+#   else
+#      include <errno.h>
+#   endif
+    typedef int HgfsInternalStatus;
+#else
+#   include <windows.h>
+    typedef DWORD HgfsInternalStatus;
+#endif
+
+/*
+ * Unfortunately, we need a catch-all "generic error" to use with
+ * HgfsInternalStatus, because there are times when cross-platform code needs
+ * to return its own errors along with errors from platform specific code.
+ *
+ * Using -1 should be safe because we expect our platforms to use zero as
+ * success and a positive range of numbers as error values.
+ */
+#define HGFS_INTERNAL_STATUS_ERROR (-1)
+
+#ifndef _WIN32
+/*
+ * This error code is used to notify the client that some of the parameters passed
+ * (e.g. file handles) are not supported. Clients are expected to correct
+ * the parameter (e.g. pass file name instead) and retry.
+ *
+ * Note that this error code is artificially made up and in future may conflict
+ * with an "official" error code when added.
+ */
+#define EPARAMETERNOTSUPPORTED  (MAX_INT32 - 1)
+#endif
+
+/*
+ * FreeBSD (pre-6.0) does not define EPROTO, so we'll define our own error code.
+ */
+#if defined(__FreeBSD__) && !defined(EPROTO)
+#define EPROTO (ELAST + 1)
+#endif
+
+#define HGFS_NAME_BUFFER_SIZE(request) (HGFS_PACKET_MAX - (sizeof *request - 1))
+#define HGFS_NAME_BUFFER_SIZET(sizet) (HGFS_PACKET_MAX - ((sizet) - 1))
+
+#ifndef _WIN32
+/*
+ * Routines for converting between Win NT and unix time formats. The
+ * hgfs attributes use the NT time formats, so the linux driver and
+ * server have to convert back and forth. [bac]
+ */
+
+uint64 HgfsConvertToNtTime(time_t unixTime, // IN
+                          long   nsec);    // IN
+static INLINE uint64
+HgfsConvertTimeSpecToNtTime(const struct timespec *unixTime) // IN
+{
+   return HgfsConvertToNtTime(unixTime->tv_sec, unixTime->tv_nsec);
+}
+
+int HgfsConvertFromNtTime(time_t * unixTime, // OUT
+                         uint64 ntTime);    // IN
+int HgfsConvertFromNtTimeNsec(struct timespec *unixTime, // OUT
+                              uint64 ntTime);            // IN
+#endif /* !def(_WIN32) */
+
+HgfsStatus HgfsConvertFromInternalStatus(HgfsInternalStatus status); // IN
+
+#endif /* _HGFSUTIL_H_ */
+
diff --git a/open-vm-tools/modules/solaris/vmhgfs/includeCheck.h b/open-vm-tools/modules/solaris/vmhgfs/includeCheck.h
new file mode 100644 (file)
index 0000000..3da2e00
--- /dev/null
@@ -0,0 +1,130 @@
+/*********************************************************
+ * Copyright (C) 1998 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * includeCheck.h --
+ *
+ *     Restrict include file use.
+ *
+ * In every .h file, define one or more of these
+ *
+ *     INCLUDE_ALLOW_VMX 
+ *     INCLUDE_ALLOW_USERLEVEL 
+ *     INCLUDE_ALLOW_VMMEXT
+ *     INCLUDE_ALLOW_VMCORE
+ *     INCLUDE_ALLOW_MODULE
+ *      INCLUDE_ALLOW_VMNIXMOD 
+ *     INCLUDE_ALLOW_VMKERNEL 
+ *     INCLUDE_ALLOW_DISTRIBUTE
+ *     INCLUDE_ALLOW_VMK_MODULE
+ *      INCLUDE_ALLOW_VMKDRIVERS
+ *      INCLUDE_ALLOW_VMIROM
+ *
+ * Then include this file.
+ *
+ * Any file that has INCLUDE_ALLOW_DISTRIBUTE defined will potentially
+ * be distributed in source form along with GPLed code.  Ensure
+ * that this is acceptable.
+ */
+
+
+/*
+ * Declare a VMCORE-only variable to help classify object
+ * files.  The variable goes in the common block and does
+ * not create multiple definition link-time conflicts.
+ */
+
+#if defined VMCORE && defined VMX86_DEVEL && defined VMX86_DEBUG && \
+    defined linux && !defined MODULE && \
+    !defined COMPILED_WITH_VMCORE
+#define COMPILED_WITH_VMCORE compiled_with_vmcore
+#ifdef ASM
+        .comm   compiled_with_vmcore, 0
+#else
+        asm(".comm compiled_with_vmcore, 0");
+#endif /* ASM */
+#endif
+
+
+#if defined VMCORE && \
+    !(defined VMX86_VMX || defined VMM || \
+      defined MONITOR_APP || defined VMMON)
+#error "Makefile problem: VMCORE without VMX86_VMX or \
+        VMM or MONITOR_APP or MODULE."
+#endif
+
+#if defined VMCORE && !defined INCLUDE_ALLOW_VMCORE
+#error "The surrounding include file is not allowed in vmcore."
+#endif
+#undef INCLUDE_ALLOW_VMCORE
+
+#if defined VMX86_VMX && !defined VMCORE && \
+    !(defined INCLUDE_ALLOW_VMX || defined INCLUDE_ALLOW_USERLEVEL)
+#error "The surrounding include file is not allowed in the VMX."
+#endif
+#undef INCLUDE_ALLOW_VMX
+
+#if defined USERLEVEL && !defined VMX86_VMX && !defined VMCORE && \
+    !defined INCLUDE_ALLOW_USERLEVEL
+#error "The surrounding include file is not allowed at userlevel."
+#endif
+#undef INCLUDE_ALLOW_USERLEVEL
+
+#if defined VMM && !defined VMCORE && \
+    !defined INCLUDE_ALLOW_VMMEXT
+#error "The surrounding include file is not allowed in the monitor."
+#endif
+#undef INCLUDE_ALLOW_VMMEXT
+
+#if defined MODULE && !defined VMKERNEL_MODULE && !defined VMNIXMOD && \
+    !defined VMMON && !defined INCLUDE_ALLOW_MODULE
+#error "The surrounding include file is not allowed in driver modules."
+#endif
+#undef INCLUDE_ALLOW_MODULE
+
+#if defined VMMON && !defined INCLUDE_ALLOW_VMMON
+#error "The surrounding include file is not allowed in vmmon."
+#endif
+#undef INCLUDE_ALLOW_VMMON
+
+#if defined VMKERNEL && !defined INCLUDE_ALLOW_VMKERNEL
+#error "The surrounding include file is not allowed in the vmkernel."
+#endif
+#undef INCLUDE_ALLOW_VMKERNEL
+
+#if defined GPLED_CODE && !defined INCLUDE_ALLOW_DISTRIBUTE
+#error "The surrounding include file is not allowed in GPL code."
+#endif
+#undef INCLUDE_ALLOW_DISTRIBUTE
+
+#if defined VMKERNEL_MODULE && !defined VMKERNEL && \
+    !defined INCLUDE_ALLOW_VMK_MODULE && !defined INCLUDE_ALLOW_VMKDRIVERS
+#error "The surrounding include file is not allowed in vmkernel modules."
+#endif
+#undef INCLUDE_ALLOW_VMK_MODULE
+#undef INCLUDE_ALLOW_VMKDRIVERS
+
+#if defined VMNIXMOD && !defined INCLUDE_ALLOW_VMNIXMOD
+#ifndef VMNIXMOD_VM
+#error "The surrounding include file is not allowed in vmnixmod."
+#endif
+#endif
+#undef INCLUDE_ALLOW_VMNIXMOD
+
+#if defined VMIROM && ! defined INCLUDE_ALLOW_VMIROM
+#error "The surrounding include file is not allowed in vmirom."
+#endif
+#undef INCLUDE_ALLOW_VMIROM
diff --git a/open-vm-tools/modules/solaris/vmhgfs/module.c b/open-vm-tools/modules/solaris/vmhgfs/module.c
new file mode 100644 (file)
index 0000000..04dbd4b
--- /dev/null
@@ -0,0 +1,424 @@
+/*********************************************************
+ * Copyright (C) 2004 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * module.c --
+ *
+ *      Structures and modules for loading and unloading of the HGFS module.
+ *
+ */
+
+
+/*
+ * For reference: Solaris Structures
+ * =================================
+ *
+ * Driver module struct hierarchy:
+ * -------------------------------
+ *
+ * (Solaris 9 & 10)
+ *
+ *  modlinkage --> modldrv --> dev_ops --> cb_ops
+ *
+ *  - modlinkage & modldrv: module loading/unloading
+ *  - dev_ops: operations for driver configuration (attach(), detach(), etc)
+ *  - cb_ops: operations on device, entry points to character device (open(),
+ *            close(), etc)
+ *
+ *
+ * VFS module struct hierarchy:
+ * ----------------------------
+ *
+ * (Solaris 9)
+ *
+ * modlinkage --> modlfs --> mod_ops
+ *                       \
+ *                        -> vfssw --> vfsops
+ *                                 \
+ *                                  -> (*fs_init_routine)()
+ *
+ *
+ * modlfs: - points to module loading/unloading operations structure (mod_ops)
+ *         - points to VFS Switch strucutre (vfssw)
+ *         - contains extended name of filesystem
+ *
+ * mod_ops: - contains pointers to _init(), _fini(), and _info(), which handle
+ *            loading/unloading module into kernel and providing information
+ *
+ * vfssw: - points to filesystem initialization routine that is called once at
+ *          module load time (not mount time)
+ *        - points to vfsops struct that points to fs-specific operations
+ *        - contains name of fs (what you would put in /etc/vfstab)
+ *        - also contains fs mount options, flags, and mutex
+ *
+ * vfsops: - points to fs-level functions (mount(), umount(), etc.)
+ *
+ * (Solaris 10)
+ *
+ * modlinkage --> modlfs --> mod_ops
+ *                       \
+ *                        -> vfsdef_v2 --> (*init)()
+ *
+ * vfsdef_v2:  - this contains a pointer to an initialization routine for the
+ *               filesystem that takes different arguments
+ *             - we no longer provide an address to a vfsops; now we need to
+ *               call vfs_makevfsops() with a preconstructed array of
+ *               fs_operation_t that defines each vfs op.  This needs to occur
+ *               in the initialization routine.
+ *
+ * (Build 58 contains the same structure named vfsdev_v3)
+ *
+ *
+ * Combination:
+ * ------------
+ *
+ * In this file we are placing both modldrv and modlfs inside one modlinkage
+ * structure.  This is achieved by placing pointers to both of these structures
+ * in modlinkage's ml_linkage arary of pointers to module structures.  This is
+ * done so the two modules can have shared state and to prevent dependency
+ * issues between them. This looks like:
+ *
+ * modlinkage --> modldrv --> as above
+ *            \
+ *             -> modlfs --> as above
+ *
+ */
+
+#include "hgfsSolaris.h"
+#include "module.h"
+#include "debug.h"
+
+
+/*
+ * Macros
+ */
+#define HGFS_VFSSW_FLAGS        0
+
+
+/*
+ * Structures
+ */
+
+/*
+ * Device driver structures
+ */
+
+/* Structure defining operations on device */
+static struct cb_ops HgfsDevCBOps = {
+   HgfsDevOpen,         /* open(9E) */
+   HgfsDevClose,        /* close(9E) */
+   nodev,               /* strategy(9E) */
+   nodev,               /* print(9E) */
+   nodev,               /* dump(9E) */
+   HgfsDevRead,         /* read(9E) */
+   HgfsDevWrite,        /* write(9E) */
+   nodev,               /* ioctl(9E) */
+   nodev,               /* devmap(9E) */
+   nodev,               /* mmap(9E) */
+   nodev,               /* segmap(9E) */
+   HgfsDevChpoll,       /* chpoll(9E) */
+   ddi_prop_op,         /* prop_op(9E) */
+   NULL,                /* streamtab(9S) */
+   (D_NEW | D_MP),      /* cb_flag: D_NEW because this is a new-style
+                                    driver and D_MP is required */
+   CB_REV,              /* cb_rev */
+   nodev,               /* aread(9E) */
+   nodev,               /* awrite(9E) */
+};
+
+
+/* Structure defining operations for driver */
+static struct dev_ops HgfsDevOps = {
+   DEVO_REV,            /* devo_rev */
+   0,                   /* devo_refcnt */
+   HgfsDevGetinfo,      /* getinfo(9E) */
+   nulldev,             /* identify(9E) */
+   nulldev,             /* probe(9E) */
+   HgfsDevAttach,       /* attach(9E) */
+   HgfsDevDetach,       /* detach(9E) */
+   nodev,               /* devo_reset */
+   &HgfsDevCBOps,       /* devo_cb_ops (points to struct cb_ops) */
+   NULL,                /* devo_bus_ops */
+   NULL                 /* power(9E) */
+};
+
+
+/* Driver module linkage structure */
+static struct modldrv HgfsDevModldrv = {
+   &mod_driverops,                      /* drv_modops (don't change) */
+   "HGFS Device Interface",             /* drv_linkinfo */
+   &HgfsDevOps                          /* drv_dev_ops (points to struct dev_ops) */
+};
+
+
+
+/*
+ * Filesystem structures
+ */
+
+#if HGFS_VFS_VERSION == 2
+/* VFS Operations Structure */
+struct vfsops HgfsVfsOps = {
+   HgfsMount,           /* vfs_mount() */
+   HgfsUnmount,         /* vfs_unmount() */
+   HgfsRoot,            /* vfs_root() */
+   HgfsStatvfs,         /* vfs_statvfs() */
+   HgfsSync,            /* vfs_sync() */
+   HgfsVget,            /* vfs_vget() */
+   HgfsMountroot,       /* vfs_mountroot() */
+   HgfsReserved,        /* vfs_reserved() */
+   HgfsFreevfs          /* vfs_freevfs() */
+};
+
+
+/* VFS Switch structure */
+static struct vfssw HgfsVfsSw = {
+   HGFS_FS_NAME,        /* Name of filesystem */
+   HgfsInit,            /* Initialization routine */
+   &HgfsVfsOps,         /* VFS Operations struct */
+   HGFS_VFSSW_FLAGS,    /* Flags: see <sys/vfs.h> */
+   NULL,                /* Mount options table prototype */
+   1,                   /* Count of references */
+   { { 0 } }            /* Lock to protect count */
+};
+#else
+
+/*
+ * Different beta builds of Solaris have different versions of this structure.
+ * We currently don't support v4 which was out in intermediate beta builds of
+ * Solaris 11. Instead we choose to update to the latest revision. But if needed,
+ * v4 could be added without significant effort.
+ */
+#if HGFS_VFS_VERSION == 2
+static struct vfsdef_v2 HgfsVfsDef = {
+#elif HGFS_VFS_VERSION == 3
+static struct vfsdef_v3 HgfsVfsDef = {
+#else
+static struct vfsdef_v5 HgfsVfsDef = {
+#endif
+   VFSDEF_VERSION,      /* Structure version: defined in <sys/vfs.h> */
+   HGFS_FS_NAME,        /* Name of filesystem */
+   HgfsInit,            /* Initialization routine: note this is a different
+                         * routine than the one used in 9 */
+   HGFS_VFSSW_FLAGS,    /* Filesystem flags */
+   NULL                 /* No mount options */
+};
+
+#endif  /* Solaris version */
+
+
+/* Filesystem module structure */
+static struct modlfs HgfsModlfs = {
+   &mod_fsops,                  /* Module operation structure: for
+                                   auto loading/unloading */
+   "Host/Guest Filesystem",     /* Name */
+#if HGFS_VFS_VERSION== 2
+   &HgfsVfsSw                   /* VFS Switch structure */
+#else
+   &HgfsVfsDef                  /* Filesystem type definition record */
+#endif
+};
+
+
+/*
+ * Modlinkage shared by device driver and filesystem.
+ */
+static struct modlinkage HgfsModlinkage = {
+   MODREV_1,            /* Module revision: must be MODREV_1 */
+   /*
+    * We put pointers to /both/ modules in the following NULL terminated array
+    * of pointers (ml_linkage[]).  This is what causes both modules to be
+    * loaded into the kernel when the single driver is added.
+    */
+   {
+      &HgfsDevModldrv,  /* Driver module structure */
+      &HgfsModlfs,      /* FS module structure */
+      NULL,             /* NULL terminator */
+   }
+};
+
+
+/*
+ * Driver autoload functions
+ */
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * _init --
+ *    Invoked when module is being loaded into kernel, and is called before
+ *    any function in the module.  Any state that spans all instances of the
+ *    driver should be allocated and initialized here.
+ *
+ * Results:
+ *    Returns the result of mod_install(9F), which is zero on success and a
+ *    non-zero value on failure.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+_init(void)
+{
+   int ret;
+
+   DEBUG(VM_DEBUG_ENTRY, "_init() for HGFS.\n");
+
+   /*
+    * Initialize hgfsInstance so filesystem knows device has not been attached
+    * yet, and hgfsType so we know whether to free the vfsops in _fini().
+    */
+   hgfsInstance = HGFS_INSTANCE_UNINITIALIZED;
+   hgfsType = HGFS_TYPE_UNINITIALIZED;
+
+   /*
+    * For reference:
+    *
+    * Solaris provides an interface to simplify allocation and deallocation of
+    * per-driver-instance state through the DDI Soft State functions.
+    *
+    * - ddi_soft_state_init() takes a double pointer and uses it as a handle
+    *   to access the various per-instance state structures.  This handle will
+    *   be passed to the other DDI Soft State functions to indicate which
+    *   state list to operate on.  The second argument is the amount of memory
+    *   to allocate for each state structure, and the last is the expected number
+    *   of instances of the driver (number of state structures).
+    *
+    * - ddi_soft_state_zalloc() and ddi_soft_state_free() allocate and free a
+    *   soft state structure respectively.  The first argument is the
+    *   handle pointer (see above) and the second is the item number
+    *   associated with this instance.
+    *
+    * - ddi_get_soft_state_free() takes a handle and item and returns a
+    *   pointer to the state structure that was allocated with
+    *   ddi_soft_state_zalloc() for that item number.
+    *
+    *   See man ddi_soft_state_init for more information.
+    *
+    */
+   ret = ddi_soft_state_init(&superInfoHead,
+                             sizeof (HgfsSuperInfo), HGFS_EXPECTED_INSTANCES);
+   if (ret) {
+      goto error;
+   }
+
+   ret = mod_install(&HgfsModlinkage);
+   if (ret) {
+      goto error;
+   }
+
+   DEBUG(VM_DEBUG_DONE, "_init() done.\n");
+   return 0;
+
+error:
+   cmn_err(HGFS_ERROR, "could not install HGFS module.\n");
+   ddi_soft_state_fini(&superInfoHead);
+   return ret;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * _fini --
+ *    Invoked when a module is being removed from the kernel.
+ *
+ * Results:
+ *    Returns the result of mod_remove(9F), which is zero on success, and a
+ *    non-zero value on failure.
+ *
+ * Side effects:
+ *    The module will be removed from the kernel.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+_fini(void)
+{
+   HgfsSuperInfo *sip;
+   int error;
+
+   DEBUG(VM_DEBUG_ENTRY, "_fini() for HGFS.\n");
+
+   sip = ddi_get_soft_state(superInfoHead, hgfsInstance);
+
+   /*
+    * Make sure the device is closed and the fs is not mounted if we have
+    * a valid superinfo pointer.
+    */
+   if (sip && (sip->devOpen || sip->vfsp)) {
+      DEBUG(VM_DEBUG_FAIL, "Cannot unload module because either device"
+            "is open or file system is mounted\n");
+      return -1;
+   }
+
+   error = mod_remove(&HgfsModlinkage);
+   if (error) {
+      cmn_err(HGFS_ERROR, "could not remove HGFS module.\n");
+      return error;
+   }
+
+#if HGFS_VFS_VERSION > 2
+   if (hgfsType != HGFS_TYPE_UNINITIALIZED) {
+      vfs_freevfsops_by_type(hgfsType);
+   }
+   if (sip && sip->vnodeOps) {
+      vn_freevnodeops(sip->vnodeOps);
+   }
+#endif
+   ddi_soft_state_fini(&superInfoHead);   /* void return */
+
+   DEBUG(VM_DEBUG_DONE, "_fini() done.\n");
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * _info --
+ *
+ *    Invoked when the modinfo(1M) command is executed.  mod_info(9F) handles
+ *    this for us.
+ *
+ * Results:
+ *    Returns mod_info(9F)'s results, which are a non-zero value on success, and
+ *    zero on failure.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+_info(struct modinfo *modinfop) // OUT: Filled in with module's information by
+{
+   DEBUG(VM_DEBUG_ENTRY, "_info().\n");
+   ASSERT(modinfop);
+
+   if (!modinfop) {
+        cmn_err(HGFS_ERROR, "NULL input in _info\n");
+        return EINVAL;
+   }
+
+   return mod_info(&HgfsModlinkage, modinfop);
+}
diff --git a/open-vm-tools/modules/solaris/vmhgfs/module.h b/open-vm-tools/modules/solaris/vmhgfs/module.h
new file mode 100644 (file)
index 0000000..9d498af
--- /dev/null
@@ -0,0 +1,77 @@
+/*********************************************************
+ * Copyright (C) 2004 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * module.h --
+ *
+ *      EXTERNs needed by structures in module.c
+ */
+
+#ifndef __MODULE_H_
+#define __MODULE_H_
+
+#include "filesystem.h"
+
+/*
+ * Device driver EXTERNs
+ */
+
+/* Functions for the cb_ops structure (see driver.c) */
+EXTERN int HgfsDevOpen(dev_t *devp, int flag, int otyp, cred_t *credp);
+EXTERN int HgfsDevClose(dev_t dev, int flag, int otyp, cred_t *credp);
+EXTERN int HgfsDevRead(dev_t dev, uio_t *uiop, cred_t *credp);
+EXTERN int HgfsDevWrite(dev_t dev, uio_t *uiop, cred_t *credp);
+EXTERN int HgfsDevChpoll(dev_t dev, short int events, int anyyet,
+                         short int *reventsp, struct pollhead **phpp);
+
+/* Functions for the dev_ops structure (see driver.c) */
+EXTERN int HgfsDevGetinfo(dev_info_t *dip, ddi_info_cmd_t infocmd,
+                          void *arg, void **result);
+EXTERN int HgfsDevAttach(dev_info_t *dip, ddi_attach_cmd_t cmd);
+EXTERN int HgfsDevDetach(dev_info_t *dip, ddi_detach_cmd_t cmd);
+
+/* Struct needed in struct modldrv */
+EXTERN struct mod_ops mod_driverops;
+
+
+/*
+ * Filesystem EXTERNs
+ */
+
+/* Filesystem initialization routine (see filesystem.c) */
+#if HGFS_VFS_VERSION == 2
+EXTERN int HgfsInit(struct vfssw *vfsswp, int fstype);
+#else
+EXTERN int HgfsInit(int, char *);
+#endif
+
+/* Functions for the vfsops structure (see filesystem.c) */
+EXTERN int HgfsMount(struct vfs *vfsp, struct vnode *vnodep,
+                 struct mounta *mntp, struct cred *credp);
+EXTERN int HgfsUnmount(struct vfs *vfsp, int mflag, struct cred *credp);
+EXTERN int HgfsRoot(struct vfs *vfsp, struct vnode **vnodepp);
+EXTERN int HgfsStatvfs(struct vfs *vfsp, struct statvfs64 *stats);
+EXTERN int HgfsSync(struct vfs* vfsp, short flags, struct cred *credp);
+EXTERN int HgfsVget(struct vfs *vfsp, struct vnode **vnodepp, struct fid *fidp);
+EXTERN int HgfsMountroot(struct vfs *vfsp, enum whymountroot reason);
+EXTERN int HgfsReserved(struct vfs *vfsp, struct vnode **vnodepp, char * /* ?? */);
+EXTERN void HgfsFreevfs(struct vfs *vfsp);
+
+/* Struct needed in struct modlfs */
+EXTERN struct mod_ops mod_fsops;
+
+
+#endif /* __MODULE_H_ */
diff --git a/open-vm-tools/modules/solaris/vmhgfs/request.c b/open-vm-tools/modules/solaris/vmhgfs/request.c
new file mode 100644 (file)
index 0000000..58c5d1f
--- /dev/null
@@ -0,0 +1,565 @@
+/*********************************************************
+ * Copyright (C) 2004 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+
+/*
+ * request.c --
+ *
+ * Implementation of routines used to initialize, allocate, and move requests
+ * between lists.
+ *
+ */
+
+/*
+ * Includes
+ */
+#include "hgfsSolaris.h"
+#include "request.h"
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ *  HgfsInitRequestList --
+ *
+ *   Initializes the request list related members of the HgfsSuperInfo for
+ *   this instance of the driver state.
+ *
+ * Results:
+ *   The pending request list, free request list, and associated
+ *   synchronization primitives are initialized.
+ *
+ * Side effects:
+ *   Each request is now in the free list and is set to UNUSED.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+HgfsInitRequestList(HgfsSuperInfo *sip) // IN: Pointer to superinfo structure
+{
+   int i;
+
+   DEBUG(VM_DEBUG_REQUEST, "HgfsInitRequestList().\n");
+
+   ASSERT(sip);
+   /*
+    * We ASSERT() this because this function must be called before the device is
+    * opened to ensure the request lists are ready to be used by the
+    * filesystem.  (The filesystem won't mount unless the device is open.)
+    * By ASSERT()ing this condition we also obviate the need to acquire the
+    * mutex when adding requests to reqFreeList in the for loop below, since we
+    * are guaranteed (in practice) to have exclusive access.
+    */
+   ASSERT(!sip->devOpen);
+
+   /* None of these fail */
+
+   /* Initialize pending request list */
+   DblLnkLst_Init(&sip->reqList);
+   mutex_init(&sip->reqMutex, NULL, MUTEX_DRIVER, NULL);
+   cv_init(&sip->reqCondVar, NULL, CV_DRIVER, NULL);
+
+   /* Initialize free request list */
+   DblLnkLst_Init(&sip->reqFreeList);
+   mutex_init(&sip->reqFreeMutex, NULL, MUTEX_DRIVER, NULL);
+   cv_init(&sip->reqFreeCondVar, NULL, CV_DRIVER, NULL);
+
+   /*
+    * Initialize pool of requests
+    *
+    * Here we are setting each request's id to its index into the requestPool
+    * so this can be used as an identifier in reply packets.  Each request's
+    * state is also set to UNUSED and is added to the free list.
+    */
+   for (i = 0; i < ARRAYSIZE(requestPool); i++) {
+      requestPool[i].id = i;
+      requestPool[i].state = HGFS_REQ_UNUSED;
+      mutex_init(&requestPool[i].stateLock, NULL, MUTEX_DRIVER, NULL);
+
+      DblLnkLst_Init(&requestPool[i].listNode);
+      DblLnkLst_LinkLast(&sip->reqFreeList, &requestPool[i].listNode);
+   }
+
+   //HgfsDebugPrintReqList(&sip->reqFreeList);
+   DEBUG(VM_DEBUG_REQUEST, "HgfsInitRequestList() done.\n");
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsCancelAllRequests  --
+ *
+ *    Cancels all pending requests by removing them from the request list and
+ *    waking up the clients waiting for replies.  Also cancels requests that
+ *    have already been sent to guestd (and are not on the pending list) and
+ *    are either abandoned or still have clients waiting for them.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    The pending request list is empty and all requests are in the free list.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+HgfsCancelAllRequests(HgfsSuperInfo *sip)       // IN: Superinfo containing
+                                                //     request list
+{
+   DblLnkLst_Links *currNode, *nextNode;
+   HgfsReq *currRequest;
+   int i;
+
+   DEBUG(VM_DEBUG_REQUEST, "HgfsCancelAllRequests().\n");
+
+   ASSERT(sip);
+
+   /* Traverse list to make sure we cancel all pending requests on the list. */
+   mutex_enter(&sip->reqMutex);
+
+   DEBUG(VM_DEBUG_REQUEST, "HgfsCancelAllRequests(): traversing pending request list.\n");
+
+   for (currNode = HGFS_REQ_LIST_HEAD_NODE(sip);
+        currNode != &sip->reqList;
+        currNode = nextNode) {
+
+      /* Get the next element while we still have a pointer to it. */
+      nextNode = currNode->next;
+
+      DblLnkLst_Unlink1(currNode);
+      currRequest = DblLnkLst_Container(currNode, HgfsReq, listNode);
+
+      if (HgfsReqGetState(currRequest) == HGFS_REQ_ABANDONED) {
+         /*
+          * If the client is no longer waiting, clean up for it by destroying
+          * the request.
+          */
+         HgfsDestroyReq(sip, currRequest);
+      } else {
+         /*
+          * ... otherwise indicate an error and wakeup the client.  Note that
+          * we can't call HgfsWakeWaitingClient() because we already hold the
+          * reqMutex lock.
+          *
+          * Also, make sure that all non-ABANDONED requests are SUBMITTED.
+          */
+         ASSERT(HgfsReqGetState(currRequest) == HGFS_REQ_SUBMITTED);
+
+         HgfsReqSetState(currRequest, HGFS_REQ_ERROR);
+         cv_signal(&currRequest->condVar);
+      }
+   }
+
+   DEBUG(VM_DEBUG_REQUEST, "HgfsCancelAllRequests(): traversing request pool.\n");
+
+   /*
+    * Now look for abandoned and submitted requests that are in the pool but
+    * not on the pending list (because they were already sent to guestd).
+    */
+   for (i = 0; i < ARRAYSIZE(requestPool); i++) {
+      /*
+       * As above, abandoned requests are cleaned up and we wake up the clients
+       * for submitted requests.
+       */
+      if (HgfsReqGetState(&requestPool[i]) == HGFS_REQ_ABANDONED) {
+         HgfsDestroyReq(sip, &requestPool[i]);
+      } else if (HgfsReqGetState(&requestPool[i]) == HGFS_REQ_SUBMITTED) {
+         HgfsReqSetState(&requestPool[i], HGFS_REQ_ERROR);
+         cv_signal(&requestPool[i].condVar);
+      }
+   }
+
+   mutex_exit(&sip->reqMutex);
+
+   DEBUG(VM_DEBUG_REQUEST, "HgfsCancelAllRequests() done.\n");
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsListIsEmpty --
+ *
+ *    Determines whether the provided list is empty.
+ *
+ *    Note: this assumes it is called with the list lock held because often
+ *    callers will need this function to be atomic with other operations.
+ *
+ * Results:
+ *    Returns zero if list is not empty, a positive integer if it is empty.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+INLINE Bool
+HgfsListIsEmpty(DblLnkLst_Links *listAnchor)    // IN: Anchor of list to check
+{
+   ASSERT(listAnchor);
+
+   return (listAnchor == listAnchor->next);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsGetNewReq --
+ *
+ *    Allocates and initializes a new request structure from the request pool.
+ *    This function blocks until a request is available or it has been
+ *    interrupted by a signal.
+ *
+ * Results:
+ *    Returns pointer to allocated HgfsReq on success, and NULL if interrupted
+ *    while waiting to be allocated a request structure.
+ *
+ * Side effects:
+ *    Request's state is set to HGFS_REQ_ALLOCATED.
+ *    Request is removed from the free list.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+HgfsReq *
+HgfsGetNewReq(HgfsSuperInfo *sip)       // IN: Superinfo containing free list
+{
+   HgfsReq *newReq;
+
+   DEBUG(VM_DEBUG_REQUEST, "HgfsGetNewReq().\n");
+
+   ASSERT(sip);
+
+   /*
+    * Here we atomically get the next free request from the free list and set
+    * that request's state to ALLOCATED.
+    */
+   mutex_enter(&sip->reqFreeMutex);
+
+   /* Wait for a request structure if there aren't any free */
+   while (HgfsListIsEmpty(&sip->reqFreeList)) {
+      /*
+       * If the list is empty, we wait on the condition variable which is
+       * unconditionally signaled whenever a request is destroyed.
+       */
+      if (cv_wait_sig(&sip->reqFreeCondVar, &sip->reqFreeMutex) == 0) {
+         /*
+          * We were interrupted while waiting for a request, so we must return
+          * NULL and release the mutex.
+          */
+         newReq = NULL;
+         goto out;
+      }
+   }
+
+   newReq = HGFS_FREE_REQ_LIST_HEAD(sip);
+
+   HgfsDebugPrintReq("HgfsGetNewReq", newReq);
+
+   /* Failure of these indicates error in program's logic */
+   ASSERT(newReq && (HgfsReqGetState(newReq) == HGFS_REQ_UNUSED));
+
+   /* Take request off the free list and indicate it has been ALLOCATED */
+   DblLnkLst_Unlink1(&newReq->listNode);
+   HgfsReqSetState(newReq, HGFS_REQ_ALLOCATED);
+
+   /* Clear packet of request before allocating to clients. */
+   bzero(newReq->packet, sizeof newReq->packet);
+
+out:
+   mutex_exit(&sip->reqFreeMutex);
+
+   DEBUG(VM_DEBUG_LIST, "Dequeued from free list: %s", newReq->packet);
+   HgfsDebugPrintReqList(&sip->reqFreeList);
+   DEBUG(VM_DEBUG_REQUEST, "HgfsGetNewReq() done.\n");
+
+   return newReq;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsDestroyReq --
+ *
+ *    Deallocates a request structure.
+ *
+ * Results:
+ *    Returns void.
+ *
+ * Side effects:
+ *    Request's state is set to HGFS_REQ_UNUSED.
+ *    Request is placed on the free list.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+INLINE void
+HgfsDestroyReq(HgfsSuperInfo *sip,      // IN: Superinfo containing free list
+               HgfsReq *oldReq)         // IN: Request to destroy
+{
+   DEBUG(VM_DEBUG_ENTRY, "HgfsDestroyReq().\n");
+
+   /* XXX This should go away later, just for testing */
+   if (HgfsReqGetState(oldReq) != HGFS_REQ_COMPLETED) {
+      DEBUG(VM_DEBUG_ALWAYS, "HgfsDestroyReq() (oldReq state=%d).\n",
+           HgfsReqGetState(oldReq));
+   }
+
+   ASSERT(sip);
+   ASSERT(oldReq);
+   /* Failure of this check indicates an error in program logic */
+   ASSERT((HgfsReqGetState(oldReq) == HGFS_REQ_COMPLETED) ||
+          (HgfsReqGetState(oldReq) == HGFS_REQ_ABANDONED) ||
+          (HgfsReqGetState(oldReq) == HGFS_REQ_ERROR));
+
+   /*
+    * To make the request available for other clients we change its state to
+    * UNUSED and place it back on the free list.
+    */
+   mutex_enter(&sip->reqFreeMutex);
+
+   HgfsReqSetState(oldReq, HGFS_REQ_UNUSED);
+   DblLnkLst_LinkLast(&sip->reqFreeList, &oldReq->listNode);
+   /* Wake up clients waiting for a request structure */
+   cv_signal(&sip->reqFreeCondVar);
+
+   mutex_exit(&sip->reqFreeMutex);
+
+   HgfsDebugPrintReqList(&sip->reqFreeList);
+
+   DEBUG(VM_DEBUG_REQUEST, "HgfsDestroyReq() done.\n");
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsEnqueueRequest --
+ *
+ *    Adds the provided request to the end of the request list.
+ *
+ *    Note: this assumes it is called with the list lock held because often
+ *    callers will need this function to be atomic with other operations.
+ *
+ * Results:
+ *    Returns void.
+ *
+ * Side effects:
+ *    Request's state is set to HGFS_REQ_SUBMITTED.
+ *    Request is added to the pending request list.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+INLINE void
+HgfsEnqueueRequest(HgfsSuperInfo *sip,  // IN: Superinfo containing request list
+                   HgfsReq *newReq)     // IN: Request to enqueue
+{
+   DEBUG(VM_DEBUG_REQUEST, "HgfsEnqueueRequest().\n");
+
+   ASSERT(sip);
+   ASSERT(newReq);
+   /* Failure of this check indicates error in program logic */
+   ASSERT(HgfsReqGetState(newReq) == HGFS_REQ_ALLOCATED);
+
+   /*
+    * This simply changes the state and places the request on the pending
+    * request list.  Signaling the (potentially sleeping) device is handled by
+    * the caller (HgfsSubmitRequest()).
+    */
+   HgfsReqSetState(newReq, HGFS_REQ_SUBMITTED);
+   DblLnkLst_LinkLast(&sip->reqList, &newReq->listNode);
+
+   DEBUG(VM_DEBUG_LIST, "Enqueued on pending list: %s", newReq->packet);
+   HgfsDebugPrintReqList(&sip->reqList);
+   DEBUG(VM_DEBUG_REQUEST, "HgfsEnqueueRequest() done.\n");
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsDequeueRequest --
+ *
+ *    Removes the next request from the list.
+ *
+ *    Note: this assumes it is called with the list lock held because often
+ *    callers will need this function to be atomic with other operations.
+ *
+ * Results:
+ *    Returns a pointer to the request removed from the list, or NULL if the
+ *    list is empty.
+ *
+ * Side effects:
+ *    Request is removed from the pending request list.
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+INLINE HgfsReq *
+HgfsDequeueRequest(HgfsSuperInfo *sip)  // IN: Superinfo containing request list
+{
+   HgfsReq *nextReq;
+
+   DEBUG(VM_DEBUG_REQUEST, "HgfsDequeueRequest().\n");
+
+   ASSERT(sip);
+
+   if (HgfsListIsEmpty(&sip->reqList)) {
+      return NULL;
+   }
+
+   nextReq = HGFS_REQ_LIST_HEAD(sip);
+
+   /*
+    * nextReq should never be NULL since we are called with the lock held and
+    * we just checked if the list was empty.  The request's state should only
+    * be SUBMITTED or ABANDONED.  (Errors occurring while copying the request
+    * to guestd happen after removal from this list.)
+    */
+   ASSERT(nextReq);
+   ASSERT(HgfsReqGetState(nextReq) == HGFS_REQ_SUBMITTED ||
+          HgfsReqGetState(nextReq) == HGFS_REQ_ABANDONED);
+
+   DblLnkLst_Unlink1(&nextReq->listNode);
+
+   DEBUG(VM_DEBUG_LIST, "Dequeued from pending list: %s", nextReq->packet);
+   HgfsDebugPrintReqList(&sip->reqList);
+   DEBUG(VM_DEBUG_REQUEST, "HgfsDequeueRequest() done.\n");
+
+   return nextReq;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsWakeWaitingClient --
+ *
+ *    Wakes up the client waiting on the specified request.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+INLINE void
+HgfsWakeWaitingClient(HgfsSuperInfo *sip,       // IN: Superinfo with request mutex
+                      HgfsReq *req)             // IN: Request to wake client for
+{
+//   DEBUG(VM_DEBUG_REQUEST, "HgfsWakeWaitingClient().\n");
+
+   ASSERT(sip);
+   ASSERT(req);
+
+   /*
+    * We need to acquire the mutex before signaling the request's condition
+    * variable since it was acquired before sleeping in HgfsSubmitRequest().
+    */
+   mutex_enter(&sip->reqMutex);
+
+   cv_signal(&req->condVar);
+
+   mutex_exit(&sip->reqMutex);
+
+//   DEBUG(VM_DEBUG_REQUEST, "HgfsWakeWaitingClient() done.\n");
+}
+
+
+/*
+ * These two state functions will help prevent forgetting to lock.
+ */
+
+
+/*
+ *----------------------------------------------------------------------------
+ * HgfsSetState --
+ *
+ *    Sets the state of the request.
+ *
+ * Results:
+ *    Returns void.
+ *
+ * Side effects:
+ *    The state of the request is modified.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+INLINE void
+HgfsReqSetState(HgfsReq *req,           // IN: Request to alter state of
+                HgfsReqState state)     // IN: State to set request to
+{
+//   DEBUG(VM_DEBUG_REQUEST, "HgfsReqSetState().\n");
+
+   ASSERT(req);
+
+   mutex_enter(&req->stateLock);
+
+   req->state = state;
+
+   mutex_exit(&req->stateLock);
+
+//   DEBUG(VM_DEBUG_REQUEST, "HgfsReqSetState() done.\n");
+}
+
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsReqGetState --
+ *
+ *    Retrieves state of provided request.
+ *
+ * Results:
+ *    Returns state of request.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+INLINE HgfsReqState
+HgfsReqGetState(HgfsReq *req)   // IN: Request to retrieve state of
+{
+   HgfsReqState state;
+
+   DEBUG(VM_DEBUG_REQUEST, "HgfsReqGetState().\n");
+
+   ASSERT(req);
+
+   mutex_enter(&req->stateLock);
+
+   state = req->state;
+
+   mutex_exit(&req->stateLock);
+
+   DEBUG(VM_DEBUG_REQUEST, "HgfsReqGetState() done.\n");
+   return state;
+}
diff --git a/open-vm-tools/modules/solaris/vmhgfs/request.h b/open-vm-tools/modules/solaris/vmhgfs/request.h
new file mode 100644 (file)
index 0000000..d197665
--- /dev/null
@@ -0,0 +1,67 @@
+/*********************************************************
+ * Copyright (C) 2004 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+
+/*
+ * request.h --
+ *
+ * Prototypes for request initialization, allocation, and list manipulation
+ * functions.
+ *
+ */
+
+#ifndef __REQUEST_H_
+#define __REQUEST_H_
+
+
+#include <sys/ksynch.h> /* mutexes and condition variables */
+
+#include "hgfsSolaris.h"
+#include "debug.h"
+
+#include "dbllnklst.h"  /* Double link list types */
+
+/*
+ * Macros
+ */
+
+/* Since the DblLnkLst_Links in the superinfo is just an anchor, we want to
+ * skip it (e.g., get the container for the next element) */
+#define HGFS_REQ_LIST_HEAD(si)           \
+            (DblLnkLst_Container(si->reqList.next, HgfsReq, listNode))
+#define HGFS_REQ_LIST_HEAD_NODE(si)      \
+            (si->reqList.next)
+#define HGFS_FREE_REQ_LIST_HEAD(si)      \
+            (DblLnkLst_Container(si->reqFreeList.next, HgfsReq, listNode))
+#define HGFS_FREE_REQ_LIST_HEAD_NODE(si) \
+            (si->reqFreeList.next)
+
+
+/*
+ * Functions
+ */
+void HgfsInitRequestList(HgfsSuperInfo *sip);
+void HgfsCancelAllRequests(HgfsSuperInfo *sip);
+INLINE Bool HgfsListIsEmpty(DblLnkLst_Links *listAnchor);
+HgfsReq *HgfsGetNewReq(HgfsSuperInfo *sip);
+INLINE void HgfsDestroyReq(HgfsSuperInfo *sip, HgfsReq *oldReq);
+INLINE void HgfsEnqueueRequest(HgfsSuperInfo *sip, HgfsReq *newReq);
+INLINE HgfsReq *HgfsDequeueRequest(HgfsSuperInfo *sip);
+INLINE void HgfsWakeWaitingClient(HgfsSuperInfo *sip, HgfsReq *req);
+INLINE void HgfsReqSetState(HgfsReq *req, HgfsReqState state);
+INLINE HgfsReqState HgfsReqGetState(HgfsReq *req);
+
+#endif /* __REQUEST_H_ */
diff --git a/open-vm-tools/modules/solaris/vmhgfs/sha1.c b/open-vm-tools/modules/solaris/vmhgfs/sha1.c
new file mode 100644 (file)
index 0000000..3da0d31
--- /dev/null
@@ -0,0 +1,241 @@
+/*********************************************************
+ * Copyright (C) 1998 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+SHA-1 in C
+Originally released by Steve Reid <steve@edmweb.com> into the public domain
+
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+  A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+  84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+  34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+/*
+       12/15/98: JEB: Removed main and moved prototypes to sha1.h
+                       Made SHA1Transform a static function
+*/
+
+#if defined(USERLEVEL) || defined(_WIN32)
+#   include <string.h>
+#   if defined(_WIN32)
+#      include <memory.h>
+#   endif
+#endif
+
+#if defined(sun) && !defined(SOL9)
+#include <memory.h>
+#endif
+
+#if defined(__FreeBSD__)
+#   if defined(_KERNEL)
+#      include <sys/libkern.h>
+#      include <sys/systm.h>
+#   else
+#      include <string.h>
+#   endif
+#endif
+
+#if defined(__APPLE__)
+#      include <string.h>
+#endif
+
+#ifdef USERLEVEL
+#include "vmware.h"
+#endif
+#ifdef VMKBOOT
+#include "vm_libc.h"
+#endif
+#include "sha1.h"
+#include "vm_basic_asm.h"
+
+/* If the endianess is not defined (it is done in string.h of glibc 2.1.1), we
+   default to LE --hpreg */
+#ifndef LITTLE_ENDIAN
+# define LITTLE_ENDIAN /* This should be #define'd if true. */
+#endif
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+#define F0(w,x,y) ((w&(x^y))^y)
+#define F1(w,x,y) (w^x^y)
+#define F2(w,x,y) (((w|x)&y)|(w&x))
+#define F3(w,x,y) (w^x^y)
+
+typedef union {
+   unsigned char c[64];
+   uint32 l[16];
+} CHAR64LONG16;
+
+static void
+R(CHAR64LONG16 *block, uint32 *f, int i)
+{
+   uint32 a, b, c, d, e, round, blk;
+   a = f[0];
+   b = f[1];
+   c = f[2];
+   d = f[3];
+   e = f[4];
+   f[1] = a;
+   f[2] = rol(b, 30);
+   f[3] = c;
+   f[4] = d;
+   if (i < 20) {
+      round = 0x5A827999 + F0(b,c,d);
+   } else if (i < 40) {
+      round = 0x6ED9EBA1 + F1(b,c,d);
+   } else if (i < 60) {
+      round = 0x8F1BBCDC + F2(b,c,d);
+   } else {
+      round = 0xCA62C1D6 + F3(b,c,d);
+   }
+   if (i < 16) {
+#ifdef LITTLE_ENDIAN
+      blk = Bswap(block->l[i]);
+#else
+      blk = block->l[i];
+#endif
+   } else {
+      blk = rol(block->l[(i+13) & 15] ^ block->l[(i+8) & 15] ^
+                block->l[(i+2) & 15] ^ block->l[i & 15], 1);
+   }
+   block->l[i & 15] = blk;
+   f[0] = e + round + blk + rol(a, 5);
+}
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+static void
+_SHA1Transform(uint32 state[5], unsigned char buffer[64])
+{
+    int i;
+    uint32 f[5];
+    CHAR64LONG16* block = (CHAR64LONG16*)buffer;
+
+    /* Copy context->state[] to working vars */
+    for (i = 0; i < 5; i++) {
+       f[i] = state[i];
+    }
+
+    for (i = 0; i < 80; i++) {
+       R(block, f, i);
+    }
+
+    /* Add the working vars back into context.state[] */
+    for (i = 0; i < 5; i++) {
+       state[i] += f[i];
+    }
+}
+
+#ifdef SHA1HANDSOFF
+void SHA1Transform(uint32 state[5], const unsigned char buffer[64])
+#else
+void SHA1Transform(uint32 state[5], unsigned char buffer[64])
+#endif
+{
+#ifdef SHA1HANDSOFF
+    unsigned char workspace[64];
+
+    /* Do not do that work in _SHA1Transform, otherwise gcc 2.7.2.3 will go
+       south and allocate a stack frame of 0x9c8 bytes, that immediately
+       leads to a stack smash and a host reset */
+    memcpy(workspace, buffer, sizeof(workspace));
+    _SHA1Transform(state, workspace);
+#else
+    _SHA1Transform(state, buffer);
+#endif
+}
+
+/* SHA1Init - Initialize new context */
+
+void SHA1Init(SHA1_CTX* context)
+{
+    /* SHA1 initialization constants */
+    context->state[0] = 0x67452301;
+    context->state[1] = 0xEFCDAB89;
+    context->state[2] = 0x98BADCFE;
+    context->state[3] = 0x10325476;
+    context->state[4] = 0xC3D2E1F0;
+    context->count[0] = context->count[1] = 0;
+}
+
+
+/* Run your data through this. */
+
+#ifdef SHA1HANDSOFF
+void SHA1Update(SHA1_CTX* context,
+                const unsigned char *data,
+                size_t len)
+#else
+void SHA1Update(SHA1_CTX* context,
+                unsigned char *data,
+                size_t len)
+#endif
+{
+    size_t i, j;
+
+    j = (context->count[0] >> 3) & 63;
+    if ((context->count[0] += (uint32) (len << 3)) < (len << 3))
+       context->count[1]++;
+    context->count[1] += (uint32) (len >> 29);
+    if ((j + len) > 63) {
+        memcpy(&context->buffer[j], data, (i = 64-j));
+        SHA1Transform(context->state, context->buffer);
+        for ( ; i + 63 < len; i += 64) {
+            SHA1Transform(context->state, &data[i]);
+        }
+        j = 0;
+    }
+    else i = 0;
+    memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+/* Add padding and return the message digest. */
+
+void SHA1Final(unsigned char digest[SHA1_HASH_LEN], SHA1_CTX* context)
+{
+    size_t i, j;
+    unsigned char finalcount[8];
+
+    for (i = 0; i < 8; i++) {
+        finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
+         >> ((3-(i & 3)) * 8) ) & 255);  /* Endian independent */
+    }
+    SHA1Update(context, (unsigned char *)"\200", 1);
+    while ((context->count[0] & 504) != 448) {
+        SHA1Update(context, (unsigned char *)"\0", 1);
+    }
+    SHA1Update(context, finalcount, 8);  /* Should cause a SHA1Transform() */
+    for (i = 0; i < SHA1_HASH_LEN; i++) {
+        digest[i] = (unsigned char)
+         ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+    }
+    /* Wipe variables */
+    i = j = 0;
+    memset(context->buffer, 0, 64);
+    memset(context->state, 0, SHA1_HASH_LEN);
+    memset(context->count, 0, 8);
+    memset(&finalcount, 0, 8);
+//#ifdef SHA1HANDSOFF
+//    /* make SHA1Transform overwrite it's own static vars */
+//    SHA1Transform(context->state, context->buffer);
+//#endif
+}
+
diff --git a/open-vm-tools/modules/solaris/vmhgfs/sha1.h b/open-vm-tools/modules/solaris/vmhgfs/sha1.h
new file mode 100644 (file)
index 0000000..f1787a2
--- /dev/null
@@ -0,0 +1,78 @@
+/*********************************************************
+ * Copyright (C) 1998 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * sha1.h --
+ *
+ *     SHA1 encryption
+ */
+
+#ifndef _SHA1_H_
+#define _SHA1_H_
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_VMCORE
+#define INCLUDE_ALLOW_VMNIXMOD
+#include "includeCheck.h"
+
+/* for uint32 */
+#include "vm_basic_types.h"
+
+/*
+SHA-1 in C
+By Steve Reid <steve@edmweb.com>
+100% Public Domain
+
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+  A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+  84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+  34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+/*
+       12/15/98: JEB: Removed main and moved prototypes to sha1.h
+                       Made SHA1Transform a static function
+*/
+
+#define        SHA1_HASH_LEN   20
+
+typedef struct {
+    uint32 state[5];
+    uint32 count[2];
+    unsigned char buffer[64];
+} SHA1_CTX;
+
+#define SHA1HANDSOFF /* Copies data before messing with it. */
+
+void SHA1Init(SHA1_CTX* context);
+#ifdef SHA1HANDSOFF
+void SHA1Update(SHA1_CTX* context,
+                const unsigned char *data,
+                size_t len);
+#else
+void SHA1Update(SHA1_CTX* context,
+                unsigned char *data,
+                size_t len);
+#endif
+void SHA1Final(unsigned char digest[SHA1_HASH_LEN], SHA1_CTX* context);
+
+void SHA1Transform(uint32 state[5], const unsigned char buffer[64]);
+
+#endif // ifndef _SHA1_H_
diff --git a/open-vm-tools/modules/solaris/vmhgfs/vm_assert.h b/open-vm-tools/modules/solaris/vmhgfs/vm_assert.h
new file mode 100644 (file)
index 0000000..80b5490
--- /dev/null
@@ -0,0 +1,315 @@
+/*********************************************************
+ * Copyright (C) 1998-2004 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * vm_assert.h --
+ *
+ *     The basic assertion facility for all VMware code.
+ *
+ *     For proper use, see
+ *     http://vmweb.vmware.com/~mts/WebSite/guide/programming/asserts.html
+ */
+
+#ifndef _VM_ASSERT_H_
+#define _VM_ASSERT_H_
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMMON
+#define INCLUDE_ALLOW_VMNIXMOD
+#define INCLUDE_ALLOW_VMKERNEL
+#define INCLUDE_ALLOW_VMKDRIVERS
+#define INCLUDE_ALLOW_VMK_MODULE
+#define INCLUDE_ALLOW_DISTRIBUTE
+#define INCLUDE_ALLOW_VMCORE
+#define INCLUDE_ALLOW_VMIROM
+#include "includeCheck.h"
+
+// XXX not necessary except some places include vm_assert.h improperly
+#include "vm_basic_types.h"
+#include "vm_basic_defs.h"
+
+
+/*
+ * XXX old file code
+ */
+
+#ifdef FILECODEINT
+#error "Don't define FILECODEINT.  It is obsolete."
+#endif
+#ifdef FILECODE
+#error "Don't define FILECODE.  It is obsolete."
+#endif
+
+
+/*
+ * Panic and log functions
+ */
+
+EXTERN void Log(const char *fmt, ...) PRINTF_DECL(1, 2);
+EXTERN void Warning(const char *fmt, ...) PRINTF_DECL(1, 2);
+EXTERN NORETURN void Panic(const char *fmt, ...) PRINTF_DECL(1, 2);
+
+EXTERN void LogThrottled(uint32 *count, const char *fmt, ...)
+            PRINTF_DECL(2, 3);
+EXTERN void WarningThrottled(uint32 *count, const char *fmt, ...)
+            PRINTF_DECL(2, 3);
+
+/* DB family:  messages which are parsed by logfile database system */
+#define WarningDB Warning
+#define LogDB Log
+#define WarningThrottledDB WarningThrottled
+#define LogThrottledDB LogThrottled
+
+
+/*
+ * Stress testing: redefine ASSERT_IFNOT() to taste
+ */
+
+#ifndef ASSERT_IFNOT
+   #ifdef __cplusplus
+      #define ASSERT_IFNOT(cond, panic) (UNLIKELY(!(cond)) ? (panic) : (void)0)
+   #else
+      #define ASSERT_IFNOT(cond, panic) (UNLIKELY(!(cond)) ? (panic) : 0)
+   #endif
+#endif
+
+
+/*
+ * Assert, panic, and log macros
+ *
+ * Some of these are redefined below undef !VMX86_DEBUG.
+ * ASSERT() is special cased because of interaction with Windows DDK.
+ */
+
+#if defined VMX86_DEBUG || defined ASSERT_ALWAYS_AVAILABLE
+#undef ASSERT
+#define ASSERT(cond) \
+           ASSERT_IFNOT(cond, _ASSERT_PANIC(AssertAssert))
+#endif
+#define ASSERT_BUG(bug, cond) \
+           ASSERT_IFNOT(cond, _ASSERT_PANIC_BUG(bug, AssertAssert))
+#define ASSERT_BUG_DEBUGONLY(bug, cond) ASSERT_BUG(bug, cond)
+
+#define PANIC()        _ASSERT_PANIC(AssertPanic)
+#define PANIC_BUG(bug) _ASSERT_PANIC_BUG(bug, AssertPanic)
+
+#define ASSERT_NOT_IMPLEMENTED(cond) \
+           ASSERT_IFNOT(cond, NOT_IMPLEMENTED())
+#define ASSERT_NOT_IMPLEMENTED_BUG(bug, cond) \
+           ASSERT_IFNOT(cond, NOT_IMPLEMENTED_BUG(bug))
+
+#define NOT_IMPLEMENTED()        _ASSERT_PANIC(AssertNotImplemented)
+#define NOT_IMPLEMENTED_BUG(bug) _ASSERT_PANIC_BUG(bug, AssertNotImplemented)
+
+#define NOT_REACHED()            _ASSERT_PANIC(AssertNotReached)
+#define NOT_REACHED_BUG(bug)     _ASSERT_PANIC_BUG(bug, AssertNotReached)
+
+#define ASSERT_MEM_ALLOC(cond) \
+           ASSERT_IFNOT(cond, _ASSERT_PANIC(AssertMemAlloc))
+
+#ifdef VMX86_DEVEL
+   #define ASSERT_LENGTH(real, expected) \
+              ASSERT_IFNOT((real) == (expected), \
+                 Panic(AssertLengthFmt, __FILE__, __LINE__, real, expected))
+#else
+   #define ASSERT_LENGTH(real, expected) ASSERT((real) == (expected))
+#endif
+
+#ifdef VMX86_DEVEL
+   #define ASSERT_DEVEL(cond) ASSERT(cond)
+#else
+   #define ASSERT_DEVEL(cond) ((void) 0)
+#endif
+
+#define ASSERT_NO_INTERRUPTS()  ASSERT(!INTERRUPTS_ENABLED())
+#define ASSERT_HAS_INTERRUPTS() ASSERT(INTERRUPTS_ENABLED())
+
+#define ASSERT_LOG_UNEXPECTED(bug, cond) \
+           (UNLIKELY(!(cond)) ? LOG_UNEXPECTED(bug) : 0)
+#ifdef VMX86_DEVEL
+   #define LOG_UNEXPECTED(bug) \
+              Warning(AssertUnexpectedFmt, __FILE__, __LINE__, bug)
+#else
+   #define LOG_UNEXPECTED(bug) \
+              Log(AssertUnexpectedFmt, __FILE__, __LINE__, bug)
+#endif
+
+#define ASSERT_NOT_TESTED(cond) (UNLIKELY(!(cond)) ? NOT_TESTED() : 0)
+#ifdef VMX86_DEVEL
+   #define NOT_TESTED() Warning(AssertNotTestedFmt, __FILE__, __LINE__)
+#else
+   #define NOT_TESTED() Log(AssertNotTestedFmt, __FILE__, __LINE__)
+#endif
+
+#define NOT_TESTED_ONCE()                                               \
+   do {                                                                 \
+      static Bool alreadyPrinted = FALSE;                               \
+      if (UNLIKELY(!alreadyPrinted)) {                                  \
+        alreadyPrinted = TRUE;                                         \
+        NOT_TESTED();                                                  \
+      }                                                                 \
+   } while (0)
+
+#define NOT_TESTED_1024()                                               \
+   do {                                                                 \
+      static uint16 count = 0;                                          \
+      if (UNLIKELY(count == 0)) { NOT_TESTED(); }                       \
+      count = (count + 1) & 1023;                                       \
+   } while (0)
+
+#define LOG_ONCE(_s)                                                    \
+   do {                                                                 \
+      static Bool logged = FALSE;                                       \
+      if (!logged) {                                                    \
+        Log _s;                                                        \
+         logged = TRUE;                                                 \
+      }                                                                 \
+   } while (0)
+
+
+/*
+ * Redefine macros that are only in debug versions
+ */
+
+#if !defined VMX86_DEBUG && !defined ASSERT_ALWAYS_AVAILABLE // {
+
+#undef  ASSERT
+#define ASSERT(cond) ((void) 0)
+
+#undef  ASSERT_BUG_DEBUGONLY
+#define ASSERT_BUG_DEBUGONLY(bug, cond) ((void) 0)
+
+#undef  ASSERT_LENGTH
+#define ASSERT_LENGTH(real, expected) ((void) 0)
+
+/*
+ * Expand NOT_REACHED() as appropriate for each situation.
+ *
+ * Mainly, we want the compiler to infer the same control-flow
+ * information as it would from Panic().  Otherwise, different
+ * compilation options will lead to different control-flow-derived
+ * errors, causing some make targets to fail while others succeed.
+ *
+ * VC++ has the __assume() built-in function which we don't trust
+ * (see bug 43485); gcc has no such construct; we just panic in
+ * userlevel code.  The monitor doesn't want to pay the size penalty
+ * (measured at 212 bytes for the release vmm for a minimal infinite
+ * loop; panic would cost even more) so it does without and lives
+ * with the inconsistency.
+ */
+
+#ifdef VMM
+#undef  NOT_REACHED
+#define NOT_REACHED() ((void) 0)
+#else
+// keep debug definition
+#endif
+
+#undef  ASSERT_LOG_UNEXPECTED
+#define ASSERT_LOG_UNEXPECTED(bug, cond) ((void) 0)
+
+#undef LOG_UNEXPECTED
+#define LOG_UNEXPECTED(bug) ((void) 0)
+
+#undef  ASSERT_NOT_TESTED
+#define ASSERT_NOT_TESTED(cond) ((void) 0)
+#undef  NOT_TESTED
+#define NOT_TESTED() ((void) 0)
+#undef  NOT_TESTED_ONCE
+#define NOT_TESTED_ONCE() ((void) 0)
+#undef  NOT_TESTED_1024
+#define NOT_TESTED_1024() ((void) 0)
+
+#endif // !VMX86_DEBUG }
+
+
+/*
+ * Compile-time assertions.
+ *
+ * ASSERT_ON_COMPILE does not use the common
+ * switch (0) { case 0: case (e): ; } trick because some compilers (e.g. MSVC)
+ * generate code for it.
+ *
+ * The implementation uses both enum and typedef because the typedef alone is
+ * insufficient; gcc allows arrays to be declared with non-constant expressions
+ * (even in typedefs, where it makes no sense).
+ */
+
+#define ASSERT_ON_COMPILE(e) \
+   do { \
+      enum { AssertOnCompileMisused = ((e) ? 1 : -1) }; \
+      typedef char AssertOnCompileFailed[AssertOnCompileMisused]; \
+   } while (0)
+
+
+/*
+ * To put an ASSERT_ON_COMPILE() outside a function, wrap it
+ * in MY_ASSERTS().  The first parameter must be unique in
+ * each .c file where it appears.  For example,
+ *
+ * MY_ASSERTS(FS3_INT,
+ *    ASSERT_ON_COMPILE(sizeof(FS3_DiskLock) == 128);
+ *    ASSERT_ON_COMPILE(sizeof(FS3_DiskLockReserved) == DISK_BLOCK_SIZE);
+ *    ASSERT_ON_COMPILE(sizeof(FS3_DiskBlock) == DISK_BLOCK_SIZE);
+ *    ASSERT_ON_COMPILE(sizeof(Hardware_DMIUUID) == 16);
+ * )
+ *
+ * Caution: ASSERT() within MY_ASSERTS() is silently ignored.
+ * The same goes for anything else not evaluated at compile time.
+ */
+
+#define MY_ASSERTS(name, assertions) \
+   static INLINE void name(void) { \
+      assertions \
+   }
+
+
+/*
+ * Internal macros, functions, and strings
+ *
+ * The monitor wants to save space at call sites, so it has specialized
+ * functions for each situation.  User level wants to save on implementation
+ * so it uses generic functions.
+ */
+
+#if !defined VMM || defined MONITOR_APP // {
+
+#define _ASSERT_PANIC(name) \
+           Panic(_##name##Fmt "\n", __FILE__, __LINE__)
+#define _ASSERT_PANIC_BUG(bug, name) \
+           Panic(_##name##Fmt " bugNr=%d\n", __FILE__, __LINE__, bug)
+
+#define AssertLengthFmt     _AssertLengthFmt
+#define AssertUnexpectedFmt _AssertUnexpectedFmt
+#define AssertNotTestedFmt  _AssertNotTestedFmt
+
+#endif // }
+
+// these don't have newline so a bug can be tacked on
+#define _AssertPanicFmt            "PANIC %s:%d"
+#define _AssertAssertFmt           "ASSERT %s:%d"
+#define _AssertNotImplementedFmt   "NOT_IMPLEMENTED %s:%d"
+#define _AssertNotReachedFmt       "NOT_REACHED %s:%d"
+#define _AssertMemAllocFmt         "MEM_ALLOC %s:%d"
+
+// these are complete formats with newline
+#define _AssertLengthFmt           "LENGTH %s:%d r=%#x e=%#x\n"
+#define _AssertUnexpectedFmt       "UNEXPECTED %s:%d bugNr=%d\n"
+#define _AssertNotTestedFmt        "NOT_TESTED %s:%d\n"
+
+#endif /* ifndef _VM_ASSERT_H_ */
diff --git a/open-vm-tools/modules/solaris/vmhgfs/vm_basic_asm.h b/open-vm-tools/modules/solaris/vmhgfs/vm_basic_asm.h
new file mode 100644 (file)
index 0000000..7d83e29
--- /dev/null
@@ -0,0 +1,854 @@
+/*********************************************************
+ * Copyright (C) 2003 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * vm_basic_asm.h
+ *
+ *     Basic asm macros
+ */
+
+#ifndef _VM_BASIC_ASM_H_
+#define _VM_BASIC_ASM_H_
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMMON
+#define INCLUDE_ALLOW_VMNIXMOD
+#define INCLUDE_ALLOW_VMK_MODULE
+#define INCLUDE_ALLOW_VMKERNEL
+#define INCLUDE_ALLOW_DISTRIBUTE
+#define INCLUDE_ALLOW_VMCORE
+#define INCLUDE_ALLOW_VMIROM
+#include "includeCheck.h"
+
+#include "vm_basic_types.h"
+#include "x86cpuid.h"
+
+#ifdef VM_X86_64
+#include "vm_basic_asm_x86_64.h"
+#else
+#include "vm_basic_asm_x86.h"
+#endif
+
+
+/*
+ * x86-64 windows doesn't support inline asm so we have to use these
+ * intrinsic functions defined in the compiler.  Not all of these are well
+ * documented.  There is an array in the compiler dll (c1.dll) which has
+ * an array of the names of all the intrinsics minus the leading
+ * underscore.  Searching around in the ntddk.h file can also be helpful.
+ *
+ * The declarations for the intrinsic functions were taken from the DDK. 
+ * Our declarations must match the ddk's otherwise the 64-bit c++ compiler
+ * will complain about second linkage of the intrinsic functions.
+ * We define the intrinsic using the basic types corresponding to the 
+ * Windows typedefs. This avoids having to include windows header files
+ * to get to the windows types.
+ */
+#ifdef _MSC_VER
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * It seems x86 & x86-64 windows still implements these intrinsic
+ * functions.  The documentation for the x86-64 suggest the
+ * __inbyte/__outbyte intrinsics eventhough the _in/_out work fine and
+ * __inbyte/__outbyte aren't supported on x86.
+ */
+int            _inp(unsigned short);
+unsigned short _inpw(unsigned short);
+unsigned long  _inpd(unsigned short);
+
+int            _outp(unsigned short, int);
+unsigned short _outpw(unsigned short, unsigned short);
+unsigned long  _outpd(uint16, unsigned long);
+#pragma intrinsic(_inp, _inpw, _inpd, _outp, _outpw, _outpw, _outpd)
+void _ReadWriteBarrier(void);
+#pragma intrinsic(_ReadWriteBarrier)
+
+#ifdef VM_X86_64
+/*
+ * intrinsic functions only supported by x86-64 windows as of 2k3sp1
+ */
+void             __cpuid(unsigned int*, unsigned int);
+unsigned __int64 __rdtsc(void);
+void             __stosw(unsigned short*, unsigned short, size_t);
+void             __stosd(unsigned long*, unsigned long, size_t);
+#pragma intrinsic(__cpuid, __rdtsc, __stosw, __stosd)
+
+/*
+ * intrinsic functions supported by x86-64 windows and newer x86
+ * compilers (13.01.2035 for _BitScanForward).
+ */
+unsigned char  _BitScanForward(unsigned long*, unsigned long);
+void           _mm_pause(void);
+#pragma intrinsic(_BitScanForward, _mm_pause)
+#endif /* VM_X86_64 */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _MSC_VER */
+
+
+#ifdef __GNUC__ // {
+
+/*
+ * Checked against the Intel manual and GCC --hpreg
+ *
+ * volatile because reading from port can modify the state of the underlying
+ * hardware.
+ *
+ * Note: The undocumented %z construct doesn't work (internal compiler error)
+ *       with gcc-2.95.1
+ */
+
+#define __GCC_IN(s, type, name) \
+static INLINE type              \
+name(uint16 port)               \
+{                               \
+   type val;                    \
+                                \
+   __asm__ __volatile__(        \
+      "in" #s " %w1, %0"        \
+      : "=a" (val)              \
+      : "Nd" (port)             \
+   );                           \
+                                \
+   return val;                  \
+}
+
+__GCC_IN(b, uint8, INB)
+__GCC_IN(w, uint16, INW)
+__GCC_IN(l, uint32, IN32)
+
+
+/*
+ * Checked against the Intel manual and GCC --hpreg
+ *
+ * Note: The undocumented %z construct doesn't work (internal compiler error)
+ *       with gcc-2.95.1
+ */
+
+#define __GCC_OUT(s, s2, port, val) do { \
+   __asm__(                              \
+      "out" #s " %" #s2 "1, %w0"         \
+      :                                  \
+      : "Nd" (port), "a" (val)           \
+   );                                    \
+} while (0)
+
+#define OUTB(port, val) __GCC_OUT(b, b, port, val)
+#define OUTW(port, val) __GCC_OUT(w, w, port, val)
+#define OUT32(port, val) __GCC_OUT(l, , port, val)
+
+
+#define GET_CURRENT_EIP(_eip) \
+      __asm__ __volatile("call 0\n\tpopl %0" : "=r" (_eip): );
+
+
+/*
+ * Checked against the Intel manual and GCC --hpreg
+ * 
+ * Need __volatile__ and "memory" since CPUID has a synchronizing effect.
+ * The CPUID may also change at runtime (APIC flag, etc).
+ *
+ */
+
+static INLINE void
+__GET_CPUID(int eax,         // IN
+            CPUIDRegs *regs) // OUT
+{
+   __asm__ __volatile__(
+#if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler.
+      "movl %%ebx, %1"  "\n\t"
+      "cpuid"           "\n\t"
+      "xchgl %%ebx, %1"
+      : "=a" (regs->eax), "=&rm" (regs->ebx), "=c" (regs->ecx), "=d" (regs->edx)
+#else
+      "cpuid"
+      : "=a" (regs->eax), "=b" (regs->ebx), "=c" (regs->ecx), "=d" (regs->edx)
+#endif
+      : "a" (eax)
+      : "memory"
+   );
+}
+
+static INLINE void
+__GET_CPUID2(int eax,         // IN
+             int ecx,         // IN
+             CPUIDRegs *regs) // OUT
+{
+   __asm__ __volatile__(
+#if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler.
+      "movl %%ebx, %1"  "\n\t"
+      "cpuid"           "\n\t"
+      "xchgl %%ebx, %1"
+      : "=a" (regs->eax), "=&rm" (regs->ebx), "=c" (regs->ecx), "=d" (regs->edx)
+#else
+      "cpuid"
+      : "=a" (regs->eax), "=b" (regs->ebx), "=c" (regs->ecx), "=d" (regs->edx)
+#endif
+      : "a" (eax), "c" (ecx)
+      : "memory"
+   );
+}
+
+static INLINE uint32
+__GET_EAX_FROM_CPUID(int eax) // IN
+{
+#if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler.
+   uint32 ebx;
+
+   __asm__ __volatile__(
+      "movl %%ebx, %1"  "\n\t"
+      "cpuid"           "\n\t"
+      "xchgl %%ebx, %1"
+      : "=a" (eax), "=&rm" (ebx)
+      : "a" (eax)
+      : "memory", "%ecx", "%edx"
+   );
+#else
+   __asm__ __volatile__(
+      "cpuid"
+      : "=a" (eax)
+      : "a" (eax)
+      : "memory", "%ebx", "%ecx", "%edx"
+   );
+#endif
+
+   return eax;
+}
+
+static INLINE uint32
+__GET_EBX_FROM_CPUID(int eax) // IN
+{
+   uint32 ebx;
+
+   __asm__ __volatile__(
+#if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler.
+      "movl %%ebx, %1"  "\n\t"
+      "cpuid"           "\n\t"
+      "xchgl %%ebx, %1"
+      : "=a" (eax), "=&rm" (ebx)
+#else
+      "cpuid"
+      : "=a" (eax), "=b" (ebx)
+#endif
+      : "a" (eax)
+      : "memory", "%ecx", "%edx"
+   );
+
+   return ebx;
+}
+
+static INLINE uint32
+__GET_ECX_FROM_CPUID(int eax) // IN
+{
+   uint32 ecx;
+#if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler.
+   uint32 ebx;
+
+   __asm__ __volatile__(
+      "movl %%ebx, %1"  "\n\t"
+      "cpuid"           "\n\t"
+      "xchgl %%ebx, %1"
+      : "=a" (eax), "=&rm" (ebx), "=c" (ecx)
+      : "a" (eax)
+      : "memory", "%edx"
+   );
+#else
+
+   __asm__ __volatile__(
+      "cpuid"
+      : "=a" (eax), "=c" (ecx)
+      : "a" (eax)
+      : "memory", "%ebx", "%edx"
+   );
+#endif
+
+   return ecx;
+}
+
+static INLINE uint32
+__GET_EDX_FROM_CPUID(int eax) // IN
+{
+   uint32 edx;
+#if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler.
+   uint32 ebx;
+
+   __asm__ __volatile__(
+      "movl %%ebx, %1"  "\n\t"
+      "cpuid"           "\n\t"
+      "xchgl %%ebx, %1"
+      : "=a" (eax), "=&rm" (ebx), "=d" (edx)
+      : "a" (eax)
+      : "memory", "%ecx"
+   );
+#else
+
+   __asm__ __volatile__(
+      "cpuid"
+      : "=a" (eax), "=d" (edx)
+      : "a" (eax)
+      : "memory", "%ebx", "%ecx"
+   );
+#endif
+
+   return edx;
+}
+
+
+static INLINE uint32
+__GET_EAX_FROM_CPUID4(int ecx) // IN
+{
+   uint32 eax;
+#if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler.
+   uint32 ebx;
+
+   __asm__ __volatile__(
+      "movl %%ebx, %1"  "\n\t"
+      "cpuid"           "\n\t"
+      "xchgl %%ebx, %1"
+      : "=a" (eax), "=&rm" (ebx), "=c" (ecx)
+      : "a" (4), "c" (ecx)
+      : "memory", "%edx"
+   );
+#else
+
+   __asm__ __volatile__(
+      "cpuid"
+      : "=a" (eax), "=c" (ecx)
+      : "a" (4), "c" (ecx)
+      : "memory", "%ebx", "%edx"
+   );
+#endif
+
+   return eax;
+}
+
+#elif defined(_MSC_VER) // } {
+static INLINE  uint8
+INB(uint16 port) 
+{
+   return (uint8)_inp(port);
+}
+static INLINE void
+OUTB(uint16 port, uint8 value)
+{
+   _outp(port, value);
+}
+static INLINE uint16
+INW(uint16 port)
+{
+   return _inpw(port);
+}
+static INLINE void
+OUTW(uint16 port, uint16 value)
+{
+   _outpw(port, value);
+}
+static INLINE  uint32
+IN32(uint16 port) 
+{
+   return _inpd(port);
+}
+static INLINE void 
+OUT32(uint16 port, uint32 value)
+{
+   _outpd(port, value);
+}
+
+#ifndef VM_X86_64
+#ifdef NEAR
+#undef NEAR
+#endif
+
+#define GET_CURRENT_EIP(_eip) do { \
+   __asm call NEAR PTR $+5 \
+   __asm pop eax \
+   __asm mov _eip, eax \
+} while (0)
+#endif
+
+static INLINE void
+__GET_CPUID(int input, CPUIDRegs *regs)
+{
+#ifdef VM_X86_64
+   __cpuid((unsigned int *)regs, input);
+#else
+   __asm push esi
+   __asm push ebx
+   __asm push ecx
+   __asm push edx
+
+   __asm mov  eax, input
+   __asm mov  esi, regs
+   __asm _emit 0x0f __asm _emit 0xa2
+   __asm mov 0x0[esi], eax
+   __asm mov 0x4[esi], ebx
+   __asm mov 0x8[esi], ecx
+   __asm mov 0xC[esi], edx
+
+   __asm pop edx
+   __asm pop ecx
+   __asm pop ebx
+   __asm pop esi
+#endif
+}
+
+#ifdef VM_X86_64
+
+/*
+ * No inline assembly in Win64. Implemented in bora/lib/user in
+ * cpuidMasm64.asm.
+ */
+
+extern void
+__GET_CPUID2(int inputEax, int inputEcx, CPUIDRegs *regs);
+
+#else // VM_X86_64
+
+static INLINE void
+__GET_CPUID2(int inputEax, int inputEcx, CPUIDRegs *regs)
+{
+   __asm push esi
+   __asm push ebx
+   __asm push ecx
+   __asm push edx
+
+   __asm mov  eax, inputEax
+   __asm mov  ecx, inputEcx
+   __asm mov  esi, regs
+   __asm _emit 0x0f __asm _emit 0xa2
+   __asm mov 0x0[esi], eax
+   __asm mov 0x4[esi], ebx
+   __asm mov 0x8[esi], ecx
+   __asm mov 0xC[esi], edx
+
+   __asm pop edx
+   __asm pop ecx
+   __asm pop ebx
+   __asm pop esi
+}
+#endif
+
+static INLINE uint32
+__GET_EAX_FROM_CPUID(int input)
+{
+#ifdef VM_X86_64
+   CPUIDRegs regs;
+   __cpuid((unsigned int *)&regs, input);
+   return regs.eax;
+#else
+   uint32 output;
+
+   //NOT_TESTED();
+   __asm push ebx
+   __asm push ecx
+   __asm push edx
+
+   __asm mov  eax, input
+   __asm _emit 0x0f __asm _emit 0xa2
+   __asm mov  output, eax
+
+   __asm pop edx
+   __asm pop ecx
+   __asm pop ebx
+
+   return output;
+#endif
+}
+
+static INLINE uint32
+__GET_EBX_FROM_CPUID(int input)
+{
+#ifdef VM_X86_64
+   CPUIDRegs regs;
+   __cpuid((unsigned int *)&regs, input);
+   return regs.ebx;
+#else
+   uint32 output;
+
+   //NOT_TESTED();
+   __asm push ebx
+   __asm push ecx
+   __asm push edx
+
+   __asm mov  eax, input
+   __asm _emit 0x0f __asm _emit 0xa2
+   __asm mov  output, ebx
+
+   __asm pop edx
+   __asm pop ecx
+   __asm pop ebx
+
+   return output;
+#endif
+}
+
+static INLINE uint32
+__GET_ECX_FROM_CPUID(int input)
+{
+#ifdef VM_X86_64
+   CPUIDRegs regs;
+   __cpuid((unsigned int *)&regs, input);
+   return regs.ecx;
+#else
+   uint32 output;
+
+   //NOT_TESTED();
+   __asm push ebx
+   __asm push ecx
+   __asm push edx
+
+   __asm mov  eax, input
+   __asm _emit 0x0f __asm _emit 0xa2
+   __asm mov  output, ecx
+
+   __asm pop edx
+   __asm pop ecx
+   __asm pop ebx
+
+   return output;
+#endif
+}
+
+static INLINE uint32
+__GET_EDX_FROM_CPUID(int input)
+{
+#ifdef VM_X86_64
+   CPUIDRegs regs;
+   __cpuid((unsigned int *)&regs, input);
+   return regs.edx;
+#else
+   uint32 output;
+
+   //NOT_TESTED();
+   __asm push ebx
+   __asm push ecx
+   __asm push edx
+
+   __asm mov  eax, input
+   __asm _emit 0x0f __asm _emit 0xa2
+   __asm mov  output, edx
+
+   __asm pop edx
+   __asm pop ecx
+   __asm pop ebx
+
+   return output;
+#endif
+}
+
+#ifdef VM_X86_64
+
+/*
+ * No inline assembly in Win64. Implemented in bora/lib/user in
+ * cpuidMasm64.asm.
+ */
+
+extern uint32
+__GET_EAX_FROM_CPUID4(int inputEcx);
+
+#else // VM_X86_64
+
+static INLINE uint32
+__GET_EAX_FROM_CPUID4(int inputEcx)
+{
+   uint32 output;
+
+   //NOT_TESTED();
+   __asm push ebx
+   __asm push ecx
+   __asm push edx
+
+   __asm mov  eax, 4
+   __asm mov  ecx, inputEcx
+   __asm _emit 0x0f __asm _emit 0xa2
+   __asm mov  output, eax
+
+   __asm pop edx
+   __asm pop ecx
+   __asm pop ebx
+
+   return output;
+}
+
+#endif // VM_X86_64
+
+#else // }
+#error 
+#endif
+
+#define CPUID_FOR_SIDE_EFFECTS() ((void)__GET_EAX_FROM_CPUID(0))
+
+static INLINE void
+__GET_CPUID4(int inputEcx, CPUIDRegs *regs)
+{
+   __GET_CPUID2(4, inputEcx, regs);
+}
+
+/* The first parameter is used as an rvalue and then as an lvalue. */
+#define GET_CPUID(_ax, _bx, _cx, _dx) { \
+   CPUIDRegs regs;                      \
+   __GET_CPUID(_ax, &regs);             \
+   _ax = regs.eax;                      \
+   _bx = regs.ebx;                      \
+   _cx = regs.ecx;                      \
+   _dx = regs.edx;                      \
+}
+
+
+/* Sequence recommended by Intel for the Pentium 4. */
+#define INTEL_MICROCODE_VERSION() (             \
+   __SET_MSR(MSR_BIOS_SIGN_ID, 0),              \
+   __GET_EAX_FROM_CPUID(1),                     \
+   __GET_MSR(MSR_BIOS_SIGN_ID))
+
+
+#ifdef _MSC_VER   
+static INLINE int
+ffs(uint32 bitVector)
+{
+   int idx;
+   if (!bitVector) {
+      return 0;
+   }
+#ifdef VM_X86_64
+   _BitScanForward((unsigned long*)&idx, (unsigned long)bitVector);
+#else
+   __asm bsf eax, bitVector
+   __asm mov idx, eax
+#endif
+   return idx+1;
+}
+#endif
+
+#ifdef __GNUC__
+static INLINE void *
+uint16set(void *dst, uint16 val, size_t count)
+{
+   int dummy0;
+   int dummy1;
+
+   __asm__ __volatile__("\t"
+                        "cld"            "\n\t"
+                        "rep ; stosw"    "\n"
+                        : "=c" (dummy0), "=D" (dummy1)
+                        : "0" (count), "1" (dst), "a" (val)
+                        : "memory", "cc"
+      );
+
+   return dst;
+}
+
+static INLINE void *
+uint32set(void *dst, uint32 val, size_t count)
+{
+   int dummy0;
+   int dummy1;
+
+   __asm__ __volatile__("\t"
+                        "cld"            "\n\t"
+                        "rep ; stosl"    "\n"
+                        : "=c" (dummy0), "=D" (dummy1)
+                        : "0" (count), "1" (dst), "a" (val)
+                        : "memory", "cc"
+      );
+
+   return dst;
+}
+
+#elif defined(_MSC_VER)
+
+static INLINE void *
+uint16set(void *dst, uint16 val, size_t count)
+{
+#ifdef VM_X86_64
+   __stosw((uint16*)dst, val, count);
+#else
+   __asm { pushf;
+           mov ax, val;
+           mov ecx, count;
+           mov edi, dst;
+           cld;
+           rep stosw;
+           popf;
+   }
+#endif
+   return dst;
+}
+
+static INLINE void *
+uint32set(void *dst, uint32 val, size_t count)
+{
+#ifdef VM_X86_64
+   __stosd((unsigned long*)dst, (unsigned long)val, count);
+#else
+   __asm { pushf;
+           mov eax, val;
+           mov ecx, count;
+           mov edi, dst;
+           cld;
+           rep stosd;
+           popf;
+   }
+#endif
+   return dst;
+}
+
+#else
+#error "No compiler defined for uint*set"
+#endif
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Bswap32 --
+ *
+ *      Swap the 4 bytes of "v" as follows: 3210 -> 0123.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE uint32
+Bswap32(uint32 v) // IN
+{
+#ifdef __GNUC__ // {
+   /* Checked against the Intel manual and GCC. --hpreg */
+   __asm__(
+      "bswap %0"
+      : "=r" (v)
+      : "0" (v)
+   );
+   return v;
+#else // } {
+   return    (v >> 24)
+          | ((v >>  8) & 0xFF00)
+          | ((v & 0xFF00) <<  8)
+          |  (v << 24)          ;
+#endif // }
+}
+#define Bswap Bswap32
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Bswap64 --
+ *
+ *      Swap the 8 bytes of "v" as follows: 76543210 -> 01234567.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE uint64
+Bswap64(uint64 v) // IN
+{
+   return ((uint64)Bswap((uint32)v) << 32) | Bswap((uint32)(v >> 32));
+}
+
+
+#ifdef __GNUC__ // {
+/*
+ * COMPILER_MEM_BARRIER prevents the compiler from re-ordering memory
+ * references accross the barrier.  NOTE: It does not generate any
+ * instruction, so the CPU is free to do whatever it wants to...
+ */
+#define COMPILER_MEM_BARRIER() __asm__ __volatile__ ("": : :"memory")
+#elif defined(_MSC_VER) // } {
+#define COMPILER_MEM_BARRIER() _ReadWriteBarrier()
+#endif // }
+
+
+/*
+ * PAUSE is a P4 instruction that improves spinlock power+performance;
+ * on non-P4 IA32 systems, the encoding is interpreted as a REPZ-NOP.
+ * Use volatile to avoid NOP removal.
+ */
+static INLINE void
+PAUSE(void)
+#ifdef __GNUC__
+{
+   __asm__ __volatile__( "pause" :);
+}
+#elif defined(_MSC_VER)
+#ifdef VM_X86_64
+{
+   _mm_pause();
+}
+#else /* VM_X86_64 */
+#pragma warning( disable : 4035)
+{
+   __asm _emit 0xf3 __asm _emit 0x90
+}
+#pragma warning (default: 4035)
+#endif /* VM_X86_64 */
+#else  /* __GNUC__  */
+#error No compiler defined for PAUSE
+#endif
+
+
+/*
+ * Checked against the Intel manual and GCC --hpreg
+ *
+ * volatile because the tsc always changes without the compiler knowing it.
+ */
+static INLINE uint64
+RDTSC(void)
+#ifdef __GNUC__
+{
+#ifdef VM_X86_64
+   uint64 tscLow;
+   uint64 tscHigh;
+
+   __asm__ __volatile__(
+      "rdtsc"
+      : "=a" (tscLow), "=d" (tscHigh)
+   );
+
+   return tscHigh << 32 | tscLow;
+#else
+   uint64 tim;
+
+   __asm__ __volatile__(
+      "rdtsc"
+      : "=A" (tim)
+   );
+
+   return tim;
+#endif
+}
+#elif defined(_MSC_VER)
+#ifdef VM_X86_64
+{
+   return __rdtsc();
+}
+#else
+#pragma warning( disable : 4035)
+{
+   __asm _emit 0x0f __asm _emit 0x31
+}
+#pragma warning (default: 4035)
+#endif /* VM_X86_64 */
+#else  /* __GNUC__  */
+#error No compiler defined for RDTSC
+#endif /* __GNUC__  */
+
+#endif
diff --git a/open-vm-tools/modules/solaris/vmhgfs/vm_basic_asm_x86.h b/open-vm-tools/modules/solaris/vmhgfs/vm_basic_asm_x86.h
new file mode 100644 (file)
index 0000000..180ab53
--- /dev/null
@@ -0,0 +1,498 @@
+/*********************************************************
+ * Copyright (C) 1998-2003 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * vm_basic_asm_x86.h
+ *
+ *     Basic IA32 asm macros
+ */
+
+#ifndef _VM_BASIC_ASM_X86_H_
+#define _VM_BASIC_ASM_X86_H_
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMMON
+#define INCLUDE_ALLOW_VMNIXMOD
+#define INCLUDE_ALLOW_VMK_MODULE
+#define INCLUDE_ALLOW_VMKERNEL
+#define INCLUDE_ALLOW_DISTRIBUTE
+#define INCLUDE_ALLOW_VMCORE
+#define INCLUDE_ALLOW_VMIROM
+#include "includeCheck.h"
+
+#ifdef VM_X86_64
+/*
+ * The gcc inline asm uses the "A" constraint which differs in 32 & 64
+ * bit mode.  32 bit means eax and edx, 64 means rax or rdx.
+ */
+#error "x86-64 not supported"
+#endif
+
+
+
+
+/*
+ * from linux: usr/include/asm/io.h
+ */
+#ifdef __GNUC__
+#ifndef __SLOW_DOWN_IO
+#ifdef SLOW_IO_BY_JUMPING
+#define __SLOW_DOWN_IO __asm__ __volatile__("jmp 1f\n1:\tjmp 1f\n1:")
+#else
+#define __SLOW_DOWN_IO __asm__ __volatile__("outb %al,$0x80")
+#endif
+#endif
+#elif _MSC_VER
+#ifdef SLOW_IO_BY_JUMPING
+#define __SLOW_DOWN_IO __asm jmp SHORT $+2 __asm  jmp SHORT $+2
+#else
+#define __SLOW_DOWN_IO __asm out 80h,al
+#endif
+#else
+#error
+#endif
+
+#ifdef REALLY_SLOW_IO
+#define SLOW_DOWN_IO { __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; }
+#else
+#define SLOW_DOWN_IO __SLOW_DOWN_IO
+#endif
+
+/*
+ * FXSAVE/FXRSTOR
+ *     save/restore SIMD/MMX fpu state
+ *
+ * The pointer passed in must be 16-byte aligned.
+ *
+ * Intel and AMD processors behave differently w.r.t. fxsave/fxrstor. Intel
+ * processors unconditionally save the exception pointer state (instruction
+ * ptr., data ptr., and error instruction opcode). FXSAVE_ES1 and FXRSTOR_ES1
+ * work correctly for Intel processors.
+ *
+ * AMD processors only save the exception pointer state if ES=1. This leads to a
+ * security hole whereby one process/VM can inspect the state of another process
+ * VM. The AMD recommended workaround involves clobbering the exception pointer
+ * state unconditionally, and this is implemented in FXRSTOR_AMD_ES0. Note that
+ * FXSAVE_ES1 will only save the exception pointer state for AMD processors if
+ * ES=1.
+ *
+ * The workaround (FXRSTOR_AMD_ES0) only costs 1 cycle more than just doing an
+ * fxrstor, on both AMD Opteron and Intel Core CPUs.
+ */
+#if defined(__GNUC__)
+static INLINE void 
+FXSAVE_ES1(uint8 *save)
+{
+   __asm__ __volatile__ ("fxsave %0\n" : "=m" (*save) : : "memory");
+}
+
+static INLINE void 
+FXRSTOR_ES1(const uint8 *load)
+{
+   __asm__ __volatile__ ("fxrstor %0\n" : : "m" (*load) : "memory");
+}
+
+static INLINE void 
+FXRSTOR_AMD_ES0(const uint8 *load)
+{
+   uint64 dummy = 0;
+      
+   __asm__ __volatile__ 
+       ("fnstsw  %%ax    \n"     // Grab x87 ES bit
+        "bt      $7,%%ax \n"     // Test ES bit
+        "jnc     1f      \n"     // Jump if ES=0
+        "fnclex          \n"     // ES=1. Clear it so fild doesn't trap
+        "1:              \n"
+        "ffree   %%st(7) \n"     // Clear tag bit - avoid poss. stack overflow
+        "fildl   %0      \n"     // Dummy Load from "safe address" changes all
+                                 // x87 exception pointers.
+        "fxrstor %1      \n"
+        :  
+        : "m" (dummy), "m" (*load)
+        : "ax", "memory");
+}
+#endif /* __GNUC__ */
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Div643232 --
+ *
+ *    Unsigned integer division:
+ *       The dividend is 64-bit wide
+ *       The divisor  is 32-bit wide
+ *       The quotient is 32-bit wide
+ *
+ *    Use this function if you are certain that:
+ *    o Either the quotient will fit in 32 bits,
+ *    o Or your code is ready to handle a #DE exception indicating overflow.
+ *    If that is not the case, then use Div643264(). --hpreg
+ *
+ * Results:
+ *    Quotient and remainder
+ *
+ * Side effects:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+#if defined(__GNUC__)
+
+static INLINE void
+Div643232(uint64 dividend,   // IN
+          uint32 divisor,    // IN
+          uint32 *quotient,  // OUT
+          uint32 *remainder) // OUT
+{
+   /* Checked against the Intel manual and GCC --hpreg */
+   __asm__(
+      "divl %4"
+      : "=a" (*quotient),
+        "=d" (*remainder)
+      : "0" ((uint32)dividend),
+        "1" ((uint32)(dividend >> 32)),
+        "rm" (divisor)
+      : "cc"
+   );
+}
+
+#elif _MSC_VER
+
+static INLINE void
+Div643232(uint64 dividend,   // IN
+          uint32 divisor,    // IN
+          uint32 *quotient,  // OUT
+          uint32 *remainder) // OUT
+{
+   /* Written and tested by mann, checked by dbudko and hpreg */
+   __asm {
+      mov  eax, DWORD PTR [dividend]
+      mov  edx, DWORD PTR [dividend+4]
+      div  DWORD PTR [divisor]
+      mov  edi, DWORD PTR [quotient]
+      mov  [edi], eax
+      mov  edi, DWORD PTR [remainder]
+      mov  [edi], edx
+   }
+}
+
+#else
+#error No compiler defined for Div643232
+#endif
+
+
+#if defined(__GNUC__)
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Div643264 --
+ *
+ *    Unsigned integer division:
+ *       The dividend is 64-bit wide
+ *       The divisor  is 32-bit wide
+ *       The quotient is 64-bit wide --hpreg
+ *
+ * Results:
+ *    Quotient and remainder
+ *
+ * Side effects:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE void
+Div643264(uint64 dividend,   // IN
+          uint32 divisor,    // IN
+          uint64 *quotient,  // OUT
+          uint32 *remainder) // OUT
+{
+   uint32 hQuotient;
+   uint32 lQuotient;
+
+   /* Checked against the Intel manual and GCC --hpreg */
+   __asm__(
+      "divl %5"        "\n\t"
+      "movl %%eax, %0" "\n\t"
+      "movl %4, %%eax" "\n\t"
+      "divl %5"
+      : "=&rm" (hQuotient),
+        "=a" (lQuotient),
+        "=d" (*remainder)
+      : "1" ((uint32)(dividend >> 32)),
+        "g" ((uint32)dividend),
+        "rm" (divisor),
+        "2" (0)
+      : "cc"
+   );
+   *quotient = (uint64)hQuotient << 32 | lQuotient;
+}
+#endif
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Mul64x3264 --
+ *
+ *    Unsigned integer by fixed point multiplication:
+ *       Unsigned 64-bit integer multiplicand.
+ *       Unsigned 32-bit fixed point multiplier, represented as
+ *         multiplier >> shift, where shift < 64.
+ *       Unsigned 64-bit integer product.
+ *
+ * Implementation:
+ *    Multiply 64x32 bits to yield a full 96-bit product.
+ *    Shift right by shift.
+ *    Return the low-order 64 bits of the result.
+ *
+ * Result:
+ *    Product
+ *
+ * Side effects:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+#if defined(__GNUC__)
+
+static INLINE uint64
+Mul64x3264(uint64 multiplicand, uint32 multiplier, uint32 shift)
+{
+   uint64 result;
+   uint32 tmp1, tmp2;
+   // ASSERT(shift >= 0 && shift < 64);
+  
+   /*
+    * Written and tested by mann, improved with suggestions by hpreg.
+    *
+    * The main improvement over the previous version is that the test
+    * of shift against 32 is moved out of the asm and into C code.
+    * This lets the compiler delete the test and one of the
+    * alternative code sequences in the case where shift is a
+    * constant.  It also lets us use the best code sequence in each
+    * alternative, rather than a compromise.  The downside is that in
+    * the non-constant case, this version takes slightly more code
+    * space.
+    *
+    * Note on the constraints: We don't really want multiplicand to
+    * start in %edx:%eax as the =A constraint dictates; in fact, we'd
+    * prefer any *other* two registers.  But gcc doesn't have
+    * constraint syntax for any other register pair, and trying to
+    * constrain ((uint32) multiplicand) to one place and (multiplicand
+    * >> 32) to another generates *really* bad code -- gcc is just not
+    * smart enough, at least in the version we are currently using.
+    */
+   if (shift < 32) {
+      __asm__("mov   %%eax, %2     \n\t" // Save lo(multiplicand) in tmp2
+              "mov   %%edx, %%eax  \n\t" // Get hi(multiplicand)
+              "mull  %4            \n\t" // p2 = hi(multiplicand) * multiplier
+              "xchg  %%eax, %2     \n\t" // Save lo(p2) in tmp2, get lo(multiplicand)
+              "mov   %%edx, %1     \n\t" // Save hi(p2) in tmp1
+              "mull  %4            \n\t" // p1 = lo(multiplicand) * multiplier
+              "addl  %2, %%edx     \n\t" // hi(p1) += lo(p2)
+              "adcl  $0, %1        \n\t" // hi(p2) += carry from previous step
+              "shrdl %%edx, %%eax  \n\t" // result = hi(p2):hi(p1):lo(p1) >> shift
+              "shrdl %1, %%edx"
+              : "=A"  (result),
+                "=&r" (tmp1),            // use in shrdl requires it to be a register
+                "=&r" (tmp2)             // could be "=&rm" but "m" is slower
+              : "0"   (multiplicand),
+                "rm"  (multiplier),
+                "c"   (shift)
+              : "cc"
+         );
+   } else {
+      __asm__("mov   %%edx, %2     \n\t" // Save hi(multiplicand) in tmp2
+              "mull  %4            \n\t" // p1 = lo(multiplicand) * multiplier
+              "mov   %%edx, %1     \n\t" // Save hi(p1) in tmp1
+              "mov   %2, %%eax     \n\t" // Discard lo(p1), get hi(multiplicand)
+              "mull  %4            \n\t" // p2 = hi(multiplicand) * multiplier
+              "addl  %1, %%eax     \n\t" // lo(p2) += hi(p1)
+              "adcl  $0, %%edx     \n\t" // hi(p2) += carry from previous step
+              "shrdl %%edx, %%eax  \n\t" // result = p2 >> (shift & 31)
+              "shrl  %%cl, %%edx"
+              : "=A"  (result),
+                "=&r" (tmp1),            // could be "=&rm" but "m" is slower
+                "=&r" (tmp2)             // could be "=&rm" but "m" is slower
+              : "0"   (multiplicand),
+                "rm"  (multiplier),
+                "c"   (shift)
+              : "cc"
+         );
+   }
+   return result;
+}
+
+#elif _MSC_VER
+#pragma warning(disable: 4035)
+
+static INLINE uint64
+Mul64x3264(uint64 multiplicand, uint32 multiplier, uint32 shift)
+{
+   // ASSERT(shift >= 0 && shift < 64);
+
+   /* Written and tested by mann, checked by dbudko and hpreg */
+   __asm {
+      mov  eax, DWORD PTR [multiplicand+4]  // Get hi(multiplicand)
+      mul  DWORD PTR [multiplier]           // p2 = hi(multiplicand) * multiplier
+      mov  ecx, eax                         // Save lo(p2)
+      mov  ebx, edx                         // Save hi(p2)
+      mov  eax, DWORD PTR [multiplicand]    // Get lo(multiplicand)
+      mul  DWORD PTR [multiplier+0]         // p1 = lo(multiplicand) * multiplier
+      add  edx, ecx                         // hi(p1) += lo(p2)
+      adc  ebx, 0                           // hi(p2) += carry from previous step
+      mov  ecx, DWORD PTR [shift]           // Get shift
+      cmp  ecx, 32                          // shift < 32?
+      jl   SHORT l2                         // Go if so
+      mov  eax, edx                         // result = hi(p2):hi(p1) >> (shift & 31)
+      mov  edx, ebx
+      shrd eax, edx, cl
+      shr  edx, cl
+      jmp  SHORT l3
+   l2:
+      shrd eax, edx, cl                     // result = hi(p2):hi(p1):lo(p1) >> shift
+      shrd edx, ebx, cl
+   l3:
+   }
+   // return with result in edx:eax
+}
+
+#pragma warning(default: 4035)
+#else
+#error No compiler defined for Mul64x3264
+#endif
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Muls64x32s64 --
+ *
+ *    Signed integer by fixed point multiplication:
+ *       Signed 64-bit integer multiplicand.
+ *       Unsigned 32-bit fixed point multiplier, represented as
+ *         multiplier >> shift, where shift < 64.
+ *       Signed 64-bit integer product.
+ *
+ * Implementation:
+ *    Multiply 64x32 bits to yield a full 96-bit product.
+ *    Shift right by the location of the binary point.
+ *    Return the low-order 64 bits of the result.
+ *
+ * Result:
+ *    Product
+ *
+ * Side effects:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+#if defined(__GNUC__)
+
+static INLINE int64
+Muls64x32s64(int64 multiplicand, uint32 multiplier, uint32 shift)
+{
+   int64 result;
+   uint32 tmp1, tmp2;
+   // ASSERT(shift >= 0 && shift < 64);
+
+   /* Written and tested by mann, checked by dbudko and hpreg */
+   /* XXX hpreg suggested some improvements that we haven't converged on yet */
+   __asm__("mov   %%eax, %2\n\t"      // Save lo(multiplicand)
+           "mov   %%edx, %%eax\n\t"   // Get hi(multiplicand)
+           "test  %%eax, %%eax\n\t"   // Check sign of multiplicand
+           "jl    0f\n\t"             // Go if negative
+           "mull  %4\n\t"             // p2 = hi(multiplicand) * multiplier
+           "jmp   1f\n"
+        "0:\n\t"
+           "mull  %4\n\t"             // p2 = hi(multiplicand) * multiplier
+           "sub   %4, %%edx\n"        // hi(p2) += -1 * multiplier
+        "1:\n\t"
+           "xchg  %%eax, %2\n\t"      // Save lo(p2), get lo(multiplicand)
+           "mov   %%edx, %1\n\t"      // Save hi(p2)
+           "mull  %4\n\t"             // p1 = lo(multiplicand) * multiplier
+           "addl  %2, %%edx\n\t"      // hi(p1) += lo(p2)
+           "adcl  $0, %1\n\t"         // hi(p2) += carry from previous step
+           "cmpl  $32, %%ecx\n\t"     // shift < 32?
+           "jl    2f\n\t"             // Go if so
+           "mov   %%edx, %%eax\n\t"   // result = hi(p2):hi(p1) >> (shift & 31)
+           "mov   %1, %%edx\n\t"
+           "shrdl %%edx, %%eax\n\t"
+           "sarl  %%cl, %%edx\n\t"
+           "jmp   3f\n"
+        "2:\n\t"
+           "shrdl %%edx, %%eax\n\t"   // result = hi(p2):hi(p1):lo(p1) >> shift
+           "shrdl %1, %%edx\n"
+        "3:\n\t"
+           : "=A" (result), "=&r" (tmp1), "=&r" (tmp2)
+           : "0" (multiplicand), "rm" (multiplier), "c" (shift)
+           : "cc");
+   return result;
+}
+
+#elif _MSC_VER
+#pragma warning(disable: 4035)
+
+static INLINE int64
+Muls64x32s64(int64 multiplicand, uint32 multiplier, uint32 shift)
+{
+   //ASSERT(shift >= 0 && shift < 64);
+  
+   /* Written and tested by mann, checked by dbudko and hpreg */
+   __asm {
+      mov  eax, DWORD PTR [multiplicand+4]  // Get hi(multiplicand)
+      test eax, eax                         // Check sign of multiplicand
+      jl   SHORT l0                         // Go if negative
+      mul  DWORD PTR [multiplier]           // p2 = hi(multiplicand) * multiplier
+      jmp  SHORT l1
+   l0:
+      mul  DWORD PTR [multiplier]           // p2 = hi(multiplicand) * multiplier
+      sub  edx, DWORD PTR [multiplier]      // hi(p2) += -1 * multiplier
+   l1:
+      mov  ecx, eax                         // Save lo(p2)
+      mov  ebx, edx                         // Save hi(p2)
+      mov  eax, DWORD PTR [multiplicand]    // Get lo(multiplicand)
+      mul  DWORD PTR [multiplier]           // p1 = lo(multiplicand) * multiplier
+      add  edx, ecx                         // hi(p1) += lo(p2)
+      adc  ebx, 0                           // hi(p2) += carry from previous step
+      mov  ecx, DWORD PTR [shift]           // Get shift
+      cmp  ecx, 32                          // shift < 32?
+      jl   SHORT l2                         // Go if so
+      mov  eax, edx                         // result = hi(p2):hi(p1) >> (shift & 31)
+      mov  edx, ebx
+      shrd eax, edx, cl
+      sar  edx, cl
+      jmp  SHORT l3
+   l2:
+      shrd eax, edx, cl                     // result = hi(p2):hi(p1):lo(p1) << shift
+      shrd edx, ebx, cl
+   l3:
+   }
+   // return with result in edx:eax
+}
+
+#pragma warning(default: 4035)
+#else
+#error No compiler defined for Muls64x32s64
+#endif
+
+
+#endif
diff --git a/open-vm-tools/modules/solaris/vmhgfs/vm_basic_asm_x86_64.h b/open-vm-tools/modules/solaris/vmhgfs/vm_basic_asm_x86_64.h
new file mode 100644 (file)
index 0000000..60e7bb5
--- /dev/null
@@ -0,0 +1,334 @@
+/*********************************************************
+ * Copyright (C) 1998-2004 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * vm_basic_asm_x86_64.h
+ *
+ *     Basic x86_64 asm macros.
+ */
+
+#ifndef _VM_BASIC_ASM_X86_64_H_
+#define _VM_BASIC_ASM_X86_64_H_
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMMON
+#define INCLUDE_ALLOW_VMK_MODULE
+#define INCLUDE_ALLOW_VMKERNEL
+#define INCLUDE_ALLOW_DISTRIBUTE
+#define INCLUDE_ALLOW_VMCORE
+#define INCLUDE_ALLOW_VMNIXMOD
+#include "includeCheck.h"
+
+#ifndef VM_X86_64
+#error "This file is x86-64 only!"
+#endif
+
+#ifdef _MSC_VER
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+uint64 _umul128(uint64 multiplier, uint64 multiplicand, 
+                uint64 *highProduct);
+int64 _mul128(int64 multiplier, int64 multiplicand, 
+              int64 *highProduct);
+uint64 __shiftright128(uint64 lowPart, uint64 highPart, uint8 shift);
+#ifdef __cplusplus
+}
+#endif
+
+#pragma intrinsic(_umul128, _mul128, __shiftright128)
+
+#endif // _MSC_VER
+
+/*
+ * FXSAVE/FXRSTOR
+ *     save/restore SIMD/MMX fpu state
+ *
+ * The pointer passed in must be 16-byte aligned.
+ *
+ * Intel and AMD processors behave differently w.r.t. fxsave/fxrstor. Intel
+ * processors unconditionally save the exception pointer state (instruction
+ * ptr., data ptr., and error instruction opcode). FXSAVE_ES1 and FXRSTOR_ES1
+ * work correctly for Intel processors.
+ *
+ * AMD processors only save the exception pointer state if ES=1. This leads to a
+ * security hole whereby one process/VM can inspect the state of another process
+ * VM. The AMD recommended workaround involves clobbering the exception pointer
+ * state unconditionally, and this is implemented in FXRSTOR_AMD_ES0. Note that
+ * FXSAVE_ES1 will only save the exception pointer state for AMD processors if
+ * ES=1.
+ *
+ * The workaround (FXRSTOR_AMD_ES0) only costs 1 cycle more than just doing an
+ * fxrstor, on both AMD Opteron and Intel Core CPUs.
+ */
+#if defined(__GNUC__)
+
+static INLINE void 
+FXSAVE_ES1(uint8 *save)
+{
+   __asm__ __volatile__ ("fxsaveq %0  \n" : "=m" (*save) : : "memory");
+}
+
+static INLINE void 
+FXSAVE_COMPAT_ES1(uint8 *save)
+{
+   __asm__ __volatile__ ("fxsave %0  \n" : "=m" (*save) : : "memory");
+}
+
+static INLINE void 
+FXRSTOR_ES1(const uint8 *load)
+{
+   __asm__ __volatile__ ("fxrstorq %0 \n" : : "m" (*load) : "memory");
+}
+
+static INLINE void 
+FXRSTOR_COMPAT_ES1(const uint8 *load)
+{
+   __asm__ __volatile__ ("fxrstor %0 \n" : : "m" (*load) : "memory");
+}
+
+static INLINE void 
+FXRSTOR_AMD_ES0(const uint8 *load)
+{
+   uint64 dummy = 0;
+      
+   __asm__ __volatile__ 
+       ("fnstsw  %%ax    \n"     // Grab x87 ES bit
+        "bt      $7,%%ax \n"     // Test ES bit
+        "jnc     1f      \n"     // Jump if ES=0
+        "fnclex          \n"     // ES=1. Clear it so fild doesn't trap
+        "1:              \n"
+        "ffree   %%st(7) \n"     // Clear tag bit - avoid poss. stack overflow
+        "fildl   %0      \n"     // Dummy Load from "safe address" changes all
+                                 // x87 exception pointers.
+        "fxrstorq %1 \n"
+        :
+        : "m" (dummy), "m" (*load)
+        : "ax", "memory");
+}
+
+#endif /* __GNUC__ */
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Mul64x3264 --
+ *
+ *    Unsigned integer by fixed point multiplication:
+ *       result = multiplicand * multiplier >> shift
+ * 
+ *       Unsigned 64-bit integer multiplicand.
+ *       Unsigned 32-bit fixed point multiplier, represented as
+ *         multiplier >> shift, where shift < 64.
+ *       Unsigned 64-bit integer product.
+ *
+ * Implementation:
+ *    Multiply 64x64 bits to yield a full 128-bit product.
+ *    Shift result in RDX:RAX right by "shift".
+ *    Return the low-order 64 bits of the above.
+ *
+ * Result:
+ *    Product
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+#if defined(__GNUC__)
+
+static INLINE uint64
+Mul64x3264(uint64 multiplicand,
+           uint32 multiplier,
+           uint32 shift)
+{
+   uint64 result, dummy;
+   const uint64 multiplier64 = multiplier;
+
+   __asm__("mulq    %3      \n\t"
+           "shrdq   %1, %0  \n\t"
+           : "=a" (result),
+             "=d" (dummy)
+           : "0"  (multiplier64),
+             "rm" (multiplicand),
+         "c"  (shift)
+           : "cc");
+   return result;
+}
+
+#elif defined(_MSC_VER)
+
+static INLINE uint64
+Mul64x3264(uint64 multiplicand, uint32 multiplier, uint32 shift)
+{
+   uint64 tmplo, tmphi;
+   tmplo = _umul128(multiplicand, multiplier, &tmphi);
+   return __shiftright128(tmplo, tmphi, (uint8) shift);
+}
+
+#endif
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Muls64x32s64 --
+ *
+ *    Signed integer by fixed point multiplication:
+ *       result = multiplicand * multiplier >> shift
+ * 
+ *       Signed 64-bit integer multiplicand.
+ *       Unsigned 32-bit fixed point multiplier, represented as
+ *         multiplier >> shift, where shift < 64.
+ *       Signed 64-bit integer product.
+ *
+ * Implementation:
+ *    Multiply 64x64 bits to yield a full 128-bit product.
+ *    Shift result in RDX:RAX right by "shift".
+ *    Return the low-order 64 bits of the above.
+ *
+ *    Note: using an unsigned shift instruction is correct because
+ *    shift < 64 and we return only the low 64 bits of the shifted
+ *    result.
+ *
+ * Result:
+ *    Product
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+#if defined(__GNUC__)
+
+static inline int64
+Muls64x32s64(int64 multiplicand, uint32 multiplier, uint32 shift)
+{
+   int64 result, dummy;
+   const int64 multiplier64 = multiplier;
+
+   __asm__("imulq   %3      \n\t"
+       "shrdq   %1, %0  \n\t"
+       : "=a" (result),
+         "=d" (dummy)
+       : "0"  (multiplier64),
+         "rm" (multiplicand),
+         "c"  (shift)
+       : "cc");
+   return result;
+}
+
+#elif defined(_MSC_VER)
+
+static INLINE int64
+Muls64x32s64(int64 multiplicand, uint32 multiplier, uint32 shift)
+{
+   int64 tmplo, tmphi;
+   tmplo = _mul128(multiplicand, multiplier, &tmphi);
+   return __shiftright128(tmplo, tmphi, (uint8) shift);
+}
+
+#endif
+
+
+#if defined(__GNUC__)
+
+static INLINE void *
+uint64set(void *dst, uint64 val, uint64 count)
+{
+   int dummy0;
+   int dummy1;
+   __asm__ __volatile__("\t"
+                        "cld"            "\n\t"
+                        "rep ; stosq"    "\n"
+                        : "=c" (dummy0), "=D" (dummy1)
+                        : "0" (count), "1" (dst), "a" (val)
+                        : "memory", "cc");
+   return dst;
+}
+
+#endif
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Div643232 --
+ *
+ *    Unsigned integer division:
+ *       The dividend is 64-bit wide
+ *       The divisor  is 32-bit wide
+ *       The quotient is 32-bit wide
+ *
+ *    Use this function if you are certain that the quotient will fit in 32 bits,
+ *    If that is not the case, a #DE exception was generated in 32-bit version,
+ *    but not in this 64-bit version. So please be careful.
+ *
+ * Results:
+ *    Quotient and remainder
+ *
+ * Side effects:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+#if defined(__GNUC__) || defined(_MSC_VER)
+
+static INLINE void
+Div643232(uint64 dividend,   // IN
+          uint32 divisor,    // IN
+          uint32 *quotient,  // OUT
+          uint32 *remainder) // OUT
+{
+   *quotient = (uint32)(dividend / divisor);
+   *remainder = (uint32)(dividend % divisor);
+}
+
+#endif
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Div643264 --
+ *
+ *    Unsigned integer division:
+ *       The dividend is 64-bit wide
+ *       The divisor  is 32-bit wide
+ *       The quotient is 64-bit wide
+ *
+ * Results:
+ *    Quotient and remainder
+ *
+ * Side effects:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+#if defined(__GNUC__)
+
+static INLINE void
+Div643264(uint64 dividend,   // IN
+          uint32 divisor,    // IN
+          uint64 *quotient,  // OUT
+          uint32 *remainder) // OUT
+{
+   *quotient = dividend / divisor;
+   *remainder = dividend % divisor;
+}
+
+#endif
+
+#endif // _VM_BASIC_ASM_X86_64_H_
diff --git a/open-vm-tools/modules/solaris/vmhgfs/vm_basic_defs.h b/open-vm-tools/modules/solaris/vmhgfs/vm_basic_defs.h
new file mode 100644 (file)
index 0000000..18b1156
--- /dev/null
@@ -0,0 +1,608 @@
+/*********************************************************
+ * Copyright (C) 2003 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * vm_basic_defs.h --
+ *
+ *     Standard macros for VMware source code.
+ */
+
+#ifndef _VM_BASIC_DEFS_H_
+#define _VM_BASIC_DEFS_H_
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMMON
+#define INCLUDE_ALLOW_VMNIXMOD
+#define INCLUDE_ALLOW_VMKERNEL
+#define INCLUDE_ALLOW_VMKDRIVERS
+#define INCLUDE_ALLOW_VMK_MODULE
+#define INCLUDE_ALLOW_DISTRIBUTE
+#define INCLUDE_ALLOW_VMCORE
+#define INCLUDE_ALLOW_VMIROM
+#include "includeCheck.h"
+#include "vm_basic_types.h" // For INLINE.
+
+/* Checks for FreeBSD, filtering out VMKERNEL. */
+#define __IS_FREEBSD__ (!defined(VMKERNEL) && defined(__FreeBSD__))
+#define __IS_FREEBSD_VER__(ver) (__IS_FREEBSD__ && __FreeBSD_version >= (ver))
+
+#if defined _WIN32 && defined USERLEVEL
+   #include <stddef.h>  /*
+                         * We re-define offsetof macro from stddef, make 
+                         * sure that its already defined before we do it
+                         */
+   #include <windows.h>        // for Sleep() and LOWORD() etc.
+#endif
+
+
+/*
+ * Simple macros
+ */
+
+#if (defined __APPLE__ || defined __FreeBSD__) && \
+    (!defined KERNEL && !defined _KERNEL && !defined VMKERNEL && !defined __KERNEL__)
+#   include <stddef.h>
+#else
+// XXX the _WIN32 one matches that of VC++, to prevent redefinition warning
+// XXX the other one matches that of gcc3.3.3/glibc2.2.4 to prevent redefinition warnings
+#ifndef offsetof
+#ifdef _WIN32
+#define offsetof(s,m)   (size_t)&(((s *)0)->m)
+#else
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+#endif
+#endif // __APPLE__
+
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(a) (sizeof (a) / sizeof *(a))
+#endif
+
+#ifndef MIN
+#define MIN(_a, _b)   (((_a) < (_b)) ? (_a) : (_b))
+#endif
+
+/* The Solaris 9 cross-compiler complains about these not being used */
+#ifndef sun
+static INLINE int 
+Min(int a, int b)
+{
+   return a < b ? a : b;
+}
+#endif
+
+#ifndef MAX
+#define MAX(_a, _b)   (((_a) > (_b)) ? (_a) : (_b))
+#endif
+
+#ifndef sun
+static INLINE int 
+Max(int a, int b)
+{
+   return a > b ? a : b;
+}
+#endif
+
+#define ROUNDUP(x,y)           (((x) + (y) - 1) / (y) * (y))
+#define ROUNDDOWN(x,y)         ((x) / (y) * (y))
+#define ROUNDUPBITS(x, bits)   (((uintptr_t) (x) + MASK(bits)) & ~MASK(bits))
+#define ROUNDDOWNBITS(x, bits) ((uintptr_t) (x) & ~MASK(bits))
+#define CEILING(x, y)          (((x) + (y) - 1) / (y))
+#if defined __APPLE__
+#include <machine/param.h>
+#undef MASK
+#endif
+#define MASK(n)                        ((1 << (n)) - 1)        /* make an n-bit mask */
+#define DWORD_ALIGN(x)          ((((x)+3) >> 2) << 2)
+#define QWORD_ALIGN(x)          ((((x)+4) >> 3) << 3)
+
+#define IMPLIES(a,b) (!(a) || (b))
+
+/*
+ * Not everybody (e.g., the monitor) has NULL
+ */
+
+#ifndef NULL
+#ifdef  __cplusplus
+#define NULL    0
+#else
+#define NULL    ((void *)0)
+#endif
+#endif
+
+
+/* 
+ * Token concatenation
+ *
+ * The C preprocessor doesn't prescan arguments when they are
+ * concatenated or stringified.  So we need extra levels of
+ * indirection to convince the preprocessor to expand its
+ * arguments.
+ */
+
+#define CONC(x, y)              x##y
+#define XCONC(x, y)             CONC(x, y)
+#define XXCONC(x, y)            XCONC(x, y)
+#define MAKESTR(x)              #x
+#define XSTR(x)                 MAKESTR(x)
+
+
+/*
+ * Page operations
+ *
+ * It has been suggested that these definitions belong elsewhere
+ * (like x86types.h).  However, I deem them common enough
+ * (since even regular user-level programs may want to do
+ * page-based memory manipulation) to be here.
+ * -- edward
+ */
+
+#ifndef PAGE_SHIFT // {
+#if defined VM_I386
+   #define PAGE_SHIFT    12
+#elif defined __APPLE__
+   #define PAGE_SHIFT    12
+#else
+   #error
+#endif
+#endif // }
+
+#ifndef PAGE_SIZE
+#define PAGE_SIZE     (1<<PAGE_SHIFT)
+#endif
+
+#ifndef PAGE_MASK
+#define PAGE_MASK     (PAGE_SIZE - 1)
+#endif
+
+#ifndef PAGE_OFFSET
+#define PAGE_OFFSET(_addr)  ((uintptr_t)(_addr)&(PAGE_SIZE-1))
+#endif
+
+#ifndef VM_PAGE_BASE
+#define VM_PAGE_BASE(_addr)  ((_addr)&~(PAGE_SIZE-1))
+#endif
+
+#ifndef VM_PAGES_SPANNED
+#define VM_PAGES_SPANNED(_addr, _size) \
+   ((((_addr) & (PAGE_SIZE - 1)) + (_size) + (PAGE_SIZE - 1)) >> PAGE_SHIFT)
+#endif
+
+#ifndef BYTES_2_PAGES
+#define BYTES_2_PAGES(_nbytes) ((_nbytes) >> PAGE_SHIFT)
+#endif
+
+#ifndef PAGES_2_BYTES
+#define PAGES_2_BYTES(_npages) (((uint64)(_npages)) << PAGE_SHIFT)
+#endif
+
+#ifndef MBYTES_2_PAGES
+#define MBYTES_2_PAGES(_nbytes) ((_nbytes) << (20 - PAGE_SHIFT))
+#endif
+
+#ifndef PAGES_2_MBYTES
+#define PAGES_2_MBYTES(_npages) ((_npages) >> (20 - PAGE_SHIFT))
+#endif
+
+#ifndef VM_PAE_LARGE_PAGE_SHIFT
+#define VM_PAE_LARGE_PAGE_SHIFT 21
+#endif 
+
+#ifndef VM_PAE_LARGE_PAGE_SIZE
+#define VM_PAE_LARGE_PAGE_SIZE (1 << VM_PAE_LARGE_PAGE_SHIFT)
+#endif
+
+#ifndef VM_PAE_LARGE_PAGE_MASK
+#define VM_PAE_LARGE_PAGE_MASK (VM_PAE_LARGE_PAGE_SIZE - 1)
+#endif
+
+#ifndef VM_PAE_LARGE_2_SMALL_PAGES
+#define VM_PAE_LARGE_2_SMALL_PAGES (BYTES_2_PAGES(VM_PAE_LARGE_PAGE_SIZE))
+#endif
+
+/*
+ * Word operations
+ */
+
+#ifndef LOWORD
+#define LOWORD(_dw)   ((_dw) & 0xffff)
+#endif
+#ifndef HIWORD
+#define HIWORD(_dw)   (((_dw) >> 16) & 0xffff)
+#endif
+
+#ifndef LOBYTE
+#define LOBYTE(_w)    ((_w) & 0xff)
+#endif
+#ifndef HIBYTE
+#define HIBYTE(_w)    (((_w) >> 8) & 0xff)
+#endif
+
+#define HIDWORD(_qw)   ((uint32)((_qw) >> 32))
+#define LODWORD(_qw)   ((uint32)(_qw))
+#define QWORD(_hi, _lo)   ((((uint64)(_hi)) << 32) | ((uint32)(_lo)))
+
+
+/*
+ * Deposit a field _src at _pos bits from the right,
+ * with a length of _len, into the integer _target.
+ */
+
+#define DEPOSIT_BITS(_src,_pos,_len,_target) { \
+       unsigned mask = ((1 << _len) - 1); \
+       unsigned shiftedmask = ((1 << _len) - 1) << _pos; \
+       _target = (_target & ~shiftedmask) | ((_src & mask) << _pos); \
+}
+
+
+/*
+ * Get return address.
+ */
+
+#ifdef _MSC_VER
+#ifdef __cplusplus
+extern "C"
+#endif 
+void *_ReturnAddress(void);
+#pragma intrinsic(_ReturnAddress)
+#define GetReturnAddress() _ReturnAddress()
+#elif __GNUC__
+#define GetReturnAddress() __builtin_return_address(0)
+#endif
+
+
+#ifdef __GNUC__
+#ifndef sun
+
+/*
+ * Get the frame pointer. We use this assembly hack instead of
+ * __builtin_frame_address() due to a bug introduced in gcc 4.1.1
+ */
+static INLINE_SINGLE_CALLER uintptr_t
+GetFrameAddr(void)
+{
+   uintptr_t bp;
+#if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ == 0))
+   bp = (uintptr_t)__builtin_frame_address(0);
+#elif (__GNUC__ == 4 && __GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ <= 3)
+#  if defined(VMM64) || defined(VM_X86_64)
+     __asm__ __volatile__("movq %%rbp, %0\n" : "=g" (bp));
+#  else
+     __asm__ __volatile__("movl %%ebp, %0\n" : "=g" (bp));
+#  endif
+#else
+   __asm__ __volatile__(
+#ifdef __linux__
+      ".print \"This newer version of GCC may or may not have the "
+               "__builtin_frame_address bug.  Need to update this. "
+               "See bug 147638.\"\n"
+      ".abort"
+#else /* MacOS */
+      ".abort \"This newer version of GCC may or may not have the "
+               "__builtin_frame_address bug.  Need to update this. "
+               "See bug 147638.\"\n"
+#endif
+      : "=g" (bp)
+   );
+#endif
+   return bp;
+}
+
+
+/*
+ * Returns the frame pointer of the calling function.
+ * Equivalent to __builtin_frame_address(1).
+ */
+static INLINE_SINGLE_CALLER uintptr_t
+GetCallerFrameAddr(void)
+{
+   return *(uintptr_t*)GetFrameAddr();
+}
+
+#endif // sun
+#endif // __GNUC__
+
+/*
+ * Data prefetch was added in gcc 3.1.1
+ * http://www.gnu.org/software/gcc/gcc-3.1/changes.html
+ */
+#ifdef __GNUC__
+#  if ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ > 1) || \
+       (__GNUC__ == 3 && __GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ >= 1))
+#     define PREFETCH_R(var) __builtin_prefetch((var), 0 /* read */, \
+                                                3 /* high temporal locality */)
+#     define PREFETCH_W(var) __builtin_prefetch((var), 1 /* write */, \
+                                                3 /* high temporal locality */)
+#  else
+#     define PREFETCH_R(var) ((void)(var))
+#     define PREFETCH_W(var) ((void)(var))
+#  endif
+#endif /* __GNUC__ */
+
+
+#ifdef USERLEVEL // {
+
+/*
+ * Note this might be a problem on NT b/c while sched_yield guarantees it
+ * moves you to the end of your priority list, Sleep(0) offers no such
+ * guarantee.  Bummer.  --Jeremy.
+ */
+
+#if defined(N_PLAT_NLM)
+/* We do not have YIELD() as we do not need it yet... */
+#elif defined(_WIN32)
+#      define YIELD()          Sleep(0)
+#else
+#      include <sched.h>        // For sched_yield.  Don't ask.  --Jeremy.
+#      define YIELD()          sched_yield()
+#endif 
+
+
+/*
+ * Standardize some Posix names on Windows.
+ */
+
+#ifdef _WIN32 // {
+
+#define snprintf  _snprintf
+#define        vsnprintf _vsnprintf
+#define strtok_r  strtok_s
+
+typedef int uid_t;
+typedef int gid_t;
+
+static INLINE void
+sleep(unsigned int sec)
+{
+   Sleep(sec * 1000);
+}
+
+static INLINE void
+usleep(unsigned long usec)
+{
+   Sleep(CEILING(usec, 1000));
+}
+
+typedef int pid_t;
+#define       F_OK          0
+#define       X_OK          1
+#define       W_OK          2
+#define       R_OK          4
+
+#endif // }
+
+/*
+ * Macro for username comparison.
+ */
+
+#ifdef _WIN32 // {
+#define USERCMP(x,y)  Str_Strcasecmp(x,y)
+#else
+#define USERCMP(x,y)  strcmp(x,y)
+#endif // }
+
+
+#endif // }
+
+#ifndef va_copy
+
+#ifdef _WIN32
+
+/*
+ * Windows needs va_copy. This works for both 32 and 64-bit Windows
+ * based on inspection of how varags.h from the Visual C CRTL is
+ * implemented. (Future versions of the RTL may break this).
+ */
+
+#define va_copy(dest, src) ((dest) = (src))
+
+#elif defined(__APPLE__) && defined(KERNEL)
+
+/*
+ * MacOS kernel-mode needs va_copy. Based on inspection of stdarg.h
+ * from the MacOSX10.4u.sdk kernel framework, this should work.
+ * (Future versions of the SDK may break this).
+ */
+
+#define va_copy(dest, src) ((dest) = (src))
+
+#elif defined(__GNUC__) && (__GNUC__ < 3)
+
+/*
+ * Old versions of gcc recognize __va_copy, but not va_copy.
+ */
+
+#define va_copy(dest, src) __va_copy(dest, src)
+
+#endif // _WIN32
+
+#endif // va_copy
+
+/*
+ * This one is outside USERLEVEL because it's used by
+ * files compiled into the Windows hgfs driver or the display
+ * driver.
+ */
+
+#ifdef _WIN32
+#define PATH_MAX 256
+#ifndef strcasecmp
+#define strcasecmp(_s1,_s2)   _stricmp((_s1),(_s2))
+#endif
+#ifndef strncasecmp
+#define strncasecmp(_s1,_s2,_n)   _strnicmp((_s1),(_s2),(_n))
+#endif
+#endif
+
+/* 
+ * Convenience macro for COMMUNITY_SOURCE
+ */
+#undef EXCLUDE_COMMUNITY_SOURCE
+#ifdef COMMUNITY_SOURCE
+   #define EXCLUDE_COMMUNITY_SOURCE(x) 
+#else
+   #define EXCLUDE_COMMUNITY_SOURCE(x) x
+#endif
+
+#undef COMMUNITY_SOURCE_INTEL_SECRET
+#if !defined(COMMUNITY_SOURCE) || defined(INTEL_SOURCE)
+/*
+ * It's ok to include INTEL_SECRET source code for non-commsrc,
+ * or for drops directed at Intel.
+ */
+   #define COMMUNITY_SOURCE_INTEL_SECRET
+#endif
+
+/*
+ * Convenience macros and definitions. Can often be used instead of #ifdef.
+ */
+
+#undef DEBUG_ONLY
+#undef SL_DEBUG_ONLY
+#undef VMX86_SL_DEBUG
+#ifdef VMX86_DEBUG
+#define vmx86_debug      1
+#define DEBUG_ONLY(x)    x
+/*
+ * Be very, very, very careful with SL_DEBUG. Pls ask ganesh or min before 
+ * using it.
+ */
+#define VMX86_SL_DEBUG
+#define vmx86_sl_debug   1
+#define SL_DEBUG_ONLY(x) x
+#else
+#define vmx86_debug      0
+#define DEBUG_ONLY(x)
+#define vmx86_sl_debug   0
+#define SL_DEBUG_ONLY(x)
+#endif
+
+#ifdef VMX86_STATS
+#define vmx86_stats   1
+#define STATS_ONLY(x) x
+#else
+#define vmx86_stats   0
+#define STATS_ONLY(x)
+#endif
+
+#ifdef VMX86_DEVEL
+#define vmx86_devel   1
+#define DEVEL_ONLY(x) x
+#else
+#define vmx86_devel   0
+#define DEVEL_ONLY(x)
+#endif
+
+#ifdef VMX86_LOG
+#define vmx86_log     1
+#define LOG_ONLY(x)   x
+#else
+#define vmx86_log     0
+#define LOG_ONLY(x)
+#endif
+
+#ifdef VMX86_VMM_SERIAL_LOGGING
+#define vmx86_vmm_serial_log     1
+#define VMM_SERIAL_LOG_ONLY(x)   x
+#else
+#define vmx86_vmm_serial_log     0
+#define VMM_SERIAL_LOG_ONLY(x)
+#endif
+
+#ifdef VMX86_SERVER
+#define vmx86_server 1
+#define SERVER_ONLY(x) x
+#define HOSTED_ONLY(x)
+#else
+#define vmx86_server 0
+#define SERVER_ONLY(x)
+#define HOSTED_ONLY(x) x
+#endif
+
+#ifdef VMX86_WGS
+#define vmx86_wgs 1
+#define WGS_ONLY(x) x
+#else
+#define vmx86_wgs 0
+#define WGS_ONLY(x) 
+#endif
+
+#ifdef VMKERNEL
+#define vmkernel 1
+#define VMKERNEL_ONLY(x) x
+#else
+#define vmkernel 0
+#define VMKERNEL_ONLY(x)
+#endif
+
+#ifdef _WIN32
+#define WIN32_ONLY(x) x
+#define POSIX_ONLY(x)
+#else
+#define WIN32_ONLY(x)
+#define POSIX_ONLY(x) x
+#endif
+
+#ifdef VMM
+#define VMM_ONLY(x) x
+#define USER_ONLY(x)
+#else
+#define VMM_ONLY(x)
+#define USER_ONLY(x) x
+#endif
+
+/* VMVISOR ifdef only allowed in the vmkernel */
+#ifdef VMKERNEL
+#ifdef VMVISOR
+#define vmvisor 1
+#define VMVISOR_ONLY(x) x
+#else
+#define vmvisor 0
+#define VMVISOR_ONLY(x)
+#endif
+#endif
+
+#ifdef _WIN32
+#define VMW_INVALID_HANDLE INVALID_HANDLE_VALUE
+#else
+#define VMW_INVALID_HANDLE (-1)
+#endif
+
+#ifdef _WIN32
+#define fsync(fd) _commit(fd)
+#define fileno(f) _fileno(f)
+#else
+#endif
+
+/*
+ * Debug output macros for Windows drivers (the Eng variant is for
+ * display/printer drivers only.
+ */
+#ifdef _WIN32
+#ifndef USES_OLD_WINDDK
+#if defined(VMX86_DEBUG) || defined(ASSERT_ALWAYS_AVAILABLE)
+#define WinDrvPrint(arg, ...) DbgPrint(arg, __VA_ARGS__)
+#define WinDrvEngPrint(arg, ...) EngDbgPrint(arg, __VA_ARGS__)
+#else
+#define WinDrvPrint(arg, ...)
+#define WinDrvEngPrint(arg, ...)
+#endif
+#endif
+#endif // _WIN32
+
+#endif // ifndef _VM_BASIC_DEFS_H_
diff --git a/open-vm-tools/modules/solaris/vmhgfs/vm_basic_types.h b/open-vm-tools/modules/solaris/vmhgfs/vm_basic_types.h
new file mode 100644 (file)
index 0000000..05feb12
--- /dev/null
@@ -0,0 +1,952 @@
+/*********************************************************
+ * Copyright (C) 1998-2008 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ *
+ * vm_basic_types.h --
+ *
+ *    basic data types.
+ */
+
+
+#ifndef _VM_BASIC_TYPES_H_
+#define _VM_BASIC_TYPES_H_
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMMON
+#define INCLUDE_ALLOW_VMNIXMOD
+#define INCLUDE_ALLOW_VMKERNEL
+#define INCLUDE_ALLOW_VMKDRIVERS
+#define INCLUDE_ALLOW_VMK_MODULE
+#define INCLUDE_ALLOW_DISTRIBUTE
+#define INCLUDE_ALLOW_VMCORE
+#define INCLUDE_ALLOW_VMIROM
+#include "includeCheck.h"
+
+/* STRICT ANSI means the Xserver build and X defines Bool differently. */
+#if !defined(__STRICT_ANSI__) || defined(__FreeBSD__)
+typedef char           Bool;
+#endif
+
+#ifndef FALSE
+#define FALSE          0
+#endif
+
+#ifndef TRUE
+#define TRUE           1
+#endif
+
+#define IsBool(x)      (((x) & ~1) == 0)
+#define IsBool2(x, y)  ((((x) | (y)) & ~1) == 0)
+
+/*
+ * Macros __i386__ and __ia64 are intrinsically defined by GCC
+ */
+#ifdef __i386__
+#define VM_I386
+#endif
+
+#ifdef _WIN64
+#define __x86_64__
+#endif
+
+#ifdef __x86_64__
+#define VM_X86_64
+#define VM_I386
+#define vm_x86_64 (1)
+#else
+#define vm_x86_64 (0)
+#endif
+
+
+
+#ifdef _WIN32
+/* safe assumption for a while */
+#define VM_I386
+#endif
+
+#ifdef _MSC_VER
+
+#pragma warning (3 :4505) // unreferenced local function
+#pragma warning (disable :4018) // signed/unsigned mismatch
+#pragma warning (disable :4761) // integral size mismatch in argument; conversion supplied
+#pragma warning (disable :4305) // truncation from 'const int' to 'short'
+#pragma warning (disable :4244) // conversion from 'unsigned short' to 'unsigned char'
+#pragma warning (disable :4267) // truncation of 'size_t'
+#pragma warning (disable :4146) // unary minus operator applied to unsigned type, result still unsigned
+#pragma warning (disable :4142) // benign redefinition of type
+
+#endif
+
+#if defined(__APPLE__) || defined(HAVE_STDINT_H)
+
+/*
+ * TODO: This is a C99 standard header.  We should be able to test for
+ * #if __STDC_VERSION__ >= 199901L, but that breaks the Netware build
+ * (which doesn't have stdint.h).
+ */
+
+#include <stdint.h>
+
+typedef uint64_t uint64;
+typedef int64_t int64;
+typedef uint32_t uint32;
+typedef int32_t int32;
+typedef uint16_t uint16;
+typedef int16_t int16;
+typedef uint8_t uint8;
+
+/*
+ * XXX: int8_t is defined to be 'signed char' on Mac hosts.
+ *
+ * Unfortunately, GCC 4.0.1 warns when doing pointer assignment or
+ * comparison between signed char * and char * (even if char is
+ * signed).
+ *
+ * If we want to use int8_t to define int8, we need to go through and
+ * replace uses of char * with signed char * to prevent warnings.
+ */
+typedef char int8;
+
+#else /* !HAVE_STDINT_H */
+
+#ifdef _MSC_VER
+
+typedef unsigned __int64 uint64;
+typedef signed __int64 int64;
+
+#elif __GNUC__
+/* The Xserver source compiles with -ansi -pendantic */
+#ifndef __STRICT_ANSI__
+#if defined(VM_X86_64)
+typedef unsigned long uint64;
+typedef long int64;
+#else
+typedef unsigned long long uint64;
+typedef long long int64;
+#endif
+#elif __FreeBSD__
+typedef unsigned long long uint64;
+typedef long long int64;
+#endif
+#else
+#error - Need compiler define for int64/uint64
+#endif /* _MSC_VER */
+
+typedef unsigned int       uint32;
+typedef unsigned short     uint16;
+typedef unsigned char      uint8;
+
+typedef int       int32;
+typedef short     int16;
+typedef char      int8;
+
+#endif /* HAVE_STDINT_H */
+
+/*
+ * FreeBSD (for the tools build) unconditionally defines these in
+ * sys/inttypes.h so don't redefine them if this file has already
+ * been included. [greg]
+ *
+ * This applies to Solaris as well.
+ */
+
+/*
+ * Before trying to do the includes based on OS defines, see if we can use
+ * feature-based defines to get as much functionality as possible
+ */
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_INTTYPES_H
+#include <sys/inttypes.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef __FreeBSD__
+#include <sys/param.h> /* For __FreeBSD_version */         
+#endif
+
+#if !defined(USING_AUTOCONF)
+#   if defined(__FreeBSD__) || defined(sun)
+#      ifdef KLD_MODULE
+#         include <sys/types.h>
+#      else
+#         if !defined(VMKERNEL) && (__FreeBSD_version >= 500043)
+#            include <inttypes.h>
+#            include <sys/types.h>
+#         else
+#            include <sys/inttypes.h>
+#         endif
+#      endif
+#   elif defined __APPLE__
+#      if KERNEL
+#         include <sys/unistd.h>
+#         include <sys/types.h> /* mostly for size_t */
+#         include <stdint.h>
+#      else
+#         include <unistd.h>
+#         include <inttypes.h>
+#         include <stdlib.h>
+#         include <stdint.h>
+#      endif
+#   else
+#      if !defined(__intptr_t_defined) && !defined(intptr_t)
+#         define __intptr_t_defined
+#         define intptr_t  intptr_t
+#         ifdef VM_I386
+#            ifdef VM_X86_64
+typedef int64     intptr_t;
+#            else
+typedef int32     intptr_t;
+#            endif
+#         endif
+#      endif
+
+#      ifndef _STDINT_H
+#         ifdef VM_I386
+#            ifdef VM_X86_64
+typedef uint64    uintptr_t;
+#            else
+typedef uint32    uintptr_t;
+#            endif
+#         endif
+#      endif
+#   endif
+#endif
+
+
+/*
+ * Time
+ * XXX These should be cleaned up.  -- edward
+ */
+
+typedef int64 VmTimeType;          /* Time in microseconds */
+typedef int64 VmTimeRealClock;     /* Real clock kept in microseconds */
+typedef int64 VmTimeVirtualClock;  /* Virtual Clock kept in CPU cycles */
+
+/*
+ * Printf format specifiers for size_t and 64-bit number.
+ * Use them like this:
+ *    printf("%"FMT64"d\n", big);
+ *
+ * FMTH is for handles/fds.
+ */
+
+#ifdef _MSC_VER
+   #define FMT64      "I64"
+   #ifdef VM_X86_64
+      #define FMTSZ      "I64"
+      #define FMTPD      "I64"
+      #define FMTH       "I64"
+   #else
+      #define FMTSZ      "I"
+      #define FMTPD      "I"
+      #define FMTH       "I"
+   #endif
+#elif defined __APPLE__
+   /* Mac OS hosts use the same formatters for 32- and 64-bit. */
+   #define FMT64 "ll"
+   #define FMTSZ "z"
+   #define FMTPD "l"
+   #define FMTH ""
+#elif __GNUC__
+   #define FMTH ""
+   #if defined(N_PLAT_NLM) || defined(sun) || \
+       (defined(__FreeBSD__) && (__FreeBSD__ + 0) && ((__FreeBSD__ + 0) < 5))
+      /*
+       * Why (__FreeBSD__ + 0)?  See bug 141008.
+       * Yes, we really need to test both (__FreeBSD__ + 0) and
+       * ((__FreeBSD__ + 0) < 5).  No, we can't remove "+ 0" from
+       * ((__FreeBSD__ + 0) < 5).
+       */
+      #ifdef VM_X86_64
+         #define FMTSZ  "l"
+         #define FMTPD  "l"
+      #else
+         #define FMTSZ  ""
+         #define FMTPD  ""
+      #endif
+   #elif defined(__linux__) \
+      || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) \
+      || (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L) \
+      || (defined(_POSIX2_VERSION) && _POSIX2_VERSION >= 200112L)
+      /* BSD, Linux */
+      #define FMTSZ     "z"
+
+      #if defined(VM_X86_64)
+         #define FMTPD  "l"
+      #else
+         #define FMTPD  ""
+      #endif
+   #else
+      /* Systems with a pre-C99 libc */
+      #define FMTSZ     "Z"
+      #ifdef VM_X86_64
+         #define FMTPD  "l"
+      #else
+         #define FMTPD  ""
+      #endif
+   #endif
+   #ifdef VM_X86_64
+      #define FMT64     "l"
+   #elif defined(sun) || defined(__FreeBSD__)
+      #define FMT64     "ll"
+   #else
+      #define FMT64     "L"
+   #endif
+#else
+   #error - Need compiler define for FMT64 and FMTSZ
+#endif
+
+/*
+ * Suffix for 64-bit constants.  Use it like this:
+ *    CONST64(0x7fffffffffffffff) for signed or
+ *    CONST64U(0x7fffffffffffffff) for unsigned.
+ *
+ * 2004.08.30(thutt):
+ *   The vmcore/asm64/gen* programs are compiled as 32-bit
+ *   applications, but must handle 64 bit constants.  If the
+ *   64-bit-constant defining macros are already defined, the
+ *   definition will not be overwritten.
+ */
+
+#if !defined(CONST64) || !defined(CONST64U)
+#ifdef _MSC_VER
+#define CONST64(c) c##I64
+#define CONST64U(c) c##uI64
+#elif __GNUC__
+#ifdef VM_X86_64
+#define CONST64(c) c##L
+#define CONST64U(c) c##uL
+#else
+#define CONST64(c) c##LL
+#define CONST64U(c) c##uLL
+#endif
+#else
+#error - Need compiler define for CONST64
+#endif
+#endif
+
+/*
+ * Use CONST3264/CONST3264U if you want a constant to be
+ * treated as a 32-bit number on 32-bit compiles and
+ * a 64-bit number on 64-bit compiles. Useful in the case
+ * of shifts, like (CONST3264U(1) << x), where x could be
+ * more than 31 on a 64-bit compile.
+ */
+
+#ifdef VM_X86_64
+    #define CONST3264(a) CONST64(a)
+    #define CONST3264U(a) CONST64U(a)
+#else
+    #define CONST3264(a) (a)
+    #define CONST3264U(a) (a)
+#endif
+
+#define MIN_INT32  ((int32)0x80000000)
+#define MAX_INT32  ((int32)0x7fffffff)
+
+#define MIN_UINT32 ((uint32)0)
+#define MAX_UINT32 ((uint32)0xffffffff)
+
+#define MIN_INT64  (CONST64(0x8000000000000000))
+#define MAX_INT64  (CONST64(0x7fffffffffffffff))
+
+#define MIN_UINT64 (CONST64U(0))
+#define MAX_UINT64 (CONST64U(0xffffffffffffffff))
+
+typedef uint8 *TCA;  /* Pointer into TC (usually). */
+
+/*
+ * Type big enough to hold an integer between 0..100
+ */
+typedef uint8 Percent;
+#define AsPercent(v)   ((Percent)(v))
+#define CHOOSE_PERCENT  AsPercent(101)
+
+
+typedef uintptr_t VA;
+typedef uintptr_t VPN;
+
+typedef uint64    PA;
+typedef uint32    PPN;
+
+typedef uint64    PhysMemOff;
+typedef uint64    PhysMemSize;
+
+/* The Xserver source compiles with -ansi -pendantic */
+#ifndef __STRICT_ANSI__
+typedef uint64    BA;
+#endif
+typedef uint32    BPN;
+typedef uint32    PageNum;
+typedef unsigned  MemHandle;
+typedef int32     World_ID;
+
+#define INVALID_WORLD_ID ((World_ID)-1)
+
+typedef World_ID User_CartelID;
+#define INVALID_CARTEL_ID INVALID_WORLD_ID
+
+typedef User_CartelID User_SessionID;
+#define INVALID_SESSION_ID INVALID_CARTEL_ID
+
+typedef User_CartelID User_CartelGroupID;
+#define INVALID_CARTELGROUP_ID INVALID_CARTEL_ID
+
+typedef uint32 Worldlet_ID;
+#define INVALID_WORLDLET_ID ((Worldlet_ID)-1)
+
+/* world page number */
+typedef uint32    WPN;
+
+/* The Xserver source compiles with -ansi -pendantic */
+#ifndef __STRICT_ANSI__
+typedef uint64     MA;
+typedef uint32     MPN;
+#endif
+
+/*
+ * This type should be used for variables that contain sector
+ * position/quantity.
+ */
+typedef uint64 SectorType;
+
+/*
+ * Linear address
+ */
+
+typedef uintptr_t LA;
+typedef uintptr_t LPN;
+#define LA_2_LPN(_la)     ((_la) >> PAGE_SHIFT)
+#define LPN_2_LA(_lpn)    ((_lpn) << PAGE_SHIFT)
+
+#define LAST_LPN   ((((LA)  1) << (8 * sizeof(LA)   - PAGE_SHIFT)) - 1)
+#define LAST_LPN32 ((((LA32)1) << (8 * sizeof(LA32) - PAGE_SHIFT)) - 1)
+#define LAST_LPN64 ((((LA64)1) << (8 * sizeof(LA64) - PAGE_SHIFT)) - 1)
+
+/* Valid bits in a LPN. */
+#define LPN_MASK   LAST_LPN
+#define LPN_MASK32 LAST_LPN32
+#define LPN_MASK64 LAST_LPN64
+
+/*
+ * On 64 bit platform, address and page number types default
+ * to 64 bit. When we need to represent a 32 bit address, we use
+ * types defined below.
+ *
+ * On 32 bit platform, the following types are the same as the
+ * default types.
+ */
+typedef uint32 VA32;
+typedef uint32 VPN32;
+typedef uint32 LA32;
+typedef uint32 LPN32;
+typedef uint32 PA32;
+typedef uint32 PPN32;
+typedef uint32 MA32;
+typedef uint32 MPN32;
+
+/*
+ * On 64 bit platform, the following types are the same as the
+ * default types.
+ */
+typedef uint64 VA64;
+typedef uint64 VPN64;
+typedef uint64 LA64;
+typedef uint64 LPN64;
+typedef uint64 PA64;
+typedef uint64 PPN64;
+typedef uint64 MA64;
+typedef uint64 MPN64;
+
+/*
+ * VA typedefs for user world apps.
+ */
+typedef VA32 UserVA32;
+typedef VA64 UserVA64;
+typedef UserVA32 UserVAConst; /* Userspace ptr to data that we may only read. */
+typedef UserVA64 UserVA64Const; /* Used by 64-bit syscalls until conversion is finished. */
+#ifdef VMKERNEL
+typedef UserVA32 UserVA;
+#else
+typedef void * UserVA;
+#endif
+
+
+/*
+ * Maximal possible PPN value (errors too) that PhysMem can handle.
+ * Must be at least as large as MAX_PPN which is the maximum PPN
+ * for any region other than buserror.
+ */
+#define PHYSMEM_MAX_PPN ((PPN)0xffffffff)
+#define MAX_PPN         ((PPN)0x1fffffff)   /* Maximal observable PPN value. */
+#define INVALID_PPN     ((PPN)0xffffffff)
+
+#define INVALID_BPN  ((BPN) 0x1fffffff)
+
+#define INVALID_MPN  ((MPN)-1)
+#define MEMREF_MPN   ((MPN)-2)
+#define RESERVED_MPN ((MPN) 0)
+/* Support 43 bits of address space. */
+#define MAX_MPN      ((MPN)0x7fffffff)
+
+#define INVALID_LPN ((LPN)-1)
+#define INVALID_VPN ((VPN)-1)
+#define INVALID_LPN64 ((LPN64)-1)
+#define INVALID_PAGENUM ((PageNum)-1)
+#define INVALID_WPN ((WPN) -1)
+
+
+/*
+ * Format modifier for printing VA, LA, and VPN.
+ * Use them like this: Log("%#"FMTLA"x\n", laddr)
+ */
+
+#if defined(VMM64) || defined(FROBOS64) || vm_x86_64 || defined __APPLE__
+#   define FMTLA "l"
+#   define FMTVA "l"
+#   define FMTVPN "l"
+#else
+#   define FMTLA ""
+#   define FMTVA ""
+#   define FMTVPN ""
+#endif
+
+#ifndef EXTERN
+#define EXTERN        extern
+#endif
+#define CONST         const
+
+
+#ifndef INLINE
+#   ifdef _MSC_VER
+#      define INLINE        __inline
+#   else
+#      define INLINE        inline
+#   endif
+#endif
+
+
+/*
+ * Annotation for data that may be exported into a DLL and used by other
+ * apps that load that DLL and import the data.
+ */
+#if defined(_WIN32) && defined(VMX86_IMPORT_DLLDATA)
+#  define VMX86_EXTERN_DATA       extern __declspec(dllimport)
+#else // !_WIN32
+#  define VMX86_EXTERN_DATA       extern
+#endif
+
+#if defined(_WIN32) && !defined(VMX86_NO_THREADS)
+#define THREADSPECIFIC __declspec(thread)
+#else
+#define THREADSPECIFIC
+#endif
+
+/*
+ * Due to the wonderful "registry redirection" feature introduced in
+ * 64-bit Windows, if you access any key under HKLM\Software in 64-bit
+ * code, you need to open/create/delete that key with
+ * VMKEY_WOW64_32KEY if you want a consistent view with 32-bit code.
+ */
+
+#ifdef _WIN32
+#ifdef _WIN64
+#define VMW_KEY_WOW64_32KEY KEY_WOW64_32KEY
+#else
+#define VMW_KEY_WOW64_32KEY 0x0
+#endif
+#endif
+
+
+/*
+ * Consider the following reasons functions are inlined:
+ *
+ *  1) inlined for performance reasons
+ *  2) inlined because it's a single-use function
+ *
+ * Functions which meet only condition 2 should be marked with this
+ * inline macro; It is not critical to be inlined (but there is a
+ * code-space & runtime savings by doing so), so when other callers
+ * are added the inline-ness should be removed.
+ */
+
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)
+/*
+ * Starting at version 3.3, gcc does not always inline functions marked
+ * 'inline' (it depends on their size). To force gcc to do so, one must use the
+ * extra __always_inline__ attribute.
+ */
+#   define INLINE_SINGLE_CALLER INLINE __attribute__((__always_inline__))
+#   if    defined(VMM) \
+       && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 1))
+#      warning Verify INLINE_SINGLE_CALLER '__always_inline__' attribute (did \
+             monitor size change?)
+#   endif
+#else
+#   define INLINE_SINGLE_CALLER INLINE
+#endif
+
+/*
+ * Used when a hard guaranteed of no inlining is needed. Very few
+ * instances need this since the absence of INLINE is a good hint
+ * that gcc will not do inlining.
+ */
+
+#if defined(__GNUC__) && defined(VMM)
+#define ABSOLUTELY_NOINLINE __attribute__((__noinline__))
+#endif
+
+/*
+ * Attributes placed on function declarations to tell the compiler
+ * that the function never returns.
+ */
+
+#ifdef _MSC_VER
+#define NORETURN __declspec(noreturn)
+#elif __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 9)
+#define NORETURN __attribute__((__noreturn__))
+#else
+#define NORETURN
+#endif
+
+/*
+ * GCC 3.2 inline asm needs the + constraint for input/ouput memory operands.
+ * Older GCCs don't know about it --hpreg
+ */
+
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)
+#   define VM_ASM_PLUS 1
+#else
+#   define VM_ASM_PLUS 0
+#endif
+
+/*
+ * Branch prediction hints:
+ *     LIKELY(exp)   - Expression exp is likely TRUE.
+ *     UNLIKELY(exp) - Expression exp is likely FALSE.
+ *   Usage example:
+ *        if (LIKELY(excCode == EXC_NONE)) {
+ *               or
+ *        if (UNLIKELY(REAL_MODE(vc))) {
+ *
+ * We know how to predict branches on gcc3 and later (hopefully),
+ * all others we don't so we do nothing.
+ */
+
+#if (__GNUC__ >= 3)
+/*
+ * gcc3 uses __builtin_expect() to inform the compiler of an expected value.
+ * We use this to inform the static branch predictor. The '!!' in LIKELY
+ * will convert any !=0 to a 1.
+ */
+#define LIKELY(_exp)     __builtin_expect(!!(_exp), 1)
+#define UNLIKELY(_exp)   __builtin_expect((_exp), 0)
+#else
+#define LIKELY(_exp)      (_exp)
+#define UNLIKELY(_exp)    (_exp)
+#endif
+
+/*
+ * GCC's argument checking for printf-like functions
+ * This is conditional until we have replaced all `"%x", void *'
+ * with `"0x%08x", (uint32) void *'. Note that %p prints different things
+ * on different platforms.  Argument checking is enabled for the
+ * vmkernel, which has already been cleansed.
+ *
+ * fmtPos is the position of the format string argument, beginning at 1
+ * varPos is the position of the variable argument, beginning at 1
+ */
+
+#if defined(__GNUC__)
+# define PRINTF_DECL(fmtPos, varPos) __attribute__((__format__(__printf__, fmtPos, varPos)))
+#else
+# define PRINTF_DECL(fmtPos, varPos)
+#endif
+
+#if defined(__GNUC__)
+# define SCANF_DECL(fmtPos, varPos) __attribute__((__format__(__scanf__, fmtPos, varPos)))
+#else
+# define SCANF_DECL(fmtPos, varPos)
+#endif
+
+/*
+ * UNUSED_PARAM should surround the parameter name and type declaration,
+ * e.g. "int MyFunction(int var1, UNUSED_PARAM(int var2))"
+ *
+ */
+
+#ifndef UNUSED_PARAM
+# if defined(__GNUC__)
+#  define UNUSED_PARAM(_parm) _parm  __attribute__((__unused__))
+# else
+#  define UNUSED_PARAM(_parm) _parm
+# endif
+#endif
+
+/*
+ * REGPARM defaults to REGPARM3, i.e., a requent that gcc
+ * puts the first three arguments in registers.  (It is fine
+ * if the function has fewer than three args.)  Gcc only.
+ * Syntactically, put REGPARM where you'd put INLINE or NORETURN.
+ */
+
+#if defined(__GNUC__)
+# define REGPARM0 __attribute__((regparm(0)))
+# define REGPARM1 __attribute__((regparm(1)))
+# define REGPARM2 __attribute__((regparm(2)))
+# define REGPARM3 __attribute__((regparm(3)))
+# define REGPARM REGPARM3
+#else
+# define REGPARM0
+# define REGPARM1
+# define REGPARM2
+# define REGPARM3
+# define REGPARM
+#endif
+
+/*
+ * ALIGNED specifies minimum alignment in "n" bytes.
+ */
+
+#ifdef __GNUC__
+#define ALIGNED(n) __attribute__((__aligned__(n)))
+#else
+#define ALIGNED(n)
+#endif
+
+/*
+ ***********************************************************************
+ * STRUCT_OFFSET_CHECK --                                    */ /**
+ *
+ * \brief Check if the actual offsef of a member in a structure 
+ *        is what is expected
+ * 
+ *
+ * \param[in]  STRUCT       Structure the member is a part of.
+ * \param[in]  MEMBER       Member to check the offset of.
+ * \param[in]  OFFSET       Expected offset of MEMBER in STRUCTURE.
+ * \param[in]  DEBUG_EXTRA  Additional bytes to be added to OFFSET to
+ *                          compensate for extra info in debug builds.
+ *
+ ***********************************************************************
+ */
+#ifdef VMX86_DEBUG
+#define STRUCT_OFFSET_CHECK(STRUCT, MEMBER, OFFSET, DEBUG_EXTRA) \
+  ASSERT_ON_COMPILE(vmk_offsetof(STRUCT, MEMBER) == (OFFSET + DEBUG_EXTRA))
+#else
+#define STRUCT_OFFSET_CHECK(STRUCT, MEMBER, OFFSET, DEBUG_EXTRA) \
+  ASSERT_ON_COMPILE(vmk_offsetof(STRUCT, MEMBER) == OFFSET)
+#endif
+
+/*
+ ***********************************************************************
+ * STRUCT_SIZE_CHECK --                                      */ /**
+ *
+ * \brief Check if the actual size of a structure is what is expected
+ * 
+ *
+ * \param[in]  STRUCT       Structure whose size is to be checked.
+ * \param[in]  SIZE         Expected size of STRUCT.
+ * \param[in]  DEBUG_EXTRA  Additional bytes to be added to SIZE to
+ *                          compensate for extra info in debug builds.
+ *
+ ***********************************************************************
+ */
+#ifdef VMX86_DEBUG
+#define STRUCT_SIZE_CHECK(STRUCT, SIZE, DEBUG_EXTRA) \
+  ASSERT_ON_COMPILE(sizeof(STRUCT) == (SIZE + DEBUG_EXTRA))
+#else
+#define STRUCT_SIZE_CHECK(STRUCT, SIZE, DEBUG_EXTRA) \
+  ASSERT_ON_COMPILE(sizeof(STRUCT) == SIZE)
+#endif
+
+/*
+ * __func__ is a stringified function name that is part of the C99 standard. The block
+ * below defines __func__ on older systems where the compiler does not support that
+ * macro.
+ */
+#if defined(__GNUC__) \
+   && ((__GNUC__ == 2 && __GNUC_MINOR < 96) \
+       || (__GNUC__ < 2))
+#   define __func__ __FUNCTION__
+#endif
+
+/*
+ * Once upon a time, this was used to silence compiler warnings that
+ * get generated when the compiler thinks that a function returns
+ * when it is marked noreturn.  Don't do it.  Use NOT_REACHED().
+ */
+
+#define INFINITE_LOOP()           do { } while (1)
+
+/*
+ * On FreeBSD (for the tools build), size_t is typedef'd if _BSD_SIZE_T_
+ * is defined. Use the same logic here so we don't define it twice. [greg]
+ */
+#ifdef __FreeBSD__
+#   ifdef _BSD_SIZE_T_
+#      undef _BSD_SIZE_T_
+#      ifdef VM_I386
+#         ifdef VM_X86_64
+             typedef uint64 size_t;
+#         else
+             typedef uint32 size_t;
+#         endif
+#      endif /* VM_I386 */
+#   endif
+
+#   ifdef _BSD_SSIZE_T_
+#      undef _BSD_SSIZE_T_
+#      define _SSIZE_T
+#      define __ssize_t_defined
+#      define _SSIZE_T_DECLARED
+#      ifdef VM_I386
+#         ifdef VM_X86_64
+             typedef int64 ssize_t;
+#         else
+             typedef int32 ssize_t;
+#         endif
+#      endif /* VM_I386 */
+#   endif
+
+#else
+#   ifndef _SIZE_T
+#      define _SIZE_T
+#      ifdef VM_I386
+#         ifdef VM_X86_64
+             typedef uint64 size_t;
+#         else
+             typedef uint32 size_t;
+#         endif
+#      endif /* VM_I386 */
+#   endif
+
+#   if !defined(FROBOS) && !defined(_SSIZE_T) && !defined(ssize_t) && \
+       !defined(__ssize_t_defined) && !defined(_SSIZE_T_DECLARED)
+#      define _SSIZE_T
+#      define __ssize_t_defined
+#      define _SSIZE_T_DECLARED
+#      ifdef VM_I386
+#         ifdef VM_X86_64
+             typedef int64 ssize_t;
+#         else
+             typedef int32 ssize_t;
+#         endif
+#      endif /* VM_I386 */
+#   endif
+
+#endif
+
+/*
+ * Format modifier for printing pid_t.  On sun the pid_t is a ulong, but on
+ * Linux it's an int.
+ * Use this like this: printf("The pid is %"FMTPID".\n", pid);
+ */
+#ifdef sun
+#   ifdef VM_X86_64
+#      define FMTPID "d"
+#   else
+#      define FMTPID "lu"
+#   endif
+#else
+# define FMTPID "d"
+#endif
+
+/*
+ * Format modifier for printing uid_t.  On sun the uid_t is a ulong, but on
+ * Linux it's an int.
+ * Use this like this: printf("The uid is %"FMTUID".\n", uid);
+ */
+#ifdef sun
+#   ifdef VM_X86_64
+#      define FMTUID "u"
+#   else
+#      define FMTUID "lu"
+#   endif
+#else
+# define FMTUID "u"
+#endif
+
+/*
+ * Format modifier for printing mode_t.  On sun the mode_t is a ulong, but on
+ * Linux it's an int.
+ * Use this like this: printf("The mode is %"FMTMODE".\n", mode);
+ */
+#ifdef sun
+#   ifdef VM_X86_64
+#      define FMTMODE "o"
+#   else
+#      define FMTMODE "lo"
+#   endif
+#else
+# define FMTMODE "o"
+#endif
+
+/*
+ * Format modifier for printing time_t. Most platforms define a time_t to be
+ * a long int, but on FreeBSD (as of 5.0, it seems), the time_t is a signed
+ * size quantity. Refer to the definition of FMTSZ to see why we need silly
+ * preprocessor arithmetic.
+ * Use this like this: printf("The mode is %"FMTTIME".\n", time);
+ */
+#if defined(__FreeBSD__) && (__FreeBSD__ + 0) && ((__FreeBSD__ + 0) >= 5)
+#   define FMTTIME FMTSZ"d"
+#else
+#   define FMTTIME "ld"
+#endif
+
+/*
+ * Define MXSemaHandle here so both vmmon and vmx see this definition.
+ */
+
+#ifdef _WIN32
+typedef uintptr_t MXSemaHandle;
+#else
+typedef int MXSemaHandle;
+#endif
+
+/*
+ * Define type for poll device handles.
+ */
+
+#ifdef _WIN32
+typedef uintptr_t PollDevHandle;
+#else
+typedef int PollDevHandle;
+#endif
+
+/*
+ * Define the utf16_t type.
+ */
+
+#if defined(_WIN32) && defined(_NATIVE_WCHAR_T_DEFINED)
+typedef wchar_t utf16_t;
+#else
+typedef uint16 utf16_t;
+#endif
+
+#endif  /* _VM_BASIC_TYPES_H_ */
diff --git a/open-vm-tools/modules/solaris/vmhgfs/vmware.h b/open-vm-tools/modules/solaris/vmhgfs/vmware.h
new file mode 100644 (file)
index 0000000..6754325
--- /dev/null
@@ -0,0 +1,56 @@
+/*********************************************************
+ * Copyright (C) 2003 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * vmware.h --
+ *
+ *     Standard include file for VMware source code.
+ */
+
+#ifndef _VMWARE_H_
+#define _VMWARE_H_
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMCORE
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMMON
+#define INCLUDE_ALLOW_VMNIXMOD
+#define INCLUDE_ALLOW_VMKERNEL
+#define INCLUDE_ALLOW_VMK_MODULE
+#define INCLUDE_ALLOW_DISTRIBUTE
+#include "includeCheck.h"
+
+#include "vm_basic_types.h"
+#include "vm_basic_defs.h"
+#include "vm_assert.h"
+
+/*
+ * Global error codes. Currently used internally, but may be exported
+ * to customers one day, like VM_E_XXX in vmcontrol_constants.h
+ */
+
+typedef enum VMwareStatus {
+   VMWARE_STATUS_SUCCESS,  /* success */
+   VMWARE_STATUS_ERROR,    /* generic error */
+   VMWARE_STATUS_NOMEM,    /* generic memory allocation error */
+   VMWARE_STATUS_INSUFFICIENT_RESOURCES, /* internal or system resource limit exceeded */
+   VMWARE_STATUS_INVALID_ARGS  /* invalid arguments */
+} VMwareStatus;
+
+#define VMWARE_SUCCESS(s) ((s) == VMWARE_STATUS_SUCCESS)
+
+
+#endif // ifndef _VMWARE_H_
diff --git a/open-vm-tools/modules/solaris/vmhgfs/vmware_pack_begin.h b/open-vm-tools/modules/solaris/vmhgfs/vmware_pack_begin.h
new file mode 100644 (file)
index 0000000..7dd9b05
--- /dev/null
@@ -0,0 +1,41 @@
+/*********************************************************
+ * Copyright (C) 2002 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * vmware_pack_begin.h --
+ *
+ *    Begin of structure packing. See vmware_pack_init.h for details.
+ *
+ *    Note that we do not use the following construct in this include file,
+ *    because we want to emit the code every time the file is included --hpreg
+ *
+ *    #ifndef foo
+ *    #   define foo
+ *    ...
+ *    #endif
+ *
+ */
+
+
+#include "vmware_pack_init.h"
+
+
+#ifdef _MSC_VER
+#   pragma pack(push, 1)
+#elif __GNUC__
+#else
+#   error Compiler packing...
+#endif
diff --git a/open-vm-tools/modules/solaris/vmhgfs/vmware_pack_end.h b/open-vm-tools/modules/solaris/vmhgfs/vmware_pack_end.h
new file mode 100644 (file)
index 0000000..0959b26
--- /dev/null
@@ -0,0 +1,42 @@
+/*********************************************************
+ * Copyright (C) 2002 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * vmware_pack_end.h --
+ *
+ *    End of structure packing. See vmware_pack_init.h for details.
+ *
+ *    Note that we do not use the following construct in this include file,
+ *    because we want to emit the code every time the file is included --hpreg
+ *
+ *    #ifndef foo
+ *    #   define foo
+ *    ...
+ *    #endif
+ *
+ */
+
+
+#include "vmware_pack_init.h"
+
+
+#ifdef _MSC_VER
+#   pragma pack(pop)
+#elif __GNUC__
+__attribute__((__packed__))
+#else
+#   error Compiler packing...
+#endif
diff --git a/open-vm-tools/modules/solaris/vmhgfs/vmware_pack_init.h b/open-vm-tools/modules/solaris/vmhgfs/vmware_pack_init.h
new file mode 100644 (file)
index 0000000..765a08c
--- /dev/null
@@ -0,0 +1,63 @@
+/*********************************************************
+ * Copyright (C) 2002 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+#ifndef __VMWARE_PACK_INIT_H__
+#   define __VMWARE_PACK_INIT_H__
+
+
+/*
+ * vmware_pack_init.h --
+ *
+ *    Platform-independent code to make the compiler pack (i.e. have them
+ *    occupy the smallest possible space) structure definitions. The following
+ *    constructs are known to work --hpreg
+ *
+ *    #include "vmware_pack_begin.h"
+ *    struct foo {
+ *       ...
+ *    }
+ *    #include "vmware_pack_end.h"
+ *    ;
+ *
+ *    typedef
+ *    #include "vmware_pack_begin.h"
+ *    struct foo {
+ *       ...
+ *    }
+ *    #include "vmware_pack_end.h"
+ *    foo;
+ */
+
+
+#ifdef _MSC_VER
+/*
+ * MSVC 6.0 emits warning 4103 when the pack push and pop pragma pairing is
+ * not balanced within 1 included file. That is annoying because our scheme
+ * is based on the pairing being balanced between 2 included files.
+ *
+ * So we disable this warning, but this is safe because the compiler will also
+ * emit warning 4161 when there is more pops than pushes within 1 main
+ * file --hpreg
+ */
+
+#   pragma warning(disable:4103)
+#elif __GNUC__
+#else
+#   error Compiler packing...
+#endif
+
+
+#endif /* __VMWARE_PACK_INIT_H__ */
diff --git a/open-vm-tools/modules/solaris/vmhgfs/vnode.c b/open-vm-tools/modules/solaris/vmhgfs/vnode.c
new file mode 100644 (file)
index 0000000..25f02f6
--- /dev/null
@@ -0,0 +1,5865 @@
+/*********************************************************
+ * Copyright (C) 2004 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+
+/*
+ * vnode.c --
+ *
+ * Implementaiton of entry points for operations on files (vnodes) and
+ * definition of the vnodeops structure.
+ */
+
+#include <sys/types.h>
+#include <sys/dirent.h>
+#include <sys/sysmacros.h>
+#include <sys/file.h>           /* FREAD, FWRITE, etc flags */
+#include <sys/fs_subr.h>        /* fs_fab_acl */
+#include <sys/stat.h>           /* S_IRWXU and friends */
+#include <sys/dnlc.h>           /* Directory name lookup cache */
+#include <sys/signal.h>         /* k_sigset_t and signal macros */
+#include <sys/proc.h>           /* practive (the active process) */
+#include <sys/user.h>           /* u macro for current user area */
+#include <sys/thread.h>         /* curthread and curproc macros */
+#include <vm/seg_vn.h>          /* segment vnode mapping for mmap() */
+#include <sys/vmsystm.h>        /* VM address mapping functions */
+
+#include "hgfsSolaris.h"
+#include "hgfsState.h"
+#include "vnode.h"
+#include "filesystem.h"
+#include "request.h"
+#include "debug.h"
+
+#include "hgfsEscape.h"         /* Escaping/unescaping buffers */
+#include "cpName.h"             /* Cross-platform name conversion */
+#include "hgfsUtil.h"           /* Cross-platform time conversion */
+#include "sha1.h"               /* SHA-1 for Node ID calculation */
+
+/*
+ * Macros
+ */
+#define HGFS_ATTR_MODE_SHIFT    6
+
+/* Sets the values of request headers properly */
+#define HGFS_INIT_REQUEST_HDR(request, req, _op)        \
+         do {                                           \
+            request->header.id = req->id;               \
+            request->header.op = _op;                   \
+         } while(0)
+
+/* Solaris times support nsecs, so only use these functions directly */
+#define HGFS_SET_TIME(unixtm, nttime)                   \
+         HgfsConvertFromNtTimeNsec(&unixtm, nttime)
+#define HGFS_GET_TIME(unixtm)                           \
+         HgfsConvertTimeSpecToNtTime(&unixtm)
+
+/* Determine if this is the root vnode. */
+#define HGFS_IS_ROOT_VNODE(sip, vp)                     \
+                (sip->rootVnode == vp)
+//             ((vp->v_flag & VROOT) && (vp->v_vfsp == sip->vfsp))
+
+
+/*
+ * Prototypes
+ */
+
+/* Local vnode functions */
+static int HgfsDirOpen(HgfsSuperInfo *sip, struct vnode *vp);
+static int HgfsFileOpen(HgfsSuperInfo *sip, struct vnode *vp,
+                        int flag, int permissions);
+static int HgfsDirClose(HgfsSuperInfo *sip, struct vnode *vp);
+static int HgfsFileClose(HgfsSuperInfo *sip, struct vnode *vp);
+static int HgfsGetNextDirEntry(HgfsSuperInfo *sip, HgfsHandle handle,
+                               uint32_t offset, char *nameOut, Bool *done);
+static int HgfsDoRead(HgfsSuperInfo *sip, HgfsHandle handle, uint64_t offset,
+                      uint32_t size, uio_t *uiop);
+static int HgfsDoWrite(HgfsSuperInfo *sip, HgfsHandle handle, int ioflag,
+                       uint64_t offset, uint32_t size, uio_t *uiop);
+static int HgfsDelete(HgfsSuperInfo *sip, char *filename, HgfsOp op);
+
+/* Local utility functions */
+#if HGFS_VFS_VERSION > 2
+static int HgfsMakeVnodeOps(HgfsSuperInfo *sip);
+#endif
+static int HgfsSubmitRequest(HgfsSuperInfo *sip, HgfsReq *req);
+static int HgfsValidateReply(HgfsReq *req, uint32_t minSize);
+static void HgfsAttrToSolaris(struct vnode *vp, const HgfsAttr *hgfsAttr,
+                              struct vattr *solAttr);
+static Bool HgfsSetattrCopy(struct vattr *solAttr, int flags,
+                            HgfsAttr *hgfsAttr, HgfsAttrChanges *update);
+static int HgfsMakeFullName(const char *path, uint32_t pathLen, const char *file,
+                            char *outBuf, ssize_t bufSize);
+static int HgfsGetOpenMode(uint32 flags);
+static int HgfsGetOpenFlags(uint32 flags);
+INLINE static void HgfsDisableSignals(k_sigset_t *oldIgnoreSet);
+INLINE static void HgfsRestoreSignals(k_sigset_t *oldIgnoreSet);
+
+
+/* vnode Operation prototypes */
+#if HGFS_VFS_VERSION <= 3
+static int HgfsOpen(struct vnode **vpp, int flag, struct cred *cr);
+static int HgfsClose(struct vnode *vp, int flag, int count, offset_t offset,
+                     struct cred *cr);
+#else
+static int HgfsOpen(struct vnode **vpp, int flag, struct cred *cr, caller_context_t *ctx);
+static int HgfsClose(struct vnode *vp, int flag, int count, offset_t offset,
+                     struct cred *cr, caller_context_t *ctx);
+#endif
+
+#if HGFS_VFS_VERSION == 2
+static int HgfsRead(struct vnode *vp, struct uio *uiop, int ioflag,
+                    struct cred *cr);
+static int HgfsWrite(struct vnode *vp, struct uio *uiop, int ioflag,
+                     struct cred *cr);
+#else
+static int HgfsRead(struct vnode *vp, struct uio *uiop, int ioflag,
+                    struct cred *cr, caller_context_t *ctx);
+static int HgfsWrite(struct vnode *vp, struct uio *uiop, int ioflag,
+                     struct cred *cr, caller_context_t *ctx);
+#endif
+
+#if HGFS_VFS_VERSION <= 3
+static int HgfsIoctl(struct vnode *vp, int cmd, intptr_t arg, int flag,
+                     struct cred *cr, int *rvalp);
+static int HgfsGetattr(struct vnode *vp, struct vattr *vap, int flags,
+                       struct cred *cr);
+#else
+static int HgfsIoctl(struct vnode *vp, int cmd, intptr_t arg, int flag,
+                     struct cred *cr, int *rvalp, caller_context_t *ctx);
+static int HgfsGetattr(struct vnode *vp, struct vattr *vap, int flags,
+                       struct cred *cr, caller_context_t *ctx);
+#endif
+
+#if HGFS_VFS_VERSION == 2
+static int HgfsSetattr(struct vnode *vp, struct vattr *vap, int flags,
+                       struct cred *cr);
+#else
+static int HgfsSetattr(struct vnode *vp, struct vattr *vap, int flags,
+                       struct cred *cr, caller_context_t *ctx);
+#endif
+
+#if HGFS_VFS_VERSION <= 3
+static int HgfsAccess(struct vnode *vp, int mode, int flags,
+                      struct cred *cr);
+static int HgfsLookup(struct vnode *dvp, char *nm, struct vnode **vpp,
+                      struct pathname *pnp, int flags,
+                      struct vnode *rdir, struct cred *cr);
+static int HgfsCreate(struct vnode *dvp, char *name, struct vattr *vap,
+                      vcexcl_t excl, int mode, struct vnode **vpp,
+                      struct cred *cr, int flag);
+static int HgfsRemove(struct vnode *vp, char *nm, struct cred *cr);
+static int HgfsLink(struct vnode *tdvp, struct vnode *svp, char *tnm,
+                    struct cred *cr);
+static int HgfsRename(struct vnode *sdvp, char *snm, struct vnode *tdvp,
+                      char *tnm, struct cred *cr);
+static int HgfsMkdir(struct vnode *dvp, char *dirname, struct vattr *vap,
+                     struct vnode **vpp, struct cred *cr);
+static int HgfsRmdir(struct vnode *vp, char *nm, struct vnode *cdir,
+                     struct cred *cr);
+static int HgfsReaddir(struct vnode *vp, struct uio *uiop, struct cred *cr,
+                       int *eofp);
+static int HgfsSymlink(struct vnode *dvp, char *linkname, struct vattr *vap,
+                       char *target, struct cred *cr);
+static int HgfsReadlink(struct vnode *vp, struct uio *uiop, struct cred *cr);
+static int HgfsFsync(struct vnode *vp, int syncflag, struct cred *cr);
+static void HgfsInactive(struct vnode *vp, struct cred *cr);
+static int HgfsFid(struct vnode *vp, struct fid *fidp);
+#else
+static int HgfsAccess(struct vnode *vp, int mode, int flags,
+                      struct cred *cr, caller_context_t *ctx);
+static int HgfsLookup(struct vnode *dvp, char *nm, struct vnode **vpp,
+                      struct pathname *pnp, int flags,
+                      struct vnode *rdir, struct cred *cr, caller_context_t *ctx,
+                      int *direntflags, pathname_t *realpnp);
+static int HgfsCreate(struct vnode *dvp, char *name, struct vattr *vap,
+                      vcexcl_t excl, int mode, struct vnode **vpp,
+                      struct cred *cr, int flag, caller_context_t *ctx,
+                      vsecattr_t *vsecp);
+static int HgfsRemove(struct vnode *vp, char *nm, struct cred *cr,
+                      caller_context_t *ctx, int flags);
+static int HgfsLink(struct vnode *tdvp, struct vnode *svp, char *tnm,
+                    struct cred *cr, caller_context_t *ctx, int flags);
+static int HgfsRename(struct vnode *sdvp, char *snm, struct vnode *tdvp,
+                      char *tnm, struct cred *cr, caller_context_t *ctx, int flags);
+static int HgfsMkdir(struct vnode *dvp, char *dirname, struct vattr *vap,
+                     struct vnode **vpp, struct cred *cr, caller_context_t *ctx,
+                     int flags, vsecattr_t *vsecp);
+static int HgfsRmdir(struct vnode *vp, char *nm, struct vnode *cdir,
+                     struct cred *cr, caller_context_t *ctx, int flags);
+static int HgfsReaddir(struct vnode *vp, struct uio *uiop, struct cred *cr,
+                       int *eofp, caller_context_t *ctx, int flags);
+static int HgfsSymlink(struct vnode *dvp, char *linkname, struct vattr *vap,
+                       char *target, struct cred *cr, caller_context_t *ctx,
+                       int flags);
+static int HgfsReadlink(struct vnode *vp, struct uio *uiop, struct cred *cr,
+                        caller_context_t *ctx);
+static int HgfsFsync(struct vnode *vp, int syncflag, struct cred *cr,
+                     caller_context_t *ctx);
+static void HgfsInactive(struct vnode *vp, struct cred *cr, caller_context_t *ctx);
+static int HgfsFid(struct vnode *vp, struct fid *fidp, caller_context_t *ctx);
+#endif
+
+#if HGFS_VFS_VERSION == 2
+static void HgfsRwlock(struct vnode *vp, int write_lock);
+#elif HGFS_VFS_VERSION == 3
+static void HgfsRwlock(struct vnode *vp, int write_lock, caller_context_t *ctx);
+#else
+static int HgfsRwlock(struct vnode *vp, int write_lock, caller_context_t *ctx);
+#endif
+
+#if HGFS_VFS_VERSION == 2
+static void HgfsRwunlock(struct vnode *vp, int write_lock);
+#else
+static void HgfsRwunlock(struct vnode *vp, int write_lock, caller_context_t *ctx);
+#endif
+
+#if HGFS_VFS_VERSION <= 3
+static int HgfsSeek(struct vnode *vp, offset_t ooff, offset_t *noffp);
+static int HgfsCmp(struct vnode *vp1, struct vnode *vp2);
+static int HgfsFrlock(struct vnode *vp, int cmd, struct flock64 *bfp, int flag,
+                      offset_t offset, struct flk_callback *, struct cred *cr);
+#else
+static int HgfsSeek(struct vnode *vp, offset_t ooff, offset_t *noffp,
+                    caller_context_t *ctx);
+static int HgfsCmp(struct vnode *vp1, struct vnode *vp2, caller_context_t *ctx);
+static int HgfsFrlock(struct vnode *vp, int cmd, struct flock64 *bfp, int flag,
+                      offset_t offset, struct flk_callback *, struct cred *cr,
+                      caller_context_t *ctx);
+#endif
+
+#if HGFS_VFS_VERSION == 2
+static int HgfsSpace(struct vnode *vp, int cmd, struct flock64 *bfp, int flag,
+                     offset_t offset, struct cred *cr);
+#else
+static int HgfsSpace(struct vnode *vp, int cmd, struct flock64 *bfp, int flag,
+                     offset_t offset, struct cred *cr, caller_context_t *ctx);
+#endif
+
+#if HGFS_VFS_VERSION <= 3
+static int HgfsRealvp(struct vnode *vp, struct vnode **vpp);
+static int HgfsGetpage(struct vnode *vp, offset_t off, size_t len, uint_t *protp,
+                       struct page **plarr, size_t plsz, struct seg *seg,
+                       caddr_t addr, enum seg_rw rw, struct cred *cr);
+static int HgfsPutpage(struct vnode *vp, offset_t off, size_t len, int flags,
+                       struct cred *cr);
+static int HgfsMap(struct vnode *vp, offset_t off, struct as *as,
+                   caddr_t *addrp, size_t len, uchar_t prot,
+                   uchar_t maxprot, uint_t flags, struct cred *cr);
+static int HgfsAddmap(struct vnode *vp, offset_t off, struct as *as,
+                      caddr_t addr, size_t len, uchar_t prot,
+                      uchar_t maxprot, uint_t flags, struct cred *cr);
+static int HgfsDelmap(struct vnode *vp, offset_t off, struct as *as,
+                      caddr_t addr, size_t len, uint_t prot,
+                      uint_t maxprot, uint_t flags, struct cred *cr);
+static int HgfsDump(struct vnode *vp, caddr_t addr, int lbdn, int dblks);
+static int HgfsPathconf(struct vnode *vp, int cmd, ulong_t *valp,
+                        struct cred *cr);
+static int HgfsPageio(struct vnode *vp, struct page *pp, u_offset_t io_off,
+                      size_t io_len, int flags, struct cred *cr);
+static int HgfsDumpctl(struct vnode *vp, int action, int *blkp);
+static void HgfsDispose(struct vnode *vp, struct page *pp, int flag, int dn,
+                        struct cred *cr);
+static int HgfsSetsecattr(struct vnode *vp, vsecattr_t *vsap, int flag,
+                          struct cred *cr);
+#else
+static int HgfsRealvp(struct vnode *vp, struct vnode **vpp, caller_context_t *ctx);
+static int HgfsGetpage(struct vnode *vp, offset_t off, size_t len, uint_t *protp,
+                       struct page **plarr, size_t plsz, struct seg *seg,
+                       caddr_t addr, enum seg_rw rw, struct cred *cr,
+                       caller_context_t *ctx);
+static int HgfsPutpage(struct vnode *vp, offset_t off, size_t len, int flags,
+                       struct cred *cr, caller_context_t *ctx);
+static int HgfsMap(struct vnode *vp, offset_t off, struct as *as,
+                   caddr_t *addrp, size_t len, uchar_t prot,
+                   uchar_t maxprot, uint_t flags, struct cred *cr, caller_context_t *ctx);
+static int HgfsAddmap(struct vnode *vp, offset_t off, struct as *as,
+                      caddr_t addr, size_t len, uchar_t prot,
+                      uchar_t maxprot, uint_t flags, struct cred *cr,
+                      caller_context_t *ctx);
+static int HgfsDelmap(struct vnode *vp, offset_t off, struct as *as,
+                      caddr_t addr, size_t len, uint_t prot,
+                      uint_t maxprot, uint_t flags, struct cred *cr,
+                      caller_context_t *ctx);
+static int HgfsDump(struct vnode *vp, caddr_t addr, offset_t lbdn, offset_t dblks,
+                    caller_context_t *ctx);
+static int HgfsPathconf(struct vnode *vp, int cmd, ulong_t *valp,
+                        struct cred *cr, caller_context_t *ctx);
+static int HgfsPageio(struct vnode *vp, struct page *pp, u_offset_t io_off,
+                      size_t io_len, int flags, struct cred *cr, caller_context_t *ctx);
+static int HgfsDumpctl(struct vnode *vp, int action, offset_t *blkp,
+                       caller_context_t *ctx);
+static void HgfsDispose(struct vnode *vp, struct page *pp, int flag, int dn,
+                        struct cred *cr, caller_context_t *ctx);
+static int HgfsSetsecattr(struct vnode *vp, vsecattr_t *vsap, int flag,
+                          struct cred *cr, caller_context_t *ctx);
+#endif
+
+#if HGFS_VFS_VERSION == 2
+static int HgfsShrlock(struct vnode *vp, int cmd, struct shrlock *chr,
+                       int flag);
+#elif HGFS_VFS_VERSION == 3
+static int HgfsShrlock(struct vnode *vp, int cmd, struct shrlock *chr,
+                       int flag, cred_t *cr);
+#else /* SOL11 */
+static int HgfsShrlock(struct vnode *vp, int cmd, struct shrlock *chr,
+                       int flag, cred_t *cr, caller_context_t *ctx);
+#endif
+
+#if HGFS_VFS_VERSION == 3
+static int HgfsVnevent(struct vnode *vp, vnevent_t event);
+#elif HGFS_VFS_VERSION == 5
+static int HgfsVnevent(struct vnode *vp, vnevent_t event, vnode_t *dvp,
+                       char *fnm, caller_context_t *ctx);
+#endif
+
+
+#if HGFS_VFS_VERSION == 2
+/* vnode Operations Structure */
+struct vnodeops HgfsVnodeOps = {
+   HgfsOpen,            /* vop_open() */
+   HgfsClose,           /* vop_close() */
+   HgfsRead,            /* vop_read() */
+   HgfsWrite,           /* vop_write() */
+   HgfsIoctl,           /* vop_ioctl() */
+   fs_setfl,            /* vop_setfl() */
+   HgfsGetattr,         /* vop_getattr() */
+   HgfsSetattr,         /* vop_setattr() */
+   HgfsAccess,          /* vop_access() */
+   HgfsLookup,          /* vop_lookup() */
+   HgfsCreate,          /* vop_create() */
+   HgfsRemove,          /* vop_remove() */
+   HgfsLink,            /* vop_link() */
+   HgfsRename,          /* vop_rename() */
+   HgfsMkdir,           /* vop_mkdir() */
+   HgfsRmdir,           /* vop_rmdir() */
+   HgfsReaddir,         /* vop_readdir() */
+   HgfsSymlink,         /* vop_symlink() */
+   HgfsReadlink,        /* vop_readlink() */
+   HgfsFsync,           /* vop_fsync() */
+   HgfsInactive,        /* vop_inactive() */
+   HgfsFid,             /* vop_fid() */
+   HgfsRwlock,          /* vop_rwlock() */
+   HgfsRwunlock,        /* vop_rwunlock() */
+   HgfsSeek,            /* vop_seek() */
+   HgfsCmp,             /* vop_cmp() */
+   HgfsFrlock,          /* vop_frlock() */
+   HgfsSpace,           /* vop_space() */
+   HgfsRealvp,          /* vop_realvp() */
+   HgfsGetpage,         /* vop_getpage() */
+   HgfsPutpage,         /* vop_putpage() */
+   HgfsMap,             /* vop_map() */
+   HgfsAddmap,          /* vop_addmap() */
+   HgfsDelmap,          /* vop_delmap() */
+   fs_poll,             /* vop_poll() */
+   HgfsDump,            /* vop_dump() */
+   HgfsPathconf,        /* vop_pathconf() */
+   HgfsPageio,          /* vop_pageio() */
+   HgfsDumpctl,         /* vop_dumpctl() */
+   HgfsDispose,         /* vop_dispose() */
+   HgfsSetsecattr,      /* vop_setsecattr() */
+   fs_fab_acl,          /* vop_getsecattr() */
+   HgfsShrlock          /* vop_shrlock() */
+};
+
+#endif
+
+
+/*
+ * Vnode Entry Points
+ */
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsOpen --
+ *
+ *    Invoked when open(2) is called on a file in our filesystem.  Sends an
+ *    OPEN request to the Hgfs server with the filename of this vnode.
+ *
+ *    "Opens a file referenced by the supplied vnode.  The open() system call
+ *    has already done a vop_lookup() on the path name, which returned a vnode
+ *    pointer and then calls to vop_open().  This function typically does very
+ *    little since most of the real work was performed by vop_lookup()."
+ *    (Solaris Internals, p537)
+ *
+ * Results:
+ *    Returns 0 on success and an error code on error.
+ *
+ * Side effects:
+ *    The HgfsOpenFile for this file is given a handle that can be used on
+ *    future read and write requests.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static int
+HgfsOpen(struct vnode **vpp,    // IN: Vnode for file to open
+         int flag,              // IN: Open flags
+         struct cred *cr)       // IN: Credentials of caller
+#else
+static int
+HgfsOpen(struct vnode **vpp,    // IN: Vnode for file to open
+         int flag,              // IN: Open flags
+         struct cred *cr,       // IN: Credentials of caller
+         caller_context_t *ctx) // IN: Context of caller
+#endif
+{
+   HgfsSuperInfo *sip;
+
+   if (!vpp || !cr) {
+      cmn_err(HGFS_ERROR, "HgfsOpen: NULL input from Kernel.\n");
+      return EINVAL;
+   }
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsOpen().\n");
+
+
+   sip = HgfsGetSuperInfo();
+   if (!sip) {
+      return EIO;
+   }
+
+   /* Make sure we know the filename. */
+   ASSERT(HGFS_KNOW_FILENAME(*vpp));
+
+   /*
+    * Make sure the handle is not already set.  If it is, this means the file
+    * has already been opened so we'll need to create a new vnode since we keep
+    * a vnode for each open instance of a file.  This ensures that the handle
+    * we'll create now won't clobber the other one's open-file state.
+    */
+   if (HgfsHandleIsSet(*vpp)) {
+      int ret;
+      struct vnode *origVp = *vpp;
+
+      ret = HgfsVnodeDup(vpp, origVp, sip, &sip->fileHashTable);
+      if (ret) {
+         return EIO;
+      }
+   }
+
+   switch((*vpp)->v_type) {
+   case VDIR:
+      DEBUG(VM_DEBUG_COMM, "HgfsOpen: opening a directory\n");
+      return HgfsDirOpen(sip, *vpp);
+
+   case VREG:
+      {
+         HgfsMode mode = 0;
+
+         /*
+          * If HgfsCreate() was called prior to this, this fills in the mode we
+          * saved there.  It's okay if this fails since often HgfsCreate()
+          * won't have been called.
+          */
+         HgfsGetOpenFileMode(*vpp, &mode);
+
+         DEBUG(VM_DEBUG_COMM, "HgfsOpen: opening a file with flag %x\n", flag);
+         return HgfsFileOpen(sip, *vpp, flag, mode);
+      }
+
+   default:
+      DEBUG(VM_DEBUG_FAIL,
+            "HgfsOpen: unrecognized file of type %d.\n", (*vpp)->v_type);
+      return EINVAL;
+   }
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsClose --
+ *
+ *    Invoked when a user calls close(2) on a file in our filesystem.  Sends
+ *    a CLOSE request to the Hgfs server with the filename of this vnode.
+ *
+ *    "Closes the file given by the supplied vnode.  When this is the last
+ *    close, some filesystems use vop_close() to initiate a writeback of
+ *    outstanding dirty pages by checking the reference cound in the vnode."
+ *    (Solaris Internals, p536)
+ *
+ * Results:
+ *    Returns 0 on success and an error code on error.
+ *
+ * Side effects:
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static int
+HgfsClose(struct vnode *vp,     // IN: Vnode of file that is being closed
+          int flag,             // IN: Flags file was opened with
+          int count,            // IN: Reference count on this vnode
+          offset_t offset,      // IN: XXX
+          struct cred *cr)      // IN: Credentials of caller
+#else
+static int
+HgfsClose(struct vnode *vp,        // IN: Vnode of file that is being closed
+          int flag,                // IN: Flags file was opened with
+          int count,               // IN: Reference count on this vnode
+          offset_t offset,         // IN: XXX
+          struct cred *cr,         // IN: Credentials of caller
+          caller_context_t *ctx)   // IN: Context of caller
+#endif
+{
+   HgfsSuperInfo *sip;
+
+   if (!vp) {
+      cmn_err(HGFS_ERROR, "HgfsClose: NULL input from Kernel.\n");
+      return EINVAL;
+   }
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsClose(). (vp=%p)\n", vp);
+   DEBUG(VM_DEBUG_INFO, "HgfsClose: flag=%x, count=%x, offset=%lld\n",
+         flag, count, offset);
+
+   /*
+    * Solaris calls this function with a count greater than one at certain
+    * times.  We only want to actually close it on the last close.
+    */
+   if (count > 1) {
+      return 0;
+   }
+
+   sip = HgfsGetSuperInfo();
+   if (!sip) {
+      return EIO;
+   }
+
+   if ( !HGFS_KNOW_FILENAME(vp) ) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsClose: we don't know the filename of:\n");
+      HgfsDebugPrintVnode(VM_DEBUG_STRUCT, "HgfsClose", vp);
+      return EINVAL;
+   }
+
+   /*
+    * If we are closing a directory we need to send a SEARCH_CLOSE request,
+    * but if we are closing a regular file we need to send a CLOSE request.
+    * Other file types are not supported by the Hgfs protocol.
+    */
+
+   switch (vp->v_type) {
+   case VDIR:
+      return HgfsDirClose(sip, vp);
+
+   case VREG:
+      return HgfsFileClose(sip, vp);
+
+   default:
+      DEBUG(VM_DEBUG_FAIL, "HgfsClose: unsupported filetype %d.\n", vp->v_type);
+      return EINVAL;
+   }
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsRead --
+ *
+ *    Invoked when a user calls read(2) on a file in our filesystem.
+ *
+ *    We call HgfsDoRead() to fill the user's buffer until the request is met
+ *    or the file has no more data.  This is done since we can only transfer
+ *    HGFS_IO_MAX bytes in any one request.
+ *
+ *    "Reads the range supplied for the given vnode.  vop_read() typically
+ *    maps the requested range of a file into kernel memory and then uses
+ *    vop_getpage() to do the real work." (Solaris Internals, p537)
+ *
+ * Results:
+ *    Returns zero on success and an error code on failure.
+ *
+ * Side effects:
+ *    None.
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION == 2
+static int
+HgfsRead(struct vnode *vp,      // IN: Vnode of file to read
+         struct uio *uiop,      // IN: User's read request
+         int ioflag,            // IN: XXX
+         struct cred *cr)       // IN: Credentials of caller
+#else
+static int
+HgfsRead(struct vnode *vp,              // IN: Vnode of file to read
+         struct uio *uiop,              // IN: User's read request
+         int ioflag,                    // IN: XXX
+         struct cred *cr,               // IN: Credentials of caller
+         caller_context_t *ctx)         // IN: Context of caller
+#endif
+{
+   HgfsSuperInfo *sip;
+   HgfsHandle handle;
+   uint64_t offset;
+   int ret;
+
+   if (!vp || !uiop) {
+      cmn_err(HGFS_ERROR, "HgfsRead: NULL input from Kernel.\n");
+      return EINVAL;
+   }
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsRead: entry.\n");
+
+   /* We can't read from directories, that's what readdir() is for. */
+   if (vp->v_type == VDIR) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsRead: cannot read directories.\n");
+      return EISDIR;
+   }
+
+   sip = HgfsGetSuperInfo();
+   if (!sip) {
+      return EIO;
+   }
+
+   /* This is where the user wants to start reading from in the file. */
+   offset = uiop->uio_loffset;
+
+   /*
+    * We need to get the handle for the requests sent to the Hgfs server.  Note
+    * that this is guaranteed to not change until a close(2) is called on this
+    * vnode, so it's safe and correct to acquire it outside the loop below.
+    */
+   ret = HgfsGetOpenFileHandle(vp, &handle);
+   if (ret) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsRead: could not get handle.\n");
+      return EINVAL;
+   }
+
+   /*
+    * Here we loop around HgfsDoRead with requests less than or equal to
+    * HGFS_IO_MAX until one of the following conditions is met:
+    *  (1) All the requested data has been read
+    *  (2) The file has no more data
+    *  (3) An error occurred
+    *
+    * Since HgfsDoRead() calls uiomove(9F), we know condition (1) is met when
+    * the uio structure's uio_resid is decremented to zero.  If HgfsDoRead()
+    * returns 0 we know condition (2) was met, and if it returns less than 0 we
+    * know condtion (3) was met.
+    */
+   do {
+      uint32_t size;
+
+      DEBUG(VM_DEBUG_INFO, "HgfsRead: offset=%"FMT64"d, uio_loffset=%lld\n",
+            offset, uiop->uio_loffset);
+      DEBUG(VM_DEBUG_HANDLE, "HgfsRead: ** handle=%d, file=%s\n",
+            handle, HGFS_VP_TO_FILENAME(vp));
+
+      /* Request at most HGFS_IO_MAX bytes */
+      size = (uiop->uio_resid > HGFS_IO_MAX) ? HGFS_IO_MAX : uiop->uio_resid;
+
+      /* Send one read request. */
+      ret = HgfsDoRead(sip, handle, offset, size, uiop);
+      if (ret == 0) {
+         /* On end of file we return success */
+         DEBUG(VM_DEBUG_DONE, "HgfsRead: end of file reached.\n");
+         return 0;
+      } else  if (ret < 0) {
+         /*
+          * HgfsDoRead() returns the negative of an appropriate error code to
+          * differentiate between success and error cases.  We flip the sign
+          * and return the appropriate error code.  See the HgfsDoRead()
+          * function header for a fuller explanation.
+          */
+         DEBUG(VM_DEBUG_FAIL, "HgfsRead: HgfsDoRead() failed.\n");
+         return -ret;
+      }
+
+      /* Bump the offset past where we have already read. */
+      offset += ret;
+   } while (uiop->uio_resid);
+
+   /* We fulfilled the user's read request, so return success. */
+   DEBUG(VM_DEBUG_DONE, "HgfsRead: done.\n");
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsWrite --
+ *
+ *    This is invoked when a user calls write(2) on a file in our filesystem.
+ *
+ *    We call HgfsDoWrite() once with requests less than or equal to
+ *    HGFS_IO_MAX bytes until the user's write request has completed.
+ *
+ *    "Writes the range supplied for the given vnode.  The write system call
+ *    typically maps the requested range of a file into kernel memory and then
+ *    uses vop_putpage() to do the real work." (Solaris Internals, p538)
+ *
+ * Results:
+ *    Returns 0 on success and error code on error.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION < 3
+static int
+HgfsWrite(struct vnode *vp,     // IN: Vnode of file to write to
+          struct uio *uiop,     // IN: User's write request
+          int ioflag,           // IN: XXX
+          struct cred *cr)      // IN: Credentials of caller
+#else
+static int
+HgfsWrite(struct vnode *vp,             // IN: Vnode of file to write to
+          struct uio *uiop,             // IN: User's write request
+          int ioflag,                   // IN: XXX
+          struct cred *cr,              // IN: Credentials of caller
+          caller_context_t *ctx)        // IN: Context of caller
+#endif
+{
+   HgfsSuperInfo *sip;
+   HgfsHandle handle;
+   uint64_t offset;
+   int ret;
+
+   if (!vp || !uiop) {
+      cmn_err(HGFS_ERROR, "HgfsWrite: NULL input from Kernel.\n");
+      return EINVAL;
+   }
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsWrite: entry. (vp=%p)\n", vp);
+   DEBUG(VM_DEBUG_INFO, "HgfsWrite: ***ioflag=%x, uio_resid=%ld\n",
+         ioflag, uiop->uio_resid);
+
+   /* Skip write requests for 0 bytes. */
+   if (uiop->uio_resid == 0) {
+      DEBUG(VM_DEBUG_INFO, "HgfsWrite: write of 0 bytes requested.\n");
+      return 0;
+   }
+
+   sip = HgfsGetSuperInfo();
+   if (!sip) {
+      return EIO;
+   }
+
+   DEBUG(VM_DEBUG_INFO, "HgfsWrite: file is %s\n", HGFS_VP_TO_FILENAME(vp));
+
+   /* This is where the user will begin writing into the file. */
+   offset = uiop->uio_loffset;
+
+   /* Get the handle we need to supply the Hgfs server. */
+   ret = HgfsGetOpenFileHandle(vp, &handle);
+   if (ret) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsWrite: could not get handle.\n");
+      return EINVAL;
+   }
+
+   /*
+    * We loop around calls to HgfsDoWrite() until either (1) we have written all
+    * of our data or (2) an error has occurred.  uiop->uio_resid is decremented
+    * by uiomove(9F) inside HgfsDoWrite(), so condition (1) is met when it
+    * reaches zero.  Condition (2) occurs when HgfsDoWrite() returns less than
+    * zero.
+    */
+   do {
+      uint32_t size;
+
+      DEBUG(VM_DEBUG_INFO, "HgfsWrite: ** offset=%"FMT64"d, uio_loffset=%lld\n",
+            offset, uiop->uio_loffset);
+      DEBUG(VM_DEBUG_HANDLE, "HgfsWrite: ** handle=%d, file=%s\n",
+            handle, HGFS_VP_TO_FILENAME(vp));
+
+      /* Write at most HGFS_IO_MAX bytes. */
+      size = (uiop->uio_resid > HGFS_IO_MAX) ? HGFS_IO_MAX : uiop->uio_resid;
+
+      /* Send one write request. */
+      ret = HgfsDoWrite(sip, handle, ioflag, offset, size, uiop);
+      if (ret < 0) {
+         /*
+          * As in HgfsRead(), we need to flip the sign.  See the comment in the
+          * function header of HgfsDoWrite() for a more complete explanation.
+          */
+         DEBUG(VM_DEBUG_INFO, "HgfsWrite: HgfsDoWrite failed, returning %d\n", -ret);
+         return -ret;
+      }
+
+      /* Increment the offest by the amount already written. */
+      offset += ret;
+
+   } while (uiop->uio_resid);
+
+   /* We have completed the user's write request, so return success. */
+   DEBUG(VM_DEBUG_DONE, "HgfsWrite: done.\n");
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsIoctl --
+ *
+ *    Invoked when a user calls ioctl(2) on a file in our filesystem.
+ *    Performs a specified operation on the file.
+ *
+ * Results:
+ *    ENOTSUP
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static int
+HgfsIoctl(struct vnode *vp,     // IN: Vnode of file to operate on
+          int cmd,              // IN: Requested command from user
+          intptr_t arg,         // IN: Arguments for command
+          int flag,             // IN: XXX
+          struct cred *cr,      // IN: Credentials of caller
+          int *rvalp)           //XXX
+#else
+static int
+HgfsIoctl(struct vnode *vp,        // IN: Vnode of file to operate on
+          int cmd,                 // IN: Requested command from user
+          intptr_t arg,            // IN: Arguments for command
+          int flag,                // IN: XXX
+          struct cred *cr,         // IN: Credentials of caller
+          int *rvalp,              //XXX
+          caller_context_t *ctx)   // IN: Context of caller
+#endif
+{
+   DEBUG(VM_DEBUG_NOTSUP, "HgfsIoctl() NOTSUP.\n");
+
+   return ENOTSUP;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsSetfl --
+ *
+ *    "Sets file locks on the supplied vnode." (Solaris Internals, p538)
+ *
+ *    Use fs_setfl from <sys/fs_subr.h>?  Do we need this?
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+/*
+int
+HgfsSetfl(struct vnode *vp,
+          int oflags,
+          int nflags,
+          struct cred *cr)
+{
+   DEBUG(VM_DEBUG_NOTSUP, "HgfsSetfl() NOTSUP.\n");
+
+   return ENOTSUP;
+}*/
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsGetattr --
+ *
+ *    "Gets the attributes for the supplied vnode." (Solaris Internals, p536)
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static int
+HgfsGetattr(struct vnode *vp,   // IN: Vnode of file to get attributes for
+            struct vattr *vap,  // OUT: Filled in with attributes of file
+            int flags,          // IN: XXX
+            struct cred *cr)    // IN: Credentials of caller
+#else
+static int
+HgfsGetattr(struct vnode *vp,      // IN: Vnode of file to get attributes for
+            struct vattr *vap,     // OUT: Filled in with attributes of file
+            int flags,             // IN: XXX
+            struct cred *cr,       // IN: Credentials of caller
+            caller_context_t *ctx) // IN: Context of caller
+#endif
+{
+   HgfsSuperInfo *sip;
+   HgfsReq *req;
+   HgfsRequestGetattr *request;
+   HgfsReplyGetattr *reply;
+   int ret;
+
+   if (!vp || !vap) {
+      cmn_err(HGFS_ERROR, "HgfsGetattr: NULL input from Kernel.\n");
+      return EINVAL;
+   }
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsGetattr().\n");
+
+   /*
+    * Here we should send a Getattr request then examine vap->va_mask to
+    * retun the values the user asked for.  HgfsAttrToSolaris() handles filling
+    * in the Solaris structure with the correct values based on the Hgfs type.
+    */
+
+   sip = HgfsGetSuperInfo();
+   if (!sip) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsGetattr() couldn't get superinfo.\n");
+      return EIO;
+   }
+
+   ASSERT(HGFS_KNOW_FILENAME(vp));
+
+   req = HgfsGetNewReq(sip);
+   if (!req) {
+      return EIO;
+   }
+
+   request = (HgfsRequestGetattr *)req->packet;
+   HGFS_INIT_REQUEST_HDR(request, req, HGFS_OP_GETATTR);
+
+   /*
+    * Now we need to convert the filename to cross-platform and unescaped
+    * format.
+    */
+   ret = CPName_ConvertTo(HGFS_VP_TO_FILENAME(vp), MAXPATHLEN, request->fileName.name);
+   if (ret < 0) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsGetattr: CPName_ConvertTo failed.\n");
+      ret = ENAMETOOLONG;
+      /* We need to set the request's state to error before destroying. */
+      HgfsReqSetState(req, HGFS_REQ_ERROR);
+      goto destroy_out;
+   }
+
+   request->fileName.length = ret;
+
+   req->packetSize = sizeof *request + request->fileName.length;
+
+   /*
+    * Now submit request and wait for reply.  The request's state will be
+    * properly set to COMPLETED, ERROR, or ABANDONED after calling
+    * HgfsSubmitRequest()
+    */
+   ret = HgfsSubmitRequest(sip, req);
+   if (ret) {
+      /* HgfsSubmitRequest destroys the request if necessary */
+      goto out;
+   }
+
+   reply = (HgfsReplyGetattr *)req->packet;
+
+   if (HgfsValidateReply(req, sizeof reply->header) != 0) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsGetattr: reply not valid.\n");
+      ret = EPROTO;
+      goto destroy_out;
+   }
+
+   switch (reply->header.status) {
+   case HGFS_STATUS_SUCCESS:
+      /* Make sure we got all of the attributes */
+      if (req->packetSize != sizeof *reply) {
+         DEBUG(VM_DEBUG_FAIL, "HgfsGetattr: packet too small.\n");
+         ret = EIO;
+         break;
+      }
+
+      DEBUG(VM_DEBUG_COMM, "HgfsGetattr: received reply for ID %d\n",
+            reply->header.id);
+      DEBUG(VM_DEBUG_COMM, " status: %d (see hgfsProto.h)\n",
+            reply->header.status);
+      DEBUG(VM_DEBUG_COMM, " file type: %d\n", reply->attr.type);
+      DEBUG(VM_DEBUG_COMM, " file size: %"FMT64"u\n", reply->attr.size);
+      DEBUG(VM_DEBUG_COMM, " permissions: %o\n", reply->attr.permissions);
+      DEBUG(VM_DEBUG_COMM, "HgfsGetattr: filename %s\n", HGFS_VP_TO_FILENAME(vp));
+
+      /* Map the Hgfs attributes into the Solaris attributes */
+      HgfsAttrToSolaris(vp, &reply->attr, vap);
+
+      DEBUG(VM_DEBUG_DONE, "HgfsGetattr: done.\n");
+      break;
+
+   /* We'll add other error codes based on status here */
+   default:
+      ret = EIO;
+      break;
+   }
+
+destroy_out:
+   HgfsDestroyReq(sip, req);
+out:
+   return ret;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsSetattr --
+ *
+ *    Maps the Solaris attributes to Hgfs attributes (by calling
+ *    HgfsSetattrCopy()) and sends a set attribute request to the Hgfs server.
+ *
+ *    "Sets the attributes for the supplied vnode." (Solaris Internals, p537)
+ *
+ * Results:
+ *    Returns 0 on success and a non-zero error code on error.
+ *
+ * Side effects:
+ *    The file on the host will have new attributes.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION == 2
+static int
+HgfsSetattr(struct vnode *vp,   // IN: Vnode of file to get attributes for
+            struct vattr *vap,  // IN: New attributes for the file
+            int flags,          // IN: Flags for this call (from sys/vnode.h)
+            struct cred *cr)    // IN: Credentials of caller
+#else
+static int
+HgfsSetattr(struct vnode *vp,       // IN: Vnode of file to get attributes for
+            struct vattr *vap,      // IN: New attributes for the file
+            int flags,              // IN: Flags for this call (from sys/vnode.h)
+            struct cred *cr,        // IN: Credentials of caller
+            caller_context_t *ctx)  // IN: Context of caller
+#endif
+{
+   HgfsSuperInfo *sip;
+   HgfsReq *req;
+   HgfsRequestSetattr *request;
+   HgfsReplySetattr *reply;
+   int ret;
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsSetattr().\n");
+
+   if (!vp || !vap) {
+      cmn_err(HGFS_ERROR, "HgfsSetattr: NULL input from Kernel.\n");
+      return EINVAL;
+   }
+
+   if ( !HGFS_KNOW_FILENAME(vp) ) {
+      DEBUG(VM_DEBUG_FAIL,
+            "HgfsSetattr: we don't know filename to set attributes for.\n");
+      return EINVAL;
+   }
+
+   sip = HgfsGetSuperInfo();
+   if (!sip) {
+      return EIO;
+   }
+
+   req = HgfsGetNewReq(sip);
+   if (!req) {
+      return EIO;
+   }
+
+   request = (HgfsRequestSetattr *)req->packet;
+   HGFS_INIT_REQUEST_HDR(request, req, HGFS_OP_SETATTR);
+
+   /*
+    * Fill the attributes and update fields of the request.  If no updates are
+    * needed then we will just return success without sending the request.
+    */
+   if (HgfsSetattrCopy(vap, flags, &request->attr, &request->update) == FALSE) {
+      DEBUG(VM_DEBUG_DONE, "HgfsSetattr: don't need to update attributes.\n");
+      ret = 0;
+      /* We need to set the request state to completed before destroying. */
+      HgfsReqSetState(req, HGFS_REQ_COMPLETED);
+      goto destroy_out;
+   }
+
+   /* Convert the filename to cross platform and escape its buffer. */
+   ret = CPName_ConvertTo(HGFS_VP_TO_FILENAME(vp), MAXPATHLEN, request->fileName.name);
+   if (ret < 0) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsSetattr: CPName_ConvertTo failed.\n");
+      ret = ENAMETOOLONG;
+      /* We need to set the request state to error before destroying. */
+      HgfsReqSetState(req, HGFS_REQ_ERROR);
+      goto destroy_out;
+   }
+
+   request->fileName.length = ret;
+
+   /* The request's size includes the request and filename. */
+   req->packetSize = sizeof *request + request->fileName.length;
+
+   ret = HgfsSubmitRequest(sip, req);
+   if (ret) {
+      /* HgfsSubmitRequest() destroys the request if necessary. */
+      goto out;
+   }
+
+   reply = (HgfsReplySetattr *)req->packet;
+
+   if (HgfsValidateReply(req, sizeof *reply) != 0) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsSetattr: invalid reply received.\n");
+      ret = EPROTO;
+      goto destroy_out;
+   }
+
+   switch(reply->header.status) {
+   case HGFS_STATUS_SUCCESS:
+      /* Success handled after switch. */
+      break;
+
+   case HGFS_STATUS_NO_SUCH_FILE_OR_DIR:
+   case HGFS_STATUS_INVALID_NAME:
+      DEBUG(VM_DEBUG_FAIL, "HgfsSetattr: no such file or directory.\n");
+      ret = ENOENT;
+      goto destroy_out;
+
+   case HGFS_STATUS_OPERATION_NOT_PERMITTED:
+      DEBUG(VM_DEBUG_FAIL, "HgfsSetattr: operation not permitted.\n");
+      ret = EPERM;
+      goto destroy_out;
+
+   default:
+      DEBUG(VM_DEBUG_FAIL, "HgfsSetattr: default error.\n");
+      ret = EPROTO;
+      goto destroy_out;
+   }
+
+   /* Success */
+   ret = 0;
+   DEBUG(VM_DEBUG_DONE, "HgfsSetattr: done.\n");
+
+destroy_out:
+   HgfsDestroyReq(sip, req);
+out:
+   return ret;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsAccess --
+ *
+ *    This function is invoked when the user calls access(2) on a file in our
+ *    filesystem.  It checks to ensure the user has the specified type of
+ *    access to the file.
+ *
+ *    We send a GET_ATTRIBUTE request by calling HgfsGetattr() to get the mode
+ *    (permissions) for the provided vnode.
+ *
+ * Results:
+ *    Returns 0 if access is allowed and a non-zero error code otherwise.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static int
+HgfsAccess(struct vnode *vp,    // IN: Vnode of file to check access for
+           int mode,            // IN: Mode of access
+           int flags,           // IN: XXX
+           struct cred *cr)     // IN: Credentials of caller
+#else
+static int
+HgfsAccess(struct vnode *vp,       // IN: Vnode of file to check access for
+           int mode,               // IN: Mode of access
+           int flags,              // IN: XXX
+           struct cred *cr,        // IN: Credentials of caller
+           caller_context_t *ctx)  // IN: Context of caller
+#endif
+{
+   int ret;
+   struct vattr vap;
+
+   if (!vp | !cr) {
+      cmn_err(HGFS_ERROR, "HgfsAccess: NULL input from Kernel.\n");
+      return EINVAL;
+   }
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsAccess(). (vp=%p, mode=%o, flags=%x)\n",
+         vp, mode, flags);
+
+   /* We only care about the file's mode (permissions).  That is, not the owner */
+   vap.va_mask = AT_MODE;
+
+   /* Get the attributes for this file from the Hgfs server. */
+#if HGFS_VFS_VERSION <= 3
+   ret = HgfsGetattr(vp, &vap, flags, cr);
+#else
+   ret = HgfsGetattr(vp, &vap, flags, cr, NULL);
+#endif
+   if (ret) {
+      return ret;
+   }
+
+   DEBUG(VM_DEBUG_INFO, "HgfsAccess: vp's mode: %o\n", vap.va_mode);
+
+   /*
+    * mode is the desired access from the caller, and is composed of S_IREAD,
+    * S_IWRITE, and S_IEXEC from <sys/stat.h>.  Since the mode of the file is
+    * guaranteed to only contain owner permissions (by the Hgfs server), we
+    * don't need to shift any bits.
+    */
+   if ((mode & S_IREAD) && !(vap.va_mode & S_IREAD)) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsAccess: read access not allowed (%s).\n",
+            HGFS_VP_TO_FILENAME(vp));
+      return EPERM;
+   }
+
+   if ((mode & S_IWRITE) && !(vap.va_mode & S_IWRITE)) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsAccess: write access not allowed (%s).\n",
+            HGFS_VP_TO_FILENAME(vp));
+      return EPERM;
+   }
+
+   if ((mode & S_IEXEC) && !(vap.va_mode & S_IEXEC)) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsAccess: execute access not allowed (%s).\n",
+            HGFS_VP_TO_FILENAME(vp));
+      return EPERM;
+   }
+
+   /* Success */
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsLookup --
+ *
+ *    Looks in the provided directory for the specified filename.  If we cannot
+ *    determine the vnode locally (i.e, the vnode is not the root vnode of the
+ *    filesystem or the provided dvp), we send a getattr request to the server
+ *    and allocate a vnode and internal filesystem state for this file.
+ *
+ *    "Looks up the path name for the supplied vnode.  The vop_lookup() does
+ *    file-name translation for the open, stat system calls." (Solaris
+ *    Internals, p537)
+ *
+ * Results:
+ *   Returns zero on success and ENOENT if the file cannot be found
+ *   If file is found, a vnode representing the file is returned in vpp.
+ *
+ * Side effects:
+ *   None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static int
+HgfsLookup(struct vnode *dvp,   // IN:  Directory to look in
+           char *nm,            // IN:  Name to lookup in directory
+           struct vnode **vpp,  // OUT: Pointer to vnode representing found file
+           struct pathname *pnp,// IN:  XXX
+           int flags,           // IN:  XXX
+           struct vnode *rdir,  // IN:  XXX
+           struct cred *cr)     // IN:  Credentials of caller
+
+#else
+static int
+HgfsLookup(struct vnode *dvp,      // IN:  Directory to look in
+           char *nm,               // IN:  Name to lookup in directory
+           struct vnode **vpp,     // OUT: Pointer to vnode representing found file
+           struct pathname *pnp,   // IN:  XXX
+           int flags,              // IN:  XXX
+           struct vnode *rdir,     // IN:  XXX
+           struct cred *cr,        // IN: Credentials of caller
+           caller_context_t *ctx,  // IN: Context of caller
+           int *direntflags,       // IN: XXX
+           pathname_t *realpnp)    // IN: XXX
+#endif
+{
+   int ret;
+   HgfsReq *req;
+   HgfsRequestGetattr *request;
+   HgfsReplyGetattr *reply;
+   HgfsSuperInfo *sip;
+   char path[MAXPATHLEN + 1];   /* Temporary buffer for full path */
+
+   if (!dvp || !nm || !vpp || !cr) {
+      cmn_err(HGFS_ERROR, "HgfsLookup: NULL input from Kernel.\n");
+      return EINVAL;
+   }
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsLookup(). (nm=%s)\n", nm);
+   //DEBUG(VM_DEBUG_ENTRY, "HgfsLookup: pnp=%x, rdir=%x\n", pnp, rdir);
+
+   /* First ensure that we are looking in a directory. */
+   if (dvp->v_type != VDIR) {
+      return ENOTDIR;
+   }
+
+   DEBUG(VM_DEBUG_COMM, " looking up \"%s\"\n", nm);
+
+   /*
+    * Get pointer to the superinfo.  If the device is not attached,
+    * hgfsInstance will not be valid and we immediately return an error.
+    */
+   sip = HgfsGetSuperInfo();
+   if (!sip) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsLookup: couldn't acquire superinfo "
+                           "(hgfsInstance=%x).\n", hgfsInstance);
+      return EIO;
+   }
+
+   /* Construct the full path for this lookup. */
+   ret = HgfsMakeFullName(HGFS_VP_TO_FILENAME(dvp),             // Path to this file
+                          HGFS_VP_TO_FILENAME_LENGTH(dvp),      // Length of path
+                          nm,                                   // File's name
+                          path,                                 // Destination buffer
+                          sizeof path);                         // Size of dest buffer
+   if (ret < 0) {
+      ret = EINVAL;
+      goto out;
+   }
+
+   DEBUG(VM_DEBUG_LOAD, "HgfsLookup: full path is \"%s\"\n", path);
+
+   /* See if the lookup is really for the root vnode. */
+   if (strcmp(path, "/") == 0) {
+      DEBUG(VM_DEBUG_INFO, "HgfsLookup: returning the root vnode.\n");
+      *vpp = HGFS_ROOT_VNODE(sip);
+      /*
+       * Note that this is the only vnode we maintain a reference count on; all
+       * others are per-open-file and should only be given to the Kernel once.
+       */
+      VN_HOLD(*vpp);
+      return  0;
+   }
+
+   /*
+    * Now that we know the full filename, we can check our hash table for this
+    * file to prevent having to send a request to the Hgfs Server.  If we do
+    * find this file in the hash table, this function will correctly create
+    * a vnode and other per-open state for us.
+    *
+    * On an 'ls -l', this saves sending two requests for each file in the
+    * directory.
+    *
+    * XXX
+    * Note that this optimization leaves open the possibility that a file that
+    * has been removed on the host will not be noticed as promptly by the
+    * filesystem.  This shouldn't cause any problems, though, because as far
+    * as we can tell this function is invoked internally by the kernel before
+    * other operations.  That is, this function is called implicitly for path
+    * traversal when user applications issue other system calls.  The operation
+    * next performed on the vnode we create here should happen prior to
+    * returning to the user application, so if that next operation fails
+    * because the file has been deleted, the user won't see different behavior
+    * than if this optimization was not included.  Nonetheless, the #if 1 below
+    * is provided to make it easy to turn off.
+    */
+#if 1
+   ret = HgfsFileNameToVnode(path, vpp, sip, sip->vfsp, &sip->fileHashTable);
+   if (ret == 0) {
+      /*
+       * The filename was in our hash table and we successfully created new
+       * per-open state for it.
+       */
+      DEBUG(VM_DEBUG_DONE, "HgfsLookup: created per-open state from filename.\n");
+      goto out;
+   }
+#endif
+
+   /*
+    * We don't have any reference to this vnode, so we must send a get
+    * attribute request to see if the file exists and create one.
+    */
+   req = HgfsGetNewReq(sip);
+   if (!req) {
+      return EIO;
+   }
+
+   /* Fill in the header of this request. */
+   request = (HgfsRequestGetattr *)req->packet;
+   HGFS_INIT_REQUEST_HDR(request, req, HGFS_OP_GETATTR);
+
+   /* Fill in the filename portion of the request. */
+   ret = CPName_ConvertTo(path, MAXPATHLEN, request->fileName.name);
+   if (ret < 0) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsLookup: CPName_ConvertTo failed.\n");
+      ret = ENAMETOOLONG;
+      /* We need to set the request state to error before destroying. */
+      HgfsReqSetState(req, HGFS_REQ_ERROR);
+      goto destroy_out;
+   }
+   request->fileName.length = ret;
+
+   /* Packet size includes the request and its payload. */
+   req->packetSize = request->fileName.length + sizeof *request;
+
+   DEBUG(VM_DEBUG_COMM, "HgfsLookup: sending getattr request for ID %d\n",
+         request->header.id);
+   DEBUG(VM_DEBUG_COMM, " fileName.length: %d\n", request->fileName.length);
+   DEBUG(VM_DEBUG_COMM, " fileName.name: \"%s\"\n", request->fileName.name);
+
+   /*
+    * Submit the request and wait for the reply.  HgfsSubmitRequest handles
+    * destroying the request on both error and interrupt cases.
+    */
+   ret = HgfsSubmitRequest(sip, req);
+   if (ret) {
+      goto out;
+   }
+
+   /* The reply is in the request's packet */
+   reply = (HgfsReplyGetattr *)req->packet;
+
+   /* Validate the reply was COMPLETED and at least contains a header */
+   if (HgfsValidateReply(req, sizeof reply->header) != 0) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsLookup(): invalid reply received for ID %d "
+            "with status %d.\n", reply->header.id, reply->header.status);
+      ret = EPROTO;
+      goto destroy_out;
+   }
+
+   DEBUG(VM_DEBUG_COMM, "HgfsLookup: received reply for ID %d\n", reply->header.id);
+   DEBUG(VM_DEBUG_COMM, " status: %d (see hgfsProto.h)\n", reply->header.status);
+   DEBUG(VM_DEBUG_COMM, " file type: %d\n", reply->attr.type);
+   DEBUG(VM_DEBUG_COMM, " file size: %"FMT64"u\n", reply->attr.size);
+   DEBUG(VM_DEBUG_COMM, " permissions: %o\n", reply->attr.permissions);
+
+   switch (reply->header.status) {
+   case HGFS_STATUS_SUCCESS:
+      /* Ensure packet contains correct amount of data */
+      if (req->packetSize != sizeof *reply) {
+         DEBUG(VM_DEBUG_COMM,
+               "HgfsLookup: invalid packet size received for \"%s\".\n", nm);
+         ret = EIO;
+         goto destroy_out;
+      }
+      /* Success */
+      break;
+
+   case HGFS_STATUS_OPERATION_NOT_PERMITTED:
+      DEBUG(VM_DEBUG_LOG, "HgfsLookup: operation not permitted on \"%s\".\n", nm);
+      ret = EACCES;
+      goto destroy_out;
+
+   case HGFS_STATUS_NO_SUCH_FILE_OR_DIR:
+   case HGFS_STATUS_INVALID_NAME:
+      /*
+       * Note, this is necessary because before creating a file Solaris does
+       * a lookup to make sure it doesn't already exist.  We need to return
+       * ENOENT in this case.
+       */
+      DEBUG(VM_DEBUG_LOG, "HgfsLookup: \"%s\" does not exist.\n", nm);
+      ret = ENOENT;
+      goto destroy_out;
+
+   default:
+      DEBUG(VM_DEBUG_LOG, "HgfsLookup: error on \"%s\".\n", nm);
+      ret = EIO;
+      goto destroy_out;
+   }
+
+   /*
+    * We need to create a vnode for this found file to give back to the Kernel.
+    * Note that v_vfsp of the filesystem's root vnode was set properly in
+    * HgfsMount(), so that value (dvp->v_vfsp) propagates down to each vnode.
+    *
+    */
+   ret = HgfsVnodeGet(vpp,                      // Location to write vnode's address
+                      sip,                      // Superinfo
+                      dvp->v_vfsp,              // VFS for our filesystem
+                      path,                     // Full name of the file
+                      reply->attr.type,         // Type of file
+                      &sip->fileHashTable);     // File hash table
+
+   if (ret) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsLookup: couldn't create vnode for \"%s\".\n", path);
+      ret = EIO;
+      goto destroy_out;
+   }
+   /* HgfsVnodeGet guarantees this. */
+   ASSERT(*vpp);
+
+   DEBUG(VM_DEBUG_LOAD, "HgfsLookup: assigned vnode %p to %s\n", *vpp, path);
+
+   ret = 0;     /* Return success */
+
+destroy_out:
+   HgfsDestroyReq(sip, req);
+out:
+   return ret;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsCreate --
+ *
+ *    This entry point is invoked when a user calls open(2) with the O_CREAT
+ *    flag specified.  The kernel calls our open entry point (HgfsOpen()) after
+ *    calling this function, so here all we do is consruct the vnode and
+ *    save the filename and permission bits for the file to be created within
+ *    our filesystem internal state.
+ *
+ *    "Creates the supplied pathname." (Solaris Internals, p536)
+ *
+ * Results:
+ *    Returns zero on success and an appropriate error code on error.
+ *
+ * Side effects:
+ *    If the file exists, the vnode is duplicated since they are kepy per-open.
+ *    If the file doesn't exist, a vnode will be created.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static int
+HgfsCreate(struct vnode *dvp,   // IN: Directory to create file in
+           char *name,          // IN: Name of file to create
+           struct vattr *vap,   // IN: Attributes for file
+           vcexcl_t excl,       // IN: Exclusive creation flag: either NONEXCL or EXCL
+           int mode,            // IN: Permissions to create with
+           struct vnode **vpp,  // OUT: Vnode of file to create
+           struct cred *cr,     // IN: Credentials of caller
+           int flag)            // IN: XXX
+#else
+static int
+HgfsCreate(struct vnode *dvp,     // IN: Directory to create file in
+           char *name,            // IN: Name of file to create
+           struct vattr *vap,     // IN: Attributes for file
+           vcexcl_t excl,         // IN: Exclusive creation flag: either NONEXCL or EXCL
+           int mode,              // IN: Permissions to create with
+           struct vnode **vpp,    // OUT: Vnode of file to create
+           struct cred *cr,       // IN: Credentials of caller
+           int flag,              // IN: XXX
+           caller_context_t *ctx, // IN: Context of caller
+           vsecattr_t *vsecp)     // IN: XXX
+#endif
+{
+   HgfsSuperInfo *sip;
+   int ret = 0;
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsCreate(): entry for \"%s\"\n", name);
+
+   if (!dvp || !name || !vap || !vpp || !cr) {
+      cmn_err(HGFS_ERROR, "HgfsCreate: NULL input from Kernel.\n");
+      return EINVAL;
+   }
+
+   sip = HgfsGetSuperInfo();
+   if (!sip) {
+      return EIO;
+   }
+
+   if (dvp->v_type != VDIR) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsCreate: files must be created in directories.\n");
+      return ENOTDIR;
+   }
+
+   /*
+    * There are two cases: either the file already exists or it doesn't.  If
+    * the file exists already then *vpp points to its vnode that was allocated
+    * in HgfsLookup().  In both cases we need to create a new vnode (since our
+    * vnodes are per-open-file, not per-file), but we don't need to construct
+    * the full name again if we already have it in the existing vnode.
+    */
+   if ( !(*vpp) ) {
+      char fullname[MAXPATHLEN + 1];
+
+      ret = HgfsMakeFullName(HGFS_VP_TO_FILENAME(dvp), // Name of directory to create in
+                             HGFS_VP_TO_FILENAME_LENGTH(dvp), // Length of name
+                             name,                    // Name of file to create
+                             fullname,                // Buffer to write full name
+                             sizeof fullname);        // Size of this buffer
+
+      if (ret < 0) {
+         DEBUG(VM_DEBUG_FAIL, "HgfsCreate: couldn't create full path name.\n");
+         return ENAMETOOLONG;
+      }
+
+      /* Create the vnode for this file. */
+      ret = HgfsVnodeGet(vpp, sip, dvp->v_vfsp, fullname,
+                         HGFS_FILE_TYPE_REGULAR, &sip->fileHashTable);
+      if (ret) {
+         return EIO;
+      }
+   } else {
+      struct vnode *origVp = *vpp;
+
+      ASSERT(origVp->v_type != VDIR);   /* HgfsMkdir() should have been invoked */
+
+      ret = HgfsVnodeDup(vpp, origVp, sip, &sip->fileHashTable);
+      if (ret) {
+         return EIO;
+      }
+
+      /* These cannot be the same. */
+      ASSERT(*vpp != origVp);
+   }
+
+   /* HgfsVnodeGet() guarantees this. */
+   ASSERT(*vpp);
+
+   /* Save the mode so when open is called we can reference it. */
+   HgfsSetOpenFileMode(*vpp, vap->va_mode);
+
+   /* Solaris automatically calls open after this, so our work is done. */
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsRemove --
+ *
+ *    Composes the full pathname of this file and sends a DELETE_FILE request
+ *    by calling HgfsDelete().
+ *
+ *    "Removes the file for the supplied vnode." (Solaris Internals, p537)
+ *
+ * Results:
+ *    Returns 0 on success or a non-zero error code on error.
+ *
+ * Side effects:
+ *    If successful, the file specified will be deleted from the host's
+ *    filesystem.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static int
+HgfsRemove(struct vnode *vp,    // IN: Directory containing file to remove
+           char *nm,            // IN: Name of file to remove
+           struct cred *cr)     // IN: Credentials of caller
+#else
+static int
+HgfsRemove(struct vnode *vp,       // IN: Directory containing file to remove
+           char *nm,               // IN: Name of file to remove
+           struct cred *cr,        // IN: Credentials of caller
+           caller_context_t *ctx,  // IN: Context of caller
+           int flags)              // IN: XXX
+#endif
+{
+   HgfsSuperInfo *sip;
+   char fullpath[MAXPATHLEN + 1];
+   int ret;
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsRemove().\n");
+
+   if (!vp || !nm) {
+      cmn_err(HGFS_ERROR, "HgfsRemove: NULL input from Kernel.\n");
+      return EINVAL;
+   }
+
+   /* Ensure parent is a directory. */
+   if (vp->v_type != VDIR) {
+      DEBUG(VM_DEBUG_FAIL,
+            "HgfsRemove: provided parent is a file, not a directory.\n");
+      return ENOTDIR;
+   }
+
+   /* Ensure we know the name of the parent. */
+   ASSERT(HGFS_KNOW_FILENAME(vp));
+
+   sip = HgfsGetSuperInfo();
+   if (!sip) {
+      return EIO;
+   }
+
+   /*
+    * We must construct the full name of the file to remove then call
+    * HgfsDelete() to send the deletion request.
+    */
+   ret = HgfsMakeFullName(HGFS_VP_TO_FILENAME(vp), // Name of directory to create in
+                          HGFS_VP_TO_FILENAME_LENGTH(vp), // Length of name
+                          nm,                      // Name of file to create
+                          fullpath,                // Buffer to write full name
+                          sizeof fullpath);        // Size of this buffer
+   if (ret < 0) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsRemove: could not construct full name.\n");
+      return ENAMETOOLONG;
+   }
+
+   DEBUG(VM_DEBUG_COMM, "HgfsRemove: removing \"%s\".\n", fullpath);
+
+   /* We can now send the delete request. */
+   return HgfsDelete(sip, fullpath, HGFS_OP_DELETE_FILE);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsLink --
+ *
+ *    "Creates a hard link to the supplied vnode." (Solaris Internals, p537)
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static int
+HgfsLink(struct vnode *tdvp,    //XXX: Vnode of directory to create link in
+         struct vnode *svp,     //XXX: Vnode of file to link to
+         char *tnm,             //XXX: Name of link in directory
+         struct cred *cr)       // IN: Credentials of caller
+#else
+static int
+HgfsLink(struct vnode *tdvp,     //XXX: Vnode of directory to create link in
+         struct vnode *svp,      //XXX: Vnode of file to link to
+         char *tnm,              //XXX: Name of link in directory
+         struct cred *cr,        // IN: Credentials of caller
+         caller_context_t *ctx,  // IN: Context of caller
+         int flags)              // IN: XXX
+#endif
+{
+   DEBUG(VM_DEBUG_NOTSUP, "HgfsLink() NOTSUP.\n");
+
+   return ENOTSUP;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsRename --
+ *
+ *    Renames the provided source name in the source directory with the
+ *    destination name in the destination directory.  A RENAME request is sent
+ *    to the Hgfs server.
+ *
+ * Results:
+ *    Returns 0 on success and an error code on error.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static int
+HgfsRename(struct vnode *sdvp,  // IN: Source directory that contains file to move
+           char *snm,           // IN: File to move
+           struct vnode *tdvp,  // IN: Destination directory of file
+           char *tnm,           // IN: Destination name of file
+           struct cred *cr)     // IN: Credentials of caller
+#else
+static int
+HgfsRename(struct vnode *sdvp,     // IN: Source directory that contains file to move
+           char *snm,              // IN: File to move
+           struct vnode *tdvp,     // IN: Destination directory of file
+           char *tnm,              // IN: Destination name of file
+           struct cred *cr,        // IN: Credentials of caller
+           caller_context_t *ctx,  // IN: Context of caller
+           int flags)              // IN: XXX
+#endif
+{
+   HgfsSuperInfo *sip;
+   HgfsReq *req;
+   HgfsRequestRename *request;
+   HgfsReplyRename *reply;
+   HgfsFileName *newNameP;
+   char srcFullPath[MAXPATHLEN + 1];
+   char dstFullPath[MAXPATHLEN + 1];
+   int ret;
+
+   if (!sdvp || !snm || !tdvp || !tnm) {
+      cmn_err(HGFS_ERROR, "HgfsRename: NULL input from Kernel.\n");
+      return EINVAL;
+   }
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsRename().\n");
+
+   sip = HgfsGetSuperInfo();
+   if (!sip) {
+      return EIO;
+   }
+
+   /* Make sure we know the names of both parent directories. */
+   ASSERT(HGFS_KNOW_FILENAME(sdvp) && HGFS_KNOW_FILENAME(tdvp));
+
+   /* Make the full path of the source. */
+   ret = HgfsMakeFullName(HGFS_VP_TO_FILENAME(sdvp), HGFS_VP_TO_FILENAME_LENGTH(sdvp),
+                          snm,
+                          srcFullPath, sizeof srcFullPath);
+   if (ret < 0) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsRename: could not construct full path of source.\n");
+      return ENAMETOOLONG;
+   }
+
+   /* Make the full path of the destination. */
+   ret = HgfsMakeFullName(HGFS_VP_TO_FILENAME(tdvp), HGFS_VP_TO_FILENAME_LENGTH(tdvp),
+                          tnm,
+                          dstFullPath, sizeof dstFullPath);
+   if (ret < 0) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsRename: could not construct full path of dest.\n");
+      return ENAMETOOLONG;
+   }
+
+   /* Ensure both names will fit in one request. */
+   if ((sizeof *request + strlen(srcFullPath) + strlen(dstFullPath))
+       > HGFS_PACKET_MAX) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsRename: names too big for one request.\n");
+      return EPROTO;
+   }
+
+   /*
+    * Now we can prepare and send the request.
+    */
+   req = HgfsGetNewReq(sip);
+   if (!req) {
+      return EIO;
+   }
+
+   request = (HgfsRequestRename *)req->packet;
+   HGFS_INIT_REQUEST_HDR(request, req, HGFS_OP_RENAME);
+
+   /* Convert the source to cross platform and unescape its buffer. */
+   ret = CPName_ConvertTo(srcFullPath, MAXPATHLEN, request->oldName.name);
+   if (ret < 0) {
+      DEBUG(VM_DEBUG_FAIL,
+            "HgfsRename: couldn't convert source to cross platform name.\n");
+      ret = ENAMETOOLONG;
+      /* We need to set the request state to error before destroying. */
+      HgfsReqSetState(req, HGFS_REQ_ERROR);
+      goto destroy_out;
+   }
+
+   request->oldName.length = ret;
+
+   /*
+    * The new name is placed directly after the old name in the packet and we
+    * access it through this pointer.
+    */
+   newNameP = (HgfsFileName *)((char *)&request->oldName +
+                               sizeof request->oldName +
+                               request->oldName.length);
+
+   /* Convert the destination to cross platform and unescape its buffer. */
+   ret = CPName_ConvertTo(dstFullPath, MAXPATHLEN, newNameP->name);
+   if (ret < 0) {
+      DEBUG(VM_DEBUG_FAIL,
+            "HgfsRename: couldn't convert destination to cross platform name.\n");
+      ret = ENAMETOOLONG;
+      /* We need to set the request state to error before destroying. */
+      HgfsReqSetState(req, HGFS_REQ_ERROR);
+      goto destroy_out;
+   }
+
+   newNameP->length = ret;
+
+   /* The request's size includes the request and both filenames. */
+   req->packetSize = sizeof *request + request->oldName.length + newNameP->length;
+
+   ret = HgfsSubmitRequest(sip, req);
+   if (ret) {
+      /* HgfsSubmitRequest() destroys the request if necessary. */
+      goto out;
+   }
+
+   reply = (HgfsReplyRename *)req->packet;
+
+   /* Validate the reply's state and size. */
+   if (HgfsValidateReply(req, sizeof *reply) != 0) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsRename: invalid reply received.\n");
+      ret = EPROTO;
+      goto destroy_out;
+   }
+
+   /* Return appropriate value. */
+   switch (reply->header.status) {
+   case HGFS_STATUS_SUCCESS:
+      /* Handled after switch. */
+      break;
+
+   case HGFS_STATUS_OPERATION_NOT_PERMITTED:
+      DEBUG(VM_DEBUG_FAIL, "HgfsRename: operation not permitted.\n");
+      ret = EACCES;
+      goto destroy_out;
+
+   case HGFS_STATUS_NOT_DIRECTORY:
+      DEBUG(VM_DEBUG_FAIL, "HgfsRename: not a directory.\n");
+      ret = ENOTDIR;
+      goto destroy_out;
+
+   case HGFS_STATUS_DIR_NOT_EMPTY:
+      DEBUG(VM_DEBUG_FAIL, "HgfsRename: directory not empty.\n");
+      ret = EEXIST;
+      goto destroy_out;
+
+   case HGFS_STATUS_NO_SUCH_FILE_OR_DIR:
+   case HGFS_STATUS_INVALID_NAME:
+      DEBUG(VM_DEBUG_FAIL, "HgfsRename: no such file or directory.\n");
+      ret = ENOENT;
+      goto destroy_out;
+
+   default:
+      DEBUG(VM_DEBUG_FAIL, "HgfsRename: default error.\n");
+      ret = EPROTO;
+      goto destroy_out;
+   }
+
+
+   /* Successfully renamed file. */
+   ret = 0;
+   DEBUG(VM_DEBUG_DONE, "HgfsRename: done.\n");
+
+destroy_out:
+   HgfsDestroyReq(sip, req);
+out:
+   return ret;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsMkdir --
+ *
+ *    Makes a directory named dirname in the directory specified by the dvp
+ *    vnode by sending a CREATE_DIR request, then allocates a vnode for this
+ *    new directory and writes its address into vpp.
+ *
+ * Results:
+ *    Returns 0 on success and a non-zero error code on failure.
+ *
+ * Side effects:
+ *    If successful, a directory is created on the host's filesystem.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static int
+HgfsMkdir(struct vnode *dvp,    // IN: Vnode of directory to create directory in
+          char *dirname,        // IN: Name of directory to create
+          struct vattr *vap,    // IN: Attributes of new directory
+          struct vnode **vpp,   // OUT: Set to point to vnode for new directory
+          struct cred *cr)      // IN: Credentials of caller
+#else
+static int
+HgfsMkdir(struct vnode *dvp,      // IN: Vnode of directory to create directory in
+          char *dirname,          // IN: Name of directory to create
+          struct vattr *vap,      // IN: Attributes of new directory
+          struct vnode **vpp,     // OUT: Set to point to vnode for new directory
+          struct cred *cr,        // IN: Credentials of caller
+          caller_context_t *ctx,  // IN: Context of caller
+          int flags,              // IN: XXX
+          vsecattr_t *vsecp)      // IN: XXX
+#endif
+{
+   HgfsSuperInfo *sip;
+   HgfsReq *req;
+   HgfsRequestCreateDir *request;
+   HgfsReplyCreateDir *reply;
+   char fullname[MAXPATHLEN + 1];
+   int ret;
+
+   if (!dvp || !dirname || !vap || !vpp) {
+      cmn_err(HGFS_ERROR, "HgfsMkdir: NULL input from Kernel.\n");
+   }
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsMkdir: dvp=%p (%s), dirname=%s, vap=%p, vpp=%p\n",
+                         dvp, HGFS_VP_TO_FILENAME(dvp), dirname, vap,
+                         *vpp);
+
+   /*
+    * We need to construct the full path of the directory to create then send
+    * a CREATE_DIR request.  If successful we will create a vnode and fill in
+    * vpp with a pointer to it.
+    *
+    * Note that unlike in HgfsCreate(), *vpp is always NULL.
+    */
+
+   if (dvp->v_type != VDIR) {
+        DEBUG(VM_DEBUG_FAIL, "HgfsMkdir: must create directory in directory.\n");
+        return ENOTDIR;
+   }
+
+   /* Construct the complete path of the directory to create. */
+   ret = HgfsMakeFullName(HGFS_VP_TO_FILENAME(dvp),// Name of directory to create in
+                          HGFS_VP_TO_FILENAME_LENGTH(dvp), // Length of name
+                          dirname,                 // Name of file to create
+                          fullname,                // Buffer to write full name
+                          sizeof fullname);        // Size of this buffer
+
+   if (ret < 0) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsCreate: couldn't create full path name.\n");
+      return ENAMETOOLONG;
+   }
+
+   /* Get pointer to our Superinfo */
+   sip = HgfsGetSuperInfo();
+   if (!sip) {
+      return EIO;
+   }
+
+   req = HgfsGetNewReq(sip);
+   if (!req) {
+      return EIO;
+   }
+
+   /* Initialize the request's contents. */
+   request = (HgfsRequestCreateDir *)req->packet;
+   HGFS_INIT_REQUEST_HDR(request, req, HGFS_OP_CREATE_DIR);
+
+   request->permissions = (vap->va_mode & S_IRWXU) >> HGFS_ATTR_MODE_SHIFT;
+
+   ret = CPName_ConvertTo(fullname, MAXPATHLEN, request->fileName.name);
+   if (ret < 0) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsMkdir: cross-platform name is too long.\n");
+      ret = ENAMETOOLONG;
+      /* We need to set the request state to error before destroying. */
+      HgfsReqSetState(req, HGFS_REQ_ERROR);
+      goto destroy_out;
+   }
+
+   request->fileName.length = ret;
+
+   /* Set the size of this request. */
+   req->packetSize = sizeof *request + request->fileName.length;
+
+   /* Send the request to guestd. */
+   ret = HgfsSubmitRequest(sip, req);
+   if (ret) {
+      /* Request is destroyed in HgfsSubmitRequest() if necessary. */
+      goto out;
+   }
+
+   reply = (HgfsReplyCreateDir *)req->packet;
+
+   if (HgfsValidateReply(req, sizeof *reply) != 0) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsMkdir: invalid reply received.\n");
+      ret = EPROTO;
+      goto destroy_out;
+   }
+
+   switch (reply->header.status) {
+   case HGFS_STATUS_SUCCESS:
+      /* Handled below switch. */
+      break;
+
+   case HGFS_STATUS_OPERATION_NOT_PERMITTED:
+      DEBUG(VM_DEBUG_FAIL, "HgfsMkdir: operation not permitted.\n");
+      ret = EACCES;
+      goto destroy_out;
+
+   case HGFS_STATUS_FILE_EXISTS:
+      DEBUG(VM_DEBUG_FAIL, "HgfsMkdir: directory already exists.\n");
+      ret = EEXIST;
+      goto destroy_out;
+
+   default:
+      ret = EPROTO;
+      goto destroy_out;
+   }
+
+   /* We now create the vnode for the new directory. */
+   ret = HgfsVnodeGet(vpp, sip, dvp->v_vfsp, fullname,
+                      HGFS_FILE_TYPE_DIRECTORY, &sip->fileHashTable);
+   if (ret) {
+      ret = EIO;
+      goto destroy_out;
+   }
+
+   ASSERT(*vpp);        /* HgfsIget guarantees this. */
+   ret = 0;
+
+destroy_out:
+   HgfsDestroyReq(sip, req);
+out:
+   return ret;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsRmdir --
+ *
+ *    Removes the specified name from the provided vnode.  Sends a DELETE
+ *    request by calling HgfsDelete() with the filename and correct opcode to
+ *    indicate deletion of a directory.
+ *
+ *    "Removes the directory pointed to by the supplied vnode." (Solaris
+ *    Internals, p537)
+ *
+ * Results:
+ *    Returns 0 on success and an error code on error.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static int
+HgfsRmdir(struct vnode *vp,     // IN: Dir containing dir to remove
+          char *nm,             // IN: Name of directory to remove
+          struct vnode *cdir,   // XXX?
+          struct cred *cr)      // IN: Credentials of caller
+#else
+static int
+HgfsRmdir(struct vnode *vp,       // IN: Dir containing dir to remove
+          char *nm,               // IN: Name of directory to remove
+          struct vnode *cdir,     // XXX?
+          struct cred *cr,        // IN: Credentials of caller
+          caller_context_t *ctx,  // IN: Context of caller
+          int flags)              // IN: XXX
+#endif
+{
+   HgfsSuperInfo *sip;
+   char fullpath[MAXPATHLEN + 1];
+   int ret;
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsRmdir().\n");
+
+   if (!vp || !nm) {
+      cmn_err(HGFS_ERROR, "HgfsRmdir: NULL input from Kernel.\n");
+      return EINVAL;
+   }
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsRmdir: vp=%p (%s), nm=%s, cdir=%p (%s)\n",
+         vp, (HGFS_VP_TO_FP(vp)) ? HGFS_VP_TO_FILENAME(vp) : "vp->v_data null",
+         nm, cdir, (HGFS_VP_TO_FP(cdir)) ? HGFS_VP_TO_FILENAME(cdir) : "cdir->v_data null");
+
+   /* A few checks to ensure we can remove the directory. */
+   if (vp->v_type != VDIR) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsRmdir: provided parent is a file, not a directory.\n");
+      return ENOTDIR;
+   }
+
+   ASSERT(HGFS_KNOW_FILENAME(vp));
+
+   sip = HgfsGetSuperInfo();
+   if (!sip) {
+      return EIO;
+   }
+
+   /*
+    * We need to construct the full name of the directory to remove then call
+    * HgfsDelete with the proper opcode.
+    */
+   ret = HgfsMakeFullName(HGFS_VP_TO_FILENAME(vp), // Name of directory to create in
+                          HGFS_VP_TO_FILENAME_LENGTH(vp), // Length of name
+                          nm,                      // Name of file to create
+                          fullpath,                // Buffer to write full name
+                          sizeof fullpath);        // Size of this buffer
+   if (ret < 0) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsRmdir: could not construct full name.\n");
+      return ENAMETOOLONG;
+   }
+
+   DEBUG(VM_DEBUG_COMM, "HgfsRmdir: removing \"%s\".\n", fullpath);
+
+   /* We can now send the delete request. */
+   return HgfsDelete(sip, fullpath, HGFS_OP_DELETE_DIR);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsReaddir --
+ *
+ *    Reads as many entries from the directory as will fit in to the provided
+ *    buffer.  Each directory entry is read by calling HgfsGetNextDirEntry().
+ *
+ *    "The vop_readdir() method reads chunks of the directory into a uio
+ *    structure.  Each chunk can contain as many entries as will fit within
+ *    the size supplied by the uio structure.  The uio_resid structure member
+ *    shows the size of the getdents request in bytes, which is divided by the
+ *    size of the directory entry made by the vop_readdir() method to
+ *    calculate how many directory entries to return." (Solaris Internals,
+ *    p555)
+ *
+ * Results:
+ *    Returns 0 on success and a non-zero error code on failure.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static int
+HgfsReaddir(struct vnode *vp,   // IN: Vnode of directory to read
+            struct uio *uiop,   // IN: User's read request
+            struct cred *cr,    // IN: Credentials of caller
+            int *eofp)          // OUT: Indicates we are done
+#else
+static int
+HgfsReaddir(struct vnode *vp,       // IN: Vnode of directory to read
+            struct uio *uiop,       // IN: User's read request
+            struct cred *cr,        // IN: Credentials of caller
+            int *eofp,              // OUT: Indicates we are done
+            caller_context_t *ctx,  // IN: Context of caller
+            int flags)              // IN: XXX
+#endif
+{
+   HgfsSuperInfo *sip;
+   HgfsHandle handle;
+   struct dirent64 *dirp, *origdirp;
+   ssize_t readSize;
+   uint64_t offset;
+   Bool done;
+   int ret;
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsReaddir().\n");
+
+   if (!vp || !uiop || !cr || !eofp) {
+      cmn_err(HGFS_ERROR, "HgfsReaddir: NULL input from Kernel.\n");
+      return EINVAL;
+   }
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsReaddir: uiop->uio_resid=%ld, "
+         "uiop->uio_loffset=%lld\n",
+         uiop->uio_resid, uiop->uio_loffset);
+
+
+   /*
+    * XXX: If would be nice if we could perform some sort of sanity check on
+    * the handle here.  Perhaps make sure handle <= NUM_SEARCHES in
+    * hgfsServer.c since the handle is the index number in searchArray.
+    */
+   if ( !HGFS_KNOW_FILENAME(vp) ) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsReaddir: we don't know the filename.\n");
+      return EBADF;
+   }
+
+
+   sip = HgfsGetSuperInfo();
+   if (!sip) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsReaddir: we can't get the superinfo.\n");
+      return EIO;
+   }
+   /*
+    * In order to fill the user's buffer with directory entries, we must
+    * iterate on HGFS_OP_SEARCH_READ requests until either the user's buffer is
+    * full or there are no more entries.  Each call to HgfsGetNextDirEntry()
+    * fills in the name and attribute structure for the next entry.  We then
+    * escape that name and place it in a kernel buffer that's the same size as
+    * the user's buffer.  Once there are no more entries or no more room in the
+    * buffer, we copy it to user space.
+    */
+
+   /*
+    * XXX
+    * Note that I allocate a large buffer in kernel space so I can do only one
+    * copy to user space, otherwise we would need to do a copy for each
+    * directory entry.  This approach is potentially bad since readSize is
+    * as big as the buffer the user called us with, and therefore in their
+    * control.  (Actually, it's likely that the user can just say it has a
+    * huge buffer without really having it.)  For this reason, I call
+    * kmem_zalloc() with the KM_NOSLEEP flag which fails if it cannot allocate
+    * memory rather than sleeping until it can (as KM_SLEEP does).
+    *
+    * This approach may want to be changed in the future.
+    */
+
+   readSize = uiop->uio_resid;
+   origdirp = dirp = (struct dirent64 *)kmem_zalloc(readSize, KM_NOSLEEP);
+   if (!origdirp) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsReaddir: couldn't allocate memory.\n");
+      return ENOMEM;
+   }
+
+   /*
+    * We need to get the handle for this open directory to send to the Hgfs
+    * server in our requests.
+    */
+   ret = HgfsGetOpenFileHandle(vp, &handle);
+   if (ret) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsReaddir: could not get handle.\n");
+      return EINVAL;
+   }
+
+
+   /*
+    * Loop until one of the following conditions is met:
+    *  o An error occurs while reading a directory entry
+    *  o There are no more directory entries to read
+    *  o The buffer is full and cannot hold the next entry
+    *
+    * We request dentries from the Hgfs server based on their index in the
+    * directory.  The offset value is initialized to the value specified in
+    * the user's io request and is incremented each time through the loop.
+    *
+    * dirp is incremented by the record length each time through the loop and
+    * is used to determine where in the kernel buffer we write to.
+    */
+   for (offset = uiop->uio_loffset, done = 0; /* Nothing */ ; offset++) {
+      char nameBuf[MAXNAMELEN + 1];
+      char escName[MAXNAMELEN + 1];
+      char fullName[MAXPATHLEN + 1];
+
+      DEBUG(VM_DEBUG_COMM,
+            "HgfsReaddir: getting directory entry at offset %"FMT64"u.\n", offset);
+
+      DEBUG(VM_DEBUG_HANDLE, "HgfsReaddir: ** handle=%d, file=%s\n",
+            handle, HGFS_VP_TO_FILENAME(vp));
+
+      ret = HgfsGetNextDirEntry(sip, handle, offset, nameBuf, &done);
+      /* If the filename was too long, we skip to the next entry ... */
+      if (ret == EOVERFLOW) {
+         continue;
+      /* ... but if another error occurred, we return that error code ... */
+      } else if (ret) {
+         DEBUG(VM_DEBUG_FAIL, "HgfsReaddir: failure occurred in HgfsGetNextDirEntry\n");
+         goto out;
+      /*
+       * ... and if there are no more entries, we set the end of file pointer
+       * and break out of the loop.
+       */
+      } else if (done == TRUE) {
+         DEBUG(VM_DEBUG_COMM, "HgfsReaddir: Done reading directory entries.\n");
+         *eofp = TRUE;
+         break;
+      }
+
+      /*
+       * We now have the directory entry, so we sanitize the name and try to
+       * put it in our buffer.
+       */
+      DEBUG(VM_DEBUG_COMM, "HgfsReaddir: received filename \"%s\"\n", nameBuf);
+
+      ret = HgfsEscape_Do(nameBuf, strlen(nameBuf), sizeof escName, escName);
+      /* If the escaped name didn't fit in the buffer, skip to the next entry. */
+      if (ret < 0) {
+         DEBUG(VM_DEBUG_FAIL, "HgfsReaddir: HgfsEscape_Do failed.\n");
+         continue;
+      }
+
+      /*
+       * Make sure there is enough room in the buffer for the entire directory
+       * entry.  If not, we just break out of the loop and copy what we have.
+       */
+      if (DIRENT64_RECLEN(ret) > (readSize - ((uintptr_t)dirp - (uintptr_t)origdirp))) {
+         DEBUG(VM_DEBUG_INFO, "HgfsReaddir: ran out of room in the buffer.\n");
+         break;
+      }
+
+      /* Fill in the directory entry. */
+      dirp->d_reclen = DIRENT64_RECLEN(ret);
+      dirp->d_off = offset;
+      memcpy(dirp->d_name, escName, ret);
+      dirp->d_name[ret] = '\0';
+
+      ret = HgfsMakeFullName(HGFS_VP_TO_FILENAME(vp),           // Directorie's name
+                             HGFS_VP_TO_FILENAME_LENGTH(vp),    // Length
+                             dirp->d_name,                      // Name of file
+                             fullName,                          // Destination buffer
+                             sizeof fullName);                  // Size of this buffer
+      /* Skip this entry if the full path was too long. */
+      if (ret < 0) {
+         continue;
+      }
+
+      /*
+       * Place the node id, which serves the purpose of inode number, for this
+       * filename directory entry.  As long as we are using a dirent64, this is
+       * okay since ino_t is also a u_longlong_t.
+       */
+      HgfsNodeIdGet(&sip->fileHashTable, fullName, (uint32_t)ret,
+                    &dirp->d_ino);
+
+      /* Advance to the location for the next directory entry */
+      dirp = (struct dirent64 *)((intptr_t)dirp + dirp->d_reclen);
+   }
+
+   /*
+    * Now that we've filled our buffer with as many dentries as fit, we copy it
+    * into the user's buffer.
+    */
+   ret = uiomove(origdirp,                                // Source buffer
+                 ((uintptr_t)dirp - (uintptr_t)origdirp), // Size of this buffer
+                 UIO_READ,                                // Read flag
+                 uiop);                                   // User's request struct
+
+   /*
+    * uiomove(9F) will have incremented the uio offset by the number of bytes
+    * written.  We reset it here to the fs-specific offset in our directory so
+    * the next time we are called it is correct.  (Note, this does not break
+    * anything and /is/ how this field is intended to be used.)
+    */
+   uiop->uio_loffset = offset;
+
+   DEBUG(VM_DEBUG_DONE, "HgfsReaddir: done (ret=%d, *eofp=%d).\n", ret, *eofp);
+out:
+   kmem_free(origdirp, readSize);
+   DEBUG(VM_DEBUG_ENTRY, "HgfsReaddir: exiting.\n");
+   return ret;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsSymlink --
+ *
+ *    "Creates a symbolic link between the two pathnames" (Solaris Internals,
+ *    p538)
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <=3
+static int
+HgfsSymlink(struct vnode *dvp,  // IN: Directory to create link in
+            char *linkname,     // IN: Name of link
+            struct vattr *vap,  // IN: Attributes for the symlink
+            char *target,       // IN: Name of target for symlink
+            struct cred *cr)    // IN: Credentials of caller
+#else
+static int
+HgfsSymlink(struct vnode *dvp,      // IN: Directory to create link in
+            char *linkname,         // IN: Name of link
+            struct vattr *vap,      // IN: Attributes for the symlink
+            char *target,           // IN: Name of target for symlink
+            struct cred *cr,        // IN: Credentials of caller
+            caller_context_t *ctx,  // IN: Context of caller
+            int flags)              // IN: XXX
+#endif
+{
+   DEBUG(VM_DEBUG_NOTSUP, "HgfsSymlink() NOTSUP.\n");
+
+   /*
+    * Hgfs doesn't support links.
+    */
+   return ENOTSUP;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsReadlink --
+ *
+ *    "Follows the symlink in the supplied vnode." (Solaris Internals, p537)
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static int
+HgfsReadlink(struct vnode *vp,  // IN: Vnode for the symlink
+             struct uio *uiop,  // IN: XXX User's request?
+             struct cred *cr)   // IN: Credentials of caller
+#else
+static int
+HgfsReadlink(struct vnode *vp,       // IN: Vnode for the symlink
+             struct uio *uiop,       // IN: XXX User's request?
+             struct cred *cr,        // IN: Credentials of caller
+             caller_context_t *ctx)  // IN: Context of caller
+#endif
+{
+   DEBUG(VM_DEBUG_NOTSUP, "HgfsReadlink() NOTSUP.\n");
+
+   /*
+    * Hgfs doesn't support links
+    */
+   return ENOTSUP;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsFsync --
+ *
+ *    We don't map any memory so we can safely return success.
+ *
+ *    "Flushes out any dirty pages for the supplied vnode." (Solaris
+ *    Internals, p536)
+ *
+ * Results:
+ *    Returns 0 on success and non-zero on error.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static int
+HgfsFsync(struct vnode *vp,     // IN: Vnode for the file to sync
+          int syncflag,         // IN: XXX?
+          struct cred *cr)      // IN: Credentials of the caller
+#else
+static int
+HgfsFsync(struct vnode *vp,       // IN: Vnode for the file to sync
+          int syncflag,           // IN: XXX?
+          struct cred *cr,        // IN: Credentials of the caller
+          caller_context_t *ctx)  // IN: Context of caller
+#endif
+{
+   DEBUG(VM_DEBUG_ENTRY, "HgfsFsync().\n");
+
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsInactive --
+ *
+ *    Frees a vnode that is no longer referenced.  This is done by calling
+ *    HgfsVnodePut() from hgfsState.c, which also cleans up our internal
+ *    filesystem state.
+ *
+ *    "Free resources and releases the supplied vnode.  The file system can
+ *    choose to destroy the vnode or put it onto an inactive list, which is
+ *    managed by the file system implementation." (Solaris Internals, p536)
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static void
+HgfsInactive(struct vnode *vp,  // IN: Vnode to operate on
+             struct cred *cr)   // IN: Credentials of the caller
+#else
+static void
+HgfsInactive(struct vnode *vp,       // IN: Vnode to operate on
+             struct cred *cr,        // IN: Credentials of the caller
+             caller_context_t *ctx)  // IN: Context of caller
+#endif
+{
+   HgfsSuperInfo *sip;
+
+   if (!vp) {
+      cmn_err(HGFS_ERROR, "HgfsInactive: NULL input from Kernel.\n");
+      return;
+   }
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsInactive().\n");
+
+   sip = HgfsGetSuperInfo();
+   if (!sip) {
+      return;
+   }
+
+   /* We need the check and decrement of v_count to be atomic */
+   mutex_enter(&vp->v_lock);
+
+   if (vp->v_count > 1) {
+      vp->v_count--;
+      mutex_exit(&vp->v_lock);
+
+      DEBUG(VM_DEBUG_LOAD, "--> decremented count of vnode %p to %d\n",
+            vp, vp->v_count);
+
+      /*
+       * XXX This should only ever happen for the root vnode with our new state
+       * organization.
+       */
+      if (vp != sip->rootVnode) {
+         DEBUG(VM_DEBUG_ALWAYS, "HgfsInactive: v_count of vnode for %s too high!\n",
+               HGFS_VP_TO_FILENAME(vp));
+      }
+      ASSERT(vp == sip->rootVnode);
+
+   } else {
+      mutex_exit(&vp->v_lock);
+
+      DEBUG(VM_DEBUG_LOAD, "--> freeing vnode %p - \"%s\"\n",
+            vp, HGFS_VP_TO_FILENAME(vp));
+
+      /* Deallocate this vnode. */
+      HgfsVnodePut(vp, &sip->fileHashTable);
+
+   }
+
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsFid --
+ *
+ *    Provide a unique file identifier for this vnode.  Note that I have never
+ *    seen this function called by the Kernel.
+ *
+ * Results:
+ *    Returns 0 on success and a non-zero error code on error.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static int
+HgfsFid(struct vnode *vp,       // IN: File to generate file identifier for
+        struct fid *fidp)       // XXX: IN/OUT?: File identifier
+#else
+static int
+HgfsFid(struct vnode *vp,       // IN: File to generate file identifier for
+        struct fid *fidp,       // XXX: IN/OUT?: File identifier
+        caller_context_t *ctx)  // IN: Context of caller
+#endif
+{
+   DEBUG(VM_DEBUG_ENTRY, "HgfsFid().\n");
+
+   if (!vp || !fidp) {
+      cmn_err(HGFS_ERROR, "HgfsFid: NULL input from Kernel.\n");
+   }
+
+   /*
+    * Make sure we can fit our node id in the provided structure.  This allows
+    * us to call memcpy() with the sizeof the source below.
+    */
+   if (sizeof fidp->fid_data < sizeof HGFS_VP_TO_NODEID(vp)) {
+      return EOVERFLOW;
+   }
+
+   memset(fidp, 0, sizeof *fidp);
+   memcpy(&fidp->fid_data, &HGFS_VP_TO_NODEID(vp), sizeof HGFS_VP_TO_NODEID(vp));
+   fidp->fid_len  = sizeof HGFS_VP_TO_NODEID(vp);
+
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsRwlock --
+ *
+ *    Acquires either a readers or writers lock.
+ *
+ *    "Holds the reader/writer lock for the supplied vnode.  This method is
+ *    called for each vnode, with the rwflag set to 0 inside a read() system
+ *    call and the rwflag set to 1 inside a write() at a time.  Some file
+ *    system implementations have opetions to ignore the writer lock inside
+ *    vop_rwlock()." (Solaris Internals, p537)
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    The file's readers/writers lock is held after this function.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION == 2
+static void
+HgfsRwlock(struct vnode *vp,    // IN: Vnode to get lock for
+           int write_lock)      // IN: Set if wants a write lock, cleared for read lock
+#elif HGFS_VFS_VERSION == 3
+static void
+HgfsRwlock(struct vnode *vp,            // IN: Vnode to get lock for
+           int write_lock,              // IN: Set for write lock, cleared for read lock
+           caller_context_t *context)   // IN: Context of caller
+#else /* SOL11 */
+static int
+HgfsRwlock(struct vnode *vp,            // IN: Vnode to get lock for
+           int write_lock,              // IN: Set for write lock, cleared for read lock
+           caller_context_t *context)   // IN: Context of caller
+#endif
+{
+   if (write_lock) {
+      rw_enter(HGFS_VP_TO_RWLOCKP(vp), RW_WRITER);
+   } else {
+      rw_enter(HGFS_VP_TO_RWLOCKP(vp), RW_READER);
+   }
+
+#if HGFS_VFS_VERSION == 5
+   return write_lock ? V_WRITELOCK_TRUE : V_WRITELOCK_FALSE;
+#endif
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsRwunlock --
+ *
+ *    "Releases the reader/writer lock for the supplied vnode." (Solaris
+ *    Internals, p537)
+ *
+ * Results:
+ *    Void.
+ *
+ * Side effects:
+ *    This file's readers/writer lock is unlocked.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION == 2
+static void
+HgfsRwunlock(struct vnode *vp,  // IN: Vnode to release lock for
+             int write_lock)    // IN: Set for write lock, cleared for read lock
+#else
+static void
+HgfsRwunlock(struct vnode *vp,          // IN: Vnode to release lock for
+             int write_lock,            // IN: Set for write lock, cleared for read lock
+             caller_context_t *context) // IN: Context of caller
+#endif
+{
+   //DEBUG(VM_DEBUG_ENTRY, "HgfsRwunlock().\n");
+
+   if (!vp) {
+      cmn_err(HGFS_ERROR, "HgfsRwunlock: NULL input from Kernel.\n");
+      return;
+   }
+
+   rw_exit(HGFS_VP_TO_RWLOCKP(vp));
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsSeek --
+ *
+ *    Checks to ensure that the specified offset is valid.  Actual manipulation
+ *    of the file position is handled by the Kernel.
+ *
+ *    "Seeks within the supplied vnode." (Solaris Internals, p537)
+ *
+ * Results:
+ *    Returns zero if this offset is valid and EINVAL if it isn't.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static int
+HgfsSeek(struct vnode *vp,      // IN:     Vnode to seek within
+         offset_t ooff,         // IN:     Current offset in this vnode
+         offset_t *noffp)       // IN/OUT: Requested new offset within file
+#else
+static int
+HgfsSeek(struct vnode *vp,      // IN:     Vnode to seek within
+         offset_t ooff,         // IN:     Current offset in this vnode
+         offset_t *noffp,       // IN/OUT: Requested new offset within file
+         caller_context_t *ctx) // IN: Context of caller
+#endif
+{
+   DEBUG(VM_DEBUG_ENTRY, "HgfsSeek().\n");
+
+   if (!noffp) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsSeek: noffp is NULL\n");
+      return EINVAL;
+   }
+
+   if (*noffp < 0) {
+      return EINVAL;
+   }
+
+   DEBUG(VM_DEBUG_INFO, "HgfsSeek: file   %s\n", HGFS_VP_TO_FILENAME(vp));
+   DEBUG(VM_DEBUG_INFO, "HgfsSeek: ooff   %llu\n", ooff);
+   DEBUG(VM_DEBUG_INFO, "HgfsSeek: *noffp %llu\n", *noffp);
+
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsCmp --
+ *
+ *    Compares two vnodes to see if they are for the same file.  Our
+ *    filesystem-specific check is to compare the filenames, file type, and
+ *    file flags.  Since we keep vnodes per-open-file, rather than per-file,
+ *    this function has significance.
+ *
+ *    This function is invoked by the VN_CMP macro only if the two given
+ *    pointers are different and each has the same operations (v_op).
+ *
+ * Results:
+ *    TRUE if vnodes are the same, FALSE otherwise.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static int
+HgfsCmp(struct vnode *vp1,      // IN: First vnode
+        struct vnode *vp2)      // IN: Second vnode
+#else
+static int
+HgfsCmp(struct vnode *vp1,      // IN: First vnode
+        struct vnode *vp2,      // IN: Second vnode
+        caller_context_t *ctx)  // IN: Context of caller
+#endif
+{
+   DEBUG(VM_DEBUG_ENTRY, "HgfsCmp: vp1=%p, vp2=%p.\n", vp1, vp2);
+
+   /*
+    * This function is only called if:
+    * ((vp1 != vp2) && (vp1->v_op == vp2->v_op))
+    *
+    * We also care if the filenames are the same.
+    */
+
+   if (vp1->v_type != vp2->v_type) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsCmp: %s != %s",
+            (vp1->v_type == VDIR) ? "VDIR" : "VREG",
+            (vp2->v_type == VDIR) ? "VDIR" : "VREG");
+      return FALSE;
+   }
+
+   if (vp1->v_flag != vp2->v_flag) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsCmp: flags: %x != %x\n", vp1->v_flag, vp2->v_flag);
+      return FALSE;
+   }
+
+   if (strcmp(HGFS_VP_TO_FILENAME(vp1), HGFS_VP_TO_FILENAME(vp2)) != 0) {
+      return FALSE;
+   }
+
+   DEBUG(VM_DEBUG_DONE, "HgfsCmp: for \"%s\", vp1 == vp2\n", HGFS_VP_TO_FILENAME(vp1));
+   return TRUE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsFrlock --
+ *
+ *    "Does file and record locking for the supplied vnode." (Solaris
+ *    Internals, p536)
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static int
+HgfsFrlock(struct vnode *vp,                    // XXX
+           int cmd,                             // IN: Command to carry out
+           struct flock64 *bfp,                 // XXX
+           int flag,                            // XXX
+           offset_t offset,                     // XXX
+           struct flk_callback *flk_callbackp,  // XXX
+           struct cred *cr)                     // IN: Credentials of caller
+#else
+static int
+HgfsFrlock(struct vnode *vp,                    // XXX
+           int cmd,                             // IN: Command to carry out
+           struct flock64 *bfp,                 // XXX
+           int flag,                            // XXX
+           offset_t offset,                     // XXX
+           struct flk_callback *flk_callbackp,  // XXX
+           struct cred *cr,                     // IN: Credentials of caller
+           caller_context_t *ctx)               // IN: Context of caller
+#endif
+{
+   DEBUG(VM_DEBUG_NOTSUP, "HgfsFrlock() NOTSUP.\n");
+
+   return ENOTSUP;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsSpace --
+ *
+ *    "Frees space for the supplied vnode." (Solaris Internals, p538)
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION == 2
+static int
+HgfsSpace(struct vnode *vp,     // IN: Vnode to free space for
+          int cmd,              // IN: XXX Command
+          struct flock64 *bfp,  // IN: XXX
+          int flag,             // IN: XXX
+          offset_t offset,      // IN: XXX
+          struct cred *cr)      // IN: Credentials of caller
+#else
+static int
+HgfsSpace(struct vnode *vp,             // IN: Vnode to free space for
+          int cmd,                      // IN: XXX Command
+          struct flock64 *bfp,          // IN: XXX
+          int flag,                     // IN: XXX
+          offset_t offset,              // IN: XXX
+          struct cred *cr,              // IN: Credentials of caller
+          caller_context_t *ctx)        // IN: Context of caller
+#endif
+{
+   DEBUG(VM_DEBUG_NOTSUP, "HgfsSpace() NOTSUP.\n");
+
+   return ENOTSUP;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsRealvp --
+ *
+ *    "Gets the real vnode from the supplied vnode." (Solaris Internals, p537)
+ *
+ * Results:
+ *    Returns 0 on success and a non-zero error code on error.  On success, vpp
+ *    is given the value of the real vnode.  Currently this always returns
+ *    success.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static int
+HgfsRealvp(struct vnode *vp,    // IN: Vnode to find real vnode for
+           struct vnode **vpp)  // OUT: Set to point to real vnode
+#else
+static int
+HgfsRealvp(struct vnode *vp,    // IN: Vnode to find real vnode for
+           struct vnode **vpp,  // OUT: Set to point to real vnode
+           caller_context_t *ctx)
+#endif
+{
+   DEBUG(VM_DEBUG_ENTRY, "HgfsRealvp().\n");
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsRealvp: vp=%p\n", vp);
+   DEBUG(VM_DEBUG_ENTRY, "HgfsRealvp: vp's name=%s\n", HGFS_VP_TO_FILENAME(vp));
+
+   /*
+    * Here we just supply the vnode we were provided.  This behavior is correct
+    * since we maintain vnodes per-open-file rather than per-file.  The "real"
+    * vnode /is/ the provided one since any other one belongs to a different
+    * "open" file.
+    */
+   *vpp = vp;
+
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsGetpage --
+ *
+ *    HgfsRead() does not map file data into the Kernel's address space, so we
+ *    shouldn't need to support this (that is, page faults will never occur).
+ *
+ *    "Gets pages in the range offset and length for the vnode from the
+ *    backing store of the file system.  Does the real work of reading a
+ *    vnode.  This method is often called as a result of read(), which causes
+ *    a page fault in seg_map, which calls vop_getpage()." (Solaris Internals,
+ *    p536)
+ *
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static int
+HgfsGetpage(struct vnode *vp,           // IN: Vnode of file to get page for
+            offset_t off,               // IN: Offset in file/page to retrieve
+            size_t len,                 // IN: Length of range to retrieve
+            uint_t *protp,              // XXX
+            struct page **plarr,        // XXX
+            size_t plsz,                // IN: XXX
+            struct seg *seg,            // XXX: Segment
+            caddr_t addr,               // IN: Address of XXX
+            enum seg_rw rw,             // IN: XXX
+            struct cred *cr)            //IN Credentials of caller
+#else
+static int
+HgfsGetpage(struct vnode *vp,           // IN: Vnode of file to get page for
+            offset_t off,               // IN: Offset in file/page to retrieve
+            size_t len,                 // IN: Length of range to retrieve
+            uint_t *protp,              // XXX
+            struct page **plarr,        // XXX
+            size_t plsz,                // IN: XXX
+            struct seg *seg,            // XXX: Segment
+            caddr_t addr,               // IN: Address of XXX
+            enum seg_rw rw,             // IN: XXX
+            struct cred *cr,            //IN Credentials of caller
+            caller_context_t *ctx)
+#endif
+{
+   DEBUG(VM_DEBUG_NOTSUP, "HgfsGetpage() NOTSUP.\n");
+
+   /* We don't currently need this; see the comment above. */
+
+   return ENOTSUP;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsPutpage --
+ *
+ *    HgfsWrite() does not map file data into the Kernel's address space, so we
+ *    shouldn't need to support this (that is, page faults will never occur).
+ *
+ *    "Writes pages in the range offset and length for the vnode to the
+ *    backing store of the file system.  Does the real work of reading a
+ *    vnode."  (Solaris Internals, p537)
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static int
+HgfsPutpage(struct vnode *vp,   // IN: Vnode of file to put page for
+            offset_t off,       // IN: Offset to begin writing
+            size_t len,         // IN: Amount of data to write
+            int flags,          // IN: XXX
+            struct cred *cr)    // IN: Credentials of caller
+#else
+static int
+HgfsPutpage(struct vnode *vp,      // IN: Vnode of file to put page for
+            offset_t off,          // IN: Offset to begin writing
+            size_t len,            // IN: Amount of data to write
+            int flags,             // IN: XXX
+            struct cred *cr,       // IN: Credentials of caller
+            caller_context_t *ctx) // IN: Context of caller
+#endif
+{
+   DEBUG(VM_DEBUG_NOTSUP, "HgfsPutpage() NOTSUP.\n");
+
+   /* We don't currently need this; see the comment above. */
+
+   return ENOTSUP;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsMap --
+ *
+ *    Each file has its VNOMAP flag set so this shouldn't be invoked.  Most
+ *    applications seem to handle this so, if this becomes a problem this
+ *    function will need to be implemented.
+ *
+ *    "Maps a range of pages into an address space by doing the appropriate
+ *    checks and calline as_map()" (Solaris Internals, p537)
+ *
+ *
+ * Results:
+ *    Returns 0 on success and a non-zero error code on error.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static int
+HgfsMap(struct vnode *vp,       // IN: Vnode of file to map page for
+        offset_t off,           // IN: XXX
+        struct as *as,          // IN: Address space
+        caddr_t *addrp,         // IN: XXX: Address in this space?
+        size_t len,             // IN: XXX:Length of area to map?
+        uchar_t prot,           // IN: XXX
+        uchar_t maxprot,        // IN: XXX
+        uint_t flags,           // IN: XXX
+        struct cred *cr)        // IN: Credentials of caller
+#else
+static int
+HgfsMap(struct vnode *vp,       // IN: Vnode of file to map page for
+        offset_t off,           // IN: XXX
+        struct as *as,          // IN: Address space
+        caddr_t *addrp,         // IN: XXX: Address in this space?
+        size_t len,             // IN: XXX:Length of area to map?
+        uchar_t prot,           // IN: XXX
+        uchar_t maxprot,        // IN: XXX
+        uint_t flags,           // IN: XXX
+        struct cred *cr,        // IN: Credentials of caller
+        caller_context_t *ctx)  // IN: Context of caller
+#endif
+{
+   /* We specify VNOMAP for each file, so this shouldn't be called. */
+   DEBUG(VM_DEBUG_NOTSUP, "HgfsMap() NOTSUP.\n");
+
+   return ENOTSUP;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsAddmap --
+ *
+ *    Since HgfsMap() above is ENOTSUP, this is not needed.
+ *
+ *    "Increments the map count." (Solaris Internals, p536)
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static int
+HgfsAddmap(struct vnode *vp,    // IN: Vnode to increment map count for
+           offset_t off,        //XXX
+           struct as *as,       // IN: Address space
+           caddr_t addrp,       // IN: XXX: Address in this space?
+           size_t len,          // IN: XXX: Length of this mapping?
+           uchar_t prot,        // IN: XXX
+           uchar_t maxprot,     // IN: XXX
+           uint_t flags,        // IN: XXX
+           struct cred *cr)     // IN: Credentials of caller
+#else
+static int
+HgfsAddmap(struct vnode *vp,       // IN: Vnode to increment map count for
+           offset_t off,           //XXX
+           struct as *as,          // IN: Address space
+           caddr_t addrp,          // IN: XXX: Address in this space?
+           size_t len,             // IN: XXX: Length of this mapping?
+           uchar_t prot,           // IN: XXX
+           uchar_t maxprot,        // IN: XXX
+           uint_t flags,           // IN: XXX
+           struct cred *cr,        // IN: Credentials of caller
+           caller_context_t *ctx)  // IN: Context of caller
+#endif
+{
+   DEBUG(VM_DEBUG_NOTSUP, "HgfsAddmap() NOTSUP.\n");
+
+   return ENOTSUP;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsDelmap --
+ *
+ *    Since HgfsMap() above is ENOTSUP, this is not needed.
+ *
+ *    "Decrements the map count." (Solaris Internals, p536)
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static int
+HgfsDelmap(struct vnode *vp,    // IN: Vnode of file to decrement map count for
+           offset_t off,        // XXX
+           struct as *as,       // IN: Address space
+           caddr_t addr,        // IN: XXX: Address in this space?
+           size_t len,          // IN: XXX: Length of this mapping?
+           uint_t prot,         // IN: XXX
+           uint_t maxprot,      // IN: XXX
+           uint_t flags,        // IN: XXX
+           struct cred *cr)     // IN: Credentials of caller
+#else
+static int
+HgfsDelmap(struct vnode *vp,    // IN: Vnode of file to decrement map count for
+           offset_t off,        // XXX
+           struct as *as,       // IN: Address space
+           caddr_t addr,        // IN: XXX: Address in this space?
+           size_t len,          // IN: XXX: Length of this mapping?
+           uint_t prot,         // IN: XXX
+           uint_t maxprot,      // IN: XXX
+           uint_t flags,        // IN: XXX
+           struct cred *cr,     // IN: Credentials of caller
+           caller_context_t *ctx)
+#endif
+{
+   DEBUG(VM_DEBUG_NOTSUP, "HgfsDelmap() NOTSUP.\n");
+
+   return ENOTSUP;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsPoll --
+ *
+ *    We are using fs_poll() instead of this, which seems acceptable so far.
+ *
+ *    Invoked when user calls poll(2) on a file in our filesystem.
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+/*
+int
+HgfsPoll(struct vnode *vp,      // IN: Vnode of file to poll
+         short ev,              // IN: Requested events
+         int any,               // IN: Whether other file descriptors have had events
+         short *revp,           // OUT: Filled in with events that have occurred
+         struct pollhead **phpp)// OUT: Set to a pollhead if necessary
+{
+   DEBUG(VM_DEBUG_NOTSUP, "HgfsPoll() NOTSUP.\n");
+
+   return ENOTSUP;
+}*/
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsDump --
+ *
+ *    "Dumps data when the kernel is in a frozen state." (Solaris Internals,
+ *    p536)
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static int
+HgfsDump(struct vnode *vp,      // IN: Vnode of XXX
+         caddr_t addr,          // IN: XXX: Location to dump to?
+         int lbdn,              // IN: XXX
+         int dblks)             // IN: XXX
+#else
+static int
+HgfsDump(struct vnode *vp,         // IN: Vnode of XXX
+         caddr_t addr,             // IN: XXX: Location to dump to?
+         offset_t lbdn,            // IN: XXX
+         offset_t dblks,           // IN: XXX
+         caller_context_t *ctx)    // IN: Context of caller
+#endif
+{
+   DEBUG(VM_DEBUG_NOTSUP, "HgfsDump() NOTSUP.\n");
+
+   return ENOTSUP;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsPathconf --
+ *
+ *    "Establishes file system parameters with the pathconf system call."
+ *    (Solaris Internals, p537)
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static int
+HgfsPathconf(struct vnode *vp,  // IN: Vnode of file to establish parameters for
+             int cmd,           // IN: Command
+             ulong_t *valp,     // OUT: XXX: Returned value?
+             struct cred *cr)   // IN: Credentials of caller
+#else
+static int
+HgfsPathconf(struct vnode *vp,       // IN: Vnode of file to establish parameters for
+             int cmd,                // IN: Command
+             ulong_t *valp,          // OUT: XXX: Returned value?
+             struct cred *cr,        // IN: Credentials of caller
+             caller_context_t *ctx)  // IN: Context of caller
+#endif
+{
+   DEBUG(VM_DEBUG_NOTSUP, "HgfsPathconf() NOTSUP.\n");
+
+   return ENOTSUP;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsPageio --
+ *
+ *    "Paged I/O supprt for file system swap files." (Solaris Internals, p537)
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static int
+HgfsPageio(struct vnode *vp,
+           struct page *pp,
+           u_offset_t io_off,
+           size_t io_len,
+           int flags,
+           struct cred *cr)
+#else
+static int
+HgfsPageio(struct vnode *vp,
+           struct page *pp,
+           u_offset_t io_off,
+           size_t io_len,
+           int flags,
+           struct cred *cr,
+           caller_context_t *ctx)
+#endif
+{
+   DEBUG(VM_DEBUG_NOTSUP, "HgfsPageio() NOTSUP.\n");
+
+   return ENOTSUP;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsDumpctl --
+ *
+ *    "Prepares the file system before and after a dump" (Solaris Internals,
+ *    p536)
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static int
+HgfsDumpctl(struct vnode *vp,
+            int action,
+            int *blkp)
+#else
+static int
+HgfsDumpctl(struct vnode *vp,
+            int action,
+            offset_t *blkp,
+            caller_context_t *ctx)
+#endif
+{
+   DEBUG(VM_DEBUG_NOTSUP, "HgfsDumpctl() NOTSUP.\n");
+
+   return ENOTSUP;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsDispose --
+ *
+ *    Since we don't map any parts of files to pages, this isn't needed.
+ *
+ *    "Frees the given page from the vnode." (Solaris Internals, p536)
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static void
+HgfsDispose(struct vnode *vp,   // IN: Vnode to free page for
+            struct page *pp,    // IN: Page to free
+            int flag,           // IN: XXX
+            int dn,             // IN: XXX
+            struct cred *cr)    // IN: Credentials of caller
+#else
+static void
+HgfsDispose(struct vnode *vp,       // IN: Vnode to free page for
+            struct page *pp,        // IN: Page to free
+            int flag,               // IN: XXX
+            int dn,                 // IN: XXX
+            struct cred *cr,        // IN: Credentials of caller
+            caller_context_t *ctx)  // IN: Context of caller
+#endif
+{
+   DEBUG(VM_DEBUG_ENTRY, "HgfsDispose().\n");
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsSetsecattr --
+ *
+ *    "Sets security access control list attributes." (Solaris Internals,
+ *    p538)
+ *
+ *    We almost certainly won't support this.
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION <= 3
+static int
+HgfsSetsecattr(struct vnode *vp,
+               vsecattr_t *vsap,
+               int flag,
+               struct cred *cr)
+#else
+static int
+HgfsSetsecattr(struct vnode *vp,
+               vsecattr_t *vsap,
+               int flag,
+               struct cred *cr,
+               caller_context_t *ctx)
+#endif
+{
+   DEBUG(VM_DEBUG_NOTSUP, "HgfsSetsecattr() NOTSUP.\n");
+
+   return ENOTSUP;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsGetsecattr --
+ *
+ *    We are using fs_fab_acl() instead of this, which seems to do the right
+ *    thing.
+ *
+ *    "Gets security access control list attributes" (Solaris Internals, p536)
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+/*
+int
+HgfsGetsecattr(struct vnode *vp,
+               vsecattr_t *vsap,
+               int flag,
+               struct cred *cr)
+{
+   DEBUG(VM_DEBUG_NOTSUP, "HgfsGetsecattr() NOTSUP.\n");
+
+   return ENOTSUP;
+}*/
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsShrlock --
+ *
+ *    "ONC shared lock support." (Solaris Internals, p538)
+ *
+ * Results:
+ *
+ * Side effects:
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION == 2
+static int
+HgfsShrlock(struct vnode *vp,           // IN: Vnode of file to lock
+            int cmd,                    // IN: Command
+            struct shrlock *chr,        // IN: Lock
+            int flag)                   // IN: Flags for XXX
+#elif HGFS_VFS_VERSION == 3
+static int
+HgfsShrlock(struct vnode *vp,           // IN: Vnode of file to lock
+            int cmd,                    // IN: Command
+            struct shrlock *chr,        // IN: Lock
+            int flag,                   // IN: Flags for XXX
+            cred_t *cr)                 // IN: Credentials of caller
+#else
+static int
+HgfsShrlock(struct vnode *vp,           // IN: Vnode of file to lock
+            int cmd,                    // IN: Command
+            struct shrlock *chr,        // IN: Lock
+            int flag,                   // IN: Flags for XXX
+            cred_t *cr,                 // IN: Credentials of caller
+            caller_context_t *ctx)      // IN: Context of caller
+#endif
+{
+   DEBUG(VM_DEBUG_NOTSUP, "HgfsShrlock() NOTSUP.\n");
+
+   return ENOTSUP;
+}
+
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsVnevent --
+ *
+ *    Handles an event for the provided vnode.
+ *
+ *    Events can be VE_SUPPORT, VE_RENAME_SRC, VE_RENAME_DEST, VE_REMOVE,
+ *    VE_RMDIR.
+ *
+ *    Note that this function showed up at some point after Build 52 (02/2004)
+ *    of Solaris 10 but before (or at) Build 58 (06/2004).  We only compile
+ *    this in if the driver is being built for Builds greater than 52.
+ *    XXX We should find out what build this function first showed up on.
+ *
+ * Results:
+ *    Returns zero on success and a non-zero error code on error.
+ *
+ * Side effects:
+ *    None.
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+#if HGFS_VFS_VERSION > 2
+#if HGFS_VFS_VERSION == 3
+static int
+HgfsVnevent(struct vnode *vp,        // IN: Vnode the event is occuring to
+            vnevent_t event)         // IN: Event that has occurred
+#else
+static int
+HgfsVnevent(struct vnode *vp,        // IN: Vnode the event is occuring to
+            vnevent_t event,         // IN: Event that has occurred
+            vnode_t *dvp,            // IN: XXX
+            char *fnm,               // IN: XXX
+            caller_context_t *ctx)   // IN: Context of caller
+#endif
+{
+   DEBUG(VM_DEBUG_NOTSUP, "HgfsVnevent: ENOTSUP\n");
+
+   return ENOTSUP;
+}
+#endif
+
+
+/*
+ * Local vnode functions.
+ *
+ * (The rest of the functions in this file are only invoked by our code so they
+ *  ASSERT() their pointer arguments.)
+ */
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsDirOpen --
+ *
+ *    Invoked when HgfsOpen() is called with a vnode of type VDIR.
+ *
+ *    Sends a SEARCH_OPEN request to the Hgfs server.
+ *
+ * Results:
+ *    Returns zero on success and an error code on error.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+HgfsDirOpen(HgfsSuperInfo *sip, // IN: Superinfo pointer
+            struct vnode *vp)   // IN: Vnode of directory to open
+{
+   int ret;
+   HgfsReq *req;
+   HgfsRequestSearchOpen *request;
+   HgfsReplySearchOpen *reply;
+
+   ASSERT(sip);
+   ASSERT(vp);
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsDirOpen: opening \"%s\"\n", HGFS_VP_TO_FILENAME(vp));
+
+   req = HgfsGetNewReq(sip);
+   if (!req) {
+      return EIO;
+   }
+
+   /* Set the correct header values */
+   request = (HgfsRequestSearchOpen *)req->packet;
+   HGFS_INIT_REQUEST_HDR(request, req, HGFS_OP_SEARCH_OPEN);
+
+   /*
+    * Convert name to cross-platform and unescape.  If the vnode is the root of
+    * our filesystem the Hgfs server expects an empty string.
+    */
+   ret = CPName_ConvertTo((HGFS_IS_ROOT_VNODE(sip, vp)) ? "" : HGFS_VP_TO_FILENAME(vp),
+                          MAXPATHLEN, request->dirName.name);
+   if (ret < 0) {
+      ret = ENAMETOOLONG;
+      /* We need to set the request state to error before destroying. */
+      HgfsReqSetState(req, HGFS_REQ_ERROR);
+      goto destroy_out;
+   }
+
+   request->dirName.length = ret;
+
+   req->packetSize = request->dirName.length + sizeof *request;
+
+   /* Submit the request to the Hgfs server */
+   ret = HgfsSubmitRequest(sip, req);
+   if (ret) {
+      /* HgfsSubmitRequest destroys the request if necessary */
+      goto out;
+   }
+
+   /* Our reply is in the request packet */
+   reply = (HgfsReplySearchOpen *)req->packet;
+
+   /* Perform basic validation of packet transfer */
+   if (HgfsValidateReply(req, sizeof reply->header) != 0) {
+         DEBUG(VM_DEBUG_FAIL, "HgfsDirOpen(): invalid reply received.\n");
+         ret = EPROTO;
+         goto destroy_out;
+   }
+
+   DEBUG(VM_DEBUG_COMM, "HgfsDirOpen: received reply for ID %d\n", reply->header.id);
+   DEBUG(VM_DEBUG_COMM, " status: %d (see hgfsProto.h)\n", reply->header.status);
+   DEBUG(VM_DEBUG_COMM, " handle: %d\n", reply->search);
+
+   switch (reply->header.status) {
+   case HGFS_STATUS_SUCCESS:
+      if (req->packetSize != sizeof *reply) {
+         DEBUG(VM_DEBUG_FAIL, "HgfsDirOpen: incorrect packet size.\n");
+         ret = EIO;
+         goto destroy_out;
+      }
+      /* Success handled after switch. */
+      break;
+
+   case HGFS_STATUS_OPERATION_NOT_PERMITTED:
+      DEBUG(VM_DEBUG_FAIL, "HgfsDirOpen: operation not permitted (%s).\n",
+            HGFS_VP_TO_FILENAME(vp));
+      ret = EACCES;
+      goto destroy_out;
+
+   default:
+      DEBUG(VM_DEBUG_FAIL, "HgfsDirOpen: default error (%s).\n",
+            HGFS_VP_TO_FILENAME(vp));
+      ret = EPROTO;
+      goto destroy_out;
+   }
+
+   /* Set the search open handle for use in HgfsReaddir() */
+   ret = HgfsSetOpenFileHandle(vp, reply->search);
+   if (ret) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsDirOpen: couldn't assign handle=%d to %s\n",
+         reply->search, HGFS_VP_TO_FILENAME(vp));
+      HgfsReqSetState(req, HGFS_REQ_ERROR);
+      ret = EINVAL;
+      goto destroy_out;
+   }
+
+   ret = 0;     /* Return success */
+
+destroy_out:
+   /* Make sure we put the request back on the list */
+   HgfsDestroyReq(sip, req);
+out:
+   DEBUG(VM_DEBUG_DONE, "HgfsDirOpen: done\n");
+   return ret;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsFileOpen --
+ *
+ *    Invoked when HgfsOpen() is called with a vnode of type VREG.  Sends
+ *    a OPEN request to the Hgfs server.
+ *
+ *    Note that this function doesn't need to handle creations since the
+ *    HgfsCreate() entry point is called by the kernel for that.
+ *
+ * Results:
+ *    Returns zero on success and an error code on error.
+ *
+ * Side effects:
+ *    None.
+ *
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+HgfsFileOpen(HgfsSuperInfo *sip,        // IN: Superinfo pointer
+             struct vnode *vp,        // IN: Vnode of file to open
+             int flag,                  // IN: Flags of open
+             int permissions)           // IN: Permissions of open (only when creating)
+{
+   HgfsReq *req;
+   HgfsRequestOpen *request;
+   HgfsReplyOpen *reply;
+   int ret;
+
+   ASSERT(sip);
+   ASSERT(vp);
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsFileOpen: opening \"%s\"\n", HGFS_VP_TO_FILENAME(vp));
+
+   req = HgfsGetNewReq(sip);
+   if (!req) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsFileOpen: HgfsGetNewReq failed.\n");
+      return EIO;
+   }
+
+   request = (HgfsRequestOpen *)req->packet;
+   HGFS_INIT_REQUEST_HDR(request, req, HGFS_OP_OPEN);
+
+   /* Convert Solaris modes to Hgfs modes */
+   ret = HgfsGetOpenMode((uint32_t)flag);
+   if (ret < 0) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsFileOpen: HgfsGetOpenMode failed.\n");
+      ret = EINVAL;
+      /* We need to set the request state to error before destroying. */
+      HgfsReqSetState(req, HGFS_REQ_ERROR);
+      goto destroy_out;
+   }
+
+   request->mode = ret;
+   DEBUG(VM_DEBUG_COMM, "HgfsFileOpen: open mode is %x\n", request->mode);
+
+   /* Convert Solaris flags to Hgfs flags */
+   ret = HgfsGetOpenFlags((uint32_t)flag);
+   if (ret < 0) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsFileOpen: HgfsGetOpenFlags failed.\n");
+      ret = EINVAL;
+      /* We need to set the request state to error before destroying. */
+      HgfsReqSetState(req, HGFS_REQ_ERROR);
+      goto destroy_out;
+   }
+
+   request->flags = ret;
+   DEBUG(VM_DEBUG_COMM, "HgfsFileOpen: open flags are %x\n", request->flags);
+
+   request->permissions = (permissions & S_IRWXU) >> HGFS_ATTR_MODE_SHIFT;
+   DEBUG(VM_DEBUG_COMM, "HgfsFileOpen: permissions are %o\n", request->permissions);
+
+   /* Convert the file name to cross platform format. */
+   ret = CPName_ConvertTo(HGFS_VP_TO_FILENAME(vp), MAXPATHLEN, request->fileName.name);
+   if (ret < 0) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsFileOpen: CPName_ConvertTo failed.\n");
+      ret = ENAMETOOLONG;
+      /* We need to set the request state to error before destroying. */
+      HgfsReqSetState(req, HGFS_REQ_ERROR);
+      goto destroy_out;
+   }
+   request->fileName.length = ret;
+
+   /* Packet size includes the request and its payload. */
+   req->packetSize = request->fileName.length + sizeof *request;
+
+   ret = HgfsSubmitRequest(sip, req);
+   if (ret) {
+      /* HgfsSubmitRequest will destroy the request if necessary. */
+      DEBUG(VM_DEBUG_FAIL, "HgfsFileOpen: could not submit request.\n");
+      goto out;
+   }
+
+   reply = (HgfsReplyOpen *)req->packet;
+
+   if (HgfsValidateReply(req, sizeof reply->header) != 0) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsFileOpen: request not valid.\n");
+      ret = EPROTO;
+      goto destroy_out;
+   }
+
+   switch (reply->header.status) {
+   case HGFS_STATUS_SUCCESS:
+      if (req->packetSize != sizeof *reply) {
+         DEBUG(VM_DEBUG_FAIL, "HgfsFileOpen: size of reply is incorrect.\n");
+         ret = EIO;
+         goto destroy_out;
+      }
+
+      /* Success case is handled after switch. */
+      break;
+
+   case HGFS_STATUS_NO_SUCH_FILE_OR_DIR:
+   case HGFS_STATUS_INVALID_NAME:
+      DEBUG(VM_DEBUG_FAIL, "HgfsFileOpen: no such file \"%s\".\n",
+            HGFS_VP_TO_FILENAME(vp));
+      ret = ENOENT;
+      goto destroy_out;
+
+   case HGFS_STATUS_FILE_EXISTS:
+      DEBUG(VM_DEBUG_FAIL, "HgfsFileOpen: \"%s\" exists.\n",
+            HGFS_VP_TO_FILENAME(vp));
+      ret = EEXIST;
+      goto destroy_out;
+
+   case HGFS_STATUS_OPERATION_NOT_PERMITTED:
+      DEBUG(VM_DEBUG_FAIL, "HgfsFileOpen: operation not permitted on %s.\n",
+            HGFS_VP_TO_FILENAME(vp));
+      ret = EACCES;
+      goto destroy_out;
+
+   case HGFS_STATUS_ACCESS_DENIED:
+      DEBUG(VM_DEBUG_FAIL, "HgfsFileOpen: access denied on %s.\n",
+            HGFS_VP_TO_FILENAME(vp));
+      ret = EACCES;
+      goto destroy_out;
+
+   default:
+      DEBUG(VM_DEBUG_FAIL, "HgfsFileOpen: default/unknown error %d.\n",
+            reply->header.status);
+      ret = EACCES;
+      goto destroy_out;
+   }
+
+   /*
+    * We successfully received a reply, so we need to save the handle in
+    * this file's HgfsOpenFile and return success.
+    */
+   ret = HgfsSetOpenFileHandle(vp, reply->file);
+   if (ret) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsFileOpen: couldn't assign handle %d (%s)\n",
+            reply->file, HGFS_VP_TO_FILENAME(vp));
+      HgfsReqSetState(req, HGFS_REQ_ERROR);
+      ret = EINVAL;
+      goto destroy_out;
+   }
+
+   ret = 0;
+
+
+destroy_out:
+   HgfsDestroyReq(sip, req);
+out:
+   return ret;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsDirClose --
+ *
+ *    Invoked when HgfsClose() is called with a vnode of type VDIR.
+ *
+ *    Sends an SEARCH_CLOSE request to the Hgfs server.
+ *
+ * Results:
+ *    Returns zero on success and an error code on error.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+HgfsDirClose(HgfsSuperInfo *sip,        // IN: Superinfo pointer
+             struct vnode *vp)          // IN: Vnode of directory to close
+{
+   HgfsReq *req;
+   HgfsRequestSearchClose *request;
+   HgfsReplySearchClose *reply;
+   int ret;
+
+   ASSERT(sip);
+   ASSERT(vp);
+
+   req = HgfsGetNewReq(sip);
+   if (!sip) {
+      return EIO;
+   }
+
+   /*
+    * Prepare the request structure.  Of note here is that the request is
+    * always the same size so we just set the packetSize to that.
+    */
+   request = (HgfsRequestSearchClose *)req->packet;
+   HGFS_INIT_REQUEST_HDR(request, req, HGFS_OP_SEARCH_CLOSE);
+
+   /* Get this open file's handle, since that is what we want to close. */
+   ret = HgfsGetOpenFileHandle(vp, &request->search);
+   if (ret) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsDirClose: couldn't get handle for %s\n",
+            HGFS_VP_TO_FILENAME(vp));
+      ret = EINVAL;
+      /* We need to set the request state to error before destroying. */
+      HgfsReqSetState(req, HGFS_REQ_ERROR);
+      goto destroy_out;
+   }
+   req->packetSize = sizeof *request;
+
+   /* Submit the request to the Hgfs server */
+   ret = HgfsSubmitRequest(sip, req);
+   if (ret) {
+      /* HgfsSubmitRequest destroys the request if necessary */
+      goto out;
+   }
+
+   reply = (HgfsReplySearchClose *)req->packet;
+
+   /* Ensure reply was received correctly and is necessary size. */
+   if (HgfsValidateReply(req, sizeof reply->header) != 0) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsDirClose: invalid reply received.\n");
+      ret = EPROTO;
+      goto destroy_out;
+   }
+
+   DEBUG(VM_DEBUG_COMM, "HgfsDirClose: received reply for ID %d\n", reply->header.id);
+   DEBUG(VM_DEBUG_COMM, " status: %d (see hgfsProto.h)\n", reply->header.status);
+
+   /* Ensure server was able to close directory. */
+   if (reply->header.status != HGFS_STATUS_SUCCESS) {
+      ret = EIO;
+      goto destroy_out;
+   }
+
+   /* Now clear this open file's handle for future use. */
+   ret = HgfsClearOpenFileHandle(vp);
+   if (ret) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsDirClose: couldn't clear handle.\n");
+      ret = EINVAL;
+      HgfsReqSetState(req, HGFS_REQ_ERROR);
+      goto destroy_out;
+   }
+
+   /* The directory was closed successfully so we return success. */
+   ret = 0;
+
+
+destroy_out:
+   HgfsDestroyReq(sip, req);
+out:
+   return ret;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsFileClose --
+ *
+ *    Invoked when HgfsClose() is called with a vnode of type VREG.
+ *
+ *    Sends a CLOSE request to the Hgfs server.
+ *
+ * Results:
+ *    Returns zero on success and an error code on error.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+HgfsFileClose(HgfsSuperInfo *sip,       // IN: Superinfo pointer
+              struct vnode *vp)         // IN: Vnode of file to close
+{
+   HgfsReq *req;
+   HgfsRequestClose *request;
+   HgfsReplyClose *reply;
+   int ret;
+
+   ASSERT(sip);
+   ASSERT(vp);
+
+   req = HgfsGetNewReq(sip);
+   if (!req) {
+      ret = EIO;
+      goto out;
+   }
+
+   request = (HgfsRequestClose *)req->packet;
+   HGFS_INIT_REQUEST_HDR(request, req, HGFS_OP_CLOSE);
+
+   /* Tell the Hgfs server which handle to close */
+   ret = HgfsGetOpenFileHandle(vp, &request->file);
+   if (ret) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsFileClose: couldn't get handle.\n");
+      ret = EINVAL;
+      /* We need to set the request state to error before destroying. */
+      HgfsReqSetState(req, HGFS_REQ_ERROR);
+      goto destroy_out;
+   }
+
+   req->packetSize = sizeof *request;
+
+   ret = HgfsSubmitRequest(sip, req);
+   if (ret) {
+      /* HgfsSubmitRequest will destroy the request if necessary. */
+      DEBUG(VM_DEBUG_FAIL, "HgfsFileClose: submit request failed.\n");
+      goto out;
+   }
+
+   if (HgfsValidateReply(req, sizeof *reply) != 0) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsFileClose: reply was invalid.\n");
+      ret = EPROTO;
+      goto destroy_out;
+   }
+
+   reply = (HgfsReplyClose *)req->packet;
+
+   switch (reply->header.status) {
+   case HGFS_STATUS_SUCCESS:
+      /*
+       * We already verified the size of the reply above since this reply type
+       * only contains a header, so we just clear the handle and return success.
+       */
+      ret = HgfsClearOpenFileHandle(vp);
+      if (ret) {
+         DEBUG(VM_DEBUG_FAIL, "HgfsFileClose: couldn't clear handle.\n");
+         ret = EINVAL;
+         HgfsReqSetState(req, HGFS_REQ_ERROR);
+         goto destroy_out;
+      }
+
+      ret = 0;
+      goto destroy_out;
+
+   case HGFS_STATUS_INVALID_HANDLE:
+      DEBUG(VM_DEBUG_FAIL, "HgfsFileClose: invalid handle error.\n");
+      ret = EPROTO;
+      goto destroy_out;
+
+   case HGFS_STATUS_OPERATION_NOT_PERMITTED:
+      DEBUG(VM_DEBUG_FAIL, "HgfsFileClose: operation not permitted error.\n");
+      ret = EACCES;
+      goto destroy_out;
+
+   default:
+      DEBUG(VM_DEBUG_FAIL, "HgfsFileClose: other/unknown error.\n");
+      ret = EPROTO;
+      goto destroy_out;
+   }
+
+destroy_out:
+   HgfsDestroyReq(sip, req);
+out:
+   DEBUG(VM_DEBUG_DONE, "HgfsFileClose: returning %d\n", ret);
+   return ret;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsGetNextDirEntry --
+ *
+ *    Writes the name of the directory entry matching the handle and offset to
+ *    nameOut.  This requires sending a SEARCH_READ request.
+ *
+ * Results:
+ *    Returns zero on success and an error code on error.  The done value is
+ *    set if there are no more directory entries.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+HgfsGetNextDirEntry(HgfsSuperInfo *sip,         // IN: Superinfo pointer
+                    HgfsHandle handle,          // IN: Handle for request
+                    uint32_t offset,            // IN: Offset
+                    char *nameOut,              // OUT: Location to write name
+                    Bool *done)                 // OUT: Whether there are any more
+{
+   HgfsReq *req;
+   HgfsRequestSearchRead *request;
+   HgfsReplySearchRead *reply;
+   int ret;
+
+   DEBUG(VM_DEBUG_ENTRY,
+         "HgfsGetNextDirEntry: handle=%d, offset=%d.\n", handle, offset);
+
+   ASSERT(sip);
+   ASSERT(nameOut);
+   ASSERT(done);
+
+   req = HgfsGetNewReq(sip);
+   if (!req) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsGetNextDirEntry: couldn't get req.\n");
+      return EIO;
+   }
+
+   /*
+    * Fill out the search read request that will return a single directory
+    * entry for the provided handle at the given offset.
+    */
+   request = (HgfsRequestSearchRead *)req->packet;
+   HGFS_INIT_REQUEST_HDR(request, req, HGFS_OP_SEARCH_READ);
+
+   request->search = handle;
+   request->offset = offset;
+
+   req->packetSize = sizeof *request;
+
+   ret = HgfsSubmitRequest(sip, req);
+   if (ret) {
+      /* HgfsSubmitRequest will destroy the request if necessary. */
+      DEBUG(VM_DEBUG_FAIL, "HgfsGetNextDirEntry: HgfsSubmitRequest failed.\n");
+      goto out;
+   }
+
+   reply = (HgfsReplySearchRead *)req->packet;
+
+   /* Validate the request state and ensure we have at least a header */
+   if (HgfsValidateReply(req, sizeof reply->header) != 0) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsGetNextDirEntry: reply not valid.\n");
+      ret = EPROTO;
+      goto destroy_out;
+   }
+
+   DEBUG(VM_DEBUG_COMM, "HgfsGetNextDirEntry: received reply for ID %d\n",
+         reply->header.id);
+   DEBUG(VM_DEBUG_COMM, " status: %d (see hgfsProto.h)\n", reply->header.status);
+
+   /* Now ensure the server didn't have an error */
+   if (reply->header.status != HGFS_STATUS_SUCCESS) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsGetNextDirEntry: server didn't return success (%d).\n",
+            reply->header.status);
+      ret = EINVAL;
+      goto destroy_out;
+   }
+
+   /* Make sure we got an entire reply (excluding filename) */
+   if (req->packetSize < sizeof *reply) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsGetNextDirEntry: server didn't provide entire reply.\n");
+      ret = EIO;
+      goto destroy_out;
+   }
+
+   /* See if there are no more filenames to read */
+   if (reply->fileName.length <= 0) {
+      DEBUG(VM_DEBUG_DONE, "HgfsGetNextDirEntry: no more directory entries.\n");
+      *done = TRUE;
+      ret = 0;         /* return success */
+      goto destroy_out;
+   }
+
+   /* Make sure filename isn't too long */
+   if ((reply->fileName.length > MAXNAMELEN) ||
+       (reply->fileName.length > HGFS_PAYLOAD_MAX(reply)) ) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsGetNextDirEntry: filename is too long.\n");
+      ret = EOVERFLOW;
+      goto destroy_out;
+   }
+
+   /*
+    * Everything is all right, copy filename to caller's buffer.  Note that
+    * Solaris directory entries don't need the attribute information in the
+    * reply.
+    */
+   memcpy(nameOut, reply->fileName.name, reply->fileName.length);
+   nameOut[reply->fileName.length] = '\0';
+   ret = 0;
+
+   DEBUG(VM_DEBUG_DONE, "HgfsGetNextDirEntry: done.\n");
+destroy_out:
+   HgfsDestroyReq(sip, req);
+out:
+   return ret;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsDoRead --
+ *
+ *    Sends a single READ request to the Hgfs server and writes the contents
+ *    into the user's buffer if successful.
+ *
+ *    This function is called repeatedly by HgfsRead() with requests of size
+ *    less than or equal to HGFS_IO_MAX.
+ *
+ *    Note that we return the negative of an appropriate error code in this
+ *    function so we can differentiate between success and failure.  On success
+ *    we need to return the number of bytes read, but Solaris' error codes are
+ *    positive so we negate them before returning.  If callers want to return
+ *    these error codes to the Kernel, they will need to flip their sign.
+ *
+ * Results:
+ *   Returns number of bytes read on success and a negative value on error.
+ *
+ * Side effects:
+ *   On success, size bytes are written into the user's buffer.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+HgfsDoRead(HgfsSuperInfo *sip,  // IN: Superinfo pointer
+           HgfsHandle handle,   // IN: Server's handle to read from
+           uint64_t offset,     // IN: File offset to read at
+           uint32_t size,       // IN: Number of bytes to read
+           uio_t *uiop)         // IN: Defines user's read request
+{
+   HgfsReq *req;
+   HgfsRequestRead *request;
+   HgfsReplyRead *reply;
+   int ret;
+
+   ASSERT(sip);
+   ASSERT(uiop);
+   ASSERT(size <= HGFS_IO_MAX); // HgfsRead() should guarantee this
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsDoRead: entry.\n");
+
+   req = HgfsGetNewReq(sip);
+   if (!req) {
+      return -EIO;
+   }
+
+   request = (HgfsRequestRead *)req->packet;
+   HGFS_INIT_REQUEST_HDR(request, req, HGFS_OP_READ);
+
+   /* Indicate which file, where in the file, and how much to read. */
+   request->file = handle;
+   request->offset = offset;
+   request->requiredSize = size;
+
+   req->packetSize = sizeof *request;
+
+   ret = HgfsSubmitRequest(sip, req);
+   if (ret) {
+      /*
+       * We need to flip the sign of the return value to indicate error; see
+       * the comment in the function header.  HgfsSubmitRequest() handles
+       * destroying the request if necessary, so we don't here.
+       */
+      ret = -ret;
+      goto out;
+   }
+
+   reply = (HgfsReplyRead *)req->packet;
+
+   /* Ensure we got an entire header. */
+   if (HgfsValidateReply(req, sizeof reply->header) != 0) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsDoRead: invalid reply received.\n");
+      ret = -EPROTO;
+      goto destroy_out;
+   }
+
+   if (reply->header.status != HGFS_STATUS_SUCCESS) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsDoRead: request not completed successfully.\n");
+      ret = -EACCES;
+      goto destroy_out;
+   }
+
+   /*
+    * Now perform checks on the actualSize.  There are three cases:
+    *  o actualSize is less than or equal to size, which indicates success
+    *  o actualSize is zero, which indicates the end of the file (and success)
+    *  o actualSize is greater than size, which indicates a server error
+    */
+   if (reply->actualSize <= size) {
+      /* If we didn't get any data, we don't need to copy to the user. */
+      if (reply->actualSize == 0) {
+         goto success;
+      }
+
+      /* Perform the copy to the user */
+      ret = uiomove(reply->payload, reply->actualSize, UIO_READ, uiop);
+      if (ret) {
+         ret = -EIO;
+         goto destroy_out;
+      }
+
+      /* We successfully copied the payload to the user's buffer */
+      goto success;
+
+   } else {
+      /* We got too much data: server error. */
+      DEBUG(VM_DEBUG_FAIL, "HgfsDoRead: received too much data in payload.\n");
+      ret = -EPROTO;
+      goto destroy_out;
+   }
+
+
+success:
+   ret = reply->actualSize;
+   DEBUG(VM_DEBUG_DONE, "HgfsDoRead: successfully read %d bytes to user.\n", ret);
+destroy_out:
+   HgfsDestroyReq(sip, req);
+out:
+   return ret;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsDoWrite --
+ *
+ *    Sends a single WRITE request to the Hgfs server with the contents of
+ *    the user's buffer.
+ *
+ *    This function is called repeatedly by HgfsWrite() with requests of size
+ *    less than or equal to HGFS_IO_MAX.
+ *
+ *    Note that we return the negative of an appropriate error code in this
+ *    function so we can differentiate between success and failure.  On success
+ *    we need to return the number of bytes written, but Solaris' error codes are
+ *    positive so we negate them before returning.  If callers want to return
+ *    these error codes to the kernel, they will need to flip their sign.
+ *
+ * Results:
+ *   Returns number of bytes written on success and a negative value on error.
+ *
+ * Side effects:
+ *   On success, size bytes are written to the file specified by the handle.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+HgfsDoWrite(HgfsSuperInfo *sip, // IN: Superinfo pointer
+            HgfsHandle handle,  // IN: Handle representing file to write to
+            int ioflag,         // IN: Flags for write
+            uint64_t offset,    // IN: Where in the file to begin writing
+            uint32_t size,      // IN: How much data to write
+            uio_t *uiop)        // IN: Describes user's write request
+{
+   HgfsReq *req;
+   HgfsRequestWrite *request;
+   HgfsReplyWrite *reply;
+   int ret;
+
+   ASSERT(sip);
+   ASSERT(uiop);
+   ASSERT(size <= HGFS_IO_MAX); // HgfsWrite() guarantees this
+
+   req = HgfsGetNewReq(sip);
+   if (!req) {
+      return -EIO;
+   }
+
+   request = (HgfsRequestWrite *)req->packet;
+   HGFS_INIT_REQUEST_HDR(request, req, HGFS_OP_WRITE);
+
+   request->file = handle;
+   request->flags = 0;
+   request->offset = offset;
+   request->requiredSize = size;
+
+   if (ioflag & FAPPEND) {
+      DEBUG(VM_DEBUG_COMM, "HgfsDoWrite: writing in append mode.\n");
+      request->flags |= HGFS_WRITE_APPEND;
+   }
+
+   DEBUG(VM_DEBUG_COMM, "HgfsDoWrite: requesting write of %d bytes.\n", size);
+
+   /* Copy the data the user wants to write into the payload. */
+   ret = uiomove(request->payload, request->requiredSize, UIO_WRITE, uiop);
+   if (ret) {
+      DEBUG(VM_DEBUG_FAIL,
+            "HgfsDoWrite: uiomove(9F) failed copying data from user.\n");
+      ret = -EIO;
+      /* We need to set the request state to error before destroying. */
+      HgfsReqSetState(req, HGFS_REQ_ERROR);
+      goto destroy_out;
+   }
+
+   /* We subtract one so request's 'char payload[1]' member isn't double counted. */
+   req->packetSize = sizeof *request + request->requiredSize - 1;
+
+   ret = HgfsSubmitRequest(sip, req);
+   if (ret) {
+      /*
+       * As in HgfsDoRead(), we need to flip the sign of the error code
+       * returned by HgfsSubmitRequest().
+       */
+      DEBUG(VM_DEBUG_FAIL, "HgfsDoWrite: HgfsSubmitRequest failed.\n");
+      ret = -ret;
+      goto out;
+   }
+
+   reply = (HgfsReplyWrite *)req->packet;
+
+   if (HgfsValidateReply(req, sizeof reply->header) != 0) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsDoWrite: invalid reply received.\n");
+      ret = -EPROTO;
+      goto destroy_out;
+   }
+
+   if (reply->header.status != HGFS_STATUS_SUCCESS) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsDoWrite: write failed (status=%d).\n",
+            reply->header.status);
+      ret = -EACCES;
+      goto destroy_out;
+   }
+
+   if (req->packetSize != sizeof *reply) {
+      DEBUG(VM_DEBUG_FAIL,
+            "HgfsDoWrite: invalid size of reply on successful reply.\n");
+      ret = -EPROTO;
+      goto destroy_out;
+   }
+
+   /* The write was completed successfully, so return the amount written. */
+   ret = reply->actualSize;
+   DEBUG(VM_DEBUG_DONE, "HgfsDoWrite: wrote %d bytes.\n", ret);
+
+destroy_out:
+   HgfsDestroyReq(sip, req);
+out:
+   return ret;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsDelete --
+ *
+ *    Sends a request to delete a file or directory.
+ *
+ * Results:
+ *    Returns 0 on success or an error code on error.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+HgfsDelete(HgfsSuperInfo *sip,          // IN: Superinfo
+           char *filename,              // IN: Full name of file to remove
+           HgfsOp op)                   // IN: Hgfs operation this delete is for
+{
+   HgfsReq *req;
+   HgfsRequestDelete *request;
+   HgfsReplyDelete *reply;
+   int ret;
+
+   ASSERT(sip);
+   ASSERT(filename);
+   ASSERT((op == HGFS_OP_DELETE_FILE) || (op == HGFS_OP_DELETE_DIR));
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsDelete().\n");
+
+   req = HgfsGetNewReq(sip);
+   if (!req) {
+      return EIO;
+   }
+
+   /* Initialize the request's contents. */
+   request = (HgfsRequestDelete *)req->packet;
+   HGFS_INIT_REQUEST_HDR(request, req, op);
+
+   /* Convert filename to cross platform and unescape. */
+   ret = CPName_ConvertTo(filename, MAXPATHLEN, request->fileName.name);
+   if (ret < 0) {
+      ret = ENAMETOOLONG;
+      /* We need to set the request state to error before destroying. */
+      HgfsReqSetState(req, HGFS_REQ_ERROR);
+      goto destroy_out;
+   }
+
+   request->fileName.length = ret;
+
+   /* Set the size of our request. (XXX should this be - 1 for char[1]?) */
+   req->packetSize = sizeof *request + request->fileName.length;
+
+   DEBUG(VM_DEBUG_COMM, "HgfsDelete: deleting \"%s\"\n", filename);
+
+   /* Submit our request to guestd. */
+   ret = HgfsSubmitRequest(sip, req);
+   if (ret) {
+      /* HgfsSubmitRequest() handles destroying the request if necessary. */
+      goto out;
+   }
+
+   reply = (HgfsReplyDelete *)req->packet;
+
+   /* Check the request status and size of reply. */
+   if (HgfsValidateReply(req, sizeof *reply) != 0) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsDelete: invalid reply received.\n");
+      ret = EPROTO;
+      goto destroy_out;
+   }
+
+   /* Return the appropriate value. */
+   switch (reply->header.status) {
+   case HGFS_STATUS_SUCCESS:
+      ret = 0;
+      break;
+
+   case HGFS_STATUS_OPERATION_NOT_PERMITTED:
+      DEBUG(VM_DEBUG_FAIL, "HgfsDelete: operation not permitted.\n");
+      ret = EACCES;
+      goto destroy_out;
+
+   case HGFS_STATUS_NOT_DIRECTORY:
+      DEBUG(VM_DEBUG_FAIL, "HgfsDelete: not a directory.\n");
+      ret = ENOTDIR;
+      goto destroy_out;
+
+   case HGFS_STATUS_DIR_NOT_EMPTY:
+      DEBUG(VM_DEBUG_FAIL, "HgfsDelete: directory not empty.\n");
+      ret = EEXIST;
+      goto destroy_out;
+
+   case HGFS_STATUS_NO_SUCH_FILE_OR_DIR:
+   case HGFS_STATUS_INVALID_NAME:
+      DEBUG(VM_DEBUG_FAIL, "HgfsDelete: no such file or directory.\n");
+      ret = ENOENT;
+      goto destroy_out;
+   case HGFS_STATUS_ACCESS_DENIED:
+      DEBUG(VM_DEBUG_FAIL, "HgfsDelete: access denied.\n");
+
+      /* XXX: Add retry behavior after removing r/o bit. */
+      ret = EACCES;
+      goto destroy_out;
+   default:
+      DEBUG(VM_DEBUG_FAIL, "HgfsDelete: default error.\n");
+      ret = EPROTO;
+      goto destroy_out;
+   }
+
+   DEBUG(VM_DEBUG_DONE, "HgfsDelete: done.\n");
+
+destroy_out:
+   HgfsDestroyReq(sip, req);
+out:
+   return ret;
+}
+
+
+/*
+ * Function(s) exported to Solaris Hgfs code
+ */
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsGetSuperInfo --
+ *
+ *    Provides a pointer to the superinfo structure as long as the filesystem
+ *    is mounted.
+ *
+ * Results:
+ *    Pointer to the superinfo on success, NULL on failure.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+inline HgfsSuperInfo *
+HgfsGetSuperInfo()
+{
+   HgfsSuperInfo *sip;
+
+   /*
+    * The superInfoHead and hgfsInstance are global variables set by the device
+    * have of the driver at attach-time (HgfsDevAttach()).  We access the soft
+    * state from the filesystem in this way to ensure consistency with the
+    * driver.
+    */
+   sip = (HgfsSuperInfo *)ddi_get_soft_state(superInfoHead, hgfsInstance);
+   if (!sip) {
+      return NULL;
+   }
+
+   /* Only return the superinfo if the filesystem is mounted. */
+   return (sip->vfsp) ? sip : NULL;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsSetVnodeOps --
+ *
+ *    Sets the vnode operations for the provided vnode.
+ *
+ *    Solaris 9:
+ *    We just set the vnode's operations field to point to our statically
+ *    created array of entry points.
+ *
+ *    Solaris 10:
+ *    The first time this function is called it will create the vnode
+ *    operations and place a pointer to them in the superinfo structure.  On
+ *    subsequent invocations the same operations structure will be assigned to
+ *    vnodes.
+ *
+ * Results:
+ *    Returns zero on success and a non-zero error code on error.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+HgfsSetVnodeOps(HgfsSuperInfo *sip,     // IN: Superinfo pointer
+                struct vnode *vp)       // IN: vnode for this file
+#if HGFS_VFS_VERSION == 2
+{
+   ASSERT(vp);
+
+   vp->v_op = &HgfsVnodeOps;
+   return 0;
+}
+#else
+{
+   int ret;
+
+   ASSERT(sip);
+   ASSERT(vp);
+
+   /* See if we need to create the vnode operations structure */
+   if (!sip->vnodeOps) {
+      ret = HgfsMakeVnodeOps(sip);
+      if (ret) {
+         DEBUG(VM_DEBUG_FAIL, "HgfsSetVnodeOps: couldn't create vnode ops.\n");
+         return HGFS_ERR;
+      } else {
+         DEBUG(VM_DEBUG_INFO, "HgfsSetVnodeOps: made vnode ops.\n");
+      }
+   }
+
+   if (vn_getops(vp) == sip->vnodeOps) {
+      DEBUG(VM_DEBUG_INFO, "HgfsSetVnodeOps: vnode ops already set.\n");
+   } else {
+      DEBUG(VM_DEBUG_INFO, "HgfsSetVnodeOps: we had to set the vnode ops.\n");
+      /* Set the operations for this vnode */
+      vn_setops(vp, sip->vnodeOps);
+   }
+
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsMakeVnodeOps --
+ *
+ *    Registers our vnode operations with the kernel.  After this function
+ *    completes, all calls to vn_alloc() for our filesystem should return vnodes
+ *    with the correct operations.
+ *
+ *    The operation structure allocated here will be freed in
+ *    HgfsFreevfs() which is called by the Kernel when the filesystem is
+ *    unmounted.
+ *
+ * Results:
+ *    Return 0 on success and non-zero on failure.
+ *
+ * Side effects:
+ *    The kernel allocates memory for our operations structure.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+HgfsMakeVnodeOps(HgfsSuperInfo *sip)    // IN: Superinfo
+{
+   int ret;
+   fs_operation_def_t vnodeOpsArr[] = {
+      HGFS_VOP(VOPNAME_OPEN, vop_open, HgfsOpen),
+      HGFS_VOP(VOPNAME_CLOSE, vop_close, HgfsClose),
+      HGFS_VOP(VOPNAME_READ, vop_read, HgfsRead),
+      HGFS_VOP(VOPNAME_WRITE, vop_write, HgfsWrite),
+      HGFS_VOP(VOPNAME_IOCTL, vop_ioctl, HgfsIoctl),
+      HGFS_VOP(VOPNAME_SETFL, vop_setfl, fs_setfl),
+      HGFS_VOP(VOPNAME_GETATTR, vop_getattr, HgfsGetattr),
+      HGFS_VOP(VOPNAME_SETATTR, vop_setattr, HgfsSetattr),
+      HGFS_VOP(VOPNAME_ACCESS, vop_access, HgfsAccess),
+      HGFS_VOP(VOPNAME_LOOKUP, vop_lookup, HgfsLookup),
+      HGFS_VOP(VOPNAME_CREATE, vop_create, HgfsCreate),
+      HGFS_VOP(VOPNAME_REMOVE, vop_remove, HgfsRemove),
+      HGFS_VOP(VOPNAME_LINK, vop_link, HgfsLink),
+      HGFS_VOP(VOPNAME_RENAME, vop_rename, HgfsRename),
+      HGFS_VOP(VOPNAME_MKDIR, vop_mkdir, HgfsMkdir),
+      HGFS_VOP(VOPNAME_RMDIR, vop_rmdir, HgfsRmdir),
+      HGFS_VOP(VOPNAME_READDIR, vop_readdir, HgfsReaddir),
+      HGFS_VOP(VOPNAME_SYMLINK, vop_symlink, HgfsSymlink),
+      HGFS_VOP(VOPNAME_READLINK, vop_readlink, HgfsReadlink),
+      HGFS_VOP(VOPNAME_FSYNC, vop_fsync, HgfsFsync),
+#if HGFS_VFS_VERSION <= 3
+      HGFS_VOP(VOPNAME_INACTIVE, vop_inactive, (fs_generic_func_p)HgfsInactive),
+      HGFS_VOP(VOPNAME_RWLOCK, vop_rwlock, (fs_generic_func_p)HgfsRwlock),
+      HGFS_VOP(VOPNAME_RWUNLOCK, vop_rwunlock, (fs_generic_func_p)HgfsRwunlock),
+      HGFS_VOP(VOPNAME_MAP, vop_map, (fs_generic_func_p)HgfsMap),
+      HGFS_VOP(VOPNAME_ADDMAP, vop_addmap, (fs_generic_func_p)HgfsAddmap),
+      HGFS_VOP(VOPNAME_POLL, vop_poll, (fs_generic_func_p)fs_poll),
+      HGFS_VOP(VOPNAME_DISPOSE, vop_dispose, (fs_generic_func_p)HgfsDispose),
+#else
+      HGFS_VOP(VOPNAME_INACTIVE, vop_inactive, HgfsInactive),
+      HGFS_VOP(VOPNAME_RWLOCK, vop_rwlock, HgfsRwlock),
+      HGFS_VOP(VOPNAME_RWUNLOCK, vop_rwunlock, HgfsRwunlock),
+      HGFS_VOP(VOPNAME_MAP, vop_map, HgfsMap),
+      HGFS_VOP(VOPNAME_ADDMAP, vop_addmap, HgfsAddmap),
+      HGFS_VOP(VOPNAME_POLL, vop_poll, fs_poll),
+      HGFS_VOP(VOPNAME_DISPOSE, vop_dispose, HgfsDispose),
+#endif
+      HGFS_VOP(VOPNAME_FID, vop_fid, HgfsFid),
+      HGFS_VOP(VOPNAME_SEEK, vop_seek, HgfsSeek),
+      HGFS_VOP(VOPNAME_CMP, vop_cmp, HgfsCmp),
+      HGFS_VOP(VOPNAME_FRLOCK, vop_frlock, HgfsFrlock),
+      HGFS_VOP(VOPNAME_SPACE, vop_space, HgfsSpace),
+      HGFS_VOP(VOPNAME_REALVP, vop_realvp, HgfsRealvp),
+      HGFS_VOP(VOPNAME_GETPAGE, vop_getpage, HgfsGetpage),
+      HGFS_VOP(VOPNAME_PUTPAGE, vop_putpage, HgfsPutpage),
+      HGFS_VOP(VOPNAME_DELMAP, vop_delmap, HgfsDelmap),
+      HGFS_VOP(VOPNAME_DUMP, vop_dump, HgfsDump),
+      HGFS_VOP(VOPNAME_PATHCONF, vop_pathconf, HgfsPathconf),
+      HGFS_VOP(VOPNAME_PAGEIO, vop_pageio, HgfsPageio),
+      HGFS_VOP(VOPNAME_DUMPCTL, vop_dumpctl, HgfsDumpctl),
+      HGFS_VOP(VOPNAME_GETSECATTR, vop_getsecattr, fs_fab_acl),
+      HGFS_VOP(VOPNAME_SETSECATTR, vop_setsecattr, HgfsSetsecattr),
+      HGFS_VOP(VOPNAME_SHRLOCK, vop_shrlock, HgfsShrlock),
+#if HGFS_VFS_VERSION > 2
+      HGFS_VOP(VOPNAME_VNEVENT, vop_vnevent, HgfsVnevent),
+#endif
+#if HGFS_VFS_VERSION <= 3
+      { NULL, NULL}
+#else
+      { NULL, { NULL }                             }
+#endif
+   };
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsMakeVnodeOps: making vnode ops.\n");
+
+   /*
+    * Create a vnodeops structure and register it with the kernel.  We save the
+    * operations structure in the superinfo so it can be assigned in the
+    * future.
+    */
+   ret = vn_make_ops(HGFS_FS_NAME, vnodeOpsArr, &sip->vnodeOps);
+   if (ret) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsMakeVnodeOps: vn_make_ops returned %d\n", ret);
+      return HGFS_ERR;
+   }
+
+   DEBUG(VM_DEBUG_DONE, "HgfsMakeVnodeOps: sip->vnodeOps=%p\n", sip->vnodeOps);
+
+   return 0;
+}
+#endif
+
+
+/*
+ * Local utility functions.
+ */
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsSubmitRequest --
+ *
+ *    Places a request on the queue for submission to guestd, then waits for
+ *    the response.
+ *
+ *    Both submitting request and waiting for reply are in this function
+ *    because the signaling of the request list's condition variable and
+ *    waiting on the request's condition variable must be atomic.
+ *
+ * Results:
+ *    Returns zero on success, and an appropriate error code on error.
+ *    Note: EINTR is returned if cv_wait_sig() is interrupted.
+ *
+ * Side effects:
+ *    The request list's condition variable is signaled.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+HgfsSubmitRequest(HgfsSuperInfo *sip,   // IN: Superinfo containing request list,
+                                        //     condition variable, and mutex
+                  HgfsReq *req)         // IN: Request to submit
+{
+   ASSERT(sip);
+   ASSERT(req);
+
+   /* The device must be open to submit requests */
+   if (!sip->devOpen) {
+      /*
+       * Destroy the request here to make things simpler for callers: they
+       * only need to destroy the request if they get a reply.
+       */
+      HgfsReqSetState(req, HGFS_REQ_ERROR);
+      HgfsDestroyReq(sip, req);
+      return ENODEV;
+   }
+
+   /*
+    * The process of submitting the request involves putting it on the request
+    * list, waking up guestd if it is waiting for a request, then atomically
+    * waiting for the reply.  We must loop on cv_wait_sig(9F) because Solaris
+    * says it may return prematurely. We must signify that we have abandoned
+    * the request if we are interrupted.
+    */
+
+   mutex_enter(&sip->reqMutex);
+
+   HgfsEnqueueRequest(sip, req);
+
+   /*
+    * We unconditionally signal the request list's condition variable because
+    * if guestd is waiting then we want to wake it up and if guestd isn't
+    * waiting then this has no effect.
+    *
+    * We also call pollwakeup to let callers of poll(2) on the device know
+    * there is now something to read.  XXX: This is bad because a caller of
+    * poll(2) could end up blocked in read(2) if operations are interleaved
+    * just so.  For now we only allow the device to be opened once to prevent
+    * this.
+    */
+   cv_signal(&sip->reqCondVar);
+   /*
+    * XXX: This will wake any process waiting for a POLLRDNORM event on our
+    * device.  We should probably change this so HgfsDevChpoll() tells us what
+    * event to signal since it knows what guestd is waiting for.  This would
+    * prevent having to change this macro should guestd or the poll()
+    * implementation ever change.  It seems like that would be a bit messy
+    * though, so we've left this as is.
+    *
+    * We release and reacquire the request mutex around the call to
+    * pollwakeup() since HgfsDevChpoll() also acquires it, and that's not
+    * allowed (see chpoll(9E) man page).  This is completely safe since nothing
+    * bad can happen to the request by allowing other code to run; we release
+    * this same lock in the loop below when we call cv_wait_sig().
+    */
+   mutex_exit(&sip->reqMutex);
+   pollwakeup(&sip->hgfsPollhead, POLLRDNORM);
+   mutex_enter(&sip->reqMutex);
+
+
+   while (HgfsReqGetState(req) == HGFS_REQ_SUBMITTED) {
+      k_sigset_t oldIgnoreSet;
+
+      //DEBUG(VM_DEBUG_SIG, "HgfsSubmitRequest: currproc is %s.\n", u.u_comm);
+
+      HgfsDisableSignals(&oldIgnoreSet);
+
+      if (cv_wait_sig(&req->condVar, &sip->reqMutex) == 0) {
+         /*
+          * We received a system signal (e.g., SIGKILL) while waiting for the
+          * reply from guestd.
+          *
+          * Since we gave up the mutex while waiting on the condition
+          * variable, we must make sure the reply didn't come /after/ we were
+          * signaled but /before/ we reacquired the mutex.  We do this by
+          * checking the state to make sure it is still SUBMITTED.  (Note that
+          * this case should be quite rare, but is possible.)
+          *
+          * If the reply has come, we ignore it (since we were interrupted) and
+          * clean up the request.  Otherwise we set the state to ABANDONED so
+          * the device half knows we are no longer waiting for the reply and it
+          * can clean up for us.
+          */
+         HgfsRestoreSignals(&oldIgnoreSet);
+
+         DEBUG(VM_DEBUG_SIG, "HgfsSubmitRequest(): interrupted while waiting for reply.\n");
+
+         if (HgfsReqGetState(req) != HGFS_REQ_SUBMITTED) {
+            /* It it's not SUBMITTED, it must be COMPLETED or ERROR */
+            ASSERT((HgfsReqGetState(req) == HGFS_REQ_COMPLETED) ||
+                     (HgfsReqGetState(req) == HGFS_REQ_ERROR));
+
+            DEBUG(VM_DEBUG_REQUEST, "HgfsSubmitRequest(): destroying request.\n");
+            HgfsDestroyReq(sip, req);
+         } else {
+            DEBUG(VM_DEBUG_REQUEST, "HgfsSubmitRequest(): setting request state to abandoned.\n");
+            HgfsReqSetState(req, HGFS_REQ_ABANDONED);
+         }
+
+         mutex_exit(&sip->reqMutex);
+         return EINTR;
+      }
+
+      HgfsRestoreSignals(&oldIgnoreSet);
+   }
+
+   /* The reply should now be in req->packet. */
+   DEBUG(VM_DEBUG_SIG, "HgfsSubmitRequest(): awoken because reply received.\n");
+
+   mutex_exit(&sip->reqMutex);
+
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsValidateReply --
+ *
+ *    Validates a reply to ensure that its state is set appropriately and the
+ *    reply is at least the minimum expected size and not greater than the
+ *    maximum allowed packet size.
+ *
+ * Results:
+ *    Returns zero on success, and a non-zero on error.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+HgfsValidateReply(HgfsReq *req,         // IN: Request that contains reply data
+                  uint32_t minSize)     // IN: Minimum size expected for the reply
+{
+   ASSERT(req);
+   ASSERT(minSize <= HGFS_PACKET_MAX);  /* we want to know if this fails */
+
+   switch (HgfsReqGetState(req)) {
+   case HGFS_REQ_ERROR:
+      DEBUG(VM_DEBUG_FAIL, "HgfsValidateReply(): received reply with error.\n");
+      return -1;
+
+   case HGFS_REQ_COMPLETED:
+      if ((req->packetSize < minSize) || (req->packetSize > HGFS_PACKET_MAX)) {
+         DEBUG(VM_DEBUG_FAIL, "HgfsValidateReply(): successfully "
+               "completed reply is too small/big: !(%d < %d < %d).\n",
+               minSize, req->packetSize, HGFS_PACKET_MAX);
+         return -1;
+      } else {
+         return 0;
+      }
+   /*
+    * If we get here then there is a programming error in this module:
+    *  HGFS_REQ_UNUSED should be for requests in the free list
+    *  HGFS_REQ_SUBMITTED should be for requests only that are awaiting
+    *                     a response
+    *  HGFS_REQ_ABANDONED should have returned an error to the client
+    */
+   default:
+      NOT_REACHED();
+      return -1;        /* avoid compiler warning */
+   }
+}
+
+
+/*
+ * XXX
+ * These were taken and slightly modified from hgfs/driver/linux/driver.c.
+ * Should we move them into a hgfs/driver/posix/driver.c?
+ */
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * HgfsGetOpenMode --
+ *
+ *    Based on the flags requested by the process making the open()
+ *    syscall, determine which open mode (access type) to request from
+ *    the server.
+ *
+ * Results:
+ *    Returns the correct HgfsOpenMode enumeration to send to the
+ *    server, or -1 on failure.
+ *
+ * Side effects:
+ *    None
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+HgfsGetOpenMode(uint32 flags) // IN: Open flags
+{
+#ifdef sun
+   /*
+    * Sun uses different values in the kernel.  These are defined in
+    * <sys/file.h>.
+    */
+   #undef O_RDONLY
+   #undef O_WRONLY
+   #undef O_RDWR
+
+   #define O_RDONLY     FREAD
+   #define O_WRONLY     FWRITE
+   #define O_RDWR       (FREAD | FWRITE)
+#endif
+
+   uint32 mask = O_RDONLY|O_WRONLY|O_RDWR;
+   int result = -1;
+
+#ifndef sun
+   LOG(4, (KERN_DEBUG "VMware hgfs: HgfsGetOpenMode: entered\n"));
+#else
+   DEBUG(VM_DEBUG_LOG, "HgfsGetOpenMode: entered\n");
+#endif
+
+   /*
+    * Mask the flags to only look at the access type.
+    */
+   flags &= mask;
+
+   /* Pick the correct HgfsOpenMode. */
+   switch (flags) {
+
+   case O_RDONLY:
+      DEBUG(VM_DEBUG_COMM, "HgfsGetOpenMode: O_RDONLY\n");
+      result = HGFS_OPEN_MODE_READ_ONLY;
+      break;
+
+   case O_WRONLY:
+      DEBUG(VM_DEBUG_COMM, "HgfsGetOpenMode: O_WRONLY\n");
+      result = HGFS_OPEN_MODE_WRITE_ONLY;
+      break;
+
+   case O_RDWR:
+      DEBUG(VM_DEBUG_COMM, "HgfsGetOpenMode: O_RDWR\n");
+      result = HGFS_OPEN_MODE_READ_WRITE;
+      break;
+
+   default:
+      /* This should never happen. */
+      NOT_REACHED();
+#ifndef sun
+      LOG(4, (KERN_DEBUG "VMware hgfs: HgfsGetOpenMode: invalid open flags %o\n",
+             flags));
+#else
+      DEBUG(VM_DEBUG_LOG, "HgfsGetOpenMode: invalid open flags %o\n", flags);
+#endif
+      result = -1;
+      break;
+   }
+
+   return result;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * HgfsGetOpenFlags --
+ *
+ *    Based on the flags requested by the process making the open()
+ *    syscall, determine which flags to send to the server to open the
+ *    file.
+ *
+ * Results:
+ *    Returns the correct HgfsOpenFlags enumeration to send to the
+ *    server, or -1 on failure.
+ *
+ * Side effects:
+ *    None
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+HgfsGetOpenFlags(uint32 flags) // IN: Open flags
+{
+#ifdef sun
+   /*
+    * Sun uses different values inside the kernel.  These are defined in
+    * <sys/file.h>.
+    */
+   #undef O_CREAT       // Must undef b/c included <sys/fs_subr.h>
+   #undef O_TRUNC
+   #undef O_EXCL
+
+   #define O_CREAT      FCREAT
+   #define O_TRUNC      FTRUNC
+   #define O_EXCL       FEXCL
+#endif
+
+   uint32 mask = O_CREAT | O_TRUNC | O_EXCL;
+   int result = -1;
+
+#ifndef sun
+   LOG(4, (KERN_DEBUG "VMware hgfs: HgfsGetOpenFlags: entered\n"));
+#else
+   DEBUG(VM_DEBUG_INFO, "HgfsGetOpenFlags: entered\n");
+#endif
+
+   /*
+    * Mask the flags to only look at O_CREAT, O_EXCL, and O_TRUNC.
+    */
+
+   flags &= mask;
+
+   /* O_EXCL has no meaning if O_CREAT is not set. */
+   if (!(flags & O_CREAT)) {
+      flags &= ~O_EXCL;
+   }
+
+   /* Pick the right HgfsOpenFlags. */
+   switch (flags) {
+
+   case 0:
+      /* Regular open; fails if file nonexistant. */
+      DEBUG(VM_DEBUG_COMM, "HgfsGetOpenFlags: 0\n");
+      result = HGFS_OPEN;
+      break;
+
+   case O_CREAT:
+      /* Create file; if it exists already just open it. */
+      DEBUG(VM_DEBUG_COMM, "HgfsGetOpenFlags: O_CREAT\n");
+      result = HGFS_OPEN_CREATE;
+      break;
+
+   case O_TRUNC:
+      /* Truncate existing file; fails if nonexistant. */
+      DEBUG(VM_DEBUG_COMM, "HgfsGetOpenFlags: O_TRUNC\n");
+      result = HGFS_OPEN_EMPTY;
+      break;
+
+   case (O_CREAT | O_EXCL):
+      /* Create file; fail if it exists already. */
+      DEBUG(VM_DEBUG_COMM, "HgfsGetOpenFlags: O_CREAT | O_EXCL\n");
+      result = HGFS_OPEN_CREATE_SAFE;
+      break;
+
+   case (O_CREAT | O_TRUNC):
+      /* Create file; if it exists already, truncate it. */
+      DEBUG(VM_DEBUG_COMM, "HgfsGetOpenFlags: O_CREAT | O_TRUNC\n");
+      result = HGFS_OPEN_CREATE_EMPTY;
+      break;
+
+   default:
+      /*
+       * This can only happen if all three flags are set, which
+       * conceptually makes no sense because O_EXCL and O_TRUNC are
+       * mutually exclusive if O_CREAT is set.
+       *
+       * However, the open(2) man page doesn't say you can't set all
+       * three flags, and certain apps (*cough* Nautilus *cough*) do
+       * so. To be friendly to those apps, we just silenty drop the
+       * O_TRUNC flag on the assumption that it's safer to honor
+       * O_EXCL.
+       */
+#ifndef sun
+      LOG(4, (KERN_DEBUG "VMware hgfs: HgfsGetOpenFlags: invalid open "
+              "flags %o. Ignoring the O_TRUNC flag.\n", flags));
+#else
+      DEBUG(VM_DEBUG_INFO, "HgfsGetOpenFlags: invalid open flags %o.  "
+            "Ignoring the O_TRUNC flag.\n", flags);
+#endif
+      result = HGFS_OPEN_CREATE_SAFE;
+      break;
+   }
+
+   return result;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsAttrToSolaris --
+ *
+ *    Maps Hgfs attributes to Solaris attributes, filling the provided Solaris
+ *    attribute structure appropriately.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+HgfsAttrToSolaris(struct vnode *vp,             // IN:  The vnode for this file
+                  const HgfsAttr *hgfsAttr,     // IN:  Hgfs attributes to copy from
+                  struct vattr *solAttr)        // OUT: Solaris attributes to fill
+{
+   ASSERT(vp);
+   ASSERT(hgfsAttr);
+   ASSERT(solAttr);
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsAttrToSolaris: %p -> %p", hgfsAttr, solAttr);
+
+   /*
+    * We only fill in those fields that va_mask tells us to.
+    */
+
+   if (solAttr->va_mask & AT_TYPE) {
+      /* Set the file type. */
+      switch (hgfsAttr->type) {
+      case HGFS_FILE_TYPE_REGULAR:
+         solAttr->va_type = VREG;
+         DEBUG(VM_DEBUG_ATTR, " Type: VREG\n");
+         break;
+
+      case HGFS_FILE_TYPE_DIRECTORY:
+         solAttr->va_type = VDIR;
+         DEBUG(VM_DEBUG_ATTR, " Type: VDIR\n");
+         break;
+
+      default:
+         /*
+          * There are only the above two filetypes.  If there is an error
+          * elsewhere that provides another value, we set the Solaris type to
+          * none and ASSERT in devel builds.
+          */
+         solAttr->va_type = VNON;
+         DEBUG(VM_DEBUG_FAIL, "HgfsAttrToSolaris: invalid HgfsFileType provided.\n");
+         ASSERT(0);
+      }
+   }
+
+   if (solAttr->va_mask & AT_MODE) {
+      /* We only have permissions for owners. */
+      solAttr->va_mode = (hgfsAttr->permissions << HGFS_ATTR_MODE_SHIFT);
+      DEBUG(VM_DEBUG_ATTR, " Owner's permissions: %o\n",
+            solAttr->va_mode >> HGFS_ATTR_MODE_SHIFT);
+   }
+
+   if (solAttr->va_mask & AT_UID) {
+      DEBUG(VM_DEBUG_ATTR, " Setting uid\n");
+      solAttr->va_uid = 0;                 /* XXX root? */
+   }
+
+   if (solAttr->va_mask & AT_GID) {
+      DEBUG(VM_DEBUG_ATTR, " Setting gid\n");
+      solAttr->va_gid = 0;                 /* XXX root? */
+   }
+
+   if (solAttr->va_mask & AT_FSID) {
+      DEBUG(VM_DEBUG_ATTR, " Setting fsid\n");
+      solAttr->va_fsid = vp->v_vfsp->vfs_dev;
+   }
+
+   if (solAttr->va_mask & AT_NODEID) {
+      /* Get the node id calculated for this file in HgfsVnodeGet() */
+      solAttr->va_nodeid = HGFS_VP_TO_NODEID(vp);
+      DEBUG(VM_DEBUG_ATTR, "*HgfsAttrToSolaris: fileName %s\n",
+            HGFS_VP_TO_FILENAME(vp));
+      DEBUG(VM_DEBUG_ATTR, " Node ID: %llu\n", solAttr->va_nodeid);
+   }
+
+   if (solAttr->va_mask & AT_NLINK) {
+      DEBUG(VM_DEBUG_ATTR, " Setting nlink\n");
+      solAttr->va_nlink = 1;               /* fake */
+   }
+
+   if (solAttr->va_mask & AT_SIZE) {
+      DEBUG(VM_DEBUG_ATTR, " Setting size\n");
+      solAttr->va_size = hgfsAttr->size;
+   }
+
+   if (solAttr->va_mask & AT_ATIME) {
+      DEBUG(VM_DEBUG_ATTR, " Setting atime\n");
+      HGFS_SET_TIME(solAttr->va_atime, hgfsAttr->accessTime);
+   }
+
+   if (solAttr->va_mask & AT_MTIME) {
+      DEBUG(VM_DEBUG_ATTR, " Setting mtime\n");
+      HGFS_SET_TIME(solAttr->va_mtime, hgfsAttr->writeTime);
+   }
+
+   if (solAttr->va_mask & AT_CTIME) {
+      DEBUG(VM_DEBUG_ATTR, " Setting ctime\n");
+      /* Since Windows doesn't keep ctime, we may need to use mtime instead. */
+      if (HGFS_SET_TIME(solAttr->va_ctime, hgfsAttr->attrChangeTime)) {
+         solAttr->va_ctime = solAttr->va_mtime;
+      }
+   }
+
+   if (solAttr->va_mask & AT_RDEV) {
+      DEBUG(VM_DEBUG_ATTR, " Setting rdev\n");
+      /* Since Windows doesn't keep ctime, we may need to use mtime instead. */
+      solAttr->va_rdev = 0;                /* devices aren't allowed in Hgfs */
+   }
+
+   if (solAttr->va_mask & AT_BLKSIZE) {
+      DEBUG(VM_DEBUG_ATTR, " Setting blksize\n");
+      /* Since Windows doesn't keep ctime, we may need to use mtime instead. */
+      solAttr->va_blksize = HGFS_BLOCKSIZE;
+   }
+
+   if (solAttr->va_mask & AT_NBLOCKS) {
+      DEBUG(VM_DEBUG_ATTR, " Setting nblocks\n");
+      solAttr->va_nblocks = (solAttr->va_size / HGFS_BLOCKSIZE) + 1;
+   }
+
+#if HGFS_VFS_VERSION == 2
+   if (solAttr->va_mask & AT_VCODE) {
+      DEBUG(VM_DEBUG_ATTR, " Setting vcode\n");
+      solAttr->va_vcode = 0;               /* fake */
+   }
+#else
+   if (solAttr->va_mask & AT_SEQ) {
+      DEBUG(VM_DEBUG_ATTR, " Setting seq\n");
+      solAttr->va_seq = 0;                /* fake */
+   }
+#endif
+
+   HgfsDebugPrintVattr(solAttr);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsSetattrCopy --
+ *
+ *    Sets the Hgfs attributes that need to be modified based on the provided
+ *    Solaris attribute structure.
+ *
+ * Results:
+ *    Returns TRUE if changes need to be made, FALSE otherwise.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+HgfsSetattrCopy(struct vattr *solAttr,          // IN:  Attributes to change to
+                int flags,                      // IN:  Context of HgfsSetattr call
+                HgfsAttr *hgfsAttr,             // OUT: Hgfs attributes to fill in
+                HgfsAttrChanges *update)        // OUT: Hgfs attribute changes to make
+{
+   uint32_t mask;
+   Bool ret = FALSE;
+
+   ASSERT(solAttr);
+   ASSERT(hgfsAttr);
+   ASSERT(update);
+
+   memset(hgfsAttr, 0, sizeof *hgfsAttr);
+   memset(update, 0, sizeof *update);
+
+   /* This is the mask of attributes to change. */
+   mask = solAttr->va_mask;
+
+   /*
+    * Hgfs supports changing these attributes:
+    * o mode bits (permissions)
+    * o size
+    * o access/write times
+    */
+
+   if (mask & AT_MODE) {
+      DEBUG(VM_DEBUG_COMM, "HgfsSetattrCopy: updating permissions.\n");
+      *update |= HGFS_ATTR_PERMISSIONS;
+      hgfsAttr->permissions = (solAttr->va_mode & S_IRWXU) >> HGFS_ATTR_MODE_SHIFT;
+      ret = TRUE;
+   }
+
+   if (mask & AT_SIZE) {
+      DEBUG(VM_DEBUG_COMM, "HgfsSetattrCopy: updating size.\n");
+      *update |= HGFS_ATTR_SIZE;
+      hgfsAttr->size = solAttr->va_size;
+      ret = TRUE;
+   }
+
+   if (mask & AT_ATIME) {
+      DEBUG(VM_DEBUG_COMM, "HgfsSetattrCopy: updating access time.\n");
+      *update |= HGFS_ATTR_ACCESS_TIME |
+                 ((flags & ATTR_UTIME) ? HGFS_ATTR_ACCESS_TIME_SET : 0);
+      hgfsAttr->accessTime = HGFS_GET_TIME(solAttr->va_atime);
+      ret = TRUE;
+   }
+
+   if (mask & AT_MTIME) {
+      DEBUG(VM_DEBUG_COMM, "HgfsSetattrCopy: updating write time.\n");
+      *update |= HGFS_ATTR_WRITE_TIME |
+                 ((flags & ATTR_UTIME) ? HGFS_ATTR_WRITE_TIME_SET : 0);
+      hgfsAttr->writeTime = HGFS_GET_TIME(solAttr->va_mtime);
+      ret = TRUE;
+   }
+
+   return ret;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsMakeFullName --
+ *
+ *    Concatenates the path and filename to construct the full path.  This
+ *    handles the special cases of . and .. filenames so the Hgfs server
+ *    doesn't return an error.
+ *
+ * Results:
+ *    Returns the length of the full path on success, and a negative value on
+ *    error.  The full pathname is placed in outBuf.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+HgfsMakeFullName(const char *path,      // IN:  Path of directory containing file
+                 uint32_t pathLen,      // IN:  Length of path
+                 const char *file,      // IN:  Name of file
+                 char *outBuf,          // OUT: Location to write full path
+                 ssize_t bufSize)       // IN:  Size of the out buffer
+{
+
+   ASSERT(path);
+   ASSERT(file);
+   ASSERT(outBuf);
+
+
+   DEBUG(VM_DEBUG_INFO, "HgfsMakeFullName:\n"
+         " path: \"%s\" (%d)\n"
+         " file: \"%s\" (%ld)\n",
+         path, pathLen, file, strlen(file));
+
+   /*
+    * Here there are three possibilities:
+    *  o file is ".", in which case we just place path in outBuf
+    *  o file is "..", in which case we strip the last component from path and
+    *    put that in outBuf
+    *  o for all other cases, we concatenate path, a path separator, file, and
+    *    a NUL terminator and place it in outBuf
+    */
+
+   /* Make sure that the path and a NUL terminator will fit. */
+   if (bufSize < pathLen + 1) {
+      return HGFS_ERR_INVAL;
+   }
+
+
+   /* Copy path for this file into the caller's buffer. */
+   memset(outBuf, 0, bufSize);
+   memcpy(outBuf, path, pathLen);
+
+   /* Handle three cases. */
+   if (strcmp(file, ".") == 0) {
+      /* NUL terminate and return provided length. */
+      outBuf[pathLen] = '\0';
+      return pathLen;
+
+   } else if (strcmp(file, "..") == 0) {
+      /*
+       * Replace the last path separator with a NUL terminator, then return the
+       * size of the buffer.
+       */
+      char *newEnd = strrchr(outBuf, '/');
+      if (!newEnd) {
+         /*
+          * We should never get here since we name the root vnode "/" in
+          * HgfsMount().
+          */
+         return HGFS_ERR_INVAL;
+      }
+
+      *newEnd = '\0';
+      return ((uintptr_t)newEnd - (uintptr_t)outBuf);
+
+   } else {
+
+      /*
+       * The full path consists of path, the path separator, file, plus a NUL
+       * terminator.  Make sure it will all fit.
+       */
+      int fileLen = strlen(file);
+      if (bufSize < pathLen + 1 + fileLen + 1) {
+         return HGFS_ERR_INVAL;
+      }
+
+      /*
+       * The CPName_ConvertTo function handles multiple path separators
+       * at the beginning of the filename, so we skip the checks to limit
+       * them to one.  This also enables clobbering newEnd above to work
+       * properly on base shares (named "//sharename") that need to turn into
+       * "/".
+       */
+      outBuf[pathLen] = '/';
+
+      /* Now append the filename and NUL terminator. */
+      memcpy(outBuf + pathLen + 1, file, fileLen);
+      outBuf[pathLen + 1 + fileLen] = '\0';
+
+      return pathLen + 1 + fileLen;
+   }
+}
+
+
+/*
+ * Process signal mask manipulation
+ */
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsDisableSignals --
+ *
+ *    Disables signals of current thread by calling sigintr().
+ *
+ * Results:
+ *    Returns the old set of signals this process ignores.
+ *
+ * Side effects:
+ *    This process is now only delivered SIGKILL sinals.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+INLINE static void
+HgfsDisableSignals(k_sigset_t *oldIgnoreSet)    // OUT: Current thread's ignore set
+{
+   ASSERT(oldIgnoreSet);
+
+   /*
+    * Passing sigintr() a 1 ensures that SIGINT will not be blocked.
+    */
+   sigintr(oldIgnoreSet, 1);
+
+   /*
+    * Note that the following alone works for Netscape ...
+    * sigaddset(&curthread->t_hold, SIGALRM);
+    */
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * HgfsRestoreSignals --
+ *
+ *    Restores the current process' set of signals to ignore to the provided
+ *    signal set.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    The process will now be delivered signals as dictated by the oldSigSet.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+INLINE static void
+HgfsRestoreSignals(k_sigset_t *oldIgnoreSet)
+{
+   ASSERT(oldIgnoreSet);
+
+   /*
+    * sigunintr() will replace the current thread's blocked signals with the
+    * provided signal set.
+    */
+   sigunintr(oldIgnoreSet);
+
+   /*
+    * Note that the following alone works for Netscape ...
+    * sigdelset(&curthread->t_hold, SIGALRM);
+    */
+}
+
+
+/*
+ * This is a less-tested, alternate implementation of HgfsReaddir().  The
+ * difference is that this one copies each entry individually so it doesn't
+ * have to a malloc() a buffer of size readSize (see the XXX comment in the
+ * HgfsReaddir() implementation above).  The thinking is that this approach is
+ * likely safer, but has the potential to be slower.  Initial tests show that
+ * this implementation "feels" the same speed as the other one.
+ */
+#if 0
+static int
+HgfsReaddir(struct vnode *vp,   // IN: Vnode of directory to read
+            struct uio *uiop,   // IN: User's read request
+            struct cred *cr,    // IN: Credentials of caller
+            int *eofp)          // OUT: Indicates we are done
+{
+   HgfsSuperInfo *sip;
+   HgfsHandle handle;
+   struct dirent64 *dirp;
+   char buf[sizeof *dirp + MAXNAMELEN];
+   ssize_t readSize;
+   uint64_t offset;
+   Bool done;
+   int ret;
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsReaddir().\n");
+
+   if (!vp || !uiop || !cr || !eofp) {
+      cmn_err(HGFS_ERROR, "HgfsReaddir: NULL input from Kernel.\n");
+      return EINVAL;
+   }
+
+   DEBUG(VM_DEBUG_ENTRY, "HgfsReaddir: uiop->uio_resid=%d, uiop->uio_loffset=%d\n",
+         uiop->uio_resid, uiop->uio_loffset);
+
+
+   /*
+    * XXX: If would be nice if we could perform some sort of sanity check on
+    * the handle here.  Perhaps make sure handle <= NUM_SEARCHES in
+    * hgfsServer.c since the handle is the index number in searchArray.
+    */
+   if ( !HGFS_KNOW_FILENAME(vp) ) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsReaddir: we don't know the filename.\n");
+      return EBADF;
+   }
+
+   sip = HgfsGetSuperInfo();
+   if (!sip) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsReaddir: we can't get the superinfo.\n");
+      return EIO;
+   }
+
+   /*
+    * In order to fill the user's buffer with directory entries, we must
+    * iterate on HGFS_OP_SEARCH_READ requests until either the user's buffer is
+    * full or there are no more entries.  Each call to HgfsGetNextDirEntry()
+    * fills in the name and attribute structure for the next entry.  We then
+    * escape the name, create the directory entry in our temporary buf, and
+    * copy the entry to the user's buffer.
+    */
+
+   readSize = uiop->uio_resid;
+   dirp = (struct dirent64 *)buf;
+
+   /*
+    * We need to get the handle for this open directory to send to the Hgfs
+    * server in our requests.
+    */
+   ret = HgfsGetOpenFileHandle(vp, &handle);
+   if (ret) {
+      DEBUG(VM_DEBUG_FAIL, "HgfsReaddir: could not get handle.\n");
+      return EINVAL;
+   }
+
+   /*
+    * Loop until one of the following conditions is met:
+    *  o An error occurs while reading a directory entry
+    *  o There are no more directory entries to read
+    *  o The buffer is full and cannot hold the next entry
+    *
+    * We request dentries from the Hgfs server based on their index in the
+    * directory.  The offset value is initialized to the value specified in
+    * the user's io request and is incremented each time through the loop.
+    *
+    * We decrement readSize by the size of the directory entry each time we
+    * successfully copy one into the user's buffer.
+    */
+   for (offset = uiop->uio_loffset, done = 0; /* Nothing */ ; offset++) {
+      char nameBuf[MAXNAMELEN + 1];
+      char escName[MAXNAMELEN + 1];
+      char fullName[MAXPATHLEN + 1];
+
+      DEBUG(VM_DEBUG_COMM,
+            "HgfsReaddir: getting directory entry at offset %d.\n", offset);
+
+      memset(nameBuf, 0, sizeof nameBuf);
+      memset(buf, 0, sizeof buf);
+
+      ret = HgfsGetNextDirEntry(sip, handle, offset, nameBuf, &done);
+      /* If the filename was too long, we skip to the next entry ... */
+      if (ret == EOVERFLOW) {
+         continue;
+      /* ... but if another error occurred, we return that error code ... */
+      } else if (ret) {
+         DEBUG(VM_DEBUG_FAIL, "HgfsReaddir: failure occurred in HgfsGetNextDirEntry\n");
+         goto out;
+      /*
+       * ... and if there are no more entries, we set the end of file pointer
+       * and break out of the loop.
+       */
+      } else if (done == TRUE) {
+         DEBUG(VM_DEBUG_COMM, "HgfsReaddir: Done reading directory entries.\n");
+         *eofp = TRUE;
+         break;
+      }
+
+      /*
+       * We now have the directory entry, so we sanitize the name and try to
+       * put it in our buffer.
+       */
+      DEBUG(VM_DEBUG_COMM, "HgfsReaddir: received filename \"%s\"\n", nameBuf);
+
+      memset(escName, 0, sizeof escName);
+
+      ret = HgfsEscape_Do(nameBuf, strlen(nameBuf), MAXNAMELEN, escName);
+      /* If the escaped name didn't fit in the buffer, skip to the next entry. */
+      if (ret < 0 || ret > MAXNAMELEN) {
+         DEBUG(VM_DEBUG_FAIL, "HgfsReaddir: HgfsEscape_Do failed.\n");
+         continue;
+      }
+
+      /*
+       * Make sure there is enough room in the buffer for the entire directory
+       * entry.  If not, we just break out of the loop and copy what we have.
+       */
+      if (DIRENT64_RECLEN(ret) > readSize) {
+         DEBUG(VM_DEBUG_INFO, "HgfsReaddir: ran out of room in the buffer.\n");
+         break;
+      }
+
+      /* Fill in the directory entry. */
+      dirp->d_reclen = DIRENT64_RECLEN(ret);
+      dirp->d_off = offset;
+      memcpy(dirp->d_name, escName, ret);
+      dirp->d_name[ret] = '\0';
+
+      ret = HgfsMakeFullName(HGFS_VP_TO_FILENAME(vp),           // Directorie's name
+                             HGFS_VP_TO_FILENAME_LENGTH(vp),    // Length
+                             dirp->d_name,                      // Name of file
+                             fullName,                          // Destination buffer
+                             sizeof fullName);                  // Size of this buffer
+      /* Skip this entry if the full path was too long. */
+      if (ret < 0) {
+         continue;
+      }
+
+      /*
+       * Place the node id, which serves the purpose of inode number, for this
+       * filename directory entry.  As long as we are using a dirent64, this is
+       * okay since ino_t is also a u_longlong_t.
+       */
+      HgfsNodeIdGet(&sip->fileHashTable, fullName, (uint32_t)ret,
+                    (u_longlong_t *)&dirp->d_ino);
+
+      /*
+       * Now that we've filled our buffer with as many dentries as fit, we copy it
+       * into the user's buffer.
+       */
+      ret = uiomove(dirp,               // Source buffer
+                    dirp->d_reclen,     // Size of this buffer
+                    UIO_READ,           // Read flag
+                    uiop);              // User's request struct
+
+      /* Break the loop if we can't copy this dentry into the user's buffer. */
+      if (ret) {
+         goto out;
+      }
+
+      /* Decrement the number of bytes copied on success */
+      readSize -= dirp->d_reclen;
+   }
+
+   /* Return success */
+   ret = 0;
+
+out:
+   /*
+    * uiomove(9F) will have incremented the uio offset by the number of bytes
+    * written.  We reset it here to the fs-specific offset in our directory so
+    * the next time we are called it is correct.  (Note, this does not break
+    * anything and /is/ how this field is intended to be used.)
+    */
+   uiop->uio_loffset = offset;  // XXX ok to do this on error too?
+
+   DEBUG(VM_DEBUG_DONE, "HgfsReaddir: done (ret=%d, *eofp=%d).\n", ret, *eofp);
+   DEBUG(VM_DEBUG_ENTRY, "HgfsReaddir: exiting.\n");
+   return ret;
+}
+#endif
diff --git a/open-vm-tools/modules/solaris/vmhgfs/vnode.h b/open-vm-tools/modules/solaris/vmhgfs/vnode.h
new file mode 100644 (file)
index 0000000..3ea5519
--- /dev/null
@@ -0,0 +1,31 @@
+/*********************************************************
+ * Copyright (C) 2004 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+/*
+ * vnode.h --
+ *
+ * Functions exported by vnode.c
+ */
+
+#ifndef __VNODE_H_
+#define __VNODE_H_
+
+#include "hgfsSolaris.h"
+
+int HgfsSetVnodeOps(HgfsSuperInfo *sip, struct vnode *vp);
+inline HgfsSuperInfo *HgfsGetSuperInfo(void);
+
+#endif
diff --git a/open-vm-tools/modules/solaris/vmhgfs/x86cpuid.h b/open-vm-tools/modules/solaris/vmhgfs/x86cpuid.h
new file mode 100644 (file)
index 0000000..eae114d
--- /dev/null
@@ -0,0 +1,968 @@
+/*********************************************************
+ * Copyright (C) 1998-2008 VMware, Inc. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of the Common
+ * Development and Distribution License (the "License") version 1.0
+ * and no later version.  You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ *         http://www.opensource.org/licenses/cddl1.php
+ *
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ *********************************************************/
+
+#ifndef _X86CPUID_H_
+#define _X86CPUID_H_
+
+/* http://www.sandpile.org/ia32/cpuid.htm */
+
+#define INCLUDE_ALLOW_USERLEVEL
+#define INCLUDE_ALLOW_VMX
+#define INCLUDE_ALLOW_VMMEXT
+#define INCLUDE_ALLOW_VMKERNEL
+#define INCLUDE_ALLOW_MODULE
+#define INCLUDE_ALLOW_VMNIXMOD
+#define INCLUDE_ALLOW_DISTRIBUTE
+#define INCLUDE_ALLOW_VMK_MODULE
+#define INCLUDE_ALLOW_VMCORE
+#define INCLUDE_ALLOW_VMMON
+#include "includeCheck.h"
+
+#include "vm_basic_types.h"
+
+/*
+ * The linux kernel's ptrace.h stupidly defines the bare
+ * EAX/EBX/ECX/EDX, which wrecks havoc with our preprocessor tricks.
+ */
+#undef EAX
+#undef EBX
+#undef ECX
+#undef EDX
+
+typedef struct CPUIDRegs {
+   uint32 eax, ebx, ecx, edx;
+} CPUIDRegs;
+
+typedef union CPUIDRegsUnion {
+   uint32 array[4];
+   CPUIDRegs regs;
+} CPUIDRegsUnion;
+
+/*
+ * Results of calling cpuid(eax, ecx) on all host logical CPU.
+ */
+#ifdef _MSC_VER
+#pragma warning (disable :4200) // non-std extension: zero-sized array in struct
+#endif
+
+typedef
+#include "vmware_pack_begin.h"
+struct CPUIDReply {
+   /*
+    * Unique host logical CPU identifier. It does not change across queries, so
+    * we use it to correlate the replies of multiple queries.
+    */
+   uint64 tag;                // OUT
+
+   CPUIDRegs regs;            // OUT
+}
+#include "vmware_pack_end.h"
+CPUIDReply;
+
+typedef
+#include "vmware_pack_begin.h"
+struct CPUIDQuery {
+   uint32 eax;                // IN
+   uint32 ecx;                // IN
+   uint32 numLogicalCPUs;     // IN/OUT
+   CPUIDReply logicalCPUs[0]; // OUT
+}
+#include "vmware_pack_end.h"
+CPUIDQuery;
+
+/*
+ * CPUID levels the monitor caches and ones that are not cached, but
+ * have fields defined below (short name and actual value).
+ * 
+ * The first parameter defines whether the level is masked/tested
+ * during power-on/migration.  Any level which is marked as FALSE here
+ * *must* have all field masks defined as IGNORE in CPUID_FIELD_DATA.
+ * A static assert in lib/cpuidcompat/cpuidcompat.c will check this.
+ *
+ * IMPORTANT: WHEN ADDING A NEW FIELD TO THE CACHED LEVELS, make sure
+ * you update vmcore/vmm/cpu/priv.c:Priv_CPUID() and vmcore/vmm64/bt/
+ * cpuid_shared.S (and geninfo) to include the new level.
+ */
+
+#define CPUID_CACHED_LEVELS                     \
+   CPUIDLEVEL(TRUE,  0,  0)                     \
+   CPUIDLEVEL(TRUE,  1,  1)                     \
+   CPUIDLEVEL(FALSE,400, 0x40000000)            \
+   CPUIDLEVEL(FALSE,410, 0x40000010)            \
+   CPUIDLEVEL(FALSE, 80, 0x80000000)            \
+   CPUIDLEVEL(TRUE,  81, 0x80000001)            \
+   CPUIDLEVEL(FALSE, 88, 0x80000008)            \
+   CPUIDLEVEL(TRUE,  8A, 0x8000000A)
+
+#define CPUID_UNCACHED_LEVELS                   \
+   CPUIDLEVEL(FALSE, 4, 4)                      \
+   CPUIDLEVEL(FALSE, 5, 5)                      \
+   CPUIDLEVEL(FALSE, 6, 6)                      \
+   CPUIDLEVEL(FALSE, A, 0xA)                    \
+   CPUIDLEVEL(FALSE, 86, 0x80000006)            \
+   CPUIDLEVEL(FALSE, 87, 0x80000007)            \
+
+#define CPUID_ALL_LEVELS                        \
+   CPUID_CACHED_LEVELS                          \
+   CPUID_UNCACHED_LEVELS
+
+/* Define cached CPUID levels in the form: CPUID_LEVEL_<ShortName> */
+typedef enum {
+#define CPUIDLEVEL(t, s, v) CPUID_LEVEL_##s,
+   CPUID_CACHED_LEVELS
+#undef CPUIDLEVEL
+   CPUID_NUM_LEVELS
+} CpuidLevels;
+
+/*
+ * CPUID result registers
+ */
+
+#define CPUID_REGS                              \
+   CPUIDREG(EAX, eax)                           \
+   CPUIDREG(EBX, ebx)                           \
+   CPUIDREG(ECX, ecx)                           \
+   CPUIDREG(EDX, edx)
+
+typedef enum {
+#define CPUIDREG(uc, lc) CPUID_REG_##uc,
+   CPUID_REGS
+#undef CPUIDREG
+   CPUID_NUM_REGS
+} CpuidRegs;
+
+/*
+ * CPU vendors
+ */
+
+typedef enum {
+   CPUID_VENDOR_UNKNOWN,
+   CPUID_VENDOR_COMMON,
+   CPUID_VENDOR_INTEL,
+   CPUID_VENDOR_AMD,
+   CPUID_VENDOR_CYRIX,
+   CPUID_VENDOR_VIA,
+   CPUID_NUM_VENDORS
+} CpuidVendors;
+
+#define CPUID_INTEL_VENDOR_STRING       "GenuntelineI"
+#define CPUID_AMD_VENDOR_STRING         "AuthcAMDenti"
+#define CPUID_CYRIX_VENDOR_STRING       "CyriteadxIns"
+#define CPUID_VIA_VENDOR_STRING         "CentaulsaurH"
+#define CPUID_HYPERV_HYPERVISOR_VENDOR_STRING  "Microsoft Hv"
+#define CPUID_INTEL_VENDOR_STRING_FIXED "GenuineIntel"
+#define CPUID_AMD_VENDOR_STRING_FIXED   "AuthenticAMD"
+#define CPUID_CYRIX_VENDOR_STRING_FIXED "CyrixInstead"
+#define CPUID_VIA_VENDOR_STRING_FIXED   "CentaurHauls"
+
+/*
+ * FIELDDEF can be defined to process the CPUID information provided
+ * in the following CPUID_FIELD_DATA macro.  The first parameter is
+ * the CPUID level of the feature (must be defined in CPUID_*_LEVELS.
+ * The second parameter is the register the field is contained in
+ * (defined in CPUID_REGS).  The third field is the vendor this
+ * feature applies to.  "COMMON" means all vendors apply.  UNKNOWN may
+ * not be used here.  The fourth and fifth parameters are the bit
+ * position of the field and the width, respectively.  The sixth is
+ * the text name of the field.
+ *
+ * The seventh and eighth parameters specify the default CPUID
+ * behavior for power-on, guest view, and migration tests (cpt/rsm &
+ * vmotion).  The eighth parameter is ignored for types other than
+ * MASK & TEST, and must be zero in this case.
+ *
+ * When adding a new field, be sure to consider its purpose.  The
+ * following list of types is provided in order of likely use.
+ *
+ * NOTE: this form of representation is separate from the masking
+ * system specified via the config file.  That is because this
+ * representation must take into account multi-bit fields.
+ *
+ * HOST    - Passthrough host value and cannot change during migration.
+ * MASK, 0 - Hide from the guest, because we don't support it or we
+ *           don't want the guest to know that it exists.
+ * IGNORE  - Ignore this field for all tests
+ *
+ *    (Think twice before using the below mask types/combinations)
+ *
+ * MASK, x - Force the guest to always see x, and don't compare for
+ *           migration -- only APIC as of today; it is controlled by
+ *           software and we know how to toggle it
+ * TEST, x - Require host CPUID field to be x for power-on
+ * RSVD    - Hidden from the guest, but compared during migration
+ *
+ *
+ * Table to explain mask type meanings:
+ *
+ *                         IGNR   MASK   TEST   HOST   RSVD
+ * --------------------------------------------------------
+ * Req'd val for power-on   -      -      x      -      -
+ * Value guest sees         *      x      *      *      0
+ * Checked on migration?    N      N      Y      Y      Y
+ *
+ * * - initial host's power-on CPUID value
+ *
+ * FIELDDEFA takes a ninth parameter, the name used when creating
+ * accessor functions in lib/public/cpuidInfoFuncs.h.
+ *
+ * FLAGDEF/FLAGDEFA is defined identically to fields, but their
+ * accessors are more appropriate for 1-bit flags.
+ */
+
+typedef enum {
+   CPUID_FIELD_MASK_IGNORE,
+   CPUID_FIELD_MASK_MASK,
+   CPUID_FIELD_MASK_TEST,
+   CPUID_FIELD_MASK_HOST,
+   CPUID_FIELD_MASK_RSVD,
+   CPUID_NUM_FIELD_MASKS
+} CpuidFieldMasks;
+
+
+typedef enum {
+   CPUID_FIELD_SUPPORTED_NO,
+   CPUID_FIELD_SUPPORTED_YES,
+   CPUID_FIELD_SUPPORTED_ANY,
+   CPUID_FIELD_SUPPORTED_NA,
+   CPUID_NUM_FIELD_SUPPORTEDS
+} CpuidFieldSupported;
+
+
+/*    LEVEL, REG, VENDOR, POS, SIZE, NAME,       MON SUPP, MASK TYPE, SET TO, CPL3, [FUNC] */
+#define CPUID_FIELD_DATA_LEVEL_0                                               \
+FIELDDEF(  0, EAX, COMMON,  0, 32, NUMLEVELS,           ANY, IGNORE, 0, FALSE)     \
+FIELDDEF(  0, EBX, COMMON,  0, 32, VENDOR1,             YES, HOST,   0, TRUE)      \
+FIELDDEF(  0, ECX, COMMON,  0, 32, VENDOR3,             YES, HOST,   0, TRUE)      \
+FIELDDEF(  0, EDX, COMMON,  0, 32, VENDOR2,             YES, HOST,   0, TRUE)
+                                                        
+/*    LEVEL, REG, VENDOR, POS, SIZE, NAME,       MON SUPP, MASK TYPE, SET TO, CPL3, [FUNC] */
+#define CPUID_FIELD_DATA_LEVEL_1                                               \
+FIELDDEFA( 1, EAX, COMMON,  0,  4, STEPPING,            ANY, IGNORE, 0, FALSE, STEPPING)  \
+FIELDDEFA( 1, EAX, COMMON,  4,  4, MODEL,               ANY, IGNORE, 0, FALSE, MODEL)     \
+FIELDDEFA( 1, EAX, COMMON,  8,  4, FAMILY,              YES, HOST,   0, FALSE, FAMILY)    \
+FIELDDEF(  1, EAX, COMMON, 12,  2, TYPE,                ANY, IGNORE, 0, FALSE)            \
+FIELDDEFA( 1, EAX, COMMON, 16,  4, EXTMODEL,            ANY, IGNORE, 0, FALSE, EXT_MODEL) \
+FIELDDEFA( 1, EAX, COMMON, 20,  8, EXTFAMILY,           YES, HOST,   0, FALSE, EXT_FAMILY) \
+FIELDDEF(  1, EBX, COMMON,  0,  8, BRAND_ID,            ANY, IGNORE, 0, FALSE)            \
+FIELDDEF(  1, EBX, COMMON,  8,  8, CLFL_SIZE,           ANY, IGNORE, 0, FALSE)            \
+FIELDDEFA( 1, EBX, COMMON, 16,  8, LCPU_COUNT,          ANY, IGNORE, 0, FALSE, LCPU_COUNT) \
+FIELDDEFA( 1, EBX, COMMON, 24,  8, APICID,              ANY, IGNORE, 0, FALSE, APICID)    \
+FLAGDEFA(  1, ECX, COMMON, 0,   1, SSE3,                YES, HOST,   0, TRUE,  SSE3)      \
+FLAGDEF(   1, ECX, INTEL,  2,   1, NDA2,                NO,  MASK,   0, FALSE)            \
+FLAGDEFA(  1, ECX, COMMON, 3,   1, MWAIT,               NO,  MASK,   0, FALSE, MWAIT)     \
+FLAGDEFA(  1, ECX, INTEL,  4,   1, DSCPL,               NO,  MASK,   0, FALSE, DSCPL)     \
+FLAGDEFA(  1, ECX, INTEL,  5,   1, VMX,                 NO,  MASK,   0, FALSE, VMX)       \
+FLAGDEF(   1, ECX, INTEL,  6,   1, SMX,                 NO,  MASK,   0, FALSE)            \
+FLAGDEF(   1, ECX, INTEL,  7,   1, EST,                 NO,  MASK,   0, FALSE)            \
+FLAGDEF(   1, ECX, INTEL,  8,   1, TM2,                 NO,  MASK,   0, FALSE)            \
+FLAGDEFA(  1, ECX, COMMON, 9,   1, SSSE3,               YES, HOST,   0, TRUE,  SSSE3)     \
+FLAGDEF(   1, ECX, INTEL,  10,  1, HTCACHE,             NO,  MASK,   0, FALSE)            \
+FLAGDEFA(  1, ECX, COMMON, 13,  1, CMPX16,              YES, HOST,   0, TRUE,  CMPX16)    \
+FLAGDEF(   1, ECX, INTEL,  14,  1, xPPR,                NO,  MASK,   0, FALSE)            \
+FLAGDEF(   1, ECX, INTEL,  15,  1, PERF_MSR,            NO,  MASK,   0, FALSE)            \
+FLAGDEF(   1, ECX, INTEL,  18,  1, DCA,                 NO,  MASK,   0, FALSE)            \
+FLAGDEFA(  1, ECX, INTEL,  19,  1, SSE41,               YES, HOST,   0, TRUE,  SSE41)     \
+FLAGDEFA(  1, ECX, INTEL,  20,  1, SSE42,               YES, HOST,   0, TRUE,  SSE42)     \
+FLAGDEF(   1, ECX, INTEL,  21,  1, X2APIC,              NO,  MASK,   0, FALSE)            \
+FLAGDEF(   1, ECX, INTEL,  22,  1, MOVBE,               NO,  RSVD,   0, TRUE)             \
+FLAGDEFA(  1, ECX, COMMON, 23,  1, POPCNT,              YES, HOST,   0, TRUE,  POPCNT)    \
+FLAGDEF(   1, ECX, INTEL,  24,  1, ULE,                 NO,  RSVD,   0, TRUE)             \
+FLAGDEF(   1, ECX, INTEL,  26,  1, XSAVE,               NO,  MASK,   0, FALSE)            \
+FLAGDEF(   1, ECX, INTEL,  27,  1, OSXSAVE,             NO,  RSVD,   0, TRUE)             \
+FLAGDEFA(  1, ECX, COMMON, 31,  1, HYPERVISOR,          ANY, IGNORE, 0, FALSE, HYPERVISOR)\
+FLAGDEFA(  1, EDX, COMMON, 0,   1, FPU,                 YES, HOST,   0, TRUE, FPU)        \
+FLAGDEFA(  1, EDX, COMMON, 1,   1, VME,                 YES, HOST,   0, FALSE, VME)       \
+FLAGDEF(   1, EDX, COMMON, 2,   1, DBGE,                YES, HOST,   0, FALSE)            \
+FLAGDEF(   1, EDX, COMMON, 3,   1, PGSZE,               YES, HOST,   0, FALSE)            \
+FLAGDEFA(  1, EDX, COMMON, 4,   1, TSC,                 YES, HOST,   0, TRUE, TSC)        \
+FLAGDEF(   1, EDX, COMMON, 5,   1, MSR,                 YES, HOST,   0, FALSE)            \
+FLAGDEFA(  1, EDX, COMMON, 6,   1, PAE,                 YES, HOST,   0, FALSE, PAE)       \
+FLAGDEF(   1, EDX, COMMON, 7,   1, MCK,                 YES, HOST,   0, FALSE)            \
+FLAGDEF(   1, EDX, COMMON, 8,   1, CPMX,                YES, HOST,   0, TRUE)             \
+FLAGDEFA(  1, EDX, COMMON, 9,   1, APIC,                ANY, MASK,   1, FALSE, APIC)      \
+FLAGDEFA(  1, EDX, COMMON, 11,  1, SEP,                 YES, HOST,   0, TRUE,  SEP)       \
+FLAGDEFA(  1, EDX, COMMON, 12,  1, MTRR,                YES, HOST,   0, FALSE, MTRR)      \
+FLAGDEFA(  1, EDX, COMMON, 13,  1, PGE,                 YES, HOST,   0, FALSE, PGE)       \
+FLAGDEFA(  1, EDX, COMMON, 14,  1, MCA,                 YES, HOST,   0, FALSE, MCA)       \
+FLAGDEFA(  1, EDX, COMMON, 15,  1, CMOV,                YES, HOST,   0, TRUE,  CMOV)      \
+FLAGDEFA(  1, EDX, COMMON, 16,  1, PAT,                 YES, HOST,   0, FALSE, PAT)       \
+FLAGDEF(   1, EDX, COMMON, 17,  1, 36PG,                YES, HOST,   0, FALSE)            \
+FLAGDEF(   1, EDX, INTEL,  18,  1, PSN,                 YES, HOST,   0, FALSE)            \
+FLAGDEFA(  1, EDX, COMMON, 19,  1, CLFL,                YES, HOST,   0, TRUE,  CLFL)      \
+FLAGDEF(   1, EDX, INTEL,  21,  1, DTES,                YES, HOST,   0, FALSE)            \
+FLAGDEF(   1, EDX, INTEL,  22,  1, ACPI,                YES, HOST,   0, FALSE)            \
+FLAGDEFA(  1, EDX, COMMON, 23,  1, MMX,                 YES, HOST,   0, TRUE,  MMX)       \
+FLAGDEFA(  1, EDX, COMMON, 24,  1, FXSAVE,              YES, HOST,   0, TRUE,  FXSAVE)    \
+FLAGDEFA(  1, EDX, COMMON, 25,  1, SSE,                 YES, HOST,   0, TRUE,  SSE)       \
+FLAGDEFA(  1, EDX, COMMON, 26,  1, SSE2,                YES, HOST,   0, TRUE,  SSE2)      \
+FLAGDEF(   1, EDX, INTEL,  27,  1, SS,                  YES, HOST,   0, FALSE)            \
+FLAGDEFA(  1, EDX, COMMON, 28,  1, HT,                  NO,  MASK,   0, FALSE, HT)        \
+FLAGDEF(   1, EDX, INTEL,  29,  1, TM,                  NO,  MASK,   0, FALSE)            \
+FLAGDEF(   1, EDX, INTEL,  30,  1, IA64,                NO,  MASK,   0, FALSE)            \
+FLAGDEF(   1, EDX, INTEL,  31,  1, PBE,                 NO,  MASK,   0, FALSE)
+
+/*    LEVEL, REG, VENDOR, POS, SIZE, NAME,       MON SUPP, MASK TYPE, SET TO, CPL3, [FUNC] */
+#define CPUID_FIELD_DATA_LEVEL_4                                               \
+FIELDDEF(  4, EAX, INTEL,   0,  5, CACHE_TYPE,          NA,  IGNORE, 0, FALSE)            \
+FIELDDEF(  4, EAX, INTEL,   5,  3, CACHE_LEVEL,         NA,  IGNORE, 0, FALSE)            \
+FIELDDEF(  4, EAX, INTEL,  14, 12, CACHE_NUMHT_SHARING, NA,  IGNORE, 0, FALSE)            \
+FIELDDEFA( 4, EAX, INTEL,  26,  6, CORE_COUNT,          NA,  IGNORE, 0, FALSE, INTEL_CORE_COUNT)  \
+FIELDDEF(  4, EBX, INTEL,   0, 12, CACHE_LINE,          NA,  IGNORE, 0, FALSE)            \
+FIELDDEF(  4, EBX, INTEL,  12, 10, CACHE_PART,          NA,  IGNORE, 0, FALSE)            \
+FIELDDEF(  4, EBX, INTEL,  22, 10, CACHE_WAYS,          NA,  IGNORE, 0, FALSE)
+
+/*     LEVEL, REG, VENDOR, POS, SIZE, NAME,       MON SUPP, MASK TYPE, SET TO, CPL3, [FUNC] */
+#define CPUID_FIELD_DATA_LEVEL_5                                           \
+FIELDDEF(  5, EAX, COMMON,  0, 16, MWAIT_MIN_SIZE,      NA,  IGNORE, 0, FALSE) \
+FIELDDEF(  5, EBX, COMMON,  0, 16, MWAIT_MAX_SIZE,      NA,  IGNORE, 0, FALSE) \
+FLAGDEF(   5, ECX, COMMON,  0,  1, MWAIT_EXTENSIONS,    NA,  IGNORE, 0, FALSE) \
+FLAGDEF(   5, ECX, COMMON,  1,  1, MWAIT_INTR_BREAK,    NA,  IGNORE, 0, FALSE) \
+FIELDDEF(  5, EDX, INTEL,   0,  4, MWAIT_C0_SUBSTATE,   NA,  IGNORE, 0, FALSE) \
+FIELDDEF(  5, EDX, INTEL,   4,  4, MWAIT_C1_SUBSTATE,   NA,  IGNORE, 0, FALSE) \
+FIELDDEF(  5, EDX, INTEL,   8,  4, MWAIT_C2_SUBSTATE,   NA,  IGNORE, 0, FALSE) \
+FIELDDEF(  5, EDX, INTEL,  12,  4, MWAIT_C3_SUBSTATE,   NA,  IGNORE, 0, FALSE) \
+FIELDDEF(  5, EDX, INTEL,  16,  4, MWAIT_C4_SUBSTATE,   NA,  IGNORE, 0, FALSE)
+
+/*    LEVEL, REG, VENDOR, POS, SIZE, NAME,       MON SUPP, MASK TYPE, SET TO, CPL3, [FUNC] */
+#define CPUID_FIELD_DATA_LEVEL_6                                               \
+FLAGDEF(   6, EAX, INTEL,   0,  1, THERMAL_SENSOR,      NA,  IGNORE, 0, FALSE)     \
+FLAGDEF(   6, EAX, INTEL,   1,  1, TURBO_MODE,          NA,  IGNORE, 0, FALSE)     \
+FIELDDEF(  6, EBX, INTEL,   0,  4, NUM_INTR_THRESHOLDS, NA,  IGNORE, 0, FALSE)     \
+FLAGDEF(   6, ECX, INTEL,   0,  1, HW_COORD_FEEDBACK,   NA,  IGNORE, 0, FALSE)
+
+/*    LEVEL, REG, VENDOR, POS, SIZE, NAME,       MON SUPP, MASK TYPE, SET TO, CPL3, [FUNC] */
+#define CPUID_FIELD_DATA_LEVEL_A                                               \
+FIELDDEFA( A, EAX, INTEL,   0,  8, PMC_VERSION,         NA,  IGNORE, 0, FALSE, PMC_VERSION) \
+FIELDDEFA( A, EAX, INTEL,   8,  8, NUM_PMCS,            NA,  IGNORE, 0, FALSE, NUM_PMCS)  \
+FIELDDEF(  A, EAX, INTEL,  16,  8, PMC_BIT_WIDTH,       NA,  IGNORE, 0, FALSE)            \
+FIELDDEFA( A, EAX, INTEL,  24,  8, PMC_EBX_LENGTH,      NA,  IGNORE, 0, FALSE, PMC_EBX_LENGTH) \
+FLAGDEF(   A, EBX, INTEL,   0,  1, PMC_CORE_CYCLE,      NA,  IGNORE, 0, FALSE)            \
+FLAGDEF(   A, EBX, INTEL,   1,  1, PMC_INSTR_RETIRED,   NA,  IGNORE, 0, FALSE)            \
+FLAGDEF(   A, EBX, INTEL,   2,  1, PMC_REF_CYCLES,      NA,  IGNORE, 0, FALSE)            \
+FLAGDEF(   A, EBX, INTEL,   3,  1, PMC_LAST_LVL_CREF,   NA,  IGNORE, 0, FALSE)            \
+FLAGDEF(   A, EBX, INTEL,   4,  1, PMC_LAST_LVL_CMISS,  NA,  IGNORE, 0, FALSE)            \
+FLAGDEF(   A, EBX, INTEL,   5,  1, PMC_BR_INST_RETIRED, NA,  IGNORE, 0, FALSE)            \
+FLAGDEF(   A, EBX, INTEL,   6,  1, PMC_BR_MISS_RETIRED, NA,  IGNORE, 0, FALSE)            \
+FIELDDEF(  A, EDX, INTEL,   0,  5, PMC_FIXED_NUM,       NA,  IGNORE, 0, FALSE)            \
+FIELDDEF(  A, EDX, INTEL,   5,  8, PMC_FIXED_SIZE,      NA,  IGNORE, 0, FALSE)
+
+/*    LEVEL, REG, VENDOR, POS, SIZE, NAME,       MON SUPP, MASK TYPE, SET TO, CPL3, [FUNC] */
+#define CPUID_FIELD_DATA_LEVEL_80                                              \
+FIELDDEF( 80, EAX, COMMON,  0, 32, NUM_EXT_LEVELS,      NA,  IGNORE, 0, FALSE)            \
+FIELDDEF( 80, EBX, AMD,     0, 32, AMD_VENDOR1,         NA,  IGNORE, 0, FALSE)            \
+FIELDDEF( 80, ECX, AMD,     0, 32, AMD_VENDOR3,         NA,  IGNORE, 0, FALSE)            \
+FIELDDEF( 80, EDX, AMD,     0, 32, AMD_VENDOR2,         NA,  IGNORE, 0, FALSE)
+                                                        
+/*    LEVEL, REG, VENDOR, POS, SIZE, NAME,       MON SUPP, MASK TYPE, SET TO, CPL3, [FUNC] */
+#define CPUID_FIELD_DATA_LEVEL_81                                              \
+FIELDDEF( 81, EAX, INTEL,   0, 32, UNKNOWN81EAX,        ANY, IGNORE, 0, FALSE)            \
+FIELDDEF( 81, EAX, AMD,     0,  4, STEPPING,            ANY, IGNORE, 0, FALSE)            \
+FIELDDEF( 81, EAX, AMD,     4,  4, MODEL,               ANY, IGNORE, 0, FALSE)            \
+FIELDDEF( 81, EAX, AMD,     8,  4, FAMILY,              ANY, IGNORE, 0, FALSE)            \
+FIELDDEF( 81, EAX, AMD,    12,  2, TYPE,                ANY, IGNORE, 0, FALSE)            \
+FIELDDEF( 81, EAX, AMD,    16,  4, EXTMODEL,            ANY, IGNORE, 0, FALSE)            \
+FIELDDEF( 81, EAX, AMD,    20,  8, EXTFAMILY,           ANY, IGNORE, 0, FALSE)            \
+FIELDDEF( 81, EBX, INTEL,   0, 32, UNKNOWN81EBX,        ANY, IGNORE, 0, FALSE)            \
+FIELDDEF( 81, EBX, AMD,     0, 16, BRAND_ID,            ANY, IGNORE, 0, FALSE)            \
+FIELDDEF( 81, EBX, AMD,    16, 16, UNDEF,               ANY, IGNORE, 0, FALSE)            \
+FLAGDEFA( 81, ECX, COMMON,  0,  1, LAHF,                YES, HOST,   0, TRUE,  LAHF64)    \
+FLAGDEFA( 81, ECX, AMD,     1,  1, CMPLEGACY,           NO,  MASK,   0, FALSE, CMPLEGACY) \
+FLAGDEFA( 81, ECX, AMD,     2,  1, SVM,                 NO,  MASK,   0, FALSE, SVM)       \
+FLAGDEFA( 81, ECX, AMD,     3,  1, EXTAPICSPC,          YES, HOST,   0, FALSE, EXTAPICSPC) \
+FLAGDEFA( 81, ECX, AMD,     4,  1, CR8AVAIL,            NO,  MASK,   0, FALSE, CR8AVAIL)  \
+FLAGDEFA( 81, ECX, AMD,     5,  1, ABM,                 YES, HOST,   0, TRUE,  ABM)       \
+FLAGDEFA( 81, ECX, AMD,     6,  1, SSE4A,               YES, HOST,   0, TRUE,  SSE4A)     \
+FLAGDEF(  81, ECX, AMD,     7,  1, MISALIGNED_SSE,      YES, HOST,   0, TRUE)             \
+FLAGDEFA( 81, ECX, AMD,     8,  1, 3DNPREFETCH,         YES, HOST,   0, TRUE, 3DNPREFETCH) \
+FLAGDEF(  81, ECX, AMD,     9,  1, OSVW,                NO,  MASK,   0, FALSE)            \
+FLAGDEF(  81, ECX, AMD,    10,  1, IBS,                 NO,  MASK,   0, FALSE)            \
+FLAGDEF(  81, ECX, AMD,    11,  1, SSE5,                NO,  RSVD,   0, TRUE)             \
+FLAGDEF(  81, ECX, AMD,    12,  1, SKINIT,              NO,  MASK,   0, FALSE)            \
+FLAGDEF(  81, ECX, AMD,    13,  1, WATCHDOG,            NO,  MASK,   0, FALSE)            \
+FLAGDEF(  81, EDX, AMD,     0,  1, FPU,                 YES, HOST,   0, TRUE)             \
+FLAGDEF(  81, EDX, AMD,     1,  1, VME,                 YES, HOST,   0, FALSE)            \
+FLAGDEF(  81, EDX, AMD,     2,  1, DBGE,                YES, HOST,   0, FALSE)            \
+FLAGDEF(  81, EDX, AMD,     3,  1, PGSZE,               YES, HOST,   0, FALSE)            \
+FLAGDEF(  81, EDX, AMD,     4,  1, TSC,                 YES, HOST,   0, TRUE)             \
+FLAGDEF(  81, EDX, AMD,     5,  1, MSR,                 YES, HOST,   0, FALSE)            \
+FLAGDEF(  81, EDX, AMD,     6,  1, PAE,                 YES, HOST,   0, FALSE)            \
+FLAGDEF(  81, EDX, AMD,     7,  1, MCK,                 YES, HOST,   0, FALSE)            \
+FLAGDEF(  81, EDX, AMD,     8,  1, CPMX,                YES, HOST,   0, TRUE)             \
+FLAGDEF(  81, EDX, AMD,     9,  1, APIC,                ANY, MASK,   1, FALSE)            \
+FLAGDEFA( 81, EDX, COMMON, 11,  1, SYSC,                ANY, IGNORE, 0, TRUE, SYSC)       \
+FLAGDEF(  81, EDX, AMD,    12,  1, MTRR,                YES, HOST,   0, FALSE)            \
+FLAGDEF(  81, EDX, AMD,    13,  1, PGE,                 YES, HOST,   0, FALSE)            \
+FLAGDEF(  81, EDX, AMD,    14,  1, MCA,                 YES, HOST,   0, FALSE)            \
+FLAGDEF(  81, EDX, AMD,    15,  1, CMOV,                YES, HOST,   0, TRUE)             \
+FLAGDEF(  81, EDX, AMD,    16,  1, PAT,                 YES, HOST,   0, FALSE)            \
+FLAGDEF(  81, EDX, AMD,    17,  1, 36PG,                YES, HOST,   0, FALSE)            \
+FLAGDEFA( 81, EDX, COMMON, 20,  1, NX,                  YES, HOST,   0, FALSE, NX)        \
+FLAGDEFA( 81, EDX, AMD,    22,  1, MMXEXT,              YES, HOST,   0, TRUE,  MMXEXT)    \
+FLAGDEF(  81, EDX, AMD,    23,  1, MMX,                 YES, HOST,   0, TRUE)             \
+FLAGDEF(  81, EDX, AMD,    24,  1, FXSAVE,              YES, HOST,   0, TRUE)             \
+FLAGDEFA( 81, EDX, AMD,    25,  1, FFXSR,               YES, HOST,   0, FALSE, FFXSR)     \
+FLAGDEF(  81, EDX, AMD,    26,  1, PDPE1GB,             NO,  MASK,   0, FALSE)            \
+FLAGDEFA( 81, EDX, COMMON, 27,  1, RDTSCP,              YES, HOST,   0, TRUE,  RDTSCP)    \
+FLAGDEFA( 81, EDX, COMMON, 29,  1, LM,                  YES, TEST,   1, FALSE, LM) \
+FLAGDEFA( 81, EDX, AMD,    30,  1, 3DNOWPLUS,           YES, HOST,   0, TRUE,  3DNOWPLUS) \
+FLAGDEFA( 81, EDX, AMD,    31,  1, 3DNOW,               YES, HOST,   0, TRUE,  3DNOW)
+
+/*    LEVEL, REG, VENDOR, POS, SIZE, NAME,       MON SUPP, MASK TYPE, SET TO, CPL3, [FUNC] */
+#define CPUID_FIELD_DATA_LEVEL_8x                                              \
+FIELDDEF( 86, ECX, AMD,     0,  8, L2CACHE_LINE,        NA,  IGNORE, 0, FALSE)            \
+FIELDDEF( 86, ECX, AMD,     8,  4, L2CACHE_LINE_PER_TAG, NA, IGNORE, 0, FALSE)            \
+FIELDDEF( 86, ECX, AMD,    12,  4, L2CACHE_WAYS,        NA,  IGNORE, 0, FALSE)            \
+FIELDDEF( 86, ECX, AMD,    16, 16, L2CACHE_SIZE,        NA,  IGNORE, 0, FALSE)            \
+FIELDDEF( 86, EDX, AMD,     0,  8, L3CACHE_LINE,        NA,  IGNORE, 0, FALSE)            \
+FIELDDEF( 86, EDX, AMD,     8,  4, L3CACHE_LINE_PER_TAG,NA,  IGNORE, 0, FALSE)            \
+FIELDDEF( 86, EDX, AMD,    12,  4, L3CACHE_WAYS,        NA,  IGNORE, 0, FALSE)            \
+FIELDDEF( 86, EDX, AMD,    18, 14, L3CACHE_SIZE,        NA,  IGNORE, 0, FALSE)            \
+FLAGDEF(  87, EDX, AMD,     0,  1, TS,                  NA,  IGNORE, 0, FALSE)            \
+FLAGDEF(  87, EDX, AMD,     1,  1, FID,                 NA,  IGNORE, 0, FALSE)            \
+FLAGDEF(  87, EDX, AMD,     2,  1, VID,                 NA,  IGNORE, 0, FALSE)            \
+FLAGDEF(  87, EDX, AMD,     3,  1, TTP,                 NA,  IGNORE, 0, FALSE)            \
+FLAGDEF(  87, EDX, AMD,     4,  1, TM,                  NA,  IGNORE, 0, FALSE)            \
+FLAGDEF(  87, EDX, AMD,     5,  1, STC,                 NA,  IGNORE, 0, FALSE)            \
+FLAGDEF(  87, EDX, AMD,     6,  1, 100MHZSTEPS,         NA,  IGNORE, 0, FALSE)            \
+FLAGDEF(  87, EDX, AMD,     7,  1, HWPSTATE,            NA,  IGNORE, 0, FALSE)            \
+FLAGDEF(  87, EDX, AMD,     8,  1, TSC_INVARIANT,       NA,  IGNORE, 0, FALSE)            \
+FIELDDEFA(88, EAX, COMMON,  0,  8, PHYSBITS,            NA,  IGNORE, 0, FALSE, PHYS_BITS) \
+FIELDDEFA(88, EAX, COMMON,  8,  8, VIRTBITS,            NA,  IGNORE, 0, FALSE, VIRT_BITS) \
+FIELDDEFA(88, ECX, AMD,     0,  8, CORE_COUNT,          NA,  IGNORE, 0, FALSE, AMD_CORE_COUNT) \
+FIELDDEFA(88, ECX, AMD,    12,  4, APICID_COREID_SIZE,  NA,  IGNORE, 0, FALSE, AMD_APICID_COREID_SIZE) \
+FIELDDEFA(8A, EAX, AMD,     0,  8, SVM_REVISION,        NO,  MASK,   0, FALSE, SVM_REVISION) \
+FLAGDEF(  8A, EAX, AMD,     8,  1, SVM_HYPERVISOR,      NO,  MASK,   0, FALSE)            \
+FIELDDEF( 8A, EAX, AMD,     9, 23, SVMEAX_RSVD,         NO,  MASK,   0, FALSE)            \
+FIELDDEF( 8A, EBX, AMD,     0, 32, SVM_N_ASIDS,         NO,  MASK,   0, FALSE)            \
+FIELDDEF( 8A, ECX, AMD,     0, 32, SVMECX_RSVD,         NO,  MASK,   0, FALSE)            \
+FLAGDEFA( 8A, EDX, AMD,     0,  1, SVM_NP,              NO,  MASK,   0, FALSE, NPT)       \
+FLAGDEF(  8A, EDX, AMD,     1,  1, SVM_LBR,             NO,  MASK,   0, FALSE)            \
+FLAGDEF(  8A, EDX, AMD,     2,  1, SVM_LOCK,            NO,  MASK,   0, FALSE)            \
+FLAGDEF(  8A, EDX, AMD,     3,  1, SVM_NRIP,            NO,  MASK,   0, FALSE)            \
+FIELDDEF( 8A, EDX, AMD,     4, 28, SVMEDX_RSVD,         NO,  MASK,   0, FALSE)
+
+#define CPUID_FIELD_DATA                                              \
+   CPUID_FIELD_DATA_LEVEL_0                                           \
+   CPUID_FIELD_DATA_LEVEL_1                                           \
+   CPUID_FIELD_DATA_LEVEL_4                                           \
+   CPUID_FIELD_DATA_LEVEL_5                                           \
+   CPUID_FIELD_DATA_LEVEL_6                                           \
+   CPUID_FIELD_DATA_LEVEL_A                                           \
+   CPUID_FIELD_DATA_LEVEL_80                                          \
+   CPUID_FIELD_DATA_LEVEL_81                                          \
+   CPUID_FIELD_DATA_LEVEL_8x
+
+/*
+ * Define all field and flag values as an enum.  The result is a full
+ * set of values taken from the table above in the form:
+ *
+ * CPUID_FEATURE_<vendor>_ID<level><reg>_<name> == mask for feature
+ * CPUID_<vendor>_ID<level><reg>_<name>_MASK    == mask for field
+ * CPUID_<vendor>_ID<level><reg>_<name>_SHIFT   == offset of field
+ *
+ * e.g. - CPUID_FEATURE_COMMON_ID1EDX_FPU     = 0x1
+ *      - CPUID_COMMON_ID88EAX_VIRTBITS_MASK  = 0xff00
+ *      - CPUID_COMMON_ID88EAX_VIRTBITS_SHIFT = 8
+ *
+ * Note: The FEATURE/MASK definitions must use some gymnastics to get
+ * around a warning when shifting left by 32.
+ */
+#define VMW_BIT_MASK(shift)  (((1 << (shift - 1)) << 1) - 1)
+
+#define FIELDDEF(lvl, reg, vend, bitpos, size, name, s, m, v, c3)       \
+   CPUID_##vend##_ID##lvl##reg##_##name##_SHIFT = bitpos,               \
+   CPUID_##vend##_ID##lvl##reg##_##name##_MASK  =                       \
+                      VMW_BIT_MASK(size) << bitpos,                     \
+   CPUID_FEATURE_##vend##_ID##lvl##reg##_##name =                       \
+                      CPUID_##vend##_ID##lvl##reg##_##name##_MASK,
+
+/* Before simplifying this take a look at bug 293638... */
+#define FIELDDEFA(lvl, reg, vend, bitpos, size, name, s, m, v, c3, f)   \
+   CPUID_##vend##_ID##lvl##reg##_##name##_SHIFT = bitpos,               \
+   CPUID_##vend##_ID##lvl##reg##_##name##_MASK  =                       \
+                      VMW_BIT_MASK(size) << bitpos,                     \
+   CPUID_FEATURE_##vend##_ID##lvl##reg##_##name =                       \
+                      CPUID_##vend##_ID##lvl##reg##_##name##_MASK,
+
+#define FLAGDEFA FIELDDEFA
+#define FLAGDEF FIELDDEF
+
+enum {
+   /* Define data for every CPUID field we have */
+   CPUID_FIELD_DATA
+};
+#undef VMW_BIT_MASK
+#undef FIELDDEF
+#undef FLAGDEF
+#undef FIELDDEFA
+#undef FLAGDEFA
+
+/*
+ * Legal CPUID config file mask characters.  For a description of the
+ * cpuid masking system, please see:
+ *
+ * http://vmweb.vmware.com/~mts/cgi-bin/view.cgi/Apps/CpuMigrationChecks
+ */
+
+#define CPUID_MASK_HIDE_CHR    '0'
+#define CPUID_MASK_HIDE_STR    "0"
+#define CPUID_MASK_FORCE_CHR   '1'
+#define CPUID_MASK_FORCE_STR   "1"
+#define CPUID_MASK_PASS_CHR    '-'
+#define CPUID_MASK_PASS_STR    "-"
+#define CPUID_MASK_TRUE_CHR    'T'
+#define CPUID_MASK_TRUE_STR    "T"
+#define CPUID_MASK_FALSE_CHR   'F'
+#define CPUID_MASK_FALSE_STR   "F"
+#define CPUID_MASK_IGNORE_CHR  'X'
+#define CPUID_MASK_IGNORE_STR  "X"
+#define CPUID_MASK_HOST_CHR    'H'
+#define CPUID_MASK_HOST_STR    "H"
+#define CPUID_MASK_RSVD_CHR    'R'
+#define CPUID_MASK_RSVD_STR    "R"
+#define CPUID_MASK_INSTALL_CHR 'I'
+#define CPUID_MASK_INSTALL_STR "I"
+
+/*
+ * If a level is listed as not masked/tested in CPUID_LEVELS above,
+ * use all "don't care" values for its mask.
+ */
+
+#define CPT_DFLT_UNDEFINED_MASK "XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX"
+
+/*
+ * When LM is disabled, we overlay the following masks onto the
+ * guest's default masks.  Any level that is not defined below should
+ * be treated as all "-"s
+ */
+
+#define CPT_ID1ECX_LM_DISABLED  "----:----:----:----:--0-:----:----:----"
+#define CPT_ID81EDX_LM_DISABLED "--0-:----:----:----:----:----:----:----"
+#define CPT_ID81ECX_LM_DISABLED "----:----:----:----:----:----:----:---0"
+
+#define CPT_GET_LM_DISABLED_MASK(lvl, reg)                                  \
+   ((lvl == 1 && reg == CPUID_REG_ECX) ? CPT_ID1ECX_LM_DISABLED :           \
+    (lvl == 0x80000001 && reg == CPUID_REG_ECX) ? CPT_ID81ECX_LM_DISABLED : \
+    (lvl == 0x80000001 && reg == CPUID_REG_EDX) ? CPT_ID81EDX_LM_DISABLED : \
+    NULL)
+
+/*
+ * Macro to define GET and SET functions for various common CPUID
+ * fields.  To create function for a new field, simply name it (CPUID_
+ * and CPUID_SET_ are automatically prepended), and list the field
+ * name that it needs to use.
+ */
+
+#define FIELD_FUNC(name, field)                                 \
+   static INLINE uint32 CPUID_##name(uint32 reg)                \
+   {                                                            \
+      return (reg & field##_MASK) >> field##_SHIFT;             \
+   }                                                            \
+   static INLINE void CPUID_SET_##name(uint32 *reg, uint32 val) \
+   {                                                            \
+      *reg = (*reg & ~field##_MASK) | (val << field##_SHIFT);   \
+   }
+
+FIELD_FUNC(STEPPING,         CPUID_COMMON_ID1EAX_STEPPING)
+FIELD_FUNC(MODEL,            CPUID_COMMON_ID1EAX_MODEL)
+FIELD_FUNC(FAMILY,           CPUID_COMMON_ID1EAX_FAMILY)
+FIELD_FUNC(TYPE,             CPUID_COMMON_ID1EAX_TYPE)
+FIELD_FUNC(EXTENDED_MODEL,   CPUID_COMMON_ID1EAX_EXTMODEL)
+FIELD_FUNC(EXTENDED_FAMILY,  CPUID_COMMON_ID1EAX_EXTFAMILY)
+FIELD_FUNC(LCPU_COUNT,       CPUID_COMMON_ID1EBX_LCPU_COUNT)
+FIELD_FUNC(APICID,           CPUID_COMMON_ID1EBX_APICID)
+FIELD_FUNC(PA_BITS,          CPUID_COMMON_ID88EAX_PHYSBITS)
+FIELD_FUNC(VIRT_BITS,        CPUID_COMMON_ID88EAX_VIRTBITS)
+FIELD_FUNC(SVM_REVISION,     CPUID_AMD_ID8AEAX_SVM_REVISION)
+FIELD_FUNC(SVM_N_ASIDS,      CPUID_AMD_ID8AEBX_SVM_N_ASIDS)
+FIELD_FUNC(INTEL_CORE_COUNT, CPUID_INTEL_ID4EAX_CORE_COUNT)
+FIELD_FUNC(AMD_CORE_COUNT,   CPUID_AMD_ID88ECX_CORE_COUNT)
+FIELD_FUNC(AMD_APICID_COREID_SIZE, CPUID_AMD_ID88ECX_APICID_COREID_SIZE)
+FIELD_FUNC(AMD_EXTAPICSPC,   CPUID_AMD_ID81ECX_EXTAPICSPC)
+FIELD_FUNC(NUM_PMCS,         CPUID_INTEL_IDAEAX_NUM_PMCS)
+FIELD_FUNC(MWAIT_MIN_SIZE,   CPUID_COMMON_ID5EAX_MWAIT_MIN_SIZE)
+FIELD_FUNC(MWAIT_MAX_SIZE,   CPUID_COMMON_ID5EBX_MWAIT_MAX_SIZE)
+FIELD_FUNC(MWAIT_C0_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C0_SUBSTATE)
+FIELD_FUNC(MWAIT_C1_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C1_SUBSTATE)
+FIELD_FUNC(MWAIT_C2_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C2_SUBSTATE)
+FIELD_FUNC(MWAIT_C3_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C3_SUBSTATE)
+FIELD_FUNC(MWAIT_C4_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C4_SUBSTATE)
+#undef FIELD_FUNC
+
+
+/*
+ * Definitions of various fields' values and more complicated
+ * macros/functions for reading cpuid fields.
+ */
+
+/* Effective Intel CPU Families */
+#define CPUID_FAMILY_486      4
+#define CPUID_FAMILY_P5       5
+#define CPUID_FAMILY_P6       6
+#define CPUID_FAMILY_P4       15
+
+/* Effective AMD CPU Families */
+#define CPUID_FAMILY_5x86     4
+#define CPUID_FAMILY_K5       5
+#define CPUID_FAMILY_K6       5
+#define CPUID_FAMILY_K7       6
+#define CPUID_FAMILY_K8       15
+#define CPUID_FAMILY_K8L      16
+#define CPUID_FAMILY_K8MOBILE 17
+#define CPUID_FAMILY_EXTENDED 15
+
+/* Intel model information */
+#define CPUID_MODEL_PPRO       1
+#define CPUID_MODEL_PII_03     3
+#define CPUID_MODEL_PII_05     5
+#define CPUID_MODEL_CELERON_06 6
+#define CPUID_MODEL_PM_09      9
+#define CPUID_MODEL_PM_0D      13
+#define CPUID_MODEL_PM_0E      14    // Yonah / Sossaman
+#define CPUID_MODEL_CORE_0F    15    // Conroe / Merom
+#define CPUID_MODEL_CORE_17    0x17  // Penryn
+#define CPUID_MODEL_NEHALEM_1A 0x1a  // Nehalem / Gainestown
+#define CPUID_MODEL_ATOM_1C    0x1c  // Silverthorne / Diamondville
+#define CPUID_MODEL_CORE_1D    0x1d  // Dunnington
+
+#define CPUID_MODEL_PIII_07    7
+#define CPUID_MODEL_PIII_08    8
+#define CPUID_MODEL_PIII_0A    10
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CPUID_IsVendor{AMD,Intel} --
+ *
+ *      Determines if the vendor string in cpuid id0 is from {AMD,Intel}.
+ *
+ * Results:
+ *      True iff vendor string is CPUID_{AMD,INTEL}_VENDOR_STRING
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------
+ */
+static INLINE Bool
+CPUID_IsRawVendor(CPUIDRegs *id0, const char* vendor)
+{
+   // hard to get strcmp() in some environments, so do it in the raw
+   return (id0->ebx == *(const uint32 *) (vendor + 0) &&
+           id0->ecx == *(const uint32 *) (vendor + 4) &&
+           id0->edx == *(const uint32 *) (vendor + 8));   
+}
+
+static INLINE Bool
+CPUID_IsVendorAMD(CPUIDRegs *id0)
+{
+   return CPUID_IsRawVendor(id0, CPUID_AMD_VENDOR_STRING);
+}
+
+static INLINE Bool
+CPUID_IsVendorIntel(CPUIDRegs *id0)
+{
+   return CPUID_IsRawVendor(id0, CPUID_INTEL_VENDOR_STRING);
+}
+
+
+static INLINE uint32
+CPUID_EFFECTIVE_FAMILY(uint32 v) /* %eax from CPUID with %eax=1. */
+{
+   return CPUID_FAMILY(v) +
+      (CPUID_FAMILY(v) == CPUID_FAMILY_EXTENDED ? CPUID_EXTENDED_FAMILY(v) : 0);
+}
+
+/* Normally only used when FAMILY==CPUID_FAMILY_EXTENDED, but Intel is
+ * now using the extended model field for FAMILY==CPUID_FAMILY_P6 to
+ * refer to the newer Core2 CPUs
+ */
+static INLINE uint32
+CPUID_EFFECTIVE_MODEL(uint32 v) /* %eax from CPUID with %eax=1. */
+{
+   return CPUID_MODEL(v) + (CPUID_EXTENDED_MODEL(v) << 4); 
+}
+
+/*
+ * Notice that CPUID families for Intel and AMD overlap. The following macros
+ * should only be used AFTER the manufacturer has been established (through
+ * the use of CPUID standard function 0).
+ */
+static INLINE Bool
+CPUID_FAMILY_IS_486(uint32 _eax)
+{
+   return CPUID_EFFECTIVE_FAMILY(_eax) == CPUID_FAMILY_486;
+}
+
+static INLINE Bool
+CPUID_FAMILY_IS_P5(uint32 _eax)
+{
+   return CPUID_EFFECTIVE_FAMILY(_eax) == CPUID_FAMILY_P5;
+}
+
+static INLINE Bool
+CPUID_FAMILY_IS_P6(uint32 _eax)
+{
+   return CPUID_EFFECTIVE_FAMILY(_eax) == CPUID_FAMILY_P6;
+}
+
+static INLINE Bool
+CPUID_FAMILY_IS_PENTIUM4(uint32 _eax)
+{
+   return CPUID_EFFECTIVE_FAMILY(_eax) == CPUID_FAMILY_P4;
+}
+
+/*
+ * Intel Pentium M processors are Yonah/Sossaman or an older P-M
+ */
+static INLINE Bool
+CPUID_UARCH_IS_PENTIUM_M(uint32 v) // IN: %eax from CPUID with %eax=1.
+{
+   /* Assumes the CPU manufacturer is Intel. */
+   return CPUID_FAMILY_IS_P6(v) &&
+          (CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_PM_09 ||
+           CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_PM_0D ||
+           CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_PM_0E);
+}
+
+/*
+ * Intel Core processors are Merom, Conroe, Woodcrest, Clovertown,
+ * Penryn, Dunnington, Kentsfield, Yorktown, Harpertown, ........
+ */
+static INLINE Bool
+CPUID_UARCH_IS_CORE(uint32 v) // IN: %eax from CPUID with %eax=1.
+{
+   uint32 model = CPUID_EFFECTIVE_MODEL(v);
+   /* Assumes the CPU manufacturer is Intel. */
+   return CPUID_FAMILY_IS_P6(v) &&
+          model >= CPUID_MODEL_CORE_0F &&
+          (model < CPUID_MODEL_NEHALEM_1A ||
+           model == CPUID_MODEL_CORE_1D);
+}
+
+
+/*
+ * Intel Nehalem processors are: Nehalem, Gainestown.
+ */
+static INLINE Bool
+CPUID_UARCH_IS_NEHALEM(uint32 v) // IN: %eax from CPUID with %eax=1.
+{
+   /* Assumes the CPU manufacturer is Intel. */
+   return CPUID_FAMILY_IS_P6(v) &&
+          CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_NEHALEM_1A;
+}
+
+
+static INLINE Bool
+CPUID_FAMILY_IS_K7(uint32 _eax)
+{
+   return CPUID_EFFECTIVE_FAMILY(_eax) == CPUID_FAMILY_K7;
+}
+
+static INLINE Bool
+CPUID_FAMILY_IS_K8(uint32 _eax)
+{
+   return CPUID_EFFECTIVE_FAMILY(_eax) == CPUID_FAMILY_K8;
+}
+
+static INLINE Bool
+CPUID_FAMILY_IS_K8EXT(uint32 _eax)
+{
+   /*
+    * We check for this pattern often enough that it's
+    * worth a separate function, for syntactic sugar.
+    */
+   return CPUID_FAMILY_IS_K8(_eax) &&
+          CPUID_EXTENDED_MODEL(_eax) != 0;
+}
+
+static INLINE Bool
+CPUID_FAMILY_IS_K8L(uint32 _eax)
+{
+   return CPUID_EFFECTIVE_FAMILY(_eax) == CPUID_FAMILY_K8L;
+}
+
+static INLINE Bool
+CPUID_FAMILY_IS_K8MOBILE(uint32 _eax)
+{
+   /* Essentially a K8 (not K8L) part, but with mobile features. */
+   return CPUID_EFFECTIVE_FAMILY(_eax) == CPUID_FAMILY_K8MOBILE;
+}
+
+static INLINE Bool
+CPUID_FAMILY_IS_K8STAR(uint32 _eax)
+{
+   /*
+    * Read function name as "K8*", as in wildcard.
+    * Matches K8 or K8L or K8MOBILE
+    */
+   return CPUID_FAMILY_IS_K8(_eax) || CPUID_FAMILY_IS_K8L(_eax) ||
+          CPUID_FAMILY_IS_K8MOBILE(_eax);
+}
+
+
+#define CPUID_TYPE_PRIMARY     0
+#define CPUID_TYPE_OVERDRIVE   1
+#define CPUID_TYPE_SECONDARY   2
+
+#define CPUID_INTEL_ID4EAX_CACHE_TYPE_NULL      0
+#define CPUID_INTEL_ID4EAX_CACHE_TYPE_DATA      1
+#define CPUID_INTEL_ID4EAX_CACHE_TYPE_INST      2
+#define CPUID_INTEL_ID4EAX_CACHE_TYPE_UNIF      3
+
+#define CPUID_INTEL_ID4EAX_CACHE_SELF_INIT      0x00000100
+#define CPUID_INTEL_ID4EAX_CACHE_FULLY_ASSOC    0x00000200
+
+
+/*
+ * On AMD chips before Opteron and Intel chips before P4 model 3,
+ * WRMSR(TSC) clears the upper half of the TSC instead of using %edx.
+ */
+static INLINE Bool
+CPUID_FullyWritableTSC(Bool isIntel, // IN
+                       uint32 v)     // IN: %eax from CPUID with %eax=1.
+{
+   /*
+    * Returns FALSE if:
+    *   - Intel && P6 (pre-core) or
+    *   - Intel && P4 (model < 3) or
+    *   - !Intel && pre-K8 Opteron
+    * Otherwise, returns TRUE.
+    */
+   return !((isIntel &&
+             ((CPUID_FAMILY_IS_P6(v) &&
+               CPUID_EFFECTIVE_MODEL(v) < CPUID_MODEL_PM_0E) ||
+              (CPUID_FAMILY_IS_PENTIUM4(v) &&
+               CPUID_EFFECTIVE_MODEL(v) < 3))) ||
+            (!isIntel &&
+             CPUID_FAMILY(v) < CPUID_FAMILY_K8));
+}
+
+
+/*
+ * For certain AMD processors, an lfence instruction is necessary at various
+ * places to ensure ordering.
+ */
+
+static INLINE Bool
+CPUID_VendorRequiresFence(CpuidVendors vendor)
+{
+   return vendor == CPUID_VENDOR_AMD;
+}
+
+static INLINE Bool
+CPUID_VersionRequiresFence(uint32 version)
+{
+   return CPUID_EFFECTIVE_FAMILY(version) == CPUID_FAMILY_K8 &&
+          CPUID_EFFECTIVE_MODEL(version) < 0x40;
+}
+
+static INLINE Bool
+CPUID_ID0RequiresFence(CPUIDRegs *id0)
+{
+   if (id0->eax == 0) {
+      return FALSE;
+   }
+   return CPUID_IsVendorAMD(id0);
+}
+
+static INLINE Bool
+CPUID_ID1RequiresFence(CPUIDRegs *id1)
+{
+   return CPUID_VersionRequiresFence(id1->eax);
+}
+
+static INLINE Bool
+CPUID_RequiresFence(CpuidVendors vendor, // IN
+                    uint32 version)      // IN: %eax from CPUID with %eax=1.
+{
+   return CPUID_VendorRequiresFence(vendor) &&
+         CPUID_VersionRequiresFence(version);
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CPUID_CountsCPUIDAsBranch --
+ *
+ *      Returns TRUE iff the cpuid given counts CPUID as a branch
+ *      (i.e. is a pre-Merom E CPU).
+ *
+ *----------------------------------------------------------------------
+ */
+
+static INLINE Bool
+CPUID_CountsCPUIDAsBranch(uint32 v) /* %eax from CPUID with %eax=1 */
+{
+   /* 
+    * CPUID no longer a branch starting with Merom E. Bug 148411.
+    * Penryn (Extended Model: 1) also has this fixed.
+    *
+    * Merom E is: CPUID.1.eax & 0xfff = 0x6f9
+    */
+   return !(CPUID_FAMILY_IS_P6(v) &&
+            (CPUID_EFFECTIVE_MODEL(v) > CPUID_MODEL_CORE_0F ||
+             (CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_CORE_0F &&
+              CPUID_STEPPING(v) >= 9)));
+}
+
+/*
+ * On Merom and later Intel chips, not present PDPTEs with reserved bits
+ * set do not fault with a #GP. See PR# 109120.
+ */
+static INLINE Bool
+CPUID_FaultOnNPReservedPDPTE(uint32 v) // IN: %eax from CPUID with %eax=1.
+{
+   return !(CPUID_FAMILY_IS_P6(v) &&
+            (CPUID_EFFECTIVE_MODEL(v) >= CPUID_MODEL_CORE_0F));
+}
+
+
+/* 
+ * The following low-level functions compute the number of
+ * cores per cpu.  They should be used cautiously because
+ * they do not necessarily work on all types of CPUs.
+ * High-level functions that are correct for all CPUs are
+ * available elsewhere: see lib/cpuidInfo/cpuidInfo.c.
+ */
+
+static INLINE uint32
+CPUID_IntelCoresPerPackage(uint32 v) /* %eax from CPUID with %eax=4 and %ecx=0. */
+{
+   // Note: This is not guaranteed to work on older Intel CPUs.
+   return 1 + CPUID_INTEL_CORE_COUNT(v);
+}
+
+static INLINE uint32
+CPUID_AMDCoresPerPackage(uint32 v) /* %ecx from CPUID with %eax=0x80000008. */
+{
+   // Note: This is not guaranteed to work on older AMD CPUs.
+   return 1 + CPUID_AMD_CORE_COUNT(v);
+}
+
+/*
+ * Hypervisor CPUID space is 0x400000XX.
+ */
+static INLINE Bool
+CPUID_IsHypervisorLevel(uint32 level, uint32 *offset)
+{
+   *offset = level & 0xff;
+   return (level & 0xffffff00) == 0x40000000;
+}
+
+
+#endif
diff --git a/open-vm-tools/vmblock-fuse/COPYING b/open-vm-tools/vmblock-fuse/COPYING
new file mode 100644 (file)
index 0000000..09f465a
--- /dev/null
@@ -0,0 +1,502 @@
+                 GNU LESSER GENERAL PUBLIC LICENSE
+                      Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+                 GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/open-vm-tools/vmblock-fuse/Makefile.am b/open-vm-tools/vmblock-fuse/Makefile.am
new file mode 100644 (file)
index 0000000..625c250
--- /dev/null
@@ -0,0 +1,50 @@
+################################################################################
+### Copyright 2008 VMware, Inc.  All rights reserved.
+###
+### This program is free software; you can redistribute it and/or modify
+### it under the terms of version 2 of the GNU General Public License as
+### published by the Free Software Foundation.
+###
+### This program is distributed in the hope that it will be useful,
+### but WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+### GNU General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with this program; if not, write to the Free Software
+### Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+################################################################################
+
+bin_PROGRAMS = vmware-vmblock-fuse
+
+# _XOPEN_SOURCE needs to be defined to at least 500 when compiling
+# vmblock-fuse's os.h to get pthread_rwlock_t.
+# -D_FILE_OFFSET_BITS=64 required for fuse.
+
+AM_CFLAGS =
+AM_CFLAGS += -Dvmblock_fuse
+AM_CFLAGS += -D_XOPEN_SOURCE=500
+AM_CFLAGS += -DUSERLEVEL
+AM_CFLAGS += -D_FILE_OFFSET_BITS=64
+AM_CFLAGS += @FUSE_CPPFLAGS@
+AM_CFLAGS += @VMWARE_USER_CPPFLAGS@
+
+vmware_vmblock_fuse_LDADD =
+vmware_vmblock_fuse_LDADD += ../lib/misc/libMisc.la
+vmware_vmblock_fuse_LDADD += @FUSE_LIBS@
+
+vmware_vmblock_fuse_SOURCES =
+vmware_vmblock_fuse_SOURCES += stubs.c
+vmware_vmblock_fuse_SOURCES += block.c
+vmware_vmblock_fuse_SOURCES += util.c
+vmware_vmblock_fuse_SOURCES += fsops.c
+vmware_vmblock_fuse_SOURCES += main.c
+
+if HAVE_ICU
+   vmware_vmblock_fuse_LDADD += @ICU_LIBS@
+   vmware_vmblock_fuse_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
+                      $(LIBTOOLFLAGS) --mode=link $(CXX) $(AM_CXXFLAGS) \
+                      $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+else
+   vmware_vmblock_fuse_LINK = $(LINK)
+endif
diff --git a/open-vm-tools/vmblock-fuse/block.c b/open-vm-tools/vmblock-fuse/block.c
new file mode 100644 (file)
index 0000000..45f8f75
--- /dev/null
@@ -0,0 +1,612 @@
+/*********************************************************
+ * Copyright (C) 2006 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * block.c --
+ *
+ *      Blocking operation implementions for the vmblock driver.
+ */
+
+/* os.h includes necessary OS-specific headers. */
+#include "os.h"
+
+#if defined(vmblock_fuse)
+#elif defined(linux)
+# include "vmblockInt.h"
+#elif defined(sun)
+# include "module.h"
+#elif defined(__FreeBSD__)
+# include "vmblock_k.h"
+#endif
+#include "block.h"
+#include "stubs.h"
+#include "dbllnklst.h"
+
+typedef struct BlockInfo {
+   DblLnkLst_Links links;
+   os_atomic_t refcount;
+   os_blocker_id_t blocker;
+   os_completion_t completion;
+   char filename[OS_PATH_MAX];
+} BlockInfo;
+
+
+/* XXX: Is it worth turning this into a hash table? */
+static DblLnkLst_Links blockedFiles;
+static os_rwlock_t blockedFilesLock;
+static os_kmem_cache_t *blockInfoCache = NULL;
+
+/* Utility functions */
+static Bool BlockExists(const char *filename);
+static BlockInfo *GetBlock(const char *filename, const os_blocker_id_t blocker);
+static BlockInfo *AllocBlock(os_kmem_cache_t *cache,
+                             const char *filename, const os_blocker_id_t blocker);
+static void FreeBlock(os_kmem_cache_t *cache, BlockInfo *block);
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * BlockInit --
+ *
+ *    Initializes blocking portion of module.
+ *
+ * Results:
+ *    Zero on success, error code on failure.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+BlockInit(void)
+{
+   ASSERT(!blockInfoCache);
+
+   blockInfoCache = os_kmem_cache_create("blockInfoCache",
+                                         sizeof (BlockInfo),
+                                         0,
+                                         NULL);
+   if (!blockInfoCache) {
+      return OS_ENOMEM;
+   }
+
+   DblLnkLst_Init(&blockedFiles);
+   os_rwlock_init(&blockedFilesLock);
+
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * BlockCleanup --
+ *
+ *    Cleans up the blocking portion of the module.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+BlockCleanup(void)
+{
+   ASSERT(blockInfoCache);
+   ASSERT(!DblLnkLst_IsLinked(&blockedFiles));
+
+   os_rwlock_destroy(&blockedFilesLock);
+   os_kmem_cache_destroy(blockInfoCache);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * BlockAddFileBlock --
+ *
+ *    Adds a block for the provided filename.  filename should be the name of
+ *    the actual file being blocked, not the name within our namespace.  The
+ *    provided blocker ID should uniquely identify this blocker.
+ *
+ *    All calls to BlockWaitOnFile() with the same filename will not return
+ *    until BlockRemoveFileBlock() is called.
+ *
+ *    Note that this function assumes a block on filename does not already
+ *    exist.
+ *
+ * Results:
+ *    Zero on success, error code on failure.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+BlockAddFileBlock(const char *filename,           // IN: name of file to block
+                  const os_blocker_id_t blocker)  // IN: blocker adding the block
+{
+   BlockInfo *block;
+
+   ASSERT(filename);
+
+   /* Create a new block. */
+   block = AllocBlock(blockInfoCache, filename, blocker);
+   if (!block) {
+      Warning("BlockAddFileBlock: out of memory\n");
+      return OS_ENOMEM;
+   }
+   os_write_lock(&blockedFilesLock);
+
+   /*
+    * Prevent duplicate blocks of any filename.  Done under same lock as list
+    * addition to ensure check for and adding of file are atomic.
+    */
+   if (BlockExists(filename)) {
+      Warning("BlockAddFileBlock: block already exists for [%s]\n", filename);
+      os_write_unlock(&blockedFilesLock);
+      FreeBlock(blockInfoCache, block);
+      return OS_EEXIST;
+   }
+
+   DblLnkLst_LinkLast(&blockedFiles, &block->links);
+
+   os_write_unlock(&blockedFilesLock);
+
+   LOG(4, "added block for [%s]\n", filename);
+
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * BlockRemoveFileBlock --
+ *
+ *    Removes the provided file block and wakes up any threads waiting within
+ *    BlockWaitOnFile().  Note that only the blocker that added a block can
+ *    remove it.
+ *
+ * Results:
+ *    Zero on success, error code on failure.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+BlockRemoveFileBlock(const char *filename,          // IN: block to remove
+                     const os_blocker_id_t blocker) // IN: blocker removing this block
+{
+   BlockInfo *block;
+
+   ASSERT(filename);
+
+   os_write_lock(&blockedFilesLock);
+
+   block = GetBlock(filename, blocker);
+   if (!block) {
+      os_write_unlock(&blockedFilesLock);
+      return OS_ENOENT;
+   }
+
+   DblLnkLst_Unlink1(&block->links);
+   os_write_unlock(&blockedFilesLock);
+
+   /* Undo GetBlock's refcount increment first. */
+   os_atomic_dec(&block->refcount);
+
+   /*
+    * Now remove /our/ reference.  (As opposed to references by waiting
+    * threads.)
+    */
+   if (os_atomic_dec_and_test(&block->refcount)) {
+      /* No threads are waiting, so clean up ourself. */
+      LOG(4, "Freeing block with no waiters on [%s]\n", filename);
+      FreeBlock(blockInfoCache, block);
+   } else {
+      /* Wake up waiters; the last one will free the BlockInfo */
+      LOG(4, "Completing block on [%s]\n", filename);
+      os_complete_all(&block->completion);
+   }
+
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * BlockRemoveAllBlocks --
+ *
+ *    Removes all blocks added by the provided blocker.
+ *
+ * Results:
+ *    Returns the number of entries removed from the blocklist.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+unsigned int
+BlockRemoveAllBlocks(const os_blocker_id_t blocker)  // IN: blocker to remove blocks for
+{
+   struct DblLnkLst_Links *curr;
+   struct DblLnkLst_Links *tmp;
+   unsigned int removed = 0;
+
+   os_write_lock(&blockedFilesLock);
+
+   DblLnkLst_ForEachSafe(curr, tmp, &blockedFiles) {
+      BlockInfo *currBlock = DblLnkLst_Container(curr, BlockInfo, links);
+      if (currBlock->blocker == blocker || blocker == OS_UNKNOWN_BLOCKER) {
+
+         DblLnkLst_Unlink1(&currBlock->links);
+
+         /*
+          * We count only entries removed from the -list-, regardless of whether
+          * or not other waiters exist.
+          */
+         ++removed;
+
+         /*
+          * BlockInfos, as the result of placing a block on a file or directory,
+          * reference themselves.  When the block is lifted, we need to remove
+          * this self-reference and handle the result appropriately.
+          */
+         if (os_atomic_dec_and_test(&currBlock->refcount)) {
+            /* Free blocks without any waiters ... */
+            LOG(4, "Freeing block with no waiters for blocker [%p] (%s)\n",
+                blocker, currBlock->filename);
+            FreeBlock(blockInfoCache, currBlock);
+         } else {
+            /* ... or wakeup the waiting threads */
+            LOG(4, "Completing block for blocker [%p] (%s)\n",
+                blocker, currBlock->filename);
+            os_complete_all(&currBlock->completion);
+         }
+      }
+   }
+
+   os_write_unlock(&blockedFilesLock);
+
+   return removed;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * BlockWaitOnFile --
+ *
+ *    Searches for a block on the provided filename.  If one exists, this
+ *    function does not return until that block has been lifted; otherwise, it
+ *    returns right away.
+ *
+ * Results:
+ *    Zero on success, otherwise an appropriate system error if our sleep/
+ *    block is interrupted.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+BlockWaitOnFile(const char *filename,   // IN: file to block on
+                BlockHandle cookie)     // IN: previously found block
+{
+   BlockInfo *block = NULL;
+   int error = 0;
+
+   ASSERT(filename);
+
+   /*
+    * Caller may have used BlockLookup to conditionally search for a
+    * block before actually going to sleep.  (This allows the caller to
+    * do a little housekeeping, such as releasing vnode locks, before
+    * blocking here.)
+    */
+   if (cookie == NULL) {
+      os_read_lock(&blockedFilesLock);
+      block = GetBlock(filename, OS_UNKNOWN_BLOCKER);
+      os_read_unlock(&blockedFilesLock);
+
+      if (!block) {
+         /* This file is not blocked, just return */
+         return 0;
+      }
+   } else {
+      /*
+       * Note that the "cookie's" reference count was incremented when it
+       * was fetched via BlockLookup, so this is completely safe.  (We'll
+       * decrement it below.)
+       */
+      block = cookie;
+   }
+
+   LOG(4, "(%"OS_FMTTID") Waiting for completion on [%s]\n", os_threadid, filename);
+   error = os_wait_for_completion(&block->completion);
+   LOG(4, "(%"OS_FMTTID") Wokeup from block on [%s]\n", os_threadid, filename);
+
+   /*
+    * The assumptions here are as follows:
+    *   1.  The BlockInfo holds a reference to itself.  (BlockInfo's refcount
+    *       is initialized to 1.)
+    *   2.  BlockInfo's self reference is deleted only when BlockInfo is
+    *       /also/ removed removed from the block list.
+    *
+    * Therefore, if the reference count hits zero, it's because the block is
+    * no longer in the list, and there is no chance of another thread finding
+    * and referencing this block between our dec_and_test and freeing it.
+    */
+   if (os_atomic_dec_and_test(&block->refcount)) {
+      /* We were the last thread, so clean up */
+      LOG(4, "(%"OS_FMTTID") I am the last to wakeup, freeing the block on [%s]\n",
+          os_threadid, filename);
+      FreeBlock(blockInfoCache, block);
+   }
+
+   return error;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * BlockLookup --
+ *
+ *      VFS-exported function for searching for blocks.
+ *
+ * Results:
+ *      Opaque pointer to a blockInfo if a block is found, NULL otherwise.
+ *
+ * Side effects:
+ *      Located blockInfo, if any, has an incremented reference count.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+BlockHandle
+BlockLookup(const char *filename,               // IN: pathname to test for
+                                                //     blocking
+            const os_blocker_id_t blocker)      // IN: specific blocker to
+                                                //     search for
+{
+   BlockInfo *block;
+
+   os_read_lock(&blockedFilesLock);
+
+   block = GetBlock(filename, blocker);
+
+   os_read_unlock(&blockedFilesLock);
+
+   return block;
+}
+
+
+#ifdef VMX86_DEVEL
+/*
+ *----------------------------------------------------------------------------
+ *
+ * BlockListFileBlocks --
+ *
+ *    Lists all the current file blocks.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+BlockListFileBlocks(void)
+{
+   DblLnkLst_Links *curr;
+   int count = 0;
+
+   os_read_lock(&blockedFilesLock);
+
+   DblLnkLst_ForEach(curr, &blockedFiles) {
+      BlockInfo *currBlock = DblLnkLst_Container(curr, BlockInfo, links);
+      LOG(1, "BlockListFileBlocks: (%d) Filename: [%s], Blocker: [%p]\n",
+          count++, currBlock->filename, currBlock->blocker);
+   }
+
+   os_read_unlock(&blockedFilesLock);
+
+   if (!count) {
+      LOG(1, "BlockListFileBlocks: No blocks currently exist.\n");
+   }
+}
+#endif
+
+
+/* Utility functions */
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * BlockExists --
+ *
+ *    Checks if a block already exists for the provided filename.
+ *
+ *    Note that this assumes the proper locking has been done on the data
+ *    structure holding the blocked files (including ensuring the atomic_dec()
+ *    without a kmem_cache_free() is safe).
+ *
+ * Results:
+ *    TRUE if a block exists, FALSE otherwise.
+ *
+ * Side effects:
+ *    If a block exists, its refcount is incremented and decremented.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+BlockExists(const char *filename)
+{
+   BlockInfo *block = GetBlock(filename, OS_UNKNOWN_BLOCKER);
+
+   if (block) {
+      os_atomic_dec(&block->refcount);
+      return TRUE;
+   }
+
+   return FALSE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * GetBlock --
+ *
+ *    Searches for a block on the provided filename by the provided blocker.
+ *    If blocker is NULL, it is ignored and any matching filename is returned.
+ *    If a block is found, the refcount is incremented.
+ *
+ *    Note that this assumes the proper locking has been done on the data
+ *    structure holding the blocked files.
+ *
+ * Results:
+ *    A pointer to the corresponding BlockInfo if found, NULL otherwise.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static BlockInfo *
+GetBlock(const char *filename,          // IN: file to find block for
+         const os_blocker_id_t blocker) // IN: blocker associated with this block
+{
+   struct DblLnkLst_Links *curr;
+
+   /* XXX The following is only temporary. */
+#ifdef __FreeBSD__
+   os_assert_rwlock_held(&blockedFilesLock);
+#else
+   ASSERT(os_rwlock_held(&blockedFilesLock));
+#endif
+
+   DblLnkLst_ForEach(curr, &blockedFiles) {
+      BlockInfo *currBlock = DblLnkLst_Container(curr, BlockInfo, links);
+      if ((blocker == OS_UNKNOWN_BLOCKER || currBlock->blocker == blocker) &&
+          strcmp(currBlock->filename, filename) == 0) {
+         os_atomic_inc(&currBlock->refcount);
+         return currBlock;
+      }
+   }
+
+   return NULL;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * AllocBlock --
+ *
+ *    Allocates and initializes a new block structure.
+ *
+ * Results:
+ *    Pointer to the struct on success, NULL on failure.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+BlockInfo *
+AllocBlock(os_kmem_cache_t *cache,        // IN: cache to allocate from
+           const char *filename,          // IN: filname of block
+           const os_blocker_id_t blocker) // IN: blocker id
+{
+   BlockInfo *block;
+   size_t ret;
+
+   /* Initialize this file's block structure. */
+   block = os_kmem_cache_alloc(blockInfoCache);
+   if (!block) {
+      return NULL;
+   }
+
+   ret = strlcpy(block->filename, filename, sizeof block->filename);
+   if (ret >= sizeof block->filename) {
+      Warning("BlockAddFileBlock: filename is too large\n");
+      os_kmem_cache_free(blockInfoCache, block);
+      return NULL;
+   }
+
+   DblLnkLst_Init(&block->links);
+   os_atomic_set(&block->refcount, 1);
+   os_completion_init(&block->completion);
+   block->blocker = blocker;
+
+   return block;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * FreeBlock --
+ *
+ *    Frees the provided block structure.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+FreeBlock(os_kmem_cache_t *cache,       // IN: cache block was allocated from
+          BlockInfo *block)             // IN: block to free
+{
+   ASSERT(cache);
+   ASSERT(block);
+
+   os_completion_destroy(&block->completion);
+   os_kmem_cache_free(cache, block);
+}
diff --git a/open-vm-tools/vmblock-fuse/block.h b/open-vm-tools/vmblock-fuse/block.h
new file mode 100644 (file)
index 0000000..62225c1
--- /dev/null
@@ -0,0 +1,47 @@
+/*********************************************************
+ * Copyright (C) 2006 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * block.h --
+ *
+ *   Blocking operations for the vmblock driver.
+ */
+
+#ifndef __BLOCK_H__
+#define __BLOCK_H__
+
+#include "os.h"
+
+typedef struct BlockInfo * BlockHandle;
+
+/*
+ * Global functions
+ */
+
+int BlockInit(void);
+void BlockCleanup(void);
+int BlockAddFileBlock(const char *filename, const os_blocker_id_t blocker);
+int BlockRemoveFileBlock(const char *filename, const os_blocker_id_t blocker);
+unsigned int BlockRemoveAllBlocks(const os_blocker_id_t blocker);
+int BlockWaitOnFile(const char *filename, BlockHandle cookie);
+BlockHandle BlockLookup(const char *filename, const os_blocker_id_t blocker);
+#ifdef VMX86_DEVEL
+void BlockListFileBlocks(void);
+#endif
+
+#endif /* __BLOCK_H__ */
diff --git a/open-vm-tools/vmblock-fuse/design.txt b/open-vm-tools/vmblock-fuse/design.txt
new file mode 100644 (file)
index 0000000..8ca4f24
--- /dev/null
@@ -0,0 +1,170 @@
+-----------------------
+| VMBlock Fuse Design |
+-----------------------
+
+Filesystem User Interface
+-------------------------
+Reexports /tmp/VMwareDnD. I'll call this the target directory.
+
+Mount point will contain:
+    * /blockdir/
+    * /dev
+    * /version - Proposed, not implemented.
+
+/blockdir/ - Contains symlinks to the contents of the target directory. In the linux port
+this is called /mountPoint/; it is created by the blocking driver and then the fs is
+mounted there. That's kind of confusing here, because we don't have 2 separate pieces.
+It's just a special directory within the file system.
+
+/dev - Control file. Control operations happen by opening this file and doing a write on
+it. The data that we write is a character representing the operation to be done,
+sometimes followed by the path of the file to be blocked or unblocked (its original path,
+eg: "/tmp/VMwareDnD/foo/bar"). The count argument to write must be the length of the
+string. This will be the length of the path + 1 for the operation character.
+
+COMMAND                        OPERATION CHARACTER    EXAMPLE
+Add block                      a                      write(fd, "a/some/path/in/target/dir", 25)
+Delete block                   d                      write(fd, "d/another/path/in/target/dir", 28)
+List blocks (only available    l (lower case L)       write(fd, "l", 1)
+    with VMX86_DEVEL)
+
+I was hoping to use the same interface as the linux kernel port, but doing writes with
+too-long sizes through fuse isn't supported and may not always work.
+
+When an entry in /blockdir/ is blocked, any readlink() on that entry will block.
+
+The control file is owned and only writable by root. We might want to change that (more
+below). Right now we have a wrapper with root priveleges acquire a vmblock control file
+descriptor, but we want to get rid of it. Specifically, this will be useful for remote
+DnD where there might not be a process with root permission.
+
+/version - NEW. XXX: Maybe we want to add a read-only file which contains a version
+number? This would allow us to make changes later and have it be easy for the tools to
+know what they can do.
+
+
+Internal Design
+---------------
+Uses FUSE's default multithreaded mode where normally, each filesystem request is serviced
+by it's own thread. This will allow accesses to block without preventing new accesses.
+
+IMPORTANT: Please read the deadlock section for more about the threading model.
+
+I'm using the common blocking code that the rest of the vmblock implementations share. It
+stores blocks as a linked list of structs which contain the direct path of the file being
+blocked (eg: "/tmp/VMwareDnD/foo/bar"), variables to link it into the list, an id of the
+control file which caused the block, a completion/condition variable, and a reference
+count. The purpose of the ref count is so that the block instance is only cleaned up once
+all threads waiting on it have woken up. Or more specifically, so that the last thread to
+wake up knows that the block isn't being used any more and will clean it up.
+
+The common blocking code uses a few constructs which are defined by port specific headers
+(os.h). For vmblock-fuse, the global blocked list will be protected by a pthread rwlock.
+Blocking will be done by waiting on condition variables. The completion type is a struct
+containing a mutex, condition variable, and done int (treated as a bool). Macros are
+defined to manipulate these properly. The atomic type used for reference counting is a
+vm_atomic type.
+
+
+Deadlock
+--------
+Older versions of fuse are limited to having 10 worker threads for processing filesystem
+requests. Once this limit is exceeded, fuse will block any operation until a thread
+becomes available to handle it. So if a block is placed on a file and many requests to
+access it are made and block, the filesystem will deadlock.
+
+This limit has been removed in fuse 2.6.0.
+The macfuse patch to fuse doesn't seem to affect this functionality and it's based off of
+fuse 2.7. I haven't testing it on macfuse though.
+
+Another possible deadlock from a fuse-devel email:
+
+On Wed, 9 Jul 2008, bargav yaarov wrote:
+
+> I have a point within my read handler where I hold a pthread_rwlock_t. At the same
+> time, another read handler is blocked waiting to acquire this lock. Now, if I attempt
+> to unmount at this time, the fuse library code calls pthread_cancel() against the
+> handling thread and I am left in a deadlocked state. How do you suggest I handle this
+> situation?
+
+Actually, CVS version of fuse has a fix for this:
+
+    * Only enable cancelation when reading a request, otherwise cancellation could happen
+      with a mutex held, which could hang the process on umount
+
+... OK, I put out a prerelease so there's no need to mess with CVS:
+
+http://sourceforge.net/project/showfiles.php?group_id=121684&package_id=140422
+
+XXX: Check if I hit this problem.
+
+
+Testing
+-------
+    * Some unit tests for fsops functions- bora/modules/vmblock/test/fuse-fsops-test.cpp.
+    * Existing full vmblock tester- bora/modules/vmblock/test/vmblocktest.c.
+    * Very simple testing program to block and unblock a single file- demo.c.
+
+
+Enforcing Permissions
+---------------------
+The vmblock-fuse code correctly report the file permissions but doesn't check them. It
+should be mounted with the "-o default_permissions" option which will tell fuse to do the
+checking for us.
+
+If the filesystem it going to be mounted by a non-root user for system wide use, it
+should also be given the "-o allow_other" option to allow users other than the one that
+mounted it to be able to use it. This will require enabling the "user_allow_other" option
+in /etc/fuse.conf.
+
+
+API
+---
+There are some helper functions, macros, and constants in the public header vmblock.h.
+I've added a new set of them which work with vmblock-fuse and I hope make using it API
+compatible with the other vmblock ports. I need to look at users of vmblock to make sure
+they access vmblock via the header the way I expect.
+
+
+Blocking Indexing Software
+--------------------------
+There are a number of program which may be running on various systems which index the
+contents of the computer. If an indexer was to hit a blocked file, it would get stuck
+which is undesireable. For the linux kernel port, the blocked files are in /proc which
+shouldn't be indexed. On solaris and freebsd, it's in /var/run which I guess is also not
+normally indexed. Right now, vmblock-fuse gets mounted for system wide use in
+/tmp/vmblock/.
+
+(s)locate/updatedb (linux)
+On ubuntu 8.04, /etc/updatedb.conf it set to ignore /tmp. I would guess this is pretty
+standard.
+
+beagle (linux)
+According to http://beagle-project.org/Indexing_Data, by default, everything in $(HOME)
+is indexed.
+
+spotlight (mac)
+I don't know if /tmp even exists on macs. I need to revisit this once I get vmblock-fuse
+running on mac.
+
+google desktop search (windows, linux)
+On linux, doesn't index /tmp. Also doesn't index hidden (.*) directories. This might be
+useful to know later on. In case it matters, a list of things that it doesn't search on
+windows is at http://desktop.google.com/support/bin/answer.py?answer=12634.
+
+
+Unprivileged User Blocking
+--------------------------
+If I have time later on, I'd like to investigate having non-root users be able to create
+blocks. This will be helpful for scenarios where we don't have a process with root
+privileges to do our blocking for us, like remote copy/paste. The security aspects need
+some careful thought but I'd like to jot down some notes on thoughts Elliot and I had
+about possible ways to do this.
+
+    * Have control file be accessible by any user as far as vmblock-fuse is concerned.
+      Have each user mount their own copy of vmblock which only they can access. Possibly
+      in their home dir. This will basically work with the current code if mounted
+      without the default_permissions option. I might want to change the permissions it
+      shows on the files.
+    * Have a single vmblock-fuse mount. Any user can add blocks but those blocks only
+      apply to accesses by that user.
diff --git a/open-vm-tools/vmblock-fuse/fsops.c b/open-vm-tools/vmblock-fuse/fsops.c
new file mode 100644 (file)
index 0000000..c649ec0
--- /dev/null
@@ -0,0 +1,725 @@
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * fsops.c --
+ *
+ *      Vmblock fuse filesystem operations.
+ *
+ *      See design.txt for more information.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <time.h>
+#include <stdint.h>
+
+#include "fsops.h"
+#include "block.h"
+#include "stubs.h"
+#include "vm_basic_types.h"
+
+/* Regular directories on a linux ext3 partition are 4K. */
+
+#define DIR_SIZE (4 * 1024)
+
+typedef struct vmblockSpecialDirEntry {
+   char *path;
+   int mode;
+   unsigned int nlink;
+   size_t size;
+} vmblockSpecialDirEntry;
+
+static vmblockSpecialDirEntry specialDirEntries[] = {
+   { "/",               S_IFDIR | 0555, 3, DIR_SIZE },
+   { CONTROL_FILE,      S_IFREG | 0200, 1, 0 },
+   { REDIRECT_DIR,      S_IFDIR | 0555, 3, DIR_SIZE },
+   { NULL,              0,              0, 0 }
+};
+static vmblockSpecialDirEntry symlinkDirEntry =
+   { REDIRECT_DIR "/*", S_IFLNK | 0777, 1, -1 };
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * RealReadLink --
+ *
+ *      Gets the target of a symlink.
+ *
+ *      The same idea as unix readlink() except that it returns 0 on
+ *      success, and fills buf with a null terminated string. If target doesn't
+ *      fit in buf, it is truncated.
+ *
+ * Results:
+ *      0 on success. Possible errors (as negative values):
+ *      -EINVAL       bufSize is not positive.
+ *      -ENOENT       path does not exist.
+ *      -ENAMETOOLONG path or target of symlink was too long.
+ *      Any other errors lstat can return.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+RealReadLink(const char *path,   // IN: Path within vmblock filesystem. Must be
+                                 //     within the redirect directory.
+             char *buf,          // OUT: Target of link if valid (or part of it).
+             size_t bufSize)     // IN: Size of buf.
+{
+   int status;
+   const char redirectPrefix[] = REDIRECT_DIR "/";
+   const int redirectPrefixLength = sizeof redirectPrefix - 1;
+   const char targetPrefix[] = TARGET_DIR "/";
+   const int targetPrefixLength = sizeof targetPrefix - 1;
+   const char *relativeTarget = path + redirectPrefixLength;
+   char target[PATH_MAX + 1];
+   const size_t spaceForRelativeTarget = sizeof target - targetPrefixLength;
+   struct stat dummyStatBuf; // Don't care what goes here.
+
+   /* TARGET_DIR + '/' needs to leave room for relative target. */
+   ASSERT_ON_COMPILE(sizeof TARGET_DIR + 1 < PATH_MAX);
+
+   ASSERT(strncmp(path, redirectPrefix, redirectPrefixLength) == 0 &&
+          strlen(path) > redirectPrefixLength);
+   if (bufSize < 1) {
+      return -EINVAL;
+   }
+
+   /*
+    * Assemble path to destination of link. This goes into a temporary buffer
+    * instead of directly into buf, because buf may not be big enough for the
+    * whole thing, but this should still return success if the target
+    * exists which means it must lstat the full target path.
+    */
+
+   strlcpy(target, targetPrefix, sizeof target);
+
+   /*
+    * spaceForRelativeTarget must be greater than strlen(relativeTarget) to
+    * leave room for the nul terminator.
+    */
+
+   if (spaceForRelativeTarget <= strlen(relativeTarget)) {
+      return -ENAMETOOLONG;
+   }
+   strlcpy(target + targetPrefixLength, relativeTarget, spaceForRelativeTarget);
+
+   /* Verify that target exists. */
+
+   status = lstat(target, &dummyStatBuf);
+   if (status != 0) {
+      return -errno;
+   }
+
+   strlcpy(buf, target, bufSize);
+   return 0;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMBlockReadLink --
+ *
+ *      Gets the target of a symlink. Blocks if there is a block on the path.
+ *
+ *      Basically the same as unix readlink() except that it returns 0 on
+ *      success, fills buf with a null terminated string, and adds our blocking
+ *      functionality.
+ *
+ * Results:
+ *      0 on success. Possible errors (as negative values):
+ *      -EINVAL       bufSize is not positive.
+ *      -ENOENT       path is not within the redirect directory.
+ *      -ENAMETOOLONG path or target of symlink was too long.
+ *      Any other errors lstat can return.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+VMBlockReadLink(const char *path,   // IN: Path within vmblock (top level) mount point.
+                char *buf,          // OUT: Target of link if valid (or part of it).
+                size_t bufSize)     // IN: Size of buf.
+{
+   int status;
+   char target[PATH_MAX + 1];
+
+   if (strncmp(path, REDIRECT_DIR, strlen(REDIRECT_DIR)) != 0) {
+      return -ENOENT;
+   }
+   status = RealReadLink(path, target, sizeof target);
+   if (status < 0) {
+      return status;
+   }
+
+   BlockWaitOnFile(target, NULL);
+
+   strlcpy(buf, target, bufSize);
+   return 0;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SetTimesToNow --
+ *
+ *      Sets the atime, mtime, and ctime of a stat struct to the current time.
+ *      If there's an error getting the current time, sets them to 0.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+SetTimesToNow(struct stat *statBuf)      // OUT
+{
+   int status;
+   struct timeval time;
+
+   status = gettimeofday(&time, NULL);
+   if (status < 0) {
+      statBuf->st_atime = statBuf->st_mtime = statBuf->st_ctime = 0;
+   } else {
+      statBuf->st_atime = statBuf->st_mtime = statBuf->st_ctime = time.tv_sec;
+   }
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMBlockGetAttr --
+ *
+ *      Gets the attributes of a directory entry. Equivalent to stat().
+ *
+ *      Returns fixed results for /, /dev, and /blockdir. For anything within
+ *      /blockdir, if a target exists with that name in the target directory,
+ *      it returns fixed stats for a symlink. Reads the stats to return from the
+ *      globals specialDirEntries and symlinkDirEntries.
+ *
+ * Results:
+ *      0 on success. Possible errors (as negative values):
+ *      -ENOENT  File or directory does not exist.
+ *      -ENAMETOOLONG path too long.
+ *      Any other errors lstat can return.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+VMBlockGetAttr(const char *path,        // IN: File to get attributes of.
+               struct stat *statBuf)    // OUT: Where to put the attributes.
+{
+   int status;
+   char target[PATH_MAX + 1];
+   vmblockSpecialDirEntry *dirEntry;
+   ASSERT(path != NULL);
+   ASSERT(statBuf != NULL);
+
+   if (strlen(path) > PATH_MAX) {
+      return -ENAMETOOLONG;
+   }
+
+   for (dirEntry = specialDirEntries; dirEntry->path != NULL; ++dirEntry) {
+      if (strcmp(path, dirEntry->path) == 0) {
+         memset(statBuf, 0, sizeof *statBuf);
+         statBuf->st_mode = dirEntry->mode;
+         statBuf->st_nlink = dirEntry->nlink;
+         statBuf->st_size = dirEntry->size;
+         SetTimesToNow(statBuf);
+         return 0;
+      }
+   }
+   if (strncmp(path, REDIRECT_DIR, strlen(REDIRECT_DIR)) == 0) {
+      status = RealReadLink(path, target, sizeof target);
+      LOG(4, "Called RealReadLink which returned: %d\n", status);
+      if (status != 0) {
+         return status;
+      }
+      memset(statBuf, 0, sizeof *statBuf);
+      statBuf->st_mode = symlinkDirEntry.mode;
+      statBuf->st_nlink = symlinkDirEntry.nlink;
+      statBuf->st_size = strlen(target);
+      SetTimesToNow(statBuf);
+      return 0;
+   }
+   return -ENOENT;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * ExternalReadDir --
+ *
+ *      Gets the contents of a directory outside the vmblock-fuse filesystem.
+ *
+ * Results:
+ *      0 on success. Possible errors (as negative values):
+ *      -EACCES  Permission denied.
+ *      -EBADF   Invalid directory stream descriptor (I don't think this can
+ *               happen).
+ *      -EMFILE  Too many file descriptors in use by process.
+ *      -ENFILE  Too many files are currently open in the system.
+ *      -ENOENT  Directory does not exist, or name is an empty string.
+ *      -ENOMEM  Insufficient memory to complete the operation.
+ *      -ENOTDIR path is not a directory.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+ExternalReadDir(const char *path,                // IN: Full (real) path to
+                                                 //     directory to read.
+                void *buf,                       // OUT: Destination for
+                                                 //      directory listing.
+                fuse_fill_dir_t filler,          // IN: Function to use to add
+                                                 //     an entry to buf. Returns
+                                                 //     1 if buffer full, 0
+                                                 //     otherwise.
+                off_t offset,                    // IN: Ignored.
+                struct fuse_file_info *fileInfo) // IN: Ignored.
+{
+   int status;
+   struct dirent *dentry = NULL;
+   struct stat statBuf;
+   DIR *dir = NULL;
+
+   LOG(4, "ExternalReadDir: path: %s\n", path);
+   dir = opendir(path);
+   if (dir == NULL) {
+      return -errno;
+   }
+
+   /*
+    * readdir() only needs to fill in the type bits of the mode in the stat
+    * struct it passes to filler().
+    * http://sourceforge.net/mailarchive/forum.php?thread_name=E1KNlwx-00008e-Fb%40pomaz-ex.szeredi.hu&forum_name=fuse-devel
+    */
+
+   memset(&statBuf, 0, sizeof statBuf);
+   statBuf.st_mode = S_IFLNK;
+
+   /* Clear errno because readdir won't change it if it succeeds. */
+
+   errno = 0;
+   while ((dentry = readdir(dir)) != NULL) {
+      status = filler(buf, dentry->d_name, &statBuf, 0);
+      if (status == 1) {
+         break;
+      }
+   }
+   if (errno != 0) {
+      return -errno;
+   }
+
+   status = closedir(dir);
+   if (status != 0) {
+      return -errno;
+   }
+   return 0;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMBlockReadDir --
+ *
+ *      Gets the contents of a directory within the filesystem.
+ *
+ *      If filler() runs out of memory, it will store an error in buf (which fuse
+ *      will check) and then return 1.
+ *      http://sourceforge.net/mailarchive/forum.php?thread_name=E1KMUnu-0007gI-29%40pomaz-ex.szeredi.hu&forum_name=fuse-devel
+ *
+ * Results:
+ *      0 on success or filler() fail. Possible errors (as negative values):
+ *      -EACCES  Permission denied.
+ *      -EBADF   Invalid directory stream descriptor (I don't think this can
+ *               happen).
+ *      -EMFILE  Too many file descriptors in use by process.
+ *      -ENFILE  Too many files are currently open in the system.
+ *      -ENOENT  Directory does not exist, or name is an empty string.
+ *      -ENOMEM  Insufficient memory to complete the operation.
+ *      -ENOTDIR path is not a directory.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+VMBlockReadDir(const char *path,                // IN: Directory to read.
+               void *buf,                       // OUT: Where to put directory
+                                                //      listing.
+               fuse_fill_dir_t filler,          // IN: Function to add an entry
+                                                //     to buf.
+               off_t offset,                    // IN: Ignored.
+               struct fuse_file_info *fileInfo) // IN: Ignored.
+{
+   struct stat fileStat;
+   struct stat dirStat;
+   LOG(4, "VMBlockReadDir: path: %s\n", path);
+
+   /*
+    * readdir() only needs to fill in the type bits of the mode in the stat
+    * struct it passes to filler().
+    * http://sourceforge.net/mailarchive/forum.php?thread_name=E1KNlwx-00008e-Fb%40pomaz-ex.szeredi.hu&forum_name=fuse-devel
+    */
+
+   memset(&fileStat, 0, sizeof fileStat);
+   fileStat.st_mode = S_IFREG;
+   memset(&dirStat, 0, sizeof dirStat);
+   dirStat.st_mode = S_IFDIR;
+
+   if (strcmp(path, "/") == 0) {
+      (void)(filler(buf, ".", &dirStat, 0) ||
+             filler(buf, "..", &dirStat, 0) ||
+             filler(buf, VMBLOCK_DEVICE_NAME, &fileStat, 0) ||
+             filler(buf, REDIRECT_DIR_NAME, &dirStat, 0));
+      return 0;
+   } else if (strcmp(path, REDIRECT_DIR) == 0) {
+      return ExternalReadDir(TARGET_DIR, buf, filler, offset, fileInfo);
+   } else {
+      return -ENOENT;
+   }
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMBlockOpen --
+ *
+ *      Opens the control file. Trying to open anything else will fail.
+ *
+ *      The file handle that is filled into fileInfo is a memory address so it
+ *      can be any number that is at least 1 and at most (void *)(-1);
+ *
+ *      fileInfo will be marked as requiring direct io. This disables any
+ *      caching, which may not be needed, but can't hurt. It also somehow helps
+ *      allow the offset to advance past 4k which matters if we take out seeking
+ *      to 0 before writing.
+ *
+ * Results:
+ *      0 on success. Possible errors (as negative values):
+ *      -EACCES  Tried to open the control file in anything other than write-
+ *               only mode. We don't need to check user/group permissions
+ *               because fuse will do that if we want them enforced.
+ *      -ENOENT  path is anything other than the control file.
+ *      -ENOMEM  Not enough memory available.
+ *      If this was a proper file system, it would probably do additional
+ *      checking and return -EISDIR or -ENAMETOOLONG in the right situations,
+ *      but we don't care about that. If it's not the control file, it's
+ *      -ENOENT.
+ *
+ * Side effects:
+ *      Allocates one byte of memory, the address of which is used as a unique
+ *      identifier of the open file.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+VMBlockOpen(const char *path,                   // IN
+            struct fuse_file_info *fileInfo)    // IN/OUT
+{
+   /*
+    * The blocking code needs a unique value associated with each open file to
+    * know who owns what block. The memory address of a malloc()ed byte is used
+    * for this purpose.
+    */
+
+   char *uniqueValue = NULL;
+
+   if (strcmp(path, CONTROL_FILE) != 0) {
+      return -ENOENT;
+   }
+   if ((fileInfo->flags & O_WRONLY) == 0) {
+      return -EACCES;
+   }
+   uniqueValue = malloc(sizeof *uniqueValue);
+   if (uniqueValue == NULL) {
+      return -ENOMEM;
+   }
+   fileInfo->fh = CharPointerToFuseFileHandle(uniqueValue);
+   fileInfo->direct_io = 1;
+   return 0;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * StripExtraPathSeparators --
+ *
+ *      Removes extra repeated '/' characters from a null terminated string.
+ *      Eg: "/foo//bar" -> "/foo/bar".
+ *      Also removes any trailing '/'s from the string.
+ *
+ *      Sometimes programs wind up building paths with extra '/'s in them which
+ *      works, but we want to know that they're the same for blocking purposes.
+ *      Similarly, we want /foo/bar/ and /foo/bar to match.
+ *
+ * Results:
+ *      path has extra separators removed (see above).
+ *      Returns the new length of the string.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+size_t
+StripExtraPathSeparators(char *path)      // IN/OUT: nul terminated string.
+{
+   unsigned int i;
+   size_t length;
+   Bool lastCharWasSep = FALSE;
+
+   ASSERT(path != NULL);
+   length = strlen(path);
+
+   for (i = 0; i < length; i++) {
+      if (path[i] == '/') {
+         if (lastCharWasSep) {
+            memmove(path + i - 1, path + i, length - i + 1);
+            --length;
+            ASSERT(i > 0);
+            --i;
+         } else {
+            lastCharWasSep = TRUE;
+         }
+      } else {
+         lastCharWasSep = FALSE;
+      }
+   }
+
+   /*
+    * Strip trailing slash when appropriate.
+    */
+
+   if (length > 1 && path[length - 1] == '/') {
+      --length;
+   }
+
+   path[length] = '\0';
+   return length;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMBlockWrite --
+ *
+ *      Writes to the control file to perform a blocking operation.
+ *
+ *      The write is the means by which a file block is add or removed. In a
+ *      development build, it also allows all blocks to be listed. The desired
+ *      operation is indicated by the first character in buf. Constants are
+ *      defined in vmblock.h:
+ *      VMBLOCK_ADD_FILEBLOCK: Add block
+ *      VMBLOCK_DEL_FILEBLOCK: Remove block
+ *      VMBLOCK_LIST_FILEBLOCKS: List blocks (only with VMX86_DEVEL)
+ *
+ *      The control file must already be open.
+ *
+ * Results:
+ *      Returns size argument on success. Possible errors (as negative values):
+ *      -EINVAL Operation character is not a valid value.
+ *      -ENAMETOOLONG File to be blocked is too long.
+ *      -ENOENT Tried to remove a block that doesn't exist.
+ *      Maybe others.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+VMBlockWrite(const char *path,                 // IN: Must be control file.
+             const char *buf,                  // IN: Operation and file operand.
+                                               //     Not nul terminated for
+                                               //     consistency with other
+                                               //     special fses, eg: procfs.
+             size_t size,                      // IN: Size of buf.
+             off_t offset,                     // IN: Ignored.
+             struct fuse_file_info *fileInfo)  // IN: Ignored.
+{
+   int status;
+   char trimmedBuf[PATH_MAX + 1];
+   os_blocker_id_t blockerId;
+
+   LOG(4, "VMBlockWrite: path: %s, size: %"FMTSZ"u\n", path, size);
+   LOG(4, "fileInfo->fh: %p\n", FuseFileHandleToCharPointer(fileInfo->fh));
+   ASSERT(strcmp(path, CONTROL_FILE) == 0);
+   if (size > PATH_MAX) {
+      return -ENAMETOOLONG;
+   }
+
+   memcpy(trimmedBuf, buf, size);
+   trimmedBuf[size] = '\0';
+   LOG(4, "buf: %s\n", trimmedBuf);
+   StripExtraPathSeparators(trimmedBuf);
+
+   blockerId = FuseFileHandleToCharPointer(fileInfo->fh);
+   switch (trimmedBuf[0]) {
+   case VMBLOCK_ADD_FILEBLOCK:
+      status = BlockAddFileBlock(trimmedBuf + 1, blockerId);
+      break;
+   case VMBLOCK_DEL_FILEBLOCK:
+      status = BlockRemoveFileBlock(trimmedBuf + 1, blockerId);
+      break;
+#ifdef VMX86_DEVEL
+   case VMBLOCK_LIST_FILEBLOCKS:
+      BlockListFileBlocks();
+      status = 0;
+      break;
+#endif // VMX86_DEVEL
+   default:
+      status = -EINVAL;
+   }
+   return status == 0 ? size : status;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMBlockRelease --
+ *
+ *      Releases an open (control) file. Removes any blocks created via this
+ *      file.
+ *
+ * Results:
+ *      Returns 0.
+ *
+ * Side effects:
+ *      Free's the memory allocated as a unique identifier for the open file.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+VMBlockRelease(const char *path,                   // IN: Must be control file.
+               struct fuse_file_info *fileInfo)    // IN/OUT: Contains fh which is
+                                                   //         freed.
+{
+   char *blockerId = FuseFileHandleToCharPointer(fileInfo->fh);
+
+   ASSERT(path);
+   ASSERT(fileInfo);
+   ASSERT(strcmp(path, CONTROL_FILE) == 0);
+   ASSERT(blockerId != NULL);
+   BlockRemoveAllBlocks(blockerId);
+   free(blockerId);
+   blockerId = NULL;
+   fileInfo->fh = CharPointerToFuseFileHandle(NULL);
+   return 0;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMBlockInit --
+ *
+ *      Initializes the filesystem.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      Calls BlockInit which allocates memory and does other initialization.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void *
+VMBlockInit(void)
+{
+   Atomic_Init();
+   BlockInit();
+   return NULL;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMBlockDestroy --
+ *
+ *      Cleans up after the filesystem.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      Calls BlockDestroy which frees memory and does other cleanup.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+VMBlockDestroy(void *private_data)    // IN: Not used.
+{
+   BlockCleanup();
+}
+
+
+struct fuse_operations vmblockOperations = {
+   .readlink = VMBlockReadLink,
+   .getattr  = VMBlockGetAttr,
+   .readdir  = VMBlockReadDir,
+   .open     = VMBlockOpen,
+   .write    = VMBlockWrite,
+   .release  = VMBlockRelease,
+   .init     = VMBlockInit,
+   .destroy  = VMBlockDestroy
+};
diff --git a/open-vm-tools/vmblock-fuse/fsops.h b/open-vm-tools/vmblock-fuse/fsops.h
new file mode 100644 (file)
index 0000000..759a0cb
--- /dev/null
@@ -0,0 +1,102 @@
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * fsops.h --
+ *
+ *      Vmblock fuse filesystem operations.
+ *
+ *      The file ops and internal functions are prototyped here and the main
+ *      function put in a separate file to enable unit testing of these
+ *      functions directly. This is also the reason none of the functions are
+ *      static.
+ */
+
+#ifndef _VMBLOCK_FUSE_H_
+#define _VMBLOCK_FUSE_H_
+
+/*
+ * FUSE_USE_VERSION sets the version of the FUSE API that will be exported.
+ * Version 25 is the newest version supported by the libfuse in our toolchain
+ * as of 2008-07.
+ */
+
+#define FUSE_USE_VERSION 25
+#include <fuse.h>
+
+#include "vmblock.h"
+#include "vm_assert.h"
+#include "vm_basic_types.h"
+
+#define REDIRECT_DIR_NAME VMBLOCK_CONTROL_MOUNTPOINT
+#define REDIRECT_DIR "/" VMBLOCK_CONTROL_MOUNTPOINT
+#define TARGET_DIR "/tmp/VMwareDnD"
+#define CONTROL_FILE "/" VMBLOCK_DEVICE_NAME
+
+/*
+ * FS operation functions
+ */
+
+int VMBlockReadLink(const char *path, char *buf, size_t bufSize);
+int VMBlockGetAttr(const char *path, struct stat *statBuf);
+int VMBlockReadDir(const char *path, void *buf, fuse_fill_dir_t filler,
+                   off_t offset, struct fuse_file_info *fileInfo);
+int VMBlockOpen(const char *path, struct fuse_file_info *fileInfo);
+int VMBlockWrite(const char *path, const char *buf, size_t size, off_t offset,
+                 struct fuse_file_info *fileInfo);
+int VMBlockRelease(const char *path, struct fuse_file_info *fileInfo);
+
+extern struct fuse_operations vmblockOperations;
+
+/*
+ * Internal functions
+ */
+
+int RealReadLink(const char *path, char *buf, size_t bufSize);
+void SetTimesToNow(struct stat *statBuf);
+int ExternalReadDir(const char *path, void *buf, fuse_fill_dir_t filler,
+                    off_t offset, struct fuse_file_info *fileInfo);
+size_t StripExtraPathSeparators(char *path);
+
+
+/*
+ * CharPointerToFuseFileHandle and FuseFileHandleToCharPointer --
+ *
+ *      Simple functions to keep all typecasting in one place.
+ *
+ *      Storing a pointer in the fh field of fuse_file_info is the recommended
+ *      way to associate a pointer with an open file according to the fuse FAQ:
+ *      http://fuse.sourceforge.net/wiki/index.php/FAQ#Is_it_possible_to_store_a_pointer_to_private_data_in_the_fuse_file_info_structurex3f.
+ */
+
+static INLINE uint64_t
+CharPointerToFuseFileHandle(const char *pointer)               // IN
+{
+   ASSERT(sizeof (uint64_t) >= sizeof (char *));
+   return (uintptr_t)(pointer);
+}
+
+static INLINE char *
+FuseFileHandleToCharPointer(const uint64_t fileHandle)   // IN
+{
+   ASSERT(fileHandle <= (uintptr_t)((void *)(-1)));
+   return (char *)((uintptr_t)(fileHandle));
+}
+
+
+#endif /* _VMBLOCK_FUSE_H_ */
diff --git a/open-vm-tools/vmblock-fuse/main.c b/open-vm-tools/vmblock-fuse/main.c
new file mode 100644 (file)
index 0000000..de602ac
--- /dev/null
@@ -0,0 +1,70 @@
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * main.c --
+ *
+ *      Entry point for vmblock-fuse file system.
+ */
+
+#include <string.h>
+#include <stdio.h>
+
+#include "fsops.h"
+
+int LOGLEVEL_THRESHOLD = 0;
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * main --
+ *
+ *      Entry point for the vmblock-fuse file system. Calls fuse_main(). See
+ *      http://fuse.sourceforge.net/doxygen/fuse_8h.html#3bf31250361d44c2436d76f47f2400ed
+ *      for more information.
+ *
+ *      There are many command line options that fuse filesystems can take. Run
+ *      with --help for a listing or consult the fuse documentation.
+ *      Options which are likely to be usefor for vmblock-fuse are
+ *      -o default_permissions and -o allow_other.
+ *
+ *      If the -d option is specified, enables our logging in addition to
+ *      what fuse does.
+ *
+ * Results:
+ *      Returns 0 on success and nonzero on failure.
+ *
+ * Side effects:
+ *      None/all.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+main(int argc,           // IN
+     char *argv[])       // IN
+{
+   int i;
+   for (i = 1; i < argc && strcmp(argv[i], "--") != 0; ++i) {
+      if (strcmp(argv[i], "-d") == 0) {
+         LOGLEVEL_THRESHOLD = 4;
+      }
+   }
+   return fuse_main(argc, argv, &vmblockOperations);
+}
diff --git a/open-vm-tools/vmblock-fuse/os.h b/open-vm-tools/vmblock-fuse/os.h
new file mode 100644 (file)
index 0000000..ef18959
--- /dev/null
@@ -0,0 +1,158 @@
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *********************************************************/
+
+
+/*
+ * os.h --
+ *
+ *      OS-specific definitions.
+ */
+
+
+#ifndef __OS_H__
+#define __OS_H__
+
+#include <limits.h>
+#include <errno.h>
+#include <pthread.h>
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "vm_atomic.h"
+#include "vm_assert.h"
+
+typedef pthread_rwlock_t                os_rwlock_t;
+typedef void                            os_kmem_cache_t; // Not used.
+typedef struct os_completion_t {
+       pthread_cond_t cv;
+       pthread_mutex_t mutex;
+       int completed;
+}                                       os_completion_t;
+typedef Atomic_Int                      os_atomic_t;
+typedef char *                          os_blocker_id_t;
+
+#define OS_UNKNOWN_BLOCKER              0
+#define OS_ENOMEM                       (-ENOMEM)
+#define OS_ENOENT                       (-ENOENT)
+#define OS_EEXIST                       (-EEXIST)
+#define OS_PATH_MAX                     PATH_MAX
+
+#define OS_FMTTID                       "u"
+#define os_threadid                     ((unsigned)(pthread_self()))
+
+#define os_panic(fmt, args)             \
+({                                      \
+   fprintf(stderr, fmt, args);          \
+   abort();                             \
+})
+
+#define os_rwlock_init(lock)            pthread_rwlock_init(lock, NULL)
+#define os_rwlock_destroy(lock)         pthread_rwlock_destroy(lock)
+
+/*
+ * XXX I don't know of anything better for os_rwlock_held that pthreads offers.
+ */
+
+#define os_rwlock_held(lock)            TRUE
+#define os_read_lock(lock)              pthread_rwlock_rdlock(lock)
+#define os_write_lock(lock)             pthread_rwlock_wrlock(lock)
+#define os_read_unlock(lock)            pthread_rwlock_unlock(lock)
+#define os_write_unlock(lock)           pthread_rwlock_unlock(lock)
+
+/*
+ * os_kmem_cache_create can't evaluate to NULL because there's a !NULL check
+ * on its result.
+ */
+
+#define os_kmem_cache_create(name, size, align, ctor)  ((void *)1)
+#define os_kmem_cache_destroy(cache)
+#define os_kmem_cache_alloc(cache)                     malloc(sizeof(struct BlockInfo))
+#define os_kmem_cache_free(cache, elem)                free(elem)
+
+/*
+ * Completion Functions
+ */
+
+#define os_completion_init(comp)                        \
+({                                                      \
+   pthread_cond_init(&(comp)->cv, NULL);                \
+   pthread_mutex_init(&(comp)->mutex, NULL);            \
+   (comp)->completed = 0;                               \
+})
+#define os_completion_destroy(comp)                     \
+({                                                      \
+   pthread_cond_destroy(&(comp)->cv);                   \
+   pthread_mutex_destroy(&(comp)->mutex);               \
+})
+#define os_wait_for_completion(comp)                    \
+({                                                      \
+    pthread_mutex_lock(&(comp)->mutex);                 \
+    while ((comp)->completed == 0) {                    \
+       pthread_cond_wait(&(comp)->cv, &(comp)->mutex);  \
+    }                                                   \
+    pthread_mutex_unlock(&(comp)->mutex);               \
+    0;                                                  \
+})
+#define os_complete_all(comp)                           \
+({                                                      \
+    pthread_mutex_lock(&(comp)->mutex);                 \
+    (comp)->completed = 1;                              \
+    pthread_cond_broadcast(&(comp)->cv);                \
+    pthread_mutex_unlock(&(comp)->mutex);               \
+    0;                                                  \
+})
+
+/*
+ * Atomic Value Functions
+ *
+ * os_atomic_dec_and_test needs to test against 1 because ReadDecInt returns
+ * the value before the dec.
+ */
+
+#define os_atomic_dec_and_test(atomic)  (Atomic_ReadDecInt(atomic) == 1)
+#define os_atomic_dec                   Atomic_DecInt
+#define os_atomic_set                   Atomic_WriteInt
+#define os_atomic_inc                   Atomic_IncInt
+
+/*
+ * Extra stuff fuse port needs defined (ie not in os.h for other ports).
+ */
+
+#ifdef VMX86_DEVEL
+extern int LOGLEVEL_THRESHOLD;
+#  define LOG(level, fmt, args...)                              \
+     ((void) (LOGLEVEL_THRESHOLD >= (level) ?                   \
+              fprintf(stderr, "DEBUG:  " fmt, ## args) :        \
+              0)                                                \
+     )
+#else
+#  define LOG(level, fmt, args...)
+#endif
+#define Warning(fmt, args...)                                   \
+     fprintf(stderr, "WARNING: " fmt, ## args)
+
+/*
+ * The GNU C library doesn't include strlcpy.
+ * XXX: This prototype is moving. See util.c.
+ */
+
+size_t strlcpy(char *dest, const char *src, size_t count);
+
+#endif /* __OS_H__ */
diff --git a/open-vm-tools/vmblock-fuse/stubs.c b/open-vm-tools/vmblock-fuse/stubs.c
new file mode 100644 (file)
index 0000000..34dfe3e
--- /dev/null
@@ -0,0 +1,54 @@
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *********************************************************/
+
+
+/*
+ * stubs.c --
+ *
+ *      Common stubs.
+ */
+
+#include <stdarg.h>
+
+#include "os.h"
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * Panic --
+ *
+ *    Panic implementation.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+void
+Panic(const char *fmt, ...)
+{
+   va_list args;
+
+   va_start(args, fmt);
+   os_panic(fmt, args);
+   va_end(args);
+}
diff --git a/open-vm-tools/vmblock-fuse/stubs.h b/open-vm-tools/vmblock-fuse/stubs.h
new file mode 100644 (file)
index 0000000..6f8aab0
--- /dev/null
@@ -0,0 +1,36 @@
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *********************************************************/
+
+
+/*
+ * stubs.h --
+ *
+ */
+
+
+#ifndef __STUBS_H__
+#define __STUBS_H__
+
+#if defined(linux) && !defined(vmblock_fuse)
+# include "driver-config.h"
+# include "compat_version.h"
+#endif
+
+void Panic(const char *fmt, ...);
+
+#endif /* __STUBS_H__ */
diff --git a/open-vm-tools/vmblock-fuse/util.c b/open-vm-tools/vmblock-fuse/util.c
new file mode 100644 (file)
index 0000000..1b1f12c
--- /dev/null
@@ -0,0 +1,53 @@
+/*********************************************************
+ * Copyright (C) 2008 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *********************************************************/
+
+#include <string.h>
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * strlcpy --
+ *
+ *    XXX: Copied from vmblock/linux/module.c. Share them.
+ *
+ *    Copies at most count - 1 bytes from src to dest, and ensures dest is NUL
+ *    terminated.
+ *
+ * Results:
+ *    Length of src.  If src >= count, src was truncated in copy.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+size_t
+strlcpy(char *dest,         // OUT: destination to copy string to
+        const char *src,    // IN : source to copy string from
+        size_t count)       // IN : size of destination buffer
+{
+   size_t ret;
+   size_t len;
+
+   ret = strlen(src);
+   len = ret >= count ? count - 1 : ret;
+   memcpy(dest, src, len);
+   dest[len] = '\0';
+   return ret;
+}
diff --git a/open-vm-tools/vmware-user/copyPasteV3.h b/open-vm-tools/vmware-user/copyPasteV3.h
new file mode 100644 (file)
index 0000000..cdd9ab7
--- /dev/null
@@ -0,0 +1,90 @@
+/*********************************************************
+ * Copyright (C) 2007 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * copyPaste.h --
+ *
+ *     Handles the linux specific copy paste operations.
+ *
+ *     TODO: Data conversion out into another class to be shared between dnd
+ *     and copypaste.
+ */
+
+#ifndef LUI_COPYPASTE_HH
+#define LUI_COPYPASTE_HH
+
+#include "cui/dnd/copyPaste.hh"
+#include "cui/vm.hh"
+
+extern "C" {
+#include "dnd.h"
+#include "../dnd/dndClipboard.h"
+}
+
+namespace lui {
+   class CopyPaste
+      : public sigc::trackable
+   {
+   public:
+      CopyPaste(cui::dnd::CopyPaste *cp);
+      ~CopyPaste(void);
+
+      void UpdateLocalClipboard(void);
+      void UpdateRemoteClipboard(void);
+
+   private:
+      /* gh */
+      void GetRemoteClipboardCB(const CPClipboard *clip);
+      void RemoteGetFilesDone(void);
+      /* clipboard stuff */
+      void LocalGetFileRequestCB(Gtk::SelectionData& selection_data, guint info);
+      void LocalClearClipboardCB(void);
+
+      /* hg */
+      /* Clipboard stuff */
+      void LocalClipboardTimestampCB(const Gtk::SelectionData& sd);
+      void LocalPrimTimestampCB(const Gtk::SelectionData& sd);
+      void LocalReceivedTargetsCB(const Glib::StringArrayHandle& targets_array);
+      void LocalReceivedFileListCB(const Gtk::SelectionData& selection_data);
+      void LocalReceivedTextCB(const Glib::ustring& text);
+
+      /* Convertion methods. */
+      void LocalGetSelectionFileList(const Gtk::SelectionData& sd);
+      utf::utf8string GetNextPath(utf::utf8string &str, size_t& index);
+      utf::string GetLastDirName(const utf::string &str);
+
+      cui::dnd::CopyPaste * const mCP;
+
+      CPClipboard mClipboard;
+      bool mIsClipboardOwner;
+      uint64 mClipTime;
+      uint64 mPrimTime;
+      GdkAtom mHGSelection;
+
+      /* File vars. */
+      bool mGHGetFilesInitated;
+      VmTimeType mGHGetListTime;
+      utf::string mGHCopiedUriList;
+      utf::utf8string mGHFCPData;
+
+      std::list<Gtk::TargetEntry> mListTargets;
+   };
+
+} //namespace lui
+
+#endif // LUI_COPYPASTE_HH