VirtualBox

source: vbox/trunk/src/VBox/Main/VFSExplorerImpl.cpp@ 23319

Last change on this file since 23319 was 23223, checked in by vboxsync, 15 years ago

API: big medium handling change and lots of assorted other cleanups and fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.1 KB
Line 
1/* $Id: VFSExplorerImpl.cpp 23223 2009-09-22 15:50:03Z vboxsync $ */
2/** @file
3 *
4 * IVFSExplorer COM class implementations.
5 */
6
7/*
8 * Copyright (C) 2009 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19 * Clara, CA 95054 USA or visit http://www.sun.com if you need
20 * additional information or have any questions.
21 */
22
23#include <iprt/dir.h>
24#include <iprt/path.h>
25#include <iprt/file.h>
26#include <iprt/s3.h>
27
28#include <VBox/param.h>
29#include <VBox/version.h>
30
31#include "VFSExplorerImpl.h"
32#include "VirtualBoxImpl.h"
33#include "ProgressImpl.h"
34
35#include "Logging.h"
36
37////////////////////////////////////////////////////////////////////////////////
38//
39// VFSExplorer definitions
40//
41////////////////////////////////////////////////////////////////////////////////
42
43/* opaque private instance data of VFSExplorer class */
44struct VFSExplorer::Data
45{
46 struct DirEntry
47 {
48 DirEntry(Utf8Str aName, VFSFileType_T aType)
49 : name(aName)
50 , type(aType) {}
51
52 Utf8Str name;
53 VFSFileType_T type;
54 };
55
56 VFSType_T storageType;
57 Utf8Str strUsername;
58 Utf8Str strPassword;
59 Utf8Str strHostname;
60 Utf8Str strPath;
61 Utf8Str strBucket;
62
63 std::list<DirEntry> entryList;
64};
65
66DEFINE_EMPTY_CTOR_DTOR(VFSExplorer)
67
68/**
69 * VFSExplorer COM initializer.
70 * @param
71 * @return
72 */
73HRESULT VFSExplorer::init(VFSType_T aType, Utf8Str aFilePath, Utf8Str aHostname, Utf8Str aUsername, Utf8Str aPassword, VirtualBox *aVirtualBox)
74{
75 /* Enclose the state transition NotReady->InInit->Ready */
76 AutoInitSpan autoInitSpan(this);
77 AssertReturn(autoInitSpan.isOk(), E_FAIL);
78
79 /* Weak reference to a VirtualBox object */
80 unconst(mVirtualBox) = aVirtualBox;
81
82 /* initialize data */
83 m = new Data;
84
85 m->storageType = aType;
86 m->strPath = aFilePath;
87 m->strHostname = aHostname;
88 m->strUsername = aUsername;
89 m->strPassword = aPassword;
90
91 if (m->storageType == VFSType_S3)
92 {
93 size_t bpos = aFilePath.find("/", 1);
94 if (bpos != Utf8Str::npos)
95 {
96 m->strBucket = aFilePath.substr(1, bpos - 1); /* The bucket without any slashes */
97 aFilePath = aFilePath.substr(bpos); /* The rest of the file path */
98 }
99 }
100
101 /* Confirm a successful initialization */
102 autoInitSpan.setSucceeded();
103
104 return S_OK;
105}
106
107/**
108 * VFSExplorer COM uninitializer.
109 * @return
110 */
111void VFSExplorer::uninit()
112{
113 delete m;
114 m = NULL;
115}
116
117/**
118 * Public method implementation.
119 * @param
120 * @return
121 */
122STDMETHODIMP VFSExplorer::COMGETTER(Path)(BSTR *aPath)
123{
124 if (!aPath)
125 return E_POINTER;
126
127 AutoCaller autoCaller(this);
128 CheckComRCReturnRC(autoCaller.rc());
129
130 AutoReadLock alock(this);
131
132 Bstr bstrPath(m->strPath);
133 bstrPath.cloneTo(aPath);
134
135 return S_OK;
136}
137
138STDMETHODIMP VFSExplorer::COMGETTER(Type)(VFSType_T *aType)
139{
140 if (!aType)
141 return E_POINTER;
142
143 AutoCaller autoCaller(this);
144 CheckComRCReturnRC(autoCaller.rc());
145
146 AutoReadLock alock(this);
147
148 *aType = m->storageType;
149
150 return S_OK;
151}
152
153struct VFSExplorer::TaskVFSExplorer
154{
155 enum TaskType
156 {
157 Update,
158 Delete
159 };
160
161 TaskVFSExplorer(TaskType aTaskType, VFSExplorer *aThat, Progress *aProgress)
162 : taskType(aTaskType),
163 pVFSExplorer(aThat),
164 progress(aProgress),
165 rc(S_OK)
166 {}
167 ~TaskVFSExplorer() {}
168
169 int startThread();
170 static int taskThread(RTTHREAD aThread, void *pvUser);
171 static int uploadProgress(unsigned uPercent, void *pvUser);
172
173 TaskType taskType;
174 VFSExplorer *pVFSExplorer;
175 ComObjPtr<Progress> progress;
176 HRESULT rc;
177
178 /* task data */
179 std::list<Utf8Str> filenames;
180};
181
182int VFSExplorer::TaskVFSExplorer::startThread()
183{
184 int vrc = RTThreadCreate(NULL, VFSExplorer::TaskVFSExplorer::taskThread, this,
185 0, RTTHREADTYPE_MAIN_HEAVY_WORKER, 0,
186 "Explorer::Task");
187
188 ComAssertMsgRCRet(vrc,
189 ("Could not create taskThreadVFS (%Rrc)\n", vrc), E_FAIL);
190
191 return vrc;
192}
193
194/* static */
195DECLCALLBACK(int) VFSExplorer::TaskVFSExplorer::taskThread(RTTHREAD /* aThread */, void *pvUser)
196{
197 std::auto_ptr<TaskVFSExplorer> task(static_cast<TaskVFSExplorer*>(pvUser));
198 AssertReturn(task.get(), VERR_GENERAL_FAILURE);
199
200 VFSExplorer *pVFSExplorer = task->pVFSExplorer;
201
202 LogFlowFuncEnter();
203 LogFlowFunc(("VFSExplorer %p\n", pVFSExplorer));
204
205 HRESULT rc = S_OK;
206
207 switch(task->taskType)
208 {
209 case TaskVFSExplorer::Update:
210 {
211 if (pVFSExplorer->m->storageType == VFSType_File)
212 rc = pVFSExplorer->updateFS(task.get());
213 else if (pVFSExplorer->m->storageType == VFSType_S3)
214 rc = pVFSExplorer->updateS3(task.get());
215 break;
216 }
217 case TaskVFSExplorer::Delete:
218 {
219 if (pVFSExplorer->m->storageType == VFSType_File)
220 rc = pVFSExplorer->deleteFS(task.get());
221 else if (pVFSExplorer->m->storageType == VFSType_S3)
222 rc = pVFSExplorer->deleteS3(task.get());
223 break;
224 }
225 }
226
227 LogFlowFunc(("rc=%Rhrc\n", rc));
228 LogFlowFuncLeave();
229
230 return VINF_SUCCESS;
231}
232
233/* static */
234int VFSExplorer::TaskVFSExplorer::uploadProgress(unsigned uPercent, void *pvUser)
235{
236 VFSExplorer::TaskVFSExplorer* pTask = *(VFSExplorer::TaskVFSExplorer**)pvUser;
237
238 if (pTask &&
239 !pTask->progress.isNull())
240 {
241 BOOL fCanceled;
242 pTask->progress->COMGETTER(Canceled)(&fCanceled);
243 if (fCanceled)
244 return -1;
245 pTask->progress->SetCurrentOperationProgress(uPercent);
246 }
247 return VINF_SUCCESS;
248}
249
250VFSFileType_T VFSExplorer::RTToVFSFileType(int aType) const
251{
252 VFSFileType_T t;
253 switch(aType)
254 {
255 default:
256 case RTDIRENTRYTYPE_UNKNOWN: t = VFSFileType_Unknown; break;
257 case RTDIRENTRYTYPE_FIFO: t = VFSFileType_Fifo; break;
258 case RTDIRENTRYTYPE_DEV_CHAR: t = VFSFileType_DevChar; break;
259 case RTDIRENTRYTYPE_DIRECTORY: t = VFSFileType_Directory; break;
260 case RTDIRENTRYTYPE_DEV_BLOCK: t = VFSFileType_DevBlock; break;
261 case RTDIRENTRYTYPE_FILE: t = VFSFileType_File; break;
262 case RTDIRENTRYTYPE_SYMLINK: t = VFSFileType_SymLink; break;
263 case RTDIRENTRYTYPE_SOCKET: t = VFSFileType_Socket; break;
264 case RTDIRENTRYTYPE_WHITEOUT: t = VFSFileType_WhiteOut; break;
265 }
266 return t;
267}
268
269HRESULT VFSExplorer::updateFS(TaskVFSExplorer *aTask)
270{
271 LogFlowFuncEnter();
272
273 AutoCaller autoCaller(this);
274 CheckComRCReturnRC(autoCaller.rc());
275
276 AutoWriteLock appLock(this);
277
278 HRESULT rc = S_OK;
279
280 std::list<VFSExplorer::Data::DirEntry> fileList;
281 char *pszPath = NULL;
282 PRTDIR pDir = NULL;
283 try
284 {
285 pszPath = RTStrDup(m->strPath.c_str());
286 RTPathStripFilename(pszPath);
287 int vrc = RTDirOpen(&pDir, pszPath);
288 if (RT_FAILURE(vrc))
289 throw setError(VBOX_E_FILE_ERROR, tr ("Can't open directory '%s' (%Rrc)"), pszPath, vrc);
290
291 if(aTask->progress)
292 aTask->progress->SetCurrentOperationProgress(33);
293 RTDIRENTRY entry;
294 while (RT_SUCCESS(vrc))
295 {
296 vrc = RTDirRead(pDir, &entry, NULL);
297 if (RT_SUCCESS(vrc))
298 {
299 Utf8Str name(entry.szName);
300 if (name != "." &&
301 name != "..")
302 fileList.push_back(VFSExplorer::Data::DirEntry(name, RTToVFSFileType(entry.enmType)));
303 }
304 }
305 if(aTask->progress)
306 aTask->progress->SetCurrentOperationProgress(66);
307 }
308 catch(HRESULT aRC)
309 {
310 rc = aRC;
311 }
312
313 /* Clean up */
314 if (pszPath)
315 RTStrFree(pszPath);
316 if (pDir)
317 RTDirClose(pDir);
318
319 if(aTask->progress)
320 aTask->progress->SetCurrentOperationProgress(99);
321
322 /* Assign the result on success (this clears the old list) */
323 if (rc == S_OK)
324 m->entryList.assign(fileList.begin(), fileList.end());
325
326 aTask->rc = rc;
327
328 if (!aTask->progress.isNull())
329 aTask->progress->notifyComplete(rc);
330
331 LogFlowFunc(("rc=%Rhrc\n", rc));
332 LogFlowFuncLeave();
333
334 return VINF_SUCCESS;
335}
336
337HRESULT VFSExplorer::deleteFS(TaskVFSExplorer *aTask)
338{
339 LogFlowFuncEnter();
340
341 AutoCaller autoCaller(this);
342 CheckComRCReturnRC(autoCaller.rc());
343
344 AutoWriteLock appLock(this);
345
346 HRESULT rc = S_OK;
347
348 float fPercentStep = 100.0f / aTask->filenames.size();
349 try
350 {
351 char szPath[RTPATH_MAX];
352 std::list<Utf8Str>::const_iterator it;
353 size_t i = 0;
354 for (it = aTask->filenames.begin();
355 it != aTask->filenames.end();
356 ++it, ++i)
357 {
358 memcpy(szPath, m->strPath.c_str(), strlen(m->strPath.c_str()) + 1);
359 RTPathStripFilename(szPath);
360 RTPathAppend(szPath, sizeof(szPath), (*it).c_str());
361 int vrc = RTFileDelete(szPath);
362 if (RT_FAILURE(vrc))
363 throw setError(VBOX_E_FILE_ERROR, tr ("Can't delete file '%s' (%Rrc)"), szPath, vrc);
364 if(aTask->progress)
365 aTask->progress->SetCurrentOperationProgress((ULONG)(fPercentStep * i));
366 }
367 }
368 catch(HRESULT aRC)
369 {
370 rc = aRC;
371 }
372
373 aTask->rc = rc;
374
375 if (!aTask->progress.isNull())
376 aTask->progress->notifyComplete(rc);
377
378 LogFlowFunc(("rc=%Rhrc\n", rc));
379 LogFlowFuncLeave();
380
381 return VINF_SUCCESS;
382}
383
384HRESULT VFSExplorer::updateS3(TaskVFSExplorer *aTask)
385{
386 LogFlowFuncEnter();
387
388 AutoCaller autoCaller(this);
389 CheckComRCReturnRC(autoCaller.rc());
390
391 AutoWriteLock appLock(this);
392
393 HRESULT rc = S_OK;
394
395 RTS3 hS3 = NULL;
396 std::list<VFSExplorer::Data::DirEntry> fileList;
397 try
398 {
399 int vrc = RTS3Create(&hS3, m->strUsername.c_str(), m->strPassword.c_str(), m->strHostname.c_str(), "virtualbox-agent/"VBOX_VERSION_STRING);
400 if (RT_FAILURE(vrc))
401 throw setError(E_FAIL, tr ("Can't open S3 storage service (%Rrc)"), vrc);
402
403 RTS3SetProgressCallback(hS3, VFSExplorer::TaskVFSExplorer::uploadProgress, &aTask);
404 /* Do we need the list of buckets or keys? */
405 if (m->strBucket.isEmpty())
406 {
407 PCRTS3BUCKETENTRY pBuckets = NULL;
408 vrc = RTS3GetBuckets(hS3, &pBuckets);
409 if (RT_FAILURE(vrc))
410 throw setError(E_FAIL, tr ("Can't get buckets (%Rrc)"), vrc);
411
412 PCRTS3BUCKETENTRY pTmpBuckets = pBuckets;
413 while (pBuckets)
414 {
415 fileList.push_back(VFSExplorer::Data::DirEntry(pBuckets->pszName, VFSFileType_Directory));
416 pBuckets = pBuckets->pNext;
417 }
418 RTS3BucketsDestroy(pTmpBuckets);
419 }
420 else
421 {
422 PCRTS3KEYENTRY pKeys = NULL;
423 vrc = RTS3GetBucketKeys(hS3, m->strBucket.c_str(), &pKeys);
424 if (RT_FAILURE(vrc))
425 throw setError(E_FAIL, tr ("Can't get keys for bucket (%Rrc)"), vrc);
426
427 PCRTS3KEYENTRY pTmpKeys = pKeys;
428 while (pKeys)
429 {
430 Utf8Str name(pKeys->pszName);
431 fileList.push_back(VFSExplorer::Data::DirEntry(pKeys->pszName, VFSFileType_File));
432 pKeys = pKeys->pNext;
433 }
434 RTS3KeysDestroy(pTmpKeys);
435 }
436 }
437 catch(HRESULT aRC)
438 {
439 rc = aRC;
440 }
441
442 if (hS3 != NULL)
443 RTS3Destroy(hS3);
444
445 /* Assign the result on success (this clears the old list) */
446 if (rc == S_OK)
447 m->entryList.assign(fileList.begin(), fileList.end());
448
449 aTask->rc = rc;
450
451 if (!aTask->progress.isNull())
452 aTask->progress->notifyComplete(rc);
453
454 LogFlowFunc(("rc=%Rhrc\n", rc));
455 LogFlowFuncLeave();
456
457 return VINF_SUCCESS;
458}
459
460HRESULT VFSExplorer::deleteS3(TaskVFSExplorer *aTask)
461{
462 LogFlowFuncEnter();
463
464 AutoCaller autoCaller(this);
465 CheckComRCReturnRC(autoCaller.rc());
466
467 AutoWriteLock appLock(this);
468
469 HRESULT rc = S_OK;
470
471 RTS3 hS3 = NULL;
472 float fPercentStep = 100.0f / aTask->filenames.size();
473 try
474 {
475 int vrc = RTS3Create(&hS3, m->strUsername.c_str(), m->strPassword.c_str(), m->strHostname.c_str(), "virtualbox-agent/"VBOX_VERSION_STRING);
476 if (RT_FAILURE(vrc))
477 throw setError(E_FAIL, tr ("Can't open S3 storage service (%Rrc)"), vrc);
478
479 RTS3SetProgressCallback(hS3, VFSExplorer::TaskVFSExplorer::uploadProgress, &aTask);
480
481 std::list<Utf8Str>::const_iterator it;
482 size_t i = 0;
483 for (it = aTask->filenames.begin();
484 it != aTask->filenames.end();
485 ++it, ++i)
486 {
487 vrc = RTS3DeleteKey(hS3, m->strBucket.c_str(), (*it).c_str());
488 if (RT_FAILURE(vrc))
489 throw setError(VBOX_E_FILE_ERROR, tr ("Can't delete file '%s' (%Rrc)"), (*it).c_str(), vrc);
490 if(aTask->progress)
491 aTask->progress->SetCurrentOperationProgress((ULONG)(fPercentStep * i));
492 }
493 }
494 catch(HRESULT aRC)
495 {
496 rc = aRC;
497 }
498
499 aTask->rc = rc;
500
501 if (hS3 != NULL)
502 RTS3Destroy(hS3);
503
504 if (!aTask->progress.isNull())
505 aTask->progress->notifyComplete(rc);
506
507 LogFlowFunc(("rc=%Rhrc\n", rc));
508 LogFlowFuncLeave();
509
510 return VINF_SUCCESS;
511}
512
513STDMETHODIMP VFSExplorer::Update(IProgress **aProgress)
514{
515 CheckComArgOutPointerValid(aProgress);
516
517 AutoCaller autoCaller(this);
518 CheckComRCReturnRC(autoCaller.rc());
519
520 AutoReadLock(this);
521
522 HRESULT rc = S_OK;
523
524 ComObjPtr<Progress> progress;
525 try
526 {
527 Bstr progressDesc = BstrFmt(tr("Update directory info for '%s'"),
528 m->strPath.raw());
529 /* Create the progress object */
530 progress.createObject();
531
532 rc = progress->init(mVirtualBox, static_cast<IVFSExplorer*>(this),
533 progressDesc,
534 TRUE /* aCancelable */);
535 if (FAILED(rc)) throw rc;
536
537 /* Initialize our worker task */
538 std::auto_ptr<TaskVFSExplorer> task(new TaskVFSExplorer(TaskVFSExplorer::Update, this, progress));
539
540 rc = task->startThread();
541 if (FAILED(rc)) throw rc;
542
543 /* Don't destruct on success */
544 task.release();
545 }
546 catch (HRESULT aRC)
547 {
548 rc = aRC;
549 }
550
551 if (SUCCEEDED(rc))
552 /* Return progress to the caller */
553 progress.queryInterfaceTo(aProgress);
554
555 return rc;
556}
557
558STDMETHODIMP VFSExplorer::Cd(IN_BSTR aDir, IProgress **aProgress)
559{
560 CheckComArgNotNull(aDir);
561 CheckComArgOutPointerValid(aProgress);
562
563 return E_NOTIMPL;
564}
565
566STDMETHODIMP VFSExplorer::CdUp(IProgress **aProgress)
567{
568 CheckComArgOutPointerValid(aProgress);
569
570 return E_NOTIMPL;
571}
572
573STDMETHODIMP VFSExplorer::EntryList(ComSafeArrayOut(BSTR, aNames), ComSafeArrayOut(VFSFileType_T, aTypes))
574{
575 if (ComSafeArrayOutIsNull(aNames) ||
576 ComSafeArrayOutIsNull(aTypes))
577 return E_POINTER;
578
579 AutoCaller autoCaller(this);
580 CheckComRCReturnRC(autoCaller.rc());
581
582 AutoReadLock alock(this);
583
584 com::SafeArray<BSTR> sfaNames((ULONG)m->entryList.size());
585 com::SafeArray<ULONG> sfaTypes((VFSFileType_T)m->entryList.size());
586
587 std::list<VFSExplorer::Data::DirEntry>::const_iterator it;
588 size_t i = 0;
589 for (it = m->entryList.begin();
590 it != m->entryList.end();
591 ++it, ++i)
592 {
593 const VFSExplorer::Data::DirEntry &entry = (*it);
594 Bstr bstr(entry.name);
595 bstr.cloneTo(&sfaNames[i]);
596 sfaTypes[i] = entry.type;
597 }
598
599 sfaNames.detachTo(ComSafeArrayOutArg(aNames));
600 sfaTypes.detachTo(ComSafeArrayOutArg(aTypes));
601
602 return S_OK;
603}
604
605STDMETHODIMP VFSExplorer::Exists(ComSafeArrayIn(IN_BSTR, aNames), ComSafeArrayOut(BSTR, aExists))
606{
607 CheckComArgSafeArrayNotNull(aNames);
608
609 AutoCaller autoCaller(this);
610 CheckComRCReturnRC(autoCaller.rc());
611
612 AutoReadLock alock(this);
613
614 com::SafeArray<IN_BSTR> sfaNames(ComSafeArrayInArg(aNames));
615 std::list<BSTR> listExists;
616
617 std::list<VFSExplorer::Data::DirEntry>::const_iterator it;
618 for (it = m->entryList.begin();
619 it != m->entryList.end();
620 ++it)
621 {
622 const VFSExplorer::Data::DirEntry &entry = (*it);
623 for (size_t a=0; a < sfaNames.size(); ++a)
624 {
625 if (entry.name == RTPathFilename(Utf8Str(sfaNames[a]).c_str()))
626 {
627 BSTR name;
628 Bstr tmp(sfaNames[a]); /* gcc-3.3 cruft */
629 tmp.cloneTo(&name);
630 listExists.push_back(name);
631 }
632 }
633 }
634
635 com::SafeArray<BSTR> sfaExists(listExists);
636 sfaExists.detachTo(ComSafeArrayOutArg(aExists));
637
638 return S_OK;
639}
640
641STDMETHODIMP VFSExplorer::Remove(ComSafeArrayIn(IN_BSTR, aNames), IProgress **aProgress)
642{
643 CheckComArgSafeArrayNotNull(aNames);
644 CheckComArgOutPointerValid(aProgress);
645
646 AutoCaller autoCaller(this);
647 CheckComRCReturnRC(autoCaller.rc());
648
649 AutoReadLock(this);
650
651 HRESULT rc = S_OK;
652
653 com::SafeArray<IN_BSTR> sfaNames(ComSafeArrayInArg(aNames));
654
655 ComObjPtr<Progress> progress;
656 try
657 {
658 /* Create the progress object */
659 progress.createObject();
660
661 rc = progress->init(mVirtualBox, static_cast<IVFSExplorer*>(this),
662 Bstr(tr("Delete files")),
663 TRUE /* aCancelable */);
664 if (FAILED(rc)) throw rc;
665
666 /* Initialize our worker task */
667 std::auto_ptr<TaskVFSExplorer> task(new TaskVFSExplorer(TaskVFSExplorer::Delete, this, progress));
668
669 /* Add all filenames to delete as task data */
670 for (size_t a=0; a < sfaNames.size(); ++a)
671 task->filenames.push_back(Utf8Str(sfaNames[a]));
672
673 rc = task->startThread();
674 if (FAILED(rc)) throw rc;
675
676 /* Don't destruct on success */
677 task.release();
678 }
679 catch (HRESULT aRC)
680 {
681 rc = aRC;
682 }
683
684 if (SUCCEEDED(rc))
685 /* Return progress to the caller */
686 progress.queryInterfaceTo(aProgress);
687
688 return rc;
689}
690
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