VirtualBox

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

Last change on this file since 42847 was 42846, checked in by vboxsync, 13 years ago

Guest Control 2.0: Update.

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

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