VirtualBox

source: vbox/trunk/src/VBox/GuestHost/SharedClipboard/ClipboardURIObject.cpp@ 79268

Last change on this file since 79268 was 78942, checked in by vboxsync, 6 years ago

Shared Clipboard/URI: Update.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette