From: Marcelo Vanzin Date: Wed, 22 Jul 2009 18:02:33 +0000 (-0700) Subject: 2009.07.22-179896 X-Git-Tag: 2009.07.22-179896 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=80b7871e367a968240c2f87ed0b58055c4e37e12;p=thirdparty%2Fopen-vm-tools.git 2009.07.22-179896 --- diff --git a/open-vm-tools/ChangeLog b/open-vm-tools/ChangeLog index ef0914173..1dc113ec9 100644 --- a/open-vm-tools/ChangeLog +++ b/open-vm-tools/ChangeLog @@ -1,3 +1,127 @@ +2009-07-22 Marcelo Vanzin + * Resync with internal trunk (2009.07.17) + + * configure.ac: fix detection of "dot" and its usage in the doxygen config + file. + + * configure.ac, libguestlib/Makefile.am, libguestlib/vmguestlib.pc.in: + install vmguestlib headers and add new pkgconfig script. + + * lib/dndGuest/dnd.{cc,hh}, lib/include/dndBase.h, vmware-user/dndUI.{cpp,h}: + fix an issue where the DnD code would prevent drops to other windows in + Unity mode, instead of just intercepting drops to the desktop. + + * lib/dndGuest/dnd.{cc,hh}, lib/dndGuest/dndRpc.hh, lib/dndGuest/dndRpcV3.cc, + lib/include/dndBase.h, vmware-user/dndUI.{cpp,h}: fix an issue where the + host Unity code would cause an undesired drop event. + + * lib/dndGuest/dnd.{cc,hh}, lib/dndGuest/dndRpc.hh, lib/dndGuest/dndRpcV3.cc, + lib/include/dndBase.h: cleanup mouse simulation code, and fix an issue + where a drag would be canceled if the contents were dragged out of a guest + and then back in. + + * lib/dndGuest/dndRpcV3.cc, vmware-user/copyPasteDnDWrapper.cpp, + vmware-user/dndUI.cpp, vmware-user/dndUI.h, vmware-user/dragDetWnd.cpp, + vmware-user/dragDetWnd.h: several DnD fixes; make the DnD code behave + more like other GTK applications (based on analysing the flow of signals + on a test widget), and get rid of one of the detection windows, merging + both the Unity and non-Unity windows. Also, some code refactoring. + + * lib/ghIntegration/*, lib/guestRpc/*, lib/include/guestCaps.h, + lib/include/unityCommon.h: add stubs for a few new GHI functions (setting + window focus, tray icon updates and enhanced app info) - currently only + implemented on Win32. + + * lib/ghIntegration/ghIntegrationX11.c: examine WM_CLASS when determining + which DE Tools are running in. The previous code was failing to show a + few entries set as "OnlyShowIn=xxx" because checking WM_NAME wasn't enough + to properly detect the desktop environment in certain cases. + + * lib/guestApp/guestAppPosixX11.c: use gconftool-2 to detect the user's + browser, since gnome-open fails to open "file://" URLs which contain query + strings. Also, use "kde-open" when running under KDE. + + * lib/guestInfo/guestInfo.c, lib/include/wiper.h, lib/wiper/wiperPosix.c: + allow shrinking LVM partitions. + + * lib/include/appUtil.h: partial refactoring of icon retrieval code. + + * lib/include/dbllnklst.h, lib/misc/dbllnklst.c: inline linked list + functions. + + * lib/include/guest_os.h, lib/misc/hostinfoPosix.c: add a couple of + distros to the known distro list. + + * lib/include/netutil.h, lib/netUtil/netUtilLinux.c: add Linux interface + name, index lookup routines. + + * lib/include/system.h, lib/system/systemLinux.c, + services/plugins/timeSync/timeSync.c: fixes a few bugs in the backwards + time sync code, mostly due to unit mismatches. + + * lib/include/unityWindowTracker.h, lib/unity/unity.c, + lib/unity/unityPlatform.h, lib/unity/unityPlatformX11Window.c, + lib/unityWindowTracker/unityWindowTracker.c: expose two new properties in + the window tracker to save an RPC to retrieve those properties. + + * lib/include/vmtoolsApp.h, services/vmtoolsd/mainLoop.c, + services/vmtoolsd/pluginMgr.c, services/vmtoolsd/toolsCoreInt.h: add + support for "application providers", which allow plugins to add support to + new kinds of application frameworks through vmtoolsd. + + * lib/unity/unityPlatformX11.c: only enable GIO channels when Unity is + actually active. + + * lib/unity/*: cleanup old GTK1 code. + + * libvmtools/vmtoolsConfig.c: don't complain if config file is empty. + + * modules/linux/dkms.conf, modules/linux/dkms.sh: fix dkms.conf, and provide + a script to create a dkms tree from open-vm-tools. + + * modules/linux/shared/vmci_queue_pair.h, modules/linux/vmci/vmciKernelIf.c: + remove two (now) unneeded functions. + + * modules/linux/vmhgfs/*: code cleanups, properly initialize the list head, + and allow receives to timeout so that hibernation works. + + * modules/linux/vmxnet/vmxnet.c, modules/linux/vmxnet3/vmxnet3_drv.c: fix + drivers for kernels 2.6.29+. + + * modules/linux/vmxnet3/*: add shared memory support for faster communication + between user space and the device backend; this doesn't affect the regular + driver functionality, but is used by some VMware code not part of Tools. + + * modules/linux/vsock/*: fix an issue where it was possible for users to send + VMCI datagrams directly to the hypervisor. + + * scripts/common/vmware-user.desktop: work around a bug in KDE where desktop + files with "NoDisplay" fail to autostart. + + * scripts/freebsd/suspend-vm-default: use netif to bring down interfaces, + since dhclient doesn't understand "-r" in the default install. + + * services/plugins/vmbackup/*: add some new code used by enhancements being + done in the Win32 version of the plugin. + + * services/vmtoolsd/mainPosix.c: fix running in background when executing + vmtoolsd while relying on PATH. + + * services/vmtoolsd/Makefile.am: point to the correct plugin install + directory. + + * toolbox/*: better command line handling in the CLI utility, plus some code + cleanup. + + * vmware-user/copyPaste.c, vmware-user/copyPasteDnDWrapper.cpp, + vmware-user/copyPasteDnDWrapper.h, vmware-user/dnd.c: properly unregister + RPCs to avoid multiple registrations (and the ensuing ASSERT) in certain + cases. + + * vmware-user/copyPasteUI.{cpp,h}: change way data is retrieved from the + clipboard, using the gtk+ clipboard wait APIs (which turn out to be more + reliable than the previous approach). + 2009-06-18 Marcelo Vanzin * Resync with internal trunk (2009.06.15) diff --git a/open-vm-tools/NEWS b/open-vm-tools/NEWS index 629c793cd..d90f591ee 100644 --- a/open-vm-tools/NEWS +++ b/open-vm-tools/NEWS @@ -1,3 +1,13 @@ +open-vm-tools 2009.07.22 changes: + * Better support for dkms by means of a script to help create a dkms tree. + + * "make install" now also installs header files for public libraries, plus + a few fixes to incorrect install behavior. + + * Lots of improvements to the new DnD code. + + * This will be the last release with support for Linux kernels < 2.6.9. + open-vm-tools 2009.06.18 changes: * Mostly a bug fix release. diff --git a/open-vm-tools/configure.ac b/open-vm-tools/configure.ac index 0abc463bf..720b8b3fd 100644 --- a/open-vm-tools/configure.ac +++ b/open-vm-tools/configure.ac @@ -35,10 +35,10 @@ ### Initialization ### -TOOLS_VERSION="2009.06.18" +TOOLS_VERSION="2009.07.22" AC_INIT( [open-vm-tools], - [2009.06.18], + [2009.07.22], [open-vm-tools-devel@lists.sourceforge.net]) # In order to make this configure script auto-detect situations where @@ -887,16 +887,15 @@ if test "$enable_docs" = "yes"; then if test "$have_doxygen" = "no"; then AC_MSG_WARN([doxygen not found; API documentation will not be generated.]) else - AC_CHECK_PROG([HAVE_DOT], - [dot], - [yes], - [no]) - if test "$HAVE_DOT" = "yes"; then - DOT=dot + AC_PATH_PROG([DOT], [dot], []) + if test "$DOT" = ""; then + HAVE_DOT=NO else - DOT= + DOT=`dirname $DOT` + HAVE_DOT=YES fi AC_SUBST([DOT]) + AC_SUBST([HAVE_DOT]) AC_PATH_PROG([MSCGEN], [mscgen], @@ -1226,6 +1225,7 @@ AC_CONFIG_FILES([ \ checkvm/Makefile \ rpctool/Makefile \ libguestlib/Makefile \ + libguestlib/vmguestlib.pc \ libvmtools/Makefile \ xferlogs/Makefile \ modules/Makefile \ diff --git a/open-vm-tools/lib/dict/dictll.c b/open-vm-tools/lib/dict/dictll.c index a1e397bcb..0733b2cdd 100644 --- a/open-vm-tools/lib/dict/dictll.c +++ b/open-vm-tools/lib/dict/dictll.c @@ -97,17 +97,20 @@ XXX document the escaping/unescaping process: rationale for which chars we escap /* -XXX document the dict format: - - whitespaces whitespaces '=' whitespaces whitespaces comment - or - whitespaces whitespaces '=' whitespaces '"' '"' whitespaces comment - - where: - - . does not contain any whitespace or = or pound - . does not contain any double-quote or pound -*/ + * The dictionary line format: + * + * = + * or + * = " " + * + * where + * does not contain any whitespace or = or # + * does not contain any double-quote or # + * does not contain any double-quote + * begins with # and ends at the end of the line + * is a sequence spaces and/or tabs + * and are optional + */ /* @@ -390,15 +393,15 @@ DictLL_MarshalLine(DynBuf *output, // IN/OUT: output buffer if (name) { /* - * Double quote, pound, pipe, 0x7F, and all control characters but + * Double quote, pipe, 0x7F, and all control characters but * tab --hpreg - * XXX Why 7F? Why not also 84 and 85 and 90 which do funny things in a - * xterm? + * 0x80 to 0xff are unescaped so characters in encodings + * like UTF-8 will be displayed normally. */ static int const toEscape[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, diff --git a/open-vm-tools/lib/dnd/dndCommon.c b/open-vm-tools/lib/dnd/dndCommon.c index 5c7789c55..9ee37d71e 100644 --- a/open-vm-tools/lib/dnd/dndCommon.c +++ b/open-vm-tools/lib/dnd/dndCommon.c @@ -342,6 +342,7 @@ DnDPrependFileRoot(ConstUnicode fileRoot, // IN : file root to append * assume that the components are delimited with single NUL characters; if * that is not true, CPName_GetComponent() will fail. */ + for (begin = *src; *begin == '\0'; begin++) ; end = CPNameUtil_Strrchr(*src, *srcSize, '\0'); @@ -352,10 +353,11 @@ DnDPrependFileRoot(ConstUnicode fileRoot, // IN : file root to append int escapedLen; if (len < 0) { - Log("DnDPrependFileRoot: error getting next component\n"); + Log("%s: error getting next component\n", __FUNCTION__); if (!firstPass) { free(newData); } + return FALSE; } @@ -363,6 +365,7 @@ DnDPrependFileRoot(ConstUnicode fileRoot, // IN : file root to append * Append this component to our list: allocate one more for NUL on first * pass and delimiter on all other passes. */ + escapedLen = HgfsEscape_GetSize(begin, len); if (0 == escapedLen) { newDataLen += rootLen + len + 1; @@ -474,13 +477,14 @@ DnD_LegacyConvertToCPName(const char *nameIn, // IN: Buffer to convert memcpy(fullName + partialNameLen + partialNameSuffixLen, nameIn, nameSize); fullName[fullNameSize] = '\0'; - LOG(4, ("DnD_LegacyConvertToCPName: generated name is \"%s\"\n", fullName)); + LOG(4, ("%s: generated name is \"%s\"\n", __FUNCTION__, fullName)); /* * CPName_ConvertTo implementation is performed here without calling any * CPName_ functions. This is safer since those functions might change, but * the legacy behavior we are special casing here will not. */ + { char const *winNameIn = fullName; char const *origOut = bufOut; @@ -497,6 +501,7 @@ DnD_LegacyConvertToCPName(const char *nameIn, // IN: Buffer to convert * Copy the string to the output buf, converting all path separators into * '\0' and ignoring the specified characters. */ + for (; *winNameIn != '\0' && bufOut < endOut; winNameIn++) { if (ignores) { char *currIgnore = ignores; @@ -526,6 +531,7 @@ DnD_LegacyConvertToCPName(const char *nameIn, // IN: Buffer to convert * When we get rid of NUL termination here, this test should * also change to "if (*winNameIn != '\0')". */ + if (bufOut == endOut) { result = -1; goto out; @@ -541,13 +547,18 @@ DnD_LegacyConvertToCPName(const char *nameIn, // IN: Buffer to convert result--; } - /* Make exception and call CPName_Print() here, since it's only for logging */ - LOG(4, ("DnD_LegacyConvertToCPName: CPName is \"%s\"\n", + /* + * Make exception and call CPName_Print() here, since it's only for + * logging + */ + + LOG(4, ("%s: CPName is \"%s\"\n", __FUNCTION__, CPName_Print(origOut, result))); } out: free(fullName); + return result; } diff --git a/open-vm-tools/lib/dndGuest/copyPasteRpcV3.cc b/open-vm-tools/lib/dndGuest/copyPasteRpcV3.cc index d413aa47c..1d10b4bc1 100644 --- a/open-vm-tools/lib/dndGuest/copyPasteRpcV3.cc +++ b/open-vm-tools/lib/dndGuest/copyPasteRpcV3.cc @@ -233,6 +233,33 @@ CopyPasteRpcV3::OnRecvMsg(const uint8 *data, // IN switch (DnDMsg_GetCmd(&msg)) { case CP_GH_GET_CLIPBOARD: ghGetClipboardChanged.emit(); +#if defined (DND_TRANSPORT_TEST) + /* Sending 60 packets to host side to test transport. */ + for (uint32 i = 1; i < 60; i++) { + DnDMsg msg; + DynBuf buf; + + DnDMsg_Init(&msg); + DynBuf_Init(&buf); + + DnDMsg_SetCmd(&msg, CP_GH_TRANSPORT_TEST); + if (!DnDMsg_AppendArg(&msg, &i, sizeof i)) { + Debug("%s: DnDMsg_AppendData failed.\n", __FUNCTION__); + goto error; + } + + if (!DnDMsg_Serialize(&msg, &buf)) { + Debug("%s: DnDMsg_Serialize failed.\n", __FUNCTION__); + goto error; + } + + mTransport->SendMsg((uint8 *)DynBuf_Get(&buf), DynBuf_GetSize(&buf)); + + error: + DynBuf_Destroy(&buf); + DnDMsg_Destroy(&msg); + } +#endif break; case CP_HG_SET_CLIPBOARD: { diff --git a/open-vm-tools/lib/dndGuest/dnd.cc b/open-vm-tools/lib/dndGuest/dnd.cc index a837a20c3..c4dc8c164 100644 --- a/open-vm-tools/lib/dndGuest/dnd.cc +++ b/open-vm-tools/lib/dndGuest/dnd.cc @@ -34,8 +34,9 @@ extern "C" { #include "eventManager.h" } -#define UNGRAB_TIMEOUT 50 // 0.5 s -#define HIDE_DET_WND_TIMER 50 // 0.5s +#define UNGRAB_TIMEOUT 50 // 0.5 s +#define UNITY_DND_DET_TIMEOUT 50 // 0.5 s +#define HIDE_DET_WND_TIMER 50 // 0.5s /* @@ -55,7 +56,7 @@ extern "C" { */ static Bool -DnDUngrabTimeout(void *clientData) // IN +DnDUngrabTimeout(void *clientData) // IN { ASSERT(clientData); DnD *dnd = (DnD *)clientData; @@ -64,6 +65,32 @@ DnDUngrabTimeout(void *clientData) // IN } +/* + *--------------------------------------------------------------------- + * + * DnDUnityDetTimeout -- + * + * UnityDnDDetTimeout callback for GH DnD. + * + * Results: + * Always TRUE. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------- + */ + +static Bool +DnDUnityDetTimeout(void *clientData) // IN +{ + ASSERT(clientData); + DnD *dnd = (DnD *)clientData; + dnd->UnityDnDDetTimeout(); + return TRUE; +} + + /* *--------------------------------------------------------------------- * @@ -114,6 +141,7 @@ DnD::DnD(DblLnkLst_Links *eventQueue) // IN mDnDAllowed(false), mStagingDir(""), mUngrabTimeout(NULL), + mUnityDnDDetTimeout(NULL), mHideDetWndTimer(NULL), mEventQueue(eventQueue) { @@ -153,6 +181,10 @@ DnD::~DnD(void) EventManager_Remove(mUngrabTimeout); mUngrabTimeout = NULL; } + if (mUnityDnDDetTimeout) { + EventManager_Remove(mUnityDnDDetTimeout); + mUnityDnDDetTimeout = NULL; + } } @@ -207,6 +239,10 @@ DnD::VmxDnDVersionChanged(struct RpcIn *rpcIn, // IN sigc::mem_fun(this, &DnD::OnGHUpdateUnityDetWnd)); mRpc->ghQueryPendingDragChanged.connect( sigc::mem_fun(this, &DnD::OnGHQueryPendingDrag)); + mRpc->moveDetWndToMousePos.connect( + sigc::mem_fun(this, &DnD::OnMoveDetWndToMousePos)); + mRpc->ghPrivateDropChanged.connect( + sigc::mem_fun(this, &DnD::OnGHPrivateDrop)); mRpc->ghCancelChanged.connect( sigc::mem_fun(this, &DnD::OnGHCancel)); mRpc->hgDragEnterChanged.connect( @@ -617,15 +653,46 @@ DnD::OnGHUpdateUnityDetWnd(bool bShow, // IN * this window to accept drop in cancel case. */ UpdateDetWnd(bShow, 1, 1); + if (mUnityDnDDetTimeout) { + EventManager_Remove(mUnityDnDDetTimeout); + mUnityDnDDetTimeout = NULL; + } + mUnityDnDDetTimeout = EventManager_Add(mEventQueue, UNITY_DND_DET_TIMEOUT, + DnDUnityDetTimeout, this); } /* Show/hide the full screent detection window. */ - updateUnityDetWndChanged.emit(bShow, unityWndId); + updateUnityDetWndChanged.emit(bShow, unityWndId, false); Debug("%s: updating Unity detection window, bShow %d, id %u\n", __FUNCTION__, bShow, unityWndId); } +/* + *---------------------------------------------------------------------- + * + * DnD::UnityDnDDetTimeout -- + * + * Can not detect pending GH DnD within UNITY_DND_DET_TIMEOUT, put + * the full screen detection window to bottom most. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +DnD::UnityDnDDetTimeout(void) +{ + mUnityDnDDetTimeout = NULL; + updateUnityDetWndChanged.emit(true, 0, true); +} + + /* *---------------------------------------------------------------------- * @@ -768,6 +835,60 @@ DnD::DragEnter(const CPClipboard *clip) } +/* + *---------------------------------------------------------------------- + * + * DnD::OnMoveDetWndToMousePos -- + * + * Move detection windows to current cursor position to prevent + * unexpected drop. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +DnD::OnMoveDetWndToMousePos(void) +{ + Debug("%s: entering\n", __FUNCTION__); + moveDetWndToMousePos.emit(); +} + + +/* + *---------------------------------------------------------------------- + * + * DnD::OnGHPrivateDrop -- + * + * User started a GH DnD, dragged back to VM and dropped. In guest + * side we should simulate the drop, hide detection window and reset + * the state machine. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +DnD::OnGHPrivateDrop(int32 x, // IN + int32 y) // IN +{ + targetPrivateDropChanged.emit(x, y); + updateDetWndChanged.emit(false, 0, 0); + mState = DNDSTATE_READY; + Debug("%s: state changed to READY\n", __FUNCTION__); +} + + /* *---------------------------------------------------------------------- * diff --git a/open-vm-tools/lib/dndGuest/dnd.hh b/open-vm-tools/lib/dndGuest/dnd.hh index b87f7c6f4..326e5c089 100644 --- a/open-vm-tools/lib/dndGuest/dnd.hh +++ b/open-vm-tools/lib/dndGuest/dnd.hh @@ -65,6 +65,7 @@ class DnD void SetDnDAllowed(bool isDnDAllowed) { mDnDAllowed = isDnDAllowed; } void UngrabTimeout(void); + void UnityDnDDetTimeout(void); void ResetDnD(void); void HGDragStartDone(void); void OnUpdateMouse(int32 x, int32 y); @@ -75,6 +76,7 @@ class DnD /* Callbacks from rpc. */ void OnGHUpdateUnityDetWnd(bool bShow, uint32 unityWndId); void OnGHQueryPendingDrag(int x, int y); + void OnGHPrivateDrop(int32 x, int32 y); void OnGHCancel(void); void OnHGDragEnter(const CPClipboard *clip); void OnHGDragStart(void); @@ -82,6 +84,7 @@ class DnD void OnHGDrop(void); void OnHGFileCopyDone(bool cancel, std::vector stagingDir); + void OnMoveDetWndToMousePos(void); std::string SetupDestDir(const std::string &destDir); @@ -90,6 +93,7 @@ class DnD bool mDnDAllowed; std::string mStagingDir; Event *mUngrabTimeout; + Event *mUnityDnDDetTimeout; Event *mHideDetWndTimer; DblLnkLst_Links *mEventQueue; }; diff --git a/open-vm-tools/lib/dndGuest/dndRpc.hh b/open-vm-tools/lib/dndGuest/dndRpc.hh index 2712c1022..f8adbaf26 100644 --- a/open-vm-tools/lib/dndGuest/dndRpc.hh +++ b/open-vm-tools/lib/dndGuest/dndRpc.hh @@ -41,6 +41,7 @@ class DnDRpc /* sigc signals for callback. */ sigc::signal ghUpdateUnityDetWndChanged; sigc::signal ghQueryPendingDragChanged; + sigc::signalghPrivateDropChanged; sigc::signal ghCancelChanged; sigc::signal hgDragEnterChanged; sigc::signal hgDragStartChanged; @@ -48,6 +49,7 @@ class DnDRpc sigc::signal hgDropChanged; sigc::signal > hgFileCopyDoneChanged; sigc::signal updateMouseChanged; + sigc::signal moveDetWndToMousePos; /* GH DnD. */ virtual bool GHDragEnter(const CPClipboard *clip) = 0; @@ -61,6 +63,7 @@ class DnDRpc protected: uint32 mHostMinorVersion; + uint32 mGuestMinorVersion; }; #endif // DND_RPC_HH diff --git a/open-vm-tools/lib/dndGuest/dndRpcV3.cc b/open-vm-tools/lib/dndGuest/dndRpcV3.cc index 40c82cbe4..9e437a9d1 100644 --- a/open-vm-tools/lib/dndGuest/dndRpcV3.cc +++ b/open-vm-tools/lib/dndGuest/dndRpcV3.cc @@ -54,11 +54,10 @@ DnDRpcV3::DnDRpcV3(struct RpcIn *rpcIn) // IN mTransport->recvMsgChanged.connect(sigc::mem_fun(this, &DnDRpcV3::OnRecvMsg)); mHostMinorVersion = 0; + mGuestMinorVersion = 0; /* Tell host that current DnD version in guest side is 3.1. */ - /* XXX Windows only for now. Linux implementation will be in shortly. */ -#if defined (_WIN32) - UpdateGuestVersion(3, 1); -#endif // _WIN32 + mGuestMinorVersion = 1; + UpdateGuestVersion(3, mGuestMinorVersion); } @@ -557,6 +556,34 @@ DnDRpcV3::OnRecvMsg(const uint8 *data, // IN break; } hgDragEnterChanged.emit(&clip); + +#if defined (DND_TRANSPORT_TEST) + /* Sending 60 packets to host side to test transport. */ + for (uint32 i = 1; i < 60; i++) { + DnDMsg msg; + DynBuf buf; + + DnDMsg_Init(&msg); + DynBuf_Init(&buf); + + DnDMsg_SetCmd(&msg, DND_GH_TRANSPORT_TEST); + if (!DnDMsg_AppendArg(&msg, &i, sizeof i)) { + Debug("%s: DnDMsg_AppendData failed.\n", __FUNCTION__); + goto error; + } + + if (!DnDMsg_Serialize(&msg, &buf)) { + Debug("%s: DnDMsg_Serialize failed.\n", __FUNCTION__); + goto error; + } + + mTransport->SendMsg((uint8 *)DynBuf_Get(&buf), DynBuf_GetSize(&buf)); + + error: + DynBuf_Destroy(&buf); + DnDMsg_Destroy(&msg); + } +#endif break; } case DND_HG_DRAG_START: @@ -614,6 +641,33 @@ DnDRpcV3::OnRecvMsg(const uint8 *data, // IN updateMouseChanged.emit(x, y); break; } + case DND_GH_PRIVATE_DROP: + { + int32 x = 0; + int32 y = 0; + + buf = DnDMsg_GetArg(&msg, 0); + if (DynBuf_GetSize(buf) == sizeof(int32)) { + memcpy(&x, (const char *)DynBuf_Get(buf), sizeof(int32)); + } else { + break; + } + + buf = DnDMsg_GetArg(&msg, 1); + if (DynBuf_GetSize(buf) == sizeof(int32)) { + memcpy(&y, (const char *)DynBuf_Get(buf), sizeof(int32)); + } else { + break; + } + + ghPrivateDropChanged.emit(x, y); + break; + } + case DND_MOVE_DET_WND_TO_MOUSE_POS: + { + moveDetWndToMousePos.emit(); + break; + } case DND_UPDATE_HOST_VERSION: { uint32 major = 0; @@ -635,6 +689,7 @@ DnDRpcV3::OnRecvMsg(const uint8 *data, // IN } Debug("%s: got host DnD version %d.%d.\n", __FUNCTION__, major, mHostMinorVersion); + UpdateGuestVersion(3, mGuestMinorVersion); break; } default: diff --git a/open-vm-tools/lib/file/file.c b/open-vm-tools/lib/file/file.c index 9ad6e8636..10833932e 100644 --- a/open-vm-tools/lib/file/file.c +++ b/open-vm-tools/lib/file/file.c @@ -30,6 +30,7 @@ #include "safetime.h" #if defined(_WIN32) #include +#define S_IXUSR 0100 #else #include #endif @@ -148,6 +149,45 @@ File_IsDirectory(ConstUnicode pathName) // IN: } +/* + *----------------------------------------------------------------------------- + * + * File_GetFilePermissions -- + * + * Return the read / write / execute permissions of a file. + * + * Results: + * TRUE if success, FALSE otherwise. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +Bool +File_GetFilePermissions(ConstUnicode pathName, // IN: + int *mode) // OUT: file mode +{ + FileData fileData; + + ASSERT(mode); + if (FileAttributes(pathName, &fileData) != 0) { + return FALSE; + } + *mode = fileData.fileMode; +#ifdef _WIN32 + /* + * On Win32 implementation of FileAttributes does not return execution bit. + */ + if (FileIO_Access(pathName, FILEIO_ACCESS_EXEC) == FILEIO_SUCCESS) { + *mode |= S_IXUSR; + } +#endif + return TRUE; +} + + /* *---------------------------------------------------------------------- * @@ -1674,6 +1714,79 @@ File_SupportsLargeFiles(ConstUnicode pathName) // IN: } +/* + *----------------------------------------------------------------------------- + * + * File_MapPathPrefix -- + * + * Given a path and a newPrefix -> oldPrefix mapping, transform + * oldPath according to the mapping. + * + * Results: + * The new path, or NULL if there is no mapping. + * + * Side effects: + * The returned string is allocated, free it. + * + *----------------------------------------------------------------------------- + */ + +char * +File_MapPathPrefix(const char *oldPath, // IN + const char **oldPrefixes, // IN + const char **newPrefixes, // IN + size_t numPrefixes) // IN +{ + int i; + size_t oldPathLen = strlen(oldPath); + + for (i = 0; i < numPrefixes; i++) { + char *newPath; + char *oldPrefix; + char *newPrefix; + size_t oldPrefixLen; + + oldPrefix = File_StripSlashes(oldPrefixes[i]); + newPrefix = File_StripSlashes(newPrefixes[i]); + oldPrefixLen = strlen(oldPrefix); + + /* + * If the prefix matches on a DIRSEPS boundary, or the prefix is the + * whole string, replace it. + * If we don't insist on matching a whole directory name, we could + * mess things of if one directory is a substring of another. + */ + + if (oldPathLen >= oldPrefixLen && + memcmp(oldPath, oldPrefix, oldPrefixLen) == 0 + && (strchr(VALID_DIRSEPS, oldPath[oldPrefixLen]) || + oldPath[oldPrefixLen] == '\0')) { + size_t newPrefixLen = strlen(newPrefix); + size_t newPathLen = (oldPathLen - oldPrefixLen) + newPrefixLen; + + ASSERT(newPathLen > 0); + ASSERT(oldPathLen >= oldPrefixLen); + + newPath = Util_SafeMalloc((newPathLen + 1) * sizeof(char)); + memcpy(newPath, newPrefix, newPrefixLen); + memcpy(newPath + newPrefixLen, oldPath + oldPrefixLen, + oldPathLen - oldPrefixLen + 1); + /* + * It should only match once. Weird self-referencing mappings + * aren't allowed. + */ + free(oldPrefix); + free(newPrefix); + return newPath; + } + free(oldPrefix); + free(newPrefix); + } + + return NULL; +} + + #if !defined(N_PLAT_NLM) /* *---------------------------------------------------------------------------- diff --git a/open-vm-tools/lib/file/fileIOPosix.c b/open-vm-tools/lib/file/fileIOPosix.c index 7279b99c4..d07a8c5b8 100644 --- a/open-vm-tools/lib/file/fileIOPosix.c +++ b/open-vm-tools/lib/file/fileIOPosix.c @@ -96,6 +96,23 @@ #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 + */ +#ifdef __linux__ + #ifndef SYS_fallocate + #ifdef __i386__ + #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 +#endif + static const unsigned int FileIO_SeekOrigins[] = { SEEK_SET, SEEK_CUR, @@ -1296,6 +1313,7 @@ FileIOCoalesce(struct iovec *inVec, // IN: Vector to coalesce from size_t inTotalSize, // IN: totalSize (bytes) in inVec Bool isWrite, // IN: coalesce for writing (or reading) Bool forceCoalesce, // IN: if TRUE always coalesce + int flags, // IN: fileIO open flags struct iovec *outVec) // OUT: Coalesced (1-entry) iovec { uint8 *cBuf; @@ -1324,7 +1342,7 @@ FileIOCoalesce(struct iovec *inVec, // IN: Vector to coalesce from // XXX: Wouldn't it be nice if we could log from here! //LOG(5, ("FILE: Coalescing %s of %d elements and %d size\n", // isWrite ? "write" : "read", inCount, inTotalSize)); - if (filePosixOptions.aligned) { + if (filePosixOptions.aligned || flags & FILEIO_OPEN_UNBUFFERED) { cBuf = Aligned_Malloc(sizeof(uint8) * inTotalSize); } else { cBuf = Util_SafeMalloc(sizeof(uint8) * inTotalSize); @@ -1366,7 +1384,8 @@ FileIODecoalesce(struct iovec *coVec, // IN: Coalesced (1-entry) vector struct iovec *origVec, // IN: Original vector int origVecCount, // IN: count for origVec size_t actualSize, // IN: # bytes to transfer back to origVec - Bool isWrite) // IN: decoalesce for writing (or reading) + Bool isWrite, // IN: decoalesce for writing (or reading) + int flags) // IN: fileIO open flags { ASSERT(coVec); ASSERT(origVec); @@ -1378,7 +1397,7 @@ FileIODecoalesce(struct iovec *coVec, // IN: Coalesced (1-entry) vector IOV_WriteBufToIov(coVec->iov_base, actualSize, origVec, origVecCount); } - if (filePosixOptions.aligned) { + if (filePosixOptions.aligned || flags & FILEIO_OPEN_UNBUFFERED) { Aligned_Free(coVec->iov_base); } else { free(coVec->iov_base); @@ -1426,7 +1445,8 @@ FileIO_Readv(FileIODescriptor *fd, // IN ASSERT(fd); - didCoalesce = FileIOCoalesce(v, numEntries, totalSize, FALSE, FALSE, &coV); + didCoalesce = FileIOCoalesce(v, numEntries, totalSize, FALSE, + FALSE, fd->flags, &coV); STAT_INST_INC(fd->stats, NumReadvs); STAT_INST_INC_BY(fd->stats, BytesReadv, totalSize); @@ -1491,7 +1511,7 @@ FileIO_Readv(FileIODescriptor *fd, // IN } if (didCoalesce) { - FileIODecoalesce(&coV, v, numEntries, bytesRead, FALSE); + FileIODecoalesce(&coV, v, numEntries, bytesRead, FALSE, fd->flags); } if (actual) { @@ -1541,7 +1561,8 @@ FileIO_Writev(FileIODescriptor *fd, // IN ASSERT(fd); - didCoalesce = FileIOCoalesce(v, numEntries, totalSize, TRUE, FALSE, &coV); + didCoalesce = FileIOCoalesce(v, numEntries, totalSize, TRUE, + FALSE, fd->flags, &coV); STAT_INST_INC(fd->stats, NumWritevs); STAT_INST_INC_BY(fd->stats, BytesWritev, totalSize); @@ -1589,7 +1610,7 @@ FileIO_Writev(FileIODescriptor *fd, // IN } if (didCoalesce) { - FileIODecoalesce(&coV, v, numEntries, bytesWritten, TRUE); + FileIODecoalesce(&coV, v, numEntries, bytesWritten, TRUE, fd->flags); } if (actual) { @@ -1641,8 +1662,7 @@ FileIO_Preadv(FileIODescriptor *fd, // IN: File descriptor ASSERT_NOT_IMPLEMENTED(totalSize < 0x80000000); didCoalesce = FileIOCoalesce(entries, numEntries, totalSize, FALSE, - TRUE /* force coalescing */, - &coV); + TRUE /* force coalescing */, fd->flags, &coV); count = didCoalesce ? 1 : numEntries; vPtr = didCoalesce ? &coV : entries; @@ -1695,7 +1715,7 @@ FileIO_Preadv(FileIODescriptor *fd, // IN: File descriptor exit: if (didCoalesce) { - FileIODecoalesce(&coV, entries, numEntries, sum, FALSE); + FileIODecoalesce(&coV, entries, numEntries, sum, FALSE, fd->flags); } return fret; @@ -1742,8 +1762,7 @@ FileIO_Pwritev(FileIODescriptor *fd, // IN: File descriptor ASSERT_NOT_IMPLEMENTED(totalSize < 0x80000000); didCoalesce = FileIOCoalesce(entries, numEntries, totalSize, TRUE, - TRUE /* force coalescing */, - &coV); + TRUE /* force coalescing */, fd->flags, &coV); count = didCoalesce ? 1 : numEntries; vPtr = didCoalesce ? &coV : entries; @@ -1800,7 +1819,7 @@ FileIO_Pwritev(FileIODescriptor *fd, // IN: File descriptor fret = FILEIO_SUCCESS; exit: if (didCoalesce) { - FileIODecoalesce(&coV, entries, numEntries, sum, TRUE); + FileIODecoalesce(&coV, entries, numEntries, sum, TRUE, fd->flags); } return fret; @@ -1892,26 +1911,36 @@ Bool FileIO_SetAllocSize(const FileIODescriptor *fd, // IN uint64 size) // IN { + +#if defined(__APPLE__) || defined(__linux__) + uint64 curSize; + uint64 preallocLen; #ifdef __APPLE__ fstore_t prealloc; - uint64 curSize; +#endif curSize = FileIO_GetAllocSize(fd); - if (curSize > size) { errno = EINVAL; return FALSE; - } + } + preallocLen = size - curSize; +#ifdef __APPLE__ prealloc.fst_flags = 0; prealloc.fst_posmode = F_PEOFPOSMODE; prealloc.fst_offset = 0; - prealloc.fst_length = size - curSize; + prealloc.fst_length = preallocLen; prealloc.fst_bytesalloc = 0; return fcntl(fd->posix, F_PREALLOCATE, &prealloc) != -1; +#elif __linux__ + return syscall(SYS_fallocate, fd->posix, FALLOC_FL_KEEP_SIZE, + curSize, preallocLen) == 0; +#endif + #else - errno = EINVAL; + errno = ENOSYS; return FALSE; #endif } diff --git a/open-vm-tools/lib/file/fileLockPosix.c b/open-vm-tools/lib/file/fileLockPosix.c index 7fae809ba..c2a2ffa2f 100644 --- a/open-vm-tools/lib/file/fileLockPosix.c +++ b/open-vm-tools/lib/file/fileLockPosix.c @@ -379,7 +379,7 @@ GetLockFileValues(const char *lockFileName, // IN: /* *---------------------------------------------------------------------- * - * IsValidProcess -- + * FileLockIsValidProcess -- * * Determine if the process, via its pid, is valid (alive). * @@ -394,7 +394,7 @@ GetLockFileValues(const char *lockFileName, // IN: */ static Bool -IsValidProcess(int pid) // IN: +FileLockIsValidProcess(int pid) // IN: { uid_t uid; int err; @@ -432,7 +432,7 @@ IsValidProcess(int pid) // IN: /* *---------------------------------------------------------------------- * - * CreateLockFile -- + * FileLockCreateLockFile -- * * Create a new lock file, either via a O_EXCL creat() call or * through the linking method. @@ -449,9 +449,9 @@ IsValidProcess(int pid) // IN: */ static int -CreateLockFile(const char *lockFileName, // IN: - const char *lockFileLink, // IN: - const char *uniqueID) // IN: +FileLockCreateLockFile(const char *lockFileName, // IN: + const char *lockFileLink, // IN: + const char *uniqueID) // IN: { int err; int lockFD; @@ -527,6 +527,7 @@ exit: } } + return status; } @@ -572,14 +573,14 @@ FileLock_LockDevice(const char *deviceName) // IN: deviceName, FileLockGetPid()); LOG(1, ("Requesting lock %s (temp = %s).\n", lockFileName, - lockFileLink)); + lockFileLink)); hostID = FileLockGetMachineID(); Str_Sprintf(uniqueID, sizeof uniqueID, "%d %s\n", FileLockGetPid(), hostID); - while ((status = CreateLockFile(lockFileName, lockFileLink, - uniqueID)) == 0) { + while ((status = FileLockCreateLockFile(lockFileName, lockFileLink, + uniqueID)) == 0) { int pid; char fileID[1000]; @@ -602,17 +603,17 @@ FileLock_LockDevice(const char *deviceName) // IN: } if (strcmp(hostID, fileID) != 0) { - // Lock was acquired by a different host. + /* Lock was acquired by a different host. */ status = 0; goto exit; } - if (IsValidProcess(pid)) { + if (FileLockIsValidProcess(pid)) { status = 0; goto exit; } - // stale lock + /* stale lock */ if (!RemoveStaleLockFile(lockFileName)) { status = -1; goto exit; @@ -872,7 +873,7 @@ FileLockValidOwner(const char *executionID, // IN: return TRUE; } - if (!IsValidProcess(pid)) { + if (!FileLockIsValidProcess(pid)) { return FALSE; } @@ -933,7 +934,7 @@ FileLockOpenFile(ConstUnicode pathName, // IN: *handle = PosixFileOpener(pathName, flags, 0644); - return *handle == -1 ? errno : 0; + return (*handle == -1) ? errno : 0; } @@ -957,7 +958,7 @@ FileLockOpenFile(ConstUnicode pathName, // IN: int FileLockCloseFile(FILELOCK_FILE_HANDLE handle) // IN: { - return close(handle) == -1 ? errno : 0; + return (close(handle) == -1) ? errno : 0; } diff --git a/open-vm-tools/lib/file/fileLockPrimitive.c b/open-vm-tools/lib/file/fileLockPrimitive.c index 75c42e278..64b475b10 100644 --- a/open-vm-tools/lib/file/fileLockPrimitive.c +++ b/open-vm-tools/lib/file/fileLockPrimitive.c @@ -95,8 +95,8 @@ typedef struct parse_table */ static int -Sleeper(LockValues *myValues, // IN/OUT: - uint32 *loopCount) // IN/OUT: +Sleeper(LockValues *myValues, // IN/OUT: + uint32 *loopCount) // IN/OUT: { uint32 msecSleepTime; @@ -266,11 +266,11 @@ FileLockParseArgs(char *argv[], // IN: #define FL_MAX_ARGS 16 int -FileLockMemberValues(ConstUnicode lockDir, // IN: - ConstUnicode fileName, // IN: - char *buffer, // OUT: - uint32 requiredSize, // IN: - LockValues *memberValues) // OUT: +FileLockMemberValues(ConstUnicode lockDir, // IN: + ConstUnicode fileName, // IN: + char *buffer, // OUT: + uint32 requiredSize, // IN: + LockValues *memberValues) // OUT: { uint32 argc = 0; FILELOCK_FILE_HANDLE handle; @@ -465,7 +465,7 @@ bail: */ Bool -FileLockValidName(ConstUnicode fileName) // IN: +FileLockValidName(ConstUnicode fileName) // IN: { uint32 i; @@ -886,7 +886,7 @@ Scanner(ConstUnicode lockDir, // IN: FileSleeper(FILELOCK_PROGRESS_SAMPLE); // relax } - // Clean up anything still on the list; they are no longer important + /* Clean up anything still on the list; they are no longer important */ while (myValues->lockList != NULL) { ptr = myValues->lockList; myValues->lockList = ptr->next; @@ -990,10 +990,10 @@ FileUnlockIntrinsic(ConstUnicode pathName, // IN: */ static int -WaitForPossession(ConstUnicode lockDir, // IN: - ConstUnicode fileName, // IN: - LockValues *memberValues, // IN: - LockValues *myValues) // IN: +WaitForPossession(ConstUnicode lockDir, // IN: + ConstUnicode fileName, // IN: + LockValues *memberValues, // IN: + LockValues *myValues) // IN: { int err = 0; @@ -1116,8 +1116,8 @@ NumberScan(ConstUnicode lockDir, // IN: */ static uint32 -SimpleRandomNumber(const char *machineID, // IN: - const char *executionID) // IN: +SimpleRandomNumber(const char *machineID, // IN: + const char *executionID) // IN: { static Atomic_Ptr atomic; /* Implicitly initialized to NULL. --mbellon */ char *context; @@ -1675,10 +1675,10 @@ bail: */ static int -ScannerVMX(ConstUnicode lockDir, // IN: - ConstUnicode fileName, // IN: - LockValues *memberValues, // IN: - LockValues *myValues) // IN/OUT: +ScannerVMX(ConstUnicode lockDir, // IN: + ConstUnicode fileName, // IN: + LockValues *memberValues, // IN: + LockValues *myValues) // IN/OUT: { ASSERT(lockDir); ASSERT(fileName); diff --git a/open-vm-tools/lib/file/filePosix.c b/open-vm-tools/lib/file/filePosix.c index 772e51c6e..2912f888e 100644 --- a/open-vm-tools/lib/file/filePosix.c +++ b/open-vm-tools/lib/file/filePosix.c @@ -819,6 +819,37 @@ File_SetTimes(ConstUnicode pathName, // IN: } +/* + *---------------------------------------------------------------------- + * + * File_SetFilePermissions -- + * + * Set file permissions. + * + * Results: + * TRUE if succeed or FALSE if error. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Bool +File_SetFilePermissions(ConstUnicode pathName, // IN: + int perms) // IN: permissions +{ + ASSERT(pathName); + if (Posix_Chmod(pathName, perms) == -1) { + /* The error is not critical, just log it. */ + Log(LGPFX" %s: failed to change permissions on file \"%s\": %s\n", __FUNCTION__, + UTF8(pathName), strerror(errno)); + return FALSE; + } + return TRUE; +} + + #if !defined(__FreeBSD__) && !defined(sun) /* *----------------------------------------------------------------------------- @@ -2787,3 +2818,36 @@ 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; +} diff --git a/open-vm-tools/lib/foundryMsg/foundryMsg.c b/open-vm-tools/lib/foundryMsg/foundryMsg.c index 73c45e433..6dc351976 100644 --- a/open-vm-tools/lib/foundryMsg/foundryMsg.c +++ b/open-vm-tools/lib/foundryMsg/foundryMsg.c @@ -257,9 +257,8 @@ static const VixCommandInfo vixCommandInfoTable[] = { VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_OPEN_TEAM, VIX_COMMAND_CATEGORY_PRIVILEGED), - VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_FIND_HOST_DEVICES, - VIX_COMMAND_CATEGORY_PRIVILEGED), - + VIX_DEFINE_UNUSED_COMMAND, + VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_ANSWER_MESSAGE, VIX_COMMAND_CATEGORY_PRIVILEGED), @@ -422,6 +421,15 @@ static const VixCommandInfo vixCommandInfoTable[] = { VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_LIST_FILESYSTEMS, VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), + VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_CHANGE_DISPLAY_TOPOLOGY, + VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), + + VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_SUSPEND_AND_RESUME, + VIX_COMMAND_CATEGORY_PRIVILEGED), + + VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_REMOVE_BULK_SNAPSHOT, + VIX_COMMAND_CATEGORY_PRIVILEGED), + }; @@ -1315,7 +1323,7 @@ abort: * * VixAsyncOp_ValidateCommandInfoTable -- * - * Checkes that the command info table is generally well-formed. + * Checks that the command info table is generally well-formed. * Makes sure that the table is big enough to contain all the * command op codes and that they are present in the right order. * @@ -1461,3 +1469,165 @@ VixGetCommandInfoForOpCode(int opCode) // IN return commandInfo; } // VixGetCommandInfoForOpCode + + +/* + *----------------------------------------------------------------------------- + * + * VixMsg_AllocGenericRequestMsg -- + * + * Allocate and initialize a generic request message. + * + * Assumes the caller holds the lock to 'propertyList'. + * + * Results: + * Returns VixError. + * Upon retrun, *request will contain either the message with the + * headers properly initialized or NULL. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +VixError +VixMsg_AllocGenericRequestMsg(int opCode, // IN + uint64 cookie, // IN + int credentialType, // IN + const char *userNamePassword, // IN + int options, // IN + VixPropertyListImpl *propertyList, // IN + VixCommandGenericRequest **request) // OUT +{ + VixError err; + VixCommandGenericRequest *requestLocal = NULL; + size_t msgHeaderAndBodyLength; + char *serializedBufferBody = NULL; + size_t serializedBufferLength = 0; + + if (NULL == request) { + ASSERT(0); + err = VIX_E_FAIL; + goto abort; + } + + *request = NULL; + + if (NULL != propertyList) { + err = VixPropertyList_Serialize(propertyList, + FALSE, + &serializedBufferLength, + &serializedBufferBody); + if (VIX_OK != err) { + goto abort; + } + } + + msgHeaderAndBodyLength = sizeof(*requestLocal) + serializedBufferLength; + requestLocal = (VixCommandGenericRequest *) + VixMsg_AllocRequestMsg(msgHeaderAndBodyLength, + opCode, + cookie, + credentialType, + userNamePassword); + if (NULL == requestLocal) { + err = VIX_E_FAIL; + goto abort; + } + + requestLocal->options = options; + requestLocal->propertyListSize = serializedBufferLength; + + if (NULL != serializedBufferBody) { + char *dst = (char *)request + sizeof(*request); + memcpy(dst, serializedBufferBody, serializedBufferLength); + } + + *request = requestLocal; + err = VIX_OK; + + abort: + free(serializedBufferBody); + + return err; +} // VixMsg_AllocGenericRequestMsg + + +/* + *----------------------------------------------------------------------------- + * + * VixMsg_ParseGenericRequestMsg -- + * + * Extract the options and property list from the request + * message, while validating message. + * + * Results: + * VixError + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +VixError +VixMsg_ParseGenericRequestMsg(const VixCommandGenericRequest *request, // IN + int *options, // OUT + VixPropertyListImpl *propertyList) // OUT +{ + VixError err; + uint64 headerAndBodyLength; + + if ((NULL == request) || (NULL == options) || (NULL == propertyList)) { + ASSERT(0); + err = VIX_E_FAIL; + goto abort; + } + + *options = 0; + VixPropertyList_Initialize(propertyList); + + /* + * In most cases we will have already called VixMsg_ValidateResponseMsg() + * on this request before, but call it here so that this function will + * always be sufficient to validate the request. + */ + err = VixMsg_ValidateRequestMsg(request, + request->header.commonHeader.totalMessageLength); + if (VIX_OK != err) { + goto abort; + } + + if (request->header.commonHeader.totalMessageLength < sizeof *request) { + err = VIX_E_INVALID_MESSAGE_BODY; + goto abort; + } + + headerAndBodyLength = (uint64) request->header.commonHeader.headerLength + + request->header.commonHeader.bodyLength; + + if (headerAndBodyLength < ((uint64) sizeof *request + + request->propertyListSize)) { + err = VIX_E_INVALID_MESSAGE_BODY; + goto abort; + } + + if (request->propertyListSize > 0) { + const char *serializedBuffer = (const char *) request + sizeof(*request); + + err = VixPropertyList_Deserialize(propertyList, + serializedBuffer, + request->propertyListSize); + if (VIX_OK != err) { + goto abort; + } + } + + *options = request->options; + err = VIX_OK; + + abort: + + return err; +} // VixMsg_ParseGenericRequestMsg diff --git a/open-vm-tools/lib/ghIntegration/ghIntegration.c b/open-vm-tools/lib/ghIntegration/ghIntegration.c index 29ed958be..5568ec33b 100644 --- a/open-vm-tools/lib/ghIntegration/ghIntegration.c +++ b/open-vm-tools/lib/ghIntegration/ghIntegration.c @@ -38,6 +38,7 @@ #include "strutil.h" #include "unityCommon.h" #include "util.h" +#include "xdrutil.h" /* @@ -103,6 +104,31 @@ static Bool GHITcloTrashFolderGetIcon(RpcInData *data); static Bool GHIUpdateHost(GHIProtocolHandlerList *handlers); +/* + * Wrapper function for the "ghi.guest.trayIcon.sendEvent" RPC. + */ +static Bool GHITcloTrayIconSendEvent(RpcInData *data); + +/* + * Wrapper function for the "ghi.guest.trayIcon.startUpdates" RPC. + */ +static Bool GHITcloTrayIconStartUpdates(RpcInData *data); + +/* + * Wrapper function for the "ghi.guest.trayIcon.stopUpdates" RPC. + */ +static Bool GHITcloTrayIconStopUpdates(RpcInData *data); + +/* + * Wrapper function for the "ghi.guest.setFocusedWindow" RPC. + */ +static Bool GHITcloSetFocusedWindow(RpcInData *data); + +/* + * Wrapper function for the "ghi.guest.getExecInfoHash" RPC. + */ +static Bool GHITcloGetExecInfoHash(RpcInData *data); + DynBuf gTcloUpdate; static GHIPlatform *ghiPlatformData; @@ -289,6 +315,16 @@ GHI_InitBackdoor(struct RpcIn *rpcIn) // IN GHITcloTrashFolderAction, NULL); RpcIn_RegisterCallbackEx(rpcIn, GHI_RPC_TRASH_FOLDER_GET_ICON, GHITcloTrashFolderGetIcon, NULL); + RpcIn_RegisterCallbackEx(rpcIn, GHI_RPC_TRAY_ICON_SEND_EVENT, + GHITcloTrayIconSendEvent, NULL); + RpcIn_RegisterCallbackEx(rpcIn, GHI_RPC_TRAY_ICON_START_UPDATES, + GHITcloTrayIconStartUpdates, NULL); + RpcIn_RegisterCallbackEx(rpcIn, GHI_RPC_TRAY_ICON_STOP_UPDATES, + GHITcloTrayIconStopUpdates, NULL); + RpcIn_RegisterCallbackEx(rpcIn, GHI_RPC_SET_FOCUSED_WINDOW, + GHITcloSetFocusedWindow, NULL); + RpcIn_RegisterCallbackEx(rpcIn, GHI_RPC_GET_EXEC_INFO_HASH, + GHITcloGetExecInfoHash, NULL); } } @@ -1352,5 +1388,360 @@ exit: * buffer will be freed by the RPC layer. */ DynXdr_Destroy(&xdrs, !ret); + Debug("%s: Exit.\n", __FUNCTION__); + return ret; +} + +/** + * @brief Send a mouse or keyboard event to a tray icon. + * + * @param[in] data Pointer to the RpcInData structure for the RPC. + * + * @retval TRUE The RPC succeeded. + * @retval FALSE The RPC failed. + */ + +Bool +GHITcloTrayIconSendEvent(RpcInData *data) +{ + Bool ret = FALSE; + XDR xdrs; + + Debug("%s: Enter.\n", __FUNCTION__); + + /* Check our arguments. */ + ASSERT(data); + ASSERT(data->name); + ASSERT(data->argsSize > 0); + + if (!(data && data->name && data->argsSize > 0)) { + Debug("%s: Invalid arguments.\n", __FUNCTION__); + goto exit; + } + + Debug("%s: Got RPC, name: \"%s\", argument length: %"FMTSZ"u.\n", + __FUNCTION__, data->name, data->argsSize); + + /* + * Build an XDR stream from the argument data. + * + * Note that the argument data begins with args + 1 since there is a space + * between the RPC name and the XDR serialization. + */ + xdrmem_create(&xdrs, (char*) data->args + 1, data->argsSize - 1, XDR_DECODE); + + /* Call the platform implementation of our RPC. */ + ret = GHIPlatformTrayIconSendEvent(ghiPlatformData, &xdrs); + + /* Destroy the XDR stream. */ + xdr_destroy(&xdrs); + + if (ret == FALSE) { + Debug("%s: RPC failed.\n", __FUNCTION__); + RPCIN_SETRETVALS(data, "RPC failed", FALSE); + goto exit; + } + + /* + * We don't have any out parameters, so we write empty values into the + * result fields of the RpcInData structure. + */ + RPCIN_SETRETVALS(data, "", FALSE); + + /* Set our return value and return to the caller. */ + ret = TRUE; + +exit: + Debug("%s: Exit.\n", __FUNCTION__); + return ret; +} + +/** + * @brief Start sending tray icon updates to the VMX. + * + * @param[in] data Pointer to the RpcInData structure for the RPC. + * + * @retval TRUE The RPC succeeded. + * @retval FALSE The RPC failed. + */ + +Bool +GHITcloTrayIconStartUpdates(RpcInData *data) +{ + Bool ret = FALSE; + + Debug("%s: Enter.\n", __FUNCTION__); + + /* Check our arguments. */ + ASSERT(data); + ASSERT(data->name); + + if (!(data && data->name)) { + Debug("%s: Invalid arguments.\n", __FUNCTION__); + goto exit; + } + + Debug("%s: Got RPC, name: \"%s\", argument length: %"FMTSZ"u.\n", + __FUNCTION__, data->name, data->argsSize); + + if (!GHIPlatformTrayIconStartUpdates(ghiPlatformData)) { + Debug("%s: Failed to start tray icon updates.\n", __FUNCTION__); + RPCIN_SETRETVALS(data, "Failed to start tray icon updates", FALSE); + goto exit; + } + + /* + * Write the result into the RPC out parameters. + */ + ret = RPCIN_SETRETVALS(data, "", TRUE); + +exit: + Debug("%s: Exit.\n", __FUNCTION__); + return ret; +} + +/** + * @brief Stop sending tray icon updates to the VMX. + * + * @param[in] data Pointer to the RpcInData structure for the RPC. + * + * @retval TRUE The RPC succeeded. + * @retval FALSE The RPC failed. + */ + +Bool +GHITcloTrayIconStopUpdates(RpcInData *data) +{ + Bool ret = FALSE; + + Debug("%s: Enter.\n", __FUNCTION__); + + /* Check our arguments. */ + ASSERT(data); + ASSERT(data->name); + + if (!(data && data->name)) { + Debug("%s: Invalid arguments.\n", __FUNCTION__); + goto exit; + } + + Debug("%s: Got RPC, name: \"%s\", argument length: %"FMTSZ"u.\n", + __FUNCTION__, data->name, data->argsSize); + + if (!GHIPlatformTrayIconStopUpdates(ghiPlatformData)) { + Debug("%s: Failed to start tray icon updates.\n", __FUNCTION__); + RPCIN_SETRETVALS(data, "Failed to start tray icon updates", FALSE); + goto exit; + } + + /* + * Write the result into the RPC out parameters. + */ + ret = RPCIN_SETRETVALS(data, "", TRUE); + +exit: + return ret; +} + + +/** + * @brief Send the ghi.guest.trayIcon.update RPC to the host. + * + * @param[in] data Pointer to the RpcInData structure for the RPC. + * + * @retval TRUE The RPC succeeded. + * @retval FALSE The RPC failed. + */ + +Bool +GHISendTrayIconUpdateRpc(XDR *xdrs) +{ + Bool ret = FALSE; + DynBuf outBuf; + + Debug("%s: Enter.\n", __FUNCTION__); + + /* Check our arguments. */ + ASSERT(xdrs); + if (NULL == xdrs) { + Debug("%s: Invalid parameter.\n", __FUNCTION__); + goto exit; + } + + /* Append our RPC name and a space to the DynBuf. */ + DynBuf_Init(&outBuf); + if (!DynBuf_Append(&outBuf, + GHI_RPC_TRAY_ICON_UPDATE, + strlen(GHI_RPC_TRAY_ICON_UPDATE))) { + Debug("%s: Failed to append RPC name to DynBuf.\n", __FUNCTION__); + goto exit; + } + + if (!DynBuf_Append(&outBuf, " ", 1)) { + Debug("%s: Failed to append space to DynBuf.\n", __FUNCTION__); + goto exit; + } + + /* Append the XDR serialized data to the DynBuf. */ + if (!DynBuf_Append(&outBuf, DynXdr_Get(xdrs), xdr_getpos(xdrs)) ) + { + Debug("%s: Failed to append XDR serialized data to DynBuf.\n", + __FUNCTION__); + goto exit; + } + + if (!RpcOut_SendOneRaw(DynBuf_Get(&outBuf), + DynBuf_GetSize(&outBuf), + NULL, + NULL)) { + Debug("%s: Failed to send RPC to host!\n", __FUNCTION__); + goto exit; + } + + ret = TRUE; + +exit: + DynBuf_Destroy(&outBuf); + Debug("%s: Exit.\n", __FUNCTION__); + return ret; +} + +/** + * @brief Set the specified window to be focused (NULL or zero window ID indicates + * that no window should be focused). + * + * @param[in] data Pointer to the RpcInData structure for the RPC. + * + * @retval TRUE The RPC succeeded. + * @retval FALSE The RPC failed. + */ + +Bool +GHITcloSetFocusedWindow(RpcInData *data) +{ + Bool ret = FALSE; + XDR xdrs; + + Debug("%s: Enter.\n", __FUNCTION__); + + /* Check our arguments. */ + ASSERT(data); + ASSERT(data->name); + + if (!(data && data->name)) { + Debug("%s: Invalid arguments.\n", __FUNCTION__); + goto exit; + } + + Debug("%s: Got RPC, name: \"%s\", argument length: %"FMTSZ"u.\n", + __FUNCTION__, data->name, data->argsSize); + + /* + * Build an XDR stream from the argument data. + * + * Note that the argument data begins with args + 1 since there is a space + * between the RPC name and the XDR serialization. + */ + xdrmem_create(&xdrs, (char*) data->args + 1, data->argsSize - 1, XDR_DECODE); + + /* Call the platform implementation of our RPC. */ + ret = GHIPlatformSetFocusedWindow(ghiPlatformData, &xdrs); + + /* Destroy the XDR stream. */ + xdr_destroy(&xdrs); + + /* + * Write the result into the RPC out parameters. + */ + ret = RPCIN_SETRETVALS(data, "", TRUE); + +exit: + return ret; +} + + +/** + * @brief Get the hash (or timestamp) of information returned by + * GHITcloGetBinaryInfo. + * + * @param[in] data Pointer to the RpcInData structure for the RPC. + * + * @retval TRUE The RPC succeeded. + * @retval FALSE The RPC failed. + */ + +Bool +GHITcloGetExecInfoHash(RpcInData *data) +{ + Bool ret = TRUE; + GHIGetExecInfoHashRequest requestMsg; + GHIGetExecInfoHashReply replyMsg; + XDR xdrs; + + memset(&requestMsg, 0, sizeof requestMsg); + memset(&replyMsg, 0, sizeof replyMsg); + + /* Check our arguments. */ + ASSERT(data); + ASSERT(data->name); + ASSERT(data->args); + + if (!(data && data->name && data->args)) { + Debug("%s: Invalid arguments.\n", __FUNCTION__); + ret = RPCIN_SETRETVALS(data, "Invalid arguments.", FALSE); + goto exit; + } + + Debug("%s: Got RPC, name: \"%s\", argument length: %"FMTSZ"u.\n", + __FUNCTION__, data->name, data->argsSize); + + /* + * Deserialize the XDR data. Note that the data begins with args + 1 since + * there is a space between the RPC name and the XDR serialization. + */ + if (!XdrUtil_Deserialize((char *)data->args + 1, data->argsSize - 1, + xdr_GHIGetExecInfoHashRequest, &requestMsg)) { + Debug("%s: Failed to deserialize data\n", __FUNCTION__); + ret = RPCIN_SETRETVALS(data, "Failed to deserialize data.", FALSE); + goto exit; + } + + /* + * Call the platform implementation of the RPC handler. + */ + if (!GHIPlatformGetExecInfoHash(ghiPlatformData, &requestMsg, &replyMsg)) { + ret = RPCIN_SETRETVALS(data, "Could not get executable info hash.", FALSE); + goto exit; + } + + /* + * Serialize the result data and return. + */ + if (NULL == DynXdr_Create(&xdrs)) { + Debug("%s: Failed to create DynXdr structure.\n", __FUNCTION__); + ret = RPCIN_SETRETVALS(data, "Failed to create XDR structure", FALSE); + goto exit; + } + + if (!xdr_GHIGetExecInfoHashReply(&xdrs, &replyMsg)) { + ret = RPCIN_SETRETVALS(data, "Failed to serialize data", FALSE); + DynXdr_Destroy(&xdrs, TRUE); + goto exit; + } + + data->result = DynXdr_Get(&xdrs); + data->resultLen = xdr_getpos(&xdrs); + data->freeResult = TRUE; + + /* + * Destroy the serialized XDR structure but leave the data buffer alone + * since it will be freed by the RpcIn layer. + */ + DynXdr_Destroy(&xdrs, FALSE); + +exit: + VMX_XDR_FREE(xdr_GHIGetExecInfoHashRequest, &requestMsg); + VMX_XDR_FREE(xdr_GHIGetExecInfoHashReply, &replyMsg); + return ret; } diff --git a/open-vm-tools/lib/ghIntegration/ghIntegrationInt.h b/open-vm-tools/lib/ghIntegration/ghIntegrationInt.h index ac4a92686..141827256 100644 --- a/open-vm-tools/lib/ghIntegration/ghIntegrationInt.h +++ b/open-vm-tools/lib/ghIntegration/ghIntegrationInt.h @@ -27,6 +27,7 @@ #include "dynbuf.h" #include "unityCommon.h" +#include "guestrpc/ghiGetExecInfoHash.h" #include "guestrpc/ghiProtocolHandler.h" typedef struct _GHIPlatform GHIPlatform; @@ -84,13 +85,46 @@ Bool GHIPlatformTrashFolderAction(GHIPlatform* ghip, const XDR *xdrs); /* Get the icon for the Trash (aka Recycle Bin) folder. */ Bool GHIPlatformTrashFolderGetIcon(GHIPlatform *ghip, XDR *xdrs); +/* + * Send a mouse event to a tray icon. + */ +Bool GHIPlatformTrayIconSendEvent(GHIPlatform *ghip, const XDR *xdrs); + +/* + * Start sending tray icon updates to the VMX. + */ +Bool GHIPlatformTrayIconStartUpdates(GHIPlatform *ghip); + +/* + * Stop sending tray icon updates to the VMX. + */ +Bool GHIPlatformTrayIconStopUpdates(GHIPlatform *ghip); + /* Implemented by ghIntegration.c for use by the platform-specific code */ Bool GHILaunchMenuChangeRPC(void); /* - * Used by the platform-specific code to send the "tools.ghi.trash.change" RPC - * to the host. + * Used by the platform-specific code to send the "ghi.guest.trashFolder.state" + * RPC to the host. */ Bool GHISendTrashFolderStateRPC(XDR *xdrs); +/* + * Used by the platform-specific code to send the "ghi.guest.trayIcon.update" + * RPC to the host. + */ +Bool GHISendTrayIconUpdateRpc(XDR *xdrs); + +/* + * Set the specified window to be focused. + */ +Bool GHIPlatformSetFocusedWindow(GHIPlatform *ghip, const XDR *xdrs); + +/* + * Get the hash (or timestamp) of information returned by get.binary.info. + */ +Bool GHIPlatformGetExecInfoHash(GHIPlatform *ghip, + const GHIGetExecInfoHashRequest *request, + GHIGetExecInfoHashReply *reply); + #endif diff --git a/open-vm-tools/lib/ghIntegration/ghIntegrationX11.c b/open-vm-tools/lib/ghIntegration/ghIntegrationX11.c index 75b14abd4..312d42d37 100644 --- a/open-vm-tools/lib/ghIntegration/ghIntegrationX11.c +++ b/open-vm-tools/lib/ghIntegration/ghIntegrationX11.c @@ -907,7 +907,15 @@ GHIPlatformGetDesktopName(void) Window temp2; // throwaway Window *children = NULL; unsigned int nchildren; - const char *retval = NULL; + static const char *desktopEnvironment = NULL; + + /* + * NB: While window managers may change during vmware-user's execution, TTBOMK + * desktop environments cannot, so this is safe. + */ + if (desktopEnvironment) { + return desktopEnvironment; + } display = gdk_x11_get_default_xdisplay(); rootWindow = DefaultRootWindow(display); @@ -916,26 +924,45 @@ GHIPlatformGetDesktopName(void) return NULL; } - for (i = 0; i < nchildren && !retval; i++) { - char *name = NULL; + for (i = 0; i < nchildren && !desktopEnvironment; i++) { + XClassHint wmClass = { 0, 0 }; int j; - if ((XFetchName(display, children[i], &name) == 0) || - name == NULL) { - continue; - } + /* + * Try WM_CLASS first, then try WM_NAME. + */ - for (j = 0; j < ARRAYSIZE(clientMappings) && !retval; j++) { - if (!strcmp(clientMappings[j][0], name)) { - retval = clientMappings[j][1]; + if (XGetClassHint(display, children[i], &wmClass) != 0) { + for (j = 0; j < ARRAYSIZE(clientMappings) && !desktopEnvironment; j++) { + if ((strcasecmp(clientMappings[j][0], wmClass.res_name) == 0) || + (strcasecmp(clientMappings[j][0], wmClass.res_class) == 0)) { + desktopEnvironment = clientMappings[j][1]; + } } + XFree(wmClass.res_name); + XFree(wmClass.res_class); } - XFree(name); + if (!desktopEnvironment) { + char *name = NULL; + + if ((XFetchName(display, children[i], &name) == 0) || + name == NULL) { + continue; + } + + for (j = 0; j < ARRAYSIZE(clientMappings) && !desktopEnvironment; j++) { + if (!strcmp(clientMappings[j][0], name)) { + desktopEnvironment = clientMappings[j][1]; + } + } + + XFree(name); + } } XFree(children); - return retval; + return desktopEnvironment; } @@ -969,9 +996,9 @@ GHIPlatformIsMenuItemAllowed(GHIPlatform *ghip, // IN: * Examine the "NoDisplay" and "Hidden" properties. */ if (g_key_file_get_boolean(keyfile, - G_KEY_FILE_DESKTOP_GROUP, - G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, - NULL) || + G_KEY_FILE_DESKTOP_GROUP, + G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, + NULL) || g_key_file_get_boolean(keyfile, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_HIDDEN, @@ -1388,7 +1415,7 @@ GHIPlatformReadApplicationsDir(GHIPlatform *ghip, // IN if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..") || !strcmp(dent->d_name, ".hidden")) { - continue; + continue; } subpathLen = Str_Sprintf(subpath, sizeof subpath, "%s/%s", dir, dent->d_name); @@ -1409,8 +1436,8 @@ GHIPlatformReadApplicationsDir(GHIPlatform *ghip, // IN } else if ((dent->d_type == DT_REG || (dent->d_type == DT_UNKNOWN && S_ISREG(sbuf.st_mode))) - && StrUtil_EndsWith(dent->d_name, ".desktop")) { - GHIPlatformReadDesktopFile(ghip, subpath); + && StrUtil_EndsWith(dent->d_name, ".desktop")) { + GHIPlatformReadDesktopFile(ghip, subpath); } } @@ -1450,7 +1477,7 @@ GHIPlatformReadAllApplications(GHIPlatform *ghip) // IN for (i = 0; i < ARRAYSIZE(desktopDirs); i++) { if (StrUtil_StartsWith(desktopDirs[i], "~/")) { - char cbuf[PATH_MAX]; + char cbuf[PATH_MAX]; Str_Sprintf(cbuf, sizeof cbuf, "%s/%s", g_get_home_dir(), desktopDirs[i] + 2); @@ -2450,8 +2477,8 @@ GHIPlatformShellAction(GHIPlatform *ghip, // IN: platform-specific state Bool GHIPlatformShellUrlOpen(GHIPlatform *ghip, // IN: platform-specific state - const char *fileUtf8, // IN: command/file - const char *actionUtf8) // IN: action + const char *fileUtf8, // IN: command/file + const char *actionUtf8) // IN: action { #ifdef GTK2 char **fileArgv = NULL; @@ -2735,3 +2762,92 @@ GHIPlatformTrashFolderGetIcon(GHIPlatform *ghip, ASSERT(xdrs); return FALSE; } + +/* @brief Send a mouse or keyboard event to a tray icon. + * + * @param[in] ghip Pointer to platform-specific GHI data. + * + * @retval TRUE Operation Succeeded. + * @retval FALSE Operation Failed. + */ + +Bool +GHIPlatformTrayIconSendEvent(GHIPlatform *ghip, + const XDR *xdrs) +{ + ASSERT(ghip); + ASSERT(xdrs); + return FALSE; +} + +/* @brief Start sending tray icon updates to the VMX. + * + * @param[in] ghip Pointer to platform-specific GHI data. + * + * @retval TRUE Operation Succeeded. + * @retval FALSE Operation Failed. + */ + +Bool +GHIPlatformTrayIconStartUpdates(GHIPlatform *ghip) +{ + ASSERT(ghip); + return FALSE; +} + +/* @brief Stop sending tray icon updates to the VMX. + * + * @param[in] ghip Pointer to platform-specific GHI data. + * + * @retval TRUE Operation Succeeded. + * @retval FALSE Operation Failed. + */ + +Bool +GHIPlatformTrayIconStopUpdates(GHIPlatform *ghip) +{ + ASSERT(ghip); + return FALSE; +} + +/* @brief Set a window to be focused. + * + * @param[in] ghip Pointer to platform-specific GHI data. + * @param[in] xdrs Pointer to serialized data from the host. + * + * @retval TRUE Operation Succeeded. + * @retval FALSE Operation Failed. + */ + +Bool +GHIPlatformSetFocusedWindow(GHIPlatform *ghip, + const XDR *xdrs) +{ + ASSERT(ghip); + ASSERT(xdrs); + return FALSE; +} + + +/** + * @brief Get the hash (or timestamp) of information returned by + * GHIPlatformGetBinaryInfo. + * + * @param[in] ghip Pointer to platform-specific GHI data. + * @param[in] request Request containing which executable to get the hash for. + * @param[out] reply Reply to be filled with the hash. + * + * @retval TRUE Operation succeeded. + * @retval FALSE Operation failed. + */ + +Bool GHIPlatformGetExecInfoHash(GHIPlatform *ghip, + const GHIGetExecInfoHashRequest *request, + GHIGetExecInfoHashReply *reply) +{ + ASSERT(ghip); + ASSERT(request); + ASSERT(reply); + + return FALSE; +} diff --git a/open-vm-tools/lib/guestApp/guestAppPosixX11.c b/open-vm-tools/lib/guestApp/guestAppPosixX11.c index c2b41c8e2..6a35d1ab5 100644 --- a/open-vm-tools/lib/guestApp/guestAppPosixX11.c +++ b/open-vm-tools/lib/guestApp/guestAppPosixX11.c @@ -35,6 +35,7 @@ extern "C" { #include // for free, system #include #include +#include #include @@ -83,7 +84,8 @@ GuestAppX11OpenUrl(const char *url, // IN gboolean spawnSuccess; GError *gerror = NULL; - char **argv = NULL; + char *argv[4]; + char **parsedArgv = NULL; char *newNetscapeBuf = NULL; Bool success = FALSE; @@ -107,42 +109,35 @@ GuestAppX11OpenUrl(const char *url, // IN if (!newNetscapeBuf) { goto abort; } - argv = g_malloc(4 * sizeof *argv); argv[0] = (char *)gBrowser; argv[1] = "-remote"; argv[2] = newNetscapeBuf; argv[3] = NULL; } else { gint argc; + gboolean parsed; /* - * See GuestAppDetectBrowser(): our browser command could come from gconf, - * in which case it's a command line that we have to parse, so that we - * can put the URL in the right place before executing the child process. + * See GuestAppDetectBrowser(): we already made sure we can parse the + * command and that it has a placeholder, so just assert that is still + * the case here. */ - if (!g_shell_parse_argv(gBrowser, &argc, &argv, &gerror)) { - Debug("Error parsing browser command line: %s\n", gerror->message); - g_clear_error(&gerror); - goto abort; - } + parsed = g_shell_parse_argv(gBrowser, &argc, &parsedArgv, NULL); + ASSERT(parsed); + if (argc > 1) { - /* - * If the browser is a command line, we expect "%s" to be the URL - * placeholder. If not found, bail out. - */ gint i; + for (i = 0; i < argc; i++) { - if (strcmp(argv[i], "%s") == 0) { - argv[i] = (char *) url; + if (strcmp(parsedArgv[i], "%s") == 0) { + g_free(parsedArgv[i]); + parsedArgv[i] = g_strdup(url); break; } } - if (i == argc) { - Debug("Browser command (%s) doesn't have an URL placeholder.\n", gBrowser); - goto abort; - } + ASSERT(i < argc); } else { - g_free(argv); - argv = g_malloc(3 * sizeof *argv); + g_strfreev(parsedArgv); + parsedArgv = NULL; argv[0] = (char *)gBrowser; argv[1] = (char *)url; argv[2] = NULL; @@ -154,7 +149,7 @@ GuestAppX11OpenUrl(const char *url, // IN * help is showing. */ spawnSuccess = g_spawn_async(NULL, // inherit working directory - argv, + (parsedArgv != NULL) ? parsedArgv : argv, /* * XXX Please don't hate me for casting off the * qualifier here. Glib does -not- modify the @@ -181,7 +176,7 @@ GuestAppX11OpenUrl(const char *url, // IN success = TRUE; abort: - g_free(argv); + g_strfreev(parsedArgv); free(newNetscapeBuf); return success; } @@ -255,7 +250,8 @@ GuestAppDetectBrowser(void) char *argv[] = { "gconftool-2", "--get", - "/desktop/gnome/url-handlers/http/command" + "/desktop/gnome/url-handlers/http/command", + NULL }; gboolean success; gchar *out = NULL; @@ -264,34 +260,85 @@ GuestAppDetectBrowser(void) success = g_spawn_sync(NULL, argv, - (char **)guestAppSpawnEnviron, - G_SPAWN_SEARCH_PATH | G_SPAWN_STDERR_TO_DEV_NULL, - NULL, - NULL, - &out, - NULL, - &status, - &err); + (char **)guestAppSpawnEnviron, + G_SPAWN_SEARCH_PATH | G_SPAWN_STDERR_TO_DEV_NULL, + NULL, + NULL, + &out, + NULL, + &status, + &err); + + /* + * gconftool-2 exits with a success status when the key we're querying is + * empty (or doesn't exist?), so make sure the output string is also empty + * (with no new lines or anything). + */ + if (out != NULL) { + g_strchomp(out); + } + if (!success || !WIFEXITED(status) || WEXITSTATUS(status) != 0 || out == NULL || strlen(out) == 0) { Warning("Failed to invoke gconftool-2: exit code %d (%s)\n", WEXITSTATUS(status), (err != NULL) ? err->message : ""); g_clear_error(&err); + g_free(out); } else { - buf = g_strchomp(out); - gBrowserIsMalloced = TRUE; - goto exit; + /* + * We got data from gconftool-2, but it may still be invalid (e.g., the + * user has configured a browser that doesn't exist). Try to detect + * that case and fallback to our regular "brute force" detection if + * we can't use the command. + */ + int argc = 0; + char **command = NULL; + if (g_shell_parse_argv(out, &argc, &command, NULL) && argc > 0) { + if ((g_path_is_absolute(command[0]) && !access(command[0], X_OK)) || + !GuestApp_FindProgram(command[0])) { + Debug("Cannot find or execute user-defined default browser '%s'.\n", + command[0]); + } else { + /* We expect "%s" to be the URL placeholder. If not found, fall back. */ + gint i; + for (i = 0; i < argc; i++) { + if (strcmp(command[i], "%s") == 0) { + break; + } + } + if (i < argc) { + buf = out; + gBrowserIsMalloced = TRUE; + g_strfreev(command); + goto exit; + } else { + Debug("Browser command (%s) doesn't have an URL placeholder.\n", out); + } + } + } else { + Debug("Failed to parse custom user-defined browser command (%s).\n", out); + } + + g_free(out); + g_strfreev(command); } } if (((getenv("KDE_FULL_SESSION") != NULL && !strcmp(getenv("KDE_FULL_SESSION"), "true")) || GuestAppFindX11Client("ksmserver") || - GuestAppFindX11Client("startkde")) && - GuestApp_FindProgram("konqueror")) { - buf = "konqueror"; - } else if (GuestApp_FindProgram("mozilla-firefox")) { + GuestAppFindX11Client("startkde"))) { + if (GuestApp_FindProgram("kde-open")) { + buf = "kde-open"; + goto exit; + } else if (GuestApp_FindProgram("konqueror")) { + buf = "konqueror"; + goto exit; + } + } + + if (GuestApp_FindProgram("mozilla-firefox")) { buf = "mozilla-firefox"; } else if (GuestApp_FindProgram("firefox")) { buf = "firefox"; diff --git a/open-vm-tools/lib/guestInfo/guestInfo.c b/open-vm-tools/lib/guestInfo/guestInfo.c index 65c4777e2..7d1c16277 100644 --- a/open-vm-tools/lib/guestInfo/guestInfo.c +++ b/open-vm-tools/lib/guestInfo/guestInfo.c @@ -296,8 +296,7 @@ GuestInfoGetDiskInfo(PGuestDiskInfo di) for (i = 0; i < pl->size; i++) { nextPartition = pl->partitions[i]; - if (!strlen(nextPartition.comment) || - strcmp(nextPartition.comment, WIPER_DEVICE_MAPPER_STRING) == 0) { + if (!strlen(nextPartition.comment)) { PPartitionEntry newPartitionList; unsigned char *error; error = WiperSinglePartition_GetSpace(&nextPartition, &freeBytes, &totalBytes); diff --git a/open-vm-tools/lib/guestRpc/Makefile.am b/open-vm-tools/lib/guestRpc/Makefile.am index 68f47ec44..c59702606 100644 --- a/open-vm-tools/lib/guestRpc/Makefile.am +++ b/open-vm-tools/lib/guestRpc/Makefile.am @@ -20,6 +20,7 @@ noinst_LTLIBRARIES = libGuestRpc.la libGuestRpc_la_SOURCES = libGuestRpc_la_SOURCES += cpFileContents_xdr.c libGuestRpc_la_SOURCES += ghiGetBinaryHandlers_xdr.c +libGuestRpc_la_SOURCES += ghiGetExecInfoHash_xdr.c libGuestRpc_la_SOURCES += ghiProtocolHandler_xdr.c libGuestRpc_la_SOURCES += guestlibV3_xdr.c libGuestRpc_la_SOURCES += nicinfo_xdr.c @@ -35,6 +36,8 @@ CLEANFILES += cpFileContents.h CLEANFILES += cpFileContents_xdr.c CLEANFILES += ghiGetBinaryHandlers.h CLEANFILES += ghiGetBinaryHandlers_xdr.c +CLEANFILES += ghiGetExecInfoHash.h +CLEANFILES += ghiGetExecInfoHash_xdr.c CLEANFILES += ghiProtocolHandler.h CLEANFILES += ghiProtocolHandler_xdr.c CLEANFILES += guestlibV3.h @@ -47,6 +50,7 @@ CLEANFILES += unityActive_xdr.c EXTRA_DIST = EXTRA_DIST += cpFileContents.x EXTRA_DIST += ghiGetBinaryHandlers.x +EXTRA_DIST += ghiGetExecInfoHash.x EXTRA_DIST += ghiProtocolHandler.x EXTRA_DIST += guestlibV3.x EXTRA_DIST += nicinfo.x @@ -89,6 +93,19 @@ ghiGetBinaryHandlers.h: ghiGetBinaryHandlers.x ghiGetBinaryHandlers_xdr.c: ghiGetBinaryHandlers.x ghiGetBinaryHandlers.h $(RPCGEN) $(RPCGENFLAGS) -c -o $@ $(builddir)/ghiGetBinaryHandlers.x +ghiGetExecInfoHash.h: ghiGetExecInfoHash.x + if [ $(top_builddir) != $(top_srcdir) ]; then \ + cp -f $(top_srcdir)/lib/guestRpc/ghiGetExecInfoHash.x $(builddir); \ + fi + $(RPCGEN) $(RPCGENFLAGS) -h -o $@ $(builddir)/ghiGetExecInfoHash.x + $(SED) 's,rpc/rpc\.h,vmxrpc.h,' $@ > $@.tmp + mv $@.tmp $@ + $(MKDIR_P) $(top_builddir)/lib/include/guestrpc + cp $@ $(top_builddir)/lib/include/guestrpc + +ghiGetExecInfoHash_xdr.c: ghiGetExecInfoHash.x ghiGetExecInfoHash.h + $(RPCGEN) $(RPCGENFLAGS) -c -o $@ $(builddir)/ghiGetExecInfoHash.x + ghiProtocolHandler.h: ghiProtocolHandler.x if [ $(top_builddir) != $(top_srcdir) ]; then \ cp -f $(top_srcdir)/lib/guestRpc/ghiProtocolHandler.x $(builddir); \ diff --git a/open-vm-tools/lib/guestRpc/ghiGetExecInfoHash.x b/open-vm-tools/lib/guestRpc/ghiGetExecInfoHash.x new file mode 100644 index 000000000..989ed0164 --- /dev/null +++ b/open-vm-tools/lib/guestRpc/ghiGetExecInfoHash.x @@ -0,0 +1,71 @@ +/********************************************************* + * 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. + * + *********************************************************/ + +/* +* ghiGetExecInfoHash.x -- +* +* Definition of the data structures used in the GuestRpc commands to +* get the hash of information returned by the get.binary.info RPC. +*/ + +#include "ghiCommonDefines.h" + +#define GHI_EXEC_INFO_HASH_MAX_LEN 1024 + +/* +* Enumerates the different versions of the messages. +*/ +enum GHIGetExecInfoHashVersion { + GHI_GET_EXEC_INFO_HASH_V1 = 1 +}; + +/* +* The structures used for version 1 of the messages. +*/ +struct GHIGetExecInfoHashRequestV1 { + /* + * A string identifier for the executable path. + */ + string execPath; +}; +struct GHIGetExecInfoHashReplyV1 { + /* + * A string identifier for the hash. + */ + string execHash; +}; + +/* + * This defines the protocol for 'getExecInfoHash' request and reply messages. + * + * The union allows us to introduce new versions of the protocol later by + * creating new values in the enumeration, without having to change much of + * the code calling the (de)serialization functions. + * + * Since the union doesn't have a default case, de-serialization will fail if + * an unknown version is provided on the wire. + */ +union GHIGetExecInfoHashRequest switch (GHIGetExecInfoHashVersion ver) { +case GHI_GET_EXEC_INFO_HASH_V1: + struct GHIGetExecInfoHashRequestV1 *requestV1; +}; +union GHIGetExecInfoHashReply switch (GHIGetExecInfoHashVersion ver) { +case GHI_GET_EXEC_INFO_HASH_V1: + struct GHIGetExecInfoHashReplyV1 *replyV1; +}; + diff --git a/open-vm-tools/lib/hgfs/cpName.c b/open-vm-tools/lib/hgfs/cpName.c index f97c679b6..dc92be0dc 100644 --- a/open-vm-tools/lib/hgfs/cpName.c +++ b/open-vm-tools/lib/hgfs/cpName.c @@ -96,7 +96,7 @@ CPName_GetComponent(char const *begin, // IN: Beginning of buffer /* Found a NUL */ if (walk == begin) { - Log("CPName_GetComponent: error: first char can't be NUL\n"); + Log("%s: error: first char can't be NUL\n", __FUNCTION__); return -1; } @@ -156,7 +156,7 @@ CPNameEscapeAndConvertFrom(char const **bufIn, // IN/OUT: Input to convert char const *savedOutConst = savedBufOut; size_t savedOutSize = *outSize; if (inputSize > *outSize) { - Log("CPNameEscapeAndConvertFrom: error: not enough room for escaping\n"); + Log("%s: error: not enough room for escaping\n", __FUNCTION__); return -1; } @@ -228,14 +228,14 @@ CPNameConvertFrom(char const **bufIn, // IN/OUT: Input to convert len = CPName_GetComponent(in, inEnd, &next); if (len < 0) { - Log("CPNameConvertFrom: error: get next component failed\n"); + Log("%s: error: get next component failed\n", __FUNCTION__); return len; } /* Bug 27926 - preventing escaping from shared folder. */ if ((len == 1 && *in == '.') || (len == 2 && in[0] == '.' && in[1] == '.')) { - Log("CPNameConvertFrom: error: found dot/dotdot\n"); + Log("%s: error: found dot/dotdot\n", __FUNCTION__); return -1; } @@ -246,7 +246,7 @@ CPNameConvertFrom(char const **bufIn, // IN/OUT: Input to convert newLen = ((int) myOutSize) - len - 1; if (newLen < 0) { - Log("CPNameConvertFrom: error: not enough room\n"); + Log("%s: error: not enough room\n", __FUNCTION__); return -1; } myOutSize = (size_t) newLen; @@ -262,7 +262,7 @@ CPNameConvertFrom(char const **bufIn, // IN/OUT: Input to convert /* NUL terminate */ if (myOutSize < 1) { - Log("CPNameConvertFrom: error: not enough room\n"); + Log("%s: error: not enough room\n", __FUNCTION__); return -1; } *out = '\0'; diff --git a/open-vm-tools/lib/hgfs/cpNameLinux.c b/open-vm-tools/lib/hgfs/cpNameLinux.c index a7c2fc08b..2da57516c 100644 --- a/open-vm-tools/lib/hgfs/cpNameLinux.c +++ b/open-vm-tools/lib/hgfs/cpNameLinux.c @@ -127,7 +127,7 @@ CPName_ConvertFromRoot(char const **bufIn, // IN/OUT: Input to convert */ len = CPName_GetComponent(*bufIn, *bufIn + *inSize, &next); if (len < 0) { - Log("CPName_ConvertFromRoot: get first component failed\n"); + Log("%s: get first component failed\n", __FUNCTION__); return HGFS_NAME_STATUS_FAILURE; } diff --git a/open-vm-tools/lib/hgfsServer/hgfsServer.c b/open-vm-tools/lib/hgfsServer/hgfsServer.c index 4a54b20b8..352e41e6a 100644 --- a/open-vm-tools/lib/hgfsServer/hgfsServer.c +++ b/open-vm-tools/lib/hgfsServer/hgfsServer.c @@ -56,6 +56,7 @@ * 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 { \ @@ -75,6 +76,7 @@ * 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 { \ @@ -834,6 +836,7 @@ 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))) { @@ -1171,13 +1174,12 @@ HgfsServerCheckOpenFlagsForShare(HgfsFileOpenInfo *openInfo,// IN: Hgfs file han /* The share name is the first component of the cross-platform name. */ len = CPName_GetComponent(openInfo->cpName, inEnd, &next); if (len < 0) { - LOG(4, ("HgfsServerCheckOpenFlagsForShare: get first component failed\n")); + LOG(4, ("%s: get first component failed\n", __FUNCTION__)); status = FALSE; goto exit; } - nameStatus = HgfsServerPolicy_GetShareMode(openInfo->cpName, - len, + nameStatus = HgfsServerPolicy_GetShareMode(openInfo->cpName, len, &shareMode); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { status = FALSE; @@ -1196,6 +1198,7 @@ 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; } } @@ -1277,13 +1280,14 @@ HgfsGetNewNode(HgfsSessionInfo *session) // IN: session info ASSERT(session); ASSERT(session->nodeArray); - LOG(4, ("HgfsGetNewNode: entered\n")); + LOG(4, ("%s: entered\n", __FUNCTION__)); if (!DblLnkLst_IsLinked(&session->nodeFreeList)) { /* * 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)) { @@ -1296,7 +1300,8 @@ HgfsGetNewNode(HgfsSessionInfo *session) // IN: session info newMem = (HgfsFileNode *)realloc(session->nodeArray, newNumNodes * sizeof *(session->nodeArray)); if (!newMem) { - LOG(4, ("HgfsGetNewNode: can't realloc more nodes\n")); + LOG(4, ("%s: can't realloc more nodes\n", __FUNCTION__)); + return NULL; } @@ -1311,19 +1316,21 @@ HgfsGetNewNode(HgfsSessionInfo *session) // IN: session info * * We'll need to lock this if we multithread. */ - LOG(4, ("Rebasing pointers, diff is %"FMTSZ"u, sizeof node is %"FMTSZ"u\n", - ptrDiff, sizeof(HgfsFileNode))); + + LOG(4, ("Rebasing pointers, diff is %"FMTSZ"u, sizeof node is " + "%"FMTSZ"u\n", ptrDiff, sizeof(HgfsFileNode))); LOG(4, ("old: %p new: %p\n", session->nodeArray, newMem)); - ASSERT(newMem == (HgfsFileNode*)((char*)session->nodeArray + ptrDiff)); + ASSERT(newMem == (HgfsFileNode *)((char*)session->nodeArray + ptrDiff)); #define HgfsServerRebase(_ptr, _type) \ - if ((size_t)((char *)_ptr - (char *)session->nodeArray) < oldSize) { \ + if ((size_t)((char *)_ptr - (char *)session->nodeArray) < oldSize) { \ _ptr = (_type *)((char *)_ptr + ptrDiff); \ } /* * 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) @@ -1377,7 +1384,8 @@ HgfsGetNewNode(HgfsSessionInfo *session) // IN: session info * * Free its localname, clear its fields, return it to the free list. * - * The session's nodeArrayLock should be acquired prior to calling this function. + * The session's nodeArrayLock should be acquired prior to calling this + * function. * * Results: * None @@ -1395,10 +1403,8 @@ HgfsRemoveFileNode(HgfsFileNode *node, // IN: file node { ASSERT(node); - LOG(4, ("HgfsRemoveFileNode: handle %u, name %s, fileId %"FMT64"u\n", - HgfsFileNode2Handle(node), - node->utf8Name, - node->localId.fileId)); + LOG(4, ("%s: handle %u, name %s, fileId %"FMT64"u\n", __FUNCTION__, + HgfsFileNode2Handle(node), node->utf8Name, node->localId.fileId)); if (node->shareName) { free(node->shareName); @@ -1480,7 +1486,8 @@ HgfsFreeFileNode(HgfsHandle handle, // IN: Handle to free * Gets a free node off the free list, sets its name, localId info, * file descriptor and permissions. * - * The session's nodeArrayLock should be acquired prior to calling this function. + * The session's nodeArrayLock should be acquired prior to calling this + * function. * * Results: * A pointer to the newly added node on success @@ -1514,13 +1521,15 @@ HgfsAddNewFileNode(HgfsFileOpenInfo *openInfo, // IN: open info struct /* Get an unused node */ newNode = HgfsGetNewNode(session); if (!newNode) { - LOG(4, ("HgfsAddNewFileNode: out of memory\n")); + LOG(4, ("%s: out of memory\n", __FUNCTION__)); + return NULL; } /* Set new node's fields */ if (!HgfsServerGetOpenMode(openInfo, &newNode->mode)) { HgfsRemoveFileNode(newNode, session); + return NULL; } @@ -1528,10 +1537,12 @@ 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, ("HgfsAddNewFileNode: out of memory\n")); + LOG(4, ("%s: out of memory\n", __FUNCTION__)); HgfsRemoveFileNode(newNode, session); + return NULL; } memcpy(newNode->shareName, shareName, shareNameLen); @@ -1541,8 +1552,9 @@ HgfsAddNewFileNode(HgfsFileOpenInfo *openInfo, // IN: open info struct newNode->utf8NameLen = strlen(openInfo->utf8Name); newNode->utf8Name = malloc(newNode->utf8NameLen + 1); if (newNode->utf8Name == NULL) { - LOG(4, ("HgfsAddNewFileNode: out of memory\n")); + LOG(4, ("%s: out of memory\n", __FUNCTION__)); HgfsRemoveFileNode(newNode, session); + return NULL; } memcpy(newNode->utf8Name, openInfo->utf8Name, newNode->utf8NameLen); @@ -1554,6 +1566,7 @@ HgfsAddNewFileNode(HgfsFileOpenInfo *openInfo, // IN: open info struct newNode->shareAccess = (openInfo->mask & HGFS_OPEN_VALID_SHARE_ACCESS) ? openInfo->shareAccess : HGFS_DEFAULT_SHARE_ACCESS; newNode->flags = 0; + if (append) { newNode->flags |= HGFS_FILE_NODE_APPEND_FL; } @@ -1567,8 +1580,9 @@ HgfsAddNewFileNode(HgfsFileOpenInfo *openInfo, // IN: open info struct newNode->serverLock = openInfo->acquiredLock; newNode->state = FILENODE_STATE_IN_USE_NOT_CACHED; - LOG(4, ("HgfsAddNewFileNode: got new node, handle %u\n", + LOG(4, ("%s: got new node, handle %u\n", __FUNCTION__, HgfsFileNode2Handle(newNode))); + return newNode; } @@ -1582,7 +1596,8 @@ HgfsAddNewFileNode(HgfsFileOpenInfo *openInfo, // IN: open info struct * the maximum number of entries then the first node is removed. The * first node should be the least recently used. * - * The session's nodeArrayLock should be acquired prior to calling this function. + * The session's nodeArrayLock should be acquired prior to calling this + * function. * * Results: * TRUE on success @@ -1604,13 +1619,16 @@ 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; } /* Remove the LRU node if the list is full. */ if (session->numCachedOpenNodes == maxCachedOpenNodes) { if (!HgfsRemoveLruNode(session)) { - LOG(4, ("HgfsAddToCacheInternal: Unable to remove LRU node from cache.\n")); + LOG(4, ("%s: Unable to remove LRU node from cache.\n", + __FUNCTION__)); + return FALSE; } } @@ -1651,7 +1669,8 @@ HgfsAddToCacheInternal(HgfsHandle handle, // IN: HGFS file handle * file descriptor. If the node was not already in the cache then nothing * is done. * - * The session's nodeArrayLock should be acquired prior to calling this function. + * The session's nodeArrayLock should be acquired prior to calling this + * function. * * Results: * TRUE on success @@ -1673,7 +1692,8 @@ HgfsRemoveFromCacheInternal(HgfsHandle handle, // IN: Hgfs handle to the node = HgfsHandle2FileNode(handle, session); if (node == NULL) { - LOG(4, ("HgfsRemoveFromCacheInternal: invalid handle.\n")); + LOG(4, ("%s: invalid handle.\n", __FUNCTION__)); + return FALSE; } @@ -1694,9 +1714,10 @@ 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)) { - LOG(4, ("HgfsRemoveFromCacheInternal: Could not close fd %u\n", - node->fileDesc)); + LOG(4, ("%s: Could not close fd %u\n", __FUNCTION__, node->fileDesc)); + return FALSE; } @@ -1745,15 +1766,19 @@ HgfsIsCachedInternal(HgfsHandle handle, // IN: Structure representing fi node = HgfsHandle2FileNode(handle, session); if (node == NULL) { - LOG(4, ("HgfsIsCachedInternal: invalid handle.\n")); + LOG(4, ("%s: invalid handle.\n", __FUNCTION__)); + return FALSE; } + if (node->state == FILENODE_STATE_IN_USE_CACHED) { /* * Move this node to the end of the list. */ + DblLnkLst_Unlink1(&node->links); DblLnkLst_LinkLast(&session->nodeCachedList, &node->links); + return TRUE; } @@ -1790,6 +1815,7 @@ HgfsIsServerLockAllowed(HgfsSessionInfo *session) // IN: session info SyncMutex_Lock(&session->nodeArrayLock); allowed = session->numCachedLockedNodes < MAX_LOCKED_FILENODES; SyncMutex_Unlock(&session->nodeArrayLock); + return allowed; } @@ -1829,13 +1855,14 @@ HgfsGetNewSearch(HgfsSessionInfo *session) // IN: session info ASSERT(session); ASSERT(session->searchArray); - LOG(4, ("HgfsGetNewSearch: entered\n")); + LOG(4, ("%s: entered\n", __FUNCTION__)); if (!DblLnkLst_IsLinked(&session->searchFreeList)) { /* * 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)) { @@ -1848,7 +1875,8 @@ HgfsGetNewSearch(HgfsSessionInfo *session) // IN: session info newMem = (HgfsSearch *)realloc(session->searchArray, newNumSearches * sizeof *(session->searchArray)); if (!newMem) { - LOG(4, ("HgfsGetNewSearch: can't realloc more searches\n")); + LOG(4, ("%s: can't realloc more searches\n", __FUNCTION__)); + return NULL; } @@ -1862,14 +1890,14 @@ HgfsGetNewSearch(HgfsSessionInfo *session) // IN: session info * must be updated to point to the new portion of memory. */ - LOG(4, ("Rebasing pointers, diff is %"FMTSZ"u, sizeof search is %"FMTSZ"u\n", - ptrDiff, sizeof(HgfsSearch))); + LOG(4, ("Rebasing pointers, diff is %"FMTSZ"u, sizeof search is " + "%"FMTSZ"u\n", ptrDiff, sizeof(HgfsSearch))); LOG(4, ("old: %p new: %p\n", session->searchArray, newMem)); ASSERT(newMem == (HgfsSearch*)((char*)session->searchArray + ptrDiff)); -#define HgfsServerRebase(_ptr, _type) \ - if ((size_t)((char *)_ptr - (char *)session->searchArray) < oldSize) { \ - _ptr = (_type *)((char *)_ptr + ptrDiff); \ +#define HgfsServerRebase(_ptr, _type) \ + if ((size_t)((char *)_ptr - (char *)session->searchArray) < oldSize) { \ + _ptr = (_type *)((char *)_ptr + ptrDiff); \ } /* @@ -1890,7 +1918,9 @@ HgfsGetNewSearch(HgfsSessionInfo *session) // IN: session info } /* Initialize the new searches */ - LOG(4, ("numSearches was %u, now is %u\n", session->numSearches, newNumSearches)); + LOG(4, ("numSearches was %u, now is %u\n", session->numSearches, + newNumSearches)); + for (i = session->numSearches; i < newNumSearches; i++) { DblLnkLst_Init(&newMem[i].links); newMem[i].utf8Dir = NULL; @@ -2011,6 +2041,7 @@ HgfsGetSearchCopy(HgfsHandle handle, // IN: Hgfs search handle exit: SyncMutex_Unlock(&session->searchArrayLock); + return found; } @@ -2048,7 +2079,8 @@ HgfsAddNewSearch(char const *utf8Dir, // IN: UTF8 name of dir to search in /* Get an unused search */ newSearch = HgfsGetNewSearch(session); if (!newSearch) { - LOG(4, ("HgfsAddNewSearch: out of memory\n")); + LOG(4, ("%s: out of memory\n", __FUNCTION__)); + return NULL; } @@ -2061,6 +2093,7 @@ HgfsAddNewSearch(char const *utf8Dir, // IN: UTF8 name of dir to search in newSearch->utf8Dir = strdup(utf8Dir); if (newSearch->utf8Dir == NULL) { HgfsRemoveSearchInternal(newSearch, session); + return NULL; } @@ -2068,11 +2101,13 @@ HgfsAddNewSearch(char const *utf8Dir, // IN: UTF8 name of dir to search in newSearch->utf8ShareName = strdup(utf8ShareName); if (newSearch->utf8ShareName == NULL) { HgfsRemoveSearchInternal(newSearch, session); + return NULL; } - LOG(4, ("HgfsAddNewSearch: got new search, handle %u\n", + LOG(4, ("%s: got new search, handle %u\n", __FUNCTION__, HgfsSearch2SearchHandle(newSearch))); + return newSearch; } @@ -2102,7 +2137,7 @@ HgfsRemoveSearchInternal(HgfsSearch *search, // IN: search ASSERT(search); ASSERT(session); - LOG(4, ("HgfsRemoveSearchInternal: handle %u, dir %s\n", + LOG(4, ("%s: handle %u, dir %s\n", __FUNCTION__, HgfsSearch2SearchHandle(search), search->utf8Dir)); /* Free all of the dirents */ @@ -2239,6 +2274,7 @@ 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; @@ -2246,6 +2282,7 @@ HgfsGetSearchResult(HgfsHandle handle, // IN: Handle to search out: SyncMutex_Unlock(&session->searchArrayLock); + return dent; } @@ -2340,7 +2377,7 @@ HgfsUpdateNodeNames(const char *oldLocalName, // IN: Name of file to look for if (strcmp(fileNode->utf8Name, oldLocalName) == 0) { newBuffer = malloc(newBufferLen + 1); if (!newBuffer) { - LOG(4, ("HgfsUpdateNodeNames: Failed to update a node name.\n")); + LOG(4, ("%s: Failed to update a node name.\n", __FUNCTION__)); continue; } memcpy(newBuffer, newLocalName, newBufferLen); @@ -2401,14 +2438,14 @@ HgfsServerClose(char const *packetIn, // IN: incoming packet HgfsRequestClose *request; request = (HgfsRequestClose *)packetIn; file = &request->file; - replySize = sizeof *request; + replySize = sizeof (HgfsReplyClose); packetOut = Util_SafeMalloc(replySize); } - LOG(4, ("HgfsServerClose: close fh %u\n", *file)); + LOG(4, ("%s: close fh %u\n", __FUNCTION__, *file)); if (!HgfsRemoveFromCache(*file, session)) { - LOG(4, ("HgfsServerClose: Could not remove the node from cache.\n")); + LOG(4, ("%s: Could not remove the node from cache.\n", __FUNCTION__)); status = HGFS_INTERNAL_STATUS_ERROR; goto error; } else { @@ -2420,10 +2457,12 @@ HgfsServerClose(char const *packetIn, // IN: incoming packet if (!HgfsPacketSend(packetOut, replySize, session, 0)) { goto error; } + return 0; error: free(packetOut); + return status; } @@ -2481,11 +2520,11 @@ HgfsServerSearchClose(char const *packetIn, // IN: incoming packet search = &request->search; } - LOG(4, ("HgfsServerSearchClose: close search #%u\n", *search)); + LOG(4, ("%s: close search #%u\n", __FUNCTION__, *search)); if (!HgfsRemoveSearch(*search, session)) { /* Invalid handle */ - LOG(4, ("HgfsServerSearchClose: invalid handle %u\n", *search)); + LOG(4, ("%s: invalid handle %u\n", __FUNCTION__, *search)); status = HGFS_INTERNAL_STATUS_ERROR; goto error; } @@ -2495,10 +2534,12 @@ HgfsServerSearchClose(char const *packetIn, // IN: incoming packet if (!HgfsPacketSend(packetOut, replySize, session, 0)) { goto error; } + return 0; error: free(packetOut); + return status; } @@ -2605,7 +2646,9 @@ HgfsServerSessionReceive(char const *packetIn, // IN: incoming packet ASSERT(request); if (session->state == HGFS_SESSION_STATE_CLOSED) { - LOG(4, ("%s: %d: Received packet after disconnected.\n", __FUNCTION__, __LINE__)); + LOG(4, ("%s: %d: Received packet after disconnected.\n", __FUNCTION__, + __LINE__)); + return; } @@ -2625,8 +2668,7 @@ HgfsServerSessionReceive(char const *packetIn, // IN: incoming packet if (op < sizeof handlers / sizeof handlers[0]) { if (packetSize >= handlers[op].minReqSize) { HgfsInternalStatus internalStatus; - internalStatus = (*handlers[op].handler)(packetIn, - packetSize, + internalStatus = (*handlers[op].handler)(packetIn, packetSize, session); status = HgfsConvertFromInternalStatus(internalStatus); } else { @@ -2634,13 +2676,16 @@ HgfsServerSessionReceive(char const *packetIn, // IN: incoming packet * The input packet is smaller than the minimal size needed for the * operation. */ + status = HGFS_STATUS_PROTOCOL_ERROR; - LOG(4, ("%s: %d: Possible BUG! Smaller packet.\n", __FUNCTION__, __LINE__)); + LOG(4, ("%s: %d: Possible BUG! Smaller packet.\n", __FUNCTION__, + __LINE__)); } } else { /* Unknown opcode */ status = HGFS_STATUS_PROTOCOL_ERROR; - LOG(4, ("%s: %d: Possible BUG! Invalid opcode.\n", __FUNCTION__, __LINE__)); + LOG(4, ("%s: %d: Possible BUG! Invalid opcode.\n", __FUNCTION__, + __LINE__)); } HGFS_ASSERT_CLIENT(op); @@ -2708,10 +2753,12 @@ HgfsServer_InitState(HgfsServerSessionCallbacks **callbackTable, // IN/OUT: our if (!HgfsServerPlatformInit()) { LOG(4, ("Could not initialize server platform specific \n")); + return FALSE; } *callbackTable = &hgfsServerSessionCBTable; + return TRUE; } @@ -2788,15 +2835,18 @@ HgfsServerSessionConnect(void *transportData, // IN: transport session co /* * Initialize all our locks first as these can fail. */ + if (!SyncMutex_Init(&session->fileIOLock, NULL)) { free(session); LOG(4, ("%s: Could not create node array sync mutex.\n", __FUNCTION__)); + return FALSE; } if (!SyncMutex_Init(&session->nodeArrayLock, NULL)) { SyncMutex_Destroy(&session->fileIOLock); free(session); LOG(4, ("%s: Could not create node array sync mutex.\n", __FUNCTION__)); + return FALSE; } if (!SyncMutex_Init(&session->searchArrayLock, NULL)) { @@ -2804,18 +2854,20 @@ HgfsServerSessionConnect(void *transportData, // IN: transport session co SyncMutex_Destroy(&session->nodeArrayLock); free(session); LOG(4, ("%s: Could not create search array sync mutex.\n", __FUNCTION__)); + return FALSE; } /* * Initialize the node handling components. */ + DblLnkLst_Init(&session->nodeFreeList); DblLnkLst_Init(&session->nodeCachedList); /* Allocate array of FileNodes and add them to free list. */ session->numNodes = NUM_FILE_NODES; - session->nodeArray = Util_SafeCalloc(session->numNodes, sizeof(HgfsFileNode)); + session->nodeArray = Util_SafeCalloc(session->numNodes, sizeof (HgfsFileNode)); session->numCachedOpenNodes = 0; session->numCachedLockedNodes = 0; @@ -2834,17 +2886,19 @@ HgfsServerSessionConnect(void *transportData, // IN: transport session co /* Allocate array of searches and add them to free list. */ session->numSearches = NUM_SEARCHES; - session->searchArray = Util_SafeCalloc(session->numSearches, sizeof(HgfsSearch)); + session->searchArray = Util_SafeCalloc(session->numSearches, sizeof (HgfsSearch)); for (i = 0; i < session->numSearches; i++) { DblLnkLst_Init(&session->searchArray[i].links); /* Append at the end of the list. */ - DblLnkLst_LinkLast(&session->searchFreeList, &session->searchArray[i].links); + DblLnkLst_LinkLast(&session->searchFreeList, + &session->searchArray[i].links); } /* * Initialize the general session stuff. */ + session->type = HGFS_SESSION_TYPE_REGULAR; session->state = HGFS_SESSION_STATE_OPEN; session->transportData = transportData; @@ -2854,6 +2908,7 @@ HgfsServerSessionConnect(void *transportData, // IN: transport session co /* Give our session a reference to hold while we are open. */ HgfsServerSessionGet(session); *sessionData = session; + return TRUE; } @@ -2956,7 +3011,6 @@ HgfsServerExitSessionInternal(HgfsSessionInfo *session) // IN: session contex ASSERT(session->nodeArray); ASSERT(session->searchArray); - SyncMutex_Lock(&session->nodeArrayLock); LOG(4, ("%s: exiting.\n", __FUNCTION__)); @@ -3086,9 +3140,12 @@ HgfsServer_ProcessPacket(char const *packetIn, // IN: incoming packet * Create the session if not already created. * This session is destroyed in HgfsServer_ExitState. */ + if (hgfsStaticSession.session == NULL) { - if (!HgfsServerSessionConnect(NULL, NULL, (void **)&hgfsStaticSession.session)) { + if (!HgfsServerSessionConnect(NULL, NULL, + (void **)&hgfsStaticSession.session)) { *packetLen = 0; + return; } @@ -3103,9 +3160,11 @@ HgfsServer_ProcessPacket(char const *packetIn, // IN: incoming packet * we should have the reply by now. * XXX This should change if any async replies are expected. */ + ASSERT(hgfsStaticSession.bufferOut); - memcpy(packetOut, hgfsStaticSession.bufferOut, hgfsStaticSession.bufferOutLen); + memcpy(packetOut, hgfsStaticSession.bufferOut, + hgfsStaticSession.bufferOutLen); *packetLen = hgfsStaticSession.bufferOutLen; HgfsServerSessionSendComplete(hgfsStaticSession.session, @@ -3182,6 +3241,7 @@ HgfsPacketSend(char *packet, // IN: packet buffer } HgfsServerSessionPut(session); + return result; } @@ -3259,6 +3319,7 @@ HgfsServerCheckPathPrefix(const char *path, // IN: Path to check * 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; } @@ -3319,6 +3380,7 @@ 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; @@ -3365,6 +3427,7 @@ 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; @@ -3384,8 +3447,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)) { + share->path, share->pathLen)) { LOG(4, ("%s: Search is still valid\n", __FUNCTION__)); break; } @@ -3480,8 +3542,10 @@ 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, ("HgfsServerStatFs: could not get the volume name\n")); + LOG(4, ("%s: could not get the volume name\n", __FUNCTION__)); + return FALSE; } @@ -3489,8 +3553,8 @@ HgfsServerStatFs(const char *pathName, // IN: Path we're interested in Str_Strcpy(p.mountPoint, pathName, sizeof p.mountPoint); wiperError = WiperSinglePartition_GetSpace(&p, freeBytes, totalBytes); if (strlen(wiperError) > 0) { - LOG(4, ("HgfsServerQueryVolume: error using wiper lib: %s\n", - wiperError)); + LOG(4, ("%s: error using wiper lib: %s\n", __FUNCTION__, wiperError)); + return FALSE; } @@ -3556,7 +3620,8 @@ HgfsServerGetAccess(char *cpName, // IN: Cross-platform filena */ len = CPName_GetComponent(cpName, inEnd, (char const **) &next); if (len < 0) { - LOG(4, ("HgfsServerGetAccess: get first component failed\n")); + LOG(4, ("%s: get first component failed\n", __FUNCTION__)); + return HGFS_NAME_STATUS_FAILURE; } @@ -3566,21 +3631,20 @@ HgfsServerGetAccess(char *cpName, // IN: Cross-platform filena } /* Check permission on the share and get the share path */ - nameStatus = HgfsServerPolicy_GetSharePath(cpName, - len, - mode, - &sharePathLen, + nameStatus = HgfsServerPolicy_GetSharePath(cpName, len, mode, &sharePathLen, &sharePath); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { - LOG(4, ("HgfsServerGetAccess: No such share (%s) or access denied\n", + LOG(4, ("%s: No such share (%s) or access denied\n", __FUNCTION__, cpName)); + return nameStatus; } /* Get the config options. */ nameStatus = HgfsServerPolicy_GetShareOptions(cpName, len, &shareOptions); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { - LOG(4, ("HgfsServerGetAccess: no matching share: %s.\n", cpName)); + LOG(4, ("%s: no matching share: %s.\n", __FUNCTION__, cpName)); + return nameStatus; } @@ -3591,10 +3655,12 @@ HgfsServerGetAccess(char *cpName, // IN: Cross-platform filena /* * Allocate space for the string. We trim the unused space later. */ + outSize = HGFS_PATH_MAX; - myBufOut = (char *)malloc(outSize * sizeof *myBufOut); + myBufOut = (char *) malloc(outSize * sizeof *myBufOut); if (!myBufOut) { - LOG(4, ("HgfsServerGetAccess: out of memory allocating string\n")); + LOG(4, ("%s: out of memory allocating string\n", __FUNCTION__)); + return HGFS_NAME_STATUS_OUT_OF_MEMORY; } @@ -3603,6 +3669,7 @@ HgfsServerGetAccess(char *cpName, // IN: Cross-platform filena /* * See if we are dealing with a "root" share or regular share */ + if (strlen(sharePath) == 0) { size_t prefixLen; @@ -3612,14 +3679,13 @@ 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, - &cpNameSize, - &tempSize, - &tempPtr); + &cpNameSize, &tempSize, &tempPtr); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { - LOG(4, ("HgfsServerGetAccess: ConvertFromRoot not complete\n")); + LOG(4, ("%s: ConvertFromRoot not complete\n", __FUNCTION__)); goto error; } @@ -3627,7 +3693,7 @@ HgfsServerGetAccess(char *cpName, // IN: Cross-platform filena /* Copy the UTF8 prefix to the output buffer. */ if (prefixLen >= HGFS_PATH_MAX) { - Log("HgfsServerGetAccess: error: prefix too long\n"); + Log("%s: error: prefix too long\n", __FUNCTION__); nameStatus = HGFS_NAME_STATUS_TOO_LONG; goto error; } @@ -3640,8 +3706,9 @@ HgfsServerGetAccess(char *cpName, // IN: Cross-platform filena /* * This is a regular share. Append the path to the out buffer. */ + if (outSize < sharePathLen + 1) { - LOG(4, ("HgfsServerGetAccess: share path too big\n")); + LOG(4, ("%s: share path too big\n", __FUNCTION__)); nameStatus = HGFS_NAME_STATUS_TOO_LONG; goto error; } @@ -3656,11 +3723,9 @@ HgfsServerGetAccess(char *cpName, // IN: Cross-platform filena tempPtr = tempBuf; - if (CPName_ConvertFrom((char const **) &cpName, - &cpNameSize, - &tempSize, + if (CPName_ConvertFrom((char const **) &cpName, &cpNameSize, &tempSize, &tempPtr) < 0) { - LOG(4, ("HgfsServerGetAccess: CP name conversion failed\n")); + LOG(4, ("%s: CP name conversion failed\n", __FUNCTION__)); nameStatus = HGFS_NAME_STATUS_FAILURE; goto error; } @@ -3670,16 +3735,15 @@ HgfsServerGetAccess(char *cpName, // IN: Cross-platform filena * separator and since our remaining paths start with a separator, we * will skip over the second separator for this case. Bug 166755. */ - if ((out != myBufOut) && - (*(out - 1) == DIRSEPC) && - (tempBuf[0] == DIRSEPC)) { + + if ((out != myBufOut) && (*(out - 1) == DIRSEPC) && (tempBuf[0] == DIRSEPC)) { startIndex++; } pathNameLen = tempPtr - &tempBuf[startIndex]; /* Copy UTF8 to the output buffer. */ if (pathNameLen >= outSize) { - LOG(4, ("HgfsServerGetAccess: pathname too long\n")); + LOG(4, ("%s: pathname too long\n", __FUNCTION__)); nameStatus = HGFS_NAME_STATUS_TOO_LONG; goto error; } @@ -3698,17 +3762,16 @@ HgfsServerGetAccess(char *cpName, // IN: Cross-platform filena * so there is a need to convert the incoming name from HGFS clients * which is assumed to be in the normalized form C (precomposed). */ - if (!CodeSet_Utf8FormCToUtf8FormD(myBufOut, - myBufOutLen, - &tempPtr, + + if (!CodeSet_Utf8FormCToUtf8FormD(myBufOut, myBufOutLen, &tempPtr, &nameLen)) { - LOG(4, ("HgfsServerGetAccess: unicode conversion to form D failed.\n")); + LOG(4, ("%s: unicode conversion to form D failed.\n", __FUNCTION__)); nameStatus = HGFS_NAME_STATUS_FAILURE; goto error; } free(myBufOut); - LOG(4, ("HgfsServerGetAccess: name is \"%s\"\n", myBufOut)); + LOG(4, ("%s: name is \"%s\"\n", __FUNCTION__, myBufOut)); /* Save returned pointers, update buffer length. */ myBufOut = tempPtr; @@ -3721,17 +3784,21 @@ HgfsServerGetAccess(char *cpName, // IN: Cross-platform filena * Convert file name to proper case if host default config option is not set * and case conversion is required for this platform. */ - if (!HgfsServerPolicy_IsShareOptionSet(shareOptions, HGFS_SHARE_HOST_DEFAULT_CASE) && + + if (!HgfsServerPolicy_IsShareOptionSet(shareOptions, + HGFS_SHARE_HOST_DEFAULT_CASE) && HgfsServerCaseConversionRequired()) { nameStatus = HgfsServerConvertCase(sharePath, sharePathLen, myBufOut, myBufOutLen, caseFlags, - &convertedMyBufOut, &convertedMyBufOutLen); + &convertedMyBufOut, + &convertedMyBufOutLen); /* * On success, use the converted file names for further operations. */ + if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { - LOG(4, ("HgfsServerGetAccess: HgfsServerConvertCase failed.\n")); + LOG(4, ("%s: HgfsServerConvertCase failed.\n", __FUNCTION__)); goto error; } @@ -3742,19 +3809,22 @@ HgfsServerGetAccess(char *cpName, // IN: Cross-platform filena } /* Check for symlinks if the followSymlinks option is not set. */ - if (!HgfsServerPolicy_IsShareOptionSet(shareOptions, HGFS_SHARE_FOLLOW_SYMLINKS)) { + if (!HgfsServerPolicy_IsShareOptionSet(shareOptions, + HGFS_SHARE_FOLLOW_SYMLINKS)) { /* * Verify that either the path is same as share path or the path until the * parent directory is within the share. * - * XXX: Symlink check could become susceptible to TOCTOU (time-of-check, time-of-use) - * attack when we move to asynchrounous HGFS operations. We should use the resolved - * file path for further file system operations, instead of using the one passed - * from the client. + * XXX: Symlink check could become susceptible to TOCTOU (time-of-check, + * time-of-use) attack when we move to asynchrounous HGFS operations. + * 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, sharePath, + sharePathLen); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { - LOG(4, ("HgfsServerGetAccess: parent path failed to be resolved: %d\n", + LOG(4, ("%s: parent path failed to be resolved: %d\n", __FUNCTION__, nameStatus)); goto error; } @@ -3768,7 +3838,7 @@ HgfsServerGetAccess(char *cpName, // IN: Cross-platform filena /* Enough space for resulting string + NUL termination */ p = realloc(myBufOut, (myBufOutLen + 1) * sizeof *p); if (!p) { - LOG(4, ("HgfsServerGetAccess: failed to trim memory\n")); + LOG(4, ("%s: failed to trim memory\n", __FUNCTION__)); } else { myBufOut = p; } @@ -3778,13 +3848,15 @@ HgfsServerGetAccess(char *cpName, // IN: Cross-platform filena } } - LOG(4, ("HgfsServerGetAccess: name is \"%s\"\n", myBufOut)); + LOG(4, ("%s: name is \"%s\"\n", __FUNCTION__, myBufOut)); *bufOut = myBufOut; + return HGFS_NAME_STATUS_COMPLETE; error: free(myBufOut); + return nameStatus; } @@ -3823,6 +3895,7 @@ HgfsServerIsSharedFolderOnly(char const *cpName,// IN: Cross-platform filename len = CPName_GetComponent(cpName, inEnd, &next); ASSERT(len > 0); + return (next == inEnd); } @@ -3854,8 +3927,9 @@ HgfsServerDumpDents(HgfsHandle searchHandle, // IN: Handle to dump dents from SyncMutex_Lock(&session->searchArrayLock); search = HgfsSearchHandle2Search(searchHandle, session); if (search != NULL) { - Log("HgfsServerDumpDents: %u dents in \"%s\"\n", - search->numDents, search->utf8Dir); + Log("%s: %u dents in \"%s\"\n", __FUNCTION__, search->numDents, + search->utf8Dir); + Log("Dumping dents:\n"); for (i = 0; i < search->numDents; i++) { Log("\"%s\"\n", search->dents[i]->d_name); @@ -3898,7 +3972,7 @@ HgfsServerGetDents(HgfsGetNameFunc getName, // IN: Function to get name state = initName(); if (!state) { - LOG(4, ("HgfsServerGetDents: Couldn't init state\n")); + LOG(4, ("%s: Couldn't init state\n", __FUNCTION__)); goto error_free; } @@ -3919,13 +3993,13 @@ HgfsServerGetDents(HgfsGetNameFunc getName, // IN: Function to get name len = 2; } else { if (!getName(state, &name, &len, &done)) { - LOG(4, ("HgfsServerGetDents: Couldn't get next name\n")); + LOG(4, ("%s: Couldn't get next name\n", __FUNCTION__)); goto error; } } if (done) { - LOG(4, ("HgfsServerGetDents: No more names\n")); + LOG(4, ("%s: No more names\n", __FUNCTION__)); break; } @@ -3936,12 +4010,13 @@ 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; #endif if (len >= maxLen) { - Log("HgfsServerGetDents: Error: Name \"%s\" is too long.\n", name); + Log("%s: Error: Name \"%s\" is too long.\n", __FUNCTION__, name); continue; } @@ -3956,25 +4031,25 @@ HgfsServerGetDents(HgfsGetNameFunc getName, // IN: Function to get name } p = realloc(myDents, totalDents * sizeof *myDents); if (!p) { - LOG(4, ("HgfsServerGetDents: Couldn't reallocate array memory\n")); + LOG(4, ("%s: Couldn't reallocate array memory\n", __FUNCTION__)); goto error; } myDents = (DirectoryEntry **)p; } /* This file/directory can be added to the list. */ - LOG(4, ("HgfsServerGetDents: Nextfilename = \"%s\"\n", name)); + LOG(4, ("%s: Nextfilename = \"%s\"\n", __FUNCTION__, name)); /* * Start with the size of the DirectoryEntry struct, subtract the static - * length of the d_name buffer (256 in Linux, 1 in Solaris, etc) and add back - * just enough space for the UTF-8 name and nul terminator. + * length of the d_name buffer (256 in Linux, 1 in Solaris, etc) and add + * back just enough space for the UTF-8 name and nul terminator. */ - newDirEntryLen = - sizeof *pDirEntry - sizeof pDirEntry->d_name + len + 1; + + newDirEntryLen = sizeof *pDirEntry - sizeof pDirEntry->d_name + len + 1; pDirEntry = (DirectoryEntry *)malloc(newDirEntryLen); if (!pDirEntry) { - LOG(4, ("HgfsServerGetDents: Couldn't allocate dentry memory\n")); + LOG(4, ("%s: Couldn't allocate dentry memory\n", __FUNCTION__)); goto error; } pDirEntry->d_reclen = (unsigned short)newDirEntryLen; @@ -3987,7 +4062,7 @@ HgfsServerGetDents(HgfsGetNameFunc getName, // IN: Function to get name /* We are done; cleanup the state */ if (!cleanupName(state)) { - LOG(4, ("HgfsServerGetDents: Non-error cleanup failed\n")); + LOG(4, ("%s: Non-error cleanup failed\n", __FUNCTION__)); goto error_free; } @@ -3997,7 +4072,7 @@ HgfsServerGetDents(HgfsGetNameFunc getName, // IN: Function to get name p = realloc(myDents, numDents * sizeof *myDents); if (!p) { - LOG(4, ("HgfsServerGetDents: Couldn't realloc less array memory\n")); + LOG(4, ("%s: Couldn't realloc less array memory\n", __FUNCTION__)); *dents = myDents; } else { *dents = (DirectoryEntry **)p; @@ -4009,7 +4084,7 @@ HgfsServerGetDents(HgfsGetNameFunc getName, // IN: Function to get name error: /* Cleanup the callback state */ if (!cleanupName(state)) { - LOG(4, ("HgfsServerGetDents: Error cleanup failed\n")); + LOG(4, ("%s: Error cleanup failed\n", __FUNCTION__)); } error_free: @@ -4075,7 +4150,7 @@ HgfsServerSearchRealDir(char const *baseDir, // IN: Directory to search SyncMutex_Lock(&session->searchArrayLock); search = HgfsAddNewSearch(baseDir, type, shareName, session); if (!search) { - LOG(4, ("HgfsServerSearchRealDir: failed to get new search\n")); + LOG(4, ("%s: failed to get new search\n", __FUNCTION__)); status = HGFS_INTERNAL_STATUS_ERROR; goto out; } @@ -4084,7 +4159,7 @@ HgfsServerSearchRealDir(char const *baseDir, // IN: Directory to search nameStatus = HgfsServerPolicy_GetShareOptions(shareName, strlen(shareName), &configOptions); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { - LOG(4, ("HgfsServerSearchRealDir: no matching share: %s.\n", shareName)); + LOG(4, ("%s: no matching share: %s.\n", __FUNCTION__, shareName)); status = HGFS_INTERNAL_STATUS_ERROR; HgfsRemoveSearchInternal(search, session); goto out; @@ -4096,15 +4171,17 @@ HgfsServerSearchRealDir(char const *baseDir, // IN: Directory to search status = HgfsServerScandir(baseDir, baseDirLen, followSymlinks, &search->dents, &numDents); if (status != 0) { - LOG(4, ("HgfsServerSearchRealDir: couldn't scandir\n")); + LOG(4, ("%s: couldn't scandir\n", __FUNCTION__)); HgfsRemoveSearchInternal(search, session); goto out; } search->numDents = numDents; *handle = HgfsSearch2SearchHandle(search); + out: SyncMutex_Unlock(&session->searchArrayLock); + return status; } @@ -4149,17 +4226,14 @@ HgfsServerSearchVirtualDir(HgfsGetNameFunc *getName, // IN: Name enumerator SyncMutex_Lock(&session->searchArrayLock); search = HgfsAddNewSearch("", type, "", session); if (!search) { - LOG(4, ("HgfsServerSearchVirtualDir: failed to get new search\n")); + LOG(4, ("%s: failed to get new search\n", __FUNCTION__)); status = HGFS_INTERNAL_STATUS_ERROR; goto out; } - result = HgfsServerGetDents(getName, - initName, - cleanupName, - &search->dents); + result = HgfsServerGetDents(getName, initName, cleanupName, &search->dents); if (result < 0) { - LOG(4, ("HgfsServerSearchVirtualDir: couldn't get dents\n")); + LOG(4, ("%s: couldn't get dents\n", __FUNCTION__)); HgfsRemoveSearchInternal(search, session); status = HGFS_INTERNAL_STATUS_ERROR; goto out; @@ -4167,8 +4241,10 @@ HgfsServerSearchVirtualDir(HgfsGetNameFunc *getName, // IN: Name enumerator search->numDents = result; *handle = HgfsSearch2SearchHandle(search); + out: SyncMutex_Unlock(&session->searchArrayLock); + return status; } @@ -4197,6 +4273,7 @@ HgfsRemoveFromCache(HgfsHandle handle, // IN: Hgfs handle to the node HgfsSessionInfo *session) // IN: Session info { Bool removed = FALSE; + SyncMutex_Lock(&session->nodeArrayLock); removed = HgfsRemoveFromCacheInternal(handle, session); SyncMutex_Unlock(&session->nodeArrayLock); @@ -4252,7 +4329,8 @@ HgfsIsCached(HgfsHandle handle, // IN: Structure representing file node * * Assumes that there is at least one node in the cache. * - * The session's nodeArrayLock should be acquired prior to calling this function. + * The session's nodeArrayLock should be acquired prior to calling this + * function. * * Results: * TRUE on success @@ -4276,7 +4354,9 @@ HgfsRemoveLruNode(HgfsSessionInfo *session) // IN: session info /* Remove the first item from the list that does not have a server lock. */ while (!found) { - lruNode = DblLnkLst_Container(session->nodeCachedList.next, HgfsFileNode, links); + 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. */ @@ -4288,7 +4368,8 @@ HgfsRemoveLruNode(HgfsSessionInfo *session) // IN: session info } handle = HgfsFileNode2Handle(lruNode); if (!HgfsRemoveFromCacheInternal(handle, session)) { - LOG(4, ("HgfsRemoveLruNode: Could not remove the node from cache.\n")); + LOG(4, ("%s: Could not remove the node from cache.\n", __FUNCTION__)); + return FALSE; } @@ -4318,9 +4399,11 @@ HgfsAddToCache(HgfsHandle handle, // IN: HGFS file handle HgfsSessionInfo *session) // IN: Session info { Bool added = FALSE; + SyncMutex_Lock(&session->nodeArrayLock); added = HgfsAddToCacheInternal(handle, session); SyncMutex_Unlock(&session->nodeArrayLock); + return added; } @@ -4365,9 +4448,11 @@ HgfsCreateAndCacheFileNode(HgfsFileOpenInfo *openInfo, // IN: Open info struct /* * Get first component. */ + len = CPName_GetComponent(openInfo->cpName, inEnd, &next); if (len < 0) { - LOG(4, ("HgfsServerGetAccess: get first component failed\n")); + LOG(4, ("%s: get first component failed\n", __FUNCTION__)); + return FALSE; } @@ -4381,24 +4466,21 @@ HgfsCreateAndCacheFileNode(HgfsFileOpenInfo *openInfo, // IN: Open info struct } SyncMutex_Lock(&session->nodeArrayLock); - node = HgfsAddNewFileNode(openInfo, - localId, - fileDesc, - append, - len, - openInfo->cpName, - sharedFolderOpen, - session); + node = HgfsAddNewFileNode(openInfo, localId, fileDesc, append, len, + openInfo->cpName, sharedFolderOpen, session); + if (node == NULL) { - LOG(4, ("HgfsCreateAndCacheFileNode: Failed to add new node.\n")); + LOG(4, ("%s: Failed to add new node.\n", __FUNCTION__)); SyncMutex_Unlock(&session->nodeArrayLock); + return FALSE; } handle = HgfsFileNode2Handle(node); if (!HgfsAddToCacheInternal(handle, session)) { - LOG(4, ("HgfsCreateAndCacheFileNode: Failed to add node to the cache.\n")); + LOG(4, ("%s: Failed to add node to the cache.\n", __FUNCTION__)); SyncMutex_Unlock(&session->nodeArrayLock); + return FALSE; } SyncMutex_Unlock(&session->nodeArrayLock); @@ -4448,7 +4530,7 @@ HgfsUnpackOpenRequest(char const *packetIn, // IN: request packet { HgfsRequestOpenV3 *requestV3 = (HgfsRequestOpenV3 *)HGFS_REQ_GET_PAYLOAD_V3(packetIn); - LOG(4, ("HgfsUnpackOpenRequest: HGFS_OP_OPEN_V3\n")); + LOG(4, ("%s: HGFS_OP_OPEN_V3\n", __FUNCTION__)); /* Enforced by the dispatch function. */ @@ -4464,8 +4546,10 @@ 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. */ + return FALSE; } @@ -4474,6 +4558,7 @@ 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; @@ -4502,6 +4587,7 @@ HgfsUnpackOpenRequest(char const *packetIn, // IN: request packet if (!(requestV2->mask & HGFS_OPEN_VALID_FILE_NAME)) { /* We do not support open requests without a valid file name. */ + return FALSE; } @@ -4509,6 +4595,7 @@ 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; @@ -4519,6 +4606,7 @@ 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 = requestV2->mask; openInfo->mode = requestV2->mode; openInfo->cpName = requestV2->fileName.name; @@ -4537,8 +4625,7 @@ HgfsUnpackOpenRequest(char const *packetIn, // IN: request packet } case HGFS_OP_OPEN: { - HgfsRequestOpen *requestV1 = - (HgfsRequestOpen *)packetIn; + HgfsRequestOpen *requestV1 = (HgfsRequestOpen *)packetIn; /* Enforced by the dispatch function. */ ASSERT(packetSize >= sizeof *requestV1); @@ -4551,14 +4638,15 @@ HgfsUnpackOpenRequest(char const *packetIn, // IN: request packet if (requestV1->fileName.length > extra) { /* The input packet is smaller than the request. */ + return FALSE; } /* For OpenV1 requests, we know exactly what fields we expect. */ openInfo->mask = HGFS_OPEN_VALID_MODE | - HGFS_OPEN_VALID_FLAGS | - HGFS_OPEN_VALID_OWNER_PERMS | - HGFS_OPEN_VALID_FILE_NAME; + HGFS_OPEN_VALID_FLAGS | + HGFS_OPEN_VALID_OWNER_PERMS | + HGFS_OPEN_VALID_FILE_NAME; openInfo->mode = requestV1->mode; openInfo->cpName = requestV1->fileName.name; openInfo->cpNameSize = requestV1->fileName.length; @@ -4713,8 +4801,8 @@ HgfsUnpackDeleteRequest(char const *packetIn, // IN: request packet case HGFS_OP_DELETE_DIR_V3: { HgfsRequestDeleteV3 *requestV3; - requestV3 = (HgfsRequestDeleteV3 *)HGFS_REQ_GET_PAYLOAD_V3(packetIn); - LOG(4, ("HgfsUnpackDeleteRequest: HGFS_OP_DELETE_DIR_V3\n")); + requestV3 = (HgfsRequestDeleteV3 *) HGFS_REQ_GET_PAYLOAD_V3(packetIn); + LOG(4, ("%s: HGFS_OP_DELETE_DIR_V3\n", __FUNCTION__)); /* Enforced by the dispatch function. */ ASSERT(packetSize >= HGFS_REQ_PAYLOAD_SIZE_V3(requestV3)); @@ -4726,6 +4814,7 @@ 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; @@ -4738,8 +4827,10 @@ 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 */ + return FALSE; } *cpName = requestV3->fileName.name; @@ -4763,6 +4854,7 @@ 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 (*hints & HGFS_DELETE_HINT_USE_FILE_DESC) { *file = requestV2->file; *cpName = NULL; @@ -4774,8 +4866,10 @@ 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 */ + return FALSE; } *cpName = requestV2->fileName.name; @@ -4794,12 +4888,13 @@ HgfsUnpackDeleteRequest(char const *packetIn, // IN: request packet extra = packetSize - sizeof *requestV1; /* - * request->fileName.length is user-provided, so this test must be carefully - * written to prevent wraparounds. + * request->fileName.length is user-provided, so this test must be + * carefully written to prevent wraparounds. */ if (requestV1->fileName.length > extra) { /* The input packet is smaller than the request. */ + return FALSE; } *cpName = requestV1->fileName.name; @@ -4873,7 +4968,7 @@ HgfsPackDeleteReply(char const *packetIn, // IN: incoming packet ((HgfsReply *)*packetOut)->status = HgfsConvertFromInternalStatus(status); break; default: - LOG(4, ("HgfsPackDeleteReply: invalid op code %d\n", header->op)); + LOG(4, ("%s: invalid op code %d\n", __FUNCTION__, header->op)); result = FALSE; break; } @@ -4951,7 +5046,7 @@ HgfsUnpackRenameRequest(char const *packetIn, // IN: request packet HgfsFileNameV3 *newName; requestV3 = (HgfsRequestRenameV3 *)HGFS_REQ_GET_PAYLOAD_V3(packetIn); - LOG(4, ("HgfsUnpackRenameRequest: HGFS_OP_RENAME_V3\n")); + LOG(4, ("%s: HGFS_OP_RENAME_V3\n", __FUNCTION__)); /* Enforced by the dispatch function. */ ASSERT(packetSize >= HGFS_REQ_PAYLOAD_SIZE_V3(requestV3)); @@ -4964,6 +5059,7 @@ 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; @@ -4977,8 +5073,10 @@ 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 */ + return FALSE; } @@ -4986,7 +5084,8 @@ HgfsUnpackRenameRequest(char const *packetIn, // IN: request packet *cpOldName = requestV3->oldName.name; *cpOldNameLen = requestV3->oldName.length; *oldCaseFlags = requestV3->oldName.caseType; - newName = (HgfsFileNameV3 *)(requestV3->oldName.name + 1 + *cpOldNameLen); + newName = (HgfsFileNameV3 *)(requestV3->oldName.name + 1 + + *cpOldNameLen); } extra -= *cpOldNameLen; @@ -4999,6 +5098,7 @@ HgfsUnpackRenameRequest(char const *packetIn, // IN: request packet } else { if (newName->length > extra) { /* The input packet is smaller than the request */ + return FALSE; } @@ -5027,6 +5127,7 @@ HgfsUnpackRenameRequest(char const *packetIn, // IN: request packet * alone test the filename or its length. This applies to the source * and the target. */ + if (*hints & HGFS_RENAME_HINT_USE_SRCFILE_DESC) { *srcFile = requestV2->srcFile; *cpOldName = NULL; @@ -5037,8 +5138,10 @@ HgfsUnpackRenameRequest(char const *packetIn, // IN: request packet * request->fileName.length is user-provided, so this test must be * carefully written to prevent wraparounds. */ + if (requestV2->oldName.length > extra) { /* The input packet is smaller than the request */ + return FALSE; } @@ -5058,6 +5161,7 @@ HgfsUnpackRenameRequest(char const *packetIn, // IN: request packet + *cpOldNameLen); if (newName->length > extra) { /* The input packet is smaller than the request */ + return FALSE; } @@ -5080,11 +5184,13 @@ HgfsUnpackRenameRequest(char const *packetIn, // IN: request packet extra = packetSize - sizeof *requestV1; /* - * request->fileName.length is user-provided, so this test must be carefully - * written to prevent wraparounds. + * request->fileName.length is user-provided, so this test must be + * carefully written to prevent wraparounds. */ + if (requestV1->oldName.length > extra) { /* The input packet is smaller than the request. */ + return FALSE; } @@ -5099,8 +5205,10 @@ HgfsUnpackRenameRequest(char const *packetIn, // IN: request packet * newName->length is user-provided, so this test must be carefully * written to prevent wraparounds. */ + if (newName->length > extra) { /* The input packet is smaller than the request. */ + return FALSE; } @@ -5169,13 +5277,13 @@ HgfsPackRenameReply(char const *packetIn, // IN: incoming packet } case HGFS_OP_RENAME_V2: case HGFS_OP_RENAME: - *packetSize = sizeof(HgfsReplyRename); + *packetSize = sizeof (HgfsReplyRename); *packetOut = Util_SafeMalloc(*packetSize); ((HgfsReply *)*packetOut)->id = header->id; ((HgfsReply *)*packetOut)->status = HgfsConvertFromInternalStatus(status); break; default: - LOG(4, ("HgfsPackRenameReply: invalid op code %d\n", header->op)); + LOG(4, ("%s: invalid op code %d\n", __FUNCTION__, header->op)); result = FALSE; break; } @@ -5247,6 +5355,7 @@ HgfsUnpackGetattrRequest(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. */ + *hints = requestV3->hints; if (requestV3->fileName.flags & HGFS_FILE_NAME_USE_FILE_DESC) { *file = requestV3->fileName.fid; @@ -5260,15 +5369,17 @@ HgfsUnpackGetattrRequest(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 */ + return FALSE; } *cpName = requestV3->fileName.name; *cpNameSize = requestV3->fileName.length; *caseType = requestV3->fileName.caseType; } - LOG(4, ("HgfsUnpackGetattrRequest: HGFS_OP_GETATTR_V3: %u\n", *caseType)); + LOG(4, ("%s: HGFS_OP_GETATTR_V3: %u\n", __FUNCTION__, *caseType)); break; } @@ -5283,6 +5394,7 @@ HgfsUnpackGetattrRequest(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. */ + *hints = requestV2->hints; if (*hints & HGFS_ATTR_HINT_USE_FILE_DESC) { *file = requestV2->file; @@ -5295,8 +5407,10 @@ HgfsUnpackGetattrRequest(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 */ + return FALSE; } *cpName = requestV2->fileName.name; @@ -5314,12 +5428,13 @@ HgfsUnpackGetattrRequest(char const *packetIn, // IN: request packet extra = packetSize - sizeof *requestV1; /* - * request->fileName.length is user-provided, so this test must be carefully - * written to prevent wraparounds. + * request->fileName.length is user-provided, so this test must be + * carefully written to prevent wraparounds. */ if (requestV1->fileName.length > extra) { /* The input packet is smaller than the request. */ + return FALSE; } *cpName = requestV1->fileName.name; @@ -5349,6 +5464,7 @@ HgfsUnpackGetattrRequest(char const *packetIn, // IN: request packet attrInfo->userId = 0; attrInfo->groupId = 0; attrInfo->hostFileId = 0; + return TRUE; } @@ -5401,7 +5517,7 @@ HgfsPackGetattrReply(char const *packetIn, // IN: incoming packet reply = (HgfsReplyGetattrV3 *)HGFS_REP_GET_PAYLOAD_V3(*packetOut); reply->attr.mask = attr->mask; reply->attr.type = attr->type; - LOG(4, ("HgfsPackGetattrReply: attr type: %u\n", reply->attr.type)); + LOG(4, ("%s: attr type: %u\n", __FUNCTION__, reply->attr.type)); /* * Is there enough space in the request packet for the utf8 name? @@ -5412,9 +5528,11 @@ HgfsPackGetattrReply(char const *packetIn, // IN: incoming packet * Also keep in mind that sizeof *reply already contains one character, * which we'll consider the nul terminator. */ + if (utf8TargetNameLen > HGFS_PACKET_MAX - HGFS_REP_PAYLOAD_SIZE_V3(reply)) { return FALSE; } + if (utf8TargetName) { memcpy(reply->symlinkTarget.name, utf8TargetName, utf8TargetNameLen); CPNameLite_ConvertTo(reply->symlinkTarget.name, utf8TargetNameLen, @@ -5469,6 +5587,7 @@ HgfsPackGetattrReply(char const *packetIn, // IN: incoming packet * Also keep in mind that sizeof *reply already contains one character, * which we'll consider the nul terminator. */ + if (utf8TargetNameLen > HGFS_PACKET_MAX - sizeof *reply) { return FALSE; } @@ -5527,7 +5646,8 @@ HgfsPackGetattrReply(char const *packetIn, // IN: incoming packet } default: - LOG(4, ("HgfsPackGetattrReply: Invalid GetAttr op.\n")); + LOG(4, ("%s: Invalid GetAttr op.\n", __FUNCTION__)); + return FALSE; } @@ -5582,7 +5702,7 @@ HgfsUnpackSearchReadRequest(const char *packetIn, // IN: request packet *hgfsSearchHandle = request->search; *offset = request->offset; - LOG(4, ("HgfsUnpackSearchReadRequest: HGFS_OP_SEARCH_READ_V3\n")); + LOG(4, ("%s: HGFS_OP_SEARCH_READ_V3\n", __FUNCTION__)); } else { HgfsRequestSearchRead *request; @@ -5657,7 +5777,8 @@ HgfsPackSearchReadReply(char const *packetIn, // IN: incoming packet HgfsReplySearchReadV3 *reply; HgfsDirEntry *dirent; - *packetSize = HGFS_REP_PAYLOAD_SIZE_V3(reply) + utf8NameLen + sizeof *dirent; + *packetSize = HGFS_REP_PAYLOAD_SIZE_V3(reply) + utf8NameLen + + sizeof *dirent; *packetOut = Util_SafeMalloc(*packetSize); replyHeader = (HgfsReply *)(*packetOut); @@ -5676,8 +5797,9 @@ HgfsPackSearchReadReply(char const *packetIn, // IN: incoming packet * Also keep in mind that sizeof *reply already contains one character, * which we'll consider the nul terminator. */ + if (utf8NameLen > HGFS_PACKET_MAX - HGFS_REP_PAYLOAD_SIZE_V3(reply) - - sizeof(struct HgfsDirEntry)) { + sizeof *dirent) { return FALSE; } @@ -5691,6 +5813,7 @@ HgfsPackSearchReadReply(char const *packetIn, // IN: incoming packet if (utf8NameLen == 0) { /* No entry. */ + return TRUE; } @@ -5735,6 +5858,7 @@ HgfsPackSearchReadReply(char const *packetIn, // IN: incoming packet * Also keep in mind that sizeof *reply already contains one character, * which we'll consider the nul terminator. */ + if (utf8NameLen > HGFS_PACKET_MAX - sizeof *reply) { return FALSE; } @@ -5743,6 +5867,7 @@ HgfsPackSearchReadReply(char const *packetIn, // IN: incoming packet if (utf8NameLen == 0) { /* No entry. */ + return TRUE; } @@ -5787,6 +5912,7 @@ HgfsPackSearchReadReply(char const *packetIn, // IN: incoming packet * Also keep in mind that sizeof *reply already contains one character, * which we'll consider the nul terminator. */ + if (utf8NameLen > HGFS_PACKET_MAX - sizeof *reply) { return FALSE; } @@ -5795,6 +5921,7 @@ HgfsPackSearchReadReply(char const *packetIn, // IN: incoming packet if (utf8NameLen == 0) { /* No entry. */ + return TRUE; } memcpy(reply->fileName.name, utf8Name, utf8NameLen); @@ -5816,7 +5943,8 @@ HgfsPackSearchReadReply(char const *packetIn, // IN: incoming packet } default: { - LOG(4, ("HgfsPackSearchReadReply: Invalid SearchRead Op.")); + LOG(4, ("%s: Invalid SearchRead Op.", __FUNCTION__)); + return FALSE; } } @@ -5901,6 +6029,7 @@ HgfsUnpackSetattrRequest(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; @@ -5912,6 +6041,7 @@ HgfsUnpackSetattrRequest(char const *packetIn, // IN: request packet if (requestV3->fileName.length > extra) { /* The input packet is smaller than the request. */ + return FALSE; } /* It is now safe to read the file name. */ @@ -5919,7 +6049,8 @@ HgfsUnpackSetattrRequest(char const *packetIn, // IN: request packet *cpNameSize = requestV3->fileName.length; *caseType = requestV3->fileName.caseType; } - LOG(4, ("HgfsUnpackSetattrRequest: unpacking HGFS_OP_SETATTR_V3, %u\n", *caseType)); + LOG(4, ("%s: unpacking HGFS_OP_SETATTR_V3, %u\n", __FUNCTION__, + *caseType)); break; } @@ -5954,6 +6085,7 @@ HgfsUnpackSetattrRequest(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 (*hints & HGFS_ATTR_HINT_USE_FILE_DESC) { *file = requestV2->file; *cpName = NULL; @@ -5963,13 +6095,14 @@ HgfsUnpackSetattrRequest(char const *packetIn, // IN: request packet if (requestV2->fileName.length > extra) { /* The input packet is smaller than the request. */ + return FALSE; } /* It is now safe to read the file name. */ *cpName = requestV2->fileName.name; *cpNameSize = requestV2->fileName.length; } - LOG(4, ("HgfsUnpackSetattrRequest: unpacking HGFS_OP_SETATTR_V2\n")); + LOG(4, ("%s: unpacking HGFS_OP_SETATTR_V2\n", __FUNCTION__)); break; } case HGFS_OP_SETATTR: @@ -5988,6 +6121,7 @@ HgfsUnpackSetattrRequest(char const *packetIn, // IN: request packet if (requestV1->fileName.length > extra) { /* The input packet is smaller than the request. */ + return FALSE; } @@ -5996,40 +6130,29 @@ HgfsUnpackSetattrRequest(char const *packetIn, // IN: request packet *cpNameSize = requestV1->fileName.length; attr->mask = 0; - attr->mask |= - requestV1->update & HGFS_ATTR_SIZE ? - HGFS_ATTR_VALID_SIZE : - 0; - attr->mask |= - requestV1->update & HGFS_ATTR_CREATE_TIME ? - HGFS_ATTR_VALID_CREATE_TIME : - 0; - attr->mask |= - requestV1->update & HGFS_ATTR_ACCESS_TIME ? - HGFS_ATTR_VALID_ACCESS_TIME : - 0; - attr->mask |= - requestV1->update & HGFS_ATTR_WRITE_TIME ? - HGFS_ATTR_VALID_WRITE_TIME : - 0; - attr->mask |= - requestV1->update & HGFS_ATTR_CHANGE_TIME ? - HGFS_ATTR_VALID_CHANGE_TIME : - 0; - attr->mask |= - requestV1->update & HGFS_ATTR_PERMISSIONS ? - HGFS_ATTR_VALID_OWNER_PERMS : - 0; - - *hints |= - requestV1->update & HGFS_ATTR_ACCESS_TIME_SET ? - HGFS_ATTR_HINT_SET_ACCESS_TIME : - 0; - - *hints |= - requestV1->update & HGFS_ATTR_WRITE_TIME_SET ? - HGFS_ATTR_HINT_SET_WRITE_TIME : - 0; + attr->mask |= requestV1->update & HGFS_ATTR_SIZE ? + HGFS_ATTR_VALID_SIZE : 0; + attr->mask |= requestV1->update & HGFS_ATTR_CREATE_TIME ? + HGFS_ATTR_VALID_CREATE_TIME : + 0; + attr->mask |= requestV1->update & HGFS_ATTR_ACCESS_TIME ? + HGFS_ATTR_VALID_ACCESS_TIME : + 0; + attr->mask |= requestV1->update & HGFS_ATTR_WRITE_TIME ? + HGFS_ATTR_VALID_WRITE_TIME : + 0; + attr->mask |= requestV1->update & HGFS_ATTR_CHANGE_TIME ? + HGFS_ATTR_VALID_CHANGE_TIME : + 0; + attr->mask |= requestV1->update & HGFS_ATTR_PERMISSIONS ? + HGFS_ATTR_VALID_OWNER_PERMS : + 0; + *hints |= requestV1->update & HGFS_ATTR_ACCESS_TIME_SET ? + HGFS_ATTR_HINT_SET_ACCESS_TIME : + 0; + *hints |= requestV1->update & HGFS_ATTR_WRITE_TIME_SET ? + HGFS_ATTR_HINT_SET_WRITE_TIME : + 0; attr->type = requestV1->attr.type; attr->size = requestV1->attr.size; @@ -6038,7 +6161,7 @@ HgfsUnpackSetattrRequest(char const *packetIn, // IN: request packet attr->writeTime = requestV1->attr.writeTime; attr->attrChangeTime = requestV1->attr.attrChangeTime; attr->ownerPerms = requestV1->attr.permissions; - LOG(4, ("HgfsUnpackSetattrRequest: unpacking HGFS_OP_SETATTR\n")); + LOG(4, ("%s: unpacking HGFS_OP_SETATTR\n", __FUNCTION__)); break; } default: @@ -6113,11 +6236,12 @@ HgfsPackSetattrReply(char const *packetIn, // IN: incoming packet } default: result = FALSE; - LOG(4, ("HgfsPackSetattrReply: invalid op code %d\n", header->op)); + LOG(4, ("%s: invalid op code %d\n", __FUNCTION__, header->op)); break; } ASSERT(result); + return result; } @@ -6168,6 +6292,7 @@ HgfsUnpackCreateDirRequest(char const *packetIn, // IN: incoming packet if (!(requestV3->mask & HGFS_CREATE_DIR_VALID_FILE_NAME)) { /* We do not support requests without a valid file name. */ + return FALSE; } @@ -6175,8 +6300,10 @@ HgfsUnpackCreateDirRequest(char const *packetIn, // IN: incoming 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. */ + return FALSE; } @@ -6185,6 +6312,7 @@ HgfsUnpackCreateDirRequest(char const *packetIn, // IN: incoming packet * garbage, but it's simpler to copy everything now and check the * valid bits before reading later. */ + info->mask = requestV3->mask; info->cpName = requestV3->fileName.name; info->cpNameSize = requestV3->fileName.length; @@ -6194,7 +6322,7 @@ HgfsUnpackCreateDirRequest(char const *packetIn, // IN: incoming packet info->ownerPerms = requestV3->ownerPerms; info->groupPerms = requestV3->groupPerms; info->otherPerms = requestV3->otherPerms; - LOG(4, ("HgfsUnpackCreateDirRequest: HGFS_OP_CREATE_DIR_V3\n")); + LOG(4, ("%s: HGFS_OP_CREATE_DIR_V3\n", __FUNCTION__)); break; } case HGFS_OP_CREATE_DIR_V2: @@ -6208,6 +6336,7 @@ HgfsUnpackCreateDirRequest(char const *packetIn, // IN: incoming packet if (!(requestV2->mask & HGFS_CREATE_DIR_VALID_FILE_NAME)) { /* We do not support requests without a valid file name. */ + return FALSE; } @@ -6215,8 +6344,10 @@ HgfsUnpackCreateDirRequest(char const *packetIn, // IN: incoming 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; } @@ -6225,6 +6356,7 @@ HgfsUnpackCreateDirRequest(char const *packetIn, // IN: incoming packet * garbage, but it's simpler to copy everything now and check the * valid bits before reading later. */ + info->mask = requestV2->mask; info->cpName = requestV2->fileName.name; info->cpNameSize = requestV2->fileName.length; @@ -6251,13 +6383,13 @@ HgfsUnpackCreateDirRequest(char const *packetIn, // IN: incoming packet if (requestV1->fileName.length > extra) { /* The input packet is smaller than the request. */ + return FALSE; } /* For CreateDirV1 requests, we know exactly what fields we expect. */ - info->mask = - HGFS_CREATE_DIR_VALID_OWNER_PERMS | - HGFS_CREATE_DIR_VALID_FILE_NAME; + info->mask = HGFS_CREATE_DIR_VALID_OWNER_PERMS | + HGFS_CREATE_DIR_VALID_FILE_NAME; info->cpName = requestV1->fileName.name; info->cpNameSize = requestV1->fileName.length; info->ownerPerms = requestV1->permissions; @@ -6321,13 +6453,13 @@ HgfsPackCreateDirReply(char const *packetIn, // IN: create dir operation ve } case HGFS_OP_CREATE_DIR_V2: case HGFS_OP_CREATE_DIR: - *packetSize = sizeof(HgfsReplyCreateDir); + *packetSize = sizeof (HgfsReplyCreateDir); *packetOut = Util_SafeMalloc(*packetSize); ((HgfsReply *)*packetOut)->id = header->id; ((HgfsReply *)*packetOut)->status = HgfsConvertFromInternalStatus(status); break; default: - LOG(4, ("HgfsPackCreateDirReply: invalid op code %d\n", header->op)); + LOG(4, ("%s: invalid op code %d\n", __FUNCTION__, header->op)); result = FALSE; break; } @@ -6343,9 +6475,9 @@ HgfsPackCreateDirReply(char const *packetIn, // IN: create dir operation ve * * HgfsBuildRelativePath -- * - * Generates relative file path which need to be used a symbolic link target which - * would generate target name defined in "target" if the path to symbolic link - * file defined in the "source". + * Generates relative file path which need to be used a symbolic link + * target which would generate target name defined in "target" if the path + * to symbolic link file defined in the "source". * Both source and target parameters represent absolute paths. * * Results: @@ -6370,7 +6502,12 @@ HgfsBuildRelativePath(const char* source, // IN: source file name size_t targetSize; char *result; char *currentPosition; - /* First remove the part of the path which is common between source and target */ + + /* + * First remove the part of the path which is common between source and + * target + */ + while (*relativeSource != '\0' && *relativeTarget != '\0') { sourceSep = strchr(relativeSource, DIRSEPC); targetSep = strchr(relativeTarget, DIRSEPC); @@ -6380,16 +6517,19 @@ HgfsBuildRelativePath(const char* source, // IN: source file name if ((sourceSep - relativeSource) != (targetSep - relativeTarget)) { break; } - if (strncmp(relativeSource, relativeTarget, (targetSep - relativeTarget)) != 0) { + if (strncmp(relativeSource, relativeTarget, + (targetSep - relativeTarget)) != 0) { break; } relativeSource = sourceSep + 1; relativeTarget = targetSep + 1; }; + /* - * Find out how many directories deep the source file is from the common part of the - * path. + * 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) { @@ -6412,7 +6552,9 @@ HgfsBuildRelativePath(const char* source, // IN: source file name * Consruct relative path by adding level number of "../" * 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) { @@ -6421,8 +6563,10 @@ 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; } @@ -6437,8 +6581,8 @@ HgfsBuildRelativePath(const char* source, // IN: source file name * * XXX: * The function must build directory notification packet and send it to the - * client. At the moment it just logs a message, actual logic will be implemented - * later when required infrastructure is ready. + * client. At the moment it just logs a message, actual logic will be + * implemented later when required infrastructure is ready. * * Results: * None. @@ -6456,12 +6600,9 @@ Hgfs_NotificationCallback(SharedFolderHandle sharedFolder, char* newName, uint32 mask) { - LOG(4, ("Hgfs_NotificationCallback: notification for folder: %d index: %d" - " file name %s (new name %s) mask %x\n", - sharedFolder, - (int)subscriber, - name, - (newName == NULL) ? "" : newName, + LOG(4, ("%s: notification for folder: %d index: %d file name %s " + "(new name %s) mask %x\n", __FUNCTION__, sharedFolder, + (int)subscriber, name, (newName == NULL) ? "" : newName, mask)); } @@ -6510,6 +6651,7 @@ 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); } @@ -6546,7 +6688,7 @@ HgfsServerOplockBreak(ServerLockData *lockData) HgfsRequestServerLockChange *request; HgfsServerLock lock; - LOG(4, ("HgfsServerOplockBreak: entered\n")); + LOG(4, ("%s: entered\n", __FUNCTION__)); /* * XXX: Just because the file in not in the cache on the server, @@ -6560,18 +6702,19 @@ HgfsServerOplockBreak(ServerLockData *lockData) * cache, or it had no lock, chances are someone else (maybe the VCPU * thread) broke the oplock and/or closed the file. */ + if (!HgfsFileDesc2Handle(lockData->fileDesc, &hgfsHandle)) { - LOG(4, ("HgfsServerOplockBreak: file is not in the cache\n")); + LOG(4, ("%s: file is not in the cache\n", __FUNCTION__)); goto free_and_exit; } if (!HgfsHandle2ServerLock(hgfsHandle, &lock)) { - LOG(4, ("HgfsServerOplockBreak: could not retrieve node's lock info.\n")); + LOG(4, ("%s: could not retrieve node's lock info.\n", __FUNCTION__)); goto free_and_exit; } if (lock == HGFS_LOCK_NONE) { - LOG(4, ("HgfsServerOplockBreak: the file does not have a server lock.\n")); + LOG(4, ("%s: the file does not have a server lock.\n", __FUNCTION__)); goto free_and_exit; } @@ -6582,9 +6725,10 @@ HgfsServerOplockBreak(ServerLockData *lockData) * XXX: This should probably go into a common allocation function that * other out-of-band requests can use. */ + requestBuffer = malloc(sizeof *request + HGFS_CLIENT_CMD_LEN); if (requestBuffer == NULL) { - LOG(4, ("HgfsServerOplockBreak: could not allocate memory.\n")); + LOG(4, ("%s: could not allocate memory.\n", __FUNCTION__)); goto ack_and_exit; } @@ -6603,17 +6747,18 @@ HgfsServerOplockBreak(ServerLockData *lockData) * If for some reason we fail, we'll acknowledge the oplock break * immediately. */ - if (HgfsServerManager_SendRequest(requestBuffer, - sizeof *request, - HgfsServerOplockBreakReply, - lockData)) { + + if (HgfsServerManager_SendRequest(requestBuffer, sizeof *request, + HgfsServerOplockBreakReply, lockData)) { return; } free(requestBuffer); ack_and_exit: HgfsAckOplockBreak(lockData, HGFS_LOCK_NONE); + return; + free_and_exit: free(lockData); } @@ -6630,7 +6775,7 @@ TestNodeFreeList(void) HgfsFileNode *node; unsigned int i; - printf("TestNodeFreeList: begin >>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + printf("%s: begin >>>>>>>>>>>>>>>>>>>>>>>>>>>\n", __FUNCTION__); for (i = 0; i < sizeof array / sizeof array[0]; i++) { char tempName[20]; @@ -6654,7 +6799,7 @@ TestNodeFreeList(void) } HgfsDumpAllNodes(); - printf("TestNodeFreeList: end <<<<<<<<<<<<<<<<<<<<<<<<<< \n"); + printf("%s: end <<<<<<<<<<<<<<<<<<<<<<<<<< \n", __FUNCTION__); } @@ -6665,7 +6810,7 @@ TestSearchFreeList(void) HgfsSearch *search; unsigned int i; - printf("TestSearchFreeList: begin >>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); + printf("%s: begin >>>>>>>>>>>>>>>>>>>>>>>>>>>\n", __FUNCTION__); for (i = 0; i < sizeof array / sizeof array[0]; i++) { char tempName[20]; @@ -6686,6 +6831,6 @@ TestSearchFreeList(void) } HgfsDumpAllSearches(); - printf("TestSearchFreeList: end <<<<<<<<<<<<<<<<<<<<<<<<<< \n"); + printf("%s: end <<<<<<<<<<<<<<<<<<<<<<<<<< \n", __FUNCTION__); } #endif diff --git a/open-vm-tools/lib/hgfsServer/hgfsServerLinux.c b/open-vm-tools/lib/hgfsServer/hgfsServerLinux.c index a36895a32..9f8ff106d 100644 --- a/open-vm-tools/lib/hgfsServer/hgfsServerLinux.c +++ b/open-vm-tools/lib/hgfsServer/hgfsServerLinux.c @@ -388,12 +388,13 @@ HgfsServerSigOplockBreak(int sigNum, // IN: Signal number ASSERT(clientData == NULL); fd = info->si_fd; - LOG(4, ("HgfsServerSigOplockBreak: Received SIGIO for fd %d\n", fd)); + LOG(4, ("%s: Received SIGIO for fd %d\n", __FUNCTION__, fd)); /* * We've got all we need from the signal handler, let it continue handling * signals of this type. */ + Sig_Continue(sigNum); /* @@ -401,6 +402,7 @@ 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; @@ -408,12 +410,12 @@ HgfsServerSigOplockBreak(int sigNum, // IN: Signal number newServerLock = HGFS_LOCK_NONE; } else if (newLease == -1) { int error = errno; - Log("HgfsServerSigOplockBreak: Could not get old lease for fd %d: %s\n", + Log("%s: Could not get old lease for fd %d: %s\n", __FUNCTION__, fd, strerror(error)); goto error; } else { - Log("HgfsServerSigOplockBreak: Unexpected reply to get lease for fd %d: " - "%d\n", fd, newLease); + Log("%s: Unexpected reply to get lease for fd %d: %d\n", + __FUNCTION__, fd, newLease); goto error; } @@ -424,6 +426,7 @@ 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; @@ -437,8 +440,8 @@ HgfsServerSigOplockBreak(int sigNum, // IN: Signal number HgfsServerOplockBreak(lockData); return; } else { - Log("HgfsServerSigOplockBreak: Could not allocate memory for lease " - "break on behalf of fd %d\n", fd); + Log("%s: Could not allocate memory for lease break on behalf of fd %d\n", + __FUNCTION__, fd); } error: @@ -592,7 +595,8 @@ HgfsServerGetOpenFlags(HgfsOpenFlags flagsIn, // IN arraySize = ARRAYSIZE(HgfsServerOpenFlags); if (flagsIn < 0 || flagsIn >= arraySize) { - Log("HgfsServerGetOpenFlags: Invalid HgfsOpenFlags %d\n", flagsIn); + Log("%s: Invalid HgfsOpenFlags %d\n", __FUNCTION__, flagsIn); + return FALSE; } @@ -696,7 +700,8 @@ HgfsServerGetOpenMode(HgfsFileOpenInfo *openInfo, // IN: Open info to examine } if (!HGFS_OPEN_MODE_IS_VALID_MODE(openInfo->mode)) { - Log("HgfsServerGetOpenMode: Invalid HgfsOpenMode %d\n", openInfo->mode); + Log("%s: Invalid HgfsOpenMode %d\n", __FUNCTION__, openInfo->mode); + return FALSE; } @@ -728,8 +733,10 @@ HgfsCloseFile(fileDesc fileDesc) // IN: File descriptor { if (close(fileDesc) != 0) { int error = errno; - LOG(4, ("HgfsCloseFile: Could not close fd %d: %s\n", fileDesc, + + LOG(4, ("%s: Could not close fd %d: %s\n", __FUNCTION__, fileDesc, strerror(error))); + return error; } @@ -771,14 +778,17 @@ HgfsCheckFileNode(char const *localName, // IN if (Posix_Stat(localName, &nodeStat) < 0) { int error = errno; - LOG(4, ("HgfsCheckFileNode: couldn't stat local file \"%s\": %s\n", + + LOG(4, ("%s: couldn't stat local file \"%s\": %s\n", __FUNCTION__, localName, strerror(error))); + return error; } - if ( nodeStat.st_dev != localId->volumeId - || nodeStat.st_ino != localId->fileId) { - LOG(4, ("HgfsCheckFileNode: local Id mismatch\n")); + if (nodeStat.st_dev != localId->volumeId || + nodeStat.st_ino != localId->fileId) { + LOG(4, ("%s: local Id mismatch\n", __FUNCTION__)); + return ENOENT; } @@ -829,27 +839,28 @@ 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. */ - LOG(4, ("HgfsGetFd: Invalid hgfs handle.\n")); + LOG(4, ("%s: Invalid hgfs handle.\n", __FUNCTION__)); status = EBADF; goto exit; } /* If the node is found in the cache */ if (HgfsIsCached(hgfsHandle, session)) { - /* * If the append flag is set check to see if the file was opened * 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); if (status != 0) { - LOG(4, ("HgfsGetFd: Couldn't close file \"%s\" for reopening\n", - node.utf8Name)); + LOG(4, ("%s: Couldn't close file \"%s\" for reopening\n", + __FUNCTION__, node.utf8Name)); goto exit; } @@ -857,8 +868,10 @@ 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, ("HgfsGetFd: Could not update the node in the cache\n")); + LOG(4, ("%s: Could not update the node in the cache\n", + __FUNCTION__)); status = EBADF; goto exit; } @@ -873,6 +886,7 @@ 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; @@ -882,6 +896,7 @@ 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); /* @@ -890,12 +905,14 @@ 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)); if (newFd < 0) { int error = errno; - LOG(4, ("HgfsGetFd: Couldn't open file \"%s\": %s\n", + + LOG(4, ("%s: Couldn't open file \"%s\": %s\n", __FUNCTION__, node.utf8Name, strerror(errno))); status = error; goto exit; @@ -905,15 +922,17 @@ 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)) { - LOG(4, ("HgfsGetFd: Could not update the node -- node is not used.\n")); + LOG(4, ("%s: Could not update the node -- node is not used.\n", + __FUNCTION__)); status = EBADF; goto exit; } /* Add the node to the cache. */ if (!HgfsAddToCache(hgfsHandle, session)) { - LOG(4, ("HgfsGetFd: Could not add node to the cache\n")); + LOG(4, ("%s: Could not add node to the cache\n", __FUNCTION__)); status = EBADF; goto exit; } @@ -923,6 +942,7 @@ HgfsGetFd(HgfsHandle hgfsHandle, // IN: HGFS file handle *fd = newFd; } free(node.utf8Name); + return status; } @@ -1034,7 +1054,7 @@ HgfsValidateOpen(HgfsFileOpenInfo *openInfo, // IN: Open info struct openPerms); if (fd < 0) { error = errno; - LOG(4, ("HgfsValidateOpen: couldn't open file \"%s\": %s\n", + LOG(4, ("%s: couldn't open file \"%s\": %s\n", __FUNCTION__, openInfo->utf8Name, strerror(error))); status = error; goto exit; @@ -1048,7 +1068,7 @@ HgfsValidateOpen(HgfsFileOpenInfo *openInfo, // IN: Open info struct /* Stat file to get its volume and file info */ if (fstat(fd, &fileStat) < 0) { error = errno; - LOG(4, ("HgfsValidateOpen: couldn't stat local file \"%s\": %s\n", + LOG(4, ("%s: couldn't stat local file \"%s\": %s\n", __FUNCTION__, openInfo->utf8Name, strerror(error))); close(fd); status = error; @@ -1129,10 +1149,12 @@ 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("HgfsAcquireServerLock: Could not set SIGIO as the desired lease " - "break signal for fd %d: %s\n", fileDesc, strerror(error)); + Log("%s: Could not set SIGIO as the desired lease break signal for " + "fd %d: %s\n", __FUNCTION__, fileDesc, strerror(error)); + return FALSE; } @@ -1140,43 +1162,48 @@ 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; } else if (desiredLock == HGFS_LOCK_SHARED) { leaseType = F_RDLCK; } else { - LOG(4, ("HgfsAcquireServerLock: Unknown server lock\n")); + LOG(4, ("%s: Unknown server lock\n", __FUNCTION__)); + return FALSE; } if (fcntl(fileDesc, F_SETLEASE, leaseType)) { - /* * If our client was opportunistic and we failed to get his lease because * 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; if (fcntl(fileDesc, F_SETLEASE, leaseType)) { error = errno; - LOG(4, ("HgfsAcquireServerLock: Could not get any opportunistic " - "lease for fd %d: %s\n", fileDesc, strerror(error))); + LOG(4, ("%s: Could not get any opportunistic lease for fd %d: %s\n", + __FUNCTION__, fileDesc, strerror(error))); + return FALSE; } } else { error = errno; - LOG(4, ("HgfsAcquireServerLock: Could not get %s lease for fd %d: " - "%s\n", leaseType == F_WRLCK ? "write" : "read", fileDesc, - strerror(errno))); + LOG(4, ("%s: Could not get %s lease for fd %d: %s\n", + __FUNCTION__, leaseType == F_WRLCK ? "write" : "read", + fileDesc, strerror(errno))); + return FALSE; } } /* Got a lease of some kind. */ - LOG(4, ("HgfsAcquireServerLock: Got %s lease for fd %d\n", + 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 @@ -1234,12 +1261,14 @@ 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, ("HgfsGetattrResolveAlias: could not create file reference: " - "error %d\n", (int32)osStatus)); + 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. @@ -1253,11 +1282,13 @@ 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); + &wasAliased, + kResolveAliasFileNoUI); if (osStatus != noErr) { - LOG(4, ("HgfsGetattrResolveAlias: could not resolve reference: error " - "%d\n", (int32)osStatus)); + LOG(4, ("%s: could not resolve reference: error %d\n", + __FUNCTION__, (int32)osStatus)); goto exit; } @@ -1274,37 +1305,38 @@ 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, ("HgfsGetattrResolveAlias: could not create resolved URL " - "reference from resolved filesystem reference\n")); + LOG(4, ("%s: could not create resolved URL reference from " + "resolved filesystem reference\n", __FUNCTION__)); goto exit; } resolvedString = CFURLGetString(resolvedRef); if (resolvedString == NULL) { - LOG(4, ("HgfsGetattrResolveAlias: could not create resolved string " - "reference from resolved URL reference\n")); + LOG(4, ("%s: could not create resolved string reference from " + "resolved URL reference\n", __FUNCTION__)); goto exit; } maxPath = CFStringGetMaximumSizeOfFileSystemRepresentation(resolvedString); myTargetName = malloc(maxPath); if (myTargetName == NULL) { - LOG(4, ("HgfsGetattrResolveAlias: could not allocate %"FMTSZ"d bytes " - "of memory for target name storage\n", maxPath)); + LOG(4, ("%s: could not allocate %"FMTSZ"d bytes of memory for " + "target name storage\n", __FUNCTION__, maxPath)); goto exit; } if (!CFURLGetFileSystemRepresentation(resolvedRef, FALSE, myTargetName, maxPath)) { - LOG(4, ("HgfsGetattrResolveAlias: could not convert and copy " - "resolved URL reference into allocated buffer\n")); + LOG(4, ("%s: could not convert and copy resolved URL reference " + "into allocated buffer\n", __FUNCTION__)); goto exit; } *targetName = myTargetName; - LOG(4, ("HgfsGetattrResolveAlias: file was an alias\n")); + LOG(4, ("%s: file was an alias\n", __FUNCTION__)); } else { *targetName = NULL; - LOG(4, ("HgfsGetattrResolveAlias: file was not an alias\n")); + LOG(4, ("%s: file was not an alias\n", __FUNCTION__)); } status = 0; @@ -1316,6 +1348,7 @@ HgfsGetattrResolveAlias(char const *fileName, // IN: Input filename if (resolvedRef != NULL) { CFRelease(resolvedRef); } + return status; #endif } @@ -1455,9 +1488,12 @@ HgfsConvertComponentCase(char *currentComponent, // IN /* * Unicode_CompareIgnoreCase crashes with invalid unicode strings, - * validate and convert it appropriately before passing it to Unicode_* functions. + * validate and convert it appropriately before passing it to Unicode_* + * functions. */ - if (!Unicode_IsBufferValid(dentryName, dentryNameLen, STRING_ENCODING_DEFAULT)) { + + if (!Unicode_IsBufferValid(dentryName, dentryNameLen, + STRING_ENCODING_DEFAULT)) { /* Invalid unicode string, skip the entry. */ continue; } @@ -1472,11 +1508,13 @@ 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) { ret = errno; - LOG(4, ("%s: failed to malloc myConvertedComponent.\n", __FUNCTION__)); + LOG(4, ("%s: failed to malloc myConvertedComponent.\n", + __FUNCTION__)); goto exit; } Str_Strcpy(myConvertedComponent, dentryName, myConvertedComponentSize); @@ -1535,19 +1573,21 @@ HgfsConstructConvertedPath(char **path, // IN/OUT ASSERT(convertedPath); ASSERT(pathSize); - p = realloc(*path, *pathSize + convertedPathLen + sizeof(DIRSEPC)); + p = realloc(*path, *pathSize + convertedPathLen + sizeof (DIRSEPC)); if (!p) { int error = errno; LOG(4, ("%s: failed to realloc.\n", __FUNCTION__)); + return error; } *path = p; - *pathSize += convertedPathLen + sizeof(DIRSEPC); + *pathSize += convertedPathLen + sizeof (DIRSEPC); /* Copy out the converted component to curDir, and free it. */ - Str_Strncat(p, *pathSize, DIRSEPS, sizeof(DIRSEPS)); + Str_Strncat(p, *pathSize, DIRSEPS, sizeof (DIRSEPS)); Str_Strncat(p, *pathSize, convertedPath, convertedPathLen); + return 0; } @@ -1613,6 +1653,7 @@ HgfsCaseInsensitiveLookup(const char *sharePath, // IN } else { *convertedFileNameLength = strlen(fileName); } + return 0; } @@ -1761,16 +1802,22 @@ HgfsServerConvertCase(const char *sharePath, // IN * and file is inaccessible using the case passed to us. We use access(2) * call to check if the passed case of the file name is correct. */ - if (caseFlags == HGFS_FILE_NAME_CASE_INSENSITIVE && access(fileName, F_OK) == -1) { + + if (caseFlags == HGFS_FILE_NAME_CASE_INSENSITIVE && + 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, convertedFileNameLength); + convertedFileName, + convertedFileNameLength); + /* - * Success or non-ENOENT error code. HgfsCaseInsensitiveLookup can return ENOENT, - * and its ok to continue if it is ENOENT. + * Success or non-ENOENT error code. HgfsCaseInsensitiveLookup can + * return ENOENT, and its ok to continue if it is ENOENT. */ + switch (error) { case ENOENT: nameStatus = HGFS_NAME_STATUS_COMPLETE; @@ -1782,6 +1829,7 @@ HgfsServerConvertCase(const char *sharePath, // IN nameStatus = HGFS_NAME_STATUS_FAILURE; break; } + return nameStatus; } @@ -1792,6 +1840,7 @@ HgfsServerConvertCase(const char *sharePath, // IN } else { *convertedFileNameLength = fileNameLength; } + return nameStatus; } @@ -2103,7 +2152,7 @@ HgfsGetattrFromName(char *fileName, // IN/OUT: Input filenam ASSERT(fileName); ASSERT(attr); - LOG(4, ("HgfsGetattrFromName: getting attrs for \"%s\"\n", fileName)); + LOG(4, ("%s: getting attrs for \"%s\"\n", __FUNCTION__, fileName)); error = HgfsStat(fileName, HgfsServerPolicy_IsShareOptionSet(configOptions, @@ -2112,8 +2161,7 @@ HgfsGetattrFromName(char *fileName, // IN/OUT: Input filenam &creationTime); if (error) { status = errno; - LOG(4, ("HgfsGetattrFromName: error stating file: %s\n", - strerror(status))); + LOG(4, ("%s: error stating file: %s\n", __FUNCTION__, strerror(status))); goto exit; } @@ -2122,23 +2170,25 @@ 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, ("HgfsGetattrFromName: is a directory\n")); + LOG(4, ("%s: is a directory\n", __FUNCTION__)); } else if (S_ISLNK(stats.st_mode)) { attr->type = HGFS_FILE_TYPE_SYMLINK; - LOG(4, ("HgfsGetattrFromName: is a symlink\n")); + LOG(4, ("%s: is a symlink\n", __FUNCTION__)); /* * 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); if (myTargetName == NULL) { error = errno; - LOG(4, ("HgfsGetattrFromName: readlink returned wrong size\n")); + LOG(4, ("%s: readlink returned wrong size\n", __FUNCTION__)); /* * Because of an unavoidable race between the lstat(2) and the @@ -2146,6 +2196,7 @@ 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; } @@ -2163,20 +2214,22 @@ HgfsGetattrFromName(char *fileName, // IN/OUT: Input filenam * * http://lists.apple.com/archives/carbon-development/2001/Nov/msg00007.html */ - LOG(4, ("HgfsGetattrFromName: NOT a directory or symlink\n")); + + LOG(4, ("%s: NOT a directory or symlink\n", __FUNCTION__)); if (HgfsGetattrResolveAlias(fileName, &myTargetName)) { - LOG(4, ("HgfsGetattrFromName: could not resolve file aliases\n")); + LOG(4, ("%s: could not resolve file aliases\n", __FUNCTION__)); } attr->type = HGFS_FILE_TYPE_REGULAR; if (myTargetName != NULL) { /* - * At this point the alias target has been successfully resolved. If the alias - * target is inside the same shared folder then convert it to relative path. - * Converting to a relative path produces a symlink that points to the target - * file in the guest OS. - * If the target lies outside the shared folder then treat it the same way as - * if alias has not been resolved. + * At this point the alias target has been successfully resolved. If + * the alias target is inside the same shared folder then convert it + * to relative path. Converting to a relative path produces a symlink + * that points to the target file in the guest OS. If the target lies + * 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; @@ -2194,19 +2247,21 @@ HgfsGetattrFromName(char *fileName, // IN/OUT: Input filenam myTargetName = relativeName; if (myTargetName != NULL) { /* - * Let's mangle the permissions and size of the file so that it more - * closely resembles a symlink. The size should be the length of the - * target name (not including the nul-terminator), and the permissions - * should be 777. + * Let's mangle the permissions and size of the file so that + * it more closely resembles a symlink. The size should be + * 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; } else { - LOG(4, ("HgfsGetattrFromName: out of memory\n")); + LOG(4, ("%s: out of memory\n", __FUNCTION__)); } } else { - LOG(4, ("HgfsGetattrFromName: alias target is outside shared folder\n")); + LOG(4, ("%s: alias target is outside shared folder\n", + __FUNCTION__)); } } } @@ -2218,12 +2273,11 @@ HgfsGetattrFromName(char *fileName, // IN/OUT: Input filenam * (precomposed) so Mac hosts must convert from normal form D * (decomposed). */ - if (!CodeSet_Utf8FormDToUtf8FormC(myTargetName, - strlen(myTargetName), - targetName, - NULL)) { - LOG(4, ("HgfsGetattrFromName: Unable to normalize form C " - "\"%s\"\n", myTargetName)); + + if (!CodeSet_Utf8FormDToUtf8FormC(myTargetName, strlen(myTargetName), + targetName, NULL)) { + LOG(4, ("%s: Unable to normalize form C \"%s\"\n", + __FUNCTION__, myTargetName)); status = HgfsConvertFromNameStatus(HGFS_NAME_STATUS_FAILURE); goto exit; } @@ -2299,11 +2353,11 @@ HgfsGetattrFromFd(int fd, // IN: file descriptor ASSERT(attr); ASSERT(session); - LOG(4, ("HgfsGetattrFromFd: getting attrs for %u\n", fd)); + LOG(4, ("%s: getting attrs for %u\n", __FUNCTION__, fd)); error = HgfsFStat(fd, &stats, &creationTime); if (error) { - LOG(4, ("HgfsGetattrFromFd: error stating file: %s\n", strerror(error))); + LOG(4, ("%s: error stating file: %s\n", __FUNCTION__, strerror(error))); status = error; goto exit; } @@ -2312,16 +2366,17 @@ 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, ("HgfsGetattrFromFd: is a directory\n")); + LOG(4, ("%s: is a directory\n", __FUNCTION__)); } else if (S_ISLNK(stats.st_mode)) { attr->type = HGFS_FILE_TYPE_SYMLINK; - LOG(4, ("HgfsGetattrFromFd: is a symlink\n")); + LOG(4, ("%s: is a symlink\n", __FUNCTION__)); } else { attr->type = HGFS_FILE_TYPE_REGULAR; - LOG(4, ("HgfsGetattrFromFd: NOT a directory or symlink\n")); + LOG(4, ("%s: NOT a directory or symlink\n", __FUNCTION__)); } HgfsStatToFileAttr(&stats, &creationTime, attr); @@ -2337,22 +2392,20 @@ HgfsGetattrFromFd(int fd, // IN: file descriptor */ if (!HgfsFileDesc2Handle(fd, session, &handle)) { - LOG(4, ("HgfsGetattrFromFd: could not get HGFS handle for fd %u\n", - fd)); + LOG(4, ("%s: could not get HGFS handle for fd %u\n", __FUNCTION__, fd)); status = EBADF; goto exit; } if (!HgfsHandle2ShareMode(handle, session, &shareMode)) { - LOG(4, ("HgfsGetattrFromFd: could not get share mode fd %u\n", - fd)); + LOG(4, ("%s: could not get share mode fd %u\n", __FUNCTION__, fd)); status = EBADF; goto exit; } if (!HgfsHandle2FileName(handle, session, &fileName, &fileNameLen)) { - LOG(4, ("HgfsGetattrFromFd: could not map cached target file handle %u\n", - handle)); + LOG(4, ("%s: could not map cached target file handle %u\n", + __FUNCTION__, handle)); status = EBADF; goto exit; } @@ -2361,14 +2414,15 @@ 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); + HgfsGetHiddenAttr(fileName, attr); if (shareMode == HGFS_OPEN_MODE_READ_ONLY) { /* * 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; } @@ -2382,6 +2436,7 @@ HgfsGetattrFromFd(int fd, // IN: file descriptor exit: free(fileName); + return status; } @@ -2454,7 +2509,7 @@ HgfsStatToFileAttr(struct stat *stats, // IN: stat information attr->ownerPerms = (stats->st_mode & S_IRWXU) >> 6; attr->groupPerms = (stats->st_mode & S_IRWXG) >> 3; attr->otherPerms = stats->st_mode & S_IRWXO; - LOG(4, ("HgfsStatToFileAttr: done, permissions %o%o%o%o, size %"FMT64"u\n", + LOG(4, ("%s: done, permissions %o%o%o%o, size %"FMT64"u\n", __FUNCTION__, attr->specialPerms, attr->ownerPerms, attr->groupPerms, attr->otherPerms, attr->size)); #ifdef __FreeBSD__ @@ -2653,8 +2708,9 @@ HgfsSetattrTimes(struct stat *statBuf, // IN: stat info != (HGFS_ATTR_VALID_ACCESS_TIME | HGFS_ATTR_VALID_WRITE_TIME)) { /* - * XXX Set also usec from nsec stat fields. - */ + * XXX Set also usec from nsec stat fields. + */ + accessTime->tv_sec = statBuf->st_atime; accessTime->tv_usec = 0; modTime->tv_sec = statBuf->st_mtime; @@ -2667,6 +2723,7 @@ 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 */ @@ -2681,7 +2738,7 @@ HgfsSetattrTimes(struct stat *statBuf, // IN: stat info if (gettimeofday(&tv, NULL) != 0) { error = errno; - LOG(4, ("HgfsSetattrTimes: gettimeofday error: %s\n", + LOG(4, ("%s: gettimeofday error: %s\n", __FUNCTION__, strerror(error))); status = error; goto exit; @@ -2704,7 +2761,7 @@ HgfsSetattrTimes(struct stat *statBuf, // IN: stat info if (gettimeofday(&tv, NULL) != 0) { error = errno; - LOG(4, ("HgfsSetattrTimes: gettimeofday error: %s\n", + LOG(4, ("%s: gettimeofday error: %s\n", __FUNCTION__, strerror(error))); status = error; goto exit; @@ -2764,13 +2821,12 @@ HgfsSetattrFromFd(HgfsHandle file, // IN: file descriptor status = HgfsGetFd(file, session, FALSE, &fd); if (status != 0) { - LOG(4, ("HgfsSetattrFromFd: Could not get file descriptor\n")); + LOG(4, ("%s: Could not get file descriptor\n", __FUNCTION__)); goto exit; } if (!HgfsHandle2ShareMode(file, session, &shareMode)) { - LOG(4, ("HgfsSetattrFromFd: could not get share mode fd %u\n", - fd)); + LOG(4, ("%s: could not get share mode fd %u\n", __FUNCTION__, fd)); status = EBADF; goto exit; } @@ -2783,7 +2839,7 @@ HgfsSetattrFromFd(HgfsHandle file, // IN: file descriptor /* We need the old stats so that we can preserve times. */ if (fstat(fd, &statBuf) == -1) { error = errno; - LOG(4, ("HgfsSetattrFromFd: error stating file %u: %s\n", + LOG(4, ("%s: error stating file %u: %s\n", __FUNCTION__, fd, strerror(error))); status = error; goto exit; @@ -2802,12 +2858,14 @@ 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, ("HgfsSetattrFromFd: set mode %o\n", (unsigned)newPermissions)); + LOG(4, ("%s: set mode %o\n", __FUNCTION__, (unsigned)newPermissions)); + if (fchmod(fd, newPermissions) < 0) { error = errno; - LOG(4, ("HgfsSetattrFromFd: error chmoding file %u: %s\n", + LOG(4, ("%s: error chmoding file %u: %s\n", __FUNCTION__, fd, strerror(error))); status = error; } @@ -2815,38 +2873,38 @@ HgfsSetattrFromFd(HgfsHandle file, // IN: file descriptor idChanged = HgfsSetattrOwnership(attr, &newUid, &newGid); if (idChanged) { - LOG(4, ("HgfsSetattrFromFd: set uid %"FMTUID" and gid %"FMTUID"\n", + LOG(4, ("%s: set uid %"FMTUID" and gid %"FMTUID"\n", __FUNCTION__, newUid, newGid)); if (fchown(fd, newUid, newGid) < 0) { error = errno; - LOG(4, ("HgfsSetattrFromFd: error chowning file %u: %s\n", + LOG(4, ("%s: error chowning file %u: %s\n", __FUNCTION__, fd, strerror(error))); status = error; } } if (attr->mask & HGFS_ATTR_VALID_SIZE) { - /* * XXX: Truncating the file will trigger an oplock break. The client * should have predicted this and removed the oplock prior to sending * the truncate request. At this point, the server must safeguard itself * against deadlock. */ + if (!HgfsHandle2ServerLock(file, session, &serverLock)) { - LOG(4, ("HgfsSetattrFromFd: File handle is no longer valid.\n")); + LOG(4, ("%s: File handle is no longer valid.\n", __FUNCTION__)); status = EBADF; } else if (serverLock != HGFS_LOCK_NONE) { - LOG(4, ("HgfsSetattrFromFd: Client attempted to truncate an " - "oplocked file\n")); + LOG(4, ("%s: Client attempted to truncate an oplocked file\n", + __FUNCTION__)); status = EBUSY; } else if (ftruncate(fd, attr->size) < 0) { error = errno; - LOG(4, ("HgfsSetattrFromFd: error truncating file %u: %s\n", + LOG(4, ("%s: error truncating file %u: %s\n", __FUNCTION__, fd, strerror(error))); status = error; } else { - LOG(4, ("HgfsSetattrFromFd: set size %"FMT64"u\n", attr->size)); + LOG(4, ("%s: set size %"FMT64"u\n", __FUNCTION__, attr->size)); } } @@ -2864,7 +2922,7 @@ HgfsSetattrFromFd(HgfsHandle file, // IN: file descriptor if (timesStatus == 0 && timesChanged) { uid_t uid; - LOG(4, ("HgfsSetattrFromFd: setting new times\n")); + LOG(4, ("%s: setting new times\n", __FUNCTION__)); /* * If the VMX is either the file owner or running as root, switch to @@ -2873,8 +2931,8 @@ HgfsSetattrFromFd(HgfsHandle file, // IN: file descriptor */ if (!Id_IsSuperUser() && (getuid() != statBuf.st_uid)) { - LOG(4, ("HgfsSetattrFromFd: only owner of file %u or root can call " - "futimes\n", fd)); + LOG(4, ("%s: only owner of file %u or root can call futimes\n", + __FUNCTION__, fd)); /* XXX: Linux kernel says both EPERM and EACCES are valid here. */ status = EPERM; goto exit; @@ -2887,7 +2945,7 @@ HgfsSetattrFromFd(HgfsHandle file, // IN: file descriptor if (futimes(fd, times) < 0) { error = errno; - LOG(4, ("HgfsSetattrFromFd: futimes error on file %u: %s\n", + LOG(4, ("%s: futimes error on file %u: %s\n", __FUNCTION__, fd, strerror(error))); status = error; } @@ -2940,14 +2998,11 @@ HgfsSetattrFromName(char *cpName, // IN: Name HgfsServerLock serverLock; HgfsShareOptions configOptions; - nameStatus = HgfsServerGetAccess(cpName, - cpNameSize, - HGFS_OPEN_MODE_WRITE_ONLY, - caseFlags, - &localName, - NULL); + nameStatus = HgfsServerGetAccess(cpName, cpNameSize, + HGFS_OPEN_MODE_WRITE_ONLY, caseFlags, + &localName, NULL); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { - LOG(4, ("HgfsSetattrFromName: access check failed\n")); + LOG(4, ("%s: access check failed\n", __FUNCTION__)); status = HgfsConvertFromNameStatus(nameStatus); goto exit; } @@ -2958,33 +3013,35 @@ HgfsSetattrFromName(char *cpName, // IN: Name nameStatus = HgfsServerPolicy_GetShareOptions(cpName, cpNameSize, &configOptions); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { - LOG(4, ("HgfsSetattrFromName: no matching share: %s.\n", cpName)); + LOG(4, ("%s: no matching share: %s.\n", __FUNCTION__, cpName)); goto exit; } - if (!HgfsServerPolicy_IsShareOptionSet(configOptions, HGFS_SHARE_FOLLOW_SYMLINKS)) { + if (!HgfsServerPolicy_IsShareOptionSet(configOptions, + HGFS_SHARE_FOLLOW_SYMLINKS)) { /* * If followSymlink option is not set, verify that the pathname isn't a - * symlink. Some of the following syscalls (chmod, for example) will follow - * a link. So we need to verify the final component too. The parent has - * already been verified in HgfsServerGetAccess. + * symlink. Some of the following syscalls (chmod, for example) will + * follow a link. So we need to verify the final component too. The + * parent has already been verified in HgfsServerGetAccess. * * 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, ("HgfsSetattrFromName: pathname contains a symlink\n")); + LOG(4, ("%s: pathname contains a symlink\n", __FUNCTION__)); status = EINVAL; goto exit_free; } } - LOG(4, ("HgfsSetattrFromName: setting attrs for \"%s\"\n", localName)); + LOG(4, ("%s: setting attrs for \"%s\"\n", __FUNCTION__, localName)); /* We need the old stats so that we can preserve times. */ if (Posix_Lstat(localName, &statBuf) == -1) { error = errno; - LOG(4, ("HgfsSetattrFromName: error stating file \"%s\": %s\n", + LOG(4, ("%s: error stating file \"%s\": %s\n", __FUNCTION__, localName, strerror(error))); status = error; goto exit_free; @@ -3003,26 +3060,30 @@ 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, ("HgfsSetattrFromName: set mode %o\n", (unsigned)newPermissions)); + LOG(4, ("%s: set mode %o\n", __FUNCTION__, (unsigned)newPermissions)); + if (Posix_Chmod(localName, newPermissions) < 0) { error = errno; - LOG(4, ("HgfsSetattrFromName: error chmoding file \"%s\": %s\n", + LOG(4, ("%s: error chmoding file \"%s\": %s\n", __FUNCTION__, localName, strerror(error))); status = error; } } 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; - LOG(4, ("HgfsSetattrFromName: error chowning file \"%s\": %s\n", + LOG(4, ("%s: error chowning file \"%s\": %s\n", __FUNCTION__, localName, strerror(error))); status = error; } @@ -3035,17 +3096,18 @@ 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, ("HgfsSetattrFromName: Client attempted to truncate an " - "oplocked file\n")); + LOG(4, ("%s: Client attempted to truncate an oplocked file\n", + __FUNCTION__)); status = EBUSY; } else if (Posix_Truncate(localName, attr->size) < 0) { error = errno; - LOG(4, ("HgfsSetattrFromName: error truncating file \"%s\": %s\n", + LOG(4, ("%s: error truncating file \"%s\": %s\n", __FUNCTION__, localName, strerror(error))); status = error; } else { - LOG(4, ("HgfsSetattrFromName: set size %"FMT64"u\n", attr->size)); + LOG(4, ("%s: set size %"FMT64"u\n", __FUNCTION__, attr->size)); } } @@ -3056,7 +3118,6 @@ HgfsSetattrFromName(char *cpName, // IN: Name timesStatus = HgfsSetattrTimes(&statBuf, attr, hints, ×[0], ×[1], ×Changed); if (timesStatus == 0 && timesChanged) { - /* * XXX Newer glibc provide also lutimes() and futimes() * when we politely ask with -D_GNU_SOURCE -D_BSD_SOURCE @@ -3064,7 +3125,7 @@ HgfsSetattrFromName(char *cpName, // IN: Name if (Posix_Utimes(localName, times) < 0) { error = errno; - LOG(4, ("HgfsSetattrFromName: utimes error on file \"%s\": %s\n", + LOG(4, ("%s: utimes error on file \"%s\": %s\n", __FUNCTION__, localName, strerror(error))); status = error; } @@ -3074,6 +3135,7 @@ HgfsSetattrFromName(char *cpName, // IN: Name exit_free: free(localName); + exit: return status; } @@ -3128,7 +3190,7 @@ HgfsServerScandir(char const *baseDir, // IN: Directory to search in result = Posix_Open(baseDir, openFlags); if (result < 0) { status = errno; - LOG(4, ("HgfsServerScandir: error in open: %d (%s)\n", status, + LOG(4, ("%s: error in open: %d (%s)\n", __FUNCTION__, status, strerror(status))); goto exit; } @@ -3138,8 +3200,7 @@ HgfsServerScandir(char const *baseDir, // IN: Directory to search in * Rather than read a single dent at a time, batch up multiple dents * in each call by using a buffer substantially larger than one dent. */ - while ((result = getdents(fd, (void *)buffer, - sizeof buffer)) > 0) { + while ((result = getdents(fd, (void *)buffer, sizeof buffer)) > 0) { size_t offset = 0; while (offset < result) { DirectoryEntry *newDent, **newDents; @@ -3161,14 +3222,13 @@ 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; goto exit; } memcpy(myDents[myNumDents], newDent, newDent->d_reclen); - HgfsEscape_Undo(myDents[myNumDents]->d_name, - strlen(myDents[myNumDents]->d_name)+ 1); /* * Dent is done. Bump the offset to the batched buffer to process the @@ -3181,7 +3241,7 @@ HgfsServerScandir(char const *baseDir, // IN: Directory to search in if (result == -1) { status = errno; - LOG(4, ("HgfsServerScandir: error in getdents: %d (%s)\n", status, + LOG(4, ("%s: error in getdents: %d (%s)\n", __FUNCTION__, status, strerror(status))); goto exit; } @@ -3189,7 +3249,7 @@ HgfsServerScandir(char const *baseDir, // IN: Directory to search in exit: if (fd != -1 && close(fd) < 0) { status = errno; - LOG(4, ("HgfsServerScandir: error in close: %d (%s)\n", status, + LOG(4, ("%s: error in close: %d (%s)\n", __FUNCTION__, status, strerror(status))); } @@ -3197,6 +3257,7 @@ 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++) { @@ -3298,27 +3359,23 @@ HgfsServerOpen(char const *packetIn, // IN: incoming packet /* HGFS_OPEN_VALID_FILE_NAME is checked in the unpack function. */ if (!(openInfo.mask & HGFS_OPEN_VALID_MODE)) { - LOG(4, ("HgfsServerOpen: filename or mode not provided\n")); + LOG(4, ("%s: filename or mode not provided\n", __FUNCTION__)); status = EINVAL; goto exit; } - nameStatus = HgfsServerGetAccess(openInfo.cpName, - openInfo.cpNameSize, - openInfo.mode, - openInfo.caseFlags, - &localName, - NULL); + nameStatus = HgfsServerGetAccess(openInfo.cpName, openInfo.cpNameSize, + openInfo.mode, openInfo.caseFlags, + &localName, NULL); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { - LOG(4, ("HgfsServerOpen: access check failed\n")); + LOG(4, ("%s: access check failed\n", __FUNCTION__)); status = HgfsConvertFromNameStatus(nameStatus); goto exit; } if (openInfo.mask & HGFS_OPEN_VALID_FLAGS) { savedOpenFlags = openInfo.flags; - if (!HgfsServerCheckOpenFlagsForShare(&openInfo, - &openInfo.flags)) { + if (!HgfsServerCheckOpenFlagsForShare(&openInfo, &openInfo.flags)) { /* Incompatible open mode with share mode. */ status = EACCES; goto exit; @@ -3328,8 +3385,8 @@ HgfsServerOpen(char const *packetIn, // IN: incoming packet ASSERT(localName); openInfo.utf8Name = localName; - LOG(4, ("HgfsServerOpen: opening \"%s\", mode %u, flags %u, perms " - "%u%u%u%u\n", openInfo.utf8Name, + LOG(4, ("%s: opening \"%s\", mode %u, flags %u, perms %u%u%u%u\n", + __FUNCTION__, openInfo.utf8Name, (openInfo.mask & HGFS_OPEN_VALID_MODE) ? openInfo.mode : 0, (openInfo.mask & HGFS_OPEN_VALID_FLAGS) ? openInfo.flags : 0, (openInfo.mask & HGFS_OPEN_VALID_SPECIAL_PERMS) ? @@ -3356,9 +3413,10 @@ 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, ("HgfsServerOpen: Client tried to open new handle for oplocked " - "file %s.\n", localName)); + LOG (4, ("%s: Client tried to open new handle for oplocked file %s.\n", + __FUNCTION__, localName)); status = EBUSY; goto exit; } @@ -3368,7 +3426,7 @@ HgfsServerOpen(char const *packetIn, // IN: incoming packet openInfo.cpNameSize, &configOptions); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { - LOG(4, ("HgfsServerSearchRead: no matching share: %s.\n", openInfo.cpName)); + LOG(4, ("%s: no matching share: %s.\n", __FUNCTION__, openInfo.cpName)); status = ENOENT; goto exit; } @@ -3377,7 +3435,8 @@ HgfsServerOpen(char const *packetIn, // IN: incoming packet HGFS_SHARE_FOLLOW_SYMLINKS); /* See if the name is valid, and if so add it and return the handle. */ - status = HgfsValidateOpen(&openInfo, followSymlinks, session, &localId, &newFd); + status = HgfsValidateOpen(&openInfo, followSymlinks, session, &localId, + &newFd); if (status == 0) { ASSERT(newFd >= 0); @@ -3385,12 +3444,15 @@ HgfsServerOpen(char const *packetIn, // IN: incoming packet * Open succeeded, so make new node and return its handle. If we fail, * it's almost certainly an internal server error. */ - if (!HgfsCreateAndCacheFileNode(&openInfo, &localId, newFd, FALSE, session)) { + + if (!HgfsCreateAndCacheFileNode(&openInfo, &localId, newFd, FALSE, + session)) { status = HGFS_INTERNAL_STATUS_ERROR; goto exit; } - if (HgfsPackOpenReply(packetIn, status, &openInfo, &packetOut, &packetOutSize)) { + if (HgfsPackOpenReply(packetIn, status, &openInfo, &packetOut, + &packetOutSize)) { if (!HgfsPacketSend(packetOut, packetOutSize, session, 0)) { free(packetOut); } @@ -3500,11 +3562,13 @@ 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; } @@ -3514,21 +3578,23 @@ HgfsServerRead(char const *packetIn, // IN: incoming packet replyActualSize = &reply->actualSize; } - LOG(4, ("HgfsServerRead: read fh %u, offset %"FMT64"u, count %u\n", + LOG(4, ("%s: read fh %u, offset %"FMT64"u, count %u\n", __FUNCTION__, file, offset, requiredSize)); /* Get the file descriptor from the cache */ status = HgfsGetFd(file, session, FALSE, &fd); if (status != 0) { - LOG(4, ("HgfsServerRead: Could not get file descriptor\n")); + LOG(4, ("%s: Could not get file descriptor\n", __FUNCTION__)); free(packetOut); + return status; } if (!HgfsHandleIsSequentialOpen(file, session, &sequentialOpen)) { - LOG(4, ("HgfsServerRead: Could not get sequenial open status\n")); + LOG(4, ("%s: Could not get sequenial open status\n", __FUNCTION__)); free(packetOut); + return EBADF; } @@ -3544,7 +3610,8 @@ 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->nodeArrayLock); + + SyncMutex_Lock(&session->fileIOLock); if (!sequentialOpen) { # ifdef linux { @@ -3561,24 +3628,24 @@ HgfsServerRead(char const *packetIn, // IN: incoming packet if (error < 0) { status = errno; - LOG(4, ("HgfsServerRead: could not seek to %"FMT64"u: %s\n", + LOG(4, ("%s: could not seek to %"FMT64"u: %s\n", __FUNCTION__, offset, strerror(status))); - SyncMutex_Unlock(&session->nodeArrayLock); + SyncMutex_Unlock(&session->fileIOLock); goto error; } } error = read(fd, payload, requiredSize); - SyncMutex_Unlock(&session->nodeArrayLock); + SyncMutex_Unlock(&session->fileIOLock); #endif if (error < 0) { status = errno; - LOG(4, ("HgfsServerRead: error reading from file: %s\n", + LOG(4, ("%s: error reading from file: %s\n", __FUNCTION__, strerror(status))); goto error; } - LOG(4, ("HgfsServerRead: read %d bytes\n", error)); + LOG(4, ("%s: read %d bytes\n", __FUNCTION__, error)); *replyActualSize = error; replySize += error; @@ -3590,9 +3657,6 @@ HgfsServerRead(char const *packetIn, // IN: incoming packet return 0; error: - if (!HgfsRemoveFromCache(file, session)) { - LOG(4, ("HgfsServerRead: Could not remove the node from cache.\n")); - } free(packetOut); return status; } @@ -3681,8 +3745,8 @@ HgfsServerWrite(char const *packetIn, // IN: incoming packet actualSize = &reply->actualSize; } - LOG(4, ("HgfsServerWrite: write fh %u, offset %"FMT64"u, count %u, extra %u\n", - file, offset, requiredSize, extra)); + LOG(4, ("%s: write fh %u, offset %"FMT64"u, count %u, extra %u\n", + __FUNCTION__, file, offset, requiredSize, extra)); /* Get the file desriptor from the cache */ status = HgfsGetFd(file, session, ((flags & HGFS_WRITE_APPEND) ? @@ -3690,14 +3754,16 @@ HgfsServerWrite(char const *packetIn, // IN: incoming packet &fd); if (status != 0) { - LOG(4, ("HgfsServerWrite: Could not get file descriptor\n")); + LOG(4, ("%s: Could not get file descriptor\n", __FUNCTION__)); free(packetOut); + return status; } if (!HgfsHandleIsSequentialOpen(file, session, &sequentialOpen)) { - LOG(4, ("HgfsServerWrite: Could not get sequential open status\n")); + LOG(4, ("%s: Could not get sequential open status\n", __FUNCTION__)); free(packetOut); + return EBADF; } @@ -3705,11 +3771,13 @@ 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; } @@ -3742,36 +3810,34 @@ HgfsServerWrite(char const *packetIn, // IN: incoming packet if (error < 0) { status = errno; - LOG(4, ("HgfsServerWrite: could not seek to %"FMT64"u: %s\n", + LOG(4, ("%s: could not seek to %"FMT64"u: %s\n", __FUNCTION__, offset, strerror(status))); - SyncMutex_Unlock(&session->nodeArrayLock); + SyncMutex_Unlock(&session->fileIOLock); goto error; } } error = write(fd, payload, requiredSize); - SyncMutex_Unlock(&session->nodeArrayLock); + SyncMutex_Unlock(&session->fileIOLock); #endif if (error < 0) { status = errno; - LOG(4, ("HgfsServerWrite: error writing to file: %s\n", + LOG(4, ("%s: error writing to file: %s\n", __FUNCTION__, strerror(status))); goto error; } - LOG(4, ("HgfsServerWrite: wrote %d bytes\n", error)); + LOG(4, ("%s: wrote %d bytes\n", __FUNCTION__, error)); *actualSize = error; status = 0; - if (!HgfsPackAndSendPacket(packetOut, replySize, 0, header->id, session, 0)) { + if (!HgfsPackAndSendPacket(packetOut, replySize, 0, header->id, + session, 0)) { goto error; } return 0; error: - if (!HgfsRemoveFromCache(file, session)) { - LOG(4, ("HgfsServerWrite: Could not remove the node from cache.\n")); - } free(packetOut); return status; } @@ -3836,11 +3902,11 @@ HgfsServerSearchOpen(char const *packetIn, // IN: incoming packet dirNameLength = requestV3->dirName.length; replySearch = &replyV3->search; replyV3->reserved = 0; - LOG(4, ("HgfsServerSearchOpen: HGFS_OP_SEARCH_OPEN_V3\n")); + LOG(4, ("%s: HGFS_OP_SEARCH_OPEN_V3\n", __FUNCTION__)); } else { HgfsRequestSearchOpen *request = (HgfsRequestSearchOpen *)packetIn; - replySize = sizeof *request; + replySize = sizeof (HgfsReplySearchOpen); packetOut = Util_SafeMalloc(replySize); /* Enforced by the dispatch function */ @@ -3856,6 +3922,7 @@ 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; @@ -3863,42 +3930,48 @@ HgfsServerSearchOpen(char const *packetIn, // IN: incoming packet } /* It is now safe to read the dirName */ - nameStatus = HgfsServerGetAccess(dirName, - dirNameLength, + nameStatus = HgfsServerGetAccess(dirName, dirNameLength, HGFS_OPEN_MODE_READ_ONLY, - caseFlags, - &baseDir, - &baseDirLen); + caseFlags, &baseDir, &baseDirLen); switch (nameStatus) { case HGFS_NAME_STATUS_COMPLETE: { - char const *inEnd; + char *inEnd; char *next; int len; ASSERT(baseDir); - LOG(4, ("HgfsServerSearchOpen: searching in \"%s\", %s.\n", baseDir, dirName)); + LOG(4, ("%s: searching in \"%s\", %s.\n", __FUNCTION__, baseDir, + dirName)); inEnd = dirName + dirNameLength; /* Get the first component. */ len = CPName_GetComponent(dirName, inEnd, (char const **) &next); if (len < 0) { - LOG(4, ("HgfsServerSearchOpen: get first component failed\n")); + LOG(4, ("%s: get first component failed\n", __FUNCTION__)); status = ENOENT; goto exit; } - LOG(4, ("HgfsServerSearchOpen: dirName: %s.\n", dirName)); + if (*inEnd != '\0') { + /* + * NT4 clients can send the name without a nul-terminator. + * The space for the nul is included and tested for in the size + * calculations above. Size of structure (includes a single + * character of the name) and the full dirname length. + */ + *inEnd = '\0'; + } + + LOG(4, ("%s: dirName: %s.\n", __FUNCTION__, dirName)); status = HgfsServerSearchRealDir(baseDir, baseDirLen, DIRECTORY_SEARCH_TYPE_DIR, - dirName, - session, - &handle); + dirName, session, &handle); free(baseDir); if (status != 0) { - LOG(4, ("HgfsServerSearchOpen: couldn't scandir\n")); + LOG(4, ("%s: couldn't scandir\n", __FUNCTION__)); goto exit; } break; @@ -3909,7 +3982,8 @@ HgfsServerSearchOpen(char const *packetIn, // IN: incoming packet * This is the base of our namespace, so enumerate all * shares. [bac] */ - LOG(4, ("HgfsServerSearchOpen: opened search on base\n")); + + LOG(4, ("%s: opened search on base\n", __FUNCTION__)); status = HgfsServerSearchVirtualDir(HgfsServerPolicy_GetShares, HgfsServerPolicy_GetSharesInit, HgfsServerPolicy_GetSharesCleanup, @@ -3917,13 +3991,13 @@ HgfsServerSearchOpen(char const *packetIn, // IN: incoming packet session, &handle); if (status != 0) { - LOG(4, ("HgfsServerSearchOpen: couldn't enumerate shares\n")); + LOG(4, ("%s: couldn't enumerate shares\n", __FUNCTION__)); goto exit; } break; default: - LOG(4, ("HgfsServerSearchOpen: access check failed\n")); + LOG(4, ("%s: access check failed\n", __FUNCTION__)); status = HgfsConvertFromNameStatus(nameStatus); goto exit; } @@ -3936,9 +4010,11 @@ 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, session, 0)) { + if (!HgfsPackAndSendPacket(packetOut, replySize, 0, header->id, + session, 0)) { status = 0; goto exit; } @@ -3946,6 +4022,7 @@ HgfsServerSearchOpen(char const *packetIn, // IN: incoming packet exit: free(packetOut); + return status; } @@ -3986,20 +4063,16 @@ HgfsServerSearchRead(char const *packetIn, // IN: incoming packet ASSERT(packetIn); ASSERT(session); - if (!HgfsUnpackSearchReadRequest(packetIn, - packetSize, - &attr, - &hgfsSearchHandle, - &requestedOffset)) { + if (!HgfsUnpackSearchReadRequest(packetIn, packetSize, &attr, + &hgfsSearchHandle, &requestedOffset)) { return EPROTO; } - LOG(4, ("HgfsServerSearchRead: read search #%u, offset %u\n", + LOG(4, ("%s: read search #%u, offset %u\n", __FUNCTION__, hgfsSearchHandle, requestedOffset)); if (!HgfsGetSearchCopy(hgfsSearchHandle, session, &search)) { - LOG(4, ("HgfsServerSearchRead: handle %u is invalid\n", - hgfsSearchHandle)); + LOG(4, ("%s: handle %u is invalid\n", __FUNCTION__, hgfsSearchHandle)); return EBADF; } @@ -4009,9 +4082,11 @@ HgfsServerSearchRead(char const *packetIn, // IN: incoming packet search.utf8ShareNameLen, &configOptions); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { - LOG(4, ("HgfsServerSearchRead: no matching share: %s.\n", search.utf8ShareName)); + LOG(4, ("%s: no matching share: %s.\n", __FUNCTION__, + search.utf8ShareName)); free(search.utf8Dir); free(search.utf8ShareName); + return ENOENT; } } @@ -4037,27 +4112,29 @@ 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) { - LOG(4, ("HgfsServerSearchRead: could not allocate space for " - "\"%s\\%s\"\n", search.utf8Dir, dent->d_name)); + LOG(4, ("%s: could not allocate space for \"%s\\%s\"\n", + __FUNCTION__, search.utf8Dir, dent->d_name)); free(search.utf8Dir); free(search.utf8ShareName); free(dent); + return ENOMEM; } memcpy(fullName, search.utf8Dir, search.utf8DirLen); fullName[search.utf8DirLen] = DIRSEPC; memcpy(&fullName[search.utf8DirLen + 1], dent->d_name, length + 1); - LOG(4, ("HgfsServerSearchRead: about to stat \"%s\"\n", fullName)); + LOG(4, ("%s: about to stat \"%s\"\n", __FUNCTION__, fullName)); - status = HgfsGetattrFromName(fullName, configOptions, search.utf8ShareName, - &attr, NULL); + status = HgfsGetattrFromName(fullName, configOptions, + search.utf8ShareName, &attr, NULL); if (status != 0) { HgfsOp savedOp = attr.requestType; - LOG(4, ("HgfsServerSearchRead: stat FAILED %s (%d)\n", + LOG(4, ("%s: stat FAILED %s (%d)\n", __FUNCTION__, fullName, status)); memset(&attr, 0, sizeof attr); attr.requestType = savedOp; @@ -4073,11 +4150,10 @@ HgfsServerSearchRead(char const *packetIn, // IN: incoming packet * (precomposed) so Mac hosts must convert from normal form D * (decomposed). */ - if (!CodeSet_Utf8FormDToUtf8FormC((const char *)dent->d_name, - length, - &entryName, - &entryNameLen)) { - LOG(4, ("HgfsServerSearchRead: Unable to normalize form C \"%s\"\n", + + if (!CodeSet_Utf8FormDToUtf8FormC((const char *)dent->d_name, length, + &entryName, &entryNameLen)) { + LOG(4, ("%s: Unable to normalize form C \"%s\"\n", __FUNCTION__, dent->d_name)); /* Skip this entry and continue. */ free(dent); @@ -4098,24 +4174,25 @@ 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, ("HgfsServerSearchRead: assigning %s default " - "attributes\n", dent->d_name)); + LOG(4, ("%s: assigning %s default attributes\n", + __FUNCTION__, dent->d_name)); HgfsServerGetDefaultDirAttrs(&attr); } else { /* Check permission on the share and get the share path */ nameStatus = - HgfsServerPolicy_GetSharePath(dent->d_name, - length, + HgfsServerPolicy_GetSharePath(dent->d_name, length, HGFS_OPEN_MODE_READ_ONLY, &sharePathLen, (char const **)&sharePath); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { - LOG(4, ("HgfsServerSearchRead: No such share or access denied\n")); + LOG(4, ("%s: No such share or access denied\n", __FUNCTION__)); free(dent); free(search.utf8Dir); free(search.utf8ShareName); + return HgfsConvertFromNameStatus(nameStatus); } @@ -4125,13 +4202,15 @@ 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) { /* * The dent no longer exists. Log the event. */ - LOG(4, ("HgfsServerSearchRead: stat FAILED\n")); + + LOG(4, ("%s: stat FAILED\n", __FUNCTION__)); } } @@ -4139,6 +4218,7 @@ 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; @@ -4148,6 +4228,7 @@ HgfsServerSearchRead(char const *packetIn, // IN: incoming packet * The POSIX implementation of HgfsSearchOpen could not have created * this kind of search. */ + NOT_IMPLEMENTED(); break; default: @@ -4157,13 +4238,14 @@ HgfsServerSearchRead(char const *packetIn, // IN: incoming packet free(search.utf8Dir); free(search.utf8ShareName); - LOG(4, ("HgfsServerSearchRead: dent name is \"%s\" len = %"FMTSZ"u\n", + LOG(4, ("%s: dent name is \"%s\" len = %"FMTSZ"u\n", __FUNCTION__, entryName, entryNameLen)); /* * We need to unescape the name before sending it back to the client */ - HgfsEscape_Undo(entryName, entryNameLen + 1); + + entryNameLen = HgfsEscape_Undo(entryName, entryNameLen + 1); /* * XXX: HgfsPackSearchReadReply will error out if the dent we @@ -4172,9 +4254,10 @@ 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)) { + if (!HgfsPackSearchReadReply(packetIn, status, entryName, entryNameLen, + &attr, &packetOut, &packetOutSize)) { status = EPROTO; } @@ -4193,7 +4276,7 @@ HgfsServerSearchRead(char const *packetIn, // IN: incoming packet /* No entry at this offset */ free(search.utf8Dir); free(search.utf8ShareName); - LOG(4, ("HgfsServerSearchRead: no entry\n")); + LOG(4, ("%s: no entry\n", __FUNCTION__)); status = 0; if (!HgfsPackSearchReadReply(packetIn, status, NULL, 0, &attr, &packetOut, &packetOutSize)) { @@ -4203,6 +4286,7 @@ HgfsServerSearchRead(char const *packetIn, // IN: incoming packet !HgfsPacketSend(packetOut, packetOutSize, session, 0)) { free(packetOut); } + return status; } @@ -4247,14 +4331,8 @@ HgfsServerGetattr(char const *packetIn, // IN: incoming packet ASSERT(packetIn); ASSERT(session); - if (!HgfsUnpackGetattrRequest(packetIn, - packetSize, - &attr, - &hints, - &cpName, - &cpNameSize, - &file, - &caseFlags)) { + if (!HgfsUnpackGetattrRequest(packetIn, packetSize, &attr, &hints, &cpName, + &cpNameSize, &file, &caseFlags)) { status = EPROTO; goto exit; } @@ -4265,7 +4343,7 @@ HgfsServerGetattr(char const *packetIn, // IN: incoming packet status = HgfsGetFd(file, session, FALSE, &fd); if (status != 0) { - LOG(4, ("HgfsServerGetattr: Could not get file descriptor\n")); + LOG(4, ("%s: Could not get file descriptor\n", __FUNCTION__)); goto exit; } status = HgfsGetattrFromFd(fd, session, &attr); @@ -4276,12 +4354,10 @@ 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, + + nameStatus = HgfsServerGetAccess(cpName, cpNameSize, HGFS_OPEN_MODE_READ_ONLY, - caseFlags, - &localName, - NULL); + caseFlags, &localName, NULL); switch (nameStatus) { case HGFS_NAME_STATUS_INCOMPLETE_BASE: @@ -4289,7 +4365,8 @@ HgfsServerGetattr(char const *packetIn, // IN: incoming packet * This is the base of our namespace; make up fake status for * this directory. */ - LOG(4, ("HgfsServerGetattr: getting attrs for base dir\n")); + + LOG(4, ("%s: getting attrs for base dir\n", __FUNCTION__)); HgfsServerGetDefaultDirAttrs(&attr); break; @@ -4301,7 +4378,7 @@ HgfsServerGetattr(char const *packetIn, // IN: incoming packet nameStatus = HgfsServerPolicy_GetShareOptions(cpName, cpNameSize, &configOptions); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { - LOG(4, ("HgfsServerGetattr: no matching share: %s.\n", cpName)); + LOG(4, ("%s: no matching share: %s.\n", __FUNCTION__, cpName)); free(localName); status = ENOENT; goto exit; @@ -4380,14 +4457,8 @@ HgfsServerSetattr(char const *packetIn, // IN: incoming packet ASSERT(packetIn); ASSERT(session); - if (!HgfsUnpackSetattrRequest(packetIn, - packetSize, - &attr, - &hints, - &cpName, - &cpNameSize, - &file, - &caseFlags)) { + if (!HgfsUnpackSetattrRequest(packetIn, packetSize, &attr, &hints, + &cpName, &cpNameSize, &file, &caseFlags)) { status = EPROTO; goto exit; } @@ -4395,12 +4466,8 @@ HgfsServerSetattr(char const *packetIn, // IN: incoming packet if (file != HGFS_INVALID_HANDLE) { status = HgfsSetattrFromFd(file, session, &attr, hints); } else { - status = HgfsSetattrFromName(cpName, - cpNameSize, - &attr, - hints, - caseFlags, - session); + status = HgfsSetattrFromName(cpName, cpNameSize, &attr, hints, + caseFlags, session); } if (!HgfsPackSetattrReply(packetIn, status, &packetOut, &packetOutSize)) { status = EPROTO; @@ -4456,14 +4523,12 @@ HgfsServerCreateDir(char const *packetIn, // IN: incoming packet return EPROTO; } - nameStatus = HgfsServerGetAccess(info.cpName, - info.cpNameSize, + nameStatus = HgfsServerGetAccess(info.cpName, info.cpNameSize, HGFS_OPEN_MODE_WRITE_ONLY, - info.caseFlags, - &localName, - NULL); + info.caseFlags, &localName, NULL); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { - LOG(4, ("HgfsServerCreateDir: access check failed\n")); + LOG(4, ("%s: access check failed\n", __FUNCTION__)); + return HgfsConvertFromNameStatus(nameStatus); } @@ -4479,6 +4544,7 @@ 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; @@ -4489,7 +4555,7 @@ HgfsServerCreateDir(char const *packetIn, // IN: incoming packet permissions |= info.mask & HGFS_CREATE_DIR_VALID_OTHER_PERMS ? info.otherPerms : (permissions & S_IRWXU) >> 6; - LOG(4, ("HgfsServerCreateDir: making dir \"%s\", mode %"FMTMODE"\n", + LOG(4, ("%s: making dir \"%s\", mode %"FMTMODE"\n", __FUNCTION__, localName, permissions)); error = Posix_Mkdir(localName, permissions); @@ -4499,13 +4565,14 @@ 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); } free(localName); if (error) { error = errno; - LOG(4, ("HgfsServerCreateDir: error: %s\n", strerror(error))); + LOG(4, ("%s: error: %s\n", __FUNCTION__, strerror(error))); return error; } if (!HgfsPackCreateDirReply(packetIn, 0, &packetOut, &packetOutSize)) { @@ -4557,45 +4624,40 @@ HgfsServerDeleteFile(char const *packetIn, // IN: incoming packet ASSERT(packetIn); ASSERT(session); - if (!HgfsUnpackDeleteRequest(packetIn, - packetSize, - &cpName, - &cpNameSize, - &hints, - &file, - &caseFlags)) { + if (!HgfsUnpackDeleteRequest(packetIn, packetSize, &cpName, &cpNameSize, + &hints, &file, &caseFlags)) { return EPROTO; } if (hints & HGFS_DELETE_HINT_USE_FILE_DESC) { if (!HgfsHandle2FileName(file, session, &cpName, &cpNameSize)) { - LOG(4, ("HgfsServerDeleteFile: could not map cached file handle %u\n", + 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 = HgfsServerGetAccess(cpName, cpNameSize, + HGFS_OPEN_MODE_WRITE_ONLY, caseFlags, + &localName, NULL); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { - LOG(4, ("HgfsServerDeleteFile: access check failed\n")); + LOG(4, ("%s: access check failed\n", __FUNCTION__)); + return HgfsConvertFromNameStatus(nameStatus); } } ASSERT(localName); - LOG(4, ("HgfsServerDeleteFile: unlinking \"%s\"\n", localName)); + LOG(4, ("%s: unlinking \"%s\"\n", __FUNCTION__, localName)); error = Posix_Unlink(localName); free(localName); if (error) { error = errno; - LOG(4, ("HgfsServerDeleteFile: error: %s\n", strerror(error))); + LOG(4, ("%s: error: %s\n", __FUNCTION__, strerror(error))); + return error; } if (!HgfsPackDeleteReply(packetIn, 0, &packetOut, &packetOutSize)) { @@ -4647,51 +4709,47 @@ HgfsServerDeleteDir(char const *packetIn, // IN: incoming packet ASSERT(packetIn); ASSERT(session); - if (!HgfsUnpackDeleteRequest(packetIn, - packetSize, - &cpName, - &cpNameSize, - &hints, - &file, - &caseFlags)) { + if (!HgfsUnpackDeleteRequest(packetIn, packetSize, &cpName, &cpNameSize, + &hints, &file, &caseFlags)) { return EPROTO; } if (hints & HGFS_DELETE_HINT_USE_FILE_DESC) { if (!HgfsHandle2FileName(file, session, &cpName, &cpNameSize)) { - LOG(4, ("HgfsServerDeleteDir: could not map cached file handle %u\n", + LOG(4, ("%s: could not map cached file handle %u\n", __FUNCTION__, file)); + return EBADF; } localName = cpName; } else { - nameStatus = HgfsServerGetAccess(cpName, - cpNameSize, + nameStatus = HgfsServerGetAccess(cpName, cpNameSize, HGFS_OPEN_MODE_WRITE_ONLY, - caseFlags, - &localName, - NULL); + caseFlags, &localName, NULL); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { - LOG(4, ("HgfsServerDeleteDir: access check failed\n")); + LOG(4, ("%s: access check failed\n", __FUNCTION__)); + return HgfsConvertFromNameStatus(nameStatus); } } /* Guest OS is not allowed to delete shared folder. */ if (HgfsServerIsSharedFolderOnly(cpName, cpNameSize)){ - LOG(4, ("HgfsServerDeleteDir: Cannot delete shared folder\n")); + LOG(4, ("%s: Cannot delete shared folder\n", __FUNCTION__)); + return EPERM; } ASSERT(localName); - LOG(4, ("HgfsServerDeleteDir: removing \"%s\"\n", localName)); + LOG(4, ("%s: removing \"%s\"\n", __FUNCTION__, localName)); error = Posix_Rmdir(localName); free(localName); if (error) { error = errno; - LOG(4, ("HgfsServerDeleteDir: error: %s\n", strerror(error))); + LOG(4, ("%s: error: %s\n", __FUNCTION__, strerror(error))); + return error; } @@ -4701,6 +4759,7 @@ HgfsServerDeleteDir(char const *packetIn, // IN: incoming packet if (!HgfsPacketSend(packetOut, packetOutSize, session, 0)) { free(packetOut); } + return 0; } @@ -4751,56 +4810,47 @@ HgfsServerRename(char const *packetIn, // IN: incoming packet ASSERT(packetIn); ASSERT(session); - if (!HgfsUnpackRenameRequest(packetIn, - packetSize, - &cpOldName, - &cpOldNameLen, - &cpNewName, - &cpNewNameLen, - &hints, - &srcFile, - &targetFile, - &oldCaseFlags, - &newCaseFlags)) { + if (!HgfsUnpackRenameRequest(packetIn, packetSize, &cpOldName, &cpOldNameLen, + &cpNewName, &cpNewNameLen, &hints, &srcFile, + &targetFile, &oldCaseFlags, &newCaseFlags)) { return EPROTO; } if (hints & HGFS_RENAME_HINT_USE_SRCFILE_DESC) { size_t localOldNameLen; - if (!HgfsHandle2FileName(srcFile, session, &localOldName, &localOldNameLen)) { - LOG(4, ("HgfsServerDeleteFile: could not map cached source file handle %u\n", - srcFile)); + if (!HgfsHandle2FileName(srcFile, session, &localOldName, + &localOldNameLen)) { + LOG(4, ("%s: could not map cached source file handle %u\n", + __FUNCTION__, srcFile)); + return EBADF; } /* Guest OS is not allowed to rename shared folder. */ if (HgfsHandleIsSharedFolderOpen(srcFile, session, &sharedFolderOpen) && sharedFolderOpen) { - LOG(4, ("HgfsServerRename: Cannot rename shared folder\n")); + LOG(4, ("%s: Cannot rename shared folder\n", __FUNCTION__)); status = EPERM; goto exit; } } else { - nameStatus = HgfsServerGetAccess(cpOldName, - cpOldNameLen, + nameStatus = HgfsServerGetAccess(cpOldName, cpOldNameLen, HGFS_OPEN_MODE_READ_WRITE, - oldCaseFlags, - &localOldName, - NULL); + oldCaseFlags, &localOldName, NULL); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { - LOG(4, ("HgfsServerRename: old name access check failed\n")); + LOG(4, ("%s: old name access check failed\n", __FUNCTION__)); + return HgfsConvertFromNameStatus(nameStatus); } ASSERT(localOldName); /* Guest OS is not allowed to rename shared folder. */ - if (HgfsServerIsSharedFolderOnly(cpOldName, - cpOldNameLen)){ - LOG(4, ("HgfsServerRename: Cannot rename shared folder\n")); + if (HgfsServerIsSharedFolderOnly(cpOldName, cpOldNameLen)) { + LOG(4, ("%s: Cannot rename shared folder\n", __FUNCTION__)); status = EPERM; goto exit; } @@ -4809,30 +4859,29 @@ HgfsServerRename(char const *packetIn, // IN: incoming packet if (hints & HGFS_RENAME_HINT_USE_TARGETFILE_DESC) { size_t localNewNameLen; - if (!HgfsHandle2FileName(targetFile, session, &localNewName, &localNewNameLen)) { - LOG(4, ("HgfsServerDeleteFile: could not map cached target file handle %u\n", - targetFile)); + if (!HgfsHandle2FileName(targetFile, session, &localNewName, + &localNewNameLen)) { + LOG(4, ("%s: could not map cached target file handle %u\n", + __FUNCTION__, targetFile)); + return EBADF; } /* Guest OS is not allowed to rename shared folder. */ if (HgfsHandleIsSharedFolderOpen(targetFile, session, &sharedFolderOpen) && sharedFolderOpen) { - LOG(4, ("HgfsServerRename: Cannot rename shared folder\n")); + LOG(4, ("%s: Cannot rename shared folder\n", __FUNCTION__)); status = EPERM; goto exit; } } else { - nameStatus = HgfsServerGetAccess(cpNewName, - cpNewNameLen, + nameStatus = HgfsServerGetAccess(cpNewName, cpNewNameLen, HGFS_OPEN_MODE_WRITE_ONLY, - newCaseFlags, - &localNewName, - NULL); + newCaseFlags, &localNewName, NULL); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { - LOG(4, ("HgfsServerRename: new name access check failed\n")); + LOG(4, ("%s: new name access check failed\n", __FUNCTION__)); status = HgfsConvertFromNameStatus(nameStatus); goto exit; } @@ -4848,7 +4897,7 @@ HgfsServerRename(char const *packetIn, // IN: incoming packet nameStatus = HgfsServerPolicy_GetShareOptions(cpNewName, cpNewNameLen, &configOptions); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { - LOG(4, ("HgfsServerRename: no matching share: %s.\n", cpNewName)); + LOG(4, ("%s: no matching share: %s.\n", __FUNCTION__, cpNewName)); status = ENOENT; goto exit; } @@ -4857,22 +4906,23 @@ HgfsServerRename(char const *packetIn, // IN: incoming packet * We were asked to avoid replacing an existing file, * so fail if the target exists. */ + status = HgfsGetattrFromName(localNewName, configOptions, cpNewName, &attr, NULL); if (status == 0) { /* The target exists, and so must fail the rename. */ - LOG(4, ("HgfsServerRename: error: target %s exists\n", localNewName)); + LOG(4, ("%s: error: target %s exists\n", __FUNCTION__, localNewName)); status = EEXIST; goto exit; } } - LOG(4, ("HgfsServerRename: renaming \"%s\" to \"%s\"\n", + LOG(4, ("%s: renaming \"%s\" to \"%s\"\n", __FUNCTION__, localOldName, localNewName)); error = Posix_Rename(localOldName, localNewName); if (error) { error = errno; - LOG(4, ("HgfsServerRename: error: %s\n", strerror(error))); + LOG(4, ("%s: error: %s\n", __FUNCTION__, strerror(error))); status = error; goto exit; } @@ -4883,6 +4933,7 @@ 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)) { @@ -4973,8 +5024,9 @@ 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, ("HgfsServerQueryVolume: Doesn't support file handle.\n")); + LOG(4, ("%s: Doesn't support file handle.\n", __FUNCTION__)); status = EPARAMETERNOTSUPPORTED; goto exit; } @@ -4990,7 +5042,7 @@ HgfsServerQueryVolume(char const *packetIn, // IN: incoming packet caseFlags = requestV3->fileName.caseType; fileName = requestV3->fileName.name; fileNameLength = requestV3->fileName.length; - LOG(4, ("HgfsServerQueryVolume: HGFS_OP_QUERY_VOLUME_INFO_V3\n")); + LOG(4, ("%s: HGFS_OP_QUERY_VOLUME_INFO_V3\n", __FUNCTION__)); } else { HgfsRequestQueryVolume *request = (HgfsRequestQueryVolume *)packetIn; HgfsReplyQueryVolume *reply; @@ -5014,6 +5066,7 @@ 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; @@ -5021,12 +5074,9 @@ HgfsServerQueryVolume(char const *packetIn, // IN: incoming packet } /* It is now safe to read the file name field. */ - nameStatus = HgfsServerGetAccess(fileName, - fileNameLength, + nameStatus = HgfsServerGetAccess(fileName, fileNameLength, HGFS_OPEN_MODE_READ_WRITE, - caseFlags, - &utf8Name, - &utf8NameLen); + caseFlags, &utf8Name, &utf8NameLen); switch (nameStatus) { case HGFS_NAME_STATUS_INCOMPLETE_BASE: /* @@ -5034,7 +5084,8 @@ HgfsServerQueryVolume(char const *packetIn, // IN: incoming packet * QueryVolumeInfo on it, on individual shares, or on just about * any pathname. */ - LOG(4,("HgfsServerQueryVolume: opened search on base\n")); + + LOG(4,("%s: opened search on base\n", __FUNCTION__)); status = HgfsServerSearchVirtualDir(HgfsServerPolicy_GetShares, HgfsServerPolicy_GetSharesInit, HgfsServerPolicy_GetSharesCleanup, @@ -5065,8 +5116,10 @@ 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) { + while ((dent = HgfsGetSearchResult(handle, session, offset, + TRUE)) != NULL) { char const *sharePath; size_t sharePathLen; uint64 freeBytes = 0; @@ -5080,8 +5133,9 @@ 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, ("HgfsServerQueryVolume: Skipping fake share %s\n", + LOG(4, ("%s: Skipping fake share %s\n", __FUNCTION__, dent->d_name)); free(dent); continue; @@ -5091,6 +5145,7 @@ HgfsServerQueryVolume(char const *packetIn, // IN: incoming packet * The above check ignores '.' and '..' so we do not include them in * the share count here. */ + shares++; /* @@ -5100,15 +5155,14 @@ HgfsServerQueryVolume(char const *packetIn, // IN: incoming packet * then do we check if there were any failures; if all shares failed * to process then we bail out with an error code. */ - nameStatus = HgfsServerPolicy_GetSharePath(dent->d_name, - length, + + nameStatus = HgfsServerPolicy_GetSharePath(dent->d_name, length, HGFS_OPEN_MODE_READ_ONLY, &sharePathLen, &sharePath); free(dent); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { - LOG(4, ("HgfsServerQueryVolume: No such share or access " - "denied\n")); + LOG(4, ("%s: No such share or access denied\n", __FUNCTION__)); if (0 == firstErr) { firstErr = HgfsConvertFromNameStatus(nameStatus); } @@ -5118,8 +5172,8 @@ HgfsServerQueryVolume(char const *packetIn, // IN: incoming packet if (!HgfsServerStatFs(sharePath, sharePathLen, &freeBytes, &totalBytes)) { - LOG(4, ("HgfsServerQueryVolume: error getting volume " - "information\n")); + LOG(4, ("%s: error getting volume information\n", + __FUNCTION__)); if (0 == firstErr) { firstErr = EIO; } @@ -5131,6 +5185,7 @@ 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) { @@ -5150,23 +5205,23 @@ HgfsServerQueryVolume(char const *packetIn, // IN: incoming packet } } if (!HgfsRemoveSearch(handle, session)) { - LOG(4, ("HgfsServerQueryVolume: could not close search on base\n")); + LOG(4, ("%s: could not close search on base\n", __FUNCTION__)); } break; case HGFS_NAME_STATUS_COMPLETE: ASSERT(utf8Name); - LOG(4,("HgfsServerQueryVolume: querying path %s\n", utf8Name)); + LOG(4,("%s: querying path %s\n", __FUNCTION__, utf8Name)); success = HgfsServerStatFs(utf8Name, utf8NameLen, &outFreeBytes, &outTotalBytes); free(utf8Name); if (!success) { - LOG(4, ("HgfsServerQueryVolume: error getting volume information\n")); + LOG(4, ("%s: error getting volume information\n", __FUNCTION__)); status = EIO; goto exit; } break; default: - LOG(4,("HgfsServerQueryVolume: file access check failed\n")); + LOG(4,("%s: file access check failed\n", __FUNCTION__)); status = HgfsConvertFromNameStatus(nameStatus); goto exit; } @@ -5234,7 +5289,7 @@ HgfsServerSymlinkCreate(char const *packetIn, // IN: incoming packet HgfsReplySymlinkCreateV3 *replyV3; HgfsFileNameV3 *targetNameP; requestV3 = (HgfsRequestSymlinkCreateV3 *)HGFS_REQ_GET_PAYLOAD_V3(packetIn); - LOG(4, ("HgfsServerSymlinkCreate: HGFS_OP_CREATE_SYMLINK_V3\n")); + LOG(4, ("%s: HGFS_OP_CREATE_SYMLINK_V3\n", __FUNCTION__)); /* Enforced by the dispatch function. */ ASSERT(packetSize >= HGFS_REQ_PAYLOAD_SIZE_V3(requestV3)); @@ -5248,6 +5303,7 @@ 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; @@ -5256,61 +5312,65 @@ 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, ("HgfsServerSymlinkCreate: Doesn't support file handle.\n")); - return EPARAMETERNOTSUPPORTED; - } - - packetOutSize = HGFS_REP_PAYLOAD_SIZE_V3(replyV3); - packetOut = Util_SafeMalloc(packetOutSize); - replyV3 = (HgfsReplySymlinkCreateV3 *)HGFS_REP_GET_PAYLOAD_V3(packetOut); - replyV3->reserved = 0; - } else { - HgfsRequestSymlinkCreate *request; - HgfsFileName *targetNameP; - request = (HgfsRequestSymlinkCreate *)packetIn; - - /* Enforced by the dispatch function. */ - ASSERT(packetSize >= sizeof *request); - extra = packetSize - sizeof *request; - - symlinkName = request->symlinkName.name; - symlinkNameLength = request->symlinkName.length; - - /* - * targetName starts after symlinkName + the variable length array - * in symlinkName. - */ - targetNameP = (HgfsFileName *)(symlinkName + 1 + symlinkNameLength); - targetName = targetNameP->name; - targetNameLength = targetNameP->length; - packetOutSize = sizeof(struct HgfsReplySymlinkCreate); - packetOut = Util_SafeMalloc(packetOutSize); - } - - /* - * request->symlinkName.length is user-provided, so this test must - * be carefully written to prevent wraparounds. - */ - if (symlinkNameLength > extra) { - /* The input packet is smaller than the request */ - status = EPROTO; - goto exit; - } - /* - * It is now safe to read the symlink file name and the - * "targetName" field - */ - - nameStatus = HgfsServerGetAccess(symlinkName, - symlinkNameLength, - HGFS_OPEN_MODE_READ_WRITE, - caseFlags, - &localSymlinkName, - NULL); - if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { - LOG(4, ("HgfsServerSymlinkCreate: symlink name access check failed\n")); + LOG(4, ("%s: Doesn't support file handle.\n", __FUNCTION__)); + + return EPARAMETERNOTSUPPORTED; + } + + packetOutSize = HGFS_REP_PAYLOAD_SIZE_V3(replyV3); + packetOut = Util_SafeMalloc(packetOutSize); + replyV3 = (HgfsReplySymlinkCreateV3 *)HGFS_REP_GET_PAYLOAD_V3(packetOut); + replyV3->reserved = 0; + } else { + HgfsRequestSymlinkCreate *request; + HgfsFileName *targetNameP; + request = (HgfsRequestSymlinkCreate *)packetIn; + + /* Enforced by the dispatch function. */ + ASSERT(packetSize >= sizeof *request); + extra = packetSize - sizeof *request; + + symlinkName = request->symlinkName.name; + symlinkNameLength = request->symlinkName.length; + + /* + * targetName starts after symlinkName + the variable length array + * in symlinkName. + */ + + targetNameP = (HgfsFileName *)(symlinkName + 1 + symlinkNameLength); + targetName = targetNameP->name; + targetNameLength = targetNameP->length; + packetOutSize = sizeof(struct HgfsReplySymlinkCreate); + packetOut = Util_SafeMalloc(packetOutSize); + } + + /* + * request->symlinkName.length is user-provided, so this test must + * be carefully written to prevent wraparounds. + */ + + if (symlinkNameLength > extra) { + /* The input packet is smaller than the request */ + status = EPROTO; + goto exit; + } + + /* + * It is now safe to read the symlink file name and the + * "targetName" field + */ + + nameStatus = HgfsServerGetAccess(symlinkName, symlinkNameLength, + HGFS_OPEN_MODE_READ_WRITE, + caseFlags, &localSymlinkName, + NULL); + if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { + LOG(4, ("%s: symlink name access check failed\n", + __FUNCTION__)); status = HgfsConvertFromNameStatus(nameStatus); goto exit; } @@ -5322,6 +5382,7 @@ 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); @@ -5335,7 +5396,7 @@ HgfsServerSymlinkCreate(char const *packetIn, // IN: incoming packet nameStatus = HgfsServerPolicy_GetShareOptions(symlinkName, symlinkNameLength, &configOptions); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { - LOG(4, ("HgfsServerSymlinkCreate: no matching share: %s.\n", symlinkName)); + LOG(4, ("%s: no matching share: %s.\n", __FUNCTION__, symlinkName)); status = HgfsConvertFromNameStatus(nameStatus); goto exit; } @@ -5346,12 +5407,13 @@ HgfsServerSymlinkCreate(char const *packetIn, // IN: incoming packet localTargetName[targetNameLength] = '\0'; /* Prohibit symlink ceation if symlink following is enabled. */ - if (HgfsServerPolicy_IsShareOptionSet(configOptions, HGFS_SHARE_FOLLOW_SYMLINKS)) { + if (HgfsServerPolicy_IsShareOptionSet(configOptions, + HGFS_SHARE_FOLLOW_SYMLINKS)) { status = EPERM; goto exit; } - LOG(4, ("HgfsServerSymlinkCreate: creating \"%s\" linked to \"%s\"\n", + LOG(4, ("%s: creating \"%s\" linked to \"%s\"\n", __FUNCTION__, localSymlinkName, localTargetName)); /* XXX: Should make use of targetNameP->flags? */ @@ -5359,7 +5421,7 @@ HgfsServerSymlinkCreate(char const *packetIn, // IN: incoming packet free(localSymlinkName); if (error) { status = errno; - LOG(4, ("HgfsServerSymlinkCreate: error: %s\n", strerror(errno))); + LOG(4, ("%s: error: %s\n", __FUNCTION__, strerror(errno))); goto exit; } @@ -5368,10 +5430,12 @@ HgfsServerSymlinkCreate(char const *packetIn, // IN: incoming packet session, 0)) { goto exit; } + return status; exit: free(packetOut); + return status; } @@ -5435,7 +5499,9 @@ HgfsServerHasSymlink(const char *fileName, // IN ASSERT(sharePath); ASSERT(sharePathLength <= fileNameLength); - LOG(4, ("%s: fileName: %s, sharePath: %s#\n", __FUNCTION__, fileName, sharePath)); + LOG(4, ("%s: fileName: %s, sharePath: %s#\n", __FUNCTION__, + fileName, sharePath)); + /* * Return success if: * - empty fileName or @@ -5443,6 +5509,7 @@ 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) { @@ -5451,21 +5518,24 @@ 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. + * 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)); + p = realloc(fileDirName, sizeof (DIRSEPS)); if (p == NULL) { nameStatus = HGFS_NAME_STATUS_OUT_OF_MEMORY; LOG(4, ("%s: failed to realloc fileDirName.\n", __FUNCTION__)); goto exit; } else { fileDirName = p; - Str_Strcpy(fileDirName, DIRSEPS, sizeof(DIRSEPS)); + Str_Strcpy(fileDirName, DIRSEPS, sizeof (DIRSEPS)); } } @@ -5473,6 +5543,7 @@ 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. */ @@ -5504,6 +5575,7 @@ HgfsServerHasSymlink(const char *fileName, // IN exit: free(resolvedFileDirPath); free(fileDirName); + return nameStatus; } @@ -5566,13 +5638,14 @@ HgfsAckOplockBreak(ServerLockData *lockData, // IN: server lock info ASSERT(lockData); fileDesc = lockData->fileDesc; - LOG(4, ("HgfsAckOplockBreak: Acknowledging break on fd %d\n", fileDesc)); + LOG(4, ("%s: Acknowledging break on fd %d\n", __FUNCTION__, fileDesc)); /* * The Linux server supports lock downgrading. We only downgrade to a shared * 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; @@ -5585,8 +5658,8 @@ HgfsAckOplockBreak(ServerLockData *lockData, // IN: server lock info /* Downgrade or acknowledge the break altogether. */ if (fcntl(fileDesc, F_SETLEASE, newLock) == -1) { int error = errno; - Log("HgfsServer_AckServerOplockBreak: Could not break lease on fd %d: " - "%s\n", fileDesc, strerror(error)); + Log("%s: Could not break lease on fd %d: %s\n", + __FUNCTION__, fileDesc, strerror(error)); } /* Cleanup. */ @@ -5676,12 +5749,14 @@ HgfsGetHiddenXAttr(char const *fileName, // IN: File name break; } default: - LOG(4, ("HgfsGetHiddenXattr: Unrecognized object type %d\n", attrBuf.objType)); + LOG(4, ("%s: Unrecognized object type %d\n", __FUNCTION__, + attrBuf.objType)); err = EINVAL; } } else { - LOG(4, ("HgfsGetHiddenXattr: Error %d when getting attributes\n", err)); + LOG(4, ("%s: Error %d when getting attributes\n", __FUNCTION__, err)); } + return err; } @@ -5691,8 +5766,8 @@ HgfsGetHiddenXAttr(char const *fileName, // IN: File name * * ChangeInvisibleFlag -- * - * Changes value of the invisible bit in a flags variable to a value defined by - * setFlag parameter. + * Changes value of the invisible bit in a flags variable to a value defined + * by setFlag parameter. * * Results: * TRUE flag has been changed, FALSE otherwise. @@ -5772,7 +5847,8 @@ HgfsSetHiddenXAttr(char const *fileName, // IN: path to the file break; } default: - LOG(4, ("HgfsGetHiddenXattr: Unrecognized object type %d\n", attrBuf.objType)); + LOG(4, ("%s: Unrecognized object type %d\n", __FUNCTION__, + attrBuf.objType)); err = EINVAL; } } else { diff --git a/open-vm-tools/lib/image/imageUtilPng.c b/open-vm-tools/lib/image/imageUtilPng.c index e84e237eb..9a67e824b 100644 --- a/open-vm-tools/lib/image/imageUtilPng.c +++ b/open-vm-tools/lib/image/imageUtilPng.c @@ -298,12 +298,7 @@ ImageUtil_ConstructPNGBuffer(const ImageInfo *image, // IN DynBuf *imageData) // OUT { - ImagePngWriteOptions options; - - options.zlibCompressLevel = -1; - options.stripAlphaChannel = TRUE; - - return ImageUtil_ConstructPNGBufferEx(image, &options, imageData); + return ImageUtil_ConstructPNGBufferEx(image, NULL, imageData); } @@ -326,9 +321,9 @@ ImageUtil_ConstructPNGBuffer(const ImageInfo *image, // IN */ Bool -ImageUtil_ConstructPNGBufferEx(const ImageInfo *image, // IN - const ImagePngWriteOptions *options, // IN - DynBuf *imageData) // OUT +ImageUtil_ConstructPNGBufferEx(const ImageInfo *image, // IN + const ImagePngWriteOptions *pOptions, // IN/OPT + DynBuf *imageData) // OUT { png_structp png_ptr; png_infop info_ptr; @@ -344,15 +339,22 @@ ImageUtil_ConstructPNGBufferEx(const ImageInfo *image, // IN int bytes_per_line; png_bytep *row_pointers; + ImagePngWriteOptions options; ASSERT(image); ASSERT(imageData); - ASSERT(options); - if (!image || !options || !imageData) { + if (!image || !imageData) { return FALSE; } + if (pOptions == NULL) { + options.zlibCompressLevel = -1; + options.stripAlphaChannel = TRUE; + } else { + options = *pOptions; + } + row_pointers = malloc(sizeof *row_pointers * image->height); if (!row_pointers) { return FALSE; @@ -400,8 +402,8 @@ ImageUtil_ConstructPNGBufferEx(const ImageInfo *image, // IN png_set_IHDR(png_ptr, info_ptr, image->width, image->height, 8, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - if (options->zlibCompressLevel >= 0 && options->zlibCompressLevel <= 9) { - png_set_compression_level(png_ptr, options->zlibCompressLevel); + if (options.zlibCompressLevel >= 0 && options.zlibCompressLevel <= 9) { + png_set_compression_level(png_ptr, options.zlibCompressLevel); } #ifdef RGB_MASK @@ -463,7 +465,7 @@ ImageUtil_ConstructPNGBufferEx(const ImageInfo *image, // IN png_set_PLTE(png_ptr, info_ptr, palette, image->numColors); } else if (image->bpp == 32) { - if (options->stripAlphaChannel) { + if (options.stripAlphaChannel) { /* * Strip the alpha channel @@ -493,7 +495,7 @@ ImageUtil_ConstructPNGBufferEx(const ImageInfo *image, // IN /* Write the file header information. REQUIRED */ png_write_info(png_ptr, info_ptr); - if ((image->bpp == 32) && options->stripAlphaChannel) { + if ((image->bpp == 32) && options.stripAlphaChannel) { /* treat the alpha channel byte as filler */ png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); } diff --git a/open-vm-tools/lib/include/appUtil.h b/open-vm-tools/lib/include/appUtil.h index 5671ab227..0595eae1e 100644 --- a/open-vm-tools/lib/include/appUtil.h +++ b/open-vm-tools/lib/include/appUtil.h @@ -25,12 +25,29 @@ #ifndef _APP_UTIL_H_ #define _APP_UTIL_H_ + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + #include "vmware.h" #include "guestCaps.h" +#ifdef __cplusplus +}; +#endif // __cplusplus + #ifdef _WIN32 +/* The maximum number of icons that can be retrieved in a single query. */ +#define APPUTIL_MAX_NUM_ICONS 16 + +/* Predefined (N x N pixels) icon sizes */ +#define APPUTIL_ICON_SMALL 16 +#define APPUTIL_ICON_BIG 32 + + typedef struct _AppUtilIconEntry { uint32 width; uint32 height; @@ -49,6 +66,10 @@ typedef enum { APPUTIL_LOWER_LEFT_DIB = 1, // the origin is the lower-left corner of the bitmap } AppUtilBitmapOrigin; +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + Bool AppUtil_GetIconDataByHandle(HICON hIcon, AppUtilBitmapOrigin origin, AppUtilIconEntry *icon); @@ -66,6 +87,23 @@ HICON AppUtil_GetWindowIcon(HWND hwnd, void AppUtil_BuildGlobalApplicationList(void); char *AppUtil_ActionURIForCommandLine(const WCHAR *commandLineUtf16); +Bool AppUtil_GetLinkIconData(const TCHAR *path, + AppUtilIconInfo *iconInfo, + AppUtilBitmapOrigin dibOrientation); +Bool AppUtil_GetAppIconData(HWND hwnd, + const TCHAR *path, + AppUtilIconInfo *iconInfo, + AppUtilBitmapOrigin dibOrientation); + +Bool +AppUtil_GetIconIndexAndLocationForShortcut(const TCHAR *shortcut, + int maxLen, + TCHAR *iconFile, + int *iconIndex); + +#ifdef __cplusplus +}; +#endif // __cplusplus #endif //_WIN32 diff --git a/open-vm-tools/lib/include/buildNumber.h b/open-vm-tools/lib/include/buildNumber.h index d1da1e96c..8500c6adf 100644 --- a/open-vm-tools/lib/include/buildNumber.h +++ b/open-vm-tools/lib/include/buildNumber.h @@ -1,12 +1,12 @@ #define BUILD_NUMBER \ - "build-172495" + "build-179896" #define BUILD_NUMBER_NUMERIC \ - 172495 + 179896 #define BUILD_NUMBER_NUMERIC_STRING \ - "172495" + "179896" #define PRODUCT_BUILD_NUMBER \ - "product-build-584" + "product-build-620" #define PRODUCT_BUILD_NUMBER_NUMERIC \ - 584 + 620 #define PRODUCT_BUILD_NUMBER_NUMERIC_STRING \ - "584" + "620" diff --git a/open-vm-tools/lib/include/circList.h b/open-vm-tools/lib/include/circList.h index 5f16c7783..5f44fd9cc 100644 --- a/open-vm-tools/lib/include/circList.h +++ b/open-vm-tools/lib/include/circList.h @@ -75,7 +75,7 @@ typedef struct ListItem { /* * delete item from the list */ -#define LIST_DEL DelListItem +#define LIST_DEL DelListItem /* * link two lists together @@ -100,7 +100,7 @@ typedef struct ListItem { /* * Get the list size. */ -#define LIST_SIZE GetListSize +#define LIST_SIZE GetListSize /* * LIST_SCAN_FROM scans the list from "from" up until "until". @@ -113,7 +113,7 @@ typedef struct ListItem { for (p = (from); (p) != NULL; \ (p) = (((p)->member == (until)) ? NULL : (p)->member)) -/* scan the entire list (non-destructively) */ +/* scan the entire list (non-destructively) */ #define LIST_SCAN(p, l) \ LIST_SCAN_FROM(p, LIST_FIRST(l), LIST_FIRST(l), next) @@ -145,7 +145,7 @@ typedef struct ListItem { * Returns the next member of a doubly linked list, or NULL if last. * Assumes: p is member of the list headed by head. * - * Result + * Result: * If head or p is NULL, return NULL. Otherwise, * next list member (or null if last). * @@ -176,7 +176,7 @@ NextListItem(ListItem *p, // IN * Returns the prev member of a doubly linked list, or NULL if first. * Assumes: p is member of the list headed by head. * - * Result + * Result: * If head or prev is NULL, return NULL. Otherwise, * prev list member (or null if first). * @@ -207,7 +207,7 @@ PrevListItem(ListItem *p, // IN * list header itself. * Assumes neither p nor headp is null and p is a member of *headp. * - * Result + * Result: * None * * Side effects: @@ -246,7 +246,7 @@ DelListItem(ListItem *p, // IN * Adds a new member to the back of a doubly linked list (queue) * Assumes neither p nor headp is null and p is not a member of *headp. * - * Result + * Result: * None * * Side effects: @@ -272,7 +272,7 @@ QueueListItem(ListItem *p, // IN head->prev = p; } } - + /* *---------------------------------------------------------------------- @@ -282,7 +282,7 @@ QueueListItem(ListItem *p, // IN * Adds a new member to the front of a doubly linked list (stack) * Assumes neither p nor headp is null and p is not a member of *headp. * - * Result + * Result: * None * * Side effects: @@ -298,7 +298,7 @@ PushListItem(ListItem *p, // IN QueueListItem(p, headp); *headp = p; } - + /* *---------------------------------------------------------------------- @@ -310,7 +310,7 @@ PushListItem(ListItem *p, // IN * No checking is done. It is assumed that l1 and l2 are two * distinct lists. * - * Result + * Result: * A list { l1 l2 }. * * Side effects: @@ -357,11 +357,11 @@ SpliceLists(ListItem *l1, // IN * Make a list l = {l1 l2} into two separate lists {l1} and {l2}, where: * l = { ... x -> p -> ... } split into: * l1 = { ... -> x } - * l2 = { p -> ... } + * l2 = { p -> ... } * Assumes neither p nor l is null and p is a member of l. * If p is the first element of l, then l1 will be NULL. * - * Result + * Result: * None. * * Side effects: @@ -414,7 +414,7 @@ SplitLists(ListItem *p, // IN */ static INLINE int -GetListSize(ListItem *head) // IN +GetListSize(ListItem *head) // IN { ListItem *li; int ret = 0; diff --git a/open-vm-tools/lib/include/config.h b/open-vm-tools/lib/include/config.h index e34bd57b5..9ae5bc615 100644 --- a/open-vm-tools/lib/include/config.h +++ b/open-vm-tools/lib/include/config.h @@ -81,6 +81,7 @@ EXTERN int32 Config_GetTriState(int32 defaultValue, EXTERN double Config_GetDouble(double defaultValue, const char *fmt, ...) PRINTF_DECL(2, 3); EXTERN Bool Config_NotSet(const char *fmt, ...) PRINTF_DECL(1, 2); +EXTERN void Config_Unset(const char *fmt, ...) PRINTF_DECL(1, 2); EXTERN void Config_UnsetWithPrefix(const char *fmt, ...) PRINTF_DECL(1, 2); EXTERN void Config_Set(void *value, int type, diff --git a/open-vm-tools/lib/include/dbllnklst.h b/open-vm-tools/lib/include/dbllnklst.h index 9a21a57cc..4c23be0de 100644 --- a/open-vm-tools/lib/include/dbllnklst.h +++ b/open-vm-tools/lib/include/dbllnklst.h @@ -67,17 +67,17 @@ #ifndef _DBLLNKLST_H_ #define _DBLLNKLST_H_ -#include "vm_basic_types.h" - #define INCLUDE_ALLOW_MODULE #define INCLUDE_ALLOW_USERLEVEL #include "includeCheck.h" +#include "vm_basic_types.h" + #define DblLnkLst_OffsetOf(type, field) ((intptr_t)&((type *)0)->field) #define DblLnkLst_Container(addr, type, field) \ - ((type *)((char *)addr - DblLnkLst_OffsetOf(type, field))) + ((type *)((char *)(addr) - DblLnkLst_OffsetOf(type, field))) #define DblLnkLst_ForEach(curr, head) \ for (curr = (head)->next; curr != (head); curr = (curr)->next) @@ -94,18 +94,199 @@ typedef struct DblLnkLst_Links { } DblLnkLst_Links; -/* Functions for both circular and anchored lists. --hpreg */ +/* + * Functions + * + * DblLnkLst_LinkFirst and DblLnkLst_LinkLast are specific + * to anchored lists. The rest are for both circular and + * anchored lists. + */ + + +/* + *---------------------------------------------------------------------- + * + * DblLnkLst_Init -- + * + * Initialize a member of a doubly linked list + * + * Result + * None + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ + +static INLINE void +DblLnkLst_Init(DblLnkLst_Links *l) // IN +{ + l->prev = l->next = l; +} + + +/* + *---------------------------------------------------------------------- + * + * DblLnkLst_Link -- + * + * Merge two doubly linked lists into one + * + * The operation is commutative + * The operation is inversible (its inverse is DblLnkLst_Unlink) + * + * Result + * None + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ + +static INLINE void +DblLnkLst_Link(DblLnkLst_Links *l1, // IN + DblLnkLst_Links *l2) // IN +{ + DblLnkLst_Links *tmp; + + (tmp = l1->prev)->next = l2; + (l1->prev = l2->prev)->next = l1; + l2->prev = tmp ; +} + + +/* + *---------------------------------------------------------------------- + * + * DblLnkLst_Unlink -- + * + * Split one doubly linked list into two + * + * No check is performed: the caller must ensure that both members + * belong to the same doubly linked list + * + * The operation is commutative + * The operation is inversible (its inverse is DblLnkLst_Link) + * + * Result + * None + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ -void DblLnkLst_Init(DblLnkLst_Links *l); -void DblLnkLst_Link(DblLnkLst_Links *l1, DblLnkLst_Links *l2); -void DblLnkLst_Unlink(DblLnkLst_Links *l1, DblLnkLst_Links *l2); -void DblLnkLst_Unlink1(DblLnkLst_Links *l); -Bool DblLnkLst_IsLinked(DblLnkLst_Links const *l); +static INLINE void +DblLnkLst_Unlink(DblLnkLst_Links *l1, // IN + DblLnkLst_Links *l2) // IN +{ + DblLnkLst_Links *tmp; -/* Functions specific to anchored lists. --hpreg */ + tmp = l1->prev ; + (l1->prev = l2->prev)->next = l1; + (l2->prev = tmp )->next = l2; +} + + +/* + *---------------------------------------------------------------------- + * + * DblLnkLst_Unlink1 -- + * + * Unlink an element from its list. + * + * Result + * None + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ + +static INLINE void +DblLnkLst_Unlink1(DblLnkLst_Links *l) // IN +{ + DblLnkLst_Unlink(l, l->next); +} + + +/* + *---------------------------------------------------------------------------- + * + * DblLnkLst_IsLinked -- + * + * Determines whether an element is linked with any other elements. + * + * Results: + * TRUE if link is linked, FALSE otherwise. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static INLINE Bool +DblLnkLst_IsLinked(DblLnkLst_Links const *l) // IN +{ + /* + * A DblLnkLst_Links is either linked to itself (not linked) or linked to + * other elements in a list (linked). + */ + return l->prev != l; +} + + +/* + *---------------------------------------------------------------------- + * + * DblLnkLst_LinkFirst -- + * + * Insert 'l' at the beginning of the list anchored at 'head' + * + * Result + * None + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ + +static INLINE void +DblLnkLst_LinkFirst(DblLnkLst_Links *head, // IN + DblLnkLst_Links *l) // IN +{ + DblLnkLst_Link(head->next, l); +} + + +/* + *---------------------------------------------------------------------- + * + * DblLnkLst_LinkLast -- + * + * Insert 'l' at the end of the list anchored at 'head' + * + * Result + * None + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ -void DblLnkLst_LinkFirst(DblLnkLst_Links *head, DblLnkLst_Links *l); -void DblLnkLst_LinkLast(DblLnkLst_Links *head, DblLnkLst_Links *l); +static INLINE void +DblLnkLst_LinkLast(DblLnkLst_Links *head, // IN + DblLnkLst_Links *l) // IN +{ + DblLnkLst_Link(head, l); +} #endif /* _DBLLNKLST_H_ */ diff --git a/open-vm-tools/lib/include/dndBase.h b/open-vm-tools/lib/include/dndBase.h index 6693a3a62..61ae90565 100644 --- a/open-vm-tools/lib/include/dndBase.h +++ b/open-vm-tools/lib/include/dndBase.h @@ -65,12 +65,14 @@ class LIB_EXPORT DnDBase /* Local UI as DnD target. */ sigc::signal updateFeedbackChanged; sigc::signal updateDetWndChanged; - sigc::signal updateUnityDetWndChanged; + sigc::signal updateUnityDetWndChanged; + sigc::signal targetPrivateDropChanged; sigc::signal reset; sigc::signal disable; sigc::signal enable; sigc::signal updateMouseChanged; + sigc::signal moveDetWndToMousePos; /* Guest cancel signals. */ sigc::signal ghCancel; diff --git a/open-vm-tools/lib/include/dndMsg.h b/open-vm-tools/lib/include/dndMsg.h index 1a8e9ae7c..17998016f 100644 --- a/open-vm-tools/lib/include/dndMsg.h +++ b/open-vm-tools/lib/include/dndMsg.h @@ -89,6 +89,9 @@ typedef enum { DND_UPDATE_HOST_VERSION, DND_UPDATE_GUEST_VERSION, DND_UPDATE_MOUSE, + DND_GH_PRIVATE_DROP, + DND_GH_TRANSPORT_TEST, + DND_MOVE_DET_WND_TO_MOUSE_POS, DND_MAX, } DnDCommand; @@ -112,6 +115,7 @@ typedef enum { CP_HG_START_FILE_COPY, // Add future commands here. + CP_GH_TRANSPORT_TEST, CP_MAX, } CopyPasteCommand; diff --git a/open-vm-tools/lib/include/escape.h b/open-vm-tools/lib/include/escape.h index cb4a7d8e7..63dbcd729 100644 --- a/open-vm-tools/lib/include/escape.h +++ b/open-vm-tools/lib/include/escape.h @@ -47,6 +47,15 @@ Escape_Undo(char escByte, // IN size_t sizeIn, // IN size_t *sizeOut); // OUT +const char * +Escape_Strchr(char escByte, // IN + const char *bufIn, // IN + char c); // IN + +char * +Escape_Unescape(char escByte, // IN + const char *bufIn); // IN + void * Escape_AnsiToUnix(void const *bufIn, // IN size_t sizeIn, // IN diff --git a/open-vm-tools/lib/include/file.h b/open-vm-tools/lib/include/file.h index 90ce9a647..5b89098ca 100644 --- a/open-vm-tools/lib/include/file.h +++ b/open-vm-tools/lib/include/file.h @@ -186,11 +186,22 @@ EXTERN Bool File_SetTimes(ConstUnicode pathName, VmTimeType writeTime, VmTimeType attrChangeTime); +EXTERN Bool File_GetFilePermissions(ConstUnicode pathName, + int *mode); + +EXTERN Bool File_SetFilePermissions(ConstUnicode pathName, + int mode); + EXTERN Bool File_SupportsFileSize(ConstUnicode pathName, uint64 fileSize); EXTERN Bool File_SupportsLargeFiles(ConstUnicode pathName); +EXTERN char *File_MapPathPrefix(const char *oldPath, + const char **oldPrefixes, + const char **newPrefixes, + size_t numPrefixes); + EXTERN Bool File_CopyFromFdToFd(FileIODescriptor src, FileIODescriptor dst); @@ -286,6 +297,8 @@ 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 diff --git a/open-vm-tools/lib/include/guestCaps.h b/open-vm-tools/lib/include/guestCaps.h index abc5af8c7..608624c0f 100644 --- a/open-vm-tools/lib/include/guestCaps.h +++ b/open-vm-tools/lib/include/guestCaps.h @@ -62,7 +62,10 @@ typedef enum { GHI_CAP_TRASH_FOLDER = 17, // supports ghi.guest.trashFolder.action, // ghi.guest.trashFolder.state, and // ghi.guest.trashFolder.getIcon commands - CAP_SET_TOPO_MODES = 18 // supports setting topology modes in video driver + CAP_SET_TOPO_MODES = 18, // supports setting topology modes in video driver + 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 } GuestCapabilities; typedef struct { @@ -122,7 +125,10 @@ static GuestCapElem guestCapTable[] = { { UNITY_CAP_STATUS_UNITY_ACTIVE, UNITY_CAP_VMDB_PATH, "unityActive" }, { GHI_CAP_SET_OUTLOOK_TEMP_FOLDER, GHI_CAP_VMDB_PATH, "setOutlookTempFolder" }, { GHI_CAP_TRASH_FOLDER, GHI_CAP_VMDB_PATH, "trashFolder" }, - { CAP_SET_TOPO_MODES, CAP_VMDB_PATH, "displayTopologyModesSet" } + { CAP_SET_TOPO_MODES, CAP_VMDB_PATH, "displayTopologyModesSet" }, + { 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"}, }; #endif // VM_NEED_VMDB_GUEST_CAP_MAPPING diff --git a/open-vm-tools/lib/include/guest_os.h b/open-vm-tools/lib/include/guest_os.h index 98d1b52e8..9601edc36 100644 --- a/open-vm-tools/lib/include/guest_os.h +++ b/open-vm-tools/lib/include/guest_os.h @@ -117,18 +117,30 @@ typedef enum GuestOSFamilyType { #define ALLWINNET64 BS(WINNET_64) #define ALLWINNET (ALLWINNET32 | ALLWINNET64) -#define ALLWINVISTA32 (BS(LONGHORN) | BS(WINVISTA)) -#define ALLWINVISTA64 (BS(LONGHORN_64) | BS(WINVISTA_64)) +#define ALLWINLONGHORN32 BS(LONGHORN) +#define ALLWINLONGHORN64 BS(LONGHORN_64) +#define ALLWINLONGHORN (ALLWINLONGHORN32 | ALLWINLONGHORN64) + +#define ALLWINVISTA32 BS(WINVISTA) +#define ALLWINVISTA64 BS(WINVISTA_64) #define ALLWINVISTA (ALLWINVISTA32 | ALLWINVISTA64) +#define ALLWIN2008R2_32 BS(WIN2008R2) +#define ALLWIN2008R2_64 BS(WIN2008R2_64) +#define ALLWIN2008R2 (ALLWIN2008R2_32 | ALLWIN2008R2_64) + #define ALLWINSEVEN32 BS(WINSEVEN) #define ALLWINSEVEN64 BS(WINSEVEN_64) #define ALLWINSEVEN (ALLWINSEVEN32 | ALLWINSEVEN64) #define ALLWINNT32 (BS(WINNT) | ALLWIN2000 | ALLWINXP32 | ALLWINNET32 | \ - ALLWINVISTA32 | ALLWINSEVEN32) -#define ALLWINNT64 (ALLWINXP64 | ALLWINNET64 | ALLWINVISTA64 | \ - ALLWINSEVEN64) + ALLWINVISTA32 | ALLWINLONGHORN32 | \ + ALLWINSEVEN32 | ALLWIN2008R2_32) + +#define ALLWINNT64 (ALLWINXP64 | ALLWINNET64 | \ + ALLWINVISTA64 | ALLWINLONGHORN64 | \ + ALLWINSEVEN64 | ALLWIN2008R2_64) + #define ALLWINNT (ALLWINNT32 | ALLWINNT64) #define ALLWIN32 (ALLWIN9X | ALLWINNT32) @@ -141,10 +153,12 @@ typedef enum GuestOSFamilyType { #define ALL26XLINUX64 (BS(OTHER26XLINUX_64) | BS(DEBIAN45_64)) #define ALLLINUX32 (BS(OTHER24XLINUX) | BS(VMKERNEL) | \ BS(OTHERLINUX) | ALL26XLINUX32) -#define ALLLINUX64 (BS(OTHERLINUX_64) | BS(OTHER24XLINUX_64) | ALL26XLINUX64) +#define ALLLINUX64 (BS(OTHERLINUX_64) | BS(OTHER24XLINUX_64) | \ + ALL26XLINUX64) #define ALLLINUX (ALLLINUX32 | ALLLINUX64) #define ALLDARWIN32 (BS(DARWIN9) | BS(DARWIN10)) #define ALLDARWIN64 (BS(DARWIN9_64) | BS(DARWIN10_64)) +#define ALLDARWIN10 (BS(DARWIN10) | BS(DARWIN10_64)) #define ALLDARWIN (ALLDARWIN32 | ALLDARWIN64) #define ALL64 (ALLWIN64 | ALLLINUX64 | \ BS(SOLARIS10_64) | BS(FREEBSD_64) | \ @@ -160,12 +174,16 @@ typedef enum GuestOSFamilyType { #define STR_OS_ANNVIX "Annvix" #define STR_OS_ARCH "Arch" #define STR_OS_ARKLINUX "Arklinux" +#define STR_OS_ASIANUX_3 "asianux3" +#define STR_OS_ASIANUX_4 "asianux4" #define STR_OS_AUROX "Aurox" #define STR_OS_ASIANUX "asianux" #define STR_OS_BLACKCAT "BlackCat" #define STR_OS_COBALT "Cobalt" #define STR_OS_CONECTIVA "Conectiva" -#define STR_OS_DEBIAN "Debian" +#define STR_OS_DEBIAN "Debian" +#define STR_OS_DEBIAN_4 "debian4" +#define STR_OS_DEBIAN_5 "debian5" #define STR_OS_FEDORA "Fedora" #define STR_OS_GENTOO "Gentoo" #define STR_OS_IMMUNIX "Immunix" @@ -256,7 +274,6 @@ typedef enum GuestOSFamilyType { #define STR_OS_WIN_NET_DC_FULL "Windows Server 2003 Datacenter Edition" #define STR_OS_WIN_NET_DC "winNetDatacenter" #define STR_OS_WIN_LONG "longhorn" -#define STR_OS_WIN_LONG_FULL "Longhorn (experimental)" #define STR_OS_WIN_VISTA "winVista" #define STR_OS_WIN_VISTA_FULL "Windows Vista" #define STR_OS_WIN_VISTA_X64 "winVista-64" @@ -349,13 +366,15 @@ typedef enum GuestOSFamilyType { #define STR_OS_WIN_SEVEN_HOME_BASIC_FULL "Windows 7 Home Basic" #define STR_OS_WIN_SEVEN_HOME_PREMIUM_FULL "Windows 7 Home Premium" #define STR_OS_WIN_SEVEN_ULTIMATE_FULL "Windows 7 Ultimate" -#define STR_OS_WIN_SEVEN_BUSINESS_FULL "Windows 7 Business" +#define STR_OS_WIN_SEVEN_PROFESSIONAL_FULL "Windows 7 Professional" +#define STR_OS_WIN_SEVEN_ENTERPRISE_FULL "Windows 7 Enterprise" /* Windows Server 2008 R2 (based on Windows 7) */ #define STR_OS_WIN_2008R2 "windows7srv" #define STR_OS_WIN_2008R2_X64 "windows7srv-64" +#define STR_OS_WIN_2008R2_FOUNDATION_FULL "Windows Server 2008 R2 Foundation Edition" #define STR_OS_WIN_2008R2_STANDARD_FULL "Windows Server 2008 R2 Standard Edition" #define STR_OS_WIN_2008R2_ENTERPRISE_FULL "Windows Server 2008 R2 Enterprise Edition" #define STR_OS_WIN_2008R2_DATACENTER_FULL "Windows Server 2008 R2 Datacenter Edition" diff --git a/open-vm-tools/lib/include/hashTable.h b/open-vm-tools/lib/include/hashTable.h index e0db2baeb..3828b2c06 100644 --- a/open-vm-tools/lib/include/hashTable.h +++ b/open-vm-tools/lib/include/hashTable.h @@ -92,6 +92,11 @@ Bool HashTable_Delete(HashTable *hashTable, const char *keyStr); +Bool +HashTable_LookupAndDelete(HashTable *hashTable, + const char *keyStr, + void **clientData); + void HashTable_Clear(HashTable *ht); diff --git a/open-vm-tools/lib/include/hgfsProto.h b/open-vm-tools/lib/include/hgfsProto.h index 23e56c4c7..3651448e9 100644 --- a/open-vm-tools/lib/include/hgfsProto.h +++ b/open-vm-tools/lib/include/hgfsProto.h @@ -403,6 +403,7 @@ typedef uint64 HgfsAttrFlags; #define HGFS_ATTR_SYSTEM (1 << 1) #define HGFS_ATTR_ARCHIVE (1 << 2) #define HGFS_ATTR_HIDDEN_FORCED (1 << 3) +#define HGFS_ATTR_REPARSE_POINT (1 << 4) /* diff --git a/open-vm-tools/lib/include/hostinfo.h b/open-vm-tools/lib/include/hostinfo.h index aa20ae1cb..ea140c46d 100644 --- a/open-vm-tools/lib/include/hostinfo.h +++ b/open-vm-tools/lib/include/hostinfo.h @@ -167,7 +167,9 @@ typedef enum { OS_DETAIL_WIN2K3_EN = 16, OS_DETAIL_WIN2K3_BUS = 17, OS_DETAIL_VISTA = 18, - OS_DETAIL_WINSEVEN = 19, // Windows 7 + OS_DETAIL_WIN2K8 = 19, + OS_DETAIL_WINSEVEN = 20, // Windows 7 + OS_DETAIL_WIN2K8R2 = 21, OS_DETAIL_UNKNOWN = 99999 // last, highest value } OS_DETAIL_TYPE; diff --git a/open-vm-tools/lib/include/imageUtil.h b/open-vm-tools/lib/include/imageUtil.h index 590c6e13b..13e34eaaf 100644 --- a/open-vm-tools/lib/include/imageUtil.h +++ b/open-vm-tools/lib/include/imageUtil.h @@ -37,6 +37,9 @@ EXTERN Bool ImageUtil_ReadPNG(ImageInfo *image, ConstUnicode pathName, int pngReadFlags); +EXTERN Bool ImageUtil_WritePNG(const ImageInfo *image, + ConstUnicode pathName, + const ImagePngWriteOptions *options); EXTERN Bool ImageUtil_WriteImage(const ImageInfo *image, ConstUnicode pathName, @@ -55,11 +58,7 @@ EXTERN Bool ImageUtil_ConstructBuffer(const ImageInfo *image, ImageType imageTyp DynBuf *imageData); EXTERN void ImageUtil_FreeImageData(ImageInfo *image); -EXTERN Bool ImageUtil_CopyImageRect(const ImageInfo *srcImage, - uint32 x, - uint32 y, - uint32 width, - uint32 height, - ImageInfo *dstImage); +EXTERN Bool ImageUtil_Combine(const ImageInfo *images, const VMPoint *origins, + size_t n, ImageInfo *combined); #endif // _IMAGEUTIL_H_ diff --git a/open-vm-tools/lib/include/imageUtilTypes.h b/open-vm-tools/lib/include/imageUtilTypes.h index aed790f70..306ad5173 100644 --- a/open-vm-tools/lib/include/imageUtilTypes.h +++ b/open-vm-tools/lib/include/imageUtilTypes.h @@ -72,7 +72,7 @@ typedef struct { } ImageInfo; typedef struct { - int zlibCompressLevel; + int zlibCompressLevel; // Set to -1 for the default compression level. Bool stripAlphaChannel; } ImagePngWriteOptions; diff --git a/open-vm-tools/lib/include/loglevel_user.h b/open-vm-tools/lib/include/loglevel_user.h index 63a2f2b94..312b66b9f 100644 --- a/open-vm-tools/lib/include/loglevel_user.h +++ b/open-vm-tools/lib/include/loglevel_user.h @@ -90,6 +90,7 @@ LOGLEVEL_VAR(pci_vmxnet3), \ LOGLEVEL_VAR(vcpuhotplug), \ LOGLEVEL_VAR(heci), \ + LOGLEVEL_VAR(vmiopluginlib), \ \ /* user/disk */ \ LOGLEVEL_VAR(aioMgr), \ @@ -214,6 +215,7 @@ LOGLEVEL_VAR(pvfslib), \ LOGLEVEL_VAR(brtalk), /* macWireless and wpa_supplicant */ \ LOGLEVEL_VAR(button), \ + LOGLEVEL_VAR(util), \ LOGLEVEL_VAR(largepage), LOGLEVEL_EXTENSION_DECLARE(LOGLEVEL_USER); diff --git a/open-vm-tools/lib/include/msgid.h b/open-vm-tools/lib/include/msgid.h index 2095dd0d2..bfb8dc5aa 100644 --- a/open-vm-tools/lib/include/msgid.h +++ b/open-vm-tools/lib/include/msgid.h @@ -30,6 +30,8 @@ #define INCLUDE_ALLOW_VMKERNEL #include "includeCheck.h" +#include "vm_basic_defs.h" + #ifndef VMKERNEL #include #endif diff --git a/open-vm-tools/lib/include/netutil.h b/open-vm-tools/lib/include/netutil.h index 5cb6a2175..9bf923fba 100644 --- a/open-vm-tools/lib/include/netutil.h +++ b/open-vm-tools/lib/include/netutil.h @@ -77,4 +77,31 @@ void NetUtil_MonitorIPStart(void); void NetUtil_MonitorIPStop(void); #endif +#if defined(linux) +# ifdef DUMMY_NETUTIL +/* + * Dummy interface table to enable other tools'/libraries' unit tests. + */ +typedef struct { + int ifIndex; + const char *ifName; +} NetUtilIfTableEntry; + + +/* + * {-1, NULL}-terminated array of NetUtilIfTableEntry pointers. + * + * (Test) applications wishing to use the dummy NetUtil_GetIf{Index,Name} + * functions must define this variable somewhere. It allows said apps + * to work with a priori knowledge of interface name <=> index mappings + * returned by said APIs. + */ +EXTERN NetUtilIfTableEntry netUtilIfTable[]; +# endif // ifdef DUMMY_NETUTIL + +int NetUtil_GetIfIndex(const char *ifName); +char *NetUtil_GetIfName(int ifIndex); + +#endif // if defined(linux) + #endif diff --git a/open-vm-tools/lib/include/rasterConv.h b/open-vm-tools/lib/include/rasterConv.h index 04f58376c..9ba436fbe 100644 --- a/open-vm-tools/lib/include/rasterConv.h +++ b/open-vm-tools/lib/include/rasterConv.h @@ -74,13 +74,13 @@ Bool Raster_IsModeReasonable(uint32 depth, uint32 bpp, Bool pseudocolor); int Raster_GetBPPDepth(uint32 depth, uint32 bpp); void Raster_ConvertPixels(uint8 *tof, int32 line_increment, int bppdepth, - uint8 *src, int32 src_increment, int src_bppdepth, - Bool pseudoColor, uint32 *pixels, + const uint8 *src, int32 src_increment, int src_bppdepth, + Bool pseudoColor, const uint32 *pixels, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h); uint32 Raster_ConvertOnePixel(uint32 pixel, int src_depth, int depth, - Bool pseudoColor, uint32 *pixels); + Bool pseudoColor, const uint32 *pixels); Bool Raster_ConversionParameters(int depth, uint32 *redMask, uint32 *greenMask, uint32 *blueMask); diff --git a/open-vm-tools/lib/include/region.h b/open-vm-tools/lib/include/region.h index 3f00239cc..cb686e455 100644 --- a/open-vm-tools/lib/include/region.h +++ b/open-vm-tools/lib/include/region.h @@ -91,8 +91,8 @@ SOFTWARE. #define NullBox ((BoxPtr)0) #define NullRegion ((RegionPtr)0) -#define R_MAXSHORT 32767 -#define R_MINSHORT (-R_MAXSHORT) +#define R_MAXSHORT SHRT_MAX +#define R_MINSHORT SHRT_MIN #define R_MAXINT 0x7FFFFFFF #define R_MININT 0x8FFFFFFF diff --git a/open-vm-tools/lib/include/system.h b/open-vm-tools/lib/include/system.h index d3c9790fb..562ae8686 100644 --- a/open-vm-tools/lib/include/system.h +++ b/open-vm-tools/lib/include/system.h @@ -29,14 +29,16 @@ # define __SYSTEM_H__ #include "vm_basic_types.h" +#ifdef _WIN32 +#include "dbllnklst.h" +#endif #include "unicode.h" - uint64 System_Uptime(void); Bool System_GetCurrentTime(int64 *secs, int64 *usecs); Bool System_AddToCurrentTime(int64 deltaSecs, int64 deltaUsecs); Unicode System_GetTimeAsString(void); -Bool System_EnableTimeSlew(int64 delta, uint32 timeSyncPeriod); +Bool System_EnableTimeSlew(int64 delta, int64 timeSyncPeriod); Bool System_DisableTimeSlew(void); Bool System_IsTimeSlewEnabled(void); Bool System_IsACPI(void); @@ -53,6 +55,18 @@ typedef struct { void *cbdata; // data to pass to callback } DesktopSwitchThreadArgs; +/* + * Representation of monitors gathered by System_GetMonitors. + */ +typedef struct MonListNode { + RECT rect; + RECT work; + BOOL isPrimary; + DWORD bpp; + BOOL isActive; + DblLnkLst_Links l; +} MonListNode; + /* * The value returned by System_GetServiceState if the current state of the * vmtools service can't be determined. We need to use a value that is not @@ -70,6 +84,7 @@ Bool System_StartDesktopSwitchThread(DesktopSwitchThreadArgs *args); Bool System_KillDesktopSwitchThread(void); Bool System_DisableAndKillScreenSaver(void); DWORD System_GetServiceState(LPCWSTR szServiceName); +DblLnkLst_Links *System_GetMonitors(); #endif diff --git a/open-vm-tools/lib/include/unityCommon.h b/open-vm-tools/lib/include/unityCommon.h index d3f7c8015..fb61dab40 100644 --- a/open-vm-tools/lib/include/unityCommon.h +++ b/open-vm-tools/lib/include/unityCommon.h @@ -24,8 +24,7 @@ */ /* - * Breakdown of components involved in Unity (as of change 748058 on - * 2008/10/23): + * Breakdown of components involved in Unity: * * 1) Unity desktop target * @@ -52,8 +51,7 @@ * 3) Unity client * * This is a VNC-capable client that supports the extensions - * specified in VNCEncode_UnitySupported (currently, - * VNCUnityWindowRectCap and VNCUnityWindowRegionCap). + * specified in VNCEncode_UnitySupported. * * Source: bora/apps/lib/cui/unityMgr.cc * bora/apps/lib/cui/unityMgrVNC.cc @@ -138,8 +136,8 @@ * * ----------------------------------------------------------------------- * - * [1] Hosted UI opens VNC connection to VMX (through authd) with - * VNCUnityWindowRectCap and VNCUnityWindowRegionCap encodings supported. + * [1] Hosted UI opens VNC connection to VMX (through authd) with supported + * encodings of at least what VNCEncode_UnitySupported requires. * * MKS remote manager receives VNC connection socket connection * and spins up MKS hostops VNC backend. @@ -240,6 +238,11 @@ #define GHI_RPC_OUTLOOK_RESTORE_TEMP_FOLDER "ghi.guest.outlook.restore.tempFolder" #define GHI_RPC_TRASH_FOLDER_ACTION "ghi.guest.trashFolder.action" #define GHI_RPC_TRASH_FOLDER_GET_ICON "ghi.guest.trashFolder.getIcon" +#define GHI_RPC_TRAY_ICON_START_UPDATES "ghi.guest.trayIcon.startUpdates" +#define GHI_RPC_TRAY_ICON_STOP_UPDATES "ghi.guest.trayIcon.stopUpates" +#define GHI_RPC_TRAY_ICON_SEND_EVENT "ghi.guest.trayIcon.sendEvent" +#define GHI_RPC_SET_FOCUSED_WINDOW "ghi.guest.setFocusedWindow" +#define GHI_RPC_GET_EXEC_INFO_HASH "ghi.guest.getExecInfoHash" /* @} */ @@ -253,11 +256,11 @@ #define UNITY_RPC_VMX_SHOW_TASKBAR "vmx.unity.show.taskbar" #define UNITY_RPC_UNITY_CAP "tools.capability.unity" #define UNITY_RPC_SHOW_TASKBAR_CAP "tools.capability.unity.taskbar" +#define UNITY_RPC_UNITY_ACTIVE "unity.active" #define GHI_RPC_LAUNCHMENU_CHANGE "tools.ghi.launchmenu.change" #define GHI_RPC_PROTOCOL_HANDLER_INFO "tools.ghi.protocolhandler.info" #define GHI_RPC_TRASH_FOLDER_STATE "ghi.guest.trashFolder.state" -#define UNITY_RPC_UNITY_ACTIVE "unity.active" - +#define GHI_RPC_TRAY_ICON_UPDATE "ghi.guest.trayIcon.update" #define GHI_RPC_HOST_SHELL_ACTION "ghi.host.shell.action" /* @} */ @@ -298,6 +301,19 @@ * Type definitions */ +/** + * @brief Tray icon event identifiers. See ghiTrayIcon.x. + * + * @note These identifiers are shared between tools and the VMX. For + * compatibility reasons, new events must be added at the end of this + * list, and existing event numbers should not be reused if an event + * is removed. + */ + +#define GHI_TRAY_ICON_EVENT_INVALID 0 +#define GHI_TRAY_ICON_EVENT_LBUTTONDBLCLK 1 +#define GHI_TRAY_ICON_EVENT_RIGHT_CLICK 2 +#define GHI_TRAY_ICON_EVENT_LEFT_CLICK 3 /** * @brief Opaque Unity window identifier. @@ -343,15 +359,15 @@ typedef enum { UNITY_WINDOW_ATTR_MAXIMIZED = 3, /**< Is maximized. @note Not mutually exclusive with @ref UNITY_WINDOW_STATE_MINIMIZED. */ UNITY_WINDOW_ATTR_CLOSABLE = 5, ///< Supports closing. - UNITY_WINDOW_ATTR_HAS_TITLEBAR = 6, ///< @deprecated - UNITY_WINDOW_ATTR_VISIBLE = 7, ///< @deprecated - UNITY_WINDOW_ATTR_CHILD_WINDOW = 8, ///< @deprecated + UNITY_WINDOW_ATTR_HAS_TITLEBAR = 6, ///< @deprecated + UNITY_WINDOW_ATTR_VISIBLE = 7, ///< @deprecated + UNITY_WINDOW_ATTR_CHILD_WINDOW = 8, ///< @deprecated UNITY_WINDOW_ATTR_HAS_TASKBAR_BTN = 9, /**< Should appear in the taskbar. @todo Consider deprecation? */ - UNITY_WINDOW_ATTR_MOVABLE = 10, ///< Can be moved around the desktop. - UNITY_WINDOW_ATTR_RESIZABLE = 11, ///< Can be resized. - UNITY_WINDOW_ATTR_ALWAYS_ABOVE = 12, ///< Should stay on top of stack. - UNITY_WINDOW_ATTR_ALWAYS_BELOW = 13, ///< Should stay at bottom of stack. + UNITY_WINDOW_ATTR_MOVABLE = 10, ///< Can be moved around the desktop. + UNITY_WINDOW_ATTR_RESIZABLE = 11, ///< Can be resized. + UNITY_WINDOW_ATTR_ALWAYS_ABOVE = 12, ///< Should stay on top of stack. + UNITY_WINDOW_ATTR_ALWAYS_BELOW = 13, ///< Should stay at bottom of stack. UNITY_WINDOW_ATTR_DISABLED = 14, ///< Keyboard, mouse input is disabled. UNITY_WINDOW_ATTR_NOACTIVATE = 15, /**< Does not raise to foreground via mouse click, alt-tab, etc. */ @@ -364,8 +380,8 @@ typedef enum { UNITY_WINDOW_ATTR_FULLSCREENABLE = 19, ///< @deprecated UNITY_WINDOW_ATTR_FULLSCREENED = 20, ///< @deprecated UNITY_WINDOW_ATTR_ATTN_WANTED = 21, ///< Application wants user's attention. - UNITY_WINDOW_ATTR_SHADEABLE = 22, ///< @deprecated - UNITY_WINDOW_ATTR_SHADED = 23, ///< @deprecated + UNITY_WINDOW_ATTR_SHADEABLE = 22, ///< @deprecated + UNITY_WINDOW_ATTR_SHADED = 23, ///< @deprecated UNITY_WINDOW_ATTR_STICKABLE = 24, ///< Can be made sticky. UNITY_WINDOW_ATTR_STICKY = 25, ///< Window should appear on all desktops. UNITY_WINDOW_ATTR_MODAL = 26, /**< Modal window. @@ -413,7 +429,7 @@ typedef uint32 UnityIconSize; // Number of pixels on the larger side of the icon @{ @def UNITY_RPC_ENTER - @brief Tell the guest to go into Unity mode. + @brief Tell the guest to go into Unity mode. @code UNITY_RPC_ENTER @endcode @@ -423,11 +439,11 @@ typedef uint32 UnityIconSize; // Number of pixels on the larger side of the icon @def UNITY_RPC_GET_UPDATE @brief Get an incremental or full update of window changes detected by - the guest. + the guest. @todo Deprecate this RPC in favor of using UNITY_RPC_GET_UPDATE_FULL and UNITY_RPC_GET_UPDATE_INCREMENTAL @code - UNITY_RPC_GET_UPDATE ["incremental"] + UNITY_RPC_GET_UPDATE ["incremental"] @endcode @param incremental If present, do an incremental update, otherwise full. @note A full update reports all current state of all windows, @@ -455,10 +471,10 @@ execPath ::= ? UTF-8 string uniquely identifying JUST the executable ? @def UNITY_RPC_GET_BINARY_INFO - @brief Return a list of icons for a window. + @brief Return a list of icons for a window. @todo Move this into a GHI-specific header. @todo Give this RPC command an intuitive name. - @code + @code UNITY_RPC_GET_BINARY_INFO windowPath @endcode @param[in] windowPath UTF-8 encoded "window path" returned by @@ -473,15 +489,15 @@ execPath ::= ? UTF-8 string uniquely identifying JUST the executable ? := '\0' @endverbatim @note Icon data is in BGRA format. An alpha channel value of 255 means - "fully opaque", and a value of 0 means "fully transparent". + "fully opaque", and a value of 0 means "fully transparent". @def UNITY_RPC_GET_BINARY_HANDLERS @brief Ask the guest to return filetypes (extensions) and URL protocols - supported by the guest. + supported by the guest. @todo Move this into a GHI-specific header. - @code - UNITY_RPC_GET_BINARY_HANDLERS + @code + UNITY_RPC_GET_BINARY_HANDLERS @endcode @sa ghiGetBinaryHandlers.x for format of data returned. @@ -489,10 +505,10 @@ execPath ::= ? UTF-8 string uniquely identifying JUST the executable ? @def UNITY_RPC_OPEN_LAUNCHMENU @brief Get the start menu sub-tree for a given item @todo Move this into a GHI-specific header. - @code + @code UNITY_RPC_OPEN_LAUNCHMENU root @endcode - @param[in] root Name of sub-tree, or "" for root of start menu. + @param[in] root Name of sub-tree, or "" for root of start menu. @return "count handle" \li @c count Number of items in the sub-tree. @@ -502,7 +518,7 @@ execPath ::= ? UTF-8 string uniquely identifying JUST the executable ? @def UNITY_RPC_GET_LAUNCHMENU_ITEM @brief Get the nth item in the menu sub-tree. @todo Move this into a GHI-specific header. - @code + @code UNITY_RPC_GET_LAUNCHMENU_ITEM handle index @endcode @param[in] handle Handle returned by @ref UNITY_RPC_OPEN_LAUNCHMENU. @@ -512,44 +528,44 @@ execPath ::= ? UTF-8 string uniquely identifying JUST the executable ? @def UNITY_RPC_CLOSE_LAUNCHMENU - @brief Close the sub-menu, releasing all associated resources. + @brief Close the sub-menu, releasing all associated resources. @todo Move this into a GHI-specific header. - @code + @code UNITY_RPC_CLOSE_LAUNCHMENU handle @endcode @param[in] handle Handle returned by @ref UNITY_RPC_OPEN_LAUNCHMENU. - @def UNITY_RPC_WINDOW_SETTOP - @brief Raise a group of windows to the top of the window stacking order. - @code - UNITY_RPC_WINDOW_SETTOP UnityWindowId{ UnityWindowId} + @def UNITY_RPC_WINDOW_SETTOP + @brief Raise a group of windows to the top of the window stacking order. + @code + UNITY_RPC_WINDOW_SETTOP UnityWindowId{ UnityWindowId} @endcode - @param[in] UnityWindowId{ UnityWindowId} group of windows to raise + @param[in] UnityWindowId{ UnityWindowId} group of windows to raise @note Order of windows is bottom to top. @note Only @ref UNITY_MAX_SETTOP_WINDOW_COUNT windows can be specified. - @def UNITY_RPC_WINDOW_CLOSE - @brief Close the specified window. - @code - UNITY_RPC_WINDOW_CLOSE UnityWindowId + @def UNITY_RPC_WINDOW_CLOSE + @brief Close the specified window. + @code + UNITY_RPC_WINDOW_CLOSE UnityWindowId @endcode - @param[in] UnityWindowId window to close + @param[in] UnityWindowId window to close @def UNITY_RPC_GET_WINDOW_CONTENTS - @brief Retreive pixel contents of the Window. - @code - UNITY_RPC_GET_WINDOW_CONTENTS UnityWindowId + @brief Retreive pixel contents of the Window. + @code + UNITY_RPC_GET_WINDOW_CONTENTS UnityWindowId @endcode - @param[in] UnityWindowId UnityWindowId of window to get contents from - @return PNG image containing the window content. + @param[in] UnityWindowId UnityWindowId of window to get contents from + @return PNG image containing the window content. - @def UNITY_RPC_GET_ICON_DATA - @brief Return icon data for a specific window. - @code + @def UNITY_RPC_GET_ICON_DATA + @brief Return icon data for a specific window. + @code UNITY_RPC_GET_ICON_DATA UnityWindowId type size dataOffset dataLength @endcode @param[in] UnityWindowId window to get icon data for @@ -560,55 +576,55 @@ execPath ::= ? UTF-8 string uniquely identifying JUST the executable ? @return PNG image containing the icon data. - @def UNITY_RPC_EXIT - @brief Cease enumerating windows and leave Unity mode. - @code - UNITY_RPC_EXIT + @def UNITY_RPC_EXIT + @brief Cease enumerating windows and leave Unity mode. + @code + UNITY_RPC_EXIT @endcode @note On success, the guest will send a @ref UNITY_RPC_UNITY_ACTIVE with an argument of 0 to indicate it has exited Unity mode. - @def UNITY_RPC_GET_UPDATE_FULL - @brief Equivalent to @ref UNITY_RPC_GET_UPDATE with no argument. - @code - UNITY_RPC_GET_UPDATE_FULL + @def UNITY_RPC_GET_UPDATE_FULL + @brief Equivalent to @ref UNITY_RPC_GET_UPDATE with no argument. + @code + UNITY_RPC_GET_UPDATE_FULL @endcode @return See @ref UnityGetUpdateReturn. - @def UNITY_RPC_GET_UPDATE_INCREMENTAL - @brief Equivalent to @ref UNITY_RPC_GET_UPDATE with an "incremental" argument. - @code - UNITY_RPC_GET_UPDATE_INCREMENTAL + @def UNITY_RPC_GET_UPDATE_INCREMENTAL + @brief Equivalent to @ref UNITY_RPC_GET_UPDATE with an "incremental" argument. + @code + UNITY_RPC_GET_UPDATE_INCREMENTAL @endcode @return See @ref UnityGetUpdateReturn. - @def UNITY_RPC_SHELL_OPEN + @def UNITY_RPC_SHELL_OPEN @brief Open the application corresponding to the passed in URI or - regular path. + regular path. @todo Move this into a GHI-specific header. - @code - UNITY_RPC_SHELL_OPEN + @code + UNITY_RPC_SHELL_OPEN @endcode - @param[in] path URI or path of executable to open + @param[in] path URI or path of executable to open @note The URI is opaque to the caller, the caller supplies this URI to the host with the expecation that it will be able to - understand the format when this RPC is invoked. + understand the format when this RPC is invoked. - @def UNITY_RPC_SHOW_TASKBAR - @brief Show or hide the guest taskbar. - @code + @def UNITY_RPC_SHOW_TASKBAR + @brief Show or hide the guest taskbar. + @code UNITY_RPC_SHOW_TASKBAR flag @endcode @param[in] flag 0 to hide the taskbar, or 1 to show the taskbar. - @def UNITY_RPC_WINDOW_MOVE_RESIZE - @brief Change the geometry of the specified window. - @code + @def UNITY_RPC_WINDOW_MOVE_RESIZE + @brief Change the geometry of the specified window. + @code UNITY_RPC_WINDOW_MOVE_RESIZE UnityWindowId x y width height @endcode @param[in] UnityWindowId UnityWindowId of window to modify @@ -629,16 +645,16 @@ newHeight ::= ? post-op window height ? ; @endverbatim - @def UNITY_RPC_DESKTOP_WORK_AREA_SET - @brief Specify the desktop work areas. + @def UNITY_RPC_DESKTOP_WORK_AREA_SET + @brief Specify the desktop work areas. @todo Add more detail about this RPC and why it matters. - @code - UNITY_RPC_DESKTOP_WORK_AREA_SET + @code + UNITY_RPC_DESKTOP_WORK_AREA_SET @endcode @param[in] list of work areas @verbatim - := { ',' x y width height } - := number of work areas to follow, 0 or greater + := { ',' x y width height } + := number of work areas to follow, 0 or greater @endverbatim @@ -658,18 +674,18 @@ newHeight ::= ? post-op window height ? ; @param[in] UnityWindowId UnityWindowId of window to hide - @def UNITY_RPC_WINDOW_MINIMIZE + @def UNITY_RPC_WINDOW_MINIMIZE @brief Minimize the specified window. - @code + @code UNITY_RPC_WINDOW_MINIMIZE UnityWindowId @endcode - @param[in] UnityWindowId UnityWindowId of window to minimize + @param[in] UnityWindowId UnityWindowId of window to minimize @def UNITY_RPC_WINDOW_UNMINIMIZE @brief Unminimizes a window to its pre-minimization state. - @code - UNITY_RPC_WINDOW_UNMINIMIZE UnityWindowId + @code + UNITY_RPC_WINDOW_UNMINIMIZE UnityWindowId @endcode @param[in] UnityWindowId window to unminimize @note This RPC originated as UNITY_RPC_WINDOW_RESTORE. The actual @@ -677,57 +693,57 @@ newHeight ::= ? post-op window height ? ; backwards compatibility. - @def UNITY_RPC_WINDOW_MAXIMIZE + @def UNITY_RPC_WINDOW_MAXIMIZE @brief Maximize the specified window. - @code + @code UNITY_RPC_WINDOW_MAXIMIZE UnityWindowId @endcode - @param[in] UnityWindowId UnityWindowId of window to maximize + @param[in] UnityWindowId UnityWindowId of window to maximize - @def UNITY_RPC_WINDOW_UNMAXIMIZE - @brief Unmaximize the specified window. - @code + @def UNITY_RPC_WINDOW_UNMAXIMIZE + @brief Unmaximize the specified window. + @code UNITY_RPC_WINDOW_UNMAXIMIZE UnityWindowId @endcode - @param[in] UnityWindowId UnityWindowId of window to unmaximize + @param[in] UnityWindowId UnityWindowId of window to unmaximize - @def UNITY_RPC_DESKTOP_CONFIG_SET - @brief Send desktop (virtual workspaces) configuration. - @code - UNITY_RPC_DESKTOP_CONFIG_SET configuration + @def UNITY_RPC_DESKTOP_CONFIG_SET + @brief Send desktop (virtual workspaces) configuration. + @code + UNITY_RPC_DESKTOP_CONFIG_SET configuration @endcode - @param[in] configuration {} + @param[in] configuration {} @verbatim - := '{'row,col'}' - := currently active cell + := '{'row,col'}' + := currently active cell @endverbatim -The RPC takes the form of a set of row, column pairs, each enclosed by -braces, and an integer. The number of rows and columns can be deduced -by looking for the max row and column value specified in these pairs. -The integer that follows the list of pairs defines the currently active +The RPC takes the form of a set of row, column pairs, each enclosed by +braces, and an integer. The number of rows and columns can be deduced +by looking for the max row and column value specified in these pairs. +The integer that follows the list of pairs defines the currently active desktop, as an offset (starting at 0) of the pair list.\n\n For example: {1,1} {1,2} {2,1} {2,2} 1 specifies a 2 x 2 virtual desktop where the upper right {1,2} is the currently active desktop. - @def UNITY_RPC_DESKTOP_ACTIVE_SET + @def UNITY_RPC_DESKTOP_ACTIVE_SET @brief Change the active desktop to the value specified. - @code + @code UNITY_RPC_DESKTOP_ACTIVE_SET offset @endcode - @param[in] offset Offset into desktop configuration, as defined by @ref UNITY_RPC_DESKTOP_CONFIG_SET, 0 or greater + @param[in] offset Offset into desktop configuration, as defined by @ref UNITY_RPC_DESKTOP_CONFIG_SET, 0 or greater - @def UNITY_RPC_WINDOW_DESKTOP_SET - @brief Change the desktop of the specified window. - @code + @def UNITY_RPC_WINDOW_DESKTOP_SET + @brief Change the desktop of the specified window. + @code UNITY_RPC_WINDOW_DESKTOP_SET UnityWindowId offset @endcode - @param[in] UnityWindowId UnityWindowId of window to move + @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. + @ref UNITY_RPC_DESKTOP_CONFIG_SET, 0 or greater. @} */ @@ -737,64 +753,64 @@ desktop where the upper right {1,2} is the currently active desktop. @{ @def UNITY_RPC_PUSH_UPDATE_CMD - @brief Send a round of Unity Window Tracker updates to the host. + @brief Send a round of Unity Window Tracker updates to the host. @todo doucment update format in unityWindowTracker.c - @code + @code UNITY_RPC_PUSH_UPDATE_CMD commands @endcode @param[in] A double-NUL-terminated string containing NUL-delimited update commands. @note Updates are followed in the command string by Z-order information, - and active desktop information. The update format is documented in - @ref unityWindowTracker.c + and active desktop information. The update format is documented in + @ref unityWindowTracker.c - @def UNITY_RPC_VMX_SHOW_TASKBAR + @def UNITY_RPC_VMX_SHOW_TASKBAR @brief Ask the host to send its "show taskbar" setting. - @code - UNITY_RPC_VMX_SHOW_TASKBAR + @code + UNITY_RPC_VMX_SHOW_TASKBAR @endcode - @def UNITY_RPC_UNITY_CAP - @brief Tell the host if the guest is capable of supporting Unity or not. - @code + @def UNITY_RPC_UNITY_CAP + @brief Tell the host if the guest is capable of supporting Unity or not. + @code UNITY_RPC_UNITY_CAP flag @endcode - @param[in] flag If 1, guest supports Unity. If 0, it does not + @param[in] flag If 1, guest supports Unity. If 0, it does not - @def UNITY_RPC_SHOW_TASKBAR_CAP + @def UNITY_RPC_SHOW_TASKBAR_CAP @brief Tells the host if the guest is capable of showing and hiding the - taskbar. - @code + taskbar. + @code UNITY_RPC_SHOW_TASKBAR_CAP flag @endcode - @param[in] flag If 1, taskbar visibility can be controlled. If 0, it cannot + @param[in] flag If 1, taskbar visibility can be controlled. If 0, it cannot - @def GHI_RPC_LAUNCHMENU_CHANGE + @def GHI_RPC_LAUNCHMENU_CHANGE @brief Inform the host that one or more launch menu items have changed. @todo Move this define to a GHI-specific header. - @code - GHI_RPC_LAUNCHMENU_CHANGE + @code + GHI_RPC_LAUNCHMENU_CHANGE @endcode - @def GHI_RPC_PROTOCOL_HANDLER_INFO - @brief This command sends the list of protocol handlers to the host. + @def GHI_RPC_PROTOCOL_HANDLER_INFO + @brief This command sends the list of protocol handlers to the host. @todo Move this define to a GHI-specific header. - @code - GHI_RPC_PROTOCOL_HANDLER_INFO + @code + GHI_RPC_PROTOCOL_HANDLER_INFO @endcode @param data XDR data containing protocol handler info. @sa GHIPlatformGetProtocolHandlers for platform-specific list of handled protocols. @sa ghiProtocolHandler.x for XDR data format. - @def UNITY_RPC_UNITY_ACTIVE - @brief Tell host we are entering or leaving Unity mode. - @code + @def UNITY_RPC_UNITY_ACTIVE + @brief Tell host we are entering or leaving Unity mode. + @code UNITY_RPC_UNITY_ACTIVE flag @endcode - @param[in] flag If 1, Unity is active. If 0, Unity is not active + @param[in] flag If 1, Unity is active. If 0, Unity is not active @} */ @@ -820,8 +836,12 @@ desktop where the upper right {1,2} is the currently active desktop. * * Each string in the list has one of the following formats: * - * @li "add" UnityWindowId @par + * @li "add" UnityWindowId arguments @par * A window identified by @a UnityWindowId has just been created. + * The @a arguments are optional, and are not provided by all Tools. + * Arguments are space-separated key=value pairs, with the following + * keys: windowPath, execPath. The values are the same as what is + * returned by the @ref UNITY_RPC_GET_WINDOW_PATH RPC. * * @li "remove" UnityWindowId @par * The window identified by @a UnityWindowId has been removed. Get rid diff --git a/open-vm-tools/lib/include/unityWindowTracker.h b/open-vm-tools/lib/include/unityWindowTracker.h index 3d668c5b0..d0961f53d 100644 --- a/open-vm-tools/lib/include/unityWindowTracker.h +++ b/open-vm-tools/lib/include/unityWindowTracker.h @@ -119,6 +119,8 @@ typedef struct UnityUpdate { union { struct { UnityWindowId id; + DynBuf windowPathUtf8; + DynBuf execPathUtf8; } addWindow; struct { @@ -199,6 +201,8 @@ typedef struct { uint32 state; UnityWindowType type; UnityDesktopId desktopId; + DynBuf windowPathUtf8; + DynBuf execPathUtf8; /* Each element is an OR of the UNITY_INFO_ATTR_* values */ unsigned char attributes[UNITY_MAX_ATTRIBUTES]; @@ -241,6 +245,13 @@ struct _UnityWindowTracker { UnityDesktopId activeDesktopId; Bool activeDesktopChanged; + /* + * True if the guest should add hidden windows to the list of tracked windows. + * The windows will be added to the tracker with the hidden attribute. + * By default the guest will not add hidden windows to the tracker. + */ + Bool addHiddenWindows; + void *cbparam; UnityUpdateCallback cb; uint32 updateFlags; @@ -258,9 +269,13 @@ void UnityWindowTracker_Cleanup(UnityWindowTracker *tracker); void UnityWindowTracker_SetDataFreeFunc(UnityWindowTracker *tracker, UnityDataFreeFunc freeFn); UnityWindowInfo *UnityWindowTracker_AddWindow(UnityWindowTracker *tracker, - UnityWindowId id); + UnityWindowId id, + DynBuf *windowPathUtf8, + DynBuf *execPathUtf8); UnityWindowInfo *UnityWindowTracker_AddWindowWithData(UnityWindowTracker *tracker, UnityWindowId id, + DynBuf *windowPathUtf8, + DynBuf *execPathUtf8, void *data); void UnityWindowTracker_MoveWindow(UnityWindowTracker *tracker, UnityWindowId id, int x1, int y1, int x2, diff --git a/open-vm-tools/lib/include/util.h b/open-vm-tools/lib/include/util.h index 18d03e0a2..6d327cf6e 100644 --- a/open-vm-tools/lib/include/util.h +++ b/open-vm-tools/lib/include/util.h @@ -146,6 +146,12 @@ int Util_CompareDotted(const char *s1, const char *s2); void Util_PrintLoadedObjects(void *addr_inside_exec); #endif +#if defined(VMX86_STATS) +Bool Util_QueryCStResidency(uint32 *numCpus, uint32 *numCStates, + uint64 **transitns, uint64 **residency, + uint64 **transTime, uint64 **residTime); +#endif + /* * In util_shared.h */ @@ -223,6 +229,7 @@ EXTERN Bool Util_MakeSureDirExistsAndAccessible(char const *path, #else # define DIRSEPS "/" # define DIRSEPC '/' +# define VALID_DIRSEPS DIRSEPS #endif diff --git a/open-vm-tools/lib/include/vix.h b/open-vm-tools/lib/include/vix.h index 3a76d43d1..044fba718 100644 --- a/open-vm-tools/lib/include/vix.h +++ b/open-vm-tools/lib/include/vix.h @@ -164,6 +164,8 @@ enum { VIX_E_UNABLE_TO_REPLAY_VM = 3039, VIX_E_CANNOT_POWER_ON_VM = 3041, VIX_E_NO_DISPLAY_SERVER = 3043, + VIX_E_VM_NOT_RECORDING = 3044, + VIX_E_VM_NOT_REPLAYING = 3045, /* VM Errors */ VIX_E_VM_NOT_FOUND = 4000, diff --git a/open-vm-tools/lib/include/vixCommands.h b/open-vm-tools/lib/include/vixCommands.h index 55164dbcd..4f3cd39ca 100644 --- a/open-vm-tools/lib/include/vixCommands.h +++ b/open-vm-tools/lib/include/vixCommands.h @@ -26,7 +26,7 @@ #define _VIX_COMMANDS_H_ #include "vm_version.h" -#include "vix.h" +#include "vixOpenSource.h" /* * These describe the format of the message objects. @@ -578,8 +578,6 @@ enum VixKeyStrokeModifiers { VIX_KEYSTROKE_MODIFIER_CONTROL = 0x04, VIX_KEYSTROKE_MODIFIER_SHIFT = 0x08, VIX_KEYSTROKE_MODIFIER_ALT = 0x10, - VIX_KEYSTROKE_MODIFIER_CAPS_LOCK = 0x20, - VIX_KEYSTROKE_MODIFIER_NUM_LOCK = 0x40, VIX_KEYSTROKE_MODIFIER_KEY_DOWN_ONLY = 0x80, VIX_KEYSTROKE_MODIFIER_KEY_UP_ONLY = 0x100, }; @@ -1043,6 +1041,19 @@ struct VixMsgSetSnapshotInfoResponse { #include "vmware_pack_end.h" VixMsgSetSnapshotInfoResponse; +typedef +#include "vmware_pack_begin.h" +struct VixMsgRemoveBulkSnapshotRequest { + VixCommandRequestHeader header; + + int32 options; + int32 numSnapshots; + /* + * This is followed by numSnapshots snapshotIDs. + */ +} +#include "vmware_pack_end.h" +VixMsgRemoveBulkSnapshotRequest; /* * Rolling Tier operations. @@ -2131,6 +2142,24 @@ struct VixCommandListFileSystemsRequest { VixCommandListFileSystemsRequest; +/* + * ********************************************************** + * A simple request packet that contains an options field and a + * property list. + */ + +typedef +#include "vmware_pack_begin.h" +struct VixCommandGenericRequest { + VixCommandRequestHeader header; + + uint32 options; + uint32 propertyListSize; + // This is followed by the buffer of serialized properties +} +#include "vmware_pack_end.h" +VixCommandGenericRequest; + /* * These are values we use to discover hosts and guests through SLPv2. @@ -2261,7 +2290,7 @@ enum { VIX_COMMAND_SET_FILE_INFO = 95, VIX_COMMAND_MOUSE_EVENTS = 96, VIX_COMMAND_OPEN_TEAM = 97, - VIX_COMMAND_FIND_HOST_DEVICES = 98, + /* DEPRECATED VIX_COMMAND_FIND_HOST_DEVICES = 98, */ VIX_COMMAND_ANSWER_MESSAGE = 99, VIX_COMMAND_ENABLE_SHARED_FOLDERS = 100, VIX_COMMAND_MOUNT_HGFS_FOLDERS = 101, @@ -2280,16 +2309,8 @@ enum { VIX_COMMAND_STOP_SNAPSHOT_LOG_RECORDING = 113, VIX_COMMAND_STOP_SNAPSHOT_LOG_PLAYBACK = 114, - /* - * HOWTO: Adding a new Vix Command. Step 2a. - * - * Add a new ID for your new function prototype here. BE CAREFUL. The - * OFFICIAL list of id's is in the bfg-main tree, in bora/lib/public/vixCommands.h. - * When people add new command id's in different tree, they may collide and use - * the same ID values. This can merge without conflicts, and cause runtime bugs. - * Once a new command is added here, a command info field needs to be added - * in bora/lib/foundryMsg. as well. - */ + + VIX_COMMAND_SAMPLE_COMMAND = 115, VIX_COMMAND_GET_GUEST_NETWORKING_CONFIG = 116, @@ -2367,7 +2388,23 @@ enum { VIX_COMMAND_LIST_FILESYSTEMS = 169, - VIX_COMMAND_LAST_NORMAL_COMMAND = 170, + VIX_COMMAND_CHANGE_DISPLAY_TOPOLOGY = 170, + + VIX_COMMAND_SUSPEND_AND_RESUME = 171, + + VIX_COMMAND_REMOVE_BULK_SNAPSHOT = 172, + + /* + * HOWTO: Adding a new Vix Command. Step 2a. + * + * Add a new ID for your new function prototype here. BE CAREFUL. The + * OFFICIAL list of id's is in the bfg-main tree, in bora/lib/public/vixCommands.h. + * When people add new command id's in different tree, they may collide and use + * the same ID values. This can merge without conflicts, and cause runtime bugs. + * 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_TEST_UNSUPPORTED_TOOLS_OPCODE_COMMAND = 998, VIX_TEST_UNSUPPORTED_VMX_OPCODE_COMMAND = 999, @@ -2511,6 +2548,18 @@ const char *VixAsyncOp_GetDebugStrForOpCode(int opCode); VixCommandSecurityCategory VixMsg_GetCommandSecurityCategory(int opCode); +VixError VixMsg_AllocGenericRequestMsg(int opCode, + uint64 cookie, + int credentialType, + const char *userNamePassword, + int options, + VixPropertyListImpl *propertyList, + VixCommandGenericRequest **request); + +VixError VixMsg_ParseGenericRequestMsg(const VixCommandGenericRequest *request, + int *options, + VixPropertyListImpl *propertyList); + #endif // VIX_HIDE_FROM_JAVA diff --git a/open-vm-tools/lib/include/vixOpenSource.h b/open-vm-tools/lib/include/vixOpenSource.h index cbfa50896..8ea2646ed 100644 --- a/open-vm-tools/lib/include/vixOpenSource.h +++ b/open-vm-tools/lib/include/vixOpenSource.h @@ -417,9 +417,9 @@ extern void VixDebugInit(int debugLevel, int apiTraceLevel, extern const char *VixDebug_GetFileBaseName(const char *path); extern void VixAssert(const char *cond, const char *file, int lineNum); -extern void VixLogError(VixError err, const char *function, int line, - const char *fileName, unsigned long threadId, const char *fmt, ...) - PRINTF_DECL(6, 7); +extern VixError VixLogError(VixError err, const char *function, int line, + const char *fileName, unsigned long threadId, const char *fmt, ...) + PRINTF_DECL(6, 7); /* diff --git a/open-vm-tools/lib/include/vm_basic_asm_x86.h b/open-vm-tools/lib/include/vm_basic_asm_x86.h index 228c6a703..1dc8b446e 100644 --- a/open-vm-tools/lib/include/vm_basic_asm_x86.h +++ b/open-vm-tools/lib/include/vm_basic_asm_x86.h @@ -60,35 +60,6 @@ #endif - - -/* - * from linux: usr/include/asm/io.h - */ -#ifdef __GNUC__ -#ifndef __SLOW_DOWN_IO -#ifdef SLOW_IO_BY_JUMPING -#define __SLOW_DOWN_IO __asm__ __volatile__("jmp 1f\n1:\tjmp 1f\n1:") -#else -#define __SLOW_DOWN_IO __asm__ __volatile__("outb %al,$0x80") -#endif -#endif -#elif _MSC_VER -#ifdef SLOW_IO_BY_JUMPING -#define __SLOW_DOWN_IO __asm jmp SHORT $+2 __asm jmp SHORT $+2 -#else -#define __SLOW_DOWN_IO __asm out 80h,al -#endif -#else -#error -#endif - -#ifdef REALLY_SLOW_IO -#define SLOW_DOWN_IO { __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; } -#else -#define SLOW_DOWN_IO __SLOW_DOWN_IO -#endif - /* * FXSAVE/FXRSTOR * save/restore SIMD/MMX fpu state diff --git a/open-vm-tools/lib/include/vm_basic_defs.h b/open-vm-tools/lib/include/vm_basic_defs.h index eac3477b4..ae4d0c3db 100644 --- a/open-vm-tools/lib/include/vm_basic_defs.h +++ b/open-vm-tools/lib/include/vm_basic_defs.h @@ -670,6 +670,12 @@ typedef int pid_t; #endif #endif // _WIN32 +#ifdef HOSTED_LG_PG +#define hosted_lg_pg 1 +#else +#define hosted_lg_pg 0 +#endif + /* *********************************************************************** * STRUCT_OFFSET_CHECK -- */ /** diff --git a/open-vm-tools/lib/include/vm_basic_types.h b/open-vm-tools/lib/include/vm_basic_types.h index e9df7377d..43bc38fac 100644 --- a/open-vm-tools/lib/include/vm_basic_types.h +++ b/open-vm-tools/lib/include/vm_basic_types.h @@ -466,7 +466,14 @@ typedef uint32 PageNum; typedef unsigned MemHandle; typedef int32 World_ID; -#define INVALID_WORLD_ID ((World_ID)-1) +/* !! do not alter the definition of INVALID_WORLD_ID without ensuring + * that the values defined in both bora/public/vm_basic_types.h and + * lib/vprobe/vm_basic_types.h are the same. Additionally, the definition + * of VMK_INVALID_WORLD_ID in vmkapi_world.h also must be defined with + * the same value + */ + +#define INVALID_WORLD_ID ((World_ID)0) typedef World_ID User_CartelID; #define INVALID_CARTEL_ID INVALID_WORLD_ID diff --git a/open-vm-tools/lib/include/vm_device_version.h b/open-vm-tools/lib/include/vm_device_version.h index 48ab7ae35..728bd3ef0 100644 --- a/open-vm-tools/lib/include/vm_device_version.h +++ b/open-vm-tools/lib/include/vm_device_version.h @@ -157,7 +157,7 @@ #define MAX_ETHERNET_CARDS 10 /************* PCI Passthrough implementation limits ********************/ -#define MAX_PCI_PASSTHRU_DEVICES 2 +#define MAX_PCI_PASSTHRU_DEVICES 6 /************* USB implementation limits ********************************/ #define MAX_USB_DEVICES_PER_HOST_CONTROLLER 127 diff --git a/open-vm-tools/lib/include/vm_product.h b/open-vm-tools/lib/include/vm_product.h index 5c94d4c09..85e763339 100644 --- a/open-vm-tools/lib/include/vm_product.h +++ b/open-vm-tools/lib/include/vm_product.h @@ -66,6 +66,7 @@ #define PRODUCT_WORKSTATION_ENTERPRISE_BRIEF_NAME \ PRODUCT_WORKSTATION_BRIEF_NAME " " "ACE Edition" #define PRODUCT_PLAYER_BRIEF_NAME "Player" +#define PRODUCT_ACE_PLAYER_BRIEF_NAME "ACE " PRODUCT_PLAYER_BRIEF_NAME #define PRODUCT_MAC_DESKTOP_BRIEF_NAME "Fusion" #define PRODUCT_ACE_MANAGEMENT_SERVER_BRIEF_NAME "ACE Management Server" @@ -91,6 +92,7 @@ #define PRODUCT_CONSOLE_NAME MAKE_NAME("Server Console") #define PRODUCT_PLAYER_NAME MAKE_NAME(PRODUCT_PLAYER_BRIEF_NAME) #define PRODUCT_PLAYER_NAME_FOR_LICENSE PRODUCT_PLAYER_NAME +#define PRODUCT_ACE_PLAYER_NAME MAKE_NAME(PRODUCT_ACE_PLAYER_BRIEF_NAME) #define PRODUCT_ACE_MANAGEMENT_SERVER_NAME MAKE_NAME(PRODUCT_ACE_MANAGEMENT_SERVER_BRIEF_NAME) #define PRODUCT_VMLS_SHORT_NAME "VMLS" diff --git a/open-vm-tools/lib/include/vm_tools_version.h b/open-vm-tools/lib/include/vm_tools_version.h index a10bb509a..7f2397fc3 100644 --- a/open-vm-tools/lib/include/vm_tools_version.h +++ b/open-vm-tools/lib/include/vm_tools_version.h @@ -886,6 +886,13 @@ typedef uint32 ToolsVersion; #define TOOLS_VERSION_WS70_BETA1_V_MNR 1 #define TOOLS_VERSION_WS70_BETA1_V_BASE 0 +#ifndef RC_INVOKED +#define TOOLS_VERSION_WS70_BETA2 TOOLS_VERSION_TO_UINT(TOOLS_VERSION_WS70_BETA2_V) +#endif /* RC_INVOKED */ +#define TOOLS_VERSION_WS70_BETA2_V_MJR 8 +#define TOOLS_VERSION_WS70_BETA2_V_MNR 1 +#define TOOLS_VERSION_WS70_BETA2_V_BASE 1 + #ifndef RC_INVOKED #define TOOLS_VERSION_FUSION30_BETA1 TOOLS_VERSION_TO_UINT(TOOLS_VERSION_FUSION30_BETA1_V) #endif /* RC_INVOKED */ @@ -893,10 +900,17 @@ typedef uint32 ToolsVersion; #define TOOLS_VERSION_FUSION30_BETA1_V_MNR 2 #define TOOLS_VERSION_FUSION30_BETA1_V_BASE 0 +#ifndef RC_INVOKED +#define TOOLS_VERSION_FUSION30_BETA2 TOOLS_VERSION_TO_UINT(TOOLS_VERSION_FUSION30_BETA2_V) +#endif /* RC_INVOKED */ +#define TOOLS_VERSION_FUSION30_BETA2_V_MJR 8 +#define TOOLS_VERSION_FUSION30_BETA2_V_MNR 2 +#define TOOLS_VERSION_FUSION30_BETA2_V_BASE 1 + -#define TOOLS_VERSION_CURRENT TOOLS_VERSION_WS70_BETA1 -#define TOOLS_VERSION_CURRENT_STR TOOLS_VERSION_TO_STR(TOOLS_VERSION_WS70_BETA1) -#define TOOLS_VERSION_CURRENT_CSV TOOLS_VERSION_TO_CSV(TOOLS_VERSION_WS70_BETA1) +#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) /* diff --git a/open-vm-tools/lib/include/vm_version.h b/open-vm-tools/lib/include/vm_version.h index 45bd868bb..216ab60cd 100644 --- a/open-vm-tools/lib/include/vm_version.h +++ b/open-vm-tools/lib/include/vm_version.h @@ -217,7 +217,7 @@ #define WBC_VERSION "e.x.p" #define SDK_VERSION "4.1.0" #define FOUNDRY_VERSION "e.x.p" -#define FOUNDRY_FILE_VERSION 1,6,2,PRODUCT_BUILD_NUMBER_NUMERIC +#define FOUNDRY_FILE_VERSION 1,7,0,PRODUCT_BUILD_NUMBER_NUMERIC #define VMLS_VERSION "e.x.p" #define VLICENSE_VERSION "1.1.0" #define DDK_VERSION "e.x.p" @@ -252,7 +252,7 @@ /* * The current Tools version, derived from vm_tools_version.h. Do not modify this. */ -#define TOOLS_VERSION "2009.06.18" +#define TOOLS_VERSION "2009.07.22" #ifdef VMX86_VPX #define VIM_API_TYPE "VirtualCenter" @@ -428,6 +428,7 @@ #define PRODUCT_VERSION_SCALABLE_SERVER_3 PRODUCT_SCALABLE_SERVER_BRIEF_NAME " 3.x" #define PRODUCT_VERSION_SCALABLE_SERVER_30 PRODUCT_SCALABLE_SERVER_BRIEF_NAME " 3.0" #define PRODUCT_VERSION_SCALABLE_SERVER_31 PRODUCT_SCALABLE_SERVER_BRIEF_NAME " 3.5" +#define PRODUCT_VERSION_SCALABLE_SERVER_40 PRODUCT_SCALABLE_SERVER_BRIEF_NAME " 4.0" #define PRODUCT_VERSION_WGS_1 PRODUCT_WGS_BRIEF_NAME " 1.x" #define PRODUCT_VERSION_WGS_2 PRODUCT_WGS_BRIEF_NAME " 2.0" #define PRODUCT_VERSION_GSX_2 PRODUCT_GSX_BRIEF_NAME " 2.x" @@ -436,12 +437,14 @@ #define PRODUCT_VERSION_WORKSTATION_5 PRODUCT_WORKSTATION_BRIEF_NAME " 5.x" #define PRODUCT_VERSION_WORKSTATION_6 PRODUCT_WORKSTATION_BRIEF_NAME " 6.0" #define PRODUCT_VERSION_WORKSTATION_65 PRODUCT_WORKSTATION_BRIEF_NAME " 6.5" +#define PRODUCT_VERSION_WORKSTATION_70 PRODUCT_WORKSTATION_BRIEF_NAME " 7.0" #define PRODUCT_VERSION_WORKSTATION_ENTERPRISE_1 "ACE 1.x" #define PRODUCT_VERSION_WORKSTATION_ENTERPRISE_2 "ACE 2.0" #define PRODUCT_VERSION_WORKSTATION_ENTERPRISE_25 "ACE 2.5" #define PRODUCT_VERSION_PLAYER_1 PRODUCT_PLAYER_BRIEF_NAME " 1.x" #define PRODUCT_VERSION_MAC_DESKTOP_1 PRODUCT_MAC_DESKTOP_BRIEF_NAME " 1.1" #define PRODUCT_VERSION_MAC_DESKTOP_2 PRODUCT_MAC_DESKTOP_BRIEF_NAME " 2.0" +#define PRODUCT_VERSION_MAC_DESKTOP_3 PRODUCT_MAC_DESKTOP_BRIEF_NAME " 3.0" /* diff --git a/open-vm-tools/lib/include/vmtoolsApp.h b/open-vm-tools/lib/include/vmtoolsApp.h index 0cc94e67e..6a00c5a86 100644 --- a/open-vm-tools/lib/include/vmtoolsApp.h +++ b/open-vm-tools/lib/include/vmtoolsApp.h @@ -46,7 +46,7 @@ * @param[in] err Error code. Must not be 0. */ #define VMTOOLSAPP_ERROR(ctx, err) do { \ - g_assert((err) != 0); \ + ASSERT((err) != 0); \ (ctx)->errorCode = (err); \ g_main_loop_quit((ctx)->mainLoop); \ } while (0) @@ -138,11 +138,27 @@ #endif +/** + * This enum lists all API versions that different versions of vmtoolsd support. + * The "ToolsAppCtx" instance provided to plugins contains a "version" field + * which is a bit-mask of these values, telling plugins what features the + * container supports. + * + * Refer to a specific feature's documentation for which version of the API + * is needed for it to be supported. + */ +typedef enum { + TOOLS_CORE_API_V1 = 0x1, +} ToolsCoreAPI; + + /** * Defines the context of a tools application. This data is provided by the * core services to applications when they're loaded. */ typedef struct ToolsAppCtx { + /** Supported API versions. This is a bit-mask. */ + ToolsCoreAPI version; /** Name of the application. */ const gchar *name; /** Whether we're running under a VMware hypervisor. */ @@ -243,10 +259,80 @@ typedef enum { * Denotes a list of signals the application is interested in (type * ToolsPluginSignalCb). */ - TOOLS_APP_SIGNALS = 2 + TOOLS_APP_SIGNALS = 2, + /** + * Denotes an application provider (type ToolsAppProvider). This allows + * plugins to extend the functionality of vmtoolsd by adding new application + * types (that other plugins can hook into). + */ + TOOLS_APP_PROVIDER = 3, } ToolsAppType; +/** + * Defines the registration data for an "application provider". Application + * providers allow plugins to hook into new application frameworks that will + * be then managed by vmtoolsd - for example, an HTTP server or a dbus endpoint. + * + * Application providers will be loaded during startup but not activated until + * at least one plugin provides registration data for that provider. + */ +typedef struct ToolsAppProvider { + /** A name describing the provider. */ + const gchar *name; + /** + * Application type. Optimally, new providers would request a new type to be + * added to the "official" ToolsAppType enum declared above, although that + * is not strictly necessary. Providers should at least try to choose an + * unused value. + */ + ToolsAppType regType; + /** Size of the registration structure for this provider. */ + size_t regSize; + /** + * Activation callback (optional). This is called when vmtoolsd detects that + * there is at least one application that needs to be registered with this + * provider. + * + * @param[in] ctx The application context. + * @param[in] prov The provider instance. + * @param[out] err Where to store any error information. + */ + void (*activate)(ToolsAppCtx *ctx, struct ToolsAppProvider *prov, GError **err); + /** + * Registration callback. This is called after "activate", to register an + * application provided by a plugin. + * + * @param[in] ctx The application context. + * @param[in] prov The provider instance. + * @param[in] reg The application registration data. + */ + void (*registerApp)(ToolsAppCtx *ctx, struct ToolsAppProvider *prov, gpointer reg); + /** + * Shutdown callback (optional). Called when the service is being shut down. + * The provider is responsible for keeping track of registrations and + * cleaning them up during shutdown. + * + * @param[in] ctx The application context. + * @param[in] prov The provider instance. + */ + void (*shutdown)(ToolsAppCtx *ctx, struct ToolsAppProvider *prov); + /** + * Debugging callback (optional). This callback is called when dumping the + * service state to the logs for debugging purposes. + * + * This callback is called once with a "NULL" reg, so that the provider can + * log its internal state, and then once for each registration struct + * provided by loaded plugins. + * + * @param[in] ctx The application context. + * @param[in] prov The provider instance. + * @param[in] reg The application registration data. + */ + void (*dumpState)(ToolsAppCtx *ctx, struct ToolsAppProvider *prov, gpointer reg); +} ToolsAppProvider; + + /** * Defines a "transport-specific" registration. The array contains data specific * to a "transport" implementation. @@ -284,11 +370,11 @@ typedef struct ToolsPluginSignalCb { * about all functionality exported by the application, and any events that the * application may be interested in. * - * All fields are optional. When the plugin is shut down, if the @a regs field - * is not NULL, it (and its element array) are freed with g_array_free(). + * When the plugin is shut down, if the @a regs field is not NULL, it (and its + * element array) are freed with g_array_free(). */ typedef struct ToolsPluginData { - /** Name of the application. */ + /** Name of the application (required). */ char *name; /** List of features provided by the app. */ GArray *regs; diff --git a/open-vm-tools/lib/include/wiper.h b/open-vm-tools/lib/include/wiper.h index fb2da3676..25d15c842 100644 --- a/open-vm-tools/lib/include/wiper.h +++ b/open-vm-tools/lib/include/wiper.h @@ -49,8 +49,6 @@ typedef enum { #define NATIVE_MAX_PATH 256 #define MAX_WIPER_FILE_SIZE (2 << 30) /* The maximum wiper file size in bytes */ -#define WIPER_DEVICE_MAPPER_STRING "Device mapper partition" - typedef struct WiperPartition { unsigned char mountPoint[NATIVE_MAX_PATH]; diff --git a/open-vm-tools/lib/include/x86cpuid.h b/open-vm-tools/lib/include/x86cpuid.h index 2dd747110..223060392 100644 --- a/open-vm-tools/lib/include/x86cpuid.h +++ b/open-vm-tools/lib/include/x86cpuid.h @@ -116,6 +116,7 @@ CPUIDQuery; #define CPUID_CACHED_LEVELS \ CPUIDLEVEL(TRUE, 0, 0) \ CPUIDLEVEL(TRUE, 1, 1) \ + CPUIDLEVEL(FALSE, 5, 5) \ CPUIDLEVEL(FALSE,400, 0x40000000) \ CPUIDLEVEL(FALSE,410, 0x40000010) \ CPUIDLEVEL(FALSE, 80, 0x80000000) \ @@ -125,7 +126,6 @@ CPUIDQuery; #define CPUID_UNCACHED_LEVELS \ CPUIDLEVEL(FALSE, 4, 4) \ - CPUIDLEVEL(FALSE, 5, 5) \ CPUIDLEVEL(FALSE, 6, 6) \ CPUIDLEVEL(FALSE, A, 0xA) \ CPUIDLEVEL(FALSE, 86, 0x80000006) \ @@ -179,6 +179,7 @@ typedef enum { #define CPUID_CYRIX_VENDOR_STRING "CyriteadxIns" #define CPUID_VIA_VENDOR_STRING "CentaulsaurH" #define CPUID_HYPERV_HYPERVISOR_VENDOR_STRING "Microsoft Hv" +#define CPUID_VMWARE_HYPERVISOR_VENDOR_STRING "VMwareVMware" #define CPUID_INTEL_VENDOR_STRING_FIXED "GenuineIntel" #define CPUID_AMD_VENDOR_STRING_FIXED "AuthenticAMD" #define CPUID_CYRIX_VENDOR_STRING_FIXED "CyrixInstead" @@ -279,7 +280,7 @@ FIELDDEFA( 1, EBX, COMMON, 24, 8, APICID, ANY, IGNORE, 0, FALSE, A FLAGDEFA( 1, ECX, COMMON, 0, 1, SSE3, YES, HOST, 0, TRUE, SSE3) \ FLAGDEFA( 1, ECX, INTEL, 1, 1, PCLMULQDQ, YES, HOST, 0, TRUE, PCLMULQDQ) \ FLAGDEF( 1, ECX, INTEL, 2, 1, NDA2, NO, MASK, 0, FALSE) \ -FLAGDEFA( 1, ECX, COMMON, 3, 1, MWAIT, NO, MASK, 0, FALSE, MWAIT) \ +FLAGDEFA( 1, ECX, COMMON, 3, 1, MWAIT, ANY, MASK, 0, FALSE, MWAIT) \ FLAGDEFA( 1, ECX, INTEL, 4, 1, DSCPL, NO, MASK, 0, FALSE, DSCPL) \ FLAGDEFA( 1, ECX, INTEL, 5, 1, VMX, NO, MASK, 0, FALSE, VMX) \ FLAGDEF( 1, ECX, INTEL, 6, 1, SMX, NO, MASK, 0, FALSE) \ @@ -344,10 +345,10 @@ FIELDDEF( 4, EBX, INTEL, 22, 10, CACHE_WAYS, NA, IGNORE, 0, FALSE) /* LEVEL, REG, VENDOR, POS, SIZE, NAME, MON SUPP, MASK TYPE, SET TO, CPL3, [FUNC] */ #define CPUID_FIELD_DATA_LEVEL_5 \ -FIELDDEF( 5, EAX, COMMON, 0, 16, MWAIT_MIN_SIZE, NA, IGNORE, 0, FALSE) \ -FIELDDEF( 5, EBX, COMMON, 0, 16, MWAIT_MAX_SIZE, NA, IGNORE, 0, FALSE) \ +FIELDDEFA( 5, EAX, COMMON, 0, 16, MWAIT_MIN_SIZE, NA, IGNORE, 0, FALSE, MWAIT_MIN_SIZE) \ +FIELDDEFA( 5, EBX, COMMON, 0, 16, MWAIT_MAX_SIZE, NA, IGNORE, 0, FALSE, MWAIT_MAX_SIZE) \ FLAGDEF( 5, ECX, COMMON, 0, 1, MWAIT_EXTENSIONS, NA, IGNORE, 0, FALSE) \ -FLAGDEF( 5, ECX, COMMON, 1, 1, MWAIT_INTR_BREAK, NA, IGNORE, 0, FALSE) \ +FLAGDEFA( 5, ECX, COMMON, 1, 1, MWAIT_INTR_BREAK, NA, IGNORE, 0, FALSE, MWAIT_INTR_BREAK) \ FIELDDEF( 5, EDX, INTEL, 0, 4, MWAIT_C0_SUBSTATE, NA, IGNORE, 0, FALSE) \ FIELDDEF( 5, EDX, INTEL, 4, 4, MWAIT_C1_SUBSTATE, NA, IGNORE, 0, FALSE) \ FIELDDEF( 5, EDX, INTEL, 8, 4, MWAIT_C2_SUBSTATE, NA, IGNORE, 0, FALSE) \ @@ -863,31 +864,6 @@ CPUID_MODEL_IS_BARCELONA(uint32 v) // IN: %eax from CPUID with %eax=1. #define CPUID_INTEL_ID4EAX_CACHE_FULLY_ASSOC 0x00000200 -/* - * On AMD chips before Opteron and Intel chips before P4 model 3, - * WRMSR(TSC) clears the upper half of the TSC instead of using %edx. - */ -static INLINE Bool -CPUID_FullyWritableTSC(CpuidVendors vendor, // IN - uint32 v) // IN: %eax from CPUID with %eax=1. -{ - /* - * Returns FALSE if: - * - Intel && P6 (pre-core) or - * - Intel && P4 (model < 3) or - * - AMD && pre-K8 Opteron - * Otherwise, returns TRUE (including for Via Nano). - */ - return !((vendor == CPUID_VENDOR_INTEL && - ((CPUID_FAMILY_IS_P6(v) && - CPUID_EFFECTIVE_MODEL(v) < CPUID_MODEL_PM_0E) || - (CPUID_FAMILY_IS_PENTIUM4(v) && - CPUID_EFFECTIVE_MODEL(v) < 3))) || - (vendor == CPUID_VENDOR_AMD && - CPUID_FAMILY(v) < CPUID_FAMILY_K8)); -} - - /* * For certain AMD processors, an lfence instruction is necessary at various * places to ensure ordering. @@ -930,44 +906,6 @@ CPUID_RequiresFence(CpuidVendors vendor, // IN } -/* - *---------------------------------------------------------------------- - * - * CPUID_CountsCPUIDAsBranch -- - * - * Returns TRUE iff the cpuid given counts CPUID as a branch - * (i.e. is a pre-Merom E CPU). - * - *---------------------------------------------------------------------- - */ - -static INLINE Bool -CPUID_CountsCPUIDAsBranch(uint32 v) /* %eax from CPUID with %eax=1 */ -{ - /* - * CPUID no longer a branch starting with Merom E. Bug 148411. - * Penryn (Extended Model: 1) also has this fixed. - * - * Merom E is: CPUID.1.eax & 0xfff = 0x6f9 - */ - return !(CPUID_FAMILY_IS_P6(v) && - (CPUID_EFFECTIVE_MODEL(v) > CPUID_MODEL_CORE_0F || - (CPUID_EFFECTIVE_MODEL(v) == CPUID_MODEL_CORE_0F && - CPUID_STEPPING(v) >= 9))); -} - -/* - * On Merom and later Intel chips, not present PDPTEs with reserved bits - * set do not fault with a #GP. See PR# 109120. - */ -static INLINE Bool -CPUID_FaultOnNPReservedPDPTE(uint32 v) // IN: %eax from CPUID with %eax=1. -{ - return !(CPUID_FAMILY_IS_P6(v) && - (CPUID_EFFECTIVE_MODEL(v) >= CPUID_MODEL_CORE_0F)); -} - - /* * The following low-level functions compute the number of * cores per cpu. They should be used cautiously because @@ -983,6 +921,7 @@ CPUID_IntelCoresPerPackage(uint32 v) /* %eax from CPUID with %eax=4 and %ecx=0. return 1 + CPUID_INTEL_CORE_COUNT(v); } + static INLINE uint32 CPUID_AMDCoresPerPackage(uint32 v) /* %ecx from CPUID with %eax=0x80000008. */ { @@ -990,6 +929,7 @@ CPUID_AMDCoresPerPackage(uint32 v) /* %ecx from CPUID with %eax=0x80000008. */ return 1 + CPUID_AMD_CORE_COUNT(v); } + /* * Hypervisor CPUID space is 0x400000XX. */ @@ -1001,20 +941,4 @@ CPUID_IsHypervisorLevel(uint32 level, uint32 *offset) } -/* Intel and VIA allow use of sysenter/sysexit in longmode. AMD does not. */ -#define CPUID_HAS_SYSENTER64() (!CPUFEATURE_IS_AMD()) - -/* Intel and VIA behave the same, AMD is different. */ -#define CPUID_LOADING_NULL_LEAVES_BASE() CPUFEATURE_IS_AMD() - -/* Intel and VIA ignore on 64 bit JMPs. */ -#define CPUID_JMP64_IGNORES_OPSZ() (!CPUFEATURE_IS_AMD()) - -/* - * Hardware-assisted virtualization supports one of two hypercalls: - * VMCALL for VT-x implementations (Intel or VIA) and VMMCALL for AMD-V - * implementations (AMD). - */ -#define CPUID_HYPERCALL_IS_VMCALL() (!CPUFEATURE_IS_AMD()) - #endif diff --git a/open-vm-tools/lib/misc/dbllnklst.c b/open-vm-tools/lib/misc/dbllnklst.c index 9fb25f3db..f9bc45156 100644 --- a/open-vm-tools/lib/misc/dbllnklst.c +++ b/open-vm-tools/lib/misc/dbllnklst.c @@ -69,211 +69,10 @@ /* - *---------------------------------------------------------------------- - * - * DblLnkLst_Init -- - * - * Initialize a member of a doubly linked list - * - * Result - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -void -DblLnkLst_Init(DblLnkLst_Links *l) // IN -{ - ASSERT(l); - - l->prev = l->next = l; -} - - -/* - *---------------------------------------------------------------------- - * - * DblLnkLst_Link -- - * - * Merge two doubly linked lists into one - * - * The operation is commutative - * The operation is inversible (its inverse is DblLnkLst_Unlink) - * - * Result - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -void -DblLnkLst_Link(DblLnkLst_Links *l1, // IN - DblLnkLst_Links *l2) // IN -{ - DblLnkLst_Links *tmp; - - ASSERT(l1); - ASSERT(l2); - - (tmp = l1->prev)->next = l2; - (l1->prev = l2->prev)->next = l1; - l2->prev = tmp ; -} - - -/* - *---------------------------------------------------------------------- - * - * DblLnkLst_Unlink -- - * - * Split one doubly linked list into two - * - * No check is performed: the caller must ensure that both members - * belong to the same doubly linked list - * - * The operation is commutative - * The operation is inversible (its inverse is DblLnkLst_Link) - * - * Result - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- + * XXX This file is empty because I made all the functions inline. + * -- edward */ -void -DblLnkLst_Unlink(DblLnkLst_Links *l1, // IN - DblLnkLst_Links *l2) // IN -{ - DblLnkLst_Links *tmp; - - ASSERT(l1); - ASSERT(l2); - - tmp = l1->prev ; - (l1->prev = l2->prev)->next = l1; - (l2->prev = tmp )->next = l2; -} - - -/* - *---------------------------------------------------------------------- - * - * DblLnkLst_Unlink1 -- - * - * Unlink an element from its list. - * - * Result - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -void -DblLnkLst_Unlink1(DblLnkLst_Links *l) // IN -{ - ASSERT(l); - - DblLnkLst_Unlink(l, l->next); -} - - -/* - *---------------------------------------------------------------------------- - * - * DblLnkLst_IsLinked -- - * - * Determines whether an element is linked with any other elements. - * - * Results: - * TRUE if link is linked, FALSE otherwise. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -Bool -DblLnkLst_IsLinked(DblLnkLst_Links const *l) // IN -{ - ASSERT(l); - - ASSERT((l->prev == l && l->next == l) || - (l->prev != l && l->next != l)); - - /* - * A DblLnkLst_Links is either linked to itself (not linked) or linked to - * other elements in a list (linked). - */ - return l->prev != l; -} - - -/* - *---------------------------------------------------------------------- - * - * DblLnkLst_LinkFirst -- - * - * Insert 'l' at the beginning of the list anchored at 'head' - * - * Result - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -void -DblLnkLst_LinkFirst(DblLnkLst_Links *head, // IN - DblLnkLst_Links *l) // IN -{ - ASSERT(head); - ASSERT(l); - - DblLnkLst_Link(head->next, l); -} - - -/* - *---------------------------------------------------------------------- - * - * DblLnkLst_LinkLast -- - * - * Insert 'l' at the end of the list anchored at 'head' - * - * Result - * None - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ - -void -DblLnkLst_LinkLast(DblLnkLst_Links *head, // IN - DblLnkLst_Links *l) // IN -{ - ASSERT(head); - ASSERT(l); - - DblLnkLst_Link(head, l); -} - #if 0 /* diff --git a/open-vm-tools/lib/misc/escape.c b/open-vm-tools/lib/misc/escape.c index bbad998ac..6a141ee27 100644 --- a/open-vm-tools/lib/misc/escape.c +++ b/open-vm-tools/lib/misc/escape.c @@ -498,6 +498,98 @@ nem: } +/* + *----------------------------------------------------------------------------- + * + * Escape_StrChr -- + * + * Find the first occurence of c in bufIn that is not preceded by + * escByte. + * + * XXX Doesn't handle recursive escaping, so + * will skip that occurence of + * + * Results: + * A pointer to the character, if found, NULL if not found. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +const char * +Escape_Strchr(char escByte, // IN + const char *bufIn, // IN + char c) // IN +{ + size_t i; + Bool escaped = FALSE; + + ASSERT(escByte != c); + ASSERT(bufIn); + + for (i = 0; bufIn[i] != '\0'; i++) { + if (escaped) { + escaped = FALSE; + } else { + if (bufIn[i] == c) { + return &bufIn[i]; + } + + if (bufIn[i] == escByte) { + escaped = TRUE; + } + } + } + return NULL; +} + + +/* + *----------------------------------------------------------------------------- + * + * Escape_Unescape -- + * + * Removes all occurences of an escape character from a string, unless + * the occurence is escaped. + * + * Results: + * An allocated string. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +char * +Escape_Unescape(char escByte, // IN + const char *bufIn) // IN +{ + DynBuf result; + Bool escaped = FALSE; + char nullbyte = '\0'; + int i; + + ASSERT(bufIn); + + DynBuf_Init(&result); + + for (i = 0; bufIn[i]; i++) { + if (bufIn[i] != escByte || escaped) { + DynBuf_Append(&result, &(bufIn[i]), sizeof(char)); + escaped = FALSE; + } else { + escaped = TRUE; + } + } + + DynBuf_Append(&result, &nullbyte, sizeof('\0')); + return DynBuf_Get(&result); +} + + /* *---------------------------------------------------------------------------- * diff --git a/open-vm-tools/lib/misc/hashTable.c b/open-vm-tools/lib/misc/hashTable.c index cf61200d0..ef8beeecc 100644 --- a/open-vm-tools/lib/misc/hashTable.c +++ b/open-vm-tools/lib/misc/hashTable.c @@ -491,6 +491,36 @@ HashTable_Lookup(HashTable *ht, // IN Bool HashTable_Delete(HashTable *ht, // IN/OUT: the hash table const char *keyStr) // IN: key for the element to remove +{ + return HashTable_LookupAndDelete(ht, keyStr, NULL); +} + + +/* + *---------------------------------------------------------------------- + * + * HashTable_LookupAndDelete -- + * + * Look up an element in the hash table, then delete it. + * + * If clientData is specified, then the entry data is returned, + * and the free function is not called. + * + * Results: + * TRUE if the entry was found and subsequently removed + * FALSE otherwise + * Entry value is returned in *clientData. + * + * Side effects: + * See above + * + *---------------------------------------------------------------------- + */ + +Bool +HashTable_LookupAndDelete(HashTable *ht, // IN/OUT: the hash table + const char *keyStr, // IN: key for the element + void **clientData) // OUT: return data { uint32 hash = HashTableComputeHash(ht, keyStr); HashTableLink *linkp; @@ -507,7 +537,9 @@ HashTable_Delete(HashTable *ht, // IN/OUT: the hash table if (ht->copyKey) { free((char *) entry->keyStr); } - if (ht->freeEntryFn) { + if (clientData != NULL) { + *clientData = Atomic_ReadPtr(&entry->clientData); + } else if (ht->freeEntryFn) { ht->freeEntryFn(Atomic_ReadPtr(&entry->clientData)); } free(entry); diff --git a/open-vm-tools/lib/misc/hostinfoPosix.c b/open-vm-tools/lib/misc/hostinfoPosix.c index f064b2c6d..e57491ee0 100644 --- a/open-vm-tools/lib/misc/hostinfoPosix.c +++ b/open-vm-tools/lib/misc/hostinfoPosix.c @@ -18,30 +18,97 @@ #include #include +#include #include -#include -#include +#include #include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #if defined(sun) #include #endif -#include -#include #include -#include #if defined(__FreeBSD__) || defined(__APPLE__) # include #endif +#if defined(__APPLE__) +#define SYS_NMLN _SYS_NAMELEN +#include +#include +#include +#include +#include +#include +#include +#include +#elif defined(__FreeBSD__) +#if !defined(RLIMIT_AS) +# if defined(RLIMIT_VMEM) +# define RLIMIT_AS RLIMIT_VMEM +# else +# define RLIMIT_AS RLIMIT_RSS +# endif +#endif +#else +#if !defined(USING_AUTOCONF) || defined(HAVE_SYS_VFS_H) +#include +#endif +#if !defined(sun) && (!defined(USING_AUTOCONF) || (defined(HAVE_SYS_IO_H) && defined(HAVE_SYS_SYSINFO_H))) +#include +#include +#ifndef HAVE_SYSINFO +#define HAVE_SYSINFO 1 +#endif +#endif +#endif + +#if defined(__APPLE__) || defined(__FreeBSD__) +#include +#endif + +#if !defined(_PATH_DEVNULL) +#define _PATH_DEVNULL "/dev/null" +#endif #include "vmware.h" +#include "hostType.h" #include "hostinfo.h" #include "safetime.h" +#include "vm_version.h" #include "str.h" +#include "msg.h" +#include "log.h" +#include "posix.h" +#include "file.h" +#include "backdoor_def.h" +#include "util.h" +#include "vmstdio.h" +#include "su.h" +#include "vm_atomic.h" +#include "x86cpuid.h" +#include "syncMutex.h" +#include "unicode.h" #include "guest_os.h" #include "dynbuf.h" -#include "vmstdio.h" -#include "posix.h" + +#if defined(VMX86_SERVER) +#include "uwvmkAPI.h" +#include "uwvmk.h" +#include "vmkSyscall.h" +#endif + +#define LGPFX "HOSTINFO:" +#define MAX_LINE_LEN 128 #define SYSTEM_BITNESS_32 "i386" #define SYSTEM_BITNESS_64_SUN "amd64" @@ -315,8 +382,8 @@ Hostinfo_GetSystemBitness(void) if (strcmp(buf, SYSTEM_BITNESS_32) == 0) { return 32; - } else if ( strcmp(buf, SYSTEM_BITNESS_64_SUN) == 0 - || strcmp(buf, SYSTEM_BITNESS_64_LINUX) == 0) { + } else if (strcmp(buf, SYSTEM_BITNESS_64_SUN) == 0 || + strcmp(buf, SYSTEM_BITNESS_64_LINUX) == 0) { return 64; } @@ -354,6 +421,7 @@ HostinfoGetOSShortName(char *distro, // IN: full distro name if (distroLower == NULL) { Warning("%s: could not allocate memory\n", __FUNCTION__); + return; } @@ -375,7 +443,8 @@ HostinfoGetOSShortName(char *distro, // IN: full distro name if (releaseStart) { sscanf(releaseStart, "release %d", &release); if (release > 0) { - snprintf(distroShort, distroShortSize, STR_OS_RED_HAT_EN"%d", release); + snprintf(distroShort, distroShortSize, STR_OS_RED_HAT_EN"%d", + release); } } @@ -416,6 +485,12 @@ HostinfoGetOSShortName(char *distro, // IN: full distro name Str_Strcpy(distroShort, STR_OS_ARCH, distroShortSize); } else if (strstr(distroLower, "arklinux")) { Str_Strcpy(distroShort, STR_OS_ARKLINUX, distroShortSize); + } else if (strstr(distroLower, "asianux server 3") || + strstr(distroLower, "asianux client 3")) { + Str_Strcpy(distroShort, STR_OS_ASIANUX_3, distroShortSize); + } else if (strstr(distroLower, "asianux server 4") || + strstr(distroLower, "asianux client 4")) { + Str_Strcpy(distroShort, STR_OS_ASIANUX_4, distroShortSize); } else if (strstr(distroLower, "aurox")) { Str_Strcpy(distroShort, STR_OS_AUROX, distroShortSize); } else if (strstr(distroLower, "black cat")) { @@ -425,7 +500,11 @@ HostinfoGetOSShortName(char *distro, // IN: full distro name } else if (strstr(distroLower, "conectiva")) { Str_Strcpy(distroShort, STR_OS_CONECTIVA, distroShortSize); } else if (strstr(distroLower, "debian")) { - Str_Strcpy(distroShort, STR_OS_DEBIAN, distroShortSize); + if (strstr(distroLower, "4.0")) { + Str_Strcpy(distroShort, STR_OS_DEBIAN_4, distroShortSize); + } else if (strstr(distroLower, "5.0")) { + Str_Strcpy(distroShort, STR_OS_DEBIAN_5, distroShortSize); + } } else if (strstr(distroLower, "fedora")) { Str_Strcpy(distroShort, STR_OS_FEDORA, distroShortSize); } else if (strstr(distroLower, "gentoo")) { @@ -498,6 +577,7 @@ HostinfoReadDistroFile(char *filename, // IN: distro version file name if ((fd = open(filename, O_RDONLY)) < 0) { Warning("%s: could not open file%s: %d\n", __FUNCTION__, filename, errno); + return FALSE; } @@ -517,11 +597,13 @@ HostinfoReadDistroFile(char *filename, // IN: distro version file name if (distroOrig == NULL) { Warning("%s: could not allocate memory\n", __FUNCTION__); close(fd); + return FALSE; } if (read(fd, distroOrig, buf_sz) != buf_sz) { - Warning("%s: could not read file %s: %d\n", __FUNCTION__, filename, errno); + Warning("%s: could not read file %s: %d\n", __FUNCTION__, filename, + errno); goto out; } @@ -689,12 +771,14 @@ Hostinfo_GetOSName(uint32 outBufFullLen, // IN: length of osNameFull buffer if (uname(&buf) < 0) { Warning("%s: uname failed %d\n", __FUNCTION__, errno); + return FALSE; } if (strlen(buf.sysname) + strlen(buf.release) + 3 > outBufFullLen) { Warning("%s: Error: buffer too small\n", __FUNCTION__); + return FALSE; } @@ -731,8 +815,7 @@ Hostinfo_GetOSName(uint32 outBufFullLen, // IN: length of osNameFull buffer } /* - * Try to get OS detailed information - * from the lsb_release command. + * Try to get OS detailed information from the lsb_release command. */ lsbOutput = HostinfoGetCmdOutput(lsbCmd); @@ -756,13 +839,14 @@ Hostinfo_GetOSName(uint32 outBufFullLen, // IN: length of osNameFull buffer if (distroArray[i].filename == NULL) { Warning("%s: Error: no distro file found\n", __FUNCTION__); + return FALSE; } } else { char *lsbStart = lsbOutput; char *quoteEnd = NULL; - if (lsbStart[0] == '"') { + if (lsbStart[1] == '"') { lsbStart++; quoteEnd = strchr(lsbStart, '"'); if (quoteEnd) { @@ -777,6 +861,7 @@ Hostinfo_GetOSName(uint32 outBufFullLen, // IN: length of osNameFull buffer if (strlen(distro) + strlen(osNameFull) + 2 > outBufFullLen) { Warning("%s: Error: buffer too small\n", __FUNCTION__); + return FALSE; } @@ -785,6 +870,7 @@ Hostinfo_GetOSName(uint32 outBufFullLen, // IN: length of osNameFull buffer if (strlen(distroShort) + 1 > outBufLen) { Warning("%s: Error: buffer too small\n", __FUNCTION__); + return FALSE; } @@ -806,7 +892,8 @@ Hostinfo_GetOSName(uint32 outBufFullLen, // IN: length of osNameFull buffer } if (nameLen + releaseLen + 1 > outBufLen) { - Warning("GuestInfoGetOSName: Error: buffer too small\n"); + Warning("%s: Error: buffer too small\n", __FUNCTION__); + return FALSE; } @@ -827,7 +914,8 @@ Hostinfo_GetOSName(uint32 outBufFullLen, // IN: length of osNameFull buffer } if (nameLen + releaseLen + 1 > outBufLen) { - Warning("GuestInfoGetOSName: Error: buffer too small\n"); + Warning("%s: Error: buffer too small\n", __FUNCTION__); + return FALSE; } @@ -837,14 +925,14 @@ Hostinfo_GetOSName(uint32 outBufFullLen, // IN: length of osNameFull buffer if (Hostinfo_GetSystemBitness() == 64) { if (strlen(osName) + sizeof STR_OS_64BIT_SUFFIX > outBufLen) { Warning("%s: Error: buffer too small\n", __FUNCTION__); + return FALSE; } Str_Strcat(osName, STR_OS_64BIT_SUFFIX, outBufLen); } /* - * Before returning, truncate - * the \n character at the end of the full name. + * Before returning, truncate the \n character at the end of the full name. */ lastCharPos = strlen(osNameFull) - 1; @@ -855,3 +943,1409 @@ Hostinfo_GetOSName(uint32 outBufFullLen, // IN: length of osNameFull buffer return TRUE; } + +#if defined(VMX86_SERVER) +/* + *---------------------------------------------------------------------- + * + * HostinfoReadProc -- + * + * Depending on what string is passed to it, this function parses the + * /proc/vmware/sched/ncpus node and returns the requested value. + * + * Results: + * A postive value on success, -1 (0xFFFFFFFF) on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static uint32 +HostinfoReadProc(const char *str) // IN: +{ + /* XXX this should use sysinfo!! (bug 59849) + */ + FILE *f; + char *line; + uint32 count; + + ASSERT(!strcmp("logical", str) || !strcmp("cores", str) || + !strcmp("packages", str)); + + ASSERT(!HostType_OSIsVMK()); // Don't use /proc/vmware + + f = Posix_Fopen("/proc/vmware/sched/ncpus", "r"); + + if (f != NULL) { + while (StdIO_ReadNextLine(f, &line, 0, NULL) == StdIO_Success) { + if (strstr(line, str)) { + if (sscanf(line, "%d ", &count) == 1) { + free(line); + break; + } + } + free(line); + } + fclose(f); + + if (count > 0) { + return count; + } + } + + return -1; +} + + +/* + *---------------------------------------------------------------------- + * + * Hostinfo_HTDisabled -- + * + * Figure out if hyperthreading is enabled + * + * Results: + * TRUE if hyperthreading is disabled, FALSE otherwise + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Bool +Hostinfo_HTDisabled(void) +{ + static uint32 logical = 0, cores = 0; + + if (HostType_OSIsVMK()) { + VMK_ReturnStatus status = VMKernel_HTEnabledCPU(); + if (status != VMK_OK) { + return TRUE; + } else { + return FALSE; + } + } + + if (logical == 0 && cores == 0) { + logical = HostinfoReadProc("logical"); + cores = HostinfoReadProc("cores"); + if (logical <= 0 || cores <= 0) { + logical = cores = 0; + } + } + + return logical == cores; +} +#endif /*ifdef VMX86_SERVER*/ + + +/* + *----------------------------------------------------------------------------- + * + * Hostinfo_NumCPUs -- + * + * Get the number of logical CPUs on the host. If the CPUs are + * hyperthread-capable, this number may be larger than the number of + * physical CPUs. For example, if the host has four hyperthreaded + * physical CPUs with 2 logical CPUs apiece, this function returns 8. + * + * This function returns the number of CPUs that the host presents to + * applications, which is what we want in the vast majority of cases. We + * would only ever care about the number of physical CPUs for licensing + * purposes. + * + * Results: + * On success, the number of CPUs (> 0) the host tells us we have. + * On failure, 0xFFFFFFFF (-1). + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +uint32 +Hostinfo_NumCPUs(void) +{ +#if defined(__APPLE__) + uint32 out; + size_t outSize = sizeof out; + + /* + * Quoting sys/sysctl.h: + * " + * These are the support HW selectors for sysctlbyname. Parameters that + * are byte counts or frequencies are 64 bit numbers. All other parameters + * are 32 bit numbers. + * ... + * hw.activecpu - The number of processors currently available for executing + * threads. Use this number to determine the number threads + * to create in SMP aware applications. This number can + * change when power management modes are changed. + * " + * + * Apparently the only way to retrieve this info is by name, and I have + * verified the info changes when you dynamically switch a CPU + * offline/online. --hpreg + */ + + if (sysctlbyname("hw.activecpu", &out, &outSize, NULL, 0) == -1) { + return -1; + } + + return out; +#elif defined(__FreeBSD__) + uint32 out; + size_t outSize = sizeof out; + +#if __FreeBSD__version >= 500019 + if (sysctlbyname("kern.smp.cpus", &out, &outSize, NULL, 0) == -1) { + return -1; + } +#else + if (sysctlbyname("machdep.smp_cpus", &out, &outSize, NULL, 0) == -1) { + if (errno == ENOENT) { + out = 1; + } else { + return -1; + } + } +#endif + + return out; +#else + static int count = 0; + + if (count <= 0) { +#if defined(VMX86_SERVER) + if (HostType_OSIsVMK()) { + VMK_ReturnStatus status = VMKernel_GetNumCPUsUsed(&count); + + if (status != VMK_OK) { + count = 0; + + return -1; + } + } else { + count = HostinfoReadProc("logical"); + + if (count <= 0) { + count = 0; + + return -1; + } + } +#else /* ifdef VMX86_SERVER */ + FILE *f; + char *line; + + f = Posix_Fopen("/proc/cpuinfo", "r"); + if (f == NULL) { + return -1; + } + + while (StdIO_ReadNextLine(f, &line, 0, NULL) == StdIO_Success) { + if (strncmp(line, "processor", strlen("processor")) == 0) { + count++; + } + free(line); + } + + fclose(f); + + if (count == 0) { + return -1; + } +#endif /* ifdef VMX86_SERVER */ + } + + return count; +#endif +} + + +/* + *---------------------------------------------------------------------- + * + * Hostinfo_OSIsSMP -- + * + * Host OS SMP capability. + * + * Results: + * TRUE is host OS is SMP capable. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Bool +Hostinfo_OSIsSMP(void) +{ + uint32 ncpu; + +#if defined(__APPLE__) + size_t ncpuSize = sizeof ncpu; + + if (sysctlbyname("hw.ncpu", &ncpu, &ncpuSize, NULL, 0) == -1) { + return FALSE; + } + +#else + ncpu = Hostinfo_NumCPUs(); + + if (ncpu == 0xFFFFFFFF) { + return FALSE; + } +#endif + + return ncpu > 1 ? TRUE : FALSE; +} + + +/* + *----------------------------------------------------------------------------- + * + * Hostinfo_NameGet -- + * + * Return the fully qualified host name of the host. + * Thread-safe. --hpreg + * + * Results: + * The (memorized) name on success + * NULL on failure + * + * Side effects: + * A host name resolution can occur. + * + *----------------------------------------------------------------------------- + */ + +Unicode +Hostinfo_NameGet(void) +{ + Unicode result; + + static Atomic_Ptr state; /* Implicitly initialized to NULL. --hpreg */ + + result = Atomic_ReadPtr(&state); + + if (UNLIKELY(result == NULL)) { + Unicode before; + + result = Hostinfo_HostName(); + + before = Atomic_ReadIfEqualWritePtr(&state, NULL, result); + + if (before) { + Unicode_Free(result); + + result = before; + } + } + + return result; +} + + +/* + *----------------------------------------------------------------------------- + * + * Hostinfo_GetUser -- + * + * Return current user name, or NULL if can't tell. + * XXX Not thread-safe (somebody could do a setenv()). --hpreg + * + * Results: + * User name. Must be free()d by caller. + * + * Side effects: + * No. + * + *----------------------------------------------------------------------------- + */ + +Unicode +Hostinfo_GetUser(void) +{ + char buffer[BUFSIZ]; + struct passwd pw; + struct passwd *ppw = &pw; + Unicode env = NULL; + Unicode name = NULL; + + if ((Posix_Getpwuid_r(getuid(), &pw, buffer, sizeof buffer, &ppw) == 0) && + (ppw != NULL)) { + if (ppw->pw_name) { + name = Unicode_Duplicate(ppw->pw_name); + } + } + + if (!name) { + env = Posix_Getenv("USER"); + + if (env) { + name = Unicode_Duplicate(env); + } + } + + return name; +} + + +/* + *----------------------------------------------------------------------------- + * + * HostinfoGetLoadAverage -- + * + * Returns system average load. + * + * Results: + * TRUE on success, FALSE otherwise. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static Bool +HostinfoGetLoadAverage(float *avg0, // IN/OUT: + float *avg1, // IN/OUT: + float *avg2) // IN/OUT: +{ + /* getloadavg(3) was introduced with glibc 2.2 */ +#if defined(GLIBC_VERSION_22) || defined(__APPLE__) + double avg[3]; + int res; + + res = getloadavg(avg, 3); + if (res < 3) { + NOT_TESTED_ONCE(); + return FALSE; + } + + if (avg0) { + *avg0 = (float) avg[0]; + } + if (avg1) { + *avg1 = (float) avg[1]; + } + if (avg2) { + *avg2 = (float) avg[2]; + } + + return TRUE; +#else + /* + * Not implemented. This function is currently only used in the vmx, so + * getloadavg is always available to us. If the linux tools ever need this, + * we can go back to having a look at the output of /proc/loadavg, but + * let's not do that now as long as it's not necessary. + */ + + NOT_IMPLEMENTED(); + + return FALSE; +#endif +} + + +/* + *----------------------------------------------------------------------------- + * + * Hostinfo_GetLoadAverage -- + * + * Returns system average load * 100. + * + * Results: + * TRUE/FALSE + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +Bool +Hostinfo_GetLoadAverage(uint32 *avg) // IN/OUT: +{ + float avg0 = 0; + + if (!HostinfoGetLoadAverage(&avg0, NULL, NULL)) { + return FALSE; + } + + *avg = (uint32) 100 * avg0; + + return TRUE; +} + + +/* + *----------------------------------------------------------------------------- + * + * Hostinfo_LogLoadAverage -- + * + * Logs system average load. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +void +Hostinfo_LogLoadAverage(void) +{ + float avg0 = 0, avg1 = 0, avg2 = 0; + + if (HostinfoGetLoadAverage(&avg0, &avg1, &avg2)) { + Log("LOADAVG: %.2f %.2f %.2f\n", avg0, avg1, avg2); + } +} + + +#if defined(__APPLE__) +/* + *----------------------------------------------------------------------------- + * + * HostinfoMacAbsTimeNS -- + * + * Return the Mac OS absolute time. + * + * Results: + * The absolute time in nanoseconds is returned. This time is documented + * to NEVER go backwards. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static inline VmTimeType +HostinfoMacAbsTimeNS(void) +{ + VmTimeType raw; + mach_timebase_info_data_t *ptr; + static Atomic_Ptr atomic; /* Implicitly initialized to NULL. --mbellon */ + + /* Insure that the time base values are correct. */ + ptr = (mach_timebase_info_data_t *) Atomic_ReadPtr(&atomic); + + if (ptr == NULL) { + char *p; + + p = Util_SafeMalloc(sizeof(mach_timebase_info_data_t)); + + mach_timebase_info((mach_timebase_info_data_t *) p); + + if (Atomic_ReadIfEqualWritePtr(&atomic, NULL, p)) { + free(p); + } + + ptr = (mach_timebase_info_data_t *) Atomic_ReadPtr(&atomic); + } + + raw = mach_absolute_time(); + + if ((ptr->numer == 1) && (ptr->denom == 1)) { + /* The scaling values are unity, save some time/arithmetic */ + return raw; + } else { + /* The scaling values are not unity. Prevent overflow when scaling */ + return ((double) raw) * (((double) ptr->numer) / ((double) ptr->denom)); + } +} +#endif + + +/* + *----------------------------------------------------------------------------- + * + * HostinfoRawSystemTimerUS -- + * + * Obtain the raw system timer value. + * + * Results: + * Relative time in microseconds or zero if a failure. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +VmTimeType +Hostinfo_RawSystemTimerUS(void) +{ +#if defined(__APPLE__) + return HostinfoMacAbsTimeNS() / 1000ULL; +#else +#if defined(VMX86_SERVER) + if (HostType_OSIsPureVMK()) { + uint64 uptime; + VMK_ReturnStatus status; + + status = VMKernel_GetUptimeUS(&uptime); + if (status != VMK_OK) { + Log("%s: failure!\n", __FUNCTION__); + return 0; // A timer read failure - this is really bad! + } + + return uptime; + } else { +#endif /* ifdef VMX86_SERVER */ + struct timeval tval; + + /* Read the time from the operating system */ + if (gettimeofday(&tval, NULL) != 0) { + Log("%s: failure!\n", __FUNCTION__); + + return 0; // A timer read failure - this is really bad! + } + + /* Convert into microseconds */ + return (((VmTimeType)tval.tv_sec) * 1000000 + tval.tv_usec); +#if defined(VMX86_SERVER) + } +#endif /* ifdef VMX86_SERVER */ +#endif /* ifdef __APPLE__ */ +} + + +/* + *----------------------------------------------------------------------------- + * + * Hostinfo_LogMemUsage -- + * Log system memory usage. + * + * Results: + * System memory usage is logged. + * + * Side effects: + * No. + * + *----------------------------------------------------------------------------- + */ + +void +Hostinfo_LogMemUsage(void) +{ + int fd = Posix_Open("/proc/self/statm", O_RDONLY); + + if (fd != -1) { + size_t len; + char buf[64]; + + len = read(fd, buf, sizeof buf); + close(fd); + + if (len != -1) { + int a[7] = { 0 }; + + buf[len < sizeof buf ? len : sizeof buf - 1] = '\0'; + + sscanf(buf, "%d %d %d %d %d %d %d", + &a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6]); + + Log("RUSAGE size=%d resident=%d share=%d trs=%d lrs=%d drs=%d dt=%d\n", + a[0], a[1], a[2], a[3], a[4], a[5], a[6]); + } + } +} + + +/* + *---------------------------------------------------------------------- + * + * Hostinfo_TouchBackDoor -- + * + * Access the backdoor. This is used to determine if we are + * running in a VM or on a physical host. On a physical host + * this should generate a GP which we catch and thereby determine + * that we are not in a VM. However some OSes do not handle the + * GP correctly and the process continues running returning garbage. + * In this case we check the EBX register which should be + * BDOOR_MAGIC if the IN was handled in a VM. Based on this we + * return either TRUE or FALSE. + * + * Results: + * TRUE if we succesfully accessed the backdoor, FALSE or segfault + * if not. + * + * Side effects: + * Exception if not in a VM. + * + *---------------------------------------------------------------------- + */ + +Bool +Hostinfo_TouchBackDoor(void) +{ + /* + * XXX: This can cause Apple's Crash Reporter to erroneously display + * a crash, even though the process has caught the SIGILL and handled + * it. + * + * It's also annoying in gdb, so we'll turn it off in devel builds. + */ + +#if !defined(__APPLE__) && !defined(VMX86_DEVEL) + uint32 eax; + uint32 ebx; + uint32 ecx; + + __asm__ __volatile__( +# if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler. + "xchgl %%ebx, %1" "\n\t" + "inl %%dx, %%eax" "\n\t" + "xchgl %%ebx, %1" + : "=a" (eax), + "=&rm" (ebx), +# else + "inl %%dx, %%eax" + : "=a" (eax), + "=b" (ebx), +# endif + "=c" (ecx) + : "0" (BDOOR_MAGIC), + "1" (~BDOOR_MAGIC), + "2" (BDOOR_CMD_GETVERSION), + "d" (BDOOR_PORT) + ); + if (ebx == BDOOR_MAGIC) { + return TRUE; + } +#endif + return FALSE; +} + + +/* + *---------------------------------------------------------------------- + * + * Hostinfo_ResetProcessState -- + * + * Clean up signal handlers and file descriptors before an exec(). + * Fds which need to be kept open can be passed as an array. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +Hostinfo_ResetProcessState(const int *keepFds, // IN: + size_t numKeepFds) // 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. + * Otherwise, the process may still receive timer signals: + * SIGALRM, SIGVTARLM, or SIGPROF. + */ + + struct itimerval it; + it.it_value.tv_sec = it.it_value.tv_usec = 0; + it.it_interval.tv_sec = it.it_interval.tv_usec = 0; + setitimer(ITIMER_REAL, &it, NULL); + setitimer(ITIMER_VIRTUAL, &it, NULL); + setitimer(ITIMER_PROF, &it, NULL); + + for (s = 1; s <= NSIG; s++) { + sa.sa_handler = SIG_DFL; + sigfillset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sigaction(s, &sa, NULL); + } + + for (fd = (int) sysconf(_SC_OPEN_MAX) - 1; fd > STDERR_FILENO; fd--) { + size_t i; + + for (i = 0; i < numKeepFds; i++) { + if (fd == keepFds[i]) { + break; + } + } + if (i == numKeepFds) { + (void) close(fd); + } + } + + if (getrlimit(RLIMIT_AS, &rlim) == 0) { + rlim.rlim_cur = rlim.rlim_max; + setrlimit(RLIMIT_AS, &rlim); + } + +#ifdef __linux__ + /* + * Drop iopl to its default value. + */ + 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 +} + + +/* + *----------------------------------------------------------------------------- + * + * Hostinfo_Daemonize -- + * + * Cross-platform daemon(3)-like wrapper. + * + * Restarts the current process as a daemon, given the path to the + * process (usually from Hostinfo_GetModulePath). This means: + * + * * You're detached from your parent. (Your parent doesn't + * need to wait for you to exit.) + * * Your process no longer has a controlling terminal or + * process group. + * * Your stdin/stdout/stderr fds are redirected to /dev/null. All + * other descriptors, except for the ones that are passed in the + * parameter keepFds, are closed. + * * Your signal handlers are reset to SIG_DFL in the daemonized + * process, and all the signals are unblocked. + * * Your main() function is called with the specified NULL-terminated + * argument list. + * + * (Don't forget that the first string in args is argv[0] -- the + * name of the process). + * + * Unless 'flags' contains HOSTINFO_DAEMONIZE_NOCHDIR, then the + * current directory of the daemon process is set to "/". + * + * Unless 'flags' contains HOSTINFO_DAEMONIZE_NOCLOSE, then all stdio + * file descriptors of the daemon process are redirected to /dev/null. + * This is true even if the stdio descriptors are included in keepFds, + * i.e. the list of fds to be kept open. + * + * If 'flags' contains HOSTINFO_DAEMONIZE_EXIT, then upon successful + * launch of the daemon, the original process will exit. + * + * If pidPath is non-NULL, then upon success, writes the PID + * (as a US-ASCII string followed by a newline) of the daemon + * process to that path. + * + * Results: + * FALSE if the process could not be daemonized. Err_Errno() contains + * the error on failure. + * TRUE if 'flags' does not contain HOSTINFO_DAEMONIZE_EXIT and + * the process was daemonized. + * Otherwise, if the process was daemonized, this function does + * not return, and flow continues from your own main() function. + * + * Side effects: + * The current process is restarted with the given arguments. + * The process state is reset (see Hostinfo_ResetProcessState). + * A new session is created (so the process has no controlling terminal). + * + *----------------------------------------------------------------------------- + */ + +Bool +Hostinfo_Daemonize(const char *path, // IN: NUL-terminated UTF-8 + // path to exec + char * const *args, // IN: NULL-terminated UTF-8 + // argv list + HostinfoDaemonizeFlags flags, // IN: flags + const char *pidPath, // IN/OPT: NUL-terminated + // UTF-8 path to write PID + const int *keepFds, // IN/OPT: array of fds to be + // kept open + size_t numKeepFds) // IN: number of fds in + // keepFds +{ + /* + * We use the double-fork method to make a background process whose + * parent is init instead of the original process. + * + * We do this instead of calling daemon(), because daemon() is + * deprecated on Mac OS 10.5 hosts, and calling it causes a compiler + * warning. + * + * We must exec() after forking, because Mac OS library frameworks + * depend on internal Mach ports, which are not correctly propagated + * across fork calls. exec'ing reinitializes the frameworks, which + * causes them to reopen their Mach ports. + */ + + int childPid; + int pipeFds[2] = { -1, -1 }; + uint32 err = EINVAL; + char *pathLocalEncoding = NULL; + char *pidPathLocalEncoding = NULL; + char **argsLocalEncoding = NULL; + int *tempFds = NULL; + sigset_t sig; + + ASSERT_ON_COMPILE(sizeof (errno) <= sizeof err); + ASSERT(args); + ASSERT(path); + ASSERT(numKeepFds == 0 || keepFds); + + if (pipe(pipeFds) == -1) { + err = Err_Errno(); + Warning("%s: Couldn't create pipe, error %u.\n", __FUNCTION__, err); + pipeFds[0] = pipeFds[1] = -1; + goto cleanup; + } + + numKeepFds++; + tempFds = malloc(sizeof tempFds[0] * numKeepFds); + if (!tempFds) { + err = Err_Errno(); + Warning("%s: Couldn't allocate memory, error %u.\n", __FUNCTION__, err); + goto cleanup; + } + tempFds[0] = pipeFds[1]; + if (keepFds) { + memcpy(tempFds + 1, keepFds, sizeof tempFds[0] * (numKeepFds - 1)); + } + + if (fcntl(pipeFds[1], F_SETFD, 1) == -1) { + err = Err_Errno(); + Warning("%s: Couldn't set close-on-exec for fd %d, error %u.\n", + __FUNCTION__, pipeFds[1], err); + goto cleanup; + } + + /* Convert the strings from UTF-8 before we fork. */ + pathLocalEncoding = Unicode_GetAllocBytes(path, STRING_ENCODING_DEFAULT); + if (!pathLocalEncoding) { + Warning("%s: Couldn't convert path [%s] to default encoding.\n", + __FUNCTION__, path); + goto cleanup; + } + + if (pidPath) { + pidPathLocalEncoding = Unicode_GetAllocBytes(pidPath, + STRING_ENCODING_DEFAULT); + + if (!pidPathLocalEncoding) { + Warning("%s: Couldn't convert path [%s] to default encoding.\n", + __FUNCTION__, pidPath); + goto cleanup; + } + } + + argsLocalEncoding = Unicode_GetAllocList(args, STRING_ENCODING_DEFAULT, -1); + if (!argsLocalEncoding) { + Warning("%s: Couldn't convert arguments to default encoding.\n", + __FUNCTION__); + goto cleanup; + } + + childPid = fork(); + + switch (childPid) { + case -1: + err = Err_Errno(); + Warning("%s: Couldn't fork first child, error %u.\n", __FUNCTION__, err); + goto cleanup; + case 0: + /* We're the first child. Continue on. */ + break; + default: + { + /* We're the original process. Check if the first child exited. */ + int status; + + close(pipeFds[1]); + waitpid(childPid, &status, 0); + if (WIFEXITED(status) && WEXITSTATUS(status) != EXIT_SUCCESS) { + Warning("%s: Child %d exited with error %d.\n", + __FUNCTION__, childPid, WEXITSTATUS(status)); + goto cleanup; + } else if (WIFSIGNALED(status)) { + Warning("%s: Child %d exited with signal %d.\n", + __FUNCTION__, childPid, WTERMSIG(status)); + goto cleanup; + } + + /* + * Check if the second child exec'ed successfully. If it had + * an error, it will write a uint32 errno to this pipe before + * exiting. Otherwise, its end of the pipe will be closed on + * exec and this call will fail as expected. + * The assumption is that we don't get a partial read. In case, + * it did happen, we can detect it by the number of bytes read. + */ + + while (TRUE) { + int res = read(pipeFds[0], &err, sizeof err); + + if (res > 0) { + Warning("%s: Child could not exec %s, read %d, error %u.\n", + __FUNCTION__, path, res, err); + goto cleanup; + } else if (res == -1 && errno == EINTR) { + continue; + } + break; + } + + err = 0; + goto cleanup; + } + } + + /* + * Close all fds except for the write end of the error pipe (which + * we've already set to close on successful exec), and the ones requested by + * the caller. Also reset the signal mask to unblock all signals. fork() + * clears pending signals. + */ + + Hostinfo_ResetProcessState(tempFds, numKeepFds); + free(tempFds); + tempFds = NULL; + sigfillset(&sig); + sigprocmask(SIG_UNBLOCK, &sig, NULL); + + if (!(flags & HOSTINFO_DAEMONIZE_NOCLOSE) && setsid() == -1) { + Warning("%s: Couldn't create new session, error %d.\n", + __FUNCTION__, Err_Errno()); + + _exit(EXIT_FAILURE); + } + + switch (fork()) { + case -1: + { + Warning("%s: Couldn't fork second child, error %d.\n", + __FUNCTION__, Err_Errno()); + + _exit(EXIT_FAILURE); + } + case 0: + // We're the second child. Continue on. + break; + default: + /* + * We're the first child. We don't need to exist any more. + * + * Exiting here causes the second child to be reparented to the + * init process, so the original process doesn't need to wait + * for the child we forked off. + */ + + _exit(EXIT_SUCCESS); + } + + /* + * We can't use our i18n wrappers for file manipulation at this + * point, since we've forked; internal library mutexes might be + * invalid. + */ + + if (!(flags & HOSTINFO_DAEMONIZE_NOCHDIR) && chdir("/") == -1) { + uint32 err = Err_Errno(); + + Warning("%s: Couldn't chdir to /, error %u.\n", __FUNCTION__, err); + + /* Let the original process know we failed to chdir. */ + if (write(pipeFds[1], &err, sizeof err) == -1) { + Warning("%s: Couldn't write to parent pipe: %u, original error: %u.\n", + __FUNCTION__, Err_Errno(), err); + } + _exit(EXIT_FAILURE); + } + + if (!(flags & HOSTINFO_DAEMONIZE_NOCLOSE)) { + int fd; + + fd = open(_PATH_DEVNULL, O_RDONLY); + if (fd != -1) { + dup2(fd, STDIN_FILENO); + close(fd); + } + + fd = open(_PATH_DEVNULL, O_WRONLY); + if (fd != -1) { + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + close(fd); + } + } + + if (pidPath) { + int64 pid; + char pidString[32]; + int pidStringLen; + int pidPathFd; + + ASSERT_ON_COMPILE(sizeof (pid_t) <= sizeof pid); + ASSERT(pidPathLocalEncoding); + + /* See above comment about how we can't use our i18n wrappers here. */ + pidPathFd = open(pidPathLocalEncoding, O_WRONLY|O_CREAT|O_TRUNC, 0644); + + if (pidPathFd == -1) { + err = Err_Errno(); + Warning("%s: Couldn't open PID path [%s], error %d.\n", + __FUNCTION__, pidPath, err); + + if (write(pipeFds[1], &err, sizeof err) == -1) { + Warning("%s: Couldn't write to parent pipe: %u, original " + "error: %u.\n", __FUNCTION__, Err_Errno(), err); + } + _exit(EXIT_FAILURE); + } + + pid = getpid(); + pidStringLen = Str_Sprintf(pidString, sizeof pidString, + "%"FMT64"d\n", pid); + if (pidStringLen <= 0) { + err = EINVAL; + + if (write(pipeFds[1], &err, sizeof err) == -1) { + Warning("%s: Couldn't write to parent pipe: %u, original " + "error: %u.\n", __FUNCTION__, Err_Errno(), err); + } + _exit(EXIT_FAILURE); + } + + if (write(pidPathFd, pidString, pidStringLen) != pidStringLen) { + err = Err_Errno(); + Warning("%s: Couldn't write PID to path [%s], error %d.\n", + __FUNCTION__, pidPath, err); + + if (write(pipeFds[1], &err, sizeof err) == -1) { + Warning("%s: Couldn't write to parent pipe: %u, original " + "error: %u.\n", __FUNCTION__, Err_Errno(), err); + } + _exit(EXIT_FAILURE); + } + + close(pidPathFd); + } + + if (execv(pathLocalEncoding, argsLocalEncoding) == -1) { + err = Err_Errno(); + Warning("%s: Couldn't exec %s, error %d.\n", __FUNCTION__, path, err); + + /* Let the original process know we failed to exec. */ + if (write(pipeFds[1], &err, sizeof err) == -1) { + Warning("Couldn't write to parent pipe: %u, original error: %u.\n", + Err_Errno(), err); + } + _exit(EXIT_FAILURE); + } + + NOT_REACHED(); + + cleanup: + free(tempFds); + + if (pipeFds[0] != -1) { + close(pipeFds[0]); + } + if (pipeFds[1] != -1) { + close(pipeFds[1]); + } + Util_FreeStringList(argsLocalEncoding, -1); + free(pidPathLocalEncoding); + free(pathLocalEncoding); + + if (err == 0) { + if (flags & HOSTINFO_DAEMONIZE_EXIT) { + _exit(EXIT_SUCCESS); + } + } else { + Err_SetErrno(err); + + if (pidPath) { + Posix_Unlink(pidPath); + } + } + + return (err == 0); +} + + +#if !defined(__APPLE__) && !defined(__FreeBSD__) +/* + *---------------------------------------------------------------------- + * + * HostinfoGetCpuInfo -- + * + * Get some attribute from /proc/cpuinfo for a given CPU + * + * Results: + * On success: Allocated, NUL-terminated attribute string. + * On failure: NULL. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static char * +HostinfoGetCpuInfo(int nCpu, // IN: + char *name) // IN: +{ + FILE *f; + char *line; + int cpu = 0; + char *value = NULL; + + f = Posix_Fopen("/proc/cpuinfo", "r"); + + if (f == NULL) { + Warning(LGPFX" %s: Unable to open /proc/cpuinfo\n", __FUNCTION__); + + return NULL; + } + + while (cpu <= nCpu && + StdIO_ReadNextLine(f, &line, 0, NULL) == StdIO_Success) { + char *s; + char *e; + + if ((s = strstr(line, name)) && + (s = strchr(s, ':'))) { + s++; + e = s + strlen(s); + + /* Skip leading and trailing while spaces */ + for (; s < e && isspace(*s); s++); + for (; s < e && isspace(e[-1]); e--); + *e = 0; + + /* Free previous value */ + free(value); + value = strdup(s); + ASSERT_MEM_ALLOC(value); + + cpu++; + } + free(line); + } + + fclose(f); + + return value; +} +#endif + + +/* + *----------------------------------------------------------------------------- + * + * Hostinfo_GetRatedCpuMhz -- + * + * Get the rated CPU speed of a given processor. + * Return value is in MHz. + * + * Results: + * TRUE on success, FALSE on failure + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +Bool +Hostinfo_GetRatedCpuMhz(int32 cpuNumber, // IN: + uint32 *mHz) // OUT: +{ +#if defined(__APPLE__) || defined(__FreeBSD__) + +# if defined(__APPLE__) +# define CPUMHZ_SYSCTL_NAME "hw.cpufrequency_max" +# elif __FreeBSD__version >= 50011 +# define CPUMHZ_SYSCTL_NAME "hw.clockrate" +# endif + +# if defined(CPUMHZ_SYSCTL_NAME) + uint32 hz; + size_t hzSize = sizeof hz; + + /* 'cpuNumber' is ignored: Intel Macs are always perfectly symetric. */ + + if (sysctlbyname(CPUMHZ_SYSCTL_NAME, &hz, &hzSize, NULL, 0) == -1) { + return FALSE; + } + + *mHz = hz / 1000000; + + return TRUE; +# else + return FALSE; +# endif +#else + float fMhz = 0; + char *readVal = HostinfoGetCpuInfo(cpuNumber, "cpu MHz"); + + if (readVal == NULL) { + return FALSE; + } + + if (sscanf(readVal, "%f", &fMhz) == 1) { + *mHz = (unsigned int)(fMhz + 0.5); + } + free(readVal); + + return TRUE; +#endif +} + + +/* + *----------------------------------------------------------------------------- + * + * Hostinfo_GetCpuDescription -- + * + * Get the descriptive name associated with a given CPU. + * + * Results: + * On success: Allocated, NUL-terminated string. + * On failure: NULL. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +char * +Hostinfo_GetCpuDescription(uint32 cpuNumber) // IN: +{ +#if defined(__APPLE__) || defined(__FreeBSD__) +# if defined(__APPLE__) +# define CPUDESC_SYSCTL_NAME "machdep.cpu.brand_string" +# else +# define CPUDESC_SYSCTL_NAME "hw.model" +# endif + + char *desc; + size_t descSize; + + /* 'cpuNumber' is ignored: Intel Macs are always perfectly symetric. */ + + if (sysctlbyname(CPUDESC_SYSCTL_NAME, NULL, &descSize, NULL, 0) == -1) { + return NULL; + } + + desc = malloc(descSize); + if (!desc) { + return NULL; + } + + if (sysctlbyname(CPUDESC_SYSCTL_NAME, desc, &descSize, NULL, 0) == -1) { + free(desc); + + return NULL; + } + + return desc; +#else +#ifdef VMX86_SERVER + if (HostType_OSIsVMK()) { + char mName[48]; + + /* VMKernel treats mName as an in/out parameter so terminate it. */ + mName[0] = '\0'; + if (VMKernel_GetCPUModelName(mName, cpuNumber, + sizeof(mName)) == VMK_OK) { + mName[sizeof(mName) - 1] = '\0'; + + return strdup(mName); + } + + return NULL; + } +#endif + + return HostinfoGetCpuInfo(cpuNumber, "model name"); +#endif +} + + +/* + *---------------------------------------------------------------------- + * + * Hostinfo_Execute -- + * + * Start program COMMAND. If WAIT is TRUE, wait for program + * to complete and return exit status. + * + * Results: + * Exit status of COMMAND. + * + * Side effects: + * Run a separate program. + * + *---------------------------------------------------------------------- + */ + +int +Hostinfo_Execute(const char *command, // IN: + char * const *args, // IN: + Bool wait) // IN: +{ + int pid; + int status; + + if (command == NULL) { + return 1; + } + + pid = fork(); + + if (pid == -1) { + return -1; + } + + if (pid == 0) { + Hostinfo_ResetProcessState(NULL, 0); + Posix_Execvp(command, args); + exit(127); + } + + if (wait) { + for (;;) { + if (waitpid(pid, &status, 0) == -1) { + if (errno == ECHILD) { + return 0; // This sucks. We really don't know. + } + if (errno != EINTR) { + return -1; + } + } else { + return status; + } + } + } else { + return 0; + } +} diff --git a/open-vm-tools/lib/netUtil/netUtilLinux.c b/open-vm-tools/lib/netUtil/netUtilLinux.c index 2b1816047..f1175cb8a 100644 --- a/open-vm-tools/lib/netUtil/netUtilLinux.c +++ b/open-vm-tools/lib/netUtil/netUtilLinux.c @@ -273,3 +273,161 @@ NetUtil_GetPrimaryNic(void) abort: return nicEntry; } + + +#if defined(linux) +# ifdef DUMMY_NETUTIL +/* + *----------------------------------------------------------------------------- + * + * NetUtil_GetIfIndex (dummy version) -- + * + * Given an interface name, return its index. + * + * Results: + * Returns a valid interface index on success or -1 on failure. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +int +NetUtil_GetIfIndex(const char *ifName) // IN: interface name +{ + NetUtilIfTableEntry *iterator; + int ifIndex = -1; + + ASSERT(netUtilIfTable != NULL); + + for (iterator = netUtilIfTable; iterator->ifName; iterator++) { + if (strcmp(iterator->ifName, ifName) == 0) { + ifIndex = iterator->ifIndex; + break; + } + } + + return ifIndex; +} + + +/* + *----------------------------------------------------------------------------- + * + * NetUtil_GetIfName (dummy version) -- + * + * Given an interface index, return its name. + * + * Results: + * Returns a valid interface name on success, NULL on failure. + * + * Side effects: + * Caller is responsible for freeing the returned string. + * + *----------------------------------------------------------------------------- + */ + +char * +NetUtil_GetIfName(int ifIndex) // IN: interface index +{ + NetUtilIfTableEntry *iterator; + char *ifName = NULL; + + ASSERT(netUtilIfTable != NULL); + + for (iterator = netUtilIfTable; iterator->ifName; iterator++) { + if (iterator->ifIndex == ifIndex) { + ifName = Util_SafeStrdup(iterator->ifName); + break; + } + } + + return ifName; +} + + +# else // ifdef DUMMY_NETUTIL +/* + *----------------------------------------------------------------------------- + * + * NetUtil_GetIfIndex -- + * + * Given an interface name, return its index. + * + * Results: + * Returns a valid interface index on success or -1 on failure. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +int +NetUtil_GetIfIndex(const char *ifName) // IN: interface name +{ + struct ifreq ifreq; + int fd = -1; + int ifIndex = -1; + + memset(&ifreq, 0, sizeof ifreq); + if (Str_Snprintf(ifreq.ifr_name, sizeof ifreq.ifr_name, "%s", ifName) == -1) { + return -1; + } + + if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { + return -1; + } + + if (ioctl(fd, SIOCGIFINDEX, &ifreq) == 0) { + ifIndex = ifreq.ifr_ifindex; + } + + close(fd); + + return ifIndex; +} + + +/* + *----------------------------------------------------------------------------- + * + * NetUtil_GetIfName -- + * + * Given an interface index, return its name. + * + * Results: + * Returns a valid interface name on success, NULL on failure. + * + * Side effects: + * Caller is responsible for freeing the returned string. + * + *----------------------------------------------------------------------------- + */ + +char * +NetUtil_GetIfName(int ifIndex) // IN: interface index +{ + struct ifreq ifreq; + char *ifName = NULL; + int fd = -1; + + memset(&ifreq, 0, sizeof ifreq); + ifreq.ifr_ifindex = ifIndex; + + if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { + return NULL; + } + + if (ioctl(fd, SIOCGIFNAME, &ifreq) == 0) { + ifName = Util_SafeStrdup(ifreq.ifr_name); + } + + close(fd); + + return ifName; +} +# endif // ifdef DUMMY_NETUTIL + +#endif // if defined(linux) diff --git a/open-vm-tools/lib/printer/printer.c b/open-vm-tools/lib/printer/printer.c index 140872551..d00ff7fc7 100644 --- a/open-vm-tools/lib/printer/printer.c +++ b/open-vm-tools/lib/printer/printer.c @@ -95,8 +95,9 @@ Printer_GetDefault(void) /* Make sure function has been loaded. */ if (!getDefaultPrinterFunc) { - Log("Printer_GetDefault: DLL not loaded\n"); + Log("%s: DLL not loaded\n", __FUNCTION__); ASSERT(FALSE); + return NULL; } @@ -104,27 +105,31 @@ Printer_GetDefault(void) success = getDefaultPrinterFunc(printerName, &bufSize); error = Err_Errno(); if (success) { - Log("Printer_GetDefault: Didn't fail with zero buffer\n"); + Log("%s: Didn't fail with zero buffer\n", __FUNCTION__); + return NULL; } if (error != ERROR_INSUFFICIENT_BUFFER) { - Log("Printer_GetDefault: Unexpected failure %d: %s\n", - error, Err_Errno2String(error)); + Log("%s: Unexpected failure %d: %s\n", error, + __FUNCTION__, Err_Errno2String(error)); + return NULL; } printerName = malloc(bufSize); if (!printerName) { - Log("Printer_GetDefault: Memory allocation failure\n"); + Log("%s: Memory allocation failure\n", __FUNCTION__); + return NULL; } success = getDefaultPrinterFunc(printerName, &bufSize); if (!success) { error = Err_Errno(); - Log("Printer_GetDefault: Failed to get default printer\n"); + Log("%s: Failed to get default printer\n", __FUNCTION__); free(printerName); + return NULL; } @@ -164,18 +169,21 @@ Printer_SetDefault(char const *printerName) // IN /* Make sure function has been loaded. */ if (!setDefaultPrinterFunc) { - Log("Printer_SetDefault: DLL not loaded\n"); + Log("%s: DLL not loaded\n", __FUNCTION__); ASSERT(FALSE); + return FALSE; } /* * Attempt to set the default printer. */ + if (!setDefaultPrinterFunc(printerName)) { error = Err_Errno(); - Log("Printer_SetDefault: Unable to SetDefaultPrinter %d: %s\n", + Log("%s: Unable to SetDefaultPrinter %d: %s\n", __FUNCTION__, error, Err_Errno2String(error)); + return FALSE; } @@ -223,7 +231,7 @@ Printer_AddConnection(char *printerName, // IN: Name of printer to add /* Make sure function has been loaded. */ if (!addPrinterConnectionFunc) { - Log("Printer_AddConnection: DLL not loaded\n"); + Log("%s: DLL not loaded\n", __FUNCTION__); ASSERT(FALSE); return FALSE; } @@ -231,16 +239,18 @@ Printer_AddConnection(char *printerName, // IN: Name of printer to add /* Try to add the printer. */ if (!addPrinterConnectionFunc((LPSTR)printerName)) { error = Err_Errno(); - Log("Printer_AddConnection: Failed to add printer %s : %d %s\n", + Log("%s: Failed to add printer %s : %d %s\n", __FUNCTION__, printerName, error, Err_Errno2String(error)); success = FALSE; } *sysError = error; + return success; #else NOT_IMPLEMENTED(); + return FALSE; #endif } @@ -278,16 +288,17 @@ Printer_Init(void) winspoolDll = Win32U_LoadLibrary("Winspool.drv"); if (!winspoolDll) { error = Err_Errno(); - Log("Printer_Init: Failed to load Winspool.drv %d: %s\n", + Log("%s: Failed to load Winspool.drv %d: %s\n", __FUNCTION__, error, Err_Errno2String(error)); - Log("Printer_Init: Trying to load Winspool as Winspool.dll...\n"); + Log("%s: Trying to load Winspool as Winspool.dll...\n", __FUNCTION__); winspoolDll = Win32U_LoadLibrary("Winspool"); if (!winspoolDll) { error = Err_Errno(); - Log("Printer_Init: Failed to load Winspool.dll %d: %s\n", + Log("%s: Failed to load Winspool.dll %d: %s\n", __FUNCTION__, error, Err_Errno2String(error)); Log("Unable to load Winspool, giving up.\n"); + return FALSE; } } @@ -297,7 +308,7 @@ Printer_Init(void) "GetDefaultPrinterA"); if (!getDefaultPrinterFunc) { error = Err_Errno(); - Log("Printer_Init: Failed to load GetDefaultPrinter %d: %s\n", + Log("%s: Failed to load GetDefaultPrinter %d: %s\n", __FUNCTION__, error, Err_Errno2String(error)); goto error; } @@ -306,7 +317,7 @@ Printer_Init(void) "SetDefaultPrinterA"); if (!setDefaultPrinterFunc) { error = Err_Errno(); - Log("Printer_Init: Failed to load SetDefaultPrinter %d: %s\n", + Log("%s: Failed to load SetDefaultPrinter %d: %s\n", __FUNCTION__, error, Err_Errno2String(error)); goto error; } @@ -315,7 +326,7 @@ Printer_Init(void) "AddPrinterConnectionA"); if (!addPrinterConnectionFunc) { error = Err_Errno(); - Log("Printer_Init: Failed to load AddPrinterConnection %d: %s\n", + Log("%s: Failed to load AddPrinterConnection %d: %s\n", __FUNCTION__, error, Err_Errno2String(error)); goto error; } @@ -359,7 +370,8 @@ Printer_Cleanup(void) DWORD error; if (!winspoolDll) { - Log("Printer_Cleanup: Printer library not loaded.\n"); + Log("%s: Printer library not loaded.\n", __FUNCTION__); + return FALSE; } @@ -369,13 +381,15 @@ Printer_Cleanup(void) if (!FreeLibrary(winspoolDll)) { error = Err_Errno(); - Log("Printer_Cleanup: Failed to FreeLibrary %d: %s\n", + Log("%s: Failed to FreeLibrary %d: %s\n", __FUNCTION__, error, Err_Errno2String(error)); winspoolDll = NULL; + return FALSE; } winspoolDll = NULL; + return TRUE; #else diff --git a/open-vm-tools/lib/raster/rasterConv.c b/open-vm-tools/lib/raster/rasterConv.c index 880a7254d..a5e47465c 100644 --- a/open-vm-tools/lib/raster/rasterConv.c +++ b/open-vm-tools/lib/raster/rasterConv.c @@ -78,11 +78,11 @@ static const uint8 byte_masks_8bgr[9][3] = { */ static void RasterConvert15to16(uint8 *tof, uint32 line_increment, - uint8 *src, uint32 src_increment, + const uint8 *src, uint32 src_increment, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h); static void RasterConvertShortTo24(uint8 *tof, uint32 line_increment, - uint8 *src, uint32 src_increment, + const uint8 *src, uint32 src_increment, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h, uint32 redMask, uint32 greenMask, @@ -91,7 +91,7 @@ static void RasterConvertShortTo24(uint8 *tof, uint32 line_increment, uint32 greenShift1, uint32 greenShift2, uint32 blueShift1, uint32 blueShift2); static void RasterConvertShortTo32(uint8 *tof, uint32 line_increment, - uint8 *src, uint32 src_increment, + const uint8 *src, uint32 src_increment, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h, uint32 redMask, uint32 greenMask, @@ -100,11 +100,11 @@ static void RasterConvertShortTo32(uint8 *tof, uint32 line_increment, uint32 greenShift1, uint32 greenShift2, uint32 blueShift1, uint32 blueShift2); static void RasterConvert16to15(uint8 *tof, uint32 line_increment, - uint8 *src, uint32 src_increment, + const uint8 *src, uint32 src_increment, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h); static void RasterConvert24toShort(uint8 *tof, uint32 line_increment, - uint8 *src, uint32 src_increment, + const uint8 *src, uint32 src_increment, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h, uint32 redMask, uint32 greenMask, @@ -112,11 +112,11 @@ static void RasterConvert24toShort(uint8 *tof, uint32 line_increment, uint32 redShift, uint32 greenShift, uint32 blueShift); static void RasterConvert24to32(uint8 *tof, uint32 line_increment, - uint8 *src, uint32 src_increment, + const uint8 *src, uint32 src_increment, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h); static void RasterConvert32toShort(uint8 *tof, uint32 line_increment, - uint8 *src, uint32 src_increment, + const uint8 *src, uint32 src_increment, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h, uint32 redMask, uint32 greenMask, @@ -124,12 +124,12 @@ static void RasterConvert32toShort(uint8 *tof, uint32 line_increment, uint32 redShift, uint32 greenShift, uint32 blueShift); static void RasterConvert32to24(uint8 *tof, uint32 line_increment, - uint8 *src, uint32 src_increment, + const uint8 *src, uint32 src_increment, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h); static void RasterConvertIndextoShort(uint8 *tof, uint32 line_increment, - uint8 *src, uint32 src_increment, - uint32 *pixels, + const uint8 *src, uint32 src_increment, + const uint32 *pixels, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h, uint32 redMask, uint32 greenMask, @@ -137,36 +137,37 @@ static void RasterConvertIndextoShort(uint8 *tof, uint32 line_increment, uint32 redShift, uint32 greenShift, uint32 blueShift); static void RasterConvertIndexto24(uint8 *tof, uint32 line_increment, - uint8 *src, uint32 src_increment, - uint32 *pixels, + const uint8 *src, uint32 src_increment, + const uint32 *pixels, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h); static void RasterConvertIndexto32(uint8 *tof, uint32 line_increment, - uint8 *src, uint32 src_increment, - uint32 *pixels, + const uint8 *src, uint32 src_increment, + const uint32 *pixels, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h); static void RasterConvert32to8(uint8 *tof, uint32 line_increment, - uint8 *src, uint32 src_increment, + const uint8 *src, uint32 src_increment, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h, uint32 redMask, uint32 greenMask, uint32 blueMask, uint32 redShift, uint32 greenShift, uint32 blueShift); static void RasterConvert24to8(uint8 *tof, uint32 line_increment, - uint8 *src, uint32 src_increment, + const uint8 *src, uint32 src_increment, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h, uint32 redMask, uint32 greenMask, uint32 blueMask, uint32 redShift, uint32 greenShift, uint32 blueShift); static void RasterConvert16to8(uint8 *tof, uint32 line_increment, - uint8 *src, uint32 src_increment, + const uint8 *src, uint32 src_increment, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h, uint32 redMask, uint32 greenMask, uint32 blueMask, int redShift, int greenShift, int blueShift); static void RasterConvertIndexto8(uint8 *tof, uint32 line_increment, - uint8 *src, uint32 src_increment, uint32 *pixels, + const uint8 *src, uint32 src_increment, + const uint32 *pixels, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h, uint32 redMask, uint32 greenMask, uint32 blueMask, @@ -263,12 +264,12 @@ Raster_GetBPPDepth(uint32 depth, uint32 bpp) void Raster_ConvertPixels(uint8 *tof, int32 line_increment, int bppdepth, - uint8 *src, int32 src_increment, int src_bppdepth, - Bool pseudoColor, uint32 *pixels, + const uint8 *src, int32 src_increment, int src_bppdepth, + Bool pseudoColor, const uint32 *pixels, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h) { - int redShift,greenShift, blueShift; + int redShift, greenShift, blueShift; if (pseudoColor) { if (src_bppdepth > 8) { @@ -539,7 +540,7 @@ Raster_ConvertPixels(uint8 *tof, int32 line_increment, int bppdepth, uint32 Raster_ConvertOnePixel(uint32 pix, int src_bppdepth, int bppdepth, - Bool pseudoColor, uint32 *pixels) + Bool pseudoColor, const uint32 *pixels) { if (pseudoColor) { if (src_bppdepth != 8) { @@ -659,8 +660,10 @@ Raster_ConvertOnePixel(uint32 pix, int src_bppdepth, int bppdepth, */ Bool -Raster_ConversionParameters(int bppdepth, uint32 *redMask, - uint32 *greenMask, uint32 *blueMask) +Raster_ConversionParameters(int bppdepth, // IN + uint32 *redMask, // OUT + uint32 *greenMask, // OUT + uint32 *blueMask) // OUT { switch (bppdepth) { case 15: @@ -714,11 +717,12 @@ Raster_ConversionParameters(int bppdepth, uint32 *redMask, static void RasterConvert15to16(uint8 *tof, uint32 line_increment, - uint8 *src, uint32 src_increment, + const uint8 *src, uint32 src_increment, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h) { - uint16 *srcptr, *dstptr; + const uint16 *srcptr; + uint16 *dstptr; int i, j; src_increment >>= 1; @@ -761,7 +765,7 @@ RasterConvert15to16(uint8 *tof, uint32 line_increment, static void RasterConvertShortTo24(uint8 *tof, uint32 line_increment, - uint8 *src, uint32 src_increment, + const uint8 *src, uint32 src_increment, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h, uint32 redMask, uint32 greenMask, uint32 blueMask, @@ -769,7 +773,7 @@ RasterConvertShortTo24(uint8 *tof, uint32 line_increment, uint32 greenShift1, uint32 greenShift2, uint32 blueShift1, uint32 blueShift2) { - uint16 *srcptr; + const uint16 *srcptr; uint8 *dstptr; int i, j, k; @@ -815,7 +819,7 @@ RasterConvertShortTo24(uint8 *tof, uint32 line_increment, static void RasterConvertShortTo32(uint8 *tof, uint32 line_increment, - uint8 *src, uint32 src_increment, + const uint8 *src, uint32 src_increment, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h, uint32 redMask, uint32 greenMask, uint32 blueMask, @@ -823,7 +827,7 @@ RasterConvertShortTo32(uint8 *tof, uint32 line_increment, uint32 greenShift1, uint32 greenShift2, uint32 blueShift1, uint32 blueShift2) { - uint16 *srcptr; + const uint16 *srcptr; uint32 *dstptr; int i, j; @@ -873,11 +877,12 @@ RasterConvertShortTo32(uint8 *tof, uint32 line_increment, static void RasterConvert16to15(uint8 *tof, uint32 line_increment, - uint8 *src, uint32 src_increment, + const uint8 *src, uint32 src_increment, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h) { - uint16 *srcptr, *dstptr; + const uint16 *srcptr; + uint16 *dstptr; int i, j; src_increment >>= 1; @@ -919,13 +924,13 @@ RasterConvert16to15(uint8 *tof, uint32 line_increment, static void RasterConvert24toShort(uint8 *tof, uint32 line_increment, - uint8 *src, uint32 src_increment, + const uint8 *src, uint32 src_increment, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h, uint32 redMask, uint32 greenMask, uint32 blueMask, uint32 redShift, uint32 greenShift, uint32 blueShift) { - uint8 *srcptr; + const uint8 *srcptr; uint16 *dstptr; int i, j, k; @@ -970,11 +975,11 @@ RasterConvert24toShort(uint8 *tof, uint32 line_increment, static void RasterConvert24to32(uint8 *tof, uint32 line_increment, - uint8 *src, uint32 src_increment, + const uint8 *src, uint32 src_increment, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h) { - uint8 *srcptr; + const uint8 *srcptr; uint32 *dstptr; int i, j, k; @@ -1019,13 +1024,13 @@ RasterConvert24to32(uint8 *tof, uint32 line_increment, static void RasterConvert32toShort(uint8 *tof, uint32 line_increment, - uint8 *src, uint32 src_increment, + const uint8 *src, uint32 src_increment, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h, uint32 redMask, uint32 greenMask, uint32 blueMask, uint32 redShift, uint32 greenShift, uint32 blueShift) { - uint32 *srcptr; + const uint32 *srcptr; uint16 *dstptr; int i, j; @@ -1069,11 +1074,11 @@ RasterConvert32toShort(uint8 *tof, uint32 line_increment, static void RasterConvert32to24(uint8 *tof, uint32 line_increment, - uint8 *src, uint32 src_increment, + const uint8 *src, uint32 src_increment, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h) { - uint32 *srcptr; + const uint32 *srcptr; uint8 *dstptr; int i, j, k; @@ -1117,13 +1122,13 @@ RasterConvert32to24(uint8 *tof, uint32 line_increment, static void RasterConvertIndexto8(uint8 *tof, uint32 line_increment, - uint8 *src, uint32 src_increment, uint32 *pixels, + const uint8 *src, uint32 src_increment, const uint32 *pixels, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h, uint32 redMask, uint32 greenMask, uint32 blueMask, uint32 redShift, uint32 greenShift, uint32 blueShift) { - uint8 *srcptr; + const uint8 *srcptr; uint8 *dstptr; int i, j; @@ -1165,13 +1170,13 @@ RasterConvertIndexto8(uint8 *tof, uint32 line_increment, static void RasterConvertIndextoShort(uint8 *tof, uint32 line_increment, - uint8 *src, uint32 src_increment, uint32 *pixels, + const uint8 *src, uint32 src_increment, const uint32 *pixels, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h, uint32 redMask, uint32 greenMask, uint32 blueMask, uint32 redShift, uint32 greenShift, uint32 blueShift) { - uint8 *srcptr; + const uint8 *srcptr; uint16 *dstptr; int i, j; @@ -1214,11 +1219,11 @@ RasterConvertIndextoShort(uint8 *tof, uint32 line_increment, static void RasterConvertIndexto24(uint8 *tof, uint32 line_increment, - uint8 *src, uint32 src_increment, uint32 *pixels, + const uint8 *src, uint32 src_increment, const uint32 *pixels, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h) { - uint8 *srcptr; + const uint8 *srcptr; uint8 *dstptr; int i, j, k; @@ -1260,11 +1265,11 @@ RasterConvertIndexto24(uint8 *tof, uint32 line_increment, static void RasterConvertIndexto32(uint8 *tof, uint32 line_increment, - uint8 *src, uint32 src_increment, uint32 *pixels, + const uint8 *src, uint32 src_increment, const uint32 *pixels, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h) { - uint8 *srcptr; + const uint8 *srcptr; uint32 *dstptr; int i, j; @@ -1306,13 +1311,13 @@ RasterConvertIndexto32(uint8 *tof, uint32 line_increment, static void RasterConvert32to8(uint8 *tof, uint32 line_increment, - uint8 *src, uint32 src_increment, + const uint8 *src, uint32 src_increment, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h, uint32 redMask, uint32 greenMask, uint32 blueMask, uint32 redShift, uint32 greenShift, uint32 blueShift) { - uint32 *srcptr; + const uint32 *srcptr; uint8 *dstptr; int i, j; @@ -1356,13 +1361,13 @@ RasterConvert32to8(uint8 *tof, uint32 line_increment, static void RasterConvert24to8(uint8 *tof, uint32 line_increment, - uint8 *src, uint32 src_increment, + const uint8 *src, uint32 src_increment, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h, uint32 redMask, uint32 greenMask, uint32 blueMask, uint32 redShift, uint32 greenShift, uint32 blueShift) { - uint8 *srcptr; + const uint8 *srcptr; uint8 *dstptr; int i, j, k; @@ -1410,13 +1415,13 @@ RasterConvert24to8(uint8 *tof, uint32 line_increment, static void RasterConvert16to8(uint8 *tof, uint32 line_increment, - uint8 *src, uint32 src_increment, + const uint8 *src, uint32 src_increment, uint32 src_x, uint32 src_y, uint32 x, uint32 y, uint32 w, uint32 h, uint32 redMask, uint32 greenMask, uint32 blueMask, int redShift, int greenShift, int blueShift) { - uint16 *srcptr; + const uint16 *srcptr; uint8 *dstptr; int i, j; diff --git a/open-vm-tools/lib/region/region.c b/open-vm-tools/lib/region/region.c index a146cdcf6..e32db817c 100644 --- a/open-vm-tools/lib/region/region.c +++ b/open-vm-tools/lib/region/region.c @@ -110,6 +110,7 @@ Equipment Corporation. #include #include +#include #include "region.h" @@ -2569,6 +2570,16 @@ miTranslateRegion( register int x, register int y) { + /* + * This check is here to validate the fix for bug 357509. R_MINSHORT was + * defined incorrectly. I changed it to SHRT_MIN, but that introduced the + * possibility of a comparison in miTranslateRegionByBoundary underflowing. + * miTranslateRegionByBoundary currently uses ints, so it won't underflow + * as long as the range of int is larger than the range of short. + * This assert checks that that is indeed the case. + */ + ASSERT_ON_COMPILE(INT_MIN < SHRT_MIN); + miTranslateRegionByBoundary(pReg, x, y, R_MINSHORT, R_MAXSHORT); } diff --git a/open-vm-tools/lib/string/str.c b/open-vm-tools/lib/string/str.c index 0e41037c7..801d1dadd 100644 --- a/open-vm-tools/lib/string/str.c +++ b/open-vm-tools/lib/string/str.c @@ -20,6 +20,18 @@ * str.c -- * * User level string wrappers + * + * WARNING: + * Do not call any variadic functions - those that use "..." repeatedly + * with the same va_list or memory corruption and/or crashes will occur. + * The suggested way deal with repeated calls is to use a va_copy: + * + * va_list tmpArgs; + * + * va_copy(tmpArgs, ap); + * // Call the variadic function + * va_end(tmpArgs); + * */ #ifdef _WIN32 @@ -119,15 +131,7 @@ Str_Sprintf(char *buf, // OUT * NB: on overflow the buffer WILL be null terminated at the last * UTF-8 code point boundary within the buffer's bounds. * - * WARNING: - * Do not call this function repeatedly with the same va_list - * or memory corruption and/or crashes will occur. The suggested - * way to deal with this: - * - * va_list tmpArgs; - * va_copy(tmpArgs, ap); - * // Call this function - * va_end(tmpArgs); + * WARNING: See warning at the top of this file. * * Side effects: * None @@ -516,15 +520,7 @@ Str_SafeAsprintf(size_t *length, // OUT * ASSERTs or returns NULL on failure, depending on the value of * 'assertOnFailure'. * - * WARNING: - * Do not call this function repeatedly with the same va_list - * or memory corruption and/or crashes will occur. The suggested - * way to deal with this: - * - * va_list tmpArgs; - * va_copy(tmpArgs, ap); - * // Call this function - * va_end(tmpArgs); + * WARNING: See warning at the top of this file. * * Side effects: * None @@ -607,19 +603,10 @@ StrVasprintfInternal(size_t *length, // OUT: * Results: * Returns NULL on failure. * - * WARNING: - * Do not call this function repeatedly with the same va_list - * or memory corruption and/or crashes will occur. The suggested - * way to deal with this: - * - * va_list tmpArgs; - * va_copy(tmpArgs, ap); - * // Call this function - * va_end(tmpArgs); + * WARNING: See warning at the top of this file. * * Side effects: * None - * *----------------------------------------------------------------------------- */ @@ -642,15 +629,7 @@ Str_Vasprintf(size_t *length, // OUT * Results: * Calls ASSERT_NOT_IMPLEMENTED on failure. * - * WARNING: - * Do not call this function repeatedly with the same va_list - * or memory corruption and/or crashes will occur. The suggested - * way to deal with this: - * - * va_list tmpArgs; - * va_copy(tmpArgs, ap); - * // Call this function - * va_end(tmpArgs); + * WARNING: See warning at the top of this file. * * Side effects: * None @@ -719,15 +698,7 @@ Str_Swprintf(wchar_t *buf, // OUT * * NB: on overflow the buffer WILL be null terminated * - * WARNING: - * Do not call this function repeatedly with the same va_list - * or memory corruption and/or crashes will occur. The suggested - * way to deal with this: - * - * va_list tmpArgs; - * va_copy(tmpArgs, ap); - * // Call this function - * va_end(tmpArgs); + * WARNING: See warning at the top of this file. * * Side effects: * None @@ -1026,15 +997,7 @@ Str_Mbscat(char *buf, // IN-OUT * ASSERTs or returns NULL on failure, depending on the value of * 'assertOnFailure'. * - * WARNING: - * Do not call this function repeatedly with the same va_list - * or memory corruption and/or crashes will occur. The suggested - * way to deal with this: - * - * va_list tmpArgs; - * va_copy(tmpArgs, ap); - * // Call this function - * va_end(tmpArgs); + * WARNING: See warning at the top of this file. * * Side effects: * None @@ -1137,15 +1100,7 @@ Str_Aswprintf(size_t *length, // OUT * Results: * Returns NULL on failure. * - * WARNING: - * Do not call this function repeatedly with the same va_list - * or memory corruption and/or crashes will occur. The suggested - * way to deal with this: - * - * va_list tmpArgs; - * va_copy(tmpArgs, ap); - * // Call this function - * va_end(tmpArgs); + * WARNING: See warning at the top of this file. * * Side effects: * None @@ -1204,15 +1159,7 @@ Str_SafeAswprintf(size_t *length, // OUT * Results: * Calls ASSERT_NOT_IMPLEMENTED on failure. * - * WARNING: - * Do not call this function repeatedly with the same va_list - * or memory corruption and/or crashes will occur. The suggested - * way to deal with this: - * - * va_list tmpArgs; - * va_copy(tmpArgs, ap); - * // Call this function - * va_end(tmpArgs); + * WARNING: See warning at the top of this file. * * Side effects: * None diff --git a/open-vm-tools/lib/sync/syncWaitQPosix.c b/open-vm-tools/lib/sync/syncWaitQPosix.c index d21c6a1e2..2a5c6def6 100644 --- a/open-vm-tools/lib/sync/syncWaitQPosix.c +++ b/open-vm-tools/lib/sync/syncWaitQPosix.c @@ -117,7 +117,6 @@ typedef union { static INLINE Bool SyncWaitQWakeUpNamed(SyncWaitQ *that); static INLINE Bool SyncWaitQWakeUpAnon(SyncWaitQ *that); -static INLINE char *SyncWaitQMakeName(const char *path, uint64 seq); #if __APPLE__ @@ -155,7 +154,7 @@ static Atomic_Int workaround = { WORKAROUND_UNKNOWN, }; */ static int -SyncWaitQInit(SyncWaitQ *that) // IN +SyncWaitQInit(SyncWaitQ *that) // IN: { if (UNLIKELY(Atomic_ReadInt(&workaround) == WORKAROUND_UNKNOWN)) { struct utsname u; @@ -165,6 +164,7 @@ SyncWaitQInit(SyncWaitQ *that) // IN * We purposedly do not use Hostinfo_OSVersion() to avoid introducing a * library dependency just for a workaround. */ + Atomic_ReadIfEqualWriteInt(&workaround, WORKAROUND_UNKNOWN, ( uname(&u) == -1 || sscanf(u.release, "%u.", &major) != 1 @@ -172,8 +172,9 @@ SyncWaitQInit(SyncWaitQ *that) // IN } ASSERT(Atomic_ReadInt(&workaround) != WORKAROUND_UNKNOWN); - return Atomic_ReadInt(&workaround) == WORKAROUND_YES - ? pthread_mutex_init(&that->mutex, NULL) : 0; + + return Atomic_ReadInt(&workaround) == WORKAROUND_YES ? + pthread_mutex_init(&that->mutex, NULL) : 0; } @@ -223,9 +224,10 @@ SyncWaitQLock(SyncWaitQ *that) // IN */ static void -SyncWaitQUnlock(SyncWaitQ *that) // IN +SyncWaitQUnlock(SyncWaitQ *that) // IN: { ASSERT(Atomic_ReadInt(&workaround) != WORKAROUND_UNKNOWN); + if (Atomic_ReadInt(&workaround) == WORKAROUND_YES) { int result; @@ -256,17 +258,17 @@ SyncWaitQUnlock(SyncWaitQ *that) // IN */ static void -SyncWaitQPanicOnFdLimit(int error) // IN +SyncWaitQPanicOnFdLimit(int error) // IN: { switch (error) { case EMFILE: - Panic("SyncWaitQ: Too many file descriptors are in use by the " - "process.\n"); + Panic("%s: Too many file descriptors are in use by the process.\n", + __FUNCTION__); break; case ENFILE: - Panic("SyncWaitQ: The system limit on the total number of open files " - "has been reached.\n"); + Panic("%s: The system limit on the total number of open files has " + "been reached.\n", __FUNCTION__); break; default: @@ -303,8 +305,8 @@ SyncWaitQPanicOnFdLimit(int error) // IN */ Bool -SyncWaitQ_Init(SyncWaitQ *that, // OUT - char const *path) // IN/OPT +SyncWaitQ_Init(SyncWaitQ *that, // OUT: + char const *path) // IN/OPT: { ASSERT(that); ASSERT(!path || path[0]); @@ -349,6 +351,25 @@ SyncWaitQ_Init(SyncWaitQ *that, // OUT } +/* + *---------------------------------------------------------------------- + * + * SyncWaitQMakeName -- + * + * Computes the name of the named system object based on the + * path of the wait queue and a sequence number + * + *---------------------------------------------------------------------- + */ + +static char * +SyncWaitQMakeName(const char *path, // IN: + uint64 seq) // IN: +{ + return Str_SafeAsprintf(NULL, "%s.%"FMT64"x", path, seq); +} + + /* *---------------------------------------------------------------------- * @@ -365,7 +386,7 @@ SyncWaitQ_Init(SyncWaitQ *that, // OUT */ void -SyncWaitQ_Destroy(SyncWaitQ *that) +SyncWaitQ_Destroy(SyncWaitQ *that) // IN: { if (!that->initialized) { return; @@ -394,6 +415,7 @@ SyncWaitQ_Destroy(SyncWaitQ *that) /* * Named */ + uint64 seq; char *name; @@ -417,16 +439,15 @@ SyncWaitQ_Destroy(SyncWaitQ *that) * Add a waiter to the waitqueue. * * Results: - * On success, a pollable handle (fd on Posix and a HANDLE on Win32) that - * can be used by the caller to determine when the queue has been woken - * up. - * On failure, -1. + * On success, a pollable handle (fd on Posix and a HANDLE on Win32) + * that can be used by the caller to determine when the queue has been + * woken up. On failure, -1. * *----------------------------------------------------------------------------- */ PollDevHandle -SyncWaitQ_Add(SyncWaitQ *that) // IN +SyncWaitQ_Add(SyncWaitQ *that) // IN: { uint64 seq; int ret = -1; @@ -435,17 +456,20 @@ SyncWaitQ_Add(SyncWaitQ *that) // IN ASSERT(that); ASSERT(that->initialized); - // Hint that we are about to wait + /* Hint that we are about to wait */ Atomic_Write(&that->waiters, TRUE); - // The following statement is the demarcation line for Add. Any - // wakeup that happens after this line should wake up this waiter - // -- Ticho + /* + * The following statement is the demarcation line for Add. Any + * wakeup that happens after this line should wake up this waiter + * -- Ticho + */ + seq = Atomic_Read64(&that->seq); /* - * It is OK to fail in the following 2 paths, because if the sequence number - * has changed, we manufacture our own fd, so any error is harmless. + * It is OK to fail in the following 2 paths, because if the sequence + * number has changed, we manufacture our own fd, so any error is harmless. */ if (that->pathName == NULL) { @@ -520,12 +544,18 @@ SyncWaitQ_Add(SyncWaitQ *that) // IN } } - // Check to see whether someone didn't wake us up while we were - // adding ourselves to the queue + /* + * Check to see whether someone didn't wake us up while we were + * adding ourselves to the queue + */ + if (seq != Atomic_Read64(&that->seq)) { - // Someone woke up the queue while we were adding ourselves to it, so - // just pretend that we were woken up too by returning a conjured up, - // woken up handle + /* + * Someone woke up the queue while we were adding ourselves to it, so + * just pretend that we were woken up too by returning a conjured up, + * woken up handle + */ + int fd[2]; if (ret >= 0) { @@ -554,6 +584,7 @@ SyncWaitQ_Add(SyncWaitQ *that) // IN * fd[0] now should be in a perpetual woken up state. It will be * closed when the client code calls SyncWaitQ_Remove() on it. */ + ret = fd[0]; } else { close(fd[0]); @@ -621,7 +652,7 @@ SyncWaitQ_Add(SyncWaitQ *that) // IN Bool SyncWaitQ_Remove(SyncWaitQ *that, // Unused - PollDevHandle handle) // IN + PollDevHandle handle) // IN: { ASSERT(that); if (!that->initialized) { @@ -661,7 +692,7 @@ SyncWaitQ_Remove(SyncWaitQ *that, // Unused */ Bool -SyncWaitQ_WakeUp(SyncWaitQ *that) // IN +SyncWaitQ_WakeUp(SyncWaitQ *that) // IN: { ASSERT(that); ASSERT(that->initialized); @@ -700,7 +731,7 @@ SyncWaitQ_WakeUp(SyncWaitQ *that) // IN */ static Bool -SyncWaitQWakeUpAnon(SyncWaitQ *that) // IN +SyncWaitQWakeUpAnon(SyncWaitQ *that) // IN: { HandlesAsI64 rwHandles, wakeupHandles; int ret; @@ -720,12 +751,15 @@ SyncWaitQWakeUpAnon(SyncWaitQ *that) // IN return FALSE; } - // The following statement is the demarcation line for wakeup - // - // There is a possibility for suprious wakeups if the WaitQ_Add - // began executing after this line but before the inc of the sequence. - // - // We assume that spurious wakups are OK. + /* + * The following statement is the demarcation line for wakeup + * + * There is a possibility for suprious wakeups if the WaitQ_Add + * began executing after this line but before the inc of the sequence. + * + * We assume that spurious wakups are OK. + */ + wakeupHandles.i64 = Atomic_ReadWrite64(&that->rwHandles, rwHandles.i64); Atomic_FetchAndInc64(&that->seq); @@ -767,7 +801,7 @@ SyncWaitQWakeUpAnon(SyncWaitQ *that) // IN */ static Bool -SyncWaitQWakeUpNamed(SyncWaitQ *that) // IN +SyncWaitQWakeUpNamed(SyncWaitQ *that) // IN: { uint64 seq; char *name; @@ -775,7 +809,7 @@ SyncWaitQWakeUpNamed(SyncWaitQ *that) // IN int ret; int error; - // The following statement is the demarcation line for wakeup + /* The following statement is the demarcation line for wakeup */ seq = Atomic_FetchAndInc64(&that->seq); name = SyncWaitQMakeName(that->pathName, seq); @@ -798,11 +832,12 @@ SyncWaitQWakeUpNamed(SyncWaitQ *that) // IN * If error == ENXIO or ENOENT, then there are no waiters, so * the wakeup is considered successful. */ + if (error == ENXIO || error == ENOENT) { return TRUE; } - Warning("SyncWaitQWakeUpNamed: open failed, errno = %d\n", error); + Warning("%s: open failed, errno = %d\n", __FUNCTION__, error); return FALSE; } @@ -816,32 +851,15 @@ SyncWaitQWakeUpNamed(SyncWaitQ *that) // IN * just closed the read end of the pipe, we may get an EPIPE * error. That's OK, because the waiter was already woken up. */ + return TRUE; } - Warning("SyncWaitQWakeUpNamed: write failed, ret = %d, errno = %d\n", + Warning("%s: write failed, ret = %d, errno = %d\n", __FUNCTION__, ret, error); + return FALSE; } return TRUE; } - - -/* - *---------------------------------------------------------------------- - * - * SyncWaitQMakeName -- - * - * Computes the name of the named system object based on the - * path of the wait queue and a sequence number - * - *---------------------------------------------------------------------- - */ - -static char * -SyncWaitQMakeName(const char *path, // IN - uint64 seq) // IN -{ - return Str_SafeAsprintf(NULL, "%s.%"FMT64"x", path, seq); -} diff --git a/open-vm-tools/lib/system/systemLinux.c b/open-vm-tools/lib/system/systemLinux.c index cd8d46273..7bcfa5e88 100644 --- a/open-vm-tools/lib/system/systemLinux.c +++ b/open-vm-tools/lib/system/systemLinux.c @@ -238,7 +238,7 @@ System_GetCurrentTime(int64 *secs, // OUT Bool System_EnableTimeSlew(int64 delta, // IN: Time difference in us - uint32 timeSyncPeriod) // IN: Time interval in 100th of a second + int64 timeSyncPeriod) // IN: Time interval in us { #if defined(__FreeBSD__) || defined(sun) @@ -261,10 +261,9 @@ System_EnableTimeSlew(int64 delta, // IN: Time difference in us struct timex tx; int error; - uint64 tick; - uint64 timeSyncPeriodUS = timeSyncPeriod * 10000L; + int64 tick; - ASSERT(timeSyncPeriod); + ASSERT(timeSyncPeriod > 0); /* * Set the tick so that delta time is corrected in timeSyncPeriod period. @@ -273,7 +272,8 @@ System_EnableTimeSlew(int64 delta, // IN: Time difference in us * interval. */ tx.modes = ADJ_TICK; - tick = (timeSyncPeriodUS + delta) / ((timeSyncPeriod / 100) * USER_HZ); + tick = (timeSyncPeriod + delta) / + ((timeSyncPeriod / 1000000) * USER_HZ); if (tick > TICK_INCR_MAX) { tick = TICK_INCR_MAX; } else if (tick < TICK_INCR_MIN) { diff --git a/open-vm-tools/lib/unity/unity.c b/open-vm-tools/lib/unity/unity.c index 810b59505..832c7e4bc 100644 --- a/open-vm-tools/lib/unity/unity.c +++ b/open-vm-tools/lib/unity/unity.c @@ -221,7 +221,7 @@ Unity_IsSupported(void) * * Unity_IsActive -- * - * Determine whether we are in Unity mode at this moment. + * Determine whether we are in Unity mode at this moment. * * Results: * TRUE if Unity is active. @@ -484,13 +484,13 @@ Unity_Exit(void) if (unity.isEnabled) { /* Hide full-screen detection window for Unity DnD. */ UnityPlatformUpdateDnDDetWnd(unity.up, FALSE); - + /* Kill Unity helper threads. */ UnityPlatformKillHelperThreads(unity.up); - + /* Restore previously saved user settings. */ UnityPlatformRestoreSystemSettings(unity.up); - + unity.isEnabled = FALSE; } } @@ -712,7 +712,9 @@ UnityTcloGetWindowPath(char const **result, // OUT { UnityWindowId window; - DynBuf *buf = &gTcloUpdate; + DynBuf windowPathUtf8; + DynBuf execPathUtf8; + unsigned int index = 0; Bool ret = TRUE; @@ -734,20 +736,34 @@ UnityTcloGetWindowPath(char const **result, // OUT * dynbuf passed in does not contain any existing data that needs to be appended to, * so this code should continue to accomodate that assumption. */ - DynBuf_SetSize(buf, 0); - if (!UnityPlatformGetWindowPath(unity.up, window, buf)) { + DynBuf_Destroy(&gTcloUpdate); + DynBuf_Init(&gTcloUpdate); + DynBuf_Init(&windowPathUtf8); + DynBuf_Init(&execPathUtf8); + if (!UnityPlatformGetWindowPath(unity.up, window, &windowPathUtf8, &execPathUtf8)) { Debug("UnityTcloGetWindowInfo: Could not get window path.\n"); - return RpcIn_SetRetVals(result, resultLen, - "Could not get window path", - FALSE); + ret = RpcIn_SetRetVals(result, resultLen, + "Could not get window path", + FALSE); + goto exit; } + /* + * Construct the buffer holding the result. Note that we need to use gTcloUpdate + * here to avoid leaking during the RPC handler. + */ + DynBuf_Copy(&windowPathUtf8, &gTcloUpdate); + DynBuf_Append(&gTcloUpdate, DynBuf_Get(&execPathUtf8), DynBuf_GetSize(&execPathUtf8)); + /* * Write the final result into the result out parameters and return! */ - *result = (char *)DynBuf_Get(buf); - *resultLen = DynBuf_GetSize(buf); + *result = (char *)DynBuf_Get(&gTcloUpdate); + *resultLen = DynBuf_GetSize(&gTcloUpdate); +exit: + DynBuf_Destroy(&windowPathUtf8); + DynBuf_Destroy(&execPathUtf8); return ret; } @@ -1117,11 +1133,23 @@ UnityUpdateCallbackFn(void *param, // IN: dynbuf int i, n, count = 0; RegionPtr region; char *titleUtf8 = NULL; + char *windowPathUtf8 = ""; + char *execPathUtf8 = ""; switch (update->type) { case UNITY_UPDATE_ADD_WINDOW: - Str_Sprintf(data, sizeof data, "add %u", update->u.addWindow.id); + if (DynBuf_GetSize(&update->u.addWindow.windowPathUtf8) > 0) { + windowPathUtf8 = DynBuf_Get(&update->u.addWindow.windowPathUtf8); + } + if (DynBuf_GetSize(&update->u.addWindow.execPathUtf8) > 0) { + execPathUtf8 = DynBuf_Get(&update->u.addWindow.execPathUtf8); + } + + Str_Sprintf(data, sizeof data, "add %u windowPath=%s execPath=%s", + update->u.addWindow.id, + windowPathUtf8, + execPathUtf8); DynBuf_AppendString(buf, data); break; @@ -1936,14 +1964,14 @@ error: * * UnityUpdateState -- * - * Communicate unity state changes to vmx. + * Communicate unity state changes to vmx. * * Results: * TRUE if everything is successful. * FALSE otherwise. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------------- */ diff --git a/open-vm-tools/lib/unity/unityPlatform.h b/open-vm-tools/lib/unity/unityPlatform.h index a47620367..3647686a5 100644 --- a/open-vm-tools/lib/unity/unityPlatform.h +++ b/open-vm-tools/lib/unity/unityPlatform.h @@ -67,7 +67,8 @@ void UnityPlatformSaveSystemSettings(UnityPlatform *up); void UnityPlatformRestoreSystemSettings(UnityPlatform *up); Bool UnityPlatformGetWindowPath(UnityPlatform *up, UnityWindowId window, - DynBuf *buf); + DynBuf *windowPathUtf8, + DynBuf *execPathUtf8); Bool UnityPlatformGetNativeWindowPath(UnityPlatform *up, UnityWindowId window, DynBuf *buf); diff --git a/open-vm-tools/lib/unity/unityPlatformX11.c b/open-vm-tools/lib/unity/unityPlatformX11.c index e59cdd711..f17bdaa6e 100644 --- a/open-vm-tools/lib/unity/unityPlatformX11.c +++ b/open-vm-tools/lib/unity/unityPlatformX11.c @@ -63,15 +63,9 @@ static void USRootWindowsProcessEvent(UnityPlatform *up, static int UnityPlatformXErrorHandler(Display *dpy, XErrorEvent *xev); static UnitySpecialWindow *UnityPlatformMakeRootWindowsObject(UnityPlatform *up); -#ifdef GTK2 static gboolean UnityPlatformHandleEventsGlib(GIOChannel *source, GIOCondition condition, gpointer data); -#else -static void UnityPlatformHandleEventsGdk(gpointer data, - gint source, - GdkInputCondition condition); -#endif static void UnityPlatformSendClientMessageFull(Display *d, Window destWindow, @@ -198,27 +192,6 @@ UnityPlatformInit(UnityWindowTracker *tracker, // IN } } - /* - * Set up a callback in the glib main loop to listen for incoming X events on the - * unity display connection. - */ -#ifdef GTK2 - { - GIOChannel *unityDisplayChannel; - unityDisplayChannel = g_io_channel_unix_new(ConnectionNumber(up->display)); - up->unityDisplayWatchID = g_io_add_watch(unityDisplayChannel, - G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, - UnityPlatformHandleEventsGlib, - up); - g_io_channel_unref(unityDisplayChannel); - } -#else - up->unityDisplayWatchID = gdk_input_add(ConnectionNumber(up->display), - GDK_INPUT_READ | GDK_INPUT_EXCEPTION, - UnityPlatformHandleEventsGdk, - up); -#endif - up->allWindows = HashTable_Alloc(128, HASH_INT_KEY, NULL); up->specialWindows = HashTable_Alloc(32, HASH_INT_KEY, NULL); up->desktopWindow = NULL; @@ -327,6 +300,12 @@ UnityPlatformCleanup(UnityPlatform *up) // IN return; } + /* + * Caller should've called Unity_Exit first. + */ + ASSERT(!up->isRunning); + ASSERT(!up->unityDisplayWatchID); + if (up->specialWindows) { HashTable_Free(up->specialWindows); up->specialWindows = NULL; @@ -336,15 +315,6 @@ UnityPlatformCleanup(UnityPlatform *up) // IN up->allWindows = NULL; } - if (up->unityDisplayWatchID) { -#ifdef GTK2 - g_source_remove(up->unityDisplayWatchID); -#else - gdk_input_remove(up->unityDisplayWatchID); -#endif - up->unityDisplayWatchID = 0; - } - if (up->display) { XCloseDisplay(up->display); up->display = NULL; @@ -795,9 +765,13 @@ UnityPlatformKillHelperThreads(UnityPlatform *up) // IN size_t numWindows; if (!up || !up->isRunning) { + ASSERT(!up->unityDisplayWatchID); return; } + g_source_remove(up->unityDisplayWatchID); + up->unityDisplayWatchID = 0; + up->desktopInfo.numDesktops = 0; // Zero means host has not set virtual desktop config UnityX11RestoreSystemSettings(up); @@ -939,6 +913,7 @@ Bool UnityPlatformStartHelperThreads(UnityPlatform *up) // IN { ASSERT(up); + ASSERT(!up->unityDisplayWatchID); XSync(up->display, TRUE); up->rootWindows = UnityPlatformMakeRootWindowsObject(up); @@ -983,6 +958,20 @@ UnityPlatformStartHelperThreads(UnityPlatform *up) // IN up->needWorkAreas = NULL; } + /* + * Set up a callback in the glib main loop to listen for incoming X events on the + * unity display connection. + */ + { + GIOChannel *unityDisplayChannel; + unityDisplayChannel = g_io_channel_unix_new(ConnectionNumber(up->display)); + up->unityDisplayWatchID = g_io_add_watch(unityDisplayChannel, + G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, + UnityPlatformHandleEventsGlib, + up); + g_io_channel_unref(unityDisplayChannel); + } + return TRUE; } @@ -1182,9 +1171,6 @@ UnityPlatformUpdateWindowState(UnityPlatform *up, // IN } -#ifdef GTK2 - - /* *----------------------------------------------------------------------------- * @@ -1218,49 +1204,6 @@ UnityPlatformHandleEventsGlib(GIOChannel *source, // IN return UnityPlatformHandleEvents(errorOccurred, inputAvailable, data); } -#else - - -/* - *----------------------------------------------------------------------------- - * - * UnityX11SignalEventsGdk -- - * - * Lets the UnityX11 object know that new events are available to process. - * This skeleton is used with Gtk+ 1.x. - * - * Results: - * None. - * - * Side effects: - * Signals the update thread. - * - *----------------------------------------------------------------------------- - */ - -static void -UnityPlatformHandleEventsGdk(gpointer data, // IN - gint source, // IN - GdkInputCondition condition) // IN -{ - gboolean errorOccurred = FALSE; - gboolean inputAvailable = FALSE; - - if (condition & GDK_INPUT_EXCEPTION) { - Debug("UnityPlatformHandleEventsGdk - errorOccurred\n"); - errorOccurred = TRUE; - } else if (condition & GDK_INPUT_READ) { - inputAvailable = TRUE; - } - - if (!UnityPlatformHandleEvents(errorOccurred, inputAvailable, data)) { - UnityPlatform *up = (UnityPlatform *) data; - - gdk_input_remove(up->unityDisplayWatchID); - up->unityDisplayWatchID = -1; - } -} -#endif /* diff --git a/open-vm-tools/lib/unity/unityPlatformX11Window.c b/open-vm-tools/lib/unity/unityPlatformX11Window.c index bc198fd6f..0297a5aa6 100644 --- a/open-vm-tools/lib/unity/unityPlatformX11Window.c +++ b/open-vm-tools/lib/unity/unityPlatformX11Window.c @@ -224,7 +224,7 @@ CompareStackingOrder(UnityPlatform *up, // IN { size_t childrenSize = nWindows * sizeof *relevantUChildren; - if (memcmp(relevantXChildren, relevantUChildren, childrenSize) || + if (memcmp(relevantXChildren, relevantUChildren, childrenSize) || memcmp(relevantXChildren, trackerChildren, childrenSize)) { Debug("%s: mismatch!\n", callerName); Debug("%s: %8s %10s %10s %10s\n", callerName, "index", "X Server", @@ -981,8 +981,31 @@ UPWindowSetRelevance(UnityPlatform *up, // IN upw->isRelevant = isRelevant; if (isRelevant) { + DynBuf windowPath; + DynBuf execPath; + Bool retval; + + DynBuf_Init(&windowPath); + DynBuf_Init(&execPath); + + retval = UnityPlatformGetWindowPath(up, + upw->toplevelWindow, + &windowPath, + &execPath); + + if (!retval) { + Debug("GetWindowPath didn't know how to identify the window...\n"); + } + Debug("Adding window %#lx to tracker\n", upw->toplevelWindow); - UnityWindowTracker_AddWindowWithData(up->tracker, upw->toplevelWindow, upw); + UnityWindowTracker_AddWindowWithData(up->tracker, + upw->toplevelWindow, + &windowPath, + &execPath, + upw); + DynBuf_Destroy(&windowPath); + DynBuf_Destroy(&execPath); + UPWindowPushFullUpdate(up, upw); } else { Debug("Removing window %#lx from tracker\n", upw->toplevelWindow); @@ -1570,7 +1593,8 @@ UnityPlatformMoveResizeWindow(UnityPlatform *up, // IN } else #endif { - if (up->desktopInfo.currentDesktop == upw->desktopNumber) { + if (upw->desktopNumber == up->desktopInfo.currentDesktop || + upw->desktopNumber == -1) { UnityRect actualRect; Window actualWindow; @@ -1749,7 +1773,6 @@ UnityPlatformArgvToWindowPaths(UnityPlatform *up, // IN argv = inArgv; -#ifdef GTK2 while (argc && AppUtil_AppIsSkippable(argv[0])) { argv++; argc--; @@ -1776,7 +1799,6 @@ UnityPlatformArgvToWindowPaths(UnityPlatform *up, // IN return FALSE; } } -#endif /* * If the program in question takes any arguments, they will be appended as URI @@ -2052,8 +2074,8 @@ tryLeader: * Get the information needed to re-launch a window and retrieve further * information on it. * - * 'buf' will hold two URI strings, one which uniquely identifies an X11 - * window (windowUri) and one which uniquely identifies the window's owning + * windowPathUtf8 uniquely identifies an X11 window (windowUri), + * execPathUtf8 uniquely identifies the window's owning * executable (execUri). * * windowUri is handy for getting icons and other data associated with a @@ -2064,17 +2086,11 @@ tryLeader: * from the same application are really associated with separate * applications.) * - * I.e., - * - * This RPC is overloaded with two URIs in order to maintain backwards - * compatibility with older VMXs / host UIs expecting to pass the first - * (and, to them, only known) URI to GHIGetBinaryInfo. - * * Results: * TRUE if everything went ok, FALSE otherwise. * * Side effects: - * None + * Original buffer contents are overwritten. * *---------------------------------------------------------------------------- */ @@ -2082,7 +2098,8 @@ tryLeader: Bool UnityPlatformGetWindowPath(UnityPlatform *up, // IN: Platform data UnityWindowId window, // IN: window handle - DynBuf *buf) // IN/OUT: full path to the binary + DynBuf *windowPathUtf8, // IN/OUT: full path to the window + DynBuf *execPathUtf8) // IN/OUT: full path to the binary { UnityPlatformWindow *upw; Bool retval = FALSE; @@ -2108,8 +2125,10 @@ UnityPlatformGetWindowPath(UnityPlatform *up, // IN: Platform data " execUri = %s\n", window, windowUri, execUri); - DynBuf_AppendString(buf, windowUri); - DynBuf_AppendString(buf, execUri); + DynBuf_SetSize(windowPathUtf8, 0); + DynBuf_SetSize(execPathUtf8, 0); + DynBuf_AppendString(windowPathUtf8, windowUri); + DynBuf_AppendString(execPathUtf8, execUri); g_free(windowUri); g_free(execUri); diff --git a/open-vm-tools/lib/unity/unityX11.h b/open-vm-tools/lib/unity/unityX11.h index 7b6c49afc..3ffdfe23a 100644 --- a/open-vm-tools/lib/unity/unityX11.h +++ b/open-vm-tools/lib/unity/unityX11.h @@ -61,6 +61,15 @@ #include #include + +/* + * Warn builders up front that GTK 2 is mandatory. + */ +#ifndef GTK2 +# error UnityX11 depends on GTK+ 2. +#endif + + /* * These defines are listed in the EWMH spec, but not available in any header file that I * know of. @@ -398,11 +407,7 @@ uint32 UnityX11GetCurrentDesktop(UnityPlatform *up); void UnityX11SetCurrentDesktop(UnityPlatform *up, uint32 currentDesktop); Time UnityPlatformGetServerTime(UnityPlatform *up); -#if GTK_MAJOR_VERSION >= 2 -# define UnityPlatformProcessMainLoop() g_main_context_iteration(NULL, TRUE) -#else -# define UnityPlatformProcessMainLoop() gtk_main_iteration() -#endif +#define UnityPlatformProcessMainLoop() g_main_context_iteration(NULL, TRUE) int UnityPlatformGetErrorCount(UnityPlatform *up); void UnityPlatformResetErrorCount(UnityPlatform *up); diff --git a/open-vm-tools/lib/unityWindowTracker/unityWindowTracker.c b/open-vm-tools/lib/unityWindowTracker/unityWindowTracker.c index 232ea7031..1a85c35a8 100644 --- a/open-vm-tools/lib/unityWindowTracker/unityWindowTracker.c +++ b/open-vm-tools/lib/unityWindowTracker/unityWindowTracker.c @@ -71,7 +71,7 @@ UnityWindowTracker_Init(UnityWindowTracker *tracker, // IN { memset(tracker, 0, sizeof(UnityWindowTracker)); tracker->cb = cb; - tracker->windows = HashTable_Alloc(128, HASH_INT_KEY, + tracker->windows = HashTable_Alloc(128, HASH_INT_KEY, (HashTableFreeEntryFn)FreeWindowInfo); } @@ -169,17 +169,48 @@ UnityWindowTracker_LookupWindow(UnityWindowTracker *tracker, // IN */ UnityWindowInfo * -UnityWindowTracker_AddWindow(UnityWindowTracker *tracker, // IN - UnityWindowId id) // IN +UnityWindowTracker_AddWindow(UnityWindowTracker *tracker, // IN + UnityWindowId id, // IN + DynBuf *windowPathUtf8, // IN + DynBuf *execPathUtf8) // IN { UnityWindowInfo *info = UnityWindowTracker_LookupWindow(tracker, id); if (!info) { + size_t windowPathSize; + size_t execPathSize; + info = (UnityWindowInfo *)Util_SafeCalloc(1, sizeof(UnityWindowInfo)); info->tracker = tracker; info->id = id; info->type = UNITY_WINDOW_TYPE_NONE; info->desktopId = tracker->activeDesktopId; DynBuf_Init(&info->titleUtf8); + DynBuf_Init(&info->windowPathUtf8); + DynBuf_Init(&info->execPathUtf8); + + /* + * Ensure that the provided paths only include one NUL terminator + * at the end of the buffer, or keep the paths empty otherwise. + */ + windowPathSize = DynBuf_GetSize(windowPathUtf8); + if (windowPathSize > 0) { + Bool isNullTerminated = Str_Strlen((char *)DynBuf_Get(windowPathUtf8), + windowPathSize) == windowPathSize - 1; + ASSERT(isNullTerminated); + if (isNullTerminated) { + DynBuf_Copy(windowPathUtf8, &info->windowPathUtf8); + } + } + execPathSize = DynBuf_GetSize(execPathUtf8); + if (execPathSize > 0) { + Bool isNullTerminated = Str_Strlen((char *)DynBuf_Get(execPathUtf8), + execPathSize) == execPathSize - 1; + ASSERT(isNullTerminated); + if (isNullTerminated) { + DynBuf_Copy(execPathUtf8, &info->execPathUtf8); + } + } + LOG(2, ("Unity adding new window (id:%d)\n", id)); HashTable_Insert(tracker->windows, (const char *)(long)id, info); info->changed |= UNITY_CHANGED_ADDED; @@ -215,11 +246,16 @@ UnityWindowTracker_AddWindow(UnityWindowTracker *tracker, // IN */ UnityWindowInfo * -UnityWindowTracker_AddWindowWithData(UnityWindowTracker *tracker, // IN - UnityWindowId id, // IN - void *data) // IN +UnityWindowTracker_AddWindowWithData(UnityWindowTracker *tracker, // IN + UnityWindowId id, // IN + DynBuf *windowPathUtf8, // IN + DynBuf *execPathUtf8, // IN + void *data) // IN { - UnityWindowInfo *info = UnityWindowTracker_AddWindow(tracker, id); + UnityWindowInfo *info = UnityWindowTracker_AddWindow(tracker, + id, + windowPathUtf8, + execPathUtf8); if (info) { if (info->data @@ -816,7 +852,10 @@ UnityWindowTracker_SendUpdate(UnityWindowTracker *tracker, // IN { switch (update->type) { case UNITY_UPDATE_ADD_WINDOW: - UnityWindowTracker_AddWindow(tracker, update->u.addWindow.id); + UnityWindowTracker_AddWindow(tracker, + update->u.addWindow.id, + &update->u.addWindow.windowPathUtf8, + &update->u.addWindow.execPathUtf8); break; case UNITY_UPDATE_MOVE_WINDOW: @@ -1080,6 +1119,8 @@ FreeWindowInfo(UnityWindowInfo *info) // IN miRegionDestroy(info->region); } DynBuf_Destroy(&info->titleUtf8); + DynBuf_Destroy(&info->windowPathUtf8); + DynBuf_Destroy(&info->execPathUtf8); free(info); } } @@ -1234,7 +1275,17 @@ PushUpdates(const char *key, // IN: window id if (!incremental || (info->changed & UNITY_CHANGED_ADDED)) { update.type = UNITY_UPDATE_ADD_WINDOW; update.u.addWindow.id = id; + DynBuf_Init(&update.u.addWindow.windowPathUtf8); + DynBuf_Init(&update.u.addWindow.execPathUtf8); + if (DynBuf_GetSize(&info->windowPathUtf8)) { + DynBuf_Copy(&info->windowPathUtf8, &update.u.addWindow.windowPathUtf8); + } + if (DynBuf_GetSize(&info->execPathUtf8)) { + DynBuf_Copy(&info->execPathUtf8, &update.u.addWindow.execPathUtf8); + } (*tracker->cb)(tracker->cbparam, &update); + DynBuf_Destroy(&update.u.addWindow.windowPathUtf8); + DynBuf_Destroy(&update.u.addWindow.execPathUtf8); } if (!incremental || (info->changed & UNITY_CHANGED_POSITION)) { update.type = UNITY_UPDATE_MOVE_WINDOW; diff --git a/open-vm-tools/lib/user/hostinfoPosix2.c b/open-vm-tools/lib/user/hostinfoPosix2.c index 09c9af732..cde4e7133 100644 --- a/open-vm-tools/lib/user/hostinfoPosix2.c +++ b/open-vm-tools/lib/user/hostinfoPosix2.c @@ -26,8 +26,8 @@ * */ -#include #include +#include #include #include #include @@ -81,7 +81,7 @@ #include #endif -#ifndef _PATH_DEVNULL +#if !defined(_PATH_DEVNULL) #define _PATH_DEVNULL "/dev/null" #endif @@ -119,236 +119,6 @@ // nothing -/* - * Local functions - */ - -#if !defined(__APPLE__) && !defined(__FreeBSD__) -static char *HostinfoGetCpuInfo(int nCpu, char *name); -#if !defined(VMX86_SERVER) -static Bool HostinfoGetMemInfo(char *name, unsigned int *value); -#endif // ifndef VMX86_SERVER -#endif // ifndef __APPLE__ - - -/* - *----------------------------------------------------------------------------- - * - * HostinfoGetLoadAverage -- - * - * Returns system average load. - * - * Results: - * TRUE on success, FALSE otherwise. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static Bool -HostinfoGetLoadAverage(float *avg0, // IN/OUT - float *avg1, // IN/OUT - float *avg2) // IN/OUT -{ - /* getloadavg(3) was introduced with glibc 2.2 */ -#if defined(GLIBC_VERSION_22) || defined(__APPLE__) - double avg[3]; - int res; - - res = getloadavg(avg, 3); - if (res < 3) { - NOT_TESTED_ONCE(); - return FALSE; - } - - if (avg0) { - *avg0 = (float) avg[0]; - } - if (avg1) { - *avg1 = (float) avg[1]; - } - if (avg2) { - *avg2 = (float) avg[2]; - } - return TRUE; -#else - /* - * Not implemented. This function is currently only used in the vmx, so - * getloadavg is always available to us. If the linux tools ever need this, - * we can go back to having a look at the output of /proc/loadavg, but let's - * no do that now as long as it's not necessary. - */ - NOT_IMPLEMENTED(); - return FALSE; -#endif -} - - -/* - *----------------------------------------------------------------------------- - * - * Hostinfo_GetLoadAverage -- - * - * Returns system average load * 100. - * - * Results: - * TRUE/FALSE - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -Bool -Hostinfo_GetLoadAverage(uint32 *avg) // IN/OUT -{ - float avg0 = 0; - - if (!HostinfoGetLoadAverage(&avg0, NULL, NULL)) { - return FALSE; - } - *avg = (uint32) 100 * avg0; - return TRUE; -} - - -/* - *----------------------------------------------------------------------------- - * - * Hostinfo_LogLoadAverage -- - * - * Logs system average load. - * - * Results: - * None. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -void -Hostinfo_LogLoadAverage(void) -{ - float avg0 = 0, avg1 = 0, avg2 = 0; - - if (!HostinfoGetLoadAverage(&avg0, &avg1, &avg2)) { - return; - } - Log("LOADAVG: %.2f %.2f %.2f\n", avg0, avg1, avg2); -} - -#if defined(__APPLE__) -/* - *----------------------------------------------------------------------------- - * - * HostinfoMacAbsTimeNS -- - * - * Return the Mac OS absolute time. - * - * Results: - * The absolute time in nanoseconds is returned. This time is documented - * to NEVER go backwards. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -static inline VmTimeType -HostinfoMacAbsTimeNS(void) -{ - VmTimeType raw; - mach_timebase_info_data_t *ptr; - static Atomic_Ptr atomic; /* Implicitly initialized to NULL. --mbellon */ - - /* Insure that the time base values are correct. */ - ptr = (mach_timebase_info_data_t *) Atomic_ReadPtr(&atomic); - - if (ptr == NULL) { - char *p; - - p = Util_SafeMalloc(sizeof(mach_timebase_info_data_t)); - - mach_timebase_info((mach_timebase_info_data_t *) p); - - if (Atomic_ReadIfEqualWritePtr(&atomic, NULL, p)) { - free(p); - } - - ptr = (mach_timebase_info_data_t *) Atomic_ReadPtr(&atomic); - } - - raw = mach_absolute_time(); - - if ((ptr->numer == 1) && (ptr->denom == 1)) { - /* The scaling values are unity, save some time/arithmetic */ - return raw; - } else { - /* The scaling values are not unity. Prevent overflow when scaling */ - return ((double) raw) * (((double) ptr->numer) / ((double) ptr->denom)); - } -} -#endif - - -/* - *----------------------------------------------------------------------------- - * - * HostinfoRawSystemTimerUS -- - * - * Obtain the raw system timer value. - * - * Results: - * Relative time in microseconds or zero if a failure. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -VmTimeType -Hostinfo_RawSystemTimerUS(void) -{ -#if defined(__APPLE__) - return HostinfoMacAbsTimeNS() / 1000ULL; -#else -#if defined(VMX86_SERVER) - if (HostType_OSIsPureVMK()) { - uint64 uptime; - VMK_ReturnStatus status; - - status = VMKernel_GetUptimeUS(&uptime); - if (status != VMK_OK) { - Log("%s: failure!\n", __FUNCTION__); - return 0; // A timer read failure - this is really bad! - } - - return uptime; - } else { -#endif /* ifdef VMX86_SERVER */ - struct timeval tval; - - /* Read the time from the operating system */ - if (gettimeofday(&tval, NULL) != 0) { - Log("%s: failure!\n", __FUNCTION__); - return 0; // A timer read failure - this is really bad! - } - /* Convert into microseconds */ - return (((VmTimeType)tval.tv_sec) * 1000000 + tval.tv_usec); -#if defined(VMX86_SERVER) - } -#endif /* ifdef VMX86_SERVER */ -#endif /* ifdef __APPLE__ */ -} - - /* *----------------------------------------------------------------------------- * @@ -376,6 +146,14 @@ Hostinfo_RawSystemTimerUS(void) VmTimeType Hostinfo_SystemTimerUS(void) { +#if defined(__APPLE__) + /* + * On Mac OS a commpage timer is used. Such timers are ensured to never + * go backwards so don't use the mutex technique - it's inefficient. + */ + + return Hostinfo_RawSystemTimerUS(); +#else SyncMutex *lck; VmTimeType curTime; VmTimeType newTime; @@ -416,6 +194,7 @@ exit: SyncMutex_Unlock(lck); return newTime; +#endif } /* @@ -442,7 +221,7 @@ VmTimeType Hostinfo_SystemUpTime(void) { #if defined(__APPLE__) - return HostinfoMacAbsTimeNS() / 1000ULL; + return Hostinfo_RawSystemTimerUS(); #elif defined(VMX86_SERVER) uint64 uptime; VMK_ReturnStatus status; @@ -522,472 +301,11 @@ Hostinfo_SystemUpTime(void) return uptime * 1000 * 1000; #else NOT_IMPLEMENTED(); -#endif -} - - -/* - *----------------------------------------------------------------------------- - * - * Hostinfo_NameGet -- - * - * Return the fully qualified host name of the host. - * Thread-safe. --hpreg - * - * Results: - * The (memorized) name on success - * NULL on failure - * - * Side effects: - * A host name resolution can occur. - * - *----------------------------------------------------------------------------- - */ - -Unicode -Hostinfo_NameGet(void) -{ - Unicode result; - - static Atomic_Ptr state; /* Implicitly initialized to NULL. --hpreg */ - - result = Atomic_ReadPtr(&state); - - if (UNLIKELY(result == NULL)) { - Unicode before; - - result = Hostinfo_HostName(); - - before = Atomic_ReadIfEqualWritePtr(&state, NULL, result); - - if (before) { - Unicode_Free(result); - - result = before; - } - } - - return result; -} - - -#ifdef VMX86_SERVER -/* - *---------------------------------------------------------------------- - * - * HostinfoReadProc -- - * - * Depending on what string is passed to it, this function parses the - * /proc/vmware/sched/ncpus node and returns the requested value. - * - * Results: - * A postive value on success, -1 (0xFFFFFFFF) on failure. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static INLINE uint32 -HostinfoReadProc(const char *str) -{ - /* XXX this should use sysinfo!! (bug 59849) - */ - FILE *f; - char *line; - uint32 count; - - ASSERT(!strcmp("logical", str) || !strcmp("cores", str) || !strcmp("packages", str)); - - ASSERT(!HostType_OSIsVMK()); // Don't use /proc/vmware - - f = Posix_Fopen("/proc/vmware/sched/ncpus", "r"); - if (f != NULL) { - while (StdIO_ReadNextLine(f, &line, 0, NULL) == StdIO_Success) { - if (strstr(line, str)) { - if (sscanf(line, "%d ", &count) == 1) { - free(line); - break; - } - } - free(line); - } - fclose(f); - - if (count > 0) { - return count; - } - } - - return -1; -} - - -/* - *---------------------------------------------------------------------- - * - * Hostinfo_HTDisabled -- - * - * Figure out if hyperthreading is enabled - * - * Results: - * TRUE if hyperthreading is disabled, FALSE otherwise - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -Bool -Hostinfo_HTDisabled(void) -{ - static uint32 logical = 0, cores = 0; - - if (HostType_OSIsVMK()) { - VMK_ReturnStatus status = VMKernel_HTEnabledCPU(); - if (status != VMK_OK) { - return TRUE; - } else { - return FALSE; - } - } - - if (logical == 0 && cores == 0) { - logical = HostinfoReadProc("logical"); - cores = HostinfoReadProc("cores"); - if (logical <= 0 || cores <= 0) { - logical = cores = 0; - } - } - - return logical == cores; -} -#endif /*ifdef VMX86_SERVER*/ - - -/* - *----------------------------------------------------------------------------- - * - * Hostinfo_NumCPUs -- - * - * Get the number of logical CPUs on the host. If the CPUs are - * hyperthread-capable, this number may be larger than the number of - * physical CPUs. For example, if the host has four hyperthreaded - * physical CPUs with 2 logical CPUs apiece, this function returns 8. - * - * This function returns the number of CPUs that the host presents to - * applications, which is what we want in the vast majority of cases. We - * would only ever care about the number of physical CPUs for licensing - * purposes. - * - * Results: - * On success, the number of CPUs (> 0) the host tells us we have. - * On failure, 0xFFFFFFFF (-1). - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -uint32 -Hostinfo_NumCPUs(void) -{ -#if defined(__APPLE__) - uint32 out; - size_t outSize = sizeof out; - - /* - * Quoting sys/sysctl.h: - * " - * These are the support HW selectors for sysctlbyname. Parameters that are - * byte counts or frequencies are 64 bit numbers. All other parameters are - * 32 bit numbers. - * ... - * hw.activecpu - The number of processors currently available for executing - * threads. Use this number to determine the number threads - * to create in SMP aware applications. This number can - * change when power management modes are changed. - * " - * - * Apparently the only way to retrieve this info is by name, and I have - * verified the info changes when you dynamically switch a CPU - * offline/online. --hpreg - */ - - if (sysctlbyname("hw.activecpu", &out, &outSize, NULL, 0) == -1) { - return -1; - } - - return out; -#elif defined(__FreeBSD__) - uint32 out; - size_t outSize = sizeof out; - -#if __FreeBSD__version >= 500019 - if (sysctlbyname("kern.smp.cpus", &out, &outSize, NULL, 0) == -1) { - return -1; - } -#else - if (sysctlbyname("machdep.smp_cpus", &out, &outSize, NULL, 0) == -1) { - if (errno == ENOENT) { - out = 1; - } else { - return -1; - } - } -#endif - - return out; -#else - static int count = 0; - - if (count <= 0) { -#ifdef VMX86_SERVER - if (HostType_OSIsVMK()) { - VMK_ReturnStatus status = VMKernel_GetNumCPUsUsed(&count); - if (status != VMK_OK) { - count = 0; - return -1; - } - } else { - count = HostinfoReadProc("logical"); - if (count <= 0) { - count = 0; - return -1; - } - } -#else /* ifdef VMX86_SERVER */ - FILE *f; - char *line; - - f = Posix_Fopen("/proc/cpuinfo", "r"); - if (f == NULL) { - Msg_Post(MSG_ERROR, - MSGID(hostlinux.opencpuinfo) - "Could not open /proc/cpuinfo.\n"); - return -1; - } - - while (StdIO_ReadNextLine(f, &line, 0, NULL) == StdIO_Success) { - if (strncmp(line, "processor", strlen("processor")) == 0) { - count++; - } - free(line); - } - - fclose(f); - - if (count == 0) { - Msg_Post(MSG_ERROR, - MSGID(hostlinux.readcpuinfo) - "Could not determine the number of processors from " - "/proc/cpuinfo.\n"); - return -1; - } -#endif /* ifdef VMX86_SERVER */ - } - - return count; -#endif -} - - -/* - *----------------------------------------------------------------------------- - * - * Hostinfo_GetRatedCpuMhz -- - * - * Get the rated CPU speed of a given processor. - * Return value is in MHz. - * - * Results: - * TRUE on success, FALSE on failure - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -Bool -Hostinfo_GetRatedCpuMhz(int32 cpuNumber, // IN - uint32 *mHz) // OUT -{ -#if defined(__APPLE__) || defined(__FreeBSD__) - -# if defined(__APPLE__) -# define CPUMHZ_SYSCTL_NAME "hw.cpufrequency_max" -# elif __FreeBSD__version >= 50011 -# define CPUMHZ_SYSCTL_NAME "hw.clockrate" -# endif - -# if defined(CPUMHZ_SYSCTL_NAME) - uint32 hz; - size_t hzSize = sizeof hz; - - // 'cpuNumber' is ignored: Intel Macs are always perfectly symetric. - - if (sysctlbyname(CPUMHZ_SYSCTL_NAME, &hz, &hzSize, NULL, 0) == -1) { - return FALSE; - } - - *mHz = hz / 1000000; - return TRUE; -# else - return FALSE; -# endif -#else - float fMhz = 0; - char *readVal = HostinfoGetCpuInfo(cpuNumber, "cpu MHz"); - - if (readVal == NULL) { - return FALSE; - } - - if (sscanf(readVal, "%f", &fMhz) == 1) { - *mHz = (unsigned int)(fMhz + 0.5); - } - free(readVal); - return TRUE; -#endif -} - - -/* - *----------------------------------------------------------------------------- - * - * Hostinfo_GetCpuDescription -- - * - * Get the descriptive name associated with a given CPU. - * - * Results: - * On success: Allocated, NUL-terminated string. - * On failure: NULL. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -char * -Hostinfo_GetCpuDescription(uint32 cpuNumber) // IN -{ -#if defined(__APPLE__) || defined(__FreeBSD__) -# if defined(__APPLE__) -# define CPUDESC_SYSCTL_NAME "machdep.cpu.brand_string" -# else -# define CPUDESC_SYSCTL_NAME "hw.model" -# endif - - char *desc; - size_t descSize; - - // 'cpuNumber' is ignored: Intel Macs are always perfectly symetric. - - if (sysctlbyname(CPUDESC_SYSCTL_NAME, NULL, &descSize, NULL, 0) - == -1) { - return NULL; - } - - desc = malloc(descSize); - if (!desc) { - return NULL; - } - - if (sysctlbyname(CPUDESC_SYSCTL_NAME, desc, &descSize, NULL, 0) - == -1) { - free(desc); - return NULL; - } - - return desc; -#else -#ifdef VMX86_SERVER - if (HostType_OSIsVMK()) { - char mName[48]; - - // VMKernel treats mName as an in/out parameter so terminate it. - mName[0] = '\0'; - if (VMKernel_GetCPUModelName(mName, cpuNumber, sizeof(mName)) == VMK_OK) { - mName[sizeof(mName) - 1] = '\0'; - return strdup(mName); - } - return NULL; - } -#endif - return HostinfoGetCpuInfo(cpuNumber, "model name"); -#endif -} - - -#if !defined(__APPLE__) -#if !defined(__FreeBSD__) -/* - *---------------------------------------------------------------------- - * - * HostinfoGetCpuInfo -- - * - * Get some attribute from /proc/cpuinfo for a given CPU - * - * Results: - * On success: Allocated, NUL-terminated attribute string. - * On failure: NULL. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -char * -HostinfoGetCpuInfo(int nCpu, // IN - char *name) // IN -{ - FILE *f; - char *line; - int cpu = 0; - char *value = NULL; - - f = Posix_Fopen("/proc/cpuinfo", "r"); - if (f == NULL) { - Warning(LGPFX" HostinfoGetCpuInfo: Unable to open /proc/cpuinfo\n"); - return NULL; - } - - while (cpu <= nCpu && - StdIO_ReadNextLine(f, &line, 0, NULL) == StdIO_Success) { - char *s; - char *e; - - if ((s = strstr(line, name)) && - (s = strchr(s, ':'))) { - s++; - e = s + strlen(s); - - /* Skip leading and trailing while spaces */ - for (; s < e && isspace(*s); s++); - for (; s < e && isspace(e[-1]); e--); - *e = 0; - - /* Free previous value */ - free(value); - value = strdup(s); - ASSERT_MEM_ALLOC(value); - - cpu++; - } - free(line); - } - - fclose(f); - return value; +#endif } -#endif /* __FreeBSD__ */ + +#if !defined(__APPLE__) /* *---------------------------------------------------------------------- * @@ -1053,9 +371,9 @@ HostinfoFindEntry(char *buffer, // IN: Buffer *---------------------------------------------------------------------- */ -Bool -HostinfoGetMemInfo(char *name, //IN - unsigned int *value) //OUT +static Bool +HostinfoGetMemInfo(char *name, // IN: + unsigned int *value) // OUT: { size_t len; char buffer[4096]; @@ -1063,7 +381,7 @@ HostinfoGetMemInfo(char *name, //IN int fd = Posix_Open("/proc/meminfo", O_RDONLY); if (fd == -1) { - Warning(LGPFX" HostinfoGetMemInfo: Unable to open /proc/meminfo\n"); + Warning(LGPFX" %s: Unable to open /proc/meminfo\n", __FUNCTION__); return FALSE; } @@ -1138,6 +456,7 @@ HostinfoSysinfo(uint64 *totalRam, // OUT: Total RAM in bytes * Kernel versions < 2.3.23. Those kernels used a smaller sysinfo * structure, whose last meaningful field is 'procs' --hpreg */ + si.mem_unit = 1; } @@ -1168,8 +487,8 @@ HostinfoSysinfo(uint64 *totalRam, // OUT: Total RAM in bytes * * HostinfoGetLinuxMemoryInfoInPages -- * - * Obtain the minimum memory to be maintained, total memory available, and - * free memory available on the host (Linux or COS) in pages. + * Obtain the minimum memory to be maintained, total memory available, + * and free memory available on the host (Linux or COS) in pages. * * Results: * TRUE on success: '*minSize', '*maxSize' and '*currentSize' are set @@ -1182,9 +501,9 @@ HostinfoSysinfo(uint64 *totalRam, // OUT: Total RAM in bytes */ Bool -HostinfoGetLinuxMemoryInfoInPages(unsigned int *minSize, // OUT - unsigned int *maxSize, // OUT - unsigned int *currentSize) // OUT +HostinfoGetLinuxMemoryInfoInPages(unsigned int *minSize, // OUT: + unsigned int *maxSize, // OUT: + unsigned int *currentSize) // OUT: { uint64 total; uint64 free; @@ -1215,6 +534,7 @@ HostinfoGetLinuxMemoryInfoInPages(unsigned int *minSize, // OUT * or 32 MB, since the "total" amount of memory reported by Linux is the * total physical memory - amount used by the kernel. */ + if (total < (uint64)128 * 1024 * 1024) { total = ROUNDUP(total, (uint64)8 * 1024 * 1024); } else { @@ -1238,7 +558,8 @@ HostinfoGetLinuxMemoryInfoInPages(unsigned int *minSize, // OUT * * HostinfoGetSwapInfoInPages -- * - * Obtain the total swap and free swap on the host (Linux or COS) in pages. + * Obtain the total swap and free swap on the host (Linux or COS) in + * pages. * * Results: * TRUE on success: '*totalSwap' and '*freeSwap' are set if not NULL @@ -1251,8 +572,8 @@ HostinfoGetLinuxMemoryInfoInPages(unsigned int *minSize, // OUT */ Bool -Hostinfo_GetSwapInfoInPages(unsigned int *totalSwap, // OUT - unsigned int *freeSwap) // OUT +Hostinfo_GetSwapInfoInPages(unsigned int *totalSwap, // OUT: + unsigned int *freeSwap) // OUT: { uint64 total; uint64 free; @@ -1279,8 +600,8 @@ Hostinfo_GetSwapInfoInPages(unsigned int *totalSwap, // OUT * * Hostinfo_GetMemoryInfoInPages -- * - * Obtain the minimum memory to be maintained, total memory available, and - * free memory available on the host in pages. + * Obtain the minimum memory to be maintained, total memory available, + * and free memory available on the host in pages. * * Results: * TRUE on success: '*minSize', '*maxSize' and '*currentSize' are set @@ -1293,9 +614,9 @@ Hostinfo_GetSwapInfoInPages(unsigned int *totalSwap, // OUT */ Bool -Hostinfo_GetMemoryInfoInPages(unsigned int *minSize, // OUT - unsigned int *maxSize, // OUT - unsigned int *currentSize) // OUT +Hostinfo_GetMemoryInfoInPages(unsigned int *minSize, // OUT: + unsigned int *maxSize, // OUT: + unsigned int *currentSize) // OUT: { #if defined(__APPLE__) mach_msg_type_number_t count; @@ -1310,8 +631,9 @@ Hostinfo_GetMemoryInfoInPages(unsigned int *minSize, // OUT */ count = HOST_VM_INFO_COUNT; - error = host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&stat, - &count); + error = host_statistics(mach_host_self(), HOST_VM_INFO, + (host_info_t) &stat, &count); + if (error != KERN_SUCCESS || count != HOST_VM_INFO_COUNT) { Warning("%s: Unable to retrieve host vm stats.\n", __FUNCTION__); return FALSE; @@ -1324,12 +646,14 @@ Hostinfo_GetMemoryInfoInPages(unsigned int *minSize, // OUT * XXX Hopefully this includes cached memory as well. We should check. * No. It returns only completely used pages. */ + *currentSize = stat.free_count; /* * Adding up the stat values does not sum to 100% of physical memory. * The correct value is available from sysctl so we do that instead. */ + if (sysctlbyname("hw.memsize", &memsize, &memsizeSize, NULL, 0) == -1) { Warning("%s: Unable to retrieve host vm hw.memsize.\n", __FUNCTION__); return FALSE; @@ -1380,9 +704,9 @@ Hostinfo_GetMemoryInfoInPages(unsigned int *minSize, // OUT */ Bool -Hostinfo_GetCOSMemoryInfoInPages(unsigned int *minSize, // OUT - unsigned int *maxSize, // OUT - unsigned int *currentSize) // OUT +Hostinfo_GetCOSMemoryInfoInPages(unsigned int *minSize, // OUT: + unsigned int *maxSize, // OUT: + unsigned int *currentSize) // OUT: { if (HostType_OSIsPureVMK()) { return FALSE; @@ -1393,551 +717,6 @@ Hostinfo_GetCOSMemoryInfoInPages(unsigned int *minSize, // OUT #endif -/* - *---------------------------------------------------------------------- - * - * Hostinfo_ResetProcessState -- - * - * Clean up signal handlers and file descriptors before an exec(). - * Fds which need to be kept open can be passed as an array. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ -void -Hostinfo_ResetProcessState(const int *keepFds, // IN: - size_t numKeepFds) // 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. - * Otherwise, the process may still receive timer signals: - * SIGALRM, SIGVTARLM, or SIGPROF. - */ - struct itimerval it; - it.it_value.tv_sec = it.it_value.tv_usec = 0; - it.it_interval.tv_sec = it.it_interval.tv_usec = 0; - setitimer(ITIMER_REAL, &it, NULL); - setitimer(ITIMER_VIRTUAL, &it, NULL); - setitimer(ITIMER_PROF, &it, NULL); - - for (s = 1; s <= NSIG; s++) { - sa.sa_handler = SIG_DFL; - sigfillset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - sigaction(s, &sa, NULL); - } - for (fd = (int) sysconf(_SC_OPEN_MAX) - 1; fd > STDERR_FILENO; fd--) { - size_t i; - for (i = 0; i < numKeepFds; i++) { - if (fd == keepFds[i]) { - break; - } - } - if (i == numKeepFds) { - (void) close(fd); - } - } - - if (getrlimit(RLIMIT_AS, &rlim) == 0) { - rlim.rlim_cur = rlim.rlim_max; - setrlimit(RLIMIT_AS, &rlim); - } - -#ifdef __linux__ - /* - * Drop iopl to its default value. - */ - 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 -} - - -/* - *---------------------------------------------------------------------- - * - * Hostinfo_Execute -- - * - * Start program COMMAND. If WAIT is TRUE, wait for program - * to complete and return exit status. - * - * Results: - * Exit status of COMMAND. - * - * Side effects: - * Run a separate program. - * - *---------------------------------------------------------------------- - */ -int -Hostinfo_Execute(const char *command, - char * const *args, - Bool wait) -{ - int pid; - int status; - - if (command == NULL) { - return 1; - } - - pid = fork(); - - if (pid == -1) { - return -1; - } - - if (pid == 0) { - Hostinfo_ResetProcessState(NULL, 0); - Posix_Execvp(command, args); - exit(127); - } - - if (wait) { - for (;;) { - if (waitpid(pid, &status, 0) == -1) { - if (errno == ECHILD) { - return 0; // This sucks. We really don't know. - } - if (errno != EINTR) { - return -1; - } - } else { - return status; - } - } - } else { - return 0; - } -} - - -/* - *----------------------------------------------------------------------------- - * - * Hostinfo_Daemonize -- - * - * Cross-platform daemon(3)-like wrapper. - * - * Restarts the current process as a daemon, given the path to the - * process (usually from Hostinfo_GetModulePath). This means: - * - * * You're detached from your parent. (Your parent doesn't - * need to wait for you to exit.) - * * Your process no longer has a controlling terminal or - * process group. - * * Your stdin/stdout/stderr fds are redirected to /dev/null. All - * other descriptors, except for the ones that are passed in the - * parameter keepFds, are closed. - * * Your signal handlers are reset to SIG_DFL in the daemonized - * process, and all the signals are unblocked. - * * Your main() function is called with the specified NULL-terminated - * argument list. - * - * (Don't forget that the first string in args is argv[0] -- the - * name of the process). - * - * Unless 'flags' contains HOSTINFO_DAEMONIZE_NOCHDIR, then the - * current directory of the daemon process is set to "/". - * - * Unless 'flags' contains HOSTINFO_DAEMONIZE_NOCLOSE, then all stdio - * file descriptors of the daemon process are redirected to /dev/null. - * This is true even if the stdio descriptors are included in keepFds, - * i.e. the list of fds to be kept open. - * - * If 'flags' contains HOSTINFO_DAEMONIZE_EXIT, then upon successful - * launch of the daemon, the original process will exit. - * - * If pidPath is non-NULL, then upon success, writes the PID - * (as a US-ASCII string followed by a newline) of the daemon - * process to that path. - * - * Results: - * FALSE if the process could not be daemonized. Err_Errno() contains - * the error on failure. - * TRUE if 'flags' does not contain HOSTINFO_DAEMONIZE_EXIT and - * the process was daemonized. - * Otherwise, if the process was daemonized, this function does - * not return, and flow continues from your own main() function. - * - * Side effects: - * The current process is restarted with the given arguments. - * The process state is reset (see Hostinfo_ResetProcessState). - * A new session is created (so the process has no controlling terminal). - * - *----------------------------------------------------------------------------- - */ - -Bool -Hostinfo_Daemonize(const char *path, // IN: NUL-terminated UTF-8 - // path to exec - char * const *args, // IN: NULL-terminated UTF-8 - // argv list - HostinfoDaemonizeFlags flags, // IN: flags - const char *pidPath, // IN/OPT: NUL-terminated - // UTF-8 path to write PID - const int *keepFds, // IN/OPT: array of fds to be - // kept open - size_t numKeepFds) // IN: number of fds in - // keepFds -{ - /* - * We use the double-fork method to make a background process whose - * parent is init instead of the original process. - * - * We do this instead of calling daemon(), because daemon() is - * deprecated on Mac OS 10.5 hosts, and calling it causes a compiler - * warning. - * - * We must exec() after forking, because Mac OS library frameworks - * depend on internal Mach ports, which are not correctly propagated - * across fork calls. exec'ing reinitializes the frameworks, which - * causes them to reopen their Mach ports. - */ - int childPid; - int pipeFds[2] = { -1, -1 }; - uint32 err = EINVAL; - char *pathLocalEncoding = NULL; - char *pidPathLocalEncoding = NULL; - char **argsLocalEncoding = NULL; - int *tempFds = NULL; - sigset_t sig; - - ASSERT_ON_COMPILE(sizeof (errno) <= sizeof err); - ASSERT(args); - ASSERT(path); - ASSERT(numKeepFds == 0 || keepFds); - - if (pipe(pipeFds) == -1) { - err = Err_Errno(); - Warning("%s: Couldn't create pipe, error %u.\n", - __FUNCTION__, err); - pipeFds[0] = pipeFds[1] = -1; - goto cleanup; - } - - numKeepFds++; - tempFds = malloc(sizeof tempFds[0] * numKeepFds); - if (!tempFds) { - err = Err_Errno(); - Warning("%s: Couldn't allocate memory, error %u.\n", - __FUNCTION__, err); - goto cleanup; - } - tempFds[0] = pipeFds[1]; - if (keepFds) { - memcpy(tempFds + 1, keepFds, sizeof tempFds[0] * (numKeepFds - 1)); - } - - if (fcntl(pipeFds[1], F_SETFD, 1) == -1) { - err = Err_Errno(); - Warning("%s: Couldn't set close-on-exec for fd %d, error %u.\n", - __FUNCTION__, pipeFds[1], err); - goto cleanup; - } - - // Convert the strings from UTF-8 before we fork. - pathLocalEncoding = Unicode_GetAllocBytes(path, STRING_ENCODING_DEFAULT); - if (!pathLocalEncoding) { - Warning("%s: Couldn't convert path [%s] to default encoding.\n", - __FUNCTION__, path); - goto cleanup; - } - - if (pidPath) { - pidPathLocalEncoding = - Unicode_GetAllocBytes(pidPath, STRING_ENCODING_DEFAULT); - if (!pidPathLocalEncoding) { - Warning("%s: Couldn't convert path [%s] to default encoding.\n", - __FUNCTION__, pidPath); - goto cleanup; - } - } - - argsLocalEncoding = Unicode_GetAllocList(args, STRING_ENCODING_DEFAULT, -1); - if (!argsLocalEncoding) { - Warning("%s: Couldn't convert arguments to default encoding.\n", - __FUNCTION__); - goto cleanup; - } - - childPid = fork(); - - switch (childPid) { - case -1: - err = Err_Errno(); - Warning("%s: Couldn't fork first child, error %u.\n", - __FUNCTION__, err); - goto cleanup; - case 0: - // We're the first child. Continue on. - break; - default: - { - // We're the original process. Check if the first child exited. - int status; - - close(pipeFds[1]); - waitpid(childPid, &status, 0); - if (WIFEXITED(status) && WEXITSTATUS(status) != EXIT_SUCCESS) { - Warning("%s: Child %d exited with error %d.\n", - __FUNCTION__, childPid, WEXITSTATUS(status)); - goto cleanup; - } else if (WIFSIGNALED(status)) { - Warning("%s: Child %d exited with signal %d.\n", - __FUNCTION__, childPid, WTERMSIG(status)); - goto cleanup; - } - - /* - * Check if the second child exec'ed successfully. If it had - * an error, it will write a uint32 errno to this pipe before - * exiting. Otherwise, its end of the pipe will be closed on - * exec and this call will fail as expected. - * The assumption is that we don't get a partial read. In case, - * it did happen, we can detect it by the number of bytes read. - */ - while (TRUE) { - int res = read(pipeFds[0], &err, sizeof err); - - if (res > 0) { - Warning("%s: Child could not exec %s, read %d, error %u.\n", - __FUNCTION__, path, res, err); - goto cleanup; - } else if (res == -1 && errno == EINTR) { - continue; - } - break; - } - - err = 0; - goto cleanup; - } - } - - /* - * Close all fds except for the write end of the error pipe (which - * we've already set to close on successful exec), and the ones requested by - * the caller. Also reset the signal mask to unblock all signals. fork() - * clears pending signals. - */ - Hostinfo_ResetProcessState(tempFds, numKeepFds); - free(tempFds); - tempFds = NULL; - sigfillset(&sig); - sigprocmask(SIG_UNBLOCK, &sig, NULL); - - if (!(flags & HOSTINFO_DAEMONIZE_NOCLOSE) && setsid() == -1) { - Warning("%s: Couldn't create new session, error %d.\n", - __FUNCTION__, Err_Errno()); - _exit(EXIT_FAILURE); - } - - switch (fork()) { - case -1: - { - Warning("%s: Couldn't fork second child, error %d.\n", - __FUNCTION__, Err_Errno()); - _exit(EXIT_FAILURE); - } - case 0: - // We're the second child. Continue on. - break; - default: - /* - * We're the first child. We don't need to exist any more. - * - * Exiting here causes the second child to be reparented to the - * init process, so the original process doesn't need to wait - * for the child we forked off. - */ - _exit(EXIT_SUCCESS); - } - - /* - * We can't use our i18n wrappers for file manipulation at this - * point, since we've forked; internal library mutexes might be - * invalid. - */ - if (!(flags & HOSTINFO_DAEMONIZE_NOCHDIR) && chdir("/") == -1) { - uint32 err = Err_Errno(); - Warning("%s: Couldn't chdir to /, error %u.\n", - __FUNCTION__, err); - // Let the original process know we failed to chdir. - if (write(pipeFds[1], &err, sizeof err) == -1) { - Warning("Couldn't write to parent pipe: %u, original error: %u.\n", - Err_Errno(), err); - } - _exit(EXIT_FAILURE); - } - - if (!(flags & HOSTINFO_DAEMONIZE_NOCLOSE)) { - int fd; - - fd = open(_PATH_DEVNULL, O_RDONLY); - if (fd != -1) { - dup2(fd, STDIN_FILENO); - close(fd); - } - - fd = open(_PATH_DEVNULL, O_WRONLY); - if (fd != -1) { - dup2(fd, STDOUT_FILENO); - dup2(fd, STDERR_FILENO); - close(fd); - } - } - - if (pidPath) { - int64 pid; - char pidString[32]; - int pidStringLen; - int pidPathFd; - - ASSERT_ON_COMPILE(sizeof (pid_t) <= sizeof pid); - ASSERT(pidPathLocalEncoding); - - // See above comment about how we can't use our i18n wrappers here. - pidPathFd = open(pidPathLocalEncoding, O_WRONLY|O_CREAT|O_TRUNC, 0644); - - if (pidPathFd == -1) { - err = Err_Errno(); - Warning("%s: Couldn't open PID path [%s], error %d.\n", - __FUNCTION__, pidPath, err); - if (write(pipeFds[1], &err, sizeof err) == -1) { - Warning("Couldn't write to parent pipe: %u, original error: %u.\n", - Err_Errno(), err); - } - _exit(EXIT_FAILURE); - } - - pid = getpid(); - pidStringLen = Str_Sprintf(pidString, sizeof pidString, - "%"FMT64"d\n", pid); - if (pidStringLen <= 0) { - err = EINVAL; - if (write(pipeFds[1], &err, sizeof err) == -1) { - Warning("Couldn't write to parent pipe: %u, original error: %u.\n", - Err_Errno(), err); - } - _exit(EXIT_FAILURE); - } - - if (write(pidPathFd, pidString, pidStringLen) != pidStringLen) { - err = Err_Errno(); - Warning("%s: Couldn't write PID to path [%s], error %d.\n", - __FUNCTION__, pidPath, err); - if (write(pipeFds[1], &err, sizeof err) == -1) { - Warning("Couldn't write to parent pipe: %u, original error: %u.\n", - Err_Errno(), err); - } - _exit(EXIT_FAILURE); - } - - close(pidPathFd); - } - - if (execv(pathLocalEncoding, argsLocalEncoding) == -1) { - err = Err_Errno(); - Warning("%s: Couldn't exec %s, error %d.\n", - __FUNCTION__, path, err); - // Let the original process know we failed to exec. - if (write(pipeFds[1], &err, sizeof err) == -1) { - Warning("Couldn't write to parent pipe: %u, original error: %u.\n", - Err_Errno(), err); - } - _exit(EXIT_FAILURE); - } - - NOT_REACHED(); - - cleanup: - free(tempFds); - - if (pipeFds[0] != -1) { - close(pipeFds[0]); - } - if (pipeFds[1] != -1) { - close(pipeFds[1]); - } - Util_FreeStringList(argsLocalEncoding, -1); - free(pidPathLocalEncoding); - free(pathLocalEncoding); - - if (err == 0) { - if (flags & HOSTINFO_DAEMONIZE_EXIT) { - _exit(EXIT_SUCCESS); - } - } else { - Err_SetErrno(err); - - if (pidPath) { - Posix_Unlink(pidPath); - } - } - - return (err == 0); -} - - -/* - *---------------------------------------------------------------------- - * - * Hostinfo_OSIsSMP -- - * - * Host OS SMP capability. - * - * Results: - * TRUE is host OS is SMP capable. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -Bool -Hostinfo_OSIsSMP(void) -{ - uint32 ncpu; - -#if defined(__APPLE__) - size_t ncpuSize = sizeof ncpu; - - if (sysctlbyname("hw.ncpu", &ncpu, &ncpuSize, NULL, 0) == -1) { - return FALSE; - } - -#else - ncpu = Hostinfo_NumCPUs(); - - if (ncpu == 0xFFFFFFFF) { - return FALSE; - } -#endif - - return ncpu > 1 ? TRUE : FALSE; -} - /* *----------------------------------------------------------------------------- * @@ -1967,7 +746,7 @@ Hostinfo_OSIsSMP(void) */ Unicode -Hostinfo_GetModulePath(uint32 priv) +Hostinfo_GetModulePath(uint32 priv) // IN: { Unicode path; @@ -2018,152 +797,3 @@ Hostinfo_GetModulePath(uint32 priv) return path; } - - -/* - *---------------------------------------------------------------------- - * - * Hostinfo_TouchBackDoor -- - * - * Access the backdoor. This is used to determine if we are - * running in a VM or on a physical host. On a physical host - * this should generate a GP which we catch and thereby determine - * that we are not in a VM. However some OSes do not handle the - * GP correctly and the process continues running returning garbage. - * In this case we check the EBX register which should be - * BDOOR_MAGIC if the IN was handled in a VM. Based on this we - * return either TRUE or FALSE. - * - * Results: - * TRUE if we succesfully accessed the backdoor, FALSE or segfault - * if not. - * - * Side effects: - * Exception if not in a VM. - * - *---------------------------------------------------------------------- - */ - -Bool -Hostinfo_TouchBackDoor(void) -{ - /* - * XXX: This can cause Apple's Crash Reporter to erroneously display - * a crash, even though the process has caught the SIGILL and handled - * it. - * - * It's also annoying in gdb, so we'll turn it off in devel builds. - */ -#if !defined(__APPLE__) && !defined(VMX86_DEVEL) - uint32 eax; - uint32 ebx; - uint32 ecx; - - __asm__ __volatile__( -# if defined __PIC__ && !vm_x86_64 // %ebx is reserved by the compiler. - "xchgl %%ebx, %1" "\n\t" - "inl %%dx, %%eax" "\n\t" - "xchgl %%ebx, %1" - : "=a" (eax), - "=&rm" (ebx), -# else - "inl %%dx, %%eax" - : "=a" (eax), - "=b" (ebx), -# endif - "=c" (ecx) - : "0" (BDOOR_MAGIC), - "1" (~BDOOR_MAGIC), - "2" (BDOOR_CMD_GETVERSION), - "d" (BDOOR_PORT) - ); - if (ebx == BDOOR_MAGIC) { - return TRUE; - } -#endif - return FALSE; -} - - -/* - *----------------------------------------------------------------------------- - * - * Hostinfo_GetUser -- - * - * Return current user name, or NULL if can't tell. - * XXX Not thread-safe (somebody could do a setenv()). --hpreg - * - * Results: - * User name. Must be free()d by caller. - * - * Side effects: - * No. - * - *----------------------------------------------------------------------------- - */ - -Unicode -Hostinfo_GetUser() -{ - char buffer[BUFSIZ]; - struct passwd pw; - struct passwd *ppw = &pw; - Unicode env = NULL; - Unicode name = NULL; - - if ((Posix_Getpwuid_r(getuid(), &pw, buffer, sizeof buffer, &ppw) == 0) && - (ppw != NULL)) { - if (ppw->pw_name) { - name = Unicode_Duplicate(ppw->pw_name); - } - } - - if (!name) { - env = Posix_Getenv("USER"); - if (env) { - name = Unicode_Duplicate(env); - } - } - return name; -} - -/* - *----------------------------------------------------------------------------- - * - * Hostinfo_LogMemUsage -- - * Log system memory usage. - * - * Results: - * System memory usage is logged. - * - * Side effects: - * No. - * - *----------------------------------------------------------------------------- - */ - -void -Hostinfo_LogMemUsage(void) -{ - int fd = Posix_Open("/proc/self/statm", O_RDONLY); - - if (fd != -1) { - size_t len; - char buf[64]; - - len = read(fd, buf, sizeof buf); - close(fd); - - if (len != -1) { - int a[7] = { 0 }; - - buf[len < sizeof buf ? len : sizeof buf - 1] = '\0'; - - sscanf(buf, "%d %d %d %d %d %d %d", - &a[0], &a[1], &a[2], &a[3], &a[4], &a[5], &a[6]); - - Log("RUSAGE size=%d resident=%d share=%d trs=%d lrs=%d drs=%d dt=%d\n", - a[0], a[1], a[2], a[3], a[4], a[5], a[6]); - } - } -} diff --git a/open-vm-tools/lib/user/util.c b/open-vm-tools/lib/user/util.c index 657b77d21..42d9d9753 100644 --- a/open-vm-tools/lib/user/util.c +++ b/open-vm-tools/lib/user/util.c @@ -99,11 +99,14 @@ static int UtilTokenHasGroup(HANDLE token, SID *group); #ifdef UTIL_BACKTRACE_USE_UNWIND #include +#define MAX_SKIPPED_FRAMES 10 + struct UtilBacktraceFromPointerData { uintptr_t basePtr; Util_OutputFunc outFunc; void *outFuncData; unsigned int frameNr; + unsigned int skippedFrames; }; struct UtilBacktraceToBufferData { @@ -373,6 +376,7 @@ UtilBacktraceFromPointerCallback(struct _Unwind_Context *ctx, // IN: Unwind cont /* * Stack grows down. So if we are below basePtr, do nothing... */ + if (cfa >= data->basePtr && data->frameNr < 500) { #ifndef VM_X86_64 # error You should not build this on 32bit - there is no eh_frame there. @@ -389,6 +393,14 @@ UtilBacktraceFromPointerCallback(struct _Unwind_Context *ctx, // IN: Unwind cont _Unwind_GetGR(ctx, 14), _Unwind_GetGR(ctx, 15)); data->frameNr++; return _URC_NO_REASON; + } else if (data->skippedFrames < MAX_SKIPPED_FRAMES && !data->frameNr) { + /* + * Skip over the frames before the specified starting point of the + * backtrace. + */ + + data->skippedFrames++; + return _URC_NO_REASON; } return _URC_END_OF_STACK; } @@ -422,6 +434,7 @@ UtilSymbolBacktraceFromPointerCallback(struct _Unwind_Context *ctx, // IN: Unwin /* * Stack grows down. So if we are below basePtr, do nothing... */ + if (cfa >= data->basePtr && data->frameNr < 500) { #ifndef VM_X86_64 # error You should not build this on 32bit - there is no eh_frame there. @@ -450,6 +463,14 @@ UtilSymbolBacktraceFromPointerCallback(struct _Unwind_Context *ctx, // IN: Unwin } data->frameNr++; return _URC_NO_REASON; + } else if (data->skippedFrames < MAX_SKIPPED_FRAMES && !data->frameNr) { + /* + * Skip over the frames before the specified starting point of the + * backtrace. + */ + + data->skippedFrames++; + return _URC_NO_REASON; } return _URC_END_OF_STACK; } @@ -511,6 +532,7 @@ Util_BacktraceFromPointerWithFunc(uintptr_t *basePtr, data.outFunc = outFunc; data.outFuncData = outFuncData; data.frameNr = 0; + data.skippedFrames = 0; _Unwind_Backtrace(UtilBacktraceFromPointerCallback, &data); #if !defined(_WIN32) && !defined(N_PLAT_NLM) && !defined(VMX86_TOOLS) @@ -523,6 +545,7 @@ Util_BacktraceFromPointerWithFunc(uintptr_t *basePtr, data.outFunc = outFunc; data.outFuncData = outFuncData; data.frameNr = 0; + data.skippedFrames = 0; _Unwind_Backtrace(UtilSymbolBacktraceFromPointerCallback, &data); #endif diff --git a/open-vm-tools/lib/user/utilPosix.c b/open-vm-tools/lib/user/utilPosix.c index 8a968f4ed..828fc7012 100644 --- a/open-vm-tools/lib/user/utilPosix.c +++ b/open-vm-tools/lib/user/utilPosix.c @@ -34,6 +34,7 @@ #include #include #include +#include #if !__FreeBSD__ && !sun # include @@ -57,6 +58,11 @@ #include "unicodeOperations.h" #include "err.h" #include "posix.h" +#include "vmstdio.h" + +#define LOGLEVEL_MODULE util +#include "loglevel_user.h" +#define LGPFX "UtilPosix:" /* For Util_GetProcessName() */ @@ -83,6 +89,12 @@ # endif #endif +#if defined(VMX86_STATS) && defined(__linux__) && !defined(VMX86_SERVER) +#define SYS_CSTATE_DIR "/sys/devices/system/cpu" +#define PROC_CSTATE_DIR "/proc/acpi/processor" +#define MAX_C_STATES 8 +#define FREQ_ACPI 3.579545 +#endif #if !__FreeBSD__ && !sun @@ -667,7 +679,8 @@ Util_GetProcessName(pid_t pid, // IN : process id fd = Posix_Open(fileName, O_RDONLY); if (fd < 0) { - Log("Util_GetProcessName: Error: cannot open %s\n", fileName); + Log("%s: Error: cannot open %s\n", __FUNCTION__, fileName); + return FALSE; } @@ -677,8 +690,9 @@ Util_GetProcessName(pid_t pid, // IN : process id #else if (nread < 0) { #endif - Log("Util_GetProcessName: Error: could not read %s\n", fileName); + Log("%s: Error: could not read %s\n", __FUNCTION__, fileName); close(fd); + return FALSE; } @@ -694,7 +708,8 @@ Util_GetProcessName(pid_t pid, // IN : process id * contains a format modifier to ensure psinfo is not overrun. */ if (sscanf(buf, PRE PSINFOFMT POST, psinfo) != 1) { - Log("Util_GetProcessName: Error, could not parse contents of %s\n", fileName); + Log("%s: Error, could not parse contents of %s\n", __FUNCTION__, + fileName); return FALSE; } @@ -705,8 +720,9 @@ Util_GetProcessName(pid_t pid, // IN : process id psnameLen = strlen(psname); if (psnameLen + 1 > bufOutSize) { - Log("Util_GetProcessName: Error, process name (%"FMTSZ"u bytes) is larger " - "than output buffer\n", psnameLen); + Log("%s: Error, process name (%"FMTSZ"u bytes) is larger " + "than output buffer\n", __FUNCTION__, psnameLen); + return FALSE; } @@ -714,3 +730,390 @@ Util_GetProcessName(pid_t pid, // IN : process id return TRUE; } #endif + +#if defined(VMX86_STATS) +#if defined(__linux__) && !defined(VMX86_SERVER) +/* + *---------------------------------------------------------------------------- + * + * UtilAllocCStArrays -- + * + * (Re-)Allocate data arrays for UtilReadSysCStRes and UtilReadProcCStRes. + * + * Results: + * TRUE if successful. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static Bool +UtilAllocCStArrays(uint32 ncpus, // IN + uint32 nstates, // IN + uint64 **transitns, // OUT + uint64 **residency, // OUT + uint64 **transTime, // OUT + uint64 **residTime) // OUT +{ + free(*transitns); + free(*residency); + free(*transTime); + free(*residTime); + + *transitns = calloc(nstates * ncpus, sizeof **transitns); + *residency = calloc(nstates * ncpus, sizeof **residency); + *transTime = calloc(ncpus, sizeof **transTime); + *residTime = calloc(ncpus, sizeof **residTime); + + if (!*transitns || !*residency || !*transTime || !*residTime) { + free(*transitns); + free(*residency); + free(*transTime); + free(*residTime); + Warning("%s: Cannot allocate memory for C-state queries\n", __FUNCTION__); + return FALSE; + } + + return TRUE; +} + + +/* + *---------------------------------------------------------------------------- + * + * UtilReadSysCStRes -- + * UtilReadProcCStRes -- + * + * Read the C-state residency statistics under /sys and /proc + * respectively. UtilReadSysCStRes should take precedence over + * UtilReadProcCStRes as /proc/acpi is getting replaced by sysfs + * in newer kernels. See Util_QueryCStResidency for description of + * parameters. + * + * Results: + * TRUE if successful. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static Bool +UtilReadSysCStRes(DIR *dir, // IN + uint32 *numCpus, // IN/OUT + uint32 *numCStates, // IN/OUT + uint64 **transitns, // OUT + uint64 **residency, // OUT + uint64 **transTime, // OUT + uint64 **residTime) // OUT +{ + struct dirent *cpuEntry; + DIR *cpuDir; + struct dirent *cstateEntry; + char pathname[PATH_MAX + 1]; + uint32 cpu = 0; + uint32 cl = 0; + + /* Determine the number of cpus and c-states. */ + while ((cpuEntry = readdir(dir))) { + if (Str_Strncasecmp(cpuEntry->d_name, "cpu", 3) == 0 && + isdigit(cpuEntry->d_name[3])) { + cpu++; + if (cl != 0) { /* already found the number of c states */ + continue; + } + if (Str_Snprintf(pathname, sizeof pathname, + SYS_CSTATE_DIR"/%s/cpuidle", cpuEntry->d_name) <= 0) { + LOG(0, ("%s: Str_Snprintf failed\n", __FUNCTION__)); + return FALSE; + } + cpuDir = Posix_OpenDir(pathname); + if (cpuDir != NULL) { + uint32 cnum; + + while ((cstateEntry = readdir(cpuDir))) { + if (Str_Strncasecmp(cstateEntry->d_name, "state", 5) == 0 && + sscanf(cstateEntry->d_name + 5, "%u", &cnum) == 1 && + cnum > cl) { + cl = cnum; /* state0 will be ignored */ + } + } + closedir(cpuDir); + } + } + } + if (cpu == 0 || cl == 0) { + return FALSE; + } + + if (*numCpus != cpu || *numCStates != cl) { + if (!UtilAllocCStArrays(cpu, cl, transitns, residency, transTime, + residTime)) { + return FALSE; + } + *numCpus = cpu; + *numCStates = cl; + } + + rewinddir(dir); + cpu = 0; + while ((cpuEntry = readdir(dir))) { + int pathlen; + VmTimeType timeUS; + + if (Str_Strncasecmp(cpuEntry->d_name, "cpu", 3) != 0 || + !isdigit(cpuEntry->d_name[3])) { + continue; + } + pathlen = Str_Snprintf(pathname, sizeof pathname, + SYS_CSTATE_DIR"/%s/cpuidle", cpuEntry->d_name); + if (pathlen <= 0) { + LOG(0, ("%s: Str_Snprintf for '%s/cpuidle' failed\n", __FUNCTION__, + cpuEntry->d_name)); + return FALSE; + } + cpuDir = Posix_OpenDir(pathname); + if (cpuDir == NULL) { + LOG(0, ("%s: Failed to open directory %s\n", __FUNCTION__, pathname)); + continue; + } + + /* + * Under the "cpuidle" directory, there is one "stateX" directory for + * each C-state. We ignore "state0", i.e. C0, which is the running state. + * Under each "stateX" directory, there is a "usage" file which contains + * the number of entries into that state, and a "time" file which + * contains the total residency in that state. + */ + + while ((cstateEntry = readdir(cpuDir))) { + FILE *statsFile; + int result; + uint32 index; + + if (Str_Strncasecmp(cstateEntry->d_name, "state", 5) != 0) { + continue; + } + if (sscanf(cstateEntry->d_name + 5, "%u", &cl) != 1 || cl == 0) { + continue; + } + cl--; /* ignoring state0 -- cl == 0 -> state1 */ + index = *numCStates * cpu + cl; + + if (Str_Snprintf(pathname + pathlen, sizeof pathname - pathlen, + "/%s/usage", cstateEntry->d_name) <= 0) { + LOG(0, ("%s: Str_Snprintf for 'usage' failed\n", __FUNCTION__)); + closedir(cpuDir); + return FALSE; + } + statsFile = Posix_Fopen(pathname, "r"); + if (statsFile == NULL) { + continue; + } + result = fscanf(statsFile, "%"FMT64"u", &(*transitns)[index]); + fclose(statsFile); + if (result <= 0) { + continue; + } + + if (Str_Snprintf(pathname + pathlen, sizeof pathname - pathlen, + "/%s/time", cstateEntry->d_name) <= 0) { + LOG(0, ("%s: Str_Snprintf for 'time' failed\n", __FUNCTION__)); + closedir(cpuDir); + return FALSE; + } + statsFile = Posix_Fopen(pathname, "r"); + if (statsFile == NULL) { + continue; + } + result = fscanf(statsFile, "%"FMT64"u", &(*residency)[index]); + fclose(statsFile); + if (result <= 0) { + continue; + } + } + closedir(cpuDir); + + timeUS = Hostinfo_SystemTimerUS(); + if (timeUS <= 0) { + LOG(0, ("%s: Hostinfo_SystemTimerUS() failed\n", __FUNCTION__)); + return FALSE; + } + (*transTime)[cpu] = timeUS; + (*residTime)[cpu] = timeUS; + cpu++; + } + + return cpu > 0; +} + + +static Bool +UtilReadProcCStRes(DIR *dir, // IN + uint32 *numCpus, // IN/OUT + uint32 *numCStates, // IN/OUT + uint64 **transitns, // OUT + uint64 **residency, // OUT + uint64 **transTime, // OUT + uint64 **residTime) // OUT +{ + struct dirent *cpuEntry; + uint32 cpu = 0; + + /* Determine the number of cpus. */ + while ((cpuEntry = readdir(dir))) { + if (cpuEntry->d_name[0] != '.') { + cpu++; + } + } + if (cpu == 0) { + return FALSE; + } + + if (*numCpus != cpu) { + /* + * We do not know the number of C-states supported until we read the + * file, so we allocate for MAX_C_STATES and determine *numCStates later. + */ + + if (!UtilAllocCStArrays(cpu, MAX_C_STATES, transitns, residency, + transTime, residTime)) { + return FALSE; + } + *numCpus = cpu; + *numCStates = 0; + } + + rewinddir(dir); + cpu = 0; + while ((cpuEntry = readdir(dir))) { + char pathname[PATH_MAX + 1]; + char *line; + size_t lineSize; + FILE *powerFile; + uint32 cl; + VmTimeType timeUS; + + if (cpuEntry->d_name[0] == '.') { + continue; + } + if (Str_Snprintf(pathname, sizeof pathname, PROC_CSTATE_DIR"/%s/power", + cpuEntry->d_name) <= 0) { + LOG(0, ("%s: Str_Snprintf for '%s/power' failed\n", __FUNCTION__, + cpuEntry->d_name)); + return FALSE; + } + powerFile = Posix_Fopen(pathname, "r"); + if (powerFile == NULL) { + continue; + } + + cl = 0; + while (StdIO_ReadNextLine(powerFile, &line, 0, &lineSize) + == StdIO_Success) { + char *ptr; + uint32 index = *numCStates * cpu + cl; + + if ((ptr = Str_Strnstr(line, "usage[", lineSize))) { + sscanf(ptr + 6, "%"FMT64"u]", &(*transitns)[index]); + if ((ptr = Str_Strnstr(line, "duration[", lineSize))) { + sscanf(ptr + 9, "%"FMT64"u]", &(*residency)[index]); + cl++; + } + } + free(line); + } + fclose(powerFile); + + timeUS = Hostinfo_SystemTimerUS(); + if (timeUS <= 0) { + LOG(0, ("%s: Hostinfo_SystemTimerUS() failed\n", __FUNCTION__)); + return FALSE; + } + (*transTime)[cpu] = timeUS; + (*residTime)[cpu] = (uint64)((double)timeUS * FREQ_ACPI); + if (*numCStates == 0) { + *numCStates = cl; + } + cpu++; + } + return cpu > 0 && *numCStates > 0; +} + + +/* + *---------------------------------------------------------------------------- + * + * Util_QueryCStResidency -- + * + * Query CPU's C-state residency statistics exposed by the host OS. + * On Linux, this is done via either the sysfs or /proc/acpi interface. + * + * The parameters transitns, residency, transTime and residTime are + * pointers to uint64 arrays, whose dimensions are specified by + * *numCpus and/or *numCStates: + * transitns -- number of trasitions into each c-state for each CPU + * residency -- time in each c-state for each CPU (in some opaque unit) + * transTime -- timestamp (microseconds) for transitns data, per CPU + * residTime -- timestamp for residency data, per CPU (in same unit as + * residency) + * + * If the dimensions specified are too small, the arrays are freed + * and new memory allocated. + * + * Results: + * TRUE if successful. + * + * Side Effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +Bool +Util_QueryCStResidency(uint32 *numCpus, // IN/OUT + uint32 *numCStates, // IN/OUT + uint64 **transitns, // OUT + uint64 **residency, // OUT + uint64 **transTime, // OUT + uint64 **residTime) // OUT +{ + DIR *dir; + Bool ret = FALSE; + + dir = Posix_OpenDir(SYS_CSTATE_DIR); + if (dir) { + ret = UtilReadSysCStRes(dir, numCpus, numCStates, transitns, residency, + transTime, residTime); + closedir(dir); + } + + if (!ret) { + dir = Posix_OpenDir(PROC_CSTATE_DIR); + if (dir) { + ret = UtilReadProcCStRes(dir, numCpus, numCStates, transitns, + residency, transTime, residTime); + closedir(dir); + } + } + + return ret; +} + +#else // #if defined(__linux__) && !defined(VMX86_SERVER) + +Bool +Util_QueryCStResidency(uint32 *numCpus, // IN/OUT + uint32 *numCStates, // IN/OUT + uint64 **transitns, // OUT + uint64 **residency, // OUT + uint64 **transTime, // OUT + uint64 **residTime) // OUT +{ + return FALSE; +} +#endif +#endif // #if defined(VMX86_STATS) diff --git a/open-vm-tools/lib/vixTools/vixTools.c b/open-vm-tools/lib/vixTools/vixTools.c index 16a54b862..3c3cfcedd 100644 --- a/open-vm-tools/lib/vixTools/vixTools.c +++ b/open-vm-tools/lib/vixTools/vixTools.c @@ -3248,9 +3248,26 @@ VixToolsListFileSystems(VixCommandRequestHeader *requestMsg, // IN Bool impersonatingVMWareUser = FALSE; void *userToken = NULL; char *destPtr; -#ifdef linux char *endDestPtr; +#if defined(_WIN32) || defined(linux) VixCommandListFileSystemsRequest *lfReq = (VixCommandListFileSystemsRequest *) requestMsg; + const char *listFileSystemsFormatString = "" + "%s" + "%"FMT64"u" + "%"FMT64"u" + "%s" + ""; +#endif +#if defined(_WIN32) + Unicode *driveList = NULL; + int numDrives = -1; + uint64 freeBytesToUser = 0; + uint64 totalBytesToUser = 0; + uint64 freeBytes = 0; + Unicode fileSystemType; + int i; +#endif +#ifdef linux MNTHANDLE fp; DECLARE_MNTINFO(mnt); const char *mountfile = NULL; @@ -3260,6 +3277,7 @@ VixToolsListFileSystems(VixCommandRequestHeader *requestMsg, // IN destPtr = resultBuffer; *destPtr = 0; + endDestPtr = resultBuffer + sizeof(resultBuffer); err = VixToolsImpersonateUser(requestMsg, &userToken); if (VIX_OK != err) { @@ -3268,11 +3286,57 @@ VixToolsListFileSystems(VixCommandRequestHeader *requestMsg, // IN impersonatingVMWareUser = TRUE; #if defined(_WIN32) - // XXX TBD - err = VIX_E_NOT_SUPPORTED; -#elif defined(linux) + numDrives = Win32U_GetLogicalDriveStrings(&driveList); + if (-1 == numDrives) { + Warning("unable to get drive listing: windows error code %d\n", + GetLastError()); + err = FoundryToolsDaemon_TranslateSystemErr(); + goto abort; + } - endDestPtr = resultBuffer + sizeof(resultBuffer); + for (i = 0; i < numDrives; i++) { + /* + * Only add to the list if it is a local drive or + * VIX_FILESYSTEMS_HIDE_NETWORK is not set + */ + if ((DRIVE_REMOTE != Win32U_GetDriveType(driveList[i])) || + !(lfReq->options & VIX_FILESYSTEMS_HIDE_NETWORK)) { + + if (!Win32U_GetDiskFreeSpaceEx(driveList[i], + (PULARGE_INTEGER) &freeBytesToUser, + (PULARGE_INTEGER) &totalBytesToUser, + (PULARGE_INTEGER) &freeBytes)) { + /* + * If we encounter an error, just return 0 values for the space info + */ + freeBytesToUser = 0; + totalBytesToUser = 0; + freeBytes = 0; + + Warning("unable to get drive size info: windows error code %d\n", + GetLastError()); + } + + // If it fails, fileSystemType will be NULL + Win32U_GetVolumeInformation(driveList[i], + NULL, + NULL, + NULL, + NULL, + &fileSystemType); + + destPtr += Str_Sprintf(destPtr, endDestPtr - destPtr, + listFileSystemsFormatString, + driveList[i], + totalBytesToUser, + freeBytesToUser, + fileSystemType); + + Unicode_Free(fileSystemType); + } + } + +#elif defined(linux) if (lfReq->options & VIX_FILESYSTEMS_HIDE_NETWORK) { mountfile = "/etc/fstab"; @@ -3299,12 +3363,7 @@ VixToolsListFileSystems(VixCommandRequestHeader *requestMsg, // IN size = (uint64) statfsbuf.f_blocks * (uint64) statfsbuf.f_bsize; freeSpace = (uint64) statfsbuf.f_bfree * (uint64) statfsbuf.f_bsize; destPtr += Str_Sprintf(destPtr, endDestPtr - destPtr, - "" - "%s" - "%"FMT64"u" - "%"FMT64"u" - "%s" - "", + listFileSystemsFormatString, MNTINFO_NAME(mnt), size, freeSpace, @@ -3317,6 +3376,14 @@ VixToolsListFileSystems(VixCommandRequestHeader *requestMsg, // IN #endif abort: +#if defined(_WIN32) + for (i = 0; i < numDrives; i++) { + Unicode_Free(driveList[i]); + } + + free(driveList); +#endif + if (impersonatingVMWareUser) { VixToolsUnimpersonateUser(userToken); } diff --git a/open-vm-tools/lib/wiper/wiperPosix.c b/open-vm-tools/lib/wiper/wiperPosix.c index 6199ab585..32393255f 100644 --- a/open-vm-tools/lib/wiper/wiperPosix.c +++ b/open-vm-tools/lib/wiper/wiperPosix.c @@ -47,6 +47,7 @@ #include "util.h" #include "str.h" #include "fileIO.h" +#include "vmstdio.h" #include "mntinfo.h" #include "posix.h" @@ -110,22 +111,113 @@ typedef struct WiperDiskString { } WiperDiskString; #endif -#if defined(__linux__) && !defined(N_PLAT_NLM) -static int dmNumEntries; -static int dmNumbers[WIPER_MAX_DM_NUMBERS]; -#endif - /* Variables */ static Bool initDone = FALSE; /* Local functions */ -static INLINE Bool WiperIsDiskDevice(MNTINFO *mnt, struct stat *s); +static Bool WiperIsDiskDevice(MNTINFO *mnt, struct stat *s); static void WiperPartitionFilter(WiperPartition *item, MNTINFO *mnt); static unsigned char *WiperGetSpace(WiperState *state, uint64 *free, uint64 *total); static void WiperClean(WiperState *state); -static INLINE Bool WiperIsDeviceMapper(struct stat *s); + + +#if defined(__linux__) + +#define MAX_DISK_MAJORS 256 /* should be enough for now */ +#define NUM_PRESEEDED_MAJORS 5 /* must match the below */ + +static unsigned int knownDiskMajor[MAX_DISK_MAJORS] = { + /* + * Pre-seed some major numbers we were comparing against before + * we started scanning /proc/devices. + */ + 3, /* First MFM, RLL and IDE hard disk/CD-ROM interface. + Inside a VM, this is simply the First IDE hard + disk/CD-ROM interface because we don't support + others */ + 8, /* SCSI disk devices */ + 22, /* Second IDE hard disk/CD-ROM interface */ + 43, /* Network block device */ + 259, /* Disks in 2.6.27 */ +}; + +static int numDiskMajors; + + +/* + *----------------------------------------------------------------------------- + * + * WiperCollectDiskMajors -- + * + * Collects major numbers of devices that we considering "disks" and + * may try to shrink. + * + * Results: + * None + * + * Side effects: + * Populates knownDiskMajor array and numDiskMajors counter for + * subsequent use by linux version of WiperIsDiskDevice(). + * + *----------------------------------------------------------------------------- + */ + +static void +WiperCollectDiskMajors(void) +{ + const char diskDevNames[] = "|ide0|ide1|sd|md|nbd|device-mapper|blkext|"; + const char blockSeparator[] = "Block devices:"; + Bool seenBlockSeparator = FALSE; + char *buf; + int major; + char device[64]; + FILE *f; + + numDiskMajors = NUM_PRESEEDED_MAJORS; + + f = Posix_Fopen("/proc/devices", "r"); + if (!f) { + return; + } + + while (StdIO_ReadNextLine(f, &buf, 0, NULL) == StdIO_Success) { + + if (!seenBlockSeparator) { + if (!memcmp(buf, blockSeparator, sizeof(blockSeparator) - 1)) { + seenBlockSeparator = TRUE; + } + } else if (sscanf(buf, "%d %61s\n", &major, device + 1) == 2) { + + device[0] = '|'; + device[sizeof(device) - 2] = '\0'; + Str_Strcat(device, "|", sizeof(device)); + + if (strstr(diskDevNames, device)) { + knownDiskMajor[numDiskMajors++] = major; + } + } + + free(buf); + + if (numDiskMajors >= MAX_DISK_MAJORS) { + break; + } + } + + fclose(f); +} + +#else + +static void +WiperCollectDiskMajors(void) +{ +} + +#endif + /* *----------------------------------------------------------------------------- @@ -144,7 +236,7 @@ static INLINE Bool WiperIsDeviceMapper(struct stat *s); */ #if defined(sun) /* SunOS { */ -static INLINE Bool +static Bool WiperIsDiskDevice(MNTINFO *mnt, // IN: file system being considered struct stat *s) // IN: stat(2) info of fs source { @@ -185,30 +277,25 @@ WiperIsDiskDevice(MNTINFO *mnt, // IN: file system being considered #elif defined(__linux__) /* } linux { */ -static INLINE Bool +static Bool WiperIsDiskDevice(MNTINFO *mnt, // IN: file system being considered struct stat *s) // IN: stat(2) info of fs source { - int majorN; - - majorN = major(s->st_rdev); - if (! ( (majorN == 3) /* First MFM, RLL and IDE hard disk/CD-ROM - interface. Inside a VM, this is simply the First - IDE hard disk/CD-ROM interface because we don't - support others */ - || (majorN == 22) /* Second IDE hard disk/CD-ROM interface */ - || (majorN == 8) /* SCSI disk devices */ - || (majorN == 43) /* Network block device */ - || (majorN == 259) /* Disks in 2.6.27 */)) { - return FALSE; + int majorN = major(s->st_rdev); + int i; + + for (i = 0; i < numDiskMajors; i++) { + if (majorN == knownDiskMajor[i]) { + return TRUE; + } } - return TRUE; + return FALSE; } #elif defined(__FreeBSD__) || defined(__APPLE__) /* } FreeBSD { */ -static INLINE Bool +static Bool WiperIsDiskDevice(MNTINFO *mnt, // IN: file system being considered struct stat *s) // IN: stat(2) info of fs source { @@ -338,11 +425,7 @@ WiperPartitionFilter(WiperPartition *item, // IN/OUT #endif if (!WiperIsDiskDevice(mnt, &s)) { - if (WiperIsDeviceMapper(&s)) { - item->comment = WIPER_DEVICE_MAPPER_STRING; - } else { - item->comment = "Not a disk device"; - } + item->comment = "Not a disk device"; return; } @@ -483,6 +566,7 @@ SingleWiperPartition_Open(const char *mountPoint) // IN goto error; } + WiperCollectDiskMajors(); WiperPartitionFilter(p, mnt); (void) CLOSE_MNTFILE(fp); @@ -603,6 +687,8 @@ WiperPartition_Open(void) goto error; } + WiperCollectDiskMajors(); + while (GETNEXT_MNTINFO(fp, mnt)) { WiperPartition item; @@ -996,73 +1082,6 @@ Wiper_Cancel(Wiper_State **s) // IN/OUT Bool Wiper_Init(WiperInitData *clientData) { -#if defined(__linux__) && !defined(N_PLAT_NLM) - FILE *fp; - int deviceNum; - char deviceName[256]; - - dmNumEntries = 0; - fp = Posix_Fopen("/proc/devices", "r"); - if (fp) { - while (!feof(fp)) { - if (fscanf(fp, "%d %255s\n", &deviceNum, deviceName) == 2) { - if (Str_Strncmp(deviceName, "device-mapper", sizeof deviceName) == 0) { - dmNumbers[dmNumEntries++] = deviceNum; - if (dmNumEntries >= WIPER_MAX_DM_NUMBERS) { - break; - } - } - } else if (fgets(deviceName, sizeof deviceName, fp) != deviceName) { - Warning("%s: Error reading device name from /proc/devices.", __func__); - break; - } - } - - fclose(fp); - } -#endif - return initDone = TRUE; } - -/* - *---------------------------------------------------------------------------- - * - * WiperIsDeviceMapper -- - * - * Determines whether a partition's device id corresponds to - * the device-mapper device. - * - * Results: - * TRUE if the device number matches a device-mapper device number - * FALSE otherwise - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static INLINE Bool -WiperIsDeviceMapper(struct stat *s) // IN -{ -#if defined(__linux__) && !defined(N_PLAT_NLM) - int majorNumber; - int i; - - ASSERT(s); - - majorNumber = major(s->st_rdev); - - for (i = 0; i < dmNumEntries; ++i) { - if (majorNumber == dmNumbers[i]) { - return TRUE; - } - } - - return FALSE; -#else - return FALSE; -#endif -} diff --git a/open-vm-tools/libguestlib/Makefile.am b/open-vm-tools/libguestlib/Makefile.am index 65d9d9a0a..642c953b7 100644 --- a/open-vm-tools/libguestlib/Makefile.am +++ b/open-vm-tools/libguestlib/Makefile.am @@ -30,3 +30,19 @@ libguestlib_la_LDFLAGS = # We require GCC, so we're fine passing compiler-specific flags. # Needed for OS's that don't link shared libraries against libc by default, e.g. FreeBSD libguestlib_la_LDFLAGS += -Wl,-lc + +libguestlib_includedir = $(includedir)/vmGuestLib + +libguestlib_include_HEADERS = +libguestlib_include_HEADERS += $(top_srcdir)/lib/include/includeCheck.h +libguestlib_include_HEADERS += $(top_srcdir)/lib/include/vmGuestLib.h +libguestlib_include_HEADERS += $(top_srcdir)/lib/include/vmSessionId.h +libguestlib_include_HEADERS += $(top_srcdir)/lib/include/vm_basic_types.h + +EXTRA_DIST = vmguestlib.pc.in + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = vmguestlib.pc + +$(pkgconfig_DATA): $(top_builddir)/config.status + diff --git a/open-vm-tools/libguestlib/vmguestlib.pc.in b/open-vm-tools/libguestlib/vmguestlib.pc.in new file mode 100644 index 000000000..815d897a2 --- /dev/null +++ b/open-vm-tools/libguestlib/vmguestlib.pc.in @@ -0,0 +1,11 @@ +# VMware GuestLib pkgconfig data. + +libdir=@libdir@ +includedir=@includedir@ + +Name: VMware GuestLib +Description: Library for retrieving information from VMware hosts. +Version: @VERSION@ +Libs: -L${libdir} -lguestlib +Cflags: -I${includedir}/vmGuestLib + diff --git a/open-vm-tools/libvmtools/vmtoolsConfig.c b/open-vm-tools/libvmtools/vmtoolsConfig.c index b279d2c8d..f41408f90 100644 --- a/open-vm-tools/libvmtools/vmtoolsConfig.c +++ b/open-vm-tools/libvmtools/vmtoolsConfig.c @@ -241,7 +241,7 @@ VMTools_LoadConfig(const gchar *path, goto exit; } - if (!File_IsFile(path)) { + if (!File_IsFile(path) || File_GetSizeByPath(path) == 0) { goto exit; } diff --git a/open-vm-tools/modules/freebsd/vmhgfs/vnopscommon.c b/open-vm-tools/modules/freebsd/vmhgfs/vnopscommon.c index 0d19328ff..cfe4d1fbc 100644 --- a/open-vm-tools/modules/freebsd/vmhgfs/vnopscommon.c +++ b/open-vm-tools/modules/freebsd/vmhgfs/vnopscommon.c @@ -333,8 +333,28 @@ HgfsReaddirInt(struct vnode *vp, // IN : Directory vnode to get entries from. /* If the filename was too long, we skip to the next entry ... */ if (ret == EOVERFLOW) { continue; - /* ... but if another error occurred, we return that error code ... */ + } else if (ret == EBADF) { + /* + * If we got invalid handle from the server, this was because user + * enabled/disabled the shared folders. We should get a new handle + * from the server, now. + */ + ret = HgfsRefreshHandle(vp, sip, &handle); + if (ret == 0) { + /* + * Now we have valid handle, let's try again from the same + * offset. + */ + offset--; + continue; + } else { + ret = EBADF; + goto out; + } } else if (ret) { + if (ret != EPROTO) { + ret = EINVAL; + } DEBUG(VM_DEBUG_FAIL, "failure occurred in HgfsGetNextDirEntry\n"); goto out; /* @@ -348,13 +368,13 @@ HgfsReaddirInt(struct vnode *vp, // IN : Directory vnode to get entries from. } break; } - /* + /* * Convert an input string to utf8 decomposed form and then escape its * buffer. */ ret = HgfsNameFromWireEncoding(nameBuf, strlen(nameBuf), dirp->d_name, sizeof dirp->d_name); - /* + /* * If the name didn't fit in the buffer or illegal utf8 characters * were encountered, skip to the next entry. */ @@ -536,7 +556,7 @@ HgfsSetattrInt(struct vnode *vp, // IN : vnode of the file reqSize = HGFS_REQ_PAYLOAD_SIZE_V3(request); reqBufferSize = HGFS_NAME_BUFFER_SIZET(reqSize); - /* + /* * Convert an input string to utf8 precomposed form, convert it to * the cross platform name format and finally unescape any illegal * filesystem characters. @@ -1644,11 +1664,11 @@ HgfsFileOpen(HgfsSuperInfo *sip, // IN: Superinfo pointer * mainly implemented to address the issue with Mac OS. When the user * attempts to create a file in the root folder, the server returns ENOENT * error code. However, Mac OS specifically checks for this case. If Mac OS asks for - * the creation of a new file and if it gets ENOENT as a return error code, + * the creation of a new file and if it gets ENOENT as a return error code, * then it assumes that the error was because of some race condition and tries it * again. Thus, returning ENOENT to the Mac OS puts the guest kernel into infinite * loop. In order to resolve this issue, before passing on the request to the - * server, we validate if user is attempting to create a new share. If yes, + * server, we validate if user is attempting to create a new share. If yes, * we return EPERM as the error code. */ if (HgfsAttemptToCreateShare(HGFS_VP_TO_FILENAME(vp), flag)) { @@ -1730,17 +1750,29 @@ HgfsRefreshHandle(struct vnode *vp, // IN: Vnode of file to open fp = HGFS_VP_TO_FP(vp); ASSERT(fp); + DEBUG(VM_DEBUG_ENTRY, "Refresh handle\n"); os_rw_lock_lock_exclusive(fp->handleLock); if (fp->handle != *handle) { /* Handle has been refreshed in another thread. */ *handle = fp->handle; } else { /* Retrieve a new handle from the host. */ - ret = HgfsRequestHostFileHandle(sip, vp, (int *)&fp->mode, HGFS_OPEN, 0, handle); + if (HGFS_VP_TO_VTYPE(vp) == VREG) { + ret = HgfsRequestHostFileHandle(sip, vp, (int *)&fp->mode, + HGFS_OPEN, 0, handle); + } else if (HGFS_VP_TO_VTYPE(vp) == VDIR) { + char *fullPath = HGFS_VP_TO_FILENAME(vp); + uint32 fullPathLen = HGFS_VP_TO_FILENAME_LENGTH(vp); + ret = HgfsSendOpenDirRequest(sip, fullPath, fullPathLen, handle); + } else { + goto out; + } if (ret == 0) { fp->handle = *handle; } } + +out: os_rw_lock_unlock_exclusive(fp->handleLock); return ret; @@ -2278,9 +2310,6 @@ HgfsGetNextDirEntry(HgfsSuperInfo *sip, // IN: Superinfo pointer ret = HgfsGetStatus(req, sizeof *replyHeader); if (ret) { DEBUG(VM_DEBUG_FAIL, "Error encountered with ret = %d\n", ret); - if (ret != EPROTO) { - ret = EINVAL; - } goto destroyOut; } @@ -2530,7 +2559,7 @@ HgfsSymlinkInt(struct vnode *dvp, // IN : directory vnode * In the long term we should fix the protocol and have only one name * format which is suitable for all names. * The following code compensates for this problem before there is such - * universal name representation. + * universal name representation. */ if (*targetName == '/') { fileNameP->length = 1; diff --git a/open-vm-tools/modules/linux/dkms.conf b/open-vm-tools/modules/linux/dkms.conf index bdf10da70..664dc479e 100644 --- a/open-vm-tools/modules/linux/dkms.conf +++ b/open-vm-tools/modules/linux/dkms.conf @@ -1,23 +1,29 @@ PACKAGE_NAME=open-vm-tools -PACKAGE_VERSION=2009.06.18 -MAKE[0]="make -C pvscsi VM_UNAME=\$kernelver; \ - make -C vmblock VM_UNAME=\$kernelver; \ - make -C vmhgfs VM_UNAME=\$kernelver; \ - make -C vmmemctl VM_UNAME=\$kernelver; \ - make -C vmsync VM_UNAME=\$kernelver; \ - make -C vmxnet VM_UNAME=\$kernelver; \ - make -C vsock VM_UNAME=\$kernelver; \ - make -C vmci VM_UNAME=\$kernelver; \ - make -C vmxnet3 VM_UNAME=\$kernelver" -CLEAN[0]="make -C pvscsi clean; \ - make -C vmblock clean; \ - make -C vmhgfs clean; \ - make -C vmmemctl clean; \ - make -C vmsync clean; \ - make -C vmxnet clean; \ - make -C vsock clean; \ - make -C vmci clean; \ - make -C vmxnet3 clean" +PACKAGE_VERSION=2009.07.22 +MAKE_CMD_TMPL="make VM_UNAME=\$kernelver \ + MODULEBUILDDIR=$dkms_tree/$PACKAGE_NAME/$PACKAGE_VERSION/build" + +# The vsock module depends on symbols exported by the vmci module, so it +# needs to be built afterwards; the MODULEBUILDDIR variable tells the makefiles +# where to store / retrive those symbol files. +MAKE[0]="$MAKE_CMD_TMPL -C pvscsi; \ + $MAKE_CMD_TMPL -C vmblock; \ + $MAKE_CMD_TMPL -C vmci; \ + $MAKE_CMD_TMPL -C vmhgfs; \ + $MAKE_CMD_TMPL -C vmmemctl; \ + $MAKE_CMD_TMPL -C vmsync; \ + $MAKE_CMD_TMPL -C vmxnet; \ + $MAKE_CMD_TMPL -C vmxnet3; \ + $MAKE_CMD_TMPL -C vsock" +CLEAN[0]="$MAKE_CMD_TMPL -C pvscsi clean; \ + $MAKE_CMD_TMPL -C vmblock clean; \ + $MAKE_CMD_TMPL -C vmci clean; \ + $MAKE_CMD_TMPL -C vmhgfs clean; \ + $MAKE_CMD_TMPL -C vmmemctl clean; \ + $MAKE_CMD_TMPL -C vmsync clean"; \ + $MAKE_CMD_TMPL -C vmxnet clean; \ + $MAKE_CMD_TMPL -C vmxnet3 clean; \ + $MAKE_CMD_TMPL -C vsock clean BUILT_MODULE_NAME[0]="pvscsi" BUILT_MODULE_NAME[1]="vmblock" BUILT_MODULE_NAME[2]="vmci" diff --git a/open-vm-tools/modules/linux/dkms.sh b/open-vm-tools/modules/linux/dkms.sh new file mode 100644 index 000000000..4513e8e8b --- /dev/null +++ b/open-vm-tools/modules/linux/dkms.sh @@ -0,0 +1,116 @@ +#!/bin/sh +################################################################################ +### Copyright 2009 VMware, Inc. All rights reserved. +### +### Script for creating a dmks-compliant source tree from an open-vm-tools +### distribution. +### +### +### 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 +################################################################################ + +if test -z "$1" -o -z "$2" +then + echo "usage: $0 src dst" + echo + echo "Where:" + 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." + exit 1 +fi + +src=$1 +dst=$2/open-vm-tools-2009.07.22 + +SHARED_HEADERS="backdoor_def.h" +SHARED_HEADERS="$SHARED_HEADERS backdoor_types.h" +SHARED_HEADERS="$SHARED_HEADERS circList.h" +SHARED_HEADERS="$SHARED_HEADERS dbllnklst.h" +SHARED_HEADERS="$SHARED_HEADERS guest_msg_def.h" +SHARED_HEADERS="$SHARED_HEADERS includeCheck.h" +SHARED_HEADERS="$SHARED_HEADERS vm_assert.h" +SHARED_HEADERS="$SHARED_HEADERS vm_atomic.h" +SHARED_HEADERS="$SHARED_HEADERS vm_basic_asm.h" +SHARED_HEADERS="$SHARED_HEADERS vm_basic_asm_x86.h" +SHARED_HEADERS="$SHARED_HEADERS vm_basic_asm_x86_64.h" +SHARED_HEADERS="$SHARED_HEADERS vm_basic_defs.h" +SHARED_HEADERS="$SHARED_HEADERS vm_basic_math.h" +SHARED_HEADERS="$SHARED_HEADERS vm_basic_types.h" +SHARED_HEADERS="$SHARED_HEADERS vm_device_version.h" +SHARED_HEADERS="$SHARED_HEADERS vmci_sockets.h" +SHARED_HEADERS="$SHARED_HEADERS vmware.h" +SHARED_HEADERS="$SHARED_HEADERS vmware_pack_begin.h" +SHARED_HEADERS="$SHARED_HEADERS vmware_pack_end.h" +SHARED_HEADERS="$SHARED_HEADERS vmware_pack_init.h" +SHARED_HEADERS="$SHARED_HEADERS x86cpuid.h" + +rm -rf $dst +mkdir -p $dst +cp -f `dirname $0`/dkms.conf $dst + +for m in pvscsi vmblock vmci vmhgfs vmmemctl vmsync vmxnet vmxnet3 vsock +do + mdst="$dst/$m" + + cp -rf $src/modules/linux/$m $mdst + cp -rf $src/modules/linux/shared $mdst + for h in $SHARED_HEADERS + do + cp -f $src/lib/include/$h $mdst/shared + done + + # Shared vmblock code. + if test $m = vmblock + then + cp -f $src/lib/include/vmblock.h $mdst/linux + cp -f $src/lib/misc/dbllnklst.c $mdst/linux + cp -rf $src/modules/shared/vmblock/* $mdst/linux + fi + + # Backdoor library (for vmhgfs and vmmemctl). + if test $m = vmhgfs -o $m = vmmemctl + then + cp -f $src/lib/include/backdoor.h $mdst + cp -f $src/lib/backdoor/*.c $src/lib/backdoor/*.h $mdst + fi + + # Other libraries used by vmhgfs + if test $m = vmhgfs + then + cp -f $src/lib/include/cpName*.h $mdst + cp -f $src/lib/include/escBitvector.h $mdst + cp -f $src/lib/include/hgfs*.h $mdst + cp -f $src/lib/include/message.h $mdst + cp -f $src/lib/include/rpcout.h $mdst + cp -f $src/lib/hgfs/*.c $src/lib/hgfs/*.h $mdst + cp -f $src/lib/hgfsBd/*.c $mdst + cp -f $src/lib/message/*.c $mdst + cp -f $src/lib/rpcOut/*.c $mdst + fi + + # Extra header file for vmsync. + if test $m = vmsync + then + cp -f $src/lib/include/syncDriverIoc.h $mdst + fi + + # Shared vmxnet / vmxnet3 headers. + if test $m = vmxnet -o $m = vmxnet3 + then + cp -f $src/modules/shared/vmxnet/* $mdst/shared + fi +done + diff --git a/open-vm-tools/modules/linux/pvscsi/scsi_defs.h b/open-vm-tools/modules/linux/pvscsi/scsi_defs.h index ed6ffca30..642f01340 100644 --- a/open-vm-tools/modules/linux/pvscsi/scsi_defs.h +++ b/open-vm-tools/modules/linux/pvscsi/scsi_defs.h @@ -237,6 +237,7 @@ #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 @@ -410,7 +411,9 @@ typedef struct { 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 +#define SCSI_MODEL_SZ sizeof(((SCSIInquiryResponse *) 0)->product) uint8 revision[4]; // product version number in ascii uint8 vendor1[20]; // vendor unique data (opaque) uint8 reserved[40]; diff --git a/open-vm-tools/modules/linux/shared/compat_sock.h b/open-vm-tools/modules/linux/shared/compat_sock.h index 224541497..b69125016 100644 --- a/open-vm-tools/modules/linux/shared/compat_sock.h +++ b/open-vm-tools/modules/linux/shared/compat_sock.h @@ -22,21 +22,9 @@ #include /* for NULL */ #include - /* * Between 2.5.70 and 2.5.71 all sock members were renamed from XXX to sk_XXX. - * - * VMW_HAVE_SK_WMEM_ALLOC is defined in module Makefile if kernel's struct sock - * has sk_wmem_alloc member. See vmnet's Makefile.kernel for details. - * It also means that all modules including this file should do - * - * EXTRA_CFLAGS += $(call vm_check_build, $(SRCROOT)/socket.c, -DVMW_HAVE_SK_WMEM_ALLOC, ) - * - * in their Makefiles. */ -#ifndef VMW_HAVE_SK_WMEM_ALLOC -# define sk_wmem_alloc wmem_alloc -#endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 71) # define compat_sk_backlog_rcv backlog_rcv diff --git a/open-vm-tools/modules/linux/shared/vmci_kernel_if.h b/open-vm-tools/modules/linux/shared/vmci_kernel_if.h index 1f268534a..198f4daf1 100644 --- a/open-vm-tools/modules/linux/shared/vmci_kernel_if.h +++ b/open-vm-tools/modules/linux/shared/vmci_kernel_if.h @@ -289,15 +289,25 @@ int VMCI_PopulatePPNList(uint8 *callBuf, const PPNSet *ppnSet); struct PageStoreAttachInfo; struct VMCIQueue; -int VMCIHost_GetUserMemory(struct PageStoreAttachInfo *attach); -void VMCIHost_ReleaseUserMemory(struct PageStoreAttachInfo *attach); -int VMCIHost_FinishAttach(struct PageStoreAttachInfo *attach, - struct VMCIQueue *produceQ, - struct VMCIQueue *detachQ); -void VMCIHost_DetachMappings(struct PageStoreAttachInfo *attach, - struct VMCIQueue *produceQ, - struct VMCIQueue *detachQ); -#endif +int VMCIHost_GetUserMemory(struct PageStoreAttachInfo *attach, + struct VMCIQueue *produceQ, + struct VMCIQueue *detachQ); +void VMCIHost_ReleaseUserMemory(struct PageStoreAttachInfo *attach, + struct VMCIQueue *produceQ, + struct VMCIQueue *detachQ); + +#ifdef _WIN32 +/* + * Special routine used on the Windows platform to save a queue when + * its backing memory goes away. + */ + +void VMCIHost_SaveProduceQ(struct PageStoreAttachInfo *attach, + struct VMCIQueue *produceQ, + struct VMCIQueue *detachQ, + const uint64 produceQSize); +#endif // _WIN32 +#endif // !VMX86_TOOLS && !VMKERNEL #endif // _VMCI_KERNEL_IF_H_ diff --git a/open-vm-tools/modules/linux/shared/vmci_queue_pair.h b/open-vm-tools/modules/linux/shared/vmci_queue_pair.h index c1a1fc5bc..be69c284e 100644 --- a/open-vm-tools/modules/linux/shared/vmci_queue_pair.h +++ b/open-vm-tools/modules/linux/shared/vmci_queue_pair.h @@ -65,8 +65,42 @@ struct page; /* + * VMCIQueueHeader + * + * A Queue cannot stand by itself as designed. Each Queue's header + * contains a pointer into itself (the producerTail) and into its peer + * (consumerHead). The reason for the separation is one of + * accessibility: Each end-point can modify two things: where the next + * location to enqueue is within its produceQ (producerTail); and + * where the next location in its consumeQ (i.e., its peer's produceQ) + * it can dequeue (consumerHead). The end-point cannot modify the + * pointers of its peer (guest to guest; NOTE that in the host both + * queue headers are mapped r/w). But, each end-point needs access to + * both Queue header structures in order to determine how much space + * is used (or left) in the Queue. This is because for an end-point + * to know how full its produceQ is, it needs to use the consumerHead + * that points into the produceQ but -that- consumerHead is in the + * Queue header for that end-points consumeQ. + * + * Thoroughly confused? Sorry. + * + * producerTail: the point to enqueue new entrants. When you approach + * a line in a store, for example, you walk up to the tail. + * + * consumerHead: the point in the queue from which the next element is + * dequeued. In other words, who is next in line is he who is at the + * head of the line. + * + * Also, producerTail points to an empty byte in the Queue, whereas + * consumerHead points to a valid byte of data (unless producerTail == + * consumerHead in which case consumerHead does not point to a valid + * byte of data). + * * For a queue of buffer 'size' bytes, the tail and head pointers will be in * the range [0, size-1]. + * + * If produceQ->producerTail == consumeQ->consumerHead then the + * produceQ is empty. */ typedef struct VMCIQueueHeader { @@ -281,15 +315,78 @@ AddPointer(Atomic_uint64 *var, // IN: * Also, the queue contents are managed by an array of bytes * which are managed elsewhere. So, this structure simply * contains the address of that array of bytes. + * + * We have a mutex to protect the queue from accesses within the + * kernel module. NOTE: the guest may be enqueuing or dequeuing + * while the host has the mutex locked. However, multiple + * kernel processes will not access the Queue simultaneously. + * + * What the mutex is trying to protect is the moment where the + * guest detaches from a queue. In that moment, we will + * allocate memory to hold the guest's produceQ and we will + * change the queueHeaderPtr to point to a newly allocated (in + * kernel memory) structure. And, the buffer pointer will be + * changed to point to an in-kernel queue content (even if there + * isn't any data in the queue for the host to consume). + * + * Note that a VMCIQueue allocated by the host passes through + * three states before it's torn down. First, the queue is + * created by the host but doesn't point to any memory and + * therefore can't absorb any enqueue requests. (NOTE: On + * Windows this could be solved because of the mutexes, as + * explained above [only in reverse, if you will]. But unless + * we added the same mutexes [or other rules about accessing the + * queues] we can't can't solve this generally on other + * operating systems.) + * + * When the guest calls SetPageStore(), then the queue is backed + * by valid memory and the host can enqueue. + * + * When the guest detaches, enqueues are absorbed by /dev/null, + * as it were. */ typedef struct VMCIQueue { VMCIQueueHeader *queueHeaderPtr; uint8 *buffer; + Bool enqueueToDevNull; + FAST_MUTEX *mutex; /* Access the mutex through this */ + 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 +#ifndef VMCIQueuePair_EnqueueToDevNull +#define VMCIQueuePair_EnqueueToDevNull(q) (FALSE) +#endif /* default VMCIQueuePair_EnqueueToDevNull() definition */ + +/* + *----------------------------------------------------------------------------- + * + * VMCIMemcpy{To,From}QueueFunc() prototypes. Functions of these + * types are passed around to enqueue and dequeue routines. Note that + * often the functions passed are simply wrappers around memcpy + * itself. + * + *----------------------------------------------------------------------------- + */ +typedef int VMCIMemcpyToQueueFunc(VMCIQueue *queue, uint64 queueOffset, + const void *src, size_t srcOffset, + size_t size); +typedef int VMCIMemcpyFromQueueFunc(void *dest, size_t destOffset, + const VMCIQueue *queue, uint64 queueOffset, + size_t size); + +/* + * NOTE: On Windows host we have special code to access the queue + * contents (and QueuePair header) so that we can protect accesses + * during tear down of the guest that owns the mappings of the + * QueuePair queue contents. See + * bora/modules/vmcrosstalk/windows/vmciHostQueuePair.c + */ + +#if !defined _WIN32 || defined VMX86_TOOLS || defined VMX86_VMX /* *----------------------------------------------------------------------------- @@ -430,23 +527,6 @@ VMCIQueue_AddConsumerHead(VMCIQueue *queue, } -/* - *----------------------------------------------------------------------------- - * - * VMCIMemcpy{To,From}QueueFunc() prototypes. Functions of these - * types are passed around to enqueue and dequeue routines. Note that - * often the functions passed are simply wrappers around memcpy - * itself. - * - *----------------------------------------------------------------------------- - */ -typedef int VMCIMemcpyToQueueFunc(VMCIQueue *queue, uint64 queueOffset, - const void *src, size_t srcOffset, - size_t size); -typedef int VMCIMemcpyFromQueueFunc(void *dest, size_t destOffset, - const VMCIQueue *queue, uint64 queueOffset, - size_t size); - /* *----------------------------------------------------------------------------- * @@ -825,6 +905,10 @@ __VMCIQueue_Enqueue(VMCIQueue *produceQueue, // IN: uint64 tail; size_t written; + if (UNLIKELY(VMCIQueuePair_EnqueueToDevNull(produceQueue))) { + return bufSize; + } + if (UNLIKELY(!VMCIQueuePair_QueueIsMapped(produceQueue) && !VMCIQueuePair_QueueIsMapped(consumeQueue))) { return VMCI_ERROR_QUEUEPAIR_NOTATTACHED; @@ -920,7 +1004,7 @@ VMCIQueue_EnqueueV(VMCIQueue *produceQueue, // IN: return __VMCIQueue_Enqueue(produceQueue, consumeQueue, produceQSize, (void *)iov, iovSize, VMCIMemcpyToQueueV); } -#endif +#endif /* Systems that support struct iovec */ /* @@ -1055,7 +1139,7 @@ VMCIQueue_DequeueV(VMCIQueue *produceQueue, // IN: return __VMCIQueue_Dequeue(produceQueue, consumeQueue, consumeQSize, (void *)iov, iovSize, VMCIMemcpyFromQueueV, TRUE); } -#endif +#endif /* Systems that support struct iovec */ /* @@ -1124,6 +1208,42 @@ VMCIQueue_PeekV(VMCIQueue *produceQueue, // IN: return __VMCIQueue_Dequeue(produceQueue, consumeQueue, consumeQSize, (void *)iov, iovSize, VMCIMemcpyFromQueueV, FALSE); } -#endif +#endif /* Systems that support struct iovec */ + +#else /* Windows 32 Host defined below */ + +int VMCIMemcpyToQueue(VMCIQueue *queue, uint64 queueOffset, const void *src, + size_t srcOffset, size_t size); +int VMCIMemcpyFromQueue(void *dest, size_t destOffset, const VMCIQueue *queue, + uint64 queueOffset, size_t size); + +void VMCIQueue_Init(const VMCIHandle handle, VMCIQueue *queue); +void VMCIQueue_GetPointers(const VMCIQueue *produceQ, + const VMCIQueue *consumeQ, + uint64 *producerTail, + uint64 *consumerHead); +int64 VMCIQueue_FreeSpace(const VMCIQueue *produceQueue, + const VMCIQueue *consumeQueue, + const uint64 produceQSize); +int64 VMCIQueue_BufReady(const VMCIQueue *consumeQueue, + const VMCIQueue *produceQueue, + const uint64 consumeQSize); +ssize_t VMCIQueue_Enqueue(VMCIQueue *produceQueue, + const VMCIQueue *consumeQueue, + const uint64 produceQSize, + const void *buf, + size_t bufSize); +ssize_t VMCIQueue_Dequeue(VMCIQueue *produceQueue, + const VMCIQueue *consumeQueue, + const uint64 consumeQSize, + void *buf, + size_t bufSize); +ssize_t VMCIQueue_Peek(VMCIQueue *produceQueue, + const VMCIQueue *consumeQueue, + const uint64 consumeQSize, + void *buf, + size_t bufSize); + +#endif /* defined _WIN32 && !defined VMX86_TOOLS */ #endif /* !_PUBLIC_VMCI_QUEUE_PAIR_H_ */ diff --git a/open-vm-tools/modules/linux/vmci/vmciKernelIf.c b/open-vm-tools/modules/linux/vmci/vmciKernelIf.c index 9e7d3360a..cc2de6acc 100644 --- a/open-vm-tools/modules/linux/vmci/vmciKernelIf.c +++ b/open-vm-tools/modules/linux/vmci/vmciKernelIf.c @@ -1394,95 +1394,6 @@ VMCIWellKnownID_AllowMap(VMCIId wellKnownID, // IN: #ifndef VMX86_TOOLS -/* - *----------------------------------------------------------------------------- - * - * VMCIHost_FinishAttach -- - - * Finish the "attach" operation by update the queues to be - * backed by the shared memory represented by the "attach" - * structure. - * - * Results: - * VMCI_SUCCESS on success or negative error on failure. - * - * Side Effects: - * None - * - *----------------------------------------------------------------------------- - */ - -int -VMCIHost_FinishAttach(PageStoreAttachInfo *attach, // IN - VMCIQueue *produceQ, // OUT - VMCIQueue *consumeQ) // OUT -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) - produceQ->queueHeaderPtr = kmap(attach->producePages[0]); - produceQ->page = &attach->producePages[1]; - consumeQ->queueHeaderPtr = kmap(attach->consumePages[0]); - consumeQ->page = &attach->consumePages[1]; -#else - /* - * Host queue pair support for earlier kernels temporarily - * disabled. See bug 365496. - */ - - ASSERT_NOT_IMPLEMENTED(FALSE); -#if 0 - produceQ->queueHeaderPtr = kmap(attach->produceIoBuf->maplist[0]); - produceQ->page = &attach->produceIoBuf->maplist[1]; - consumeQ->queueHeaderPtr = kmap(attach->consumeIoBuf->maplist[0]); - consumeQ->page = &attach->consumeIoBuf->maplist[1]; -#endif -#endif - - return VMCI_SUCCESS; -} - - -/* - *----------------------------------------------------------------------------- - * - * VMCIHost_DetachMappings -- - * Remove any local mappings of memory referenced in 'attach' in - * preparation for releasing the shared memory region entirely. - * - * Results: - * None. - * - * Side Effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -void -VMCIHost_DetachMappings(struct PageStoreAttachInfo *attach, - struct VMCIQueue *produceQ, - struct VMCIQueue *detachQ) -{ - /* - * Unmap the header pages - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) - kunmap(attach->producePages[0]); - kunmap(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]); -#endif -#endif -} - - /* *----------------------------------------------------------------------------- * @@ -1501,7 +1412,9 @@ VMCIHost_DetachMappings(struct PageStoreAttachInfo *attach, */ int -VMCIHost_GetUserMemory(PageStoreAttachInfo *attach) // IN/OUT +VMCIHost_GetUserMemory(PageStoreAttachInfo *attach, // IN/OUT + VMCIQueue *produceQ, // OUT + VMCIQueue *consumeQ) // OUT { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) int retval; @@ -1563,6 +1476,13 @@ VMCIHost_GetUserMemory(PageStoreAttachInfo *attach) // IN/OUT err = VMCI_ERROR_NO_MEM; } + if (err == VMCI_SUCCESS) { + produceQ->queueHeaderPtr = kmap(attach->producePages[0]); + produceQ->page = &attach->producePages[1]; + consumeQ->queueHeaderPtr = kmap(attach->consumePages[0]); + consumeQ->page = &attach->consumePages[1]; + } + out: up_write(¤t->mm->mmap_sem); @@ -1620,6 +1540,13 @@ errorDealloc: 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) { @@ -1632,11 +1559,12 @@ out: sizeof *attach->consumeIoBuf); } } + return err; -#else +#else // 0 -- Instead just return FALSE return FALSE; -#endif -#endif +#endif // 0 +#endif // Linux version >= 2.6.0 } @@ -1658,7 +1586,9 @@ out: */ void -VMCIHost_ReleaseUserMemory(PageStoreAttachInfo *attach) // IN +VMCIHost_ReleaseUserMemory(PageStoreAttachInfo *attach, // IN/OUT + VMCIQueue *produceQ, // OUT + VMCIQueue *consumeQ) // OUT { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) @@ -1666,6 +1596,10 @@ VMCIHost_ReleaseUserMemory(PageStoreAttachInfo *attach) // IN ASSERT(attach->producePages); ASSERT(attach->consumePages); + + kunmap(attach->producePages[0]); + kunmap(attach->consumePages[0]); + for (i = 0; i < attach->numProducePages; i++) { ASSERT(attach->producePages[i]); @@ -1694,6 +1628,9 @@ VMCIHost_ReleaseUserMemory(PageStoreAttachInfo *attach) // IN 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); diff --git a/open-vm-tools/modules/linux/vmhgfs/bdhandler.c b/open-vm-tools/modules/linux/vmhgfs/bdhandler.c index 1fa9840a0..0111e4df5 100644 --- a/open-vm-tools/modules/linux/vmhgfs/bdhandler.c +++ b/open-vm-tools/modules/linux/vmhgfs/bdhandler.c @@ -160,11 +160,10 @@ HgfsBdChannelSend(HgfsTransportChannel *channel, // IN: Channel ret = HgfsBd_Dispatch(channel->priv, HGFS_REQ_PAYLOAD(req), &payloadSize, &replyPacket); if (ret == 0) { + LOG(8, ("VMware hgfs: %s: Backdoor reply received.\n", __func__)); /* Request sent successfully. Copy the reply and wake the client. */ ASSERT(replyPacket); HgfsCompleteReq(req, replyPacket, payloadSize); - LOG(8, (KERN_DEBUG "VMware hgfs: HgfsSendUnsentReqs: Backdoor " - "reply received\n")); } else { channel->priv = NULL; channel->status = HGFS_CHANNEL_NOTCONNECTED; diff --git a/open-vm-tools/modules/linux/vmhgfs/request.c b/open-vm-tools/modules/linux/vmhgfs/request.c index cbb80d77d..344e78907 100644 --- a/open-vm-tools/modules/linux/vmhgfs/request.c +++ b/open-vm-tools/modules/linux/vmhgfs/request.c @@ -73,6 +73,7 @@ HgfsGetNewRequest(void) "can't allocate memory\n")); return NULL; } + INIT_LIST_HEAD(&req->list); init_waitqueue_head(&req->queue); req->payloadSize = 0; req->state = HGFS_REQ_STATE_ALLOCATED; diff --git a/open-vm-tools/modules/linux/vmhgfs/tcp.c b/open-vm-tools/modules/linux/vmhgfs/tcp.c index 4ed83a16f..82743a104 100644 --- a/open-vm-tools/modules/linux/vmhgfs/tcp.c +++ b/open-vm-tools/modules/linux/vmhgfs/tcp.c @@ -277,17 +277,15 @@ HgfsTcpConnect(HgfsTransportChannel *channel) addr.sin_addr.s_addr = in_aton(HOST_IP); addr.sin_port = htons(HOST_PORT); - error = compat_sock_create_kern(AF_INET, SOCK_STREAM, IPPROTO_TCP, - &sock); + error = compat_sock_create_kern(AF_INET, SOCK_STREAM, IPPROTO_TCP, &sock); if (error >= 0) { error = sock->ops->connect(sock, (struct sockaddr *)&addr, sizeof addr, 0); if (error >= 0) { channel->priv = sock; - /* Reset receive buffer when a new connection is connected. */ - recvBuffer.state = HGFS_TCP_CONN_RECV_HEADER; - + HgfsTcpResetRecvBuffer(); + sock->sk->compat_sk_rcvtimeo = HGFS_SOCKET_RECV_TIMEOUT * HZ; channel->status = HGFS_CHANNEL_CONNECTED; LOG(8, ("%s: tcp channel connected.\n", __func__)); ret = TRUE; @@ -336,18 +334,15 @@ HgfsVSocketConnect(HgfsTransportChannel *channel) addr.svm_cid = VMCI_HOST_CONTEXT_ID; addr.svm_port = HOST_VSOCKET_PORT; - error = compat_sock_create_kern(family, SOCK_STREAM, 0, - &sock); + error = compat_sock_create_kern(family, SOCK_STREAM, 0, &sock); if (error >= 0) { error = sock->ops->connect(sock, (struct sockaddr *)&addr, sizeof addr, 0); if (error >= 0) { channel->priv = sock; - /* Reset receive buffer when a new connection is connected. */ HgfsTcpResetRecvBuffer(); sock->sk->compat_sk_rcvtimeo = HGFS_SOCKET_RECV_TIMEOUT * HZ; - channel->status = HGFS_CHANNEL_CONNECTED; LOG(8, ("%s: vsocket channel connected.\n", __func__)); ret = TRUE; diff --git a/open-vm-tools/modules/linux/vmxnet/vmxnet.c b/open-vm-tools/modules/linux/vmxnet/vmxnet.c index e1cecce52..a8e040271 100644 --- a/open-vm-tools/modules/linux/vmxnet/vmxnet.c +++ b/open-vm-tools/modules/linux/vmxnet/vmxnet.c @@ -878,6 +878,21 @@ static int vmxnet_probe_device(struct pci_dev *pdev, // IN: vmxnet PCI device const struct pci_device_id *id) // IN: matching device ID { +#ifdef HAVE_NET_DEVICE_OPS + static const struct net_device_ops vmxnet_netdev_ops = { + .ndo_open = &vmxnet_open, + .ndo_start_xmit = &vmxnet_start_tx, + .ndo_stop = &vmxnet_close, + .ndo_get_stats = &vmxnet_get_stats, + .ndo_set_multicast_list = &vmxnet_set_multicast_list, + .ndo_change_mtu = &vmxnet_change_mtu, +# ifdef VMW_HAVE_POLL_CONTROLLER + .ndo_poll_controller = vmxnet_netpoll, +# endif + .ndo_set_mac_address = &vmxnet_set_mac_address, + .ndo_tx_timeout = &vmxnet_tx_timeout, + }; +#endif /* HAVE_NET_DEVICE_OPS */ struct Vmxnet_Private *lp; struct net_device *dev; unsigned int ioaddr, reqIOAddr, reqIOSize; @@ -982,6 +997,9 @@ vmxnet_probe_device(struct pci_dev *pdev, // IN: vmxnet PCI device dev->irq = irq_line; +#ifdef HAVE_NET_DEVICE_OPS + dev->netdev_ops = &vmxnet_netdev_ops; +#else dev->open = &vmxnet_open; dev->hard_start_xmit = &vmxnet_start_tx; dev->stop = &vmxnet_close; @@ -992,14 +1010,17 @@ vmxnet_probe_device(struct pci_dev *pdev, // IN: vmxnet PCI device #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,43) dev->tx_timeout = &vmxnet_tx_timeout; - dev->watchdog_timeo = VMXNET_WATCHDOG_TIMEOUT; #endif #ifdef VMW_HAVE_POLL_CONTROLLER dev->poll_controller = vmxnet_netpoll; #endif - /* Do this after ether_setup(), which sets the default value. */ dev->set_mac_address = &vmxnet_set_mac_address; +#endif /* HAVE_NET_DEVICE_OPS */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,43) + dev->watchdog_timeo = VMXNET_WATCHDOG_TIMEOUT; +#endif #ifdef SET_ETHTOOL_OPS SET_ETHTOOL_OPS(dev, &vmxnet_ethtool_ops); diff --git a/open-vm-tools/modules/linux/vmxnet3/Makefile.kernel b/open-vm-tools/modules/linux/vmxnet3/Makefile.kernel index 30d033005..dd6922d75 100644 --- a/open-vm-tools/modules/linux/vmxnet3/Makefile.kernel +++ b/open-vm-tools/modules/linux/vmxnet3/Makefile.kernel @@ -34,6 +34,8 @@ EXTRA_CFLAGS += $(call vm_check_build, $(AUTOCONF_DIR)/netif_num_params.c, , -DV obj-m += $(DRIVER).o +$(DRIVER)-y := $(subst $(SRCROOT)/, , $(patsubst %.c, %.o, $(wildcard $(SRCROOT)/*.c))) + clean: rm -rf $(wildcard $(DRIVER).mod.c $(DRIVER).ko .tmp_versions \ Module.symvers Modules.symvers Module.markers modules.order \ diff --git a/open-vm-tools/modules/linux/vmxnet3/vmxnet3.c b/open-vm-tools/modules/linux/vmxnet3/vmxnet3_drv.c similarity index 94% rename from open-vm-tools/modules/linux/vmxnet3/vmxnet3.c rename to open-vm-tools/modules/linux/vmxnet3/vmxnet3_drv.c index b3bff15ce..57ef1627a 100644 --- a/open-vm-tools/modules/linux/vmxnet3/vmxnet3.c +++ b/open-vm-tools/modules/linux/vmxnet3/vmxnet3_drv.c @@ -38,6 +38,7 @@ #include "compat_spinlock.h" #include "compat_ioport.h" #include "compat_pci.h" +#include "compat_highmem.h" #include "compat_init.h" #include "compat_timer.h" #include "compat_netdevice.h" @@ -48,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -67,14 +69,8 @@ #include "vm_device_version.h" #include "vmxnet3_version.h" -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) && !defined(VMXNET3_NO_NAPI) -# define VMXNET3_NAPI -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) -# define VMXNET3_NEW_NAPI -#endif -#endif - #include "vmxnet3_int.h" +#include "vmxnet3_shm.h" #ifdef VLAN_GROUP_ARRAY_SPLIT_PARTS # define compat_vlan_group_get_device(vlan_grp, vid) vlan_group_get_device(vlan_grp, vid) @@ -84,17 +80,6 @@ # define compat_vlan_group_set_device(vlan_grp, vid, dev) ((vlan_grp)->vlan_devices[(vid)] = (dev)) #endif -#ifdef VMX86_DEBUG -# define VMXNET3_ASSERT(cond) BUG_ON(!(cond)) -#else -# define VMXNET3_ASSERT(cond) do {} while (0) -#endif - -#ifdef VMXNET3_DO_LOG -# define VMXNET3_LOG(msg...) printk(KERN_ERR msg) -#else -# define VMXNET3_LOG(msg...) -#endif #ifdef VMXNET3_NAPI # ifdef VMX86_DEBUG @@ -156,6 +141,15 @@ static struct pci_driver vmxnet3_driver = { }; static int disable_lro; +static int devices_found; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 2) +static unsigned int num_enable_shm; +#endif +#define VMXNET3_SHM_MAX_DEVICES 10 +static int enable_shm[VMXNET3_SHM_MAX_DEVICES + 1] = + { [0 ... VMXNET3_SHM_MAX_DEVICES] = -1 }; +static char *shm_disclaimer = NULL; +#define VMXNET3_SHM_DISCLAIMER "IReallyWantThisModeIAmAVMSafePartner" /* *---------------------------------------------------------------------------- @@ -713,15 +707,16 @@ static void vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx, struct vmxnet3_tx_queue *tq, - struct pci_dev *pdev) + struct pci_dev *pdev, + struct vmxnet3_adapter *adapter) { uint32 dw2, len; - char *buf; + unsigned long buf_offset; int i; Vmxnet3_GenericDesc *gdesc; struct vmxnet3_tx_buf_info *tbi = NULL; - VMXNET3_ASSERT(ctx->copy_size <= compat_skb_headlen(skb)); + VMXNET3_ASSERT(ctx->copy_size <= vmxnet3_skb_headlen(adapter, skb)); /* use the previous gen bit for the SOP desc */ dw2 = (tq->tx_ring.gen ^ 0x1) << VMXNET3_TXD_GEN_SHIFT; @@ -751,8 +746,8 @@ vmxnet3_map_pkt(struct sk_buff *skb, } /* linear part can use multiple tx desc if it's big */ - len = compat_skb_headlen(skb) - ctx->copy_size; - buf = skb->data + ctx->copy_size; + len = vmxnet3_skb_headlen(adapter, skb) - ctx->copy_size; + buf_offset = ctx->copy_size; while (len) { uint32 buf_size; @@ -760,8 +755,9 @@ vmxnet3_map_pkt(struct sk_buff *skb, tbi = tq->buf_info + tq->tx_ring.next2fill; tbi->map_type = VMXNET3_MAP_SINGLE; - tbi->dma_addr = pci_map_single(pdev, buf, - buf_size, PCI_DMA_TODEVICE); + tbi->dma_addr = vmxnet3_map_single(adapter, skb, buf_offset, + buf_size, PCI_DMA_TODEVICE); + tbi->len = buf_size; /* this automatically convert 2^14 to 0 */ gdesc = tq->tx_ring.base + tq->tx_ring.next2fill; @@ -777,7 +773,15 @@ vmxnet3_map_pkt(struct sk_buff *skb, dw2 = tq->tx_ring.gen << VMXNET3_TXD_GEN_SHIFT; len -= buf_size; - buf += buf_size; + buf_offset += buf_size; + + if (adapter->is_shm) { + /* + * The linear region of the skb is never larger than a page, so + * it always fits into one descriptor. + */ + VMXNET3_ASSERT(len == 0); + } } for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { @@ -785,8 +789,10 @@ vmxnet3_map_pkt(struct sk_buff *skb, tbi = tq->buf_info + tq->tx_ring.next2fill; tbi->map_type = VMXNET3_MAP_PAGE; - tbi->dma_addr = pci_map_page(pdev, frag->page, frag->page_offset, - frag->size, PCI_DMA_TODEVICE); + tbi->dma_addr = vmxnet3_map_page(adapter, frag->page, + frag->page_offset, + frag->size, PCI_DMA_TODEVICE); + tbi->len = frag->size; gdesc = tq->tx_ring.base + tq->tx_ring.next2fill; @@ -838,7 +844,8 @@ vmxnet3_map_pkt(struct sk_buff *skb, static int vmxnet3_parse_and_copy_hdr(struct sk_buff *skb, struct vmxnet3_tx_queue *tq, - struct vmxnet3_tx_ctx *ctx) + struct vmxnet3_tx_ctx *ctx, + struct vmxnet3_adapter *adapter) { Vmxnet3_TxDataDesc *tdd; @@ -871,15 +878,18 @@ vmxnet3_parse_and_copy_hdr(struct sk_buff *skb, } ctx->copy_size = ctx->eth_ip_hdr_size + ctx->l4_hdr_size; } else { - ctx->eth_ip_hdr_size = 14; + ctx->eth_ip_hdr_size = 0; ctx->l4_hdr_size = 0; /* copy as much as allowed */ - ctx->copy_size = min((unsigned int)VMXNET3_HDR_COPY_SIZE, skb_headlen(skb)); + ctx->copy_size = min((unsigned int)VMXNET3_HDR_COPY_SIZE, + vmxnet3_skb_headlen(adapter, skb)); } - /* make sure headers are accessible directly */ - if (UNLIKELY(!compat_pskb_may_pull(skb, ctx->copy_size))) { - goto err; + if (!adapter->is_shm) { + /* make sure headers are accessible directly */ + if (UNLIKELY(!compat_pskb_may_pull(skb, ctx->copy_size))) { + goto err; + } } } @@ -890,10 +900,19 @@ vmxnet3_parse_and_copy_hdr(struct sk_buff *skb, } tdd = tq->data_ring.base + tq->tx_ring.next2fill; - VMXNET3_ASSERT(ctx->copy_size <= compat_skb_headlen(skb)); + VMXNET3_ASSERT(ctx->copy_size <= vmxnet3_skb_headlen(adapter, skb)); - memcpy(tdd->data, skb->data, ctx->copy_size); - VMXNET3_LOG("copy %u bytes to dataRing[%u]\n", ctx->copy_size, tq->tx_ring.next2fill); + if (!adapter->is_shm) { + memcpy(tdd->data, skb->data, ctx->copy_size); + } else { + void *virt = kmap(VMXNET3_SHM_IDX2PAGE(adapter->shm, VMXNET3_SHM_SKB_GETIDX(skb))); + memcpy(tdd->data, + virt, + ctx->copy_size); + kunmap(virt); + } + VMXNET3_LOG("copy %u bytes to dataRing[%u]\n", + ctx->copy_size, tq->tx_ring.next2fill); return 1; err: @@ -961,7 +980,7 @@ vmxnet3_prepare_tso(struct sk_buff *skb, *---------------------------------------------------------------------------- */ -static int +int vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq, struct vmxnet3_adapter *adapter, @@ -974,7 +993,8 @@ vmxnet3_tq_xmit(struct sk_buff *skb, Vmxnet3_GenericDesc *gdesc; /* conservatively estimate # of descriptors to use */ - count = VMXNET3_TXD_NEEDED(skb_headlen(skb)) + skb_shinfo(skb)->nr_frags + 1; + count = VMXNET3_TXD_NEEDED(vmxnet3_skb_headlen(adapter, skb)) + + skb_shinfo(skb)->nr_frags + 1; ctx.ipv4 = (skb->protocol == __constant_ntohs(ETH_P_IP)); @@ -990,6 +1010,14 @@ vmxnet3_tq_xmit(struct sk_buff *skb, vmxnet3_prepare_tso(skb, &ctx); } else { if (UNLIKELY(count > VMXNET3_MAX_TXD_PER_PKT)) { + if (UNLIKELY(adapter->is_shm)) { + VMXNET3_ASSERT(count <= VMXNET3_MAX_TXD_PER_PKT_SHM); + if (count > VMXNET3_MAX_TXD_PER_PKT_SHM) { + tq->stats.drop_too_many_frags++; + goto drop_pkt; + } + } + /* non-tso pkts must not use more than VMXNET3_MAX_TXD_PER_PKT entries */ if (compat_skb_linearize(skb) != 0) { tq->stats.drop_too_many_frags++; @@ -998,11 +1026,11 @@ vmxnet3_tq_xmit(struct sk_buff *skb, tq->stats.linearized++; /* recalculate the # of descriptors to use */ - count = VMXNET3_TXD_NEEDED(skb_headlen(skb)) + 1; + count = VMXNET3_TXD_NEEDED(vmxnet3_skb_headlen(adapter, skb)) + 1; } } - ret = vmxnet3_parse_and_copy_hdr(skb, tq, &ctx); + ret = vmxnet3_parse_and_copy_hdr(skb, tq, &ctx, adapter); if (ret >= 0) { VMXNET3_ASSERT(ret > 0 || ctx.copy_size == 0); /* hdrs parsed, check against other limits */ @@ -1036,7 +1064,7 @@ vmxnet3_tq_xmit(struct sk_buff *skb, } /* fill tx descs related to addr & len */ - vmxnet3_map_pkt(skb, &ctx, tq, adapter->pdev); + vmxnet3_map_pkt(skb, &ctx, tq, adapter->pdev, adapter); /* setup the EOP desc */ ctx.eop_txd->dword[3] = VMXNET3_TXD_CQ | VMXNET3_TXD_EOP; @@ -1087,7 +1115,7 @@ hdr_too_big: tq->stats.drop_oversized_hdr++; drop_pkt: tq->stats.drop_total++; - compat_dev_kfree_skb(skb, FREE_WRITE); + vmxnet3_dev_kfree_skb(adapter, skb); return COMPAT_NETDEV_TX_OK; } @@ -1113,6 +1141,11 @@ static int vmxnet3_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { struct vmxnet3_adapter *adapter = compat_netdev_priv(netdev); + + if (adapter->is_shm) { + return vmxnet3_shm_start_tx(skb, netdev); + } + struct vmxnet3_tx_queue *tq = &adapter->tx_queue; return vmxnet3_tq_xmit(skb, tq, adapter, netdev); @@ -1178,7 +1211,8 @@ vmxnet3_unmap_tx_buf(struct vmxnet3_tx_buf_info *tbi, static int vmxnet3_unmap_pkt(uint32 eop_idx, struct vmxnet3_tx_queue *tq, - struct pci_dev *pdev) + struct pci_dev *pdev, + struct vmxnet3_adapter *adapter) { struct sk_buff *skb; int entries = 0; @@ -1206,7 +1240,7 @@ vmxnet3_unmap_pkt(uint32 eop_idx, entries ++; } - compat_dev_kfree_skb_any(skb, FREE_WRITE); + vmxnet3_dev_kfree_skb_any(adapter, skb); return entries; } @@ -1233,7 +1267,8 @@ vmxnet3_tq_tx_complete(struct vmxnet3_tx_queue *tq, gdesc = tq->comp_ring.base + tq->comp_ring.next2proc; while (gdesc->tcd.gen == tq->comp_ring.gen) { - completed += vmxnet3_unmap_pkt(gdesc->tcd.txdIdx, tq, adapter->pdev); + completed += vmxnet3_unmap_pkt(gdesc->tcd.txdIdx, tq, + adapter->pdev, adapter); vmxnet3_comp_ring_adv_next2proc(&tq->comp_ring); gdesc = tq->comp_ring.base + tq->comp_ring.next2proc; @@ -1279,7 +1314,7 @@ vmxnet3_tq_cleanup(struct vmxnet3_tx_queue *tq, vmxnet3_unmap_tx_buf(tbi, adapter->pdev); if (tbi->skb) { - compat_dev_kfree_skb_any(tbi->skb, FREE_WRITE); + vmxnet3_dev_kfree_skb_any(adapter, tbi->skb); tbi->skb = NULL; } vmxnet3_cmd_ring_adv_next2comp(&tq->tx_ring); @@ -1497,15 +1532,18 @@ vmxnet3_rq_alloc_rx_buf(struct vmxnet3_rx_queue *rq, if (rbi->buf_type == VMXNET3_RX_BUF_SKB) { if (rbi->skb == NULL) { - rbi->skb = dev_alloc_skb(rbi->len + COMPAT_NET_IP_ALIGN); + rbi->skb = vmxnet3_dev_alloc_skb(adapter, rbi->len + COMPAT_NET_IP_ALIGN); if (UNLIKELY(rbi->skb == NULL)) { rq->stats.rx_buf_alloc_failure++; break; } - skb_reserve(rbi->skb, COMPAT_NET_IP_ALIGN); rbi->skb->dev = adapter->netdev; - rbi->dma_addr = pci_map_single(adapter->pdev, rbi->skb->data, - rbi->len, PCI_DMA_FROMDEVICE); + + if (!adapter->is_shm) { + skb_reserve(rbi->skb, COMPAT_NET_IP_ALIGN); + } + rbi->dma_addr = vmxnet3_map_single(adapter, rbi->skb, 0, + rbi->len, PCI_DMA_FROMDEVICE); } else { /* rx buffer skipped by the device */ } @@ -1515,13 +1553,14 @@ vmxnet3_rq_alloc_rx_buf(struct vmxnet3_rx_queue *rq, rbi->len == PAGE_SIZE); if (rbi->page == NULL) { - rbi->page = alloc_page(GFP_ATOMIC); + rbi->page = vmxnet3_alloc_page(adapter); if (UNLIKELY(rbi->page == NULL)) { rq->stats.rx_buf_alloc_failure++; break; } - rbi->dma_addr = pci_map_page(adapter->pdev, rbi->page, 0, - PAGE_SIZE, PCI_DMA_FROMDEVICE); + rbi->dma_addr = vmxnet3_map_page(adapter, rbi->page, + 0, PAGE_SIZE, + PCI_DMA_FROMDEVICE); } else { /* rx buffers skipped by the device */ } @@ -1571,7 +1610,8 @@ vmxnet3_append_frag(struct sk_buff *skb, Vmxnet3_RxCompDesc *rcd, struct vmxnet3_rx_buf_info *rbi) { - struct skb_frag_struct *frag = skb_shinfo(skb)->frags + skb_shinfo(skb)->nr_frags; + struct skb_frag_struct *frag = skb_shinfo(skb)->frags + + skb_shinfo(skb)->nr_frags; VMXNET3_ASSERT(skb_shinfo(skb)->nr_frags < MAX_SKB_FRAGS); @@ -1646,7 +1686,8 @@ vmxnet3_rx_csum(struct vmxnet3_adapter *adapter, static void vmxnet3_rx_error(struct vmxnet3_rx_queue *rq, Vmxnet3_RxCompDesc *rcd, - struct vmxnet3_rx_ctx *ctx) + struct vmxnet3_rx_ctx *ctx, + struct vmxnet3_adapter *adapter) { rq->stats.drop_err++; if (!rcd->fcs) { @@ -1654,7 +1695,7 @@ vmxnet3_rx_error(struct vmxnet3_rx_queue *rq, } rq->stats.drop_total++; - compat_dev_kfree_skb_irq(ctx->skb, FREE_WRITE); + vmxnet3_dev_kfree_skb_irq(adapter, ctx->skb); ctx->skb = NULL; } @@ -1730,11 +1771,12 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, ctx->skb = rbi->skb; rbi->skb = NULL; - skb_put(ctx->skb, rcd->len); pci_unmap_single(adapter->pdev, rbi->dma_addr, rbi->len, PCI_DMA_FROMDEVICE); + + vmxnet3_skb_put(adapter, ctx->skb, rcd->len); } else { VMXNET3_ASSERT(ctx->skb != NULL); /* non SOP buffer must be type 1 in most cases */ @@ -1742,11 +1784,12 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, VMXNET3_ASSERT(rxd->btype == VMXNET3_RXD_BTYPE_BODY); if (rcd->len) { - vmxnet3_append_frag(ctx->skb, rcd, rbi); pci_unmap_page(adapter->pdev, rbi->dma_addr, rbi->len, PCI_DMA_FROMDEVICE); + + vmxnet3_append_frag(ctx->skb, rcd, rbi); rbi->page = NULL; } } else { @@ -1767,30 +1810,37 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, skb = ctx->skb; if (rcd->eop) { - skb->len += skb->data_len; - skb->truesize += skb->data_len; - if (UNLIKELY(rcd->err)) { - vmxnet3_rx_error(rq, rcd, ctx); + vmxnet3_rx_error(rq, rcd, ctx, adapter); goto rcd_done; } - vmxnet3_rx_csum(adapter, skb, (Vmxnet3_GenericDesc*)rcd); - skb->protocol = eth_type_trans(skb, adapter->netdev); + if (adapter->is_shm) { + vmxnet3_shm_rx_skb(adapter, skb); -#ifdef VMXNET3_NAPI - if (UNLIKELY(adapter->vlan_grp && rcd->ts)) { - vlan_hwaccel_receive_skb(skb, adapter->vlan_grp, rcd->tci); + wake_up(&adapter->shm->rxq); } else { - netif_receive_skb(skb); - } + skb->len += skb->data_len; + skb->truesize += skb->data_len; + + vmxnet3_rx_csum(adapter, skb, (Vmxnet3_GenericDesc*)rcd); + skb->protocol = eth_type_trans(skb, adapter->netdev); + +#ifdef VMXNET3_NAPI + if (UNLIKELY(adapter->vlan_grp && rcd->ts)) { + vlan_hwaccel_receive_skb(skb, adapter->vlan_grp, rcd->tci); + } else { + netif_receive_skb(skb); + } #else - if (UNLIKELY(adapter->vlan_grp && rcd->ts)) { - vlan_hwaccel_rx(skb, adapter->vlan_grp, rcd->tci); - } else { - netif_rx(skb); - } + if (UNLIKELY(adapter->vlan_grp && rcd->ts)) { + vlan_hwaccel_rx(skb, adapter->vlan_grp, rcd->tci); + } else { + netif_rx(skb); + } #endif + } + adapter->netdev->last_rx = jiffies; ctx->skb = NULL; } @@ -1859,7 +1909,7 @@ vmxnet3_rq_cleanup(struct vmxnet3_rx_queue *rq, rxd->addr, rxd->len, PCI_DMA_FROMDEVICE); - compat_dev_kfree_skb(rq->buf_info[ring_idx][i].skb, FREE_WRITE); + vmxnet3_dev_kfree_skb(adapter, rq->buf_info[ring_idx][i].skb); rq->buf_info[ring_idx][i].skb = NULL; } else if (rxd->btype == VMXNET3_RXD_BTYPE_BODY && rq->buf_info[ring_idx][i].page) { @@ -1867,7 +1917,7 @@ vmxnet3_rq_cleanup(struct vmxnet3_rx_queue *rq, rxd->addr, rxd->len, PCI_DMA_FROMDEVICE); - put_page(rq->buf_info[ring_idx][i].page); + vmxnet3_put_page(adapter, rq->buf_info[ring_idx][i].page); rq->buf_info[ring_idx][i].page = NULL; } } @@ -2836,6 +2886,10 @@ vmxnet3_adjust_rx_ring_size(struct vmxnet3_adapter *adapter) adapter->rx_buf_per_pkt = 1 + (sz + PAGE_SIZE - 1) / PAGE_SIZE; } + if (adapter->is_shm) { + adapter->skb_buf_size = PAGE_SIZE; + } + /* * for simplicity, force the ring0 size to be a multiple of * rx_buf_per_pkt * VMXNET3_RING_SIZE_ALIGN @@ -2927,6 +2981,14 @@ vmxnet3_open(struct net_device *netdev) spin_lock_init(&adapter->tx_queue.tx_lock); + if (adapter->is_shm) { + printk(KERN_INFO "bringing up shared memory vmxnet3 %s\n", netdev->name); + err = vmxnet3_shm_open(adapter, netdev->name); + if (err) { + goto shm_err; + } + } + err = vmxnet3_create_queues(adapter, VMXNET3_DEF_TX_RING_SIZE, VMXNET3_DEF_RX_RING_SIZE, VMXNET3_DEF_RX_RING_SIZE); if (err) { @@ -2946,6 +3008,8 @@ activate_err: vmxnet3_rq_destroy(&adapter->rx_queue, adapter); vmxnet3_tq_destroy(&adapter->tx_queue, adapter); queue_err: + vmxnet3_shm_close(adapter); +shm_err: return err; } @@ -2965,12 +3029,18 @@ vmxnet3_close(struct net_device *netdev) vmxnet3_quiesce_dev(adapter); + if (adapter->is_shm) { + vmxnet3_shm_close(adapter); + } + vmxnet3_rq_destroy(&adapter->rx_queue, adapter); vmxnet3_tq_destroy(&adapter->tx_queue, adapter); COMPAT_NETDEV_MOD_DEC_USE_COUNT; clear_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state); + + return 0; } @@ -4156,6 +4226,24 @@ static int vmxnet3_probe_device(struct pci_dev *pdev, const struct pci_device_id *id) { +#ifdef HAVE_NET_DEVICE_OPS + static const struct net_device_ops vmxnet3_netdev_ops = { + .ndo_open = vmxnet3_open, + .ndo_stop = vmxnet3_close, + .ndo_start_xmit = vmxnet3_xmit_frame, + .ndo_set_mac_address = vmxnet3_set_mac_addr, + .ndo_change_mtu = vmxnet3_change_mtu, + .ndo_get_stats = vmxnet3_get_stats, + .ndo_tx_timeout = vmxnet3_tx_timeout, + .ndo_set_multicast_list = vmxnet3_set_mc, + .ndo_vlan_rx_register = vmxnet3_vlan_rx_register, + .ndo_vlan_rx_add_vid = vmxnet3_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = vmxnet3_vlan_rx_kill_vid, +# ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = vmxnet3_netpoll, +# endif + }; +#endif /* HAVE_NET_DEVICE_OPS */ int err; Bool dma64 = FALSE; /* stupid gcc */ uint32 ver; @@ -4228,35 +4316,52 @@ vmxnet3_probe_device(struct pci_dev *pdev, vmxnet3_declare_features(adapter, dma64); + adapter->dev_number = devices_found; + 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) { + printk(KERN_ERR "Did not activate shm, disclaimer missing\n"); + } else { + adapter->is_shm = TRUE; + } + } + } + vmxnet3_alloc_intr_resources(adapter); vmxnet3_read_mac_addr(adapter, mac); memcpy(netdev->dev_addr, mac, netdev->addr_len); +#ifdef HAVE_NET_DEVICE_OPS + netdev->netdev_ops = &vmxnet3_netdev_ops; +#else netdev->open = vmxnet3_open; netdev->stop = vmxnet3_close; netdev->hard_start_xmit = vmxnet3_xmit_frame; netdev->set_mac_address = vmxnet3_set_mac_addr; netdev->change_mtu = vmxnet3_change_mtu; netdev->get_stats = vmxnet3_get_stats; - SET_ETHTOOL_OPS(netdev, &vmxnet3_ethtool_ops); netdev->tx_timeout = vmxnet3_tx_timeout; - netdev->watchdog_timeo = 5 * HZ; - - COMPAT_INIT_WORK(&adapter->work, vmxnet3_reset_work, adapter); - -#ifdef VMXNET3_NAPI - compat_netif_napi_add(netdev, &adapter->napi, vmxnet3_poll, 64); -#endif - netdev->set_multicast_list = vmxnet3_set_mc; netdev->vlan_rx_register = vmxnet3_vlan_rx_register; netdev->vlan_rx_add_vid = vmxnet3_vlan_rx_add_vid; netdev->vlan_rx_kill_vid = vmxnet3_vlan_rx_kill_vid; - #ifdef CONFIG_NET_POLL_CONTROLLER netdev->poll_controller = vmxnet3_netpoll; #endif +#endif /* HAVE_NET_DEVICE_OPS */ + + netdev->watchdog_timeo = 5 * HZ; + SET_ETHTOOL_OPS(netdev, &vmxnet3_ethtool_ops); + + COMPAT_INIT_WORK(&adapter->work, vmxnet3_reset_work, adapter); + +#ifdef VMXNET3_NAPI + compat_netif_napi_add(netdev, &adapter->napi, vmxnet3_poll, 64); +#endif COMPAT_SET_MODULE_OWNER(netdev); COMPAT_SET_NETDEV_DEV(netdev, &pdev->dev); @@ -4268,6 +4373,7 @@ vmxnet3_probe_device(struct pci_dev *pdev, } set_bit(VMXNET3_STATE_BIT_QUIESCED, &adapter->state); + devices_found++; return 0; err_register: @@ -4364,6 +4470,7 @@ vmxnet3_suspend(struct pci_dev *pdev, pm_message_t state) return 0; } + vmxnet3_disable_all_intrs(adapter); netif_device_detach(netdev); netif_stop_queue(netdev); @@ -4494,6 +4601,7 @@ vmxnet3_resume(struct pci_dev *pdev) pci_enable_wake(pdev, PCI_D0, 0); VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_UPDATE_PMCFG); + vmxnet3_enable_all_intrs(adapter); return 0; } @@ -4564,4 +4672,13 @@ MODULE_VERSION(VMXNET3_DRIVER_VERSION_STRING); */ MODULE_INFO(supported, "external"); module_param(disable_lro, int, 0); - +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 2) +MODULE_PARM(enable_shm, "0-10i"); +#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10) +module_param_array(enable_shm, int, num_enable_shm, 0); +#else +module_param_array(enable_shm, int, &num_enable_shm, 0); +#endif +MODULE_PARM_DESC(enable_shm, "Shared memory enable"); +module_param(shm_disclaimer, charp, 0); +MODULE_PARM_DESC(shm_disclaimer, "Shared memory disclaimer"); diff --git a/open-vm-tools/modules/linux/vmxnet3/vmxnet3_int.h b/open-vm-tools/modules/linux/vmxnet3/vmxnet3_int.h index bbc9d3216..c0c544fde 100644 --- a/open-vm-tools/modules/linux/vmxnet3/vmxnet3_int.h +++ b/open-vm-tools/modules/linux/vmxnet3/vmxnet3_int.h @@ -24,6 +24,13 @@ #include "vmxnet3_defs.h" +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) && !defined(VMXNET3_NO_NAPI) +# define VMXNET3_NAPI +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) +# define VMXNET3_NEW_NAPI +#endif +#endif + typedef struct vmxnet3_cmd_ring { Vmxnet3_GenericDesc *base; uint32 size; @@ -146,6 +153,7 @@ struct vmxnet3_rx_buf_info { union { struct sk_buff *skb; struct page *page; + unsigned long shm_idx; }; dma_addr_t dma_addr; }; @@ -231,6 +239,10 @@ struct vmxnet3_adapter { compat_work work; unsigned long state; /* VMXNET3_STATE_BIT_xxx */ + + int dev_number; + Bool is_shm; + struct vmxnet3_shm_pool *shm; }; struct vmxnet3_stat_desc { @@ -264,3 +276,23 @@ struct vmxnet3_stat_desc { #define VMXNET3_MAX_SKB_BUF_SIZE (3*1024) #endif + +#ifdef VMX86_DEBUG +# define VMXNET3_ASSERT(cond) BUG_ON(!(cond)) +#else +# define VMXNET3_ASSERT(cond) do {} while (0) +#endif + +#ifdef VMXNET3_DO_LOG +# define VMXNET3_LOG(msg...) printk(KERN_ERR msg) +#else +# define VMXNET3_LOG(msg...) +#endif + +// used by vmxnet3_shm_tx_pkt +int +vmxnet3_tq_xmit(struct sk_buff *skb, + struct vmxnet3_tx_queue *tq, + struct vmxnet3_adapter *adapter, + struct net_device *netdev); + diff --git a/open-vm-tools/modules/linux/vmxnet3/vmxnet3_shm.c b/open-vm-tools/modules/linux/vmxnet3/vmxnet3_shm.c new file mode 100644 index 000000000..eee0cf392 --- /dev/null +++ b/open-vm-tools/modules/linux/vmxnet3/vmxnet3_shm.c @@ -0,0 +1,1419 @@ +/********************************************************* + * 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 + * + *********************************************************/ + +/* + * vmxnet3_shm.c -- + * + * Shared memory infrastructure for VMXNET3 linux driver. Used by the + * VMXNET3 driver to back its rings with memory from a shared memory + * pool that is shared with user space. + */ +#include "driver-config.h" + +#include "compat_module.h" +#include + +#include "compat_slab.h" +#include "compat_spinlock.h" +#include "compat_ioport.h" +#include "compat_pci.h" +#include "compat_highmem.h" +#include "compat_init.h" +#include "compat_timer.h" +#include "compat_netdevice.h" +#include "compat_skbuff.h" +#include "compat_interrupt.h" +#include "compat_workqueue.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "vm_basic_types.h" +#include "vmnet_def.h" +#include "vm_device_version.h" +#include "vmxnet3_version.h" + + +#include "vmxnet3_int.h" +#include "vmxnet3_shm.h" + + +static int +vmxnet3_shm_consume_user_tx_queue(struct vmxnet3_shm_pool *shm); + + +/* + *---------------------------------------------------------------------------- + * + * kernel_rx_idx -- + * + * Result: + * Kernel's current shared memory RX ring index + * + * Side-effects: + * None + * + *---------------------------------------------------------------------------- + */ + +static inline uint16 +kernel_rx_idx(const struct vmxnet3_shm_pool *shm) +{ + return shm->ctl.ptr->kernel_rxi; +} + + +/* + *---------------------------------------------------------------------------- + * + * inc_kernel_rx_idx -- + * + * Result: + * None + * + * Side-effects: + * Increment the kernel's shared memory RX ring index + * + *---------------------------------------------------------------------------- + */ + +static inline void +inc_kernel_rx_idx(const struct vmxnet3_shm_pool *shm) +{ + shm->ctl.ptr->kernel_rxi = (shm->ctl.ptr->kernel_rxi + 1) % SHM_RX_RING_SIZE; +} + + +/* + *---------------------------------------------------------------------------- + * + * kernel_rx_idx -- + * + * Result: + * Kernel's current shared memory RX ring index + * + * Side-effects: + * None + * + *---------------------------------------------------------------------------- + */ + +static inline uint16 +kernel_tx_idx(const struct vmxnet3_shm_pool *shm) +{ + return shm->ctl.ptr->kernel_txi; +} + + +/* + *---------------------------------------------------------------------------- + * + * inc_kernel_tx_idx -- + * + * Result: + * None + * + * Side-effects: + * Increment the kernel's shared memory TX ring index + * + *---------------------------------------------------------------------------- + */ + +static inline void +inc_kernel_tx_idx(const struct vmxnet3_shm_pool *shm) +{ + shm->ctl.ptr->kernel_txi = (shm->ctl.ptr->kernel_txi + 1) % SHM_TX_RING_SIZE; +} + + +/* + *---------------------------------------------------------------------------- + * + * user_rx_idx -- + * + * Result: + * Users's current shared memory RX ring index + * + * Side-effects: + * None + * + *---------------------------------------------------------------------------- + */ + +static inline uint16 +user_rx_idx(const struct vmxnet3_shm_pool *shm) +{ + return shm->ctl.ptr->user_rxi; +} + +/* + *---------------------------------------------------------------------------- + * + * kernel_rx_entry -- + * + * Result: + * Kernel's current shared memory RX ring entry + * + * Side-effects: + * None + * + *---------------------------------------------------------------------------- + */ + +static inline struct vmxnet3_shm_ringentry * +kernel_rx_entry(const struct vmxnet3_shm_pool *shm) +{ + return &shm->ctl.ptr->rx_ring[kernel_rx_idx(shm)]; +} + +/* + *---------------------------------------------------------------------------- + * + * kernel_tx_entry -- + * + * Result: + * Kernel's current shared memory TX ring entry + * + * Side-effects: + * None + * + *---------------------------------------------------------------------------- + */ + +static inline struct vmxnet3_shm_ringentry * +kernel_tx_entry(const struct vmxnet3_shm_pool *shm) +{ + return &shm->ctl.ptr->tx_ring[kernel_tx_idx(shm)]; +} + + +/* + *---------------------------------------------------------------------------- + * + * user_rx_entry -- + * + * Used by vmxnet3_shm_chardev_poll + * + * Result: + * User's current shared memory RX ring entry + * + * Side-effects: + * None + * + *---------------------------------------------------------------------------- + */ + +static inline struct vmxnet3_shm_ringentry * +user_rx_entry(const struct vmxnet3_shm_pool *shm) +{ + return &shm->ctl.ptr->rx_ring[user_rx_idx(shm)]; +} + + +// kobject type +static void +vmxnet3_shm_pool_release(struct kobject *kobj); + +static const struct kobj_type vmxnet3_shm_pool_type = { + .release = vmxnet3_shm_pool_release +}; + +// vm operations +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) +static int +vmxnet3_shm_chardev_fault(struct vm_area_struct *vma, + struct vm_fault *vmf); + +static struct vm_operations_struct vmxnet3_shm_vm_ops = { + .fault = vmxnet3_shm_chardev_fault, +}; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 1) +static struct page * +vmxnet3_shm_chardev_nopage(struct vm_area_struct *vma, + unsigned long address, + int *type); + +static struct vm_operations_struct vmxnet3_shm_vm_ops = { + .nopage = vmxnet3_shm_chardev_nopage, +}; +#else +static struct page * +vmxnet3_shm_chardev_nopage(struct vm_area_struct *vma, + unsigned long address, + int unused); + +static struct vm_operations_struct vmxnet3_shm_vm_ops = { + .nopage = vmxnet3_shm_chardev_nopage, +}; +#endif + +// file operations +static int vmxnet3_shm_chardev_mmap(struct file *filp, + struct vm_area_struct *vma); + +static int vmxnet3_shm_chardev_open(struct inode * inode, + struct file * filp); + +static int vmxnet3_shm_chardev_release(struct inode * inode, + struct file * filp); + +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 struct file_operations shm_fops = { + .owner = THIS_MODULE, + .mmap = vmxnet3_shm_chardev_mmap, + .open = vmxnet3_shm_chardev_open, + .release = vmxnet3_shm_chardev_release, + .poll = vmxnet3_shm_chardev_poll, + .ioctl = vmxnet3_shm_chardev_ioctl, +}; + +static LIST_HEAD(vmxnet3_shm_list); +static spinlock_t vmxnet3_shm_list_lock = SPIN_LOCK_UNLOCKED; + +////////////////////////////////// vmxnet3_shm_pool kobject + + +//// Lifecycle + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) +#define compat_kobject_init(kobj, ktype) { kobject_init(kobj, (struct kobj_type *) ktype); } +#else +#define compat_kobject_init(kobj, _ktype) { \ + (kobj)->ktype = (struct kobj_type *) _ktype; \ + kobject_init(kobj); \ + } +#endif + + +/* + *----------------------------------------------------------------------------- + * + * vmxnet3_shm_pool_create -- + * + * Allocate and initialize shared memory pool. Allocates the data and + * control pages, resets them to zero, initializes locks, registers the + * character device, etc. Creates virtual address mappings for the pool, + * but does not set up DMA yet. + * + * Results: + * The new shared memory pool object, or NULL on failure. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +struct vmxnet3_shm_pool * +vmxnet3_shm_pool_create(struct vmxnet3_adapter *adapter, + char *name) +{ + int i; + unsigned long flags; + struct vmxnet3_shm_pool *shm; + struct vmxnet3_shm_ctl *ctl_ptr; + struct page *ctl_page; + + // Allocate shm_pool kobject + shm = kmalloc(sizeof(*shm), GFP_KERNEL); + if (shm == NULL) { + goto fail_shm; + } + memset(shm, 0, sizeof(*shm)); + compat_kobject_init(&shm->kobj, &vmxnet3_shm_pool_type); + //shm->kobj.ktype = &vmxnet3_shm_pool_type; + //kobject_init(&shm->kobj); + snprintf(shm->name, sizeof(shm->name), "vmxnet_%s_shm", name); + kobject_set_name(&shm->kobj, shm->name); + shm->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); + if (ctl_page == NULL) { + 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; + + // Register char device + shm->misc_dev.minor = MISC_DYNAMIC_MINOR; + shm->misc_dev.name = shm->name; + shm->misc_dev.fops = &shm_fops; + if (misc_register(&shm->misc_dev)) { + printk(KERN_ERR "failed to register vmxnet3_shm character device\n"); + goto fail_cdev; + } + + // Initialize locks + spin_lock_init(&shm->alloc_lock); + spin_lock_init(&shm->tx_lock); + spin_lock_init(&shm->rx_lock); + init_waitqueue_head(&shm->rxq); + + spin_lock_irqsave(&vmxnet3_shm_list_lock, flags); + list_add(&shm->list, &vmxnet3_shm_list); + spin_unlock_irqrestore(&vmxnet3_shm_list_lock, flags); + + printk(KERN_INFO "created vmxnet shared memory pool %s\n", shm->name); + + return shm; + +fail_cdev: + kunmap(ctl_page); + __free_page(ctl_page); + +fail_data: +fail_ctl: + for (i = 0; i < shm->data.num_pages; i++) { + if (VMXNET3_SHM_IDX2PAGE(shm, i) != NULL) { + __free_page(VMXNET3_SHM_IDX2PAGE(shm, i)); + } + } + + kfree(shm); + +fail_shm: + return NULL; +} + + +/* + *----------------------------------------------------------------------------- + * + * vmxnet3_shm_pool_release -- + * + * Release a shared memory pool. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static void +vmxnet3_shm_pool_release(struct kobject *kobj) +{ + int i; + unsigned long flags; + struct vmxnet3_shm_pool *shm = container_of(kobj, struct vmxnet3_shm_pool, kobj); + + spin_lock_irqsave(&vmxnet3_shm_list_lock, flags); + list_del(&shm->list); + spin_unlock_irqrestore(&vmxnet3_shm_list_lock, flags); + + misc_deregister(&shm->misc_dev); + + // Free control pages + for (i = 0; i < SHM_CTL_SIZE; i++) { + kunmap(shm->ctl.pages[i]); + __free_page(shm->ctl.pages[i]); + } + + // Free data pages + for (i = 1; i < SHM_DATA_SIZE; i++) { + kunmap(VMXNET3_SHM_IDX2PAGE(shm,i)); + __free_page(VMXNET3_SHM_IDX2PAGE(shm, i)); + } + + kfree(shm); + + printk(KERN_INFO "destroyed vmxnet shared memory pool %s\n", shm->name); +} + + +//// Shared memory pool management + +/* + *----------------------------------------------------------------------------- + * + * vmxnet3_shm_alloc_page -- + * + * Allocate a page from the shared memory area. + * + * Results: + * Index to page or SHM_INVALID_IDX on failure. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +uint16 +vmxnet3_shm_alloc_page(struct vmxnet3_shm_pool *shm) +{ + uint16 idx; + unsigned long flags; + + spin_lock_irqsave(&shm->alloc_lock, flags); + if (shm->allocator.count == 0) { + idx = SHM_INVALID_IDX; + } else { + idx = shm->allocator.stack[--shm->allocator.count]; + VMXNET3_ASSERT(idx != SHM_INVALID_IDX); + } + //printk(KERN_INFO "allocator count: %d (alloc idx: %d)\n", shm->allocator.count, idx); + spin_unlock_irqrestore(&shm->alloc_lock, flags); + + return idx; +} + + +/* + *----------------------------------------------------------------------------- + * + * vmxnet3_shm_free_page -- + * + * Free a page back to the shared memory area + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +void +vmxnet3_shm_free_page(struct vmxnet3_shm_pool *shm, + uint16 idx) +{ + unsigned long flags; + + spin_lock_irqsave(&shm->alloc_lock, flags); + VMXNET3_ASSERT(shm->allocator.count < SHM_DATA_SIZE); + shm->allocator.stack[shm->allocator.count++] = idx; + //printk(KERN_INFO "allocator count: %d (freed idx: %d)\n", shm->allocator.count, idx); + spin_unlock_irqrestore(&shm->alloc_lock, flags); +} + + +//// Char device + +/* + *----------------------------------------------------------------------------- + * + * vmxnet3_shm_addr2idx -- + * + * Convert user space address into index into the shared memory pool. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static inline unsigned long +vmxnet3_shm_addr2idx(struct vm_area_struct *vma, + unsigned long address) +{ + return vma->vm_pgoff + ((address - vma->vm_start) >> PAGE_SHIFT); +} + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) +/* + *----------------------------------------------------------------------------- + * + * vmxnet3_shm_chardev_fault -- + * + * mmap fault handler. Called if the user space requests a page for + * which there is no shared memory mapping yet. We need to lookup + * the page we want to back the shared memory mapping with. + * + * Results: + * The page backing the user space address. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static int +vmxnet3_shm_chardev_fault(struct vm_area_struct *vma, + struct vm_fault *vmf) +{ + struct vmxnet3_shm_pool *shm = vma->vm_private_data; + unsigned long address = (unsigned long)vmf->virtual_address; + unsigned long idx = vmxnet3_shm_addr2idx(vma, address); + struct page *pageptr; + + if (idx >= SHM_DATA_START && idx < SHM_DATA_START + SHM_DATA_SIZE) { + pageptr = VMXNET3_SHM_IDX2PAGE(shm, idx - SHM_DATA_START); + } else if (idx >= SHM_CTL_START && idx < SHM_CTL_START + SHM_CTL_SIZE) { + pageptr = shm->ctl.pages[idx - SHM_CTL_START]; + } else { + pageptr = NULL; + } + + if (pageptr) { + get_page(pageptr); + } + + vmf->page = pageptr; + + return pageptr ? VM_FAULT_MINOR : VM_FAULT_ERROR; +} +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 1) + +/* + *----------------------------------------------------------------------------- + * + * vmxnet3_shm_chardev_nopage -- + * + * mmap nopage handler. Called if the user space requests a page for + * which there is no shared memory mapping yet. We need to lookup + * the page we want to back the shared memory mapping with. + * + * Results: + * The page backing the user space address. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static struct page * +vmxnet3_shm_chardev_nopage(struct vm_area_struct *vma, + unsigned long address, + int *type) +{ + struct vmxnet3_shm_pool *shm = vma->vm_private_data; + unsigned long idx = vmxnet3_shm_addr2idx(vma, address); + struct page *pageptr; + + if (idx >= SHM_DATA_START && idx < SHM_DATA_START + SHM_DATA_SIZE) { + pageptr = VMXNET3_SHM_IDX2PAGE(shm, idx - SHM_DATA_START); + } else if (idx >= SHM_CTL_START && idx < SHM_CTL_START + SHM_CTL_SIZE) { + pageptr = shm->ctl.pages[idx - SHM_CTL_START]; + } else { + pageptr = NULL; + } + + if (pageptr) { + get_page(pageptr); + } + + if (type) { + *type = pageptr ? VM_FAULT_MINOR : VM_FAULT_SIGBUS; + } + + return pageptr; +} + +#else +/* + *----------------------------------------------------------------------------- + * + * vmxnet3_shm_chardev_nopage -- + * + * mmap nopage handler. Called if the user space requests a page for + * which there is no shared memory mapping yet. We need to lookup + * the page we want to back the shared memory mapping with. + * + * Results: + * The page backing the user space address. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static struct page * +vmxnet3_shm_chardev_nopage(struct vm_area_struct *vma, + unsigned long address, + int unused) +{ + struct vmxnet3_shm_pool *shm = vma->vm_private_data; + unsigned long idx = vmxnet3_shm_addr2idx(vma, address); + struct page *pageptr; + + if (idx >= SHM_DATA_START && idx < SHM_DATA_START + SHM_DATA_SIZE) { + pageptr = VMXNET3_SHM_IDX2PAGE(shm, idx - SHM_DATA_START); + } else if (idx >= SHM_CTL_START && idx < SHM_CTL_START + SHM_CTL_SIZE) { + pageptr = shm->ctl.pages[idx - SHM_CTL_START]; + } else { + pageptr = NULL; + } + + if (pageptr) { + get_page(pageptr); + } + + return pageptr; +} +#endif + + +/* + *----------------------------------------------------------------------------- + * + * vmxnet3_shm_chardev_mmap -- + * + * Setup mmap. + * + * Results: + * Always 0. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ +static int +vmxnet3_shm_chardev_mmap(struct file *filp, + struct vm_area_struct *vma) +{ + vma->vm_private_data = filp->private_data; + vma->vm_ops = &vmxnet3_shm_vm_ops; + vma->vm_flags |= VM_RESERVED; + return 0; +} + + +/* + *----------------------------------------------------------------------------- + * + * vmxnet3_shm_chardev_poll -- + * + * Poll called from user space. We consume the TX queue and then go to + * sleep until we get woken up by an interrupt. + * + * Results: + * Poll mask. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static unsigned int +vmxnet3_shm_chardev_poll(struct file *filp, + poll_table *wait) +{ + struct vmxnet3_shm_pool *shm = filp->private_data; + unsigned int mask = 0; + unsigned long flags; + struct vmxnet3_shm_ringentry *re; + + // consume TX queue + vmxnet3_shm_consume_user_tx_queue(shm); + + // Wait on the rxq for an interrupt to wake us + poll_wait(filp, &shm->rxq, wait); + + // Check if the user's current RX entry is full + spin_lock_irqsave(&shm->rx_lock, flags); + re = user_rx_entry(shm); + if (re->own) { + // XXX: We need a comment that explains what this does. + mask |= POLLIN | POLLRDNORM; + } + spin_unlock_irqrestore(&shm->rx_lock, flags); + + return mask; +} + + +/* + *----------------------------------------------------------------------------- + * + * vmxnet3_shm_chardev_ioctl -- + * + * Handle ioctls from user space. + * + * Results: + * Return code depends on ioctl. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static int +vmxnet3_shm_chardev_ioctl(struct inode *inode, + struct file *filp, + unsigned int cmd, + unsigned long arg) +{ + struct vmxnet3_shm_pool *shm = filp->private_data; + uint16 idx; + uint16 idx1; + int i; + + switch(cmd) { + + case SHM_IOCTL_TX: + vmxnet3_shm_consume_user_tx_queue(shm); + return 0; + + case SHM_IOCTL_ALLOC_ONE: + idx = vmxnet3_shm_alloc_page(shm); + if (idx != SHM_INVALID_IDX) { + return idx; + } else { + return -ENOMEM; + } + + case SHM_IOCTL_ALLOC_MANY: + for (i = 0; i < arg; i++) { + idx = vmxnet3_shm_alloc_page(shm); + if (idx != SHM_INVALID_IDX) { + if (vmxnet3_shm_user_rx(shm, idx, 0, 1, 1)) { + vmxnet3_shm_free_page(shm, idx); + return -ENOMEM; + } + } else { + return -ENOMEM; + } + } + return 0; + + case SHM_IOCTL_ALLOC_ONE_AND_MANY: + idx1 = vmxnet3_shm_alloc_page(shm); + if (idx1 == SHM_INVALID_IDX) { + return -ENOMEM; + } + for (i = 0; i < arg - 1; i++) { + idx = vmxnet3_shm_alloc_page(shm); + if (idx != SHM_INVALID_IDX) { + if (vmxnet3_shm_user_rx(shm, idx, 0, 1, 1)) { + vmxnet3_shm_free_page(shm, idx); + vmxnet3_shm_free_page(shm, idx1); + return -ENOMEM; + } + } else { + vmxnet3_shm_free_page(shm, idx1); + return -ENOMEM; + } + } + return idx1; + + case SHM_IOCTL_FREE_ONE: + if (arg != SHM_INVALID_IDX && arg < SHM_DATA_SIZE) { + vmxnet3_shm_free_page(shm, arg); + } + return 0; + } + + return -ENOTTY; +} + + +/* + *----------------------------------------------------------------------------- + * + * vmxnet3_shm_chardev_find_by_minor -- + * + * Find the right shared memory pool based on the minor number of the + * char device. + * + * Results: + * Pointer to the shared memory pool, or NULL on error. + * + * Side effects: + * Takes a reference on the kobj of the shm object. + * + *----------------------------------------------------------------------------- + */ + +static struct vmxnet3_shm_pool * +vmxnet3_shm_chardev_find_by_minor(unsigned int minor) +{ + struct vmxnet3_shm_pool *shm, *tmp; + unsigned long flags; + + spin_lock_irqsave(&vmxnet3_shm_list_lock, flags); + + list_for_each_entry_safe(shm, tmp, &vmxnet3_shm_list, list) { + if (shm->misc_dev.minor == minor && kobject_get(&shm->kobj)) { + spin_unlock_irqrestore(&vmxnet3_shm_list_lock, flags); + return shm; + } + } + + spin_unlock_irqrestore(&vmxnet3_shm_list_lock, flags); + + return NULL; +} + + +/* + *----------------------------------------------------------------------------- + * + * vmxnet3_shm_chardev_open -- + * + * Find the right shared memory pool based on the minor number of the + * char device. + * + * Results: + * 0 on success or -ENODEV if no device exists with the given minor number + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static int +vmxnet3_shm_chardev_open(struct inode * inode, + struct file * filp) +{ + // Stash pointer to shm in file so file ops can use it + filp->private_data = vmxnet3_shm_chardev_find_by_minor(iminor(inode)); + if (filp->private_data == NULL) { + return -ENODEV; + } + + // XXX: What does this do?? +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) +// filp->f_mapping->backing_dev_info = &directly_mappable_cdev_bdi; +#endif + + return 0; +} + + +/* + *----------------------------------------------------------------------------- + * + * vmxnet3_shm_chardev_release -- + * + * Closing the char device. Release the ref count on the shared memory + * pool, perform cleanup. + * + * Results: + * Always 0. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static int +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 + + return 0; +} + + +//// TX and RX + +/* + *----------------------------------------------------------------------------- + * + * vmxnet3_free_skbpages -- + * + * Free the shared memory pages (secretly) backing this skb. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +void +vmxnet3_free_skbpages(struct vmxnet3_adapter *adapter, + struct sk_buff *skb) +{ + int i; + + vmxnet3_shm_free_page(adapter->shm, VMXNET3_SHM_SKB_GETIDX(skb)); + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; + + vmxnet3_shm_free_page(adapter->shm, (unsigned long)frag->page); + } + + skb_shinfo(skb)->nr_frags = 0; +} + + +/* + *----------------------------------------------------------------------------- + * + * vmxnet3_shm_start_tx -- + * + * The shared memory vmxnet version of the hard_start_xmit routine. + * Just frees the given packet as we do not intend to transmit any + * packet given to us by the TCP/IP stack. + * + * Results: + * Always 0 for success. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +int +vmxnet3_shm_start_tx(struct sk_buff *skb, + struct net_device *dev) +{ + compat_dev_kfree_skb_irq(skb, FREE_WRITE); + return COMPAT_NETDEV_TX_OK; +} + + +/* + *----------------------------------------------------------------------------- + * + * vmxnet3_shm_tx_pkt -- + * + * Send a packet (collection of ring entries) using h/w tx routine. + * + * Results: + * 0 on success. Negative value to indicate error + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static inline int +vmxnet3_shm_tx_pkt(struct vmxnet3_adapter *adapter, + struct vmxnet3_shm_ringentry *res, + int frags) +{ + struct sk_buff* skb; + int i; + + skb = dev_alloc_skb(100); + if (skb == NULL) { + VMXNET3_ASSERT(FALSE); + return -ENOMEM; + } + + VMXNET3_SHM_SKB_SETIDX(skb, res[0].idx); + VMXNET3_SHM_SKB_SETLEN(skb, res[0].len); + + for (i = 1; i < frags; i++) { + struct skb_frag_struct *frag = skb_shinfo(skb)->frags + + skb_shinfo(skb)->nr_frags; + + VMXNET3_ASSERT(skb_shinfo(skb)->nr_frags < MAX_SKB_FRAGS); + + frag->page = (struct page*)(unsigned long)res[i].idx; + frag->page_offset = 0; + frag->size = res[i].len; + skb_shinfo(skb)->nr_frags ++; + } + + { + struct vmxnet3_tx_queue *tq = &adapter->tx_queue; + int ret; + skb->protocol = cpu_to_be16(0x86dd); + adapter->shm->ctl.ptr->stats.kernel_tx += frags; // XXX: move to better place + ret = vmxnet3_tq_xmit(skb, tq, adapter, adapter->netdev); + if (ret == COMPAT_NETDEV_TX_BUSY) { + for (i = 0; i < frags; i++) { + vmxnet3_shm_free_page(adapter->shm, res[i].idx); + } + skb_shinfo(skb)->nr_frags = 0; + kfree_skb(skb); + } + + return ret; + } + + return 0; +} + + +/* + *----------------------------------------------------------------------------- + * + * vmxnet3_shm_tx_re -- + * + * Add one entry to the partial TX array. If re->eop is set, i.e. if + * the packet is complete, TX the partial packet. + * + * Results: + * 1 if eop + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +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) { + int status = vmxnet3_shm_tx_pkt(shm->adapter, + 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); + } + } + shm->partial_tx.frags = 0; + return 1; + } + + return 0; +} + + +/* + *----------------------------------------------------------------------------- + * + * vmxnet3_shm_consume_user_tx_queue -- + * + * Consume all packets in the user TX queue and send full + * packets to the device + * + * Results: + * 0 on success. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static int +vmxnet3_shm_consume_user_tx_queue(struct vmxnet3_shm_pool *shm) +{ + unsigned long flags; + struct vmxnet3_shm_ringentry *re; + + spin_lock_irqsave(&shm->tx_lock, flags); + + // Check if the device has been closed + if (shm->adapter == NULL) { + spin_unlock_irqrestore(&shm->tx_lock, flags); + return -1; + } + + /* + * Loop through each full entry in the user TX ring. Discard trash frags and + * add the others to the partial TX array. If an entry has eop set, TX the + * partial packet. + */ + while ((re = kernel_tx_entry(shm))->own) { + if (re->trash) { + vmxnet3_shm_free_page(shm, re->idx); + shm->ctl.ptr->stats.kernel_tx++; + } else { + vmxnet3_shm_tx_re(shm, *re); + } + inc_kernel_tx_idx(shm); + *re = RE_ZERO; + } + + spin_unlock_irqrestore(&shm->tx_lock, flags); + + return 0; +} + + +/* + *----------------------------------------------------------------------------- + * + * vmxnet3_shm_user_desc_available -- + * + * Checks if we have num_entries ring entries available on the rx ring. + * + * Results: + * 0 for yes + * -ENOMEM for not enough entries available + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static int +vmxnet3_shm_user_desc_available(struct vmxnet3_shm_pool *shm, + uint16 num_entries) +{ + struct vmxnet3_shm_ringentry *re; + uint16 reIdx = kernel_rx_idx(shm); + + while (num_entries > 0) { + re = &shm->ctl.ptr->rx_ring[reIdx]; + if (re->own) { + return -ENOMEM; + } + reIdx = (reIdx + 1) % SHM_RX_RING_SIZE; + num_entries--; + } + + return 0; +} + + +/* + *----------------------------------------------------------------------------- + * + * vmxnet3_shm_rx_skb -- + * + * Receives an skb into the rx ring. If we can't receive all fragments, + * the entire skb is dropped. + * + * Results: + * 0 for success + * -ENOMEM for not enough entries available + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +int +vmxnet3_shm_rx_skb(struct vmxnet3_adapter *adapter, + struct sk_buff *skb) +{ + int ret; + int i; + int num_entries = 1 + skb_shinfo(skb)->nr_frags; + int eop = (num_entries == 1); + + if (vmxnet3_shm_user_desc_available(adapter->shm, num_entries) == -ENOMEM) { + vmxnet3_dev_kfree_skb_irq(adapter, skb); + return -ENOMEM; + } + + ret = vmxnet3_shm_user_rx(adapter->shm, + VMXNET3_SHM_SKB_GETIDX(skb), + VMXNET3_SHM_SKB_GETLEN(skb), + 0 /* trash */, + eop); + if (ret != 0) { + VMXNET3_ASSERT(FALSE); + printk(KERN_ERR "vmxnet3_shm_user_rx failed on frag 0\n"); + } + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; + unsigned long shm_idx = (unsigned long)frag->page; + + eop = (i == skb_shinfo(skb)->nr_frags - 1); + + ret = vmxnet3_shm_user_rx(adapter->shm, + shm_idx, + frag->size, + 0 /* trash */, + eop); + if (ret != 0) { + VMXNET3_ASSERT(FALSE); + printk(KERN_ERR "vmxnet3_shm_user_rx failed on frag 1+\n"); + } + } + + + /* + * Do NOT use the vmxnet3 version of kfree_skb, as we handed + * ownership of shm pages to the user space, thus we must not + * free them again. + */ + skb_shinfo(skb)->nr_frags = 0; + compat_dev_kfree_skb_irq(skb, FREE_WRITE); + + return 0; +} + + +/* + *----------------------------------------------------------------------------- + * + * vmxnet3_shm_user_rx -- + * + * Put one packet fragment into the shared memory RX ring + * + * Results: + * 0 on success. + * Negative value on error. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +int +vmxnet3_shm_user_rx(struct vmxnet3_shm_pool *shm, + uint16 idx, + uint16 len, + int trash, + int eop) +{ + struct vmxnet3_shm_ringentry *re = kernel_rx_entry(shm); + shm->ctl.ptr->stats.kernel_rx++; + if (re->own) { + return -ENOMEM; + } + inc_kernel_rx_idx(shm); + re->idx = idx; + re->len = len; + re->trash = trash; + re->eop = eop; + re->own = TRUE; + return 0; +} + + +/* + *----------------------------------------------------------------------------- + * + * vmxnet3_shm_open -- + * + * Called when the vmxnet3 device is opened. Allocates the per-device + * shared memory pool. + * + * Results: + * 0 on success. + * Negative value on error. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +int +vmxnet3_shm_open(struct vmxnet3_adapter *adapter, + char *name) +{ + adapter->shm = vmxnet3_shm_pool_create(adapter, name); + if (adapter->shm == NULL) { + printk(KERN_ERR "failed to create shared memory pool\n"); + return -ENOMEM; + } + return 0; +} + + +/* + *----------------------------------------------------------------------------- + * + * vmxnet3_shm_close -- + * + * Called when the vmxnet3 device is closed. Does not free the per-device + * shared memory pool. The character device might still be open. Thus + * freeing the shared memory pool is tied to the ref count on + * shm->kobj dropping to zero instead. + * + * Results: + * 0 on success. + * Negative value on error. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +int +vmxnet3_shm_close(struct vmxnet3_adapter *adapter) +{ + unsigned long flags; + + // Can't unset the lp pointer if a TX is in progress + spin_lock_irqsave(&adapter->shm->tx_lock, flags); + adapter->shm->adapter = NULL; + spin_unlock_irqrestore(&adapter->shm->tx_lock, flags); + + kobject_put(&adapter->shm->kobj); + return 0; +} diff --git a/open-vm-tools/modules/linux/vmxnet3/vmxnet3_shm.h b/open-vm-tools/modules/linux/vmxnet3/vmxnet3_shm.h new file mode 100644 index 000000000..a6cf90e51 --- /dev/null +++ b/open-vm-tools/modules/linux/vmxnet3/vmxnet3_shm.h @@ -0,0 +1,317 @@ +/********************************************************* + * 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 + * + *********************************************************/ + +/* + * vmxnet3_shm.h -- + * + * Definitions for shared memory infrastructure for VMXNET3 linux driver. + */ + +#ifndef _VMXNET3_SHM_H_ +#define _VMXNET3_SHM_H_ + +#include "vmxnet3_shm_shared.h" +#include + +/* + * Bumping up the max tx descriptor per packet. + * We need one more than VMXNET3_SHM_MAX_FRAGS because of partial header copy. + */ +#define VMXNET3_MAX_TXD_PER_PKT_SHM (VMXNET3_SHM_MAX_FRAGS + 1) + +struct vmxnet3_shm_mapped_page +{ + struct page *page; + void *virt; +}; + +struct vmxnet3_shm_pool +{ + struct list_head list; + char name[IFNAMSIZ + 16]; + struct kobject kobj; + + struct + { + // pages backing the map in virtual address order + struct vmxnet3_shm_mapped_page pages[SHM_DATA_SIZE]; + unsigned int num_pages; + } data; + + struct + { + // pages backing the map in virtual address order + struct page *pages[SHM_CTL_SIZE]; + struct vmxnet3_shm_ctl *ptr; + } ctl; + + struct + { + /* + * This is a stack of free pages. count is the number of free pages, so + * count - 1 is the topmost free page. + */ + uint16 count; + uint16 stack[SHM_DATA_SIZE]; + } allocator; + + struct + { + struct vmxnet3_shm_ringentry res[VMXNET3_SHM_MAX_FRAGS]; + int frags; + } partial_tx; + + struct miscdevice misc_dev; + + wait_queue_head_t rxq; + spinlock_t alloc_lock, tx_lock, rx_lock; + struct vmxnet3_adapter *adapter; +}; + +// Convert ring index to the struct page* or virt address. +#define VMXNET3_SHM_IDX2PAGE(shm, idx) (shm->data.pages[(idx)].page) +#define VMXNET3_SHM_SET_IDX2PAGE(shm, idx, x) (shm->data.pages[(idx)].page = (x)) + +#define VMXNET3_SHM_SKB_GETIDX(skb) (compat_skb_transport_offset(skb)) +#define VMXNET3_SHM_SKB_SETIDX(skb, idx) (compat_skb_set_transport_header(skb, idx)) +#define VMXNET3_SHM_SKB_SETLEN(skb, len) (compat_skb_set_network_header(skb, len)) +#define VMXNET3_SHM_SKB_GETLEN(skb) (compat_skb_network_offset(skb)) + +int +vmxnet3_shm_close(struct vmxnet3_adapter *adapter); +int +vmxnet3_shm_open(struct vmxnet3_adapter *adapter, char *name); +int +vmxnet3_shm_user_rx(struct vmxnet3_shm_pool *shm, + uint16 idx, uint16 len, + int trash, int eop); +void +vmxnet3_free_skbpages(struct vmxnet3_adapter *adapter, struct sk_buff *skb); + +uint16 +vmxnet3_shm_alloc_page(struct vmxnet3_shm_pool *shm); +void +vmxnet3_shm_free_page(struct vmxnet3_shm_pool *shm, uint16 idx); + +int +vmxnet3_shm_start_tx(struct sk_buff *skb, struct net_device *dev); +int +vmxnet3_shm_rx_skb(struct vmxnet3_adapter *adapter, struct sk_buff *skb); + +/* + *----------------------------------------------------------------------------- + * + * vmxnet3_dev_kfree_skb_* -- + * + * Covers for dev_kfree_skb*. Deal with the shared memory version of skbs. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ +static inline void +vmxnet3_dev_kfree_skb(struct vmxnet3_adapter *adapter, struct sk_buff *skb) +{ + if (adapter->is_shm) { + vmxnet3_free_skbpages(adapter, skb); + } + compat_dev_kfree_skb(skb, FREE_WRITE); +} + +static inline void +vmxnet3_dev_kfree_skb_any(struct vmxnet3_adapter *adapter, struct sk_buff *skb) +{ + if (adapter->is_shm) { + vmxnet3_free_skbpages(adapter, skb); + } + compat_dev_kfree_skb_any(skb, FREE_WRITE); +} + +static inline void +vmxnet3_dev_kfree_skb_irq(struct vmxnet3_adapter *adapter, struct sk_buff *skb) +{ + if (adapter->is_shm) { + vmxnet3_free_skbpages(adapter, skb); + } + compat_dev_kfree_skb_irq(skb, FREE_WRITE); +} + +/* + *----------------------------------------------------------------------------- + * + * vmxnet3_skb_* -- + * + * Covers for (compat_)skb_*. Deal with the shared memory version of skbs. + * + * Results: + * Depends. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ +static inline unsigned int +vmxnet3_skb_headlen(struct vmxnet3_adapter *adapter, struct sk_buff *skb) +{ + if (adapter->is_shm) { + return VMXNET3_SHM_SKB_GETLEN(skb); + } else { + return compat_skb_headlen(skb); + } +} + +static inline void +vmxnet3_skb_put(struct vmxnet3_adapter *adapter, struct sk_buff *skb, unsigned int len) +{ + if (!adapter->is_shm) { + skb_put(skb, len); + } else { + unsigned int oldlen = VMXNET3_SHM_SKB_GETLEN(skb); + VMXNET3_SHM_SKB_SETLEN(skb, len + oldlen); + } +} + +static inline struct sk_buff* +vmxnet3_dev_alloc_skb(struct vmxnet3_adapter *adapter, unsigned long length) +{ + if (adapter->is_shm) { + int idx; + struct sk_buff* skb; + idx = vmxnet3_shm_alloc_page(adapter->shm); + if (idx == SHM_INVALID_IDX) { + return NULL; + } + + // The length is arbitrary because that memory shouldn't be used + skb = dev_alloc_skb(100); + if (skb == NULL) { + vmxnet3_shm_free_page(adapter->shm, idx); + return NULL; + } + + VMXNET3_SHM_SKB_SETIDX(skb, idx); + VMXNET3_SHM_SKB_SETLEN(skb, 0); + + return skb; + } else { + return dev_alloc_skb(length); + } +} + +/* + *----------------------------------------------------------------------------- + * + * vmxnet3_map_* -- + * + * Covers for pci_map_*. Deal with the shared memory version of skbs. + * + * Results: + * DMA address + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ +static inline dma_addr_t +vmxnet3_map_single(struct vmxnet3_adapter *adapter, + struct sk_buff * skb, + size_t offset, + size_t len, + int direction) +{ + if (adapter->is_shm) { + unsigned long shm_idx = VMXNET3_SHM_SKB_GETIDX(skb); + struct page *real_page = VMXNET3_SHM_IDX2PAGE(adapter->shm, shm_idx); + return pci_map_page(adapter->pdev, + real_page, + offset, + len, + direction); + } else { + return pci_map_single(adapter->pdev, + skb->data + offset, + len, + direction); + } + +} + +static inline dma_addr_t +vmxnet3_map_page(struct vmxnet3_adapter *adapter, + struct page *page, + size_t offset, + size_t len, + int direction) +{ + if (adapter->is_shm) { + unsigned long shm_idx = (unsigned long)page; + page = VMXNET3_SHM_IDX2PAGE(adapter->shm, shm_idx); + } + + return pci_map_page(adapter->pdev, + page, + offset, + len, + direction); +} + +/* + *----------------------------------------------------------------------------- + * + * vmxnet3_(put|alloc)_page -- + * + * Allocation and release of pages. Either use regular or shared memory + * pages. + * + * Results: + * Depends + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ +static inline void +vmxnet3_put_page(struct vmxnet3_adapter *adapter, + struct page *page) +{ + if (!adapter->is_shm) { + put_page(page); + } else { + vmxnet3_shm_free_page(adapter->shm, (unsigned long)page); + } +} + +static inline void * +vmxnet3_alloc_page(struct vmxnet3_adapter *adapter) +{ + if (adapter->is_shm) { + return (void*) (unsigned long) vmxnet3_shm_alloc_page(adapter->shm); + } else { + return alloc_page(GFP_ATOMIC); + } +} + + +#endif diff --git a/open-vm-tools/modules/linux/vmxnet3/vmxnet3_shm_shared.h b/open-vm-tools/modules/linux/vmxnet3/vmxnet3_shm_shared.h new file mode 100644 index 000000000..e3eca683d --- /dev/null +++ b/open-vm-tools/modules/linux/vmxnet3/vmxnet3_shm_shared.h @@ -0,0 +1,91 @@ +/********************************************************* + * 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 + * + *********************************************************/ + +/* + * vmxnet3_shm_shared.h -- + * + * Header shared between vmxnet3 shared memory kernel driver and userspace. + * + */ + +#ifndef __VMXNET_SHARED_SHM +#define __VMXNET_SHARED_SHM + +#include + +// ioctl constants +#define SHM_IOCTL_MAGIC 'v' +#define SHM_IOCTL_TX _IO(SHM_IOCTL_MAGIC, 0) +#define SHM_IOCTL_ALLOC_ONE _IO(SHM_IOCTL_MAGIC, 1) +#define SHM_IOCTL_ALLOC_MANY _IO(SHM_IOCTL_MAGIC, 2) +#define SHM_IOCTL_ALLOC_ONE_AND_MANY _IO(SHM_IOCTL_MAGIC, 3) +#define SHM_IOCTL_FREE_ONE _IO(SHM_IOCTL_MAGIC, 4) + +/* + * invalid index + * + * Must be 0 so that a invalid shared memory page has the same + * value as a NULL struct page. We need that because we overload + * the same field for regular and shared memory version of vmxnet3. + */ +#define SHM_INVALID_IDX 0 + +// sizes of shared memory regions in pages +#define SHM_DATA_START 0 +#define SHM_DATA_SIZE 4096 +#define SHM_CTL_START 16384 +#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 + +// maximum fragments per packet is 16 (64k) + 2 for metadata +#define VMXNET3_SHM_MAX_FRAGS 18 + +// shared memory ring entry +struct vmxnet3_shm_ringentry +{ + uint16_t idx; // index of this page in the pool + uint16_t len: 13; // length of data in this page + uint16_t own: 1; // whether the receiver owns the re + uint16_t eop: 1; // end of packet + uint16_t trash: 1; // ignore all the data in this packet, but still take ownership +}; + +static const struct vmxnet3_shm_ringentry RE_ZERO = {0,0,0,0,0}; + +// shared memory control page +struct vmxnet3_shm_ctl +{ + struct vmxnet3_shm_ringentry rx_ring[SHM_RX_RING_SIZE]; + struct vmxnet3_shm_ringentry tx_ring[SHM_TX_RING_SIZE]; + + // XXX move kernel_* into the kernel, currently here for debugging + // user_rxi is used by poll() to avoid going to sleep when there are packets waiting + uint16_t user_rxi, user_txi; + uint16_t kernel_rxi, kernel_txi; + + struct + { + uint64_t user_rx, user_tx; + uint64_t kernel_rx, kernel_tx; + } stats; +}; + +#endif diff --git a/open-vm-tools/modules/linux/vmxnet3/vmxnet3_version.h b/open-vm-tools/modules/linux/vmxnet3/vmxnet3_version.h index 80b817d46..f3c0891c9 100644 --- a/open-vm-tools/modules/linux/vmxnet3/vmxnet3_version.h +++ b/open-vm-tools/modules/linux/vmxnet3/vmxnet3_version.h @@ -25,11 +25,11 @@ #ifndef _VMXNET3_VERSION_H_ #define _VMXNET3_VERSION_H_ -#define VMXNET3_DRIVER_VERSION 1.0.0.34 -#define VMXNET3_DRIVER_VERSION_COMMAS 1,0,0,34 -#define VMXNET3_DRIVER_VERSION_STRING "1.0.0.34" +#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" /* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */ -#define VMXNET3_DRIVER_VERSION_NUM 0x01000022 +#define VMXNET3_DRIVER_VERSION_NUM 0x01000100 #endif /* _VMXNET3_VERSION_H_ */ diff --git a/open-vm-tools/modules/linux/vsock/linux/af_vsock.c b/open-vm-tools/modules/linux/vsock/linux/af_vsock.c index ad97e8386..d152b5db0 100644 --- a/open-vm-tools/modules/linux/vsock/linux/af_vsock.c +++ b/open-vm-tools/modules/linux/vsock/linux/af_vsock.c @@ -871,7 +871,8 @@ VSockVmciRecvStreamCB(void *data, // IN * Ignore incoming packets from contexts without sockets, or resources that * aren't vsock implementations. */ - if (!VSockAddr_SocketContext(VMCI_HANDLE_TO_CONTEXT_ID(dg->src)) || + + if (!VSockAddr_SocketContextStream(VMCI_HANDLE_TO_CONTEXT_ID(dg->src)) || VSOCK_PACKET_RID != VMCI_HANDLE_TO_RESOURCE_ID(dg->src)) { return VMCI_ERROR_NO_ACCESS; } @@ -1491,10 +1492,10 @@ VSockVmciRecvListen(struct sock *sk, // IN sk->compat_sk_ack_backlog++; pending->compat_sk_state = SS_CONNECTING; - vpending->produceSize = vpending->consumeSize = pkt->u.size; + vpending->produceSize = vpending->consumeSize = qpSize; /* XXX Move this into the notify file. */ - vpending->notify.writeNotifyWindow = pkt->u.size; + vpending->notify.writeNotifyWindow = qpSize; /* * We might never receive another message for this socket and it's not @@ -3106,6 +3107,12 @@ VSockVmciDgramConnect(struct socket *sock, // IN } } + if (!VSockAddr_SocketContextDgram(remoteAddr->svm_cid, + remoteAddr->svm_port)) { + err = -EINVAL; + goto out; + } + memcpy(&vsk->remoteAddr, remoteAddr, sizeof vsk->remoteAddr); sock->state = SS_CONNECTED; @@ -3178,7 +3185,7 @@ VSockVmciStreamConnect(struct socket *sock, // IN } /* The hypervisor and well-known contexts do not have socket endpoints. */ - if (!VSockAddr_SocketContext(remoteAddr->svm_cid)) { + if (!VSockAddr_SocketContextStream(remoteAddr->svm_cid)) { err = -ENETUNREACH; goto out; } @@ -3325,7 +3332,7 @@ VSockVmciAccept(struct socket *sock, // IN err = sock_intr_errno(timeout); goto outWait; } else if (timeout == 0) { - err = -ETIMEDOUT; + err = -EAGAIN; goto outWait; } @@ -3528,7 +3535,8 @@ VSockVmciPoll(struct file *file, // IN * Sockets whose connections have been close, reset, or terminated should also * be considered read, and we check the shutdown flag for that. */ - if (sk->compat_sk_shutdown) { + if (sk->compat_sk_shutdown & RCV_SHUTDOWN || + vsk->peerShutdown & SEND_SHUTDOWN) { mask |= POLLIN | POLLRDNORM; } @@ -3779,6 +3787,16 @@ VSockVmciDgramSendmsg(struct kiocb *kiocb, // UNUSED goto out; } + /* + * Make sure that we don't allow a userlevel app to send datagrams + * to the hypervisor that modify VMCI device state. + */ + if (!VSockAddr_SocketContextDgram(remoteAddr->svm_cid, + remoteAddr->svm_port)) { + err = -EINVAL; + goto out; + } + /* * Allocate a buffer for the user's message and our packet header. */ diff --git a/open-vm-tools/modules/linux/vsock/linux/vsockAddr.c b/open-vm-tools/modules/linux/vsock/linux/vsockAddr.c index 8da3122fc..cbdc00b64 100644 --- a/open-vm-tools/modules/linux/vsock/linux/vsockAddr.c +++ b/open-vm-tools/modules/linux/vsock/linux/vsockAddr.c @@ -351,10 +351,10 @@ exit: /* *---------------------------------------------------------------------------- * - * VSockAddr_SocketContext -- + * VSockAddr_SocketContextStream -- * * Determines whether the provided context id represents a context that - * contains socket endpoints. + * contains a stream socket endpoints. * * Results: * TRUE if the context does have socket endpoints, FALSE otherwise. @@ -366,7 +366,7 @@ exit: */ Bool -VSockAddr_SocketContext(uint32 cid) // IN +VSockAddr_SocketContextStream(uint32 cid) // IN { uint32 i; VMCIId nonSocketContexts[] = { @@ -384,3 +384,34 @@ VSockAddr_SocketContext(uint32 cid) // IN return TRUE; } + + +/* + *---------------------------------------------------------------------------- + * + * VSockAddr_SocketContextDgram -- + * + * Determines whether the provided represent + * a protected datagram endpoint. + * + * Results: + * TRUE if the context does have socket endpoints, FALSE otherwise. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +Bool +VSockAddr_SocketContextDgram(uint32 cid, // IN + uint32 rid) // IN +{ + if (cid == VMCI_HYPERVISOR_CONTEXT_ID) { + if (rid != VMCI_VSOCK_VMX_LOOKUP) { + return FALSE; + } + } + + return TRUE; +} diff --git a/open-vm-tools/modules/linux/vsock/linux/vsockAddr.h b/open-vm-tools/modules/linux/vsock/linux/vsockAddr.h index e70f2b8c5..a90ea31f2 100644 --- a/open-vm-tools/modules/linux/vsock/linux/vsockAddr.h +++ b/open-vm-tools/modules/linux/vsock/linux/vsockAddr.h @@ -45,8 +45,8 @@ Bool VSockAddr_EqualsHandlePort(struct sockaddr_vm *addr, VMCIHandle handle, uint32 port); int32 VSockAddr_Cast(const struct sockaddr *addr, int32 len, struct sockaddr_vm **outAddr); -Bool VSockAddr_SocketContext(VMCIId cid); - +Bool VSockAddr_SocketContextStream(uint32 cid); +Bool VSockAddr_SocketContextDgram(uint32 cid, uint32 rid); #endif // _VSOCK_ADDR_H_ diff --git a/open-vm-tools/modules/shared/vmxnet/net_sg.h b/open-vm-tools/modules/shared/vmxnet/net_sg.h index 9f6b70e2d..9a33653c4 100644 --- a/open-vm-tools/modules/shared/vmxnet/net_sg.h +++ b/open-vm-tools/modules/shared/vmxnet/net_sg.h @@ -69,7 +69,6 @@ typedef enum NetSG_AddrType { NET_SG_MACH_ADDR, NET_SG_PHYS_ADDR, NET_SG_VIRT_ADDR, - NET_SG_VMM_STACK_OFFSET, } NetSG_AddrType; typedef struct NetSG_Array { diff --git a/open-vm-tools/scripts/common/vmware-user.desktop b/open-vm-tools/scripts/common/vmware-user.desktop index f086a3a91..a2c30e265 100644 --- a/open-vm-tools/scripts/common/vmware-user.desktop +++ b/open-vm-tools/scripts/common/vmware-user.desktop @@ -5,5 +5,6 @@ Encoding=UTF-8 # be sure to also fix up OVT staging targets. Exec=vmware-user-suid-wrapper Name=VMware User Agent -NoDisplay=true +# KDE bug 190522: KDE does not autostart items with NoDisplay=tru... +# NoDisplay=true X-KDE-autostart-phase=1 diff --git a/open-vm-tools/scripts/freebsd/suspend-vm-default b/open-vm-tools/scripts/freebsd/suspend-vm-default index d914a4b67..ef6a5c453 100644 --- a/open-vm-tools/scripts/freebsd/suspend-vm-default +++ b/open-vm-tools/scripts/freebsd/suspend-vm-default @@ -33,17 +33,11 @@ if [ -d "$scriptsdir" ]; then fi # Release the IP if DHCP is used. -case "`uname -r`" in -6.*) # 'PID dhclient: em0' => 'em0' - for intf in `pgrep -fl dhclient | cut -d" " -f3 | sort | uniq`; do - ifconfig "$intf" down - ifconfig "$intf" delete - done - ;; -*) # Have dhclient running => release lease - ps auxw | grep -q dhclient - if [ "$?" -eq 0 ]; then - dhclient -r - fi - ;; -esac +for intf in `pgrep -fl dhclient | cut -d" " -f3 | sort | uniq`; do + if [ -x /etc/rc.d/netif ]; then + /etc/rc.d/netif stop "$intf" + else + ifconfig "$intf" down + ifconfig "$intf" delete + fi +done diff --git a/open-vm-tools/services/plugins/powerOps/powerOps.c b/open-vm-tools/services/plugins/powerOps/powerOps.c index e5f1ac9bb..d9a1607c1 100644 --- a/open-vm-tools/services/plugins/powerOps/powerOps.c +++ b/open-vm-tools/services/plugins/powerOps/powerOps.c @@ -231,7 +231,7 @@ PowerOpsScriptCallback(gpointer _state) { PowerOpState *state = _state; - g_assert(state->pid != INVALID_PID); + ASSERT(state->pid != INVALID_PID); if (!ProcMgr_IsAsyncProcRunning(state->pid)) { int exitcode; @@ -320,7 +320,7 @@ PowerOpsScriptCallback(GPid pid, { PowerOpState *state = _state; - g_assert(state->pid != INVALID_PID); + ASSERT(state->pid != INVALID_PID); PowerOpsStateChangeDone(_state, status == 0); g_spawn_close_pid(state->pid); @@ -450,7 +450,7 @@ PowerOpsStateChange(RpcInData *data) char *tmp; dfltPath = GuestApp_GetInstallPath(); - g_assert(dfltPath != NULL); + ASSERT(dfltPath != NULL); /* * Before the switch to vmtoolsd, the config file was saved with diff --git a/open-vm-tools/services/plugins/resolutionSet/resolutionInt.h b/open-vm-tools/services/plugins/resolutionSet/resolutionInt.h index 7c5401cee..a6a8475f8 100644 --- a/open-vm-tools/services/plugins/resolutionSet/resolutionInt.h +++ b/open-vm-tools/services/plugins/resolutionSet/resolutionInt.h @@ -45,7 +45,6 @@ typedef struct { Bool initialized; // TRUE if successfully initialized. Bool canSetResolution; // TRUE if back-end supports Resolution_Set. Bool canSetTopology; // TRUE if back-end supports DisplayTopology_Set. - Bool isWDDM; // TRUE if the driver does WDDM. } ResolutionInfoType; diff --git a/open-vm-tools/services/plugins/resolutionSet/resolutionSet.c b/open-vm-tools/services/plugins/resolutionSet/resolutionSet.c index c57e1ff1f..974372dee 100644 --- a/open-vm-tools/services/plugins/resolutionSet/resolutionSet.c +++ b/open-vm-tools/services/plugins/resolutionSet/resolutionSet.c @@ -412,7 +412,7 @@ ResolutionSetCapabilities(gpointer src, ResolutionInfoType *resInfo = &resolutionInfo; int resServerCap = 0; - Debug("%s: enter\n", __FUNCTION__); +Debug("%s: enter\n", __FUNCTION__); if (set) { if (!resInfo->initialized) { return FALSE; @@ -427,11 +427,11 @@ ResolutionSetCapabilities(gpointer src, caps[DPY_TOPO_SET_IDX].value = 2; caps[DPY_GLOBAL_OFFSET_IDX].value = 1; - } #if defined(RESOLUTION_WIN32) - Debug("%s: setting DPY_TOPO_MODES_SET_IDX to 1\n", __FUNCTION__); - caps[DPY_TOPO_MODES_SET_IDX].value = 1; +Debug("%s: setting DPY_TOPO_MODES_SET_IDX to 1\n", __FUNCTION__); + caps[DPY_TOPO_MODES_SET_IDX].value = 1; #endif + } } ResolutionServerCapReg(ctx, resServerCap); diff --git a/open-vm-tools/services/plugins/timeSync/timeSync.c b/open-vm-tools/services/plugins/timeSync/timeSync.c index 6b7aaf100..bada3a34b 100644 --- a/open-vm-tools/services/plugins/timeSync/timeSync.c +++ b/open-vm-tools/services/plugins/timeSync/timeSync.c @@ -25,7 +25,7 @@ #define G_LOG_DOMAIN "timeSync" /* sync the time once a minute */ -#define TIME_SYNC_TIME 60000 +#define TIME_SYNC_TIME 60 /* only PERCENT_CORRECTION percent is corrected everytime */ #define PERCENT_CORRECTION 50 @@ -51,7 +51,7 @@ typedef struct TimeSyncData { gboolean slewCorrection; uint32 slewPercentCorrection; gint timeSyncState; - uint32 timeSyncPeriod; /* In milliseconds. */ + uint32 timeSyncPeriod; /* In seconds. */ GSource *timer; } TimeSyncData; @@ -223,6 +223,7 @@ TimeSyncDoSync(Bool slewCorrection, } } else if (slewCorrection && timeLagCall) { int64 slewDiff; + int64 timeSyncPeriodUS = data->timeSyncPeriod * 1000000; /* Don't consider interruptLag during clock slewing. */ slewDiff = diff - interruptLag; @@ -230,7 +231,7 @@ TimeSyncDoSync(Bool slewCorrection, /* Correct only data->slewPercentCorrection percent error. */ slewDiff = (data->slewPercentCorrection * slewDiff) / 100; - if (!System_EnableTimeSlew(slewDiff, data->timeSyncPeriod)) { + if (!System_EnableTimeSlew(slewDiff, timeSyncPeriodUS)) { g_warning("Unable to slew the guest OS time: %s.\n\n", Msg_ErrString()); return FALSE; } @@ -272,7 +273,7 @@ ToolsDaemonTimeSyncLoop(gpointer _data) { TimeSyncData *data = _data; - g_assert(data != NULL); + ASSERT(data != NULL); if (!TimeSyncDoSync(data->slewCorrection, FALSE, FALSE, data)) { g_warning("Unable to synchronize time.\n"); @@ -375,15 +376,15 @@ TimeSyncStartStopLoop(ToolsAppCtx *ctx, TimeSyncData *data, gboolean start) { - g_assert(data != NULL); + ASSERT(data != NULL); if (start && data->timer == NULL) { g_debug("Starting time sync loop.\n"); - g_debug("New sync period is %d sec.\n", data->timeSyncPeriod / 1000); + g_debug("New sync period is %d sec.\n", data->timeSyncPeriod); if (!ToolsDaemonTimeSyncLoop(data)) { return FALSE; } - data->timer = g_timeout_source_new(data->timeSyncPeriod); + data->timer = g_timeout_source_new(data->timeSyncPeriod * 1000); VMTOOLSAPP_ATTACH_SOURCE(ctx, data->timer, ToolsDaemonTimeSyncLoop, data, NULL); #if defined(_WIN32) @@ -487,9 +488,11 @@ TimeSyncSetOption(gpointer src, /* * Try the one-shot time sync if time sync transitions from * 'off' to 'on'. + * Note that if TOOLSOPTION_SYNCTIME_ENABLE is absent from + * vmx config file it is considered to be TRUE. */ if (data->timeSyncState == 0 && start && - g_key_file_get_boolean(ctx->config, "timeSync", + g_key_file_get_boolean(ctx->config, "vmsvc", TOOLSOPTION_SYNCTIME_ENABLE, NULL)) { TimeSyncDoSync(data->slewCorrection, TRUE, TRUE, data); } @@ -504,10 +507,15 @@ TimeSyncSetOption(gpointer src, g_debug("Daemon: Setting slewCorrection, %d.\n", data->slewCorrection); } else if (strcmp(option, TOOLSOPTION_SYNCTIME_PERCENTCORRECTION) == 0) { int32 percent; + g_debug("Daemon: Setting slewPercentCorrection to %s.\n", value); if (!StrUtil_StrToInt(&percent, value)) { return FALSE; } - data->slewPercentCorrection = percent; + if (percent <= 0 || percent > 100) { + data->slewPercentCorrection = PERCENT_CORRECTION; + } else { + data->slewPercentCorrection = percent; + } } else if (strcmp(option, TOOLSOPTION_SYNCTIME_PERIOD) == 0) { uint32 period; @@ -521,7 +529,7 @@ TimeSyncSetOption(gpointer src, * not running, just remember the new sync period value. */ if (period != data->timeSyncPeriod) { - data->timeSyncPeriod = (period > 0) ? period * 1000 : TIME_SYNC_TIME; + data->timeSyncPeriod = (period > 0) ? period : TIME_SYNC_TIME; if (data->timer != NULL) { TimeSyncStartStopLoop(ctx, data, FALSE); @@ -606,7 +614,7 @@ ToolsOnLoad(ToolsAppCtx *ctx) { TOOLS_APP_SIGNALS, VMTools_WrapArray(sigs, sizeof *sigs, ARRAYSIZE(sigs)) } }; - data->slewCorrection = TRUE; + data->slewCorrection = FALSE; data->slewPercentCorrection = PERCENT_CORRECTION; data->timeSyncState = -1; data->timeSyncPeriod = TIME_SYNC_TIME; diff --git a/open-vm-tools/services/plugins/vmbackup/stateMachine.c b/open-vm-tools/services/plugins/vmbackup/stateMachine.c index 3334752a8..d2e63060c 100644 --- a/open-vm-tools/services/plugins/vmbackup/stateMachine.c +++ b/open-vm-tools/services/plugins/vmbackup/stateMachine.c @@ -178,8 +178,8 @@ static void VmBackupFinalize(void) { g_debug("*** %s\n", __FUNCTION__); - g_assert(gBackupState != NULL); - g_assert(gBackupState->machineState == VMBACKUP_MSTATE_IDLE); + ASSERT(gBackupState != NULL); + ASSERT(gBackupState->machineState == VMBACKUP_MSTATE_IDLE); if (gBackupState->currentOp != NULL) { VmBackup_Cancel(gBackupState->currentOp); @@ -196,7 +196,8 @@ VmBackupFinalize(void) g_source_destroy(gBackupState->keepAlive); } - free(gBackupState->volumes); + g_free(gBackupState->volumes); + g_free(gBackupState->snapshots); free(gBackupState); gBackupState = NULL; } @@ -306,7 +307,7 @@ static gboolean VmBackupAsyncCallback(void *clientData) { g_debug("*** %s\n", __FUNCTION__); - g_assert(gBackupState != NULL); + ASSERT(gBackupState != NULL); g_source_unref(gBackupState->timerEvent); gBackupState->timerEvent = NULL; @@ -487,7 +488,7 @@ VmBackupStart(RpcInData *data) } if (data->args[index] != '\0') { - gBackupState->volumes = Util_SafeStrdup(data->args + index); + gBackupState->volumes = g_strndup(data->args + index, data->argsSize - index); } } @@ -577,6 +578,9 @@ VmBackupSnapshotDone(RpcInData *data) "Error: unexpected state for snapshot done message.", FALSE); } else { + if (data->argsSize > 1) { + gBackupState->snapshots = g_strndup(data->args + 1, data->argsSize - 1); + } if (!gSyncProvider->snapshotDone(gBackupState, gSyncProvider->clientData)) { VmBackup_SendEvent(VMBACKUP_EVENT_REQUESTOR_ERROR, VMBACKUP_SYNC_ERROR, diff --git a/open-vm-tools/services/plugins/vmbackup/vmBackupInt.h b/open-vm-tools/services/plugins/vmbackup/vmBackupInt.h index f9e2da313..8e316c3c2 100644 --- a/open-vm-tools/services/plugins/vmbackup/vmBackupInt.h +++ b/open-vm-tools/services/plugins/vmbackup/vmBackupInt.h @@ -80,7 +80,8 @@ typedef struct VmBackupState { VmBackupOp *currentOp; const char *currentOpName; char *volumes; - guint pollPeriod; + char *snapshots; + guint pollPeriod; GSource *timerEvent; GSource *keepAlive; Bool (*callback)(struct VmBackupState *); diff --git a/open-vm-tools/services/plugins/vmbackup/vmbackup_def.h b/open-vm-tools/services/plugins/vmbackup/vmbackup_def.h index 55665470f..76780187d 100644 --- a/open-vm-tools/services/plugins/vmbackup/vmbackup_def.h +++ b/open-vm-tools/services/plugins/vmbackup/vmbackup_def.h @@ -80,11 +80,5 @@ typedef enum { VMBACKUP_UNEXPECTED_ERROR } VmBackupStatus; -/* Event name used for communnication between the VSS components. */ -#ifdef _WIN32 -#define VMVSS_RESUME_MSG TEXT("VmVss_ResumeSnapshotProvider") -#define VMVSS_LOGGING_EVENT TEXT("VmVss_DebugLoggingEvent") -#endif - #endif diff --git a/open-vm-tools/services/vmtoolsd/Makefile.am b/open-vm-tools/services/vmtoolsd/Makefile.am index 6b1ada90a..a1f238f20 100644 --- a/open-vm-tools/services/vmtoolsd/Makefile.am +++ b/open-vm-tools/services/vmtoolsd/Makefile.am @@ -25,7 +25,7 @@ vmtoolsd_CPPFLAGS += @GMODULE_CPPFLAGS@ vmtoolsd_CPPFLAGS += @GOBJECT_CPPFLAGS@ vmtoolsd_CPPFLAGS += @GTHREAD_CPPFLAGS@ vmtoolsd_CPPFLAGS += -I$(builddir) -vmtoolsd_CPPFLAGS += -DVMTOOLSD_PLUGIN_ROOT=\"$(pkglibdir)\" +vmtoolsd_CPPFLAGS += -DVMTOOLSD_PLUGIN_ROOT=\"$(pkglibdir)/plugins\" vmtoolsd_LDADD = vmtoolsd_LDADD += @VMTOOLS_LIBS@ diff --git a/open-vm-tools/services/vmtoolsd/mainLoop.c b/open-vm-tools/services/vmtoolsd/mainLoop.c index bb30d4692..6e346663a 100644 --- a/open-vm-tools/services/vmtoolsd/mainLoop.c +++ b/open-vm-tools/services/vmtoolsd/mainLoop.c @@ -66,8 +66,8 @@ ToolsCoreInitializeDebug(ToolsServiceState *state) } libdata = initFn(&state->ctx, state->debugPlugin); - g_assert(libdata != NULL); - g_assert(libdata->debugPlugin != NULL); + ASSERT(libdata != NULL); + ASSERT(libdata->debugPlugin != NULL); state->debugData = libdata; } @@ -178,52 +178,31 @@ void ToolsCore_DumpState(ToolsServiceState *state) { guint i; + const char *providerStates[] = { + "idle", + "active", + "error" + }; + + ASSERT_ON_COMPILE(ARRAYSIZE(providerStates) == TOOLS_PROVIDER_MAX); g_message("VM Tools Service '%s':\n", state->name); g_message(" Plugin path: %s\n", state->pluginPath); - if (state->plugins != NULL) { - for (i = 0; i < state->plugins->len; i++) { - ToolsPlugin *plugin = g_ptr_array_index(state->plugins, i); - GArray *regs = (plugin->data != NULL) ? plugin->data->regs : NULL; - guint j; - - g_message(" Plugin: %s\n", plugin->data->name); - - if (regs == NULL) { - g_message(" No registrations.\n"); - continue; - } - - for (j = 0; j < regs->len; j++) { - guint k; - ToolsAppReg *reg = &g_array_index(regs, ToolsAppReg, j); - - switch (reg->type) { - case TOOLS_APP_GUESTRPC: - for (k = 0; k < reg->data->len; k++) { - RpcChannelCallback *cb = &g_array_index(reg->data, - RpcChannelCallback, - k); - g_message(" RPC callback: %s\n", cb->name); - } - break; - - case TOOLS_APP_SIGNALS: - for (k = 0; k < reg->data->len; k++) { - ToolsPluginSignalCb *sig = &g_array_index(reg->data, - ToolsPluginSignalCb, - k); - g_message(" Signal callback: %s\n", sig->signame); - } - break; - } - } + for (i = 0; i < state->providers->len; i++) { + ToolsAppProviderReg *prov = &g_array_index(state->providers, + ToolsAppProviderReg, + i); + g_message(" App provider: %s (%s)\n", + prov->prov->name, + providerStates[prov->state]); + if (prov->prov->dumpState != NULL) { + prov->prov->dumpState(&state->ctx, prov->prov, NULL); } - } else { - g_message(" No plugins loaded."); } + ToolsCore_DumpPluginInfo(state); + g_signal_emit_by_name(state->ctx.serviceObj, TOOLS_CORE_SIG_DUMP_STATE, &state->ctx); @@ -274,6 +253,7 @@ ToolsCore_Setup(ToolsServiceState *state) /* Initializes the app context. */ gctx = g_main_context_default(); + state->ctx.version = TOOLS_CORE_API_V1; state->ctx.name = state->name; state->ctx.errorCode = EXIT_SUCCESS; state->ctx.mainLoop = g_main_loop_new(gctx, TRUE); diff --git a/open-vm-tools/services/vmtoolsd/mainPosix.c b/open-vm-tools/services/vmtoolsd/mainPosix.c index 688988e9b..ded73ff04 100644 --- a/open-vm-tools/services/vmtoolsd/mainPosix.c +++ b/open-vm-tools/services/vmtoolsd/mainPosix.c @@ -123,9 +123,12 @@ main(int argc, * was used, or things may not work as expected. */ if (!g_path_is_absolute(argv[0])) { - char *cwd = File_Cwd(NULL); - char *abs = g_strdup_printf("%s%c%s", cwd, DIRSEPC, argv[0]); - vm_free(cwd); + gchar *abs = g_find_program_in_path(argv[0]); + if (abs == NULL) { + char *cwd = File_Cwd(NULL); + abs = g_strdup_printf("%s%c%s", cwd, DIRSEPC, argv[0]); + vm_free(cwd); + } argv[0] = abs; } diff --git a/open-vm-tools/services/vmtoolsd/pluginMgr.c b/open-vm-tools/services/vmtoolsd/pluginMgr.c index 797b01979..fc8f083f9 100644 --- a/open-vm-tools/services/vmtoolsd/pluginMgr.c +++ b/open-vm-tools/services/vmtoolsd/pluginMgr.c @@ -31,9 +31,288 @@ #ifdef USE_APPLOADER -static Bool (*LoadDependencies)(char *libName); +static Bool (*LoadDependencies)(char *libName, Bool useShipped); #endif +typedef void (*PluginDataCallback)(ToolsServiceState *state, + ToolsPluginData *plugin); + +typedef void (*PluginAppRegCallback)(ToolsServiceState *state, + ToolsPluginData *plugin, + ToolsAppType type, + ToolsAppProviderReg *preg, + gpointer reg); + + +/** + * State dump callback for application registration information. + * + * @param[in] state The service state. + * @param[in] plugin The plugin information. + * @param[in] type Application type. + * @param[in] preg Provider information. + * @param[in] reg Application registration. + */ + +static void +ToolsCoreDumpAppInfo(ToolsServiceState *state, + ToolsPluginData *plugin, + ToolsAppType type, + ToolsAppProviderReg *preg, + gpointer reg) +{ + if (preg != NULL) { + if (preg->prov->dumpState != NULL) { + preg->prov->dumpState(&state->ctx, preg->prov, reg); + } else { + g_message(" App type %u (no provider info).\n", type); + } + } else { + g_message(" App type %u (no provider).\n", type); + } +} + + +/** + * State dump callback for generic plugin information. + * + * @param[in] state The service state. + * @param[in] plugin The plugin information. + */ + +static void +ToolsCoreDumpPluginInfo(ToolsServiceState *state, + ToolsPluginData *plugin) +{ + g_message(" Plugin: %s\n", plugin->name); + + if (plugin->regs == NULL) { + g_message(" No registrations.\n"); + } +} + + +/** + * State dump callback for GuestRPC applications. + * + * @param[in] ctx The application context. + * @param[in] prov Unused. + * @param[in] reg The application registration data. + */ + +static void +ToolsCoreDumpRPC(ToolsAppCtx *ctx, + ToolsAppProvider *prov, + gpointer reg) +{ + if (reg != NULL) { + RpcChannelCallback *cb = reg; + g_message(" RPC callback: %s\n", cb->name); + } +} + + +/** + * State dump callback for signal connections. + * + * @param[in] ctx The application context. + * @param[in] prov Unused. + * @param[in] reg The application registration data. + */ + +static void +ToolsCoreDumpSignal(ToolsAppCtx *ctx, + ToolsAppProvider *prov, + gpointer reg) +{ + if (reg != NULL) { + ToolsPluginSignalCb *sig = reg; + g_message(" Signal callback: %s\n", sig->signame); + } +} + + +/** + * Callback to register applications with the given provider. + * + * @param[in] state The service state. + * @param[in] plugin The plugin information. + * @param[in] type Application type. + * @param[in] preg Provider information. + * @param[in] reg Application registration. + */ + +static void +ToolsCoreRegisterApp(ToolsServiceState *state, + ToolsPluginData *plugin, + ToolsAppType type, + ToolsAppProviderReg *preg, + gpointer reg) +{ + if (preg == NULL) { + g_warning("Plugin %s wants to register app of type %d but no " + "provider was found.\n", plugin->name, type); + return; + } + + if (preg->state == TOOLS_PROVIDER_ERROR) { + g_warning("Plugin %s wants to register app of type %d but the " + "provider failed to activate.\n", plugin->name, type); + return; + } + + /* + * Register the app with the provider, activating it if necessary. If + * it fails to activate, tag it so we don't try again. + */ + if (preg->state == TOOLS_PROVIDER_IDLE) { + if (preg->prov->activate != NULL) { + GError *err = NULL; + preg->prov->activate(&state->ctx, preg->prov, &err); + if (err != NULL) { + g_warning("Error activating provider %s: %s.\n", + preg->prov->name, err->message); + preg->state = TOOLS_PROVIDER_ERROR; + g_clear_error(&err); + return; + } + } + preg->state = TOOLS_PROVIDER_ACTIVE; + } + + preg->prov->registerApp(&state->ctx, preg->prov, reg); +} + + +/** + * Callback to register application providers. + * + * @param[in] state The service state. + * @param[in] plugin The plugin information. + * @param[in] type Application type. + * @param[in] preg Provider information. + * @param[in] reg Application registration. + */ + +static void +ToolsCoreRegisterProvider(ToolsServiceState *state, + ToolsPluginData *plugin, + ToolsAppType type, + ToolsAppProviderReg *preg, + gpointer reg) +{ + if (type == TOOLS_APP_PROVIDER) { + ToolsAppProvider *prov = reg; + ToolsAppProviderReg newreg = { prov, TOOLS_PROVIDER_IDLE }; + + /* Assert that no two providers choose the same app type. */ + ASSERT(preg == NULL); + + ASSERT(prov->name != NULL); + ASSERT(prov->registerApp != NULL); + g_array_append_val(state->providers, newreg); + } +} + + +/** + * Iterates through the list of plugins, and through each plugin's app + * registration data, calling the appropriate callback for each piece + * of data. + * + * One of the two callback arguments must be provided. + * + * @param[in] state Service state. + * @param[in] pluginCb Callback called for each plugin data instance. + * @param[in] appRegCb Callback called for each application registration. + */ + +static void +ToolsCoreForEachPlugin(ToolsServiceState *state, + PluginDataCallback pluginCb, + PluginAppRegCallback appRegCb) +{ + guint i; + + ASSERT(pluginCb != NULL || appRegCb != NULL); + + for (i = 0; i < state->plugins->len; i++) { + ToolsPlugin *plugin = g_ptr_array_index(state->plugins, i); + GArray *regs = (plugin->data != NULL) ? plugin->data->regs : NULL; + guint j; + + if (pluginCb != NULL) { + pluginCb(state, plugin->data); + } + + if (regs == NULL || appRegCb == NULL) { + continue; + } + + for (j = 0; j < regs->len; j++) { + guint k; + guint provIdx = -1; + ToolsAppReg *reg = &g_array_index(regs, ToolsAppReg, j); + ToolsAppProviderReg *preg = NULL; + + /* Find the provider for the desired reg type. */ + for (k = 0; k < state->providers->len; k++) { + ToolsAppProviderReg *tmp = &g_array_index(state->providers, + ToolsAppProviderReg, + k); + if (tmp->prov->regType == reg->type) { + preg = tmp; + provIdx = k; + break; + } + } + + for (k = 0; k < reg->data->len; k++) { + gpointer appdata = ®->data->data[preg->prov->regSize * k]; + appRegCb(state, plugin->data, reg->type, preg, appdata); + } + } + } +} + + +/** + * Registration callback for GuestRPC applications. + * + * @param[in] ctx The application context. + * @param[in] prov Unused. + * @param[in] reg The application registration data. + */ + +static void +ToolsCoreRegisterRPC(ToolsAppCtx *ctx, + ToolsAppProvider *prov, + gpointer reg) +{ + RpcChannel_RegisterCallback(ctx->rpc, reg); +} + + +/** + * Registration callback for signal connections. + * + * @param[in] ctx The application context. + * @param[in] prov Unused. + * @param[in] reg The application registration data. + */ + +static void +ToolsCoreRegisterSignal(ToolsAppCtx *ctx, + ToolsAppProvider *prov, + gpointer reg) +{ + ToolsPluginSignalCb *sig = reg; + g_signal_connect(ctx->serviceObj, + sig->signame, + sig->callback, + sig->clientData); +} + /** * Compares two strings. To be used with g_ptr_array_sort. @@ -54,6 +333,23 @@ ToolsCoreStrPtrCompare(gconstpointer _str1, } +/** + * State dump callback for logging information about loaded plugins. + * + * @param[in] state The service state. + */ + +void +ToolsCore_DumpPluginInfo(ToolsServiceState *state) +{ + if (state->plugins == NULL) { + g_message(" No plugins loaded."); + } else { + ToolsCoreForEachPlugin(state, ToolsCoreDumpPluginInfo, ToolsCoreDumpAppInfo); + } +} + + /** * Loads all plugins present in the plugin directory. If the plugin path * is NULL, then default directories are used in case the service is either @@ -158,7 +454,7 @@ ToolsCore_LoadPlugins(ToolsServiceState *state) } #ifdef USE_APPLOADER - if (!LoadDependencies(path)) { + if (!LoadDependencies(path, FALSE)) { g_warning("Loading of library dependencies for %s failed.\n", entry); goto next; } @@ -226,59 +522,54 @@ exit: void ToolsCore_RegisterPlugins(ToolsServiceState *state) { - guint i; + ToolsAppProvider *fakeProv; + ToolsAppProviderReg fakeReg; if (state->plugins == NULL) { return; } - for (i = 0; i < state->plugins->len; i++) { - ToolsPlugin *plugin = g_ptr_array_index(state->plugins, i); - GArray *regs = (plugin->data != NULL) ? plugin->data->regs : NULL; - guint j; + /* + * Create two "fake" app providers for the functionality provided by + * vmtoolsd (GuestRPC channel, glib signals). + */ + state->providers = g_array_new(FALSE, TRUE, sizeof (ToolsAppProviderReg)); + + if (state->ctx.rpc != NULL) { + fakeProv = g_malloc0(sizeof *fakeProv); + fakeProv->regType = TOOLS_APP_GUESTRPC; + fakeProv->regSize = sizeof (RpcChannelCallback); + fakeProv->name = "GuestRPC"; + fakeProv->registerApp = ToolsCoreRegisterRPC; + fakeProv->dumpState = ToolsCoreDumpRPC; + + fakeReg.prov = fakeProv; + fakeReg.state = TOOLS_PROVIDER_ACTIVE; + g_array_append_val(state->providers, fakeReg); + } - if (regs == NULL) { - continue; - } + fakeProv = g_malloc0(sizeof *fakeProv); + fakeProv->regType = TOOLS_APP_SIGNALS; + fakeProv->regSize = sizeof (ToolsPluginSignalCb); + fakeProv->name = "Signals"; + fakeProv->registerApp = ToolsCoreRegisterSignal; + fakeProv->dumpState = ToolsCoreDumpSignal; - for (j = 0; j < regs->len; j++) { - guint k; - ToolsAppReg *reg = &g_array_index(regs, ToolsAppReg, j); + fakeReg.prov = fakeProv; + fakeReg.state = TOOLS_PROVIDER_ACTIVE; + g_array_append_val(state->providers, fakeReg); - switch (reg->type) { - case TOOLS_APP_GUESTRPC: - ASSERT(reg->data != NULL); - if (state->ctx.rpc == NULL) { - g_warning("Plugin '%s' asked to register a Guest RPC handler, " - "but there's no RPC channel.\n", plugin->data->name); - } else { - for (k = 0; k < reg->data->len; k++) { - RpcChannelCallback *cb = &g_array_index(reg->data, - RpcChannelCallback, - k); - RpcChannel_RegisterCallback(state->ctx.rpc, cb); - } - } - break; - - case TOOLS_APP_SIGNALS: - ASSERT(reg->data != NULL); - for (k = 0; k < reg->data->len; k++) { - ToolsPluginSignalCb *sig = &g_array_index(reg->data, - ToolsPluginSignalCb, - k); - g_signal_connect(state->ctx.serviceObj, - sig->signame, - sig->callback, - sig->clientData); - } - break; + /* + * First app providers need to be identified, so that we know that they're + * available for use by plugins who need them. + */ + ToolsCoreForEachPlugin(state, NULL, ToolsCoreRegisterProvider); - default: - NOT_IMPLEMENTED(); - } - } - } + /* + * Now that we know all app providers, register all the apps, activating + * individual app providers as necessary. + */ + ToolsCoreForEachPlugin(state, NULL, ToolsCoreRegisterApp); } @@ -298,6 +589,7 @@ ToolsCore_RegisterPlugins(ToolsServiceState *state) void ToolsCore_UnloadPlugins(ToolsServiceState *state) { + guint i; GArray *pcaps = NULL; if (state->plugins == NULL) { @@ -317,6 +609,25 @@ ToolsCore_UnloadPlugins(ToolsServiceState *state) g_signal_emit_by_name(state->ctx.serviceObj, TOOLS_CORE_SIG_SHUTDOWN, &state->ctx); + /* + * Stop all app providers, and free the memory we allocated for the two + * internal app providers. + */ + for (i = 0; i < state->providers->len; i++) { + ToolsAppProviderReg *preg = &g_array_index(state->providers, + ToolsAppProviderReg, + i); + + if (preg->prov->shutdown != NULL) { + preg->prov->shutdown(&state->ctx, preg->prov); + } + + if (preg->prov->regType == TOOLS_APP_GUESTRPC || + preg->prov->regType == TOOLS_APP_SIGNALS) { + g_free(preg->prov); + } + } + while (state->plugins->len > 0) { ToolsPlugin *plugin = g_ptr_array_index(state->plugins, state->plugins->len - 1); GArray *regs = (plugin->data != NULL) ? plugin->data->regs : NULL; @@ -339,6 +650,9 @@ ToolsCore_UnloadPlugins(ToolsServiceState *state) g_free(plugin); } + g_array_free(state->providers, TRUE); + state->providers = NULL; + g_ptr_array_free(state->plugins, TRUE); state->plugins = NULL; } diff --git a/open-vm-tools/services/vmtoolsd/toolsCoreInt.h b/open-vm-tools/services/vmtoolsd/toolsCoreInt.h index 631824f9a..3e12654c6 100644 --- a/open-vm-tools/services/vmtoolsd/toolsCoreInt.h +++ b/open-vm-tools/services/vmtoolsd/toolsCoreInt.h @@ -45,6 +45,22 @@ typedef struct ToolsPlugin { ToolsPluginData *data; } ToolsPlugin; +/** State of app providers. */ +typedef enum { + TOOLS_PROVIDER_IDLE, + TOOLS_PROVIDER_ACTIVE, + TOOLS_PROVIDER_ERROR, + + /* Keep this as the last one, always. */ + TOOLS_PROVIDER_MAX +} ToolsAppProviderState; + +/** Defines the internal app provider data. */ +typedef struct ToolsAppProviderReg { + ToolsAppProvider *prov; + ToolsAppProviderState state; +} ToolsAppProviderReg; + /** Defines internal service state. */ typedef struct ToolsServiceState { gchar *name; @@ -63,6 +79,7 @@ typedef struct ToolsServiceState { gchar *debugPlugin; RpcDebugLibData *debugData; ToolsAppCtx ctx; + GArray *providers; } ToolsServiceState; @@ -74,6 +91,9 @@ ToolsCore_ParseCommandLine(ToolsServiceState *state, void ToolsCore_Cleanup(ToolsServiceState *state); +void +ToolsCore_DumpPluginInfo(ToolsServiceState *state); + void ToolsCore_DumpState(ToolsServiceState *state); diff --git a/open-vm-tools/services/vmtoolsd/toolsRpc.c b/open-vm-tools/services/vmtoolsd/toolsRpc.c index 5406d19f7..3f85401f8 100644 --- a/open-vm-tools/services/vmtoolsd/toolsRpc.c +++ b/open-vm-tools/services/vmtoolsd/toolsRpc.c @@ -58,7 +58,7 @@ ToolsCoreCheckReset(struct RpcChannel *chan, gchar *msg; app = ToolsCore_GetTcloName(state); - g_assert(app != NULL); + ASSERT(app != NULL); msg = g_strdup_printf("vmx.capability.unified_loop %s", app); if (!RpcChannel_Send(state->ctx.rpc, msg, strlen(msg) + 1, NULL, NULL)) { @@ -229,7 +229,7 @@ ToolsCore_InitRpc(ToolsServiceState *state) const gchar *app; GMainContext *mainCtx = g_main_loop_get_context(state->ctx.mainLoop); - g_assert(state->ctx.rpc == NULL); + ASSERT(state->ctx.rpc == NULL); if (state->debugPlugin != NULL) { app = "debug"; @@ -251,7 +251,7 @@ ToolsCore_InitRpc(ToolsServiceState *state) state->ctx.rpc = RpcChannel_NewBackdoorChannel(mainCtx); app = ToolsCore_GetTcloName(state); - g_assert(app != NULL); + ASSERT(app != NULL); } RpcChannel_Setup(state->ctx.rpc, diff --git a/open-vm-tools/toolbox/toolbox-cmd.c b/open-vm-tools/toolbox/toolbox-cmd.c index 2580ca412..33534bba5 100644 --- a/open-vm-tools/toolbox/toolbox-cmd.c +++ b/open-vm-tools/toolbox/toolbox-cmd.c @@ -1,3 +1,4 @@ + /********************************************************* * Copyright (C) 2008 VMware, Inc. All rights reserved. * @@ -35,7 +36,7 @@ VM_EMBED_VERSION(TOOLBOXCMD_VERSION_STRING); typedef int (*ToolboxCmdFunc)(char **argv, int argc); -typedef void (*ToolboxHelpFunc)(char *progName); +typedef void (*ToolboxHelpFunc)(const char *progName); /* @@ -43,13 +44,14 @@ typedef void (*ToolboxHelpFunc)(char *progName); */ const typedef struct CmdTable { - const char *command; /* The name of the command. */ - ToolboxCmdFunc func; /* The function to execute. */ - Bool requireRoot; /* Indicates whether root is required. */ - ToolboxHelpFunc helpFunc; /* The help function associated with the command. */ + const char *command; /* The name of the command. */ + ToolboxCmdFunc func; /* The function to execute. */ + Bool requireArguments; /* The function requires arguments. */ + Bool requireRoot; /* Indicates whether root is required. */ + ToolboxHelpFunc helpFunc; /* The help function associated with the command. */ } CmdTable; -static int quiet_flag; /* Flag set by `--quiet'. */ +static Bool quiet_flag; /* Flag set by `--quiet'. */ /* * Sadly, our home-brewed implementation of getopt() doesn't come with an @@ -78,14 +80,13 @@ static int DiskCommand(char **argv, int argc); static int StatCommand(char **argv, int argc); static int ScriptCommand(char **argv, int argc); static int TimeSyncCommand(char **argv, int argc); -static void DeviceHelp(char *progName); -static void DiskHelp(char *progName); -static void ScriptHelp(char *progName); -static void StatHelp(char *progName); -static void TimeSyncHelp(char *progName); -static void ToolboxCmdHelp(char *progName); +static void DeviceHelp(const char *progName); +static void DiskHelp(const char *progName); +static void ScriptHelp(const char *progName); +static void StatHelp(const char *progName); +static void TimeSyncHelp(const char *progName); +static void ToolboxCmdHelp(const char *progName); static CmdTable *ParseCommand(char **argv, int argc); -static Bool CheckArgumentLength(char **argv, int argc); /* @@ -93,43 +94,62 @@ static Bool CheckArgumentLength(char **argv, int argc); * Must go after function declarations */ static CmdTable commands[] = { - { "timesync", TimeSyncCommand, FALSE, TimeSyncHelp}, - { "script", ScriptCommand, TRUE, ScriptHelp}, - { "disk", DiskCommand, TRUE, DiskHelp}, - { "stat", StatCommand, FALSE, StatHelp}, - { "device", DeviceCommand, FALSE, DeviceHelp}, - { "help", HelpCommand, FALSE, ToolboxCmdHelp}, - { NULL, } }; + { "timesync", TimeSyncCommand, TRUE, FALSE, TimeSyncHelp}, + { "script", ScriptCommand, FALSE /* We will handle argument checks ourselves */, + TRUE, ScriptHelp}, + { "disk", DiskCommand, TRUE, TRUE, DiskHelp}, + { "stat", StatCommand, TRUE, FALSE, StatHelp}, + { "device", DeviceCommand, TRUE, FALSE, DeviceHelp}, + { "help", HelpCommand, FALSE, FALSE, ToolboxCmdHelp}, +}; /* *----------------------------------------------------------------------------- * - * CheckArgumentLength -- + * ToolboxMissingEntityError -- * - * Makes sure that the program receives at least one subcommand. + * Print out error message regarding missing argument. * * Results: - * TRUE if there is at least one subcommand. - * FALSE otherwise. + * None. * * Side effects: - * Prints to stderr if the subcommand is missing. + * None. * *----------------------------------------------------------------------------- */ -static Bool -CheckArgumentLength(char **argv, // IN: The command line arguments. - int argc) // IN: The length of the command line argumensts +static void +ToolboxMissingEntityError(const char *name, // IN: command name (argv[0]) + const char *entity) // IN: what is missing { - if (++optind < argc) { - return TRUE; - } else { - fprintf(stderr, "Missing command\n"); - return FALSE; - } + fprintf(stderr, "%s: Missing %s\n", name, entity); +} + +/* + *----------------------------------------------------------------------------- + * + * ToolboxUnknownEntityError -- + * + * Print out error message regarding unknown argument. + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static void +ToolboxUnknownEntityError(const char *name, // IN: command name (argv[0]) + const char *entity, // IN: what is unknown + const char *str) // IN: errorneous string +{ + fprintf(stderr, "%s: Unknown %s '%s'\n", name, entity, str); } @@ -150,7 +170,7 @@ CheckArgumentLength(char **argv, // IN: The command line arguments. */ static void -DeviceHelp(char *progName) // IN: The name of the program obtained from argv[0] +DeviceHelp(const char *progName) // IN: The name of the program obtained from argv[0] { printf("device: functions related to the virtual machine's hardware devices\n" "Usage: %s device [args]\n" @@ -180,19 +200,19 @@ DeviceHelp(char *progName) // IN: The name of the program obtained from argv[0] */ static void -ToolboxCmdHelp(char *progName) +ToolboxCmdHelp(const char *progName) { printf("Usage: %s [options] [subcommand]\n" "Type \'%s help \' for help on a specific command.\n" - "Type \'%s --version' to see the Vmware Tools version.\n" - "Use --quiet to suppress stdout output.\n" + "Type \'%s -v' to see the Vmware Tools version.\n" + "Use '-q' option to suppress stdout output.\n" "Most commands take a subcommand.\n\n" "Available commands:\n" - " timesync\n" " device\n" - " script\n" " disk\n" + " script\n" " stat\n" + " timesync\n" "\n" "For additional information please visit http://www.vmware.com/support/\n\n", progName, progName, progName); @@ -216,7 +236,7 @@ ToolboxCmdHelp(char *progName) */ static void -TimeSyncHelp(char *progName) // IN: The name of the program obtained from argv[0] +TimeSyncHelp(const char *progName) // IN: The name of the program obtained from argv[0] { printf("timesync: functions for controlling time synchronization on the guest OS\n" "Usage: %s timesync \n\n" @@ -244,10 +264,10 @@ TimeSyncHelp(char *progName) // IN: The name of the program obtained from argv[0 */ static void -ScriptHelp(char *progName) // IN: The name of the program obtained from argv[0] +ScriptHelp(const char *progName) // IN: The name of the program obtained from argv[0] { printf("script: control the scripts run in response to power operations\n" - "Usage: %s script [args]\n\n" + "Usage: %s script [args]\n\n" "Subcommands:\n" " enable: enable the given script and restore its path to the default\n" " disable: disable the given script\n" @@ -274,7 +294,7 @@ ScriptHelp(char *progName) // IN: The name of the program obtained from argv[0] */ static void -DiskHelp(char *progName) // IN: The name of the program obtained from argv[0] +DiskHelp(const char *progName) // IN: The name of the program obtained from argv[0] { printf("disk: perform disk shrink operations\n" "Usage: %s disk [args]\n\n" @@ -302,7 +322,7 @@ DiskHelp(char *progName) // IN: The name of the program obtained from argv[0] */ static void -StatHelp(char *progName) // IN: The name of the program obtained from argv[0] +StatHelp(const char *progName) // IN: The name of the program obtained from argv[0] { printf("stat: print useful guest and host information\n" "Usage: %s stat \n\n" @@ -342,19 +362,23 @@ static int HelpCommand(char **argv, // IN: Command line arguments int argc) // IN: Length of argv { - if (CheckArgumentLength(argv, argc)) { - int i = 0; - while (commands[i].command != 0) { - if (toolbox_strcmp(commands[i].command, argv[optind]) == 0) { + int retval = EXIT_SUCCESS; + + if (++optind < argc) { + int i; + + for (i = 0; i < ARRAYSIZE(commands); i++) { + if (toolbox_strcmp(commands[i].command, argv[optind]) == 0) { commands[i].helpFunc(argv[0]); return EXIT_SUCCESS; } - i++; } - fprintf(stderr, "Unknown subcommand\n"); + ToolboxUnknownEntityError(argv[0], "subcommand", argv[optind]); + retval = EX_USAGE; } + ToolboxCmdHelp(argv[0]); - return EX_USAGE; + return retval; } @@ -367,7 +391,7 @@ HelpCommand(char **argv, // IN: Command line arguments * * Results: * Returns EXIT_SUCCESS on success. - * Returns ther exit code on errors. + * Returns the exit code on errors. * * Side effects: * Might enable or disable a device. @@ -377,31 +401,31 @@ HelpCommand(char **argv, // IN: Command line arguments static int DeviceCommand(char **argv, // IN: Command line arguments - int argc) // IN: Length of command line argumenst + int argc) // IN: Length of command line arguments { - if (CheckArgumentLength(argv, argc)) { - if (toolbox_strcmp(argv[optind], "list") == 0) { - return Devices_ListDevices(); - } else { - char *subcommand = argv[optind++]; - if (optind < argc) { - if (toolbox_strcmp(subcommand, "status") == 0) { - return Devices_DeviceStatus(argv[optind]); - } else if (toolbox_strcmp(subcommand, "enable") == 0) { - return Devices_EnableDevice(argv[optind], quiet_flag); - } else if (toolbox_strcmp(subcommand, "disable") == 0) { - return Devices_DisableDevice(argv[optind], quiet_flag); - } else { - fprintf(stderr, "Unknown subcommand\n"); - - } - } else { - fprintf(stderr, "Missing device name\n"); - - } + char *subcommand = argv[optind]; + Bool haveDeviceArg = optind + 1 < argc; + + if (toolbox_strcmp(subcommand, "list") == 0) { + return Devices_ListDevices(); + } else if (toolbox_strcmp(subcommand, "status") == 0) { + if (haveDeviceArg) { + return Devices_DeviceStatus(argv[optind + 1]); + } + } else if (toolbox_strcmp(subcommand, "enable") == 0) { + if (haveDeviceArg) { + return Devices_EnableDevice(argv[optind + 1], quiet_flag); } + } else if (toolbox_strcmp(subcommand, "disable") == 0) { + if (haveDeviceArg) { + return Devices_DisableDevice(argv[optind + 1], quiet_flag); + } + } else { + ToolboxUnknownEntityError(argv[0], "subcommand", subcommand); + return EX_USAGE; } - DeviceHelp(argv[0]); + + ToolboxMissingEntityError(argv[0], "device name"); return EX_USAGE; } @@ -427,22 +451,17 @@ static int DiskCommand(char **argv, // IN: command line arguments int argc) // IN: The length of the command line arguments { - if (CheckArgumentLength(argv, argc)) { - if (toolbox_strcmp(argv[optind], "list") == 0) { - return Shrink_List(); - } else if (toolbox_strcmp(argv[optind], "shrink") == 0) { - optind++; // Position optind at the mountpoint - if (optind < argc) { - return Shrink_DoShrink(argv[optind], quiet_flag); - } else { - fprintf(stderr, "Missing mount point\n"); - } + if (toolbox_strcmp(argv[optind], "list") == 0) { + return Shrink_List(); + } else if (toolbox_strcmp(argv[optind], "shrink") == 0) { + if (++optind >= argc) { + ToolboxMissingEntityError(argv[0], "mount point"); } else { - fprintf(stderr, "Unknown subcommand\n"); - + return Shrink_DoShrink(argv[optind], quiet_flag); } + } else { + ToolboxUnknownEntityError(argv[0], "subcommand", argv[optind]); } - DiskHelp(argv[0]); return EX_USAGE; } @@ -465,36 +484,33 @@ DiskCommand(char **argv, // IN: command line arguments */ static int -StatCommand(char **argv, // IN: Comand line arguments +StatCommand(char **argv, // IN: Command line arguments int argc) // IN: Length of command line arguments { - if (CheckArgumentLength(argv, argc)) { - if (toolbox_strcmp(argv[optind], "memory") == 0) { - return Stat_MemorySize(); - } else if (toolbox_strcmp(argv[optind], "hosttime") == 0) { - return Stat_HostTime(); - } else if (toolbox_strcmp(argv[optind], "sessionid") == 0) { - return Stat_GetSessionID(); - } else if (toolbox_strcmp(argv[optind], "balloon") == 0) { - return Stat_GetMemoryBallooned(); - } else if (toolbox_strcmp(argv[optind], "swap") == 0) { - return Stat_GetMemorySwapped(); - } else if (toolbox_strcmp(argv[optind], "memlimit") == 0) { - return Stat_GetMemoryLimit(); - } else if (toolbox_strcmp(argv[optind], "memres") == 0) { - return Stat_GetMemoryReservation(); - } else if (toolbox_strcmp(argv[optind], "cpures") == 0) { - return Stat_GetCpuReservation(); - } else if (toolbox_strcmp(argv[optind], "cpulimit") == 0) { - return Stat_GetCpuLimit(); - } else if (toolbox_strcmp(argv[optind], "speed") == 0) { - return Stat_ProcessorSpeed(); - } else { - fprintf(stderr, "Unknown subcommand\n"); - } + if (toolbox_strcmp(argv[optind], "memory") == 0) { + return Stat_MemorySize(); + } else if (toolbox_strcmp(argv[optind], "hosttime") == 0) { + return Stat_HostTime(); + } else if (toolbox_strcmp(argv[optind], "sessionid") == 0) { + return Stat_GetSessionID(); + } else if (toolbox_strcmp(argv[optind], "balloon") == 0) { + return Stat_GetMemoryBallooned(); + } else if (toolbox_strcmp(argv[optind], "swap") == 0) { + return Stat_GetMemorySwapped(); + } else if (toolbox_strcmp(argv[optind], "memlimit") == 0) { + return Stat_GetMemoryLimit(); + } else if (toolbox_strcmp(argv[optind], "memres") == 0) { + return Stat_GetMemoryReservation(); + } else if (toolbox_strcmp(argv[optind], "cpures") == 0) { + return Stat_GetCpuReservation(); + } else if (toolbox_strcmp(argv[optind], "cpulimit") == 0) { + return Stat_GetCpuLimit(); + } else if (toolbox_strcmp(argv[optind], "speed") == 0) { + return Stat_ProcessorSpeed(); + } else { + ToolboxUnknownEntityError(argv[0], "subcommand", argv[optind]); + return EX_USAGE; } - StatHelp(argv[0]); - return EX_USAGE; } @@ -519,37 +535,43 @@ static int ScriptCommand(char **argv, // IN: command line arguments. int argc) // IN: the length of the command line arguments. { - if (CheckArgumentLength(argv, argc)) { - char* apm = argv[optind++]; + const char *apm; - if (optind >= argc) { - fprintf(stderr, "Missing subcommand\n"); - return EX_USAGE; - } + if (++optind >= argc) { + ToolboxMissingEntityError(argv[0], "script type"); + return EX_USAGE; + } - if (toolbox_strcmp(argv[optind], "default") == 0) { - return Script_GetDefault(apm); - } else if (toolbox_strcmp(argv[optind], "current") == 0) { - return Script_GetCurrent(apm); - } else if (toolbox_strcmp(argv[optind], "set") == 0) { - optind++; - if (optind < argc) { - return Script_Set(apm, argv[optind], quiet_flag); - } else { - fprintf(stderr, "Missing script path\n"); - ScriptHelp(argv[0]); - return EX_USAGE; - } - } else if (toolbox_strcmp(argv[optind], "enable") == 0) { - return Script_Enable(apm, quiet_flag); - } else if (toolbox_strcmp(argv[optind], "disable") == 0) { - return Script_Disable(apm, quiet_flag); - } else { - fprintf(stderr, "Unknown subcommand"); + apm = argv[optind++]; + + if (!Script_CheckName(apm)) { + ToolboxUnknownEntityError(argv[0], "script type", apm); + return EX_USAGE; + } + + if (optind >= argc) { + ToolboxMissingEntityError(argv[0], "subcommand"); + return EX_USAGE; + } + + if (toolbox_strcmp(argv[optind], "default") == 0) { + return Script_GetDefault(apm); + } else if (toolbox_strcmp(argv[optind], "current") == 0) { + return Script_GetCurrent(apm); + } else if (toolbox_strcmp(argv[optind], "set") == 0) { + if (++optind >= argc) { + ToolboxMissingEntityError(argv[0], "script path"); + return EX_USAGE; } + return Script_Set(apm, argv[optind], quiet_flag); + } else if (toolbox_strcmp(argv[optind], "enable") == 0) { + return Script_Enable(apm, quiet_flag); + } else if (toolbox_strcmp(argv[optind], "disable") == 0) { + return Script_Disable(apm, quiet_flag); + } else { + ToolboxUnknownEntityError(argv[0], "subcommand", argv[optind]); + return EX_USAGE; } - ScriptHelp(argv[0]); - return EX_USAGE; } @@ -574,19 +596,16 @@ static int TimeSyncCommand(char **argv, // IN: command line arguments int argc) // IN: The length of the command line arguments { - if (CheckArgumentLength(argv, argc)) { - if (toolbox_strcmp(argv[optind], "enable") == 0) { - return TimeSync_Enable(quiet_flag); - } else if (toolbox_strcmp(argv[optind], "disable") == 0) { - return TimeSync_Disable(quiet_flag); - } else if (toolbox_strcmp(argv[optind], "status") == 0) { - return TimeSync_Status(); - } else { - fprintf(stderr, "Unknown subcommand"); - } + if (toolbox_strcmp(argv[optind], "enable") == 0) { + return TimeSync_Enable(quiet_flag); + } else if (toolbox_strcmp(argv[optind], "disable") == 0) { + return TimeSync_Disable(quiet_flag); + } else if (toolbox_strcmp(argv[optind], "status") == 0) { + return TimeSync_Status(); + } else { + ToolboxUnknownEntityError(argv[0], "subcommand", argv[optind]); + return EX_USAGE; } - TimeSyncHelp(argv[0]); - return EX_USAGE; } @@ -610,20 +629,15 @@ static CmdTable * ParseCommand(char **argv, // IN: Command line arguments int argc) // IN: Length of command line arguments { - if (optind < argc) { - int i = 0; - while (commands[i].command != 0) { - if (toolbox_strcmp(commands[i].command, argv[optind]) == 0) { - return &commands[i]; - } - i++; + int i; + + for (i = 0; i < ARRAYSIZE(commands); i++) { + if (toolbox_strcmp(commands[i].command, argv[optind]) == 0) { + return &commands[i]; } - return &commands[i]; - } else { - fprintf(stderr, "Missing command\n"); - ToolboxCmdHelp(argv[0]); - exit(EX_USAGE); } + + return NULL; } @@ -649,7 +663,12 @@ int main(int argc, // IN: length of command line arguments char **argv) // IN: Command line arguments { + Bool show_help = FALSE; + Bool show_version = FALSE; + CmdTable *cmd = NULL; int c; + int retval; + /* * Check if we are in a VM */ @@ -658,11 +677,6 @@ main(int argc, // IN: length of command line arguments exit(EXIT_FAILURE); } - if (argc < 2) { - ToolboxCmdHelp(argv[0]); - exit(EX_USAGE); - } - /* * Parse the command line optional arguments */ @@ -676,48 +690,65 @@ main(int argc, // IN: length of command line arguments #endif /* Detect the end of the options. */ - if (c == -1) - break; + if (c == -1) { + break; + } switch (c) { case 'h': - ToolboxCmdHelp(argv[0]); - exit(EXIT_SUCCESS); + show_help = TRUE; + break; case 'v': - printf("%s (%s)\n", TOOLBOXCMD_VERSION_STRING, BUILD_NUMBER); - exit(EXIT_SUCCESS); + show_version = TRUE; + break; case 'q': - quiet_flag = 1; - break; + quiet_flag = TRUE; + break; case '?': - /* getopt_long already printed an error message. */ - ToolboxCmdHelp(argv[0]); - abort(); - break; + /* getopt_long already printed an error message. */ + fprintf(stderr, "Try '%s -h' for more information.\n", argv[0]); + return EXIT_FAILURE; default: - abort(); + return EXIT_FAILURE; } } - /* Process any remaining command line arguments (not options), and - * execute corresponding command - */ - if (optind < argc) { - CmdTable *cmd = ParseCommand(argv, argc); - if (cmd->command == NULL) { - ToolboxCmdHelp(argv[0]); - return EX_USAGE; + if (show_version) { + printf("%s (%s)\n", TOOLBOXCMD_VERSION_STRING, BUILD_NUMBER); + } else if (show_help) { + ToolboxCmdHelp(argv[0]); + } else { + /* Process any remaining command line arguments (not options), and + * execute corresponding command + */ + if (optind >= argc) { + ToolboxMissingEntityError(argv[0], "command"); + retval = EX_USAGE; + } else if ((cmd = ParseCommand(argv, argc)) == NULL) { + 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", + argv[0], cmd->command); + retval = EX_NOPERM; + } else if (cmd->requireArguments && ++optind >= argc) { + ToolboxMissingEntityError(argv[0], "subcommand"); + retval = EX_USAGE; + } else { + retval = cmd->func(argv, argc); } - if (cmd->requireRoot && !System_IsUserAdmin()) { - fprintf(stderr,"You must be root to perform %s operations\n", - cmd->command); - return EX_NOPERM; + + if (retval == EX_USAGE && (cmd == NULL || strcmp(cmd->command, "help"))) { + fprintf(stderr, "Try '%s help%s%s' for more information.\n", + argv[0], cmd ? " " : "", cmd ? cmd->command : ""); } - return cmd->func(argv, argc); + + return retval; } + return EXIT_SUCCESS; } diff --git a/open-vm-tools/toolbox/toolboxCmdInt.h b/open-vm-tools/toolbox/toolboxCmdInt.h index d860bad9c..901f2e5f2 100644 --- a/open-vm-tools/toolbox/toolboxCmdInt.h +++ b/open-vm-tools/toolbox/toolboxCmdInt.h @@ -94,12 +94,12 @@ int TimeSync_Status(void); * Script Operations */ -int Script_GetDefault(char*); -int Script_GetCurrent(char*); -int Script_Enable(char*, int); -int Script_Disable(char*, int); -int Script_Set(char*, char*, int); - +int Script_GetDefault(const char *); +int Script_GetCurrent(const char *); +int Script_Enable(const char *, int); +int Script_Disable(const char *, int); +int Script_Set(const char *, const char *, int); +Bool Script_CheckName(const char *); /* * Disk Shrink Operations diff --git a/open-vm-tools/toolbox/toolboxcmd-scripts.c b/open-vm-tools/toolbox/toolboxcmd-scripts.c index 80030db37..ccf8bf015 100644 --- a/open-vm-tools/toolbox/toolboxcmd-scripts.c +++ b/open-vm-tools/toolbox/toolboxcmd-scripts.c @@ -43,9 +43,9 @@ typedef enum ScriptType { Current } ScriptType; -static int ScriptToggle(char *apm, Bool enable, int quiet_flag); -static char* GetConfName(char *apm); -static int GetConfEntry(char *apm, ScriptType type); +static int ScriptToggle(const char *apm, Bool enable, int quiet_flag); +static const char* GetConfName(const char *apm); +static int GetConfEntry(const char *apm, ScriptType type); /* @@ -64,8 +64,8 @@ static int GetConfEntry(char *apm, ScriptType type); *----------------------------------------------------------------------------- */ -static char * -GetConfName(char *apm) // IN: apm name. +static const char * +GetConfName(const char *apm) // IN: apm name. { if (toolbox_strcmp(apm, SCRIPT_SUSPEND) == 0) { return CONFNAME_SUSPENDSCRIPT; @@ -135,12 +135,12 @@ LoadConfFile(void) */ static int -GetConfEntry(char *apm, // IN: apm name +GetConfEntry(const char *apm, // IN: apm name ScriptType type) // IN: Script type (default or current) { gchar *entry = NULL; GKeyFile *confDict = NULL; - char *confName; + const char *confName; int ret; confName = GetConfName(apm); @@ -193,7 +193,7 @@ GetConfEntry(char *apm, // IN: apm name */ int -Script_GetDefault(char *apm) // IN: APM name +Script_GetDefault(const char *apm) // IN: APM name { return GetConfEntry(apm, Default); } @@ -218,7 +218,7 @@ Script_GetDefault(char *apm) // IN: APM name */ int -Script_GetCurrent(char *apm) // IN: apm function name +Script_GetCurrent(const char *apm) // IN: apm function name { return GetConfEntry(apm, Current); } @@ -244,12 +244,12 @@ Script_GetCurrent(char *apm) // IN: apm function name */ static int -ScriptToggle(char *apm, // IN: APM name - Bool enable, // IN: status - int quiet_flag) // IN: Verbosity flag +ScriptToggle(const char *apm, // IN: APM name + Bool enable, // IN: status + int quiet_flag) // IN: Verbosity flag { const char *path; - char *confName; + const char *confName; gchar *confPath; int ret = EXIT_SUCCESS; GKeyFile *confDict; @@ -301,8 +301,8 @@ ScriptToggle(char *apm, // IN: APM name */ int -Script_Enable(char *apm, // IN: APM name - int quiet_flag) // IN: Verbosity flag +Script_Enable(const char *apm, // IN: APM name + int quiet_flag) // IN: Verbosity flag { return ScriptToggle(apm, TRUE, quiet_flag); } @@ -325,8 +325,8 @@ Script_Enable(char *apm, // IN: APM name */ int -Script_Disable(char *apm, // IN: APM name - int quiet_flag) // IN: Verbosity Flag +Script_Disable(const char *apm, // IN: APM name + int quiet_flag) // IN: Verbosity Flag { return ScriptToggle(apm, FALSE, quiet_flag); } @@ -352,11 +352,11 @@ Script_Disable(char *apm, // IN: APM name */ int -Script_Set(char *apm, // IN: APM name - char *path, // IN: path to script - int quiet_flag) // IN: Verbosity flag +Script_Set(const char *apm, // IN: APM name + const char *path, // IN: path to script + int quiet_flag) // IN: Verbosity flag { - char *confName; + const char *confName; int ret = EXIT_SUCCESS; gchar *confPath = NULL; GKeyFile *confDict = NULL; @@ -389,3 +389,25 @@ Script_Set(char *apm, // IN: APM name return ret; } + +/* + *----------------------------------------------------------------------------- + * + * Script_CheckName -- + * + * Check if it is known script + * + * Results: + * TRUE if name is known, FALSE otherwise. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +Bool +Script_CheckName(const char *apm) // IN: script name +{ + return GetConfName(apm) != NULL; +} diff --git a/open-vm-tools/vmware-user/copyPaste.c b/open-vm-tools/vmware-user/copyPaste.c index e9fa559cb..201b6e4b3 100644 --- a/open-vm-tools/vmware-user/copyPaste.c +++ b/open-vm-tools/vmware-user/copyPaste.c @@ -1821,6 +1821,7 @@ CopyPaste_GetVmxCopyPasteVersion(void) char *reply = NULL; size_t replyLen; + Debug("%s: enter\n", __FUNCTION__); if (!RpcOut_sendOne(&reply, &replyLen, "vmx.capability.copypaste_version")) { Debug("CopyPaste_GetVmxCopyPasteVersion: could not get VMX copyPaste " "version capability: %s\n", reply ? reply : "NULL"); @@ -1857,6 +1858,7 @@ CopyPaste_GetVmxCopyPasteVersion(void) Bool CopyPaste_RegisterCapability(void) { + Debug("%s: enter\n", __FUNCTION__); /* Tell the VMX about the copyPaste version we support. */ if (!RpcOut_sendOne(NULL, NULL, "tools.capability.copypaste_version 2")) { Debug("CopyPaste_RegisterCapability: could not set guest copypaste " @@ -1888,6 +1890,7 @@ CopyPaste_RegisterCapability(void) Bool CopyPaste_Register(GtkWidget* mainWnd) { + Debug("%s: enter\n", __FUNCTION__); /* Text copy/paste initialization for all versions. */ #ifndef GDK_SELECTION_CLIPBOARD GDK_SELECTION_CLIPBOARD = gdk_atom_intern("CLIPBOARD", FALSE); @@ -1963,6 +1966,7 @@ CopyPaste_Register(GtkWidget* mainWnd) void CopyPaste_Unregister(GtkWidget* mainWnd) { + Debug("%s: enter\n", __FUNCTION__); gtk_signal_disconnect_by_func(GTK_OBJECT(mainWnd), GTK_SIGNAL_FUNC(CopyPasteSelectionReceivedCB), mainWnd); @@ -1972,6 +1976,11 @@ CopyPaste_Unregister(GtkWidget* mainWnd) gtk_signal_disconnect_by_func(GTK_OBJECT(mainWnd), GTK_SIGNAL_FUNC(CopyPasteSelectionClearCB), mainWnd); + RpcIn_UnregisterCallback(gRpcIn, "copypaste.hg.data.set"); + RpcIn_UnregisterCallback(gRpcIn, "copypaste.hg.data.finish"); + RpcIn_UnregisterCallback(gRpcIn, "copypaste.gh.data.get"); + RpcIn_UnregisterCallback(gRpcIn, "copypaste.gh.get.next.file"); + RpcIn_UnregisterCallback(gRpcIn, "copypaste.gh.finish"); } @@ -1994,6 +2003,7 @@ CopyPaste_Unregister(GtkWidget* mainWnd) void CopyPaste_OnReset(void) { + Debug("%s: enter\n", __FUNCTION__); if (gHGFCPFileTransferStatus == FCP_FILE_TRANSFERRING) { File_DeleteDirectoryTree(gFileRoot); if (DnD_BlockIsReady(&gBlockCtrl) && @@ -2073,6 +2083,7 @@ CopyPaste_IsRpcCPSupported(void) void CopyPasteStateInit(void) { + Debug("%s: enter\n", __FUNCTION__); gHostClipboardBuf[0] = '\0'; gGuestSelPrimaryBuf[0] = '\0'; gGuestSelClipboardBuf[0] = '\0'; @@ -2087,6 +2098,6 @@ CopyPasteStateInit(void) * or greater. */ gFileRootSize = DnD_GetNewFileRoot(gFileRoot, sizeof gFileRoot); - Debug("CopyPaste_Register create file root [%s]\n", gFileRoot); + Debug("%s: create file root [%s]\n", __FUNCTION__, gFileRoot); } } diff --git a/open-vm-tools/vmware-user/copyPasteDnDWrapper.cpp b/open-vm-tools/vmware-user/copyPasteDnDWrapper.cpp index 24ac9194f..c5bfe3321 100644 --- a/open-vm-tools/vmware-user/copyPasteDnDWrapper.cpp +++ b/open-vm-tools/vmware-user/copyPasteDnDWrapper.cpp @@ -181,17 +181,21 @@ CopyPasteDnDWrapper::RegisterCP() Debug("%s: Setting block control to %p (fd %d)\n", __func__, m_blockCtrl, m_blockCtrl->fd); m_copyPasteUI->SetBlockControl(m_blockCtrl); - m_copyPasteUI->Init(); - SetCPIsRegistered(TRUE); - int version = GetCPVersion(); - Debug("%s: version is %d\n", __FUNCTION__, version); - if (version >= 3) { - m_copyPasteUI->VmxCopyPasteVersionChanged(gRpcIn, version); - m_copyPasteUI->SetCopyPasteAllowed(TRUE); - m_isLegacy = false; + if (m_copyPasteUI->Init()) { + SetCPIsRegistered(TRUE); + int version = GetCPVersion(); + Debug("%s: version is %d\n", __FUNCTION__, version); + if (version >= 3) { + m_copyPasteUI->VmxCopyPasteVersionChanged(gRpcIn, version); + m_copyPasteUI->SetCopyPasteAllowed(TRUE); + m_isLegacy = false; + } else { + Debug("%s: version < 3, unregistering.\n", __FUNCTION__); + UnregisterCP(); + } } else { - Debug("%s: version < 3, unregistering.\n", __FUNCTION__); - UnregisterCP(); + delete m_copyPasteUI; + m_copyPasteUI = NULL; } } } @@ -240,25 +244,28 @@ CopyPasteDnDWrapper::RegisterDnD() __func__, m_blockCtrl, m_blockCtrl->fd); m_dndUI->SetBlockControl(m_blockCtrl); - m_dndUI->Init(); - - UnityDnD state; - state.detWnd = m_dndUI->GetDetWndAsWidget(true); - state.setMode = CopyPasteDnDWrapper_SetUnityMode; - Unity_SetActiveDnDDetWnd(&state); - - SetDnDIsRegistered(TRUE); - int version = GetDnDVersion(); - Debug("%s: dnd version is %d\n", __FUNCTION__, version); - if (version >= 3) { - Debug("%s: calling VmxDnDVersionChanged (version %d) and SetDnDAllowed\n", - __FUNCTION__, version); - m_dndUI->VmxDnDVersionChanged(gRpcIn, version); - m_dndUI->SetDnDAllowed(TRUE); - m_isLegacy = false; + if (m_dndUI->Init()) { + UnityDnD state; + state.detWnd = m_dndUI->GetDetWndAsWidget(); + state.setMode = CopyPasteDnDWrapper_SetUnityMode; + Unity_SetActiveDnDDetWnd(&state); + + SetDnDIsRegistered(TRUE); + int version = GetDnDVersion(); + Debug("%s: dnd version is %d\n", __FUNCTION__, version); + if (version >= 3) { + Debug("%s: calling VmxDnDVersionChanged (version %d) and SetDnDAllowed\n", + __FUNCTION__, version); + m_dndUI->VmxDnDVersionChanged(gRpcIn, version); + m_dndUI->SetDnDAllowed(TRUE); + m_isLegacy = false; + } else { + Debug("%s: version < 3, unregistering.\n", __FUNCTION__); + UnregisterDnD(); + } } else { - Debug("%s: version < 3, unregistering.\n", __FUNCTION__); - UnregisterDnD(); + delete m_dndUI; + m_dndUI = NULL; } } } @@ -450,10 +457,22 @@ CopyPasteDnDWrapper::OnReset() if (IsCPRegistered()) { UnregisterCP(); } - RegisterCP(); - RegisterDnD(); + if (!IsCPRegistered()) { + RegisterCP(); + } + if (!IsDnDRegistered()) { + RegisterDnD(); + } if (!IsDnDRegistered() || !IsCPRegistered()) { Debug("%s: unable to reset fully!\n", __FUNCTION__); } + if (m_isLegacy) { + if (IsCPRegistered()) { + CopyPaste_OnReset(); + } + if (IsDnDRegistered()) { + DnD_OnReset(m_hgWnd, m_ghWnd); + } + } } diff --git a/open-vm-tools/vmware-user/copyPasteUI.cpp b/open-vm-tools/vmware-user/copyPasteUI.cpp index cd6223496..16d6ec4d9 100644 --- a/open-vm-tools/vmware-user/copyPasteUI.cpp +++ b/open-vm-tools/vmware-user/copyPasteUI.cpp @@ -66,8 +66,6 @@ CopyPasteUI::CopyPasteUI() : mClipboardEmpty(true), mHGStagingDir(""), mIsClipboardOwner(false), - mClipTimePrev(0), - mPrimTimePrev(0), mHGGetFilesInitiated(false), mFileTransferDone(false), mBlockAdded(false), @@ -94,14 +92,13 @@ CopyPasteUI::CopyPasteUI() *----------------------------------------------------------------------------- */ -void +bool CopyPasteUI::Init() { if (mInited) { - return; + return true; } - mInited = true; CPClipboard_Init(&mClipboard); Gtk::TargetEntry gnome(FCP_TARGET_NAME_GNOME_COPIED_FILES); @@ -116,7 +113,7 @@ CopyPasteUI::Init() if (!RpcOut_sendOne(NULL, NULL, "tools.capability.copypaste_version 3")) { Debug("%s: could not set guest copypaste version capability\n", __FUNCTION__); - return; + return false; } Debug("%s: set copypaste version 3\n", __FUNCTION__); @@ -126,6 +123,8 @@ CopyPasteUI::Init() sigc::mem_fun(this, &CopyPasteUI::GetLocalClipboard)); mCP.localGetFilesDoneChanged.connect( sigc::mem_fun(this, &CopyPasteUI::GetLocalFilesDone)); + mInited = true; + return true; } @@ -580,64 +579,31 @@ CopyPasteUI::LocalPrimTimestampCB(const Gtk::SelectionData& sd) // IN mGHSelection = GDK_SELECTION_PRIMARY; if (mClipTime > mPrimTime) { mGHSelection = GDK_SELECTION_CLIPBOARD; - Debug("%s: mClipTimePrev: %"FMT64"u.", __FUNCTION__, mClipTimePrev); - } else { - Debug("%s: mPrimTimePrev: %"FMT64"u.", __FUNCTION__, mPrimTimePrev); } - mPrimTimePrev = mPrimTime; - mClipTimePrev = mClipTime; - - /* Ask for available targets from active selection. */ - Glib::RefPtr refClipboard = - Gtk::Clipboard::get(mGHSelection); + Glib::RefPtr refClipboard; +again: + refClipboard = Gtk::Clipboard::get(mGHSelection); - refClipboard->request_targets( - sigc::mem_fun(this, &CopyPasteUI::LocalReceivedTargetsCB)); -} - - -/* - *---------------------------------------------------------------------- - * - * CopyPasteUI::LocalReceivedTargetsCB -- - * - * Received targets. Check if any desired target available. If so, - * ask for all supported contents. - * - * Results: - * None. - * - * Side effects: - * Clipboard owner may send us file list. - * - *---------------------------------------------------------------------- - */ - -void -CopyPasteUI::LocalReceivedTargetsCB(const Glib::StringArrayHandle& targetsArray) // IN -{ - std::list targets = targetsArray; - Glib::RefPtr refClipboard = Gtk::Clipboard::get(mGHSelection); + Debug("%s: trying %s selection, trying again\n", + __FUNCTION__, + mGHSelection == GDK_SELECTION_PRIMARY ? "Primary" : "Clip"); - Debug("%s: enter", __FUNCTION__); CPClipboard_Clear(&mClipboard); - if (std::find(targets.begin(), - targets.end(), - FCP_TARGET_NAME_GNOME_COPIED_FILES) != targets.end()) { - Debug("%s: gnome copy file list available\n", __FUNCTION__); - refClipboard->request_contents(FCP_TARGET_NAME_GNOME_COPIED_FILES, - sigc::mem_fun(this, - &CopyPasteUI::LocalReceivedFileListCB)); - return; + /* First check for URIs. This must always be done first */ + bool haveURIs = false; + std::string format; + if (refClipboard->wait_is_target_available(FCP_TARGET_NAME_GNOME_COPIED_FILES)) { + format = FCP_TARGET_NAME_GNOME_COPIED_FILES; + haveURIs = true; + } else if (refClipboard->wait_is_target_available(FCP_TARGET_NAME_URI_LIST)) { + format = FCP_TARGET_NAME_URI_LIST; + haveURIs = true; } - if (std::find(targets.begin(), - targets.end(), - FCP_TARGET_NAME_URI_LIST) != targets.end()) { - Debug("%s: KDE copy file list available\n", __FUNCTION__); - refClipboard->request_contents(FCP_TARGET_NAME_URI_LIST, + if (haveURIs) { + refClipboard->request_contents(format, sigc::mem_fun(this, &CopyPasteUI::LocalReceivedFileListCB)); return; @@ -645,13 +611,13 @@ CopyPasteUI::LocalReceivedTargetsCB(const Glib::StringArrayHandle& targetsArray) /* Try to get image data from clipboard. */ Glib::RefPtr img = refClipboard->wait_for_image(); + gsize bufSize; if (img) { gchar *buf = NULL; - gsize bufSize; img->save_to_buffer(buf, bufSize, Glib::ustring("png")); if (bufSize > 0 && - bufSize <= (int)DNDMSG_MAX_ARGSZ && + bufSize <= (int)CPCLIPITEM_MAX_SIZE_V3 && CPClipboard_SetItem(&mClipboard, CPFORMAT_IMG_PNG, buf, bufSize)) { mCP.SetRemoteClipboard(&mClipboard); @@ -663,33 +629,71 @@ CopyPasteUI::LocalReceivedTargetsCB(const Glib::StringArrayHandle& targetsArray) return; } - /* - * Try to get RTF data from local clipboard. 2 targets are supported, and - * both share same callback because data is same. - */ - if (std::find(targets.begin(), - targets.end(), - TARGET_NAME_APPLICATION_RTF) != targets.end()) { - Debug("%s: TARGET_NAME_APPLICATION_RTF available\n", __FUNCTION__); - refClipboard->request_contents(TARGET_NAME_APPLICATION_RTF, - sigc::mem_fun(this, - &CopyPasteUI::LocalReceivedRTFCB)); - return; + /* Try to get RTF data from clipboard. */ + bool haveRTF = false; + if (refClipboard->wait_is_target_available(TARGET_NAME_APPLICATION_RTF)) { + Debug("%s: RTF is available\n", __FUNCTION__); + format = TARGET_NAME_APPLICATION_RTF; + haveRTF = true; + } + if (refClipboard->wait_is_target_available(TARGET_NAME_TEXT_RICHTEXT)) { + Debug("%s: RICHTEXT is available\n", __FUNCTION__); + format = TARGET_NAME_TEXT_RICHTEXT; + haveRTF = true; } - if (std::find(targets.begin(), - targets.end(), - TARGET_NAME_TEXT_RICHTEXT) != targets.end()) { - Debug("%s: TARGET_NAME_TEXT_RICHTEXT available\n", __FUNCTION__); - refClipboard->request_contents(TARGET_NAME_TEXT_RICHTEXT, - sigc::mem_fun(this, - &CopyPasteUI::LocalReceivedRTFCB)); - return; + if (haveRTF) { + /* + * There is a function for waiting for rtf data, but that was leading + * to crashes. It's use required we instantiate a class that implements + * Gtk::TextBuffer and then query that class for a reference to it's + * TextBuffer instance. This all compiled fine but crashed in testing + * so we opt to use the more generic API here which seemed more stable. + */ + Gtk::SelectionData sdata = refClipboard->wait_for_contents(format); + bufSize = sdata.get_length(); + if (bufSize > 0 && + bufSize <= (int)CPCLIPITEM_MAX_SIZE_V3 && + CPClipboard_SetItem(&mClipboard, CPFORMAT_RTF, + (const void *)sdata.get_data(), bufSize + 1)) { + mCP.SetRemoteClipboard(&mClipboard); + 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); + } } - Debug("%s: ask for text\n", __FUNCTION__); - refClipboard->request_text(sigc::mem_fun(this, - &CopyPasteUI::LocalReceivedTextCB)); + /* Try to get Text data from clipboard. */ + if (refClipboard->wait_is_text_available()) { + Debug("%s: ask for text\n", __FUNCTION__); + Glib::ustring str = refClipboard->wait_for_text(); + bufSize = str.size(); + if (bufSize > 0 && + bufSize <= (int)CPCLIPITEM_MAX_SIZE_V3 && + CPClipboard_SetItem(&mClipboard, CPFORMAT_TEXT, + (const void *)str.data(), bufSize + 1)) { + mCP.SetRemoteClipboard(&mClipboard); + 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__); + } + } } @@ -724,113 +728,6 @@ CopyPasteUI::LocalReceivedFileListCB(const Gtk::SelectionData& sd) // IN } -/* - *---------------------------------------------------------------------- - * - * CopyPasteUI::LocalReceivedRTFCB -- - * - * Got clipboard (or primary selection) RTF text, add to local - * clipboard cache and send clipboard to host. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -CopyPasteUI::LocalReceivedRTFCB(const Gtk::SelectionData& sd) // IN -{ - utf::string source = sd.get_data_as_string().c_str(); - Glib::RefPtr refClipboard = Gtk::Clipboard::get(mGHSelection); - - /* Add NUL terminator. */ - if (source.bytes() > 0 && - source.bytes() < DNDMSG_MAX_ARGSZ && - CPClipboard_SetItem(&mClipboard, CPFORMAT_RTF, source.c_str(), - source.bytes() + 1)) { - Debug("%s: Got RTF, size %"FMTSZ"u\n", __FUNCTION__, source.bytes()); - } else { - Debug("%s: Failed to get RTF\n", __FUNCTION__); - } - - /* - * Still should try to get plain text. LocalReceivedTextCB will send data - * to guest. - */ - Debug("%s: ask for text\n", __FUNCTION__); - refClipboard->request_text(sigc::mem_fun(this, - &CopyPasteUI::LocalReceivedTextCB)); -} - - -/* - *---------------------------------------------------------------------- - * - * CopyPasteUI::LocalReceivedTextCB -- - * - * Got clipboard (or primary selection) text, add to local clipboard - * cache and send clipboard to host. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -CopyPasteUI::LocalReceivedTextCB(const Glib::ustring& text) // IN -{ - Debug("%s: enter", __FUNCTION__); - utf::string source = text; - - /* - * With 'cut' operation OpenOffice will put data into clipboard but - * set 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. - */ - if (0 == source.bytes() && - mClipTime == mPrimTime && - mClipTime != 0) { - mClipTime = 0; - mPrimTime = 0; - mGHSelection = GDK_SELECTION_CLIPBOARD; - - /* Ask for available targets from active selection. */ - Glib::RefPtr refClipboard = - Gtk::Clipboard::get(mGHSelection); - - refClipboard->request_targets( - sigc::mem_fun(this, &CopyPasteUI::LocalReceivedTargetsCB)); - return; - } - - Debug("%s: Got text: %s", __FUNCTION__, source.c_str()); - - /* Add NUL terminator. */ - if (source.bytes() > 0 && - source.bytes() < CPCLIPITEM_MAX_SIZE_V3 && - CPClipboard_SetItem(&mClipboard, CPFORMAT_TEXT, source.c_str(), - source.bytes() + 1)) { - Debug("%s: got text, size %"FMTSZ"u\n", __FUNCTION__, source.bytes()); - } else { - Debug("%s: failed to get text\n", __FUNCTION__); - } - - if (!CPClipboard_IsEmpty(&mClipboard)) { - mCP.SetRemoteClipboard(&mClipboard); - } -} - - /* *----------------------------------------------------------------------------- * diff --git a/open-vm-tools/vmware-user/copyPasteUI.h b/open-vm-tools/vmware-user/copyPasteUI.h index c77cd0a66..66d856a5b 100644 --- a/open-vm-tools/vmware-user/copyPasteUI.h +++ b/open-vm-tools/vmware-user/copyPasteUI.h @@ -54,7 +54,7 @@ class CopyPasteUI : public sigc::trackable public: CopyPasteUI(); virtual ~CopyPasteUI(); - void Init(); + bool Init(); void VmxCopyPasteVersionChanged(struct RpcIn *rpcIn, uint32 version); void SetCopyPasteAllowed(bool isCopyPasteAllowed) @@ -79,10 +79,7 @@ private: bool GetLocalClipboard(CPClipboard *clip); void LocalClipboardTimestampCB(const Gtk::SelectionData& sd); void LocalPrimTimestampCB(const Gtk::SelectionData& sd); - void LocalReceivedTargetsCB(const Glib::StringArrayHandle& targets_array); void LocalReceivedFileListCB(const Gtk::SelectionData& selection_data); - void LocalReceivedRTFCB(const Gtk::SelectionData& selection_data); - void LocalReceivedTextCB(const Glib::ustring& text); void GetLocalFilesDone(bool success); /* Conversion methods. */ @@ -100,8 +97,6 @@ private: bool mIsClipboardOwner; uint64 mClipTime; uint64 mPrimTime; - uint64 mClipTimePrev; - uint64 mPrimTimePrev; GdkAtom mGHSelection; CPClipboard mClipboard; diff --git a/open-vm-tools/vmware-user/dnd.c b/open-vm-tools/vmware-user/dnd.c index 68bf9f6ba..9a5f3aa95 100644 --- a/open-vm-tools/vmware-user/dnd.c +++ b/open-vm-tools/vmware-user/dnd.c @@ -2591,6 +2591,17 @@ DnD_Unregister(GtkWidget *hgWnd, // IN: The widget for hg dnd gtk_signal_disconnect_by_func(GTK_OBJECT(ghWnd), GTK_SIGNAL_FUNC(DnDGtkDragDropCB), ghWnd); + + RpcIn_UnregisterCallback(gRpcIn, "dnd.data.set"); + RpcIn_UnregisterCallback(gRpcIn, "dnd.enter"); + RpcIn_UnregisterCallback(gRpcIn, "dnd.move"); + RpcIn_UnregisterCallback(gRpcIn, "dnd.drop"); + RpcIn_UnregisterCallback(gRpcIn, "dnd.data.finish"); + + /* Guest->Host RPC callbacks */ + RpcIn_UnregisterCallback(gRpcIn, "dnd.ungrab"); + RpcIn_UnregisterCallback(gRpcIn, "dnd.data.get.file"); + RpcIn_UnregisterCallback(gRpcIn, "dnd.finish"); } diff --git a/open-vm-tools/vmware-user/dndUI.cpp b/open-vm-tools/vmware-user/dndUI.cpp index 82691d4c0..f94224b2c 100644 --- a/open-vm-tools/vmware-user/dndUI.cpp +++ b/open-vm-tools/vmware-user/dndUI.cpp @@ -36,6 +36,7 @@ extern "C" { #include "cpName.h" #include "debug.h" #include "cpNameUtil.h" +#include "hostinfo.h" #include "rpcout.h" #include "eventManager.h" #include "unity.h" @@ -55,20 +56,19 @@ DnDUI::DnDUI(DblLnkLst_Links *eventQueue) : m_eventQueue(eventQueue), m_DnD(NULL), m_detWnd(NULL), - m_detWndFull(NULL), m_blockCtrl(NULL), m_HGGetDataInProgress(false), m_blockAdded(false), m_GHDnDInProgress(false), - m_GHDnDHostStatus(false), - m_GHDnDAction((Gdk::DragAction)0), m_GHDnDDataReceived(false), - m_GHDnDDropOccurred(false), - m_VMIsSource(false), m_unityMode(false), m_inHGDrag(false), - m_effect(DROP_UNKNOWN), - m_isFileDnD(false) + m_effect(DROP_NONE), + m_isFileDnD(false), + m_mousePosX(0), + m_mousePosY(0), + m_dc(NULL), + m_destDropTime(0) { Debug("%s: enter\n", __FUNCTION__); } @@ -82,17 +82,12 @@ DnDUI::DnDUI(DblLnkLst_Links *eventQueue) DnDUI::~DnDUI() { Debug("%s: enter\n", __FUNCTION__); - Reset(); if (m_DnD) { delete m_DnD; } if (m_detWnd) { delete m_detWnd; } - if (m_detWndFull) { - delete m_detWndFull; - } - m_feedbackChanged.disconnect(); CPClipboard_Destroy(&m_clipboard); } @@ -102,12 +97,13 @@ DnDUI::~DnDUI() * Initialize DnDUI object. */ -void +bool DnDUI::Init() { Debug("%s: enter\n", __FUNCTION__); char *reply = NULL; size_t replyLen; + bool ret = true; ASSERT(m_eventQueue); CPClipboard_Init(&m_clipboard); @@ -121,11 +117,6 @@ DnDUI::Init() Debug("%s: unable to allocate DragDetWnd object\n", __FUNCTION__); goto fail; } - m_detWndFull = new DragDetWnd(); - if (!m_detWndFull) { - Debug("%s: unable to allocate DragDetWnd object\n", __FUNCTION__); - goto fail; - } #if defined(DETWNDDEBUG) @@ -137,7 +128,6 @@ DnDUI::Init() */ m_detWnd->SetAttributes(); - m_detWndFull->SetAttributes(); #endif SetTargetsAndCallbacks(); @@ -159,56 +149,61 @@ DnDUI::Init() Debug("%s: VMX version ok: %d\n", __FUNCTION__, atoi(reply)); - m_DnD->reset.connect(sigc::mem_fun(this, &DnDUI::ResetUIStateCB)); + /* Set common layer callbacks. */ m_DnD->dragStartChanged.connect( - sigc::mem_fun(this, &DnDUI::RemoteDragStartCB)); + sigc::mem_fun(this, &DnDUI::CommonDragStartCB)); m_DnD->fileCopyDoneChanged.connect( - sigc::mem_fun(this, &DnDUI::GetLocalFilesDoneCB)); + sigc::mem_fun(this, &DnDUI::CommonSourceFileCopyDoneCB)); m_DnD->updateDetWndChanged.connect( - sigc::mem_fun(this, &DnDUI::UpdateDetWndCB)); + sigc::mem_fun(this, &DnDUI::CommonUpdateDetWndCB)); m_DnD->updateUnityDetWndChanged.connect( - sigc::mem_fun(this, &DnDUI::UpdateUnityDetWndCB)); + sigc::mem_fun(this, &DnDUI::CommonUpdateUnityDetWndCB)); + m_DnD->moveDetWndToMousePos.connect( + sigc::mem_fun(this, &DnDUI::CommonMoveDetWndToMousePos)); m_DnD->sourceCancelChanged.connect( - sigc::mem_fun(this, &DnDUI::SourceCancelCB)); + sigc::mem_fun(this, &DnDUI::CommonSourceCancelCB)); + m_DnD->targetPrivateDropChanged.connect( + sigc::mem_fun(this, &DnDUI::CommonDestPrivateDropCB)); m_DnD->ghCancel.connect( - sigc::mem_fun(this, &DnDUI::GHCancelCB)); + sigc::mem_fun(this, &DnDUI::CommonDestCancelCB)); m_DnD->sourceDropChanged.connect( - sigc::mem_fun(this, &DnDUI::SourceDropCB)); + sigc::mem_fun(this, &DnDUI::CommonSourceDropCB)); + m_DnD->updateMouseChanged.connect( + sigc::mem_fun(this, &DnDUI::CommonUpdateMouseCB)); + /* Set Gtk+ callbacks for source. */ + m_detWnd->signal_drag_begin().connect( + sigc::mem_fun(this, &DnDUI::GtkSourceDragBeginCB)); m_detWnd->signal_drag_data_get().connect( - sigc::mem_fun(this, &DnDUI::LocalDragDataGetCB)); + sigc::mem_fun(this, &DnDUI::GtkSourceDragDataGetCB)); m_detWnd->signal_drag_end().connect( - sigc::mem_fun(this, &DnDUI::LocalDragEndCB)); - m_detWnd->signal_drag_drop().connect( - sigc::mem_fun(this, &DnDUI::LocalDragDropCB)); - m_detWnd->signal_drag_begin().connect( - sigc::mem_fun(this, &DnDUI::LocalDragBeginCB)); + sigc::mem_fun(this, &DnDUI::GtkSourceDragEndCB)); - UpdateDetWndCB(false, 0, 0); - UpdateUnityDetWndCB(false, 0); + CommonUpdateDetWndCB(false, 0, 0); + CommonUpdateUnityDetWndCB(false, 0, false); goto out; fail: + ret = false; if (m_DnD) { delete m_DnD; + m_DnD = NULL; } if (m_detWnd) { delete m_detWnd; - } - if (m_detWndFull) { - delete m_detWndFull; + m_detWnd = NULL; } out: if (reply) { free(reply); } - return; + return ret; } /** * * Setup targets we support, claim ourselves as a drag destination, and - * register callbacks for Gdk drag and drop callbacks the platform will + * register callbacks for Gtk+ drag and drop callbacks the platform will * send to us. */ @@ -248,12 +243,13 @@ DnDUI::SetTargetsAndCallbacks() */ m_detWnd->drag_dest_set(targets, Gtk::DEST_DEFAULT_MOTION, Gdk::ACTION_COPY | Gdk::ACTION_MOVE); - m_detWnd->signal_drag_leave().connect(sigc::mem_fun(this, &DnDUI::LocalDragLeaveCB)); - m_detWnd->signal_drag_motion().connect(sigc::mem_fun(this, &DnDUI::LocalDragMotionCB)); - m_detWnd->signal_drag_drop().connect(sigc::mem_fun(this, &DnDUI::LocalDragDropCB)); - m_detWnd->signal_drag_data_received().connect(sigc::mem_fun(this, &DnDUI::LocalDragDataReceivedCB)); + m_detWnd->signal_drag_leave().connect(sigc::mem_fun(this, &DnDUI::GtkDestDragLeaveCB)); + m_detWnd->signal_drag_motion().connect(sigc::mem_fun(this, &DnDUI::GtkDestDragMotionCB)); + m_detWnd->signal_drag_drop().connect(sigc::mem_fun(this, &DnDUI::GtkDestDragDropCB)); + m_detWnd->signal_drag_data_received().connect(sigc::mem_fun(this, &DnDUI::GtkDestDragDataReceivedCB)); } +/* Begin of callbacks issued by common layer code */ /** * @@ -261,33 +257,20 @@ DnDUI::SetTargetsAndCallbacks() */ void -DnDUI::ResetUIStateCB(void) +DnDUI::CommonResetCB(void) { - m_GHDnDHostStatus = false; - m_GHDnDAction = (Gdk::DragAction)0; + Debug("%s: entering\n", __FUNCTION__); m_GHDnDDataReceived = false; - m_GHDnDDropOccurred = false; m_HGGetDataInProgress = false; - m_VMIsSource = false; m_GHDnDInProgress = false; - m_feedbackChanged.disconnect(); - m_effect = DROP_UNKNOWN; + m_effect = DROP_NONE; + m_inHGDrag = false; + m_dc = NULL; + m_isFileDnD = false; RemoveBlock(); } -/** - * Set block control member. - * - * @param[in] block control as setup by vmware-user. - */ - -void -DnDUI::SetBlockControl(DnDBlockControl *blockCtrl) -{ - m_blockCtrl = blockCtrl; -} - /* Source functions for HG DnD. */ /** @@ -299,7 +282,7 @@ DnDUI::SetBlockControl(DnDBlockControl *blockCtrl) */ void -DnDUI::RemoteDragStartCB(const CPClipboard *clip, std::string stagingDir) +DnDUI::CommonDragStartCB(const CPClipboard *clip, std::string stagingDir) { Glib::RefPtr targets; Gdk::DragAction actions; @@ -310,6 +293,14 @@ DnDUI::RemoteDragStartCB(const CPClipboard *clip, std::string stagingDir) Debug("%s: enter\n", __FUNCTION__); + /* + * Before the DnD, we should make sure that the mouse is released + * otherwise it may be another DnD, not ours. Send a release, then + * a press here to cover this case. + */ + SendFakeXEvents(false, true, false, false, false, 0, 0); + SendFakeXEvents(true, true, true, false, true, 0, 0); + /* * Construct the target and action list, as well as a fake motion notify * event that's consistent with one that would typically start a drag. @@ -332,7 +323,7 @@ DnDUI::RemoteDragStartCB(const CPClipboard *clip, std::string stagingDir) } if (CPClipboard_ItemExists(&m_clipboard, CPFORMAT_FILECONTENTS)) { - if (LocalPrepareFileContentsDrag()) { + if (WriteFileContentsToStagingDir()) { targets->add(Glib::ustring(DRAG_TARGET_NAME_URI_LIST)); } } @@ -354,7 +345,7 @@ DnDUI::RemoteDragStartCB(const CPClipboard *clip, std::string stagingDir) /* TODO set the x/y coords to the actual drag initialization point. */ event.type = GDK_MOTION_NOTIFY; event.window = m_detWnd->get_window()->gobj(); - event.send_event = FALSE; + event.send_event = false; event.time = GDK_CURRENT_TIME; event.x = 10; event.y = 10; @@ -370,291 +361,112 @@ DnDUI::RemoteDragStartCB(const CPClipboard *clip, std::string stagingDir) m_blockAdded = false; m_isFileDnD = false; SourceDragStartDone(); + /* Initialize host hide feedback to DROP_NONE. */ + m_effect = DROP_NONE; + SourceUpdateFeedback(m_effect); } /** * - * Try to extract file contents from m_clipboard. Write all files to a - * temporary staging directory. Construct uri list. - * - * @return TRUE if success, FALSE otherwise. + * Cancel current HG DnD. */ -bool -DnDUI::LocalPrepareFileContentsDrag(void) +void +DnDUI::CommonSourceCancelCB(void) { - void *buf = NULL; - size_t sz = 0; - XDR xdrs; - CPFileContents fileContents; - CPFileContentsList *contentsList = NULL; - size_t nFiles = 0; - CPFileItem *fileItem = NULL; - Unicode tempDir = NULL; - size_t i = 0; - bool ret = FALSE; - - if (!CPClipboard_GetItem(&m_clipboard, CPFORMAT_FILECONTENTS, &buf, &sz)) { - return false; - } - - /* Extract file contents from buf. */ - xdrmem_create(&xdrs, (char *)buf, sz, XDR_DECODE); - memset(&fileContents, 0, sizeof fileContents); - - if (!xdr_CPFileContents(&xdrs, &fileContents)) { - Debug("%s: xdr_CPFileContents failed.\n", __FUNCTION__); - xdr_destroy(&xdrs); - return false; - } - xdr_destroy(&xdrs); - - contentsList = fileContents.CPFileContents_u.fileContentsV1; - if (!contentsList) { - Debug("%s: invalid contentsList.\n", __FUNCTION__); - goto exit; - } - - nFiles = contentsList->fileItem.fileItem_len; - if (0 == nFiles) { - Debug("%s: invalid nFiles.\n", __FUNCTION__); - goto exit; - } - - fileItem = contentsList->fileItem.fileItem_val; - if (!fileItem) { - Debug("%s: invalid fileItem.\n", __FUNCTION__); - goto exit; - } + Debug("%s: entering\n", __FUNCTION__); /* - * Write files into a temporary staging directory. These files will be moved - * to final destination, or deleted on next reboot. + * Force the window to show, position the mouse over it, and release. + * Seems like moving the window to 0, 0 eliminates frequently observed + * flybacks when we cancel as user moves mouse in and out of destination + * window in a H->G DnD. */ - tempDir = DnD_CreateStagingDirectory(); - if (!tempDir) { - Debug("%s: DnD_CreateStagingDirectory failed.\n", __FUNCTION__); - goto exit; - } - - m_HGFileContentsUriList = ""; - - for (i = 0; i < nFiles; i++) { - utf::string fileName; - utf::string filePathName; - VmTimeType createTime = -1; - VmTimeType accessTime = -1; - VmTimeType writeTime = -1; - VmTimeType attrChangeTime = -1; - - if (!fileItem[i].cpName.cpName_val || - 0 == fileItem[i].cpName.cpName_len) { - Debug("%s: invalid fileItem[%"FMTSZ"u].cpName.\n", __FUNCTION__, i); - goto exit; - } - - /* - * '\0' is used as directory separator in cross-platform name. Now turn - * '\0' in data into DIRSEPC. - * - * Note that we don't convert the final '\0' into DIRSEPC so the string - * is NUL terminated. - */ - CPNameUtil_CharReplace(fileItem[i].cpName.cpName_val, - fileItem[i].cpName.cpName_len - 1, - '\0', - DIRSEPC); - fileName = fileItem[i].cpName.cpName_val; - filePathName = tempDir; - filePathName += DIRSEPS + fileName; - - if (fileItem[i].validFlags & CP_FILE_VALID_TYPE && - CP_FILE_TYPE_DIRECTORY == fileItem[i].type) { - if (!File_CreateDirectory(filePathName.c_str())) { - goto exit; - } - Debug("%s: created directory [%s].\n", - __FUNCTION__, filePathName.c_str()); - } else if (fileItem[i].validFlags & CP_FILE_VALID_TYPE && - CP_FILE_TYPE_REGULAR == fileItem[i].type) { - FileIODescriptor file; - FileIOResult fileErr; - - FileIO_Invalidate(&file); - - fileErr = FileIO_Open(&file, - filePathName.c_str(), - FILEIO_ACCESS_WRITE, - FILEIO_OPEN_CREATE_EMPTY); - if (!FileIO_IsSuccess(fileErr)) { - goto exit; - } - - fileErr = FileIO_Write(&file, - fileItem[i].content.content_val, - fileItem[i].content.content_len, - NULL); - - FileIO_Close(&file); - Debug("%s: created file [%s].\n", - __FUNCTION__, filePathName.c_str()); - } else { - /* - * Right now only Windows can provide CPFORMAT_FILECONTENTS data. - * Symlink file is not expected. Continue with next file if the - * type is not valid. - */ - continue; - } - - /* Update file time attributes. */ - createTime = fileItem->validFlags & CP_FILE_VALID_CREATE_TIME ? - fileItem->createTime: -1; - accessTime = fileItem->validFlags & CP_FILE_VALID_ACCESS_TIME ? - fileItem->accessTime: -1; - writeTime = fileItem->validFlags & CP_FILE_VALID_WRITE_TIME ? - fileItem->writeTime: -1; - attrChangeTime = fileItem->validFlags & CP_FILE_VALID_CHANGE_TIME ? - fileItem->attrChangeTime: -1; - - if (!File_SetTimes(filePathName.c_str(), - createTime, - accessTime, - writeTime, - attrChangeTime)) { - /* Not a critical error, only log it. */ - Debug("%s: File_SetTimes failed with file [%s].\n", - __FUNCTION__, filePathName.c_str()); - } - - /* Update file permission attributes. */ - if (fileItem->validFlags & CP_FILE_VALID_PERMS) { - if (Posix_Chmod(filePathName.c_str(), - fileItem->permissions) < 0) { - /* Not a critical error, only log it. */ - Debug("%s: Posix_Chmod failed with file [%s].\n", - __FUNCTION__, filePathName.c_str()); - } - } - - /* - * If there is no DIRSEPC inside the fileName, this file/directory is a - * top level one. We only put top level name into uri list. - */ - if (fileName.find(DIRSEPS, 0) == utf::string::npos) { - m_HGFileContentsUriList += "file://" + filePathName + "\r\n"; - } - } - Debug("%s: created uri list [%s].\n", - __FUNCTION__, m_HGFileContentsUriList.c_str()); - ret = true; - -exit: - xdr_free((xdrproc_t) xdr_CPFileContents, (char *)&fileContents); - if (tempDir && !ret) { - DnD_DeleteStagingFiles(tempDir, FALSE); - } - free(tempDir); - return ret; + CommonUpdateDetWndCB(true, 0, 0); + SendFakeXEvents(true, true, false, true, true, 0, 0); + CommonUpdateDetWndCB(false, 0, 0); + m_inHGDrag = false; + m_HGGetDataInProgress = false; + m_effect = DROP_NONE; + RemoveBlock(); } /** * - * Tell host that we are done with HG DnD initialization. - */ - -void -DnDUI::SourceDragStartDone(void) -{ - Debug("%s: enter\n", __FUNCTION__); - m_inHGDrag = true; - m_DnD->HGDragStartDone(); -} - - -/** + * Handle common layer private drop CB. * - * Handler for when the guest provides drag status during a host->guest - * operation. This will change as we drag over different things in the guest. - * Here, we map what is report to a Gdk drag action, and then forward this - * status value to the Gdk drag context. + * @param[in] x position to release the mouse button (ignored). + * @param[in] y position to release the mouse button (ignored). * - * @param[in] effect drop effect - * @param[in] gc Gdk drag context object, to which status is forwarded. + * @note We ignore the coordinates, because we just need to release the mouse + * in its current position. */ void -DnDUI::SourceFeedbackChangedCB(DND_DROPEFFECT effect, - const Glib::RefPtr dc) +DnDUI::CommonDestPrivateDropCB(int32 x, + int32 y) { - Debug("%s: enter\n", __FUNCTION__); - if (effect == DROP_NONE) { - m_GHDnDAction = (Gdk::DragAction)0; - } else if (effect & DROP_COPY) { - m_GHDnDAction = Gdk::ACTION_COPY; - } else if (effect & DROP_MOVE) { - m_GHDnDAction = Gdk::ACTION_MOVE; - } else if (effect & DROP_LINK) { + Debug("%s: entering\n", __FUNCTION__); + /* Unity manager in host side may already send the drop into guest. */ + if (m_GHDnDInProgress) { + /* - * We don't do link. + * Release the mouse button. */ - m_GHDnDAction = Gdk::ACTION_COPY; - } else { - m_GHDnDAction = (Gdk::DragAction)0; + SendFakeXEvents(false, true, false, false, false, 0, 0); } - m_GHDnDHostStatus = !!effect; - - dc->drag_status(m_GHDnDAction, GDK_CURRENT_TIME); + CommonResetCB(); } /** * - * Cancel current HG DnD. + * Cancel current DnD (G->H only). */ void -DnDUI::SourceCancelCB(void) +DnDUI::CommonDestCancelCB(void) { Debug("%s: entering\n", __FUNCTION__); - m_inHGDrag = false; - m_HGGetDataInProgress = false; - m_effect = DROP_UNKNOWN; - RemoveBlock(); -} - - -/** - * - * Cancel current GH DnD. - */ + /* Unity manager in host side may already send the drop into guest. */ + if (m_GHDnDInProgress) { + CommonUpdateDetWndCB(true, 0, 0); -void -DnDUI::GHCancelCB(void) -{ - ResetUIStateCB(); + /* + * Show the window, move it to the mouse position, and release the + * mouse button. + */ + SendFakeXEvents(true, true, false, true, false, 0, 0); + } + m_destDropTime = GetTimeInMillis(); + CommonResetCB(); } /** * - * Got drop from host side. Add block first then host can simulate the drop - * in the guest. + * Got drop from host side. Release the mouse button in the detection window */ void -DnDUI::SourceDropCB(void) +DnDUI::CommonSourceDropCB(void) { Debug("%s: enter\n", __FUNCTION__); - m_inHGDrag = false; + CommonUpdateDetWndCB(true, 0, 0); + + /* + * Move the mouse to the saved coordinates, and release the mouse button. + */ + SendFakeXEvents(false, true, false, false, true, m_mousePosX, m_mousePosY); + CommonUpdateDetWndCB(false, 0, 0); } /** * - * Callback when HG file transfer is done, which finishes the file + * Callback when file transfer is done, which finishes the file * copying from host to guest staging directory. * * @param[in] success if true, transfer was successful @@ -662,51 +474,30 @@ DnDUI::SourceDropCB(void) */ void -DnDUI::GetLocalFilesDoneCB(bool success, - std::vector stagingDir) +DnDUI::CommonSourceFileCopyDoneCB(bool success, + std::vector stagingDir) { Debug("%s: %s\n", __FUNCTION__, success ? "success" : "failed"); /* Copied files are already removed in common layer. */ stagingDir.clear(); - Reset(); + CommonResetCB(); m_HGGetDataInProgress = false; } -/* Target functions for GH DnD. */ - /** * - * This is triggered when user drags valid data from guest to host. Try to - * get clip data and notify host to start GH DnD. + * Shows/hides drag detection windows based on the mask. + * + * @param[in] bShow if true, show the window, else hide it. + * @param[in] x x-coordinate to which the detection window needs to be moved + * @param[in] y y-coordinate to which the detection window needs to be moved */ void -DnDUI::TargetDragEnter(void) -{ - Debug("%s: entering\n", __FUNCTION__); - - /* Check if there is valid data with current detection window. */ - if (!CPClipboard_IsEmpty(&m_clipboard)) { - Debug("%s: got valid data from detWnd.\n", __FUNCTION__); - m_DnD->DragEnter(&m_clipboard); - } -} - - -/** - * - * Shows/hides drag detection windows based on the mask. - * - * @param[in] bShow if true, show the window, else hide it. - * @param[in] x x-coordinate to which the detection window needs to be moved - * @param[in] y y-coordinate to which the detection window needs to be moved - */ - -void -DnDUI::UpdateDetWndCB(bool bShow, - int32 x, - int32 y) +DnDUI::CommonUpdateDetWndCB(bool bShow, + int32 x, + int32 y) { /* If the window is being shown, move it to the right place. */ if (bShow) { @@ -715,16 +506,20 @@ DnDUI::UpdateDetWndCB(bool bShow, m_detWnd->Show(); m_detWnd->Raise(); - m_detWnd->SetGeometry(x, y, 2 * DRAG_DET_WINDOW_WIDTH, 2 * DRAG_DET_WINDOW_WIDTH); + m_detWnd->SetGeometry(x, y, DRAG_DET_WINDOW_WIDTH * 2, DRAG_DET_WINDOW_WIDTH * 2); + Debug("%s: show at (%d, %d, %d, %d)\n", __FUNCTION__, x, y, DRAG_DET_WINDOW_WIDTH * 2, DRAG_DET_WINDOW_WIDTH * 2); /* * Wiggle the mouse here. Especially for G->H DnD, this improves * reliability of making the drag escape the guest window immensly. * Stolen from the legacy V2 DnD code. */ - DnDHGFakeMove(x, y); + SendFakeMouseMove(x, y); + m_detWnd->SetIsVisible(true); } else { + Debug("%s: hide\n", __FUNCTION__); m_detWnd->Hide(); + m_detWnd->SetIsVisible(false); } } @@ -735,38 +530,92 @@ DnDUI::UpdateDetWndCB(bool bShow, * * @param[in] bShow if true, show the window, else hide it. * @param[in] unityWndId active front window + * @param[in] bottom if true, adjust the z-order to be bottom most. */ void -DnDUI::UpdateUnityDetWndCB(bool bShow, - uint32 unityWndId) +DnDUI::CommonUpdateUnityDetWndCB(bool bShow, + uint32 unityWndId, + bool bottom) { - if (bShow && unityWndId > 0) { - int width = m_detWndFull->GetScreenWidth(); - int height = m_detWndFull->GetScreenHeight(); - m_detWndFull->SetGeometry(0, 0, width, height); - m_detWndFull->Lower(); - m_detWndFull->Show(); + if (bShow && ((unityWndId > 0) || bottom)) { + int width = m_detWnd->GetScreenWidth(); + int height = m_detWnd->GetScreenHeight(); + m_detWnd->SetGeometry(0, 0, width, height); + m_detWnd->Show(); + if (bottom) { + m_detWnd->Lower(); + } + + Debug("%s: show, (0, 0, %d, %d)\n", __FUNCTION__, width, height); } else { - m_detWndFull->Hide(); + if (m_detWnd->GetIsVisible() == true) { + if (m_unityMode) { + + /* + * Show and move detection window to current mouse position + * and resize. + */ + SendFakeXEvents(true, false, true, true, false, 0, 0); + } + } else { + m_detWnd->Hide(); + Debug("%s: hide\n", __FUNCTION__); + } } } /** * - * Reset the UI independent DnD layer. + * Move detection windows to current cursor position. */ void -DnDUI::Reset(void) +DnDUI::CommonMoveDetWndToMousePos(void) { - Debug("%s: entering\n", __FUNCTION__); - if (m_DnD) { - m_DnD->ResetDnD(); + SendFakeXEvents(true, false, true, true, false, 0, 0); +} + + +/** + * + * Handle request from common layer to update mouse position. + * + * @param[in] x x coordinate of pointer + * @param[in] y y coordinate of pointer + */ + +void +DnDUI::CommonUpdateMouseCB(int32 x, + int32 y) +{ + // Position the pointer, and record its position. + + SendFakeXEvents(false, false, false, false, true, x, y); + m_mousePosX = x; + m_mousePosY = y; + + if (m_dc && !m_GHDnDInProgress) { + + // If we are the context of a DnD, send DnD feedback to the source. + + DND_DROPEFFECT effect; + effect = ToDropEffect((Gdk::DragAction)(m_dc->action)); + if (effect != m_effect) { + m_effect = effect; + Debug("%s: Updating feedback\n", __FUNCTION__); + SourceUpdateFeedback(m_effect); + } } } +/* Beginning of Gtk+ Callbacks */ + +/* + * Source callbacks from Gtk+. Most are seen only when we are acting as a + * drag source. + */ /** * @@ -786,39 +635,46 @@ DnDUI::Reset(void) * we only return false if we don't recognize the types being offered. We * return true otherwise, even if we don't accept the drag right now for some * other reason. + * + * @note you may see this callback during DnD when detection window is acting + * as a source. In that case it will be ignored. In a future refactoring, + * we will try and avoid this. */ bool -DnDUI::LocalDragMotionCB(const Glib::RefPtr &dc, - int x, - int y, - guint time) +DnDUI::GtkDestDragMotionCB(const Glib::RefPtr &dc, + int x, + int y, + guint timeValue) { - DND_DROPEFFECT effect; - - effect = ToDropEffect(dc->get_action()); - if (effect != m_effect) { - m_effect = effect; - Debug("%s: Updating feedback\n", __FUNCTION__); - SourceUpdateFeedback(m_effect); - } - /* * If this is a Host to Guest drag, we are done here, so return. */ + Debug("%s: enter", __FUNCTION__); + + unsigned long curTime = GetTimeInMillis(); + if (curTime - m_destDropTime <= 1000) { + Debug("%s: ignored %ld %ld %ld\n", __FUNCTION__, + curTime, m_destDropTime, curTime - m_destDropTime); + return true; + } - if (m_inHGDrag) { + Debug("%s: not ignored %ld %ld %ld\n", __FUNCTION__, + curTime, m_destDropTime, curTime - m_destDropTime); + + if (m_inHGDrag || m_HGGetDataInProgress) { + Debug("%s: ignored not in hg drag or not getting hg data\n", __FUNCTION__); return true; } Gdk::DragAction srcActions; Gdk::DragAction suggestedAction; + Gdk::DragAction dndAction = (Gdk::DragAction)0; Glib::ustring target = m_detWnd->drag_dest_find_target(dc); if (!m_DnD->IsDnDAllowed()) { Debug("%s: No dnd allowed!\n", __FUNCTION__); - m_GHDnDAction = (Gdk::DragAction)0; - dc->drag_status(m_GHDnDAction, time); + dc->drag_status(dndAction, timeValue); return true; } @@ -847,6 +703,8 @@ DnDUI::LocalDragMotionCB(const Glib::RefPtr &dc, return true; } + m_dc = dc->gobj(); + if (target != "") { /* * We give preference to the suggested action from the source, and prefer @@ -855,19 +713,20 @@ DnDUI::LocalDragMotionCB(const Glib::RefPtr &dc, suggestedAction = dc->get_suggested_action(); srcActions = dc->get_actions(); if (suggestedAction == Gdk::ACTION_COPY || suggestedAction == Gdk::ACTION_MOVE) { - m_GHDnDAction = suggestedAction; + dndAction = suggestedAction; } else if (srcActions & Gdk::ACTION_COPY) { - m_GHDnDAction= Gdk::ACTION_COPY; + dndAction= Gdk::ACTION_COPY; } else if (srcActions & Gdk::ACTION_MOVE) { - m_GHDnDAction = Gdk::ACTION_MOVE; + dndAction = Gdk::ACTION_MOVE; } else { - m_GHDnDAction = (Gdk::DragAction)0; + dndAction = (Gdk::DragAction)0; } } else { - m_GHDnDAction = (Gdk::DragAction)0; + dndAction = (Gdk::DragAction)0; } - if (m_GHDnDAction != (Gdk::DragAction)0) { + if (dndAction != (Gdk::DragAction)0) { + dc->drag_status(dndAction, timeValue); if (!m_GHDnDInProgress) { Debug("%s: new drag, need to get data for host\n", __FUNCTION__); /* @@ -876,19 +735,9 @@ DnDUI::LocalDragMotionCB(const Glib::RefPtr &dc, * retrieve the drop data. */ m_GHDnDInProgress = true; - m_GHDnDAction = (Gdk::DragAction)0; /* only begin drag enter after we get the data */ /* Need to grab all of the data. */ - m_detWnd->drag_get_data(dc, target, time); - } else if (m_GHDnDDataReceived) { - Debug("%s: m_GHDnDDataReceived, setting mouse position\n", __FUNCTION__); - m_DnD->SetMouse(x, y, true); - - if (m_GHDnDHostStatus) { - /* Got host response, respond with a proper drag status. */ - Debug("%s: Existing status, calling drag_status()\n", __FUNCTION__); - dc->drag_status(m_GHDnDAction, time); - } + m_detWnd->drag_get_data(dc, target, timeValue); } else { Debug("%s: Multiple drag motions before gh data has been received.\n", __FUNCTION__); @@ -903,99 +752,38 @@ DnDUI::LocalDragMotionCB(const Glib::RefPtr &dc, /** * - * Got feedback from our DropSource, send it over to host. Called by - * drag motion callback. - * - * @param[in] effect feedback to send to the UI-independent DnD layer. - */ - -void -DnDUI::SourceUpdateFeedback(DND_DROPEFFECT effect) -{ - Debug("%s: entering\n", __FUNCTION__); - m_DnD->SetFeedback(effect); -} - - -/** - * - * "drag_leave" signal handler for GTK. We can't clean up the drop - * operation here, because it might be part of a drop. See the - * LocalDragLeaveTimeout() function for more details. + * "drag_leave" signal handler for GTK. Log the reception of this signal, + * but otherwise unhandled in our implementation. * * @param[in] dc drag context * @param[in] time time of the drag */ void -DnDUI::LocalDragLeaveCB(const Glib::RefPtr &dc, guint time) +DnDUI::GtkDestDragLeaveCB(const Glib::RefPtr &dc, + guint time) { Debug("%s: enter\n", __FUNCTION__); - m_feedbackChanged.disconnect(); - dc->drag_finish(true, dc->get_action() == Gdk::ACTION_MOVE, time); - ResetUIStateCB(); } +/* + * Gtk+ callbacks that are seen when we are a drag source. + */ + /** * * "drag_begin" signal handler for GTK. - * Added to help understand Gtk+ state when looking at logs. * * @param[in] context drag context */ void -DnDUI::LocalDragBeginCB(const Glib::RefPtr& context) -{ - Debug("%s: enter\n", __FUNCTION__); -} - - -/** - * - * "drag_drop" signal handler for GTK. Send the drop to the host (by - * way of the backdoor), then tell the host to get the files. - * - * @param[in] dc drag context - * @param[in] x x location of the drop - * @param[in] y y location of the drop - * @param[in] time timestamp for the drop - * - * @return true on success, false otherwise. - */ - -bool -DnDUI::LocalDragDropCB(const Glib::RefPtr &dc, - int x, - int y, - guint time) +DnDUI::GtkSourceDragBeginCB(const Glib::RefPtr& context) { - Debug("%s: enter x %d y %d\n", __FUNCTION__, x, y); - - Glib::ustring target; - - target = m_detWnd->drag_dest_find_target(dc); - - if (m_VMIsSource) { - Debug("%s: Dropping in same vm.\n", __FUNCTION__); - /* Act as a drop */ - ResetUIStateCB(); - return false; - } - - if (target == "") { - Debug("%s: No valid data on clipboard.\n", __FUNCTION__); - m_DnD->ResetDnD(); - return false; - } - - if (CPClipboard_IsEmpty(&m_clipboard)) { - Debug("%s: No valid data on m_clipboard.\n", __FUNCTION__); - m_DnD->ResetDnD(); - return false; - } - return true; + Debug("%s: enter dc %p, m_dc %p\n", __FUNCTION__, + context ? context->gobj() : NULL, m_dc ? m_dc : NULL); + m_dc = context->gobj(); } @@ -1014,10 +802,10 @@ DnDUI::LocalDragDropCB(const Glib::RefPtr &dc, */ void -DnDUI::LocalDragDataGetCB(const Glib::RefPtr &dc, - Gtk::SelectionData& selection_data, - guint info, - guint time) +DnDUI::GtkSourceDragDataGetCB(const Glib::RefPtr &dc, + Gtk::SelectionData& selection_data, + guint info, + guint time) { size_t index = 0; std::string str; @@ -1036,6 +824,7 @@ DnDUI::LocalDragDataGetCB(const Glib::RefPtr &dc, if (!m_inHGDrag) { Debug("%s: not in drag, return\n", __FUNCTION__); + return; } if (target == DRAG_TARGET_NAME_URI_LIST && @@ -1102,6 +891,8 @@ DnDUI::LocalDragDataGetCB(const Glib::RefPtr &dc, m_HGGetDataInProgress = true; m_isFileDnD = true; AddBlock(); + } else { + Debug("%s: not calling AddBlock\n", __FUNCTION__); } selection_data.set(DRAG_TARGET_NAME_URI_LIST, uriList.c_str()); Debug("%s: exit\n", __FUNCTION__); @@ -1139,26 +930,43 @@ DnDUI::LocalDragDataGetCB(const Glib::RefPtr &dc, /* Can not get any valid data, cancel this HG DnD. */ Debug("%s: no valid data for HG DnD\n", __FUNCTION__); m_DnD->SourceCancel(); - ResetUIStateCB(); + CommonResetCB(); } /** * - * "drag_end" handler for GTK. + * "drag_end" handler for GTK. Received by drag source. * * @param[in] dc drag state */ void -DnDUI::LocalDragEndCB(const Glib::RefPtr &dc) +DnDUI::GtkSourceDragEndCB(const Glib::RefPtr &dc) { - Debug("%s: enter\n", __FUNCTION__); + Debug("%s: entering dc %p, m_dc %p\n", __FUNCTION__, + dc ? dc->gobj() : NULL, m_dc ? m_dc : NULL); + + /* + * We may see a drag end for the previous DnD, but after a new + * DnD has started. If so, ignore it. + */ + if (m_dc && dc && (m_dc != dc->gobj())) { + Debug("%s: got old dc (new DnD started), ignoring\n", __FUNCTION__); + return; + } + + /* + * If we are a file DnD, don't call CommonResetCB() here, since + * we will do so in the fileCopyDoneChanged callback. + */ if (!m_isFileDnD) { - Reset(); + CommonResetCB(); } + m_inHGDrag = false; } +/* Gtk+ callbacks seen when we are a drag destination. */ /** * @@ -1177,15 +985,15 @@ DnDUI::LocalDragEndCB(const Glib::RefPtr &dc) */ void -DnDUI::LocalDragDataReceivedCB(const Glib::RefPtr &dc, - int x, - int y, - const Gtk::SelectionData& sd, - guint info, - guint time) +DnDUI::GtkDestDragDataReceivedCB(const Glib::RefPtr &dc, + int x, + int y, + const Gtk::SelectionData& sd, + guint info, + guint time) { Debug("%s: enter\n", __FUNCTION__); - /* The HG DnD may already finish before we got response. */ + /* The GH DnD may already finish before we got response. */ if (!m_GHDnDInProgress) { Debug("%s: not valid\n", __FUNCTION__); return; @@ -1195,11 +1003,18 @@ DnDUI::LocalDragDataReceivedCB(const Glib::RefPtr &dc, /* * Try to get data provided from the source. If we cannot get any data, - * there is no need to inform the guest of anything. + * there is no need to inform the guest of anything. If there is no data, + * reset, so that the next drag_motion callback that we see will be allowed + * to request data again. */ - LocalGetSelection(sd); + if (SetCPClipboardFromGtk(sd) == false) { + Debug("%s: Failed to set CP clipboard.\n", __FUNCTION__); + CommonResetCB(); + return; + } if (CPClipboard_IsEmpty(&m_clipboard)) { Debug("%s: Failed getting item.\n", __FUNCTION__); + CommonResetCB(); return; } @@ -1218,37 +1033,66 @@ DnDUI::LocalDragDataReceivedCB(const Glib::RefPtr &dc, Debug("%s: Drag entering.\n", __FUNCTION__); m_GHDnDDataReceived = true; TargetDragEnter(); - m_feedbackChanged = m_DnD->updateFeedbackChanged.connect( - sigc::bind(sigc::mem_fun(this, &DnDUI::SourceFeedbackChangedCB), dc)); - } else if (m_GHDnDDropOccurred) { - Debug("%s: Drag dropping.\n", __FUNCTION__); - m_DnD->TargetDrop(&m_clipboard, x, y); - dc->drag_finish(true, dc->get_action() == Gdk::ACTION_MOVE, time); - /* - * Can't use ResetUIStateCB because file transfer state should not be - * cleared. - */ - m_GHDnDDataReceived = false; - m_GHDnDAction = (Gdk::DragAction)0; - m_GHDnDHostStatus = false; - m_GHDnDInProgress = false; - m_feedbackChanged.disconnect(); } else { - Debug("%s: neither m_GHDnDDropOccurred, nor !m_GHDnDDataReceived\n", - __FUNCTION__); + Debug("%s: not !m_GHDnDDataReceived\n", __FUNCTION__); + } +} + + +/** + * + * "drag_drop" signal handler for GTK. Send the drop to the host (by + * way of the backdoor), then tell the host to get the files. + * + * @param[in] dc drag context + * @param[in] x x location of the drop + * @param[in] y y location of the drop + * @param[in] time timestamp for the drop + * + * @return true on success, false otherwise. + */ + +bool +DnDUI::GtkDestDragDropCB(const Glib::RefPtr &dc, + int x, + int y, + guint time) +{ + Debug("%s: enter x %d y %d\n", __FUNCTION__, x, y); + + Glib::ustring target; + + target = m_detWnd->drag_dest_find_target(dc); + Debug("%s: calling drag_finish\n", __FUNCTION__); + dc->drag_finish(true, false, time); + + if (target == "") { + Debug("%s: No valid data on clipboard.\n", __FUNCTION__); + return false; } + + if (CPClipboard_IsEmpty(&m_clipboard)) { + Debug("%s: No valid data on m_clipboard.\n", __FUNCTION__); + return false; + } + + return true; } +/* General utility functions */ /** * - * Try to construct cross-platform clipboard data from selection data. + * Try to construct cross-platform clipboard data from selection data + * provided to us by Gtk+. * * @param[in] sd Gtk selection data to convert to CP clipboard data + * + * @return false on failure, true on success */ -void -DnDUI::LocalGetSelection(const Gtk::SelectionData& sd) // IN +bool +DnDUI::SetCPClipboardFromGtk(const Gtk::SelectionData& sd) // IN { char *newPath; char *newRelPath; @@ -1269,6 +1113,12 @@ DnDUI::LocalGetSelection(const Gtk::SelectionData& sd) // IN */ utf::string source = sd.get_data_as_string().c_str(); Debug("%s: Got file list: [%s]\n", __FUNCTION__, source.c_str()); + + if (sd.get_data_as_string().length() == 0) { + Debug("%s: empty file list!\n", __FUNCTION__); + return false; + } + /* * In gnome, before file list there may be a extra line indicating it * is a copy or cut. @@ -1313,7 +1163,7 @@ DnDUI::LocalGetSelection(const Gtk::SelectionData& sd) // IN DynBuf_GetSize(&buf)); } DynBuf_Destroy(&buf); - return; + return true; } /* Try to get plain text. */ @@ -1329,8 +1179,9 @@ DnDUI::LocalGetSelection(const Gtk::SelectionData& sd) // IN Debug("%s: Got text, size %"FMTSZ"u\n", __FUNCTION__, source.bytes()); } else { Debug("%s: Failed to get text\n", __FUNCTION__); + return false; } - return; + return true; } /* Try to get RTF string. */ @@ -1342,10 +1193,13 @@ DnDUI::LocalGetSelection(const Gtk::SelectionData& sd) // IN CPClipboard_SetItem(&m_clipboard, CPFORMAT_RTF, source.c_str(), source.bytes() + 1)) { Debug("%s: Got RTF, size %"FMTSZ"u\n", __FUNCTION__, source.bytes()); + return true; } else { Debug("%s: Failed to get text\n", __FUNCTION__ ); + return false; } } + return true; } @@ -1452,10 +1306,10 @@ DnDUI::GetNextPath(utf::utf8string& str, */ bool -DnDUI::DnDHGFakeMove(const int x, - const int y) +DnDUI::SendFakeMouseMove(const int x, + const int y) { - return DnDFakeXEvents(false, false, false, false, true, x, y); + return SendFakeXEvents(false, false, false, false, true, x, y); } @@ -1475,17 +1329,20 @@ DnDUI::DnDHGFakeMove(const int x, * @param[in] xCoord x coordinate * @param[in] yCoord y coordinate * + * @note todo this code should be implemented using GDK APIs. + * @note todo this code should be moved into the detection window class + * * @return true on success, false on failure. */ bool -DnDUI::DnDFakeXEvents(const bool showWidget, - const bool buttonEvent, - const bool buttonPress, - const bool moveWindow, - const bool coordsProvided, - const int xCoord, - const int yCoord) +DnDUI::SendFakeXEvents(const bool showWidget, + const bool buttonEvent, + const bool buttonPress, + const bool moveWindow, + const bool coordsProvided, + const int xCoord, + const int yCoord) { GtkWidget *widget; Window rootWnd; @@ -1498,8 +1355,7 @@ DnDUI::DnDFakeXEvents(const bool showWidget, x = xCoord; y = yCoord; - Debug("%s: enter\n", __FUNCTION__); - widget = GetDetWndAsWidget(false); + widget = GetDetWndAsWidget(); if (!widget) { Debug("%s: unable to get widget\n", __FUNCTION__); @@ -1543,10 +1399,49 @@ DnDUI::DnDFakeXEvents(const bool showWidget, return false; } - Debug("%s: mouse is at (%d, %d)\n", __FUNCTION__, rootXReturn, rootYReturn); + Debug("%s: current mouse is at (%d, %d)\n", __FUNCTION__, + rootXReturn, rootYReturn); + + /* + * Position away from the edge of the window. + */ + int width = m_detWnd->GetScreenWidth(); + int height = m_detWnd->GetScreenHeight(); + bool change = false; x = rootXReturn; y = rootYReturn; + + /* + * first do left and top edges. + */ + + if (x <= 5) { + x = 6; + change = true; + } + + if (y <= 5) { + y = 6; + change = true; + } + + /* + * next, move result away from right and bottom edges. + */ + if (x > width - 5) { + x = width - 6; + change = true; + } + if (y > height - 5) { + y = height - 6; + change = true; + } + + if (change) { + Debug("%s: adjusting mouse position. root %d, %d, adjusted %d, %d\n", + __FUNCTION__, rootXReturn, rootYReturn, x, y); + } } if (moveWindow) { @@ -1557,8 +1452,9 @@ DnDUI::DnDFakeXEvents(const bool showWidget, * is okay since the window is invisible and hidden on cancels and DnD * finish. */ - XMoveResizeWindow(dndXDisplay, dndXWindow, x, y, 25, 25); + XMoveResizeWindow(dndXDisplay, dndXWindow, x - 5 , y - 5, 25, 25); XRaiseWindow(dndXDisplay, dndXWindow); + Debug("%s: move wnd to (%d, %d, %d, %d)\n", __FUNCTION__, x - 5, y - 5 , x + 25, y + 25); } /* @@ -1567,6 +1463,7 @@ DnDUI::DnDFakeXEvents(const bool showWidget, */ XTestFakeMotionEvent(dndXDisplay, -1, x, y, CurrentTime); XTestFakeMotionEvent(dndXDisplay, -1, x + 1, y + 1, CurrentTime); + Debug("%s: move mouse to (%d, %d) and (%d, %d)\n", __FUNCTION__, x, y, x + 1, y + 1); if (buttonEvent) { Debug("%s: faking left mouse button %s\n", __FUNCTION__, @@ -1587,30 +1484,20 @@ DnDUI::DnDFakeXEvents(const bool showWidget, * window. This function is also called by the code that issues fake * X events to the detection window. * - * @param[in] full true to get the GtkWindow for the full (unity) - * detection window, otherwise false. - * * @return a pointer to the GtkWidget for the detection window, or NULL * on failure. */ GtkWidget * -DnDUI::GetDetWndAsWidget(const bool full) +DnDUI::GetDetWndAsWidget() { GtkInvisible *window; GtkWidget *widget = NULL; - DragDetWnd *detWnd; - - if (full) { - detWnd = m_detWndFull; - } else { - detWnd = m_detWnd; - } - if (!detWnd) { + if (!m_detWnd) { return NULL; } - window = detWnd->gobj(); + window = m_detWnd->gobj(); if (window) { widget = GTK_WIDGET(window); } @@ -1627,6 +1514,7 @@ DnDUI::GetDetWndAsWidget(const bool full) void DnDUI::AddBlock() { + Debug("%s: enter\n", __FUNCTION__); if (m_blockAdded) { Debug("%s: block already added\n", __FUNCTION__); return; @@ -1684,6 +1572,7 @@ DnDUI::ToDropEffect(Gdk::DragAction action) switch(action) { case Gdk::ACTION_COPY: + case Gdk::ACTION_DEFAULT: effect = DROP_COPY; break; case Gdk::ACTION_MOVE: @@ -1693,7 +1582,6 @@ DnDUI::ToDropEffect(Gdk::DragAction action) effect = DROP_LINK; break; case Gdk::ACTION_PRIVATE: - case Gdk::ACTION_DEFAULT: case Gdk::ACTION_ASK: default: effect = DROP_UNKNOWN; @@ -1703,4 +1591,273 @@ DnDUI::ToDropEffect(Gdk::DragAction action) } +/** + * + * Try to extract file contents from m_clipboard. Write all files to a + * temporary staging directory. Construct uri list. + * + * @return true if success, false otherwise. + */ + +bool +DnDUI::WriteFileContentsToStagingDir(void) +{ + void *buf = NULL; + size_t sz = 0; + XDR xdrs; + CPFileContents fileContents; + CPFileContentsList *contentsList = NULL; + size_t nFiles = 0; + CPFileItem *fileItem = NULL; + Unicode tempDir = NULL; + size_t i = 0; + bool ret = false; + + if (!CPClipboard_GetItem(&m_clipboard, CPFORMAT_FILECONTENTS, &buf, &sz)) { + return false; + } + + /* Extract file contents from buf. */ + xdrmem_create(&xdrs, (char *)buf, sz, XDR_DECODE); + memset(&fileContents, 0, sizeof fileContents); + + if (!xdr_CPFileContents(&xdrs, &fileContents)) { + Debug("%s: xdr_CPFileContents failed.\n", __FUNCTION__); + xdr_destroy(&xdrs); + return false; + } + xdr_destroy(&xdrs); + + contentsList = fileContents.CPFileContents_u.fileContentsV1; + if (!contentsList) { + Debug("%s: invalid contentsList.\n", __FUNCTION__); + goto exit; + } + + nFiles = contentsList->fileItem.fileItem_len; + if (0 == nFiles) { + Debug("%s: invalid nFiles.\n", __FUNCTION__); + goto exit; + } + + fileItem = contentsList->fileItem.fileItem_val; + if (!fileItem) { + Debug("%s: invalid fileItem.\n", __FUNCTION__); + goto exit; + } + + /* + * Write files into a temporary staging directory. These files will be moved + * to final destination, or deleted on next reboot. + */ + tempDir = DnD_CreateStagingDirectory(); + if (!tempDir) { + Debug("%s: DnD_CreateStagingDirectory failed.\n", __FUNCTION__); + goto exit; + } + + m_HGFileContentsUriList = ""; + + for (i = 0; i < nFiles; i++) { + utf::string fileName; + utf::string filePathName; + VmTimeType createTime = -1; + VmTimeType accessTime = -1; + VmTimeType writeTime = -1; + VmTimeType attrChangeTime = -1; + + if (!fileItem[i].cpName.cpName_val || + 0 == fileItem[i].cpName.cpName_len) { + Debug("%s: invalid fileItem[%"FMTSZ"u].cpName.\n", __FUNCTION__, i); + goto exit; + } + + /* + * '\0' is used as directory separator in cross-platform name. Now turn + * '\0' in data into DIRSEPC. + * + * Note that we don't convert the final '\0' into DIRSEPC so the string + * is NUL terminated. + */ + CPNameUtil_CharReplace(fileItem[i].cpName.cpName_val, + fileItem[i].cpName.cpName_len - 1, + '\0', + DIRSEPC); + fileName = fileItem[i].cpName.cpName_val; + filePathName = tempDir; + filePathName += DIRSEPS + fileName; + + if (fileItem[i].validFlags & CP_FILE_VALID_TYPE && + CP_FILE_TYPE_DIRECTORY == fileItem[i].type) { + if (!File_CreateDirectory(filePathName.c_str())) { + goto exit; + } + Debug("%s: created directory [%s].\n", + __FUNCTION__, filePathName.c_str()); + } else if (fileItem[i].validFlags & CP_FILE_VALID_TYPE && + CP_FILE_TYPE_REGULAR == fileItem[i].type) { + FileIODescriptor file; + FileIOResult fileErr; + + FileIO_Invalidate(&file); + + fileErr = FileIO_Open(&file, + filePathName.c_str(), + FILEIO_ACCESS_WRITE, + FILEIO_OPEN_CREATE_EMPTY); + if (!FileIO_IsSuccess(fileErr)) { + goto exit; + } + + fileErr = FileIO_Write(&file, + fileItem[i].content.content_val, + fileItem[i].content.content_len, + NULL); + + FileIO_Close(&file); + Debug("%s: created file [%s].\n", + __FUNCTION__, filePathName.c_str()); + } else { + /* + * Right now only Windows can provide CPFORMAT_FILECONTENTS data. + * Symlink file is not expected. Continue with next file if the + * type is not valid. + */ + continue; + } + + /* Update file time attributes. */ + createTime = fileItem->validFlags & CP_FILE_VALID_CREATE_TIME ? + fileItem->createTime: -1; + accessTime = fileItem->validFlags & CP_FILE_VALID_ACCESS_TIME ? + fileItem->accessTime: -1; + writeTime = fileItem->validFlags & CP_FILE_VALID_WRITE_TIME ? + fileItem->writeTime: -1; + attrChangeTime = fileItem->validFlags & CP_FILE_VALID_CHANGE_TIME ? + fileItem->attrChangeTime: -1; + + if (!File_SetTimes(filePathName.c_str(), + createTime, + accessTime, + writeTime, + attrChangeTime)) { + /* Not a critical error, only log it. */ + Debug("%s: File_SetTimes failed with file [%s].\n", + __FUNCTION__, filePathName.c_str()); + } + + /* Update file permission attributes. */ + if (fileItem->validFlags & CP_FILE_VALID_PERMS) { + if (Posix_Chmod(filePathName.c_str(), + fileItem->permissions) < 0) { + /* Not a critical error, only log it. */ + Debug("%s: Posix_Chmod failed with file [%s].\n", + __FUNCTION__, filePathName.c_str()); + } + } + + /* + * If there is no DIRSEPC inside the fileName, this file/directory is a + * top level one. We only put top level name into uri list. + */ + if (fileName.find(DIRSEPS, 0) == utf::string::npos) { + m_HGFileContentsUriList += "file://" + filePathName + "\r\n"; + } + } + Debug("%s: created uri list [%s].\n", + __FUNCTION__, m_HGFileContentsUriList.c_str()); + ret = true; + +exit: + xdr_free((xdrproc_t) xdr_CPFileContents, (char *)&fileContents); + if (tempDir && !ret) { + DnD_DeleteStagingFiles(tempDir, false); + } + free(tempDir); + return ret; +} + + +/** + * + * Tell host that we are done with HG DnD initialization. + */ + +void +DnDUI::SourceDragStartDone(void) +{ + Debug("%s: enter\n", __FUNCTION__); + m_inHGDrag = true; + m_DnD->HGDragStartDone(); +} + + +/** + * Set block control member. + * + * @param[in] block control as setup by vmware-user. + */ + +void +DnDUI::SetBlockControl(DnDBlockControl *blockCtrl) +{ + m_blockCtrl = blockCtrl; +} + + +/** + * + * Got feedback from our DropSource, send it over to host. Called by + * drag motion callback. + * + * @param[in] effect feedback to send to the UI-independent DnD layer. + */ + +void +DnDUI::SourceUpdateFeedback(DND_DROPEFFECT effect) +{ + Debug("%s: entering\n", __FUNCTION__); + m_DnD->SetFeedback(effect); +} + + +/** + * + * This is triggered when user drags valid data from guest to host. Try to + * get clip data and notify host to start GH DnD. + */ +void +DnDUI::TargetDragEnter(void) +{ + Debug("%s: entering\n", __FUNCTION__); + + /* Check if there is valid data with current detection window. */ + if (!CPClipboard_IsEmpty(&m_clipboard)) { + Debug("%s: got valid data from detWnd.\n", __FUNCTION__); + m_DnD->DragEnter(&m_clipboard); + } + + /* + * Show the window, and position it under the current mouse position. + * This is particularly important for KDE 3.5 guests. + */ + SendFakeXEvents(true, false, true, true, false, 0, 0); +} + + +/** + * + * Get Unix time in milliseconds. See man 2 gettimeofday for details. + * + * @return unix time in milliseconds. + */ + +unsigned long +DnDUI::GetTimeInMillis(void) +{ + VmTimeType atime; + + Hostinfo_GetTimeOfDay(&atime); + return((unsigned long)(atime / 1000)); +} diff --git a/open-vm-tools/vmware-user/dndUI.h b/open-vm-tools/vmware-user/dndUI.h index b09fb5d3c..233086c25 100644 --- a/open-vm-tools/vmware-user/dndUI.h +++ b/open-vm-tools/vmware-user/dndUI.h @@ -58,123 +58,135 @@ class DnDUI public: DnDUI(DblLnkLst_Links *eventQueue); ~DnDUI(); - void Init(); + bool Init(); void VmxDnDVersionChanged(struct RpcIn *rpcIn, uint32 version) - { ASSERT(m_DnD); m_DnD->VmxDnDVersionChanged(rpcIn, version); } + {ASSERT(m_DnD); m_DnD->VmxDnDVersionChanged(rpcIn, version);} void SetDnDAllowed(bool isDnDAllowed) - { ASSERT(m_DnD); m_DnD->SetDnDAllowed(isDnDAllowed); } - void Reset(void); - void ResetUIStateCB(); + {ASSERT(m_DnD); m_DnD->SetDnDAllowed(isDnDAllowed);} void SetBlockControl(DnDBlockControl *blockCtrl); void SetUnityMode(Bool mode) {m_unityMode = mode;}; - DragDetWnd *GetFullDetWnd() {return m_detWndFull;} - GtkWidget *GetDetWndAsWidget(const bool full); + + DragDetWnd *GetFullDetWnd() {return m_detWnd;} + GtkWidget *GetDetWndAsWidget(); + +private: /** - * Source functions for HG DnD + * Blocking FS Helper Functions. */ - void SourceDragStartDone(void); - void SourceUpdateFeedback(DND_DROPEFFECT effect); + void AddBlock(); + void RemoveBlock(); /** - * Target function for GH DnD. + * Callbacks from Common DnD layer. */ - void TargetDragEnter(void); + void CommonResetCB(); + void CommonUpdateMouseCB(int32 x, int32 y); /** - * Callbacks. H->G + * Source functions for HG DnD. */ + void CommonDragStartCB(const CPClipboard *clip, std::string stagingDir); + void CommonSourceDropCB(void); - bool LocalDragMotionCB(const Glib::RefPtr &dc, int x, - int y, guint time); - void LocalDragDataReceivedCB(const Glib::RefPtr &dc, - int x, int y, const Gtk::SelectionData &sd, - guint info, guint time); - void LocalGetSelection(const Gtk::SelectionData& sd); - void LocalDragLeaveCB(const Glib::RefPtr &dc, guint time); - bool LocalDragDropCB(const Glib::RefPtr &dc, int x, int y, - guint time); - - void SourceFeedbackChangedCB(DND_DROPEFFECT effect, const Glib::RefPtr dc); - - void LocalDragDataGetCB( - const Glib::RefPtr& context, - Gtk::SelectionData& selection_data, guint info, guint time); - void LocalDragEndCB( - const Glib::RefPtr& context); - void LocalDragBeginCB( - const Glib::RefPtr& context); - -#if defined(DETWNDTEST) - void CreateTestUI(); -#endif -private: + /** + * Called when HG Dnd is completed. + */ + void CommonSourceCancelCB(void); - void AddBlock(); - void RemoveBlock(); + /** + * Called when GH DnD is completed. + */ + void CommonDestPrivateDropCB(int32 x, int32 y); + void CommonDestCancelCB(void); /** - * Source functions for HG DnD. + * Source functions for file transfer. + */ + void CommonSourceFileCopyDoneCB(bool success, std::vector stagingDir); + + /** + * Callbacks for showing/hiding detection window. + */ + void CommonUpdateDetWndCB(bool bShow, int32 x, int32 y); + void CommonUpdateUnityDetWndCB(bool bShow, uint32 unityWndId, bool bottom); + void CommonMoveDetWndToMousePos(void); + + /** + * Gtk+ Callbacks: Drag Destination. */ - void RemoteDragStartCB(const CPClipboard *clip, - std::string stagingDir); - void SourceDropCB(void); - void SourceCancelCB(void); + void GtkDestDragDataReceivedCB(const Glib::RefPtr &dc, + int x, int y, const Gtk::SelectionData &sd, + guint info, guint time); + bool GtkDestDragDropCB(const Glib::RefPtr &dc, + int x, int y, guint time); + void GtkDestDragLeaveCB(const Glib::RefPtr &dc, + guint time); + bool GtkDestDragMotionCB(const Glib::RefPtr &dc, int x, + int y, guint time); /** - * Called when GH is completed. + * Gtk+ Callbacks: Drag Source. + */ + void GtkSourceDragBeginCB(const Glib::RefPtr& context); + void GtkSourceDragDataGetCB(const Glib::RefPtr& context, + Gtk::SelectionData& selection_data, guint info, + guint time); + void GtkSourceDragEndCB(const Glib::RefPtr& context); + /** + * Source functions for HG DnD. Makes calls to common layer. */ - void GHCancelCB(void); + void SourceDragStartDone(void); + void SourceUpdateFeedback(DND_DROPEFFECT effect); /** - * Source functions for HG file transfer. + * Target function for GH DnD. Makes call to common layer. */ - void GetLocalFilesDoneCB(bool success, std::vector stagingDir); + void TargetDragEnter(void); /** * Misc methods. */ + bool SetCPClipboardFromGtk(const Gtk::SelectionData& sd); std::string GetLastDirName(const std::string &str); utf::utf8string GetNextPath(utf::utf8string &str, size_t& index); - void UpdateDetWndCB(bool bShow, int32 x, int32 y); - void UpdateUnityDetWndCB(bool bShow, uint32 unityWndId); DND_DROPEFFECT ToDropEffect(Gdk::DragAction action); void SetTargetsAndCallbacks(); - bool DnDFakeXEvents(const bool showWidget, const bool buttonEvent, - const bool buttonPress, const bool moveWindow, - const bool coordsProvided, const int xCoord, const int yCoord); - bool DnDHGFakeMove(const int x, const int y); - bool LocalPrepareFileContentsDrag(); + bool SendFakeXEvents(const bool showWidget, const bool buttonEvent, + const bool buttonPress, const bool moveWindow, + const bool coordsProvided, + const int xCoord, const int yCoord); + bool SendFakeMouseMove(const int x, const int y); + bool WriteFileContentsToStagingDir(); + unsigned long GetTimeInMillis(); DblLnkLst_Links *m_eventQueue; DnD *m_DnD; std::string m_HGStagingDir; utf::string m_HGFileContentsUriList; DragDetWnd *m_detWnd; - DragDetWnd *m_detWndFull; CPClipboard m_clipboard; DnDBlockControl *m_blockCtrl; bool m_HGGetDataInProgress; int m_HGEffect; bool m_blockAdded; - /* State to determine if drag motion is is a drag enter. */ + /* State to determine if drag motion is a drag enter. */ bool m_GHDnDInProgress; /* Icon updates from the guest. */ - bool m_GHDnDHostStatus; - /* Drop actions for host and guest respectively. */ - Gdk::DragAction m_GHDnDAction; /* Only update mouse when we have clipboard contents from the host. */ bool m_GHDnDDataReceived; bool m_GHDnDDropOccurred; - bool m_VMIsSource; - sigc::connection m_feedbackChanged; bool m_unityMode; bool m_inHGDrag; DND_DROPEFFECT m_effect; bool m_isFileDnD; + int32 m_mousePosX; + int32 m_mousePosY; + GdkDragContext *m_dc; + unsigned long m_destDropTime; }; #endif // DND_UI_H diff --git a/open-vm-tools/vmware-user/dragDetWnd.cpp b/open-vm-tools/vmware-user/dragDetWnd.cpp index 6c7b3be43..25f32c3f9 100644 --- a/open-vm-tools/vmware-user/dragDetWnd.cpp +++ b/open-vm-tools/vmware-user/dragDetWnd.cpp @@ -42,8 +42,12 @@ extern "C" { * Constructor. */ -DragDetWnd::DragDetWnd() +DragDetWnd::DragDetWnd() : + m_isVisible(false) { +#if defined(DETWNDDEBUG) + DebugSetAttributes(); +#endif } diff --git a/open-vm-tools/vmware-user/dragDetWnd.h b/open-vm-tools/vmware-user/dragDetWnd.h index 55dba43c1..6ee455f45 100644 --- a/open-vm-tools/vmware-user/dragDetWnd.h +++ b/open-vm-tools/vmware-user/dragDetWnd.h @@ -50,11 +50,14 @@ public: void SetGeometry(const int x, const int y, const int width, const int height); void GetGeometry(int &x, int &y, int &width, int &height); + void SetIsVisible(const bool isVisible) {m_isVisible = isVisible;}; + bool GetIsVisible() {return m_isVisible;}; #if defined(DETWNDEBUG) - void SetAttributes(); + void DebugSetAttributes(); #endif private: void Flush(); + bool m_isVisible; }; #if defined(DETWNDTEST) diff --git a/open-vm-tools/vmware-user/vmware-user.cpp b/open-vm-tools/vmware-user/vmware-user.cpp index 1f8862a19..87a697ad2 100644 --- a/open-vm-tools/vmware-user/vmware-user.cpp +++ b/open-vm-tools/vmware-user/vmware-user.cpp @@ -543,7 +543,7 @@ VMwareUserRpcInSetOptionCB(char const **result, // OUT char *value; unsigned int index = 0; Bool ret = FALSE; - char *retStr = NULL; + const char *retStr = NULL; /* parse the option & value string */ option = StrUtil_GetNextToken(&index, args, " ");