Index: /trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp	(revision 33897)
+++ /trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp	(revision 33898)
@@ -95,4 +95,9 @@
                  "                            --username <name> --password <password>\n"
                  "                            [--dryrun] [--recursive] [--verbose] [--flags <flags>]\n"
+                 "\n"
+                 "                            createdirectory <vmname>|<uuid>\n"
+                 "                            <directory to create on guest>\n"
+                 "                            --username <name> --password <password>\n"
+                 "                            [--parents] [--mode <mode>]\n"
                  "\n"
                  "                            updateadditions <vmname>|<uuid>\n"
@@ -593,5 +598,5 @@
         return VERR_NO_MEMORY;
     }
-    
+
     pNode->Node.pPrev = NULL;
     pNode->Node.pNext = NULL;
@@ -1237,4 +1242,225 @@
 }
 
+static int handleCtrlCreateDirectory(HandlerArg *a)
+{
+    /*
+     * Check the syntax.  We can deduce the correct syntax from the number of
+     * arguments.
+     */
+    if (a->argc < 2) /* At least the directory we want to create should be present :-). */
+        return errorSyntax(USAGE_GUESTCONTROL, "Incorrect parameters");
+
+    Utf8Str Utf8Directory(a->argv[1]);
+    Utf8Str Utf8UserName;
+    Utf8Str Utf8Password;
+    uint32_t uFlags = CreateDirectoryFlag_None;
+    uint32_t uMode = 0;
+    bool fVerbose = false;
+
+    /* Iterate through all possible commands (if available). */
+    bool usageOK = true;
+    for (int i = 3; usageOK && i < a->argc; i++)
+    {
+        if (   !strcmp(a->argv[i], "--username")
+            || !strcmp(a->argv[i], "--user"))
+        {
+            if (i + 1 >= a->argc)
+                usageOK = false;
+            else
+            {
+                Utf8UserName = a->argv[i + 1];
+                ++i;
+            }
+        }
+        else if (   !strcmp(a->argv[i], "--password")
+                 || !strcmp(a->argv[i], "--pwd"))
+        {
+            if (i + 1 >= a->argc)
+                usageOK = false;
+            else
+            {
+                Utf8Password = a->argv[i + 1];
+                ++i;
+            }
+        }
+        else if (   !strcmp(a->argv[i], "--parents")
+                 || !strcmp(a->argv[i], "-p"))
+        {
+            uFlags |= CreateDirectoryFlag_Parents;
+        }
+        else if (   !strcmp(a->argv[i], "--mode")
+                 || !strcmp(a->argv[i], "-m"))
+        {
+            if (i + 1 >= a->argc)
+                usageOK = false;
+            else
+            {
+                uMode = atoi(a->argv[i + 1]);
+                ++i;
+            }
+        }
+        else if (!strcmp(a->argv[i], "--flags"))
+        {
+            if (i + 1 >= a->argc)
+                usageOK = false;
+            else
+            {
+                /* Nothing to do here yet. */
+                ++i;
+            }
+        }
+        /** @todo Add force flag for overwriting existing stuff. */
+        else if (!strcmp(a->argv[i], "--verbose"))
+            fVerbose = true;
+        else
+            return errorSyntax(USAGE_GUESTCONTROL,
+                               "Invalid parameter '%s'", Utf8Str(a->argv[i]).c_str());
+    }
+
+    if (!usageOK)
+        return errorSyntax(USAGE_GUESTCONTROL, "Incorrect parameters");
+
+    if (Utf8Directory.isEmpty())
+        return errorSyntax(USAGE_GUESTCONTROL,
+                           "No directory specified!");
+
+    if (Utf8UserName.isEmpty())
+        return errorSyntax(USAGE_GUESTCONTROL,
+                           "No user name specified!");
+
+    /* Lookup VM. */
+    ComPtr<IMachine> machine;
+    /* Assume it's an UUID. */
+    HRESULT rc;
+    CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
+                                           machine.asOutParam()));
+    if (FAILED(rc))
+        return 1;
+
+    /* Machine is running? */
+    MachineState_T machineState;
+    CHECK_ERROR_RET(machine, COMGETTER(State)(&machineState), 1);
+    if (machineState != MachineState_Running)
+    {
+        RTMsgError("Machine \"%s\" is not running!\n", a->argv[0]);
+        return 1;
+    }
+
+    /* Open a session for the VM. */
+    CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Shared), 1);
+
+    do
+    {
+        /* Get the associated console. */
+        ComPtr<IConsole> console;
+        CHECK_ERROR_BREAK(a->session, COMGETTER(Console)(console.asOutParam()));
+        /* ... and session machine */
+        ComPtr<IMachine> sessionMachine;
+        CHECK_ERROR_BREAK(a->session, COMGETTER(Machine)(sessionMachine.asOutParam()));
+
+        ComPtr<IGuest> guest;
+        CHECK_ERROR_BREAK(console, COMGETTER(Guest)(guest.asOutParam()));
+
+        ComPtr<IProgress> progress;
+        rc = guest->CreateDirectory(Bstr(Utf8Directory).raw(),
+                                    Bstr(Utf8UserName).raw(), Bstr(Utf8Password).raw(),
+                                    uMode, uFlags, progress.asOutParam());
+        if (FAILED(rc))
+        {
+            /* If we got a VBOX_E_IPRT error we handle the error in a more gentle way
+             * because it contains more accurate info about what went wrong. */
+            ErrorInfo info(guest, COM_IIDOF(IGuest));
+            if (info.isFullAvailable())
+            {
+                if (rc == VBOX_E_IPRT_ERROR)
+                    RTMsgError("%ls.", info.getText().raw());
+                else
+                    RTMsgError("%ls (%Rhrc).", info.getText().raw(), info.getResultCode());
+            }
+        }
+        else
+        {
+            /* Setup signal handling if cancelable. */
+            ASSERT(progress);
+            bool fCanceledAlready = false;
+            BOOL fCancelable;
+            HRESULT hrc = progress->COMGETTER(Cancelable)(&fCancelable);
+            if (FAILED(hrc))
+                fCancelable = FALSE;
+            if (fCancelable)
+            {
+                signal(SIGINT,   ctrlCopySignalHandler);
+        #ifdef SIGBREAK
+                signal(SIGBREAK, ctrlCopySignalHandler);
+        #endif
+            }
+
+            /* Wait for process to exit ... */
+            BOOL fCompleted = FALSE;
+            BOOL fCanceled = FALSE;
+            while (   SUCCEEDED(progress->COMGETTER(Completed(&fCompleted)))
+                   && !fCompleted)
+            {
+                /* Process async cancelation */
+                if (g_fCopyCanceled && !fCanceledAlready)
+                {
+                    hrc = progress->Cancel();
+                    if (SUCCEEDED(hrc))
+                        fCanceledAlready = TRUE;
+                    else
+                        g_fCopyCanceled = false;
+                }
+
+                /* Progress canceled by Main API? */
+                if (   SUCCEEDED(progress->COMGETTER(Canceled(&fCanceled)))
+                    && fCanceled)
+                {
+                    break;
+                }
+            }
+
+            /* Undo signal handling */
+            if (fCancelable)
+            {
+                signal(SIGINT,   SIG_DFL);
+        #ifdef SIGBREAK
+                signal(SIGBREAK, SIG_DFL);
+        #endif
+            }
+
+            if (fCanceled)
+            {
+                //RTPrintf("Copy operation canceled!\n");
+            }
+            else if (   fCompleted
+                     && SUCCEEDED(rc))
+            {
+                LONG iRc = false;
+                CHECK_ERROR_RET(progress, COMGETTER(ResultCode)(&iRc), rc);
+                if (FAILED(iRc))
+                {
+                    com::ProgressErrorInfo info(progress);
+                    if (   info.isFullAvailable()
+                        || info.isBasicAvailable())
+                    {
+                        /* If we got a VBOX_E_IPRT error we handle the error in a more gentle way
+                         * because it contains more accurate info about what went wrong. */
+                        if (info.getResultCode() == VBOX_E_IPRT_ERROR)
+                            RTMsgError("%ls.", info.getText().raw());
+                        else
+                        {
+                            RTMsgError("Copy operation error details:");
+                            GluePrintErrorInfo(info);
+                        }
+                    }
+                }
+            }
+        }
+
+        a->session->UnlockMachine();
+    } while (0);
+    return SUCCEEDED(rc) ? 0 : 1;
+}
+
 static int handleCtrlUpdateAdditions(HandlerArg *a)
 {
@@ -1388,7 +1614,14 @@
         return handleCtrlExecProgram(&arg);
     }
