VirtualBox

source: vbox/trunk/src/VBox/HostServices/SharedFolders/vbsfpath.cpp@ 57782

Last change on this file since 57782 was 57782, checked in by vboxsync, 9 years ago

SharedFolders: options for guest to host path conversion.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.1 KB
Line 
1/* $Id: vbsfpath.cpp 57782 2015-09-16 12:15:31Z vboxsync $ */
2/** @file
3 * Shared Folders - guest/host path convertion and verification.
4 */
5
6/*
7 * Copyright (C) 2006-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.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#ifdef UNITTEST
19# include "testcase/tstSharedFolderService.h"
20#endif
21
22#include "vbsfpath.h"
23#include "mappings.h"
24#include "vbsf.h"
25#include "shflhandle.h"
26
27#include <iprt/alloc.h>
28#include <iprt/asm.h>
29#include <iprt/assert.h>
30#include <iprt/fs.h>
31#include <iprt/dir.h>
32#include <iprt/file.h>
33#include <iprt/path.h>
34#include <iprt/string.h>
35#include <iprt/symlink.h>
36#include <iprt/uni.h>
37#include <iprt/stream.h>
38#ifdef RT_OS_DARWIN
39# include <Carbon/Carbon.h>
40#endif
41
42#ifdef UNITTEST
43# include "teststubs.h"
44#endif
45
46#define SHFL_RT_LINK(pClient) ((pClient)->fu32Flags & SHFL_CF_SYMLINKS ? RTPATH_F_ON_LINK : RTPATH_F_FOLLOW_LINK)
47
48/**
49 * @todo find a better solution for supporting the execute bit for non-windows
50 * guests on windows host. Search for "0111" to find all the relevant places.
51 */
52
53/**
54 * Corrects the casing of the final component
55 *
56 * @returns
57 * @param pClient .
58 * @param pszFullPath .
59 * @param pszStartComponent .
60 */
61static int vbsfCorrectCasing(SHFLCLIENTDATA *pClient, char *pszFullPath, char *pszStartComponent)
62{
63 Log2(("vbsfCorrectCasing: %s %s\n", pszFullPath, pszStartComponent));
64
65 AssertReturn((uintptr_t)pszFullPath < (uintptr_t)pszStartComponent - 1U, VERR_INTERNAL_ERROR_2);
66 AssertReturn(pszStartComponent[-1] == RTPATH_DELIMITER, VERR_INTERNAL_ERROR_5);
67
68 /*
69 * Allocate a buffer that can hold really long file name entries as well as
70 * the initial search pattern.
71 */
72 size_t cchComponent = strlen(pszStartComponent);
73 size_t cchParentDir = pszStartComponent - pszFullPath;
74 size_t cchFullPath = cchParentDir + cchComponent;
75 Assert(strlen(pszFullPath) == cchFullPath);
76
77 size_t cbDirEntry = 4096;
78 if (cchFullPath + 4 > cbDirEntry - RT_OFFSETOF(RTDIRENTRYEX, szName))
79 cbDirEntry = RT_OFFSETOF(RTDIRENTRYEX, szName) + cchFullPath + 4;
80
81 PRTDIRENTRYEX pDirEntry = (PRTDIRENTRYEX)RTMemAlloc(cbDirEntry);
82 if (pDirEntry == NULL)
83 return VERR_NO_MEMORY;
84
85 /*
86 * Construct the search criteria in the szName member of pDirEntry.
87 */
88 /** @todo This is quite inefficient, especially for directories with many
89 * files. If any of the typically case sensitive host systems start
90 * supporting opendir wildcard filters, it would make sense to build
91 * one here with '?' for case foldable charaters. */
92 /** @todo Use RTDirOpen here and drop the whole uncessary path copying? */
93 int rc = RTPathJoinEx(pDirEntry->szName, cbDirEntry - RT_OFFSETOF(RTDIRENTRYEX, szName),
94 pszFullPath, cchParentDir,
95 RT_STR_TUPLE("*"));
96 AssertRC(rc);
97 if (RT_SUCCESS(rc))
98 {
99 PRTDIR hSearch = NULL;
100 rc = RTDirOpenFiltered(&hSearch, pDirEntry->szName, RTDIRFILTER_WINNT, 0);
101 if (RT_SUCCESS(rc))
102 {
103 for (;;)
104 {
105 size_t cbDirEntrySize = cbDirEntry;
106
107 rc = RTDirReadEx(hSearch, pDirEntry, &cbDirEntrySize, RTFSOBJATTRADD_NOTHING, SHFL_RT_LINK(pClient));
108 if (rc == VERR_NO_MORE_FILES)
109 break;
110
111 if ( rc != VINF_SUCCESS
112 && rc != VWRN_NO_DIRENT_INFO)
113 {
114 AssertFailed();
115 if ( rc == VERR_NO_TRANSLATION
116 || rc == VERR_INVALID_UTF8_ENCODING)
117 continue;
118 break;
119 }
120
121 Log2(("vbsfCorrectCasing: found %s\n", &pDirEntry->szName[0]));
122 if ( pDirEntry->cbName == cchComponent
123 && !RTStrICmp(pszStartComponent, &pDirEntry->szName[0]))
124 {
125 Log(("Found original name %s (%s)\n", &pDirEntry->szName[0], pszStartComponent));
126 strcpy(pszStartComponent, &pDirEntry->szName[0]);
127 rc = VINF_SUCCESS;
128 break;
129 }
130 }
131
132 RTDirClose(hSearch);
133 }
134 }
135
136 if (RT_FAILURE(rc))
137 Log(("vbsfCorrectCasing %s failed with %Rrc\n", pszStartComponent, rc));
138
139 RTMemFree(pDirEntry);
140
141 return rc;
142}
143
144/* Temporary stand-in for RTPathExistEx. */
145static int vbsfQueryExistsEx(const char *pszPath, uint32_t fFlags)
146{
147#if 0 /** @todo Fix the symlink issue on windows! */
148 return RTPathExistsEx(pszPath, fFlags);
149#else
150 RTFSOBJINFO IgnInfo;
151 return RTPathQueryInfoEx(pszPath, &IgnInfo, RTFSOBJATTRADD_NOTHING, fFlags);
152#endif
153}
154
155/**
156 * Helper for vbsfBuildFullPath that performs case corrections on the path
157 * that's being build.
158 *
159 * @returns VINF_SUCCESS at the moment.
160 * @param pClient The client data.
161 * @param pszFullPath Pointer to the full path. This is the path
162 * which may need case corrections. The
163 * corrections will be applied in place.
164 * @param cchFullPath The length of the full path.
165 * @param fWildCard Whether the last component may contain
166 * wildcards and thus might require exclusion
167 * from the case correction.
168 * @param fPreserveLastComponent Always exclude the last component from case
169 * correction if set.
170 */
171static int vbsfCorrectPathCasing(SHFLCLIENTDATA *pClient, char *pszFullPath, size_t cchFullPath,
172 bool fWildCard, bool fPreserveLastComponent)
173{
174 /*
175 * Hide the last path component if it needs preserving. This is required
176 * in the following cases:
177 * - Contains the wildcard(s).
178 * - Is a 'rename' target.
179 */
180 char *pszLastComponent = NULL;
181 if (fWildCard || fPreserveLastComponent)
182 {
183 char *pszSrc = pszFullPath + cchFullPath - 1;
184 Assert(strchr(pszFullPath, '\0') == pszSrc + 1);
185 while ((uintptr_t)pszSrc > (uintptr_t)pszFullPath)
186 {
187 if (*pszSrc == RTPATH_DELIMITER)
188 break;
189 pszSrc--;
190 }
191 if (*pszSrc == RTPATH_DELIMITER)
192 {
193 if ( fPreserveLastComponent
194 /* Or does it really have wildcards? */
195 || strchr(pszSrc + 1, '*') != NULL
196 || strchr(pszSrc + 1, '?') != NULL
197 || strchr(pszSrc + 1, '>') != NULL
198 || strchr(pszSrc + 1, '<') != NULL
199 || strchr(pszSrc + 1, '"') != NULL )
200 {
201 pszLastComponent = pszSrc;
202 *pszLastComponent = '\0';
203 }
204 }
205 }
206
207 /*
208 * If the path/file doesn't exist, we need to attempt case correcting it.
209 */
210 /** @todo Don't check when creating files or directories; waste of time. */
211 int rc = vbsfQueryExistsEx(pszFullPath, SHFL_RT_LINK(pClient));
212 if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND)
213 {
214 Log(("Handle case insensitive guest fs on top of host case sensitive fs for %s\n", pszFullPath));
215
216 /*
217 * Work from the end of the path to find a partial path that's valid.
218 */
219 char *pszSrc = pszLastComponent ? pszLastComponent - 1 : pszFullPath + cchFullPath - 1;
220 Assert(strchr(pszFullPath, '\0') == pszSrc + 1);
221
222 while ((uintptr_t)pszSrc > (uintptr_t)pszFullPath)
223 {
224 if (*pszSrc == RTPATH_DELIMITER)
225 {
226 *pszSrc = '\0';
227 rc = vbsfQueryExistsEx(pszFullPath, SHFL_RT_LINK(pClient));
228 *pszSrc = RTPATH_DELIMITER;
229 if (RT_SUCCESS(rc))
230 {
231#ifdef DEBUG
232 *pszSrc = '\0';
233 Log(("Found valid partial path %s\n", pszFullPath));
234 *pszSrc = RTPATH_DELIMITER;
235#endif
236 break;
237 }
238 }
239
240 pszSrc--;
241 }
242 Assert(*pszSrc == RTPATH_DELIMITER && RT_SUCCESS(rc));
243 if ( *pszSrc == RTPATH_DELIMITER
244 && RT_SUCCESS(rc))
245 {
246 /*
247 * Turn around and work the other way case correcting the components.
248 */
249 pszSrc++;
250 for (;;)
251 {
252 bool fEndOfString = true;
253
254 /* Find the end of the component. */
255 char *pszEnd = pszSrc;
256 while (*pszEnd)
257 {
258 if (*pszEnd == RTPATH_DELIMITER)
259 break;
260 pszEnd++;
261 }
262
263 if (*pszEnd == RTPATH_DELIMITER)
264 {
265 fEndOfString = false;
266 *pszEnd = '\0';
267#if 0 /** @todo Please, double check this. The original code is in the #if 0, what I hold as correct is in the #else. */
268 rc = RTPathQueryInfoEx(pszSrc, &info, RTFSOBJATTRADD_NOTHING, SHFL_RT_LINK(pClient));
269#else
270 rc = vbsfQueryExistsEx(pszFullPath, SHFL_RT_LINK(pClient));
271#endif
272 Assert(rc == VINF_SUCCESS || rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND);
273 }
274 else if (pszEnd == pszSrc)
275 rc = VINF_SUCCESS; /* trailing delimiter */
276 else
277 rc = VERR_FILE_NOT_FOUND;
278
279 if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND)
280 {
281 /* Path component is invalid; try to correct the casing. */
282 rc = vbsfCorrectCasing(pClient, pszFullPath, pszSrc);
283 if (RT_FAILURE(rc))
284 {
285 /* Failed, so don't bother trying any further components. */
286 if (!fEndOfString)
287 *pszEnd = RTPATH_DELIMITER; /* Restore the original full path. */
288 break;
289 }
290 }
291
292 /* Next (if any). */
293 if (fEndOfString)
294 break;
295
296 *pszEnd = RTPATH_DELIMITER;
297 pszSrc = pszEnd + 1;
298 }
299 if (RT_FAILURE(rc))
300 Log(("Unable to find suitable component rc=%d\n", rc));
301 }
302 else
303 rc = VERR_FILE_NOT_FOUND;
304
305 }
306
307 /* Restore the final component if it was dropped. */
308 if (pszLastComponent)
309 *pszLastComponent = RTPATH_DELIMITER;
310
311 /* might be a new file so don't fail here! */
312 return VINF_SUCCESS;
313}
314
315
316#ifdef RT_OS_DARWIN
317/* Misplaced hack! See todo! */
318
319/** Normalize the string using kCFStringNormalizationFormD.
320 *
321 * @param pwszSrc The input UTF-16 string.
322 * @param cwcSrc Length of the input string in characters.
323 * @param ppwszDst Where to store the pointer to the resulting normalized string.
324 * @param pcwcDst Where to store length of the normalized string in characters (without the trailing nul).
325 */
326static int vbsfNormalizeStringDarwin(const PRTUTF16 pwszSrc, uint32_t cwcSrc, PRTUTF16 *ppwszDst, uint32_t *pcwcDst)
327{
328 /** @todo This belongs in rtPathToNative or in the windows shared folder file system driver...
329 * The question is simply whether the NFD normalization is actually applied on a (virtual) file
330 * system level in darwin, or just by the user mode application libs. */
331
332 PRTUTF16 pwszNFD;
333 uint32_t cwcNFD;
334
335 CFMutableStringRef inStr = ::CFStringCreateMutable(NULL, 0);
336
337 /* Is 8 times length enough for decomposed in worst case...? */
338 size_t cbNFDAlloc = cwcSrc * 8 + 2;
339 pwszNFD = (PRTUTF16)RTMemAllocZ(cbNFDAlloc);
340 if (!pwszNFD)
341 {
342 return VERR_NO_MEMORY;
343 }
344
345 ::CFStringAppendCharacters(inStr, (UniChar*)pwszSrc, cwcSrc);
346 ::CFStringNormalize(inStr, kCFStringNormalizationFormD);
347 cwcNFD = ::CFStringGetLength(inStr);
348
349 CFRange rangeCharacters;
350 rangeCharacters.location = 0;
351 rangeCharacters.length = cwcNFD;
352 ::CFStringGetCharacters(inStr, rangeCharacters, pwszNFD);
353
354 pwszNFD[cwcNFD] = 0x0000; /* NULL terminated */
355
356 CFRelease(inStr);
357
358 *ppwszDst = pwszNFD;
359 *pcwcDst = cwcNFD;
360 return VINF_SUCCESS;
361}
362#endif
363
364
365/**
366 * Check the given UTF-8 path for root escapes.
367 *
368 * Verify that the path is within the root directory of the mapping. Count '..'
369 * and other path components and check that we do not go over the root.
370 *
371 * @returns VBox status code.
372 * @retval VINF_SUCCESS
373 * @retval VERR_INVALID_NAME
374 *
375 * @param pszPath The (UTF-8) path to check. Slashes has been convert
376 * to host slashes by this time.
377 *
378 * @remarks This function assumes that the path will be appended to the root
379 * directory of the shared folder mapping. Keep that in mind when
380 * checking absolute paths!
381 */
382static int vbsfPathCheckRootEscape(const char *pszPath)
383{
384 /*
385 * Walk the path, component by component and check for escapes.
386 */
387
388 int cComponents = 0; /* How many normal path components. */
389 int cParentDirs = 0; /* How many '..' components. */
390
391 for (;;)
392 {
393 char ch;
394
395 /* Skip leading path delimiters. */
396 do
397 ch = *pszPath++;
398 while (RTPATH_IS_SLASH(ch));
399 if (ch == '\0')
400 return VINF_SUCCESS;
401
402 /* Check if that is a dot component. */
403 int cDots = 0;
404 while (ch == '.')
405 {
406 cDots++;
407 ch = *pszPath++;
408 }
409
410 if ( cDots >= 1
411 && (ch == '\0' || RTPATH_IS_SLASH(ch)) )
412 {
413 if (cDots >= 2) /* Consider all multidots sequences as a 'parent dir'. */
414 {
415 cParentDirs++;
416
417 /* Escaping? */
418 if (cParentDirs > cComponents)
419 return VERR_INVALID_NAME;
420 }
421 /* else: Single dot, nothing changes. */
422 }
423 else
424 {
425 /* Not a dot component, skip to the end of it. */
426 while (ch != '\0' && !RTPATH_IS_SLASH(ch))
427 ch = *pszPath++;
428 cComponents++;
429 }
430 Assert(cComponents >= cParentDirs);
431
432 /* The end? */
433 Assert(ch == '\0' || RTPATH_IS_SLASH(ch));
434 if (ch == '\0')
435 return VINF_SUCCESS;
436 }
437}
438
439#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
440/* See MSDN "Naming Files, Paths, and Namespaces".
441 * '<', '>' and '"' are allowed as possible wildcards (see ANSI_DOS_STAR, etc in ntifs.h)
442 */
443static const char sachCharBlackList[] = ":/\\|";
444#elif defined(RT_OS_DARWIN)
445/* Technically only '/' is not allowed, but apparently ':' has a special meaning in Finder.
446 */
447static const char sachCharBlackList[] = ":/";
448#else
449/* Something else. */
450static const char sachCharBlackList[] = "/";
451#endif
452
453/** Verify if the character can be used in a host file name.
454 * Wildcard characters ('?', '*') are allowed.
455 *
456 * @param c Character to verify.
457 */
458static bool vbsfPathIsValidNameChar(unsigned char c)
459{
460 /* Character 0 is not allowed too. */
461 if (c == 0 || strchr(sachCharBlackList, c))
462 {
463 return false;
464 }
465
466#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
467 /* Characters less than 32 are not allowed. */
468 if (c < 32)
469 {
470 return false;
471 }
472#endif
473
474 return true;
475}
476
477/** Verify if the character is a wildcard.
478 *
479 * @param c Character to verify.
480 */
481static bool vbsfPathIsWildcardChar(char c)
482{
483 if ( c == '*'
484 || c == '?'
485#ifdef RT_OS_WINDOWS /* See ntifs.h */
486 || c == '<' /* ANSI_DOS_STAR */
487 || c == '>' /* ANSI_DOS_QM */
488 || c == '"' /* ANSI_DOS_DOT */
489#endif
490 )
491 {
492 return true;
493 }
494
495 return false;
496}
497
498int vbsfPathGuestToHost(SHFLCLIENTDATA *pClient, SHFLROOT hRoot,
499 PSHFLSTRING pGuestString, uint32_t cbGuestString,
500 char **ppszHostPath, uint32_t *pcbHostPathRoot,
501 uint32_t fu32Options,
502 uint32_t *pfu32PathFlags)
503{
504#ifdef VBOX_STRICT
505 /*
506 * Check that the pGuestPath has correct size and encoding.
507 */
508 if (ShflStringIsValidIn(pGuestString, cbGuestString, RT_BOOL(pClient->fu32Flags & SHFL_CF_UTF8)) == false)
509 {
510 LogFunc(("Invalid input string\n"));
511 return VERR_INTERNAL_ERROR;
512 }
513#else
514 NOREF(cbGuestString);
515#endif
516
517 /*
518 * Resolve the root handle into a string.
519 */
520 uint32_t cbRootLen = 0;
521 const char *pszRoot = NULL;
522 int rc = vbsfMappingsQueryHostRootEx(hRoot, &pszRoot, &cbRootLen);
523 if (RT_FAILURE(rc))
524 {
525 LogFunc(("invalid root\n"));
526 return rc;
527 }
528
529 AssertReturn(cbRootLen > 0, VERR_INTERNAL_ERROR_2); /* vbsfMappingsQueryHostRootEx ensures this. */
530
531 /*
532 * Get the UTF8 string with the relative path provided by the guest.
533 * If guest uses UTF-16 then convert it to UTF-8.
534 */
535 uint32_t cbGuestPath;
536 const char *pchGuestPath;
537 char *pchGuestPathAllocated = NULL; /* Converted from UTF-16. */
538 if (BIT_FLAG(pClient->fu32Flags, SHFL_CF_UTF8))
539 {
540 /* UTF-8 */
541 cbGuestPath = pGuestString->u16Length;
542 pchGuestPath = (char *)&pGuestString->String.utf8[0];
543 }
544 else
545 {
546 /* UTF-16 */
547 uint32_t cwcSrc;
548 PRTUTF16 pwszSrc;
549
550#ifdef RT_OS_DARWIN /* Misplaced hack! See todo! */
551 cwcSrc = 0;
552 pwszSrc = NULL;
553 rc = vbsfNormalizeStringDarwin(&pGuestString->String.ucs2[0],
554 pGuestString->u16Length / sizeof(RTUTF16),
555 &pwszSrc, &cwcSrc);
556#else
557 cwcSrc = pGuestString->u16Length / sizeof(RTUTF16);
558 pwszSrc = &pGuestString->String.ucs2[0];
559#endif
560
561 if (RT_SUCCESS(rc))
562 {
563 size_t cbPathAsUtf8 = RTUtf16CalcUtf8Len(pwszSrc);
564 if (cbPathAsUtf8 >= cwcSrc)
565 {
566 /* Allocate buffer that will be able to contain the converted UTF-8 string. */
567 pchGuestPathAllocated = (char *)RTMemAlloc(cbPathAsUtf8 + 1);
568 if (RT_LIKELY(pchGuestPathAllocated != NULL))
569 {
570 if (RT_LIKELY(cbPathAsUtf8))
571 {
572 size_t cchActual;
573 char *pszDst = pchGuestPathAllocated;
574 rc = RTUtf16ToUtf8Ex(pwszSrc, cwcSrc, &pszDst, cbPathAsUtf8 + 1, &cchActual);
575 AssertRC(rc);
576 AssertStmt(RT_FAILURE(rc) || cchActual == cbPathAsUtf8, rc = VERR_INTERNAL_ERROR_4);
577 Assert(strlen(pszDst) == cbPathAsUtf8);
578 }
579
580 if (RT_SUCCESS(rc))
581 {
582 /* Terminate the string. */
583 pchGuestPathAllocated[cbPathAsUtf8] = '\0';
584
585 cbGuestPath = cbPathAsUtf8;
586 pchGuestPath = pchGuestPathAllocated;
587 }
588 }
589 else
590 {
591 rc = VERR_NO_MEMORY;
592 }
593 }
594 else
595 {
596 AssertFailed();
597 rc = VERR_INTERNAL_ERROR_3;
598 }
599
600#ifdef RT_OS_DARWIN
601 RTMemFree(pwszSrc);
602#endif
603 }
604 }
605
606 char *pszFullPath = NULL;
607
608 if (RT_SUCCESS(rc))
609 {
610 LogFlowFunc(("Root %s path %.*s\n", pszRoot, cbGuestPath, pchGuestPath));
611
612 /*
613 * Allocate enough memory to build the host full path from the root and the relative path.
614 */
615 uint32_t cbFullPathAlloc = cbRootLen + 1 + cbGuestPath + 1; /* root + possible_slash + relative + 0 */
616 pszFullPath = (char *)RTMemAlloc(cbFullPathAlloc);
617 if (RT_LIKELY(pszFullPath != NULL))
618 {
619 /* Copy the root. */
620 memcpy(pszFullPath, pszRoot, cbRootLen);
621 if (!RTPATH_IS_SLASH(pszFullPath[cbRootLen - 1]))
622 {
623 pszFullPath[cbRootLen++] = RTPATH_SLASH;
624 }
625
626 /* Init the pointer for the relative path. */
627 char *pchDst = &pszFullPath[cbRootLen];
628
629 uint32_t cbSrc = cbGuestPath;
630 const char *pchSrc = pchGuestPath;
631
632 /* Strip leading delimiters from the path the guest specified. */
633 while ( cbSrc > 0
634 && *pchSrc == pClient->PathDelimiter)
635 {
636 ++pchSrc;
637 --cbSrc;
638 }
639
640 /*
641 * Iterate the guest path components, verify each of them
642 * and append to the host full path replacing delimiters with host slash.
643 */
644 bool fLastComponentHasWildcard = false;
645 for (; cbSrc > 0; --cbSrc, ++pchSrc)
646 {
647 if (RT_LIKELY(*pchSrc != pClient->PathDelimiter))
648 {
649 if (RT_LIKELY(vbsfPathIsValidNameChar(*pchSrc)))
650 {
651 if (pfu32PathFlags && vbsfPathIsWildcardChar(*pchSrc))
652 {
653 fLastComponentHasWildcard = true;
654 }
655
656 *pchDst++ = *pchSrc;
657 }
658 else
659 {
660 rc = VERR_INVALID_NAME;
661 break;
662 }
663 }
664 else
665 {
666 /* Replace with the host slash. */
667 *pchDst++ = RTPATH_SLASH;
668
669 if (pfu32PathFlags && fLastComponentHasWildcard && cbSrc > 1)
670 {
671 /* Processed component has a wildcard and there are more characters in the path. */
672 *pfu32PathFlags |= VBSF_F_PATH_HAS_WILDCARD_IN_PREFIX;
673 }
674 fLastComponentHasWildcard = false;
675 }
676 }
677
678 if (RT_SUCCESS(rc))
679 {
680 const size_t cbFullPathLength = pchDst - &pszFullPath[0]; /* As strlen(pszFullPath). */
681
682 *pchDst++ = 0;
683
684 if (pfu32PathFlags && fLastComponentHasWildcard)
685 {
686 *pfu32PathFlags |= VBSF_F_PATH_HAS_WILDCARD_IN_LAST;
687 }
688
689 /* Check the appended path for root escapes. */
690 if (fu32Options & VBSF_O_PATH_CHECK_ROOT_ESCAPE)
691 {
692 rc = vbsfPathCheckRootEscape(&pszFullPath[cbRootLen]);
693 }
694 if (RT_SUCCESS(rc))
695 {
696 /*
697 * When the host file system is case sensitive and the guest expects
698 * a case insensitive fs, then problems can occur.
699 */
700 if ( vbsfIsHostMappingCaseSensitive(hRoot)
701 && !vbsfIsGuestMappingCaseSensitive(hRoot))
702 {
703 bool fWildCard = RT_BOOL(fu32Options & VBSF_O_PATH_WILDCARD);
704 bool fPreserveLastComponent = RT_BOOL(fu32Options & VBSF_O_PATH_PRESERVE_LAST_COMPONENT);
705 rc = vbsfCorrectPathCasing(pClient, pszFullPath, cbFullPathLength, fWildCard, fPreserveLastComponent);
706 }
707
708 if (RT_SUCCESS(rc))
709 {
710 LogFunc(("%s\n", pszFullPath));
711
712 /* Return the full host path. */
713 *ppszHostPath = pszFullPath;
714
715 if (pcbHostPathRoot)
716 {
717 *pcbHostPathRoot = cbRootLen - 1; /* Must index the path delimiter. */
718 }
719 }
720 }
721 }
722 }
723 else
724 {
725 rc = VERR_NO_MEMORY;
726 }
727 }
728
729 /*
730 * Cleanup.
731 */
732 RTMemFree(pchGuestPathAllocated);
733
734 if (RT_SUCCESS(rc))
735 {
736 return rc;
737 }
738
739 /*
740 * Cleanup on failure.
741 */
742 RTMemFree(pszFullPath);
743
744 return rc;
745}
746
747void vbsfFreeHostPath(char *pszHostPath)
748{
749 RTMemFree(pszHostPath);
750}
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