]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
2009.08.24-187411 2009.08.24-187411
authorMarcelo Vanzin <mvanzin@mvanzin-dev1.eng.vmware.com>
Mon, 24 Aug 2009 21:43:39 +0000 (14:43 -0700)
committerMarcelo Vanzin <mvanzin@mvanzin-dev1.eng.vmware.com>
Mon, 24 Aug 2009 21:43:39 +0000 (14:43 -0700)
170 files changed:
open-vm-tools/ChangeLog
open-vm-tools/NEWS
open-vm-tools/configure.ac
open-vm-tools/docs/api/services/utils.txt
open-vm-tools/lib/Makefile.am
open-vm-tools/lib/appUtil/appUtil.c
open-vm-tools/lib/appUtil/appUtilX11.c
open-vm-tools/lib/dnd/dndLinux.c
open-vm-tools/lib/file/file.c
open-vm-tools/lib/file/fileIO.c
open-vm-tools/lib/file/fileIOPosix.c
open-vm-tools/lib/file/filePosix.c
open-vm-tools/lib/foundryMsg/foundryMsg.c
open-vm-tools/lib/ghIntegration/ghIntegrationX11.c
open-vm-tools/lib/guestInfo/Makefile.am
open-vm-tools/lib/guestInfo/guestInfo.c
open-vm-tools/lib/guestInfo/guestInfoInt.h
open-vm-tools/lib/guestInfo/guestInfoPosix.c
open-vm-tools/lib/guestRpc/ghiCommonDefines.h
open-vm-tools/lib/guestRpc/ghiGetExecInfoHash.x
open-vm-tools/lib/guestRpc/nicinfo.x
open-vm-tools/lib/hgfsBd/hgfsBd.c
open-vm-tools/lib/hgfsHelper/Makefile.am [new file with mode: 0644]
open-vm-tools/lib/hgfsHelper/hgfsHelperPosix.c [new file with mode: 0644]
open-vm-tools/lib/hgfsServer/hgfsServer.c
open-vm-tools/lib/hgfsServer/hgfsServerInt.h
open-vm-tools/lib/hgfsServer/hgfsServerLinux.c
open-vm-tools/lib/hgfsServerPolicyGuest/hgfsServerPolicyGuest.c
open-vm-tools/lib/image/imageUtilPng.c
open-vm-tools/lib/include/appUtil.h
open-vm-tools/lib/include/buildNumber.h
open-vm-tools/lib/include/community_source.h [new file with mode: 0644]
open-vm-tools/lib/include/file.h
open-vm-tools/lib/include/fileIO.h
open-vm-tools/lib/include/guestCaps.h
open-vm-tools/lib/include/guestInfo.h
open-vm-tools/lib/include/hgfsHelper.h [new file with mode: 0644]
open-vm-tools/lib/include/hgfsProto.h
open-vm-tools/lib/include/hgfsServerPolicy.h
open-vm-tools/lib/include/hostinfo.h
open-vm-tools/lib/include/imageUtil.h
open-vm-tools/lib/include/loglevel_user.h
open-vm-tools/lib/include/netutil.h
open-vm-tools/lib/include/preference.h
open-vm-tools/lib/include/safetime.h
open-vm-tools/lib/include/slashProc.h [new file with mode: 0644]
open-vm-tools/lib/include/system.h
open-vm-tools/lib/include/unityCommon.h
open-vm-tools/lib/include/util.h
open-vm-tools/lib/include/util_shared.h
open-vm-tools/lib/include/vix.h
open-vm-tools/lib/include/vixCommands.h
open-vm-tools/lib/include/vm_basic_defs.h
open-vm-tools/lib/include/vm_basic_types.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/vmblock_user.h [new file with mode: 0644]
open-vm-tools/lib/include/vmtools.h
open-vm-tools/lib/include/wiper.h
open-vm-tools/lib/include/x86cpuid.h
open-vm-tools/lib/include/xdrutil.h
open-vm-tools/lib/misc/codesetOld.c
open-vm-tools/lib/misc/hostinfoPosix.c
open-vm-tools/lib/netUtil/netUtilLinux.c
open-vm-tools/lib/raster/rasterConv.c
open-vm-tools/lib/rpcChannel/rpcChannel.c
open-vm-tools/lib/slashProc/Makefile.am [new file with mode: 0644]
open-vm-tools/lib/slashProc/net.c [new file with mode: 0644]
open-vm-tools/lib/slashProc/slashProcNetInt.h [new file with mode: 0644]
open-vm-tools/lib/unity/unityPlatformX11Window.c
open-vm-tools/lib/unityWindowTracker/unityWindowTracker.c
open-vm-tools/lib/user/hostinfo.c
open-vm-tools/lib/user/util.c
open-vm-tools/lib/user/utilPosix.c
open-vm-tools/lib/vixTools/vixTools.c
open-vm-tools/lib/wiper/Makefile.am
open-vm-tools/lib/wiper/wiperCommon.c [new file with mode: 0644]
open-vm-tools/lib/wiper/wiperPosix.c
open-vm-tools/libvmtools/Makefile.am
open-vm-tools/libvmtools/signalSource.c
open-vm-tools/libvmtools/vmtools.c
open-vm-tools/libvmtools/vmtoolsConfig.c
open-vm-tools/libvmtools/vmtoolsLog.c
open-vm-tools/modules/freebsd/shared/compat_freebsd.h
open-vm-tools/modules/freebsd/shared/compat_mount.h [new file with mode: 0644]
open-vm-tools/modules/freebsd/shared/compat_priv.h [new file with mode: 0644]
open-vm-tools/modules/freebsd/shared/compat_vop.h
open-vm-tools/modules/freebsd/vmblock/subr.c
open-vm-tools/modules/freebsd/vmblock/vfsops.c
open-vm-tools/modules/freebsd/vmblock/vnops.c
open-vm-tools/modules/freebsd/vmmemctl/os.c
open-vm-tools/modules/freebsd/vmmemctl/os.h
open-vm-tools/modules/freebsd/vmmemctl/vmballoon.c
open-vm-tools/modules/linux/dkms.conf
open-vm-tools/modules/linux/dkms.sh
open-vm-tools/modules/linux/pvscsi/pvscsi.c
open-vm-tools/modules/linux/pvscsi/scsi_defs.h
open-vm-tools/modules/linux/shared/compat_pci.h
open-vm-tools/modules/linux/shared/compat_skbuff.h
open-vm-tools/modules/linux/shared/vmci_call_defs.h
open-vm-tools/modules/linux/shared/vmci_infrastructure.h
open-vm-tools/modules/linux/shared/vmci_iocontrols.h
open-vm-tools/modules/linux/shared/vmci_queue_pair.h
open-vm-tools/modules/linux/vmblock/linux/control.c
open-vm-tools/modules/linux/vmblock/linux/dentry.c
open-vm-tools/modules/linux/vmblock/linux/file.c
open-vm-tools/modules/linux/vmblock/linux/filesystem.c
open-vm-tools/modules/linux/vmblock/linux/filesystem.h
open-vm-tools/modules/linux/vmblock/linux/inode.c
open-vm-tools/modules/linux/vmblock/linux/module.c
open-vm-tools/modules/linux/vmblock/linux/os.h
open-vm-tools/modules/linux/vmblock/linux/super.c
open-vm-tools/modules/linux/vmblock/linux/vmblockInt.h
open-vm-tools/modules/linux/vmci/vmciGuestKernelIf.c
open-vm-tools/modules/linux/vmci/vmciKernelIf.c
open-vm-tools/modules/linux/vmci/vmci_drv.c
open-vm-tools/modules/linux/vmci/vmci_version.h
open-vm-tools/modules/linux/vmhgfs/dir.c
open-vm-tools/modules/linux/vmhgfs/fsutil.c
open-vm-tools/modules/linux/vmhgfs/fsutil.h
open-vm-tools/modules/linux/vmhgfs/inode.c
open-vm-tools/modules/linux/vmhgfs/link.c
open-vm-tools/modules/linux/vmmemctl/os.c
open-vm-tools/modules/linux/vmmemctl/os.h
open-vm-tools/modules/linux/vmmemctl/vmballoon.c
open-vm-tools/modules/linux/vmxnet3/vmxnet3_drv.c
open-vm-tools/modules/linux/vmxnet3/vmxnet3_int.h
open-vm-tools/modules/linux/vmxnet3/vmxnet3_shm.c
open-vm-tools/modules/linux/vmxnet3/vmxnet3_shm_shared.h
open-vm-tools/modules/linux/vmxnet3/vmxnet3_version.h
open-vm-tools/modules/linux/vsock/linux/af_vsock.c
open-vm-tools/modules/linux/vsock/linux/af_vsock.h
open-vm-tools/modules/linux/vsock/linux/notify.c
open-vm-tools/modules/linux/vsock/linux/notify.h
open-vm-tools/modules/linux/vsock/linux/notifyQState.c [new file with mode: 0644]
open-vm-tools/modules/linux/vsock/linux/util.c
open-vm-tools/modules/linux/vsock/linux/vsockPacket.h
open-vm-tools/modules/shared/vmxnet/vmnet_def.h
open-vm-tools/modules/shared/vmxnet/vmxnet3_defs.h
open-vm-tools/modules/solaris/vmmemctl/os.c
open-vm-tools/modules/solaris/vmmemctl/os.h
open-vm-tools/modules/solaris/vmmemctl/vmballoon.c
open-vm-tools/services/plugins/guestInfo/guestInfoServer.c
open-vm-tools/services/plugins/hgfsServer/hgfsPlugin.c
open-vm-tools/services/plugins/resolutionSet/resolutionSet.c
open-vm-tools/services/plugins/vix/Makefile.am
open-vm-tools/services/plugins/vix/foundryToolsDaemon.c
open-vm-tools/services/plugins/vmbackup/stateMachine.c
open-vm-tools/services/vmtoolsd/mainLoop.c
open-vm-tools/services/vmtoolsd/mainPosix.c
open-vm-tools/services/vmtoolsd/pluginMgr.c
open-vm-tools/services/vmtoolsd/toolsCoreInt.h
open-vm-tools/services/vmtoolsd/toolsRpc.c
open-vm-tools/tests/Makefile.am
open-vm-tools/tests/testVmblock/COPYING [new file with mode: 0644]
open-vm-tools/tests/testVmblock/Makefile.am [new file with mode: 0644]
open-vm-tools/tests/testVmblock/manual-blocker.c [new file with mode: 0644]
open-vm-tools/tests/testVmblock/vmblocktest.c [new file with mode: 0644]
open-vm-tools/toolbox/toolbox-cmd.c
open-vm-tools/toolbox/toolboxCmdInt.h
open-vm-tools/toolbox/toolboxInt.h
open-vm-tools/toolbox/toolboxShrink.c
open-vm-tools/toolbox/toolboxcmd-scripts.c
open-vm-tools/toolbox/toolboxcmd-shrink.c
open-vm-tools/toolbox/toolboxcmd-stat.c
open-vm-tools/vmware-user/Makefile.am
open-vm-tools/vmware-user/copyPasteUI.cpp
open-vm-tools/vmware-user/stringxx/string.cc
open-vm-tools/vmware-user/stringxx/string.hh

index 1dc113ec9164304baeb8b6305d1e82e17f21b58b..410e3237105e19e163a5a6bac641c441020d7a55 100644 (file)
@@ -1,3 +1,115 @@
+2009-08-24     Marcelo Vanzin   <mvanzin@vmware.com>
+       * Resync with internal trunk (2009.08.19)
+
+       * configure.ac: remove support for Linux kernels < 2.6.9.
+
+       * lib/include/vmtools.h, libvmtools/vmtoolsLog.c, doc/api/services/util.txt:
+         add new log handled that allows appending to existing log files, and fix
+         an issue where old log files would be "rotated" whenever the config file
+         was reloaded.
+
+       * lib/appUtil/appUtilX11.c, lib/ghIntegration/ghIntegrationX11.c,
+         lib/include/appUtil.h: fix compilation issues on FreeBSD when unity
+         was enabled.
+
+       * lib/dnd/dndLinux.c, lib/include/vmblock_user.h, tests/testVmblock/*: add
+         vmblock tests and, as part of the change, do some refactoring of vmblock
+         related functions.
+
+       * lib/guestInfo/guestInfo.c, lib/include/wiper.h, lib/wiper/*,
+         toolbox/toolboxcmd-shrink.c, toolbox/toolboxShrink.c: refactor the wiper
+         structures so that they behave the same on Win32 and other platforms, and
+         also reuse data structures already in use by other parts of the code. This
+         fixes an "use after free" issue that toolbox-cmd had on Win32.
+
+       * lib/guestInfo/guestInfo.c, lib/guestInfo/guestInfoInt.h,
+         lib/guestInfo/guestInfoPosix.c, lib/guestRpc/nicinfo.x,
+         lib/include/guestInfo.h, lib/include/netutil.h, lib/include/slashProc.h,
+         lib/netutil/netUtilLinux.c, lib/slashProc/*,
+         services/plugins/guestInfo/guestInfoServer.c: add support for sending more
+         network-related information to the host, such as routing tables and name
+         servers.
+
+       * lib/hgfsBd/hgfsBd.c: don't log RPC errors when HGFS is disabled.
+
+       * lib/hgfsHelper/*, lib/include/hgfsHelper.h, lib/vixTools/vixTools.c: new
+         library with functions to query information about HGFS; expose some HGFS
+         properties through VIX.
+
+       * lib/hgfsServer/*, lib/hgfsServerPolicyGuest/hgfsServerPolicyGuest.c,
+         lib/include/hgfsServerPolicy.h: fix checking of whether an object belongs
+         to a particular share; this was causing issues with invalid information
+         being returned in certain cases.
+
+       * lib/hgfsServer/*, lib/include/hgfsProto.h: changes to support new VIX API
+         calls (mostly affecting Win32 only).
+
+       * lib/include/guestCaps.h, lib/include/unityCommon.h: add boilerplate for new
+         RPCs for setting windows as sticky / non-sticky (not yet implemented).
+
+       * lib/include/hgfsProto.h: new definitions for the next version of the HGFS
+         protocol.
+
+       * lib/include/xdrutil.h: make XDRUTIL_ARRAYAPPEND() more type-safe when using
+         GCC.
+
+       * lib/misc/codesetOld.c: fix some issues with UTF16 -> UTF8 conversion.
+
+       * lib/rpcChannel/rpcChannel.c, libvmtools/signalSource.c,
+         libvmtools/vmtools.c, libvmtools/vmtoolsConfig.c: g_assert -> ASSERT.
+
+       * lib/unityWindowTracker/unityWindowTracker.c: fix issue with z-ordering of
+         modal dialogs.
+
+       * libvmtools/vmtoolsConfig.c: fix some old config translation issues.
+
+       * modules/freebsd/shared/*, modules/freebsd/vmblock/*: make vmblock work on
+         FreeBSD 8.
+
+       * modules/freebsd/vmmemctl/*, modules/linux/vmmemctl/*,
+         modules/solaris/vmmemctl/*, : refactoring and code changes to support the
+         driver on Mac OS X.
+
+       * modules/linux/vmblock/*, modules/linux/vmci/*, modules/linux/vsock/linux/*:
+         remove compatibility code for older kernels.
+
+       * modules/linux/vmhgfs/*: fix memory leak in HgfsAccessInt().
+
+       * modules/linux/vmxnet3/*: fix kunmap usage in vmxnet3_shm, and reset the
+         shared pages when the char device is closed.
+
+       * modules/linux/vsock/linux/af_vsock.{c,h}, modules/linux/vsock/linux/util.c:
+         add vsock protocol negotiation for notifyOn ops. This allows the driver to
+         negotiate with the remove end which version of the notification protocol to
+         use.
+
+       * modules/linux/vsock/linux/notify.c, modules/linux/vsock/linux/notify.h,
+         modules/linux/vsock/linux/notifyQState.c,
+         modules/linux/vsock/linux/vsockPacket.h: add pktOn protocol. This new
+         protocol improves performance by detecting changes in the queue state
+         instead of sending WAITING_READ and WAITING_WRITE packets.
+
+       * services/plugins/hgfsServer/hgfsPlugin.c,
+         services/plugins/resolutionSet/resolutionSet.c,
+         services/vmtoolsd/mainLoop.c, services/vmtoolsd/pluginMgr.c,
+         services/vmtoolsd/toolsRpc.c: load plugins even when an RPC channel cannot
+         be instantiated (i.e., when running outside of a virtual machine); this
+         allows plugins to perform actions (at load time) also when running outside
+         virtual machines (e.g., to undo some configuration done when the OS was run
+         in a VM).
+
+       * services/vmtoolsd/mainLoop.c, services/vmtoolsd/mainPosix.c,
+         services/vmtoolsd/toolsCoreInt.h: handle SIGHUP differently; instead of
+         stopping the service, just re-load the config data. This should make it
+         easier to integrate the tools service with other tools such as logrotate.
+
+       * toolbox/toolbox-cmd.c, toolbox/toolboxcmd-stat.c: remove memory info query,
+         which didn't really return useful information.
+
+       * vmware-user/copyPasteUI.cpp: if the clipboard/primary with most recent
+         timestamp has no data on it, try the other before giving up during
+         copy/paste.
+
 2009-07-22     Marcelo Vanzin   <mvanzin@vmware.com>
        * Resync with internal trunk (2009.07.17)
 
index d90f591ee3357208e890ddafddd20429e274bd38..96ffef1458030307ea7d83c5c80f74e2283392c2 100644 (file)
@@ -1,3 +1,14 @@
+open-vm-tools 2009.08.24 changes:
+       * Remove support for Linux kernels < 2.6.9.
+
+       * The vsock now implements a new notification protocol that has better
+       performance than the previous.
+
+       * New infrastructure for sending more network config-related information
+       about the virtual machine to the host.
+
+       * Other bug fixes and minor improvements to the code.
+
 open-vm-tools 2009.07.22 changes:
        * Better support for dkms by means of a script to help create a dkms tree.
 
index 720b8b3fd5a8dc4fced4c025858b6936aed224dc..7eb54c9c2293ccbc06cdb287b5d38e7ddfa288ad 100644 (file)
 ### Initialization
 ###
 
-TOOLS_VERSION="2009.07.22"
+TOOLS_VERSION="2009.08.24"
 AC_INIT(
    [open-vm-tools],
-   [2009.07.22],
+   [2009.08.24],
    [open-vm-tools-devel@lists.sourceforge.net])
 
 # In order to make this configure script auto-detect situations where
@@ -138,6 +138,9 @@ osVersion="`getOsVersion`"
 if test "$with_kernel_modules" = "yes"; then
    case "$os" in
       linux)
+         if test "$osVersion" -lt 206009; then
+            AC_MSG_ERROR([Kernels prior to 2.6.9 are not supported in this release of open-vm-tools. Configure using --without-kernel-modules to suppress building kernel drivers.])
+         fi
          if test ! -d "$LINUXDIR/kernel/"; then
              AC_MSG_ERROR([$LINUXDIR/kernel does not exist])
          fi
@@ -928,22 +931,10 @@ if test "$os" = "linux"; then
    CPPFLAGS="$CPPFLAGS -D_BSD_SOURCE"
    CPPFLAGS="$CPPFLAGS -D_SVID_SOURCE"
 
-   if test "$osVersion" -ge 202000; then
-      MODULES="$MODULES vmmemctl vmxnet"
-   fi
-   if test "$osVersion" -ge 204000; then
-      MODULES="$MODULES vmblock vmci vmhgfs vsock"
-      buildHgfsmounter=yes
-   fi
-   if test "$osVersion" -ge 206000; then
-      MODULES="$MODULES vmxnet3"
-   fi
-   if test "$osVersion" -ge 206006; then
-      MODULES="$MODULES vmsync"
-   fi
-   if test "$osVersion" -ge 206008; then
-      MODULES="$MODULES pvscsi"
-   fi
+   MODULES="$MODULES vmmemctl vmsync vmci vsock"
+   MODULES="$MODULES vmxnet vmxnet3 pvscsi"
+   MODULES="$MODULES vmblock vmhgfs"
+   buildHgfsmounter=yes
 fi
 
 if test "$os" = "freebsd"; then
@@ -1172,6 +1163,7 @@ AC_CONFIG_FILES([                      \
    lib/guestRpc/Makefile               \
    lib/hgfs/Makefile                   \
    lib/hgfsBd/Makefile                 \
+   lib/hgfsHelper/Makefile             \
    lib/hgfsServer/Makefile             \
    lib/hgfsServerManagerGuest/Makefile \
    lib/hgfsServerPolicyGuest/Makefile  \
@@ -1192,6 +1184,7 @@ AC_CONFIG_FILES([                      \
    lib/rpcOut/Makefile                 \
    lib/rpcVmx/Makefile                 \
    lib/SLPv2Parser/Makefile            \
+   lib/slashProc/Makefile              \
    lib/string/Makefile                 \
    lib/stubs/Makefile                  \
    lib/sync/Makefile                   \
@@ -1234,6 +1227,7 @@ AC_CONFIG_FILES([                      \
    tests/vmrpcdbg/Makefile             \
    tests/testDebug/Makefile            \
    tests/testPlugin/Makefile           \
+   tests/testVmblock/Makefile          \
    docs/Makefile                       \
    docs/api/Makefile                   \
    scripts/Makefile                   \
index e92743a7f85d2a8a5c2594382c956c912dbe5803..dbb710f2627d279d45da0bcaad8724d15c53cdf4 100644 (file)
@@ -47,10 +47,11 @@ for each domain are:
      - Valid values: error, critical, warning, message, info, debug, none
      - This value is required when configuring a domain.
    - handler: the handler to use when logging.
-     - Valid values: std, outputdebugstring (Win32-only), file
+     - Valid values: std, outputdebugstring (Win32-only), file, file+
+       (same as "file", but appends to existing log file).
      - Default: "std" on Unix, "outputdebugstring" on Windows.
    - data: optional configuration data for the handler.
-     - Required for the "file" handler (path to log file).
+     - Required for the "file" handlers (path to log file).
 
 Logging configuration should be under the "[logging]" group in the
 application's configuration file.
index c83035ff0ec2ac64aeea3ca8071960f988c74600..7214393eb731d30b6597433ce56f89a9dd36685f 100644 (file)
@@ -42,6 +42,7 @@ SUBDIRS += guestApp
 SUBDIRS += guestInfo
 SUBDIRS += hgfs
 SUBDIRS += hgfsBd
+SUBDIRS += hgfsHelper
 SUBDIRS += hgfsServer
 SUBDIRS += hgfsServerManagerGuest
 SUBDIRS += hgfsServerPolicyGuest
@@ -67,6 +68,9 @@ SUBDIRS += rpcChannel
 SUBDIRS += rpcIn
 SUBDIRS += rpcOut
 SUBDIRS += rpcVmx
+if LINUX
+   SUBDIRS += slashProc
+endif
 SUBDIRS += SLPv2Parser
 SUBDIRS += string
 SUBDIRS += stubs
index 99bd9270626c831355ecf2f528ffd900c5a15f11..a6c149bb6807a561844c493951f34586c5a56e32 100644 (file)
@@ -38,7 +38,7 @@
  * AppUtil_SendGuestCaps --
  *
  *     Send a list of guest capabilities to the host.
- *
+ * 
  * Results:
  *     None.
  *
index b37b22eaf201bea0cdf6b7fd7a50bd092842e725..5ac358e69b66a9f214381f1449e89c9d68da23ab 100644 (file)
@@ -36,6 +36,7 @@
 #error "Gtk 2.0 is required"
 #endif
 
+#include <libgen.h>
 #include <glib.h>
 #include <gtk/gtk.h>
 #include <gdk/gdkx.h>
index 8e37a4a9cce0c11a6ecdb059740084d3ffc02a3f..94cb81e7dcf80691fc663cc4768f7446ff00d9c0 100644 (file)
@@ -40,7 +40,7 @@
 #include "escape.h"
 #include "su.h"
 #if defined(linux) || defined(sun) || defined(__FreeBSD__)
-#include "vmblock.h"
+#include "vmblock_user.h"
 #include "mntinfo.h"
 #endif
 
@@ -261,43 +261,6 @@ DnD_UriListGetNextFile(char const *uriList,  // IN    : text/uri-list string
 /* We need to make this suck less. */
 #if defined(linux) || defined(sun) || defined(__FreeBSD__)
 
-#if defined(linux)
-
-static INLINE int
-VMBLOCK_CONTROL(int fd, int op, const char *path)
-{
-   return write(fd, path, op);
-}
-
-#elif defined(__FreeBSD__)
-
-static INLINE int
-VMBLOCK_CONTROL(int fd, int cmd, const char *path)
-{
-   char tpath[MAXPATHLEN];
-
-   if (path != NULL) {
-      /*
-       * FreeBSD's ioctl data parameters must be of fixed size.  Guarantee a safe
-       * buffer of size MAXPATHLEN by copying the user's string to one of our own.
-       */
-      strlcpy(tpath, path, MAXPATHLEN);
-   }
-
-   return ioctl(fd, cmd, tpath);
-}
-
-#elif defined(sun)
-
-static INLINE int
-VMBLOCK_CONTROL(int fd, int cmd, const char *path)
-{
-   return ioctl(fd, cmd, path);
-}
-
-#endif
-
-
 /*
  *----------------------------------------------------------------------------
  *
@@ -390,66 +353,6 @@ DnD_CheckBlockLegacy(int blockFd)                    // IN
 }
 
 
-/*
- * DnD_VmblockFuseControl --
- *
- *    Controlling function for FUSE-based blocker implementation.
- *    Passes requests to block and unblock file access to fuse module.
- *
- * Results:
- *    0 on success, -1 on failure.
- *
- * Notes:
- *    None.
- *
- */
-
-static ssize_t
-DnD_VmblockFuseControl(int fd,            // IN
-                       char op,           // IN
-                       const char *path)  // IN
-{
-   /*
-    * buffer needs room for an operation character and a string with max length
-    * PATH_MAX - 1.
-    */
-
-   char buffer[PATH_MAX];
-   size_t pathLength;
-
-   pathLength = strlen(path);
-   if (pathLength >= PATH_MAX) {
-      errno = ENAMETOOLONG;
-      return -1;
-   }
-
-   buffer[0] = op;
-   memcpy(buffer + 1, path, pathLength);
-
-   /*
-    * The lseek is only to prevent the file pointer from overflowing;
-    * vmblock-fuse ignores the file pointer / offset. Overflowing the file
-    * pointer causes write to fail:
-    * http://article.gmane.org/gmane.comp.file-systems.fuse.devel/6648
-    * There's also a race condition here where many threads all calling
-    * VMBLOCK_CONTROL at the same time could have all their seeks executed one
-    * after the other, followed by all the writes. Again, it's not a problem
-    * unless the file pointer overflows which is very unlikely with 32 bit
-    * offsets and practically impossible with 64 bit offsets.
-    */
-
-   if (lseek(fd, 0, SEEK_SET) < 0) {
-      return -1;
-   }
-
-   if (write(fd, buffer, pathLength + 1) < 0) {
-      return -1;
-   }
-
-   return 0;
-}
-
-
 /*
  *----------------------------------------------------------------------------
  *
@@ -473,8 +376,8 @@ DnD_AddBlockFuse(int blockFd,                    // IN
 {
    ASSERT(blockFd >= 0);
 
-   if (DnD_VmblockFuseControl(blockFd, VMBLOCK_FUSE_ADD_FILEBLOCK,
-                              blockPath) != 0) {
+   if (VMBLOCK_CONTROL_FUSE(blockFd, VMBLOCK_FUSE_ADD_FILEBLOCK,
+                            blockPath) != 0) {
       LOG(1, ("%s: Cannot add block on %s (%s)\n",
               __func__, blockPath, strerror(errno)));
       return FALSE;
@@ -505,8 +408,8 @@ DnD_RemoveBlockFuse(int blockFd,                    // IN
                     const char *blockedPath)        // IN
 {
    if (blockFd >= 0) {
-      if (DnD_VmblockFuseControl(blockFd, VMBLOCK_FUSE_DEL_FILEBLOCK,
-                                 blockedPath) != 0) {
+      if (VMBLOCK_CONTROL_FUSE(blockFd, VMBLOCK_FUSE_DEL_FILEBLOCK,
+                               blockedPath) != 0) {
          Log("%s: Cannot delete block on %s (%s)\n",
              __func__, blockedPath, strerror(errno));
          return FALSE;
index 10833932e5a1e333d6bd7e2ffac92af2f9f31360..9f918e491345529bdd3bfad5601112914b7e75bc 100644 (file)
@@ -31,6 +31,7 @@
 #if defined(_WIN32)
 #include <io.h>
 #define S_IXUSR    0100
+#define S_IWUSR    0200
 #else
 #include <unistd.h>
 #endif
@@ -1942,7 +1943,17 @@ File_DeleteDirectoryTree(ConstUnicode pathName)  // IN: directory to delete
       } else {
          /* is file, delete */
          if (File_Unlink(curPath) == -1) {
+#if defined(_WIN32)
+            if (File_SetFilePermissions(curPath, S_IWUSR)) {
+               if (File_Unlink(curPath) == -1) {
+                  sawFileError = TRUE;
+               }
+            } else {
+               sawFileError = TRUE;
+            }
+#else
             sawFileError = TRUE;
+#endif
          }
       }
 
index b21531a45c1351d2399075d4346b1132faaad7ad..9f7380a1546fbfda77b2b37d0d576187e10856ac 100644 (file)
@@ -273,13 +273,20 @@ FileIO_Lock(FileIODescriptor *file, // IN/OUT:
 
          /* Return a serious failure status if the locking code did */
          switch (err) {
-         case 0:             // file is currently locked
+         case 0:             // File is currently locked
+         case EROFS:         // Attempt to lock for write on RO FS
             ret = FILEIO_LOCK_FAILED;
             break;
-         case ENAMETOOLONG:  // path is too long
+         case ENAMETOOLONG:  // Path is too long
             ret = FILEIO_FILE_NAME_TOO_LONG;
             break;
-         default:            // some sort of locking error
+         case ENOENT:        // No such file or directory
+            ret = FILEIO_FILE_NOT_FOUND;
+            break;
+         case EACCES:       // Permissions issues
+            ret = FILEIO_NO_PERMISSION;
+            break;
+         default:            // Some sort of locking error
             ret = FILEIO_ERROR;
          }
       }
index d07a8c5b8de4019b9cf396ae284284eb2d56b00e..a8634eddfadb66fc53b6b1143e71f287e326e642 100644 (file)
 #include "unicodeOperations.h"
 #include "memaligned.h"
 
-#if defined(__APPLE__)
+#if defined(__APPLE__) || defined(__linux__)
 #include "hostinfo.h"
+#endif
+
+#if defined(__APPLE__)
+#include <sys/sysctl.h>
 #define XATTR_BACKUP_REENABLED "com.vmware.backupReenabled"
 #endif
 
-/* 
+/*
  * fallocate() is only supported since the glibc-2.8 and
- * linux kernel-2.6.23.Presently the glibc in our toolchain is 2.3 
+ * linux kernel-2.6.23. Presently the glibc in our toolchain is 2.3.
  */
 #ifdef __linux__
-   #ifndef SYS_fallocate 
+   #ifndef SYS_fallocate
       #ifdef __i386__
-         #define SYS_fallocate 324   
-      #elif __x86_64__ 
-         #define SYS_fallocate 285 
+         #define SYS_fallocate 324
+      #elif __x86_64__
+         #define SYS_fallocate 285
       #endif
    #endif
-   #ifndef FALLOC_FL_KEEP_SIZE 
-       #define FALLOC_FL_KEEP_SIZE 1
-   #endif      
+   #ifndef FALLOC_FL_KEEP_SIZE
+      #define FALLOC_FL_KEEP_SIZE 1
+   #endif
 #endif
 
 static const unsigned int FileIO_SeekOrigins[] = {
@@ -136,6 +140,7 @@ typedef struct FilePosixOptions {
    Bool enabled;
    int countThreshold;
    int sizeThreshold;
+   int aioNumThreads;
 } FilePosixOptions;
 
 #if defined(__APPLE__)
@@ -235,6 +240,8 @@ FileIO_OptionalSafeInitialize(void)
          Config_GetLong(5, "filePosix.coalesce.count");
       filePosixOptions.sizeThreshold =
          Config_GetLong(16*1024, "filePosix.coalesce.size");
+      filePosixOptions.aioNumThreads =
+         Config_GetLong(0, "aiomgr.numThreads");
       filePosixOptions.initialized = TRUE;
    }
 }
@@ -1687,9 +1694,8 @@ FileIO_Preadv(FileIODescriptor *fd,    // IN: File descriptor
          ssize_t retval = pread(fd->posix, buf, leftToRead, fileOffset);
 
          if (retval == -1) {
-            if (errno == EINTR || errno == EAGAIN) {
-               LOG_ONCE((LGPFX" %s got %s.  Retrying\n",
-                         __FUNCTION__, errno == EINTR ? "EINTR" : "EAGAIN"));
+            if (errno == EINTR) {
+               LOG_ONCE((LGPFX" %s got EINTR.  Retrying\n", __FUNCTION__));
                NOT_TESTED_ONCE();
                continue;
             }
@@ -1787,9 +1793,8 @@ FileIO_Pwritev(FileIODescriptor *fd,   // IN: File descriptor
          ssize_t retval = pwrite(fd->posix, buf, leftToWrite, fileOffset);
 
          if (retval == -1) {
-            if (errno == EINTR || errno == EAGAIN) {
-               LOG_ONCE((LGPFX" %s got %s.  Retrying\n",
-                         __FUNCTION__, errno == EINTR ? "EINTR" : "EAGAIN"));
+            if (errno == EINTR) {
+               LOG_ONCE((LGPFX" %s got EINTR.  Retrying\n", __FUNCTION__));
                NOT_TESTED_ONCE();
                continue;
             }
@@ -1878,7 +1883,7 @@ FileIO_GetAllocSize(const FileIODescriptor *fd)  // IN
    ASSERT(fd);
 
 #if __linux__ && defined(N_PLAT_NLM)
-   /* Netware doesn't have st_blocks.  Just fall back to GetSize. */ 
+   /* Netware doesn't have st_blocks.  Just fall back to GetSize. */
    return FileIO_GetSize(fd);
 #else
    /*
@@ -1902,7 +1907,7 @@ FileIO_GetAllocSize(const FileIODescriptor *fd)  // IN
  *      TRUE on success.  Sets errno on failure.
  *
  * Side effects:
- *      None
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -1923,7 +1928,7 @@ FileIO_SetAllocSize(const FileIODescriptor *fd,  // IN
    if (curSize > size) {
       errno = EINVAL;
       return FALSE;
-   }   
+   }
    preallocLen = size - curSize;
 
 #ifdef __APPLE__
@@ -1935,8 +1940,17 @@ FileIO_SetAllocSize(const FileIODescriptor *fd,  // IN
 
    return fcntl(fd->posix, F_PREALLOCATE, &prealloc) != -1;
 #elif __linux__
-   return syscall(SYS_fallocate, fd->posix, FALLOC_FL_KEEP_SIZE, 
-                 curSize, preallocLen) == 0;
+   {
+      int ret;
+
+      ret = syscall(SYS_fallocate, fd->posix, FALLOC_FL_KEEP_SIZE,
+                    curSize, preallocLen);
+      if (ret == 0) {
+         return TRUE;
+      }
+      errno = ret;
+      return FALSE;
+   }
 #endif
 
 #else
@@ -2416,6 +2430,174 @@ exit:
    return result;
 }
 
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * HostSupportsPrealloc --
+ *
+ *      Returns TRUE if the host OS is new enough to support F_PREALLOCATE
+ *      without data loss bugs.  On OSX, this has been verified fixed
+ *      on 10.6 build with kern.osreleasae 10.0.0d6.
+ *
+ * Results:
+ *      TRUE if the current host OS is new enough.
+ *      FALSE if it is not or we can't tell because of an error.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static Bool
+HostSupportsPrealloc(void)
+{
+   char curRel[32];
+   char type;
+   unsigned static const int req[] = { 10, 0, 0, 6 };
+   unsigned int cur[4], i;
+   int num;
+   size_t len = sizeof(curRel);
+   Bool ret = FALSE;
+
+   if (sysctlbyname("kern.osrelease", (void *) &curRel, &len, NULL, 0) == -1) {
+      goto exit;
+   }
+
+   curRel[31] = '\0';
+   Log("Current OS Release is %s\n", curRel);
+
+   /*
+    * Apple's osversion is in the format X.Y.Z which maps to the public
+    * OSX version 10.X-4.Y, and Z is incremented for each publicly
+    * released build.  The Z part is of the form A<type>B, where a and
+    * B are version numbers and <type> is either d (devel), a (alpha),
+    * b (beta), rc, or fc.  If the <type>B is missing, then its a GA build.
+    *
+    * Since we're checking for 10.0.0d6, we can just say anything without
+    * a type or with a type other than d is higher.  For d, we compare
+    * the last number.
+    */
+
+   num = sscanf(curRel, "%u.%u.%u%c%u", &cur[0], &cur[1], &cur[2], &type,
+                &cur[3]);
+   if (num < 3) {
+      goto exit;
+   }
+
+   for (i = 0; i < 3; i++) {
+      if (req[i] > cur[i]) {
+         goto exit;
+      } else if (req[i] < cur[i]) {
+         ret = TRUE;
+         goto exit; 
+      }
+   }
+   if (num == 5 && type == 'd') {
+      ret = req[3] <= cur[3];
+      goto exit;
+   }
+   /*
+    * If we get a type with no letter (num == 4), thats odd.
+    * Consider it mal-formatted and fail.
+    */
+   ret = num != 4;
+
+exit:
+   if (!ret && filePosixOptions.initialized && 
+       filePosixOptions.aioNumThreads == 1) {
+      ret =TRUE;
+   } 
+   return  ret;
+}
+
+#else
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * HostSupportsPrealloc --
+ *
+ *      fallocate() is supported for ext4 and xfs since 2.6.23 kernels
+ *
+ * Results:
+ *      TRUE if the current host is linux and kernel is >= 2.6.23.
+ *      FALSE if it is not .
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static Bool
+HostSupportsPrealloc(void)
+{
+#if  (defined(__linux__ ) && !defined(VMX86_SERVER))
+    if (Hostinfo_OSVersion(0) >=2 && Hostinfo_OSVersion(1) >=6 &&
+        Hostinfo_OSVersion(2) >=23) {
+       return TRUE;
+    }
+#endif
+    return FALSE;
+}
+
 #endif
 
 
+/*
+ *----------------------------------------------------------------------------
+ *
+ * FileIO_SupportsPrealloc --
+ *
+ *      Checks if the HostOS/filesystem supports preallocation.
+ *
+ * Results:
+ *      TRUE if supported by the Host OS/filesystem.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+Bool
+FileIO_SupportsPrealloc(const char *pathName,   // IN
+                        Bool fsCheck)           // IN
+{
+   Bool ret = TRUE;
+
+   if (!HostSupportsPrealloc()) {
+      return FALSE;
+   }
+
+   if (!fsCheck) {
+         return ret;
+   }
+
+#if (defined( __linux__) && !defined(VMX86_SERVER))
+   {
+      struct statfs statBuf;
+      Unicode fullPath;
+
+      ret = FALSE;
+      if (!pathName) {
+         return ret;
+      }
+
+      fullPath = File_FullPath(pathName);
+      if (!fullPath) {
+         return ret;
+      }
+
+      if (Posix_Statfs(fullPath, &statBuf) == 0 &&
+         statBuf.f_type == EXT4_SUPER_MAGIC) {
+         ret = TRUE;
+      }
+      Unicode_Free(fullPath);
+   }
+#endif
+   return ret;
+}
+
index 2912f888ed0966f1d18e66c8e853e9477116c3dc..f5d955bc131f03c55b6e5437ac8b81546a6b7dad 100644 (file)
@@ -1005,26 +1005,69 @@ File_GetFreeSpace(ConstUnicode pathName,  // IN: File name
    if (statfsbuf.f_type == VMFS_MAGIC_NUMBER) {
       int fd;
       FS_FreeSpaceArgs args = { 0 };
-      Unicode directory = NULL;
+      Unicode specialPath = NULL;
+
+      /*
+       * If the file exists and can be opened we're all set. If the file
+       * doesn't exist we can use the parent directory for the ioctl.
+       * However, if the file exists and can't be opened (e.g. permissions
+       * issues) a correct answer can only be returned if the target isn't a
+       * directory. If the target is a directory its parent may be a mount
+       * point - leading across a mount point to a different file system.
+       * PR 412387
+       */
 
-      File_SplitName(fullPath, NULL, &directory, NULL);
-      /* Must use an ioctl() to get free space for a VMFS file. */
       ret = -1;
-      fd = Posix_Open(directory, O_RDONLY, 0);
+
+      fd = Posix_Open(fullPath, O_RDONLY, 0);
+
+      if (fd == -1) {
+         switch (errno) {
+         case EPERM:
+         case EACCES:
+            {
+               int err = errno;
+               struct stat statbuf;
+
+               if (Posix_Stat(fullPath, &statbuf) == -1) {
+                  errno = err;
+                  break;
+               }
+
+               if ((statbuf.st_mode & S_IFMT) == S_IFDIR) {
+                  Warning(LGPFX" %s: directory (%s) present but inaccessible\n",
+                          __func__, UTF8(fullPath));
+                  errno = err;
+                  break;
+               }
+            }
+            /* FALLTHROUGH */
+
+         case ENOENT:
+         default:
+            File_SplitName(fullPath, NULL, &specialPath, NULL);
+
+            fd = Posix_Open(specialPath, O_RDONLY, 0);
+         }
+      }
+
       if (fd == -1) {
          Warning(LGPFX" %s: open of %s failed with: %s\n", __func__,
-                 UTF8(directory), Msg_ErrString());
+                 (specialPath == NULL) ? UTF8(fullPath) : UTF8(specialPath),
+                 Msg_ErrString());
       } else {
          if (ioctl(fd, IOCTLCMD_VMFS_GET_FREE_SPACE, &args) == -1) {
             Warning(LGPFX" %s: ioctl on %s failed with: %s\n", __func__,
-                    UTF8(fullPath), Msg_ErrString());
+                    (specialPath == NULL) ? UTF8(fullPath) : UTF8(specialPath),
+                    Msg_ErrString());
          } else {
             ret = args.bytesFree;
          }
+
          close(fd);
       }
 
-      Unicode_Free(directory);
+      Unicode_Free(specialPath);
    }
 #endif
 
@@ -2818,36 +2861,3 @@ File_IsCharDevice(ConstUnicode pathName)  // IN:
    return (FileAttributes(pathName, &fileData) == 0) &&
            (fileData.fileType == FILE_TYPE_CHARDEVICE);
 }
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * File_SupportsPrealloc --
- *  
- *
- * Results:
- *      TRUE    if APPLE or file system type is ext2/ext3/ext4
- *      FALSE   if not supported by default in auto mode
- *
- * Side effects:
- *      None
- *
- *----------------------------------------------------------------------------
- */
-
-Bool
-File_SupportsPrealloc(const char *file)
-{
-
-#if (defined( __linux__) && !defined(VMX86_SERVER)) 
-   struct statfs statBuf;   
-   if (FileGetStats(file, FALSE, &statBuf) && 
-       statBuf.f_type == EXT4_SUPER_MAGIC) {
-       return TRUE;    
-   }
-#elif APPLE
-   return TRUE
-#endif 
-   return FALSE;
-}
index 6dc351976e7e1dca5bc711a37a5f4df3969605db..53bd7373a2585307bca10310bd7aba4aeda7cfda 100644 (file)
@@ -430,6 +430,11 @@ static const VixCommandInfo vixCommandInfoTable[] = {
    VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_REMOVE_BULK_SNAPSHOT,
                            VIX_COMMAND_CATEGORY_PRIVILEGED),
 
+   VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_COPY_FILE_FROM_READER_TO_GUEST,
+                           VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED),
+
+   VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_GENERATE_NONCE,
+                           VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED),
 };
 
 
@@ -760,6 +765,15 @@ VixMsg_ValidateRequestMsg(const void *vMsg, // IN
       return VIX_E_INVALID_MESSAGE_HEADER;
    }
 
+   if ((VIX_REQUESTMSG_INCLUDES_AUTH_DATA_V1 & message->requestFlags) &&
+       (message->commonHeader.totalMessageLength <
+          (uint64)message->commonHeader.headerLength +
+          message->commonHeader.bodyLength +
+          message->commonHeader.credentialLength +
+          sizeof (VixMsgAuthDataV1))) {
+      return VIX_E_INVALID_MESSAGE_HEADER;
+   }
+
    return VIX_OK;
 } // VixMsg_ValidateRequestMsg
 
index 312d42d372ac9912f77aabe17752cb40a10cc02b..7408b82b75c7d38db45196de260389d96adf52e4 100644 (file)
@@ -62,8 +62,8 @@
 #include "imageUtil.h"
 #include "strutil.h"
 #include <paths.h>
-#include <mntent.h>
 #include "vm_atomic.h"
+#include "mntinfo.h"
 #include "ghIntegration.h"
 #include "ghIntegrationInt.h"
 #include "guest_msg_def.h"
index a276f8176e762adbf7d7922cda308250384b08a9..cf06d4f4482a37c5ec9c12fdee4e6743301ea6f9 100644 (file)
@@ -21,5 +21,8 @@ libGuestInfo_la_SOURCES =
 libGuestInfo_la_SOURCES += guestInfo.c
 libGuestInfo_la_SOURCES += guestInfoPosix.c
 
+libGuestInfo_la_CPPFLAGS =
+libGuestInfo_la_CPPFLAGS += @GLIB2_CPPFLAGS@
+
 AM_CFLAGS = $(DNET_CPPFLAGS)
 
index 7d1c16277a0b57593a9cf88a0e934f7aef9cc00b..6b69ef2aae727dce8208da07f3f6df84c2eefeec 100644 (file)
  *
  *********************************************************/
 
-/*
- * guestInfo.c ---
+/**
+ * @file guestInfo.c
  *
- *     Provides interface to information about the guest, such as hostname,
- *     NIC/IP address information, etc.
+ *     Library backing parts of the vm.GuestInfo VIM APIs.
  */
 
 #include <stdlib.h>
 #include <string.h>
 
+#if defined _WIN32
+#   include <ws2tcpip.h>
+#endif
+
 #include "vm_assert.h"
 #include "debug.h"
 #include "guestInfoInt.h"
 #include "str.h"
+#include "util.h"
 #include "wiper.h"
 #include "xdrutil.h"
+#include "netutil.h"
+
+
+/**
+ * Helper to initialize an opaque struct member.
+ *
+ * @todo Move to xdrutil.h?  Sticking point is dependency on Util_SafeMalloc.
+ */
+#define XDRUTIL_SAFESETOPAQUE(ptr, type, src, size)                     \
+   do {                                                                 \
+      (ptr)->type##_len = (size);                                       \
+      (ptr)->type##_val = Util_SafeMalloc((size));                      \
+      memcpy((ptr)->type##_val, (src), (size));                         \
+   } while (0)
 
 
 /*
- * Global functions
+ * Global functions.
  */
 
+
 /*
- *-----------------------------------------------------------------------------
+ ******************************************************************************
+ * GuestInfo_GetAvailableDiskSpace --                                    */ /**
  *
- * GuestInfo_GetAvailableDiskSpace --
+ * @brief Given a mount point, return the amount of free space on that volume.
  *
- *    Get the amount of disk space available on the volume the FCP (file copy/
- *    paste) staging area is in. DnD and FCP use same staging area in guest.
- *    But it is only called in host->guest FCP case. DnD checks guest available
- *    disk space in host side (UI).
+ * Get the amount of disk space available on the volume the FCP (file copy/
+ * paste) staging area is in. DnD and FCP use same staging area in guest.
+ * But it is only called in host->guest FCP case. DnD checks guest available
+ * disk space in host side (UI).
  *
- * Results:
- *    Available disk space size if succeed, otherwise 0.
+ * @param[in]  pathName Mount point to examine.
  *
- * Side effects:
- *    None.
+ * @todo This doesn't belong in lib/guestInfo.
  *
- *-----------------------------------------------------------------------------
+ * @return Bytes free on success, 0 on failure.
+ *
+ ******************************************************************************
  */
 
 uint64
@@ -81,256 +100,402 @@ GuestInfo_GetAvailableDiskSpace(char *pathName)
 }
 
 
-
 /*
- *-----------------------------------------------------------------------------
+ ******************************************************************************
+ * GuestInfo_GetFqdn --                                                  */ /**
  *
- * GuestInfo_GetFqdn --
+ * @brief Returns the guest's hostname (aka fully qualified domain name, FQDN).
  *
- *      Returns the guest's hostname.
+ * @param[in]  outBufLen Size of outBuf.
+ * @param[out] outBuf    Output buffer.
  *
- * Results:
- *      Returns TRUE on success, FALSE on failure.
- *      Returns the guest's fully qualified domain name in fqdn.
+ * @retval TRUE  Success.  Hostname written to @a outBuf.
+ * @retval FALSE Failure.
  *
- * Side effects:
- *      None.
- *
- *-----------------------------------------------------------------------------
+ ******************************************************************************
  */
 
 Bool
-GuestInfo_GetFqdn(int outBufLen,        // IN: sizeof fqdn
-                  char fqdn[])          // OUT: buffer to store hostname
+GuestInfo_GetFqdn(int outBufLen,        // IN
+                  char fqdn[])          // OUT
 {
    return GuestInfoGetFqdn(outBufLen, fqdn);
 }
 
 
 /*
- *-----------------------------------------------------------------------------
- *
- * GuestInfo_GetNicInfo --
+ ******************************************************************************
+ * GuestInfo_GetNicInfo --                                               */ /**
  *
- *      Returns the guest's hostname.
+ * @brief Returns guest networking configuration (and some runtime state).
  *
- * Results:
- *      Return MAC addresses of all the NICs in the guest and their
- *      corresponding IP addresses.
+ * @param[out] nicInfo  Will point to a newly allocated NicInfo.
  *
- *      Returns TRUE on success and FALSE on failure.
- *      Return MAC addresses of all NICs and their corresponding IPs.
+ * @note
+ * Caller is responsible for freeing @a nicInfo with GuestInfo_FreeNicInfo.
  *
- * Side effects:
- *      Memory is allocated for each NIC, as well as IP addresses of all NICs
- *      on successful return.
+ * @retval TRUE  Success.  @a nicInfo now points to a populated NicInfoV3.
+ * @retval FALSE Failure.
  *
- *-----------------------------------------------------------------------------
+ ******************************************************************************
  */
 
 Bool
-GuestInfo_GetNicInfo(GuestNicList *nicInfo)  // OUT: storage for NIC information
+GuestInfo_GetNicInfo(NicInfoV3 **nicInfo)  // OUT
 {
-   return GuestInfoGetNicInfo(nicInfo);
+   Bool retval = FALSE;
+
+   *nicInfo = Util_SafeCalloc(1, sizeof (struct NicInfoV3));
+
+   retval = GuestInfoGetNicInfo(*nicInfo);
+   if (!retval) {
+      free(*nicInfo);
+      *nicInfo = NULL;
+   }
+
+   return retval;
 }
 
 
 /*
- *----------------------------------------------------------------------
+ ******************************************************************************
+ * GuestInfo_FreeNicInfo --                                              */ /**
  *
- * GuestInfo_GetDiskInfo --
+ * @brief Frees a NicInfoV3 structure and all memory it points to.
  *
- *      Get disk information.
+ * @param[in] nicInfo   Pointer to NicInfoV3 container.
  *
- * Results:
- *      TRUE if successful, FALSE otherwise.
+ * @sa GuestInfo_GetNicInfo
  *
- * Side effects:
- *     Allocates memory for di->partitionList.
+ ******************************************************************************
+ */
+
+void
+GuestInfo_FreeNicInfo(NicInfoV3 *nicInfo)       // IN
+{
+   if (nicInfo != NULL) {
+      VMX_XDR_FREE(xdr_NicInfoV3, nicInfo);
+      free(nicInfo);
+   }
+}
+
+
+/*
+ ******************************************************************************
+ * GuestInfo_GetDiskInfo --                                              */ /**
  *
- *----------------------------------------------------------------------
+ * @brief Get disk information.
+ *
+ * @param[in,out] di    DiskInfo container.
+ *
+ * @note 
+ * Allocates memory for di->partitionList.
+ *
+ * @retval TRUE  Success.
+ * @retval FALSE Failure.
+ *
+ ******************************************************************************
  */
 
 Bool
 GuestInfo_GetDiskInfo(PGuestDiskInfo di)     // IN/OUT
 {
-   return GuestInfoGetDiskInfo(di);
+   WiperPartition_List pl;
+   DblLnkLst_Links *curr;
+   unsigned int partCount = 0;
+   uint64 freeBytes = 0;
+   uint64 totalBytes = 0;
+   unsigned int partNameSize = 0;
+   Bool success = FALSE;
+
+   ASSERT(di);
+   partNameSize = sizeof (di->partitionList)[0].name;
+   di->numEntries = 0;
+   di->partitionList = NULL;
+
+   /* Get partition list. */
+   if (!WiperPartition_Open(&pl)) {
+      Debug("GetDiskInfo: ERROR: could not get partition list\n");
+      return FALSE;
+   }
+
+   DblLnkLst_ForEach(curr, &pl.link) {
+      WiperPartition *part = DblLnkLst_Container(curr, WiperPartition, link);
+
+      if (part->type != PARTITION_UNSUPPORTED) {
+         PPartitionEntry newPartitionList;
+         PPartitionEntry partEntry;
+         unsigned char *error;
+
+         error = WiperSinglePartition_GetSpace(part, &freeBytes, &totalBytes);
+         if (strlen(error)) {
+            Debug("GetDiskInfo: ERROR: could not get space for partition %s: %s\n",
+                  part->mountPoint, error);
+            goto out;
+         }
+
+         if (strlen(part->mountPoint) + 1 > partNameSize) {
+            Debug("GetDiskInfo: ERROR: Partition name buffer too small\n");
+            goto out;
+         }
+
+         newPartitionList = realloc(di->partitionList,
+                                    (partCount + 1) * sizeof *di->partitionList);
+         if (newPartitionList == NULL) {
+            Debug("GetDiskInfo: ERROR: could not allocate partition list.\n");
+            goto out;
+         }
+
+         partEntry = &newPartitionList[partCount++];
+         Str_Strcpy(partEntry->name, part->mountPoint, partNameSize);
+         partEntry->freeBytes = freeBytes;
+         partEntry->totalBytes = totalBytes;
+
+         di->partitionList = newPartitionList;
+      }
+   }
+
+   di->numEntries = partCount;
+   success = TRUE;
+
+out:
+   WiperPartition_Close(&pl);
+   return success;
 }
 
 
-/**
- * Add a NIC into the given list. The macAddress of the new GuestNic is
- * initialized with the given address.
+/*
+ * Private library functions.
+ */
+
+
+/*
+ ******************************************************************************
+ * GuestInfoAddNicEntry --                                               */ /**
+ *
+ * @brief GuestNicV3 constructor.
  *
  * @param[in,out] nicInfo     List of NICs.
  * @param[in]     macAddress  MAC address of new NIC.
+ * @param[in]     dnsInfo     Per-NIC DNS config state.
+ *
+ * @note The returned GuestNic will take ownership of @a dnsInfo.  The caller
+ *       must not free it directly.
  *
- * @return The new NIC, or NULL on failure.
+ * @return Pointer to the new NIC.
+ *
+ ******************************************************************************
  */
 
-GuestNic *
-GuestInfoAddNicEntry(GuestNicList *nicInfo,                    // IN/OUT
-                     const char macAddress[NICINFO_MAC_LEN])   // IN
+GuestNicV3 *
+GuestInfoAddNicEntry(NicInfoV3 *nicInfo,                       // IN/OUT
+                     const char macAddress[NICINFO_MAC_LEN],   // IN
+                     DnsConfigInfo *dnsInfo)                   // IN
 {
-   GuestNic *newNic;
+   GuestNicV3 *newNic;
 
    newNic = XDRUTIL_ARRAYAPPEND(nicInfo, nics, 1);
-   if (newNic != NULL) {
-      Str_Strcpy(newNic->macAddress, macAddress, sizeof newNic->macAddress);
-   }
+   ASSERT_MEM_ALLOC(newNic);
+
+   newNic->macAddress = Util_SafeStrdup(macAddress);
+   newNic->dnsConfigInfo = dnsInfo;
 
    return newNic;
 }
 
 
-/**
- * Add an IP address entry into the GuestNic.
+/*
+ ******************************************************************************
+ * GuestInfoAddIpAddress --                                              */ /**
+ *
+ * @brief Add an IP address entry into the GuestNic.
  *
  * @param[in,out] nic      The NIC information.
- * @param[in]     ipAddr   The new IP address to add.
- * @param[in]     af_type  Interface type.
+ * @param[in]     sockAddr The new IP address.
+ * @param[in]     pfxLen   Prefix length (use 0 if unknown).
+ * @param[in]     origin   Address's origin.  (Optional.)
+ * @param[in]     status   Address's status.  (Optional.)
  *
  * @return Newly allocated IP address struct, NULL on failure.
+ *
+ ******************************************************************************
  */
 
-VmIpAddress *
-GuestInfoAddIpAddress(GuestNic *nic,                    // IN/OUT
-                      const char *ipAddr,               // IN
-                      const uint32 af_type)             // IN
+IpAddressEntry *
+GuestInfoAddIpAddress(GuestNicV3 *nic,                  // IN/OUT
+                      const struct sockaddr *sockAddr,  // IN
+                      InetAddressPrefixLength pfxLen,   // IN
+                      const IpAddressOrigin *origin,    // IN
+                      const IpAddressStatus *status)    // IN
 {
-   VmIpAddress *ip;
+   IpAddressEntry *ip;
+
+   ASSERT(sockAddr);
 
    ip = XDRUTIL_ARRAYAPPEND(nic, ips, 1);
-   if (ip != NULL) {
-      Str_Strcpy(ip->ipAddress, ipAddr, sizeof ip->ipAddress);
-      ip->addressFamily = af_type;
+   ASSERT_MEM_ALLOC(ip);
+
+   ASSERT_ON_COMPILE(sizeof *origin == sizeof *ip->ipAddressOrigin);
+   ASSERT_ON_COMPILE(sizeof *status == sizeof *ip->ipAddressStatus);
+
+   switch (sockAddr->sa_family) {
+   case AF_INET:
+      {
+         static const IpAddressStatus defaultStatus = IAS_PREFERRED;
+
+         GuestInfoSockaddrToTypedIpAddress(sockAddr, &ip->ipAddressAddr);
+
+         ip->ipAddressPrefixLength = pfxLen;
+         ip->ipAddressOrigin = origin ? Util_DupeThis(origin, sizeof *origin) : NULL;
+         ip->ipAddressStatus = status ? Util_DupeThis(status, sizeof *status) :
+            Util_DupeThis(&defaultStatus, sizeof defaultStatus);
+      }
+      break;
+   case AF_INET6:
+      {
+         static const IpAddressStatus defaultStatus = IAS_UNKNOWN;
+
+         GuestInfoSockaddrToTypedIpAddress(sockAddr, &ip->ipAddressAddr);
+
+         ip->ipAddressPrefixLength = pfxLen;
+         ip->ipAddressOrigin = origin ? Util_DupeThis(origin, sizeof *origin) : NULL;
+         ip->ipAddressStatus = status ? Util_DupeThis(status, sizeof *status) :
+            Util_DupeThis(&defaultStatus, sizeof defaultStatus);
+      }
+      break;
+   default:
+      NOT_REACHED();
    }
 
    return ip;
 }
 
 
-/**
- * Add an IPv4 netmask / IPv6 prefix length to the IpAddress in ASCII form.
+/*
+ ******************************************************************************
+ * GuestInfoSockaddrToTypedIpAddress --                                  */ /**
+ *
+ * @brief Converts a <tt>struct sockaddr</tt> to a @c TypedIpAddress.
  *
- * If convertToMask is true the 'n' bits subnet mask is converted
- * to an ASCII string as a hexadecimal number (0xffffff00) and
- * added to the IPAddressEntry.  (Applies to IPv4 only.)
+ * @param[in]  sa       Source @c sockaddr.
+ * @param[out] typedIp  Destination @c TypedIpAddress.
  *
- * If convertToMask is false the value is added to the IPAddressEntry in
- * string form - ie '24'.
+ * @warning Caller is responsible for making sure source is AF_INET or
+ * AF_INET6.
  *
- * @param[in,out] ipAddressEntry    The IP address info.
- * @param[in]     subnetMaskBits    The mask.
- * @param[in]     convertToMask     See above.
+ ******************************************************************************
  */
 
 void
-GuestInfoAddSubnetMask(VmIpAddress *ipAddressEntry,            // IN/OUT
-                       const uint32 subnetMaskBits,            // IN
-                       Bool convertToMask)                     // IN
+GuestInfoSockaddrToTypedIpAddress(const struct sockaddr *sa,    // IN
+                                  TypedIpAddress *typedIp)      // OUT
 {
-   int i;
-   uint32 subnetMask = 0;
-
-   ASSERT(ipAddressEntry);
-   /*
-    * It's an error to set convertToMask on an IPv6 address.
-    */
-   ASSERT(ipAddressEntry->addressFamily == INFO_IP_ADDRESS_FAMILY_IPV4 ||
-          !convertToMask);
-
-   if (convertToMask && (subnetMaskBits <= 32)) {
-      /*
-       * Convert the subnet mask from a number of bits (ie. '24') to
-       * hexadecimal notation such 0xffffff00
-       */
-      for (i = 0; i < subnetMaskBits; i++) {
-         subnetMask |= (0x80000000 >> i);
-      }
-
-      // Convert the hexadecimal value to a string and add to the IpAddress Entry
-      Str_Sprintf(ipAddressEntry->subnetMask,
-                  sizeof ipAddressEntry->subnetMask,
-                  "0x%x", subnetMask);
-   } else {
-      Str_Sprintf(ipAddressEntry->subnetMask,
-                  sizeof ipAddressEntry->subnetMask,
-                  "%d", subnetMaskBits);
+   struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+   struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
+
+   switch (sa->sa_family) {
+   case AF_INET:
+      typedIp->ipAddressAddrType = IAT_IPV4;
+      XDRUTIL_SAFESETOPAQUE(&typedIp->ipAddressAddr, InetAddress,
+                            &sin->sin_addr.s_addr,
+                            sizeof sin->sin_addr.s_addr);
+      break;
+   case AF_INET6:
+      typedIp->ipAddressAddrType = IAT_IPV6;
+      XDRUTIL_SAFESETOPAQUE(&typedIp->ipAddressAddr, InetAddress,
+                            &sin6->sin6_addr.s6_addr,
+                            sizeof sin6->sin6_addr.s6_addr);
+      break;
+   default:
+      NOT_REACHED();
    }
-   return;
 }
 
 
-/**
- * Get disk information.
+#if defined linux || defined _WIN32
+/*
+ ******************************************************************************
+ * GuestInfoGetNicInfoIfIndex --                                         */ /**
+ *
+ * @brief Given a local interface's index, find its corresponding location in the
+ * NicInfoV3 @c nics vector.
+ *
+ * @param[in]  nicInfo     NIC container.
+ * @param[in]  ifIndex     Device to search for.
+ * @param[out] nicifIndex  Array offset, if found.
  *
- * @param[out]    di    Where to store the disk information.
+ * @retval TRUE  Device found.
+ * @retval FALSE Device not found.
  *
- * @return TRUE if successful, FALSE otherwise.
+ ******************************************************************************
  */
 
 Bool
-GuestInfoGetDiskInfo(PGuestDiskInfo di)
+GuestInfoGetNicInfoIfIndex(NicInfoV3 *nicInfo,  // IN
+                           int ifIndex,         // IN
+                           int *nicIfIndex)     // OUT
 {
-   int i = 0;
-   WiperPartition_List *pl = NULL;
-   unsigned int partCount = 0;
-   uint64 freeBytes = 0;
-   uint64 totalBytes = 0;
-   WiperPartition nextPartition;
-   unsigned int partNameSize = 0;
-   Bool success = FALSE;
-
-   ASSERT(di);
-   partNameSize = sizeof (di->partitionList)[0].name;
-   di->numEntries = 0;
-   di->partitionList = NULL;
-
-   /* Get partition list. */
-   pl = WiperPartition_Open();
-   if (pl == NULL) {
-      Debug("GetDiskInfo: ERROR: could not get partition list\n");
+   char hwAddrString[NICINFO_MAC_LEN];
+   unsigned char hwAddr[16];
+   IanaIfType ifType;
+   Bool ret = FALSE;
+   u_int i;
+
+   ASSERT(nicInfo);
+   ASSERT(nicIfIndex);
+
+   if (NetUtil_GetHardwareAddress(ifIndex, hwAddr, sizeof hwAddr,
+                                  &ifType) != 6 ||
+       ifType != IANA_IFTYPE_ETHERNETCSMACD) {
       return FALSE;
    }
 
-   for (i = 0; i < pl->size; i++) {
-      nextPartition = pl->partitions[i];
-      if (!strlen(nextPartition.comment)) {
-         PPartitionEntry newPartitionList;
-         unsigned char *error;
-         error = WiperSinglePartition_GetSpace(&nextPartition, &freeBytes, &totalBytes);
-         if (strlen(error)) {
-            Debug("GetDiskInfo: ERROR: could not get space for partition %s: %s\n",
-                  nextPartition.mountPoint, error);
-            goto out;
-         }
-
-         if (strlen(nextPartition.mountPoint) + 1 > partNameSize) {
-            Debug("GetDiskInfo: ERROR: Partition name buffer too small\n");
-            goto out;
-         }
-
-         newPartitionList = realloc(di->partitionList,
-                                    (partCount + 1) * sizeof *di->partitionList);
-         if (newPartitionList == NULL) {
-            Debug("GetDiskInfo: ERROR: could not allocate partition list.\n");
-            goto out;
-         }
-         di->partitionList = newPartitionList;
-
-         Str_Strcpy((di->partitionList)[partCount].name, nextPartition.mountPoint,
-                        partNameSize);
-         (di->partitionList)[partCount].freeBytes = freeBytes;
-         (di->partitionList)[partCount].totalBytes = totalBytes;
-         partCount++;
+   Str_Sprintf(hwAddrString, sizeof hwAddrString,
+               "%02x:%02x:%02x:%02x:%02x:%02x",
+               hwAddr[0], hwAddr[1], hwAddr[2],
+               hwAddr[3], hwAddr[4], hwAddr[5]);
+
+   XDRUTIL_FOREACH(i, nicInfo, nics) {
+      GuestNicV3 *nic = XDRUTIL_GETITEM(nicInfo, nics, i);
+      if (!strcasecmp(nic->macAddress, hwAddrString)) {
+         *nicIfIndex = i;
+         ret = TRUE;
+         break;
       }
    }
 
-   di->numEntries = partCount;
-   success = TRUE;
-out:
-   WiperPartition_Close(pl);
-   return success;
+   return ret;
 }
+#endif // if defined linux || defined _WIN32
+
+
+/*
+ * XXX
+ */
+
+
+/**
+ * Return a copy of arbitrary memory.
+ *
+ * @param[in] source     Source address.
+ * @param[in] sourceSize Number of bytes to allocate, copy.
+ *
+ * @return Pointer to newly allocated memory.
+ *
+ * @todo Determine if I'm duplicating functionality.
+ * @todo Move this to bora/lib/util or whatever.
+ */
 
+void *
+Util_DupeThis(const void *source,
+              size_t sourceSize)
+{
+   void *dest;
+
+   ASSERT(source);
+
+   dest = Util_SafeMalloc(sourceSize);
+   memcpy(dest, source, sourceSize);
+
+   return dest;
+}
index de39df73876dbe6a522b64c35abc63c5dc6c7e46..21a84083bd5925e443d0b22082aba34ca393114b 100644 (file)
 #include "guestInfo.h"
 #include "guestrpc/nicinfo.h"
 
+#if defined __FreeBSD__ || defined __sun__ || defined __APPLE__
+#   include <sys/socket.h>      // struct sockaddr
+#endif
+
 Bool GuestInfoGetFqdn(int outBufLen, char fqdn[]);
-Bool GuestInfoGetNicInfo(GuestNicList *nicInfo);
+Bool GuestInfoGetNicInfo(NicInfoV3 *nicInfo);
 void GuestInfoMemset(void * mem, int value, unsigned int size);
 Bool GuestInfoGetDiskInfo(PGuestDiskInfo di);
 Bool GuestInfo_PerfMon(struct GuestMemInfo *vmStats);
 
-GuestNic *GuestInfoAddNicEntry(GuestNicList *nicInfo,
-                               const char macAddress[NICINFO_MAC_LEN]);
-VmIpAddress *GuestInfoAddIpAddress(GuestNic *nic,
-                                   const char *ipAddr,
-                                   const uint32 af_type);
-void GuestInfoAddSubnetMask(VmIpAddress *ipAddressEntry,
-                            const uint32 subnetMaskBits,
-                            Bool convertToMask);
-
+GuestNicV3 *GuestInfoAddNicEntry(NicInfoV3 *nicInfo,                    // IN/OUT
+                                 const char macAddress[NICINFO_MAC_LEN], // IN
+                                 DnsConfigInfo *dnsInfo);               // IN
+
+IpAddressEntry *GuestInfoAddIpAddress(GuestNicV3 *nic,                  // IN/OUT
+                                      const struct sockaddr *sockAddr,  // IN
+                                      InetAddressPrefixLength pfxLen,   // IN
+                                      const IpAddressOrigin *origin,    // IN
+                                      const IpAddressStatus *status);   // IN
+#if defined linux || defined _WIN32
+Bool GuestInfoGetNicInfoIfIndex(NicInfoV3 *nicInfo,  // IN
+                                int ifIndex,         // IN
+                                int *nicIfIndex);    // OUT
+#endif // if defined linux || defined _WIN32
+void GuestInfoSockaddrToTypedIpAddress(const struct sockaddr *sa,    // IN
+                                       TypedIpAddress *typedIp);     // OUT
+
+/* XXX */
+void * Util_DupeThis(const void *source, size_t sourceSize);
 #endif
index a02a4c40da1e85b91d4da0e0e5307611b6a40c00..991fdc5eb33453b31b1cd44da872a25a58a9844d 100644 (file)
@@ -1,5 +1,5 @@
 /*********************************************************
- * Copyright (C) 1998 VMware, Inc. All rights reserved.
+ * Copyright (C) 2005 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
  *
  *********************************************************/
 
-
-/*
- * guestInfoPosix.c --
- *
- *    Routines to get guest information. These are invoked by guestInfoServer
- *    which writes this information into Vmdb.
+/**
+ * @file guestInfoPosix.c
  *
+ * Contains POSIX-specific bits of GuestInfo collector library.
  */
 
-#ifndef VMX86_DEVEL
-
-#endif
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <glib.h>
 #include <fcntl.h>
 #ifdef sun
 # include <sys/systeminfo.h>
 #  include <dnet.h>
 # endif
 #endif
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#ifdef __linux__
+#   include <net/if.h>
+#endif
+
+
+/*
+ * resolver(3) and IPv6:
+ *
+ * The ISC BIND resolver included various IPv6 implementations over time, but
+ * unfortunately the ISC hadn't bumped __RES accordingly.  (__RES is -supposed-
+ * to behave as a version datestamp for the resolver interface.)  Similarly
+ * the GNU C Library forked resolv.h and made modifications of their own, also
+ * without changing __RES.
+ *
+ * glibc 2.1.92 included a patch which provides IPv6 name server support by
+ * embedding in6_addr pointers in _res._u._ext.  Since I only care about major
+ * and minor numbers, though, I'm going to condition this impl. on glibc 2.2.
+ *
+ * ISC, OTOH, provided accessing IPv6 servers via a res_getservers API.
+ * TTBOMK, this went public with BIND 8.3.0.  Unfortunately __RES wasn't
+ * bumped for this release, so instead I'm going to assume that appearance with
+ * that release of a new macro, RES_F_DNS0ERR, implies this API is available.
+ * (For internal builds, we'll know instantly when a build breaks.  The down-
+ * side is that this could cause some trouble for Open VM Tools users. ,_,)
+ *
+ * resolv.h version     IPv6 API        __RES
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * glibc 2.2+           _ext            19991006
+ * BIND 8.3.0           getservers      19991006
+ * BIND 8.3.4+          getservers      20030124(+?)
+ *
+ * To distinguish between the variants where __RES == 19991006, I'll
+ * discriminate on the existence of new macros included with the appropriate
+ * version.
+ */
+
+#if defined __GLIBC__
+#   if __GLIBC_PREREQ(2,2)
+#      define      RESOLVER_IPV6_EXT
+#   endif // __GLIBC_PREREQ(2,2)
+#elif (__RES > 19991006 || (__RES == 19991006 && defined RES_F_EDNS0ERR))
+#   define      RESOLVER_IPV6_GETSERVERS
+#endif // if defined __GLIBC__
+
+
 #include "util.h"
 #include "sys/utsname.h"
 #include "sys/ioctl.h"
 #include "guest_os.h"
 #include "guestApp.h"
 #include "guestInfo.h"
+#include "xdrutil.h"
+#include "slashProc.h"
+#include "netutil.h"
+#include "file.h"
 
 
 /*
- *-----------------------------------------------------------------------------
- *
- * GuestInfoGetFqdn--
- *
- *      Return the guest's fully qualified domain name.
- *      This is just a thin wrapper around gethostname.
- *
- * Return value:
- *      Returns TRUE on success and FALSE on failure.
- *      Returns the guest's fully qualified domain name.
+ * Local functions
+ */
+
+
+#ifndef NO_DNET
+static void RecordNetworkAddress(GuestNicV3 *nic, const struct addr *addr);
+static int ReadInterfaceDetails(const struct intf_entry *entry, void *arg);
+static Bool RecordResolverInfo(NicInfoV3 *nicInfo);
+static void RecordResolverNS(DnsConfigInfo *dnsConfigInfo);
+static Bool RecordRoutingInfo(NicInfoV3 *nicInfo);
+#endif
+
+
+/*
+ ******************************************************************************
+ * GuestInfoGetFqdn --                                                   */ /**
  *
- * Side effects:
- *      None
+ * @copydoc GuestInfo_GetFqdn
  *
- *-----------------------------------------------------------------------------
+ ******************************************************************************
  */
 
 Bool
@@ -96,96 +149,118 @@ GuestInfoGetFqdn(int outBufLen,    // IN: length of output buffer
 }
 
 
-#ifndef NO_DNET
 /*
- *-----------------------------------------------------------------------------
+ ******************************************************************************
+ * GuestInfoGetNicInfo --                                                */ /**
  *
- * RecordNetworkAddress --
+ * @copydoc GuestInfo_GetNicInfo
  *
- *      Massages a dnet(3)-style interface address (IPv4 or IPv6) and stores it
- *      as part of a GuestNic structure.
+ ******************************************************************************
+ */
+
+Bool
+GuestInfoGetNicInfo(NicInfoV3 *nicInfo) // OUT
+{
+#ifndef NO_DNET
+   intf_t *intf;
+
+   /* Get a handle to read the network interface configuration details. */
+   if ((intf = intf_open()) == NULL) {
+      Debug("GuestInfo: Error, failed NULL result from intf_open()\n");
+      return FALSE;
+   }
+
+   if (intf_loop(intf, ReadInterfaceDetails, nicInfo) < 0) {
+      intf_close(intf);
+      Debug("GuestInfo: Error, negative result from intf_loop\n");
+      return FALSE;
+   }
+
+   intf_close(intf);
+
+   if (!RecordResolverInfo(nicInfo)) {
+      return FALSE;
+   }
+
+   if (!RecordRoutingInfo(nicInfo)) {
+      return FALSE;
+   }
+
+   return TRUE;
+#else
+   return FALSE;
+#endif
+}
+
+
+/*
+ * Local functions
+ */
+
+
+#ifndef NO_DNET
+/*
+ ******************************************************************************
+ * RecordNetworkAddress --                                               */ /**
  *
- * Results:
- *      If addr is IPv4 or IPv6, it will be appended to the GuestNic's list of
- *      IP addresses.
+ * @brief Massages a dnet(3)-style interface address (IPv4 or IPv6) and stores
+ *        it as part of a GuestNicV3 structure.
  *
- * Side effects:
- *      None.
+ * @param[in]  nic      Operand NIC.
+ * @param[in]  addr     dnet(3) address.
  *
- *-----------------------------------------------------------------------------
+ ******************************************************************************
  */
 
 static void
-RecordNetworkAddress(GuestNic *nic,             // IN: operand NIC
+RecordNetworkAddress(GuestNicV3 *nic,           // IN: operand NIC
                      const struct addr *addr)   // IN: dnet(3) address to process
 {
-   char ipAddress[NICINFO_MAX_IP_LEN];
-   VmIpAddress *ip = NULL;
+   struct sockaddr_storage ss;
+   struct sockaddr *sa = (struct sockaddr *)&ss;
 
-   switch (addr->addr_type) {
-   case ADDR_TYPE_IP:
-      /*
-       * GuestNicInfo clients expect IPv4 addresses and netmasks to be stored
-       * as strings in separate fields.  As such, we'll use ip_ntop instead of
-       * addr_ntop to get a string without the netmask bits.
-       */
-      ip_ntop(&addr->addr_ip, ipAddress, sizeof ipAddress);
-      ip = GuestInfoAddIpAddress(nic, ipAddress, INFO_IP_ADDRESS_FAMILY_IPV4);
-      if (ip) {
-         GuestInfoAddSubnetMask(ip, addr->addr_bits, TRUE);
-      }
-      break;
-   case ADDR_TYPE_IP6:
-      ip6_ntop(&addr->addr_ip6, ipAddress, sizeof ipAddress);
-      ip = GuestInfoAddIpAddress(nic, ipAddress, INFO_IP_ADDRESS_FAMILY_IPV6);
-      if (ip) {
-         GuestInfoAddSubnetMask(ip, addr->addr_bits, FALSE);
-      }
-      break;
-   default:
-      Debug("%s: Unknown address type: %hu\n", __func__, addr->addr_type);
-      break;
-   }
+   memset(&ss, 0, sizeof ss);
+   addr_ntos(addr, sa);
+   GuestInfoAddIpAddress(nic, sa, addr->addr_bits, NULL, NULL);
 }
 
 
 /*
- *-----------------------------------------------------------------------------
+ ******************************************************************************
+ * ReadInterfaceDetails --                                               */ /**
  *
- * ReadInterfaceDetails --
+ * @brief Callback function called by libdnet when iterating over all the NICs
+ * on the host.
  *
- *      Callback function called by libdnet when iterating over all the
- *      NICs on the host.
+ * @param[in]  entry    Current interface entry.
+ * @param[in]  arg      Pointer to NicInfoV3 container.
  *
- * Return value:
- *      Returns 0 on success and -1 on failure.
- *      Adds the MAC addresses of all NICs and their corresponding IPs.
+ * @note New GuestNicV3 structures are added to the NicInfoV3 structure.
  *
- * Side effects:
- *      Memory is allocated for each NIC, as well as IP addresses of all NICs
- *      on successful return.
+ * @retval 0    Success.
+ * @retval -1   Failure.
  *
- *-----------------------------------------------------------------------------
+ ******************************************************************************
  */
 
-int
+static int
 ReadInterfaceDetails(const struct intf_entry *entry,  // IN: current interface entry
                      void *arg)                       // IN: Pointer to the GuestNicList
 {
    int i;
-   GuestNicList *nicInfo = arg;
+   NicInfoV3 *nicInfo = arg;
 
-   if ((entry->intf_type & INTF_TYPE_ETH) == INTF_TYPE_ETH) {
-      GuestNic *nic;
+   ASSERT(entry);
+   ASSERT(arg);
+
+   if (entry->intf_type == INTF_TYPE_ETH) {
+      GuestNicV3 *nic = NULL;
       char macAddress[NICINFO_MAC_LEN];
 
       Str_Sprintf(macAddress, sizeof macAddress, "%s",
                   addr_ntoa(&entry->intf_link_addr));
-      nic = GuestInfoAddNicEntry(nicInfo, macAddress);
-
-      if (nic == NULL) {
-         return -1;
-      }
+      nic = GuestInfoAddNicEntry(nicInfo, macAddress, NULL);
+      ASSERT_MEM_ALLOC(nic);
 
       /* Record the "primary" address. */
       if (entry->intf_addr.addr_type == ADDR_TYPE_IP ||
@@ -205,51 +280,351 @@ ReadInterfaceDetails(const struct intf_entry *entry,  // IN: current interface e
 
    return 0;
 }
-#endif
 
 
 /*
- *-----------------------------------------------------------------------------
+ ******************************************************************************
+ * RecordResolverInfo --                                                 */ /**
  *
- * GuestInfoGetNicInfo --
+ * @brief Query resolver(3), mapping settings to DnsConfigInfo.
  *
- *      Return MAC addresses of all the NICs in the guest and their
- *      corresponding IP addresses.
+ * @param[out] nicInfo  NicInfoV3 container.
  *
- * Return value:
- *      Returns TRUE on success and FALSE on failure.
- *      Return MAC addresses of all NICs and their corresponding IPs.
+ * @retval TRUE         Values collected, attached to @a nicInfo.
+ * @retval FALSE        Something went wrong.  @a nicInfo is unharmed.
  *
- * Side effects:
- *      Memory is allocated for each NIC, as well as IP addresses of all NICs
- *      on successful return.
+ ******************************************************************************
+ */
+
+static Bool
+RecordResolverInfo(NicInfoV3 *nicInfo)  // OUT
+{
+   DnsConfigInfo *dnsConfigInfo = NULL;
+   char namebuf[DNSINFO_MAX_ADDRLEN + 1];
+   char **s;
+
+   if (res_init() == -1) {
+      return FALSE;
+   }
+
+   dnsConfigInfo = Util_SafeCalloc(1, sizeof *dnsConfigInfo);
+
+   /*
+    * Copy in the host name.
+    */
+   if (!GuestInfoGetFqdn(sizeof namebuf, namebuf)) {
+      goto fail;
+   }
+   dnsConfigInfo->hostName =
+      Util_SafeCalloc(1, sizeof *dnsConfigInfo->hostName);
+   *dnsConfigInfo->hostName = Util_SafeStrdup(namebuf);
+
+   /*
+    * Repeat with the domain name.
+    */
+   dnsConfigInfo->domainName =
+      Util_SafeCalloc(1, sizeof *dnsConfigInfo->domainName);
+   *dnsConfigInfo->domainName = Util_SafeStrdup(_res.defdname);
+
+   /*
+    * Name servers.
+    */
+   RecordResolverNS(dnsConfigInfo);
+
+   /*
+    * Search suffixes.
+    */
+   for (s = _res.dnsrch; *s; s++) {
+      DnsHostname *suffix = XDRUTIL_ARRAYAPPEND(dnsConfigInfo, searchSuffixes, 1);
+      ASSERT_MEM_ALLOC(suffix);
+      *suffix = Util_SafeStrdup(*s);
+   }
+
+   /*
+    * "Commit" dnsConfigInfo to nicInfo.
+    */
+   nicInfo->dnsConfigInfo = dnsConfigInfo;
+
+   return TRUE;
+
+fail:
+   VMX_XDR_FREE(xdr_DnsConfigInfo, dnsConfigInfo);
+   free(dnsConfigInfo);
+   return FALSE;
+}
+
+
+/*
+ ******************************************************************************
+ * RecordResolverNS --                                                   */ /**
+ *
+ * @brief Copies name servers used by resolver(3) to @a dnsConfigInfo.
  *
- *-----------------------------------------------------------------------------
+ * @param[out] dnsConfigInfo    Destination DnsConfigInfo container.
+ *
+ ******************************************************************************
  */
 
-Bool
-GuestInfoGetNicInfo(GuestNicList *nicInfo)   // OUT
+static void
+RecordResolverNS(DnsConfigInfo *dnsConfigInfo) // IN
 {
-#ifndef NO_DNET
-   intf_t *intf;
+   int i;
 
-   memset(nicInfo, 0, sizeof *nicInfo);
+#if defined RESOLVER_IPV6_GETSERVERS
+   {
+      union res_sockaddr_union *ns;
+      ns = Util_SafeCalloc(_res.nscount, sizeof *ns);
+      if (res_getservers(&_res, ns, _res.nscount) != _res.nscount) {
+         Warning("%s: res_getservers failed.\n", __func__);
+         return;
+      }
+      for (i = 0; i < _res.nscount; i++) {
+         struct sockaddr *sa = (struct sockaddr *)&ns[i];
+         if (sa->sa_family == AF_INET || sa->sa_family == AF_INET6) {
+            TypedIpAddress *ip = XDRUTIL_ARRAYAPPEND(dnsConfigInfo, serverList, 1);
+            ASSERT_MEM_ALLOC(ip);
+            GuestInfoSockaddrToTypedIpAddress(sa, ip);
+         }
+      }
+   }
+#else                                   // if defined RESOLVER_IPV6_GETSERVERS
+   {
+      /*
+       * Name servers (IPv4).
+       */
+      for (i = 0; i < MAXNS; i++) {
+         struct sockaddr_in *sin = &_res.nsaddr_list[i];
+         if (sin->sin_family == AF_INET) {
+            TypedIpAddress *ip = XDRUTIL_ARRAYAPPEND(dnsConfigInfo, serverList, 1);
+            ASSERT_MEM_ALLOC(ip);
+            GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin, ip);
+         }
+      }
+#   if defined RESOLVER_IPV6_EXT
+      /*
+       * Name servers (IPv6).
+       */
+      for (i = 0; i < MAXNS; i++) {
+         struct sockaddr_in6 *sin6 = _res._u._ext.nsaddrs[i];
+         if (sin6) {
+            TypedIpAddress *ip = XDRUTIL_ARRAYAPPEND(dnsConfigInfo, serverList, 1);
+            ASSERT_MEM_ALLOC(ip);
+            GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin6, ip);
+         }
+      }
+#   endif                               //    if defined RESOLVER_IPV6_EXT
+   }
+#endif                                  // if !defined RESOLVER_IPV6_GETSERVERS
+}
 
-   /* Get a handle to read the network interface configuration details. */
-   if ((intf = intf_open()) == NULL) {
-      Debug("GuestInfo: Error, failed NULL result from intf_open()\n");
+
+#if defined __linux__
+/*
+ ******************************************************************************
+ * RecordRoutingInfoIPv4 --                                              */ /**
+ *
+ * @brief Query the IPv4 routing subsystem and pack up contents
+ * (struct rtentry) into InetCidrRouteEntries.
+ *
+ * @param[out] nicInfo  NicInfoV3 container.
+ *
+ * @note Do not call this routine without first populating @a nicInfo 's NIC
+ * list.
+ *
+ * @retval TRUE         Values collected, attached to @a nicInfo.
+ * @retval FALSE        Something went wrong.  @a nicInfo is unharmed.
+ *
+ ******************************************************************************
+ */
+
+static Bool
+RecordRoutingInfoIPv4(NicInfoV3 *nicInfo)
+{
+   GPtrArray *routes = NULL;
+   guint i;
+   Bool ret = FALSE;
+
+   if ((routes = SlashProcNet_GetRoute()) == NULL) {
       return FALSE;
    }
 
-   if (intf_loop(intf, ReadInterfaceDetails, nicInfo) < 0) {
-      intf_close(intf);
-      Debug("GuestInfo: Error, negative result from intf_loop\n");
+   for (i = 0; i < routes->len; i++) {
+      struct rtentry *rtentry;
+      struct sockaddr_in *sin_dst;
+      struct sockaddr_in *sin_gateway;
+      struct sockaddr_in *sin_genmask;
+      InetCidrRouteEntry *icre;
+      uint32_t ifIndex;
+
+      rtentry = g_ptr_array_index(routes, i);
+
+      if ((rtentry->rt_flags & RTF_UP) == 0 ||
+          !GuestInfoGetNicInfoIfIndex(nicInfo,
+                                      if_nametoindex(rtentry->rt_dev),
+                                      &ifIndex)) {
+         continue;
+      }
+
+      icre = XDRUTIL_ARRAYAPPEND(nicInfo, routes, 1);
+      ASSERT_MEM_ALLOC(icre);
+
+      sin_dst = (struct sockaddr_in *)&rtentry->rt_dst;
+      sin_gateway = (struct sockaddr_in *)&rtentry->rt_gateway;
+      sin_genmask = (struct sockaddr_in *)&rtentry->rt_genmask;
+
+      GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin_dst,
+                                        &icre->inetCidrRouteDest);
+
+      addr_stob((struct sockaddr *)sin_genmask,
+                (uint16_t *)&icre->inetCidrRoutePfxLen);
+
+      /*
+       * Gateways are optional (ex: one can bind a route to an interface w/o
+       * specifying a next hop address).
+       */
+      if (rtentry->rt_flags & RTF_GATEWAY) {
+         TypedIpAddress *ip = Util_SafeCalloc(1, sizeof *ip);
+         GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin_gateway, ip);
+         icre->inetCidrRouteNextHop = ip;
+      }
+
+      /*
+       * Interface, metric.
+       */
+      icre->inetCidrRouteIfIndex = ifIndex;
+      icre->inetCidrRouteMetric = rtentry->rt_metric;
+   }
+
+   ret = TRUE;
+
+   SlashProcNet_FreeRoute(routes);
+   return ret;
+}
+
+
+/*
+ ******************************************************************************
+ * RecordRoutingInfoIPv6 --                                              */ /**
+ *
+ * @brief Query the IPv6 routing subsystem and pack up contents
+ * (struct in6_rtmsg) into InetCidrRouteEntries.
+ *
+ * @param[out] nicInfo  NicInfoV3 container.
+ *
+ * @note Do not call this routine without first populating @a nicInfo 's NIC
+ * list.
+ *
+ * @retval TRUE         Values collected, attached to @a nicInfo.
+ * @retval FALSE        Something went wrong.  @a nicInfo is unharmed.
+ *
+ ******************************************************************************
+ */
+
+static Bool
+RecordRoutingInfoIPv6(NicInfoV3 *nicInfo)
+{
+   GPtrArray *routes = NULL;
+   guint i;
+   Bool ret = FALSE;
+
+   if ((routes = SlashProcNet_GetRoute6()) == NULL) {
       return FALSE;
    }
 
-   intf_close(intf);
+   for (i = 0; i < routes->len; i++) {
+      struct sockaddr_storage ss;
+      struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
+      struct in6_rtmsg *in6_rtmsg;
+      InetCidrRouteEntry *icre;
+      uint32_t ifIndex = -1;
+
+      in6_rtmsg = g_ptr_array_index(routes, i);
+
+      if ((in6_rtmsg->rtmsg_flags & RTF_UP) == 0 ||
+          !GuestInfoGetNicInfoIfIndex(nicInfo, in6_rtmsg->rtmsg_ifindex,
+                                      &ifIndex)) {
+         continue;
+      }
+
+      icre = XDRUTIL_ARRAYAPPEND(nicInfo, routes, 1);
+      ASSERT_MEM_ALLOC(icre);
+
+      /*
+       * Destination.
+       */
+      sin6->sin6_family = AF_INET6;
+      sin6->sin6_addr = in6_rtmsg->rtmsg_dst;
+      GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin6,
+                                        &icre->inetCidrRouteDest);
+
+      icre->inetCidrRoutePfxLen = in6_rtmsg->rtmsg_dst_len;
+
+      /*
+       * Next hop.
+       */
+      if (in6_rtmsg->rtmsg_flags & RTF_GATEWAY) {
+         TypedIpAddress *ip = Util_SafeCalloc(1, sizeof *ip);
+         sin6->sin6_addr = in6_rtmsg->rtmsg_gateway;
+         GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin6, ip);
+         icre->inetCidrRouteNextHop = ip;
+      }
+
+      /*
+       * Interface, metric.
+       */
+      icre->inetCidrRouteIfIndex = ifIndex;
+      icre->inetCidrRouteMetric = in6_rtmsg->rtmsg_metric;
+   }
+
+   ret = TRUE;
+
+   SlashProcNet_FreeRoute6(routes);
+   return ret;
+}
+
+
+/*
+ ******************************************************************************
+ * RecordRoutingInfo --                                                  */ /**
+ *
+ * @brief Query the routing subsystem and pack up contents into
+ * InetCidrRouteEntries.
+ *
+ * @param[out] nicInfo  NicInfoV3 container.
+ *
+ * @note Do not call this routine without first populating @a nicInfo 's NIC
+ * list.
+ *
+ * @retval TRUE         Values collected, attached to @a nicInfo.
+ * @retval FALSE        Something went wrong.
+ *
+ ******************************************************************************
+ */
+
+static Bool
+RecordRoutingInfo(NicInfoV3 *nicInfo)
+{
+   Bool ret = TRUE;
+
+   if (File_Exists("/proc/net/route") && !RecordRoutingInfoIPv4(nicInfo)) {
+      Warning("%s: Unable to collect IPv4 routing table.\n", __func__);
+      ret = FALSE;
+   }
+
+   if (File_Exists("/proc/net/ipv6_route") && !RecordRoutingInfoIPv6(nicInfo)) {
+      Warning("%s: Unable to collect IPv6 routing table.\n", __func__);
+      ret = FALSE;
+   }
+
+   return ret;
+}
+
+#else                                           // if defined __linux__
+static Bool
+RecordRoutingInfo(NicInfoV3 *nicInfo)
+{
    return TRUE;
-#else
-   return FALSE;
-#endif
 }
+#endif                                          // else
+
+#endif // ifndef NO_DNET
index e643375f2e54fe61468fda434c6504e86e4970e0..b76bb2dc59e0edd511ef8659c7b66a17a0b7d90d 100644 (file)
@@ -38,4 +38,9 @@
  */
 #define GHI_HANDLERS_ACTIONURI_MAX_PATH 1040
 
+/*
+ * Maximum length for a guest app hash value (usually much shorter).
+ */
+#define GHI_EXEC_INFO_HASH_MAX_LEN 1024
+
 #endif // ifndef _GHI_COMMON_DEFINES_H_
index 989ed016480799d548a4db8546a1502919746bb0..14d73a53e13a76b4d6ffced0d839be8521411843 100644 (file)
@@ -25,8 +25,6 @@
 
 #include "ghiCommonDefines.h"
 
-#define GHI_EXEC_INFO_HASH_MAX_LEN 1024
-
 /*
 * Enumerates the different versions of the messages.
 */
index 743282334efcc2307e1a494af0fa0b170aa5fa95..323d1bc3d8fdf4b724eeac0557731a9a554a3f0d 100644 (file)
@@ -28,7 +28,9 @@
  * version one is legacy code we can't change.
  */
 enum NicInfoVersion {
-    NIC_INFO_V2 = 2
+   NIC_INFO_V1 = 1,     /* XXX Not represented here. */
+   NIC_INFO_V2 = 2,
+   NIC_INFO_V3 = 3
 };
 
 /*
@@ -42,11 +44,16 @@ const NICINFO_MAX_NICS     = 16;
 /* MAC Addresses are "AA:BB:CC:DD:EE:FF" = 18 bytes. */
 const NICINFO_MAC_LEN      = 18;
 
+/*
+ * Corresponds to public/guestInfo.h::GuestInfoIPAddressFamilyType.
+ */
+enum NicInfoAddrType {
+   NICINFO_ADDR_IPV4 = 0,
+   NICINFO_ADDR_IPV6 = 1
+};
+
 struct VmIpAddress {
-   /*
-    * Corresponds to public/guestInfo.h::GuestInfoIPAddressFamilyType.
-    */
-   uint32      addressFamily;
+   NicInfoAddrType addressFamily;
    Bool        dhcpEnabled;
    char        ipAddress[NICINFO_MAX_IP_LEN];
    /*
@@ -69,6 +76,242 @@ struct GuestNicList {
    struct GuestNic nics<NICINFO_MAX_NICS>;
 };
 
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * NIC Info version 3.
+ *
+ *      V3 adds routing, DNS, and WINS information to the NIC list.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+
+/*
+ * IP v4 and v6 addressing.
+ *
+ * These types were redefined primarily to allow much more efficient wire
+ * encoding.
+ */
+
+
+/*
+ * See RFC 4001, InetAddress.
+ */
+const INET_ADDRESS_MAX_LEN = 255;
+typedef opaque InetAddress<INET_ADDRESS_MAX_LEN>;
+
+
+/*
+ * See RFC 4001, InetAddressType.
+ */
+enum InetAddressType {
+   IAT_UNKNOWN  = 0,
+   IAT_IPV4     = 1,
+   IAT_IPV6     = 2,
+   IAT_IPV4Z    = 3,
+   IAT_IPV6Z    = 4,
+   IAT_DNS      = 16
+};
+
+
+/*
+ * See RFC 4001, InetAddressPrefixLength.
+ */
+typedef unsigned int InetAddressPrefixLength;
+
+
+/*
+ * See RFC 4293, IpAddressOriginTC.
+ */
+enum IpAddressOrigin {
+   IAO_OTHER            = 1,
+   IAO_MANUAL           = 2,
+   IAO_DHCP             = 4,
+   IAO_LINKLAYER        = 5,
+   IAO_RANDOM           = 6
+};
+
+
+/*
+ * See RFC 4293, IpAddressStatusTC.
+ *
+ * "The status of an address.  Most of the states correspond to states
+ * from the IPv6 Stateless Address Autoconfiguration protocol.
+ *    ...
+ * "In the absence of other information, an IPv4 address is always
+ * preferred(1)." 
+ */
+enum IpAddressStatus {
+   IAS_PREFERRED        = 1,
+   IAS_DEPRECATED       = 2,
+   IAS_INVALID          = 3,
+   IAS_INACCESSIBLE     = 4,
+   IAS_UNKNOWN          = 5,
+   IAS_TENTATIVE        = 6,
+   IAS_DUPLICATE        = 7,
+   IAS_OPTIMISTIC       = 8
+};
+
+
+/*
+ * Convenient type for lists of addresses.
+ */
+struct TypedIpAddress {
+   InetAddressType      ipAddressAddrType;
+   InetAddress          ipAddressAddr;
+};
+
+
+/*
+ * See RFC 4293, IpAddressEntry.
+ *
+ * "An address mapping for a particular interface."
+ *
+ * We deviate from the RFC in a few places:
+ *  - The prefix length is listed explicitly here rather than reference
+ *    a separate prefix table.
+ *  - Interface indices aren't included as this structure is dependent
+ *    upon/encapsulated by a GuestNicV3 structure.
+ */
+struct IpAddressEntry {
+   TypedIpAddress               ipAddressAddr;
+   InetAddressPrefixLength      ipAddressPrefixLength;
+   IpAddressOrigin              *ipAddressOrigin;
+   IpAddressStatus              *ipAddressStatus;
+};
+
+
+/*
+ * Runtime DNS resolver state.
+ */
+
+
+/*
+ * Quoth RFC 2181 Â§11 (Name Syntax):
+ *    "The length of any one label is limited to between 1 and 63 octets.  A
+ *    full domain name is limited to 255 octets (including the separators)."
+ */
+const DNSINFO_MAX_ADDRLEN = 255;
+typedef string DnsHostname<DNSINFO_MAX_ADDRLEN>;
+
+
+/*
+ * Arbitrary limits.
+ */
+const DNSINFO_MAX_SUFFIXES = 10;
+const DNSINFO_MAX_SERVERS = 16;
+
+struct DnsConfigInfo {
+   DnsHostname  *hostName;
+   DnsHostname  *domainName;
+   TypedIpAddress serverList<DNSINFO_MAX_SERVERS>;
+   DnsHostname  searchSuffixes<DNSINFO_MAX_SUFFIXES>;
+};
+
+
+/*
+ * Runtime WINS resolver state.  Addresses are assumed to be IPv4 only.
+ */
+
+struct WinsConfigInfo {
+   TypedIpAddress       primary;
+   TypedIpAddress       secondary;
+};
+
+
+/*
+ * Runtime routing tables.
+ */
+
+
+/*
+ * Arbitrary limit.
+ */
+const NICINFO_MAX_ROUTES = 100;
+
+
+/*
+ * See RFC 4292 for details.
+ */
+enum InetCidrRouteType {
+   ICRT_OTHER   = 1,
+   ICRT_REJECT  = 2,
+   ICRT_LOCAL   = 3,
+   ICRT_REMOTE  = 4
+};
+
+struct InetCidrRouteEntry {
+   TypedIpAddress               inetCidrRouteDest;
+   InetAddressPrefixLength      inetCidrRoutePfxLen;
+
+   /*
+    * Next hop isn't mandatory.
+    */
+   TypedIpAddress               *inetCidrRouteNextHop;
+
+   /*
+    * inetCidrRouteProto is omitted as we're concerned only with static/
+    * netmgmt routes.
+    */
+
+   /* This is an array index into GuestNicListV3::nics. */
+   uint32                       inetCidrRouteIfIndex;
+
+   /* XXX Do we really need this? */
+   InetCidrRouteType            inetCidrRouteType;
+
+   /* -1 == unused. */
+   uint32                       inetCidrRouteMetric;
+};
+
+
+/*
+ * Fun with DHCP
+ */
+
+const DHCP_MAX_CONFIG_SIZE = 16384;
+
+struct DhcpConfigInfo {
+   bool         enabled;
+   string       dhcpSettings<DHCP_MAX_CONFIG_SIZE>;
+};
+
+
+/*
+ * Top-level containers.
+ */
+
+
+/*
+ * Describes a single NIC.
+ */
+
+struct GuestNicV3 {
+   string               macAddress<NICINFO_MAC_LEN>;
+   IpAddressEntry       ips<NICINFO_MAX_IPS>;
+   DnsConfigInfo        *dnsConfigInfo;
+   WinsConfigInfo       *winsConfigInfo;
+   DhcpConfigInfo       *dhcpConfigInfov4;
+   DhcpConfigInfo       *dhcpConfigInfov6;
+};
+
+
+/*
+ * Attempts to model general network state.
+ */
+
+struct NicInfoV3 {
+   GuestNicV3           nics<NICINFO_MAX_NICS>;
+   InetCidrRouteEntry   routes<NICINFO_MAX_ROUTES>;
+   DnsConfigInfo        *dnsConfigInfo;
+   WinsConfigInfo       *winsConfigInfo;
+   DhcpConfigInfo       *dhcpConfigInfov4;
+   DhcpConfigInfo       *dhcpConfigInfov6;
+};
+
+
 /*
  * This defines the protocol for a "nic info" message. The union allows
  * us to create new versions of the protocol later by creating new values
@@ -81,5 +324,6 @@ struct GuestNicList {
 union GuestNicProto switch (NicInfoVersion ver) {
 case NIC_INFO_V2:
    struct GuestNicList *nicsV2;
+case NIC_INFO_V3:
+   struct NicInfoV3 *nicInfoV3;
 };
-
index a64db5a182e2552e61e947c2b9dd45b1a6de8047..4f9e4596f810ea2e7bf705dae1d43e6d9879e113 100644 (file)
@@ -306,8 +306,8 @@ HgfsBd_Enabled(RpcOut *out,         // IN: RPCI Channel
                char *requestPacket) // IN: Buffer (obtained from HgfsBd_GetBuf)
 {
    char const *replyPacket; // Buffer returned by HgfsBd_Dispatch
-   size_t packetSize;
-   int error;
+   size_t replyLen;
+   Bool success;
 
    /*
     * Send a bogus (empty) request to the VMX. If hgfs is disabled on
@@ -316,16 +316,14 @@ HgfsBd_Enabled(RpcOut *out,         // IN: RPCI Channel
     * (it will be an error packet because our request was malformed,
     * but we just discard it anyway).
     */
-   packetSize = 0;
-   error = HgfsBd_Dispatch(out,
-                           requestPacket,
-                           &packetSize,
-                           &replyPacket);
-   if (error < 0) {
-      return FALSE;
+   success = RpcOut_send(out, requestPacket - HGFS_CLIENT_CMD_LEN,
+                         HGFS_CLIENT_CMD_LEN,
+                         &replyPacket, &replyLen);
+   if (success == TRUE) {
+      ASSERT(replyLen <= HGFS_LARGE_PACKET_MAX);
    }
 
-   return TRUE;
+   return success;
 }
 
 
diff --git a/open-vm-tools/lib/hgfsHelper/Makefile.am b/open-vm-tools/lib/hgfsHelper/Makefile.am
new file mode 100644 (file)
index 0000000..1f37ff8
--- /dev/null
@@ -0,0 +1,22 @@
+################################################################################
+### Copyright 2009 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
+################################################################################
+
+noinst_LTLIBRARIES = libHgfsHelper.la
+
+libHgfsHelper_la_SOURCES =
+libHgfsHelper_la_SOURCES += hgfsHelperPosix.c
+
diff --git a/open-vm-tools/lib/hgfsHelper/hgfsHelperPosix.c b/open-vm-tools/lib/hgfsHelper/hgfsHelperPosix.c
new file mode 100644 (file)
index 0000000..533d8fc
--- /dev/null
@@ -0,0 +1,104 @@
+/*********************************************************
+ * Copyright (C) 2009 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.
+ *
+ *********************************************************/
+
+/*
+ * hgfsHelperPosix.c --
+ *
+ *    Provides a posix helper library for guest applications to access
+ *    the HGFS file system.
+ *
+ */
+
+#if !defined __linux__ && !defined __FreeBSD__ && !defined sun && !defined __APPLE__
+#   error This file should not be compiled
+#endif
+
+#include "vmware.h"
+#include "debug.h"
+
+#include "hgfsHelper.h"
+
+#if defined __linux__
+#define HGFSHLPR_DEFAULT_MOUNT_PATH      "/mnt/hgfs"
+#elif defined sun
+#define HGFSHLPR_DEFAULT_MOUNT_PATH      "/hgfs"
+#elif defined __APPLE__
+#define HGFSHLPR_DEFAULT_MOUNT_PATH      "/Volumes/Shared Folders"
+#endif
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsHlpr_QuerySharesDefaultRootPath --
+ *
+ *      Queries the driver for its share's root paths.
+ *      Currently only one is expected to be supported
+ *      and returned, although later versions may not.
+ *      E.g. "/mnt/hgfs" is the root path to
+ *      the HGFS shares.
+ *
+ * Results:
+ *      TRUE always.
+ *
+ * Side Effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsHlpr_QuerySharesDefaultRootPath(Unicode *hgfsRootPath)
+{
+#if defined __FreeBSD__
+   return FALSE;
+#else
+   ASSERT(hgfsRootPath != NULL);
+
+   *hgfsRootPath = Unicode_AllocWithUTF8(HGFSHLPR_DEFAULT_MOUNT_PATH);
+
+   Debug("%s: HGFS shares root path name \"%s\"\n",
+         __FUNCTION__, UTF8(*hgfsRootPath));
+
+   return TRUE;
+#endif
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsHlpr_FreeSharesRootPath --
+ *
+ *      Frees the share's root paths previously returned
+ *      to the caller from the HgfsHlpr_QuerySharesRootPath.
+ *
+ * Results:
+ *      None.
+ *
+ * Side Effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+HgfsHlpr_FreeSharesRootPath(Unicode hgfsRootPath)
+{
+   Unicode_Free(hgfsRootPath);
+}
index 352e41e6a002f38e51bee5f337fdcdd8235a5265..63dfb74a18eba87aa0ff3f999dfb83e82874687b 100644 (file)
@@ -56,7 +56,6 @@
  * NOTE: This flag is only meant to be used while testing. This should
  *       _always_ be undefined when checking code in.
  */
-
 #if 0
 #define HGFS_ASSERT_CLIENT(op) \
    do { \
@@ -76,7 +75,6 @@
  * NOTE: This flag is only meant to be used while testing. This should
  *       _always_ be undefined when checking code in.
  */
-
 #if 0
 #define HGFS_ASSERT_MINIMUM_OP(op) \
    do { \
@@ -186,9 +184,6 @@ static Bool hgfsChangeNotificationSupported = FALSE;
 
 /* Local functions. */
 
-static Bool HgfsServerCheckPathPrefix(const char *path,
-                                     const char *share,
-                                      size_t shareLen);
 static void HgfsInvalidateSessionObjects(DblLnkLst_Links *shares,
                                          HgfsSessionInfo *session);
 static Bool HgfsAddToCacheInternal(HgfsHandle handle,
@@ -206,6 +201,7 @@ static HgfsHandle HgfsSearch2SearchHandle(HgfsSearch const *search);
 static HgfsSearch *HgfsAddNewSearch(char const *utf8Dir,
                                     DirectorySearchType type,
                                     char const *utf8ShareName,
+                                    char const *rootDir,
                                     HgfsSessionInfo *session);
 static void HgfsDumpAllSearches(HgfsSessionInfo *session);
 static void HgfsDumpAllNodes(HgfsSessionInfo *session);
@@ -493,7 +489,8 @@ HgfsDumpAllNodes(HgfsSessionInfo *session)  // IN: session info
 Bool
 HgfsHandle2FileDesc(HgfsHandle handle,        // IN: Hgfs file handle
                     HgfsSessionInfo *session, // IN: Session info
-                    fileDesc *fd)             // OUT: OS handle (file descriptor)
+                    fileDesc *fd,             // OUT: OS handle (file descriptor)
+                    void **fileCtx)           // OUT: OS file context
 {
    Bool found = FALSE;
    HgfsFileNode *fileNode = NULL;
@@ -505,6 +502,9 @@ HgfsHandle2FileDesc(HgfsHandle handle,        // IN: Hgfs file handle
    }
 
    *fd = fileNode->fileDesc;
+   if (fileCtx) {
+      *fileCtx = fileNode->fileCtx;
+   }
    found = TRUE;
 
 exit:
@@ -767,6 +767,37 @@ HgfsHandle2FileName(HgfsHandle handle,       // IN: Hgfs file handle
                     HgfsSessionInfo *session,// IN: Session info
                     char **fileName,         // OUT: UTF8 file name
                     size_t *fileNameSize)    // OUT: UTF8 file name size
+{
+   Bool unused1, unused2;
+   return HgfsHandle2FileNameMode(handle, session, &unused1, &unused2, fileName,
+                                  fileNameSize);
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsHandle2FileNameMode --
+ *
+ *    Given an OS handle/fd, return file's hgfs name and permissions
+ *    associated with the corresponding shared folder.
+ *
+ * Results:
+ *    TRUE if the node was found.
+ *    FALSE otherwise.
+ *
+ * Side effects:
+ *    Allocates memory and makes a copy of the file name.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsHandle2FileNameMode(HgfsHandle handle,       // IN: Hgfs file handle
+                        HgfsSessionInfo *session,// IN: Session info
+                        Bool *readPermissions,   // OUT: shared folder permissions
+                        Bool *writePermissions,  // OUT: shared folder permissions
+                        char **fileName,         // OUT: UTF8 file name
+                        size_t *fileNameSize)    // OUT: UTF8 file name size
 {
    Bool found = FALSE;
    HgfsFileNode *existingFileNode = NULL;
@@ -787,6 +818,8 @@ HgfsHandle2FileName(HgfsHandle handle,       // IN: Hgfs file handle
    if (name == NULL) {
       goto exit_unlock;
    }
+   *readPermissions = existingFileNode->shareInfo.readPermissions;
+   *writePermissions = existingFileNode->shareInfo.writePermissions;
    nameSize = existingFileNode->utf8NameLen;
    memcpy(name, existingFileNode->utf8Name, nameSize);
    name[nameSize] = '\0';
@@ -836,7 +869,6 @@ HgfsFileHasServerLock(const char *utf8Name,             // IN: Name in UTF8
    SyncMutex_Lock(&session->nodeArrayLock);
    for (i = 0; i < session->numNodes; i++) {
       HgfsFileNode *existingFileNode = &session->nodeArray[i];
-
       if ((existingFileNode->state == FILENODE_STATE_IN_USE_CACHED) &&
           (existingFileNode->serverLock != HGFS_LOCK_NONE) &&
           (!stricmp(existingFileNode->utf8Name, utf8Name))) {
@@ -912,6 +944,7 @@ HgfsGetNodeCopy(HgfsHandle handle,        // IN: Hgfs file handle
    copy->flags = original->flags;
    copy->state = original->state;
    copy->handle = original->handle;
+   copy->fileCtx = original->fileCtx;
    found = TRUE;
 
 exit:
@@ -1025,7 +1058,8 @@ exit:
 Bool
 HgfsUpdateNodeFileDesc(HgfsHandle handle,        // IN: Hgfs file handle
                        HgfsSessionInfo *session, // IN: Session info
-                       fileDesc fd)              // OUT: OS handle (file desc)
+                       fileDesc fd,              // IN: OS handle (file desc)
+                       void *fileCtx)            // IN: OS file context
 {
    HgfsFileNode *node;
    Bool updated = FALSE;
@@ -1037,6 +1071,7 @@ HgfsUpdateNodeFileDesc(HgfsHandle handle,        // IN: Hgfs file handle
    }
 
    node->fileDesc = fd;
+   node->fileCtx = fileCtx;
    updated = TRUE;
 
 exit:
@@ -1198,7 +1233,6 @@ HgfsServerCheckOpenFlagsForShare(HgfsFileOpenInfo *openInfo,// IN: Hgfs file han
           * if the file does not exist, which it is okay, as creating
           * a new file is not allowed and should be failed.
           */
-
          *flags = HGFS_OPEN;
       }
    }
@@ -1287,7 +1321,6 @@ HgfsGetNewNode(HgfsSessionInfo *session)  // IN: session info
        * This has to be unsigned and with maximum bit length. This is
        * required to take care of "negative" differences as well.
        */
-
       uintptr_t ptrDiff;
 
       if (DOLOG(4)) {
@@ -1330,7 +1363,6 @@ HgfsGetNewNode(HgfsSessionInfo *session)  // IN: session info
          /*
           * Rebase the links of all file nodes
           */
-
          for (i = 0; i < session->numNodes; i++) {
             HgfsServerRebase(newMem[i].links.prev, DblLnkLst_Links)
             HgfsServerRebase(newMem[i].links.next, DblLnkLst_Links)
@@ -1356,6 +1388,7 @@ HgfsGetNewNode(HgfsSessionInfo *session)  // IN: session info
          newMem[i].state = FILENODE_STATE_UNUSED;
          newMem[i].utf8Name = NULL;
          newMem[i].utf8NameLen = 0;
+         newMem[i].fileCtx = NULL;
 
          /* Append at the end of the list */
          DblLnkLst_LinkLast(&session->nodeFreeList, &newMem[i].links);
@@ -1416,6 +1449,8 @@ HgfsRemoveFileNode(HgfsFileNode *node,        // IN: file node
    }
    node->utf8Name = NULL;
    node->state = FILENODE_STATE_UNUSED;
+   ASSERT(node->fileCtx == NULL);
+   node->fileCtx = NULL;
 
    /* Prepend at the beginning of the list */
    DblLnkLst_LinkFirst(&session->nodeFreeList, &node->links);
@@ -1510,6 +1545,7 @@ HgfsAddNewFileNode(HgfsFileOpenInfo *openInfo,  // IN: open info struct
                    HgfsSessionInfo *session)    // IN: session info
 {
    HgfsFileNode *newNode;
+   char* rootDir;
 
    ASSERT(openInfo);
    ASSERT(localId);
@@ -1529,7 +1565,6 @@ HgfsAddNewFileNode(HgfsFileOpenInfo *openInfo,  // IN: open info struct
    /* Set new node's fields */
    if (!HgfsServerGetOpenMode(openInfo, &newNode->mode)) {
       HgfsRemoveFileNode(newNode, session);
-
       return NULL;
    }
 
@@ -1537,12 +1572,10 @@ HgfsAddNewFileNode(HgfsFileOpenInfo *openInfo,  // IN: open info struct
     * Save a copy of the share name so we can look up its
     * access mode at various times over the node's lifecycle.
     */
-
    newNode->shareName = malloc(shareNameLen + 1);
    if (newNode->shareName == NULL) {
       LOG(4, ("%s: out of memory\n", __FUNCTION__));
       HgfsRemoveFileNode(newNode, session);
-
       return NULL;
    }
    memcpy(newNode->shareName, shareName, shareNameLen);
@@ -1554,12 +1587,22 @@ HgfsAddNewFileNode(HgfsFileOpenInfo *openInfo,  // IN: open info struct
    if (newNode->utf8Name == NULL) {
       LOG(4, ("%s: out of memory\n", __FUNCTION__));
       HgfsRemoveFileNode(newNode, session);
-
       return NULL;
    }
    memcpy(newNode->utf8Name, openInfo->utf8Name, newNode->utf8NameLen);
    newNode->utf8Name[newNode->utf8NameLen] = '\0';
 
+   newNode->shareInfo.rootDirLen = strlen(openInfo->shareInfo.rootDir);
+   rootDir = malloc(newNode->shareInfo.rootDirLen + 1);
+   if (rootDir == NULL) {
+      LOG(4, ("HgfsAddNewFileNode: out of memory\n"));
+      HgfsRemoveFileNode(newNode, session);
+      return NULL;
+   }
+   memcpy(rootDir, openInfo->shareInfo.rootDir, newNode->shareInfo.rootDirLen);
+   rootDir[newNode->shareInfo.rootDirLen] = '\0';
+   newNode->shareInfo.rootDir = rootDir;
+
    newNode->handle = HgfsServerGetNextHandleCounter();
    newNode->localId = *localId;
    newNode->fileDesc = fileDesc;
@@ -1579,10 +1622,11 @@ HgfsAddNewFileNode(HgfsFileOpenInfo *openInfo,  // IN: open info struct
 
    newNode->serverLock = openInfo->acquiredLock;
    newNode->state = FILENODE_STATE_IN_USE_NOT_CACHED;
+   newNode->shareInfo.readPermissions = openInfo->shareInfo.readPermissions;
+   newNode->shareInfo.writePermissions = openInfo->shareInfo.writePermissions;
 
    LOG(4, ("%s: got new node, handle %u\n", __FUNCTION__,
            HgfsFileNode2Handle(newNode)));
-
    return newNode;
 }
 
@@ -1619,7 +1663,6 @@ HgfsAddToCacheInternal(HgfsHandle handle,         // IN: HGFS file handle
    if (HgfsIsCachedInternal(handle, session)) {
       ASSERT((node = HgfsHandle2FileNode(handle, session)) &&
              node->state == FILENODE_STATE_IN_USE_CACHED);
-
       return TRUE;
    }
 
@@ -1714,12 +1757,12 @@ HgfsRemoveFromCacheInternal(HgfsHandle handle,        // IN: Hgfs handle to the
        * Instead, we'll just await the lobotomization of the node cache to
        * really fix this.
        */
-
-      if (HgfsCloseFile(node->fileDesc)) {
+      if (HgfsCloseFile(node->fileDesc, node->fileCtx)) {
          LOG(4, ("%s: Could not close fd %u\n", __FUNCTION__, node->fileDesc));
 
          return FALSE;
       }
+      node->fileCtx = NULL;
 
      /*
       * If we have just removed the node then the number of used nodes better
@@ -1775,7 +1818,6 @@ HgfsIsCachedInternal(HgfsHandle handle,         // IN: Structure representing fi
       /*
        * Move this node to the end of the list.
        */
-
       DblLnkLst_Unlink1(&node->links);
       DblLnkLst_LinkLast(&session->nodeCachedList, &node->links);
 
@@ -1927,6 +1969,8 @@ HgfsGetNewSearch(HgfsSessionInfo *session)  // IN: session info
          newMem[i].utf8DirLen = 0;
          newMem[i].utf8ShareName = NULL;
          newMem[i].utf8ShareNameLen = 0;
+         newMem[i].shareInfo.rootDir = NULL;
+         newMem[i].shareInfo.rootDirLen = 0;
          newMem[i].dents = NULL;
          newMem[i].numDents = 0;
 
@@ -2070,6 +2114,7 @@ HgfsSearch *
 HgfsAddNewSearch(char const *utf8Dir,       // IN: UTF8 name of dir to search in
                  DirectorySearchType type,  // IN: What kind of search is this?
                  char const *utf8ShareName, // IN: Share name containing the directory
+                 char const *rootDir,       // IN: Root directory for the share
                  HgfsSessionInfo *session)  // IN: Session info
 {
    HgfsSearch *newSearch;
@@ -2105,9 +2150,15 @@ HgfsAddNewSearch(char const *utf8Dir,       // IN: UTF8 name of dir to search in
       return NULL;
    }
 
+   newSearch->shareInfo.rootDirLen = strlen(rootDir);
+   newSearch->shareInfo.rootDir = strdup(rootDir);
+   if (newSearch->shareInfo.rootDir == NULL) {
+      HgfsRemoveSearchInternal(newSearch, session);
+      return NULL;
+   }
+
    LOG(4, ("%s: got new search, handle %u\n", __FUNCTION__,
            HgfsSearch2SearchHandle(newSearch)));
-
    return newSearch;
 }
 
@@ -2153,6 +2204,7 @@ HgfsRemoveSearchInternal(HgfsSearch *search,       // IN: search
 
    free(search->utf8Dir);
    free(search->utf8ShareName);
+   free((char*)search->shareInfo.rootDir);
 
    /* Prepend at the beginning of the list */
    DblLnkLst_LinkFirst(&session->searchFreeList, &search->links);
@@ -2274,7 +2326,6 @@ HgfsGetSearchResult(HgfsHandle handle,         // IN: Handle to search
        * at the top of hgfsServerInt.h, you'll see that on Windows we only
        * define d_reclen and d_name, as those are the only fields we need.
        */
-
       dent->d_reclen = originalDent->d_reclen;
       memcpy(dent->d_name, originalDent->d_name, nameLen);
       dent->d_name[nameLen] = 0;
@@ -2598,6 +2649,7 @@ static struct {
    { HgfsServerQueryVolume,      HGFS_SIZEOF_OP(HgfsRequestQueryVolumeV3)      },
    { HgfsServerSymlinkCreate,    HGFS_SIZEOF_OP(HgfsRequestSymlinkCreateV3)    },
    { HgfsServerServerLockChange, sizeof (HgfsRequestServerLockChange)          },
+   { HgfsServerWriteWin32Stream, HGFS_SIZEOF_OP(HgfsRequestWriteWin32StreamV3) },
 
 };
 
@@ -3283,67 +3335,6 @@ HgfsPackAndSendPacket(char *packet,               // IN: packet to send
 }
 
 
-/*
- *-----------------------------------------------------------------------------
- *
- * HgfsServerCheckPathPrefix --
- *
- *      Given a path and a Hgfs host share path, check to see if the given
- *      share is a prefix of the path.
- *
- * Results:
- *      TRUE if share is a prefix of path.
- *      FALSE otherwise.
- *
- * Side effects:
- *      None
- *
- *-----------------------------------------------------------------------------
- */
-
-static Bool
-HgfsServerCheckPathPrefix(const char *path,  // IN: Path to check
-                          const char *share, // IN: Prefix of path
-                          size_t shareLen)   // IN: Length of share
-{
-   ASSERT(path);
-   ASSERT(share);
-
-   /* First make sure that share is a prefix of path. */
-   if (strncmp(path, share, shareLen) != 0) {
-      return FALSE;
-   }
-
-   /*
-    * Special case. The root share on Linux or Apple ("/") will not be followed
-    * by a second path separator. In this case, no additional checks besides the
-    * initial prefix check are needed. Just return success.
-    */
-
-   if (shareLen == 1 && *share == DIRSEPC) {
-      return TRUE;
-   }
-
-   /*
-    * Now check to prevent false positives. In particular, consider the case
-    * where we have two shares: shareName and shareName1.
-    * Given the path /shareName1/test, the above check will allow through both
-    * shareName and shareName1. Check to make sure that the given share is
-    * a full path component.
-    */
-
-   if (*(path + shareLen) == DIRSEPC) {
-      return TRUE;
-   }
-
-   if (*(path + shareLen) == '\0') {
-      return TRUE;
-   }
-
-   return FALSE;
-}
-
-
 /*
  *-----------------------------------------------------------------------------
  *
@@ -3380,7 +3371,6 @@ HgfsInvalidateSessionObjects(DblLnkLst_Links *shares,  // IN: List of new shares
     * Iterate over each node, skipping those that are unused. For each node,
     * if its filename is no longer within a share, remove it.
     */
-
    for (i = 0; i < session->numNodes; i++) {
       HgfsHandle handle;
       DblLnkLst_Links *l;
@@ -3399,9 +3389,7 @@ HgfsInvalidateSessionObjects(DblLnkLst_Links *shares,  // IN: List of new shares
 
          share = DblLnkLst_Container(l, HgfsSharedFolder, links);
          ASSERT(share);
-         if (HgfsServerCheckPathPrefix(session->nodeArray[i].utf8Name,
-                                       share->path,
-                                       share->pathLen)) {
+         if (strcmp(session->nodeArray[i].shareInfo.rootDir, share->path) == 0) {
             LOG(4, ("%s: Node is still valid\n", __FUNCTION__));
             break;
          }
@@ -3427,7 +3415,6 @@ HgfsInvalidateSessionObjects(DblLnkLst_Links *shares,  // IN: List of new shares
     * Iterate over each search, skipping those that are on the free list. For
     * each search, if its base name is no longer within a share, remove it.
     */
-
    for (i = 0; i < session->numSearches; i++) {
       HgfsHandle handle;
       DblLnkLst_Links *l;
@@ -3446,8 +3433,7 @@ HgfsInvalidateSessionObjects(DblLnkLst_Links *shares,  // IN: List of new shares
 
          share = DblLnkLst_Container(l, HgfsSharedFolder, links);
          ASSERT(share);
-         if (HgfsServerCheckPathPrefix(session->searchArray[i].utf8Dir,
-                                       share->path, share->pathLen)) {
+         if (strcmp(session->searchArray[i].shareInfo.rootDir, share->path) == 0) {
             LOG(4, ("%s: Search is still valid\n", __FUNCTION__));
             break;
          }
@@ -3542,7 +3528,6 @@ HgfsServerStatFs(const char *pathName, // IN: Path we're interested in
     * delimiter on copy. Allow 0 length drives so that hidden feature "" can
     * work.
     */
-
    if (pathLength < 0 || pathLength >= sizeof p.mountPoint) {
       LOG(4, ("%s: could not get the volume name\n", __FUNCTION__));
 
@@ -3565,16 +3550,15 @@ HgfsServerStatFs(const char *pathName, // IN: Path we're interested in
 /*
  *-----------------------------------------------------------------------------
  *
- * HgfsServerGetAccess --
+ * HgfsServerGetShareInfo --
  *
- *    Test a name for access permission and construct its local name
- *    if access is allowed. The name returned is allocated and must be
- *    freed by the caller.
+ *    Construct local name based on the crossplatform CPName for the file.
+ *    The name returned is allocated and must be freed by the caller.
  *
  *    outLen can be NULL, in which case the length is not returned.
  *
  * Results:
- *    A status code indicating either success (access is allowed) or
+ *    A status code indicating either success (correspondent share exists) or
  *    a failure status.
  *
  * Side effects:
@@ -3584,22 +3568,20 @@ HgfsServerStatFs(const char *pathName, // IN: Path we're interested in
  */
 
 HgfsNameStatus
-HgfsServerGetAccess(char *cpName,                  // IN:  Cross-platform filename to check
-                    size_t cpNameSize,             // IN:  Size of name cpName
-                    HgfsOpenMode mode,             // IN:  Requested access mode
-                    uint32 caseFlags,              // IN:  Case-sensitivity flags
-                    char **bufOut,                 // OUT: File name in local fs
-                    size_t *outLen)                // OUT: Length of name out
+HgfsServerGetShareInfo(char *cpName,            // IN:  Cross-platform filename to check
+                       size_t cpNameSize,       // IN:  Size of name cpName
+                       uint32 caseFlags,        // IN:  Case-sensitivity flags
+                       HgfsShareInfo *shareInfo,// OUT: properties of the shared folder
+                       char **bufOut,           // OUT: File name in local fs
+                       size_t *outLen)          // OUT: Length of name out
 {
    HgfsNameStatus nameStatus;
-   char const *sharePath;
    char const *inEnd;
    char *next;
    char *myBufOut;
    char *convertedMyBufOut;
    char *out;
    size_t outSize;
-   size_t sharePathLen; /* Length of share's path */
    size_t myBufOutLen;
    size_t convertedMyBufOutLen;
    int len;
@@ -3631,14 +3613,16 @@ HgfsServerGetAccess(char *cpName,                  // IN:  Cross-platform filena
    }
 
    /* Check permission on the share and get the share path */
-   nameStatus = HgfsServerPolicy_GetSharePath(cpName, len, mode, &sharePathLen,
-                                              &sharePath);
+   nameStatus = HgfsServerPolicy_ProcessCPName(cpName,
+                                               len,
+                                               &shareInfo->readPermissions,
+                                               &shareInfo->writePermissions,
+                                               &shareInfo->rootDir);
    if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
-      LOG(4, ("%s: No such share (%s) or access denied\n", __FUNCTION__,
-              cpName));
-
+      LOG(4, ("%s: No such share (%s)\n", __FUNCTION__, cpName));
       return nameStatus;
    }
+   shareInfo->rootDirLen = strlen(shareInfo->rootDir);
 
    /* Get the config options. */
    nameStatus = HgfsServerPolicy_GetShareOptions(cpName, len, &shareOptions);
@@ -3669,8 +3653,7 @@ HgfsServerGetAccess(char *cpName,                  // IN:  Cross-platform filena
    /*
     * See if we are dealing with a "root" share or regular share
     */
-
-   if (strlen(sharePath) == 0) {
+   if (shareInfo->rootDirLen == 0) {
       size_t prefixLen;
 
       /*
@@ -3679,7 +3662,6 @@ HgfsServerGetAccess(char *cpName,                  // IN:  Cross-platform filena
        * buffer (for Win32) or simply get the prefix for root (for
        * linux).
        */
-
       tempSize = sizeof tempBuf;
       tempPtr = tempBuf;
       nameStatus = CPName_ConvertFromRoot((char const **) &cpName,
@@ -3706,16 +3688,15 @@ HgfsServerGetAccess(char *cpName,                  // IN:  Cross-platform filena
       /*
        * This is a regular share. Append the path to the out buffer.
        */
-
-      if (outSize < sharePathLen + 1) {
+      if (outSize < shareInfo->rootDirLen + 1) {
          LOG(4, ("%s: share path too big\n", __FUNCTION__));
          nameStatus = HGFS_NAME_STATUS_TOO_LONG;
          goto error;
       }
 
-      memcpy(out, sharePath, sharePathLen + 1);
-      out += sharePathLen;
-      outSize -= sharePathLen;
+      memcpy(out, shareInfo->rootDir, shareInfo->rootDirLen + 1);
+      out += shareInfo->rootDirLen;
+      outSize -= shareInfo->rootDirLen;
    }
 
    /* Convert the rest of the input name (if any) to a local name */
@@ -3788,8 +3769,8 @@ HgfsServerGetAccess(char *cpName,                  // IN:  Cross-platform filena
    if (!HgfsServerPolicy_IsShareOptionSet(shareOptions,
                                           HGFS_SHARE_HOST_DEFAULT_CASE) &&
        HgfsServerCaseConversionRequired()) {
-      nameStatus = HgfsServerConvertCase(sharePath, sharePathLen, myBufOut,
-                                         myBufOutLen, caseFlags,
+      nameStatus = HgfsServerConvertCase(shareInfo->rootDir, shareInfo->rootDirLen,
+                                         myBufOut, myBufOutLen, caseFlags,
                                          &convertedMyBufOut,
                                          &convertedMyBufOutLen);
 
@@ -3820,12 +3801,11 @@ HgfsServerGetAccess(char *cpName,                  // IN:  Cross-platform filena
        * We should use the resolved file path for further file system
        * operations, instead of using the one passed from the client.
        */
-
-      nameStatus = HgfsServerHasSymlink(myBufOut, myBufOutLen, sharePath,
-                                        sharePathLen);
+      nameStatus = HgfsServerHasSymlink(myBufOut, myBufOutLen, shareInfo->rootDir,
+                                        shareInfo->rootDirLen);
       if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
-         LOG(4, ("%s: parent path failed to be resolved: %d\n", __FUNCTION__,
-                 nameStatus));
+         LOG(4, ("%s: parent path failed to be resolved: %d\n",
+                 __FUNCTION__, nameStatus));
          goto error;
       }
    }
@@ -3870,7 +3850,7 @@ error:
  *
  *    This function assumes that CPName_GetComponent() will always succeed
  *    with a size greater than 0, so it must ONLY be called after a call to
- *    HgfsServerGetAccess() that returns HGFS_NAME_STATUS_COMPLETE.
+ *    HgfsServerGetShareInfo() that returns HGFS_NAME_STATUS_COMPLETE.
  *
  * Results:
  *    True if it is a shared folder only, otherwise false
@@ -4010,7 +3990,6 @@ HgfsServerGetDents(HgfsGetNameFunc getName,     // IN: Function to get name
        * our purposes, so we use PATH_MAX as a reasonable upper bound on the
        * length of the name.
        */
-
       maxLen = PATH_MAX;
 #else
       maxLen = sizeof pDirEntry->d_name;
@@ -4130,9 +4109,9 @@ error_free:
 HgfsInternalStatus
 HgfsServerSearchRealDir(char const *baseDir,      // IN: Directory to search
                         size_t baseDirLen,        // IN: Length of directory
-                        DirectorySearchType type, // IN: Kind of search
                         char const *shareName,    // IN: Share name containing the directory
-                        HgfsSessionInfo *session, // IN: Share name containing the directory
+                        char const *rootDir,      // IN: Shared folder root directory
+                        HgfsSessionInfo *session, // IN: Session info
                         HgfsHandle *handle)       // OUT: Search handle
 {
    HgfsSearch *search = NULL;
@@ -4144,11 +4123,11 @@ HgfsServerSearchRealDir(char const *baseDir,      // IN: Directory to search
 
    ASSERT(baseDir);
    ASSERT(handle);
-   ASSERT(type == DIRECTORY_SEARCH_TYPE_DIR);
    ASSERT(shareName);
 
    SyncMutex_Lock(&session->searchArrayLock);
-   search = HgfsAddNewSearch(baseDir, type, shareName, session);
+   search = HgfsAddNewSearch(baseDir, DIRECTORY_SEARCH_TYPE_DIR, shareName,
+                             rootDir, session);
    if (!search) {
       LOG(4, ("%s: failed to get new search\n", __FUNCTION__));
       status = HGFS_INTERNAL_STATUS_ERROR;
@@ -4224,7 +4203,7 @@ HgfsServerSearchVirtualDir(HgfsGetNameFunc *getName,     // IN: Name enumerator
    ASSERT(handle);
 
    SyncMutex_Lock(&session->searchArrayLock);
-   search = HgfsAddNewSearch("", type, "", session);
+   search = HgfsAddNewSearch("", type, "", "", session);
    if (!search) {
       LOG(4, ("%s: failed to get new search\n", __FUNCTION__));
       status = HGFS_INTERNAL_STATUS_ERROR;
@@ -4352,24 +4331,39 @@ HgfsRemoveLruNode(HgfsSessionInfo *session)   // IN: session info
    ASSERT(session);
    ASSERT(session->numCachedOpenNodes > 0);
 
-   /* Remove the first item from the list that does not have a server lock. */
+   /*
+    * Remove the first item from the list that does not have a server lock,
+    * file context or is open in sequential mode.
+    */
    while (!found) {
       lruNode = DblLnkLst_Container(session->nodeCachedList.next,
                                     HgfsFileNode, links);
 
       ASSERT(lruNode->state == FILENODE_STATE_IN_USE_CACHED);
-      if (lruNode->serverLock != HGFS_LOCK_NONE) {
-         /* Move this node with the server lock to the beginning of the list. */
+      if (lruNode->serverLock != HGFS_LOCK_NONE || lruNode->fileCtx != NULL
+          || (lruNode->flags & HGFS_FILE_NODE_SEQUENTIAL_FL) != 0) {
+         /*
+         * Move this node with the server lock to the beginning of the list.
+         * Also, prevent files opened in HGFS_FILE_NODE_SEQUENTIAL_FL mode
+         * from being closed. -- On some platforms, this mode does not
+         * allow files to be closed/re-opened (eg: When restoring a file
+         * into a Windows guest you cannot use BackupWrite, then close and
+         * re-open the file and continue to use BackupWrite.
+         */
          DblLnkLst_Unlink1(&lruNode->links);
          DblLnkLst_LinkLast(&session->nodeCachedList, &lruNode->links);
       } else {
          found = TRUE;
       }
    }
-   handle = HgfsFileNode2Handle(lruNode);
-   if (!HgfsRemoveFromCacheInternal(handle, session)) {
-      LOG(4, ("%s: Could not remove the node from cache.\n", __FUNCTION__));
-
+   if (found) {
+      handle = HgfsFileNode2Handle(lruNode);
+      if (!HgfsRemoveFromCacheInternal(handle, session)) {
+         LOG(4, ("%s: Could not remove the node from cache.\n", __FUNCTION__));
+         return FALSE;
+      }
+   } else {
+      LOG(4, ("%s: Could not find a node to remove from cache.\n", __FUNCTION__));
       return FALSE;
    }
 
@@ -4546,7 +4540,6 @@ HgfsUnpackOpenRequest(char const *packetIn,        // IN: request packet
           * requestV3->fileName.length is user-provided, so this test must be
           * carefully written to prevent wraparounds.
           */
-
          if (requestV3->fileName.length > extra) {
             /* The input packet is smaller than the request. */
 
@@ -4558,12 +4551,11 @@ HgfsUnpackOpenRequest(char const *packetIn,        // IN: request packet
           * garbage, but it's simpler to copy everything now and check the
           * valid bits before reading later.
           */
-
          openInfo->mask = requestV3->mask;
          openInfo->mode = requestV3->mode;
          openInfo->cpName = requestV3->fileName.name;
          openInfo->cpNameSize = requestV3->fileName.length;
-        openInfo->caseFlags = requestV3->fileName.caseType;
+         openInfo->caseFlags = requestV3->fileName.caseType;
          openInfo->flags = requestV3->flags;
          openInfo->specialPerms = requestV3->specialPerms;
          openInfo->ownerPerms = requestV3->ownerPerms;
@@ -4595,7 +4587,6 @@ HgfsUnpackOpenRequest(char const *packetIn,        // IN: request packet
           * requestV2->fileName.length is user-provided, so this test must be
           * carefully written to prevent wraparounds.
           */
-
          if (requestV2->fileName.length > extra) {
             /* The input packet is smaller than the request. */
             return FALSE;
@@ -4814,7 +4805,6 @@ HgfsUnpackDeleteRequest(char const *packetIn,        // IN: request packet
        * If we've been asked to reuse a handle, we don't need to look at, let
        * alone test the filename or its length.
        */
-
       if (requestV3->fileName.flags & HGFS_FILE_NAME_USE_FILE_DESC) {
          *file = requestV3->fileName.fid;
          *cpName = NULL;
@@ -4827,7 +4817,6 @@ HgfsUnpackDeleteRequest(char const *packetIn,        // IN: request packet
           * request->fileName.length is user-provided, so this test must be
           * carefully written to prevent wraparounds.
           */
-
          if (requestV3->fileName.length > extra) {
             /* The input packet is smaller than the request */
 
@@ -4835,7 +4824,7 @@ HgfsUnpackDeleteRequest(char const *packetIn,        // IN: request packet
          }
          *cpName = requestV3->fileName.name;
          *cpNameSize = requestV3->fileName.length;
-        *caseFlags = requestV3->fileName.caseType;
+         *caseFlags = requestV3->fileName.caseType;
       }
       break;
    }
@@ -4866,7 +4855,6 @@ HgfsUnpackDeleteRequest(char const *packetIn,        // IN: request packet
           * request->fileName.length is user-provided, so this test must be
           * carefully written to prevent wraparounds.
           */
-
          if (requestV2->fileName.length > extra) {
             /* The input packet is smaller than the request */
 
@@ -5059,7 +5047,6 @@ HgfsUnpackRenameRequest(char const *packetIn,       // IN: request packet
        * alone test the filename or its length. This applies to the source
        * and the target.
        */
-
       if (requestV3->oldName.flags & HGFS_FILE_NAME_USE_FILE_DESC) {
          *srcFile = requestV3->oldName.fid;
          *cpOldName = NULL;
@@ -5073,7 +5060,6 @@ HgfsUnpackRenameRequest(char const *packetIn,       // IN: request packet
           * request->fileName.length is user-provided, so this test must be
           * carefully written to prevent wraparounds.
           */
-
          if (requestV3->oldName.length > extra) {
             /* The input packet is smaller than the request */
 
@@ -6470,6 +6456,137 @@ HgfsPackCreateDirReply(char const *packetIn,      // IN: create dir operation ve
 }
 
 
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsUnpackWriteWin32StreamRequest --
+ *
+ *    Unpack hgfs SendFileUsingReader request. Returns file to write to, data
+ *    and whether to restore the security stream.
+ *
+ * Results:
+ *    TRUE on success.
+ *    FALSE on failure.
+ *
+ * Side effects:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsUnpackWriteWin32StreamRequest(char const *packetIn, // IN: incoming packet
+                                 size_t packetSize,    // IN: size of packet
+                                 HgfsHandle *file,     // OUT: file to write to
+                                 char **payload,       // OUT: data to write
+                                 size_t *requiredSize, // OUT: size of data
+                                 Bool *doSecurity)     // OUT: restore sec.str.
+{
+   HgfsRequest *request;
+   size_t extra;
+
+   ASSERT(packetIn);
+   ASSERT(file);
+   ASSERT(payload);
+   ASSERT(requiredSize);
+   ASSERT(doSecurity);
+
+   request = (HgfsRequest *)packetIn;
+
+   switch (request->op) {
+   case HGFS_OP_WRITE_WIN32_STREAM_V3:
+      {
+         HgfsRequestWriteWin32StreamV3 *requestV3 =
+           (HgfsRequestWriteWin32StreamV3 *)HGFS_REQ_GET_PAYLOAD_V3(packetIn);
+
+        /* Enforced by the dispatch function */
+        ASSERT(packetSize >= HGFS_REQ_PAYLOAD_SIZE_V3(request) - 1);
+        extra = packetSize - HGFS_REQ_PAYLOAD_SIZE_V3(request) + 1;
+
+        *file = requestV3->file;
+        *payload = requestV3->payload;
+        *requiredSize = requestV3->requiredSize;
+        *doSecurity = (requestV3->flags & HGFS_WIN32_STREAM_IGNORE_SECURITY) == 0;
+
+         /*
+         * requiredSize is user-provided, so this test must be carefully
+         * written to prevent wraparounds.
+         */
+        if (*requiredSize > extra) {
+           /*
+            * The driver wants to write more bytes than there is in its payload.
+            * Truncate the request.
+            */
+           
+           *requiredSize = extra;
+        }
+
+        break;
+      }
+   default:
+      return FALSE;
+   }
+
+   return TRUE;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsPackWriteWin32StreamReply --
+ *
+ *    Pack hgfs SendFileUsingReader reply.
+ *    Returns the actual amount of data written in the reply.
+ *
+ * Results:
+ *    TRUE if valid op and reply set, FALSE otherwise.
+ *
+ * Side effects:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsPackWriteWin32StreamReply(char const *packetIn,      // IN: incoming packet
+                             HgfsInternalStatus status, // IN: reply status
+                             uint32 actualSize,         // IN: amount written
+                             char **packetOut,          // OUT: outgoing packet
+                             size_t *packetSize)        // OUT: size of packet
+{
+   HgfsRequest *header = (HgfsRequest *)packetIn;
+
+   ASSERT(packetIn);
+   ASSERT(packetOut);
+   ASSERT(packetSize);
+
+   *packetOut = NULL;
+   *packetSize = 0;
+
+   switch (header->op) {
+   case HGFS_OP_WRITE_WIN32_STREAM_V3: {
+      HgfsReplyWriteWin32StreamV3 *reply;
+
+      *packetSize = HGFS_REP_PAYLOAD_SIZE_V3(reply);
+      *packetOut = Util_SafeMalloc(*packetSize);
+      ((HgfsReply *)*packetOut)->id = header->id;
+      ((HgfsReply *)*packetOut)->status = HgfsConvertFromInternalStatus(status);
+
+      reply = (HgfsReplyWriteWin32StreamV3 *)HGFS_REP_GET_PAYLOAD_V3(*packetOut);
+      reply->actualSize = actualSize;
+      reply->reserved = 0;
+      break;
+   }
+   default:
+      return FALSE;
+   }
+
+   return TRUE;
+}
+
+
+
 /*
  *-----------------------------------------------------------------------------
  *
@@ -6529,7 +6646,6 @@ HgfsBuildRelativePath(const char* source,    // IN: source file name
     * Find out how many directories deep the source file is from the common
     * part of the  path.
     */
-
    while(*relativeSource != '\0') {
       sourceSep = strchr(relativeSource, DIRSEPC);
       if (sourceSep != NULL) {
@@ -6553,8 +6669,7 @@ HgfsBuildRelativePath(const char* source,    // IN: source file name
     * to the relative target path.
     */
 
-   targetSize = level * HGFS_PARENT_DIR_LEN + strlen(relativeTarget) +
-                                                                  sizeof '\0';
+   targetSize = level * HGFS_PARENT_DIR_LEN + strlen(relativeTarget) + sizeof '\0';
    result = malloc(targetSize);
    currentPosition = result;
    if (result != NULL) {
@@ -6563,10 +6678,8 @@ HgfsBuildRelativePath(const char* source,    // IN: source file name
          level--;
          currentPosition += HGFS_PARENT_DIR_LEN;
       }
-      memcpy(currentPosition, relativeTarget, strlen(relativeTarget) +
-                                                                 sizeof '\0');
+      memcpy(currentPosition, relativeTarget, strlen(relativeTarget) + sizeof '\0');
    }
-
    return result;
 }
 
@@ -6651,7 +6764,6 @@ HgfsServerOplockBreakReply(const unsigned char *packetIn, // IN: Reply packet
     * is double checked in HgfsAckOplockBreak, so we'd be safe from a garbage
     * value.
     */
-
    HgfsAckOplockBreak(lockData, reply->serverLock);
 }
 
index 96f45f1a6561e4ef9eae62cade3015ac25be7531..ef46d2934ab07979e19db33d32a43834647df4c7 100644 (file)
@@ -127,6 +127,20 @@ typedef enum {
 #  define HGFS_DEFAULT_SHARE_ACCESS 0
 #endif // _WIN32
 
+typedef struct HgfsShareInfo {
+   /* Filename of the root directory for the shared folder */
+   const char *rootDir;
+
+   /* Length of the root directory filename (does not include nul terminator) */
+   size_t rootDirLen;
+
+   /* Read permissions for the shared folder, needed for handle => name conversions. */
+   Bool readPermissions;
+
+   /* Write permissions for the shared folder, needed for handle => name conversions. */
+   Bool writePermissions;
+} HgfsShareInfo;
+
 /*
  * This struct represents a file on the local filesystem that has been
  * opened by a remote client. We store the name of the local file and
@@ -178,6 +192,17 @@ typedef struct HgfsFileNode {
 
    /* File flags - see below. */
    uint32 flags;
+
+   /*
+    * Context as required by some file operations. Eg: BackupWrite on
+    * Windows: BackupWrite requires the caller to hold on to a pointer
+    * to a Windows internal data structure between subsequent calls to
+    * BackupWrite while restoring a file.
+    */
+   void *fileCtx;
+
+   /* Parameters associated with the share. */
+   HgfsShareInfo shareInfo;
 } HgfsFileNode;
 
 
@@ -228,6 +253,9 @@ typedef struct HgfsSearch {
     * when we want to retrieve the attributes for each dent.
     */
    DirectorySearchType type;
+
+   /* Parameters associated with the share. */
+   HgfsShareInfo shareInfo;
 } HgfsSearch;
 
 /* HgfsSessionInfo flags. */
@@ -339,6 +367,7 @@ typedef struct HgfsFileOpenInfo {
    char *cpName;
    char *utf8Name;
    uint32 caseFlags;                 /* Case-sensitivity flags. */
+   HgfsShareInfo shareInfo;          /* Parameters associated with the share. */
 } HgfsFileOpenInfo;
 
 typedef struct HgfsFileAttrInfo {
@@ -431,6 +460,14 @@ HgfsServerGetAccess(char *in,                    // IN:  CP filename to check
                     char **bufOut,               // OUT: File name in local fs
                     size_t *outLen);             // OUT: Length of name out
 
+HgfsNameStatus
+HgfsServerGetShareInfo(char *cpName,            // IN:  Cross-platform filename to check
+                       size_t cpNameSize,       // IN:  Size of name cpName
+                       uint32 caseFlags,        // IN:  Case-sensitivity flags
+                       HgfsShareInfo* shareInfo,// OUT: Shared folder properties
+                       char **bufOut,           // OUT: File name in local fs
+                       size_t *outLen);         // OUT: Length of name out
+
 Bool
 HgfsServerIsSharedFolderOnly(char const *in,  // IN:  CP filename to check
                              size_t inSize);  // IN:  Size of name in
@@ -445,8 +482,8 @@ HgfsServerScandir(char const *baseDir,      // IN: Directory to search in
 HgfsInternalStatus
 HgfsServerSearchRealDir(char const *baseDir,      // IN: Directory to search
                         size_t baseDirLen,        // IN: Length of directory
-                        DirectorySearchType type, // IN: Kind of search
                         char const *shareName,    // IN: Share name
+                        char const *rootDir,      // IN: Root directory for the share
                         HgfsSessionInfo *session, // IN: Session info
                         HgfsHandle *handle);      // OUT: Search handle
 
@@ -532,6 +569,11 @@ HgfsServerServerLockChange(char const *packetIn,       // IN: incoming packet
                            size_t packetSize,          // IN: size of packet
                            HgfsSessionInfo *session);  // IN: opaque transport data
 
+HgfsInternalStatus
+HgfsServerWriteWin32Stream(char const *packetIn,       // IN: incoming packet
+                           size_t packetSize,          // IN: size of packet
+                           HgfsSessionInfo *session);  // IN: opaque transport data
+
 /* Unpack/pack requests/reply helper functions. */
 
 Bool
@@ -643,6 +685,21 @@ HgfsPackCreateDirReply(char const *packetIn,      // IN: incoming packet
                        char **packetOut,          // OUT: outgoing packet
                        size_t *packetSize);       // OUT: size of packet
 
+Bool
+HgfsUnpackWriteWin32StreamRequest(char const *packetIn, // IN: incoming packet
+                                 size_t packetSize,    // IN: size of packet
+                                 HgfsHandle *file,     // OUT: file to write to
+                                 char **payload,       // OUT: data to write
+                                 size_t *requiredSize, // OUT: size of data
+                                 Bool *doSecurity);    // OUT: restore sec.str.
+
+Bool
+HgfsPackWriteWin32StreamReply(char const *packetIn,      // IN: incoming packet
+                             HgfsInternalStatus status, // IN: reply status
+                             uint32 actualSize,         // IN: amount written
+                             char **packetOut,          // OUT: outgoing packet
+                             size_t *packetSize);       // OUT: size of packet
+
 /* Node cache functions. */
 
 Bool
@@ -663,7 +720,8 @@ HgfsIsServerLockAllowed(HgfsSessionInfo *session);  // IN: session info
 Bool
 HgfsHandle2FileDesc(HgfsHandle handle,        // IN: Hgfs file handle
                     HgfsSessionInfo *session, // IN: session info
-                    fileDesc *fd);            // OUT: OS handle (file descriptor)
+                    fileDesc *fd,             // OUT: OS handle (file descriptor)
+                    void **fileCtx);          // OUT: OS file context
 
 Bool
 HgfsFileDesc2Handle(fileDesc fd,              // IN: OS handle (file descriptor)
@@ -680,7 +738,13 @@ HgfsHandle2FileName(HgfsHandle handle,        // IN: Hgfs file handle
                     HgfsSessionInfo *session, // IN: session info
                     char **fileName,          // OUT: CP file name
                     size_t *fileNameSize);    // OUT: CP file name size
-
+Bool
+HgfsHandle2FileNameMode(HgfsHandle handle,       // IN: Hgfs file handle
+                        HgfsSessionInfo *session,// IN: Session info
+                        Bool *readPermissions,   // OUT: shared folder permissions
+                        Bool *writePermissions,  // OUT: shared folder permissions
+                        char **fileName,         // OUT: UTF8 file name
+                        size_t *fileNameSize);   // OUT: UTF8 file name size
 Bool
 HgfsHandle2AppendFlag(HgfsHandle handle,        // IN: Hgfs file handle
                       HgfsSessionInfo *session, // IN: session info
@@ -699,7 +763,8 @@ HgfsHandle2ServerLock(HgfsHandle handle,        // IN: Hgfs file handle
 Bool
 HgfsUpdateNodeFileDesc(HgfsHandle handle,        // IN: Hgfs file handle
                        HgfsSessionInfo *session, // IN: session info
-                       fileDesc fd);             // OUT: OS handle (file desc
+                       fileDesc fd,              // IN: OS handle (file desc
+                       void *fileCtx);           // IN: OS file context
 
 Bool
 HgfsUpdateNodeServerLock(fileDesc fd,                // IN: OS handle
@@ -738,7 +803,8 @@ HgfsGetSearchCopy(HgfsHandle handle,        // IN: Hgfs search handle
                   HgfsSearch *copy);        // IN/OUT: Copy of the search
 
 HgfsInternalStatus
-HgfsCloseFile(fileDesc fileDesc);           // IN: OS handle of the file
+HgfsCloseFile(fileDesc fileDesc,            // IN: OS handle of the file
+              void *fileCtx);               // IN: file context
 
 Bool
 HgfsServerGetOpenMode(HgfsFileOpenInfo *openInfo, // IN:  Open info to examine
index 9f8ff106d847ef1b65ce099a07630d34a5ec27d9..8049cf9e45a762a9d567d5826dc8f695eb889257 100644 (file)
@@ -280,6 +280,9 @@ static HgfsInternalStatus HgfsGetattrFromName(char *fileName,
                                               char *shareName,
                                               HgfsFileAttrInfo *attr,
                                               char **targetName);
+static HgfsInternalStatus HgfsAccess(char *fileName,
+                                     char *shareName,
+                                     size_t shareNameLen);
 
 static HgfsInternalStatus HgfsGetattrFromFd(int fd,
                                             HgfsSessionInfo *session,
@@ -394,7 +397,6 @@ HgfsServerSigOplockBreak(int sigNum,       // IN: Signal number
     * We've got all we need from the signal handler, let it continue handling
     * signals of this type.
     */
-
    Sig_Continue(sigNum);
 
    /*
@@ -402,7 +404,6 @@ HgfsServerSigOplockBreak(int sigNum,       // IN: Signal number
     * break is pending will return the new lease we should use. It'll be
     * F_RDLCK if we can downgrade, or F_UNLCK if we should break altogether.
     */
-
    newLease = fcntl(fd, F_GETLEASE);
    if (newLease == F_RDLCK) {
       newServerLock = HGFS_LOCK_SHARED;
@@ -426,7 +427,6 @@ HgfsServerSigOplockBreak(int sigNum,       // IN: Signal number
     * the acknowledgement, and firing the platform-specific acknowledgement
     * function (where we'll downgrade the lease).
     */
-
    lockData = malloc(sizeof *lockData);
    if (lockData) {
       lockData->fileDesc = fd;
@@ -716,7 +716,7 @@ HgfsServerGetOpenMode(HgfsFileOpenInfo *openInfo, // IN:  Open info to examine
  *
  * HgfsCloseFile --
  *
- *    Closes the file descriptor.
+ *    Closes the file descriptor and release the file context.
  *
  * Results:
  *    Zero on success.
@@ -729,14 +729,14 @@ HgfsServerGetOpenMode(HgfsFileOpenInfo *openInfo, // IN:  Open info to examine
  */
 
 HgfsInternalStatus
-HgfsCloseFile(fileDesc fileDesc) // IN: File descriptor
+HgfsCloseFile(fileDesc fileDesc, // IN: File descriptor
+              void *fileCtx)     // IN: File context
 {
    if (close(fileDesc) != 0) {
       int error = errno;
 
       LOG(4, ("%s: Could not close fd %d: %s\n", __FUNCTION__, fileDesc, 
               strerror(error)));
-
       return error;
    }
 
@@ -781,7 +781,6 @@ HgfsCheckFileNode(char const *localName,      // IN
 
       LOG(4, ("%s: couldn't stat local file \"%s\": %s\n", __FUNCTION__,
               localName, strerror(error)));
-
       return error;
    }
 
@@ -839,7 +838,6 @@ HgfsGetFd(HgfsHandle hgfsHandle,    // IN:  HGFS file handle
     * path. Unfortuntely, even the fast path may need to look at the node's
     * append flag.
     */
-
    node.utf8Name = NULL;
    if (!HgfsGetNodeCopy(hgfsHandle, session, TRUE, &node)) {
       /* XXX: Technically, this can also fail if we're out of memory. */
@@ -855,9 +853,8 @@ HgfsGetFd(HgfsHandle hgfsHandle,    // IN:  HGFS file handle
        * in append mode. If not, close the file and reopen it in append
        * mode.
        */
-
       if (append && !(node.flags & HGFS_FILE_NODE_APPEND_FL)) {
-         status = HgfsCloseFile(node.fileDesc);
+         status = HgfsCloseFile(node.fileDesc, node.fileCtx);
          if (status != 0) {
             LOG(4, ("%s: Couldn't close file \"%s\" for reopening\n",
                     __FUNCTION__, node.utf8Name));
@@ -868,7 +865,6 @@ HgfsGetFd(HgfsHandle hgfsHandle,    // IN:  HGFS file handle
           * Update the node in the cache with the new value of the append
           * flag.
           */
-
          if (!HgfsUpdateNodeAppendFlag(hgfsHandle, session, TRUE)) {
             LOG(4, ("%s: Could not update the node in the cache\n",
                     __FUNCTION__));
@@ -886,7 +882,6 @@ HgfsGetFd(HgfsHandle hgfsHandle,    // IN:  HGFS file handle
     * reopening. This means we need to open a file. But first, verify
     * that the file we intend to open isn't stale.
     */
-
    status = HgfsCheckFileNode(node.utf8Name, &node.localId);
    if (status != 0) {
       goto exit;
@@ -896,7 +891,6 @@ HgfsGetFd(HgfsHandle hgfsHandle,    // IN:  HGFS file handle
     * We're not interested in creating a new file. So let's just get the
     * flags for a simple open request. This really should always work.
     */
-
    HgfsServerGetOpenFlags(0, &openFlags);
 
    /*
@@ -905,7 +899,6 @@ HgfsGetFd(HgfsHandle hgfsHandle,    // IN:  HGFS file handle
     *
     * XXX: We should use O_LARGEFILE, see lib/file/fileIOPosix.c --hpreg
     */
-
    newFd = Posix_Open(node.utf8Name,
                node.mode | openFlags | (append ? O_APPEND : 0));
 
@@ -922,8 +915,7 @@ HgfsGetFd(HgfsHandle hgfsHandle,    // IN:  HGFS file handle
     * Update the original node with the new value of the file desc.
     * This call might fail if the node is not used anymore.
     */
-
-   if (!HgfsUpdateNodeFileDesc(hgfsHandle, session, newFd)) {
+   if (!HgfsUpdateNodeFileDesc(hgfsHandle, session, newFd, NULL)) {
       LOG(4, ("%s: Could not update the node -- node is not used.\n",
               __FUNCTION__));
       status = EBADF;
@@ -942,7 +934,6 @@ HgfsGetFd(HgfsHandle hgfsHandle,    // IN:  HGFS file handle
       *fd = newFd;
    }
    free(node.utf8Name);
-
    return status;
 }
 
@@ -1029,6 +1020,57 @@ HgfsValidateOpen(HgfsFileOpenInfo *openInfo, // IN: Open info struct
       openFlags &= ~O_NOFOLLOW;
    }
 
+   /*
+    * Need to validate that open does not change the file for read
+    * only shared folders.
+    */
+   status = 0;
+   if (!openInfo->shareInfo.writePermissions) {
+      if ((openFlags & (O_APPEND | O_CREAT | O_TRUNC)) ||
+          (openMode & (O_WRONLY | O_RDWR))) {
+         status = access(openInfo->utf8Name, F_OK);
+         if (status < 0) {
+            status = errno;
+            if (status == ENOENT && (openFlags & O_CREAT) != 0) {
+               status = EACCES;
+            }
+         } else {
+            /*
+             * Handle the case when the file already exists:
+             * If there is an attempt to createa new file, fail with "EEXIST"
+             * error, otherwise set error to "EACCES".
+             */
+            if ((openFlags & O_CREAT) && (openFlags & O_EXCL)) {
+               status = EEXIST;
+            } else  {
+               status = EACCES;
+            }
+         }
+      }
+      if (status != 0) {
+         goto exit;
+      }
+   }
+
+   if (!openInfo->shareInfo.readPermissions) {
+      /*
+       * "Drop Box" / "FTP incoming" type of shared folders.
+       * Allow creating a new file. Deny opening exisitng file.
+       */
+      status = access(openInfo->utf8Name, F_OK);
+      if (status < 0) {
+         status = errno;
+         if (status != ENOENT || (openFlags & O_CREAT) == 0) {
+            status = EACCES;
+         }
+      } else {
+         status = EACCES;
+      }
+      if (status != 0) {
+         goto exit;
+      }
+   }
+
    /*
     * Determine if hidden attribute needs to be updated.
     * It needs to be updated if a new file is created or an existing file is truncated.
@@ -1041,7 +1083,7 @@ HgfsValidateOpen(HgfsFileOpenInfo *openInfo, // IN: Open info struct
           ((openFlags & O_CREAT) && (openFlags & O_EXCL))) {
          needToSetAttribute = TRUE;
       } else if (openFlags & O_CREAT) {
-         int err = access(openInfo->utf8Name, F_OK);
+         int err = Posix_Access(openInfo->utf8Name, F_OK);
          needToSetAttribute = (err != 0) && (errno == ENOENT);
       }
    }
@@ -1149,7 +1191,6 @@ HgfsAcquireServerLock(fileDesc fileDesc,            // IN: OS handle
     *
     * XXX: Do I need to do fcntl(fileDesc, F_SETOWN, getpid())?
     */
-
    if (fcntl(fileDesc, F_SETSIG, SIGIO)) {
       error = errno;
       Log("%s: Could not set SIGIO as the desired lease break signal for "
@@ -1162,7 +1203,6 @@ HgfsAcquireServerLock(fileDesc fileDesc,            // IN: OS handle
     * If the client just wanted the best lock possible, start off with a write
     * lease and move down to a read lease if that was unavailable.
     */
-
    if ((desiredLock == HGFS_LOCK_OPPORTUNISTIC) ||
        (desiredLock == HGFS_LOCK_EXCLUSIVE)) {
       leaseType = F_WRLCK;
@@ -1179,7 +1219,6 @@ HgfsAcquireServerLock(fileDesc fileDesc,            // IN: OS handle
        * someone else is already writing or reading to the file, try again with
        * a read lease.
        */
-
       if (desiredLock == HGFS_LOCK_OPPORTUNISTIC &&
           (errno == EAGAIN || errno == EACCES)) {
          leaseType = F_RDLCK;
@@ -1203,7 +1242,6 @@ HgfsAcquireServerLock(fileDesc fileDesc,            // IN: OS handle
    /* Got a lease of some kind. */
    LOG(4, ("%s: Got %s lease for fd %d\n", __FUNCTION__,
            leaseType == F_WRLCK ? "write" : "read", fileDesc));
-
    *serverLock = leaseType == F_WRLCK ? HGFS_LOCK_EXCLUSIVE : HGFS_LOCK_SHARED;
    return TRUE;
 #else
@@ -1261,14 +1299,12 @@ HgfsGetattrResolveAlias(char const *fileName,       // IN:  Input filename
     * symlinks to symlinks. If the file is an alias, wasAliased will be set to
     * TRUE and fileRef will reference the target file.
     */
-
    osStatus = FSPathMakeRef(fileName, &fileRef, NULL);
    if (osStatus != noErr) {
       LOG(4, ("%s: could not create file reference: error %d\n",
               __FUNCTION__, (int32)osStatus));
       goto exit;
    }
-
    /*
     * If alias points to an unmounted volume, the volume needs to be explicitly
     * mounted on the host. Mount flag kResolveAliasFileNoUI serves the purpose.
@@ -1282,7 +1318,6 @@ HgfsGetattrResolveAlias(char const *fileName,       // IN:  Input filename
     * (HgfsGetattrFromName) will assume that an error means the file is a
     * regular file.
     */
-
    osStatus = FSResolveAliasFileWithMountFlags(&fileRef, FALSE, &targetIsFolder,
                                                &wasAliased,
                                                kResolveAliasFileNoUI);
@@ -1305,7 +1340,6 @@ HgfsGetattrResolveAlias(char const *fileName,       // IN:  Input filename
        * and convert the CFURL to a basic UTF-8 string using a call to
        * CFURLGetFileSystemRepresentation().
        */
-
       resolvedRef = CFURLCreateFromFSRef(NULL, &fileRef);
       if (resolvedRef == NULL) {
          LOG(4, ("%s: could not create resolved URL reference from "
@@ -1348,7 +1382,6 @@ HgfsGetattrResolveAlias(char const *fileName,       // IN:  Input filename
    if (resolvedRef != NULL) {
       CFRelease(resolvedRef);
    }
-
    return status;
 #endif
 }
@@ -1459,7 +1492,7 @@ HgfsConvertComponentCase(char *currentComponent,           // IN
    ASSERT(convertedComponentSize);
 
    /* Open the specified directory. */
-   dir = opendir(dirPath);
+   dir = Posix_OpenDir(dirPath);
    if (!dir) {
       ret = errno;
       goto exit;
@@ -1508,7 +1541,6 @@ HgfsConvertComponentCase(char *currentComponent,           // IN
           * The current directory entry is a case insensitive match to
           * the specified component. Malloc and copy the current directory entry.
           */
-
          myConvertedComponentSize = dentryNameLen + 1;
          myConvertedComponent = malloc(myConvertedComponentSize);
          if (myConvertedComponent == NULL) {
@@ -1577,7 +1609,6 @@ HgfsConstructConvertedPath(char **path,                 // IN/OUT
    if (!p) {
       int error = errno;
       LOG(4, ("%s: failed to realloc.\n", __FUNCTION__));
-
       return error;
    }
 
@@ -1587,7 +1618,6 @@ HgfsConstructConvertedPath(char **path,                 // IN/OUT
    /* Copy out the converted component to curDir, and free it. */
    Str_Strncat(p, *pathSize, DIRSEPS, sizeof (DIRSEPS));
    Str_Strncat(p, *pathSize, convertedPath, convertedPathLen);
-
    return 0;
 }
 
@@ -1653,7 +1683,6 @@ HgfsCaseInsensitiveLookup(const char *sharePath,           // IN
       } else {
          *convertedFileNameLength = strlen(fileName);
       }
-
       return 0;
    }
 
@@ -1804,10 +1833,9 @@ HgfsServerConvertCase(const char *sharePath,              // IN
     */
 
    if (caseFlags == HGFS_FILE_NAME_CASE_INSENSITIVE &&
-       access(fileName, F_OK) == -1) {
+       Posix_Access(fileName, F_OK) == -1) {
       LOG(4, ("%s: Case insensitive lookup, fileName: %s, flags: %u.\n",
               __FUNCTION__, fileName, caseFlags));
-
       error = HgfsCaseInsensitiveLookup(sharePath, sharePathLength,
                                         fileName, fileNameLength,
                                         convertedFileName,
@@ -1817,8 +1845,13 @@ HgfsServerConvertCase(const char *sharePath,              // IN
        * Success or non-ENOENT error code. HgfsCaseInsensitiveLookup can
        * return ENOENT, and its ok to continue if it is ENOENT.
        */
-
       switch (error) {
+         /*
+          * Both ENOENT and 0 mean that HgfsCaseInsensitiveLookup
+          * successfully built the converted name thus we return
+          * HGFS_NAME_STATUS_COMPLETE in these two cases.
+          */
+         case 0:
          case ENOENT:
             nameStatus = HGFS_NAME_STATUS_COMPLETE;
             break;
@@ -1829,7 +1862,6 @@ HgfsServerConvertCase(const char *sharePath,              // IN
             nameStatus = HGFS_NAME_STATUS_FAILURE;
             break;
       }
-
       return nameStatus;
    }
 
@@ -1840,7 +1872,6 @@ HgfsServerConvertCase(const char *sharePath,              // IN
    } else {
       *convertedFileNameLength = fileNameLength;
    }
-
    return nameStatus;
 }
 
@@ -1891,13 +1922,13 @@ HgfsEffectivePermissions(char *fileName,          // IN: Input filename
                          uint32 *permissions)     // OUT: Effective permissions
 {
    *permissions = 0;
-   if (access(fileName, R_OK) == 0) {
+   if (Posix_Access(fileName, R_OK) == 0) {
       *permissions |= HGFS_PERM_READ;
    }
-   if (access(fileName, X_OK) == 0) {
+   if (Posix_Access(fileName, X_OK) == 0) {
       *permissions |= HGFS_PERM_EXEC;
    }
-   if (!readOnlyShare && (access(fileName, W_OK) == 0)) {
+   if (!readOnlyShare && (Posix_Access(fileName, W_OK) == 0)) {
       *permissions |= HGFS_PERM_WRITE;
    }
    return 0;
@@ -2170,7 +2201,6 @@ HgfsGetattrFromName(char *fileName,                    // IN/OUT:  Input filenam
     * regular files, directories, and symlinks. On Mac OS, we'll additionally
     * treat finder aliases as symlinks.
     */
-
    if (S_ISDIR(stats.st_mode)) {
       attr->type = HGFS_FILE_TYPE_DIRECTORY;
       LOG(4, ("%s: is a directory\n", __FUNCTION__));
@@ -2182,7 +2212,6 @@ HgfsGetattrFromName(char *fileName,                    // IN/OUT:  Input filenam
        * In the case of a symlink, we should populate targetName if the
        * caller asked. Use st_size and readlink() to do so.
        */
-
       if (targetName != NULL) {
 
          myTargetName = Posix_ReadLink(fileName);
@@ -2196,7 +2225,6 @@ HgfsGetattrFromName(char *fileName,                    // IN/OUT:  Input filenam
              * not have read the entire link. If that happens, just return
              * "out of memory".
              */
-
             status = error ? error : ENOMEM;
             goto exit;
          }
@@ -2229,7 +2257,6 @@ HgfsGetattrFromName(char *fileName,                    // IN/OUT:  Input filenam
           * outside the shared folder then treat it the same way as if alias
           * has not been resolved.
           */
-
          HgfsNameStatus nameStatus;
          size_t sharePathLen;
          const char* sharePath;
@@ -2252,7 +2279,6 @@ HgfsGetattrFromName(char *fileName,                    // IN/OUT:  Input filenam
                 * the length of the target name (not including the
                 * nul-terminator), and the permissions should be 777.
                 */
-
                stats.st_size = strlen(myTargetName);
                stats.st_mode |= ACCESSPERMS;
                attr->type = HGFS_FILE_TYPE_SYMLINK;
@@ -2317,6 +2343,49 @@ exit:
 }
 
 
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsAccess --
+ *
+ *    Check is a file with the given name exists and accessible, error code
+ *    otherwise.
+ *    The function does not follow symlinks unless HGFS_SHARE_FOLLOW_SYMLINKS
+ *    flag is specified for the shared folder.
+ *
+ * Results:
+ *    Zero on success.
+ *    Non-zero on failure.
+ *
+ * Side effects:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static HgfsInternalStatus
+HgfsAccess(char *fileName,         // IN: local file path
+           char *shareName,        // IN: Name of the share
+           size_t shareNameLen)    // IN: Length of the share name
+{
+   HgfsFileAttrInfo attr;
+   HgfsShareOptions configOptions;
+   HgfsNameStatus nameStatus;
+   HgfsInternalStatus status;
+
+   /* Get the config options. */
+   nameStatus = HgfsServerPolicy_GetShareOptions(shareName, shareNameLen,
+                                                 &configOptions);
+   if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
+      LOG(4, ("%s: no matching share: %s.\n", __FUNCTION__, shareName));
+      status = ENOENT;
+   } else {
+      status = HgfsGetattrFromName(fileName, configOptions, shareName,
+                                   &attr, NULL);
+   }
+   return status;
+}
+
 /*
  *-----------------------------------------------------------------------------
  *
@@ -2366,7 +2435,6 @@ HgfsGetattrFromFd(int fd,                     // IN:  file descriptor
     * For now, everything that isn't a directory or symlink is a regular
     * file.
     */
-
    if (S_ISDIR(stats.st_mode)) {
       attr->type = HGFS_FILE_TYPE_DIRECTORY;
       LOG(4, ("%s: is a directory\n", __FUNCTION__));
@@ -2414,7 +2482,6 @@ HgfsGetattrFromFd(int fd,                     // IN:  file descriptor
     * In the case we have a Windows client, force the hidden flag.
     * This will be ignored by Linux, Solaris clients.
     */
-
    HgfsGetHiddenAttr(fileName, attr);
 
    if (shareMode == HGFS_OPEN_MODE_READ_ONLY) {
@@ -2422,7 +2489,6 @@ HgfsGetattrFromFd(int fd,                     // IN:  file descriptor
        * Share does not allow write, so tell the client
        * everything is read only.
        */
-
       if (attr->mask & HGFS_ATTR_VALID_OWNER_PERMS) {
          attr->ownerPerms &= ~HGFS_PERM_WRITE;
       }
@@ -2436,7 +2502,6 @@ HgfsGetattrFromFd(int fd,                     // IN:  file descriptor
 
 exit:
    free(fileName);
-
    return status;
 }
 
@@ -2723,7 +2788,6 @@ HgfsSetattrTimes(struct stat *statBuf,       // IN: stat info
        * the guest time, and alwaysUseHostTime will be TRUE if the config
        * option to always use host time is set.
        */
-
       if (attr->mask & HGFS_ATTR_VALID_ACCESS_TIME) {
          if (!alwaysUseHostTime && (hints & HGFS_ATTR_HINT_SET_ACCESS_TIME)) {
             /* Use the guest-provided time */
@@ -2858,7 +2922,6 @@ HgfsSetattrFromFd(HgfsHandle file,          // IN: file descriptor
     * toggle permsChanged since it should not influence our decision of
     * whether to actually call chmod or not.
     */
-
    permsChanged = HgfsSetattrMode(&statBuf, attr, &newPermissions);
    if (permsChanged) {
       LOG(4, ("%s: set mode %o\n", __FUNCTION__, (unsigned)newPermissions));
@@ -2890,7 +2953,6 @@ HgfsSetattrFromFd(HgfsHandle file,          // IN: file descriptor
        * the truncate request. At this point, the server must safeguard itself
        * against deadlock.
        */
-
       if (!HgfsHandle2ServerLock(file, session, &serverLock)) {
          LOG(4, ("%s: File handle is no longer valid.\n", __FUNCTION__));
          status = EBADF;
@@ -2997,10 +3059,15 @@ HgfsSetattrFromName(char *cpName,             // IN: Name
    Bool idChanged = FALSE;
    HgfsServerLock serverLock;
    HgfsShareOptions configOptions;
-
-   nameStatus = HgfsServerGetAccess(cpName, cpNameSize,
-                                    HGFS_OPEN_MODE_WRITE_ONLY, caseFlags,
-                                    &localName, NULL);
+   size_t localNameLen;
+   HgfsShareInfo shareInfo;
+
+   nameStatus = HgfsServerGetShareInfo(cpName,
+                                       cpNameSize,
+                                       caseFlags,
+                                       &shareInfo,
+                                       &localName,
+                                       &localNameLen);
    if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
       LOG(4, ("%s: access check failed\n", __FUNCTION__));
       status = HgfsConvertFromNameStatus(nameStatus);
@@ -3028,7 +3095,6 @@ HgfsSetattrFromName(char *cpName,             // IN: Name
        * XXX: This is racy. But clients interested in preventing a race should
        * have sent us a Setattr packet with a valid HGFS handle.
        */
-
       if (File_IsSymLink(localName)) {
          LOG(4, ("%s: pathname contains a symlink\n", __FUNCTION__));
          status = EINVAL;
@@ -3047,6 +3113,13 @@ HgfsSetattrFromName(char *cpName,             // IN: Name
       goto exit_free;
    }
 
+   if (!HgfsServerPolicy_CheckMode(HGFS_OPEN_MODE_WRITE_ONLY,
+                                   shareInfo.writePermissions,
+                                   shareInfo.readPermissions)) {
+      status = EACCES;
+      goto exit_free;
+   }
+
    /*
     * Try to make each requested attribute change. In the event that
     * one operation fails, we still attempt to perform any other
@@ -3060,7 +3133,6 @@ HgfsSetattrFromName(char *cpName,             // IN: Name
     * toggle permsChanged since it should not influence our decision of
     * whether to actually call chmod or not.
     */
-
    permsChanged = HgfsSetattrMode(&statBuf, attr, &newPermissions);
    if (permsChanged) {
       LOG(4, ("%s: set mode %o\n", __FUNCTION__, (unsigned)newPermissions));
@@ -3074,12 +3146,10 @@ HgfsSetattrFromName(char *cpName,             // IN: Name
    }
 
    idChanged = HgfsSetattrOwnership(attr, &newUid, &newGid);
-
    /*
     * Chown changes the uid and gid together. If one of them should
     * not be changed, we pass in -1.
     */
-
    if (idChanged) {
       if (Posix_Lchown(localName, newUid, newGid) < 0) {
          error = errno;
@@ -3096,7 +3166,6 @@ HgfsSetattrFromName(char *cpName,             // IN: Name
        * the truncate request. At this point, the server must safeguard itself
        * against deadlock.
        */
-
       if (HgfsFileHasServerLock(localName, session, &serverLock, &fd)) {
          LOG(4, ("%s: Client attempted to truncate an oplocked file\n",
                  __FUNCTION__));
@@ -3135,7 +3204,6 @@ HgfsSetattrFromName(char *cpName,             // IN: Name
 
 exit_free:
    free(localName);
-
 exit:
    return status;
 }
@@ -3222,7 +3290,6 @@ HgfsServerScandir(char const *baseDir,      // IN: Directory to search in
           * Allocate the new dent and set it up. We do a straight memcpy of
           * the entire record to avoid dealing with platform-specific fields.
           */
-
          myDents[myNumDents] = malloc(newDent->d_reclen);
          if (myDents[myNumDents] == NULL) {
             status = ENOMEM;
@@ -3257,7 +3324,6 @@ HgfsServerScandir(char const *baseDir,      // IN: Directory to search in
     * On error, free all allocated dents. On success, set the dents pointer
     * given to us by the client.
     */
-
    if (status != 0) {
       size_t i;
       for (i = 0; i < myNumDents; i++) {
@@ -3348,6 +3414,7 @@ HgfsServerOpen(char const *packetIn,     // IN: incoming packet
    char *packetOut;
    size_t packetOutSize;
    HgfsOpenFlags savedOpenFlags = 0;
+   size_t localNameLen;
 
    ASSERT(packetIn);
    ASSERT(session);
@@ -3364,9 +3431,12 @@ HgfsServerOpen(char const *packetIn,     // IN: incoming packet
       goto exit;
    }
 
-   nameStatus = HgfsServerGetAccess(openInfo.cpName, openInfo.cpNameSize,
-                                    openInfo.mode, openInfo.caseFlags,
-                                    &localName, NULL);
+   nameStatus = HgfsServerGetShareInfo(openInfo.cpName,
+                                       openInfo.cpNameSize,
+                                       openInfo.caseFlags,
+                                       &openInfo.shareInfo,
+                                       &localName,
+                                       &localNameLen);
    if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
       LOG(4, ("%s: access check failed\n", __FUNCTION__));
       status = HgfsConvertFromNameStatus(nameStatus);
@@ -3413,7 +3483,6 @@ HgfsServerOpen(char const *packetIn,     // IN: incoming packet
     * since that won't break a shared oplock, but the clients should already
     * realize that the second open can be avoided via sharing handles, too.
     */
-
    if (HgfsFileHasServerLock(localName, session, &serverLock, &newFd)) {
       LOG (4, ("%s: Client tried to open new handle for oplocked file %s.\n",
                __FUNCTION__, localName));
@@ -3562,13 +3631,11 @@ HgfsServerRead(char const *packetIn,     // IN: incoming packet
        * requiredSize is user-provided, so this test must be carefully
        * written to prevent wraparounds.
        */
-
       if (requiredSize > extra) {
          /*
           * The client wants to read more bytes than our payload can handle.
           * Truncate the request
           */
-
          requiredSize = extra;
       }
 
@@ -3587,14 +3654,12 @@ HgfsServerRead(char const *packetIn,     // IN: incoming packet
    if (status != 0) {
       LOG(4, ("%s: Could not get file descriptor\n", __FUNCTION__));
       free(packetOut);
-
       return status;
    }
 
    if (!HgfsHandleIsSequentialOpen(file, session, &sequentialOpen)) {
       LOG(4, ("%s: Could not get sequenial open status\n", __FUNCTION__));
       free(packetOut);
-
       return EBADF;
    }
 
@@ -3610,7 +3675,6 @@ HgfsServerRead(char const *packetIn,     // IN: incoming packet
     * Seek to the offset and read from the file. Grab the IO lock to make
     * this and the subsequent read atomic.
     */
-
    SyncMutex_Lock(&session->fileIOLock);
    if (!sequentialOpen) {
 #   ifdef linux
@@ -3756,14 +3820,12 @@ HgfsServerWrite(char const *packetIn,     // IN: incoming packet
    if (status != 0) {
       LOG(4, ("%s: Could not get file descriptor\n", __FUNCTION__));
       free(packetOut);
-
       return status;
    }
 
    if (!HgfsHandleIsSequentialOpen(file, session, &sequentialOpen)) {
       LOG(4, ("%s: Could not get sequential open status\n", __FUNCTION__));
       free(packetOut);
-
       return EBADF;
    }
 
@@ -3771,13 +3833,11 @@ HgfsServerWrite(char const *packetIn,     // IN: incoming packet
     * requiredSize is user-provided, so this test must be carefully
     * written to prevent wraparounds.
     */
-
    if (requiredSize > extra) {
       /*
        * The driver wants to write more bytes than there is in its payload.
        * Truncate the request
        */
-
       requiredSize = extra;
    }
 
@@ -3878,6 +3938,7 @@ HgfsServerSearchOpen(char const *packetIn,     // IN: incoming packet
    HgfsCaseType caseFlags = HGFS_FILE_NAME_DEFAULT_CASE;
    size_t replySize;
    char *packetOut;
+   HgfsShareInfo shareInfo;
 
    ASSERT(packetIn);
    ASSERT(session);
@@ -3922,17 +3983,19 @@ HgfsServerSearchOpen(char const *packetIn,     // IN: incoming packet
     * request->dirName.length is user-provided, so this test must be carefully
     * written to prevent wraparounds.
     */
-
    if (dirNameLength > extra) {
       /* The input packet is smaller than the request */
       status = EPROTO;
       goto exit;
    }
-   /* It is now safe to read the dirName */
 
-   nameStatus = HgfsServerGetAccess(dirName, dirNameLength,
-                                    HGFS_OPEN_MODE_READ_ONLY,
-                                    caseFlags, &baseDir, &baseDirLen);
+   /* It is now safe to read the file name. */
+   nameStatus = HgfsServerGetShareInfo(dirName,
+                                       dirNameLength,
+                                       caseFlags,
+                                       &shareInfo,
+                                       &baseDir,
+                                       &baseDirLen);
    switch (nameStatus) {
    case HGFS_NAME_STATUS_COMPLETE:
    {
@@ -3967,9 +4030,19 @@ HgfsServerSearchOpen(char const *packetIn,     // IN: incoming packet
       LOG(4, ("%s: dirName: %s.\n", __FUNCTION__, dirName));
       status = HgfsServerSearchRealDir(baseDir,
                                        baseDirLen,
-                                       DIRECTORY_SEARCH_TYPE_DIR,
-                                       dirName, session, &handle);
+                                       dirName,
+                                       shareInfo.rootDir,
+                                       session,
+                                       &handle);
       free(baseDir);
+      /*
+       * If the directory exists but shared folder is write only
+       * then return access denied, otherwise preserve the original
+       * error code.
+       */
+      if (!shareInfo.readPermissions && HGFS_NAME_STATUS_COMPLETE == status) {
+         status = HGFS_NAME_STATUS_ACCESS_DENIED;
+      }
       if (status != 0) {
          LOG(4, ("%s: couldn't scandir\n", __FUNCTION__));
          goto exit;
@@ -4010,7 +4083,6 @@ HgfsServerSearchOpen(char const *packetIn,     // IN: incoming packet
     * Return handle to the search object as the reply to the search
     * open.
     */
-
    *replySearch = handle;
 
    if (!HgfsPackAndSendPacket(packetOut, replySize, 0, header->id,
@@ -4022,7 +4094,6 @@ HgfsServerSearchOpen(char const *packetIn,     // IN: incoming packet
 
 exit:
    free(packetOut);
-
    return status;
 }
 
@@ -4086,7 +4157,6 @@ HgfsServerSearchRead(char const *packetIn,     // IN: incoming packet
                  search.utf8ShareName));
          free(search.utf8Dir);
          free(search.utf8ShareName);
-
          return ENOENT;
       }
    }
@@ -4112,7 +4182,6 @@ HgfsServerSearchRead(char const *packetIn,     // IN: incoming packet
           * Construct the UTF8 version of the full path to the file, and call
           * HgfsGetattrFromName to get the attributes of the file.
           */
-
          fullNameLen = search.utf8DirLen + 1 + length;
          fullName = (char *)malloc(fullNameLen + 1);
          if (!fullName) {
@@ -4121,7 +4190,6 @@ HgfsServerSearchRead(char const *packetIn,     // IN: incoming packet
             free(search.utf8Dir);
             free(search.utf8ShareName);
             free(dent);
-
             return ENOMEM;
          }
          memcpy(fullName, search.utf8Dir, search.utf8DirLen);
@@ -4174,7 +4242,6 @@ HgfsServerSearchRead(char const *packetIn,     // IN: incoming packet
           * share gets resolved into its full path, and gets its attributes
           * via HgfsGetattrFromName.
           */
-
          if (strcmp(dent->d_name, ".") == 0 ||
              strcmp(dent->d_name, "..") == 0) {
             LOG(4, ("%s: assigning %s default attributes\n",
@@ -4192,7 +4259,6 @@ HgfsServerSearchRead(char const *packetIn,     // IN: incoming packet
                free(dent);
                free(search.utf8Dir);
                free(search.utf8ShareName);
-
                return HgfsConvertFromNameStatus(nameStatus);
             }
 
@@ -4202,7 +4268,6 @@ HgfsServerSearchRead(char const *packetIn,     // IN: incoming packet
              * problems on the host, the server still enumerates it and
              * returns to the client.
              */
-
             status = HgfsGetattrFromName(sharePath, configOptions, dent->d_name,
                                         &attr, NULL);
             if (status != 0) {
@@ -4218,7 +4283,6 @@ HgfsServerSearchRead(char const *packetIn,     // IN: incoming packet
          * No conversion needed on OS X because dent->d_name is the shareName
          * that was converted to normal form C in hgfsServerPolicyHost.
          */
-
         entryName = dent->d_name;
         entryNameLen = length;
          break;
@@ -4228,7 +4292,6 @@ HgfsServerSearchRead(char const *packetIn,     // IN: incoming packet
           * The POSIX implementation of HgfsSearchOpen could not have created
           * this kind of search.
           */
-
          NOT_IMPLEMENTED();
          break;
       default:
@@ -4244,7 +4307,6 @@ HgfsServerSearchRead(char const *packetIn,     // IN: incoming packet
       /*
        * We need to unescape the name before sending it back to the client
        */
-
       entryNameLen = HgfsEscape_Undo(entryName, entryNameLen + 1);
 
       /*
@@ -4254,7 +4316,6 @@ HgfsServerSearchRead(char const *packetIn,     // IN: incoming packet
        * one with success. Now we return an error. This may be a non-issue
        * since what filesystems allow dent lengths as high as 6144 bytes?
        */
-
       status = 0;
       if (!HgfsPackSearchReadReply(packetIn, status, entryName, entryNameLen,
                                    &attr, &packetOut, &packetOutSize)) {
@@ -4286,7 +4347,6 @@ HgfsServerSearchRead(char const *packetIn,     // IN: incoming packet
        !HgfsPacketSend(packetOut, packetOutSize, session, 0)) {
       free(packetOut);
    }
-
    return status;
 }
 
@@ -4327,6 +4387,8 @@ HgfsServerGetattr(char const *packetIn,     // IN: incoming packet
    HgfsShareOptions configOptions;
    char *packetOut;
    size_t packetOutSize;
+   size_t localNameLen;
+   HgfsShareInfo shareInfo;
 
    ASSERT(packetIn);
    ASSERT(session);
@@ -4354,10 +4416,12 @@ HgfsServerGetattr(char const *packetIn,     // IN: incoming packet
        * Depending on whether this file/dir is real or virtual, either
        * forge its attributes or look them up in the actual filesystem.
        */
-
-      nameStatus = HgfsServerGetAccess(cpName, cpNameSize,
-                                       HGFS_OPEN_MODE_READ_ONLY,
-                                       caseFlags, &localName, NULL);
+      nameStatus = HgfsServerGetShareInfo(cpName,
+                                          cpNameSize,
+                                          caseFlags,
+                                          &shareInfo,
+                                          &localName,
+                                          &localNameLen);
 
       switch (nameStatus) {
       case HGFS_NAME_STATUS_INCOMPLETE_BASE:
@@ -4387,7 +4451,12 @@ HgfsServerGetattr(char const *packetIn,     // IN: incoming packet
          status = HgfsGetattrFromName(localName, configOptions, cpName, &attr,
                                       &targetName);
          free(localName);
-         if (status != 0) {
+         if (status == 0 &&
+             !HgfsServerPolicy_CheckMode(HGFS_OPEN_MODE_READ_ONLY,
+                                         shareInfo.writePermissions,
+                                         shareInfo.readPermissions)) {
+            status = EACCES;
+         } else if (status != 0) {
             /*
              * If it is a dangling share server should not return ENOENT
              * to the client because it causes confusion: a name that is returned
@@ -4457,6 +4526,8 @@ HgfsServerSetattr(char const *packetIn,     // IN: incoming packet
    ASSERT(packetIn);
    ASSERT(session);
 
+   LOG(4, ("NEW LIB! HgfsServerSetAttr Called!\n"));
+
    if (!HgfsUnpackSetattrRequest(packetIn, packetSize, &attr, &hints,
                                  &cpName, &cpNameSize, &file, &caseFlags)) {
       status = EPROTO;
@@ -4515,6 +4586,8 @@ HgfsServerCreateDir(char const *packetIn,     // IN: incoming packet
    mode_t permissions;
    char *packetOut;
    size_t packetOutSize;
+   size_t localNameLen;
+   HgfsShareInfo shareInfo;
 
    ASSERT(packetIn);
    ASSERT(session);
@@ -4523,9 +4596,12 @@ HgfsServerCreateDir(char const *packetIn,     // IN: incoming packet
       return EPROTO;
    }
 
-   nameStatus = HgfsServerGetAccess(info.cpName, info.cpNameSize,
-                                    HGFS_OPEN_MODE_WRITE_ONLY,
-                                    info.caseFlags, &localName, NULL);
+   nameStatus = HgfsServerGetShareInfo(info.cpName,
+                                       info.cpNameSize,
+                                       info.caseFlags,
+                                       &shareInfo,
+                                       &localName,
+                                       &localNameLen);
    if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
       LOG(4, ("%s: access check failed\n", __FUNCTION__));
 
@@ -4534,6 +4610,25 @@ HgfsServerCreateDir(char const *packetIn,     // IN: incoming packet
 
    ASSERT(localName);
 
+   /*
+    * For read-only shares we must never attempt to create a directory.
+    * However the error code must be different depending on the existence
+    * of the file or directory with the same name.
+    */
+   if (!shareInfo.writePermissions) {
+      int error = HgfsAccess(localName, info.cpName, info.cpNameSize);
+      if (error != 0) {
+         if (error == ENOENT) {
+            error = EACCES;
+         }
+      } else {
+         error = EEXIST;
+      }
+      LOG(4, ("HgfsServerCreateDir: failed access check, error %d\n", error));
+      free(localName);
+      return error;
+   }
+
    /*
     * Create mode_t for use in mkdir(). If owner permissions are missing, use
     * read/write/execute for the owner permissions. If group or other
@@ -4544,7 +4639,6 @@ HgfsServerCreateDir(char const *packetIn,     // IN: incoming packet
     * a directory requires a valid mode, it's highly unlikely that we'll ever
     * be creating a directory without owner permissions.
     */
-
    permissions = ~ALLPERMS;
    permissions |= info.mask & HGFS_CREATE_DIR_VALID_SPECIAL_PERMS ?
                   info.specialPerms << 9 : 0;
@@ -4565,7 +4659,6 @@ HgfsServerCreateDir(char const *packetIn,     // IN: incoming packet
        *  Set hidden attribute when requested.
        *  Do not fail directory creation if setting hidden attribute fails.
        */
-
       HgfsSetHiddenXAttr(localName, TRUE);
    }
 
@@ -4620,6 +4713,8 @@ HgfsServerDeleteFile(char const *packetIn,     // IN: incoming packet
    uint32 caseFlags;
    char *packetOut;
    size_t packetOutSize;
+   size_t localNameLen;
+   HgfsShareInfo shareInfo;
 
    ASSERT(packetIn);
    ASSERT(session);
@@ -4630,18 +4725,21 @@ HgfsServerDeleteFile(char const *packetIn,     // IN: incoming packet
    }
 
    if (hints & HGFS_DELETE_HINT_USE_FILE_DESC) {
-      if (!HgfsHandle2FileName(file, session, &cpName, &cpNameSize)) {
+      if (!HgfsHandle2FileNameMode(file, session, &shareInfo.writePermissions,
+                                   &shareInfo.readPermissions, &cpName, &cpNameSize)) {
          LOG(4, ("%s: could not map cached file handle %u\n", __FUNCTION__,
                  file));
-
          return EBADF;
       }
       localName = cpName;
 
    } else {
-      nameStatus = HgfsServerGetAccess(cpName, cpNameSize,
-                                       HGFS_OPEN_MODE_WRITE_ONLY, caseFlags,
-                                       &localName, NULL);
+      nameStatus = HgfsServerGetShareInfo(cpName,
+                                          cpNameSize,
+                                          caseFlags,
+                                          &shareInfo,
+                                          &localName,
+                                          &localNameLen);
       if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
          LOG(4, ("%s: access check failed\n", __FUNCTION__));
 
@@ -4651,6 +4749,21 @@ HgfsServerDeleteFile(char const *packetIn,     // IN: incoming packet
 
    ASSERT(localName);
 
+   /*
+    * Deleting a file needs both read and write permssions.
+    * However the error code must be different depending on the existence
+    * of the file with the same name.
+    */
+   if (!shareInfo.writePermissions || !shareInfo.readPermissions) {
+      int error = HgfsAccess(localName, cpName, cpNameSize);
+      if (error == 0) {
+         error = EACCES;
+      }
+      LOG(4, ("HgfsServerDeleteFile: failed access check, error %d\n", error));
+      free(localName);
+      return error;
+   }
+
    LOG(4, ("%s: unlinking \"%s\"\n", __FUNCTION__, localName));
    error = Posix_Unlink(localName);
    free(localName);
@@ -4705,6 +4818,8 @@ HgfsServerDeleteDir(char const *packetIn,     // IN: incoming packet
    uint32 caseFlags;
    char *packetOut;
    size_t packetOutSize;
+   size_t localNameLen;
+   HgfsShareInfo shareInfo;
 
    ASSERT(packetIn);
    ASSERT(session);
@@ -4715,18 +4830,21 @@ HgfsServerDeleteDir(char const *packetIn,     // IN: incoming packet
    }
 
    if (hints & HGFS_DELETE_HINT_USE_FILE_DESC) {
-      if (!HgfsHandle2FileName(file, session, &cpName, &cpNameSize)) {
+      if (!HgfsHandle2FileNameMode(file, session, &shareInfo.writePermissions,
+                                   &shareInfo.readPermissions, &cpName, &cpNameSize)) {
          LOG(4, ("%s: could not map cached file handle %u\n", __FUNCTION__,
             file));
-
          return EBADF;
       }
       localName = cpName;
 
    } else {
-      nameStatus = HgfsServerGetAccess(cpName, cpNameSize,
-                                       HGFS_OPEN_MODE_WRITE_ONLY,
-                                       caseFlags, &localName, NULL);
+      nameStatus = HgfsServerGetShareInfo(cpName,
+                                          cpNameSize,
+                                          caseFlags,
+                                          &shareInfo,
+                                          &localName,
+                                          &localNameLen);
       if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
          LOG(4, ("%s: access check failed\n", __FUNCTION__));
 
@@ -4741,6 +4859,21 @@ HgfsServerDeleteDir(char const *packetIn,     // IN: incoming packet
       return EPERM;
    }
 
+   /*
+    * Deleting a directory needs both read and write permssions.
+    * However the error code must be different depending on the existence
+    * of the file with the same name.
+    */
+   if (!shareInfo.writePermissions || !shareInfo.readPermissions) {
+      int error = HgfsAccess(localName, cpName, cpNameSize);
+      if (error == 0) {
+         error = EACCES;
+      }
+      LOG(4, ("HgfsServerDeleteDir: failed access check, error %d\n", error));
+      free(localName);
+      return error;
+   }
+
    ASSERT(localName);
 
    LOG(4, ("%s: removing \"%s\"\n", __FUNCTION__, localName));
@@ -4759,7 +4892,6 @@ HgfsServerDeleteDir(char const *packetIn,     // IN: incoming packet
    if (!HgfsPacketSend(packetOut, packetOutSize, session, 0)) {
       free(packetOut);
    }
-
    return 0;
 }
 
@@ -4791,7 +4923,9 @@ HgfsServerRename(char const *packetIn,     // IN: incoming packet
 {
    HgfsNameStatus nameStatus;
    char *localOldName = NULL;
+   size_t localOldNameLen;
    char *localNewName = NULL;
+   size_t localNewNameLen;
    char *cpOldName;
    uint32 cpOldNameLen;
    char *cpNewName;
@@ -4806,6 +4940,7 @@ HgfsServerRename(char const *packetIn,     // IN: incoming packet
    uint32 newCaseFlags = 0;
    char *packetOut;
    size_t packetOutSize;
+   HgfsShareInfo shareInfo;
 
    ASSERT(packetIn);
    ASSERT(session);
@@ -4819,11 +4954,11 @@ HgfsServerRename(char const *packetIn,     // IN: incoming packet
    if (hints & HGFS_RENAME_HINT_USE_SRCFILE_DESC) {
       size_t localOldNameLen;
 
-      if (!HgfsHandle2FileName(srcFile, session, &localOldName,
-                               &localOldNameLen)) {
+      if (!HgfsHandle2FileNameMode(srcFile, session, &shareInfo.writePermissions,
+                                   &shareInfo.readPermissions, &localOldName,
+                                   &localOldNameLen)) {
          LOG(4, ("%s: could not map cached source file handle %u\n",
                  __FUNCTION__, srcFile));
-
          return EBADF;
       }
 
@@ -4837,12 +4972,13 @@ HgfsServerRename(char const *packetIn,     // IN: incoming packet
 
    } else {
 
-      nameStatus = HgfsServerGetAccess(cpOldName, cpOldNameLen,
-                                       HGFS_OPEN_MODE_READ_WRITE,
-                                       oldCaseFlags, &localOldName, NULL);
+      nameStatus = HgfsServerGetShareInfo(cpOldName,
+                                          cpOldNameLen,
+                                          oldCaseFlags,
+                                          &shareInfo,
+                                          &localOldName,
+                                          &localOldNameLen);
       if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
-         LOG(4, ("%s: old name access check failed\n", __FUNCTION__));
-
          return HgfsConvertFromNameStatus(nameStatus);
       }
 
@@ -4854,16 +4990,30 @@ HgfsServerRename(char const *packetIn,     // IN: incoming packet
          status = EPERM;
          goto exit;
       }
+
+      /*
+       * Renaming a file requires both read and write permissions for the original file.
+       * However the error code must be different depending on the existence
+       * of the file with the same name.
+       */
+      if (!shareInfo.writePermissions || !shareInfo.readPermissions) {
+         status = HgfsAccess(localOldName, cpOldName, cpOldNameLen);
+         if (status == 0) {
+            status = EACCES;
+         }
+         LOG(4, ("HgfsServerRename: failed access check, error %d\n", status));
+         goto exit;
+      }
    }
 
    if (hints & HGFS_RENAME_HINT_USE_TARGETFILE_DESC) {
       size_t localNewNameLen;
 
-      if (!HgfsHandle2FileName(targetFile, session, &localNewName,
-                               &localNewNameLen)) {
+      if (!HgfsHandle2FileNameMode(targetFile, session, &shareInfo.writePermissions,
+                                   &shareInfo.readPermissions, &localNewName,
+                                   &localNewNameLen)) {
          LOG(4, ("%s: could not map cached target file handle %u\n",
                  __FUNCTION__, targetFile));
-
          return EBADF;
       }
 
@@ -4877,9 +5027,12 @@ HgfsServerRename(char const *packetIn,     // IN: incoming packet
 
    } else {
 
-      nameStatus = HgfsServerGetAccess(cpNewName, cpNewNameLen,
-                                       HGFS_OPEN_MODE_WRITE_ONLY,
-                                       newCaseFlags, &localNewName, NULL);
+      nameStatus = HgfsServerGetShareInfo(cpNewName,
+                                          cpNewNameLen,
+                                          newCaseFlags,
+                                          &shareInfo,
+                                          &localNewName,
+                                          &localNewNameLen);
       if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
          LOG(4, ("%s: new name access check failed\n", __FUNCTION__));
          status = HgfsConvertFromNameStatus(nameStatus);
@@ -4917,6 +5070,20 @@ HgfsServerRename(char const *packetIn,     // IN: incoming packet
       }
    }
 
+   /*
+    * Renaming a file requires both read and write permssions for the target file.
+    * However the error code must be different depending on the existence
+    * of the file with the same name.
+    */
+   if (!shareInfo.writePermissions || !shareInfo.readPermissions) {
+      status = HgfsAccess(localNewName, cpNewName, cpNewNameLen);
+      if (status == 0 || status == ENOENT) {
+         status = EACCES;
+      }
+      LOG(4, ("HgfsServerRename: failed access check, error %d\n", status));
+      goto exit;
+   }
+
    LOG(4, ("%s: renaming \"%s\" to \"%s\"\n", __FUNCTION__,
            localOldName, localNewName));
    error = Posix_Rename(localOldName, localNewName);
@@ -4933,7 +5100,6 @@ HgfsServerRename(char const *packetIn,     // IN: incoming packet
     * XXX: Note that this operation can fail (out of memory), but we'd like
     * the client to see success anyway, because the rename succeeded.
     */
-
    status = 0;
    HgfsUpdateNodeNames(localOldName, localNewName, session);
    if (!HgfsPackRenameReply(packetIn, status, &packetOut, &packetOutSize)) {
@@ -5005,6 +5171,7 @@ HgfsServerQueryVolume(char const *packetIn,     // IN: incoming packet
    uint64 *totalBytes;
    char *packetOut;
    size_t packetOutSize;
+   HgfsShareInfo shareInfo;
 
    ASSERT(packetIn);
    ASSERT(session);
@@ -5024,7 +5191,6 @@ HgfsServerQueryVolume(char const *packetIn,     // IN: incoming packet
        * We don't yet support file handle for this operation.
        * Clients should retry using the file name.
        */
-
       if (requestV3->fileName.flags & HGFS_FILE_NAME_USE_FILE_DESC) {
          LOG(4, ("%s: Doesn't support file handle.\n", __FUNCTION__));
          status = EPARAMETERNOTSUPPORTED;
@@ -5066,7 +5232,6 @@ HgfsServerQueryVolume(char const *packetIn,     // IN: incoming packet
     * request->fileName.length is user-provided, so this test must be carefully
     * written to prevent wraparounds.
     */
-
    if (fileNameLength > extra) {
       /* The input packet is smaller than the request. */
       status = EPROTO;
@@ -5074,9 +5239,12 @@ HgfsServerQueryVolume(char const *packetIn,     // IN: incoming packet
    }
 
    /* It is now safe to read the file name field. */
-   nameStatus = HgfsServerGetAccess(fileName, fileNameLength,
-                                    HGFS_OPEN_MODE_READ_WRITE,
-                                    caseFlags, &utf8Name, &utf8NameLen);
+   nameStatus = HgfsServerGetShareInfo(fileName,
+                                       fileNameLength,
+                                       caseFlags,
+                                       &shareInfo,
+                                       &utf8Name,
+                                       &utf8NameLen);
    switch (nameStatus) {
    case HGFS_NAME_STATUS_INCOMPLETE_BASE:
       /*
@@ -5116,7 +5284,6 @@ HgfsServerQueryVolume(char const *packetIn,     // IN: incoming packet
        * Now go through all shares and get share paths on the server.
        * Then retrieve space info for each share's volume.
        */
-
       offset = 0;
       while ((dent = HgfsGetSearchResult(handle, session, offset,
                                          TRUE)) != NULL) {
@@ -5133,7 +5300,6 @@ HgfsServerQueryVolume(char const *packetIn,     // IN: incoming packet
           * need to make sure to handle them properly. In particular, they
           * should be ignored within QueryVolume, as they're not real shares.
           */
-
          if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) {
             LOG(4, ("%s: Skipping fake share %s\n", __FUNCTION__, 
                     dent->d_name));
@@ -5145,7 +5311,6 @@ HgfsServerQueryVolume(char const *packetIn,     // IN: incoming packet
           * The above check ignores '.' and '..' so we do not include them in
           * the share count here.
           */
-
          shares++;
 
          /*
@@ -5185,7 +5350,6 @@ HgfsServerQueryVolume(char const *packetIn,     // IN: incoming packet
           * Pick the drive with amount of space available and return that
           * according to different volume info type.
           */
-
          switch (infoType) {
          case VOLUME_INFO_TYPE_MIN:
             if ((outFreeBytes > freeBytes) || firstShare) {
@@ -5279,6 +5443,8 @@ HgfsServerSymlinkCreate(char const *packetIn,     // IN: incoming packet
    char *packetOut;
    size_t packetOutSize;
    HgfsInternalStatus status = 0;
+   size_t localSymlinkNameLen;
+   HgfsShareInfo shareInfo;
 
    ASSERT(packetIn);
    ASSERT(session);
@@ -5303,7 +5469,6 @@ HgfsServerSymlinkCreate(char const *packetIn,     // IN: incoming packet
        * targetName starts after symlinkName + the variable length array
        * in symlinkName.
        */
-
       targetNameP = (HgfsFileNameV3 *)(symlinkName + 1 + symlinkNameLength);
       targetName = targetNameP->name;
       targetNameLength = targetNameP->length;
@@ -5312,7 +5477,6 @@ HgfsServerSymlinkCreate(char const *packetIn,     // IN: incoming packet
        * We don't yet support file handle for this operation.
        * Clients should retry using the file name.
        */
-
       if (requestV3->symlinkName.flags & HGFS_FILE_NAME_USE_FILE_DESC ||
           targetNameP->flags & HGFS_FILE_NAME_USE_FILE_DESC) {
                 LOG(4, ("%s: Doesn't support file handle.\n", __FUNCTION__));
@@ -5364,17 +5528,33 @@ HgfsServerSymlinkCreate(char const *packetIn,     // IN: incoming packet
            * "targetName" field
            */
 
-          nameStatus = HgfsServerGetAccess(symlinkName, symlinkNameLength,
-                                           HGFS_OPEN_MODE_READ_WRITE,
-                                           caseFlags, &localSymlinkName,
-                                           NULL);
-          if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
+   nameStatus = HgfsServerGetShareInfo(symlinkName,
+                                       symlinkNameLength,
+                                       caseFlags,
+                                       &shareInfo,
+                                       &localSymlinkName,
+                                       &localSymlinkNameLen);
+   if (nameStatus != HGFS_NAME_STATUS_COMPLETE) {
              LOG(4, ("%s: symlink name access check failed\n",
                       __FUNCTION__));
       status = HgfsConvertFromNameStatus(nameStatus);
       goto exit;
    }
 
+   if (!shareInfo.writePermissions ) {
+      int error = HgfsAccess(localSymlinkName, symlinkName, symlinkNameLength);
+      if (error != 0) {
+         if (error == ENOENT) {
+            error = EACCES;
+         }
+      } else {
+         error = EEXIST;
+      }
+      LOG(4, ("HgfsServerCreateDir: failed access check, error %d\n", error));
+      free(localSymlinkName);
+      return error;
+   }
+
    ASSERT(localSymlinkName);
    extra -= symlinkNameLength;
 
@@ -5382,7 +5562,6 @@ HgfsServerSymlinkCreate(char const *packetIn,     // IN: incoming packet
     * targetNameLength is user-provided, so this test must be carefully
     * written to prevent wraparounds.
     */
-
    if (targetNameLength > extra) {
       /* The input packet is smaller than the request */
       free(localSymlinkName);
@@ -5430,12 +5609,10 @@ HgfsServerSymlinkCreate(char const *packetIn,     // IN: incoming packet
                               session, 0)) {
       goto exit;
    }
-
    return status;
 
 exit:
    free(packetOut);
-
    return status;
 }
 
@@ -5509,7 +5686,6 @@ HgfsServerHasSymlink(const char *fileName,        // IN
     *   access to entire host) or
     * - fileName and sharePath are same.
     */
-
    if (fileNameLength == 0 ||
        sharePathLength == 0 ||
        Str_Strcmp(sharePath, fileName) == 0) {
@@ -5518,14 +5694,12 @@ HgfsServerHasSymlink(const char *fileName,      // IN
 
    /* Separate out parent directory of the fileName. */
    File_GetPathName(fileName, &fileDirName, NULL);
-
    /*
     * File_GetPathName may return an empty string to signify the root of
     * the filesystem. To simplify subsequent processing, let's convert such
     * empty strings to "/" when found. See File_GetPathName header comment
     * for details.
     */
-
    if (strlen(fileDirName) == 0) {
       char *p;
       p = realloc(fileDirName, sizeof (DIRSEPS));
@@ -5543,7 +5717,6 @@ HgfsServerHasSymlink(const char *fileName,        // IN
     * Resolve parent directory of fileName.
     * Use realpath(2) to resolve the parent.
     */
-
    resolvedFileDirPath = Posix_RealPath(fileDirName);
    if (resolvedFileDirPath == NULL) {
       /* Let's return some meaningful errors if possible. */
@@ -5575,11 +5748,35 @@ HgfsServerHasSymlink(const char *fileName,      // IN
 exit:
    free(resolvedFileDirPath);
    free(fileDirName);
-
    return nameStatus;
 }
 
 
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsServerWriteWin32Stream --
+ *
+ *    Handle a write request in the WIN32_STREAM_ID format.
+ *
+ * Results:
+ *    EOPNOTSUPP, because this is unimplemented.
+ *
+ * Side effects:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+HgfsInternalStatus
+HgfsServerWriteWin32Stream(char const *packetIn,     // IN: incoming packet
+                           size_t packetSize,        // IN: size of packet
+                           HgfsSessionInfo *session) // IN: session info
+{
+   return EOPNOTSUPP;
+}
+
+
 /*
  *-----------------------------------------------------------------------------
  *
@@ -5645,7 +5842,6 @@ HgfsAckOplockBreak(ServerLockData *lockData, // IN: server lock info
     * lock if our previous call to fcntl() said we could, and if the client
     * wants to downgrade to a shared lock. Otherwise, we break altogether.
     */
-
    if (lockData->serverLock == HGFS_LOCK_SHARED &&
        replyLock == HGFS_LOCK_SHARED) {
       newLock = F_RDLCK;
@@ -5756,7 +5952,6 @@ HgfsGetHiddenXAttr(char const *fileName,   // IN: File name
    } else {
       LOG(4, ("%s: Error %d when getting attributes\n", __FUNCTION__, err));
    }
-
    return err;
 }
 
index bf1e5a2a7497d1f2b094d01397a22751f6c19931..79d74e96c6f594c8c2f94961441eca2d21f1b6b9 100644 (file)
@@ -481,6 +481,51 @@ HgfsServerPolicy_GetSharePath(char const *nameIn,        // IN: Name to check
 }
 
 
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsServerPolicy_ProcessCPName --
+ *
+ *    Get the local path for a share name by looking at the requested
+ *    name, finding the matching share (if any) and returning the share's
+ *    local path local path and permissions.
+ *
+ * Results:
+ *    An HgfsNameStatus value indicating the result is returned.
+ *
+ *    The local path for the shareName is also returned if a match is found.
+ *
+ * Side effects:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+HgfsNameStatus
+HgfsServerPolicy_ProcessCPName(char const *nameIn,         // IN: name in CPName form
+                               size_t nameInLen,           // IN: length of the name
+                               Bool *readAccess,           // OUT: Read permissions
+                               Bool *writeAccess,          // OUT: Write permissions
+                               char const **shareBaseDir)  // OUT: Shared directory
+{
+   HgfsSharedFolder *myShare;
+
+   ASSERT(nameIn);
+   ASSERT(shareBaseDir);
+
+   myShare = HgfsServerPolicyGetShare(&myState, nameIn, nameInLen);
+   if (!myShare) {
+      LOG(4, ("%s: No matching share name\n", __FUNCTION__));
+      return HGFS_NAME_STATUS_DOES_NOT_EXIST;
+   }
+
+   *readAccess = myShare->readAccess;
+   *writeAccess = myShare->writeAccess;
+   *shareBaseDir = myShare->path;
+   return HGFS_NAME_STATUS_COMPLETE;
+}
+
+
 /*
  *-----------------------------------------------------------------------------
  *
@@ -608,3 +653,62 @@ HgfsServerPolicy_GetShareMode(char const *nameIn,        // IN: Share name to re
 
    return HGFS_NAME_STATUS_COMPLETE;
 }
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * HgfsServerPolicy_CheckMode --
+ *
+ *    Checks if the requested mode may be granted depending on read/write permissions.
+ *
+ * Results:
+ *    TRUE if the requested mode can be granted, FALSE otherwise.
+ *
+ * Side effects:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+HgfsServerPolicy_CheckMode(HgfsOpenMode mode,          // IN: mode to check
+                           Bool writePermissions,      // IN: callers write permissions
+                           Bool readPermissions)       // IN: callers read permissions
+{
+   /*
+    * See if access is allowed in the requested mode.
+    *
+    * XXX Yeah, this is retarded. We should be using bits instead of
+    * an enum for HgfsOpenMode. Add it to the todo list. [bac]
+    */
+   switch (HGFS_OPEN_MODE_ACCMODE(mode)) {
+   case HGFS_OPEN_MODE_READ_ONLY:
+      if (!readPermissions) {
+         LOG(4, ("HgfsServerPolicyCheckMode: Read access denied\n"));
+         return FALSE;
+      }
+      break;
+
+   case HGFS_OPEN_MODE_WRITE_ONLY:
+      if (!writePermissions) {
+         LOG(4, ("HgfsServerPolicyCheckMode: Write access denied\n"));
+         return FALSE;
+      }
+      break;
+
+   case HGFS_OPEN_MODE_READ_WRITE:
+      if (!readPermissions || !writePermissions) {
+         LOG(4, ("HgfsServerPolicyCheckMode: Read/write access denied\n"));
+         return FALSE;
+      }
+      break;
+
+   default:
+      LOG(0, ("HgfsServerPolicyCheckMode: Invalid mode\n"));
+      ASSERT(FALSE);
+      return FALSE;
+   }
+
+   return TRUE;
+}
index 9a67e824b1843f1c2780e581650825ee09f0b546..60dae4c4a9d399be78e9f69add89592eafd56ec1 100644 (file)
@@ -282,31 +282,6 @@ ImageUtilDataWriteCallback(png_structp png_ptr,         // IN
  *
  * ImageUtil_ConstructPNGBuffer --
  *
- *      Writes a PNG of the image to the DynBuf passed in.
- *
- * Results:
- *      TRUE if successful, FALSE otherwise.
- *
- * Side effects:
- *      If successful, imageData should be destroyed.
- *
- *----------------------------------------------------------------------------
- */
-
-Bool
-ImageUtil_ConstructPNGBuffer(const ImageInfo *image, // IN
-                             DynBuf *imageData)      // OUT
-
-{
-   return ImageUtil_ConstructPNGBufferEx(image, NULL, imageData);
-}
-
-
-/*
- *----------------------------------------------------------------------------
- *
- * ImageUtil_ConstructPNGBufferEx --
- *
  *      Writes a PNG of the image to the DynBuf passed in. Accepts a zlib
  *      compression level (0-9, 0 means no compression, -1 means "use the
  *      default").
@@ -321,9 +296,9 @@ ImageUtil_ConstructPNGBuffer(const ImageInfo *image, // IN
  */
 
 Bool
-ImageUtil_ConstructPNGBufferEx(const ImageInfo *image,               // IN
-                               const ImagePngWriteOptions *pOptions, // IN/OPT
-                               DynBuf *imageData)                    // OUT
+ImageUtil_ConstructPNGBuffer(const ImageInfo *image,               // IN
+                             const ImagePngWriteOptions *pOptions, // IN/OPT
+                             DynBuf *imageData)                    // OUT
 {
    png_structp png_ptr;
    png_infop info_ptr;
index 0595eae1e5df760ee5b97bca457e55928c49ff9d..12e7a4103849c506d737292bfc820f13e2b893fe 100644 (file)
@@ -105,9 +105,8 @@ AppUtil_GetIconIndexAndLocationForShortcut(const TCHAR *shortcut,
 };
 #endif // __cplusplus
 
-#endif //_WIN32
+#else // not _WIN32
 
-#if defined(linux)
 #include <glib.h>
 
 void AppUtil_Init(void);
index 8500c6adfa2af9b90be0744ddc9a471702f65127..a14e56b16062a0bc35575b6621fbe4c0e4b653db 100644 (file)
@@ -1,12 +1,12 @@
 #define BUILD_NUMBER \
-       "build-179896"
+       "build-187411"
 #define BUILD_NUMBER_NUMERIC \
-       179896
+       187411
 #define BUILD_NUMBER_NUMERIC_STRING \
-       "179896"
+       "187411"
 #define PRODUCT_BUILD_NUMBER \
-       "product-build-620"
+       "product-build-653"
 #define PRODUCT_BUILD_NUMBER_NUMERIC \
-       620
+       653
 #define PRODUCT_BUILD_NUMBER_NUMERIC_STRING \
-       "620"
+       "653"
diff --git a/open-vm-tools/lib/include/community_source.h b/open-vm-tools/lib/include/community_source.h
new file mode 100644 (file)
index 0000000..4923270
--- /dev/null
@@ -0,0 +1,74 @@
+/*********************************************************
+ * Copyright (C) 2009 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.
+ *
+ *********************************************************/
+
+/*********************************************************
+ * 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.
+ *
+ *********************************************************/
+
+/*
+ * community_source.h --
+ *
+ *    Macros for excluding source code from community.
+ */
+
+#ifndef _COMMUNITY_SOURCE_H_
+#define _COMMUNITY_SOURCE_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"
+
+/* 
+ * 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
+
+#endif
index 5b89098ca7c252ad8d13d14de8c148b12d92b5af..35b01b3e28004980ed776dcdad8f08e4aa76f8e4 100644 (file)
@@ -297,8 +297,6 @@ EXTERN Bool File_MakeCfgFileExecutable(ConstUnicode pathName);
 
 EXTERN char *File_ExpandAndCheckDir(const char *dirName);
 
-EXTERN Bool File_SupportsPrealloc(const char *file);
-
 #ifdef __cplusplus
 } // extern "C" {
 #endif
index 4998d886c21db376510680de025a61c0552e4e49..d23272734c961f976938bc7bbfd32eb4f705194e 100644 (file)
@@ -417,4 +417,6 @@ EXTERN Bool FileIO_SetExcludedFromTimeMachine(char const *pathName,
                                               Bool isExcluded);
 #endif
 
+Bool FileIO_SupportsPrealloc(const char *pathName, Bool fsCheck);
+
 #endif // _FILEIO_H_
index 608624c0fe05d9deb85b355b43adb71761d5e391..7a90b45d6b8f76d4f89da4299b15a1b153ed4c86 100644 (file)
@@ -66,6 +66,7 @@ typedef enum {
    GHI_CAP_TRAY_ICONS                   = 19, // supports ghi.guest.trayIcon commands
    GHI_CAP_SET_FOCUSED_WINDOW           = 20, // supports ghi.guest.setFocusedWindow
    GHI_CAP_GET_EXEC_INFO_HASH           = 21, // supports ghi.guest.getExecInfoHash
+   UNITY_CAP_STICKY_WINDOWS             = 22, // supports unity.window.{un,}stick
 } GuestCapabilities;
 
 typedef struct {
@@ -129,6 +130,7 @@ static GuestCapElem guestCapTable[] = {
    { GHI_CAP_TRAY_ICONS,                   GHI_CAP_VMDB_PATH,   "trayIcons" },
    { GHI_CAP_SET_FOCUSED_WINDOW,           GHI_CAP_VMDB_PATH,   "setFocusedWindow"},
    { GHI_CAP_GET_EXEC_INFO_HASH,           GHI_CAP_VMDB_PATH,   "getExecInfoHash"},
+   { UNITY_CAP_STICKY_WINDOWS,             UNITY_CAP_VMDB_PATH, "sticky"},
 };
 
 #endif // VM_NEED_VMDB_GUEST_CAP_MAPPING
index 669ad07d280f12e90020c6561c25a139c7074c2c..c76938fb56e3766069cb99c630df521d6ec89a5d 100644 (file)
@@ -110,11 +110,14 @@ typedef struct _DiskInfo {
 
 /*
  * Global functions
+ *
+ * XXX These belong in a bora-vmsoft header.
  */
 
 #ifndef N_PLAT_NLM
 extern Bool GuestInfo_GetFqdn(int outBufLen, char fqdn[]);
-extern Bool GuestInfo_GetNicInfo(GuestNicList *nicInfo);
+extern Bool GuestInfo_GetNicInfo(NicInfoV3 **nicInfo);
+extern void GuestInfo_FreeNicInfo(NicInfoV3 *nicInfo);
 extern Bool GuestInfo_GetDiskInfo(PGuestDiskInfo di);
 extern Bool GuestInfo_GetOSName(unsigned int outBufFullLen,
                                 unsigned int outBufLen, char *osNameFull,
diff --git a/open-vm-tools/lib/include/hgfsHelper.h b/open-vm-tools/lib/include/hgfsHelper.h
new file mode 100644 (file)
index 0000000..999a938
--- /dev/null
@@ -0,0 +1,38 @@
+/*********************************************************
+ * Copyright (C) 2009 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.
+ *
+ *********************************************************/
+
+/*
+ * hgfsClient.h
+ *
+ *    Provides a helper library for guest applications to access
+ *    the HGFS file system.
+ */
+
+#ifndef _HGFS_HELPER_H_
+#define _HGFS_HELPER_H_
+
+#include "vm_basic_types.h"
+#include "unicode.h"
+
+Bool HgfsHlpr_QuerySharesDefaultRootPath(Unicode *hgfsRootPath);
+void HgfsHlpr_FreeSharesRootPath(Unicode hgfsRootPath);
+#if defined(_WIN32)
+Bool HgfsHlpr_ReadRegistryDefaultRootPath(Unicode *hgfsRootPath);
+#endif // _WIN32
+
+#endif
index 3651448e9fd2e3442b737483c74334c0fe04fa61..09e82030eb335deb3e9ec1af61abbe6cd9395053 100644 (file)
@@ -117,6 +117,34 @@ typedef enum {
    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_WRITE_WIN32_STREAM_V3, /* Write WIN32_STREAM_ID format data to file */
+
+   /*
+    * Operations for version 4, deprecating version 3 operations.
+    */
+
+   HGFS_OP_CREATE_SESSION_V4,     /* Create a session and return host capabilities. */
+   HGFS_OP_DESTROY_SESSION_V4,    /* Destroy/close session. */
+   HGFS_OP_OPEN_V4,               /* Open file */
+   HGFS_OP_DIRECTORY_READ_V4,     /* Read directory entries. */
+   HGFS_OP_ENUMERATE_STREAMS_V4,  /* Enumerate alternative named streams for a file. */
+   HGFS_OP_GETATTR_V4,            /* Get file attributes */
+   HGFS_OP_SETATTR_V4,            /* Set file attributes */
+   HGFS_OP_DELETE_V4,             /* Delete a file or a directory */
+   HGFS_OP_LINKMOVE_V4,           /* Rename/move/create hard link. */
+   HGFS_OP_FSCTL_V4,              /* Sending FS control requests. */
+   HGFS_OP_ACCESS_CHECK_V4,       /* Flush all cached data to the disk. */
+   HGFS_OP_FSYNC_V4,              /* Access check. */
+   HGFS_OP_QUERY_VOLUME_INFO_V4,  /* Query volume information. */
+   HGFS_OP_OPLOCK_ACQUIRE_V4,     /* Acquire OPLOCK. */
+   HGFS_OP_OPLOCK_BREAK_V4,       /* Break or downgrade OPLOCK. */
+   HGFS_OP_LOCK_BYTE_RANGE_V4,    /* Acquire byte range lock. */
+   HGFS_OP_UNLOCK_BYTE_RANGE_V4,  /* Release byte range lock. */
+   HGFS_OP_QUERY_EAS_V4,          /* Query extended attributes. */
+   HGFS_OP_SET_EAS_V4,            /* Add or modify extended attributes. */
+   HGFS_OP_SET_WATCH_V4,          /* Start monitoring directory changes. */
+   HGFS_OP_REMOVE_WATCH_V4,       /* Stop monitoring directory changes. */
+   HGFS_OP_NOTIFY_V4,             /* Notification for a directory change event. */
 
    HGFS_OP_MAX,                   /* Dummy op, must be last in enum */
 } HgfsOp;
@@ -405,6 +433,13 @@ typedef uint64 HgfsAttrFlags;
 #define HGFS_ATTR_HIDDEN_FORCED (1 << 3)
 #define HGFS_ATTR_REPARSE_POINT (1 << 4)
 
+/* V4 additional definitions for hgfsAttrFlags. */
+#define HGFS_ATTR_COMPRESSED            (1 << 5)
+#define HGFS_ATTR_ENCRYPTED             (1 << 6)
+#define HGFS_ATTR_OFFLINE               (1 << 7)
+#define HGFS_ATTR_READONLY              (1 << 8)
+#define HGFS_ATTR_SPARSE                (1 << 9)
+#define HGFS_ATTR_TEMPORARY             (1 << 10)
 
 /*
  * Specifies which open request fields contain
@@ -427,6 +462,10 @@ typedef uint64 HgfsOpenValid;
 #define HGFS_OPEN_VALID_SERVER_LOCK       (1 << 10)
 #define HGFS_OPEN_VALID_FILE_NAME         (1 << 11)
 
+/* V4 additional open mask flags. */
+#define HGFS_OPEN_VALID_EA                      (1 << 12)
+#define HGFS_OPEN_VALID_ACL                     (1 << 13)
+#define HGFS_OPEN_VALID_STREAM_NAME             (1 << 14)
 
 /*
  * Specifies which attribute fields contain
@@ -883,6 +922,39 @@ struct HgfsReplyWriteV3 {
 #include "vmware_pack_end.h"
 HgfsReplyWriteV3;
 
+/* Stream write flags */
+typedef enum {
+   HGFS_WIN32_STREAM_IGNORE_SECURITY = (1<<0),
+} HgfsWin32StreamFlags;
+
+/*
+ * HgfsRequestWriteWin32Stream.
+ * Server must support HGFS_LARGE_PACKET_MAX to implement this op.
+ */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestWriteWin32StreamV3 {
+   HgfsHandle file;      /* Opaque file ID used by the server */
+   HgfsWin32StreamFlags flags;
+   uint32 reserved1;
+   uint32 requiredSize;
+   uint64 reserved2;     /* Reserved for future use */
+   char payload[1];
+}
+#include "vmware_pack_end.h"
+HgfsRequestWriteWin32StreamV3;
+
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyWriteWin32StreamV3 {
+   uint32 actualSize;
+   uint64 reserved;      /* Reserved for future use */
+}
+#include "vmware_pack_end.h"
+HgfsReplyWriteWin32StreamV3;
+
 
 /* Deprecated */
 
@@ -1606,5 +1678,960 @@ struct HgfsReplySymlinkCreateV3 {
 #include "vmware_pack_end.h"
 HgfsReplySymlinkCreateV3;
 
+/* HGFS protocol version 4 definitions. */
+
+/*
+ * HGFS_PACKET_FLAG_NOTIFICATION set in flags field means that
+ * this is a notification or a callback request (not a reply to client request).
+ */
+
+#define HGFS_PACKET_FLAG_NOTIFICATION         (1 << 0)
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsHeader {
+   uint8 version;       /* Header version. */
+   uint8 reserved1[3];  /* Reserved for future use. */
+   uint8 dummy;         /* Needed to distinguish between older and newer header. */
+   uint8 reserved2[3];  /* Reserved for future use. */
+   uint32 packetSize;   /* Size of the packet, including the header size. */
+   uint32 headerSize;   /* Size of the Hgfs header. */
+   uint32 requestId;    /* Request ID. */
+   uint32 op;           /* Operation. */
+   uint32 status;       /* Return value. */
+   uint32 flags;        /* Flags. */
+   uint32 information;  /* Generic field, used e.g. for native error code. */
+   uint64 sessionId;    /* Session ID. */
+   uint64 reserved;     /* Reserved for future use. */
+}
+#include "vmware_pack_end.h"
+HgfsHeader;
+
+/*
+ * Flag HGFS_REQUEST_SUPPORTED is set for every requests that are supported by the host.
+ */
+#define HGFS_REQUEST_SUPPORTED                  (1 << 0)
+
+/*
+ * Following flags define which optional parameters for file open
+ * requests are supported by the host.
+ * HGFS_OPENV4_SUPPORTS_EA - host is capable of setting EA when creating
+ *                           a new file.
+ * HGFS_OPENV4_SUPPORTS_ACL - host is capable of setting ACLs when creating
+ *                           a new file.
+ * HGFS_OPENV4_SUPPORTS_NAMED_STREAMS - opening/enumerating named streams
+ *                                      is supported.
+ * HGFS_OPENV4_SUPPORTS_SHARED_ACCESS - host supports file sharing restrictions.
+ * HGFS_OPENV4_SUPPORTS_UNIX_PERMISSIONS - host stores POSIX permissions with
+ *                                         file.
+ * HGFS_OPENV4_POSIX_FILE_DELETION - host supports POSIX file deletion semantics.
+ */
+typedef uint32 HgfsOpenV4Capabilities;
+#define HGFS_OPENV4_SUPPORTS_EA                 (1 << 1)
+#define HGFS_OPENV4_SUPPORTS_ACL                (1 << 2)
+#define HGFS_OPENV4_SUPPORTS_NAMED_STREAMS      (1 << 3)
+#define HGFS_OPENV4_SUPPORTS_SHARED_ACCESS      (1 << 4)
+#define HGFS_OPENV4_SUPPORTS_UNIX_PERMISSIONS   (1 << 5)
+#define HGFS_OPENV4_POSIX_FILE_DELETION         (1 << 6)
+
+/*
+ *  There is a significant difference in byte range locking semantics between Windows
+ *  and POSIX file systems. Windows implements mandatory locking which means that every
+ *  read or write request that conflicts with byte range locks is rejected. POSIX has
+ *  an advisory locking which means that locks are validated only when another lock is
+ *  requested and are not enforced for read/write operations.
+ *  Applications in guest OS may expect byte range locking semantics that matches guest
+ *  OS which may be different from semantics that is natively supported by host OS. In
+ *  this case either HGFS server or HGFS client should provide compensation for the host
+ *  OS semantics to maintain application compatibility.
+ *  Client must know if the server is capable to provide appropriate byte range locking
+ *  semantics to perform some compensation on behalf of server when necessary.
+ *
+ *  Following flags define various capabilities of byte range lock implementation on
+ *  the host.
+ *
+ *  HGFS_BYTE_RANGE_LOCKS_SUPPORTS_64 means that server is capable of locking 64 bit
+ *                                    length ranges.
+ *  HGFS_BYTE_RANGE_LOCKS_SUPPORTS_32 means that server is limited to 32-bit ranges.
+ *  HGFS_BYTE_RANGE_LOCKS_SUPPORTS_MANDATORY means that server is capable of enforcing
+ *                                           read/write restrictions for locked ranges.
+ *  HGFS_BYTE_RANGE_LOCKS_SUPPORTS_ADVISORY means that server supports advisory locking;
+ *                                          locks are validated only for other bytes
+ *                                          range locking and are not enforced
+ *                                          for read/write operations.
+ */
+typedef uint32 HgfsByteRangeLockingCapabilities;
+#define HGFS_BYTE_RANGE_LOCKS_SUPPORTS_64               (1 << 1)
+#define HGFS_BYTE_RANGE_LOCKS_SUPPORTS_32               (1 << 2)
+#define HGFS_BYTE_RANGE_LOCKS_SUPPORTS_MANDATORY        (1 << 3)
+#define HGFS_BYTE_RANGE_LOCKS_SUPPORTS_ADVISORY         (1 << 4)
+
+/* HGFS_SUPPORTS_HARD_LINKS is set when the host supports hard links. */
+typedef uint32 HgfsLinkMoveCapabilities;
+#define HGFS_SUPPORTS_HARD_LINKS                        (1 << 1)
+
+ /*
+  * HGFS_SET_WATCH_SUPPORTS_FINE_GRAIN_EVENTS is set when host supports
+  * fine grain event reporting for directory notification.
+  */
+typedef uint32 HgfsSetWatchCapabilities;
+#define HGFS_SET_WATCH_SUPPORTS_FINE_GRAIN_EVENTS       (1 << 1)
+
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsCapability {
+   HgfsOp op;            /* Op. */
+   uint32 flags;         /* Flags. */
+}
+#include "vmware_pack_end.h"
+HgfsCapability;
+
+typedef HgfsFileName HgfsUserName;
+typedef HgfsFileName HgfsGroupName;
+
+/* Following structures describe user identity on the host which runs HGFS service. */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsIdentity {
+   uint32 uid;                        /* user id. */
+   uint32 gid;                        /* Primary group id. */
+   HgfsUserName user;                 /* User name in form specified in RFC 3530. */
+   HgfsGroupName group;               /* Group name in form specified in RFC 3530. */
+}
+#include "vmware_pack_end.h"
+HgfsIdentity;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestCreateSession {
+   uint32 numCapabilities;            /* Number of capabilities to follow. */
+   uint32 maxPacketSize;              /* Maximum packet size supported. */
+   uint64 reserved;                   /* Reserved for future use. */
+   HgfsCapability capabilities[1];    /* Array of HgfsCapabilities. */
+}
+#include "vmware_pack_end.h"
+HgfsRequestCreateSession;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyCreateSession {
+   uint64 sessionId;                  /* Session ID. */
+   uint32 numCapabilities;            /* Number of capabilities to follow. */
+   uint32 maxPacketSize;              /* Maximum packet size supported. */
+   uint32 identityOffset;             /* Offset to HgfsIdentity or 0 if no identity. */
+   uint64 reserved;                   /* Reserved for future use. */
+   HgfsCapability capabilities[1];    /* Array of HgfsCapabilities. */
+}
+#include "vmware_pack_end.h"
+HgfsReplyCreateSession;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestDestroySession {
+   uint64 sessionId;   /* Session ID. */
+   uint64 reserved;    /* Reserved for future use. */
+}
+#include "vmware_pack_end.h"
+HgfsRequestDestroySession;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyDestroySession {
+   uint64 reserved;    /* Reserved for future use. */
+}
+#include "vmware_pack_end.h"
+HgfsReplyDestroySession;
+
+/* Adds new error status: HGFS_STATUS_INVALID_SESSION. */
+
+/*
+ * If file handle is used to set watch (HGFS_FILE_NAME_USE_FILE_DESC
+ * is set in the fileName), closing this handle implicitly removes the watch.
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestSetWatch {
+    uint64 events;             /* What events to watch? */
+    uint32 flags;              /* Flags. */
+    uint64 reserved;           /* Reserved for future use. */
+    HgfsFileNameV3 fileName;   /* Filename to watch. */
+}
+#include "vmware_pack_end.h"
+HgfsRequestSetWatch;
+
+/*
+ *  Coarse grain notification event types.
+ */
+#define HGFS_ACTION_ADDED        (1 << 0)   /* File was added. */
+#define HGFS_ACTION_REMOVED      (1 << 1)   /* File was removed. */
+#define HGFS_ACTION_MODIFIED     (1 << 2)   /* File attributes were changed. */
+#define HGFS_ACTION_RENAMED      (1 << 3)   /* File was renamed. */
+
+/*
+ * Fine grain notification event types.
+ * HgfsRequestSetWatch events.
+ * Events marked with (*) apply only to directories.
+ */
+#define HGFS_NOTIFY_ACCESS        (1 << 0)    /* File accessed (read) */
+#define HGFS_NOTIFY_ATTRIB        (1 << 1)    /* Windows file attributes changed. */
+#define HGFS_NOTIFY_SIZE          (1 << 2)    /* File size changed. */
+#define HGFS_NOTIFY_ATIME         (1 << 3)    /* Access time changed. */
+#define HGFS_NOTIFY_MTIME         (1 << 4)    /* Modification time changed. */
+#define HGFS_NOTIFY_CTIME         (1 << 5)    /* Attribute change time changed. */
+#define HGFS_NOTIFY_CRTIME        (1 << 6)    /* Creation time changed. */
+#define HGFS_NOTIFY_NAME          (1 << 7)    /* File / Directory name changed. */
+#define HGFS_NOTIFY_OPEN          (1 << 8)    /* File opened */
+#define HGFS_NOTIFY_CLOSE_WRITE   (1 << 9)    /* File opened for writing closed */
+#define HGFS_NOTIFY_CLOSE_NOWRITE (1 << 10)   /* File opened for reading closed */
+#define HGFS_NOTIFY_CREATE        (1 << 11)   /* File / directory created */
+#define HGFS_NOTIFY_DELETE        (1 << 12)   /* (*) File / directory deleted */
+#define HGFS_NOTIFY_DELETE_SELF   (1 << 13)   /* Watched file / directory deleted */
+#define HGFS_NOTIFY_MODIFY        (1 << 14)   /* File or directory modified. */
+#define HGFS_NOTIFY_MOVE_SELF     (1 << 15)   /* Watched file / directory moved. */
+#define HGFS_NOTIFY_MOVE_FROM     (1 << 16)   /* (*) Moved out of watched directory. */
+#define HGFS_NOTIFY_MOVE_TO       (1 << 17)   /* (*) Moved into watched directory. */
+#define HGFS_NOTIFY_RENAME        (1 << 18)   /* File / directory name changed. */
+
+/* HgfsRequestSetWatch flags. */
+#define HGFS_NOTIFY_FLAG_WATCH_TREE  (1 << 0)    /* Watch the entire directory tree. */
+#define HGFS_NOTIFY_FLAG_DONT_FOLLOW (1 << 1)    /* Don't follow symlinks. */
+#define HGFS_NOTIFY_FLAG_ONE_SHOT    (1 << 2)    /* Generate only one notification. */
+#define HGFS_NOTIFY_FLAG_POSIX_HINT  (1 << 3)    /* Client is POSIX and thus expects
+                                                  * fine grain notification. Server
+                                                  * may provide coarse grain
+                                                  * notification even if this flag is
+                                                  * set.
+                                                  */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplySetWatch {
+    HgfsHandle watchId;    /* Watch identifier for subsequent references. */
+    uint64 reserved;       /* Reserved for future use. */
+}
+#include "vmware_pack_end.h"
+HgfsReplySetWatch;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestRemoveWatch {
+    HgfsHandle watchId;    /* Watch identifier to remove. */
+}
+#include "vmware_pack_end.h"
+HgfsRequestRemoveWatch;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyRemoveWatch {
+    uint64 reserved;       /* Reserved for future use. */
+}
+#include "vmware_pack_end.h"
+HgfsReplyRemoveWatch;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsNotifyEvent {
+   uint32 nextOffset;        /* Offset of next event; 0 if it i sthe last one. */
+   uint64 mask;              /* Event occurred. */
+   uint64 reserved;          /* Reserved for future use. */
+   HgfsFileName fileName;    /* Filename. */
+   HgfsFileName oldName;     /* New filename for rename operation. */
+}
+#include "vmware_pack_end.h"
+HgfsNotifyEvent;
+
+/* Too many events, some or all event were dropped by the server. */
+#define HGFS_NOTIFY_FLAG_OVERFLOW          (1 << 0)
+/* Watch had been removed either explicitly or implicitly. */
+#define HGFS_NOTIFY_FLAG_REMOVED           (1 << 1)
+/* Server generated coasrse grain events. */
+#define HGFS_NOTIFY_FLAG_COARSE_GRAIN      (1 << 2)
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestNotify {
+   HgfsHandle watchId;         /* Watch identifier. */
+   uint32 flags;               /* Various flags. */
+   uint32 count;               /* Number of events occured. */
+   uint64 reserved;            /* Reserved for future use. */
+   HgfsNotifyEvent events[1];  /* Events. HgfsNotifyEvent(s). */
+}
+#include "vmware_pack_end.h"
+HgfsRequestNotify;
+
+// Query EA flags values.
+#define HGFS_QUERY_EA_INDEX_SPECIFIED (1 << 0)
+#define HGFS_QUERY_EA_SINGLE_ENTRY    (1 << 1)
+#define HGFS_QUERY_EA_RESTART_SCAN    (1 << 2)
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestQueryEA {
+   uint32 flags;                 /* EA flags. */
+   uint32 index;
+   uint64 reserved;              /* Reserved for future use. */
+   uint32 eaNameLength;          /* EA name length. */
+   uint32 eaNameOffset;          /* Offset of the eaName field. */
+   HgfsFileNameV3 fileName;      /* File to watch. */
+   char eaNames[1];              /* List of NULL terminated EA names.
+                                  * Actual location of the data depends on
+                                  * fileName length and defined by eaNameOffset.
+                                  */
+}
+#include "vmware_pack_end.h"
+HgfsRequestQueryEA;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyQueryEA {
+   uint32 nextOffset;            /* Offset of the next structure when more then
+                                  * one record is returned.
+                                  */
+   uint32 flags;                 /* EA flags. */
+   uint32 index;                 /* Index needed to resume scan. */
+   uint64 reserved;              /* Reserved for future use. */
+   uint32 eaDataLength;          /* EA value length. */
+   char eaData[1];               /* NULL termianed EA name followed by EA value. */
+}
+#include "vmware_pack_end.h"
+HgfsReplyQueryEA;
+
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsEA {
+   uint32 nextOffset;      /* Offset of the next structure in the chain. */
+   uint32 valueLength;     /* EA value length. */
+   char data[1];           /* NULL terminated EA name followed by EA value. */
+}
+#include "vmware_pack_end.h"
+HgfsEA;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestSetEA {
+   uint32 flags;           /* Flags, see below. */
+   uint64 reserved;        /* Reserved for future use. */
+   uint32 numEAs;          /* Number of EAs in this request. */
+   HgfsEA attributes[1];   /* Array of attributes. */
+}
+#include "vmware_pack_end.h"
+HgfsRequestSetEA;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplySetEA {
+   uint64 reserved;        /* Reserved for future use. */
+}
+#include "vmware_pack_end.h"
+HgfsReplySetEA;
+
+/*
+ * EA Flags. When both flags are set EA is either created or replaced if it exists.
+ * HGFS_EA_FLAG_CREATE - create if EA is not present, error otherwise.
+ * HGFS_EA_FLAG_REPLACE - Replace exisitng EA. Error if EA not already present.
+ */
+#define HGFS_EA_FLAG_CREATE      (1 << 0)
+#define HGFS_EA_FLAG_REPLACE     (1 << 1)
+
+/*
+ * Byte range lock flag values:
+ * HGFS_RANGE_LOCK_EXCLUSIVE - Requested lock is exclusive when this flag is set,
+ *                             otherwise it is a shared lock.
+ * HGFS_RANGE_LOCK_FAIL_IMMEDIATLY - If the flag is not set server waits until the
+ *                                   lock becomes available.
+ */
+#define HGFS_RANGE_LOCK_EXCLUSIVE               (1 << 0)
+#define HGFS_RANGE_LOCK_FAIL_IMMEDIATLY         (1 << 1)
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestLockRange {
+   HgfsHandle     fid;          /* File to take lock on. */
+   uint32 flags;                /* Various flags. */
+   uint64 start;                /* Starting offset in the file. */
+   uint64 length;               /* Number of bytes to lock. */
+   uint64 reserved;             /* Reserved for future use. */
+}
+#include "vmware_pack_end.h"
+HgfsRequestLockRange;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyLockRange {
+   uint64 reserved;             /* Reserved for future use. */
+}
+#include "vmware_pack_end.h"
+HgfsReplyLockRange;
+
+#define HGFS_RANGE_LOCK_UNLOCK_ALL               (1 << 0)
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestUnlockRange {
+   HgfsHandle     fid;          /* File to take lock on. */
+   uint32 flags;                /* Various flags. */
+   uint64 start;                /* Starting offset in the file. */
+   uint64 length;               /* Number of bytes to lock. */
+}
+#include "vmware_pack_end.h"
+HgfsRequestUnlockRange;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyUnlockRange {
+   uint64 reserved;             /* Reserved for future use. */
+}
+#include "vmware_pack_end.h"
+HgfsReplyUnlockRange;
+
+/*
+ * There are three types of oplocks: level 1, batch, and level 2. Both the level 1 and
+ * batch oplocks are "exclusive access" opens. They are used slightly differently,
+ * however, and hence have somewhat different semantics. A level 2 oplock is a "shared
+ * access" grant on the file.
+ * Level 1 is used by a remote client that wishes to modify the data. Once granted a
+ * Level 1 oplock, the remote client may cache the data, modify the data in its cache
+ * and need not write it back to the server immediately.
+ * Batch oplocks are used by remote clients for accessing script files where the file is
+ * opened, read or written, and then closed repeatedly. Thus, a batch oplock
+ * corresponds not to a particular application opening the file, but rather to a remote
+ * clients network file system caching the file because it knows something about the
+ * semantics of the given file access. The name "batch" comes from the fact that this
+ * behavior was observed by Microsoft with "batch files" being processed by command line
+ * utilities. Log files especially exhibit this behavior when a script it being
+ * processed each command is executed in turn. If the output of the script is redirected
+ * to a log file the file fits the pattern described earlier, namely open/write/close.
+ * With many lines in a file this pattern can be repeated hundreds of times.
+ * Level 2 is used by a remote client that merely wishes to read the data. Once granted
+ * a Level 2 oplock, the remote client may cache the data and need not worry that the
+ * data on the remote file server will change without it being advised of that change.
+ * An oplock must be broken whenever the cache consistency guarantee provided by the
+ * oplock can no longer be provided. Thus, whenever a second network client attempts to
+ * access data in the same file across the network, the file server is responsible for
+ * "breaking" the oplocks and only then allowing the remote client to access the file.
+ * This ensures that the data is guaranteed to be consistent and hence we have preserved
+ * the consistency guarantees essential to proper operation.
+ *
+ * HGFS_OPLOCK_NONE: no oplock. No caching on client side.
+ * HGFS_OPLOCK_SHARED: shared (or LEVEL II) oplock. Read caching is allowed.
+ * HGFS_OPLOCK_EXCLUSIVE: exclusive (or LEVEL I) oplock. Read/write caching is allowed.
+ * HGFS_OPLOCK_BATCH: batch oplock. Read/Write and Open caching is allowed.
+ */
+
+typedef enum {
+   HGFS_OPLOCK_NONE,
+   HGFS_OPLOCK_SHARED,
+   HGFS_OPLOCK_EXCLUSIVE,
+   HGFS_OPLOCK_BATCH,
+} HgfsOpportunisticLock;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestServerLockChangeV2 {
+   HgfsHandle fid;                    /* File to take lock on. */
+   HgfsOpportunisticLock serverLock;  /* Lock type. */
+   uint64 reserved;
+}
+#include "vmware_pack_end.h"
+HgfsRequestServerLockChangeV2;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyServerLockChangeV2 {
+   HgfsOpportunisticLock serverLock;  /* Lock granted. */
+   uint64 reserved;
+}
+#include "vmware_pack_end.h"
+HgfsReplyServerLockChangeV2;
+
+/*
+ * This request is sent from server to the client to notify that oplock
+ * is revoked or downgraded.
+ */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestOplockBreakV4 {
+   HgfsHandle fid;                    /* File handle. */
+   HgfsOpportunisticLock serverLock;  /* Lock downgraded to this type. */
+   uint64 reserved;                   /* Reserved for future use. */
+}
+#include "vmware_pack_end.h"
+HgfsRequestOplockBreakV4;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyOplockBreakV4 {
+   uint64 reserved;                 /* Reserved for future use. */
+}
+#include "vmware_pack_end.h"
+HgfsReplyOplockBreakV4;
+
+/*
+ *  Flusing of a whole volume is not supported.
+ *  Flusing of reqular files is supported on all hosts.
+ *  Flusing of directories is supproted on POSIX hosts and is
+ *  NOOP on Windows hosts. 
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestFsyncV4 {
+   HgfsHandle fid;      /* File to sync. */
+   uint64 reserved;
+}
+#include "vmware_pack_end.h"
+HgfsRequestFsyncV4;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyFsyncV4 {
+   uint64 reserved;
+}
+#include "vmware_pack_end.h"
+HgfsReplyFsyncV4;
+
+/*
+ * This request is name based only.
+ * Server fails this request if HGFS_FILE_E_USE_FILE_DESC is set in the fileName.
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestAccessCheckV4 {
+   HgfsFileNameV3 fileName;     /* File concerned. */
+   HgfsPermissions perms;       /* Permissions to check for. */
+   uint64 reserved;             /* Reserved for future use. */
+}
+#include "vmware_pack_end.h"
+HgfsRequestAccessCheckV4;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyAccessCheckV4 {
+   uint64 reserved;             /* Reserved for future use. */
+}
+#include "vmware_pack_end.h"
+HgfsReplyAccessCheckV4;
+
+/*
+ * Additional HgfsPersmissions type: checks file existense without
+ * requesting any particular access.
+ * Matches F_OK mode parameter for POSIX access (2) API.
+ */
+#define HGFS_PERM_EXISTS  8
+
+/*
+ * HGFS_PLATFORM_ALL is a HGFS specific platform independent FSCTL
+ * that correspond to different OS specific codes.
+ * Other types of FSCTL are platform specific to allow better user
+ * experience when guest and host OS are the same. HGFS does not interpret
+ * platform specific FSCTL in any way, it just passes it through to the
+ * host. If the host run appropriate OS it executes FSCTL on user's behalf,
+ * otherwise it fails the request.
+ */
+typedef enum HgfsPlatformType {
+   HGFS_PLATFORM_ALL,
+   HGFS_PLATFORM_WINDOWS,
+   HGFS_PLATFORM_LINUX,
+   HGFS_PLATFORM_MAC
+}HgfsPlatformType;
+
+#define HGFS_FSCTL_SET_SPARSE 1 /* Platform independent FSCTL to make file sparse. */
+
+/* Platform together with the code define exact meaning of the operation. */
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestFsctlV4 {
+   HgfsHandle fid;
+   uint32 code;
+   HgfsPlatformType platform;
+   uint32 dataLength;
+   char data[1];
+}
+#include "vmware_pack_end.h"
+HgfsRequestFsctlV4;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyFsctlV4 {
+   uint32 dataLength;
+   char data[1];
+}
+#include "vmware_pack_end.h"
+HgfsReplyFsctlV4;
+
+/*
+ * Creating a new file or reading file attributes involves ACL. There is a good
+ * definition of multi-platform ACLs in RFC 3530, section 5.11. HGFS should use
+ * ACLs defined in this document (http://tools.ietf.org/html/rfc3530#section-5.11).
+ * ACL support is not mandatory. If a request to create file with ACL comes to a host
+ * that does not support ACL, the request should succeed and setting ACL is ignored.
+ * Such behavior is consistent with other file systems.
+ */
+typedef uint64 HgfsOpenCreateOptions;
+
+/* O_SYMLINK in Mac OS or FILE_FLAG_OPEN_REPARSE_POINT in Windows. */
+#define HGFS_OPENCREATE_OPTION_SYMLINK            (1 << 0)
+/* O_SHLOCK in Mac OS or obtain shared range lock for the whole file. */
+#define HGFS_OPENCREATE_OPTION_SHLOCK             (1 << 1)
+/* O_EXLOCK in Mac OS or obtain exclusive range lock for the whole file. */
+#define HGFS_OPENCREATE_OPTION_EXLOCK             (1 << 2)
+/* O_SYNC in Linux, ignored in Mac, FILE_FLAG_WRITE_THROUGH in Windows. */
+#define HGFS_OPENCREATE_OPTION_WRITETHROUGH       (1 << 3)
+/* FILE_FLAG_NO_BUFFERING in Windows, O_SYNC in Linux, ignored on Mac OS. */
+#define HGFS_OPENCREATE_OPTION_NO_BUFERING        (1 << 4)
+/*
+ * O_NOFOLLOW in POSIX. Windows server checks for reparse point
+ * and fails the request if file has one.
+ */
+#define HGFS_OPENCREATE_OPTION_NO_FOLLOW          (1 << 5)
+/* FILE_FLAG_NO_RECALL in Windows. Ignored by POSIX host. */
+#define HGFS_OPENCREATE_OPTION_NO_RECALL          (1 << 6)
+/* FILE_FLAG_RANDOM_ACCESS in Windows. Ignored by POSIX host. */
+#define HGFS_OPENCREATE_OPTION_RANDOM             (1 << 7)
+/* FILE_FLAG_SEQUENTIAL_SCAN in Windows. Ignored by POSIX host. */
+#define HGFS_OPENCREATE_OPTION_SEQUENTIAL         (1 << 8)
+/* FILE_FLAG_BACKUP_SEMANTICS in Windows. Ignored by POSIX host. */
+#define HGFS_OPENCREATE_OPTION_BACKUP_SEMANTICS   (1 << 9)
+/* Fail opening if the file already exists and it is not a directory. */
+#define HGFS_OPENCREATE_OPTION_DIRECTORY          (1 << 10)
+/* Fail opening if the file already exists and it is a directory. */
+#define HGFS_OPENCREATE_OPTION_NON_DIRECTORY      (1 << 11)
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestOpenV4 {
+   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 */
+   HgfsOpenCreateOptions createOptions; /* Various options. */
+   HgfsOpportunisticLock requestedLock;   /* The type of lock desired by the client */
+   HgfsFileNameV3 fileName;      /* fid can be used only for relative open,
+                                  * i.e. to open named stream.
+                                  */
+   HgfsFileName streamName;      /* Name of the alternative named stream.
+                                  * All flags are the same as defined in fileName.
+                                  * The name is used in conjuction with fileName
+                                  * field, for example if Windows opens file
+                                  * "abc.txt:stream" then fileName contains
+                                  * "abc.txt" and streamName contains "stream"
+                                  */
+   /*
+    * EA to set if the file is created or overwritten. The parameter should be ignored
+    * if the file already exists.
+    * It is needed to correctly implement Windows semantics for opening files.
+    * It should work atomically - failure to add EA should result in failure to create
+    * the new file.
+    * If the host file system does not support EA server should fail the request rather
+    * then succeeding and silently dropping EA.
+    */
+   HgfsRequestSetEA extendedAttributes;
+   uint32 aclLength;               /* Length of the acl field. */
+   char acl[1];                    /* Multi-platform ACL as defined in RFC 3530. */
+}
+#include "vmware_pack_end.h"
+HgfsRequestOpenV4;
+
+typedef enum HgfsOpenResult {
+   HGFS_FILE_OPENED,
+   HGFS_FILE_CREATED,
+   HGFS_FILE_OVERWRITTEN,
+   HGFS_FILE_SUPERSIDED,
+ } HgfsOpenResult;
+
+/*
+ * Win32 API has a special value for the desired access - MAXIMUM_ALLOWED.
+ * Such desired access means that file system must grant as much rights for the file
+ * as it is allowed for the current user.
+ * HGFS client must know what access rights were granted to properly communicate this
+ * information to the IoManager; grantedAccess field is used for this purpose.
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyOpenV4 {
+   HgfsHandle file;                   /* Opaque file ID used by the server */
+   HgfsOpportunisticLock grantedLock; /* The type of lock acquired by the server */
+   HgfsOpenResult openResult;         /* Opened/overwritten or a new file created? */
+   uint32 grantedAccess;              /* Granted access rights. */
+   uint64 fileId;                     /* Persistent volume-wide unique file id. */
+   uint64 volumeId;                   /* Persistent unique volume id. */
+}
+#include "vmware_pack_end.h"
+HgfsReplyOpenV4;
+
+/*
+ *  Flags that define behaviour of the move/creating hard link operation.
+ */
+typedef uint64 HgfsMoveLinkFlags;
+
+#define HGFS_LINKMOVE_FLAG_REPLACE_EXISTING   (1 << 0)   /* Delete existing target. */
+#define HGFS_LINKMOVE_FLAG_HARD_LINK          (1 << 1)   /* Create hard link. */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestLinkMoveV4 {
+   HgfsFileNameV3 oldFileName;      /* Path to the exisitng source file.*/
+   HgfsFileNameV3 newFileName;      /* Path to the destinatio name.*/
+   HgfsMoveLinkFlags flags;         /* Flags that define behaviour of the operation.*/
+}
+#include "vmware_pack_end.h"
+HgfsRequestLinkMoveV4;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyLinkMove4 {
+   uint64 reserved;                 /* Reserved for future use. */
+}
+#include "vmware_pack_end.h"
+HgfsReplyLinkMove4;
+
+/*
+ * HgfsQueryVolumeMaskV4 mask in a request defines which volume properties client needs;
+ * mask in a reply defines which properties were actually returned by the host.
+ *
+ * HGFS_QUERY_VOLUME_MASK_SIZE controls totalBytes, freeBytes and availableBytes.
+ * HGFS_QUERY_VOLUME_MASK_FS_CAPABILITIES controls capabilities.
+ * HGFS_QUERY_VOLUME_MASK_ATTRIBUTES controls creationTime.
+ * HGFS_QUERY_VOLUME_MASK_VOLUME_GEOMETRY controls bytesPerSector and sectorPerCluster.
+ * HGFS_QUERY_VOLUME_MASK_VOLUME_LABEL controls volume label.
+ * HGFS_QUERY_VOLUME_MASK_FS_NAME controls fileSystemName.
+ */
+typedef uint64 HgfsQueryVolumeMaskV4;
+
+#define HGFS_QUERY_VOLUME_MASK_SIZE             (1 << 0)
+#define HGFS_QUERY_VOLUME_MASK_ATTRIBUTES       (1 << 1)
+#define HGFS_QUERY_VOLUME_MASK_FS_CAPABILITIES  (1 << 2)
+#define HGFS_QUERY_VOLUME_MASK_VOLUME_LABEL     (1 << 3)
+#define HGFS_QUERY_VOLUME_MASK_VOLUME_GEOMETRY  (1 << 4)
+#define HGFS_QUERY_VOLUME_MASK_FS_NAME          (1 << 5)
+
+typedef uint64 HgfsFileSystemCapabilities;
+#define HGFS_VOLUME_CASE_SENSITIVE           (1 << 0)
+#define HGFS_VOLUME_SUPPORTS_EA              (1 << 1)
+#define HGFS_VOLUME_SUPPORTS_COMPRESSION     (1 << 2)
+#define HGFS_VOLUME_SUPPORTS_SHORT_NAMES     (1 << 3)
+#define HGFS_VOLUME_SUPPORTS_ACL             (1 << 4)
+#define HGFS_VOLUME_READ_ONLY                (1 << 5)
+#define HGFS_VOLUME_SUPPORTS_ENCRYPTION      (1 << 6)
+#define HGFS_VOLUME_SUPPORTS_OBJECT_ID       (1 << 7)
+#define HGFS_VOLUME_SUPPORTS_REMOTE_STORAGE  (1 << 8)
+#define HGFS_VOLUME_SUPPORTS_SYMLINKS        (1 << 9)
+#define HGFS_VOLUME_SUPPORTS_SPARSE_FILES    (1 << 10)
+#define HGFS_VOLUME_SUPPORTS_UNICODE         (1 << 11)
+#define HGFS_VOLUME_SUPPORTS_QUOTA           (1 << 12)
+#define HGFS_VOLUME_SUPPORTS_NAMED_STREAMS   (1 << 13)
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestQueryVolumeV4 {
+   HgfsQueryVolumeMaskV4 mask;
+   HgfsFileNameV3 name;
+}
+#include "vmware_pack_end.h"
+HgfsRequestQueryVolumeV4;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyQueryVolumeV4 {
+   HgfsQueryVolumeMaskV4 mask; /* Identifies which values were set by the host. */
+   uint64 totalBytes;          /* Total volume capacity. */
+   uint64 freeBytes;           /* Free space on the volume. */
+   uint64 availableBytes;      /* Free space available for the user. */
+   HgfsFileSystemCapabilities capabilities; /* File system capabilities. */
+   uint64 creationTime;        /* Volume creation time. */
+   uint32 bytesPerSector;      /* Sector size for the volume. */
+   uint32 sectorsPerCluster;   /* Cluster size for the volume. */
+   HgfsFileName volumeLabel;   /* Volume name or label. */
+   HgfsFileName fileSystemName;/* File system name. */
+}
+#include "vmware_pack_end.h"
+HgfsReplyQueryVolumeV4;
+
+typedef uint32 HgfsDirectoryReadMaskV4;
+#define HGFS_DIRECTORY_READ_NAME                (1 << 0)
+#define HGFS_DIRECTORY_READ_SHORT_NAME          (1 << 1)
+#define HGFS_DIRECTORY_READ_FILE_SIZE           (1 << 2)
+#define HGFS_DIRECTORY_READ_ALLOCATION_SIZE     (1 << 3)
+#define HGFS_DIRECTORY_READ_EA_SIZE             (1 << 4)
+#define HGFS_DIRECTORY_READ_TIME_STAMP          (1 << 5)
+#define HGFS_DIRECTORY_READ_FILE_ATTRIBUTES     (1 << 6)
+#define HGFS_DIRECTORY_READ_FILE_NODE_TYPE      (1 << 7)
+
+typedef uint32 HgfsDirectoryReadFlagsV4;
+#define HGFS_DIRECTORY_READ_INITIAL_QUERY       (1 << 1)
+#define HGFS_DIRECTORY_READ_SINGLE_ENTRY        (1 << 2)
+
+/*
+ * Read directory request can be used to enumerate files in a directory.
+ * File handle used in the request must be returned by HgfsRequestOpenV4 or later.
+ * searchPattern parameter allows filter out file names in the server for optimization.
+ * It is optional - host may ignore patterns and return entries that do not match
+ * the pattern. It is client responsibility to filter out names that do not match
+ * the pattern.
+ *
+ * The mask field in request allows client to specify which properties it is
+ * interested in. It allows to implement optimization in the server by skipping
+ * parameters which client does not need.
+ *
+ * Service fills mask field in the reply buffer to specify which of the requested
+ * properties it supports, which may be a subset of requested properties.
+ */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestReadDirectoryV4 {
+     HgfsDirectoryReadMaskV4 mask;
+     HgfsDirectoryReadFlagsV4 flags;
+     HgfsHandle fid;
+     uint32 restartIndex;
+     HgfsFileName searchPattern;
+}
+#include "vmware_pack_end.h"
+HgfsRequestReadDirectoryV4;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsDirectoryEntryV4 {
+   uint32 nextEntryOffset;
+   uint32 fileIndex;
+   HgfsAttrFlags attributes;
+   HgfsFileType fileType;
+   uint64 fileSize;
+   uint64 allocationSize;
+   uint64 creationTime;
+   uint64 accessTime;
+   uint64 modificationTime;
+   uint64 changeAttributesTime;
+   uint32 eaSize;
+   HgfsFileName shortName;
+   HgfsFileName fileName;
+}
+#include "vmware_pack_end.h"
+HgfsDirectoryEntryV4;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyReadDirectoryV4 {
+   uint32 numberEntriesReturned;
+   uint32 offsetToContinue;
+   HgfsDirectoryReadMaskV4 mask; /* Returned mask that may be a subset of requested mask. */
+   HgfsDirectoryEntryV4 entries[1];
+}
+#include "vmware_pack_end.h"
+HgfsReplyReadDirectoryV4;
+
+/*
+ * File handle returned by HgfsRequestOpenV4 or later. Descriptors returned by
+ * HgfsHandle fid; earlier versions of HgfsRequestOpen are not supported.
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestEnumerateStreamsV4 {
+   uint32 restartIndex;
+}
+#include "vmware_pack_end.h"
+HgfsRequestEnumerateStreamsV4;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestStreamEntryV4 {
+   uint32 nextEntryOffset;
+   uint32 fileIndex;
+   HgfsFileName fileName;
+}
+#include "vmware_pack_end.h"
+HgfsRequestStreamEntryV4;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestGetAttrV4 {
+   uint32 mask;
+   uint32 flags;
+   HgfsFileNameV3 name;
+}
+#include "vmware_pack_end.h"
+HgfsRequestGetAttrV4;
+
+/*
+ * V4 reports different file size for symlinks then V3 or V2.
+ * It does not return file name length as EOF - it reports actual EOF.
+ * On POSIX the value is always 0 and on Windows it is an actual EOF of
+ * a file with a reparse point.
+ * Each client must adjust the value for file size according to guest OS rules.
+ *
+ * Mask in HgfsAttr2V2 should be extended to include short name, symlink target and ACL.
+ * If the host does not support a requested feature it is free to clear the
+ * correspondent bit in the mask and ignore the feature.
+ *
+ * Multi-platform notice: symbolic link is represented by a file with REPARSE_POINT
+ * on Windows. Thus Windows supports swtiching a file type between
+ * regular or directory => symlink and back.
+ * Setting symlinkTarget attribute on Windows host results in assigning
+ * reparse point to the host file.
+ */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsAttrV4 {
+   HgfsAttrV2 attr;
+   uint32 numberOfLinks;
+   HgfsFileName shortName;
+   HgfsFileName symlinkTarget;
+   uint32 aclLength;
+   char acl[1];
+}
+#include "vmware_pack_end.h"
+HgfsAttrV4;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyGetAttrV4 {
+   HgfsAttrV4 attr;
+}
+#include "vmware_pack_end.h"
+HgfsReplyGetAttrV4;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplySetAttrV4 {
+   uint32 mask;                      /* Defines which attributes were set. */
+}
+#include "vmware_pack_end.h"
+HgfsReplySetAttrV4;
+
+/*
+ * Unlike V3 deletion this command can be used to delete both files and directories.
+ * Its semantics depends on whether fid or file path is specified in the fileName.
+ * When path is used it implements/emulates POSIX semantics - name is deleted from
+ * the directory however if the file is opened it is still accessible. When fid is used
+ * the file name disappears from the folder only when the last handle for the file is
+ * closed - Windows style deletion.
+ */
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsRequestDeleteFileV4 {
+   HgfsFileNameV3 fileName;
+}
+#include "vmware_pack_end.h"
+HgfsRequestDeleteFileV4;
+
+typedef
+#include "vmware_pack_begin.h"
+struct HgfsReplyDeleteFileV4 {
+   uint64 reserved;
+}
+#include "vmware_pack_end.h"
+HgfsReplyDeleteFileV4;
 
 #endif /* _HGFS_PROTO_H_ */
index 09858f073abf89a4a69efe717afd9255c44f97b3..4339a795c89e1233c1e5638c888ad88ff34c1542 100644 (file)
@@ -92,6 +92,12 @@ HgfsServerPolicy_GetShareOptions(char const *nameIn,        // IN: Share name
 Bool
 HgfsServerPolicy_IsShareOptionSet(HgfsShareOptions shareOptions,  // IN: Config options
                                   uint32 option);                 // IN: Option to check
+HgfsNameStatus
+HgfsServerPolicy_ProcessCPName(char const *nameIn,         // IN: name in CPName form
+                               size_t nameInLen,           // IN: length of the name
+                               Bool *readAccess,           // OUT: Read permissions
+                               Bool *writeAccess,          // OUT: Write permissions
+                               char const **shareBaseDir); // OUT: Shared directory
 
 void
 HgfsServerPolicy_FreeShareList(HgfsServerPolicy_ShareList *shareList); // IN: list to free
@@ -99,4 +105,9 @@ HgfsServerPolicy_FreeShareList(HgfsServerPolicy_ShareList *shareList); // IN: li
 HgfsServerPolicy_ShareList *
 HgfsServerPolicy_GetSharesWithTag(const char *tag); // IN: tag to search for
 
+Bool
+HgfsServerPolicy_CheckMode(HgfsOpenMode mode,          // IN: mode to check
+                           Bool writePermissions,      // IN: callers write permissions
+                           Bool readPermissions);      // IN: callers read permissions
+
 #endif // _HGFS_SERVER_POLICY_H_
index ea140c46de8067ad7e274f3129c81916df1ffd07..81f797ca7c7feb97a934ffa54ac970fc43d59d00 100644 (file)
@@ -75,6 +75,7 @@ extern Bool Hostinfo_OSIsWow64(void);
 #endif
 extern Bool Hostinfo_TouchBackDoor(void);
 extern Bool Hostinfo_TouchXen(void);
+extern char *Hostinfo_HypervisorCPUIDSig(void);
 
 #define HGMP_PRIVILEGE    0
 #define HGMP_NO_PRIVILEGE 1
@@ -186,5 +187,8 @@ Bool Hostinfo_GetAllCpuid(CPUIDQuery *query);
 void Hostinfo_LogLoadAverage(void);
 Bool Hostinfo_GetLoadAverage(uint32 *l);
 
+#ifdef __APPLE__
+size_t Hostinfo_GetKernelZoneElemSize(char const *name);
+#endif
 
 #endif /* ifndef _HOSTINFO_H_ */
index 13e34eaafc7a4d960b30a1ce781d6e3e73753d8f..18e53e7b95c16454732e55a9a477f7c0b2bc5560 100644 (file)
@@ -49,13 +49,11 @@ EXTERN Bool ImageUtil_ReadPNGBuffer(ImageInfo *image,
                                     const unsigned char *imageData,
                                     size_t dataLen,
                                     int pngReadFlags);
-EXTERN Bool ImageUtil_ConstructPNGBuffer(const ImageInfo *image, DynBuf *imageData);
-EXTERN Bool ImageUtil_ConstructPNGBufferEx(const ImageInfo *image,
-                                           const ImagePngWriteOptions *options,
-                                           DynBuf *imageData);
+EXTERN Bool ImageUtil_ConstructPNGBuffer(const ImageInfo *image,
+                                         const ImagePngWriteOptions *options,
+                                         DynBuf *imageData);
 EXTERN Bool ImageUtil_ConstructBMPBuffer(const ImageInfo *image, DynBuf *imageData);
-EXTERN Bool ImageUtil_ConstructBuffer(const ImageInfo *image, ImageType imageType,
-                                      DynBuf *imageData);
+
 EXTERN void ImageUtil_FreeImageData(ImageInfo *image);
 
 EXTERN Bool ImageUtil_Combine(const ImageInfo *images, const VMPoint *origins,
index 312b66b9f3bb23e355c0999678279cf099cc150b..c09285f7a86636a83f3137cad9a59d9f44e488ca 100644 (file)
@@ -15,7 +15,7 @@
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
  *
  *********************************************************/
-  
+
 #ifndef _LOGLEVEL_USER_H_
 #define _LOGLEVEL_USER_H_
 
@@ -70,6 +70,7 @@
    LOGLEVEL_VAR(usb), \
    LOGLEVEL_VAR(vusbmouse), \
    LOGLEVEL_VAR(vusbkeyboard), \
+   LOGLEVEL_VAR(vusbhid), \
    LOGLEVEL_VAR(hidQueue), \
    LOGLEVEL_VAR(pci_1394), \
    LOGLEVEL_VAR(1394), \
    LOGLEVEL_VAR(brtalk), /* macWireless and wpa_supplicant */ \
    LOGLEVEL_VAR(button), \
    LOGLEVEL_VAR(util), \
-   LOGLEVEL_VAR(largepage),
+   LOGLEVEL_VAR(largepage), \
+   LOGLEVEL_VAR(guestAppMonitor),
 
 LOGLEVEL_EXTENSION_DECLARE(LOGLEVEL_USER);
 
-#endif /* _LOGLEVEL_USER_H_ */ 
+#endif /* _LOGLEVEL_USER_H_ */
index 9bf923fba19fdce27fbbffa62b03899199c30210..c7af8e341c0259312b4fbcec4c578ccba46cae5b 100644 (file)
 #define __NETUTIL_H__
 
 #ifdef _WIN32
-#include <winsock2.h>
-#include <iphlpapi.h>
-#include <windows.h>
+/*
+ * Redefine the WINNT version for this file to be 'LONGHORN' so that we'll get
+ * the definitions for MIB_IPFORWARDTABLE2 et. al.
+ */
+#   if (_WIN32_WINNT < 0x0600)
+#      undef _WIN32_WINNT
+#      define _WIN32_WINNT 0x0600
+#   endif
+
+#   include <windows.h>
+#   include <ws2tcpip.h>
+#   include "vmware/iphlpapi_packed.h"
+#else
+#   include <arpa/inet.h>
 #endif
 
 #include "vm_basic_types.h"
 #  include "guestInfo.h"
 #endif
 
+/*
+ * Interface types as assigned by IANA.
+ * See http://www.iana.org/assignments/ianaiftype-mib for more details.
+ */
+
+typedef enum {
+   IANA_IFTYPE_OTHER            = 1,
+   IANA_IFTYPE_ETHERNETCSMACD   = 6,
+} IanaIfType;
+
 
 /*
  * Modified from iptypes.h...
@@ -69,6 +90,9 @@ ULONG NetUtil_GetAdaptersAddresses(ULONG Family,
                                    PIP_ADAPTER_ADDRESSES adap_addresses,
                                    PULONG SizePointer);
 
+PMIB_IPFORWARDTABLE NetUtilWin32_GetIpForwardTable(void);
+PMIB_IPFORWARD_TABLE2 NetUtilWin32_GetIpForwardTable2(void);
+void NetUtilWin32_FreeMibTable(PMIB_IPFORWARD_TABLE2);
 #endif
 
 #ifdef N_PLAT_NLM
@@ -77,6 +101,15 @@ void NetUtil_MonitorIPStart(void);
 void NetUtil_MonitorIPStop(void);
 #endif
 
+#ifdef WIN32
+int NetUtil_InetPToN(int af, const char *src, void *dst);
+const char *NetUtil_InetNToP(int af, const void *src, char *dst,
+                             socklen_t size);
+#else // ifdef WIN32
+#   define NetUtil_InetPToN     inet_pton
+#   define NetUtil_InetNToP     inet_ntop
+#endif
+
 #if defined(linux)
 #   ifdef DUMMY_NETUTIL
 /*
@@ -101,7 +134,11 @@ EXTERN NetUtilIfTableEntry netUtilIfTable[];
 
 int   NetUtil_GetIfIndex(const char *ifName);
 char *NetUtil_GetIfName(int ifIndex);
-
 #endif // if defined(linux)
 
-#endif
+size_t NetUtil_GetHardwareAddress(int ifIndex,         // IN
+                                  char *hwAddr,        // OUT
+                                  size_t hwAddrSize,   // IN
+                                  IanaIfType *ifType); // OUT
+
+#endif // ifndef _NETUTIL_H_
index 4a7235a14ce666cb072791bc8bd02b2b641941ec..11b428674fe0f61aff9fbfb1aed465a84e985590 100644 (file)
@@ -37,6 +37,9 @@ extern int64 Preference_GetInt64(int64 defaultvalue, const char *fmt);
 extern double Preference_GetDouble(double defaultValue, const char *fmt);
 extern char *Preference_GetString(const char *defaultValue, const char *fmt);
 extern char *Preference_GetStringPlain(const char *defaultValue, const char *fmt);
+extern char *Preference_GetStringEnum(const void *defaultValue,
+                                      const char **choices,
+                                      const char *name);
 extern int32 Preference_Generation(void);
 extern void Preference_Log(void);
 extern char *Preference_GetPathName(const char *defaultValue, const char *fmt);
index 6caa5e98d167855833c73cecf1dc13c31042b64f..f387816f12ef9d1ff3e2010fcf644e53a8515e19 100644 (file)
@@ -50,6 +50,9 @@
 #error Use safetime.h instead of time.h, stat.h, and types.h
 #endif
 
+#undef  FMTTIME
+#define FMTTIME FMT64"d"
+
 #if (_MSC_VER < 1400)
 
 #define _STAT_DEFINED
diff --git a/open-vm-tools/lib/include/slashProc.h b/open-vm-tools/lib/include/slashProc.h
new file mode 100644 (file)
index 0000000..bd3d7b4
--- /dev/null
@@ -0,0 +1,44 @@
+/*********************************************************
+ * Copyright (C) 2009 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.
+ *
+ *********************************************************/
+
+/**
+ * @file slashProc.h
+ */
+
+#ifndef _SLASHPROC_H_
+#define _SLASHPROC_H_
+
+#include <glib.h>
+#include <net/route.h>
+
+
+/*
+ * Global functions
+ */
+
+
+EXTERN GHashTable *SlashProcNet_GetSnmp(void);
+EXTERN GHashTable *SlashProcNet_GetSnmp6(void);
+
+EXTERN GPtrArray  *SlashProcNet_GetRoute(void);
+EXTERN void        SlashProcNet_FreeRoute(GPtrArray *);
+
+EXTERN GPtrArray  *SlashProcNet_GetRoute6(void);
+EXTERN void        SlashProcNet_FreeRoute6(GPtrArray *);
+
+#endif // ifndef _SLASHPROC_H_
index 562ae8686447204ff9e1bef06b3825fb9768f308..5588a5bf73bd4fe71fa4b4ab94784b2d26acef7d 100644 (file)
@@ -78,6 +78,7 @@ typedef struct MonListNode {
 BOOL System_SetProcessPrivilege(LPCTSTR lpszPrivilege, Bool bEnablePrivilege);
 int32 System_GetSPVersion(void);
 Bool System_IsLoginScreenActive(void);
+Bool System_IsProcessElevated(void);
 Bool System_IsScreenSaverActive(void);
 Bool System_IsScreenSaverRunning(void);
 Bool System_StartDesktopSwitchThread(DesktopSwitchThreadArgs *args);
index fb61dab40eea4fd393416b359892e94fd750fc97..aa0c844b3e38a618da6b3b583201baffe411cfb7 100644 (file)
 #define UNITY_RPC_DESKTOP_CONFIG_SET      "unity.desktop.config.set"
 #define UNITY_RPC_DESKTOP_ACTIVE_SET      "unity.desktop.active.set"
 #define UNITY_RPC_WINDOW_DESKTOP_SET      "unity.window.desktop.set"
+#define UNITY_RPC_WINDOW_STICK            "unity.window.stick"
+#define UNITY_RPC_WINDOW_UNSTICK          "unity.window.unstick"
 
 #define GHI_RPC_GUEST_SHELL_ACTION                    "ghi.guest.shell.action"
 #define GHI_RPC_SET_GUEST_HANDLER                     "ghi.guest.handler.set"
@@ -744,6 +746,22 @@ desktop where the upper right <tt>{1,2}</tt> is the currently active desktop.
    @param[in] UnityWindowId UnityWindowId of window to move
    @param[in] offset Offset into desktop configuration, as defined by
                      @ref UNITY_RPC_DESKTOP_CONFIG_SET, 0 or greater.
+
+
+   @def         UNITY_RPC_WINDOW_STICK
+   @brief       "Stick" a window to the screen.
+   @code
+   UNITY_RPC_WINDOW_STICK UnityWindowId
+   @endcode
+   @param[in] UnityWindowId UnityWindowId of window to stick.
+
+   @def         UNITY_RPC_WINDOW_UNSTICK
+   @brief       "Unstick" a window from the screen.
+   @code
+   UNITY_RPC_WINDOW_UNSTICK UnityWindowId
+   @endcode
+   @param[in] UnityWindowId UnityWindowId of window to unstick.
+
    @}
 */
 
index 6d327cf6e5633371e0bbad01889cda471da976c8..55abf53c29e593879d6ef4822e058a0af024d538 100644 (file)
@@ -81,9 +81,9 @@ EXTERN char *Util_GetMacOSDefaultVMPath();
 #endif // __APPLE__
 
 
-EXTERN uint32 CRC_Compute(uint8 *buf, int len);
-EXTERN uint32 Util_Checksum32(uint32 *buf, int len);
-EXTERN uint32 Util_Checksum(uint8 *buf, int len);
+EXTERN uint32 CRC_Compute(const uint8 *buf, int len);
+EXTERN uint32 Util_Checksum32(const uint32 *buf, int len);
+EXTERN uint32 Util_Checksum(const uint8 *buf, int len);
 EXTERN uint32 Util_Checksumv(void *iov, int numEntries);
 EXTERN Unicode Util_ExpandString(ConstUnicode fileName);
 EXTERN void Util_ExitThread(int);
index 172610b6032326ef7be66446c82029533f94b80f..80b9389fb23b20d22c7c4661b6d9dbf54581e9aa 100644 (file)
@@ -74,7 +74,7 @@ UtilCRCMakeTable(void)
 }
    
 static INLINE_SINGLE_CALLER uint32 
-UtilCRCUpdate(uint32 crc, uint8 *buf, int len)
+UtilCRCUpdate(uint32 crc, const uint8 *buf, int len)
 {
    uint32 c = crc;
    int n;
@@ -108,7 +108,7 @@ UtilCRCUpdate(uint32 crc, uint8 *buf, int len)
  *----------------------------------------------------------------------
  */
 uint32 
-CRC_Compute(uint8 *buf, int len)
+CRC_Compute(const uint8 *buf, int len)
 {
    return UtilCRCUpdate(0xffffffffL, buf, len) ^ 0xffffffffL;
 }
index 044fba71884dd8c6479d200858d6bfceb633d7f9..ec826a33467d48b87457b4f484de2768aed6bc3b 100644 (file)
@@ -117,6 +117,7 @@ enum {
    VIX_E_NEED_KEY                               = 30,
    VIX_E_LICENSE                                = 32,
    VIX_E_VM_HOST_DISCONNECTED                   = 34,
+   VIX_E_AUTHENTICATION_FAIL                    = 35,
 
    /* Handle Errors */
    VIX_E_INVALID_HANDLE                         = 1000,
@@ -460,6 +461,10 @@ enum {
    VIX_PROPERTY_SNAPSHOT_POWERSTATE                   = 4205,
    VIX_PROPERTY_SNAPSHOT_IS_REPLAYABLE                = 4207,
 
+   VIX_PROPERTY_GUEST_SHAREDFOLDERS_SHARES_PATH       = 4525,
+
+   /* Virtual machine encryption properties */
+   VIX_PROPERTY_VM_ENCRYPTION_PASSWORD                = 7001,
 };
 
 /*
@@ -1119,7 +1124,8 @@ VixHandle VixVM_UpgradeVirtualHardware(VixHandle vmHandle,
 
 enum {
    VIX_INSTALLTOOLS_MOUNT_TOOLS_INSTALLER = 0x00,
-   VIX_INSTALLTOOLS_AUTO_UPGRADE   = 0x01
+   VIX_INSTALLTOOLS_AUTO_UPGRADE          = 0x01,
+   VIX_INSTALLTOOLS_RETURN_IMMEDIATELY    = 0x02
 };
 
 VixHandle VixVM_InstallTools(VixHandle vmHandle,
index 4f3cd39ca0fde1212be64927d0f53696eae04a91..961696f35d57d35002abf97b78019e20491bddf2 100644 (file)
@@ -94,6 +94,7 @@ enum {
    VIX_REQUESTMSG_RETURN_ON_INITIATING_TOOLS_UPGRADE  = 0x02,
    VIX_REQUESTMSG_RUN_IN_ANY_VMX_STATE                = 0x04,
    VIX_REQUESTMSG_REQUIRES_INTERACTIVE_ENVIRONMENT    = 0x08,
+   VIX_REQUESTMSG_INCLUDES_AUTH_DATA_V1               = 0x10,
 };
 
 
@@ -398,6 +399,15 @@ struct VixMsgSetVMStateRequest {
 VixMsgSetVMStateRequest;
 
 
+typedef
+#include "vmware_pack_begin.h"
+struct VixMsgAuthDataV1 {
+   int64  nonce;
+   uint32 sequenceNumber;
+   uint8  hashValue[32];
+}
+#include "vmware_pack_end.h"
+VixMsgAuthDataV1;
 
 
 
@@ -1482,6 +1492,17 @@ struct VixCommandMakeSessionKeyResponse {
 VixCommandMakeSessionKeyResponse;
 
 
+typedef
+#include "vmware_pack_begin.h"
+struct VixCommandGenerateNonceResponse {
+   VixCommandResponseHeader     header;
+
+   int64                        nonce;
+}
+#include "vmware_pack_end.h"
+VixCommandGenerateNonceResponse;
+
+
 enum {
    VIX_CYPHERTYPE_NONE        = 0,
    VIX_CYPHERTYPE_DEFAULT     = 1,
@@ -2394,6 +2415,10 @@ enum {
 
    VIX_COMMAND_REMOVE_BULK_SNAPSHOT             = 172,
 
+   VIX_COMMAND_COPY_FILE_FROM_READER_TO_GUEST   = 173,
+
+   VIX_COMMAND_GENERATE_NONCE                   = 174,
+
    /*
     * HOWTO: Adding a new Vix Command. Step 2a.
     *
@@ -2404,7 +2429,7 @@ enum {
     * Once a new command is added here, a command info field needs to be added
     * in bora/lib/foundryMsg. as well.
     */
-   VIX_COMMAND_LAST_NORMAL_COMMAND              = 173,
+   VIX_COMMAND_LAST_NORMAL_COMMAND              = 175,
 
    VIX_TEST_UNSUPPORTED_TOOLS_OPCODE_COMMAND    = 998,
    VIX_TEST_UNSUPPORTED_VMX_OPCODE_COMMAND      = 999,
index ae4d0c3db18e680270bab0a93305de3580700549..08f2188fd15e91692cb1862df9179444e1c5e6ab 100644 (file)
@@ -514,25 +514,6 @@ typedef int pid_t;
 #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.
  */
index 43bc38faca9afc967cef5c74084e43d46460f6e6..0034514e909f65d64e19f8fb3a75dcd6ab68ea08 100644 (file)
@@ -940,7 +940,21 @@ typedef void * UserVA;
 #if defined(__FreeBSD__) && (__FreeBSD__ + 0) && ((__FreeBSD__ + 0) >= 5)
 #   define FMTTIME FMTSZ"d"
 #else
-#   define FMTTIME "ld"
+#   if defined(_MSC_VER)
+#      ifndef _SAFETIME_H_
+#         if (_MSC_VER < 1400) || defined(_USE_32BIT_TIME_T)
+#             define FMTTIME "ld"
+#         else
+#             define FMTTIME FMT64"d"
+#         endif
+#      else
+#         ifndef FMTTIME
+#            error "safetime.h did not define FMTTIME"
+#         endif
+#      endif
+#   else
+#      define FMTTIME "ld"
+#   endif
 #endif
 
 /*
index 85e7633394533d3d4c178ca3d24098948ce9475e..9a35b5e72b2f431259179d795dd4206486407c82 100644 (file)
 #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 MAKE_NAME("View Client")
 #define PRODUCT_VDM_CLIENT_NAME_FOR_LICENSE PRODUCT_VDM_CLIENT_NAME
 
 // XXX VMvisor is the underlying technology for possibly several products,
       || defined(VMX86_WGS)      \
       || defined(VMX86_DESKTOP)  \
       || defined(VMX86_ENTERPRISE_DESKTOP) \
-      || defined(VMX86_MUI)       \
+      || defined(VMX86_MUI)      \
       || defined(VMX86_API)      \
       || defined(VMX86_VPX)      \
       || defined(VMX86_WBC)      \
  * For Host Agent (hostd)
  */
 
-#define HOST_AGENT_PRODUCT_NAME                PRODUCT_NAME " Host Agent"
+#define HOST_AGENT_PRODUCT_NAME     PRODUCT_NAME " Host Agent"
 
 /* Used by bora/vim/lib/vmgina module.
  * @todo Use this also in /bora/install/msi/InstUtil/desktop/vmInstUtil.cpp
  *       to guarantee that the service is installed with exactly this name.
  */
-#define HOST_AGENT_SERVICE_NAME                "VMwareHostd"
+#define HOST_AGENT_SERVICE_NAME     "VMwareHostd"
 
 #endif /* VM_PRODUCT_H */
index 7f2397fc33167aafbbc3e073d0c03455dc0bdd63..237bfac2adc08ee9746f08629f30087f7aa4b3b6 100644 (file)
@@ -893,6 +893,13 @@ typedef uint32 ToolsVersion;
 #define   TOOLS_VERSION_WS70_BETA2_V_MNR  1
 #define   TOOLS_VERSION_WS70_BETA2_V_BASE 1
 
+#ifndef RC_INVOKED
+#define   TOOLS_VERSION_WS70_RC  TOOLS_VERSION_TO_UINT(TOOLS_VERSION_WS70_RC_V)
+#endif /* RC_INVOKED */
+#define   TOOLS_VERSION_WS70_RC_V_MJR  8
+#define   TOOLS_VERSION_WS70_RC_V_MNR  1
+#define   TOOLS_VERSION_WS70_RC_V_BASE 2
+
 #ifndef RC_INVOKED
 #define   TOOLS_VERSION_FUSION30_BETA1  TOOLS_VERSION_TO_UINT(TOOLS_VERSION_FUSION30_BETA1_V)
 #endif /* RC_INVOKED */
@@ -907,10 +914,16 @@ typedef uint32 ToolsVersion;
 #define   TOOLS_VERSION_FUSION30_BETA2_V_MNR  2
 #define   TOOLS_VERSION_FUSION30_BETA2_V_BASE 1
 
+#ifndef RC_INVOKED
+#define   TOOLS_VERSION_FUSION30_RC  TOOLS_VERSION_TO_UINT(TOOLS_VERSION_FUSION30_RC_V)
+#endif /* RC_INVOKED */
+#define   TOOLS_VERSION_FUSION30_RC_V_MJR  8
+#define   TOOLS_VERSION_FUSION30_RC_V_MNR  2
+#define   TOOLS_VERSION_FUSION30_RC_V_BASE 2
 
-#define   TOOLS_VERSION_CURRENT        TOOLS_VERSION_WS70_BETA2
-#define   TOOLS_VERSION_CURRENT_STR    TOOLS_VERSION_TO_STR(TOOLS_VERSION_WS70_BETA2)
-#define   TOOLS_VERSION_CURRENT_CSV    TOOLS_VERSION_TO_CSV(TOOLS_VERSION_WS70_BETA2)
+#define   TOOLS_VERSION_CURRENT        TOOLS_VERSION_WS70_RC
+#define   TOOLS_VERSION_CURRENT_STR    TOOLS_VERSION_TO_STR(TOOLS_VERSION_WS70_RC)
+#define   TOOLS_VERSION_CURRENT_CSV    TOOLS_VERSION_TO_CSV(TOOLS_VERSION_WS70_RC)
 
 
 /*
index 216ab60cd53341a69a8d62d0b07793913338d454..a881c916df0a7d6bbf50bb15185733c3d73d5d55 100644 (file)
@@ -90,7 +90,7 @@
 #elif defined(VMX86_VCB)
    #define PRODUCT_VERSION    1,0,0,PRODUCT_BUILD_NUMBER_NUMERIC
 #elif defined(VMX86_VLICENSE)
-   #define PRODUCT_VERSION    1,1,0,PRODUCT_BUILD_NUMBER_NUMERIC
+   #define PRODUCT_VERSION    1,1,2,PRODUCT_BUILD_NUMBER_NUMERIC
 #else
    #define PRODUCT_VERSION    3,1,0,PRODUCT_BUILD_NUMBER_NUMERIC
 #endif
 #define FOUNDRY_VERSION "e.x.p"
 #define FOUNDRY_FILE_VERSION 1,7,0,PRODUCT_BUILD_NUMBER_NUMERIC
 #define VMLS_VERSION "e.x.p"
-#define VLICENSE_VERSION "1.1.0"
+#define VLICENSE_VERSION "1.1.2"
 #define DDK_VERSION "e.x.p"
 #define VIM_API_VERSION "4.0"
 #define VIPERL_VERSION "1.1.0"
 /*
  * The current Tools version, derived from vm_tools_version.h. Do not modify this.
  */
-#define TOOLS_VERSION "2009.07.22"
+#define TOOLS_VERSION "2009.08.24"
 
 #ifdef VMX86_VPX
 #define VIM_API_TYPE "VirtualCenter"
diff --git a/open-vm-tools/lib/include/vmblock_user.h b/open-vm-tools/lib/include/vmblock_user.h
new file mode 100644 (file)
index 0000000..13213ee
--- /dev/null
@@ -0,0 +1,165 @@
+/*********************************************************
+ * Copyright (C) 2009 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.
+ *
+ *********************************************************/
+
+/*********************************************************
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of VMware Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission of VMware Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *********************************************************/
+
+/*********************************************************
+ * 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.
+ *
+ *********************************************************/
+
+/*
+ * vmblock_user.h --
+ *
+ *   Provides interfaces that allow user level programs to talk to the
+ *   vmblock fs.
+ */
+
+#ifndef _VMBLOCK_USER_H_
+#define _VMBLOCK_USER_H_
+
+#include "vm_basic_types.h"
+#include "vmblock.h"
+
+static INLINE int
+VMBLOCK_CONTROL_FUSE(int fd,            // IN
+                     char op,           // IN
+                     const char *path)  // IN
+{
+   /*
+    * buffer needs room for an operation character and a string with max length
+    * PATH_MAX - 1.
+    */
+
+   char buffer[PATH_MAX];
+   size_t pathLength;
+
+   pathLength = strlen(path);
+   if (pathLength >= PATH_MAX) {
+      errno = ENAMETOOLONG;
+      return -1;
+   }
+
+   buffer[0] = op;
+   memcpy(buffer + 1, path, pathLength);
+
+   /*
+    * The lseek is only to prevent the file pointer from overflowing;
+    * vmblock-fuse ignores the file pointer / offset. Overflowing the file
+    * pointer causes write to fail:
+    * http://article.gmane.org/gmane.comp.file-systems.fuse.devel/6648
+    * There's also a race condition here where many threads all calling
+    * VMBLOCK_CONTROL at the same time could have all their seeks executed one
+    * after the other, followed by all the writes. Again, it's not a problem
+    * unless the file pointer overflows which is very unlikely with 32 bit
+    * offsets and practically impossible with 64 bit offsets.
+    */
+
+   if (lseek(fd, 0, SEEK_SET) < 0) {
+      return -1;
+   }
+
+   if (write(fd, buffer, pathLength + 1) < 0) {
+      return -1;
+   }
+
+   return 0;
+}
+
+#if defined(vmblock_fuse)
+
+#define VMBLOCK_CONTROL(fd, op, path) VMBLOCK_CONTROL_FUSE(fd, op, path)
+
+#elif defined(linux)
+
+static INLINE int
+VMBLOCK_CONTROL(int fd, int op, const char *path)
+{
+   return write(fd, path, op);
+}
+
+#elif defined(__FreeBSD__)
+
+static INLINE int
+VMBLOCK_CONTROL(int fd, int cmd, const char *path)
+{
+   char tpath[MAXPATHLEN];
+   size_t pathSize;
+
+   if (path == NULL) {
+      return -1;
+   }
+
+  /*
+   * FreeBSD's ioctl data parameters must be of fixed size.  Guarantee a safe
+   * buffer of size MAXPATHLEN by copying the user's string to one of our own.
+   */
+   pathSize = strlcpy(tpath, path, MAXPATHLEN);
+   if (pathSize >= sizeof tpath) {
+      return -1;
+   }
+
+   return ioctl(fd, cmd, tpath);
+}
+
+#elif defined(sun)
+
+static INLINE int
+VMBLOCK_CONTROL(int fd, int cmd, const char *path)
+{
+   return ioctl(fd, cmd, path);
+}
+
+#endif
+
+#endif // _VMBLOCK_USER_H_
index b33e6372a924bbe2a60364981430a01990396fdb..6944059934f0b79f1490e11bde9b95eaf84eda2d 100644 (file)
@@ -109,6 +109,9 @@ VMTools_ReloadConfig(const gchar *path,
                      GKeyFile **config,
                      time_t *mtime);
 
+void
+VMTools_ResetLogging(gboolean cleanDefault);
+
 gboolean
 VMTools_WriteConfig(const gchar *path,
                     GKeyFile *config,
index 25d15c8421d38c7570447bdcff8e39bf4d711533..0efa4bc95ed874ecc692a0182804870905e1587c 100644 (file)
 #ifndef _WIPER_H_
 # define _WIPER_H_
 
-
 #if defined(_WIN32) && defined(_MSC_VER)
 #include <windows.h>
 #endif
 
-
 #include "vm_basic_types.h"
+#include "dbllnklst.h"
 
 
 typedef enum {
+   PARTITION_UNSUPPORTED = 0,
    PARTITION_EXT2,
    PARTITION_EXT3,
    PARTITION_REISERFS,
@@ -52,28 +52,25 @@ typedef enum {
 typedef struct WiperPartition {
    unsigned char mountPoint[NATIVE_MAX_PATH];
 
-   /* 
-    * Empty if type is set, otherwise describes why the partition can not be
-    * wiped
-    */
-   char *comment;
-
-   /* Type of the partition we know how to wipe */
+   /* Type of the partition */
    WiperPartition_Type type;
 
+   /*
+    * NULL if type is not PARTITION_UNSUPPORTED, otherwise describes
+    * why the partition can not be wiped.
+    */
+   const char *comment;
+
 #if defined(_WIN32)
    /* Private flags used by the Win32 implementation */
    DWORD flags;
 #endif
 
-#if defined(N_PLAT_NLM)
-   unsigned long volumeNumber;
-#endif
+   DblLnkLst_Links link;
 } WiperPartition;
 
 typedef struct WiperPartition_List {
-   WiperPartition *partitions;
-   unsigned int size;
+   DblLnkLst_Links link;
 } WiperPartition_List;
 
 typedef struct WiperInitData {
@@ -83,15 +80,16 @@ typedef struct WiperInitData {
 } WiperInitData;
 
 Bool Wiper_Init(WiperInitData *clientData);
-WiperPartition_List *WiperPartition_Open(void);
+Bool WiperPartition_Open(WiperPartition_List *pl);
 void WiperPartition_Close(WiperPartition_List *pl);
 
-WiperPartition *SingleWiperPartition_Open(const char *mntpt);
-void SingleWiperPartition_Close(WiperPartition *pl);
+WiperPartition *WiperSinglePartition_Allocate(void);
+WiperPartition *WiperSinglePartition_Open(const char *mntpt);
+void WiperSinglePartition_Close(WiperPartition *);
 
-unsigned char *WiperSinglePartition_GetSpace(const WiperPartition *p,  
-                              uint64 *free,       
-                              uint64 *total);      
+unsigned char *WiperSinglePartition_GetSpace(const WiperPartition *p,
+                              uint64 *free,
+                              uint64 *total);
 
 /* External definition of the wiper state */
 struct Wiper_State;
index 223060392220d0e22e986caaf362b934f2d7af2d..14195712948dda05db43f0dbba205fa2d8a17111 100644 (file)
@@ -48,6 +48,7 @@
 #include "includeCheck.h"
 
 #include "vm_basic_types.h"
+#include "community_source.h"
 
 /*
  * The linux kernel's ptrace.h stupidly defines the bare
@@ -107,10 +108,6 @@ CPUIDQuery;
  * 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                     \
@@ -121,6 +118,7 @@ CPUIDQuery;
    CPUIDLEVEL(FALSE,410, 0x40000010)            \
    CPUIDLEVEL(FALSE, 80, 0x80000000)            \
    CPUIDLEVEL(TRUE,  81, 0x80000001)            \
+   CPUIDLEVEL(FALSE, 87, 0x80000007)            \
    CPUIDLEVEL(FALSE, 88, 0x80000008)            \
    CPUIDLEVEL(TRUE,  8A, 0x8000000A)
 
@@ -128,8 +126,7 @@ CPUIDQuery;
    CPUIDLEVEL(FALSE, 4, 4)                      \
    CPUIDLEVEL(FALSE, 6, 6)                      \
    CPUIDLEVEL(FALSE, A, 0xA)                    \
-   CPUIDLEVEL(FALSE, 86, 0x80000006)            \
-   CPUIDLEVEL(FALSE, 87, 0x80000007)            \
+   CPUIDLEVEL(FALSE, 86, 0x80000006)
 
 #define CPUID_ALL_LEVELS                        \
    CPUID_CACHED_LEVELS                          \
@@ -143,6 +140,11 @@ typedef enum {
    CPUID_NUM_LEVELS
 } CpuidLevels;
 
+
+/* SVM CPUID feature leaf */
+#define CPUID_SVM_FEATURES         0x8000000a
+
+
 /*
  * CPUID result registers
  */
@@ -659,6 +661,7 @@ FIELD_FUNC(MWAIT_C4_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C4_SUBSTATE)
 #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_NEHALEM_1E 0x1e  // Lynnfield
 
 #define CPUID_MODEL_PIII_07    7
 #define CPUID_MODEL_PIII_08    8
@@ -789,9 +792,13 @@ CPUID_UARCH_IS_NEHALEM(uint32 v) // IN: %eax from CPUID with %eax=1.
 
    return CPUID_FAMILY_IS_P6(v) &&
           (
+           effectiveModel == CPUID_MODEL_NEHALEM_1E ||
            effectiveModel == CPUID_MODEL_NEHALEM_1A);
 }
 
+
+
+
 static INLINE Bool
 CPUID_FAMILY_IS_K7(uint32 _eax)
 {
index 4e051f0786abd47f892ab21c2355df5813080981..d64be4d36ccfc5d3d6a9d78695230a964a8f2764 100644 (file)
  * Wrapper for XdrUtil_ArrayAppend that automatically populates the arguments
  * from a given XDR array.
  */
-#define XDRUTIL_ARRAYAPPEND(ptr, field, cnt)                \
-   XdrUtil_ArrayAppend((void **) &(ptr)->field.field##_val, \
-                       &(ptr)->field.field##_len,           \
-                       sizeof *(ptr)->field.field##_val,    \
-                       (cnt));
+#ifdef __GNUC__
+#   define XDRUTIL_ARRAYAPPEND(ptr, field, cnt)                 \
+       (typeof ((ptr)->field.field##_val))                      \
+       XdrUtil_ArrayAppend((void **) &(ptr)->field.field##_val, \
+                           &(ptr)->field.field##_len,           \
+                           sizeof *(ptr)->field.field##_val,    \
+                           (cnt))
+#else
+#   define XDRUTIL_ARRAYAPPEND(ptr, field, cnt)                 \
+       XdrUtil_ArrayAppend((void **) &(ptr)->field.field##_val, \
+                           &(ptr)->field.field##_len,           \
+                           sizeof *(ptr)->field.field##_val,    \
+                           (cnt))
+#endif
 
 void *
 XdrUtil_ArrayAppend(void **array, u_int *arrayLen, size_t elemSz, u_int elemCnt);
index 09cf418032ca75af4a2dfc68adfc3ebd76a77e92..e6fccb2ddc2509db9c33fd65a6ae2b30239b44d1 100644 (file)
@@ -76,6 +76,10 @@ static const char nul[] = {'\0', '\0'};
 static const wchar_t nul = L'\0';
 #endif
 
+#ifndef USE_ICONV
+static Bool CodeSetOldIso88591ToUtf8Db(char const *bufIn, size_t sizeIn,
+                                       unsigned int flags, DynBuf *db);
+#endif
 
 /*
  *-----------------------------------------------------------------------------
@@ -103,35 +107,35 @@ CodeSetOldGetUtf8(const char *string,     // IN: string
    uint8 *e;
    uint32 c;
    int len;
-
    ASSERT(string < end);
 
    c = *p;
 
    if (c < 0x80) {
-      // ASCII
+      // ASCII: U+0000 - U+007F: 1 byte of UTF-8.
       len = 1;
       goto out;
    }
 
-   if (c < 0xc2) {
+   if ((c < 0xc2) || (c > 0xf4)) {
       // 0x81 to 0xbf are not valid first bytes
       // 0xc0 and 0xc1 cannot appear in UTF-8, see below
+      // leading char can not be > 0xf4, illegal as well
       return 0;
    }
 
    if (c < 0xe0) {
+      // U+0080 - U+07FF: 2 bytes of UTF-8.
       c -= 0xc0;
       len = 2;
-   } else if (c <= 0xf0) {
+   } else if (c < 0xf0) {
+      // U+0800 - U+FFFF: 3 bytes of UTF-8.
       c -= 0xe0;
       len = 3;
-   } else if (c <= 0xf8) {
+   } else {
+      // U+10000 - U+10FFFF: 4 bytes of UTF-8.
       c -= 0xf0;
       len = 4;
-   } else {
-      // bad first byte
-      return 0;
    }
 
    if ((e = p + len) > (uint8 *) end) {
@@ -1171,6 +1175,14 @@ CodeSetOld_GenericToGenericDb(char const *codeIn,  // IN
       } else {
          goto exit;
       }
+   } else if (STRING_ENCODING_ISO_8859_1 == encIn) {
+      if (STRING_ENCODING_UTF8 == encOut) {
+         if (!CodeSetOldIso88591ToUtf8Db(bufIn, sizeIn, flags, db)) {
+            goto exit;
+         }
+      } else {
+         goto exit;
+      }
    } else {
       goto exit;
    }
@@ -2085,6 +2097,50 @@ CodeSetOld_Utf8ToAsciiDb(char const *bufIn,   // IN
 }
 
 
+#ifndef USE_ICONV
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * CodeSetOldIso88591ToUtf8Db --
+ *
+ *      Convert ISO-8859-1 to UTF-8
+ *
+ * Results:
+ *      On success, TRUE and conversion result appended to db.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+CodeSetOldIso88591ToUtf8Db(char const *bufIn,   // IN
+                           size_t sizeIn,       // IN
+                           unsigned int flags,  // IN
+                           DynBuf *db)          // OUT
+{
+   size_t i;
+   size_t last = 0;
+
+   for (i = 0; i < sizeIn; i++) {
+      unsigned int c = (unsigned char)bufIn[i];
+      if (UNLIKELY(c >= 0x80)) {
+         unsigned char buf[2];
+
+         buf[0] = 0xC0 | (c >> 6);
+         buf[1] = 0x80 | (c & 0x3F);
+        DynBuf_Append(db, bufIn + last, i - last);
+         DynBuf_Append(db, buf, sizeof buf);
+        last = i + 1;
+      }
+   }
+   DynBuf_Append(db, bufIn + last, i - last);
+   return TRUE;
+}
+#endif
+
+
 #if defined(_WIN32)
 /*
  *-----------------------------------------------------------------------------
index e57491ee0d2e05254100c41606b992cdf330be50..9fb593a91a1c671b9a7faba93cbe07f346176fe2 100644 (file)
@@ -51,6 +51,7 @@
 #include <mach/mach_init.h>
 #include <mach/mach.h>
 #include <mach/mach_time.h>
+#include <sys/mman.h>
 #elif defined(__FreeBSD__)
 #if !defined(RLIMIT_AS)
 #  if defined(RLIMIT_VMEM)
@@ -123,7 +124,7 @@ static Bool hostinfoOSVersionInitialized;
 #if defined(__APPLE__)
 #define SYS_NMLN _SYS_NAMELEN
 #endif
-static int hostinfoOSVersion[3];
+static int hostinfoOSVersion[4];
 static char hostinfoOSVersionString[SYS_NMLN];
 
 #define DISTRO_BUF_SIZE 255
@@ -226,7 +227,7 @@ HostinfoOSVersionInit(void)
 
    Str_Strcpy(hostinfoOSVersionString, u.release, SYS_NMLN);
 
-   ASSERT(ARRAYSIZE(hostinfoOSVersion) >= 3);
+   ASSERT(ARRAYSIZE(hostinfoOSVersion) >= 4);
    if (sscanf(u.release, "%d.%d.%d%s",
              &hostinfoOSVersion[0], &hostinfoOSVersion[1],
              &hostinfoOSVersion[2], extra) < 1) {
@@ -235,6 +236,11 @@ HostinfoOSVersionInit(void)
       NOT_IMPLEMENTED();
    }
 
+   /* If there is a 4th number, use it, otherwise use 0. */
+   if (sscanf(extra, ".%d%*s", &hostinfoOSVersion[3]) < 1) {
+      hostinfoOSVersion[3] = 0;
+   }
+
    hostinfoOSVersionInitialized = TRUE;
 }
 
@@ -1654,10 +1660,6 @@ Hostinfo_ResetProcessState(const int *keepFds, // IN:
    int s, fd;
    struct sigaction sa;
    struct rlimit rlim;
-#ifdef __linux__
-   int err;
-   uid_t euid;
-#endif
 
    /*
     * Disable itimers before resetting the signal handlers.
@@ -1700,15 +1702,21 @@ Hostinfo_ResetProcessState(const int *keepFds, // IN:
 #ifdef __linux__
    /*
     * Drop iopl to its default value.
+    * iopl() is not implemented in userworlds
     */
-   euid = Id_GetEUid();
-   /* At this point, _unless we are running as root_, we shouldn't have root
-      privileges --hpreg */
-   ASSERT(euid != 0 || getuid() == 0);
-   Id_SetEUid(0);
-   err = iopl(0);
-   Id_SetEUid(euid);
-   ASSERT_NOT_IMPLEMENTED(err == 0);
+   if (!vmx86_server) {
+      int err;
+      uid_t euid;
+
+      euid = Id_GetEUid();
+      /* At this point, _unless we are running as root_, we shouldn't have root
+         privileges --hpreg */
+      ASSERT(euid != 0 || getuid() == 0);
+      Id_SetEUid(0);
+      err = iopl(0);
+      Id_SetEUid(euid);
+      ASSERT_NOT_IMPLEMENTED(err == 0);
+   }
 #endif
 }
 
@@ -2349,3 +2357,155 @@ Hostinfo_Execute(const char *command,  // IN:
       return 0;
    }
 }
+
+
+#ifdef __APPLE__
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Hostinfo_GetKernelZoneElemSize --
+ *
+ *      Retrieve the size of the elements in a named kernel zone.
+ *
+ *      We used to do it like zprint (see
+ *      darwinsource-10.4.5/system_cmds-336.10/zprint.tproj/zprint.c::main()),
+ *      i.e. by calling host_zone_info(), but there are 3 problems with that:
+ *
+ *      1) mach/mach_host.defs defines both arrays passed to host_zone_info()
+ *         as 'out' parameters, but the implementation of the function in
+ *         xnu-792.13.8/osfmk/kern/zalloc.c clearly expects them as 'inout'
+ *         parameters. This issue is confirmed in practice: the input values
+ *         passed by the user process are ignored. Now comes the scary part: is
+ *         the input of the kernel function deterministically invalid, or is it
+ *         some non-deterministic garbage (in which case the user process can
+ *         corrupt its address space)? The answer is in the Mach IPC code. A
+ *         cursory kernel debugging session seems to imply that the input
+ *         pointer values are garbage, but the input size values are always 0.
+ *         So the function seems safe to use in practice.
+ *
+ *      2) Starting with Mac OS 10.6, host_zone_info() always returns
+ *         KERN_NOT_SUPPORTED when the sizes of the user and kernel virtual
+ *         address spaces (32-bit or 64-bit) do not match. Was bug 377049.
+ *
+ *      3) Apple broke the ABI: For 64-bit code, the 'zone_info.zi_*_size'
+ *         fields are 32-bit in the Mac OS 10.5 SDK, but 64-bit in the Mac OS
+ *         10.6 SDK. So a 64-bit VMX compiled against the Mac OS 10.5 SDK works
+ *         with the Mac OS 10.5 (32-bit) kernel but fails with the Mac OS 10.6
+ *         64-bit kernel.
+ *
+ *      So now we just let Apple deal with their own mess: we invoke zprint,
+ *      and we parse its non-localized output. Should Apple stop shipping
+ *      zprint, we can always ship our own replacement for it.
+ *
+ * Results:
+ *      On success: the size (in bytes) > 0.
+ *      On failure: 0.
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+size_t
+Hostinfo_GetKernelZoneElemSize(char const *name) // IN: Kernel zone name
+{
+   size_t retval = 0;
+   struct {
+      size_t retval;
+   } volatile *shared;
+   pid_t child;
+   pid_t pid;
+
+   /*
+    * popen(3) incorrectly executes the shell with the identity of the calling
+    * process, ignoring a potential per-thread identity. And starting with
+    * Mac OS 10.6 it is even worse: if there is a per-thread identity, popen(3)
+    * removes it!
+    *
+    * So we run this code in a separate process which runs with the same
+    * identity as the current thread.
+    */
+
+   shared = mmap(NULL, sizeof *shared, PROT_READ | PROT_WRITE,
+                 MAP_ANON | MAP_SHARED, -1, 0);
+   if (shared == (void *)-1) {
+      Warning("%s: mmap error %d.\n", __FUNCTION__, errno);
+      return retval;
+   }
+
+   // In case the child is terminated before it can set it.
+   shared->retval = retval;
+
+   child = fork();
+   if (child == (pid_t)-1) {
+      Warning("%s: fork error %d.\n", __FUNCTION__, errno);
+      munmap((void *)shared, sizeof *shared);
+      return retval;
+   }
+
+   // This executes only in the child process.
+   if (!child) {
+      size_t nameLen;
+      FILE *stream;
+      Bool parsingProperties = FALSE;
+
+      ASSERT(name);
+
+      nameLen = strlen(name);
+      ASSERT(nameLen && *name != '\t');
+
+      stream = popen("/usr/bin/zprint -C", "r");
+      if (!stream) {
+         Warning("%s: popen error %d.\n", __FUNCTION__, errno);
+         exit(EXIT_SUCCESS);
+      }
+
+      for (;;) {
+         char *line;
+         size_t lineLen;
+
+         if (StdIO_ReadNextLine(stream, &line, 0, &lineLen) != StdIO_Success) {
+            break;
+         }
+
+         if (parsingProperties) {
+            if (   // Not a property line anymore. Property not found.
+                   lineLen < 1 || memcmp(line, "\t", 1)
+                   // Property found.
+                || sscanf(line, " elem_size: %"FMTSZ"u bytes",
+                          &shared->retval) == 1) {
+               free(line);
+               break;
+            }
+         } else if (!(   lineLen < nameLen + 6
+                      || memcmp(line, name, nameLen)
+                      || memcmp(line + nameLen, " zone:", 6))) {
+            // Zone found.
+            parsingProperties = TRUE;
+         }
+
+         free(line);
+      }
+
+      pclose(stream);
+      exit(EXIT_SUCCESS);
+   }
+
+   /*
+    * This executes only in the parent process.
+    * Wait for the child to terminate, and return its retval.
+    */
+
+   do {
+      int status;
+
+      pid = waitpid(child, &status, 0);
+   } while (pid == -1 && errno == EINTR);
+   ASSERT_NOT_IMPLEMENTED(pid == child);
+
+   retval = shared->retval;
+   munmap((void *)shared, sizeof *shared);
+   return retval;
+}
+#endif /* __APPLE__ */
index f1175cb8a280eb3ce42bd84a5811b7a1c5006d1a..399caefabcc416afdddd4b5aa453bbcf0b04c490 100644 (file)
@@ -57,6 +57,7 @@
 #include <sys/ioctl.h>
 #include <net/if.h>
 #include <sys/ioctl.h>
+#include <net/if_arp.h>         // for ARPHRD_ETHER
 
 #if defined(__FreeBSD__) || defined(__APPLE__)
 #include "ifaddrs.h"
@@ -430,4 +431,60 @@ NetUtil_GetIfName(int ifIndex)  // IN: interface index
 }
 #   endif // ifdef DUMMY_NETUTIL
 
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * NetUtil_GetHardwareAddress --
+ *
+ *      Given an interface name, return its hardware/link layer address.
+ *
+ * Results:
+ *      Returns TRUE and populates hwAddr on success.
+ *      Returns FALSE on failure.
+ *
+ * Side effects:
+ *      None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+size_t
+NetUtil_GetHardwareAddress(int ifIndex,         // IN
+                           char *hwAddr,        // OUT
+                           size_t hwAddrSize,   // IN
+                           IanaIfType *ifType)  // OUT
+{
+   struct ifreq ifreq;
+   int fd = -1;
+   size_t ret = 0;
+
+   if (hwAddrSize < IFHWADDRLEN) {
+      return FALSE;
+   }
+
+   ASSERT(sizeof ifreq.ifr_name >= IF_NAMESIZE);
+
+   memset(&ifreq, 0, sizeof ifreq);
+   if (if_indextoname(ifIndex, ifreq.ifr_name) == NULL) {
+      return FALSE;
+   }
+
+   if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
+      return FALSE;
+   }
+
+   if (ioctl(fd, SIOCGIFHWADDR, &ifreq) == 0 &&
+       ifreq.ifr_hwaddr.sa_family == ARPHRD_ETHER) {
+      memcpy(hwAddr, ifreq.ifr_hwaddr.sa_data, IFHWADDRLEN);
+      *ifType = IANA_IFTYPE_ETHERNETCSMACD;
+      ret = IFHWADDRLEN;
+   }
+
+   close(fd);
+
+   return ret;
+}
+
+
 #endif // if defined(linux)
index a5e47465c87bde2505e35ccea4f78fafc82e7d57..cc49d36249dbe78612c94081a8a938d889fe1558 100644 (file)
@@ -257,7 +257,8 @@ Raster_GetBPPDepth(uint32 depth, uint32 bpp)
  *     None
  *
  * Side effects:
- *     None
+ *      If converting from a lower true-color depth to 32-bpp, fills the
+ *      alpha values of the destination rectangle to 0xFF.
  *
  *----------------------------------------------------------------------
  */
@@ -812,7 +813,7 @@ RasterConvertShortTo24(uint8 *tof, uint32 line_increment,
  *     None
  *
  * Side effects:
- *     None
+ *      Fills the alpha values of the destination rectangle to 0xFF.
  *
  *----------------------------------------------------------------------
  */
@@ -842,7 +843,8 @@ RasterConvertShortTo32(uint8 *tof, uint32 line_increment,
    for (i=0; i<h; i++) {
       for (j=0; j<w; j++) {
         uint32 pix = srcptr[j];
-        dstptr[j] = (REDMASK_32 &
+        dstptr[j] = (0xFF << 24) |
+                     (REDMASK_32 &
                      ((((pix & redMask) >> redShift1) |
                        ((pix & redMask) >> redShift2)) << 16)) |
                     (GREENMASK_32 &
@@ -968,7 +970,7 @@ RasterConvert24toShort(uint8 *tof, uint32 line_increment,
  *     None
  *
  * Side effects:
- *     None
+ *      Fills the alpha values of the destination rectangle to 0xFF.
  *
  *----------------------------------------------------------------------
  */
@@ -995,7 +997,8 @@ RasterConvert24to32(uint8 *tof, uint32 line_increment,
         uint8 blue = srcptr[k++];
         uint8 green = srcptr[k++];
         uint8 red = srcptr[k++];
-        dstptr[j] = ((red << 16) & REDMASK_32) |
+        dstptr[j] = (0xFF << 24) |
+                     ((red << 16) & REDMASK_32) |
                     ((green << 8) & GREENMASK_32) |
                     (blue & BLUEMASK_32);
       }
@@ -1258,7 +1261,7 @@ RasterConvertIndexto24(uint8 *tof, uint32 line_increment,
  *     None
  *
  * Side effects:
- *     None
+ *      None
  *
  *----------------------------------------------------------------------
  */
index 65811726dfd16290a698cbb2415ae20d3337a6f6..a68023ef8caf193c860563684126ed5d8eb9fc01 100644 (file)
@@ -23,6 +23,7 @@
  */
 
 #include <string.h>
+#include "vm_assert.h"
 #include "dynxdr.h"
 #include "rpcChannelInt.h"
 #include "str.h"
@@ -348,7 +349,7 @@ RpcChannel_Dispatch(RpcInData *data)
       status = rpc->callback(data);
    }
 
-   g_assert(data->result != NULL);
+   ASSERT(data->result != NULL);
 
 exit:
    data->name = NULL;
@@ -481,9 +482,9 @@ void
 RpcChannel_RegisterCallback(RpcChannel *chan,
                             RpcChannelCallback *rpc)
 {
-   g_assert(rpc->name != NULL && strlen(rpc->name) > 0);
-   g_assert(rpc->callback);
-   g_assert(rpc->xdrIn == NULL || rpc->xdrInSize > 0);
+   ASSERT(rpc->name != NULL && strlen(rpc->name) > 0);
+   ASSERT(rpc->callback);
+   ASSERT(rpc->xdrIn == NULL || rpc->xdrInSize > 0);
    if (chan->rpcs == NULL) {
       chan->rpcs = g_hash_table_new(g_str_hash, g_str_equal);
    }
diff --git a/open-vm-tools/lib/slashProc/Makefile.am b/open-vm-tools/lib/slashProc/Makefile.am
new file mode 100644 (file)
index 0000000..f7fde2f
--- /dev/null
@@ -0,0 +1,27 @@
+################################################################################
+### Copyright 2007 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
+################################################################################
+
+noinst_LTLIBRARIES = libSlashProc.la
+
+libSlashProc_la_SOURCES =
+libSlashProc_la_SOURCES += net.c
+
+libSlashProc_la_CPPFLAGS =
+libSlashProc_la_CPPFLAGS += @GLIB2_CPPFLAGS@
+
+AM_CFLAGS = $(DNET_CPPFLAGS)
+
diff --git a/open-vm-tools/lib/slashProc/net.c b/open-vm-tools/lib/slashProc/net.c
new file mode 100644 (file)
index 0000000..ace9800
--- /dev/null
@@ -0,0 +1,888 @@
+/*********************************************************
+ * Copyright (C) 2009 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.
+ *
+ *********************************************************/
+
+/**
+ * @file net.c
+ *
+ *     Parses assorted /proc/net nodes.
+ */
+
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include "vmware.h"
+#include "panic.h"
+#include "slashProc.h"
+#include "slashProcNetInt.h"
+#include "netutil.h"
+
+
+/*
+ * Local data.
+ */
+
+
+#define PROC_NET_SNMP   "/proc/net/snmp"
+#define PROC_NET_SNMP6  "/proc/net/snmp6"
+#define PROC_NET_ROUTE  "/proc/net/route"
+#define PROC_NET_ROUTE6 "/proc/net/ipv6_route"
+
+
+/**
+ * @brief Evaluate an expression with a regular expression match.
+ *
+ * Convenience wrapper to fetch a regular expression match result, evaluate
+ * it as an argument in some expression, and then free it.
+ *
+ * @param[in] matchInfo  GMatchInfo RE context.
+ * @param[in] matchIndex Match index.
+ * @param[in] expr       Expression to evaluate.  Must contain @c MATCH as
+ *                       placeholder where matched value will be inserted.
+ */
+#define MATCHEXPR(matchInfo, matchIndex, expr) do {                     \
+   gchar *MATCH = g_match_info_fetch(matchInfo, matchIndex);            \
+   expr;                                                                \
+   g_free(MATCH);                                                       \
+} while(0)
+
+
+/**
+ * Override-able @c /proc/net/snmp path.  Useful for debugging.
+ */
+static const char *pathToNetSnmp = PROC_NET_SNMP;
+
+
+/**
+ * Override-able @c /proc/net/snmp6 path.  Useful for debugging.
+ */
+static const char *pathToNetSnmp6 = PROC_NET_SNMP6;
+
+
+/**
+ * Override-able @c /proc/net/route path.  Useful for debugging.
+ */
+static const char *pathToNetRoute = PROC_NET_ROUTE;
+
+
+/**
+ * Override-able @c /proc/net/ipv6_route path.  Useful for debugging.
+ */
+static const char *pathToNetRoute6 = PROC_NET_ROUTE6;
+
+
+/*
+ * Private function prototypes.
+ */
+
+static void Ip6StringToIn6Addr(const char *ip6String,
+                               struct in6_addr *in6_addr);
+static guint64 MatchToGuint64(const GMatchInfo *matchInfo,
+                              const gint matchIndex,
+                              gint base);
+
+
+/*
+ * Library private functions.
+ */
+
+
+#ifdef VMX86_DEVEL
+/*
+ ******************************************************************************
+ * SlashProcNetSetPathSnmp --                                           */ /**
+ *
+ * @brief Overrides @ref pathToNetSnmp.  Useful for debugging.
+ *
+ * @param[in] newPathToNetSnmp  New path to used in place of @ref PROC_NET_SNMP.
+ *                              If @c NULL, @ref pathToNewSnmp reverts to @ref
+ *                              PROC_NET_SNMP.
+ *
+ ******************************************************************************
+ */
+
+void
+SlashProcNetSetPathSnmp(const char *newPathToNetSnmp)
+{
+   pathToNetSnmp = newPathToNetSnmp ? newPathToNetSnmp : PROC_NET_SNMP;
+}
+
+
+/*
+ ******************************************************************************
+ * SlashProcNetSetPathSnmp6 --                                          */ /**
+ *
+ * @brief Overrides @ref pathToNetSnmp6.  Useful for debugging.
+ *
+ * @sa SlashProcNetSetPathSnmp
+ *
+ ******************************************************************************
+ */
+
+void
+SlashProcNetSetPathSnmp6(const char *newPathToNetSnmp6)
+{
+   pathToNetSnmp6 = newPathToNetSnmp6 ? newPathToNetSnmp6 : PROC_NET_SNMP6;
+}
+
+
+/*
+ ******************************************************************************
+ * SlashProcNetSetPathRoute --                                          */ /**
+ *
+ * @brief Overrides @ref pathToNetRoute.  Useful for debugging.
+ *
+ * @sa SlashProcNetSetPathSnmp
+ *
+ ******************************************************************************
+ */
+
+void
+SlashProcNetSetPathRoute(const char *newPathToNetRoute)
+{
+   pathToNetRoute = newPathToNetRoute ? newPathToNetRoute : PROC_NET_ROUTE;
+}
+
+
+/*
+ ******************************************************************************
+ * SlashProcNetSetPathRoute6 --                                         */ /**
+ *
+ * @brief Overrides @ref pathToNetRoute6.  Useful for debugging.
+ *
+ * @sa SlashProcNetSetPathSnmp
+ *
+ ******************************************************************************
+ */
+
+void
+SlashProcNetSetPathRoute6(const char *newPathToNetRoute6)
+{
+   pathToNetRoute6 = newPathToNetRoute6 ? newPathToNetRoute6 : PROC_NET_ROUTE6;
+}
+#endif // ifdef VMX86_DEVEL
+
+
+/*
+ * Library public functions.
+ */
+
+
+/*
+ ******************************************************************************
+ * SlashProcNet_GetSnmp --                                              */ /**
+ *
+ * @brief Reads @ref pathToNetSnmp and returns contents as a
+ *        <tt>GHashTable(gchar *key, guint64 *value)</tt>.
+ *
+ * Example usage:
+ * @code
+ * GHashTable *netSnmp = SlashProcNet_GetSnmp();
+ * guint64 *inDiscards = g_hash_table_lookup(netSnmp, "IpInDiscards");
+ * @endcode
+ *
+ * @note        Caller should free the returned @c GHashTable with
+ *              @c g_hash_table_destroy.
+ * @note        This routine creates persistent GLib GRegexs.
+ *
+ * @return      On failure, NULL.  On success, a valid @c GHashTable.
+ * @todo        Provide a case-insensitive key comparison function.
+ * @todo        Consider init/cleanup routines to not "leak" GRegexs.
+ *
+ ******************************************************************************
+ */
+
+GHashTable *
+SlashProcNet_GetSnmp(void)
+{
+   GHashTable *myHashTable = NULL;
+   GIOChannel *myChannel = NULL;
+   GIOStatus keyIoStatus;
+   GIOStatus valIoStatus;
+   gchar *myKeyLine = NULL;
+   gchar *myValLine = NULL;
+   Bool parseError = FALSE;
+   int fd = -1;
+
+   static GRegex *myKeyRegex = NULL;
+   static GRegex *myValRegex = NULL;
+
+   if (myKeyRegex == NULL) {
+      myKeyRegex = g_regex_new("^(\\w+): (\\w+ )*(\\w+)$", G_REGEX_OPTIMIZE,
+                               0, NULL);
+      myValRegex = g_regex_new("^(\\w+): (-?\\d+ )*(-?\\d+)$", G_REGEX_OPTIMIZE,
+                               0, NULL);
+      ASSERT(myKeyRegex);
+      ASSERT(myValRegex);
+   }
+
+   if ((fd = g_open(pathToNetSnmp, O_RDONLY)) == -1) {
+      return NULL;
+   }
+
+   myChannel = g_io_channel_unix_new(fd);
+
+   myHashTable = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+
+   /*
+    * Expected format:
+    *
+    * pfx0: key0 key1 key2 ... keyN
+    * pfx0: val0 val1 val2 ... valN
+    * ...
+    * pfxN: ...
+    */
+
+   while ((keyIoStatus = g_io_channel_read_line(myChannel, &myKeyLine, NULL, NULL,
+                                                NULL)) == G_IO_STATUS_NORMAL &&
+          (valIoStatus = g_io_channel_read_line(myChannel, &myValLine, NULL, NULL,
+                                                NULL)) == G_IO_STATUS_NORMAL) {
+
+      GMatchInfo *keyMatchInfo = NULL;
+      GMatchInfo *valMatchInfo = NULL;
+
+      gchar **myKeys = NULL;
+      gchar **myVals = NULL;
+
+      gchar **myKey = NULL;
+      gchar **myVal = NULL;
+
+      gchar *keyPrefix = NULL;
+      gchar *valPrefix = NULL;
+
+      /*
+       * Per format above, we expect a pair of lines with a matching prefix.
+       */
+      {
+         if (!g_regex_match(myKeyRegex, myKeyLine, 0, &keyMatchInfo) ||
+             !g_regex_match(myValRegex, myValLine, 0, &valMatchInfo)) {
+            parseError = TRUE;
+            goto badIteration;
+         }
+
+         keyPrefix = g_match_info_fetch(keyMatchInfo, 1);
+         valPrefix = g_match_info_fetch(valMatchInfo, 1);
+
+         ASSERT(keyPrefix);
+         ASSERT(valPrefix);
+
+         if (strcmp(keyPrefix, valPrefix)) {
+            parseError = TRUE;
+            goto badIteration;
+         }
+      }
+
+      myKeys = g_strsplit(myKeyLine, " ", 0);
+      myVals = g_strsplit(myValLine, " ", 0);
+
+      /*
+       * Iterate over the columns, combining the column keys with the prefix
+       * to form the new key name.  (I.e., "Ip: InDiscards" => "IpInDiscards".)
+       */
+      for (myKey = &myKeys[1], myVal = &myVals[1];
+           *myKey && *myVal;
+           myKey++, myVal++) {
+         gchar *hashKey;
+         guint64 *myIntVal = NULL;
+
+         hashKey = g_strjoin(NULL, keyPrefix, *myKey, NULL);
+         g_strstrip(hashKey);
+
+         /*
+          * By virtue of having matched the above regex, this conversion
+          * must hold.
+          */
+         myIntVal = g_new(guint64, 1);
+         *myIntVal = g_ascii_strtoull(*myVal, NULL, 10);
+
+         /*
+          * If our input contains duplicate keys, which I really don't see
+          * happening, the latter value overrides the former.
+          *
+          * NB: myHashTable claims ownership of hashKey.
+          */
+         g_hash_table_insert(myHashTable, hashKey, myIntVal);
+      }
+
+      /*
+       * Make sure the column counts matched.  If we succeeded, both pointers
+       * should now be NULL.
+       */
+      if (*myKey || *myVal) {
+         parseError = TRUE;
+      }
+
+badIteration:
+      g_match_info_free(keyMatchInfo);
+      g_match_info_free(valMatchInfo);
+
+      g_free(keyPrefix);
+      g_free(valPrefix);
+
+      g_strfreev(myKeys);
+      g_strfreev(myVals);
+
+      g_free(myKeyLine);
+      g_free(myValLine);
+      myKeyLine = NULL;
+      myValLine = NULL;
+
+      if (parseError) {
+         break;
+      }
+   }
+
+   /*
+    * Error conditions:
+    *    Hash table empty:      Unable to parse any input.
+    *    myKeyLine != NULL:     Failed to read "key" and "value" lines during
+    *                           same loop iteration.
+    *    parseError == TRUE:    See loop body above.
+    */
+   if (keyIoStatus == G_IO_STATUS_ERROR ||
+       valIoStatus == G_IO_STATUS_ERROR ||
+       g_hash_table_size(myHashTable) == 0 ||
+       parseError) {
+      g_hash_table_destroy(myHashTable);
+      myHashTable = NULL;
+   }
+
+   g_free(myKeyLine);
+   g_free(myValLine);
+   myKeyLine = NULL;
+   myValLine = NULL;
+
+   close(fd);
+
+   g_free(myChannel);
+
+   return myHashTable;
+}
+
+
+/*
+ ******************************************************************************
+ * SlashProcNet_GetSnmp6 --                                             */ /**
+ *
+ * @brief Reads @ref pathToNetSnmp6 and returns contents as a
+ *        <tt>GHashTable(gchar *key, guint64 *value)</tt>.
+ *
+ * Example usage:
+ * @code
+ * GHashTable *netSnmp6 = SlashProcNet_GetSnmp6();
+ * guint64 *raw6Discards = g_hash_table_lookup(netSnmp6, "Ip6InDiscards");
+ * @endcode
+ *
+ * @note        Caller should free the returned @c GHashTable with
+ *              @c g_hash_table_destroy.
+ * @note        This routine creates persistent GLib GRegexs.
+ *
+ * @return      On failure, NULL.  On success, a valid @c GHashTable.
+ * @todo        Provide a case-insensitive key comparison function.
+ * @todo        Consider init/cleanup routines to not "leak" GRegexs.
+ *
+ ******************************************************************************
+ */
+
+GHashTable *
+SlashProcNet_GetSnmp6(void)
+{
+   GHashTable *myHashTable = NULL;
+   GIOChannel *myChannel = NULL;
+   GIOStatus ioStatus;
+   gchar *myInputLine = NULL;
+   Bool parseError = FALSE;
+   int fd = -1;
+
+   static GRegex *myRegex = NULL;
+
+   if (myRegex == NULL) {
+      myRegex = g_regex_new("^(\\w+)\\s+(-?\\d+)\\s*$", G_REGEX_OPTIMIZE,
+                            0, NULL);
+      ASSERT(myRegex);
+   }
+
+   if ((fd = g_open(pathToNetSnmp6, O_RDONLY)) == -1) {
+      return NULL;
+   }
+
+   myChannel = g_io_channel_unix_new(fd);
+
+   myHashTable = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+
+   /*
+    * Expected format:
+    *
+    * key1                              value1
+    * key2                              value2
+    * ...
+    * keyN                              valueN
+    */
+
+   while ((ioStatus = g_io_channel_read_line(myChannel, &myInputLine, NULL,
+                                             NULL, NULL)) == G_IO_STATUS_NORMAL) {
+      GMatchInfo *matchInfo = NULL;
+
+      if (g_regex_match(myRegex, myInputLine, 0, &matchInfo)) {
+         gchar *myKey = NULL;
+         gchar *myVal = NULL;
+         guint64 *myIntVal = NULL;
+
+         myKey = g_match_info_fetch(matchInfo, 1);
+         myVal = g_match_info_fetch(matchInfo, 2);
+
+         /*
+          * By virtue of having matched the above regex, this conversion
+          * must hold.
+          */
+         myIntVal = g_new(guint64, 1);
+         *myIntVal = g_ascii_strtoull(myVal, NULL, 10);
+
+         /*
+          * The hash table will take ownership of myKey and myIntVal.  We're
+          * still responsible for myVal.
+          */
+         g_hash_table_insert(myHashTable, myKey, myIntVal);
+         g_free(myVal);
+      } else {
+         parseError = TRUE;
+      }
+
+      g_match_info_free(matchInfo);
+      g_free(myInputLine);
+      myInputLine = NULL;
+
+      if (parseError) {
+         break;
+      }
+   }
+
+   if (ioStatus == G_IO_STATUS_ERROR ||
+       g_hash_table_size(myHashTable) == 0 ||
+       parseError) {
+      g_hash_table_destroy(myHashTable);
+      myHashTable = NULL;
+   }
+
+   close(fd);
+
+   g_free(myChannel);
+
+   return myHashTable;
+}
+
+
+/*
+ ******************************************************************************
+ * SlashProcNet_GetRoute --                                             */ /**
+ *
+ * @brief Reads @ref pathToNetRoute and returns a @c GPtrArray of
+ *        <tt>struct rtentry</tt>s.
+ *
+ * Example usage:
+ * @code
+ * GPtrArray *rtArray;
+ * guint i;
+ * rtArray = SlashProcNet_GetRoute();
+ * for (i = 0; i < rtArray->len; i++) {
+ *    struct rtentry *myRoute = g_ptr_array_index(rtArray, i);
+ *    // Do something with myRoute->rt_dst.
+ * }
+ * SlashProcNet_FreeRoute(rtArray);
+ * @endcode
+ *
+ * @note        Caller is responsible for freeing the @c GPtrArray with
+ *              SlashProcNet_FreeRoute.
+ * @note        This routine creates persistent GLib GRegexs.
+ *
+ * @return      On failure, NULL.  On success, a valid @c GPtrArray.
+ * @todo        Consider init/cleanup routines to not "leak" GRegexs.
+ * @todo        Consider rewriting, integrating with libdnet.
+ *
+ ******************************************************************************
+ */
+
+GPtrArray *
+SlashProcNet_GetRoute(void)
+{
+   GIOChannel *myChannel = NULL;
+   GIOStatus myIoStatus;
+   GPtrArray *myArray = NULL;
+   gchar *myLine = NULL;
+   int fd = -1;
+
+   static GRegex *myFieldsRE = NULL;
+   static GRegex *myValuesRE = NULL;
+
+   if (myFieldsRE == NULL) {
+      myFieldsRE = g_regex_new("^Iface\\s+Destination\\s+Gateway\\s+Flags\\s+"
+                               "RefCnt\\s+Use\\s+Metric\\s+Mask\\s+MTU\\s+"
+                               "Window\\s+IRTT\\s*$", 0, 0, NULL);
+      myValuesRE = g_regex_new("^(\\w+)\\s+([[:xdigit:]]{8})\\s+"
+                               "([[:xdigit:]]{8})\\s+([[:xdigit:]]{4})\\s+"
+                               "\\d+\\s+\\d+\\s+(\\d+)\\s+"
+                               "([[:xdigit:]]{8})\\s+(\\d+)\\s+\\d+\\s+(\\d+)\\s*$",
+                               0, 0, NULL);
+      ASSERT(myFieldsRE);
+      ASSERT(myValuesRE);
+   }
+
+   /*
+    * 1.  Open pathToNetRoute, associate it with a GIOChannel.
+    */
+
+   if ((fd = g_open(pathToNetRoute, O_RDONLY)) == -1) {
+      Warning("%s: open(%s): %s\n", __func__, pathToNetRoute,
+              g_strerror(errno));
+      return NULL;
+   }
+
+   myChannel = g_io_channel_unix_new(fd);
+
+   /*
+    * 2.  Sanity check the header, making sure it matches what we expect.
+    *     (It's -extremely- unlikely this will change, but we should check
+    *     anyway.)
+    */
+
+   myIoStatus = g_io_channel_read_line(myChannel, &myLine, NULL, NULL, NULL);
+   if (myIoStatus != G_IO_STATUS_NORMAL ||
+       g_regex_match(myFieldsRE, myLine, 0, NULL) == FALSE) {
+      goto out;
+   }
+
+   g_free(myLine);
+   myLine = NULL;
+
+   myArray = g_ptr_array_new();
+
+   /*
+    * 3.  For each line...
+    */
+
+   while ((myIoStatus = g_io_channel_read_line(myChannel, &myLine, NULL, NULL,
+                                               NULL)) == G_IO_STATUS_NORMAL) {
+      GMatchInfo *myMatchInfo = NULL;
+      struct rtentry *myEntry = NULL;
+      struct sockaddr_in *sin = NULL;
+      Bool parseError = FALSE;
+
+      /*
+       * 3a. Validate with regex.
+       */
+      if (!g_regex_match(myValuesRE, myLine, 0, &myMatchInfo)) {
+         parseError = TRUE;
+         goto badIteration;
+      }
+
+      /*
+       * 3b. Allocate new rtentry, add to array.  This simplifies the cleanup
+       *     code path.
+       */
+      myEntry = g_new0(struct rtentry, 1);
+      g_ptr_array_add(myArray, myEntry);
+
+      /*
+       * 3c. Copy contents to new struct rtentry.
+       */
+      myEntry->rt_dev = g_match_info_fetch(myMatchInfo, 1);
+
+      sin = (struct sockaddr_in *)&myEntry->rt_dst;
+      sin->sin_family = AF_INET;
+      sin->sin_addr.s_addr = MatchToGuint64(myMatchInfo, 2, 16);
+
+      sin = (struct sockaddr_in *)&myEntry->rt_gateway;
+      sin->sin_family = AF_INET;
+      sin->sin_addr.s_addr = MatchToGuint64(myMatchInfo, 3, 16);
+
+      sin = (struct sockaddr_in *)&myEntry->rt_genmask;
+      sin->sin_family = AF_INET;
+      sin->sin_addr.s_addr = MatchToGuint64(myMatchInfo, 6, 16);
+
+      myEntry->rt_flags = MatchToGuint64(myMatchInfo, 4, 16);
+      myEntry->rt_metric = MatchToGuint64(myMatchInfo, 5, 10);
+      myEntry->rt_mtu = MatchToGuint64(myMatchInfo, 7, 10);
+      myEntry->rt_irtt = MatchToGuint64(myMatchInfo, 8, 10);
+
+badIteration:
+      g_free(myLine);
+      myLine = NULL;
+
+      g_match_info_free(myMatchInfo);
+      myMatchInfo = NULL;
+
+      if (parseError) {
+         break;
+      }
+   }
+
+   if (myArray && myIoStatus != G_IO_STATUS_EOF) {
+      SlashProcNet_FreeRoute(myArray);
+      myArray = NULL;
+   }
+
+out:
+   g_free(myLine);
+   g_free(myChannel);
+
+   close(fd);
+
+   return myArray;
+}
+
+
+/*
+ ******************************************************************************
+ * SlashProcNet_FreeRoute --                                            */ /**
+ *
+ * @brief Frees memory associated with a GPtrArray allocated by
+ *        SlashProcNet_GetRoute.
+ *
+ * @param[in]   routeArray      Array to free.
+ *
+ ******************************************************************************
+ */
+
+void
+SlashProcNet_FreeRoute(GPtrArray *routeArray)
+{
+   int i;
+
+   if (routeArray == NULL) {
+      return;
+   }
+
+   for (i = 0; i < routeArray->len; i++) {
+      struct rtentry *myEntry = g_ptr_array_index(routeArray, i);
+      ASSERT(myEntry->rt_dev);
+      g_free(myEntry->rt_dev);
+      g_free(myEntry);
+   }
+
+   g_ptr_array_free(routeArray, TRUE);
+}
+
+
+/*
+ ******************************************************************************
+ * SlashProcNet_GetRoute6 --                                            */ /**
+ *
+ * @brief Reads @ref pathToNetRoute6 and returns a @c GPtrArray of
+ *        <tt>struct in6_rtmsg</tt>s.
+ *
+ * Example usage:
+ * @code
+ * GPtrArray *rtArray;
+ * guint i;
+ * rtArray = SlashProcNet_GetRoute6();
+ * for (i = 0; i < rtArray->len; i++) {
+ *    struct in6_rtmsg *myRoute = g_ptr_array_index(rtArray, i);
+ *    // Do something with myRoute->rtmsg_dst.
+ * }
+ * SlashProcNet_FreeRoute6(rtArray, TRUE);
+ * @endcode
+ *
+ * @note        Caller is responsible for freeing the @c GPtrArray with
+ *              SlashProcNet_FreeRoute6.
+ * @note        This routine creates persistent GLib GRegexs.
+ *
+ * @return      On failure, NULL.  On success, a valid @c GPtrArray.
+ * @todo        Consider init/cleanup routines to not "leak" GRegexs.
+ * @todo        Consider rewriting, integrating with libdnet.
+ *
+ ******************************************************************************
+ */
+
+GPtrArray *
+SlashProcNet_GetRoute6(void)
+{
+   GIOChannel *myChannel = NULL;
+   GIOStatus myIoStatus;
+   GPtrArray *myArray = NULL;
+   gchar *myLine = NULL;
+   Bool parseError = FALSE;
+   int fd = -1;
+
+   static GRegex *myValuesRE = NULL;
+
+   if (myValuesRE == NULL) {
+      myValuesRE = g_regex_new("^([[:xdigit:]]{32}) ([[:xdigit:]]{2}) "
+                                "([[:xdigit:]]{32}) ([[:xdigit:]]{2}) "
+                                "([[:xdigit:]]{32}) ([[:xdigit:]]{8}) "
+                                "[[:xdigit:]]{8} [[:xdigit:]]{8} "
+                                "([[:xdigit:]]{8})\\s+(\\w+)\\s*$", 0, 0,
+                                NULL);
+      ASSERT(myValuesRE);
+   }
+
+   /*
+    * 1.  Open pathToNetRoute6, associate it with a GIOChannel.
+    */
+
+   if ((fd = g_open(pathToNetRoute6, O_RDONLY)) == -1) {
+      Warning("%s: open(%s): %s\n", __func__, pathToNetRoute,
+              g_strerror(errno));
+      return NULL;
+   }
+
+   myChannel = g_io_channel_unix_new(fd);
+
+   myArray = g_ptr_array_new();
+
+   while ((myIoStatus = g_io_channel_read_line(myChannel, &myLine, NULL, NULL,
+                                               NULL)) == G_IO_STATUS_NORMAL) {
+      struct in6_rtmsg *myEntry = NULL;
+      GMatchInfo *myMatchInfo = NULL;
+
+      if (!g_regex_match(myValuesRE, myLine, 0, &myMatchInfo)) {
+         parseError = TRUE;
+         goto badIteration;
+      }
+
+      myEntry = g_new0(struct in6_rtmsg, 1);
+      g_ptr_array_add(myArray, myEntry);
+
+      MATCHEXPR(myMatchInfo, 1, Ip6StringToIn6Addr(MATCH, &myEntry->rtmsg_dst));
+      MATCHEXPR(myMatchInfo, 3, Ip6StringToIn6Addr(MATCH, &myEntry->rtmsg_src));
+      MATCHEXPR(myMatchInfo, 5, Ip6StringToIn6Addr(MATCH, &myEntry->rtmsg_gateway));
+
+      myEntry->rtmsg_dst_len = MatchToGuint64(myMatchInfo, 2, 16);
+      myEntry->rtmsg_src_len = MatchToGuint64(myMatchInfo, 4, 16);
+      myEntry->rtmsg_metric = MatchToGuint64(myMatchInfo, 6, 16);
+      myEntry->rtmsg_flags = MatchToGuint64(myMatchInfo, 7, 16);
+
+      MATCHEXPR(myMatchInfo, 8, myEntry->rtmsg_ifindex = NetUtil_GetIfIndex(MATCH));
+
+badIteration:
+      g_free(myLine);
+      myLine = NULL;
+
+      g_match_info_free(myMatchInfo);
+      myMatchInfo = NULL;
+
+      if (parseError) {
+         break;
+      }
+   }
+
+   if (myArray && myIoStatus != G_IO_STATUS_EOF) {
+      g_ptr_array_free(myArray, TRUE);
+      myArray = NULL;
+   }
+
+   g_free(myLine);
+   myLine = NULL;
+   g_free(myChannel);
+   myChannel = NULL;
+
+   return myArray;
+}
+
+
+/*
+ ******************************************************************************
+ * SlashProcNet_FreeRoute6 --                                           */ /**
+ *
+ * @brief Frees memory associated with a GPtrArray allocated by
+ *        SlashProcNet_GetRoute6.
+ *
+ * @param[in]   routeArray      Array to free.
+ *
+ ******************************************************************************
+ */
+
+void
+SlashProcNet_FreeRoute6(GPtrArray *routeArray)
+{
+   int i;
+
+   if (routeArray == NULL) {
+      return;
+   }
+
+   for (i = 0; i < routeArray->len; i++) {
+      struct rtentry *myEntry = g_ptr_array_index(routeArray, i);
+      g_free(myEntry);
+   }
+
+   g_ptr_array_free(routeArray, TRUE);
+}
+
+
+/*
+ * Private functions.
+ */
+
+
+/*
+ ******************************************************************************
+ * Ip6StringToIn6Addr --                                                */ /**
+ *
+ * @brief Parses a @c /proc/net/ipv6_route hexadecimal IPv6 address and
+ *        records it in a <tt>struct in6_addr</tt>.
+ *
+ * @param[in]   ip6String       Source string.
+ * @param[out]  in6_addr        Output struct.
+ *
+ ******************************************************************************
+ */
+
+static void
+Ip6StringToIn6Addr(const char *ip6String,
+                   struct in6_addr *in6_addr)
+{
+   unsigned int i;
+
+   ASSERT(strlen(ip6String) == 32);
+
+   for (i = 0; i < 16; i++) {
+      int nmatched;
+      nmatched = sscanf(&ip6String[2 * i], "%2hhx", &in6_addr->s6_addr[i]);
+      ASSERT(nmatched == 1);
+   }
+}
+
+
+/*
+ ******************************************************************************
+ * MatchToGuint64 --                                                    */ /**
+ *
+ * @brief Wrapper around @c g_ascii_strtoull and @c g_match_info_fetch.
+ *
+ * @param[in]   matchInfo       Source regular expression match context.
+ * @param[in]   matchIndex      Match number to fetch.
+ * @param[in]   base            Base represented by matched string.
+ *                              (See @c g_ascii_strtoull docs.)
+ *
+ ******************************************************************************
+ */
+
+static guint64
+MatchToGuint64(const GMatchInfo *matchInfo,
+               const gint matchIndex,
+               gint base)
+{
+   guint64 retval;
+   MATCHEXPR(matchInfo, matchIndex, retval = g_ascii_strtoull(MATCH, NULL, base));
+   return retval;
+}
diff --git a/open-vm-tools/lib/slashProc/slashProcNetInt.h b/open-vm-tools/lib/slashProc/slashProcNetInt.h
new file mode 100644 (file)
index 0000000..eaeada1
--- /dev/null
@@ -0,0 +1,39 @@
+/*********************************************************
+ * Copyright (C) 2009 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.
+ *
+ *********************************************************/
+
+/**
+ * @file netInt.h
+ *
+ *     SlashProcNet internal bits.
+ */
+
+#ifndef _SLASHPROCNETINT_H_
+#define _SLASHPROCNETINT_H_
+
+#define INCLUDE_ALLOW_USERLEVEL
+#include "includeCheck.h"
+
+#ifdef VMX86_DEVEL
+EXTERN void SlashProcNetSetPathSnmp(const char *newPathToNetSnmp);
+EXTERN void SlashProcNetSetPathSnmp6(const char *newPathToNetSnmp6);
+EXTERN void SlashProcNetSetPathRoute(const char *newPathToNetRoute);
+EXTERN void SlashProcNetSetPathRoute6(const char *newPathToNetRoute6);
+#endif // ifdef VMX86_DEVEL
+
+#endif // ifndef _SLASHPROCNETINT_H_
+
index 0297a5aa6d253bf18b602cf06159c18bc31ba235..f0fa844cffa627868ae44836068e52192f6b28ed 100644 (file)
@@ -2227,7 +2227,7 @@ UnityPlatformGetWindowContents(UnityPlatform *up,     // IN
    vmimage.bytesPerLine = ximage->bytes_per_line;
    vmimage.data = ximage->data;
 
-   if (ImageUtil_ConstructPNGBuffer(&vmimage, imageData)) {
+   if (ImageUtil_ConstructPNGBuffer(&vmimage, NULL, imageData)) {
       result = TRUE;
    }
 
index 1a85c35a87c8cb7deeffe163047f293890873e7a..60c2a72fab0843941d214fc1ac3719c767223e6a 100644 (file)
@@ -887,6 +887,12 @@ UnityWindowTracker_SendUpdate(UnityWindowTracker *tracker,        // IN
    case UNITY_UPDATE_CHANGE_ZORDER:
       UnityWindowTracker_SetZOrder(tracker, update->u.zorder.ids,
                                    update->u.zorder.count);
+      /*
+       * This function is only every called from the host. Thus, if we get
+       * a zorder changed event from the guest it's safe to blindly trust it
+       * mark the zorder as changed. See bug 409742 for more info.
+       */
+      tracker->zorderChanged = TRUE;
       break;
 
    case UNITY_UPDATE_CHANGE_WINDOW_STATE:
index f7cfb286ed7ce22aae8eaa093158156724f3d200..7167b0754e86c9900e23c475ad63ee0d7a0c38b7 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "cpuid_info.h"
 #include "hostinfo.h"
+#include "util.h"
 
 #define LOGLEVEL_MODULE hostinfo
 #include "loglevel_user.h"
@@ -253,6 +254,41 @@ Hostinfo_GetCpuid(HostinfoCpuIdInfo *info) // OUT
 }
 
 
+/*
+ *----------------------------------------------------------------------
+ *
+ *  Hostinfo_HypervisorCPUIDSig --
+ *
+ *      Get the hypervisor signature string from CPUID.
+ *
+ * Results:
+ *      Unqualified 16 byte nul-terminated hypervisor string
+ *     String may contain garbage and caller must free
+ *
+ * Side effects:
+ *     None
+ *
+ *----------------------------------------------------------------------
+ */
+
+char * 
+Hostinfo_HypervisorCPUIDSig(void)
+{
+   CPUIDRegs regs;
+   uint32 *name;
+
+   name = Util_SafeMalloc(4 * sizeof *name);
+
+   __GET_CPUID(0x40000000, &regs);
+   name[0] = regs.ebx;
+   name[1] = regs.ecx;
+   name[2] = regs.edx;
+   name[3] = 0;
+
+   return (char *)name;
+}
+
+
 /*
  *----------------------------------------------------------------------
  *
@@ -260,8 +296,9 @@ Hostinfo_GetCpuid(HostinfoCpuIdInfo *info) // OUT
  *
  *      Check for Xen.
  *
- *      Official way is to check CPUID function 0x4000 0000, which
- *         returns a hypervisor string.  See PR156185,
+ *      Official way is to call Hostinfo_HypervisorCPUIDSig(), which
+ *         returns a hypervisor string.  This is a secondary check
+ *        that guards against a backdoor failure.  See PR156185,
  *         http://xenbits.xensource.com/xen-unstable.hg?file/6a383beedf83/tools/misc/xen-detect.c
  *      (Canonical way is /proc/xen, but CPUID is better).
  *
@@ -283,26 +320,12 @@ Hostinfo_GetCpuid(HostinfoCpuIdInfo *info) // OUT
 Bool
 Hostinfo_TouchXen(void)
 {
+#ifdef linux
 #define XEN_CPUID 0x40000000
 #define XEN_STRING "XenVMMXenVMM"
    CPUIDRegs regs;
    uint32 name[4];
 
-   /* 
-    * HVM mode: simple cpuid instr 
-    * Xen hypervisor traps CPUID and adds information leaf(s)
-    * at CPUID leaf XEN_CPUID and higher.
-    */
-   __GET_CPUID(XEN_CPUID, &regs);
-   name[0] = regs.ebx;
-   name[1] = regs.ecx;
-   name[2] = regs.edx;
-   name[3] = 0;
-   if (0 == strcmp(XEN_STRING, (const char*)name)) {
-      return TRUE;
-   }
-
-#ifdef linux
    /* 
     * PV mode: ud2a "xen" cpuid (faults on native hardware).
     * (Only Linux can run PV, so skip others here).
index 42d9d9753cc346e2e1e9b5011c6cdeb522bca5bd..328703e081325db13c1efbc873f93f0cffbd2b64 100644 (file)
@@ -177,7 +177,7 @@ Util_Init(void)
  */
 
 uint32
-Util_Checksum32(uint32 *buf, int len)
+Util_Checksum32(const uint32 *buf, int len)
 {
    uint32 checksum = 0;
    int i;
@@ -200,7 +200,7 @@ Util_Checksum32(uint32 *buf, int len)
  */
 
 uint32
-Util_Checksum(uint8 *buf, int len)
+Util_Checksum(const uint8 *buf, int len)
 {
    uint32 checksum;
    int remainder, shift;
@@ -655,20 +655,34 @@ Util_BacktraceToBuffer(uintptr_t *basePtr,
 Bool
 Util_Data2Buffer(char *buf,         // OUT
                  size_t bufSize,    // IN
-                 const voiddata0, // IN
+                 const void *data0, // IN
                  size_t dataSize)   // IN
 {
-   char* cp = buf;
-   const uint8* data = (const uint8*) data0;
-   size_t n = MIN(dataSize, ((bufSize-1) / 3));
-
-   while (n > 0) {
-      Str_Sprintf(cp, 4, " %02X", *data);
-      cp += 3;
-      data++, n--;
+   size_t n;
+
+   /* At least 1 byte (for NUL) must be available. */
+   if (!bufSize) {
+      return FALSE;
+   }
+
+   bufSize = bufSize / 3;
+   n = MIN(dataSize, bufSize);
+   if (n != 0) {
+      const uint8 *data = data0;
+
+      while (n > 0) {
+         static const char digits[] = "0123456789ABCDEF";
+
+         *buf++ = digits[*data >> 4];
+         *buf++ = digits[*data & 0xF];
+         *buf++ = ' ';
+         data++;
+         n--;
+      }
+      buf--;
    }
-   *cp = '\0';
-   return (dataSize <= bufSize);
+   *buf = 0;
+   return dataSize <= bufSize;
 }
 
 
index 828fc7012b690c6f16eb29e9a05b534a12404c94..a87039331cf528b1c358aa3eea89cb28f2794b9b 100644 (file)
@@ -125,14 +125,18 @@ Util_BumpNoFds(uint32 *cur,     // OUT
    int err;
 
    /*
-    * Check for minimum file descriptor limit. The number 2048 is
+    * Check for minimum file descriptor limit. The number is
     * somewhat arbitrary. Trying to do multiple snapshots of a split
     * disk can rapidly consume descriptors however, so we ought to
     * have a large number. This is only pushing back the problem of
     * course. Ideally we'd have a fully scalable solution.
     */
 
+#if __APPLE__
+   static const rlim_t fdsDesired = 8192;
+#else
    static const rlim_t fdsDesired = 2048;
+#endif
 
    err = getrlimit(RLIMIT_NOFILE, &lim);
    ASSERT_NOT_IMPLEMENTED(err >= 0);
index 3c3cfcedd6db2bdb90ebc16528713c2ad381b5c3..174ab59156588eb04014e2551ddbc7d682918ca0 100644 (file)
@@ -95,6 +95,7 @@
 #include "registryWin32.h"
 #include "win32u.h"
 #endif /* _WIN32 */
+#include "hgfsHelper.h"
 
 #ifdef linux
 #include "mntinfo.h"
@@ -227,6 +228,8 @@ static VixError VixToolsSetGuestNetworkingConfig(VixCommandRequestHeader *reques
 
 static VixError VixTools_Base64EncodeBuffer(char **resultValuePtr, size_t *resultValLengthPtr);
 
+static VixError VixToolsSetSharedFoldersProperties(VixPropertyListImpl *propList);
+
 #if defined(_WIN32)
 static HRESULT VixToolsEnableDHCPOnPrimary(void);
 
@@ -953,6 +956,9 @@ VixTools_GetToolsPropertiesImpl(GuestApp_Dict **confDictRef,      // IN
       goto abort;
    }
 
+   /* Retrieve the share folders UNC root path. */
+   err = VixToolsSetSharedFoldersProperties(&propList);
+
    /*
     * Serialize the property list to buffer then encode it.
     * This is the string we return to the VMX process.
@@ -981,6 +987,9 @@ abort:
 
    VixPropertyList_Initialize(&propList);
 
+   /* Retrieve the share folders UNC root path. */
+   err = VixToolsSetSharedFoldersProperties(&propList);
+
    /*
     * Serialize the property list to buffer then encode it.
     * This is the string we return to the VMX process.
@@ -1005,6 +1014,52 @@ abort:
 } // VixTools_GetToolsPropertiesImpl
 
 
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VixToolsSetSharedFoldersProperties --
+ *
+ *    Set information about the shared folders feature.
+ *
+ * Return value:
+ *    VixError
+ *
+ * Side effects:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static VixError
+VixToolsSetSharedFoldersProperties(VixPropertyListImpl *propList)    // IN
+{
+   VixError err = VIX_OK;
+
+   /* Retrieve the share folders UNC root path. */
+   Unicode hgfsRootPath = NULL;
+
+   if (!HgfsHlpr_QuerySharesDefaultRootPath(&hgfsRootPath)) {
+      /* Exit ok as we have nothing to set from shared folders. */
+      goto exit;
+   }
+
+   ASSERT(hgfsRootPath != NULL);
+
+   err = VixPropertyList_SetString(propList,
+                                   VIX_PROPERTY_GUEST_SHAREDFOLDERS_SHARES_PATH,
+                                   UTF8(hgfsRootPath));
+   if (VIX_OK != err) {
+      goto exit;
+   }
+
+exit:
+   if (hgfsRootPath != NULL) {
+      HgfsHlpr_FreeSharesRootPath(hgfsRootPath);
+   }
+   return err;
+}
+
+
 #if 0
 /*
  *-----------------------------------------------------------------------------
@@ -3653,23 +3708,116 @@ VixToolsDoesUsernameMatchCurrentUser(const char *username)  // IN
 #ifdef _WIN32
    char *currentUser = NULL;
    DWORD currentUserSize = 0;
-   
+   DWORD retVal = 0;
+   HANDLE processToken = INVALID_HANDLE_VALUE;
+   PTOKEN_USER processTokenInfo = NULL;
+   DWORD processTokenInfoSize = 0;
+   Unicode sidUserName = NULL;
+   DWORD sidUserNameSize = 0;
+   Unicode sidDomainName = NULL;
+   DWORD sidDomainNameSize = 0;
+   SID_NAME_USE sidNameUse;
+
    /*
-    * For Windows, get the name of the owner of this process, then
-    * compare it to the provided username.
+    * Check to see if the user provided a '<Domain>\<User>' formatted username
     */
-   if (!Win32U_GetUserName(currentUser, &currentUserSize)) {
+   if (NULL != Str_Strchr(username, '\\')) {
+      /*
+       * A '<Domain>\<User>' formatted username was provided.
+       * We must retrieve the domain as well as the username to verify
+       * the current vixtools user matches the username provided
+       */
+      retVal = OpenProcessToken(GetCurrentProcess(),
+                                TOKEN_READ,
+                                &processToken);
+
+      if (!retVal || !processToken) {
+         Warning("unable to open process token: windows error code %d\n",
+                 GetLastError());
+         err = FoundryToolsDaemon_TranslateSystemErr();
+
+         goto abort;
+      }
+
+      // Determine necessary buffer size
+      GetTokenInformation(processToken,
+                          TokenUser,
+                          NULL,
+                          0,
+                          &processTokenInfoSize);
+
       if (ERROR_INSUFFICIENT_BUFFER != GetLastError()) {
+         Warning("unable to get token info: windows error code %d\n",
+                 GetLastError());
          err = FoundryToolsDaemon_TranslateSystemErr();
          goto abort;
       }
 
-      currentUser = Util_SafeMalloc(currentUserSize);
+      processTokenInfo = Util_SafeMalloc(processTokenInfoSize);
 
-      if (!Win32U_GetUserName(currentUser, &currentUserSize)) {
+      if (!GetTokenInformation(processToken,
+                               TokenUser,
+                               processTokenInfo,
+                               processTokenInfoSize,
+                               &processTokenInfoSize)) {
+         Warning("unable to get token info: windows error code %d\n",
+                 GetLastError());
+         err = FoundryToolsDaemon_TranslateSystemErr();
+         goto abort;
+      }
+
+      // Retrieve user name and domain name based on user's SID.
+      Win32U_LookupAccountSid(NULL,
+                              processTokenInfo->User.Sid,
+                              NULL,
+                              &sidUserNameSize,
+                              NULL,
+                              &sidDomainNameSize,
+                              &sidNameUse);
+
+      if (ERROR_INSUFFICIENT_BUFFER != GetLastError()) {
+         Warning("unable to lookup account sid: windows error code %d\n",
+                 GetLastError());
          err = FoundryToolsDaemon_TranslateSystemErr();
          goto abort;
       }
+
+      sidUserName = Util_SafeMalloc(sidUserNameSize);
+      sidDomainName = Util_SafeMalloc(sidDomainNameSize);
+
+      if (!Win32U_LookupAccountSid(NULL,
+                                   processTokenInfo->User.Sid,
+                                   sidUserName,
+                                   &sidUserNameSize,
+                                   sidDomainName,
+                                   &sidDomainNameSize,
+                                   &sidNameUse)) {
+         Warning("unable to lookup account sid: windows error code %d\n",
+                 GetLastError());
+         err = FoundryToolsDaemon_TranslateSystemErr();
+         goto abort;
+     }
+
+      // Populate currentUser with Domain + '\' + Username
+      currentUser = Str_SafeAsprintf(NULL, "%s\\%s", sidDomainName, sidUserName);
+   } else {
+      /*
+       * For Windows, get the name of the owner of this process, then
+       * compare it to the provided username.
+       */
+      if (!Win32U_GetUserName(currentUser, &currentUserSize)) {
+         if (ERROR_INSUFFICIENT_BUFFER != GetLastError()) {
+            err = FoundryToolsDaemon_TranslateSystemErr();
+            goto abort;
+         }
+
+         currentUser = Util_SafeMalloc(currentUserSize);
+
+         if (!Win32U_GetUserName(currentUser, &currentUserSize)) {
+            err = FoundryToolsDaemon_TranslateSystemErr();
+            goto abort;
+         }
+      }
    }
 
    if (0 != Unicode_CompareIgnoreCase(username, currentUser)) {
@@ -3680,6 +3828,10 @@ VixToolsDoesUsernameMatchCurrentUser(const char *username)  // IN
    err = VIX_OK;
 
 abort:
+   free(sidDomainName);
+   free(sidUserName);
+   free(processTokenInfo);
+   CloseHandle(processToken);
    free(currentUser);
 
 #else /* Below is the POSIX case. */
index a17f35f077248b258031066c7381b4a1f456f1c1..762e2eb7c2eb590ab8453273001d6efe3db0c84d 100644 (file)
@@ -18,4 +18,5 @@
 noinst_LTLIBRARIES = libWiper.la
 
 libWiper_la_SOURCES =
+libWiper_la_SOURCES += wiperCommon.c
 libWiper_la_SOURCES += wiperPosix.c
diff --git a/open-vm-tools/lib/wiper/wiperCommon.c b/open-vm-tools/lib/wiper/wiperCommon.c
new file mode 100644 (file)
index 0000000..90b0ea8
--- /dev/null
@@ -0,0 +1,122 @@
+/*********************************************************
+ * Copyright (C) 2009 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.
+ *
+ *********************************************************/
+
+/*
+ * wiperCommon.c --
+ *
+ *      OS-agnostic parts of the library for wiping a virtual disk.
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "dbllnklst.h"
+#include "wiper.h"
+#include "util.h"
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * WiperSinglePartition_Allocate --
+ *
+ *      Allocates and initialized empty WiperPartition structure.
+ *
+ * Results:
+ *      NULL if there is no memory, otherwise a pointer to newly allocated
+ *      WiperPartition structure.
+ *
+ * Side Effects:
+ *      Allocates memory.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+WiperPartition *
+WiperSinglePartition_Allocate(void)
+{
+   WiperPartition *p = (WiperPartition *) malloc(sizeof *p);
+
+   if (p != NULL) {
+      memset(p->mountPoint, 0, sizeof p->mountPoint);
+      p->type = PARTITION_UNSUPPORTED;
+      p->comment = NULL;
+      DblLnkLst_Init(&p->link);
+   }
+
+   return p;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * WiperSinglePartition_Close --
+ *
+ *      Destroy the information returned by a previous call to
+ *      WiperSinglePartition_Allocate(). The partition should be removed
+ *      from all lists prior to calling WiperSinglePartition_Close().
+ *
+ * Results:
+ *      None.
+ *
+ * Side Effects:
+ *      Frees memory occupied by the element.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+WiperSinglePartition_Close(WiperPartition *p)      // IN
+{
+   if (p) {
+      free((char *)p->comment); /* Casting away constness */
+      free(p);
+   }
+}
+
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * WiperPartition_Close --
+ *
+ *      Destroy the information collected by previous call to
+ *      WiperPartition_Open().
+ *
+ * Results:
+ *      None
+ *
+ * Side Effects:
+ *      Frees memory occupied by elements of the list.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+void
+WiperPartition_Close(WiperPartition_List *pl)      // IN/OUT
+{
+   DblLnkLst_Links *curr, *next;
+
+   DblLnkLst_ForEachSafe(curr, next, &pl->link) {
+      WiperPartition *part = DblLnkLst_Container(curr, WiperPartition, link);
+
+      DblLnkLst_Unlink1(curr);
+      WiperSinglePartition_Close(part);
+   }
+}
+
index 32393255f68fc2ae1eb57beef4de8b7ba8632228..add12c9d158b22f00f92c83ee5ac16caacd50697 100644 (file)
@@ -50,6 +50,7 @@
 #include "vmstdio.h"
 #include "mntinfo.h"
 #include "posix.h"
+#include "util.h"
 
 
 /* Number of bytes per disk sector */
@@ -370,6 +371,9 @@ WiperPartitionFilter(WiperPartition *item,         // IN/OUT
                      MNTINFO *mnt)                 // IN
 {
    struct stat s;
+   const char *comment = NULL;
+
+   item->type = PARTITION_UNSUPPORTED;
 
    /*
     * Let's ignore remote filesystems before we do a stat(2) on the actual
@@ -378,137 +382,76 @@ WiperPartitionFilter(WiperPartition *item,         // IN/OUT
     */
    if (strcmp(MNTINFO_FSTYPE(mnt), "autofs") == 0) {
       /* XXX Should we look at autofs' config files? --hpreg */
-      item->comment = "Not implemented. Contact VMware";
-      return;
-   }
+      comment = "Not implemented. Contact VMware";
 
-   if (strcmp(MNTINFO_FSTYPE(mnt), "vmhgfs") == 0) {
-      item->comment = "Remote partition";
-      return;
-   }
+   } else if (strcmp(MNTINFO_FSTYPE(mnt), "vmhgfs") == 0) {
+      comment = "Remote partition";
 
-   if (strcmp(MNTINFO_FSTYPE(mnt), "nfs") == 0) {
-      item->comment = "Remote filesystem";
-      return;
-   }
+   } if (strcmp(MNTINFO_FSTYPE(mnt), "nfs") == 0) {
+      comment = "Remote filesystem";
 
-   if (strcmp(MNTINFO_FSTYPE(mnt), "smbfs") == 0) {
-      item->comment = "Remote filesystem";
-      return;
-   }
+   } if (strcmp(MNTINFO_FSTYPE(mnt), "smbfs") == 0) {
+      comment = "Remote filesystem";
 
-   if (strcmp(MNTINFO_FSTYPE(mnt), "swap") == 0) {
-      item->comment = "Swap partition";
-      return;
-   }
+   } if (strcmp(MNTINFO_FSTYPE(mnt), "swap") == 0) {
+      comment = "Swap partition";
 
-   if (strcmp(MNTINFO_FSTYPE(mnt), PROCFS) == 0) {
-      item->comment = "Proc partition";
-      return;
-   }
+   } if (strcmp(MNTINFO_FSTYPE(mnt), PROCFS) == 0) {
+      comment = "Proc partition";
 
-   if (strcmp(MNTINFO_FSTYPE(mnt), "devpts") == 0) {
-      item->comment = "Devpts partition";
-      return;
-   }
+   } if (strcmp(MNTINFO_FSTYPE(mnt), "devpts") == 0) {
+      comment = "Devpts partition";
 
-   if (Posix_Stat(MNTINFO_NAME(mnt), &s) < 0) {
-      item->comment = "Unknown device";
-      return;
-   }
+   } if (Posix_Stat(MNTINFO_NAME(mnt), &s) < 0) {
+      comment = "Unknown device";
 
 #if defined(sun) || defined(__linux__)
-   if (! S_ISBLK(s.st_mode)) {
-      item->comment = "Not a block device";
-      return;
-   }
+   } else if (! S_ISBLK(s.st_mode)) {
+      comment = "Not a block device";
 #endif
 
-   if (!WiperIsDiskDevice(mnt, &s)) {
-      item->comment = "Not a disk device";
-      return;
-   }
+   } else if (!WiperIsDiskDevice(mnt, &s)) {
+      comment = "Not a disk device";
 
-   if (MNTINFO_MNT_IS_RO(mnt)) {
-      item->comment = "Not writable";
-      return;
-   }
+   } if (MNTINFO_MNT_IS_RO(mnt)) {
+      comment = "Not writable";
 
-   if (strcmp(MNTINFO_FSTYPE(mnt), "ext2") == 0) {
-      item->comment = "";
+   } if (strcmp(MNTINFO_FSTYPE(mnt), "ext2") == 0) {
       item->type = PARTITION_EXT2;
-      return;
-   }
 
-   if (strcmp(MNTINFO_FSTYPE(mnt), "ext3") == 0) {
-      item->comment = "";
+   } if (strcmp(MNTINFO_FSTYPE(mnt), "ext3") == 0) {
       item->type = PARTITION_EXT3;
-      return;
-   }
 
-   if (strcmp(MNTINFO_FSTYPE(mnt), "reiserfs") == 0) {
-      item->comment = "";
+   } if (strcmp(MNTINFO_FSTYPE(mnt), "reiserfs") == 0) {
       item->type = PARTITION_REISERFS;
-      return;
-   }
 
-   if (strcmp(MNTINFO_FSTYPE(mnt), "ntfs") == 0) {
-      item->comment = "";
+   } if (strcmp(MNTINFO_FSTYPE(mnt), "ntfs") == 0) {
       item->type = PARTITION_NTFS;
-      return;
-   }
 
-   if (strcmp(MNTINFO_FSTYPE(mnt), "vfat") == 0) {
-      item->comment = "";
+   } if (strcmp(MNTINFO_FSTYPE(mnt), "vfat") == 0) {
       item->type = PARTITION_FAT;
-      return;
-   }
 
-   if (strcmp(MNTINFO_FSTYPE(mnt), "ufs") == 0) {
-      item->comment = "";
+   } if (strcmp(MNTINFO_FSTYPE(mnt), "ufs") == 0) {
       item->type = PARTITION_UFS;
-      return;
-   }
 
-   if (strcmp(MNTINFO_FSTYPE(mnt), "pcfs") == 0) {
-      item->comment = "";
+   } if (strcmp(MNTINFO_FSTYPE(mnt), "pcfs") == 0) {
       item->type = PARTITION_PCFS;
-      return;
-   }
 
-   item->comment = "Unknown filesystem. Contact VMware";
-   return;
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * SingleWiperPartition_Close --
- *
- *      Destroy the information returned by a previous call to
- *      SingleWiperPartition_Open().
- *
- * Results:
- *      None
- *
- * Side Effects:
- *      None
- *
- *-----------------------------------------------------------------------------
- */
+   } else {
+      comment = "Unknown filesystem. Contact VMware";
+   }
 
-void
-SingleWiperPartition_Close(WiperPartition *p)      // IN
-{
-   free(p);
+   if (item->type == PARTITION_UNSUPPORTED) {
+      ASSERT(comment);
+      item->comment = Util_SafeStrdup(comment);
+   }
 }
 
 
 /*
  *-----------------------------------------------------------------------------
  *
- * SingleWiperPartition_Open --
+ * WiperSinglePartition_Open --
  *
  *      Return information about the input 'mountPoint' partition.
  *
@@ -523,26 +466,20 @@ SingleWiperPartition_Close(WiperPartition *p)      // IN
  */
 
 WiperPartition *
-SingleWiperPartition_Open(const char *mountPoint)      // IN
+WiperSinglePartition_Open(const char *mountPoint)      // IN
 {
    char *mntpt = NULL;
    MNTHANDLE fp;
    int len = 0;
    DECLARE_MNTINFO(mnt);
-   WiperPartition *p;
+   WiperPartition *p = NULL;
 
    ASSERT(initDone);
-   fp = NULL;
-   p = (WiperPartition *) malloc(sizeof *p);
-   if (p == NULL) {
-      Log("Not enough memory while opening a partition.\n");
-      goto error;
-   }
 
    fp = OPEN_MNTFILE("r");
    if (fp == NULL) {
       Log("Could not open %s\n", MNTFILE);
-      goto error;
+      return NULL;
    }
 
    mntpt = Util_SafeStrdup(mountPoint);
@@ -560,33 +497,30 @@ SingleWiperPartition_Open(const char *mountPoint)      // IN
    len = strlen(mntpt);
    while (GETNEXT_MNTINFO(fp, mnt)) {
       if (strncmp(MNTINFO_MNTPT(mnt), mntpt, len) == 0) {
-         if (Str_Snprintf(p->mountPoint, NATIVE_MAX_PATH,
-                          "%s", MNTINFO_MNTPT(mnt)) == -1) {
+
+         p = WiperSinglePartition_Allocate();
+         if (p == NULL) {
+            Log("Not enough memory while opening a partition.\n");
+         } else if (Str_Snprintf(p->mountPoint, NATIVE_MAX_PATH,
+                                 "%s", MNTINFO_MNTPT(mnt)) == -1) {
             Log("NATIVE_MAX_PATH is too small.\n");
-            goto error;
+            WiperSinglePartition_Close(p);
+            p = NULL;
+         } else {
+            WiperCollectDiskMajors();
+            WiperPartitionFilter(p, mnt);
          }
 
-         WiperCollectDiskMajors();
-         WiperPartitionFilter(p, mnt);
-         (void) CLOSE_MNTFILE(fp);
-
-         fp = NULL;
-
-         free(mntpt);
-         return p;
+         goto out;
       }
    }
 
    Log("Could not find a mount point for %s in %s\n", mntpt, MNTFILE);
 
-  error:
-   SingleWiperPartition_Close(p);
-   if (fp != NULL) {
-      (void) CLOSE_MNTFILE(fp);
-      fp = NULL;
-   }
+ out:
    free(mntpt);
-   return NULL;
+   (void) CLOSE_MNTFILE(fp);
+   return p;
 }
 
 /*
@@ -661,104 +595,55 @@ WiperSinglePartition_GetSpace(const WiperPartition *p,  // IN
  *-----------------------------------------------------------------------------
  */
 
-WiperPartition_List *
-WiperPartition_Open(void)
+Bool
+WiperPartition_Open(WiperPartition_List *pl)
 {
-   WiperPartition_List *pl;
    MNTHANDLE fp;
    DECLARE_MNTINFO(mnt);
+   Bool rc = TRUE;
 
    ASSERT(initDone);
-   fp = NULL;
 
-   pl = (WiperPartition_List *)malloc(sizeof *pl);
-   if (pl == NULL) {
-      Log("Not enough memory while opening a partition.\n");
-      goto error;
-   }
-
-   pl->partitions = NULL;
-   pl->size = 0;
+   DblLnkLst_Init(&pl->link);
 
    /* Basically call functions to parse /etc/mtab ... */
    fp = OPEN_MNTFILE("r");
    if (fp == NULL) {
       Log("Unable to open mount file.\n");
-      goto error;
+      return FALSE;
    }
 
    WiperCollectDiskMajors();
 
    while (GETNEXT_MNTINFO(fp, mnt)) {
-      WiperPartition item;
-
-      if (Str_Snprintf(item.mountPoint, NATIVE_MAX_PATH, "%s",
-                       MNTINFO_MNTPT(mnt)) == -1) {
-              Log("NATIVE_MAX_PATH is too small.\n");
-              goto error;
-      }
-
-      WiperPartitionFilter(&item, mnt);
+      WiperPartition *part = WiperSinglePartition_Allocate();
 
-      /* Add the partition to the list */
-      pl->partitions = (WiperPartition *)realloc(pl->partitions,
-                                                 (pl->size + 1) *
-                                                 sizeof *pl->partitions);
-      if (pl->partitions == NULL) {
+      if (part == NULL) {
          Log("Not enough memory while opening a partition.\n");
-              goto error;
+         rc = FALSE;
+         break;
       }
 
-      pl->partitions[pl->size] = item;
-      pl->size++;
-   }
-
-   (void) CLOSE_MNTFILE(fp);
-   fp = NULL;
-
-   return pl;
+      if (Str_Snprintf(part->mountPoint, NATIVE_MAX_PATH, "%s",
+                       MNTINFO_MNTPT(mnt)) == -1) {
+         Log("NATIVE_MAX_PATH is too small.\n");
+         WiperSinglePartition_Close(part);
+         rc = FALSE;
+         break;
+      }
 
-error:
-   WiperPartition_Close(pl);
-   pl = NULL;
-   if (fp != NULL) {
-      (void) CLOSE_MNTFILE(fp);
-      fp = NULL;
+      WiperPartitionFilter(part, mnt);
+      DblLnkLst_LinkLast(&pl->link, &part->link);
    }
-   return NULL;
-}
 
+   if (!rc)
+      WiperPartition_Close(pl);
 
-/*
- *-----------------------------------------------------------------------------
- *
- * WiperPartition_Close --
- *
- *      Destroy the information returned by a previous call to
- *      WiperPartition_Open()
- *
- * Results:
- *      None
- *
- * Side Effects:
- *      None
- *
- *-----------------------------------------------------------------------------
- */
-
-void
-WiperPartition_Close(WiperPartition_List *pl)      // IN/OUT
-{
-   if (pl != NULL) {
-      free(pl->partitions);
-      pl->partitions = NULL;
-      free(pl);
-   }
+   (void) CLOSE_MNTFILE(fp);
+   return rc;
 }
 
 
-
-
 /*
  *-----------------------------------------------------------------------------
  *
index c3d5c733403ae58e1c8aa63248f657d973764e11..7ad86a6a290bbacad2314a7d48f8a111f89913b8 100644 (file)
@@ -50,6 +50,10 @@ libvmtools_la_LIBADD += @LIBVMTOOLS_LIBADD@
 libvmtools_la_LIBADD += @GLIB2_LIBS@
 libvmtools_la_LIBADD += @ICU_LIBS@
 
+if LINUX
+libvmtools_la_LIBADD += ../lib/slashProc/libSlashProc.la
+endif
+
 libvmtools_la_SOURCES =
 libvmtools_la_SOURCES += signalSource.c
 libvmtools_la_SOURCES += vmtools.c
index b5f20b121d563c1541ddc9493592155cad914cda..a35b1dcab5239e2b3e015ccf27aac08a69bcf3b0 100644 (file)
@@ -27,6 +27,7 @@
  *    used for reliable event delivery.
  */
 
+#include "vm_assert.h"
 #include "vmtools.h"
 #include <errno.h>
 #include <fcntl.h>
@@ -82,7 +83,7 @@ SignalSourceReadSigInfo(void)
          return;
       } else {
          /* XXX: Maybe we should handle this in some other way? */
-         g_assert(nbytes == sizeof info);
+         ASSERT(nbytes == sizeof info);
       }
       memcpy(&gHandler.currSignal, &info, sizeof info);
       gHandler.signals[info.si_signo] = SIG_SRC_SIGNALED;
@@ -133,7 +134,7 @@ SignalSourceSigHandler(int signum,
           * have to be created...
           */
          g_warning("Too many signals queued, this shouldn't happen.\n");
-         g_assert(FALSE);
+         ASSERT(FALSE);
       } else {
          g_warning("Could not queue signal %d (error %d: %s)\n",
                    signum, errno, strerror(errno));
@@ -264,8 +265,8 @@ VMTools_NewSignalSource(int signum)
    };
    SignalSource *ret;
 
-   g_assert(signum < MAX_SIGNALS);
-   g_assert(signum != SIGKILL && signum != SIGSTOP);
+   ASSERT(signum < MAX_SIGNALS);
+   ASSERT(signum != SIGKILL && signum != SIGSTOP);
 
    G_LOCK(gLock);
    if (!gHandler.initialized) {
@@ -273,7 +274,7 @@ VMTools_NewSignalSource(int signum)
       if (pipe(gHandler.wakeupPipe) == -1 ||
           fcntl(gHandler.wakeupPipe[0], F_SETFL, O_RDONLY | O_NONBLOCK) < 0 ||
           fcntl(gHandler.wakeupPipe[1], F_SETFL, O_WRONLY | O_NONBLOCK) < 0) {
-         g_assert(FALSE);
+         ASSERT(FALSE);
       }
       gHandler.wakeupFd.fd = gHandler.wakeupPipe[0];
       gHandler.wakeupFd.events = G_IO_IN | G_IO_ERR;
index e5eaf31e3674b68f4c66faeba52272350f8400b3..fde18b76ff4c418439f6064111cf0e31aadd3249 100644 (file)
@@ -43,8 +43,6 @@
 VM_EMBED_VERSION(VMTOOLSLIB_VERSION_STRING);
 #endif
 
-extern void VMTools_ResetLogging(gboolean cleanDefault);
-
 
 /**
  * A convenience function for wrapping an array with a GArray instance.
@@ -91,9 +89,9 @@ VMToolsDllInit(void *lib)
    VMTools_ResetLogging(FALSE);
    wiperData.resourceModule = lib;
    success = (NetUtil_LoadIpHlpApiDll() == ERROR_SUCCESS);
-   g_assert(success);
+   ASSERT(success);
    success = Wiper_Init(&wiperData);
-   g_assert(success);
+   ASSERT(success);
 #else
    VMTools_ResetLogging(FALSE);
    success = Wiper_Init(NULL);
index f41408f900121d12601ebf1df5a7c51e15a8df94..944ee9d7d911a162a07b10139a7d4caf3863c383 100644 (file)
@@ -72,6 +72,9 @@ VMToolsConfigUpgradeLog(GKeyFile *cfg,
     * and vmware-user. Instead of baking in the library whether we're
     * running one or the other, separate the two configurations, so that
     * the user can choose a different location for one or another.
+    *
+    * Also append the PID to the vmusr log path, since the old code did
+    * that automatically.
     */
    gchar *userlog;
 
@@ -82,7 +85,7 @@ VMToolsConfigUpgradeLog(GKeyFile *cfg,
    g_key_file_set_string(cfg, entry->destGroup,
                          VMTOOLS_GUEST_SERVICE ".data", value);
 
-   userlog = g_strdup_printf("%s.user", value);
+   userlog = g_strdup_printf("%s.user.${PID}", value);
    g_key_file_set_string(cfg, entry->destGroup,
                          VMTOOLS_USER_SERVICE ".handler", "file");
    g_key_file_set_string(cfg, entry->destGroup,
@@ -90,6 +93,12 @@ VMToolsConfigUpgradeLog(GKeyFile *cfg,
    g_key_file_set_string(cfg, entry->destGroup,
                          VMTOOLS_USER_SERVICE ".data", userlog);
 
+   /*
+    * Keep the log.file entry since vmware-user is still using the old-style
+    * config. This can go away once it's ported over.
+    */
+   g_key_file_set_string(cfg, entry->destGroup, CONFNAME_LOGFILE, value);
+
    g_free(userlog);
 }
 
@@ -131,10 +140,11 @@ VMToolsConfigUpgrade(GuestApp_Dict *old,
    for (entry = entries; entry->key != NULL; entry++) {
       const char *value = GuestApp_GetDictEntry(old, entry->key);
       const char *dfltValue = GuestApp_GetDictEntryDefault(old, entry->key);
-      
+
       if (value == NULL || (dfltValue != NULL && strcmp(value, dfltValue) == 0)) {
          continue;
       }
+
       switch (entry->type) {
       case CFG_BOOLEAN:
          {
@@ -153,26 +163,16 @@ VMToolsConfigUpgrade(GuestApp_Dict *old,
          }
 
       case CFG_STRING:
-         {
-            const char *val = GuestApp_GetDictEntry(old, entry->key);
-            if (val != NULL) {
-               g_key_file_set_string(dst, entry->destGroup, entry->destKey, val);
-            }
-            break;
-         }
+         g_key_file_set_string(dst, entry->destGroup, entry->destKey, value);
+         break;
 
       case CFG_CALLBACK:
-         {
-            const char *val = GuestApp_GetDictEntry(old, entry->key);
-            if (val != NULL) {
-               g_assert(entry->data);
-               ((CfgCallback)entry->data)(dst, entry, val);
-            }
-            break;
-         }
+         ASSERT(entry->data);
+         ((CfgCallback)entry->data)(dst, entry, value);
+         break;
 
       default:
-         g_assert_not_reached();
+         NOT_REACHED();
       }
    }
 }
@@ -200,7 +200,7 @@ VMTools_GetToolsConfFile(void)
     */
    if (confPath == NULL) {
       confPath = GuestApp_GetConfPath();
-      g_assert(confPath != NULL);
+      ASSERT(confPath != NULL);
    }
    confFilePath = g_strdup_printf("%s%c%s", confPath, DIRSEPC, CONF_FILE);
    free(confPath);
@@ -327,11 +327,11 @@ VMTools_ReloadConfig(const gchar *path,
    gboolean ret = FALSE;
    GKeyFile *newConfig = NULL;
 
-   g_assert(config != NULL);
-   g_assert(mtime != NULL);
+   ASSERT(config != NULL);
+   ASSERT(mtime != NULL);
 
    if (g_stat(path, &confStat) == -1) {
-      g_warning("Failed to stat conf file: %s\n", strerror(errno));
+      g_debug("Failed to stat conf file: %s\n", strerror(errno));
       goto exit;
    }
 
@@ -394,8 +394,8 @@ VMTools_WriteConfig(const gchar *path,
    FILE *out = NULL;
    GError *lerr = NULL;
 
-   g_assert(path != NULL);
-   g_assert(config != NULL);
+   ASSERT(path != NULL);
+   ASSERT(config != NULL);
 
    localPath = VMTOOLS_GET_FILENAME_LOCAL(path, &lerr);
    if (lerr != NULL) {
index 759002fb383431b919d4ec5b184cc1bed77764ac..cf6ff05447344f97c099038d855b58aaec6e2844 100644 (file)
@@ -96,13 +96,12 @@ VMToolsLogOutputDebugString(const gchar *domain,
                             gpointer _data);
 #endif
 
-void VMTools_ResetLogging(gboolean cleanDefault);
-
 typedef struct LogHandlerData {
    gchar            *domain;
    GLogLevelFlags    mask;
    FILE             *file;
    gchar            *path;
+   gboolean          append;
    guint             handlerId;
    gboolean          inherited;
 } LogHandlerData;
@@ -122,12 +121,15 @@ static GPtrArray *gDomains = NULL;
  * present. Only one old log file is preserved.
  *
  * @param[in] path   Path to log file.
+ * @param[in] append Whether to open the log for appending (if TRUE, a backup
+ *                   file is not generated).
  *
  * @return File pointer for writing to the file (NULL on error).
  */
 
 static FILE *
-VMToolsLogOpenFile(const gchar *path)
+VMToolsLogOpenFile(const gchar *path,
+                   gboolean append)
 {
    FILE *logfile = NULL;
    gchar *pathLocal;
@@ -135,7 +137,7 @@ VMToolsLogOpenFile(const gchar *path)
    ASSERT(path != NULL);
    pathLocal = VMTOOLS_GET_FILENAME_LOCAL(path, NULL);
 
-   if (g_file_test(path, G_FILE_TEST_EXISTS)) {
+   if (!append && g_file_test(path, G_FILE_TEST_EXISTS)) {
       /* Back up existing log file. */
       gchar *bakFile = g_strdup_printf("%s.old", pathLocal);
       if (!g_file_test(bakFile, G_FILE_TEST_IS_DIR) &&
@@ -146,7 +148,7 @@ VMToolsLogOpenFile(const gchar *path)
       g_free(bakFile);
    }
 
-   logfile = g_fopen(pathLocal, "w");
+   logfile = g_fopen(pathLocal, append ? "a" : "w");
    VMTOOLS_RELEASE_FILENAME_LOCAL(pathLocal);
    return logfile;
 }
@@ -317,7 +319,7 @@ VMToolsLogFile(const gchar *domain,
          FILE *dest;
          data = data->inherited ? gDefaultData : data;
          if (data->file == NULL && data->path != NULL) {
-            data->file = VMToolsLogOpenFile(data->path);
+            data->file = VMToolsLogOpenFile(data->path, data->append);
             if (data->file == NULL) {
                g_warning("Unable to open log file %s for domain %s.\n",
                          data->domain, data->path);
@@ -396,7 +398,8 @@ VMToolsConfigLogDomain(const gchar *domain,
       }
    } else if (strcmp(handler, "std") == 0) {
       handlerFn = VMToolsLogFile;
-   } else if (strcmp(handler, "file") == 0) {
+   } else if (strcmp(handler, "file") == 0 ||
+              strcmp(handler, "file+") == 0) {
       /* Don't set up the file sink if logging is disabled. */
       if (strcmp(level, "none") != 0) {
          handlerFn = VMToolsLogFile;
@@ -482,17 +485,33 @@ VMToolsConfigLogDomain(const gchar *domain,
    data->domain = g_strdup(domain);
    data->mask = levelsMask;
    data->path = logpath;
+   data->append = (handler != NULL && strcmp(handler, "file+") == 0);
    logpath = NULL;
 
    if (strcmp(domain, VMTools_GetDefaultLogDomain()) == 0) {
-      /* Replace the default log configuration before freeing the old data. */
+      /*
+       * Replace the global log configuration. If the default log domain was
+       * logging to a file and the file path hasn't changed, then keep the old
+       * file handle open, instead of rotating the log.
+       */
       LogHandlerData *old = gDefaultData;
-      LogHandlerData *gdata = g_malloc0(sizeof *gdata);
 
-      memcpy(gdata, data, sizeof *gdata);
-      g_log_set_default_handler(handlerFn, gdata);
+      if (old->file != NULL) {
+         ASSERT(old->path);
+         if (data->path != NULL && strcmp(data->path, old->path) == 0) {
+            g_free(data->path);
+            data->file = old->file;
+            data->path = old->path;
+            old->path = NULL;
+         } else {
+            fclose(old->file);
+            g_free(old->path);
+         }
+      }
 
-      gDefaultData = gdata;
+      g_log_set_default_handler(handlerFn, data);
+      gDefaultData = data;
+      data = NULL;
       gDefaultLogFunc = handlerFn;
       g_free(old);
    } else if (handler == NULL) {
@@ -500,12 +519,14 @@ VMToolsConfigLogDomain(const gchar *domain,
       data->inherited = TRUE;
    }
 
-   if (gDomains == NULL) {
-      gDomains = g_ptr_array_new();
+   if (data != NULL) {
+      if (gDomains == NULL) {
+         gDomains = g_ptr_array_new();
+      }
+      g_ptr_array_add(gDomains, data);
+      data->handlerId = g_log_set_handler(domain, ALL_LOG_LEVELS | G_LOG_FATAL_MASK,
+                                          handlerFn, data);
    }
-   g_ptr_array_add(gDomains, data);
-   data->handlerId = g_log_set_handler(domain, ALL_LOG_LEVELS | G_LOG_FATAL_MASK,
-                                       handlerFn, data);
 
 exit:
    g_free(handler);
@@ -539,7 +560,7 @@ VMTools_GetDefaultLogDomain(void)
 void
 VMTools_SetDefaultLogDomain(const gchar *domain)
 {
-   g_assert(domain != NULL);
+   ASSERT(domain != NULL);
    if (gLogDomain != NULL) {
       g_free(gLogDomain);
    }
@@ -630,6 +651,8 @@ void
 VMTools_ResetLogging(gboolean cleanDefault)
 {
    gboolean oldLogEnabled = gLogEnabled;
+   gchar *currentPath = NULL;
+   FILE *currentFile = NULL;
 
    /* Disable logging while we're playing with the configuration. */
    gLogEnabled = FALSE;
@@ -655,6 +678,8 @@ VMTools_ResetLogging(gboolean cleanDefault)
    }
 
    if (gDefaultData != NULL) {
+      currentFile = gDefaultData->file;
+      currentPath = gDefaultData->path;
       g_free(gDefaultData);
       gDefaultData = NULL;
    }
@@ -677,8 +702,15 @@ VMTools_ResetLogging(gboolean cleanDefault)
 #if defined(VMX86_DEBUG)
       gDefaultData->mask |= G_LOG_LEVEL_MESSAGE;
 #endif
+      gDefaultData->file = currentFile;
+      gDefaultData->path = currentPath;
       gLogEnabled = oldLogEnabled;
       g_log_set_default_handler(gDefaultLogFunc, gDefaultData);
+   } else {
+      if (currentFile != NULL) {
+         fclose(currentFile);
+      }
+      g_free(currentPath);
    }
 }
 
index abce26be4e3b50a53f3a1a208e8a46fbdd3cb3fc..4bbb5d2ef8334473d5f021851b658e1dc302cef2 100644 (file)
@@ -49,6 +49,8 @@
 
 #include <sys/param.h>
 #include "compat_vop.h"
+#include "compat_mount.h"
+#include "compat_priv.h"
 
 /*
  * FreeBSD version 8 and above uses the kproc API instead of the kthread API in its
diff --git a/open-vm-tools/modules/freebsd/shared/compat_mount.h b/open-vm-tools/modules/freebsd/shared/compat_mount.h
new file mode 100644 (file)
index 0000000..5a823da
--- /dev/null
@@ -0,0 +1,58 @@
+/*********************************************************
+ * Copyright (C) 2009 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
+ *
+ *********************************************************/
+
+/*********************************************************
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of VMware Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission of VMware Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *********************************************************/
+
+#ifndef __COMPAT_MOUNT_H__
+#   define __COMPAT_MOUNT_H__ 1
+
+#if __FreeBSD_version >= 800011
+#define COMPAT_VFS_STATFS(mp, sbp, threadvar) VFS_STATFS((mp), (sbp))
+#define compat_td curthread
+#else
+#define COMPAT_VFS_STATFS(mp, sbp, threadvar) VFS_STATFS((mp), (sbp), (threadvar))
+#define compat_td td
+#endif
+
+#endif
diff --git a/open-vm-tools/modules/freebsd/shared/compat_priv.h b/open-vm-tools/modules/freebsd/shared/compat_priv.h
new file mode 100644 (file)
index 0000000..14ebfeb
--- /dev/null
@@ -0,0 +1,56 @@
+/*********************************************************
+ * Copyright (C) 2009 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
+ *
+ *********************************************************/
+
+/*********************************************************
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of VMware Inc. nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission of VMware Inc.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *********************************************************/
+
+#ifndef __COMPAT_PRIV_H__
+#   define __COMPAT_PRIV_H__ 1
+
+#if __FreeBSD_version >= 800011
+#define compat_priv_check(td, priv) priv_check((td), (priv))
+#else
+#define compat_priv_check(td, priv) suser(td)
+#endif
+
+#endif
index d37440112e173fc06af5a3ce1e002b9d32ced32e..43ecc69d58a6f3bd1ef2c7da94e21f613c8f2607 100644 (file)
@@ -54,6 +54,8 @@
 #define compat_lockstatus(lock, threadvar) lockstatus((lock))
 #define compat_lockmgr(lock, flags, randompointerparam, threadval) lockmgr((lock), (flags), (randompointerparam))
 #define compat_vn_lock(vp, flags, threadval) vn_lock((vp), (flags))
+#define compat_accmode_t accmode_t
+#define compat_a_accmode a_accmode
 #else
 #define COMPAT_THREAD_VAR(varname, varval) struct thread *varname = varval
 #define COMPAT_VOP_LOCK(vop, flags, threadvar) VOP_LOCK((vop), (flags), (threadvar))
@@ -61,6 +63,8 @@
 #define compat_lockstatus(lock, threadvar) lockstatus((lock), (threadvar))
 #define compat_vn_lock(vp, flags, threadval) vn_lock((vp), (flags), (threadval))
 #define compat_lockmgr(lock, flags, randompointerparam, threadval) lockmgr((lock), (flags), (randompointerparam), (threadval))
+#define compat_accmode_t mode_t
+#define compat_a_accmode a_mode
 #endif
 
 /*
index 31166281e997c09301200fde472095aae775b043..23c6fc50ab7e68b4366d6c8d4e01aac4b3424064 100644 (file)
@@ -56,6 +56,8 @@
 #include <sys/vnode.h>
 #include <sys/file.h>
 
+#include "compat_freebsd.h"
+
 #include "vmblock_k.h"
 #include "block.h"
 
@@ -181,11 +183,9 @@ static struct vnode *
 VMBlockHashGet(struct mount *mp,        // IN: vmblock file system information
                struct vnode *lowervp)   // IN: lower vnode to search for
 {
-   struct thread *td = curthread;   /* XXX */
    struct nodeHashHead *hd;
    struct VMBlockNode *a;
    struct vnode *vp;
-   int error;
 
    ASSERT_VOP_LOCKED(lowervp, "hashEntryget");
 
@@ -199,23 +199,14 @@ VMBlockHashGet(struct mount *mp,        // IN: vmblock file system information
    mtx_lock(&hashMutex);
    LIST_FOREACH(a, hd, hashEntry) {
       if (a->lowerVnode == lowervp && VMBTOVP(a)->v_mount == mp) {
-         vp = VMBTOVP(a);
-         VI_LOCK(vp);
-         mtx_unlock(&hashMutex);
-         /*
-          * We need to clear the OWEINACT flag here as this may lead vget()
-          * to try to lock our vnode which is already locked via lowervp.
-          */
-         vp->v_iflag &= ~VI_OWEINACT;
-         error = vget(vp, LK_INTERLOCK, td);
          /*
           * Since we have the lower node locked the nullfs node can not be
           * in the process of recycling.  If it had been recycled before we
           * grabed the lower lock it would not have been found on the hash.
           */
-         if (error) {
-            panic("hashEntryget: vget error %d", error);
-         }
+         vp = VMBTOVP(a);
+         vref(vp);
+         mtx_unlock(&hashMutex);
          return vp;
       }
    }
@@ -246,11 +237,9 @@ static struct vnode *
 VMBlockHashInsert(struct mount *mp,             // IN: VMBlock file system info
                   struct VMBlockNode *xp)       // IN: node to insert into hash
 {
-   struct thread *td = curthread;   /* XXX */
    struct nodeHashHead *hd;
    struct VMBlockNode *oxp;
    struct vnode *ovp;
-   int error;
 
    hd = VMBLOCK_NHASH(xp->lowerVnode);
    mtx_lock(&hashMutex);
@@ -261,13 +250,8 @@ VMBlockHashInsert(struct mount *mp,             // IN: VMBlock file system info
           * operation.
           */
          ovp = VMBTOVP(oxp);
-         VI_LOCK(ovp);
+         vref(ovp);
          mtx_unlock(&hashMutex);
-         ovp->v_iflag &= ~VI_OWEINACT;
-         error = vget(ovp, LK_INTERLOCK, td);
-         if (error) {
-            panic("hashEntryins: vget error %d", error);
-         }
          return ovp;
       }
    }
@@ -326,9 +310,9 @@ VMBlockInsMntQueDtr(struct vnode *vp, // IN: node to cleanup
 {
    vp->v_data = NULL;
    vp->v_vnlock = &vp->v_lock;
-   FREE(xp, M_VMBLOCKFSNODE);
+   free(xp, M_VMBLOCKFSNODE);
    vp->v_op = &dead_vnodeops;
-   (void) vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curthread);
+   (void) compat_vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curthread);
    vgone(vp);
    vput(vp);
 }
@@ -617,13 +601,6 @@ VMBlockDestroyBlockName(char *blockName)        // IN: name to free
 
 #ifdef DIAGNOSTIC                               /* if (DIAGNOSTIC) { */
 
-#ifdef KDB                                      /* if (KDB) { */
-# define        VMBlockCheckVp_barrier 1
-#else
-# define        VMBlockCheckVp_barrier 0
-#endif                                          /* }    */
-
-
 /*
  *-----------------------------------------------------------------------------
  *
@@ -659,7 +636,6 @@ VMBlockCheckVp(vp, fil, lno)
     */
    if (vp->v_op != null_vnodeop_p) {
       printf ("VMBlockCheckVp: on non-null-node\n");
-      while (VMBlockCheckVp_barrier) /*WAIT*/ ;
       panic("VMBlockCheckVp");
    };
 #endif
@@ -671,8 +647,6 @@ VMBlockCheckVp(vp, fil, lno)
          printf(" %lx", p[i]);
       }
       printf("\n");
-      /* wait for debugger */
-      while (VMBlockCheckVp_barrier) /*WAIT*/ ;
       panic("VMBlockCheckVp");
    }
    if (vrefcnt(a->lowerVnode) < 1) {
@@ -682,8 +656,6 @@ VMBlockCheckVp(vp, fil, lno)
          printf(" %lx", p[i]);
       }
       printf("\n");
-      /* wait for debugger */
-      while (VMBlockCheckVp_barrier) /*WAIT*/ ;
       panic ("null with unref'ed lowervp");
    };
 #ifdef notyet
index 37bcaf1332d43f3555cf6ed87cd2bb0516628e4b..a430b6193d1c5bc47ac531ca88749d731b78a74d 100644 (file)
@@ -113,8 +113,12 @@ VFS_SET(VMBlockVFSOps, vmblock, VFCF_LOOPBACK);
  */
 
 static int
-VMBlockVFSMount(struct mount *mp,       // IN: mount(2) parameters
-                struct thread *td)      // IN: caller's kernel thread context
+#if __FreeBSD_version >= 800011
+VMBlockVFSMount(struct mount *mp)        // IN: mount(2) parameters
+#else
+VMBlockVFSMount(struct mount *mp,        // IN: mount(2) parameters
+                struct thread *td)       // IN: caller's thread context
+#endif
 {
    struct VMBlockMount *xmp;
    struct nameidata nd, *ndp = &nd;
@@ -158,7 +162,8 @@ VMBlockVFSMount(struct mount *mp,       // IN: mount(2) parameters
    /*
     * Find lower node and lock if not already locked.
     */
-   NDINIT(ndp, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, target, td);
+
+   NDINIT(ndp, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, target, compat_td);
    error = namei(ndp);
    if (error) {
       NDFREE(ndp, 0);
@@ -189,7 +194,7 @@ VMBlockVFSMount(struct mount *mp,       // IN: mount(2) parameters
     * Make sure the node alias worked
     */
    if (error) {
-      COMPAT_VOP_UNLOCK(vp, 0, td);
+      COMPAT_VOP_UNLOCK(vp, 0, compat_td);
       vrele(lowerrootvp);
       free(xmp, M_VMBLOCKFSMNT);   /* XXX */
       return error;
@@ -211,7 +216,7 @@ VMBlockVFSMount(struct mount *mp,       // IN: mount(2) parameters
    /*
     * Unlock the node (either the lower or the alias)
     */
-   COMPAT_VOP_UNLOCK(vp, 0, td);
+   COMPAT_VOP_UNLOCK(vp, 0, compat_td);
 
    /*
     * If the staging area is a local filesystem, reflect that here, too.  (We
@@ -253,9 +258,14 @@ VMBlockVFSMount(struct mount *mp,       // IN: mount(2) parameters
  */
 
 static int
-VMBlockVFSUnmount(struct mount *mp,     // IN: filesystem to unmount
-                  int mntflags,         // IN: unmount(2) flags (ex: MNT_FORCE)
-                  struct thread *td)    // IN: caller's kernel thread context
+#if __FreeBSD_version >= 800011
+VMBlockVFSUnmount(struct mount *mp,    // IN: filesystem to unmount
+                  int mntflags)        // IN: unmount(2) flags (ex: MNT_FORCE)
+#else
+VMBlockVFSUnmount(struct mount *mp,    // IN: filesystem to unmount
+                  int mntflags,        // IN: unmount(2) flags (ex: MNT_FORCE)
+                  struct thread *td)   // IN: caller's kernel thread context
+#endif
 {
    struct VMBlockMount *xmp;
    struct vnode *vp;
@@ -290,21 +300,21 @@ VMBlockVFSUnmount(struct mount *mp,     // IN: filesystem to unmount
     * transfer will happen atomically.  (Er, at least within the scope of
     * the vnode subsystem.)
     */
-   COMPAT_VOP_LOCK(vp, LK_EXCLUSIVE|LK_RETRY|LK_INTERLOCK, td);
+   COMPAT_VOP_LOCK(vp, LK_EXCLUSIVE|LK_RETRY|LK_INTERLOCK, compat_td);
 
    removed = BlockRemoveAllBlocks(OS_UNKNOWN_BLOCKER);
 
    VI_LOCK(vp);
    vp->v_usecount -= removed;
    VI_UNLOCK(vp);
-   COMPAT_VOP_UNLOCK(vp, 0, td);
+   COMPAT_VOP_UNLOCK(vp, 0, compat_td);
 
    if (mntflags & MNT_FORCE) {
       flags |= FORCECLOSE;
    }
 
    /* There is 1 extra root vnode reference (xmp->rootVnode). */
-   error = vflush(mp, 1, flags, td);
+   error = vflush(mp, 1, flags, compat_td);
    if (error) {
       return error;
    }
@@ -336,10 +346,16 @@ VMBlockVFSUnmount(struct mount *mp,     // IN: filesystem to unmount
  */
 
 static int
+#if __FreeBSD_version >= 800011
+VMBlockVFSRoot(struct mount *mp,        // IN: vmblock file system
+               int flags,               // IN: lockmgr(9) flags
+               struct vnode **vpp)      // OUT: root vnode
+#else
 VMBlockVFSRoot(struct mount *mp,        // IN: vmblock file system
                int flags,               // IN: lockmgr(9) flags
                struct vnode **vpp,      // OUT: root vnode
                struct thread *td)       // IN: caller's thread context
+#endif
 {
    struct vnode *vp;
 
@@ -348,7 +364,7 @@ VMBlockVFSRoot(struct mount *mp,        // IN: vmblock file system
     */
    vp = MNTTOVMBLOCKMNT(mp)->rootVnode;
    VREF(vp);
-   compat_vn_lock(vp, flags | LK_RETRY, td);
+   compat_vn_lock(vp, flags | LK_RETRY, compat_td);
    *vpp = vp;
    return 0;
 }
@@ -373,9 +389,14 @@ VMBlockVFSRoot(struct mount *mp,        // IN: vmblock file system
  */
 
 static int
+#if __FreeBSD_version >= 800011
+VMBlockVFSStatFS(struct mount *mp,      // IN: vmblock file system
+                 struct statfs *sbp)    // OUT: statfs(2) arg container
+#else
 VMBlockVFSStatFS(struct mount *mp,      // IN: vmblock file system
                  struct statfs *sbp,    // OUT: statfs(2) arg container
                  struct thread *td)     // IN: caller's thread context
+#endif
 {
    int error;
    struct statfs mstat;
@@ -386,7 +407,7 @@ VMBlockVFSStatFS(struct mount *mp,      // IN: vmblock file system
 
    bzero(&mstat, sizeof mstat);
 
-   error = VFS_STATFS(MNTTOVMBLOCKMNT(mp)->mountVFS, &mstat, td);
+   error = COMPAT_VFS_STATFS(MNTTOVMBLOCKMNT(mp)->mountVFS, &mstat, compat_td);
    if (error) {
       return error;
    }
@@ -423,9 +444,14 @@ VMBlockVFSStatFS(struct mount *mp,      // IN: vmblock file system
  */
 
 static int
+#if __FreeBSD_version >= 800011
+VMBlockVFSSync(struct mount *mp,        // Ignored
+               int waitfor)             // Ignored
+#else
 VMBlockVFSSync(struct mount *mp,        // Ignored
                int waitfor,             // Ignored
                struct thread *td)       // Ignored
+#endif
 {
    return 0;
 }
index 3fc69c611baf34da24d7d8d466c8d4e52f199c89..c9241e15c614367cf223f54665977678541084f2 100644 (file)
@@ -751,8 +751,11 @@ struct vop_open_args {
        *
        * NB:  Allowing only the superuser to open this directory breaks
        *      readdir() of the filesystem root for non-privileged users.
+       *
+       * Also, on FreeBSD 8.0 and newer we check for a specific module priv
+       * because none of the existing privs seemed to match very well.
        */
-      if ((retval = suser(ap->a_td)) == 0) {
+      if ((retval = compat_priv_check(ap->a_td, PRIV_DRIVER)) == 0) {
 #if __FreeBSD_version >= 700055
          fp = ap->a_fp;
 #else
@@ -1036,7 +1039,7 @@ struct vop_access_args {
 */
 {
    struct vnode *vp = ap->a_vp;
-   mode_t mode = ap->a_mode;
+   compat_accmode_t mode = ap->compat_a_accmode;
 
    /*
     * Disallow write attempts on read-only layers; unless the file is a
index af1da72ce466c664c018b8ef672c7aa64ebaa529..b99761d87d0171ab2d7e40cdd5a912efd4f865b2 100644 (file)
  *
  *********************************************************/
 
-/* 
+/*
  * os.c --
  *
- *     Wrappers for FreeBSD system functions required by "vmmemctl".
- *     This allows customers to build their own vmmemctl driver for
- *     custom FreeBSD kernels without the need for source code.
+ *      Wrappers for FreeBSD system functions required by "vmmemctl".
  */
 
 /*
@@ -73,14 +71,14 @@ typedef struct {
    volatile int stop;
 
    /* registered state */
-   os_timer_handler handler;
+   OSTimerHandler *handler;
    void *data;
    int period;
 } os_timer;
 
 typedef struct {
    /* registered state */
-   os_status_handler handler;
+   OSStatusHandler *handler;
    const char *name_verbose;
    const char *name;
 } os_status;
@@ -109,26 +107,99 @@ static os_state global_state;
 static void vmmemctl_init_sysctl(void);
 static void vmmemctl_deinit_sysctl(void);
 
+
 /*
- * Simple Wrappers
+ *-----------------------------------------------------------------------------
+ *
+ * OS_Malloc --
+ *
+ *      Allocates kernel memory.
+ *
+ * Results:
+ *      On success: Pointer to allocated memory
+ *      On failure: NULL
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
  */
 
-void *os_kmalloc_nosleep(unsigned int size)
+void *
+OS_Malloc(size_t size) // IN
 {
    return(malloc(size, M_VMMEMCTL, M_NOWAIT));
 }
 
-void os_kfree(void *obj, unsigned int size)
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_Free --
+ *
+ *      Free allocated kernel memory.
+ *
+ * Results:
+ *      None
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+OS_Free(void *ptr,   // IN
+        size_t size) // IN
 {
-   free(obj, M_VMMEMCTL);
+   free(ptr, M_VMMEMCTL);
 }
 
-void os_bzero(void *b, unsigned int len)
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_MemZero --
+ *
+ *      Fill a memory location with 0s.
+ *
+ * Results:
+ *      None
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+OS_MemZero(void *ptr,   // OUT
+           size_t size) // IN
 {
-   bzero(b, len);
+   bzero(ptr, size);
 }
 
-void os_memcpy(void *dest, const void *src, unsigned int size)
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_MemCopy --
+ *
+ *      Copy a memory portion into another location.
+ *
+ * Results:
+ *      None
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+OS_MemCopy(void *dest,      // OUT
+           const void *src, // IN
+           size_t size)     // IN
 {
    memcpy(dest, src, size);
 }
@@ -148,18 +219,45 @@ static __inline__ unsigned long os_ffz(unsigned long word)
    return word;
 }
 
-int os_sprintf(char *str, const char *format, ...)
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_Snprintf --
+ *
+ *      Print a string into a bounded memory location.
+ *
+ * Results:
+ *      Number of character printed including trailing \0.
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+OS_Snprintf(char *buf,          // OUT
+            size_t size,        // IN
+            const char *format, // IN
+            ...)                // IN
 {
+   int result;
    va_list args;
+
    va_start(args, format);
-   return(vsprintf(str, format, args));
+   result = vsnprintf(buf, size, format, args);
+   va_end(args);
+
+   return result;
 }
 
 /*
  * System-Dependent Operations
  */
 
-char *os_identity(void)
+const char *
+OS_Identity(void)
 {
    return("bsd");
 }
@@ -169,12 +267,14 @@ char *os_identity(void)
  *
  * Currently we just return the total memory pages.
  */
-unsigned int os_predict_max_balloon_pages(void)
+unsigned int
+OS_PredictMaxReservedPages(void)
 {
    return(cnt.v_page_count);
 }
 
-unsigned long os_addr_to_ppn(unsigned long addr)
+unsigned long
+OS_AddrToPPN(unsigned long addr)
 {
    return (((vm_page_t)addr)->phys_addr) >> PAGE_SHIFT;
 }
@@ -308,16 +408,18 @@ static void os_balloonobject_delete(void)
 
 static void os_balloonobject_create(void)
 {
-   global_state.vmobject = vm_object_allocate(OBJT_DEFAULT, 
+   global_state.vmobject = vm_object_allocate(OBJT_DEFAULT,
                   OFF_TO_IDX(VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS));
 }
 
-unsigned long os_alloc_reserved_page(int can_sleep)
+unsigned long
+OS_AllocReservedPage(int canSleep)
 {
-   return (unsigned long)os_kmem_alloc(can_sleep);
+   return (unsigned long)os_kmem_alloc(canSleep);
 }
 
-void os_free_reserved_page(unsigned long page)
+void
+OS_FreeReservedPage(unsigned long page)
 {
    os_kmem_free((vm_page_t)page);
 }
@@ -333,18 +435,22 @@ static void os_timer_internal(void *data)
    }
 }
 
-void os_timer_init(os_timer_handler handler, void *data, int period)
+void
+OS_TimerInit(OSTimerHandler *handler, // IN
+             void *clientData,        // IN
+             int period)              // IN
 {
    os_timer *t = &global_state.timer;
 
    callout_handle_init(&t->callout_handle);
    t->handler = handler;
-   t->data = data;
+   t->data = clientData;
    t->period = period;
    t->stop = 0;
 }
 
-void os_timer_start(void)
+void
+OS_TimerStart(void)
 {
    os_timer *t = &global_state.timer;
 
@@ -355,7 +461,8 @@ void os_timer_start(void)
    t->callout_handle = timeout(os_timer_internal, t, t->period);
 }
 
-void os_timer_stop(void)
+void
+OS_TimerStop(void)
 {
    os_timer *t = &global_state.timer;
 
@@ -366,19 +473,39 @@ void os_timer_stop(void)
    untimeout(os_timer_internal, t, t->callout_handle);
 }
 
-unsigned int os_timer_hz(void)
+unsigned int
+OS_TimerHz(void)
 {
    return hz;
 }
 
-void os_yield(void)
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_Yield --
+ *
+ *      Yield the CPU, if needed.
+ *
+ * Results:
+ *      None
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+OS_Yield(void)
 {
    /* Do nothing. */
 }
 
-void os_init(const char *name,
-             const char *name_verbose,
-             os_status_handler handler)
+void
+OS_Init(const char *name,
+        const char *name_verbose,
+        OSStatusHandler *handler)
 {
    os_state *state = &global_state;
    os_pmap *pmap = &state->pmap;
@@ -409,7 +536,8 @@ void os_init(const char *name,
    printf("%s initialized\n", state->status.name_verbose);
 }
 
-void os_cleanup(void)
+void
+OS_Cleanup(void)
 {
    os_state *state = &global_state;
    os_pmap *pmap = &state->pmap;
@@ -485,7 +613,7 @@ vmmemctl_sysctl(SYSCTL_HANDLER_ARGS)
    char stats[PAGE_SIZE];
    size_t len;
 
-   len = 1 + global_state.status.handler(stats);
+   len = 1 + global_state.status.handler(stats, PAGE_SIZE);
 
    return SYSCTL_OUT(req, stats, len);
 }
index 8a5f690e6b32f51c1435815ae5691e3c060dde01..b991edd7162768ce2ea1ed068a3fae4b46fc7054 100644 (file)
  *
  *********************************************************/
 
-/* 
+/*
  * os.h --
  *
- *     Definitions for OS-specific wrapper functions required
- *     by "vmmemctl".  This allows customers to build their own
- *     vmmemctl driver for custom versioned kernels without the
- *     need for source code. 
+ *      Definitions for OS-specific wrapper functions required by "vmmemctl".
  */
 
 #ifndef        OS_H
 #define        OS_H
 
-/*
- * Needs fixing for 64bit OSes
- */
-#ifndef __x86_64__
-#define CDECL __attribute__((cdecl, regparm(0)))
-#else
-#define CDECL
-#endif
-
 /*
  * Types
  */
 
-typedef void CDECL (*os_timer_handler)(void *);
-typedef int  CDECL (*os_status_handler)(char *);
+typedef void OSTimerHandler(void *clientData);
+typedef int  OSStatusHandler(char *buf, size_t size);
 
 /*
  * Operations
  */
 
-extern void CDECL *os_kmalloc_nosleep(unsigned int size);
-extern void CDECL os_kfree(void *obj, unsigned int size);
-extern void CDECL os_yield(void);
-extern void CDECL os_bzero(void *s, unsigned int n);
-extern void CDECL os_memcpy(void *dest, const void *src, unsigned int size);
-extern int  CDECL os_sprintf(char *str, const char *format, ...);
-
-extern unsigned long CDECL os_addr_to_ppn(unsigned long addr);
-extern unsigned long CDECL os_alloc_reserved_page(int can_sleep);
-extern void          CDECL os_free_reserved_page(unsigned long page);
+extern void OS_Init(const char *name,
+                    const char *nameVerbose,
+                    OSStatusHandler *handler);
+extern void OS_Cleanup(void);
+extern const char *OS_Identity(void);
 
-extern void CDECL os_timer_init(os_timer_handler handler, void *data, int period);
-extern void CDECL os_timer_start(void);
-extern void CDECL os_timer_stop(void);
+extern void OS_MemZero(void *ptr, size_t size);
+extern void OS_MemCopy(void *dest, const void *src, size_t size);
+extern int  OS_Snprintf(char *buf, size_t size, const char *format, ...);
 
-extern void CDECL os_init(const char *name,
-                          const char *name_verbose,
-                          os_status_handler handler);
-extern void CDECL os_cleanup(void);
+extern void *OS_Malloc(size_t size);
+extern void OS_Free(void *ptr, size_t size);
 
-extern char CDECL *os_identity(void);
+extern void OS_Yield(void);
 
-extern unsigned int CDECL os_predict_max_balloon_pages(void);
+extern unsigned int OS_TimerHz(void);
+extern void OS_TimerInit(OSTimerHandler *handler, void *clientData, int period);
+extern void OS_TimerStart(void);
+extern void OS_TimerStop(void);
 
-extern unsigned int CDECL os_timer_hz(void);
+extern unsigned int  OS_PredictMaxReservedPages(void);
+extern unsigned long OS_AddrToPPN(unsigned long addr);
+extern unsigned long OS_AllocReservedPage(int canSleep);
+extern void          OS_FreeReservedPage(unsigned long page);
 
 #endif  /* OS_H */
index a88eea718b20884969db59c8d749287eb4798a3e..91212ec8fa036ccb365a6f85b8e463be8a9da713 100644 (file)
  *
  *********************************************************/
 
-/* 
+/*
  * vmballoon.c --
  *
- *     VMware server physical memory management driver for Unix-ish
- *     (Linux, FreeBSD, Solaris) guests.  The driver acts like a
- *     "balloon" that can be inflated to reclaim physical pages by
- *     reserving them in the guest and invalidating them in the
- *     monitor, freeing up the underlying machine pages so they can
- *     be allocated to other guests.  The balloon can also be
- *     deflated to allow the guest to use more physical memory.
- *     Higher level policies can control the sizes of balloons in VMs
- *     in order to manage physical memory resources.
+ *      VMware physical memory management driver for Unix-ish
+ *      (Linux, FreeBSD, Solaris, Mac OS) guests. The driver acts like
+ *      a "balloon" that can be inflated to reclaim physical pages by
+ *      reserving them in the guest and invalidating them in the
+ *      monitor, freeing up the underlying machine pages so they can
+ *      be allocated to other guests.  The balloon can also be
+ *      deflated to allow the guest to use more physical memory.
+ *      Higher level policies can control the sizes of balloons in VMs
+ *      in order to manage physical memory resources.
  */
 
 #ifdef __cplusplus
@@ -38,12 +38,12 @@ extern "C" {
  * Compile-Time Options
  */
 
-#define        BALLOON_RATE_ADAPT      (1)
+#define BALLOON_RATE_ADAPT      (1)
 
-#define        BALLOON_DEBUG           (1)
-#define        BALLOON_DEBUG_VERBOSE   (0)
+#define BALLOON_DEBUG           (1)
+#define BALLOON_DEBUG_VERBOSE   (0)
 
-#define        BALLOON_STATS
+#define BALLOON_STATS
 #define BALLOON_STATS_PROCFS
 
 /*
@@ -65,38 +65,38 @@ extern "C" {
 #define NULL 0
 #endif
 
-#define        BALLOON_NAME                    "vmmemctl"
-#define        BALLOON_NAME_VERBOSE            "VMware memory control driver"
+#define BALLOON_NAME                    "vmmemctl"
+#define BALLOON_NAME_VERBOSE            "VMware memory control driver"
 
-#define        BALLOON_PROTOCOL_VERSION        (2)
+#define BALLOON_PROTOCOL_VERSION        (2)
 
-#define        BALLOON_CHUNK_PAGES             (1000)
+#define BALLOON_CHUNK_PAGES             (1000)
 
-#define BALLOON_NOSLEEP_ALLOC_MAX      (16384)
+#define BALLOON_NOSLEEP_ALLOC_MAX       (16384)
 
-#define        BALLOON_RATE_ALLOC_MIN          (512)
-#define        BALLOON_RATE_ALLOC_MAX          (2048)
-#define        BALLOON_RATE_ALLOC_INC          (16)
+#define BALLOON_RATE_ALLOC_MIN          (512)
+#define BALLOON_RATE_ALLOC_MAX          (2048)
+#define BALLOON_RATE_ALLOC_INC          (16)
 
-#define        BALLOON_RATE_FREE_MIN           (512)
-#define        BALLOON_RATE_FREE_MAX           (16384)
-#define        BALLOON_RATE_FREE_INC           (16)
+#define BALLOON_RATE_FREE_MIN           (512)
+#define BALLOON_RATE_FREE_MAX           (16384)
+#define BALLOON_RATE_FREE_INC           (16)
 
-#define        BALLOON_ERROR_PAGES             (16)
+#define BALLOON_ERROR_PAGES             (16)
 
-/* 
+/*
  * When guest is under memory pressure, use a reduced page allocation
  * rate for next several cycles.
  */
-#define SLOW_PAGE_ALLOCATION_CYCLES    (4)
+#define SLOW_PAGE_ALLOCATION_CYCLES     (4)
 
-/* 
+/*
  * Move it to bora/public/balloon_def.h later, if needed. Note that
  * BALLOON_PAGE_ALLOC_FAILURE is an internal error code used for
  * distinguishing page allocation failures from monitor-backdoor errors.
  * We use value 1000 because all monitor-backdoor error codes are < 1000.
  */
-#define BALLOON_PAGE_ALLOC_FAILURE     (1000)
+#define BALLOON_PAGE_ALLOC_FAILURE      (1000)
 
 // Maximum number of page allocations without yielding processor
 #define BALLOON_ALLOC_YIELD_THRESHOLD   (1024)
@@ -156,7 +156,7 @@ static Balloon globalBalloon;
 static int BalloonGuestType(void);
 
 static unsigned long BalloonPrimAllocPage(BalloonPageAllocType canSleep);
-static void   BalloonPrimFreePage(unsigned long page);
+static void BalloonPrimFreePage(unsigned long page);
 
 static int  Balloon_AllocPage(Balloon *b, BalloonPageAllocType allocType);
 static int  Balloon_FreePage(Balloon *b, int monitorUnlock);
@@ -165,7 +165,7 @@ static void Balloon_Reset(Balloon *b);
 
 static void Balloon_StartTimer(Balloon *b);
 static void Balloon_StopTimer(Balloon *b);
-static void CDECL Balloon_BH(void *data);
+static void BalloonTimerHandler(void *clientData);
 
 static int Balloon_MonitorStart(Balloon *b);
 static int Balloon_MonitorGuestType(Balloon *b);
@@ -177,51 +177,43 @@ static int Balloon_MonitorUnlockPage(Balloon *b, unsigned long addr);
  * Macros
  */
 
-#ifndef        MIN
-#define        MIN(a, b)       (((a) < (b)) ? (a) : (b))
-#endif
-#ifndef        MAX
-#define        MAX(a, b)       (((a) > (b)) ? (a) : (b))
-#endif
-
-#ifdef BALLOON_STATS
-#define        STATS_INC(stat) (stat)++
+#ifdef  BALLOON_STATS
+#define STATS_INC(stat) (stat)++
 #else
-#define        STATS_INC(stat)
+#define STATS_INC(stat)
 #endif
 
 /*
  * Macros to generate operations for simple lists of OBJ.
  * OBJ must contain next and prev fields.
- * 
  */
 
-#define        GENERATE_LIST_INSERT(OBJ)                       \
-static void OBJ ## _Insert(OBJ **head, OBJ *obj)       \
-{                                                      \
-   OBJ *h = *head;                                     \
-                                                       \
-   /* add element to head of list */                   \
-   obj->next = h;                                      \
-   if (h != NULL) {                                    \
-      h->prev = obj;                                   \
-   }                                                   \
-   *head = obj;                                                \
-   obj->prev = NULL;                                   \
+#define GENERATE_LIST_INSERT(OBJ)                       \
+static void OBJ ## _Insert(OBJ **head, OBJ *obj)        \
+{                                                       \
+   OBJ *h = *head;                                      \
+                                                        \
+   /* add element to head of list */                    \
+   obj->next = h;                                       \
+   if (h != NULL) {                                     \
+      h->prev = obj;                                    \
+   }                                                    \
+   *head = obj;                                         \
+   obj->prev = NULL;                                    \
 }
 
-#define        GENERATE_LIST_REMOVE(OBJ)                       \
-static void OBJ ## _Remove(OBJ **head, OBJ *obj)       \
-{                                                      \
-    /* splice element out of list */                   \
-    if (obj->prev != NULL) {                           \
-      obj->prev->next = obj->next;                     \
-    } else {                                           \
-      *head = obj->next;                               \
-    }                                                  \
-    if (obj->next != NULL) {                           \
-      obj->next->prev = obj->prev;                     \
-    }                                                  \
+#define GENERATE_LIST_REMOVE(OBJ)                       \
+static void OBJ ## _Remove(OBJ **head, OBJ *obj)        \
+{                                                       \
+    /* splice element out of list */                    \
+    if (obj->prev != NULL) {                            \
+      obj->prev->next = obj->next;                      \
+    } else {                                            \
+      *head = obj->next;                                \
+    }                                                   \
+    if (obj->next != NULL) {                            \
+      obj->next->prev = obj->prev;                      \
+    }                                                   \
 }
 
 /*
@@ -235,25 +227,28 @@ GENERATE_LIST_REMOVE(BalloonChunk);
  * Procfs Operations
  */
 
+
 /*
  *----------------------------------------------------------------------
  *
  * BalloonProcRead --
  *
  *      Ballon driver status reporting routine.  Note that this is only
- *     used for Linux.
+ *      used for Linux.
  *
  * Results:
  *      Writes ASCII status information into "buf".
- *     Returns number of bytes written.
+ *      Returns number of bytes written.
  *
  * Side effects:
  *      None.
  *
  *----------------------------------------------------------------------
  */
-static int CDECL
-BalloonProcRead(char *buf)
+
+static int
+BalloonProcRead(char *buf,      // OUT
+                size_t size) // IN
 {
    int len = 0;
    BalloonStats stats;
@@ -261,14 +256,14 @@ BalloonProcRead(char *buf)
    BalloonGetStats(&stats);
 
    /* format size info */
-   len += os_sprintf(buf + len,
+   len += OS_Snprintf(buf + len, size - len,
                      "target:             %8d pages\n"
                      "current:            %8d pages\n",
                      stats.nPagesTarget,
                      stats.nPages);
 
    /* format rate info */
-   len += os_sprintf(buf + len,
+   len += OS_Snprintf(buf + len, size - len,
                      "rateNoSleepAlloc:   %8d pages/sec\n"
                      "rateSleepAlloc:     %8d pages/sec\n"
                      "rateFree:           %8d pages/sec\n",
@@ -276,8 +271,8 @@ BalloonProcRead(char *buf)
                      stats.rateAlloc,
                      stats.rateFree);
 
-#ifdef BALLOON_STATS_PROCFS
-   len += os_sprintf(buf + len,
+#ifdef BALLOON_STATS_PROCFS
+   len += OS_Snprintf(buf + len, size - len,
                      "\n"
                      "timer:              %8u\n"
                      "start:              %8u (%4u failed)\n"
@@ -305,7 +300,7 @@ BalloonProcRead(char *buf)
                      stats.primErrorPageFree);
 #endif
 
-   return(len);
+   return len;
 }
 
 /*
@@ -318,7 +313,7 @@ BalloonProcRead(char *buf)
  * AddrToPPN --
  *
  *      Return the physical page number corresponding to the specified
- *     Linux kernel-mapped address.
+ *      kernel-mapped address.
  *
  * Results:
  *      Returns PPN for "addr".
@@ -331,7 +326,7 @@ BalloonProcRead(char *buf)
 static inline unsigned long
 AddrToPPN(unsigned long addr)
 {
-   return(os_addr_to_ppn(addr));
+   return OS_AddrToPPN(addr);
 }
 
 /*
@@ -341,12 +336,12 @@ AddrToPPN(unsigned long addr)
  *
  *      Attempts to allocate and reserve a physical page.
  *
- *     If canSleep == 1, i.e., BALLOON_PAGE_ALLOC_CANSLEEP:
- *        The allocation can wait (sleep) for page writeout (swap)
- *        by the guest.
- *     otherwise canSleep == 0, i.e., BALLOON_PAGE_ALLOC_NOSLEEP:
- *        If allocation of a page requires disk writeout, then
- *        just fail. DON'T sleep.
+ *      If canSleep == 1, i.e., BALLOON_PAGE_ALLOC_CANSLEEP:
+ *         The allocation can wait (sleep) for page writeout (swap)
+ *         by the guest.
+ *      otherwise canSleep == 0, i.e., BALLOON_PAGE_ALLOC_NOSLEEP:
+ *         If allocation of a page requires disk writeout, then
+ *         just fail. DON'T sleep.
  *
  * Results:
  *      Returns the physical address of the allocated page, or 0 if error.
@@ -359,7 +354,7 @@ AddrToPPN(unsigned long addr)
 static unsigned long
 BalloonPrimAllocPage(BalloonPageAllocType canSleep)
 {
-   return(os_alloc_reserved_page(canSleep));
+   return OS_AllocReservedPage(canSleep);
 }
 
 /*
@@ -380,7 +375,7 @@ BalloonPrimAllocPage(BalloonPageAllocType canSleep)
 static void
 BalloonPrimFreePage(unsigned long page)
 {
-   return(os_free_reserved_page(page));
+   return OS_FreeReservedPage(page);
 }
 
 /*
@@ -389,7 +384,7 @@ BalloonPrimFreePage(unsigned long page)
  * BalloonGuestType --
  *
  *      Return balloon guest OS identifier obtained by parsing
- *     system-dependent identity string.
+ *      system-dependent identity string.
  *
  * Results:
  *      Returns one of BALLOON_GUEST_{LINUX,BSD,SOLARIS,UNKNOWN}.
@@ -402,11 +397,11 @@ BalloonPrimFreePage(unsigned long page)
 static int
 BalloonGuestType(void)
 {
-   char *identity;
+   const char *identity;
 
    /* obtain OS identify string */
-   identity = os_identity();
-   
+   identity = OS_Identity();
+
    /* unknown if not specified */
    if (identity == NULL) {
       return(BALLOON_GUEST_UNKNOWN);
@@ -416,19 +411,19 @@ BalloonGuestType(void)
    switch (identity[0]) {
    case 'l':
    case 'L':
-      return(BALLOON_GUEST_LINUX);
+      return BALLOON_GUEST_LINUX;
    case 'b':
    case 'B':
-      return(BALLOON_GUEST_BSD);
+      return BALLOON_GUEST_BSD;
    case 's':
    case 'S':
-      return(BALLOON_GUEST_SOLARIS);
+      return BALLOON_GUEST_SOLARIS;
    default:
       break;
    }
 
    /* unknown */
-   return(BALLOON_GUEST_UNKNOWN);
+   return BALLOON_GUEST_UNKNOWN;
 }
 
 /*
@@ -443,7 +438,7 @@ void BalloonGetStats(BalloonStats *stats)
    /*
     * Copy statistics out of global structure.
     */
-   os_memcpy(stats, &b->stats, sizeof (BalloonStats));
+   OS_MemCopy(stats, &b->stats, sizeof (BalloonStats));
 
    /*
     * Fill in additional information about size and rates, which is
@@ -465,37 +460,41 @@ void BalloonGetStats(BalloonStats *stats)
  * BalloonChunk_Create --
  *
  *      Creates a new BalloonChunk object capable of tracking
- *     BALLOON_CHUNK_PAGES PPNs.
+ *      BALLOON_CHUNK_PAGES PPNs.
  *
- *     We do not bother to define two versions (NOSLEEP and CANSLEEP)
- *     of os_kmalloc because Chunk_Create does not require a new page
- *     often.
+ *      We do not bother to define two versions (NOSLEEP and CANSLEEP)
+ *      of OS_Malloc because Chunk_Create does not require a new page
+ *      often.
  *
  * Results:
- *      Returns initialized BalloonChunk, or NULL if error.
+ *      On success: initialized BalloonChunk
+ *      On failure: NULL
  *
  * Side effects:
- *      None.
+ *      None
  *
  *----------------------------------------------------------------------
  */
+
 static BalloonChunk *
 BalloonChunk_Create(void)
 {
    BalloonChunk *chunk;
 
    /* allocate memory, fail if unable */
-   if ((chunk = (BalloonChunk *) os_kmalloc_nosleep(sizeof(BalloonChunk))) == NULL) {
-      return(NULL);
+   chunk = OS_Malloc(sizeof *chunk);
+   if (chunk == NULL) {
+      return NULL;
    }
 
    /* initialize */
-   os_bzero(chunk, sizeof(BalloonChunk));
+   OS_MemZero(chunk, sizeof *chunk);
 
    /* everything OK */
-   return(chunk);
+   return chunk;
 }
 
+
 /*
  *----------------------------------------------------------------------
  *
@@ -515,7 +514,7 @@ static void
 BalloonChunk_Destroy(BalloonChunk *chunk)
 {
    /* reclaim storage */
-   os_kfree(chunk, sizeof (BalloonChunk));
+   OS_Free(chunk, sizeof *chunk);
 }
 
 /*
@@ -542,7 +541,7 @@ static int
 Balloon_Init(Balloon *b)
 {
    /* clear state */
-   os_bzero(b, sizeof(Balloon));
+   OS_MemZero(b, sizeof *b);
 
    /* initialize rates */
    b->rateAlloc = BALLOON_RATE_ALLOC_MAX;
@@ -580,7 +579,7 @@ Balloon_Deallocate(Balloon *b)
       (void) Balloon_FreePage(b, FALSE);
       if (++cnt >= b->rateFree) {
          cnt = 0;
-         os_yield();
+         OS_Yield();
       }
    }
 }
@@ -591,7 +590,7 @@ Balloon_Deallocate(Balloon *b)
  * Balloon_Reset --
  *
  *      Resets balloon "b" to empty state.  Frees all allocated pages
- *     and attempts to reset contact with the monitor. 
+ *      and attempts to reset contact with the monitor.
  *
  * Results:
  *      None.
@@ -623,12 +622,12 @@ Balloon_Reset(Balloon *b)
 /*
  *----------------------------------------------------------------------
  *
- * Balloon_BH --
+ * BalloonTimerHandler --
  *
  *      Balloon bottom half handler.  Contacts monitor via backdoor
- *     to obtain balloon size target, and starts adjusting balloon
- *     size to achieve target by allocating or deallocating pages.
- *     Resets balloon if requested by the monitor.
+ *      to obtain balloon size target, and starts adjusting balloon
+ *      size to achieve target by allocating or deallocating pages.
+ *      Resets balloon if requested by the monitor.
  *
  * Results:
  *      None.
@@ -638,10 +637,10 @@ Balloon_Reset(Balloon *b)
  *
  *----------------------------------------------------------------------
  */
-static void CDECL
-Balloon_BH(void *data)
+static void
+BalloonTimerHandler(void *clientData)
 {
-   Balloon *b = (Balloon *) data;
+   Balloon *b = (Balloon *) clientData;
    uint32 target;
    int status;
 
@@ -679,14 +678,14 @@ Balloon_BH(void *data)
  *      None.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
 static void
 Balloon_StartTimer(Balloon *b)
 {
-   os_timer_start();
+   OS_TimerStart();
 }
 
 /*
@@ -700,14 +699,14 @@ Balloon_StartTimer(Balloon *b)
  *      None.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
 static void
 Balloon_StopTimer(Balloon *b)
 {
-   os_timer_stop();
+   OS_TimerStop();
 }
 
 
@@ -717,14 +716,14 @@ Balloon_StopTimer(Balloon *b)
  * Balloon_ErrorPagesAlloc --
  *
  *      Attempt to add "page" to list of non-balloonable pages
- *     associated with "b".
+ *      associated with "b".
  *
  * Results:
- *      Returns BALLOON_SUCCESS iff successful, or BALLOON_FAILURE
- *     if non-balloonable page list is already full.
+ *      On success: BALLOON_SUCCESS
+ *      On failure: BALLOON_FAILURE (non-balloonable page list is already full)
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -749,13 +748,13 @@ Balloon_ErrorPagesAlloc(Balloon *b, unsigned long page)
  * Balloon_ErrorPagesFree --
  *
  *      Deallocates all pages on the list of non-balloonable pages
- *     associated with "b".
+ *      associated with "b".
  *
  * Results:
- *     None.
+ *      None.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -766,7 +765,7 @@ Balloon_ErrorPagesFree(Balloon *b)
 
    /* free all non-balloonable "error" pages */
    for (i = 0; i < b->errors.nextPage; i++) {
-      BalloonPrimFreePage(b->errors.page[i]);      
+      BalloonPrimFreePage(b->errors.page[i]);
       b->errors.page[i] = 0;
       STATS_INC(b->stats.primErrorPageFree);
    }
@@ -779,13 +778,13 @@ Balloon_ErrorPagesFree(Balloon *b)
  * Balloon_AllocPage --
  *
  *      Attempts to allocate a physical page, inflating balloon "b".
- *     Informs monitor of PPN for allocated page via backdoor.
+ *      Informs monitor of PPN for allocated page via backdoor.
  *
  * Results:
  *      Returns BALLOON_SUCCESS if successful, otherwise error code.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -854,14 +853,14 @@ Balloon_AllocPage(Balloon *b, BalloonPageAllocType allocType)
  * Balloon_FreePage --
  *
  *      Attempts to deallocate a physical page, deflating balloon "b".
- *     Informs monitor of PPN for deallocated page via backdoor if
- *     "monitorUnlock" is specified.
+ *      Informs monitor of PPN for deallocated page via backdoor if
+ *      "monitorUnlock" is specified.
  *
  * Results:
  *      Returns BALLOON_SUCCESS if successful, otherwise error code.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -929,15 +928,15 @@ Balloon_FreePage(Balloon *b, int monitorUnlock)
  *
  * BalloonDecreaseRateAlloc --
  *
- *     Wrapper to quickly reduce the page allocation rate. This function
- *     is called only when a CANSLEEP allocation fails. This implies severe 
- *     memory pressure inside the guest, so quickly decrease the rateAlloc.
+ *      Wrapper to quickly reduce the page allocation rate. This function
+ *      is called only when a CANSLEEP allocation fails. This implies severe
+ *      memory pressure inside the guest, so quickly decrease the rateAlloc.
  *
  * Results:
  *      None.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -954,27 +953,27 @@ BalloonDecreaseRateAlloc(Balloon *b)
  *
  * BalloonIncreaseRateAlloc --
  *
- *     Wrapper to increase the page allocation rate. 
+ *      Wrapper to increase the page allocation rate.
  *
- *     This function is called when the balloon target is met or
- *     b->rateAlloc (or more) pages have been successfully allocated.
- *     This implies that the guest may not be under high memory 
- *     pressure. So let us increase the rateAlloc.
+ *      This function is called when the balloon target is met or
+ *      b->rateAlloc (or more) pages have been successfully allocated.
+ *      This implies that the guest may not be under high memory
+ *      pressure. So let us increase the rateAlloc.
  *
- *     If meeting balloon target requires less than b->rateAlloc
- *     pages, then we do not change the page allocation rate.
+ *      If meeting balloon target requires less than b->rateAlloc
+ *      pages, then we do not change the page allocation rate.
  *
- *     If the number of pages successfully allocated (nAlloc) is far
- *     higher than b->rateAlloc, then it implies that NOSLEEP 
- *     allocations are highly successful. Therefore, we predict that
- *     the guest is under no memory pressure, and so increase
- *     b->rateAlloc quickly.
+ *      If the number of pages successfully allocated (nAlloc) is far
+ *      higher than b->rateAlloc, then it implies that NOSLEEP
+ *      allocations are highly successful. Therefore, we predict that
+ *      the guest is under no memory pressure, and so increase
+ *      b->rateAlloc quickly.
  *
  * Results:
  *      None.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -983,7 +982,7 @@ BalloonIncreaseRateAlloc(Balloon *b, uint32 nAlloc)
 {
    if (BALLOON_RATE_ADAPT) {
       if (nAlloc >= b->rateAlloc) {
-         uint32 mult = nAlloc / b->rateAlloc; 
+         uint32 mult = nAlloc / b->rateAlloc;
          b->rateAlloc = MIN(b->rateAlloc + mult * BALLOON_RATE_ALLOC_INC,
                             BALLOON_RATE_ALLOC_MAX);
       }
@@ -1001,7 +1000,7 @@ BalloonIncreaseRateAlloc(Balloon *b, uint32 nAlloc)
  *      Returns BALLOON_SUCCESS if successful, otherwise error code.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -1011,7 +1010,7 @@ BalloonInflate(Balloon *b, uint32 target)
    int status, allocations = 0;
    uint32 i, nAllocNoSleep, nAllocCanSleep;
 
-   /* 
+   /*
     * First try NOSLEEP page allocations to inflate balloon.
     *
     * If we do not throttle nosleep allocations, we can drain all
@@ -1019,10 +1018,10 @@ BalloonInflate(Balloon *b, uint32 target)
     * As a side-effect, draining free pages helps to inform (force)
     * the guest to start swapping if balloon target is not met yet,
     * which is a desired behavior. However, balloon driver can consume
-    * all available CPU cycles if too many pages are allocated in a 
-    * second. Therefore, we throttle nosleep allocations even when 
-    * the guest is not under memory pressure. OTOH, if we have already 
-    * predicted that the guest is under memory pressure, then we 
+    * all available CPU cycles if too many pages are allocated in a
+    * second. Therefore, we throttle nosleep allocations even when
+    * the guest is not under memory pressure. OTOH, if we have already
+    * predicted that the guest is under memory pressure, then we
     * slowdown page allocations considerably.
     */
    if (b->slowPageAllocationCycles > 0) {
@@ -1036,16 +1035,16 @@ BalloonInflate(Balloon *b, uint32 target)
       status = Balloon_AllocPage(b, BALLOON_PAGE_ALLOC_NOSLEEP);
       if (status != BALLOON_SUCCESS) {
          if (status != BALLOON_PAGE_ALLOC_FAILURE) {
-            /* 
+            /*
              * Not a page allocation failure, so release non-balloonable
              * pages, and fail.
              */
             Balloon_ErrorPagesFree(b);
             return(status);
          }
-         /* 
-          * NOSLEEP page allocation failed, so the guest is under memory 
-          * pressure. Let us slowdown page allocations for next few 
+         /*
+          * NOSLEEP page allocation failed, so the guest is under memory
+          * pressure. Let us slowdown page allocations for next few
           * cycles so that the guest gets out of memory pressure.
           */
          b->slowPageAllocationCycles = SLOW_PAGE_ALLOCATION_CYCLES;
@@ -1053,12 +1052,12 @@ BalloonInflate(Balloon *b, uint32 target)
       }
 
       if (++allocations > BALLOON_ALLOC_YIELD_THRESHOLD) {
-         os_yield();
+         OS_Yield();
          allocations = 0;
       }
    }
 
-   /* 
+   /*
     * Check whether nosleep allocation successfully zapped nAllocNoSleep
     * pages.
     */
@@ -1068,7 +1067,7 @@ BalloonInflate(Balloon *b, uint32 target)
       Balloon_ErrorPagesFree(b);
       return(BALLOON_SUCCESS);
    } else {
-      /* 
+      /*
        * NOSLEEP allocation failed, so the guest is under memory pressure.
        * If already b->rateAlloc pages were zapped, then succeed. Otherwise,
        * try CANSLEEP allocation.
@@ -1084,14 +1083,14 @@ BalloonInflate(Balloon *b, uint32 target)
       }
    }
 
-   /* 
+   /*
     * Use CANSLEEP page allocation to inflate balloon if below target.
     *
     * Sleep allocations are required only when nosleep allocation fails.
     * This implies that the guest is already under memory pressure, so
     * let us always throttle canSleep allocations. The total number pages
-    * allocated using noSleep and canSleep methods is throttled at 
-    * b->rateAlloc per second when the guest is under memory pressure. 
+    * allocated using noSleep and canSleep methods is throttled at
+    * b->rateAlloc per second when the guest is under memory pressure.
     */
    nAllocCanSleep = target - b->nPages;
    nAllocCanSleep = MIN(nAllocCanSleep, b->rateAlloc - nAllocNoSleep);
@@ -1101,7 +1100,7 @@ BalloonInflate(Balloon *b, uint32 target)
       status = Balloon_AllocPage(b, BALLOON_PAGE_ALLOC_CANSLEEP);
       if(status != BALLOON_SUCCESS) {
          if (status == BALLOON_PAGE_ALLOC_FAILURE) {
-            /* 
+            /*
              * CANSLEEP page allocation failed, so guest is under severe
              * memory pressure. Quickly decrease rateAlloc.
              */
@@ -1113,17 +1112,17 @@ BalloonInflate(Balloon *b, uint32 target)
       }
 
       if (++allocations > BALLOON_ALLOC_YIELD_THRESHOLD) {
-         os_yield();
+         OS_Yield();
          allocations = 0;
       }
    }
 
-   /* 
+   /*
     * Either met the balloon target or b->rateAlloc pages have been
     * successfully zapped.
     */
    BalloonIncreaseRateAlloc(b, nAllocNoSleep + nAllocCanSleep);
-                            
+
    /* release non-balloonable pages, succeed */
    Balloon_ErrorPagesFree(b);
    return(BALLOON_SUCCESS);
@@ -1140,7 +1139,7 @@ BalloonInflate(Balloon *b, uint32 target)
  *      Returns BALLOON_SUCCESS if successful, otherwise error code.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -1149,7 +1148,7 @@ BalloonDeflate(Balloon *b, uint32 target)
 {
    int status, i;
    uint32 nFree = b->nPages - target;
-      
+
    /* limit deallocation rate */
    nFree = MIN(nFree, b->rateFree);
 
@@ -1173,20 +1172,20 @@ BalloonDeflate(Balloon *b, uint32 target)
    /* everything OK */
    return(BALLOON_SUCCESS);
 }
+
 /*
  *----------------------------------------------------------------------
  *
  * Balloon_AdjustSize --
  *
  *      Attempts to allocate or deallocate physical pages in order
- *     to reach desired "target" size for balloon "b".
+ *      to reach desired "target" size for balloon "b".
  *
  * Results:
  *      Returns BALLOON_SUCCESS if successful, otherwise error code.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -1224,10 +1223,10 @@ Balloon_AdjustSize(Balloon *b, uint32 target)
  *      Attempts to contact monitor via backdoor to begin operation.
  *
  * Results:
- *     Returns BALLOON_SUCCESS if successful, otherwise error code.
+ *      Returns BALLOON_SUCCESS if successful, otherwise error code.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -1266,10 +1265,10 @@ Balloon_MonitorStart(Balloon *b)
  *      Attempts to contact monitor and report guest OS identity.
  *
  * Results:
- *     Returns BALLOON_SUCCESS if successful, otherwise error code.
+ *      Returns BALLOON_SUCCESS if successful, otherwise error code.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -1311,24 +1310,24 @@ Balloon_MonitorGuestType(Balloon *b)
  * Balloon_MonitorGetTarget --
  *
  *      Attempts to contact monitor via backdoor to obtain desired
- *     balloon size.
+ *      balloon size.
  *
- *     Predicts the maximum achievable balloon size and sends it 
- *     to vmm => vmkernel via vEbx register.
+ *      Predicts the maximum achievable balloon size and sends it
+ *      to vmm => vmkernel via vEbx register.
  *
- *     os_predict_max_balloon_pages() returns either predicted max balloon
- *     pages or BALLOON_MAX_SIZE_USE_CONFIG. In the later scenario,
- *     vmkernel uses global config options for determining a guest's max
- *     balloon size. Note that older vmballoon drivers set vEbx to 
- *     BALLOON_MAX_SIZE_USE_CONFIG, i.e., value 0 (zero). So vmkernel
- *     will fallback to config-based max balloon size estimation.
+ *      OS_PredictMaxReservedPages() returns either predicted max balloon
+ *      pages or BALLOON_MAX_SIZE_USE_CONFIG. In the later scenario,
+ *      vmkernel uses global config options for determining a guest's max
+ *      balloon size. Note that older vmballoon drivers set vEbx to
+ *      BALLOON_MAX_SIZE_USE_CONFIG, i.e., value 0 (zero). So vmkernel
+ *      will fallback to config-based max balloon size estimation.
  *
  * Results:
- *     If successful, sets "target" to value obtained from monitor,
+ *      If successful, sets "target" to value obtained from monitor,
  *      and returns BALLOON_SUCCESS. Otherwise returns error code.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -1340,7 +1339,7 @@ Balloon_MonitorGetTarget(Balloon *b, uint32 *target)
 
    /* prepare backdoor args */
    bp.in.cx.halfs.low = BALLOON_BDOOR_CMD_TARGET;
-   bp.in.size = os_predict_max_balloon_pages();
+   bp.in.size = OS_PredictMaxReservedPages();
 
    /* invoke backdoor */
    Backdoor_Balloon(&bp);
@@ -1369,14 +1368,14 @@ Balloon_MonitorGetTarget(Balloon *b, uint32 *target)
  *
  * Balloon_MonitorLockPage --
  *
- *      Attempts to contact monitor and add PPN containing "addr" 
- *     to set of "balloon locked" pages.
+ *      Attempts to contact monitor and add PPN containing "addr"
+ *      to set of "balloon locked" pages.
  *
  * Results:
- *     Returns BALLOON_SUCCESS if successful, otherwise error code.
+ *      Returns BALLOON_SUCCESS if successful, otherwise error code.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -1428,14 +1427,14 @@ Balloon_MonitorLockPage(Balloon *b, unsigned long addr)
  *
  * Balloon_MonitorUnlockPage --
  *
- *      Attempts to contact monitor and remove PPN containing "addr" 
- *     from set of "balloon locked" pages.
+ *      Attempts to contact monitor and remove PPN containing "addr"
+ *      from set of "balloon locked" pages.
  *
  * Results:
- *     Returns BALLOON_SUCCESS if successful, otherwise error code.
+ *      Returns BALLOON_SUCCESS if successful, otherwise error code.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -1497,18 +1496,18 @@ BalloonModuleInit(void)
       return(BALLOON_FAILURE);
    }
 
+   /* os-specific initialization */
+   OS_Init(BALLOON_NAME, BALLOON_NAME_VERBOSE, BalloonProcRead);
+
    /* initialize global state */
    Balloon_Init(b);
 
-   /* os-specific initialization */
-   os_init(BALLOON_NAME, BALLOON_NAME_VERBOSE, BalloonProcRead);
-   os_timer_init(Balloon_BH, (void *) b, os_timer_hz());
-
    /* start timer */
+   OS_TimerInit(BalloonTimerHandler, b, OS_TimerHz());
    Balloon_StartTimer(b);
 
    /* everything OK */
-   return(BALLOON_SUCCESS);
+   return BALLOON_SUCCESS;
 }
 
 static void
@@ -1528,8 +1527,8 @@ BalloonModuleCleanup(void)
    Balloon_Deallocate(b);
 
    /* os-specific cleanup */
-   os_cleanup();
-}   
+   OS_Cleanup();
+}
 
 int init_module(void)
 {
index 664dc479e74603a723788eb14f2ea5756a5e0938..d35b0df417219c2f4ccbfe4799a17ca4e2ff7172 100644 (file)
@@ -1,5 +1,5 @@
 PACKAGE_NAME=open-vm-tools
-PACKAGE_VERSION=2009.07.22
+PACKAGE_VERSION=2009.08.24
 MAKE_CMD_TMPL="make VM_UNAME=\$kernelver \
                MODULEBUILDDIR=$dkms_tree/$PACKAGE_NAME/$PACKAGE_VERSION/build"
 
index 4513e8e8bc3999bc91f82f12e1046f66f1a8af40..a85ae7d3f2a6a8dd3ee83276b2c92849939d94a7 100644 (file)
@@ -28,16 +28,17 @@ then
    echo "   src:  root of unpacked open-vm-tools package"
    echo "   dst:  where to create the dkms tree"
    echo
-   echo "The script will create an 'open-vm-tools' module with version 2009.07.22."
+   echo "The script will create an 'open-vm-tools' module with version 2009.08.24."
    exit 1
 fi
 
 src=$1
-dst=$2/open-vm-tools-2009.07.22
+dst=$2/open-vm-tools-2009.08.24
 
 SHARED_HEADERS="backdoor_def.h"
 SHARED_HEADERS="$SHARED_HEADERS backdoor_types.h"
 SHARED_HEADERS="$SHARED_HEADERS circList.h"
+SHARED_HEADERS="$SHARED_HEADERS community_source.h"
 SHARED_HEADERS="$SHARED_HEADERS dbllnklst.h"
 SHARED_HEADERS="$SHARED_HEADERS guest_msg_def.h"
 SHARED_HEADERS="$SHARED_HEADERS includeCheck.h"
index d5144a8495a5b6619d330cac2420b7232d600a5e..125b5cc88e9872eab5cdf0cf9f1a40dae3bb50f5 100644 (file)
@@ -454,11 +454,11 @@ static int __devinit pvscsi_probe(struct pci_dev *pdev,
        if (pdev->vendor != PCI_VENDOR_ID_VMWARE)
                goto out_disable_device;
 
-       if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0 &&
-           pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK) == 0) {
+       if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) == 0 &&
+           pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) == 0) {
                printk(KERN_INFO "pvscsi: using 64bit dma\n");
-       } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) == 0 &&
-                  pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK) == 0) {
+       } else if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) == 0 &&
+                  pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)) == 0) {
                printk(KERN_INFO "pvscsi: using 32bit dma\n");
         } else {
                printk(KERN_ERR "pvscsi: failed to set DMA mask\n");
index 642f013404b6d1063f96ad970be9e7656819434f..855f67d00dde24d6bc92761b3afa33a3413f4c8d 100644 (file)
@@ -36,6 +36,7 @@
 
 #include "vm_basic_defs.h"  // for offsetof()
 
+#define SCSI_MIN_CMD_LEN   6
 #define SCSI_MAX_CMD_LEN   16
 
 /*
  * NB: Command descriptions come from the "SCSI Book" and not
  *     from the SCSI specifications (YMMV).
  */
-#define SCSI_CMD_TEST_UNIT_READY       0x00    // test if LUN ready to accept a command
-#define SCSI_CMD_REZERO_UNIT          0x01     // seek to track 0
-#define SCSI_CMD_REQUEST_SENSE        0x03     // return detailed error information
-#define SCSI_CMD_FORMAT_UNIT          0x04     //
-#define SCSI_CMD_READ_BLOCKLIMITS      0x05    //
-#define SCSI_CMD_REASSIGN_BLOCKS       0x07    // 
-#define SCSI_CMD_INIT_ELEMENT_STATUS   0x07     // Media changer
-#define SCSI_CMD_READ6                0x08     // read w/ limited addressing
-#define SCSI_CMD_WRITE6                       0x0a     // write w/ limited addressing
-#define SCSI_CMD_PRINT                0x0a     // print data
-#define SCSI_CMD_SEEK6                0x0b     // seek to LBN
-#define SCSI_CMD_SLEW_AND_PRINT               0x0b     // advance and print
-#define SCSI_CMD_READ_REVERSE         0x0f     // read backwards
-#define SCSI_CMD_WRITE_FILEMARKS       0x10    // 
-#define SCSI_CMD_SYNC_BUFFER          0x10     // print contents of buffer
-#define SCSI_CMD_SPACE                0x11     // 
-#define SCSI_CMD_INQUIRY              0x12     // return LUN-specific information
-#define SCSI_CMD_RECOVER_BUFFERED      0x14    // recover buffered data
-#define SCSI_CMD_MODE_SELECT          0x15     // set device parameters
-#define SCSI_CMD_RESERVE_UNIT         0x16     // make LUN accessible only to certain initiators
-#define SCSI_CMD_RELEASE_UNIT         0x17     // make LUN accessible to other initiators
-#define SCSI_CMD_COPY                 0x18     // autonomous copy from/to another device
-#define SCSI_CMD_ERASE                0x19     // 
-#define SCSI_CMD_MODE_SENSE           0x1a     // read device parameters
-#define SCSI_CMD_START_UNIT           0x1b     // load/unload medium
-#define SCSI_CMD_SCAN                 0x1b     // perform scan
-#define SCSI_CMD_STOP_PRINT           0x1b     // interrupt printing
-#define SCSI_CMD_RECV_DIAGNOSTIC       0x1c    // read self-test results
-#define SCSI_CMD_SEND_DIAGNOSTIC       0x1d    // initiate self-test
-#define SCSI_CMD_MEDIUM_REMOVAL               0x1e     // lock/unlock door
-#define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23   // read format capacities
-#define SCSI_CMD_SET_WINDOW           0x24     // set scanning window
-#define SCSI_CMD_GET_WINDOW           0x25     // get scanning window
-#define SCSI_CMD_READ_CAPACITY        0x25     // read number of logical blocks
-#define SCSI_CMD_READ10                       0x28     // read
-#define SCSI_CMD_READ_GENERATION       0x29    // read max generation address of LBN
-#define SCSI_CMD_WRITE10              0x2a     // write
-#define SCSI_CMD_SEEK10                       0x2b     // seek LBN
-#define SCSI_CMD_POSITION_TO_ELEMENT   0x2b     // media changer
-#define SCSI_CMD_ERASE10               0x2c
-#define SCSI_CMD_READ_UPDATED_BLOCK    0x2d    // read specific version of changed block
-#define SCSI_CMD_WRITE_VERIFY         0x2e     // write w/ verify of success
-#define SCSI_CMD_VERIFY                       0x2f     // verify success
-#define SCSI_CMD_SEARCH_DATA_HIGH      0x30    // search for data pattern
-#define SCSI_CMD_SEARCH_DATA_EQUAL     0x31    // search for data pattern
-#define SCSI_CMD_SEARCH_DATA_LOW       0x32    // search for data pattern
-#define SCSI_CMD_SET_LIMITS           0x33     // define logical block boundaries
-#define SCSI_CMD_PREFETCH             0x34     // read data into buffer
-#define SCSI_CMD_READ_POSITION        0x34     // read current tape position
-#define SCSI_CMD_SYNC_CACHE           0x35     // re-read data into buffer
-#define SCSI_CMD_LOCKUNLOCK_CACHE      0x36    // lock/unlock data in cache
-#define SCSI_CMD_READ_DEFECT_DATA      0x37    // 
-#define SCSI_CMD_MEDIUM_SCAN          0x38     // search for free area
-#define SCSI_CMD_COMPARE              0x39     // compare data
-#define SCSI_CMD_COPY_VERIFY          0x3a     // autonomous copy w/ verify
-#define SCSI_CMD_WRITE_BUFFER         0x3b     // write data buffer
-#define SCSI_CMD_READ_BUFFER          0x3c     // read data buffer
-#define SCSI_CMD_UPDATE_BLOCK         0x3d     // substitute block with an updated one
-#define SCSI_CMD_READ_LONG            0x3e     // read data and ECC
-#define SCSI_CMD_WRITE_LONG           0x3f     // write data and ECC
-#define SCSI_CMD_CHANGE_DEF           0x40     // set SCSI version
-#define SCSI_CMD_WRITE_SAME           0x41     // 
-#define SCSI_CMD_READ_SUBCHANNEL       0x42    // read subchannel data and status
-#define SCSI_CMD_READ_TOC             0x43     // read contents table
-#define SCSI_CMD_READ_HEADER          0x44     // read LBN header
-#define SCSI_CMD_PLAY_AUDIO10         0x45     // audio playback
-#define SCSI_CMD_GET_CONFIGURATION     0x46    // get configuration (SCSI-3)
-#define SCSI_CMD_PLAY_AUDIO_MSF               0x47     // audio playback starting at MSF address
-#define SCSI_CMD_PLAY_AUDIO_TRACK      0x48    // audio playback starting at track/index
-#define SCSI_CMD_PLAY_AUDIO_RELATIVE   0x49    // audio playback starting at relative track
-#define SCSI_CMD_GET_EVENT_STATUS_NOTIFICATION 0x4a
-#define SCSI_CMD_PAUSE                0x4b     // audio playback pause/resume
-#define SCSI_CMD_LOG_SELECT           0x4c     // select statistics
-#define SCSI_CMD_LOG_SENSE            0x4d     // read statistics
-#define SCSI_CMD_STOP_PLAY            0x4e     // audio playback stop
-#define SCSI_CMD_READ_DISC_INFO        0x51     // info on CDRs
-#define SCSI_CMD_READ_TRACK_INFO       0x52     // track info on CDRs
-#define SCSI_CMD_RESERVE_TRACK         0x53     // leave space for data on CDRs
-#define SCSI_CMD_SEND_OPC_INFORMATION  0x54     // Optimum Power Calibration
-#define SCSI_CMD_MODE_SELECT10        0x55     // set device parameters
-#define SCSI_CMD_RESERVE_UNIT10        0x56     //
-#define SCSI_CMD_RELEASE_UNIT10        0x57     //
-#define SCSI_CMD_REPAIR_TRACK          0x58
-#define SCSI_CMD_MODE_SENSE10         0x5a     // read device parameters
-#define SCSI_CMD_CLOSE_SESSION         0x5b     // close area/sesssion (recordable)
-#define SCSI_CMD_READ_BUFFER_CAPACITY  0x5c     // CDR burning info.
-#define SCSI_CMD_SEND_CUE_SHEET        0x5d     // (CDR Related?)
-#define SCSI_CMD_PERSISTENT_RESERVE_IN 0x5e     //
-#define SCSI_CMD_PERSISTENT_RESERVE_OUT 0x5f    //
-#define SCSI_CMD_XDWRITE_EXTENDED      0x80
-#define SCSI_CMD_REBUILD               0x81
-#define SCSI_CMD_REGENERATE            0x82
-#define SCSI_CMD_EXTENDED_COPY         0x83     // extended copy
-#define SCSI_CMD_RECEIVE_COPY_RESULTS  0x84     // receive copy results
-#define SCSI_CMD_READ16                       0x88     // read data
-#define SCSI_CMD_WRITE16               0x8a     // write data
-#define SCSI_CMD_ORWRITE16             0x8b
-#define SCSI_CMD_READ_ATTRIBUTE        0x8c     // read attribute
-#define SCSI_CMD_WRITE_ATTRIBUTE       0x8d     // write attribute
-#define SCSI_CMD_WRITE_VERIFY16        0x8e
-#define SCSI_CMD_VERIFY16              0x8f
-#define SCSI_CMD_PREFETCH16            0x90
-#define SCSI_CMD_SYNC_CACHE16          0x91
-#define SCSI_CMD_WRITE_SAME16          0x93
-#define SCSI_CMD_READ_CAPACITY16       0x9e     // read number of logical blocks
-#define SCSI_CMD_WRITE_LONG16          0x9f
-#define SCSI_CMD_REPORT_LUNS           0xa0     // 
-#define SCSI_CMD_BLANK                 0xa1     // erase RW media
-#define SCSI_CMD_SECURITY_PROTOCOL_IN  0xa2     // 
-#define SCSI_CMD_MAINTENANCE_IN        0xa3    // service actions define reports
-#define SCSI_CMD_MAINTENANCE_OUT       0xa4    // service actions define changes
-#define SCSI_CMD_SEND_KEY             0xa3
-#define SCSI_CMD_REPORT_KEY           0xa4     // report key (SCSI-3)
-#define SCSI_CMD_MOVE_MEDIUM          0xa5     // 
-#define SCSI_CMD_PLAY_AUDIO12         0xa5     // audio playback
-#define SCSI_CMD_EXCHANGE_MEDIUM       0xa6     //
-#define SCSI_CMD_LOADCD                       0xa6     //
-#define SCSI_CMD_SET_READ_AHEAD        0xa7
-#define SCSI_CMD_READ12                       0xa8     // read (SCSI-3)
-#define SCSI_CMD_PLAY_TRACK_RELATIVE   0xa9    // audio playback starting at relative track
-#define SCSI_CMD_WRITE12              0xaa     // write data
-#define SCSI_CMD_READ_MEDIA_SERIAL_NUMBER 0xab  //
-#define SCSI_CMD_ERASE12              0xac     // erase logical block
-#define SCSI_CMD_GET_PERFORMANCE       0xac    //
-#define SCSI_CMD_READ_DVD_STRUCTURE    0xad    // read DVD structure (SCSI-3)
-#define SCSI_CMD_WRITE_VERIFY12               0xae     // write logical block, verify success
-#define SCSI_CMD_VERIFY12             0xaf     // verify data
-#define SCSI_CMD_SEARCH_DATA_HIGH12    0xb0    // search data pattern
-#define SCSI_CMD_SEARCH_DATA_EQUAL12   0xb1    // search data pattern
-#define SCSI_CMD_SEARCH_DATA_LOW12     0xb2    // search data pattern
-#define SCSI_CMD_SET_LIMITS12         0xb3     // set block limits
+#define SCSI_CMD_TEST_UNIT_READY       0x00  // test if LUN ready to accept a command
+#define SCSI_CMD_REZERO_UNIT           0x01  // seek to track 0
+#define SCSI_CMD_REQUEST_SENSE         0x03  // return detailed error information
+#define SCSI_CMD_FORMAT_UNIT           0x04  //
+#define SCSI_CMD_READ_BLOCKLIMITS      0x05  //
+#define SCSI_CMD_REASSIGN_BLOCKS       0x07  //
+#define SCSI_CMD_INIT_ELEMENT_STATUS   0x07  // Media changer
+#define SCSI_CMD_READ6                 0x08  // read w/ limited addressing
+#define SCSI_CMD_WRITE6                0x0a  // write w/ limited addressing
+#define SCSI_CMD_PRINT                 0x0a  // print data
+#define SCSI_CMD_SEEK6                 0x0b  // seek to LBN
+#define SCSI_CMD_SLEW_AND_PRINT        0x0b  // advance and print
+#define SCSI_CMD_READ_REVERSE          0x0f  // read backwards
+#define SCSI_CMD_WRITE_FILEMARKS       0x10  //
+#define SCSI_CMD_SYNC_BUFFER           0x10  // print contents of buffer
+#define SCSI_CMD_SPACE                 0x11  //
+#define SCSI_CMD_INQUIRY               0x12  // return LUN-specific information
+#define SCSI_CMD_RECOVER_BUFFERED      0x14  // recover buffered data
+#define SCSI_CMD_MODE_SELECT           0x15  // set device parameters
+#define SCSI_CMD_RESERVE_UNIT          0x16  // make LUN accessible only to certain initiators
+#define SCSI_CMD_RELEASE_UNIT          0x17  // make LUN accessible to other initiators
+#define SCSI_CMD_COPY                  0x18  // autonomous copy from/to another device
+#define SCSI_CMD_ERASE                 0x19  //
+#define SCSI_CMD_MODE_SENSE            0x1a  // read device parameters
+#define SCSI_CMD_START_UNIT            0x1b  // load/unload medium
+#define SCSI_CMD_SCAN                  0x1b  // perform scan
+#define SCSI_CMD_STOP_PRINT            0x1b  // interrupt printing
+#define SCSI_CMD_RECV_DIAGNOSTIC       0x1c  // read self-test results
+#define SCSI_CMD_SEND_DIAGNOSTIC       0x1d  // initiate self-test
+#define SCSI_CMD_MEDIUM_REMOVAL        0x1e  // lock/unlock door
+#define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23 // read format capacities
+#define SCSI_CMD_SET_WINDOW            0x24  // set scanning window
+#define SCSI_CMD_GET_WINDOW            0x25  // get scanning window
+#define SCSI_CMD_READ_CAPACITY         0x25  // read number of logical blocks
+#define SCSI_CMD_READ10                0x28  // read
+#define SCSI_CMD_READ_GENERATION       0x29  // read max generation address of LBN
+#define SCSI_CMD_WRITE10               0x2a  // write
+#define SCSI_CMD_SEEK10                0x2b  // seek LBN
+#define SCSI_CMD_POSITION_TO_ELEMENT   0x2b  // media changer
+#define SCSI_CMD_ERASE10               0x2c  //
+#define SCSI_CMD_READ_UPDATED_BLOCK    0x2d  // read specific version of changed block
+#define SCSI_CMD_WRITE_VERIFY          0x2e  // write w/ verify of success
+#define SCSI_CMD_VERIFY                0x2f  // verify success
+#define SCSI_CMD_SEARCH_DATA_HIGH      0x30  // search for data pattern
+#define SCSI_CMD_SEARCH_DATA_EQUAL     0x31  // search for data pattern
+#define SCSI_CMD_SEARCH_DATA_LOW       0x32  // search for data pattern
+#define SCSI_CMD_SET_LIMITS            0x33  // define logical block boundaries
+#define SCSI_CMD_PREFETCH              0x34  // read data into buffer
+#define SCSI_CMD_READ_POSITION         0x34  // read current tape position
+#define SCSI_CMD_SYNC_CACHE            0x35  // re-read data into buffer
+#define SCSI_CMD_LOCKUNLOCK_CACHE      0x36  // lock/unlock data in cache
+#define SCSI_CMD_READ_DEFECT_DATA      0x37  //
+#define SCSI_CMD_MEDIUM_SCAN           0x38  // search for free area
+#define SCSI_CMD_COMPARE               0x39  // compare data
+#define SCSI_CMD_COPY_VERIFY           0x3a  // autonomous copy w/ verify
+#define SCSI_CMD_WRITE_BUFFER          0x3b  // write data buffer
+#define SCSI_CMD_READ_BUFFER           0x3c  // read data buffer
+#define SCSI_CMD_UPDATE_BLOCK          0x3d  // substitute block with an updated one
+#define SCSI_CMD_READ_LONG             0x3e  // read data and ECC
+#define SCSI_CMD_WRITE_LONG            0x3f  // write data and ECC
+#define SCSI_CMD_CHANGE_DEF            0x40  // set SCSI version
+#define SCSI_CMD_WRITE_SAME            0x41  //
+#define SCSI_CMD_READ_SUBCHANNEL       0x42  // read subchannel data and status
+#define SCSI_CMD_READ_TOC              0x43  // read contents table
+#define SCSI_CMD_READ_HEADER           0x44  // read LBN header
+#define SCSI_CMD_PLAY_AUDIO10          0x45  // audio playback
+#define SCSI_CMD_GET_CONFIGURATION     0x46  // get configuration (SCSI-3)
+#define SCSI_CMD_PLAY_AUDIO_MSF        0x47  // audio playback starting at MSF address
+#define SCSI_CMD_PLAY_AUDIO_TRACK      0x48  // audio playback starting at track/index
+#define SCSI_CMD_PLAY_AUDIO_RELATIVE   0x49  // audio playback starting at relative track
+#define SCSI_CMD_GET_EVENT_STATUS_NOTIFICATION 0x4a //
+#define SCSI_CMD_PAUSE                 0x4b  // audio playback pause/resume
+#define SCSI_CMD_LOG_SELECT            0x4c  // select statistics
+#define SCSI_CMD_LOG_SENSE             0x4d  // read statistics
+#define SCSI_CMD_STOP_PLAY             0x4e  // audio playback stop
+#define SCSI_CMD_READ_DISC_INFO        0x51  // info on CDRs
+#define SCSI_CMD_READ_TRACK_INFO       0x52  // track info on CDRs
+#define SCSI_CMD_RESERVE_TRACK         0x53  // leave space for data on CDRs
+#define SCSI_CMD_SEND_OPC_INFORMATION  0x54  // Optimum Power Calibration
+#define SCSI_CMD_MODE_SELECT10         0x55  // set device parameters
+#define SCSI_CMD_RESERVE_UNIT10        0x56  //
+#define SCSI_CMD_RELEASE_UNIT10        0x57  //
+#define SCSI_CMD_REPAIR_TRACK          0x58  //
+#define SCSI_CMD_MODE_SENSE10          0x5a  // read device parameters
+#define SCSI_CMD_CLOSE_SESSION         0x5b  // close area/sesssion (recordable)
+#define SCSI_CMD_READ_BUFFER_CAPACITY  0x5c  // CDR burning info.
+#define SCSI_CMD_SEND_CUE_SHEET        0x5d  // (CDR Related?)
+#define SCSI_CMD_PERSISTENT_RESERVE_IN 0x5e  //
+#define SCSI_CMD_PERSISTENT_RESERVE_OUT 0x5f //
+#define SCSI_CMD_XDWRITE_EXTENDED      0x80  //
+#define SCSI_CMD_REBUILD               0x81  //
+#define SCSI_CMD_REGENERATE            0x82  //
+#define SCSI_CMD_EXTENDED_COPY         0x83  // extended copy
+#define SCSI_CMD_RECEIVE_COPY_RESULTS  0x84  // receive copy results
+#define SCSI_CMD_READ16                0x88  // read data
+#define SCSI_CMD_WRITE16               0x8a  // write data
+#define SCSI_CMD_ORWRITE16             0x8b  //
+#define SCSI_CMD_READ_ATTRIBUTE        0x8c  // read attribute
+#define SCSI_CMD_WRITE_ATTRIBUTE       0x8d  // write attribute
+#define SCSI_CMD_WRITE_VERIFY16        0x8e  //
+#define SCSI_CMD_VERIFY16              0x8f  //
+#define SCSI_CMD_PREFETCH16            0x90  //
+#define SCSI_CMD_SYNC_CACHE16          0x91  //
+#define SCSI_CMD_WRITE_SAME16          0x93  //
+#define SCSI_CMD_READ_CAPACITY16       0x9e  // read number of logical blocks
+#define SCSI_CMD_WRITE_LONG16          0x9f  //
+#define SCSI_CMD_REPORT_LUNS           0xa0  //
+#define SCSI_CMD_BLANK                 0xa1  // erase RW media
+#define SCSI_CMD_SECURITY_PROTOCOL_IN  0xa2  //
+#define SCSI_CMD_MAINTENANCE_IN        0xa3  // service actions define reports
+#define SCSI_CMD_MAINTENANCE_OUT       0xa4  // service actions define changes
+#define SCSI_CMD_SEND_KEY              0xa3  //
+#define SCSI_CMD_REPORT_KEY            0xa4  // report key (SCSI-3)
+#define SCSI_CMD_MOVE_MEDIUM           0xa5  //
+#define SCSI_CMD_PLAY_AUDIO12          0xa5  // audio playback
+#define SCSI_CMD_EXCHANGE_MEDIUM       0xa6  //
+#define SCSI_CMD_LOADCD                0xa6  //
+#define SCSI_CMD_SET_READ_AHEAD        0xa7  //
+#define SCSI_CMD_READ12                0xa8  // read (SCSI-3)
+#define SCSI_CMD_PLAY_TRACK_RELATIVE   0xa9  // audio playback starting at relative track
+#define SCSI_CMD_WRITE12               0xaa  // write data
+#define SCSI_CMD_READ_MEDIA_SERIAL_NUMBER 0xab //
+#define SCSI_CMD_ERASE12               0xac  // erase logical block
+#define SCSI_CMD_GET_PERFORMANCE       0xac  //
+#define SCSI_CMD_READ_DVD_STRUCTURE    0xad  // read DVD structure (SCSI-3)
+#define SCSI_CMD_WRITE_VERIFY12        0xae  // write logical block, verify success
+#define SCSI_CMD_VERIFY12              0xaf  // verify data
+#define SCSI_CMD_SEARCH_DATA_HIGH12    0xb0  // search data pattern
+#define SCSI_CMD_SEARCH_DATA_EQUAL12   0xb1  // search data pattern
+#define SCSI_CMD_SEARCH_DATA_LOW12     0xb2  // search data pattern
+#define SCSI_CMD_SET_LIMITS12          0xb3  // set block limits
 #define SCSI_CMD_REQUEST_VOLUME_ELEMENT_ADDR 0xb5 //
-#define SCSI_CMD_SECURITY_PROTOCOL_OUT 0xb5
-#define SCSI_CMD_SEND_VOLUME_TAG       0xb6     //
-#define SCSI_CMD_SET_STREAMING         0xb6     // For avoiding over/underrun
-#define SCSI_CMD_READ_DEFECT_DATA12    0xb7    // read defect data information
-#define SCSI_CMD_READ_ELEMENT_STATUS   0xb8    // read element status
-#define SCSI_CMD_SELECT_CDROM_SPEED    0xb8    // set data rate
-#define SCSI_CMD_READ_CD_MSF          0xb9     // read CD information (all formats, MSF addresses)
-#define SCSI_CMD_AUDIO_SCAN           0xba     // fast audio playback
-#define SCSI_CMD_SET_CDROM_SPEED       0xbb     // (proposed)
-#define SCSI_CMD_SEND_CDROM_XA_DATA    0xbc
-#define SCSI_CMD_PLAY_CD              0xbc
-#define SCSI_CMD_MECH_STATUS           0xbd
-#define SCSI_CMD_READ_CD              0xbe     // read CD information (all formats, MSF addresses)
-#define SCSI_CMD_SEND_DVD_STRUCTURE    0xbf    // burning DVDs?
+#define SCSI_CMD_SECURITY_PROTOCOL_OUT 0xb5  //
+#define SCSI_CMD_SEND_VOLUME_TAG       0xb6  //
+#define SCSI_CMD_SET_STREAMING         0xb6  // For avoiding over/underrun
+#define SCSI_CMD_READ_DEFECT_DATA12    0xb7  // read defect data information
+#define SCSI_CMD_READ_ELEMENT_STATUS   0xb8  // read element status
+#define SCSI_CMD_SELECT_CDROM_SPEED    0xb8  // set data rate
+#define SCSI_CMD_READ_CD_MSF           0xb9  // read CD information (all formats, MSF addresses)
+#define SCSI_CMD_AUDIO_SCAN            0xba  // fast audio playback
+#define SCSI_CMD_SET_CDROM_SPEED       0xbb  // (proposed)
+#define SCSI_CMD_SEND_CDROM_XA_DATA    0xbc  //
+#define SCSI_CMD_PLAY_CD               0xbc  //
+#define SCSI_CMD_MECH_STATUS           0xbd  //
+#define SCSI_CMD_READ_CD               0xbe  // read CD information (all formats, MSF addresses)
+#define SCSI_CMD_SEND_DVD_STRUCTURE    0xbf  // burning DVDs?
 
 /*
- * A workaround for a specific scanner (NIKON LS-2000).  
+ * A workaround for a specific scanner (NIKON LS-2000).
  * Can be removed once Linux backend uses 2.4.x interface
  */
 #define SCSI_CMD_VENDOR_NIKON_UNKNOWN  0xe1
 
-#define SCSI_SENSE_KEY_NONE           0x0   // there is no sense information
+#define SCSI_SENSE_KEY_NONE            0x0   // there is no sense information
 #define SCSI_SENSE_KEY_RECOVERED_ERROR 0x1   // the last command completed succesfully but used error correction in the process
 #define SCSI_SENSE_KEY_NOT_READY       0x2   // the addressed LUN is not ready to be accessed
 #define SCSI_SENSE_KEY_MEDIUM_ERROR    0x3   // the target detected a data error on 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
+#define SCSI_SENSE_KEY_EQUAL           0xc   // comparison for SEARCH DATA was unsuccessful
 #define SCSI_SENSE_KEY_VOLUME_OVERFLOW 0xd   // the medium is full
 #define SCSI_SENSE_KEY_MISCOMPARE      0xe   // source and data on the medium do not agree
 
 /*
- * The Additional Sense Code - ASC             and
- *     Additional Sense Code Qualifiers - ASCQ
- * always come in pairs. 
+ * The Additional Sense Code - ASC
+ * and Additional Sense Code Qualifiers - ASCQ
+ * always come in pairs.
  *
  * Note:
  *     These values are found at senseBuffer[12} and senseBuffer[13].
  *     You may see references to these in legacy code. New code should make an
  *     attempt to use the ASC/ASCQ syntax.
  */
-#define SCSI_ASC_LU_NOT_READY                                   0x04  // logical unit not ready
-#define SCSI_ASC_LU_NOT_READY_ASCQ_UNIT_BECOMING_READY               0x01
-#define SCSI_ASC_LU_NOT_READY_ASCQ_INIT_CMD_REQUIRED                 0x02  // initializing command required
-#define SCSI_ASC_LU_NOT_READY_ASCQ_MANUAL_INTERVENTION_REQUIRED      0x03
-#define SCSI_ASC_LU_NOT_READY_ASCQ_TARGET_PORT_IN_TRANSITION        0x0a // an ascq
-#define SCSI_ASC_LU_NOT_READY_ASCQ_TARGET_PORT_IN_STANDBY_MODE       0x0b // an ascq
-#define SCSI_ASC_LU_NO_RESPONSE_TO_SELECTION                    0x05  // logical unit doesn't respond to selection
-#define SCSI_ASC_NO_REFERENCE_POSITION_FOUND                    0x06
-#define SCSI_ASC_WRITE_ERROR                                    0x0c  // Write error
-#define SCSI_ASC_UNRECOVERED_READ_ERROR                         0x11  // Unrecovered read error
-#define SCSI_ASC_PARAM_LIST_LENGTH_ERROR                        0x1a  // parameter list length error
-#define SCSI_ASC_RECOVERED_DATA                                 0x17
-#define SCSI_ASC_INVALID_COMMAND_OPERATION                     0x20  // invalid command operation code
-#define SCSI_ASC_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE             0x21  // Invalid LBA
-#define SCSI_ASC_INVALID_FIELD_IN_CDB                           0x24
-#define SCSI_ASC_LU_NOT_SUPPORTED                               0x25  // LU has been removed
-#define SCSI_ASC_INVALID_FIELD_IN_PARAMETER_LIST                0x26
-#define SCSI_ASC_WRITE_PROTECTED                               0x27  // device is write protected
-#define SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED                        0x28  // after changing medium
-#define SCSI_ASC_POWER_ON_OR_RESET                                     0x29  // device power-on or SCSI reset
-#define SCSI_ASC_ASYMMETRIC_ACCESS_STATE_CHANGED                0x2a
-#define SCSI_ASC_INCOMPATIBLE_MEDIUM                            0x30  // Generic bad medium error
-#define SCSI_ASC_SAVING_PARAMS_NOT_SUPPORTED                    0x39  // Saving parameters not supported
-#define SCSI_ASC_MEDIUM_NOT_PRESENT                             0x3a  // changing medium
-#define SCSI_ASC_MEDIUM_NOT_PRESENT_ASCQ_TRAY_OPEN              0x02 // an ascq
-#define SCSI_ASC_INVALID_MESSAGE_ERROR                          0x49
-#define SCSI_ASC_COMMAND_PHASE_ERROR                            0x4a
-#define SCSI_ASC_DATA_PHASE_ERROR                               0x4b
-#define SCSI_ASC_MEDIUM_REMOVAL_FAILED                          0x53 // w/ 0x4 it is failed, 0x5 is prevented
-#define SCSI_ASC_INSUFFICIENT_REGISTRATION_RESOURCES            0x55 // during persistent reservations
-#define SCSI_ASCQ_INSUFFICIENT_REGISTRATION_RESOURCES           0x04 
-#define SCSI_ASCQ_ASYMMETRIC_ACCESS_STATE_CHANGED               0x06
-#define SCSI_ASCQ_TARGET_PORT_IN_STANDBY_STATE                  0x0b
-#define SCSI_ASCQ_TARGET_PORT_IN_UNAVAILABLE_STATE              0x0c
-#define SCSI_ASC_INVALID_MODE_FOR_THIS_TRACK                    0x64 
-
-#define SCSI_TAG_ENABLE                0x20    // Set to indicate tag is valid
-#define SCSI_TAG_SIMPLE                (SCSI_TAG_ENABLE|0x0)   // No constraint
-#define SCSI_TAG_HEAD          (SCSI_TAG_ENABLE|0x1)   // Always first
-#define SCSI_TAG_ORDER         (SCSI_TAG_ENABLE|0x2)   // Syncronizing
+#define SCSI_ASC_LU_NOT_READY                                  0x04  // logical unit not ready
+#define SCSI_ASC_LU_NOT_READY_ASCQ_UNIT_BECOMING_READY         0x01
+#define SCSI_ASC_LU_NOT_READY_ASCQ_INIT_CMD_REQUIRED           0x02  // initializing command required
+#define SCSI_ASC_LU_NOT_READY_ASCQ_MANUAL_INTERVENTION_REQUIRED   0x03
+#define SCSI_ASC_LU_NOT_READY_ASCQ_TARGET_PORT_IN_TRANSITION      0x0a  // an ascq
+#define SCSI_ASC_LU_NOT_READY_ASCQ_TARGET_PORT_IN_STANDBY_MODE    0x0b  // an ascq
+#define SCSI_ASC_LU_NO_RESPONSE_TO_SELECTION                   0x05  // logical unit doesn't respond to selection
+#define SCSI_ASC_NO_REFERENCE_POSITION_FOUND                   0x06
+#define SCSI_ASC_WRITE_ERROR                                   0x0c  // Write error
+#define SCSI_ASC_UNRECOVERED_READ_ERROR                        0x11  // Unrecovered read error
+#define SCSI_ASC_PARAM_LIST_LENGTH_ERROR                       0x1a  // parameter list length error
+#define SCSI_ASC_RECOVERED_DATA                                0x17
+#define SCSI_ASC_INVALID_COMMAND_OPERATION                     0x20  // invalid command operation code
+#define SCSI_ASC_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE            0x21  // Invalid LBA
+#define SCSI_ASC_INVALID_FIELD_IN_CDB                          0x24
+#define SCSI_ASC_LU_NOT_SUPPORTED                              0x25  // LU has been removed
+#define SCSI_ASC_INVALID_FIELD_IN_PARAMETER_LIST               0x26
+#define SCSI_ASC_WRITE_PROTECTED                               0x27  // device is write protected
+#define SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED                       0x28  // after changing medium
+#define SCSI_ASC_POWER_ON_OR_RESET                             0x29  // device power-on or SCSI reset
+#define SCSI_ASC_ASYMMETRIC_ACCESS_STATE_CHANGED               0x2a
+#define SCSI_ASC_INCOMPATIBLE_MEDIUM                           0x30  // Generic bad medium error
+#define SCSI_ASC_SAVING_PARAMS_NOT_SUPPORTED                   0x39  // Saving parameters not supported
+#define SCSI_ASC_MEDIUM_NOT_PRESENT                            0x3a  // changing medium
+#define SCSI_ASC_MEDIUM_NOT_PRESENT_ASCQ_TRAY_OPEN             0x02  // an ascq
+#define SCSI_ASC_INVALID_MESSAGE_ERROR                         0x49
+#define SCSI_ASC_COMMAND_PHASE_ERROR                           0x4a
+#define SCSI_ASC_DATA_PHASE_ERROR                              0x4b
+#define SCSI_ASC_MEDIUM_REMOVAL_FAILED                         0x53  // w/ 0x4 it is failed, 0x5 is prevented
+#define SCSI_ASC_INSUFFICIENT_REGISTRATION_RESOURCES           0x55  // during persistent reservations
+#define SCSI_ASCQ_INSUFFICIENT_REGISTRATION_RESOURCES          0x04
+#define SCSI_ASCQ_ASYMMETRIC_ACCESS_STATE_CHANGED              0x06
+#define SCSI_ASCQ_TARGET_PORT_IN_STANDBY_STATE                 0x0b
+#define SCSI_ASCQ_TARGET_PORT_IN_UNAVAILABLE_STATE             0x0c
+#define SCSI_ASC_INVALID_MODE_FOR_THIS_TRACK                   0x64
+
+#define SCSI_TAG_ENABLE 0x20                    // Set to indicate tag is valid
+#define SCSI_TAG_SIMPLE (SCSI_TAG_ENABLE|0x0)   // No constraint
+#define SCSI_TAG_HEAD   (SCSI_TAG_ENABLE|0x1)   // Always first
+#define SCSI_TAG_ORDER  (SCSI_TAG_ENABLE|0x2)   // Syncronizing
 
 #define SCSI_CMD_START_UNIT_START_BIT 0x01   // Value of Start bit for SCSI_CMD_START_UNIT
 
  * We do not support 16-byte CDB's, only 6-, 10-, and 12-byte versions.
  */
 typedef struct {
-   uint32   opcode:8,  // operation code
-           lun:3,      // logical unit number
-           lbn:21;     // logical block number
-   uint8    len;       // data length
-   uint8    ctrl;      // control byte
+   uint8    opcode;     // operation code
+   uint8    lbnhi:5,    // top 5 bits of logical block number
+            lun:3;      // logical unit number
+   uint16   lbnlo;      // bottom 16 bits of logical block number
+   uint8    length;     // data length
+   uint8    control;    // control byte
 } SCSICDB6;
 typedef
 #include "vmware_pack_begin.h"
 struct {
    uint8    opcode;
    uint8       :5,
-           lun:3;
+            lun:3;
    uint32   lbn;
    uint8    reserved;
-   uint16   len;
-   uint8    ctrl;
+   uint16   length;
+   uint8    control;
 }
 #include "vmware_pack_end.h"
 SCSICDB10;
@@ -308,11 +310,11 @@ typedef
 struct {
    uint8    opcode;
    uint8       :5,
-           lun:3;
+            lun:3;
    uint32   lbn;
-   uint32   len;
+   uint32   length;
    uint8    reserved;
-   uint8    ctrl;
+   uint8    control;
 }
 #include "vmware_pack_end.h"
 SCSICDB12;
@@ -329,13 +331,13 @@ typedef struct {
          resv12:3,
          lun   :3;
    uint8 pagecode;         // only valid when cmddt or evdp is set
-   uint8 reserved;        
-   uint8 len;
-   uint8 ctrl;
+   uint8 reserved;
+   uint8 length;
+   uint8 control;
 } SCSIInquiryCmd;
 
-/* 
- * Format of the SCSI-3 INQUIRY command as defined in SPC-3 
+/*
+ * Format of the SCSI-3 INQUIRY command as defined in SPC-3
  */
 typedef struct {
    uint8 opcode;           // INQUIRY (0x12)
@@ -343,81 +345,81 @@ typedef struct {
          obslt :1,         // Obsolete as per SPC-3
          resv  :6;         // The remaining bits are all RESERVED
    uint8 pagecode;         // Only valid when evpd is set
-   uint8 lenMSB;           // The SPC-3 spec has a 2 byte len field
-   uint8 len;
-   uint8 ctrl;
+   uint8 lengthMSB;        // The SPC-3 spec has a 2 byte len field
+   uint8 length;
+   uint8 control;
 } SCSI3InquiryCmd;
 
 typedef struct {
    uint8 devclass    :5,   // SCSI device class
-#define SCSI_CLASS_DISK           0x00     // disk drive
-#define SCSI_CLASS_TAPE           0x01     // tape drive
-#define SCSI_CLASS_PRINTER 0x02            // printer
-#define SCSI_CLASS_CPU    0x03     // processor device
-#define SCSI_CLASS_WORM           0x04     // WORM drive
-#define SCSI_CLASS_CDROM   0x05            // CD-ROM drive
-#define SCSI_CLASS_SCANNER 0x06            // scanner
-#define SCSI_CLASS_OPTICAL 0x07            // optical disk
-#define SCSI_CLASS_MEDIA   0x08            // media changer
-#define SCSI_CLASS_COM    0x09     // communication device
-#define SCSI_CLASS_RAID           0x0c     // RAID controller (SCSI-3, reserved in SCSI-2)
-#define SCSI_CLASS_SES            0x0d     // SCSI Enclosure Services device (t10 SES)
-#define SCSI_CLASS_UNKNOWN 0x1f            // unknown device
-        pqual       :3;   // peripheral qualifier
-#define SCSI_PQUAL_CONNECTED    0  // device described is connected to the LUN
-#define SCSI_PQUAL_NOTCONNECTED         1  // target supports such a device, but none is connected
-#define SCSI_PQUAL_NODEVICE     3  // target does not support a physical device for this LUN
-   uint8    :7,                   // reserved for SCSI-1
-        rmb:1;            // removable bit
-   uint8 ansi       :3,   // ANSI version
-#define SCSI_ANSI_SCSI1             0x0   // device supports SCSI-1
-#define SCSI_ANSI_CCS       0x1   // device supports the CCS
-#define SCSI_ANSI_SCSI2             0x2   // device supports SCSI-2
+#define SCSI_CLASS_DISK    0x00      // disk drive
+#define SCSI_CLASS_TAPE    0x01      // tape drive
+#define SCSI_CLASS_PRINTER 0x02      // printer
+#define SCSI_CLASS_CPU     0x03      // processor device
+#define SCSI_CLASS_WORM    0x04      // WORM drive
+#define SCSI_CLASS_CDROM   0x05      // CD-ROM drive
+#define SCSI_CLASS_SCANNER 0x06      // scanner
+#define SCSI_CLASS_OPTICAL 0x07      // optical disk
+#define SCSI_CLASS_MEDIA   0x08      // media changer
+#define SCSI_CLASS_COM     0x09      // communication device
+#define SCSI_CLASS_RAID    0x0c      // RAID controller (SCSI-3, reserved in SCSI-2)
+#define SCSI_CLASS_SES     0x0d      // SCSI Enclosure Services device (t10 SES)
+#define SCSI_CLASS_UNKNOWN 0x1f      // unknown device
+         pqual       :3;   // peripheral qualifier
+#define SCSI_PQUAL_CONNECTED     0  // device described is connected to the LUN
+#define SCSI_PQUAL_NOTCONNECTED  1  // target supports such a device, but none is connected
+#define SCSI_PQUAL_NODEVICE      3  // target does not support a physical device for this LUN
+   uint8             :7,   // reserved for SCSI-1
+         rmb         :1;   // removable bit
+   uint8 ansi        :3,   // ANSI version
+#define SCSI_ANSI_SCSI1      0x0   // device supports SCSI-1
+#define SCSI_ANSI_CCS        0x1   // device supports the CCS
+#define SCSI_ANSI_SCSI2      0x2   // device supports SCSI-2
 #define SCSI_ANSI_SCSI3_SPC  0x3   // device supports SCSI-3 version SPC
 #define SCSI_ANSI_SCSI3_SPC2 0x4   // device supports SCSI-3 version SPC-2
 #define SCSI_ANSI_SCSI3_SPC3 0x5   // device supports SCSI-3 version SPC-3
 #define SCSI_ANSI_SCSI3_SPC4 0x6   // device supports SCSI-3 version SPC-4
-        ecma        :3,   // ECMA version
-        iso         :2;   // ISO version
+         ecma        :3,   // ECMA version
+         iso         :2;   // ISO version
    uint8 dataformat  :4,   // format of the following standard data
-                    :1,
-        naca        :1,
-        tio         :1,   // device supports TERMINATE I/O PROCESS message
-        aen         :1;   // asynchronous event notification capability
-   uint8 optlen;          // length of additional data that follows
-   uint8       :4,
-         tpgs  :2,         // Target Portal Group Support
-               :2;
+                     :1,
+         naca        :1,
+         tio         :1,   // device supports TERMINATE I/O PROCESS message
+         aen         :1;   // asynchronous event notification capability
+   uint8 optlen;           // length of additional data that follows
+   uint8             :4,
+         tpgs        :2,   // Target Portal Group Support
+                     :2;
 #define SCSI_TPGS_NONE                       0x0
 #define SCSI_TPGS_IMPLICIT_ONLY              0x1
-#define SCSI_TPGS_IMPLICIT                  SCSI_TPGS_IMPLICIT_ONLY 
+#define SCSI_TPGS_IMPLICIT                   SCSI_TPGS_IMPLICIT_ONLY
 #define SCSI_TPGS_EXPLICIT_ONLY              0x2
 #define SCSI_TPGS_EXPLICIT                   SCSI_TPGS_EXPLICIT_ONLY
 #define SCSI_TPGS_BOTH_IMPLICIT_AND_EXPLICIT 0x3
 #define SCSI_TPGS_BOTH                       SCSI_TPGS_BOTH_IMPLICIT_AND_EXPLICIT
-   uint8 adr16      :1,   // device supports 16-bit wide SCSI addresses
-        adr32       :1,   // device supports 32-bit wide SCSI addresses
-        arq         :1,
-        mchngr      :1,   // device has attached media changer (SCSI-3)
-        dualp       :1,   // device is dual-ported (SCSI-3)
-         port       :1,   // port A or port B when dual-ported (SCSI-3)
-                    :2;
-   uint8 sftr       :1,   // device supports soft reset capability
-        que         :1,   // device supports tagged commands
-        trndis      :1,   // device supports transfer disable messages (SCSI-3)
-        link        :1,   // device supports linked commands
-        sync        :1,   // device supports synchronous transfers
-        w16         :1,   // device supports 16-bit wide SCSI data transfers
-         w32        :1,   // device supports 32-bit wide SCSI data transfers
-        rel         :1;   // device supports relative addressing
+   uint8 adr16       :1,   // device supports 16-bit wide SCSI addresses
+         adr32       :1,   // device supports 32-bit wide SCSI addresses
+         arq         :1,
+         mchngr      :1,   // device has attached media changer (SCSI-3)
+         dualp       :1,   // device is dual-ported (SCSI-3)
+         port        :1,   // port A or port B when dual-ported (SCSI-3)
+                     :2;
+   uint8 sftr        :1,   // device supports soft reset capability
+         que         :1,   // device supports tagged commands
+         trndis      :1,   // device supports transfer disable messages (SCSI-3)
+         link        :1,   // device supports linked commands
+         sync        :1,   // device supports synchronous transfers
+         w16         :1,   // device supports 16-bit wide SCSI data transfers
+         w32         :1,   // device supports 32-bit wide SCSI data transfers
+         rel         :1;   // device supports relative addressing
    uint8 manufacturer[8];  // manufacturer's name in ascii
 #define SCSI_VENDOR_SZ sizeof(((SCSIInquiryResponse *) 0)->manufacturer)
-   uint8 product[16];     // product name in ascii
+   uint8 product[16];      // product name in ascii
 #define SCSI_MODEL_SZ sizeof(((SCSIInquiryResponse *) 0)->product)
-   uint8 revision[4];     // product version number in ascii
-   uint8 vendor1[20];     // vendor unique data (opaque)
+   uint8 revision[4];      // product version number in ascii
+   uint8 vendor1[20];      // vendor unique data (opaque)
    uint8 reserved[40];
-} SCSIInquiryResponse;    // standard INQUIRY response format
+} SCSIInquiryResponse;     // standard INQUIRY response format
 
 /*
  * Same as SCSIInquiryResponse, except that only 36 bytes long.  See above
@@ -426,39 +428,39 @@ typedef struct {
  */
 typedef struct {
    uint8 devclass    :5,   // SCSI device class
-        pqual       :3;   // peripheral qualifier
-   uint8    :7,                   // reserved for SCSI-1
-        rmb:1;            // removable bit
-   uint8 ansi       :3,   // ANSI version
-        ecma        :3,   // ECMA version
-        iso         :2;   // ISO version
+         pqual       :3;   // peripheral qualifier
+   uint8             :7,   // reserved for SCSI-1
+         rmb         :1;   // removable bit
+   uint8 ansi        :3,   // ANSI version
+         ecma        :3,   // ECMA version
+         iso         :2;   // ISO version
    uint8 dataformat  :4,   // format of the following standard data
-                    :1,
-        naca        :1,
-        tio         :1,   // device supports TERMINATE I/O PROCESS message
-        aen         :1;   // asynchronous event notification capability
-   uint8 optlen;          // length of additional data that follows
-   uint8       :4,
-         tpgs  :2,         // Target Portal Group Support
-               :2;
-   uint8 adr16      :1,   // device supports 16-bit wide SCSI addresses
-        adr32       :1,   // device supports 32-bit wide SCSI addresses
-        arq         :1,
-        mchngr      :1,   // device has attached media changer (SCSI-3)
-        dualp       :1,   // device is dual-ported (SCSI-3)
-         port       :1,   // port A or port B when dual-ported (SCSI-3)
-                    :2;
-   uint8 sftr       :1,   // device supports soft reset capability
-        que         :1,   // device supports tagged commands
-        trndis      :1,   // device supports transfer disable messages (SCSI-3)
-        link        :1,   // device supports linked commands
-        sync        :1,   // device supports synchronous transfers
-        w16         :1,   // device supports 16-bit wide SCSI data transfers
-         w32        :1,   // device supports 32-bit wide SCSI data transfers
-        rel         :1;   // device supports relative addressing
+                     :1,
+         naca        :1,
+         tio         :1,   // device supports TERMINATE I/O PROCESS message
+         aen         :1;   // asynchronous event notification capability
+   uint8 optlen;           // length of additional data that follows
+   uint8             :4,
+         tpgs        :2,   // Target Portal Group Support
+                     :2;
+   uint8 adr16       :1,   // device supports 16-bit wide SCSI addresses
+         adr32       :1,   // device supports 32-bit wide SCSI addresses
+         arq         :1,
+         mchngr      :1,   // device has attached media changer (SCSI-3)
+         dualp       :1,   // device is dual-ported (SCSI-3)
+         port        :1,   // port A or port B when dual-ported (SCSI-3)
+                     :2;
+   uint8 sftr        :1,   // device supports soft reset capability
+         que         :1,   // device supports tagged commands
+         trndis      :1,   // device supports transfer disable messages (SCSI-3)
+         link        :1,   // device supports linked commands
+         sync        :1,   // device supports synchronous transfers
+         w16         :1,   // device supports 16-bit wide SCSI data transfers
+         w32         :1,   // device supports 32-bit wide SCSI data transfers
+         rel         :1;   // device supports relative addressing
    uint8 manufacturer[8];  // manufacturer's name in ascii
-   uint8 product[16];     // product name in ascii
-   uint8 revision[4];     // product version number in ascii
+   uint8 product[16];   // product name in ascii
+   uint8 revision[4];   // product version number in ascii
 } SCSIInquiry36Response;   // standard INQUIRY response format
 
 #define SCSI_STANDARD_INQUIRY_MIN_LENGTH 36
@@ -470,17 +472,17 @@ typedef struct {
 /*
  * The following structures define the Page format supported by the
  * vscsi layer in vmkernel. The SPC-3 r23 spec defines a very generic
- * layout of these pages, however the structures here are customized 
+ * layout of these pages, however the structures here are customized
  * for vmkernel.
  */
 typedef
 #include "vmware_pack_begin.h"
 struct SCSIInqPage00ResponseHeader {
-   uint8  devClass     :5,
-         pQual         :3;
-   uint8  pageCode;
-   uint8  reserved1;
-   uint8  pageLength;
+   uint8 devClass :5,
+         pQual    :3;
+   uint8 pageCode;
+   uint8 reserved1;
+   uint8 pageLength;
 }
 #include "vmware_pack_end.h"
 SCSIInqPage00ResponseHeader;
@@ -488,58 +490,58 @@ SCSIInqPage00ResponseHeader;
 typedef
 #include "vmware_pack_begin.h"
 struct SCSIInqPage80ResponseHeader {
-   uint8  devClass     :5,
-         pQual         :3;
-   uint8  pageCode;
-   uint8  reserved1;
-   uint8  pageLength;
+   uint8 devClass :5,
+         pQual    :3;
+   uint8 pageCode;
+   uint8 reserved1;
+   uint8 pageLength;
 }
 #include "vmware_pack_end.h"
 SCSIInqPage80ResponseHeader;
 
 // Inquiry page 0x83: Identifier Type
-#define SCSI_IDENTIFIERTYPE_VENDOR_SPEC        0x0
-#define SCSI_IDENTIFIERTYPE_T10                0x1
-#define SCSI_IDENTIFIERTYPE_EUI                0x2
-#define SCSI_IDENTIFIERTYPE_NAA                0x3
-#define SCSI_IDENTIFIERTYPE_RTPI       0x4
-#define SCSI_IDENTIFIERTYPE_TPG                0x5
-#define SCSI_IDENTIFIERTYPE_LUG                0x6
-#define SCSI_IDENTIFIERTYPE_MD5                0x7
-#define SCSI_IDENTIFIERTYPE_SNS        0x8
-#define SCSI_IDENTIFIERTYPE_RESERVED           0x9
-#define SCSI_IDENTIFIERTYPE_MAX         SCSI_IDENTIFIERTYPE_RESERVED
+#define SCSI_IDENTIFIERTYPE_VENDOR_SPEC   0x0
+#define SCSI_IDENTIFIERTYPE_T10           0x1
+#define SCSI_IDENTIFIERTYPE_EUI           0x2
+#define SCSI_IDENTIFIERTYPE_NAA           0x3
+#define SCSI_IDENTIFIERTYPE_RTPI          0x4
+#define SCSI_IDENTIFIERTYPE_TPG           0x5
+#define SCSI_IDENTIFIERTYPE_LUG           0x6
+#define SCSI_IDENTIFIERTYPE_MD5           0x7
+#define SCSI_IDENTIFIERTYPE_SNS           0x8
+#define SCSI_IDENTIFIERTYPE_RESERVED      0x9
+#define SCSI_IDENTIFIERTYPE_MAX           SCSI_IDENTIFIERTYPE_RESERVED
 
 // Inquiry page 0x83: Transport Layer
-#define SCSI_PROTOCOLID_FCP2           0x0
-#define SCSI_PROTOCOLID_SPI5           0x1
-#define SCSI_PROTOCOLID_SSAS3P         0x2
-#define SCSI_PROTOCOLID_SBP3           0x3
-#define SCSI_PROTOCOLID_SRP            0x4
-#define SCSI_PROTOCOLID_ISCSI          0x5
-#define SCSI_PROTOCOLID_SAS            0x6
-#define SCSI_PROTOCOLID_ADT            0x7
-#define SCSI_PROTOCOLID_ATA            0x8
-#define SCSI_PROTOCOLID_RESERVED       0xE
-#define SCSI_PROTOCOLID_NO_PROTOCOL    0xF
+#define SCSI_PROTOCOLID_FCP2        0x0
+#define SCSI_PROTOCOLID_SPI5        0x1
+#define SCSI_PROTOCOLID_SSAS3P      0x2
+#define SCSI_PROTOCOLID_SBP3        0x3
+#define SCSI_PROTOCOLID_SRP         0x4
+#define SCSI_PROTOCOLID_ISCSI       0x5
+#define SCSI_PROTOCOLID_SAS         0x6
+#define SCSI_PROTOCOLID_ADT         0x7
+#define SCSI_PROTOCOLID_ATA         0x8
+#define SCSI_PROTOCOLID_RESERVED    0xE
+#define SCSI_PROTOCOLID_NO_PROTOCOL 0xF
 
 // Inquiry page 0x83: UUID Encoding
-#define SCSI_CODESET_BINARY            0x1
-#define SCSI_CODESET_ASCII             0x2
-#define SCSI_CODESET_UTF8              0x3
-#define SCSI_CODESET_RESERVED          0xF
+#define SCSI_CODESET_BINARY   0x1
+#define SCSI_CODESET_ASCII    0x2
+#define SCSI_CODESET_UTF8     0x3
+#define SCSI_CODESET_RESERVED 0xF
 
 // Inquiry page 0x83: UUID Entity
-#define SCSI_ASSOCIATION_LUN           0x0
-#define SCSI_ASSOCIATION_TARGET_PORT   0x1
-#define SCSI_ASSOCIATION_TARGET_DEVICE 0x2
-#define SCSI_ASSOCIATION_RESERVED      0x3
+#define SCSI_ASSOCIATION_LUN           0x0
+#define SCSI_ASSOCIATION_TARGET_PORT   0x1
+#define SCSI_ASSOCIATION_TARGET_DEVICE 0x2
+#define SCSI_ASSOCIATION_RESERVED      0x3
 
 typedef
 #include "vmware_pack_begin.h"
 struct SCSIInqPage83ResponseHeader {
-   uint8  devClass     :5,
-          pQual                :3;
+   uint8  devClass   :5,
+          pQual      :3;
    uint8  pageCode;
    uint16 pageLength;
 }
@@ -579,11 +581,11 @@ typedef
 #include "vmware_pack_begin.h"
 struct SCSI2InqPage83ResponseDescriptor {
    /* Identification Descriptor follows */
-   uint8  codeSet     :4, 
-          reserved    :4; 
-   uint8  idType      :4, 
+   uint8  codeSet     :4,
+          reserved    :4;
+   uint8  idType      :4,
           association :2,
-          reserved1   :2; 
+          reserved1   :2;
    uint8  reserved2;
    uint8  idLength;
 }
@@ -641,12 +643,12 @@ SCSIReportLunsResponse;
  * may need them.
  */
 typedef struct {
-   uint8    opcode;       // operation code
-   uint8         :3,
-           dbd   :1,      // disable block descriptors
-                 :1,
-           lun   :3;      // logical unit number
-   uint8    page         :6,      // page code
+   uint8 opcode;        // operation code
+   uint8          :3,
+         dbd      :1,   // disable block descriptors
+                  :1,
+         lun      :3;   // logical unit number
+   uint8 page     :6,   // page code
 #define SCSI_MS_PAGE_VENDOR   0x00     // vendor-specific (ALL)
 #define SCSI_MS_PAGE_RWERROR  0x01     // read/write error (DISK/TAPE/CDROM/OPTICAL)
 #define SCSI_MS_PAGE_CONNECT  0x02     // disconnect/connect (ALL)
@@ -672,14 +674,14 @@ typedef struct {
 #define SCSI_MS_PAGE_CDCAPS   0x2a     // CD-ROM capabilities and mechanical status (CDROM)
 // more defined...
 #define SCSI_MS_PAGE_ALL      0x3f     // all available pages (ALL)
-           pcf   :2;      // page control field
+         pcf      :2;   // page control field
 #define SCSI_MS_PCF_CURRENT   0x00     // current values
 #define SCSI_MS_PCF_VOLATILE  0x01     // changeable values
 #define SCSI_MS_PCF_DEFAULT   0x02     // default values
 #define SCSI_MS_PCF_SAVED     0x03     // saved values
    uint8    subpage;
-   uint8    length;  // data length
-   uint8    ctrl;         // control byte
+   uint8    length;        // data length
+   uint8    control;       // control byte
 } SCSIModeSenseCmd;
 
 
@@ -689,11 +691,11 @@ typedef struct {
 typedef
 #include "vmware_pack_begin.h"
 struct {
-   uint8  opcode;         // FORMAT UNIT (0x4)
-   uint8  dlf    :3,      // defect list format
-         cmplst :1,       // complete list
-         fmtdata:1,       // format data
-         lun    :3;
+   uint8  opcode;    // FORMAT UNIT (0x4)
+   uint8  dlf    :3, // defect list format
+          cmplst :1, // complete list
+          fmtdata:1, // format data
+          lun    :3;
    uint8  vendor;
    uint16 interleave;
    uint8  control;
@@ -705,81 +707,81 @@ SCSIFormatCmd;
  * Format Defect List header
  */
 typedef struct {
-   uint8 reserved;        
-   uint8 fov   :1,        // Format options valid
-        dpry  :1,         // disable primary
-        dcrt  :1,         // disable certification
-        stpf  :1,         // stop format
-        ip    :1,         // initialization pattern
-        dsp   :1,         // disable saving parameters
-        immed :1,         // immediate 
-        vs    :1;
-   uint16 length;         // Defect list length
+   uint8 reserved;
+   uint8 fov   :1,   // Format options valid
+         dpry  :1,   // disable primary
+         dcrt  :1,   // disable certification
+         stpf  :1,   // stop format
+         ip    :1,   // initialization pattern
+         dsp   :1,   // disable saving parameters
+         immed :1,   // immediate
+         vs    :1;
+   uint16 length;    // Defect list length
 } SCSIDefectListHdr;
 
-typedef 
+typedef
 #include "vmware_pack_begin.h"
 struct {
-   uint8    opcode;       // operation code
-   uint8         :3,
-           dbd   :1,      // disable block descriptors
-                 :1,
-           lun   :3;      // logical unit number
-   uint8    page  :6,     // page code
-           pcf   :2;      // page control field
+   uint8    opcode;        // operation code
+   uint8            :3,
+            dbd     :1,    // disable block descriptors
+                    :1,
+            lun     :3;    // logical unit number
+   uint8    page    :6,    // page code
+            pcf     :2;    // page control field
    uint8    reserved[4];
    uint16   length;       // data length
-   uint8    ctrl;         // control byte
+   uint8    control;       // control byte
 }
 #include "vmware_pack_end.h"
 SCSIModeSense10Cmd;
 
 typedef struct {
-   uint8    opcode;       // operation code
-   uint8    sp   :1,      // save pages
-                 :3,
-           pf    :1,      // page format
-           lun   :3;      // logical unit number
+   uint8    opcode;     // operation code
+   uint8    sp    :1,   // save pages
+                  :3,
+            pf    :1,   // page format
+            lun   :3;   // logical unit number
    uint8    reserved[2];
-   uint8    len;          // data length
-   uint8    ctrl;         // control byte
+   uint8    length;     // data length
+   uint8    control;    // control byte
 } SCSIModeSelectCmd;
 
-typedef 
+typedef
 #include "vmware_pack_begin.h"
 struct {
-   uint8    opcode;       // operation code
-   uint8    sp   :1,      // save pages
-                 :3,
-           pf    :1,      // page format
-           lun   :3;      // logical unit number
+   uint8    opcode;     // operation code
+   uint8    sp   :1,    // save pages
+                 :3,
+            pf   :1,    // page format
+            lun  :3;    // logical unit number
    uint8    reserved[5];
-   uint16   len;          // data length
-   uint8    ctrl;         // control byte
+   uint16   length;     // data length
+   uint8    control;    // control byte
 }
 #include "vmware_pack_end.h"
 SCSIModeSelect10Cmd;
 
 typedef struct {
-   uint8    len;          // data length
+   uint8    len;           // data length
    uint8    mediaType;
    uint8    devSpecific;   // device specific
-   uint8    bdLen;        // block descriptor length
+   uint8    bdLen;         // block descriptor length
 } SCSIModeHeader6;
 
 typedef struct {
-   uint16   len;          // data length
+   uint16   len;           // data length
    uint8    mediaType;
    uint8    devSpecific;   // device specific
    uint16   reserved;
-   uint16   bdLen;        // block descriptor length
+   uint16   bdLen;         // block descriptor length
 } SCSIModeHeader10;
 
 typedef struct {
-   uint8 reserved1:4;
-   uint8 dpofua:1;         // disable page out / force unit access
-   uint8 reserved2:2;
-   uint8 wp:1;             // write protected
+   uint8 reserved1:4,
+         dpofua   :1,   // disable page out / force unit access
+         reserved2:2,
+         wp       :1;   // write protected
 } SCSIBlockModeSenseDeviceParameter;
 
 /*
@@ -788,11 +790,11 @@ typedef struct {
 typedef
 #include "vmware_pack_begin.h"
 struct {
-   uint8 opcode:8;     // operation code
-   uint8 ext:1,
-      tid:3,
-      tparty:1,
-      lun:3;           // logical unit number
+   uint8    opcode:8;   // operation code
+   uint8    ext   :1,
+            tid   :3,
+            tparty:1,
+            lun   :3;   // logical unit number
    uint8    resid;
    uint16   extlen;
    uint8    control;
@@ -805,11 +807,11 @@ SCSIReserveCmd;
  * types (a fourth is added in SCSI-3).  The following structures
  * define these pages as sent+received with MODE SENSE and SELECT.
  */
-typedef struct {          // connect/disconnect page
-   uint8    page  :6,     // page code: 0x02
-                 :1,
-           ps    :1;
-   uint8    len;          // page length (0x0e)
+typedef struct {           // connect/disconnect page
+   uint8    page  :6,      // page code: 0x02
+                  :1,
+            ps    :1;
+   uint8    len;           // page length (0x0e)
    uint8    bufFull;
    uint8    bufEmpty;
    uint16   maxBusInactiveTime;
@@ -817,159 +819,159 @@ typedef struct {           // connect/disconnect page
    uint16   maxConnectTime;
    uint16   maxBurstLength;
    uint8    dtdc  :3,
-           dimm  :1,      // disconnect immediate (SCSI-3)
-                 :3,
-           emdp  :1;      // enable MODIFY DATA POINTER (SCSI-3)
+            dimm  :1,      // disconnect immediate (SCSI-3)
+                  :3,
+            emdp  :1;      // enable MODIFY DATA POINTER (SCSI-3)
 } SCSIConnectPage;
 
-typedef struct {          // peripheral device page
-   uint8    page  :6,     // page code: 0x09
-                 :1,
-           ps    :1;
-   uint8    len;          // page length (n-1)
-   uint16   ifID;         // physical interface identifier
+typedef struct {     // peripheral device page
+   uint8    page  :6,      // page code: 0x09
+                  :1,
+            ps    :1;
+   uint8    len;           // page length (n-1)
+   uint16   ifID;          // physical interface identifier
    uint8    reserved[4];
    uint8    undefined[1];  // variable-length vendor-specific data
 } SCSIPeriphPage;
 
 typedef struct {
-   uint8    page  :6,     // page code: 0x0a
-                 :1,
-           ps    :1;
-   uint8    len;          // page length (0x06)
+   uint8    page  :6,      // page code: 0x0a
+                  :1,
+            ps    :1;
+   uint8    len;           // page length (0x06)
    uint8    rlec  :1,
-           gltsd :1,
-                 :2,
-                 :4;
-   uint8    dque  :1,     // disable tagged queuing
-           qerr  :1,      // 
-                 :2,
-           qalg  :4;      // queue algorithm
-   uint8    eaenp :1,     // error AEN permission
-           uaaenp:1,      // unit attention AEN permission
-           raenp :1,      // ready AEN permission
-                 :4,
-           eeca  :1;      // 
+            gltsd :1,
+                  :2,
+                  :4;
+   uint8    dque  :1,      // disable tagged queuing
+            qerr  :1,      //
+                  :2,
+            qalg  :4;      // queue algorithm
+   uint8    eaenp :1,      // error AEN permission
+            uaaenp:1,      // unit attention AEN permission
+            raenp :1,      // ready AEN permission
+                  :4,
+            eeca  :1;      //
    uint8    reserved;
    uint16   aenWaitTime;   // AEN waiting time after initialization
    uint16   busyTimeout;   // busy timeout in 100ms (SCSI-3)
 } SCSIControlPage;
 
 typedef struct {
-   uint8    page  :6,     // page code: 0x09
-                 :1,
-           ps    :1;
-   uint8    len;          // page length 0x06
-   uint8    dcr          :1,      // error recover parameters
-           dte   :1,      // diable transfer on seeing recovered error
-           per   :1,      // post error: report recovered errors
-                 :1,
-           rc    :1,      // read continuous: don't delay data transfer to correct errors
-           tb    :1,      // transfer block when unrecovered
-                 :2;
+   uint8    page  :6,      // page code: 0x09
+                  :1,
+            ps    :1;
+   uint8    len;           // page length 0x06
+   uint8    dcr   :1,      // error recover parameters
+            dte   :1,      // diable transfer on seeing recovered error
+            per   :1,      // post error: report recovered errors
+                  :1,
+            rc    :1,      // read continuous: don't delay data transfer to correct errors
+            tb    :1,      // transfer block when unrecovered
+                  :2;
    uint8    readRetries;   // read retry count
    uint8    reserved[4];
 } SCSIRWErrorPage;
 
 typedef struct {
-   uint8    page  :6,     // page code: 0x0d
-                 :1,
-           ps    :1;
-   uint8    len;          // page length 0x06
-   uint8         :8;
-   uint8    inactive:4,           // head inactivity timeout
-                 :4;
+   uint8    page     :6,   // page code: 0x0d
+                     :1,
+            ps       :1;
+   uint8    len;           // page length 0x06
+   uint8             :8;
+   uint8    inactive :4,   // head inactivity timeout
+                     :4;
    uint16   secsPerMinute; // number of MSF seconds per MSF minute
    uint16   framesPerSec;  // number of MSF frames per MSF second
 } SCSICDROMPage;
 
 typedef struct {
-   uint8    page  :6,     // page code: 0x0e
-                 :1,
-           ps    :1;
-   uint8    len;          // page length 0x0e
-   uint8         :1,
-           sotb  :1,
-           immediate:1,
-                 :5;
-   uint8         :8;
-   uint8         :8;
+   uint8    page     :6,   // page code: 0x0e
+                     :1,
+            ps       :1;
+   uint8    len;           // page length 0x0e
+   uint8             :1,
+            sotb     :1,
+            immediate:1,
+                     :5;
+   uint8             :8;
+   uint8             :8;
    uint8    lbaFactor:4,
-                 :3,
-           aprv  :1;
-   uint16   lbaPerSec;    // number of LBAs per second
-   uint8    port0 :4,     // output port 0 select
-                 :4;
+                     :3,
+            aprv     :1;
+   uint16   lbaPerSec;     // number of LBAs per second
+   uint8    port0    :4,   // output port 0 select
+                     :4;
    uint8    port0Volume;
-   uint8    port1 :4,     // output port 1 select
-                 :4;
+   uint8    port1    :4,   // output port 1 select
+                     :4;
    uint8    port1Volume;
-   uint8    port2 :4,     // output port 2 select
-                 :4;
+   uint8    port2    :4,   // output port 2 select
+                     :4;
    uint8    port2Volume;
-   uint8    port3 :4,     // output port 3 select
-                 :4;
+   uint8    port3    :4,   // output port 3 select
+                     :4;
    uint8    port3Volume;
 } SCSICDROMAudioPage;
 
 typedef struct {
-   uint8    page  :6,     // page code: 0x2a
-                 :1,
-           ps    :1;
-   uint8    len;          // page length 0x12
-   uint8    cdrRd      :1,// CD-R read per Orange Book Part II
-           cdeRd       :1,// CD-E read per Orange Book Part III
-           method2     :1,// CD-R media w/ Addressing Method 2
-                       :5;
-   uint8    cdrWr      :1,// CD-R write per Orange Book Part II
-           cdeWr       :1,// CD-E write per Orange Book Part III
-                       :6;
-   uint8    audioPlay  :1,// drive is capable of audio play
-           composite   :1,// drive is capable of delivering composite audio+video
-           digPort1    :1,// drive supports digital output (IEC958) on port 1
-           digPort2    :1,// drive supports digital output on port 2
-           mode2Form1  :1,// drive reads Mode 2 Form 1 (XA) format
-           mode2Form2  :1,// drive reads Mode 2 Form 2 format
-           multiSession:1,// drive reads multi-session or Photo-CD discs
-                       :1;
-   uint8    cdDA       :1,// CD-DA commands (Red Book) supported
-           daAccu      :1,// CD-DA stream is accurate
-           rwSupported :1,// R-W supported
-           rwDeinter   :1,// R-W subchannel data de-interleaved and corrected
-           c2Ptrs      :1,// C2 Error Pointers supported
-           isrc        :1,// drive returns International Standard Recording Code Info
-           upc         :1,// drive returns Media Catalog Number
-                       :1;
-   uint8    lock       :1,// PREVENT/ALLOW commands lock media into drive
-           lockState   :1,// current state of drive
-           jumpers     :1,// state of prevent/allow jumpers
-           eject       :1,// drive can eject disc via START/STOP command
-                       :1,
-           loadType    :3;// loading mechanism type
-   uint8    sv         :1,// separate volume
-           scm         :1,// separate channel mute
-           sdp         :1,// supports disc present in MECHANISM STATUS command
-           sss         :1,// s/w slot selection w/ LOAD/UNLOCK command
-                       :4;
-   uint16   maxSpeed;     // maximum speed supported (in KB/s)
+   uint8    page     :6,   // page code: 0x2a
+                     :1,
+            ps       :1;
+   uint8    len;           // page length 0x12
+   uint8    cdrRd    :1,   // CD-R read per Orange Book Part II
+            cdeRd    :1,   // CD-E read per Orange Book Part III
+            method2  :1,   // CD-R media w/ Addressing Method 2
+                     :5;
+   uint8    cdrWr    :1,   // CD-R write per Orange Book Part II
+            cdeWr    :1,   // CD-E write per Orange Book Part III
+                     :6;
+   uint8    audioPlay:1,   // drive is capable of audio play
+            composite:1,   // drive is capable of delivering composite audio+video
+            digPort1 :1,   // drive supports digital output (IEC958) on port 1
+            digPort2 :1,   // drive supports digital output on port 2
+            mode2Form1:1,  // drive reads Mode 2 Form 1 (XA) format
+            mode2Form2:1,  // drive reads Mode 2 Form 2 format
+            multiSession:1,// drive reads multi-session or Photo-CD discs
+                     :1;
+   uint8    cdDA     :1,   // CD-DA commands (Red Book) supported
+            daAccu   :1,   // CD-DA stream is accurate
+            rwSupported:1, // R-W supported
+            rwDeinter:1,   // R-W subchannel data de-interleaved and corrected
+            c2Ptrs   :1,   // C2 Error Pointers supported
+            isrc     :1,   // drive returns International Standard Recording Code Info
+            upc      :1,   // drive returns Media Catalog Number
+                     :1;
+   uint8    lock     :1,   // PREVENT/ALLOW commands lock media into drive
+            lockState:1,   // current state of drive
+            jumpers  :1,   // state of prevent/allow jumpers
+            eject    :1,   // drive can eject disc via START/STOP command
+                     :1,
+            loadType :3;   // loading mechanism type
+   uint8    sv       :1,   // separate volume
+            scm      :1,   // separate channel mute
+            sdp      :1,   // supports disc present in MECHANISM STATUS command
+            sss      :1,   // s/w slot selection w/ LOAD/UNLOCK command
+                     :4;
+   uint16   maxSpeed;      // maximum speed supported (in KB/s)
    uint16   numVolLevels;  // number of volume levels supported
-   uint16   bufSize;      // buffer size supported by drive (KBytes)
-   uint16   curSpeed;     // current speed selected (in KB/s)
+   uint16   bufSize;       // buffer size supported by drive (KBytes)
+   uint16   curSpeed;      // current speed selected (in KB/s)
    uint8    reserved;
-   uint8               :1,// format of digital data output
-           bck         :1,// data is valid on the falling edge of BCK
-           rck         :1,// HIGH on LRCK indicates left channel
-           lsbf        :1,// LSB first
-           length      :2,
-                       :2;
+   uint8             :1,   // format of digital data output
+            bck      :1,   // data is valid on the falling edge of BCK
+            rck      :1,   // HIGH on LRCK indicates left channel
+            lsbf     :1,   // LSB first
+            length   :2,
+                     :2;
    uint8    reserved2[2];
 } SCSICDROMCapabilitiesPage;
 
 typedef struct {
-   uint8    page  :6,     // page code: 0x03
-                 :1,
-           ps    :1;
-   uint8    len;          // page length 0x16
+   uint8    page  :6,         // page code: 0x03
+                  :1,
+            ps    :1;
+   uint8    len;              // page length 0x16
    uint16   tracksPerZone;
    uint16   repSectorsPerZone;
    uint16   repTracksPerZone;
@@ -979,46 +981,46 @@ typedef struct {
    uint16   interleave;
    uint16   trackSkew;
    uint16   cylinderSkew;
-   uint8         :3,
-           surf  :1,
-           rmb   :1,
-           hsec  :1,
-           ssec  :1;
+   uint8          :3,
+            surf  :1,
+            rmb   :1,
+            hsec  :1,
+            ssec  :1;
    uint8    reserved[3];
 } SCSIFormatPage;
 
 typedef uint8 uint24[3];
 
 typedef struct {
-   uint8    page  :6,     // page code: 0x04
-                 :1,
-           ps    :1;
-   uint8    len;          // page length 0x16
-   uint24   cylinders;    // number of cylinders
-   uint8    heads;        // number of heads
+   uint8    page  :6,         // page code: 0x04
+                  :1,
+            ps    :1;
+   uint8    len;              // page length 0x16
+   uint24   cylinders;        // number of cylinders
+   uint8    heads;            // number of heads
    uint24   writeCompCylinder; // starting cylinder for write compensation
    uint24   writeCurCylinder; // starting cylinder for reduce write current
    uint16   stepRate;
-   uint24   landingZone;   // cylinder number of landing zone
-   uint8    rpl          :1,
-                 :7;
-   uint8    rotOffset;    // rotational offset
-   uint8         :8;
-   uint16   rotRate;      // medium rotation rate
+   uint24   landingZone;      // cylinder number of landing zone
+   uint8    rpl   :1,
+                  :7;
+   uint8    rotOffset;        // rotational offset
+   uint8          :8;
+   uint16   rotRate;          // medium rotation rate
    uint8    reserved[2];
 } SCSIGeometryPage;
 
 typedef struct {
-   uint8    page  :6,     // page code: 0x08
-                 :1,
-           ps    :1;
-   uint8    len;          // page length 0x0a (0x12 for SCSI-3)
-   uint8    rcd          :1,
-           mf    :1,
-           wce   :1,
-                 :5;
-   uint8    readPri:4,    // read retention priority
-           writePri:4;    // write retention priority
+   uint8    page     :6,   // page code: 0x08
+                     :1,
+            ps       :1;
+   uint8    len;           // page length 0x0a (0x12 for SCSI-3)
+   uint8    rcd      :1,
+            mf       :1,
+            wce      :1,
+                     :5;
+   uint8    readPri  :4,   // read retention priority
+            writePri :4;   // write retention priority
    uint16   prefetchDisable;// disable pre-fetch transfer length
    uint16   prefetchMin;   // pre-fetch minimum
    uint16   prefetchMax;   // pre-fetch maximum
@@ -1026,101 +1028,102 @@ typedef struct {
 } SCSICachePage;
 
 typedef struct {
-   uint8    page  :6,     // page code: 0x08
-                 :1,
-           ps    :1;
-   uint8    len;          // page length 0x16
-   uint8         :6,
-           lpn   :1,
-           nd    :1;
-   uint8         :8;
-   uint16   maxNotches;           // maximum number of notches
+   uint8    page  :6,   // page code: 0x08
+                  :1,
+            ps    :1;
+   uint8    len;        // page length 0x16
+   uint8          :6,
+            lpn   :1,
+            nd    :1;
+   uint8          :8;
+   uint16   maxNotches; // maximum number of notches
    uint16   activeNotch;
-   uint32   activeStart;   // beginning of active notch
-   uint32   activeEnd;    // end of active notch
+   uint32   activeStart;// beginning of active notch
+   uint32   activeEnd;  // end of active notch
 } SCSINotchPage;
 
 typedef struct {
-   uint8    page  :6,     // page code: 0x06
-                 :1,
-           ps    :1;
-   uint8    len;          // page length 0x02
+   uint8    page  :6,   // page code: 0x06
+                  :1,
+            ps    :1;
+   uint8    len;        // page length 0x02
    uint8    rubr  :1,
-                 :7;
-   uint8         :8;
+                  :7;
+   uint8          :8;
 } SCSIOpticalPage;
+
 typedef struct {
-   uint8    page  :6,     // page code: 0x0f
-                 :1,
-           ps    :1;
-   uint8    len;          // page length 0x0e
-   uint8         :6,
-           dcc   :1,
-           dce   :1;
-   uint8         :5,
-           red   :2,
-           dde   :1;
+   uint8    page  :6,   // page code: 0x0f
+                  :1,
+            ps    :1;
+   uint8    len;        // page length 0x0e
+   uint8          :6,
+            dcc   :1,
+            dce   :1;
+   uint8          :5,
+            red   :2,
+            dde   :1;
    uint8  compAlg[4];
    uint8  decompAlg[4];
    uint8  reserved[4];
 } SCSICompressionPage;
 
 typedef struct {
-   uint8    page  :6,     // page code: 0x10
-                 :1,
-           ps    :1;
-   uint8    len;          // page length 0x0e
-   uint8    format:5,     // active format
-           car   :1,
-           cap   :1,
-                 :1;
-   uint8    partition;    // active partition
-   uint8    wbeRatio;     // write buffer empty ratio
-   uint8    rbeRatio;     // read buffer empty ratio
+   uint8    page  :6,   // page code: 0x10
+                  :1,
+            ps    :1;
+   uint8    len;        // page length 0x0e
+   uint8    format:5,   // active format
+            car   :1,
+            cap   :1,
+                  :1;
+   uint8    partition;  // active partition
+   uint8    wbeRatio;   // write buffer empty ratio
+   uint8    rbeRatio;   // read buffer empty ratio
    uint16   writeDelay;
-   uint8    rew          :1,
-           rb0   :1,
-           sofc  :2,
-           avc   :1,
-           rsmk  :1,
-           bis   :1,
-           dbr   :1;
+   uint8    rew   :1,
+            rb0   :1,
+            sofc  :2,
+            avc   :1,
+            rsmk  :1,
+            bis   :1,
+            dbr   :1;
    uint8    gapSize;
-   uint8         :3,
-           sew   :1,
-           eeg   :1,
-           eod   :3;
+   uint8          :3,
+            sew   :1,
+            eeg   :1,
+            eod   :3;
    uint24   bufSizeAtEW;
    uint8    compression;
-   uint8         :8;
+   uint8          :8;
 } SCSIDeviceConfigPage;
 
 typedef struct {
-   uint8    page  :6,     // page code: 0x03
-                 :1,
-           ps    :1;
-   uint8    len;          // page length 0x06
-   uint8    unit;         // measurement unit
-   uint8         :8;
+   uint8    page  :6,   // page code: 0x03
+                  :1,
+            ps    :1;
+   uint8    len;        // page length 0x06
+   uint8    unit;       // measurement unit
+   uint8          :8;
    uint16   divisor;
-   uint16        :16;
+   uint16         :16;
 } SCSIUnitsPage;
 
 
 /*
  * Format of START STOP UNIT (0x1b).
  */
-typedef 
+typedef
 #include "vmware_pack_begin.h"
 struct {
-   uint8 opcode;       // 0x1b
-   uint8 immed:1,
-          rsvd:7;
+   uint8 opcode;     // 0x1b
+   uint8 immed :1,
+         rsvd  :7;
    uint8 reserved[2];
-   uint8  start:1,
-           loej:1,      // load/eject
-          rsvd1:2,
-          power:4;
+   uint8 start :1,
+         loej  :1,   // load/eject
+         rsvd1 :2,
+         power :4;
    uint8 control;
 }
 #include "vmware_pack_end.h"
@@ -1130,10 +1133,10 @@ SCSIStartStopUnitCmd;
 /*
  * Format of ALLOW PREVENT MEDIUM REMOVAL (0x1e).
  */
-typedef 
+typedef
 #include "vmware_pack_begin.h"
 struct {
-   uint8 opcode;       // 0x1e
+   uint8 opcode;     // 0x1e
    uint8 reserved[3];
    uint8 prevent:2,
                 :6;
@@ -1148,18 +1151,18 @@ SCSIMediumRemovalCmd;
  * These are defined here because multiple SCSI devices
  * need them.
  */
-typedef 
+typedef
 #include "vmware_pack_begin.h"
 struct {
-   uint8 opcode;       // 0x25
+   uint8 opcode;  // 0x25
    uint8 rel   :1,
-              :4,
-        lun   :3;
+               :4,
+         lun   :3;
 #define SCSI_RW10_MAX_LBN 0xffffffffu
    uint32 lbn;
    uint8 reserved[2];
    uint8 pmi   :1,
-              :7;
+               :7;
    uint8 control;
 }
 #include "vmware_pack_end.h"
@@ -1170,24 +1173,24 @@ typedef struct {
    uint32 blocksize;
 } SCSIReadCapacityResponse;
 
-typedef 
+typedef
 #include "vmware_pack_begin.h"
 struct {
-   uint8 opcode;       // 0x9e
+   uint8 opcode;  // 0x9e
 #define SCSI_READ_CAPACITY16_SERVICE_ACTION 0x10
    uint8 action:5,
-              :3;
+               :3;
    uint64 lbn;
    uint32 len;
    uint8 pmi   :1,
-        rel   :1,
-              :6;
+         rel   :1,
+               :6;
    uint8 control;
 }
 #include "vmware_pack_end.h"
 SCSIReadCapacity16Cmd;
 
-typedef 
+typedef
 #include "vmware_pack_begin.h"
 struct {
    uint64 lbn;
@@ -1201,27 +1204,17 @@ SCSIReadCapacity16Response;
  * request. These are defined here because multiple SCSI
  * devices need them.
  */
-typedef 
-#include "vmware_pack_begin.h"
-struct {
-   uint32 opcode:8,
-         lun:3,
-         lbn:21;
-   uint8  length;
-   uint8  control;
-}
-#include "vmware_pack_end.h"
-SCSIReadWrite6Cmd;
+typedef SCSICDB6 SCSIReadWrite6Cmd;
 
-typedef 
+typedef
 #include "vmware_pack_begin.h"
 struct {
    uint8 opcode;
    uint8 rel   :1,
-              :2,
-        flua  :1,
-        dpo   :1,
-        lun   :3;
+               :2,
+         flua  :1,
+         dpo   :1,
+         lun   :3;
    uint32 lbn;
    uint8 reserved;
    uint16 length;
@@ -1230,15 +1223,15 @@ struct {
 #include "vmware_pack_end.h"
 SCSIReadWrite10Cmd;
 
-typedef 
+typedef
 #include "vmware_pack_begin.h"
 struct {
    uint8 opcode;
    uint8 rel   :1,
-              :2,
-        flua  :1,
-        dpo   :1,
-        lun   :3;
+               :2,
+         flua  :1,
+         dpo   :1,
+         lun   :3;
    uint32 lbn;
    uint32 length;
    uint8 reserved;
@@ -1247,15 +1240,15 @@ struct {
 #include "vmware_pack_end.h"
 SCSIReadWrite12Cmd;
 
-typedef 
+typedef
 #include "vmware_pack_begin.h"
 struct {
    uint8 opcode;
    uint8 rel   :1,
-              :2,
-        flua  :1,
-        dpo   :1,
-              :3;
+               :2,
+         flua  :1,
+         dpo   :1,
+               :3;
    uint64 lbn;
    uint32 length;
    uint8 reserved;
@@ -1264,22 +1257,22 @@ struct {
 #include "vmware_pack_end.h"
 SCSIReadWrite16Cmd;
 
-typedef 
+typedef
 #include "vmware_pack_begin.h"
 struct {
    uint8    opcode;
-   uint8    xtnt  :1,           // extent-based reservation
-            ptyID :3,           // 3rd party reservation ID
-            pty          :1,    // 3rd party reservation
-            lun          :3;    // logical unit number
-   uint8    resvID;             // SCSI-3: reservation ID
-   uint16   resvListLen;        // SCSI-3: reservation list length
-   uint8    ctrl;               // control byte
+   uint8    xtnt  :1,      // extent-based reservation
+            ptyID :3,      // 3rd party reservation ID
+            pty   :1,      // 3rd party reservation
+            lun   :3;      // logical unit number
+   uint8    resvID;        // SCSI-3: reservation ID
+   uint16   resvListLen;   // SCSI-3: reservation list length
+   uint8    control;       // control byte
 }
 #include "vmware_pack_end.h"
 SCSIReserveUnitCmd;
 
-typedef 
+typedef
 #include "vmware_pack_begin.h"
 struct {
    uint8    opcode;
@@ -1289,12 +1282,12 @@ struct {
             lun   :3;           // logical unit number
    uint8    resvID;             // SCSI-3: reservation ID
    uint8    reserved[2];
-   uint8    ctrl;               // control byte
-} 
+   uint8    control;            // control byte
+}
 #include "vmware_pack_end.h"
 SCSIReleaseUnitCmd;
 
-typedef 
+typedef
 #include "vmware_pack_begin.h"
 struct {
    uint8    opcode;
@@ -1305,8 +1298,8 @@ struct {
             pf    :1,           // page format
             lun   :3;           // logical unit number
    uint8    reserved;
-   uint16   len;                // data length
-   uint8    ctrl;               // control byte
+   uint16   length;             // data length
+   uint8    control;            // control byte
 }
 #include "vmware_pack_end.h"
 SCSISendDiagnosticCmd;
@@ -1323,8 +1316,8 @@ struct {
             lun     :3;         // logical unit number
    uint32   lbn;                // logical block address
    uint8    reserved;
-   uint16   len;                // verification length
-   uint8    ctrl;               // control byte
+   uint16   length;             // verification length
+   uint8    control;            // control byte
 }
 #include "vmware_pack_end.h"
 SCSIVerify10Cmd;
@@ -1333,7 +1326,7 @@ typedef
 #include "vmware_pack_begin.h"
 struct {
    uint8    opcode;
-   uint8    polled   :1,        // asynchronous or not
+   uint8    polled   :1,         // asynchronous or not
                      :7;
    uint8    reserved0[2];
 #define SCSI_GESN_CLASS_RSVD0           (1 << 0)
@@ -1346,14 +1339,14 @@ struct {
 #define SCSI_GESN_CLASS_RSVD1           (1 << 7)
    uint8    notifyClassReq;      // the class of events we are interested in
    uint8    reserved1[2];
-   uint16   length;             // allocation length
+   uint16   length;              // allocation length
    uint8    control;
 }
 #include "vmware_pack_end.h"
 SCSIGetEventStatusNotificationCmd;
 
 /*
- * Format of Persistent Reservation Commands per SPC-3 r23, required for 
+ * Format of Persistent Reservation Commands per SPC-3 r23, required for
  * virtualizing reservations.
  */
 
@@ -1365,8 +1358,8 @@ typedef enum {
    READ_FULL_STATUS               = 0x3
 } SCSIPersistentReserveInServiceAction;
 
-/* 
- * Persistent reservation type codes 
+/*
+ * Persistent reservation type codes
  */
 typedef enum {
    WRITE_EXCL                     = 0x1,
@@ -1377,16 +1370,16 @@ typedef enum {
    EXCL_ACCESS_ALL_REG            = 0x8
 } SCSIPersistentReserveTypeCode;
 
-typedef 
+typedef
 #include "vmware_pack_begin.h"
-struct { 
-   uint8  opcode; 
+struct {
+   uint8  opcode;
    uint8  serviceAction :5,
           reserved      :3;
    uint8  reserved1[5];
    uint16 allocationLength;
    uint8  control;
-} 
+}
 #include "vmware_pack_end.h"
 SCSIPersistentReserveInCmd;
 
@@ -1403,7 +1396,7 @@ typedef enum {
 } SCSIPersistentReserveOutServiceAction;
 
 
-typedef 
+typedef
 #include "vmware_pack_begin.h"
 struct {
    uint8  opcode;
@@ -1412,9 +1405,9 @@ struct {
    uint8  type          :4,
           scope         :4;
    uint8  reserved1[2];
-   uint32 parameterListLength; 
+   uint32 parameterListLength;
    uint8  control;
-} 
+}
 #include "vmware_pack_end.h"
 SCSIPersistentReserveOutCmd;
 
@@ -1436,11 +1429,11 @@ struct {
     * following are true:
     *  a. the SPEC_I_PT but is set to 0
     *  b. service action is not REGISTER AND MOVE
-    * 
+    *
     * This is currently the only supported mode in the vmkernel,
     * so no additional parameter data is included in this struct
     */
-} 
+}
 #include "vmware_pack_end.h"
 SCSIPersistentReserveOutPList;
 
@@ -1455,7 +1448,7 @@ struct {
    uint8  type      :4,
           scope     :4;
    uint8 obsolete1[2];
-} 
+}
 #include "vmware_pack_end.h"
 SCSIPRReadReservationResp;
 
@@ -1470,13 +1463,13 @@ SCSIPRReadReservationResp;
  * of sense data at a time; the base SCSI device support invalidates
  * this data structure before each SCSI operation as needed.
  */
-typedef 
+typedef
 #include "vmware_pack_begin.h"
 struct {
-   uint8 error   :7,      // 0x70 for current command, 0x71 for earlier command
-#define SCSI_SENSE_ERROR_CURCMD  0x70      // sense data is for "current command"
-#define SCSI_SENSE_ERROR_PREVCMD 0x71      // sense data is for an earlier command
-        valid    :1;      // sense data valid
+   uint8 error   :7,    // 0x70 for current command, 0x71 for earlier command
+#define SCSI_SENSE_ERROR_CURCMD  0x70      // sense data is for "current command"
+#define SCSI_SENSE_ERROR_PREVCMD 0x71      // sense data is for an earlier command
+         valid   :1;    // sense data valid
 /* NB: Please Note that the valid bit above does NOT tell you whether
  * the sense is actually valid and thus the name is really badly chosen
  * (even though it is the official name from the SCSI II specification).
@@ -1485,25 +1478,25 @@ struct {
  * we have seen that many tape drives are capable of returning sense
  * without this bit set....
  */
-   uint8 segment;         // segment number
-   uint8 key     :4,      // sense key
-                 :1,
-        ili      :1,
-        eom      :1,
-        filmrk   :1;
-   uint8 info[4];         // general information
-   uint8 optLen;          // length of optional data that follows
-   uint8 cmdInfo[4];      // command-specific information
-   uint8 code;            // sense code
-   uint8 xcode;                   // extended sense code
-   uint8 fru;             // 
-   uint8 bitpos          :3,
-        bpv      :1,
-                 :2,
-        cd       :1,      // 1 if error in command, 0 if in data
-        sksv     :1;      // sense key specific data is valid
-   uint16 epos;                   // offset of first byte in error
-   
+   uint8 segment;       // segment number
+   uint8 key      :4,   // sense key
+                  :1,
+         ili      :1,
+         eom      :1,
+         filmrk   :1;
+   uint8 info[4];       // general information
+   uint8 optLen;        // length of optional data that follows
+   uint8 cmdInfo[4];    // command-specific information
+   uint8 code;          // sense code
+   uint8 xcode;         // extended sense code
+   uint8 fru;           //
+   uint8 bitpos   :3,
+         bpv      :1,
+                  :2,
+         cd       :1,   // 1 if error in command, 0 if in data
+         sksv     :1;   // sense key specific data is valid
+   uint16 epos;         // offset of first byte in error
+
    // Some vendors want to return additional data which
    // requires a sense buffer of up to 64 bytes.
    uint8 additional[46];
@@ -1647,6 +1640,129 @@ struct {
 SCSIRDSDVDPhysicalInfoLeadin;
 
 
+/*
+ * MSF structure for CDs.
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct {
+   uint8     minute;
+   uint8     second;
+   uint8     frame;
+}
+#include "vmware_pack_end.h"
+SCSICDMSF;
+
+
+/*
+ * ReadCD packet data.
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct {
+   uint8     opcode;
+   uint8     obsolete:1,
+             dap:1,
+             expectedSectorType:3,
+             reserved1:3;
+   uint32    lbn;
+   uint8     length[3];
+   uint8     reserved2:1,
+             c2errors:2,
+             mainChannelSelectionBits:5;
+   uint8     subChannelSelectionBits:3,
+             reserved3:5;
+   uint8     control;
+}
+#include "vmware_pack_end.h"
+SCSIReadCDCmd;
+
+
+/*
+ * ReadCDMSF packet data.
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct {
+   uint8     opcode;
+   uint8     obsolete:1,
+             dap:1,
+             expectedSectorType:3,
+             reserved1:3;
+   uint8     reserved;
+   SCSICDMSF start;
+   SCSICDMSF end;
+   uint8     reserved2:1,
+             c2errors:2,
+             mainChannelSelectionBits:5;
+   uint8     subChannelSelectionBits:3,
+             reserved3:5;
+   uint8     control;
+}
+#include "vmware_pack_end.h"
+SCSIReadCDMSFCmd;
+
+
+/*
+ * ReadTOC packet data.
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct {
+   uint8     opcode;
+   uint8     reserved1:1,
+             msf:1,
+             reserved2:6;
+   uint8     format:3, /* MMC says 4 bits for eons.  Original ATAPI is only 3 bits. */
+             reserved3:5;
+   uint8     reserved4[3];
+   uint8     trackNumber;
+   uint16    allocationLength;
+   uint8     control;
+}
+#include "vmware_pack_end.h"
+SCSIReadTOCCmd;
+
+
+/*
+ * ReadSubChannel packet data.
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct {
+   uint8     opcode;
+   uint8     reserved1:1,
+             msf:1,
+             reserved2:6;
+   uint8     reserved3:6,
+             subq:1,
+             reserved4:1;
+   uint8     format;
+   uint8     reserved5[2];
+   uint8     trackNumber;
+   uint16    allocationLength;
+   uint8     control;
+}
+#include "vmware_pack_end.h"
+SCSIReadSubChannelCmd;
+
+
+/*
+ * PlayMSF packet data.
+ */
+typedef
+#include "vmware_pack_begin.h"
+struct {
+   uint8     opcode;
+   uint8     reserved[2];
+   SCSICDMSF start;
+   SCSICDMSF end;
+   uint8     control;
+}
+#include "vmware_pack_end.h"
+SCSIPlayMSFCmd;
+
+
 /*
  * Host and device status definitions.
  *
@@ -1693,13 +1809,13 @@ typedef enum {
    SDSTAT_CHECK                   = 0x02, // check condition
    SDSTAT_CONDITION_MET           = 0x04, // condition met
    SDSTAT_BUSY                    = 0x08, // device busy
-   SDSTAT_INTERMEDIATE            = 0x10, 
+   SDSTAT_INTERMEDIATE            = 0x10,
    SDSTAT_INTERMEDIATE_CONDITION  = 0x14,
    SDSTAT_RESERVATION_CONFLICT    = 0x18, // device reserved by another host
    SDSTAT_COMMAND_TERMINATED      = 0x22,
-   SDSTAT_TASK_SET_FULL           = 0x28, 
-   SDSTAT_ACA_ACTIVE              = 0x30, 
-   SDSTAT_TASK_ABORTED            = 0x40, 
+   SDSTAT_TASK_SET_FULL           = 0x28,
+   SDSTAT_ACA_ACTIVE              = 0x30,
+   SDSTAT_TASK_ABORTED            = 0x40,
 } SCSIDeviceStatus;
 
 typedef enum {
@@ -1719,7 +1835,7 @@ typedef enum {
 
 /*
  *---------------------------------------------------------------------------
- * 
+ *
  * SCSICdb_IsRead --
  *
  *      This function returns TRUE if the scsi command passed as an argument is
@@ -1737,7 +1853,7 @@ typedef enum {
 static INLINE Bool
 SCSICdb_IsRead(uint8 cdb0)        // IN
 {
-   return cdb0 == SCSI_CMD_READ6 
+   return cdb0 == SCSI_CMD_READ6
        || cdb0 == SCSI_CMD_READ10
        || cdb0 == SCSI_CMD_READ12
        || cdb0 == SCSI_CMD_READ16;
@@ -1746,7 +1862,7 @@ SCSICdb_IsRead(uint8 cdb0)        // IN
 
 /*
  *---------------------------------------------------------------------------
- * 
+ *
  * SCSICdb_IsWrite --
  *
  *      This function returns TRUE if the scsi command passed as an argument is
@@ -1764,7 +1880,7 @@ SCSICdb_IsRead(uint8 cdb0)        // IN
 static INLINE Bool
 SCSICdb_IsWrite(uint8 cdb0)       // IN
 {
-   return cdb0 == SCSI_CMD_WRITE6 
+   return cdb0 == SCSI_CMD_WRITE6
        || cdb0 == SCSI_CMD_WRITE10
        || cdb0 == SCSI_CMD_WRITE12
        || cdb0 == SCSI_CMD_WRITE16;
@@ -1795,6 +1911,51 @@ SCSICdb_IsRW(uint8 cdb0)        // IN
 }
 
 
+/*
+ *---------------------------------------------------------------------------
+ *
+ * SCSICdb_GetCDBLength --
+ *
+ *      This function returns length of specified command.  Multibyte
+ *      CDB (0x7F) is reported as reserved command.
+ *
+ * Results:
+ *      6 for commands 00-1F
+ *      10 for commands 20-5F
+ *      16 for commands 80-9F
+ *      12 for commands A0-BF
+ *      SCSI_GRP_RESERVED for commands 60-7F
+ *      SCSI_GRP_VENDOR for commands C0-FF
+ *         Both SCSI_GRP_RESERVED & SCSI_GRP_VENDOR are guarateed to have
+ *         bigger value than 16.
+ *
+ * Side effects:
+ *      None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+#define SCSI_GRP_RESERVED  64
+#define SCSI_GRP_VENDOR    65
+
+static INLINE size_t
+SCSICdb_GetCDBLength(uint8 cdb0)    // IN
+{
+   static const unsigned char lengths[] = {
+      6,                 /* 00 - 1F */
+      10,                /* 20 - 3F */
+      10,                /* 40 - 5F */
+      SCSI_GRP_RESERVED, /* 60 - 7F */
+      16,                /* 80 - 9F */
+      12,                /* A0 - BF */
+      SCSI_GRP_VENDOR,   /* C0 - DF */
+      SCSI_GRP_VENDOR,   /* E0 - FF */
+   };
+
+   return lengths[cdb0 >> 5];
+}
+
+
 /*
  *---------------------------------------------------------------------------
  * 
@@ -1838,7 +1999,7 @@ SCSICdb_GetLengthFieldOffset(uint8 cmd)
  *
  * SCSI3InquiryLen --
  *
- *      Returns 16-bit allocation length specified in SCSI3 Inquriy CMD cmd 
+ *      Returns 16-bit allocation length specified in SCSI3 Inquriy CMD cmd
  *
  * Results:
  *      16-bit allocation length.
@@ -1850,18 +2011,18 @@ SCSICdb_GetLengthFieldOffset(uint8 cmd)
  */
 
 static INLINE uint16
-SCSI3InquiryLen(SCSI3InquiryCmd *inqCmd)        // IN
+SCSI3InquiryLen(const SCSI3InquiryCmd *inqCmd)     // IN
 {
-  return (inqCmd->lenMSB << 8) + inqCmd->len;
+  return (inqCmd->lengthMSB << 8) + inqCmd->length;
 }
 
 
-typedef 
+typedef
 #include "vmware_pack_begin.h"
 struct SCSICmdInfo {
    uint8 code;
    uint8 xferType;
-   char *name;
+   const char *name;
    uint8 emulation;
 }
 #include "vmware_pack_end.h"
@@ -1883,259 +2044,259 @@ extern SCSICmdInfo scsiCmdInfo[256];
 #define SCSI_CMD_INFO_DATA \
    {SCSI_CMD_TEST_UNIT_READY,  SCSI_XFER_NONE,     "TEST UNIT READY", SCSI_EMULATE}, \
    {SCSI_CMD_REZERO_UNIT,      SCSI_XFER_NONE,     "REWIND/REZERO UNIT", SCSI_DONT_EMULATE}, \
-   {0x02,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
-   {SCSI_CMD_REQUEST_SENSE,    SCSI_XFER_TOHOST,   "REQUEST SENSE", SCSI_EMULATE},     \
-   {SCSI_CMD_FORMAT_UNIT,      SCSI_XFER_TODEVICE, "FORMAT UNIT", SCSI_EMULATE},       \
-   {SCSI_CMD_READ_BLOCKLIMITS, SCSI_XFER_TOHOST,   "READ BLOCK LIMITS", SCSI_DONT_EMULATE},\
-   {0x06,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
-   {SCSI_CMD_INIT_ELEMENT_STATUS, SCSI_XFER_AUTO,  NULL, SCSI_DONT_EMULATE},               \
-   {SCSI_CMD_READ6,            SCSI_XFER_TOHOST,   "READ(6)", SCSI_EMULATE},           \
-   {0x09,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
-   {SCSI_CMD_WRITE6,           SCSI_XFER_TODEVICE, "WRITE(6)", SCSI_EMULATE},  \
-   {SCSI_CMD_SLEW_AND_PRINT,   SCSI_XFER_TODEVICE, NULL, SCSI_DONT_EMULATE},               \
-   {0x0c,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
-   {0x0d,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
-   {0x0e,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
-   {SCSI_CMD_READ_REVERSE,     SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
-   {SCSI_CMD_SYNC_BUFFER,      SCSI_XFER_NONE,     NULL, SCSI_DONT_EMULATE},               \
-   {SCSI_CMD_SPACE,            SCSI_XFER_NONE,     "SPACE", SCSI_DONT_EMULATE},            \
+   {0x02,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_REQUEST_SENSE,    SCSI_XFER_TOHOST,   "REQUEST SENSE", SCSI_EMULATE}, \
+   {SCSI_CMD_FORMAT_UNIT,      SCSI_XFER_TODEVICE, "FORMAT UNIT", SCSI_EMULATE}, \
+   {SCSI_CMD_READ_BLOCKLIMITS, SCSI_XFER_TOHOST,   "READ BLOCK LIMITS", SCSI_DONT_EMULATE}, \
+   {0x06,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_INIT_ELEMENT_STATUS, SCSI_XFER_AUTO,  NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_READ6,            SCSI_XFER_TOHOST,   "READ(6)", SCSI_EMULATE}, \
+   {0x09,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_WRITE6,           SCSI_XFER_TODEVICE, "WRITE(6)", SCSI_EMULATE}, \
+   {SCSI_CMD_SLEW_AND_PRINT,   SCSI_XFER_TODEVICE, NULL, SCSI_DONT_EMULATE}, \
+   {0x0c,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x0d,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x0e,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_READ_REVERSE,     SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_SYNC_BUFFER,      SCSI_XFER_NONE,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_SPACE,            SCSI_XFER_NONE,     "SPACE", SCSI_DONT_EMULATE}, \
    {SCSI_CMD_INQUIRY,          SCSI_XFER_TOHOST,   "INQUIRY", SCSI_EMULATE}, \
-   {0x13,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
-   {SCSI_CMD_RECOVER_BUFFERED, SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
-   {SCSI_CMD_MODE_SELECT,      SCSI_XFER_TODEVICE, "MODE SELECT(6)", SCSI_DONT_EMULATE},  \
-   {SCSI_CMD_RESERVE_UNIT,     SCSI_XFER_NONE,     "RESERVE(6)", SCSI_EMULATE},        \
-   {SCSI_CMD_RELEASE_UNIT,     SCSI_XFER_NONE,     "RELEASE(6)", SCSI_EMULATE},        \
-   {SCSI_CMD_COPY,             SCSI_XFER_AUTO,     "COPY AND VERIFY", SCSI_DONT_EMULATE},  \
-   {SCSI_CMD_ERASE,            SCSI_XFER_NONE,     "ERASE", SCSI_DONT_EMULATE},            \
-   {SCSI_CMD_MODE_SENSE,       SCSI_XFER_TOHOST,   "MODE SENSE(6)", SCSI_EMULATE},   \
-   {SCSI_CMD_SCAN,             SCSI_XFER_TODEVICE, NULL, SCSI_EMULATE},                \
+   {0x13,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_RECOVER_BUFFERED, SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_MODE_SELECT,      SCSI_XFER_TODEVICE, "MODE SELECT(6)", SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_RESERVE_UNIT,     SCSI_XFER_NONE,     "RESERVE(6)", SCSI_EMULATE}, \
+   {SCSI_CMD_RELEASE_UNIT,     SCSI_XFER_NONE,     "RELEASE(6)", SCSI_EMULATE}, \
+   {SCSI_CMD_COPY,             SCSI_XFER_AUTO,     "COPY AND VERIFY", SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_ERASE,            SCSI_XFER_NONE,     "ERASE", SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_MODE_SENSE,       SCSI_XFER_TOHOST,   "MODE SENSE(6)", SCSI_EMULATE}, \
+   {SCSI_CMD_SCAN,             SCSI_XFER_TODEVICE, NULL, SCSI_EMULATE}, \
    {SCSI_CMD_RECV_DIAGNOSTIC,  SCSI_XFER_AUTO,     "RECEIVE DIAGNOSTIC RESULTS", SCSI_DONT_EMULATE}, \
-   {SCSI_CMD_SEND_DIAGNOSTIC,  SCSI_XFER_TODEVICE, "SEND DIAGNOSTIC", SCSI_DONT_EMULATE},  \
+   {SCSI_CMD_SEND_DIAGNOSTIC,  SCSI_XFER_TODEVICE, "SEND DIAGNOSTIC", SCSI_DONT_EMULATE}, \
    {SCSI_CMD_MEDIUM_REMOVAL,   SCSI_XFER_NONE,     "LOCK/UNLOCK DOOR", SCSI_DONT_EMULATE_DONT_LOG}, \
-   {0x1f,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
-   {0x20,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
-   {0x21,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
-   {0x22,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
+   {0x1f,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x20,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x21,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x22,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
    {SCSI_CMD_READ_FORMAT_CAPACITIES, SCSI_XFER_TOHOST, "READ FORMAT CAPACITIES", SCSI_DONT_EMULATE}, \
-   {SCSI_CMD_SET_WINDOW,       SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
-   {SCSI_CMD_READ_CAPACITY,    SCSI_XFER_TOHOST,   "READ CAPACITY", SCSI_EMULATE},     \
-   {0x26,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
-   {0x27,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
-   {SCSI_CMD_READ10,           SCSI_XFER_TOHOST,   "READ(10)", SCSI_EMULATE},  \
-   {SCSI_CMD_READ_GENERATION,  SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
-   {SCSI_CMD_WRITE10,          SCSI_XFER_TODEVICE, "WRITE(10)", SCSI_EMULATE}, \
-   {SCSI_CMD_SEEK10,           SCSI_XFER_NONE,     NULL, SCSI_DONT_EMULATE},               \
-   {0x2c,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
-   {SCSI_CMD_READ_UPDATED_BLOCK, SCSI_XFER_AUTO,   NULL, SCSI_DONT_EMULATE},               \
-   {SCSI_CMD_WRITE_VERIFY,     SCSI_XFER_AUTO,     "WRITE VERIFY", SCSI_DONT_EMULATE},     \
-   {SCSI_CMD_VERIFY,           SCSI_XFER_NONE,     "VERIFY", SCSI_EMULATE},            \
-   {SCSI_CMD_SEARCH_DATA_HIGH, SCSI_XFER_AUTO,     "SEARCH HIGH", SCSI_DONT_EMULATE},      \
-   {SCSI_CMD_SEARCH_DATA_EQUAL, SCSI_XFER_AUTO,     "SEARCH EQUAL", SCSI_DONT_EMULATE},    \
-   {SCSI_CMD_SEARCH_DATA_LOW,  SCSI_XFER_AUTO,     "SEARCH LOW", SCSI_DONT_EMULATE},       \
-   {SCSI_CMD_SET_LIMITS,       SCSI_XFER_AUTO,     "SET LIMITS", SCSI_DONT_EMULATE},       \
-   {SCSI_CMD_READ_POSITION,    SCSI_XFER_TOHOST,   NULL, SCSI_DONT_EMULATE},               \
-   {SCSI_CMD_SYNC_CACHE,       SCSI_XFER_NONE,     "SYNC CACHE", SCSI_EMULATE},        \
-   {SCSI_CMD_LOCKUNLOCK_CACHE, SCSI_XFER_AUTO,     "LOCK/UNLOCK CACHE", SCSI_DONT_EMULATE},\
+   {SCSI_CMD_SET_WINDOW,       SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_READ_CAPACITY,    SCSI_XFER_TOHOST,   "READ CAPACITY", SCSI_EMULATE}, \
+   {0x26,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x27,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_READ10,           SCSI_XFER_TOHOST,   "READ(10)", SCSI_EMULATE}, \
+   {SCSI_CMD_READ_GENERATION,  SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_WRITE10,          SCSI_XFER_TODEVICE, "WRITE(10)", SCSI_EMULATE}, \
+   {SCSI_CMD_SEEK10,           SCSI_XFER_NONE,     NULL, SCSI_DONT_EMULATE}, \
+   {0x2c,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_READ_UPDATED_BLOCK, SCSI_XFER_AUTO,   NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_WRITE_VERIFY,     SCSI_XFER_AUTO,     "WRITE VERIFY", SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_VERIFY,           SCSI_XFER_NONE,     "VERIFY", SCSI_EMULATE}, \
+   {SCSI_CMD_SEARCH_DATA_HIGH, SCSI_XFER_AUTO,     "SEARCH HIGH", SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_SEARCH_DATA_EQUAL, SCSI_XFER_AUTO,     "SEARCH EQUAL", SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_SEARCH_DATA_LOW,  SCSI_XFER_AUTO,     "SEARCH LOW", SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_SET_LIMITS,       SCSI_XFER_AUTO,     "SET LIMITS", SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_READ_POSITION,    SCSI_XFER_TOHOST,   NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_SYNC_CACHE,       SCSI_XFER_NONE,     "SYNC CACHE", SCSI_EMULATE}, \
+   {SCSI_CMD_LOCKUNLOCK_CACHE, SCSI_XFER_AUTO,     "LOCK/UNLOCK CACHE", SCSI_DONT_EMULATE}, \
    {SCSI_CMD_READ_DEFECT_DATA, SCSI_XFER_AUTO,     "READ DEFECT DATA", SCSI_DONT_EMULATE}, \
-   {SCSI_CMD_MEDIUM_SCAN,      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
-   {SCSI_CMD_COMPARE,          SCSI_XFER_AUTO,     "COMPARE", SCSI_DONT_EMULATE},          \
-   {SCSI_CMD_COPY_VERIFY,      SCSI_XFER_AUTO,     "COPY AND VERIFY", SCSI_DONT_EMULATE},  \
-   {SCSI_CMD_WRITE_BUFFER,     SCSI_XFER_AUTO,     "WRITE BUFFER", SCSI_DONT_EMULATE_DONT_LOG},        \
-   {SCSI_CMD_READ_BUFFER,      SCSI_XFER_AUTO,     "READ BUFFER", SCSI_DONT_EMULATE_DONT_LOG}, \
-   {SCSI_CMD_UPDATE_BLOCK,     SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
-   {SCSI_CMD_READ_LONG,        SCSI_XFER_AUTO,     "READ LONG", SCSI_DONT_EMULATE},        \
-   {SCSI_CMD_WRITE_LONG,       SCSI_XFER_AUTO,     "WRITE LONG", SCSI_DONT_EMULATE},       \
-   {SCSI_CMD_CHANGE_DEF,       SCSI_XFER_NONE,     "CHANGE DEFINITION", SCSI_DONT_EMULATE},\
-   {SCSI_CMD_WRITE_SAME,       SCSI_XFER_AUTO,     "WRITE SAME", SCSI_DONT_EMULATE},       \
-   {SCSI_CMD_READ_SUBCHANNEL,  SCSI_XFER_TOHOST,   "READ SUBCHANNEL", SCSI_DONT_EMULATE},  \
-   {SCSI_CMD_READ_TOC,         SCSI_XFER_TOHOST,   "READ TOC", SCSI_DONT_EMULATE},         \
-   {SCSI_CMD_READ_HEADER,      SCSI_XFER_TOHOST,   "READ HEADER", SCSI_DONT_EMULATE},      \
-   {SCSI_CMD_PLAY_AUDIO10,     SCSI_XFER_NONE,     "PLAY AUDIO(10)", SCSI_DONT_EMULATE},   \
-   {SCSI_CMD_GET_CONFIGURATION, SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},              \
-   {SCSI_CMD_PLAY_AUDIO_MSF,   SCSI_XFER_NONE,     "PLAY AUDIO MSF", SCSI_DONT_EMULATE},   \
+   {SCSI_CMD_MEDIUM_SCAN,      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_COMPARE,          SCSI_XFER_AUTO,     "COMPARE", SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_COPY_VERIFY,      SCSI_XFER_AUTO,     "COPY AND VERIFY", SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_WRITE_BUFFER,     SCSI_XFER_AUTO,     "WRITE BUFFER", SCSI_DONT_EMULATE_DONT_LOG}, \
+   {SCSI_CMD_READ_BUFFER,      SCSI_XFER_AUTO,     "READ BUFFER", SCSI_DONT_EMULATE_DONT_LOG}, \
+   {SCSI_CMD_UPDATE_BLOCK,     SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_READ_LONG,        SCSI_XFER_AUTO,     "READ LONG", SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_WRITE_LONG,       SCSI_XFER_AUTO,     "WRITE LONG", SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_CHANGE_DEF,       SCSI_XFER_NONE,     "CHANGE DEFINITION", SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_WRITE_SAME,       SCSI_XFER_AUTO,     "WRITE SAME", SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_READ_SUBCHANNEL,  SCSI_XFER_TOHOST,   "READ SUBCHANNEL", SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_READ_TOC,         SCSI_XFER_TOHOST,   "READ TOC", SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_READ_HEADER,      SCSI_XFER_TOHOST,   "READ HEADER", SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_PLAY_AUDIO10,     SCSI_XFER_NONE,     "PLAY AUDIO(10)", SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_GET_CONFIGURATION, SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_PLAY_AUDIO_MSF,   SCSI_XFER_NONE,     "PLAY AUDIO MSF", SCSI_DONT_EMULATE}, \
    {SCSI_CMD_PLAY_AUDIO_TRACK, SCSI_XFER_AUTO,     "PLAY AUDIO TRACK", SCSI_DONT_EMULATE}, \
    {SCSI_CMD_PLAY_AUDIO_RELATIVE, SCSI_XFER_AUTO,  "PLAY AUDIO RELATIVE", SCSI_DONT_EMULATE}, \
-   {SCSI_CMD_GET_EVENT_STATUS_NOTIFICATION,    SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},  \
-   {SCSI_CMD_PAUSE,            SCSI_XFER_NONE,     "PAUSE/RESUME", SCSI_DONT_EMULATE},     \
-   {SCSI_CMD_LOG_SELECT,       SCSI_XFER_TODEVICE, "LOG SELECT", SCSI_DONT_EMULATE},       \
-   {SCSI_CMD_LOG_SENSE,        SCSI_XFER_TOHOST,   "LOG SENSE", SCSI_DONT_EMULATE},        \
-   {SCSI_CMD_STOP_PLAY,        SCSI_XFER_NONE,     "STOP PLAY", SCSI_DONT_EMULATE},        \
-   {0x4f,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
-   {0x50,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
-   {SCSI_CMD_READ_DISC_INFO,   SCSI_XFER_TOHOST,   "CDR INFO", SCSI_DONT_EMULATE},         \
-   {SCSI_CMD_READ_TRACK_INFO,  SCSI_XFER_TOHOST,   "TRACK INFO", SCSI_DONT_EMULATE},       \
-   {SCSI_CMD_RESERVE_TRACK,    SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
-   {0x54,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
-   {SCSI_CMD_MODE_SELECT10,    SCSI_XFER_TODEVICE, "MODE SELECT(10)", SCSI_DONT_EMULATE},  \
-   {SCSI_CMD_RESERVE_UNIT10,   SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
-   {SCSI_CMD_RELEASE_UNIT10,   SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
-   {0x58,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
-   {0x59,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
-   {SCSI_CMD_MODE_SENSE10,     SCSI_XFER_TOHOST,   "MODE SENSE(10)", SCSI_DONT_EMULATE},   \
-   {SCSI_CMD_CLOSE_SESSION,    SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
-   {SCSI_CMD_READ_BUFFER_CAPACITY, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE},               \
-   {SCSI_CMD_SEND_CUE_SHEET,   SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
+   {SCSI_CMD_GET_EVENT_STATUS_NOTIFICATION,    SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_PAUSE,            SCSI_XFER_NONE,     "PAUSE/RESUME", SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_LOG_SELECT,       SCSI_XFER_TODEVICE, "LOG SELECT", SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_LOG_SENSE,        SCSI_XFER_TOHOST,   "LOG SENSE", SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_STOP_PLAY,        SCSI_XFER_NONE,     "STOP PLAY", SCSI_DONT_EMULATE}, \
+   {0x4f,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x50,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_READ_DISC_INFO,   SCSI_XFER_TOHOST,   "CDR INFO", SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_READ_TRACK_INFO,  SCSI_XFER_TOHOST,   "TRACK INFO", SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_RESERVE_TRACK,    SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x54,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_MODE_SELECT10,    SCSI_XFER_TODEVICE, "MODE SELECT(10)", SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_RESERVE_UNIT10,   SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_RELEASE_UNIT10,   SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x58,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x59,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_MODE_SENSE10,     SCSI_XFER_TOHOST,   "MODE SENSE(10)", SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_CLOSE_SESSION,    SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_READ_BUFFER_CAPACITY, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_SEND_CUE_SHEET,   SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
    {SCSI_CMD_PERSISTENT_RESERVE_IN, SCSI_XFER_TOHOST,     "PERSISTENT RESERVE IN", SCSI_EMULATE}, \
-   {SCSI_CMD_PERSISTENT_RESERVE_OUT, SCSI_XFER_TODEVICE,     "PERSISTENT RESERVE OUT", SCSI_EMULATE},         \
-   {0x60,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x61,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x62,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x63,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x64,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x65,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x66,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x67,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x68,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x69,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x6a,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x6b,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x6c,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x6d,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x6e,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x6f,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x70,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x71,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x72,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x73,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x74,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x75,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x76,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x77,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x78,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x79,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x7a,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x7b,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x7c,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x7d,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x7e,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x7f,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x80,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x81,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x82,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x83,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x84,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x85,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x86,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x87,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {SCSI_CMD_READ16,           SCSI_XFER_TOHOST,   "READ(16)", SCSI_EMULATE},          \
-   {0x89,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},           \
-   {SCSI_CMD_WRITE16,          SCSI_XFER_TODEVICE, "WRITE(16)", SCSI_EMULATE},         \
-   {0x8b,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x8c,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x8d,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x8e,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {SCSI_CMD_VERIFY16,         SCSI_XFER_NONE,     "VERIFY(16)", SCSI_EMULATE},        \
-   {0x90,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x91,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x92,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x93,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x94,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x95,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x96,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x97,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x98,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x99,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x9a,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x9b,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x9c,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0x9d,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {SCSI_CMD_READ_CAPACITY16,  SCSI_XFER_TOHOST,   "READ CAPACITY 16", SCSI_EMULATE},          \
-   {0x9f,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {SCSI_CMD_REPORT_LUNS,      SCSI_XFER_AUTO,     "REPORT LUNS", SCSI_EMULATE},\
-   {SCSI_CMD_BLANK,            SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xa2,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {SCSI_CMD_SEND_KEY,         SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {SCSI_CMD_REPORT_KEY,       SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {SCSI_CMD_PLAY_AUDIO12,     SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {SCSI_CMD_LOADCD,           SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xa7,                      SCSI_XFER_AUTO,     "MOVE MEDIUM", SCSI_DONT_EMULATE},  \
-   {SCSI_CMD_READ12,           SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {SCSI_CMD_PLAY_TRACK_RELATIVE, SCSI_XFER_AUTO,  NULL, SCSI_DONT_EMULATE},   \
-   {SCSI_CMD_WRITE12,          SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xab,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {SCSI_CMD_ERASE12,          SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {SCSI_CMD_READ_DVD_STRUCTURE, SCSI_XFER_AUTO,   NULL, SCSI_DONT_EMULATE},   \
-   {SCSI_CMD_WRITE_VERIFY12,   SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {SCSI_CMD_VERIFY12,         SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {SCSI_CMD_SEARCH_DATA_HIGH12, SCSI_XFER_AUTO,   NULL, SCSI_DONT_EMULATE},   \
-   {SCSI_CMD_SEARCH_DATA_EQUAL12, SCSI_XFER_AUTO,  NULL, SCSI_DONT_EMULATE},   \
-   {SCSI_CMD_SEARCH_DATA_LOW12, SCSI_XFER_AUTO,    NULL, SCSI_DONT_EMULATE},   \
-   {SCSI_CMD_SET_LIMITS12,     SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
+   {SCSI_CMD_PERSISTENT_RESERVE_OUT, SCSI_XFER_TODEVICE,     "PERSISTENT RESERVE OUT", SCSI_EMULATE}, \
+   {0x60,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x61,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x62,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x63,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x64,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x65,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x66,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x67,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x68,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x69,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x6a,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x6b,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x6c,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x6d,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x6e,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x6f,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x70,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x71,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x72,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x73,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x74,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x75,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x76,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x77,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x78,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x79,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x7a,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x7b,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x7c,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x7d,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x7e,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x7f,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x80,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x81,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x82,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x83,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x84,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x85,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x86,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x87,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_READ16,           SCSI_XFER_TOHOST,   "READ(16)", SCSI_EMULATE}, \
+   {0x89,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_WRITE16,          SCSI_XFER_TODEVICE, "WRITE(16)", SCSI_EMULATE}, \
+   {0x8b,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x8c,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x8d,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x8e,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_VERIFY16,         SCSI_XFER_NONE,     "VERIFY(16)", SCSI_EMULATE}, \
+   {0x90,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x91,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x92,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x93,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x94,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x95,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x96,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x97,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x98,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x99,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x9a,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x9b,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x9c,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0x9d,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_READ_CAPACITY16,  SCSI_XFER_TOHOST,   "READ CAPACITY 16", SCSI_EMULATE}, \
+   {0x9f,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_REPORT_LUNS,      SCSI_XFER_AUTO,     "REPORT LUNS", SCSI_EMULATE}, \
+   {SCSI_CMD_BLANK,            SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xa2,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_SEND_KEY,         SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_REPORT_KEY,       SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_PLAY_AUDIO12,     SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_LOADCD,           SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xa7,                      SCSI_XFER_AUTO,     "MOVE MEDIUM", SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_READ12,           SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_PLAY_TRACK_RELATIVE, SCSI_XFER_AUTO,  NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_WRITE12,          SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xab,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_ERASE12,          SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_READ_DVD_STRUCTURE, SCSI_XFER_AUTO,   NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_WRITE_VERIFY12,   SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_VERIFY12,         SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_SEARCH_DATA_HIGH12, SCSI_XFER_AUTO,   NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_SEARCH_DATA_EQUAL12, SCSI_XFER_AUTO,  NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_SEARCH_DATA_LOW12, SCSI_XFER_AUTO,    NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_SET_LIMITS12,     SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
    {0xb4,                      SCSI_XFER_AUTO,     "READ ELEMENT STATUS", SCSI_DONT_EMULATE}, \
-   {SCSI_CMD_REQUEST_VOLUME_ELEMENT_ADDR, SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},    \
-   {SCSI_CMD_SET_STREAMING,    SCSI_XFER_TODEVICE, "SET STREAMING", SCSI_DONT_EMULATE},        \
-   {SCSI_CMD_READ_DEFECT_DATA12, SCSI_XFER_AUTO,   NULL, SCSI_DONT_EMULATE},   \
-   {SCSI_CMD_SELECT_CDROM_SPEED, SCSI_XFER_AUTO,   NULL, SCSI_DONT_EMULATE},   \
-   {SCSI_CMD_READ_CD_MSF,      SCSI_XFER_TOHOST,   "READ CD MSF", SCSI_DONT_EMULATE},      \
-   {SCSI_CMD_AUDIO_SCAN,       SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {SCSI_CMD_SET_CDROM_SPEED,  SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {SCSI_CMD_PLAY_CD,          SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
+   {SCSI_CMD_REQUEST_VOLUME_ELEMENT_ADDR, SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_SET_STREAMING,    SCSI_XFER_TODEVICE, "SET STREAMING", SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_READ_DEFECT_DATA12, SCSI_XFER_AUTO,   NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_SELECT_CDROM_SPEED, SCSI_XFER_AUTO,   NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_READ_CD_MSF,      SCSI_XFER_TOHOST,   "READ CD MSF", SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_AUDIO_SCAN,       SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_SET_CDROM_SPEED,  SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_PLAY_CD,          SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
    {SCSI_CMD_MECH_STATUS,      SCSI_XFER_TOHOST,   "MECHANISM STATUS", SCSI_DONT_EMULATE}, \
-   {SCSI_CMD_READ_CD,          SCSI_XFER_TOHOST,   "READ CD MSF", SCSI_DONT_EMULATE},      \
-   {SCSI_CMD_SEND_DVD_STRUCTURE, SCSI_XFER_AUTO,   NULL, SCSI_DONT_EMULATE},   \
-   {0xc0,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xc1,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xc2,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xc3,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xc4,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xc5,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xc6,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xc7,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xc8,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xc9,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xca,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xcb,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xcc,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xcd,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xce,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xcf,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xd0,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xd1,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xd2,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xd3,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xd4,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xd5,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xd6,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xd7,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xd8,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xd9,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xda,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xdb,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xdc,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xdd,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xde,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xdf,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xe0,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xe1,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xe2,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xe3,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xe4,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xe5,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xe6,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xe7,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xe8,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xe9,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xea,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xeb,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xec,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xed,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xee,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xef,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xf0,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xf1,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xf2,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xf3,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xf4,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xf5,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xf6,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xf7,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xf8,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xf9,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xfa,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xfb,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},   \
-   {0xfc,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
-   {0xfd,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
-   {0xfe,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               \
-   {0xff,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},               
+   {SCSI_CMD_READ_CD,          SCSI_XFER_TOHOST,   "READ CD", SCSI_DONT_EMULATE}, \
+   {SCSI_CMD_SEND_DVD_STRUCTURE, SCSI_XFER_AUTO,   NULL, SCSI_DONT_EMULATE}, \
+   {0xc0,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xc1,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xc2,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xc3,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xc4,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xc5,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xc6,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xc7,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xc8,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xc9,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xca,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xcb,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xcc,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xcd,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xce,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xcf,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xd0,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xd1,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xd2,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xd3,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xd4,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xd5,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xd6,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xd7,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xd8,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xd9,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xda,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xdb,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xdc,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xdd,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xde,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xdf,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xe0,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xe1,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xe2,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xe3,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xe4,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xe5,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xe6,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xe7,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xe8,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xe9,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xea,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xeb,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xec,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xed,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xee,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xef,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xf0,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xf1,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xf2,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xf3,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xf4,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xf5,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xf6,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xf7,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xf8,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xf9,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xfa,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xfb,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xfc,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xfd,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xfe,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE}, \
+   {0xff,                      SCSI_XFER_AUTO,     NULL, SCSI_DONT_EMULATE},
 
 #endif
index 52b77e0ae0c94bf5f91ba1292326181df21f5700..fc88ae8e998404f9181f2e4028d7ad368553360d 100644 (file)
 #   include <linux/bios32.h>
 #endif
 
+#if KERNEL_VERSION(2, 6, 6) <= LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
+#   ifndef DMA_BIT_MASK
+#      define DMA_BIT_MASK(n) DMA_##n##BIT_MASK
+#   endif
+#endif
+
 
 /* 2.0.x has useless struct pci_dev; remap it to our own */
 #ifndef KERNEL_2_1
index 685be7b769381b935a3947227bcdb12a9d48d82e..f4623d5d7e090bbb1b72a69d2d3b03b6537e4528 100644 (file)
@@ -37,7 +37,9 @@
 #define compat_skb_end_pointer(skb)        skb_end_pointer(skb)
 #define compat_skb_ip_header(skb)          ((struct iphdr *)skb_network_header(skb))
 #define compat_skb_tcp_header(skb)         ((struct tcphdr *)skb_transport_header(skb))
-#define compat_skb_reset_mac_header(skb)   skb_reset_mac_header(skb)
+#define compat_skb_reset_mac_header(skb)          skb_reset_mac_header(skb)
+#define compat_skb_reset_network_header(skb)      skb_reset_network_header(skb)
+#define compat_skb_reset_transport_header(skb)    skb_reset_transport_header(skb)
 #define compat_skb_set_network_header(skb, off)   skb_set_network_header(skb, off)
 #define compat_skb_set_transport_header(skb, off) skb_set_transport_header(skb, off)
 #else
@@ -52,6 +54,8 @@
 #define compat_skb_ip_header(skb)          (skb)->nh.iph
 #define compat_skb_tcp_header(skb)         (skb)->h.th
 #define compat_skb_reset_mac_header(skb)   ((skb)->mac.raw = (skb)->data)
+#define compat_skb_reset_network_header(skb)      ((skb)->nh.raw = (skb)->data)
+#define compat_skb_reset_transport_header(skb)    ((skb)->h.raw = (skb)->data)
 #define compat_skb_set_network_header(skb, off)   ((skb)->nh.raw = (skb)->data + (off))
 #define compat_skb_set_transport_header(skb, off) ((skb)->h.raw = (skb)->data + (off))
 #endif
index 9829d49187f8f9260c507023db10b74a53c87c47..89542d1f8d2a2607d0ccb495c9b93e5d1fe24ad3 100644 (file)
@@ -85,7 +85,7 @@ typedef struct VMCIDatagramWellKnownMapMsg {
  * Struct size is 16 bytes. All fields in struct are aligned to their natural
  * alignment.
  */
-typedef struct VMCIResourcesQueuryHdr {
+typedef struct VMCIResourcesQueryHdr {
    VMCIDatagram hdr;
    uint32       numResources;
    uint32       _padding;
index 6560e2bc0342421ec06a84da3ab0bfd2a9e52046..67b6be9b7cff70481295c9d2f6ba15e5d8dc35e1 100644 (file)
@@ -42,6 +42,7 @@ typedef enum {
    VMCIOBJ_CONTEXT,
    VMCIOBJ_PROCESS,
    VMCIOBJ_DATAGRAM_PROCESS,
+   VMCIOBJ_SOCKET,
    VMCIOBJ_NOT_SET,
 } VMCIObjType;
 
index 777d70db6c3c6c4ea832625c5158db8d9fbbb79b..979f8df5ccd7d4ed7affd4c6b9c67f3ff1299b41 100644 (file)
@@ -255,6 +255,7 @@ enum IOCTLCmd_VMCI {
  * or opening the device in kernel-mode, and are always in UNICODE.
  */
 #define VMCI_DEVICE_NAME         TEXT("\\\\.\\VMCI")
+#define VMCI_DEVICE_NAME_NT      L"\\??\\VMCI"
 #define VMCI_DEVICE_NAME_PATH    L"\\Device\\vmci"
 #define VMCI_DEVICE_LINK_PATH    L"\\DosDevices\\vmci"
 
@@ -333,24 +334,26 @@ enum IOCTLCmd_VMCI {
                VMCIIOCTL_BUFFERED(SOCKETS_IOCTL)
 #define IOCTL_VMCI_SOCKETS_LISTEN \
                VMCIIOCTL_BUFFERED(SOCKETS_LISTEN)
-#define IOCTL_VMCI_SOCKETS_RECV \
-               VMCIIOCTL_BUFFERED(SOCKETS_RECV)
 #define IOCTL_VMCI_SOCKETS_RECV_FROM \
                VMCIIOCTL_BUFFERED(SOCKETS_RECV_FROM)
 #define IOCTL_VMCI_SOCKETS_SELECT \
                VMCIIOCTL_BUFFERED(SOCKETS_SELECT)
-#define IOCTL_VMCI_SOCKETS_SEND \
-               VMCIIOCTL_BUFFERED(SOCKETS_SEND)
 #define IOCTL_VMCI_SOCKETS_SEND_TO \
                VMCIIOCTL_BUFFERED(SOCKETS_SEND_TO)
 #define IOCTL_VMCI_SOCKETS_SET_SOCK_OPT \
                VMCIIOCTL_BUFFERED(SOCKETS_SET_SOCK_OPT)
 #define IOCTL_VMCI_SOCKETS_SHUTDOWN \
                VMCIIOCTL_BUFFERED(SOCKETS_SHUTDOWN)
-#define IOCTL_VMCI_SOCKETS_SOCKET \
-               VMCIIOCTL_BUFFERED(SOCKETS_SOCKET)
 /* END VMCI SOCKETS */
 
+
+/*
+ * For accessing VMCIOBJ_SOCKET in IOCTLs.  Both functions take a file object's
+ * fs context and get or set the socket.
+ */
+PVOID VMCIFsContext_GetSocket(PVOID fsContext);
+void VMCIFsContext_SetSocket(PVOID fsContext, PVOID socket);
+
 #endif // _WIN32
 
 
index be69c284e861b26daaa6bd8725c4355685476ea7..fa2dc1924ca0fcc4af218e76b607a9ac14a7e645 100644 (file)
@@ -261,6 +261,33 @@ AddPointer(Atomic_uint64 *var, // IN:
       } VMCIQueue;
 #  endif
 #else
+  /*
+   * VMCIQueuePair_QueueIsMapped()
+   *
+   * This macro will return TRUE if a queue created by either the
+   * guest or host has had the memory for the queue pair mapped by the
+   * VMX and made avaiable to the host by way of the SetPageFile
+   * ioctls.
+   *
+   * After SetPageFile, the queue memory will remain available to the
+   * host until the host detaches.  On Linux and Mac OS platforms the
+   * memory for the queue pair remains available to the host driver
+   * after the VMX process for the guest goes away.  On Windows, the
+   * memory is copied (under the protection of a mutex) so that the
+   * host can continue to operate on the queues after the VMX is gone.
+   *
+   * The version of the VMCIQueue data structure which is provided by
+   * the VMCI kernel module is protected by the VMCI
+   * QueuePairList_Lock and the VMCI QueuePairList_FindEntry()
+   * function.  Therefore, host-side clients shouldn't be able to
+   * access the structure after it's gone.  And, the memory the
+   * queueHeaderPtr points to is torn down (and freed) after the entry
+   * has been removed from the QueuePairList and just before the entry
+   * itself is deallocated.
+   */
+
+#  define VMCIQueuePair_QueueIsMapped(q)       ((q)->queueHeaderPtr != NULL)
+
 #  if defined(__linux__) && defined(__KERNEL__)
       /*
        * Linux Kernel Host
@@ -277,7 +304,6 @@ AddPointer(Atomic_uint64 *var, // IN:
         VMCIQueueHeader *queueHeaderPtr;
         struct page **page;
       } VMCIQueue;
-#     define VMCIQueuePair_QueueIsMapped(q)    ((q)->page != NULL)
 #  elif defined __APPLE__
       /*
        * Mac OS Host
@@ -303,7 +329,6 @@ AddPointer(Atomic_uint64 *var, // IN:
          IOMemoryDescriptor *pages;
          IOMemoryMap *header;
       } VMCIQueue;
-#    define VMCIQueuePair_QueueIsMapped(q) ((q)->pages)
 #  else
       /*
        * Windows Host
@@ -353,7 +378,6 @@ AddPointer(Atomic_uint64 *var, // IN:
          FAST_MUTEX __mutex;   /* Don't touch except to init */
       } VMCIQueue;
 #define VMCIQueuePair_EnqueueToDevNull(q)      ((q)->enqueueToDevNull)
-#define VMCIQueuePair_QueueIsMapped(q)          ((q)->buffer != NULL)
 #  endif
 #endif
 
index 522fd73f8ac81717b4fcd18fcb528da21b461754..cd7ebaa398bdd465efc20924f3f9bc668bd9fe03 100644 (file)
@@ -27,8 +27,9 @@
 #include <linux/module.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
-#include "compat_uaccess.h"
-#include "compat_fs.h"
+#include <linux/fs.h>
+
+#include <asm/uaccess.h>
 
 #include "vmblockInt.h"
 #include "block.h"
@@ -295,14 +296,14 @@ ControlFileOpWrite(struct file *file,       // IN: Opened file, used for ID
     * side-stepping the syscall auditing and doing the copy from user space
     * ourself.  Change this back once we GPL the module.
     */
-   filename = compat___getname();
+   filename = __getname();
    if (!filename) {
       Warning("ControlFileOpWrite: Could not obtain memory for filename.\n");
       return -ENOMEM;
    }
 
    /*
-    * XXX: compat___getname() returns a pointer to a PATH_MAX-sized buffer.
+    * XXX: __getname() returns a pointer to a PATH_MAX-sized buffer.
     * Hard-coding this size is also gross, but it's our only option here and
     * InodeOpLookup() already set a bad example by doing this.
     */
@@ -338,7 +339,7 @@ ControlFileOpWrite(struct file *file,       // IN: Opened file, used for ID
    }
 
 exit:
-   compat___putname(filename);
+   __putname(filename);
    return ret;
 }
 
index 961d590877fad6105a9df0f73d581edd28637abc..66537c8c82bbcbb7aa87254c4d9084d27bd3f70a 100644 (file)
  */
 
 #include "driver-config.h"
-#include "compat_fs.h"
-#include "compat_namei.h"
 
+#include <linux/fs.h>
+#include "compat_namei.h"
 #include "vmblockInt.h"
 #include "filesystem.h"
 #include "block.h"
 
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 75)
 static int DentryOpRevalidate(struct dentry *dentry, struct nameidata *nd);
-#else
-static int DentryOpRevalidate(struct dentry *dentry, int flags);
-#endif
 
 struct dentry_operations LinkDentryOps = {
    .d_revalidate = DentryOpRevalidate,
@@ -62,15 +58,9 @@ struct dentry_operations LinkDentryOps = {
  *----------------------------------------------------------------------------
  */
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 75)
 static int
 DentryOpRevalidate(struct dentry *dentry,  // IN: dentry revalidating
                    struct nameidata *nd)   // IN: lookup flags & intent
-#else
-static int
-DentryOpRevalidate(struct dentry *dentry,  // IN: dentry revalidating
-                   int flags)              // IN: lookup flags (e.g., LOOKUP_CONTINUE)
-#endif
 {
    VMBlockInodeInfo *iinfo;
    struct nameidata actualNd;
@@ -111,14 +101,10 @@ DentryOpRevalidate(struct dentry *dentry,  // IN: dentry revalidating
    if (actualDentry &&
        actualDentry->d_op &&
        actualDentry->d_op->d_revalidate) {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 75)
       return actualDentry->d_op->d_revalidate(actualDentry, nd);
-#else
-      return actualDentry->d_op->d_revalidate(actualDentry, flags);
-#endif
    }
 
-   if (compat_path_lookup(iinfo->name, 0, &actualNd)) {
+   if (path_lookup(iinfo->name, 0, &actualNd)) {
       LOG(4, "DentryOpRevalidate: [%s] no longer exists\n", iinfo->name);
       return 0;
    }
index 6b651f0a29d33f61422b201c8caebcda1b31d49f..c55ae57ea83abd87a363d2a452ae23de96381c78 100644 (file)
@@ -25,8 +25,9 @@
 
 #include "driver-config.h"
 #include <linux/module.h>
-#include "compat_fs.h"
-#include "compat_sched.h"
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/pagemap.h>
 
 #include "vmblockInt.h"
 #include "filesystem.h"
index 850c97174dd8df7da8f2f299af4fece09a8fd83e..53840fdfb4a88483a8c467e83b2daef49fe8e10d 100644 (file)
  */
 
 #include "driver-config.h"
-#include "compat_kernel.h"
+#include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/proc_fs.h>
 #include <linux/mount.h>
-#include "compat_fs.h"
-#include "compat_spinlock.h"
+#include <linux/fs.h>
+
 #include "compat_namei.h"
-#include "compat_slab.h"
 
 #include "os.h"
 #include "vmblockInt.h"
 #define VMBLOCK_ROOT_INO  1
 #define GetRootInode(sb)  Iget(sb, NULL, NULL, VMBLOCK_ROOT_INO)
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 25)
-#   define KERNEL_25_FS 0
-#else
-#   define KERNEL_25_FS 1
-#endif
-
 static struct inode *GetInode(struct super_block *sb, ino_t ino);
 
 /* File system operations */
-#if KERNEL_25_FS /* { */
-#   if defined(VMW_GETSB_2618)
+
+#if defined(VMW_GETSB_2618)
 static int FsOpGetSb(struct file_system_type *fsType, int flags,
                      const char *devName, void *rawData, struct vfsmount *mnt);
-#   elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 70)
+#else
 static struct super_block *FsOpGetSb(struct file_system_type *fsType, int flags,
                                      const char *devName, void *rawData);
-#   else
-static struct super_block *FsOpGetSb(struct file_system_type *fsType, int flags,
-                                     char *devName, void *rawData);
-#   endif
-#else /* } { */
-static struct super_block *FsOpReadSuper24(struct super_block *sb, void *rawData,
-                                           int flags);
-#endif /* } */
+#endif
 static int FsOpReadSuper(struct super_block *sb, void *rawData, int flags);
 
 
@@ -80,12 +66,8 @@ static size_t fsRootLen;
 static struct file_system_type fsType = {
    .owner = THIS_MODULE,
    .name = VMBLOCK_FS_NAME,
-#if KERNEL_25_FS
    .get_sb = FsOpGetSb,
    .kill_sb = kill_anon_super,
-#else
-   .read_super = FsOpReadSuper24,
-#endif
 };
 
 
@@ -239,16 +221,9 @@ VMBlockReadInode(struct inode *inode)  // IN: Inode to initialize
 ino_t
 GetNextIno(void)
 {
-   static spinlock_t inoLock = SPIN_LOCK_UNLOCKED;
-   static ino_t nextIno = VMBLOCK_ROOT_INO + 1;
-   ino_t ret;
+   static atomic_t nextIno = ATOMIC_INIT(VMBLOCK_ROOT_INO + 1);
 
-   /* Too bad atomic_t's don't provide an atomic increment and read ... */
-   spin_lock(&inoLock);
-   ret = nextIno++;
-   spin_unlock(&inoLock);
-
-   return ret;
+   return (ino_t) atomic_inc_return(&nextIno);
 }
 
 
@@ -277,7 +252,6 @@ static struct inode *
 GetInode(struct super_block *sb, // IN: file system superblock object
         ino_t ino)              // IN: inode number to assign to new inode
 {
-#ifdef VMW_USE_IGET_LOCKED
    struct inode *inode;
 
    inode = iget_locked(sb, ino);
@@ -288,9 +262,6 @@ GetInode(struct super_block *sb, // IN: file system superblock object
       unlock_new_inode(inode);
    }
    return inode;
-#else
-   return iget(sb, ino);
-#endif
 }
 
 
@@ -414,11 +385,9 @@ error_inode:
 static void
 InodeCacheCtor(COMPAT_KMEM_CACHE_CTOR_ARGS(slabElem))  // IN: allocated slab item to initialize
 {
-#ifdef VMW_EMBED_INODE
    VMBlockInodeInfo *iinfo = slabElem;
 
    inode_init_once(&iinfo->inode);
-#endif
 }
 
 
@@ -460,6 +429,7 @@ MakeFullName(struct inode *dir,       // IN : directory
       bufOut[fsRootLen] = '\0';
    } else {
       VMBlockInodeInfo *dirIinfo;
+      int ret;
 
       ASSERT(dir);
       ASSERT(dentry);
@@ -470,47 +440,18 @@ MakeFullName(struct inode *dir,       // IN : directory
       }
 
       dirIinfo = INODE_TO_IINFO(dir);
+
       /*
        * If dirIinfo->name[1] is '\0', then it is "/" and we don't need
        * another '/' between it and the additional name.
        */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 10)
-      {
-         int ret;
-
-         ret = snprintf(bufOut, bufOutSize,
-                        dirIinfo->name[1] == '\0' ? "%s%s" : "%s/%s",
-                        dirIinfo->name, dentry->d_name.name);
-         if (ret >= bufOutSize) {
-            Warning("MakeFullName: path was too long.\n");
-            return -ENAMETOOLONG;
-         }
-      }
-#else
-      {
-         /* snprintf was not exported prior to 2.4.10 */
-         size_t dirLen;
-         size_t pathSepLen;
-         size_t dentryLen;
-         size_t pathLen;
-
-         dirLen = strlen(dirIinfo->name);
-         pathSepLen = dirLen == 1 ? 0 : 1;
-         dentryLen = strlen(dentry->d_name.name);
-         pathLen = dirLen + dentryLen + pathSepLen;
-         if (pathLen >= bufOutSize) {
-            Warning("MakeFullName: path was too long.\n");
-            return -ENAMETOOLONG;
-         }
-         memcpy(bufOut, dirIinfo->name, dirLen);
-         if (pathSepLen == 1) {
-            ASSERT(dirLen == 1);
-            bufOut[dirLen] = '/';
-         }
-         memcpy(bufOut + dirLen + pathSepLen, dentry->d_name.name, dentryLen);
-         bufOut[pathLen] = '\0';
+      ret = snprintf(bufOut, bufOutSize,
+                     dirIinfo->name[1] == '\0' ? "%s%s" : "%s/%s",
+                     dirIinfo->name, dentry->d_name.name);
+      if (ret >= bufOutSize) {
+         Warning("MakeFullName: path was too long.\n");
+         return -ENAMETOOLONG;
       }
-#endif
    }
 
    return 0;
@@ -593,7 +534,6 @@ FsOpReadSuper(struct super_block *sb, // OUT: Superblock object
 }
 
 
-#if KERNEL_25_FS /* { */
 #if defined(VMW_GETSB_2618)
 /*
  *-----------------------------------------------------------------------------
@@ -641,48 +581,13 @@ FsOpGetSb(struct file_system_type *fs_type, // IN: file system type of mount
  *-----------------------------------------------------------------------------
  */
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 70)
 static struct super_block *
 FsOpGetSb(struct file_system_type *fs_type, // IN: file system type of mount
           int flags,                        // IN: mount flags
           const char *dev_name,             // IN: device mounting on
           void *rawData)                    // IN: mount arguments
-#else
-static struct super_block *
-FsOpGetSb(struct file_system_type *fs_type, // IN: file system type of mount
-          int flags,                        // IN: mount flags
-          char *dev_name,                   // IN: device mounting on
-          void *rawData)                    // IN: mount arguments
-#endif
 {
    return get_sb_nodev(fs_type, flags, rawData, FsOpReadSuper);
 }
 #endif
-#else /* } { */
-
-/*
- *-----------------------------------------------------------------------------
- *
- * FsOpReadSuper24 --
- *
- *    Compatibility wrapper for 2.4.x kernels read_super.
- *    Converts success to sb, and failure to NULL.
- *
- * Results:
- *    The initialized superblock on success
- *    NULL on failure
- *
- * Side effects:
- *    None
- *
- *-----------------------------------------------------------------------------
- */
 
-static struct super_block *
-FsOpReadSuper24(struct super_block *sb,  // OUT: Superblock object
-                void *rawData,           // IN : mount arguments
-                int flags)               // IN : mount flags
-{
-   return FsOpReadSuper(sb, rawData, flags) ? NULL : sb;
-}
-#endif /* } */
index 2f39702d28bd9bdfd76b35c5788cddd02e826d8c..e4772fcf984aef11e3134a3f0a8821490b155eb1 100644 (file)
 #define __FILESYSTEM_H__
 
 #include "compat_slab.h"
-#include "compat_fs.h"
+#include <linux/fs.h>
 
 #include "vm_basic_types.h"
 
-#ifndef container_of
-#define container_of(ptr, type, memb)   ((type *)((char *)(ptr) - offsetof(type, memb)))
-#endif
-
-#ifdef VMW_EMBED_INODE
-# define INODE_SET_IINFO(inode, iinfo)
-# define INODE_TO_IINFO(_inode)         container_of(_inode, VMBlockInodeInfo, inode)
-#else
-# define INODE_SET_IINFO(inode, iinfo)  (inode)->u.generic_ip = iinfo
-# define INODE_TO_IINFO(_inode)                                              \
-         ({                                                                  \
-            /* Allocate an inode info for new inodes */                      \
-            if ((_inode)->u.generic_ip == NULL) {                            \
-               VMBlockInodeInfo *_iinfo;                                     \
-               ASSERT(VMBlockInodeCache);                                    \
-               _iinfo = kmem_cache_alloc(VMBlockInodeCache, SLAB_KERNEL);    \
-               /* We must set the inode info for new inodes */               \
-               INODE_SET_IINFO(_inode, _iinfo);                              \
-            }                                                                \
-            ((VMBlockInodeInfo *)((_inode)->u.generic_ip));                  \
-         })
-#endif
-
+#define INODE_TO_IINFO(_inode)          container_of(_inode, VMBlockInodeInfo, inode)
 #define INODE_TO_ACTUALDENTRY(inode)    INODE_TO_IINFO(inode)->actualDentry
 #define INODE_TO_ACTUALINODE(inode)     INODE_TO_IINFO(inode)->actualDentry->d_inode
 
@@ -83,10 +61,8 @@ typedef struct VMBlockInodeInfo {
    char name[PATH_MAX];
    size_t nameLen;
    struct dentry *actualDentry;
-#ifdef VMW_EMBED_INODE
    /* Embedded inode */
    struct inode inode;
-#endif
 } VMBlockInodeInfo;
 
 
index d27dc28b4480d4c15112094551238fcfaa40f8ed..098c94c8cb4cae87f47e72e8a3601cb44db4ccdd 100644 (file)
 
 #include "driver-config.h"
 #include <linux/module.h>
-#include "compat_fs.h"
+#include <linux/fs.h>
 #include <linux/time.h>
-#include "compat_namei.h"
-#include "compat_uaccess.h"
-#include "compat_sched.h"
+#include <linux/namei.h>
 
 #include "vmblockInt.h"
 #include "filesystem.h"
 
 
 /* Inode operations */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 75)
 static struct dentry *InodeOpLookup(struct inode *dir,
                                     struct dentry *dentry, struct nameidata *nd);
-#else
-static struct dentry *InodeOpLookup(struct inode *dir, struct dentry *dentry);
-#endif
 static int InodeOpReadlink(struct dentry *dentry, char __user *buffer, int buflen);
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
 static void *InodeOpFollowlink(struct dentry *dentry, struct nameidata *nd);
@@ -78,16 +72,10 @@ static struct inode_operations LinkInodeOps = {
  *----------------------------------------------------------------------------
  */
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 75)
 static struct dentry *
 InodeOpLookup(struct inode *dir,      // IN: parent directory's inode
               struct dentry *dentry,  // IN: dentry to lookup
               struct nameidata *nd)   // IN: lookup intent and information
-#else
-static struct dentry *
-InodeOpLookup(struct inode *dir,      // IN: parent directory's inode
-              struct dentry *dentry)  // IN: dentry to lookup
-#endif
 {
    char *filename;
    struct inode *inode;
@@ -105,7 +93,7 @@ InodeOpLookup(struct inode *dir,      // IN: parent directory's inode
    }
 
    /* Get a slab from the kernel's names_cache of PATH_MAX-sized buffers. */
-   filename = compat___getname();
+   filename = __getname();
    if (!filename) {
       Warning("InodeOpLookup: unable to obtain memory for filename.\n");
       return ERR_PTR(-ENOMEM);
@@ -114,13 +102,13 @@ InodeOpLookup(struct inode *dir,      // IN: parent directory's inode
    ret = MakeFullName(dir, dentry, filename, PATH_MAX);
    if (ret < 0) {
       Warning("InodeOpLookup: could not construct full name\n");
-      compat___putname(filename);
+      __putname(filename);
       return ERR_PTR(ret);
    }
 
    /* Block if there is a pending block on this file */
    BlockWaitOnFile(filename, NULL);
-   compat___putname(filename);
+   __putname(filename);
 
    inode = Iget(dir->i_sb, dir, dentry, GetNextIno());
    if (!inode) {
index c24f2efc180aa6225cb696d880e07b7711a2d996..bb33165d4362c78edcac2cf3ce9185ca394ae4dc 100644 (file)
  */
 
 #include "driver-config.h"
-#include "compat_init.h"
-#include "compat_kernel.h"
-#include "compat_module.h"
+#include <linux/init.h>
+#include <linux/module.h>
 #include <linux/limits.h>
 #include <linux/errno.h>
-#include "compat_string.h"
 
 #include "vmblockInt.h"
 #include "vmblock_version.h"
 /* Module parameters */
 #ifdef VMX86_DEVEL /* { */
 int LOGLEVEL_THRESHOLD = 4;
-#  if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9)
-   module_param(LOGLEVEL_THRESHOLD, int, 0600);
-#  else
-   MODULE_PARM(LOGLEVEL_THRESHOLD, "i");
-#  endif
+module_param(LOGLEVEL_THRESHOLD, int, 0600);
 MODULE_PARM_DESC(LOGLEVEL_THRESHOLD, "Logging level (0 means no log, "
                  "10 means very verbose, 4 is default)");
 #endif /* } */
 
 static char *root = "/tmp/VMwareDnD";
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9)
 module_param(root, charp, 0600);
-#else
-MODULE_PARM(root, "s");
-#endif
 MODULE_PARM_DESC(root, "The directory the file system redirects to.");
 
 /* Module information */
@@ -67,15 +57,6 @@ MODULE_VERSION(VMBLOCK_DRIVER_VERSION_STRING);
  */
 MODULE_INFO(supported, "external");
 
-/* Functions */
-static int VMBlockInit(void);
-static void VMBlockExit(void);
-
-/* Define init/exit routines */
-module_init(VMBlockInit);
-module_exit(VMBlockExit);
-
-
 /*
  *----------------------------------------------------------------------------
  *
@@ -117,6 +98,8 @@ error:
    return ret;
 }
 
+module_init(VMBlockInit);
+
 
 /*
  *----------------------------------------------------------------------------
@@ -144,39 +127,4 @@ VMBlockExit(void)
    LOG(4, "module unloaded\n");
 }
 
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 70)
-/*
- *----------------------------------------------------------------------------
- *
- * strlcpy --
- *
- *    2.4 doesn't have strlcpy().
- *
- *    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;
-}
-#endif
+module_exit(VMBlockExit);
index eaeb44f0e862086d1a3771c7274f18e45370d07f..f592e17e51ce86b82461b2a3db53d9514326ce81 100644 (file)
 #define __OS_H__
 
 #include "driver-config.h"
-#include "compat_list.h"
-#include "compat_completion.h"
+#include <linux/completion.h>
 #include <linux/limits.h>
 #include "compat_slab.h"
-#include "compat_wait.h"
+#include <linux/sched.h>
 #include <asm/atomic.h>
 #include <asm/errno.h>
-#include "compat_sched.h"
 #include <asm/current.h>
-#include "compat_kernel.h"
-#include "compat_spinlock.h"
 
 typedef rwlock_t os_rwlock_t;
 typedef compat_kmem_cache os_kmem_cache_t;
-typedef compat_completion os_completion_t;
+typedef struct completion os_completion_t;
 typedef atomic_t os_atomic_t;
 typedef struct file * os_blocker_id_t;
 
@@ -54,22 +50,12 @@ typedef struct file * os_blocker_id_t;
 
 #define OS_FMTTID                       "d"
 #define os_threadid                     (current->pid)
-/*
- * XXX vprintk() wasn't exported until 2.6.9; we should do something more
- * intelligent here eventually.
- */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9)
-# define os_panic(fmt, args)             \
+
+#define os_panic(fmt, args)              \
       ({                                 \
           vprintk(fmt, args);            \
           BUG();                         \
       })
-#else
-# define os_panic(fmt, args)             \
-      ({                                 \
-          BUG();                         \
-      })
-#endif
 
 #define os_rwlock_init(lock)            rwlock_init(lock)
 #define os_rwlock_destroy(lock)
@@ -94,7 +80,7 @@ typedef struct file * os_blocker_id_t;
 #define os_kmem_cache_alloc(cache)      kmem_cache_alloc(cache, GFP_KERNEL)
 #define os_kmem_cache_free(cache, elem) kmem_cache_free(cache, elem)
 
-#define os_completion_init(comp)        compat_init_completion(comp)
+#define os_completion_init(comp)        init_completion(comp)
 #define os_completion_destroy(comp)
 /*
  * XXX This should be made interruptible using
@@ -103,10 +89,10 @@ typedef struct file * os_blocker_id_t;
  */
 #define os_wait_for_completion(comp)                                    \
 ({                                                                      \
-    compat_wait_for_completion(comp);                                   \
+    wait_for_completion(comp);                                          \
     0;                                                                  \
  })
-#define os_complete_all(comp)           compat_complete_all(comp)
+#define os_complete_all(comp)           complete_all(comp)
 
 #define os_atomic_dec_and_test(atomic)  atomic_dec_and_test(atomic)
 #define os_atomic_dec(atomic)           atomic_dec(atomic)
index 79e2e4a90f638787572ad77af158bc172ebd2737..fb65c578cf15ce3bb54f15883e19738c3f063ba3 100644 (file)
  */
 
 #include "driver-config.h"
-#include "compat_fs.h"
-#include "compat_statfs.h"
+#include <linux/fs.h>
+#include <linux/statfs.h>
 
 #include "vmblockInt.h"
 #include "filesystem.h"
 
 /* Super block operations */
-#ifdef VMW_EMBED_INODE
 static struct inode *SuperOpAllocInode(struct super_block *sb);
 static void SuperOpDestroyInode(struct inode *inode);
-#else
-static void SuperOpClearInode(struct inode *inode);
-#endif
-#ifndef VMW_USE_IGET_LOCKED
-static void SuperOpReadInode(struct inode *inode);
-#endif
 #ifdef VMW_STATFS_2618
-static int SuperOpStatfs(struct dentry *dentry, struct compat_kstatfs *stat);
+static int SuperOpStatfs(struct dentry *dentry, struct kstatfs *stat);
 #else
-static int SuperOpStatfs(struct super_block *sb, struct compat_kstatfs *stat);
+static int SuperOpStatfs(struct super_block *sb, struct kstatfs *stat);
 #endif
 
 
 struct super_operations VMBlockSuperOps = {
-#ifdef VMW_EMBED_INODE
    .alloc_inode   = SuperOpAllocInode,
    .destroy_inode = SuperOpDestroyInode,
-#else
-   .clear_inode   = SuperOpClearInode,
-#endif
-#ifndef VMW_USE_IGET_LOCKED
-   .read_inode    = SuperOpReadInode,
-#endif
    .statfs        = SuperOpStatfs,
 };
 
 
-#ifdef VMW_EMBED_INODE
 /*
  *----------------------------------------------------------------------------
  *
@@ -93,7 +78,6 @@ SuperOpAllocInode(struct super_block *sb) // IN: superblock of file system
    /* The inode we give back to VFS is embedded within our inode info struct. */
    return &iinfo->inode;
 }
-#endif
 
 
 /*
@@ -116,43 +100,12 @@ SuperOpAllocInode(struct super_block *sb) // IN: superblock of file system
  */
 
 static void
-#ifdef VMW_EMBED_INODE
 SuperOpDestroyInode(struct inode *inode)  // IN: Inode to free
-#else
-SuperOpClearInode(struct inode *inode)    // IN: Inode to free
-#endif
 {
    kmem_cache_free(VMBlockInodeCache, INODE_TO_IINFO(inode));
 }
 
 
-#ifndef VMW_USE_IGET_LOCKED
-/*
- *----------------------------------------------------------------------------
- *
- * SuperOpReadInode --
- *
- *    Performs any filesystem wide inode initialization. This is only called by
- *    iget() in older kernels that do not support iget_locked(). Newer kernels
- *    that use the iget_locked() interface are required to initialize the inode
- *    after it has been returned to the filesystem.
- *
- * Results:
- *    None.
- *
- * Side effects:
- *    None.
- *
- *----------------------------------------------------------------------------
- */
-
-static void
-SuperOpReadInode(struct inode *inode)  // IN: Inode to initialize
-{
-   VMBlockReadInode(inode);
-}
-#endif
-
 /*
  *----------------------------------------------------------------------------
  *
@@ -172,11 +125,11 @@ SuperOpReadInode(struct inode *inode)  // IN: Inode to initialize
 #ifdef VMW_STATFS_2618
 static int
 SuperOpStatfs(struct dentry *dentry,
-              struct compat_kstatfs *stat)
+              struct kstatfs *stat)
 #else
 static int
 SuperOpStatfs(struct super_block *sb,
-              struct compat_kstatfs *stat)
+              struct kstatfs *stat)
 #endif
 {
    if (!stat) {
index db8e420e0d4b3b978d0c5eec8b7daf1ed472c78b..76cc4a165bc51ac7c6ceec407cf9619690a19702 100644 (file)
@@ -33,8 +33,8 @@
 #ifndef __VMBLOCKINT_H__
 #define __VMBLOCKINT_H__
 
-#include "compat_version.h"
-#include "compat_mm.h"
+#include <linux/version.h>
+#include <linux/mm.h>
 
 #include "vmblock.h"
 #include "vm_basic_types.h"
@@ -73,9 +73,7 @@ extern int LOGLEVEL_THRESHOLD;
  *
  * XXX This should go in driver-config.h, but vmmon's hostKernel.h is retarded.
  */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 29)
 static const void *forceProcessorCheck __attribute__((unused)) = __alloc_pages;
-#endif
 
 
 /*
@@ -87,8 +85,4 @@ int VMBlockCleanupControlOps(void);
 int VMBlockInitFileSystem(char const *root);
 int VMBlockCleanupFileSystem(void);
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 70)
-size_t strlcpy(char *dest, const char *src, size_t count);
-#endif
-
 #endif /* __VMBLOCK_H__ */
index d9e5cd14fffa59c9f08e49f3f953c355332ac23f..f57b0eb8032159b7a8c7b479f4e385fa89a087c7 100644 (file)
  *********************************************************/
 
 /*
- * vmciGuestKernelIf.c -- 
- * 
+ * vmciGuestKernelIf.c --
+ *
  *      This file implements guest only OS helper functions for VMCI.
  *      This is the linux specific implementation.
- */ 
+ */
 
 /* Must come before any kernel header file */
 #include "driver-config.h"
@@ -30,9 +30,7 @@
 #error "Wrong platform."
 #endif
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9)
 #include <linux/moduleparam.h>
-#endif
 
 #include "compat_version.h"
 #include "compat_pci.h"
index cc2de6acc10ed04f124f51aa22af31501f3ea723..1bd87968f8e0e9905ddd503c09fabba19dfce40f 100644 (file)
 #error "Wrong platform."
 #endif
 
+#if !defined(VMX86_TOOLS) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9)
+#  error "Host Linux kernels before 2.6.9 are not supported."
+#endif
+
 #define EXPORT_SYMTAB
 #define __NO_VERSION__
 #include "compat_module.h"
@@ -1416,7 +1420,6 @@ VMCIHost_GetUserMemory(PageStoreAttachInfo *attach,      // IN/OUT
                        VMCIQueue *produceQ,              // OUT
                        VMCIQueue *consumeQ)              // OUT
 {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
    int retval;
    int err = VMCI_SUCCESS;
 
@@ -1501,70 +1504,6 @@ errorDealloc:
    }
 
    return err;
-
-#else
-   /*
-    * Host queue pair support for earlier kernels temporarily
-    * disabled. See bug 365496.
-    */
-
-   ASSERT_NOT_IMPLEMENTED(FALSE);
-#if 0
-   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;
-   }
-
-   if (err == VMCI_SUCCESS) {
-      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];
-   }
-
-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;
-#else // 0 -- Instead just return FALSE
-   return FALSE;
-#endif // 0
-#endif // Linux version >= 2.6.0
 }
 
 
@@ -1590,8 +1529,6 @@ VMCIHost_ReleaseUserMemory(PageStoreAttachInfo *attach,      // IN/OUT
                            VMCIQueue *produceQ,              // OUT
                            VMCIQueue *consumeQ)              // OUT
 {
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
    int i;
 
    ASSERT(attach->producePages);
@@ -1620,31 +1557,6 @@ VMCIHost_ReleaseUserMemory(PageStoreAttachInfo *attach,      // IN/OUT
    VMCI_FreeKernelMem(attach->consumePages,
                       attach->numConsumePages *
                       sizeof attach->consumePages[0]);
-#else
-   /*
-    * Host queue pair support for earlier kernels temporarily
-    * disabled. See bug 365496.
-    */
-
-   ASSERT_NOT_IMPLEMENTED(FALSE);
-#if 0
-   kunmap(attach->produceIoBuf->maplist[0]);
-   kunmap(attach->consumeIoBuf->maplist[0]);
-
-   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
 }
 
-#endif
+#endif  /* Host only code */
index ac64f024f7e53ef709e98fdbb48b91504c667f22..e487ecbd28c3500f88f8297877111d1f08b81cdd 100644 (file)
  *
  *********************************************************/
 
-/* 
+/*
  * vmci.c --
  *
  *      Linux guest driver for the VMCI device.
  */
-   
+
 #include "driver-config.h"
 
-#define EXPORT_SYMTAB
-   
-   
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9)
 #include <linux/moduleparam.h>
-#endif
-   
+
 #include "compat_kernel.h"
 #include "compat_module.h"
 #include "compat_pci.h"
@@ -73,11 +68,11 @@ static int vmci_probe_device(struct pci_dev *pdev,
 static void vmci_remove_device(struct pci_dev* pdev);
 static int vmci_open(struct inode *inode, struct file *file);
 static int vmci_close(struct inode *inode, struct file *file);
-static int vmci_ioctl(struct inode *inode, struct file *file, 
+static int vmci_ioctl(struct inode *inode, struct file *file,
                       unsigned int cmd, unsigned long arg);
 static unsigned int vmci_poll(struct file *file, poll_table *wait);
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
-static compat_irqreturn_t vmci_interrupt(int irq, void *dev_id, 
+static compat_irqreturn_t vmci_interrupt(int irq, void *dev_id,
                                          struct pt_regs * regs);
 #else
 static compat_irqreturn_t vmci_interrupt(int irq, void *dev_id);
@@ -109,15 +104,15 @@ static vmci_device vmci_dev;
 /* We dynamically request the device major number at init time. */
 static int device_major_nr = 0;
 
-DECLARE_TASKLET(vmci_tasklet, dispatch_datagrams, 
+DECLARE_TASKLET(vmci_tasklet, dispatch_datagrams,
                 (unsigned long)&vmci_dev);
 
-/* 
- * Allocate a buffer for incoming datagrams globally to avoid repeated 
- * allocation in the interrupt handler's atomic context. 
- */ 
+/*
+ * Allocate a buffer for incoming datagrams globally to avoid repeated
+ * allocation in the interrupt handler's atomic context.
+ */
 
-static uint8 *data_buffer = NULL;  
+static uint8 *data_buffer = NULL;
 static uint32 data_buffer_size = VMCI_MAX_DG_SIZE;
 
 
@@ -145,7 +140,7 @@ vmci_init(void)
    /* Register device node ops. */
    err = register_chrdev(0, "vmci", &vmci_ops);
    if (err < 0) {
-      printk(KERN_ERR "Unable to register vmci device\n"); 
+      printk(KERN_ERR "Unable to register vmci device\n");
       return err;
    }
    device_major_nr = err;
@@ -161,7 +156,7 @@ vmci_init(void)
    if (data_buffer == NULL) {
       goto error;
    }
-  
+
    /* This should be last to make sure we are done initializing. */
    err = pci_register_driver(&vmci_driver);
    if (err < 0) {
@@ -197,7 +192,7 @@ static void
 vmci_exit(void)
 {
    pci_unregister_driver(&vmci_driver);
-   
+
    unregister_chrdev(device_major_nr, "vmci");
 
    vfree(data_buffer);
@@ -293,7 +288,7 @@ vmci_probe_device(struct pci_dev *pdev,           // IN: vmci PCI device
    vmci_dev.enabled = TRUE;
    pci_set_drvdata(pdev, &vmci_dev);
 
-   /* 
+   /*
     * We do global initialization here because we need datagrams for
     * event init. If we ever support more than one VMCI device we will
     * have to create seperate LateInit/EarlyExit functions that can be
@@ -309,7 +304,7 @@ vmci_probe_device(struct pci_dev *pdev,           // IN: vmci PCI device
    VMCIUtil_Init();
    VMCIQueuePair_Init();
 
-   if (request_irq(vmci_dev.irq, vmci_interrupt, COMPAT_IRQF_SHARED, 
+   if (request_irq(vmci_dev.irq, vmci_interrupt, COMPAT_IRQF_SHARED,
                    "vmci", &vmci_dev)) {
       printk(KERN_ERR "vmci: irq %u in use\n", vmci_dev.irq);
       goto components_exit;
@@ -372,7 +367,7 @@ vmci_remove_device(struct pci_dev* pdev)
    VMCIEvent_Exit();
    //VMCIDatagram_Exit();
    VMCIProcess_Exit();
-   
+
    down(&dev->lock);
    printk(KERN_INFO "Resetting vmci device\n");
    outl(VMCI_CONTROL_RESET, vmci_dev.ioaddr + VMCI_CONTROL_ADDR);
@@ -382,7 +377,7 @@ vmci_remove_device(struct pci_dev* pdev)
 
    printk(KERN_INFO "Unregistered vmci device.\n");
    up(&dev->lock);
-   
+
    compat_pci_disable_device(pdev);
 }
 
@@ -549,7 +544,7 @@ vmci_ioctl(struct inode *inode,  // IN
         retval = -EFAULT;
         break;
       }
-      
+
       if (VMCIDatagramProcess_Create(&dgmProc, &createInfo,
                                      0 /* Unused */) < VMCI_SUCCESS) {
         retval = -EINVAL;
@@ -608,8 +603,8 @@ vmci_ioctl(struct inode *inode,  // IN
       }
 
       DEBUG_ONLY(printk("VMCI: Datagram dst handle 0x%x:0x%x, src handle "
-                       "0x%x:0x%x, payload size %"FMT64"u.\n", 
-                       dg->dst.context, dg->dst.resource, 
+                       "0x%x:0x%x, payload size %"FMT64"u.\n",
+                       dg->dst.context, dg->dst.resource,
                        dg->src.context, dg->src.resource, dg->payloadSize));
 
       sendInfo.result = VMCIDatagram_Send(dg);
@@ -638,8 +633,8 @@ vmci_ioctl(struct inode *inode,  // IN
       }
 
       ASSERT(devHndl->obj);
-      recvInfo.result = 
-        VMCIDatagramProcess_ReadCall((VMCIDatagramProcess *)devHndl->obj, 
+      recvInfo.result =
+        VMCIDatagramProcess_ReadCall((VMCIDatagramProcess *)devHndl->obj,
                                      recvInfo.len, &dg);
       if (recvInfo.result < VMCI_SUCCESS) {
         retval = -EINVAL;
@@ -699,17 +694,17 @@ vmci_poll(struct file *file, // IN
    VMCIGuestDeviceHandle *devHndl =
       (VMCIGuestDeviceHandle *) file->private_data;
 
-   /* 
-    * Check for call to this VMCI process. 
+   /*
+    * Check for call to this VMCI process.
     */
-   
+
    if (!devHndl) {
       return mask;
    }
    if (devHndl->objType == VMCIOBJ_DATAGRAM_PROCESS) {
       VMCIDatagramProcess *dgmProc = (VMCIDatagramProcess *) devHndl->obj;
       ASSERT(dgmProc);
-      
+
       if (wait != NULL) {
          poll_wait(file, &dgmProc->host.waitQueue, wait);
       }
@@ -803,7 +798,7 @@ VMCI_DeviceEnabled(void)
    down(&vmci_dev.lock);
    retval = vmci_dev.enabled;
    up(&vmci_dev.lock);
-   
+
    return retval;
 }
 
@@ -846,7 +841,7 @@ VMCI_SendDatagram(VMCIDatagram *dg)
     */
    spin_lock_irqsave(&vmci_dev.dev_spinlock, flags);
 
-   /* 
+   /*
     * Send the datagram and retrieve the return value from the result register.
     */
    __asm__ __volatile__(
@@ -894,7 +889,7 @@ dispatch_datagrams(unsigned long data)
             "present.\n");
       return;
    }
-      
+
    if (data_buffer == NULL) {
       printk(KERN_DEBUG "vmci: dispatch_datagrams(): no buffer present.\n");
       return;
index e92477f3c69150912ce7021a586f07026f82948e..01b6cf44fdfeba6e55d311ea4fa3535861abdc94 100644 (file)
@@ -25,8 +25,8 @@
 #ifndef _VMCI_VERSION_H_
 #define _VMCI_VERSION_H_
 
-#define VMCI_DRIVER_VERSION          1.0.18.0
-#define VMCI_DRIVER_VERSION_COMMAS   1,0,18,0
-#define VMCI_DRIVER_VERSION_STRING   "1.0.18.0"
+#define VMCI_DRIVER_VERSION          1.0.19.0
+#define VMCI_DRIVER_VERSION_COMMAS   1,0,19,0
+#define VMCI_DRIVER_VERSION_STRING   "1.0.19.0"
 
 #endif /* _VMCI_VERSION_H_ */
index 18e52c82ca477ad8965d0e4a00ecda0f21c70312..7865e13f6b2c24f4fad36da7e9892805ce1b8aed 100644 (file)
 
 /* Private functions. */
 static int HgfsUnpackSearchReadReply(HgfsReq *req,
-                                     HgfsAttrInfo *attr);
+                                     HgfsAttrInfo *attr,
+                                     char **entryName);
 static int HgfsGetNextDirEntry(HgfsSuperInfo *si,
                                HgfsHandle searchHandle,
                                uint32 offset,
                                HgfsAttrInfo *attr,
+                               char **entryName,
                                Bool *done);
 static int HgfsPackDirOpenRequest(struct inode *inode,
                                   struct file *file,
-                                 HgfsOp opUsed,
+                                  HgfsOp opUsed,
                                   HgfsReq *req);
 
 /* HGFS file operations for directories. */
@@ -98,7 +100,8 @@ struct file_operations HgfsDirFileOperations = {
  */
 static int
 HgfsUnpackSearchReadReply(HgfsReq *req,        // IN: Reply packet
-                          HgfsAttrInfo *attr)  // IN/OUT: Attributes
+                          HgfsAttrInfo *attr,  // IN/OUT: Attributes
+                          char **entryName)    // OUT: file name
 {
    char *fileName;
    uint32 fileNameLength;
@@ -175,15 +178,15 @@ HgfsUnpackSearchReadReply(HgfsReq *req,        // IN: Reply packet
                  fileNameLength, strlen(fileName), fileName));
          return -EPROTO;
       }
-      attr->fileName = kmalloc(fileNameLength + 1, GFP_KERNEL);
-      if (attr->fileName == NULL) {
+      *entryName = kmalloc(fileNameLength + 1, GFP_KERNEL);
+      if (*entryName == NULL) {
          LOG(4, (KERN_DEBUG "VMware hgfs: HgfsUnpackSearchReadReply: out of "
                  "memory allocating filename, ignoring\n"));
          return -ENOMEM;
       }
-      memcpy(attr->fileName, fileName, fileNameLength + 1);
+      memcpy(*entryName, fileName, fileNameLength + 1);
    } else {
-      attr->fileName = NULL;
+      *entryName = NULL;
    }
    return 0;
 }
@@ -196,7 +199,7 @@ HgfsUnpackSearchReadReply(HgfsReq *req,        // IN: Reply packet
  *
  *    Get the directory entry with the given offset from the server.
  *
- *    attr->fileName gets allocated and must be freed by the caller.
+ *    fileName gets allocated and must be freed by the caller.
  *
  * Results:
  *    Returns zero on success, negative error on failure. If the
@@ -213,6 +216,7 @@ HgfsGetNextDirEntry(HgfsSuperInfo *si,       // IN: Superinfo for this SB
                     HgfsHandle searchHandle, // IN: Handle of dir
                     uint32 offset,           // IN: Offset of next dentry to get
                     HgfsAttrInfo *attr,      // OUT: File attributes of dentry
+                    char **entryName,        // OUT: File name
                     Bool *done)              // OUT: Set true when there are
                                              // no more dentries
 {
@@ -268,8 +272,8 @@ HgfsGetNextDirEntry(HgfsSuperInfo *si,       // IN: Superinfo for this SB
 
       switch(result) {
       case 0:
-         result = HgfsUnpackSearchReadReply(req, attr);
-         if (result == 0 && attr->fileName == NULL) {
+         result = HgfsUnpackSearchReadReply(req, attr, entryName);
+         if (result == 0 && *entryName == NULL) {
             /* We're at the end of the directory. */
             LOG(6, (KERN_DEBUG "VMware hgfs: HgfsGetNextDirEntry: end of "
                     "dir\n"));
@@ -573,6 +577,7 @@ HgfsReaddir(struct file *file, // IN:  Directory to read from
    HgfsSuperInfo *si;
    HgfsAttrInfo attr;
    uint32 d_type;    // type of dirent
+   char *fileName = NULL;
    char *escName = NULL; // buf for escaped version of name
    size_t escNameLength = NAME_MAX + 1;
    int nameLength = 0;
@@ -616,13 +621,14 @@ HgfsReaddir(struct file *file, // IN:  Directory to read from
        * Nonzero result = we failed to get valid reply from server.
        * Zero result:
        *     - done == TRUE means we hit the end of the directory
-       *     - Otherwise, attr.fileName has the name of the next dirent
+       *     - Otherwise, fileName has the name of the next dirent
        *
        */
       result = HgfsGetNextDirEntry(si,
                                    FILE_GET_FI_P(file)->handle,
                                    (uint32)file->f_pos,
                                    &attr,
+                                   &fileName,
                                    &done);
       if (result == -ENAMETOOLONG) {
          /*
@@ -654,11 +660,10 @@ HgfsReaddir(struct file *file, // IN:  Directory to read from
        * CP name format, but that is done implicitely here since we
        * are guaranteed to have just one path component per dentry.
        */
-      result = HgfsEscape_Do(attr.fileName,
-                            strlen(attr.fileName),
-                            escNameLength,
-                            escName);
-      kfree(attr.fileName);
+      result = HgfsEscape_Do(fileName, strlen(fileName),
+                             escNameLength, escName);
+      kfree(fileName);
+      fileName = NULL;
 
       /*
        * Check the filename length.
index 3c69efdcb4625eef0cd54d79ee4f62f66a2b17d4..8d28b79c9d7a81f7c1bb67f4383cd6bf5a4a219e 100644 (file)
@@ -52,7 +52,8 @@ static struct inode *HgfsInodeLookup(struct super_block *sb,
 static void HgfsSetFileType(struct inode *inode,
                             HgfsAttrInfo const *attr);
 static int HgfsUnpackGetattrReply(HgfsReq *req,
-                                  HgfsAttrInfo *attr);
+                                  HgfsAttrInfo *attr,
+                                  char **fileName);
 static int HgfsPackGetattrRequest(HgfsReq *req,
                                   struct dentry *dentry,
                                   Bool allowHandleReuse,
@@ -227,7 +228,8 @@ HgfsSetFileType(struct inode *inode,          // IN/OUT: Inode to update
  */
 static int
 HgfsUnpackGetattrReply(HgfsReq *req,        // IN: Reply packet
-                       HgfsAttrInfo *attr)  // IN/OUT: Attributes
+                       HgfsAttrInfo *attr,  // IN/OUT: Attributes
+                       char **fileName)     // OUT: file name
 {
    int result;
    char *name = NULL;
@@ -267,19 +269,23 @@ HgfsUnpackGetattrReply(HgfsReq *req,        // IN: Reply packet
       }
    }
 
-   if (length != 0) {
+   if (fileName) {
+      if (length != 0) {
 
-      attr->fileName = kmalloc(length + 1, GFP_KERNEL);
-      if (attr->fileName == NULL) {
-         LOG(4, (KERN_DEBUG "VMware hgfs: HgfsUnpackGetattrReply: out of "
-                 "memory allocating symlink target name, ignoring\n"));
-         return -ENOMEM;
-      }
+         *fileName = kmalloc(length + 1, GFP_KERNEL);
+         if (*fileName == NULL) {
+            LOG(4, (KERN_DEBUG "VMware hgfs: HgfsUnpackGetattrReply: out of "
+                    "memory allocating symlink target name, ignoring\n"));
+            return -ENOMEM;
+         }
 
-      /* Copy and convert. From now on, the symlink target is in UTF8. */
-      memcpy(attr->fileName, name, length);
-      CPNameLite_ConvertFrom(attr->fileName, length, '/');
-      attr->fileName[length] = '\0';
+         /* Copy and convert. From now on, the symlink target is in UTF8. */
+         memcpy(*fileName, name, length);
+         CPNameLite_ConvertFrom(*fileName, length, '/');
+         (*fileName)[length] = '\0';
+      } else {
+         *fileName = NULL;
+      }
    }
 
    return 0;
@@ -790,8 +796,8 @@ HgfsChangeFileAttributes(struct inode *inode,          // IN/OUT: Inode
  *    for the indicated remote name, and if it succeeds copy the
  *    results of the getattr into the provided HgfsAttrInfo.
  *
- *    attr->fileName will be allocated on success if the file is a
- *    symlink; it's the caller's duty to free it.
+ *    fileName (if supplied) will be set to a newly allocated string
+ *    if the file is a symlink; it's the caller's duty to free it.
  *
  * Results:
  *    Returns zero on success, or a negative error on failure.
@@ -804,7 +810,8 @@ HgfsChangeFileAttributes(struct inode *inode,          // IN/OUT: Inode
 
 int
 HgfsPrivateGetattr(struct dentry *dentry,  // IN: Dentry containing name
-                   HgfsAttrInfo *attr)     // OUT: Attr to copy into
+                   HgfsAttrInfo *attr,     // OUT: Attr to copy into
+                   char **fileName)        // OUT: pointer to allocated file name
 {
    struct HgfsSuperInfo *si;
    HgfsReq *req;
@@ -850,7 +857,7 @@ HgfsPrivateGetattr(struct dentry *dentry,  // IN: Dentry containing name
        */
       switch (result) {
       case 0:
-         result = HgfsUnpackGetattrReply(req, attr);
+         result = HgfsUnpackGetattrReply(req, attr, fileName);
          break;
       case -EBADF:
          /*
@@ -1076,12 +1083,10 @@ HgfsInstantiate(struct dentry *dentry,    // IN: Dentry to use
       int error;
 
       LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInstantiate: issuing getattr\n"));
-      newAttr.fileName = NULL;
-      error = HgfsPrivateGetattr(dentry, &newAttr);
+      error = HgfsPrivateGetattr(dentry, &newAttr, NULL);
       if (error) {
          return error;
       }
-      kfree(newAttr.fileName);
       attr = &newAttr;
    }
 
index e90e8728604aebed39b80035ac79a12a8d23cc52..d1fd012b6fc9fd055bb94c1005a30b9ac895672d 100644 (file)
@@ -59,7 +59,6 @@ typedef struct HgfsAttrInfo {
    uint32 userId;                  /* UID */
    uint32 groupId;                 /* GID */
    uint64 hostFileId;              /* Inode number */
-   char *fileName;                 /* Either symlink target or filename */
 } HgfsAttrInfo;
 
 
@@ -69,7 +68,8 @@ int HgfsUnpackCommonAttr(HgfsReq *req,
 void HgfsChangeFileAttributes(struct inode *inode,
                               HgfsAttrInfo const *attr);
 int HgfsPrivateGetattr(struct dentry *dentry,
-                       HgfsAttrInfo *attr);
+                       HgfsAttrInfo *attr,
+                       char **fileName);
 struct inode *HgfsIget(struct super_block *sb,
                        ino_t ino,
                        HgfsAttrInfo const *attr);
index 4dd79fab7d14d9acbdd5d7d4ce4854ca42a7a556..fbf529aa0087a8cee8fafd4d0438d77a3fdff5c5 100644 (file)
@@ -1098,8 +1098,7 @@ HgfsLookup(struct inode *dir,      // IN: Inode of parent directory
 
    /* Do a getattr on the file to see if it exists on the server. */
    inode = NULL;
-   attr.fileName = NULL;
-   error = HgfsPrivateGetattr(dentry, &attr);
+   error = HgfsPrivateGetattr(dentry, &attr, NULL);
    if (!error) {
       /* File exists on the server. */
 
@@ -1108,7 +1107,6 @@ HgfsLookup(struct inode *dir,      // IN: Inode of parent directory
        * the server.
        */
       inode = HgfsIget(dir->i_sb, 0, &attr);
-      kfree(attr.fileName);
       if (!inode) {
          error = -ENOMEM;
          LOG(4, (KERN_DEBUG "VMware hgfs: HgfsLookup: out of memory getting "
@@ -1765,7 +1763,7 @@ HgfsAccessInt(struct dentry *dentry, // IN: dentry to check access for
    if (!dentry) {
       return 0;
    }
-   ret = HgfsPrivateGetattr(dentry, &attr);
+   ret = HgfsPrivateGetattr(dentry, &attr, NULL);
    if (ret == 0) {
       uint32 effectivePermissions;
 
@@ -2094,8 +2092,7 @@ HgfsRevalidate(struct dentry *dentry)  // IN: Dentry to revalidate
        * be current with our view of the file.
        */
       compat_filemap_write_and_wait(dentry->d_inode->i_mapping);
-      attr.fileName = NULL;
-      error = HgfsPrivateGetattr(dentry, &attr);
+      error = HgfsPrivateGetattr(dentry, &attr, NULL);
       if (!error) {
          /*
           * If server provides file ID, we need to check whether it has changed
@@ -2117,7 +2114,6 @@ HgfsRevalidate(struct dentry *dentry)  // IN: Dentry to revalidate
          /* Update inode's attributes and reset the age. */
          HgfsChangeFileAttributes(dentry->d_inode, &attr);
          HgfsDentryAgeReset(dentry);
-         kfree(attr.fileName);
       }
    } else {
       LOG(6, (KERN_DEBUG "VMware hgfs: HgfsRevalidate: using cached dentry "
index e684fb202e70fcec1e6238a5acdec296580b2042..9fb95a542d14ac765576a09e1b42bc9a1725cf5b 100644 (file)
@@ -87,6 +87,7 @@ HgfsFollowlink(struct dentry *dentry, // IN: Dentry containing link
 #endif
 {
    HgfsAttrInfo attr;
+   char *fileName = NULL;
    int error;
 
    ASSERT(dentry);
@@ -100,22 +101,20 @@ HgfsFollowlink(struct dentry *dentry, // IN: Dentry containing link
 
    LOG(6, (KERN_DEBUG "VMware hgfs: HgfsFollowlink: calling "
            "HgfsPrivateGetattr\n"));
-   attr.fileName = NULL;
-   error = HgfsPrivateGetattr(dentry, &attr);
+   error = HgfsPrivateGetattr(dentry, &attr, &fileName);
    if (!error) {
 
       /* Let's make sure we got called on a symlink. */
-      if (attr.type != HGFS_FILE_TYPE_SYMLINK ||
-          attr.fileName == NULL) {
+      if (attr.type != HGFS_FILE_TYPE_SYMLINK || fileName == NULL) {
          LOG(6, (KERN_DEBUG "VMware hgfs: HgfsFollowlink: got called "
                  "on something that wasn't a symlink\n"));
          error = -EINVAL;
       } else {
          LOG(6, (KERN_DEBUG "VMware hgfs: HgfsFollowlink: calling "
                  "vfs_follow_link\n"));
-         error = vfs_follow_link(nd, attr.fileName);
+         error = vfs_follow_link(nd, fileName);
       }
-      kfree(attr.fileName);
+      kfree(fileName);
    }
   out:
 
@@ -151,6 +150,7 @@ HgfsReadlink(struct dentry *dentry,  // IN:  Dentry containing link
 
 {
    HgfsAttrInfo attr;
+   char *fileName = NULL;
    int error;
 
    ASSERT(dentry);
@@ -163,22 +163,20 @@ HgfsReadlink(struct dentry *dentry,  // IN:  Dentry containing link
 
    LOG(6, (KERN_DEBUG "VMware hgfs: HgfsReadlink: calling "
            "HgfsPrivateGetattr\n"));
-   attr.fileName = NULL;
-   error = HgfsPrivateGetattr(dentry, &attr);
+   error = HgfsPrivateGetattr(dentry, &attr, &fileName);
    if (!error) {
 
       /* Let's make sure we got called on a symlink. */
-      if (attr.type != HGFS_FILE_TYPE_SYMLINK ||
-          attr.fileName == NULL) {
+      if (attr.type != HGFS_FILE_TYPE_SYMLINK || fileName == NULL) {
          LOG(6, (KERN_DEBUG "VMware hgfs: HgfsReadlink: got called "
                  "on something that wasn't a symlink\n"));
          error = -EINVAL;
       } else {
          LOG(6, (KERN_DEBUG "VMware hgfs: HgfsReadlink: calling "
                  "vfs_readlink\n"));
-         error = vfs_readlink(dentry, buffer, buflen, attr.fileName);
+         error = vfs_readlink(dentry, buffer, buflen, fileName);
       }
-      kfree(attr.fileName);
+      kfree(fileName);
    }
    return error;
 }
index aab6567772ffda0ff8a8c99c736f58a1ff4b4191..573cfc26f1164192fe92cd9e26b64605188c0547 100644 (file)
  *
  *********************************************************/
 
-/* 
+/*
  * os.c --
  *
- *     Wrappers for Linux system functions required by "vmmemctl".
- *     This allows customers to build their own vmmemctl driver for
- *     custom versioned kernels without the need for source code.
+ *      Wrappers for Linux system functions required by "vmmemctl".
  */
 
 /*
 
 #include "driver-config.h"
 
-#include "compat_module.h"
+#include <linux/module.h>
 #include <linux/types.h>
-#include "compat_kernel.h"
-#include "compat_completion.h"
-#include "compat_mm.h"
+#include <linux/kernel.h>
+#include <linux/mm.h>
 #include <linux/fs.h>
 #include <linux/timer.h>
-#include <linux/interrupt.h>
-#include "compat_sched.h"
-#include <asm/uaccess.h>
-#include "compat_page.h"
-#include "compat_wait.h"
-#include "vmmemctl_version.h"
+#include <linux/kthread.h>
 
 #ifdef CONFIG_PROC_FS
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
-/*
- * The get_info callback of proc_dir_entry was removed in 2.6.26.
- * We must therefore use the seq_file interface from that point on.
- */
-#define VMW_USE_SEQ_FILE
 #include <linux/seq_file.h>
-#endif
 #endif /* CONFIG_PROC_FS */
 
-#if    LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-#include <linux/smp_lock.h>
-#include "compat_kthread.h"
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 9)
-int errno;  /* compat_exit() needs global errno variable. */
-#endif
-
-/*
- * Compatibility definitions.
- */
+#include "compat_sched.h"
 
-/*
- * Execute as a separate kernel thread on 2.4.x kernels.
- * Allow allocations from high memory  on 2.4.x kernels.
- */
-#define        OS_KTHREAD      (1)
-COMPAT_KTHREAD_DECLARE_STOP_INFO();
-#endif
+#include <asm/uaccess.h>
+#include <asm/page.h>
 
+#include "vmmemctl_version.h"
 #include "os.h"
 
 
@@ -91,45 +62,28 @@ COMPAT_KTHREAD_DECLARE_STOP_INFO();
  * Constants
  */
 
-#ifdef OS_KTHREAD
 /*
  * Use __GFP_HIGHMEM to allow pages from HIGHMEM zone. We don't
- * allow wait (__GFP_WAIT) for NOSLEEP page allocations. Use 
- * __GFP_NOWARN, if available, to suppress page allocation failure
- * warnings.
+ * allow wait (__GFP_WAIT) for NOSLEEP page allocations. Use
+ * __GFP_NOWARN, to suppress page allocation failure warnings.
  */
-#ifdef __GFP_NOWARN
 #define OS_PAGE_ALLOC_NOSLEEP  (__GFP_HIGHMEM|__GFP_NOWARN)
-#else
-#define OS_PAGE_ALLOC_NOSLEEP  (__GFP_HIGHMEM)
-#endif
 
 /*
  * GFP_ATOMIC allocations dig deep for free pages. Maybe it is
- * okay because balloon driver uses os_kmalloc_*() to only allocate
- * few bytes, and the allocation requires a new page only occasionally. 
+ * okay because balloon driver uses OS_Malloc() to only allocate
+ * few bytes, and the allocation requires a new page only occasionally.
  * Still if __GFP_NOMEMALLOC flag is available, then use it to inform
- * the guest's page allocator not to use emergency pools,
+ * the guest's page allocator not to use emergency pools.
  */
-#ifdef __GFP_NOWARN
-
 #ifdef __GFP_NOMEMALLOC
 #define OS_KMALLOC_NOSLEEP     (GFP_ATOMIC|__GFP_NOMEMALLOC|__GFP_NOWARN)
 #else
 #define OS_KMALLOC_NOSLEEP     (GFP_ATOMIC|__GFP_NOWARN)
 #endif
 
-#else
-
-#ifdef __GFP_NOMEMALLOC
-#define OS_KMALLOC_NOSLEEP     (GFP_ATOMIC|__GFP_NOMEMALLOC)
-#else
-#define OS_KMALLOC_NOSLEEP     (GFP_ATOMIC)
-#endif
-
-#endif
 /*
- * Use GFP_HIGHUSER when executing in a separate kernel thread 
+ * Use GFP_HIGHUSER when executing in a separate kernel thread
  * context and allocation can sleep.  This is less stressful to
  * the guest memory system, since it allows the thread to block
  * while memory is reclaimed, and won't take pages from emergency
@@ -137,53 +91,24 @@ COMPAT_KTHREAD_DECLARE_STOP_INFO();
  */
 #define        OS_PAGE_ALLOC_CANSLEEP  (GFP_HIGHUSER)
 
-#else /* OS_KTHREAD not defined */
-
-/* 2.2.x kernel is a special case. The balloon driver is unable
- * to block (sleep) because it is not executing in a separate kernel 
- * thread. Therefore, the driver can only use NOSLEEP page 
- * allocations. 
- *
- * Use __GFP_LOW when available (2.2.x kernels) to avoid stressing
- * the guest memory system, otherwise simply use GFP_ATOMIC, which
- * is always defined (normally as __GFP_HIGH).
- */
-#ifdef __GFP_LOW
-#define        OS_PAGE_ALLOC_NOSLEEP   (__GFP_LOW)
-#define OS_KMALLOC_NOSLEEP     (GFP_ATOMIC)
-#else
-#define        OS_PAGE_ALLOC_NOSLEEP   (GFP_ATOMIC)
-#define OS_KMALLOC_NOSLEEP     (GFP_ATOMIC)
-#endif
-
-#endif
-
 /*
  * Types
  */
 
 typedef struct {
    /* registered state */
-   os_timer_handler handler;
+   OSTimerHandler *handler;
    void *data;
    int period;
 
    /* system structures */
-#ifdef OS_KTHREAD   
    wait_queue_head_t delay;
    struct task_struct *task;
-#else
-   /* termination flag */
-   atomic_t stop;
-
-   struct timer_list timer;
-   struct tq_struct task;
-#endif
 } os_timer;
 
 typedef struct {
    /* registered state */
-   os_status_handler handler;
+   OSStatusHandler *handler;
    const char *name_verbose;
    const char *name;
 } os_status;
@@ -199,9 +124,7 @@ typedef struct {
  */
 
 #ifdef CONFIG_PROC_FS
-#if    LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 static struct proc_dir_entry *global_proc_entry;
-#ifdef VMW_USE_SEQ_FILE
 static int os_proc_open(struct inode *, struct file *);
 static struct file_operations global_proc_fops = {
    .open = os_proc_open,
@@ -209,66 +132,146 @@ static struct file_operations global_proc_fops = {
    .llseek = seq_lseek,
    .release = single_release,
 };
-#else
-static int os_proc_read(char *, char **, off_t, int);
-#endif /* VMW_USE_SEQ_FILE */
-#else
-static int os_proc_read(char *, char **, off_t, int, int);
-static struct proc_dir_entry global_proc_entry = {
-   0, 8, "vmmemctl", S_IFREG | S_IRUGO, 1, 0, 0, 0, NULL, os_proc_read,
-};
-#endif
 #endif /* CONFIG_PROC_FS */
 
 static os_state global_state;
 
+
 /*
- * Simple Wrappers
+ *-----------------------------------------------------------------------------
+ *
+ * OS_Malloc --
+ *
+ *      Allocates kernel memory.
+ *
+ * Results:
+ *      On success: Pointer to allocated memory
+ *      On failure: NULL
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
  */
 
-void * CDECL
-os_kmalloc_nosleep(unsigned int size)
+void *
+OS_Malloc(size_t size) // IN
 {
    return(kmalloc(size, OS_KMALLOC_NOSLEEP));
 }
 
-void CDECL
-os_kfree(void *obj, unsigned int size)
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_Free --
+ *
+ *      Free allocated kernel memory.
+ *
+ * Results:
+ *      None
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+OS_Free(void *ptr,   // IN
+        size_t size) // IN
 {
-   kfree(obj);
+   kfree(ptr);
 }
 
-void CDECL
-os_bzero(void *s, unsigned int n)
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_MemZero --
+ *
+ *      Fill a memory location with 0s.
+ *
+ * Results:
+ *      None
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+OS_MemZero(void *ptr,   // OUT
+           size_t size) // IN
 {
-   memset(s, 0, n);
+   memset(ptr, 0, size);
 }
 
-void CDECL
-os_memcpy(void *dest, const void *src, unsigned int size)
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_MemCopy --
+ *
+ *      Copy a memory portion into another location.
+ *
+ * Results:
+ *      None
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+OS_MemCopy(void *dest,      // OUT
+           const void *src, // IN
+           size_t size)     // IN
 {
    memcpy(dest, src, size);
 }
 
-int CDECL
-os_sprintf(char *str, const char *format, ...)
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_Snprintf --
+ *
+ *      Print a string into a bounded memory location.
+ *
+ * Results:
+ *      Number of character printed including trailing \0.
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+OS_Snprintf(char *buf,          // OUT
+            size_t size,        // IN
+            const char *format, // IN
+            ...)                // IN
 {
    int result;
    va_list args;
 
    va_start(args, format);
-   result = vsprintf(str, format, args);
+   result = vsnprintf(buf, size, format, args);
    va_end(args);
 
-   return(result);
+   return result;
 }
 
 /*
  * System-Dependent Operations
  */
 
-char * CDECL
-os_identity(void)
+const char *
+OS_Identity(void)
 {
    return("linux");
 }
@@ -282,131 +285,65 @@ os_identity(void)
  * booted with a mem=XX parameter) the totalram-size is equal to alloc.max.
  *
  * Returns the maximum achievable balloon size in pages
- */  
-unsigned int CDECL
-os_predict_max_balloon_pages(void)
+ */
+unsigned int
+OS_PredictMaxReservedPages(void)
 {
    struct sysinfo info;
    os_state *state = &global_state;
 
-#if    LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-
-   /* 
-    * In 2.4.0 and later, si_meminfo() is cheap. Moreover, we want to provide
-    * dynamic max balloon size later. So let us call si_meminfo() every 
-    * iteration. 
+   /*
+    * si_meminfo() is cheap. Moreover, we want to provide dynamic
+    * max balloon size later. So let us call si_meminfo() every
+    * iteration.
     */
    si_meminfo(&info);
-   
-   /* In 2.4.x and later kernels, info.totalram is in pages */
-   state->totalMemoryPages = info.totalram;
-   return(state->totalMemoryPages);
-
-#else 
 
-   /* 2.2.x kernel */
-   if (!state->totalMemoryPages) {
-      si_meminfo(&info); /* In 2.2.x, si_meminfo() is a costly operation */
-      /* In 2.2.x kernels, info.totalram is in bytes */
-      state->totalMemoryPages = info.totalram >> PAGE_SHIFT;
-   }
-   return(state->totalMemoryPages);
-
-#endif
+   /* info.totalram is in pages */
+   state->totalMemoryPages = info.totalram;
+   return state->totalMemoryPages;
 }
 
 /*
  * Use newer alloc_page() interface on 2.4.x kernels.
  * Use "struct page *" value as page handle for clients.
  */
-unsigned long CDECL
-os_addr_to_ppn(unsigned long addr)
+unsigned long
+OS_AddrToPPN(unsigned long addr)
 {
    struct page *page = (struct page *) addr;
-   return(page_to_pfn(page));
+
+   return page_to_pfn(page);
 }
 
-unsigned long CDECL
-os_alloc_reserved_page(int can_sleep)
+unsigned long
+OS_AllocReservedPage(int canSleep)
 {
-   struct page *page;
-   /* allocate page */
-   if (can_sleep) {
-#ifdef OS_KTHREAD
-      page = alloc_page(OS_PAGE_ALLOC_CANSLEEP);
-#else
-      return 0;
-#endif
-   } else {
-      page = alloc_page(OS_PAGE_ALLOC_NOSLEEP);
-   }
-   return((unsigned long) page);
+   struct page *page = alloc_page(canSleep ?
+                           OS_PAGE_ALLOC_CANSLEEP : OS_PAGE_ALLOC_NOSLEEP);
+
+   return (unsigned long)page;
 }
 
-void CDECL
-os_free_reserved_page(unsigned long addr)
+void
+OS_FreeReservedPage(unsigned long addr)
 {
    /* deallocate page */
    struct page *page = (struct page *) addr;
    __free_page(page);
 }
 
-#ifndef        OS_KTHREAD
-static void os_timer_add(os_timer *t)
-{
-   /* schedule timer callback */
-   struct timer_list *timer = &t->timer;
-   timer->expires = jiffies + t->period;
-   add_timer(timer);
-}
-
-static void os_timer_remove(os_timer *t)
-{
-   /* deschedule timer callback */
-   struct timer_list *timer = &t->timer;
-   (void) del_timer(timer);
-}
-
-static void os_timer_bh(void *data)
-{
-   os_timer *t = (os_timer *) data;
-
-   if (!atomic_read(&t->stop)) {
-      /* execute registered handler, rearm timer */
-      (*(t->handler))(t->data);
-      os_timer_add(t);
-   }
-}
-
-static void os_timer_internal(ulong data)
-{
-   os_timer *t = (os_timer *) data;
-
-   /* perform real work in registered bottom-half handler */
-   queue_task(&t->task, &tq_immediate);
-   mark_bh(IMMEDIATE_BH);
-}
-#endif
-
-void CDECL
-os_timer_init(os_timer_handler handler, void *data, int period)
+void
+OS_TimerInit(OSTimerHandler *handler, // IN
+             void *clientData,        // IN
+             int period)              // IN
 {
    os_timer *t = &global_state.timer;
    t->handler = handler;
-   t->data = data;
+   t->data = clientData;
    t->period = period;
-#ifndef OS_KTHREAD
-   atomic_set(&t->stop, 0);
-   t->task.routine = os_timer_bh;
-   t->task.data = t;
-   /* initialize timer state */
-   init_timer(&t->timer);
-   t->timer.function = os_timer_internal;
-   t->timer.data = (ulong) t;
-#endif
 }
 
-#ifdef OS_KTHREAD
 static int os_timer_thread_loop(void *data)
 {
    os_timer *t = (os_timer *) data;
@@ -419,98 +356,77 @@ static int os_timer_thread_loop(void *data)
       /* sleep for specified period */
       wait_event_interruptible_timeout(t->delay,
                                        compat_wait_check_freezing() ||
-                                       compat_kthread_should_stop(),
+                                       kthread_should_stop(),
                                        t->period);
       compat_try_to_freeze();
-      if (compat_kthread_should_stop()) {
+      if (kthread_should_stop()) {
          break;
       }
 
       /* execute registered handler */
-      (*(t->handler))(t->data);
+      t->handler(t->data);
    }
 
    /* terminate */
    return(0);
 }
 
-static int os_timer_thread_start(os_timer *t)
+void
+OS_TimerStart(void)
 {
+   os_timer *t = &global_state.timer;
    os_status *s = &global_state.status;
 
    /* initialize sync objects */
    init_waitqueue_head(&t->delay);
 
    /* create kernel thread */
-   t->task = compat_kthread_run(os_timer_thread_loop, t, "vmmemctl");
+   t->task = kthread_run(os_timer_thread_loop, t, "vmmemctl");
    if (IS_ERR(t->task)) {
       /* fail */
       printk(KERN_WARNING "%s: unable to create kernel thread\n", s->name);
-      return(-1);
-   }
-
-   if (OS_DEBUG) {
+   } else if (OS_DEBUG) {
       printk(KERN_DEBUG "%s: started kernel thread pid=%d\n", s->name,
              t->task->pid);
    }
-
-   return(0);
 }
 
-static void os_timer_thread_stop(os_timer *t)
+void
+OS_TimerStop(void)
 {
-   compat_kthread_stop(t->task);
+   kthread_stop(global_state.timer.task);
 }
-#endif
 
-void CDECL
-os_timer_start(void)
+unsigned int
+OS_TimerHz(void)
 {
-   os_timer *t = &global_state.timer;
-
-#ifdef OS_KTHREAD
-   os_timer_thread_start(t);
-#else
-   /* clear termination flag */
-   atomic_set(&t->stop, 0);
-
-   os_timer_add(t);
-#endif
+   return HZ;
 }
 
-void CDECL
-os_timer_stop(void)
-{
-   os_timer *t = &global_state.timer;
 
-#ifdef OS_KTHREAD
-   os_timer_thread_stop(t);
-#else
-   /* set termination flag */
-   atomic_set(&t->stop, 1);
-
-   os_timer_remove(t);
-#endif
-}
-
-unsigned int CDECL
-os_timer_hz(void)
-{
-   return HZ;
-}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_Yield --
+ *
+ *      Yield the CPU, if needed.
+ *
+ * Results:
+ *      None
+ *
+ * Side effects:
+ *      This thread might get descheduled, other threads might get scheduled.
+ *
+ *-----------------------------------------------------------------------------
+ */
 
-void CDECL
-os_yield(void)
+void
+OS_Yield(void)
 {
-#ifdef OS_KTHREAD
    cond_resched();
-#else
-   /* Do nothing.  Timer callbacks should not sleep. */
-#endif
 }
 
 #ifdef CONFIG_PROC_FS
-#ifdef VMW_USE_SEQ_FILE
 static int os_proc_show(struct seq_file *f,
                        void *data)
 {
@@ -529,8 +445,8 @@ static int os_proc_show(struct seq_file *f,
       goto out;
    }
 
-   s->handler(buf);
-   
+   s->handler(buf, PAGE_SIZE);
+
    if (seq_puts(f, buf) != 0) {
       err = -ENOSPC;
       goto out;
@@ -550,37 +466,12 @@ static int os_proc_open(struct inode *inode,
    return single_open(file, os_proc_show, NULL);
 }
 
-#else
-#if    LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-static int os_proc_read(char *buf,
-                        char **start,
-                        off_t offset,
-                        int length)
-#else
-static int os_proc_read(char *buf,
-                        char **start,
-                        off_t offset,
-                        int length,
-                        int unused)
 #endif
-{
-   os_status *s = &global_state.status;
 
-   /* done if no handler */
-   if (s->handler == NULL) {
-      return(0);
-   }
-
-   /* invoke registered handler */
-   return(s->handler(buf));
-}
-#endif /* VMW_USE_SEQ_FILE */
-#endif
-
-void CDECL
-os_init(const char *name,
+void
+OS_Init(const char *name,
         const char *name_verbose,
-        os_status_handler handler)
+        OSStatusHandler *handler)
 {
    os_state *state = &global_state;
    static int initialized = 0;
@@ -592,11 +483,7 @@ os_init(const char *name,
 
    /* prevent module unload with extra reference */
    if (OS_DISABLE_UNLOAD) {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 48)
-      MOD_INC_USE_COUNT;
-#else
       try_module_get(THIS_MODULE);
-#endif
    }
 
    /* zero global state */
@@ -609,40 +496,24 @@ os_init(const char *name,
 
 #ifdef CONFIG_PROC_FS
    /* register procfs device */
-#if    LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
    global_proc_entry = create_proc_entry("vmmemctl", S_IFREG | S_IRUGO, NULL);
    if (global_proc_entry != NULL) {
-#ifdef VMW_USE_SEQ_FILE
       global_proc_entry->proc_fops = &global_proc_fops;
-#else
-      global_proc_entry->get_info = os_proc_read;
-#endif /* VMW_USE_SEQ_FILE */
    }
-#else
-   proc_register(&proc_root, &global_proc_entry);
-#endif
 #endif /* CONFIG_PROC_FS */
 
    /* log device load */
    printk(KERN_INFO "%s initialized\n", state->status.name_verbose);
 }
 
-void CDECL
-os_cleanup(void)
+void
+OS_Cleanup(void)
 {
    os_status *s = &global_state.status;
-   int err;
 
 #ifdef CONFIG_PROC_FS
    /* unregister procfs entry */
-#if    LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
    remove_proc_entry("vmmemctl", NULL);
-   err = 0;
-#else
-   if ((err = proc_unregister(&proc_root, global_proc_entry.low_ino)) != 0) {
-      printk(KERN_WARNING "%s: unable to unregister procfs entry (%d)\n", s->name, err);
-   }
-#endif
 #endif /* CONFIG_PROC_FS */
 
    /* log device unload */
index 8a5f690e6b32f51c1435815ae5691e3c060dde01..b991edd7162768ce2ea1ed068a3fae4b46fc7054 100644 (file)
  *
  *********************************************************/
 
-/* 
+/*
  * os.h --
  *
- *     Definitions for OS-specific wrapper functions required
- *     by "vmmemctl".  This allows customers to build their own
- *     vmmemctl driver for custom versioned kernels without the
- *     need for source code. 
+ *      Definitions for OS-specific wrapper functions required by "vmmemctl".
  */
 
 #ifndef        OS_H
 #define        OS_H
 
-/*
- * Needs fixing for 64bit OSes
- */
-#ifndef __x86_64__
-#define CDECL __attribute__((cdecl, regparm(0)))
-#else
-#define CDECL
-#endif
-
 /*
  * Types
  */
 
-typedef void CDECL (*os_timer_handler)(void *);
-typedef int  CDECL (*os_status_handler)(char *);
+typedef void OSTimerHandler(void *clientData);
+typedef int  OSStatusHandler(char *buf, size_t size);
 
 /*
  * Operations
  */
 
-extern void CDECL *os_kmalloc_nosleep(unsigned int size);
-extern void CDECL os_kfree(void *obj, unsigned int size);
-extern void CDECL os_yield(void);
-extern void CDECL os_bzero(void *s, unsigned int n);
-extern void CDECL os_memcpy(void *dest, const void *src, unsigned int size);
-extern int  CDECL os_sprintf(char *str, const char *format, ...);
-
-extern unsigned long CDECL os_addr_to_ppn(unsigned long addr);
-extern unsigned long CDECL os_alloc_reserved_page(int can_sleep);
-extern void          CDECL os_free_reserved_page(unsigned long page);
+extern void OS_Init(const char *name,
+                    const char *nameVerbose,
+                    OSStatusHandler *handler);
+extern void OS_Cleanup(void);
+extern const char *OS_Identity(void);
 
-extern void CDECL os_timer_init(os_timer_handler handler, void *data, int period);
-extern void CDECL os_timer_start(void);
-extern void CDECL os_timer_stop(void);
+extern void OS_MemZero(void *ptr, size_t size);
+extern void OS_MemCopy(void *dest, const void *src, size_t size);
+extern int  OS_Snprintf(char *buf, size_t size, const char *format, ...);
 
-extern void CDECL os_init(const char *name,
-                          const char *name_verbose,
-                          os_status_handler handler);
-extern void CDECL os_cleanup(void);
+extern void *OS_Malloc(size_t size);
+extern void OS_Free(void *ptr, size_t size);
 
-extern char CDECL *os_identity(void);
+extern void OS_Yield(void);
 
-extern unsigned int CDECL os_predict_max_balloon_pages(void);
+extern unsigned int OS_TimerHz(void);
+extern void OS_TimerInit(OSTimerHandler *handler, void *clientData, int period);
+extern void OS_TimerStart(void);
+extern void OS_TimerStop(void);
 
-extern unsigned int CDECL os_timer_hz(void);
+extern unsigned int  OS_PredictMaxReservedPages(void);
+extern unsigned long OS_AddrToPPN(unsigned long addr);
+extern unsigned long OS_AllocReservedPage(int canSleep);
+extern void          OS_FreeReservedPage(unsigned long page);
 
 #endif  /* OS_H */
index a88eea718b20884969db59c8d749287eb4798a3e..91212ec8fa036ccb365a6f85b8e463be8a9da713 100644 (file)
  *
  *********************************************************/
 
-/* 
+/*
  * vmballoon.c --
  *
- *     VMware server physical memory management driver for Unix-ish
- *     (Linux, FreeBSD, Solaris) guests.  The driver acts like a
- *     "balloon" that can be inflated to reclaim physical pages by
- *     reserving them in the guest and invalidating them in the
- *     monitor, freeing up the underlying machine pages so they can
- *     be allocated to other guests.  The balloon can also be
- *     deflated to allow the guest to use more physical memory.
- *     Higher level policies can control the sizes of balloons in VMs
- *     in order to manage physical memory resources.
+ *      VMware physical memory management driver for Unix-ish
+ *      (Linux, FreeBSD, Solaris, Mac OS) guests. The driver acts like
+ *      a "balloon" that can be inflated to reclaim physical pages by
+ *      reserving them in the guest and invalidating them in the
+ *      monitor, freeing up the underlying machine pages so they can
+ *      be allocated to other guests.  The balloon can also be
+ *      deflated to allow the guest to use more physical memory.
+ *      Higher level policies can control the sizes of balloons in VMs
+ *      in order to manage physical memory resources.
  */
 
 #ifdef __cplusplus
@@ -38,12 +38,12 @@ extern "C" {
  * Compile-Time Options
  */
 
-#define        BALLOON_RATE_ADAPT      (1)
+#define BALLOON_RATE_ADAPT      (1)
 
-#define        BALLOON_DEBUG           (1)
-#define        BALLOON_DEBUG_VERBOSE   (0)
+#define BALLOON_DEBUG           (1)
+#define BALLOON_DEBUG_VERBOSE   (0)
 
-#define        BALLOON_STATS
+#define BALLOON_STATS
 #define BALLOON_STATS_PROCFS
 
 /*
@@ -65,38 +65,38 @@ extern "C" {
 #define NULL 0
 #endif
 
-#define        BALLOON_NAME                    "vmmemctl"
-#define        BALLOON_NAME_VERBOSE            "VMware memory control driver"
+#define BALLOON_NAME                    "vmmemctl"
+#define BALLOON_NAME_VERBOSE            "VMware memory control driver"
 
-#define        BALLOON_PROTOCOL_VERSION        (2)
+#define BALLOON_PROTOCOL_VERSION        (2)
 
-#define        BALLOON_CHUNK_PAGES             (1000)
+#define BALLOON_CHUNK_PAGES             (1000)
 
-#define BALLOON_NOSLEEP_ALLOC_MAX      (16384)
+#define BALLOON_NOSLEEP_ALLOC_MAX       (16384)
 
-#define        BALLOON_RATE_ALLOC_MIN          (512)
-#define        BALLOON_RATE_ALLOC_MAX          (2048)
-#define        BALLOON_RATE_ALLOC_INC          (16)
+#define BALLOON_RATE_ALLOC_MIN          (512)
+#define BALLOON_RATE_ALLOC_MAX          (2048)
+#define BALLOON_RATE_ALLOC_INC          (16)
 
-#define        BALLOON_RATE_FREE_MIN           (512)
-#define        BALLOON_RATE_FREE_MAX           (16384)
-#define        BALLOON_RATE_FREE_INC           (16)
+#define BALLOON_RATE_FREE_MIN           (512)
+#define BALLOON_RATE_FREE_MAX           (16384)
+#define BALLOON_RATE_FREE_INC           (16)
 
-#define        BALLOON_ERROR_PAGES             (16)
+#define BALLOON_ERROR_PAGES             (16)
 
-/* 
+/*
  * When guest is under memory pressure, use a reduced page allocation
  * rate for next several cycles.
  */
-#define SLOW_PAGE_ALLOCATION_CYCLES    (4)
+#define SLOW_PAGE_ALLOCATION_CYCLES     (4)
 
-/* 
+/*
  * Move it to bora/public/balloon_def.h later, if needed. Note that
  * BALLOON_PAGE_ALLOC_FAILURE is an internal error code used for
  * distinguishing page allocation failures from monitor-backdoor errors.
  * We use value 1000 because all monitor-backdoor error codes are < 1000.
  */
-#define BALLOON_PAGE_ALLOC_FAILURE     (1000)
+#define BALLOON_PAGE_ALLOC_FAILURE      (1000)
 
 // Maximum number of page allocations without yielding processor
 #define BALLOON_ALLOC_YIELD_THRESHOLD   (1024)
@@ -156,7 +156,7 @@ static Balloon globalBalloon;
 static int BalloonGuestType(void);
 
 static unsigned long BalloonPrimAllocPage(BalloonPageAllocType canSleep);
-static void   BalloonPrimFreePage(unsigned long page);
+static void BalloonPrimFreePage(unsigned long page);
 
 static int  Balloon_AllocPage(Balloon *b, BalloonPageAllocType allocType);
 static int  Balloon_FreePage(Balloon *b, int monitorUnlock);
@@ -165,7 +165,7 @@ static void Balloon_Reset(Balloon *b);
 
 static void Balloon_StartTimer(Balloon *b);
 static void Balloon_StopTimer(Balloon *b);
-static void CDECL Balloon_BH(void *data);
+static void BalloonTimerHandler(void *clientData);
 
 static int Balloon_MonitorStart(Balloon *b);
 static int Balloon_MonitorGuestType(Balloon *b);
@@ -177,51 +177,43 @@ static int Balloon_MonitorUnlockPage(Balloon *b, unsigned long addr);
  * Macros
  */
 
-#ifndef        MIN
-#define        MIN(a, b)       (((a) < (b)) ? (a) : (b))
-#endif
-#ifndef        MAX
-#define        MAX(a, b)       (((a) > (b)) ? (a) : (b))
-#endif
-
-#ifdef BALLOON_STATS
-#define        STATS_INC(stat) (stat)++
+#ifdef  BALLOON_STATS
+#define STATS_INC(stat) (stat)++
 #else
-#define        STATS_INC(stat)
+#define STATS_INC(stat)
 #endif
 
 /*
  * Macros to generate operations for simple lists of OBJ.
  * OBJ must contain next and prev fields.
- * 
  */
 
-#define        GENERATE_LIST_INSERT(OBJ)                       \
-static void OBJ ## _Insert(OBJ **head, OBJ *obj)       \
-{                                                      \
-   OBJ *h = *head;                                     \
-                                                       \
-   /* add element to head of list */                   \
-   obj->next = h;                                      \
-   if (h != NULL) {                                    \
-      h->prev = obj;                                   \
-   }                                                   \
-   *head = obj;                                                \
-   obj->prev = NULL;                                   \
+#define GENERATE_LIST_INSERT(OBJ)                       \
+static void OBJ ## _Insert(OBJ **head, OBJ *obj)        \
+{                                                       \
+   OBJ *h = *head;                                      \
+                                                        \
+   /* add element to head of list */                    \
+   obj->next = h;                                       \
+   if (h != NULL) {                                     \
+      h->prev = obj;                                    \
+   }                                                    \
+   *head = obj;                                         \
+   obj->prev = NULL;                                    \
 }
 
-#define        GENERATE_LIST_REMOVE(OBJ)                       \
-static void OBJ ## _Remove(OBJ **head, OBJ *obj)       \
-{                                                      \
-    /* splice element out of list */                   \
-    if (obj->prev != NULL) {                           \
-      obj->prev->next = obj->next;                     \
-    } else {                                           \
-      *head = obj->next;                               \
-    }                                                  \
-    if (obj->next != NULL) {                           \
-      obj->next->prev = obj->prev;                     \
-    }                                                  \
+#define GENERATE_LIST_REMOVE(OBJ)                       \
+static void OBJ ## _Remove(OBJ **head, OBJ *obj)        \
+{                                                       \
+    /* splice element out of list */                    \
+    if (obj->prev != NULL) {                            \
+      obj->prev->next = obj->next;                      \
+    } else {                                            \
+      *head = obj->next;                                \
+    }                                                   \
+    if (obj->next != NULL) {                            \
+      obj->next->prev = obj->prev;                      \
+    }                                                   \
 }
 
 /*
@@ -235,25 +227,28 @@ GENERATE_LIST_REMOVE(BalloonChunk);
  * Procfs Operations
  */
 
+
 /*
  *----------------------------------------------------------------------
  *
  * BalloonProcRead --
  *
  *      Ballon driver status reporting routine.  Note that this is only
- *     used for Linux.
+ *      used for Linux.
  *
  * Results:
  *      Writes ASCII status information into "buf".
- *     Returns number of bytes written.
+ *      Returns number of bytes written.
  *
  * Side effects:
  *      None.
  *
  *----------------------------------------------------------------------
  */
-static int CDECL
-BalloonProcRead(char *buf)
+
+static int
+BalloonProcRead(char *buf,      // OUT
+                size_t size) // IN
 {
    int len = 0;
    BalloonStats stats;
@@ -261,14 +256,14 @@ BalloonProcRead(char *buf)
    BalloonGetStats(&stats);
 
    /* format size info */
-   len += os_sprintf(buf + len,
+   len += OS_Snprintf(buf + len, size - len,
                      "target:             %8d pages\n"
                      "current:            %8d pages\n",
                      stats.nPagesTarget,
                      stats.nPages);
 
    /* format rate info */
-   len += os_sprintf(buf + len,
+   len += OS_Snprintf(buf + len, size - len,
                      "rateNoSleepAlloc:   %8d pages/sec\n"
                      "rateSleepAlloc:     %8d pages/sec\n"
                      "rateFree:           %8d pages/sec\n",
@@ -276,8 +271,8 @@ BalloonProcRead(char *buf)
                      stats.rateAlloc,
                      stats.rateFree);
 
-#ifdef BALLOON_STATS_PROCFS
-   len += os_sprintf(buf + len,
+#ifdef BALLOON_STATS_PROCFS
+   len += OS_Snprintf(buf + len, size - len,
                      "\n"
                      "timer:              %8u\n"
                      "start:              %8u (%4u failed)\n"
@@ -305,7 +300,7 @@ BalloonProcRead(char *buf)
                      stats.primErrorPageFree);
 #endif
 
-   return(len);
+   return len;
 }
 
 /*
@@ -318,7 +313,7 @@ BalloonProcRead(char *buf)
  * AddrToPPN --
  *
  *      Return the physical page number corresponding to the specified
- *     Linux kernel-mapped address.
+ *      kernel-mapped address.
  *
  * Results:
  *      Returns PPN for "addr".
@@ -331,7 +326,7 @@ BalloonProcRead(char *buf)
 static inline unsigned long
 AddrToPPN(unsigned long addr)
 {
-   return(os_addr_to_ppn(addr));
+   return OS_AddrToPPN(addr);
 }
 
 /*
@@ -341,12 +336,12 @@ AddrToPPN(unsigned long addr)
  *
  *      Attempts to allocate and reserve a physical page.
  *
- *     If canSleep == 1, i.e., BALLOON_PAGE_ALLOC_CANSLEEP:
- *        The allocation can wait (sleep) for page writeout (swap)
- *        by the guest.
- *     otherwise canSleep == 0, i.e., BALLOON_PAGE_ALLOC_NOSLEEP:
- *        If allocation of a page requires disk writeout, then
- *        just fail. DON'T sleep.
+ *      If canSleep == 1, i.e., BALLOON_PAGE_ALLOC_CANSLEEP:
+ *         The allocation can wait (sleep) for page writeout (swap)
+ *         by the guest.
+ *      otherwise canSleep == 0, i.e., BALLOON_PAGE_ALLOC_NOSLEEP:
+ *         If allocation of a page requires disk writeout, then
+ *         just fail. DON'T sleep.
  *
  * Results:
  *      Returns the physical address of the allocated page, or 0 if error.
@@ -359,7 +354,7 @@ AddrToPPN(unsigned long addr)
 static unsigned long
 BalloonPrimAllocPage(BalloonPageAllocType canSleep)
 {
-   return(os_alloc_reserved_page(canSleep));
+   return OS_AllocReservedPage(canSleep);
 }
 
 /*
@@ -380,7 +375,7 @@ BalloonPrimAllocPage(BalloonPageAllocType canSleep)
 static void
 BalloonPrimFreePage(unsigned long page)
 {
-   return(os_free_reserved_page(page));
+   return OS_FreeReservedPage(page);
 }
 
 /*
@@ -389,7 +384,7 @@ BalloonPrimFreePage(unsigned long page)
  * BalloonGuestType --
  *
  *      Return balloon guest OS identifier obtained by parsing
- *     system-dependent identity string.
+ *      system-dependent identity string.
  *
  * Results:
  *      Returns one of BALLOON_GUEST_{LINUX,BSD,SOLARIS,UNKNOWN}.
@@ -402,11 +397,11 @@ BalloonPrimFreePage(unsigned long page)
 static int
 BalloonGuestType(void)
 {
-   char *identity;
+   const char *identity;
 
    /* obtain OS identify string */
-   identity = os_identity();
-   
+   identity = OS_Identity();
+
    /* unknown if not specified */
    if (identity == NULL) {
       return(BALLOON_GUEST_UNKNOWN);
@@ -416,19 +411,19 @@ BalloonGuestType(void)
    switch (identity[0]) {
    case 'l':
    case 'L':
-      return(BALLOON_GUEST_LINUX);
+      return BALLOON_GUEST_LINUX;
    case 'b':
    case 'B':
-      return(BALLOON_GUEST_BSD);
+      return BALLOON_GUEST_BSD;
    case 's':
    case 'S':
-      return(BALLOON_GUEST_SOLARIS);
+      return BALLOON_GUEST_SOLARIS;
    default:
       break;
    }
 
    /* unknown */
-   return(BALLOON_GUEST_UNKNOWN);
+   return BALLOON_GUEST_UNKNOWN;
 }
 
 /*
@@ -443,7 +438,7 @@ void BalloonGetStats(BalloonStats *stats)
    /*
     * Copy statistics out of global structure.
     */
-   os_memcpy(stats, &b->stats, sizeof (BalloonStats));
+   OS_MemCopy(stats, &b->stats, sizeof (BalloonStats));
 
    /*
     * Fill in additional information about size and rates, which is
@@ -465,37 +460,41 @@ void BalloonGetStats(BalloonStats *stats)
  * BalloonChunk_Create --
  *
  *      Creates a new BalloonChunk object capable of tracking
- *     BALLOON_CHUNK_PAGES PPNs.
+ *      BALLOON_CHUNK_PAGES PPNs.
  *
- *     We do not bother to define two versions (NOSLEEP and CANSLEEP)
- *     of os_kmalloc because Chunk_Create does not require a new page
- *     often.
+ *      We do not bother to define two versions (NOSLEEP and CANSLEEP)
+ *      of OS_Malloc because Chunk_Create does not require a new page
+ *      often.
  *
  * Results:
- *      Returns initialized BalloonChunk, or NULL if error.
+ *      On success: initialized BalloonChunk
+ *      On failure: NULL
  *
  * Side effects:
- *      None.
+ *      None
  *
  *----------------------------------------------------------------------
  */
+
 static BalloonChunk *
 BalloonChunk_Create(void)
 {
    BalloonChunk *chunk;
 
    /* allocate memory, fail if unable */
-   if ((chunk = (BalloonChunk *) os_kmalloc_nosleep(sizeof(BalloonChunk))) == NULL) {
-      return(NULL);
+   chunk = OS_Malloc(sizeof *chunk);
+   if (chunk == NULL) {
+      return NULL;
    }
 
    /* initialize */
-   os_bzero(chunk, sizeof(BalloonChunk));
+   OS_MemZero(chunk, sizeof *chunk);
 
    /* everything OK */
-   return(chunk);
+   return chunk;
 }
 
+
 /*
  *----------------------------------------------------------------------
  *
@@ -515,7 +514,7 @@ static void
 BalloonChunk_Destroy(BalloonChunk *chunk)
 {
    /* reclaim storage */
-   os_kfree(chunk, sizeof (BalloonChunk));
+   OS_Free(chunk, sizeof *chunk);
 }
 
 /*
@@ -542,7 +541,7 @@ static int
 Balloon_Init(Balloon *b)
 {
    /* clear state */
-   os_bzero(b, sizeof(Balloon));
+   OS_MemZero(b, sizeof *b);
 
    /* initialize rates */
    b->rateAlloc = BALLOON_RATE_ALLOC_MAX;
@@ -580,7 +579,7 @@ Balloon_Deallocate(Balloon *b)
       (void) Balloon_FreePage(b, FALSE);
       if (++cnt >= b->rateFree) {
          cnt = 0;
-         os_yield();
+         OS_Yield();
       }
    }
 }
@@ -591,7 +590,7 @@ Balloon_Deallocate(Balloon *b)
  * Balloon_Reset --
  *
  *      Resets balloon "b" to empty state.  Frees all allocated pages
- *     and attempts to reset contact with the monitor. 
+ *      and attempts to reset contact with the monitor.
  *
  * Results:
  *      None.
@@ -623,12 +622,12 @@ Balloon_Reset(Balloon *b)
 /*
  *----------------------------------------------------------------------
  *
- * Balloon_BH --
+ * BalloonTimerHandler --
  *
  *      Balloon bottom half handler.  Contacts monitor via backdoor
- *     to obtain balloon size target, and starts adjusting balloon
- *     size to achieve target by allocating or deallocating pages.
- *     Resets balloon if requested by the monitor.
+ *      to obtain balloon size target, and starts adjusting balloon
+ *      size to achieve target by allocating or deallocating pages.
+ *      Resets balloon if requested by the monitor.
  *
  * Results:
  *      None.
@@ -638,10 +637,10 @@ Balloon_Reset(Balloon *b)
  *
  *----------------------------------------------------------------------
  */
-static void CDECL
-Balloon_BH(void *data)
+static void
+BalloonTimerHandler(void *clientData)
 {
-   Balloon *b = (Balloon *) data;
+   Balloon *b = (Balloon *) clientData;
    uint32 target;
    int status;
 
@@ -679,14 +678,14 @@ Balloon_BH(void *data)
  *      None.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
 static void
 Balloon_StartTimer(Balloon *b)
 {
-   os_timer_start();
+   OS_TimerStart();
 }
 
 /*
@@ -700,14 +699,14 @@ Balloon_StartTimer(Balloon *b)
  *      None.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
 static void
 Balloon_StopTimer(Balloon *b)
 {
-   os_timer_stop();
+   OS_TimerStop();
 }
 
 
@@ -717,14 +716,14 @@ Balloon_StopTimer(Balloon *b)
  * Balloon_ErrorPagesAlloc --
  *
  *      Attempt to add "page" to list of non-balloonable pages
- *     associated with "b".
+ *      associated with "b".
  *
  * Results:
- *      Returns BALLOON_SUCCESS iff successful, or BALLOON_FAILURE
- *     if non-balloonable page list is already full.
+ *      On success: BALLOON_SUCCESS
+ *      On failure: BALLOON_FAILURE (non-balloonable page list is already full)
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -749,13 +748,13 @@ Balloon_ErrorPagesAlloc(Balloon *b, unsigned long page)
  * Balloon_ErrorPagesFree --
  *
  *      Deallocates all pages on the list of non-balloonable pages
- *     associated with "b".
+ *      associated with "b".
  *
  * Results:
- *     None.
+ *      None.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -766,7 +765,7 @@ Balloon_ErrorPagesFree(Balloon *b)
 
    /* free all non-balloonable "error" pages */
    for (i = 0; i < b->errors.nextPage; i++) {
-      BalloonPrimFreePage(b->errors.page[i]);      
+      BalloonPrimFreePage(b->errors.page[i]);
       b->errors.page[i] = 0;
       STATS_INC(b->stats.primErrorPageFree);
    }
@@ -779,13 +778,13 @@ Balloon_ErrorPagesFree(Balloon *b)
  * Balloon_AllocPage --
  *
  *      Attempts to allocate a physical page, inflating balloon "b".
- *     Informs monitor of PPN for allocated page via backdoor.
+ *      Informs monitor of PPN for allocated page via backdoor.
  *
  * Results:
  *      Returns BALLOON_SUCCESS if successful, otherwise error code.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -854,14 +853,14 @@ Balloon_AllocPage(Balloon *b, BalloonPageAllocType allocType)
  * Balloon_FreePage --
  *
  *      Attempts to deallocate a physical page, deflating balloon "b".
- *     Informs monitor of PPN for deallocated page via backdoor if
- *     "monitorUnlock" is specified.
+ *      Informs monitor of PPN for deallocated page via backdoor if
+ *      "monitorUnlock" is specified.
  *
  * Results:
  *      Returns BALLOON_SUCCESS if successful, otherwise error code.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -929,15 +928,15 @@ Balloon_FreePage(Balloon *b, int monitorUnlock)
  *
  * BalloonDecreaseRateAlloc --
  *
- *     Wrapper to quickly reduce the page allocation rate. This function
- *     is called only when a CANSLEEP allocation fails. This implies severe 
- *     memory pressure inside the guest, so quickly decrease the rateAlloc.
+ *      Wrapper to quickly reduce the page allocation rate. This function
+ *      is called only when a CANSLEEP allocation fails. This implies severe
+ *      memory pressure inside the guest, so quickly decrease the rateAlloc.
  *
  * Results:
  *      None.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -954,27 +953,27 @@ BalloonDecreaseRateAlloc(Balloon *b)
  *
  * BalloonIncreaseRateAlloc --
  *
- *     Wrapper to increase the page allocation rate. 
+ *      Wrapper to increase the page allocation rate.
  *
- *     This function is called when the balloon target is met or
- *     b->rateAlloc (or more) pages have been successfully allocated.
- *     This implies that the guest may not be under high memory 
- *     pressure. So let us increase the rateAlloc.
+ *      This function is called when the balloon target is met or
+ *      b->rateAlloc (or more) pages have been successfully allocated.
+ *      This implies that the guest may not be under high memory
+ *      pressure. So let us increase the rateAlloc.
  *
- *     If meeting balloon target requires less than b->rateAlloc
- *     pages, then we do not change the page allocation rate.
+ *      If meeting balloon target requires less than b->rateAlloc
+ *      pages, then we do not change the page allocation rate.
  *
- *     If the number of pages successfully allocated (nAlloc) is far
- *     higher than b->rateAlloc, then it implies that NOSLEEP 
- *     allocations are highly successful. Therefore, we predict that
- *     the guest is under no memory pressure, and so increase
- *     b->rateAlloc quickly.
+ *      If the number of pages successfully allocated (nAlloc) is far
+ *      higher than b->rateAlloc, then it implies that NOSLEEP
+ *      allocations are highly successful. Therefore, we predict that
+ *      the guest is under no memory pressure, and so increase
+ *      b->rateAlloc quickly.
  *
  * Results:
  *      None.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -983,7 +982,7 @@ BalloonIncreaseRateAlloc(Balloon *b, uint32 nAlloc)
 {
    if (BALLOON_RATE_ADAPT) {
       if (nAlloc >= b->rateAlloc) {
-         uint32 mult = nAlloc / b->rateAlloc; 
+         uint32 mult = nAlloc / b->rateAlloc;
          b->rateAlloc = MIN(b->rateAlloc + mult * BALLOON_RATE_ALLOC_INC,
                             BALLOON_RATE_ALLOC_MAX);
       }
@@ -1001,7 +1000,7 @@ BalloonIncreaseRateAlloc(Balloon *b, uint32 nAlloc)
  *      Returns BALLOON_SUCCESS if successful, otherwise error code.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -1011,7 +1010,7 @@ BalloonInflate(Balloon *b, uint32 target)
    int status, allocations = 0;
    uint32 i, nAllocNoSleep, nAllocCanSleep;
 
-   /* 
+   /*
     * First try NOSLEEP page allocations to inflate balloon.
     *
     * If we do not throttle nosleep allocations, we can drain all
@@ -1019,10 +1018,10 @@ BalloonInflate(Balloon *b, uint32 target)
     * As a side-effect, draining free pages helps to inform (force)
     * the guest to start swapping if balloon target is not met yet,
     * which is a desired behavior. However, balloon driver can consume
-    * all available CPU cycles if too many pages are allocated in a 
-    * second. Therefore, we throttle nosleep allocations even when 
-    * the guest is not under memory pressure. OTOH, if we have already 
-    * predicted that the guest is under memory pressure, then we 
+    * all available CPU cycles if too many pages are allocated in a
+    * second. Therefore, we throttle nosleep allocations even when
+    * the guest is not under memory pressure. OTOH, if we have already
+    * predicted that the guest is under memory pressure, then we
     * slowdown page allocations considerably.
     */
    if (b->slowPageAllocationCycles > 0) {
@@ -1036,16 +1035,16 @@ BalloonInflate(Balloon *b, uint32 target)
       status = Balloon_AllocPage(b, BALLOON_PAGE_ALLOC_NOSLEEP);
       if (status != BALLOON_SUCCESS) {
          if (status != BALLOON_PAGE_ALLOC_FAILURE) {
-            /* 
+            /*
              * Not a page allocation failure, so release non-balloonable
              * pages, and fail.
              */
             Balloon_ErrorPagesFree(b);
             return(status);
          }
-         /* 
-          * NOSLEEP page allocation failed, so the guest is under memory 
-          * pressure. Let us slowdown page allocations for next few 
+         /*
+          * NOSLEEP page allocation failed, so the guest is under memory
+          * pressure. Let us slowdown page allocations for next few
           * cycles so that the guest gets out of memory pressure.
           */
          b->slowPageAllocationCycles = SLOW_PAGE_ALLOCATION_CYCLES;
@@ -1053,12 +1052,12 @@ BalloonInflate(Balloon *b, uint32 target)
       }
 
       if (++allocations > BALLOON_ALLOC_YIELD_THRESHOLD) {
-         os_yield();
+         OS_Yield();
          allocations = 0;
       }
    }
 
-   /* 
+   /*
     * Check whether nosleep allocation successfully zapped nAllocNoSleep
     * pages.
     */
@@ -1068,7 +1067,7 @@ BalloonInflate(Balloon *b, uint32 target)
       Balloon_ErrorPagesFree(b);
       return(BALLOON_SUCCESS);
    } else {
-      /* 
+      /*
        * NOSLEEP allocation failed, so the guest is under memory pressure.
        * If already b->rateAlloc pages were zapped, then succeed. Otherwise,
        * try CANSLEEP allocation.
@@ -1084,14 +1083,14 @@ BalloonInflate(Balloon *b, uint32 target)
       }
    }
 
-   /* 
+   /*
     * Use CANSLEEP page allocation to inflate balloon if below target.
     *
     * Sleep allocations are required only when nosleep allocation fails.
     * This implies that the guest is already under memory pressure, so
     * let us always throttle canSleep allocations. The total number pages
-    * allocated using noSleep and canSleep methods is throttled at 
-    * b->rateAlloc per second when the guest is under memory pressure. 
+    * allocated using noSleep and canSleep methods is throttled at
+    * b->rateAlloc per second when the guest is under memory pressure.
     */
    nAllocCanSleep = target - b->nPages;
    nAllocCanSleep = MIN(nAllocCanSleep, b->rateAlloc - nAllocNoSleep);
@@ -1101,7 +1100,7 @@ BalloonInflate(Balloon *b, uint32 target)
       status = Balloon_AllocPage(b, BALLOON_PAGE_ALLOC_CANSLEEP);
       if(status != BALLOON_SUCCESS) {
          if (status == BALLOON_PAGE_ALLOC_FAILURE) {
-            /* 
+            /*
              * CANSLEEP page allocation failed, so guest is under severe
              * memory pressure. Quickly decrease rateAlloc.
              */
@@ -1113,17 +1112,17 @@ BalloonInflate(Balloon *b, uint32 target)
       }
 
       if (++allocations > BALLOON_ALLOC_YIELD_THRESHOLD) {
-         os_yield();
+         OS_Yield();
          allocations = 0;
       }
    }
 
-   /* 
+   /*
     * Either met the balloon target or b->rateAlloc pages have been
     * successfully zapped.
     */
    BalloonIncreaseRateAlloc(b, nAllocNoSleep + nAllocCanSleep);
-                            
+
    /* release non-balloonable pages, succeed */
    Balloon_ErrorPagesFree(b);
    return(BALLOON_SUCCESS);
@@ -1140,7 +1139,7 @@ BalloonInflate(Balloon *b, uint32 target)
  *      Returns BALLOON_SUCCESS if successful, otherwise error code.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -1149,7 +1148,7 @@ BalloonDeflate(Balloon *b, uint32 target)
 {
    int status, i;
    uint32 nFree = b->nPages - target;
-      
+
    /* limit deallocation rate */
    nFree = MIN(nFree, b->rateFree);
 
@@ -1173,20 +1172,20 @@ BalloonDeflate(Balloon *b, uint32 target)
    /* everything OK */
    return(BALLOON_SUCCESS);
 }
+
 /*
  *----------------------------------------------------------------------
  *
  * Balloon_AdjustSize --
  *
  *      Attempts to allocate or deallocate physical pages in order
- *     to reach desired "target" size for balloon "b".
+ *      to reach desired "target" size for balloon "b".
  *
  * Results:
  *      Returns BALLOON_SUCCESS if successful, otherwise error code.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -1224,10 +1223,10 @@ Balloon_AdjustSize(Balloon *b, uint32 target)
  *      Attempts to contact monitor via backdoor to begin operation.
  *
  * Results:
- *     Returns BALLOON_SUCCESS if successful, otherwise error code.
+ *      Returns BALLOON_SUCCESS if successful, otherwise error code.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -1266,10 +1265,10 @@ Balloon_MonitorStart(Balloon *b)
  *      Attempts to contact monitor and report guest OS identity.
  *
  * Results:
- *     Returns BALLOON_SUCCESS if successful, otherwise error code.
+ *      Returns BALLOON_SUCCESS if successful, otherwise error code.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -1311,24 +1310,24 @@ Balloon_MonitorGuestType(Balloon *b)
  * Balloon_MonitorGetTarget --
  *
  *      Attempts to contact monitor via backdoor to obtain desired
- *     balloon size.
+ *      balloon size.
  *
- *     Predicts the maximum achievable balloon size and sends it 
- *     to vmm => vmkernel via vEbx register.
+ *      Predicts the maximum achievable balloon size and sends it
+ *      to vmm => vmkernel via vEbx register.
  *
- *     os_predict_max_balloon_pages() returns either predicted max balloon
- *     pages or BALLOON_MAX_SIZE_USE_CONFIG. In the later scenario,
- *     vmkernel uses global config options for determining a guest's max
- *     balloon size. Note that older vmballoon drivers set vEbx to 
- *     BALLOON_MAX_SIZE_USE_CONFIG, i.e., value 0 (zero). So vmkernel
- *     will fallback to config-based max balloon size estimation.
+ *      OS_PredictMaxReservedPages() returns either predicted max balloon
+ *      pages or BALLOON_MAX_SIZE_USE_CONFIG. In the later scenario,
+ *      vmkernel uses global config options for determining a guest's max
+ *      balloon size. Note that older vmballoon drivers set vEbx to
+ *      BALLOON_MAX_SIZE_USE_CONFIG, i.e., value 0 (zero). So vmkernel
+ *      will fallback to config-based max balloon size estimation.
  *
  * Results:
- *     If successful, sets "target" to value obtained from monitor,
+ *      If successful, sets "target" to value obtained from monitor,
  *      and returns BALLOON_SUCCESS. Otherwise returns error code.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -1340,7 +1339,7 @@ Balloon_MonitorGetTarget(Balloon *b, uint32 *target)
 
    /* prepare backdoor args */
    bp.in.cx.halfs.low = BALLOON_BDOOR_CMD_TARGET;
-   bp.in.size = os_predict_max_balloon_pages();
+   bp.in.size = OS_PredictMaxReservedPages();
 
    /* invoke backdoor */
    Backdoor_Balloon(&bp);
@@ -1369,14 +1368,14 @@ Balloon_MonitorGetTarget(Balloon *b, uint32 *target)
  *
  * Balloon_MonitorLockPage --
  *
- *      Attempts to contact monitor and add PPN containing "addr" 
- *     to set of "balloon locked" pages.
+ *      Attempts to contact monitor and add PPN containing "addr"
+ *      to set of "balloon locked" pages.
  *
  * Results:
- *     Returns BALLOON_SUCCESS if successful, otherwise error code.
+ *      Returns BALLOON_SUCCESS if successful, otherwise error code.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -1428,14 +1427,14 @@ Balloon_MonitorLockPage(Balloon *b, unsigned long addr)
  *
  * Balloon_MonitorUnlockPage --
  *
- *      Attempts to contact monitor and remove PPN containing "addr" 
- *     from set of "balloon locked" pages.
+ *      Attempts to contact monitor and remove PPN containing "addr"
+ *      from set of "balloon locked" pages.
  *
  * Results:
- *     Returns BALLOON_SUCCESS if successful, otherwise error code.
+ *      Returns BALLOON_SUCCESS if successful, otherwise error code.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -1497,18 +1496,18 @@ BalloonModuleInit(void)
       return(BALLOON_FAILURE);
    }
 
+   /* os-specific initialization */
+   OS_Init(BALLOON_NAME, BALLOON_NAME_VERBOSE, BalloonProcRead);
+
    /* initialize global state */
    Balloon_Init(b);
 
-   /* os-specific initialization */
-   os_init(BALLOON_NAME, BALLOON_NAME_VERBOSE, BalloonProcRead);
-   os_timer_init(Balloon_BH, (void *) b, os_timer_hz());
-
    /* start timer */
+   OS_TimerInit(BalloonTimerHandler, b, OS_TimerHz());
    Balloon_StartTimer(b);
 
    /* everything OK */
-   return(BALLOON_SUCCESS);
+   return BALLOON_SUCCESS;
 }
 
 static void
@@ -1528,8 +1527,8 @@ BalloonModuleCleanup(void)
    Balloon_Deallocate(b);
 
    /* os-specific cleanup */
-   os_cleanup();
-}   
+   OS_Cleanup();
+}
 
 int init_module(void)
 {
index 57ef1627a3450e49bd5ca7c08799d4d58a935ec4..872a13c44cc69523586e64716676f7bb8f8a0e19 100644 (file)
 #include <linux/if_arp.h>
 #include <linux/inetdevice.h>
 
+#ifdef CONFIG_COMPAT
+#ifndef HAVE_UNLOCKED_IOCTL
+#include <linux/ioctl32.h>
+#endif
+#endif
+
 #include "vm_basic_types.h"
 #include "vmnet_def.h"
 #include "vm_device_version.h"
@@ -149,6 +155,7 @@ static unsigned int num_enable_shm;
 static int enable_shm[VMXNET3_SHM_MAX_DEVICES + 1] =
    { [0 ... VMXNET3_SHM_MAX_DEVICES] = -1 };
 static char *shm_disclaimer = NULL;
+static int correct_shm_disclaimer;
 #define VMXNET3_SHM_DISCLAIMER "IReallyWantThisModeIAmAVMSafePartner"
 
 /*
@@ -909,7 +916,7 @@ vmxnet3_parse_and_copy_hdr(struct sk_buff *skb,
       memcpy(tdd->data,
              virt,
              ctx->copy_size);
-      kunmap(virt);
+      kunmap(VMXNET3_SHM_IDX2PAGE(adapter->shm, VMXNET3_SHM_SKB_GETIDX(skb)));
    }
    VMXNET3_LOG("copy %u bytes to dataRing[%u]\n",
                ctx->copy_size, tq->tx_ring.next2fill);
@@ -1670,14 +1677,15 @@ vmxnet3_rx_csum(struct vmxnet3_adapter *adapter,
  *
  * vmxnet3_rx_error --
  *
- *    called when ERR bit is set for a received pkt
+ *    called when ERR bit is set for a received pkt. The desc and the associated 
+ *    rx buffer have not been processed yet.
  *
  * Result:
  *    none
  *
  * Side-effects:
  *    1. up the stat counters
- *    2. free the pkt
+ *    2. free the skb if needed
  *    3. reset ctx->skb
  *
  *----------------------------------------------------------------------------
@@ -1695,7 +1703,19 @@ vmxnet3_rx_error(struct vmxnet3_rx_queue *rq,
    }
    rq->stats.drop_total++;
 
-   vmxnet3_dev_kfree_skb_irq(adapter, ctx->skb);
+   /* 
+    * We do not unmap and chain the rx buffer to the skb.
+    * We basically pretend this buffer is not used and will be recycled
+    * by vmxnet3_rq_alloc_rx_buf()
+    */
+
+   /* 
+    * ctx->skb may be NULL if this is the first and the only one
+    * desc for the pkt
+    */
+   if (ctx->skb) {
+      vmxnet3_dev_kfree_skb_irq(adapter, ctx->skb);
+   }
    ctx->skb = NULL;
 }
 
@@ -1754,6 +1774,11 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
       VMXNET3_ASSERT(rcd->len <= rxd->len);
       VMXNET3_ASSERT(rxd->addr == rbi->dma_addr && rxd->len == rbi->len);
 
+      if (UNLIKELY(rcd->eop && rcd->err)) {
+         vmxnet3_rx_error(rq, rcd, ctx, adapter);
+         goto rcd_done;
+      }
+
       if (rcd->sop) { /* first buf of the pkt */
          VMXNET3_ASSERT(rxd->btype == VMXNET3_RXD_BTYPE_HEAD &&
                         rcd->rqID == rq->qid);
@@ -1793,28 +1818,16 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
                rbi->page = NULL;
             }
          } else {
-            /* the only time a non-SOP buffer is type 0 is when it's EOP and
-             * error flag is raised
+            /* 
+             * The only time a non-SOP buffer is type 0 is when it's EOP and
+             * error flag is raised, which has already been handled.
              */
-            if (UNLIKELY(rcd->err && rcd->eop)) {
-               /* pretend this buffer is skipped by the device.
-                * dont chain it and don't reset rbi->skb to NULL
-                */
-               VMXNET3_LOG("Err EOP is type 0 from ring[%u].rxd[%u]\n", ring_idx, idx);
-            } else {
-               /* bug in the device */
-               VMXNET3_ASSERT(FALSE);
-            }
+            VMXNET3_ASSERT(FALSE);
          }
       }
 
       skb = ctx->skb;
       if (rcd->eop) {
-         if (UNLIKELY(rcd->err)) {
-            vmxnet3_rx_error(rq, rcd, ctx, adapter);
-            goto rcd_done;
-         }
-
          if (adapter->is_shm) {
             vmxnet3_shm_rx_skb(adapter, skb);
 
@@ -2461,7 +2474,7 @@ vmxnet3_set_mc(struct net_device *netdev)
  *----------------------------------------------------------------------------
  */
 
-static int
+int
 vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
 {
    int err;
@@ -2566,7 +2579,7 @@ vmxnet3_reset_dev(struct vmxnet3_adapter *adapter)
  *----------------------------------------------------------------------------
  */
 
-static int
+int
 vmxnet3_quiesce_dev(struct vmxnet3_adapter *adapter)
 {
    if (test_and_set_bit(VMXNET3_STATE_BIT_QUIESCED, &adapter->state)) {
@@ -2683,8 +2696,8 @@ vmxnet3_alloc_pci_resources(struct vmxnet3_adapter *adapter, Bool *dma64)
    }
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 6)
-   if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) {
-      if (pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK) != 0) {
+   if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) == 0) {
+      if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) {
          printk(KERN_ERR "pci_set_consistent_dma_mask failed for adapter %s\n",
                 compat_pci_name(pdev));
          err = -EIO;
@@ -2692,7 +2705,7 @@ vmxnet3_alloc_pci_resources(struct vmxnet3_adapter *adapter, Bool *dma64)
       }
       *dma64 = TRUE;
    } else {
-      if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) {
+      if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) {
          printk(KERN_ERR "pci_set_dma_mask failed for adapter %s\n",
                 compat_pci_name(pdev));
          err = -EIO;
@@ -3060,7 +3073,7 @@ vmxnet3_close(struct net_device *netdev)
  *
  *----------------------------------------------------------------------------
  */
-static void
+void
 vmxnet3_force_close(struct vmxnet3_adapter *adapter)
 {
    /* 
@@ -4320,9 +4333,7 @@ vmxnet3_probe_device(struct pci_dev *pdev,
    adapter->is_shm = FALSE;
    if (adapter->dev_number < VMXNET3_SHM_MAX_DEVICES) {
       if (enable_shm[adapter->dev_number] == 1) {
-         if (shm_disclaimer == NULL ||
-             strncmp(shm_disclaimer, VMXNET3_SHM_DISCLAIMER,
-                     strlen(VMXNET3_SHM_DISCLAIMER)) != 0) {
+         if (!correct_shm_disclaimer) {
             printk(KERN_ERR "Did not activate shm, disclaimer missing\n");
          } else {
             adapter->is_shm = TRUE;
@@ -4629,6 +4640,21 @@ static int __init
 vmxnet3_init_module(void)
 {
    printk(KERN_INFO "%s - version %s\n", VMXNET3_DRIVER_DESC, VMXNET3_DRIVER_VERSION_REPORT);
+
+   correct_shm_disclaimer = shm_disclaimer &&
+      (strncmp(shm_disclaimer, VMXNET3_SHM_DISCLAIMER, strlen(VMXNET3_SHM_DISCLAIMER)) == 0);
+
+#ifdef CONFIG_COMPAT
+#ifndef HAVE_UNLOCKED_IOCTL
+   if (correct_shm_disclaimer) {
+      register_ioctl32_conversion(SHM_IOCTL_TX, NULL);
+      register_ioctl32_conversion(SHM_IOCTL_ALLOC_ONE, NULL);
+      register_ioctl32_conversion(SHM_IOCTL_ALLOC_MANY, NULL);
+      register_ioctl32_conversion(SHM_IOCTL_ALLOC_ONE_AND_MANY, NULL);
+      register_ioctl32_conversion(SHM_IOCTL_FREE_ONE, NULL);
+   }
+#endif
+#endif
    return pci_register_driver(&vmxnet3_driver);
 }
 
@@ -4652,6 +4678,17 @@ vmxnet3_init_module(void)
 static void
 vmxnet3_exit_module(void)
 {
+#ifdef CONFIG_COMPAT
+#ifndef HAVE_UNLOCKED_IOCTL
+   if (correct_shm_disclaimer) {
+      unregister_ioctl32_conversion(SHM_IOCTL_TX);
+      unregister_ioctl32_conversion(SHM_IOCTL_ALLOC_ONE);
+      unregister_ioctl32_conversion(SHM_IOCTL_ALLOC_MANY);
+      unregister_ioctl32_conversion(SHM_IOCTL_ALLOC_ONE_AND_MANY);
+      unregister_ioctl32_conversion(SHM_IOCTL_FREE_ONE);
+   }
+#endif
+#endif
    pci_unregister_driver(&vmxnet3_driver);
 }
 
index c0c544fde4bb4ff0eccf7f9e7dc6046017f677cc..11201e67fc580c9a6d1f06924340cf675ef174cb 100644 (file)
@@ -296,3 +296,11 @@ vmxnet3_tq_xmit(struct sk_buff *skb,
                 struct vmxnet3_adapter *adapter,
                 struct net_device *netdev);
 
+int
+vmxnet3_quiesce_dev(struct vmxnet3_adapter *adapter);
+
+int
+vmxnet3_activate_dev(struct vmxnet3_adapter *adapter);
+
+void
+vmxnet3_force_close(struct vmxnet3_adapter *adapter);
index eee0cf39262c59f718390b05cca3c3790a837390..67c2cc534478f1dc9dcb72c9cb5f7965cada11e7 100644 (file)
@@ -290,10 +290,16 @@ static int vmxnet3_shm_chardev_release(struct inode * inode,
 static unsigned int vmxnet3_shm_chardev_poll(struct file *filp,
                                              poll_table *wait);
 
-static int vmxnet3_shm_chardev_ioctl(struct inode *inode,
-                                     struct file *filp,
-                                     unsigned int cmd,
-                                     unsigned long arg);
+static long vmxnet3_shm_chardev_ioctl(struct file *filp,
+                                      unsigned int cmd,
+                                      unsigned long arg);
+
+#ifndef HAVE_UNLOCKED_IOCTL
+static int vmxnet3_shm_chardev_old_ioctl(struct inode *inode,
+                                         struct file *filp,
+                                         unsigned int cmd,
+                                         unsigned long arg);
+#endif
 
 static struct file_operations shm_fops = {
    .owner = THIS_MODULE,
@@ -301,7 +307,14 @@ static struct file_operations shm_fops = {
    .open = vmxnet3_shm_chardev_open,
    .release = vmxnet3_shm_chardev_release,
    .poll = vmxnet3_shm_chardev_poll,
-   .ioctl = vmxnet3_shm_chardev_ioctl,
+#ifdef HAVE_UNLOCKED_IOCTL
+   .unlocked_ioctl = vmxnet3_shm_chardev_ioctl,
+#ifdef CONFIG_COMPAT
+   .compat_ioctl = vmxnet3_shm_chardev_ioctl,
+#endif
+#else
+   .ioctl = vmxnet3_shm_chardev_old_ioctl,
+#endif
 };
 
 static LIST_HEAD(vmxnet3_shm_list);
@@ -322,6 +335,88 @@ static spinlock_t vmxnet3_shm_list_lock = SPIN_LOCK_UNLOCKED;
 #endif
 
 
+/*
+ *----------------------------------------------------------------------------
+ *
+ * vmxnet3_shm_init_allocator --
+ *
+ * Zero all shared memory data pages and fill the allocator with them.
+ *
+ * Result:
+ *    None
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+vmxnet3_shm_init_allocator(struct vmxnet3_shm_pool *shm)
+{
+   int i;
+
+   shm->allocator.count = 0;
+   for (i = 1; i < shm->data.num_pages; i++) {
+      struct page *page = VMXNET3_SHM_IDX2PAGE(shm, i);
+      void *virt = kmap(page);
+      memset(virt, 0, PAGE_SIZE);
+      kunmap(page);
+
+      shm->allocator.stack[shm->allocator.count++] = i;
+
+      VMXNET3_ASSERT(i != SHM_INVALID_IDX);
+   }
+   VMXNET3_ASSERT(shm->allocator.count <= SHM_DATA_SIZE);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * vmxnet3_shm_pool_reset --
+ *
+ *    Clean up after userspace has closed the device
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+vmxnet3_shm_pool_reset(struct vmxnet3_shm_pool *shm)
+{
+   int err = 0;
+   printk(KERN_INFO "resetting shm pool\n");
+
+   /*
+    * Reset_work may be in the middle of resetting the device, wait for its
+    * completion.
+    */
+   while (test_and_set_bit(VMXNET3_STATE_BIT_RESETTING, &shm->adapter->state)) {
+      compat_msleep(1);
+   }
+
+   if (compat_netif_running(shm->adapter->netdev)) {
+      vmxnet3_quiesce_dev(shm->adapter);
+   }
+
+   vmxnet3_shm_init_allocator(shm);
+
+   if (compat_netif_running(shm->adapter->netdev)) {
+      err = vmxnet3_activate_dev(shm->adapter);
+   }
+
+   memset(shm->ctl.ptr, 0, PAGE_SIZE);
+
+   clear_bit(VMXNET3_STATE_BIT_RESETTING, &shm->adapter->state);
+
+   if (err) {
+      vmxnet3_force_close(shm->adapter);
+   }
+}
+
 /*
  *-----------------------------------------------------------------------------
  *
@@ -367,29 +462,15 @@ vmxnet3_shm_pool_create(struct vmxnet3_adapter *adapter,
    // Allocate data pages
    shm->data.num_pages = SHM_DATA_SIZE;
    for (i = 1; i < shm->data.num_pages; i++) {
-#ifdef __GFP_ZERO
-      struct page *page = alloc_page(GFP_KERNEL|__GFP_ZERO);
-#else
       struct page *page = alloc_page(GFP_KERNEL);
-#endif
       if (page == NULL) {
          goto fail_data;
       }
 
-#ifndef __GFP_ZERO
-      {
-         void *virt = kmap(page);
-         memset(virt, 0, PAGE_SIZE);
-         kunmap(virt);
-      }
-#endif
-
       VMXNET3_SHM_SET_IDX2PAGE(shm, i, page);
-      shm->allocator.stack[shm->allocator.count++] = i;
 
       VMXNET3_ASSERT(i != SHM_INVALID_IDX);
    }
-   VMXNET3_ASSERT(shm->allocator.count <= SHM_DATA_SIZE);
 
    // Allocate control page
    ctl_page = alloc_page(GFP_KERNEL);
@@ -397,10 +478,13 @@ vmxnet3_shm_pool_create(struct vmxnet3_adapter *adapter,
       goto fail_ctl;
    }
    ctl_ptr = (void*)kmap(ctl_page);
-   memset(ctl_ptr, 0, PAGE_SIZE);
    shm->ctl.pages[0] = ctl_page;
    shm->ctl.ptr = ctl_ptr;
 
+   // Reset data and control pages
+   vmxnet3_shm_init_allocator(shm);
+   memset(shm->ctl.ptr, 0, PAGE_SIZE);
+
    // Register char device
    shm->misc_dev.minor = MISC_DYNAMIC_MINOR;
    shm->misc_dev.name = shm->name;
@@ -480,7 +564,6 @@ vmxnet3_shm_pool_release(struct kobject *kobj)
 
    // Free data pages
    for (i = 1; i < SHM_DATA_SIZE; i++) {
-      kunmap(VMXNET3_SHM_IDX2PAGE(shm,i));
       __free_page(VMXNET3_SHM_IDX2PAGE(shm, i));
    }
 
@@ -774,7 +857,13 @@ vmxnet3_shm_chardev_poll(struct file *filp,
    struct vmxnet3_shm_ringentry *re;
 
    // consume TX queue
-   vmxnet3_shm_consume_user_tx_queue(shm);
+   if (vmxnet3_shm_consume_user_tx_queue(shm) == -1) {
+      // the device has been closed, let the user space
+      // know there is activity, so that it gets a chance
+      // to read the channelBad flag.
+      mask |= POLLIN;
+      return mask;
+   }
 
    // Wait on the rxq for an interrupt to wake us
    poll_wait(filp, &shm->rxq, wait);
@@ -808,9 +897,8 @@ vmxnet3_shm_chardev_poll(struct file *filp,
  *-----------------------------------------------------------------------------
  */
 
-static int
-vmxnet3_shm_chardev_ioctl(struct inode *inode,
-                          struct file *filp,
+static long
+vmxnet3_shm_chardev_ioctl(struct file *filp,
                           unsigned int cmd,
                           unsigned long arg)
 {
@@ -827,11 +915,7 @@ vmxnet3_shm_chardev_ioctl(struct inode *inode,
 
       case SHM_IOCTL_ALLOC_ONE:
          idx = vmxnet3_shm_alloc_page(shm);
-         if (idx != SHM_INVALID_IDX) {
-            return idx;
-         } else {
-            return -ENOMEM;
-         }
+         return idx;
 
       case SHM_IOCTL_ALLOC_MANY:
          for (i = 0; i < arg; i++) {
@@ -839,10 +923,10 @@ vmxnet3_shm_chardev_ioctl(struct inode *inode,
             if (idx != SHM_INVALID_IDX) {
                if (vmxnet3_shm_user_rx(shm, idx, 0, 1, 1)) {
                   vmxnet3_shm_free_page(shm, idx);
-                  return -ENOMEM;
+                  return SHM_INVALID_IDX;
                }
             } else {
-               return -ENOMEM;
+               return SHM_INVALID_IDX;
             }
          }
          return 0;
@@ -850,7 +934,7 @@ vmxnet3_shm_chardev_ioctl(struct inode *inode,
       case SHM_IOCTL_ALLOC_ONE_AND_MANY:
          idx1 = vmxnet3_shm_alloc_page(shm);
          if (idx1 == SHM_INVALID_IDX) {
-            return -ENOMEM;
+            return SHM_INVALID_IDX;
          }
          for (i = 0; i < arg - 1; i++) {
             idx = vmxnet3_shm_alloc_page(shm);
@@ -858,11 +942,11 @@ vmxnet3_shm_chardev_ioctl(struct inode *inode,
                if (vmxnet3_shm_user_rx(shm, idx, 0, 1, 1)) {
                   vmxnet3_shm_free_page(shm, idx);
                   vmxnet3_shm_free_page(shm, idx1);
-                  return -ENOMEM;
+                  return SHM_INVALID_IDX;
                }
             } else {
                vmxnet3_shm_free_page(shm, idx1);
-               return -ENOMEM;
+               return SHM_INVALID_IDX;
             }
          }
          return idx1;
@@ -877,6 +961,15 @@ vmxnet3_shm_chardev_ioctl(struct inode *inode,
    return -ENOTTY;
 }
 
+#ifndef HAVE_UNLOCKED_IOCTL
+static int vmxnet3_shm_chardev_old_ioctl(struct inode *inode,
+                                         struct file *filp,
+                                         unsigned int cmd,
+                                         unsigned long arg)
+{
+   return vmxnet3_shm_chardev_ioctl(filp, cmd, arg);
+}
+#endif
 
 /*
  *-----------------------------------------------------------------------------
@@ -974,9 +1067,15 @@ vmxnet3_shm_chardev_release(struct inode * inode,
                             struct file * filp)
 {
    struct vmxnet3_shm_pool *shm = filp->private_data;
-   kobject_put(&shm->kobj);
 
-   // XXX: I guess we should reset the control pages here
+   if (shm->adapter) {
+      vmxnet3_shm_pool_reset(shm);
+   } else {
+      vmxnet3_shm_init_allocator(shm);
+      memset(shm->ctl.ptr, 0, PAGE_SIZE);
+   }
+   
+   kobject_put(&shm->kobj);
 
    return 0;
 }
@@ -1070,6 +1169,9 @@ vmxnet3_shm_tx_pkt(struct vmxnet3_adapter *adapter,
 
    skb = dev_alloc_skb(100);
    if (skb == NULL) {
+      for (i = 0; i < frags; i++) {
+         vmxnet3_shm_free_page(adapter->shm, res[i].idx);
+      }
       VMXNET3_ASSERT(FALSE);
       return -ENOMEM;
    }
@@ -1131,8 +1233,6 @@ static int
 vmxnet3_shm_tx_re(struct vmxnet3_shm_pool *shm,
                   struct vmxnet3_shm_ringentry re)
 {
-   int i;
-
    shm->partial_tx.res[shm->partial_tx.frags++] = re;
 
    if (re.eop) {
@@ -1140,9 +1240,7 @@ vmxnet3_shm_tx_re(struct vmxnet3_shm_pool *shm,
                                      shm->partial_tx.res,
                                      shm->partial_tx.frags);
       if (status < 0) {
-         for (i = 0; i < shm->partial_tx.frags; i++) {
-            vmxnet3_shm_free_page(shm, shm->partial_tx.res[i].idx);
-         }
+         VMXNET3_LOG("vmxnet3_shm_tx_pkt failed %d\n", status);
       }
       shm->partial_tx.frags = 0;
       return 1;
@@ -1414,6 +1512,12 @@ vmxnet3_shm_close(struct vmxnet3_adapter *adapter)
    adapter->shm->adapter = NULL;
    spin_unlock_irqrestore(&adapter->shm->tx_lock, flags);
 
+   // Mark the channel as 'in bad state' 
+   adapter->shm->ctl.ptr->channelBad = 1;
+   
    kobject_put(&adapter->shm->kobj);
+   
+   wake_up(&adapter->shm->rxq);
+
    return 0;
 }
index e3eca683d8e771938fdb345e16a7640290fea5fc..a838d51e7883a41db6f219a3dc1d9b2dad86403b 100644 (file)
@@ -52,8 +52,8 @@
 #define SHM_CTL_SIZE 1
 
 // ring size (in entries) is limited by the single control page - 4 bytes per re
-#define SHM_RX_RING_SIZE 507
-#define SHM_TX_RING_SIZE 507
+#define SHM_RX_RING_SIZE 500
+#define SHM_TX_RING_SIZE 500
 
 // maximum fragments per packet is 16 (64k) + 2 for metadata
 #define VMXNET3_SHM_MAX_FRAGS 18
@@ -86,6 +86,8 @@ struct vmxnet3_shm_ctl
       uint64_t user_rx, user_tx;
       uint64_t kernel_rx, kernel_tx;
    } stats;
+
+   uint64_t channelBad;
 };
 
 #endif
index f3c0891c92249500e8d6b418c5fef3a299635c8c..03b9dff64021e365c72d5ae9a8f5cac8029f5e3e 100644 (file)
 #ifndef _VMXNET3_VERSION_H_
 #define _VMXNET3_VERSION_H_
 
-#define VMXNET3_DRIVER_VERSION          1.0.1.0
-#define VMXNET3_DRIVER_VERSION_COMMAS   1,0,1,0
-#define VMXNET3_DRIVER_VERSION_STRING   "1.0.1.0"
+#define VMXNET3_DRIVER_VERSION          1.0.3.0
+#define VMXNET3_DRIVER_VERSION_COMMAS   1,0,3,0
+#define VMXNET3_DRIVER_VERSION_STRING   "1.0.3.0"
 
 /* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */
-#define VMXNET3_DRIVER_VERSION_NUM      0x01000100
+#define VMXNET3_DRIVER_VERSION_NUM      0x01000300
 
 #endif /* _VMXNET3_VERSION_H_ */
index d152b5db065b4cb6ca17ceebda13c8b1d9518972..c2b2febb429d1a35533c3da2c154ad73d47687a0 100644 (file)
 #include <linux/poll.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/bitops.h>
 #include <asm/io.h>
 #if defined(__x86_64__) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12)
-#   if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
-#      include <asm/ioctl32.h>
-#   else
-#      include <linux/ioctl32.h>
-#   endif
+#   include <linux/ioctl32.h>
 /* Use weak: not all kernels export sys_ioctl for use by modules */
-#   if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 66)
 asmlinkage __attribute__((weak)) long
 sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
-#   else
-asmlinkage __attribute__((weak)) int
-sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
-#   endif
 #endif
 
 #include "compat_module.h"
@@ -146,6 +138,9 @@ sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
 #include "vsock_version.h"
 #include "driverLog.h"
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9)
+#  error "Linux kernels before 2.6.9 are not supported."
+#endif
 
 #define VSOCK_INVALID_FAMILY        NPROTO
 #define VSOCK_AF_IS_REGISTERED(val) ((val) >= 0 && (val) < NPROTO)
@@ -162,6 +157,9 @@ sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
 int VSockVmci_GetAFValue(void);
 
 /* Internal functions. */
+static Bool VSockVmciProtoToNotifyStruct(struct sock *sk,
+                                         VSockProtoVersion *proto,
+                                         Bool oldPktProto);
 static int VSockVmciGetAFValue(void);
 static int VSockVmciRecvDgramCB(void *data, VMCIDatagram *dg);
 static int VSockVmciRecvStreamCB(void *data, VMCIDatagram *dg);
@@ -176,6 +174,8 @@ static int VSockVmciRecvConnectingServer(struct sock *sk,
 static int VSockVmciRecvConnectingClient(struct sock *sk, VSockPacket *pkt);
 static int VSockVmciRecvConnectingClientNegotiate(struct sock *sk,
                                                   VSockPacket *pkt);
+static int VSockVmciRecvConnectingClientInvalid(struct sock *sk,
+                                                VSockPacket *pkt);
 static int VSockVmciRecvConnected(struct sock *sk, VSockPacket *pkt);
 static int __VSockVmciBind(struct sock *sk, struct sockaddr_vm *addr);
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
@@ -216,38 +216,6 @@ static int VSockVmciStreamSetsockopt(struct socket *sock, int level, int optname
 static int VSockVmciStreamGetsockopt(struct socket *sock, int level, int optname,
                                      char __user *optval, int __user * optlen);
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 43)
-static int VSockVmciDgramSendmsg(struct socket *sock, struct msghdr *msg,
-                                 int len, struct scm_cookie *scm);
-static int VSockVmciDgramRecvmsg(struct socket *sock, struct msghdr *msg,
-                                 int len, int flags, struct scm_cookie *scm);
-static int VSockVmciStreamSendmsg(struct socket *sock, struct msghdr *msg,
-                                  int len, struct scm_cookie *scm);
-static int VSockVmciStreamRecvmsg(struct socket *sock, struct msghdr *msg,
-                                  int len, int flags, struct scm_cookie *scm);
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 65)
-static int VSockVmciDgramSendmsg(struct kiocb *kiocb, struct socket *sock,
-                                 struct msghdr *msg, int len,
-                                 struct scm_cookie *scm);
-static int VSockVmciDgramRecvmsg(struct kiocb *kiocb, struct socket *sock,
-                                 struct msghdr *msg, int len,
-                                 int flags, struct scm_cookie *scm);
-static int VSockVmciStreamSendmsg(struct kiocb *kiocb, struct socket *sock,
-                                  struct msghdr *msg, int len,
-                                  struct scm_cookie *scm);
-static int VSockVmciStreamRecvmsg(struct kiocb *kiocb, struct socket *sock,
-                                  struct msghdr *msg, int len,
-                                  int flags, struct scm_cookie *scm);
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 2)
-static int VSockVmciDgramSendmsg(struct kiocb *kiocb,
-                                 struct socket *sock, struct msghdr *msg, int len);
-static int VSockVmciDgramRecvmsg(struct kiocb *kiocb, struct socket *sock,
-                                 struct msghdr *msg, int len, int flags);
-static int VSockVmciStreamSendmsg(struct kiocb *kiocb,
-                                  struct socket *sock, struct msghdr *msg, int len);
-static int VSockVmciStreamRecvmsg(struct kiocb *kiocb, struct socket *sock,
-                                  struct msghdr *msg, int len, int flags);
-#else
 static int VSockVmciDgramSendmsg(struct kiocb *kiocb,
                                  struct socket *sock, struct msghdr *msg, size_t len);
 static int VSockVmciDgramRecvmsg(struct kiocb *kiocb, struct socket *sock,
@@ -256,7 +224,6 @@ static int VSockVmciStreamSendmsg(struct kiocb *kiocb,
                                  struct socket *sock, struct msghdr *msg, size_t len);
 static int VSockVmciStreamRecvmsg(struct kiocb *kiocb, struct socket *sock,
                                  struct msghdr *msg, size_t len, int flags);
-#endif
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
 static int VSockVmciCreate(struct socket *sock, int protocol);
@@ -280,8 +247,7 @@ static long VSockVmciDevUnlockedIoctl(struct file *filp,
  * Variables.
  */
 
-/* Protocol family.  We only use this for builds against 2.6.9 and later. */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9)
+/* Protocol family. */
 static struct proto vsockVmciProto = {
    .name     = "AF_VMCI",
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
@@ -289,38 +255,31 @@ static struct proto vsockVmciProto = {
    .owner    = THIS_MODULE,
 #endif
    /*
-    * Before 2.6.9, each address family created their own slab (by calling
-    * kmem_cache_create() directly).  From 2.6.9 until 2.6.11, these address
-    * families instead called sk_alloc_slab() and the allocated slab was
-    * assigned to the slab variable in the proto struct and was created of size
-    * slab_obj_size.  As of 2.6.12 and later, this slab allocation was moved
-    * into proto_register() and only done if you specified a non-zero value for
+    * From 2.6.9 until 2.6.11, these address families called sk_alloc_slab()
+    * and the allocated slab was assigned to the slab variable in the proto
+    * struct and was created of size slab_obj_size.
+    * As of 2.6.12 and later, this slab allocation was moved into
+    * proto_register() and only done if you specified a non-zero value for
     * the second argument (alloc_slab); the size of the slab element was
     * changed to obj_size.
     */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9)
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12)
    .slab_obj_size = sizeof (VSockVmciSock),
 #else
    .obj_size = sizeof (VSockVmciSock),
 #endif
 };
-#endif
 
 static struct net_proto_family vsockVmciFamilyOps = {
    .family = VSOCK_INVALID_FAMILY,
    .create = VSockVmciCreate,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 69)
    .owner  = THIS_MODULE,
-#endif
 };
 
 /* Socket operations, split for DGRAM and STREAM sockets. */
 static struct proto_ops vsockVmciDgramOps = {
    .family     = VSOCK_INVALID_FAMILY,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 69)
    .owner      = THIS_MODULE,
-#endif
    .release    = VSockVmciRelease,
    .bind       = VSockVmciBind,
    .connect    = VSockVmciDgramConnect,
@@ -336,16 +295,12 @@ static struct proto_ops vsockVmciDgramOps = {
    .sendmsg    = VSockVmciDgramSendmsg,
    .recvmsg    = VSockVmciDgramRecvmsg,
    .mmap       = sock_no_mmap,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 4)
    .sendpage   = sock_no_sendpage,
-#endif
 };
 
 static struct proto_ops vsockVmciStreamOps = {
    .family     = VSOCK_INVALID_FAMILY,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 69)
    .owner      = THIS_MODULE,
-#endif
    .release    = VSockVmciRelease,
    .bind       = VSockVmciBind,
    .connect    = VSockVmciStreamConnect,
@@ -361,9 +316,7 @@ static struct proto_ops vsockVmciStreamOps = {
    .sendmsg    = VSockVmciStreamSendmsg,
    .recvmsg    = VSockVmciStreamRecvmsg,
    .mmap       = sock_no_mmap,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 4)
    .sendpage   = sock_no_sendpage,
-#endif
 };
 
 static struct file_operations vsockVmciDeviceOps = {
@@ -401,11 +354,7 @@ static Bool vmciDevicePresent = FALSE;
 static VMCIHandle vmciStreamHandle = { VMCI_INVALID_ID, VMCI_INVALID_ID };
 static VMCIId qpResumedSubId = VMCI_INVALID_ID;
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9)
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 5)
-kmem_cache_t *vsockCachep;
-#endif
-#endif
+static int protocolOverride = -1;
 
 /*
  * 64k is hopefully a reasonable default, but we should do some real
@@ -422,6 +371,125 @@ kmem_cache_t *vsockCachep;
 #endif
 
 
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciOldProtoOverride --
+ *
+ *      Check to see if the user has asked us to override all sockets to use
+ *      the vsock notify protocol.
+ *
+ * Results:
+ *      TRUE if there is a protocol override in effect.
+ *       - oldPktProto is TRUE the original protocol should be used.
+ *      FALSE if there is no override in effect.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+VSockVmciOldProtoOverride(Bool *oldPktProto)        // IN
+{
+   ASSERT(oldPktProto);
+
+   if (protocolOverride != -1) {
+      if (protocolOverride == 0) {
+         *oldPktProto = TRUE;
+      } else {
+         *oldPktProto = FALSE;
+      }
+      Warning("Proto override in use.\n");
+      return TRUE;
+   }
+
+   return FALSE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciProtoToNotifyStruct --
+ *
+ *      Given a particular notify protocol version, setup the socket's notify
+ *      struct correctly.
+ *
+ * Results:
+ *      TRUE on success. FALSE otherwise.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+VSockVmciProtoToNotifyStruct(struct sock *sk,          // IN
+                             VSockProtoVersion *proto, // IN
+                             Bool oldPktProto)         // IN
+{
+   VSockVmciSock *vsk;
+
+   ASSERT(sk);
+   ASSERT(proto);
+
+   vsk = vsock_sk(sk);
+
+   if (oldPktProto) {
+      if (*proto != VSOCK_PROTO_INVALID) {
+         Warning("Can't set both an old and new protocol\n");
+         return FALSE;
+      }
+      vsk->notifyOps = &vSockVmciNotifyPktOps;
+      goto exit;
+   }
+
+   switch(*proto) {
+   case VSOCK_PROTO_PKT_ON_NOTIFY:
+      vsk->notifyOps= &vSockVmciNotifyPktQStateOps;
+      break;
+   default:
+      Warning("Unknown notify protocol version\n");
+      return FALSE;
+   }
+
+exit:
+   NOTIFYCALL(vsk, socketInit, sk);
+   return TRUE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNewProtoSupportedVersions
+ *
+ *      Gets the supported REQUEST2/NEGOTIATE2 vsock protocol versions.
+ *
+ * Results:
+ *      Either 1 specific protocol version (override mode) or
+ *      VSOCK_PROTO_ALL_SUPPORTED.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static VSockProtoVersion
+VSockVmciNewProtoSupportedVersions(void) // IN
+{
+   if (protocolOverride != -1) {
+      return protocolOverride;
+   }
+
+   return VSOCK_PROTO_ALL_SUPPORTED;
+}
+
+
 /*
  *----------------------------------------------------------------------------
  *
@@ -929,11 +997,9 @@ VSockVmciRecvStreamCB(void *data,           // IN
     * when implementing backwards compatibility in the future.
     */
    if (pkt->type >= VSOCK_PACKET_TYPE_MAX) {
-      if (VSOCK_SEND_INVALID_BH(&dst, &src) < 0) {
-         Warning("unable to send reply for invalid packet.\n");
-         err = VMCI_ERROR_INVALID_ARGS;
-         goto out;
-      }
+      VSOCK_SEND_INVALID_BH(&dst, &src);
+      err = VMCI_ERROR_INVALID_ARGS;
+      goto out;
    }
 
    /*
@@ -1097,9 +1163,7 @@ VSockVmciHandleDetach(struct sock *sk) // IN
        * receive, but we can still receive if there is data left in our consume
        * queue.
        */
-      sk->compat_sk_shutdown |= SEND_SHUTDOWN;
       if (VSockVmciStreamHasData(vsk) <= 0) {
-         sk->compat_sk_shutdown |= RCV_SHUTDOWN;
          sk->compat_sk_state = SS_UNCONNECTED;
       }
       sk->compat_sk_state_change(sk);
@@ -1390,6 +1454,8 @@ VSockVmciRecvListen(struct sock *sk,   // IN
    VSockVmciSock *vpending;
    int err;
    uint64 qpSize;
+   Bool oldRequest = FALSE;
+   Bool oldPktProto = FALSE;
 
    ASSERT(sk);
    ASSERT(pkt);
@@ -1431,10 +1497,16 @@ VSockVmciRecvListen(struct sock *sk,   // IN
     * The listen state only accepts connection requests.  Reply with a reset
     * unless we received a reset.
     */
-   if (pkt->type != VSOCK_PACKET_TYPE_REQUEST ||
-       pkt->u.size == 0) {
-      VSOCK_REPLY_RESET(pkt);
-      return -EINVAL;
+
+   if (!(pkt->type == VSOCK_PACKET_TYPE_REQUEST ||
+         pkt->type == VSOCK_PACKET_TYPE_REQUEST2)) {
+       VSOCK_REPLY_RESET(pkt);
+       return -EINVAL;
+   }
+
+   if (pkt->u.size == 0) {
+       VSOCK_REPLY_RESET(pkt);
+       return -EINVAL;
    }
 
    /*
@@ -1474,13 +1546,61 @@ VSockVmciRecvListen(struct sock *sk,   // IN
     * it. Otherwise propose our own size.
     */
    if (pkt->u.size >= vsk->queuePairMinSize &&
-      pkt->u.size <= vsk->queuePairMaxSize) {
+       pkt->u.size <= vsk->queuePairMaxSize) {
       qpSize = pkt->u.size;
    } else {
       qpSize = vsk->queuePairSize;
    }
 
-   err = VSOCK_SEND_NEGOTIATE(pending, qpSize);
+   /*
+    * Figure out if we are using old or new requests based on the overrides
+    * pkt types sent by our peer.
+    */
+   if (VSockVmciOldProtoOverride(&oldPktProto)) {
+      oldRequest = oldPktProto;
+   } else {
+      if (pkt->type == VSOCK_PACKET_TYPE_REQUEST) {
+         oldRequest = TRUE;
+      } else if (pkt->type == VSOCK_PACKET_TYPE_REQUEST2) {
+         oldRequest = FALSE;
+      }
+   }
+
+   if (oldRequest) {
+      /* Handle a REQUEST (or override) */
+      VSockProtoVersion version = VSOCK_PROTO_INVALID;
+      if (VSockVmciProtoToNotifyStruct(pending, &version, TRUE)) {
+         err = VSOCK_SEND_NEGOTIATE(pending, qpSize);
+      } else {
+         err = -EINVAL;
+      }
+   } else {
+      /* Handle a REQUEST2 (or override) */
+      int protoInt = pkt->proto;
+      int pos;
+      uint16 activeProtoVersion = 0;
+
+      /*
+       * The list of possible protocols is the intersection of all protocols
+       * the client supports ... plus all the protocols we support.
+       */
+      protoInt &= VSockVmciNewProtoSupportedVersions();
+
+      /* We choose the highest possible protocol version and use that one. */
+      pos = fls(protoInt);
+      if (pos) {
+         activeProtoVersion = (1 << (pos - 1));
+         if (VSockVmciProtoToNotifyStruct(pending, &activeProtoVersion, FALSE)) {
+            err = VSOCK_SEND_NEGOTIATE2(pending, qpSize,
+                                        activeProtoVersion);
+         } else {
+            err = -EINVAL;
+         }
+      } else {
+         err = -EINVAL;
+      }
+   }
+
    if (err < 0) {
       VSOCK_SEND_RESET(sk, pkt);
       sock_put(pending);
@@ -1494,8 +1614,7 @@ VSockVmciRecvListen(struct sock *sk,   // IN
    pending->compat_sk_state = SS_CONNECTING;
    vpending->produceSize = vpending->consumeSize = qpSize;
 
-   /* XXX Move this into the notify file. */
-   vpending->notify.writeNotifyWindow = qpSize;
+   NOTIFYCALL(vpending, processRequest, pending);
 
    /*
     * We might never receive another message for this socket and it's not
@@ -1738,8 +1857,10 @@ VSockVmciRecvConnectingClient(struct sock *sk,       // IN: socket
       sk->compat_sk_socket->state = SS_CONNECTED;
       VSockVmciInsertConnected(vsockConnectedSocketsVsk(vsk), sk);
       sk->compat_sk_state_change(sk);
+
       break;
    case VSOCK_PACKET_TYPE_NEGOTIATE:
+   case VSOCK_PACKET_TYPE_NEGOTIATE2:
       if (pkt->u.size == 0 ||
           VMCI_HANDLE_TO_CONTEXT_ID(pkt->dg.src) != vsk->remoteAddr.svm_cid ||
           pkt->srcPort != vsk->remoteAddr.svm_port ||
@@ -1761,11 +1882,34 @@ VSockVmciRecvConnectingClient(struct sock *sk,       // IN: socket
          goto destroy;
       }
 
+      break;
+   case VSOCK_PACKET_TYPE_INVALID:
+      err = VSockVmciRecvConnectingClientInvalid(sk, pkt);
+      if (err) {
+         skerr = -err;
+         goto destroy;
+      }
+
       break;
    case VSOCK_PACKET_TYPE_RST:
-      skerr = ECONNRESET;
-      err = 0;
-      goto destroy;
+      /*
+       * Older versions of the linux code (WS 6.5 / ESX 4.0) used to continue
+       * processing here after they sent an INVALID packet. This meant that we
+       * got a RST after the INVALID. We ignore a RST after an INVALID. The
+       * common code doesn't send the RST ... so we can hang if an old version
+       * of the common code fails between getting a REQUEST and sending an
+       * OFFER back. Not much we can do about it... except hope that it
+       * doesn't happen.
+       */
+      if (vsk->ignoreConnectingRst) {
+         vsk->ignoreConnectingRst = FALSE;
+      } else {
+         skerr = ECONNRESET;
+         err = 0;
+         goto destroy;
+      }
+
+      break;
    default:
       /* Close and cleanup the connection. */
       skerr = EPROTO;
@@ -1774,7 +1918,10 @@ VSockVmciRecvConnectingClient(struct sock *sk,       // IN: socket
    }
 
    ASSERT(pkt->type == VSOCK_PACKET_TYPE_ATTACH ||
-          pkt->type == VSOCK_PACKET_TYPE_NEGOTIATE);
+          pkt->type == VSOCK_PACKET_TYPE_NEGOTIATE ||
+          pkt->type == VSOCK_PACKET_TYPE_NEGOTIATE2 ||
+          pkt->type == VSOCK_PACKET_TYPE_INVALID ||
+          pkt->type == VSOCK_PACKET_TYPE_RST);
 
    return 0;
 
@@ -1819,6 +1966,10 @@ VSockVmciRecvConnectingClientNegotiate(struct sock *sk,   // IN: socket
    VMCIId attachSubId;
    VMCIId detachSubId;
    Bool isLocal;
+   uint32 flags;
+   Bool oldProto = TRUE;
+   Bool oldPktProto;
+   VSockProtoVersion version;
 
    vsk = vsock_sk(sk);
    handle = VMCI_INVALID_HANDLE;
@@ -1838,6 +1989,13 @@ VSockVmciRecvConnectingClientNegotiate(struct sock *sk,   // IN: socket
    ASSERT(vsk->attachSubId == VMCI_INVALID_ID);
    ASSERT(vsk->detachSubId == VMCI_INVALID_ID);
 
+   /*
+    * If we have gotten here then we should be past the point where old linux
+    * vsock could have sent the bogus rst.
+    */
+   vsk->sentRequest = FALSE;
+   vsk->ignoreConnectingRst = FALSE;
+
    /* Verify that we're OK with the proposed queue pair size */
    if (pkt->u.size < vsk->queuePairMinSize ||
        pkt->u.size > vsk->queuePairMaxSize) {
@@ -1845,6 +2003,32 @@ VSockVmciRecvConnectingClientNegotiate(struct sock *sk,   // IN: socket
       goto destroy;
    }
 
+   /*
+    * Setup the notify ops to be the highest supported version that both the
+    * server and the client support.
+    */
+
+   if (VSockVmciOldProtoOverride(&oldPktProto)) {
+      oldProto = oldPktProto;
+   } else {
+      if (pkt->type == VSOCK_PACKET_TYPE_NEGOTIATE) {
+         oldProto = TRUE;
+      } else if (pkt->type == VSOCK_PACKET_TYPE_NEGOTIATE2) {
+         oldProto = FALSE;
+      }
+   }
+
+   if (oldProto) {
+      version = VSOCK_PROTO_INVALID;
+   } else {
+      version = pkt->proto;
+   }
+
+   if (!VSockVmciProtoToNotifyStruct(sk, &version, oldProto)) {
+      err = -EINVAL;
+      goto destroy;
+   }
+
    /*
     * Subscribe to attach and detach events first.
     *
@@ -1873,12 +2057,13 @@ VSockVmciRecvConnectingClientNegotiate(struct sock *sk,   // IN: socket
    /* Make VMCI select the handle for us. */
    handle = VMCI_INVALID_HANDLE;
    isLocal = vsk->remoteAddr.svm_cid == vsk->localAddr.svm_cid;
+   flags = isLocal ? VMCI_QPFLAG_LOCAL : 0;
 
    err = VSockVmciQueuePairAlloc(&handle,
                                  &produceQ, pkt->u.size,
                                  &consumeQ, pkt->u.size,
                                  vsk->remoteAddr.svm_cid,
-                                 isLocal ? VMCI_QPFLAG_LOCAL : 0,
+                                 flags,
                                  vsk->trusted);
    if (err < 0) {
       goto destroy;
@@ -1898,12 +2083,11 @@ VSockVmciRecvConnectingClientNegotiate(struct sock *sk,   // IN: socket
 
    vsk->produceSize = vsk->consumeSize = pkt->u.size;
 
-   /* XXX Move this into the notify file. */
-   vsk->notify.writeNotifyWindow = pkt->u.size;
-
    vsk->attachSubId = attachSubId;
    vsk->detachSubId = detachSubId;
 
+   NOTIFYCALL(vsk, processNegotiate, sk);
+
    return 0;
 
 destroy:
@@ -1926,6 +2110,52 @@ destroy:
 }
 
 
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciRecvConnectingClientInvalid --
+ *
+ *    Handles an invalid packet for a client in the connecting state.
+ *
+ *    Note that this assumes the socket lock is held for both sk and pending.
+ *
+ * Results:
+ *    Zero on success, negative error code on failure.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+VSockVmciRecvConnectingClientInvalid(struct sock *sk,   // IN: socket
+                                     VSockPacket *pkt)  // IN: current packet
+{
+   int err = 0;
+   VSockVmciSock *vsk;
+
+   ASSERT(sk);
+   ASSERT(pkt);
+
+   vsk = vsock_sk(sk);
+
+   if (vsk->sentRequest) {
+      vsk->sentRequest = FALSE;
+      vsk->ignoreConnectingRst = TRUE;
+
+      err = VSOCK_SEND_CONN_REQUEST(sk, vsk->queuePairSize);
+      if (err < 0) {
+         err = VSockVmci_ErrorToVSockError(err);
+      } else {
+         err = 0;
+      }
+   }
+
+   return err;
+}
+
+
 /*
  *----------------------------------------------------------------------------
  *
@@ -1977,7 +2207,7 @@ VSockVmciRecvConnected(struct sock *sk,      // IN
    switch (pkt->type) {
    case VSOCK_PACKET_TYPE_SHUTDOWN:
       if (pkt->u.mode) {
-         VSockVmciSock *vsk = vsock_sk(sk);
+         vsk = vsock_sk(sk);
 
          vsk->peerShutdown |= pkt->u.mode;
          sk->compat_sk_state_change(sk);
@@ -1998,10 +2228,8 @@ VSockVmciRecvConnected(struct sock *sk,      // IN
        */
       compat_sock_set_done(sk);
       vsk->peerShutdown = SHUTDOWN_MASK;
-      sk->compat_sk_shutdown |= SEND_SHUTDOWN;
       if (VSockVmciStreamHasData(vsk) <= 0) {
         sk->compat_sk_state = SS_DISCONNECTING;
-        sk->compat_sk_shutdown = SHUTDOWN_MASK;
       }
       sk->compat_sk_state_change(sk);
       break;
@@ -2046,6 +2274,7 @@ __VSockVmciSendControlPkt(VSockPacket *pkt,           // IN
                           uint64 size,                // IN
                           uint64 mode,                // IN
                           VSockWaitingInfo *wait,     // IN
+                          VSockProtoVersion proto,    // IN
                           VMCIHandle handle,          // IN
                           Bool convertError)          // IN
 {
@@ -2060,7 +2289,7 @@ __VSockVmciSendControlPkt(VSockPacket *pkt,           // IN
    VSOCK_ADDR_NOFAMILY_ASSERT(src);
    VSOCK_ADDR_NOFAMILY_ASSERT(dst);
 
-   VSockPacket_Init(pkt, src, dst, type, size, mode, wait, handle);
+   VSockPacket_Init(pkt, src, dst, type, size, mode, wait, proto, handle);
    LOG_PACKET(pkt);
    VSOCK_STATS_CTLPKT_LOG(pkt->type);
    err = VMCIDatagram_Send(&pkt->dg);
@@ -2107,7 +2336,8 @@ VSockVmciReplyControlPktFast(VSockPacket *pkt,       // IN
    } else {
       VSockPacket_GetAddresses(pkt, &src, &dst);
       return __VSockVmciSendControlPkt(&reply, &src, &dst, type,
-                                       size, mode, wait, handle, TRUE);
+                                       size, mode, wait,
+                                       VSOCK_PROTO_INVALID, handle, TRUE);
    }
 }
 
@@ -2149,7 +2379,8 @@ VSockVmciSendControlPktBH(struct sockaddr_vm *src,      // IN
    static VSockPacket pkt;
 
    return __VSockVmciSendControlPkt(&pkt, src, dst, type,
-                                    size, mode, wait, handle, FALSE);
+                                    size, mode, wait, VSOCK_PROTO_INVALID,
+                                    handle, FALSE);
 }
 
 
@@ -2170,12 +2401,13 @@ VSockVmciSendControlPktBH(struct sockaddr_vm *src,      // IN
  */
 
 int
-VSockVmciSendControlPkt(struct sock *sk,        // IN
-                        VSockPacketType type,   // IN
-                        uint64 size,            // IN
-                        uint64 mode,            // IN
-                        VSockWaitingInfo *wait, // IN
-                        VMCIHandle handle)      // IN
+VSockVmciSendControlPkt(struct sock *sk,         // IN
+                        VSockPacketType type,    // IN
+                        uint64 size,             // IN
+                        uint64 mode,             // IN
+                        VSockWaitingInfo *wait,  // IN
+                        VSockProtoVersion proto, // IN
+                        VMCIHandle handle)       // IN
 {
    VSockPacket *pkt;
    VSockVmciSock *vsk;
@@ -2206,7 +2438,8 @@ VSockVmciSendControlPkt(struct sock *sk,        // IN
    }
 
    err = __VSockVmciSendControlPkt(pkt, &vsk->localAddr, &vsk->remoteAddr,
-                                   type, size, mode, wait, handle, TRUE);
+                                   type, size, mode, wait, proto, handle,
+                                   TRUE);
    kfree(pkt);
 
    return err;
@@ -2339,7 +2572,11 @@ __VSockVmciBind(struct sock *sk,          // IN/OUT
       goto out;
    }
 
-   VSockAddr_Init(&vsk->localAddr, newAddr.svm_cid, newAddr.svm_port);
+   /*
+    * VSockVmci_GetAFValue() acquires a mutex and may sleep, so fill the
+    * field after unlocking socket tables.
+    */
+   VSockAddr_InitNoFamily(&vsk->localAddr, newAddr.svm_cid, newAddr.svm_port);
 
    /*
     * Remove stream sockets from the unbound list and add them to the hash
@@ -2349,9 +2586,12 @@ __VSockVmciBind(struct sock *sk,          // IN/OUT
    if (sk->compat_sk_socket->type == SOCK_STREAM) {
       __VSockVmciRemoveBound(sk);
       __VSockVmciInsertBound(vsockBoundSockets(&vsk->localAddr), sk);
+      spin_unlock_bh(&vsockTableLock);
    }
+   vsk->localAddr.svm_family = VSockVmci_GetAFValue();
+   VSOCK_ADDR_ASSERT(&vsk->localAddr);
 
-   err = 0;
+   return 0;
 
 out:
    if (sk->compat_sk_socket->type == SOCK_STREAM) {
@@ -2412,25 +2652,14 @@ __VSockVmciCreate(struct net *net,       // IN: Network namespace
    vsk = NULL;
 
    /*
-    * Before 2.5.5, sk_alloc() always used its own cache and protocol-specific
-    * data was contained in the protinfo union.  We cannot use those other
-    * structures so we allocate our own structure and attach it to the
-    * user_data pointer that we don't otherwise need.  We must be sure to free
-    * it later in our destruct routine.
-    *
-    * From 2.5.5 until 2.6.8, sk_alloc() offerred to use a cache that the
-    * caller provided.  After this, the cache was moved into the proto
-    * structure, but you still had to specify the size and cache yourself until
-    * 2.6.12. Most recently (in 2.6.24), sk_alloc() was changed to expect the
+    * From 2.6.9 to until 2.6.12 sk_alloc() used a cache in
+    * the protocol structure, but you still had to specify the size and cache
+    * yourself.
+    * Most recently (in 2.6.24), sk_alloc() was changed to expect the
     * network namespace, and the option to zero the sock was dropped.
     *
     */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 5)
-   sk = sk_alloc(vsockVmciFamilyOps.family, priority, 1);
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9)
-   sk = sk_alloc(vsockVmciFamilyOps.family, priority,
-                 sizeof (VSockVmciSock), vsockCachep);
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12)
    sk = sk_alloc(vsockVmciFamilyOps.family, priority,
                  vsockVmciProto.slab_obj_size, vsockVmciProto.slab);
 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
@@ -2442,15 +2671,6 @@ __VSockVmciCreate(struct net *net,       // IN: Network namespace
       return NULL;
    }
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 5)
-   vsock_sk(sk) = kmalloc(sizeof *vsk, priority);
-   if (!vsock_sk(sk)) {
-      sk_free(sk);
-      return NULL;
-   }
-   sk_vsock(vsock_sk(sk)) = sk;
-#endif
-
    /*
     * If we go this far, we know the socket family is registered, so there's no
     * need to register it now.
@@ -2492,6 +2712,8 @@ __VSockVmciCreate(struct net *net,       // IN: Network namespace
    INIT_LIST_HEAD(&vsk->pendingLinks);
    INIT_LIST_HEAD(&vsk->acceptQueue);
    vsk->rejected = FALSE;
+   vsk->sentRequest = FALSE;
+   vsk->ignoreConnectingRst = FALSE;
    vsk->attachSubId = vsk->detachSubId = VMCI_INVALID_ID;
    vsk->peerShutdown = 0;
 
@@ -2502,8 +2724,7 @@ __VSockVmciCreate(struct net *net,       // IN: Network namespace
       vsk->trusted = capable(CAP_NET_ADMIN);
    }
 
-   vsk->notifyOps = &vSockVmciNotifyPktOps;
-   NOTIFYCALL(vsk, socketInit, sk);
+   vsk->notifyOps = NULL;
 
    if (sock) {
       VSockVmciInsertBound(vsockUnboundSockets, sk);
@@ -2637,11 +2858,6 @@ VSockVmciSkDestruct(struct sock *sk) // IN
 
    NOTIFYCALL(vsk, socketDestruct, sk);
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 5)
-   ASSERT(vsock_sk(sk) == vsk);
-   kfree(vsock_sk(sk));
-#endif
-
    down(&registrationMutex);
    vsockVmciSocketCount--;
    VSockVmciTestUnregister();
@@ -2650,7 +2866,6 @@ VSockVmciSkDestruct(struct sock *sk) // IN
 
    VSOCK_STATS_CTLPKT_DUMP_ALL();
    VSOCK_STATS_HIST_DUMP_ALL();
-
 }
 
 
@@ -2707,24 +2922,15 @@ VSockVmciRegisterProto(void)
    int err = 0;
 
    /*
-    * Before 2.6.9, each address family created their own slab (by calling
-    * kmem_cache_create() directly).  From 2.6.9 until 2.6.11, these address
-    * families instead called sk_alloc_slab() and the allocated slab was
-    * assigned to the slab variable in the proto struct and was created of size
-    * slab_obj_size.  As of 2.6.12 and later, this slab allocation was moved
-    * into proto_register() and only done if you specified a non-zero value for
-    * the second argument (alloc_slab); the size of the slab element was
+    * From 2.6.9 until 2.6.11, these address families called sk_alloc_slab()
+    * and the allocated slab was assigned to the slab variable in the proto
+    * struct and was created of size slab_obj_size. As of 2.6.12 and later,
+    * this slab allocation was moved
+    * into proto_register() and only done if you specified a non-zero value
+    * for the second argument (alloc_slab); the size of the slab element was
     * changed to obj_size.
     */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 5)
-   /* Simply here for clarity and so else case at end implies > rest. */
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9)
-   vsockCachep = kmem_cache_create("vsock", sizeof (VSockVmciSock),
-                                   0, SLAB_HWCACHE_ALIGN, NULL, NULL);
-   if (!vsockCachep) {
-      err = -ENOMEM;
-   }
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12)
    err = sk_alloc_slab(&vsockVmciProto, "vsock");
    if (err != 0) {
       sk_alloc_slab_error(&vsockVmciProto);
@@ -2757,11 +2963,7 @@ VSockVmciRegisterProto(void)
 static void
 VSockVmciUnregisterProto(void)
 {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 5)
-   /* Simply here for clarity and so else case at end implies > rest. */
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9)
-   kmem_cache_destroy(vsockCachep);
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12)
    sk_free_slab(&vsockVmciProto);
 #else
    proto_unregister(&vsockVmciProto);
@@ -3149,6 +3351,7 @@ VSockVmciStreamConnect(struct socket *sock,   // IN
    VSockVmciSock *vsk;
    struct sockaddr_vm *remoteAddr;
    long timeout;
+   Bool oldPktProto = FALSE;
    COMPAT_DEFINE_WAIT(wait);
 
    err = 0;
@@ -3205,10 +3408,22 @@ VSockVmciStreamConnect(struct socket *sock,   // IN
 
       sk->compat_sk_state = SS_CONNECTING;
 
-      err = VSOCK_SEND_CONN_REQUEST(sk, vsk->queuePairSize);
-      if (err < 0) {
-         sk->compat_sk_state = SS_UNCONNECTED;
-         goto out;
+      if (VSockVmciOldProtoOverride(&oldPktProto) && oldPktProto) {
+         err = VSOCK_SEND_CONN_REQUEST(sk, vsk->queuePairSize);
+         if (err < 0) {
+            sk->compat_sk_state = SS_UNCONNECTED;
+            goto out;
+         }
+      } else {
+         int supportedProtoVersions = VSockVmciNewProtoSupportedVersions();
+         err = VSOCK_SEND_CONN_REQUEST2(sk, vsk->queuePairSize,
+                                        supportedProtoVersions);
+         if (err < 0) {
+            sk->compat_sk_state = SS_UNCONNECTED;
+            goto out;
+         }
+
+         vsk->sentRequest = TRUE;
       }
 
       /*
@@ -3476,13 +3691,20 @@ VSockVmciPoll(struct file *file,    // IN
       mask |= POLLERR;
    }
 
-   if (sk->compat_sk_shutdown == SHUTDOWN_MASK) {
+   /*
+    * INET sockets treat local write shutdown and peer write shutdown
+    * as a case of POLLHUP set.
+    */
+   if ((sk->compat_sk_shutdown == SHUTDOWN_MASK) ||
+       ((sk->compat_sk_shutdown & SEND_SHUTDOWN) &&
+        (vsk->peerShutdown & SEND_SHUTDOWN))) {
       mask |= POLLHUP;
    }
 
    /* POLLRDHUP wasn't added until 2.6.17. */
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17)
-   if (sk->compat_sk_shutdown & RCV_SHUTDOWN) {
+   if (sk->compat_sk_shutdown & RCV_SHUTDOWN ||
+       vsk->peerShutdown & SEND_SHUTDOWN) {
       mask |= POLLRDHUP;
    }
 #endif
@@ -3547,17 +3769,29 @@ VSockVmciPoll(struct file *file,    // IN
         if (!(sk->compat_sk_shutdown & SEND_SHUTDOWN)) {
             Bool spaceAvailNow = FALSE;
             int32 ret = 0;
+
             NOTIFYCALLRET(vsk, ret, pollOut, sk, 1, &spaceAvailNow);
             if (ret < 0) {
                mask |= POLLERR;
             } else {
                if (spaceAvailNow) {
-                  mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
+                  /* Remove POLLWRBAND since INET sockets are not setting it.*/
+                  mask |= POLLOUT | POLLWRNORM;
                }
             }
         }
       }
 
+      /*
+       * Simulate INET socket poll behaviors, which sets POLLOUT|POLLWRNORM when
+       * peer is closed and nothing to read, but local send is not shutdown.
+       */
+      if (sk->compat_sk_state == SS_UNCONNECTED) {
+         if (!(sk->compat_sk_shutdown & SEND_SHUTDOWN)) {
+            mask |= POLLOUT | POLLWRNORM;
+         }
+      }
+
       release_sock(sk);
    }
 
@@ -3697,32 +3931,11 @@ VSockVmciShutdown(struct socket *sock,  // IN
  *----------------------------------------------------------------------------
  */
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 43)
-static int
-VSockVmciDgramSendmsg(struct socket *sock,          // IN: socket to send on
-                      struct msghdr *msg,           // IN: message to send
-                      int len,                      // IN: length of message
-                      struct scm_cookie *scm)       // UNUSED
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 65)
-static int
-VSockVmciDgramSendmsg(struct kiocb *kiocb,          // UNUSED
-                      struct socket *sock,          // IN: socket to send on
-                      struct msghdr *msg,           // IN: message to send
-                      int len,                      // IN: length of message
-                      struct scm_cookie *scm);      // UNUSED
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 2)
-static int
-VSockVmciDgramSendmsg(struct kiocb *kiocb,          // UNUSED
-                      struct socket *sock,          // IN: socket to send on
-                      struct msghdr *msg,           // IN: message to send
-                      int len)                      // IN: length of message
-#else
 static int
 VSockVmciDgramSendmsg(struct kiocb *kiocb,          // UNUSED
                       struct socket *sock,          // IN: socket to send on
                       struct msghdr *msg,           // IN: message to send
                       size_t len)                   // IN: length of message
-#endif
 {
    int err;
    struct sock *sk;
@@ -4008,32 +4221,11 @@ VSockVmciStreamGetsockopt(struct socket *sock,          // IN
  *----------------------------------------------------------------------------
  */
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 43)
-static int
-VSockVmciStreamSendmsg(struct socket *sock,          // IN: socket to send on
-                       struct msghdr *msg,           // IN: message to send
-                       int len,                      // IN: length of message
-                       struct scm_cookie *scm)       // UNUSED
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 65)
-static int
-VSockVmciStreamSendmsg(struct kiocb *kiocb,          // UNUSED
-                       struct socket *sock,          // IN: socket to send on
-                       struct msghdr *msg,           // IN: message to send
-                       int len,                      // IN: length of message
-                       struct scm_cookie *scm);      // UNUSED
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 2)
-static int
-VSockVmciStreamSendmsg(struct kiocb *kiocb,          // UNUSED
-                       struct socket *sock,          // IN: socket to send on
-                       struct msghdr *msg,           // IN: message to send
-                       int len)                      // IN: length of message
-#else
 static int
 VSockVmciStreamSendmsg(struct kiocb *kiocb,          // UNUSED
                        struct socket *sock,          // IN: socket to send on
                        struct msghdr *msg,           // IN: message to send
                        size_t len)                   // IN: length of message
-#endif
 {
    struct sock *sk;
    VSockVmciSock *vsk;
@@ -4061,7 +4253,9 @@ VSockVmciStreamSendmsg(struct kiocb *kiocb,          // UNUSED
       goto out;
    }
 
-   if (sk->compat_sk_shutdown & SEND_SHUTDOWN) {
+   /* Send data only if both sides are not shutdown in the direction. */
+   if (sk->compat_sk_shutdown & SEND_SHUTDOWN ||
+       vsk->peerShutdown & RCV_SHUTDOWN) {
       err = -EPIPE;
       goto out;
    }
@@ -4109,6 +4303,7 @@ VSockVmciStreamSendmsg(struct kiocb *kiocb,          // UNUSED
          }
 
          NOTIFYCALLRET(vsk, err, sendPreBlock, sk, &sendData);
+
          if (err < 0) {
             goto outWait;
          }
@@ -4200,36 +4395,12 @@ out:
  *----------------------------------------------------------------------------
  */
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 43)
-static int
-VSockVmciDgramRecvmsg(struct socket *sock,           // IN: socket to receive from
-                      struct msghdr *msg,            // IN/OUT: message to receive into
-                      int len,                       // IN: length of receive buffer
-                      int flags,                     // IN: receive flags
-                      struct scm_cookie *scm)        // UNUSED
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 65)
-static int
-VSockVmciDgramRecvmsg(struct kiocb *kiocb,          // UNUSED
-                      struct socket *sock,          // IN: socket to receive from
-                      struct msghdr *msg,           // IN/OUT: message to receive into
-                      int len,                      // IN: length of receive buffer
-                      int flags,                    // IN: receive flags
-                      struct scm_cookie *scm)       // UNUSED
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 2)
-static int
-VSockVmciDgramRecvmsg(struct kiocb *kiocb,          // UNUSED
-                      struct socket *sock,          // IN: socket to receive from
-                      struct msghdr *msg,           // IN/OUT: message to receive into
-                      int len,                      // IN: length of receive buffer
-                      int flags)                    // IN: receive flags
-#else
 static int
 VSockVmciDgramRecvmsg(struct kiocb *kiocb,          // UNUSED
                       struct socket *sock,          // IN: socket to receive from
                       struct msghdr *msg,           // IN/OUT: message to receive into
                       size_t len,                   // IN: length of receive buffer
                       int flags)                    // IN: receive flags
-#endif
 {
    int err;
    int noblock;
@@ -4315,36 +4486,12 @@ out:
  *----------------------------------------------------------------------------
  */
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 43)
-static int
-VSockVmciStreamRecvmsg(struct socket *sock,           // IN: socket to receive from
-                       struct msghdr *msg,            // IN/OUT: message to receive into
-                       int len,                       // IN: length of receive buffer
-                       int flags,                     // IN: receive flags
-                       struct scm_cookie *scm)        // UNUSED
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 65)
-static int
-VSockVmciStreamRecvmsg(struct kiocb *kiocb,          // UNUSED
-                       struct socket *sock,          // IN: socket to receive from
-                       struct msghdr *msg,           // IN/OUT: message to receive into
-                       int len,                      // IN: length of receive buffer
-                       int flags,                    // IN: receive flags
-                       struct scm_cookie *scm)       // UNUSED
-#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 2)
-static int
-VSockVmciStreamRecvmsg(struct kiocb *kiocb,          // UNUSED
-                       struct socket *sock,          // IN: socket to receive from
-                       struct msghdr *msg,           // IN/OUT: message to receive into
-                       int len,                      // IN: length of receive buffer
-                       int flags)                    // IN: receive flags
-#else
 static int
 VSockVmciStreamRecvmsg(struct kiocb *kiocb,          // UNUSED
                        struct socket *sock,          // IN: socket to receive from
                        struct msghdr *msg,           // IN/OUT: message to receive into
                        size_t len,                   // IN: length of receive buffer
                        int flags)                    // IN: receive flags
-#endif
 {
    struct sock *sk;
    VSockVmciSock *vsk;
@@ -4383,6 +4530,10 @@ VSockVmciStreamRecvmsg(struct kiocb *kiocb,          // UNUSED
       goto out;
    }
 
+   /*
+    * We don't check peerShutdown flag here since peer may actually shut down,
+    * but there can be data in the VMCI queue that local socket can receive.
+    */
    if (sk->compat_sk_shutdown & RCV_SHUTDOWN) {
       err = 0;
       goto out;
@@ -4492,12 +4643,10 @@ VSockVmciStreamRecvmsg(struct kiocb *kiocb,          // UNUSED
 
       /*
        * If the other side has shutdown for sending and there is nothing more to
-       * read, then set our socket's RCV_SHUTDOWN flag and modify the socket
-       * state.
+       * read, then modify the socket state.
        */
       if (vsk->peerShutdown & SEND_SHUTDOWN) {
          if (VSockVmciStreamHasData(vsk) <= 0) {
-            sk->compat_sk_shutdown |= RCV_SHUTDOWN;
             sk->compat_sk_state = SS_UNCONNECTED;
             compat_sock_set_done(sk);
             sk->compat_sk_state_change(sk);
@@ -4607,18 +4756,10 @@ VSockVmciIoctl32Handler(unsigned int fd,        // IN
                         struct file * filp)     // IN
 {
    int ret;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 26) || \
-   (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 3))
-   lock_kernel();
-#endif
    ret = -ENOTTY;
    if (filp && filp->f_op && filp->f_op->ioctl == VSockVmciDevIoctl) {
       ret = VSockVmciDevIoctl(filp->f_dentry->d_inode, filp, iocmd, ioarg);
    }
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 26) || \
-   (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 3))
-   unlock_kernel();
-#endif
    return ret;
 }
 #endif /* !HAVE_COMPAT_IOCTL */
@@ -4935,6 +5076,7 @@ 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
@@ -4942,3 +5084,9 @@ MODULE_LICENSE("GPL v2");
  * by default (i.e., neither mkinitrd nor modprobe will accept it).
  */
 MODULE_INFO(supported, "external");
+
+#ifdef VMX86_DEVEL
+/* We only support protocol negotiation overrides on devel builds. */
+module_param(protocolOverride, int, 0);
+MODULE_PARM_DESC(protocolOverride, "Specify a vsock protocol (auto negotiated by default");
+#endif
index f66a914a28274a2442427e46e7f6bbfde0ab6a7b..85f9714678dd6e9ec31d9d0bf7d1527d2a7ef541 100644 (file)
@@ -93,6 +93,8 @@ typedef struct VSockVmciSock {
    Bool rejected;
    compat_delayed_work dwork;
    uint32 peerShutdown;
+   Bool sentRequest;
+   Bool ignoreConnectingRst;
 } VSockVmciSock;
 
 int VSockVmciSendControlPktBH(struct sockaddr_vm *src,
@@ -107,7 +109,9 @@ int VSockVmciReplyControlPktFast(VSockPacket *pkt, VSockPacketType type,
                                  VSockWaitingInfo *wait, VMCIHandle handle);
 int VSockVmciSendControlPkt(struct sock *sk, VSockPacketType type,
                             uint64 size, uint64 mode,
-                            VSockWaitingInfo *wait, VMCIHandle handle);
+                            VSockWaitingInfo *wait,
+                            VSockProtoVersion version,
+                            VMCIHandle handle);
 
 int64 VSockVmciStreamHasData(VSockVmciSock *vsk);
 int64 VSockVmciStreamHasSpace(VSockVmciSock *vsk);
@@ -130,34 +134,50 @@ int64 VSockVmciStreamHasSpace(VSockVmciSock *vsk);
    ((_pkt)->type == VSOCK_PACKET_TYPE_RST) ?                            \
       0 :                                                               \
       VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_RST,               \
-                              0, 0, NULL, VMCI_INVALID_HANDLE)
+                              0, 0, NULL, VSOCK_PROTO_INVALID,          \
+                              VMCI_INVALID_HANDLE)
 #define VSOCK_SEND_NEGOTIATE(_sk, _size)                                \
    VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_NEGOTIATE,            \
-                           _size, 0, NULL, VMCI_INVALID_HANDLE)
+                           _size, 0, NULL, VSOCK_PROTO_INVALID,         \
+                           VMCI_INVALID_HANDLE)
+#define VSOCK_SEND_NEGOTIATE2(_sk, _size, signalProto)                  \
+   VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_NEGOTIATE2,           \
+                           _size, 0, NULL, signalProto,                 \
+                           VMCI_INVALID_HANDLE)
 #define VSOCK_SEND_QP_OFFER(_sk, _handle)                               \
    VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_OFFER,                \
-                           0, 0, NULL, _handle)
+                           0, 0, NULL, VSOCK_PROTO_INVALID, _handle)
 #define VSOCK_SEND_CONN_REQUEST(_sk, _size)                             \
    VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_REQUEST,              \
-                           _size, 0, NULL, VMCI_INVALID_HANDLE)
+                           _size, 0, NULL, VSOCK_PROTO_INVALID,         \
+                           VMCI_INVALID_HANDLE)
+#define VSOCK_SEND_CONN_REQUEST2(_sk, _size, signalProto)               \
+   VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_REQUEST2,             \
+                           _size, 0, NULL, signalProto,                 \
+                           VMCI_INVALID_HANDLE)
 #define VSOCK_SEND_ATTACH(_sk, _handle)                                 \
    VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_ATTACH,               \
-                           0, 0, NULL, _handle)
+                           0, 0, NULL, VSOCK_PROTO_INVALID, _handle)
 #define VSOCK_SEND_WROTE(_sk)                                           \
    VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_WROTE,                \
-                           0, 0, NULL, VMCI_INVALID_HANDLE)
+                           0, 0, NULL, VSOCK_PROTO_INVALID,             \
+                           VMCI_INVALID_HANDLE)
 #define VSOCK_SEND_READ(_sk)                                            \
    VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_READ,                 \
-                           0, 0, NULL, VMCI_INVALID_HANDLE)
+                           0, 0, NULL, VSOCK_PROTO_INVALID,             \
+                           VMCI_INVALID_HANDLE)
 #define VSOCK_SEND_SHUTDOWN(_sk, _mode)                                 \
    VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_SHUTDOWN,             \
-                           0, _mode, NULL, VMCI_INVALID_HANDLE)
+                           0, _mode, NULL, VSOCK_PROTO_INVALID,         \
+                           VMCI_INVALID_HANDLE)
 #define VSOCK_SEND_WAITING_WRITE(_sk, _waitInfo)                        \
    VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_WAITING_WRITE,        \
-                           0, 0, _waitInfo, VMCI_INVALID_HANDLE)
+                           0, 0, _waitInfo, VSOCK_PROTO_INVALID,        \
+                           VMCI_INVALID_HANDLE)
 #define VSOCK_SEND_WAITING_READ(_sk, _waitInfo)                         \
    VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_WAITING_READ,         \
-                           0, 0, _waitInfo, VMCI_INVALID_HANDLE)
+                           0, 0, _waitInfo, VSOCK_PROTO_INVALID,        \
+                           VMCI_INVALID_HANDLE)
 #define VSOCK_REPLY_RESET(_pkt)                                         \
    VSockVmciReplyControlPktFast(_pkt, VSOCK_PACKET_TYPE_RST,            \
                                 0, 0, NULL, VMCI_INVALID_HANDLE)
index 81f0ce0ba2565d987d3bec015e03ecb8032c8fe1..858773495a65577d0a1ca29f7fe53678a21e262b 100644 (file)
@@ -33,7 +33,7 @@
 #include "af_vsock.h"
 
 #define PKT_FIELD(vsk, fieldName) \
-   (vsk)->notify.fieldName
+   (vsk)->notify.pkt.fieldName
 
 #define VSOCK_MAX_DGRAM_RESENDS       10
 
@@ -1124,6 +1124,65 @@ VSockVmciNotifyPktHandlePkt(struct sock *sk,         // IN
    }
 }
 
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNotifyPktProcessRequest
+ *
+ *      Called near the end of process request.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+VSockVmciNotifyPktProcessRequest(struct sock *sk) // IN
+{
+   VSockVmciSock *vsk;
+
+   ASSERT(sk);
+
+   vsk = vsock_sk(sk);
+
+   PKT_FIELD(vsk, writeNotifyWindow) = vsk->consumeSize;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNotifyPktProcessNegotiate
+ *
+ *      Called near the end of process negotiate.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+VSockVmciNotifyPktProcessNegotiate(struct sock *sk) // IN
+{
+   VSockVmciSock *vsk;
+
+   ASSERT(sk);
+
+   vsk = vsock_sk(sk);
+
+   PKT_FIELD(vsk, writeNotifyWindow) = vsk->consumeSize;
+}
+
+
 /* Socket control packet based operations. */
 VSockVmciNotifyOps vSockVmciNotifyPktOps = {
    VSockVmciNotifyPktSocketInit,
@@ -1138,5 +1197,7 @@ VSockVmciNotifyOps vSockVmciNotifyPktOps = {
    VSockVmciNotifyPktSendInit,
    VSockVmciNotifyPktSendPreBlock,
    VSockVmciNotifyPktSendPreEnqueue,
-   VSockVmciNotifyPktSendPostEnqueue
+   VSockVmciNotifyPktSendPostEnqueue,
+   VSockVmciNotifyPktProcessRequest,
+   VSockVmciNotifyPktProcessNegotiate,
 };
index e07346e53227851760e0d113c8a37c430fcfe5ff..bf91adc18af780333b029a4c41b26ef2e36f1409 100644 (file)
 #  define VSOCK_OPTIMIZATION_FLOW_CONTROL 1
 #endif
 
+#define VSOCK_MAX_DGRAM_RESENDS       10
+
 #define NOTIFYCALLRET(vsk, rv, mod_fn, args...)                     \
 do {                                                                \
-  if (vsk->notifyOps->mod_fn != NULL) {                             \
+  if (vsk->notifyOps &&                                             \
+      vsk->notifyOps->mod_fn != NULL) {                             \
         rv = (vsk->notifyOps->mod_fn)(args);                        \
   } else {                                                          \
         rv = 0;                                                     \
@@ -47,13 +50,13 @@ do {                                                                \
 
 #define NOTIFYCALL(vsk, mod_fn, args...)                            \
 do {                                                                \
-  if (vsk->notifyOps->mod_fn != NULL) {                             \
+  if (vsk->notifyOps &&                                             \
+      vsk->notifyOps->mod_fn != NULL) {                             \
         (vsk->notifyOps->mod_fn)(args);                             \
   }                                                                 \
 } while (0)
 
-
-typedef struct VSockVmciNotify {
+typedef struct VSockVmciNotifyPkt {
    uint64 writeNotifyWindow;
    uint64 writeNotifyMinWindow;
    Bool peerWaitingRead;
@@ -65,23 +68,29 @@ typedef struct VSockVmciNotify {
    VSockWaitingInfo peerWaitingWriteInfo;
    uint64 produceQGeneration;
    uint64 consumeQGeneration;
+} VSockVmciNotifyPkt;
+
+typedef struct VSockVmciNotifyPktQState {
+   uint64 writeNotifyWindow;
+   uint64 writeNotifyMinWindow;
+   Bool peerWaitingWrite;
+   Bool peerWaitingWriteDetected;
+} VSockVmciNotifyPktQState;
+
+typedef union VSockVmciNotify {
+   VSockVmciNotifyPkt pkt;
+   VSockVmciNotifyPktQState pktQState;
 } VSockVmciNotify;
 
 typedef struct VSockVmciRecvNotifyData {
-#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
    uint64 consumeHead;
    uint64 produceTail;
-#ifdef VSOCK_OPTIMIZATION_FLOW_CONTROL
    Bool notifyOnBlock;
-#endif
-#endif
 } VSockVmciRecvNotifyData;
 
 typedef struct VSockVmciSendNotifyData {
-#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
    uint64 consumeHead;
    uint64 produceTail;
-#endif
 } VSockVmciSendNotifyData;
 
 /* Socket notification callbacks. */
@@ -110,8 +119,11 @@ typedef struct VSockVmciNotifyOps {
    int32 (*sendPostEnqueue)(struct sock *sk,
                             ssize_t written,
                             VSockVmciSendNotifyData *data);
+   void  (*processRequest)(struct sock *sk);
+   void  (*processNegotiate)(struct sock *sk);
 } VSockVmciNotifyOps;
 
 extern VSockVmciNotifyOps vSockVmciNotifyPktOps;
+extern VSockVmciNotifyOps vSockVmciNotifyPktQStateOps;
 
 #endif /* __NOTIFY_H__ */
diff --git a/open-vm-tools/modules/linux/vsock/linux/notifyQState.c b/open-vm-tools/modules/linux/vsock/linux/notifyQState.c
new file mode 100644 (file)
index 0000000..bee549e
--- /dev/null
@@ -0,0 +1,788 @@
+/*********************************************************
+ * Copyright (C) 2009 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
+ *
+ *********************************************************/
+
+/*
+ * notifyQState.c --
+ *
+ *      Linux control notifications based on Queuepair state for the VMCI
+ *      Stream Sockets protocol.
+ */
+
+
+#include "driver-config.h"
+
+#include <linux/socket.h>
+
+#include "compat_sock.h"
+
+#include "notify.h"
+#include "af_vsock.h"
+
+#define PKT_FIELD(vsk, fieldName) \
+   (vsk)->notify.pktQState.fieldName
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNotifyWaitingWrite --
+ *
+ *      Determines if the conditions have been met to notify a waiting writer.
+ *
+ * Results:
+ *      TRUE if a notification should be sent, FALSE otherwise.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+VSockVmciNotifyWaitingWrite(VSockVmciSock *vsk)    // IN
+{
+   Bool retval;
+   uint64 notifyLimit;
+
+   if (!PKT_FIELD(vsk, peerWaitingWrite)) {
+      return FALSE;
+   }
+
+   /*
+    * When the sender blocks, we take that as a sign that the sender
+    * is faster than the receiver. To reduce the transmit rate of the
+    * sender, we delay the sending of the read notification by
+    * decreasing the writeNotifyWindow. The notification is delayed
+    * until the number of bytes used in the queue drops below the
+    * writeNotifyWindow.
+    */
+
+   if (!PKT_FIELD(vsk, peerWaitingWriteDetected)) {
+      PKT_FIELD(vsk, peerWaitingWriteDetected) = TRUE;
+      PKT_FIELD(vsk, writeNotifyWindow) -= PAGE_SIZE;
+      if (PKT_FIELD(vsk, writeNotifyWindow) <
+                    PKT_FIELD(vsk, writeNotifyMinWindow)) {
+         PKT_FIELD(vsk, writeNotifyWindow) =
+            PKT_FIELD(vsk, writeNotifyMinWindow);
+      }
+   }
+   notifyLimit = vsk->consumeSize - PKT_FIELD(vsk, writeNotifyWindow);
+
+   /*
+    * The notifyLimit is used to delay notifications in the case where
+    * flow control is enabled. Below the test is expressed in terms of
+    * free space in the queue:
+    *   if freeSpace > ConsumeSize - writeNotifyWindow then notify
+    * An alternate way of expressing this is to rewrite the expression
+    * to use the data ready in the receive queue:
+    *   if writeNotifyWindow > bufferReady then notify
+    * as freeSpace == ConsumeSize - bufferReady.
+    */
+
+   retval = VMCIQueue_FreeSpace(vsk->consumeQ, vsk->produceQ, vsk->consumeSize) >
+            notifyLimit;
+
+   if (retval) {
+      /*
+       * Once we notify the peer, we reset the detected flag so the
+       * next wait will again cause a decrease in the window size.
+       */
+
+      PKT_FIELD(vsk, peerWaitingWriteDetected) = FALSE;
+   }
+   return retval;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciHandleRead --
+ *
+ *      Handles an incoming read message.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+VSockVmciHandleRead(struct sock *sk,            // IN
+                    VSockPacket *pkt,           // IN: unused
+                    Bool bottomHalf,            // IN: unused
+                    struct sockaddr_vm *dst,    // IN: unused
+                    struct sockaddr_vm *src)    // IN: unused
+{
+
+   sk->compat_sk_write_space(sk);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciHandleWrote --
+ *
+ *      Handles an incoming wrote message.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+VSockVmciHandleWrote(struct sock *sk,            // IN
+                     VSockPacket *pkt,           // IN: unused
+                     Bool bottomHalf,            // IN: unused
+                     struct sockaddr_vm *dst,    // IN: unused
+                     struct sockaddr_vm *src)    // IN: unused
+{
+   sk->compat_sk_data_ready(sk, 0);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciBlockUpdateWriteWindow --
+ *
+ *      Updates the write window when we are blocking for data.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+VSockVmciBlockUpdateWriteWindow(struct sock *sk) // IN
+{
+   VSockVmciSock *vsk;
+
+   vsk = vsock_sk(sk);
+
+   if (PKT_FIELD(vsk, writeNotifyWindow) < vsk->consumeSize) {
+      PKT_FIELD(vsk, writeNotifyWindow) =
+         MIN(PKT_FIELD(vsk, writeNotifyWindow) + PAGE_SIZE,
+             vsk->consumeSize);
+   }
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciSendReadNotification --
+ *
+ *      Sends a read notification to this socket's peer.
+ *
+ * Results:
+ *      >= 0 if the datagram is sent successfully, negative error value
+ *      otherwise.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+VSockVmciSendReadNotification(struct sock *sk)  // IN
+{
+   VSockVmciSock *vsk;
+   Bool sentRead;
+   unsigned int retries;
+   int err;
+
+   ASSERT(sk);
+
+   vsk = vsock_sk(sk);
+   sentRead = FALSE;
+   retries = 0;
+   err = 0;
+
+   if (VSockVmciNotifyWaitingWrite(vsk)) {
+      /*
+       * Notify the peer that we have read, retrying the send on failure up to our
+       * maximum value.  XXX For now we just log the failure, but later we should
+       * schedule a work item to handle the resend until it succeeds.  That would
+       * require keeping track of work items in the vsk and cleaning them up upon
+       * socket close.
+       */
+      while (!(vsk->peerShutdown & RCV_SHUTDOWN) &&
+             !sentRead &&
+             retries < VSOCK_MAX_DGRAM_RESENDS) {
+         err = VSOCK_SEND_READ(sk);
+         if (err >= 0) {
+            sentRead = TRUE;
+         }
+
+         retries++;
+      }
+
+      if (retries >= VSOCK_MAX_DGRAM_RESENDS && !sentRead) {
+         Warning("unable to send read notification to peer for socket %p.\n", sk);
+      } else {
+         PKT_FIELD(vsk, peerWaitingWrite) = FALSE;
+      }
+   }
+   return err;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNotifyPktSocketInit --
+ *
+ *      Function that is called after a socket is created and before any
+ *      notify ops are used.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+VSockVmciNotifyPktSocketInit(struct sock *sk) // IN
+{
+   VSockVmciSock *vsk;
+   vsk = vsock_sk(sk);
+
+   PKT_FIELD(vsk, writeNotifyWindow) = 0;
+   PKT_FIELD(vsk, writeNotifyMinWindow) = PAGE_SIZE;
+   PKT_FIELD(vsk, peerWaitingWrite) = FALSE;
+   PKT_FIELD(vsk, peerWaitingWriteDetected) = FALSE;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNotifyPktSocketDestruct --
+ *
+ *      Function that is called when the socket is being released.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+VSockVmciNotifyPktSocketDestruct(struct sock *sk) // IN
+{
+   VSockVmciSock *vsk;
+   vsk = vsock_sk(sk);
+
+   PKT_FIELD(vsk, writeNotifyWindow) = 0;
+   PKT_FIELD(vsk, writeNotifyMinWindow) = PAGE_SIZE;
+   PKT_FIELD(vsk, peerWaitingWrite) = FALSE;
+   PKT_FIELD(vsk, peerWaitingWriteDetected) = FALSE;
+   return;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNotifyPktPollIn --
+ *
+ *      Called by the poll function to figure out if there is data to read
+ *      and to setup future notifications if needed. Only called on sockets
+ *      that aren't shutdown for recv.
+ *
+ * Results:
+ *      0 on success. Negative error on failure.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int32
+VSockVmciNotifyPktPollIn(struct sock *sk,    // IN
+                         int target,         // IN
+                         Bool *dataReadyNow) // IN
+{
+   VSockVmciSock *vsk;
+
+   ASSERT(sk);
+   ASSERT(dataReadyNow);
+
+   vsk = vsock_sk(sk);
+
+   if (VSockVmciStreamHasData(vsk)) {
+      *dataReadyNow = TRUE;
+   } else {
+      /*
+       * We can't read right now because there is nothing in the queue.
+       * Ask for notifications when there is something to read.
+       */
+      if (sk->compat_sk_state == SS_CONNECTED) {
+         VSockVmciBlockUpdateWriteWindow(sk);
+      }
+      *dataReadyNow = FALSE;
+   }
+
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNotifyPktPollOut
+ *
+ *      Called by the poll function to figure out if there is space to write
+ *      and to setup future notifications if needed. Only called on a
+ *      connected socket that isn't shutdown for send.
+ *
+ * Results:
+ *      0 on success. Negative error on failure.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int32
+VSockVmciNotifyPktPollOut(struct sock *sk,     // IN
+                          int target,          // IN
+                          Bool *spaceAvailNow) // IN
+{
+   int64 produceQFreeSpace;
+   VSockVmciSock *vsk;
+
+   ASSERT(sk);
+   ASSERT(spaceAvailNow);
+
+   vsk = vsock_sk(sk);
+
+   produceQFreeSpace =
+      VSockVmciStreamHasSpace(vsk);
+   if (produceQFreeSpace > 0) {
+      *spaceAvailNow = TRUE;
+      return 0;
+   } else if (produceQFreeSpace == 0) {
+      /*
+       * This is a connected socket but we can't currently send data. Nothing
+       * else to do.
+       */
+      *spaceAvailNow = FALSE;
+   }
+
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNotifyPktRecvInit --
+ *
+ *      Called at the start of a stream recv call with the socket lock held.
+ *
+ * Results:
+ *      0 on success. Negative error on failure.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int32
+VSockVmciNotifyPktRecvInit(struct sock *sk,               // IN
+                           int target,                    // IN
+                           VSockVmciRecvNotifyData *data) // IN
+{
+   VSockVmciSock *vsk;
+
+   ASSERT(sk);
+   ASSERT(data);
+
+   vsk = vsock_sk(sk);
+
+   data->consumeHead = 0;
+   data->produceTail = 0;
+   data->notifyOnBlock = FALSE;
+
+   if (PKT_FIELD(vsk, writeNotifyMinWindow) < target + 1) {
+      ASSERT(target < vsk->consumeSize);
+      PKT_FIELD(vsk, writeNotifyMinWindow) = target + 1;
+      if (PKT_FIELD(vsk, writeNotifyWindow) <
+          PKT_FIELD(vsk, writeNotifyMinWindow)) {
+         /*
+          * If the current window is smaller than the new minimal
+          * window size, we need to reevaluate whether we need to
+          * notify the sender. If the number of ready bytes are
+          * smaller than the new window, we need to send a
+          * notification to the sender before we block.
+          */
+
+         PKT_FIELD(vsk, writeNotifyWindow) =
+            PKT_FIELD(vsk, writeNotifyMinWindow);
+         data->notifyOnBlock = TRUE;
+      }
+   }
+
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNotifyPktRecvPreBlock --
+ *
+ *      Called right before a socket is about to block with the socket lock
+ *      held. The socket lock may have been released between the entry
+ *      function and the preblock call.
+ *
+ *      Note: This function may be called multiple times before the post
+ *      block function is called.
+ *
+ * Results:
+ *      0 on success. Negative error on failure.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int32
+VSockVmciNotifyPktRecvPreBlock(struct sock *sk,               // IN
+                               int target,                    // IN
+                               VSockVmciRecvNotifyData *data) // IN
+{
+   VSockVmciSock *vsk;
+   int err;
+
+   ASSERT(sk);
+   ASSERT(data);
+
+   vsk = vsock_sk(sk);
+   err = 0;
+
+   VSockVmciBlockUpdateWriteWindow(sk);
+
+   if (data->notifyOnBlock) {
+      err = VSockVmciSendReadNotification(sk);
+      if (err < 0) {
+         return err;
+      }
+      data->notifyOnBlock = FALSE;
+   }
+
+   return err;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNotifyPktRecvPostDequeue --
+ *
+ *      Called right after we dequeue / peek data from a socket.
+ *
+ * Results:
+ *      0 on success. Negative error on failure.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int32
+VSockVmciNotifyPktRecvPostDequeue(struct sock *sk,               // IN
+                                  int target,                    // IN
+                                  ssize_t copied,                // IN
+                                  Bool dataRead,                 // IN
+                                  VSockVmciRecvNotifyData *data) // IN
+{
+   VSockVmciSock *vsk;
+   int err;
+   Bool wasFull = FALSE;
+   uint64 freeSpace;
+
+   ASSERT(sk);
+   ASSERT(data);
+
+   vsk = vsock_sk(sk);
+   err = 0;
+
+   if (dataRead) {
+      Atomic_MFence();
+
+      freeSpace = VMCIQueue_FreeSpace(vsk->consumeQ,
+                                      vsk->produceQ,
+                                      vsk->consumeSize);
+      wasFull = freeSpace == copied;
+
+      if (wasFull) {
+         PKT_FIELD(vsk, peerWaitingWrite) = TRUE;
+      }
+
+      err = VSockVmciSendReadNotification(sk);
+      if (err < 0) {
+         return err;
+      }
+
+      /* See the comment in VSockVmciNotifyPktSendPostEnqueue */
+      sk->compat_sk_data_ready(sk, 0);
+   }
+
+   return err;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNotifyPktSendInit --
+ *
+ *      Called at the start of a stream send call with the socket lock held.
+ *
+ * Results:
+ *      0 on success. A negative error code on failure.
+ *
+ * Side effects:
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int32
+VSockVmciNotifyPktSendInit(struct sock *sk,               // IN
+                           VSockVmciSendNotifyData *data) // IN
+{
+   ASSERT(sk);
+   ASSERT(data);
+
+   data->consumeHead = 0;
+   data->produceTail = 0;
+
+   return 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNotifySendPostEnqueue --
+ *
+ *      Called right after we enqueue data to a socket.
+ *
+ * Results:
+ *      0 on success. Negative error on failure.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int32
+VSockVmciNotifyPktSendPostEnqueue(struct sock *sk,               // IN
+                                  ssize_t written,               // IN
+                                  VSockVmciSendNotifyData *data) // IN
+{
+   int err = 0;
+   VSockVmciSock *vsk;
+   Bool sentWrote = FALSE;
+   Bool wasEmpty;
+
+   int retries = 0;
+
+   ASSERT(sk);
+   ASSERT(data);
+
+   vsk = vsock_sk(sk);
+
+   Atomic_MFence();
+
+   wasEmpty = (VMCIQueue_BufReady(vsk->produceQ,
+                                  vsk->consumeQ,
+                                  vsk->produceSize) == written);
+   if (wasEmpty) {
+      while (!(vsk->peerShutdown & RCV_SHUTDOWN) &&
+             !sentWrote &&
+             retries < VSOCK_MAX_DGRAM_RESENDS) {
+         err = VSOCK_SEND_WROTE(sk);
+         if (err >= 0) {
+            sentWrote = TRUE;
+         }
+
+         retries++;
+      }
+   }
+
+   if (retries >= VSOCK_MAX_DGRAM_RESENDS && !sentWrote) {
+      Warning("unable to send wrote notification to peer for socket %p.\n", sk);
+      return err;
+   }
+
+   return err;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNotifyPktHandlePkt
+ *
+ *      Called when a notify packet is recieved for a socket in the connected
+ *      state. Note this might be called from a bottom half.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+VSockVmciNotifyPktHandlePkt(struct sock *sk,         // IN
+                            VSockPacket *pkt,        // IN
+                            Bool bottomHalf,         // IN
+                            struct sockaddr_vm *dst, // IN
+                            struct sockaddr_vm *src, // IN
+                            Bool *pktProcessed)      // In
+{
+   Bool processed = FALSE;
+
+   ASSERT(sk);
+   ASSERT(pkt);
+
+   switch (pkt->type) {
+   case VSOCK_PACKET_TYPE_WROTE:
+      VSockVmciHandleWrote(sk, pkt, bottomHalf, dst, src);
+      processed = TRUE;
+      break;
+   case VSOCK_PACKET_TYPE_READ:
+      VSockVmciHandleRead(sk, pkt, bottomHalf, dst, src);
+      processed = TRUE;
+      break;
+   }
+
+   if (pktProcessed) {
+      *pktProcessed = processed;
+   }
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNotifyPktProcessRequest
+ *
+ *      Called near the end of process request.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+VSockVmciNotifyPktProcessRequest(struct sock *sk) // IN
+{
+   VSockVmciSock *vsk;
+
+   ASSERT(sk);
+
+   vsk = vsock_sk(sk);
+
+   PKT_FIELD(vsk, writeNotifyWindow) = vsk->consumeSize;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciNotifyPktProcessNegotiate
+ *
+ *      Called near the end of process negotiate.
+ *
+ * Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+VSockVmciNotifyPktProcessNegotiate(struct sock *sk) // IN
+{
+   VSockVmciSock *vsk;
+
+   ASSERT(sk);
+
+   vsk = vsock_sk(sk);
+
+   PKT_FIELD(vsk, writeNotifyWindow) = vsk->consumeSize;
+}
+
+
+/* Socket always on control packet based operations. */
+VSockVmciNotifyOps vSockVmciNotifyPktQStateOps = {
+   VSockVmciNotifyPktSocketInit,
+   VSockVmciNotifyPktSocketDestruct,
+   VSockVmciNotifyPktPollIn,
+   VSockVmciNotifyPktPollOut,
+   VSockVmciNotifyPktHandlePkt,
+   VSockVmciNotifyPktRecvInit,
+   VSockVmciNotifyPktRecvPreBlock,
+   NULL, /* recvPreDequeue */
+   VSockVmciNotifyPktRecvPostDequeue,
+   VSockVmciNotifyPktSendInit,
+   NULL, /* sendPreBlock */
+   NULL, /* sendPreEnqueue */
+   VSockVmciNotifyPktSendPostEnqueue,
+   VSockVmciNotifyPktProcessRequest,
+   VSockVmciNotifyPktProcessNegotiate,
+};
index 53f2edb8e394a62c4e7f3bee05ab8df2a1a03b7d..93288565540437c34fb80ead9ce215f14b99f976 100644 (file)
@@ -83,6 +83,8 @@ VSockVmciLogPkt(char const *function,   // IN
       [VSOCK_PACKET_TYPE_SHUTDOWN]       = "SHUTDOWN",
       [VSOCK_PACKET_TYPE_WAITING_WRITE]  = "WAITING_WRITE",
       [VSOCK_PACKET_TYPE_WAITING_READ]   = "WAITING_READ",
+      [VSOCK_PACKET_TYPE_REQUEST2]       = "REQUEST2",
+      [VSOCK_PACKET_TYPE_NEGOTIATE2]     = "NEGOTIATE2",
    };
 
    written = snprintf(cur, left, "PKT: %u:%u -> %u:%u",
@@ -138,6 +140,14 @@ VSockVmciLogPkt(char const *function,   // IN
 
       break;
 
+   case VSOCK_PACKET_TYPE_REQUEST2:
+   case VSOCK_PACKET_TYPE_NEGOTIATE2:
+      written = snprintf(cur, left, ", %s, size = %"FMT64"u, "
+                         "proto = %u",
+                         typeStrings[pkt->type], pkt->u.size,
+                         pkt->proto);
+      break;
+
    default:
       written = snprintf(cur, left, ", unrecognized type");
    }
index 2aa7f8be808f093255283e3ed9d761532e6a1582..3e6f23da91cd39545138f5f9cf2cebbeb5956c6a 100644 (file)
 /* The resource ID on which control packets are sent. */
 #define VSOCK_PACKET_RID 1
 
-/* Assert that the given packet is valid. */
-#define VSOCK_PACKET_ASSERT(_p)                 \
-   ASSERT((_p));                                \
-   ASSERT((_p)->type < VSOCK_PACKET_TYPE_MAX);  \
-   ASSERT(0 == (_p)->_reserved1);               \
-   ASSERT(0 == (_p)->_reserved2)
-
+/*
+ * Assert that the given packet is valid.
+ * We check that the two original reserved fields equal zero because the
+ * version of the common code that shipped with ESX 4.0 and WS 6.5 did so and
+ * will return a RST packet if they aren't set that way. For newer packet
+ * types added after that release we don't do this.
+ */
+#define VSOCK_PACKET_ASSERT(_p)                      \
+   do {                                              \
+      ASSERT((_p));                                  \
+      ASSERT((_p)->type < VSOCK_PACKET_TYPE_MAX);    \
+      if ((_p)->type < VSOCK_PACKET_TYPE_REQUEST2) { \
+         ASSERT(0 == (_p)->proto);                   \
+         ASSERT(0 == (_p)->_reserved2);              \
+      }                                              \
+   } while(0)
 
 typedef enum VSockPacketType {
    VSOCK_PACKET_TYPE_INVALID = 0,   // Invalid type.
-   VSOCK_PACKET_TYPE_REQUEST,       // Connection request.
+   VSOCK_PACKET_TYPE_REQUEST,       // Connection request (WR/WW/READ/WRITE)
    VSOCK_PACKET_TYPE_NEGOTIATE,     // Connection negotiate.
    VSOCK_PACKET_TYPE_OFFER,         // Connection offer queue pair.
    VSOCK_PACKET_TYPE_ATTACH,        // Connection attach.
@@ -59,9 +68,17 @@ typedef enum VSockPacketType {
    VSOCK_PACKET_TYPE_SHUTDOWN,      // Shutdown the connection.
    VSOCK_PACKET_TYPE_WAITING_WRITE, // Notify peer we are waiting to write.
    VSOCK_PACKET_TYPE_WAITING_READ,  // Notify peer we are waiting to read.
+   VSOCK_PACKET_TYPE_REQUEST2,      // Connection request (new proto flags)
+   VSOCK_PACKET_TYPE_NEGOTIATE2,    // Connection request (new proto flags)
    VSOCK_PACKET_TYPE_MAX            // Last message.
 } VSockPacketType;
 
+typedef uint16 VSockProtoVersion;
+#define VSOCK_PROTO_INVALID        0        // Invalid protocol version.
+#define VSOCK_PROTO_PKT_ON_NOTIFY (1 << 0)  // Queuepair inspection proto.
+
+#define VSOCK_PROTO_ALL_SUPPORTED (VSOCK_PROTO_PKT_ON_NOTIFY)
+
 typedef struct VSockWaitingInfo {
    uint64 generation; // Generation of the queue.
    uint64 offset;     // Offset within the queue.
@@ -78,7 +95,8 @@ typedef struct VSockPacket {
    VMCIDatagram dg;          // Datagram header.
    uint8 version;            // Version.
    uint8 type;               // Type of message.
-   uint16 _reserved1;        // Reserved.
+   VSockProtoVersion proto;  // Supported proto versions in CONNECT2 and
+                             // NEGOTIATE2. 0 otherwise.
    uint32 srcPort;           // Source port.
    uint32 dstPort;           // Destination port.
    uint32 _reserved2;        // Reserved.
@@ -121,6 +139,7 @@ VSockPacket_Init(VSockPacket *pkt,        // OUT
                  uint64 size,             // IN
                  uint64 mode,             // IN
                  VSockWaitingInfo *wait,  // IN
+                 VSockProtoVersion proto, // IN
                  VMCIHandle handle)       // IN
 {
    ASSERT(pkt);
@@ -134,7 +153,7 @@ VSockPacket_Init(VSockPacket *pkt,        // OUT
    pkt->type = type;
    pkt->srcPort = src->svm_port;
    pkt->dstPort = dst->svm_port;
-   VSockOS_ClearMemory(&pkt->_reserved1, sizeof pkt->_reserved1);
+   VSockOS_ClearMemory(&pkt->proto, sizeof pkt->proto);
    VSockOS_ClearMemory(&pkt->_reserved2, sizeof pkt->_reserved2);
 
    switch (pkt->type) {
@@ -167,6 +186,12 @@ VSockPacket_Init(VSockPacket *pkt,        // OUT
       ASSERT(wait);
       VSockOS_Memcpy(&pkt->u.wait, wait, sizeof pkt->u.wait);
       break;
+
+   case VSOCK_PACKET_TYPE_REQUEST2:
+   case VSOCK_PACKET_TYPE_NEGOTIATE2:
+      pkt->u.size = size;
+      pkt->proto = proto;
+      break;
    }
 
    VSOCK_PACKET_ASSERT(pkt);
@@ -216,8 +241,11 @@ VSockPacket_Validate(VSockPacket *pkt)
       goto exit;
    }
 
-   if (0 != pkt->_reserved1 || 0 != pkt->_reserved2) {
-      goto exit;
+   /* See the comment above VSOCK_PACKET_ASSERT. */
+   if (pkt->type < VSOCK_PACKET_TYPE_REQUEST2) {
+      if (0 != pkt->proto || 0 != pkt->_reserved2) {
+         goto exit;
+      }
    }
 
    switch (pkt->type) {
@@ -251,7 +279,7 @@ VSockPacket_Validate(VSockPacket *pkt)
    }
 
    err = 0;
-   
+
 exit:
    return sockerr2err(err);
 }
index d6a042c67ca0def701c937ff48ced3d47f4b7c42..07fbbb6f6ead95a6df20470fe32fa259f7eb892b 100644 (file)
@@ -75,4 +75,5 @@
 #define VMNET_CAP_IP6_CSUM      0x80000        /* Can do IPv6 csum offload. */
 #define VMNET_CAP_TSO6         0x100000        /* Can do TSO segmentation offload for IPv6 pkts. */
 #define VMNET_CAP_TSO256k      0x200000        /* Can do TSO segmentation offload for pkts up to 256kB. */
+#define VMNET_CAP_UPT          0x400000        /* Support UPT */
 #endif // _VMNET_DEF_H_
index 7ff08739f6f545ecbf88ad1203ae2b9a94166b2c..9a6334c5929ee6464f9552b9e2fec6edc282a8e5 100644 (file)
@@ -151,7 +151,7 @@ Vmxnet3_TxDesc;
 
 typedef
 #include "vmware_pack_begin.h"
-struct vmxnet3_TxDataDesc {
+struct Vmxnet3_TxDataDesc {
    uint8 data[VMXNET3_HDR_COPY_SIZE];
 }
 #include "vmware_pack_end.h"
@@ -371,7 +371,7 @@ Vmxnet3_MiscConf;
 
 typedef
 #include "vmware_pack_begin.h"
-struct vmxnet3_TxQueueConf {
+struct Vmxnet3_TxQueueConf {
    uint64    txRingBasePA;
    uint64    dataRingBasePA;
    uint64    compRingBasePA;
index ecb16b19a1489c42ae97ca43c71ee583a49366ab..f3badc8423ee8da55480a1a06790dda5bf708e0e 100644 (file)
  *
  *********************************************************/
 
-/* 
+/*
  * os.c --
  *
- *     Wrappers for Solaris system functions required by "vmmemctl".
+ *      Wrappers for Solaris system functions required by "vmmemctl".
  */
 
 /*
@@ -41,6 +41,7 @@
 #include <sys/ksynch.h>
 
 #include "os.h"
+#include "vm_assert.h"
 #include "balloon_def.h"
 #include "vmballoon_kstats.h"
 #include "vmmemctl.h"
@@ -73,7 +74,7 @@ typedef struct {
    kcondvar_t cv;
 
    /* registered state */
-   os_timer_handler handler;
+   OSTimerHandler *handler;
    void *data;
    int period;
 } os_timer;
@@ -104,33 +105,127 @@ typedef struct {
 static os_state global_state;
 static dev_info_t *vmmemctl_dip;       /* only one instance */
 
+
 /*
- * Simple Wrappers
+ *-----------------------------------------------------------------------------
+ *
+ * OS_Malloc --
+ *
+ *      Allocates kernel memory.
+ *
+ * Results:
+ *      On success: Pointer to allocated memory
+ *      On failure: NULL
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
  */
 
-void *os_kmalloc_nosleep(unsigned int size)
+void *
+OS_Malloc(size_t size) // IN
 {
    return (kmem_alloc(size, KM_NOSLEEP));
 }
 
-void os_kfree(void *obj, unsigned int size)
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_Free --
+ *
+ *      Free allocated kernel memory.
+ *
+ * Results:
+ *      None
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+OS_Free(void *ptr,   // IN
+        size_t size) // IN
 {
-   kmem_free(obj, size);
+   kmem_free(ptr, size);
 }
 
-void os_bzero(void *b, unsigned int len)
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_MemZero --
+ *
+ *      Fill a memory location with 0s.
+ *
+ * Results:
+ *      None
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+OS_MemZero(void *ptr,   // OUT
+           size_t size) // IN
 {
-   bzero(b, len);
+   bzero(ptr, size);
 }
 
-void os_memcpy(void *dest, const void *src, unsigned int size)
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_MemCopy --
+ *
+ *      Copy a memory portion into another location.
+ *
+ * Results:
+ *      None
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+OS_MemCopy(void *dest,      // OUT
+           const void *src, // IN
+           size_t size)     // IN
 {
    bcopy(src, dest, size);
 }
 
-int os_sprintf(char *str, const char *format, ...)
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_Snprintf --
+ *
+ *      Print a string into a bounded memory location.
+ *
+ * Results:
+ *      Number of character printed including trailing \0.
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+OS_Snprintf(char *buf,          // OUT
+            size_t size,        // IN
+            const char *format, // IN
+            ...)                // IN
 {
-   ASSERT(0);
+   NOT_REACHED();
    /*
     * XXX disabled because the varargs header file doesn't seem to
     * work in the current (gcc 2.95.3) cross-compiler environment.
@@ -143,7 +238,8 @@ int os_sprintf(char *str, const char *format, ...)
  * System-Dependent Operations
  */
 
-char *os_identity(void)
+const char *
+OS_Identity(void)
 {
    return "solaris";
 }
@@ -153,12 +249,14 @@ char *os_identity(void)
  *
  * Currently we just return the total memory pages.
  */
-unsigned int os_predict_max_balloon_pages(void)
+unsigned int
+OS_PredictMaxReservedPages(void)
 {
    return(maxmem);
 }
 
-unsigned long os_addr_to_ppn(unsigned long addr)
+unsigned long
+OS_AddrToPPN(unsigned long addr)
 {
    return (ulong_t)page_pptonum(((os_page *)addr)->pp);
 }
@@ -184,7 +282,8 @@ unsigned long os_addr_to_ppn(unsigned long addr)
  * interface for allocating physical pages that may allow us to
  * eliminate some of this.
  */
-unsigned long os_alloc_reserved_page(int can_sleep)
+unsigned long
+OS_AllocReservedPage(int canSleep)
 {
    os_state *state = &global_state;
    page_t *pp;
@@ -198,12 +297,12 @@ unsigned long os_alloc_reserved_page(int can_sleep)
    /*
     * Reserve space for the page.
     */
-   flags = can_sleep ? KM_SLEEP : KM_NOSLEEP;
+   flags = canSleep ? KM_SLEEP : KM_NOSLEEP;
    if (!page_resv(1, flags))
       return 0;                /* no space! */
 
    /*
-    * Allocating space for os_page early simplifies error handling. 
+    * Allocating space for os_page early simplifies error handling.
     */
    if ((page = kmem_alloc(sizeof (os_page), flags)) == NULL) {
       page_unresv(1);
@@ -219,7 +318,7 @@ unsigned long os_alloc_reserved_page(int can_sleep)
     * Allocate the page itself.  Note that this can fail.
     */
    kseg.s_as = &kas;
-   flags = can_sleep ? PG_EXCL | PG_WAIT : PG_EXCL;
+   flags = canSleep ? PG_EXCL | PG_WAIT : PG_EXCL;
    pp = page_create_va(vp, off, PAGESIZE, flags, &kseg,
                       (caddr_t)(ulong_t)off);
    if (pp != NULL) {
@@ -245,7 +344,8 @@ unsigned long os_alloc_reserved_page(int can_sleep)
    return (unsigned long)page;
 }
 
-void os_free_reserved_page(unsigned long addr)
+void
+OS_FreeReservedPage(unsigned long addr)
 {
    os_state *state = &global_state;
    os_page *page = (os_page *)addr;
@@ -296,13 +396,16 @@ static int os_worker(void)
 /*
  * Initialize timer data.
  */
-void os_timer_init(os_timer_handler handler, void *data, int period)
+void
+OS_TimerInit(OSTimerHandler *handler, // IN
+             void *clientData,        // IN
+             int period)              // IN
 {
    os_timer *t = &global_state.timer;
 
    t->id = 0;
    t->handler = handler;
-   t->data = data;
+   t->data = clientData;
    t->period = period;
    t->stop = 0;
 
@@ -310,14 +413,16 @@ void os_timer_init(os_timer_handler handler, void *data, int period)
    cv_init(&t->cv, NULL, CV_DRIVER, NULL);
 }
 
-void os_timer_start(void)
+void
+OS_TimerStart(void)
 {
    os_timer *t = &global_state.timer;
 
    t->stop = 0;
 }
 
-void os_timer_stop(void)
+void
+OS_TimerStop(void)
 {
    os_timer *t = &global_state.timer;
 
@@ -340,19 +445,38 @@ static void os_timer_cleanup(void)
    cv_destroy(&timer->cv);
 }
 
-unsigned int os_timer_hz(void)
+unsigned int
+OS_TimerHz(void)
 {
    return drv_usectohz(ONE_SECOND_IN_MICROSECONDS);
 }
 
-void os_yield(void)
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * OS_Yield --
+ *
+ *      Yield the CPU, if needed.
+ *
+ * Results:
+ *      None
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+OS_Yield(void)
 {
    /* Do nothing. */
 }
 
-void os_init(const char *name,
+void OS_Init(const char *name,
              const char *name_verbose,
-             os_status_handler handler)
+             OSStatusHandler *handler)
 {
    os_state *state = &global_state;
    static int initialized = 0;
@@ -381,7 +505,7 @@ void os_init(const char *name,
    cmn_err(CE_CONT, "!%s initialized\n", name_verbose);
 }
 
-void os_cleanup(void)
+void OS_Cleanup(void)
 {
    os_state *state = &global_state;
 
index 7061eabf1fdb243cbf657bb83f6ece240480f5e0..39d5d2a2500e12a74cbf39d2781095c92d1ddc2e 100644 (file)
  *
  *********************************************************/
 
-/* 
+/*
  * os.h --
  *
- *     Definitions for OS-specific wrapper functions required
- *     by "vmmemctl".  This allows customers to build their own
- *     vmmemctl driver for custom versioned kernels without the
- *     need for source code. 
+ *      Definitions for OS-specific wrapper functions required by "vmmemctl".
  */
 
 #ifndef        OS_H
 #define        OS_H
 
-/*
- * Needs fixing for 64bit OSes
- */
-#ifndef __x86_64__
-#define CDECL __attribute__((cdecl, regparm(0)))
-#else
-#define CDECL
-#endif
-
 /*
  * Types
  */
 
-typedef void CDECL (*os_timer_handler)(void *);
-typedef int  CDECL (*os_status_handler)(char *);
+typedef void OSTimerHandler(void *clientData);
+typedef int  OSStatusHandler(char *buf, size_t size);
 
 /*
  * Operations
  */
 
-extern void CDECL *os_kmalloc_nosleep(unsigned int size);
-extern void CDECL os_kfree(void *obj, unsigned int size);
-extern void CDECL os_yield(void);
-extern void CDECL os_bzero(void *s, unsigned int n);
-extern void CDECL os_memcpy(void *dest, const void *src, unsigned int size);
-extern int  CDECL os_sprintf(char *str, const char *format, ...);
-
-extern unsigned long CDECL os_addr_to_ppn(unsigned long addr);
-extern unsigned long CDECL os_alloc_reserved_page(int can_sleep);
-extern void          CDECL os_free_reserved_page(unsigned long page);
+extern void OS_Init(const char *name,
+                    const char *nameVerbose,
+                    OSStatusHandler *handler);
+extern void OS_Cleanup(void);
+extern const char *OS_Identity(void);
 
-extern void CDECL os_timer_init(os_timer_handler handler, void *data, int period);
-extern void CDECL os_timer_start(void);
-extern void CDECL os_timer_stop(void);
+extern void OS_MemZero(void *ptr, size_t size);
+extern void OS_MemCopy(void *dest, const void *src, size_t size);
+extern int  OS_Snprintf(char *buf, size_t size, const char *format, ...);
 
-extern void CDECL os_init(const char *name,
-                          const char *name_verbose,
-                          os_status_handler handler);
-extern void CDECL os_cleanup(void);
+extern void *OS_Malloc(size_t size);
+extern void OS_Free(void *ptr, size_t size);
 
-extern char CDECL *os_identity(void);
+extern void OS_Yield(void);
 
-extern unsigned int CDECL os_predict_max_balloon_pages(void);
+extern unsigned int OS_TimerHz(void);
+extern void OS_TimerInit(OSTimerHandler *handler, void *clientData, int period);
+extern void OS_TimerStart(void);
+extern void OS_TimerStop(void);
 
-extern unsigned int CDECL os_timer_hz(void);
+extern unsigned int  OS_PredictMaxReservedPages(void);
+extern unsigned long OS_AddrToPPN(unsigned long addr);
+extern unsigned long OS_AllocReservedPage(int canSleep);
+extern void          OS_FreeReservedPage(unsigned long page);
 
 #endif  /* OS_H */
index 8e68226a154dfa9fb9fde014bf787d872fcf8473..f2f055878e6ce13699ffaf34c7c29fdf7efb7bc6 100644 (file)
  *
  *********************************************************/
 
-/* 
+/*
  * vmballoon.c --
  *
- *     VMware server physical memory management driver for Unix-ish
- *     (Linux, FreeBSD, Solaris) guests.  The driver acts like a
- *     "balloon" that can be inflated to reclaim physical pages by
- *     reserving them in the guest and invalidating them in the
- *     monitor, freeing up the underlying machine pages so they can
- *     be allocated to other guests.  The balloon can also be
- *     deflated to allow the guest to use more physical memory.
- *     Higher level policies can control the sizes of balloons in VMs
- *     in order to manage physical memory resources.
+ *      VMware physical memory management driver for Unix-ish
+ *      (Linux, FreeBSD, Solaris, Mac OS) guests. The driver acts like
+ *      a "balloon" that can be inflated to reclaim physical pages by
+ *      reserving them in the guest and invalidating them in the
+ *      monitor, freeing up the underlying machine pages so they can
+ *      be allocated to other guests.  The balloon can also be
+ *      deflated to allow the guest to use more physical memory.
+ *      Higher level policies can control the sizes of balloons in VMs
+ *      in order to manage physical memory resources.
  */
 
 #ifdef __cplusplus
@@ -36,12 +36,12 @@ extern "C" {
  * Compile-Time Options
  */
 
-#define        BALLOON_RATE_ADAPT      (1)
+#define BALLOON_RATE_ADAPT      (1)
 
-#define        BALLOON_DEBUG           (1)
-#define        BALLOON_DEBUG_VERBOSE   (0)
+#define BALLOON_DEBUG           (1)
+#define BALLOON_DEBUG_VERBOSE   (0)
 
-#define        BALLOON_STATS
+#define BALLOON_STATS
 #define BALLOON_STATS_PROCFS
 
 /*
@@ -63,38 +63,38 @@ extern "C" {
 #define NULL 0
 #endif
 
-#define        BALLOON_NAME                    "vmmemctl"
-#define        BALLOON_NAME_VERBOSE            "VMware memory control driver"
+#define BALLOON_NAME                    "vmmemctl"
+#define BALLOON_NAME_VERBOSE            "VMware memory control driver"
 
-#define        BALLOON_PROTOCOL_VERSION        (2)
+#define BALLOON_PROTOCOL_VERSION        (2)
 
-#define        BALLOON_CHUNK_PAGES             (1000)
+#define BALLOON_CHUNK_PAGES             (1000)
 
-#define BALLOON_NOSLEEP_ALLOC_MAX      (16384)
+#define BALLOON_NOSLEEP_ALLOC_MAX       (16384)
 
-#define        BALLOON_RATE_ALLOC_MIN          (512)
-#define        BALLOON_RATE_ALLOC_MAX          (2048)
-#define        BALLOON_RATE_ALLOC_INC          (16)
+#define BALLOON_RATE_ALLOC_MIN          (512)
+#define BALLOON_RATE_ALLOC_MAX          (2048)
+#define BALLOON_RATE_ALLOC_INC          (16)
 
-#define        BALLOON_RATE_FREE_MIN           (512)
-#define        BALLOON_RATE_FREE_MAX           (16384)
-#define        BALLOON_RATE_FREE_INC           (16)
+#define BALLOON_RATE_FREE_MIN           (512)
+#define BALLOON_RATE_FREE_MAX           (16384)
+#define BALLOON_RATE_FREE_INC           (16)
 
-#define        BALLOON_ERROR_PAGES             (16)
+#define BALLOON_ERROR_PAGES             (16)
 
-/* 
+/*
  * When guest is under memory pressure, use a reduced page allocation
  * rate for next several cycles.
  */
-#define SLOW_PAGE_ALLOCATION_CYCLES    (4)
+#define SLOW_PAGE_ALLOCATION_CYCLES     (4)
 
-/* 
+/*
  * Move it to bora/public/balloon_def.h later, if needed. Note that
  * BALLOON_PAGE_ALLOC_FAILURE is an internal error code used for
  * distinguishing page allocation failures from monitor-backdoor errors.
  * We use value 1000 because all monitor-backdoor error codes are < 1000.
  */
-#define BALLOON_PAGE_ALLOC_FAILURE     (1000)
+#define BALLOON_PAGE_ALLOC_FAILURE      (1000)
 
 // Maximum number of page allocations without yielding processor
 #define BALLOON_ALLOC_YIELD_THRESHOLD   (1024)
@@ -154,7 +154,7 @@ static Balloon globalBalloon;
 static int BalloonGuestType(void);
 
 static unsigned long BalloonPrimAllocPage(BalloonPageAllocType canSleep);
-static void   BalloonPrimFreePage(unsigned long page);
+static void BalloonPrimFreePage(unsigned long page);
 
 static int  Balloon_AllocPage(Balloon *b, BalloonPageAllocType allocType);
 static int  Balloon_FreePage(Balloon *b, int monitorUnlock);
@@ -163,7 +163,7 @@ static void Balloon_Reset(Balloon *b);
 
 static void Balloon_StartTimer(Balloon *b);
 static void Balloon_StopTimer(Balloon *b);
-static void CDECL Balloon_BH(void *data);
+static void BalloonTimerHandler(void *clientData);
 
 static int Balloon_MonitorStart(Balloon *b);
 static int Balloon_MonitorGuestType(Balloon *b);
@@ -175,51 +175,43 @@ static int Balloon_MonitorUnlockPage(Balloon *b, unsigned long addr);
  * Macros
  */
 
-#ifndef        MIN
-#define        MIN(a, b)       (((a) < (b)) ? (a) : (b))
-#endif
-#ifndef        MAX
-#define        MAX(a, b)       (((a) > (b)) ? (a) : (b))
-#endif
-
-#ifdef BALLOON_STATS
-#define        STATS_INC(stat) (stat)++
+#ifdef  BALLOON_STATS
+#define STATS_INC(stat) (stat)++
 #else
-#define        STATS_INC(stat)
+#define STATS_INC(stat)
 #endif
 
 /*
  * Macros to generate operations for simple lists of OBJ.
  * OBJ must contain next and prev fields.
- * 
  */
 
-#define        GENERATE_LIST_INSERT(OBJ)                       \
-static void OBJ ## _Insert(OBJ **head, OBJ *obj)       \
-{                                                      \
-   OBJ *h = *head;                                     \
-                                                       \
-   /* add element to head of list */                   \
-   obj->next = h;                                      \
-   if (h != NULL) {                                    \
-      h->prev = obj;                                   \
-   }                                                   \
-   *head = obj;                                                \
-   obj->prev = NULL;                                   \
+#define GENERATE_LIST_INSERT(OBJ)                       \
+static void OBJ ## _Insert(OBJ **head, OBJ *obj)        \
+{                                                       \
+   OBJ *h = *head;                                      \
+                                                        \
+   /* add element to head of list */                    \
+   obj->next = h;                                       \
+   if (h != NULL) {                                     \
+      h->prev = obj;                                    \
+   }                                                    \
+   *head = obj;                                         \
+   obj->prev = NULL;                                    \
 }
 
-#define        GENERATE_LIST_REMOVE(OBJ)                       \
-static void OBJ ## _Remove(OBJ **head, OBJ *obj)       \
-{                                                      \
-    /* splice element out of list */                   \
-    if (obj->prev != NULL) {                           \
-      obj->prev->next = obj->next;                     \
-    } else {                                           \
-      *head = obj->next;                               \
-    }                                                  \
-    if (obj->next != NULL) {                           \
-      obj->next->prev = obj->prev;                     \
-    }                                                  \
+#define GENERATE_LIST_REMOVE(OBJ)                       \
+static void OBJ ## _Remove(OBJ **head, OBJ *obj)        \
+{                                                       \
+    /* splice element out of list */                    \
+    if (obj->prev != NULL) {                            \
+      obj->prev->next = obj->next;                      \
+    } else {                                            \
+      *head = obj->next;                                \
+    }                                                   \
+    if (obj->next != NULL) {                            \
+      obj->next->prev = obj->prev;                      \
+    }                                                   \
 }
 
 /*
@@ -233,25 +225,28 @@ GENERATE_LIST_REMOVE(BalloonChunk);
  * Procfs Operations
  */
 
+
 /*
  *----------------------------------------------------------------------
  *
  * BalloonProcRead --
  *
  *      Ballon driver status reporting routine.  Note that this is only
- *     used for Linux.
+ *      used for Linux.
  *
  * Results:
  *      Writes ASCII status information into "buf".
- *     Returns number of bytes written.
+ *      Returns number of bytes written.
  *
  * Side effects:
  *      None.
  *
  *----------------------------------------------------------------------
  */
-static int CDECL
-BalloonProcRead(char *buf)
+
+static int
+BalloonProcRead(char *buf,      // OUT
+                size_t size) // IN
 {
    int len = 0;
    BalloonStats stats;
@@ -259,14 +254,14 @@ BalloonProcRead(char *buf)
    BalloonGetStats(&stats);
 
    /* format size info */
-   len += os_sprintf(buf + len,
+   len += OS_Snprintf(buf + len, size - len,
                      "target:             %8d pages\n"
                      "current:            %8d pages\n",
                      stats.nPagesTarget,
                      stats.nPages);
 
    /* format rate info */
-   len += os_sprintf(buf + len,
+   len += OS_Snprintf(buf + len, size - len,
                      "rateNoSleepAlloc:   %8d pages/sec\n"
                      "rateSleepAlloc:     %8d pages/sec\n"
                      "rateFree:           %8d pages/sec\n",
@@ -274,8 +269,8 @@ BalloonProcRead(char *buf)
                      stats.rateAlloc,
                      stats.rateFree);
 
-#ifdef BALLOON_STATS_PROCFS
-   len += os_sprintf(buf + len,
+#ifdef BALLOON_STATS_PROCFS
+   len += OS_Snprintf(buf + len, size - len,
                      "\n"
                      "timer:              %8u\n"
                      "start:              %8u (%4u failed)\n"
@@ -303,7 +298,7 @@ BalloonProcRead(char *buf)
                      stats.primErrorPageFree);
 #endif
 
-   return(len);
+   return len;
 }
 
 /*
@@ -316,7 +311,7 @@ BalloonProcRead(char *buf)
  * AddrToPPN --
  *
  *      Return the physical page number corresponding to the specified
- *     Linux kernel-mapped address.
+ *      kernel-mapped address.
  *
  * Results:
  *      Returns PPN for "addr".
@@ -329,7 +324,7 @@ BalloonProcRead(char *buf)
 static inline unsigned long
 AddrToPPN(unsigned long addr)
 {
-   return(os_addr_to_ppn(addr));
+   return OS_AddrToPPN(addr);
 }
 
 /*
@@ -339,12 +334,12 @@ AddrToPPN(unsigned long addr)
  *
  *      Attempts to allocate and reserve a physical page.
  *
- *     If canSleep == 1, i.e., BALLOON_PAGE_ALLOC_CANSLEEP:
- *        The allocation can wait (sleep) for page writeout (swap)
- *        by the guest.
- *     otherwise canSleep == 0, i.e., BALLOON_PAGE_ALLOC_NOSLEEP:
- *        If allocation of a page requires disk writeout, then
- *        just fail. DON'T sleep.
+ *      If canSleep == 1, i.e., BALLOON_PAGE_ALLOC_CANSLEEP:
+ *         The allocation can wait (sleep) for page writeout (swap)
+ *         by the guest.
+ *      otherwise canSleep == 0, i.e., BALLOON_PAGE_ALLOC_NOSLEEP:
+ *         If allocation of a page requires disk writeout, then
+ *         just fail. DON'T sleep.
  *
  * Results:
  *      Returns the physical address of the allocated page, or 0 if error.
@@ -357,7 +352,7 @@ AddrToPPN(unsigned long addr)
 static unsigned long
 BalloonPrimAllocPage(BalloonPageAllocType canSleep)
 {
-   return(os_alloc_reserved_page(canSleep));
+   return OS_AllocReservedPage(canSleep);
 }
 
 /*
@@ -378,7 +373,7 @@ BalloonPrimAllocPage(BalloonPageAllocType canSleep)
 static void
 BalloonPrimFreePage(unsigned long page)
 {
-   return(os_free_reserved_page(page));
+   return OS_FreeReservedPage(page);
 }
 
 /*
@@ -387,7 +382,7 @@ BalloonPrimFreePage(unsigned long page)
  * BalloonGuestType --
  *
  *      Return balloon guest OS identifier obtained by parsing
- *     system-dependent identity string.
+ *      system-dependent identity string.
  *
  * Results:
  *      Returns one of BALLOON_GUEST_{LINUX,BSD,SOLARIS,UNKNOWN}.
@@ -400,11 +395,11 @@ BalloonPrimFreePage(unsigned long page)
 static int
 BalloonGuestType(void)
 {
-   char *identity;
+   const char *identity;
 
    /* obtain OS identify string */
-   identity = os_identity();
-   
+   identity = OS_Identity();
+
    /* unknown if not specified */
    if (identity == NULL) {
       return(BALLOON_GUEST_UNKNOWN);
@@ -414,19 +409,19 @@ BalloonGuestType(void)
    switch (identity[0]) {
    case 'l':
    case 'L':
-      return(BALLOON_GUEST_LINUX);
+      return BALLOON_GUEST_LINUX;
    case 'b':
    case 'B':
-      return(BALLOON_GUEST_BSD);
+      return BALLOON_GUEST_BSD;
    case 's':
    case 'S':
-      return(BALLOON_GUEST_SOLARIS);
+      return BALLOON_GUEST_SOLARIS;
    default:
       break;
    }
 
    /* unknown */
-   return(BALLOON_GUEST_UNKNOWN);
+   return BALLOON_GUEST_UNKNOWN;
 }
 
 /*
@@ -441,7 +436,7 @@ void BalloonGetStats(BalloonStats *stats)
    /*
     * Copy statistics out of global structure.
     */
-   os_memcpy(stats, &b->stats, sizeof (BalloonStats));
+   OS_MemCopy(stats, &b->stats, sizeof (BalloonStats));
 
    /*
     * Fill in additional information about size and rates, which is
@@ -463,37 +458,41 @@ void BalloonGetStats(BalloonStats *stats)
  * BalloonChunk_Create --
  *
  *      Creates a new BalloonChunk object capable of tracking
- *     BALLOON_CHUNK_PAGES PPNs.
+ *      BALLOON_CHUNK_PAGES PPNs.
  *
- *     We do not bother to define two versions (NOSLEEP and CANSLEEP)
- *     of os_kmalloc because Chunk_Create does not require a new page
- *     often.
+ *      We do not bother to define two versions (NOSLEEP and CANSLEEP)
+ *      of OS_Malloc because Chunk_Create does not require a new page
+ *      often.
  *
  * Results:
- *      Returns initialized BalloonChunk, or NULL if error.
+ *      On success: initialized BalloonChunk
+ *      On failure: NULL
  *
  * Side effects:
- *      None.
+ *      None
  *
  *----------------------------------------------------------------------
  */
+
 static BalloonChunk *
 BalloonChunk_Create(void)
 {
    BalloonChunk *chunk;
 
    /* allocate memory, fail if unable */
-   if ((chunk = (BalloonChunk *) os_kmalloc_nosleep(sizeof(BalloonChunk))) == NULL) {
-      return(NULL);
+   chunk = OS_Malloc(sizeof *chunk);
+   if (chunk == NULL) {
+      return NULL;
    }
 
    /* initialize */
-   os_bzero(chunk, sizeof(BalloonChunk));
+   OS_MemZero(chunk, sizeof *chunk);
 
    /* everything OK */
-   return(chunk);
+   return chunk;
 }
 
+
 /*
  *----------------------------------------------------------------------
  *
@@ -513,7 +512,7 @@ static void
 BalloonChunk_Destroy(BalloonChunk *chunk)
 {
    /* reclaim storage */
-   os_kfree(chunk, sizeof (BalloonChunk));
+   OS_Free(chunk, sizeof *chunk);
 }
 
 /*
@@ -540,7 +539,7 @@ static int
 Balloon_Init(Balloon *b)
 {
    /* clear state */
-   os_bzero(b, sizeof(Balloon));
+   OS_MemZero(b, sizeof *b);
 
    /* initialize rates */
    b->rateAlloc = BALLOON_RATE_ALLOC_MAX;
@@ -578,7 +577,7 @@ Balloon_Deallocate(Balloon *b)
       (void) Balloon_FreePage(b, FALSE);
       if (++cnt >= b->rateFree) {
          cnt = 0;
-         os_yield();
+         OS_Yield();
       }
    }
 }
@@ -589,7 +588,7 @@ Balloon_Deallocate(Balloon *b)
  * Balloon_Reset --
  *
  *      Resets balloon "b" to empty state.  Frees all allocated pages
- *     and attempts to reset contact with the monitor. 
+ *      and attempts to reset contact with the monitor.
  *
  * Results:
  *      None.
@@ -621,12 +620,12 @@ Balloon_Reset(Balloon *b)
 /*
  *----------------------------------------------------------------------
  *
- * Balloon_BH --
+ * BalloonTimerHandler --
  *
  *      Balloon bottom half handler.  Contacts monitor via backdoor
- *     to obtain balloon size target, and starts adjusting balloon
- *     size to achieve target by allocating or deallocating pages.
- *     Resets balloon if requested by the monitor.
+ *      to obtain balloon size target, and starts adjusting balloon
+ *      size to achieve target by allocating or deallocating pages.
+ *      Resets balloon if requested by the monitor.
  *
  * Results:
  *      None.
@@ -636,10 +635,10 @@ Balloon_Reset(Balloon *b)
  *
  *----------------------------------------------------------------------
  */
-static void CDECL
-Balloon_BH(void *data)
+static void
+BalloonTimerHandler(void *clientData)
 {
-   Balloon *b = (Balloon *) data;
+   Balloon *b = (Balloon *) clientData;
    uint32 target;
    int status;
 
@@ -677,14 +676,14 @@ Balloon_BH(void *data)
  *      None.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
 static void
 Balloon_StartTimer(Balloon *b)
 {
-   os_timer_start();
+   OS_TimerStart();
 }
 
 /*
@@ -698,14 +697,14 @@ Balloon_StartTimer(Balloon *b)
  *      None.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
 static void
 Balloon_StopTimer(Balloon *b)
 {
-   os_timer_stop();
+   OS_TimerStop();
 }
 
 
@@ -715,14 +714,14 @@ Balloon_StopTimer(Balloon *b)
  * Balloon_ErrorPagesAlloc --
  *
  *      Attempt to add "page" to list of non-balloonable pages
- *     associated with "b".
+ *      associated with "b".
  *
  * Results:
- *      Returns BALLOON_SUCCESS iff successful, or BALLOON_FAILURE
- *     if non-balloonable page list is already full.
+ *      On success: BALLOON_SUCCESS
+ *      On failure: BALLOON_FAILURE (non-balloonable page list is already full)
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -747,13 +746,13 @@ Balloon_ErrorPagesAlloc(Balloon *b, unsigned long page)
  * Balloon_ErrorPagesFree --
  *
  *      Deallocates all pages on the list of non-balloonable pages
- *     associated with "b".
+ *      associated with "b".
  *
  * Results:
- *     None.
+ *      None.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -764,7 +763,7 @@ Balloon_ErrorPagesFree(Balloon *b)
 
    /* free all non-balloonable "error" pages */
    for (i = 0; i < b->errors.nextPage; i++) {
-      BalloonPrimFreePage(b->errors.page[i]);      
+      BalloonPrimFreePage(b->errors.page[i]);
       b->errors.page[i] = 0;
       STATS_INC(b->stats.primErrorPageFree);
    }
@@ -777,13 +776,13 @@ Balloon_ErrorPagesFree(Balloon *b)
  * Balloon_AllocPage --
  *
  *      Attempts to allocate a physical page, inflating balloon "b".
- *     Informs monitor of PPN for allocated page via backdoor.
+ *      Informs monitor of PPN for allocated page via backdoor.
  *
  * Results:
  *      Returns BALLOON_SUCCESS if successful, otherwise error code.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -852,14 +851,14 @@ Balloon_AllocPage(Balloon *b, BalloonPageAllocType allocType)
  * Balloon_FreePage --
  *
  *      Attempts to deallocate a physical page, deflating balloon "b".
- *     Informs monitor of PPN for deallocated page via backdoor if
- *     "monitorUnlock" is specified.
+ *      Informs monitor of PPN for deallocated page via backdoor if
+ *      "monitorUnlock" is specified.
  *
  * Results:
  *      Returns BALLOON_SUCCESS if successful, otherwise error code.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -927,15 +926,15 @@ Balloon_FreePage(Balloon *b, int monitorUnlock)
  *
  * BalloonDecreaseRateAlloc --
  *
- *     Wrapper to quickly reduce the page allocation rate. This function
- *     is called only when a CANSLEEP allocation fails. This implies severe 
- *     memory pressure inside the guest, so quickly decrease the rateAlloc.
+ *      Wrapper to quickly reduce the page allocation rate. This function
+ *      is called only when a CANSLEEP allocation fails. This implies severe
+ *      memory pressure inside the guest, so quickly decrease the rateAlloc.
  *
  * Results:
  *      None.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -952,27 +951,27 @@ BalloonDecreaseRateAlloc(Balloon *b)
  *
  * BalloonIncreaseRateAlloc --
  *
- *     Wrapper to increase the page allocation rate. 
+ *      Wrapper to increase the page allocation rate.
  *
- *     This function is called when the balloon target is met or
- *     b->rateAlloc (or more) pages have been successfully allocated.
- *     This implies that the guest may not be under high memory 
- *     pressure. So let us increase the rateAlloc.
+ *      This function is called when the balloon target is met or
+ *      b->rateAlloc (or more) pages have been successfully allocated.
+ *      This implies that the guest may not be under high memory
+ *      pressure. So let us increase the rateAlloc.
  *
- *     If meeting balloon target requires less than b->rateAlloc
- *     pages, then we do not change the page allocation rate.
+ *      If meeting balloon target requires less than b->rateAlloc
+ *      pages, then we do not change the page allocation rate.
  *
- *     If the number of pages successfully allocated (nAlloc) is far
- *     higher than b->rateAlloc, then it implies that NOSLEEP 
- *     allocations are highly successful. Therefore, we predict that
- *     the guest is under no memory pressure, and so increase
- *     b->rateAlloc quickly.
+ *      If the number of pages successfully allocated (nAlloc) is far
+ *      higher than b->rateAlloc, then it implies that NOSLEEP
+ *      allocations are highly successful. Therefore, we predict that
+ *      the guest is under no memory pressure, and so increase
+ *      b->rateAlloc quickly.
  *
  * Results:
  *      None.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -981,7 +980,7 @@ BalloonIncreaseRateAlloc(Balloon *b, uint32 nAlloc)
 {
    if (BALLOON_RATE_ADAPT) {
       if (nAlloc >= b->rateAlloc) {
-         uint32 mult = nAlloc / b->rateAlloc; 
+         uint32 mult = nAlloc / b->rateAlloc;
          b->rateAlloc = MIN(b->rateAlloc + mult * BALLOON_RATE_ALLOC_INC,
                             BALLOON_RATE_ALLOC_MAX);
       }
@@ -999,7 +998,7 @@ BalloonIncreaseRateAlloc(Balloon *b, uint32 nAlloc)
  *      Returns BALLOON_SUCCESS if successful, otherwise error code.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -1009,7 +1008,7 @@ BalloonInflate(Balloon *b, uint32 target)
    int status, allocations = 0;
    uint32 i, nAllocNoSleep, nAllocCanSleep;
 
-   /* 
+   /*
     * First try NOSLEEP page allocations to inflate balloon.
     *
     * If we do not throttle nosleep allocations, we can drain all
@@ -1017,10 +1016,10 @@ BalloonInflate(Balloon *b, uint32 target)
     * As a side-effect, draining free pages helps to inform (force)
     * the guest to start swapping if balloon target is not met yet,
     * which is a desired behavior. However, balloon driver can consume
-    * all available CPU cycles if too many pages are allocated in a 
-    * second. Therefore, we throttle nosleep allocations even when 
-    * the guest is not under memory pressure. OTOH, if we have already 
-    * predicted that the guest is under memory pressure, then we 
+    * all available CPU cycles if too many pages are allocated in a
+    * second. Therefore, we throttle nosleep allocations even when
+    * the guest is not under memory pressure. OTOH, if we have already
+    * predicted that the guest is under memory pressure, then we
     * slowdown page allocations considerably.
     */
    if (b->slowPageAllocationCycles > 0) {
@@ -1034,16 +1033,16 @@ BalloonInflate(Balloon *b, uint32 target)
       status = Balloon_AllocPage(b, BALLOON_PAGE_ALLOC_NOSLEEP);
       if (status != BALLOON_SUCCESS) {
          if (status != BALLOON_PAGE_ALLOC_FAILURE) {
-            /* 
+            /*
              * Not a page allocation failure, so release non-balloonable
              * pages, and fail.
              */
             Balloon_ErrorPagesFree(b);
             return(status);
          }
-         /* 
-          * NOSLEEP page allocation failed, so the guest is under memory 
-          * pressure. Let us slowdown page allocations for next few 
+         /*
+          * NOSLEEP page allocation failed, so the guest is under memory
+          * pressure. Let us slowdown page allocations for next few
           * cycles so that the guest gets out of memory pressure.
           */
          b->slowPageAllocationCycles = SLOW_PAGE_ALLOCATION_CYCLES;
@@ -1051,12 +1050,12 @@ BalloonInflate(Balloon *b, uint32 target)
       }
 
       if (++allocations > BALLOON_ALLOC_YIELD_THRESHOLD) {
-         os_yield();
+         OS_Yield();
          allocations = 0;
       }
    }
 
-   /* 
+   /*
     * Check whether nosleep allocation successfully zapped nAllocNoSleep
     * pages.
     */
@@ -1066,7 +1065,7 @@ BalloonInflate(Balloon *b, uint32 target)
       Balloon_ErrorPagesFree(b);
       return(BALLOON_SUCCESS);
    } else {
-      /* 
+      /*
        * NOSLEEP allocation failed, so the guest is under memory pressure.
        * If already b->rateAlloc pages were zapped, then succeed. Otherwise,
        * try CANSLEEP allocation.
@@ -1082,14 +1081,14 @@ BalloonInflate(Balloon *b, uint32 target)
       }
    }
 
-   /* 
+   /*
     * Use CANSLEEP page allocation to inflate balloon if below target.
     *
     * Sleep allocations are required only when nosleep allocation fails.
     * This implies that the guest is already under memory pressure, so
     * let us always throttle canSleep allocations. The total number pages
-    * allocated using noSleep and canSleep methods is throttled at 
-    * b->rateAlloc per second when the guest is under memory pressure. 
+    * allocated using noSleep and canSleep methods is throttled at
+    * b->rateAlloc per second when the guest is under memory pressure.
     */
    nAllocCanSleep = target - b->nPages;
    nAllocCanSleep = MIN(nAllocCanSleep, b->rateAlloc - nAllocNoSleep);
@@ -1099,7 +1098,7 @@ BalloonInflate(Balloon *b, uint32 target)
       status = Balloon_AllocPage(b, BALLOON_PAGE_ALLOC_CANSLEEP);
       if(status != BALLOON_SUCCESS) {
          if (status == BALLOON_PAGE_ALLOC_FAILURE) {
-            /* 
+            /*
              * CANSLEEP page allocation failed, so guest is under severe
              * memory pressure. Quickly decrease rateAlloc.
              */
@@ -1111,17 +1110,17 @@ BalloonInflate(Balloon *b, uint32 target)
       }
 
       if (++allocations > BALLOON_ALLOC_YIELD_THRESHOLD) {
-         os_yield();
+         OS_Yield();
          allocations = 0;
       }
    }
 
-   /* 
+   /*
     * Either met the balloon target or b->rateAlloc pages have been
     * successfully zapped.
     */
    BalloonIncreaseRateAlloc(b, nAllocNoSleep + nAllocCanSleep);
-                            
+
    /* release non-balloonable pages, succeed */
    Balloon_ErrorPagesFree(b);
    return(BALLOON_SUCCESS);
@@ -1138,7 +1137,7 @@ BalloonInflate(Balloon *b, uint32 target)
  *      Returns BALLOON_SUCCESS if successful, otherwise error code.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -1147,7 +1146,7 @@ BalloonDeflate(Balloon *b, uint32 target)
 {
    int status, i;
    uint32 nFree = b->nPages - target;
-      
+
    /* limit deallocation rate */
    nFree = MIN(nFree, b->rateFree);
 
@@ -1171,20 +1170,20 @@ BalloonDeflate(Balloon *b, uint32 target)
    /* everything OK */
    return(BALLOON_SUCCESS);
 }
+
 /*
  *----------------------------------------------------------------------
  *
  * Balloon_AdjustSize --
  *
  *      Attempts to allocate or deallocate physical pages in order
- *     to reach desired "target" size for balloon "b".
+ *      to reach desired "target" size for balloon "b".
  *
  * Results:
  *      Returns BALLOON_SUCCESS if successful, otherwise error code.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -1222,10 +1221,10 @@ Balloon_AdjustSize(Balloon *b, uint32 target)
  *      Attempts to contact monitor via backdoor to begin operation.
  *
  * Results:
- *     Returns BALLOON_SUCCESS if successful, otherwise error code.
+ *      Returns BALLOON_SUCCESS if successful, otherwise error code.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -1264,10 +1263,10 @@ Balloon_MonitorStart(Balloon *b)
  *      Attempts to contact monitor and report guest OS identity.
  *
  * Results:
- *     Returns BALLOON_SUCCESS if successful, otherwise error code.
+ *      Returns BALLOON_SUCCESS if successful, otherwise error code.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -1309,24 +1308,24 @@ Balloon_MonitorGuestType(Balloon *b)
  * Balloon_MonitorGetTarget --
  *
  *      Attempts to contact monitor via backdoor to obtain desired
- *     balloon size.
+ *      balloon size.
  *
- *     Predicts the maximum achievable balloon size and sends it 
- *     to vmm => vmkernel via vEbx register.
+ *      Predicts the maximum achievable balloon size and sends it
+ *      to vmm => vmkernel via vEbx register.
  *
- *     os_predict_max_balloon_pages() returns either predicted max balloon
- *     pages or BALLOON_MAX_SIZE_USE_CONFIG. In the later scenario,
- *     vmkernel uses global config options for determining a guest's max
- *     balloon size. Note that older vmballoon drivers set vEbx to 
- *     BALLOON_MAX_SIZE_USE_CONFIG, i.e., value 0 (zero). So vmkernel
- *     will fallback to config-based max balloon size estimation.
+ *      OS_PredictMaxReservedPages() returns either predicted max balloon
+ *      pages or BALLOON_MAX_SIZE_USE_CONFIG. In the later scenario,
+ *      vmkernel uses global config options for determining a guest's max
+ *      balloon size. Note that older vmballoon drivers set vEbx to
+ *      BALLOON_MAX_SIZE_USE_CONFIG, i.e., value 0 (zero). So vmkernel
+ *      will fallback to config-based max balloon size estimation.
  *
  * Results:
- *     If successful, sets "target" to value obtained from monitor,
+ *      If successful, sets "target" to value obtained from monitor,
  *      and returns BALLOON_SUCCESS. Otherwise returns error code.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -1338,7 +1337,7 @@ Balloon_MonitorGetTarget(Balloon *b, uint32 *target)
 
    /* prepare backdoor args */
    bp.in.cx.halfs.low = BALLOON_BDOOR_CMD_TARGET;
-   bp.in.size = os_predict_max_balloon_pages();
+   bp.in.size = OS_PredictMaxReservedPages();
 
    /* invoke backdoor */
    Backdoor_Balloon(&bp);
@@ -1367,14 +1366,14 @@ Balloon_MonitorGetTarget(Balloon *b, uint32 *target)
  *
  * Balloon_MonitorLockPage --
  *
- *      Attempts to contact monitor and add PPN containing "addr" 
- *     to set of "balloon locked" pages.
+ *      Attempts to contact monitor and add PPN containing "addr"
+ *      to set of "balloon locked" pages.
  *
  * Results:
- *     Returns BALLOON_SUCCESS if successful, otherwise error code.
+ *      Returns BALLOON_SUCCESS if successful, otherwise error code.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -1426,14 +1425,14 @@ Balloon_MonitorLockPage(Balloon *b, unsigned long addr)
  *
  * Balloon_MonitorUnlockPage --
  *
- *      Attempts to contact monitor and remove PPN containing "addr" 
- *     from set of "balloon locked" pages.
+ *      Attempts to contact monitor and remove PPN containing "addr"
+ *      from set of "balloon locked" pages.
  *
  * Results:
- *     Returns BALLOON_SUCCESS if successful, otherwise error code.
+ *      Returns BALLOON_SUCCESS if successful, otherwise error code.
  *
  * Side effects:
- *     None.
+ *      None.
  *
  *----------------------------------------------------------------------
  */
@@ -1495,18 +1494,18 @@ BalloonModuleInit(void)
       return(BALLOON_FAILURE);
    }
 
+   /* os-specific initialization */
+   OS_Init(BALLOON_NAME, BALLOON_NAME_VERBOSE, BalloonProcRead);
+
    /* initialize global state */
    Balloon_Init(b);
 
-   /* os-specific initialization */
-   os_init(BALLOON_NAME, BALLOON_NAME_VERBOSE, BalloonProcRead);
-   os_timer_init(Balloon_BH, (void *) b, os_timer_hz());
-
    /* start timer */
+   OS_TimerInit(BalloonTimerHandler, b, OS_TimerHz());
    Balloon_StartTimer(b);
 
    /* everything OK */
-   return(BALLOON_SUCCESS);
+   return BALLOON_SUCCESS;
 }
 
 static void
@@ -1526,8 +1525,8 @@ BalloonModuleCleanup(void)
    Balloon_Deallocate(b);
 
    /* os-specific cleanup */
-   os_cleanup();
-}   
+   OS_Cleanup();
+}
 
 int init_module(void)
 {
index 4adb1f06e18462faffb64dca0f8aafe45c338a43..c860b0fe6b0600495694b9f07a1c272f6a958c3b 100644 (file)
 #include <math.h>
 #include <limits.h>
 
+#ifndef WIN32
+#   include <arpa/inet.h>
+#endif
+
 #include "vmware.h"
 #include "buildNumber.h"
 #include "conf.h"
@@ -70,7 +74,7 @@ VM_EMBED_VERSION(VMTOOLSD_VERSION_STRING);
 
 typedef struct _GuestInfoCache{
    char value[INFO_MAX][MAX_VALUE_LEN]; /* Stores values of all key-value pairs. */
-   GuestNicList  nicInfo;
+   NicInfoV3     *nicInfo;
    GuestDiskInfo diskInfo;
 } GuestInfoCache;
 
@@ -89,10 +93,10 @@ static Bool vmResumed;
 static Bool GuestInfoUpdateVmdb(ToolsAppCtx *ctx, GuestInfoType infoType, void *info);
 static Bool SetGuestInfo(ToolsAppCtx *ctx, GuestInfoType key,
                          const char *value, char delimiter);
-static Bool NicInfoChanged(GuestNicList *nicInfo);
+static Bool NicInfoChanged(NicInfoV3 *nicInfo);
 static Bool DiskInfoChanged(PGuestDiskInfo diskInfo);
 static void GuestInfoClearCache(void);
-static int PrintNicInfo(GuestNicList *nicInfo, int (*PrintFunc)(const char *, ...));
+static GuestNicList *NicInfoV3ToV2(const NicInfoV3 *infoV3);
 
 
 /**
@@ -302,7 +306,7 @@ GuestInfoGather(gpointer data)
    char osNameFull[MAX_VALUE_LEN];
    char osName[MAX_VALUE_LEN];
    gboolean disableQueryDiskInfo;
-   GuestNicList nicInfo;
+   NicInfoV3 *nicInfo = NULL;
    GuestDiskInfo diskInfo;
 #if defined(_WIN32) || defined(linux)
    GuestMemInfo vmStats = {0};
@@ -311,8 +315,6 @@ GuestInfoGather(gpointer data)
 
    g_debug("Entered guest info gather.\n");
 
-   memset(&nicInfo, 0, sizeof nicInfo);
-
    /* Send tools version. */
    if (!GuestInfoUpdateVmdb(ctx, INFO_BUILD_NUMBER, BUILD_NUMBER)) {
       /*
@@ -364,20 +366,20 @@ GuestInfoGather(gpointer data)
    /* Get NIC information. */
    if (!GuestInfo_GetNicInfo(&nicInfo)) {
       g_warning("Failed to get nic info.\n");
-   } else if (NicInfoChanged(&nicInfo)) {
-      if (GuestInfoUpdateVmdb(ctx, INFO_IPADDRESS, &nicInfo)) {
+   } else if (NicInfoChanged(nicInfo)) {
+      if (GuestInfoUpdateVmdb(ctx, INFO_IPADDRESS, nicInfo)) {
          /*
           * Update the cache. Release the memory previously used by the cache,
           * and copy the new information into the cache.
           */
-         VMX_XDR_FREE(xdr_GuestNicList, &gInfoCache.nicInfo);
+         GuestInfo_FreeNicInfo(gInfoCache.nicInfo);
          gInfoCache.nicInfo = nicInfo;
       } else {
          g_warning("Failed to update VMDB.\n");
       }
    } else {
       g_debug("Nic info not changed.\n");
-      VMX_XDR_FREE(xdr_GuestNicList, &nicInfo);
+      GuestInfo_FreeNicInfo(nicInfo);
    }
 
    /* Send the uptime to VMX so that it can detect soft resets. */
@@ -419,17 +421,15 @@ GuestInfoGather(gpointer data)
  *----------------------------------------------------------------------
  */
 
-Bool
-GuestInfoConvertNicInfoToNicInfoV1(GuestNicList *info,        // IN
+void
+GuestInfoConvertNicInfoToNicInfoV1(NicInfoV3 *info,           // IN
                                    GuestNicInfoV1 *infoV1)    // OUT
 {
    uint32 maxNics;
    u_int i;
 
-   if ((NULL == info) ||
-       (NULL == infoV1)) {
-      return FALSE;
-   }
+   ASSERT(info);
+   ASSERT(infoV1);
 
    maxNics = MIN(info->nics.nics_len, MAX_NICS);
    infoV1->numNicEntries = maxNics;
@@ -440,7 +440,7 @@ GuestInfoConvertNicInfoToNicInfoV1(GuestNicList *info,        // IN
    XDRUTIL_FOREACH(i, info, nics) {
       u_int j;
       uint32 maxIPs;
-      GuestNic *nic = XDRUTIL_GETITEM(info, nics, i);
+      GuestNicV3 *nic = XDRUTIL_GETITEM(info, nics, i);
 
       Str_Strcpy(infoV1->nicList[i].macAddress,
                  nic->macAddress,
@@ -450,18 +450,20 @@ GuestInfoConvertNicInfoToNicInfoV1(GuestNicList *info,        // IN
       infoV1->nicList[i].numIPs = 0;
 
       XDRUTIL_FOREACH(j, nic, ips) {
-         VmIpAddress *ip = XDRUTIL_GETITEM(nic, ips, j);
+         IpAddressEntry *ip = XDRUTIL_GETITEM(nic, ips, j);
+         TypedIpAddress *typedIp = &ip->ipAddressAddr;
+
+         if (typedIp->ipAddressAddrType != IAT_IPV4) {
+            continue;
+         }
 
-         if (strlen(ip->ipAddress) < sizeof infoV1->nicList[i].ipAddress[j]) {
-            Str_Strcpy(infoV1->nicList[i].ipAddress[j],
-                       ip->ipAddress,
-                       sizeof infoV1->nicList[i].ipAddress[j]);
+         if (NetUtil_InetNToP(AF_INET, typedIp->ipAddressAddr.InetAddress_val,
+                              infoV1->nicList[i].ipAddress[j],
+                              sizeof infoV1->nicList[i].ipAddress[j])) {
             infoV1->nicList[i].numIPs++;
             if (infoV1->nicList[i].numIPs == maxIPs) {
                break;
             }
-         } else {
-            g_debug("Ignoring IPV6 address for compatibility.\n");
          }
       }
 
@@ -472,8 +474,6 @@ GuestInfoConvertNicInfoToNicInfoV1(GuestNicList *info,        // IN
          break;
       }
    }
-
-   return TRUE;
 }
 
 
@@ -538,72 +538,104 @@ GuestInfoUpdateVmdb(ToolsAppCtx *ctx,       // IN: Application context
 
    case INFO_IPADDRESS:
       {
-         static Bool isCmdV1 = FALSE;
+         static NicInfoVersion supportedVersion = NIC_INFO_V3;
+         NicInfoV3 *nicInfoV3 = (NicInfoV3 *)info;
          char *reply = NULL;
          size_t replyLen;
          Bool status;
 
-         if (FALSE == isCmdV1) {
-            /* 13 = max size of string representation of an int + 3 spaces. */
-            char request[sizeof GUEST_INFO_COMMAND + 13];
-            GuestNicProto message;
-            XDR xdrs;
-
-            if (DynXdr_Create(&xdrs) == NULL) {
-               return FALSE;
-            }
+nicinfo_fsm:
+         switch (supportedVersion) {
+         case NIC_INFO_V3:
+         case NIC_INFO_V2:
+            {
+               /*
+                * 13 = max size of string representation of an int + 3 spaces.
+                * XXX Ditch the magic numbers.
+                */
+               char request[sizeof GUEST_INFO_COMMAND + 13];
+               GuestNicProto message = {0};
+               GuestNicList *nicList = NULL;
+               NicInfoVersion fallbackVersion;
+               XDR xdrs;
+
+               if (DynXdr_Create(&xdrs) == NULL) {
+                  return FALSE;
+               }
 
-            /* Add the RPC preamble: message name, and type. */
-            Str_Sprintf(request, sizeof request, "%s  %d ",
-                        GUEST_INFO_COMMAND, INFO_IPADDRESS_V2);
+               /* Add the RPC preamble: message name, and type. */
+               Str_Sprintf(request, sizeof request, "%s  %d ",
+                           GUEST_INFO_COMMAND, INFO_IPADDRESS_V2);
+
+               /*
+                * Fill in message according to the version we'll attempt.  Also
+                * note which version we'll fall back to should the VMX reject
+                * our update.
+                */
+               if (supportedVersion == NIC_INFO_V3) {
+                  message.ver = NIC_INFO_V3;
+                  message.GuestNicProto_u.nicInfoV3 = nicInfoV3;
+
+                  fallbackVersion = NIC_INFO_V2;
+               } else {
+                  nicList = NicInfoV3ToV2(nicInfoV3);
+                  message.ver = NIC_INFO_V2;
+                  message.GuestNicProto_u.nicsV2 = nicList;
+
+                  fallbackVersion = NIC_INFO_V1;
+               }
 
-            message.ver = NIC_INFO_V2;
-            message.GuestNicProto_u.nicsV2 = info;
+               /* Write preamble and serialized nic info to XDR stream. */
+               if (!DynXdr_AppendRaw(&xdrs, request, strlen(request)) ||
+                   !xdr_GuestNicProto(&xdrs, &message)) {
+                  g_warning("Error serializing nic info v2 data.");
+                  DynXdr_Destroy(&xdrs, TRUE);
+                  return FALSE;
+               }
 
-            /* Write preamble and serialized nic info to XDR stream. */
-            if (!DynXdr_AppendRaw(&xdrs, request, strlen(request)) ||
-                !xdr_GuestNicProto(&xdrs, &message)) {
-               g_warning("Error serializing nic info v2 data.");
+               status = RpcChannel_Send(ctx->rpc,
+                                        DynXdr_Get(&xdrs),
+                                        xdr_getpos(&xdrs),
+                                        &reply,
+                                        &replyLen);
                DynXdr_Destroy(&xdrs, TRUE);
-               return FALSE;
-            }
 
-            status = RpcChannel_Send(ctx->rpc,
-                                     DynXdr_Get(&xdrs),
-                                     xdr_getpos(&xdrs),
-                                     &reply,
-                                     &replyLen);
-            DynXdr_Destroy(&xdrs, TRUE);
-            if (!status) {
-               g_warning("Failed to send V2 nic info message.\n");
-            }
+               if (nicList) {
+                  free(nicList);
+                  nicList = NULL;
+               }
 
-            if (g_key_file_get_boolean(ctx->config, "guestinfo", "printNicInfo", NULL)) {
-               PrintNicInfo((GuestNicList *) info,
-                            (int (*)(const char *fmt, ...)) RpcVMX_Log);
+               if (!status) {
+                  g_warning("NicInfo update failed: version %u, reply \"%s\".\n",
+                            supportedVersion, reply);
+                  supportedVersion = fallbackVersion;
+                  vm_free(reply);
+                  reply = NULL;
+                  goto nicinfo_fsm;
+               }
             }
-         } else {
-            status = FALSE;
-         }
-         if (!status) {
-            /*
-             * Could be that we are talking to the old protocol that GuestNicInfo is
-             * still fixed size.  Another try to send the fixed sized Nic info.
-             */
-            char request[sizeof (GuestNicInfoV1) + sizeof GUEST_INFO_COMMAND +
+            break;
+
+         case NIC_INFO_V1:
+            {
+               /*
+                * Could be that we are talking to the old protocol that
+                * GuestNicInfo is still fixed size.  Another try to send the
+                * fixed sized Nic info.
+                */
+               char request[sizeof (GuestNicInfoV1) + sizeof GUEST_INFO_COMMAND +
                          2 +                 /* 2 bytes are for digits of infotype. */
                          3 * sizeof (char)]; /* 3 spaces */
-            GuestNicInfoV1 nicInfo;
+               GuestNicInfoV1 nicInfo;
+
+               Str_Sprintf(request,
+                           sizeof request,
+                           "%s  %d ",
+                           GUEST_INFO_COMMAND,
+                           INFO_IPADDRESS);
+
+               GuestInfoConvertNicInfoToNicInfoV1(nicInfoV3, &nicInfo);
 
-            vm_free(reply);
-            reply = NULL;
-
-            Str_Sprintf(request,
-                        sizeof request,
-                        "%s  %d ",
-                        GUEST_INFO_COMMAND,
-                        INFO_IPADDRESS);
-            if (GuestInfoConvertNicInfoToNicInfoV1(info, &nicInfo)) {
                memcpy(request + strlen(request),
                       &nicInfo,
                       sizeof(GuestNicInfoV1));
@@ -617,15 +649,16 @@ GuestInfoUpdateVmdb(ToolsAppCtx *ctx,       // IN: Application context
                                         &replyLen);
 
                g_debug("Just sent fixed sized nic info message.\n");
+
                if (!status) {
                   g_debug("Failed to update fixed sized nic information\n");
                   vm_free(reply);
                   return FALSE;
                }
-               isCmdV1 = TRUE;
-            } else {
-               return FALSE;
             }
+            break;
+         default:
+            NOT_REACHED();
          }
 
          g_debug("Updated new NIC information\n");
@@ -831,14 +864,14 @@ SetGuestInfo(ToolsAppCtx *ctx,   // IN: application context
  *-----------------------------------------------------------------------------
  */
 
-GuestNic *
-GuestInfoFindMacAddress(GuestNicList *nicInfo,  // IN/OUT
+GuestNicV3 *
+GuestInfoFindMacAddress(NicInfoV3 *nicInfo,     // IN/OUT
                         const char *macAddress) // IN
 {
    u_int i;
 
    for (i = 0; i < nicInfo->nics.nics_len; i++) {
-      GuestNic *nic = &nicInfo->nics.nics_val[i];
+      GuestNicV3 *nic = &nicInfo->nics.nics_val[i];
       if (strncmp(nic->macAddress, macAddress, NICINFO_MAC_LEN) == 0) {
          return nic;
       }
@@ -868,10 +901,18 @@ GuestInfoFindMacAddress(GuestNicList *nicInfo,  // IN/OUT
  */
 
 Bool
-NicInfoChanged(GuestNicList *nicInfo)  // IN
+NicInfoChanged(NicInfoV3 *nicInfo)  // IN
 {
    u_int i;
-   GuestNicList *cachedNicInfo = &gInfoCache.nicInfo;
+   NicInfoV3 *cachedNicInfo = gInfoCache.nicInfo;
+
+   if (!cachedNicInfo) {
+      return TRUE;
+   }
+
+   /*
+    * XXX Add routing, DNS, WINS comparisons.
+    */
 
    if (cachedNicInfo->nics.nics_len != nicInfo->nics.nics_len) {
       g_debug("Number of nics has changed\n");
@@ -880,8 +921,8 @@ NicInfoChanged(GuestNicList *nicInfo)  // IN
 
    for (i = 0; i < cachedNicInfo->nics.nics_len; i++) {
       u_int j;
-      GuestNic *cachedNic = &cachedNicInfo->nics.nics_val[i];
-      GuestNic *matchedNic;
+      GuestNicV3 *cachedNic = &cachedNicInfo->nics.nics_val[i];
+      GuestNicV3 *matchedNic;
 
       /* Find the corresponding nic in the new nic info. */
       matchedNic = GuestInfoFindMacAddress(nicInfo, cachedNic->macAddress);
@@ -899,15 +940,24 @@ NicInfoChanged(GuestNicList *nicInfo)  // IN
 
       /* Which IP addresses have been modified for this NIC? */
       for (j = 0; j < cachedNic->ips.ips_len; j++) {
-         VmIpAddress *cachedIp = &cachedNic->ips.ips_val[j];
+         TypedIpAddress *cachedIp = &cachedNic->ips.ips_val[j].ipAddressAddr;
          Bool foundIP = FALSE;
+         ssize_t cmpsz =
+            cachedIp->ipAddressAddrType == IAT_IPV4 ? 4 :
+            cachedIp->ipAddressAddrType == IAT_IPV6 ? 16 :
+            -1;
          u_int k;
 
+         /* XXX */
+         ASSERT(cmpsz != -1);
+
          for (k = 0; k < matchedNic->ips.ips_len; k++) {
-            VmIpAddress *matchedIp = &matchedNic->ips.ips_val[k];
-            if (0 == strncmp(cachedIp->ipAddress,
-                             matchedIp->ipAddress,
-                             NICINFO_MAX_IP_LEN)) {
+            TypedIpAddress *matchedIp =
+               &matchedNic->ips.ips_val[k].ipAddressAddr;
+            if (cachedIp->ipAddressAddrType == matchedIp->ipAddressAddrType &&
+                memcmp(cachedIp->ipAddressAddr.InetAddress_val,
+                       matchedIp->ipAddressAddr.InetAddress_val,
+                       cmpsz) == 0) {
                foundIP = TRUE;
                break;
             }
@@ -915,9 +965,11 @@ NicInfoChanged(GuestNicList *nicInfo)  // IN
 
          if (FALSE == foundIP) {
             /* This ip address couldn't be found and has been modified. */
+#if 0
             g_debug("MAC address %s, ipaddress %s deleted\n",
                     cachedNic->macAddress,
                     cachedIp->ipAddress);
+#endif
             return TRUE;
          }
 
@@ -929,56 +981,6 @@ NicInfoChanged(GuestNicList *nicInfo)  // IN
 }
 
 
-/*
- *----------------------------------------------------------------------------
- *
- * PrintNicInfo --
- *
- *      Print NIC info struct using the specified print function.
- *
- * Results:
- *      Sum of return values of print function (for printf, this will be the
- *      number of characters printed).
- *
- * Side effects:
- *      None.
- *
- *----------------------------------------------------------------------------
- */
-
-int
-PrintNicInfo(GuestNicList *nicInfo,               // IN
-             int (*PrintFunc)(const char *, ...)) // IN
-{
-   int ret = 0;
-   u_int i = 0;
-
-   ret += PrintFunc("NicInfo: count: %ud\n", nicInfo->nics.nics_len);
-   for (i = 0; i < nicInfo->nics.nics_len; i++) {
-      u_int j;
-      GuestNic *nic = &nicInfo->nics.nics_val[i];
-
-      ret += PrintFunc("NicInfo: nic [%d/%d] mac:      %s",
-                       i+1,
-                       nicInfo->nics.nics_len,
-                       nic->macAddress);
-
-      for (j = 0; j < nic->ips.ips_len; j++) {
-         VmIpAddress *ipAddress = &nic->ips.ips_val[j];
-
-         ret += PrintFunc("NicInfo: nic [%d/%d] IP [%d/%d]: %s",
-                          i+1,
-                          nicInfo->nics.nics_len,
-                          j+1,
-                          nic->ips.ips_len,
-                          ipAddress->ipAddress);
-      }
-   }
-
-   return ret;
-}
-
-
 /*
  *----------------------------------------------------------------------
  *
@@ -1074,8 +1076,67 @@ GuestInfoClearCache(void)
       gInfoCache.value[i][0] = 0;
    }
 
-   VMX_XDR_FREE(xdr_GuestNicList, &gInfoCache.nicInfo);
-   memset(&gInfoCache.nicInfo, 0, sizeof gInfoCache.nicInfo);
+   GuestInfo_FreeNicInfo(gInfoCache.nicInfo);
+   gInfoCache.nicInfo = NULL;
+}
+
+
+/*
+ ***********************************************************************
+ * NicInfoV3ToV2 --                                             */ /**
+ *
+ * @brief Converts the NicInfoV3 NIC list to a GuestNicList.
+ *
+ * @note  This function performs @e shallow copies of things such as
+ *        IP address array, making it depend on the source NicInfoV3.
+ *        In other words, do @e not free NicInfoV3 before freeing the
+ *        returned pointer.
+ *
+ * @param[in]  infoV3   Source NicInfoV3 container.
+ *
+ * @return Pointer to a GuestNicList.  Caller should free it using
+ *         plain ol' @c free.
+ *
+ ***********************************************************************
+ */
+
+static GuestNicList *
+NicInfoV3ToV2(const NicInfoV3 *infoV3)
+{
+   GuestNicList *nicList;
+   unsigned int i, j;
+
+   nicList = Util_SafeCalloc(sizeof *nicList, 1);
+
+   XDRUTIL_ARRAYAPPEND(nicList, nics, infoV3->nics.nics_len);
+   XDRUTIL_FOREACH(i, infoV3, nics) {
+      GuestNicV3 *nic = XDRUTIL_GETITEM(infoV3, nics, i);
+      GuestNic *oldNic = XDRUTIL_GETITEM(nicList, nics, i);
+
+      Str_Strcpy(oldNic->macAddress, nic->macAddress, sizeof oldNic->macAddress);
+
+      XDRUTIL_ARRAYAPPEND(oldNic, ips, nic->ips.ips_len);
+
+      XDRUTIL_FOREACH(j, nic, ips) {
+         IpAddressEntry *ipEntry = XDRUTIL_GETITEM(nic, ips, j);
+         TypedIpAddress *ip = &ipEntry->ipAddressAddr;
+         VmIpAddress *oldIp = XDRUTIL_GETITEM(oldNic, ips, j);
+
+         /* XXX */
+         oldIp->addressFamily = (ip->ipAddressAddrType == IAT_IPV4) ?
+            NICINFO_ADDR_IPV4 : NICINFO_ADDR_IPV6;
+
+         NetUtil_InetNToP(ip->ipAddressAddrType == IAT_IPV4 ?
+                          AF_INET : AF_INET6,
+                          ip->ipAddressAddr.InetAddress_val, oldIp->ipAddress,
+                          sizeof oldIp->ipAddress);
+
+         Str_Sprintf(oldIp->subnetMask, sizeof oldIp->subnetMask, "%u",
+                     ipEntry->ipAddressPrefixLength);
+      }
+   }
+
+   return nicList;
 }
 
 
@@ -1118,9 +1179,11 @@ ToolsOnLoad(ToolsAppCtx *ctx)
    vmResumed = FALSE;
 
    /* Add the first timer event. */
-   src = g_timeout_source_new(GUESTINFO_TIME_INTERVAL_MSEC * 10);
-   VMTOOLSAPP_ATTACH_SOURCE(ctx, src, GuestInfoGather, ctx, NULL);
-   g_source_unref(src);
+   if (ctx->rpc) {
+      src = g_timeout_source_new(GUESTINFO_TIME_INTERVAL_MSEC * 10);
+      VMTOOLSAPP_ATTACH_SOURCE(ctx, src, GuestInfoGather, ctx, NULL);
+      g_source_unref(src);
+   }
 
    return &regData;
 }
index 96ece869c831014c0bd2a8974299d716261c6463..5071500052e6a9ca9142cc0dd9990dc267d4b85f 100644 (file)
@@ -150,7 +150,7 @@ HgfsServerCapReg(gpointer src,
     *
     * Long story short, we shouldn't care if this function fails.
     */
-   if (!RpcChannel_Send(ctx->rpc, msg, strlen(msg) + 1, NULL, NULL)) {
+   if (ctx->rpc && !RpcChannel_Send(ctx->rpc, msg, strlen(msg) + 1, NULL, NULL)) {
       g_warning("Setting HGFS server capability failed!\n");
    }
 
index 974372dee3e2df17fb3cc9c0858e35b2b1723aac..6c682500ccdd0370a39ca1e58dc767093a17d377 100644 (file)
@@ -369,7 +369,7 @@ ResolutionServerCapReg(ToolsAppCtx *ctx,
                          appName,
                          set);
 
-   if (!RpcChannel_Send(ctx->rpc, msg, strlen(msg) + 1, NULL, NULL)) {
+   if (ctx->rpc && !RpcChannel_Send(ctx->rpc, msg, strlen(msg) + 1, NULL, NULL)) {
       g_warning("Setting resolution_server capability failed!\n");
    }
 
index 687e2192aea283a70036dfefc5fb9daef3c877db..4cb2df436efa14b61250eff9554866ea8f26065e 100644 (file)
@@ -36,6 +36,7 @@ libvix_la_SOURCES =
 libvix_la_SOURCES += foundryToolsDaemon.c
 libvix_la_SOURCES += vixPlugin.c
 libvix_la_SOURCES += $(top_srcdir)/lib/vixTools/vixTools.c
+libvix_la_SOURCES += $(top_srcdir)/lib/hgfsHelper/hgfsHelperPosix.c
 
 if HAVE_X11
 install-data-hook:
index 72f7ff9053928bba1f43051e8687f6fcbc501309..26eacf87b8e634be939a9f58e08fc8eaedd78e54 100644 (file)
 #include "hgfsDevLinux.h"
 #endif
 
-#ifndef __FreeBSD__
-#include "netutil.h"
-#endif
-
 /* Only Win32 and Linux use impersonation functions. */
 #if !defined(__FreeBSD__) && !defined(sun)
 #include "impersonate.h"
index d2e63060ca1aeca75ec5f0dca655fd1cdc3004ac..a9f3f7d5e55201ad94646b5d96d195d9fe874385 100644 (file)
@@ -179,7 +179,6 @@ VmBackupFinalize(void)
 {
    g_debug("*** %s\n", __FUNCTION__);
    ASSERT(gBackupState != NULL);
-   ASSERT(gBackupState->machineState == VMBACKUP_MSTATE_IDLE);
 
    if (gBackupState->currentOp != NULL) {
       VmBackup_Cancel(gBackupState->currentOp);
index 6e346663a1abe0ec01cc9c6c98d2cc5e2d14ae00..b68c8c742209b4504cd3a8dabd91e0d61bb9a6eb 100644 (file)
@@ -74,10 +74,7 @@ ToolsCoreInitializeDebug(ToolsServiceState *state)
 
 
 /**
- * Reloads the config file and re-configure the logging subsystem if the
- * log file was updated. If the config file is being loaded for the first
- * time, try to upgrade it to the new version if an old version is
- * detected.
+ * Timer callback that just calls ToolsCore_ReloadConfig().
  *
  * @param[in]  clientData  Service state.
  *
@@ -85,44 +82,9 @@ ToolsCoreInitializeDebug(ToolsServiceState *state)
  */
 
 static gboolean
-ToolsCoreReloadConfig(gpointer clientData)
+ToolsCoreConfFileCb(gpointer clientData)
 {
-   ToolsServiceState *state = clientData;
-   char *confFile = state->configFile;
-   gboolean loaded = TRUE;
-
-   if (confFile == NULL) {
-      confFile = VMTools_GetToolsConfFile();
-   }
-
-   if (state->ctx.config == NULL) {
-      state->ctx.config = VMTools_LoadConfig(confFile,
-                                             G_KEY_FILE_NONE,
-                                             state->mainService);
-      state->configMtime = time(NULL);
-      if (state->ctx.config == NULL) {
-         /* Couldn't load the config file. Just create an empty dictionary. */
-         state->ctx.config = g_key_file_new();
-      }
-   } else if (VMTools_ReloadConfig(confFile,
-                                   G_KEY_FILE_NONE,
-                                   &state->ctx.config,
-                                   &state->configMtime)) {
-      g_debug("Config file reloaded.\n");
-   } else {
-      loaded = FALSE;
-   }
-
-   if (loaded) {
-      VMTools_ConfigLogging(state->ctx.config);
-      if (state->log) {
-         VMTools_EnableLogging(state->log);
-      }
-   }
-
-   if (state->configFile == NULL) {
-      g_free(confFile);
-   }
+   ToolsCore_ReloadConfig(clientData, FALSE);
    return TRUE;
 }
 
@@ -231,6 +193,60 @@ ToolsCore_GetTcloName(ToolsServiceState *state)
 }
 
 
+/**
+ * Reloads the config file and re-configure the logging subsystem if the
+ * log file was updated. If the config file is being loaded for the first
+ * time, try to upgrade it to the new version if an old version is
+ * detected.
+ *
+ * @param[in]  state       Service state.
+ * @param[in]  force       Whether to force reconfiguration of the logging
+ *                         subsystem.
+ */
+
+void
+ToolsCore_ReloadConfig(ToolsServiceState *state,
+                       gboolean force)
+{
+   char *confFile;
+   gboolean loaded = TRUE;
+
+   VMTools_SetDefaultLogDomain(state->name);
+
+   confFile = g_strdup(state->configFile);
+   if (confFile == NULL) {
+      confFile = VMTools_GetToolsConfFile();
+   }
+
+   if (state->ctx.config == NULL) {
+      state->ctx.config = VMTools_LoadConfig(confFile,
+                                             G_KEY_FILE_NONE,
+                                             state->mainService);
+      state->configMtime = time(NULL);
+      if (state->ctx.config == NULL) {
+         /* Couldn't load the config file. Just create an empty dictionary. */
+         state->ctx.config = g_key_file_new();
+      }
+   } else if (VMTools_ReloadConfig(confFile,
+                                   G_KEY_FILE_NONE,
+                                   &state->ctx.config,
+                                   &state->configMtime)) {
+      g_debug("Config file reloaded.\n");
+   } else {
+      loaded = FALSE;
+   }
+
+   if (force || loaded) {
+      VMTools_ConfigLogging(state->ctx.config);
+      if (state->log) {
+         VMTools_EnableLogging(state->log);
+      }
+   }
+
+   g_free(confFile);
+}
+
+
 /**
  * Performs any initial setup steps for the service's main loop.
  *
@@ -248,8 +264,7 @@ ToolsCore_Setup(ToolsServiceState *state)
       g_thread_init(NULL);
    }
 
-   VMTools_SetDefaultLogDomain(state->name);
-   ToolsCoreReloadConfig(state);
+   ToolsCore_ReloadConfig(state, FALSE);
 
    /* Initializes the app context. */
    gctx = g_main_context_default();
@@ -273,7 +288,11 @@ ToolsCore_Setup(ToolsServiceState *state)
       goto error;
    }
 
-   if (!state->ctx.rpc->start(state->ctx.rpc)) {
+   /*
+    * Start the RPC channel if it's been created. The channel may be NULL if this is
+    * not running in the context of a VM.
+    */
+   if (state->ctx.rpc && !state->ctx.rpc->start(state->ctx.rpc)) {
       goto error;
    }
 
@@ -310,7 +329,16 @@ exit:
 int
 ToolsCore_Run(ToolsServiceState *state)
 {
-   g_timeout_add(CONF_POLL_TIME * 10, ToolsCoreReloadConfig, state);
+   /*
+    * If there's no RPC channel (not in a VM) then there's no point in trying to
+    * run the loop, just exit with a '0' return status (see bug 297528 for why '0').
+    */
+   if (!state->ctx.rpc) {
+      return 0;
+   }
+
+   g_timeout_add(CONF_POLL_TIME * 10, ToolsCoreConfFileCb, state);
+
 #if defined(__APPLE__)
    ToolsCore_CFRunLoop(state);
 #else
index ded73ff047708cb96f4162b24c2bf2f0521c241c..498ba0120f2d3d4a78ffc8e5cabb10a08788167d 100644 (file)
@@ -42,6 +42,27 @@ VM_EMBED_VERSION(VMTOOLSD_VERSION_STRING);
 
 static ToolsServiceState gState = { NULL, };
 
+
+/**
+ * Reloads the service configuration - including forcing rotation of log
+ * files by reinitializing the logging subsystem.
+ *
+ * @param[in]  info     Unused.
+ * @param[in]  data     Service state.
+ *
+ * @return TRUE
+ */
+
+static gboolean
+ToolsCoreSigHUPCb(const siginfo_t *info,
+                  gpointer data)
+{
+   VMTools_ResetLogging(TRUE);
+   ToolsCore_ReloadConfig(data, TRUE);
+   return TRUE;
+}
+
+
 /**
  * Handles a signal that would terminate the process. Asks the main loop
  * to exit nicely.
@@ -162,7 +183,7 @@ main(int argc,
 
    src = VMTools_NewSignalSource(SIGHUP);
    VMTOOLSAPP_ATTACH_SOURCE(&gState.ctx, src,
-                            ToolsCoreSigHandler, gState.ctx.mainLoop, NULL);
+                            ToolsCoreSigHUPCb, &gState, NULL);
    g_source_unref(src);
 
    src = VMTools_NewSignalSource(SIGINT);
index fc8f083f974bc0fb4895b1d93c3bc6b950549c0f..b27a4ff2e7629ad8e2300b3ef3875864dc9d8bf3 100644 (file)
@@ -603,7 +603,9 @@ ToolsCore_UnloadPlugins(ToolsServiceState *state)
                          &pcaps);
 
    if (pcaps != NULL) {
-      ToolsCore_SetCapabilities(state->ctx.rpc, pcaps, FALSE);
+      if (state->ctx.rpc) {
+         ToolsCore_SetCapabilities(state->ctx.rpc, pcaps, FALSE);
+      }
       g_array_free(pcaps, TRUE);
    }
 
index 3e12654c618717e0330d0f2f86280b7cba78979b..8274181273c140b32ce8189d7bde9386b121605f 100644 (file)
@@ -112,6 +112,10 @@ ToolsCore_InitRpc(ToolsServiceState *state);
 gboolean
 ToolsCore_LoadPlugins(ToolsServiceState *state);
 
+void
+ToolsCore_ReloadConfig(ToolsServiceState *state,
+                       gboolean force);
+
 void
 ToolsCore_RegisterPlugins(ToolsServiceState *state);
 
index 3f85401f80d66a98c07ed1cd66b50ded330ec3dc..8ca3628c8d388e6d22eb3e40c9300f4927b52888 100644 (file)
@@ -238,34 +238,38 @@ ToolsCore_InitRpc(ToolsServiceState *state)
    } else {
       /*
        * Currently we try to bring up an RpcIn channel, which will only run
-       * inside a Virtual Machine. We want to exit with a "success" status
-       * if this check fails, though. (See bug 297528 for why.)
+       * inside a Virtual Machine. Some plugins may still want to launch and at
+       * least begin even in not in a VM (typically because the installation is dual
+       * purposed between a VM and Bootcamp) - plugins may wish to undo some state
+       * if not in a VM.
        *
        * XXX: this should be relaxed when we try to bring up a VMCI or TCP channel.
        */
       if (!state->ctx.isVMware) {
          g_warning("The %s service needs to run inside a virtual machine.\n",
                    state->name);
-         exit(0);
+         state->ctx.rpc = NULL;
+      } else {
+         state->ctx.rpc = RpcChannel_NewBackdoorChannel(mainCtx);
       }
-
-      state->ctx.rpc = RpcChannel_NewBackdoorChannel(mainCtx);
       app = ToolsCore_GetTcloName(state);
       ASSERT(app != NULL);
    }
 
-   RpcChannel_Setup(state->ctx.rpc,
-                    app,
-                    mainCtx,
-                    &state->ctx,
-                    ToolsCoreCheckReset,
-                    state);
-
-   /* Register the "built in" RPCs. */
-   for (i = 0; i < ARRAYSIZE(rpcs); i++) {
-      RpcChannelCallback *rpc = &rpcs[i];
-      rpc->clientData = state;
-      RpcChannel_RegisterCallback(state->ctx.rpc, rpc);
+   if (state->ctx.rpc) {
+      RpcChannel_Setup(state->ctx.rpc,
+                       app,
+                       mainCtx,
+                       &state->ctx,
+                       ToolsCoreCheckReset,
+                       state);
+
+      /* Register the "built in" RPCs. */
+      for (i = 0; i < ARRAYSIZE(rpcs); i++) {
+         RpcChannelCallback *rpc = &rpcs[i];
+         rpc->clientData = state;
+         RpcChannel_RegisterCallback(state->ctx.rpc, rpc);
+      }
    }
 
    return TRUE;
index a09fde2a690895dbbca3a3752d13ac20a0918f06..221ddbc0b38479745277e635e0ca5b35ad6d7582 100644 (file)
@@ -19,6 +19,7 @@ SUBDIRS =
 SUBDIRS += vmrpcdbg
 SUBDIRS += testDebug
 SUBDIRS += testPlugin
+SUBDIRS += testVmblock
 
 install-exec-local:
        rm -f $(DESTDIR)$(TEST_PLUGIN_INSTALLDIR)/*.a
diff --git a/open-vm-tools/tests/testVmblock/COPYING b/open-vm-tools/tests/testVmblock/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/tests/testVmblock/Makefile.am b/open-vm-tools/tests/testVmblock/Makefile.am
new file mode 100644 (file)
index 0000000..13a6b45
--- /dev/null
@@ -0,0 +1,41 @@
+################################################################################
+### Copyright 2009 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
+################################################################################
+
+noinst_PROGRAMS = vmware-testvmblock-legacy
+noinst_PROGRAMS += vmware-testvmblock-manual-legacy
+
+if HAVE_FUSE
+  noinst_PROGRAMS += vmware-testvmblock-fuse
+  noinst_PROGRAMS += vmware-testvmblock-manual-fuse
+endif
+
+AM_CFLAGS =
+AM_CFLAGS += -DVMX86_DEVEL
+AM_CFLAGS += -DVMX86_DEBUG
+
+AM_LDFLAGS =
+AM_LDFLAGS += -lpthread
+
+vmware_testvmblock_legacy_SOURCES = vmblocktest.c
+
+vmware_testvmblock_manual_legacy_SOURCES = manual-blocker.c
+
+vmware_testvmblock_fuse_CFLAGS = $(AM_CFLAGS) -Dvmblock_fuse
+vmware_testvmblock_fuse_SOURCES = vmblocktest.c
+
+vmware_testvmblock_manual_fuse_CFLAGS = $(AM_CFLAGS) -Dvmblock_fuse
+vmware_testvmblock_manual_fuse_SOURCES = manual-blocker.c
diff --git a/open-vm-tools/tests/testVmblock/manual-blocker.c b/open-vm-tools/tests/testVmblock/manual-blocker.c
new file mode 100644 (file)
index 0000000..52dbb0a
--- /dev/null
@@ -0,0 +1,103 @@
+/*********************************************************
+ * 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.
+ *
+ *********************************************************/
+
+/*
+ * manual-blocker.c --
+ *
+ *      A small test program for manually manipulating vmblock.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include "vmblock_user.h"
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * main --
+ *
+ *      Takes the target file to block as a command line arg. Sits in a loop
+ *      waiting for commands.
+ *
+ * Results:
+ *      Returns 0 on success and nonzero on failure.
+ *
+ * Side effects:
+ *      None/all.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+int
+main(int argc,
+     char *argv[])
+{
+   int status;
+   char op;
+
+   if (argc < 2 ||
+       strcmp(argv[1], "-h") == 0 ||
+       strcmp(argv[1], "--help") == 0) {
+      printf("Usage: %s <path>\n", argv[0]);
+      puts("a to Add a block, d to Delete a block, or l to List blocks (to"
+           " vmblock's log).\n");
+      return 1;
+   }
+
+   int fd = open(VMBLOCK_DEVICE, VMBLOCK_DEVICE_MODE);
+   if (fd <= 0) {
+      perror("open");
+      return 2;
+   }
+   printf("Opened " VMBLOCK_DEVICE " as fd %d.\n", fd);
+
+   while (1) {
+      op = getchar();
+      if (op == 'a') {
+         status = VMBLOCK_CONTROL(fd, VMBLOCK_ADD_FILEBLOCK, argv[1]);
+         if (status != 0) {
+            perror(NULL);
+         } else {
+            printf("%s blocked.\n", argv[1]);
+         }
+      } else if (op == 'd') {
+         status = VMBLOCK_CONTROL(fd, VMBLOCK_DEL_FILEBLOCK, argv[1]);
+         if (status != 0) {
+            perror(NULL);
+         } else {
+            printf("%s unblocked.\n", argv[1]);
+         }
+      } else if (op == 'l') {
+         status = VMBLOCK_CONTROL(fd, VMBLOCK_LIST_FILEBLOCKS, argv[1]);
+         if (status != 0) {
+            perror(NULL);
+         } else {
+            printf("Check vmblock's log for list of blocks.\n");
+         }
+      }
+   }
+
+   return 0;
+}
diff --git a/open-vm-tools/tests/testVmblock/vmblocktest.c b/open-vm-tools/tests/testVmblock/vmblocktest.c
new file mode 100644 (file)
index 0000000..ed63def
--- /dev/null
@@ -0,0 +1,647 @@
+/*********************************************************
+ * 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.
+ *
+ *********************************************************/
+
+/*
+ * vmblocktest.c --
+ *
+ *   Test program for the vmblock file system.  Ensures correctness and
+ *   stability.
+ *
+ */
+
+#if !defined(linux) && !defined(sun) && !defined(__FreeBSD__) && !defined(vmblock_fuse)
+# error "vmblocktest.c needs to be ported to your OS."
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <libgen.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+#include <semaphore.h>
+#ifdef sun
+# include <stropts.h>
+#endif
+
+#include "vmblock_user.h"
+#include "vm_basic_types.h"
+
+#define BLOCKROOT                 VMBLOCK_MOUNT_POINT "/"
+#define CONTROLFILE               VMBLOCK_DEVICE
+#define CONTROLFILE_MODE          VMBLOCK_DEVICE_MODE
+#define REALROOT                   "/tmp/VMwareDnD/"
+#define FILENAME                   "/foo"
+#define ACCESSORFULLNAME(dir)      BLOCKROOT dir FILENAME
+#define BLOCKERFULLNAME(dir)       REALROOT dir
+
+#define lprintf(...)                                                    \
+   do {                                                                 \
+      pthread_mutex_lock(&print_lock);                                  \
+      printf(__VA_ARGS__);                                              \
+      fflush(stdout);                                                   \
+      pthread_mutex_unlock(&print_lock);                                \
+   } while(0)
+
+#define lfprintf(stream, ...)                                           \
+   do {                                                                 \
+      pthread_mutex_lock(&print_lock);                                  \
+      fprintf(stream, __VA_ARGS__);                                     \
+      fflush(stream);                                                   \
+      pthread_mutex_unlock(&print_lock);                                \
+   } while(0)
+
+#define Log(fmt, args...)          lprintf(fmt, ## args)
+#define ERROR(fmt, args...)        lfprintf(stderr, fmt, ## args)
+#define THREAD_LOG(fmt, args...)   lprintf(" (%lx) " fmt, (unsigned long)pthread_self(), ## args)
+#define THREAD_ERROR(fmt, args...) lfprintf(stderr, " (%"FMTPID") " fmt, getpid(), ## args)
+
+#if defined (linux) || defined(__FreeBSD__)
+# define os_thread_yield()      sched_yield()
+#elif defined(sun)
+# define os_thread_yield()      yield()
+#endif
+
+/*
+ * This program may optionally throttle accessor thread generation
+ * via POSIX semaphores.
+ */
+#if defined(USE_SEMAPHORES)
+sem_t sem;
+# define SEM_THREADS    (unsigned int)10
+# define SEM_INIT()     sem_init(&sem, 0, SEM_THREADS)
+# define SEM_DESTROY()  sem_destroy(&sem)
+# define SEM_WAIT()     sem_wait(&sem)
+# define SEM_POST()     sem_post(&sem)
+# define PTHREAD_SEMAPHORE_CLEANUP()    pthread_cleanup_push(sem_post,  \
+                                                             (void *)&sem)
+#else
+# define SEM_INIT()
+# define SEM_DESTROY()
+# define SEM_WAIT()
+# define SEM_POST()
+# define PTHREAD_SEMAPHORE_CLEANUP()
+#endif
+
+/* Types */
+typedef struct FileState {
+   /* Accessors will access the file through the vmblock namespace */
+   char *accessorName;
+   /* The blocker will add blocks using the real file's name */
+   char *blockerName;
+   Bool blocked;
+   unsigned int waiters;
+} FileState;
+
+typedef struct ThreadInfo {
+   int blockFd;
+   pthread_mutex_t *lock;
+   FileState *files;
+   size_t filesArraySize;
+   unsigned int sleepTime;
+} ThreadInfo;
+
+/* Variables */
+static Bool programQuit = FALSE;
+static FileState files[] = {
+   { ACCESSORFULLNAME("0"), BLOCKERFULLNAME("0"), FALSE, 0 },
+   { ACCESSORFULLNAME("1"), BLOCKERFULLNAME("1"), FALSE, 0 },
+   { ACCESSORFULLNAME("2"), BLOCKERFULLNAME("2"), FALSE, 0 },
+   { ACCESSORFULLNAME("3"), BLOCKERFULLNAME("3"), FALSE, 0 },
+   { ACCESSORFULLNAME("4"), BLOCKERFULLNAME("4"), FALSE, 0 },
+   { ACCESSORFULLNAME("5"), BLOCKERFULLNAME("5"), FALSE, 0 },
+   { ACCESSORFULLNAME("6"), BLOCKERFULLNAME("6"), FALSE, 0 },
+   { ACCESSORFULLNAME("7"), BLOCKERFULLNAME("7"), FALSE, 0 },
+   { ACCESSORFULLNAME("8"), BLOCKERFULLNAME("8"), FALSE, 0 },
+   { ACCESSORFULLNAME("9"), BLOCKERFULLNAME("9"), FALSE, 0 },
+};
+
+/* Thread entry points */
+static void *blocker(void *arg);
+static void *accessor(void *arg);
+
+/* Utility functions */
+static Bool addBlock(int fd, char const *filename);
+static Bool delBlock(int fd, char const *filename);
+static Bool listBlocks(int fd);
+#ifdef VMBLOCK_PURGE_FILEBLOCKS
+static Bool purgeBlocks(int fd);
+#endif
+static unsigned int getRand(unsigned int max);
+static void sighandler(int sig);
+
+pthread_mutex_t print_lock;
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * main --
+ *
+ *    Does all necessary setup then starts the blocker thread and continually
+ *    starts accessor threads.
+ *
+ * Results:
+ *    EXIT_SUCCESS and EXIT_FAILURE.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+int
+main(int argc,
+     char *argv[])
+{
+   int ret = EXIT_SUCCESS;
+   int i;
+   int blockFd;
+   char *progname;
+   pthread_t blockerThread;
+   pthread_mutex_t filesLock;
+   pthread_attr_t attr;
+   ThreadInfo info;
+   int count;
+
+   progname = basename(argv[0]);
+   pthread_mutex_init(&filesLock, NULL);
+
+   SEM_INIT();
+   pthread_mutex_init(&print_lock, NULL);
+
+   /* Open device user to add/delete blocks */
+   blockFd = open(CONTROLFILE, CONTROLFILE_MODE);
+   if (blockFd < 0) {
+      ERROR("%s: could not open " CONTROLFILE "\n", progname);
+      exit(EXIT_FAILURE);
+   }
+
+   /* Provide ability to just list blocks */
+   if (argc > 1) {
+      if (strcmp(argv[1], "-list") == 0) {
+         listBlocks(blockFd);
+#ifdef VMBLOCK_PURGE_FILEBLOCKS
+      } else if (strcmp(argv[1], "-purge") == 0) {
+         purgeBlocks(blockFd);
+#endif
+      }
+      close(blockFd);
+      exit(EXIT_SUCCESS);
+   }
+
+   /* Create directories/files used during test */
+   for (i = 0; i < sizeof files/sizeof files[0]; i++) {
+      int err;
+      struct stat statbuf;
+      char buf[PATH_MAX];
+
+      err = stat(files[i].blockerName, &statbuf);
+      if (!err) {
+         if (S_ISDIR(statbuf.st_mode)) {
+            goto create_file;
+         }
+
+         ERROR("%s: file [%s] already exists and is not a directory\n",
+               progname, files[i].blockerName);
+         goto exit_failure;
+      }
+
+      err = mkdir(files[i].blockerName, S_IRWXU | S_IRWXG);
+      if (err) {
+         ERROR("%s: could not create [%s]\n", progname, files[i].blockerName);
+         goto exit_failure;
+      }
+
+create_file:
+      strncpy(buf, files[i].blockerName, sizeof buf);
+      strncat(buf, FILENAME, sizeof buf - strlen(files[i].blockerName));
+      err = stat(buf, &statbuf);
+      if (!err) {
+         if (S_ISREG(statbuf.st_mode)) {
+            continue;
+         }
+
+         ERROR("%s: file [%s] already exists and is not a regular file\n",
+               progname, buf);
+         goto exit_failure;
+      }
+
+      err = creat(buf, S_IRUSR | S_IRGRP);
+      if (err < 0) {
+         ERROR("%s: could not create [%s]\n", progname, buf);
+         goto exit_failure;
+      }
+
+      continue;
+
+exit_failure:
+      close(blockFd);
+      exit(EXIT_FAILURE);
+   }
+
+   if (signal(SIGINT, sighandler) == SIG_ERR ||
+       signal(SIGTERM, sighandler) == SIG_ERR) {
+      ERROR("%s: could not install signal handlers\n", progname);
+      close(blockFd);
+      exit(EXIT_FAILURE);
+   }
+
+   /* Seems cleaner than a bunch of globals ... */
+   info.blockFd = blockFd;
+   info.lock = &filesLock;
+   info.files = files;
+   info.filesArraySize = sizeof files/sizeof files[0];
+   info.sleepTime = 1;
+
+   /*
+    * Start a thread that flips a random file's state, then sleeps for a while
+    * and does it again.
+    */
+   if (pthread_create(&blockerThread, NULL, blocker, &info)) {
+      ERROR("%s: could not create blocker thread\n", progname);
+      close(blockFd);
+      exit(EXIT_FAILURE);
+   }
+
+   /*
+    * Start a bunch of threads that try to open a random file, check its status
+    * once they have it open (to make sure it is not blocked), then close it
+    * and exit.
+    */
+   pthread_attr_init(&attr);
+   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+   count = 0;
+   while (!programQuit) {
+      pthread_t thread;
+      int rv;
+      SEM_WAIT();
+      /* Create threads until we cannot anymore */
+      if ((rv = pthread_create(&thread, &attr, accessor, &info)) != 0) {
+         SEM_POST();
+         if (rv == EAGAIN || rv == ENOMEM) {
+            os_thread_yield();
+            continue;
+         }
+         ERROR("%s: could not create an accessor thread (%d total)\n",
+               progname, count);
+         ERROR("%s: pthread_create: %s\n", progname, strerror(rv));
+         ret = EXIT_FAILURE;
+         break;
+      }
+      count++;
+   }
+
+   Log("%s: Not creating any more accessor threads.\n", progname);
+
+   programQuit = TRUE;
+   pthread_join(blockerThread, NULL);
+
+   pthread_mutex_destroy(&filesLock);
+   close(blockFd);
+
+   Log("%s: Exiting with %s.\n",
+       progname, ret == EXIT_SUCCESS ? "success" : "failure");
+
+   exit(ret);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * blocker --
+ *
+ *    Entry point for the single blocker thread.  Continuously picks a file at
+ *    random and changes its state by adding or deleting a block on that file.
+ *
+ * Results:
+ *    EXIT_SUCCESS and EXIT_FAILURE.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void *
+blocker(void *arg)  // IN
+{
+   ThreadInfo *info = (ThreadInfo *)arg;
+   unsigned int index;
+
+   if (!info) {
+      THREAD_ERROR("blocker: no thread info provided\n");
+      pthread_exit((void *)EXIT_FAILURE);
+   }
+
+   while (!programQuit) {
+      index = getRand(info->filesArraySize - 1);
+
+      pthread_mutex_lock(info->lock);
+
+      if (info->files[index].blocked) {
+         info->files[index].blocked = FALSE;
+         if ( !delBlock(info->blockFd, info->files[index].blockerName) ) {
+            THREAD_ERROR("blocker: could not delete block on [%s]\n",
+                         info->files[index].blockerName);
+            goto error;
+         }
+      } else if (info->files[index].waiters == 0) {
+         /*
+          * Only add a new block if all previous waiters are done.  This
+          * ensures we don't get incorrect error messages from accessor threads
+          * even though the open(2) and check are not atomic in the accessor.
+          */
+         info->files[index].blocked = TRUE;
+         if ( !addBlock(info->blockFd, info->files[index].blockerName) ) {
+            THREAD_ERROR("blocker: could not add block on [%s]\n",
+                         info->files[index].blockerName);
+            goto error;
+         }
+      }
+
+      pthread_mutex_unlock(info->lock);
+
+      sleep(info->sleepTime);
+   }
+
+   pthread_mutex_lock(info->lock);
+   for (index = 0; index < info->filesArraySize; index++) {
+      if (info->files[index].blocked) {
+         info->files[index].blocked = FALSE;
+#ifndef TEST_CLOSE_FD
+         THREAD_LOG("blocker: deleting block for [%s]\n",
+                    info->files[index].blockerName);
+         if ( !delBlock(info->blockFd, info->files[index].blockerName) ) {
+            THREAD_ERROR("blocker: could not delete existing block on exit for [%s]\n",
+                         info->files[index].blockerName);
+         }
+#else
+         THREAD_LOG("blocker: unmarking block for [%s], left for unblock on release\n",
+                    info->files[index].blockerName);
+#endif
+      }
+   }
+   pthread_mutex_unlock(info->lock);
+
+   pthread_exit(EXIT_SUCCESS);
+
+error:
+   programQuit = TRUE;
+   pthread_mutex_unlock(info->lock);
+   pthread_exit((void *)EXIT_FAILURE);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * accessor --
+ *
+ *    Entry point for accessor threads.  Picks a file at random and attempts to
+ *    open it.  Once it is opened, ensures the state of the file is not blocked
+ *    and outputs an error message accordingly.
+ *
+ * Results:
+ *    EXIT_SUCCESS and EXIT_FAILURE.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void *
+accessor(void *arg)  // IN
+{
+   ThreadInfo *info = (ThreadInfo *)arg;
+   unsigned int index;
+   int fd;
+   uintptr_t ret = EXIT_SUCCESS;
+
+   PTHREAD_SEMAPHORE_CLEANUP();
+
+   if (!info) {
+      THREAD_ERROR("blocker: no thread info provided\n");
+      pthread_exit((void *)EXIT_FAILURE);
+   }
+
+   index = getRand(info->filesArraySize - 1);
+
+   /*
+    * We can't hold the lock while calling open(2), since we will deadlock
+    * waiting for the blocker thread to remove the block on the file.  So, we
+    * bump the waiter count to ensure that a new block is not placed on this
+    * file until we have checked its state.  This prevents incorrect error
+    * messages that would happen if the blocker placed a new block on the file
+    * between our open(2) call returning and acquiring the lock.
+    *
+    * The fact that we can't hold the lock through open(2) also means that it's
+    * not atomic with respect to checking the file's blocked flag.  Given this,
+    * it's possible that we'll miss some errors if the block is removed after
+    * open(2) returns but before we check the blocked flag -- hopefully running
+    * this test for a very long time will be sufficient to catch these cases.
+    * (Having the blocker sleep increases the likelihood of seeing such
+    * errors.)
+    */
+   pthread_mutex_lock(info->lock);
+   info->files[index].waiters++;
+   pthread_mutex_unlock(info->lock);
+
+   fd = open(info->files[index].accessorName, O_RDONLY);
+   if (fd < 0) {
+      if (errno == EMFILE) {
+         /* We already have hit the maximum number of file descriptors */
+         pthread_mutex_lock(info->lock);
+         info->files[index].waiters--;
+         pthread_mutex_unlock(info->lock);
+         pthread_exit((void *)EXIT_FAILURE);
+      }
+      THREAD_ERROR("accessor: could not open file [%s]\n",
+                   info->files[index].accessorName);
+      THREAD_ERROR("accessor: open: %s\n", strerror(errno));
+      pthread_exit((void *)EXIT_FAILURE);
+   }
+
+   pthread_mutex_lock(info->lock);
+   info->files[index].waiters--;
+
+   if (info->files[index].blocked) {
+      THREAD_ERROR("accessor: [ERROR] accessed file [%s] while blocked (%d)\n",
+                   info->files[index].accessorName, info->files[index].blocked);
+      ret = EXIT_FAILURE;
+   }
+   pthread_mutex_unlock(info->lock);
+   close(fd);
+
+   pthread_exit((void *)ret);
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * addBlock --
+ *
+ *    Adds a block on the specified filename.
+ *
+ * Results:
+ *    TRUE on success, FALSE on failure.
+ *
+ * Side effects:
+ *    Future open(2)s on the file will block until delBlock() is called for
+ *    that file.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+addBlock(int fd,                // IN: fd of control device
+         char const *filename)  // IN: filename to add block for
+{
+   Log("Blocking [%s]\n", filename);
+   return VMBLOCK_CONTROL(fd, VMBLOCK_ADD_FILEBLOCK, filename) == 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * delBlock --
+ *
+ *    Deletes a block on the specified filename.
+ *
+ * Results:
+ *    TRUE on success, FALSE on failure.
+ *
+ * Side effects:
+ *    Previous open(2)s that had blocked will now complete.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+delBlock(int fd,                // IN: fd of control device
+         char const *filename)  // IN: filename to delete block for
+{
+   Log("Unblocking [%s]\n", filename);
+   return VMBLOCK_CONTROL(fd, VMBLOCK_DEL_FILEBLOCK, filename) == 0;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * listBlocks --
+ *
+ *    Tells the kernel module to list all existing blocks.
+ *
+ * Results:
+ *    TRUE on success, FALSE on failure.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+listBlocks(int fd)      // IN: fd of control device
+{
+   Log("Listing blocks (check kernel log output)\n");
+   return VMBLOCK_CONTROL(fd, VMBLOCK_LIST_FILEBLOCKS, NULL) == 0;
+}
+
+
+#ifdef VMBLOCK_PURGE_FILEBLOCKS
+/*
+ *----------------------------------------------------------------------------
+ *
+ * purgeBlocks --
+ *
+ *    Tells the kernel module to purge all existing blocks, regardless of
+ *    who opened them.
+ *
+ * Results:
+ *    TRUE on success, FALSE on failure.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static Bool
+purgeBlocks(int fd)      // IN: fd of control device
+{
+   Log("Purging all blocks\n");
+   return VMBLOCK_CONTROL(fd, VMBLOCK_PURGE_FILEBLOCKS, NULL) == 0;
+}
+#endif
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * getRand --
+ *
+ *    Retrieves the next random number within the range [0, max].
+ *
+ * Results:
+ *    A random number.
+ *
+ * Side effects:
+ *    None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static unsigned int
+getRand(unsigned int max)   // IN: max value returnable
+{
+   return random() % max;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * sighandler --
+ *
+ *    Sets the programQuit flag when a signal is received.
+ *
+ * Results:
+ *    None.
+ *
+ * Side effects:
+ *    Program will quit.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+sighandler(int sig)
+{
+   programQuit = TRUE;
+}
index 33534bba5f248c8f2d80770dccc07a5a60332ebd..d84dee8a25eb6ef97a56d1aab32a431a36f84e9d 100644 (file)
@@ -328,7 +328,6 @@ StatHelp(const char *progName) // IN: The name of the program obtained from argv
           "Usage: %s stat <subcommand>\n\n"
           "Subcommands\n"
           "   hosttime: print the host time\n"
-          "   memory: print the virtual machine memory in MBs\n"
           "   speed: print the CPU speed in MHz\n"
           "ESX guests only subcommands\n"
           "   sessionid: print the current session id\n"
@@ -487,9 +486,7 @@ static int
 StatCommand(char **argv, // IN: Command line arguments
             int argc)    // IN: Length of command line arguments
 {
-   if (toolbox_strcmp(argv[optind], "memory") == 0) {
-      return Stat_MemorySize();
-   } else if (toolbox_strcmp(argv[optind], "hosttime") == 0) {
+   if (toolbox_strcmp(argv[optind], "hosttime") == 0) {
       return Stat_HostTime();
    } else if (toolbox_strcmp(argv[optind], "sessionid") == 0) {
       return Stat_GetSessionID();
@@ -732,7 +729,14 @@ main(int argc,    // IN: length of command line arguments
          ToolboxUnknownEntityError(argv[0], "command", argv[optind]);
          retval = EX_USAGE;
       } else if (cmd->requireRoot && !System_IsUserAdmin()) {
-         fprintf(stderr, "%s: You must be root to perform %s operations",
+         fprintf(stderr,
+#ifdef _WIN32
+                 "%s: Administrator permissions are needed to perform %s "
+                 "operations. Use an administrator command prompt to "
+                 "complete these tasks.",
+#else
+                 "%s: You must be root to perform %s operations",
+#endif
                  argv[0], cmd->command);
          retval = EX_NOPERM;
       } else if (cmd->requireArguments && ++optind >= argc) {
index 901f2e5f2db84757f9e5f4e3ea067edf9db681f1..1a8673c36c2e7562c0878154272859ad80b12b24 100644 (file)
@@ -112,7 +112,6 @@ int Shrink_DoShrink(char*, int);
  * Stat commands
  */
 
-int Stat_MemorySize(void);
 int Stat_HostTime(void);
 int Stat_ProcessorSpeed(void);
 int Stat_GetSessionID(void);
index ce0a94d08f451f5f25ffcf32110603e56a942d6e..56b0685d49df55966ccfa11c0169fb584727b650 100644 (file)
@@ -43,7 +43,7 @@
 #define MAX_DEVICES 50  /* maximum number of devices we'll show */
 #define SHRINK_DISABLED_ERR "Shrink disk is disabled for this virtual machine.\n\n" \
                             "Shrinking is disabled for linked clones, parents of " \
-                           "linked clones, \npre-allocated disks, snapshots, and " \
+                           "linked clones, \npre-allocated disks, snapshots, or due to " \
                            "other factors. \nSee the User's manual for more " \
                            "information.\n"
 #define SHRINK_FEATURE_ERR "The shrink feature is not available,\n\n" \
@@ -51,7 +51,7 @@
                            "because too many communication channels are open.\n\n If you are running " \
                            "an old version of a VMware product, you should consider upgrading.\n\n" \
                            "If too many communication channels are open, you should power off your " \
-                           "virtual machine and then power it back on\n." 
+                           "virtual machine and then power it back on.\n"
 #define SHRINK_CONFLICT_ERR "Error, The Toolbox believes disk shrinking is " \
                            "enabled while the host believes it is disabled.\n\n " \
                            "Please close and reopen the Toolbox to synchronize " \
index 845e4c65ec626a72065aab576241e3ee8876f11d..46afeea39ceebf3bcff09ad9596ab2dae8b64811 100644 (file)
@@ -71,9 +71,7 @@ Shrink_Create(GtkWidget *mainWnd)
    GtkWidget *viewport;
    GtkWidget *ebox;
 
-   int i;
-   WiperPartition_List *plist;
-   WiperPartition *partkb;
+   WiperPartition_List plist;
    gchar *items;
    int newrow;
 
@@ -155,19 +153,25 @@ Shrink_Create(GtkWidget *mainWnd)
             gtk_clist_set_selection_mode(GTK_CLIST(shrinkList), GTK_SELECTION_MULTIPLE);
 
             Wiper_Init(NULL);
-            plist = WiperPartition_Open();
-            if (plist != NULL) {
-               for (i=0; i < plist->size; i++) {
-                  if (strlen(plist->partitions[i].comment) == 0) {
-                     partkb = (WiperPartition *)malloc(sizeof (WiperPartition));
-                     memcpy(partkb, &(plist->partitions[i]), sizeof (WiperPartition));
-                     items  = partkb->mountPoint;
+            if (WiperPartition_Open(&plist)) {
+               DblLnkLst_Links *curr, *next;
+
+               DblLnkLst_ForEachSafe(curr, next, &plist.link) {
+                  WiperPartition *part = DblLnkLst_Container(curr, WiperPartition, link);
+
+                  if (part->type != PARTITION_UNSUPPORTED) {
+                     /*
+                      * Detach the element we are interested in so it is not
+                      * destroyed when we call WiperPartition_Close.
+                      */
+                     DblLnkLst_Unlink1(&part->link);
+                     items  = part->mountPoint;
                      newrow = gtk_clist_append(GTK_CLIST(shrinkList), &items);
-                     gtk_clist_set_row_data(GTK_CLIST(shrinkList), newrow,
-                                            partkb);
+                     gtk_clist_set_row_data_full(GTK_CLIST(shrinkList), newrow,
+                                 part, (GDestroyNotify)WiperSinglePartition_Close);
                   }
                }
-               WiperPartition_Close(plist);
+               WiperPartition_Close(&plist);
             }
          } else {
             label = gtk_label_new(SHRINK_DISABLED_ERR);
@@ -184,7 +188,6 @@ Shrink_Create(GtkWidget *mainWnd)
          gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
          gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
          gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
-
       }
    }
 
@@ -229,8 +232,7 @@ Shrink_OnShrinkClicked(GtkButton *btn,     // IN: unused
       }
       do {
          rnum =  GPOINTER_TO_UINT(slist->data);
-         part = (WiperPartition *)(gtk_clist_get_row_data(GTK_CLIST(shrinkList),
-                                                          rnum));
+         part = gtk_clist_get_row_data(GTK_CLIST(shrinkList), rnum);
          if (Shrink_DoWipe(part, mainWnd)) {
             disks_to_shrink++;
             slist = slist->next;
@@ -244,7 +246,7 @@ Shrink_OnShrinkClicked(GtkButton *btn,     // IN: unused
          if (ToolsMain_YesNoBox("Shrink Disk",
                                 "Do you want to shrink the disk(s)?\n")) {
             if (GuestApp_DiskShrink()) {
-               ToolsMain_MsgBox("Information", "The shrink process is complete.");
+               ToolsMain_MsgBox("Information", "The shrink process has finished.");
             }
             gtk_clist_unselect_all(GTK_CLIST(shrinkList));
          }
index ccf8bf01543264751d15b694088cfc74c9f7eb99..24e741a67985b38feef0317bb4681a1f112db080 100644 (file)
@@ -363,7 +363,7 @@ Script_Set(const char *apm,   // IN: APM name
    GError *err = NULL;
 
    if (!File_Exists(path)) {
-      fprintf(stderr, "%s doesn't exists\n", path);
+      fprintf(stderr, "%s doesn't exist\n", path);
       return EX_OSFILE;
    }
 
index d06dcb5f44d8855851e12618da13dd12f8332edc..33e4f643b57699a1535f39a2ebd63ea0f8339ab1 100644 (file)
@@ -37,8 +37,8 @@
 static void ShrinkWiperDestroy(int signal);
 #endif
 
-static WiperPartition_List * ShrinkGetMountPoints(void);
-static WiperPartition * ShrinkGetPartition(char *mountPoint, int quiet_flag);
+static Bool ShrinkGetMountPoints(WiperPartition_List *);
+static WiperPartition * ShrinkGetPartition(char *mountPoint);
 static Wiper_State *wiper = NULL;
 
 
@@ -59,19 +59,24 @@ static Wiper_State *wiper = NULL;
  */
 
 int
-Shrink_List(void) // IN: Verbosity flag.
+Shrink_List(void)
 {
-   int i;
-   WiperPartition_List *plist = ShrinkGetMountPoints();
-   if (plist == NULL) {
+   WiperPartition_List plist;
+   DblLnkLst_Links *curr;
+
+   if (!ShrinkGetMountPoints(&plist)) {
       return EX_TEMPFAIL;
    }
-   for (i = 0; i < plist->size; i++) {
-      if (strlen(plist->partitions[i].comment) == 0) {
-         printf("%s\n", plist->partitions[i].mountPoint);
+
+   DblLnkLst_ForEach(curr, &plist.link) {
+      WiperPartition *p = DblLnkLst_Container(curr, WiperPartition, link);
+      if (p->type != PARTITION_UNSUPPORTED) {
+         printf("%s\n", p->mountPoint);
       }
    }
-   WiperPartition_Close(plist);
+
+   WiperPartition_Close(&plist);
+
    return EXIT_SUCCESS;
 }
 
@@ -93,25 +98,32 @@ Shrink_List(void) // IN: Verbosity flag.
  */
 
 static WiperPartition*
-ShrinkGetPartition(char *mountPoint, // IN: mount point
-                   int quiet_flag)   // IN: Verbosity flag
+ShrinkGetPartition(char *mountPoint)
 {
-   int i;
-   WiperPartition *part;
-   WiperPartition_List *plist = ShrinkGetMountPoints();
-   if (!plist) {
+   WiperPartition_List plist;
+   WiperPartition *p, *part = NULL;
+   DblLnkLst_Links *curr;
+
+   if (!ShrinkGetMountPoints(&plist)) {
       return NULL;
    }
-   part = (WiperPartition *) malloc(sizeof *part);
-   for (i = 0; i < plist->size; i++) {
-      if (toolbox_strcmp(plist->partitions[i].mountPoint, mountPoint) == 0) {
-         memcpy(part, &plist->partitions[i], sizeof *part);
-         WiperPartition_Close(plist);
-         return part;
+
+   DblLnkLst_ForEach(curr, &plist.link) {
+      p = DblLnkLst_Container(curr, WiperPartition, link);
+      if (toolbox_strcmp(p->mountPoint, mountPoint) == 0) {
+         part = p;
+         /*
+          * Detach the element we are interested in so it is not
+          * destroyed when we call WiperPartition_Close.
+          */
+         DblLnkLst_Unlink1(&part->link);
+         break;
       }
    }
-   WiperPartition_Close(plist);
-   return NULL;
+
+   WiperPartition_Close(&plist);
+
+   return part;
 }
 
 
@@ -131,19 +143,19 @@ ShrinkGetPartition(char *mountPoint, // IN: mount point
  *-----------------------------------------------------------------------------
  */
 
-static WiperPartition_List*
-ShrinkGetMountPoints(void) // IN: Verbosity flag
+static Bool
+ShrinkGetMountPoints(WiperPartition_List *pl) // OUT: Known mount points
 {
-   if (GuestApp_IsDiskShrinkCapable()) {
-      if (GuestApp_IsDiskShrinkEnabled()) {
-         return WiperPartition_Open();
-      } else {
-         fprintf(stderr,SHRINK_DISABLED_ERR);
-      }
-   } else {
+   if (!GuestApp_IsDiskShrinkCapable()) {
       fprintf(stderr, SHRINK_FEATURE_ERR);
+   } else if (!GuestApp_IsDiskShrinkEnabled()) {
+      fprintf(stderr, SHRINK_DISABLED_ERR);
+   } else if (!WiperPartition_Open(pl)) {
+      fprintf(stderr, "Unable to collect partition data.\n");
+   } else {
+      return TRUE;
    }
-   return NULL;
+   return FALSE;
 }
 
 
@@ -175,18 +187,22 @@ Shrink_DoShrink(char *mountPoint, // IN: mount point
    int progress = 0;
    unsigned char *err;
    WiperPartition *part;
+   int rc;
+
 #ifndef _WIN32
    signal(SIGINT, ShrinkWiperDestroy);
 #endif
-   part = ShrinkGetPartition(mountPoint, quiet_flag);
+
+   part = ShrinkGetPartition(mountPoint);
    if (part == NULL) {
       fprintf(stderr, "Unable to find partition %s\n", mountPoint);
       return EX_OSFILE;
    }
 
-   if (strlen(part->comment) != 0) {
+   if (part->type == PARTITION_UNSUPPORTED) {
       fprintf(stderr, "Partition %s is not shrinkable\n", part->mountPoint);
-      return EX_UNAVAILABLE;
+      rc = EX_UNAVAILABLE;
+      goto out;
    }
 
    /*
@@ -196,59 +212,57 @@ Shrink_DoShrink(char *mountPoint, // IN: mount point
     */
    if (!GuestApp_IsDiskShrinkEnabled()) {
       fprintf(stderr, SHRINK_CONFLICT_ERR);
-      free(part);
-      return EX_TEMPFAIL;
+      rc = EX_TEMPFAIL;
+      goto out;
    }
 
-   wiper = Wiper_Start (part, MAX_WIPER_FILE_SIZE);
+   wiper = Wiper_Start(part, MAX_WIPER_FILE_SIZE);
+
    while (progress < 100 && wiper != NULL) {
       err = Wiper_Next(&wiper, &progress);
       if (strlen(err) > 0) {
          if (strcmp(err, "error.create") == 0) {
             fprintf(stderr, "Error, Unable to create wiper file\n");
-            free(part);
-            return EX_TEMPFAIL;
-         }
-         else {
+         } else {
             fprintf(stderr, "Error, %s", err);
-            free(part);
-            return EX_TEMPFAIL;
          }
-         free(wiper);
-         wiper = NULL;
+
+         rc = EX_TEMPFAIL;
       }
+
       if (!quiet_flag) {
          printf("\rProgress: %d [", progress);
          for (i = 0; i <= progress / 10; i++) {
-            printf("=");
+            putchar('=');
          }
-         printf(">");
-         for (; i <= 100 / 10; i++) {
-            printf(" ");
-            }
-         printf("]");
+         printf(">%*c", 10 - i + 1, ']');
+         fflush(stdout);
       }
    }
+
    if (progress >= 100) {
       char *result;
       size_t resultLen;
+
       if (RpcOut_sendOne(&result, &resultLen, "disk.shrink")) {
          if (!quiet_flag) {
             printf("\nDisk shrinking complete\n");
          }
-         wiper = NULL;
-         free(part);
-         return EXIT_SUCCESS;
-      }
-      if (!quiet_flag) {
-         fprintf(stderr, "%s\n", result);
+         rc = EXIT_SUCCESS;
+         goto out;
       }
-      wiper = NULL;
-      free(part);
+
+      fprintf(stderr, "%s\n", result);
    }
 
    fprintf(stderr, "Shrinking not completed\n");
-   return EX_TEMPFAIL;
+   rc = EX_TEMPFAIL;
+
+out:
+   WiperSinglePartition_Close(part);
+   free(wiper);
+   wiper = NULL;
+   return rc;
 }
 
 
index dcf9fd3193696adf7b090e93faa2703863b9e621..08614f13a9138f404e3e01a1cc42f569d8dbe632 100644 (file)
@@ -105,40 +105,6 @@ Stat_ProcessorSpeed(void)
 }
 
 
-/*
- *-----------------------------------------------------------------------------
- *
- * Stat_MemorySize  --
- *
- *      Gets the virtual machine's memory in MBs.
- *
- * Results:
- *      EXIT_SUCCESS on success.
- *      EX_TEMPFAIL on failure.
- *
- * Side effects:
- *      None.
- *
- *-----------------------------------------------------------------------------
- */
-
-int
-Stat_MemorySize(void)
-{
-   uint32 memsize;
-   Backdoor_proto bp;
-   bp.in.cx.halfs.low = BDOOR_CMD_GETMEMSIZE;
-   Backdoor(&bp);
-   memsize = bp.out.ax.word;
-   if (memsize < 0) {
-      fprintf(stderr, "Unable to get memory size\n");
-      return EX_TEMPFAIL;
-   }
-   printf("%u MB\n", memsize);
-   return EXIT_SUCCESS;
-}
-
-
 /*
  *-----------------------------------------------------------------------------
  *
index 9e6a8b4f370915d6256e38c1c4f692a7b35c7fa4..443cb3ef8725fbac87b6902026f65b10269fcbbe 100644 (file)
@@ -63,6 +63,7 @@ else
 endif
 vmware_user_LDADD += ../lib/user/libUser.la
 vmware_user_LDADD += ../lib/vixTools/libVixTools.la
+vmware_user_LDADD += ../lib/hgfsHelper/libHgfsHelper.la
 vmware_user_LDADD += ../lib/vmCheck/libVmCheck.la
 vmware_user_LDADD += ../lib/vmSignal/libVmSignal.la
 vmware_user_LDADD += ../lib/wiper/libWiper.la
@@ -98,7 +99,8 @@ endif
 vmware_user_LDADD += -lcrypt
 vmware_user_LDADD += -lstdc++
 if LINUX
-vmware_user_LDADD += -lgcc_s
+   vmware_user_LDADD += -lgcc_s
+   vmware_user_LDADD += ../lib/slashProc/libSlashProc.la
 endif
 vmware_user_LDADD += @GTK_LIBS@
 if HAVE_GTKMM
index 16d6ec4d9cef8c5cedc3df5a049d055297837eec..e6f3bbd506d751d0b0a4302adf71ca02918984be 100644 (file)
@@ -582,11 +582,12 @@ CopyPasteUI::LocalPrimTimestampCB(const Gtk::SelectionData& sd)  // IN
    }
 
    Glib::RefPtr<Gtk::Clipboard> refClipboard;
+   bool flipped = false;
 again:
+   bool validDataInClip = false;
    refClipboard = Gtk::Clipboard::get(mGHSelection);
 
-   Debug("%s: trying %s selection, trying again\n",
-          __FUNCTION__,
+   Debug("%s: trying %s selection.\n", __FUNCTION__,
           mGHSelection == GDK_SELECTION_PRIMARY ? "Primary" : "Clip");
 
    CPClipboard_Clear(&mClipboard);
@@ -656,9 +657,8 @@ again:
           bufSize <= (int)CPCLIPITEM_MAX_SIZE_V3 &&
           CPClipboard_SetItem(&mClipboard, CPFORMAT_RTF,
                               (const void *)sdata.get_data(), bufSize + 1)) {
-         mCP.SetRemoteClipboard(&mClipboard);
+         validDataInClip = true;
          Debug("%s: Got RTF\n", __FUNCTION__);
-         return;
       } else {
          Debug("%s: Failed to get RTF size %d max %d\n",
                __FUNCTION__, (int) bufSize, (int)CPCLIPITEM_MAX_SIZE_V3);
@@ -674,26 +674,30 @@ again:
           bufSize <= (int)CPCLIPITEM_MAX_SIZE_V3 &&
           CPClipboard_SetItem(&mClipboard, CPFORMAT_TEXT,
                               (const void *)str.data(), bufSize + 1)) {
-         mCP.SetRemoteClipboard(&mClipboard);
+         validDataInClip = true;
          Debug("%s: Got TEXT: %"FMTSZ"u\n", __FUNCTION__, bufSize);
-         return;
-      } else if (mClipTime == mPrimTime && mClipTime) {
-         /*
-          * With 'cut' operation OpenOffice will put data into clipboard but
-          * set the same timestamp for both clipboard and primary selection.
-          * If primary timestamp is same as clipboard timestamp, we should try
-          * clipboard again if primary selection is empty. For details, please
-          * refer to bug 300780.
-          */
-         mClipTime = 0;
-         mPrimTime = 0;
-         mGHSelection = GDK_SELECTION_CLIPBOARD;
-         Debug("%s: trying again with clip\n", __FUNCTION__);
-         goto again;
       } else {
          Debug("%s: Failed to get TEXT\n", __FUNCTION__);
       }
    }
+
+   if (validDataInClip) {
+      /*
+       * RTF or text data (or both) in the clipboard.
+       */
+      mCP.SetRemoteClipboard(&mClipboard);
+   } else if (!flipped) {
+      /*
+       * If we get here, we got nothing (no image, URI, text) so
+       * try the other selection.
+       */
+      Debug("%s: got nothing for this selection, try the other.\n",
+            __FUNCTION__);
+      mGHSelection = mGHSelection == GDK_SELECTION_PRIMARY ?
+                     GDK_SELECTION_CLIPBOARD : GDK_SELECTION_PRIMARY;
+      flipped = true;
+      goto again;
+   }
 }
 
 
index 3816fe9e7207c3823c75877df18643e28e60cc05..6d2b76d5c78cb9ea89aeca93ecea5ab71a5db4c5 100644 (file)
@@ -62,7 +62,8 @@ const string::size_type string::npos = Glib::ustring::npos;
 
 string::string()
    : mUstr(),
-     mUtf16Cache(NULL)
+     mUtf16Cache(NULL),
+     mUtf16Length(npos)
 {
 }
 
@@ -85,7 +86,8 @@ string::string()
 
 string::string(ConstUnicode s) // IN
    : mUstr(),
-     mUtf16Cache(NULL)
+     mUtf16Cache(NULL),
+     mUtf16Length(npos)
 {
    ASSERT(s);
    mUstr = Unicode_GetUTF8(s);
@@ -118,7 +120,8 @@ string::string(ConstUnicode s) // IN
 
 string::string(const ubstr_t &s) // IN
    : mUstr(),
-     mUtf16Cache(NULL)
+     mUtf16Cache(NULL),
+     mUtf16Length(npos)
 {
    // If the input is empty, then there's nothing to do.
    if (s.length() == 0) {
@@ -153,7 +156,8 @@ string::string(const ubstr_t &s) // IN
 
 string::string(const _bstr_t &s) // IN
    : mUstr(),
-     mUtf16Cache(NULL)
+     mUtf16Cache(NULL),
+     mUtf16Length(npos)
 {
    // If the input is empty, then there's nothing to do.
    if (s.length() == 0) {
@@ -194,7 +198,8 @@ string::string(const _bstr_t &s) // IN
 
 string::string(const utf16string &s) // IN
    : mUstr(),
-     mUtf16Cache(NULL)
+     mUtf16Cache(NULL),
+     mUtf16Length(npos)
 {
    // If the input is empty, then there's nothing to do.
    if (s.empty()) {
@@ -224,7 +229,8 @@ string::string(const utf16string &s) // IN
 
 string::string(const utf16_t *s) // IN
    : mUstr(),
-     mUtf16Cache(NULL)
+     mUtf16Cache(NULL),
+     mUtf16Length(npos)
 {
    ASSERT(s != NULL);
 
@@ -267,7 +273,8 @@ string::string(const utf16_t *s) // IN
 string::string(const char *s,           // IN
                StringEncoding encoding) // IN
    : mUstr(),
-     mUtf16Cache(NULL)
+     mUtf16Cache(NULL),
+     mUtf16Length(npos)
 {
    ASSERT(s != NULL);
 
@@ -309,7 +316,8 @@ string::string(const char *s,           // IN
 
 string::string(const Glib::ustring &s)    // IN
    : mUstr(s.c_str()),
-     mUtf16Cache(NULL)
+     mUtf16Cache(NULL),
+     mUtf16Length(npos)
 {
    ASSERT(Validate(s));
 }
@@ -339,7 +347,8 @@ string::string(const Glib::ustring &s)    // IN
 
 string::string(const string &s) // IN
    : mUstr(s.mUstr.c_str()),
-     mUtf16Cache(NULL)
+     mUtf16Cache(NULL),
+     mUtf16Length(npos)
 {
 }
 
@@ -494,6 +503,7 @@ string::swap(string &s) // IN/OUT
 {
    mUstr.swap(s.mUstr);
    std::swap(mUtf16Cache, s.mUtf16Cache);
+   std::swap(mUtf16Length, s.mUtf16Length);
 }
 
 
@@ -641,6 +651,33 @@ string::size()
 }
 
 
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * utf::string::w_size --
+ *
+ * Results:
+ *      Returns the length of this string, in UTF-16 code units,
+ *      excluding NUL.
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+string::size_type
+string::w_size()
+   const
+{
+   if (mUtf16Length == npos) {
+      mUtf16Length = Unicode_UTF16Strlen(GetUtf16Cache());
+   }
+
+   return mUtf16Length;
+}
+
+
 /*
  *-----------------------------------------------------------------------------
  *
@@ -1739,6 +1776,7 @@ string::InvalidateCache()
 {
    free(mUtf16Cache);
    mUtf16Cache = NULL;
+   mUtf16Length = npos;
 }
 
 
@@ -2185,7 +2223,7 @@ void
 CreateWritableBuffer(const string& s,           // IN:
                      std::vector<utf16_t>& buf) // OUT: A copy of the string, as UTF-16.
 {
-   CopyArray(s.w_str(), Unicode_UTF16Strlen(s.w_str()) + 1, buf);
+   CopyArray(s.w_str(), s.w_size() + 1, buf);
 }
 
 
index 442e78602f9eb89c42351f62079fc2d6eec2c65d..cfc507e7a2bfbdc1bb54d124e75ffa1bcb4c9956 100644 (file)
@@ -129,6 +129,7 @@ public:
    void resize(size_type n, value_type c = '\0');
    bool empty() const;
    size_type size() const;
+   size_type w_size() const;
    size_type length() const;
    size_type bytes() const;
    string foldCase() const;
@@ -219,6 +220,12 @@ private:
 
    // Cached representations.
    mutable utf16_t *mUtf16Cache;
+   mutable size_type mUtf16Length;
+
+   /*
+    * All added members need to be initialized in all constructors and need
+    * to be handled in swap().
+    */
 };
 
 // Helper operators