VirtualBox

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

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