VirtualBox

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

Last change on this file since 103068 was 99739, checked in by vboxsync, 16 months ago

*: doxygen corrections (mostly about removing @returns from functions returning void).

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

© 2024 Oracle
ContactPrivacy/Do Not Sell My InfoTerms of Use