summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Config.kmk5
-rw-r--r--include/VBox/GuestHost/GuestControl.h302
-rw-r--r--include/VBox/HostServices/GuestControlSvc.h380
-rw-r--r--include/VBox/VBoxGuestLib.h63
-rw-r--r--include/VBox/log.h3
-rw-r--r--src/VBox/Additions/common/VBoxGuest/lib/Makefile.kmk3
-rw-r--r--src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibGuestCtrl.cpp556
-rw-r--r--src/VBox/Additions/common/VBoxService/Makefile.kmk8
-rw-r--r--src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp4
-rw-r--r--src/VBox/Additions/common/VBoxService/VBoxServiceControl.h38
-rw-r--r--src/VBox/Additions/common/VBoxService/VBoxServiceControlSession.cpp618
-rw-r--r--src/VBox/HostServices/GuestControl/Makefile.kmk3
-rw-r--r--src/VBox/HostServices/GuestControl/VBoxGuestControlSvc.cpp39
-rw-r--r--src/VBox/HostServices/GuestControl/testcase/Makefile.kmk43
-rw-r--r--src/VBox/HostServices/GuestControl/testcase/tstGuestControlMockHGCM.cpp322
-rw-r--r--src/VBox/Main/Makefile.kmk6
-rw-r--r--src/VBox/Main/idl/VirtualBox.xidl154
-rw-r--r--src/VBox/Main/include/GuestCtrlImplPrivate.h105
-rw-r--r--src/VBox/Main/include/GuestDirectoryImpl.h32
-rw-r--r--src/VBox/Main/include/GuestProcessImpl.h18
-rw-r--r--src/VBox/Main/src-client/GuestCtrlPrivate.cpp250
-rw-r--r--src/VBox/Main/src-client/GuestDirectoryImpl.cpp630
-rw-r--r--src/VBox/Main/src-client/GuestFileImpl.cpp18
-rw-r--r--src/VBox/Main/src-client/GuestProcessImpl.cpp78
-rw-r--r--src/VBox/Main/src-client/GuestSessionImpl.cpp528
-rw-r--r--src/VBox/Main/src-client/GuestSessionImplTasks.cpp16
-rw-r--r--src/VBox/Main/testcase/Makefile.kmk2
-rw-r--r--src/VBox/Main/testcase/tstGuestCtrlParseBuffer.cpp12
28 files changed, 3786 insertions, 450 deletions
diff --git a/Config.kmk b/Config.kmk
index 3fa5632473b..63aebda3b53 100644
--- a/Config.kmk
+++ b/Config.kmk
@@ -897,6 +897,11 @@ VBOX_WITH_HOST_CHANNEL = 1
# Enable the guest control service.
if1of ($(KBUILD_TARGET), darwin freebsd linux solaris win)
VBOX_WITH_GUEST_CONTROL = 1
+ # Enables support for handling certain commands via the built-in (busybox-like) toolbox in VBoxService. See @bugref{9783}
+ # This is for supporting Guest Additions < 7.1.
+ VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT = 1
+ # Enables treating the toolbox as built-in commands. Requires 7.1 Guest Additions. See @bugref{9783}
+ VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS =
endif
# Enable ballooning
VBOX_WITH_MEMBALLOON = 1
diff --git a/include/VBox/GuestHost/GuestControl.h b/include/VBox/GuestHost/GuestControl.h
index 6d36cc3daea..4ad8bf3507c 100644
--- a/include/VBox/GuestHost/GuestControl.h
+++ b/include/VBox/GuestHost/GuestControl.h
@@ -42,6 +42,7 @@
# pragma once
#endif
+#include <iprt/time.h>
#include <iprt/types.h>
/* Everything defined in this file lives in this namespace. */
@@ -141,6 +142,33 @@ enum eProcessStatus
#define PATHRENAME_FLAG_VALID_MASK UINT32_C(0x00000003)
/** @} */
+/** @name GSTCTL_CREATETEMP_F_XXX - Guest temporary directory/file creation flags.
+ * @{
+ */
+/** Does not specify anything. */
+#define GSTCTL_CREATETEMP_F_NONE UINT32_C(0)
+/** Creates a directory instead of a file. */
+#define GSTCTL_CREATETEMP_F_DIRECTORY RT_BIT(0)
+/** Creates a secure temporary file / directory.
+ * Might not be supported on all (guest) OSes.
+ *
+ * @sa IPRT's implementation of RTDirCreateTempSecure() / RTFileCreateTempSecumre(). */
+#define GSTCTL_CREATETEMP_F_SECURE RT_BIT(1)
+/** Mask of valid flags. */
+#define GSTCTL_CREATETEMP_F_VALID_MASK UINT32_C(0x00000003)
+/** @} */
+
+/** @name GSTCTL_CREATEDIRECTORY_F_XXX - Guest directory creation flags.
+ * @{
+ */
+/** Does not specify anything. */
+#define GSTCTL_CREATEDIRECTORY_F_NONE UINT32_C(0)
+/** Also creates parent directories if they don't exist yet. */
+#define GSTCTL_CREATEDIRECTORY_F_PARENTS RT_BIT(0)
+/** Mask of valid flags. */
+#define GSTCTL_CREATEDIRECTORY_F_VALID_MASK UINT32_C(0x00000001)
+/** @} */
+
/** @name GUEST_SHUTDOWN_FLAG_XXX - Guest shutdown flags.
* Must match Main's GuestShutdownFlag_ definitions.
* @{
@@ -228,7 +256,281 @@ enum eInputStatus
INPUT_STS_OVERFLOW = 30
};
+/**
+ * Guest file system object -- additional information in a GSTCTLFSOBJATTR object.
+ */
+enum GSTCTLFSOBJATTRADD
+{
+ /** No additional information is available / requested. */
+ GSTCTLFSOBJATTRADD_NOTHING = 1,
+ /** The additional unix attributes (RTFSOBJATTR::u::Unix) are available /
+ * requested. */
+ GSTCTLFSOBJATTRADD_UNIX,
+ /** The additional unix attributes (RTFSOBJATTR::u::UnixOwner) are
+ * available / requested. */
+ GSTCTLFSOBJATTRADD_UNIX_OWNER,
+ /** The additional unix attributes (RTFSOBJATTR::u::UnixGroup) are
+ * available / requested. */
+ GSTCTLFSOBJATTRADD_UNIX_GROUP,
+ /** The additional extended attribute size (RTFSOBJATTR::u::EASize) is available / requested. */
+ GSTCTLFSOBJATTRADD_EASIZE,
+ /** The last valid item (inclusive).
+ * The valid range is RTFSOBJATTRADD_NOTHING thru RTFSOBJATTRADD_LAST. */
+ GSTCTLFSOBJATTRADD_LAST = GSTCTLFSOBJATTRADD_EASIZE,
+
+ /** The usual 32-bit hack. */
+ GSTCTLFSOBJATTRADD_32BIT_SIZE_HACK = 0x7fffffff
+};
+
+/** The number of bytes reserved for the additional attribute union. */
+#define GSTCTLFSOBJATTRUNION_MAX_SIZE 128
+/**
+ * Additional Unix Attributes (GSTCTLFSOBJATTRADD_UNIX).
+ */
+typedef struct GSTCTLFSOBJATTRUNIX
+{
+ /** The user owning the filesystem object (st_uid).
+ * This field is NIL_RTUID if not supported. */
+ RTUID uid;
+
+ /** The group the filesystem object is assigned (st_gid).
+ * This field is NIL_RTGID if not supported. */
+ RTGID gid;
+
+ /** Number of hard links to this filesystem object (st_nlink).
+ * This field is 1 if the filesystem doesn't support hardlinking or
+ * the information isn't available.
+ */
+ uint32_t cHardlinks;
+
+ /** The device number of the device which this filesystem object resides on (st_dev).
+ * This field is 0 if this information is not available. */
+ RTDEV INodeIdDevice;
+
+ /** The unique identifier (within the filesystem) of this filesystem object (st_ino).
+ * Together with INodeIdDevice, this field can be used as a OS wide unique id
+ * when both their values are not 0.
+ * This field is 0 if the information is not available.
+ *
+ * @remarks The special '..' dir always shows up with 0 on NTFS/Windows. */
+ RTINODE INodeId;
+
+ /** User flags (st_flags).
+ * This field is 0 if this information is not available. */
+ uint32_t fFlags;
+
+ /** The current generation number (st_gen).
+ * This field is 0 if this information is not available. */
+ uint32_t GenerationId;
+
+ /** The device number of a character or block device type object (st_rdev).
+ * This field is 0 if the file isn't of a character or block device type and
+ * when the OS doesn't subscribe to the major+minor device idenfication scheme. */
+ RTDEV Device;
+} GSTCTLFSOBJATTRUNIX;
+
+/**
+ * Additional guest Unix attributes (GSTCTLFSOBJATTRADD_UNIX_OWNER).
+ */
+typedef struct GSTCTLFSOBJATTRUNIXOWNER
+{
+ /** The user owning the filesystem object (st_uid).
+ * This field is NIL_RTUID if not supported. */
+ RTUID uid;
+ /** The user name.
+ * Empty if not available or not supported, truncated if too long. */
+ char szName[GSTCTLFSOBJATTRUNION_MAX_SIZE - sizeof(RTUID)];
+} GSTCTLFSOBJATTRUNIXOWNER;
+
+/**
+ * Additional guest Unix attributes (GSTCTLFSOBJATTRADD_UNIX_GROUP).
+ */
+typedef struct GSTCTLFSOBJATTRUNIXGROUP
+{
+ /** The user owning the filesystem object (st_uid).
+ * This field is NIL_RTUID if not supported. */
+ RTGID gid;
+ /** The group name.
+ * Empty if not available or not supported, truncated if too long. */
+ char szName[GSTCTLFSOBJATTRUNION_MAX_SIZE - sizeof(RTGID)];
+} GSTCTLFSOBJATTRUNIXGROUP;
+
+/**
+ * Guest filesystem object attributes.
+ */
+#pragma pack(1)
+typedef struct GSTCTLFSOBJATTR
+{
+ /** Mode flags (st_mode). RTFS_UNIX_*, RTFS_TYPE_*, and RTFS_DOS_*. */
+ RTFMODE fMode;
+
+ /** The additional attributes available. */
+ GSTCTLFSOBJATTRADD enmAdditional;
+
+ /**
+ * Additional attributes.
+ *
+ * Unless explicitly specified to an API, the API can provide additional
+ * data as it is provided by the underlying OS.
+ */
+ union GSTCTLFSOBJATTRUNION
+ {
+ /** Additional Unix Attributes - GUEST_FSOBJATTRADD_UNIX. */
+ GSTCTLFSOBJATTRUNIX Unix;
+ /** Additional Unix Owner Attributes - GUEST_FSOBJATTRADD_UNIX_OWNER. */
+ GSTCTLFSOBJATTRUNIXOWNER UnixOwner;
+ /** Additional Unix Group Attributes - GUEST_FSOBJATTRADD_UNIX_GROUP. */
+ GSTCTLFSOBJATTRUNIXGROUP UnixGroup;
+
+ /**
+ * Extended attribute size is available when RTFS_DOS_HAVE_EA_SIZE is set.
+ */
+ struct GSTCTLFSOBJATTREASIZE
+ {
+ /** Size of EAs. */
+ RTFOFF cb;
+ } EASize;
+ /** Reserved space. */
+ uint8_t abReserveSpace[128];
+ } u;
+} GSTCTLFSOBJATTR;
+#pragma pack()
+/** Pointer to a guest filesystem object attributes structure. */
+typedef GSTCTLFSOBJATTR *PGSTCTLFSOBJATTR;
+/** Pointer to a const guest filesystem object attributes structure. */
+typedef const GSTCTLFSOBJATTR *PCGSTCTLFSOBJATTR;
+
+/** @name GSTCTL_QUERYINFO_F_XXX - Generic flags for querying guest file system information.
+ * @{ */
+/** No guest stat flags specified. */
+#define GSTCTL_QUERYINFO_F_NONE UINT32_C(0)
+/** Last component: Work on the link. */
+#define GSTCTL_QUERYINFO_F_ON_LINK RT_BIT_32(0)
+/** Last component: Follow if link. */
+#define GSTCTL_QUERYINFO_F_FOLLOW_LINK RT_BIT_32(1)
+/** Don't allow symbolic links as part of the path.
+ * @remarks this flag is currently not implemented and will be ignored. */
+#define GSTCTL_QUERYINFO_F_NO_SYMLINKS RT_BIT_32(2)
+/** GSTCTL_QUERYINFO_F_XXX flag valid mask. */
+#define GSTCTL_QUERYINFO_F_VALID_MASK UINT32_C(0x00000007)
+/** @} */
+
+/**
+ * Filter option for HOST_MSG_DIR_OPEN.
+ */
+typedef enum GSTCTLDIRFILTER
+{
+ /** The usual invalid 0 entry. */
+ GSTCTLDIRFILTER_INVALID = 0,
+ /** No filter should be applied (and none was specified). */
+ GSTCTLDIRFILTER_NONE,
+ /** The Windows NT filter.
+ * The following wildcard chars: *, ?, <, > and "
+ * The matching is done on the uppercased strings. */
+ GSTCTLDIRFILTER_WINNT,
+ /** The UNIX filter.
+ * The following wildcard chars: *, ?, [..]
+ * The matching is done on exact case. */
+ GSTCTLDIRFILTER_UNIX,
+ /** The UNIX filter, uppercased matching.
+ * Same as GSTCTLDIRFILTER_UNIX except that the strings are uppercased before comparing. */
+ GSTCTLDIRFILTER_UNIX_UPCASED,
+
+ /** The usual full 32-bit value. */
+ GSTCTLDIRFILTER_32BIT_HACK = 0x7fffffff
+} GSTCTLDIRFILTER;
+
+/** @name GSTCTLDIR_F_XXX - Directory flags for HOST_MSG_DIR_OPEN.
+ * @{ */
+/** Don't allow symbolic links as part of the path.
+ * @remarks this flag is currently not implemented and will be ignored. */
+#define GSTCTLDIR_F_NO_SYMLINKS RT_BIT_32(0)
+/** Deny relative opening of anything above this directory. */
+#define GSTCTLDIR_F_DENY_ASCENT RT_BIT_32(1)
+/** Don't follow symbolic links in the final component. */
+#define GSTCTLDIR_F_NO_FOLLOW RT_BIT_32(2)
+/** Long path hack: Don't apply RTPathAbs to the path. */
+#define GSTCTLDIR_F_NO_ABS_PATH RT_BIT_32(3)
+/** Valid flag mask. */
+#define GSTCTLDIR_F_VALID_MASK UINT32_C(0x0000000f)
+
+/**
+ * Guest filesystem object information structure.
+ *
+ * This is returned by
+ * - GUEST_FS_NOTIFYTYPE_QUERY_INFO
+ * - GUEST_DIR_NOTIFYTYPE_READ
+ */
+#pragma pack(1)
+typedef struct GSTCTLFSOBJINFO
+{
+ /** Logical size (st_size).
+ * For normal files this is the size of the file.
+ * For symbolic links, this is the length of the path name contained
+ * in the symbolic link.
+ * For other objects this fields needs to be specified.
+ */
+ RTFOFF cbObject;
+
+ /** Disk allocation size (st_blocks * DEV_BSIZE). */
+ RTFOFF cbAllocated;
+
+ /** Time of last access (st_atime). */
+ RTTIMESPEC AccessTime;
+
+ /** Time of last data modification (st_mtime). */
+ RTTIMESPEC ModificationTime;
+
+ /** Time of last status change (st_ctime).
+ * If not available this is set to ModificationTime.
+ */
+ RTTIMESPEC ChangeTime;
+
+ /** Time of file birth (st_birthtime).
+ * If not available this is set to ChangeTime.
+ */
+ RTTIMESPEC BirthTime;
+
+ /** Attributes. */
+ GSTCTLFSOBJATTR Attr;
+
+} GSTCTLFSOBJINFO;
+#pragma pack()
+/** Pointer to a guest filesystem object information structure. */
+typedef GSTCTLFSOBJINFO *PGSTCTLFSOBJINFO;
+/** Pointer to a const guest filesystem object information structure. */
+typedef const GSTCTLFSOBJINFO *PCGSTCTLFSOBJINFO;
+
+/**
+ * Guest directory entry with extended information.
+ *
+ * This is inspired by IPRT + the PC interfaces.
+ */
+#pragma pack(1)
+typedef struct GSTCTLDIRENTRYEX
+{
+ /** Full information about the guest object. */
+ GSTCTLFSOBJINFO Info;
+ /** The length of the short field (number of RTUTF16 entries (not chars)).
+ * It is 16-bit for reasons of alignment. */
+ uint16_t cwcShortName;
+ /** The short name for 8.3 compatibility.
+ * Empty string if not available.
+ * Since the length is a bit tricky for a UTF-8 encoded name, and since this
+ * is practically speaking only a windows thing, it is encoded as UCS-2. */
+ RTUTF16 wszShortName[14];
+ /** The length of the filename. */
+ uint16_t cbName;
+ /** The filename. (no path)
+ * Using the pcbDirEntry parameter of RTDirReadEx makes this field variable in size. */
+ char szName[260];
+} GSTCTLDIRENTRYEX;
+#pragma pack()
+/** Pointer to a guest directory entry. */
+typedef GSTCTLDIRENTRYEX *PGSTCTLDIRENTRYEX;
+/** Pointer to a const guest directory entry. */
+typedef GSTCTLDIRENTRYEX const *PCGSTCTLDIRENTRYEX;
} /* namespace guestControl */
diff --git a/include/VBox/HostServices/GuestControlSvc.h b/include/VBox/HostServices/GuestControlSvc.h
index 5816566a727..248c794d9ae 100644
--- a/include/VBox/HostServices/GuestControlSvc.h
+++ b/include/VBox/HostServices/GuestControlSvc.h
@@ -40,10 +40,12 @@
# pragma once
#endif
+#include <iprt/assert.h>
+#include <VBox/hgcmsvc.h>
+
#include <VBox/VMMDevCoreTypes.h>
+#include <VBox/GuestHost/GuestControl.h>
#include <VBox/VBoxGuestCoreTypes.h>
-#include <VBox/hgcmsvc.h>
-#include <iprt/assert.h>
/* Everything defined in this file lives in this namespace. */
namespace guestControl {
@@ -199,11 +201,37 @@ enum eHostMsg
/**
* Gets the current file position of an opened guest file.
*/
- HOST_MSG_FILE_TELL,
+ HOST_MSG_FILE_TELL = 271,
/**
* Changes the file size.
*/
- HOST_MSG_FILE_SET_SIZE,
+ HOST_MSG_FILE_SET_SIZE = 272,
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+ /**
+ * Removes a file on the guest.
+ */
+ HOST_MSG_FILE_REMOVE = 273,
+ /**
+ * Opens (creates) a directory on the guest.
+ */
+ HOST_MSG_DIR_OPEN = 310,
+ /**
+ * Closes a directory on the guest.
+ */
+ HOST_MSG_DIR_CLOSE = 311,
+ /**
+ * Reads the next directory entry on the guest.
+ */
+ HOST_MSG_DIR_READ = 312,
+ /**
+ * Rewinds and restarts the directory reading on the guest.
+ */
+ HOST_MSG_DIR_REWIND = 313,
+ /**
+ * Creates a directory on the guest.
+ */
+ HOST_MSG_DIR_CREATE = 314,
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
/**
* Removes a directory on the guest.
*/
@@ -215,16 +243,25 @@ enum eHostMsg
/**
* Retrieves the user's documents directory.
*/
- HOST_MSG_PATH_USER_DOCUMENTS,
+ HOST_MSG_PATH_USER_DOCUMENTS = 331,
/**
* Retrieves the user's home directory.
*/
- HOST_MSG_PATH_USER_HOME,
+ HOST_MSG_PATH_USER_HOME = 332,
/**
* Issues a shutdown / reboot of the guest OS.
*/
- HOST_MSG_SHUTDOWN,
-
+ HOST_MSG_SHUTDOWN = 333,
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+ /**
+ * Retrieves information about a file system object.
+ */
+ HOST_MSG_FS_QUERY_INFO = 334,
+ /**
+ * Creates a temporary file or directory.
+ */
+ HOST_MSG_FS_CREATE_TEMP = 335,
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
/** Blow the type up to 32-bits. */
HOST_MSG_32BIT_HACK = 0x7fffffff
};
@@ -257,11 +294,23 @@ DECLINLINE(const char *) GstCtrlHostMsgtoStr(enum eHostMsg enmMsg)
RT_CASE_RET_STR(HOST_MSG_FILE_SEEK);
RT_CASE_RET_STR(HOST_MSG_FILE_TELL);
RT_CASE_RET_STR(HOST_MSG_FILE_SET_SIZE);
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+ RT_CASE_RET_STR(HOST_MSG_FILE_REMOVE);
+ RT_CASE_RET_STR(HOST_MSG_DIR_OPEN);
+ RT_CASE_RET_STR(HOST_MSG_DIR_CLOSE);
+ RT_CASE_RET_STR(HOST_MSG_DIR_READ);
+ RT_CASE_RET_STR(HOST_MSG_DIR_REWIND);
+ RT_CASE_RET_STR(HOST_MSG_DIR_CREATE);
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
RT_CASE_RET_STR(HOST_MSG_DIR_REMOVE);
RT_CASE_RET_STR(HOST_MSG_PATH_RENAME);
RT_CASE_RET_STR(HOST_MSG_PATH_USER_DOCUMENTS);
RT_CASE_RET_STR(HOST_MSG_PATH_USER_HOME);
RT_CASE_RET_STR(HOST_MSG_SHUTDOWN);
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+ RT_CASE_RET_STR(HOST_MSG_FS_QUERY_INFO);
+ RT_CASE_RET_STR(HOST_MSG_FS_CREATE_TEMP);
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
RT_CASE_RET_STR(HOST_MSG_32BIT_HACK);
}
return "Unknown";
@@ -578,7 +627,19 @@ enum eGuestMsg
* Guest notifies the host about some file event.
* @todo proper docs.
*/
- GUEST_MSG_FILE_NOTIFY = 240
+ GUEST_MSG_FILE_NOTIFY = 240,
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+ /**
+ * Guest notifies the host about some file system event.
+ *
+ * @retval VINF_SUCCESS on success.
+ * @retval VERR_INVALID_CLIENT_ID
+ * @retval VERR_WRONG_PARAMETER_COUNT
+ * @retval VERR_WRONG_PARAMETER_TYPE
+ * @since 7.1
+ */
+ GUEST_MSG_FS_NOTIFY = 241
+#endif
};
/**
@@ -617,11 +678,13 @@ DECLINLINE(const char *) GstCtrlGuestMsgToStr(enum eGuestMsg enmMsg)
RT_CASE_RET_STR(GUEST_MSG_EXEC_IO_NOTIFY);
RT_CASE_RET_STR(GUEST_MSG_DIR_NOTIFY);
RT_CASE_RET_STR(GUEST_MSG_FILE_NOTIFY);
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+ RT_CASE_RET_STR(GUEST_MSG_FS_NOTIFY);
+#endif
}
return "Unknown";
}
-
/**
* Guest session notification types.
* @sa HGCMMsgSessionNotify.
@@ -649,7 +712,7 @@ enum GUEST_SESSION_NOTIFYTYPE
/**
* Guest directory notification types.
- * @sa HGCMMsgDirNotify.
+ * @sa HGCMMsgReplyDirNotify.
*/
enum GUEST_DIR_NOTIFYTYPE
{
@@ -660,6 +723,12 @@ enum GUEST_DIR_NOTIFYTYPE
GUEST_DIR_NOTIFYTYPE_OPEN = 10,
/** Guest directory closed. */
GUEST_DIR_NOTIFYTYPE_CLOSE = 20,
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+ /** Guest directory read. */
+ GUEST_DIR_NOTIFYTYPE_READ = 21,
+ /** Guest directory was rewind. */
+ GUEST_DIR_NOTIFYTYPE_REWIND = 22,
+#endif
/** Information about an open guest directory. */
GUEST_DIR_NOTIFYTYPE_INFO = 40,
/** Guest directory created. */
@@ -688,6 +757,21 @@ enum GUEST_FILE_NOTIFYTYPE
};
/**
+ * Guest file system notification types.
+ */
+enum GUEST_FS_NOTIFYTYPE
+{
+ /** Unknown fs notification type; do not use. */
+ GUEST_FS_NOTIFYTYPE_UNKNOWN = 0,
+ /** File system query information notification from the guest.
+ * @since 7.1 */
+ GUEST_FS_NOTIFYTYPE_QUERY_INFO = 2,
+ /** Temporary directory creation notification from the guest.
+ * @since 7.1 */
+ GUEST_FS_NOTIFYTYPE_CREATE_TEMP = 1,
+};
+
+/**
* Guest file seeking types. Has to match FileSeekType in Main.
*
* @note This is not compatible with RTFileSeek, which is an unncessary pain.
@@ -715,6 +799,12 @@ enum GUEST_FILE_SEEKTYPE
#define VBOX_GUESTCTRL_GF_0_PROCESS_DYNAMIC_SIZES RT_BIT_64(2)
/** Supports shutting down / rebooting the guest. */
#define VBOX_GUESTCTRL_GF_0_SHUTDOWN RT_BIT_64(3)
+/** VBoxService' toolbox commands (vbox_rm, vbox_stat, ++) are supported by
+ * dedicated built-in HGCM commands.
+ *
+ * The toolbox commands now are being marked as deprecated.
+ * @since 7.1 */
+# define VBOX_GUESTCTRL_GF_0_TOOLBOX_AS_CMDS RT_BIT_64(4)
/** Bit that must be set in the 2nd parameter, will be cleared if the host reponds
* correctly (old hosts might not). */
#define VBOX_GUESTCTRL_GF_1_MUST_BE_ONE RT_BIT_64(63)
@@ -803,6 +893,29 @@ typedef struct HGCMMsgCancelPendingWaits
VBGLIOCHGCMCALL hdr;
} HGCMMsgCancelPendingWaits;
+/**
+ * Generic reply header for reply-based messages.
+ *
+ * @note Be careful when changing this, as older Guest Additions might depend on this
+ * and other stuff can break, too. So better leave this alone.
+ */
+typedef struct HGCMReplyHdr
+{
+ VBGLIOCHGCMCALL hdr;
+ /** Context ID. */
+ HGCMFunctionParameter context;
+ /** Message type. */
+ HGCMFunctionParameter type;
+ /** IPRT result of overall operation. */
+ HGCMFunctionParameter rc;
+} HGCMReplyHdr;
+
+/** Number of HGCM parameters the HGCMReplyHdr has. */
+#define GSTCTL_HGCM_REPLY_HDR_PARMS 3
+
+/**
+ * Generic reply message from guest to the host.
+ */
typedef struct HGCMMsgReply
{
VBGLIOCHGCMCALL hdr;
@@ -812,10 +925,51 @@ typedef struct HGCMMsgReply
HGCMFunctionParameter type;
/** IPRT result of overall operation. */
HGCMFunctionParameter rc;
- /** Optional payload to this reply. */
+ /** Optional payload to this reply
+ * Uses the REPLY_PAYLOAD_XXX structs. */
HGCMFunctionParameter payload;
} HGCMMsgReply;
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+/**
+ * Creates a temporary directory / file on the guest.
+ */
+typedef struct HGCMMsgFsCreateTemp
+{
+ VBGLIOCHGCMCALL hdr;
+ /** Context ID. */
+ HGCMFunctionParameter context;
+ /** Template name to use for file/directory creation.
+ * If \a tmpdir is set, this path will be relative to \a tmpdir and must not be an absolute path. */
+ HGCMFunctionParameter template_name;
+ /** Temporary directory to use.
+ * If empty, the guest OS' temporary directory will be determined via IPRT on the guest side. */
+ HGCMFunctionParameter tmpdir;
+ /** Creation flags.
+ * See GSTCTL_CREATETEMP_F_XXX. */
+ HGCMFunctionParameter flags;
+ /** File mode to use for creation (ignored if GSTCTL_CREATETEMP_F_SECURE is defined).
+ * See GSTCTL_CREATETEMP_F_XXX. */
+ HGCMFunctionParameter mode;
+} HGCMMsgFsCreateTemp;
+
+/**
+ * Queries information for a file system object on the guest.
+ */
+typedef struct HGCMMsgFsQueryInfo
+{
+ VBGLIOCHGCMCALL hdr;
+ /** Context ID. */
+ HGCMFunctionParameter context;
+ /** Path to query information for. */
+ HGCMFunctionParameter path;
+ /** Additional file system attributes to lookup (GSTCTLFSOBJATTRADD). */
+ HGCMFunctionParameter add_attributes;
+ /** Flags (GSTCTL_QUERYINFO_F_XXX). */
+ HGCMFunctionParameter flags;
+} HGCMMsgFsQueryInfo;
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
+
/**
* Creates a guest session.
*/
@@ -863,6 +1017,84 @@ typedef struct HGCMMsgSessionNotify
HGCMFunctionParameter result;
} HGCMMsgSessionNotify;
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+/**
+ * Opens a guest directory.
+ */
+typedef struct HGCMMsgDirOpen
+{
+ VBGLIOCHGCMCALL hdr;
+ /** Context ID. */
+ HGCMFunctionParameter context;
+ /** Path of directory to open. */
+ HGCMFunctionParameter path;
+ /** Filter string to use (wildcard style). */
+ HGCMFunctionParameter filter;
+ /** Filter type to use when walking the directory (GSTCTLDIRFILTER). */
+ HGCMFunctionParameter filter_type;
+ /** Directory open flags (GSTCTLDIR_F_XXX). */
+ HGCMFunctionParameter flags;
+} HGCMMsgDirOpen;
+
+/**
+ * Closes a guest directory.
+ */
+typedef struct HGCMMsgDirClose
+{
+ VBGLIOCHGCMCALL hdr;
+ /** Context ID. */
+ HGCMFunctionParameter context;
+ /** Directory handle to close. */
+ HGCMFunctionParameter handle;
+} HGCMMsgDirClose;
+
+/**
+ * Reads the next entry of a guest directory.
+ */
+typedef struct HGCMMsgDirRead
+{
+ VBGLIOCHGCMCALL hdr;
+ /** Context ID. */
+ HGCMFunctionParameter context;
+ /** Handle of directory listing to read the next entry for. */
+ HGCMFunctionParameter handle;
+ /** Custom directory entry size (in bytes) to use. */
+ HGCMFunctionParameter entry_size;
+ /** Additional directory attributes to use (GSTCTLFSOBJATTRADD). */
+ HGCMFunctionParameter add_attributes;
+ /** Directory reading flags. */
+ HGCMFunctionParameter flags;
+} HGCMMsgDirRead;
+
+/**
+ * Rewinds the listing of a guest directory.
+ */
+typedef struct HGCMMsgDirRewind
+{
+ VBGLIOCHGCMCALL hdr;
+ /** Context ID. */
+ HGCMFunctionParameter context;
+ /** Handle of directory listing to rewind. */
+ HGCMFunctionParameter handle;
+} HGCMMsgDirRewind;
+
+/**
+ * Creates a directory on the guest.
+ */
+typedef struct HGCMMsgDirCreate
+{
+ VBGLIOCHGCMCALL hdr;
+ /** Context ID. */
+ HGCMFunctionParameter context;
+ /** Path of directory to create. */
+ HGCMFunctionParameter path;
+ /** Creation mode. */
+ HGCMFunctionParameter mode;
+ /** Creation flags (GSTCTL_CREATEDIRECTORY_F_XXX). */
+ HGCMFunctionParameter flags;
+} HGCMMsgDirCreate;
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
+
typedef struct HGCMMsgPathRename
{
VBGLIOCHGCMCALL hdr;
@@ -1213,6 +1445,20 @@ typedef struct HGCMMsgFileSetSize
HGCMFunctionParameter cb64NewSize;
} HGCMMsgFileSetSize;
+/**
+ * Removes (deletes) a guest file.
+ *
+ * @since 7.1
+ */
+typedef struct HGCMMsgFileRemove
+{
+ VBGLIOCHGCMCALL hdr;
+ /** UInt32: Context ID. */
+ HGCMFunctionParameter context;
+ /** File to open. */
+ HGCMFunctionParameter filename;
+} HGCMMsgFileRemove;
+
/******************************************************************************
* HGCM replies from the guest. These are handled in Main's low-level HGCM *
@@ -1277,37 +1523,92 @@ typedef struct HGCMReplyFileNotify
typedef struct HGCMReplyDirNotify
{
- VBGLIOCHGCMCALL hdr;
- /** Context ID. */
- HGCMFunctionParameter context;
- /** Notification type. */
- HGCMFunctionParameter type;
- /** IPRT result of overall operation. */
- HGCMFunctionParameter rc;
+ /** The generic reply header. */
+ HGCMReplyHdr reply_hdr;
+ /** Union based on \a reply_hdr.type. */
union
{
- struct
- {
- /** Directory information. */
- HGCMFunctionParameter objInfo;
- } info;
+ /**
+ * Parameters used for \a type GUEST_DIR_NOTIFYTYPE_OPEN.
+ *
+ * @since 7.1
+ */
struct
{
/** Guest directory handle. */
HGCMFunctionParameter handle;
} open;
+ /**
+ * Parameters used for \a type GUEST_DIR_NOTIFYTYPE_READ.
+ *
+ * @since 7.1
+ */
struct
{
- /** Current read directory entry. */
+ /** Current read directory entry (GSTCTLDIRENTRYEX). */
HGCMFunctionParameter entry;
- /** Extended entry object information. Optional. */
- HGCMFunctionParameter objInfo;
+ /** Resolved user ID as a string (uid). */
+ HGCMFunctionParameter user;
+ /** Resolved group IDs as a string.
+ *
+ * Multiple groups are delimited by "\r\n", whereas
+ * the first group always is the primary group. */
+ HGCMFunctionParameter groups;
+ /** @todo ACL; not implemented yet.
+ * Windows ACL, defined in SDDL. */
+ HGCMFunctionParameter acl;
} read;
} u;
} HGCMReplyDirNotify;
+/**
+ * Reply to a HOST_MSG_FS_QUERY_INFO or HOST_MSG_FS_CREATE_TEMP message.
+ *
+ * @since 7.1
+ */
+typedef struct HGCMReplyFsNotify
+{
+ /** The generic reply header. */
+ HGCMReplyHdr reply_hdr;
+ /** Union based on \a reply_hdr.type. */
+ union
+ {
+ /**
+ * Parameters used for \a type GUEST_FS_NOTIFYTYPE_QUERY_INFO.
+ *
+ * @since 7.1
+ */
+ struct
+ {
+ /** File system object information (GSTCTLFSOBJINFO). */
+ HGCMFunctionParameter obj_info;
+ /** Resolved user ID as a string (uid). */
+ HGCMFunctionParameter user;
+ /** Resolved group IDs as a string.
+ *
+ * Multiple groups are delimited by "\r\n", whereas
+ * the first group always is the primary group. */
+ HGCMFunctionParameter groups;
+ /** @todo ACL; not implemented yet.
+ * Windows ACL, defined in SDDL. */
+ HGCMFunctionParameter acl;
+ } queryinfo;
+ /**
+ * Parameters used for \a type GUEST_FS_NOTIFYTYPE_CREATE_TEMP.
+ *
+ * @since 7.1
+ */
+ struct
+ {
+ /** The create temporary file / directory when \a rc
+ * indicates success. */
+ HGCMFunctionParameter path;
+ } createtemp;
+ } u;
+} HGCMReplyFsNotify;
#pragma pack ()
+
/******************************************************************************
* Callback data structures. *
******************************************************************************/
@@ -1420,10 +1721,8 @@ typedef struct CALLBACKDATA_DIR_NOTIFY
{
struct
{
- /** Size (in bytes) of directory information. */
- uint32_t cbObjInfo;
/** Pointer to directory information. */
- void *pvObjInfo;
+ PGSTCTLFSOBJINFO pObjInfo;
} info;
struct
{
@@ -1434,13 +1733,9 @@ typedef struct CALLBACKDATA_DIR_NOTIFY
struct
{
/** Size (in bytes) of directory entry information. */
- uint32_t cbEntry;
+ uint32_t cbEntry;
/** Pointer to directory entry information. */
- void *pvEntry;
- /** Size (in bytes) of directory entry object information. */
- uint32_t cbObjInfo;
- /** Pointer to directory entry object information. */
- void *pvObjInfo;
+ GSTCTLDIRENTRYEX *pEntry;
} read;
} u;
} CALLBACKDATA_DIR_NOTIFY, *PCALLBACKDATA_DIR_NOTIFY;
@@ -1494,6 +1789,19 @@ typedef struct CALLBACKDATA_FILE_NOTIFY
} u;
} CALLBACKDATA_FILE_NOTIFY, *PCALLBACKDATA_FILE_NOTIFY;
+
+/*******************************************************************************
+* Payload structures for the generic reply message (HGCMMsgReply). *
+* *
+* The name suffix must match the host command name, e.g. *
+* Host command HOST_MSG_FOO_BAR -> REPLY_PAYLOAD_FOO_BAR *
+*******************************************************************************/
+
+typedef struct REPLY_PAYLOAD_FS_QUERY_INFO
+{
+ GSTCTLFSOBJINFO objInfo;
+
+} REPLY_PAYLOAD_FS_QUERY_INFO;
} /* namespace guestControl */
#endif /* !VBOX_INCLUDED_HostServices_GuestControlSvc_h */
diff --git a/include/VBox/VBoxGuestLib.h b/include/VBox/VBoxGuestLib.h
index 72799ced42a..8d52e9fc886 100644
--- a/include/VBox/VBoxGuestLib.h
+++ b/include/VBox/VBoxGuestLib.h
@@ -40,6 +40,10 @@
# include <VBox/GuestHost/DragAndDrop.h>
# include <VBox/GuestHost/DragAndDropDefs.h>
# endif
+# ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+# include <VBox/GuestHost/GuestControl.h>
+ using namespace guestControl;
+# endif
# ifdef VBOX_WITH_SHARED_CLIPBOARD
# include <VBox/GuestHost/SharedClipboard.h>
# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
@@ -1078,11 +1082,21 @@ VBGLR3DECL(int) VbglR3GuestCtrlSessionClose(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_
VBGLR3DECL(int) VbglR3GuestCtrlSessionNotify(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uType, int32_t iResult);
VBGLR3DECL(int) VbglR3GuestCtrlSessionGetOpen(PVBGLR3GUESTCTRLCMDCTX pCtx, PVBGLR3GUESTCTRLSESSIONSTARTUPINFO *ppStartupInfo);
VBGLR3DECL(int) VbglR3GuestCtrlSessionGetClose(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *pfFlags, uint32_t *pidSession);
+VBGLR3DECL(int) VbglR3GuestCtrlFileGetClose(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle);
+VBGLR3DECL(int) VbglR3GuestCtrlFileGetRead(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle, uint32_t *puToRead);
/* Guest path handling. */
VBGLR3DECL(int) VbglR3GuestCtrlPathGetRename(PVBGLR3GUESTCTRLCMDCTX pCtx, char *pszSource, uint32_t cbSource, char *pszDest,
uint32_t cbDest, uint32_t *pfFlags);
VBGLR3DECL(int) VbglR3GuestCtrlPathGetUserDocuments(PVBGLR3GUESTCTRLCMDCTX pCtx);
VBGLR3DECL(int) VbglR3GuestCtrlPathGetUserHome(PVBGLR3GUESTCTRLCMDCTX pCtx);
+# ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+/** @name Guest Control file system functions.
+ * @{
+ */
+VBGLR3DECL(int) VbglR3GuestCtrlFsGetQueryInfo(PVBGLR3GUESTCTRLCMDCTX pCtx, char *pszPath, uint32_t cbPath, GSTCTLFSOBJATTRADD *penmAddAttrib, uint32_t *pfFlags);
+VBGLR3DECL(int) VbglR3GuestCtrlFsGetCreateTemp(PVBGLR3GUESTCTRLCMDCTX pCtx, char *pszTemplate, uint32_t cbTemplate, char *pszPath, uint32_t cbPath, uint32_t *pfFlags, uint32_t *pfMode);
+/** @} */
+# endif
VBGLR3DECL(int) VbglR3GuestCtrlGetShutdown(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *pfAction);
/* Guest process execution. */
VBGLR3DECL(int) VbglR3GuestCtrlProcStartupInfoInit(PVBGLR3GUESTCTRLPROCSTARTUPINFO pStartupInfo);
@@ -1098,6 +1112,17 @@ VBGLR3DECL(int) VbglR3GuestCtrlProcGetOutput(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32
VBGLR3DECL(int) VbglR3GuestCtrlProcGetWaitFor(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puPID, uint32_t *puWaitFlags,
uint32_t *puTimeoutMS);
/* Guest native directory handling. */
+# ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+/** @name Guest Control directory functions.
+ * @{
+ */
+VBGLR3DECL(int) VbglR3GuestCtrlDirGetCreate(PVBGLR3GUESTCTRLCMDCTX pCtx, char *pszPath, uint32_t cbPath, uint32_t *pfMode, uint32_t *pfFlags);
+VBGLR3DECL(int) VbglR3GuestCtrlDirGetOpen(PVBGLR3GUESTCTRLCMDCTX pCtx, char *pszPath, uint32_t cbPath, uint32_t *pfFlags, GSTCTLDIRFILTER *penmFilter);
+VBGLR3DECL(int) VbglR3GuestCtrlDirGetClose(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle);
+VBGLR3DECL(int) VbglR3GuestCtrlDirGetRead(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle, uint32_t *pcbDirEntry, uint32_t *penmAddAttrib, uint32_t *pfFlags);
+VBGLR3DECL(int) VbglR3GuestCtrlDirGetRewind(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle);
+/** @} */
+# endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
VBGLR3DECL(int) VbglR3GuestCtrlDirGetRemove(PVBGLR3GUESTCTRLCMDCTX pCtx, char *pszPath, uint32_t cbPath, uint32_t *pfFlags);
/* Guest native file handling. */
VBGLR3DECL(int) VbglR3GuestCtrlFileGetOpen(PVBGLR3GUESTCTRLCMDCTX pCtx, char *pszFileName, uint32_t cbFileName, char *pszOpenMode,
@@ -1115,28 +1140,48 @@ VBGLR3DECL(int) VbglR3GuestCtrlFileGetSeek(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t
uint32_t *puSeekMethod, uint64_t *poffSeek);
VBGLR3DECL(int) VbglR3GuestCtrlFileGetTell(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle);
VBGLR3DECL(int) VbglR3GuestCtrlFileGetSetSize(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle, uint64_t *pcbNew);
+# ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+VBGLR3DECL(int) VbglR3GuestCtrlFileGetRemove(PVBGLR3GUESTCTRLCMDCTX pCtx, char *pszFileName, uint32_t cbFileName);
+# endif
/* Guest -> Host. */
+# ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+/** @name Guest Control directory callbacks.
+ * @{
+ */
+VBGLR3DECL(int) VbglR3GuestCtrlDirCbOpen(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, uint32_t uFileHandle);
+VBGLR3DECL(int) VbglR3GuestCtrlDirCbClose(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc);
+VBGLR3DECL(int) VbglR3GuestCtrlDirCbReadEx(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, PGSTCTLDIRENTRYEX pEntry, uint32_t cbSize, char *pszUser, char *pszGroups, void *pvACL, size_t cbACL);
+VBGLR3DECL(int) VbglR3GuestCtrlDirCbRead(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, PGSTCTLDIRENTRYEX pEntry, uint32_t cbSize);
+VBGLR3DECL(int) VbglR3GuestCtrlDirCbRewind(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc);
+/** @} */
+# endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
+
VBGLR3DECL(int) VbglR3GuestCtrlFileCbOpen(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, uint32_t uFileHandle);
VBGLR3DECL(int) VbglR3GuestCtrlFileCbClose(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc);
VBGLR3DECL(int) VbglR3GuestCtrlFileCbError(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc);
VBGLR3DECL(int) VbglR3GuestCtrlFileCbRead(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, void *pvData, uint32_t cbData);
-VBGLR3DECL(int) VbglR3GuestCtrlFileCbReadOffset(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc,
- void *pvData, uint32_t cbData, int64_t offNew);
+VBGLR3DECL(int) VbglR3GuestCtrlFileCbReadOffset(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, void *pvData, uint32_t cbData, int64_t offNew);
VBGLR3DECL(int) VbglR3GuestCtrlFileCbWrite(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, uint32_t cbWritten);
VBGLR3DECL(int) VbglR3GuestCtrlFileCbWriteOffset(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, uint32_t cbWritten, int64_t offNew);
VBGLR3DECL(int) VbglR3GuestCtrlFileCbSeek(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, uint64_t offCurrent);
VBGLR3DECL(int) VbglR3GuestCtrlFileCbTell(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, uint64_t offCurrent);
VBGLR3DECL(int) VbglR3GuestCtrlFileCbSetSize(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, uint64_t cbNew);
-VBGLR3DECL(int) VbglR3GuestCtrlProcCbStatus(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uPID, uint32_t uStatus, uint32_t fFlags,
- void *pvData, uint32_t cbData);
-VBGLR3DECL(int) VbglR3GuestCtrlProcCbOutput(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uPID, uint32_t uHandle, uint32_t fFlags,
- void *pvData, uint32_t cbData);
-VBGLR3DECL(int) VbglR3GuestCtrlProcCbStatusInput(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t u32PID, uint32_t uStatus,
- uint32_t fFlags, uint32_t cbWritten);
-/** @} */
+# ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+/** @name Guest Control file system callbacks.
+ * @{
+ */
+VBGLR3DECL(int) VbglR3GuestCtrlFsCbQueryInfoEx(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, PGSTCTLFSOBJINFO pObjInfo, char *pszUser, char *pszGroups, void *pvACL, uint32_t cbACL);
+VBGLR3DECL(int) VbglR3GuestCtrlFsCbQueryInfo(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, PGSTCTLFSOBJINFO pObjInfo);
+VBGLR3DECL(int) VbglR3GuestCtrlFsCbCreateTemp(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, const char *pszPath);
+/** @} */
+# endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
+
+VBGLR3DECL(int) VbglR3GuestCtrlProcCbStatus(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uPID, uint32_t uStatus, uint32_t fFlags, void *pvData, uint32_t cbData);
+VBGLR3DECL(int) VbglR3GuestCtrlProcCbOutput(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uPID, uint32_t uHandle, uint32_t fFlags, void *pvData, uint32_t cbData);
+VBGLR3DECL(int) VbglR3GuestCtrlProcCbStatusInput(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t u32PID, uint32_t uStatus, uint32_t fFlags, uint32_t cbWritten);
# endif /* VBOX_WITH_GUEST_CONTROL defined */
/** @name Auto-logon handling
diff --git a/include/VBox/log.h b/include/VBox/log.h
index c77f2809851..9648e18368d 100644
--- a/include/VBox/log.h
+++ b/include/VBox/log.h
@@ -490,6 +490,8 @@ typedef enum VBOXLOGGROUP
LOG_GROUP_MAIN_GUESTDEBUGCONTROL,
/** Main group, IGuestDirectory. */
LOG_GROUP_MAIN_GUESTDIRECTORY,
+ /** Main group, IGuestDirectoryEvent. */
+ LOG_GROUP_MAIN_GUESTDIRECTORYEVENT,
/** Main group, IGuestDnDSource. */
LOG_GROUP_MAIN_GUESTDNDSOURCE,
/** Main group, IGuestDnDTarget. */
@@ -1062,6 +1064,7 @@ typedef enum VBOXLOGGROUP
"MAIN_GUEST", \
"MAIN_GUESTDEBUGCONTROL", \
"MAIN_GUESTDIRECTORY", \
+ "MAIN_GUESTDIRECTORYEVENT", \
"MAIN_GUESTDNDSOURCE", \
"MAIN_GUESTDNDTARGET", \
"MAIN_GUESTERRORINFO", \
diff --git a/src/VBox/Additions/common/VBoxGuest/lib/Makefile.kmk b/src/VBox/Additions/common/VBoxGuest/lib/Makefile.kmk
index 3949e15d67c..288d3ff8930 100644
--- a/src/VBox/Additions/common/VBoxGuest/lib/Makefile.kmk
+++ b/src/VBox/Additions/common/VBoxGuest/lib/Makefile.kmk
@@ -120,7 +120,8 @@ VBoxGuestR3Lib_DEFS = \
$(if $(VBOX_WITH_SHARED_CLIPBOARD),VBOX_WITH_SHARED_CLIPBOARD,) \
$(if $(VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS),VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS,) \
$(if $(VBOX_WITH_SHARED_FOLDERS),VBOX_WITH_SHARED_FOLDERS,) \
- $(if $(VBOX_WITH_GUEST_CONTROL),VBOX_WITH_GUEST_CONTROL,)
+ $(if $(VBOX_WITH_GUEST_CONTROL),VBOX_WITH_GUEST_CONTROL,) \
+ $(if $(VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS),VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS,)
VBoxGuestR3Lib_SOURCES = \
VBoxGuestR3Lib.cpp \
VBoxGuestR3LibAdditions.cpp \
diff --git a/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibGuestCtrl.cpp b/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibGuestCtrl.cpp
index dacf4b098a2..a012ca52cfc 100644
--- a/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibGuestCtrl.cpp
+++ b/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibGuestCtrl.cpp
@@ -979,6 +979,163 @@ VBGLR3DECL(int) VbglR3GuestCtrlSessionGetClose(PVBGLR3GUESTCTRLCMDCTX pCtx, uint
}
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+/**
+ * Retrieves a HOST_MSG_DIR_OPEN message.
+ *
+ * @returns VBox status code.
+ * @param pCtx Guest control command context to use.
+ * @param pszPath Where to return the directory path to open.
+ * @param cbPath Size (in bytes) of \a pszPath.
+ * @param pfFlags Where to return the directory listing flags.
+ * @param enmFilter Where to return the directory filter type.
+ */
+VBGLR3DECL(int) VbglR3GuestCtrlDirGetOpen(PVBGLR3GUESTCTRLCMDCTX pCtx, char *pszPath, uint32_t cbPath, uint32_t *pfFlags,
+ GSTCTLDIRFILTER *penmFilter)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertReturn(pCtx->uNumParms == 4, VERR_INVALID_PARAMETER);
+
+ AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
+ AssertReturn(cbPath, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pfFlags, VERR_INVALID_POINTER);
+ AssertPtrReturn(penmFilter, VERR_INVALID_POINTER);
+
+ int rc;
+ do
+ {
+ HGCMMsgDirOpen Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, vbglR3GuestCtrlGetMsgFunctionNo(pCtx->uClientID), pCtx->uNumParms);
+ VbglHGCMParmUInt32Set(&Msg.context, HOST_MSG_DIR_OPEN);
+ VbglHGCMParmPtrSet(&Msg.path, pszPath, cbPath);
+ VbglHGCMParmUInt64Set(&Msg.flags, 0);
+ VbglHGCMParmUInt64Set(&Msg.filter, 0);
+
+ rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ Msg.context.GetUInt32(&pCtx->uContextID);
+ Msg.flags.GetUInt32(pfFlags);
+ Msg.filter.GetUInt32((uint32_t *)penmFilter);
+ }
+ } while (rc == VERR_INTERRUPTED && g_fVbglR3GuestCtrlHavePeekGetCancel);
+ return rc;
+}
+
+
+/**
+ * Retrieves a HOST_MSG_DIR_CLOSE message.
+ *
+ * @returns VBox status code.
+ * @param pCtx Guest control command context to use.
+ * @param puHandle Where to return the handle of the guest directory to close.
+ */
+VBGLR3DECL(int) VbglR3GuestCtrlDirGetClose(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertReturn(pCtx->uNumParms == 2, VERR_INVALID_PARAMETER);
+
+ AssertPtrReturn(puHandle, VERR_INVALID_POINTER);
+
+ int rc;
+ do
+ {
+ HGCMMsgDirClose Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, vbglR3GuestCtrlGetMsgFunctionNo(pCtx->uClientID), pCtx->uNumParms);
+ VbglHGCMParmUInt32Set(&Msg.context, HOST_MSG_DIR_CLOSE);
+ VbglHGCMParmUInt64Set(&Msg.handle, 0);
+
+ rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ Msg.context.GetUInt32(&pCtx->uContextID);
+ Msg.handle.GetUInt32(puHandle);
+ }
+ } while (rc == VERR_INTERRUPTED && g_fVbglR3GuestCtrlHavePeekGetCancel);
+ return rc;
+}
+
+
+/**
+ * Retrieves a HOST_MSG_DIR_READ message.
+ *
+ * @returns VBox status code.
+ * @param pCtx Guest control command context to use.
+ * @param puHandle Where to return the directory handle to rewind.
+ * @param pcbDirEntry Where to return the directory entry size.
+ * @param penmAddAttrib Where to return the additional attributes enumeration.
+ * @param pfFlags Where to return the directory reading flags..
+ */
+VBGLR3DECL(int) VbglR3GuestCtrlDirGetRead(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle, uint32_t *pcbDirEntry,
+ uint32_t *penmAddAttrib, uint32_t *pfFlags)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertReturn(pCtx->uNumParms == 4, VERR_INVALID_PARAMETER);
+
+ AssertPtrReturn(puHandle, VERR_INVALID_POINTER);
+ AssertPtrReturn(pcbDirEntry, VERR_INVALID_POINTER);
+ AssertPtrReturn(penmAddAttrib, VERR_INVALID_POINTER);
+ AssertPtrReturn(pfFlags, VERR_INVALID_POINTER);
+
+ int rc;
+ do
+ {
+ HGCMMsgDirRead Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, vbglR3GuestCtrlGetMsgFunctionNo(pCtx->uClientID), pCtx->uNumParms);
+ VbglHGCMParmUInt32Set(&Msg.context, HOST_MSG_DIR_READ);
+ VbglHGCMParmUInt64Set(&Msg.handle, 0);
+ VbglHGCMParmUInt32Set(&Msg.entry_size, 0);
+ VbglHGCMParmUInt32Set(&Msg.add_attributes, 0);
+ VbglHGCMParmUInt32Set(&Msg.flags, 0);
+
+ rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ Msg.context.GetUInt32(&pCtx->uContextID);
+ Msg.handle.GetUInt32(puHandle);
+ Msg.entry_size.GetUInt32(pcbDirEntry);
+ Msg.add_attributes.GetUInt32(penmAddAttrib);
+ Msg.flags.GetUInt32(pfFlags);
+ }
+ } while (rc == VERR_INTERRUPTED && g_fVbglR3GuestCtrlHavePeekGetCancel);
+ return rc;
+}
+
+
+/**
+ * Retrieves a HOST_MSG_DIR_REWIND message.
+ *
+ * @returns VBox status code.
+ * @param pCtx Guest control command context to use.
+ * @param puHandle Where to return the directory handle to rewind.
+ */
+VBGLR3DECL(int) VbglR3GuestCtrlDirGetRewind(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertReturn(pCtx->uNumParms == 2, VERR_INVALID_PARAMETER);
+
+ AssertPtrReturn(puHandle, VERR_INVALID_POINTER);
+
+ int rc;
+ do
+ {
+ HGCMMsgDirRewind Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, vbglR3GuestCtrlGetMsgFunctionNo(pCtx->uClientID), pCtx->uNumParms);
+ VbglHGCMParmUInt32Set(&Msg.context, HOST_MSG_DIR_REWIND);
+ VbglHGCMParmUInt64Set(&Msg.handle, 0);
+
+ rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ Msg.context.GetUInt32(&pCtx->uContextID);
+ Msg.handle.GetUInt32(puHandle);
+ }
+ } while (rc == VERR_INTERRUPTED && g_fVbglR3GuestCtrlHavePeekGetCancel);
+ return rc;
+}
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
+
+
/**
* Retrieves a HOST_PATH_RENAME message.
*/
@@ -1063,6 +1220,103 @@ VBGLR3DECL(int) VbglR3GuestCtrlPathGetUserHome(PVBGLR3GUESTCTRLCMDCTX pCtx)
return rc;
}
+
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+/**
+ * Retrieves a HOST_MSG_FS_QUERY_INFO message.
+ *
+ * @returns VBox status code.
+ * @param pCtx Guest control command context to use.
+ * @param pszPath Where to return the path of the file system object to query.
+ * @param cbPath Size (in bytes) of \a pszPath.
+ * @param penmAddAttrib Where to return the additional attributes enumeration.
+ * @param pfFlags Where to return the flags for .
+ */
+VBGLR3DECL(int) VbglR3GuestCtrlFsGetQueryInfo(PVBGLR3GUESTCTRLCMDCTX pCtx,
+ char *pszPath, uint32_t cbPath, GSTCTLFSOBJATTRADD *penmAddAttrib, uint32_t *pfFlags)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertReturn(pCtx->uNumParms == 4, VERR_INVALID_PARAMETER);
+
+ AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
+ AssertReturn(cbPath, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(penmAddAttrib, VERR_INVALID_POINTER);
+ AssertPtrReturn(pfFlags, VERR_INVALID_POINTER);
+
+ int rc;
+ do
+ {
+ HGCMMsgFsQueryInfo Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, vbglR3GuestCtrlGetMsgFunctionNo(pCtx->uClientID), pCtx->uNumParms);
+ VbglHGCMParmUInt32Set(&Msg.context, HOST_MSG_FS_QUERY_INFO);
+ VbglHGCMParmPtrSet(&Msg.path, pszPath, cbPath);
+ VbglHGCMParmUInt32Set(&Msg.add_attributes, 0);
+ VbglHGCMParmUInt32Set(&Msg.flags, 0);
+
+ rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ Msg.context.GetUInt32(&pCtx->uContextID);
+ Msg.add_attributes.GetUInt32((uint32_t *)penmAddAttrib);
+ Msg.flags.GetUInt32(pfFlags);
+ }
+
+ } while (rc == VERR_INTERRUPTED && g_fVbglR3GuestCtrlHavePeekGetCancel);
+ return rc;
+}
+
+
+/**
+ * Retrieves a HOST_MSG_FS_CREATE_TEMP message.
+ *
+ * @returns VBox status code.
+ * @param pCtx Guest control command context to use.
+ * @param pszTemplate Where to return the template name.
+ * @param cbTemplate Size (in bytes) of \a pszTemplate.
+ * @param pszPath Where to return the temporary directory path.
+ * @param cbTemplate Size (in bytes) of \a pszPath.
+ * @param pfFlags Where to return the creation flags.
+ * @param pfMode Where to return the creation mode.
+ */
+VBGLR3DECL(int) VbglR3GuestCtrlFsGetCreateTemp(PVBGLR3GUESTCTRLCMDCTX pCtx,
+ char *pszTemplate, uint32_t cbTemplate, char *pszPath, uint32_t cbPath,
+ uint32_t *pfFlags, uint32_t *pfMode)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertReturn(pCtx->uNumParms == 5, VERR_INVALID_PARAMETER);
+
+ AssertPtrReturn(pszTemplate, VERR_INVALID_POINTER);
+ AssertReturn(cbTemplate, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
+ AssertReturn(cbPath, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pfFlags, VERR_INVALID_POINTER);
+ AssertPtrReturn(pfMode, VERR_INVALID_POINTER);
+
+ int rc;
+ do
+ {
+ HGCMMsgFsCreateTemp Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, vbglR3GuestCtrlGetMsgFunctionNo(pCtx->uClientID), pCtx->uNumParms);
+ VbglHGCMParmUInt32Set(&Msg.context, HOST_MSG_FS_CREATE_TEMP);
+ VbglHGCMParmPtrSet(&Msg.template_name, pszTemplate, cbTemplate);
+ VbglHGCMParmPtrSet(&Msg.tmpdir, pszPath, cbPath);
+ VbglHGCMParmUInt32Set(&Msg.flags, 0);
+ VbglHGCMParmUInt32Set(&Msg.mode, 0);
+
+ rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ Msg.context.GetUInt32(&pCtx->uContextID);
+ Msg.flags.GetUInt32(pfFlags);
+ Msg.mode.GetUInt32(pfMode);
+ }
+
+ } while (rc == VERR_INTERRUPTED && g_fVbglR3GuestCtrlHavePeekGetCancel);
+ return rc;
+}
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
+
+
/**
* Retrieves a HOST_MSG_SHUTDOWN message.
*
@@ -1468,6 +1722,51 @@ VBGLR3DECL(int) VbglR3GuestCtrlProcGetInput(PVBGLR3GUESTCTRLCMDCTX pCtx,
}
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+/**
+ * Retrieves a HOST_MSG_DIR_CREATE message.
+ *
+ * @returns VBox status code.
+ * @param pCtx Guest control command context to use.
+ * @param pszPath Where to return the path.
+ * @param cbPath Size (in bytes) of \a pszPath.
+ * @param pfMode Where to return the creation mode.
+ * @param pfFlags Where to return the creation flags (GSTCTL_CREATEDIRECTORY_F_XXX).
+ */
+VBGLR3DECL(int) VbglR3GuestCtrlDirGetCreate(PVBGLR3GUESTCTRLCMDCTX pCtx, char *pszPath, uint32_t cbPath, uint32_t *pfMode, uint32_t *pfFlags)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertReturn(pCtx->uNumParms == 4, VERR_INVALID_PARAMETER);
+
+ AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
+ AssertReturn(cbPath, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pfFlags, VERR_INVALID_POINTER);
+ AssertPtrReturn(pfMode, VERR_INVALID_POINTER);
+
+ int rc;
+ do
+ {
+ HGCMMsgDirCreate Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, vbglR3GuestCtrlGetMsgFunctionNo(pCtx->uClientID), pCtx->uNumParms);
+ VbglHGCMParmUInt32Set(&Msg.context, HOST_MSG_DIR_CREATE);
+ VbglHGCMParmPtrSet(&Msg.path, pszPath, cbPath);
+ VbglHGCMParmUInt32Set(&Msg.mode, 0);
+ VbglHGCMParmUInt32Set(&Msg.flags, 0);
+
+ rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ Msg.context.GetUInt32(&pCtx->uContextID);
+ Msg.flags.GetUInt32(pfFlags);
+ Msg.mode.GetUInt32(pfMode);
+ }
+
+ } while (rc == VERR_INTERRUPTED && g_fVbglR3GuestCtrlHavePeekGetCancel);
+ return rc;
+}
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
+
+
/**
* Retrieves a HOST_DIR_REMOVE message.
*/
@@ -1827,6 +2126,34 @@ VBGLR3DECL(int) VbglR3GuestCtrlFileGetSetSize(PVBGLR3GUESTCTRLCMDCTX pCtx, uint3
}
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+VBGLR3DECL(int) VbglR3GuestCtrlFileGetRemove(PVBGLR3GUESTCTRLCMDCTX pCtx, char *pszFileName, uint32_t cbFileName)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+
+ AssertReturn(pCtx->uNumParms == 2, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pszFileName, VERR_INVALID_POINTER);
+ AssertReturn(cbFileName, VERR_INVALID_PARAMETER);
+
+ int rc;
+ do
+ {
+ HGCMMsgFileRemove Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->uClientID, vbglR3GuestCtrlGetMsgFunctionNo(pCtx->uClientID), pCtx->uNumParms);
+ VbglHGCMParmUInt32Set(&Msg.context, HOST_MSG_FILE_REMOVE);
+ VbglHGCMParmPtrSet(&Msg.filename, pszFileName, cbFileName);
+
+ rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
+ if (RT_SUCCESS(rc))
+ {
+ Msg.context.GetUInt32(&pCtx->uContextID);
+ }
+ } while (rc == VERR_INTERRUPTED && g_fVbglR3GuestCtrlHavePeekGetCancel);
+ return rc;
+}
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
+
+
/**
* Retrieves a HOST_EXEC_TERMINATE message.
*/
@@ -1890,6 +2217,147 @@ VBGLR3DECL(int) VbglR3GuestCtrlProcGetWaitFor(PVBGLR3GUESTCTRLCMDCTX pCtx,
}
+/*********************************************************************************************************************************
+ * Directory callbacks *
+ ********************************************************************************************************************************/
+
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+/**
+ * Replies to a HOST_MSG_DIR_OPEN message.
+ *
+ * @returns VBox status code.
+ * @param pCtx Guest control command context to use.
+ * @param uRc Guest rc of operation (note: IPRT-style signed int).
+ * @param uDirHandle Directory handle of opened directory.
+ */
+VBGLR3DECL(int) VbglR3GuestCtrlDirCbOpen(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, uint32_t uDirHandle)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+
+ HGCMReplyDirNotify Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.reply_hdr.hdr, pCtx->uClientID, GUEST_MSG_DIR_NOTIFY,
+ RT_SUCCESS((int)uRc) ? GSTCTL_HGCM_REPLY_HDR_PARMS + 1 : GSTCTL_HGCM_REPLY_HDR_PARMS);
+ VbglHGCMParmUInt32Set(&Msg.reply_hdr.context, pCtx->uContextID);
+ VbglHGCMParmUInt32Set(&Msg.reply_hdr.type, GUEST_DIR_NOTIFYTYPE_OPEN);
+ VbglHGCMParmUInt32Set(&Msg.reply_hdr.rc, uRc);
+
+ if (RT_SUCCESS((int)uRc))
+ VbglHGCMParmUInt32Set(&Msg.u.open.handle, uDirHandle);
+
+ return VbglR3HGCMCall(&Msg.reply_hdr.hdr, RT_UOFFSET_AFTER(HGCMReplyDirNotify, u.open));
+}
+
+
+/**
+ * Replies to a HOST_MSG_DIR_CLOSE message.
+ *
+ * @returns VBox status code.
+ * @param pCtx Guest control command context to use.
+ * @param uRc Guest rc of operation (note: IPRT-style signed int).
+ */
+VBGLR3DECL(int) VbglR3GuestCtrlDirCbClose(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+
+ HGCMReplyDirNotify Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.reply_hdr.hdr, pCtx->uClientID, GUEST_MSG_DIR_NOTIFY, GSTCTL_HGCM_REPLY_HDR_PARMS);
+ VbglHGCMParmUInt32Set(&Msg.reply_hdr.context, pCtx->uContextID);
+ VbglHGCMParmUInt32Set(&Msg.reply_hdr.type, GUEST_DIR_NOTIFYTYPE_CLOSE);
+ VbglHGCMParmUInt32Set(&Msg.reply_hdr.rc, uRc);
+
+ return VbglR3HGCMCall(&Msg.reply_hdr.hdr, RT_UOFFSET_AFTER(HGCMReplyDirNotify, u));
+}
+
+
+/**
+ * Replies to a HOST_MSG_DIR_READ message, extended version.
+ *
+ * @returns VBox status code.
+ * @param pCtx Guest control command context to use.
+ * @param uRc Guest rc of operation (note: IPRT-style signed int).
+ * @param pEntry Directory entry to send.
+ * @param cbSize Size (in bytes) of \a pDirEntry to send.
+ * This might be needed as the size can be bigger than GSTCTLDIRENTRYEX.
+ * See RTDirReadEx() for more information.
+ * @param pszUser Associated user ID (owner, uid) as a string.
+ * @param pszGroups Associated user groups as a string.
+ * Multiple groups are delimited by "\r\n", whereas the first group always is the primary group.
+ * @param pvACL ACL block to send.
+ * @param cbACL Size (in bytes) of ACL block to send.
+ */
+VBGLR3DECL(int) VbglR3GuestCtrlDirCbReadEx(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, PGSTCTLDIRENTRYEX pEntry, uint32_t cbSize,
+ char *pszUser, char *pszGroups, void *pvACL, size_t cbACL)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertReturn(RT_FAILURE((int)uRc) || pszUser, VERR_INVALID_POINTER);
+ AssertReturn(RT_FAILURE((int)uRc) || pszGroups, VERR_INVALID_POINTER);
+ AssertReturn(RT_FAILURE((int)uRc) || pvACL, VERR_INVALID_POINTER);
+ AssertReturn(RT_FAILURE((int)uRc) || cbACL, VERR_INVALID_PARAMETER);
+
+ HGCMReplyDirNotify Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.reply_hdr.hdr, pCtx->uClientID, GUEST_MSG_DIR_NOTIFY,
+ RT_SUCCESS((int)uRc) ? GSTCTL_HGCM_REPLY_HDR_PARMS + 4 : GSTCTL_HGCM_REPLY_HDR_PARMS);
+ VbglHGCMParmUInt32Set(&Msg.reply_hdr.context, pCtx->uContextID);
+ VbglHGCMParmUInt32Set(&Msg.reply_hdr.type, GUEST_DIR_NOTIFYTYPE_READ);
+ VbglHGCMParmUInt32Set(&Msg.reply_hdr.rc, uRc);
+
+ if (RT_SUCCESS((int)uRc))
+ {
+ VbglHGCMParmPtrSet(&Msg.u.read.entry, pEntry, cbSize);
+ VbglHGCMParmPtrSetString(&Msg.u.read.user, pszUser);
+ VbglHGCMParmPtrSetString(&Msg.u.read.groups, pszGroups);
+ VbglHGCMParmPtrSet (&Msg.u.read.acl, pvACL, cbACL);
+ }
+
+ return VbglR3HGCMCall(&Msg.reply_hdr.hdr, RT_UOFFSET_AFTER(HGCMReplyDirNotify, u.read));
+}
+
+
+/**
+ * Replies to a HOST_MSG_DIR_READ message.
+ *
+ * @returns VBox status code.
+ * @param pCtx Guest control command context to use.
+ * @param uRc Guest rc of operation (note: IPRT-style signed int).
+ * @param pEntry Directory entry to send.
+ * @param cbSize Size (in bytes) of \a pDirEntry to send.
+ * This might be needed as the size can be bigger than GSTCTLDIRENTRYEX.
+ * See RTDirReadEx() for more information.
+ */
+VBGLR3DECL(int) VbglR3GuestCtrlDirCbRead(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, PGSTCTLDIRENTRYEX pEntry, uint32_t cbSize)
+{
+ char szIgnored[1];
+ return VbglR3GuestCtrlDirCbReadEx(pCtx, uRc, pEntry, cbSize, szIgnored /* pszUser */, szIgnored /* pszGroups */,
+ szIgnored /* pvACL */, sizeof(szIgnored) /* cbACL */);
+}
+
+
+/**
+ * Replies to a HOST_MSG_DIR_REWIND message.
+ *
+ * @returns VBox status code.
+ * @param pCtx Guest control command context to use.
+ * @param uRc Guest rc of operation (note: IPRT-style signed int).
+ */
+VBGLR3DECL(int) VbglR3GuestCtrlDirCbRewind(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+
+ HGCMReplyDirNotify Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.reply_hdr.hdr, pCtx->uClientID, GUEST_MSG_DIR_NOTIFY, GSTCTL_HGCM_REPLY_HDR_PARMS);
+ VbglHGCMParmUInt32Set(&Msg.reply_hdr.context, pCtx->uContextID);
+ VbglHGCMParmUInt32Set(&Msg.reply_hdr.type, GUEST_DIR_NOTIFYTYPE_REWIND);
+ VbglHGCMParmUInt32Set(&Msg.reply_hdr.rc, uRc);
+
+ return VbglR3HGCMCall(&Msg.reply_hdr.hdr, RT_UOFFSET_AFTER(HGCMReplyDirNotify, u));
+}
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
+
+
+/*********************************************************************************************************************************
+ * File callbacks *
+ ********************************************************************************************************************************/
+
/**
* Replies to a HOST_MSG_FILE_OPEN message.
*
@@ -2127,6 +2595,94 @@ VBGLR3DECL(int) VbglR3GuestCtrlFileCbSetSize(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32
}
+/*********************************************************************************************************************************
+ * File system callbacks *
+ ********************************************************************************************************************************/
+
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+/**
+ * Replies to a HOST_MSG_FS_QUERY_INFO message, extended version.
+ *
+ * @returns VBox status code.
+ * @param pCtx Guest control command context to use.
+ * @param uRc Guest rc of operation (note: IPRT-style signed int).
+ * @param pFsObjInfo Guest file system object information to send.
+ * @param pszUser Associated user ID (owner, uid) as a string.
+ * @param pszGroups Associated user groups as a string.
+ * Multiple groups are delimited by "\r\n", whereas the first group always is the primary group.
+ * @param pvACL ACL block to send.
+ * @param cbACL Size (in bytes) of ACL block to send.
+ */
+VBGLR3DECL(int) VbglR3GuestCtrlFsCbQueryInfoEx(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, PGSTCTLFSOBJINFO pFsObjInfo,
+ char *pszUser, char *pszGroups, void *pvACL, uint32_t cbACL)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(pFsObjInfo, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszUser, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszGroups, VERR_INVALID_POINTER);
+ AssertPtrReturn(pvACL, VERR_INVALID_POINTER);
+ AssertReturn(cbACL, VERR_INVALID_PARAMETER);
+
+ HGCMReplyFsNotify Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.reply_hdr.hdr, pCtx->uClientID, GUEST_MSG_FS_NOTIFY, 4);
+ VbglHGCMParmUInt32Set(&Msg.reply_hdr.context, pCtx->uContextID);
+ VbglHGCMParmUInt32Set(&Msg.reply_hdr.type, GUEST_FS_NOTIFYTYPE_QUERY_INFO);
+ VbglHGCMParmUInt32Set(&Msg.reply_hdr.rc, uRc);
+ VbglHGCMParmPtrSet (&Msg.u.queryinfo.obj_info, pFsObjInfo, sizeof(GSTCTLFSOBJINFO));
+ VbglHGCMParmPtrSetString(&Msg.u.queryinfo.user, pszUser);
+ VbglHGCMParmPtrSetString(&Msg.u.queryinfo.groups, pszGroups);
+ VbglHGCMParmPtrSet (&Msg.u.queryinfo.acl, pvACL, cbACL);
+
+ return VbglR3HGCMCall(&Msg.reply_hdr.hdr, RT_UOFFSET_AFTER(HGCMReplyDirNotify, u.read));
+}
+
+
+/**
+ * Replies to a HOST_MSG_FS_QUERY_INFO message.
+ *
+ * @returns VBox status code.
+ * @param pCtx Guest control command context to use.
+ * @param uRc Guest rc of operation (note: IPRT-style signed int).
+ * @param pFsObjInfo Guest file system object information to send.
+ */
+VBGLR3DECL(int) VbglR3GuestCtrlFsCbQueryInfo(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, PGSTCTLFSOBJINFO pFsObjInfo)
+{
+ char szIgnored[1];
+ return VbglR3GuestCtrlFsCbQueryInfoEx(pCtx, uRc, pFsObjInfo, szIgnored /* pszUser */, szIgnored /* pszGroups */,
+ szIgnored /* pvACL */, sizeof(szIgnored) /* cbACL */);
+}
+
+
+/**
+ * Replies to a HOST_MSG_FS_CREATE_TEMP message.
+ *
+ * @returns VBox status code.
+ * @param pCtx Guest control command context to use.
+ * @param uRc Guest rc of operation (note: IPRT-style signed int).
+ * @param pszPath Path of created temporary file / directory, if \a uRc marks a success.
+ * Specify an empty path on failure -- NULL is not allowed!
+ */
+VBGLR3DECL(int) VbglR3GuestCtrlFsCbCreateTemp(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, const char *pszPath)
+{
+ AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
+
+ HGCMReplyFsNotify Msg;
+ VBGL_HGCM_HDR_INIT(&Msg.reply_hdr.hdr, pCtx->uClientID, GUEST_MSG_FS_NOTIFY, 4);
+ VbglHGCMParmUInt32Set(&Msg.reply_hdr.context, pCtx->uContextID);
+ VbglHGCMParmUInt32Set(&Msg.reply_hdr.type, GUEST_FS_NOTIFYTYPE_CREATE_TEMP);
+ VbglHGCMParmUInt32Set(&Msg.reply_hdr.rc, uRc);
+ VbglHGCMParmPtrSetString(&Msg.u.createtemp.path, pszPath);
+
+ return VbglR3HGCMCall(&Msg.reply_hdr.hdr, RT_UOFFSET_AFTER(HGCMReplyFsNotify, u.createtemp));
+}
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
+
+
+/*********************************************************************************************************************************
+ * Process callbacks *
+ ********************************************************************************************************************************/
+
/**
* Callback for reporting a guest process status (along with some other stuff) to the host.
*
diff --git a/src/VBox/Additions/common/VBoxService/Makefile.kmk b/src/VBox/Additions/common/VBoxService/Makefile.kmk
index c21854aaa04..e84385c6b59 100644
--- a/src/VBox/Additions/common/VBoxService/Makefile.kmk
+++ b/src/VBox/Additions/common/VBoxService/Makefile.kmk
@@ -47,7 +47,9 @@ PROGRAMS += VBoxService
VBOX_WITH_VBOXSERVICE_TIMESYNC := 1
# Busybox-like toolbox, embedded into VBoxService.
-VBOX_WITH_VBOXSERVICE_TOOLBOX := 1
+ifndef VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT
+ VBOX_WITH_VBOXSERVICE_TOOLBOX := 1
+endif
# VM-management functions, like memory ballooning and statistics.
VBOX_WITH_VBOXSERVICE_MANAGEMENT := 1
@@ -100,7 +102,9 @@ VBoxService_DEFS = \
$(if $(VBOX_WITH_DBUS),VBOX_WITH_DBUS,) \
$(if $(VBOX_WITH_GUEST_CONTROL),VBOX_WITH_GUEST_CONTROL,) \
$(if $(VBOX_WITH_GUEST_PROPS),VBOX_WITH_GUEST_PROPS,) \
- $(if $(VBOX_WITH_HGCM),VBOX_WITH_HGCM,)
+ $(if $(VBOX_WITH_HGCM),VBOX_WITH_HGCM,) \
+ $(if $(VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT),VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT,) \
+ $(if $(VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS),VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS,)
ifdef VBOX_WITH_AUTOMATIC_DEFS_QUOTING
VBoxService_DEFS += VBOX_BUILD_TARGET="$(KBUILD_TARGET).$(KBUILD_TARGET_ARCH)"
else
diff --git a/src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp b/src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp
index cfe13cfc19e..0726d408872 100644
--- a/src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp
+++ b/src/VBox/Additions/common/VBoxService/VBoxServiceControl.cpp
@@ -257,8 +257,10 @@ static int vgsvcGstCtrlInvalidate(void)
const uint64_t fGuestFeatures = VBOX_GUESTCTRL_GF_0_SET_SIZE
| VBOX_GUESTCTRL_GF_0_PROCESS_ARGV0
| VBOX_GUESTCTRL_GF_0_PROCESS_DYNAMIC_SIZES
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+ | VBOX_GUESTCTRL_GF_0_TOOLBOX_AS_CMDS
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
| VBOX_GUESTCTRL_GF_0_SHUTDOWN;
-
rc = VbglR3GuestCtrlReportFeatures(g_idControlSvcClient, fGuestFeatures, &g_fControlHostFeatures0);
if (RT_SUCCESS(rc))
VGSvcVerbose(3, "Host features: %#RX64\n", g_fControlHostFeatures0);
diff --git a/src/VBox/Additions/common/VBoxService/VBoxServiceControl.h b/src/VBox/Additions/common/VBoxService/VBoxServiceControl.h
index 445a3923171..eb308afa839 100644
--- a/src/VBox/Additions/common/VBoxService/VBoxServiceControl.h
+++ b/src/VBox/Additions/common/VBoxService/VBoxServiceControl.h
@@ -57,13 +57,37 @@ typedef enum VBOXSERVICECTRLPIPEID
VBOXSERVICECTRLPIPEID_IPC_NOTIFY = 100
} VBOXSERVICECTRLPIPEID;
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+/**
+ * Structure for one (opened) guest directory.
+ */
+typedef struct VBOXSERVICECTRLDIR
+{
+ /** Pointer to list archor of following list node.
+ * @todo Would be nice to have a RTListGetAnchor(). */
+ PRTLISTANCHOR pAnchor;
+ /** Node to global guest control directory list. */
+ /** @todo Use a map later? */
+ RTLISTNODE Node;
+ /** The (absolute) directory path. */
+ char *pszPathAbs;
+ /** The directory handle on the guest. */
+ RTDIR hDir;
+ /** Directory handle to identify this directory. */
+ uint32_t uHandle;
+ /** Context ID. */
+ uint32_t uContextID;
+} VBOXSERVICECTRLDIR;
+/** Pointer to a guest directory. */
+typedef VBOXSERVICECTRLDIR *PVBOXSERVICECTRLDIR;
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
+
/**
* Structure for one (opened) guest file.
*/
typedef struct VBOXSERVICECTRLFILE
{
- /** Pointer to list archor of following
- * list node.
+ /** Pointer to list archor of following list node.
* @todo Would be nice to have a RTListGetAnchor(). */
PRTLISTANCHOR pAnchor;
/** Node to global guest control file list. */
@@ -80,7 +104,7 @@ typedef struct VBOXSERVICECTRLFILE
/** RTFILE_O_XXX flags. */
uint64_t fOpen;
} VBOXSERVICECTRLFILE;
-/** Pointer to thread data. */
+/** Pointer to a guest file. */
typedef VBOXSERVICECTRLFILE *PVBOXSERVICECTRLFILE;
/**
@@ -176,9 +200,15 @@ typedef struct VBOXSERVICECTRLSESSION
RTLISTANCHOR lstProcesses;
/** Number of guest processes in the process list. */
uint32_t cProcesses;
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+ /** List of guest control files (VBOXSERVICECTRLDIR). */
+ RTLISTANCHOR lstDirs;
+ /** Number of guest directories in \a lstDirs. */
+ uint32_t cDirs;
+#endif
/** List of guest control files (VBOXSERVICECTRLFILE). */
RTLISTANCHOR lstFiles;
- /** Number of guest files in the file list. */
+ /** Number of guest files in \a lstFiles. */
uint32_t cFiles;
/** The session's critical section. */
RTCRITSECT CritSect;
diff --git a/src/VBox/Additions/common/VBoxService/VBoxServiceControlSession.cpp b/src/VBox/Additions/common/VBoxService/VBoxServiceControlSession.cpp
index 67be297b9f8..106ec54855e 100644
--- a/src/VBox/Additions/common/VBoxService/VBoxServiceControlSession.cpp
+++ b/src/VBox/Additions/common/VBoxService/VBoxServiceControlSession.cpp
@@ -100,6 +100,77 @@ static bool vgsvcGstCtrlSessionGrowScratchBuf(void **ppvScratchBuf, uint32_t *pc
}
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+/**
+ * Free's a guest directory entry.
+ *
+ * @returns VBox status code.
+ * @param pDir Directory entry to free.
+ * The pointer will be invalid on success.
+ */
+static int vgsvcGstCtrlSessionDirFree(PVBOXSERVICECTRLDIR pDir)
+{
+ if (!pDir)
+ return VINF_SUCCESS;
+
+ int rc;
+ if (pDir->hDir != NIL_RTDIR)
+ {
+ rc = RTDirClose(pDir->hDir);
+ pDir->hDir = NIL_RTDIR;
+ }
+ else
+ rc = VINF_SUCCESS;
+
+ if (RT_SUCCESS(rc))
+ {
+ RTStrFree(pDir->pszPathAbs);
+ RTListNodeRemove(&pDir->Node);
+ RTMemFree(pDir);
+ }
+
+ return rc;
+}
+
+
+/**
+ * Acquires an internal guest directory.
+ *
+ * Must be released via vgsvcGstCtrlSessionDirRelease().
+ *
+ * @returns VBox status code.
+ * @param pSession Guest control session to acquire guest directory for.
+ * @param uHandle Handle of directory to acquire.
+ *
+ * @note No locking done yet.
+ */
+static PVBOXSERVICECTRLDIR vgsvcGstCtrlSessionDirAcquire(const PVBOXSERVICECTRLSESSION pSession, uint32_t uHandle)
+{
+ AssertPtrReturn(pSession, NULL);
+
+ /** @todo Use a map later! */
+ PVBOXSERVICECTRLDIR pDirCur;
+ RTListForEach(&pSession->lstDirs, pDirCur, VBOXSERVICECTRLDIR, Node)
+ {
+ if (pDirCur->uHandle == uHandle)
+ return pDirCur;
+ }
+
+ return NULL;
+}
+
+
+/**
+ * Releases a formerly acquired guest directory.
+ *
+ * @param pDir Directory to release.
+ */
+static void vgsvcGstCtrlSessionDirRelease(PVBOXSERVICECTRLDIR pDir)
+{
+ RT_NOREF(pDir);
+}
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
+
static int vgsvcGstCtrlSessionFileFree(PVBOXSERVICECTRLFILE pFile)
{
@@ -389,7 +460,7 @@ static int vgsvcGstCtrlSessionHandleFileOpen(PVBOXSERVICECTRLSESSION pSession, P
}
else
{
- VGSvcError("[File %s] empty filename!\n", szFile);
+ VGSvcError("Opening file failed: Empty filename!\n");
rc = VERR_INVALID_NAME;
}
@@ -901,6 +972,330 @@ static int vgsvcGstCtrlSessionHandleFileSetSize(const PVBOXSERVICECTRLSESSION pS
}
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+static int vgsvcGstCtrlSessionHandleFileRemove(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
+
+ /*
+ * Retrieve the request.
+ */
+ char szPath[RTPATH_MAX];
+ int rc = VbglR3GuestCtrlFileGetRemove(pHostCtx, szPath, sizeof(szPath));
+ if (RT_SUCCESS(rc))
+ {
+ VGSvcVerbose(4, "Deleting file szPath=%s\n", szPath);
+ rc = RTFileDelete(szPath);
+
+ /*
+ * Report result back to host.
+ */
+ int rc2 = VbglR3GuestCtrlMsgReply(pHostCtx, rc);
+ if (RT_FAILURE(rc2))
+ {
+ VGSvcError("Failed to report file deletion status, rc=%Rrc\n", rc2);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+ }
+ else
+ {
+ VGSvcError("Error fetching parameters for file deletion operation: %Rrc\n", rc);
+ VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
+ }
+ VGSvcVerbose(5, "Deleting file returned rc=%Rrc\n", rc);
+ return rc;
+}
+
+
+static int vgsvcGstCtrlSessionHandleDirOpen(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
+
+ char szPath[RTPATH_MAX];
+ uint32_t fFlags;
+ GSTCTLDIRFILTER enmFilter;
+ uint32_t uHandle = 0;
+ int rc = VbglR3GuestCtrlDirGetOpen(pHostCtx, szPath, sizeof(szPath), &fFlags, &enmFilter);
+ VGSvcVerbose(4, "[Dir %s]: fFlags=%#x, enmFilter=%#x, rc=%Rrc\n", szPath, enmFilter, rc);
+ if (RT_SUCCESS(rc))
+ {
+ PVBOXSERVICECTRLDIR pDir = (PVBOXSERVICECTRLDIR)RTMemAllocZ(sizeof(VBOXSERVICECTRLDIR));
+ AssertPtrReturn(pDir, VERR_NO_MEMORY);
+ pDir->hDir = NIL_RTDIR; /* Not zero or NULL! */
+ if (szPath[0])
+ {
+ pDir->pszPathAbs = RTStrDup(szPath);
+ if (!pDir->pszPathAbs)
+ rc = VERR_NO_MEMORY;
+
+ if (RT_SUCCESS(rc))
+ {
+ rc = RTDirOpenFiltered(&pDir->hDir, pDir->pszPathAbs, (RTDIRFILTER)enmFilter, fFlags);
+ if (RT_SUCCESS(rc))
+ {
+ uHandle = VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(pHostCtx->uContextID);
+ pDir->uHandle = uHandle;
+ RTListAppend(&pSession->lstDirs, &pDir->Node);
+ VGSvcVerbose(2, "[Dir %s] Opened (ID=%RU32)\n", pDir->pszPathAbs, pDir->uHandle);
+ }
+ }
+ }
+ else
+ {
+ VGSvcError("Opening directory failed: Empty path!\n");
+ rc = VERR_INVALID_NAME;
+ }
+
+ /* Clean up if we failed. */
+ if (RT_FAILURE(rc))
+ {
+ RTStrFree(pDir->pszPathAbs);
+ if (pDir->hDir != NIL_RTDIR)
+ RTDirClose(pDir->hDir);
+ RTMemFree(pDir);
+ }
+
+ /*
+ * Report result back to host.
+ */
+ int rc2 = VbglR3GuestCtrlDirCbOpen(pHostCtx, rc, uHandle);
+ if (RT_FAILURE(rc2))
+ {
+ VGSvcError("[Dir %s]: Failed to report directory open status, rc=%Rrc\n", szPath, rc2);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+ }
+ else
+ {
+ VGSvcError("Error fetching parameters for directory open operation: %Rrc\n", rc);
+ VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
+ }
+
+ VGSvcVerbose(4, "[Dir %s] Opening (flags=%#x, filter flags=%#x) returned rc=%Rrc\n",
+ szPath, fFlags, enmFilter, rc);
+ return rc;
+}
+
+
+static int vgsvcGstCtrlSessionHandleDirClose(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
+
+ /*
+ * Retrieve the message.
+ */
+ uint32_t uHandle = 0;
+ int rc = VbglR3GuestCtrlDirGetClose(pHostCtx, &uHandle /* Dir handle to close */);
+ if (RT_SUCCESS(rc))
+ {
+ PVBOXSERVICECTRLDIR pDir = vgsvcGstCtrlSessionDirAcquire(pSession, uHandle);
+ if (pDir)
+ {
+ VGSvcVerbose(2, "[Dir %s] Closing (handle=%RU32)\n", pDir ? pDir->pszPathAbs : "<Not found>", uHandle);
+ rc = vgsvcGstCtrlSessionDirFree(pDir);
+
+ vgsvcGstCtrlSessionDirRelease(pDir);
+ }
+ else
+ {
+ VGSvcError("Directory %u (%#x) not found!\n", uHandle, uHandle);
+ rc = VERR_NOT_FOUND;
+ }
+
+ /*
+ * Report result back to host.
+ */
+ int rc2 = VbglR3GuestCtrlDirCbClose(pHostCtx, rc);
+ if (RT_FAILURE(rc2))
+ {
+ VGSvcError("Failed to report directory close status, rc=%Rrc\n", rc2);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+ }
+ else
+ {
+ VGSvcError("Error fetching parameters for directory close operation: %Rrc\n", rc);
+ VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
+ }
+ return rc;
+}
+
+
+static int vgsvcGstCtrlSessionHandleDirRead(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
+
+ /*
+ * Retrieve the message.
+ */
+ uint32_t uHandle;
+ size_t cbDirEntry;
+ GSTCTLFSOBJATTRADD enmAttrAdd;
+ uint32_t fFlags;
+ GSTCTLDIRENTRYEX DirEntryEx;
+ int rc = VbglR3GuestCtrlDirGetRead(pHostCtx, &uHandle, (uint32_t *)&cbDirEntry, (uint32_t *)&enmAttrAdd, &fFlags);
+ if (RT_SUCCESS(rc))
+ {
+ PVBOXSERVICECTRLDIR pDir = vgsvcGstCtrlSessionDirAcquire(pSession, uHandle);
+ if (pDir)
+ {
+ VGSvcVerbose(2, "[Dir %s] Reading next entry (handle=%RU32)\n", pDir ? pDir->pszPathAbs : "<Not found>", uHandle);
+
+ /*
+ * For now we ASSUME that RTDIRENTRYEX == GSTCTLDIRENTRYEX, which implies that we simply can cast RTDIRENTRYEX
+ * to GSTCTLDIRENTRYEX. This might change in the future, however, so be extra cautious here.
+ *
+ * Ditto for RTFSOBJATTRADD == GSTCTLFSOBJATTRADD.
+ */
+ AssertCompileSize(DirEntryEx, sizeof(RTDIRENTRYEX));
+ AssertCompile (RT_OFFSETOF(GSTCTLDIRENTRYEX, Info) == RT_OFFSETOF(RTDIRENTRYEX, Info));
+ AssertCompile (RT_OFFSETOF(GSTCTLDIRENTRYEX, szName) == RT_OFFSETOF(RTDIRENTRYEX, szName));
+ AssertCompile (RT_OFFSETOF(GSTCTLFSOBJINFO, Attr) == RT_OFFSETOF(RTFSOBJINFO, Attr));
+
+ PRTDIRENTRYEX pDirEntryExRuntime = (PRTDIRENTRYEX)&DirEntryEx;
+
+ rc = RTDirReadEx(pDir->hDir, pDirEntryExRuntime, &cbDirEntry, (RTFSOBJATTRADD)enmAttrAdd, fFlags);
+
+ /* Paranoia. */
+ AssertStmt(cbDirEntry <= _256K, rc = VERR_BUFFER_OVERFLOW);
+
+ if (RT_SUCCESS(rc))
+ {
+ int rc2 = VbglR3GuestCtrlDirCbRead(pHostCtx, rc, &DirEntryEx, (uint32_t)cbDirEntry);
+ if (RT_FAILURE(rc2))
+ VGSvcError("Failed to report directory read status, rc=%Rrc\n", rc2);
+ }
+
+ vgsvcGstCtrlSessionDirRelease(pDir);
+ }
+ else
+ {
+ VGSvcError("Directory %u (%#x) not found!\n", uHandle, uHandle);
+ rc = VERR_NOT_FOUND;
+ }
+
+ if (RT_FAILURE(rc))
+ {
+ /* On failure we send a simply reply to save bandwidth. */
+ int rc2 = VbglR3GuestCtrlMsgReply(pHostCtx, rc);
+ if (RT_FAILURE(rc2))
+ {
+ VGSvcError("Failed to report directory read error %Rrc, rc=%Rrc\n", rc, rc2);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+ }
+ }
+ else
+ {
+ VGSvcError("Error fetching parameters for directory read operation: %Rrc\n", rc);
+ VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
+ }
+ return rc;
+}
+
+
+static int vgsvcGstCtrlSessionHandleDirRewind(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
+
+ /*
+ * Retrieve the message.
+ */
+ uint32_t uHandle = 0;
+ int rc = VbglR3GuestCtrlDirGetRewind(pHostCtx, &uHandle);
+ if (RT_SUCCESS(rc))
+ {
+ PVBOXSERVICECTRLDIR pDir = vgsvcGstCtrlSessionDirAcquire(pSession, uHandle);
+ if (pDir)
+ {
+ VGSvcVerbose(2, "[Dir %s] Rewinding (handle=%RU32)\n", pDir ? pDir->pszPathAbs : "<Not found>", uHandle);
+
+ rc = RTDirRewind(pDir->hDir);
+
+ vgsvcGstCtrlSessionDirRelease(pDir);
+ }
+ else
+ {
+ VGSvcError("Directory %u (%#x) not found!\n", uHandle, uHandle);
+ rc = VERR_NOT_FOUND;
+ }
+
+ /*
+ * Report result back to host.
+ */
+ int rc2 = VbglR3GuestCtrlDirCbRewind(pHostCtx, rc);
+ if (RT_FAILURE(rc2))
+ {
+ VGSvcError("Failed to report directory rewind status, rc=%Rrc\n", rc2);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+ }
+ else
+ {
+ VGSvcError("Error fetching parameters for directory rewind operation: %Rrc\n", rc);
+ VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
+ }
+ return rc;
+}
+
+
+static int vgsvcGstCtrlSessionHandleDirCreate(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
+
+ /*
+ * Retrieve the request.
+ */
+ char szPath[RTPATH_MAX];
+ RTFMODE fMode;
+ uint32_t fCreate;
+ int rc = VbglR3GuestCtrlDirGetCreate(pHostCtx, szPath, sizeof(szPath), &fMode, &fCreate);
+ if (RT_SUCCESS(rc))
+ {
+ if (!(fCreate & ~GSTCTL_CREATEDIRECTORY_F_VALID_MASK))
+ {
+ VGSvcVerbose(4, "Creating directory (szPath='%s', fMode=%#x, fCreate=%#x), rc=%Rrc\n", szPath, fMode, fCreate, rc);
+ rc = RTDirCreate(szPath, fMode, fCreate);
+ }
+ else
+ {
+ VGSvcError("Invalid directory creation flags: %#x\n", fCreate);
+ rc = VERR_NOT_SUPPORTED;
+ }
+
+ /*
+ * Report result back to host.
+ */
+ int rc2 = VbglR3GuestCtrlMsgReply(pHostCtx, rc);
+ if (RT_FAILURE(rc2))
+ {
+ VGSvcError("Failed to report directory creation status, rc=%Rrc\n", rc2);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+ }
+ else
+ {
+ VGSvcError("Error fetching parameters for directory creation operation: %Rrc\n", rc);
+ VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
+ }
+ VGSvcVerbose(5, "Creating directory returned rc=%Rrc\n", rc);
+ return rc;
+}
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
+
+
static int vgsvcGstCtrlSessionHandlePathRename(PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
{
AssertPtrReturn(pSession, VERR_INVALID_POINTER);
@@ -1367,6 +1762,158 @@ static int vgsvcGstCtrlSessionHandleProcWaitFor(const PVBOXSERVICECTRLSESSION pS
}
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+static int vgsvcGstCtrlSessionHandleFsQueryInfo(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
+
+ /*
+ * Retrieve the request.
+ */
+ char szPath[RTPATH_MAX];
+ GSTCTLFSOBJATTRADD enmAttrAdd;
+ uint32_t fFlags;
+ RTFSOBJINFO objInfoRuntime;
+
+ int rc = VbglR3GuestCtrlFsGetQueryInfo(pHostCtx, szPath, sizeof(szPath), &enmAttrAdd, &fFlags);
+ if (RT_SUCCESS(rc))
+ {
+ if (!(fFlags & ~GSTCTL_QUERYINFO_F_VALID_MASK))
+ {
+ uint32_t fFlagsRuntime = 0;
+ if (fFlags & GSTCTL_QUERYINFO_F_ON_LINK)
+ fFlagsRuntime |= RTPATH_F_ON_LINK;
+ if (fFlags & GSTCTL_QUERYINFO_F_FOLLOW_LINK)
+ fFlagsRuntime |= RTPATH_F_FOLLOW_LINK;
+ if (fFlags & GSTCTL_QUERYINFO_F_NO_SYMLINKS)
+ fFlagsRuntime |= RTPATH_F_NO_SYMLINKS;
+
+#define CASE_ATTR_ADD_VAL(a_Val) \
+ case GSTCTL##a_Val: enmAttrRuntime = RT##a_Val; break;
+
+ RTFSOBJATTRADD enmAttrRuntime;
+ switch (enmAttrAdd)
+ {
+ CASE_ATTR_ADD_VAL(FSOBJATTRADD_NOTHING);
+ CASE_ATTR_ADD_VAL(FSOBJATTRADD_UNIX);
+ CASE_ATTR_ADD_VAL(FSOBJATTRADD_UNIX_OWNER);
+ CASE_ATTR_ADD_VAL(FSOBJATTRADD_UNIX_GROUP);
+ CASE_ATTR_ADD_VAL(FSOBJATTRADD_EASIZE);
+ default:
+ enmAttrRuntime = RTFSOBJATTRADD_NOTHING;
+ break;
+ }
+
+#undef CASE_ATTR_ADD_VAL
+
+ /*
+ * For now we ASSUME that RTFSOBJINFO == GSTCTLFSOBJINFO, which implies that we simply can cast RTFSOBJINFO
+ * to GSTCTLFSOBJINFO. This might change in the future, however, so be extra cautious here.
+ *
+ * Ditto for RTFSOBJATTR == GSTCTLFSOBJATTR.
+ */
+ AssertCompileSize(objInfoRuntime, sizeof(GSTCTLFSOBJINFO));
+ AssertCompile (RT_OFFSETOF(GSTCTLFSOBJINFO, cbObject) == RT_OFFSETOF(GSTCTLFSOBJINFO, cbObject));
+ AssertCompile (RT_OFFSETOF(GSTCTLFSOBJINFO, Attr) == RT_OFFSETOF(GSTCTLFSOBJINFO, Attr));
+ AssertCompileSize(RTFSOBJATTR, sizeof(GSTCTLFSOBJATTR));
+
+ rc = RTPathQueryInfoEx(szPath, &objInfoRuntime, enmAttrRuntime, fFlagsRuntime);
+ }
+ else
+ {
+ VGSvcError("Invalid stat flags: %#x\n", fFlags);
+ rc = VERR_NOT_SUPPORTED;
+ }
+
+ PGSTCTLFSOBJINFO pObjInfo = (PGSTCTLFSOBJINFO)&objInfoRuntime;
+
+ /** @todo Implement lookups! */
+ char szNotImplemented[] = "<not-implemented>";
+ char *pszUser = szNotImplemented;
+ char *pszGroups = szNotImplemented;
+ int rc2 = VbglR3GuestCtrlFsCbQueryInfoEx(pHostCtx, rc, pObjInfo, pszUser, pszGroups,
+ szNotImplemented, sizeof(szNotImplemented));
+ if (RT_FAILURE(rc2))
+ {
+ VGSvcError("Failed to reply to fsqueryinfo request %Rrc, rc=%Rrc\n", rc, rc2);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+ }
+ else
+ {
+ VGSvcError("Error fetching parameters for fsqueryinfo operation: %Rrc\n", rc);
+ VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
+ }
+ return rc;
+}
+
+
+static int vgsvcGstCtrlSessionHandleFsCreateTemp(const PVBOXSERVICECTRLSESSION pSession, PVBGLR3GUESTCTRLCMDCTX pHostCtx)
+{
+ AssertPtrReturn(pSession, VERR_INVALID_POINTER);
+ AssertPtrReturn(pHostCtx, VERR_INVALID_POINTER);
+
+ /*
+ * Retrieve the request.
+ */
+ char szTemplate[RTPATH_MAX];
+ char szPath[RTPATH_MAX];
+ uint32_t fFlags = GSTCTL_CREATETEMP_F_NONE;
+ RTFMODE fMode = 0700;
+ int rc = VbglR3GuestCtrlFsGetCreateTemp(pHostCtx, szTemplate, sizeof(szTemplate), szPath, sizeof(szPath), &fFlags, &fMode);
+ if (RT_SUCCESS(rc))
+ {
+ if (!(fFlags & ~GSTCTL_CREATETEMP_F_VALID_MASK))
+ {
+ const char *pszWhat = fMode & GSTCTL_CREATETEMP_F_DIRECTORY ? "directory" : "file";
+ VGSvcVerbose(4, "Creating temporary %s (szTemplate='%s', fFlags=%#x), rc=%Rrc\n", pszWhat, szTemplate, fFlags, rc);
+
+ bool const fSecure = RT_BOOL(fMode & GSTCTL_CREATETEMP_F_SECURE);
+ if (fMode & GSTCTL_CREATETEMP_F_DIRECTORY)
+ {
+ if (fSecure)
+ rc = RTDirCreateTempSecure(szTemplate); /* File mode is fixed to 0700. */
+ else
+ rc = RTDirCreateTemp(szTemplate, fMode);
+ }
+ else /* File */
+ {
+ if (fSecure)
+ rc = RTFileCreateTempSecure(szTemplate); /* File mode is fixed to 0700. */
+ else
+ rc = RTFileCreateTemp(szTemplate, fMode);
+ }
+ }
+ else
+ {
+ VGSvcError("Invalid temporary directory/file creation flags: %#x\n", fFlags);
+ rc = VERR_NOT_SUPPORTED;
+ }
+
+ /*
+ * Report result back to host.
+ */
+ int rc2 = VbglR3GuestCtrlFsCbCreateTemp(pHostCtx, rc, szTemplate);
+ if (RT_FAILURE(rc2))
+ {
+ VGSvcError("Failed to report temporary file/directory creation status, rc=%Rrc\n", rc2);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+ }
+ else
+ {
+ VGSvcError("Error fetching parameters for file/directory creation operation: %Rrc\n", rc);
+ VbglR3GuestCtrlMsgSkip(pHostCtx->uClientID, rc, UINT32_MAX);
+ }
+ VGSvcVerbose(5, "Creating temporary file/directory returned rc=%Rrc\n", rc);
+ return rc;
+}
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
+
+
int VGSvcGstCtrlSessionHandler(PVBOXSERVICECTRLSESSION pSession, uint32_t uMsg, PVBGLR3GUESTCTRLCMDCTX pHostCtx,
void **ppvScratchBuf, uint32_t *pcbScratchBuf, volatile bool *pfShutdown)
{
@@ -1393,11 +1940,6 @@ int VGSvcGstCtrlSessionHandler(PVBOXSERVICECTRLSESSION pSession, uint32_t uMsg,
*pfShutdown = true; /* Shutdown in any case. */
break;
- case HOST_MSG_DIR_REMOVE:
- if (fImpersonated)
- rc = vgsvcGstCtrlSessionHandleDirRemove(pSession, pHostCtx);
- break;
-
case HOST_MSG_EXEC_CMD:
rc = vgsvcGstCtrlSessionHandleProcExec(pSession, pHostCtx);
break;
@@ -1418,6 +1960,18 @@ int VGSvcGstCtrlSessionHandler(PVBOXSERVICECTRLSESSION pSession, uint32_t uMsg,
rc = vgsvcGstCtrlSessionHandleProcWaitFor(pSession, pHostCtx);
break;
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+ case HOST_MSG_FS_QUERY_INFO:
+ if (fImpersonated)
+ rc = vgsvcGstCtrlSessionHandleFsQueryInfo(pSession, pHostCtx);
+ break;
+
+ case HOST_MSG_FS_CREATE_TEMP:
+ if (fImpersonated)
+ rc = vgsvcGstCtrlSessionHandleFsCreateTemp(pSession, pHostCtx);
+ break;
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
+
case HOST_MSG_FILE_OPEN:
if (fImpersonated)
rc = vgsvcGstCtrlSessionHandleFileOpen(pSession, pHostCtx);
@@ -1463,6 +2017,43 @@ int VGSvcGstCtrlSessionHandler(PVBOXSERVICECTRLSESSION pSession, uint32_t uMsg,
rc = vgsvcGstCtrlSessionHandleFileSetSize(pSession, pHostCtx);
break;
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+ case HOST_MSG_FILE_REMOVE:
+ if (fImpersonated)
+ rc = vgsvcGstCtrlSessionHandleFileRemove(pSession, pHostCtx);
+ break;
+
+ case HOST_MSG_DIR_OPEN:
+ if (fImpersonated)
+ rc = vgsvcGstCtrlSessionHandleDirOpen(pSession, pHostCtx);
+ break;
+
+ case HOST_MSG_DIR_CLOSE:
+ if (fImpersonated)
+ rc = vgsvcGstCtrlSessionHandleDirClose(pSession, pHostCtx);
+ break;
+
+ case HOST_MSG_DIR_READ:
+ if (fImpersonated)
+ rc = vgsvcGstCtrlSessionHandleDirRead(pSession, pHostCtx);
+ break;
+
+ case HOST_MSG_DIR_REWIND:
+ if (fImpersonated)
+ rc = vgsvcGstCtrlSessionHandleDirRewind(pSession, pHostCtx);
+ break;
+
+ case HOST_MSG_DIR_CREATE:
+ if (fImpersonated)
+ rc = vgsvcGstCtrlSessionHandleDirCreate(pSession, pHostCtx);
+ break;
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
+
+ case HOST_MSG_DIR_REMOVE:
+ if (fImpersonated)
+ rc = vgsvcGstCtrlSessionHandleDirRemove(pSession, pHostCtx);
+ break;
+
case HOST_MSG_PATH_RENAME:
if (fImpersonated)
rc = vgsvcGstCtrlSessionHandlePathRename(pSession, pHostCtx);
@@ -1488,7 +2079,8 @@ int VGSvcGstCtrlSessionHandler(PVBOXSERVICECTRLSESSION pSession, uint32_t uMsg,
if (RT_SUCCESS(rc))
{ /* likely */ }
else if (rc != VERR_NOT_SUPPORTED) /* Note: Reply to host must must be sent by above handler. */
- VGSvcError("Error while handling message (uMsg=%RU32, cParms=%RU32), rc=%Rrc\n", uMsg, pHostCtx->uNumParms, rc);
+ VGSvcError("Error while handling message %s (%#x, cParms=%RU32), rc=%Rrc\n",
+ GstCtrlHostMsgtoStr((eHostMsg)uMsg), uMsg, pHostCtx->uNumParms, rc);
else
{
/* We must skip and notify host here as best we can... */
@@ -1500,9 +2092,6 @@ int VGSvcGstCtrlSessionHandler(PVBOXSERVICECTRLSESSION pSession, uint32_t uMsg,
rc = VINF_SUCCESS;
}
- if (RT_FAILURE(rc))
- VGSvcError("Error while handling message (uMsg=%RU32, cParms=%RU32), rc=%Rrc\n", uMsg, pHostCtx->uNumParms, rc);
-
return rc;
}
@@ -2035,6 +2624,12 @@ int VGSvcGstCtrlSessionClose(PVBOXSERVICECTRLSESSION pSession)
pFile = NULL; /* To make it obvious. */
}
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+ AssertMsg(pSession->cDirs == 0,
+ ("Session directory list still contains %RU32 when it should not\n", pSession->cDirs));
+ AssertMsg(RTListIsEmpty(&pSession->lstDirs),
+ ("Session directory list is not empty when it should\n"));
+#endif
AssertMsg(pSession->cFiles == 0,
("Session file list still contains %RU32 when it should not\n", pSession->cFiles));
AssertMsg(RTListIsEmpty(&pSession->lstFiles),
@@ -2067,6 +2662,9 @@ int VGSvcGstCtrlSessionInit(PVBOXSERVICECTRLSESSION pSession, uint32_t fFlags)
AssertPtrReturn(pSession, VERR_INVALID_POINTER);
RTListInit(&pSession->lstProcesses);
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+ RTListInit(&pSession->lstDirs);
+#endif
RTListInit(&pSession->lstFiles);
pSession->cProcesses = 0;
diff --git a/src/VBox/HostServices/GuestControl/Makefile.kmk b/src/VBox/HostServices/GuestControl/Makefile.kmk
index beb5c1c15ad..3160a4900bd 100644
--- a/src/VBox/HostServices/GuestControl/Makefile.kmk
+++ b/src/VBox/HostServices/GuestControl/Makefile.kmk
@@ -38,6 +38,9 @@ DLLS += VBoxGuestControlSvc
VBoxGuestControlSvc_TEMPLATE = VBoxR3Dll
VBoxGuestControlSvc_NAME.os2 = VBoxGCTL
VBoxGuestControlSvc_DEFS = VBOX_WITH_HGCM
+ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+ VBoxGuestControlSvc_DEFS += VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+endif
VBoxGuestControlSvc_INCS = $(PATH_ROOT)/src/VBox/Main/include
VBoxGuestControlSvc_INCS.win = \
$(VBOX_PATH_SDK)
diff --git a/src/VBox/HostServices/GuestControl/VBoxGuestControlSvc.cpp b/src/VBox/HostServices/GuestControl/VBoxGuestControlSvc.cpp
index 74063e448a0..be244d33503 100644
--- a/src/VBox/HostServices/GuestControl/VBoxGuestControlSvc.cpp
+++ b/src/VBox/HostServices/GuestControl/VBoxGuestControlSvc.cpp
@@ -73,6 +73,8 @@
#include <VBox/HostServices/GuestControlSvc.h>
#include <VBox/GuestHost/GuestControl.h> /** @todo r=bird: Why two headers??? */
+#include "VBoxGuestControlSvc-internal.h"
+
#include <VBox/err.h>
#include <VBox/log.h>
#include <VBox/AssertGuest.h>
@@ -1625,6 +1627,7 @@ int GstCtrlService::clientMsgSkip(ClientState *pClient, VBOXHGCMCALLHANDLE hCall
hostCallback(GUEST_MSG_FILE_NOTIFY, 3, aReplyParams);
break;
case HOST_MSG_FILE_READ:
+ RT_FALL_THROUGH();
case HOST_MSG_FILE_READ_AT:
HGCMSvcSetU32(&aReplyParams[1], GUEST_FILE_NOTIFYTYPE_READ); /* type */
HGCMSvcSetU32(&aReplyParams[2], rcSkip); /* rc */
@@ -1632,6 +1635,7 @@ int GstCtrlService::clientMsgSkip(ClientState *pClient, VBOXHGCMCALLHANDLE hCall
hostCallback(GUEST_MSG_FILE_NOTIFY, 4, aReplyParams);
break;
case HOST_MSG_FILE_WRITE:
+ RT_FALL_THROUGH();
case HOST_MSG_FILE_WRITE_AT:
HGCMSvcSetU32(&aReplyParams[1], GUEST_FILE_NOTIFYTYPE_WRITE); /* type */
HGCMSvcSetU32(&aReplyParams[2], rcSkip); /* rc */
@@ -1656,14 +1660,36 @@ int GstCtrlService::clientMsgSkip(ClientState *pClient, VBOXHGCMCALLHANDLE hCall
HGCMSvcSetU64(&aReplyParams[3], 0); /* actual */
hostCallback(GUEST_MSG_FILE_NOTIFY, 4, aReplyParams);
break;
-
- case HOST_MSG_EXEC_GET_OUTPUT: /** @todo This can't be right/work. */
- case HOST_MSG_EXEC_TERMINATE: /** @todo This can't be right/work. */
- case HOST_MSG_EXEC_WAIT_FOR: /** @todo This can't be right/work. */
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+ case HOST_MSG_FS_QUERY_INFO:
+ RT_FALL_THROUGH();
+ case HOST_MSG_FS_CREATE_TEMP:
+ RT_FALL_THROUGH();
+ case HOST_MSG_FILE_REMOVE:
+ RT_FALL_THROUGH();
+ case HOST_MSG_DIR_OPEN:
+ RT_FALL_THROUGH();
+ case HOST_MSG_DIR_CLOSE:
+ RT_FALL_THROUGH();
+ case HOST_MSG_DIR_READ:
+ RT_FALL_THROUGH();
+ case HOST_MSG_DIR_REWIND:
+ RT_FALL_THROUGH();
+ case HOST_MSG_DIR_CREATE:
+ RT_FALL_THROUGH();
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
+ case HOST_MSG_EXEC_GET_OUTPUT: /** @todo BUGBUG This can't be right/work. */
+ case HOST_MSG_EXEC_TERMINATE: /** @todo BUGBUG This can't be right/work. */
+ case HOST_MSG_EXEC_WAIT_FOR: /** @todo BUGBUG This can't be right/work. */
+ break;
+ case HOST_MSG_DIR_REMOVE:
+ RT_FALL_THROUGH();
+ case HOST_MSG_PATH_RENAME:
+ RT_FALL_THROUGH();
case HOST_MSG_PATH_USER_DOCUMENTS:
+ RT_FALL_THROUGH();
case HOST_MSG_PATH_USER_HOME:
- case HOST_MSG_PATH_RENAME:
- case HOST_MSG_DIR_REMOVE:
+ RT_FALL_THROUGH();
default:
HGCMSvcSetU32(&aReplyParams[1], pFirstMsg->mType);
HGCMSvcSetU32(&aReplyParams[2], (uint32_t)rcSkip);
@@ -2609,4 +2635,3 @@ extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *pTa
LogFlowFunc(("Returning %Rrc\n", rc));
return rc;
}
-
diff --git a/src/VBox/HostServices/GuestControl/testcase/Makefile.kmk b/src/VBox/HostServices/GuestControl/testcase/Makefile.kmk
index abaa7a187e3..a48c9edc6b5 100644
--- a/src/VBox/HostServices/GuestControl/testcase/Makefile.kmk
+++ b/src/VBox/HostServices/GuestControl/testcase/Makefile.kmk
@@ -30,6 +30,38 @@ include $(KBUILD_PATH)/subheader.kmk
if defined(VBOX_WITH_TESTCASES) && !defined(VBOX_ONLY_ADDITIONS) && !defined(VBOX_ONLY_SDK)
+ #
+ # Testcase which mocks HGCM to also test the VbglR3-side of Guest Control.
+ #
+ # Goal is to use and test as much guest side code as possible as a self-contained
+ # binary on the host here.
+ #
+ # Note: No #ifdef TESTCASE hacks or similar allowed, has to run
+ # without #ifdef modifications to the core code!
+ #
+ PROGRAMS += tstGuestControlMockHGCM
+
+ tstGuestControlMockHGCM_TEMPLATE = VBoxR3TstExe
+ tstGuestControlMockHGCM_DEFS = VBOX_WITH_HGCM VBOX_WITH_GUEST_CONTROL
+ tstGuestControlMockHGCM_SOURCES = \
+ ../VBoxGuestControlSvc.cpp \
+ $(PATH_ROOT)/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibGuestCtrl.cpp \
+ $(PATH_ROOT)/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibMisc.cpp \
+ $(PATH_ROOT)/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3Lib.cpp \
+ $(PATH_ROOT)/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibGR.cpp \
+ $(PATH_ROOT)/src/VBox/HostServices/common/message.cpp \
+ tstGuestControlMockHGCM.cpp
+ tstGuestControlMockHGCM_LIBS = $(LIB_RUNTIME)
+ tstGuestControlMockHGCM_CLEAN = $(tstGuestControlMockHGCM_0_OUTDIR)/tstGuestControlMockHGCM.run
+
+ if 0 # Enable this if you want automatic runs after compilation.
+ $$(tstGuestControlMockHGCM_0_OUTDIR)/tstGuestControlMockHGCM.run: $$(tstGuestControlMockHGCM_1_STAGE_TARGET)
+ export VBOX_LOG_DEST=nofile; $(tstGuestControlMockHGCM_1_STAGE_TARGET) quiet
+ $(QUIET)$(APPEND) -t "$@" "done"
+ OTHERS += $(tstGuestControlMockHGCM_0_OUTDIR)/tstGuestControlMockHGCM.run
+ endif
+
+
# Set this in LocalConfig.kmk if you are working on the guest property
# service to automatically run the testcase at build time.
# OTHERS += $(tstGuestControlSvc_0_OUTDIR)/tstGuestControlSvc.run
@@ -52,5 +84,14 @@ if defined(VBOX_WITH_TESTCASES) && !defined(VBOX_ONLY_ADDITIONS) && !defined(VBO
endif
-include $(FILE_KBUILD_SUB_FOOTER)
+#
+# List of above testcases that will be included in the ValKit.
+#
+ifdef VBOX_WITH_VALIDATIONKIT_UNITTESTS_PACKING
+ if1of ($(KBUILD_TARGET), linux solaris win)
+ VALKIT_UNITTESTS_WHITELIST_GUEST_ADDITIONS += \
+ tstGuestControlMockHGCM
+ endif
+endif # VBOX_WITH_VALIDATIONKIT_UNITTESTS_PACKING
+include $(FILE_KBUILD_SUB_FOOTER)
diff --git a/src/VBox/HostServices/GuestControl/testcase/tstGuestControlMockHGCM.cpp b/src/VBox/HostServices/GuestControl/testcase/tstGuestControlMockHGCM.cpp
new file mode 100644
index 00000000000..41f12d4219a
--- /dev/null
+++ b/src/VBox/HostServices/GuestControl/testcase/tstGuestControlMockHGCM.cpp
@@ -0,0 +1,322 @@
+/* $Id$ */
+/** @file
+ * Guest Control host service test case.
+ */
+
+/*
+ * Copyright (C) 2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include <VBox/HostServices/GuestControlSvc.h>
+#include <VBox/VBoxGuestLib.h>
+
+#include <VBox/GuestHost/HGCMMock.h>
+#include <VBox/GuestHost/HGCMMockUtils.h>
+
+#include <iprt/assert.h>
+#include <iprt/initterm.h>
+#include <iprt/mem.h>
+#include <iprt/rand.h>
+#include <iprt/stream.h>
+#include <iprt/string.h>
+#include <iprt/test.h>
+#include <iprt/utf16.h>
+
+
+/*********************************************************************************************************************************
+* Static globals *
+*********************************************************************************************************************************/
+static RTTEST g_hTest;
+
+
+/*********************************************************************************************************************************
+* Shared Clipboard testing *
+*********************************************************************************************************************************/
+struct CLIPBOARDTESTDESC;
+/** Pointer to a test description. */
+typedef CLIPBOARDTESTDESC *PTESTDESC;
+
+struct CLIPBOARDTESTCTX;
+/** Pointer to a test context. */
+typedef CLIPBOARDTESTCTX *PCLIPBOARDTESTCTX;
+
+/** Pointer a test descriptor. */
+typedef CLIPBOARDTESTDESC *PTESTDESC;
+
+typedef DECLCALLBACKTYPE(int, FNTESTSETUP,(PCLIPBOARDTESTCTX pTstCtx, void **ppvCtx));
+/** Pointer to a test setup callback. */
+typedef FNTESTSETUP *PFNTESTSETUP;
+
+typedef DECLCALLBACKTYPE(int, FNTESTEXEC,(PCLIPBOARDTESTCTX pTstCtx, void *pvCtx));
+/** Pointer to a test exec callback. */
+typedef FNTESTEXEC *PFNTESTEXEC;
+
+typedef DECLCALLBACKTYPE(int, FNTESTDESTROY,(PCLIPBOARDTESTCTX pTstCtx, void *pvCtx));
+/** Pointer to a test destroy callback. */
+typedef FNTESTDESTROY *PFNTESTDESTROY;
+
+
+/**
+ * Structure for keeping a clipboard test task.
+ */
+typedef struct CLIPBOARDTESTTASK
+{
+
+} CLIPBOARDTESTTASK;
+typedef CLIPBOARDTESTTASK *PCLIPBOARDTESTTASK;
+
+/**
+ * Structure for keeping a clipboard test context.
+ */
+typedef struct CLIPBOARDTESTCTX
+{
+ /** The HGCM Mock utils context. */
+ TSTHGCMUTILSCTX HGCM;
+ /** Clipboard-specific task data. */
+ CLIPBOARDTESTTASK Task;
+ struct
+ {
+ /** The VbglR3 Guest Control context to work on. */
+ VBGLR3GUESTCTRLCMDCTX CmdCtx;
+ } Guest;
+} CLIPBOARDTESTCTX;
+
+/** The one and only clipboard test context. One at a time. */
+CLIPBOARDTESTCTX g_TstCtx;
+
+/**
+ * Structure for keeping a clipboard test description.
+ */
+typedef struct CLIPBOARDTESTDESC
+{
+ /** The setup callback. */
+ PFNTESTSETUP pfnSetup;
+ /** The exec callback. */
+ PFNTESTEXEC pfnExec;
+ /** The destruction callback. */
+ PFNTESTDESTROY pfnDestroy;
+} CLIPBOARDTESTDESC;
+
+typedef struct SHCLCONTEXT
+{
+} SHCLCONTEXT;
+
+
+static void testGuestSimple(void)
+{
+ RTTestISub("Testing client (guest) API - Simple");
+
+ PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst(); RT_NOREF(pSvc);
+
+ /* Preparations. */
+ VBGLR3GUESTCTRLCMDCTX Ctx;
+ RT_ZERO(Ctx);
+
+ /*
+ * Multiple connects / disconnects.
+ */
+ RTTESTI_CHECK_RC_OK(VbglR3GuestCtrlConnect(&Ctx.uClientID));
+ RTTESTI_CHECK_RC_OK(VbglR3GuestCtrlDisconnect(Ctx.uClientID));
+
+ /*
+ * Feature tests.
+ */
+ RTTESTI_CHECK_RC_OK(VbglR3GuestCtrlConnect(&Ctx.uClientID));
+ RTTESTI_CHECK_RC_OK(VbglR3GuestCtrlReportFeatures(Ctx.uClientID, 0x0, NULL /* pfHostFeatures */));
+ /* Report bogus features to the host. */
+ RTTESTI_CHECK_RC_OK(VbglR3GuestCtrlReportFeatures(Ctx.uClientID, 0xdeadb33f, NULL /* pfHostFeatures */));
+ RTTESTI_CHECK_RC_OK(VbglR3GuestCtrlDisconnect(Ctx.uClientID));
+}
+
+static void testHostCall(void)
+{
+}
+
+
+/*********************************************************************************************************************************
+ * Test: Guest reading from host *
+ ********************************************************************************************************************************/
+typedef struct TSTUSERMOCK
+{
+} TSTUSERMOCK;
+typedef TSTUSERMOCK *PTSTUSERMOCK;
+
+static void tstTestReadFromHost_MockInit(PTSTUSERMOCK pUsrMock, const char *pszName)
+{
+ RT_NOREF(pUsrMock, pszName);
+}
+
+static void tstTestReadFromHost_MockDestroy(PTSTUSERMOCK pUsrMock)
+{
+ RT_NOREF(pUsrMock);
+}
+
+static DECLCALLBACK(int) tstTestReadFromHost_ThreadGuest(PTSTHGCMUTILSCTX pCtx, void *pvCtx)
+{
+ RTThreadSleep(1000); /* Fudge; wait until the host has prepared the data for the clipboard. */
+
+ PCLIPBOARDTESTCTX pTstCtx = (PCLIPBOARDTESTCTX)pvCtx;
+ AssertPtr(pTstCtx);
+
+ RT_ZERO(pTstCtx->Guest.CmdCtx);
+ RTTEST_CHECK_RC_OK(g_hTest, VbglR3GuestCtrlConnect(&pTstCtx->Guest.CmdCtx.uClientID));
+
+ RTThreadSleep(1000); /* Fudge; wait until the host has prepared the data for the clipboard. */
+
+ /* Signal that the task ended. */
+ TstHGCMUtilsTaskSignal(&pCtx->Task, VINF_SUCCESS);
+
+ RTTEST_CHECK_RC_OK(g_hTest, VbglR3GuestCtrlDisconnect(pTstCtx->Guest.CmdCtx.uClientID));
+
+ return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) tstTestReadFromHostSetup(PCLIPBOARDTESTCTX pTstCtx, void **ppvCtx)
+{
+ RT_NOREF(pTstCtx, ppvCtx);
+
+ int rc = VINF_SUCCESS;
+
+ return rc;
+}
+
+static DECLCALLBACK(int) tstTestReadFromHostExec(PCLIPBOARDTESTCTX pTstCtx, void *pvCtx)
+{
+ RT_NOREF(pvCtx);
+
+ TstHGCMUtilsGuestThreadStart(&pTstCtx->HGCM, tstTestReadFromHost_ThreadGuest, pTstCtx);
+
+ PTSTHGCMUTILSTASK pTask = (PTSTHGCMUTILSTASK)TstHGCMUtilsTaskGetCurrent(&pTstCtx->HGCM);
+
+ bool fUseMock = false;
+ TSTUSERMOCK UsrMock;
+ if (fUseMock)
+ tstTestReadFromHost_MockInit(&UsrMock, "tstX11Hst");
+
+ /* Wait until the task has been finished. */
+ TstHGCMUtilsTaskWait(pTask, RT_MS_30SEC);
+
+ if (fUseMock)
+ tstTestReadFromHost_MockDestroy(&UsrMock);
+
+ return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) tstTestReadFromHostDestroy(PCLIPBOARDTESTCTX pTstCtx, void *pvCtx)
+{
+ RT_NOREF(pvCtx);
+
+ int vrc = TstHGCMUtilsGuestThreadStop(&pTstCtx->HGCM);
+ AssertRC(vrc);
+ vrc = TstHGCMUtilsHostThreadStop(&pTstCtx->HGCM);
+ AssertRC(vrc);
+
+ return vrc;
+}
+
+
+/*********************************************************************************************************************************
+ * Main *
+ ********************************************************************************************************************************/
+
+/** Test definition table. */
+CLIPBOARDTESTDESC g_aTests[] =
+{
+ /* Tests guest reading clipboard data from the host. */
+ { tstTestReadFromHostSetup, tstTestReadFromHostExec, tstTestReadFromHostDestroy }
+};
+/** Number of tests defined. */
+unsigned g_cTests = RT_ELEMENTS(g_aTests);
+
+static int tstOne(PTESTDESC pTstDesc)
+{
+ PCLIPBOARDTESTCTX pTstCtx = &g_TstCtx;
+
+ void *pvCtx;
+ int rc = pTstDesc->pfnSetup(pTstCtx, &pvCtx);
+ if (RT_SUCCESS(rc))
+ {
+ rc = pTstDesc->pfnExec(pTstCtx, pvCtx);
+
+ int rc2 = pTstDesc->pfnDestroy(pTstCtx, pvCtx);
+ if (RT_SUCCESS(rc))
+ rc = rc2;
+ }
+
+ return rc;
+}
+
+int main(int argc, char *argv[])
+{
+ /*
+ * Init the runtime, test and say hello.
+ */
+ const char *pcszExecName;
+ NOREF(argc);
+ pcszExecName = strrchr(argv[0], '/');
+ pcszExecName = pcszExecName ? pcszExecName + 1 : argv[0];
+ RTEXITCODE rcExit = RTTestInitAndCreate(pcszExecName, &g_hTest);
+ if (rcExit != RTEXITCODE_SUCCESS)
+ return rcExit;
+ RTTestBanner(g_hTest);
+
+#ifndef DEBUG_andy
+ /* Don't let assertions in the host service panic (core dump) the test cases. */
+ RTAssertSetMayPanic(false);
+#endif
+
+ PTSTHGCMMOCKSVC const pSvc = TstHgcmMockSvcInst();
+
+ TstHgcmMockSvcCreate(pSvc, 42 /** @todo */);
+ TstHgcmMockSvcStart(pSvc);
+
+ /*
+ * Run the tests.
+ */
+ if (1)
+ {
+ testGuestSimple();
+ testHostCall();
+ }
+
+ RT_ZERO(g_TstCtx);
+
+ PTSTHGCMUTILSCTX pCtx = &g_TstCtx.HGCM;
+ TstHGCMUtilsCtxInit(pCtx, pSvc);
+
+ PTSTHGCMUTILSTASK pTask = (PTSTHGCMUTILSTASK)TstHGCMUtilsTaskGetCurrent(pCtx);
+ TstHGCMUtilsTaskInit(pTask);
+ pTask->pvUser = &g_TstCtx.Task;
+
+ for (unsigned i = 0; i < RT_ELEMENTS(g_aTests); i++)
+ tstOne(&g_aTests[i]);
+
+ TstHGCMUtilsTaskDestroy(pTask);
+
+ TstHgcmMockSvcStop(pSvc);
+ TstHgcmMockSvcDestroy(pSvc);
+
+ /*
+ * Summary
+ */
+ return RTTestSummaryAndDestroy(g_hTest);
+}
+
diff --git a/src/VBox/Main/Makefile.kmk b/src/VBox/Main/Makefile.kmk
index 5247c84dc02..6dd832f4cb6 100644
--- a/src/VBox/Main/Makefile.kmk
+++ b/src/VBox/Main/Makefile.kmk
@@ -200,6 +200,12 @@ endif
ifdef VBOX_WITH_MAIN_NLS
VBOX_MAIN_DEFS += VBOX_WITH_MAIN_NLS
endif
+ifdef VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT
+ VBOX_MAIN_DEFS += VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT
+endif
+ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+ VBOX_MAIN_DEFS += VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+endif
# Unconditionally enable the new semaphore key generation code
VBOX_MAIN_DEFS += VBOX_WITH_NEW_SYS_V_KEYGEN
diff --git a/src/VBox/Main/idl/VirtualBox.xidl b/src/VBox/Main/idl/VirtualBox.xidl
index 4639f99b3b9..f6b4c5f4519 100644
--- a/src/VBox/Main/idl/VirtualBox.xidl
+++ b/src/VBox/Main/idl/VirtualBox.xidl
@@ -14244,6 +14244,34 @@
</enum>
<enum
+ name="DirectoryStatus"
+ uuid="a50ca1fc-85a9-4a7a-b755-68c3db01caf1"
+ >
+ <desc>
+ Directory statuses.
+ </desc>
+
+ <const name="Undefined" value="0">
+ <desc>Directory is in an undefined state.</desc>
+ </const>
+ <const name="Open" value="1">
+ <desc>Guest directory has been successfully opened.</desc>
+ </const>
+ <const name="Close" value="2">
+ <desc>Guest directory has been closed.</desc>
+ </const>
+ <const name="Rewind" value="3">
+ <desc>Guest directory reading was rewound.</desc>
+ </const>
+ <const name="Down" value="4">
+ <desc>Service/OS is stopping, guest directory was closed.</desc>
+ </const>
+ <const name="Error" value="5">
+ <desc>Something went wrong.</desc>
+ </const>
+ </enum>
+
+ <enum
name="FileAccessMode"
uuid="231a578f-47fb-ea30-3b3e-8489558227f0"
>
@@ -16379,7 +16407,7 @@
<interface
name="IDirectory" extends="$unknown"
- uuid="758d7eac-e4b1-486a-8f2e-747ae346c3e9"
+ uuid="c7b24ad6-dba7-486c-b1ed-5f16d8d6da22"
wsmap="managed"
reservedMethods="4" reservedAttributes="8"
>
@@ -16391,10 +16419,28 @@
<desc>The path specified when opening the directory.</desc>
</attribute>
+ <attribute name="eventSource" type="IEventSource" readonly="yes">
+ <desc>
+ Event source for directory events.
+ </desc>
+ </attribute>
+
<attribute name="filter" type="wstring" readonly="yes">
<desc>Directory listing filter to (specified when opening the directory).</desc>
</attribute>
+ <attribute name="id" type="unsigned long" readonly="yes">
+ <desc>
+ The ID VirtualBox internally assigned to the open directory.
+ </desc>
+ </attribute>
+
+ <attribute name="status" type="DirectoryStatus" readonly="yes">
+ <desc>
+ Current directory status.
+ </desc>
+ </attribute>
+
<method name="close">
<desc>
Closes this directory. After closing operations like reading the next
@@ -16415,6 +16461,12 @@
</param>
</method>
+ <method name="rewind">
+ <desc>
+ Rewinds the directory reading.
+ </desc>
+ </method>
+
<!-- Would be useful to add queryInfo() and setACL() here later, but at
present IPRT isn't doing a race free job with the former and doesn't
have the latter. So, let it be for now. -->
@@ -16798,7 +16850,7 @@
</attribute>
<attribute name="fileAttributes" type="wstring" readonly="yes">
<desc>
- File attributes. Not implemented yet.
+ File attributes.
</desc>
</attribute>
<attribute name="objectSize" type="long long" readonly="yes">
@@ -26259,7 +26311,7 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi)
-->
<enum
name="VBoxEventType"
- uuid="e4c5252d-7d1a-4051-8cfb-5b2d7a73d992"
+ uuid="03b0e6ea-28fe-4f0a-a3ec-1a21703da6f7"
>
<desc>
@@ -26758,8 +26810,25 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi)
See <link to="IMachineGroupsChangedEvent">IMachineGroupsChangedEvent</link>.
</desc>
</const>
+ <const name="OnGuestDirectoryRegistered" value="119">
+ <desc>
+ See <link to="IGuestDirectoryRegisteredEvent">IGuestDirectoryRegisteredEvent</link>.
+ </desc>
+ </const>
+ <const name="OnGuestDirectoryStateChanged" value="120">
+ <desc>
+ See <link to="IGuestDirectoryStateChangedEvent">IGuestDirectoryStateChangedEvent</link>.
+ </desc>
+ </const>
+ <const name="OnGuestDirectoryRead" value="121">
+ <desc>
+ See <link to="IGuestDirectoryReadEvent">IGuestDirectoryReadEvent</link>.
+ <note internal="yes">For performance reasons this is a separate event to
+ not unnecessarily overflow the event queue.</note>
+ </desc>
+ </const>
<!-- End event marker -->
- <const name="End" value="119">
+ <const name="End" value="122">
<desc>
Must be last event, used for iterations and structures relying on numerical event values.
</desc>
@@ -27983,6 +28052,83 @@ Snapshot 1 (B.vdi) Snapshot 1 (B.vdi)
</interface>
<interface
+ name="IGuestDirectoryEvent" extends="IGuestSessionEvent"
+ uuid="02b69798-7cc2-4005-ac57-1ad7ff7a0997"
+ wsmap="managed"
+ >
+ <desc>Base abstract interface for all guest directory events.</desc>
+
+ <attribute name="directory" type="IGuestDirectory" readonly="yes">
+ <desc>
+ Guest directory object which is related to this event.
+ </desc>
+ </attribute>
+
+ </interface>
+
+ <interface
+ name="IGuestDirectoryRegisteredEvent" extends="IGuestDirectoryEvent"
+ uuid="926baa39-cfc9-462e-a1a1-c439e28f7f89"
+ wsmap="managed" autogen="VBoxEvent" id="OnGuestDirectoryRegistered"
+ >
+ <desc>
+ Notification when a guest directory was registered or unregistered.
+ </desc>
+
+ <attribute name="registered" type="boolean" readonly="yes">
+ <desc>
+ If @c true, the guest directory was registered, otherwise it was
+ unregistered.
+ </desc>
+ </attribute>
+
+ </interface>
+
+ <interface
+ name="IGuestDirectoryStateChangedEvent" extends="IGuestDirectoryEvent"
+ uuid="c32bce60-d69d-4eb7-a02a-411ecbab6a18"
+ wsmap="managed" autogen="VBoxEvent" id="OnGuestDirectoryStateChanged"
+ >
+ <desc>
+ Notification when a guest directory changed its state.
+ </desc>
+
+ <attribute name="status" type="DirectoryStatus" readonly="yes">
+ <desc>
+ New guest directory status.
+ </desc>
+ </attribute>
+ <attribute name="error" type="IVirtualBoxErrorInfo" readonly="yes">
+ <desc>
+ Error information in case of new session status is indicating an error.
+
+ The attribute <link to="IVirtualBoxErrorInfo::resultDetail"/> will contain
+ the runtime (IPRT) error code from the guest. See include/iprt/err.h and
+ include/VBox/err.h for details.
+ </desc>
+ </attribute>
+ <!-- Note: No events for reads for performance reasons.
+ See dedicated event IGuestDirectoryReadEvent. -->
+
+ </interface>
+
+ <interface
+ name="IGuestDirectoryReadEvent" extends="IGuestDirectoryEvent"
+ uuid="6eef78d9-51d6-495b-8f91-807654a189a2"
+ wsmap="managed" autogen="VBoxEvent" id="OnGuestDirectoryRead"
+ >
+ <desc>
+ Notification when a directory entry has been read.
+ </desc>
+
+ <attribute name="objInfo" type="IFsObjInfo" readonly="yes">
+ <desc>Object information of the current directory entry read. Also see
+ <link to="IFsObjInfo"/>.</desc>
+ </attribute>
+
+ </interface>
+
+ <interface
name="IGuestFileEvent" extends="IGuestSessionEvent"
uuid="c8adb7b0-057d-4391-b928-f14b06b710c5"
wsmap="managed"
diff --git a/src/VBox/Main/include/GuestCtrlImplPrivate.h b/src/VBox/Main/include/GuestCtrlImplPrivate.h
index c90d1af8490..70695b17846 100644
--- a/src/VBox/Main/include/GuestCtrlImplPrivate.h
+++ b/src/VBox/Main/include/GuestCtrlImplPrivate.h
@@ -61,7 +61,7 @@ typedef std::vector <LONG> ProcessAffinity;
/** Vector holding process startup arguments. */
typedef std::vector <Utf8Str> ProcessArguments;
-class GuestProcessStreamBlock;
+class GuestToolboxStreamBlock;
class GuestSession;
@@ -635,8 +635,9 @@ public:
Type_File,
/** Guest error is from a guest directory object. */
Type_Directory,
- /** Guest error is from a the built-in toolbox "vbox_cat" command. */
- Type_ToolCat,
+ /** Guest error is from a file system operation. */
+ Type_Fs,
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT
/** Guest error is from a the built-in toolbox "vbox_ls" command. */
Type_ToolLs,
/** Guest error is from a the built-in toolbox "vbox_rm" command. */
@@ -647,6 +648,7 @@ public:
Type_ToolMkTemp,
/** Guest error is from a the built-in toolbox "vbox_stat" command. */
Type_ToolStat,
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT */
/** The usual 32-bit hack. */
Type_32BIT_HACK = 0x7fffffff
};
@@ -720,13 +722,16 @@ protected:
struct GuestDirectoryOpenInfo
{
GuestDirectoryOpenInfo(void)
- : mFlags(0) { }
+ : menmFilter(GSTCTLDIRFILTER_NONE)
+ , mFlags(0) { }
/** The directory path. */
Utf8Str mPath;
- /** Then open filter. */
+ /** The filter to use (wildcard style). */
Utf8Str mFilter;
- /** Opening flags. */
+ /** The filter option to use. */
+ GSTCTLDIRFILTER menmFilter;
+ /** Opening flags (of type GSTCTLDIRFILTER_XXX). */
uint32_t mFlags;
};
@@ -798,12 +803,30 @@ struct GuestFileOpenInfo
/**
+ * Helper class for guest file system operations.
+ */
+class GuestFs
+{
+ DECLARE_TRANSLATE_METHODS(GuestFs)
+
+private:
+
+ /* Not directly instantiable. */
+ GuestFs(void) { }
+
+public:
+
+ static Utf8Str guestErrorToString(const GuestErrorInfo &guestErrorInfo);
+};
+
+
+/**
* Structure representing information of a
* file system object.
*/
struct GuestFsObjData
{
- GuestFsObjData(void)
+ GuestFsObjData(const Utf8Str &strName = "")
: mType(FsObjType_Unknown)
, mObjectSize(0)
, mAllocatedSize(0)
@@ -818,21 +841,32 @@ struct GuestFsObjData
, mNumHardLinks(0)
, mDeviceNumber(0)
, mGenerationID(0)
- , mUserFlags(0) { }
+ , mUserFlags(0) { mName = strName; }
+
+ void Init(const Utf8Str &strName) { mName = strName; }
+
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+ int FromGuestFsObjInfo(PCGSTCTLFSOBJINFO pFsObjInfo, const Utf8Str &strUser = "", const Utf8Str &strGroups = "",
+ const void *pvACL = NULL, size_t cbACL = 0);
+#endif
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT
/** @name Helper functions to extract the data from a certin VBoxService tool's guest stream block.
* @{ */
- int FromLs(const GuestProcessStreamBlock &strmBlk, bool fLong);
- int FromRm(const GuestProcessStreamBlock &strmBlk);
- int FromStat(const GuestProcessStreamBlock &strmBlk);
- int FromMkTemp(const GuestProcessStreamBlock &strmBlk);
+ int FromToolboxLs(const GuestToolboxStreamBlock &strmBlk, bool fLong);
+ int FromToolboxRm(const GuestToolboxStreamBlock &strmBlk);
+ int FromToolboxStat(const GuestToolboxStreamBlock &strmBlk);
+ int FromToolboxMkTemp(const GuestToolboxStreamBlock &strmBlk);
/** @} */
+#endif
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT
/** @name Static helper functions to work with time from stream block keys.
* @{ */
- static PRTTIMESPEC TimeSpecFromKey(const GuestProcessStreamBlock &strmBlk, const Utf8Str &strKey, PRTTIMESPEC pTimeSpec);
- static int64_t UnixEpochNsFromKey(const GuestProcessStreamBlock &strmBlk, const Utf8Str &strKey);
+ static PRTTIMESPEC TimeSpecFromKey(const GuestToolboxStreamBlock &strmBlk, const Utf8Str &strKey, PRTTIMESPEC pTimeSpec);
+ static int64_t UnixEpochNsFromKey(const GuestToolboxStreamBlock &strmBlk, const Utf8Str &strKey);
/** @} */
+#endif
/** @name helper functions to work with IPRT stuff.
* @{ */
@@ -931,19 +965,19 @@ public:
/**
* Class representing the "value" side of a "key=value" pair.
*/
-class GuestProcessStreamValue
+class GuestToolboxStreamValue
{
public:
- GuestProcessStreamValue(void) { }
- GuestProcessStreamValue(const char *pszValue)
+ GuestToolboxStreamValue(void) { }
+ GuestToolboxStreamValue(const char *pszValue)
: mValue(pszValue) {}
- GuestProcessStreamValue(const GuestProcessStreamValue& aThat)
+ GuestToolboxStreamValue(const GuestToolboxStreamValue& aThat)
: mValue(aThat.mValue) { }
/** Copy assignment operator. */
- GuestProcessStreamValue &operator=(GuestProcessStreamValue const &a_rThat) RT_NOEXCEPT
+ GuestToolboxStreamValue &operator=(GuestToolboxStreamValue const &a_rThat) RT_NOEXCEPT
{
mValue = a_rThat.mValue;
@@ -954,23 +988,26 @@ public:
};
/** Map containing "key=value" pairs of a guest process stream. */
-typedef std::pair< Utf8Str, GuestProcessStreamValue > GuestCtrlStreamPair;
-typedef std::map < Utf8Str, GuestProcessStreamValue > GuestCtrlStreamPairMap;
-typedef std::map < Utf8Str, GuestProcessStreamValue >::iterator GuestCtrlStreamPairMapIter;
-typedef std::map < Utf8Str, GuestProcessStreamValue >::const_iterator GuestCtrlStreamPairMapIterConst;
+typedef std::pair< Utf8Str, GuestToolboxStreamValue > GuestCtrlStreamPair;
+typedef std::map < Utf8Str, GuestToolboxStreamValue > GuestCtrlStreamPairMap;
+typedef std::map < Utf8Str, GuestToolboxStreamValue >::iterator GuestCtrlStreamPairMapIter;
+typedef std::map < Utf8Str, GuestToolboxStreamValue >::const_iterator GuestCtrlStreamPairMapIterConst;
/**
* Class representing a block of stream pairs (key=value). Each block in a raw guest
* output stream is separated by "\0\0", each pair is separated by "\0". The overall
* end of a guest stream is marked by "\0\0\0\0".
+ *
+ * Only used for the busybox-like toolbox commands within VBoxService.
+ * Deprecated, do not use anymore.
*/
-class GuestProcessStreamBlock
+class GuestToolboxStreamBlock
{
public:
- GuestProcessStreamBlock(void);
+ GuestToolboxStreamBlock(void);
- virtual ~GuestProcessStreamBlock(void);
+ virtual ~GuestToolboxStreamBlock(void);
public:
@@ -999,22 +1036,24 @@ protected:
};
/** Vector containing multiple allocated stream pair objects. */
-typedef std::vector< GuestProcessStreamBlock > GuestCtrlStreamObjects;
-typedef std::vector< GuestProcessStreamBlock >::iterator GuestCtrlStreamObjectsIter;
-typedef std::vector< GuestProcessStreamBlock >::const_iterator GuestCtrlStreamObjectsIterConst;
+typedef std::vector< GuestToolboxStreamBlock > GuestCtrlStreamObjects;
+typedef std::vector< GuestToolboxStreamBlock >::iterator GuestCtrlStreamObjectsIter;
+typedef std::vector< GuestToolboxStreamBlock >::const_iterator GuestCtrlStreamObjectsIterConst;
/**
* Class for parsing machine-readable guest process output by VBoxService'
* toolbox commands ("vbox_ls", "vbox_stat" etc), aka "guest stream".
+ *
+ * Deprecated, do not use anymore.
*/
-class GuestProcessStream
+class GuestToolboxStream
{
public:
- GuestProcessStream();
+ GuestToolboxStream();
- virtual ~GuestProcessStream();
+ virtual ~GuestToolboxStream();
public:
@@ -1030,7 +1069,7 @@ public:
size_t GetSize() { return m_cbUsed; }
- int ParseBlock(GuestProcessStreamBlock &streamBlock);
+ int ParseBlock(GuestToolboxStreamBlock &streamBlock);
protected:
diff --git a/src/VBox/Main/include/GuestDirectoryImpl.h b/src/VBox/Main/include/GuestDirectoryImpl.h
index cfc55553d57..277ffd31fd4 100644
--- a/src/VBox/Main/include/GuestDirectoryImpl.h
+++ b/src/VBox/Main/include/GuestDirectoryImpl.h
@@ -67,11 +67,22 @@ public:
public:
/** @name Public internal methods.
* @{ */
- int i_closeInternal(int *pvrcGuest);
+ int i_open(int *pvrcGuest);
+ int i_close(int *pvrcGuest);
+ EventSource *i_getEventSource(void) { return mEventSource; }
+ int i_onDirNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData);
int i_read(ComObjPtr<GuestFsObjInfo> &fsObjInfo, int *pvrcGuest);
- int i_readInternal(GuestFsObjData &objData, int *prcGuest);
+ int i_readInternal(GuestFsObjData &objData, int *pvrcGuest);
+ int i_rewind(uint32_t uTimeoutMS, int *pvrcGuest);
+ int i_setStatus(DirectoryStatus_T enmStatus, int vrcDir);
/** @} */
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT
+ int i_openViaToolbox(int *pvrcGuest);
+ int i_closeViaToolbox(int *pvrcGuest);
+ int i_readInternalViaToolbox(GuestFsObjData &objData, int *pvrcGuest);
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT */
+
public:
/** @name Public static internal methods.
* @{ */
@@ -89,15 +100,30 @@ private:
/** Wrapped @name IGuestDirectory methods.
* @{ */
HRESULT close();
+ HRESULT getEventSource(ComPtr<IEventSource> &aEventSource);
+ HRESULT getId(ULONG *aId);
+ HRESULT getStatus(DirectoryStatus_T *aStatus);
HRESULT read(ComPtr<IFsObjInfo> &aObjInfo);
+ HRESULT rewind(void);
/** @} */
+ /** This can safely be used without holding any locks.
+ * An AutoCaller suffices to prevent it being destroy while in use and
+ * internally there is a lock providing the necessary serialization. */
+ const ComObjPtr<EventSource> mEventSource;
+
struct Data
{
/** The directory's open info. */
GuestDirectoryOpenInfo mOpenInfo;
+ /** The current directory status. */
+ DirectoryStatus_T mStatus;
+ /** The last returned directory error returned from the guest side. */
+ int mLastError;
+# ifdef VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT
/** The process tool instance to use. */
- GuestProcessTool mProcessTool;
+ GuestProcessToolbox mProcessTool;
+# endif
/** Object data cache.
* Its mName attribute acts as a beacon if the cache is valid or not. */
GuestFsObjData mObjData;
diff --git a/src/VBox/Main/include/GuestProcessImpl.h b/src/VBox/Main/include/GuestProcessImpl.h
index 86fadf76385..5c01d31ee83 100644
--- a/src/VBox/Main/include/GuestProcessImpl.h
+++ b/src/VBox/Main/include/GuestProcessImpl.h
@@ -228,14 +228,14 @@ struct GuestProcessToolErrorInfo
* Note! When implementing new functionality / commands, do *not* use this approach anymore!
* This class has to be kept to guarantee backwards-compatibility.
*/
-class GuestProcessTool
+class GuestProcessToolbox
{
public:
DECLARE_TRANSLATE_METHODS(GuestProcessTool)
- GuestProcessTool(void);
+ GuestProcessToolbox(void);
- virtual ~GuestProcessTool(void);
+ virtual ~GuestProcessToolbox(void);
public:
@@ -243,19 +243,19 @@ public:
void uninit(void);
- int getCurrentBlock(uint32_t uHandle, GuestProcessStreamBlock &strmBlock);
+ int getCurrentBlock(uint32_t uHandle, GuestToolboxStreamBlock &strmBlock);
int getRc(void) const;
/** Returns the stdout output from the guest process tool. */
- GuestProcessStream &getStdOut(void) { return mStdOut; }
+ GuestToolboxStream &getStdOut(void) { return mStdOut; }
/** Returns the stderr output from the guest process tool. */
- GuestProcessStream &getStdErr(void) { return mStdErr; }
+ GuestToolboxStream &getStdErr(void) { return mStdErr; }
int wait(uint32_t fToolWaitFlags, int *pvrcGuest);
- int waitEx(uint32_t fToolWaitFlags, GuestProcessStreamBlock *pStreamBlock, int *pvrcGuest);
+ int waitEx(uint32_t fToolWaitFlags, GuestToolboxStreamBlock *pStreamBlock, int *pvrcGuest);
bool isRunning(void);
@@ -301,9 +301,9 @@ protected:
/** The toolbox' startup info. */
GuestProcessStartupInfo mStartupInfo;
/** Stream object for handling the toolbox' stdout data. */
- GuestProcessStream mStdOut;
+ GuestToolboxStream mStdOut;
/** Stream object for handling the toolbox' stderr data. */
- GuestProcessStream mStdErr;
+ GuestToolboxStream mStdErr;
};
#endif /* !MAIN_INCLUDED_GuestProcessImpl_h */
diff --git a/src/VBox/Main/src-client/GuestCtrlPrivate.cpp b/src/VBox/Main/src-client/GuestCtrlPrivate.cpp
index 164152558c6..7db93e428c5 100644
--- a/src/VBox/Main/src-client/GuestCtrlPrivate.cpp
+++ b/src/VBox/Main/src-client/GuestCtrlPrivate.cpp
@@ -52,6 +52,177 @@
#include <VBox/AssertGuest.h>
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+/**
+ * Returns a stringyfied error of a guest fs error.
+ *
+ * @returns Stringyfied error.
+ * @param guestErrorInfo Guest error info to get stringyfied error for.
+ */
+/* static */
+Utf8Str GuestFs::guestErrorToString(const GuestErrorInfo &guestErrorInfo)
+{
+ Utf8Str strErr;
+
+ /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */
+ switch (guestErrorInfo.getVrc())
+ {
+ case VERR_ACCESS_DENIED:
+ strErr.printf(tr("Access to \"%s\" denied"), guestErrorInfo.getWhat().c_str());
+ break;
+
+ case VERR_FILE_NOT_FOUND: /* This is the most likely error. */
+ RT_FALL_THROUGH();
+ case VERR_PATH_NOT_FOUND:
+ strErr.printf(tr("No such file or directory \"%s\""), guestErrorInfo.getWhat().c_str());
+ break;
+
+ case VERR_INVALID_VM_HANDLE:
+ strErr.printf(tr("VMM device is not available (is the VM running?)"));
+ break;
+
+ case VERR_HGCM_SERVICE_NOT_FOUND:
+ strErr.printf(tr("The guest execution service is not available"));
+ break;
+
+ case VERR_BAD_EXE_FORMAT:
+ strErr.printf(tr("The file \"%s\" is not an executable format"), guestErrorInfo.getWhat().c_str());
+ break;
+
+ case VERR_AUTHENTICATION_FAILURE:
+ strErr.printf(tr("The user \"%s\" was not able to logon"), guestErrorInfo.getWhat().c_str());
+ break;
+
+ case VERR_INVALID_NAME:
+ strErr.printf(tr("The file \"%s\" is an invalid name"), guestErrorInfo.getWhat().c_str());
+ break;
+
+ case VERR_TIMEOUT:
+ strErr.printf(tr("The guest did not respond within time"));
+ break;
+
+ case VERR_CANCELLED:
+ strErr.printf(tr("The execution operation was canceled"));
+ break;
+
+ case VERR_GSTCTL_MAX_CID_OBJECTS_REACHED:
+ strErr.printf(tr("Maximum number of concurrent guest processes has been reached"));
+ break;
+
+ case VERR_NOT_FOUND:
+ strErr.printf(tr("The guest execution service is not ready (yet)"));
+ break;
+
+ default:
+ strErr.printf(tr("Unhandled error %Rrc for \"%s\" occurred on guest -- please file a bug report"),
+ guestErrorInfo.getVrc(), guestErrorInfo.getWhat().c_str());
+ break;
+ }
+
+ return strErr;
+}
+
+
+/**
+ * Set the file system object data from a given GSTCTLFSOBJINFO struct.
+ *
+ * @returns VBox status code.
+ * @param pFsObjInfo Pointer to GSTCTLFSOBJINFO struct to use.
+ * @param strUser Resolved user name owning the object on the guest.
+ * @param strGroups Resolved user group(s) the object on the guest is associated with.
+ * On Windows there can be multiple groups assigned. The groups are separated with ";"
+ * The first group found is always the primary group.
+ * @param pvACL ACL data associated with the object.
+ * @param cbACL Size of ACL data (in bytes) associated with the object.
+ */
+int GuestFsObjData::FromGuestFsObjInfo(PCGSTCTLFSOBJINFO pFsObjInfo,
+ const Utf8Str &strUser /* = "" */, const Utf8Str &strGroups /* = "" */, const void *pvACL /* = NULL */, size_t cbACL /* = 0 */)
+{
+ RT_NOREF(pvACL, cbACL);
+
+ int rc;
+
+ mType = GuestBase::fileModeToFsObjType(pFsObjInfo->Attr.fMode);
+
+ mFileAttrs = "";
+ switch (mType)
+ {
+ case FsObjType_File: mFileAttrs += '-'; break;
+ case FsObjType_Directory: mFileAttrs += 'd'; break;
+ case FsObjType_Symlink: mFileAttrs += 'l'; break;
+ case FsObjType_DevChar: mFileAttrs += 'c'; break;
+ case FsObjType_DevBlock: mFileAttrs += 'b'; break;
+ case FsObjType_Fifo: mFileAttrs += 'f'; break;
+ case FsObjType_Socket: mFileAttrs += 's'; break;
+ case FsObjType_WhiteOut: mFileAttrs += 'w'; break;
+ default:
+ mFileAttrs += '?';
+ AssertFailedStmt(rc = VERR_NOT_SUPPORTED);
+ break;
+ }
+
+#define ADD_ATTR(a_Flag, a_Set, a_Clear) \
+ mFileAttrs += pFsObjInfo->Attr.fMode & a_Flag ? a_Set : a_Clear
+
+ ADD_ATTR(RTFS_UNIX_IRUSR, 'r', '-');
+ ADD_ATTR(RTFS_UNIX_IWUSR, 'w', '-');
+ ADD_ATTR(RTFS_UNIX_IXUSR, 'x', '-');
+
+ ADD_ATTR(RTFS_UNIX_IRGRP, 'r', '-');
+ ADD_ATTR(RTFS_UNIX_IWGRP, 'w', '-');
+ ADD_ATTR(RTFS_UNIX_IXGRP, 'x', '-');
+
+ ADD_ATTR(RTFS_UNIX_IROTH, 'r', '-');
+ ADD_ATTR(RTFS_UNIX_IWOTH, 'w', '-');
+ ADD_ATTR(RTFS_UNIX_IXOTH, 'x', '-');
+
+ /** @todo Implement sticky bits. */
+ mFileAttrs += " "; /* Reserve 3 chars for sticky bits. */
+
+ mFileAttrs += " "; /* Separator. */
+
+ ADD_ATTR(RTFS_DOS_READONLY , 'R', '-');
+ ADD_ATTR(RTFS_DOS_HIDDEN , 'H', '-');
+ ADD_ATTR(RTFS_DOS_SYSTEM , 'S', '-');
+ ADD_ATTR(RTFS_DOS_DIRECTORY , 'D', '-');
+ ADD_ATTR(RTFS_DOS_ARCHIVED , 'A', '-');
+ ADD_ATTR(RTFS_DOS_NT_DEVICE , 'd', '-');
+ ADD_ATTR(RTFS_DOS_NT_NORMAL , 'N', '-');
+ ADD_ATTR(RTFS_DOS_NT_TEMPORARY , 'T', '-');
+ ADD_ATTR(RTFS_DOS_NT_SPARSE_FILE , 'P', '-');
+ ADD_ATTR(RTFS_DOS_NT_REPARSE_POINT , 'J', '-');
+ ADD_ATTR(RTFS_DOS_NT_COMPRESSED , 'C', '-');
+ ADD_ATTR(RTFS_DOS_NT_OFFLINE , 'O', '-');
+ ADD_ATTR(RTFS_DOS_NT_NOT_CONTENT_INDEXED, 'I', '-');
+ ADD_ATTR(RTFS_DOS_NT_ENCRYPTED , 'E', '-');
+
+#undef ADD_ATTR
+
+ mObjectSize = pFsObjInfo->cbObject;
+ mAllocatedSize = pFsObjInfo->cbAllocated;
+ mAccessTime = pFsObjInfo->AccessTime.i64NanosecondsRelativeToUnixEpoch;
+ mBirthTime = pFsObjInfo->BirthTime.i64NanosecondsRelativeToUnixEpoch;
+ mChangeTime = pFsObjInfo->ChangeTime.i64NanosecondsRelativeToUnixEpoch;
+ mModificationTime = pFsObjInfo->ModificationTime.i64NanosecondsRelativeToUnixEpoch;
+ mUserName = strUser;
+ mUID = pFsObjInfo->Attr.u.Unix.uid;
+ mGID = pFsObjInfo->Attr.u.Unix.gid;
+ mGroupName = strGroups; /** @todo Separate multiple group. */
+ mNumHardLinks = pFsObjInfo->Attr.u.Unix.cHardlinks;
+ mNodeIDDevice = pFsObjInfo->Attr.u.Unix.INodeIdDevice;
+ mNodeID = pFsObjInfo->Attr.u.Unix.INodeId;
+ mDeviceNumber = RTFS_IS_DEV_BLOCK(pFsObjInfo->Attr.fMode)
+ || RTFS_IS_DEV_CHAR (pFsObjInfo->Attr.fMode) ? pFsObjInfo->Attr.u.Unix.Device : 0;
+ mGenerationID = pFsObjInfo->Attr.u.Unix.GenerationId;
+ mUserFlags = 0;
+
+ mACL = ""; /** @todo Implement ACL handling. */
+
+ return VINF_SUCCESS;
+}
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
+
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT
/**
* Extracts the timespec from a given stream block key.
*
@@ -61,7 +232,7 @@
* @param pTimeSpec Where to store the extracted timespec.
*/
/* static */
-PRTTIMESPEC GuestFsObjData::TimeSpecFromKey(const GuestProcessStreamBlock &strmBlk, const Utf8Str &strKey, PRTTIMESPEC pTimeSpec)
+PRTTIMESPEC GuestFsObjData::TimeSpecFromKey(const GuestToolboxStreamBlock &strmBlk, const Utf8Str &strKey, PRTTIMESPEC pTimeSpec)
{
AssertPtrReturn(pTimeSpec, NULL);
@@ -83,7 +254,7 @@ PRTTIMESPEC GuestFsObjData::TimeSpecFromKey(const GuestProcessStreamBlock &strmB
* @param strKey Key to get nanoseconds for.
*/
/* static */
-int64_t GuestFsObjData::UnixEpochNsFromKey(const GuestProcessStreamBlock &strmBlk, const Utf8Str &strKey)
+int64_t GuestFsObjData::UnixEpochNsFromKey(const GuestToolboxStreamBlock &strmBlk, const Utf8Str &strKey)
{
RTTIMESPEC TimeSpec;
if (!GuestFsObjData::TimeSpecFromKey(strmBlk, strKey, &TimeSpec))
@@ -102,7 +273,7 @@ int64_t GuestFsObjData::UnixEpochNsFromKey(const GuestProcessStreamBlock &strmBl
* @param strmBlk Stream block to use for initialization.
* @param fLong Whether the stream block contains long (detailed) information or not.
*/
-int GuestFsObjData::FromLs(const GuestProcessStreamBlock &strmBlk, bool fLong)
+int GuestFsObjData::FromToolboxLs(const GuestToolboxStreamBlock &strmBlk, bool fLong)
{
LogFlowFunc(("\n"));
#ifdef DEBUG
@@ -252,7 +423,7 @@ int GuestFsObjData::FromLs(const GuestProcessStreamBlock &strmBlk, bool fLong)
* @returns VBox status code.
* @param strmBlk Stream block output data to parse.
*/
-int GuestFsObjData::FromRm(const GuestProcessStreamBlock &strmBlk)
+int GuestFsObjData::FromToolboxRm(const GuestToolboxStreamBlock &strmBlk)
{
#ifdef DEBUG
strmBlk.DumpToLog();
@@ -271,10 +442,10 @@ int GuestFsObjData::FromRm(const GuestProcessStreamBlock &strmBlk)
* @returns VBox status code.
* @param strmBlk Stream block output data to parse.
*/
-int GuestFsObjData::FromStat(const GuestProcessStreamBlock &strmBlk)
+int GuestFsObjData::FromToolboxStat(const GuestToolboxStreamBlock &strmBlk)
{
/* Should be identical output. */
- return GuestFsObjData::FromLs(strmBlk, true /*fLong*/);
+ return GuestFsObjData::FromToolboxLs(strmBlk, true /*fLong*/);
}
/**
@@ -284,7 +455,7 @@ int GuestFsObjData::FromStat(const GuestProcessStreamBlock &strmBlk)
* @returns VBox status code.
* @param strmBlk Stream block output data to parse.
*/
-int GuestFsObjData::FromMkTemp(const GuestProcessStreamBlock &strmBlk)
+int GuestFsObjData::FromToolboxMkTemp(const GuestToolboxStreamBlock &strmBlk)
{
LogFlowFunc(("\n"));
@@ -301,6 +472,8 @@ int GuestFsObjData::FromMkTemp(const GuestProcessStreamBlock &strmBlk)
return vrc;
}
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT */
+
/**
* Returns the IPRT-compatible file mode.
* Note: Only handling RTFS_TYPE_ flags are implemented for now.
@@ -336,15 +509,16 @@ RTFMODE GuestFsObjData::GetFileMode(void) const
///////////////////////////////////////////////////////////////////////////////
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT
/** @todo *NOT* thread safe yet! */
/** @todo Add exception handling for STL stuff! */
-GuestProcessStreamBlock::GuestProcessStreamBlock(void)
+GuestToolboxStreamBlock::GuestToolboxStreamBlock(void)
{
}
-GuestProcessStreamBlock::~GuestProcessStreamBlock()
+GuestToolboxStreamBlock::~GuestToolboxStreamBlock()
{
Clear();
}
@@ -352,7 +526,7 @@ GuestProcessStreamBlock::~GuestProcessStreamBlock()
/**
* Clears (destroys) the currently stored stream pairs.
*/
-void GuestProcessStreamBlock::Clear(void)
+void GuestToolboxStreamBlock::Clear(void)
{
mPairs.clear();
}
@@ -361,7 +535,7 @@ void GuestProcessStreamBlock::Clear(void)
/**
* Dumps the currently stored stream pairs to the (debug) log.
*/
-void GuestProcessStreamBlock::DumpToLog(void) const
+void GuestToolboxStreamBlock::DumpToLog(void) const
{
LogFlowFunc(("Dumping contents of stream block=0x%p (%ld items):\n",
this, mPairs.size()));
@@ -381,7 +555,7 @@ void GuestProcessStreamBlock::DumpToLog(void) const
* @param pszKey Name of key to get the value for.
* @param piVal Pointer to value to return.
*/
-int GuestProcessStreamBlock::GetInt64Ex(const char *pszKey, int64_t *piVal) const
+int GuestToolboxStreamBlock::GetInt64Ex(const char *pszKey, int64_t *piVal) const
{
AssertPtrReturn(pszKey, VERR_INVALID_POINTER);
AssertPtrReturn(piVal, VERR_INVALID_POINTER);
@@ -400,7 +574,7 @@ int GuestProcessStreamBlock::GetInt64Ex(const char *pszKey, int64_t *piVal) cons
* @return int64_t Value to return, 0 if not found / on failure.
* @param pszKey Name of key to get the value for.
*/
-int64_t GuestProcessStreamBlock::GetInt64(const char *pszKey) const
+int64_t GuestToolboxStreamBlock::GetInt64(const char *pszKey) const
{
int64_t iVal;
if (RT_SUCCESS(GetInt64Ex(pszKey, &iVal)))
@@ -413,7 +587,7 @@ int64_t GuestProcessStreamBlock::GetInt64(const char *pszKey) const
*
* @return uint32_t Current number of stream pairs.
*/
-size_t GuestProcessStreamBlock::GetCount(void) const
+size_t GuestToolboxStreamBlock::GetCount(void) const
{
return mPairs.size();
}
@@ -424,7 +598,7 @@ size_t GuestProcessStreamBlock::GetCount(void) const
* @return VBox status code.
* @retval VERR_NOT_FOUND if the return code string ("rc") was not found.
*/
-int GuestProcessStreamBlock::GetVrc(void) const
+int GuestToolboxStreamBlock::GetVrc(void) const
{
const char *pszValue = GetString("rc");
if (pszValue)
@@ -439,7 +613,7 @@ int GuestProcessStreamBlock::GetVrc(void) const
* @return uint32_t Pointer to string to return, NULL if not found / on failure.
* @param pszKey Name of key to get the value for.
*/
-const char *GuestProcessStreamBlock::GetString(const char *pszKey) const
+const char *GuestToolboxStreamBlock::GetString(const char *pszKey) const
{
AssertPtrReturn(pszKey, NULL);
@@ -463,7 +637,7 @@ const char *GuestProcessStreamBlock::GetString(const char *pszKey) const
* @param pszKey Name of key to get the value for.
* @param puVal Pointer to value to return.
*/
-int GuestProcessStreamBlock::GetUInt32Ex(const char *pszKey, uint32_t *puVal) const
+int GuestToolboxStreamBlock::GetUInt32Ex(const char *pszKey, uint32_t *puVal) const
{
const char *pszValue = GetString(pszKey);
if (pszValue)
@@ -481,7 +655,7 @@ int GuestProcessStreamBlock::GetUInt32Ex(const char *pszKey, uint32_t *puVal) co
* @param pszKey Name of key to get the value for.
* @param iDefault The default to return on error if not found.
*/
-int32_t GuestProcessStreamBlock::GetInt32(const char *pszKey, int32_t iDefault) const
+int32_t GuestToolboxStreamBlock::GetInt32(const char *pszKey, int32_t iDefault) const
{
const char *pszValue = GetString(pszKey);
if (pszValue)
@@ -502,7 +676,7 @@ int32_t GuestProcessStreamBlock::GetInt32(const char *pszKey, int32_t iDefault)
* @param pszKey Name of key to get the value for.
* @param uDefault The default value to return.
*/
-uint32_t GuestProcessStreamBlock::GetUInt32(const char *pszKey, uint32_t uDefault /*= 0*/) const
+uint32_t GuestToolboxStreamBlock::GetUInt32(const char *pszKey, uint32_t uDefault /*= 0*/) const
{
uint32_t uVal;
if (RT_SUCCESS(GetUInt32Ex(pszKey, &uVal)))
@@ -517,7 +691,7 @@ uint32_t GuestProcessStreamBlock::GetUInt32(const char *pszKey, uint32_t uDefaul
* @param pszKey Key name to process.
* @param pszValue Value to set. Set NULL for deleting the key.
*/
-int GuestProcessStreamBlock::SetValue(const char *pszKey, const char *pszValue)
+int GuestToolboxStreamBlock::SetValue(const char *pszKey, const char *pszValue)
{
AssertPtrReturn(pszKey, VERR_INVALID_POINTER);
@@ -537,7 +711,7 @@ int GuestProcessStreamBlock::SetValue(const char *pszKey, const char *pszValue)
if (pszValue)
{
- GuestProcessStreamValue val(pszValue);
+ GuestToolboxStreamValue val(pszValue);
mPairs[strKey] = val;
}
}
@@ -550,14 +724,14 @@ int GuestProcessStreamBlock::SetValue(const char *pszKey, const char *pszValue)
///////////////////////////////////////////////////////////////////////////////
-GuestProcessStream::GuestProcessStream(void)
+GuestToolboxStream::GuestToolboxStream(void)
: m_cbMax(_32M)
, m_cbAllocated(0)
, m_cbUsed(0)
, m_offBuffer(0)
, m_pbBuffer(NULL) { }
-GuestProcessStream::~GuestProcessStream(void)
+GuestToolboxStream::~GuestToolboxStream(void)
{
Destroy();
}
@@ -570,7 +744,7 @@ GuestProcessStream::~GuestProcessStream(void)
* @param pbData Pointer to data to add.
* @param cbData Size (in bytes) of data to add.
*/
-int GuestProcessStream::AddData(const BYTE *pbData, size_t cbData)
+int GuestToolboxStream::AddData(const BYTE *pbData, size_t cbData)
{
AssertPtrReturn(pbData, VERR_INVALID_POINTER);
AssertReturn(cbData, VERR_INVALID_PARAMETER);
@@ -641,7 +815,7 @@ int GuestProcessStream::AddData(const BYTE *pbData, size_t cbData)
/**
* Destroys the internal data buffer.
*/
-void GuestProcessStream::Destroy(void)
+void GuestToolboxStream::Destroy(void)
{
if (m_pbBuffer)
{
@@ -661,7 +835,7 @@ void GuestProcessStream::Destroy(void)
*
* @param pszFile Absolute path to host file to dump the output to.
*/
-void GuestProcessStream::Dump(const char *pszFile)
+void GuestToolboxStream::Dump(const char *pszFile)
{
LogFlowFunc(("Dumping contents of stream=0x%p (cbAlloc=%u, cbSize=%u, cbOff=%u) to %s\n",
m_pbBuffer, m_cbAllocated, m_cbUsed, m_offBuffer, pszFile));
@@ -693,7 +867,7 @@ void GuestProcessStream::Dump(const char *pszFile)
* @return VBox status code.
* @param streamBlock Reference to guest stream block to fill.
*/
-int GuestProcessStream::ParseBlock(GuestProcessStreamBlock &streamBlock)
+int GuestToolboxStream::ParseBlock(GuestToolboxStreamBlock &streamBlock)
{
if ( !m_pbBuffer
|| !m_cbUsed)
@@ -748,6 +922,7 @@ int GuestProcessStream::ParseBlock(GuestProcessStreamBlock &streamBlock)
return vrc;
}
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT */
GuestBase::GuestBase(void)
: mConsole(NULL)
@@ -1351,12 +1526,14 @@ int GuestBase::waitForEvent(GuestWaitEvent *pWaitEvt, uint32_t msTimeout, VBoxEv
Utf8Str strErr;
-#define CASE_TOOL_ERROR(a_eType, a_strTool) \
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT
+# define CASE_TOOL_ERROR(a_eType, a_strTool) \
case a_eType: \
{ \
- strErr = GuestProcessTool::guestErrorToString(a_strTool, guestErrorInfo); \
+ strErr = GuestProcessToolbox::guestErrorToString(a_strTool, guestErrorInfo); \
break; \
}
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT */
switch (guestErrorInfo.getType())
{
@@ -1376,13 +1553,17 @@ int GuestBase::waitForEvent(GuestWaitEvent *pWaitEvt, uint32_t msTimeout, VBoxEv
strErr = GuestDirectory::i_guestErrorToString(guestErrorInfo.getVrc(), guestErrorInfo.getWhat().c_str());
break;
- CASE_TOOL_ERROR(GuestErrorInfo::Type_ToolCat, VBOXSERVICE_TOOL_CAT);
+ case GuestErrorInfo::Type_Fs:
+ strErr = GuestFs::guestErrorToString(guestErrorInfo);
+ break;
+
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT
CASE_TOOL_ERROR(GuestErrorInfo::Type_ToolLs, VBOXSERVICE_TOOL_LS);
CASE_TOOL_ERROR(GuestErrorInfo::Type_ToolMkDir, VBOXSERVICE_TOOL_MKDIR);
CASE_TOOL_ERROR(GuestErrorInfo::Type_ToolMkTemp, VBOXSERVICE_TOOL_MKTEMP);
CASE_TOOL_ERROR(GuestErrorInfo::Type_ToolRm, VBOXSERVICE_TOOL_RM);
CASE_TOOL_ERROR(GuestErrorInfo::Type_ToolStat, VBOXSERVICE_TOOL_STAT);
-
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT */
default:
AssertMsgFailed(("Type not implemented (type=%RU32, vrc=%Rrc)\n", guestErrorInfo.getType(), guestErrorInfo.getVrc()));
strErr = Utf8StrFmt("Unknown / Not implemented -- Please file a bug report (type=%RU32, vrc=%Rrc)\n",
@@ -1404,9 +1585,14 @@ int GuestBase::waitForEvent(GuestWaitEvent *pWaitEvt, uint32_t msTimeout, VBoxEv
/* static */
FsObjType_T GuestBase::fileModeToFsObjType(RTFMODE fMode)
{
- if (RTFS_IS_FILE(fMode)) return FsObjType_File;
+ if (RTFS_IS_FIFO(fMode)) return FsObjType_Fifo;
+ else if (RTFS_IS_DEV_CHAR(fMode)) return FsObjType_DevChar;
else if (RTFS_IS_DIRECTORY(fMode)) return FsObjType_Directory;
+ else if (RTFS_IS_DEV_BLOCK(fMode)) return FsObjType_DevBlock;
+ else if (RTFS_IS_FILE(fMode)) return FsObjType_File;
else if (RTFS_IS_SYMLINK(fMode)) return FsObjType_Symlink;
+ else if (RTFS_IS_SOCKET(fMode)) return FsObjType_Socket;
+ else if (RTFS_IS_WHITEOUT(fMode)) return FsObjType_WhiteOut;
return FsObjType_Unknown;
}
diff --git a/src/VBox/Main/src-client/GuestDirectoryImpl.cpp b/src/VBox/Main/src-client/GuestDirectoryImpl.cpp
index 5f20dfd0e1d..e3fd5e8b15b 100644
--- a/src/VBox/Main/src-client/GuestDirectoryImpl.cpp
+++ b/src/VBox/Main/src-client/GuestDirectoryImpl.cpp
@@ -35,14 +35,18 @@
#ifndef VBOX_WITH_GUEST_CONTROL
# error "VBOX_WITH_GUEST_CONTROL must defined in this file"
#endif
+#include "GuestImpl.h"
#include "GuestDirectoryImpl.h"
#include "GuestSessionImpl.h"
#include "GuestCtrlImplPrivate.h"
+#include "VirtualBoxErrorInfoImpl.h"
#include "Global.h"
#include "AutoCaller.h"
+#include "VBoxEvents.h"
#include <VBox/com/array.h>
+#include <VBox/AssertGuest.h>
// constructor / destructor
@@ -69,8 +73,8 @@ void GuestDirectory::FinalRelease(void)
int GuestDirectory::init(Console *pConsole, GuestSession *pSession, ULONG aObjectID, const GuestDirectoryOpenInfo &openInfo)
{
- LogFlowThisFunc(("pConsole=%p, pSession=%p, aObjectID=%RU32, strPath=%s, strFilter=%s, uFlags=%x\n",
- pConsole, pSession, aObjectID, openInfo.mPath.c_str(), openInfo.mFilter.c_str(), openInfo.mFlags));
+ LogFlowThisFunc(("pConsole=%p, pSession=%p, aObjectID=%RU32, strPath=%s, enmFilter=%#x, fFlags=%x\n",
+ pConsole, pSession, aObjectID, openInfo.mPath.c_str(), openInfo.menmFilter, openInfo.mFlags));
AssertPtrReturn(pConsole, VERR_INVALID_POINTER);
AssertPtrReturn(pSession, VERR_INVALID_POINTER);
@@ -85,55 +89,14 @@ int GuestDirectory::init(Console *pConsole, GuestSession *pSession, ULONG aObjec
mSession = pSession;
mObjectID = aObjectID;
- mData.mOpenInfo = openInfo;
- }
-
- if (RT_SUCCESS(vrc))
- {
- /* Start the directory process on the guest. */
- GuestProcessStartupInfo procInfo;
- procInfo.mName.printf(tr("Opening directory \"%s\""), openInfo.mPath.c_str());
- procInfo.mTimeoutMS = 5 * 60 * 1000; /* 5 minutes timeout. */
- procInfo.mFlags = ProcessCreateFlag_WaitForStdOut;
- procInfo.mExecutable= Utf8Str(VBOXSERVICE_TOOL_LS);
-
- procInfo.mArguments.push_back(procInfo.mExecutable);
- procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
- /* We want the long output format which contains all the object details. */
- procInfo.mArguments.push_back(Utf8Str("-l"));
-#if 0 /* Flags are not supported yet. */
- if (uFlags & DirectoryOpenFlag_NoSymlinks)
- procInfo.mArguments.push_back(Utf8Str("--nosymlinks")); /** @todo What does GNU here? */
-#endif
- /** @todo Recursion support? */
- procInfo.mArguments.push_back(openInfo.mPath); /* The directory we want to open. */
+ mData.mOpenInfo = openInfo;
+ mData.mStatus = DirectoryStatus_Undefined;
+ mData.mLastError = VINF_SUCCESS;
- /*
- * Start the process synchronously and keep it around so that we can use
- * it later in subsequent read() calls.
- */
- vrc = mData.mProcessTool.init(mSession, procInfo, false /*fAsync*/, NULL /*pvrcGuest*/);
- if (RT_SUCCESS(vrc))
- {
- /* As we need to know if the directory we were about to open exists and and is accessible,
- * do the first read here in order to return a meaningful status here. */
- int vrcGuest = VERR_IPE_UNINITIALIZED_STATUS;
- vrc = i_readInternal(mData.mObjData, &vrcGuest);
- if (RT_FAILURE(vrc))
- {
- /*
- * We need to actively terminate our process tool in case of an error here,
- * as this otherwise would be done on (directory) object destruction implicitly.
- * This in turn then will run into a timeout, as the directory object won't be
- * around anymore at that time. Ugly, but that's how it is for the moment.
- */
- int vrcTerm = mData.mProcessTool.terminate(30 * RT_MS_1SEC, NULL /* prcGuest */);
- AssertRC(vrcTerm);
-
- if (vrc == VERR_GSTCTL_GUEST_ERROR)
- vrc = vrcGuest;
- }
- }
+ unconst(mEventSource).createObject();
+ HRESULT hr = mEventSource->init();
+ if (FAILED(hr))
+ vrc = VERR_COM_UNEXPECTED;
}
/* Confirm a successful initialization when it's the case. */
@@ -176,6 +139,14 @@ HRESULT GuestDirectory::getDirectoryName(com::Utf8Str &aDirectoryName)
return S_OK;
}
+HRESULT GuestDirectory::getEventSource(ComPtr<IEventSource> &aEventSource)
+{
+ /* No need to lock - lifetime constant. */
+ mEventSource.queryInterfaceTo(aEventSource.asOutParam());
+
+ return S_OK;
+}
+
HRESULT GuestDirectory::getFilter(com::Utf8Str &aFilter)
{
LogFlowThisFuncEnter();
@@ -187,6 +158,26 @@ HRESULT GuestDirectory::getFilter(com::Utf8Str &aFilter)
return S_OK;
}
+HRESULT GuestDirectory::getId(ULONG *aId)
+{
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ *aId = mObjectID;
+
+ return S_OK;
+}
+
+HRESULT GuestDirectory::getStatus(DirectoryStatus_T *aStatus)
+{
+ LogFlowThisFuncEnter();
+
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ *aStatus = mData.mStatus;
+
+ return S_OK;
+}
+
// private methods
/////////////////////////////////////////////////////////////////////////////
@@ -208,35 +199,288 @@ int GuestDirectory::i_callbackDispatcher(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGU
int vrc;
switch (pCbCtx->uMessage)
{
+ case GUEST_MSG_DISCONNECTED:
+ /** @todo vrc = i_onGuestDisconnected(pCbCtx, pSvcCb); */
+ vrc = VINF_SUCCESS; // TODO
+ break;
+
case GUEST_MSG_DIR_NOTIFY:
{
- int idx = 1; /* Current parameter index. */
- CALLBACKDATA_DIR_NOTIFY dataCb;
- /* pSvcCb->mpaParms[0] always contains the context ID. */
- HGCMSvcGetU32(&pSvcCb->mpaParms[idx++], &dataCb.uType);
- HGCMSvcGetU32(&pSvcCb->mpaParms[idx++], &dataCb.rc);
+ vrc = i_onDirNotify(pCbCtx, pSvcCb);
+ break;
+ }
- LogFlowFunc(("uType=%RU32, vrcGguest=%Rrc\n", dataCb.uType, (int)dataCb.rc));
+ default:
+ /* Silently ignore not implemented functions. */
+ vrc = VERR_NOT_SUPPORTED;
+ break;
+ }
- switch (dataCb.uType)
- {
- /* Nothing here yet, nothing to dispatch further. */
+ LogFlowFuncLeaveRC(vrc);
+ return vrc;
+}
- default:
- vrc = VERR_NOT_SUPPORTED;
- break;
+/**
+ * Opens the directory on the guest side.
+ *
+ * @return VBox status code.
+ * @param pvrcGuest Where to store the guest result code in case VERR_GSTCTL_GUEST_ERROR is returned.
+ */
+int GuestDirectory::i_open(int *pvrcGuest)
+{
+ int vrc;
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+ if ((mSession->i_getParent()->i_getGuestControlFeatures0() & VBOX_GUESTCTRL_GF_0_TOOLBOX_AS_CMDS))
+ {
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ GuestWaitEvent *pEvent = NULL;
+ GuestEventTypes eventTypes;
+ try
+ {
+ eventTypes.push_back(VBoxEventType_OnGuestDirectoryStateChanged);
+
+ vrc = registerWaitEvent(eventTypes, &pEvent);
+ }
+ catch (std::bad_alloc &)
+ {
+ vrc = VERR_NO_MEMORY;
+ }
+
+ /* Prepare HGCM call. */
+ VBOXHGCMSVCPARM paParms[8];
+ int i = 0;
+ HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
+ HGCMSvcSetPv(&paParms[i++], (void *)mData.mOpenInfo.mPath.c_str(), (ULONG)mData.mOpenInfo.mPath.length() + 1);
+ HGCMSvcSetPv(&paParms[i++], (void *)mData.mOpenInfo.mFilter.c_str(), (ULONG)mData.mOpenInfo.mFilter.length() + 1);
+ HGCMSvcSetU32(&paParms[i++], mData.mOpenInfo.menmFilter);
+ HGCMSvcSetU32(&paParms[i++], mData.mOpenInfo.mFlags);
+
+ alock.release(); /* Drop lock before sending. */
+
+ vrc = sendMessage(HOST_MSG_DIR_OPEN, i, paParms);
+ if (RT_SUCCESS(vrc))
+ {
+ vrc = pEvent->Wait(30 * 1000);
+ if (RT_SUCCESS(vrc))
+ {
}
+ }
+ }
+ else
+ {
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT
+ vrc = i_openViaToolbox(pvrcGuest);
+#else
+ RT_NOREF(pvrcGuest);
+ vrc = VERR_NOT_SUPPORTED;
+#endif
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+ }
+#endif
+
+ return vrc;
+}
+
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT
+/**
+ * Opens the directory on the guest side (legacy version).
+ *
+ * @returns VBox status code.
+ * @param pvrcGuest Where to store the guest result code in case VERR_GSTCTL_GUEST_ERROR is returned.
+ *
+ * @note This uses an own guest process via the built-in toolbox in VBoxSerivce.
+ */
+int GuestDirectory::i_openViaToolbox(int *pvrcGuest)
+{
+ /* Start the directory process on the guest. */
+ GuestProcessStartupInfo procInfo;
+ procInfo.mName.printf(tr("Opening directory \"%s\""), mData.mOpenInfo.mPath.c_str());
+ procInfo.mTimeoutMS = 5 * 60 * 1000; /* 5 minutes timeout. */
+ procInfo.mFlags = ProcessCreateFlag_WaitForStdOut;
+ procInfo.mExecutable= Utf8Str(VBOXSERVICE_TOOL_LS);
+
+ procInfo.mArguments.push_back(procInfo.mExecutable);
+ procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
+ /* We want the long output format which contains all the object details. */
+ procInfo.mArguments.push_back(Utf8Str("-l"));
+# if 0 /* Flags are not supported yet. */
+ if (uFlags & DirectoryOpenFlag_NoSymlinks)
+ procInfo.mArguments.push_back(Utf8Str("--nosymlinks")); /** @todo What does GNU here? */
+# endif
+ /** @todo Recursion support? */
+ procInfo.mArguments.push_back(mData.mOpenInfo.mPath); /* The directory we want to open. */
+
+ /*
+ * Start the process synchronously and keep it around so that we can use
+ * it later in subsequent read() calls.
+ */
+ int vrc = mData.mProcessTool.init(mSession, procInfo, false /*fAsync*/, NULL /*pvrcGuest*/);
+ if (RT_SUCCESS(vrc))
+ {
+ /* As we need to know if the directory we were about to open exists and and is accessible,
+ * do the first read here in order to return a meaningful status here. */
+ int vrcGuest = VERR_IPE_UNINITIALIZED_STATUS;
+ vrc = i_readInternal(mData.mObjData, &vrcGuest);
+ if (RT_FAILURE(vrc))
+ {
+ /*
+ * We need to actively terminate our process tool in case of an error here,
+ * as this otherwise would be done on (directory) object destruction implicitly.
+ * This in turn then will run into a timeout, as the directory object won't be
+ * around anymore at that time. Ugly, but that's how it is for the moment.
+ */
+ /* ignore rc */ mData.mProcessTool.terminate(30 * RT_MS_1SEC, NULL /* pvrcGuest */);
+ }
+
+ if (pvrcGuest)
+ *pvrcGuest = vrcGuest;
+ }
+
+ return vrc;
+}
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT */
+
+/**
+ * Called when the guest side notifies the host of a directory event.
+ *
+ * @returns VBox status code.
+ * @param pCbCtx Host callback context.
+ * @param pSvcCbData Host callback data.
+ */
+int GuestDirectory::i_onDirNotify(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCbData)
+{
+#ifndef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+ RT_NOREF(pCbCtx, pSvcCbData);
+ return VERR_NOT_SUPPORTED;
+#else
+ AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
+ AssertPtrReturn(pSvcCbData, VERR_INVALID_POINTER);
+
+ LogFlowThisFuncEnter();
+
+ if (pSvcCbData->mParms < 3)
+ return VERR_INVALID_PARAMETER;
+
+ int idx = 1; /* Current parameter index. */
+ CALLBACKDATA_DIR_NOTIFY dataCb;
+ RT_ZERO(dataCb);
+ /* pSvcCb->mpaParms[0] always contains the context ID. */
+ HGCMSvcGetU32(&pSvcCbData->mpaParms[idx++], &dataCb.uType);
+ HGCMSvcGetU32(&pSvcCbData->mpaParms[idx++], &dataCb.rc);
+
+ int vrcGuest = (int)dataCb.rc; /* uint32_t vs. int. */
+
+ LogFlowThisFunc(("uType=%RU32, vrcGuest=%Rrc\n", dataCb.uType, vrcGuest));
+
+ if (RT_FAILURE(vrcGuest))
+ {
+ /** @todo Set status? */
+
+ /* Ignore return code, as the event to signal might not be there (anymore). */
+ signalWaitEventInternal(pCbCtx, vrcGuest, NULL /* pPayload */);
+ return VINF_SUCCESS; /* Report to the guest. */
+ }
+
+ int vrc = VERR_NOT_SUPPORTED; /* Play safe by default. */
+
+ ComObjPtr<VirtualBoxErrorInfo> errorInfo;
+ HRESULT hrc = errorInfo.createObject();
+ ComAssertComRCRet(hrc, VERR_COM_UNEXPECTED);
+ if (RT_FAILURE(vrcGuest))
+ {
+ hrc = errorInfo->initEx(VBOX_E_GSTCTL_GUEST_ERROR, vrcGuest,
+ COM_IIDOF(IGuestFile), getComponentName(),
+ i_guestErrorToString(vrcGuest, mData.mOpenInfo.mPath.c_str()));
+ ComAssertComRCRet(hrc, VERR_COM_UNEXPECTED);
+ }
+
+ switch (dataCb.uType)
+ {
+ case GUEST_DIR_NOTIFYTYPE_ERROR:
+ {
+ vrc = i_setStatus(DirectoryStatus_Error, vrcGuest);
+ break;
+ }
+
+ case GUEST_DIR_NOTIFYTYPE_OPEN:
+ {
+ vrc = i_setStatus(DirectoryStatus_Open, vrcGuest);
+ break;
+ }
+
+ case GUEST_DIR_NOTIFYTYPE_CLOSE:
+ {
+ vrc = i_setStatus(DirectoryStatus_Close, vrcGuest);
+ break;
+ }
+
+ case GUEST_DIR_NOTIFYTYPE_READ:
+ {
+ ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mParms == 7, ("mParms=%u\n", pSvcCbData->mParms),
+ vrc = VERR_WRONG_PARAMETER_COUNT);
+ ASSERT_GUEST_MSG_STMT_BREAK(pSvcCbData->mpaParms[idx].type == VBOX_HGCM_SVC_PARM_PTR,
+ ("type=%u\n", pSvcCbData->mpaParms[idx].type),
+ vrc = VERR_WRONG_PARAMETER_TYPE);
+
+ PGSTCTLFSOBJINFO pObjInfo;
+ uint32_t cbObjInfo;
+ vrc = HGCMSvcGetPv(&pSvcCbData->mpaParms[idx++], (void **)&pObjInfo, &cbObjInfo);
+ AssertRCBreak(vrc);
+ AssertBreakStmt(cbObjInfo == sizeof(GSTCTLFSOBJINFO), VERR_INVALID_PARAMETER);
+
+ GuestFsObjData fsObjData(mData.mOpenInfo.mPath);
+ vrc = fsObjData.FromGuestFsObjInfo(pObjInfo);
+ AssertRCBreak(vrc);
+ ComObjPtr<GuestFsObjInfo> ptrFsObjInfo;
+ hrc = ptrFsObjInfo.createObject();
+ ComAssertComRCBreak(hrc, VERR_COM_UNEXPECTED);
+ vrc = ptrFsObjInfo->init(fsObjData);
+ AssertRCBreak(vrc);
+
+ ::FireGuestDirectoryReadEvent(mEventSource, mSession, this, ptrFsObjInfo);
+ break;
+ }
+
+ case GUEST_DIR_NOTIFYTYPE_REWIND:
+ {
+ /* Note: This does not change the overall status of the directory (i.e. open). */
+ ::FireGuestDirectoryStateChangedEvent(mEventSource, mSession, this, DirectoryStatus_Rewind, errorInfo);
break;
}
default:
- /* Silently ignore not implemented functions. */
- vrc = VERR_NOT_SUPPORTED;
+ AssertFailed();
break;
}
- LogFlowFuncLeaveRC(vrc);
+ try
+ {
+ if (RT_SUCCESS(vrc))
+ {
+ GuestWaitEventPayload payload(dataCb.uType, &dataCb, sizeof(dataCb));
+
+ /* Ignore return code, as the event to signal might not be there (anymore). */
+ signalWaitEventInternal(pCbCtx, vrcGuest, &payload);
+ }
+ else /* OOM situation, wrong HGCM parameters or smth. not expected. */
+ {
+ /* Ignore return code, as the event to signal might not be there (anymore). */
+ signalWaitEventInternalEx(pCbCtx, vrc, 0 /* guestRc */, NULL /* pPayload */);
+ }
+ }
+ catch (int vrcEx) /* Thrown by GuestWaitEventPayload constructor. */
+ {
+ /* Also try to signal the waiter, to let it know of the OOM situation.
+ * Ignore return code, as the event to signal might not be there (anymore). */
+ signalWaitEventInternalEx(pCbCtx, vrcEx, 0 /* guestRc */, NULL /* pPayload */);
+ vrc = vrcEx;
+ }
+
+ LogFlowThisFunc(("uType=%RU32, rcGuest=%Rrc, vrc=%Rrc\n", dataCb.uType, vrcGuest, vrc));
return vrc;
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
}
/**
@@ -301,15 +545,29 @@ int GuestDirectory::i_onSessionStatusChange(GuestSessionStatus_T enmSessionStatu
* guest session's directory list.
*
* @return VBox status code.
- * @param prcGuest Where to store the guest result code in case VERR_GSTCTL_GUEST_ERROR is returned.
+ * @param pvrcGuest Where to store the guest result code in case VERR_GSTCTL_GUEST_ERROR is returned.
*/
-int GuestDirectory::i_closeInternal(int *prcGuest)
+int GuestDirectory::i_close(int *pvrcGuest)
{
- AssertPtrReturn(prcGuest, VERR_INVALID_POINTER);
-
- int vrc = mData.mProcessTool.terminate(30 * 1000 /* 30s timeout */, prcGuest);
- if (RT_FAILURE(vrc))
- return vrc;
+ int vrc;
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+ if (mSession->i_getParent()->i_getGuestControlFeatures0() & VBOX_GUESTCTRL_GF_0_TOOLBOX_AS_CMDS)
+ {
+ // TODO
+ vrc = VERR_NOT_IMPLEMENTED;
+ }
+ else
+ {
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
+#ifndef VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT
+ RT_NOREF(pvrcGuest);
+ vrc = VINF_SUCCESS; /* Nothing to do here. */
+#else
+ vrc = i_closeViaToolbox(pvrcGuest);
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT */
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+ }
+#endif
AssertPtr(mSession);
int vrc2 = mSession->i_directoryUnregister(this);
@@ -320,19 +578,71 @@ int GuestDirectory::i_closeInternal(int *prcGuest)
return vrc;
}
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT
+/**
+ * Closes this guest directory and removes it from the guest session's directory list (legacy version).
+ *
+ * @return VBox status code.
+ * @param pvrcGuest Where to store the guest result code in case VERR_GSTCTL_GUEST_ERROR is returned.
+ *
+ * @note This uses an own guest process via the built-in toolbox in VBoxSerivce.
+ */
+int GuestDirectory::i_closeViaToolbox(int *pvrcGuest)
+{
+ return mData.mProcessTool.terminate(30 * 1000 /* 30s timeout */, pvrcGuest);
+}
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT */
+
/**
* Reads the next directory entry, internal version.
*
* @return VBox status code. Will return VERR_NO_MORE_FILES if no more entries are available.
* @param objData Where to store the read directory entry as internal object data.
- * @param prcGuest Where to store the guest result code in case VERR_GSTCTL_GUEST_ERROR is returned.
+ * @param pvrcGuest Where to store the guest result code in case VERR_GSTCTL_GUEST_ERROR is returned.
*/
-int GuestDirectory::i_readInternal(GuestFsObjData &objData, int *prcGuest)
+int GuestDirectory::i_readInternal(GuestFsObjData &objData, int *pvrcGuest)
{
- AssertPtrReturn(prcGuest, VERR_INVALID_POINTER);
+ AssertPtrReturn(pvrcGuest, VERR_INVALID_POINTER);
+
+ int vrc;
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+ if (mSession->i_getParent()->i_getGuestControlFeatures0() & VBOX_GUESTCTRL_GF_0_TOOLBOX_AS_CMDS)
+ {
+ // TODO
+ RT_NOREF(objData, pvrcGuest);
+ vrc = 0;
+ }
+ else
+ {
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
+#ifndef VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT
+ RT_NOREF(objData);
+ vrc = VERR_NOT_SUPPORTED;
+#else /* VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT */
+ vrc = i_readInternalViaToolbox(objData, pvrcGuest);
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT */
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+ }
+#endif
- GuestProcessStreamBlock curBlock;
- int vrc = mData.mProcessTool.waitEx(GUESTPROCESSTOOL_WAIT_FLAG_STDOUT_BLOCK, &curBlock, prcGuest);
+ LogFlowThisFunc(("Returning vrc=%Rrc\n", vrc));
+ return vrc;
+}
+
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT
+/**
+ * Reads the next directory entry, internal version (legacy version).
+ *
+ * @return VBox status code. Will return VERR_NO_MORE_FILES if no more entries are available.
+ * @param objData Where to store the read directory entry as internal object data.
+ * @param pvrcGuest Where to store the guest result code in case VERR_GSTCTL_GUEST_ERROR is returned.
+ *
+ * @note This uses an own guest process via the built-in toolbox in VBoxSerivce.
+ */
+int GuestDirectory::i_readInternalViaToolbox(GuestFsObjData &objData, int *pvrcGuest)
+{
+ GuestToolboxStreamBlock curBlock;
+ int vrc = mData.mProcessTool.waitEx(GUESTPROCESSTOOL_WAIT_FLAG_STDOUT_BLOCK, &curBlock, pvrcGuest);
if (RT_SUCCESS(vrc))
{
/*
@@ -348,7 +658,7 @@ int GuestDirectory::i_readInternal(GuestFsObjData &objData, int *prcGuest)
{
if (curBlock.GetString("name"))
{
- vrc = objData.FromLs(curBlock, true /* fLong */);
+ vrc = objData.FromToolboxLs(curBlock, true /* fLong */);
}
else
vrc = VERR_PATH_NOT_FOUND;
@@ -361,20 +671,20 @@ int GuestDirectory::i_readInternal(GuestFsObjData &objData, int *prcGuest)
}
}
- LogFlowThisFunc(("Returning vrc=%Rrc\n", vrc));
return vrc;
}
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT */
/**
* Reads the next directory entry.
*
* @return VBox status code. Will return VERR_NO_MORE_FILES if no more entries are available.
* @param fsObjInfo Where to store the read directory entry.
- * @param prcGuest Where to store the guest result code in case VERR_GSTCTL_GUEST_ERROR is returned.
+ * @param pvrcGuest Where to store the guest result code in case VERR_GSTCTL_GUEST_ERROR is returned.
*/
-int GuestDirectory::i_read(ComObjPtr<GuestFsObjInfo> &fsObjInfo, int *prcGuest)
+int GuestDirectory::i_read(ComObjPtr<GuestFsObjInfo> &fsObjInfo, int *pvrcGuest)
{
- AssertPtrReturn(prcGuest, VERR_INVALID_POINTER);
+ AssertPtrReturn(pvrcGuest, VERR_INVALID_POINTER);
/* Create the FS info object. */
HRESULT hr = fsObjInfo.createObject();
@@ -392,11 +702,11 @@ int GuestDirectory::i_read(ComObjPtr<GuestFsObjInfo> &fsObjInfo, int *prcGuest)
mData.mObjData.mName = ""; /* Mark the object data as being empty (beacon). */
}
}
- else /* Otherwise ask the guest for the next object data (block). */
+ else /* Otherwise ask the guest for the next object data. */
{
GuestFsObjData objData;
- vrc = i_readInternal(objData, prcGuest);
+ vrc = i_readInternal(objData, pvrcGuest);
if (RT_SUCCESS(vrc))
vrc = fsObjInfo->init(objData);
}
@@ -405,6 +715,127 @@ int GuestDirectory::i_read(ComObjPtr<GuestFsObjInfo> &fsObjInfo, int *prcGuest)
return vrc;
}
+/**
+ * Rewinds the directory reading.
+ *
+ * @returns VBox status code.
+ * @retval VERR_GSTCTL_GUEST_ERROR when an error from the guest side has been received.
+ * @param uTimeoutMS Timeout (in ms) to wait.
+ * @param pvrcGuest Where to store the guest result code in case VERR_GSTCTL_GUEST_ERROR is returned.
+ */
+int GuestDirectory::i_rewind(uint32_t uTimeoutMS, int *pvrcGuest)
+{
+ RT_NOREF(pvrcGuest);
+#ifndef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+ RT_NOREF(uTimeoutMS, pvrcGuest);
+#else
+ /* Only available for Guest Additions 7.1+. */
+ if (mSession->i_getParent()->i_getGuestControlFeatures0() & VBOX_GUESTCTRL_GF_0_TOOLBOX_AS_CMDS)
+ {
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ int vrc;
+
+ GuestWaitEvent *pEvent = NULL;
+ GuestEventTypes eventTypes;
+ try
+ {
+ eventTypes.push_back(VBoxEventType_OnGuestDirectoryStateChanged);
+ vrc = registerWaitEvent(eventTypes, &pEvent);
+ }
+ catch (std::bad_alloc &)
+ {
+ vrc = VERR_NO_MEMORY;
+ }
+
+ if (RT_FAILURE(vrc))
+ return vrc;
+
+ /* Prepare HGCM call. */
+ VBOXHGCMSVCPARM paParms[4];
+ int i = 0;
+ HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
+ HGCMSvcSetU32(&paParms[i++], mObjectID /* Directory handle */);
+
+ alock.release(); /* Drop lock before sending. */
+
+ vrc = sendMessage(HOST_MSG_DIR_REWIND, i, paParms);
+ if (RT_SUCCESS(vrc))
+ {
+ VBoxEventType_T evtType;
+ ComPtr<IEvent> pIEvent;
+ vrc = waitForEvent(pEvent, uTimeoutMS, &evtType, pIEvent.asOutParam());
+ if (RT_SUCCESS(vrc))
+ {
+ if (evtType == VBoxEventType_OnGuestDirectoryStateChanged)
+ {
+ ComPtr<IGuestDirectoryStateChangedEvent> pEvt = pIEvent;
+ Assert(!pEvt.isNull());
+ }
+ else
+ vrc = VWRN_GSTCTL_OBJECTSTATE_CHANGED;
+ }
+ else if (pEvent->HasGuestError()) /* Return guest vrc if available. */
+ vrc = pEvent->GetGuestError();
+ }
+
+ unregisterWaitEvent(pEvent);
+ return vrc;
+ }
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
+
+ return VERR_NOT_SUPPORTED;
+}
+
+/**
+ * Sets the current internal directory object status.
+ *
+ * @returns VBox status code.
+ * @param enmStatus New directory status to set.
+ * @param vrcDir New result code to set.
+ *
+ * @note Takes the write lock.
+ */
+int GuestDirectory::i_setStatus(DirectoryStatus_T enmStatus, int vrcDir)
+{
+ LogFlowThisFuncEnter();
+
+ AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ LogFlowThisFunc(("oldStatus=%RU32, newStatus=%RU32, vrcDir=%Rrc\n", mData.mStatus, enmStatus, vrcDir));
+
+#ifdef VBOX_STRICT
+ if (enmStatus == DirectoryStatus_Error)
+ AssertMsg(RT_FAILURE(vrcDir), ("Guest vrc must be an error (%Rrc)\n", vrcDir));
+ else
+ AssertMsg(RT_SUCCESS(vrcDir), ("Guest vrc must not be an error (%Rrc)\n", vrcDir));
+#endif
+
+ if (mData.mStatus != enmStatus)
+ {
+ mData.mStatus = enmStatus;
+ mData.mLastError = vrcDir;
+
+ ComObjPtr<VirtualBoxErrorInfo> errorInfo;
+ HRESULT hrc = errorInfo.createObject();
+ ComAssertComRCRet(hrc, VERR_COM_UNEXPECTED);
+ if (RT_FAILURE(vrcDir))
+ {
+ hrc = errorInfo->initEx(VBOX_E_GSTCTL_GUEST_ERROR, vrcDir,
+ COM_IIDOF(IGuestDirectory), getComponentName(),
+ i_guestErrorToString(vrcDir, mData.mOpenInfo.mPath.c_str()));
+ ComAssertComRCRet(hrc, VERR_COM_UNEXPECTED);
+ }
+ /* Note: On vrcDir success, errorInfo is set to S_OK and also sent via the event below. */
+
+ alock.release(); /* Release lock before firing off event. */
+
+ ::FireGuestDirectoryStateChangedEvent(mEventSource, mSession, this, enmStatus, errorInfo);
+ }
+
+ return VINF_SUCCESS;
+}
+
// implementation of public methods
/////////////////////////////////////////////////////////////////////////////
HRESULT GuestDirectory::close()
@@ -417,7 +848,7 @@ HRESULT GuestDirectory::close()
HRESULT hrc = S_OK;
int vrcGuest = VERR_IPE_UNINITIALIZED_STATUS;
- int vrc = i_closeInternal(&vrcGuest);
+ int vrc = i_close(&vrcGuest);
if (RT_FAILURE(vrc))
{
switch (vrc)
@@ -467,16 +898,24 @@ HRESULT GuestDirectory::read(ComPtr<IFsObjInfo> &aObjInfo)
{
case VERR_GSTCTL_GUEST_ERROR:
{
- GuestErrorInfo ge(GuestErrorInfo::Type_ToolLs, vrcGuest, mData.mOpenInfo.mPath.c_str());
+ GuestErrorInfo ge(
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT
+ GuestErrorInfo::Type_ToolLs
+#else
+ GuestErrorInfo::Type_Fs
+#endif
+ , vrcGuest, mData.mOpenInfo.mPath.c_str());
hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrcGuest, tr("Reading guest directory failed: %s"),
GuestBase::getErrorAsString(ge).c_str());
break;
}
+
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT
case VERR_GSTCTL_PROCESS_EXIT_CODE:
hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Reading guest directory \"%s\" failed: %Rrc"),
mData.mOpenInfo.mPath.c_str(), mData.mProcessTool.getRc());
break;
-
+#endif
case VERR_PATH_NOT_FOUND:
hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Reading guest directory \"%s\" failed: Path not found"),
mData.mOpenInfo.mPath.c_str());
@@ -489,7 +928,7 @@ HRESULT GuestDirectory::read(ComPtr<IFsObjInfo> &aObjInfo)
break;
default:
- hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Reading guest directory \"%s\" returned error: %Rrc\n"),
+ hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Reading guest directory \"%s\" returned unhandled error: %Rrc\n"),
mData.mOpenInfo.mPath.c_str(), vrc);
break;
}
@@ -499,3 +938,18 @@ HRESULT GuestDirectory::read(ComPtr<IFsObjInfo> &aObjInfo)
return hrc;
}
+HRESULT GuestDirectory::rewind(void)
+{
+ AutoCaller autoCaller(this);
+ if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
+
+ int vrcGuest = VERR_IPE_UNINITIALIZED_STATUS;
+ int vrc = i_rewind(30 * 1000 /* Timeout in ms */, &vrcGuest);
+ if (RT_SUCCESS(vrc))
+ return S_OK;
+
+ GuestErrorInfo ge(GuestErrorInfo::Type_Directory, vrcGuest, mData.mOpenInfo.mPath.c_str());
+ return setErrorBoth(VBOX_E_IPRT_ERROR, vrcGuest, tr("Rewinding guest directory failed: %s"),
+ GuestBase::getErrorAsString(ge).c_str());
+}
+
diff --git a/src/VBox/Main/src-client/GuestFileImpl.cpp b/src/VBox/Main/src-client/GuestFileImpl.cpp
index dcbbfe88e13..101a0b5ca46 100644
--- a/src/VBox/Main/src-client/GuestFileImpl.cpp
+++ b/src/VBox/Main/src-client/GuestFileImpl.cpp
@@ -899,7 +899,7 @@ int GuestFile::i_openFile(uint32_t uTimeoutMS, int *prcGuest)
*/
int GuestFile::i_queryInfo(GuestFsObjData &objData, int *prcGuest)
{
- AssertPtr(mSession);
+ AssertPtrReturn(mSession, VERR_OBJECT_DESTROYED);
return mSession->i_fsQueryInfo(mData.mOpenInfo.mFilename, FALSE /* fFollowSymlinks */, objData, prcGuest);
}
@@ -1575,7 +1575,13 @@ HRESULT GuestFile::queryInfo(ComPtr<IFsObjInfo> &aObjInfo)
{
if (GuestProcess::i_isGuestError(vrc))
{
- GuestErrorInfo ge(GuestErrorInfo::Type_ToolStat, vrcGuest, mData.mOpenInfo.mFilename.c_str());
+ GuestErrorInfo ge(
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT
+ GuestErrorInfo::Type_ToolStat,
+#else
+ GuestErrorInfo::Type_File,
+#endif
+ vrcGuest, mData.mOpenInfo.mFilename.c_str());
hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrcGuest, tr("Querying guest file information failed: %s"),
GuestBase::getErrorAsString(ge).c_str());
}
@@ -1608,7 +1614,13 @@ HRESULT GuestFile::querySize(LONG64 *aSize)
{
if (GuestProcess::i_isGuestError(vrc))
{
- GuestErrorInfo ge(GuestErrorInfo::Type_ToolStat, vrcGuest, mData.mOpenInfo.mFilename.c_str());
+ GuestErrorInfo ge(
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT
+ GuestErrorInfo::Type_ToolStat,
+#else
+ GuestErrorInfo::Type_File,
+#endif
+ vrcGuest, mData.mOpenInfo.mFilename.c_str());
hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrcGuest, tr("Querying guest file size failed: %s"),
GuestBase::getErrorAsString(ge).c_str());
}
diff --git a/src/VBox/Main/src-client/GuestProcessImpl.cpp b/src/VBox/Main/src-client/GuestProcessImpl.cpp
index bc9a6538c33..829047325b9 100644
--- a/src/VBox/Main/src-client/GuestProcessImpl.cpp
+++ b/src/VBox/Main/src-client/GuestProcessImpl.cpp
@@ -2252,13 +2252,13 @@ HRESULT GuestProcess::writeArray(ULONG aHandle, const std::vector<ProcessInputFl
///////////////////////////////////////////////////////////////////////////////
-GuestProcessTool::GuestProcessTool(void)
+GuestProcessToolbox::GuestProcessToolbox(void)
: pSession(NULL),
pProcess(NULL)
{
}
-GuestProcessTool::~GuestProcessTool(void)
+GuestProcessToolbox::~GuestProcessToolbox(void)
{
uninit();
}
@@ -2273,8 +2273,8 @@ GuestProcessTool::~GuestProcessTool(void)
* @param pvrcGuest Where to return the guest error when
* VERR_GSTCTL_GUEST_ERROR was returned. Optional.
*/
-int GuestProcessTool::init(GuestSession *pGuestSession, const GuestProcessStartupInfo &startupInfo,
- bool fAsync, int *pvrcGuest)
+int GuestProcessToolbox::init(GuestSession *pGuestSession, const GuestProcessStartupInfo &startupInfo,
+ bool fAsync, int *pvrcGuest)
{
LogFlowThisFunc(("pGuestSession=%p, exe=%s, fAsync=%RTbool\n",
pGuestSession, startupInfo.mExecutable.c_str(), fAsync));
@@ -2315,7 +2315,7 @@ int GuestProcessTool::init(GuestSession *pGuestSession, const GuestProcessStartu
/**
* Unitializes a guest process tool by terminating it on the guest.
*/
-void GuestProcessTool::uninit(void)
+void GuestProcessToolbox::uninit(void)
{
/* Make sure the process is terminated and unregistered from the guest session. */
int vrcGuestIgnored;
@@ -2338,9 +2338,9 @@ void GuestProcessTool::uninit(void)
* @param uHandle Guest process file handle to get current block for.
* @param strmBlock Where to return the stream block on success.
*/
-int GuestProcessTool::getCurrentBlock(uint32_t uHandle, GuestProcessStreamBlock &strmBlock)
+int GuestProcessToolbox::getCurrentBlock(uint32_t uHandle, GuestToolboxStreamBlock &strmBlock)
{
- const GuestProcessStream *pStream = NULL;
+ const GuestToolboxStream *pStream = NULL;
if (uHandle == GUEST_PROC_OUT_H_STDOUT)
pStream = &mStdOut;
else if (uHandle == GUEST_PROC_OUT_H_STDERR)
@@ -2369,13 +2369,13 @@ int GuestProcessTool::getCurrentBlock(uint32_t uHandle, GuestProcessStreamBlock
*
* @returns Result code from guest process tool.
*/
-int GuestProcessTool::getRc(void) const
+int GuestProcessToolbox::getRc(void) const
{
LONG exitCode = -1;
HRESULT hrc = pProcess->COMGETTER(ExitCode(&exitCode));
AssertComRC(hrc);
- return GuestProcessTool::exitCodeToRc(mStartupInfo, exitCode);
+ return GuestProcessToolbox::exitCodeToRc(mStartupInfo, exitCode);
}
/**
@@ -2383,7 +2383,7 @@ int GuestProcessTool::getRc(void) const
*
* @returns \c true if running, or \c false if not.
*/
-bool GuestProcessTool::isRunning(void)
+bool GuestProcessToolbox::isRunning(void)
{
AssertReturn(!pProcess.isNull(), false);
@@ -2408,7 +2408,7 @@ bool GuestProcessTool::isRunning(void)
* @return @c true if the tool has been run correctly (exit status 0), or @c false if some error
* occurred (exit status <> 0 or wrong process state).
*/
-bool GuestProcessTool::isTerminatedOk(void)
+bool GuestProcessToolbox::isTerminatedOk(void)
{
return getTerminationStatus() == VINF_SUCCESS ? true : false;
}
@@ -2427,9 +2427,9 @@ bool GuestProcessTool::isTerminatedOk(void)
* VERR_GSTCTL_GUEST_ERROR is returned.
*/
/* static */
-int GuestProcessTool::run( GuestSession *pGuestSession,
- const GuestProcessStartupInfo &startupInfo,
- int *pvrcGuest /* = NULL */)
+int GuestProcessToolbox::run( GuestSession *pGuestSession,
+ const GuestProcessStartupInfo &startupInfo,
+ int *pvrcGuest /* = NULL */)
{
int vrcGuest = VERR_IPE_UNINITIALIZED_STATUS;
@@ -2441,7 +2441,7 @@ int GuestProcessTool::run( GuestSession *pGuestSession,
if (GuestProcess::i_isGuestError(errorInfo.vrcGuest))
{
if (errorInfo.vrcGuest == VERR_GSTCTL_PROCESS_EXIT_CODE) /* Translate exit code to a meaningful error code. */
- vrcGuest = GuestProcessTool::exitCodeToRc(startupInfo, errorInfo.iExitCode);
+ vrcGuest = GuestProcessToolbox::exitCodeToRc(startupInfo, errorInfo.iExitCode);
else /* At least return something. */
vrcGuest = errorInfo.vrcGuest;
@@ -2466,9 +2466,9 @@ int GuestProcessTool::run( GuestSession *pGuestSession,
* @param errorInfo Error information returned for error handling.
*/
/* static */
-int GuestProcessTool::runErrorInfo(GuestSession *pGuestSession,
- GuestProcessStartupInfo const &startupInfo,
- GuestProcessToolErrorInfo &errorInfo)
+int GuestProcessToolbox::runErrorInfo(GuestSession *pGuestSession,
+ GuestProcessStartupInfo const &startupInfo,
+ GuestProcessToolErrorInfo &errorInfo)
{
return runExErrorInfo(pGuestSession, startupInfo, NULL /* paStrmOutObjects */, 0 /* cStrmOutObjects */, errorInfo);
}
@@ -2485,23 +2485,23 @@ int GuestProcessTool::runErrorInfo(GuestSession *pGuestSessio
* @param pvrcGuest Error code returned from the guest side if VERR_GSTCTL_GUEST_ERROR is returned. Optional.
*/
/* static */
-int GuestProcessTool::runEx(GuestSession *pGuestSession,
- GuestProcessStartupInfo const &startupInfo,
- GuestCtrlStreamObjects *paStrmOutObjects,
- uint32_t cStrmOutObjects,
- int *pvrcGuest /* = NULL */)
+int GuestProcessToolbox::runEx(GuestSession *pGuestSession,
+ GuestProcessStartupInfo const &startupInfo,
+ GuestCtrlStreamObjects *paStrmOutObjects,
+ uint32_t cStrmOutObjects,
+ int *pvrcGuest /* = NULL */)
{
int vrcGuest = VERR_IPE_UNINITIALIZED_STATUS;
GuestProcessToolErrorInfo errorInfo = { VERR_IPE_UNINITIALIZED_STATUS, INT32_MAX };
- int vrc = GuestProcessTool::runExErrorInfo(pGuestSession, startupInfo, paStrmOutObjects, cStrmOutObjects, errorInfo);
+ int vrc = GuestProcessToolbox::runExErrorInfo(pGuestSession, startupInfo, paStrmOutObjects, cStrmOutObjects, errorInfo);
if (RT_SUCCESS(vrc))
{
/* Make sure to check the error information we got from the guest tool. */
if (GuestProcess::i_isGuestError(errorInfo.vrcGuest))
{
if (errorInfo.vrcGuest == VERR_GSTCTL_PROCESS_EXIT_CODE) /* Translate exit code to a meaningful error code. */
- vrcGuest = GuestProcessTool::exitCodeToRc(startupInfo, errorInfo.iExitCode);
+ vrcGuest = GuestProcessToolbox::exitCodeToRc(startupInfo, errorInfo.iExitCode);
else /* At least return something. */
vrcGuest = errorInfo.vrcGuest;
@@ -2532,18 +2532,18 @@ int GuestProcessTool::runEx(GuestSession *pGuestSession,
* @param errorInfo Error information returned for error handling.
*/
/* static */
-int GuestProcessTool::runExErrorInfo(GuestSession *pGuestSession,
- GuestProcessStartupInfo const &startupInfo,
- GuestCtrlStreamObjects *paStrmOutObjects,
- uint32_t cStrmOutObjects,
- GuestProcessToolErrorInfo &errorInfo)
+int GuestProcessToolbox::runExErrorInfo(GuestSession *pGuestSession,
+ GuestProcessStartupInfo const &startupInfo,
+ GuestCtrlStreamObjects *paStrmOutObjects,
+ uint32_t cStrmOutObjects,
+ GuestProcessToolErrorInfo &errorInfo)
{
AssertPtrReturn(pGuestSession, VERR_INVALID_POINTER);
/* paStrmOutObjects is optional. */
/** @todo Check if this is a valid toolbox. */
- GuestProcessTool procTool;
+ GuestProcessToolbox procTool;
int vrc = procTool.init(pGuestSession, startupInfo, false /* Async */, &errorInfo.vrcGuest);
if (RT_SUCCESS(vrc))
{
@@ -2551,7 +2551,7 @@ int GuestProcessTool::runExErrorInfo(GuestSession *pGuestSessio
{
try
{
- GuestProcessStreamBlock strmBlk;
+ GuestToolboxStreamBlock strmBlk;
vrc = procTool.waitEx( paStrmOutObjects
? GUESTPROCESSTOOL_WAIT_FLAG_STDOUT_BLOCK
: GUESTPROCESSTOOL_WAIT_FLAG_NONE, &strmBlk, &errorInfo.vrcGuest);
@@ -2589,7 +2589,7 @@ int GuestProcessTool::runExErrorInfo(GuestSession *pGuestSessio
*
* @param piExitCode Exit code of the tool. Optional.
*/
-int GuestProcessTool::getTerminationStatus(int32_t *piExitCode /* = NULL */)
+int GuestProcessToolbox::getTerminationStatus(int32_t *piExitCode /* = NULL */)
{
Assert(!pProcess.isNull());
/* pExitCode is optional. */
@@ -2621,7 +2621,7 @@ int GuestProcessTool::getTerminationStatus(int32_t *piExitCode /* = NULL */)
* @param pvrcGuest Where to return the guest error when
* VERR_GSTCTL_GUEST_ERROR was returned. Optional.
*/
-int GuestProcessTool::wait(uint32_t fToolWaitFlags, int *pvrcGuest)
+int GuestProcessToolbox::wait(uint32_t fToolWaitFlags, int *pvrcGuest)
{
return waitEx(fToolWaitFlags, NULL /* pStrmBlkOut */, pvrcGuest);
}
@@ -2635,7 +2635,7 @@ int GuestProcessTool::wait(uint32_t fToolWaitFlags, int *pvrcGuest)
* @param pvrcGuest Where to return the guest error when
* VERR_GSTCTL_GUEST_ERROR was returned. Optional.
*/
-int GuestProcessTool::waitEx(uint32_t fToolWaitFlags, GuestProcessStreamBlock *pStrmBlkOut, int *pvrcGuest)
+int GuestProcessToolbox::waitEx(uint32_t fToolWaitFlags, GuestToolboxStreamBlock *pStrmBlkOut, int *pvrcGuest)
{
LogFlowThisFunc(("fToolWaitFlags=0x%x, pStreamBlock=%p, pvrcGuest=%p\n", fToolWaitFlags, pStrmBlkOut, pvrcGuest));
@@ -2829,7 +2829,7 @@ int GuestProcessTool::waitEx(uint32_t fToolWaitFlags, GuestProcessStreamBlock *p
* @param pvrcGuest Where to return the guest error when
* VERR_GSTCTL_GUEST_ERROR was returned. Optional.
*/
-int GuestProcessTool::terminate(uint32_t uTimeoutMS, int *pvrcGuest)
+int GuestProcessToolbox::terminate(uint32_t uTimeoutMS, int *pvrcGuest)
{
LogFlowThisFuncEnter();
@@ -2851,7 +2851,7 @@ int GuestProcessTool::terminate(uint32_t uTimeoutMS, int *pvrcGuest)
* @param iExitCode The toolbox tool's exit code to lookup IPRT error for.
*/
/* static */
-int GuestProcessTool::exitCodeToRc(const GuestProcessStartupInfo &startupInfo, int32_t iExitCode)
+int GuestProcessToolbox::exitCodeToRc(const GuestProcessStartupInfo &startupInfo, int32_t iExitCode)
{
if (startupInfo.mArguments.size() == 0)
{
@@ -2870,7 +2870,7 @@ int GuestProcessTool::exitCodeToRc(const GuestProcessStartupInfo &startupInfo, i
* @param iExitCode The toolbox tool's exit code to lookup IPRT error for.
*/
/* static */
-int GuestProcessTool::exitCodeToRc(const char *pszTool, int32_t iExitCode)
+int GuestProcessToolbox::exitCodeToRc(const char *pszTool, int32_t iExitCode)
{
AssertPtrReturn(pszTool, VERR_INVALID_POINTER);
@@ -2952,7 +2952,7 @@ int GuestProcessTool::exitCodeToRc(const char *pszTool, int32_t iExitCode)
* @param guestErrorInfo Guest error info to get stringyfied error for.
*/
/* static */
-Utf8Str GuestProcessTool::guestErrorToString(const char *pszTool, const GuestErrorInfo &guestErrorInfo)
+Utf8Str GuestProcessToolbox::guestErrorToString(const char *pszTool, const GuestErrorInfo &guestErrorInfo)
{
Utf8Str strErr;
diff --git a/src/VBox/Main/src-client/GuestSessionImpl.cpp b/src/VBox/Main/src-client/GuestSessionImpl.cpp
index 93b31712432..bc5e2015c2b 100644
--- a/src/VBox/Main/src-client/GuestSessionImpl.cpp
+++ b/src/VBox/Main/src-client/GuestSessionImpl.cpp
@@ -951,47 +951,90 @@ int GuestSession::i_directoryCreate(const Utf8Str &strPath, uint32_t uMode, uint
int vrc = VINF_SUCCESS;
- GuestProcessStartupInfo procInfo;
- procInfo.mFlags = ProcessCreateFlag_Hidden;
- procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_MKDIR);
-
- try
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+ if (mParent->i_getGuestControlFeatures0() & VBOX_GUESTCTRL_GF_0_TOOLBOX_AS_CMDS)
{
- procInfo.mArguments.push_back(procInfo.mExecutable); /* Set argv0. */
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
- /* Construct arguments. */
- if (uFlags)
+ GuestWaitEvent *pEvent = NULL;
+ vrc = registerWaitEvent(mData.mSession.mID, mData.mObjectID, &pEvent);
+ if (RT_FAILURE(vrc))
+ return vrc;
+
+ uint32_t fFlags = GSTCTL_CREATEDIRECTORY_F_NONE;
+ if (uFlags & DirectoryCreateFlag_Parents)
+ fFlags |= GSTCTL_CREATEDIRECTORY_F_PARENTS;
+ Assert(!(fFlags & ~GSTCTL_CREATEDIRECTORY_F_VALID_MASK));
+
+ /* Prepare HGCM call. */
+ VBOXHGCMSVCPARM paParms[4];
+ int i = 0;
+ HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
+ HGCMSvcSetPv (&paParms[i++], (void*)strPath.c_str(), (ULONG)strPath.length() + 1);
+ HGCMSvcSetU32(&paParms[i++], fFlags);
+ HGCMSvcSetU32(&paParms[i++], uMode);
+
+ alock.release(); /* Drop lock before sending. */
+
+ vrc = i_sendMessage(HOST_MSG_DIR_CREATE, i, paParms);
+ if (RT_SUCCESS(vrc))
{
- if (uFlags & DirectoryCreateFlag_Parents)
- procInfo.mArguments.push_back(Utf8Str("--parents")); /* We also want to create the parent directories. */
- else
- vrc = VERR_INVALID_PARAMETER;
+ vrc = pEvent->Wait(30 * 1000);
+ if (RT_SUCCESS(vrc))
+ {
+ // TODO
+ }
}
+ }
+ else
+ {
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT
+ GuestProcessStartupInfo procInfo;
+ procInfo.mFlags = ProcessCreateFlag_Hidden;
+ procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_MKDIR);
- if ( RT_SUCCESS(vrc)
- && uMode)
+ try
{
- procInfo.mArguments.push_back(Utf8Str("--mode")); /* Set the creation mode. */
+ procInfo.mArguments.push_back(procInfo.mExecutable); /* Set argv0. */
- char szMode[16];
- if (RTStrPrintf(szMode, sizeof(szMode), "%o", uMode))
+ /* Construct arguments. */
+ if (uFlags)
{
- procInfo.mArguments.push_back(Utf8Str(szMode));
+ if (uFlags & DirectoryCreateFlag_Parents)
+ procInfo.mArguments.push_back(Utf8Str("--parents")); /* We also want to create the parent directories. */
+ else
+ vrc = VERR_INVALID_PARAMETER;
}
- else
- vrc = VERR_BUFFER_OVERFLOW;
+
+ if ( RT_SUCCESS(vrc)
+ && uMode)
+ {
+ procInfo.mArguments.push_back(Utf8Str("--mode")); /* Set the creation mode. */
+
+ char szMode[16];
+ if (RTStrPrintf(szMode, sizeof(szMode), "%o", uMode))
+ {
+ procInfo.mArguments.push_back(Utf8Str(szMode));
+ }
+ else
+ vrc = VERR_BUFFER_OVERFLOW;
+ }
+
+ procInfo.mArguments.push_back("--"); /* '--version' is a valid directory name. */
+ procInfo.mArguments.push_back(strPath); /* The directory we want to create. */
+ }
+ catch (std::bad_alloc &)
+ {
+ vrc = VERR_NO_MEMORY;
}
- procInfo.mArguments.push_back("--"); /* '--version' is a valid directory name. */
- procInfo.mArguments.push_back(strPath); /* The directory we want to create. */
- }
- catch (std::bad_alloc &)
- {
- vrc = VERR_NO_MEMORY;
+ if (RT_SUCCESS(vrc))
+ vrc = GuestProcessToolbox::run(this, procInfo, pvrcGuest);
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT */
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
}
-
- if (RT_SUCCESS(vrc))
- vrc = GuestProcessTool::run(this, procInfo, pvrcGuest);
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
LogFlowFuncLeaveRC(vrc);
return vrc;
@@ -1180,71 +1223,119 @@ int GuestSession::i_fsCreateTemp(const Utf8Str &strTemplate, const Utf8Str &strP
LogFlowThisFunc(("strTemplate=%s, strPath=%s, fDirectory=%RTbool, fMode=%o, fSecure=%RTbool\n",
strTemplate.c_str(), strPath.c_str(), fDirectory, fMode, fSecure));
- GuestProcessStartupInfo procInfo;
- procInfo.mFlags = ProcessCreateFlag_WaitForStdOut;
- try
+ int vrc;
+ int vrcGuest = VERR_IPE_UNINITIALIZED_STATUS;
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+ if (mParent->i_getGuestControlFeatures0() & VBOX_GUESTCTRL_GF_0_TOOLBOX_AS_CMDS)
{
- procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_MKTEMP);
- procInfo.mArguments.push_back(procInfo.mExecutable); /* Set argv0. */
- procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ GuestWaitEvent *pEvent = NULL;
+ vrc = registerWaitEvent(mData.mSession.mID, mData.mObjectID, &pEvent);
+ if (RT_FAILURE(vrc))
+ return vrc;
+
+ uint32_t fFlags = GSTCTL_CREATETEMP_F_NONE;
if (fDirectory)
- procInfo.mArguments.push_back(Utf8Str("-d"));
- if (strPath.length()) /* Otherwise use /tmp or equivalent. */
- {
- procInfo.mArguments.push_back(Utf8Str("-t"));
- procInfo.mArguments.push_back(strPath);
- }
- /* Note: Secure flag and mode cannot be specified at the same time. */
+ fFlags |= GSTCTL_CREATETEMP_F_DIRECTORY;
if (fSecure)
+ fFlags |= GSTCTL_CREATETEMP_F_SECURE;
+ Assert(!(fFlags & ~GSTCTL_CREATETEMP_F_VALID_MASK));
+
+ /* Prepare HGCM call. */
+ VBOXHGCMSVCPARM paParms[8];
+ int i = 0;
+ HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
+ HGCMSvcSetStr(&paParms[i++], strTemplate.c_str());
+ HGCMSvcSetStr(&paParms[i++], strPath.c_str());
+ HGCMSvcSetU32(&paParms[i++], fFlags);
+ HGCMSvcSetU32(&paParms[i++], fMode);
+
+ alock.release(); /* Drop lock before sending. */
+
+ vrc = i_sendMessage(HOST_MSG_FS_CREATE_TEMP, i, paParms);
+ if (RT_SUCCESS(vrc))
{
- procInfo.mArguments.push_back(Utf8Str("--secure"));
+ vrc = pEvent->Wait(30 * 1000);
+ if (RT_SUCCESS(vrc))
+ {
+ // TODO
+ }
}
- else
+ }
+ else
+ {
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT
+ GuestProcessStartupInfo procInfo;
+ procInfo.mFlags = ProcessCreateFlag_WaitForStdOut;
+ try
{
- procInfo.mArguments.push_back(Utf8Str("--mode"));
+ procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_MKTEMP);
+ procInfo.mArguments.push_back(procInfo.mExecutable); /* Set argv0. */
+ procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
+ if (fDirectory)
+ procInfo.mArguments.push_back(Utf8Str("-d"));
+ if (strPath.length()) /* Otherwise use /tmp or equivalent. */
+ {
+ procInfo.mArguments.push_back(Utf8Str("-t"));
+ procInfo.mArguments.push_back(strPath);
+ }
+ /* Note: Secure flag and mode cannot be specified at the same time. */
+ if (fSecure)
+ {
+ procInfo.mArguments.push_back(Utf8Str("--secure"));
+ }
+ else
+ {
+ procInfo.mArguments.push_back(Utf8Str("--mode"));
- /* Note: Pass the mode unmodified down to the guest. See @ticketref{21394}. */
- char szMode[16];
- int vrc2 = RTStrPrintf2(szMode, sizeof(szMode), "%d", fMode);
- AssertRCReturn(vrc2, vrc2);
- procInfo.mArguments.push_back(szMode);
+ /* Note: Pass the mode unmodified down to the guest. See @ticketref{21394}. */
+ char szMode[16];
+ vrc = RTStrPrintf2(szMode, sizeof(szMode), "%d", fMode);
+ AssertRCReturn(vrc, vrc);
+ procInfo.mArguments.push_back(szMode);
+ }
+ procInfo.mArguments.push_back("--"); /* strTemplate could be '--help'. */
+ procInfo.mArguments.push_back(strTemplate);
+ }
+ catch (std::bad_alloc &)
+ {
+ Log(("Out of memory!\n"));
+ return VERR_NO_MEMORY;
}
- procInfo.mArguments.push_back("--"); /* strTemplate could be '--help'. */
- procInfo.mArguments.push_back(strTemplate);
- }
- catch (std::bad_alloc &)
- {
- Log(("Out of memory!\n"));
- return VERR_NO_MEMORY;
- }
- /** @todo Use an internal HGCM command for this operation, since
- * we now can run in a user-dedicated session. */
- int vrcGuest = VERR_IPE_UNINITIALIZED_STATUS;
- GuestCtrlStreamObjects stdOut;
- int vrc = GuestProcessTool::runEx(this, procInfo, &stdOut, 1 /* cStrmOutObjects */, &vrcGuest);
- if (!GuestProcess::i_isGuestError(vrc))
- {
- GuestFsObjData objData;
- if (!stdOut.empty())
+ GuestCtrlStreamObjects stdOut;
+ vrc = GuestProcessToolbox::runEx(this, procInfo, &stdOut, 1 /* cStrmOutObjects */, &vrcGuest);
+ if (!GuestProcess::i_isGuestError(vrc))
{
- vrc = objData.FromMkTemp(stdOut.at(0));
- if (RT_FAILURE(vrc))
+ GuestFsObjData objData;
+ if (!stdOut.empty())
{
- vrcGuest = vrc;
- if (pvrcGuest)
- *pvrcGuest = vrcGuest;
- vrc = VERR_GSTCTL_GUEST_ERROR;
+ vrc = objData.FromToolboxMkTemp(stdOut.at(0));
+ if (RT_FAILURE(vrc))
+ {
+ vrcGuest = vrc;
+ if (pvrcGuest)
+ *pvrcGuest = vrcGuest;
+ vrc = VERR_GSTCTL_GUEST_ERROR;
+ }
}
- }
- else
- vrc = VERR_BROKEN_PIPE;
+ else
+ vrc = VERR_BROKEN_PIPE;
- if (RT_SUCCESS(vrc))
- strName = objData.mName;
+ if (RT_SUCCESS(vrc))
+ strName = objData.mName;
+ }
+ else if (pvrcGuest)
+ *pvrcGuest = vrcGuest;
+#else
+ RT_NOREF(strName);
+ vrc = VERR_NOT_SUPPORTED;
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT */
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
}
- else if (pvrcGuest)
- *pvrcGuest = vrcGuest;
+#endif
LogFlowThisFunc(("Returning vrc=%Rrc, vrcGuest=%Rrc\n", vrc, vrcGuest));
return vrc;
@@ -1284,7 +1375,10 @@ int GuestSession::i_directoryOpen(const GuestDirectoryOpenInfo &openInfo, ComObj
return vrc;
}
- /* We need to release the write lock first before initializing the directory object below,
+ /**
+ * If VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT is enabled:
+ *
+ * We need to release the write lock first before opening the directory object below,
* as we're starting a guest process as part of it. This in turn will try to acquire the session's
* write lock. */
alock.release();
@@ -1293,6 +1387,9 @@ int GuestSession::i_directoryOpen(const GuestDirectoryOpenInfo &openInfo, ComObj
AssertPtr(pConsole);
vrc = pDirectory->init(pConsole, this /* Parent */, idObject, openInfo);
+ if (RT_SUCCESS(vrc))
+ vrc = pDirectory->i_open(pvrcGuest);
+
if (RT_FAILURE(vrc))
{
/* Make sure to acquire the write lock again before unregistering the object. */
@@ -1587,46 +1684,86 @@ int GuestSession::i_fileRemove(const Utf8Str &strPath, int *pvrcGuest)
{
LogFlowThisFunc(("strPath=%s\n", strPath.c_str()));
- GuestProcessStartupInfo procInfo;
- GuestProcessStream streamOut;
+ int vrc;
+ int vrcGuest = VERR_IPE_UNINITIALIZED_STATUS;
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+ if (mParent->i_getGuestControlFeatures0() & VBOX_GUESTCTRL_GF_0_TOOLBOX_AS_CMDS)
+ {
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
- procInfo.mFlags = ProcessCreateFlag_WaitForStdOut;
- procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_RM);
+ GuestWaitEvent *pEvent = NULL;
+ vrc = registerWaitEvent(mData.mSession.mID, mData.mObjectID, &pEvent);
+ if (RT_FAILURE(vrc))
+ return vrc;
- try
- {
- procInfo.mArguments.push_back(procInfo.mExecutable); /* Set argv0. */
- procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
- procInfo.mArguments.push_back("--"); /* strPath could be '--help', which is a valid filename. */
- procInfo.mArguments.push_back(strPath); /* The file we want to remove. */
+ /* Prepare HGCM call. */
+ VBOXHGCMSVCPARM paParms[4];
+ int i = 0;
+ HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
+ HGCMSvcSetPv (&paParms[i++], (void*)strPath.c_str(), (ULONG)strPath.length() + 1);
+
+ alock.release(); /* Drop lock before sending. */
+
+ vrc = i_sendMessage(HOST_MSG_FILE_REMOVE, i, paParms);
+ if (RT_SUCCESS(vrc))
+ {
+ vrc = pEvent->Wait(30 * 1000);
+ if (RT_SUCCESS(vrc))
+ {
+ // TODO
+ }
+ }
}
- catch (std::bad_alloc &)
+ else
{
- return VERR_NO_MEMORY;
- }
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT
+ GuestProcessStartupInfo procInfo;
+ GuestToolboxStream streamOut;
- int vrcGuest = VERR_IPE_UNINITIALIZED_STATUS;
- GuestCtrlStreamObjects stdOut;
- int vrc = GuestProcessTool::runEx(this, procInfo, &stdOut, 1 /* cStrmOutObjects */, &vrcGuest);
- if (GuestProcess::i_isGuestError(vrc))
- {
- if (!stdOut.empty())
+ procInfo.mFlags = ProcessCreateFlag_WaitForStdOut;
+ procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_RM);
+
+ try
{
- GuestFsObjData objData;
- vrc = objData.FromRm(stdOut.at(0));
- if (RT_FAILURE(vrc))
+ procInfo.mArguments.push_back(procInfo.mExecutable); /* Set argv0. */
+ procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
+ procInfo.mArguments.push_back("--"); /* strPath could be '--help', which is a valid filename. */
+ procInfo.mArguments.push_back(strPath); /* The file we want to remove. */
+ }
+ catch (std::bad_alloc &)
+ {
+ return VERR_NO_MEMORY;
+ }
+
+ GuestCtrlStreamObjects stdOut;
+ vrc = GuestProcessToolbox::runEx(this, procInfo, &stdOut, 1 /* cStrmOutObjects */, &vrcGuest);
+ if (GuestProcess::i_isGuestError(vrc))
+ {
+ if (!stdOut.empty())
{
- vrcGuest = vrc;
- if (pvrcGuest)
- *pvrcGuest = vrcGuest;
- vrc = VERR_GSTCTL_GUEST_ERROR;
+ GuestFsObjData objData;
+ vrc = objData.FromToolboxRm(stdOut.at(0));
+ if (RT_FAILURE(vrc))
+ {
+ vrcGuest = vrc;
+ if (pvrcGuest)
+ *pvrcGuest = vrcGuest;
+ vrc = VERR_GSTCTL_GUEST_ERROR;
+ }
}
+ else
+ vrc = VERR_BROKEN_PIPE;
}
- else
- vrc = VERR_BROKEN_PIPE;
+ else if (pvrcGuest)
+ *pvrcGuest = vrcGuest;
+#else
+ RT_NOREF(pvrcGuest);
+ vrc = VERR_NOT_SUPPORTED;
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT */
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
}
- else if (pvrcGuest)
- *pvrcGuest = vrcGuest;
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
LogFlowThisFunc(("Returning vrc=%Rrc, vrcGuest=%Rrc\n", vrc, vrcGuest));
return vrc;
@@ -1820,48 +1957,133 @@ int GuestSession::i_fsQueryInfo(const Utf8Str &strPath, bool fFollowSymlinks, Gu
{
LogFlowThisFunc(("strPath=%s\n", strPath.c_str()));
- /** @todo Merge this with IGuestFile::queryInfo(). */
- GuestProcessStartupInfo procInfo;
- procInfo.mFlags = ProcessCreateFlag_WaitForStdOut;
- try
+ int vrc;
+ int vrcGuest = VERR_IPE_UNINITIALIZED_STATUS;
+
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
+ if (mParent->i_getGuestControlFeatures0() & VBOX_GUESTCTRL_GF_0_TOOLBOX_AS_CMDS)
{
- procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_STAT);
- procInfo.mArguments.push_back(procInfo.mExecutable); /* Set argv0. */
- procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
+ AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
+
+ GuestWaitEvent *pEvent = NULL;
+ vrc = registerWaitEvent(mData.mSession.mID, mData.mObjectID, &pEvent);
+ if (RT_FAILURE(vrc))
+ return vrc;
+
+ uint32_t fFlags = GSTCTL_QUERYINFO_F_NONE;
if (fFollowSymlinks)
- procInfo.mArguments.push_back(Utf8Str("-L"));
- procInfo.mArguments.push_back("--"); /* strPath could be '--help', which is a valid filename. */
- procInfo.mArguments.push_back(strPath);
+ fFlags |= GSTCTL_QUERYINFO_F_FOLLOW_LINK;
+
+ /* Prepare HGCM call. */
+ VBOXHGCMSVCPARM paParms[4];
+ int i = 0;
+ HGCMSvcSetU32(&paParms[i++], pEvent->ContextID());
+ HGCMSvcSetPv (&paParms[i++], (void*)strPath.c_str(), (ULONG)strPath.length() + 1);
+ HGCMSvcSetU32(&paParms[i++], GSTCTLFSOBJATTRADD_UNIX /* Implicit */);
+ HGCMSvcSetU32(&paParms[i++], fFlags);
+
+ alock.release(); /* Drop lock before sending. */
+
+ vrc = i_sendMessage(HOST_MSG_FS_QUERY_INFO, i, paParms);
+ if (RT_SUCCESS(vrc))
+ {
+ vrc = pEvent->Wait(30 * 1000);
+ if (RT_SUCCESS(vrc))
+ {
+ // TODO
+ #if 0
+ const ComPtr<IEvent> pThisEvent = pEvent->Event();
+ if (pThisEvent.isNotNull()) /* Make sure that we actually have an event associated. */
+ {
+ if (pType)
+ {
+ HRESULT hrc = pThisEvent->COMGETTER(Type)(pType);
+ if (FAILED(hrc))
+ vrc = VERR_COM_UNEXPECTED;
+ }
+ if ( RT_SUCCESS(vrc)
+ && ppEvent)
+ pThisEvent.queryInterfaceTo(ppEvent);
+
+ unconst(pThisEvent).setNull();
+ }
+
+ if (pEvent->Payload().Size() == sizeof(GSTCTLFSOBJINFO))
+ {
+ HRESULT hrc1 = pFileEvent->COMGETTER(Data)(ComSafeArrayAsOutParam(data));
+ ComAssertComRC(hrc1);
+
+ objData.Init(strPath);
+
+ PGSTCTLFSOBJINFO
+
+ objData.FromGuestFsObjInfo((PGSTCTLFSOBJINFO)pEvent->Payload().Raw());
+ }
+ else
+ vrc = VERR_INVALID_PARAMETER;
+ #endif
+ }
+ else
+ {
+ if (vrc == VERR_GSTCTL_GUEST_ERROR)
+ {
+ if (pvrcGuest)
+ *pvrcGuest = pEvent->GuestResult();
+ }
+ }
+ }
+ unregisterWaitEvent(pEvent);
}
- catch (std::bad_alloc &)
+ else
{
- Log(("Out of memory!\n"));
- return VERR_NO_MEMORY;
- }
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT
+ /** @todo Merge this with IGuestFile::queryInfo(). */
+ GuestProcessStartupInfo procInfo;
+ procInfo.mFlags = ProcessCreateFlag_WaitForStdOut;
+ try
+ {
+ procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_STAT);
+ procInfo.mArguments.push_back(procInfo.mExecutable); /* Set argv0. */
+ procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
+ if (fFollowSymlinks)
+ procInfo.mArguments.push_back(Utf8Str("-L"));
+ procInfo.mArguments.push_back("--"); /* strPath could be '--help', which is a valid filename. */
+ procInfo.mArguments.push_back(strPath);
+ }
+ catch (std::bad_alloc &)
+ {
+ Log(("Out of memory!\n"));
+ return VERR_NO_MEMORY;
+ }
- int vrcGuest = VERR_IPE_UNINITIALIZED_STATUS;
- GuestCtrlStreamObjects stdOut;
- int vrc = GuestProcessTool::runEx(this, procInfo,
- &stdOut, 1 /* cStrmOutObjects */,
- &vrcGuest);
- if (!GuestProcess::i_isGuestError(vrc))
- {
- if (!stdOut.empty())
+ GuestCtrlStreamObjects stdOut;
+ vrc = GuestProcessToolbox::runEx(this, procInfo, &stdOut, 1 /* cStrmOutObjects */, &vrcGuest);
+ if (!GuestProcess::i_isGuestError(vrc))
{
- vrc = objData.FromStat(stdOut.at(0));
- if (RT_FAILURE(vrc))
+ if (!stdOut.empty())
{
- vrcGuest = vrc;
- if (pvrcGuest)
- *pvrcGuest = vrcGuest;
- vrc = VERR_GSTCTL_GUEST_ERROR;
+ vrc = objData.FromToolboxStat(stdOut.at(0));
+ if (RT_FAILURE(vrc))
+ {
+ vrcGuest = vrc;
+ if (pvrcGuest)
+ *pvrcGuest = vrcGuest;
+ vrc = VERR_GSTCTL_GUEST_ERROR;
+ }
}
+ else
+ vrc = VERR_BROKEN_PIPE;
}
- else
- vrc = VERR_BROKEN_PIPE;
+ else if (pvrcGuest)
+ *pvrcGuest = vrcGuest;
+#else
+ RT_NOREF(fFollowSymlinks, objData, pvrcGuest);
+ vrc = VERR_NOT_SUPPORTED;
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT */
+#ifdef VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS
}
- else if (pvrcGuest)
- *pvrcGuest = vrcGuest;
+#endif /* VBOX_WITH_GSTCTL_TOOLBOX_AS_CMDS */
LogFlowThisFunc(("Returning vrc=%Rrc, vrcGuest=%Rrc\n", vrc, vrcGuest));
return vrc;
@@ -3801,7 +4023,7 @@ HRESULT GuestSession::directoryCreateTemp(const com::Utf8Str &aTemplateName, ULO
{
case VERR_GSTCTL_GUEST_ERROR:
{
- GuestErrorInfo ge(GuestErrorInfo::Type_ToolMkTemp, vrcGuest, aPath.c_str());
+ GuestErrorInfo ge(GuestErrorInfo::Type_Fs, vrcGuest, aPath.c_str());
hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrcGuest, tr("Temporary guest directory creation failed: %s"),
GuestBase::getErrorAsString(ge).c_str());
break;
@@ -3846,7 +4068,7 @@ HRESULT GuestSession::directoryExists(const com::Utf8Str &aPath, BOOL aFollowSym
break;
default:
{
- GuestErrorInfo ge(GuestErrorInfo::Type_ToolStat, vrcGuest, aPath.c_str());
+ GuestErrorInfo ge(GuestErrorInfo::Type_Fs, vrcGuest, aPath.c_str());
hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrcGuest, tr("Querying directory existence failed: %s"),
GuestBase::getErrorAsString(ge).c_str());
break;
@@ -4189,7 +4411,7 @@ HRESULT GuestSession::fileExists(const com::Utf8Str &aPath, BOOL aFollowSymlinks
default:
{
- GuestErrorInfo ge(GuestErrorInfo::Type_ToolStat, vrcGuest, aPath.c_str());
+ GuestErrorInfo ge(GuestErrorInfo::Type_Fs, vrcGuest, aPath.c_str());
hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrcGuest, tr("Querying guest file existence failed: %s"),
GuestBase::getErrorAsString(ge).c_str());
break;
@@ -4342,7 +4564,7 @@ HRESULT GuestSession::fileQuerySize(const com::Utf8Str &aPath, BOOL aFollowSymli
{
if (GuestProcess::i_isGuestError(vrc))
{
- GuestErrorInfo ge(GuestErrorInfo::Type_ToolStat, vrcGuest, aPath.c_str());
+ GuestErrorInfo ge(GuestErrorInfo::Type_Fs, vrcGuest, aPath.c_str());
hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrcGuest, tr("Querying guest file size failed: %s"),
GuestBase::getErrorAsString(ge).c_str());
}
@@ -4397,7 +4619,7 @@ HRESULT GuestSession::fsObjExists(const com::Utf8Str &aPath, BOOL aFollowSymlink
hrc = S_OK; /* Ignore these vrc values. */
else
{
- GuestErrorInfo ge(GuestErrorInfo::Type_ToolStat, vrcGuest, aPath.c_str());
+ GuestErrorInfo ge(GuestErrorInfo::Type_Fs, vrcGuest, aPath.c_str());
hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrcGuest, tr("Querying guest file existence information failed: %s"),
GuestBase::getErrorAsString(ge).c_str());
}
@@ -4420,16 +4642,16 @@ HRESULT GuestSession::fsObjQueryInfo(const com::Utf8Str &aPath, BOOL aFollowSyml
LogFlowThisFunc(("aPath=%s, aFollowSymlinks=%RTbool\n", aPath.c_str(), RT_BOOL(aFollowSymlinks)));
- GuestFsObjData Info;
+ GuestFsObjData objData;
int vrcGuest = VERR_IPE_UNINITIALIZED_STATUS;
- int vrc = i_fsQueryInfo(aPath, aFollowSymlinks != FALSE, Info, &vrcGuest);
+ int vrc = i_fsQueryInfo(aPath, aFollowSymlinks != FALSE, objData, &vrcGuest);
if (RT_SUCCESS(vrc))
{
ComObjPtr<GuestFsObjInfo> ptrFsObjInfo;
hrc = ptrFsObjInfo.createObject();
if (SUCCEEDED(hrc))
{
- vrc = ptrFsObjInfo->init(Info);
+ vrc = ptrFsObjInfo->init(objData);
if (RT_SUCCESS(vrc))
hrc = ptrFsObjInfo.queryInterfaceTo(aInfo.asOutParam());
else
@@ -4440,7 +4662,7 @@ HRESULT GuestSession::fsObjQueryInfo(const com::Utf8Str &aPath, BOOL aFollowSyml
{
if (GuestProcess::i_isGuestError(vrc))
{
- GuestErrorInfo ge(GuestErrorInfo::Type_ToolStat, vrcGuest, aPath.c_str());
+ GuestErrorInfo ge(GuestErrorInfo::Type_Fs, vrcGuest, aPath.c_str());
hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrcGuest, tr("Querying guest file information failed: %s"),
GuestBase::getErrorAsString(ge).c_str());
}
@@ -4468,7 +4690,7 @@ HRESULT GuestSession::fsObjRemove(const com::Utf8Str &aPath)
{
if (GuestProcess::i_isGuestError(vrc))
{
- GuestErrorInfo ge(GuestErrorInfo::Type_ToolRm, vrcGuest, aPath.c_str());
+ GuestErrorInfo ge(GuestErrorInfo::Type_File, vrcGuest, aPath.c_str());
hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrcGuest, tr("Removing guest file failed: %s"),
GuestBase::getErrorAsString(ge).c_str());
}
diff --git a/src/VBox/Main/src-client/GuestSessionImplTasks.cpp b/src/VBox/Main/src-client/GuestSessionImplTasks.cpp
index 29b558aaff8..320052af32c 100644
--- a/src/VBox/Main/src-client/GuestSessionImplTasks.cpp
+++ b/src/VBox/Main/src-client/GuestSessionImplTasks.cpp
@@ -549,7 +549,7 @@ int GuestSessionTask::fileCopyFromGuest(const Utf8Str &strSrc, const Utf8Str &st
{
if (vrc == VERR_GSTCTL_GUEST_ERROR)
setProgressErrorMsg(VBOX_E_IPRT_ERROR, tr("Guest file lookup failed"),
- GuestErrorInfo(GuestErrorInfo::Type_ToolStat, vrcGuest, strSrc.c_str()));
+ GuestErrorInfo(GuestErrorInfo::Type_Fs, vrcGuest, strSrc.c_str()));
else
setProgressErrorMsg(VBOX_E_IPRT_ERROR,
Utf8StrFmt(tr("Guest file lookup for \"%s\" failed: %Rrc"), strSrc.c_str(), vrc));
@@ -1246,7 +1246,7 @@ int FsList::AddDirFromGuest(const Utf8Str &strPath, const Utf8Str &strSubDir /*
vrc = VINF_SUCCESS;
}
- int vrc2 = pDir->i_closeInternal(&vrcGuest);
+ int vrc2 = pDir->i_close(&vrcGuest);
if (RT_SUCCESS(vrc))
vrc = vrc2;
@@ -1543,7 +1543,7 @@ HRESULT GuestSessionTaskCopyFrom::Init(const Utf8Str &strTaskDesc)
{
if (vrc == VERR_GSTCTL_GUEST_ERROR)
strErrorInfo = GuestBase::getErrorAsString(tr("Guest source lookup failed"),
- GuestErrorInfo(GuestErrorInfo::Type_ToolStat, vrcGuest, strSrc.c_str()));
+ GuestErrorInfo(GuestErrorInfo::Type_Fs, vrcGuest, strSrc.c_str()));
else
strErrorInfo.printf(tr("Guest source lookup for \"%s\" failed: %Rrc"),
strSrc.c_str(), vrc);
@@ -2629,15 +2629,15 @@ int GuestSessionTaskUpdateAdditions::runFileOnGuest(GuestSession *pSession, Gues
LogRel(("Running %s ...\n", procInfo.mName.c_str()));
- GuestProcessTool procTool;
+ GuestProcessToolbox procToRun;
int vrcGuest = VERR_IPE_UNINITIALIZED_STATUS;
- int vrc = procTool.init(pSession, procInfo, false /* Async */, &vrcGuest);
+ int vrc = procToRun.init(pSession, procInfo, false /* Async */, &vrcGuest);
if (RT_SUCCESS(vrc))
{
if (RT_SUCCESS(vrcGuest))
- vrc = procTool.wait(GUESTPROCESSTOOL_WAIT_FLAG_NONE, &vrcGuest);
+ vrc = procToRun.wait(GUESTPROCESSTOOL_WAIT_FLAG_NONE, &vrcGuest);
if (RT_SUCCESS(vrc))
- vrc = procTool.getTerminationStatus();
+ vrc = procToRun.getTerminationStatus();
}
if (RT_FAILURE(vrc))
@@ -2647,7 +2647,7 @@ int GuestSessionTaskUpdateAdditions::runFileOnGuest(GuestSession *pSession, Gues
case VERR_GSTCTL_PROCESS_EXIT_CODE:
setProgressErrorMsg(VBOX_E_IPRT_ERROR,
Utf8StrFmt(tr("Running update file \"%s\" on guest failed: %Rrc"),
- procInfo.mExecutable.c_str(), procTool.getRc()));
+ procInfo.mExecutable.c_str(), procToRun.getRc()));
break;
case VERR_GSTCTL_GUEST_ERROR:
diff --git a/src/VBox/Main/testcase/Makefile.kmk b/src/VBox/Main/testcase/Makefile.kmk
index 30cd1dfea6a..51f082c0aa5 100644
--- a/src/VBox/Main/testcase/Makefile.kmk
+++ b/src/VBox/Main/testcase/Makefile.kmk
@@ -224,7 +224,7 @@ tstGuestCtrlContextID_INCS = ../include \
#
tstGuestCtrlParseBuffer_TEMPLATE = VBoxMainClientTstExe
tstGuestCtrlParseBuffer_INTERMEDIATES = $(VBOX_MAIN_APIWRAPPER_GEN_HDRS)
-tstGuestCtrlParseBuffer_DEFS += VBOX_WITH_HGCM VBOX_WITH_GUEST_CONTROL VBOX_GUESTCTRL_TEST_CASE
+tstGuestCtrlParseBuffer_DEFS += VBOX_WITH_HGCM VBOX_WITH_GSTCTL_TOOLBOX_SUPPORT VBOX_WITH_GUEST_CONTROL VBOX_GUESTCTRL_TEST_CASE
tstGuestCtrlParseBuffer_SOURCES = \
tstGuestCtrlParseBuffer.cpp \
../src-client/GuestCtrlPrivate.cpp
diff --git a/src/VBox/Main/testcase/tstGuestCtrlParseBuffer.cpp b/src/VBox/Main/testcase/tstGuestCtrlParseBuffer.cpp
index cc422ff4fe4..ec80dbccff8 100644
--- a/src/VBox/Main/testcase/tstGuestCtrlParseBuffer.cpp
+++ b/src/VBox/Main/testcase/tstGuestCtrlParseBuffer.cpp
@@ -163,12 +163,12 @@ int manualTest(void)
{
RTTestIPrintf(RTTESTLVL_DEBUG, "Manual test #%d\n", iTest);
- GuestProcessStream stream;
+ GuestToolboxStream stream;
rc = stream.AddData((BYTE *)s_aTest[iTest].pbData, s_aTest[iTest].cbData);
for (;;)
{
- GuestProcessStreamBlock block;
+ GuestToolboxStreamBlock block;
rc = stream.ParseBlock(block);
RTTestIPrintf(RTTESTLVL_DEBUG, "\tReturned with rc=%Rrc, numItems=%ld\n",
rc, block.GetCount());
@@ -212,7 +212,7 @@ int main()
{
RTTestIPrintf(RTTESTLVL_DEBUG, "=> Test #%u\n", iTest);
- GuestProcessStream stream;
+ GuestToolboxStream stream;
if (RT_FAILURE(g_aTestBlocks[iTest].iResult))
RTTestDisableAssertions(hTest);
int iResult = stream.AddData((BYTE *)g_aTestBlocks[iTest].pbData, g_aTestBlocks[iTest].cbData);
@@ -220,7 +220,7 @@ int main()
RTTestRestoreAssertions(hTest);
if (RT_SUCCESS(iResult))
{
- GuestProcessStreamBlock curBlock;
+ GuestToolboxStreamBlock curBlock;
iResult = stream.ParseBlock(curBlock);
if (iResult != g_aTestBlocks[iTest].iResult)
RTTestFailed(hTest, "Block #%u: Returned %Rrc, expected %Rrc", iTest, iResult, g_aTestBlocks[iTest].iResult);
@@ -256,7 +256,7 @@ int main()
{
RTTestIPrintf(RTTESTLVL_DEBUG, "=> Block test #%u\n", iTest);
- GuestProcessStream stream;
+ GuestToolboxStream stream;
int iResult = stream.AddData((BYTE*)g_aTestStream[iTest].pbData, g_aTestStream[iTest].cbData);
if (RT_SUCCESS(iResult))
{
@@ -264,7 +264,7 @@ int main()
uint8_t uSafeCouunter = 0;
do
{
- GuestProcessStreamBlock curBlock;
+ GuestToolboxStreamBlock curBlock;
iResult = stream.ParseBlock(curBlock);
RTTestIPrintf(RTTESTLVL_DEBUG, "Block #%u: Returned with %Rrc", iTest, iResult);
if (RT_SUCCESS(iResult))