Index: trunk/src/VBox/Main/src-client/GuestDirectoryImpl.cpp
===================================================================
--- trunk/src/VBox/Main/src-client/GuestDirectoryImpl.cpp	(revision 47627)
+++ trunk/src/VBox/Main/src-client/GuestDirectoryImpl.cpp	(revision 49349)
@@ -59,9 +59,13 @@
 /////////////////////////////////////////////////////////////////////////////
 
-int GuestDirectory::init(GuestSession *aSession,
-                         const Utf8Str &strPath, const Utf8Str &strFilter, uint32_t uFlags)
-{
-    LogFlowThisFunc(("strPath=%s, strFilter=%s, uFlags=%x\n",
-                     strPath.c_str(), strFilter.c_str(), uFlags));
+int GuestDirectory::init(Console *pConsole, GuestSession *pSession,
+                         ULONG uDirID, const GuestDirectoryOpenInfo &openInfo)
+{
+    LogFlowThisFunc(("pConsole=%p, pSession=%p, uDirID=%RU32, strPath=%s, strFilter=%s, uFlags=%x\n",
+                     pConsole, pSession, uDirID, openInfo.mPath.c_str(), openInfo.mFilter.c_str(),
+                     openInfo.mFlags));
+
+    AssertPtrReturn(pConsole, VERR_INVALID_POINTER);
+    AssertPtrReturn(pSession, VERR_INVALID_POINTER);
 
     /* Enclose the state transition NotReady->InInit->Ready. */
@@ -69,42 +73,56 @@
     AssertReturn(autoInitSpan.isOk(), E_FAIL);
 
-    mData.mSession = aSession;
-    mData.mName    = strPath;
-    mData.mFilter  = strFilter;
-    mData.mFlags   = uFlags;
-
-    /* Start the directory process on the guest. */
-    GuestProcessStartupInfo procInfo;
-    procInfo.mName      = Utf8StrFmt(tr("Reading directory \"%s\"", strPath.c_str()));
-    procInfo.mCommand   = Utf8Str(VBOXSERVICE_TOOL_LS);
-    procInfo.mTimeoutMS = 5 * 60 * 1000; /* 5 minutes timeout. */
-    procInfo.mFlags     = ProcessCreateFlag_WaitForStdOut;
-
-    procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
-    /* We want the long output format which contains all the object details. */
-    procInfo.mArguments.push_back(Utf8Str("-l"));
+#ifndef VBOX_WITH_GUEST_CONTROL
+    autoInitSpan.setSucceeded();
+    return VINF_SUCCESS;
+#else
+    int vrc = bindToSession(pConsole, pSession, uDirID /* Object ID */);
+    if (RT_SUCCESS(vrc))
+    {
+        mSession = pSession;
+
+        mData.mID = uDirID;
+        mData.mOpenInfo = openInfo;
+    }
+
+    if (RT_SUCCESS(vrc))
+    {
+        /* Start the directory process on the guest. */
+        GuestProcessStartupInfo procInfo;
+        procInfo.mName      = Utf8StrFmt(tr("Reading directory \"%s\"", openInfo.mPath.c_str()));
+        procInfo.mCommand   = Utf8Str(VBOXSERVICE_TOOL_LS);
+        procInfo.mTimeoutMS = 5 * 60 * 1000; /* 5 minutes timeout. */
+        procInfo.mFlags     = ProcessCreateFlag_WaitForStdOut;
+
+        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? */
+        if (uFlags & DirectoryOpenFlag_NoSymlinks)
+            procInfo.mArguments.push_back(Utf8Str("--nosymlinks")); /** @todo What does GNU here? */
 #endif
-    /** @todo Recursion support? */
-    procInfo.mArguments.push_back(strPath); /* The directory we want to open. */
-
-    /*
-     * Start the process asynchronously and keep it around so that we can use
-     * it later in subsequent read() calls.
-     * Note: No guest rc available because operation is asynchronous.
-     */
-    int rc = mData.mProcessTool.Init(mData.mSession, procInfo,
-                                     true /* Async */, NULL /* Guest rc */);
-    if (RT_SUCCESS(rc))
+        /** @todo Recursion support? */
+        procInfo.mArguments.push_back(openInfo.mPath); /* The directory we want to open. */
+
+        /*
+         * Start the process asynchronously and keep it around so that we can use
+         * it later in subsequent read() calls.
+         * Note: No guest rc available because operation is asynchronous.
+         */
+        vrc = mData.mProcessTool.Init(mSession, procInfo,
+                                      true /* Async */, NULL /* Guest rc */);
+    }
+
+    if (RT_SUCCESS(vrc))
     {
         /* Confirm a successful initialization when it's the case. */
         autoInitSpan.setSucceeded();
-        return rc;
-    }
-
-    autoInitSpan.setFailed();
-    return rc;
+        return vrc;
+    }
+    else
+        autoInitSpan.setFailed();
+
+    return vrc;
+#endif /* VBOX_WITH_GUEST_CONTROL */
 }
 
@@ -139,5 +157,5 @@
     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-    mData.mName.cloneTo(aName);
