VirtualBox

source: vbox/trunk/src/VBox/GuestHost/DragAndDrop/DnDDroppedFiles.cpp@ 85659

Last change on this file since 85659 was 85456, checked in by vboxsync, 5 years ago

DnD/DnDDroppedFiles: Init / destruction fixes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.1 KB
Line 
1/* $Id: DnDDroppedFiles.cpp 85456 2020-07-24 13:10:47Z vboxsync $ */
2/** @file
3 * DnD - Directory handling.
4 */
5
6/*
7 * Copyright (C) 2014-2020 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/assert.h>
26#include <iprt/dir.h>
27#include <iprt/err.h>
28#include <iprt/file.h>
29#include <iprt/mem.h>
30#include <iprt/path.h>
31#include <iprt/string.h>
32
33#include <VBox/log.h>
34
35
36/*********************************************************************************************************************************
37* Prototypes *
38*********************************************************************************************************************************/
39static int dndDroppedFilesCloseInternal(PDNDDROPPEDFILES pDF);
40
41
42static int dndDroppedFilesInitInternal(PDNDDROPPEDFILES pDF)
43{
44 pDF->m_fOpen = 0;
45 pDF->m_hDir = NIL_RTDIR;
46 pDF->pszPathAbs = NULL;
47
48 RTListInit(&pDF->m_lstDirs);
49 RTListInit(&pDF->m_lstFiles);
50
51 return VINF_SUCCESS;
52}
53
54int DnDDroppedFilesInitEx(PDNDDROPPEDFILES pDF,
55 const char *pszPath, DNDURIDROPPEDFILEFLAGS fFlags /* = DNDURIDROPPEDFILE_FLAGS_NONE */)
56{
57 int rc = dndDroppedFilesInitInternal(pDF);
58 if (RT_FAILURE(rc))
59 return rc;
60
61 return DnDDroppedFilesOpenEx(pDF, pszPath, fFlags);
62}
63
64int DnDDroppedFilesInit(PDNDDROPPEDFILES pDF)
65{
66 return dndDroppedFilesInitInternal(pDF);
67}
68
69void DnDDroppedFilesDestroy(PDNDDROPPEDFILES pDF)
70{
71 /* Only make sure to not leak any handles and stuff, don't delete any
72 * directories / files here. */
73 dndDroppedFilesCloseInternal(pDF);
74
75 RTStrFree(pDF->pszPathAbs);
76 pDF->pszPathAbs = NULL;
77}
78
79/**
80 * Adds a file reference to a dropped files directory.
81 *
82 * @returns VBox status code.
83 * @param pszFile Path of file entry to add.
84 */
85int DnDDroppedFilesAddFile(PDNDDROPPEDFILES pDF, const char *pszFile)
86{
87 AssertPtrReturn(pszFile, VERR_INVALID_POINTER);
88
89 PDNDDROPPEDFILESENTRY pEntry = (PDNDDROPPEDFILESENTRY)RTMemAlloc(sizeof(DNDDROPPEDFILESENTRY));
90 if (!pEntry)
91 return VERR_NO_MEMORY;
92
93 pEntry->pszPath = RTStrDup(pszFile);
94 if (pEntry->pszPath)
95 {
96 RTListAppend(&pDF->m_lstFiles, &pEntry->Node);
97 return VINF_SUCCESS;
98 }
99
100 RTMemFree(pEntry);
101 return VERR_NO_MEMORY;
102}
103
104/**
105 * Adds a directory reference to a dropped files directory.
106 * Note: This does *not* (recursively) add sub entries.
107 *
108 * @returns VBox status code.
109 * @param pszDir Path of directory entry to add.
110 */
111int DnDDroppedFilesAddDir(PDNDDROPPEDFILES pDF, const char *pszDir)
112{
113 AssertPtrReturn(pszDir, VERR_INVALID_POINTER);
114
115 PDNDDROPPEDFILESENTRY pEntry = (PDNDDROPPEDFILESENTRY)RTMemAlloc(sizeof(DNDDROPPEDFILESENTRY));
116 if (!pEntry)
117 return VERR_NO_MEMORY;
118
119 pEntry->pszPath = RTStrDup(pszDir);
120 if (pEntry->pszPath)
121 {
122 RTListAppend(&pDF->m_lstDirs, &pEntry->Node);
123 return VINF_SUCCESS;
124 }
125
126 RTMemFree(pEntry);
127 return VERR_NO_MEMORY;
128}
129
130/**
131 * Closes the dropped files directory handle, internal version.
132 *
133 * @returns VBox status code.
134 */
135static int dndDroppedFilesCloseInternal(PDNDDROPPEDFILES pDF)
136{
137 int rc;
138 if (pDF->m_hDir != NULL)
139 {
140 rc = RTDirClose(pDF->m_hDir);
141 if (RT_SUCCESS(rc))
142 pDF->m_hDir = NULL;
143 }
144 else
145 rc = VINF_SUCCESS;
146
147 LogFlowFuncLeaveRC(rc);
148 return rc;
149}
150
151/**
152 * Closes the dropped files directory handle.
153 *
154 * @returns VBox status code.
155 */
156int DnDDroppedFilesClose(PDNDDROPPEDFILES pDF)
157{
158 return dndDroppedFilesCloseInternal(pDF);
159}
160
161/**
162 * Returns the absolute path of the dropped files directory.
163 *
164 * @returns Pointer to absolute path of the dropped files directory.
165 */
166const char *DnDDroppedFilesGetDirAbs(PDNDDROPPEDFILES pDF)
167{
168 return pDF->pszPathAbs;
169}
170
171/**
172 * Returns whether the dropped files directory has been opened or not.
173 *
174 * @returns \c true if open, \c false if not.
175 */
176bool DnDDroppedFilesIsOpen(PDNDDROPPEDFILES pDF)
177{
178 return (pDF->m_hDir != NULL);
179}
180
181/**
182 * Opens (creates) the dropped files directory.
183 *
184 * @returns VBox status code.
185 * @param pszPath Absolute path where to create the dropped files directory.
186 * @param fFlags Dropped files flags to use for this directory.
187 */
188int DnDDroppedFilesOpenEx(PDNDDROPPEDFILES pDF,
189 const char *pszPath, DNDURIDROPPEDFILEFLAGS fFlags /* = DNDURIDROPPEDFILE_FLAGS_NONE */)
190{
191 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
192 AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER); /* Flags not supported yet. */
193
194 int rc;
195
196 do
197 {
198 char szDropDir[RTPATH_MAX];
199 RTStrPrintf(szDropDir, sizeof(szDropDir), "%s", pszPath);
200
201 /** @todo On Windows we also could use the registry to override
202 * this path, on Posix a dotfile and/or a guest property
203 * can be used. */
204
205 /* Append our base drop directory. */
206 rc = RTPathAppend(szDropDir, sizeof(szDropDir), "VirtualBox Dropped Files"); /** @todo Make this tag configurable? */
207 if (RT_FAILURE(rc))
208 break;
209
210 /* Create it when necessary. */
211 if (!RTDirExists(szDropDir))
212 {
213 rc = RTDirCreateFullPath(szDropDir, RTFS_UNIX_IRWXU);
214 if (RT_FAILURE(rc))
215 break;
216 }
217
218 /* The actually drop directory consist of the current time stamp and a
219 * unique number when necessary. */
220 char szTime[64];
221 RTTIMESPEC time;
222 if (!RTTimeSpecToString(RTTimeNow(&time), szTime, sizeof(szTime)))
223 {
224 rc = VERR_BUFFER_OVERFLOW;
225 break;
226 }
227
228 rc = DnDPathSanitizeFileName(szTime, sizeof(szTime));
229 if (RT_FAILURE(rc))
230 break;
231
232 rc = RTPathAppend(szDropDir, sizeof(szDropDir), szTime);
233 if (RT_FAILURE(rc))
234 break;
235
236 /* Create it (only accessible by the current user) */
237 rc = RTDirCreateUniqueNumbered(szDropDir, sizeof(szDropDir), RTFS_UNIX_IRWXU, 3, '-');
238 if (RT_SUCCESS(rc))
239 {
240 RTDIR hDir;
241 rc = RTDirOpen(&hDir, szDropDir);
242 if (RT_SUCCESS(rc))
243 {
244 pDF->pszPathAbs = RTStrDup(szDropDir);
245 AssertPtrBreakStmt(pDF->pszPathAbs, rc = VERR_NO_MEMORY);
246 pDF->m_hDir = hDir;
247 pDF->m_fOpen = fFlags;
248 }
249 }
250
251 } while (0);
252
253 LogFlowFuncLeaveRC(rc);
254 return rc;
255}
256
257/**
258 * Opens (creates) the dropped files directory in the system's temp directory.
259 *
260 * @returns VBox status code.
261 * @param fFlags Dropped files flags to use for this directory.
262 */
263int DnDDroppedFilesOpenTemp(PDNDDROPPEDFILES pDF, DNDURIDROPPEDFILEFLAGS fFlags)
264{
265 AssertReturn(fFlags == 0, VERR_INVALID_PARAMETER); /* Flags not supported yet. */
266
267 /*
268 * Get the user's temp directory. Don't use the user's root directory (or
269 * something inside it) because we don't know for how long/if the data will
270 * be kept after the guest OS used it.
271 */
272 char szTemp[RTPATH_MAX];
273 int rc = RTPathTemp(szTemp, sizeof(szTemp));
274 if (RT_SUCCESS(rc))
275 rc = DnDDroppedFilesOpenEx(pDF, szTemp, fFlags);
276
277 return rc;
278}
279
280static void dndDroppedFilesEntryFree(PDNDDROPPEDFILESENTRY pEntry)
281{
282 if (!pEntry)
283 return;
284 RTStrFree(pEntry->pszPath);
285 RTListNodeRemove(&pEntry->Node);
286 RTMemFree(pEntry);
287}
288
289static void dndDroppedFilesResetList(PRTLISTANCHOR pListAnchor)
290{
291 PDNDDROPPEDFILESENTRY pEntryCur, pEntryNext;
292 RTListForEachSafe(pListAnchor, pEntryCur, pEntryNext, DNDDROPPEDFILESENTRY, Node)
293 dndDroppedFilesEntryFree(pEntryCur);
294 Assert(RTListIsEmpty(pListAnchor));
295}
296
297/**
298 * Resets a droppped files directory.
299 *
300 * @returns VBox status code.
301 * @param fDelete Whether to physically delete the directory and its content
302 * or just clear the internal references.
303 */
304int DnDDroppedFilesReset(PDNDDROPPEDFILES pDF, bool fDelete)
305{
306 int rc = dndDroppedFilesCloseInternal(pDF);
307 if (RT_SUCCESS(rc))
308 {
309 if (fDelete)
310 {
311 rc = DnDDroppedFilesRollback(pDF);
312 }
313 else
314 {
315 dndDroppedFilesResetList(&pDF->m_lstDirs);
316 dndDroppedFilesResetList(&pDF->m_lstFiles);
317 }
318 }
319
320 LogFlowFuncLeaveRC(rc);
321 return rc;
322}
323
324/**
325 * Re-opens a droppes files directory.
326 *
327 * @returns VBox status code, or VERR_NOT_FOUND if the dropped files directory has not been opened before.
328 */
329int DnDDroppedFilesReopen(PDNDDROPPEDFILES pDF)
330{
331 if (!pDF->pszPathAbs)
332 return VERR_NOT_FOUND;
333
334 return DnDDroppedFilesOpenEx(pDF, pDF->pszPathAbs, pDF->m_fOpen);
335}
336
337/**
338 * Performs a rollback of a dropped files directory.
339 * This cleans the directory by physically deleting all files / directories which have been added before.
340 *
341 * @returns VBox status code.
342 */
343int DnDDroppedFilesRollback(PDNDDROPPEDFILES pDF)
344{
345 if (!pDF->pszPathAbs)
346 return VINF_SUCCESS;
347
348 int rc = VINF_SUCCESS;
349
350 /* Rollback by removing any stuff created.
351 * Note: Only remove empty directories, never ever delete
352 * anything recursive here! Steam (tm) knows best ... :-) */
353 int rc2;
354 PDNDDROPPEDFILESENTRY pEntryCur, pEntryNext;
355 RTListForEachSafe(&pDF->m_lstFiles, pEntryCur, pEntryNext, DNDDROPPEDFILESENTRY, Node)
356 {
357 rc2 = RTFileDelete(pEntryCur->pszPath);
358 if (RT_SUCCESS(rc2))
359 dndDroppedFilesEntryFree(pEntryCur);
360 else if (RT_SUCCESS(rc))
361 rc = rc2;
362 /* Keep going. */
363 }
364
365 RTListForEachSafe(&pDF->m_lstDirs, pEntryCur, pEntryNext, DNDDROPPEDFILESENTRY, Node)
366 {
367 rc2 = RTDirRemove(pEntryCur->pszPath);
368 if (RT_SUCCESS(rc2))
369 dndDroppedFilesEntryFree(pEntryCur);
370 else if (RT_SUCCESS(rc))
371 rc = rc2;
372 /* Keep going. */
373 }
374
375 if (RT_SUCCESS(rc))
376 {
377 rc2 = dndDroppedFilesCloseInternal(pDF);
378 if (RT_SUCCESS(rc2))
379 {
380 /* Try to remove the empty root dropped files directory as well.
381 * Might return VERR_DIR_NOT_EMPTY or similar. */
382 rc2 = RTDirRemove(pDF->pszPathAbs);
383 }
384 if (RT_SUCCESS(rc))
385 rc = rc2;
386 }
387
388 LogFlowFuncLeaveRC(rc);
389 return rc;
390}
391
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