VirtualBox

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

Last change on this file since 71930 was 69753, checked in by vboxsync, 7 years ago

iprt/dir: Morphing PRTDIR into a handle named RTDIR. (Been wanting to correct this for years. Don't know why I makde it a pointer rather than an abstrct handle like everything else.)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.3 KB
Line 
1/* $Id: vbsfpath.cpp 69753 2017-11-19 14:27:58Z vboxsync $ */
2/** @file
3 * Shared Folders - 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#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 RTDIR hSearch = NULL;
100 rc = RTDirOpenFiltered(&hSearch, pDirEntry->szName, RTDIRFILTER_WINNT, 0 /*fFlags*/);
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 if ( rc == VERR_NO_TRANSLATION
115 || rc == VERR_INVALID_UTF8_ENCODING)
116 continue;
117 AssertMsgFailed(("%Rrc\n", rc));
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#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
366/* See MSDN "Naming Files, Paths, and Namespaces".
367 * '<', '>' and '"' are allowed as possible wildcards (see ANSI_DOS_STAR, etc in ntifs.h)
368 */
369static const char sachCharBlackList[] = ":/\\|";
370#else
371/* Something else. */
372static const char sachCharBlackList[] = "/";
373#endif
374
375/** Verify if the character can be used in a host file name.
376 * Wildcard characters ('?', '*') are allowed.
377 *
378 * @param c Character to verify.
379 */
380static bool vbsfPathIsValidNameChar(unsigned char c)
381{
382 /* Character 0 is not allowed too. */
383 if (c == 0 || strchr(sachCharBlackList, c))
384 {
385 return false;
386 }
387
388#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
389 /* Characters less than 32 are not allowed. */
390 if (c < 32)
391 {
392 return false;
393 }
394#endif
395
396 return true;
397}
398
399/** Verify if the character is a wildcard.
400 *
401 * @param c Character to verify.
402 */
403static bool vbsfPathIsWildcardChar(char c)
404{
405 if ( c == '*'
406 || c == '?'
407#ifdef RT_OS_WINDOWS /* See ntifs.h */
408 || c == '<' /* ANSI_DOS_STAR */
409 || c == '>' /* ANSI_DOS_QM */
410 || c == '"' /* ANSI_DOS_DOT */
411#endif
412 )
413 {
414 return true;
415 }
416
417 return false;
418}
419
420int vbsfPathGuestToHost(SHFLCLIENTDATA *pClient, SHFLROOT hRoot,
421 PSHFLSTRING pGuestString, uint32_t cbGuestString,
422 char **ppszHostPath, uint32_t *pcbHostPathRoot,
423 uint32_t fu32Options,
424 uint32_t *pfu32PathFlags)
425{
426#ifdef VBOX_STRICT
427 /*
428 * Check that the pGuestPath has correct size and encoding.
429 */
430 if (ShflStringIsValidIn(pGuestString, cbGuestString, RT_BOOL(pClient->fu32Flags & SHFL_CF_UTF8)) == false)
431 {
432 LogFunc(("Invalid input string\n"));
433 return VERR_INTERNAL_ERROR;
434 }
435#else
436 NOREF(cbGuestString);
437#endif
438
439 /*
440 * Resolve the root handle into a string.
441 */
442 uint32_t cbRootLen = 0;
443 const char *pszRoot = NULL;
444 int rc = vbsfMappingsQueryHostRootEx(hRoot, &pszRoot, &cbRootLen);
445 if (RT_FAILURE(rc))
446 {
447 LogFunc(("invalid root\n"));
448 return rc;
449 }
450
451 AssertReturn(cbRootLen > 0, VERR_INTERNAL_ERROR_2); /* vbsfMappingsQueryHostRootEx ensures this. */
452
453 /*
454 * Get the UTF8 string with the relative path provided by the guest.
455 * If guest uses UTF-16 then convert it to UTF-8.
456 */
457 uint32_t cbGuestPath = 0; /* Shut up MSC */
458 const char *pchGuestPath = NULL; /* Ditto. */
459 char *pchGuestPathAllocated = NULL; /* Converted from UTF-16. */
460 if (BIT_FLAG(pClient->fu32Flags, SHFL_CF_UTF8))
461 {
462 /* UTF-8 */
463 cbGuestPath = pGuestString->u16Length;
464 pchGuestPath = (char *)&pGuestString->String.utf8[0];
465 }
466 else
467 {
468 /* UTF-16 */
469 uint32_t cwcSrc;
470 PRTUTF16 pwszSrc;
471
472#ifdef RT_OS_DARWIN /* Misplaced hack! See todo! */
473 cwcSrc = 0;
474 pwszSrc = NULL;
475 rc = vbsfNormalizeStringDarwin(&pGuestString->String.ucs2[0],
476 pGuestString->u16Length / sizeof(RTUTF16),
477 &pwszSrc, &cwcSrc);
478#else
479 cwcSrc = pGuestString->u16Length / sizeof(RTUTF16);
480 pwszSrc = &pGuestString->String.ucs2[0];
481#endif
482
483 if (RT_SUCCESS(rc))
484 {
485 size_t cbPathAsUtf8 = RTUtf16CalcUtf8Len(pwszSrc);
486 if (cbPathAsUtf8 >= cwcSrc)
487 {
488 /* Allocate buffer that will be able to contain the converted UTF-8 string. */
489 pchGuestPathAllocated = (char *)RTMemAlloc(cbPathAsUtf8 + 1);
490 if (RT_LIKELY(pchGuestPathAllocated != NULL))
491 {
492 if (RT_LIKELY(cbPathAsUtf8))
493 {
494 size_t cchActual;
495 char *pszDst = pchGuestPathAllocated;
496 rc = RTUtf16ToUtf8Ex(pwszSrc, cwcSrc, &pszDst, cbPathAsUtf8 + 1, &cchActual);
497 AssertRC(rc);
498 AssertStmt(RT_FAILURE(rc) || cchActual == cbPathAsUtf8, rc = VERR_INTERNAL_ERROR_4);
499 Assert(strlen(pszDst) == cbPathAsUtf8);
500 }
501
502 if (RT_SUCCESS(rc))
503 {
504 /* Terminate the string. */
505 pchGuestPathAllocated[cbPathAsUtf8] = '\0';
506
507 cbGuestPath = (uint32_t)cbPathAsUtf8; Assert(cbGuestPath == cbPathAsUtf8);
508 pchGuestPath = pchGuestPathAllocated;
509 }
510 }
511 else
512 {
513 rc = VERR_NO_MEMORY;
514 }
515 }
516 else
517 {
518 AssertFailed();
519 rc = VERR_INTERNAL_ERROR_3;
520 }
521
522#ifdef RT_OS_DARWIN
523 RTMemFree(pwszSrc);
524#endif
525 }
526 }
527
528 char *pszFullPath = NULL;
529
530 if (RT_SUCCESS(rc))
531 {
532 LogFlowFunc(("Root %s path %.*s\n", pszRoot, cbGuestPath, pchGuestPath));
533
534 /*
535 * Allocate enough memory to build the host full path from the root and the relative path.
536 */
537 const uint32_t cbFullPathAlloc = cbRootLen + 1 + cbGuestPath + 1; /* root + possible_slash + relative + 0 */
538 pszFullPath = (char *)RTMemAlloc(cbFullPathAlloc);
539 if (RT_LIKELY(pszFullPath != NULL))
540 {
541 /* Buffer for the verified guest path. */
542 char *pchVerifiedPath = (char *)RTMemAlloc(cbGuestPath + 1);
543 if (RT_LIKELY(pchVerifiedPath != NULL))
544 {
545 /* Init the pointer for the guest relative path. */
546 uint32_t cbSrc = cbGuestPath;
547 const char *pchSrc = pchGuestPath;
548
549 /* Strip leading delimiters from the path the guest specified. */
550 while ( cbSrc > 0
551 && *pchSrc == pClient->PathDelimiter)
552 {
553 ++pchSrc;
554 --cbSrc;
555 }
556
557 /*
558 * Iterate the guest path components, verify each of them replacing delimiters with the host slash.
559 */
560 char *pchDst = pchVerifiedPath;
561 bool fLastComponentHasWildcard = false;
562 for (; cbSrc > 0; --cbSrc, ++pchSrc)
563 {
564 if (RT_LIKELY(*pchSrc != pClient->PathDelimiter))
565 {
566 if (RT_LIKELY(vbsfPathIsValidNameChar(*pchSrc)))
567 {
568 if (pfu32PathFlags && vbsfPathIsWildcardChar(*pchSrc))
569 {
570 fLastComponentHasWildcard = true;
571 }
572
573 *pchDst++ = *pchSrc;
574 }
575 else
576 {
577 rc = VERR_INVALID_NAME;
578 break;
579 }
580 }
581 else
582 {
583 /* Replace with the host slash. */
584 *pchDst++ = RTPATH_SLASH;
585
586 if (pfu32PathFlags && fLastComponentHasWildcard && cbSrc > 1)
587 {
588 /* Processed component has a wildcard and there are more characters in the path. */
589 *pfu32PathFlags |= VBSF_F_PATH_HAS_WILDCARD_IN_PREFIX;
590 }
591 fLastComponentHasWildcard = false;
592 }
593 }
594
595 if (RT_SUCCESS(rc))
596 {
597 *pchDst++ = 0;
598
599 /* Construct the full host path removing '.' and '..'. */
600 rc = vbsfPathAbs(pszRoot, pchVerifiedPath, pszFullPath, cbFullPathAlloc);
601 if (RT_SUCCESS(rc))
602 {
603 if (pfu32PathFlags && fLastComponentHasWildcard)
604 {
605 *pfu32PathFlags |= VBSF_F_PATH_HAS_WILDCARD_IN_LAST;
606 }
607
608 /* Check if the full path is still within the shared folder. */
609 if (fu32Options & VBSF_O_PATH_CHECK_ROOT_ESCAPE)
610 {
611 if (!RTPathStartsWith(pszFullPath, pszRoot))
612 {
613 rc = VERR_INVALID_NAME;
614 }
615 }
616
617 if (RT_SUCCESS(rc))
618 {
619 /*
620 * If the host file system is case sensitive and the guest expects
621 * a case insensitive fs, then correct the path components casing.
622 */
623 if ( vbsfIsHostMappingCaseSensitive(hRoot)
624 && !vbsfIsGuestMappingCaseSensitive(hRoot))
625 {
626 const bool fWildCard = RT_BOOL(fu32Options & VBSF_O_PATH_WILDCARD);
627 const bool fPreserveLastComponent = RT_BOOL(fu32Options & VBSF_O_PATH_PRESERVE_LAST_COMPONENT);
628 rc = vbsfCorrectPathCasing(pClient, pszFullPath, strlen(pszFullPath),
629 fWildCard, fPreserveLastComponent);
630 }
631
632 if (RT_SUCCESS(rc))
633 {
634 LogFlowFunc(("%s\n", pszFullPath));
635
636 /* Return the full host path. */
637 *ppszHostPath = pszFullPath;
638
639 if (pcbHostPathRoot)
640 {
641 /* Return the length of the root path without the trailing slash. */
642 *pcbHostPathRoot = RTPATH_IS_SLASH(pszFullPath[cbRootLen - 1]) ?
643 cbRootLen - 1 : /* pszRoot already had the trailing slash. */
644 cbRootLen; /* pszRoot did not have the trailing slash. */
645 }
646 }
647 }
648 }
649 else
650 {
651 LogFunc(("vbsfPathAbs %Rrc\n", rc));
652 }
653 }
654
655 RTMemFree(pchVerifiedPath);
656 }
657 else
658 {
659 rc = VERR_NO_MEMORY;
660 }
661 }
662 else
663 {
664 rc = VERR_NO_MEMORY;
665 }
666 }
667
668 /*
669 * Cleanup.
670 */
671 RTMemFree(pchGuestPathAllocated);
672
673 if (RT_SUCCESS(rc))
674 {
675 return rc;
676 }
677
678 /*
679 * Cleanup on failure.
680 */
681 RTMemFree(pszFullPath);
682
683 LogFunc(("%Rrc\n", rc));
684 return rc;
685}
686
687void vbsfFreeHostPath(char *pszHostPath)
688{
689 RTMemFree(pszHostPath);
690}
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