-    else if (!strcmp(a->argv[0], "copyto"))
+    else if (   !strcmp(a->argv[0], "copyto")
+             || !strcmp(a->argv[0], "cp"))
     {
         return handleCtrlCopyTo(&arg);
+    }
+    else if (   !strcmp(a->argv[0], "createdirectory")
+             || !strcmp(a->argv[0], "createdir")
+             || !strcmp(a->argv[0], "mkdir"))
+    {
+        return handleCtrlCreateDirectory(&arg);
     }
     else if (   !strcmp(a->argv[0], "updateadditions")
Index: /trunk/src/VBox/Main/GuestImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/GuestImpl.cpp	(revision 33897)
+++ /trunk/src/VBox/Main/GuestImpl.cpp	(revision 33898)
@@ -2316,4 +2316,19 @@
                     if (RTStrPrintf(szOutput, sizeof(szOutput), "--output=%s", Utf8Dest.c_str()))
                     {
+                        /*
+                         * Normalize path slashes, based on the detected guest.
+                         */
+                        Utf8Str osType = mData.mOSTypeId;
+                        if (   osType.contains("Microsoft", Utf8Str::CaseInsensitive)
+                            || osType.contains("Windows", Utf8Str::CaseInsensitive))
+                        {
+                            /* We have a Windows guest. */
+                            RTPathChangeToDosSlashes(szOutput, true /* Force conversion. */);
+                        }
+                        else /* ... or something which isn't from Redmond ... */
+                        {
+                            RTPathChangeToUnixSlashes(szOutput, true /* Force conversion. */);
+                        }
+
                         args.push_back(Bstr(VBOXSERVICE_TOOL_CAT).raw()); /* The actual (internal) tool to use (as argv[0]). */
                         args.push_back(Bstr(szOutput).raw());             /* We want to write a file ... */
@@ -2326,6 +2341,6 @@
                     if (SUCCEEDED(rc))
                     {
-                        LogRel(("Copying file \"%s\" to guest \"%s\" ...\n",
-                                Utf8Source.c_str(), Utf8Dest.c_str()));
+                        LogRel(("Copying file \"%s\" to guest \"%s\" (%u bytes) ...\n",
+                                Utf8Source.c_str(), Utf8Dest.c_str(), cbSize));
                         /*
                          * Okay, since we gathered all stuff we need until now to start the
@@ -2389,4 +2404,132 @@
                 }
                 RTFileClose(fileSource);
+            }
+        }
+    }
+    catch (std::bad_alloc &)
+    {
+        rc = E_OUTOFMEMORY;
+    }
+    return rc;
+#endif /* VBOX_WITH_GUEST_CONTROL */
+}
+
+STDMETHODIMP Guest::CreateDirectory(IN_BSTR aDirectory,
+                                    IN_BSTR aUserName, IN_BSTR aPassword,
+                                    ULONG aMode, ULONG aFlags,
+                                    IProgress **aProgress)
+{
+#ifndef VBOX_WITH_GUEST_CONTROL
+    ReturnComNotImplemented();
+#else  /* VBOX_WITH_GUEST_CONTROL */
+    using namespace guestControl;
+
+    CheckComArgStrNotEmptyOrNull(aDirectory);
+
+    /* Do not allow anonymous executions (with system rights). */
+    if (RT_UNLIKELY((aUserName) == NULL || *(aUserName) == '\0'))
+        return setError(E_INVALIDARG, tr("No user name specified"));
+
+    LogRel(("Creating guest directory \"%s\" as  user \"%s\" ...\n",
+            Utf8Str(aDirectory).c_str(), Utf8Str(aUserName).c_str()));
+
+    return createDirectoryInternal(aDirectory,
+                                   aUserName, aPassword,
+                                   aMode, aFlags, aProgress, NULL /* rc */);
+#endif
+}
+
+STDMETHODIMP Guest::createDirectoryInternal(IN_BSTR aDirectory,
+                                            IN_BSTR aUserName, IN_BSTR aPassword,
+                                            ULONG aMode, ULONG aFlags,
+                                            IProgress **aProgress, int *pRC)
+{
+#ifndef VBOX_WITH_GUEST_CONTROL
+    ReturnComNotImplemented();
+#else /* VBOX_WITH_GUEST_CONTROL */
+    using namespace guestControl;
+
+    CheckComArgStrNotEmptyOrNull(aDirectory);
+    CheckComArgOutPointerValid(aProgress);
+
+    AutoCaller autoCaller(this);
+    if (FAILED(autoCaller.rc())) return autoCaller.rc();
+
+    /* Validate flags. */
+    if (aFlags != CreateDirectoryFlag_None)
+    {
+        if (!(aFlags & CreateDirectoryFlag_Parents))
+        {
+            return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), aFlags);
+        }
+    }
+
+    HRESULT rc = S_OK;
+
+    try
+    {
+        Utf8Str Utf8Directory(aDirectory);
+        Utf8Str Utf8UserName(aUserName);
+        Utf8Str Utf8Password(aPassword);
+
+        com::SafeArray<IN_BSTR> args;
+        com::SafeArray<IN_BSTR> env;
+
+        /*
+         * Prepare tool command line.
+         */
+        args.push_back(Bstr(VBOXSERVICE_TOOL_CAT).raw()); /* The actual (internal) tool to use (as argv[0]). */
+        if (aFlags & CreateDirectoryFlag_Parents)
+            args.push_back(Bstr("--parents").raw());      /* We also want to create the parent directories. */
+        if (aMode > 0)
+        {
+            args.push_back(Bstr("--mode").raw());         /* Set the creation mode. */
+
+            char szMode[16];
+            if (RTStrPrintf(szMode, sizeof(szMode), "%o", aMode))
+                args.push_back(Bstr(szMode).raw());
+            else
+                rc = setError(VBOX_E_IPRT_ERROR, tr("Error preparing command line"));
+        }
+        args.push_back(Bstr(Utf8Directory).raw());  /* The directory we want to create. */
+
+        /*
+         * Execute guest process.
+         */
+        ComPtr<IProgress> execProgress;
+        ULONG uPID;
+        if (SUCCEEDED(rc))
+        {
+            rc = ExecuteProcess(Bstr(VBOXSERVICE_TOOL_CAT).raw(),
+                                ExecuteProcessFlag_None,
+                                ComSafeArrayAsInParam(args),
+                                ComSafeArrayAsInParam(env),
+                                Bstr(Utf8UserName).raw(),
+                                Bstr(Utf8Password).raw(),
+                                5 * 1000 /* Wait 5s for getting the process started. */,
+                                &uPID, execProgress.asOutParam());
+        }
+
+        if (SUCCEEDED(rc))
+        {
+            /* Wait for process to exit ... */
+            BOOL fCompleted = FALSE;
+            BOOL fCanceled = FALSE;
+
+            while (   SUCCEEDED(execProgress->COMGETTER(Completed(&fCompleted)))
+                   && !fCompleted)
+            {
+                /* Progress canceled by Main API? */
+                if (   SUCCEEDED(execProgress->COMGETTER(Canceled(&fCanceled)))
+                    && fCanceled)
+                {
+                    break;
+                }
+            }
+
+            if (SUCCEEDED(rc))
+            {
+                /* Return the progress to the caller. */
+                execProgress.queryInterfaceTo(aProgress);
             }
         }
Index: /trunk/src/VBox/Main/idl/VirtualBox.xidl
===================================================================
--- /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 33897)
+++ /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 33898)
@@ -7697,7 +7697,24 @@
   </enum>
 
