VirtualBox

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

Last change on this file since 78242 was 76592, checked in by vboxsync, 6 years ago

Main: Don't use Logging.h.

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