VirtualBox

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

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

SharedFolders: more fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.8 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 bool fWritable, bool fAutoMount, bool fSymlinksCreate)
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 FolderMapping[i].fSymlinksCreate = fSymlinksCreate;
239
240 /* Check if the host file system is case sensitive */
241 RTFSPROPERTIES prop;
242 char *pszAsciiRoot;
243
244 rc = RTStrUtf8ToCurrentCP(&pszAsciiRoot, FolderMapping[i].pszFolderName);
245 if (RT_SUCCESS(rc))
246 {
247 rc = RTFsQueryProperties(pszAsciiRoot, &prop);
248 AssertRC(rc);
249 RTStrFree(pszAsciiRoot);
250 }
251
252 FolderMapping[i].fHostCaseSensitive = RT_SUCCESS(rc) ? prop.fCaseSensitive : false;
253 vbsfRootHandleAdd(i);
254 break;
255 }
256 }
257 if (i == SHFL_MAX_MAPPINGS)
258 {
259 AssertMsgFailed(("vbsfMappingsAdd: no more room to add mapping %ls to %ls!!\n", pFolderName->String.ucs2, pMapName->String.ucs2));
260 return VERR_TOO_MUCH_DATA;
261 }
262
263 Log(("vbsfMappingsAdd: added mapping %ls to %ls\n", pFolderName->String.ucs2, pMapName->String.ucs2));
264 return VINF_SUCCESS;
265}
266
267#ifdef UNITTEST
268/** Unit test the SHFL_FN_REMOVE_MAPPING API. Located here as a form of API
269 * documentation. */
270void testMappingsRemove(RTTEST hTest)
271{
272 /* If the number or types of parameters are wrong the API should fail. */
273 testMappingsRemoveBadParameters(hTest);
274 /* Add tests as required... */
275}
276#endif
277int vbsfMappingsRemove(PSHFLSTRING pMapName)
278{
279 unsigned i;
280
281 Assert(pMapName);
282
283 Log(("vbsfMappingsRemove %ls\n", pMapName->String.ucs2));
284 for (i=0; i<SHFL_MAX_MAPPINGS; i++)
285 {
286 if (FolderMapping[i].fValid == true)
287 {
288 if (!RTUtf16LocaleICmp(FolderMapping[i].pMapName->String.ucs2, pMapName->String.ucs2))
289 {
290 if (FolderMapping[i].cMappings != 0)
291 {
292 Log(("vbsfMappingsRemove: trying to remove active share %ls\n", pMapName->String.ucs2));
293 return VERR_PERMISSION_DENIED;
294 }
295
296 RTStrFree(FolderMapping[i].pszFolderName);
297 RTMemFree(FolderMapping[i].pMapName);
298 FolderMapping[i].pszFolderName = NULL;
299 FolderMapping[i].pMapName = NULL;
300 FolderMapping[i].fValid = false;
301 vbsfRootHandleRemove(i);
302 break;
303 }
304 }
305 }
306
307 if (i == SHFL_MAX_MAPPINGS)
308 {
309 AssertMsgFailed(("vbsfMappingsRemove: mapping %ls not found!!!!\n", pMapName->String.ucs2));
310 return VERR_FILE_NOT_FOUND;
311 }
312 Log(("vbsfMappingsRemove: mapping %ls removed\n", pMapName->String.ucs2));
313 return VINF_SUCCESS;
314}
315
316const char* vbsfMappingsQueryHostRoot(SHFLROOT root)
317{
318 MAPPING *pFolderMapping = vbsfMappingGetByRoot(root);
319 AssertReturn(pFolderMapping, NULL);
320 return pFolderMapping->pszFolderName;
321}
322
323bool vbsfIsGuestMappingCaseSensitive(SHFLROOT root)
324{
325 MAPPING *pFolderMapping = vbsfMappingGetByRoot(root);
326 AssertReturn(pFolderMapping, false);
327 return pFolderMapping->fGuestCaseSensitive;
328}
329
330bool vbsfIsHostMappingCaseSensitive(SHFLROOT root)
331{
332 MAPPING *pFolderMapping = vbsfMappingGetByRoot(root);
333 AssertReturn(pFolderMapping, false);
334 return pFolderMapping->fHostCaseSensitive;
335}
336
337#ifdef UNITTEST
338/** Unit test the SHFL_FN_QUERY_MAPPINGS API. Located here as a form of API
339 * documentation (or should it better be inline in include/VBox/shflsvc.h?) */
340void testMappingsQuery(RTTEST hTest)
341{
342 /* The API should return all mappings if we provide enough buffers. */
343 testMappingsQuerySimple(hTest);
344 /* If we provide too few buffers that should be signalled correctly. */
345 testMappingsQueryTooFewBuffers(hTest);
346 /* The SHFL_MF_AUTOMOUNT flag means return only auto-mounted mappings. */
347 testMappingsQueryAutoMount(hTest);
348 /* The mappings return array must have numberOfMappings entries. */
349 testMappingsQueryArrayWrongSize(hTest);
350}
351#endif
352/**
353 * Note: If pMappings / *pcMappings is smaller than the actual amount of mappings
354 * that *could* have been returned *pcMappings contains the required buffer size
355 * so that the caller can retry the operation if wanted.
356 */
357int vbsfMappingsQuery(PSHFLCLIENTDATA pClient, PSHFLMAPPING pMappings, uint32_t *pcMappings)
358{
359 int rc = VINF_SUCCESS;
360
361 uint32_t cMappings = 0; /* Will contain actual valid mappings. */
362 uint32_t idx = 0; /* Current index in mappings buffer. */
363
364 LogFlow(("vbsfMappingsQuery: pClient = %p, pMappings = %p, pcMappings = %p, *pcMappings = %d\n",
365 pClient, pMappings, pcMappings, *pcMappings));
366
367 for (uint32_t i = 0; i < SHFL_MAX_MAPPINGS; i++)
368 {
369 MAPPING *pFolderMapping = vbsfMappingGetByRoot(i);
370 if ( pFolderMapping != NULL
371 && pFolderMapping->fValid == true)
372 {
373 if (idx < *pcMappings)
374 {
375 /* Skip mappings which are not marked for auto-mounting if
376 * the SHFL_MF_AUTOMOUNT flag ist set. */
377 if ( (pClient->fu32Flags & SHFL_MF_AUTOMOUNT)
378 && !pFolderMapping->fAutoMount)
379 continue;
380
381 pMappings[idx].u32Status = SHFL_MS_NEW;
382 pMappings[idx].root = i;
383 idx++;
384 }
385 cMappings++;
386 }
387 }
388
389 /* Return actual number of mappings, regardless whether the handed in
390 * mapping buffer was big enough. */
391 *pcMappings = cMappings;
392
393 LogFlow(("vbsfMappingsQuery: return rc = %Rrc\n", rc));
394 return rc;
395}
396
397#ifdef UNITTEST
398/** Unit test the SHFL_FN_QUERY_MAP_NAME API. Located here as a form of API
399 * documentation. */
400void testMappingsQueryName(RTTEST hTest)
401{
402 /* If we query an valid mapping it should be returned. */
403 testMappingsQueryNameValid(hTest);
404 /* If we query an invalid mapping that should be signalled. */
405 testMappingsQueryNameInvalid(hTest);
406 /* If we pass in a bad string buffer that should be detected. */
407 testMappingsQueryNameBadBuffer(hTest);
408}
409#endif
410int vbsfMappingsQueryName(PSHFLCLIENTDATA pClient, SHFLROOT root, SHFLSTRING *pString)
411{
412 int rc = VINF_SUCCESS;
413
414 LogFlow(("vbsfMappingsQuery: pClient = %p, root = %d, *pString = %p\n",
415 pClient, root, pString));
416
417 MAPPING *pFolderMapping = vbsfMappingGetByRoot(root);
418 if (pFolderMapping == NULL)
419 {
420 return VERR_INVALID_PARAMETER;
421 }
422
423 if (BIT_FLAG(pClient->fu32Flags, SHFL_CF_UTF8))
424 {
425 /* Not implemented. */
426 AssertFailed();
427 return VERR_INVALID_PARAMETER;
428 }
429
430 if (pFolderMapping->fValid == true)
431 {
432 pString->u16Length = pFolderMapping->pMapName->u16Length;
433 memcpy(pString->String.ucs2, pFolderMapping->pMapName->String.ucs2, pString->u16Size);
434 }
435 else
436 rc = VERR_FILE_NOT_FOUND;
437
438 LogFlow(("vbsfMappingsQuery:Name return rc = %Rrc\n", rc));
439
440 return rc;
441}
442
443int vbsfMappingsQueryWritable(PSHFLCLIENTDATA pClient, SHFLROOT root, bool *fWritable)
444{
445 int rc = VINF_SUCCESS;
446
447 LogFlow(("vbsfMappingsQueryWritable: pClient = %p, root = %d\n", pClient, root));
448
449 MAPPING *pFolderMapping = vbsfMappingGetByRoot(root);
450 AssertReturn(pFolderMapping, VERR_INVALID_PARAMETER);
451
452 if (pFolderMapping->fValid == true)
453 *fWritable = pFolderMapping->fWritable;
454 else
455 rc = VERR_FILE_NOT_FOUND;
456
457 LogFlow(("vbsfMappingsQuery:Writable return rc = %Rrc\n", rc));
458
459 return rc;
460}
461
462int vbsfMappingsQueryAutoMount(PSHFLCLIENTDATA pClient, SHFLROOT root, bool *fAutoMount)
463{
464 int rc = VINF_SUCCESS;
465
466 LogFlow(("vbsfMappingsQueryAutoMount: pClient = %p, root = %d\n", pClient, root));
467
468 MAPPING *pFolderMapping = vbsfMappingGetByRoot(root);
469 AssertReturn(pFolderMapping, VERR_INVALID_PARAMETER);
470
471 if (pFolderMapping->fValid == true)
472 *fAutoMount = pFolderMapping->fAutoMount;
473 else
474 rc = VERR_FILE_NOT_FOUND;
475
476 LogFlow(("vbsfMappingsQueryAutoMount:Writable return rc = %Rrc\n", rc));
477
478 return rc;
479}
480
481int vbsfMappingsQuerySymlinksCreate(PSHFLCLIENTDATA pClient, SHFLROOT root, bool *fSymlinksCreate)
482{
483 int rc = VINF_SUCCESS;
484
485 LogFlow(("vbsfMappingsQueryAutoMount: pClient = %p, root = %d\n", pClient, root));
486
487 MAPPING *pFolderMapping = vbsfMappingGetByRoot(root);
488 AssertReturn(pFolderMapping, VERR_INVALID_PARAMETER);
489
490 if (pFolderMapping->fValid == true)
491 *fSymlinksCreate = pFolderMapping->fSymlinksCreate;
492 else
493 rc = VERR_FILE_NOT_FOUND;
494
495 LogFlow(("vbsfMappingsQueryAutoMount:SymlinksCreate return rc = %Rrc\n", rc));
496
497 return rc;
498}
499
500#ifdef UNITTEST
501/** Unit test the SHFL_FN_MAP_FOLDER API. Located here as a form of API
502 * documentation. */
503void testMapFolder(RTTEST hTest)
504{
505 /* If we try to map a valid name we should get the root. */
506 testMapFolderValid(hTest);
507 /* If we try to map a valid name we should get VERR_FILE_NOT_FOUND. */
508 testMapFolderInvalid(hTest);
509 /* If we map a folder twice we can unmap it twice.
510 * Currently unmapping too often is only asserted but not signalled. */
511 testMapFolderTwice(hTest);
512 /* The delimiter should be converted in e.g. file delete operations. */
513 testMapFolderDelimiter(hTest);
514 /* Test case sensitive mapping by opening a file with the wrong case. */
515 testMapFolderCaseSensitive(hTest);
516 /* Test case insensitive mapping by opening a file with the wrong case. */
517 testMapFolderCaseInsensitive(hTest);
518 /* If the number or types of parameters are wrong the API should fail. */
519 testMapFolderBadParameters(hTest);
520}
521#endif
522int vbsfMapFolder(PSHFLCLIENTDATA pClient, PSHFLSTRING pszMapName,
523 RTUTF16 pwszDelimiter, bool fCaseSensitive, SHFLROOT *pRoot)
524{
525 MAPPING *pFolderMapping = NULL;
526
527 if (BIT_FLAG(pClient->fu32Flags, SHFL_CF_UTF8))
528 {
529 Log(("vbsfMapFolder %s\n", pszMapName->String.utf8));
530 }
531 else
532 {
533 Log(("vbsfMapFolder %ls\n", pszMapName->String.ucs2));
534 }
535
536 if (pClient->PathDelimiter == 0)
537 {
538 pClient->PathDelimiter = pwszDelimiter;
539 }
540 else
541 {
542 Assert(pwszDelimiter == pClient->PathDelimiter);
543 }
544
545 if (BIT_FLAG(pClient->fu32Flags, SHFL_CF_UTF8))
546 {
547 int rc;
548 PRTUTF16 utf16Name;
549
550 rc = RTStrToUtf16 ((const char *) pszMapName->String.utf8, &utf16Name);
551 if (RT_FAILURE (rc))
552 return rc;
553
554 pFolderMapping = vbsfMappingGetByName(utf16Name, pRoot);
555 RTUtf16Free (utf16Name);
556 }
557 else
558 {
559 pFolderMapping = vbsfMappingGetByName(pszMapName->String.ucs2, pRoot);
560 }
561
562 if (!pFolderMapping)
563 {
564 return VERR_FILE_NOT_FOUND;
565 }
566
567 pFolderMapping->cMappings++;
568 Assert(pFolderMapping->cMappings == 1 || pFolderMapping->fGuestCaseSensitive == fCaseSensitive);
569 pFolderMapping->fGuestCaseSensitive = fCaseSensitive;
570 return VINF_SUCCESS;
571}
572
573#ifdef UNITTEST
574/** Unit test the SHFL_FN_UNMAP_FOLDER API. Located here as a form of API
575 * documentation. */
576void testUnmapFolder(RTTEST hTest)
577{
578 /* Unmapping a mapped folder should succeed.
579 * If the folder is not mapped this is only asserted, not signalled. */
580 testUnmapFolderValid(hTest);
581 /* Unmapping a non-existant root should fail. */
582 testUnmapFolderInvalid(hTest);
583 /* If the number or types of parameters are wrong the API should fail. */
584 testUnmapFolderBadParameters(hTest);
585}
586#endif
587int vbsfUnmapFolder(PSHFLCLIENTDATA pClient, SHFLROOT root)
588{
589 int rc = VINF_SUCCESS;
590
591 MAPPING *pFolderMapping = vbsfMappingGetByRoot(root);
592 if (pFolderMapping == NULL)
593 {
594 AssertFailed();
595 return VERR_FILE_NOT_FOUND;
596 }
597
598 Assert(pFolderMapping->fValid == true && pFolderMapping->cMappings > 0);
599 if (pFolderMapping->cMappings > 0)
600 pFolderMapping->cMappings--;
601
602 Log(("vbsfUnmapFolder\n"));
603 return rc;
604}
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