VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/VFSExplorerImpl.cpp@ 49716

Last change on this file since 49716 was 49644, checked in by vboxsync, 11 years ago

stage 1/8 of 6813 changes

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