VirtualBox

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

Last change on this file since 70161 was 69753, checked in by vboxsync, 7 years ago

iprt/dir: Morphing PRTDIR into a handle named RTDIR. (Been wanting to correct this for years. Don't know why I makde it a pointer rather than an abstrct handle like everything else.)

  • 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 69753 2017-11-19 14:27:58Z 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 RTDIR hDir;
288 int vrc = RTDirOpen(&hDir, m->strPath.c_str());
289 if (RT_SUCCESS(vrc))
290 {
291 try
292 {
293 if (aTask->m_ptrProgress)
294 aTask->m_ptrProgress->SetCurrentOperationProgress(33);
295 RTDIRENTRYEX entry;
296 while (RT_SUCCESS(vrc))
297 {
298 vrc = RTDirReadEx(hDir, &entry, NULL, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
299 if (RT_SUCCESS(vrc))
300 {
301 Utf8Str name(entry.szName);
302 if ( name != "."
303 && name != "..")
304 fileList.push_back(VFSExplorer::Data::DirEntry(name, i_iprtToVfsObjType(entry.Info.Attr.fMode),
305 entry.Info.cbObject,
306 entry.Info.Attr.fMode & (RTFS_UNIX_IRWXU | RTFS_UNIX_IRWXG | RTFS_UNIX_IRWXO)));
307 }
308 }
309 if (aTask->m_ptrProgress)
310 aTask->m_ptrProgress->SetCurrentOperationProgress(66);
311 }
312 catch (HRESULT aRC)
313 {
314 rc = aRC;
315 }
316
317 /* Clean up */
318 RTDirClose(hDir);
319 }
320 else
321 rc = setError(VBOX_E_FILE_ERROR, tr ("Can't open directory '%s' (%Rrc)"), m->strPath.c_str(), vrc);
322
323 if (aTask->m_ptrProgress)
324 aTask->m_ptrProgress->SetCurrentOperationProgress(99);
325
326 /* Assign the result on success (this clears the old list) */
327 if (rc == S_OK)
328 m->entryList.assign(fileList.begin(), fileList.end());
329
330 aTask->m_rc = rc;
331
332 if (!aTask->m_ptrProgress.isNull())
333 aTask->m_ptrProgress->i_notifyComplete(rc);
334
335 LogFlowFunc(("rc=%Rhrc\n", rc));
336 LogFlowFuncLeave();
337
338 return VINF_SUCCESS;
339}
340
341HRESULT VFSExplorer::i_deleteFS(TaskVFSExplorer *aTask)
342{
343 LogFlowFuncEnter();
344
345 AutoCaller autoCaller(this);
346 if (FAILED(autoCaller.rc())) return autoCaller.rc();
347
348 AutoWriteLock appLock(this COMMA_LOCKVAL_SRC_POS);
349
350 HRESULT rc = S_OK;
351
352 float fPercentStep = 100.0f / (float)aTask->m_lstFilenames.size();
353 try
354 {
355 char szPath[RTPATH_MAX];
356 std::list<Utf8Str>::const_iterator it;
357 size_t i = 0;
358 for (it = aTask->m_lstFilenames.begin();
359 it != aTask->m_lstFilenames.end();
360 ++it, ++i)
361 {
362 int vrc = RTPathJoin(szPath, sizeof(szPath), m->strPath.c_str(), (*it).c_str());
363 if (RT_FAILURE(vrc))
364 throw setError(E_FAIL, tr("Internal Error (%Rrc)"), vrc);
365 vrc = RTFileDelete(szPath);
366 if (RT_FAILURE(vrc))
367 throw setError(VBOX_E_FILE_ERROR, tr("Can't delete file '%s' (%Rrc)"), szPath, vrc);
368 if (aTask->m_ptrProgress)
369 aTask->m_ptrProgress->SetCurrentOperationProgress((ULONG)(fPercentStep * (float)i));
370 }
371 }
372 catch (HRESULT aRC)
373 {
374 rc = aRC;
375 }
376
377 aTask->m_rc = rc;
378
379 if (aTask->m_ptrProgress.isNotNull())
380 aTask->m_ptrProgress->i_notifyComplete(rc);
381
382 LogFlowFunc(("rc=%Rhrc\n", rc));
383 LogFlowFuncLeave();
384
385 return VINF_SUCCESS;
386}
387
388HRESULT VFSExplorer::update(ComPtr<IProgress> &aProgress)
389{
390 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
391
392 HRESULT rc = S_OK;
393
394 ComObjPtr<Progress> progress;
395 try
396 {
397 Bstr progressDesc = BstrFmt(tr("Update directory info for '%s'"),
398 m->strPath.c_str());
399 /* Create the progress object */
400 progress.createObject();
401
402 rc = progress->init(mVirtualBox,
403 static_cast<IVFSExplorer*>(this),
404 progressDesc.raw(),
405 TRUE /* aCancelable */);
406 if (FAILED(rc)) throw rc;
407
408 /* Initialize our worker task */
409 TaskVFSExplorer* pTask = new TaskVFSExplorer(TaskVFSExplorer::Update, this, progress);
410
411 //this function delete task in case of exceptions, so there is no need in the call of delete operator
412 rc = pTask->createThreadWithType(RTTHREADTYPE_MAIN_HEAVY_WORKER);
413 }
414 catch (HRESULT aRC)
415 {
416 rc = aRC;
417 }
418
419 if (SUCCEEDED(rc))
420 /* Return progress to the caller */
421 progress.queryInterfaceTo(aProgress.asOutParam());
422
423 return rc;
424}
425
426HRESULT VFSExplorer::cd(const com::Utf8Str &aDir, ComPtr<IProgress> &aProgress)
427{
428 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
429 m->strPath = aDir;
430 return update(aProgress);
431}
432
433HRESULT VFSExplorer::cdUp(ComPtr<IProgress> &aProgress)
434{
435 Utf8Str strUpPath;
436 {
437 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
438 /* Remove lowest dir entry in a platform neutral way. */
439 char *pszNewPath = RTStrDup(m->strPath.c_str());
440 RTPathStripTrailingSlash(pszNewPath);
441 RTPathStripFilename(pszNewPath);
442 strUpPath = pszNewPath;
443 RTStrFree(pszNewPath);
444 }
445
446 return cd(strUpPath, aProgress);
447}
448
449HRESULT VFSExplorer::entryList(std::vector<com::Utf8Str> &aNames,
450 std::vector<ULONG> &aTypes,
451 std::vector<LONG64> &aSizes,
452 std::vector<ULONG> &aModes)
453{
454 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
455 aNames.resize(m->entryList.size());
456 aTypes.resize(m->entryList.size());
457 aSizes.resize(m->entryList.size());
458 aModes.resize(m->entryList.size());
459
460 std::list<VFSExplorer::Data::DirEntry>::const_iterator it;
461 size_t i = 0;
462 for (it = m->entryList.begin();
463 it != m->entryList.end();
464 ++it, ++i)
465 {
466 const VFSExplorer::Data::DirEntry &entry = (*it);
467 aNames[i] = entry.name;
468 aTypes[i] = entry.type;
469 aSizes[i] = entry.size;
470 aModes[i] = entry.mode;
471 }
472
473 return S_OK;
474}
475
476HRESULT VFSExplorer::exists(const std::vector<com::Utf8Str> &aNames,
477 std::vector<com::Utf8Str> &aExists)
478{
479
480 AutoCaller autoCaller(this);
481 if (FAILED(autoCaller.rc())) return autoCaller.rc();
482
483 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
484 aExists.resize(0);
485 for (size_t i=0; i < aNames.size(); ++i)
486 {
487 std::list<VFSExplorer::Data::DirEntry>::const_iterator it;
488 for (it = m->entryList.begin();
489 it != m->entryList.end();
490 ++it)
491 {
492 const VFSExplorer::Data::DirEntry &entry = (*it);
493 if (entry.name == RTPathFilename(aNames[i].c_str()))
494 aExists.push_back(aNames[i]);
495 }
496 }
497
498 return S_OK;
499}
500
501HRESULT VFSExplorer::remove(const std::vector<com::Utf8Str> &aNames,
502 ComPtr<IProgress> &aProgress)
503{
504 AutoCaller autoCaller(this);
505 if (FAILED(autoCaller.rc())) return autoCaller.rc();
506
507 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
508
509 HRESULT rc = S_OK;
510
511 ComObjPtr<Progress> progress;
512 try
513 {
514 /* Create the progress object */
515 progress.createObject();
516
517 rc = progress->init(mVirtualBox, static_cast<IVFSExplorer*>(this),
518 Bstr(tr("Delete files")).raw(),
519 TRUE /* aCancelable */);
520 if (FAILED(rc)) throw rc;
521
522 /* Initialize our worker task */
523 TaskVFSExplorer* pTask = new TaskVFSExplorer(TaskVFSExplorer::Delete, this, progress);
524
525 /* Add all filenames to delete as task data */
526 for (size_t i = 0; i < aNames.size(); ++i)
527 pTask->m_lstFilenames.push_back(aNames[i]);
528
529 //this function delete task in case of exceptions, so there is no need in the call of delete operator
530 rc = pTask->createThreadWithType(RTTHREADTYPE_MAIN_HEAVY_WORKER);
531 }
532 catch (HRESULT aRC)
533 {
534 rc = aRC;
535 }
536
537 if (SUCCEEDED(rc))
538 /* Return progress to the caller */
539 progress.queryInterfaceTo(aProgress.asOutParam());
540
541 return rc;
542}
543
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