VirtualBox

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

最後變更 在這個檔案從85433是 85433,由 vboxsync 提交於 5 年 前

DnD: Also initialize directory list in dndDroppedFilesInitInternal().

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

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