VirtualBox

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

Last change on this file since 79268 was 79174, 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: 9.9 KB
Line 
1/* $Id: ClipboardArea.cpp 79174 2019-06-17 10:30:49Z vboxsync $ */
2/** @file
3 * Shared Clipboard - Area handling.
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/asm.h>
26#include <iprt/assert.h>
27#include <iprt/dir.h>
28#include <iprt/err.h>
29#include <iprt/file.h>
30#include <iprt/path.h>
31#include <iprt/string.h>
32
33
34#include <VBox/log.h>
35
36SharedClipboardArea::SharedClipboardArea(void)
37 : m_cRefs(0)
38 , m_fOpen(0)
39 , m_hDir(NIL_RTDIR)
40 , m_uID(NIL_SHAREDCLIPBOARDAREAID)
41{
42 int rc = initInternal();
43 if (RT_FAILURE(rc))
44 throw rc;
45}
46
47SharedClipboardArea::SharedClipboardArea(const char *pszPath,
48 SHAREDCLIPBOARDAREAID uID /* = NIL_SHAREDCLIPBOARDAREAID */,
49 SHAREDCLIPBOARDAREAOPENFLAGS fFlags /* = SHAREDCLIPBOARDAREA_OPEN_FLAGS_NONE */)
50 : m_tsCreatedMs(0)
51 , m_cRefs(0)
52 , m_fOpen(0)
53 , m_hDir(NIL_RTDIR)
54 , m_uID(uID)
55{
56 int rc = initInternal();
57 if (RT_SUCCESS(rc))
58 rc = OpenEx(pszPath, fFlags);
59
60 if (RT_FAILURE(rc))
61 throw rc;
62}
63
64SharedClipboardArea::~SharedClipboardArea(void)
65{
66 /* Only make sure to not leak any handles and stuff, don't delete any
67 * directories / files here. */
68 closeInternal();
69
70 int rc = destroyInternal();
71 AssertRC(rc);
72}
73
74/**
75 * Adds a reference to a Shared Clipboard area.
76 *
77 * @returns New reference count.
78 */
79uint32_t SharedClipboardArea::AddRef(void)
80{
81 return ++m_cRefs;
82}
83
84/**
85 * Removes a reference from a Shared Clipboard area.
86 *
87 * @returns New reference count.
88 */
89uint32_t SharedClipboardArea::Release(void)
90{
91 if (m_cRefs)
92 m_cRefs--;
93
94 return m_cRefs;
95}
96
97/**
98 * Locks a Shared Clipboard area.
99 *
100 * @returns VBox status code.
101 */
102int SharedClipboardArea::Lock(void)
103{
104 return RTCritSectEnter(&m_CritSect);
105}
106
107/**
108 * Unlocks a Shared Clipboard area.
109 *
110 * @returns VBox status code.
111 */
112int SharedClipboardArea::Unlock(void)
113{
114 return RTCritSectLeave(&m_CritSect);
115}
116
117int SharedClipboardArea::AddFile(const char *pszFile)
118{
119 AssertPtrReturn(pszFile, VERR_INVALID_POINTER);
120
121 if (!this->m_lstFiles.contains(pszFile))
122 this->m_lstFiles.append(pszFile);
123 return VINF_SUCCESS;
124}
125
126int SharedClipboardArea::AddDir(const char *pszDir)
127{
128 AssertPtrReturn(pszDir, VERR_INVALID_POINTER);
129
130 if (!this->m_lstDirs.contains(pszDir))
131 this->m_lstDirs.append(pszDir);
132 return VINF_SUCCESS;
133}
134
135int SharedClipboardArea::initInternal(void)
136{
137 return RTCritSectInit(&m_CritSect);
138}
139
140int SharedClipboardArea::destroyInternal(void)
141{
142 return RTCritSectDelete(&m_CritSect);
143}
144
145int SharedClipboardArea::closeInternal(void)
146{
147 int rc;
148 if (this->m_hDir != NIL_RTDIR)
149 {
150 rc = RTDirClose(this->m_hDir);
151 if (RT_SUCCESS(rc))
152 this->m_hDir = NIL_RTDIR;
153 }
154 else
155 rc = VINF_SUCCESS;
156
157 if ( RT_SUCCESS(rc)
158 && m_strPathAbs.isNotEmpty())
159 rc = RTDirRemoveRecursive(m_strPathAbs.c_str(), RTDIRRMREC_F_CONTENT_AND_DIR);
160
161 if (RT_SUCCESS(rc))
162 {
163 this->m_fOpen = SHAREDCLIPBOARDAREA_OPEN_FLAGS_NONE;
164 this->m_uID = NIL_SHAREDCLIPBOARDAREAID;
165 }
166
167 LogFlowFuncLeaveRC(rc);
168 return rc;
169}
170
171/**
172 * Construcuts an area's base path.
173 * Note: This does *not* create any directories or whatsoever!
174 *
175 * @returns VBox status code.
176 * @param pszBase Base path to use for the area.
177 * @param uID Area ID to use for the path.
178 * @param pszPath Where to store the constructured area base path.
179 * @param cbPath Size (in bytes) of the constructured area base path.
180 */
181/* static */
182int SharedClipboardArea::PathConstruct(const char *pszBase, SHAREDCLIPBOARDAREAID uID, char *pszPath, size_t cbPath)
183{
184 LogFlowFunc(("pszBase=%s, uAreaID=%RU32\n", pszBase, uID));
185
186 int rc = RTStrCopy(pszPath, cbPath, pszBase);
187 if (RT_SUCCESS(rc))
188 {
189 /** @todo On Windows we also could use the registry to override
190 * this path, on Posix a dotfile and/or a guest property
191 * can be used. */
192
193 /* Append our base area directory. */
194 rc = RTPathAppend(pszPath, cbPath, "VirtualBox Shared Clipboards"); /** @todo Make this tag configurable? */
195 if (RT_SUCCESS(rc))
196 {
197 rc = RTPathAppend(pszPath, cbPath, "Clipboard-");
198 if (RT_SUCCESS(rc))
199 {
200 char szID[16];
201 ssize_t cchID = RTStrFormatU32(szID, sizeof(szID), uID, 10, 0, 0, 0);
202 if (cchID)
203 {
204 rc = RTStrCat(pszPath, cbPath, szID);
205 }
206 else
207 rc = VERR_INVALID_PARAMETER;
208 }
209 }
210 }
211
212 LogFlowFunc(("rc=%Rrc, szPath=%s\n", rc, pszPath));
213 return rc;
214}
215
216int SharedClipboardArea::Close(void)
217{
218 return closeInternal();
219}
220
221SHAREDCLIPBOARDAREAID SharedClipboardArea::GetID(void) const
222{
223 return this->m_uID;
224}
225
226const char *SharedClipboardArea::GetDirAbs(void) const
227{
228 return this->m_strPathAbs.c_str();
229}
230
231uint32_t SharedClipboardArea::GetRefCount(void)
232{
233 return ASMAtomicReadU32(&m_cRefs);
234}
235
236bool SharedClipboardArea::IsOpen(void) const
237{
238 return (this->m_hDir != NULL);
239}
240
241int SharedClipboardArea::OpenEx(const char *pszPath,
242 SHAREDCLIPBOARDAREAID uID /* = NIL_SHAREDCLIPBOARDAREAID */,
243 SHAREDCLIPBOARDAREAOPENFLAGS fFlags /* = SHAREDCLIPBOARDAREA_OPEN_FLAGS_NONE */)
244{
245 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
246 AssertReturn(!(fFlags & ~SHAREDCLIPBOARDAREA_OPEN_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);
247
248 char szAreaDir[RTPATH_MAX];
249 int rc = SharedClipboardArea::PathConstruct(pszPath, uID, szAreaDir, sizeof(szAreaDir));
250 if (RT_SUCCESS(rc))
251 {
252 if ( RTDirExists(szAreaDir)
253 && (fFlags & SHAREDCLIPBOARDAREA_OPEN_FLAGS_MUST_NOT_EXIST))
254 {
255 rc = VERR_ALREADY_EXISTS;
256 }
257 else
258 rc = RTDirCreateFullPath(szAreaDir, RTFS_UNIX_IRWXU); /** @todo Tweak path mode? */
259
260 if (RT_SUCCESS(rc))
261 {
262 RTDIR hDir;
263 rc = RTDirOpen(&hDir, szAreaDir);
264 if (RT_SUCCESS(rc))
265 {
266 this->m_hDir = hDir;
267 this->m_strPathAbs = szAreaDir;
268 this->m_fOpen = fFlags;
269 this->m_uID = uID;
270 this->m_tsCreatedMs = RTTimeMilliTS();
271 }
272 }
273 }
274
275 LogFlowFuncLeaveRC(rc);
276 return rc;
277}
278
279int SharedClipboardArea::OpenTemp(SHAREDCLIPBOARDAREAID uID,
280 SHAREDCLIPBOARDAREAOPENFLAGS fFlags /* = SHAREDCLIPBOARDAREA_OPEN_FLAGS_NONE */)
281{
282 AssertReturn(!(fFlags & ~SHAREDCLIPBOARDAREA_OPEN_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);
283
284 /*
285 * Get the user's temp directory. Don't use the user's root directory (or
286 * something inside it) because we don't know for how long/if the data will
287 * be kept after the guest OS used it.
288 */
289 char szTemp[RTPATH_MAX];
290 int rc = RTPathTemp(szTemp, sizeof(szTemp));
291 if (RT_SUCCESS(rc))
292 rc = OpenEx(szTemp, uID, fFlags);
293
294 return rc;
295}
296
297int SharedClipboardArea::Reset(bool fDeleteContent)
298{
299 int rc = closeInternal();
300 if (RT_SUCCESS(rc))
301 {
302 if (fDeleteContent)
303 {
304 rc = Rollback();
305 }
306 else
307 {
308 this->m_lstDirs.clear();
309 this->m_lstFiles.clear();
310 }
311 }
312
313 LogFlowFuncLeaveRC(rc);
314 return rc;
315}
316
317int SharedClipboardArea::Reopen(void)
318{
319 if (this->m_strPathAbs.isEmpty())
320 return VERR_NOT_FOUND;
321
322 return OpenEx(this->m_strPathAbs.c_str(), this->m_fOpen);
323}
324
325int SharedClipboardArea::Rollback(void)
326{
327 if (this->m_strPathAbs.isEmpty())
328 return VINF_SUCCESS;
329
330 int rc = VINF_SUCCESS;
331
332 /* Rollback by removing any stuff created.
333 * Note: Only remove empty directories, never ever delete
334 * anything recursive here! Steam (tm) knows best ... :-) */
335 int rc2;
336 for (size_t i = 0; i < this->m_lstFiles.size(); i++)
337 {
338 rc2 = RTFileDelete(this->m_lstFiles.at(i).c_str());
339 if (RT_SUCCESS(rc2))
340 this->m_lstFiles.removeAt(i);
341 else if (RT_SUCCESS(rc))
342 rc = rc2;
343 /* Keep going. */
344 }
345
346 for (size_t i = 0; i < this->m_lstDirs.size(); i++)
347 {
348 rc2 = RTDirRemove(this->m_lstDirs.at(i).c_str());
349 if (RT_SUCCESS(rc2))
350 this->m_lstDirs.removeAt(i);
351 else if (RT_SUCCESS(rc))
352 rc = rc2;
353 /* Keep going. */
354 }
355
356 if (RT_SUCCESS(rc))
357 {
358 Assert(this->m_lstFiles.isEmpty());
359 Assert(this->m_lstDirs.isEmpty());
360
361 rc2 = closeInternal();
362 if ( RT_SUCCESS(rc2)
363 && m_strPathAbs.isNotEmpty())
364 {
365 /* Try to remove the empty root dropped files directory as well.
366 * Might return VERR_DIR_NOT_EMPTY or similar. */
367 rc2 = RTDirRemove(this->m_strPathAbs.c_str());
368 }
369 if (RT_SUCCESS(rc))
370 rc = rc2;
371 }
372
373 LogFlowFuncLeaveRC(rc);
374 return rc;
375}
376
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