+    mData.mOpenInfo.mPath.cloneTo(aName);
 
     return S_OK;
@@ -155,5 +173,5 @@
     AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
 
-    mData.mFilter.cloneTo(aFilter);
+    mData.mOpenInfo.mFilter.cloneTo(aFilter);
 
     return S_OK;
@@ -162,4 +180,80 @@
 // private methods
 /////////////////////////////////////////////////////////////////////////////
+
+int GuestDirectory::callbackDispatcher(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
+{
+    AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
+    AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
+
+    LogFlowThisFunc(("strPath=%s, uContextID=%RU32, uFunction=%RU32, pSvcCb=%p\n",
+                     mData.mOpenInfo.mPath.c_str(), pCbCtx->uContextID, pCbCtx->uFunction, pSvcCb));
+
+    int vrc;
+    switch (pCbCtx->uFunction)
+    {
+        case GUEST_DIR_NOTIFY:
+        {
+            int idx = 1; /* Current parameter index. */
+            CALLBACKDATA_DIR_NOTIFY dataCb;
+            /* pSvcCb->mpaParms[0] always contains the context ID. */
+            pSvcCb->mpaParms[idx++].getUInt32(&dataCb.uType);
+            pSvcCb->mpaParms[idx++].getUInt32(&dataCb.rc);
+
+            int guestRc = (int)dataCb.rc; /* uint32_t vs. int. */
+
+            LogFlowFunc(("uType=%RU32, guestRc=%Rrc\n",
+                         dataCb.uType, guestRc));
+
+            switch (dataCb.uType)
+            {
+                /* Nothing here yet, nothing to dispatch further. */
+
+                default:
+                    vrc = VERR_NOT_SUPPORTED;
+                    break;
+            }
+            break;
+        }
+
+        default:
+            /* Silently ignore not implemented functions. */
+            vrc = VERR_NOT_SUPPORTED;
+            break;
+    }
+
+#ifdef DEBUG
+    LogFlowFuncLeaveRC(vrc);
+#endif
+    return vrc;
+}
+
+/* static */
+Utf8Str GuestDirectory::guestErrorToString(int guestRc)
+{
+    Utf8Str strError;
+
+    /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */
+    switch (guestRc)
+    {
+        case VERR_DIR_NOT_EMPTY:
+            strError += Utf8StrFmt("Directoy is not empty");
+            break;
+
+        default:
+            strError += Utf8StrFmt("%Rrc", guestRc);
+            break;
+    }
+
+    return strError;
+}
+
+/* static */
+HRESULT GuestDirectory::setErrorExternal(VirtualBoxBase *pInterface, int guestRc)
+{
+    AssertPtr(pInterface);
+    AssertMsg(RT_FAILURE(guestRc), ("Guest rc does not indicate a failure when setting error\n"));
+
+    return pInterface->setError(VBOX_E_IPRT_ERROR, GuestDirectory::guestErrorToString(guestRc).c_str());
+}
 
 // implementation of public methods
@@ -176,6 +270,6 @@
     if (FAILED(autoCaller.rc())) return autoCaller.rc();
 
-    AssertPtr(mData.mSession);
-    int rc = mData.mSession->directoryRemoveFromList(this);
+    AssertPtr(mSession);
+    int rc = mSession->directoryRemoveFromList(this);
     AssertRC(rc);
 
@@ -188,5 +282,5 @@
         switch (rc)
         {
-           case VERR_GSTCTL_GUEST_ERROR:
+            case VERR_GSTCTL_GUEST_ERROR:
                 hr = GuestProcess::setErrorExternal(this, guestRc);
                 break;
@@ -200,5 +294,5 @@
                 hr = setError(VBOX_E_IPRT_ERROR,
                               tr("Terminating open guest directory \"%s\" failed: %Rrc"),
-                              mData.mName.c_str(), rc);
+                              mData.mOpenInfo.mPath.c_str(), rc);
                 break;
         }
@@ -293,10 +387,10 @@
             case VERR_ACCESS_DENIED:
                 hr = setError(VBOX_E_IPRT_ERROR, tr("Reading directory \"%s\" failed: Unable to read / access denied"),
-                              mData.mName.c_str());
+                              mData.mOpenInfo.mPath.c_str());
                 break;
 
             case VERR_PATH_NOT_FOUND:
                 hr = setError(VBOX_E_IPRT_ERROR, tr("Reading directory \"%s\" failed: Path not found"),
-                              mData.mName.c_str());
+                              mData.mOpenInfo.mPath.c_str());
                 break;
 
@@ -304,10 +398,10 @@
                 /* See SDK reference. */
                 hr = setError(VBOX_E_OBJECT_NOT_FOUND, tr("No more entries for directory \"%s\""),
-                              mData.mName.c_str());
+                              mData.mOpenInfo.mPath.c_str());
                 break;
 
             default:
                 hr = setError(VBOX_E_IPRT_ERROR, tr("Error while reading directory \"%s\": %Rrc\n"),
-                              mData.mName.c_str(), rc);
+                              mData.mOpenInfo.mPath.c_str(), rc);
                 break;
         }
