VirtualBox

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

Last change on this file since 47908 was 47627, checked in by vboxsync, 11 years ago

Main/GuestCtrl: Reduced locking times, more error checking, adjusted logging.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.2 KB
Line 
1
2/* $Id: GuestDirectoryImpl.cpp 47627 2013-08-09 08:31:24Z vboxsync $ */
3/** @file
4 * VirtualBox Main - Guest directory handling.
5 */
6
7/*
8 * Copyright (C) 2012-2013 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#ifdef LOG_GROUP
33 #undef LOG_GROUP
34#endif
35#define LOG_GROUP LOG_GROUP_GUEST_CONTROL
36#include <VBox/log.h>
37
38
39// constructor / destructor
40/////////////////////////////////////////////////////////////////////////////
41
42DEFINE_EMPTY_CTOR_DTOR(GuestDirectory)
43
44HRESULT GuestDirectory::FinalConstruct(void)
45{
46 LogFlowThisFunc(("\n"));
47 return BaseFinalConstruct();
48}
49
50void GuestDirectory::FinalRelease(void)
51{
52 LogFlowThisFuncEnter();
53 uninit();
54 BaseFinalRelease();
55 LogFlowThisFuncLeave();
56}
57
58// public initializer/uninitializer for internal purposes only
59/////////////////////////////////////////////////////////////////////////////
60
61int GuestDirectory::init(GuestSession *aSession,
62 const Utf8Str &strPath, const Utf8Str &strFilter, uint32_t uFlags)
63{
64 LogFlowThisFunc(("strPath=%s, strFilter=%s, uFlags=%x\n",
65 strPath.c_str(), strFilter.c_str(), uFlags));
66
67 /* Enclose the state transition NotReady->InInit->Ready. */
68 AutoInitSpan autoInitSpan(this);
69 AssertReturn(autoInitSpan.isOk(), E_FAIL);
70
71 mData.mSession = aSession;
72 mData.mName = strPath;
73 mData.mFilter = strFilter;
74 mData.mFlags = uFlags;
75
76 /* Start the directory process on the guest. */
77 GuestProcessStartupInfo procInfo;
78 procInfo.mName = Utf8StrFmt(tr("Reading directory \"%s\"", strPath.c_str()));
79 procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_LS);
80 procInfo.mTimeoutMS = 5 * 60 * 1000; /* 5 minutes timeout. */
81 procInfo.mFlags = ProcessCreateFlag_WaitForStdOut;
82
83 procInfo.mArguments.push_back(Utf8Str("--machinereadable"));
84 /* We want the long output format which contains all the object details. */
85 procInfo.mArguments.push_back(Utf8Str("-l"));
86#if 0 /* Flags are not supported yet. */
87 if (uFlags & DirectoryOpenFlag_NoSymlinks)
88 procInfo.mArguments.push_back(Utf8Str("--nosymlinks")); /** @todo What does GNU here? */
89#endif
90 /** @todo Recursion support? */
91 procInfo.mArguments.push_back(strPath); /* The directory we want to open. */
92
93 /*
94 * Start the process asynchronously and keep it around so that we can use
95 * it later in subsequent read() calls.
96 * Note: No guest rc available because operation is asynchronous.
97 */
98 int rc = mData.mProcessTool.Init(mData.mSession, procInfo,
99 true /* Async */, NULL /* Guest rc */);
100 if (RT_SUCCESS(rc))
101 {
102 /* Confirm a successful initialization when it's the case. */
103 autoInitSpan.setSucceeded();
104 return rc;
105 }
106
107 autoInitSpan.setFailed();
108 return rc;
109}
110
111/**
112 * Uninitializes the instance.
113 * Called from FinalRelease().
114 */
115void GuestDirectory::uninit(void)
116{
117 LogFlowThisFunc(("\n"));
118
119 /* Enclose the state transition Ready->InUninit->NotReady. */
120 AutoUninitSpan autoUninitSpan(this);
121 if (autoUninitSpan.uninitDone())
122 return;
123
124 LogFlowThisFuncLeave();
125}
126
127// implementation of public getters/setters for attributes
128/////////////////////////////////////////////////////////////////////////////
129
130STDMETHODIMP GuestDirectory::COMGETTER(DirectoryName)(BSTR *aName)
131{
132 LogFlowThisFuncEnter();
133
134 CheckComArgOutPointerValid(aName);
135
136 AutoCaller autoCaller(this);
137 if (FAILED(autoCaller.rc())) return autoCaller.rc();
138
139 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
140
141 mData.mName.cloneTo(aName);
142
143 return S_OK;
144}
145
146STDMETHODIMP GuestDirectory::COMGETTER(Filter)(BSTR *aFilter)
147{
148 LogFlowThisFuncEnter();
149
150 CheckComArgOutPointerValid(aFilter);
151
152 AutoCaller autoCaller(this);
153 if (FAILED(autoCaller.rc())) return autoCaller.rc();
154
155 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
156
157 mData.mFilter.cloneTo(aFilter);
158
159 return S_OK;
160}
161
162// private methods
163/////////////////////////////////////////////////////////////////////////////
164
165// implementation of public methods
166/////////////////////////////////////////////////////////////////////////////
167
168STDMETHODIMP GuestDirectory::Close(void)
169{
170#ifndef VBOX_WITH_GUEST_CONTROL
171 ReturnComNotImplemented();
172#else
173 LogFlowThisFuncEnter();
174
175 AutoCaller autoCaller(this);
176 if (FAILED(autoCaller.rc())) return autoCaller.rc();
177
178 AssertPtr(mData.mSession);
179 int rc = mData.mSession->directoryRemoveFromList(this);
180 AssertRC(rc);
181
182 HRESULT hr = S_OK;
183
184 int guestRc;
185 rc = mData.mProcessTool.Terminate(30 * 1000, &guestRc);
186 if (RT_FAILURE(rc))
187 {
188 switch (rc)
189 {
190 case VERR_GSTCTL_GUEST_ERROR:
191 hr = GuestProcess::setErrorExternal(this, guestRc);
192 break;
193
194 case VERR_NOT_SUPPORTED:
195 /* Silently skip old Guest Additions which do not support killing the
196 * the guest directory handling process. */
197 break;
198
199 default:
200 hr = setError(VBOX_E_IPRT_ERROR,
201 tr("Terminating open guest directory \"%s\" failed: %Rrc"),
202 mData.mName.c_str(), rc);
203 break;
204 }
205 }
206
207 /*
208 * Release autocaller before calling uninit.
209 */
210 autoCaller.release();
211
212 uninit();
213
214 LogFlowThisFunc(("Returning rc=%Rrc\n", rc));
215 return hr;
216#endif /* VBOX_WITH_GUEST_CONTROL */
217}
218
219STDMETHODIMP GuestDirectory::Read(IFsObjInfo **aInfo)
220{
221#ifndef VBOX_WITH_GUEST_CONTROL
222 ReturnComNotImplemented();
223#else
224 LogFlowThisFuncEnter();
225
226 AutoCaller autoCaller(this);
227 if (FAILED(autoCaller.rc())) return autoCaller.rc();
228
229 GuestProcessStreamBlock curBlock;
230 int guestRc;
231
232 int rc = mData.mProcessTool.WaitEx(GUESTPROCESSTOOL_FLAG_STDOUT_BLOCK,
233 &curBlock, &guestRc);
234
235 /*
236 * Note: The guest process can still be around to serve the next
237 * upcoming stream block next time.
238 */
239 if ( RT_SUCCESS(rc)
240 && !mData.mProcessTool.IsRunning())
241 {
242 rc = mData.mProcessTool.TerminatedOk(NULL /* Exit code */);
243 if (rc == VERR_NOT_EQUAL)
244 rc = VERR_ACCESS_DENIED;
245 }
246
247 if (RT_SUCCESS(rc))
248 {
249 if (curBlock.GetCount()) /* Did we get content? */
250 {
251 GuestFsObjData objData;
252 rc = objData.FromLs(curBlock);
253 if (RT_FAILURE(rc))
254 rc = VERR_PATH_NOT_FOUND;
255
256 if (RT_SUCCESS(rc))
257 {
258 /* Create the object. */
259 ComObjPtr<GuestFsObjInfo> pFsObjInfo;
260 HRESULT hr2 = pFsObjInfo.createObject();
261 if (FAILED(hr2))
262 rc = VERR_COM_UNEXPECTED;
263
264 if (RT_SUCCESS(rc))
265 rc = pFsObjInfo->init(objData);
266
267 if (RT_SUCCESS(rc))
268 {
269 /* Return info object to the caller. */
270 hr2 = pFsObjInfo.queryInterfaceTo(aInfo);
271 if (FAILED(hr2))
272 rc = VERR_COM_UNEXPECTED;
273 }
274 }
275 }
276 else
277 {
278 /* Nothing to read anymore. Tell the caller. */
279 rc = VERR_NO_MORE_FILES;
280 }
281 }
282
283 HRESULT hr = S_OK;
284
285 if (RT_FAILURE(rc)) /** @todo Add more errors here. */
286 {
287 switch (rc)
288 {
289 case VERR_GSTCTL_GUEST_ERROR:
290 hr = GuestProcess::setErrorExternal(this, guestRc);
291 break;
292
293 case VERR_ACCESS_DENIED:
294 hr = setError(VBOX_E_IPRT_ERROR, tr("Reading directory \"%s\" failed: Unable to read / access denied"),
295 mData.mName.c_str());
296 break;
297
298 case VERR_PATH_NOT_FOUND:
299 hr = setError(VBOX_E_IPRT_ERROR, tr("Reading directory \"%s\" failed: Path not found"),
300 mData.mName.c_str());
301 break;
302
303 case VERR_NO_MORE_FILES:
304 /* See SDK reference. */
305 hr = setError(VBOX_E_OBJECT_NOT_FOUND, tr("No more entries for directory \"%s\""),
306 mData.mName.c_str());
307 break;
308
309 default:
310 hr = setError(VBOX_E_IPRT_ERROR, tr("Error while reading directory \"%s\": %Rrc\n"),
311 mData.mName.c_str(), rc);
312 break;
313 }
314 }
315
316 LogFlowThisFunc(("Returning rc=%Rrc\n", rc));
317 return hr;
318#endif /* VBOX_WITH_GUEST_CONTROL */
319}
320
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