VirtualBox

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

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

Main: initial code for upload to cloud (second try)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.8 KB
Line 
1/* $Id: VFSExplorerImpl.cpp 20081 2009-05-27 12:55:11Z 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 case RTDIRENTRYTYPE_UNKNOWN: t = VFSFileType_Unknown; break;
256 case RTDIRENTRYTYPE_FIFO: t = VFSFileType_Fifo; break;
257 case RTDIRENTRYTYPE_DEV_CHAR: t = VFSFileType_DevChar; break;
258 case RTDIRENTRYTYPE_DIRECTORY: t = VFSFileType_Directory; break;
259 case RTDIRENTRYTYPE_DEV_BLOCK: t = VFSFileType_DevBlock; break;
260 case RTDIRENTRYTYPE_FILE: t = VFSFileType_File; break;
261 case RTDIRENTRYTYPE_SYMLINK: t = VFSFileType_SymLink; break;
262 case RTDIRENTRYTYPE_SOCKET: t = VFSFileType_Socket; break;
263 case RTDIRENTRYTYPE_WHITEOUT: t = VFSFileType_WhiteOut; break;
264 }
265 return t;
266}
267
268HRESULT VFSExplorer::updateFS(TaskVFSExplorer *aTask)
269{
270 LogFlowFuncEnter();
271
272 AutoCaller autoCaller(this);
273 CheckComRCReturnRC(autoCaller.rc());
274
275 AutoWriteLock appLock(this);
276
277 HRESULT rc = S_OK;
278
279 std::list<VFSExplorer::Data::DirEntry> fileList;
280 char *pszPath = NULL;
281 PRTDIR pDir = NULL;
282 try
283 {
284 pszPath = RTStrDup(m->strPath.c_str());
285 RTPathStripFilename(pszPath);
286 int vrc = RTDirOpen(&pDir, pszPath);
287 if (RT_FAILURE(vrc))
288 throw setError(VBOX_E_FILE_ERROR, tr ("Can't open directory '%s' (%Rrc)"), pszPath, vrc);
289
290 if(aTask->progress)
291 aTask->progress->setCurrentOperationProgress(33);
292 RTDIRENTRY entry;
293 while (RT_SUCCESS(vrc))
294 {
295 vrc = RTDirRead(pDir, &entry, NULL);
296 if (RT_SUCCESS(vrc))
297 {
298 Utf8Str name(entry.szName);
299 if (name != "." &&
300 name != "..")
301 fileList.push_back(VFSExplorer::Data::DirEntry(name, RTToVFSFileType(entry.enmType)));
302 }
303 }
304 if(aTask->progress)
305 aTask->progress->setCurrentOperationProgress(66);
306 }
307 catch(HRESULT aRC)
308 {
309 rc = aRC;
310 }
311
312 /* Clean up */
313 if (pszPath)
314 RTStrFree(pszPath);
315 if (pDir)
316 RTDirClose(pDir);
317
318 if(aTask->progress)
319 aTask->progress->setCurrentOperationProgress(99);
320
321 /* Assign the result on success (this clears the old list) */
322 if (rc == S_OK)
323 m->entryList.assign(fileList.begin(), fileList.end());
324
325 aTask->rc = rc;
326
327 if (!aTask->progress.isNull())
328 aTask->progress->notifyComplete(rc);
329
330 LogFlowFunc(("rc=%Rhrc\n", rc));
331 LogFlowFuncLeave();
332
333 return VINF_SUCCESS;
334}
335
336HRESULT VFSExplorer::deleteFS(TaskVFSExplorer *aTask)
337{
338 LogFlowFuncEnter();
339
340 AutoCaller autoCaller(this);
341 CheckComRCReturnRC(autoCaller.rc());
342
343 AutoWriteLock appLock(this);
344
345 HRESULT rc = S_OK;
346
347 float fPercentStep = 100.0 / aTask->filenames.size();
348 try
349 {
350 char szPath[RTPATH_MAX];
351 std::list<Utf8Str>::const_iterator it;
352 size_t i = 0;
353 for (it = aTask->filenames.begin();
354 it != aTask->filenames.end();
355 ++it, ++i)
356 {
357 memcpy(szPath, m->strPath.c_str(), strlen(m->strPath.c_str()) + 1);
358 RTPathStripFilename(szPath);
359 RTPathAppend(szPath, sizeof(szPath), (*it).c_str());
360 int vrc = RTFileDelete(szPath);
361 if (RT_FAILURE(vrc))
362 throw setError(VBOX_E_FILE_ERROR, tr ("Can't delete file '%s' (%Rrc)"), szPath, vrc);
363 if(aTask->progress)
364 aTask->progress->setCurrentOperationProgress(fPercentStep * i);
365 }
366 }
367 catch(HRESULT aRC)
368 {
369 rc = aRC;
370 }
371
372 aTask->rc = rc;
373
374 if (!aTask->progress.isNull())
375 aTask->progress->notifyComplete(rc);
376
377 LogFlowFunc(("rc=%Rhrc\n", rc));
378 LogFlowFuncLeave();
379
380 return VINF_SUCCESS;
381}
382
383HRESULT VFSExplorer::updateS3(TaskVFSExplorer *aTask)
384{
385 LogFlowFuncEnter();
386
387 AutoCaller autoCaller(this);
388 CheckComRCReturnRC(autoCaller.rc());
389
390 AutoWriteLock appLock(this);
391
392 HRESULT rc = S_OK;
393
394 RTS3 hS3 = NULL;
395 std::list<VFSExplorer::Data::DirEntry> fileList;
396 try
397 {
398 int vrc = RTS3Create(&hS3, m->strUsername.c_str(), m->strPassword.c_str(), m->strHostname.c_str(), "virtualbox-agent/"VBOX_VERSION_STRING);
399 if (RT_FAILURE(vrc))
400 throw setError(E_FAIL, tr ("Can't open S3 storage service (%Rrc)"), vrc);
401
402 RTS3SetProgressCallback(hS3, VFSExplorer::TaskVFSExplorer::uploadProgress, &aTask);
403 /* Do we need the list of buckets or keys? */
404 if (m->strBucket.isEmpty())
405 {
406 PCRTS3BUCKETENTRY pBuckets = NULL;
407 vrc = RTS3GetBuckets(hS3, &pBuckets);
408 if (RT_FAILURE(vrc))
409 throw setError(E_FAIL, tr ("Can't get buckets (%Rrc)"), vrc);
410
411 PCRTS3BUCKETENTRY pTmpBuckets = pBuckets;
412 while (pBuckets)
413 {
414 fileList.push_back(VFSExplorer::Data::DirEntry(pBuckets->pszName, VFSFileType_Directory));
415 pBuckets = pBuckets->pNext;
416 }
417 RTS3BucketsDestroy(pTmpBuckets);
418 }
419 else
420 {
421 PCRTS3KEYENTRY pKeys = NULL;
422 vrc = RTS3GetBucketKeys(hS3, m->strBucket, &pKeys);
423 if (RT_FAILURE(vrc))
424 throw setError(E_FAIL, tr ("Can't get keys for bucket (%Rrc)"), vrc);
425
426 PCRTS3KEYENTRY pTmpKeys = pKeys;
427 while (pKeys)
428 {
429 Utf8Str name(pKeys->pszName);
430 fileList.push_back(VFSExplorer::Data::DirEntry(pKeys->pszName, VFSFileType_File));
431 pKeys = pKeys->pNext;
432 }
433 RTS3KeysDestroy(pTmpKeys);
434 }
435 }
436 catch(HRESULT aRC)
437 {
438 rc = aRC;
439 }
440
441 if (hS3 != NULL)
442 RTS3Destroy(hS3);
443
444 /* Assign the result on success (this clears the old list) */
445 if (rc == S_OK)
446 m->entryList.assign(fileList.begin(), fileList.end());
447
448 aTask->rc = rc;
449
450 if (!aTask->progress.isNull())
451 aTask->progress->notifyComplete(rc);
452
453 LogFlowFunc(("rc=%Rhrc\n", rc));
454 LogFlowFuncLeave();
455
456 return VINF_SUCCESS;
457}
458
459HRESULT VFSExplorer::deleteS3(TaskVFSExplorer *aTask)
460{
461 LogFlowFuncEnter();
462
463 AutoCaller autoCaller(this);
464 CheckComRCReturnRC(autoCaller.rc());
465
466 AutoWriteLock appLock(this);
467
468 HRESULT rc = S_OK;
469
470 RTS3 hS3 = NULL;
471 float fPercentStep = 100.0 / aTask->filenames.size();
472 try
473 {
474 int vrc = RTS3Create(&hS3, m->strUsername.c_str(), m->strPassword.c_str(), m->strHostname.c_str(), "virtualbox-agent/"VBOX_VERSION_STRING);
475 if (RT_FAILURE(vrc))
476 throw setError(E_FAIL, tr ("Can't open S3 storage service (%Rrc)"), vrc);
477
478 RTS3SetProgressCallback(hS3, VFSExplorer::TaskVFSExplorer::uploadProgress, &aTask);
479
480 std::list<Utf8Str>::const_iterator it;
481 size_t i = 0;
482 for (it = aTask->filenames.begin();
483 it != aTask->filenames.end();
484 ++it, ++i)
485 {
486 vrc = RTS3DeleteKey(hS3, m->strBucket.c_str(), (*it).c_str());
487 if (RT_FAILURE(vrc))
488 throw setError(VBOX_E_FILE_ERROR, tr ("Can't delete file '%s' (%Rrc)"), (*it).c_str(), vrc);
489 if(aTask->progress)
490 aTask->progress->setCurrentOperationProgress(fPercentStep * i);
491 }
492 }
493 catch(HRESULT aRC)
494 {
495 rc = aRC;
496 }
497
498 aTask->rc = rc;
499
500 if (hS3 != NULL)
501 RTS3Destroy(hS3);
502
503 if (!aTask->progress.isNull())
504 aTask->progress->notifyComplete(rc);
505
506 LogFlowFunc(("rc=%Rhrc\n", rc));
507 LogFlowFuncLeave();
508
509 return VINF_SUCCESS;
510}
511
512STDMETHODIMP VFSExplorer::Update(IProgress **aProgress)
513{
514 CheckComArgOutPointerValid(aProgress);
515
516 AutoCaller autoCaller(this);
517 CheckComRCReturnRC(autoCaller.rc());
518
519 AutoReadLock(this);
520
521 HRESULT rc = S_OK;
522
523 ComObjPtr<Progress> progress;
524 try
525 {
526 Bstr progressDesc = BstrFmt(tr("Update directory info for '%s'"),
527 m->strPath.raw());
528 /* Create the progress object */
529 progress.createObject();
530
531 rc = progress->init(mVirtualBox, static_cast<IVFSExplorer*>(this),
532 progressDesc,
533 TRUE /* aCancelable */);
534 if (FAILED(rc)) throw rc;
535
536 /* Initialize our worker task */
537 std::auto_ptr<TaskVFSExplorer> task(new TaskVFSExplorer(TaskVFSExplorer::Update, this, progress));
538
539 rc = task->startThread();
540 if (FAILED(rc)) throw rc;
541
542 /* Don't destruct on success */
543 task.release();
544 }
545 catch (HRESULT aRC)
546 {
547 rc = aRC;
548 }
549
550 if (SUCCEEDED(rc))
551 /* Return progress to the caller */
552 progress.queryInterfaceTo(aProgress);
553
554 return rc;
555}
556
557STDMETHODIMP VFSExplorer::EntryList(ComSafeArrayOut(BSTR, aNames), ComSafeArrayOut(VFSFileType_T, aTypes))
558{
559 if (ComSafeArrayOutIsNull(aNames) ||
560 ComSafeArrayOutIsNull(aTypes))
561 return E_POINTER;
562
563 AutoCaller autoCaller(this);
564 CheckComRCReturnRC(autoCaller.rc());
565
566 AutoReadLock alock(this);
567
568 com::SafeArray<BSTR> sfaNames((ULONG)m->entryList.size());
569 com::SafeArray<ULONG> sfaTypes((VFSFileType_T)m->entryList.size());
570
571 std::list<VFSExplorer::Data::DirEntry>::const_iterator it;
572 size_t i = 0;
573 for (it = m->entryList.begin();
574 it != m->entryList.end();
575 ++it, ++i)
576 {
577 const VFSExplorer::Data::DirEntry &entry = (*it);
578 Bstr bstr(entry.name);
579 bstr.cloneTo(&sfaNames[i]);
580 sfaTypes[i] = entry.type;
581 }
582
583 sfaNames.detachTo(ComSafeArrayOutArg(aNames));
584 sfaTypes.detachTo(ComSafeArrayOutArg(aTypes));
585
586 return S_OK;
587}
588
589STDMETHODIMP VFSExplorer::Exists(ComSafeArrayIn(IN_BSTR, aNames), ComSafeArrayOut(BSTR, aExists))
590{
591 CheckComArgSafeArrayNotNull(aNames);
592 CheckComArgSafeArrayNotNull(aExists);
593
594 AutoCaller autoCaller(this);
595 CheckComRCReturnRC(autoCaller.rc());
596
597 AutoReadLock alock(this);
598
599 com::SafeArray<IN_BSTR> sfaNames(ComSafeArrayInArg(aNames));
600 std::list<BSTR> listExists;
601
602 std::list<VFSExplorer::Data::DirEntry>::const_iterator it;
603 for (it = m->entryList.begin();
604 it != m->entryList.end();
605 ++it)
606 {
607 const VFSExplorer::Data::DirEntry &entry = (*it);
608 for (size_t a=0; a < sfaNames.size(); ++a)
609 {
610 if (entry.name == RTPathFilename(Utf8Str(sfaNames[a])))
611 {
612 BSTR name;
613 Bstr(sfaNames[a]).cloneTo(&name);
614 listExists.push_back(name);
615 }
616 }
617 }
618
619 com::SafeArray<BSTR> sfaExists(listExists);
620 sfaExists.detachTo(ComSafeArrayOutArg(aExists));
621
622 return S_OK;
623}
624
625STDMETHODIMP VFSExplorer::Remove(ComSafeArrayIn(IN_BSTR, aNames), IProgress **aProgress)
626{
627 CheckComArgSafeArrayNotNull(aNames);
628 CheckComArgOutPointerValid(aProgress);
629
630 AutoCaller autoCaller(this);
631 CheckComRCReturnRC(autoCaller.rc());
632
633 AutoReadLock(this);
634
635 HRESULT rc = S_OK;
636
637 com::SafeArray<IN_BSTR> sfaNames(ComSafeArrayInArg(aNames));
638
639 ComObjPtr<Progress> progress;
640 try
641 {
642 /* Create the progress object */
643 progress.createObject();
644
645 rc = progress->init(mVirtualBox, static_cast<IVFSExplorer*>(this),
646 Bstr(tr("Delete files")),
647 TRUE /* aCancelable */);
648 if (FAILED(rc)) throw rc;
649
650 /* Initialize our worker task */
651 std::auto_ptr<TaskVFSExplorer> task(new TaskVFSExplorer(TaskVFSExplorer::Delete, this, progress));
652
653 /* Add all filenames to delete as task data */
654 for (size_t a=0; a < sfaNames.size(); ++a)
655 task->filenames.push_back(Utf8Str(sfaNames[a]));
656
657 rc = task->startThread();
658 if (FAILED(rc)) throw rc;
659
660 /* Don't destruct on success */
661 task.release();
662 }
663 catch (HRESULT aRC)
664 {
665 rc = aRC;
666 }
667
668 if (SUCCEEDED(rc))
669 /* Return progress to the caller */
670 progress.queryInterfaceTo(aProgress);
671
672 return rc;
673}
674
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