VirtualBox

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

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

scm --update-copyright-year

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