+2009-07-22 Marcelo Vanzin <mvanzin@vmware.com>
+ * 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 <mvanzin@vmware.com>
* Resync with internal trunk (2009.06.15)
+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.
### 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
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],
checkvm/Makefile \
rpctool/Makefile \
libguestlib/Makefile \
+ libguestlib/vmguestlib.pc \
libvmtools/Makefile \
xferlogs/Makefile \
modules/Makefile \
/*
-XXX document the dict format:
-
- whitespaces <name> whitespaces '=' whitespaces <value> whitespaces comment
- or
- whitespaces <name> whitespaces '=' whitespaces '"' <value> '"' whitespaces comment
-
- where:
-
- . <name> does not contain any whitespace or = or pound
- . <value> does not contain any double-quote or pound
-*/
+ * The dictionary line format:
+ *
+ * <ws> <name> <ws> = <ws> <value> <ws> <comment>
+ * or
+ * <ws> <name> <ws> = <ws> " <quoted-value> " <ws> <comment>
+ *
+ * where
+ * <name> does not contain any whitespace or = or #
+ * <value> does not contain any double-quote or #
+ * <quoted-value> does not contain any double-quote
+ * <comment> begins with # and ends at the end of the line
+ * <ws> is a sequence spaces and/or tabs
+ * <comment> and <ws> are optional
+ */
/*
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,
* 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');
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;
}
* 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;
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;
* 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;
* When we get rid of NUL termination here, this test should
* also change to "if (*winNameIn != '\0')".
*/
+
if (bufOut == endOut) {
result = -1;
goto out;
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;
}
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:
{
#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
/*
*/
static Bool
-DnDUngrabTimeout(void *clientData) // IN
+DnDUngrabTimeout(void *clientData) // IN
{
ASSERT(clientData);
DnD *dnd = (DnD *)clientData;
}
+/*
+ *---------------------------------------------------------------------
+ *
+ * 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;
+}
+
+
/*
*---------------------------------------------------------------------
*
mDnDAllowed(false),
mStagingDir(""),
mUngrabTimeout(NULL),
+ mUnityDnDDetTimeout(NULL),
mHideDetWndTimer(NULL),
mEventQueue(eventQueue)
{
EventManager_Remove(mUngrabTimeout);
mUngrabTimeout = NULL;
}
+ if (mUnityDnDDetTimeout) {
+ EventManager_Remove(mUnityDnDDetTimeout);
+ mUnityDnDDetTimeout = NULL;
+ }
}
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(
* 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);
+}
+
+
/*
*----------------------------------------------------------------------
*
}
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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__);
+}
+
+
/*
*----------------------------------------------------------------------
*
void SetDnDAllowed(bool isDnDAllowed)
{ mDnDAllowed = isDnDAllowed; }
void UngrabTimeout(void);
+ void UnityDnDDetTimeout(void);
void ResetDnD(void);
void HGDragStartDone(void);
void OnUpdateMouse(int32 x, int32 y);
/* 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);
void OnHGDrop(void);
void OnHGFileCopyDone(bool cancel,
std::vector<uint8> stagingDir);
+ void OnMoveDetWndToMousePos(void);
std::string SetupDestDir(const std::string &destDir);
bool mDnDAllowed;
std::string mStagingDir;
Event *mUngrabTimeout;
+ Event *mUnityDnDDetTimeout;
Event *mHideDetWndTimer;
DblLnkLst_Links *mEventQueue;
};
/* sigc signals for callback. */
sigc::signal<void, bool, uint32> ghUpdateUnityDetWndChanged;
sigc::signal<void, int, int> ghQueryPendingDragChanged;
+ sigc::signal<void, int32, int32>ghPrivateDropChanged;
sigc::signal<void> ghCancelChanged;
sigc::signal<void, const CPClipboard*> hgDragEnterChanged;
sigc::signal<void> hgDragStartChanged;
sigc::signal<void> hgDropChanged;
sigc::signal<void, bool, const std::vector<uint8> > hgFileCopyDoneChanged;
sigc::signal<void, int32, int32> updateMouseChanged;
+ sigc::signal<void> moveDetWndToMousePos;
/* GH DnD. */
virtual bool GHDragEnter(const CPClipboard *clip) = 0;
protected:
uint32 mHostMinorVersion;
+ uint32 mGuestMinorVersion;
};
#endif // DND_RPC_HH
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);
}
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:
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;
}
Debug("%s: got host DnD version %d.%d.\n",
__FUNCTION__, major, mHostMinorVersion);
+ UpdateGuestVersion(3, mGuestMinorVersion);
break;
}
default:
#include "safetime.h"
#if defined(_WIN32)
#include <io.h>
+#define S_IXUSR 0100
#else
#include <unistd.h>
#endif
}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * 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;
+}
+
+
/*
*----------------------------------------------------------------------
*
}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * 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)
/*
*----------------------------------------------------------------------------
#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,
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;
// 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);
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);
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);
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);
}
if (didCoalesce) {
- FileIODecoalesce(&coV, v, numEntries, bytesRead, FALSE);
+ FileIODecoalesce(&coV, v, numEntries, bytesRead, FALSE, fd->flags);
}
if (actual) {
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);
}
if (didCoalesce) {
- FileIODecoalesce(&coV, v, numEntries, bytesWritten, TRUE);
+ FileIODecoalesce(&coV, v, numEntries, bytesWritten, TRUE, fd->flags);
}
if (actual) {
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;
exit:
if (didCoalesce) {
- FileIODecoalesce(&coV, entries, numEntries, sum, FALSE);
+ FileIODecoalesce(&coV, entries, numEntries, sum, FALSE, fd->flags);
}
return fret;
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;
fret = FILEIO_SUCCESS;
exit:
if (didCoalesce) {
- FileIODecoalesce(&coV, entries, numEntries, sum, TRUE);
+ FileIODecoalesce(&coV, entries, numEntries, sum, TRUE, fd->flags);
}
return fret;
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
}
/*
*----------------------------------------------------------------------
*
- * IsValidProcess --
+ * FileLockIsValidProcess --
*
* Determine if the process, via its pid, is valid (alive).
*
*/
static Bool
-IsValidProcess(int pid) // IN:
+FileLockIsValidProcess(int pid) // IN:
{
uid_t uid;
int err;
/*
*----------------------------------------------------------------------
*
- * CreateLockFile --
+ * FileLockCreateLockFile --
*
* Create a new lock file, either via a O_EXCL creat() call or
* through the linking method.
*/
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;
}
}
+
return status;
}
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];
}
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;
return TRUE;
}
- if (!IsValidProcess(pid)) {
+ if (!FileLockIsValidProcess(pid)) {
return FALSE;
}
*handle = PosixFileOpener(pathName, flags, 0644);
- return *handle == -1 ? errno : 0;
+ return (*handle == -1) ? errno : 0;
}
int
FileLockCloseFile(FILELOCK_FILE_HANDLE handle) // IN:
{
- return close(handle) == -1 ? errno : 0;
+ return (close(handle) == -1) ? errno : 0;
}
*/
static int
-Sleeper(LockValues *myValues, // IN/OUT:
- uint32 *loopCount) // IN/OUT:
+Sleeper(LockValues *myValues, // IN/OUT:
+ uint32 *loopCount) // IN/OUT:
{
uint32 msecSleepTime;
#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;
*/
Bool
-FileLockValidName(ConstUnicode fileName) // IN:
+FileLockValidName(ConstUnicode fileName) // IN:
{
uint32 i;
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;
*/
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;
*/
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;
*/
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);
}
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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)
/*
*-----------------------------------------------------------------------------
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;
+}
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),
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),
+
};
*
* 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.
*
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
#include "strutil.h"
#include "unityCommon.h"
#include "util.h"
+#include "xdrutil.h"
/*
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;
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);
}
}
* 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;
}
#include "dynbuf.h"
#include "unityCommon.h"
+#include "guestrpc/ghiGetExecInfoHash.h"
#include "guestrpc/ghiProtocolHandler.h"
typedef struct _GHIPlatform GHIPlatform;
/* 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
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);
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;
}
* 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,
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);
} 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);
}
}
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);
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;
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;
+}
#include <stdlib.h> // for free, system
#include <string.h>
#include <strings.h>
+#include <unistd.h>
#include <glib.h>
gboolean spawnSuccess;
GError *gerror = NULL;
- char **argv = NULL;
+ char *argv[4];
+ char **parsedArgv = NULL;
char *newNetscapeBuf = NULL;
Bool success = FALSE;
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;
* 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
success = TRUE;
abort:
- g_free(argv);
+ g_strfreev(parsedArgv);
free(newNetscapeBuf);
return success;
}
char *argv[] = {
"gconftool-2",
"--get",
- "/desktop/gnome/url-handlers/http/command"
+ "/desktop/gnome/url-handlers/http/command",
+ NULL
};
gboolean success;
gchar *out = NULL;
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";
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);
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
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
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
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); \
--- /dev/null
+/*********************************************************
+ * 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<GHI_HANDLERS_ACTIONURI_MAX_PATH>;
+};
+struct GHIGetExecInfoHashReplyV1 {
+ /*
+ * A string identifier for the hash.
+ */
+ string execHash<GHI_EXEC_INFO_HASH_MAX_LEN>;
+};
+
+/*
+ * 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;
+};
+
/* 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;
}
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;
}
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;
}
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;
/* NUL terminate */
if (myOutSize < 1) {
- Log("CPNameConvertFrom: error: not enough room\n");
+ Log("%s: error: not enough room\n", __FUNCTION__);
return -1;
}
*out = '\0';
*/
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;
}
* 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 { \
* 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 { \
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))) {
/* 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;
* 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;
}
}
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)) {
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;
}
*
* 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)
*
* 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
{
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);
* 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
/* 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;
}
* 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);
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);
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;
}
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;
}
* 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
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;
}
}
* 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
node = HgfsHandle2FileNode(handle, session);
if (node == NULL) {
- LOG(4, ("HgfsRemoveFromCacheInternal: invalid handle.\n"));
+ LOG(4, ("%s: invalid handle.\n", __FUNCTION__));
+
return FALSE;
}
* 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;
}
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;
}
SyncMutex_Lock(&session->nodeArrayLock);
allowed = session->numCachedLockedNodes < MAX_LOCKED_FILENODES;
SyncMutex_Unlock(&session->nodeArrayLock);
+
return allowed;
}
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)) {
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;
}
* 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); \
}
/*
}
/* 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;
exit:
SyncMutex_Unlock(&session->searchArrayLock);
+
return found;
}
/* 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;
}
newSearch->utf8Dir = strdup(utf8Dir);
if (newSearch->utf8Dir == NULL) {
HgfsRemoveSearchInternal(newSearch, session);
+
return NULL;
}
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;
}
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 */
* 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;
out:
SyncMutex_Unlock(&session->searchArrayLock);
+
return dent;
}
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);
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 {
if (!HgfsPacketSend(packetOut, replySize, session, 0)) {
goto error;
}
+
return 0;
error:
free(packetOut);
+
return status;
}
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;
}
if (!HgfsPacketSend(packetOut, replySize, session, 0)) {
goto error;
}
+
return 0;
error:
free(packetOut);
+
return status;
}
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;
}
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 {
* 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);
if (!HgfsServerPlatformInit()) {
LOG(4, ("Could not initialize server platform specific \n"));
+
return FALSE;
}
*callbackTable = &hgfsServerSessionCBTable;
+
return TRUE;
}
/*
* 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)) {
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;
/* 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;
/* Give our session a reference to hold while we are open. */
HgfsServerSessionGet(session);
*sessionData = session;
+
return TRUE;
}
ASSERT(session->nodeArray);
ASSERT(session->searchArray);
-
SyncMutex_Lock(&session->nodeArrayLock);
LOG(4, ("%s: exiting.\n", __FUNCTION__));
* 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;
}
* 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,
}
HgfsServerSessionPut(session);
+
return result;
}
* 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;
}
* 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;
* 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;
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;
}
* 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;
}
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;
}
*/
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;
}
}
/* 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;
}
/*
* 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;
}
/*
* See if we are dealing with a "root" share or regular share
*/
+
if (strlen(sharePath) == 0) {
size_t prefixLen;
* 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;
}
/* 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;
}
/*
* 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;
}
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;
}
* 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;
}
* 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;
* 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;
}
}
/* 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;
}
/* 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;
}
}
}
- 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;
}
len = CPName_GetComponent(cpName, inEnd, &next);
ASSERT(len > 0);
+
return (next == inEnd);
}
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);
state = initName();
if (!state) {
- LOG(4, ("HgfsServerGetDents: Couldn't init state\n"));
+ LOG(4, ("%s: Couldn't init state\n", __FUNCTION__));
goto error_free;
}
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;
}
* 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;
}
}
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;
/* 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;
}
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;
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:
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;
}
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;
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;
}
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;
search->numDents = result;
*handle = HgfsSearch2SearchHandle(search);
+
out:
SyncMutex_Unlock(&session->searchArrayLock);
+
return status;
}
HgfsSessionInfo *session) // IN: Session info
{
Bool removed = FALSE;
+
SyncMutex_Lock(&session->nodeArrayLock);
removed = HgfsRemoveFromCacheInternal(handle, session);
SyncMutex_Unlock(&session->nodeArrayLock);
*
* 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
/* 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. */
}
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;
}
HgfsSessionInfo *session) // IN: Session info
{
Bool added = FALSE;
+
SyncMutex_Lock(&session->nodeArrayLock);
added = HgfsAddToCacheInternal(handle, session);
SyncMutex_Unlock(&session->nodeArrayLock);
+
return added;
}
/*
* 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;
}
}
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);
{
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. */
* 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;
}
* 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;
if (!(requestV2->mask & HGFS_OPEN_VALID_FILE_NAME)) {
/* We do not support open requests without a valid file name. */
+
return FALSE;
}
* 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;
* 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;
}
case HGFS_OP_OPEN:
{
- HgfsRequestOpen *requestV1 =
- (HgfsRequestOpen *)packetIn;
+ HgfsRequestOpen *requestV1 = (HgfsRequestOpen *)packetIn;
/* Enforced by the dispatch function. */
ASSERT(packetSize >= sizeof *requestV1);
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;
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));
* 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;
* 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;
* 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;
* 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;
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;
((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;
}
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));
* 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;
* 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;
}
*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;
} else {
if (newName->length > extra) {
/* The input packet is smaller than the request */
+
return FALSE;
}
* 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;
* 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;
}
+ *cpOldNameLen);
if (newName->length > extra) {
/* The input packet is smaller than the request */
+
return FALSE;
}
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;
}
* 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;
}
}
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;
}
* 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;
* 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;
}
* 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;
* 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;
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;
attrInfo->userId = 0;
attrInfo->groupId = 0;
attrInfo->hostFileId = 0;
+
return TRUE;
}
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?
* 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,
* 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;
}
}
default:
- LOG(4, ("HgfsPackGetattrReply: Invalid GetAttr op.\n"));
+ LOG(4, ("%s: Invalid GetAttr op.\n", __FUNCTION__));
+
return FALSE;
}
*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;
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);
* 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;
}
if (utf8NameLen == 0) {
/* No entry. */
+
return TRUE;
}
* 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;
}
if (utf8NameLen == 0) {
/* No entry. */
+
return TRUE;
}
* 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;
}
if (utf8NameLen == 0) {
/* No entry. */
+
return TRUE;
}
memcpy(reply->fileName.name, utf8Name, utf8NameLen);
}
default: {
- LOG(4, ("HgfsPackSearchReadReply: Invalid SearchRead Op."));
+ LOG(4, ("%s: Invalid SearchRead Op.", __FUNCTION__));
+
return FALSE;
}
}
* 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;
if (requestV3->fileName.length > extra) {
/* The input packet is smaller than the request. */
+
return FALSE;
}
/* It is now safe to read the file name. */
*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;
}
* 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;
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:
if (requestV1->fileName.length > extra) {
/* The input packet is smaller than the request. */
+
return FALSE;
}
*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;
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:
}
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;
}
if (!(requestV3->mask & HGFS_CREATE_DIR_VALID_FILE_NAME)) {
/* We do not support requests without a valid file name. */
+
return FALSE;
}
* 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;
}
* 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;
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:
if (!(requestV2->mask & HGFS_CREATE_DIR_VALID_FILE_NAME)) {
/* We do not support requests without a valid file name. */
+
return FALSE;
}
* 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;
}
* 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;
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;
}
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;
}
*
* 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:
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);
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) {
* 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) {
level--;
currentPosition += HGFS_PARENT_DIR_LEN;
}
- memcpy(currentPosition, relativeTarget, strlen(relativeTarget) + sizeof '\0');
+ memcpy(currentPosition, relativeTarget, strlen(relativeTarget) +
+ sizeof '\0');
}
+
return result;
}
*
* 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.
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));
}
* is double checked in HgfsAckOplockBreak, so we'd be safe from a garbage
* value.
*/
+
HgfsAckOplockBreak(lockData, reply->serverLock);
}
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,
* 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;
}
* 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;
}
* 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);
}
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];
}
HgfsDumpAllNodes();
- printf("TestNodeFreeList: end <<<<<<<<<<<<<<<<<<<<<<<<<< \n");
+ printf("%s: end <<<<<<<<<<<<<<<<<<<<<<<<<< \n", __FUNCTION__);
}
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];
}
HgfsDumpAllSearches();
- printf("TestSearchFreeList: end <<<<<<<<<<<<<<<<<<<<<<<<<< \n");
+ printf("%s: end <<<<<<<<<<<<<<<<<<<<<<<<<< \n", __FUNCTION__);
}
#endif
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);
/*
* 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;
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;
}
* the acknowledgement, and firing the platform-specific acknowledgement
* function (where we'll downgrade the lease).
*/
+
lockData = malloc(sizeof *lockData);
if (lockData) {
lockData->fileDesc = fd;
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:
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;
}
}
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;
}
{
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;
}
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;
}
* 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;
}
* 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;
}
* 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;
* 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);
/*
*
* 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;
* 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;
}
*fd = newFd;
}
free(node.utf8Name);
+
return status;
}
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;
/* 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;
*
* 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;
}
* 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
* 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.
* (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;
}
* 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;
if (resolvedRef != NULL) {
CFRelease(resolvedRef);
}
+
return status;
#endif
}
/*
* 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;
}
* 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);
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;
}
} else {
*convertedFileNameLength = strlen(fileName);
}
+
return 0;
}
* 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;
nameStatus = HGFS_NAME_STATUS_FAILURE;
break;
}
+
return nameStatus;
}
} else {
*convertedFileNameLength = fileNameLength;
}
+
return nameStatus;
}
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,
&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;
}
* 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
* not have read the entire link. If that happens, just return
* "out of memory".
*/
+
status = error ? error : ENOMEM;
goto exit;
}
*
* 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;
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__));
}
}
}
* (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;
}
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;
}
* 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);
*/
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;
}
* 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;
}
exit:
free(fileName);
+
return status;
}
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__
!= (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;
* 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 */
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;
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;
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;
}
/* 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;
* 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;
}
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));
}
}
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
*/
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;
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;
}
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;
}
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;
* 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;
}
* 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));
}
}
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
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;
}
exit_free:
free(localName);
+
exit:
return status;
}
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;
}
* 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;
* 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
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;
}
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)));
}
* 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++) {
/* 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;
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) ?
* 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;
}
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;
}
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);
* 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);
}
* 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;
}
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;
}
* 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
{
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;
return 0;
error:
- if (!HgfsRemoveFromCache(file, session)) {
- LOG(4, ("HgfsServerRead: Could not remove the node from cache.\n"));
- }
free(packetOut);
return status;
}
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) ?
&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;
}
* 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;
}
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;
}
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 */
* 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;
}
/* 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;
* 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,
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;
}
* 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;
}
exit:
free(packetOut);
+
return status;
}
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;
}
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;
}
}
* 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;
* (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);
* 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);
}
* 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__));
}
}
* 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;
* The POSIX implementation of HgfsSearchOpen could not have created
* this kind of search.
*/
+
NOT_IMPLEMENTED();
break;
default:
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
* 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;
}
/* 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)) {
!HgfsPacketSend(packetOut, packetOutSize, session, 0)) {
free(packetOut);
}
+
return status;
}
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;
}
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);
* 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:
* 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;
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;
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;
}
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;
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);
}
* 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;
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);
* 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)) {
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)) {
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;
}
if (!HgfsPacketSend(packetOut, packetOutSize, session, 0)) {
free(packetOut);
}
+
return 0;
}
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;
}
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;
}
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;
}
* 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;
}
* 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)) {
* 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;
}
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;
* 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;
}
/* 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:
/*
* 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,
* 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;
* 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;
* The above check ignores '.' and '..' so we do not include them in
* the share count here.
*/
+
shares++;
/*
* 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);
}
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;
}
* 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) {
}
}
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;
}
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));
* targetName starts after symlinkName + the variable length array
* in symlinkName.
*/
+
targetNameP = (HgfsFileNameV3 *)(symlinkName + 1 + symlinkNameLength);
targetName = targetNameP->name;
targetNameLength = targetNameP->length;
* 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;
}
* 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);
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;
}
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? */
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;
}
session, 0)) {
goto exit;
}
+
return status;
exit:
free(packetOut);
+
return status;
}
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
* access to entire host) or
* - fileName and sharePath are same.
*/
+
if (fileNameLength == 0 ||
sharePathLength == 0 ||
Str_Strcmp(sharePath, fileName) == 0) {
/* 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));
}
}
* 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. */
exit:
free(resolvedFileDirPath);
free(fileDirName);
+
return nameStatus;
}
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;
/* 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. */
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;
}
*
* 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.
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 {
DynBuf *imageData) // OUT
{
- ImagePngWriteOptions options;
-
- options.zlibCompressLevel = -1;
- options.stripAlphaChannel = TRUE;
-
- return ImageUtil_ConstructPNGBufferEx(image, &options, imageData);
+ return ImageUtil_ConstructPNGBufferEx(image, NULL, imageData);
}
*/
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;
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;
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
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
/* 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);
}
#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;
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);
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
#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"
/*
* delete item from the list
*/
-#define LIST_DEL DelListItem
+#define LIST_DEL DelListItem
/*
* link two lists together
/*
* Get the list size.
*/
-#define LIST_SIZE GetListSize
+#define LIST_SIZE GetListSize
/*
* LIST_SCAN_FROM scans the list from "from" up until "until".
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)
* 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).
*
* 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).
*
* list header itself.
* Assumes neither p nor headp is null and p is a member of *headp.
*
- * Result
+ * Result:
* None
*
* Side effects:
* 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:
head->prev = p;
}
}
-
+
/*
*----------------------------------------------------------------------
* 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:
QueueListItem(p, headp);
*headp = p;
}
-
+
/*
*----------------------------------------------------------------------
* No checking is done. It is assumed that l1 and l2 are two
* distinct lists.
*
- * Result
+ * Result:
* A list { l1 l2 }.
*
* Side effects:
* 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:
*/
static INLINE int
-GetListSize(ListItem *head) // IN
+GetListSize(ListItem *head) // IN
{
ListItem *li;
int ret = 0;
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,
#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)
} 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_ */
/* Local UI as DnD target. */
sigc::signal<void, DND_DROPEFFECT> updateFeedbackChanged;
sigc::signal<void, bool, int, int> updateDetWndChanged;
- sigc::signal<void, bool, uint32> updateUnityDetWndChanged;
+ sigc::signal<void, bool, uint32, bool> updateUnityDetWndChanged;
+ sigc::signal<void, int32, int32> targetPrivateDropChanged;
sigc::signal<void> reset;
sigc::signal<void> disable;
sigc::signal<void> enable;
sigc::signal<void, int, int> updateMouseChanged;
+ sigc::signal<void> moveDetWndToMousePos;
/* Guest cancel signals. */
sigc::signal<void> ghCancel;
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;
CP_HG_START_FILE_COPY,
// Add future commands here.
+ CP_GH_TRANSPORT_TEST,
CP_MAX,
} CopyPasteCommand;
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
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);
EXTERN char *File_ExpandAndCheckDir(const char *dirName);
+EXTERN Bool File_SupportsPrealloc(const char *file);
+
#ifdef __cplusplus
} // extern "C" {
#endif
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 {
{ 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
#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)
#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) | \
#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"
#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"
#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"
HashTable_Delete(HashTable *hashTable,
const char *keyStr);
+Bool
+HashTable_LookupAndDelete(HashTable *hashTable,
+ const char *keyStr,
+ void **clientData);
+
void
HashTable_Clear(HashTable *ht);
#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)
/*
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;
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,
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_
} ImageInfo;
typedef struct {
- int zlibCompressLevel;
+ int zlibCompressLevel; // Set to -1 for the default compression level.
Bool stripAlphaChannel;
} ImagePngWriteOptions;
LOGLEVEL_VAR(pci_vmxnet3), \
LOGLEVEL_VAR(vcpuhotplug), \
LOGLEVEL_VAR(heci), \
+ LOGLEVEL_VAR(vmiopluginlib), \
\
/* user/disk */ \
LOGLEVEL_VAR(aioMgr), \
LOGLEVEL_VAR(pvfslib), \
LOGLEVEL_VAR(brtalk), /* macWireless and wpa_supplicant */ \
LOGLEVEL_VAR(button), \
+ LOGLEVEL_VAR(util), \
LOGLEVEL_VAR(largepage),
LOGLEVEL_EXTENSION_DECLARE(LOGLEVEL_USER);
#define INCLUDE_ALLOW_VMKERNEL
#include "includeCheck.h"
+#include "vm_basic_defs.h"
+
#ifndef VMKERNEL
#include <string.h>
#endif
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
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);
#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
# 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);
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
Bool System_KillDesktopSwitchThread(void);
Bool System_DisableAndKillScreenSaver(void);
DWORD System_GetServiceState(LPCWSTR szServiceName);
+DblLnkLst_Links *System_GetMonitors();
#endif
*/
/*
- * Breakdown of components involved in Unity (as of change 748058 on
- * 2008/10/23):
+ * Breakdown of components involved in Unity:
*
* 1) Unity desktop target
*
* 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
*
* -----------------------------------------------------------------------
*
- * [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.
#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"
/* @} */
#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"
/* @} */
* 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.
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. */
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.
@{
@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
@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,
@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
<nul> := '\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.
@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
<tt>"count handle"</tt>
\li @c count Number of items in the sub-tree.
@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.
@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
@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
@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 <work_areas>
+ @code
+ UNITY_RPC_DESKTOP_WORK_AREA_SET <work_areas>
@endcode
@param[in] <work_areas> list of work areas
@verbatim
-<work_areas> := <count>{ ',' x y width height }
-<count> := number of work areas to follow, 0 or greater
+<work_areas> := <count>{ ',' x y width height }
+<count> := number of work areas to follow, 0 or greater
@endverbatim
@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
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 <cell> {<cell>} <current>
+ @param[in] configuration <cell> {<cell>} <current>
@verbatim
-<cell> := '{'row,col'}'
-<current> := currently active cell
+<cell> := '{'row,col'}'
+<current> := 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: <tt>{1,1} {1,2} {2,1} {2,2} 1</tt> specifies a 2 x 2 virtual
desktop where the upper right <tt>{1,2}</tt> 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.
@}
*/
@{
@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
@}
*/
*
* Each string in the list has one of the following formats:
*
- * @li <tt>"add" UnityWindowId</tt> @par
+ * @li <tt>"add" UnityWindowId arguments</tt> @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 <tt>"remove" UnityWindowId</tt> @par
* The window identified by @a UnityWindowId has been removed. Get rid
union {
struct {
UnityWindowId id;
+ DynBuf windowPathUtf8;
+ DynBuf execPathUtf8;
} addWindow;
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];
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;
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,
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
*/
#else
# define DIRSEPS "/"
# define DIRSEPC '/'
+# define VALID_DIRSEPS DIRSEPS
#endif
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,
#define _VIX_COMMANDS_H_
#include "vm_version.h"
-#include "vix.h"
+#include "vixOpenSource.h"
/*
* These describe the format of the message objects.
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,
};
#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.
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.
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,
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,
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,
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
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);
/*
#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
#endif
#endif // _WIN32
+#ifdef HOSTED_LG_PG
+#define hosted_lg_pg 1
+#else
+#define hosted_lg_pg 0
+#endif
+
/*
***********************************************************************
* STRUCT_OFFSET_CHECK -- */ /**
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
#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
#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"
#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"
#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 */
#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)
/*
#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"
/*
* 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"
#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"
#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"
/*
* @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)
#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. */
* 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.
* 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;
#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];
#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) \
#define CPUID_UNCACHED_LEVELS \
CPUIDLEVEL(FALSE, 4, 4) \
- CPUIDLEVEL(FALSE, 5, 5) \
CPUIDLEVEL(FALSE, 6, 6) \
CPUIDLEVEL(FALSE, A, 0xA) \
CPUIDLEVEL(FALSE, 86, 0x80000006) \
#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"
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) \
/* 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) \
#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.
}
-/*
- *----------------------------------------------------------------------
- *
- * 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
return 1 + CPUID_INTEL_CORE_COUNT(v);
}
+
static INLINE uint32
CPUID_AMDCoresPerPackage(uint32 v) /* %ecx from CPUID with %eax=0x80000008. */
{
return 1 + CPUID_AMD_CORE_COUNT(v);
}
+
/*
* Hypervisor CPUID space is 0x400000XX.
*/
}
-/* 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 <op> 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
/*
- *----------------------------------------------------------------------
- *
- * 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
/*
}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * Escape_StrChr --
+ *
+ * Find the first occurence of c in bufIn that is not preceded by
+ * escByte.
+ *
+ * XXX Doesn't handle recursive escaping, so <escByte><escByte><c>
+ * will skip that occurence of <c>
+ *
+ * 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);
+}
+
+
/*
*----------------------------------------------------------------------------
*
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;
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);
#include <stdio.h>
#include <stdlib.h>
+#include <unistd.h>
#include <string.h>
-#include <errno.h>
-#include <sys/time.h>
+#include <ctype.h>
#include <sys/utsname.h>
+#include <netdb.h>
#include <fcntl.h>
+#include <limits.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <pwd.h>
+#include <sys/resource.h>
#if defined(sun)
#include <sys/systeminfo.h>
#endif
-#include <unistd.h>
-#include <sys/types.h>
#include <sys/socket.h>
-#include <sys/stat.h>
#if defined(__FreeBSD__) || defined(__APPLE__)
# include <sys/sysctl.h>
#endif
+#if defined(__APPLE__)
+#define SYS_NMLN _SYS_NAMELEN
+#include <assert.h>
+#include <CoreServices/CoreServices.h>
+#include <mach-o/dyld.h>
+#include <mach/host_info.h>
+#include <mach/mach_host.h>
+#include <mach/mach_init.h>
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#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 <sys/vfs.h>
+#endif
+#if !defined(sun) && (!defined(USING_AUTOCONF) || (defined(HAVE_SYS_IO_H) && defined(HAVE_SYS_SYSINFO_H)))
+#include <sys/io.h>
+#include <sys/sysinfo.h>
+#ifndef HAVE_SYSINFO
+#define HAVE_SYSINFO 1
+#endif
+#endif
+#endif
+
+#if defined(__APPLE__) || defined(__FreeBSD__)
+#include <paths.h>
+#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"
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;
}
if (distroLower == NULL) {
Warning("%s: could not allocate memory\n", __FUNCTION__);
+
return;
}
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);
}
}
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")) {
} 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")) {
if ((fd = open(filename, O_RDONLY)) < 0) {
Warning("%s: could not open file%s: %d\n", __FUNCTION__, filename, errno);
+
return FALSE;
}
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;
}
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;
}
}
/*
- * 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);
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) {
if (strlen(distro) + strlen(osNameFull) + 2 > outBufFullLen) {
Warning("%s: Error: buffer too small\n", __FUNCTION__);
+
return FALSE;
}
if (strlen(distroShort) + 1 > outBufLen) {
Warning("%s: Error: buffer too small\n", __FUNCTION__);
+
return FALSE;
}
}
if (nameLen + releaseLen + 1 > outBufLen) {
- Warning("GuestInfoGetOSName: Error: buffer too small\n");
+ Warning("%s: Error: buffer too small\n", __FUNCTION__);
+
return FALSE;
}
}
if (nameLen + releaseLen + 1 > outBufLen) {
- Warning("GuestInfoGetOSName: Error: buffer too small\n");
+ Warning("%s: Error: buffer too small\n", __FUNCTION__);
+
return FALSE;
}
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;
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;
+ }
+}
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)
/* 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;
}
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;
}
/* 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;
}
/* 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;
}
/* 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
}
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;
}
}
"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;
}
"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;
}
"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;
}
DWORD error;
if (!winspoolDll) {
- Log("Printer_Cleanup: Printer library not loaded.\n");
+ Log("%s: Printer library not loaded.\n", __FUNCTION__);
+
return FALSE;
}
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
*/
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,
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,
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,
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,
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,
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,
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) {
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) {
*/
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:
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;
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,
uint32 greenShift1, uint32 greenShift2,
uint32 blueShift1, uint32 blueShift2)
{
- uint16 *srcptr;
+ const uint16 *srcptr;
uint8 *dstptr;
int i, j, k;
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,
uint32 greenShift1, uint32 greenShift2,
uint32 blueShift1, uint32 blueShift2)
{
- uint16 *srcptr;
+ const uint16 *srcptr;
uint32 *dstptr;
int i, j;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
#include <stdlib.h>
#include <string.h>
+#include <limits.h>
#include "region.h"
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);
}
* 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
* 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
* 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
* 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
- *
*-----------------------------------------------------------------------------
*/
* 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
*
* 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
* 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
* 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
* 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
static INLINE Bool SyncWaitQWakeUpNamed(SyncWaitQ *that);
static INLINE Bool SyncWaitQWakeUpAnon(SyncWaitQ *that);
-static INLINE char *SyncWaitQMakeName(const char *path, uint64 seq);
#if __APPLE__
*/
static int
-SyncWaitQInit(SyncWaitQ *that) // IN
+SyncWaitQInit(SyncWaitQ *that) // IN:
{
if (UNLIKELY(Atomic_ReadInt(&workaround) == WORKAROUND_UNKNOWN)) {
struct utsname u;
* 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
}
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;
}
*/
static void
-SyncWaitQUnlock(SyncWaitQ *that) // IN
+SyncWaitQUnlock(SyncWaitQ *that) // IN:
{
ASSERT(Atomic_ReadInt(&workaround) != WORKAROUND_UNKNOWN);
+
if (Atomic_ReadInt(&workaround) == WORKAROUND_YES) {
int result;
*/
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:
*/
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]);
}
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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);
+}
+
+
/*
*----------------------------------------------------------------------
*
*/
void
-SyncWaitQ_Destroy(SyncWaitQ *that)
+SyncWaitQ_Destroy(SyncWaitQ *that) // IN:
{
if (!that->initialized) {
return;
/*
* Named
*/
+
uint64 seq;
char *name;
* 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;
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) {
}
}
- // 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) {
* 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]);
Bool
SyncWaitQ_Remove(SyncWaitQ *that, // Unused
- PollDevHandle handle) // IN
+ PollDevHandle handle) // IN:
{
ASSERT(that);
if (!that->initialized) {
*/
Bool
-SyncWaitQ_WakeUp(SyncWaitQ *that) // IN
+SyncWaitQ_WakeUp(SyncWaitQ *that) // IN:
{
ASSERT(that);
ASSERT(that->initialized);
*/
static Bool
-SyncWaitQWakeUpAnon(SyncWaitQ *that) // IN
+SyncWaitQWakeUpAnon(SyncWaitQ *that) // IN:
{
HandlesAsI64 rwHandles, wakeupHandles;
int ret;
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);
*/
static Bool
-SyncWaitQWakeUpNamed(SyncWaitQ *that) // IN
+SyncWaitQWakeUpNamed(SyncWaitQ *that) // IN:
{
uint64 seq;
char *name;
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);
* 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;
}
* 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);
-}
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)
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.
* 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) {
*
* 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.
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;
}
}
{
UnityWindowId window;
- DynBuf *buf = &gTcloUpdate;
+ DynBuf windowPathUtf8;
+ DynBuf execPathUtf8;
+
unsigned int index = 0;
Bool ret = TRUE;
* 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;
}
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;
*
* 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.
*
*----------------------------------------------------------------------------
*/
void UnityPlatformRestoreSystemSettings(UnityPlatform *up);
Bool UnityPlatformGetWindowPath(UnityPlatform *up,
UnityWindowId window,
- DynBuf *buf);
+ DynBuf *windowPathUtf8,
+ DynBuf *execPathUtf8);
Bool UnityPlatformGetNativeWindowPath(UnityPlatform *up,
UnityWindowId window,
DynBuf *buf);
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,
}
}
- /*
- * 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;
return;
}
+ /*
+ * Caller should've called Unity_Exit first.
+ */
+ ASSERT(!up->isRunning);
+ ASSERT(!up->unityDisplayWatchID);
+
if (up->specialWindows) {
HashTable_Free(up->specialWindows);
up->specialWindows = NULL;
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;
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);
UnityPlatformStartHelperThreads(UnityPlatform *up) // IN
{
ASSERT(up);
+ ASSERT(!up->unityDisplayWatchID);
XSync(up->display, TRUE);
up->rootWindows = UnityPlatformMakeRootWindowsObject(up);
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;
}
}
-#ifdef GTK2
-
-
/*
*-----------------------------------------------------------------------------
*
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
/*
{
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",
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);
} else
#endif
{
- if (up->desktopInfo.currentDesktop == upw->desktopNumber) {
+ if (upw->desktopNumber == up->desktopInfo.currentDesktop ||
+ upw->desktopNumber == -1) {
UnityRect actualRect;
Window actualWindow;
argv = inArgv;
-#ifdef GTK2
while (argc && AppUtil_AppIsSkippable(argv[0])) {
argv++;
argc--;
return FALSE;
}
}
-#endif
/*
* If the program in question takes any arguments, they will be appended as URI
* 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
* from the same application are really associated with separate
* applications.)
*
- * I.e., <windowUri><nul><execUri><nul>
- *
- * 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.
*
*----------------------------------------------------------------------------
*/
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;
" 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);
#include <unistd.h>
#include <stdlib.h>
+
+/*
+ * 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.
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);
{
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);
}
*/
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;
*/
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
{
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:
miRegionDestroy(info->region);
}
DynBuf_Destroy(&info->titleUtf8);
+ DynBuf_Destroy(&info->windowPathUtf8);
+ DynBuf_Destroy(&info->execPathUtf8);
free(info);
}
}
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;
*
*/
-#include <stdlib.h>
#include <stdio.h>
+#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <paths.h>
#endif
-#ifndef _PATH_DEVNULL
+#if !defined(_PATH_DEVNULL)
#define _PATH_DEVNULL "/dev/null"
#endif
// 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__ */
-}
-
-
/*
*-----------------------------------------------------------------------------
*
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;
SyncMutex_Unlock(lck);
return newTime;
+#endif
}
/*
Hostinfo_SystemUpTime(void)
{
#if defined(__APPLE__)
- return HostinfoMacAbsTimeNS() / 1000ULL;
+ return Hostinfo_RawSystemTimerUS();
#elif defined(VMX86_SERVER)
uint64 uptime;
VMK_ReturnStatus status;
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__)
/*
*----------------------------------------------------------------------
*
*----------------------------------------------------------------------
*/
-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];
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;
}
* Kernel versions < 2.3.23. Those kernels used a smaller sysinfo
* structure, whose last meaningful field is 'procs' --hpreg
*/
+
si.mem_unit = 1;
}
*
* 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
*/
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;
* 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 {
*
* 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
*/
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;
*
* 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
*/
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;
*/
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;
* 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;
*/
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;
#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;
-}
-
/*
*-----------------------------------------------------------------------------
*
*/
Unicode
-Hostinfo_GetModulePath(uint32 priv)
+Hostinfo_GetModulePath(uint32 priv) // IN:
{
Unicode path;
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]);
- }
- }
-}
#ifdef UTIL_BACKTRACE_USE_UNWIND
#include <unwind.h>
+#define MAX_SKIPPED_FRAMES 10
+
struct UtilBacktraceFromPointerData {
uintptr_t basePtr;
Util_OutputFunc outFunc;
void *outFuncData;
unsigned int frameNr;
+ unsigned int skippedFrames;
};
struct UtilBacktraceToBufferData {
/*
* 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.
_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;
}
/*
* 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.
}
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;
}
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)
data.outFunc = outFunc;
data.outFuncData = outFuncData;
data.frameNr = 0;
+ data.skippedFrames = 0;
_Unwind_Backtrace(UtilSymbolBacktraceFromPointerCallback, &data);
#endif
#include <unistd.h>
#include <errno.h>
#include <dirent.h>
+#include <ctype.h>
#if !__FreeBSD__ && !sun
# include <pwd.h>
#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() */
# 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
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;
}
#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;
}
* 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;
}
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;
}
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)
Bool impersonatingVMWareUser = FALSE;
void *userToken = NULL;
char *destPtr;
-#ifdef linux
char *endDestPtr;
+#if defined(_WIN32) || defined(linux)
VixCommandListFileSystemsRequest *lfReq = (VixCommandListFileSystemsRequest *) requestMsg;
+ const char *listFileSystemsFormatString = "<filesystem>"
+ "<name>%s</name>"
+ "<size>%"FMT64"u</size>"
+ "<freeSpace>%"FMT64"u</freeSpace>"
+ "<type>%s</type>"
+ "</filesystem>";
+#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;
destPtr = resultBuffer;
*destPtr = 0;
+ endDestPtr = resultBuffer + sizeof(resultBuffer);
err = VixToolsImpersonateUser(requestMsg, &userToken);
if (VIX_OK != err) {
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";
size = (uint64) statfsbuf.f_blocks * (uint64) statfsbuf.f_bsize;
freeSpace = (uint64) statfsbuf.f_bfree * (uint64) statfsbuf.f_bsize;
destPtr += Str_Sprintf(destPtr, endDestPtr - destPtr,
- "<filesystem>"
- "<name>%s</name>"
- "<size>%"FMT64"u</size>"
- "<freeSpace>%"FMT64"u</freeSpace>"
- "<type>%s</type>"
- "</filesystem>",
+ listFileSystemsFormatString,
MNTINFO_NAME(mnt),
size,
freeSpace,
#endif
abort:
+#if defined(_WIN32)
+ for (i = 0; i < numDrives; i++) {
+ Unicode_Free(driveList[i]);
+ }
+
+ free(driveList);
+#endif
+
if (impersonatingVMWareUser) {
VixToolsUnimpersonateUser(userToken);
}
#include "util.h"
#include "str.h"
#include "fileIO.h"
+#include "vmstdio.h"
#include "mntinfo.h"
#include "posix.h"
} 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
+
/*
*-----------------------------------------------------------------------------
*/
#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
{
#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
{
#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;
}
goto error;
}
+ WiperCollectDiskMajors();
WiperPartitionFilter(p, mnt);
(void) CLOSE_MNTFILE(fp);
goto error;
}
+ WiperCollectDiskMajors();
+
while (GETNEXT_MNTINFO(fp, mnt)) {
WiperPartition item;
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
-}
# 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
+
--- /dev/null
+# 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
+
goto exit;
}
- if (!File_IsFile(path)) {
+ if (!File_IsFile(path) || File_GetSizeByPath(path) == 0) {
goto exit;
}
/* 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;
/*
}
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.
*/
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.
* 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)) {
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;
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;
}
* 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;
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"
--- /dev/null
+#!/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
+
#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
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];
#include <linux/stddef.h> /* for NULL */
#include <net/sock.h>
-
/*
* 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
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_
/*
+ * 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 {
* 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
/*
*-----------------------------------------------------------------------------
}
-/*
- *-----------------------------------------------------------------------------
- *
- * 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);
-
/*
*-----------------------------------------------------------------------------
*
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;
return __VMCIQueue_Enqueue(produceQueue, consumeQueue, produceQSize,
(void *)iov, iovSize, VMCIMemcpyToQueueV);
}
-#endif
+#endif /* Systems that support struct iovec */
/*
return __VMCIQueue_Dequeue(produceQueue, consumeQueue, consumeQSize,
(void *)iov, iovSize, VMCIMemcpyFromQueueV, TRUE);
}
-#endif
+#endif /* Systems that support struct iovec */
/*
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_ */
#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
-}
-
-
/*
*-----------------------------------------------------------------------------
*
*/
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;
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);
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) {
sizeof *attach->consumeIoBuf);
}
}
+
return err;
-#else
+#else // 0 -- Instead just return FALSE
return FALSE;
-#endif
-#endif
+#endif // 0
+#endif // Linux version >= 2.6.0
}
*/
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)
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]);
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);
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;
"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;
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;
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;
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;
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;
#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);
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 \
#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 <asm/dma.h>
#include <asm/page.h>
#include <asm/uaccess.h>
+#include <linux/types.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/ip.h>
#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)
# 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
};
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"
/*
*----------------------------------------------------------------------------
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;
}
/* 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;
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;
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++) {
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;
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;
}
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;
+ }
}
}
}
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:
*----------------------------------------------------------------------------
*/
-static int
+int
vmxnet3_tq_xmit(struct sk_buff *skb,
struct vmxnet3_tx_queue *tq,
struct vmxnet3_adapter *adapter,
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));
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++;
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 */
}
/* 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;
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;
}
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);
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;
entries ++;
}
- compat_dev_kfree_skb_any(skb, FREE_WRITE);
+ vmxnet3_dev_kfree_skb_any(adapter, skb);
return entries;
}
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;
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);
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 */
}
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 */
}
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);
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) {
}
rq->stats.drop_total++;
- compat_dev_kfree_skb_irq(ctx->skb, FREE_WRITE);
+ vmxnet3_dev_kfree_skb_irq(adapter, ctx->skb);
ctx->skb = NULL;
}
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 */
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 {
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;
}
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) {
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;
}
}
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
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) {
vmxnet3_rq_destroy(&adapter->rx_queue, adapter);
vmxnet3_tq_destroy(&adapter->tx_queue, adapter);
queue_err:
+ vmxnet3_shm_close(adapter);
+shm_err:
return err;
}
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;
}
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;
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);
}
set_bit(VMXNET3_STATE_BIT_QUIESCED, &adapter->state);
+ devices_found++;
return 0;
err_register:
return 0;
}
+ vmxnet3_disable_all_intrs(adapter);
netif_device_detach(netdev);
netif_stop_queue(netdev);
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;
}
*/
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");
#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;
union {
struct sk_buff *skb;
struct page *page;
+ unsigned long shm_idx;
};
dma_addr_t dma_addr;
};
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 {
#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);
+
--- /dev/null
+/*********************************************************
+ * 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 <linux/moduleparam.h>
+
+#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 <asm/dma.h>
+#include <asm/page.h>
+#include <asm/uaccess.h>
+#include <linux/types.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/in.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+#include <asm/checksum.h>
+
+#include <linux/if_vlan.h>
+#include <linux/if_arp.h>
+#include <linux/inetdevice.h>
+
+#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;
+}
--- /dev/null
+/*********************************************************
+ * 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 <linux/miscdevice.h>
+
+/*
+ * 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
--- /dev/null
+/*********************************************************
+ * 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 <linux/ioctl.h>
+
+// 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
#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_ */
* 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;
}
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
}
}
+ if (!VSockAddr_SocketContextDgram(remoteAddr->svm_cid,
+ remoteAddr->svm_port)) {
+ err = -EINVAL;
+ goto out;
+ }
+
memcpy(&vsk->remoteAddr, remoteAddr, sizeof vsk->remoteAddr);
sock->state = SS_CONNECTED;
}
/* 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;
}
err = sock_intr_errno(timeout);
goto outWait;
} else if (timeout == 0) {
- err = -ETIMEDOUT;
+ err = -EAGAIN;
goto outWait;
}
* 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;
}
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.
*/
/*
*----------------------------------------------------------------------------
*
- * 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.
*/
Bool
-VSockAddr_SocketContext(uint32 cid) // IN
+VSockAddr_SocketContextStream(uint32 cid) // IN
{
uint32 i;
VMCIId nonSocketContexts[] = {
return TRUE;
}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockAddr_SocketContextDgram --
+ *
+ * Determines whether the provided <context id, resource id> 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;
+}
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_
NET_SG_MACH_ADDR,
NET_SG_PHYS_ADDR,
NET_SG_VIRT_ADDR,
- NET_SG_VMM_STACK_OFFSET,
} NetSG_AddrType;
typedef struct NetSG_Array {
# 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
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
{
PowerOpState *state = _state;
- g_assert(state->pid != INVALID_PID);
+ ASSERT(state->pid != INVALID_PID);
if (!ProcMgr_IsAsyncProcRunning(state->pid)) {
int exitcode;
{
PowerOpState *state = _state;
- g_assert(state->pid != INVALID_PID);
+ ASSERT(state->pid != INVALID_PID);
PowerOpsStateChangeDone(_state, status == 0);
g_spawn_close_pid(state->pid);
char *tmp;
dfltPath = GuestApp_GetInstallPath();
- g_assert(dfltPath != NULL);
+ ASSERT(dfltPath != NULL);
/*
* Before the switch to vmtoolsd, the config file was saved with
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;
ResolutionInfoType *resInfo = &resolutionInfo;
int resServerCap = 0;
- Debug("%s: enter\n", __FUNCTION__);
+Debug("%s: enter\n", __FUNCTION__);
if (set) {
if (!resInfo->initialized) {
return FALSE;
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);
#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
gboolean slewCorrection;
uint32 slewPercentCorrection;
gint timeSyncState;
- uint32 timeSyncPeriod; /* In milliseconds. */
+ uint32 timeSyncPeriod; /* In seconds. */
GSource *timer;
} TimeSyncData;
}
} else if (slewCorrection && timeLagCall) {
int64 slewDiff;
+ int64 timeSyncPeriodUS = data->timeSyncPeriod * 1000000;
/* Don't consider interruptLag during clock slewing. */
slewDiff = diff - interruptLag;
/* 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;
}
{
TimeSyncData *data = _data;
- g_assert(data != NULL);
+ ASSERT(data != NULL);
if (!TimeSyncDoSync(data->slewCorrection, FALSE, FALSE, data)) {
g_warning("Unable to synchronize time.\n");
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)
/*
* 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);
}
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;
* 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);
{ 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;
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);
g_source_destroy(gBackupState->keepAlive);
}
- free(gBackupState->volumes);
+ g_free(gBackupState->volumes);
+ g_free(gBackupState->snapshots);
free(gBackupState);
gBackupState = NULL;
}
VmBackupAsyncCallback(void *clientData)
{
g_debug("*** %s\n", __FUNCTION__);
- g_assert(gBackupState != NULL);
+ ASSERT(gBackupState != NULL);
g_source_unref(gBackupState->timerEvent);
gBackupState->timerEvent = NULL;
}
if (data->args[index] != '\0') {
- gBackupState->volumes = Util_SafeStrdup(data->args + index);
+ gBackupState->volumes = g_strndup(data->args + index, data->argsSize - index);
}
}
"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,
VmBackupOp *currentOp;
const char *currentOpName;
char *volumes;
- guint pollPeriod;
+ char *snapshots;
+ guint pollPeriod;
GSource *timerEvent;
GSource *keepAlive;
Bool (*callback)(struct VmBackupState *);
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
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@
}
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;
}
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);
/* 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);
* 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;
}
#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.
}
+/**
+ * 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
}
#ifdef USE_APPLOADER
- if (!LoadDependencies(path)) {
+ if (!LoadDependencies(path, FALSE)) {
g_warning("Loading of library dependencies for %s failed.\n", entry);
goto next;
}
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);
}
void
ToolsCore_UnloadPlugins(ToolsServiceState *state)
{
+ guint i;
GArray *pcaps = NULL;
if (state->plugins == NULL) {
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;
g_free(plugin);
}
+ g_array_free(state->providers, TRUE);
+ state->providers = NULL;
+
g_ptr_array_free(state->plugins, TRUE);
state->plugins = NULL;
}
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;
gchar *debugPlugin;
RpcDebugLibData *debugData;
ToolsAppCtx ctx;
+ GArray *providers;
} ToolsServiceState;
void
ToolsCore_Cleanup(ToolsServiceState *state);
+void
+ToolsCore_DumpPluginInfo(ToolsServiceState *state);
+
void
ToolsCore_DumpState(ToolsServiceState *state);
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)) {
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";
state->ctx.rpc = RpcChannel_NewBackdoorChannel(mainCtx);
app = ToolsCore_GetTcloName(state);
- g_assert(app != NULL);
+ ASSERT(app != NULL);
}
RpcChannel_Setup(state->ctx.rpc,
+
/*********************************************************
* Copyright (C) 2008 VMware, Inc. All rights reserved.
*
typedef int (*ToolboxCmdFunc)(char **argv, int argc);
-typedef void (*ToolboxHelpFunc)(char *progName);
+typedef void (*ToolboxHelpFunc)(const 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
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);
/*
* 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);
}
*/
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 <subcommand> [args]\n"
*/
static void
-ToolboxCmdHelp(char *progName)
+ToolboxCmdHelp(const char *progName)
{
printf("Usage: %s <command> [options] [subcommand]\n"
"Type \'%s help <command>\' 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);
*/
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 <subcommand>\n\n"
*/
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 <power|resume|suspend|shutdown> <subcomamnd> [args]\n\n"
+ "Usage: %s script <power|resume|suspend|shutdown> <subcommand> [args]\n\n"
"Subcommands:\n"
" enable: enable the given script and restore its path to the default\n"
" disable: disable the given script\n"
*/
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 <subcommand> [args]\n\n"
*/
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 <subcommand>\n\n"
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;
}
*
* 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.
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;
}
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;
}
*/
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;
}
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;
}
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;
}
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;
}
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
*/
exit(EXIT_FAILURE);
}
- if (argc < 2) {
- ToolboxCmdHelp(argv[0]);
- exit(EX_USAGE);
- }
-
/*
* Parse the command line optional 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;
}
* 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
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);
/*
*-----------------------------------------------------------------------------
*/
-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;
*/
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);
*/
int
-Script_GetDefault(char *apm) // IN: APM name
+Script_GetDefault(const char *apm) // IN: APM name
{
return GetConfEntry(apm, Default);
}
*/
int
-Script_GetCurrent(char *apm) // IN: apm function name
+Script_GetCurrent(const char *apm) // IN: apm function name
{
return GetConfEntry(apm, Current);
}
*/
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;
*/
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);
}
*/
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);
}
*/
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;
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;
+}
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");
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 "
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);
void
CopyPaste_Unregister(GtkWidget* mainWnd)
{
+ Debug("%s: enter\n", __FUNCTION__);
gtk_signal_disconnect_by_func(GTK_OBJECT(mainWnd),
GTK_SIGNAL_FUNC(CopyPasteSelectionReceivedCB),
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");
}
void
CopyPaste_OnReset(void)
{
+ Debug("%s: enter\n", __FUNCTION__);
if (gHGFCPFileTransferStatus == FCP_FILE_TRANSFERRING) {
File_DeleteDirectoryTree(gFileRoot);
if (DnD_BlockIsReady(&gBlockCtrl) &&
void
CopyPasteStateInit(void)
{
+ Debug("%s: enter\n", __FUNCTION__);
gHostClipboardBuf[0] = '\0';
gGuestSelPrimaryBuf[0] = '\0';
gGuestSelClipboardBuf[0] = '\0';
* 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);
}
}
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;
}
}
}
__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;
}
}
}
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);
+ }
+ }
}
: mClipboardEmpty(true),
mHGStagingDir(""),
mIsClipboardOwner(false),
- mClipTimePrev(0),
- mPrimTimePrev(0),
mHGGetFilesInitiated(false),
mFileTransferDone(false),
mBlockAdded(false),
*-----------------------------------------------------------------------------
*/
-void
+bool
CopyPasteUI::Init()
{
if (mInited) {
- return;
+ return true;
}
- mInited = true;
CPClipboard_Init(&mClipboard);
Gtk::TargetEntry gnome(FCP_TARGET_NAME_GNOME_COPIED_FILES);
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__);
sigc::mem_fun(this, &CopyPasteUI::GetLocalClipboard));
mCP.localGetFilesDoneChanged.connect(
sigc::mem_fun(this, &CopyPasteUI::GetLocalFilesDone));
+ mInited = true;
+ return true;
}
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<Gtk::Clipboard> refClipboard =
- Gtk::Clipboard::get(mGHSelection);
+ Glib::RefPtr<Gtk::Clipboard> 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<utf::string> targets = targetsArray;
- Glib::RefPtr<Gtk::Clipboard> 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;
/* Try to get image data from clipboard. */
Glib::RefPtr<Gdk::Pixbuf> 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);
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__);
+ }
+ }
}
}
-/*
- *----------------------------------------------------------------------
- *
- * 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<Gtk::Clipboard> 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<Gtk::Clipboard> 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);
- }
-}
-
-
/*
*-----------------------------------------------------------------------------
*
public:
CopyPasteUI();
virtual ~CopyPasteUI();
- void Init();
+ bool Init();
void VmxCopyPasteVersionChanged(struct RpcIn *rpcIn,
uint32 version);
void SetCopyPasteAllowed(bool isCopyPasteAllowed)
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. */
bool mIsClipboardOwner;
uint64 mClipTime;
uint64 mPrimTime;
- uint64 mClipTimePrev;
- uint64 mPrimTimePrev;
GdkAtom mGHSelection;
CPClipboard mClipboard;
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");
}
#include "cpName.h"
#include "debug.h"
#include "cpNameUtil.h"
+#include "hostinfo.h"
#include "rpcout.h"
#include "eventManager.h"
#include "unity.h"
: 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__);
}
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);
}
* 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);
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)
*/
m_detWnd->SetAttributes();
- m_detWndFull->SetAttributes();
#endif
SetTargetsAndCallbacks();
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.
*/
*/
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 */
/**
*
*/
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. */
/**
*/
void
-DnDUI::RemoteDragStartCB(const CPClipboard *clip, std::string stagingDir)
+DnDUI::CommonDragStartCB(const CPClipboard *clip, std::string stagingDir)
{
Glib::RefPtr<Gtk::TargetList> targets;
Gdk::DragAction actions;
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.
}
if (CPClipboard_ItemExists(&m_clipboard, CPFORMAT_FILECONTENTS)) {
- if (LocalPrepareFileContentsDrag()) {
+ if (WriteFileContentsToStagingDir()) {
targets->add(Glib::ustring(DRAG_TARGET_NAME_URI_LIST));
}
}
/* 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;
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<Gdk::DragContext> 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
*/
void
-DnDUI::GetLocalFilesDoneCB(bool success,
- std::vector<uint8> stagingDir)
+DnDUI::CommonSourceFileCopyDoneCB(bool success,
+ std::vector<uint8> 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) {
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);
}
}
*
* @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.
+ */
/**
*
* 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<Gdk::DragContext> &dc,
- int x,
- int y,
- guint time)
+DnDUI::GtkDestDragMotionCB(const Glib::RefPtr<Gdk::DragContext> &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;
}
return true;
}
+ m_dc = dc->gobj();
+
if (target != "") {
/*
* We give preference to the suggested action from the source, and prefer
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__);
/*
* 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__);
/**
*
- * 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<Gdk::DragContext> &dc, guint time)
+DnDUI::GtkDestDragLeaveCB(const Glib::RefPtr<Gdk::DragContext> &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<Gdk::DragContext>& 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<Gdk::DragContext> &dc,
- int x,
- int y,
- guint time)
+DnDUI::GtkSourceDragBeginCB(const Glib::RefPtr<Gdk::DragContext>& 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();
}
*/
void
-DnDUI::LocalDragDataGetCB(const Glib::RefPtr<Gdk::DragContext> &dc,
- Gtk::SelectionData& selection_data,
- guint info,
- guint time)
+DnDUI::GtkSourceDragDataGetCB(const Glib::RefPtr<Gdk::DragContext> &dc,
+ Gtk::SelectionData& selection_data,
+ guint info,
+ guint time)
{
size_t index = 0;
std::string str;
if (!m_inHGDrag) {
Debug("%s: not in drag, return\n", __FUNCTION__);
+ return;
}
if (target == DRAG_TARGET_NAME_URI_LIST &&
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__);
/* 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<Gdk::DragContext> &dc)
+DnDUI::GtkSourceDragEndCB(const Glib::RefPtr<Gdk::DragContext> &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. */
/**
*
*/
void
-DnDUI::LocalDragDataReceivedCB(const Glib::RefPtr<Gdk::DragContext> &dc,
- int x,
- int y,
- const Gtk::SelectionData& sd,
- guint info,
- guint time)
+DnDUI::GtkDestDragDataReceivedCB(const Glib::RefPtr<Gdk::DragContext> &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;
/*
* 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;
}
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<Gdk::DragContext> &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;
*/
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.
DynBuf_GetSize(&buf));
}
DynBuf_Destroy(&buf);
- return;
+ return true;
}
/* Try to get plain text. */
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. */
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;
}
*/
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);
}
* @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;
x = xCoord;
y = yCoord;
- Debug("%s: enter\n", __FUNCTION__);
- widget = GetDetWndAsWidget(false);
+ widget = GetDetWndAsWidget();
if (!widget) {
Debug("%s: unable to get widget\n", __FUNCTION__);
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) {
* 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);
}
/*
*/
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__,
* 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);
}
void
DnDUI::AddBlock()
{
+ Debug("%s: enter\n", __FUNCTION__);
if (m_blockAdded) {
Debug("%s: block already added\n", __FUNCTION__);
return;
switch(action) {
case Gdk::ACTION_COPY:
+ case Gdk::ACTION_DEFAULT:
effect = DROP_COPY;
break;
case Gdk::ACTION_MOVE:
effect = DROP_LINK;
break;
case Gdk::ACTION_PRIVATE:
- case Gdk::ACTION_DEFAULT:
case Gdk::ACTION_ASK:
default:
effect = DROP_UNKNOWN;
}
+/**
+ *
+ * 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));
+}
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<Gdk::DragContext> &dc, int x,
- int y, guint time);
- void LocalDragDataReceivedCB(const Glib::RefPtr<Gdk::DragContext> &dc,
- int x, int y, const Gtk::SelectionData &sd,
- guint info, guint time);
- void LocalGetSelection(const Gtk::SelectionData& sd);
- void LocalDragLeaveCB(const Glib::RefPtr<Gdk::DragContext> &dc, guint time);
- bool LocalDragDropCB(const Glib::RefPtr<Gdk::DragContext> &dc, int x, int y,
- guint time);
-
- void SourceFeedbackChangedCB(DND_DROPEFFECT effect, const Glib::RefPtr<Gdk::DragContext> dc);
-
- void LocalDragDataGetCB(
- const Glib::RefPtr<Gdk::DragContext>& context,
- Gtk::SelectionData& selection_data, guint info, guint time);
- void LocalDragEndCB(
- const Glib::RefPtr<Gdk::DragContext>& context);
- void LocalDragBeginCB(
- const Glib::RefPtr<Gdk::DragContext>& 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<uint8> 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<Gdk::DragContext> &dc,
+ int x, int y, const Gtk::SelectionData &sd,
+ guint info, guint time);
+ bool GtkDestDragDropCB(const Glib::RefPtr<Gdk::DragContext> &dc,
+ int x, int y, guint time);
+ void GtkDestDragLeaveCB(const Glib::RefPtr<Gdk::DragContext> &dc,
+ guint time);
+ bool GtkDestDragMotionCB(const Glib::RefPtr<Gdk::DragContext> &dc, int x,
+ int y, guint time);
/**
- * Called when GH is completed.
+ * Gtk+ Callbacks: Drag Source.
+ */
+ void GtkSourceDragBeginCB(const Glib::RefPtr<Gdk::DragContext>& context);
+ void GtkSourceDragDataGetCB(const Glib::RefPtr<Gdk::DragContext>& context,
+ Gtk::SelectionData& selection_data, guint info,
+ guint time);
+ void GtkSourceDragEndCB(const Glib::RefPtr<Gdk::DragContext>& 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<uint8> 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
* Constructor.
*/
-DragDetWnd::DragDetWnd()
+DragDetWnd::DragDetWnd() :
+ m_isVisible(false)
{
+#if defined(DETWNDDEBUG)
+ DebugSetAttributes();
+#endif
}
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)
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, " ");