VirtualBox

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

Last change on this file since 39607 was 39607, checked in by vboxsync, 13 years ago

HostServices/SharedFolders: store the host folder name as UTF8 as we always convert it to UTF8 and never use the other format

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