VirtualBox

Changeset 56961 in vbox


Ignore:
Timestamp:
Jul 17, 2015 7:55:21 AM (10 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
101671
Message:

HostServices/SharedFolders: guest to host path conversion (new files)

File:
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/HostServices/SharedFolders/vbsfpath.cpp

    r56938 r56961  
    11/* $Id$ */
    22/** @file
    3  * Shared Folders - VBox Shared Folders.
     3 * Shared Folders - guest/host path convertion and verification.
    44 */
    55
    66/*
    7  * Copyright (C) 2006-2013 Oracle Corporation
     7 * Copyright (C) 2006-2015 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2020#endif
    2121
     22#include "vbsfpath.h"
    2223#include "mappings.h"
    2324#include "vbsf.h"
     
    2526
    2627#include <iprt/alloc.h>
     28#include <iprt/asm.h>
    2729#include <iprt/assert.h>
    2830#include <iprt/fs.h>
     
    4951 */
    5052
    51 void vbsfStripLastComponent(char *pszFullPath, uint32_t cbFullPathRoot)
    52 {
    53     RTUNICP cp;
    54 
    55     /* Do not strip root. */
    56     char *s = pszFullPath + cbFullPathRoot;
    57     char *delimSecondLast = NULL;
    58     char *delimLast = NULL;
    59 
    60     LogFlowFunc(("%s -> %s\n", pszFullPath, s));
    61 
    62     for (;;)
    63     {
    64         cp = RTStrGetCp(s);
    65 
    66         if (cp == RTUNICP_INVALID || cp == 0)
    67         {
    68             break;
    69         }
    70 
    71         if (cp == RTPATH_DELIMITER)
    72         {
    73             if (delimLast != NULL)
    74             {
    75                 delimSecondLast = delimLast;
    76             }
    77 
    78             delimLast = s;
    79         }
    80 
    81         s = RTStrNextCp(s);
    82     }
    83 
    84     if (cp == 0)
    85     {
    86         if (delimLast + 1 == s)
    87         {
    88             if (delimSecondLast)
    89             {
    90                 *delimSecondLast = 0;
    91             }
    92             else if (delimLast)
    93             {
    94                 *delimLast = 0;
    95             }
    96         }
    97         else
    98         {
    99             if (delimLast)
    100             {
    101                 *delimLast = 0;
    102             }
    103         }
    104     }
    105 
    106     LogFlowFunc(("%s, %s, %s\n", pszFullPath, delimLast, delimSecondLast));
    107 }
    108 
    10953/**
    11054 * Corrects the casing of the final component
     
    370314
    371315
    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) )
     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}
    382362#endif
    383363
     
    400380 *          checking absolute paths!
    401381 */
    402 static int vbsfPathCheck(const char *pszPath)
     382static int vbsfPathCheckRootEscape(const char *pszPath)
    403383{
    404384    /*
     
    457437}
    458438
    459 static int vbsfBuildFullPath(SHFLCLIENTDATA *pClient, SHFLROOT root, PSHFLSTRING pPath,
    460                              uint32_t cbPath, char **ppszFullPath, uint32_t *pcbFullPathRoot,
    461                              bool fWildCard = false, bool fPreserveLastComponent = false)
    462 {
    463     /* Resolve the root prefix into a string. */
    464     const char *pszRoot = vbsfMappingsQueryHostRoot(root);
    465     if (   !pszRoot
    466         || !*pszRoot)
    467     {
    468         Log(("vbsfBuildFullPath: invalid root!\n"));
    469         return VERR_INVALID_PARAMETER;
    470     }
    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;
     439#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
     440/* See MSDN "Naming Files, Paths, and Namespaces".
     441 * '<', '>' and '"' are allowed as possible wildcards (see ANSI_DOS_STAR, etc in ntifs.h)
     442 */
     443static const char sachCharBlackList[] = ":/\\|";
     444#elif defined(RT_OS_DARWIN)
     445/* Technically only '/' is not allowed, but apparently ':' has a special meaning in Finder.
     446 */
     447static const char sachCharBlackList[] = ":/";
     448#else
     449/* Something else. */
     450static const char sachCharBlackList[] = "/";
     451#endif
     452
     453/** Verify if the character can be used in a host file name.
     454 * Wildcard characters ('?', '*') are allowed.
     455 *
     456 * @param c Character to verify.
     457 */
     458static bool vbsfPathIsValidNameChar(char c)
     459{
     460    /* Character 0 is not allowed too. */
     461    if (c == 0 || strchr(sachCharBlackList, c))
     462    {
     463        return false;
     464    }
     465
     466#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
     467    /* Characters less than 32 are not allowed. */
     468    if (c < 32)
     469    {
     470        return false;
     471    }
     472#endif
     473
     474    return true;
     475}
     476
     477/** Verify if the character is a wildcard.
     478 *
     479 * @param c Character to verify.
     480 */
     481static bool vbsfPathIsWildcardChar(char c)
     482{
     483    if (   c == '*'
     484        || c == '?'
     485#ifdef RT_OS_WINDOWS /* See ntifs.h */
     486        || c == '<' /* ANSI_DOS_STAR */
     487        || c == '>' /* ANSI_DOS_QM */
     488        || c == '"' /* ANSI_DOS_DOT */
     489#endif
     490       )
     491    {
     492        return true;
     493    }
     494
     495    return false;
     496}
     497
     498int vbsfPathGuestToHost(SHFLCLIENTDATA *pClient, SHFLROOT hRoot,
     499                        PSHFLSTRING pGuestString, uint32_t cbGuestString,
     500                        char **ppszHostPath, uint32_t *pcbHostPathRoot,
     501                        bool fWildCard, bool fPreserveLastComponent,
     502                        uint32_t *pfu32PathFlags)
     503{
     504#ifdef VBOX_STRICT
     505    /*
     506     * Check that the pGuestPath has correct size and encoding.
     507     */
     508    if (ShflStringIsValidIn(pGuestString, cbGuestString, RT_BOOL(pClient->fu32Flags & SHFL_CF_UTF8)) == false)
     509    {
     510        LogFunc(("Invalid input string\n"));
     511        return VERR_INTERNAL_ERROR;
     512    }
     513#else
     514    NOREF(cbGuestString);
     515#endif
     516
     517    /*
     518     * Resolve the root handle into a string.
     519     */
     520    uint32_t cbRootLen = 0;
     521    const char *pszRoot = NULL;
     522    int rc = vbsfMappingsQueryHostRootEx(hRoot, &pszRoot, &cbRootLen);
     523    if (RT_FAILURE(rc))
     524    {
     525        LogFunc(("invalid root\n"));
     526        return rc;
     527    }
     528
     529    AssertReturn(cbRootLen > 0, VERR_INTERNAL_ERROR_2); /* vbsfMappingsQueryHostRootEx ensures this. */
     530
     531    /*
     532     * Get the UTF8 string with the relative path provided by the guest.
     533     * If guest uses UTF-16 then convert it to UTF-8.
     534     */
     535    uint32_t    cbGuestPath;
     536    const char *pchGuestPath;
     537    char *pchGuestPathAllocated = NULL; /* Converted from UTF-16. */
    483538    if (BIT_FLAG(pClient->fu32Flags, SHFL_CF_UTF8))
    484539    {
    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);
     540        /* UTF-8 */
     541        cbGuestPath = pGuestString->u16Length;
     542        pchGuestPath = (char *)&pGuestString->String.utf8[0];
     543    }
     544    else
     545    {
     546        /* UTF-16 */
     547        uint32_t cwcSrc;
     548        PRTUTF16 pwszSrc;
     549
     550#ifdef RT_OS_DARWIN /* Misplaced hack! See todo! */
     551        cwcSrc = 0;
     552        pwszSrc = NULL;
     553        rc = vbsfNormalizeStringDarwin(&pGuestString->String.ucs2[0],
     554                                       pGuestString->u16Length / sizeof(RTUTF16),
     555                                       &pwszSrc, &cwcSrc);
     556#else
     557        cwcSrc  = pGuestString->u16Length / sizeof(RTUTF16);
     558        pwszSrc = &pGuestString->String.ucs2[0];
     559#endif
     560
     561        if (RT_SUCCESS(rc))
     562        {
     563            size_t cbPathAsUtf8 = RTUtf16CalcUtf8Len(pwszSrc);
     564            if (cbPathAsUtf8 >= cwcSrc)
     565            {
     566                /* Allocate buffer that will be able to contain the converted UTF-8 string. */
     567                pchGuestPathAllocated = (char *)RTMemAlloc(cbPathAsUtf8 + 1);
     568                if (RT_LIKELY(pchGuestPathAllocated != NULL))
     569                {
     570                    if (RT_LIKELY(cbPathAsUtf8))
     571                    {
     572                        size_t cchActual;
     573                        char *pszDst = pchGuestPathAllocated;
     574                        rc = RTUtf16ToUtf8Ex(pwszSrc, cwcSrc, &pszDst, cbPathAsUtf8 + 1, &cchActual);
     575                        AssertRC(rc);
     576                        AssertStmt(RT_FAILURE(rc) || cchActual == cbPathAsUtf8, rc = VERR_INTERNAL_ERROR_4);
     577                        Assert(strlen(pszDst) == cbPathAsUtf8);
     578                    }
     579
     580                    if (RT_SUCCESS(rc))
     581                    {
     582                        /* Terminate the string. */
     583                        pchGuestPathAllocated[cbPathAsUtf8] = '\0';
     584
     585                        cbGuestPath = cbPathAsUtf8;
     586                        pchGuestPath = pchGuestPathAllocated;
     587                    }
     588                }
     589                else
     590                {
     591                    rc = VERR_NO_MEMORY;
     592                }
     593            }
     594            else
     595            {
     596                AssertFailed();
     597                rc = VERR_INTERNAL_ERROR_3;
     598            }
     599
     600#ifdef RT_OS_DARWIN
     601            RTMemFree(pwszSrc);
     602#endif
     603        }
     604    }
     605
     606    char *pszFullPath = NULL;
     607
     608    if (RT_SUCCESS(rc))
     609    {
     610        LogFlowFunc(("Root %s path %.*s\n", pszRoot, cbGuestPath, pchGuestPath));
     611
     612        /*
     613         * Allocate enough memory to build the host full path from the root and the relative path.
     614         */
     615        uint32_t cbFullPathAlloc = cbRootLen + 1 + cbGuestPath + 1; /* root + possible_slash + relative + 0 */
     616        pszFullPath = (char *)RTMemAlloc(cbFullPathAlloc);
    501617        if (RT_LIKELY(pszFullPath != NULL))
    502618        {
    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;
     619            /* Copy the root. */
     620            memcpy(pszFullPath, pszRoot, cbRootLen);
     621            if (!RTPATH_IS_SLASH(pszFullPath[cbRootLen - 1]))
     622            {
     623                pszFullPath[cbRootLen++] = RTPATH_SLASH;
     624            }
     625
     626            /* Init the pointer for the relative path. */
     627            char *pchDst = &pszFullPath[cbRootLen];
     628
     629            uint32_t cbSrc = cbGuestPath;
     630            const char *pchSrc = pchGuestPath;
     631
     632            /* Strip leading delimiters from the path the guest specified. */
     633            while (   cbSrc > 0
     634                   && *pchSrc == pClient->PathDelimiter)
     635            {
     636                ++pchSrc;
     637                --cbSrc;
     638            }
     639
     640            /*
     641             * Iterate the guest path components, verify each of them
     642             * and append to the host full path replacing delimiters with host slash.
     643             */
     644            bool fLastComponentHasWildcard = false;
     645            for (; cbSrc > 0; --cbSrc, ++pchSrc)
     646            {
     647                if (RT_LIKELY(*pchSrc != pClient->PathDelimiter))
     648                {
     649                    if (RT_LIKELY(vbsfPathIsValidNameChar(*pchSrc)))
     650                    {
     651                        if (pfu32PathFlags && vbsfPathIsWildcardChar(*pchSrc))
     652                        {
     653                            fLastComponentHasWildcard = true;
     654                        }
     655
     656                        *pchDst++ = *pchSrc;
     657                    }
     658                    else
     659                    {
     660                        rc = VERR_INVALID_NAME;
     661                        break;
     662                    }
     663                }
     664                else
     665                {
     666                    /* Replace with the host slash. */
     667                    *pchDst++ = RTPATH_SLASH;
     668
     669                    if (pfu32PathFlags && fLastComponentHasWildcard && cbSrc > 1)
     670                    {
     671                        /* Processed component has a wildcard and there are more characters in the path. */
     672                        *pfu32PathFlags |= VBSF_F_PATH_HAS_WILDCARD_IN_PREFIX;
     673                    }
     674                    fLastComponentHasWildcard = false;
     675                }
     676            }
     677
     678            if (RT_SUCCESS(rc))
     679            {
     680                const size_t cbFullPathLength = pchDst - &pszFullPath[0]; /* As strlen(pszFullPath). */
     681
     682                *pchDst++ = 0;
     683
     684                if (pfu32PathFlags && fLastComponentHasWildcard)
     685                {
     686                    *pfu32PathFlags |= VBSF_F_PATH_HAS_WILDCARD_IN_LAST;
     687                }
     688
     689                /* Check the appended path for root escapes. */
     690                rc = vbsfPathCheckRootEscape(&pszFullPath[cbRootLen]);
     691                if (RT_SUCCESS(rc))
     692                {
     693                    /*
     694                     * When the host file system is case sensitive and the guest expects
     695                     * a case insensitive fs, then problems can occur.
     696                     */
     697                    if (    vbsfIsHostMappingCaseSensitive(hRoot)
     698                        && !vbsfIsGuestMappingCaseSensitive(hRoot))
     699                    {
     700                        rc = vbsfCorrectPathCasing(pClient, pszFullPath, cbFullPathLength, fWildCard, fPreserveLastComponent);
     701                    }
     702
     703                    if (RT_SUCCESS(rc))
     704                    {
     705                       LogFunc(("%s\n", pszFullPath));
     706
     707                       /* Return the full host path. */
     708                       *ppszHostPath = pszFullPath;
     709
     710                       if (pcbHostPathRoot)
     711                       {
     712                           *pcbHostPathRoot = cbRootLen - 1; /* Must index the path delimiter. */
     713                       }
     714                    }
     715                }
     716            }
    516717        }
    517718        else
    518719        {
    519             Log(("RTMemAlloc %x failed!!\n", cchFullPath + 1));
    520720            rc = VERR_NO_MEMORY;
    521721        }
    522722    }
    523     else /* Client speaks UTF-16. */
    524     {
    525 #ifdef RT_OS_DARWIN /* Misplaced hack! See todo! */
    526 /** @todo This belongs in rtPathToNative or in the windows shared folder file system driver...
    527  * The question is simply whether the NFD normalization is actually applied on a (virtual) file
    528  * system level in darwin, or just by the user mode application libs. */
    529         SHFLSTRING *pPathParameter = pPath;
    530         size_t cbPathLength;
    531         CFMutableStringRef inStr = ::CFStringCreateMutable(NULL, 0);
    532         uint16_t ucs2Length;
    533         CFRange rangeCharacters;
    534 
    535         // Is 8 times length enough for decomposed in worst case...?
    536         cbPathLength = sizeof(SHFLSTRING) + pPathParameter->u16Length * 8 + 2;
    537         pPath = (SHFLSTRING *)RTMemAllocZ(cbPathLength);
    538         if (!pPath)
    539         {
    540             rc = VERR_NO_MEMORY;
    541             Log(("RTMemAllocZ %x failed!!\n", cbPathLength));
    542             return rc;
    543         }
    544 
    545         ::CFStringAppendCharacters(inStr, (UniChar*)pPathParameter->String.ucs2,
    546                                    pPathParameter->u16Length / sizeof(pPathParameter->String.ucs2[0]));
    547         ::CFStringNormalize(inStr, kCFStringNormalizationFormD);
    548         ucs2Length = ::CFStringGetLength(inStr);
    549 
    550         rangeCharacters.location = 0;
    551         rangeCharacters.length = ucs2Length;
    552         ::CFStringGetCharacters(inStr, rangeCharacters, pPath->String.ucs2);
    553         pPath->String.ucs2[ucs2Length] = 0x0000; // NULL terminated
    554         pPath->u16Length = ucs2Length * sizeof(pPath->String.ucs2[0]);
    555         pPath->u16Size = pPath->u16Length + sizeof(pPath->String.ucs2[0]);
    556 
    557         CFRelease(inStr);
    558 #endif
    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
    579 
    580         /* Allocate buffer that will be able to contain the root prefix and
    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));
    614             rc = VERR_NO_MEMORY;
    615         }
    616 
    617 #ifdef RT_OS_DARWIN
    618         RTMemFree(pPath);
    619         pPath = pPathParameter;
    620 #endif
    621     }
     723
     724    /*
     725     * Cleanup.
     726     */
     727    RTMemFree(pchGuestPathAllocated);
     728
    622729    if (RT_SUCCESS(rc))
    623730    {
    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;
     731        return rc;
     732    }
     733
     734    /*
     735     * Cleanup on failure.
     736     */
     737    RTMemFree(pszFullPath);
     738
    678739    return rc;
    679740}
    680741
    681 static void vbsfFreeFullPath(char *pszFullPath)
    682 {
    683     RTMemFree(pszFullPath);
    684 }
    685 
    686 /**
    687  * Convert shared folder create flags (see include/iprt/shflsvc.h) into iprt create flags.
    688  *
    689  * @returns iprt status code
    690  * @param  fShflFlags shared folder create flags
    691  * @param  fMode      file attributes
    692  * @retval pfOpen     iprt create flags
    693  */
    694 static int vbsfConvertFileOpenFlags(unsigned fShflFlags, RTFMODE fMode, SHFLHANDLE handleInitial, uint32_t *pfOpen)
    695 {
    696     uint32_t fOpen = 0;
    697     int rc = VINF_SUCCESS;
    698 
    699     if (   (fMode & RTFS_DOS_MASK) != 0
    700         && (fMode & RTFS_UNIX_MASK) == 0)
    701     {
    702         /* A DOS/Windows guest, make RTFS_UNIX_* from RTFS_DOS_*.
    703          * @todo this is based on rtFsModeNormalize/rtFsModeFromDos.
    704          *       May be better to use RTFsModeNormalize here.
    705          */
    706         fMode |= RTFS_UNIX_IRUSR | RTFS_UNIX_IRGRP | RTFS_UNIX_IROTH;
    707         /* x for directories. */
    708         if (fMode & RTFS_DOS_DIRECTORY)
    709             fMode |= RTFS_TYPE_DIRECTORY | RTFS_UNIX_IXUSR | RTFS_UNIX_IXGRP | RTFS_UNIX_IXOTH;
    710         /* writable? */
    711         if (!(fMode & RTFS_DOS_READONLY))
    712             fMode |= RTFS_UNIX_IWUSR | RTFS_UNIX_IWGRP | RTFS_UNIX_IWOTH;
    713 
    714         /* Set the requested mode using only allowed bits. */
    715         fOpen |= ((fMode & RTFS_UNIX_MASK) << RTFILE_O_CREATE_MODE_SHIFT) & RTFILE_O_CREATE_MODE_MASK;
    716     }
    717     else
    718     {
    719         /* Old linux and solaris additions did not initialize the Info.Attr.fMode field
    720          * and it contained random bits from stack. Detect this using the handle field value
    721          * passed from the guest: old additions set it (incorrectly) to 0, new additions
    722          * set it to SHFL_HANDLE_NIL(~0).
    723          */
    724         if (handleInitial == 0)
    725         {
    726             /* Old additions. Do nothing, use default mode. */
    727         }
    728         else
    729         {
    730             /* New additions or Windows additions. Set the requested mode using only allowed bits.
    731              * Note: Windows guest set RTFS_UNIX_MASK bits to 0, which means a default mode
    732              *       will be set in fOpen.
    733              */
    734             fOpen |= ((fMode & RTFS_UNIX_MASK) << RTFILE_O_CREATE_MODE_SHIFT) & RTFILE_O_CREATE_MODE_MASK;
    735         }
    736     }
    737 
    738     switch (BIT_FLAG(fShflFlags, SHFL_CF_ACCESS_MASK_RW))
    739     {
    740         default:
    741         case SHFL_CF_ACCESS_NONE:
    742         {
    743             /** @todo treat this as read access, but theoretically this could be a no access request. */
    744             fOpen |= RTFILE_O_READ;
    745             Log(("FLAG: SHFL_CF_ACCESS_NONE\n"));
    746             break;
    747         }
    748 
    749         case SHFL_CF_ACCESS_READ:
    750         {
    751             fOpen |= RTFILE_O_READ;
    752             Log(("FLAG: SHFL_CF_ACCESS_READ\n"));
    753             break;
    754         }
    755 
    756         case SHFL_CF_ACCESS_WRITE:
    757         {
    758             fOpen |= RTFILE_O_WRITE;
    759             Log(("FLAG: SHFL_CF_ACCESS_WRITE\n"));
    760             break;
    761         }
    762 
    763         case SHFL_CF_ACCESS_READWRITE:
    764         {
    765             fOpen |= RTFILE_O_READWRITE;
    766             Log(("FLAG: SHFL_CF_ACCESS_READWRITE\n"));
    767             break;
    768         }
    769     }
    770 
    771     if (fShflFlags & SHFL_CF_ACCESS_APPEND)
    772     {
    773         fOpen |= RTFILE_O_APPEND;
    774     }
    775 
    776     switch (BIT_FLAG(fShflFlags, SHFL_CF_ACCESS_MASK_ATTR))
    777     {
    778         default:
    779         case SHFL_CF_ACCESS_ATTR_NONE:
    780         {
    781             fOpen |= RTFILE_O_ACCESS_ATTR_DEFAULT;
    782             Log(("FLAG: SHFL_CF_ACCESS_ATTR_NONE\n"));
    783             break;
    784         }
    785 
    786         case SHFL_CF_ACCESS_ATTR_READ:
    787         {
    788             fOpen |= RTFILE_O_ACCESS_ATTR_READ;
    789             Log(("FLAG: SHFL_CF_ACCESS_ATTR_READ\n"));
    790             break;
    791         }
    792 
    793         case SHFL_CF_ACCESS_ATTR_WRITE:
    794         {
    795             fOpen |= RTFILE_O_ACCESS_ATTR_WRITE;
    796             Log(("FLAG: SHFL_CF_ACCESS_ATTR_WRITE\n"));
    797             break;
    798         }
    799 
    800         case SHFL_CF_ACCESS_ATTR_READWRITE:
    801         {
    802             fOpen |= RTFILE_O_ACCESS_ATTR_READWRITE;
    803             Log(("FLAG: SHFL_CF_ACCESS_ATTR_READWRITE\n"));
    804             break;
    805         }
    806     }
    807 
    808     /* Sharing mask */
    809     switch (BIT_FLAG(fShflFlags, SHFL_CF_ACCESS_MASK_DENY))
    810     {
    811     default:
    812     case SHFL_CF_ACCESS_DENYNONE:
    813         fOpen |= RTFILE_O_DENY_NONE;
    814         Log(("FLAG: SHFL_CF_ACCESS_DENYNONE\n"));
    815         break;
    816 
    817     case SHFL_CF_ACCESS_DENYREAD:
    818         fOpen |= RTFILE_O_DENY_READ;
    819         Log(("FLAG: SHFL_CF_ACCESS_DENYREAD\n"));
    820         break;
    821 
    822     case SHFL_CF_ACCESS_DENYWRITE:
    823         fOpen |= RTFILE_O_DENY_WRITE;
    824         Log(("FLAG: SHFL_CF_ACCESS_DENYWRITE\n"));
    825         break;
    826 
    827     case SHFL_CF_ACCESS_DENYALL:
    828         fOpen |= RTFILE_O_DENY_ALL;
    829         Log(("FLAG: SHFL_CF_ACCESS_DENYALL\n"));
    830         break;
    831     }
    832 
    833     /* Open/Create action mask */
    834     switch (BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_EXISTS))
    835     {
    836     case SHFL_CF_ACT_OPEN_IF_EXISTS:
    837         if (SHFL_CF_ACT_CREATE_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
    838         {
    839             fOpen |= RTFILE_O_OPEN_CREATE;
    840             Log(("FLAGS: SHFL_CF_ACT_OPEN_IF_EXISTS and SHFL_CF_ACT_CREATE_IF_NEW\n"));
    841         }
    842         else if (SHFL_CF_ACT_FAIL_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
    843         {
    844             fOpen |= RTFILE_O_OPEN;
    845             Log(("FLAGS: SHFL_CF_ACT_OPEN_IF_EXISTS and SHFL_CF_ACT_FAIL_IF_NEW\n"));
    846         }
    847         else
    848         {
    849             Log(("FLAGS: invalid open/create action combination\n"));
    850             rc = VERR_INVALID_PARAMETER;
    851         }
    852         break;
    853     case SHFL_CF_ACT_FAIL_IF_EXISTS:
    854         if (SHFL_CF_ACT_CREATE_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
    855         {
    856             fOpen |= RTFILE_O_CREATE;
    857             Log(("FLAGS: SHFL_CF_ACT_FAIL_IF_EXISTS and SHFL_CF_ACT_CREATE_IF_NEW\n"));
    858         }
    859         else
    860         {
    861             Log(("FLAGS: invalid open/create action combination\n"));
    862             rc = VERR_INVALID_PARAMETER;
    863         }
    864         break;
    865     case SHFL_CF_ACT_REPLACE_IF_EXISTS:
    866         if (SHFL_CF_ACT_CREATE_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
    867         {
    868             fOpen |= RTFILE_O_CREATE_REPLACE;
    869             Log(("FLAGS: SHFL_CF_ACT_REPLACE_IF_EXISTS and SHFL_CF_ACT_CREATE_IF_NEW\n"));
    870         }
    871         else if (SHFL_CF_ACT_FAIL_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
    872         {
    873             fOpen |= RTFILE_O_OPEN | RTFILE_O_TRUNCATE;
    874             Log(("FLAGS: SHFL_CF_ACT_REPLACE_IF_EXISTS and SHFL_CF_ACT_FAIL_IF_NEW\n"));
    875         }
    876         else
    877         {
    878             Log(("FLAGS: invalid open/create action combination\n"));
    879             rc = VERR_INVALID_PARAMETER;
    880         }
    881         break;
    882     case SHFL_CF_ACT_OVERWRITE_IF_EXISTS:
    883         if (SHFL_CF_ACT_CREATE_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
    884         {
    885             fOpen |= RTFILE_O_CREATE_REPLACE;
    886             Log(("FLAGS: SHFL_CF_ACT_OVERWRITE_IF_EXISTS and SHFL_CF_ACT_CREATE_IF_NEW\n"));
    887         }
    888         else if (SHFL_CF_ACT_FAIL_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
    889         {
    890             fOpen |= RTFILE_O_OPEN | RTFILE_O_TRUNCATE;
    891             Log(("FLAGS: SHFL_CF_ACT_OVERWRITE_IF_EXISTS and SHFL_CF_ACT_FAIL_IF_NEW\n"));
    892         }
    893         else
    894         {
    895             Log(("FLAGS: invalid open/create action combination\n"));
    896             rc = VERR_INVALID_PARAMETER;
    897         }
    898         break;
    899     default:
    900         rc = VERR_INVALID_PARAMETER;
    901         Log(("FLAG: SHFL_CF_ACT_MASK_IF_EXISTS - invalid parameter\n"));
    902     }
    903 
    904     if (RT_SUCCESS(rc))
    905     {
    906         *pfOpen = fOpen;
    907     }
    908     return rc;
    909 }
    910 
    911 /**
    912  * Open a file or create and open a new one.
    913  *
    914  * @returns IPRT status code
    915  * @param  pClient               Data structure describing the client accessing the shared folder
    916  * @param  pszPath               Path to the file or folder on the host.
    917  * @param  pParms->CreateFlags   Creation or open parameters, see include/VBox/shflsvc.h
    918  * @param  pParms->Info          When a new file is created this specifies the initial parameters.
    919  *                               When a file is created or overwritten, it also specifies the
    920  *                               initial size.
    921  * @retval pParms->Result        Shared folder status code, see include/VBox/shflsvc.h
    922  * @retval pParms->Handle        On success the (shared folder) handle of the file opened or
    923  *                               created
    924  * @retval pParms->Info          On success the parameters of the file opened or created
    925  */
    926 static int vbsfOpenFile(SHFLCLIENTDATA *pClient, const char *pszPath, SHFLCREATEPARMS *pParms)
    927 {
    928     LogFlow(("vbsfOpenFile: pszPath = %s, pParms = %p\n", pszPath, pParms));
    929     Log(("SHFL create flags %08x\n", pParms->CreateFlags));
    930 
    931     SHFLHANDLE      handle = SHFL_HANDLE_NIL;
    932     SHFLFILEHANDLE *pHandle = 0;
    933     /* Open or create a file. */
    934     uint32_t fOpen = 0;
    935     bool fNoError = false;
    936     static int cErrors;
    937 
    938     int rc = vbsfConvertFileOpenFlags(pParms->CreateFlags, pParms->Info.Attr.fMode, pParms->Handle, &fOpen);
    939     if (RT_SUCCESS(rc))
    940     {
    941         rc = VERR_NO_MEMORY;  /* Default error. */
    942         handle  = vbsfAllocFileHandle(pClient);
    943         if (handle != SHFL_HANDLE_NIL)
    944         {
    945             pHandle = vbsfQueryFileHandle(pClient, handle);
    946             if (pHandle)
    947             {
    948                 rc = RTFileOpen(&pHandle->file.Handle, pszPath, fOpen);
    949             }
    950         }
    951     }
    952     if (RT_FAILURE(rc))
    953     {
    954         switch (rc)
    955         {
    956         case VERR_FILE_NOT_FOUND:
    957             pParms->Result = SHFL_FILE_NOT_FOUND;
    958 
    959             /* This actually isn't an error, so correct the rc before return later,
    960                because the driver (VBoxSF.sys) expects rc = VINF_SUCCESS and checks the result code. */
    961             fNoError = true;
    962             break;
    963         case VERR_PATH_NOT_FOUND:
    964             pParms->Result = SHFL_PATH_NOT_FOUND;
    965 
    966             /* This actually isn't an error, so correct the rc before return later,
    967                because the driver (VBoxSF.sys) expects rc = VINF_SUCCESS and checks the result code. */
    968             fNoError = true;
    969             break;
    970         case VERR_ALREADY_EXISTS:
    971             RTFSOBJINFO info;
    972 
    973             /** @todo Possible race left here. */
    974             if (RT_SUCCESS(RTPathQueryInfoEx(pszPath, &info, RTFSOBJATTRADD_NOTHING, SHFL_RT_LINK(pClient))))
    975             {
    976 #ifdef RT_OS_WINDOWS
    977                 info.Attr.fMode |= 0111;
    978 #endif
    979                 vbfsCopyFsObjInfoFromIprt(&pParms->Info, &info);
    980             }
    981             pParms->Result = SHFL_FILE_EXISTS;
    982 
    983             /* This actually isn't an error, so correct the rc before return later,
    984                because the driver (VBoxSF.sys) expects rc = VINF_SUCCESS and checks the result code. */
    985             fNoError = true;
    986             break;
    987         case VERR_TOO_MANY_OPEN_FILES:
    988             if (cErrors < 32)
    989             {
    990                 LogRel(("SharedFolders host service: Cannot open '%s' -- too many open files.\n", pszPath));
    991 #if defined RT_OS_LINUX || RT_OS_SOLARIS
    992                 if (cErrors < 1)
    993                     LogRel(("SharedFolders host service: Try to increase the limit for open files (ulimit -n)\n"));
    994 #endif
    995                 cErrors++;
    996             }
    997             pParms->Result = SHFL_NO_RESULT;
    998             break;
    999         default:
    1000             pParms->Result = SHFL_NO_RESULT;
    1001         }
    1002     }
    1003     else
    1004     {
    1005         /** @note The shared folder status code is very approximate, as the runtime
    1006           *       does not really provide this information. */
    1007         pParms->Result = SHFL_FILE_EXISTS;  /* We lost the information as to whether it was
    1008                                                created when we eliminated the race. */
    1009         if (   (   SHFL_CF_ACT_REPLACE_IF_EXISTS
    1010                 == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_EXISTS))
    1011             || (   SHFL_CF_ACT_OVERWRITE_IF_EXISTS
    1012                 == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_EXISTS)))
    1013         {
    1014             /* For now, we do not treat a failure here as fatal. */
    1015             /* @todo Also set the size for SHFL_CF_ACT_CREATE_IF_NEW if
    1016                      SHFL_CF_ACT_FAIL_IF_EXISTS is set. */
    1017             RTFileSetSize(pHandle->file.Handle, pParms->Info.cbObject);
    1018             pParms->Result = SHFL_FILE_REPLACED;
    1019         }
    1020         if (   (   SHFL_CF_ACT_FAIL_IF_EXISTS
    1021                 == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_EXISTS))
    1022             || (   SHFL_CF_ACT_CREATE_IF_NEW
    1023                 == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_NEW)))
    1024         {
    1025             pParms->Result = SHFL_FILE_CREATED;
    1026         }
    1027 #if 0
    1028         /* @todo */
    1029         /* Set new attributes. */
    1030         if (   (   SHFL_CF_ACT_REPLACE_IF_EXISTS
    1031                 == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_EXISTS))
    1032             || (   SHFL_CF_ACT_CREATE_IF_NEW
    1033                 == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_NEW)))
    1034         {
    1035             RTFileSetTimes(pHandle->file.Handle,
    1036                           &pParms->Info.AccessTime,
    1037                           &pParms->Info.ModificationTime,
    1038                           &pParms->Info.ChangeTime,
    1039                           &pParms->Info.BirthTime
    1040                           );
    1041 
    1042             RTFileSetMode (pHandle->file.Handle, pParms->Info.Attr.fMode);
    1043         }
    1044 #endif
    1045         RTFSOBJINFO info;
    1046 
    1047         /* Get file information */
    1048         rc = RTFileQueryInfo(pHandle->file.Handle, &info, RTFSOBJATTRADD_NOTHING);
    1049         if (RT_SUCCESS(rc))
    1050         {
    1051 #ifdef RT_OS_WINDOWS
    1052             info.Attr.fMode |= 0111;
    1053 #endif
    1054             vbfsCopyFsObjInfoFromIprt(&pParms->Info, &info);
    1055         }
    1056     }
    1057     /* Free resources if any part of the function has failed. */
    1058     if (RT_FAILURE(rc))
    1059     {
    1060         if (   (0 != pHandle)
    1061             && (NIL_RTFILE != pHandle->file.Handle)
    1062             && (0 != pHandle->file.Handle))
    1063         {
    1064             RTFileClose(pHandle->file.Handle);
    1065             pHandle->file.Handle = NIL_RTFILE;
    1066         }
    1067         if (SHFL_HANDLE_NIL != handle)
    1068         {
    1069             vbsfFreeFileHandle(pClient, handle);
    1070         }
    1071         pParms->Handle = SHFL_HANDLE_NIL;
    1072     }
    1073     else
    1074     {
    1075         pParms->Handle = handle;
    1076     }
    1077 
    1078     /* Report the driver that all is okay, we're done here */
    1079     if (fNoError)
    1080         rc = VINF_SUCCESS;
    1081 
    1082     LogFlow(("vbsfOpenFile: rc = %Rrc\n", rc));
    1083     return rc;
    1084 }
    1085 
    1086 /**
    1087  * Open a folder or create and open a new one.
    1088  *
    1089  * @returns IPRT status code
    1090  * @param  pszPath               Path to the file or folder on the host.
    1091  * @param  pParms->CreateFlags   Creation or open parameters, see include/VBox/shflsvc.h
    1092  * @retval pParms->Result        Shared folder status code, see include/VBox/shflsvc.h
    1093  * @retval pParms->Handle        On success the (shared folder) handle of the folder opened or
    1094  *                               created
    1095  * @retval pParms->Info          On success the parameters of the folder opened or created
    1096  *
    1097  * @note folders are created with fMode = 0777
    1098  */
    1099 static int vbsfOpenDir(SHFLCLIENTDATA *pClient, const char *pszPath,
    1100                        SHFLCREATEPARMS *pParms)
    1101 {
    1102     LogFlow(("vbsfOpenDir: pszPath = %s, pParms = %p\n", pszPath, pParms));
    1103     Log(("SHFL create flags %08x\n", pParms->CreateFlags));
    1104 
    1105     int rc = VERR_NO_MEMORY;
    1106     SHFLHANDLE      handle = vbsfAllocDirHandle(pClient);
    1107     SHFLFILEHANDLE *pHandle = vbsfQueryDirHandle(pClient, handle);
    1108     if (0 != pHandle)
    1109     {
    1110         rc = VINF_SUCCESS;
    1111         pParms->Result = SHFL_FILE_EXISTS;  /* May be overwritten with SHFL_FILE_CREATED. */
    1112         /** @todo Can anyone think of a sensible, race-less way to do this?  Although
    1113                   I suspect that the race is inherent, due to the API available... */
    1114         /* Try to create the folder first if "create if new" is specified.  If this
    1115            fails, and "open if exists" is specified, then we ignore the failure and try
    1116            to open the folder anyway. */
    1117         if (   SHFL_CF_ACT_CREATE_IF_NEW
    1118             == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_NEW))
    1119         {
    1120             /** @todo render supplied attributes.
    1121             * bird: The guest should specify this. For windows guests RTFS_DOS_DIRECTORY should suffice. */
    1122             RTFMODE fMode = 0777;
    1123 
    1124             pParms->Result = SHFL_FILE_CREATED;
    1125             rc = RTDirCreate(pszPath, fMode, 0);
    1126             if (RT_FAILURE(rc))
    1127             {
    1128                 switch (rc)
    1129                 {
    1130                 case VERR_ALREADY_EXISTS:
    1131                     pParms->Result = SHFL_FILE_EXISTS;
    1132                     break;
    1133                 case VERR_PATH_NOT_FOUND:
    1134                     pParms->Result = SHFL_PATH_NOT_FOUND;
    1135                     break;
    1136                 default:
    1137                     pParms->Result = SHFL_NO_RESULT;
    1138                 }
    1139             }
    1140         }
    1141         if (   RT_SUCCESS(rc)
    1142             || (SHFL_CF_ACT_OPEN_IF_EXISTS == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_EXISTS)))
    1143         {
    1144             /* Open the directory now */
    1145             rc = RTDirOpenFiltered(&pHandle->dir.Handle, pszPath, RTDIRFILTER_NONE, 0);
    1146             if (RT_SUCCESS(rc))
    1147             {
    1148                 RTFSOBJINFO info;
    1149 
    1150                 rc = RTDirQueryInfo(pHandle->dir.Handle, &info, RTFSOBJATTRADD_NOTHING);
    1151                 if (RT_SUCCESS(rc))
    1152                 {
    1153                     vbfsCopyFsObjInfoFromIprt(&pParms->Info, &info);
    1154                 }
    1155             }
    1156             else
    1157             {
    1158                 switch (rc)
    1159                 {
    1160                 case VERR_FILE_NOT_FOUND:  /* Does this make sense? */
    1161                     pParms->Result = SHFL_FILE_NOT_FOUND;
    1162                     break;
    1163                 case VERR_PATH_NOT_FOUND:
    1164                     pParms->Result = SHFL_PATH_NOT_FOUND;
    1165                     break;
    1166                 case VERR_ACCESS_DENIED:
    1167                     pParms->Result = SHFL_FILE_EXISTS;
    1168                     break;
    1169                 default:
    1170                     pParms->Result = SHFL_NO_RESULT;
    1171                 }
    1172             }
    1173         }
    1174     }
    1175     if (RT_FAILURE(rc))
    1176     {
    1177         if (   (0 != pHandle)
    1178             && (0 != pHandle->dir.Handle))
    1179         {
    1180             RTDirClose(pHandle->dir.Handle);
    1181             pHandle->dir.Handle = 0;
    1182         }
    1183         if (SHFL_HANDLE_NIL != handle)
    1184         {
    1185             vbsfFreeFileHandle(pClient, handle);
    1186         }
    1187         pParms->Handle = SHFL_HANDLE_NIL;
    1188     }
    1189     else
    1190     {
    1191         pParms->Handle = handle;
    1192     }
    1193     LogFlow(("vbsfOpenDir: rc = %Rrc\n", rc));
    1194     return rc;
    1195 }
    1196 
    1197 static int vbsfCloseDir(SHFLFILEHANDLE *pHandle)
    1198 {
    1199     int rc = VINF_SUCCESS;
    1200 
    1201     LogFlow(("vbsfCloseDir: Handle = %08X Search Handle = %08X\n",
    1202              pHandle->dir.Handle, pHandle->dir.SearchHandle));
    1203 
    1204     RTDirClose(pHandle->dir.Handle);
    1205 
    1206     if (pHandle->dir.SearchHandle)
    1207         RTDirClose(pHandle->dir.SearchHandle);
    1208 
    1209     if (pHandle->dir.pLastValidEntry)
    1210     {
    1211         RTMemFree(pHandle->dir.pLastValidEntry);
    1212         pHandle->dir.pLastValidEntry = NULL;
    1213     }
    1214 
    1215     LogFlow(("vbsfCloseDir: rc = %d\n", rc));
    1216 
    1217     return rc;
    1218 }
    1219 
    1220 
    1221 static int vbsfCloseFile(SHFLFILEHANDLE *pHandle)
    1222 {
    1223     int rc = VINF_SUCCESS;
    1224 
    1225     LogFlow(("vbsfCloseFile: Handle = %08X\n",
    1226              pHandle->file.Handle));
    1227 
    1228     rc = RTFileClose(pHandle->file.Handle);
    1229 
    1230     LogFlow(("vbsfCloseFile: rc = %d\n", rc));
    1231 
    1232     return rc;
    1233 }
    1234 
    1235 /**
    1236  * Look up file or folder information by host path.
    1237  *
    1238  * @returns iprt status code (currently VINF_SUCCESS)
    1239  * @param   pszFullPath    The path of the file to be looked up
    1240  * @retval  pParms->Result Status of the operation (success or error)
    1241  * @retval  pParms->Info   On success, information returned about the file
    1242  */
    1243 static int vbsfLookupFile(SHFLCLIENTDATA *pClient, char *pszPath, SHFLCREATEPARMS *pParms)
    1244 {
    1245     RTFSOBJINFO info;
    1246     int rc;
    1247 
    1248     rc = RTPathQueryInfoEx(pszPath, &info, RTFSOBJATTRADD_NOTHING, SHFL_RT_LINK(pClient));
    1249     LogFlow(("SHFL_CF_LOOKUP\n"));
    1250     /* Client just wants to know if the object exists. */
    1251     switch (rc)
    1252     {
    1253         case VINF_SUCCESS:
    1254         {
    1255 #ifdef RT_OS_WINDOWS
    1256             info.Attr.fMode |= 0111;
    1257 #endif
    1258             vbfsCopyFsObjInfoFromIprt(&pParms->Info, &info);
    1259             pParms->Result = SHFL_FILE_EXISTS;
    1260             break;
    1261         }
    1262 
    1263         case VERR_FILE_NOT_FOUND:
    1264         {
    1265             pParms->Result = SHFL_FILE_NOT_FOUND;
    1266             rc = VINF_SUCCESS;
    1267             break;
    1268         }
    1269 
    1270         case VERR_PATH_NOT_FOUND:
    1271         {
    1272             pParms->Result = SHFL_PATH_NOT_FOUND;
    1273             rc = VINF_SUCCESS;
    1274             break;
    1275         }
    1276     }
    1277     pParms->Handle = SHFL_HANDLE_NIL;
    1278     return rc;
    1279 }
    1280 
    1281 #ifdef UNITTEST
    1282 /** Unit test the SHFL_FN_CREATE API.  Located here as a form of API
    1283  * documentation. */
    1284 void testCreate(RTTEST hTest)
    1285 {
    1286     /* Simple opening of an existing file. */
    1287     testCreateFileSimple(hTest);
    1288     /* Simple opening of an existing directory. */
    1289     /** @todo How do wildcards in the path name work? */
    1290     testCreateDirSimple(hTest);
    1291     /* If the number or types of parameters are wrong the API should fail. */
    1292     testCreateBadParameters(hTest);
    1293     /* Add tests as required... */
    1294 }
    1295 #endif
    1296 /**
    1297  * Create or open a file or folder.  Perform character set and case
    1298  * conversion on the file name if necessary.
    1299  *
    1300  * @returns IPRT status code, but see note below
    1301  * @param   pClient        Data structure describing the client accessing the shared
    1302  *                         folder
    1303  * @param   root           The index of the shared folder in the table of mappings.
    1304  *                         The host path of the shared folder is found using this.
    1305  * @param   pPath          The path of the file or folder relative to the host path
    1306  *                         indexed by root.
    1307  * @param   cbPath         Presumably the length of the path in pPath.  Actually
    1308  *                         ignored, as pPath contains a length parameter.
    1309  * @param   pParms->Info   If a new file is created or an old one overwritten, set
    1310  *                         these attributes
    1311  * @retval  pParms->Result Shared folder result code, see include/VBox/shflsvc.h
    1312  * @retval  pParms->Handle Shared folder handle to the newly opened file
    1313  * @retval  pParms->Info   Attributes of the file or folder opened
    1314  *
    1315  * @note This function returns success if a "non-exceptional" error occurred,
    1316  *       such as "no such file".  In this case, the caller should check the
    1317  *       pParms->Result return value and whether pParms->Handle is valid.
    1318  */
    1319 int vbsfCreate(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLSTRING *pPath, uint32_t cbPath, SHFLCREATEPARMS *pParms)
    1320 {
    1321     int rc = VINF_SUCCESS;
    1322 
    1323     LogFlow(("vbsfCreate: pClient = %p, pPath = %p, cbPath = %d, pParms = %p CreateFlags=%x\n",
    1324              pClient, pPath, cbPath, pParms, pParms->CreateFlags));
    1325 
    1326     /* Check the client access rights to the root. */
    1327     /** @todo */
    1328 
    1329     /* Build a host full path for the given path, handle file name case issues (if the guest
    1330      * expects case-insensitive paths but the host is case-sensitive) and convert ucs2 to utf8 if
    1331      * necessary.
    1332      */
    1333     char *pszFullPath = NULL;
    1334     uint32_t cbFullPathRoot = 0;
    1335 
    1336     rc = vbsfBuildFullPath(pClient, root, pPath, cbPath, &pszFullPath, &cbFullPathRoot);
    1337     if (RT_SUCCESS(rc))
    1338     {
    1339         /* Reset return value in case client forgot to do so.
    1340          * pParms->Handle must not be reset here, as it is used
    1341          * in vbsfOpenFile to detect old additions.
    1342          */
    1343         pParms->Result = SHFL_NO_RESULT;
    1344 
    1345         if (BIT_FLAG(pParms->CreateFlags, SHFL_CF_LOOKUP))
    1346         {
    1347             rc = vbsfLookupFile(pClient, pszFullPath, pParms);
    1348         }
    1349         else
    1350         {
    1351             /* Query path information. */
    1352             RTFSOBJINFO info;
    1353 
    1354             rc = RTPathQueryInfoEx(pszFullPath, &info, RTFSOBJATTRADD_NOTHING, SHFL_RT_LINK(pClient));
    1355             LogFlow(("RTPathQueryInfoEx returned %Rrc\n", rc));
    1356 
    1357             if (RT_SUCCESS(rc))
    1358             {
    1359                 /* Mark it as a directory in case the caller didn't. */
    1360                 /**
    1361                   * @todo I left this in in order not to change the behaviour of the
    1362                   *       function too much.  Is it really needed, and should it really be
    1363                   *       here?
    1364                   */
    1365                 if (BIT_FLAG(info.Attr.fMode, RTFS_DOS_DIRECTORY))
    1366                 {
    1367                     pParms->CreateFlags |= SHFL_CF_DIRECTORY;
    1368                 }
    1369 
    1370                 /**
    1371                   * @todo This should be in the Windows Guest Additions, as no-one else
    1372                   *       needs it.
    1373                   */
    1374                 if (BIT_FLAG(pParms->CreateFlags, SHFL_CF_OPEN_TARGET_DIRECTORY))
    1375                 {
    1376                     vbsfStripLastComponent(pszFullPath, cbFullPathRoot);
    1377                     pParms->CreateFlags &= ~SHFL_CF_ACT_MASK_IF_EXISTS;
    1378                     pParms->CreateFlags &= ~SHFL_CF_ACT_MASK_IF_NEW;
    1379                     pParms->CreateFlags |= SHFL_CF_DIRECTORY;
    1380                     pParms->CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS;
    1381                     pParms->CreateFlags |= SHFL_CF_ACT_FAIL_IF_NEW;
    1382                 }
    1383             }
    1384 
    1385             rc = VINF_SUCCESS;
    1386 
    1387             /* Note: do not check the SHFL_CF_ACCESS_WRITE here, only check if the open operation
    1388              * will cause changes.
    1389              *
    1390              * Actual operations (write, set attr, etc), which can write to a shared folder, have
    1391              * the check and will return VERR_WRITE_PROTECT if the folder is not writable.
    1392              */
    1393             if (   (pParms->CreateFlags & SHFL_CF_ACT_MASK_IF_EXISTS) == SHFL_CF_ACT_REPLACE_IF_EXISTS
    1394                 || (pParms->CreateFlags & SHFL_CF_ACT_MASK_IF_EXISTS) == SHFL_CF_ACT_OVERWRITE_IF_EXISTS
    1395                 || (pParms->CreateFlags & SHFL_CF_ACT_MASK_IF_NEW) == SHFL_CF_ACT_CREATE_IF_NEW
    1396                )
    1397             {
    1398                 /* is the guest allowed to write to this share? */
    1399                 bool fWritable;
    1400                 rc = vbsfMappingsQueryWritable(pClient, root, &fWritable);
    1401                 if (RT_FAILURE(rc) || !fWritable)
    1402                     rc = VERR_WRITE_PROTECT;
    1403             }
    1404 
    1405             if (RT_SUCCESS(rc))
    1406             {
    1407                 if (BIT_FLAG(pParms->CreateFlags, SHFL_CF_DIRECTORY))
    1408                 {
    1409                     rc = vbsfOpenDir(pClient, pszFullPath, pParms);
    1410                 }
    1411                 else
    1412                 {
    1413                     rc = vbsfOpenFile(pClient, pszFullPath, pParms);
    1414                 }
    1415             }
    1416             else
    1417             {
    1418                 pParms->Handle = SHFL_HANDLE_NIL;
    1419             }
    1420         }
    1421 
    1422         /* free the path string */
    1423         vbsfFreeFullPath(pszFullPath);
    1424     }
    1425 
    1426     Log(("vbsfCreate: handle = %RX64 rc = %Rrc result=%x\n", (uint64_t)pParms->Handle, rc, pParms->Result));
    1427 
    1428     return rc;
    1429 }
    1430 
    1431 #ifdef UNITTEST
    1432 /** Unit test the SHFL_FN_CLOSE API.  Located here as a form of API
    1433  * documentation. */
    1434 void testClose(RTTEST hTest)
    1435 {
    1436     /* If the API parameters are invalid the API should fail. */
    1437     testCloseBadParameters(hTest);
    1438     /* Add tests as required... */
    1439 }
    1440 #endif
    1441 int vbsfClose(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle)
    1442 {
    1443     int rc = VINF_SUCCESS;
    1444 
    1445     LogFlow(("vbsfClose: pClient = %p, Handle = %RX64\n",
    1446              pClient, Handle));
    1447 
    1448     uint32_t type = vbsfQueryHandleType(pClient, Handle);
    1449     Assert((type & ~(SHFL_HF_TYPE_DIR | SHFL_HF_TYPE_FILE)) == 0);
    1450 
    1451     switch (type & (SHFL_HF_TYPE_DIR | SHFL_HF_TYPE_FILE))
    1452     {
    1453         case SHFL_HF_TYPE_DIR:
    1454         {
    1455             rc = vbsfCloseDir(vbsfQueryDirHandle(pClient, Handle));
    1456             break;
    1457         }
    1458         case SHFL_HF_TYPE_FILE:
    1459         {
    1460             rc = vbsfCloseFile(vbsfQueryFileHandle(pClient, Handle));
    1461             break;
    1462         }
    1463         default:
    1464             return VERR_INVALID_HANDLE;
    1465     }
    1466     vbsfFreeFileHandle(pClient, Handle);
    1467 
    1468     Log(("vbsfClose: rc = %Rrc\n", rc));
    1469 
    1470     return rc;
    1471 }
    1472 
    1473 #ifdef UNITTEST
    1474 /** Unit test the SHFL_FN_READ API.  Located here as a form of API
    1475  * documentation. */
    1476 void testRead(RTTEST hTest)
    1477 {
    1478     /* If the number or types of parameters are wrong the API should fail. */
    1479     testReadBadParameters(hTest);
    1480     /* Basic reading from a file. */
    1481     testReadFileSimple(hTest);
    1482     /* Add tests as required... */
    1483 }
    1484 #endif
    1485 int vbsfRead  (SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint64_t offset, uint32_t *pcbBuffer, uint8_t *pBuffer)
    1486 {
    1487     SHFLFILEHANDLE *pHandle = vbsfQueryFileHandle(pClient, Handle);
    1488     size_t count = 0;
    1489     int rc;
    1490 
    1491     if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0)
    1492     {
    1493         AssertFailed();
    1494         return VERR_INVALID_PARAMETER;
    1495     }
    1496 
    1497     Log(("vbsfRead %RX64 offset %RX64 bytes %x\n", Handle, offset, *pcbBuffer));
    1498 
    1499     if (*pcbBuffer == 0)
    1500         return VINF_SUCCESS; /* @todo correct? */
    1501 
    1502 
    1503     rc = RTFileSeek(pHandle->file.Handle, offset, RTFILE_SEEK_BEGIN, NULL);
    1504     if (rc != VINF_SUCCESS)
    1505     {
    1506         AssertRC(rc);
    1507         return rc;
    1508     }
    1509 
    1510     rc = RTFileRead(pHandle->file.Handle, pBuffer, *pcbBuffer, &count);
    1511     *pcbBuffer = (uint32_t)count;
    1512     Log(("RTFileRead returned %Rrc bytes read %x\n", rc, count));
    1513     return rc;
    1514 }
    1515 
    1516 #ifdef UNITTEST
    1517 /** Unit test the SHFL_FN_WRITE API.  Located here as a form of API
    1518  * documentation. */
    1519 void testWrite(RTTEST hTest)
    1520 {
    1521     /* If the number or types of parameters are wrong the API should fail. */
    1522     testWriteBadParameters(hTest);
    1523     /* Simple test of writing to a file. */
    1524     testWriteFileSimple(hTest);
    1525     /* Add tests as required... */
    1526 }
    1527 #endif
    1528 int vbsfWrite(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint64_t offset, uint32_t *pcbBuffer, uint8_t *pBuffer)
    1529 {
    1530     SHFLFILEHANDLE *pHandle = vbsfQueryFileHandle(pClient, Handle);
    1531     size_t count = 0;
    1532     int rc;
    1533 
    1534     if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0)
    1535     {
    1536         AssertFailed();
    1537         return VERR_INVALID_PARAMETER;
    1538     }
    1539 
    1540     Log(("vbsfWrite %RX64 offset %RX64 bytes %x\n", Handle, offset, *pcbBuffer));
    1541 
    1542     /* Is the guest allowed to write to this share?
    1543      * XXX Actually this check was still done in vbsfCreate() -- RTFILE_O_WRITE cannot be set if vbsfMappingsQueryWritable() failed. */
    1544     bool fWritable;
    1545     rc = vbsfMappingsQueryWritable(pClient, root, &fWritable);
    1546     if (RT_FAILURE(rc) || !fWritable)
    1547         return VERR_WRITE_PROTECT;
    1548 
    1549     if (*pcbBuffer == 0)
    1550         return VINF_SUCCESS; /** @todo correct? */
    1551 
    1552     rc = RTFileSeek(pHandle->file.Handle, offset, RTFILE_SEEK_BEGIN, NULL);
    1553     if (rc != VINF_SUCCESS)
    1554     {
    1555         AssertRC(rc);
    1556         return rc;
    1557     }
    1558 
    1559     rc = RTFileWrite(pHandle->file.Handle, pBuffer, *pcbBuffer, &count);
    1560     *pcbBuffer = (uint32_t)count;
    1561     Log(("RTFileWrite returned %Rrc bytes written %x\n", rc, count));
    1562     return rc;
    1563 }
    1564 
    1565 
    1566 #ifdef UNITTEST
    1567 /** Unit test the SHFL_FN_FLUSH API.  Located here as a form of API
    1568  * documentation. */
    1569 void testFlush(RTTEST hTest)
    1570 {
    1571     /* If the number or types of parameters are wrong the API should fail. */
    1572     testFlushBadParameters(hTest);
    1573     /* Simple opening and flushing of a file. */
    1574     testFlushFileSimple(hTest);
    1575     /* Add tests as required... */
    1576 }
    1577 #endif
    1578 int vbsfFlush(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle)
    1579 {
    1580     SHFLFILEHANDLE *pHandle = vbsfQueryFileHandle(pClient, Handle);
    1581     int rc = VINF_SUCCESS;
    1582 
    1583     if (pHandle == 0)
    1584     {
    1585         AssertFailed();
    1586         return VERR_INVALID_HANDLE;
    1587     }
    1588 
    1589     Log(("vbsfFlush %RX64\n", Handle));
    1590     rc = RTFileFlush(pHandle->file.Handle);
    1591     AssertRC(rc);
    1592     return rc;
    1593 }
    1594 
    1595 #ifdef UNITTEST
    1596 /** Unit test the SHFL_FN_LIST API.  Located here as a form of API
    1597  * documentation. */
    1598 void testDirList(RTTEST hTest)
    1599 {
    1600     /* If the number or types of parameters are wrong the API should fail. */
    1601     testDirListBadParameters(hTest);
    1602     /* Test listing an empty directory (simple edge case). */
    1603     testDirListEmpty(hTest);
    1604     /* Add tests as required... */
    1605 }
    1606 #endif
    1607 int vbsfDirList(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, SHFLSTRING *pPath, uint32_t flags,
    1608                 uint32_t *pcbBuffer, uint8_t *pBuffer, uint32_t *pIndex, uint32_t *pcFiles)
    1609 {
    1610     SHFLFILEHANDLE *pHandle = vbsfQueryDirHandle(pClient, Handle);
    1611     PRTDIRENTRYEX  pDirEntry = 0, pDirEntryOrg;
    1612     uint32_t       cbDirEntry, cbBufferOrg;
    1613     int            rc = VINF_SUCCESS;
    1614     PSHFLDIRINFO   pSFDEntry;
    1615     PRTUTF16       pwszString;
    1616     PRTDIR         DirHandle;
    1617     bool           fUtf8;
    1618 
    1619     fUtf8 = BIT_FLAG(pClient->fu32Flags, SHFL_CF_UTF8) != 0;
    1620 
    1621     if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0)
    1622     {
    1623         AssertFailed();
    1624         return VERR_INVALID_PARAMETER;
    1625     }
    1626     Assert(pIndex && *pIndex == 0);
    1627     DirHandle = pHandle->dir.Handle;
    1628 
    1629     cbDirEntry = 4096;
    1630     pDirEntryOrg = pDirEntry  = (PRTDIRENTRYEX)RTMemAlloc(cbDirEntry);
    1631     if (pDirEntry == 0)
    1632     {
    1633         AssertFailed();
    1634         return VERR_NO_MEMORY;
    1635     }
    1636 
    1637     cbBufferOrg = *pcbBuffer;
    1638     *pcbBuffer  = 0;
    1639     pSFDEntry   = (PSHFLDIRINFO)pBuffer;
    1640 
    1641     *pIndex = 1; /* not yet complete */
    1642     *pcFiles = 0;
    1643 
    1644     if (pPath)
    1645     {
    1646         if (pHandle->dir.SearchHandle == 0)
    1647         {
    1648             /* Build a host full path for the given path
    1649              * and convert ucs2 to utf8 if necessary.
    1650              */
    1651             char *pszFullPath = NULL;
    1652 
    1653             Assert(pHandle->dir.pLastValidEntry == 0);
    1654 
    1655             rc = vbsfBuildFullPath(pClient, root, pPath, pPath->u16Size, &pszFullPath, NULL, true);
    1656 
    1657             if (RT_SUCCESS(rc))
    1658             {
    1659                 rc = RTDirOpenFiltered(&pHandle->dir.SearchHandle, pszFullPath, RTDIRFILTER_WINNT, 0);
    1660 
    1661                 /* free the path string */
    1662                 vbsfFreeFullPath(pszFullPath);
    1663 
    1664                 if (RT_FAILURE(rc))
    1665                     goto end;
    1666             }
    1667             else
    1668                 goto end;
    1669         }
    1670         Assert(pHandle->dir.SearchHandle);
    1671         DirHandle = pHandle->dir.SearchHandle;
    1672     }
    1673 
    1674     while (cbBufferOrg)
    1675     {
    1676         size_t cbDirEntrySize = cbDirEntry;
    1677         uint32_t cbNeeded;
    1678 
    1679         /* Do we still have a valid last entry for the active search? If so, then return it here */
    1680         if (pHandle->dir.pLastValidEntry)
    1681         {
    1682             pDirEntry = pHandle->dir.pLastValidEntry;
    1683         }
    1684         else
    1685         {
    1686             pDirEntry = pDirEntryOrg;
    1687 
    1688             rc = RTDirReadEx(DirHandle, pDirEntry, &cbDirEntrySize, RTFSOBJATTRADD_NOTHING, SHFL_RT_LINK(pClient));
    1689             if (rc == VERR_NO_MORE_FILES)
    1690             {
    1691                 *pIndex = 0; /* listing completed */
    1692                 break;
    1693             }
    1694 
    1695             if (   rc != VINF_SUCCESS
    1696                 && rc != VWRN_NO_DIRENT_INFO)
    1697             {
    1698                 //AssertFailed();
    1699                 if (   rc == VERR_NO_TRANSLATION
    1700                     || rc == VERR_INVALID_UTF8_ENCODING)
    1701                     continue;
    1702                 break;
    1703             }
    1704         }
    1705 
    1706         cbNeeded = RT_OFFSETOF(SHFLDIRINFO, name.String);
    1707         if (fUtf8)
    1708             cbNeeded += pDirEntry->cbName + 1;
    1709         else
    1710             /* Overestimating, but that's ok */
    1711             cbNeeded += (pDirEntry->cbName + 1) * 2;
    1712 
    1713         if (cbBufferOrg < cbNeeded)
    1714         {
    1715             /* No room, so save this directory entry, or else it's lost forever */
    1716             pHandle->dir.pLastValidEntry = pDirEntry;
    1717 
    1718             if (*pcFiles == 0)
    1719             {
    1720                 AssertFailed();
    1721                 return VINF_BUFFER_OVERFLOW;    /* Return directly and don't free pDirEntry */
    1722             }
    1723             return VINF_SUCCESS;    /* Return directly and don't free pDirEntry */
    1724         }
    1725 
    1726 #ifdef RT_OS_WINDOWS
    1727         pDirEntry->Info.Attr.fMode |= 0111;
    1728 #endif
    1729         vbfsCopyFsObjInfoFromIprt(&pSFDEntry->Info, &pDirEntry->Info);
    1730         pSFDEntry->cucShortName = 0;
    1731 
    1732         if (fUtf8)
    1733         {
    1734             void *src, *dst;
    1735 
    1736             src = &pDirEntry->szName[0];
    1737             dst = &pSFDEntry->name.String.utf8[0];
    1738 
    1739             memcpy(dst, src, pDirEntry->cbName + 1);
    1740 
    1741             pSFDEntry->name.u16Size = pDirEntry->cbName + 1;
    1742             pSFDEntry->name.u16Length = pDirEntry->cbName;
    1743         }
    1744         else
    1745         {
    1746             pSFDEntry->name.String.ucs2[0] = 0;
    1747             pwszString = pSFDEntry->name.String.ucs2;
    1748             int rc2 = RTStrToUtf16Ex(pDirEntry->szName, RTSTR_MAX, &pwszString, pDirEntry->cbName+1, NULL);
    1749             AssertRC(rc2);
    1750 
    1751 #ifdef RT_OS_DARWIN
    1752 /** @todo This belongs in rtPathToNative or in the windows shared folder file system driver...
    1753  * The question is simply whether the NFD normalization is actually applied on a (virtual) file
    1754  * system level in darwin, or just by the user mode application libs. */
    1755             {
    1756                 // Convert to
    1757                 // Normalization Form C (composed Unicode). We need this because
    1758                 // Mac OS X file system uses NFD (Normalization Form D :decomposed Unicode)
    1759                 // while most other OS', server-side programs usually expect NFC.
    1760                 uint16_t ucs2Length;
    1761                 CFRange rangeCharacters;
    1762                 CFMutableStringRef inStr = ::CFStringCreateMutable(NULL, 0);
    1763 
    1764                 ::CFStringAppendCharacters(inStr, (UniChar *)pwszString, RTUtf16Len(pwszString));
    1765                 ::CFStringNormalize(inStr, kCFStringNormalizationFormC);
    1766                 ucs2Length = ::CFStringGetLength(inStr);
    1767 
    1768                 rangeCharacters.location = 0;
    1769                 rangeCharacters.length = ucs2Length;
    1770                 ::CFStringGetCharacters(inStr, rangeCharacters, pwszString);
    1771                 pwszString[ucs2Length] = 0x0000; // NULL terminated
    1772 
    1773                 CFRelease(inStr);
    1774             }
    1775 #endif
    1776             pSFDEntry->name.u16Length = (uint32_t)RTUtf16Len(pSFDEntry->name.String.ucs2) * 2;
    1777             pSFDEntry->name.u16Size = pSFDEntry->name.u16Length + 2;
    1778 
    1779             Log(("SHFL: File name size %d\n", pSFDEntry->name.u16Size));
    1780             Log(("SHFL: File name %ls\n", &pSFDEntry->name.String.ucs2));
    1781 
    1782             // adjust cbNeeded (it was overestimated before)
    1783             cbNeeded = RT_OFFSETOF(SHFLDIRINFO, name.String) + pSFDEntry->name.u16Size;
    1784         }
    1785 
    1786         pSFDEntry   = (PSHFLDIRINFO)((uintptr_t)pSFDEntry + cbNeeded);
    1787         *pcbBuffer += cbNeeded;
    1788         cbBufferOrg-= cbNeeded;
    1789 
    1790         *pcFiles   += 1;
    1791 
    1792         /* Free the saved last entry, that we've just returned */
    1793         if (pHandle->dir.pLastValidEntry)
    1794         {
    1795             RTMemFree(pHandle->dir.pLastValidEntry);
    1796             pHandle->dir.pLastValidEntry = NULL;
    1797         }
    1798 
    1799         if (flags & SHFL_LIST_RETURN_ONE)
    1800             break; /* we're done */
    1801     }
    1802     Assert(rc != VINF_SUCCESS || *pcbBuffer > 0);
    1803 
    1804 end:
    1805     if (pDirEntry)
    1806         RTMemFree(pDirEntry);
    1807 
    1808     return rc;
    1809 }
    1810 
    1811 #ifdef UNITTEST
    1812 /** Unit test the SHFL_FN_READLINK API.  Located here as a form of API
    1813  * documentation. */
    1814 void testReadLink(RTTEST hTest)
    1815 {
    1816     /* If the number or types of parameters are wrong the API should fail. */
    1817     testReadLinkBadParameters(hTest);
    1818     /* Add tests as required... */
    1819 }
    1820 #endif
    1821 int vbsfReadLink(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLSTRING *pPath, uint32_t cbPath, uint8_t *pBuffer, uint32_t cbBuffer)
    1822 {
    1823     int rc = VINF_SUCCESS;
    1824 
    1825     if (pPath == 0 || pBuffer == 0)
    1826     {
    1827         AssertFailed();
    1828         return VERR_INVALID_PARAMETER;
    1829     }
    1830 
    1831     /* Build a host full path for the given path, handle file name case issues
    1832      * (if the guest expects case-insensitive paths but the host is
    1833      * case-sensitive) and convert ucs2 to utf8 if necessary.
    1834      */
    1835     char *pszFullPath = NULL;
    1836     uint32_t cbFullPathRoot = 0;
    1837 
    1838     rc = vbsfBuildFullPath(pClient, root, pPath, cbPath, &pszFullPath, &cbFullPathRoot);
    1839 
    1840     if (RT_SUCCESS(rc))
    1841     {
    1842         rc = RTSymlinkRead(pszFullPath, (char *) pBuffer, cbBuffer, 0);
    1843 
    1844         /* free the path string */
    1845         vbsfFreeFullPath(pszFullPath);
    1846     }
    1847 
    1848     return rc;
    1849 }
    1850 
    1851 int vbsfQueryFileInfo(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
    1852 {
    1853     uint32_t type = vbsfQueryHandleType(pClient, Handle);
    1854     int            rc = VINF_SUCCESS;
    1855     SHFLFSOBJINFO   *pObjInfo = (SHFLFSOBJINFO *)pBuffer;
    1856     RTFSOBJINFO    fileinfo;
    1857 
    1858 
    1859     if (   !(type == SHFL_HF_TYPE_DIR || type == SHFL_HF_TYPE_FILE)
    1860         || pcbBuffer == 0
    1861         || pObjInfo == 0
    1862         || *pcbBuffer < sizeof(SHFLFSOBJINFO))
    1863     {
    1864         AssertFailed();
    1865         return VERR_INVALID_PARAMETER;
    1866     }
    1867 
    1868     /* @todo other options */
    1869     Assert(flags == (SHFL_INFO_GET|SHFL_INFO_FILE));
    1870 
    1871     *pcbBuffer  = 0;
    1872 
    1873     if (type == SHFL_HF_TYPE_DIR)
    1874     {
    1875         SHFLFILEHANDLE *pHandle = vbsfQueryDirHandle(pClient, Handle);
    1876         rc = RTDirQueryInfo(pHandle->dir.Handle, &fileinfo, RTFSOBJATTRADD_NOTHING);
    1877     }
    1878     else
    1879     {
    1880         SHFLFILEHANDLE *pHandle = vbsfQueryFileHandle(pClient, Handle);
    1881         rc = RTFileQueryInfo(pHandle->file.Handle, &fileinfo, RTFSOBJATTRADD_NOTHING);
    1882 #ifdef RT_OS_WINDOWS
    1883         if (RT_SUCCESS(rc) && RTFS_IS_FILE(pObjInfo->Attr.fMode))
    1884             pObjInfo->Attr.fMode |= 0111;
    1885 #endif
    1886     }
    1887     if (rc == VINF_SUCCESS)
    1888     {
    1889         vbfsCopyFsObjInfoFromIprt(pObjInfo, &fileinfo);
    1890         *pcbBuffer = sizeof(SHFLFSOBJINFO);
    1891     }
    1892     else
    1893         AssertFailed();
    1894 
    1895     return rc;
    1896 }
    1897 
    1898 static int vbsfSetFileInfo(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
    1899 {
    1900     uint32_t type = vbsfQueryHandleType(pClient, Handle);
    1901     int             rc = VINF_SUCCESS;
    1902     SHFLFSOBJINFO  *pSFDEntry;
    1903 
    1904     if (   !(type == SHFL_HF_TYPE_DIR || type == SHFL_HF_TYPE_FILE)
    1905         || pcbBuffer == 0
    1906         || pBuffer == 0
    1907         || *pcbBuffer < sizeof(SHFLFSOBJINFO))
    1908     {
    1909         AssertFailed();
    1910         return VERR_INVALID_PARAMETER;
    1911     }
    1912 
    1913     *pcbBuffer  = 0;
    1914     pSFDEntry   = (SHFLFSOBJINFO *)pBuffer;
    1915 
    1916     Assert(flags == (SHFL_INFO_SET | SHFL_INFO_FILE));
    1917 
    1918     /* Change only the time values that are not zero */
    1919     if (type == SHFL_HF_TYPE_DIR)
    1920     {
    1921         SHFLFILEHANDLE *pHandle = vbsfQueryDirHandle(pClient, Handle);
    1922         rc = RTDirSetTimes(pHandle->dir.Handle,
    1923                             (RTTimeSpecGetNano(&pSFDEntry->AccessTime)) ?       &pSFDEntry->AccessTime : NULL,
    1924                             (RTTimeSpecGetNano(&pSFDEntry->ModificationTime)) ? &pSFDEntry->ModificationTime: NULL,
    1925                             (RTTimeSpecGetNano(&pSFDEntry->ChangeTime)) ?       &pSFDEntry->ChangeTime: NULL,
    1926                             (RTTimeSpecGetNano(&pSFDEntry->BirthTime)) ?        &pSFDEntry->BirthTime: NULL
    1927                             );
    1928     }
    1929     else
    1930     {
    1931         SHFLFILEHANDLE *pHandle = vbsfQueryFileHandle(pClient, Handle);
    1932         rc = RTFileSetTimes(pHandle->file.Handle,
    1933                             (RTTimeSpecGetNano(&pSFDEntry->AccessTime)) ?       &pSFDEntry->AccessTime : NULL,
    1934                             (RTTimeSpecGetNano(&pSFDEntry->ModificationTime)) ? &pSFDEntry->ModificationTime: NULL,
    1935                             (RTTimeSpecGetNano(&pSFDEntry->ChangeTime)) ?       &pSFDEntry->ChangeTime: NULL,
    1936                             (RTTimeSpecGetNano(&pSFDEntry->BirthTime)) ?        &pSFDEntry->BirthTime: NULL
    1937                             );
    1938     }
    1939     if (rc != VINF_SUCCESS)
    1940     {
    1941         Log(("RTFileSetTimes failed with %Rrc\n", rc));
    1942         Log(("AccessTime       %RX64\n", RTTimeSpecGetNano(&pSFDEntry->AccessTime)));
    1943         Log(("ModificationTime %RX64\n", RTTimeSpecGetNano(&pSFDEntry->ModificationTime)));
    1944         Log(("ChangeTime       %RX64\n", RTTimeSpecGetNano(&pSFDEntry->ChangeTime)));
    1945         Log(("BirthTime        %RX64\n", RTTimeSpecGetNano(&pSFDEntry->BirthTime)));
    1946         /* temporary hack */
    1947         rc = VINF_SUCCESS;
    1948     }
    1949 
    1950     if (type == SHFL_HF_TYPE_FILE)
    1951     {
    1952         SHFLFILEHANDLE *pHandle = vbsfQueryFileHandle(pClient, Handle);
    1953         /* Change file attributes if necessary */
    1954         if (pSFDEntry->Attr.fMode)
    1955         {
    1956             RTFMODE fMode = pSFDEntry->Attr.fMode;
    1957 
    1958 #ifndef RT_OS_WINDOWS
    1959             /* Don't allow the guest to clear the own bit, otherwise the guest wouldn't be
    1960              * able to access this file anymore. Only for guests, which set the UNIX mode. */
    1961             if (fMode & RTFS_UNIX_MASK)
    1962                 fMode |= RTFS_UNIX_IRUSR;
    1963 #endif
    1964 
    1965             rc = RTFileSetMode(pHandle->file.Handle, fMode);
    1966             if (rc != VINF_SUCCESS)
    1967             {
    1968                 Log(("RTFileSetMode %x failed with %Rrc\n", fMode, rc));
    1969                 /* silent failure, because this tends to fail with e.g. windows guest & linux host */
    1970                 rc = VINF_SUCCESS;
    1971             }
    1972         }
    1973     }
    1974     /* TODO: mode for directories */
    1975 
    1976     if (rc == VINF_SUCCESS)
    1977     {
    1978         uint32_t bufsize = sizeof(*pSFDEntry);
    1979 
    1980         rc = vbsfQueryFileInfo(pClient, root, Handle, SHFL_INFO_GET|SHFL_INFO_FILE, &bufsize, (uint8_t *)pSFDEntry);
    1981         if (rc == VINF_SUCCESS)
    1982         {
    1983             *pcbBuffer = sizeof(SHFLFSOBJINFO);
    1984         }
    1985         else
    1986             AssertFailed();
    1987     }
    1988 
    1989     return rc;
    1990 }
    1991 
    1992 
    1993 static int vbsfSetEndOfFile(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
    1994 {
    1995     SHFLFILEHANDLE *pHandle = vbsfQueryFileHandle(pClient, Handle);
    1996     int             rc = VINF_SUCCESS;
    1997     SHFLFSOBJINFO  *pSFDEntry;
    1998 
    1999     if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0 || *pcbBuffer < sizeof(SHFLFSOBJINFO))
    2000     {
    2001         AssertFailed();
    2002         return VERR_INVALID_PARAMETER;
    2003     }
    2004 
    2005     *pcbBuffer  = 0;
    2006     pSFDEntry   = (SHFLFSOBJINFO *)pBuffer;
    2007 
    2008     if (flags & SHFL_INFO_SIZE)
    2009     {
    2010         rc = RTFileSetSize(pHandle->file.Handle, pSFDEntry->cbObject);
    2011         if (rc != VINF_SUCCESS)
    2012             AssertFailed();
    2013     }
    2014     else
    2015         AssertFailed();
    2016 
    2017     if (rc == VINF_SUCCESS)
    2018     {
    2019         RTFSOBJINFO fileinfo;
    2020 
    2021         /* Query the new object info and return it */
    2022         rc = RTFileQueryInfo(pHandle->file.Handle, &fileinfo, RTFSOBJATTRADD_NOTHING);
    2023         if (rc == VINF_SUCCESS)
    2024         {
    2025 #ifdef RT_OS_WINDOWS
    2026             fileinfo.Attr.fMode |= 0111;
    2027 #endif
    2028             vbfsCopyFsObjInfoFromIprt(pSFDEntry, &fileinfo);
    2029             *pcbBuffer = sizeof(SHFLFSOBJINFO);
    2030         }
    2031         else
    2032             AssertFailed();
    2033     }
    2034 
    2035     return rc;
    2036 }
    2037 
    2038 int vbsfQueryVolumeInfo(SHFLCLIENTDATA *pClient, SHFLROOT root, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
    2039 {
    2040     int            rc = VINF_SUCCESS;
    2041     SHFLVOLINFO   *pSFDEntry;
    2042     char          *pszFullPath = NULL;
    2043     SHFLSTRING     dummy;
    2044 
    2045     if (pcbBuffer == 0 || pBuffer == 0 || *pcbBuffer < sizeof(SHFLVOLINFO))
    2046     {
    2047         AssertFailed();
    2048         return VERR_INVALID_PARAMETER;
    2049     }
    2050 
    2051     /* @todo other options */
    2052     Assert(flags == (SHFL_INFO_GET|SHFL_INFO_VOLUME));
    2053 
    2054     *pcbBuffer  = 0;
    2055     pSFDEntry   = (PSHFLVOLINFO)pBuffer;
    2056 
    2057     ShflStringInitBuffer(&dummy, sizeof(dummy));
    2058     dummy.String.ucs2[0] = '\0';
    2059     rc = vbsfBuildFullPath(pClient, root, &dummy, 0, &pszFullPath, NULL);
    2060 
    2061     if (RT_SUCCESS(rc))
    2062     {
    2063         rc = RTFsQuerySizes(pszFullPath, &pSFDEntry->ullTotalAllocationBytes, &pSFDEntry->ullAvailableAllocationBytes, &pSFDEntry->ulBytesPerAllocationUnit, &pSFDEntry->ulBytesPerSector);
    2064         if (rc != VINF_SUCCESS)
    2065             goto exit;
    2066 
    2067         rc = RTFsQuerySerial(pszFullPath, &pSFDEntry->ulSerial);
    2068         if (rc != VINF_SUCCESS)
    2069             goto exit;
    2070 
    2071         RTFSPROPERTIES FsProperties;
    2072         rc = RTFsQueryProperties(pszFullPath, &FsProperties);
    2073         if (rc != VINF_SUCCESS)
    2074             goto exit;
    2075         vbfsCopyFsPropertiesFromIprt(&pSFDEntry->fsProperties, &FsProperties);
    2076 
    2077         *pcbBuffer = sizeof(SHFLVOLINFO);
    2078     }
    2079     else AssertFailed();
    2080 
    2081 exit:
    2082     AssertMsg(rc == VINF_SUCCESS, ("failure: rc = %Rrc\n", rc));
    2083     /* free the path string */
    2084     vbsfFreeFullPath(pszFullPath);
    2085     return rc;
    2086 }
    2087 
    2088 int vbsfQueryFSInfo(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
    2089 {
    2090     if (pcbBuffer == 0 || pBuffer == 0)
    2091     {
    2092         AssertFailed();
    2093         return VERR_INVALID_PARAMETER;
    2094     }
    2095 
    2096     if (flags & SHFL_INFO_FILE)
    2097         return vbsfQueryFileInfo(pClient, root, Handle, flags, pcbBuffer, pBuffer);
    2098 
    2099     if (flags & SHFL_INFO_VOLUME)
    2100         return vbsfQueryVolumeInfo(pClient, root, flags, pcbBuffer, pBuffer);
    2101 
    2102     AssertFailed();
    2103     return VERR_INVALID_PARAMETER;
    2104 }
    2105 
    2106 #ifdef UNITTEST
    2107 /** Unit test the SHFL_FN_INFORMATION API.  Located here as a form of API
    2108  * documentation. */
    2109 void testFSInfo(RTTEST hTest)
    2110 {
    2111     /* If the number or types of parameters are wrong the API should fail. */
    2112     testFSInfoBadParameters(hTest);
    2113     /* Basic get and set file size test. */
    2114     testFSInfoQuerySetFMode(hTest);
    2115     /* Basic get and set dir atime test. */
    2116     testFSInfoQuerySetDirATime(hTest);
    2117     /* Basic get and set file atime test. */
    2118     testFSInfoQuerySetFileATime(hTest);
    2119     /* Basic set end of file. */
    2120     testFSInfoQuerySetEndOfFile(hTest);
    2121     /* Add tests as required... */
    2122 }
    2123 #endif
    2124 int vbsfSetFSInfo(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
    2125 {
    2126     uint32_t type =   vbsfQueryHandleType(pClient, Handle)
    2127                     & (SHFL_HF_TYPE_DIR|SHFL_HF_TYPE_FILE|SHFL_HF_TYPE_VOLUME);
    2128 
    2129     if (type == 0 || pcbBuffer == 0 || pBuffer == 0)
    2130     {
    2131         AssertFailed();
    2132         return VERR_INVALID_PARAMETER;
    2133     }
    2134 
    2135     /* is the guest allowed to write to this share? */
    2136     bool fWritable;
    2137     int rc = vbsfMappingsQueryWritable(pClient, root, &fWritable);
    2138     if (RT_FAILURE(rc) || !fWritable)
    2139         return VERR_WRITE_PROTECT;
    2140 
    2141     if (flags & SHFL_INFO_FILE)
    2142         return vbsfSetFileInfo(pClient, root, Handle, flags, pcbBuffer, pBuffer);
    2143 
    2144     if (flags & SHFL_INFO_SIZE)
    2145         return vbsfSetEndOfFile(pClient, root, Handle, flags, pcbBuffer, pBuffer);
    2146 
    2147 //    if (flags & SHFL_INFO_VOLUME)
    2148 //        return vbsfVolumeInfo(pClient, root, Handle, flags, pcbBuffer, pBuffer);
    2149     AssertFailed();
    2150     return VERR_INVALID_PARAMETER;
    2151 }
    2152 
    2153 #ifdef UNITTEST
    2154 /** Unit test the SHFL_FN_LOCK API.  Located here as a form of API
    2155  * documentation. */
    2156 void testLock(RTTEST hTest)
    2157 {
    2158     /* If the number or types of parameters are wrong the API should fail. */
    2159     testLockBadParameters(hTest);
    2160     /* Simple file locking and unlocking test. */
    2161     testLockFileSimple(hTest);
    2162     /* Add tests as required... */
    2163 }
    2164 #endif
    2165 int vbsfLock(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint64_t offset, uint64_t length, uint32_t flags)
    2166 {
    2167     SHFLFILEHANDLE *pHandle = vbsfQueryFileHandle(pClient, Handle);
    2168     uint32_t        fRTLock = 0;
    2169     int             rc;
    2170 
    2171     Assert((flags & SHFL_LOCK_MODE_MASK) != SHFL_LOCK_CANCEL);
    2172 
    2173     if (pHandle == 0)
    2174     {
    2175         AssertFailed();
    2176         return VERR_INVALID_HANDLE;
    2177     }
    2178     if (   ((flags & SHFL_LOCK_MODE_MASK) == SHFL_LOCK_CANCEL)
    2179         || (flags & SHFL_LOCK_ENTIRE)
    2180        )
    2181     {
    2182         AssertFailed();
    2183         return VERR_INVALID_PARAMETER;
    2184     }
    2185 
    2186     /* Lock type */
    2187     switch(flags & SHFL_LOCK_MODE_MASK)
    2188     {
    2189     case SHFL_LOCK_SHARED:
    2190         fRTLock = RTFILE_LOCK_READ;
    2191         break;
    2192 
    2193     case SHFL_LOCK_EXCLUSIVE:
    2194         fRTLock = RTFILE_LOCK_READ | RTFILE_LOCK_WRITE;
    2195         break;
    2196 
    2197     default:
    2198         AssertFailed();
    2199         return VERR_INVALID_PARAMETER;
    2200     }
    2201 
    2202     /* Lock wait type */
    2203     if (flags & SHFL_LOCK_WAIT)
    2204         fRTLock |= RTFILE_LOCK_WAIT;
    2205     else
    2206         fRTLock |= RTFILE_LOCK_IMMEDIATELY;
    2207 
    2208 #ifdef RT_OS_WINDOWS
    2209     rc = RTFileLock(pHandle->file.Handle, fRTLock, offset, length);
    2210     if (rc != VINF_SUCCESS)
    2211         Log(("RTFileLock %RTfile %RX64 %RX64 failed with %Rrc\n", pHandle->file.Handle, offset, length, rc));
    2212 #else
    2213     Log(("vbsfLock: Pretend success handle=%x\n", Handle));
    2214     rc = VINF_SUCCESS;
    2215 #endif
    2216     return rc;
    2217 }
    2218 
    2219 int vbsfUnlock(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint64_t offset, uint64_t length, uint32_t flags)
    2220 {
    2221     SHFLFILEHANDLE *pHandle = vbsfQueryFileHandle(pClient, Handle);
    2222     int             rc;
    2223 
    2224     Assert((flags & SHFL_LOCK_MODE_MASK) == SHFL_LOCK_CANCEL);
    2225 
    2226     if (pHandle == 0)
    2227     {
    2228         return VERR_INVALID_HANDLE;
    2229     }
    2230     if (   ((flags & SHFL_LOCK_MODE_MASK) != SHFL_LOCK_CANCEL)
    2231         || (flags & SHFL_LOCK_ENTIRE)
    2232        )
    2233     {
    2234        return VERR_INVALID_PARAMETER;
    2235     }
    2236 
    2237 #ifdef RT_OS_WINDOWS
    2238     rc = RTFileUnlock(pHandle->file.Handle, offset, length);
    2239     if (rc != VINF_SUCCESS)
    2240         Log(("RTFileUnlock %RTfile %RX64 %RTX64 failed with %Rrc\n", pHandle->file.Handle, offset, length, rc));
    2241 #else
    2242     Log(("vbsfUnlock: Pretend success handle=%x\n", Handle));
    2243     rc = VINF_SUCCESS;
    2244 #endif
    2245 
    2246     return rc;
    2247 }
    2248 
    2249 
    2250 #ifdef UNITTEST
    2251 /** Unit test the SHFL_FN_REMOVE API.  Located here as a form of API
    2252  * documentation. */
    2253 void testRemove(RTTEST hTest)
    2254 {
    2255     /* If the number or types of parameters are wrong the API should fail. */
    2256     testRemoveBadParameters(hTest);
    2257     /* Add tests as required... */
    2258 }
    2259 #endif
    2260 int vbsfRemove(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLSTRING *pPath, uint32_t cbPath, uint32_t flags)
    2261 {
    2262     int rc = VINF_SUCCESS;
    2263 
    2264     /* Validate input */
    2265     if (   flags & ~(SHFL_REMOVE_FILE|SHFL_REMOVE_DIR|SHFL_REMOVE_SYMLINK)
    2266         || cbPath == 0
    2267         || pPath == 0)
    2268     {
    2269         AssertFailed();
    2270         return VERR_INVALID_PARAMETER;
    2271     }
    2272 
    2273     /* Build a host full path for the given path
    2274      * and convert ucs2 to utf8 if necessary.
    2275      */
    2276     char *pszFullPath = NULL;
    2277 
    2278     rc = vbsfBuildFullPath(pClient, root, pPath, cbPath, &pszFullPath, NULL);
    2279     if (RT_SUCCESS(rc))
    2280     {
    2281         /* is the guest allowed to write to this share? */
    2282         bool fWritable;
    2283         rc = vbsfMappingsQueryWritable(pClient, root, &fWritable);
    2284         if (RT_FAILURE(rc) || !fWritable)
    2285             rc = VERR_WRITE_PROTECT;
    2286 
    2287         if (RT_SUCCESS(rc))
    2288         {
    2289             if (flags & SHFL_REMOVE_SYMLINK)
    2290                 rc = RTSymlinkDelete(pszFullPath, 0);
    2291             else if (flags & SHFL_REMOVE_FILE)
    2292                 rc = RTFileDelete(pszFullPath);
    2293             else
    2294                 rc = RTDirRemove(pszFullPath);
    2295         }
    2296 
    2297 #ifndef DEBUG_dmik
    2298         // VERR_ACCESS_DENIED for example?
    2299         // Assert(rc == VINF_SUCCESS || rc == VERR_DIR_NOT_EMPTY);
    2300 #endif
    2301         /* free the path string */
    2302         vbsfFreeFullPath(pszFullPath);
    2303     }
    2304     return rc;
    2305 }
    2306 
    2307 
    2308 #ifdef UNITTEST
    2309 /** Unit test the SHFL_FN_RENAME API.  Located here as a form of API
    2310  * documentation. */
    2311 void testRename(RTTEST hTest)
    2312 {
    2313     /* If the number or types of parameters are wrong the API should fail. */
    2314     testRenameBadParameters(hTest);
    2315     /* Add tests as required... */
    2316 }
    2317 #endif
    2318 int vbsfRename(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLSTRING *pSrc, SHFLSTRING *pDest, uint32_t flags)
    2319 {
    2320     int rc = VINF_SUCCESS;
    2321 
    2322     /* Validate input */
    2323     if (   flags & ~(SHFL_REMOVE_FILE|SHFL_REMOVE_DIR|SHFL_RENAME_REPLACE_IF_EXISTS)
    2324         || pSrc == 0
    2325         || pDest == 0)
    2326     {
    2327         AssertFailed();
    2328         return VERR_INVALID_PARAMETER;
    2329     }
    2330 
    2331     /* Build a host full path for the given path
    2332      * and convert ucs2 to utf8 if necessary.
    2333      */
    2334     char *pszFullPathSrc = NULL;
    2335     char *pszFullPathDest = NULL;
    2336 
    2337     rc = vbsfBuildFullPath(pClient, root, pSrc, pSrc->u16Size, &pszFullPathSrc, NULL);
    2338     if (rc != VINF_SUCCESS)
    2339         return rc;
    2340 
    2341     rc = vbsfBuildFullPath(pClient, root, pDest, pDest->u16Size, &pszFullPathDest, NULL, false, true);
    2342     if (RT_SUCCESS (rc))
    2343     {
    2344         Log(("Rename %s to %s\n", pszFullPathSrc, pszFullPathDest));
    2345 
    2346         /* is the guest allowed to write to this share? */
    2347         bool fWritable;
    2348         rc = vbsfMappingsQueryWritable(pClient, root, &fWritable);
    2349         if (RT_FAILURE(rc) || !fWritable)
    2350             rc = VERR_WRITE_PROTECT;
    2351 
    2352         if (RT_SUCCESS(rc))
    2353         {
    2354             if (flags & SHFL_RENAME_FILE)
    2355             {
    2356                 rc = RTFileMove(pszFullPathSrc, pszFullPathDest,
    2357                                   ((flags & SHFL_RENAME_REPLACE_IF_EXISTS) ? RTFILEMOVE_FLAGS_REPLACE : 0));
    2358             }
    2359             else
    2360             {
    2361                 /* NT ignores the REPLACE flag and simply return and already exists error. */
    2362                 rc = RTDirRename(pszFullPathSrc, pszFullPathDest,
    2363                                    ((flags & SHFL_RENAME_REPLACE_IF_EXISTS) ? RTPATHRENAME_FLAGS_REPLACE : 0));
    2364             }
    2365         }
    2366 
    2367 #ifndef DEBUG_dmik
    2368         AssertRC(rc);
    2369 #endif
    2370         /* free the path string */
    2371         vbsfFreeFullPath(pszFullPathDest);
    2372     }
    2373     /* free the path string */
    2374     vbsfFreeFullPath(pszFullPathSrc);
    2375     return rc;
    2376 }
    2377 
    2378 #ifdef UNITTEST
    2379 /** Unit test the SHFL_FN_SYMLINK API.  Located here as a form of API
    2380  * documentation. */
    2381 void testSymlink(RTTEST hTest)
    2382 {
    2383     /* If the number or types of parameters are wrong the API should fail. */
    2384     testSymlinkBadParameters(hTest);
    2385     /* Add tests as required... */
    2386 }
    2387 #endif
    2388 int vbsfSymlink(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLSTRING *pNewPath, SHFLSTRING *pOldPath, SHFLFSOBJINFO *pInfo)
    2389 {
    2390     int rc = VINF_SUCCESS;
    2391 
    2392     char *pszFullNewPath = NULL;
    2393     const char *pszOldPath = (const char *)pOldPath->String.utf8;
    2394 
    2395     /* XXX: no support for UCS2 at the moment. */
    2396     if (!BIT_FLAG(pClient->fu32Flags, SHFL_CF_UTF8))
    2397         return VERR_NOT_IMPLEMENTED;
    2398 
    2399     bool fSymlinksCreate;
    2400     rc = vbsfMappingsQuerySymlinksCreate(pClient, root, &fSymlinksCreate);
    2401     AssertRCReturn(rc, rc);
    2402     if (!fSymlinksCreate)
    2403         return VERR_WRITE_PROTECT; /* XXX or VERR_TOO_MANY_SYMLINKS? */
    2404 
    2405     rc = vbsfBuildFullPath(pClient, root, pNewPath, pNewPath->u16Size, &pszFullNewPath, NULL);
    2406     AssertRCReturn(rc, rc);
    2407 
    2408     rc = RTSymlinkCreate(pszFullNewPath, (const char *)pOldPath->String.utf8,
    2409                          RTSYMLINKTYPE_UNKNOWN, 0);
    2410     if (RT_SUCCESS(rc))
    2411     {
    2412         RTFSOBJINFO info;
    2413         rc = RTPathQueryInfoEx(pszFullNewPath, &info, RTFSOBJATTRADD_NOTHING, SHFL_RT_LINK(pClient));
    2414         if (RT_SUCCESS(rc))
    2415             vbfsCopyFsObjInfoFromIprt(pInfo, &info);
    2416     }
    2417 
    2418     vbsfFreeFullPath(pszFullNewPath);
    2419 
    2420     return rc;
    2421 }
    2422 
    2423 /*
    2424  * Clean up our mess by freeing all handles that are still valid.
    2425  *
    2426  */
    2427 int vbsfDisconnect(SHFLCLIENTDATA *pClient)
    2428 {
    2429     for (int i=0; i<SHFLHANDLE_MAX; i++)
    2430     {
    2431         SHFLHANDLE Handle = (SHFLHANDLE)i;
    2432         if (vbsfQueryHandleType(pClient, Handle))
    2433         {
    2434             Log(("Open handle %08x\n", i));
    2435             vbsfClose(pClient, SHFL_HANDLE_ROOT /* incorrect, but it's not important */, (SHFLHANDLE)i);
    2436         }
    2437     }
    2438     return VINF_SUCCESS;
    2439 }
     742void vbsfFreeHostPath(char *pszHostPath)
     743{
     744    RTMemFree(pszHostPath);
     745}
Note: See TracChangeset for help on using the changeset viewer.

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