VirtualBox

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

Last change on this file since 43061 was 42897, checked in by vboxsync, 12 years ago

Guest Control 2.0: Bugfixes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.6 KB
Line 
1
2/* $Id: GuestDirectoryImpl.cpp 42897 2012-08-21 10:03:52Z vboxsync $ */
3/** @file
4 * VirtualBox Main - XXX.
5 */
6
7/*
8 * Copyright (C) 2012 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(GuestSession *aSession,
62 const Utf8Str &strPath, const Utf8Str &strFilter /*= ""*/, uint32_t uFlags /*= 0*/)
63{
64 LogFlowThisFunc(("strPath=%s, strFilter=%s, uFlags=%x\n",
65 strPath.c_str(), strFilter.c_str(), uFlags));
66
67 /* Enclose the state transition NotReady->InInit->Ready. */
68 AutoInitSpan autoInitSpan(this);
69 AssertReturn(autoInitSpan.isOk(), E_FAIL);
70
71 mData.mSession = aSession;
72 mData.mName = strPath;
73 mData.mFilter = strFilter;
74 mData.mFlags = uFlags;
75
76 /* Start the directory process on the guest. */
77 GuestProcessStartupInfo procInfo;
78 procInfo.mName = Utf8StrFmt(tr("Reading directory \"%s\"", strPath.c_str()));
79 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_LS);
80 procInfo.mTimeoutMS = 0; /* No timeout. */
81 procInfo.mFlags = ProcessCreateFlag_Hidden | ProcessCreateFlag_WaitForStdOut;
82
83 procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
84 /* We want the long output format which contains all the object details. */
85 procInfo.mArguments.push_back(Utf8Str("-l"));
86#if 0 /* Flags are not supported yet. */
87 if (uFlags & DirectoryOpenFlag_NoSymlinks)
88 procInfo.mArguments.push_back(Utf8Str("--nosymlinks")); /** @todo What does GNU here? */
89#endif
90 /** @todo Recursion support? */
91 procInfo.mArguments.push_back(strPath); /* The directory we want to open. */
92
93 /*
94 * Start the process asynchronously and keep it around so that we can use
95 * it later in subsequent read() calls.
96 */
97 ComObjPtr<GuestProcess> pProcess;
98 int rc = mData.mSession->processCreateExInteral(procInfo, pProcess);
99 if (RT_SUCCESS(rc))
100 rc = pProcess->startProcessAsync();
101
102 LogFlowThisFunc(("rc=%Rrc\n", rc));
103
104 if (RT_SUCCESS(rc))
105 {
106 mData.mProcess = pProcess;
107
108 /* Confirm a successful initialization when it's the case. */
109 autoInitSpan.setSucceeded();
110 return rc;
111 }
112
113 autoInitSpan.setFailed();
114 return rc;
115}
116
117/**
118 * Uninitializes the instance.
119 * Called from FinalRelease().
120 */
121void GuestDirectory::uninit(void)
122{
123 LogFlowThisFunc(("\n"));
124
125 /* Enclose the state transition Ready->InUninit->NotReady. */
126 AutoUninitSpan autoUninitSpan(this);
127 if (autoUninitSpan.uninitDone())
128 return;
129
130 LogFlowThisFuncLeave();
131}
132
133// implementation of public getters/setters for attributes
134/////////////////////////////////////////////////////////////////////////////
135
136STDMETHODIMP GuestDirectory::COMGETTER(DirectoryName)(BSTR *aName)
137{
138 LogFlowThisFuncEnter();
139
140 CheckComArgOutPointerValid(aName);
141
142 AutoCaller autoCaller(this);
143 if (FAILED(autoCaller.rc())) return autoCaller.rc();
144
145 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
146
147 mData.mName.cloneTo(aName);
148
149 return S_OK;
150}
151
152STDMETHODIMP GuestDirectory::COMGETTER(Filter)(BSTR *aFilter)
153{
154 LogFlowThisFuncEnter();
155
156 CheckComArgOutPointerValid(aFilter);
157
158 AutoCaller autoCaller(this);
159 if (FAILED(autoCaller.rc())) return autoCaller.rc();
160
161 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
162
163 mData.mFilter.cloneTo(aFilter);
164
165 return S_OK;
166}
167
168// private methods
169/////////////////////////////////////////////////////////////////////////////
170
171int GuestDirectory::parseData(GuestProcessStreamBlock &streamBlock)
172{
173 LogFlowThisFunc(("cbStream=%RU32\n", mData.mStream.GetSize()));
174
175 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
176
177 int rc;
178 do
179 {
180 /* Try parsing the data to see if the current block is complete. */
181 rc = mData.mStream.ParseBlock(streamBlock);
182 if (streamBlock.GetCount())
183 break;
184
185 } while (RT_SUCCESS(rc));
186
187 LogFlowFuncLeaveRC(rc);
188 return rc;
189}
190
191// implementation of public methods
192/////////////////////////////////////////////////////////////////////////////
193
194STDMETHODIMP GuestDirectory::Close(void)
195{
196#ifndef VBOX_WITH_GUEST_CONTROL
197 ReturnComNotImplemented();
198#else
199 LogFlowThisFuncEnter();
200
201 AutoCaller autoCaller(this);
202 if (FAILED(autoCaller.rc())) return autoCaller.rc();
203
204 AssertPtr(mData.mSession);
205 int rc = mData.mSession->directoryRemoveFromList(this);
206 if (mData.mProcess)
207 {
208 int rc2 = mData.mSession->processRemoveFromList(mData.mProcess);
209 if (RT_SUCCESS(rc))
210 rc = rc2;
211 }
212
213 /*
214 * Release autocaller before calling uninit.
215 */
216 autoCaller.release();
217
218 uninit();
219
220 LogFlowFuncLeaveRC(rc);
221 return S_OK;
222#endif /* VBOX_WITH_GUEST_CONTROL */
223}
224
225STDMETHODIMP GuestDirectory::Read(IFsObjInfo **aInfo)
226{
227#ifndef VBOX_WITH_GUEST_CONTROL
228 ReturnComNotImplemented();
229#else
230 LogFlowThisFuncEnter();
231
232 AutoCaller autoCaller(this);
233 if (FAILED(autoCaller.rc())) return autoCaller.rc();
234
235 ComObjPtr<GuestProcess> pProcess = mData.mProcess;
236 Assert(!pProcess.isNull());
237
238 GuestProcessStreamBlock streamBlock;
239 GuestFsObjData objData;
240
241 int rc = parseData(streamBlock);
242 if ( RT_FAILURE(rc)
243 || streamBlock.IsEmpty()) /* More data needed. */
244 {
245 rc = pProcess->waitForStart(30 * 1000 /* 30s timeout */);
246 }
247
248 if (RT_SUCCESS(rc))
249 {
250 BYTE byBuf[_64K];
251 size_t cbRead = 0;
252
253 /** @todo Merge with GuestSession::queryFileInfoInternal. */
254 for (;RT_SUCCESS(rc);)
255 {
256 GuestProcessWaitResult waitRes;
257 rc = pProcess->waitFor( ProcessWaitForFlag_Terminate
258 | ProcessWaitForFlag_StdOut,
259 30 * 1000 /* Timeout */, waitRes);
260 if ( RT_FAILURE(rc)
261 || waitRes.mResult == ProcessWaitResult_Terminate
262 || waitRes.mResult == ProcessWaitResult_Error
263 || waitRes.mResult == ProcessWaitResult_Timeout)
264 {
265 if (RT_FAILURE(waitRes.mRC))
266 rc = waitRes.mRC;
267 break;
268 }
269
270 rc = pProcess->readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
271 30 * 1000 /* Timeout */, byBuf, sizeof(byBuf),
272 &cbRead);
273 if (RT_FAILURE(rc))
274 break;
275
276 if (cbRead)
277 {
278 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
279
280 rc = mData.mStream.AddData(byBuf, cbRead);
281 if (RT_FAILURE(rc))
282 break;
283
284 LogFlowThisFunc(("rc=%Rrc, cbRead=%RU64, cbStreamOut=%RU32\n",
285 rc, cbRead, mData.mStream.GetSize()));
286
287 rc = parseData(streamBlock);
288 if (RT_SUCCESS(rc))
289 {
290 /* Parsing the current stream block succeeded so
291 * we don't need more at the moment. */
292 break;
293 }
294 }
295 }
296
297 LogFlowThisFunc(("Reading done with rc=%Rrc, cbRead=%RU64, cbStream=%RU32\n",
298 rc, cbRead, mData.mStream.GetSize()));
299
300 if (RT_SUCCESS(rc))
301 {
302 rc = parseData(streamBlock);
303 if (rc == VERR_NO_DATA) /* Since this is the last parsing call, this is ok. */
304 rc = VINF_SUCCESS;
305 }
306
307 /*
308 * Note: The guest process can still be around to serve the next
309 * upcoming stream block next time.
310 */
311 if (RT_SUCCESS(rc))
312 {
313 /** @todo Move into common function. */
314 ProcessStatus_T procStatus = ProcessStatus_Undefined;
315 LONG exitCode = 0;
316
317 HRESULT hr2 = pProcess->COMGETTER(Status(&procStatus));
318 ComAssertComRC(hr2);
319 hr2 = pProcess->COMGETTER(ExitCode(&exitCode));
320 ComAssertComRC(hr2);
321
322 if ( ( procStatus != ProcessStatus_Started
323 && procStatus != ProcessStatus_Paused
324 && procStatus != ProcessStatus_Terminating
325 )
326 && exitCode != 0)
327 {
328 rc = VERR_ACCESS_DENIED;
329 }
330 }
331 }
332
333 if (RT_SUCCESS(rc))
334 {
335 if (streamBlock.GetCount()) /* Did we get content? */
336 {
337 rc = objData.FromLs(streamBlock);
338 if (RT_FAILURE(rc))
339 rc = VERR_PATH_NOT_FOUND;
340
341 if (RT_SUCCESS(rc))
342 {
343 /* Create the object. */
344 ComObjPtr<GuestFsObjInfo> pFsObjInfo;
345 HRESULT hr2 = pFsObjInfo.createObject();
346 if (FAILED(hr2))
347 rc = VERR_COM_UNEXPECTED;
348
349 if (RT_SUCCESS(rc))
350 rc = pFsObjInfo->init(objData);
351
352 if (RT_SUCCESS(rc))
353 {
354 /* Return info object to the caller. */
355 hr2 = pFsObjInfo.queryInterfaceTo(aInfo);
356 if (FAILED(hr2))
357 rc = VERR_COM_UNEXPECTED;
358 }
359 }
360 }
361 else
362 {
363 /* Nothing to read anymore. Tell the caller. */
364 rc = VERR_NO_MORE_FILES;
365 }
366 }
367
368 HRESULT hr = S_OK;
369
370 if (RT_FAILURE(rc)) /** @todo Add more errors here. */
371 {
372 switch (rc)
373 {
374 case VERR_ACCESS_DENIED:
375 hr = setError(VBOX_E_IPRT_ERROR, tr("Reading directory \"%s\" failed: Unable to read / access denied"),
376 mData.mName.c_str());
377 break;
378
379 case VERR_PATH_NOT_FOUND:
380 hr = setError(VBOX_E_IPRT_ERROR, tr("Reading directory \"%s\" failed: Path not found"),
381 mData.mName.c_str());
382 break;
383
384 case VERR_NO_MORE_FILES:
385 hr = setError(VBOX_E_OBJECT_NOT_FOUND, tr("No more entries for directory \"%s\""),
386 mData.mName.c_str());
387 break;
388
389 default:
390 hr = setError(VBOX_E_IPRT_ERROR, tr("Error while reading directory \"%s\": %Rrc\n"),
391 mData.mName.c_str(), rc);
392 break;
393 }
394 }
395
396 LogFlowFuncLeaveRC(rc);
397 return hr;
398#endif /* VBOX_WITH_GUEST_CONTROL */
399}
400
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