VirtualBox

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

Last change on this file since 73037 was 73036, checked in by vboxsync, 6 years ago

Guest Control/Main: Renamed VERR_GSTCTL_PROCESS_EXIT_CODE -> VERR_GSTCTL_PROCESS_EXIT_CODE and GuestProcessTool::terminatedOk() -> GuestProcessTool::getTerminationStatus() to better emphasize its usage and catch errors easier.

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