VirtualBox

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

Last change on this file since 56268 was 55645, checked in by vboxsync, 10 years ago

Removed 106 #ifdef/#ifndef VBOX_WITH_GUEST_CONTROL statements that was never really necessary.

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