VirtualBox

Changeset 51250 in vbox


Ignore:
Timestamp:
May 14, 2014 8:11:22 AM (11 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
93688
Message:

shared folders: several fixes, cleanup

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/shflsvc.h

    r51015 r51250  
    205205
    206206/**
    207  * Validates a HGCM string parameter.
     207 * Validates a HGCM string output parameter.
    208208 *
    209209 * @returns true if valid, false if not.
     
    212212 * @param   cbBuf       The buffer size from the parameter.
    213213 */
    214 DECLINLINE(bool) ShflStringIsValid(PCSHFLSTRING pString, uint32_t cbBuf)
     214DECLINLINE(bool) ShflStringIsValidOut(PCSHFLSTRING pString, uint32_t cbBuf)
    215215{
    216216    if (RT_UNLIKELY(cbBuf <= RT_UOFFSETOF(SHFLSTRING, String)))
     
    220220    if (RT_UNLIKELY(pString->u16Length >= pString->u16Size))
    221221        return false;
    222     /** @todo r=bird: Check that u16Length is a multiple of two if UTF-16 input? */
    223     /** @todo r=bird: Do we require the string to have a NUL terminator char, if
    224      *        so check for it!! (Just had a problem with too small (/2) u16Length
    225      *        and code behaving incorrectly because it worked up to the terminator
    226      *        instead of the length.) */
    227     /** @todo r=bird: Who checks for valid UTF-8 encoding of strings? */
    228222    return true;
    229223}
    230224
    231225/**
    232  * Validates an optional HGCM string parameter.
     226 * Validates a HGCM string input parameter.
     227 *
     228 * @returns true if valid, false if not.
     229 *
     230 * @param   pString     The string buffer pointer.
     231 * @param   cbBuf       The buffer size from the parameter.
     232 * @param   fUtf8Not16  Set if UTF-8 encoding, clear if UTF-16 encoding.
     233 */
     234DECLINLINE(bool) ShflStringIsValidIn(PCSHFLSTRING pString, uint32_t cbBuf, bool fUtf8Not16)
     235{
     236    int rc;
     237    if (RT_UNLIKELY(cbBuf <= RT_UOFFSETOF(SHFLSTRING, String)))
     238        return false;
     239    if (RT_UNLIKELY((uint32_t)pString->u16Size + RT_UOFFSETOF(SHFLSTRING, String) > cbBuf))
     240        return false;
     241    if (fUtf8Not16)
     242    {
     243        /* UTF-8: */
     244        if (RT_UNLIKELY(pString->u16Length >= pString->u16Size))
     245            return false;
     246        rc = RTStrValidateEncodingEx((const char *)&pString->String.utf8[0], pString->u16Length + 1,
     247                                     RTSTR_VALIDATE_ENCODING_EXACT_LENGTH | RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED);
     248    }
     249    else
     250    {
     251        /* UTF-16: */
     252        if (RT_UNLIKELY(pString->u16Length & 1))
     253            return false;
     254        if (RT_UNLIKELY((uint32_t)sizeof(RTUTF16) + pString->u16Length > pString->u16Size))
     255            return false;
     256        rc = RTUtf16ValidateEncodingEx(&pString->String.ucs2[0], pString->u16Length / 2 + 1,
     257                                       RTSTR_VALIDATE_ENCODING_EXACT_LENGTH | RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED);
     258    }
     259    if (RT_FAILURE(rc))
     260        return false;
     261    return true;
     262}
     263
     264/**
     265 * Validates an optional HGCM string input parameter.
    233266 *
    234267 * @returns true if valid, false if not.
     
    236269 * @param   pString     The string buffer pointer. Can be NULL.
    237270 * @param   cbBuf       The buffer size from the parameter.
    238  */
    239 DECLINLINE(bool) ShflStringIsValidOrNull(PCSHFLSTRING pString, uint32_t cbBuf)
     271 * @param   fUtf8Not16  Set if UTF-8 encoding, clear if UTF-16 encoding.
     272 */
     273DECLINLINE(bool) ShflStringIsValidOrNullIn(PCSHFLSTRING pString, uint32_t cbBuf, bool fUtf8Not16)
    240274{
    241275    if (pString)
    242         return ShflStringIsValid(pString, cbBuf);
     276        return ShflStringIsValidIn(pString, cbBuf, fUtf8Not16);
    243277    if (RT_UNLIKELY(cbBuf > 0))
    244278        return false;
  • trunk/src/VBox/HostServices/SharedFolders/mappings.cpp

    r44528 r51250  
    535535#endif
    536536int vbsfMapFolder(PSHFLCLIENTDATA pClient, PSHFLSTRING pszMapName,
    537                   RTUTF16 pwszDelimiter, bool fCaseSensitive, SHFLROOT *pRoot)
     537                  RTUTF16 wcDelimiter, bool fCaseSensitive, SHFLROOT *pRoot)
    538538{
    539539    MAPPING *pFolderMapping = NULL;
     
    548548    }
    549549
     550    AssertMsgReturn(wcDelimiter == '/' || wcDelimiter == '\\',
     551                    ("Invalid path delimiter: %#x\n", wcDelimiter),
     552                    VERR_INVALID_PARAMETER);
    550553    if (pClient->PathDelimiter == 0)
    551554    {
    552         pClient->PathDelimiter = pwszDelimiter;
     555        pClient->PathDelimiter = wcDelimiter;
    553556    }
    554557    else
    555558    {
    556         Assert(pwszDelimiter == pClient->PathDelimiter);
     559        AssertMsgReturn(wcDelimiter == pClient->PathDelimiter,
     560                        ("wcDelimiter=%#x PathDelimiter=%#x", wcDelimiter, pClient->PathDelimiter),
     561                        VERR_INVALID_PARAMETER);
    557562    }
    558563
  • trunk/src/VBox/HostServices/SharedFolders/service.cpp

    r44528 r51250  
    385385
    386386                /* Verify parameters values. */
    387                 if (!ShflStringIsValid(pString, paParms[1].u.pointer.size))
     387                if (!ShflStringIsValidOut(pString, paParms[1].u.pointer.size))
    388388                {
    389389                    rc = VERR_INVALID_PARAMETER;
     
    431431
    432432                /* Verify parameters values. */
    433                 if (   !ShflStringIsValid(pPath, cbPath)
     433                if (   !ShflStringIsValidIn(pPath, cbPath, RT_BOOL(pClient->fu32Flags & SHFL_CF_UTF8))
    434434                    || (cbParms != sizeof (SHFLCREATEPARMS))
    435435                   )
     
    442442                {
    443443                    /* Execute the function. */
    444 
    445444                    rc = vbsfCreate (pClient, root, pPath, cbPath, pParms);
    446445
     
    490489                {
    491490                    /* Execute the function. */
    492 
    493491                    rc = vbsfClose (pClient, root, Handle);
    494492
     
    762760                if (   (length < sizeof (SHFLDIRINFO))
    763761                    ||  length > paParms[5].u.pointer.size
    764                     ||  !ShflStringIsValidOrNull(pPath, paParms[4].u.pointer.size)
     762                    ||  !ShflStringIsValidOrNullIn(pPath, paParms[4].u.pointer.size, RT_BOOL(pClient->fu32Flags & SHFL_CF_UTF8))
    765763                   )
    766764                {
     
    830828
    831829                /* Verify parameters values. */
    832                 if (!ShflStringIsValidOrNull(pPath, paParms[1].u.pointer.size))
     830                if (!ShflStringIsValidOrNullIn(pPath, paParms[1].u.pointer.size, RT_BOOL(pClient->fu32Flags & SHFL_CF_UTF8)))
    833831                {
    834832                    rc = VERR_INVALID_PARAMETER;
     
    875873
    876874                /* Verify parameters values. */
    877                 if (!ShflStringIsValid(pszMapName, paParms[0].u.pointer.size))
     875                if (!ShflStringIsValidIn(pszMapName, paParms[0].u.pointer.size, RT_BOOL(pClient->fu32Flags & SHFL_CF_UTF8)))
    878876                {
    879877                    rc = VERR_INVALID_PARAMETER;
     
    926924
    927925                /* Verify parameters values. */
    928                 if (!ShflStringIsValid(pszMapName, paParms[0].u.pointer.size))
    929                 {
    930                     rc = VERR_INVALID_PARAMETER;
    931                 }
    932                 else
    933                 {
    934 
    935                     /* Execute the function. */
     926                if (ShflStringIsValidIn(pszMapName, paParms[0].u.pointer.size, RT_BOOL(pClient->fu32Flags & SHFL_CF_UTF8)))
     927                {
     928                    rc = VINF_SUCCESS;
     929                }
     930                else
     931                {
     932                    rc = VERR_INVALID_PARAMETER;
     933
     934                    /* Fudge for windows GAs getting the length wrong by one char. */
     935                    if (   !(pClient->fu32Flags & SHFL_CF_UTF8)
     936                        && paParms[0].u.pointer.size >= sizeof(SHFLSTRING)
     937                        && pszMapName->u16Length >= 2
     938                        && pszMapName->String.ucs2[pszMapName->u16Length / 2 - 1] == 0x0000)
     939                    {
     940                        pszMapName->u16Length -= 2;
     941                        if (ShflStringIsValidIn(pszMapName, paParms[0].u.pointer.size, false /*fUtf8Not16*/))
     942                            rc = VINF_SUCCESS;
     943                        else
     944                            pszMapName->u16Length += 2;
     945                    }
     946                }
     947
     948                /* Execute the function. */
     949                if (RT_SUCCESS(rc))
    936950                    rc = vbsfMapFolder (pClient, pszMapName, delimiter, fCaseSensitive, &root);
    937951
    938                     if (RT_SUCCESS(rc))
    939                     {
    940                         /* Update parameters.*/
    941                         paParms[1].u.uint32 = root;
    942                     }
     952                if (RT_SUCCESS(rc))
     953                {
     954                    /* Update parameters.*/
     955                    paParms[1].u.uint32 = root;
    943956                }
    944957            }
     
    10651078
    10661079                /* Verify parameters values. */
    1067                 if (!ShflStringIsValid(pPath, cbPath))
     1080                if (!ShflStringIsValidIn(pPath, cbPath, RT_BOOL(pClient->fu32Flags & SHFL_CF_UTF8)))
    10681081                {
    10691082                    rc = VERR_INVALID_PARAMETER;
     
    11091122
    11101123                /* Verify parameters values. */
    1111                 if (    !ShflStringIsValid(pSrc, paParms[1].u.pointer.size)
    1112                     ||  !ShflStringIsValid(pDest, paParms[2].u.pointer.size)
     1124                if (    !ShflStringIsValidIn(pSrc, paParms[1].u.pointer.size, RT_BOOL(pClient->fu32Flags & SHFL_CF_UTF8))
     1125                    ||  !ShflStringIsValidIn(pDest, paParms[2].u.pointer.size, RT_BOOL(pClient->fu32Flags & SHFL_CF_UTF8))
    11131126                   )
    11141127                {
     
    12091222
    12101223                /* Verify parameters values. */
    1211                 if (    !ShflStringIsValid(pNewPath, paParms[1].u.pointer.size)
    1212                     ||  !ShflStringIsValid(pOldPath, paParms[2].u.pointer.size)
     1224                if (    !ShflStringIsValidIn(pNewPath, paParms[1].u.pointer.size, RT_BOOL(pClient->fu32Flags & SHFL_CF_UTF8))
     1225                    ||  !ShflStringIsValidIn(pOldPath, paParms[2].u.pointer.size, RT_BOOL(pClient->fu32Flags & SHFL_CF_UTF8))
    12131226                    ||  (cbInfo != sizeof(SHFLFSOBJINFO))
    12141227                   )
     
    13061319
    13071320            /* Verify parameters values. */
    1308             if (    !ShflStringIsValid(pFolderName, paParms[0].u.pointer.size)
    1309                 ||  !ShflStringIsValid(pMapName, paParms[1].u.pointer.size)
     1321            if (    !ShflStringIsValidIn(pFolderName, paParms[0].u.pointer.size, false /*fUtf8Not16*/)
     1322                ||  !ShflStringIsValidIn(pMapName, paParms[1].u.pointer.size, false /*fUtf8Not16*/)
    13101323               )
    13111324            {
     
    13621375
    13631376            /* Verify parameters values. */
    1364             if (!ShflStringIsValid(pString, paParms[0].u.pointer.size))
     1377            if (!ShflStringIsValidIn(pString, paParms[0].u.pointer.size, false /*fUtf8Not16*/))
    13651378            {
    13661379                rc = VERR_INVALID_PARAMETER;
  • trunk/src/VBox/HostServices/SharedFolders/vbsf.cpp

    r44528 r51250  
    107107}
    108108
     109/**
     110 * Corrects the casing of the final component
     111 *
     112 * @returns
     113 * @param   pClient             .
     114 * @param   pszFullPath         .
     115 * @param   pszStartComponent   .
     116 */
    109117static int vbsfCorrectCasing(SHFLCLIENTDATA *pClient, char *pszFullPath, char *pszStartComponent)
    110118{
    111     PRTDIRENTRYEX  pDirEntry = NULL;
    112     uint32_t       cbDirEntry, cbComponent;
    113     int            rc = VERR_FILE_NOT_FOUND;
    114     PRTDIR         hSearch = 0;
    115     char           szWildCard[4];
    116 
    117119    Log2(("vbsfCorrectCasing: %s %s\n", pszFullPath, pszStartComponent));
    118120
    119     cbComponent = (uint32_t) strlen(pszStartComponent);
    120 
    121     cbDirEntry = 4096;
    122     pDirEntry  = (PRTDIRENTRYEX)RTMemAlloc(cbDirEntry);
    123     if (pDirEntry == 0)
    124     {
    125         AssertFailed();
     121    AssertReturn((uintptr_t)pszFullPath < (uintptr_t)pszStartComponent - 1U, VERR_INTERNAL_ERROR_2);
     122    AssertReturn(pszStartComponent[-1] == RTPATH_DELIMITER, VERR_INTERNAL_ERROR_5);
     123
     124    /*
     125     * Allocate a buffer that can hold really long file name entries as well as
     126     * the initial search pattern.
     127     */
     128    size_t cchComponent = strlen(pszStartComponent);
     129    size_t cchParentDir = pszStartComponent - pszFullPath;
     130    size_t cchFullPath  = cchParentDir + cchComponent;
     131    Assert(strlen(pszFullPath) == cchFullPath);
     132
     133    size_t cbDirEntry   = 4096;
     134    if (cchFullPath + 4 > cbDirEntry - RT_OFFSETOF(RTDIRENTRYEX, szName))
     135        cbDirEntry = RT_OFFSETOF(RTDIRENTRYEX, szName) + cchFullPath + 4;
     136
     137    PRTDIRENTRYEX pDirEntry = (PRTDIRENTRYEX)RTMemAlloc(cbDirEntry);
     138    if (pDirEntry == NULL)
    126139        return VERR_NO_MEMORY;
    127     }
    128 
    129     /** @todo this is quite inefficient, especially for directories with many files */
    130     Assert(pszFullPath < pszStartComponent-1);
    131     Assert(*(pszStartComponent-1) == RTPATH_DELIMITER);
    132     *(pszStartComponent-1) = 0;
    133     strcpy(pDirEntry->szName, pszFullPath);
    134     szWildCard[0] = RTPATH_DELIMITER;
    135     szWildCard[1] = '*';
    136     szWildCard[2] = 0;
    137     strcat(pDirEntry->szName, szWildCard);
    138 
    139     rc = RTDirOpenFiltered(&hSearch, pDirEntry->szName, RTDIRFILTER_WINNT, 0);
    140     *(pszStartComponent-1) = RTPATH_DELIMITER;
     140
     141    /*
     142     * Construct the search criteria in the szName member of pDirEntry.
     143     */
     144    /** @todo This is quite inefficient, especially for directories with many
     145     *        files.  If any of the typically case sensitive host systems start
     146     *        supporting opendir wildcard filters, it would make sense to build
     147     *        one here with '?' for case foldable charaters. */
     148    /** @todo Use RTDirOpen here and drop the whole uncessary path copying? */
     149    int rc = RTPathJoinEx(pDirEntry->szName, cbDirEntry - RT_OFFSETOF(RTDIRENTRYEX, szName),
     150                          pszFullPath, cchParentDir,
     151                          RT_STR_TUPLE("*"));
     152    AssertRC(rc);
     153    if (RT_SUCCESS(rc))
     154    {
     155        PRTDIR hSearch = NULL;
     156        rc = RTDirOpenFiltered(&hSearch, pDirEntry->szName, RTDIRFILTER_WINNT, 0);
     157        if (RT_SUCCESS(rc))
     158        {
     159            for (;;)
     160            {
     161                size_t cbDirEntrySize = cbDirEntry;
     162
     163                rc = RTDirReadEx(hSearch, pDirEntry, &cbDirEntrySize, RTFSOBJATTRADD_NOTHING, SHFL_RT_LINK(pClient));
     164                if (rc == VERR_NO_MORE_FILES)
     165                    break;
     166
     167                if (   rc != VINF_SUCCESS
     168                    && rc != VWRN_NO_DIRENT_INFO)
     169                {
     170                    AssertFailed();
     171                    if (   rc == VERR_NO_TRANSLATION
     172                        || rc == VERR_INVALID_UTF8_ENCODING)
     173                        continue;
     174                    break;
     175                }
     176
     177                Log2(("vbsfCorrectCasing: found %s\n", &pDirEntry->szName[0]));
     178                if (    pDirEntry->cbName == cchComponent
     179                    &&  !RTStrICmp(pszStartComponent, &pDirEntry->szName[0]))
     180                {
     181                    Log(("Found original name %s (%s)\n", &pDirEntry->szName[0], pszStartComponent));
     182                    strcpy(pszStartComponent, &pDirEntry->szName[0]);
     183                    rc = VINF_SUCCESS;
     184                    break;
     185                }
     186            }
     187
     188            RTDirClose(hSearch);
     189        }
     190    }
     191
    141192    if (RT_FAILURE(rc))
    142         goto end;
    143 
    144     for (;;)
    145     {
    146         size_t cbDirEntrySize = cbDirEntry;
    147 
    148         rc = RTDirReadEx(hSearch, pDirEntry, &cbDirEntrySize, RTFSOBJATTRADD_NOTHING, SHFL_RT_LINK(pClient));
    149         if (rc == VERR_NO_MORE_FILES)
    150             break;
    151 
    152         if (   rc != VINF_SUCCESS
    153             && rc != VWRN_NO_DIRENT_INFO)
    154         {
    155             AssertFailed();
    156             if (   rc == VERR_NO_TRANSLATION
    157                 || rc == VERR_INVALID_UTF8_ENCODING)
    158                 continue;
    159             break;
    160         }
    161 
    162         Log2(("vbsfCorrectCasing: found %s\n", &pDirEntry->szName[0]));
    163         if (    pDirEntry->cbName == cbComponent
    164             &&  !RTStrICmp(pszStartComponent, &pDirEntry->szName[0]))
    165         {
    166             Log(("Found original name %s (%s)\n", &pDirEntry->szName[0], pszStartComponent));
    167             strcpy(pszStartComponent, &pDirEntry->szName[0]);
    168             rc = VINF_SUCCESS;
    169             break;
    170         }
    171     }
    172 
    173 end:
    174     if (RT_FAILURE(rc))
    175         Log(("vbsfCorrectCasing %s failed with %d\n", pszStartComponent, rc));
    176 
    177     if (pDirEntry)
    178         RTMemFree(pDirEntry);
    179 
    180     if (hSearch)
    181         RTDirClose(hSearch);
     193        Log(("vbsfCorrectCasing %s failed with %Rrc\n", pszStartComponent, rc));
     194
     195    RTMemFree(pDirEntry);
     196
    182197    return rc;
    183198}
     199
     200/* Temporary stand-in for RTPathExistEx. */
     201static int vbsfQueryExistsEx(const char *pszPath, uint32_t fFlags)
     202{
     203#if 0 /** @todo Fix the symlink issue on windows! */
     204    return RTPathExistsEx(pszPath, fFlags);
     205#else
     206    RTFSOBJINFO IgnInfo;
     207    return RTPathQueryInfoEx(pszPath, &IgnInfo, RTFSOBJATTRADD_NOTHING, fFlags);
     208#endif
     209}
     210
     211/**
     212 * Helper for vbsfBuildFullPath that performs case corrections on the path
     213 * that's being build.
     214 *
     215 * @returns VINF_SUCCESS at the moment.
     216 * @param   pClient                 The client data.
     217 * @param   pszFullPath             Pointer to the full path.  This is the path
     218 *                                  which may need case corrections.  The
     219 *                                  corrections will be applied in place.
     220 * @param   cchFullPath             The length of the full path.
     221 * @param   fWildCard               Whether the last component may contain
     222 *                                  wildcards and thus might require exclusion
     223 *                                  from the case correction.
     224 * @param   fPreserveLastComponent  Always exclude the last component from case
     225 *                                  correction if set.
     226 */
     227static int vbsfCorrectPathCasing(SHFLCLIENTDATA *pClient, char *pszFullPath, size_t cchFullPath,
     228                                 bool fWildCard, bool fPreserveLastComponent)
     229{
     230    /*
     231     * Hide the last path component if it needs preserving.  This is required
     232     * in the following cases:
     233     *    - Contains the wildcard(s).
     234     *    - Is a 'rename' target.
     235     */
     236    char *pszLastComponent = NULL;
     237    if (fWildCard || fPreserveLastComponent)
     238    {
     239        char *pszSrc = pszFullPath + cchFullPath - 1;
     240        Assert(strchr(pszFullPath, '\0') == pszSrc + 1);
     241        while ((uintptr_t)pszSrc > (uintptr_t)pszFullPath)
     242        {
     243            if (*pszSrc == RTPATH_DELIMITER)
     244                break;
     245            pszSrc--;
     246        }
     247        if (*pszSrc == RTPATH_DELIMITER)
     248        {
     249            if (   fPreserveLastComponent
     250                /* Or does it really have wildcards? */
     251                || strchr(pszSrc + 1, '*') != NULL
     252                || strchr(pszSrc + 1, '?') != NULL
     253                || strchr(pszSrc + 1, '>') != NULL
     254                || strchr(pszSrc + 1, '<') != NULL
     255                || strchr(pszSrc + 1, '"') != NULL )
     256            {
     257                pszLastComponent = pszSrc;
     258                *pszLastComponent = '\0';
     259            }
     260        }
     261    }
     262
     263    /*
     264     * If the path/file doesn't exist, we need to attempt case correcting it.
     265     */
     266    /** @todo Don't check when creating files or directories; waste of time. */
     267    int rc = vbsfQueryExistsEx(pszFullPath, SHFL_RT_LINK(pClient));
     268    if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND)
     269    {
     270        Log(("Handle case insensitive guest fs on top of host case sensitive fs for %s\n", pszFullPath));
     271
     272        /*
     273         * Work from the end of the path to find a partial path that's valid.
     274         */
     275        char *pszSrc = pszLastComponent ? pszLastComponent - 1 : pszFullPath + cchFullPath - 1;
     276        Assert(strchr(pszFullPath, '\0') == pszSrc + 1);
     277
     278        while ((uintptr_t)pszSrc > (uintptr_t)pszFullPath)
     279        {
     280            if (*pszSrc == RTPATH_DELIMITER)
     281            {
     282                *pszSrc = '\0';
     283                rc = vbsfQueryExistsEx(pszFullPath, SHFL_RT_LINK(pClient));
     284                *pszSrc = RTPATH_DELIMITER;
     285                if (RT_SUCCESS(rc))
     286                {
     287#ifdef DEBUG
     288                    *pszSrc = '\0';
     289                    Log(("Found valid partial path %s\n", pszFullPath));
     290                    *pszSrc = RTPATH_DELIMITER;
     291#endif
     292                    break;
     293                }
     294            }
     295
     296            pszSrc--;
     297        }
     298        Assert(*pszSrc == RTPATH_DELIMITER && RT_SUCCESS(rc));
     299        if (   *pszSrc == RTPATH_DELIMITER
     300            && RT_SUCCESS(rc))
     301        {
     302            /*
     303             * Turn around and work the other way case correcting the components.
     304             */
     305            pszSrc++;
     306            for (;;)
     307            {
     308                bool fEndOfString = true;
     309
     310                /* Find the end of the component. */
     311                char *pszEnd = pszSrc;
     312                while (*pszEnd)
     313                {
     314                    if (*pszEnd == RTPATH_DELIMITER)
     315                        break;
     316                    pszEnd++;
     317                }
     318
     319                if (*pszEnd == RTPATH_DELIMITER)
     320                {
     321                    fEndOfString = false;
     322                    *pszEnd = '\0';
     323#if 0 /** @todo Please, double check this. The original code is in the #if 0, what I hold as correct is in the #else. */
     324                    rc = RTPathQueryInfoEx(pszSrc, &info, RTFSOBJATTRADD_NOTHING, SHFL_RT_LINK(pClient));
     325#else
     326                    rc = vbsfQueryExistsEx(pszFullPath, SHFL_RT_LINK(pClient));
     327#endif
     328                    Assert(rc == VINF_SUCCESS || rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND);
     329                }
     330                else if (pszEnd == pszSrc)
     331                    rc = VINF_SUCCESS;  /* trailing delimiter */
     332                else
     333                    rc = VERR_FILE_NOT_FOUND;
     334
     335                if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND)
     336                {
     337                    /* Path component is invalid; try to correct the casing. */
     338                    rc = vbsfCorrectCasing(pClient, pszFullPath, pszSrc);
     339                    if (RT_FAILURE(rc))
     340                    {
     341                        /* Failed, so don't bother trying any further components. */
     342                        if (!fEndOfString)
     343                            *pszEnd = RTPATH_DELIMITER; /* Restore the original full path. */
     344                        break;
     345                    }
     346                }
     347
     348                /* Next (if any). */
     349                if (fEndOfString)
     350                    break;
     351
     352                *pszEnd = RTPATH_DELIMITER;
     353                pszSrc = pszEnd + 1;
     354            }
     355            if (RT_FAILURE(rc))
     356                Log(("Unable to find suitable component rc=%d\n", rc));
     357        }
     358        else
     359            rc = VERR_FILE_NOT_FOUND;
     360
     361    }
     362
     363    /* Restore the final component if it was dropped. */
     364    if (pszLastComponent)
     365        *pszLastComponent = RTPATH_DELIMITER;
     366
     367    /* might be a new file so don't fail here! */
     368    return VINF_SUCCESS;
     369}
     370
     371
     372/** @def VBSF_IS_PATH_SLASH
     373 * Checks if @a a_ch is a path delimiter (slash, not volume spearator) for the
     374 * guest or the host.
     375 * @param   a_pClient   Pointer to the client data (SHFLCLIENTDATA).
     376 * @param   a_ch        The character to inspect.
     377 */
     378#if 1
     379# define VBSF_IS_PATH_SLASH(a_pClient, a_ch)     ( (a_ch) == '\\' || (a_ch) == '/' || RTPATH_IS_SLASH(a_ch) )
     380#else
     381# define VBSF_IS_PATH_SLASH(a_pClient, a_ch)     ( (RTUTF16)(a_ch) == (a_pClient)->PathDelimiter || RTPATH_IS_SLASH(a_ch) )
     382#endif
     383
    184384
    185385/**
     
    193393 * @retval  VERR_INVALID_NAME
    194394 *
    195  * @param   pUtf8Path   The path to check.
    196  * @param   cchPath     The length of the path in chars (not code points, but
    197  *                      the C type) excluding the string terminator.
     395 * @param   pszPath         The (UTF-8) path to check.  Slashes has been convert
     396 *                          to host slashes by this time.
    198397 *
    199398 * @remarks This function assumes that the path will be appended to the root
     
    201400 *          checking absolute paths!
    202401 */
    203 static int vbsfPathCheck(const char *pUtf8Path, size_t cchPath)
    204 {
    205     int rc = VINF_SUCCESS;
    206 
    207     size_t i = 0;
     402static int vbsfPathCheck(const char *pszPath)
     403{
     404    /*
     405     * Walk the path, component by component and check for escapes.
     406     */
     407
    208408    int cComponents = 0; /* How many normal path components. */
    209409    int cParentDirs = 0; /* How many '..' components. */
     
    211411    for (;;)
    212412    {
     413        char ch;
     414
    213415        /* Skip leading path delimiters. */
    214         while (   i < cchPath
    215                && (pUtf8Path[i] == '\\' || pUtf8Path[i] == '/'))
    216             i++;
    217 
    218         if (i >= cchPath)
    219             break;
     416        do
     417            ch = *pszPath++;
     418        while (RTPATH_IS_SLASH(ch));
     419        if (ch == '\0')
     420            return VINF_SUCCESS;
    220421
    221422        /* Check if that is a dot component. */
    222423        int cDots = 0;
    223         while (i < cchPath && pUtf8Path[i] == '.')
     424        while (ch == '.')
    224425        {
    225426            cDots++;
    226             i++;
    227         }
    228 
    229         if (   cDots >= 2 /* Consider all multidots sequences as a 'parent dir'. */
    230             && (i >= cchPath || (pUtf8Path[i] == '\\' || pUtf8Path[i] == '/')))
    231         {
    232             cParentDirs++;
    233         }
    234         else if (   cDots == 1
    235                  && (i >= cchPath || (pUtf8Path[i] == '\\' || pUtf8Path[i] == '/')))
    236         {
    237             /* Single dot, nothing changes. */
     427            ch = *pszPath++;
     428        }
     429
     430        if (   cDots >= 1
     431            && (ch == '\0' || RTPATH_IS_SLASH(ch)) )
     432        {
     433            if (cDots >= 2) /* Consider all multidots sequences as a 'parent dir'. */
     434            {
     435                cParentDirs++;
     436
     437                /* Escaping? */
     438                if (cParentDirs > cComponents)
     439                    return VERR_INVALID_NAME;
     440            }
     441            /* else: Single dot, nothing changes. */
    238442        }
    239443        else
    240444        {
    241             /* Skip this component. */
    242             while (   i < cchPath
    243                    && (pUtf8Path[i] != '\\' && pUtf8Path[i] != '/'))
    244                 i++;
    245 
     445            /* Not a dot component, skip to the end of it. */
     446            while (ch != '\0' && !RTPATH_IS_SLASH(ch))
     447                ch = *pszPath++;
    246448            cComponents++;
    247449        }
    248 
    249         Assert(i >= cchPath || (pUtf8Path[i] == '\\' || pUtf8Path[i] == '/'));
    250 
    251         /* Verify counters for every component. */
    252         if (cParentDirs > cComponents)
    253         {
    254             rc = VERR_INVALID_NAME;
    255             break;
    256         }
    257     }
    258 
    259     return rc;
     450        Assert(cComponents >= cParentDirs);
     451
     452        /* The end? */
     453        Assert(ch == '\0' || RTPATH_IS_SLASH(ch));
     454        if (ch == '\0')
     455            return VINF_SUCCESS;
     456    }
    260457}
    261458
     
    264461                             bool fWildCard = false, bool fPreserveLastComponent = false)
    265462{
    266     int rc = VINF_SUCCESS;
    267     char *pszFullPath = NULL;
    268     size_t cbRoot;
     463    /* Resolve the root prefix into a string. */
    269464    const char *pszRoot = vbsfMappingsQueryHostRoot(root);
    270 
    271465    if (   !pszRoot
    272         || !(cbRoot = strlen(pszRoot)))
     466        || !*pszRoot)
    273467    {
    274468        Log(("vbsfBuildFullPath: invalid root!\n"));
    275469        return VERR_INVALID_PARAMETER;
    276470    }
    277 
     471    uint32_t cchRoot = (uint32_t)strlen(pszRoot);
     472#if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS
     473    Assert(!strchr(pszRoot, '/'));
     474#endif
     475
     476    /*
     477     * Combine the root prefix with the guest path into a full UTF-8 path in a
     478     * buffer pointed to by pszFullPath.  cchRoot may be adjusted in the process.
     479     */
     480    int    rc;
     481    size_t cchFullPath;
     482    char  *pszFullPath = NULL;
    278483    if (BIT_FLAG(pClient->fu32Flags, SHFL_CF_UTF8))
    279484    {
    280         /* Verify that the path is under the root directory. */
    281         rc = vbsfPathCheck((const char *)&pPath->String.utf8[0], pPath->u16Length);
    282         if (RT_SUCCESS(rc))
    283         {
    284             size_t cbUtf8FullPath = cbRoot + 1 + pPath->u16Length + 1;
    285             char *utf8FullPath = (char *) RTMemAllocZ(cbUtf8FullPath);
    286 
    287             if (!utf8FullPath)
    288             {
    289                 rc = VERR_NO_MEMORY;
    290                 *ppszFullPath = NULL;
    291                 Log(("RTMemAllocZ %x failed!!\n", cbUtf8FullPath));
    292             }
    293             else
    294             {
    295                 /** @todo r-bird: Pardon me for asking, but who validates the UTF-8 encoding?*/
    296                 memcpy(utf8FullPath, pszRoot, cbRoot);
    297                 utf8FullPath[cbRoot] = '/';
    298                 memcpy(utf8FullPath + cbRoot + 1, &pPath->String.utf8[0], pPath->u16Length);
    299                 utf8FullPath[cbUtf8FullPath - 1] = 0;
    300                 pszFullPath = utf8FullPath;
    301 
    302                 if (pcbFullPathRoot)
    303                     *pcbFullPathRoot = (uint32_t)cbRoot; /* Must index the path delimiter. */
    304             }
     485        /* Strip leading slashes from the path the guest specified. */
     486        uint32_t    cchSrc = pPath->u16Length;
     487        const char *pszSrc = (char *)&pPath->String.utf8[0];
     488        Log(("Root %s path %.*s\n", pszRoot, cchSrc, pszSrc));
     489
     490        while (   cchSrc > 0
     491               && VBSF_IS_PATH_SLASH(pClient, *pszSrc))
     492        {
     493            pszSrc++;
     494            cchSrc--;
     495        }
     496
     497        /* Allocate a buffer that will be able to contain the root prefix and
     498           the path specified by the guest. */
     499        cchFullPath = cchRoot + cchSrc;
     500        pszFullPath = (char *)RTMemAlloc(cchFullPath + 1 + 1);
     501        if (RT_LIKELY(pszFullPath != NULL))
     502        {
     503            memcpy(pszFullPath, pszRoot, cchRoot);
     504            if (!RTPATH_IS_SLASH(pszRoot[-1]))
     505            {
     506                pszFullPath[cchRoot++] = RTPATH_DELIMITER;
     507                cchFullPath++;
     508            }
     509
     510            if (cchSrc)
     511                memcpy(&pszFullPath[cchRoot], pszSrc, cchSrc);
     512
     513            /* Terminate the string. */
     514            pszFullPath[cchRoot + cchSrc] = '\0';
     515            rc = VINF_SUCCESS;
    305516        }
    306517        else
    307518        {
    308             Log(("vbsfBuildFullPath: vbsfPathCheck failed with %Rrc\n", rc));
    309         }
    310     }
    311     else
    312     {
    313 #ifdef RT_OS_DARWIN
     519            Log(("RTMemAlloc %x failed!!\n", cchFullPath + 1));
     520            rc = VERR_NO_MEMORY;
     521        }
     522    }
     523    else /* Client speaks UTF-16. */
     524    {
     525#ifdef RT_OS_DARWIN /* Misplaced hack! See todo! */
    314526/** @todo This belongs in rtPathToNative or in the windows shared folder file system driver...
    315527 * The question is simply whether the NFD normalization is actually applied on a (virtual) file
     
    345557        CFRelease(inStr);
    346558#endif
    347         /* Client sends us UCS2, so convert it to UTF8. */
    348         Log(("Root %s path %.*ls\n", pszRoot, pPath->u16Length/sizeof(pPath->String.ucs2[0]), pPath->String.ucs2));
     559
     560        /* Strip leading slashes and calculate the UTF-8 length. */
     561        size_t      cwcSrc  = pPath->u16Length / sizeof(RTUTF16);
     562        PRTUTF16    pwszSrc = &pPath->String.ucs2[0];
     563        Log(("Root %s path %.*ls\n", pszRoot, cwcSrc, pwszSrc));
     564
     565        while (   cwcSrc > 0
     566               && *pwszSrc < 0x80
     567               && VBSF_IS_PATH_SLASH(pClient, (char)*pwszSrc))
     568        {
     569            pwszSrc++;
     570            cwcSrc--;
     571        }
     572
     573        size_t      cchPathAsUtf8 = RTUtf16CalcUtf8Len(pwszSrc);
     574#ifdef RT_OS_DARWIN
     575        AssertReturnStmt(cchPathAsUtf8 >= cwcSrc, RTMemFree(pPath), VERR_INTERNAL_ERROR_3);
     576#else
     577        AssertReturn(cchPathAsUtf8 >= cwcSrc, VERR_INTERNAL_ERROR_3);
     578#endif
    349579
    350580        /* Allocate buffer that will be able to contain the root prefix and
    351          * the pPath converted to UTF8. Expect a 2 bytes UCS2 to be converted
    352          * to 8 bytes UTF8 in the worst case.
    353          */
    354         uint32_t cbFullPath = (cbRoot + ShflStringLength(pPath)) * 4;
    355         pszFullPath = (char *)RTMemAllocZ(cbFullPath);
    356         if (!pszFullPath)
    357         {
     581         * the pPath converted to UTF-8. */
     582        cchFullPath = cchRoot + cchPathAsUtf8;
     583        pszFullPath = (char *)RTMemAlloc(cchFullPath + 1 + 1);
     584        if (RT_LIKELY(pszFullPath != NULL))
     585        {
     586            /* Copy the root prefix into the result buffer and make sure it
     587               ends with a path separator. */
     588            memcpy(pszFullPath, pszRoot, cchRoot);
     589            if (!RTPATH_IS_SLASH(pszFullPath[cchRoot - 1]))
     590            {
     591                pszFullPath[cchRoot++] = RTPATH_DELIMITER;
     592                cchFullPath++;
     593            }
     594
     595            /* Append the path specified by the guest (if any). */
     596            if (cchPathAsUtf8)
     597            {
     598                size_t cchActual;
     599                char *pszDst = &pszFullPath[cchRoot];
     600                rc = RTUtf16ToUtf8Ex(pwszSrc, cwcSrc, &pszDst, cchFullPath - cchRoot + 1, &cchActual);
     601                AssertRC(rc);
     602                AssertStmt(RT_FAILURE(rc) || cchActual == cchPathAsUtf8, rc = VERR_INTERNAL_ERROR_4);
     603                Assert(strlen(pszDst) == cchPathAsUtf8);
     604            }
     605            else
     606                rc = VINF_SUCCESS;
     607
     608            /* Terminate the string. */
     609            pszFullPath[cchRoot + cchPathAsUtf8] = '\0';
     610        }
     611        else
     612        {
     613            Log(("RTMemAlloc %x failed!!\n", cchFullPath + 1));
    358614            rc = VERR_NO_MEMORY;
    359615        }
    360         else
    361         {
    362             memcpy(pszFullPath, pszRoot, cbRoot + 1);
    363             char *pszDst = pszFullPath;
    364             size_t cbDst = strlen(pszDst);
    365             size_t cb    = cbFullPath;
    366             if (pszDst[cbDst - 1] != RTPATH_DELIMITER)
    367             {
    368                 pszDst[cbDst] = RTPATH_DELIMITER;
    369                 cbDst++;
    370             }
    371 
    372             if (pcbFullPathRoot)
    373                 *pcbFullPathRoot = cbDst - 1; /* Must index the path delimiter.  */
    374 
    375             pszDst += cbDst;
    376             cb     -= cbDst;
    377 
    378             if (pPath->u16Length)
    379             {
    380                 /* Convert and copy components. */
    381                 size_t   cwcSrc  = pPath->u16Length / sizeof(RTUTF16);
    382                 PRTUTF16 pwszSrc = &pPath->String.ucs2[0];
    383 
    384                 /* Correct path delimiters */
    385                 if (pClient->PathDelimiter != RTPATH_DELIMITER)
    386                 {
    387                     LogFlow(("Correct path delimiter in %ls\n", pwszSrc));
    388                     while (*pwszSrc)
    389                     {
    390                         if (*pwszSrc == pClient->PathDelimiter)
    391                             *pwszSrc = RTPATH_DELIMITER;
    392                         pwszSrc++;
    393                     }
    394                     pwszSrc = &pPath->String.ucs2[0];
    395                     LogFlow(("Corrected string %ls\n", pwszSrc));
    396                 }
    397                 if (*pwszSrc == RTPATH_DELIMITER)
    398                 {
    399                     pwszSrc++;  /* we already appended a delimiter to the first part */
    400                     cwcSrc--;
    401                 }
    402 
    403                 rc = RTUtf16ToUtf8Ex(pwszSrc, cwcSrc, &pszDst, cb, &cbDst);
    404                 if (RT_FAILURE(rc))
    405                 {
    406                     AssertFailed();
    407 #ifdef RT_OS_DARWIN
    408                     RTMemFree(pPath);
    409                     pPath = pPathParameter;
    410 #endif
    411                     return rc;
    412                 }
    413                 Assert(cbDst == strlen(pszDst));
    414 
    415                 /* Verify that the path is under the root directory. */
    416                 rc = vbsfPathCheck(pszDst, cbDst);
    417                 if (RT_FAILURE(rc))
    418                 {
    419 #ifdef RT_OS_DARWIN
    420                     RTMemFree(pPath);
    421 #endif
    422                     return rc;
    423                 }
    424 
    425                 cb     -= cbDst;
    426                 pszDst += cbDst;
    427 
    428                 Assert(cb > 0);
    429             }
    430 
    431             /* Nul terminate the string */
    432             *pszDst = 0;
    433         }
     616
    434617#ifdef RT_OS_DARWIN
    435618        RTMemFree(pPath);
     
    437620#endif
    438621    }
    439 
    440622    if (RT_SUCCESS(rc))
    441623    {
    442         /* When the host file system is case sensitive and the guest expects
    443          * a case insensitive fs, then problems can occur */
    444         if (     vbsfIsHostMappingCaseSensitive(root)
    445             &&  !vbsfIsGuestMappingCaseSensitive(root))
    446         {
    447             RTFSOBJINFO info;
    448             char *pszLastComponent = NULL;
    449 
    450             if (fWildCard || fPreserveLastComponent)
    451             {
    452                 /* strip off the last path component, that has to be preserved:
    453                  * contains the wildcard(s) or a 'rename' target. */
    454                 size_t cb = strlen(pszFullPath);
    455                 char *pszSrc = pszFullPath + cb - 1;
    456 
    457                 while (pszSrc > pszFullPath)
    458                 {
    459                     if (*pszSrc == RTPATH_DELIMITER)
    460                         break;
    461                     pszSrc--;
    462                 }
    463                 if (*pszSrc == RTPATH_DELIMITER)
    464                 {
    465                     bool fHaveWildcards = false;
    466                     char *psz = pszSrc;
    467 
    468                     while (*psz)
    469                     {
    470                         char ch = *psz;
    471                         if (ch == '*' || ch == '?' || ch == '>' || ch == '<' || ch == '"')
    472                         {
    473                             fHaveWildcards = true;
    474                             break;
    475                         }
    476                         psz++;
    477                     }
    478 
    479                     if (fHaveWildcards || fPreserveLastComponent)
    480                     {
    481                         pszLastComponent = pszSrc;
    482                         *pszLastComponent = 0;
    483                     }
    484                 }
    485             }
    486 
    487             /** @todo don't check when creating files or directories; waste of time */
    488             rc = RTPathQueryInfoEx(pszFullPath, &info, RTFSOBJATTRADD_NOTHING, SHFL_RT_LINK(pClient));
    489             if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND)
    490             {
    491                 size_t cb = strlen(pszFullPath);
    492                 char   *pszSrc = pszFullPath + cb - 1;
    493 
    494                 Log(("Handle case insensitive guest fs on top of host case sensitive fs for %s\n", pszFullPath));
    495 
    496                 /* Find partial path that's valid */
    497                 while (pszSrc > pszFullPath)
    498                 {
    499                     if (*pszSrc == RTPATH_DELIMITER)
    500                     {
    501                         *pszSrc = 0;
    502                         rc = RTPathQueryInfoEx(pszFullPath, &info, RTFSOBJATTRADD_NOTHING, SHFL_RT_LINK(pClient));
    503                         *pszSrc = RTPATH_DELIMITER;
    504                         if (RT_SUCCESS(rc))
    505                         {
    506 #ifdef DEBUG
    507                             *pszSrc = 0;
    508                             Log(("Found valid partial path %s\n", pszFullPath));
    509                             *pszSrc = RTPATH_DELIMITER;
    510 #endif
    511                             break;
    512                         }
    513                     }
    514 
    515                     pszSrc--;
    516                 }
    517                 Assert(*pszSrc == RTPATH_DELIMITER && RT_SUCCESS(rc));
    518                 if (    *pszSrc == RTPATH_DELIMITER
    519                     &&  RT_SUCCESS(rc))
    520                 {
    521                     pszSrc++;
    522                     for (;;)
    523                     {
    524                         char *pszEnd = pszSrc;
    525                         bool fEndOfString = true;
    526 
    527                         while (*pszEnd)
    528                         {
    529                             if (*pszEnd == RTPATH_DELIMITER)
    530                                 break;
    531                             pszEnd++;
    532                         }
    533 
    534                         if (*pszEnd == RTPATH_DELIMITER)
    535                         {
    536                             fEndOfString = false;
    537                             *pszEnd = 0;
    538                             rc = RTPathQueryInfoEx(pszSrc, &info, RTFSOBJATTRADD_NOTHING, SHFL_RT_LINK(pClient));
    539                             Assert(rc == VINF_SUCCESS || rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND);
    540                         }
    541                         else if (pszEnd == pszSrc)
    542                             rc = VINF_SUCCESS;  /* trailing delimiter */
    543                         else
    544                             rc = VERR_FILE_NOT_FOUND;
    545 
    546                         if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND)
    547                         {
    548                             /* path component is invalid; try to correct the casing */
    549                             rc = vbsfCorrectCasing(pClient, pszFullPath, pszSrc);
    550                             if (RT_FAILURE(rc))
    551                             {
    552                                 if (!fEndOfString)
    553                                     *pszEnd = RTPATH_DELIMITER; /* restore the original full path */
    554                                 break;
    555                             }
    556                         }
    557 
    558                         if (fEndOfString)
    559                             break;
    560 
    561                         *pszEnd = RTPATH_DELIMITER;
    562                         pszSrc = pszEnd + 1;
    563                     }
    564                     if (RT_FAILURE(rc))
    565                         Log(("Unable to find suitable component rc=%d\n", rc));
    566                 }
    567                 else
    568                     rc = VERR_FILE_NOT_FOUND;
    569 
    570             }
    571             if (pszLastComponent)
    572                 *pszLastComponent = RTPATH_DELIMITER;
    573 
    574             /* might be a new file so don't fail here! */
    575             rc = VINF_SUCCESS;
    576         }
    577         *ppszFullPath = pszFullPath;
    578 
    579         LogFlow(("vbsfBuildFullPath: %s rc=%Rrc\n", pszFullPath, rc));
    580     }
    581 
     624        Assert(strlen(pszFullPath) == cchFullPath);
     625        Assert(RTPATH_IS_SLASH(pszFullPath[cchRoot - 1])); /* includes delimiter. */
     626
     627        if (pcbFullPathRoot)
     628            *pcbFullPathRoot = cchRoot - 1; /* Must index the path delimiter. */
     629
     630        /*
     631         * Convert guest path delimiters into host ones and check for attempts
     632         * to escape the shared folder root directory.
     633         *
     634         * After this, there will only be RTPATH_DELIMITER slashes in the path!
     635         *
     636         * ASSUMES that the root path only has RTPATH_DELIMITER as well.
     637         */
     638        char  ch;
     639        char *pszTmp = &pszFullPath[cchRoot];
     640        while ((ch = *pszTmp) != '\0')
     641        {
     642            if (VBSF_IS_PATH_SLASH(pClient, ch))
     643                *pszTmp = RTPATH_DELIMITER;
     644            pszTmp++;
     645        }
     646        LogFlow(("Corrected string %s\n", pszFullPath));
     647
     648        rc = vbsfPathCheck(&pszFullPath[cchRoot]);
     649        if (RT_SUCCESS(rc))
     650        {
     651            /*
     652             * When the host file system is case sensitive and the guest expects
     653             * a case insensitive fs, then problems can occur.
     654             */
     655            if (    vbsfIsHostMappingCaseSensitive(root)
     656                && !vbsfIsGuestMappingCaseSensitive(root))
     657                rc = vbsfCorrectPathCasing(pClient, pszFullPath, cchFullPath, fWildCard, fPreserveLastComponent);
     658            if (RT_SUCCESS(rc))
     659            {
     660                /*
     661                 * We're good.
     662                 */
     663                *ppszFullPath = pszFullPath;
     664                LogFlow(("vbsfBuildFullPath: %s rc=%Rrc\n", pszFullPath, rc));
     665                return rc;
     666            }
     667
     668            /* Failed, clean up. */
     669            Log(("vbsfBuildFullPath: %s rc=%Rrc\n", pszFullPath, rc));
     670        }
     671        else
     672            Log(("vbsfBuildPath: Caught escape attempt: (%.*s) '%s'\n", cchRoot, pszFullPath, &pszFullPath[cchRoot]));
     673    }
     674
     675    if (pszFullPath)
     676        RTMemFree(pszFullPath);
     677    *ppszFullPath = NULL;
    582678    return rc;
    583679}
     
    19602056
    19612057    ShflStringInitBuffer(&dummy, sizeof(dummy));
     2058    dummy.String.ucs2[0] = '\0';
    19622059    rc = vbsfBuildFullPath(pClient, root, &dummy, 0, &pszFullPath, NULL);
    19632060
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette