VirtualBox

source: vbox/trunk/src/VBox/GuestHost/DragAndDrop/DnDURIObject.cpp@ 77807

Last change on this file since 77807 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.9 KB
Line 
1/* $Id: DnDURIObject.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * DnD - URI object class. For handling creation/reading/writing to files and directories on host or guest side.
4 */
5
6/*
7 * Copyright (C) 2014-2019 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
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_GUEST_DND
23#include <VBox/GuestHost/DragAndDrop.h>
24
25#include <iprt/dir.h>
26#include <iprt/err.h>
27#include <iprt/file.h>
28#include <iprt/fs.h>
29#include <iprt/path.h>
30#include <iprt/uri.h>
31
32#include <VBox/log.h>
33
34
35DnDURIObject::DnDURIObject(void)
36 : m_enmType(Type_Unknown)
37 , m_enmView(View_Unknown)
38 , m_fIsOpen(false)
39{
40 RT_ZERO(u);
41}
42
43DnDURIObject::DnDURIObject(Type enmType,
44 const RTCString &strSrcPathAbs /* = 0 */,
45 const RTCString &strDstPathAbs /* = 0 */)
46 : m_enmType(enmType)
47 , m_enmView(View_Unknown)
48 , m_strSrcPathAbs(strSrcPathAbs)
49 , m_strTgtPathAbs(strDstPathAbs)
50 , m_fIsOpen(false)
51{
52 RT_ZERO(u);
53}
54
55DnDURIObject::~DnDURIObject(void)
56{
57 closeInternal();
58}
59
60/**
61 * Closes the object's internal handles (to files / ...).
62 *
63 */
64void DnDURIObject::closeInternal(void)
65{
66 LogFlowThisFuncEnter();
67
68 if (!m_fIsOpen)
69 return;
70
71 switch (m_enmType)
72 {
73 case Type_File:
74 {
75 RTFileClose(u.File.hFile);
76 u.File.hFile = NIL_RTFILE;
77 RT_ZERO(u.File.objInfo);
78 break;
79 }
80
81 case Type_Directory:
82 {
83 RTDirClose(u.Dir.hDir);
84 u.Dir.hDir = NIL_RTDIR;
85 RT_ZERO(u.Dir.objInfo);
86 break;
87 }
88
89 default:
90 break;
91 }
92
93 m_fIsOpen = false;
94}
95
96/**
97 * Closes the object.
98 * This also closes the internal handles associated with the object (to files / ...).
99 */
100void DnDURIObject::Close(void)
101{
102 closeInternal();
103}
104
105/**
106 * Returns the directory / file mode of the object.
107 *
108 * @return File / directory mode.
109 */
110RTFMODE DnDURIObject::GetMode(void) const
111{
112 switch (m_enmType)
113 {
114 case Type_File:
115 return u.File.objInfo.Attr.fMode;
116
117 case Type_Directory:
118 return u.Dir.objInfo.Attr.fMode;
119
120 default:
121 break;
122 }
123
124 AssertFailed();
125 return 0;
126}
127
128/**
129 * Returns the bytes already processed (read / written).
130 *
131 * Note: Only applies if the object is of type DnDURIObject::Type_File.
132 *
133 * @return Bytes already processed (read / written).
134 */
135uint64_t DnDURIObject::GetProcessed(void) const
136{
137 if (m_enmType == Type_File)
138 return u.File.cbProcessed;
139
140 return 0;
141}
142
143/**
144 * Returns the file's logical size (in bytes).
145 *
146 * Note: Only applies if the object is of type DnDURIObject::Type_File.
147 *
148 * @return The file's logical size (in bytes).
149 */
150uint64_t DnDURIObject::GetSize(void) const
151{
152 if (m_enmType == Type_File)
153 return u.File.cbToProcess;
154
155 return 0;
156}
157
158/**
159 * Returns whether the processing of the object is complete or not.
160 * For file objects this means that all bytes have been processed.
161 *
162 * @return True if complete, False if not.
163 */
164bool DnDURIObject::IsComplete(void) const
165{
166 bool fComplete;
167
168 switch (m_enmType)
169 {
170 case Type_File:
171 Assert(u.File.cbProcessed <= u.File.cbToProcess);
172 fComplete = u.File.cbProcessed == u.File.cbToProcess;
173 break;
174
175 case Type_Directory:
176 fComplete = true;
177 break;
178
179 default:
180 fComplete = true;
181 break;
182 }
183
184 return fComplete;
185}
186
187/**
188 * Returns whether the object is in an open state or not.
189 */
190bool DnDURIObject::IsOpen(void) const
191{
192 return m_fIsOpen;
193}
194
195/**
196 * (Re-)Opens the object with a specific view, open and file mode.
197 *
198 * @return IPRT status code.
199 * @param enmView View to use for opening the object.
200 * @param fOpen File open flags to use.
201 * @param fMode File mode to use.
202 */
203int DnDURIObject::Open(View enmView, uint64_t fOpen /* = 0 */, RTFMODE fMode /* = 0 */)
204{
205 return OpenEx( enmView == View_Source
206 ? m_strSrcPathAbs : m_strTgtPathAbs
207 , enmView, fOpen, fMode, DNDURIOBJECT_FLAGS_NONE);
208}
209
210/**
211 * Open the object with a specific file type, and, depending on the type, specifying additional parameters.
212 *
213 * @return IPRT status code.
214 * @param strPathAbs Absolute path of the object (file / directory / ...).
215 * @param enmView View of the object.
216 * @param fOpen Open mode to use; only valid for file objects.
217 * @param fMode File mode to use; only valid for file objects.
218 * @param fFlags Additional DnD URI object flags.
219 */
220int DnDURIObject::OpenEx(const RTCString &strPathAbs, View enmView,
221 uint64_t fOpen /* = 0 */, RTFMODE fMode /* = 0 */, DNDURIOBJECTFLAGS fFlags /* = DNDURIOBJECT_FLAGS_NONE */)
222{
223 AssertReturn(!(fFlags & ~DNDURIOBJECT_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);
224 RT_NOREF1(fFlags);
225
226 if (m_fIsOpen)
227 return VINF_SUCCESS;
228
229 int rc = VINF_SUCCESS;
230
231 switch (enmView)
232 {
233 case View_Source:
234 m_strSrcPathAbs = strPathAbs;
235 break;
236
237 case View_Target:
238 m_strTgtPathAbs = strPathAbs;
239 break;
240
241 default:
242 rc = VERR_NOT_IMPLEMENTED;
243 break;
244 }
245
246 if ( RT_SUCCESS(rc)
247 && fOpen) /* Opening mode specified? */
248 {
249 LogFlowThisFunc(("strPath=%s, enmView=%RU32, fOpen=0x%x, fMode=0x%x, fFlags=0x%x\n",
250 strPathAbs.c_str(), enmView, fOpen, fMode, fFlags));
251 switch (m_enmType)
252 {
253 case Type_File:
254 {
255 /*
256 * Open files on the source with RTFILE_O_DENY_WRITE to prevent races
257 * where the OS writes to the file while the destination side transfers
258 * it over.
259 */
260 LogFlowThisFunc(("Opening ...\n"));
261 rc = RTFileOpen(&u.File.hFile, strPathAbs.c_str(), fOpen);
262 if (RT_SUCCESS(rc))
263 {
264 if ( (fOpen & RTFILE_O_WRITE) /* Only set the file mode on write. */
265 && fMode /* Some file mode to set specified? */)
266 {
267 rc = RTFileSetMode(u.File.hFile, fMode);
268 }
269 else if (fOpen & RTFILE_O_READ)
270 {
271 rc = queryInfoInternal(enmView);
272 }
273 }
274
275 if (RT_SUCCESS(rc))
276 {
277 LogFlowThisFunc(("File cbObject=%RU64, fMode=0x%x\n",
278 u.File.objInfo.cbObject, u.File.objInfo.Attr.fMode));
279 u.File.cbToProcess = u.File.objInfo.cbObject;
280 u.File.cbProcessed = 0;
281 }
282
283 break;
284 }
285
286 case Type_Directory:
287 {
288 rc = RTDirOpen(&u.Dir.hDir, strPathAbs.c_str());
289 if (RT_SUCCESS(rc))
290 rc = queryInfoInternal(enmView);
291 break;
292 }
293
294 default:
295 rc = VERR_NOT_IMPLEMENTED;
296 break;
297 }
298 }
299
300 if (RT_SUCCESS(rc))
301 {
302 m_enmView = enmView;
303 m_fIsOpen = true;
304 }
305
306 LogFlowFuncLeaveRC(rc);
307 return rc;
308}
309
310/**
311 * Queries information about the object using a specific view, internal version.
312 *
313 * @return IPRT status code.
314 * @param enmView View to use for querying information.
315 */
316int DnDURIObject::queryInfoInternal(View enmView)
317{
318 RT_NOREF(enmView);
319
320 int rc;
321
322 switch (m_enmType)
323 {
324 case Type_File:
325 rc = RTFileQueryInfo(u.File.hFile, &u.File.objInfo, RTFSOBJATTRADD_NOTHING);
326 break;
327
328 case Type_Directory:
329 rc = RTDirQueryInfo(u.Dir.hDir, &u.Dir.objInfo, RTFSOBJATTRADD_NOTHING);
330 break;
331
332 default:
333 rc = VERR_NOT_IMPLEMENTED;
334 break;
335 }
336
337 return rc;
338}
339
340/**
341 * Queries information about the object using a specific view.
342 *
343 * @return IPRT status code.
344 * @param enmView View to use for querying information.
345 */
346int DnDURIObject::QueryInfo(View enmView)
347{
348 return queryInfoInternal(enmView);
349}
350
351/**
352 * Rebases an absolute URI path from an old path base to a new path base.
353 * This function is needed in order to transform path from the source side to the target side.
354 *
355 * @return IPRT status code.
356 * @param strPathAbs Absolute URI path to rebase.
357 * @param strBaseOld Old base path to rebase from.
358 * @param strBaseNew New base path to rebase to.
359 *
360 ** @todo Put this into an own class like DnDURIPath : public RTCString?
361 */
362/* static */
363int DnDURIObject::RebaseURIPath(RTCString &strPathAbs,
364 const RTCString &strBaseOld /* = "" */,
365 const RTCString &strBaseNew /* = "" */)
366{
367 char *pszPath = RTUriFilePath(strPathAbs.c_str());
368 if (!pszPath) /* No URI? */
369 pszPath = RTStrDup(strPathAbs.c_str());
370
371 int rc;
372
373 if (pszPath)
374 {
375 const char *pszPathStart = pszPath;
376 const char *pszBaseOld = strBaseOld.c_str();
377 if ( pszBaseOld
378 && RTPathStartsWith(pszPath, pszBaseOld))
379 {
380 pszPathStart += strlen(pszBaseOld);
381 }
382
383 rc = VINF_SUCCESS;
384
385 if (RT_SUCCESS(rc))
386 {
387 char *pszPathNew = RTPathJoinA(strBaseNew.c_str(), pszPathStart);
388 if (pszPathNew)
389 {
390 char *pszPathURI = RTUriCreate("file" /* pszScheme */, "/" /* pszAuthority */,
391 pszPathNew /* pszPath */,
392 NULL /* pszQuery */, NULL /* pszFragment */);
393 if (pszPathURI)
394 {
395 LogFlowFunc(("Rebasing \"%s\" to \"%s\"\n", strPathAbs.c_str(), pszPathURI));
396
397 strPathAbs = RTCString(pszPathURI) + "\r\n";
398 RTStrFree(pszPathURI);
399 }
400 else
401 rc = VERR_INVALID_PARAMETER;
402
403 RTStrFree(pszPathNew);
404 }
405 else
406 rc = VERR_NO_MEMORY;
407 }
408
409 RTStrFree(pszPath);
410 }
411 else
412 rc = VERR_NO_MEMORY;
413
414 return rc;
415}
416
417/**
418 * Reads data from the object. Only applies to files objects.
419 *
420 * @return IPRT status code.
421 * @param pvBuf Buffer where to store the read data.
422 * @param cbBuf Size (in bytes) of the buffer.
423 * @param pcbRead Pointer where to store how many bytes were read. Optional.
424 */
425int DnDURIObject::Read(void *pvBuf, size_t cbBuf, uint32_t *pcbRead)
426{
427 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
428 AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
429 /* pcbRead is optional. */
430
431 AssertMsgReturn(m_fIsOpen, ("Object not in open state\n"), VERR_INVALID_STATE);
432 AssertMsgReturn(m_enmView == View_Source, ("Cannot write to an object which is not in target view\n"),
433 VERR_INVALID_STATE);
434
435 size_t cbRead = 0;
436
437 int rc;
438 switch (m_enmType)
439 {
440 case Type_File:
441 {
442 rc = RTFileRead(u.File.hFile, pvBuf, cbBuf, &cbRead);
443 if (RT_SUCCESS(rc))
444 {
445 u.File.cbProcessed += cbRead;
446 Assert(u.File.cbProcessed <= u.File.cbToProcess);
447
448 /* End of file reached or error occurred? */
449 if ( u.File.cbToProcess
450 && u.File.cbProcessed == u.File.cbToProcess)
451 {
452 rc = VINF_EOF;
453 }
454 }
455 break;
456 }
457
458 case Type_Directory:
459 {
460 rc = VINF_SUCCESS;
461 break;
462 }
463
464 default:
465 rc = VERR_NOT_IMPLEMENTED;
466 break;
467 }
468
469 if (RT_SUCCESS(rc))
470 {
471 if (pcbRead)
472 *pcbRead = (uint32_t)cbRead;
473 }
474
475 LogFlowFunc(("Returning strSourcePath=%s, cbRead=%zu, rc=%Rrc\n", m_strSrcPathAbs.c_str(), cbRead, rc));
476 return rc;
477}
478
479/**
480 * Resets the object's state and closes all related handles.
481 */
482void DnDURIObject::Reset(void)
483{
484 LogFlowThisFuncEnter();
485
486 Close();
487
488 m_enmType = Type_Unknown;
489 m_enmView = View_Unknown;
490 m_strSrcPathAbs = "";
491 m_strTgtPathAbs = "";
492
493 RT_ZERO(u);
494}
495
496/**
497 * Sets the bytes to process by the object.
498 *
499 * Note: Only applies if the object is of type DnDURIObject::Type_File.
500 *
501 * @return IPRT return code.
502 * @param cbSize Size (in bytes) to process.
503 */
504int DnDURIObject::SetSize(uint64_t cbSize)
505{
506 AssertReturn(m_enmType == Type_File, VERR_INVALID_PARAMETER);
507
508 /** @todo Implement sparse file support here. */
509
510 u.File.cbToProcess = cbSize;
511 return VINF_SUCCESS;
512}
513
514/**
515 * Writes data to an object. Only applies to file objects.
516 *
517 * @return IPRT status code.
518 * @param pvBuf Buffer of data to write.
519 * @param cbBuf Size (in bytes) of data to write.
520 * @param pcbWritten Pointer where to store how many bytes were written. Optional.
521 */
522int DnDURIObject::Write(const void *pvBuf, size_t cbBuf, uint32_t *pcbWritten)
523{
524 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
525 AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
526 /* pcbWritten is optional. */
527
528 AssertMsgReturn(m_fIsOpen, ("Object not in open state\n"), VERR_INVALID_STATE);
529 AssertMsgReturn(m_enmView == View_Target, ("Cannot write to an object which is not in target view\n"),
530 VERR_INVALID_STATE);
531
532 size_t cbWritten = 0;
533
534 int rc;
535 switch (m_enmType)
536 {
537 case Type_File:
538 {
539 rc = RTFileWrite(u.File.hFile, pvBuf, cbBuf, &cbWritten);
540 if (RT_SUCCESS(rc))
541 u.File.cbProcessed += cbWritten;
542 break;
543 }
544
545 case Type_Directory:
546 {
547 rc = VINF_SUCCESS;
548 break;
549 }
550
551 default:
552 rc = VERR_NOT_IMPLEMENTED;
553 break;
554 }
555
556 if (RT_SUCCESS(rc))
557 {
558 if (pcbWritten)
559 *pcbWritten = (uint32_t)cbWritten;
560 }
561
562 LogFlowThisFunc(("Returning strSourcePathAbs=%s, cbWritten=%zu, rc=%Rrc\n", m_strSrcPathAbs.c_str(), cbWritten, rc));
563 return rc;
564}
565
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