VirtualBox

Changeset 42864 in vbox


Ignore:
Timestamp:
Aug 17, 2012 1:36:01 PM (12 years ago)
Author:
vboxsync
Message:

Main/Guest control: Removed old API.

Location:
trunk/src/VBox/Main
Files:
4 deleted
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/Makefile.kmk

    r42838 r42864  
    625625        src-client/GuestSessionImpl.cpp \
    626626        src-client/GuestCtrlImpl.cpp \
    627         src-client/GuestCtrlImplDir.cpp \
    628         src-client/GuestCtrlImplFile.cpp \
    629627        src-client/KeyboardImpl.cpp \
    630628        src-client/MachineDebuggerImpl.cpp \
     
    646644VBoxC_SOURCES += \
    647645        src-client/GuestSessionImplTasks.cpp \
    648         src-client/GuestCtrlPrivate.cpp \
    649         src-client/GuestCtrlImplTasks.cpp \
    650         src-client/GuestDirEntryImpl.cpp
     646        src-client/GuestCtrlPrivate.cpp
    651647endif
    652648
     
    680676VBoxC_SOURCES += \
    681677        src-client/EbmlWriter.cpp \
    682         src-client/VideoRec.cpp 
     678        src-client/VideoRec.cpp
    683679endif
    684680
  • trunk/src/VBox/Main/idl/VirtualBox.xidl

    r42846 r42864  
    89148914
    89158915  <enum
    8916     name="ExecuteProcessFlag"
    8917     uuid="1c49b831-b2c7-4a30-97dd-999a2e2cbf90"
    8918     >
    8919     <desc>
    8920       Guest process execution flags.
    8921     </desc>
    8922 
    8923     <const name="None"                    value="0">
    8924       <desc>No flag set.</desc>
    8925     </const>
    8926     <const name="WaitForProcessStartOnly" value="1">
    8927       <desc>Only use the specified timeout value to wait for starting the guest process - the guest
    8928         process itself then uses an infinite timeout.</desc>
    8929     </const>
    8930     <const name="IgnoreOrphanedProcesses" value="2">
    8931       <desc>Do not report an error when executed processes are still alive when VBoxService or the guest OS is shutting down.</desc>
    8932     </const>
    8933     <const name="Hidden"                  value="4">
    8934       <desc>Do not show the started process according to the guest OS guidelines.</desc>
    8935     </const>
    8936     <const name="NoProfile"               value="8">
    8937       <desc>Do not use the user's profile data when exeuting a process. Only available for Windows guests.</desc>
    8938     </const>
    8939     <const name="WaitForStdOut"           value="16">
    8940       <desc>The guest process waits until all data from stdout is read out.</desc>
    8941     </const>
    8942     <const name="WaitForStdErr"           value="32">
    8943       <desc>The guest process waits until all data from stderr is read out.</desc>
    8944     </const>
    8945   </enum>
    8946 
    8947   <enum
    8948     name="ExecuteProcessStatus"
    8949     uuid="153768d9-d971-4098-8b5a-c5cb1ab9ea88"
    8950     >
    8951     <desc>
    8952       Guest process execution status.
    8953     </desc>
    8954     <const name="Undefined"               value="0">
    8955       <desc>Process is in an undefined state.</desc>
    8956     </const>
    8957 
    8958     <const name="Started"                 value="1">
    8959       <desc>Process has been started.</desc>
    8960     </const>
    8961     <const name="TerminatedNormally"      value="2">
    8962       <desc>Process terminated normally.</desc>
    8963     </const>
    8964     <const name="TerminatedSignal"        value="3">
    8965       <desc>Process terminated via signal.</desc>
    8966     </const>
    8967     <const name="TerminatedAbnormally"    value="4">
    8968       <desc>Process terminated abnormally.</desc>
    8969     </const>
    8970      <const name="TimedOutKilled"         value="5">
    8971       <desc>Process timed out and was killed.</desc>
    8972     </const>
    8973     <const name="TimedOutAbnormally"      value="6">
    8974       <desc>Process timed out and was not killed successfully.</desc>
    8975     </const>
    8976     <const name="Down"                    value="7">
    8977       <desc>Service/OS is stopping, process was killed.</desc>
    8978     </const>
    8979     <const name="Error"                   value="8">
    8980       <desc>Something went wrong (error code in flags).</desc>
    8981     </const>
    8982   </enum>
    8983 
    8984   <enum
    89858916    name="FileSeekType"
    89868917    uuid="1b73f4f3-3515-4073-a506-76878d9e2541"
     
    94069337  </enum>
    94079338
    9408   <enum
    9409     name="GuestDirEntryType"
    9410     uuid="6d19d924-1b77-4fc8-b369-a3b2c85c8241"
    9411     >
    9412     <desc>
    9413       Guest directory entry type.
    9414     </desc>
    9415     <const name="Unknown"                 value="0">
    9416       <desc>Unknown.</desc>
    9417     </const>
    9418     <const name="Directory"               value="4">
    9419       <desc>Regular file.</desc>
    9420     </const>
    9421     <const name="File"                    value="10">
    9422       <desc>Regular file.</desc>
    9423     </const>
    9424     <const name="Symlink"                 value="12">
    9425       <desc>Symbolic link.</desc>
    9426     </const>
    9427   </enum>
    9428 
    9429   <interface
    9430     name="IGuestDirEntry" extends="$unknown"
    9431     uuid="20a66efc-c2f6-4438-826f-38454c04369e"
    9432     wsmap="struct"
    9433     >
    9434     <desc>
    9435       Structure representing a directory entry on the guest OS.
    9436     </desc>
    9437     <attribute name="nodeId" type="long long" readonly="yes">
    9438       <desc>The unique identifier (within the guest's file system) of this file system object.</desc>
    9439     </attribute>
    9440     <attribute name="name" type="wstring" readonly="yes">
    9441       <desc>The filename.</desc>
    9442     </attribute>
    9443     <attribute name="type" type="GuestDirEntryType" readonly="yes">
    9444       <desc>The entry type.</desc>
    9445     </attribute>
    9446   </interface>
    9447 
    94489339  <interface
    94499340    name="IGuestSession" extends="$unknown"
     
    1127511166        </desc>
    1127611167      </param>
    11277     </method>
    11278 
    11279     <method name="executeProcess">
    11280       <desc>
    11281         Executes an existing program inside the guest VM.
    11282 
    11283         <note>
    11284         Starting at VirtualBox 4.1.8 guest process execution by default is limited
    11285         to serve up to 25 guest processes at a time. If all 25 guest processes
    11286         are still active and running, starting a new guest process will result in an
    11287         appropriate error message.
    11288 
    11289         If ExecuteProcessFlag_WaitForStdOut and/or respectively
    11290         ExecuteProcessFlag_WaitForStdErr of <link to="ExecuteProcessFlag"/> is
    11291         set, the guest process will not exit until all data from the specified
    11292         stream(s) is/are read out.
    11293 
    11294         To raise or lower the guest process execution limit, either the guest property
    11295         "/VirtualBox/GuestAdd/VBoxService/--control-procs-max-kept" or VBoxService'
    11296         command line by specifying "--control-procs-max-kept" needs to be modified.
    11297         A restart of the guest OS is required afterwards. To serve unlimited guest
    11298         processes, a value of "0" needs to be set (not recommended).
    11299         </note>
    11300 
    11301         <result name="VBOX_E_IPRT_ERROR">
    11302           Could not execute process.
    11303         </result>
    11304 
    11305       </desc>
    11306       <param name="execName" type="wstring" dir="in">
    11307         <desc>
    11308           Full path name of the command to execute on the guest; the
    11309           commands has to exists in the guest VM in order to be executed.
    11310         </desc>
    11311       </param>
    11312       <param name="flags" type="unsigned long" dir="in">
    11313         <desc>
    11314           <link to="ExecuteProcessFlag"/> flags.
    11315         </desc>
    11316       </param>
    11317       <param name="arguments" type="wstring" safearray="yes" dir="in">
    11318         <desc>
    11319           Array of arguments passed to the execution command.
    11320         </desc>
    11321       </param>
    11322       <param name="environment" type="wstring" safearray="yes" dir="in">
    11323         <desc>
    11324           Environment variables that can be set while the command is being
    11325           executed, in form of "NAME=VALUE"; one pair per entry. To unset a
    11326           variable just set its name ("NAME") without a value.
    11327         </desc>
    11328       </param>
    11329       <param name="userName" type="wstring" dir="in">
    11330         <desc>
    11331           User name under which the command will be executed; has to exist
    11332           and have the appropriate rights to execute programs in the VM.
    11333         </desc>
    11334       </param>
    11335       <param name="password" type="wstring" dir="in">
    11336         <desc>
    11337           Password of the user account specified.
    11338         </desc>
    11339       </param>
    11340       <param name="timeoutMS" type="unsigned long" dir="in">
    11341         <desc>
    11342           The maximum timeout value (in msec) to wait for finished program
    11343           execution. Pass 0 for an infinite timeout.
    11344         </desc>
    11345       </param>
    11346       <param name="pid" type="unsigned long" dir="out">
    11347         <desc>
    11348           The PID (process ID) of the started command for later reference.
    11349         </desc>
    11350       </param>
    11351       <param name="progress" type="IProgress" dir="return">
    11352         <desc>Progress object to track the operation completion.</desc>
    11353       </param>
    11354     </method>
    11355 
    11356     <method name="getProcessOutput">
    11357       <desc>
    11358         Retrieves output of a formerly started and running guest process.
    11359 
    11360         <note>
    11361         Starting with VirtualBox 4.1.8 this only will return output data
    11362         from stdout or stderr if flag ExecuteProcessFlag_WaitForStdOut
    11363         and/or respectively ExecuteProcessFlag_WaitForStdErr of
    11364         <link to="ExecuteProcessFlag"/> is set in the
    11365         former <link to="#executeProcess"/> call for this guest process.
    11366         </note>
    11367 
    11368         <result name="VBOX_E_IPRT_ERROR">
    11369           Could not retrieve output.
    11370         </result>
    11371 
    11372       </desc>
    11373       <param name="pid" type="unsigned long" dir="in">
    11374         <desc>
    11375           Process id returned by earlier <link to="#executeProcess"/> call.
    11376         </desc>
    11377       </param>
    11378       <param name="flags" type="unsigned long" dir="in">
    11379         <desc>
    11380           <link to="ProcessOutputFlag"/> flags.
    11381         </desc>
    11382       </param>
    11383       <param name="timeoutMS" type="unsigned long" dir="in">
    11384         <desc>
    11385           The maximum timeout value (in msec) to wait for output
    11386           data. Pass 0 for an infinite timeout.
    11387         </desc>
    11388       </param>
    11389       <param name="size" type="long long" dir="in">
    11390         <desc>
    11391           Size in bytes to read in the buffer.
    11392         </desc>
    11393       </param>
    11394       <param name="data" type="octet" safearray="yes" dir="return">
    11395         <desc>
    11396           Buffer for retrieving the actual output. A data size of 0 means end of file
    11397           if the requested size was not 0. This is the unprocessed
    11398           output data, i.e. the line ending style depends on the platform of
    11399           the system the server is running on.
    11400         </desc>
    11401       </param>
    11402     </method>
    11403 
    11404     <method name="getProcessStatus">
    11405       <desc>
    11406         Retrieves status, exit code and the exit reason of a formerly started
    11407         guest process. If a guest process exited or got terminated this function
    11408         returns its final status and removes this process from the list of
    11409         known guest processes for further retrieval.
    11410 
    11411         <result name="VBOX_E_IPRT_ERROR">
    11412           Process with specified PID was not found.
    11413         </result>
    11414 
    11415       </desc>
    11416       <param name="pid" type="unsigned long" dir="in">
    11417         <desc>
    11418           Process id returned by earlier <link to="#executeProcess"/> call.
    11419         </desc>
    11420       </param>
    11421       <param name="exitcode" type="unsigned long" dir="out">
    11422         <desc>
    11423           The exit code (if available).
    11424         </desc>
    11425       </param>
    11426       <param name="flags" type="unsigned long" dir="out">
    11427         <desc>
    11428           Additional flags of process status. Not used at the moment and
    11429           must be set to 0.
    11430         </desc>
    11431       </param>
    11432       <param name="reason" type="ExecuteProcessStatus" dir="return">
    11433         <desc>
    11434           The current process status.
    11435         </desc>
    11436       </param>
    11437     </method>
    11438 
    11439     <method name="copyFromGuest">
    11440       <desc>
    11441         Copies files/directories from guest to the host.
    11442 
    11443         <result name="VBOX_E_IPRT_ERROR">
    11444           Error while copying.
    11445         </result>
    11446 
    11447       </desc>
    11448       <param name="source" type="wstring" dir="in">
    11449         <desc>
    11450           Source file on the guest to copy.
    11451         </desc>
    11452       </param>
    11453       <param name="dest" type="wstring" dir="in">
    11454         <desc>
    11455           Destination path on the host.
    11456         </desc>
    11457       </param>
    11458       <param name="userName" type="wstring" dir="in">
    11459         <desc>
    11460           User name under which the copy command will be executed; the
    11461           user has to exist and have the appropriate rights to read from
    11462           the source path.
    11463         </desc>
    11464       </param>
    11465       <param name="password" type="wstring" dir="in">
    11466         <desc>
    11467           Password of the user account specified.
    11468         </desc>
    11469       </param>
    11470       <param name="flags" type="unsigned long" dir="in">
    11471         <desc>
    11472           <link to="CopyFileFlag"/> flags. Not used at the moment and should be set to 0.
    11473         </desc>
    11474       </param>
    11475       <param name="progress" type="IProgress" dir="return">
    11476         <desc>Progress object to track the operation completion.</desc>
    11477       </param>
    11478     </method>
    11479 
    11480     <method name="copyToGuest">
    11481       <desc>
    11482         Copies files/directories from host to the guest.
    11483 
    11484         <result name="VBOX_E_IPRT_ERROR">
    11485           Error while copying.
    11486         </result>
    11487 
    11488       </desc>
    11489       <param name="source" type="wstring" dir="in">
    11490         <desc>
    11491           Source file on the host to copy.
    11492         </desc>
    11493       </param>
    11494       <param name="dest" type="wstring" dir="in">
    11495         <desc>
    11496           Destination path on the guest.
    11497         </desc>
    11498       </param>
    11499       <param name="userName" type="wstring" dir="in">
    11500         <desc>
    11501           User name under which the copy command will be executed; the
    11502           user has to exist and have the appropriate rights to write to
    11503           the destination path.
    11504         </desc>
    11505       </param>
    11506       <param name="password" type="wstring" dir="in">
    11507         <desc>
    11508           Password of the user account specified.
    11509         </desc>
    11510       </param>
    11511       <param name="flags" type="unsigned long" dir="in">
    11512         <desc>
    11513           <link to="CopyFileFlag"/> flags. Not used at the moment and should be set to 0.
    11514         </desc>
    11515       </param>
    11516       <param name="progress" type="IProgress" dir="return">
    11517         <desc>Progress object to track the operation completion.</desc>
    11518       </param>
    11519     </method>
    11520 
    11521     <method name="directoryClose">
    11522       <desc>
    11523         Closes a formerly opened guest directory.
    11524 
    11525         <result name="VBOX_E_IPRT_ERROR">
    11526           Error while closing directory.
    11527         </result>
    11528 
    11529       </desc>
    11530       <param name="handle" type="unsigned long" dir="in">
    11531         <desc>
    11532           Handle of opened directory to close.
    11533         </desc>
    11534       </param>
    11535     </method>
    11536 
    11537     <method name="directoryCreate">
    11538       <desc>
    11539         Creates a directory on the guest.
    11540 
    11541         <result name="VBOX_E_IPRT_ERROR">
    11542           Error while creating directory.
    11543         </result>
    11544 
    11545       </desc>
    11546       <param name="directory" type="wstring" dir="in">
    11547         <desc>
    11548           Directory to create.
    11549         </desc>
    11550       </param>
    11551       <param name="userName" type="wstring" dir="in">
    11552         <desc>
    11553           User name under which the directory creation will be executed; the
    11554           user has to exist and have the appropriate rights to create the
    11555           desired directory.
    11556         </desc>
    11557       </param>
    11558       <param name="password" type="wstring" dir="in">
    11559         <desc>
    11560           Password of the user account specified.
    11561         </desc>
    11562       </param>
    11563       <param name="mode" type="unsigned long" dir="in">
    11564         <desc>
    11565           File mode.
    11566         </desc>
    11567       </param>
    11568       <param name="flags" type="unsigned long" dir="in">
    11569         <desc>
    11570           <link to="DirectoryCreateFlag"/> flags.
    11571         </desc>
    11572       </param>
    11573     </method>
    11574 
    11575     <method name="directoryOpen">
    11576       <desc>
    11577         Opens a directory on the guest.
    11578 
    11579         <result name="VBOX_E_IPRT_ERROR">
    11580           Error while opening / reading directory.
    11581         </result>
    11582 
    11583       </desc>
    11584       <param name="directory" type="wstring" dir="in">
    11585         <desc>
    11586           Directory to read.
    11587         </desc>
    11588       </param>
    11589       <param name="filter" type="wstring" dir="in">
    11590         <desc>
    11591           Directory filter (DOS style wildcards). Set to empty
    11592           string if no filter required.
    11593         </desc>
    11594       </param>
    11595       <param name="flags" type="unsigned long" dir="in">
    11596         <desc>
    11597           <link to="DirectoryOpenFlag"/> flags.
    11598         </desc>
    11599       </param>
    11600       <param name="userName" type="wstring" dir="in">
    11601         <desc>
    11602           User name under which the directory reading will be performed; the
    11603           user has to exist and have the appropriate rights to access / read the
    11604           desired directory.
    11605         </desc>
    11606       </param>
    11607       <param name="password" type="wstring" dir="in">
    11608         <desc>
    11609           Password of the user account specified.
    11610         </desc>
    11611       </param>
    11612       <param name="handle" type="unsigned long" dir="return">
    11613         <desc>
    11614           Handle of opened directory returned by openDirectory.
    11615         </desc>
    11616       </param>
    11617     </method>
    11618 
    11619     <method name="directoryRead">
    11620       <desc>
    11621         Reads the next directory entry of an opened guest directory.
    11622 
    11623         <result name="E_ABORT">
    11624           When the end of the directory has been reached.
    11625         </result>
    11626 
    11627         <result name="VBOX_E_IPRT_ERROR">
    11628           Error while opening / reading directory.
    11629         </result>
    11630 
    11631       </desc>
    11632       <param name="handle" type="unsigned long" dir="in">
    11633         <desc>
    11634           Handle of opened directory returned by openDirectory.
    11635         </desc>
    11636       </param>
    11637       <param name="entry" type="IGuestDirEntry" dir="return">
    11638         <desc>
    11639           Information about next directory entry on success.
    11640         </desc>
    11641       </param>
    11642     </method>
    11643 
    11644     <method name="fileExists">
    11645       <desc>
    11646         Checks if the specified file name exists and is a regular file.
    11647 
    11648         If the file name ends with a slash or backslash, the function assumes
    11649         it's a directory and will check if the specified directory exists and
    11650         is a regular directory.
    11651 
    11652         <result name="VBOX_E_IPRT_ERROR">
    11653           Error while looking up information.
    11654         </result>
    11655 
    11656       </desc>
    11657       <param name="file" type="wstring" dir="in">
    11658         <desc>
    11659           Full path of file to check.
    11660         </desc>
    11661       </param>
    11662       <param name="userName" type="wstring" dir="in">
    11663         <desc>
    11664           User name under which the lookup will be performed; the
    11665           user has to exist and have the appropriate rights to access / read the
    11666           desired directory.
    11667         </desc>
    11668       </param>
    11669       <param name="password" type="wstring" dir="in">
    11670         <desc>
    11671           Password of the user account specified.
    11672         </desc>
    11673       </param>
    11674       <param name="exists" type="boolean" dir="return">
    11675         <desc>
    11676           True if it's a regular file, false if it isn't (or doesn't exist).
    11677         </desc>
    11678       </param>
    11679     </method>
    11680 
    11681     <method name="fileQuerySize">
    11682       <desc>
    11683         Queries the size of a file, given the path to it.
    11684 
    11685         <result name="VBOX_E_IPRT_ERROR">
    11686           Error while looking up information.
    11687         </result>
    11688 
    11689       </desc>
    11690       <param name="file" type="wstring" dir="in">
    11691         <desc>
    11692           Full path of file to query file size for.
    11693         </desc>
    11694       </param>
    11695       <param name="userName" type="wstring" dir="in">
    11696         <desc>
    11697           User name under which the lookup will be performed; the
    11698           user has to exist and have the appropriate rights to access / read the
    11699           desired directory.
    11700         </desc>
    11701       </param>
    11702       <param name="password" type="wstring" dir="in">
    11703         <desc>
    11704           Password of the user account specified.
    11705         </desc>
    11706       </param>
    11707       <param name="size" type="long long" dir="return">
    11708         <desc>
    11709           Size (in bytes) of file specified.
    11710         </desc>
    11711       </param>
    11712     </method>
    11713 
    11714     <method name="setProcessInput">
    11715       <desc>
    11716         Sends input into a formerly started process.
    11717 
    11718         <result name="VBOX_E_IPRT_ERROR">
    11719           Could not send input.
    11720         </result>
    11721 
    11722       </desc>
    11723       <param name="pid" type="unsigned long" dir="in">
    11724         <desc>
    11725           Process id returned by earlier <link to="#executeProcess"/> call.
    11726         </desc>
    11727       </param>
    11728       <param name="flags" type="unsigned long" dir="in">
    11729         <desc>
    11730           <link to="ProcessInputFlag"/> flags.
    11731         </desc>
    11732       </param>
    11733       <param name="timeoutMS" type="unsigned long" dir="in">
    11734         <desc>
    11735           The maximum timeout value (in msec) to wait for getting the
    11736           data transfered to the guest. Pass 0 for an infinite timeout.
    11737         </desc>
    11738       </param>
    11739       <param name="data" type="octet" dir="in" safearray="yes">
    11740         <desc>
    11741           Buffer of input data to send to the started process to.
    11742         </desc>
    11743       </param>
    11744       <param name="written" type="unsigned long" dir="return">
    11745         <desc>
    11746           Number of bytes written.
    11747         </desc>
    11748       </param>
    11749     </method>
     11168    </method> 
    1175011169
    1175111170    <method name="updateGuestAdditions">
  • trunk/src/VBox/Main/include/GuestImpl.h

    r42693 r42864  
    2727#include "GuestSessionImpl.h"
    2828#include "HGCM.h"
    29 #ifdef VBOX_WITH_GUEST_CONTROL
    30 # include <iprt/fs.h>
    31 # include <VBox/HostServices/GuestControlSvc.h>
    32 using namespace guestControl;
    33 #endif
    3429
    3530#ifdef VBOX_WITH_DRAG_AND_DROP
     
    7368    DECLARE_EMPTY_CTOR_DTOR (Guest)
    7469
    75     HRESULT FinalConstruct();
    76     void FinalRelease();
    77 
    78     // Public initializer/uninitializer for internal purposes only
     70    HRESULT FinalConstruct(void);
     71    void FinalRelease(void);
     72
     73    // Public initializer/uninitializer for internal purposes only.
    7974    HRESULT init (Console *aParent);
    8075    void uninit();
    8176
    82     // IGuest properties
     77    // IGuest properties.
    8378    STDMETHOD(COMGETTER(OSTypeId)) (BSTR *aOSTypeId);
    8479    STDMETHOD(COMGETTER(AdditionsRunLevel)) (AdditionsRunLevelType_T *aRunLevel);
     
    9186    STDMETHOD(COMGETTER(StatisticsUpdateInterval)) (ULONG *aUpdateInterval);
    9287    STDMETHOD(COMSETTER(StatisticsUpdateInterval)) (ULONG aUpdateInterval);
    93 
    94     // IGuest methods
     88    // IGuest methods.
    9589    STDMETHOD(GetFacilityStatus)(AdditionsFacilityType_T aType, LONG64 *aTimestamp, AdditionsFacilityStatus_T *aStatus);
    9690    STDMETHOD(GetAdditionsStatus)(AdditionsRunLevelType_T aLevel, BOOL *aActive);
    9791    STDMETHOD(SetCredentials)(IN_BSTR aUsername, IN_BSTR aPassword,
    9892                              IN_BSTR aDomain, BOOL aAllowInteractiveLogon);
     93    // Drag'n drop support.
    9994    STDMETHOD(DragHGEnter)(ULONG uScreenId, ULONG uX, ULONG uY, DragAndDropAction_T defaultAction, ComSafeArrayIn(DragAndDropAction_T, allowedActions), ComSafeArrayIn(IN_BSTR, formats), DragAndDropAction_T *pResultAction);
    10095    STDMETHOD(DragHGMove)(ULONG uScreenId, ULONG uX, ULONG uY, DragAndDropAction_T defaultAction, ComSafeArrayIn(DragAndDropAction_T, allowedActions), ComSafeArrayIn(IN_BSTR, formats), DragAndDropAction_T *pResultAction);
     
    105100    STDMETHOD(DragGHDropped)(IN_BSTR strFormat, DragAndDropAction_T action, IProgress **ppProgress);
    106101    STDMETHOD(DragGHGetData)(ComSafeArrayOut(BYTE, data));
    107     // Process execution
    108     STDMETHOD(ExecuteProcess)(IN_BSTR aCommand, ULONG aFlags,
    109                               ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
    110                               IN_BSTR aUsername, IN_BSTR aPassword,
    111                               ULONG aTimeoutMS, ULONG *aPID, IProgress **aProgress);
    112     STDMETHOD(GetProcessOutput)(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, LONG64 aSize, ComSafeArrayOut(BYTE, aData));
    113     STDMETHOD(SetProcessInput)(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, ComSafeArrayIn(BYTE, aData), ULONG *aBytesWritten);
    114     STDMETHOD(GetProcessStatus)(ULONG aPID, ULONG *aExitCode, ULONG *aFlags, ExecuteProcessStatus_T *aStatus);
    115     // File copying
    116     STDMETHOD(CopyFromGuest)(IN_BSTR aSource, IN_BSTR aDest, IN_BSTR aUsername, IN_BSTR aPassword, ULONG aFlags, IProgress **aProgress);
    117     STDMETHOD(CopyToGuest)(IN_BSTR aSource, IN_BSTR aDest, IN_BSTR aUsername, IN_BSTR aPassword, ULONG aFlags, IProgress **aProgress);
    118     // Directory handling
    119     STDMETHOD(DirectoryClose)(ULONG aHandle);
    120     STDMETHOD(DirectoryCreate)(IN_BSTR aDirectory, IN_BSTR aUsername, IN_BSTR aPassword, ULONG aMode, ULONG aFlags);
    121 #if 0
    122     STDMETHOD(DirectoryExists)(IN_BSTR aDirectory, IN_BSTR aUsername, IN_BSTR aPassword, BOOL *aExists);
    123 #endif
    124     STDMETHOD(DirectoryOpen)(IN_BSTR aDirectory, IN_BSTR aFilter,
    125                              ULONG aFlags, IN_BSTR aUsername, IN_BSTR aPassword, ULONG *aHandle);
    126     STDMETHOD(DirectoryRead)(ULONG aHandle, IGuestDirEntry **aDirEntry);
    127     // File handling
    128     STDMETHOD(FileExists)(IN_BSTR aFile, IN_BSTR aUsername, IN_BSTR aPassword, BOOL *aExists);
    129     STDMETHOD(FileQuerySize)(IN_BSTR aFile, IN_BSTR aUsername, IN_BSTR aPassword, LONG64 *aSize);
    130102    // Misc stuff
    131103    STDMETHOD(InternalGetStatistics)(ULONG *aCpuUser, ULONG *aCpuKernel, ULONG *aCpuIdle,
     
    136108    STDMETHOD(FindSession)(IN_BSTR aSessionName, ComSafeArrayOut(IGuestSession *, aSessions));
    137109
    138     // Public methods that are not in IDL (only called internally).
     110public:
     111    /** @name Static internal methods.
     112     * @{ */
     113#ifdef VBOX_WITH_GUEST_CONTROL
     114    /** Static callback for handling guest control notifications. */
     115    static DECLCALLBACK(int) notifyCtrlDispatcher(void *pvExtension, uint32_t u32Function, void *pvParms, uint32_t cbParms);
     116    static void staticUpdateStats(RTTIMERLR hTimerLR, void *pvUser, uint64_t iTick);
     117#endif
     118    /** @}  */
     119
     120public:
     121    /** @name Public internal methods.
     122     * @{ */
     123    void enableVMMStatistics(BOOL aEnable) { mCollectVMMStats = aEnable; };
    139124    void setAdditionsInfo(Bstr aInterfaceVersion, VBOXOSTYPE aOsType);
    140125    void setAdditionsInfo2(uint32_t a_uFullVersion, const char *a_pszName, uint32_t a_uRevision, uint32_t a_fFeatures);
     
    150135        return setErrorInternal(aResultCode, getStaticClassIID(), getStaticComponentName(), aText, false, true);
    151136    }
    152 
    153 # ifdef VBOX_WITH_GUEST_CONTROL
    154     // Internal guest directory functions
    155     int directoryCreateHandle(ULONG *puHandle, ULONG uPID, IN_BSTR aDirectory, IN_BSTR aFilter, ULONG uFlags);
    156     HRESULT directoryCreateInternal(IN_BSTR aDirectory, IN_BSTR aUsername, IN_BSTR aPassword,
    157                                     ULONG aMode, ULONG aFlags, int *pRC);
    158     void directoryDestroyHandle(uint32_t uHandle);
    159     HRESULT directoryExistsInternal(IN_BSTR aDirectory, IN_BSTR aUsername, IN_BSTR aPassword, BOOL *aExists);
    160     uint32_t directoryGetPID(uint32_t uHandle);
    161     int directoryGetNextEntry(uint32_t uHandle, GuestProcessStreamBlock &streamBlock);
    162     bool directoryHandleExists(uint32_t uHandle);
    163     HRESULT directoryOpenInternal(IN_BSTR aDirectory, IN_BSTR aFilter,
    164                                   ULONG aFlags,
    165                                   IN_BSTR aUsername, IN_BSTR aPassword,
    166                                   ULONG *aHandle, int *pRC);
    167     HRESULT directoryQueryInfoInternal(IN_BSTR aDirectory, IN_BSTR aUsername, IN_BSTR aPassword, PRTFSOBJINFO aObjInfo, RTFSOBJATTRADD enmAddAttribs, int *pRC);
    168     // Internal guest execution functions
    169     HRESULT executeAndWaitForTool(IN_BSTR aTool, IN_BSTR aDescription,
    170                                   ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
    171                                   IN_BSTR aUsername, IN_BSTR aPassword,
    172                                   ULONG uFlagsToAdd,
    173                                   GuestCtrlStreamObjects *pObjStdOut, GuestCtrlStreamObjects *pObjStdErr,
    174                                   IProgress **aProgress, ULONG *aPID);
    175     HRESULT executeProcessInternal(IN_BSTR aCommand, ULONG aFlags,
    176                                    ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
    177                                    IN_BSTR aUsername, IN_BSTR aPassword,
    178                                    ULONG aTimeoutMS, ULONG *aPID, IProgress **aProgress, int *pRC);
    179     HRESULT getProcessOutputInternal(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS,
    180                                      LONG64 aSize, ComSafeArrayOut(BYTE, aData), int *pRC);
    181     HRESULT executeSetResult(const char *pszCommand, const char *pszUser, ULONG ulTimeout, PCALLBACKDATAEXECSTATUS pExecStatus, ULONG *puPID);
    182     int     executeStreamQueryFsObjInfo(IN_BSTR aObjName,GuestProcessStreamBlock &streamBlock, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttribs);
    183     int     executeStreamDrain(ULONG aPID, ULONG ulFlags, GuestProcessStream *pStream);
    184     int     executeStreamGetNextBlock(ULONG ulPID, ULONG ulFlags, GuestProcessStream &stream, GuestProcessStreamBlock &streamBlock);
    185     int     executeStreamParseNextBlock(ULONG ulPID, ULONG ulFlags, GuestProcessStream &stream, GuestProcessStreamBlock &streamBlock);
    186     HRESULT executeStreamParse(ULONG uPID, ULONG ulFlags, GuestCtrlStreamObjects &streamObjects);
    187     HRESULT executeWaitForExit(ULONG uPID, ComPtr<IProgress> pProgress, ULONG uTimeoutMS);
    188     // Internal guest file functions
    189     HRESULT fileExistsInternal(IN_BSTR aFile, IN_BSTR aUsername, IN_BSTR aPassword, BOOL *aExists);
    190     HRESULT fileQueryInfoInternal(IN_BSTR aFile, IN_BSTR aUsername, IN_BSTR aPassword, PRTFSOBJINFO aObjInfo, RTFSOBJATTRADD enmAddAttribs, int *pRC);
    191     HRESULT fileQuerySizeInternal(IN_BSTR aFile, IN_BSTR aUsername, IN_BSTR aPassword, LONG64 *aSize);
    192 
    193     // Guest control dispatcher.
    194     /** Static callback for handling guest control notifications. */
    195     static DECLCALLBACK(int) notifyCtrlDispatcher(void *pvExtension, uint32_t u32Function, void *pvParms, uint32_t cbParms);
    196 
    197     // Internal tasks.
    198     //extern struct GuestTask;
    199     HRESULT taskCopyFileToGuest(GuestTask *aTask);
    200     HRESULT taskCopyFileFromGuest(GuestTask *aTask);
    201     HRESULT taskUpdateGuestAdditions(GuestTask *aTask);
    202 #endif
    203     void enableVMMStatistics(BOOL aEnable) { mCollectVMMStats = aEnable; };
    204 
    205 public:
    206     /** @name Public internal methods.
    207      * @{ */
     137#ifdef VBOX_WITH_GUEST_CONTROL
    208138    int         dispatchToSession(uint32_t uContextID, uint32_t uFunction, void *pvData, size_t cbData);
    209139    uint32_t    getAdditionsVersion(void) { return mData.mAdditionsVersionFull; }
     
    213143                              const Utf8Str &strSessionName, ComObjPtr<GuestSession> &pGuestSession);
    214144    inline bool sessionExists(uint32_t uSessionID);
     145#endif
    215146    /** @}  */
    216147
    217148private:
    218 
    219 #ifdef VBOX_WITH_GUEST_CONTROL
    220     // Internal guest callback representation.
    221     typedef struct VBOXGUESTCTRL_CALLBACK
    222     {
    223         eVBoxGuestCtrlCallbackType  mType;
    224         /** Pointer to user-supplied data. */
    225         void                       *pvData;
    226         /** Size of user-supplied data. */
    227         uint32_t                    cbData;
    228         /** The host PID. Needed for translating to
    229          *  a guest PID. */
    230         uint32_t                    uHostPID;
    231         /** Pointer to user-supplied IProgress. */
    232         ComObjPtr<Progress>         pProgress;
    233     } VBOXGUESTCTRL_CALLBACK, *PVBOXGUESTCTRL_CALLBACK;
    234     typedef std::map< uint32_t, VBOXGUESTCTRL_CALLBACK > CallbackMap;
    235     typedef std::map< uint32_t, VBOXGUESTCTRL_CALLBACK >::iterator CallbackMapIter;
    236     typedef std::map< uint32_t, VBOXGUESTCTRL_CALLBACK >::const_iterator CallbackMapIterConst;
    237 
    238     int callbackAdd(const PVBOXGUESTCTRL_CALLBACK pCallbackData, uint32_t *puContextID);
    239     int callbackAssignHostPID(uint32_t uContextID, uint32_t uHostPID);
    240     void callbackDestroy(uint32_t uContextID);
    241     void callbackRemove(uint32_t uContextID);
    242     bool callbackExists(uint32_t uContextID);
    243     void callbackFreeUserData(void *pvData);
    244     uint32_t callbackGetHostPID(uint32_t uContextID);
    245     int callbackGetUserData(uint32_t uContextID, eVBoxGuestCtrlCallbackType *pEnmType, void **ppvData, size_t *pcbData);
    246     void* callbackGetUserDataMutableRaw(uint32_t uContextID, size_t *pcbData);
    247     int callbackInit(PVBOXGUESTCTRL_CALLBACK pCallback, eVBoxGuestCtrlCallbackType enmType, ComPtr<Progress> pProgress);
    248     bool callbackIsCanceled(uint32_t uContextID);
    249     bool callbackIsComplete(uint32_t uContextID);
    250     int callbackMoveForward(uint32_t uContextID, const char *pszMessage);
    251     int callbackNotifyEx(uint32_t uContextID, int iRC, const char *pszMessage);
    252     int callbackNotifyComplete(uint32_t uContextID);
    253     int callbackNotifyAllForPID(uint32_t uGuestPID, int iRC, const char *pszMessage);
    254     int callbackWaitForCompletion(uint32_t uContextID, LONG lStage, LONG lTimeout);
    255 
    256     int notifyCtrlClientDisconnected(uint32_t u32Function, PCALLBACKDATACLIENTDISCONNECTED pData);
    257     int notifyCtrlExecStatus(uint32_t u32Function, PCALLBACKDATAEXECSTATUS pData);
    258     int notifyCtrlExecOut(uint32_t u32Function, PCALLBACKDATAEXECOUT pData);
    259     int notifyCtrlExecInStatus(uint32_t u32Function, PCALLBACKDATAEXECINSTATUS pData);
    260 
    261     // Internal guest process representation.
    262     typedef struct VBOXGUESTCTRL_PROCESS
    263     {
    264         /** The guest PID -- needed for controlling the actual guest
    265          *  process which has its own PID (generated by the guest OS). */
    266         uint32_t                    mGuestPID;
    267         /** The last reported process status. */
    268         ExecuteProcessStatus_T      mStatus;
    269         /** The process execution flags. */
    270         uint32_t                    mFlags;
    271         /** The process' exit code. */
    272         uint32_t                    mExitCode;
    273     } VBOXGUESTCTRL_PROCESS, *PVBOXGUESTCTRL_PROCESS;
    274     typedef std::map< uint32_t, VBOXGUESTCTRL_PROCESS > GuestProcessMap;
    275     typedef std::map< uint32_t, VBOXGUESTCTRL_PROCESS >::iterator GuestProcessMapIter;
    276     typedef std::map< uint32_t, VBOXGUESTCTRL_PROCESS >::const_iterator GuestProcessMapIterConst;
    277 
    278     uint32_t processGetGuestPID(uint32_t uHostPID);
    279     int  processGetStatus(uint32_t uHostPID, PVBOXGUESTCTRL_PROCESS pProcess, bool fRemove);
    280     int  processSetStatus(uint32_t uHostPID, uint32_t uGuestPID,
    281                           ExecuteProcessStatus_T enmStatus, uint32_t uExitCode, uint32_t uFlags);
    282 
    283     // Internal guest directory representation.
    284     typedef struct VBOXGUESTCTRL_DIRECTORY
    285     {
    286         Bstr                        mDirectory;
    287         Bstr                        mFilter;
    288         ULONG                       mFlags;
    289         /** Associated host PID of started vbox_ls tool. */
    290         ULONG                       mPID;
    291         GuestProcessStream          mStream;
    292     } VBOXGUESTCTRL_DIRECTORY, *PVBOXGUESTCTRL_DIRECTORY;
    293     typedef std::map< uint32_t, VBOXGUESTCTRL_DIRECTORY > GuestDirectoryMap;
    294     typedef std::map< uint32_t, VBOXGUESTCTRL_DIRECTORY >::iterator GuestDirectoryMapIter;
    295     typedef std::map< uint32_t, VBOXGUESTCTRL_DIRECTORY >::const_iterator GuestDirectoryMapIterConst;
    296 
    297     // Utility functions.
    298     int prepareExecuteEnv(const char *pszEnv, void **ppvList, uint32_t *pcbList, uint32_t *pcEnv);
    299 
    300     /*
    301      * Handler for guest execution control notifications.
    302      */
    303     HRESULT setErrorCompletion(int rc);
    304     HRESULT setErrorFromProgress(ComPtr<IProgress> pProgress);
    305     HRESULT setErrorHGCM(int rc);
    306 # endif
     149    /** @name Private internal methods.
     150     * @{ */
     151    void updateStats(uint64_t iTick);
     152    /** @}  */
    307153
    308154    typedef std::map< AdditionsFacilityType_T, ComObjPtr<AdditionsFacility> > FacilityMap;
     
    331177    };
    332178
    333     ULONG mMemoryBalloonSize;
    334     ULONG mStatUpdateInterval;
    335     ULONG mCurrentGuestStat[GUESTSTATTYPE_MAX];
    336     ULONG mGuestValidStats;
    337     BOOL  mCollectVMMStats;
    338     BOOL  mfPageFusionEnabled;
     179    ULONG             mMemoryBalloonSize;
     180    ULONG             mStatUpdateInterval;
     181    ULONG             mCurrentGuestStat[GUESTSTATTYPE_MAX];
     182    ULONG             mGuestValidStats;
     183    BOOL              mCollectVMMStats;
     184    BOOL              mfPageFusionEnabled;
    339185
    340186    Console *mParent;
    341187    Data mData;
    342188
    343 # ifdef VBOX_WITH_GUEST_CONTROL
     189#ifdef VBOX_WITH_GUEST_CONTROL
    344190    /** General extension callback for guest control. */
    345191    HGCMSVCEXTHANDLE  mhExtCtrl;
    346     /** Next upcoming context ID. */
    347     volatile uint32_t mNextContextID;
    348     /** Next upcoming host PID */
    349     volatile uint32_t mNextHostPID;
    350     /** Next upcoming directory handle ID. */
    351     volatile uint32_t mNextDirectoryID;
    352     CallbackMap       mCallbackMap;
    353     GuestDirectoryMap mGuestDirectoryMap;
    354     GuestProcessMap   mGuestProcessMap;
    355 # endif
     192#endif
    356193
    357194#ifdef VBOX_WITH_DRAG_AND_DROP
     
    360197    friend class GuestDnDPrivate;
    361198#endif
    362     static void staticUpdateStats(RTTIMERLR hTimerLR, void *pvUser, uint64_t iTick);
    363     void updateStats(uint64_t iTick);
     199
    364200    RTTIMERLR         mStatTimer;
    365201    uint32_t          mMagic;
  • trunk/src/VBox/Main/src-client/GuestCtrlImpl.cpp

    r42758 r42864  
    4747#ifdef VBOX_WITH_GUEST_CONTROL
    4848/**
    49  * Appends environment variables to the environment block.
    50  *
    51  * Each var=value pair is separated by the null character ('\\0').  The whole
    52  * block will be stored in one blob and disassembled on the guest side later to
    53  * fit into the HGCM param structure.
    54  *
    55  * @returns VBox status code.
    56  *
    57  * @param   pszEnvVar       The environment variable=value to append to the
    58  *                          environment block.
    59  * @param   ppvList         This is actually a pointer to a char pointer
    60  *                          variable which keeps track of the environment block
    61  *                          that we're constructing.
    62  * @param   pcbList         Pointer to the variable holding the current size of
    63  *                          the environment block.  (List is a misnomer, go
    64  *                          ahead a be confused.)
    65  * @param   pcEnvVars       Pointer to the variable holding count of variables
    66  *                          stored in the environment block.
    67  */
    68 int Guest::prepareExecuteEnv(const char *pszEnv, void **ppvList, uint32_t *pcbList, uint32_t *pcEnvVars)
    69 {
    70     int rc = VINF_SUCCESS;
    71     uint32_t cchEnv = strlen(pszEnv); Assert(cchEnv >= 2);
    72     if (*ppvList)
    73     {
    74         uint32_t cbNewLen = *pcbList + cchEnv + 1; /* Include zero termination. */
    75         char *pvTmp = (char *)RTMemRealloc(*ppvList, cbNewLen);
    76         if (pvTmp == NULL)
    77             rc = VERR_NO_MEMORY;
    78         else
    79         {
    80             memcpy(pvTmp + *pcbList, pszEnv, cchEnv);
    81             pvTmp[cbNewLen - 1] = '\0'; /* Add zero termination. */
    82             *ppvList = (void **)pvTmp;
    83         }
    84     }
    85     else
    86     {
    87         char *pszTmp;
    88         if (RTStrAPrintf(&pszTmp, "%s", pszEnv) >= 0)
    89         {
    90             *ppvList = (void **)pszTmp;
    91             /* Reset counters. */
    92             *pcEnvVars = 0;
    93             *pcbList = 0;
    94         }
    95     }
    96     if (RT_SUCCESS(rc))
    97     {
    98         *pcbList += cchEnv + 1; /* Include zero termination. */
    99         *pcEnvVars += 1;        /* Increase env variable count. */
    100     }
    101     return rc;
    102 }
    103 
    104 /**
    105  * Adds a callback with a user provided data block and an optional progress object
    106  * to the callback map. A callback is identified by a unique context ID which is used
    107  * to identify a callback from the guest side.
    108  *
    109  * @return  IPRT status code.
    110  * @param   pCallback
    111  * @param   puContextID
    112  */
    113 int Guest::callbackAdd(const PVBOXGUESTCTRL_CALLBACK pCallback, uint32_t *puContextID)
    114 {
    115     AssertPtrReturn(pCallback, VERR_INVALID_PARAMETER);
    116     /* puContextID is optional. */
    117 
    118     int rc = VERR_NOT_FOUND;
    119 
    120     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    121 
    122     /* Create a new context ID and assign it. */
    123     uint32_t uNewContextID = 0;
    124     uint32_t uTries = 0;
    125     for (;;)
    126     {
    127         /* Create a new context ID ... */
    128         uNewContextID = ASMAtomicIncU32(&mNextContextID);
    129         if (uNewContextID == UINT32_MAX)
    130             ASMAtomicUoWriteU32(&mNextContextID, 1000);
    131         /* Is the context ID already used?  Try next ID ... */
    132         if (!callbackExists(uNewContextID))
    133         {
    134             /* Callback with context ID was not found. This means
    135              * we can use this context ID for our new callback we want
    136              * to add below. */
    137             rc = VINF_SUCCESS;
    138             break;
    139         }
    140 
    141         if (++uTries == UINT32_MAX)
    142             break; /* Don't try too hard. */
    143     }
    144 
    145     if (RT_SUCCESS(rc))
    146     {
    147         /* Add callback with new context ID to our callback map. */
    148         mCallbackMap[uNewContextID] = *pCallback;
    149         Assert(mCallbackMap.size());
    150 
    151         /* Report back new context ID. */
    152         if (puContextID)
    153             *puContextID = uNewContextID;
    154     }
    155 
    156     return rc;
    157 }
    158 
    159 /**
    160  * Assigns a host PID to a specified context.
    161  * Does not do locking!
    162  *
    163  * @param   uContextID
    164  * @param   uHostPID
    165  */
    166 int Guest::callbackAssignHostPID(uint32_t uContextID, uint32_t uHostPID)
    167 {
    168     AssertReturn(uContextID, VERR_INVALID_PARAMETER);
    169     AssertReturn(uHostPID, VERR_INVALID_PARAMETER);
    170 
    171     int rc = VINF_SUCCESS;
    172 
    173     CallbackMapIter it = mCallbackMap.find(uContextID);
    174     if (it == mCallbackMap.end())
    175         return VERR_NOT_FOUND;
    176 
    177     it->second.uHostPID = uHostPID;
    178 
    179     return VINF_SUCCESS;
    180 }
    181 
    182 /**
    183  * Destroys the formerly allocated callback data. The callback then
    184  * needs to get removed from the callback map via callbackRemove().
    185  * Does not do locking!
    186  *
    187  * @param   uContextID
    188  */
    189 void Guest::callbackDestroy(uint32_t uContextID)
    190 {
    191     AssertReturnVoid(uContextID);
    192 
    193     CallbackMapIter it = mCallbackMap.find(uContextID);
    194     if (it != mCallbackMap.end())
    195     {
    196         LogFlowFunc(("Callback with CID=%u found\n", uContextID));
    197         if (it->second.pvData)
    198         {
    199             LogFlowFunc(("Destroying callback with CID=%u ...\n", uContextID));
    200 
    201             callbackFreeUserData(it->second.pvData);
    202             it->second.cbData = 0;
    203         }
    204     }
    205 }
    206 
    207 /**
    208  * Removes a callback from the callback map.
    209  * Does not do locking!
    210  *
    211  * @param   uContextID
    212  */
    213 void Guest::callbackRemove(uint32_t uContextID)
    214 {
    215     callbackDestroy(uContextID);
    216 
    217     mCallbackMap.erase(uContextID);
    218 }
    219 
    220 /**
    221  * Checks whether a callback with the given context ID
    222  * exists or not.
    223  * Does not do locking!
    224  *
    225  * @return  bool                True, if callback exists, false if not.
    226  * @param   uContextID          Context ID to check.
    227  */
    228 bool Guest::callbackExists(uint32_t uContextID)
    229 {
    230     AssertReturn(uContextID, false);
    231 
    232     CallbackMapIter it = mCallbackMap.find(uContextID);
    233     return (it == mCallbackMap.end()) ? false : true;
    234 }
    235 
    236 /**
    237  * Frees the user data (actual context data) of a callback.
    238  * Does not do locking!
    239  *
    240  * @param   pvData              Data to free.
    241  */
    242 void Guest::callbackFreeUserData(void *pvData)
    243 {
    244     if (pvData)
    245     {
    246         RTMemFree(pvData);
    247         pvData = NULL;
    248     }
    249 }
    250 
    251 /**
    252  * Retrieves the (generated) host PID of a given callback.
    253  *
    254  * @return  The host PID, if found, 0 otherwise.
    255  * @param   uContextID              Context ID to lookup host PID for.
    256  * @param   puHostPID               Where to store the host PID.
    257  */
    258 uint32_t Guest::callbackGetHostPID(uint32_t uContextID)
    259 {
    260     AssertReturn(uContextID, 0);
    261 
    262     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    263 
    264     CallbackMapIterConst it = mCallbackMap.find(uContextID);
    265     if (it == mCallbackMap.end())
    266         return 0;
    267 
    268     return it->second.uHostPID;
    269 }
    270 
    271 int Guest::callbackGetUserData(uint32_t uContextID, eVBoxGuestCtrlCallbackType *pEnmType,
    272                                void **ppvData, size_t *pcbData)
    273 {
    274     AssertReturn(uContextID, VERR_INVALID_PARAMETER);
    275     /* pEnmType is optional. */
    276     /* ppvData is optional. */
    277     /* pcbData is optional. */
    278 
    279     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    280 
    281     CallbackMapIterConst it = mCallbackMap.find(uContextID);
    282     if (it == mCallbackMap.end())
    283         return VERR_NOT_FOUND;
    284 
    285     if (pEnmType)
    286         *pEnmType = it->second.mType;
    287 
    288     if (   ppvData
    289         && it->second.cbData)
    290     {
    291         void *pvData = RTMemAlloc(it->second.cbData);
    292         AssertPtrReturn(pvData, VERR_NO_MEMORY);
    293         memcpy(pvData, it->second.pvData, it->second.cbData);
    294         *ppvData = pvData;
    295     }
    296 
    297     if (pcbData)
    298         *pcbData = it->second.cbData;
    299 
    300     return VINF_SUCCESS;
    301 }
    302 
    303 /* Does not do locking! Caller has to take care of it because the caller needs to
    304  * modify the data ...*/
    305 void* Guest::callbackGetUserDataMutableRaw(uint32_t uContextID, size_t *pcbData)
    306 {
    307     /* uContextID can be 0. */
    308     /* pcbData is optional. */
    309 
    310     CallbackMapIterConst it = mCallbackMap.find(uContextID);
    311     if (it != mCallbackMap.end())
    312     {
    313         if (pcbData)
    314             *pcbData = it->second.cbData;
    315         return it->second.pvData;
    316     }
    317 
    318     return NULL;
    319 }
    320 
    321 int Guest::callbackInit(PVBOXGUESTCTRL_CALLBACK pCallback, eVBoxGuestCtrlCallbackType enmType,
    322                         ComPtr<Progress> pProgress)
    323 {
    324     AssertPtrReturn(pCallback, VERR_INVALID_POINTER);
    325     /* Everything else is optional. */
    326 
    327     int vrc = VINF_SUCCESS;
    328     switch (enmType)
    329     {
    330         case VBOXGUESTCTRLCALLBACKTYPE_EXEC_START:
    331         {
    332             PCALLBACKDATAEXECSTATUS pData = (PCALLBACKDATAEXECSTATUS)RTMemAlloc(sizeof(CALLBACKDATAEXECSTATUS));
    333             AssertPtrReturn(pData, VERR_NO_MEMORY);
    334             RT_BZERO(pData, sizeof(CALLBACKDATAEXECSTATUS));
    335             pCallback->cbData = sizeof(CALLBACKDATAEXECSTATUS);
    336             pCallback->pvData = pData;
    337             break;
    338         }
    339 
    340         case VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT:
    341         {
    342             PCALLBACKDATAEXECOUT pData = (PCALLBACKDATAEXECOUT)RTMemAlloc(sizeof(CALLBACKDATAEXECOUT));
    343             AssertPtrReturn(pData, VERR_NO_MEMORY);
    344             RT_BZERO(pData, sizeof(CALLBACKDATAEXECOUT));
    345             pCallback->cbData = sizeof(CALLBACKDATAEXECOUT);
    346             pCallback->pvData = pData;
    347             break;
    348         }
    349 
    350         case VBOXGUESTCTRLCALLBACKTYPE_EXEC_INPUT_STATUS:
    351         {
    352             PCALLBACKDATAEXECINSTATUS pData = (PCALLBACKDATAEXECINSTATUS)RTMemAlloc(sizeof(CALLBACKDATAEXECINSTATUS));
    353             AssertPtrReturn(pData, VERR_NO_MEMORY);
    354             RT_BZERO(pData, sizeof(CALLBACKDATAEXECINSTATUS));
    355             pCallback->cbData = sizeof(CALLBACKDATAEXECINSTATUS);
    356             pCallback->pvData = pData;
    357             break;
    358         }
    359 
    360         default:
    361             vrc = VERR_INVALID_PARAMETER;
    362             break;
    363     }
    364 
    365     if (RT_SUCCESS(vrc))
    366     {
    367         /* Init/set common stuff. */
    368         pCallback->mType  = enmType;
    369         pCallback->pProgress = pProgress;
    370     }
    371 
    372     return vrc;
    373 }
    374 
    375 bool Guest::callbackIsCanceled(uint32_t uContextID)
    376 {
    377     if (!uContextID)
    378         return true; /* If no context ID given then take a shortcut. */
    379 
    380     ComPtr<IProgress> pProgress;
    381     {
    382         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    383 
    384         CallbackMapIterConst it = mCallbackMap.find(uContextID);
    385         if (it != mCallbackMap.end())
    386             pProgress = it->second.pProgress;
    387     }
    388 
    389     if (pProgress)
    390     {
    391         BOOL fCanceled = FALSE;
    392         HRESULT hRC = pProgress->COMGETTER(Canceled)(&fCanceled);
    393         if (   SUCCEEDED(hRC)
    394             && !fCanceled)
    395         {
    396             return false;
    397         }
    398     }
    399 
    400     return true; /* No progress / error means canceled. */
    401 }
    402 
    403 bool Guest::callbackIsComplete(uint32_t uContextID)
    404 {
    405     AssertReturn(uContextID, true);
    406 
    407     ComPtr<IProgress> pProgress;
    408     {
    409         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    410 
    411         CallbackMapIterConst it = mCallbackMap.find(uContextID);
    412         if (it != mCallbackMap.end())
    413             pProgress = it->second.pProgress;
    414     }
    415 
    416     if (pProgress)
    417     {
    418         BOOL fCompleted = FALSE;
    419         HRESULT hRC = pProgress->COMGETTER(Completed)(&fCompleted);
    420         if (   SUCCEEDED(hRC)
    421             && fCompleted)
    422         {
    423             return true;
    424         }
    425     }
    426 
    427     return false;
    428 }
    429 
    430 int Guest::callbackMoveForward(uint32_t uContextID, const char *pszMessage)
    431 {
    432     AssertReturn(uContextID, VERR_INVALID_PARAMETER);
    433     AssertPtrReturn(pszMessage, VERR_INVALID_PARAMETER);
    434 
    435     ComPtr<IProgress> pProgress;
    436     {
    437         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    438 
    439         CallbackMapIterConst it = mCallbackMap.find(uContextID);
    440         if (it != mCallbackMap.end())
    441             pProgress = it->second.pProgress;
    442     }
    443 
    444     if (pProgress)
    445     {
    446         HRESULT hr = pProgress->SetNextOperation(Bstr(pszMessage).raw(), 1 /* Weight */);
    447         if (FAILED(hr))
    448             return VERR_CANCELLED;
    449 
    450         return VINF_SUCCESS;
    451     }
    452 
    453     return VERR_NOT_FOUND;
    454 }
    455 
    456 /**
    457  * Notifies a specified callback about its final status.
    458  *
    459  * @return  IPRT status code.
    460  * @param   uContextID
    461  * @param   iRC
    462  * @param   pszMessage
    463  */
    464 int Guest::callbackNotifyEx(uint32_t uContextID, int iRC, const char *pszMessage)
    465 {
    466     AssertReturn(uContextID, VERR_INVALID_PARAMETER);
    467     if (RT_FAILURE(iRC))
    468         AssertReturn(pszMessage, VERR_INVALID_PARAMETER);
    469 
    470     LogFlowFunc(("Checking whether callback (CID=%u) needs notification iRC=%Rrc, pszMsg=%s\n",
    471                  uContextID, iRC, pszMessage ? pszMessage : "<No message given>"));
    472 
    473     ComObjPtr<Progress> pProgress;
    474     {
    475         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    476 
    477         CallbackMapIterConst it = mCallbackMap.find(uContextID);
    478         if (it != mCallbackMap.end())
    479             pProgress = it->second.pProgress;
    480     }
    481 
    482 #if 0
    483     BOOL fCanceled = FALSE;
    484     HRESULT hRC = pProgress->COMGETTER(Canceled)(&fCanceled);
    485     if (   SUCCEEDED(hRC)
    486         && fCanceled)
    487     {
    488         /* If progress already canceled do nothing here. */
    489         return VINF_SUCCESS;
    490     }
    491 #endif
    492 
    493     if (pProgress)
    494     {
    495         /*
    496          * Assume we didn't complete to make sure we clean up even if the
    497          * following call fails.
    498          */
    499         BOOL fCompleted = FALSE;
    500         HRESULT hRC = pProgress->COMGETTER(Completed)(&fCompleted);
    501         if (   SUCCEEDED(hRC)
    502             && !fCompleted)
    503         {
    504             LogFlowFunc(("Notifying callback with CID=%u, iRC=%Rrc, pszMsg=%s\n",
    505                          uContextID, iRC, pszMessage ? pszMessage : "<No message given>"));
    506 
    507             /*
    508              * To get waitForCompletion completed (unblocked) we have to notify it if necessary (only
    509              * cancel won't work!). This could happen if the client thread (e.g. VBoxService, thread of a spawned process)
    510              * is disconnecting without having the chance to sending a status message before, so we
    511              * have to abort here to make sure the host never hangs/gets stuck while waiting for the
    512              * progress object to become signalled.
    513              */
    514             if (RT_SUCCESS(iRC))
    515             {
    516                 hRC = pProgress->notifyComplete(S_OK);
    517             }
    518             else
    519             {
    520                 hRC = pProgress->notifyComplete(VBOX_E_IPRT_ERROR /* Must not be S_OK. */,
    521                                                 COM_IIDOF(IGuest),
    522                                                 Guest::getStaticComponentName(),
    523                                                 pszMessage);
    524             }
    525 
    526             LogFlowFunc(("Notified callback with CID=%u returned %Rhrc (0x%x)\n",
    527                          uContextID, hRC, hRC));
    528         }
    529         else
    530             LogFlowFunc(("Callback with CID=%u already notified\n", uContextID));
    531 
    532         /*
    533          * Do *not* NULL pProgress here, because waiting function like executeProcess()
    534          * will still rely on this object for checking whether they have to give up!
    535          */
    536     }
    537     /* If pProgress is not found (anymore) that's fine.
    538      * Might be destroyed already. */
    539     return S_OK;
    540 }
    541 
    542 /**
    543  * Notifies all callbacks which are assigned to a certain guest PID to set a certain
    544  * return/error code and an optional (error) message.
    545  *
    546  * @return  IPRT status code.
    547  * @param   uGuestPID               Guest PID to find all callbacks for.
    548  * @param   iRC                     Return (error) code to set for the found callbacks.
    549  * @param   pszMessage              Optional (error) message to set.
    550  */
    551 int Guest::callbackNotifyAllForPID(uint32_t uGuestPID, int iRC, const char *pszMessage)
    552 {
    553     AssertReturn(uGuestPID, VERR_INVALID_PARAMETER);
    554 
    555     int vrc = VINF_SUCCESS;
    556 
    557     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    558 
    559     CallbackMapIter it;
    560     for (it = mCallbackMap.begin(); it != mCallbackMap.end(); it++)
    561     {
    562         switch (it->second.mType)
    563         {
    564             case VBOXGUESTCTRLCALLBACKTYPE_EXEC_START:
    565                 break;
    566 
    567             /* When waiting for process output while the process is destroyed,
    568              * make sure we also destroy the actual waiting operation (internal progress object)
    569              * in order to not block the caller. */
    570             case VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT:
    571             {
    572                 PCALLBACKDATAEXECOUT pItData = (PCALLBACKDATAEXECOUT)it->second.pvData;
    573                 AssertPtr(pItData);
    574                 if (pItData->u32PID == uGuestPID)
    575                     vrc = callbackNotifyEx(it->first, iRC, pszMessage);
    576                 break;
    577             }
    578 
    579             /* When waiting for injecting process input while the process is destroyed,
    580              * make sure we also destroy the actual waiting operation (internal progress object)
    581              * in order to not block the caller. */
    582             case VBOXGUESTCTRLCALLBACKTYPE_EXEC_INPUT_STATUS:
    583             {
    584                 PCALLBACKDATAEXECINSTATUS pItData = (PCALLBACKDATAEXECINSTATUS)it->second.pvData;
    585                 AssertPtr(pItData);
    586                 if (pItData->u32PID == uGuestPID)
    587                     vrc = callbackNotifyEx(it->first, iRC, pszMessage);
    588                 break;
    589             }
    590 
    591             default:
    592                 vrc = VERR_INVALID_PARAMETER;
    593                 AssertMsgFailed(("Unknown callback type %d, iRC=%d, message=%s\n",
    594                                  it->second.mType, iRC, pszMessage ? pszMessage : "<No message given>"));
    595                 break;
    596         }
    597 
    598         if (RT_FAILURE(vrc))
    599             break;
    600     }
    601 
    602     return vrc;
    603 }
    604 
    605 int Guest::callbackNotifyComplete(uint32_t uContextID)
    606 {
    607     return callbackNotifyEx(uContextID, S_OK, NULL /* No message */);
    608 }
    609 
    610 /**
    611  * Waits for a callback (using its context ID) to complete.
    612  *
    613  * @return  IPRT status code.
    614  * @param   uContextID              Context ID to wait for.
    615  * @param   lStage                  Stage to wait for. Specify -1 if no staging is present/required.
    616  *                                  Specifying a stage is only needed if there's a multi operation progress
    617  *                                  object to wait for.
    618  * @param   lTimeout                Timeout (in ms) to wait for.
    619  */
    620 int Guest::callbackWaitForCompletion(uint32_t uContextID, LONG lStage, LONG lTimeout)
    621 {
    622     AssertReturn(uContextID, VERR_INVALID_PARAMETER);
    623 
    624     /*
    625      * Wait for the HGCM low level callback until the process
    626      * has been started (or something went wrong). This is necessary to
    627      * get the PID.
    628      */
    629 
    630     int vrc = VINF_SUCCESS;
    631     ComPtr<IProgress> pProgress;
    632     {
    633         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    634 
    635         CallbackMapIterConst it = mCallbackMap.find(uContextID);
    636         if (it != mCallbackMap.end())
    637             pProgress = it->second.pProgress;
    638         else
    639             vrc = VERR_NOT_FOUND;
    640     }
    641 
    642     if (RT_SUCCESS(vrc))
    643     {
    644         LogFlowFunc(("Waiting for callback completion (CID=%u, Stage=%RI32, timeout=%RI32ms) ...\n",
    645                      uContextID, lStage, lTimeout));
    646         HRESULT rc;
    647         if (lStage < 0)
    648             rc = pProgress->WaitForCompletion(lTimeout);
    649         else
    650             rc = pProgress->WaitForOperationCompletion((ULONG)lStage, lTimeout);
    651         if (SUCCEEDED(rc))
    652         {
    653             if (!callbackIsComplete(uContextID))
    654                 vrc = callbackIsCanceled(uContextID)
    655                     ? VERR_CANCELLED : VINF_SUCCESS;
    656         }
    657         else
    658             vrc = VERR_TIMEOUT;
    659     }
    660 
    661     LogFlowFunc(("Callback (CID=%u) completed with rc=%Rrc\n",
    662                  uContextID, vrc));
    663     return vrc;
    664 }
    665 
    666 /**
    66749 * Static callback function for receiving updates on guest control commands
    66850 * from the guest. Acts as a dispatcher for the actual class instance.
     
    67355 *
    67456 */
     57/* static */
    67558DECLCALLBACK(int) Guest::notifyCtrlDispatcher(void    *pvExtension,
    67659                                              uint32_t u32Function,
     
    742125    }
    743126
    744 #ifdef DEBUG
    745     /* @todo Don't use legacy stuff in debug mode. Remove for final! */
    746     return rc;
    747 #endif
    748 
    749     /* Legacy handling. */
    750     switch (u32Function)
    751     {
    752         case GUEST_DISCONNECTED:
    753         {
    754             PCALLBACKDATACLIENTDISCONNECTED pCBData = reinterpret_cast<PCALLBACKDATACLIENTDISCONNECTED>(pvParms);
    755             AssertPtr(pCBData);
    756             AssertReturn(sizeof(CALLBACKDATACLIENTDISCONNECTED) == cbParms, VERR_INVALID_PARAMETER);
    757             AssertReturn(CALLBACKDATAMAGIC_CLIENT_DISCONNECTED == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
    758 
    759             rc = pGuest->notifyCtrlClientDisconnected(u32Function, pCBData);
    760             break;
    761         }
    762 
    763         case GUEST_EXEC_SEND_STATUS:
    764         {
    765             PCALLBACKDATAEXECSTATUS pCBData = reinterpret_cast<PCALLBACKDATAEXECSTATUS>(pvParms);
    766             AssertPtr(pCBData);
    767             AssertReturn(sizeof(CALLBACKDATAEXECSTATUS) == cbParms, VERR_INVALID_PARAMETER);
    768             AssertReturn(CALLBACKDATAMAGIC_EXEC_STATUS == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
    769 
    770             rc = pGuest->notifyCtrlExecStatus(u32Function, pCBData);
    771             break;
    772         }
    773 
    774         case GUEST_EXEC_SEND_OUTPUT:
    775         {
    776             PCALLBACKDATAEXECOUT pCBData = reinterpret_cast<PCALLBACKDATAEXECOUT>(pvParms);
    777             AssertPtr(pCBData);
    778             AssertReturn(sizeof(CALLBACKDATAEXECOUT) == cbParms, VERR_INVALID_PARAMETER);
    779             AssertReturn(CALLBACKDATAMAGIC_EXEC_OUT == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
    780 
    781             rc = pGuest->notifyCtrlExecOut(u32Function, pCBData);
    782             break;
    783         }
    784 
    785         case GUEST_EXEC_SEND_INPUT_STATUS:
    786         {
    787             PCALLBACKDATAEXECINSTATUS pCBData = reinterpret_cast<PCALLBACKDATAEXECINSTATUS>(pvParms);
    788             AssertPtr(pCBData);
    789             AssertReturn(sizeof(CALLBACKDATAEXECINSTATUS) == cbParms, VERR_INVALID_PARAMETER);
    790             AssertReturn(CALLBACKDATAMAGIC_EXEC_IN_STATUS == pCBData->hdr.u32Magic, VERR_INVALID_PARAMETER);
    791 
    792             rc = pGuest->notifyCtrlExecInStatus(u32Function, pCBData);
    793             break;
    794         }
    795 
    796         default:
    797             /* Silently ignore not implemented functions. */
    798             rc = VERR_NOT_IMPLEMENTED;
    799             break;
    800     }
    801 
    802127    LogFlowFuncLeaveRC(rc);
    803128    return rc;
    804129}
    805 
    806 /* Function for handling the execution start/termination notification. */
    807 /* Callback can be called several times. */
    808 int Guest::notifyCtrlExecStatus(uint32_t                u32Function,
    809                                 PCALLBACKDATAEXECSTATUS pData)
    810 {
    811     AssertReturn(u32Function, VERR_INVALID_PARAMETER);
    812     AssertPtrReturn(pData, VERR_INVALID_PARAMETER);
    813 
    814     uint32_t uContextID = pData->hdr.u32ContextID;
    815     /* The context ID might be 0 in case the guest was not able to fetch
    816      * actual command. So we can't do much now but report an error. */
    817 
    818     /* Scope write locks as much as possible. */
    819     {
    820         AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    821 
    822         LogFlowFunc(("Execution status (CID=%u, pData=0x%p)\n",
    823                      uContextID, pData));
    824 
    825         PCALLBACKDATAEXECSTATUS pCallbackData =
    826             (PCALLBACKDATAEXECSTATUS)callbackGetUserDataMutableRaw(uContextID, NULL /* cbData */);
    827         if (pCallbackData)
    828         {
    829             pCallbackData->u32PID = pData->u32PID;
    830             pCallbackData->u32Status = pData->u32Status;
    831             pCallbackData->u32Flags = pData->u32Flags;
    832             /** @todo Copy void* buffer contents? */
    833         }
    834         /* If pCallbackData is NULL this might be an old request for which no user data
    835          * might exist anymore. */
    836     }
    837 
    838     int vrc = VINF_SUCCESS; /* Function result. */
    839     int rcCallback = VINF_SUCCESS; /* Callback result. */
    840     Utf8Str errMsg;
    841 
    842     /* Was progress canceled before? */
    843     bool fCanceled = callbackIsCanceled(uContextID);
    844     if (!fCanceled)
    845     {
    846         /* Handle process map. This needs to be done first in order to have a valid
    847          * map in case some callback gets notified a bit below. */
    848 
    849         uint32_t uHostPID = 0;
    850 
    851         /* Note: PIDs never get removed here in case the guest process signalled its
    852          *       end; instead the next call of GetProcessStatus() will remove the PID
    853          *       from the process map after we got the process' final (exit) status.
    854          *       See waitpid() for an example. */
    855         if (pData->u32PID) /* Only add/change a process if it has a valid PID (>0). */
    856         {
    857             uHostPID = callbackGetHostPID(uContextID);
    858             Assert(uHostPID);
    859 
    860             switch (pData->u32Status)
    861             {
    862                 /* Just reach through flags. */
    863                 case PROC_STS_TES:
    864                 case PROC_STS_TOK:
    865                     vrc = processSetStatus(uHostPID, pData->u32PID,
    866                                            (ExecuteProcessStatus_T)pData->u32Status,
    867                                            0 /* Exit code */, pData->u32Flags);
    868                     break;
    869                 /* Interprete u32Flags as the guest process' exit code. */
    870                 default:
    871                     vrc = processSetStatus(uHostPID, pData->u32PID,
    872                                            (ExecuteProcessStatus_T)pData->u32Status,
    873                                            pData->u32Flags /* Exit code */, 0 /* Flags */);
    874                     break;
    875             }
    876         }
    877 
    878         if (RT_SUCCESS(vrc))
    879         {
    880             /* Do progress handling. */
    881             switch (pData->u32Status)
    882             {
    883                 case PROC_STS_STARTED:
    884                     vrc = callbackMoveForward(uContextID, Guest::tr("Waiting for process to exit ..."));
    885                     LogRel(("Guest process (PID %u) started\n", pData->u32PID)); /** @todo Add process name */
    886                     break;
    887 
    888                 case PROC_STS_TEN: /* Terminated normally. */
    889                     vrc = callbackNotifyComplete(uContextID);
    890                     LogRel(("Guest process (PID %u) exited normally (exit code: %u)\n",
    891                             pData->u32PID, pData->u32Flags)); /** @todo Add process name */
    892                     break;
    893 
    894                 case PROC_STS_TEA: /* Terminated abnormally. */
    895                     LogRel(("Guest process (PID %u) terminated abnormally (exit code: %u)\n",
    896                             pData->u32PID, pData->u32Flags)); /** @todo Add process name */
    897                     errMsg = Utf8StrFmt(Guest::tr("Process terminated abnormally with status '%u'"),
    898                                         pData->u32Flags);
    899                     rcCallback = VERR_GENERAL_FAILURE; /** @todo */
    900                     break;
    901 
    902                 case PROC_STS_TES: /* Terminated through signal. */
    903                     LogRel(("Guest process (PID %u) terminated through signal (exit code: %u)\n",
    904                             pData->u32PID, pData->u32Flags)); /** @todo Add process name */
    905                     errMsg = Utf8StrFmt(Guest::tr("Process terminated via signal with status '%u'"),
    906                                         pData->u32Flags);
    907                     rcCallback = VERR_GENERAL_FAILURE; /** @todo */
    908                     break;
    909 
    910                 case PROC_STS_TOK:
    911                     LogRel(("Guest process (PID %u) timed out and was killed\n", pData->u32PID)); /** @todo Add process name */
    912                     errMsg = Utf8StrFmt(Guest::tr("Process timed out and was killed"));
    913                     rcCallback = VERR_TIMEOUT;
    914                     break;
    915 
    916                 case PROC_STS_TOA:
    917                     LogRel(("Guest process (PID %u) timed out and could not be killed\n", pData->u32PID)); /** @todo Add process name */
    918                     errMsg = Utf8StrFmt(Guest::tr("Process timed out and could not be killed"));
    919                     rcCallback = VERR_TIMEOUT;
    920                     break;
    921 
    922                 case PROC_STS_DWN:
    923                     LogRel(("Guest process (PID %u) killed because system is shutting down\n", pData->u32PID)); /** @todo Add process name */
    924                     /*
    925                      * If u32Flags has ExecuteProcessFlag_IgnoreOrphanedProcesses set, we don't report an error to
    926                      * our progress object. This is helpful for waiters which rely on the success of our progress object
    927                      * even if the executed process was killed because the system/VBoxService is shutting down.
    928                      *
    929                      * In this case u32Flags contains the actual execution flags reached in via Guest::ExecuteProcess().
    930                      */
    931                     if (pData->u32Flags & ExecuteProcessFlag_IgnoreOrphanedProcesses)
    932                     {
    933                         vrc = callbackNotifyComplete(uContextID);
    934                     }
    935                     else
    936                     {
    937                         errMsg = Utf8StrFmt(Guest::tr("Process killed because system is shutting down"));
    938                         rcCallback = VERR_CANCELLED;
    939                     }
    940                     break;
    941 
    942                 case PROC_STS_ERROR:
    943                 {
    944                     Utf8Str errDetail;
    945                     if (pData->u32PID)
    946                     {
    947                         errDetail = Utf8StrFmt(Guest::tr("Guest process (PID %u) could not be started because of rc=%Rrc"),
    948                                                pData->u32PID, pData->u32Flags);
    949                     }
    950                     else
    951                     {
    952                         switch (pData->u32Flags) /* u32Flags member contains the IPRT error code from guest side. */
    953                         {
    954                             case VERR_FILE_NOT_FOUND: /* This is the most likely error. */
    955                                 errDetail = Utf8StrFmt(Guest::tr("The specified file was not found on guest"));
    956                                 break;
    957 
    958                             case VERR_PATH_NOT_FOUND:
    959                                 errDetail = Utf8StrFmt(Guest::tr("Could not resolve path to specified file was not found on guest"));
    960                                 break;
    961 
    962                             case VERR_BAD_EXE_FORMAT:
    963                                 errDetail = Utf8StrFmt(Guest::tr("The specified file is not an executable format on guest"));
    964                                 break;
    965 
    966                             case VERR_AUTHENTICATION_FAILURE:
    967                                 errDetail = Utf8StrFmt(Guest::tr("The specified user was not able to logon on guest"));
    968                                 break;
    969 
    970                             case VERR_TIMEOUT:
    971                                 errDetail = Utf8StrFmt(Guest::tr("The guest did not respond within time"));
    972                                 break;
    973 
    974                             case VERR_CANCELLED:
    975                                 errDetail = Utf8StrFmt(Guest::tr("The execution operation was canceled"));
    976                                 break;
    977 
    978                             case VERR_PERMISSION_DENIED:
    979                                 errDetail = Utf8StrFmt(Guest::tr("Invalid user/password credentials"));
    980                                 break;
    981 
    982                             case VERR_MAX_PROCS_REACHED:
    983                                 errDetail = Utf8StrFmt(Guest::tr("Guest process could not be started because maximum number of parallel guest processes has been reached"));
    984                                 break;
    985 
    986                             default:
    987                                 errDetail = Utf8StrFmt(Guest::tr("Guest process reported error %Rrc"), pData->u32Flags);
    988                                 break;
    989                         }
    990                     }
    991 
    992                     errMsg = Utf8StrFmt(Guest::tr("Process execution failed: "), pData->u32Flags) + errDetail;
    993                     rcCallback = pData->u32Flags; /* Report back guest rc. */
    994 
    995                     LogRel((errMsg.c_str()));
    996 
    997                     break;
    998                 }
    999 
    1000                 default:
    1001                     vrc = VERR_INVALID_PARAMETER;
    1002                     break;
    1003             }
    1004         }
    1005     }
    1006     else
    1007     {
    1008         errMsg = Utf8StrFmt(Guest::tr("Process execution canceled"));
    1009         rcCallback = VERR_CANCELLED;
    1010     }
    1011 
    1012     /* Do we need to handle the callback error? */
    1013     if (RT_FAILURE(rcCallback))
    1014     {
    1015         AssertMsg(!errMsg.isEmpty(), ("Error message must not be empty!\n"));
    1016 
    1017         if (uContextID)
    1018         {
    1019             /* Notify all callbacks which are still waiting on something
    1020              * which is related to the current PID. */
    1021             if (pData->u32PID)
    1022             {
    1023                 int rc2 = callbackNotifyAllForPID(pData->u32PID, rcCallback, errMsg.c_str());
    1024                 if (RT_FAILURE(rc2))
    1025                 {
    1026                     LogFlowFunc(("Failed to notify other callbacks for PID=%u\n",
    1027                                  pData->u32PID));
    1028                     if (RT_SUCCESS(vrc))
    1029                         vrc = rc2;
    1030                 }
    1031             }
    1032 
    1033             /* Let the caller know what went wrong ... */
    1034             int rc2 = callbackNotifyEx(uContextID, rcCallback, errMsg.c_str());
    1035             if (RT_FAILURE(rc2))
    1036             {
    1037                 LogFlowFunc(("Failed to notify callback CID=%u for PID=%u\n",
    1038                              uContextID, pData->u32PID));
    1039                 if (RT_SUCCESS(vrc))
    1040                     vrc = rc2;
    1041             }
    1042         }
    1043         else
    1044         {
    1045             /* Since we don't know which context exactly failed all we can do is to shutdown
    1046              * all contexts ... */
    1047             errMsg = Utf8StrFmt(Guest::tr("Client reported critical error %Rrc -- shutting down"),
    1048                                 pData->u32Flags);
    1049 
    1050             /* Cancel all callbacks. */
    1051             CallbackMapIter it;
    1052             for (it = mCallbackMap.begin(); it != mCallbackMap.end(); it++)
    1053             {
    1054                 int rc2 = callbackNotifyEx(it->first, VERR_CANCELLED,
    1055                                            errMsg.c_str());
    1056                 AssertRC(rc2);
    1057             }
    1058         }
    1059 
    1060         LogFlowFunc(("Process (CID=%u, status=%u) reported: %s\n",
    1061                      uContextID, pData->u32Status, errMsg.c_str()));
    1062     }
    1063     LogFlowFunc(("Returned with rc=%Rrc, rcCallback=%Rrc\n",
    1064                  vrc, rcCallback));
    1065     return vrc;
    1066 }
    1067 
    1068 /* Function for handling the execution output notification. */
    1069 int Guest::notifyCtrlExecOut(uint32_t             u32Function,
    1070                              PCALLBACKDATAEXECOUT pData)
    1071 {
    1072     AssertReturn(u32Function, VERR_INVALID_PARAMETER);
    1073     AssertPtrReturn(pData, VERR_INVALID_PARAMETER);
    1074 
    1075     uint32_t uContextID = pData->hdr.u32ContextID;
    1076     Assert(uContextID);
    1077 
    1078     /* Scope write locks as much as possible. */
    1079     {
    1080         AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1081 
    1082         LogFlowFunc(("Output status (CID=%u, pData=0x%p)\n",
    1083                      uContextID, pData));
    1084 
    1085         PCALLBACKDATAEXECOUT pCallbackData =
    1086             (PCALLBACKDATAEXECOUT)callbackGetUserDataMutableRaw(uContextID, NULL /* cbData */);
    1087         if (pCallbackData)
    1088         {
    1089             pCallbackData->u32PID = pData->u32PID;
    1090             pCallbackData->u32HandleId = pData->u32HandleId;
    1091             pCallbackData->u32Flags = pData->u32Flags;
    1092 
    1093             /* Make sure we really got something! */
    1094             if (   pData->cbData
    1095                 && pData->pvData)
    1096             {
    1097                 callbackFreeUserData(pCallbackData->pvData);
    1098 
    1099                 /* Allocate data buffer and copy it */
    1100                 pCallbackData->pvData = RTMemAlloc(pData->cbData);
    1101                 pCallbackData->cbData = pData->cbData;
    1102 
    1103                 AssertReturn(pCallbackData->pvData, VERR_NO_MEMORY);
    1104                 memcpy(pCallbackData->pvData, pData->pvData, pData->cbData);
    1105             }
    1106             else /* Nothing received ... */
    1107             {
    1108                 pCallbackData->pvData = NULL;
    1109                 pCallbackData->cbData = 0;
    1110             }
    1111         }
    1112         /* If pCallbackData is NULL this might be an old request for which no user data
    1113          * might exist anymore. */
    1114     }
    1115 
    1116     int vrc;
    1117     if (callbackIsCanceled(pData->u32PID))
    1118     {
    1119         vrc = callbackNotifyEx(uContextID, VERR_CANCELLED,
    1120                                Guest::tr("The output operation was canceled"));
    1121     }
    1122     else
    1123         vrc = callbackNotifyComplete(uContextID);
    1124 
    1125     return vrc;
    1126 }
    1127 
    1128 /* Function for handling the execution input status notification. */
    1129 int Guest::notifyCtrlExecInStatus(uint32_t                  u32Function,
    1130                                   PCALLBACKDATAEXECINSTATUS pData)
    1131 {
    1132     AssertReturn(u32Function, VERR_INVALID_PARAMETER);
    1133     AssertPtrReturn(pData, VERR_INVALID_PARAMETER);
    1134 
    1135     uint32_t uContextID = pData->hdr.u32ContextID;
    1136     Assert(uContextID);
    1137 
    1138     /* Scope write locks as much as possible. */
    1139     {
    1140         AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1141 
    1142         LogFlowFunc(("Input status (CID=%u, pData=0x%p)\n",
    1143                      uContextID, pData));
    1144 
    1145         PCALLBACKDATAEXECINSTATUS pCallbackData =
    1146             (PCALLBACKDATAEXECINSTATUS)callbackGetUserDataMutableRaw(uContextID, NULL /* cbData */);
    1147         if (pCallbackData)
    1148         {
    1149             /* Save bytes processed. */
    1150             pCallbackData->cbProcessed = pData->cbProcessed;
    1151             pCallbackData->u32Status   = pData->u32Status;
    1152             pCallbackData->u32Flags    = pData->u32Flags;
    1153             pCallbackData->u32PID      = pData->u32PID;
    1154         }
    1155         /* If pCallbackData is NULL this might be an old request for which no user data
    1156          * might exist anymore. */
    1157     }
    1158 
    1159     return callbackNotifyComplete(uContextID);
    1160 }
    1161 
    1162 int Guest::notifyCtrlClientDisconnected(uint32_t                        u32Function,
    1163                                         PCALLBACKDATACLIENTDISCONNECTED pData)
    1164 {
    1165     /* u32Function is 0. */
    1166     AssertPtrReturn(pData, VERR_INVALID_PARAMETER);
    1167 
    1168     uint32_t uContextID = pData->hdr.u32ContextID;
    1169     Assert(uContextID);
    1170 
    1171     LogFlowFunc(("Client disconnected (CID=%u)\n,", uContextID));
    1172 
    1173     return callbackNotifyEx(uContextID, VERR_CANCELLED,
    1174                             Guest::tr("Client disconnected"));
    1175 }
    1176 
    1177 uint32_t Guest::processGetGuestPID(uint32_t uHostPID)
    1178 {
    1179     AssertReturn(uHostPID, 0);
    1180 
    1181     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1182 
    1183     GuestProcessMapIter it = mGuestProcessMap.find(uHostPID);
    1184     if (it == mGuestProcessMap.end())
    1185         return 0;
    1186 
    1187     return it->second.mGuestPID;
    1188 }
    1189 
    1190 /**
    1191  * Gets guest process information. Removes the process from the map
    1192  * after the process was marked as exited/terminated.
    1193  *
    1194  * @return  IPRT status code.
    1195  * @param   uHostPID                Host PID of guest process to get status for.
    1196  * @param   pProcess                Where to store the process information. Optional.
    1197  * @param   fRemove                 Flag indicating whether to remove the
    1198  *                                  process from the map when process marked a
    1199  *                                  exited/terminated.
    1200  */
    1201 int Guest::processGetStatus(uint32_t uHostPID, PVBOXGUESTCTRL_PROCESS pProcess,
    1202                             bool fRemove)
    1203 {
    1204     AssertReturn(uHostPID, VERR_INVALID_PARAMETER);
    1205 
    1206     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1207 
    1208     GuestProcessMapIter it = mGuestProcessMap.find(uHostPID);
    1209     if (it != mGuestProcessMap.end())
    1210     {
    1211         if (pProcess)
    1212         {
    1213             pProcess->mGuestPID = it->second.mGuestPID;
    1214             pProcess->mStatus   = it->second.mStatus;
    1215             pProcess->mExitCode = it->second.mExitCode;
    1216             pProcess->mFlags    = it->second.mFlags;
    1217         }
    1218 
    1219         /* Only remove processes from our map when they signalled their final
    1220          * status. */
    1221         if (   fRemove
    1222             && (   it->second.mStatus != ExecuteProcessStatus_Undefined
    1223                 && it->second.mStatus != ExecuteProcessStatus_Started))
    1224         {
    1225             mGuestProcessMap.erase(it);
    1226         }
    1227 
    1228         return VINF_SUCCESS;
    1229     }
    1230 
    1231     return VERR_NOT_FOUND;
    1232 }
    1233 
    1234 /**
    1235  * Sets the current status of a guest process.
    1236  *
    1237  * @return  IPRT status code.
    1238  * @param   uHostPID                Host PID of guest process to set status (and guest PID) for.
    1239  * @param   uGuestPID               Guest PID to assign to the host PID.
    1240  * @param   enmStatus               Current status to set.
    1241  * @param   uExitCode               Exit code (if any).
    1242  * @param   uFlags                  Additional flags.
    1243  */
    1244 int Guest::processSetStatus(uint32_t uHostPID, uint32_t uGuestPID,
    1245                             ExecuteProcessStatus_T enmStatus, uint32_t uExitCode, uint32_t uFlags)
    1246 {
    1247     AssertReturn(uHostPID, VERR_INVALID_PARAMETER);
    1248     /* Assigning a guest PID is optional. */
    1249 
    1250     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1251 
    1252     GuestProcessMapIter it = mGuestProcessMap.find(uHostPID);
    1253     if (it != mGuestProcessMap.end())
    1254     {
    1255         it->second.mGuestPID = uGuestPID;
    1256         it->second.mStatus   = enmStatus;
    1257         it->second.mExitCode = uExitCode;
    1258         it->second.mFlags    = uFlags;
    1259     }
    1260     else
    1261     {
    1262         VBOXGUESTCTRL_PROCESS process;
    1263 
    1264         /* uGuestPID is optional -- the caller could call this function
    1265          * before the guest process actually was started and a (valid) guest PID
    1266          * was returned. */
    1267         process.mGuestPID = uGuestPID;
    1268         process.mStatus   = enmStatus;
    1269         process.mExitCode = uExitCode;
    1270         process.mFlags    = uFlags;
    1271 
    1272         mGuestProcessMap[uHostPID] = process;
    1273     }
    1274 
    1275     return VINF_SUCCESS;
    1276 }
    1277 
    1278 HRESULT Guest::setErrorCompletion(int rc)
    1279 {
    1280     HRESULT hRC;
    1281     if (rc == VERR_NOT_FOUND)
    1282         hRC = setErrorNoLog(VBOX_E_VM_ERROR,
    1283                             tr("VMM device is not available (is the VM running?)"));
    1284     else if (rc == VERR_CANCELLED)
    1285         hRC = setErrorNoLog(VBOX_E_IPRT_ERROR,
    1286                             tr("Process execution has been canceled"));
    1287     else if (rc == VERR_TIMEOUT)
    1288         hRC= setErrorNoLog(VBOX_E_IPRT_ERROR,
    1289                             tr("The guest did not respond within time"));
    1290     else
    1291         hRC = setErrorNoLog(E_UNEXPECTED,
    1292                             tr("Waiting for completion failed with error %Rrc"), rc);
    1293     return hRC;
    1294 }
    1295 
    1296 HRESULT Guest::setErrorFromProgress(ComPtr<IProgress> pProgress)
    1297 {
    1298     BOOL fCompleted;
    1299     HRESULT rc = pProgress->COMGETTER(Completed)(&fCompleted);
    1300     ComAssertComRC(rc);
    1301 
    1302     LONG rcProc = S_OK;
    1303     Utf8Str strError;
    1304 
    1305     if (!fCompleted)
    1306     {
    1307         BOOL fCanceled;
    1308         rc = pProgress->COMGETTER(Canceled)(&fCanceled);
    1309         ComAssertComRC(rc);
    1310 
    1311         strError = fCanceled ? Utf8StrFmt(Guest::tr("Process execution was canceled"))
    1312                              : Utf8StrFmt(Guest::tr("Process neither completed nor canceled; this shouldn't happen"));
    1313     }
    1314     else
    1315     {
    1316         rc = pProgress->COMGETTER(ResultCode)(&rcProc);
    1317         ComAssertComRC(rc);
    1318 
    1319         if (FAILED(rcProc))
    1320         {
    1321             ProgressErrorInfo info(pProgress);
    1322             strError = info.getText();
    1323         }
    1324     }
    1325 
    1326     if (FAILED(rcProc))
    1327     {
    1328         AssertMsg(!strError.isEmpty(), ("Error message must not be empty!\n"));
    1329         return setErrorInternal(rcProc,
    1330                                 this->getClassIID(),
    1331                                 this->getComponentName(),
    1332                                 strError,
    1333                                 false /* aWarning */,
    1334                                 false /* aLogIt */);
    1335     }
    1336 
    1337     return S_OK;
    1338 }
    1339 
    1340 HRESULT Guest::setErrorHGCM(int rc)
    1341 {
    1342     HRESULT hRC;
    1343     if (rc == VERR_INVALID_VM_HANDLE)
    1344         hRC = setErrorNoLog(VBOX_E_VM_ERROR,
    1345                             tr("VMM device is not available (is the VM running?)"));
    1346     else if (rc == VERR_NOT_FOUND)
    1347         hRC = setErrorNoLog(VBOX_E_IPRT_ERROR,
    1348                             tr("The guest execution service is not ready (yet)"));
    1349     else if (rc == VERR_HGCM_SERVICE_NOT_FOUND)
    1350         hRC= setErrorNoLog(VBOX_E_IPRT_ERROR,
    1351                             tr("The guest execution service is not available"));
    1352     else /* HGCM call went wrong. */
    1353         hRC = setErrorNoLog(E_UNEXPECTED,
    1354                             tr("The HGCM call failed with error %Rrc"), rc);
    1355     return hRC;
    1356 }
    1357130#endif /* VBOX_WITH_GUEST_CONTROL */
    1358 
    1359 STDMETHODIMP Guest::ExecuteProcess(IN_BSTR aCommand, ULONG aFlags,
    1360                                    ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
    1361                                    IN_BSTR aUsername, IN_BSTR aPassword,
    1362                                    ULONG aTimeoutMS, ULONG *aPID, IProgress **aProgress)
    1363 {
    1364 /** @todo r=bird: Eventually we should clean up all the timeout parameters
    1365  *        in the API and have the same way of specifying infinite waits!  */
    1366 #ifndef VBOX_WITH_GUEST_CONTROL
    1367     ReturnComNotImplemented();
    1368 #else  /* VBOX_WITH_GUEST_CONTROL */
    1369     using namespace guestControl;
    1370 
    1371     CheckComArgStrNotEmptyOrNull(aCommand);
    1372     CheckComArgOutPointerValid(aPID);
    1373     CheckComArgOutPointerValid(aProgress);
    1374 
    1375     /* Do not allow anonymous executions (with system rights). */
    1376     if (RT_UNLIKELY((aUsername) == NULL || *(aUsername) == '\0'))
    1377         return setError(E_INVALIDARG, tr("No user name specified"));
    1378 
    1379     LogRel(("Executing guest process \"%s\" as user \"%s\" ...\n",
    1380             Utf8Str(aCommand).c_str(), Utf8Str(aUsername).c_str()));
    1381 
    1382     return executeProcessInternal(aCommand, aFlags, ComSafeArrayInArg(aArguments),
    1383                                   ComSafeArrayInArg(aEnvironment),
    1384                                   aUsername, aPassword, aTimeoutMS, aPID, aProgress, NULL /* rc */);
    1385 #endif
    1386 }
    1387 
    1388 #ifdef VBOX_WITH_GUEST_CONTROL
    1389 /**
    1390  * Executes and waits for an internal tool (that is, a tool which is integrated into
    1391  * VBoxService, beginning with "vbox_" (e.g. "vbox_ls")) to finish its operation.
    1392  *
    1393  * @return  HRESULT
    1394  * @param   aTool                   Name of tool to execute.
    1395  * @param   aDescription            Friendly description of the operation.
    1396  * @param   aFlags                  Execution flags.
    1397  * @param   aUsername               Username to execute tool under.
    1398  * @param   aPassword               The user's password.
    1399  * @param   uFlagsToAdd             ExecuteProcessFlag flags to add to the execution operation.
    1400  * @param   aProgress               Pointer which receives the tool's progress object. Optional.
    1401  * @param   aPID                    Pointer which receives the tool's PID. Optional.
    1402  */
    1403 HRESULT Guest::executeAndWaitForTool(IN_BSTR aTool, IN_BSTR aDescription,
    1404                                      ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
    1405                                      IN_BSTR aUsername, IN_BSTR aPassword,
    1406                                      ULONG uFlagsToAdd,
    1407                                      GuestCtrlStreamObjects *pObjStdOut, GuestCtrlStreamObjects *pObjStdErr,
    1408                                      IProgress **aProgress, ULONG *aPID)
    1409 {
    1410     ComPtr<IProgress> pProgress;
    1411     ULONG uPID;
    1412     ULONG uFlags = ExecuteProcessFlag_Hidden;
    1413     if (uFlagsToAdd)
    1414         uFlags |= uFlagsToAdd;
    1415 
    1416     bool fParseOutput = false;
    1417     if (   (   (uFlags & ExecuteProcessFlag_WaitForStdOut)
    1418             && pObjStdOut)
    1419         || (   (uFlags & ExecuteProcessFlag_WaitForStdErr)
    1420             && pObjStdErr))
    1421     {
    1422         fParseOutput = true;
    1423     }
    1424 
    1425     HRESULT hr = ExecuteProcess(aTool,
    1426                                 uFlags,
    1427                                 ComSafeArrayInArg(aArguments),
    1428                                 ComSafeArrayInArg(aEnvironment),
    1429                                 aUsername, aPassword,
    1430                                 0 /* No timeout */,
    1431                                 &uPID, pProgress.asOutParam());
    1432     if (SUCCEEDED(hr))
    1433     {
    1434         /* Wait for tool being started. */
    1435         hr = pProgress->WaitForOperationCompletion( 0 /* Stage, starting the process */,
    1436                                                    -1 /* No timeout */);
    1437     }
    1438 
    1439     if (   SUCCEEDED(hr)
    1440         && !(uFlags & ExecuteProcessFlag_WaitForProcessStartOnly))
    1441     {
    1442         if (!fParseOutput)
    1443         {
    1444             if (   !(uFlags & ExecuteProcessFlag_WaitForStdOut)
    1445                 && !(uFlags & ExecuteProcessFlag_WaitForStdErr))
    1446             {
    1447                 hr = executeWaitForExit(uPID, pProgress, 0 /* No timeout */);
    1448             }
    1449         }
    1450         else
    1451         {
    1452             BOOL fCompleted;
    1453             while (   SUCCEEDED(pProgress->COMGETTER(Completed)(&fCompleted))
    1454                    && !fCompleted)
    1455             {
    1456                 BOOL fCanceled;
    1457                 hr = pProgress->COMGETTER(Canceled)(&fCanceled);
    1458                 AssertComRC(hr);
    1459                 if (fCanceled)
    1460                 {
    1461                     hr = setErrorNoLog(VBOX_E_IPRT_ERROR,
    1462                                        tr("%s was cancelled"), Utf8Str(aDescription).c_str());
    1463                     break;
    1464                 }
    1465 
    1466                 if (   (uFlags & ExecuteProcessFlag_WaitForStdOut)
    1467                     && pObjStdOut)
    1468                 {
    1469                     hr = executeStreamParse(uPID, ProcessOutputFlag_None /* StdOut */, *pObjStdOut);
    1470                 }
    1471 
    1472                 if (   (uFlags & ExecuteProcessFlag_WaitForStdErr)
    1473                     && pObjStdErr)
    1474                 {
    1475                     hr = executeStreamParse(uPID, ProcessOutputFlag_StdErr, *pObjStdErr);
    1476                 }
    1477 
    1478                 if (FAILED(hr))
    1479                     break;
    1480             }
    1481         }
    1482     }
    1483 
    1484     if (SUCCEEDED(hr))
    1485     {
    1486         if (aProgress)
    1487         {
    1488             /* Return the progress to the caller. */
    1489             pProgress.queryInterfaceTo(aProgress);
    1490         }
    1491         else if (!pProgress.isNull())
    1492             pProgress.setNull();
    1493 
    1494         if (aPID)
    1495             *aPID = uPID;
    1496     }
    1497 
    1498     return hr;
    1499 }
    1500 
    1501 /**
    1502  * TODO
    1503  *
    1504  * @return  HRESULT
    1505  * @param   aObjName
    1506  * @param   pStreamBlock
    1507  * @param   pObjInfo
    1508  * @param   enmAddAttribs
    1509  */
    1510 int Guest::executeStreamQueryFsObjInfo(IN_BSTR aObjName,
    1511                                        GuestProcessStreamBlock &streamBlock,
    1512                                        PRTFSOBJINFO pObjInfo,
    1513                                        RTFSOBJATTRADD enmAddAttribs)
    1514 {
    1515     Utf8Str Utf8ObjName(aObjName);
    1516     int64_t iVal;
    1517     int rc = streamBlock.GetInt64Ex("st_size", &iVal);
    1518     if (RT_SUCCESS(rc))
    1519         pObjInfo->cbObject = iVal;
    1520     /** @todo Add more stuff! */
    1521     return rc;
    1522 }
    1523 
    1524 /**
    1525  * Tries to drain the guest's output and fill it into
    1526  * a guest process stream object for later usage.
    1527  *
    1528  * @todo    What's about specifying stderr?
    1529  * @return  IPRT status code.
    1530  * @param   aPID                    PID of process to get the output from.
    1531  * @param   aFlags                  Which stream to drain (stdout or stderr).
    1532  * @param   pStream                 Pointer to guest process stream to fill. If NULL,
    1533  *                                  data goes to /dev/null.
    1534  */
    1535 int Guest::executeStreamDrain(ULONG aPID, ULONG aFlags, GuestProcessStream *pStream)
    1536 {
    1537     AssertReturn(aPID, VERR_INVALID_PARAMETER);
    1538     /* pStream is optional. */
    1539 
    1540     int rc = VINF_SUCCESS;
    1541     for (;;)
    1542     {
    1543         SafeArray<BYTE> aData;
    1544         HRESULT hr = getProcessOutputInternal(aPID, aFlags,
    1545                                               0 /* Infinite timeout */,
    1546                                               _64K, ComSafeArrayAsOutParam(aData), &rc);
    1547         if (RT_SUCCESS(rc))
    1548         {
    1549             if (   pStream
    1550                 && aData.size())
    1551             {
    1552                 rc = pStream->AddData(aData.raw(), aData.size());
    1553                 if (RT_UNLIKELY(RT_FAILURE(rc)))
    1554                     break;
    1555             }
    1556 
    1557             continue; /* Try one more time. */
    1558         }
    1559         else /* No more output and/or error! */
    1560         {
    1561             if (   rc == VERR_NOT_FOUND
    1562                 || rc == VERR_BROKEN_PIPE)
    1563             {
    1564                 rc = VINF_SUCCESS;
    1565             }
    1566 
    1567             break;
    1568         }
    1569     }
    1570 
    1571     return rc;
    1572 }
    1573 
    1574 /**
    1575  * Tries to retrieve the next stream block of a given stream and
    1576  * drains the process output only as much as needed to get this next
    1577  * stream block.
    1578  *
    1579  * @return  IPRT status code.
    1580  * @param   ulPID
    1581  * @param   ulFlags
    1582  * @param   stream
    1583  * @param   streamBlock
    1584  */
    1585 int Guest::executeStreamGetNextBlock(ULONG ulPID,
    1586                                      ULONG ulFlags,
    1587                                      GuestProcessStream &stream,
    1588                                      GuestProcessStreamBlock &streamBlock)
    1589 {
    1590     AssertReturn(!streamBlock.GetCount(), VERR_INVALID_PARAMETER);
    1591 
    1592     LogFlowFunc(("Getting next stream block of PID=%u, Flags=%u; cbStrmSize=%u, cbStrmOff=%u\n",
    1593                  ulPID, ulFlags, stream.GetSize(), stream.GetOffset()));
    1594 
    1595     int rc;
    1596 
    1597     uint32_t cPairs = 0;
    1598     bool fDrainStream = true;
    1599 
    1600     do
    1601     {
    1602         rc = stream.ParseBlock(streamBlock);
    1603         LogFlowFunc(("Parsing block rc=%Rrc, strmBlockCnt=%ld\n",
    1604                      rc, streamBlock.GetCount()));
    1605 
    1606         if (RT_FAILURE(rc)) /* More data needed or empty buffer? */
    1607         {
    1608             if (fDrainStream)
    1609             {
    1610                 SafeArray<BYTE> aData;
    1611                 HRESULT hr = getProcessOutputInternal(ulPID, ulFlags,
    1612                                                       0 /* Infinite timeout */,
    1613                                                       _64K, ComSafeArrayAsOutParam(aData), &rc);
    1614                 if (SUCCEEDED(hr))
    1615                 {
    1616                     LogFlowFunc(("Got %ld bytes of additional data\n", aData.size()));
    1617 
    1618                     if (RT_FAILURE(rc))
    1619                     {
    1620                         if (rc == VERR_BROKEN_PIPE)
    1621                              rc = VINF_SUCCESS; /* No more data because process already ended. */
    1622                         break;
    1623                     }
    1624 
    1625                     if (aData.size())
    1626                     {
    1627                         rc = stream.AddData(aData.raw(), aData.size());
    1628                         if (RT_UNLIKELY(RT_FAILURE(rc)))
    1629                             break;
    1630                     }
    1631 
    1632                     /* Reset found pairs to not break out too early and let all the new
    1633                      * data to be parsed as well. */
    1634                     cPairs = 0;
    1635                     continue; /* Try one more time. */
    1636                 }
    1637                 else
    1638                 {
    1639                     LogFlowFunc(("Getting output returned hr=%Rhrc\n", hr));
    1640 
    1641                     /* No more output to drain from stream. */
    1642                     if (rc == VERR_NOT_FOUND)
    1643                     {
    1644                         fDrainStream = false;
    1645                         continue;
    1646                     }
    1647 
    1648                     break;
    1649                 }
    1650             }
    1651             else
    1652             {
    1653                 /* We haved drained the stream as much as we can and reached the
    1654                  * end of our stream buffer -- that means that there simply is no
    1655                  * stream block anymore, which is ok. */
    1656                 if (rc == VERR_NO_DATA)
    1657                     rc = VINF_SUCCESS;
    1658                 break;
    1659             }
    1660         }
    1661         else
    1662             cPairs = streamBlock.GetCount();
    1663     }
    1664     while (!cPairs);
    1665 
    1666     LogFlowFunc(("Returned with strmBlockCnt=%ld, cPairs=%ld, rc=%Rrc\n",
    1667                  streamBlock.GetCount(), cPairs, rc));
    1668     return rc;
    1669 }
    1670 
    1671 /**
    1672  * Tries to get the next upcoming value block from a started guest process
    1673  * by first draining its output and then processing the received guest stream.
    1674  *
    1675  * @return  IPRT status code.
    1676  * @param   ulPID                   PID of process to get/parse the output from.
    1677  * @param   ulFlags                 ?
    1678  * @param   stream                  Reference to process stream object to use.
    1679  * @param   streamBlock             Reference that receives the next stream block data.
    1680  *
    1681  */
    1682 int Guest::executeStreamParseNextBlock(ULONG ulPID,
    1683                                        ULONG ulFlags,
    1684                                        GuestProcessStream &stream,
    1685                                        GuestProcessStreamBlock &streamBlock)
    1686 {
    1687     AssertReturn(!streamBlock.GetCount(), VERR_INVALID_PARAMETER);
    1688 
    1689     int rc;
    1690     do
    1691     {
    1692         rc = stream.ParseBlock(streamBlock);
    1693         if (RT_FAILURE(rc))
    1694             break;
    1695     }
    1696     while (!streamBlock.GetCount());
    1697 
    1698     return rc;
    1699 }
    1700 
    1701 /**
    1702  * Gets output from a formerly started guest process, tries to parse all of its guest
    1703  * stream (as long as data is available) and returns a stream object which can contain
    1704  * multiple stream blocks (which in turn then can contain key=value pairs).
    1705  *
    1706  * @return  HRESULT
    1707  * @param   ulPID                   PID of process to get/parse the output from.
    1708  * @param   ulFlags                 ?
    1709  * @param   streamObjects           Reference to a guest stream object structure for
    1710  *                                  storing the parsed data.
    1711  */
    1712 HRESULT Guest::executeStreamParse(ULONG ulPID, ULONG ulFlags, GuestCtrlStreamObjects &streamObjects)
    1713 {
    1714     GuestProcessStream stream;
    1715     int rc = executeStreamDrain(ulPID, ulFlags, &stream);
    1716     if (RT_SUCCESS(rc))
    1717     {
    1718         do
    1719         {
    1720             /* Try to parse the stream output we gathered until now. If we still need more
    1721              * data the parsing routine will tell us and we just do another poll round. */
    1722             GuestProcessStreamBlock curBlock;
    1723             rc = executeStreamParseNextBlock(ulPID, ulFlags, stream, curBlock);
    1724             if (RT_SUCCESS(rc))
    1725                 streamObjects.push_back(curBlock);
    1726         } while (RT_SUCCESS(rc));
    1727 
    1728         if (rc == VERR_NO_DATA) /* End of data reached. */
    1729             rc = VINF_SUCCESS;
    1730     }
    1731 
    1732     if (RT_FAILURE(rc))
    1733         return setError(VBOX_E_IPRT_ERROR,
    1734                         tr("Error while parsing guest output (%Rrc)"), rc);
    1735     return rc;
    1736 }
    1737 
    1738 /**
    1739  * Waits for a fomerly started guest process to exit using its progress
    1740  * object and returns its final status. Returns E_ABORT if guest process
    1741  * was canceled.
    1742  *
    1743  * @return  IPRT status code.
    1744  * @param   uPID                    PID of guest process to wait for.
    1745  * @param   pProgress               Progress object to wait for.
    1746  * @param   uTimeoutMS              Timeout (in ms) for waiting; use 0 for
    1747  *                                  an indefinite timeout.
    1748  * @param   pRetStatus              Pointer where to store the final process
    1749  *                                  status. Optional.
    1750  * @param   puRetExitCode           Pointer where to store the final process
    1751  *                                  exit code. Optional.
    1752  */
    1753 HRESULT Guest::executeWaitForExit(ULONG uPID, ComPtr<IProgress> pProgress, ULONG uTimeoutMS)
    1754 {
    1755     HRESULT rc = S_OK;
    1756 
    1757     BOOL fCanceled = FALSE;
    1758     if (   SUCCEEDED(pProgress->COMGETTER(Canceled(&fCanceled)))
    1759         && fCanceled)
    1760     {
    1761         return E_ABORT;
    1762     }
    1763 
    1764     BOOL fCompleted = FALSE;
    1765     if (   SUCCEEDED(pProgress->COMGETTER(Completed(&fCompleted)))
    1766         && !fCompleted)
    1767     {
    1768         rc = pProgress->WaitForCompletion(  !uTimeoutMS
    1769                                           ? -1 /* No timeout */
    1770                                           : uTimeoutMS);
    1771         if (FAILED(rc))
    1772             rc = setError(VBOX_E_IPRT_ERROR,
    1773                           tr("Waiting for guest process to end failed (%Rhrc)"), rc);
    1774     }
    1775 
    1776     return rc;
    1777 }
    1778 
    1779 /**
    1780  * Does the actual guest process execution, internal function.
    1781  *
    1782  * @return  HRESULT
    1783  * @param   aCommand                Command line to execute.
    1784  * @param   aFlags                  Execution flags.
    1785  * @param   Username                Username to execute the process with.
    1786  * @param   aPassword               The user's password.
    1787  * @param   aTimeoutMS              Timeout (in ms) to wait for the execution operation.
    1788  * @param   aPID                    Pointer that receives the guest process' PID.
    1789  * @param   aProgress               Pointer that receives the guest process' progress object.
    1790  * @param   pRC                     Pointer that receives the internal IPRT return code. Optional.
    1791  */
    1792 HRESULT Guest::executeProcessInternal(IN_BSTR aCommand, ULONG aFlags,
    1793                                       ComSafeArrayIn(IN_BSTR, aArguments), ComSafeArrayIn(IN_BSTR, aEnvironment),
    1794                                       IN_BSTR aUsername, IN_BSTR aPassword,
    1795                                       ULONG aTimeoutMS, ULONG *aPID, IProgress **aProgress, int *pRC)
    1796 {
    1797 /** @todo r=bird: Eventually we should clean up all the timeout parameters
    1798  *        in the API and have the same way of specifying infinite waits!  */
    1799     using namespace guestControl;
    1800 
    1801     AutoCaller autoCaller(this);
    1802     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    1803 
    1804     /* Validate flags. */
    1805     if (aFlags != ExecuteProcessFlag_None)
    1806     {
    1807         if (   !(aFlags & ExecuteProcessFlag_IgnoreOrphanedProcesses)
    1808             && !(aFlags & ExecuteProcessFlag_WaitForProcessStartOnly)
    1809             && !(aFlags & ExecuteProcessFlag_Hidden)
    1810             && !(aFlags & ExecuteProcessFlag_NoProfile)
    1811             && !(aFlags & ExecuteProcessFlag_WaitForStdOut)
    1812             && !(aFlags & ExecuteProcessFlag_WaitForStdErr))
    1813         {
    1814             if (pRC)
    1815                 *pRC = VERR_INVALID_PARAMETER;
    1816             return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), aFlags);
    1817         }
    1818     }
    1819 
    1820     HRESULT rc = S_OK;
    1821 
    1822     try
    1823     {
    1824         /*
    1825          * Create progress object.  Note that this is a multi operation
    1826          * object to perform the following steps:
    1827          * - Operation 1 (0): Create/start process.
    1828          * - Operation 2 (1): Wait for process to exit.
    1829          * If this progress completed successfully (S_OK), the process
    1830          * started and exited normally. In any other case an error/exception
    1831          * occurred.
    1832          */
    1833         ComObjPtr <Progress> pProgress;
    1834         rc = pProgress.createObject();
    1835         if (SUCCEEDED(rc))
    1836         {
    1837             rc = pProgress->init(static_cast<IGuest*>(this),
    1838                                  Bstr(tr("Executing process")).raw(),
    1839                                  TRUE,
    1840                                  2,                                          /* Number of operations. */
    1841                                  Bstr(tr("Starting process ...")).raw());    /* Description of first stage. */
    1842         }
    1843         ComAssertComRC(rc);
    1844 
    1845         /*
    1846          * Prepare process execution.
    1847          */
    1848         int vrc = VINF_SUCCESS;
    1849         Utf8Str Utf8Command(aCommand);
    1850 
    1851         /* Adjust timeout. If set to 0, we define
    1852          * an infinite timeout. */
    1853         if (aTimeoutMS == 0)
    1854             aTimeoutMS = UINT32_MAX;
    1855 
    1856         /* Prepare arguments. */
    1857         char **papszArgv = NULL;
    1858         uint32_t uNumArgs = 0;
    1859         if (aArguments)
    1860         {
    1861             com::SafeArray<IN_BSTR> args(ComSafeArrayInArg(aArguments));
    1862             uNumArgs = args.size();
    1863             papszArgv = (char**)RTMemAlloc(sizeof(char*) * (uNumArgs + 1));
    1864             AssertReturn(papszArgv, E_OUTOFMEMORY);
    1865             for (unsigned i = 0; RT_SUCCESS(vrc) && i < uNumArgs; i++)
    1866                 vrc = RTUtf16ToUtf8(args[i], &papszArgv[i]);
    1867             papszArgv[uNumArgs] = NULL;
    1868         }
    1869 
    1870         Utf8Str Utf8UserName(aUsername);
    1871         Utf8Str Utf8Password(aPassword);
    1872         uint32_t uHostPID = 0;
    1873 
    1874         if (RT_SUCCESS(vrc))
    1875         {
    1876             uint32_t uContextID = 0;
    1877 
    1878             char *pszArgs = NULL;
    1879             if (uNumArgs > 0)
    1880                 vrc = RTGetOptArgvToString(&pszArgs, papszArgv, RTGETOPTARGV_CNV_QUOTE_MS_CRT);
    1881             if (RT_SUCCESS(vrc))
    1882             {
    1883                 uint32_t cbArgs = pszArgs ? strlen(pszArgs) + 1 : 0; /* Include terminating zero. */
    1884 
    1885                 /* Prepare environment. */
    1886                 void *pvEnv = NULL;
    1887                 uint32_t uNumEnv = 0;
    1888                 uint32_t cbEnv = 0;
    1889                 if (aEnvironment)
    1890                 {
    1891                     com::SafeArray<IN_BSTR> env(ComSafeArrayInArg(aEnvironment));
    1892 
    1893                     for (unsigned i = 0; i < env.size(); i++)
    1894                     {
    1895                         vrc = prepareExecuteEnv(Utf8Str(env[i]).c_str(), &pvEnv, &cbEnv, &uNumEnv);
    1896                         if (RT_FAILURE(vrc))
    1897                             break;
    1898                     }
    1899                 }
    1900 
    1901                 if (RT_SUCCESS(vrc))
    1902                 {
    1903                     VBOXGUESTCTRL_CALLBACK callback;
    1904                     vrc = callbackInit(&callback, VBOXGUESTCTRLCALLBACKTYPE_EXEC_START, pProgress);
    1905                     if (RT_SUCCESS(vrc))
    1906                         vrc = callbackAdd(&callback, &uContextID);
    1907 
    1908                     if (RT_SUCCESS(vrc))
    1909                     {
    1910                         VBOXHGCMSVCPARM paParms[15];
    1911                         int i = 0;
    1912                         paParms[i++].setUInt32(uContextID);
    1913                         paParms[i++].setPointer((void*)Utf8Command.c_str(), (uint32_t)Utf8Command.length() + 1);
    1914                         paParms[i++].setUInt32(aFlags);
    1915                         paParms[i++].setUInt32(uNumArgs);
    1916                         paParms[i++].setPointer((void*)pszArgs, cbArgs);
    1917                         paParms[i++].setUInt32(uNumEnv);
    1918                         paParms[i++].setUInt32(cbEnv);
    1919                         paParms[i++].setPointer((void*)pvEnv, cbEnv);
    1920                         paParms[i++].setPointer((void*)Utf8UserName.c_str(), (uint32_t)Utf8UserName.length() + 1);
    1921                         paParms[i++].setPointer((void*)Utf8Password.c_str(), (uint32_t)Utf8Password.length() + 1);
    1922 
    1923                         /*
    1924                          * If the WaitForProcessStartOnly flag is set, we only want to define and wait for a timeout
    1925                          * until the process was started - the process itself then gets an infinite timeout for execution.
    1926                          * This is handy when we want to start a process inside a worker thread within a certain timeout
    1927                          * but let the started process perform lengthly operations then.
    1928                          */
    1929                         if (aFlags & ExecuteProcessFlag_WaitForProcessStartOnly)
    1930                             paParms[i++].setUInt32(UINT32_MAX /* Infinite timeout */);
    1931                         else
    1932                             paParms[i++].setUInt32(aTimeoutMS);
    1933 
    1934                         VMMDev *pVMMDev = NULL;
    1935                         {
    1936                             /* Make sure mParent is valid, so set the read lock while using.
    1937                              * Do not keep this lock while doing the actual call, because in the meanwhile
    1938                              * another thread could request a write lock which would be a bad idea ... */
    1939                             AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    1940 
    1941                             /* Forward the information to the VMM device. */
    1942                             AssertPtr(mParent);
    1943                             pVMMDev = mParent->getVMMDev();
    1944                         }
    1945 
    1946                         if (pVMMDev)
    1947                         {
    1948                             LogFlowFunc(("hgcmHostCall numParms=%d\n", i));
    1949                             vrc = pVMMDev->hgcmHostCall("VBoxGuestControlSvc", HOST_EXEC_CMD,
    1950                                                        i, paParms);
    1951                         }
    1952                         else
    1953                             vrc = VERR_INVALID_VM_HANDLE;
    1954                     }
    1955                     RTMemFree(pvEnv);
    1956                 }
    1957                 RTStrFree(pszArgs);
    1958             }
    1959 
    1960             if (RT_SUCCESS(vrc))
    1961             {
    1962                 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    1963 
    1964                 /*
    1965                  * Generate a host-driven PID so that we immediately can return to the caller and
    1966                  * don't need to wait until the guest started the desired process to return the
    1967                  * PID generated by the guest OS.
    1968                  *
    1969                  * The guest PID will later be mapped to the host PID for later lookup.
    1970                  */
    1971                 vrc = VERR_NOT_FOUND; /* We did not find a host PID yet ... */
    1972 
    1973                 uint32_t uTries = 0;
    1974                 for (;;)
    1975                 {
    1976                     /* Create a new context ID ... */
    1977                     uHostPID = ASMAtomicIncU32(&mNextHostPID);
    1978                     if (uHostPID == UINT32_MAX)
    1979                         ASMAtomicUoWriteU32(&mNextHostPID, 1000);
    1980                     /* Is the host PID already used? Try next PID ... */
    1981                     GuestProcessMapIter it = mGuestProcessMap.find(uHostPID);
    1982                     if (it == mGuestProcessMap.end())
    1983                     {
    1984                         /* Host PID not used (anymore), we're done here ... */
    1985                         vrc = VINF_SUCCESS;
    1986                         break;
    1987                     }
    1988 
    1989                     if (++uTries == UINT32_MAX)
    1990                         break; /* Don't try too hard. */
    1991                 }
    1992 
    1993                 if (RT_SUCCESS(vrc))
    1994                     vrc = processSetStatus(uHostPID, 0 /* No guest PID yet */,
    1995                                            ExecuteProcessStatus_Undefined /* Process not started yet */,
    1996                                            0 /* uExitCode */, 0 /* uFlags */);
    1997 
    1998                 if (RT_SUCCESS(vrc))
    1999                     vrc = callbackAssignHostPID(uContextID, uHostPID);
    2000             }
    2001             else
    2002                 rc = setErrorHGCM(vrc);
    2003 
    2004             for (unsigned i = 0; i < uNumArgs; i++)
    2005                 RTMemFree(papszArgv[i]);
    2006             RTMemFree(papszArgv);
    2007 
    2008             if (RT_FAILURE(vrc))
    2009                 rc = VBOX_E_IPRT_ERROR;
    2010         }
    2011 
    2012         if (SUCCEEDED(rc))
    2013         {
    2014             /* Return host PID. */
    2015             *aPID = uHostPID;
    2016 
    2017             /* Return the progress to the caller. */
    2018             pProgress.queryInterfaceTo(aProgress);
    2019         }
    2020         else
    2021         {
    2022             if (!pRC) /* Skip logging internal calls. */
    2023                 LogRel(("Executing guest process \"%s\" as user \"%s\" failed with %Rrc\n",
    2024                         Utf8Command.c_str(), Utf8UserName.c_str(), vrc));
    2025         }
    2026 
    2027         if (pRC)
    2028             *pRC = vrc;
    2029     }
    2030     catch (std::bad_alloc &)
    2031     {
    2032         rc = E_OUTOFMEMORY;
    2033         if (pRC)
    2034             *pRC = VERR_NO_MEMORY;
    2035     }
    2036     return rc;
    2037 }
    2038 #endif /* VBOX_WITH_GUEST_CONTROL */
    2039 
    2040 STDMETHODIMP Guest::SetProcessInput(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, ComSafeArrayIn(BYTE, aData), ULONG *aBytesWritten)
    2041 {
    2042 #ifndef VBOX_WITH_GUEST_CONTROL
    2043     ReturnComNotImplemented();
    2044 #else  /* VBOX_WITH_GUEST_CONTROL */
    2045     using namespace guestControl;
    2046 
    2047     CheckComArgExpr(aPID, aPID > 0);
    2048     CheckComArgOutPointerValid(aBytesWritten);
    2049 
    2050     /* Validate flags. */
    2051     if (aFlags)
    2052     {
    2053         if (!(aFlags & ProcessInputFlag_EndOfFile))
    2054             return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), aFlags);
    2055     }
    2056 
    2057     AutoCaller autoCaller(this);
    2058     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2059 
    2060     HRESULT rc = S_OK;
    2061 
    2062     try
    2063     {
    2064         VBOXGUESTCTRL_PROCESS process;
    2065         int vrc = processGetStatus(aPID, &process, false /* Don't remove */);
    2066         if (RT_SUCCESS(vrc))
    2067         {
    2068             /* PID exists; check if process is still running. */
    2069             if (process.mStatus != ExecuteProcessStatus_Started)
    2070                 rc = setError(VBOX_E_IPRT_ERROR,
    2071                               Guest::tr("Cannot inject input to a not running process (PID %u)"), aPID);
    2072         }
    2073         else
    2074             rc = setError(VBOX_E_IPRT_ERROR,
    2075                           Guest::tr("Cannot inject input to a non-existent process (PID %u)"), aPID);
    2076 
    2077         if (RT_SUCCESS(vrc))
    2078         {
    2079             uint32_t uContextID = 0;
    2080 
    2081             uint32_t uGuestPID = processGetGuestPID(aPID);
    2082             Assert(uGuestPID);
    2083 
    2084             /*
    2085              * Create progress object.
    2086              * This progress object, compared to the one in executeProgress() above,
    2087              * is only single-stage local and is used to determine whether the operation
    2088              * finished or got canceled.
    2089              */
    2090             ComObjPtr <Progress> pProgress;
    2091             rc = pProgress.createObject();
    2092             if (SUCCEEDED(rc))
    2093             {
    2094                 rc = pProgress->init(static_cast<IGuest*>(this),
    2095                                      Bstr(tr("Setting input for process")).raw(),
    2096                                      TRUE /* Cancelable */);
    2097             }
    2098             if (FAILED(rc)) throw rc;
    2099             ComAssert(!pProgress.isNull());
    2100 
    2101             /* Adjust timeout. */
    2102             if (aTimeoutMS == 0)
    2103                 aTimeoutMS = UINT32_MAX;
    2104 
    2105             VBOXGUESTCTRL_CALLBACK callback;
    2106             vrc = callbackInit(&callback, VBOXGUESTCTRLCALLBACKTYPE_EXEC_INPUT_STATUS, pProgress);
    2107             if (RT_SUCCESS(vrc))
    2108             {
    2109                 PCALLBACKDATAEXECINSTATUS pData = (PCALLBACKDATAEXECINSTATUS)callback.pvData;
    2110 
    2111                 /* Save PID + output flags for later use. */
    2112                 pData->u32PID   = uGuestPID;
    2113                 pData->u32Flags = aFlags;
    2114             }
    2115 
    2116             if (RT_SUCCESS(vrc))
    2117                 vrc = callbackAdd(&callback, &uContextID);
    2118 
    2119             if (RT_SUCCESS(vrc))
    2120             {
    2121                 com::SafeArray<BYTE> sfaData(ComSafeArrayInArg(aData));
    2122                 uint32_t cbSize = sfaData.size();
    2123 
    2124                 VBOXHGCMSVCPARM paParms[6];
    2125                 int i = 0;
    2126                 paParms[i++].setUInt32(uContextID);
    2127                 paParms[i++].setUInt32(uGuestPID);
    2128                 paParms[i++].setUInt32(aFlags);
    2129                 paParms[i++].setPointer(sfaData.raw(), cbSize);
    2130                 paParms[i++].setUInt32(cbSize);
    2131 
    2132                 {
    2133                     VMMDev *pVMMDev = NULL;
    2134                     {
    2135                         /* Make sure mParent is valid, so set the read lock while using.
    2136                          * Do not keep this lock while doing the actual call, because in the meanwhile
    2137                          * another thread could request a write lock which would be a bad idea ... */
    2138                         AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2139 
    2140                         /* Forward the information to the VMM device. */
    2141                         AssertPtr(mParent);
    2142                         pVMMDev = mParent->getVMMDev();
    2143                     }
    2144 
    2145                     if (pVMMDev)
    2146                     {
    2147                         LogFlowFunc(("hgcmHostCall numParms=%d\n", i));
    2148                         vrc = pVMMDev->hgcmHostCall("VBoxGuestControlSvc", HOST_EXEC_SET_INPUT,
    2149                                                    i, paParms);
    2150                         if (RT_FAILURE(vrc))
    2151                             rc = setErrorHGCM(vrc);
    2152                     }
    2153                 }
    2154             }
    2155 
    2156             if (RT_SUCCESS(vrc))
    2157             {
    2158                 LogFlowFunc(("Waiting for HGCM callback ...\n"));
    2159 
    2160                  /*
    2161                  * Wait for getting back the input response from the guest.
    2162                  */
    2163                 vrc = callbackWaitForCompletion(uContextID, -1 /* No staging required */, aTimeoutMS);
    2164                 if (RT_SUCCESS(vrc))
    2165                 {
    2166                     PCALLBACKDATAEXECINSTATUS pExecStatusIn;
    2167                     vrc = callbackGetUserData(uContextID, NULL /* We know the type. */,
    2168                                               (void**)&pExecStatusIn, NULL /* Don't need the size. */);
    2169                     if (RT_SUCCESS(vrc))
    2170                     {
    2171                         AssertPtr(pExecStatusIn);
    2172                         switch (pExecStatusIn->u32Status)
    2173                         {
    2174                             case INPUT_STS_WRITTEN:
    2175                                 *aBytesWritten = pExecStatusIn->cbProcessed;
    2176                                 break;
    2177 
    2178                             case INPUT_STS_ERROR:
    2179                                 rc = setError(VBOX_E_IPRT_ERROR,
    2180                                               tr("Client reported error %Rrc while processing input data"),
    2181                                               pExecStatusIn->u32Flags);
    2182                                 break;
    2183 
    2184                             case INPUT_STS_TERMINATED:
    2185                                 rc = setError(VBOX_E_IPRT_ERROR,
    2186                                               tr("Client terminated while processing input data"));
    2187                                 break;
    2188 
    2189                             case INPUT_STS_OVERFLOW:
    2190                                 rc = setError(VBOX_E_IPRT_ERROR,
    2191                                               tr("Client reported buffer overflow while processing input data"));
    2192                                 break;
    2193 
    2194                             default:
    2195                                 /*AssertReleaseMsgFailed(("Client reported unknown input error, status=%u, flags=%u\n",
    2196                                                         pExecStatusIn->u32Status, pExecStatusIn->u32Flags));*/
    2197                                 break;
    2198                         }
    2199 
    2200                         callbackFreeUserData(pExecStatusIn);
    2201                     }
    2202                     else
    2203                     {
    2204                         rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
    2205                                            tr("Unable to retrieve process input status data"));
    2206                     }
    2207                 }
    2208                 else
    2209                     rc = setErrorCompletion(vrc);
    2210             }
    2211 
    2212             {
    2213                 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    2214 
    2215                 /* The callback isn't needed anymore -- just was kept locally. */
    2216                 callbackRemove(uContextID);
    2217             }
    2218 
    2219             /* Cleanup. */
    2220             if (!pProgress.isNull())
    2221                 pProgress->uninit();
    2222             pProgress.setNull();
    2223         }
    2224     }
    2225     catch (std::bad_alloc &)
    2226     {
    2227         rc = E_OUTOFMEMORY;
    2228     }
    2229     return rc;
    2230 #endif
    2231 }
    2232 
    2233 STDMETHODIMP Guest::GetProcessOutput(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS, LONG64 aSize, ComSafeArrayOut(BYTE, aData))
    2234 {
    2235 #ifndef VBOX_WITH_GUEST_CONTROL
    2236     ReturnComNotImplemented();
    2237 #else  /* VBOX_WITH_GUEST_CONTROL */
    2238     using namespace guestControl;
    2239 
    2240     return getProcessOutputInternal(aPID, aFlags, aTimeoutMS,
    2241                                     aSize, ComSafeArrayOutArg(aData), NULL /* rc */);
    2242 #endif
    2243 }
    2244 
    2245 HRESULT Guest::getProcessOutputInternal(ULONG aPID, ULONG aFlags, ULONG aTimeoutMS,
    2246                                         LONG64 aSize, ComSafeArrayOut(BYTE, aData), int *pRC)
    2247 {
    2248 /** @todo r=bird: Eventually we should clean up all the timeout parameters
    2249  *        in the API and have the same way of specifying infinite waits!  */
    2250 #ifndef VBOX_WITH_GUEST_CONTROL
    2251     ReturnComNotImplemented();
    2252 #else  /* VBOX_WITH_GUEST_CONTROL */
    2253     using namespace guestControl;
    2254 
    2255     CheckComArgExpr(aPID, aPID > 0);
    2256     if (aSize < 0)
    2257         return setError(E_INVALIDARG, tr("The size argument (%lld) is negative"), aSize);
    2258     if (aSize == 0)
    2259         return setError(E_INVALIDARG, tr("The size (%lld) is zero"), aSize);
    2260     if (aFlags)
    2261     {
    2262         if (!(aFlags & ProcessOutputFlag_StdErr))
    2263         {
    2264             return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), aFlags);
    2265         }
    2266     }
    2267 
    2268     AutoCaller autoCaller(this);
    2269     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2270 
    2271     HRESULT rc = S_OK;
    2272 
    2273     try
    2274     {
    2275         VBOXGUESTCTRL_PROCESS proc;
    2276         int vrc = processGetStatus(aPID, &proc, false /* Don't remove */);
    2277         if (RT_FAILURE(vrc))
    2278         {
    2279             rc = setError(VBOX_E_IPRT_ERROR,
    2280                           Guest::tr("Guest process (PID %u) does not exist"), aPID);
    2281         }
    2282         else if (proc.mStatus != ExecuteProcessStatus_Started)
    2283         {
    2284             /* If the process is already or still in the process table but does not run yet
    2285              * (or anymore) don't remove it but report back an appropriate error. */
    2286             vrc = VERR_BROKEN_PIPE;
    2287             /* Not getting any output is fine, so don't report an API error (rc)
    2288              * and only signal something through internal error code (vrc). */
    2289         }
    2290 
    2291         if (RT_SUCCESS(vrc))
    2292         {
    2293             uint32_t uContextID = 0;
    2294 
    2295             /*
    2296              * Create progress object.
    2297              * This progress object, compared to the one in executeProgress() above,
    2298              * is only single-stage local and is used to determine whether the operation
    2299              * finished or got canceled.
    2300              */
    2301             ComObjPtr <Progress> pProgress;
    2302             rc = pProgress.createObject();
    2303             if (SUCCEEDED(rc))
    2304             {
    2305                 rc = pProgress->init(static_cast<IGuest*>(this),
    2306                                      Bstr(tr("Getting output for guest process")).raw(),
    2307                                      TRUE /* Cancelable */);
    2308             }
    2309             if (FAILED(rc)) throw rc;
    2310             ComAssert(!pProgress.isNull());
    2311 
    2312             /* Adjust timeout. */
    2313             if (aTimeoutMS == 0)
    2314                 aTimeoutMS = UINT32_MAX;
    2315 
    2316             /* Set handle ID. */
    2317             uint32_t uHandleID = OUTPUT_HANDLE_ID_STDOUT; /* Default */
    2318             if (aFlags & ProcessOutputFlag_StdErr)
    2319                 uHandleID = OUTPUT_HANDLE_ID_STDERR;
    2320 
    2321             uint32_t uGuestPID = processGetGuestPID(aPID);
    2322             Assert(uGuestPID);
    2323 
    2324             /** @todo Use a buffer for next iteration if returned data is too big
    2325              *        for current read.
    2326              *        aSize is bogus -- will be ignored atm! */
    2327             VBOXGUESTCTRL_CALLBACK callback;
    2328             vrc = callbackInit(&callback, VBOXGUESTCTRLCALLBACKTYPE_EXEC_OUTPUT, pProgress);
    2329             if (RT_SUCCESS(vrc))
    2330             {
    2331                 PCALLBACKDATAEXECOUT pData = (PCALLBACKDATAEXECOUT)callback.pvData;
    2332 
    2333                 /* Save PID + output flags for later use. */
    2334                 pData->u32PID   = uGuestPID;
    2335                 pData->u32Flags = aFlags;
    2336             }
    2337 
    2338             if (RT_SUCCESS(vrc))
    2339                 vrc = callbackAdd(&callback, &uContextID);
    2340 
    2341             if (RT_SUCCESS(vrc))
    2342             {
    2343                 VBOXHGCMSVCPARM paParms[5];
    2344                 int i = 0;
    2345                 paParms[i++].setUInt32(uContextID);
    2346                 paParms[i++].setUInt32(uGuestPID);
    2347                 paParms[i++].setUInt32(uHandleID);
    2348                 paParms[i++].setUInt32(0 /* Flags, none set yet */);
    2349 
    2350                 VMMDev *pVMMDev = NULL;
    2351                 {
    2352                     /* Make sure mParent is valid, so set the read lock while using.
    2353                      * Do not keep this lock while doing the actual call, because in the meanwhile
    2354                      * another thread could request a write lock which would be a bad idea ... */
    2355                     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2356 
    2357                     /* Forward the information to the VMM device. */
    2358                     AssertPtr(mParent);
    2359                     pVMMDev = mParent->getVMMDev();
    2360                 }
    2361 
    2362                 if (pVMMDev)
    2363                 {
    2364                     LogFlowFunc(("hgcmHostCall numParms=%d\n", i));
    2365                     vrc = pVMMDev->hgcmHostCall("VBoxGuestControlSvc", HOST_EXEC_GET_OUTPUT,
    2366                                                i, paParms);
    2367                 }
    2368             }
    2369 
    2370             if (RT_SUCCESS(vrc))
    2371             {
    2372                 LogFlowFunc(("Waiting for HGCM callback (timeout=%RI32ms) ...\n", aTimeoutMS));
    2373 
    2374                 /*
    2375                  * Wait for the HGCM low level callback until the process
    2376                  * has been started (or something went wrong). This is necessary to
    2377                  * get the PID.
    2378                  */
    2379 
    2380                 /*
    2381                  * Wait for the first output callback notification to arrive.
    2382                  */
    2383                 vrc = callbackWaitForCompletion(uContextID, -1 /* No staging required */, aTimeoutMS);
    2384                 if (RT_SUCCESS(vrc))
    2385                 {
    2386                     PCALLBACKDATAEXECOUT pExecOut = NULL;
    2387                     vrc = callbackGetUserData(uContextID, NULL /* We know the type. */,
    2388                                               (void**)&pExecOut, NULL /* Don't need the size. */);
    2389                     if (RT_SUCCESS(vrc))
    2390                     {
    2391                         com::SafeArray<BYTE> outputData((size_t)aSize);
    2392 
    2393                         if (pExecOut->cbData)
    2394                         {
    2395                             bool fResize;
    2396 
    2397                             /* Do we need to resize the array? */
    2398                             if (pExecOut->cbData > aSize)
    2399                             {
    2400                                 fResize = outputData.resize(pExecOut->cbData);
    2401                                 Assert(fResize);
    2402                             }
    2403 
    2404                             /* Fill output in supplied out buffer. */
    2405                             Assert(outputData.size() >= pExecOut->cbData);
    2406                             memcpy(outputData.raw(), pExecOut->pvData, pExecOut->cbData);
    2407                             fResize = outputData.resize(pExecOut->cbData); /* Shrink to fit actual buffer size. */
    2408                             Assert(fResize);
    2409                         }
    2410                         else
    2411                         {
    2412                             /* No data within specified timeout available. */
    2413                             bool fResize = outputData.resize(0);
    2414                             Assert(fResize);
    2415                         }
    2416 
    2417                         /* Detach output buffer to output argument. */
    2418                         outputData.detachTo(ComSafeArrayOutArg(aData));
    2419 
    2420                         callbackFreeUserData(pExecOut);
    2421                     }
    2422                     else
    2423                     {
    2424                         rc = setErrorNoLog(VBOX_E_IPRT_ERROR,
    2425                                            tr("Unable to retrieve process output data (%Rrc)"), vrc);
    2426                     }
    2427                 }
    2428                 else
    2429                     rc = setErrorCompletion(vrc);
    2430             }
    2431             else
    2432                 rc = setErrorHGCM(vrc);
    2433 
    2434             {
    2435                 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    2436 
    2437                 /* The callback isn't needed anymore -- just was kept locally. */
    2438                 callbackRemove(uContextID);
    2439             }
    2440 
    2441             /* Cleanup. */
    2442             if (!pProgress.isNull())
    2443                 pProgress->uninit();
    2444             pProgress.setNull();
    2445         }
    2446 
    2447         if (pRC)
    2448             *pRC = vrc;
    2449     }
    2450     catch (std::bad_alloc &)
    2451     {
    2452         rc = E_OUTOFMEMORY;
    2453         if (pRC)
    2454             *pRC = VERR_NO_MEMORY;
    2455     }
    2456     return rc;
    2457 #endif
    2458 }
    2459 
    2460 STDMETHODIMP Guest::GetProcessStatus(ULONG aPID, ULONG *aExitCode, ULONG *aFlags, ExecuteProcessStatus_T *aStatus)
    2461 {
    2462 #ifndef VBOX_WITH_GUEST_CONTROL
    2463     ReturnComNotImplemented();
    2464 #else  /* VBOX_WITH_GUEST_CONTROL */
    2465 
    2466     AutoCaller autoCaller(this);
    2467     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2468 
    2469     HRESULT rc = S_OK;
    2470 
    2471     try
    2472     {
    2473         VBOXGUESTCTRL_PROCESS process;
    2474         int vrc = processGetStatus(aPID, &process,
    2475                                    true /* Remove when terminated */);
    2476         if (RT_SUCCESS(vrc))
    2477         {
    2478             if (aExitCode)
    2479                 *aExitCode = process.mExitCode;
    2480             if (aFlags)
    2481                 *aFlags = process.mFlags;
    2482             if (aStatus)
    2483                 *aStatus = process.mStatus;
    2484         }
    2485         else
    2486             rc = setError(VBOX_E_IPRT_ERROR,
    2487                           tr("Process (PID %u) not found!"), aPID);
    2488     }
    2489     catch (std::bad_alloc &)
    2490     {
    2491         rc = E_OUTOFMEMORY;
    2492     }
    2493     return rc;
    2494 #endif
    2495 }
    2496 
    2497 STDMETHODIMP Guest::CopyFromGuest(IN_BSTR aSource, IN_BSTR aDest,
    2498                                   IN_BSTR aUsername, IN_BSTR aPassword,
    2499                                   ULONG aFlags, IProgress **aProgress)
    2500 {
    2501 #ifndef VBOX_WITH_GUEST_CONTROL
    2502     ReturnComNotImplemented();
    2503 #else /* VBOX_WITH_GUEST_CONTROL */
    2504     CheckComArgStrNotEmptyOrNull(aSource);
    2505     CheckComArgStrNotEmptyOrNull(aDest);
    2506     CheckComArgOutPointerValid(aProgress);
    2507 
    2508     /* Do not allow anonymous executions (with system rights). */
    2509     if (RT_UNLIKELY((aUsername) == NULL || *(aUsername) == '\0'))
    2510         return setError(E_INVALIDARG, tr("No user name specified"));
    2511 
    2512     AutoCaller autoCaller(this);
    2513     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2514 
    2515     /* Validate flags. */
    2516     if (aFlags != CopyFileFlag_None)
    2517     {
    2518         if (   !(aFlags & CopyFileFlag_Recursive)
    2519             && !(aFlags & CopyFileFlag_Update)
    2520             && !(aFlags & CopyFileFlag_FollowLinks))
    2521         {
    2522             return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), aFlags);
    2523         }
    2524     }
    2525 
    2526     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2527 
    2528     HRESULT rc = S_OK;
    2529 
    2530     ComObjPtr<Progress> progress;
    2531     try
    2532     {
    2533         /* Create the progress object. */
    2534         progress.createObject();
    2535 
    2536         rc = progress->init(static_cast<IGuest*>(this),
    2537                             Bstr(tr("Copying file from guest to host")).raw(),
    2538                             TRUE /* aCancelable */);
    2539         if (FAILED(rc)) throw rc;
    2540 
    2541         /* Initialize our worker task. */
    2542         GuestTask *pTask = new GuestTask(GuestTask::TaskType_CopyFileFromGuest, this, progress);
    2543         AssertPtr(pTask);
    2544         std::auto_ptr<GuestTask> task(pTask);
    2545 
    2546         /* Assign data - aSource is the source file on the host,
    2547          * aDest reflects the full path on the guest. */
    2548         task->strSource   = (Utf8Str(aSource));
    2549         task->strDest     = (Utf8Str(aDest));
    2550         task->strUserName = (Utf8Str(aUsername));
    2551         task->strPassword = (Utf8Str(aPassword));
    2552         task->uFlags      = aFlags;
    2553 
    2554         rc = task->startThread();
    2555         if (FAILED(rc)) throw rc;
    2556 
    2557         /* Don't destruct on success. */
    2558         task.release();
    2559     }
    2560     catch (HRESULT aRC)
    2561     {
    2562         rc = aRC;
    2563     }
    2564 
    2565     if (SUCCEEDED(rc))
    2566     {
    2567         /* Return progress to the caller. */
    2568         progress.queryInterfaceTo(aProgress);
    2569     }
    2570     return rc;
    2571 #endif /* VBOX_WITH_GUEST_CONTROL */
    2572 }
    2573 
    2574 STDMETHODIMP Guest::CopyToGuest(IN_BSTR aSource, IN_BSTR aDest,
    2575                                 IN_BSTR aUsername, IN_BSTR aPassword,
    2576                                 ULONG aFlags, IProgress **aProgress)
    2577 {
    2578 #ifndef VBOX_WITH_GUEST_CONTROL
    2579     ReturnComNotImplemented();
    2580 #else /* VBOX_WITH_GUEST_CONTROL */
    2581     CheckComArgStrNotEmptyOrNull(aSource);
    2582     CheckComArgStrNotEmptyOrNull(aDest);
    2583     CheckComArgOutPointerValid(aProgress);
    2584 
    2585     /* Do not allow anonymous executions (with system rights). */
    2586     if (RT_UNLIKELY((aUsername) == NULL || *(aUsername) == '\0'))
    2587         return setError(E_INVALIDARG, tr("No user name specified"));
    2588 
    2589     AutoCaller autoCaller(this);
    2590     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    2591 
    2592     /* Validate flags. */
    2593     if (aFlags != CopyFileFlag_None)
    2594     {
    2595         if (   !(aFlags & CopyFileFlag_Recursive)
    2596             && !(aFlags & CopyFileFlag_Update)
    2597             && !(aFlags & CopyFileFlag_FollowLinks))
    2598         {
    2599             return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), aFlags);
    2600         }
    2601     }
    2602 
    2603     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    2604 
    2605     HRESULT rc = S_OK;
    2606 
    2607     ComObjPtr<Progress> pProgress;
    2608     try
    2609     {
    2610         /* Create the progress object. */
    2611         pProgress.createObject();
    2612 
    2613         rc = pProgress->init(static_cast<IGuest*>(this),
    2614                              Bstr(tr("Copying file from host to guest")).raw(),
    2615                              TRUE /* aCancelable */);
    2616         if (FAILED(rc)) throw rc;
    2617 
    2618         /* Initialize our worker task. */
    2619         GuestTask *pTask = new GuestTask(GuestTask::TaskType_CopyFileToGuest, this, pProgress);
    2620         AssertPtr(pTask);
    2621         std::auto_ptr<GuestTask> task(pTask);
    2622 
    2623         /* Assign data - aSource is the source file on the host,
    2624          * aDest reflects the full path on the guest. */
    2625         task->strSource   = (Utf8Str(aSource));
    2626         task->strDest     = (Utf8Str(aDest));
    2627         task->strUserName = (Utf8Str(aUsername));
    2628         task->strPassword = (Utf8Str(aPassword));
    2629         task->uFlags      = aFlags;
    2630 
    2631         rc = task->startThread();
    2632         if (FAILED(rc)) throw rc;
    2633 
    2634         /* Don't destruct on success. */
    2635         task.release();
    2636     }
    2637     catch (HRESULT aRC)
    2638     {
    2639         rc = aRC;
    2640     }
    2641 
    2642     if (SUCCEEDED(rc))
    2643     {
    2644         /* Return progress to the caller. */
    2645         pProgress.queryInterfaceTo(aProgress);
    2646     }
    2647     return rc;
    2648 #endif /* VBOX_WITH_GUEST_CONTROL */
    2649 }
    2650131
    2651132STDMETHODIMP Guest::UpdateGuestAdditions(IN_BSTR aSource, ComSafeArrayIn(AdditionsUpdateFlag_T, aFlags), IProgress **aProgress)
     
    2676157
    2677158    HRESULT hr = S_OK;
    2678 #if 1
     159
    2679160    /* Create an anonymous session. This is required to run the Guest Additions
    2680161     * update process with administrative rights. */
     
    2724205    }
    2725206    return hr;
    2726 #else /* Legacy, can be removed later. */
    2727     ComObjPtr<Progress> progress;
    2728     try
    2729     {
    2730         /* Create the progress object. */
    2731         progress.createObject();
    2732 
    2733         rc = progress->init(static_cast<IGuest*>(this),
    2734                             Bstr(tr("Updating Guest Additions")).raw(),
    2735                             TRUE /* aCancelable */);
    2736         if (FAILED(rc)) throw rc;
    2737 
    2738         /* Initialize our worker task. */
    2739         GuestTask *pTask = new GuestTask(GuestTask::TaskType_UpdateGuestAdditions, this, progress);
    2740         AssertPtr(pTask);
    2741         std::auto_ptr<GuestTask> task(pTask);
    2742 
    2743         /* Assign data - in that case aSource is the full path
    2744          * to the Guest Additions .ISO we want to mount. */
    2745         task->strSource = (Utf8Str(aSource));
    2746         task->uFlags = aFlags;
    2747 
    2748         rc = task->startThread();
    2749         if (FAILED(rc)) throw rc;
    2750 
    2751         /* Don't destruct on success. */
    2752         task.release();
    2753     }
    2754     catch (HRESULT aRC)
    2755     {
    2756         rc = aRC;
    2757     }
    2758 
    2759     if (SUCCEEDED(rc))
    2760     {
    2761         /* Return progress to the caller. */
    2762         progress.queryInterfaceTo(aProgress);
    2763     }
    2764     return rc;
    2765 #endif
    2766207#endif /* VBOX_WITH_GUEST_CONTROL */
    2767208}
  • trunk/src/VBox/Main/src-client/GuestImpl.cpp

    r42817 r42864  
    3232
    3333#include <VBox/VMMDev.h>
    34 #ifdef VBOX_WITH_GUEST_CONTROL
    35 # include <VBox/com/array.h>
    36 # include <VBox/com/ErrorInfo.h>
    37 #endif
    3834#include <iprt/cpp/utils.h>
    3935#include <iprt/timer.h>
     
    108104    AssertMsgRC(vrc, ("Failed to create guest statistics update timer(%Rra)\n", vrc));
    109105
    110 #ifdef VBOX_WITH_GUEST_CONTROL
    111     /* Init the context ID counter at 1000. */
    112     mNextContextID = 1000;
    113     /* Init the host PID counter. */
    114     mNextHostPID = 0;
    115 #endif
    116 
    117106#ifdef VBOX_WITH_DRAG_AND_DROP
    118107    m_pGuestDnD = new GuestDnD(this);
     
    134123    if (autoUninitSpan.uninitDone())
    135124        return;
    136 
    137 #ifdef VBOX_WITH_GUEST_CONTROL
    138     /* Scope write lock as much as possible. */
    139     {
    140         /*
    141          * Cleanup must be done *before* AutoUninitSpan to cancel all
    142          * all outstanding waits in API functions (which hold AutoCaller
    143          * ref counts).
    144          */
    145         AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    146 
    147         /* Notify left over callbacks that we are about to shutdown ... */
    148         CallbackMapIter it;
    149         for (it = mCallbackMap.begin(); it != mCallbackMap.end(); it++)
    150         {
    151             int rc2 = callbackNotifyEx(it->first, VERR_CANCELLED,
    152                                        Guest::tr("VM is shutting down, canceling uncompleted guest requests ..."));
    153             AssertRC(rc2);
    154         }
    155 
    156         /* Destroy left over callback data. */
    157         for (it = mCallbackMap.begin(); it != mCallbackMap.end(); it++)
    158             callbackDestroy(it->first);
    159 
    160         /* Clear process map (remove all callbacks). */
    161         mGuestProcessMap.clear();
    162     }
    163 #endif
    164125
    165126    /* Destroy stat update timer */
  • trunk/src/VBox/Main/src-client/xpcom/module.cpp

    r42852 r42864  
    6767NS_DECL_CLASSINFO(GuestDirectory)
    6868NS_IMPL_THREADSAFE_ISUPPORTS2_CI(GuestDirectory, IGuestDirectory, IDirectory)
    69 NS_DECL_CLASSINFO(GuestDirEntry)
    70 NS_IMPL_THREADSAFE_ISUPPORTS1_CI(GuestDirEntry, IGuestDirEntry)
    7169NS_DECL_CLASSINFO(GuestFile)
    7270NS_IMPL_THREADSAFE_ISUPPORTS2_CI(GuestFile, IGuestFile, IFile)
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette