VirtualBox

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

Last change on this file since 98110 was 98103, checked in by vboxsync, 23 months ago

Copyright year updates by scm.

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