VirtualBox

source: vbox/trunk/src/VBox/GuestHost/SharedClipboard/ClipboardCache.cpp@ 78583

Last change on this file since 78583 was 78581, checked in by vboxsync, 5 years ago

Shared Clipboard/URI: Update.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.4 KB
Line 
1/* $Id: ClipboardCache.cpp 78581 2019-05-18 15:48:41Z vboxsync $ */
2/** @file
3 * Shared Clipboard - Cache 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
36SharedClipboardCache::SharedClipboardCache(void)
37 : m_cRefs(0)
38 , m_fOpen(0)
39 , m_hDir(NULL)
40{
41 int rc = initInternal();
42 if (RT_FAILURE(rc))
43 throw rc;
44}
45
46SharedClipboardCache::SharedClipboardCache(const char *pszPath,
47 SHAREDCLIPBOARDCACHEFLAGS fFlags /* = SHAREDCLIPBOARDCACHE_FLAGS_NONE */)
48 : m_cRefs(0)
49 , m_fOpen(0)
50 , m_hDir(NULL)
51{
52 int rc = initInternal();
53 if (RT_SUCCESS(rc))
54 rc = OpenEx(pszPath, fFlags);
55
56 if (RT_FAILURE(rc))
57 throw rc;
58}
59
60SharedClipboardCache::~SharedClipboardCache(void)
61{
62 /* Only make sure to not leak any handles and stuff, don't delete any
63 * directories / files here. */
64 closeInternal();
65
66 int rc = destroyInternal();
67 AssertRC(rc);
68}
69
70/**
71 * Adds a reference to a Shared Clipboard cache.
72 *
73 * @returns New reference count.
74 */
75uint16_t SharedClipboardCache::AddRef(void)
76{
77 return ASMAtomicIncU32(&m_cRefs);
78}
79
80/**
81 * Removes a reference from a Shared Clipboard cache.
82 *
83 * @returns New reference count.
84 */
85uint16_t SharedClipboardCache::Release(void)
86{
87 Assert(m_cRefs);
88 return ASMAtomicDecU32(&m_cRefs);
89}
90
91/**
92 * Locks a Shared Clipboard cache.
93 *
94 * @returns VBox status code.
95 */
96int SharedClipboardCache::Lock(void)
97{
98 return RTCritSectEnter(&m_CritSect);
99}
100
101/**
102 * Unlocks a Shared Clipboard cache.
103 *
104 * @returns VBox status code.
105 */
106int SharedClipboardCache::Unlock(void)
107{
108 return RTCritSectLeave(&m_CritSect);
109}
110
111int SharedClipboardCache::AddFile(const char *pszFile)
112{
113 AssertPtrReturn(pszFile, VERR_INVALID_POINTER);
114
115 if (!this->m_lstFiles.contains(pszFile))
116 this->m_lstFiles.append(pszFile);
117 return VINF_SUCCESS;
118}
119
120int SharedClipboardCache::AddDir(const char *pszDir)
121{
122 AssertPtrReturn(pszDir, VERR_INVALID_POINTER);
123
124 if (!this->m_lstDirs.contains(pszDir))
125 this->m_lstDirs.append(pszDir);
126 return VINF_SUCCESS;
127}
128
129int SharedClipboardCache::initInternal(void)
130{
131 return RTCritSectInit(&m_CritSect);
132}
133
134int SharedClipboardCache::destroyInternal(void)
135{
136 return RTCritSectDelete(&m_CritSect);
137}
138
139int SharedClipboardCache::closeInternal(void)
140{
141 int rc;
142 if (this->m_hDir != NULL)
143 {
144 rc = RTDirClose(this->m_hDir);
145 if (RT_SUCCESS(rc))
146 this->m_hDir = NULL;
147 }
148 else
149 rc = VINF_SUCCESS;
150
151 LogFlowFuncLeaveRC(rc);
152 return rc;
153}
154
155int SharedClipboardCache::Close(void)
156{
157 return closeInternal();
158}
159
160const char *SharedClipboardCache::GetDirAbs(void) const
161{
162 return this->m_strPathAbs.c_str();
163}
164
165bool SharedClipboardCache::IsOpen(void) const
166{
167 return (this->m_hDir != NULL);
168}
169
170int SharedClipboardCache::OpenEx(const char *pszPath, SHAREDCLIPBOARDCACHEFLAGS fFlags /* = SHAREDCLIPBOARDCACHE_FLAGS_NONE */)
171{
172 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
173 AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER); /* Flags not supported yet. */
174
175 int rc;
176
177 do
178 {
179 char pszDropDir[RTPATH_MAX];
180 RTStrPrintf(pszDropDir, sizeof(pszDropDir), "%s", pszPath);
181
182 /** @todo On Windows we also could use the registry to override
183 * this path, on Posix a dotfile and/or a guest property
184 * can be used. */
185
186 /* Append our base drop directory. */
187 rc = RTPathAppend(pszDropDir, sizeof(pszDropDir), "VirtualBox Shared Clipboard Files"); /** @todo Make this tag configurable? */
188 if (RT_FAILURE(rc))
189 break;
190
191 /* Create it when necessary. */
192 if (!RTDirExists(pszDropDir))
193 {
194 rc = RTDirCreateFullPath(pszDropDir, RTFS_UNIX_IRWXU);
195 if (RT_FAILURE(rc))
196 break;
197 }
198
199 /* The actually drop directory consist of the current time stamp and a
200 * unique number when necessary. */
201 char pszTime[64];
202 RTTIMESPEC time;
203 if (!RTTimeSpecToString(RTTimeNow(&time), pszTime, sizeof(pszTime)))
204 {
205 rc = VERR_BUFFER_OVERFLOW;
206 break;
207 }
208
209 rc = SharedClipboardPathSanitizeFilename(pszTime, sizeof(pszTime));
210 if (RT_FAILURE(rc))
211 break;
212
213 rc = RTPathAppend(pszDropDir, sizeof(pszDropDir), pszTime);
214 if (RT_FAILURE(rc))
215 break;
216
217 /* Create it (only accessible by the current user) */
218 rc = RTDirCreateUniqueNumbered(pszDropDir, sizeof(pszDropDir), RTFS_UNIX_IRWXU, 3, '-');
219 if (RT_SUCCESS(rc))
220 {
221 RTDIR hDir;
222 rc = RTDirOpen(&hDir, pszDropDir);
223 if (RT_SUCCESS(rc))
224 {
225 this->m_hDir = hDir;
226 this->m_strPathAbs = pszDropDir;
227 this->m_fOpen = fFlags;
228 }
229 }
230
231 } while (0);
232
233 LogFlowFuncLeaveRC(rc);
234 return rc;
235}
236
237int SharedClipboardCache::OpenTemp(SHAREDCLIPBOARDCACHEFLAGS fFlags /* = SHAREDCLIPBOARDCACHE_FLAGS_NONE */)
238{
239 AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER); /* Flags not supported yet. */
240
241 /*
242 * Get the user's temp directory. Don't use the user's root directory (or
243 * something inside it) because we don't know for how long/if the data will
244 * be kept after the guest OS used it.
245 */
246 char szTemp[RTPATH_MAX];
247 int rc = RTPathTemp(szTemp, sizeof(szTemp));
248 if (RT_SUCCESS(rc))
249 rc = OpenEx(szTemp, fFlags);
250
251 return rc;
252}
253
254int SharedClipboardCache::Reset(bool fRemoveDropDir)
255{
256 int rc = closeInternal();
257 if (RT_SUCCESS(rc))
258 {
259 if (fRemoveDropDir)
260 {
261 rc = Rollback();
262 }
263 else
264 {
265 this->m_lstDirs.clear();
266 this->m_lstFiles.clear();
267 }
268 }
269
270 LogFlowFuncLeaveRC(rc);
271 return rc;
272}
273
274int SharedClipboardCache::Reopen(void)
275{
276 if (this->m_strPathAbs.isEmpty())
277 return VERR_NOT_FOUND;
278
279 return OpenEx(this->m_strPathAbs.c_str(), this->m_fOpen);
280}
281
282int SharedClipboardCache::Rollback(void)
283{
284 if (this->m_strPathAbs.isEmpty())
285 return VINF_SUCCESS;
286
287 int rc = VINF_SUCCESS;
288
289 /* Rollback by removing any stuff created.
290 * Note: Only remove empty directories, never ever delete
291 * anything recursive here! Steam (tm) knows best ... :-) */
292 int rc2;
293 for (size_t i = 0; i < this->m_lstFiles.size(); i++)
294 {
295 rc2 = RTFileDelete(this->m_lstFiles.at(i).c_str());
296 if (RT_SUCCESS(rc2))
297 this->m_lstFiles.removeAt(i);
298 else if (RT_SUCCESS(rc))
299 rc = rc2;
300 /* Keep going. */
301 }
302
303 for (size_t i = 0; i < this->m_lstDirs.size(); i++)
304 {
305 rc2 = RTDirRemove(this->m_lstDirs.at(i).c_str());
306 if (RT_SUCCESS(rc2))
307 this->m_lstDirs.removeAt(i);
308 else if (RT_SUCCESS(rc))
309 rc = rc2;
310 /* Keep going. */
311 }
312
313 if (RT_SUCCESS(rc))
314 {
315 Assert(this->m_lstFiles.isEmpty());
316 Assert(this->m_lstDirs.isEmpty());
317
318 rc2 = closeInternal();
319 if (RT_SUCCESS(rc2))
320 {
321 /* Try to remove the empty root dropped files directory as well.
322 * Might return VERR_DIR_NOT_EMPTY or similar. */
323 rc2 = RTDirRemove(this->m_strPathAbs.c_str());
324 }
325 if (RT_SUCCESS(rc))
326 rc = rc2;
327 }
328
329 LogFlowFuncLeaveRC(rc);
330 return rc;
331}
332
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use