+  <enum
+    name="CreateDirectoryFlag"
+    uuid="26ff5bdd-c81f-4304-857b-b8be5e3f9cd6"
+  >
+    <desc>
+      Directory creation flags.
+    </desc>
+
+    <const name="None"                    value="0">
+      <desc>No flag set.</desc>
+    </const>
+
+    <const name="Parents"                 value="1">
+      <desc>No error if existing, make parent directories as needed.</desc>
+    </const>
+  </enum>
+
   <interface
      name="IGuest" extends="$unknown"
-     uuid="ded6983f-5c81-4bf9-90af-73f65fd9b728"
+     uuid="1039b0cc-9bc1-4c6d-8d12-864aa48aa5b9"
      wsmap="managed"
      >
@@ -8023,4 +8040,45 @@
         <desc>
           Copy flags.
+        </desc>
+      </param>
+      <param name="progress" type="IProgress" dir="return">
+        <desc>Progress object to track the operation completion.</desc>
+      </param>
+    </method>
+
+    <method name="createDirectory">
+      <desc>
+        Creates a directory on the guest.
+
+        <result name="VBOX_E_IPRT_ERROR">
+          Error while creating directory.
+        </result>
+
+      </desc>
+      <param name="directory" type="wstring" dir="in">
+        <desc>
+          Directory to create.
+        </desc>
+      </param>
+      <param name="userName" type="wstring" dir="in">
+        <desc>
+          User name under which the directory creation will be executed; the
+          user has to exist and have the appropriate rights to create the
+          desired directory.
+        </desc>
+      </param>
+      <param name="password" type="wstring" dir="in">
+        <desc>
+          Password of the user account specified.
+        </desc>
+      </param>
+      <param name="mode" type="unsigned long" dir="in">
+        <desc>
+          File mode.
+        </desc>
+      </param>
+      <param name="flags" type="unsigned long" dir="in">
+        <desc>
+          Additional flags. Not used at the moment and must be set to 0.
         </desc>
       </param>
