VirtualBox

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

Last change on this file since 78783 was 78083, checked in by vboxsync, 6 years ago

DnD/GuestHost: Initialize file / directory handles in DnDURIObject::DnDURIObject(enmType, ...).

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