VirtualBox

source: vbox/trunk/src/VBox/HostServices/SharedFolders/mappings.cpp@ 75380

Last change on this file since 75380 was 75380, checked in by vboxsync, 6 years ago

Main,VBoxManage,FE/Qt: Extended the createSharedFolder and ISharedFolder methods with a mount poit parameter/attribute for use when auto-mounting. This is especially useful for Windows and OS/2 guests which operates with drive letters. The change has not yet trickled down to the guest interface and VBoxService.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.9 KB
Line 
1/** @file
2 * Shared Folders: Mappings support.
3 */
4
5/*
6 * Copyright (C) 2006-2017 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 */
16
17#ifdef UNITTEST
18# include "testcase/tstSharedFolderService.h"
19#endif
20
21#include "mappings.h"
22#include "vbsfpath.h"
23#include <iprt/alloc.h>
24#include <iprt/assert.h>
25#include <iprt/path.h>
26#include <iprt/string.h>
27
28#ifdef UNITTEST
29# include "teststubs.h"
30#endif
31
32/* Shared folders order in the saved state and in the FolderMapping can differ.
33 * So a translation array of root handle is needed.
34 */
35
36static MAPPING FolderMapping[SHFL_MAX_MAPPINGS];
37static SHFLROOT aIndexFromRoot[SHFL_MAX_MAPPINGS];
38
39void vbsfMappingInit(void)
40{
41 unsigned root;
42
43 for (root = 0; root < RT_ELEMENTS(aIndexFromRoot); root++)
44 {
45 aIndexFromRoot[root] = SHFL_ROOT_NIL;
46 }
47}
48
49int vbsfMappingLoaded(const PMAPPING pLoadedMapping, SHFLROOT root)
50{
51 /* Mapping loaded from the saved state with the index. Which means
52 * the guest uses the iMapping as root handle for this folder.
53 * Check whether there is the same mapping in FolderMapping and
54 * update the aIndexFromRoot.
55 *
56 * Also update the mapping properties, which were lost: cMappings.
57 */
58 if (root >= SHFL_MAX_MAPPINGS)
59 {
60 return VERR_INVALID_PARAMETER;
61 }
62
63 SHFLROOT i;
64 for (i = 0; i < RT_ELEMENTS(FolderMapping); i++)
65 {
66 MAPPING *pMapping = &FolderMapping[i];
67
68 /* Equal? */
69 if ( pLoadedMapping->fValid == pMapping->fValid
70 && ShflStringSizeOfBuffer(pLoadedMapping->pMapName) == ShflStringSizeOfBuffer(pMapping->pMapName)
71 && memcmp(pLoadedMapping->pMapName, pMapping->pMapName, ShflStringSizeOfBuffer(pMapping->pMapName)) == 0)
72 {
73 /* Actual index is i. */
74 aIndexFromRoot[root] = i;
75
76 /* Update the mapping properties. */
77 pMapping->cMappings = pLoadedMapping->cMappings;
78
79 return VINF_SUCCESS;
80 }
81 }
82
83 /* No corresponding mapping on the host but the guest still uses it.
84 * Add a 'placeholder' mapping.
85 */
86 LogRel2(("SharedFolders: mapping a placeholder for '%ls' -> '%s'\n",
87 pLoadedMapping->pMapName->String.ucs2, pLoadedMapping->pszFolderName));
88 return vbsfMappingsAdd(pLoadedMapping->pszFolderName, pLoadedMapping->pMapName,
89 pLoadedMapping->fWritable, pLoadedMapping->fAutoMount, pLoadedMapping->pAutoMountPoint,
90 pLoadedMapping->fSymlinksCreate, /* fMissing = */ true, /* fPlaceholder = */ true);
91}
92
93MAPPING *vbsfMappingGetByRoot(SHFLROOT root)
94{
95 if (root < RT_ELEMENTS(aIndexFromRoot))
96 {
97 SHFLROOT iMapping = aIndexFromRoot[root];
98
99 if ( iMapping != SHFL_ROOT_NIL
100 && iMapping < RT_ELEMENTS(FolderMapping))
101 {
102 return &FolderMapping[iMapping];
103 }
104 }
105
106 return NULL;
107}
108
109static SHFLROOT vbsfMappingGetRootFromIndex(SHFLROOT iMapping)
110{
111 unsigned root;
112
113 for (root = 0; root < RT_ELEMENTS(aIndexFromRoot); root++)
114 {
115 if (iMapping == aIndexFromRoot[root])
116 {
117 return root;
118 }
119 }
120
121 return SHFL_ROOT_NIL;
122}
123
124static MAPPING *vbsfMappingGetByName (PRTUTF16 pwszName, SHFLROOT *pRoot)
125{
126 unsigned i;
127
128 for (i=0; i<SHFL_MAX_MAPPINGS; i++)
129 {
130 if (FolderMapping[i].fValid == true)
131 {
132 if (!RTUtf16LocaleICmp(FolderMapping[i].pMapName->String.ucs2, pwszName))
133 {
134 SHFLROOT root = vbsfMappingGetRootFromIndex(i);
135
136 if (root != SHFL_ROOT_NIL)
137 {
138 if (pRoot)
139 {
140 *pRoot = root;
141 }
142 return &FolderMapping[i];
143 }
144 else
145 {
146 AssertFailed();
147 }
148 }
149 }
150 }
151
152 return NULL;
153}
154
155static void vbsfRootHandleAdd(SHFLROOT iMapping)
156{
157 unsigned root;
158
159 for (root = 0; root < RT_ELEMENTS(aIndexFromRoot); root++)
160 {
161 if (aIndexFromRoot[root] == SHFL_ROOT_NIL)
162 {
163 aIndexFromRoot[root] = iMapping;
164 return;
165 }
166 }
167
168 AssertFailed();
169}
170
171static void vbsfRootHandleRemove(SHFLROOT iMapping)
172{
173 unsigned root;
174
175 for (root = 0; root < RT_ELEMENTS(aIndexFromRoot); root++)
176 {
177 if (aIndexFromRoot[root] == iMapping)
178 {
179 aIndexFromRoot[root] = SHFL_ROOT_NIL;
180 return;
181 }
182 }
183
184 AssertFailed();
185}
186
187
188
189#ifdef UNITTEST
190/** Unit test the SHFL_FN_ADD_MAPPING API. Located here as a form of API
191 * documentation. */
192void testMappingsAdd(RTTEST hTest)
193{
194 /* If the number or types of parameters are wrong the API should fail. */
195 testMappingsAddBadParameters(hTest);
196 /* Add tests as required... */
197}
198#endif
199/*
200 * We are always executed from one specific HGCM thread. So thread safe.
201 */
202int vbsfMappingsAdd(const char *pszFolderName, PSHFLSTRING pMapName, bool fWritable,
203 bool fAutoMount, PSHFLSTRING pAutoMountPoint, bool fSymlinksCreate, bool fMissing, bool fPlaceholder)
204{
205 unsigned i;
206
207 Assert(pszFolderName && pMapName);
208
209 Log(("vbsfMappingsAdd %ls\n", pMapName->String.ucs2));
210
211 /* check for duplicates */
212 for (i=0; i<SHFL_MAX_MAPPINGS; i++)
213 {
214 if (FolderMapping[i].fValid == true)
215 {
216 if (!RTUtf16LocaleICmp(FolderMapping[i].pMapName->String.ucs2, pMapName->String.ucs2))
217 {
218 AssertMsgFailed(("vbsfMappingsAdd: %ls mapping already exists!!\n", pMapName->String.ucs2));
219 return VERR_ALREADY_EXISTS;
220 }
221 }
222 }
223
224 for (i=0; i<SHFL_MAX_MAPPINGS; i++)
225 {
226 if (FolderMapping[i].fValid == false)
227 {
228 /* Make sure the folder name is an absolute path, otherwise we're
229 likely to get into trouble with buffer sizes in vbsfPathGuestToHost. */
230 char szAbsFolderName[RTPATH_MAX];
231 int rc = vbsfPathAbs(NULL, pszFolderName, szAbsFolderName, sizeof(szAbsFolderName));
232 AssertRCReturn(rc, rc);
233
234 FolderMapping[i].pszFolderName = RTStrDup(szAbsFolderName);
235 FolderMapping[i].pMapName = ShflStringDup(pMapName);
236 FolderMapping[i].pAutoMountPoint = ShflStringDup(pAutoMountPoint);
237 if ( !FolderMapping[i].pszFolderName
238 || !FolderMapping[i].pMapName
239 || !FolderMapping[i].pAutoMountPoint)
240 {
241 RTStrFree(FolderMapping[i].pszFolderName);
242 RTMemFree(FolderMapping[i].pMapName);
243 RTMemFree(FolderMapping[i].pAutoMountPoint);
244 return VERR_NO_MEMORY;
245 }
246
247 FolderMapping[i].fValid = true;
248 FolderMapping[i].cMappings = 0;
249 FolderMapping[i].fWritable = fWritable;
250 FolderMapping[i].fAutoMount = fAutoMount;
251 FolderMapping[i].fSymlinksCreate = fSymlinksCreate;
252 FolderMapping[i].fMissing = fMissing;
253 FolderMapping[i].fPlaceholder = fPlaceholder;
254
255 /* Check if the host file system is case sensitive */
256 RTFSPROPERTIES prop;
257 prop.fCaseSensitive = false; /* Shut up MSC. */
258 rc = RTFsQueryProperties(FolderMapping[i].pszFolderName, &prop);
259 AssertRC(rc);
260 FolderMapping[i].fHostCaseSensitive = RT_SUCCESS(rc) ? prop.fCaseSensitive : false;
261 vbsfRootHandleAdd(i);
262 break;
263 }
264 }
265 if (i == SHFL_MAX_MAPPINGS)
266 {
267 AssertLogRelMsgFailed(("vbsfMappingsAdd: no more room to add mapping %s to %ls!!\n", pszFolderName, pMapName->String.ucs2));
268 return VERR_TOO_MUCH_DATA;
269 }
270
271 Log(("vbsfMappingsAdd: added mapping %s to %ls\n", pszFolderName, pMapName->String.ucs2));
272 return VINF_SUCCESS;
273}
274
275#ifdef UNITTEST
276/** Unit test the SHFL_FN_REMOVE_MAPPING API. Located here as a form of API
277 * documentation. */
278void testMappingsRemove(RTTEST hTest)
279{
280 /* If the number or types of parameters are wrong the API should fail. */
281 testMappingsRemoveBadParameters(hTest);
282 /* Add tests as required... */
283}
284#endif
285int vbsfMappingsRemove(PSHFLSTRING pMapName)
286{
287 unsigned i;
288
289 Assert(pMapName);
290
291 Log(("vbsfMappingsRemove %ls\n", pMapName->String.ucs2));
292 for (i=0; i<SHFL_MAX_MAPPINGS; i++)
293 {
294 if (FolderMapping[i].fValid == true)
295 {
296 if (!RTUtf16LocaleICmp(FolderMapping[i].pMapName->String.ucs2, pMapName->String.ucs2))
297 {
298 if (FolderMapping[i].cMappings != 0)
299 {
300 LogRel2(("SharedFolders: removing '%ls' -> '%s', which is still used by the guest\n",
301 pMapName->String.ucs2, FolderMapping[i].pszFolderName));
302 FolderMapping[i].fMissing = true;
303 FolderMapping[i].fPlaceholder = true;
304 return VINF_PERMISSION_DENIED;
305 }
306
307 /* pMapName can be the same as FolderMapping[i].pMapName,
308 * log it before deallocating the memory.
309 */
310 Log(("vbsfMappingsRemove: mapping %ls removed\n", pMapName->String.ucs2));
311
312 RTStrFree(FolderMapping[i].pszFolderName);
313 RTMemFree(FolderMapping[i].pMapName);
314 FolderMapping[i].pszFolderName = NULL;
315 FolderMapping[i].pMapName = NULL;
316 FolderMapping[i].fValid = false;
317 vbsfRootHandleRemove(i);
318 return VINF_SUCCESS;
319 }
320 }
321 }
322
323 AssertMsgFailed(("vbsfMappingsRemove: mapping %ls not found!!!!\n", pMapName->String.ucs2));
324 return VERR_FILE_NOT_FOUND;
325}
326
327const char* vbsfMappingsQueryHostRoot(SHFLROOT root)
328{
329 MAPPING *pFolderMapping = vbsfMappingGetByRoot(root);
330 AssertReturn(pFolderMapping, NULL);
331 if (pFolderMapping->fMissing)
332 return NULL;
333 return pFolderMapping->pszFolderName;
334}
335
336int vbsfMappingsQueryHostRootEx(SHFLROOT hRoot, const char **ppszRoot, uint32_t *pcbRootLen)
337{
338 MAPPING *pFolderMapping = vbsfMappingGetByRoot(hRoot);
339 AssertReturn(pFolderMapping, VERR_INVALID_PARAMETER);
340 if (pFolderMapping->fMissing)
341 return VERR_NOT_FOUND;
342 if ( pFolderMapping->pszFolderName == NULL
343 || pFolderMapping->pszFolderName[0] == 0)
344 return VERR_NOT_FOUND;
345 *ppszRoot = pFolderMapping->pszFolderName;
346 *pcbRootLen = (uint32_t)strlen(pFolderMapping->pszFolderName);
347 return VINF_SUCCESS;
348}
349
350bool vbsfIsGuestMappingCaseSensitive(SHFLROOT root)
351{
352 MAPPING *pFolderMapping = vbsfMappingGetByRoot(root);
353 AssertReturn(pFolderMapping, false);
354 return pFolderMapping->fGuestCaseSensitive;
355}
356
357bool vbsfIsHostMappingCaseSensitive(SHFLROOT root)
358{
359 MAPPING *pFolderMapping = vbsfMappingGetByRoot(root);
360 AssertReturn(pFolderMapping, false);
361 return pFolderMapping->fHostCaseSensitive;
362}
363
364#ifdef UNITTEST
365/** Unit test the SHFL_FN_QUERY_MAPPINGS API. Located here as a form of API
366 * documentation (or should it better be inline in include/VBox/shflsvc.h?) */
367void testMappingsQuery(RTTEST hTest)
368{
369 /* The API should return all mappings if we provide enough buffers. */
370 testMappingsQuerySimple(hTest);
371 /* If we provide too few buffers that should be signalled correctly. */
372 testMappingsQueryTooFewBuffers(hTest);
373 /* The SHFL_MF_AUTOMOUNT flag means return only auto-mounted mappings. */
374 testMappingsQueryAutoMount(hTest);
375 /* The mappings return array must have numberOfMappings entries. */
376 testMappingsQueryArrayWrongSize(hTest);
377}
378#endif
379/**
380 * Note: If pMappings / *pcMappings is smaller than the actual amount of mappings
381 * that *could* have been returned *pcMappings contains the required buffer size
382 * so that the caller can retry the operation if wanted.
383 */
384int vbsfMappingsQuery(PSHFLCLIENTDATA pClient, PSHFLMAPPING pMappings, uint32_t *pcMappings)
385{
386 int rc = VINF_SUCCESS;
387
388 uint32_t cMappings = 0; /* Will contain actual valid mappings. */
389 uint32_t idx = 0; /* Current index in mappings buffer. */
390
391 LogFlow(("vbsfMappingsQuery: pClient = %p, pMappings = %p, pcMappings = %p, *pcMappings = %d\n",
392 pClient, pMappings, pcMappings, *pcMappings));
393
394 for (uint32_t i = 0; i < SHFL_MAX_MAPPINGS; i++)
395 {
396 MAPPING *pFolderMapping = vbsfMappingGetByRoot(i);
397 if ( pFolderMapping != NULL
398 && pFolderMapping->fValid == true)
399 {
400 if (idx < *pcMappings)
401 {
402 /* Skip mappings which are not marked for auto-mounting if
403 * the SHFL_MF_AUTOMOUNT flag ist set. */
404 if ( (pClient->fu32Flags & SHFL_MF_AUTOMOUNT)
405 && !pFolderMapping->fAutoMount)
406 continue;
407
408 pMappings[idx].u32Status = SHFL_MS_NEW;
409 pMappings[idx].root = i;
410 idx++;
411 }
412 cMappings++;
413 }
414 }
415
416 /* Return actual number of mappings, regardless whether the handed in
417 * mapping buffer was big enough. */
418 *pcMappings = cMappings;
419
420 LogFlow(("vbsfMappingsQuery: return rc = %Rrc\n", rc));
421 return rc;
422}
423
424#ifdef UNITTEST
425/** Unit test the SHFL_FN_QUERY_MAP_NAME API. Located here as a form of API
426 * documentation. */
427void testMappingsQueryName(RTTEST hTest)
428{
429 /* If we query an valid mapping it should be returned. */
430 testMappingsQueryNameValid(hTest);
431 /* If we query an invalid mapping that should be signalled. */
432 testMappingsQueryNameInvalid(hTest);
433 /* If we pass in a bad string buffer that should be detected. */
434 testMappingsQueryNameBadBuffer(hTest);
435}
436#endif
437int vbsfMappingsQueryName(PSHFLCLIENTDATA pClient, SHFLROOT root, SHFLSTRING *pString)
438{
439 int rc = VINF_SUCCESS;
440
441 LogFlow(("vbsfMappingsQuery: pClient = %p, root = %d, *pString = %p\n",
442 pClient, root, pString));
443
444 MAPPING *pFolderMapping = vbsfMappingGetByRoot(root);
445 if (pFolderMapping == NULL)
446 {
447 return VERR_INVALID_PARAMETER;
448 }
449
450 if (BIT_FLAG(pClient->fu32Flags, SHFL_CF_UTF8))
451 {
452 /* Not implemented. */
453 AssertFailed();
454 return VERR_INVALID_PARAMETER;
455 }
456
457 if (pFolderMapping->fValid == true)
458 {
459 if (pString->u16Size < pFolderMapping->pMapName->u16Size)
460 {
461 Log(("vbsfMappingsQuery: passed string too short (%d < %d bytes)!\n",
462 pString->u16Size, pFolderMapping->pMapName->u16Size));
463 rc = VERR_INVALID_PARAMETER;
464 }
465 else
466 {
467 pString->u16Length = pFolderMapping->pMapName->u16Length;
468 memcpy(pString->String.ucs2, pFolderMapping->pMapName->String.ucs2,
469 pFolderMapping->pMapName->u16Size);
470 }
471 }
472 else
473 rc = VERR_FILE_NOT_FOUND;
474
475 LogFlow(("vbsfMappingsQuery:Name return rc = %Rrc\n", rc));
476
477 return rc;
478}
479
480/** Queries fWritable flag for the given root. Returns error if the root is not accessible.
481 */
482int vbsfMappingsQueryWritable(PSHFLCLIENTDATA pClient, SHFLROOT root, bool *fWritable)
483{
484 RT_NOREF1(pClient);
485 int rc = VINF_SUCCESS;
486
487 LogFlow(("vbsfMappingsQueryWritable: pClient = %p, root = %d\n", pClient, root));
488
489 MAPPING *pFolderMapping = vbsfMappingGetByRoot(root);
490 AssertReturn(pFolderMapping, VERR_INVALID_PARAMETER);
491
492 if ( pFolderMapping->fValid
493 && !pFolderMapping->fMissing)
494 *fWritable = pFolderMapping->fWritable;
495 else
496 rc = VERR_FILE_NOT_FOUND;
497
498 LogFlow(("vbsfMappingsQuery:Writable return rc = %Rrc\n", rc));
499
500 return rc;
501}
502
503int vbsfMappingsQueryAutoMount(PSHFLCLIENTDATA pClient, SHFLROOT root, bool *fAutoMount)
504{
505 RT_NOREF1(pClient);
506 int rc = VINF_SUCCESS;
507
508 LogFlow(("vbsfMappingsQueryAutoMount: pClient = %p, root = %d\n", pClient, root));
509
510 MAPPING *pFolderMapping = vbsfMappingGetByRoot(root);
511 AssertReturn(pFolderMapping, VERR_INVALID_PARAMETER);
512
513 if (pFolderMapping->fValid == true)
514 *fAutoMount = pFolderMapping->fAutoMount;
515 else
516 rc = VERR_FILE_NOT_FOUND;
517
518 LogFlow(("vbsfMappingsQueryAutoMount:Writable return rc = %Rrc\n", rc));
519
520 return rc;
521}
522
523int vbsfMappingsQuerySymlinksCreate(PSHFLCLIENTDATA pClient, SHFLROOT root, bool *fSymlinksCreate)
524{
525 RT_NOREF1(pClient);
526 int rc = VINF_SUCCESS;
527
528 LogFlow(("vbsfMappingsQueryAutoMount: pClient = %p, root = %d\n", pClient, root));
529
530 MAPPING *pFolderMapping = vbsfMappingGetByRoot(root);
531 AssertReturn(pFolderMapping, VERR_INVALID_PARAMETER);
532
533 if (pFolderMapping->fValid == true)
534 *fSymlinksCreate = pFolderMapping->fSymlinksCreate;
535 else
536 rc = VERR_FILE_NOT_FOUND;
537
538 LogFlow(("vbsfMappingsQueryAutoMount:SymlinksCreate return rc = %Rrc\n", rc));
539
540 return rc;
541}
542
543#ifdef UNITTEST
544/** Unit test the SHFL_FN_MAP_FOLDER API. Located here as a form of API
545 * documentation. */
546void testMapFolder(RTTEST hTest)
547{
548 /* If we try to map a valid name we should get the root. */
549 testMapFolderValid(hTest);
550 /* If we try to map a valid name we should get VERR_FILE_NOT_FOUND. */
551 testMapFolderInvalid(hTest);
552 /* If we map a folder twice we can unmap it twice.
553 * Currently unmapping too often is only asserted but not signalled. */
554 testMapFolderTwice(hTest);
555 /* The delimiter should be converted in e.g. file delete operations. */
556 testMapFolderDelimiter(hTest);
557 /* Test case sensitive mapping by opening a file with the wrong case. */
558 testMapFolderCaseSensitive(hTest);
559 /* Test case insensitive mapping by opening a file with the wrong case. */
560 testMapFolderCaseInsensitive(hTest);
561 /* If the number or types of parameters are wrong the API should fail. */
562 testMapFolderBadParameters(hTest);
563}
564#endif
565int vbsfMapFolder(PSHFLCLIENTDATA pClient, PSHFLSTRING pszMapName,
566 RTUTF16 wcDelimiter, bool fCaseSensitive, SHFLROOT *pRoot)
567{
568 MAPPING *pFolderMapping = NULL;
569
570 if (BIT_FLAG(pClient->fu32Flags, SHFL_CF_UTF8))
571 {
572 Log(("vbsfMapFolder %s\n", pszMapName->String.utf8));
573 }
574 else
575 {
576 Log(("vbsfMapFolder %ls\n", pszMapName->String.ucs2));
577 }
578
579 AssertMsgReturn(wcDelimiter == '/' || wcDelimiter == '\\',
580 ("Invalid path delimiter: %#x\n", wcDelimiter),
581 VERR_INVALID_PARAMETER);
582 if (pClient->PathDelimiter == 0)
583 {
584 pClient->PathDelimiter = wcDelimiter;
585 }
586 else
587 {
588 AssertMsgReturn(wcDelimiter == pClient->PathDelimiter,
589 ("wcDelimiter=%#x PathDelimiter=%#x", wcDelimiter, pClient->PathDelimiter),
590 VERR_INVALID_PARAMETER);
591 }
592
593 if (BIT_FLAG(pClient->fu32Flags, SHFL_CF_UTF8))
594 {
595 int rc;
596 PRTUTF16 utf16Name;
597
598 rc = RTStrToUtf16 ((const char *) pszMapName->String.utf8, &utf16Name);
599 if (RT_FAILURE (rc))
600 return rc;
601
602 pFolderMapping = vbsfMappingGetByName(utf16Name, pRoot);
603 RTUtf16Free (utf16Name);
604 }
605 else
606 {
607 pFolderMapping = vbsfMappingGetByName(pszMapName->String.ucs2, pRoot);
608 }
609
610 if (!pFolderMapping)
611 {
612 return VERR_FILE_NOT_FOUND;
613 }
614
615 pFolderMapping->cMappings++;
616 Assert(pFolderMapping->cMappings == 1 || pFolderMapping->fGuestCaseSensitive == fCaseSensitive);
617 pFolderMapping->fGuestCaseSensitive = fCaseSensitive;
618 return VINF_SUCCESS;
619}
620
621#ifdef UNITTEST
622/** Unit test the SHFL_FN_UNMAP_FOLDER API. Located here as a form of API
623 * documentation. */
624void testUnmapFolder(RTTEST hTest)
625{
626 /* Unmapping a mapped folder should succeed.
627 * If the folder is not mapped this is only asserted, not signalled. */
628 testUnmapFolderValid(hTest);
629 /* Unmapping a non-existant root should fail. */
630 testUnmapFolderInvalid(hTest);
631 /* If the number or types of parameters are wrong the API should fail. */
632 testUnmapFolderBadParameters(hTest);
633}
634#endif
635int vbsfUnmapFolder(PSHFLCLIENTDATA pClient, SHFLROOT root)
636{
637 RT_NOREF1(pClient);
638 int rc = VINF_SUCCESS;
639
640 MAPPING *pFolderMapping = vbsfMappingGetByRoot(root);
641 if (pFolderMapping == NULL)
642 {
643 AssertFailed();
644 return VERR_FILE_NOT_FOUND;
645 }
646
647 Assert(pFolderMapping->fValid == true && pFolderMapping->cMappings > 0);
648 if (pFolderMapping->cMappings > 0)
649 pFolderMapping->cMappings--;
650
651 if ( pFolderMapping->cMappings == 0
652 && pFolderMapping->fPlaceholder)
653 {
654 /* Automatically remove, it is not used by the guest anymore. */
655 Assert(pFolderMapping->fMissing);
656 LogRel2(("SharedFolders: unmapping placeholder '%ls' -> '%s'\n",
657 pFolderMapping->pMapName->String.ucs2, pFolderMapping->pszFolderName));
658 vbsfMappingsRemove(pFolderMapping->pMapName);
659 }
660
661 Log(("vbsfUnmapFolder\n"));
662 return rc;
663}
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