VirtualBox

Ignore:
Timestamp:
Dec 10, 2018 12:01:34 PM (6 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
127349
Message:

os2/VBoxSF: Use UTF-16 for talking to the host, fits better with conversions APIs in kernel. Experimenting with using single request buffers for open/create.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/os2/VBoxSF/VBoxSF.cpp

    r75558 r76108  
    189189
    190190/**
    191  * Allocates a SHFLSTRING buffer.
     191 * Allocates a SHFLSTRING buffer (UTF-16).
    192192 *
    193193 * @returns Pointer to a SHFLSTRING buffer, NULL if out of memory.
    194  * @param   cchLength   The desired string buffer length (excluding terminator).
    195  */
    196 PSHFLSTRING vboxSfOs2StrAlloc(size_t cchLength)
    197 {
    198     AssertReturn(cchLength <= 0x1000, NULL);
    199 
    200     PSHFLSTRING pStr = (PSHFLSTRING)VbglR0PhysHeapAlloc(SHFLSTRING_HEADER_SIZE + cchLength + 1);
     194 * @param   cwcLength   The desired string buffer length in UTF-16 units
     195 *                      (excluding terminator).
     196 */
     197PSHFLSTRING vboxSfOs2StrAlloc(size_t cwcLength)
     198{
     199    AssertReturn(cwcLength <= 0x1000, NULL);
     200    uint16_t cb = (uint16_t)cwcLength + 1;
     201    cb *= sizeof(RTUTF16);
     202
     203    PSHFLSTRING pStr = (PSHFLSTRING)VbglR0PhysHeapAlloc(SHFLSTRING_HEADER_SIZE + cb);
    201204    if (pStr)
    202205    {
    203         pStr->u16Size       = (uint16_t)(cchLength + 1);
    204         pStr->u16Length     = 0;
    205         pStr->String.ach[0] = '\0';
     206        pStr->u16Size         = cb;
     207        pStr->u16Length       = 0;
     208        pStr->String.utf16[0] = '\0';
    206209        return pStr;
    207210    }
     
    211214
    212215/**
    213  * Duplicates a UTF-8 string into a SHFLSTRING buffer.
     216 * Duplicates a shared folders string buffer (UTF-16).
    214217 *
    215218 * @returns Pointer to a SHFLSTRING buffer containing the copy.
    216219 *          NULL if out of memory or the string is too long.
    217  * @param   pachSrc     The string to clone.
    218  * @param   cchSrc      The length of the substring, RTMAX_STR for the whole.
    219  */
    220 PSHFLSTRING vboxSfOs2StrDup(const char *pachSrc, size_t cchSrc)
    221 {
    222     if (cchSrc == RTSTR_MAX)
    223         cchSrc = strlen(pachSrc);
    224     if (cchSrc < 0x1000)
    225     {
    226         PSHFLSTRING pStr = (PSHFLSTRING)VbglR0PhysHeapAlloc(SHFLSTRING_HEADER_SIZE + cchSrc + 1);
    227         if (pStr)
    228         {
    229             pStr->u16Size  = (uint16_t)(cchSrc + 1);
    230             pStr->u16Length = (uint16_t)cchSrc;
    231             memcpy(pStr->String.ach, pachSrc, cchSrc);
    232             pStr->String.ach[cchSrc] = '\0';
    233             return pStr;
    234         }
     220 * @param   pSrc        The string to clone.
     221 */
     222PSHFLSTRING vboxSfOs2StrDup(PCSHFLSTRING pSrc)
     223{
     224    PSHFLSTRING pDst = (PSHFLSTRING)VbglR0PhysHeapAlloc(SHFLSTRING_HEADER_SIZE + pSrc->u16Length + sizeof(RTUTF16));
     225    if (pDst)
     226    {
     227        pDst->u16Size   = pSrc->u16Length + (uint16_t)sizeof(RTUTF16);
     228        pDst->u16Length = pSrc->u16Length;
     229        memcpy(&pDst->String, &pSrc->String, pSrc->u16Length);
     230        pDst->String.utf16[pSrc->u16Length / sizeof(RTUTF16)] = '\0';
     231        return pDst;
    235232    }
    236233    return NULL;
     
    268265    int rc = VbglR0SfConnect(&g_SfClient);
    269266    if (RT_SUCCESS(rc))
    270     {
    271         rc = VbglR0SfSetUtf8(&g_SfClient);
    272         if (RT_SUCCESS(rc))
    273             g_fIsConnectedToService = true;
    274         else
    275         {
    276             LogRel(("VbglR0SfSetUtf8 failed: %Rrc\n", rc));
    277             VbglR0SfDisconnect(&g_SfClient);
    278         }
    279     }
     267        g_fIsConnectedToService = true;
    280268    else
    281269        LogRel(("VbglR0SfConnect failed: %Rrc\n", rc));
     
    358346 *
    359347 * @returns VBox status code.
    360  * @param   pName       The name of the folder to map.
     348 * @param   pName       The name of the folder to map - ASCII (not UTF-16!).
     349 *                      Must be large enough to hold UTF-16 expansion of the
     350 *                      string, will do so upon return.
    361351 * @param   pszTag      Folder tag (for the VBoxService automounter).  Optional.
    362352 * @param   ppFolder    Where to return the folder structure on success.
     
    386376            memcpy(&pNew->szName[pName->u16Length + 1], pszTag, cbTag);
    387377
     378        /* Expand the folder name to UTF-16. */
     379        uint8_t                 off     = pNew->cchName;
     380        uint8_t volatile const *pbSrc   = &pName->String.utf8[0];
     381        RTUTF16 volatile       *pwcDst  = &pName->String.utf16[0];
     382        do
     383            pwcDst[off] = pbSrc[off];
     384        while (off-- > 0);
     385        pName->u16Length *= sizeof(RTUTF16);
     386        Assert(pName->u16Length + sizeof(RTUTF16) <= pName->u16Size);
     387
     388        /* Try do the mapping.*/
    388389        rc = VbglR0SfMapFolder(&g_SfClient, pName, &pNew->hHostFolder);
    389390        if (RT_SUCCESS(rc))
     
    397398        else
    398399        {
    399             LogRel(("vboxSfOs2MapFolder: VbglR0SfMapFolder(,%.*s,) -> %Rrc\n", pName->u16Length, pName->String.utf8, rc));
     400            LogRel(("vboxSfOs2MapFolder: VbglR0SfMapFolder(,%s,) -> %Rrc\n", pNew->szName, rc));
    400401            RTMemFree(pNew);
    401402        }
     
    465466
    466467/**
    467  * Converts a path to UTF-8 and puts it in a VBGL friendly buffer.
     468 * Converts a path to UTF-16 and puts it in a VBGL friendly buffer.
    468469 *
    469470 * @returns OS/2 status code
     
    474475APIRET vboxSfOs2ConvertPath(const char *pszFolderPath, PSHFLSTRING *ppStr)
    475476{
    476     /* Skip unnecessary leading slashes. */
     477    /*
     478     * Skip unnecessary leading slashes.
     479     */
    477480    char ch = *pszFolderPath;
    478481    if (ch == '\\' || ch == '/')
     
    480483            pszFolderPath++;
    481484
    482     /** @todo do proper codepage -> utf8 conversion and straighten out
    483      *        everything... */
     485    /*
     486     * Since the KEE unicode conversion routines does not seem to know of
     487     * surrogate pairs, we will get a very good output size estimate by
     488     * using strlen() on the input.
     489     */
    484490    size_t cchSrc = strlen(pszFolderPath);
    485     PSHFLSTRING pDst = vboxSfOs2StrAlloc(cchSrc);
     491    PSHFLSTRING pDst = vboxSfOs2StrAlloc(cchSrc + 4 /*fudge*/);
    486492    if (pDst)
    487493    {
    488         pDst->u16Length = (uint16_t)cchSrc;
    489         memcpy(pDst->String.utf8, pszFolderPath, cchSrc);
    490         pDst->String.utf8[cchSrc] = '\0';
    491         *ppStr = pDst;
    492         return NO_ERROR;
    493     }
     494        APIRET rc = KernStrToUcs(NULL, &pDst->String.utf16[0], (char *)pszFolderPath, cchSrc + 4, cchSrc);
     495        if (rc == NO_ERROR)
     496        {
     497            pDst->u16Length = (uint16_t)RTUtf16Len(pDst->String.utf16) * (uint16_t)sizeof(RTUTF16);
     498            *ppStr = pDst;
     499            return NO_ERROR;
     500        }
     501        VbglR0PhysHeapFree(pDst);
     502
     503        /*
     504         * This shouldn't happen, but just in case we try again with
     505         * twice the buffer size.
     506         */
     507        if (rc == 0x20412 /*ULS_BUFFERFULL*/)
     508        {
     509            pDst = vboxSfOs2StrAlloc((cchSrc + 16) * 2);
     510            if (pDst)
     511            {
     512                rc = KernStrToUcs(NULL, pDst->String.utf16, (char *)pszFolderPath, (cchSrc + 16) * 2, cchSrc);
     513                if (rc == NO_ERROR)
     514                {
     515                    pDst->u16Length = (uint16_t)RTUtf16Len(pDst->String.utf16) * (uint16_t)sizeof(RTUTF16);
     516                    *ppStr = pDst;
     517                    return NO_ERROR;
     518                }
     519                VbglR0PhysHeapFree(pDst);
     520                LogRel(("vboxSfOs2ConvertPath: KernStrToUcs returns %#x for %.*Rhxs\n", rc, cchSrc, pszFolderPath));
     521            }
     522        }
     523        else
     524            LogRel(("vboxSfOs2ConvertPath: KernStrToUcs returns %#x for %.*Rhxs\n", rc, cchSrc, pszFolderPath));
     525    }
     526
     527    LogRel(("vboxSfOs2ConvertPath: Out of memory - cchSrc=%#x\n", cchSrc));
    494528    *ppStr = NULL;
     529    return ERROR_NOT_ENOUGH_MEMORY;
     530}
     531
     532
     533/**
     534 * Converts a path to UTF-16 and puts it in a VBGL friendly buffer within a
     535 * larger buffer.
     536 *
     537 * @returns OS/2 status code
     538 * @param   pszFolderPath   The path to convert.
     539 * @param   offStrInBuf     The offset of the SHLFSTRING in the return buffer.
     540 *                          This first part of the buffer is zeroed.
     541 * @param   ppvBuf          Where to return the pointer to the buffer.  Free
     542 *                          using vboxSfOs2FreePath.
     543 */
     544APIRET vboxSfOs2ConvertPathEx(const char *pszFolderPath, uint32_t offStrInBuf, void **ppvBuf)
     545{
     546    /*
     547     * Skip unnecessary leading slashes.
     548     */
     549    char ch = *pszFolderPath;
     550    if (ch == '\\' || ch == '/')
     551        while ((ch = pszFolderPath[1]) == '\\' || ch == '/')
     552            pszFolderPath++;
     553
     554    /*
     555     * Since the KEE unicode conversion routines does not seem to know of
     556     * surrogate pairs, we will get a very good output size estimate by
     557     * using strlen() on the input.
     558     */
     559    size_t cchSrc = strlen(pszFolderPath);
     560    void *pvBuf = VbglR0PhysHeapAlloc(offStrInBuf + SHFLSTRING_HEADER_SIZE + (cchSrc + 4) * sizeof(RTUTF16));
     561    if (pvBuf)
     562    {
     563        RT_BZERO(pvBuf, offStrInBuf);
     564
     565        PSHFLSTRING pDst = (PSHFLSTRING)((uint8_t *)pvBuf + offStrInBuf);
     566        APIRET rc = KernStrToUcs(NULL, &pDst->String.utf16[0], (char *)pszFolderPath, cchSrc + 4, cchSrc);
     567        if (rc == NO_ERROR)
     568        {
     569            pDst->u16Length = (uint16_t)RTUtf16Len(pDst->String.utf16) * (uint16_t)sizeof(RTUTF16);
     570            pDst->u16Size   = (uint16_t)((cchSrc + 4) * sizeof(RTUTF16));
     571            Assert(pDst->u16Length < pDst->u16Size);
     572            *ppvBuf = pvBuf;
     573            return NO_ERROR;
     574        }
     575        VbglR0PhysHeapFree(pvBuf);
     576
     577#if 0
     578        /*
     579         * This shouldn't happen, but just in case we try again with
     580         * twice the buffer size.
     581         */
     582        if (rc == 0x20412 /*ULS_BUFFERFULL*/)
     583        {
     584            pDst = vboxSfOs2StrAlloc((cchSrc + 16) * 2);
     585            if (pDst)
     586            {
     587                rc = KernStrToUcs(NULL, pDst->String.utf16, (char *)pszFolderPath, (cchSrc + 16) * 2, cchSrc);
     588                if (rc == NO_ERROR)
     589                {
     590                    pDst->u16Length = (uint16_t)RTUtf16Len(pDst->String.utf16) * (uint16_t)sizeof(RTUTF16);
     591                    *ppStr = pDst;
     592                    return NO_ERROR;
     593                }
     594                VbglR0PhysHeapFree(pDst);
     595                LogRel(("vboxSfOs2ConvertPath: KernStrToUcs returns %#x for %.*Rhxs\n", rc, cchSrc, pszFolderPath));
     596            }
     597        }
     598        else
     599#endif
     600            LogRel(("vboxSfOs2ConvertPath: KernStrToUcs returns %#x for %.*Rhxs\n", rc, cchSrc, pszFolderPath));
     601    }
     602
     603    LogRel(("vboxSfOs2ConvertPath: Out of memory - cchSrc=%#x offStrInBuf=%#x\n", cchSrc, offStrInBuf));
     604    *ppvBuf = NULL;
    495605    return ERROR_NOT_ENOUGH_MEMORY;
    496606}
     
    553663         * Copy the name into the buffer format that Vbgl desires.
    554664         */
    555         PSHFLSTRING pStrName = vboxSfOs2StrDup(pachFolderName, cchFolderName);
     665        PSHFLSTRING pStrName = vboxSfOs2StrAlloc(cchFolderName);
    556666        if (pStrName)
    557667        {
     668            memcpy(pStrName->String.ach, pachFolderName, cchFolderName);
     669            pStrName->String.ach[cchFolderName] = '\0';
     670            pStrName->u16Length = (uint16_t)cchFolderName;
     671
    558672            /*
    559673             * Do the attaching.
     
    692806                 */
    693807                rc = vboxSfOs2ConvertPath(&pszPath[3], ppStrFolderPath);
     808                if (rc == NO_ERROR)
     809                    return rc;
     810
     811                vboxSfOs2ReleaseFolder(pFolder);
     812                *ppFolder = NULL;
     813                return rc;
     814            }
     815            KernReleaseSharedMutex(&g_MtxFolders);
     816            LogRel(("vboxSfOs2ResolvePath: No folder mapped on '%s'. Detach race?\n", pszPath));
     817            return ERROR_PATH_NOT_FOUND;
     818        }
     819        LogRel(("vboxSfOs2ResolvePath: No root slash: '%s'\n", pszPath));
     820        return ERROR_PATH_NOT_FOUND;
     821    }
     822    LogRel(("vboxSfOs2ResolvePath: Unexpected path: %s\n", pszPath));
     823    RT_NOREF_PV(pCdFsd); RT_NOREF_PV(offCurDirEnd);
     824    return ERROR_PATH_NOT_FOUND;
     825}
     826
     827
     828/**
     829 * Resolves the given path to a folder structure and folder relative string,
     830 * the latter placed within a larger request buffer.
     831 *
     832 * @returns OS/2 status code.
     833 * @param   pszPath         The path to resolve.
     834 * @param   pCdFsd          The IFS dependent CWD structure if present.
     835 * @param   offCurDirEnd    The offset into @a pszPath of the CWD.  -1 if not
     836 *                          CWD relative path.
     837 * @param   offStrInBuf     The offset of the SHLFSTRING in the return buffer.
     838 *                          This first part of the buffer is zeroed.
     839 * @param   ppFolder        Where to return the referenced pointer to the folder
     840 *                          structure.  Call vboxSfOs2ReleaseFolder() when done.
     841 * @param   ppvBuf          Where to return the Pointer to the buffer.  Free
     842 *                          using VbglR0PhysHeapFree.
     843 */
     844APIRET vboxSfOs2ResolvePathEx(const char *pszPath, PVBOXSFCD pCdFsd, LONG offCurDirEnd, uint32_t offStrInBuf,
     845                              PVBOXSFFOLDER *ppFolder, void **ppvBuf)
     846{
     847    APIRET rc;
     848
     849    /*
     850     * UNC path?  Reject the prefix to be on the safe side.
     851     */
     852    char ch = pszPath[0];
     853    if (ch == '\\' || ch == '/')
     854    {
     855        size_t cchPrefix = vboxSfOs2UncPrefixLength(pszPath);
     856        if (cchPrefix > 0)
     857        {
     858            /* Find the length of the folder name (share). */
     859            const char *pszFolderName = &pszPath[cchPrefix];
     860            size_t      cchFolderName = 0;
     861            while ((ch = pszFolderName[cchFolderName]) != '\0' && ch != '\\' && ch != '/')
     862            {
     863                if ((uint8_t)ch >= 0x20 && (uint8_t)ch <= 0x7f && ch != ':')
     864                    cchFolderName++;
     865                else
     866                {
     867                    LogRel(("vboxSfOs2ResolvePath: Invalid share name (@%u): %.*Rhxs\n",
     868                            cchPrefix + cchFolderName, strlen(pszPath), pszPath));
     869                    return ERROR_INVALID_NAME;
     870                }
     871            }
     872            if (cchFolderName >= VBOXSFOS2_MAX_FOLDER_NAME)
     873            {
     874                LogRel(("vboxSfOs2ResolvePath: Folder name is too long: %u, max %u (%s)\n",
     875                        cchFolderName, VBOXSFOS2_MAX_FOLDER_NAME, pszPath));
     876                return ERROR_FILENAME_EXCED_RANGE;
     877            }
     878
     879            /*
     880             * Look for the share.
     881             */
     882            KernRequestSharedMutex(&g_MtxFolders);
     883            PVBOXSFFOLDER pFolder = *ppFolder = vboxSfOs2FindAndRetainFolder(pszFolderName, cchFolderName);
     884            if (pFolder)
     885            {
     886                vboxSfOs2RetainFolder(pFolder);
     887                KernReleaseSharedMutex(&g_MtxFolders);
     888            }
     889            else
     890            {
     891                uint32_t const uRevBefore = g_uFolderRevision;
     892                KernReleaseSharedMutex(&g_MtxFolders);
     893                rc = vboxSfOs2AttachUncAndRetain(pszFolderName, cchFolderName, uRevBefore, ppFolder);
     894                if (rc == NO_ERROR)
     895                    pFolder = *ppFolder;
     896                else
     897                    return rc;
     898            }
     899
     900            /*
     901             * Convert the path and put it in a Vbgl compatible buffer..
     902             */
     903            rc = vboxSfOs2ConvertPathEx(&pszFolderName[cchFolderName], offStrInBuf, ppvBuf);
     904            if (rc == NO_ERROR)
     905                return rc;
     906
     907            vboxSfOs2ReleaseFolder(pFolder);
     908            *ppFolder = NULL;
     909            return rc;
     910        }
     911
     912        LogRel(("vboxSfOs2ResolvePath: Unexpected path: %s\n", pszPath));
     913        return ERROR_PATH_NOT_FOUND;
     914    }
     915
     916    /*
     917     * Drive letter?
     918     */
     919    ch &= ~0x20; /* upper case */
     920    if (   ch >= 'A'
     921        && ch <= 'Z'
     922        && pszPath[1] == ':')
     923    {
     924        unsigned iDrive = ch - 'A';
     925        ch  = pszPath[2];
     926        if (ch == '\\' || ch == '/')
     927        {
     928            KernRequestSharedMutex(&g_MtxFolders);
     929            PVBOXSFFOLDER pFolder = *ppFolder = g_apDriveFolders[iDrive];
     930            if (pFolder)
     931            {
     932                vboxSfOs2RetainFolder(pFolder);
     933                KernReleaseSharedMutex(&g_MtxFolders);
     934
     935                /*
     936                 * Convert the path and put it in a Vbgl compatible buffer..
     937                 */
     938                rc = vboxSfOs2ConvertPathEx(&pszPath[3], offStrInBuf, ppvBuf);
    694939                if (rc == NO_ERROR)
    695940                    return rc;
     
    10061251    RT_NOREF(uType); /* pass 1 or pass 2 doesn't matter to us, we've only got one 'server'. */
    10071252
    1008     if (vboxSfOs2UncPrefixLength(pszName) > 0 )
     1253    if (vboxSfOs2UncPrefixLength(pszName) > 0)
    10091254        return NO_ERROR;
    10101255    return ERROR_NOT_SUPPORTED;
     
    10741319                {
    10751320                    SHFLSTRING Path;
    1076                     uint8_t    abPadding[SHFLSTRING_HEADER_SIZE + 4];
     1321                    uint8_t    abPadding[SHFLSTRING_HEADER_SIZE + 4 * sizeof(RTUTF16)];
    10771322                };
    10781323            } Open;
     
    10961341        pu->Open.Params.CreateFlags = SHFL_CF_DIRECTORY   | SHFL_CF_ACT_FAIL_IF_NEW  | SHFL_CF_ACT_OPEN_IF_EXISTS
    10971342                                    | SHFL_CF_ACCESS_READ | SHFL_CF_ACCESS_ATTR_READ | SHFL_CF_ACCESS_DENYNONE;
    1098         pu->Open.Path.u16Size   = 3;
    1099         pu->Open.Path.u16Length = 2;
    1100         pu->Open.Path.String.utf8[0] = '\\';
    1101         pu->Open.Path.String.utf8[1] = '.';
    1102         pu->Open.Path.String.utf8[2] = '\0';
     1343        pu->Open.Path.u16Size   = 3 * sizeof(RTUTF16);
     1344        pu->Open.Path.u16Length = 2 * sizeof(RTUTF16);
     1345        pu->Open.Path.String.utf16[0] = '\\';
     1346        pu->Open.Path.String.utf16[1] = '.';
     1347        pu->Open.Path.String.utf16[2] = '\0';
    11031348
    11041349        int vrc = VbglR0SfCreate(&g_SfClient, &pFolder->hHostFolder, &pu->Open.Path, &pu->Open.Params);
     
    12721517{
    12731518    LogFlow(("FS32_MKDIR: pCdFsi=%p pCdFsd=%p pszDir=%p:{%s} pEAOp=%p fFlags=%#x\n", pCdFsi, pCdFsd, pszDir, pszDir, offCurDirEnd, pEaOp, fFlags));
     1519    RT_NOREF(fFlags);
    12741520
    12751521    /*
     
    16261872    LogFlow(("FS32_FILEATTRIBUTE: fFlags=%#x pCdFsi=%p:{%#x,%s} pCdFsd=%p pszName=%p:{%s} offCurDirEnd=%d pfAttr=%p\n",
    16271873             fFlags, pCdFsi, pCdFsi->cdi_hVPB, pCdFsi->cdi_curdir, pCdFsd, pszName, pszName, offCurDirEnd, pfAttr));
    1628     RT_NOREF(offCurDirEnd);
     1874    RT_NOREF(pCdFsi, offCurDirEnd);
    16291875
    16301876    APIRET rc;
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