VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/GuestDirectoryImpl.cpp@ 49498

Last change on this file since 49498 was 49349, checked in by vboxsync, 11 years ago

Guest Control:

  • Implemented IGuestSession::DirectoryRemove, IGuestSession::DirectoryRemoveRecursive, IGuestSession::DirectoryRename + IGuestSession::FileRename.
  • Added appropriate commands to VBoxManage (basic support for now).
  • Implemented support for proper guest session process termination via SCM.
  • Implemented support for internal anonymous wait events which are not relying on the public API's VBoxEventType_T.
  • Various bugfixes.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.0 KB
Line 
1
2/* $Id: GuestDirectoryImpl.cpp 49349 2013-10-31 16:40:46Z vboxsync $ */
3/** @file
4 * VirtualBox Main - Guest directory handling.
5 */
6
7/*
8 * Copyright (C) 2012-2013 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19
20/*******************************************************************************
21* Header Files *
22*******************************************************************************/
23#include "GuestDirectoryImpl.h"
24#include "GuestSessionImpl.h"
25#include "GuestCtrlImplPrivate.h"
26
27#include "Global.h"
28#include "AutoCaller.h"
29
30#include <VBox/com/array.h>
31
32#ifdef LOG_GROUP
33 #undef LOG_GROUP
34#endif
35#define LOG_GROUP LOG_GROUP_GUEST_CONTROL
36#include <VBox/log.h>
37
38
39// constructor / destructor
40/////////////////////////////////////////////////////////////////////////////
41
42DEFINE_EMPTY_CTOR_DTOR(GuestDirectory)
43
44HRESULT GuestDirectory::FinalConstruct(void)
45{
46 LogFlowThisFunc(("\n"));
47 return BaseFinalConstruct();
48}
49
50void GuestDirectory::FinalRelease(void)
51{
52 LogFlowThisFuncEnter();
53 uninit();
54 BaseFinalRelease();
55 LogFlowThisFuncLeave();
56}
57
58// public initializer/uninitializer for internal purposes only
59/////////////////////////////////////////////////////////////////////////////
60
61int GuestDirectory::init(Console *pConsole, GuestSession *pSession,
62 ULONG uDirID, const GuestDirectoryOpenInfo &openInfo)
63{
64 LogFlowThisFunc(("pConsole=%p, pSession=%p, uDirID=%RU32, strPath=%s, strFilter=%s, uFlags=%x\n",
65 pConsole, pSession, uDirID, openInfo.mPath.c_str(), openInfo.mFilter.c_str(),
66 openInfo.mFlags));
67
68 AssertPtrReturn(pConsole, VERR_INVALID_POINTER);
69 AssertPtrReturn(pSession, VERR_INVALID_POINTER);
70
71 /* Enclose the state transition NotReady->InInit->Ready. */
72 AutoInitSpan autoInitSpan(this);
73 AssertReturn(autoInitSpan.isOk(), E_FAIL);
74
75#ifndef VBOX_WITH_GUEST_CONTROL
76 autoInitSpan.setSucceeded();
77 return VINF_SUCCESS;
78#else
79 int vrc = bindToSession(pConsole, pSession, uDirID /* Object ID */);
80 if (RT_SUCCESS(vrc))
81 {
82 mSession = pSession;
83
84 mData.mID = uDirID;
85 mData.mOpenInfo = openInfo;
86 }
87
88 if (RT_SUCCESS(vrc))
89 {
90 /* Start the directory process on the guest. */
91 GuestProcessStartupInfo procInfo;
92 procInfo.mName = Utf8StrFmt(tr("Reading directory \"%s\"", openInfo.mPath.c_str()));
93 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_LS);
94 procInfo.mTimeoutMS = 5 * 60 * 1000; /* 5 minutes timeout. */
95 procInfo.mFlags = ProcessCreateFlag_WaitForStdOut;
96
97 procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
98 /* We want the long output format which contains all the object details. */
99 procInfo.mArguments.push_back(Utf8Str("-l"));
100#if 0 /* Flags are not supported yet. */
101 if (uFlags & DirectoryOpenFlag_NoSymlinks)
102 procInfo.mArguments.push_back(Utf8Str("--nosymlinks")); /** @todo What does GNU here? */
103#endif
104 /** @todo Recursion support? */
105 procInfo.mArguments.push_back(openInfo.mPath); /* The directory we want to open. */
106
107 /*
108 * Start the process asynchronously and keep it around so that we can use
109 * it later in subsequent read() calls.
110 * Note: No guest rc available because operation is asynchronous.
111 */
112 vrc = mData.mProcessTool.Init(mSession, procInfo,
113 true /* Async */, NULL /* Guest rc */);
114 }
115
116 if (RT_SUCCESS(vrc))
117 {
118 /* Confirm a successful initialization when it's the case. */
119 autoInitSpan.setSucceeded();
120 return vrc;
121 }
122 else
123 autoInitSpan.setFailed();
124
125 return vrc;
126#endif /* VBOX_WITH_GUEST_CONTROL */
127}
128
129/**
130 * Uninitializes the instance.
131 * Called from FinalRelease().
132 */
133void GuestDirectory::uninit(void)
134{
135 LogFlowThisFunc(("\n"));
136
137 /* Enclose the state transition Ready->InUninit->NotReady. */
138 AutoUninitSpan autoUninitSpan(this);
139 if (autoUninitSpan.uninitDone())
140 return;
141
142 LogFlowThisFuncLeave();
143}
144
145// implementation of public getters/setters for attributes
146/////////////////////////////////////////////////////////////////////////////
147
148STDMETHODIMP GuestDirectory::COMGETTER(DirectoryName)(BSTR *aName)
149{
150 LogFlowThisFuncEnter();
151
152 CheckComArgOutPointerValid(aName);
153
154 AutoCaller autoCaller(this);
155 if (FAILED(autoCaller.rc())) return autoCaller.rc();
156
157 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
158
159 mData.mOpenInfo.mPath.cloneTo(aName);
160
161 return S_OK;
162}
163
164STDMETHODIMP GuestDirectory::COMGETTER(Filter)(BSTR *aFilter)
165{
166 LogFlowThisFuncEnter();
167
168 CheckComArgOutPointerValid(aFilter);
169
170 AutoCaller autoCaller(this);
171 if (FAILED(autoCaller.rc())) return autoCaller.rc();
172
173 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
174
175 mData.mOpenInfo.mFilter.cloneTo(aFilter);
176
177 return S_OK;
178}
179
180// private methods
181/////////////////////////////////////////////////////////////////////////////
182
183int GuestDirectory::callbackDispatcher(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
184{
185 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
186 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
187
188 LogFlowThisFunc(("strPath=%s, uContextID=%RU32, uFunction=%RU32, pSvcCb=%p\n",
189 mData.mOpenInfo.mPath.c_str(), pCbCtx->uContextID, pCbCtx->uFunction, pSvcCb));
190
191 int vrc;
192 switch (pCbCtx->uFunction)
193 {
194 case GUEST_DIR_NOTIFY:
195 {
196 int idx = 1; /* Current parameter index. */
197 CALLBACKDATA_DIR_NOTIFY dataCb;
198 /* pSvcCb->mpaParms[0] always contains the context ID. */
199 pSvcCb->mpaParms[idx++].getUInt32(&dataCb.uType);
200 pSvcCb->mpaParms[idx++].getUInt32(&dataCb.rc);
201
202 int guestRc = (int)dataCb.rc; /* uint32_t vs. int. */
203
204 LogFlowFunc(("uType=%RU32, guestRc=%Rrc\n",
205 dataCb.uType, guestRc));
206
207 switch (dataCb.uType)
208 {
209 /* Nothing here yet, nothing to dispatch further. */
210
211 default:
212 vrc = VERR_NOT_SUPPORTED;
213 break;
214 }
215 break;
216 }
217
218 default:
219 /* Silently ignore not implemented functions. */
220 vrc = VERR_NOT_SUPPORTED;
221 break;
222 }
223
224#ifdef DEBUG
225 LogFlowFuncLeaveRC(vrc);
226#endif
227 return vrc;
228}
229
230/* static */
231Utf8Str GuestDirectory::guestErrorToString(int guestRc)
232{
233 Utf8Str strError;
234
235 /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */
236 switch (guestRc)
237 {
238 case VERR_DIR_NOT_EMPTY:
239 strError += Utf8StrFmt("Directoy is not empty");
240 break;
241
242 default:
243 strError += Utf8StrFmt("%Rrc", guestRc);
244 break;
245 }
246
247 return strError;
248}
249
250/* static */
251HRESULT GuestDirectory::setErrorExternal(VirtualBoxBase *pInterface, int guestRc)
252{
253 AssertPtr(pInterface);
254 AssertMsg(RT_FAILURE(guestRc), ("Guest rc does not indicate a failure when setting error\n"));
255
256 return pInterface->setError(VBOX_E_IPRT_ERROR, GuestDirectory::guestErrorToString(guestRc).c_str());
257}
258
259// implementation of public methods
260/////////////////////////////////////////////////////////////////////////////
261
262STDMETHODIMP GuestDirectory::Close(void)
263{
264#ifndef VBOX_WITH_GUEST_CONTROL
265 ReturnComNotImplemented();
266#else
267 LogFlowThisFuncEnter();
268
269 AutoCaller autoCaller(this);
270 if (FAILED(autoCaller.rc())) return autoCaller.rc();
271
272 AssertPtr(mSession);
273 int rc = mSession->directoryRemoveFromList(this);
274 AssertRC(rc);
275
276 HRESULT hr = S_OK;
277
278 int guestRc;
279 rc = mData.mProcessTool.Terminate(30 * 1000, &guestRc);
280 if (RT_FAILURE(rc))
281 {
282 switch (rc)
283 {
284 case VERR_GSTCTL_GUEST_ERROR:
285 hr = GuestProcess::setErrorExternal(this, guestRc);
286 break;
287
288 case VERR_NOT_SUPPORTED:
289 /* Silently skip old Guest Additions which do not support killing the
290 * the guest directory handling process. */
291 break;
292
293 default:
294 hr = setError(VBOX_E_IPRT_ERROR,
295 tr("Terminating open guest directory \"%s\" failed: %Rrc"),
296 mData.mOpenInfo.mPath.c_str(), rc);
297 break;
298 }
299 }
300
301 /*
302 * Release autocaller before calling uninit.
303 */
304 autoCaller.release();
305
306 uninit();
307
308 LogFlowThisFunc(("Returning rc=%Rrc\n", rc));
309 return hr;
310#endif /* VBOX_WITH_GUEST_CONTROL */
311}
312
313STDMETHODIMP GuestDirectory::Read(IFsObjInfo **aInfo)
314{
315#ifndef VBOX_WITH_GUEST_CONTROL
316 ReturnComNotImplemented();
317#else
318 LogFlowThisFuncEnter();
319
320 AutoCaller autoCaller(this);
321 if (FAILED(autoCaller.rc())) return autoCaller.rc();
322
323 GuestProcessStreamBlock curBlock;
324 int guestRc;
325
326 int rc = mData.mProcessTool.WaitEx(GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK,
327 &curBlock, &guestRc);
328
329 /*
330 * Note: The guest process can still be around to serve the next
331 * upcoming stream block next time.
332 */
333 if ( RT_SUCCESS(rc)
334 && !mData.mProcessTool.IsRunning())
335 {
336 rc = mData.mProcessTool.TerminatedOk(NULL /* Exit code */);
337 if (rc == VERR_NOT_EQUAL)
338 rc = VERR_ACCESS_DENIED;
339 }
340
341 if (RT_SUCCESS(rc))
342 {
343 if (curBlock.GetCount()) /* Did we get content? */
344 {
345 GuestFsObjData objData;
346 rc = objData.FromLs(curBlock);
347 if (RT_FAILURE(rc))
348 rc = VERR_PATH_NOT_FOUND;
349
350 if (RT_SUCCESS(rc))
351 {
352 /* Create the object. */
353 ComObjPtr<GuestFsObjInfo> pFsObjInfo;
354 HRESULT hr2 = pFsObjInfo.createObject();
355 if (FAILED(hr2))
356 rc = VERR_COM_UNEXPECTED;
357
358 if (RT_SUCCESS(rc))
359 rc = pFsObjInfo->init(objData);
360
361 if (RT_SUCCESS(rc))
362 {
363 /* Return info object to the caller. */
364 hr2 = pFsObjInfo.queryInterfaceTo(aInfo);
365 if (FAILED(hr2))
366 rc = VERR_COM_UNEXPECTED;
367 }
368 }
369 }
370 else
371 {
372 /* Nothing to read anymore. Tell the caller. */
373 rc = VERR_NO_MORE_FILES;
374 }
375 }
376
377 HRESULT hr = S_OK;
378
379 if (RT_FAILURE(rc)) /** @todo Add more errors here. */
380 {
381 switch (rc)
382 {
383 case VERR_GSTCTL_GUEST_ERROR:
384 hr = GuestProcess::setErrorExternal(this, guestRc);
385 break;
386
387 case VERR_ACCESS_DENIED:
388 hr = setError(VBOX_E_IPRT_ERROR, tr("Reading directory \"%s\" failed: Unable to read / access denied"),
389 mData.mOpenInfo.mPath.c_str());
390 break;
391
392 case VERR_PATH_NOT_FOUND:
393 hr = setError(VBOX_E_IPRT_ERROR, tr("Reading directory \"%s\" failed: Path not found"),
394 mData.mOpenInfo.mPath.c_str());
395 break;
396
397 case VERR_NO_MORE_FILES:
398 /* See SDK reference. */
399 hr = setError(VBOX_E_OBJECT_NOT_FOUND, tr("No more entries for directory \"%s\""),
400 mData.mOpenInfo.mPath.c_str());
401 break;
402
403 default:
404 hr = setError(VBOX_E_IPRT_ERROR, tr("Error while reading directory \"%s\": %Rrc\n"),
405 mData.mOpenInfo.mPath.c_str(), rc);
406 break;
407 }
408 }
409
410 LogFlowThisFunc(("Returning rc=%Rrc\n", rc));
411 return hr;
412#endif /* VBOX_WITH_GUEST_CONTROL */
413}
414
Note: See TracBrowser for help on using the repository browser.

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