VirtualBox

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

Last change on this file since 69734 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.4 KB
Line 
1/* $Id: VFSExplorerImpl.cpp 69500 2017-10-28 15:14:05Z vboxsync $ */
2/** @file
3 * IVFSExplorer COM class implementations.
4 */
5
6/*
7 * Copyright (C) 2009-2017 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 <iprt/dir.h>
19#include <iprt/path.h>
20#include <iprt/file.h>
21#include <iprt/s3.h>
22#include <iprt/cpp/utils.h>
23
24#include <VBox/com/array.h>
25
26#include <VBox/param.h>
27#include <VBox/version.h>
28
29#include "VFSExplorerImpl.h"
30#include "VirtualBoxImpl.h"
31#include "ProgressImpl.h"
32
33#include "AutoCaller.h"
34#include "Logging.h"
35#include "ThreadTask.h"
36
37#include <memory>
38
39struct VFSExplorer::Data
40{
41 struct DirEntry
42 {
43 DirEntry(Utf8Str strName, FsObjType_T fileType, uint64_t cbSize, uint32_t fMode)
44 : name(strName)
45 , type(fileType)
46 , size(cbSize)
47 , mode(fMode) {}
48
49 Utf8Str name;
50 FsObjType_T type;
51 uint64_t size;
52 uint32_t mode;
53 };
54
55 VFSType_T storageType;
56 Utf8Str strUsername;
57 Utf8Str strPassword;
58 Utf8Str strHostname;
59 Utf8Str strPath;
60 Utf8Str strBucket;
61 std::list<DirEntry> entryList;
62};
63
64
65VFSExplorer::VFSExplorer()
66 : mVirtualBox(NULL)
67{
68}
69
70VFSExplorer::~VFSExplorer()
71{
72}
73
74
75/**
76 * VFSExplorer COM initializer.
77 * @param aType VFS type.
78 * @param aFilePath File path.
79 * @param aHostname Host name.
80 * @param aUsername User name.
81 * @param aPassword Password.
82 * @param aVirtualBox VirtualBox object.
83 * @return
84 */
85HRESULT VFSExplorer::init(VFSType_T aType, Utf8Str aFilePath, Utf8Str aHostname, Utf8Str aUsername,
86 Utf8Str aPassword, VirtualBox *aVirtualBox)
87{
88 /* Enclose the state transition NotReady->InInit->Ready */
89 AutoInitSpan autoInitSpan(this);
90 AssertReturn(autoInitSpan.isOk(), E_FAIL);
91
92 /* Weak reference to a VirtualBox object */
93 unconst(mVirtualBox) = aVirtualBox;
94
95 /* initialize data */
96 m = new Data;
97
98 m->storageType = aType;
99 m->strPath = aFilePath;
100 m->strHostname = aHostname;
101 m->strUsername = aUsername;
102 m->strPassword = aPassword;
103
104 if (m->storageType == VFSType_S3)
105 {
106 size_t bpos = aFilePath.find("/", 1);
107 if (bpos != Utf8Str::npos)
108 {
109 m->strBucket = aFilePath.substr(1, bpos - 1); /* The bucket without any slashes */
110 aFilePath = aFilePath.substr(bpos); /* The rest of the file path */
111 }
112 }
113
114 /* Confirm a successful initialization */
115 autoInitSpan.setSucceeded();
116
117 return S_OK;
118}
119
120/**
121 * VFSExplorer COM uninitializer.
122 * @return
123 */
124void VFSExplorer::uninit()
125{
126 delete m;
127 m = NULL;
128}
129
130/**
131 * Public method implementation.
132 * @param aPath Where to store the path.
133 * @return
134 */
135HRESULT VFSExplorer::getPath(com::Utf8Str &aPath)
136{
137 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
138
139 aPath = m->strPath;
140
141 return S_OK;
142}
143
144
145HRESULT VFSExplorer::getType(VFSType_T *aType)
146{
147 if (!aType)
148 return E_POINTER;
149
150 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
151
152 *aType = m->storageType;
153
154 return S_OK;
155}
156
157class VFSExplorer::TaskVFSExplorer : public ThreadTask
158{
159public:
160 enum TaskType
161 {
162 Update,
163 Delete
164 };
165
166 TaskVFSExplorer(TaskType aTaskType, VFSExplorer *aThat, Progress *aProgress)
167 : m_taskType(aTaskType),
168 m_pVFSExplorer(aThat),
169 m_ptrProgress(aProgress),
170 m_rc(S_OK)
171 {
172 m_strTaskName = "Explorer::Task";
173 }
174 ~TaskVFSExplorer() {}
175
176private:
177 void handler();
178
179#if 0 /* unused */
180 static DECLCALLBACK(int) uploadProgress(unsigned uPercent, void *pvUser);
181#endif
182
183 TaskType m_taskType;
184 VFSExplorer *m_pVFSExplorer;
185
186 ComObjPtr<Progress> m_ptrProgress;
187 HRESULT m_rc;
188
189 /* task data */
190 std::list<Utf8Str> m_lstFilenames;
191
192 friend class VFSExplorer;
193};
194
195/* static */
196void VFSExplorer::TaskVFSExplorer::handler()
197{
198 VFSExplorer *pVFSExplorer = this->m_pVFSExplorer;
199
200 LogFlowFuncEnter();
201 LogFlowFunc(("VFSExplorer %p\n", pVFSExplorer));
202
203 HRESULT rc = S_OK;
204
205 switch (this->m_taskType)
206 {
207 case TaskVFSExplorer::Update:
208 {
209 if (pVFSExplorer->m->storageType == VFSType_File)
210 rc = pVFSExplorer->i_updateFS(this);
211 else if (pVFSExplorer->m->storageType == VFSType_S3)
212 rc = VERR_NOT_IMPLEMENTED;
213 break;
214 }
215 case TaskVFSExplorer::Delete:
216 {
217 if (pVFSExplorer->m->storageType == VFSType_File)
218 rc = pVFSExplorer->i_deleteFS(this);
219 else if (pVFSExplorer->m->storageType == VFSType_S3)
220 rc = VERR_NOT_IMPLEMENTED;
221 break;
222 }
223 default:
224 AssertMsgFailed(("Invalid task type %u specified!\n", this->m_taskType));
225 break;
226 }
227
228 LogFlowFunc(("rc=%Rhrc\n", rc)); NOREF(rc);
229 LogFlowFuncLeave();
230}
231
232#if 0 /* unused */
233/* static */
234DECLCALLBACK(int) VFSExplorer::TaskVFSExplorer::uploadProgress(unsigned uPercent, void *pvUser)
235{
236 VFSExplorer::TaskVFSExplorer* pTask = *(VFSExplorer::TaskVFSExplorer**)pvUser;
237
238 if (pTask &&
239 !pTask->m_ptrProgress.isNull())
240 {
241 BOOL fCanceled;
242 pTask->m_ptrProgress->COMGETTER(Canceled)(&fCanceled);
243 if (fCanceled)
244 return -1;
245 pTask->m_ptrProgress->SetCurrentOperationProgress(uPercent);
246 }
247 return VINF_SUCCESS;
248}
249#endif
250
251FsObjType_T VFSExplorer::i_iprtToVfsObjType(RTFMODE aType) const
252{
253 int a = aType & RTFS_TYPE_MASK;
254 FsObjType_T t = FsObjType_Unknown;
255 if ((a & RTFS_TYPE_DIRECTORY) == RTFS_TYPE_DIRECTORY)
256 t = FsObjType_Directory;
257 else if ((a & RTFS_TYPE_FILE) == RTFS_TYPE_FILE)
258 t = FsObjType_File;
259 else if ((a & RTFS_TYPE_SYMLINK) == RTFS_TYPE_SYMLINK)
260 t = FsObjType_Symlink;
261 else if ((a & RTFS_TYPE_FIFO) == RTFS_TYPE_FIFO)
262 t = FsObjType_Fifo;
263 else if ((a & RTFS_TYPE_DEV_CHAR) == RTFS_TYPE_DEV_CHAR)
264 t = FsObjType_DevChar;
265 else if ((a & RTFS_TYPE_DEV_BLOCK) == RTFS_TYPE_DEV_BLOCK)
266 t = FsObjType_DevBlock;
267 else if ((a & RTFS_TYPE_SOCKET) == RTFS_TYPE_SOCKET)
268 t = FsObjType_Socket;
269 else if ((a & RTFS_TYPE_WHITEOUT) == RTFS_TYPE_WHITEOUT)
270 t = FsObjType_WhiteOut;
271
272 return t;
273}
274
275HRESULT VFSExplorer::i_updateFS(TaskVFSExplorer *aTask)
276{
277 LogFlowFuncEnter();
278
279 AutoCaller autoCaller(this);
280 if (FAILED(autoCaller.rc())) return autoCaller.rc();
281
282 AutoWriteLock appLock(this COMMA_LOCKVAL_SRC_POS);
283
284 HRESULT rc = S_OK;
285
286 std::list<VFSExplorer::Data::DirEntry> fileList;
287 char *pszPath = NULL;
288 PRTDIR pDir = NULL;
289 try
290 {
291 int vrc = RTDirOpen(&pDir, m->strPath.c_str());
292 if (RT_FAILURE(vrc))
293 throw setError(VBOX_E_FILE_ERROR, tr ("Can't open directory '%s' (%Rrc)"), pszPath, vrc);
294
295 if (aTask->m_ptrProgress)
296 aTask->m_ptrProgress->SetCurrentOperationProgress(33);
297 RTDIRENTRYEX entry;
298 while (RT_SUCCESS(vrc))
299 {
300 vrc = RTDirReadEx(pDir, &entry, NULL, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
301 if (RT_SUCCESS(vrc))
302 {
303 Utf8Str name(entry.szName);
304 if ( name != "."
305 && name != "..")
306 fileList.push_back(VFSExplorer::Data::DirEntry(name, i_iprtToVfsObjType(entry.Info.Attr.fMode),
307 entry.Info.cbObject,
308 entry.Info.Attr.fMode & (RTFS_UNIX_IRWXU | RTFS_UNIX_IRWXG | RTFS_UNIX_IRWXO)));
309 }
310 }
311 if (aTask->m_ptrProgress)
312 aTask->m_ptrProgress->SetCurrentOperationProgress(66);
313 }
314 catch(HRESULT aRC)
315 {
316 rc = aRC;
317 }
318
319 /* Clean up */
320 if (pszPath)
321 RTStrFree(pszPath);
322 if (pDir)
323 RTDirClose(pDir);
324
325 if (aTask->m_ptrProgress)
326 aTask->m_ptrProgress->SetCurrentOperationProgress(99);
327
328 /* Assign the result on success (this clears the old list) */
329 if (rc == S_OK)
330 m->entryList.assign(fileList.begin(), fileList.end());
331
332 aTask->m_rc = rc;
333
334 if (!aTask->m_ptrProgress.isNull())
335 aTask->m_ptrProgress->i_notifyComplete(rc);
336
337 LogFlowFunc(("rc=%Rhrc\n", rc));
338 LogFlowFuncLeave();
339
340 return VINF_SUCCESS;
341}
342
343HRESULT VFSExplorer::i_deleteFS(TaskVFSExplorer *aTask)
344{
345 LogFlowFuncEnter();
346
347 AutoCaller autoCaller(this);
348 if (FAILED(autoCaller.rc())) return autoCaller.rc();
349
350 AutoWriteLock appLock(this COMMA_LOCKVAL_SRC_POS);
351
352 HRESULT rc = S_OK;
353
354 float fPercentStep = 100.0f / (float)aTask->m_lstFilenames.size();
355 try
356 {
357 char szPath[RTPATH_MAX];
358 std::list<Utf8Str>::const_iterator it;
359 size_t i = 0;
360 for (it = aTask->m_lstFilenames.begin();
361 it != aTask->m_lstFilenames.end();
362 ++it, ++i)
363 {
364 int vrc = RTPathJoin(szPath, sizeof(szPath), m->strPath.c_str(), (*it).c_str());
365 if (RT_FAILURE(vrc))
366 throw setError(E_FAIL, tr("Internal Error (%Rrc)"), vrc);
367 vrc = RTFileDelete(szPath);
368 if (RT_FAILURE(vrc))
369 throw setError(VBOX_E_FILE_ERROR, tr("Can't delete file '%s' (%Rrc)"), szPath, vrc);
370 if (aTask->m_ptrProgress)
371 aTask->m_ptrProgress->SetCurrentOperationProgress((ULONG)(fPercentStep * (float)i));
372 }
373 }
374 catch (HRESULT aRC)
375 {
376 rc = aRC;
377 }
378
379 aTask->m_rc = rc;
380
381 if (aTask->m_ptrProgress.isNotNull())
382 aTask->m_ptrProgress->i_notifyComplete(rc);
383
384 LogFlowFunc(("rc=%Rhrc\n", rc));
385 LogFlowFuncLeave();
386
387 return VINF_SUCCESS;
388}
389
390HRESULT VFSExplorer::update(ComPtr<IProgress> &aProgress)
391{
392 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
393
394 HRESULT rc = S_OK;
395
396 ComObjPtr<Progress> progress;
397 try
398 {
399 Bstr progressDesc = BstrFmt(tr("Update directory info for '%s'"),
400 m->strPath.c_str());
401 /* Create the progress object */
402 progress.createObject();
403
404 rc = progress->init(mVirtualBox,
405 static_cast<IVFSExplorer*>(this),
406 progressDesc.raw(),
407 TRUE /* aCancelable */);
408 if (FAILED(rc)) throw rc;
409
410 /* Initialize our worker task */
411 TaskVFSExplorer* pTask = new TaskVFSExplorer(TaskVFSExplorer::Update, this, progress);
412
413 //this function delete task in case of exceptions, so there is no need in the call of delete operator
414 rc = pTask->createThreadWithType(RTTHREADTYPE_MAIN_HEAVY_WORKER);
415 }
416 catch (HRESULT aRC)
417 {
418 rc = aRC;
419 }
420
421 if (SUCCEEDED(rc))
422 /* Return progress to the caller */
423 progress.queryInterfaceTo(aProgress.asOutParam());
424
425 return rc;
426}
427
428HRESULT VFSExplorer::cd(const com::Utf8Str &aDir, ComPtr<IProgress> &aProgress)
429{
430 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
431 m->strPath = aDir;
432 return update(aProgress);
433}
434
435HRESULT VFSExplorer::cdUp(ComPtr<IProgress> &aProgress)
436{
437 Utf8Str strUpPath;
438 {
439 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
440 /* Remove lowest dir entry in a platform neutral way. */
441 char *pszNewPath = RTStrDup(m->strPath.c_str());
442 RTPathStripTrailingSlash(pszNewPath);
443 RTPathStripFilename(pszNewPath);
444 strUpPath = pszNewPath;
445 RTStrFree(pszNewPath);
446 }
447
448 return cd(strUpPath, aProgress);
449}
450
451HRESULT VFSExplorer::entryList(std::vector<com::Utf8Str> &aNames,
452 std::vector<ULONG> &aTypes,
453 std::vector<LONG64> &aSizes,
454 std::vector<ULONG> &aModes)
455{
456 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
457 aNames.resize(m->entryList.size());
458 aTypes.resize(m->entryList.size());
459 aSizes.resize(m->entryList.size());
460 aModes.resize(m->entryList.size());
461
462 std::list<VFSExplorer::Data::DirEntry>::const_iterator it;
463 size_t i = 0;
464 for (it = m->entryList.begin();
465 it != m->entryList.end();
466 ++it, ++i)
467 {
468 const VFSExplorer::Data::DirEntry &entry = (*it);
469 aNames[i] = entry.name;
470 aTypes[i] = entry.type;
471 aSizes[i] = entry.size;
472 aModes[i] = entry.mode;
473 }
474
475 return S_OK;
476}
477
478HRESULT VFSExplorer::exists(const std::vector<com::Utf8Str> &aNames,
479 std::vector<com::Utf8Str> &aExists)
480{
481
482 AutoCaller autoCaller(this);
483 if (FAILED(autoCaller.rc())) return autoCaller.rc();
484
485 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
486 aExists.resize(0);
487 for (size_t i=0; i < aNames.size(); ++i)
488 {
489 std::list<VFSExplorer::Data::DirEntry>::const_iterator it;
490 for (it = m->entryList.begin();
491 it != m->entryList.end();
492 ++it)
493 {
494 const VFSExplorer::Data::DirEntry &entry = (*it);
495 if (entry.name == RTPathFilename(aNames[i].c_str()))
496 aExists.push_back(aNames[i]);
497 }
498 }
499
500 return S_OK;
501}
502
503HRESULT VFSExplorer::remove(const std::vector<com::Utf8Str> &aNames,
504 ComPtr<IProgress> &aProgress)
505{
506 AutoCaller autoCaller(this);
507 if (FAILED(autoCaller.rc())) return autoCaller.rc();
508
509 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
510
511 HRESULT rc = S_OK;
512
513 ComObjPtr<Progress> progress;
514 try
515 {
516 /* Create the progress object */
517 progress.createObject();
518
519 rc = progress->init(mVirtualBox, static_cast<IVFSExplorer*>(this),
520 Bstr(tr("Delete files")).raw(),
521 TRUE /* aCancelable */);
522 if (FAILED(rc)) throw rc;
523
524 /* Initialize our worker task */
525 TaskVFSExplorer* pTask = new TaskVFSExplorer(TaskVFSExplorer::Delete, this, progress);
526
527 /* Add all filenames to delete as task data */
528 for (size_t i = 0; i < aNames.size(); ++i)
529 pTask->m_lstFilenames.push_back(aNames[i]);
530
531 //this function delete task in case of exceptions, so there is no need in the call of delete operator
532 rc = pTask->createThreadWithType(RTTHREADTYPE_MAIN_HEAVY_WORKER);
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
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