VirtualBox

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

Last change on this file since 74897 was 73003, checked in by vboxsync, 6 years ago

Main: Use setErrorBoth when we've got a VBox status code handy. (The COM status codes aren't too specfic and this may help us decode error messages and provide an alternative to strstr for API clients. setErrorBoth isn't new, btw.)

  • 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 73003 2018-07-09 11:09:32Z 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 = setErrorBoth(VBOX_E_FILE_ERROR, vrc, 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 setErrorBoth(E_FAIL, vrc, tr("Internal Error (%Rrc)"), vrc);
365 vrc = RTFileDelete(szPath);
366 if (RT_FAILURE(vrc))
367 throw setErrorBoth(VBOX_E_FILE_ERROR, vrc, 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