diff options
Diffstat (limited to 'src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibGuestCtrl.cpp')
-rw-r--r-- | src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibGuestCtrl.cpp | 2214 |
1 files changed, 2214 insertions, 0 deletions
diff --git a/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibGuestCtrl.cpp b/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibGuestCtrl.cpp new file mode 100644 index 00000000..69c9df5b --- /dev/null +++ b/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibGuestCtrl.cpp @@ -0,0 +1,2214 @@ +/* $Id: VBoxGuestR3LibGuestCtrl.cpp $ */ +/** @file + * VBoxGuestR3Lib - Ring-3 Support Library for VirtualBox guest additions, guest control. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * 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, in version 3 of the + * License. + * + * 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, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <iprt/string.h> +#include <iprt/mem.h> +#include <iprt/assert.h> +#include <iprt/cpp/autores.h> +#include <iprt/stdarg.h> +#include <VBox/err.h> +#include <VBox/log.h> +#include <VBox/GuestHost/GuestControl.h> +#include <VBox/HostServices/GuestControlSvc.h> + +#ifndef RT_OS_WINDOWS +# include <signal.h> +# ifdef RT_OS_DARWIN +# include <pthread.h> +# define sigprocmask pthread_sigmask /* On xnu sigprocmask works on the process, not the calling thread as elsewhere. */ +# endif +#endif + +#include "VBoxGuestR3LibInternal.h" + +using namespace guestControl; + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +/** Set if GUEST_MSG_PEEK_WAIT and friends are supported. */ +static int g_fVbglR3GuestCtrlHavePeekGetCancel = -1; + + +/** + * Connects to the guest control service. + * + * @returns VBox status code + * @param pidClient Where to put The client ID on success. The client ID + * must be passed to all the other calls to the service. + */ +VBGLR3DECL(int) VbglR3GuestCtrlConnect(uint32_t *pidClient) +{ + return VbglR3HGCMConnect("VBoxGuestControlSvc", pidClient); +} + + +/** + * Disconnect from the guest control service. + * + * @returns VBox status code. + * @param idClient The client ID returned by VbglR3GuestCtrlConnect(). + */ +VBGLR3DECL(int) VbglR3GuestCtrlDisconnect(uint32_t idClient) +{ + return VbglR3HGCMDisconnect(idClient); +} + + +/** + * Waits until a new host message arrives. + * This will block until a message becomes available. + * + * @returns VBox status code. + * @param idClient The client ID returned by VbglR3GuestCtrlConnect(). + * @param pidMsg Where to store the message id. + * @param pcParameters Where to store the number of parameters which will + * be received in a second call to the host. + */ +static int vbglR3GuestCtrlMsgWaitFor(uint32_t idClient, uint32_t *pidMsg, uint32_t *pcParameters) +{ + AssertPtrReturn(pidMsg, VERR_INVALID_POINTER); + AssertPtrReturn(pcParameters, VERR_INVALID_POINTER); + + HGCMMsgWaitFor Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, + GUEST_MSG_WAIT, /* Tell the host we want our next message. */ + 2); /* Just peek for the next message! */ + VbglHGCMParmUInt32Set(&Msg.msg, 0); + VbglHGCMParmUInt32Set(&Msg.num_parms, 0); + + /* + * We should always get a VERR_TOO_MUCH_DATA response here, see + * guestControl::HostMessage::Peek() and its caller ClientState::SendReply(). + * We accept success too here, in case someone decide to make the protocol + * slightly more sane. + * + * Note! A really sane protocol design would have a separate call for getting + * info about a pending message (returning VINF_SUCCESS), and a separate + * one for retriving the actual message parameters. Not this weird + * stuff, to put it rather bluntly. + * + * Note! As a result of this weird design, we are not able to correctly + * retrieve message if we're interrupted by a signal, like SIGCHLD. + * Because IPRT wants to use waitpid(), we're forced to have a handler + * installed for SIGCHLD, so when working with child processes there + * will be signals in the air and we will get VERR_INTERRUPTED returns. + * The way HGCM handles interrupted calls is to silently (?) drop them + * as they complete (see VMMDev), so the server knows little about it + * and just goes on to the next message inline. + * + * So, as a "temporary" mesasure, we block SIGCHLD here while waiting, + * because it will otherwise be impossible do simple stuff like 'mkdir' + * on a mac os x guest, and probably most other unix guests. + */ +#ifdef RT_OS_WINDOWS + int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); +#else + sigset_t SigSet; + sigemptyset(&SigSet); + sigaddset(&SigSet, SIGCHLD); + sigprocmask(SIG_BLOCK, &SigSet, NULL); + int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); + sigprocmask(SIG_UNBLOCK, &SigSet, NULL); +#endif + if ( rc == VERR_TOO_MUCH_DATA + || RT_SUCCESS(rc)) + { + int rc2 = VbglHGCMParmUInt32Get(&Msg.msg, pidMsg); + if (RT_SUCCESS(rc2)) + { + rc2 = VbglHGCMParmUInt32Get(&Msg.num_parms, pcParameters); + if (RT_SUCCESS(rc2)) + { + /* Ok, so now we know what message type and how much parameters there are. */ + return rc; + } + } + rc = rc2; + } + *pidMsg = UINT32_MAX - 1; + *pcParameters = UINT32_MAX - 2; + return rc; +} + + +/** + * Determins the value of g_fVbglR3GuestCtrlHavePeekGetCancel. + * + * @returns true if supported, false if not. + * @param idClient The client ID to use for the testing. + */ +DECL_NO_INLINE(static, bool) vbglR3GuestCtrlDetectPeekGetCancelSupport(uint32_t idClient) +{ + /* + * Seems we get VINF_SUCCESS back from the host if we try unsupported + * guest control messages, so we need to supply some random message + * parameters and check that they change. + */ + uint32_t const idDummyMsg = UINT32_C(0x8350bdca); + uint32_t const cDummyParmeters = UINT32_C(0x7439604f); + uint32_t const cbDummyMask = UINT32_C(0xc0ffe000); + Assert(cDummyParmeters > VMMDEV_MAX_HGCM_PARMS); + + int rc; + struct + { + VBGLIOCHGCMCALL Hdr; + HGCMFunctionParameter idMsg; + HGCMFunctionParameter cParams; + HGCMFunctionParameter acbParams[14]; + } PeekCall; + Assert(RT_ELEMENTS(PeekCall.acbParams) + 2 < VMMDEV_MAX_HGCM_PARMS); + + do + { + memset(&PeekCall, 0xf6, sizeof(PeekCall)); + VBGL_HGCM_HDR_INIT(&PeekCall.Hdr, idClient, GUEST_MSG_PEEK_NOWAIT, 16); + VbglHGCMParmUInt32Set(&PeekCall.idMsg, idDummyMsg); + VbglHGCMParmUInt32Set(&PeekCall.cParams, cDummyParmeters); + for (uint32_t i = 0; i < RT_ELEMENTS(PeekCall.acbParams); i++) + VbglHGCMParmUInt32Set(&PeekCall.acbParams[i], i | cbDummyMask); + + rc = VbglR3HGCMCall(&PeekCall.Hdr, sizeof(PeekCall)); + } while (rc == VERR_INTERRUPTED); + + LogRel2(("vbglR3GuestCtrlDetectPeekGetCancelSupport: rc=%Rrc %#x %#x %#x %#x %#x %#x %#x %#x %#x %#x %#x %#x %#x %#x %#x %#x\n", + rc, PeekCall.idMsg.u.value32, PeekCall.cParams.u.value32, + PeekCall.acbParams[ 0].u.value32, PeekCall.acbParams[ 1].u.value32, + PeekCall.acbParams[ 2].u.value32, PeekCall.acbParams[ 3].u.value32, + PeekCall.acbParams[ 4].u.value32, PeekCall.acbParams[ 5].u.value32, + PeekCall.acbParams[ 6].u.value32, PeekCall.acbParams[ 7].u.value32, + PeekCall.acbParams[ 8].u.value32, PeekCall.acbParams[ 9].u.value32, + PeekCall.acbParams[10].u.value32, PeekCall.acbParams[11].u.value32, + PeekCall.acbParams[12].u.value32, PeekCall.acbParams[13].u.value32)); + + /* + * VERR_TRY_AGAIN is likely and easy. + */ + if ( rc == VERR_TRY_AGAIN + && PeekCall.idMsg.u.value32 == 0 + && PeekCall.cParams.u.value32 == 0 + && PeekCall.acbParams[0].u.value32 == 0 + && PeekCall.acbParams[1].u.value32 == 0 + && PeekCall.acbParams[2].u.value32 == 0 + && PeekCall.acbParams[3].u.value32 == 0) + { + g_fVbglR3GuestCtrlHavePeekGetCancel = 1; + LogRel(("vbglR3GuestCtrlDetectPeekGetCancelSupport: Supported (#1)\n")); + return true; + } + + /* + * VINF_SUCCESS is annoying but with 16 parameters we've got plenty to check. + */ + if ( rc == VINF_SUCCESS + && PeekCall.idMsg.u.value32 != idDummyMsg + && PeekCall.idMsg.u.value32 != 0 + && PeekCall.cParams.u.value32 <= VMMDEV_MAX_HGCM_PARMS) + { + for (uint32_t i = 0; i < RT_ELEMENTS(PeekCall.acbParams); i++) + if (PeekCall.acbParams[i].u.value32 != (i | cbDummyMask)) + { + g_fVbglR3GuestCtrlHavePeekGetCancel = 0; + LogRel(("vbglR3GuestCtrlDetectPeekGetCancelSupport: Not supported (#1)\n")); + return false; + } + g_fVbglR3GuestCtrlHavePeekGetCancel = 1; + LogRel(("vbglR3GuestCtrlDetectPeekGetCancelSupport: Supported (#2)\n")); + return true; + } + + /* + * Okay, pretty sure it's not supported then. + */ + LogRel(("vbglR3GuestCtrlDetectPeekGetCancelSupport: Not supported (#3)\n")); + g_fVbglR3GuestCtrlHavePeekGetCancel = 0; + return false; +} + + +/** + * Reads g_fVbglR3GuestCtrlHavePeekGetCancel and resolved -1. + * + * @returns true if supported, false if not. + * @param idClient The client ID to use for the testing. + */ +DECLINLINE(bool) vbglR3GuestCtrlSupportsPeekGetCancel(uint32_t idClient) +{ + int fState = g_fVbglR3GuestCtrlHavePeekGetCancel; + if (RT_LIKELY(fState != -1)) + return fState != 0; + return vbglR3GuestCtrlDetectPeekGetCancelSupport(idClient); +} + + +/** + * Figures which getter function to use to retrieve the message. + */ +DECLINLINE(uint32_t) vbglR3GuestCtrlGetMsgFunctionNo(uint32_t idClient) +{ + return vbglR3GuestCtrlSupportsPeekGetCancel(idClient) ? GUEST_MSG_GET : GUEST_MSG_WAIT; +} + + +/** + * Checks if the host supports the optimizes message and session functions. + * + * @returns true / false. + * @param idClient The client ID returned by VbglR3GuestCtrlConnect(). + * We may need to use this for checking. + * @since 6.0 + */ +VBGLR3DECL(bool) VbglR3GuestCtrlSupportsOptimizations(uint32_t idClient) +{ + return vbglR3GuestCtrlSupportsPeekGetCancel(idClient); +} + + +/** + * Make us the guest control master client. + * + * @returns VBox status code. + * @param idClient The client ID returned by VbglR3GuestCtrlConnect(). + */ +VBGLR3DECL(int) VbglR3GuestCtrlMakeMeMaster(uint32_t idClient) +{ + int rc; + do + { + VBGLIOCHGCMCALL Hdr; + VBGL_HGCM_HDR_INIT(&Hdr, idClient, GUEST_MSG_MAKE_ME_MASTER, 0); + rc = VbglR3HGCMCall(&Hdr, sizeof(Hdr)); + } while (rc == VERR_INTERRUPTED); + return rc; +} + + +/** + * Reports features to the host and retrieve host feature set. + * + * @returns VBox status code. + * @param idClient The client ID returned by VbglR3GuestCtrlConnect(). + * @param fGuestFeatures Features to report, VBOX_GUESTCTRL_GF_XXX. + * @param pfHostFeatures Where to store the features VBOX_GUESTCTRL_HF_XXX. + */ +VBGLR3DECL(int) VbglR3GuestCtrlReportFeatures(uint32_t idClient, uint64_t fGuestFeatures, uint64_t *pfHostFeatures) +{ + int rc; + do + { + struct + { + VBGLIOCHGCMCALL Hdr; + HGCMFunctionParameter f64Features0; + HGCMFunctionParameter f64Features1; + } Msg; + VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, GUEST_MSG_REPORT_FEATURES, 2); + VbglHGCMParmUInt64Set(&Msg.f64Features0, fGuestFeatures); + VbglHGCMParmUInt64Set(&Msg.f64Features1, VBOX_GUESTCTRL_GF_1_MUST_BE_ONE); + + rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg)); + if (RT_SUCCESS(rc)) + { + Assert(Msg.f64Features0.type == VMMDevHGCMParmType_64bit); + Assert(Msg.f64Features1.type == VMMDevHGCMParmType_64bit); + if (Msg.f64Features1.u.value64 & VBOX_GUESTCTRL_GF_1_MUST_BE_ONE) + rc = VERR_NOT_SUPPORTED; + else if (pfHostFeatures) + *pfHostFeatures = Msg.f64Features0.u.value64; + break; + } + } while (rc == VERR_INTERRUPTED); + return rc; + +} + + +/** + * Query the host features. + * + * @returns VBox status code. + * @param idClient The client ID returned by VbglR3GuestCtrlConnect(). + * @param pfHostFeatures Where to store the host feature, VBOX_GUESTCTRL_HF_XXX. + */ +VBGLR3DECL(int) VbglR3GuestCtrlQueryFeatures(uint32_t idClient, uint64_t *pfHostFeatures) +{ + int rc; + do + { + struct + { + VBGLIOCHGCMCALL Hdr; + HGCMFunctionParameter f64Features0; + HGCMFunctionParameter f64Features1; + } Msg; + VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, GUEST_MSG_QUERY_FEATURES, 2); + VbglHGCMParmUInt64Set(&Msg.f64Features0, 0); + VbglHGCMParmUInt64Set(&Msg.f64Features1, RT_BIT_64(63)); + + rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg)); + if (RT_SUCCESS(rc)) + { + Assert(Msg.f64Features0.type == VMMDevHGCMParmType_64bit); + Assert(Msg.f64Features1.type == VMMDevHGCMParmType_64bit); + if (Msg.f64Features1.u.value64 & RT_BIT_64(63)) + rc = VERR_NOT_SUPPORTED; + else if (pfHostFeatures) + *pfHostFeatures = Msg.f64Features0.u.value64; + break; + } + } while (rc == VERR_INTERRUPTED); + return rc; + +} + + +/** + * Peeks at the next host message, waiting for one to turn up. + * + * @returns VBox status code. + * @retval VERR_INTERRUPTED if interrupted. Does the necessary cleanup, so + * caller just have to repeat this call. + * @retval VERR_VM_RESTORED if the VM has been restored (idRestoreCheck). + * + * @param idClient The client ID returned by VbglR3GuestCtrlConnect(). + * @param pidMsg Where to store the message id. + * @param pcParameters Where to store the number of parameters which will + * be received in a second call to the host. + * @param pidRestoreCheck Pointer to the VbglR3GetSessionId() variable to use + * for the VM restore check. Optional. + * + * @note Restore check is only performed optimally with a 6.0 host. + */ +VBGLR3DECL(int) VbglR3GuestCtrlMsgPeekWait(uint32_t idClient, uint32_t *pidMsg, uint32_t *pcParameters, uint64_t *pidRestoreCheck) +{ + AssertPtrReturn(pidMsg, VERR_INVALID_POINTER); + AssertPtrReturn(pcParameters, VERR_INVALID_POINTER); + + int rc; + if (vbglR3GuestCtrlSupportsPeekGetCancel(idClient)) + { + struct + { + VBGLIOCHGCMCALL Hdr; + HGCMFunctionParameter idMsg; /* Doubles as restore check on input. */ + HGCMFunctionParameter cParameters; + } Msg; + VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, GUEST_MSG_PEEK_WAIT, 2); + VbglHGCMParmUInt64Set(&Msg.idMsg, pidRestoreCheck ? *pidRestoreCheck : 0); + VbglHGCMParmUInt32Set(&Msg.cParameters, 0); + rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg)); + LogRel2(("VbglR3GuestCtrlMsgPeekWait -> %Rrc\n", rc)); + if (RT_SUCCESS(rc)) + { + AssertMsgReturn( Msg.idMsg.type == VMMDevHGCMParmType_64bit + && Msg.cParameters.type == VMMDevHGCMParmType_32bit, + ("msg.type=%d num_parms.type=%d\n", Msg.idMsg.type, Msg.cParameters.type), + VERR_INTERNAL_ERROR_3); + + *pidMsg = (uint32_t)Msg.idMsg.u.value64; + *pcParameters = Msg.cParameters.u.value32; + return rc; + } + + /* + * If interrupted we must cancel the call so it doesn't prevent us from making another one. + */ + if (rc == VERR_INTERRUPTED) + { + VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, GUEST_MSG_CANCEL, 0); + int rc2 = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg.Hdr)); + AssertRC(rc2); + } + + /* + * If restored, update pidRestoreCheck. + */ + if (rc == VERR_VM_RESTORED && pidRestoreCheck) + *pidRestoreCheck = Msg.idMsg.u.value64; + + *pidMsg = UINT32_MAX - 1; + *pcParameters = UINT32_MAX - 2; + return rc; + } + + /* + * Fallback if host < v6.0. + * + * Note! The restore check isn't perfect. Would require checking afterwards + * and stash the result if we were restored during the call. Too much + * hazzle for a downgrade scenario. + */ + if (pidRestoreCheck) + { + uint64_t idRestoreCur = *pidRestoreCheck; + rc = VbglR3GetSessionId(&idRestoreCur); + if (RT_SUCCESS(rc) && idRestoreCur != *pidRestoreCheck) + { + *pidRestoreCheck = idRestoreCur; + return VERR_VM_RESTORED; + } + } + + rc = vbglR3GuestCtrlMsgWaitFor(idClient, pidMsg, pcParameters); + if (rc == VERR_TOO_MUCH_DATA) + rc = VINF_SUCCESS; + return rc; +} + + +/** + * Asks the host guest control service to set a message filter to this + * client so that it only will receive certain messages in the future. + * The filter(s) are a bitmask for the context IDs, served from the host. + * + * @return IPRT status code. + * @param idClient The client ID returned by VbglR3GuestCtrlConnect(). + * @param uValue The value to filter messages for. + * @param uMaskAdd Filter mask to add. + * @param uMaskRemove Filter mask to remove. + */ +VBGLR3DECL(int) VbglR3GuestCtrlMsgFilterSet(uint32_t idClient, uint32_t uValue, uint32_t uMaskAdd, uint32_t uMaskRemove) +{ + HGCMMsgFilterSet Msg; + + /* Tell the host we want to set a filter. */ + VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, GUEST_MSG_FILTER_SET, 4); + VbglHGCMParmUInt32Set(&Msg.value, uValue); + VbglHGCMParmUInt32Set(&Msg.mask_add, uMaskAdd); + VbglHGCMParmUInt32Set(&Msg.mask_remove, uMaskRemove); + VbglHGCMParmUInt32Set(&Msg.flags, 0 /* Flags, unused */); + + return VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); +} + + +/** + * Replies to a message from the host. + * + * @returns VBox status code. + * @param pCtx Guest control command context to use. + * @param rc Guest rc to reply. + */ +VBGLR3DECL(int) VbglR3GuestCtrlMsgReply(PVBGLR3GUESTCTRLCMDCTX pCtx, + int rc) +{ + return VbglR3GuestCtrlMsgReplyEx(pCtx, rc, 0 /* uType */, + NULL /* pvPayload */, 0 /* cbPayload */); +} + + +/** + * Replies to a message from the host, extended version. + * + * @returns VBox status code. + * @param pCtx Guest control command context to use. + * @param rc Guest rc to reply. + * @param uType Reply type; not used yet and must be 0. + * @param pvPayload Pointer to data payload to reply. Optional. + * @param cbPayload Size of data payload (in bytes) to reply. + */ +VBGLR3DECL(int) VbglR3GuestCtrlMsgReplyEx(PVBGLR3GUESTCTRLCMDCTX pCtx, + int rc, uint32_t uType, + void *pvPayload, uint32_t cbPayload) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + /* Everything else is optional. */ + + HGCMMsgReply Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, GUEST_MSG_REPLY, 4); + VbglHGCMParmUInt32Set(&Msg.context, pCtx->uContextID); + VbglHGCMParmUInt32Set(&Msg.type, uType); + VbglHGCMParmUInt32Set(&Msg.rc, (uint32_t)rc); /* int vs. uint32_t */ + VbglHGCMParmPtrSet(&Msg.payload, pvPayload, cbPayload); + + return VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); +} + +/** + * Tell the host to skip the current message replying VERR_NOT_SUPPORTED + * + * @return IPRT status code. + * @param idClient The client ID returned by VbglR3GuestCtrlConnect(). + * @param rcSkip The status code to pass back to Main when skipping. + * @param idMsg The message ID to skip, pass UINT32_MAX to pass any. + */ +VBGLR3DECL(int) VbglR3GuestCtrlMsgSkip(uint32_t idClient, int rcSkip, uint32_t idMsg) +{ + if (vbglR3GuestCtrlSupportsPeekGetCancel(idClient)) + { + struct + { + VBGLIOCHGCMCALL Hdr; + HGCMFunctionParameter rcSkip; + HGCMFunctionParameter idMsg; + } Msg; + VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, GUEST_MSG_SKIP, 2); + VbglHGCMParmUInt32Set(&Msg.rcSkip, (uint32_t)rcSkip); + VbglHGCMParmUInt32Set(&Msg.idMsg, idMsg); + return VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg)); + } + + /* This is generally better than nothing... */ + return VbglR3GuestCtrlMsgSkipOld(idClient); +} + + +/** + * Tells the host service to skip the current message returned by + * VbglR3GuestCtrlMsgWaitFor(). + * + * @return IPRT status code. + * @param idClient The client ID returned by VbglR3GuestCtrlConnect(). + */ +VBGLR3DECL(int) VbglR3GuestCtrlMsgSkipOld(uint32_t idClient) +{ + HGCMMsgSkip Msg; + + /* Tell the host we want to skip the current assigned message. */ + VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, GUEST_MSG_SKIP_OLD, 1); + VbglHGCMParmUInt32Set(&Msg.flags, 0 /* Flags, unused */); + return VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); +} + + +/** + * Asks the host to cancel (release) all pending waits which were deferred. + * + * @returns VBox status code. + * @param idClient The client ID returned by VbglR3GuestCtrlConnect(). + */ +VBGLR3DECL(int) VbglR3GuestCtrlCancelPendingWaits(uint32_t idClient) +{ + HGCMMsgCancelPendingWaits Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, GUEST_MSG_CANCEL, 0); + return VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); +} + + +/** + * Prepares a session. + * @since 6.0 + * @sa GUEST_SESSION_PREPARE + */ +VBGLR3DECL(int) VbglR3GuestCtrlSessionPrepare(uint32_t idClient, uint32_t idSession, void const *pvKey, uint32_t cbKey) +{ + int rc; + do + { + struct + { + VBGLIOCHGCMCALL Hdr; + HGCMFunctionParameter idSession; + HGCMFunctionParameter pKey; + } Msg; + VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, GUEST_MSG_SESSION_PREPARE, 2); + VbglHGCMParmUInt32Set(&Msg.idSession, idSession); + VbglHGCMParmPtrSet(&Msg.pKey, (void *)pvKey, cbKey); + rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg)); + } while (rc == VERR_INTERRUPTED); + return rc; +} + + +/** + * Accepts a session. + * @since 6.0 + * @sa GUEST_SESSION_ACCEPT + */ +VBGLR3DECL(int) VbglR3GuestCtrlSessionAccept(uint32_t idClient, uint32_t idSession, void const *pvKey, uint32_t cbKey) +{ + int rc; + do + { + struct + { + VBGLIOCHGCMCALL Hdr; + HGCMFunctionParameter idSession; + HGCMFunctionParameter pKey; + } Msg; + VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, GUEST_MSG_SESSION_ACCEPT, 2); + VbglHGCMParmUInt32Set(&Msg.idSession, idSession); + VbglHGCMParmPtrSet(&Msg.pKey, (void *)pvKey, cbKey); + rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg)); + } while (rc == VERR_INTERRUPTED); + return rc; +} + + +/** + * Cancels a prepared session. + * @since 6.0 + * @sa GUEST_SESSION_CANCEL_PREPARED + */ +VBGLR3DECL(int) VbglR3GuestCtrlSessionCancelPrepared(uint32_t idClient, uint32_t idSession) +{ + int rc; + do + { + struct + { + VBGLIOCHGCMCALL Hdr; + HGCMFunctionParameter idSession; + } Msg; + VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, GUEST_MSG_SESSION_CANCEL_PREPARED, 1); + VbglHGCMParmUInt32Set(&Msg.idSession, idSession); + rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg)); + } while (rc == VERR_INTERRUPTED); + return rc; +} + + +/** + * Invalidates the internal state because the (VM) session has been changed (i.e. restored). + * + * @returns VBox status code. + * @param idClient Client ID to use for invalidating state. + * @param idNewControlSession New control session ID. Currently unused. + */ +VBGLR3DECL(int) VbglR3GuestCtrlSessionHasChanged(uint32_t idClient, uint64_t idNewControlSession) +{ + RT_NOREF(idNewControlSession); + + vbglR3GuestCtrlDetectPeekGetCancelSupport(idClient); + + return VINF_SUCCESS; +} + + +/** + * Asks a specific guest session to close. + * + * @return IPRT status code. + * @param pCtx Guest control command context to use. + * @param fFlags Some kind of flag. Figure it out yourself. + */ +VBGLR3DECL(int) VbglR3GuestCtrlSessionClose(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t fFlags) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + AssertReturn(pCtx->uNumParms == 2, VERR_INVALID_PARAMETER); + + HGCMMsgSessionClose Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, GUEST_MSG_SESSION_CLOSE, pCtx->uNumParms); + VbglHGCMParmUInt32Set(&Msg.context, pCtx->uContextID); + VbglHGCMParmUInt32Set(&Msg.flags, fFlags); + + return VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); +} + + +/** + * Notifies a guest session. + * + * @returns VBox status code. + * @param pCtx Guest control command context to use. + * @param uType Notification type of type GUEST_SESSION_NOTIFYTYPE_XXX. + * @param iResult Result code (rc) to notify. + */ +VBGLR3DECL(int) VbglR3GuestCtrlSessionNotify(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uType, int32_t iResult) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + + HGCMMsgSessionNotify Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, GUEST_MSG_SESSION_NOTIFY, 3); + VbglHGCMParmUInt32Set(&Msg.context, pCtx->uContextID); + VbglHGCMParmUInt32Set(&Msg.type, uType); + VbglHGCMParmUInt32Set(&Msg.result, (uint32_t)iResult); + + return VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); +} + +/** + * Initializes a session startup info, extended version. + * + * @returns VBox status code. + * @param pStartupInfo Session startup info to initializes. + * @param cbUser Size (in bytes) to use for the user name buffer. + * @param cbPassword Size (in bytes) to use for the password buffer. + * @param cbDomain Size (in bytes) to use for the domain name buffer. + */ +VBGLR3DECL(int) VbglR3GuestCtrlSessionStartupInfoInitEx(PVBGLR3GUESTCTRLSESSIONSTARTUPINFO pStartupInfo, + size_t cbUser, size_t cbPassword, size_t cbDomain) +{ + AssertPtrReturn(pStartupInfo, VERR_INVALID_POINTER); + + RT_BZERO(pStartupInfo, sizeof(VBGLR3GUESTCTRLSESSIONSTARTUPINFO)); + +#define ALLOC_STR(a_Str, a_cb) \ + if ((a_cb) > 0) \ + { \ + pStartupInfo->psz##a_Str = RTStrAlloc(a_cb); \ + AssertPtrBreak(pStartupInfo->psz##a_Str); \ + pStartupInfo->cb##a_Str = (uint32_t)a_cb; \ + } + + do + { + ALLOC_STR(User, cbUser); + ALLOC_STR(Password, cbPassword); + ALLOC_STR(Domain, cbDomain); + + return VINF_SUCCESS; + + } while (0); + +#undef ALLOC_STR + + VbglR3GuestCtrlSessionStartupInfoDestroy(pStartupInfo); + return VERR_NO_MEMORY; +} + +/** + * Initializes a session startup info. + * + * @returns VBox status code. + * @param pStartupInfo Session startup info to initializes. + */ +VBGLR3DECL(int) VbglR3GuestCtrlSessionStartupInfoInit(PVBGLR3GUESTCTRLSESSIONSTARTUPINFO pStartupInfo) +{ + return VbglR3GuestCtrlSessionStartupInfoInitEx(pStartupInfo, + GUEST_PROC_DEF_USER_LEN, GUEST_PROC_DEF_PASSWORD_LEN, + GUEST_PROC_DEF_DOMAIN_LEN); +} + +/** + * Destroys a session startup info. + * + * @param pStartupInfo Session startup info to destroy. + */ +VBGLR3DECL(void) VbglR3GuestCtrlSessionStartupInfoDestroy(PVBGLR3GUESTCTRLSESSIONSTARTUPINFO pStartupInfo) +{ + if (!pStartupInfo) + return; + + RTStrFree(pStartupInfo->pszUser); + RTStrFree(pStartupInfo->pszPassword); + RTStrFree(pStartupInfo->pszDomain); + + RT_BZERO(pStartupInfo, sizeof(VBGLR3GUESTCTRLSESSIONSTARTUPINFO)); +} + +/** + * Free's a session startup info. + * + * @param pStartupInfo Session startup info to free. + * The pointer will not be valid anymore after return. + */ +VBGLR3DECL(void) VbglR3GuestCtrlSessionStartupInfoFree(PVBGLR3GUESTCTRLSESSIONSTARTUPINFO pStartupInfo) +{ + if (!pStartupInfo) + return; + + VbglR3GuestCtrlSessionStartupInfoDestroy(pStartupInfo); + + RTMemFree(pStartupInfo); + pStartupInfo = NULL; +} + +/** + * Duplicates a session startup info. + * + * @returns Duplicated session startup info on success, or NULL on error. + * @param pStartupInfo Session startup info to duplicate. + */ +VBGLR3DECL(PVBGLR3GUESTCTRLSESSIONSTARTUPINFO) VbglR3GuestCtrlSessionStartupInfoDup(PVBGLR3GUESTCTRLSESSIONSTARTUPINFO pStartupInfo) +{ + AssertPtrReturn(pStartupInfo, NULL); + + PVBGLR3GUESTCTRLSESSIONSTARTUPINFO pStartupInfoDup = (PVBGLR3GUESTCTRLSESSIONSTARTUPINFO) + RTMemDup(pStartupInfo, sizeof(VBGLR3GUESTCTRLSESSIONSTARTUPINFO)); + if (pStartupInfoDup) + { + do + { + pStartupInfoDup->pszUser = NULL; + pStartupInfoDup->pszPassword = NULL; + pStartupInfoDup->pszDomain = NULL; + +#define DUP_STR(a_Str) \ + if (pStartupInfo->cb##a_Str) \ + { \ + pStartupInfoDup->psz##a_Str = (char *)RTStrDup(pStartupInfo->psz##a_Str); \ + AssertPtrBreak(pStartupInfoDup->psz##a_Str); \ + pStartupInfoDup->cb##a_Str = (uint32_t)strlen(pStartupInfoDup->psz##a_Str) + 1 /* Include terminator */; \ + } + DUP_STR(User); + DUP_STR(Password); + DUP_STR(Domain); + +#undef DUP_STR + + return pStartupInfoDup; + + } while (0); /* To use break macros above. */ + + VbglR3GuestCtrlSessionStartupInfoFree(pStartupInfoDup); + } + + return NULL; +} + +/** + * Retrieves a HOST_SESSION_CREATE message. + * + * @returns VBox status code. + * @param pCtx Guest control command context to use. + * @param ppStartupInfo Where to store the allocated session startup info. + * Needs to be free'd by VbglR3GuestCtrlSessionStartupInfoFree(). + */ +VBGLR3DECL(int) VbglR3GuestCtrlSessionGetOpen(PVBGLR3GUESTCTRLCMDCTX pCtx, PVBGLR3GUESTCTRLSESSIONSTARTUPINFO *ppStartupInfo) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + AssertReturn(pCtx->uNumParms == 6, VERR_INVALID_PARAMETER); + AssertPtrReturn(ppStartupInfo, VERR_INVALID_POINTER); + + PVBGLR3GUESTCTRLSESSIONSTARTUPINFO pStartupInfo + = (PVBGLR3GUESTCTRLSESSIONSTARTUPINFO)RTMemAlloc(sizeof(VBGLR3GUESTCTRLSESSIONSTARTUPINFO)); + if (!pStartupInfo) + return VERR_NO_MEMORY; + + int rc = VbglR3GuestCtrlSessionStartupInfoInit(pStartupInfo); + if (RT_FAILURE(rc)) + { + VbglR3GuestCtrlSessionStartupInfoFree(pStartupInfo); + return rc; + } + + do + { + HGCMMsgSessionOpen Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, vbglR3GuestCtrlGetMsgFunctionNo(pCtx->uClientID), pCtx->uNumParms); + VbglHGCMParmUInt32Set(&Msg.context, HOST_MSG_SESSION_CREATE); + VbglHGCMParmUInt32Set(&Msg.protocol, 0); + VbglHGCMParmPtrSet(&Msg.username, pStartupInfo->pszUser, pStartupInfo->cbUser); + VbglHGCMParmPtrSet(&Msg.password, pStartupInfo->pszPassword, pStartupInfo->cbPassword); + VbglHGCMParmPtrSet(&Msg.domain, pStartupInfo->pszDomain, pStartupInfo->cbDomain); + VbglHGCMParmUInt32Set(&Msg.flags, 0); + + rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); + if (RT_SUCCESS(rc)) + { + Msg.context.GetUInt32(&pCtx->uContextID); + Msg.protocol.GetUInt32(&pStartupInfo->uProtocol); + Msg.flags.GetUInt32(&pStartupInfo->fFlags); + + pStartupInfo->uSessionID = VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(pCtx->uContextID); + } + + } while (rc == VERR_INTERRUPTED && g_fVbglR3GuestCtrlHavePeekGetCancel); + + if (RT_SUCCESS(rc)) + { + *ppStartupInfo = pStartupInfo; + } + else + VbglR3GuestCtrlSessionStartupInfoFree(pStartupInfo); + + LogFlowFuncLeaveRC(rc); + return rc; +} + + +/** + * Retrieves a HOST_SESSION_CLOSE message. + */ +VBGLR3DECL(int) VbglR3GuestCtrlSessionGetClose(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *pfFlags, uint32_t *pidSession) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + AssertReturn(pCtx->uNumParms == 2, VERR_INVALID_PARAMETER); + + AssertPtrReturn(pfFlags, VERR_INVALID_POINTER); + + int rc; + do + { + HGCMMsgSessionClose Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, vbglR3GuestCtrlGetMsgFunctionNo(pCtx->uClientID), pCtx->uNumParms); + VbglHGCMParmUInt32Set(&Msg.context, HOST_MSG_SESSION_CLOSE); + VbglHGCMParmUInt32Set(&Msg.flags, 0); + + rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); + if (RT_SUCCESS(rc)) + { + Msg.context.GetUInt32(&pCtx->uContextID); + Msg.flags.GetUInt32(pfFlags); + + if (pidSession) + *pidSession = VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(pCtx->uContextID); + } + } while (rc == VERR_INTERRUPTED && g_fVbglR3GuestCtrlHavePeekGetCancel); + return rc; +} + + +/** + * Retrieves a HOST_PATH_RENAME message. + */ +VBGLR3DECL(int) VbglR3GuestCtrlPathGetRename(PVBGLR3GUESTCTRLCMDCTX pCtx, + char *pszSource, uint32_t cbSource, + char *pszDest, uint32_t cbDest, + uint32_t *pfFlags) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + AssertReturn(pCtx->uNumParms == 4, VERR_INVALID_PARAMETER); + + AssertPtrReturn(pszSource, VERR_INVALID_POINTER); + AssertReturn(cbSource, VERR_INVALID_PARAMETER); + AssertPtrReturn(pszDest, VERR_INVALID_POINTER); + AssertReturn(cbDest, VERR_INVALID_PARAMETER); + AssertPtrReturn(pfFlags, VERR_INVALID_POINTER); + + int rc; + do + { + HGCMMsgPathRename Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, vbglR3GuestCtrlGetMsgFunctionNo(pCtx->uClientID), pCtx->uNumParms); + VbglHGCMParmUInt32Set(&Msg.context, HOST_MSG_PATH_RENAME); + VbglHGCMParmPtrSet(&Msg.source, pszSource, cbSource); + VbglHGCMParmPtrSet(&Msg.dest, pszDest, cbDest); + VbglHGCMParmUInt32Set(&Msg.flags, 0); + + rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); + if (RT_SUCCESS(rc)) + { + Msg.context.GetUInt32(&pCtx->uContextID); + Msg.flags.GetUInt32(pfFlags); + } + + } while (rc == VERR_INTERRUPTED && g_fVbglR3GuestCtrlHavePeekGetCancel); + return rc; +} + + +/** + * Retrieves a HOST_PATH_USER_DOCUMENTS message. + */ +VBGLR3DECL(int) VbglR3GuestCtrlPathGetUserDocuments(PVBGLR3GUESTCTRLCMDCTX pCtx) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + AssertReturn(pCtx->uNumParms == 1, VERR_INVALID_PARAMETER); + + int rc; + do + { + HGCMMsgPathUserDocuments Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, vbglR3GuestCtrlGetMsgFunctionNo(pCtx->uClientID), pCtx->uNumParms); + VbglHGCMParmUInt32Set(&Msg.context, HOST_MSG_PATH_USER_DOCUMENTS); + + rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); + if (RT_SUCCESS(rc)) + Msg.context.GetUInt32(&pCtx->uContextID); + } while (rc == VERR_INTERRUPTED && g_fVbglR3GuestCtrlHavePeekGetCancel); + return rc; +} + + +/** + * Retrieves a HOST_PATH_USER_HOME message. + */ +VBGLR3DECL(int) VbglR3GuestCtrlPathGetUserHome(PVBGLR3GUESTCTRLCMDCTX pCtx) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + AssertReturn(pCtx->uNumParms == 1, VERR_INVALID_PARAMETER); + + int rc; + do + { + HGCMMsgPathUserHome Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, vbglR3GuestCtrlGetMsgFunctionNo(pCtx->uClientID), pCtx->uNumParms); + VbglHGCMParmUInt32Set(&Msg.context, HOST_MSG_PATH_USER_HOME); + + rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); + if (RT_SUCCESS(rc)) + Msg.context.GetUInt32(&pCtx->uContextID); + } while (rc == VERR_INTERRUPTED && g_fVbglR3GuestCtrlHavePeekGetCancel); + return rc; +} + +/** + * Retrieves a HOST_MSG_SHUTDOWN message. + * + * @returns VBox status code. + * @param pCtx Guest control command context to use. + * @param pfAction Where to store the action flags on success. + */ +VBGLR3DECL(int) VbglR3GuestCtrlGetShutdown(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *pfAction) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + AssertReturn(pCtx->uNumParms == 2, VERR_INVALID_PARAMETER); + AssertPtrReturn(pfAction, VERR_INVALID_POINTER); + + int rc; + do + { + HGCMMsgShutdown Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, vbglR3GuestCtrlGetMsgFunctionNo(pCtx->uClientID), pCtx->uNumParms); + VbglHGCMParmUInt32Set(&Msg.context, HOST_MSG_SHUTDOWN); + VbglHGCMParmUInt32Set(&Msg.action, 0); + + rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); + if (RT_SUCCESS(rc)) + { + Msg.context.GetUInt32(&pCtx->uContextID); + Msg.action.GetUInt32(pfAction); + } + } while (rc == VERR_INTERRUPTED && g_fVbglR3GuestCtrlHavePeekGetCancel); + return rc; +} + +/** + * Initializes a process startup info, extended version. + * + * @returns VBox status code. + * @param pStartupInfo Process startup info to initializes. + * @param cbCmd Size (in bytes) to use for the command buffer. + * @param cbUser Size (in bytes) to use for the user name buffer. + * @param cbPassword Size (in bytes) to use for the password buffer. + * @param cbDomain Size (in bytes) to use for the domain buffer. + * @param cbArgs Size (in bytes) to use for the arguments buffer. + * @param cbEnv Size (in bytes) to use for the environment buffer. + */ +VBGLR3DECL(int) VbglR3GuestCtrlProcStartupInfoInitEx(PVBGLR3GUESTCTRLPROCSTARTUPINFO pStartupInfo, + size_t cbCmd, + size_t cbUser, size_t cbPassword, size_t cbDomain, + size_t cbArgs, size_t cbEnv) +{ + AssertPtrReturn(pStartupInfo, VERR_INVALID_POINTER); + AssertReturn(cbCmd, VERR_INVALID_PARAMETER); + AssertReturn(cbUser, VERR_INVALID_PARAMETER); + AssertReturn(cbPassword, VERR_INVALID_PARAMETER); + AssertReturn(cbDomain, VERR_INVALID_PARAMETER); + AssertReturn(cbArgs, VERR_INVALID_PARAMETER); + AssertReturn(cbEnv, VERR_INVALID_PARAMETER); + + RT_BZERO(pStartupInfo, sizeof(VBGLR3GUESTCTRLPROCSTARTUPINFO)); + +#define ALLOC_STR(a_Str, a_cb) \ + if ((a_cb) > 0) \ + { \ + pStartupInfo->psz##a_Str = RTStrAlloc(a_cb); \ + AssertPtrBreak(pStartupInfo->psz##a_Str); \ + pStartupInfo->cb##a_Str = (uint32_t)a_cb; \ + } + + do + { + ALLOC_STR(Cmd, cbCmd); + ALLOC_STR(Args, cbArgs); + ALLOC_STR(Env, cbEnv); + ALLOC_STR(User, cbUser); + ALLOC_STR(Password, cbPassword); + ALLOC_STR(Domain, cbDomain); + + return VINF_SUCCESS; + + } while (0); + +#undef ALLOC_STR + + VbglR3GuestCtrlProcStartupInfoDestroy(pStartupInfo); + return VERR_NO_MEMORY; +} + +/** + * Initializes a process startup info with default values. + * + * @param pStartupInfo Process startup info to initializes. + */ +VBGLR3DECL(int) VbglR3GuestCtrlProcStartupInfoInit(PVBGLR3GUESTCTRLPROCSTARTUPINFO pStartupInfo) +{ + return VbglR3GuestCtrlProcStartupInfoInitEx(pStartupInfo, + GUEST_PROC_DEF_CMD_LEN, + GUEST_PROC_DEF_USER_LEN /* Deprecated, now handled via session creation. */, + GUEST_PROC_DEF_PASSWORD_LEN /* Ditto. */, + GUEST_PROC_DEF_DOMAIN_LEN /* Ditto. */, + GUEST_PROC_DEF_ARGS_LEN, GUEST_PROC_DEF_ENV_LEN); +} + +/** + * Destroys a process startup info. + * + * @param pStartupInfo Process startup info to destroy. + */ +VBGLR3DECL(void) VbglR3GuestCtrlProcStartupInfoDestroy(PVBGLR3GUESTCTRLPROCSTARTUPINFO pStartupInfo) +{ + if (!pStartupInfo) + return; + + RTStrFree(pStartupInfo->pszCmd); + RTStrFree(pStartupInfo->pszArgs); + RTStrFree(pStartupInfo->pszEnv); + RTStrFree(pStartupInfo->pszUser); + RTStrFree(pStartupInfo->pszPassword); + RTStrFree(pStartupInfo->pszDomain); + + RT_BZERO(pStartupInfo, sizeof(VBGLR3GUESTCTRLPROCSTARTUPINFO)); +} + +/** + * Free's a process startup info. + * + * @param pStartupInfo Process startup info to free. + * The pointer will not be valid anymore after return. + */ +VBGLR3DECL(void) VbglR3GuestCtrlProcStartupInfoFree(PVBGLR3GUESTCTRLPROCSTARTUPINFO pStartupInfo) +{ + if (!pStartupInfo) + return; + + VbglR3GuestCtrlProcStartupInfoDestroy(pStartupInfo); + + RTMemFree(pStartupInfo); + pStartupInfo = NULL; +} + +/** + * Duplicates a process startup info. + * + * @returns Duplicated process startup info on success, or NULL on error. + * @param pStartupInfo Process startup info to duplicate. + */ +VBGLR3DECL(PVBGLR3GUESTCTRLPROCSTARTUPINFO) VbglR3GuestCtrlProcStartupInfoDup(PVBGLR3GUESTCTRLPROCSTARTUPINFO pStartupInfo) +{ + AssertPtrReturn(pStartupInfo, NULL); + + PVBGLR3GUESTCTRLPROCSTARTUPINFO pStartupInfoDup = (PVBGLR3GUESTCTRLPROCSTARTUPINFO) + RTMemDup(pStartupInfo, sizeof(VBGLR3GUESTCTRLPROCSTARTUPINFO)); + if (pStartupInfoDup) + { + do + { + pStartupInfoDup->pszCmd = NULL; + pStartupInfoDup->pszArgs = NULL; + pStartupInfoDup->pszEnv = NULL; + pStartupInfoDup->pszUser = NULL; + pStartupInfoDup->pszPassword = NULL; + pStartupInfoDup->pszDomain = NULL; + +#define DUP_STR(a_Str) \ + if (pStartupInfo->cb##a_Str) \ + { \ + pStartupInfoDup->psz##a_Str = (char *)RTStrDup(pStartupInfo->psz##a_Str); \ + AssertPtrBreak(pStartupInfoDup->psz##a_Str); \ + pStartupInfoDup->cb##a_Str = (uint32_t)strlen(pStartupInfoDup->psz##a_Str) + 1 /* Include terminator */; \ + } + +#define DUP_MEM(a_Str) \ + if (pStartupInfo->cb##a_Str) \ + { \ + pStartupInfoDup->psz##a_Str = (char *)RTMemDup(pStartupInfo->psz##a_Str, pStartupInfo->cb##a_Str); \ + AssertPtrBreak(pStartupInfoDup->psz##a_Str); \ + pStartupInfoDup->cb##a_Str = (uint32_t)pStartupInfo->cb##a_Str; \ + } + + DUP_STR(Cmd); + DUP_MEM(Args); + DUP_MEM(Env); + DUP_STR(User); + DUP_STR(Password); + DUP_STR(Domain); + +#undef DUP_STR +#undef DUP_MEM + + return pStartupInfoDup; + + } while (0); /* To use break macros above. */ + + VbglR3GuestCtrlProcStartupInfoFree(pStartupInfoDup); + } + + return NULL; +} + +/** + * Retrieves a HOST_EXEC_CMD message. + * + * @returns VBox status code. + * @param pCtx Guest control command context to use. + * @param ppStartupInfo Where to store the allocated session startup info. + * Needs to be free'd by VbglR3GuestCtrlProcStartupInfoFree(). + */ +VBGLR3DECL(int) VbglR3GuestCtrlProcGetStart(PVBGLR3GUESTCTRLCMDCTX pCtx, PVBGLR3GUESTCTRLPROCSTARTUPINFO *ppStartupInfo) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + AssertPtrReturn(ppStartupInfo, VERR_INVALID_POINTER); + + PVBGLR3GUESTCTRLPROCSTARTUPINFO pStartupInfo + = (PVBGLR3GUESTCTRLPROCSTARTUPINFO)RTMemAlloc(sizeof(VBGLR3GUESTCTRLPROCSTARTUPINFO)); + if (!pStartupInfo) + return VERR_NO_MEMORY; + + int rc = VbglR3GuestCtrlProcStartupInfoInit(pStartupInfo); + if (RT_FAILURE(rc)) + { + VbglR3GuestCtrlProcStartupInfoFree(pStartupInfo); + return rc; + } + + unsigned cRetries = 0; + const unsigned cMaxRetries = 32; /* Should be enough for now. */ + const unsigned cGrowthFactor = 2; /* By how much the buffers will grow if they're too small yet. */ + + do + { + LogRel(("VbglR3GuestCtrlProcGetStart: Retrieving\n")); + + HGCMMsgProcExec Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, vbglR3GuestCtrlGetMsgFunctionNo(pCtx->uClientID), pCtx->uNumParms); + VbglHGCMParmUInt32Set(&Msg.context, HOST_MSG_EXEC_CMD); + VbglHGCMParmPtrSet(&Msg.cmd, pStartupInfo->pszCmd, pStartupInfo->cbCmd); + VbglHGCMParmUInt32Set(&Msg.flags, 0); + VbglHGCMParmUInt32Set(&Msg.num_args, 0); + VbglHGCMParmPtrSet(&Msg.args, pStartupInfo->pszArgs, pStartupInfo->cbArgs); + VbglHGCMParmUInt32Set(&Msg.num_env, 0); + VbglHGCMParmUInt32Set(&Msg.cb_env, 0); + VbglHGCMParmPtrSet(&Msg.env, pStartupInfo->pszEnv, pStartupInfo->cbEnv); + if (pCtx->uProtocol < 2) + { + VbglHGCMParmPtrSet(&Msg.u.v1.username, pStartupInfo->pszUser, pStartupInfo->cbUser); + VbglHGCMParmPtrSet(&Msg.u.v1.password, pStartupInfo->pszPassword, pStartupInfo->cbPassword); + VbglHGCMParmUInt32Set(&Msg.u.v1.timeout, 0); + } + else + { + VbglHGCMParmUInt32Set(&Msg.u.v2.timeout, 0); + VbglHGCMParmUInt32Set(&Msg.u.v2.priority, 0); + VbglHGCMParmUInt32Set(&Msg.u.v2.num_affinity, 0); + VbglHGCMParmPtrSet(&Msg.u.v2.affinity, pStartupInfo->uAffinity, sizeof(pStartupInfo->uAffinity)); + } + + rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); + if (RT_FAILURE(rc)) + { + LogRel(("VbglR3GuestCtrlProcGetStart: 1 - %Rrc (retry %u, cbCmd=%RU32, cbArgs=%RU32, cbEnv=%RU32)\n", + rc, cRetries, pStartupInfo->cbCmd, pStartupInfo->cbArgs, pStartupInfo->cbEnv)); + + if ( rc == VERR_BUFFER_OVERFLOW + && cRetries++ < cMaxRetries) + { +#define GROW_STR(a_Str, a_cbMax) \ + pStartupInfo->psz##a_Str = (char *)RTMemRealloc(pStartupInfo->psz##a_Str, \ + RT_MIN(pStartupInfo->cb##a_Str * cGrowthFactor, a_cbMax)); \ + AssertPtrBreakStmt(pStartupInfo->psz##a_Str, VERR_NO_MEMORY); \ + pStartupInfo->cb##a_Str = RT_MIN(pStartupInfo->cb##a_Str * cGrowthFactor, a_cbMax); + + /* We can't tell which parameter doesn't fit, so we have to resize all. */ + GROW_STR(Cmd , GUEST_PROC_MAX_CMD_LEN); + GROW_STR(Args, GUEST_PROC_MAX_ARGS_LEN); + GROW_STR(Env, GUEST_PROC_MAX_ENV_LEN); + +#undef GROW_STR + LogRel(("VbglR3GuestCtrlProcGetStart: 2 - %Rrc (retry %u, cbCmd=%RU32, cbArgs=%RU32, cbEnv=%RU32)\n", + rc, cRetries, pStartupInfo->cbCmd, pStartupInfo->cbArgs, pStartupInfo->cbEnv)); + LogRel(("g_fVbglR3GuestCtrlHavePeekGetCancel=%RTbool\n", RT_BOOL(g_fVbglR3GuestCtrlHavePeekGetCancel))); + } + else + break; + } + else + { + Msg.context.GetUInt32(&pCtx->uContextID); + Msg.flags.GetUInt32(&pStartupInfo->fFlags); + Msg.num_args.GetUInt32(&pStartupInfo->cArgs); + Msg.num_env.GetUInt32(&pStartupInfo->cEnvVars); + Msg.cb_env.GetUInt32(&pStartupInfo->cbEnv); + if (pCtx->uProtocol < 2) + Msg.u.v1.timeout.GetUInt32(&pStartupInfo->uTimeLimitMS); + else + { + Msg.u.v2.timeout.GetUInt32(&pStartupInfo->uTimeLimitMS); + Msg.u.v2.priority.GetUInt32(&pStartupInfo->uPriority); + Msg.u.v2.num_affinity.GetUInt32(&pStartupInfo->cAffinity); + } + } + } while (( rc == VERR_INTERRUPTED + || rc == VERR_BUFFER_OVERFLOW) && g_fVbglR3GuestCtrlHavePeekGetCancel); + + if (RT_SUCCESS(rc)) + { + *ppStartupInfo = pStartupInfo; + } + else + VbglR3GuestCtrlProcStartupInfoFree(pStartupInfo); + + LogRel(("VbglR3GuestCtrlProcGetStart: Returning %Rrc (retry %u, cbCmd=%RU32, cbArgs=%RU32, cbEnv=%RU32)\n", + rc, cRetries, pStartupInfo->cbCmd, pStartupInfo->cbArgs, pStartupInfo->cbEnv)); + + LogFlowFuncLeaveRC(rc); + return rc; +} + +/** + * Allocates and gets host data, based on the message ID. + * + * This will block until data becomes available. + * + * @returns VBox status code. + * @param pCtx Guest control command context to use. + * @param puPID Where to return the guest PID to retrieve output from on success. + * @param puHandle Where to return the guest process handle to retrieve output from on success. + * @param pfFlags Where to return the output flags on success. + */ +VBGLR3DECL(int) VbglR3GuestCtrlProcGetOutput(PVBGLR3GUESTCTRLCMDCTX pCtx, + uint32_t *puPID, uint32_t *puHandle, uint32_t *pfFlags) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + AssertReturn(pCtx->uNumParms == 4, VERR_INVALID_PARAMETER); + + AssertPtrReturn(puPID, VERR_INVALID_POINTER); + AssertPtrReturn(puHandle, VERR_INVALID_POINTER); + AssertPtrReturn(pfFlags, VERR_INVALID_POINTER); + + int rc; + do + { + HGCMMsgProcOutput Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, vbglR3GuestCtrlGetMsgFunctionNo(pCtx->uClientID), pCtx->uNumParms); + VbglHGCMParmUInt32Set(&Msg.context, HOST_MSG_EXEC_GET_OUTPUT); + VbglHGCMParmUInt32Set(&Msg.pid, 0); + VbglHGCMParmUInt32Set(&Msg.handle, 0); + VbglHGCMParmUInt32Set(&Msg.flags, 0); + + rc = VbglR3HGCMCall(&Msg.hdr, RT_UOFFSETOF(HGCMMsgProcOutput, data)); + if (RT_SUCCESS(rc)) + { + Msg.context.GetUInt32(&pCtx->uContextID); + Msg.pid.GetUInt32(puPID); + Msg.handle.GetUInt32(puHandle); + Msg.flags.GetUInt32(pfFlags); + } + } while (rc == VERR_INTERRUPTED && g_fVbglR3GuestCtrlHavePeekGetCancel); + return rc; +} + + +/** + * Retrieves the input data from host which then gets sent to the started + * process (HOST_EXEC_SET_INPUT). + * + * This will block until data becomes available. + */ +VBGLR3DECL(int) VbglR3GuestCtrlProcGetInput(PVBGLR3GUESTCTRLCMDCTX pCtx, + uint32_t *puPID, uint32_t *pfFlags, + void *pvData, uint32_t cbData, + uint32_t *pcbSize) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + AssertReturn(pCtx->uNumParms == 5, VERR_INVALID_PARAMETER); + + AssertPtrReturn(puPID, VERR_INVALID_POINTER); + AssertPtrReturn(pfFlags, VERR_INVALID_POINTER); + AssertPtrReturn(pvData, VERR_INVALID_POINTER); + AssertPtrReturn(pcbSize, VERR_INVALID_POINTER); + + int rc; + do + { + HGCMMsgProcInput Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, vbglR3GuestCtrlGetMsgFunctionNo(pCtx->uClientID), pCtx->uNumParms); + VbglHGCMParmUInt32Set(&Msg.context, HOST_MSG_EXEC_SET_INPUT); + VbglHGCMParmUInt32Set(&Msg.pid, 0); + VbglHGCMParmUInt32Set(&Msg.flags, 0); + VbglHGCMParmPtrSet(&Msg.data, pvData, cbData); + VbglHGCMParmUInt32Set(&Msg.size, 0); + + rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); + if (RT_SUCCESS(rc)) + { + Msg.context.GetUInt32(&pCtx->uContextID); + Msg.pid.GetUInt32(puPID); + Msg.flags.GetUInt32(pfFlags); + Msg.size.GetUInt32(pcbSize); + } + } while (rc == VERR_INTERRUPTED && g_fVbglR3GuestCtrlHavePeekGetCancel); + + if ( rc != VERR_TOO_MUCH_DATA + || g_fVbglR3GuestCtrlHavePeekGetCancel) + return rc; + return VERR_BUFFER_OVERFLOW; +} + + +/** + * Retrieves a HOST_DIR_REMOVE message. + */ +VBGLR3DECL(int) VbglR3GuestCtrlDirGetRemove(PVBGLR3GUESTCTRLCMDCTX pCtx, + char *pszPath, uint32_t cbPath, + uint32_t *pfFlags) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + AssertReturn(pCtx->uNumParms == 3, VERR_INVALID_PARAMETER); + + AssertPtrReturn(pszPath, VERR_INVALID_POINTER); + AssertReturn(cbPath, VERR_INVALID_PARAMETER); + AssertPtrReturn(pfFlags, VERR_INVALID_POINTER); + + int rc; + do + { + HGCMMsgDirRemove Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, vbglR3GuestCtrlGetMsgFunctionNo(pCtx->uClientID), pCtx->uNumParms); + VbglHGCMParmUInt32Set(&Msg.context, HOST_MSG_DIR_REMOVE); + VbglHGCMParmPtrSet(&Msg.path, pszPath, cbPath); + VbglHGCMParmUInt32Set(&Msg.flags, 0); + + rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); + if (RT_SUCCESS(rc)) + { + Msg.context.GetUInt32(&pCtx->uContextID); + Msg.flags.GetUInt32(pfFlags); + } + } while (rc == VERR_INTERRUPTED && g_fVbglR3GuestCtrlHavePeekGetCancel); + return rc; +} + + +/** + * Retrieves a HOST_FILE_OPEN message. + */ +VBGLR3DECL(int) VbglR3GuestCtrlFileGetOpen(PVBGLR3GUESTCTRLCMDCTX pCtx, + char *pszFileName, uint32_t cbFileName, + char *pszAccess, uint32_t cbAccess, + char *pszDisposition, uint32_t cbDisposition, + char *pszSharing, uint32_t cbSharing, + uint32_t *puCreationMode, + uint64_t *poffAt) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + AssertReturn(pCtx->uNumParms == 7, VERR_INVALID_PARAMETER); + + AssertPtrReturn(pszFileName, VERR_INVALID_POINTER); + AssertReturn(cbFileName, VERR_INVALID_PARAMETER); + AssertPtrReturn(pszAccess, VERR_INVALID_POINTER); + AssertReturn(cbAccess, VERR_INVALID_PARAMETER); + AssertPtrReturn(pszDisposition, VERR_INVALID_POINTER); + AssertReturn(cbDisposition, VERR_INVALID_PARAMETER); + AssertPtrReturn(pszSharing, VERR_INVALID_POINTER); + AssertReturn(cbSharing, VERR_INVALID_PARAMETER); + AssertPtrReturn(puCreationMode, VERR_INVALID_POINTER); + AssertPtrReturn(poffAt, VERR_INVALID_POINTER); + + int rc; + do + { + HGCMMsgFileOpen Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, vbglR3GuestCtrlGetMsgFunctionNo(pCtx->uClientID), pCtx->uNumParms); + VbglHGCMParmUInt32Set(&Msg.context, HOST_MSG_FILE_OPEN); + VbglHGCMParmPtrSet(&Msg.filename, pszFileName, cbFileName); + VbglHGCMParmPtrSet(&Msg.openmode, pszAccess, cbAccess); + VbglHGCMParmPtrSet(&Msg.disposition, pszDisposition, cbDisposition); + VbglHGCMParmPtrSet(&Msg.sharing, pszSharing, cbSharing); + VbglHGCMParmUInt32Set(&Msg.creationmode, 0); + VbglHGCMParmUInt64Set(&Msg.offset, 0); + + rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); + if (RT_SUCCESS(rc)) + { + Msg.context.GetUInt32(&pCtx->uContextID); + Msg.creationmode.GetUInt32(puCreationMode); + Msg.offset.GetUInt64(poffAt); + } + } while (rc == VERR_INTERRUPTED && g_fVbglR3GuestCtrlHavePeekGetCancel); + return rc; +} + + +/** + * Retrieves a HOST_FILE_CLOSE message. + */ +VBGLR3DECL(int) VbglR3GuestCtrlFileGetClose(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + + AssertReturn(pCtx->uNumParms == 2, VERR_INVALID_PARAMETER); + AssertPtrReturn(puHandle, VERR_INVALID_POINTER); + + int rc; + do + { + HGCMMsgFileClose Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, vbglR3GuestCtrlGetMsgFunctionNo(pCtx->uClientID), pCtx->uNumParms); + VbglHGCMParmUInt32Set(&Msg.context, HOST_MSG_FILE_CLOSE); + VbglHGCMParmUInt32Set(&Msg.handle, 0); + + rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); + if (RT_SUCCESS(rc)) + { + Msg.context.GetUInt32(&pCtx->uContextID); + Msg.handle.GetUInt32(puHandle); + } + } while (rc == VERR_INTERRUPTED && g_fVbglR3GuestCtrlHavePeekGetCancel); + return rc; +} + + +/** + * Retrieves a HOST_FILE_READ message. + */ +VBGLR3DECL(int) VbglR3GuestCtrlFileGetRead(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle, uint32_t *puToRead) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + + AssertReturn(pCtx->uNumParms == 3, VERR_INVALID_PARAMETER); + AssertPtrReturn(puHandle, VERR_INVALID_POINTER); + AssertPtrReturn(puToRead, VERR_INVALID_POINTER); + + int rc; + do + { + HGCMMsgFileRead Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, vbglR3GuestCtrlGetMsgFunctionNo(pCtx->uClientID), pCtx->uNumParms); + VbglHGCMParmUInt32Set(&Msg.context, HOST_MSG_FILE_READ); + VbglHGCMParmUInt32Set(&Msg.handle, 0); + VbglHGCMParmUInt32Set(&Msg.size, 0); + + rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); + if (RT_SUCCESS(rc)) + { + Msg.context.GetUInt32(&pCtx->uContextID); + Msg.handle.GetUInt32(puHandle); + Msg.size.GetUInt32(puToRead); + } + } while (rc == VERR_INTERRUPTED && g_fVbglR3GuestCtrlHavePeekGetCancel); + return rc; +} + + +/** + * Retrieves a HOST_FILE_READ_AT message. + */ +VBGLR3DECL(int) VbglR3GuestCtrlFileGetReadAt(PVBGLR3GUESTCTRLCMDCTX pCtx, + uint32_t *puHandle, uint32_t *puToRead, uint64_t *poffAt) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + + AssertReturn(pCtx->uNumParms == 4, VERR_INVALID_PARAMETER); + AssertPtrReturn(puHandle, VERR_INVALID_POINTER); + AssertPtrReturn(puToRead, VERR_INVALID_POINTER); + + int rc; + do + { + HGCMMsgFileReadAt Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, vbglR3GuestCtrlGetMsgFunctionNo(pCtx->uClientID), pCtx->uNumParms); + VbglHGCMParmUInt32Set(&Msg.context, HOST_MSG_FILE_READ_AT); + VbglHGCMParmUInt32Set(&Msg.handle, 0); + VbglHGCMParmUInt64Set(&Msg.offset, 0); + VbglHGCMParmUInt32Set(&Msg.size, 0); + + rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); + if (RT_SUCCESS(rc)) + { + Msg.context.GetUInt32(&pCtx->uContextID); + Msg.handle.GetUInt32(puHandle); + Msg.offset.GetUInt64(poffAt); + Msg.size.GetUInt32(puToRead); + } + } while (rc == VERR_INTERRUPTED && g_fVbglR3GuestCtrlHavePeekGetCancel); + return rc; +} + + +/** + * Retrieves a HOST_FILE_WRITE message. + */ +VBGLR3DECL(int) VbglR3GuestCtrlFileGetWrite(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle, + void *pvData, uint32_t cbData, uint32_t *pcbSize) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + + AssertReturn(pCtx->uNumParms == 4, VERR_INVALID_PARAMETER); + AssertPtrReturn(puHandle, VERR_INVALID_POINTER); + AssertPtrReturn(pvData, VERR_INVALID_POINTER); + AssertReturn(cbData, VERR_INVALID_PARAMETER); + AssertPtrReturn(pcbSize, VERR_INVALID_POINTER); + + int rc; + do + { + HGCMMsgFileWrite Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, vbglR3GuestCtrlGetMsgFunctionNo(pCtx->uClientID), pCtx->uNumParms); + VbglHGCMParmUInt32Set(&Msg.context, HOST_MSG_FILE_WRITE); + VbglHGCMParmUInt32Set(&Msg.handle, 0); + VbglHGCMParmPtrSet(&Msg.data, pvData, cbData); + VbglHGCMParmUInt32Set(&Msg.size, 0); + + rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); + if (RT_SUCCESS(rc)) + { + Msg.context.GetUInt32(&pCtx->uContextID); + Msg.handle.GetUInt32(puHandle); + Msg.size.GetUInt32(pcbSize); + } + } while (rc == VERR_INTERRUPTED && g_fVbglR3GuestCtrlHavePeekGetCancel); + + if ( rc != VERR_TOO_MUCH_DATA + || g_fVbglR3GuestCtrlHavePeekGetCancel) + return rc; + return VERR_BUFFER_OVERFLOW; +} + + +/** + * Retrieves a HOST_FILE_WRITE_AT message. + */ +VBGLR3DECL(int) VbglR3GuestCtrlFileGetWriteAt(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle, + void *pvData, uint32_t cbData, uint32_t *pcbSize, uint64_t *poffAt) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + + AssertReturn(pCtx->uNumParms == 5, VERR_INVALID_PARAMETER); + AssertPtrReturn(puHandle, VERR_INVALID_POINTER); + AssertPtrReturn(pvData, VERR_INVALID_POINTER); + AssertReturn(cbData, VERR_INVALID_PARAMETER); + AssertPtrReturn(pcbSize, VERR_INVALID_POINTER); + + int rc; + do + { + HGCMMsgFileWriteAt Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, vbglR3GuestCtrlGetMsgFunctionNo(pCtx->uClientID), pCtx->uNumParms); + VbglHGCMParmUInt32Set(&Msg.context, HOST_MSG_FILE_WRITE_AT); + VbglHGCMParmUInt32Set(&Msg.handle, 0); + VbglHGCMParmPtrSet(&Msg.data, pvData, cbData); + VbglHGCMParmUInt32Set(&Msg.size, 0); + VbglHGCMParmUInt64Set(&Msg.offset, 0); + + rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); + if (RT_SUCCESS(rc)) + { + Msg.context.GetUInt32(&pCtx->uContextID); + Msg.handle.GetUInt32(puHandle); + Msg.size.GetUInt32(pcbSize); + Msg.offset.GetUInt64(poffAt); + } + } while (rc == VERR_INTERRUPTED && g_fVbglR3GuestCtrlHavePeekGetCancel); + + if ( rc != VERR_TOO_MUCH_DATA + || g_fVbglR3GuestCtrlHavePeekGetCancel) + return rc; + return VERR_BUFFER_OVERFLOW; +} + + +/** + * Retrieves a HOST_FILE_SEEK message. + */ +VBGLR3DECL(int) VbglR3GuestCtrlFileGetSeek(PVBGLR3GUESTCTRLCMDCTX pCtx, + uint32_t *puHandle, uint32_t *puSeekMethod, uint64_t *poffAt) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + + AssertReturn(pCtx->uNumParms == 4, VERR_INVALID_PARAMETER); + AssertPtrReturn(puHandle, VERR_INVALID_POINTER); + AssertPtrReturn(puSeekMethod, VERR_INVALID_POINTER); + AssertPtrReturn(poffAt, VERR_INVALID_POINTER); + + int rc; + do + { + HGCMMsgFileSeek Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, vbglR3GuestCtrlGetMsgFunctionNo(pCtx->uClientID), pCtx->uNumParms); + VbglHGCMParmUInt32Set(&Msg.context, HOST_MSG_FILE_SEEK); + VbglHGCMParmUInt32Set(&Msg.handle, 0); + VbglHGCMParmUInt32Set(&Msg.method, 0); + VbglHGCMParmUInt64Set(&Msg.offset, 0); + + rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); + if (RT_SUCCESS(rc)) + { + Msg.context.GetUInt32(&pCtx->uContextID); + Msg.handle.GetUInt32(puHandle); + Msg.method.GetUInt32(puSeekMethod); + Msg.offset.GetUInt64(poffAt); + } + } while (rc == VERR_INTERRUPTED && g_fVbglR3GuestCtrlHavePeekGetCancel); + return rc; +} + + +/** + * Retrieves a HOST_FILE_TELL message. + */ +VBGLR3DECL(int) VbglR3GuestCtrlFileGetTell(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + + AssertReturn(pCtx->uNumParms == 2, VERR_INVALID_PARAMETER); + AssertPtrReturn(puHandle, VERR_INVALID_POINTER); + + int rc; + do + { + HGCMMsgFileTell Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, vbglR3GuestCtrlGetMsgFunctionNo(pCtx->uClientID), pCtx->uNumParms); + VbglHGCMParmUInt32Set(&Msg.context, HOST_MSG_FILE_TELL); + VbglHGCMParmUInt32Set(&Msg.handle, 0); + + rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); + if (RT_SUCCESS(rc)) + { + Msg.context.GetUInt32(&pCtx->uContextID); + Msg.handle.GetUInt32(puHandle); + } + } while (rc == VERR_INTERRUPTED && g_fVbglR3GuestCtrlHavePeekGetCancel); + return rc; +} + + +/** + * Retrieves a HOST_FILE_SET_SIZE message. + */ +VBGLR3DECL(int) VbglR3GuestCtrlFileGetSetSize(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle, uint64_t *pcbNew) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + + AssertReturn(pCtx->uNumParms == 3, VERR_INVALID_PARAMETER); + AssertPtrReturn(puHandle, VERR_INVALID_POINTER); + AssertPtrReturn(pcbNew, VERR_INVALID_POINTER); + + int rc; + do + { + HGCMMsgFileSetSize Msg; + VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->uClientID, vbglR3GuestCtrlGetMsgFunctionNo(pCtx->uClientID), pCtx->uNumParms); + VbglHGCMParmUInt32Set(&Msg.id32Context, HOST_MSG_FILE_SET_SIZE); + VbglHGCMParmUInt32Set(&Msg.id32Handle, 0); + VbglHGCMParmUInt64Set(&Msg.cb64NewSize, 0); + + rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg)); + if (RT_SUCCESS(rc)) + { + Msg.id32Context.GetUInt32(&pCtx->uContextID); + Msg.id32Handle.GetUInt32(puHandle); + Msg.cb64NewSize.GetUInt64(pcbNew); + } + } while (rc == VERR_INTERRUPTED && g_fVbglR3GuestCtrlHavePeekGetCancel); + return rc; +} + + +/** + * Retrieves a HOST_EXEC_TERMINATE message. + */ +VBGLR3DECL(int) VbglR3GuestCtrlProcGetTerminate(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puPID) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + + AssertReturn(pCtx->uNumParms == 2, VERR_INVALID_PARAMETER); + AssertPtrReturn(puPID, VERR_INVALID_POINTER); + + int rc; + do + { + HGCMMsgProcTerminate Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, vbglR3GuestCtrlGetMsgFunctionNo(pCtx->uClientID), pCtx->uNumParms); + VbglHGCMParmUInt32Set(&Msg.context, HOST_MSG_EXEC_TERMINATE); + VbglHGCMParmUInt32Set(&Msg.pid, 0); + + rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); + if (RT_SUCCESS(rc)) + { + Msg.context.GetUInt32(&pCtx->uContextID); + Msg.pid.GetUInt32(puPID); + } + } while (rc == VERR_INTERRUPTED && g_fVbglR3GuestCtrlHavePeekGetCancel); + return rc; +} + + +/** + * Retrieves a HOST_EXEC_WAIT_FOR message. + */ +VBGLR3DECL(int) VbglR3GuestCtrlProcGetWaitFor(PVBGLR3GUESTCTRLCMDCTX pCtx, + uint32_t *puPID, uint32_t *puWaitFlags, uint32_t *puTimeoutMS) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + + AssertReturn(pCtx->uNumParms == 5, VERR_INVALID_PARAMETER); + AssertPtrReturn(puPID, VERR_INVALID_POINTER); + + int rc; + do + { + HGCMMsgProcWaitFor Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, vbglR3GuestCtrlGetMsgFunctionNo(pCtx->uClientID), pCtx->uNumParms); + VbglHGCMParmUInt32Set(&Msg.context, HOST_MSG_EXEC_WAIT_FOR); + VbglHGCMParmUInt32Set(&Msg.pid, 0); + VbglHGCMParmUInt32Set(&Msg.flags, 0); + VbglHGCMParmUInt32Set(&Msg.timeout, 0); + + rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); + if (RT_SUCCESS(rc)) + { + Msg.context.GetUInt32(&pCtx->uContextID); + Msg.pid.GetUInt32(puPID); + Msg.flags.GetUInt32(puWaitFlags); + Msg.timeout.GetUInt32(puTimeoutMS); + } + } while (rc == VERR_INTERRUPTED && g_fVbglR3GuestCtrlHavePeekGetCancel); + return rc; +} + + +/** + * Replies to a HOST_MSG_FILE_OPEN message. + * + * @returns VBox status code. + * @param pCtx Guest control command context to use. + * @param uRc Guest rc of operation (note: IPRT-style signed int). + * @param uFileHandle File handle of opened file on success. + */ +VBGLR3DECL(int) VbglR3GuestCtrlFileCbOpen(PVBGLR3GUESTCTRLCMDCTX pCtx, + uint32_t uRc, uint32_t uFileHandle) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + + HGCMReplyFileNotify Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, GUEST_MSG_FILE_NOTIFY, 4); + VbglHGCMParmUInt32Set(&Msg.context, pCtx->uContextID); + VbglHGCMParmUInt32Set(&Msg.type, GUEST_FILE_NOTIFYTYPE_OPEN); + VbglHGCMParmUInt32Set(&Msg.rc, uRc); + VbglHGCMParmUInt32Set(&Msg.u.open.handle, uFileHandle); + + return VbglR3HGCMCall(&Msg.hdr, RT_UOFFSET_AFTER(HGCMReplyFileNotify, u.open)); +} + + +/** + * Replies to a HOST_MSG_FILE_CLOSE message. + * + * @returns VBox status code. + * @param pCtx Guest control command context to use. + * @param uRc Guest rc of operation (note: IPRT-style signed int). + */ +VBGLR3DECL(int) VbglR3GuestCtrlFileCbClose(PVBGLR3GUESTCTRLCMDCTX pCtx, + uint32_t uRc) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + + HGCMReplyFileNotify Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, GUEST_MSG_FILE_NOTIFY, 3); + VbglHGCMParmUInt32Set(&Msg.context, pCtx->uContextID); + VbglHGCMParmUInt32Set(&Msg.type, GUEST_FILE_NOTIFYTYPE_CLOSE); + VbglHGCMParmUInt32Set(&Msg.rc, uRc); + + return VbglR3HGCMCall(&Msg.hdr, RT_UOFFSETOF(HGCMReplyFileNotify, u)); +} + + +/** + * Sends an unexpected file handling error to the host. + * + * @returns VBox status code. + * @param pCtx Guest control command context to use. + * @param uRc Guest rc of operation (note: IPRT-style signed int). + */ +VBGLR3DECL(int) VbglR3GuestCtrlFileCbError(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + + HGCMReplyFileNotify Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, GUEST_MSG_FILE_NOTIFY, 3); + VbglHGCMParmUInt32Set(&Msg.context, pCtx->uContextID); + VbglHGCMParmUInt32Set(&Msg.type, GUEST_FILE_NOTIFYTYPE_ERROR); + VbglHGCMParmUInt32Set(&Msg.rc, uRc); + + return VbglR3HGCMCall(&Msg.hdr, RT_UOFFSETOF(HGCMReplyFileNotify, u)); +} + + +/** + * Replies to a HOST_MSG_FILE_READ message. + * + * @returns VBox status code. + * @param pCtx Guest control command context to use. + * @param uRc Guest rc of operation (note: IPRT-style signed int). + * @param pvData Pointer to read file data from guest on success. + * @param cbData Size (in bytes) of read file data from guest on success. + */ +VBGLR3DECL(int) VbglR3GuestCtrlFileCbRead(PVBGLR3GUESTCTRLCMDCTX pCtx, + uint32_t uRc, + void *pvData, uint32_t cbData) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + + HGCMReplyFileNotify Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, GUEST_MSG_FILE_NOTIFY, 4); + VbglHGCMParmUInt32Set(&Msg.context, pCtx->uContextID); + VbglHGCMParmUInt32Set(&Msg.type, GUEST_FILE_NOTIFYTYPE_READ); + VbglHGCMParmUInt32Set(&Msg.rc, uRc); + VbglHGCMParmPtrSet(&Msg.u.read.data, pvData, cbData); + + return VbglR3HGCMCall(&Msg.hdr, RT_UOFFSET_AFTER(HGCMReplyFileNotify, u.read)); +} + + +/** + * Replies to a HOST_MSG_FILE_READ_AT message. + * + * @returns VBox status code. + * @param pCtx Guest control command context to use. + * @param uRc Guest rc of operation (note: IPRT-style signed int). + * @param pvData Pointer to read file data from guest on success. + * @param cbData Size (in bytes) of read file data from guest on success. + * @param offNew New offset (in bytes) the guest file pointer points at on success. + */ +VBGLR3DECL(int) VbglR3GuestCtrlFileCbReadOffset(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, + void *pvData, uint32_t cbData, int64_t offNew) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + + HGCMReplyFileNotify Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, GUEST_MSG_FILE_NOTIFY, 5); + VbglHGCMParmUInt32Set(&Msg.context, pCtx->uContextID); + VbglHGCMParmUInt32Set(&Msg.type, GUEST_FILE_NOTIFYTYPE_READ_OFFSET); + VbglHGCMParmUInt32Set(&Msg.rc, uRc); + VbglHGCMParmPtrSet(&Msg.u.ReadOffset.pvData, pvData, cbData); + VbglHGCMParmUInt64Set(&Msg.u.ReadOffset.off64New, (uint64_t)offNew); + + return VbglR3HGCMCall(&Msg.hdr, RT_UOFFSET_AFTER(HGCMReplyFileNotify, u.ReadOffset)); +} + + +/** + * Replies to a HOST_MSG_FILE_WRITE message. + * + * @returns VBox status code. + * @param pCtx Guest control command context to use. + * @param uRc Guest rc of operation (note: IPRT-style signed int). + * @param cbWritten Size (in bytes) of file data successfully written to guest file. Can be partial. + */ +VBGLR3DECL(int) VbglR3GuestCtrlFileCbWrite(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, uint32_t cbWritten) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + + HGCMReplyFileNotify Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, GUEST_MSG_FILE_NOTIFY, 4); + VbglHGCMParmUInt32Set(&Msg.context, pCtx->uContextID); + VbglHGCMParmUInt32Set(&Msg.type, GUEST_FILE_NOTIFYTYPE_WRITE); + VbglHGCMParmUInt32Set(&Msg.rc, uRc); + VbglHGCMParmUInt32Set(&Msg.u.write.written, cbWritten); + + return VbglR3HGCMCall(&Msg.hdr, RT_UOFFSET_AFTER(HGCMReplyFileNotify, u.write)); +} + + +/** + * Replies to a HOST_MSG_FILE_WRITE_AT message. + * + * @returns VBox status code. + * @param pCtx Guest control command context to use. + * @param uRc Guest rc of operation (note: IPRT-style signed int). + * @param cbWritten Size (in bytes) of file data successfully written to guest file. Can be partial. + * @param offNew New offset (in bytes) the guest file pointer points at on success. + */ +VBGLR3DECL(int) VbglR3GuestCtrlFileCbWriteOffset(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, uint32_t cbWritten, int64_t offNew) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + + HGCMReplyFileNotify Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, GUEST_MSG_FILE_NOTIFY, 5); + VbglHGCMParmUInt32Set(&Msg.context, pCtx->uContextID); + VbglHGCMParmUInt32Set(&Msg.type, GUEST_FILE_NOTIFYTYPE_WRITE_OFFSET); + VbglHGCMParmUInt32Set(&Msg.rc, uRc); + VbglHGCMParmUInt32Set(&Msg.u.WriteOffset.cb32Written, cbWritten); + VbglHGCMParmUInt64Set(&Msg.u.WriteOffset.off64New, (uint64_t)offNew); + + return VbglR3HGCMCall(&Msg.hdr, RT_UOFFSET_AFTER(HGCMReplyFileNotify, u.WriteOffset)); +} + + +/** + * Replies to a HOST_MSG_FILE_SEEK message. + * + * @returns VBox status code. + * @param pCtx Guest control command context to use. + * @param uRc Guest rc of operation (note: IPRT-style signed int). + * @param offCurrent New offset (in bytes) the guest file pointer points at on success. + */ +VBGLR3DECL(int) VbglR3GuestCtrlFileCbSeek(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, uint64_t offCurrent) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + + HGCMReplyFileNotify Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, GUEST_MSG_FILE_NOTIFY, 4); + VbglHGCMParmUInt32Set(&Msg.context, pCtx->uContextID); + VbglHGCMParmUInt32Set(&Msg.type, GUEST_FILE_NOTIFYTYPE_SEEK); + VbglHGCMParmUInt32Set(&Msg.rc, uRc); + VbglHGCMParmUInt64Set(&Msg.u.seek.offset, offCurrent); + + return VbglR3HGCMCall(&Msg.hdr, RT_UOFFSET_AFTER(HGCMReplyFileNotify, u.seek)); +} + + +/** + * Replies to a HOST_MSG_FILE_TELL message. + * + * @returns VBox status code. + * @param pCtx Guest control command context to use. + * @param uRc Guest rc of operation (note: IPRT-style signed int). + * @param offCurrent Current offset (in bytes) the guest file pointer points at on success. + */ +VBGLR3DECL(int) VbglR3GuestCtrlFileCbTell(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, uint64_t offCurrent) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + + HGCMReplyFileNotify Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, GUEST_MSG_FILE_NOTIFY, 4); + VbglHGCMParmUInt32Set(&Msg.context, pCtx->uContextID); + VbglHGCMParmUInt32Set(&Msg.type, GUEST_FILE_NOTIFYTYPE_TELL); + VbglHGCMParmUInt32Set(&Msg.rc, uRc); + VbglHGCMParmUInt64Set(&Msg.u.tell.offset, offCurrent); + + return VbglR3HGCMCall(&Msg.hdr, RT_UOFFSET_AFTER(HGCMReplyFileNotify, u.tell)); +} + + +/** + * Replies to a HOST_MSG_FILE_SET_SIZE message. + * + * @returns VBox status code. + * @param pCtx Guest control command context to use. + * @param uRc Guest rc of operation (note: IPRT-style signed int). + * @param cbNew New file size (in bytes) of the guest file on success. + */ +VBGLR3DECL(int) VbglR3GuestCtrlFileCbSetSize(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, uint64_t cbNew) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + + HGCMReplyFileNotify Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, GUEST_MSG_FILE_NOTIFY, 4); + VbglHGCMParmUInt32Set(&Msg.context, pCtx->uContextID); + VbglHGCMParmUInt32Set(&Msg.type, GUEST_FILE_NOTIFYTYPE_SET_SIZE); + VbglHGCMParmUInt32Set(&Msg.rc, uRc); + VbglHGCMParmUInt64Set(&Msg.u.SetSize.cb64Size, cbNew); + + return VbglR3HGCMCall(&Msg.hdr, RT_UOFFSET_AFTER(HGCMReplyFileNotify, u.SetSize)); +} + + +/** + * Callback for reporting a guest process status (along with some other stuff) to the host. + * + * @returns VBox status code. + * @param pCtx Guest control command context to use. + * @param uPID Guest process PID to report status for. + * @param uStatus Status to report. Of type PROC_STS_XXX. + * @param fFlags Additional status flags, depending on the reported status. See RTPROCSTATUS. + * @param pvData Pointer to additional status data. Optional. + * @param cbData Size (in bytes) of additional status data. + */ +VBGLR3DECL(int) VbglR3GuestCtrlProcCbStatus(PVBGLR3GUESTCTRLCMDCTX pCtx, + uint32_t uPID, uint32_t uStatus, uint32_t fFlags, + void *pvData, uint32_t cbData) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + + HGCMMsgProcStatus Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, GUEST_MSG_EXEC_STATUS, 5); + VbglHGCMParmUInt32Set(&Msg.context, pCtx->uContextID); + VbglHGCMParmUInt32Set(&Msg.pid, uPID); + VbglHGCMParmUInt32Set(&Msg.status, uStatus); + VbglHGCMParmUInt32Set(&Msg.flags, fFlags); + VbglHGCMParmPtrSet(&Msg.data, pvData, cbData); + + return VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); +} + + +/** + * Sends output (from stdout/stderr) from a running process. + * + * @returns VBox status code. + * @param pCtx Guest control command context to use. + * @param uPID Guest process PID to report status for. + * @param uHandle Guest process handle the output belong to. + * @param fFlags Additional output flags. + * @param pvData Pointer to actual output data. + * @param cbData Size (in bytes) of output data. + */ +VBGLR3DECL(int) VbglR3GuestCtrlProcCbOutput(PVBGLR3GUESTCTRLCMDCTX pCtx, + uint32_t uPID,uint32_t uHandle, uint32_t fFlags, + void *pvData, uint32_t cbData) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + + HGCMMsgProcOutput Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, GUEST_MSG_EXEC_OUTPUT, 5); + VbglHGCMParmUInt32Set(&Msg.context, pCtx->uContextID); + VbglHGCMParmUInt32Set(&Msg.pid, uPID); + VbglHGCMParmUInt32Set(&Msg.handle, uHandle); + VbglHGCMParmUInt32Set(&Msg.flags, fFlags); + VbglHGCMParmPtrSet(&Msg.data, pvData, cbData); + + return VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); +} + + +/** + * Callback for reporting back the input status of a guest process to the host. + * + * @returns VBox status code. + * @param pCtx Guest control command context to use. + * @param uPID Guest process PID to report status for. + * @param uStatus Status to report. Of type INPUT_STS_XXX. + * @param fFlags Additional input flags. + * @param cbWritten Size (in bytes) of input data handled. + */ +VBGLR3DECL(int) VbglR3GuestCtrlProcCbStatusInput(PVBGLR3GUESTCTRLCMDCTX pCtx, + uint32_t uPID, uint32_t uStatus, + uint32_t fFlags, uint32_t cbWritten) +{ + AssertPtrReturn(pCtx, VERR_INVALID_POINTER); + + HGCMMsgProcStatusInput Msg; + VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, GUEST_MSG_EXEC_INPUT_STATUS, 5); + VbglHGCMParmUInt32Set(&Msg.context, pCtx->uContextID); + VbglHGCMParmUInt32Set(&Msg.pid, uPID); + VbglHGCMParmUInt32Set(&Msg.status, uStatus); + VbglHGCMParmUInt32Set(&Msg.flags, fFlags); + VbglHGCMParmUInt32Set(&Msg.written, cbWritten); + + return VbglR3HGCMCall(&Msg.hdr, sizeof(Msg)); +} + |