VirtualBox

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

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

HostServices/SharedFolders: starter unit test.

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

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