VirtualBox

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

Last change on this file since 63147 was 60622, checked in by vboxsync, 9 years ago

Guest Control: Added proper handling for (VBoxService) toolbox exit codes, resolving various copyto/copyfrom bugs.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.8 KB
Line 
1/* $Id: GuestDirectoryImpl.cpp 60622 2016-04-21 13:00:20Z vboxsync $ */
2/** @file
3 * VirtualBox Main - Guest directory handling.
4 */
5
6/*
7 * Copyright (C) 2012-2016 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.mTimeoutMS = 5 * 60 * 1000; /* 5 minutes timeout. */
92 procInfo.mFlags = ProcessCreateFlag_WaitForStdOut;
93 procInfo.mExecutable= Utf8Str(VBOXSERVICE_TOOL_LS);
94
95 procInfo.mArguments.push_back(procInfo.mExecutable);
96 procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
97 /* We want the long output format which contains all the object details. */
98 procInfo.mArguments.push_back(Utf8Str("-l"));
99#if 0 /* Flags are not supported yet. */
100 if (uFlags & DirectoryOpenFlag_NoSymlinks)
101 procInfo.mArguments.push_back(Utf8Str("--nosymlinks")); /** @todo What does GNU here? */
102#endif
103 /** @todo Recursion support? */
104 procInfo.mArguments.push_back(openInfo.mPath); /* The directory we want to open. */
105
106 /*
107 * Start the process asynchronously and keep it around so that we can use
108 * it later in subsequent read() calls.
109 * Note: No guest rc available because operation is asynchronous.
110 */
111 vrc = mData.mProcessTool.Init(mSession, procInfo,
112 true /* Async */, NULL /* Guest rc */);
113 }
114
115 if (RT_SUCCESS(vrc))
116 {
117 /* Confirm a successful initialization when it's the case. */
118 autoInitSpan.setSucceeded();
119 return vrc;
120 }
121 else
122 autoInitSpan.setFailed();
123
124 return vrc;
125}
126
127/**
128 * Uninitializes the instance.
129 * Called from FinalRelease().
130 */
131void GuestDirectory::uninit(void)
132{
133 LogFlowThisFuncEnter();
134
135 /* Enclose the state transition Ready->InUninit->NotReady. */
136 AutoUninitSpan autoUninitSpan(this);
137 if (autoUninitSpan.uninitDone())
138 return;
139
140 LogFlowThisFuncLeave();
141}
142
143// implementation of private wrapped getters/setters for attributes
144/////////////////////////////////////////////////////////////////////////////
145
146HRESULT GuestDirectory::getDirectoryName(com::Utf8Str &aDirectoryName)
147{
148 LogFlowThisFuncEnter();
149
150 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
151
152 aDirectoryName = mData.mOpenInfo.mPath;
153
154 return S_OK;
155}
156
157HRESULT GuestDirectory::getFilter(com::Utf8Str &aFilter)
158{
159 LogFlowThisFuncEnter();
160
161 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
162
163 aFilter = mData.mOpenInfo.mFilter;
164
165 return S_OK;
166}
167
168// private methods
169/////////////////////////////////////////////////////////////////////////////
170
171int GuestDirectory::i_callbackDispatcher(PVBOXGUESTCTRLHOSTCBCTX pCbCtx, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
172{
173 AssertPtrReturn(pCbCtx, VERR_INVALID_POINTER);
174 AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
175
176 LogFlowThisFunc(("strPath=%s, uContextID=%RU32, uFunction=%RU32, pSvcCb=%p\n",
177 mData.mOpenInfo.mPath.c_str(), pCbCtx->uContextID, pCbCtx->uFunction, pSvcCb));
178
179 int vrc;
180 switch (pCbCtx->uFunction)
181 {
182 case GUEST_DIR_NOTIFY:
183 {
184 int idx = 1; /* Current parameter index. */
185 CALLBACKDATA_DIR_NOTIFY dataCb;
186 /* pSvcCb->mpaParms[0] always contains the context ID. */
187 pSvcCb->mpaParms[idx++].getUInt32(&dataCb.uType);
188 pSvcCb->mpaParms[idx++].getUInt32(&dataCb.rc);
189
190 int guestRc = (int)dataCb.rc; /* uint32_t vs. int. */
191
192 LogFlowFunc(("uType=%RU32, guestRc=%Rrc\n",
193 dataCb.uType, guestRc));
194
195 switch (dataCb.uType)
196 {
197 /* Nothing here yet, nothing to dispatch further. */
198
199 default:
200 vrc = VERR_NOT_SUPPORTED;
201 break;
202 }
203 break;
204 }
205
206 default:
207 /* Silently ignore not implemented functions. */
208 vrc = VERR_NOT_SUPPORTED;
209 break;
210 }
211
212#ifdef DEBUG
213 LogFlowFuncLeaveRC(vrc);
214#endif
215 return vrc;
216}
217
218/* static */
219Utf8Str GuestDirectory::i_guestErrorToString(int guestRc)
220{
221 Utf8Str strError;
222
223 /** @todo pData->u32Flags: int vs. uint32 -- IPRT errors are *negative* !!! */
224 switch (guestRc)
225 {
226 case VERR_DIR_NOT_EMPTY:
227 strError += Utf8StrFmt("Directoy is not empty");
228 break;
229
230 default:
231 strError += Utf8StrFmt("%Rrc", guestRc);
232 break;
233 }
234
235 return strError;
236}
237
238/**
239 * Called by IGuestSession right before this directory gets
240 * removed from the public directory list.
241 */
242int GuestDirectory::i_onRemove(void)
243{
244 LogFlowThisFuncEnter();
245
246 int vrc = VINF_SUCCESS;
247
248 LogFlowFuncLeaveRC(vrc);
249 return vrc;
250}
251
252/* static */
253HRESULT GuestDirectory::i_setErrorExternal(VirtualBoxBase *pInterface, int guestRc)
254{
255 AssertPtr(pInterface);
256 AssertMsg(RT_FAILURE(guestRc), ("Guest rc does not indicate a failure when setting error\n"));
257
258 return pInterface->setError(VBOX_E_IPRT_ERROR, GuestDirectory::i_guestErrorToString(guestRc).c_str());
259}
260
261// implementation of public methods
262/////////////////////////////////////////////////////////////////////////////
263HRESULT GuestDirectory::close()
264{
265 LogFlowThisFuncEnter();
266
267 AutoCaller autoCaller(this);
268 if (FAILED(autoCaller.rc())) return autoCaller.rc();
269
270 HRESULT hr = S_OK;
271
272 int guestRc;
273 int rc = mData.mProcessTool.i_terminate(30 * 1000, &guestRc);
274 if (RT_FAILURE(rc))
275 {
276 switch (rc)
277 {
278 case VERR_GSTCTL_GUEST_ERROR:
279 hr = GuestProcess::i_setErrorExternal(this, guestRc);
280 break;
281
282 case VERR_NOT_SUPPORTED:
283 /* Silently skip old Guest Additions which do not support killing the
284 * the guest directory handling process. */
285 break;
286
287 default:
288 hr = setError(VBOX_E_IPRT_ERROR,
289 tr("Terminating open guest directory \"%s\" failed: %Rrc"),
290 mData.mOpenInfo.mPath.c_str(), rc);
291 break;
292 }
293 }
294
295 AssertPtr(mSession);
296 int rc2 = mSession->i_directoryRemoveFromList(this);
297 if (RT_SUCCESS(rc))
298 rc = rc2;
299
300 LogFlowThisFunc(("Returning rc=%Rrc\n", rc));
301 return hr;
302}
303
304HRESULT GuestDirectory::read(ComPtr<IFsObjInfo> &aObjInfo)
305{
306 LogFlowThisFuncEnter();
307
308 AutoCaller autoCaller(this);
309 if (FAILED(autoCaller.rc())) return autoCaller.rc();
310
311 GuestProcessStreamBlock curBlock;
312 int guestRc;
313
314 int rc = mData.mProcessTool.i_waitEx(GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK,
315 &curBlock, &guestRc);
316
317 /*
318 * Note: The guest process can still be around to serve the next
319 * upcoming stream block next time.
320 */
321 if ( RT_SUCCESS(rc)
322 && !mData.mProcessTool.i_isRunning())
323 {
324 rc = mData.mProcessTool.i_terminatedOk();
325 }
326
327 if (RT_SUCCESS(rc))
328 {
329 if (curBlock.GetCount()) /* Did we get content? */
330 {
331 GuestFsObjData objData;
332 rc = objData.FromLs(curBlock);
333 if (RT_FAILURE(rc))
334 rc = VERR_PATH_NOT_FOUND;
335
336 if (RT_SUCCESS(rc))
337 {
338 /* Create the object. */
339 ComObjPtr<GuestFsObjInfo> pFsObjInfo;
340 HRESULT hr2 = pFsObjInfo.createObject();
341 if (FAILED(hr2))
342 rc = VERR_COM_UNEXPECTED;
343
344 if (RT_SUCCESS(rc))
345 rc = pFsObjInfo->init(objData);
346
347 if (RT_SUCCESS(rc))
348 {
349 /* Return info object to the caller. */
350 hr2 = pFsObjInfo.queryInterfaceTo(aObjInfo.asOutParam());
351 if (FAILED(hr2))
352 rc = VERR_COM_UNEXPECTED;
353 }
354 }
355 }
356 else
357 {
358 /* Nothing to read anymore. Tell the caller. */
359 rc = VERR_NO_MORE_FILES;
360 }
361 }
362
363 HRESULT hr = S_OK;
364
365 if (RT_FAILURE(rc)) /** @todo Add more errors here. */
366 {
367 switch (rc)
368 {
369 case VERR_GSTCTL_GUEST_ERROR:
370 hr = GuestProcess::i_setErrorExternal(this, guestRc);
371 break;
372
373 case VWRN_GSTCTL_PROCESS_EXIT_CODE:
374 hr = setError(VBOX_E_IPRT_ERROR, tr("Reading directory \"%s\" failed: %Rrc"),
375 mData.mOpenInfo.mPath.c_str(), mData.mProcessTool.i_getRc());
376 break;
377
378 case VERR_PATH_NOT_FOUND:
379 hr = setError(VBOX_E_IPRT_ERROR, tr("Reading directory \"%s\" failed: Path not found"),
380 mData.mOpenInfo.mPath.c_str());
381 break;
382
383 case VERR_NO_MORE_FILES:
384 /* See SDK reference. */
385 hr = setError(VBOX_E_OBJECT_NOT_FOUND, tr("No more entries for directory \"%s\""),
386 mData.mOpenInfo.mPath.c_str());
387 break;
388
389 default:
390 hr = setError(VBOX_E_IPRT_ERROR, tr("Error while reading directory \"%s\": %Rrc\n"),
391 mData.mOpenInfo.mPath.c_str(), rc);
392 break;
393 }
394 }
395
396 LogFlowThisFunc(("Returning rc=%Rrc\n", rc));
397 return hr;
398}
399
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