VirtualBox

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

Last change on this file since 63174 was 62485, checked in by vboxsync, 8 years ago

(C) 2016

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