VirtualBox

Ignore:
Timestamp:
Jan 1, 2019 8:56:07 AM (6 years ago)
Author:
vboxsync
Message:

IPRT: Attempted to address some the more obvious shortcomings of RTPathCalcRelative. Had to add a parameter that clearifies whether the from path is a file (VHD usage) or directory (rest).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/common/path/RTPathCalcRelative.cpp

    r76553 r76589  
    3131#include "internal/iprt.h"
    3232#include <iprt/path.h>
     33
    3334#include <iprt/assert.h>
     35#if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS
     36# include <iprt/ctype.h>
     37#endif
    3438#include <iprt/err.h>
    3539#include <iprt/string.h>
     
    3943
    4044RTDECL(int) RTPathCalcRelative(char *pszPathDst, size_t cbPathDst,
    41                                const char *pszPathFrom,
     45                               const char *pszPathFrom, bool fFromFile,
    4246                               const char *pszPathTo)
    4347{
    44     int rc = VINF_SUCCESS;
    45 
    4648    AssertPtrReturn(pszPathDst, VERR_INVALID_POINTER);
    4749    AssertReturn(cbPathDst, VERR_INVALID_PARAMETER);
    4850    AssertPtrReturn(pszPathFrom, VERR_INVALID_POINTER);
    4951    AssertPtrReturn(pszPathTo, VERR_INVALID_POINTER);
    50     AssertReturn(RTPathStartsWithRoot(pszPathFrom), VERR_INVALID_PARAMETER);
    51     AssertReturn(RTPathStartsWithRoot(pszPathTo), VERR_INVALID_PARAMETER);
    52     AssertReturn(RTStrCmp(pszPathFrom, pszPathTo), VERR_INVALID_PARAMETER);
    5352
    5453    /*
    5554     * Check for different root specifiers (drive letters), creating a relative path doesn't work here.
    56      * @todo: How to handle case insensitive root specifiers correctly?
    5755     */
    5856    size_t offRootFrom = rtPathRootSpecLen(pszPathFrom);
     57    AssertReturn(offRootFrom > 0, VERR_INVALID_PARAMETER);
     58
    5959    size_t offRootTo   = rtPathRootSpecLen(pszPathTo);
    60 
    61     if (   offRootFrom != offRootTo
    62         || RTStrNCmp(pszPathFrom, pszPathTo, offRootFrom))
     60    AssertReturn(offRootTo > 0, VERR_INVALID_PARAMETER);
     61
     62
     63    /** @todo correctly deal with extra root slashes! */
     64    if (offRootFrom != offRootTo)
    6365        return VERR_NOT_SUPPORTED;
    6466
    65     /* Filter out the parent path which is equal to both paths. */
    66     while (   *pszPathFrom == *pszPathTo
    67            && *pszPathFrom != '\0'
    68            && *pszPathTo != '\0')
    69     {
    70         pszPathFrom++;
    71         pszPathTo++;
    72     }
     67#if RTPATH_STYLE != RTPATH_STR_F_STYLE_DOS
     68    if (RTStrNCmp(pszPathFrom, pszPathTo, offRootFrom))
     69        return VERR_NOT_SUPPORTED;
     70#else
     71    if (RTStrNICmp(pszPathFrom, pszPathTo, offRootFrom))
     72        for (size_t off = 0; off < offRootFrom; off++)
     73        {
     74            char const chFrom = pszPathFrom[off];
     75            char const chTo   = pszPathTo[off];
     76            if (   chFrom != chTo
     77                && RT_C_TO_LOWER(chFrom) != RT_C_TO_LOWER(chTo) /** @todo proper case insensitivity! */
     78                && (!RTPATH_IS_SLASH(chFrom) || !RTPATH_IS_SLASH(chTo)) )
     79                return VERR_NOT_SUPPORTED;
     80        }
     81#endif
     82
     83    pszPathFrom += offRootFrom;
     84    pszPathTo   += offRootTo;
    7385
    7486    /*
    75      * Because path components can start with an equal string but differ afterwards we
    76      * need to go back to the beginning of the current component.
     87     * Skip out the part of the path which is equal to both.
    7788     */
    78     while (!RTPATH_IS_SEP(*pszPathFrom))
    79         pszPathFrom--;
    80 
    81     pszPathFrom++; /* Skip path separator. */
    82 
    83     while (!RTPATH_IS_SEP(*pszPathTo))
    84         pszPathTo--;
    85 
    86     pszPathTo++; /* Skip path separator. */
     89    const char *pszStartOfFromComp = pszPathFrom;
     90    for (;;)
     91    {
     92        char const chFrom = *pszPathFrom;
     93        char const chTo   = *pszPathTo;
     94        if (!RTPATH_IS_SLASH(chFrom))
     95        {
     96            if (chFrom == chTo)
     97            {
     98                if (chFrom)
     99                { /* likely */ }
     100                else
     101                {
     102                    /* Special case: The two paths are equal. */
     103                    if (fFromFile)
     104                    {
     105                        size_t cchComp = pszPathFrom - pszStartOfFromComp;
     106                        if (cchComp < cbPathDst)
     107                        {
     108                            memcpy(pszPathDst, pszStartOfFromComp, cchComp);
     109                            pszPathDst[cchComp] = '\0';
     110                            return VINF_SUCCESS;
     111                        }
     112                    }
     113                    else if (sizeof(".") <= cbPathDst)
     114                    {
     115                        memcpy(pszPathDst, ".", sizeof("."));
     116                        return VINF_SUCCESS;
     117                    }
     118                    return VERR_BUFFER_OVERFLOW;
     119                }
     120            }
     121#if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS
     122            else if (RT_C_TO_LOWER(chFrom) == RT_C_TO_LOWER(chTo))
     123            { /* if not likely, then simpler code structure wise. */ }
     124#endif
     125            else if (chFrom != '\0' || !RTPATH_IS_SLASH(chTo) || fFromFile)
     126                break;
     127            else
     128            {
     129                pszStartOfFromComp = pszPathFrom;
     130                do
     131                    pszPathTo++;
     132                while (RTPATH_IS_SLASH(*pszPathTo));
     133                break;
     134            }
     135            pszPathFrom++;
     136            pszPathTo++;
     137        }
     138        else if (RTPATH_IS_SLASH(chTo))
     139        {
     140            /* Both have slashes.  Skip any additional ones before taking down
     141               the start of the component for rewinding purposes. */
     142            do
     143                pszPathTo++;
     144            while (RTPATH_IS_SLASH(*pszPathTo));
     145            do
     146                pszPathFrom++;
     147            while (RTPATH_IS_SLASH(*pszPathFrom));
     148            pszStartOfFromComp = pszPathFrom;
     149        }
     150        else
     151            break;
     152    }
     153
     154    /* Rewind to the start of the current component. */
     155    pszPathTo  -= pszPathFrom - pszStartOfFromComp;
     156    pszPathFrom = pszStartOfFromComp;
    87157
    88158    /* Paths point to the first non equal component now. */
    89     char aszPathTmp[RTPATH_MAX + 1];
    90     unsigned offPathTmp = 0;
     159
     160    /*
     161     * Constructure the relative path.
     162     */
    91163
    92164    /* Create the part to go up from pszPathFrom. */
     165    unsigned offDst = 0;
     166
     167    if (!fFromFile && *pszPathFrom != '\0')
     168    {
     169        if (offDst + 3 < cbPathDst)
     170        {
     171            pszPathDst[offDst++] = '.';
     172            pszPathDst[offDst++] = '.';
     173            pszPathDst[offDst++] = RTPATH_SLASH;
     174        }
     175        else
     176            return VERR_BUFFER_OVERFLOW;
     177    }
     178
    93179    while (*pszPathFrom != '\0')
    94180    {
    95         while (   !RTPATH_IS_SEP(*pszPathFrom)
    96                && *pszPathFrom != '\0')
     181        char ch;
     182        while (   (ch = *pszPathFrom) != '\0'
     183               && !RTPATH_IS_SLASH(*pszPathFrom))
    97184            pszPathFrom++;
    98 
    99         if (RTPATH_IS_SEP(*pszPathFrom))
    100         {
    101             if (offPathTmp + 3 >= sizeof(aszPathTmp) - 1)
    102                 return VERR_FILENAME_TOO_LONG;
    103             aszPathTmp[offPathTmp++] = '.';
    104             aszPathTmp[offPathTmp++] = '.';
    105             aszPathTmp[offPathTmp++] = RTPATH_SLASH;
     185        while (   (ch = *pszPathFrom) != '\0'
     186               && RTPATH_IS_SLASH(ch))
    106187            pszPathFrom++;
    107         }
    108     }
    109 
    110     aszPathTmp[offPathTmp] = '\0';
     188        if (!ch)
     189            break;
     190
     191        if (offDst + 3 < cbPathDst)
     192        {
     193            pszPathDst[offDst++] = '.';
     194            pszPathDst[offDst++] = '.';
     195            pszPathDst[offDst++] = RTPATH_SLASH;
     196        }
     197        else
     198            return VERR_BUFFER_OVERFLOW;
     199    }
    111200
    112201    /* Now append the rest of pszPathTo to the final path. */
    113     char *pszPathTmp = &aszPathTmp[offPathTmp];
    114     size_t cbPathTmp = sizeof(aszPathTmp) - offPathTmp - 1;
    115     rc = RTStrCatP(&pszPathTmp, &cbPathTmp, pszPathTo);
    116     if (RT_SUCCESS(rc))
    117     {
    118         *pszPathTmp = '\0';
    119 
    120         size_t cchPathTmp = strlen(aszPathTmp);
    121         if (cchPathTmp >= cbPathDst)
    122            return VERR_BUFFER_OVERFLOW;
    123         memcpy(pszPathDst, aszPathTmp, cchPathTmp + 1);
    124     }
    125     else
    126         rc = VERR_FILENAME_TOO_LONG;
    127 
    128     return rc;
     202    size_t cchTo = strlen(pszPathTo);
     203    if (offDst + cchTo <= cbPathDst)
     204    {
     205        memcpy(&pszPathDst[offDst], pszPathTo, cchTo);
     206        pszPathDst[offDst + cchTo] = '\0';
     207        return VINF_SUCCESS;
     208    }
     209    return VERR_BUFFER_OVERFLOW;
    129210}
    130211
Note: See TracChangeset for help on using the changeset viewer.

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