VirtualBox

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

Last change on this file since 71314 was 71302, checked in by vboxsync, 7 years ago

Guest Control: Guest directory creation fixes.

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