VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/GuestCtrlImplDir.cpp@ 38290

Last change on this file since 38290 was 38290, checked in by vboxsync, 14 years ago

GuestCtrl: Update.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.3 KB
Line 
1/* $Id: */
2/** @file
3 * VirtualBox Guest Control - Guest directory handling.
4 */
5
6/*
7 * Copyright (C) 2011 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#include "GuestImpl.h"
19#include "GuestCtrlImplPrivate.h"
20#include "GuestDirEntryImpl.h"
21
22#include "Global.h"
23#include "ConsoleImpl.h"
24#include "ProgressImpl.h"
25#include "VMMDev.h"
26
27#include "AutoCaller.h"
28#include "Logging.h"
29
30#include <VBox/VMMDev.h>
31#ifdef VBOX_WITH_GUEST_CONTROL
32# include <VBox/com/array.h>
33# include <VBox/com/ErrorInfo.h>
34#endif
35
36STDMETHODIMP Guest::DirectoryClose(ULONG aHandle)
37{
38#ifndef VBOX_WITH_GUEST_CONTROL
39 ReturnComNotImplemented();
40#else /* VBOX_WITH_GUEST_CONTROL */
41 using namespace guestControl;
42
43 if (directoryHandleExists(aHandle))
44 {
45 directoryDestroyHandle(aHandle);
46 return S_OK;
47 }
48
49 return setError(VBOX_E_IPRT_ERROR,
50 Guest::tr("Directory handle is invalid"));
51#endif
52}
53
54STDMETHODIMP Guest::DirectoryCreate(IN_BSTR aDirectory,
55 IN_BSTR aUserName, IN_BSTR aPassword,
56 ULONG aMode, ULONG aFlags)
57{
58#ifndef VBOX_WITH_GUEST_CONTROL
59 ReturnComNotImplemented();
60#else /* VBOX_WITH_GUEST_CONTROL */
61 using namespace guestControl;
62
63 CheckComArgStrNotEmptyOrNull(aDirectory);
64
65 /* Do not allow anonymous executions (with system rights). */
66 if (RT_UNLIKELY((aUserName) == NULL || *(aUserName) == '\0'))
67 return setError(E_INVALIDARG, tr("No user name specified"));
68
69 LogRel(("Creating guest directory \"%s\" as user \"%s\" ...\n",
70 Utf8Str(aDirectory).c_str(), Utf8Str(aUserName).c_str()));
71
72 return directoryCreateInternal(aDirectory,
73 aUserName, aPassword,
74 aMode, aFlags, NULL /* rc */);
75#endif
76}
77
78#ifdef VBOX_WITH_GUEST_CONTROL
79HRESULT Guest::directoryCreateInternal(IN_BSTR aDirectory,
80 IN_BSTR aUsername, IN_BSTR aPassword,
81 ULONG aMode, ULONG aFlags, int *pRC)
82{
83 using namespace guestControl;
84
85 CheckComArgStrNotEmptyOrNull(aDirectory);
86
87 AutoCaller autoCaller(this);
88 if (FAILED(autoCaller.rc())) return autoCaller.rc();
89
90 /* Validate flags. */
91 if (aFlags != DirectoryCreateFlag_None)
92 {
93 if (!(aFlags & DirectoryCreateFlag_Parents))
94 {
95 return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), aFlags);
96 }
97 }
98
99 HRESULT rc = S_OK;
100 try
101 {
102 Utf8Str Utf8Directory(aDirectory);
103
104 com::SafeArray<IN_BSTR> args;
105 com::SafeArray<IN_BSTR> env;
106
107 /*
108 * Prepare tool command line.
109 */
110 if (aFlags & DirectoryCreateFlag_Parents)
111 args.push_back(Bstr("--parents").raw()); /* We also want to create the parent directories. */
112 if (aMode > 0)
113 {
114 args.push_back(Bstr("--mode").raw()); /* Set the creation mode. */
115
116 char szMode[16];
117 RTStrPrintf(szMode, sizeof(szMode), "%o", aMode);
118 args.push_back(Bstr(szMode).raw());
119 }
120 args.push_back(Bstr(Utf8Directory).raw()); /* The directory we want to create. */
121
122 rc = executeAndWaitForTool(Bstr(VBOXSERVICE_TOOL_MKDIR).raw(), Bstr("Creating directory").raw(),
123 ComSafeArrayAsInParam(args),
124 ComSafeArrayAsInParam(env),
125 aUsername, aPassword,
126 NULL /* Progress */, NULL /* PID */);
127 }
128 catch (std::bad_alloc &)
129 {
130 rc = E_OUTOFMEMORY;
131 }
132 return rc;
133}
134
135/**
136 * Creates a new directory handle ID and returns it. Returns VERR_TOO_MUCH_DATA
137 * if no free handles left, otherwise VINF_SUCCESS (or some other IPRT error).
138 *
139 * @return IPRT status code.
140 * @param puHandle Pointer where the handle gets stored to.
141 * @param uPID PID of guest process running the associated "vbox_ls".
142 * @param pszDirectory Directory the handle is assigned to.
143 * @param pszFilter Directory filter. Optional.
144 * @param uFlags Directory open flags.
145 *
146 */
147int Guest::directoryCreateHandle(ULONG *puHandle, ULONG uPID,
148 const char *pszDirectory, const char *pszFilter, ULONG uFlags)
149{
150 AssertPtrReturn(puHandle, VERR_INVALID_POINTER);
151 AssertPtrReturn(pszDirectory, VERR_INVALID_POINTER);
152 /* pszFilter is optional. */
153
154 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
155
156 int rc = VERR_TOO_MUCH_DATA;
157 for (uint32_t i = 0; i < UINT32_MAX - 1; i++)
158 {
159 /* Create a new context ID ... */
160 uint32_t uHandleTry = ASMAtomicIncU32(&mNextDirectoryID);
161 GuestDirectoryMapIter it = mGuestDirectoryMap.find(uHandleTry);
162 if (it == mGuestDirectoryMap.end())
163 {
164 rc = VINF_SUCCESS;
165 if (!RTStrAPrintf(&mGuestDirectoryMap[uHandleTry].mpszDirectory, pszDirectory))
166 rc = VERR_NO_MEMORY;
167 else
168 {
169 /* Filter is optional. */
170 if (pszFilter)
171 {
172 if (!RTStrAPrintf(&mGuestDirectoryMap[uHandleTry].mpszFilter, pszFilter))
173 rc = VERR_NO_MEMORY;
174 }
175
176 if (RT_SUCCESS(rc))
177 {
178 mGuestDirectoryMap[uHandleTry].mPID = uPID;
179 mGuestDirectoryMap[uHandleTry].mFlags = uFlags;
180 *puHandle = uHandleTry;
181
182 break;
183 }
184 }
185
186 if (RT_FAILURE(rc))
187 break;
188
189 Assert(mGuestDirectoryMap.size());
190 }
191 }
192
193 return rc;
194}
195
196/**
197 * Destroys a previously created directory handle and its
198 * associated data.
199 *
200 * @return IPRT status code.
201 * @param uHandle Handle to destroy.
202 */
203void Guest::directoryDestroyHandle(uint32_t uHandle)
204{
205 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
206
207 GuestDirectoryMapIter it = mGuestDirectoryMap.find(uHandle);
208 if (it != mGuestDirectoryMap.end())
209 {
210 RTStrFree(it->second.mpszDirectory);
211 RTStrFree(it->second.mpszFilter);
212
213 /* Destroy raw guest stream buffer - not used
214 * anymore. */
215 it->second.mStream.Destroy();
216
217 /* Remove callback context (not used anymore). */
218 mGuestDirectoryMap.erase(it);
219 }
220}
221
222/**
223 * Gets the associated PID from a directory handle.
224 *
225 * @return uint32_t Associated PID, 0 if handle not found/invalid.
226 * @param uHandle Directory handle to get PID for.
227 */
228uint32_t Guest::directoryGetPID(uint32_t uHandle)
229{
230 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
231
232 GuestDirectoryMapIter it = mGuestDirectoryMap.find(uHandle);
233 if (it != mGuestDirectoryMap.end())
234 return it->second.mPID;
235
236 return 0;
237}
238
239int Guest::directoryGetNextEntry(uint32_t uHandle, GuestProcessStreamBlock &streamBlock)
240{
241 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
242
243 GuestDirectoryMapIter it = mGuestDirectoryMap.find(uHandle);
244 if (it != mGuestDirectoryMap.end())
245 {
246 HRESULT hr = executeStreamCollectBlock(it->second.mPID,
247 it->second.mStream, streamBlock);
248 if (FAILED(hr))
249 return VERR_INVALID_PARAMETER; /** @todo Find better rc! */
250
251 return VINF_SUCCESS;
252 }
253
254 return VERR_NOT_FOUND;
255}
256
257/**
258 * Checks whether a specified directory handle exists (is valid)
259 * or not.
260 *
261 * @return bool True if handle exists, false if not.
262 * @param uHandle Directory handle to check.
263 */
264bool Guest::directoryHandleExists(uint32_t uHandle)
265{
266 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
267
268 GuestDirectoryMapIter it = mGuestDirectoryMap.find(uHandle);
269 if (it != mGuestDirectoryMap.end())
270 return true;
271
272 return false;
273}
274#endif /* VBOX_WITH_GUEST_CONTROL */
275
276STDMETHODIMP Guest::DirectoryOpen(IN_BSTR aDirectory, IN_BSTR aFilter,
277 ULONG aFlags, IN_BSTR aUserName, IN_BSTR aPassword,
278 ULONG *aHandle)
279{
280#ifndef VBOX_WITH_GUEST_CONTROL
281 ReturnComNotImplemented();
282#else /* VBOX_WITH_GUEST_CONTROL */
283 using namespace guestControl;
284
285 CheckComArgStrNotEmptyOrNull(aDirectory);
286 CheckComArgNotNull(aHandle);
287
288 /* Do not allow anonymous executions (with system rights). */
289 if (RT_UNLIKELY((aUserName) == NULL || *(aUserName) == '\0'))
290 return setError(E_INVALIDARG, tr("No user name specified"));
291
292 return directoryOpenInternal(aDirectory, aFilter,
293 aFlags,
294 aUserName, aPassword,
295 aHandle, NULL /* rc */);
296#endif
297}
298
299#ifdef VBOX_WITH_GUEST_CONTROL
300HRESULT Guest::directoryOpenInternal(IN_BSTR aDirectory, IN_BSTR aFilter,
301 ULONG aFlags,
302 IN_BSTR aUsername, IN_BSTR aPassword,
303 ULONG *aHandle, int *pRC)
304{
305 using namespace guestControl;
306
307 CheckComArgStrNotEmptyOrNull(aDirectory);
308 CheckComArgNotNull(aHandle);
309
310 AutoCaller autoCaller(this);
311 if (FAILED(autoCaller.rc())) return autoCaller.rc();
312
313 /* Validate flags. No flags supported yet. */
314 if (aFlags != DirectoryOpenFlag_None)
315 return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), aFlags);
316
317 HRESULT rc = S_OK;
318 try
319 {
320 Utf8Str Utf8Directory(aDirectory);
321 Utf8Str Utf8Filter(aFilter);
322
323 com::SafeArray<IN_BSTR> args;
324 com::SafeArray<IN_BSTR> env;
325
326 /*
327 * Prepare tool command line.
328 */
329
330 /* We need to get output which is machine-readable in form
331 * of "key=value\0..key=value\0\0". */
332 args.push_back(Bstr("--machinereadable").raw());
333
334 /* We want the long output format. Handy for getting a lot of
335 * details we could (should?) use (later). */
336 args.push_back(Bstr("-l").raw());
337
338 /* As we want to keep this stuff simple we don't do recursive (-R)
339 * or dereferencing (--dereference) lookups here. This has to be done by
340 * the user. */
341
342 /* Construct and hand in actual directory name + filter we want to open. */
343 char *pszDirectoryFinal;
344 int cbRet;
345 if (Utf8Filter.isEmpty())
346 cbRet = RTStrAPrintf(&pszDirectoryFinal, "%s", Utf8Directory.c_str());
347 else
348 cbRet = RTStrAPrintf(&pszDirectoryFinal, "%s/%s",
349 Utf8Directory.c_str(), Utf8Filter.c_str());
350 if (!cbRet)
351 return setError(E_OUTOFMEMORY, tr("Out of memory while allocating final directory"));
352
353 args.push_back(Bstr(pszDirectoryFinal).raw()); /* The directory we want to open. */
354
355 ULONG uPID;
356 rc = executeAndWaitForTool(Bstr(VBOXSERVICE_TOOL_LS).raw(), Bstr("Opening directory").raw(),
357 ComSafeArrayAsInParam(args),
358 ComSafeArrayAsInParam(env),
359 aUsername, aPassword,
360 NULL /* Progress */, &uPID);
361 if (SUCCEEDED(rc))
362 {
363 /* Assign new directory handle ID. */
364 int vrc = directoryCreateHandle(aHandle, uPID,
365 Utf8Directory.c_str(),
366 Utf8Filter.isEmpty() ? NULL : Utf8Filter.c_str(),
367 aFlags);
368 if (RT_FAILURE(vrc))
369 rc = setError(VBOX_E_IPRT_ERROR,
370 tr("Unable to create guest directory handle (%Rrc)"), vrc);
371 }
372 }
373 catch (std::bad_alloc &)
374 {
375 rc = E_OUTOFMEMORY;
376 }
377 return rc;
378}
379#endif /* VBOX_WITH_GUEST_CONTROL */
380
381STDMETHODIMP Guest::DirectoryRead(ULONG aHandle, IGuestDirEntry **aDirEntry)
382{
383#ifndef VBOX_WITH_GUEST_CONTROL
384 ReturnComNotImplemented();
385#else /* VBOX_WITH_GUEST_CONTROL */
386 using namespace guestControl;
387
388 CheckComArgOutPointerValid(aDirEntry);
389
390 AutoCaller autoCaller(this);
391 if (FAILED(autoCaller.rc())) return autoCaller.rc();
392
393 HRESULT rc = S_OK;
394 try
395 {
396 GuestProcessStreamBlock streamBlock;
397 int vrc = directoryGetNextEntry(aHandle, streamBlock);
398 if (RT_SUCCESS(vrc))
399 {
400 ComObjPtr <GuestDirEntry> pDirEntry;
401 rc = pDirEntry.createObject();
402 ComAssertComRC(rc);
403
404 rc = pDirEntry->init(this, streamBlock);
405 if (SUCCEEDED(rc))
406 {
407 pDirEntry.queryInterfaceTo(aDirEntry);
408 }
409 else
410 rc = setError(VBOX_E_IPRT_ERROR,
411 Guest::tr("Unable to init guest directory entry"));
412 }
413 else
414 rc = setError(VBOX_E_IPRT_ERROR,
415 Guest::tr("Directory handle is invalid"));
416 }
417 catch (std::bad_alloc &)
418 {
419 rc = E_OUTOFMEMORY;
420 }
421 return rc;
422#endif
423}
424
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette