diff options
Diffstat (limited to 'src/VBox/Main/src-client/GuestDirectoryImpl.cpp')
-rw-r--r-- | src/VBox/Main/src-client/GuestDirectoryImpl.cpp | 236 |
1 files changed, 181 insertions, 55 deletions
diff --git a/src/VBox/Main/src-client/GuestDirectoryImpl.cpp b/src/VBox/Main/src-client/GuestDirectoryImpl.cpp index 36d262b9..52d0cf95 100644 --- a/src/VBox/Main/src-client/GuestDirectoryImpl.cpp +++ b/src/VBox/Main/src-client/GuestDirectoryImpl.cpp @@ -1,11 +1,11 @@ /* $Id: GuestDirectoryImpl.cpp $ */ /** @file - * VirtualBox Main - XXX. + * VirtualBox Main - Guest directory handling. */ /* - * Copyright (C) 2012 Oracle Corporation + * Copyright (C) 2012-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -58,54 +58,72 @@ void GuestDirectory::FinalRelease(void) // public initializer/uninitializer for internal purposes only ///////////////////////////////////////////////////////////////////////////// -int GuestDirectory::init(GuestSession *aSession, - const Utf8Str &strPath, const Utf8Str &strFilter, uint32_t uFlags) +int GuestDirectory::init(Console *pConsole, GuestSession *pSession, + ULONG uDirID, const GuestDirectoryOpenInfo &openInfo) { - LogFlowThisFunc(("strPath=%s, strFilter=%s, uFlags=%x\n", - strPath.c_str(), strFilter.c_str(), uFlags)); + 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. */ AutoInitSpan autoInitSpan(this); 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. */ + /** @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 */); + } - /* - * 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)) + if (RT_SUCCESS(vrc)) { /* Confirm a successful initialization when it's the case. */ autoInitSpan.setSucceeded(); - return rc; + return vrc; } + else + autoInitSpan.setFailed(); - autoInitSpan.setFailed(); - return rc; + return vrc; +#endif /* VBOX_WITH_GUEST_CONTROL */ } /** @@ -114,7 +132,7 @@ int GuestDirectory::init(GuestSession *aSession, */ void GuestDirectory::uninit(void) { - LogFlowThisFunc(("\n")); + LogFlowThisFuncEnter(); /* Enclose the state transition Ready->InUninit->NotReady. */ AutoUninitSpan autoUninitSpan(this); @@ -138,7 +156,7 @@ STDMETHODIMP GuestDirectory::COMGETTER(DirectoryName)(BSTR *aName) AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - mData.mName.cloneTo(aName); + mData.mOpenInfo.mPath.cloneTo(aName); return S_OK; } @@ -154,7 +172,7 @@ STDMETHODIMP GuestDirectory::COMGETTER(Filter)(BSTR *aFilter) AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS); - mData.mFilter.cloneTo(aFilter); + mData.mOpenInfo.mFilter.cloneTo(aFilter); return S_OK; } @@ -162,6 +180,96 @@ STDMETHODIMP GuestDirectory::COMGETTER(Filter)(BSTR *aFilter) // 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; +} + +/** + * Called by IGuestSession right before this directory gets + * removed from the public directory list. + */ +int GuestDirectory::onRemove(void) +{ + LogFlowThisFuncEnter(); + + int vrc = VINF_SUCCESS; + + LogFlowFuncLeaveRC(vrc); + return vrc; +} + +/* 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 ///////////////////////////////////////////////////////////////////////////// @@ -175,20 +283,38 @@ STDMETHODIMP GuestDirectory::Close(void) AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); - AssertPtr(mData.mSession); - int rc = mData.mSession->directoryRemoveFromList(this); + HRESULT hr = S_OK; + + int guestRc; + int rc = mData.mProcessTool.Terminate(30 * 1000, &guestRc); + if (RT_FAILURE(rc)) + { + switch (rc) + { + case VERR_GSTCTL_GUEST_ERROR: + hr = GuestProcess::setErrorExternal(this, guestRc); + break; - mData.mProcessTool.Terminate(); + case VERR_NOT_SUPPORTED: + /* Silently skip old Guest Additions which do not support killing the + * the guest directory handling process. */ + break; - /* - * Release autocaller before calling uninit. - */ - autoCaller.release(); + default: + hr = setError(VBOX_E_IPRT_ERROR, + tr("Terminating open guest directory \"%s\" failed: %Rrc"), + mData.mOpenInfo.mPath.c_str(), rc); + break; + } + } - uninit(); + AssertPtr(mSession); + int rc2 = mSession->directoryRemoveFromList(this); + if (RT_SUCCESS(rc)) + rc = rc2; - LogFlowFuncLeaveRC(rc); - return S_OK; + LogFlowThisFunc(("Returning rc=%Rrc\n", rc)); + return hr; #endif /* VBOX_WITH_GUEST_CONTROL */ } @@ -262,34 +388,34 @@ STDMETHODIMP GuestDirectory::Read(IFsObjInfo **aInfo) { switch (rc) { - case VERR_GENERAL_FAILURE: /** @todo Special guest control rc needed! */ + case VERR_GSTCTL_GUEST_ERROR: hr = GuestProcess::setErrorExternal(this, guestRc); break; 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; case VERR_NO_MORE_FILES: /* 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; } } - LogFlowFuncLeaveRC(rc); + LogFlowThisFunc(("Returning rc=%Rrc\n", rc)); return hr; #endif /* VBOX_WITH_GUEST_CONTROL */ } |