VirtualBox

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

Last change on this file since 104956 was 99739, checked in by vboxsync, 19 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
Line 
1/* $Id: VFSExplorerImpl.cpp 99739 2023-05-11 01:01:08Z vboxsync $ */
2/** @file
3 * IVFSExplorer COM class implementations.
4 */
5
6/*
7 * Copyright (C) 2009-2023 Oracle and/or its affiliates.
8 *
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
26 */
27
28#define LOG_GROUP LOG_GROUP_MAIN_VFSEXPLORER
29#include <iprt/dir.h>
30#include <iprt/path.h>
31#include <iprt/file.h>
32#include <iprt/cpp/utils.h>
33
34#include <VBox/com/array.h>
35
36#include <VBox/param.h>
37#include <VBox/version.h>
38
39#include "VFSExplorerImpl.h"
40#include "VirtualBoxImpl.h"
41#include "ProgressImpl.h"
42
43#include "AutoCaller.h"
44#include "LoggingNew.h"
45#include "ThreadTask.h"
46
47#include <memory>
48
49struct VFSExplorer::Data
50{
51 struct DirEntry
52 {
53 DirEntry(Utf8Str strName, FsObjType_T fileType, RTFOFF cbSize, uint32_t fMode)
54 : name(strName)
55 , type(fileType)
56 , size(cbSize)
57 , mode(fMode) {}
58
59 Utf8Str name;
60 FsObjType_T type;
61 RTFOFF size;
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
75VFSExplorer::VFSExplorer()
76 : mVirtualBox(NULL)
77{
78}
79
80VFSExplorer::~VFSExplorer()
81{
82}
83
84
85/**
86 * VFSExplorer COM initializer.
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.
93 * @return
94 */
95HRESULT VFSExplorer::init(VFSType_T aType, Utf8Str aFilePath, Utf8Str aHostname, Utf8Str aUsername,
96 Utf8Str aPassword, VirtualBox *aVirtualBox)
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.
141 * @param aPath Where to store the path.
142 * @return S_OK
143 */
144HRESULT VFSExplorer::getPath(com::Utf8Str &aPath)
145{
146 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
147
148 aPath = m->strPath;
149
150 return S_OK;
151}
152
153
154HRESULT VFSExplorer::getType(VFSType_T *aType)
155{
156 if (!aType)
157 return E_POINTER;
158
159 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
160
161 *aType = m->storageType;
162
163 return S_OK;
164}
165
166class VFSExplorer::TaskVFSExplorer : public ThreadTask
167{
168public:
169 enum TaskType
170 {
171 Update,
172 Delete
173 };
174
175 TaskVFSExplorer(TaskType aTaskType, VFSExplorer *aThat, Progress *aProgress)
176 : m_taskType(aTaskType),
177 m_pVFSExplorer(aThat),
178 m_ptrProgress(aProgress),
179 m_rc(S_OK)
180 {
181 m_strTaskName = "Explorer::Task";
182 }
183 ~TaskVFSExplorer() {}
184
185private:
186 void handler();
187
188#if 0 /* unused */
189 static DECLCALLBACK(int) uploadProgress(unsigned uPercent, void *pvUser);
190#endif
191
192 TaskType m_taskType;
193 VFSExplorer *m_pVFSExplorer;
194
195 ComObjPtr<Progress> m_ptrProgress;
196 HRESULT m_rc;
197
198 /* task data */
199 std::list<Utf8Str> m_lstFilenames;
200
201 friend class VFSExplorer;
202};
203
204/* static */
205void VFSExplorer::TaskVFSExplorer::handler()
206{
207 VFSExplorer *pVFSExplorer = this->m_pVFSExplorer;
208
209 LogFlowFuncEnter();
210 LogFlowFunc(("VFSExplorer %p\n", pVFSExplorer));
211
212 HRESULT hrc = S_OK;
213
214 switch (this->m_taskType)
215 {
216 case TaskVFSExplorer::Update:
217 {
218 if (pVFSExplorer->m->storageType == VFSType_File)
219 hrc = pVFSExplorer->i_updateFS(this);
220 else if (pVFSExplorer->m->storageType == VFSType_S3)
221 hrc = E_NOTIMPL;
222 break;
223 }
224 case TaskVFSExplorer::Delete:
225 {
226 if (pVFSExplorer->m->storageType == VFSType_File)
227 hrc = pVFSExplorer->i_deleteFS(this);
228 else if (pVFSExplorer->m->storageType == VFSType_S3)
229 hrc = E_NOTIMPL;
230 break;
231 }
232 default:
233 AssertMsgFailed(("Invalid task type %u specified!\n", this->m_taskType));
234 break;
235 }
236
237 LogFlowFunc(("hrc=%Rhrc\n", hrc)); NOREF(hrc);
238 LogFlowFuncLeave();
239}
240
241#if 0 /* unused */
242/* static */
243DECLCALLBACK(int) VFSExplorer::TaskVFSExplorer::uploadProgress(unsigned uPercent, void *pvUser)
244{
245 VFSExplorer::TaskVFSExplorer* pTask = *(VFSExplorer::TaskVFSExplorer**)pvUser;
246
247 if (pTask &&
248 !pTask->m_ptrProgress.isNull())
249 {
250 BOOL fCanceled;
251 pTask->m_ptrProgress->COMGETTER(Canceled)(&fCanceled);
252 if (fCanceled)
253 return -1;
254 pTask->m_ptrProgress->SetCurrentOperationProgress(uPercent);
255 }
256 return VINF_SUCCESS;
257}
258#endif
259
260FsObjType_T VFSExplorer::i_iprtToVfsObjType(RTFMODE aType) const
261{
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 }
274}
275
276HRESULT VFSExplorer::i_updateFS(TaskVFSExplorer *aTask)
277{
278 LogFlowFuncEnter();
279
280 AutoCaller autoCaller(this);
281 if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
282
283 AutoWriteLock appLock(this COMMA_LOCKVAL_SRC_POS);
284
285 HRESULT hrc = 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
308 & (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 hrcXcpt)
315 {
316 hrc = hrcXcpt;
317 }
318
319 /* Clean up */
320 RTDirClose(hDir);
321 }
322 else
323 hrc = setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr ("Can't open directory '%s' (%Rrc)"), m->strPath.c_str(), vrc);
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 (hrc == S_OK)
330 m->entryList.assign(fileList.begin(), fileList.end());
331
332 aTask->m_rc = hrc;
333
334 if (!aTask->m_ptrProgress.isNull())
335 aTask->m_ptrProgress->i_notifyComplete(hrc);
336
337 LogFlowFunc(("hrc=%Rhrc\n", hrc));
338 LogFlowFuncLeave();
339
340 return S_OK; /** @todo ??? */
341}
342
343HRESULT VFSExplorer::i_deleteFS(TaskVFSExplorer *aTask)
344{
345 LogFlowFuncEnter();
346
347 AutoCaller autoCaller(this);
348 if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
349
350 AutoWriteLock appLock(this COMMA_LOCKVAL_SRC_POS);
351
352 HRESULT hrc = 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 setErrorBoth(E_FAIL, vrc, tr("Internal Error (%Rrc)"), vrc);
367 vrc = RTFileDelete(szPath);
368 if (RT_FAILURE(vrc))
369 throw setErrorBoth(VBOX_E_FILE_ERROR, vrc, 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 hrcXcpt)
375 {
376 hrc = hrcXcpt;
377 }
378
379 aTask->m_rc = hrc;
380
381 if (aTask->m_ptrProgress.isNotNull())
382 aTask->m_ptrProgress->i_notifyComplete(hrc);
383
384 LogFlowFunc(("hrc=%Rhrc\n", hrc));
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 hrc = 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 hrc = progress->init(mVirtualBox, static_cast<IVFSExplorer*>(this), progressDesc.raw(), TRUE /* aCancelable */);
405 if (FAILED(hrc)) throw hrc;
406
407 /* Initialize our worker task */
408 TaskVFSExplorer* pTask = new TaskVFSExplorer(TaskVFSExplorer::Update, this, progress);
409
410 //this function delete task in case of exceptions, so there is no need in the call of delete operator
411 hrc = pTask->createThreadWithType(RTTHREADTYPE_MAIN_HEAVY_WORKER);
412 }
413 catch (HRESULT hrcXcpt)
414 {
415 hrc = hrcXcpt;
416 }
417
418 if (SUCCEEDED(hrc))
419 /* Return progress to the caller */
420 progress.queryInterfaceTo(aProgress.asOutParam());
421
422 return hrc;
423}
424
425HRESULT VFSExplorer::cd(const com::Utf8Str &aDir, ComPtr<IProgress> &aProgress)
426{
427 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
428 m->strPath = aDir;
429 return update(aProgress);
430}
431
432HRESULT VFSExplorer::cdUp(ComPtr<IProgress> &aProgress)
433{
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
445 return cd(strUpPath, aProgress);
446}
447
448HRESULT VFSExplorer::entryList(std::vector<com::Utf8Str> &aNames,
449 std::vector<ULONG> &aTypes,
450 std::vector<LONG64> &aSizes,
451 std::vector<ULONG> &aModes)
452{
453 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
454 aNames.resize(m->entryList.size());
455 aTypes.resize(m->entryList.size());
456 aSizes.resize(m->entryList.size());
457 aModes.resize(m->entryList.size());
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);
466 aNames[i] = entry.name;
467 aTypes[i] = entry.type;
468 aSizes[i] = entry.size;
469 aModes[i] = entry.mode;
470 }
471
472 return S_OK;
473}
474
475HRESULT VFSExplorer::exists(const std::vector<com::Utf8Str> &aNames,
476 std::vector<com::Utf8Str> &aExists)
477{
478
479 AutoCaller autoCaller(this);
480 if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
481
482 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
483 aExists.resize(0);
484 for (size_t i=0; i < aNames.size(); ++i)
485 {
486 std::list<VFSExplorer::Data::DirEntry>::const_iterator it;
487 for (it = m->entryList.begin();
488 it != m->entryList.end();
489 ++it)
490 {
491 const VFSExplorer::Data::DirEntry &entry = (*it);
492 if (entry.name == RTPathFilename(aNames[i].c_str()))
493 aExists.push_back(aNames[i]);
494 }
495 }
496
497 return S_OK;
498}
499
500HRESULT VFSExplorer::remove(const std::vector<com::Utf8Str> &aNames,
501 ComPtr<IProgress> &aProgress)
502{
503 AutoCaller autoCaller(this);
504 if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
505
506 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
507
508 HRESULT hrc = S_OK;
509
510 ComObjPtr<Progress> progress;
511 try
512 {
513 /* Create the progress object */
514 progress.createObject();
515
516 hrc = progress->init(mVirtualBox, static_cast<IVFSExplorer*>(this),
517 Bstr(tr("Delete files")).raw(),
518 TRUE /* aCancelable */);
519 if (FAILED(hrc)) throw hrc;
520
521 /* Initialize our worker task */
522 TaskVFSExplorer* pTask = new TaskVFSExplorer(TaskVFSExplorer::Delete, this, progress);
523
524 /* Add all filenames to delete as task data */
525 for (size_t i = 0; i < aNames.size(); ++i)
526 pTask->m_lstFilenames.push_back(aNames[i]);
527
528 //this function delete task in case of exceptions, so there is no need in the call of delete operator
529 hrc = pTask->createThreadWithType(RTTHREADTYPE_MAIN_HEAVY_WORKER);
530 }
531 catch (HRESULT hrcXcpt)
532 {
533 hrc = hrcXcpt;
534 }
535
536 if (SUCCEEDED(hrc))
537 /* Return progress to the caller */
538 progress.queryInterfaceTo(aProgress.asOutParam());
539
540 return hrc;
541}
542
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