VirtualBox

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

Last change on this file since 39336 was 38439, checked in by vboxsync, 13 years ago

GuestCtrl: Removed dead code.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.0 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. Optional.
141 * @param uPID PID of guest process running the associated "vbox_ls".
142 * @param aDirectory Directory the handle is assigned to.
143 * @param aFilter Directory filter. Optional.
144 * @param uFlags Directory open flags.
145 *
146 */
147int Guest::directoryCreateHandle(ULONG *puHandle, ULONG uPID,
148 IN_BSTR aDirectory, IN_BSTR aFilter, ULONG uFlags)
149{
150 AssertReturn(uPID, VERR_INVALID_PARAMETER);
151 CheckComArgStrNotEmptyOrNull(aDirectory);
152 /* aFilter is optional. */
153 /* uFlags are optional. */
154
155 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
156
157 int rc = VERR_TOO_MUCH_DATA;
158 for (uint32_t i = 0; i < UINT32_MAX - 1; i++)
159 {
160 /* Create a new context ID ... */
161 uint32_t uHandleTry = ASMAtomicIncU32(&mNextDirectoryID);
162 GuestDirectoryMapIter it = mGuestDirectoryMap.find(uHandleTry);
163 if (it == mGuestDirectoryMap.end()) /* We found a free slot ... */
164 {
165 mGuestDirectoryMap[uHandleTry].mDirectory = aDirectory;
166 mGuestDirectoryMap[uHandleTry].mFilter = aFilter;
167 mGuestDirectoryMap[uHandleTry].mPID = uPID;
168 mGuestDirectoryMap[uHandleTry].mFlags = uFlags;
169 Assert(mGuestDirectoryMap.size());
170
171 rc = VINF_SUCCESS;
172
173 if (puHandle)
174 *puHandle = uHandleTry;
175 break;
176 }
177 }
178
179 return rc;
180}
181
182/**
183 * Destroys a previously created directory handle and its
184 * associated data.
185 *
186 * @return IPRT status code.
187 * @param uHandle Handle to destroy.
188 */
189void Guest::directoryDestroyHandle(uint32_t uHandle)
190{
191 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
192
193 GuestDirectoryMapIter it = mGuestDirectoryMap.find(uHandle);
194 if (it != mGuestDirectoryMap.end())
195 {
196 /* Destroy raw guest stream buffer - not used
197 * anymore. */
198 it->second.mStream.Destroy();
199
200 /* Remove callback context (not used anymore). */
201 mGuestDirectoryMap.erase(it);
202 }
203}
204
205#if 0
206STDMETHODIMP Guest::DirectoryExists(IN_BSTR aDirectory, IN_BSTR aUsername, IN_BSTR aPassword, BOOL *aExists)
207{
208#ifndef VBOX_WITH_GUEST_CONTROL
209 ReturnComNotImplemented();
210#else /* VBOX_WITH_GUEST_CONTROL */
211 using namespace guestControl;
212
213 CheckComArgStrNotEmptyOrNull(aDirectory);
214
215 /* Do not allow anonymous executions (with system rights). */
216 if (RT_UNLIKELY((aUsername) == NULL || *(aUsername) == '\0'))
217 return setError(E_INVALIDARG, tr("No user name specified"));
218
219 return directoryExistsInternal(aDirectory,
220 aUsername, aPassword, aExists);
221#endif
222}
223#endif
224
225#ifdef VBOX_WITH_GUEST_CONTROL
226HRESULT Guest::directoryExistsInternal(IN_BSTR aDirectory, IN_BSTR aUsername, IN_BSTR aPassword, BOOL *aExists)
227{
228 using namespace guestControl;
229
230 CheckComArgStrNotEmptyOrNull(aDirectory);
231
232 AutoCaller autoCaller(this);
233 if (FAILED(autoCaller.rc())) return autoCaller.rc();
234
235 int rc;
236 HRESULT hr = directoryQueryInfoInternal(aDirectory,
237 aUsername, aPassword,
238 NULL /* No RTFSOBJINFO needed */,
239 RTFSOBJATTRADD_NOTHING, &rc);
240 if (SUCCEEDED(hr))
241 {
242 switch (rc)
243 {
244 case VINF_SUCCESS:
245 *aExists = TRUE;
246 break;
247
248 case VERR_FILE_NOT_FOUND:
249 *aExists = FALSE;
250 break;
251
252 case VERR_NOT_FOUND:
253 rc = setError(VBOX_E_IPRT_ERROR,
254 Guest::tr("Unable to query directory existence"));
255 break;
256
257 default:
258 AssertReleaseMsgFailed(("directoryExistsInternal: Unknown return value (%Rrc)\n", rc));
259 break;
260 }
261 }
262 return hr;
263}
264#endif
265
266/**
267 * Gets the associated PID from a directory handle.
268 *
269 * @return uint32_t Associated PID, 0 if handle not found/invalid.
270 * @param uHandle Directory handle to get PID for.
271 */
272uint32_t Guest::directoryGetPID(uint32_t uHandle)
273{
274 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
275
276 GuestDirectoryMapIter it = mGuestDirectoryMap.find(uHandle);
277 if (it != mGuestDirectoryMap.end())
278 return it->second.mPID;
279
280 return 0;
281}
282
283/**
284 * Returns the next directory entry of an open guest directory.
285 * Returns VERR_NO_DATA if no more entries available or VERR_NOT_FOUND
286 * if directory handle is invalid.
287 *
288 * @return IPRT status code.
289 * @param uHandle Directory handle to get entry for.
290 * @param streamBlock Reference that receives the next stream block data.
291 */
292int Guest::directoryGetNextEntry(uint32_t uHandle, GuestProcessStreamBlock &streamBlock)
293{
294 // LOCK DOES NOT WORK HERE!?
295 //AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
296
297 GuestDirectoryMapIter it = mGuestDirectoryMap.find(uHandle);
298 if (it != mGuestDirectoryMap.end())
299 {
300 return executeStreamGetNextBlock(it->second.mPID,
301 it->second.mStream, streamBlock);
302 }
303
304 return VERR_NOT_FOUND;
305}
306
307/**
308 * Checks whether a specified directory handle exists (is valid)
309 * or not.
310 *
311 * @return bool True if handle exists, false if not.
312 * @param uHandle Directory handle to check.
313 */
314bool Guest::directoryHandleExists(uint32_t uHandle)
315{
316 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
317
318 GuestDirectoryMapIter it = mGuestDirectoryMap.find(uHandle);
319 if (it != mGuestDirectoryMap.end())
320 return true;
321
322 return false;
323}
324#endif /* VBOX_WITH_GUEST_CONTROL */
325
326STDMETHODIMP Guest::DirectoryOpen(IN_BSTR aDirectory, IN_BSTR aFilter,
327 ULONG aFlags, IN_BSTR aUserName, IN_BSTR aPassword,
328 ULONG *aHandle)
329{
330#ifndef VBOX_WITH_GUEST_CONTROL
331 ReturnComNotImplemented();
332#else /* VBOX_WITH_GUEST_CONTROL */
333 using namespace guestControl;
334
335 CheckComArgStrNotEmptyOrNull(aDirectory);
336 CheckComArgNotNull(aHandle);
337
338 /* Do not allow anonymous executions (with system rights). */
339 if (RT_UNLIKELY((aUserName) == NULL || *(aUserName) == '\0'))
340 return setError(E_INVALIDARG, tr("No user name specified"));
341
342 return directoryOpenInternal(aDirectory, aFilter,
343 aFlags,
344 aUserName, aPassword,
345 aHandle, NULL /* rc */);
346#endif
347}
348
349#ifdef VBOX_WITH_GUEST_CONTROL
350HRESULT Guest::directoryOpenInternal(IN_BSTR aDirectory, IN_BSTR aFilter,
351 ULONG aFlags,
352 IN_BSTR aUsername, IN_BSTR aPassword,
353 ULONG *aHandle, int *pRC)
354{
355 using namespace guestControl;
356
357 CheckComArgStrNotEmptyOrNull(aDirectory);
358 CheckComArgNotNull(aHandle);
359
360 AutoCaller autoCaller(this);
361 if (FAILED(autoCaller.rc())) return autoCaller.rc();
362
363 /* Validate flags. No flags supported yet. */
364 if (aFlags != DirectoryOpenFlag_None)
365 return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), aFlags);
366
367 HRESULT hr = S_OK;
368 try
369 {
370 Utf8Str Utf8Directory(aDirectory);
371 Utf8Str Utf8Filter(aFilter);
372
373 com::SafeArray<IN_BSTR> args;
374 com::SafeArray<IN_BSTR> env;
375
376 /*
377 * Prepare tool command line.
378 */
379
380 /* We need to get output which is machine-readable in form
381 * of "key=value\0..key=value\0\0". */
382 args.push_back(Bstr("--machinereadable").raw());
383
384 /* We want the long output format. Handy for getting a lot of
385 * details we could (should?) use (later). */
386 args.push_back(Bstr("-l").raw());
387
388 /* As we want to keep this stuff simple we don't do recursive (-R)
389 * or dereferencing (--dereference) lookups here. This has to be done by
390 * the user. */
391
392 /* Construct and hand in actual directory name + filter we want to open. */
393 char *pszDirectoryFinal;
394 int cbRet;
395 if (Utf8Filter.isEmpty())
396 cbRet = RTStrAPrintf(&pszDirectoryFinal, "%s", Utf8Directory.c_str());
397 else
398 cbRet = RTStrAPrintf(&pszDirectoryFinal, "%s/%s",
399 Utf8Directory.c_str(), Utf8Filter.c_str());
400 if (!cbRet)
401 return setError(E_OUTOFMEMORY, tr("Out of memory while allocating final directory"));
402
403 args.push_back(Bstr(pszDirectoryFinal).raw()); /* The directory we want to open. */
404
405 ULONG uPID;
406 /** @todo Don't wait for tool to finish! Might take a lot of time! */
407 hr = executeAndWaitForTool(Bstr(VBOXSERVICE_TOOL_LS).raw(), Bstr("Opening directory").raw(),
408 ComSafeArrayAsInParam(args),
409 ComSafeArrayAsInParam(env),
410 aUsername, aPassword,
411 NULL /* Progress */, &uPID);
412 if (SUCCEEDED(hr))
413 {
414 /* Assign new directory handle ID. */
415 ULONG uHandleNew;
416 int vrc = directoryCreateHandle(&uHandleNew, uPID,
417 aDirectory, aFilter, aFlags);
418 if (RT_SUCCESS(vrc))
419 {
420 *aHandle = uHandleNew;
421 }
422 else
423 hr = setError(VBOX_E_IPRT_ERROR,
424 tr("Unable to create guest directory handle (%Rrc)"), vrc);
425 }
426 }
427 catch (std::bad_alloc &)
428 {
429 hr = E_OUTOFMEMORY;
430 }
431 return hr;
432}
433
434HRESULT Guest::directoryQueryInfoInternal(IN_BSTR aDirectory,
435 IN_BSTR aUsername, IN_BSTR aPassword,
436 PRTFSOBJINFO aObjInfo, RTFSOBJATTRADD enmAddAttribs,
437 int *pRC)
438{
439 using namespace guestControl;
440
441 /** @todo Search directory cache first? */
442
443 CheckComArgStrNotEmptyOrNull(aDirectory);
444 /* aUsername is optional. */
445 /* aPassword is optional. */
446 /* aObjInfo is optional. */
447
448 AutoCaller autoCaller(this);
449 if (FAILED(autoCaller.rc())) return autoCaller.rc();
450
451 HRESULT hr = S_OK;
452 try
453 {
454 Utf8Str Utf8Dir(aDirectory);
455 Utf8Str Utf8Username(aUsername);
456 Utf8Str Utf8Password(aPassword);
457
458 com::SafeArray<IN_BSTR> args;
459 com::SafeArray<IN_BSTR> env;
460
461 /*
462 * Prepare tool command line.
463 */
464
465 /* We need to get output which is machine-readable in form
466 * of "key=value\0..key=value\0\0". */
467 args.push_back(Bstr("--machinereadable").raw());
468
469 /* Only the actual file name to chekc is needed for now. */
470 args.push_back(Bstr(Utf8Dir).raw());
471
472 /*
473 * Execute guest process.
474 */
475 ULONG uPID;
476 hr = executeAndWaitForTool(Bstr(VBOXSERVICE_TOOL_STAT).raw(), Bstr("Querying directory information").raw(),
477 ComSafeArrayAsInParam(args),
478 ComSafeArrayAsInParam(env),
479 aUsername, aPassword,
480 NULL /* Progress */, &uPID);
481 if (SUCCEEDED(hr))
482 {
483 GuestCtrlStreamObjects streamObjs;
484 hr = executeStreamParse(uPID, streamObjs);
485 if (SUCCEEDED(hr))
486 {
487 int rc = VINF_SUCCESS;
488
489 Assert(streamObjs.size());
490 const char *pszFsType = streamObjs[0].GetString("ftype");
491 if (!pszFsType) /* Attribute missing? */
492 rc = VERR_NOT_FOUND;
493 if ( RT_SUCCESS(rc)
494 && strcmp(pszFsType, "d")) /* Directory? */
495 {
496 rc = VERR_FILE_NOT_FOUND;
497 /* This is not critical for Main, so don't set hr --
498 * we will take care of rc then. */
499 }
500 if ( RT_SUCCESS(rc)
501 && aObjInfo) /* Do we want object details? */
502 {
503 hr = executeStreamQueryFsObjInfo(aDirectory, streamObjs[0],
504 aObjInfo, enmAddAttribs);
505 }
506
507 if (pRC)
508 *pRC = rc;
509 }
510 }
511 }
512 catch (std::bad_alloc &)
513 {
514 hr = E_OUTOFMEMORY;
515 }
516 return hr;
517}
518#endif /* VBOX_WITH_GUEST_CONTROL */
519
520STDMETHODIMP Guest::DirectoryRead(ULONG aHandle, IGuestDirEntry **aDirEntry)
521{
522#ifndef VBOX_WITH_GUEST_CONTROL
523 ReturnComNotImplemented();
524#else /* VBOX_WITH_GUEST_CONTROL */
525 using namespace guestControl;
526
527 CheckComArgOutPointerValid(aDirEntry);
528
529 AutoCaller autoCaller(this);
530 if (FAILED(autoCaller.rc())) return autoCaller.rc();
531
532 HRESULT hr = S_OK;
533 try
534 {
535 GuestProcessStreamBlock streamBlock;
536 int rc = directoryGetNextEntry(aHandle, streamBlock);
537 if (RT_SUCCESS(rc))
538 {
539 ComObjPtr <GuestDirEntry> pDirEntry;
540 hr = pDirEntry.createObject();
541 ComAssertComRC(hr);
542
543 Assert(streamBlock.GetCount());
544 hr = pDirEntry->init(this, streamBlock);
545 if (SUCCEEDED(hr))
546 {
547 pDirEntry.queryInterfaceTo(aDirEntry);
548 }
549 else
550 hr = setError(VBOX_E_IPRT_ERROR,
551 Guest::tr("Failed to init guest directory entry"));
552 }
553 else if (rc == VERR_NO_DATA)
554 {
555 /* No more directory entries to read. That's fine. */
556 hr = E_ABORT; /** @todo Find/define a better rc! */
557 }
558 else
559 hr = setError(VBOX_E_IPRT_ERROR,
560 Guest::tr("Failed getting next directory entry (%Rrc)"), rc);
561 }
562 catch (std::bad_alloc &)
563 {
564 hr = E_OUTOFMEMORY;
565 }
566 return hr;
567#endif
568}
569
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