VirtualBox

Changeset 69688 in vbox for trunk/src/VBox/Runtime/r3/nt


Ignore:
Timestamp:
Nov 14, 2017 2:44:25 PM (7 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
119060
Message:

iprt: pathint-nt.cpp: Added RTNtPathRelativeFromUtf8 for RTDirRel. Untested.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r3/nt/pathint-nt.cpp

    r69111 r69688  
    3333
    3434#include <iprt/path.h>
     35#include <iprt/mem.h>
    3536#include <iprt/string.h>
    3637#include <iprt/err.h>
     
    406407
    407408/**
     409 * Gets the NT path to the object represented by the given handle.
     410 *
     411 * @returns IPRT status code.
     412 * @param   pNtName             Where to return the NT path.  Free using
     413 *                              RTUtf16Alloc.
     414 * @param   hHandle             The handle.
     415 * @param   cwcExtra            How much extra space is needed.
     416 */
     417static int rtNtPathFromHandle(struct _UNICODE_STRING *pNtName, HANDLE hHandle, size_t cwcExtra)
     418{
     419    /*
     420     * Query the name into a buffer.
     421     */
     422    ULONG cbBuf = _2K;
     423    PUNICODE_STRING pUniStrBuf = (PUNICODE_STRING)RTMemTmpAllocZ(cbBuf);
     424    if (!pUniStrBuf)
     425        return VERR_NO_TMP_MEMORY;
     426
     427    ULONG cbNameBuf = cbBuf;
     428    NTSTATUS rcNt = NtQueryObject(hHandle, ObjectNameInformation, pUniStrBuf, cbBuf, &cbNameBuf);
     429    while (   rcNt == STATUS_BUFFER_OVERFLOW
     430           || rcNt == STATUS_BUFFER_TOO_SMALL)
     431    {
     432        do
     433            cbBuf *= 2;
     434        while (cbBuf <= cbNameBuf);
     435        RTMemTmpFree(pUniStrBuf);
     436        pUniStrBuf = (PUNICODE_STRING)RTMemTmpAllocZ(cbBuf);
     437        if (!pUniStrBuf)
     438            return VERR_NO_TMP_MEMORY;
     439
     440        cbNameBuf = cbBuf;
     441        rcNt = NtQueryObject(hHandle, ObjectNameInformation, pUniStrBuf, cbBuf, &cbNameBuf);
     442    }
     443    int rc;
     444    if (NT_SUCCESS(rcNt))
     445    {
     446        /*
     447         * Copy the result into the return string.
     448         */
     449        size_t cbNeeded = cwcExtra * sizeof(RTUTF16) + pNtName->Length + sizeof(RTUTF16);
     450        if (cbNeeded < _64K)
     451        {
     452            pNtName->Length        = pUniStrBuf->Length;
     453            pNtName->MaximumLength = (uint16_t)cbNeeded;
     454            pNtName->Buffer        = RTUtf16Alloc(cbNeeded);
     455            if (pNtName->Buffer)
     456            {
     457                memcpy(pNtName->Buffer, pUniStrBuf->Buffer, pUniStrBuf->Length);
     458                pNtName->Buffer[pUniStrBuf->Length / sizeof(RTUTF16)] = '\0';
     459                rc = VINF_SUCCESS;
     460            }
     461            else
     462                rc = VERR_NO_UTF16_MEMORY;
     463        }
     464        else
     465            rc = VERR_FILENAME_TOO_LONG;
     466    }
     467    else
     468        rc = RTErrConvertFromNtStatus(rcNt);
     469    RTMemTmpFree(pUniStrBuf);
     470    return rc;
     471}
     472
     473
     474/**
     475 * Rewinds the path back to the start of the previous component.
     476 *
     477 * Will preserve root slash.
     478 *
     479 * @returns Pointer to character after the start-of-component slash, or
     480 *          pwszStart.
     481 * @param   pwcEnd              The current end of the path.
     482 * @param   pwszStart           The start of the path.
     483 */
     484static PRTUTF16 rtNtPathGetPrevComponent(PRTUTF16 pwcEnd, PRTUTF16 pwszStart)
     485{
     486    if ((uintptr_t)pwcEnd > (uintptr_t)pwszStart)
     487    {
     488        RTUTF16 wc = pwcEnd[-1];
     489        if (   (wc == '\\' || wc == '/')
     490            && (uintptr_t)(pwcEnd - pwszStart) != 1)
     491            pwcEnd--;
     492
     493        while (   (uintptr_t)pwcEnd > (uintptr_t)pwszStart
     494               && (wc = pwcEnd[-1]) != '\\'
     495               && (wc = pwcEnd[-1]) != '/')
     496            pwcEnd--;
     497    }
     498    return pwcEnd;
     499}
     500
     501
     502/**
     503 * Converts a relative windows-style path to relative NT format and encoding.
     504 *
     505 * @returns IPRT status code.
     506 * @param   pNtName             Where to return the NT name.  Free using
     507 *                              rtTNtPathToNative with phRootDir set to NULL.
     508 * @param   phRootDir           On input, the handle to the directory the path
     509 *                              is relative to.  On output, the handle to
     510 *                              specify as root directory in the object
     511 *                              attributes when accessing the path.  If
     512 *                              enmAscent is kRTNtPathRelativeAscent_Allow, it
     513 *                              may have been set to NULL.
     514 * @param   pszPath             The relative UTF-8 path.
     515 * @param   enmAscent           How to handle ascent.
     516 */
     517RTDECL(int) RTNtPathRelativeFromUtf8(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath,
     518                                     RTNTPATHRELATIVEASCENT enmAscent)
     519{
     520    size_t cwcMax;
     521    int rc = RTStrCalcUtf16LenEx(pszPath, RTSTR_MAX, &cwcMax);
     522    if (RT_FAILURE(rc))
     523        return rc;
     524    if (cwcMax + 2 >= _32K)
     525        return VERR_FILENAME_TOO_LONG;
     526
     527    PRTUTF16 pwszDst;
     528    pNtName->Length        = 0;
     529    pNtName->MaximumLength = (uint16_t)((cwcMax + 2) * sizeof(RTUTF16));
     530    pNtName->Buffer        = pwszDst = RTUtf16Alloc((cwcMax + 2) * sizeof(RTUTF16));
     531    if (!pwszDst)
     532        return VERR_NO_UTF16_MEMORY;
     533
     534    PRTUTF16 pwszDstCur  = pwszDst;
     535    PRTUTF16 pwszDstComp = pwszDst;
     536    for (;;)
     537    {
     538        RTUNICP uc;
     539        rc = RTStrGetCpEx(&pszPath, &uc);
     540        if (RT_SUCCESS(rc))
     541        {
     542            switch (uc)
     543            {
     544                default:
     545                    pwszDstCur = RTUtf16PutCp(pwszDst, uc);
     546                    break;
     547
     548                case '\\':
     549                case '/':
     550                    if (pwszDstCur != pwszDstComp)
     551                        pwszDstComp = pwszDstCur = RTUtf16PutCp(pwszDstCur, '\\');
     552                    /* else: only one slash between components. */
     553                    break;
     554
     555                case '.':
     556                    if (pwszDstCur == pwszDstComp)
     557                    {
     558                        /*
     559                         * Single dot changes nothing.
     560                         */
     561                        char ch2 = *pszPath;
     562                        if (ch2 == '\0')
     563                        {
     564                            /* Trailing single dot means we need to drop trailing slash. */
     565                            if (pwszDstCur != pwszDst)
     566                                pwszDstCur--;
     567                            *pwszDstCur = '\0';
     568                            pNtName->Length = (uint16_t)(pwszDstCur - pwszDst);
     569                            return VINF_SUCCESS;
     570                        }
     571
     572                        if (ch2 == '\\' || ch2 == '/')
     573                        {
     574                            pszPath++; /* Ignore lone dot followed but another component. */
     575                            break;
     576                        }
     577
     578                        /*
     579                         * Two dots drops off the last directory component.  This gets complicated
     580                         * when we start out without any path and we need to consult enmAscent.
     581                         */
     582                        if (ch2 == '.')
     583                        {
     584                            char ch3 = pszPath[1];
     585                            if (   ch3 == '\\'
     586                                || ch3 == '/'
     587                                || ch3 == '\0')
     588                            {
     589                                /* Drop a path component. */
     590                                if (pwszDstComp != pwszDst)
     591                                    pwszDstComp = pwszDstCur = rtNtPathGetPrevComponent(pwszDstCur, pwszDst);
     592                                /* Hit the start, which is a bit complicated. */
     593                                else
     594                                    switch (enmAscent)
     595                                    {
     596                                        case kRTNtPathRelativeAscent_Allow:
     597                                            if (*phRootDir != RTNT_INVALID_HANDLE_VALUE)
     598                                            {
     599                                                RTUtf16Free(pwszDst);
     600                                                rc = rtNtPathFromHandle(pNtName, *phRootDir, cwcMax + 2);
     601                                                if (RT_FAILURE(rc))
     602                                                    return rc;
     603
     604                                                *phRootDir = RTNT_INVALID_HANDLE_VALUE;
     605                                                pwszDst    = pNtName->Buffer;
     606                                                pwszDstCur = &pwszDst[pNtName->Length / sizeof(RTUTF16)];
     607                                                if (   pwszDst != pwszDstCur
     608                                                    && pwszDstCur[-1] != '\\'
     609                                                    && pwszDstCur[-1] != '/')
     610                                                    *pwszDstCur++ = '\\';
     611                                                pwszDstComp = pwszDstCur = rtNtPathGetPrevComponent(pwszDstCur, pwszDst);
     612                                            }
     613                                            /* else: ignore attempt to ascend beyond the NT root (won't get here). */
     614                                            break;
     615
     616                                        case kRTNtPathRelativeAscent_Ignore:
     617                                            /* nothing to do here */
     618                                            break;
     619
     620                                        default:
     621                                        case kRTNtPathRelativeAscent_Fail:
     622                                            RTUtf16Free(pwszDst);
     623                                            return VERR_PATH_NOT_FOUND;
     624                                    }
     625
     626                                if (ch3 == '\0')
     627                                {
     628                                    *pwszDstCur = '\0';
     629                                    pNtName->Length = (uint16_t)(pwszDstCur - pwszDst);
     630                                    return VINF_SUCCESS;
     631                                }
     632                                pszPath += 2;
     633                                break;
     634                            }
     635                        }
     636                    }
     637
     638                    /* Neither '.' nor '..'. */
     639                    pwszDstCur = RTUtf16PutCp(pwszDstCur, '.');
     640                    break;
     641
     642                case '\0':
     643                    *pwszDstCur = '\0';
     644                    pNtName->Length = (uint16_t)(pwszDstCur - pwszDst);
     645                    return VINF_SUCCESS;
     646            }
     647        }
     648    }
     649}
     650
     651
     652/**
    408653 * Frees the native path and root handle.
    409654 *
    410655 * @param   pNtName             The NT path after a successful rtNtPathToNative
    411  *                              call.
    412  * @param   phRootDir           The root handle variable from the same call.
     656 *                              call or RTNtPathRelativeFromUtf8.
     657 * @param   phRootDir           The root handle variable from rtNtPathToNative,
     658 *                              but NOT RTNtPathRelativeFromUtf8.
    413659 */
    414660static void rtNtPathFreeNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir)
     
    417663    pNtName->Buffer = NULL;
    418664
    419     RT_NOREF_PV(phRootDir); /* never returned by rtNtPathToNative */
     665    RT_NOREF_PV(phRootDir); /* never returned by rtNtPathToNative, shouldn't be freed in connection with RTNtPathRelativeFromUtf8 */
    420666}
    421667
     
    424670 * Frees the native path and root handle.
    425671 *
    426  * @param   pNtName             The NT path from a successful RTNtPathToNative
    427  *                              or RTNtPathFromWinUtf16Ex call.
    428  * @param   phRootDir           The root handle variable from the same call.
     672 * @param   pNtName             The NT path after a successful rtNtPathToNative
     673 *                              call or RTNtPathRelativeFromUtf8.
     674 * @param   phRootDir           The root handle variable from rtNtPathToNative,
    429675 */
    430676RTDECL(void) RTNtPathFree(struct _UNICODE_STRING *pNtName, HANDLE *phRootDir)
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