VirtualBox

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

Last change on this file since 97698 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

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