VirtualBox

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

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

HGCM,Main,SharedFolder,SharedClipboard,GuestProperties: Added HGCM service helpers for statistics and dbg info registration/deregistration. A PUVM is passed to HGCMService (where the helpers are implemented) when the service is loaded. Since this drags in both dbg.h and stam.h, LOG_GROUP defines now have to be at the top of the include list as everywhere else (i.e. hgcmsvc.h will define LOG_GROUP default by dragging in log.h). Added generic statistics of HGCM message processing and function level statistics to the shared folder service. [missing files, ++]

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