Index: /trunk/src/VBox/Main/include/GuestImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/GuestImpl.h	(revision 33897)
+++ /trunk/src/VBox/Main/include/GuestImpl.h	(revision 33898)
@@ -102,4 +102,5 @@
     STDMETHOD(GetProcessStatus)(ULONG aPID, ULONG *aExitCode, ULONG *aFlags, ULONG *aStatus);
     STDMETHOD(CopyToGuest)(IN_BSTR aSource, IN_BSTR aDest, IN_BSTR aUserName, IN_BSTR aPassword, ULONG aFlags, IProgress **aProgress);
+    STDMETHOD(CreateDirectory)(IN_BSTR aDirectory, IN_BSTR aUserName, IN_BSTR aPassword, ULONG aMode, ULONG aFlags, IProgress **aProgress);
     STDMETHOD(InternalGetStatistics)(ULONG *aCpuUser, ULONG *aCpuKernel, ULONG *aCpuIdle,
                                      ULONG *aMemTotal, ULONG *aMemFree, ULONG *aMemBalloon, ULONG *aMemShared, ULONG *aMemCache,
@@ -112,4 +113,6 @@
                                    IN_BSTR aUserName, IN_BSTR aPassword,
                                    ULONG aTimeoutMS, ULONG *aPID, IProgress **aProgress, int *pRC);
+    HRESULT createDirectoryInternal(IN_BSTR aDirectory, IN_BSTR aUserName, IN_BSTR aPassword,
+                                    ULONG aMode, ULONG aFlags, IProgress **aProgress, int *pRC);
     void setAdditionsInfo(Bstr aInterfaceVersion, VBOXOSTYPE aOsType);
     void setAdditionsInfo2(Bstr aAdditionsVersion, Bstr aVersionName, Bstr aRevision);
