VirtualBox

Changeset 52944 in vbox for trunk/src/VBox/Runtime


Ignore:
Timestamp:
Oct 5, 2014 4:37:10 AM (10 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
96384
Message:

IPRT: Separated out RTPathAbs from the posix, fixing it up for windows + OS/2, and made it generic. Also added some NT path routines.

Location:
trunk/src/VBox/Runtime
Files:
2 added
7 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/Makefile.kmk

    r52600 r52944  
    587587        generic/RTLogWriteStdOut-generic.cpp \
    588588        generic/RTLogWriteUser-generic.cpp \
     589        generic/RTPathGetCurrentDrive-generic.cpp \
    589590        generic/RTPathIsSame-generic.cpp \
    590591        generic/RTProcessQueryUsernameA-generic.cpp \
     
    702703        generic/RTMpGetCurFrequency-generic.cpp \
    703704        generic/RTMpGetMaxFrequency-generic.cpp \
     705        generic/RTPathAbs-generic.cpp \
    704706        generic/RTRandAdvCreateSystemFaster-generic.cpp \
    705707        generic/RTRandAdvCreateSystemTruer-generic.cpp \
     
    768770        generic/RTFileMove-generic.cpp \
    769771        generic/RTLogWriteDebugger-generic.cpp \
     772        generic/RTPathAbs-generic.cpp \
     773        generic/RTPathGetCurrentOnDrive-generic.cpp \
    770774        generic/RTProcDaemonize-generic.cpp \
    771775        generic/RTSemEventMultiWait-2-ex-generic.cpp \
     
    852856        generic/RTFileMove-generic.cpp \
    853857        generic/RTLogWriteDebugger-generic.cpp \
     858        generic/RTPathAbs-generic.cpp \
     859        generic/RTPathGetCurrentOnDrive-generic.cpp \
    854860        generic/RTProcDaemonize-generic.cpp \
    855861        generic/RTRandAdvCreateSystemFaster-generic.cpp \
     
    924930        generic/RTFileMove-generic.cpp \
    925931        generic/RTLogWriteDebugger-generic.cpp \
     932        generic/RTPathAbs-generic.cpp \
     933        generic/RTPathGetCurrentOnDrive-generic.cpp \
    926934        generic/RTProcDaemonize-generic.cpp \
    927935        generic/RTThreadGetAffinity-stub-generic.cpp \
     
    991999        generic/RTFileMove-generic.cpp \
    9921000        generic/RTLogWriteDebugger-generic.cpp \
     1001        generic/RTPathAbs-generic.cpp \
     1002        generic/RTPathGetCurrentOnDrive-generic.cpp \
    9931003        generic/RTSemEventMultiWait-2-ex-generic.cpp \
    9941004        generic/RTSemEventMultiWaitNoResume-2-ex-generic.cpp \
     
    10601070        generic/RTFileMove-generic.cpp \
    10611071        generic/RTLogWriteDebugger-generic.cpp \
     1072        generic/RTPathAbs-generic.cpp \
     1073        generic/RTPathGetCurrentOnDrive-generic.cpp \
    10621074        generic/RTProcDaemonize-generic.cpp \
    10631075        generic/RTProcIsRunningByName-generic.cpp \
     
    11321144        generic/RTFileMove-generic.cpp \
    11331145        generic/RTLogWriteDebugger-generic.cpp \
     1146        generic/RTPathAbs-generic.cpp \
     1147        generic/RTPathGetCurrentOnDrive-generic.cpp \
    11341148        generic/RTProcDaemonize-generic.cpp \
    11351149        generic/RTTimeLocalNow-generic.cpp \
  • trunk/src/VBox/Runtime/common/string/utf-16.cpp

    r51770 r52944  
    100100
    101101
     102RTDECL(PRTUTF16) RTUtf16AllocTag(size_t cb, const char *pszTag)
     103{
     104    if (cb > sizeof(RTUTF16))
     105        cb = RT_ALIGN_Z(cb, sizeof(RTUTF16));
     106    else
     107        cb = sizeof(RTUTF16);
     108    PRTUTF16 pwsz = (PRTUTF16)RTMemAllocTag(cb, pszTag);
     109    if (pwsz)
     110        *pwsz = '\0';
     111    return pwsz;
     112}
     113RT_EXPORT_SYMBOL(RTUtf16AllocTag);
     114
     115
    102116RTDECL(void)  RTUtf16Free(PRTUTF16 pwszString)
    103117{
  • trunk/src/VBox/Runtime/generic/RTPathAbs-generic.cpp

    r52854 r52944  
    11/* $Id$ */
    22/** @file
    3  * IPRT - Path Manipulation, POSIX, Part 1.
     3 * IPRT - RTPathAbs, generic implementation.
    44 */
    55
    66/*
    7  * Copyright (C) 2006-2012 Oracle Corporation
     7 * Copyright (C) 2006-2014 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    3030*******************************************************************************/
    3131#define LOG_GROUP RTLOGGROUP_PATH
    32 #include <stdlib.h>
    33 #include <limits.h>
    34 #include <errno.h>
    35 #include <unistd.h>
    36 #include <sys/stat.h>
    37 #include <sys/time.h>
    38 #include <stdio.h>
    39 #include <sys/types.h>
    40 #include <pwd.h>
    41 
    4232#include <iprt/path.h>
    43 #include <iprt/env.h>
     33
    4434#include <iprt/assert.h>
    45 #include <iprt/string.h>
     35#include <iprt/ctype.h>
    4636#include <iprt/err.h>
    4737#include <iprt/log.h>
     38#include <iprt/string.h>
    4839#include "internal/path.h"
    49 #include "internal/process.h"
    5040#include "internal/fs.h"
    5141
    5242
    53 
    54 RTDECL(int) RTPathReal(const char *pszPath, char *pszRealPath, size_t cchRealPath)
     43static char *rtPathSkipRootSpec(char *pszCur)
    5544{
    56     /*
    57      * Convert input.
    58      */
    59     char const *pszNativePath;
    60     int rc = rtPathToNative(&pszNativePath, pszPath, NULL);
    61     if (RT_SUCCESS(rc))
    62     {
    63         /*
    64          * On POSIX platforms the API doesn't take a length parameter, which makes it
    65          * a little bit more work.
    66          */
    67         char szTmpPath[PATH_MAX + 1];
    68         const char *psz = realpath(pszNativePath, szTmpPath);
    69         if (psz)
    70             rc = rtPathFromNativeCopy(pszRealPath, cchRealPath, szTmpPath, NULL);
    71         else
    72             rc = RTErrConvertFromErrno(errno);
    73         rtPathFreeNative(pszNativePath, pszPath);
    74     }
    75 
    76     LogFlow(("RTPathReal(%p:{%s}, %p:{%s}, %u): returns %Rrc\n", pszPath, pszPath,
    77              pszRealPath, RT_SUCCESS(rc) ? pszRealPath : "<failed>",  cchRealPath, rc));
    78     return rc;
     45#ifdef HAVE_DRIVE
     46    if (pszCur[0] && RTPATH_IS_VOLSEP(pszCur[1]) && pszCur[2] == RTPATH_SLASH)
     47        pszCur += 3;
     48# ifdef HAVE_UNC
     49    else if (pszCur[0] == RTPATH_SLASH && pszCur[1] == RTPATH_SLASH)
     50    {
     51        pszCur += 2;
     52        while (*pszCur == RTPATH_SLASH)
     53            pszCur++;
     54        if (*pszCur)
     55        {
     56            while (*pszCur != RTPATH_SLASH && *pszCur)
     57                pszCur++;
     58            if (*pszCur == RTPATH_SLASH)
     59            {
     60                pszCur++;
     61                while (*pszCur != RTPATH_SLASH && *pszCur)
     62                    pszCur++;
     63                if (*pszCur == RTPATH_SLASH)
     64                    pszCur++;
     65            }
     66        }
     67    }
     68# endif
     69#else
     70    if (pszCur[0] == RTPATH_SLASH)
     71        pszCur += 1;
     72#endif
     73    return pszCur;
    7974}
    8075
     
    8277/**
    8378 * Cleans up a path specifier a little bit.
     79 *
    8480 * This includes removing duplicate slashes, unnecessary single dots, and
    85  * trailing slashes. Also, replaces all RTPATH_SLASH characters with '/'.
    86  *
    87  * @returns Number of bytes in the clean path.
     81 * trailing slashes. Also, replaces all slash characters with RTPATH_SLASH.
     82 *
     83 * @returns Length of the cleaned path (in chars).
    8884 * @param   pszPath     The path to cleanup.
    8985 */
    9086static int fsCleanPath(char *pszPath)
    9187{
    92     /*
    93      * Change to '/' and remove duplicates.
    94      */
    95     char   *pszSrc = pszPath;
    96     char   *pszTrg = pszPath;
     88    char *pszSrc = pszPath;
     89    char *pszTrg = pszPath;
     90
     91    /*
     92     * On windows, you either use on or two slashes at the head of a path,
     93     * seems like it treats additional slashes as part of the UNC server name.
     94     * Just change slashes to RTPATH_SLASH and skip them.
     95     */
     96    /** @todo check how OS/2 treats unnecessary leading slashes */
     97    int cchIgnoreLeading = 0;
    9798#ifdef HAVE_UNC
    98     int     fUnc = 0;
    99     if (    RTPATH_IS_SLASH(pszPath[0])
    100         &&  RTPATH_IS_SLASH(pszPath[1]))
    101     {   /* Skip first slash in a unc path. */
    102         pszSrc++;
    103         *pszTrg++ = '/';
    104         fUnc = 1;
    105     }
    106 #endif
    107 
     99    if (   RTPATH_IS_SLASH(pszSrc[0])
     100        && RTPATH_IS_SLASH(pszSrc[1]))
     101    {
     102        pszTrg[0] = RTPATH_SLASH;
     103        pszTrg[1] = RTPATH_SLASH;
     104        pszTrg += 2;
     105        pszSrc += 2;
     106        cchIgnoreLeading = 1;
     107        while (RTPATH_IS_SLASH(*pszSrc))
     108        {
     109            cchIgnoreLeading++;
     110            pszSrc++;
     111            *pszTrg++ = RTPATH_SLASH;
     112        }
     113    }
     114#endif
     115
     116    /*
     117     * Change slashes to RTPATH_SLASH and remove duplicates.
     118     */
    108119    for (;;)
    109120    {
     
    111122        if (RTPATH_IS_SLASH(ch))
    112123        {
    113             *pszTrg++ = '/';
     124            *pszTrg++ = RTPATH_SLASH;
    114125            for (;;)
    115126            {
    116                 do  ch = *pszSrc++;
     127                do
     128                    ch = *pszSrc++;
    117129                while (RTPATH_IS_SLASH(ch));
    118130
    119131                /* Remove '/./' and '/.'. */
    120                 if (ch != '.' || (*pszSrc && !RTPATH_IS_SLASH(*pszSrc)))
     132                if (   ch != '.'
     133                    || (*pszSrc && !RTPATH_IS_SLASH(*pszSrc)))
    121134                    break;
    122135            }
     
    128141    }
    129142
    130     /*
    131      * Remove trailing slash if the path may be pointing to a directory.
    132      */
    133     int cch = pszTrg - pszPath;
    134     if (    cch > 1
    135         &&  RTPATH_IS_SLASH(pszTrg[-1])
    136 #ifdef HAVE_DRIVE
    137         &&  !RTPATH_IS_VOLSEP(pszTrg[-2])
    138 #endif
    139         &&  !RTPATH_IS_SLASH(pszTrg[-2]))
    140         pszPath[--cch] = '\0';
    141 
    142     return cch;
     143    return pszTrg - pszPath;
    143144}
    144145
     
    154155    AssertPtr(pszPath);
    155156    if (RT_UNLIKELY(!*pszPath))
    156         return VERR_INVALID_PARAMETER;
     157        return VERR_INVALID_PARAMETER; //VERR_INVALID_NAME;
    157158
    158159    /*
     
    160161     */
    161162    size_t cchPath = strlen(pszPath);
    162     if (cchPath > PATH_MAX)
     163    if (cchPath >= RTPATH_MAX)
    163164    {
    164165        LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cchAbsPath, VERR_FILENAME_TOO_LONG));
     
    166167    }
    167168
    168     char szTmpPath[PATH_MAX + 1];
     169    char szTmpPath[RTPATH_MAX];
    169170    memcpy(szTmpPath, pszPath, cchPath + 1);
    170171    size_t cchTmpPath = fsCleanPath(szTmpPath);
     
    173174     * Handle "." specially (fsCleanPath does).
    174175     */
    175     if (szTmpPath[0] == '.' && !szTmpPath[1])
    176         return RTPathGetCurrent(pszAbsPath, cchAbsPath);
    177 
    178     /*
    179      * Do we have a root slash?
    180      */
    181     char *pszCur = szTmpPath;
     176    if (szTmpPath[0] == '.')
     177    {
     178        if (   cchTmpPath == 1
     179            || (cchTmpPath == 2 && szTmpPath[1] == RTPATH_SLASH))
     180        {
     181            rc = RTPathGetCurrent(pszAbsPath, cchAbsPath);
     182            if (RT_SUCCESS(rc))
     183            {
     184                size_t cch = fsCleanPath(pszAbsPath);
     185                char  *pszTop = rtPathSkipRootSpec(pszAbsPath);
     186#if 1
     187                if ((uintptr_t)&pszAbsPath[cch] > (uintptr_t)pszTop && pszAbsPath[cch - 1] == RTPATH_SLASH)
     188                    pszAbsPath[cch - 1] = '\0';
     189#else
     190                if (   cchTmpPath == 2
     191                    && (uintptr_t)&pszAbsPath[cch - 1] > (uintptr_t)pszTop && pszAbsPath[cch - 1] != RTPATH_SLASH)
     192                {
     193                    if (cch + 1 < cchAbsPath)
     194                    {
     195                        pszAbsPath[cch++] = RTPATH_SLASH;
     196                        pszAbsPath[cch] = '\0';
     197                    }
     198                    else
     199                        rc = VERR_BUFFER_OVERFLOW;
     200                }
     201#endif
     202            }
     203            return rc;
     204        }
     205    }
     206
     207    /*
     208     * Do we have an incomplete root spec?  Supply the missing bits.
     209     */
    182210#ifdef HAVE_DRIVE
    183     if (pszCur[0] && RTPATH_IS_VOLSEP(pszCur[1]) && pszCur[2] == '/')
    184         pszCur += 3;
     211    if (   !(szTmpPath[0] && RTPATH_IS_VOLSEP(szTmpPath[1]) && szTmpPath[2] == RTPATH_SLASH)
    185212# ifdef HAVE_UNC
    186     else if (pszCur[0] == '/' && pszCur[1] == '/')
    187         pszCur += 2;
     213        && !(szTmpPath[0] == RTPATH_SLASH && szTmpPath[1] == RTPATH_SLASH)
    188214# endif
    189 #else  /* !HAVE_DRIVE */
    190     if (pszCur[0] == '/')
    191         pszCur += 1;
    192 #endif /* !HAVE_DRIVE */
    193     else
    194     {
    195         /*
    196          * No, prepend the current directory to the relative path.
    197          */
    198         char szCurDir[RTPATH_MAX];
    199         rc = RTPathGetCurrent(szCurDir, sizeof(szCurDir));
    200         AssertRCReturn(rc, rc);
    201 
    202         size_t cchCurDir = fsCleanPath(szCurDir); /* paranoia */
    203         if (cchCurDir + cchTmpPath + 1 > PATH_MAX)
    204         {
    205             LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cchAbsPath, VERR_FILENAME_TOO_LONG));
    206             return VERR_FILENAME_TOO_LONG;
    207         }
    208 
    209         memmove(szTmpPath + cchCurDir + 1, szTmpPath, cchTmpPath + 1);
    210         memcpy(szTmpPath, szCurDir, cchCurDir);
    211         szTmpPath[cchCurDir] = '/';
    212 
    213 
     215        )
     216#else
     217    if (szTmpPath[0] != RTPATH_SLASH)
     218#endif
     219    {
     220        char    szCurDir[RTPATH_MAX];
     221        size_t  cchCurDir;
     222        int     offApplyAt;
     223        bool    fNeedSlash;
    214224#ifdef HAVE_DRIVE
    215         if (pszCur[0] && RTPATH_IS_VOLSEP(pszCur[1]) && pszCur[2] == '/')
    216             pszCur += 3;
     225        if (szTmpPath[0] && RTPATH_IS_VOLSEP(szTmpPath[1]) && szTmpPath[2] != RTPATH_SLASH)
     226        {
     227            /*
     228             * Relative to drive specific current directory.
     229             */
     230            rc = RTPathGetCurrentOnDrive(szTmpPath[0], szCurDir, sizeof(szCurDir));
     231            fNeedSlash = true;
     232            offApplyAt = 2;
     233        }
    217234# ifdef HAVE_UNC
    218         else if (pszCur[0] == '/' && pszCur[1] == '/')
    219             pszCur += 2;
     235        else if (szTmpPath[0] == RTPATH_SLASH && szTmpPath[1] != RTPATH_SLASH)
     236# else
     237        else if (szTmpPath[0] == RTPATH_SLASH)
    220238# endif
    221 #else
    222         if (pszCur[0] == '/')
    223             pszCur += 1;
    224 #endif
     239        {
     240            /*
     241             * Root of current drive.  This may return a UNC root if we're not
     242             * standing on a drive but on a UNC share.
     243             */
     244            rc = RTPathGetCurrentDrive(szCurDir, sizeof(szCurDir));
     245            fNeedSlash = false;
     246            offApplyAt = 0;
     247        }
    225248        else
    226             AssertMsgFailedReturn(("pszCur=%s\n", pszCur), VERR_INTERNAL_ERROR);
    227     }
    228 
    229     char *pszTop = pszCur;
     249#endif
     250        {
     251            /*
     252             * Relative to current directory.
     253             */
     254            rc = RTPathGetCurrent(szCurDir, sizeof(szCurDir));
     255            fNeedSlash = true;
     256            offApplyAt = 0;
     257        }
     258        if (RT_SUCCESS(rc))
     259        {
     260            cchCurDir = fsCleanPath(szCurDir);
     261            if (fNeedSlash && cchCurDir > 0 && szCurDir[cchCurDir - 1] == RTPATH_SLASH)
     262                fNeedSlash = false;
     263
     264            if (cchCurDir + fNeedSlash + cchTmpPath - offApplyAt <= RTPATH_MAX)
     265            {
     266                memmove(szTmpPath + cchCurDir + fNeedSlash, szTmpPath + offApplyAt, cchTmpPath + 1 - offApplyAt);
     267                memcpy(szTmpPath, szCurDir, cchCurDir);
     268                if (fNeedSlash)
     269                    szTmpPath[cchCurDir] = RTPATH_SLASH;
     270            }
     271            else
     272                rc = VERR_FILENAME_TOO_LONG;
     273        }
     274        if (RT_FAILURE(rc))
     275        {
     276            LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cchAbsPath, rc));
     277            return rc;
     278        }
     279    }
     280
     281    /*
     282     * Skip past the root spec.
     283     */
     284    char *pszCur = rtPathSkipRootSpec(szTmpPath);
     285    AssertMsgReturn(pszCur != &szTmpPath[0], ("pszCur=%s\n", pszCur), VERR_INTERNAL_ERROR);
     286    char * const pszTop = pszCur;
    230287
    231288    /*
     
    236293        if (   pszCur[0] == '.'
    237294            && pszCur[1] == '.'
    238             && (!pszCur[2] || pszCur[2] == '/'))
     295            && (!pszCur[2] || pszCur[2] == RTPATH_SLASH))
    239296        {
    240297            /* rewind to the previous component if any */
    241             char *pszPrev = pszCur - 1;
    242             if (pszPrev > pszTop)
    243                 while (*--pszPrev != '/')
    244                     ;
    245 
    246             AssertMsg(*pszPrev == '/', ("szTmpPath={%s}, pszPrev=+%u\n", szTmpPath, pszPrev - szTmpPath));
    247             memmove(pszPrev, pszCur + 2, strlen(pszCur + 2) + 1);
    248 
    249             pszCur = pszPrev;
     298            char *pszPrev = pszCur;
     299            if ((uintptr_t)pszPrev > (uintptr_t)pszTop)
     300            {
     301                pszPrev--;
     302                while (   (uintptr_t)pszPrev > (uintptr_t)pszTop
     303                       && pszPrev[-1] != RTPATH_SLASH)
     304                    pszPrev--;
     305            }
     306            if (!pszCur[2])
     307            {
     308                if (pszPrev != pszTop)
     309                    pszPrev[-1] = '\0';
     310                else
     311                    *pszPrev = '\0';
     312                break;
     313            }
     314            Assert(pszPrev[-1] == RTPATH_SLASH);
     315            memmove(pszPrev, pszCur + 3, strlen(pszCur + 3) + 1);
     316            pszCur = pszPrev - 1;
    250317        }
    251318        else
    252319        {
    253320            /* advance to end of component. */
    254             while (*pszCur && *pszCur != '/')
     321            while (*pszCur && *pszCur != RTPATH_SLASH)
    255322                pszCur++;
    256323        }
     
    263330    }
    264331
    265     if (pszCur < pszTop)
    266     {
    267         /*
    268          * We overwrote the root slash with '\0', restore it.
    269          */
    270         *pszCur++ = '/';
    271         *pszCur = '\0';
    272     }
    273     else if (pszCur > pszTop && pszCur[-1] == '/')
    274     {
    275         /*
    276          * Extra trailing slash in a non-root path, remove it.
    277          * (A bit questionable...)
    278          */
    279         *--pszCur = '\0';
    280     }
     332    cchTmpPath = pszCur - szTmpPath;
     333
     334#if 1
     335    /*
     336     * Strip trailing slash if that's what's desired.
     337     */
     338
     339    if ((uintptr_t)&szTmpPath[cchTmpPath] > (uintptr_t)pszTop && szTmpPath[cchTmpPath - 1] == RTPATH_SLASH)
     340        szTmpPath[--cchTmpPath] = '\0';
     341#endif
    281342
    282343    /*
    283344     * Copy the result to the user buffer.
    284345     */
    285     cchTmpPath = pszCur - szTmpPath;
    286346    if (cchTmpPath < cchAbsPath)
    287347    {
     
    297357}
    298358
    299 
    300 RTR3DECL(int) RTPathSetMode(const char *pszPath, RTFMODE fMode)
    301 {
    302     AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
    303     AssertReturn(*pszPath, VERR_INVALID_PARAMETER);
    304 
    305     int rc;
    306     fMode = rtFsModeNormalize(fMode, pszPath, 0);
    307     if (rtFsModeIsValidPermissions(fMode))
    308     {
    309         char const *pszNativePath;
    310         rc = rtPathToNative(&pszNativePath, pszPath, NULL);
    311         if (RT_SUCCESS(rc))
    312         {
    313             if (chmod(pszNativePath, fMode & RTFS_UNIX_MASK) != 0)
    314                 rc = RTErrConvertFromErrno(errno);
    315             rtPathFreeNative(pszNativePath, pszPath);
    316         }
    317     }
    318     else
    319     {
    320         AssertMsgFailed(("Invalid file mode! %RTfmode\n", fMode));
    321         rc = VERR_INVALID_FMODE;
    322     }
    323     return rc;
    324 }
    325 
    326 
    327 /**
    328  * Checks if two files are the one and same file.
    329  */
    330 static bool rtPathSame(const char *pszNativeSrc, const char *pszNativeDst)
    331 {
    332     struct stat SrcStat;
    333     if (lstat(pszNativeSrc, &SrcStat))
    334         return false;
    335     struct stat DstStat;
    336     if (lstat(pszNativeDst, &DstStat))
    337         return false;
    338     Assert(SrcStat.st_dev && DstStat.st_dev);
    339     Assert(SrcStat.st_ino && DstStat.st_ino);
    340     if (    SrcStat.st_dev == DstStat.st_dev
    341         &&  SrcStat.st_ino == DstStat.st_ino
    342         &&  (SrcStat.st_mode & S_IFMT) == (DstStat.st_mode & S_IFMT))
    343         return true;
    344     return false;
    345 }
    346 
    347 
    348 /**
    349  * Worker for RTPathRename, RTDirRename, RTFileRename.
    350  *
    351  * @returns IPRT status code.
    352  * @param   pszSrc      The source path.
    353  * @param   pszDst      The destination path.
    354  * @param   fRename     The rename flags.
    355  * @param   fFileType   The filetype. We use the RTFMODE filetypes here. If it's 0,
    356  *                      anything goes. If it's RTFS_TYPE_DIRECTORY we'll check that the
    357  *                      source is a directory. If Its RTFS_TYPE_FILE we'll check that it's
    358  *                      not a directory (we are NOT checking whether it's a file).
    359  */
    360 DECLHIDDEN(int) rtPathPosixRename(const char *pszSrc, const char *pszDst, unsigned fRename, RTFMODE fFileType)
    361 {
    362     /*
    363      * Convert the paths.
    364      */
    365     char const *pszNativeSrc;
    366     int rc = rtPathToNative(&pszNativeSrc, pszSrc, NULL);
    367     if (RT_SUCCESS(rc))
    368     {
    369         char const *pszNativeDst;
    370         rc = rtPathToNative(&pszNativeDst, pszDst, NULL);
    371         if (RT_SUCCESS(rc))
    372         {
    373             /*
    374              * Check that the source exists and that any types that's specified matches.
    375              * We have to check this first to avoid getting errnous VERR_ALREADY_EXISTS
    376              * errors from the next step.
    377              *
    378              * There are race conditions here (perhaps unlikely ones, but still), but I'm
    379              * afraid there is little with can do to fix that.
    380              */
    381             struct stat SrcStat;
    382             if (lstat(pszNativeSrc, &SrcStat))
    383                 rc = RTErrConvertFromErrno(errno);
    384             else if (!fFileType)
    385                 rc = VINF_SUCCESS;
    386             else if (RTFS_IS_DIRECTORY(fFileType))
    387                 rc = S_ISDIR(SrcStat.st_mode) ? VINF_SUCCESS : VERR_NOT_A_DIRECTORY;
    388             else
    389                 rc = S_ISDIR(SrcStat.st_mode) ? VERR_IS_A_DIRECTORY : VINF_SUCCESS;
    390             if (RT_SUCCESS(rc))
    391             {
    392                 bool fSameFile = false;
    393 
    394                 /*
    395                  * Check if the target exists, rename is rather destructive.
    396                  * We'll have to make sure we don't overwrite the source!
    397                  * Another race condition btw.
    398                  */
    399                 struct stat DstStat;
    400                 if (lstat(pszNativeDst, &DstStat))
    401                     rc = errno == ENOENT ? VINF_SUCCESS : RTErrConvertFromErrno(errno);
    402                 else
    403                 {
    404                     Assert(SrcStat.st_dev && DstStat.st_dev);
    405                     Assert(SrcStat.st_ino && DstStat.st_ino);
    406                     if (    SrcStat.st_dev == DstStat.st_dev
    407                         &&  SrcStat.st_ino == DstStat.st_ino
    408                         &&  (SrcStat.st_mode & S_IFMT) == (DstStat.st_mode & S_IFMT))
    409                     {
    410                         /*
    411                          * It's likely that we're talking about the same file here.
    412                          * We should probably check paths or whatever, but for now this'll have to be enough.
    413                          */
    414                         fSameFile = true;
    415                     }
    416                     if (fSameFile)
    417                         rc = VINF_SUCCESS;
    418                     else if (S_ISDIR(DstStat.st_mode) || !(fRename & RTPATHRENAME_FLAGS_REPLACE))
    419                         rc = VERR_ALREADY_EXISTS;
    420                     else
    421                         rc = VINF_SUCCESS;
    422 
    423                 }
    424                 if (RT_SUCCESS(rc))
    425                 {
    426                     if (!rename(pszNativeSrc, pszNativeDst))
    427                         rc = VINF_SUCCESS;
    428                     else if (   (fRename & RTPATHRENAME_FLAGS_REPLACE)
    429                              && (errno == ENOTDIR || errno == EEXIST))
    430                     {
    431                         /*
    432                          * Check that the destination isn't a directory.
    433                          * Yet another race condition.
    434                          */
    435                         if (rtPathSame(pszNativeSrc, pszNativeDst))
    436                         {
    437                             rc = VINF_SUCCESS;
    438                             Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): appears to be the same file... (errno=%d)\n",
    439                                  pszSrc, pszDst, fRename, fFileType, errno));
    440                         }
    441                         else
    442                         {
    443                             if (lstat(pszNativeDst, &DstStat))
    444                                 rc = errno != ENOENT ? RTErrConvertFromErrno(errno) : VINF_SUCCESS;
    445                             else if (S_ISDIR(DstStat.st_mode))
    446                                 rc = VERR_ALREADY_EXISTS;
    447                             else
    448                                 rc = VINF_SUCCESS;
    449                             if (RT_SUCCESS(rc))
    450                             {
    451                                 if (!unlink(pszNativeDst))
    452                                 {
    453                                     if (!rename(pszNativeSrc, pszNativeDst))
    454                                         rc = VINF_SUCCESS;
    455                                     else
    456                                     {
    457                                         rc = RTErrConvertFromErrno(errno);
    458                                         Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): rename failed rc=%Rrc errno=%d\n",
    459                                              pszSrc, pszDst, fRename, fFileType, rc, errno));
    460                                     }
    461                                 }
    462                                 else
    463                                 {
    464                                     rc = RTErrConvertFromErrno(errno);
    465                                     Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): failed to unlink dst rc=%Rrc errno=%d\n",
    466                                          pszSrc, pszDst, fRename, fFileType, rc, errno));
    467                                 }
    468                             }
    469                             else
    470                                 Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): dst !dir check failed rc=%Rrc\n",
    471                                      pszSrc, pszDst, fRename, fFileType, rc));
    472                         }
    473                     }
    474                     else
    475                     {
    476                         rc = RTErrConvertFromErrno(errno);
    477                         if (errno == ENOTDIR)
    478                             rc = VERR_ALREADY_EXISTS; /* unless somebody is racing us, this is the right interpretation */
    479                         Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): rename failed rc=%Rrc errno=%d\n",
    480                              pszSrc, pszDst, fRename, fFileType, rc, errno));
    481                     }
    482                 }
    483                 else
    484                     Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): destination check failed rc=%Rrc errno=%d\n",
    485                          pszSrc, pszDst, fRename, fFileType, rc, errno));
    486             }
    487             else
    488                 Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): source type check failed rc=%Rrc errno=%d\n",
    489                      pszSrc, pszDst, fRename, fFileType, rc, errno));
    490 
    491             rtPathFreeNative(pszNativeDst, pszDst);
    492         }
    493         rtPathFreeNative(pszNativeSrc, pszSrc);
    494     }
    495     return rc;
    496 }
    497 
    498 
    499 RTR3DECL(int) RTPathRename(const char *pszSrc, const char *pszDst, unsigned fRename)
    500 {
    501     /*
    502      * Validate input.
    503      */
    504     AssertMsgReturn(VALID_PTR(pszSrc), ("%p\n", pszSrc), VERR_INVALID_POINTER);
    505     AssertMsgReturn(VALID_PTR(pszDst), ("%p\n", pszDst), VERR_INVALID_POINTER);
    506     AssertMsgReturn(*pszSrc, ("%p\n", pszSrc), VERR_INVALID_PARAMETER);
    507     AssertMsgReturn(*pszDst, ("%p\n", pszDst), VERR_INVALID_PARAMETER);
    508     AssertMsgReturn(!(fRename & ~RTPATHRENAME_FLAGS_REPLACE), ("%#x\n", fRename), VERR_INVALID_PARAMETER);
    509 
    510     /*
    511      * Hand it to the worker.
    512      */
    513     int rc = rtPathPosixRename(pszSrc, pszDst, fRename, 0);
    514 
    515     Log(("RTPathRename(%p:{%s}, %p:{%s}, %#x): returns %Rrc\n", pszSrc, pszSrc, pszDst, pszDst, fRename, rc));
    516     return rc;
    517 }
    518 
    519 
    520 RTR3DECL(int) RTPathUnlink(const char *pszPath, uint32_t fUnlink)
    521 {
    522     return VERR_NOT_IMPLEMENTED;
    523 }
    524 
    525 
    526 RTDECL(bool) RTPathExists(const char *pszPath)
    527 {
    528     return RTPathExistsEx(pszPath, RTPATH_F_FOLLOW_LINK);
    529 }
    530 
    531 
    532 RTDECL(bool) RTPathExistsEx(const char *pszPath, uint32_t fFlags)
    533 {
    534     /*
    535      * Validate input.
    536      */
    537     AssertPtrReturn(pszPath, false);
    538     AssertReturn(*pszPath, false);
    539     Assert(RTPATH_F_IS_VALID(fFlags, 0));
    540 
    541     /*
    542      * Convert the path and check if it exists using stat().
    543      */
    544     char const *pszNativePath;
    545     int rc = rtPathToNative(&pszNativePath, pszPath, NULL);
    546     if (RT_SUCCESS(rc))
    547     {
    548         struct stat Stat;
    549         if (fFlags & RTPATH_F_FOLLOW_LINK)
    550             rc = stat(pszNativePath, &Stat);
    551         else
    552             rc = lstat(pszNativePath, &Stat);
    553         if (!rc)
    554             rc = VINF_SUCCESS;
    555         else
    556             rc = VERR_GENERAL_FAILURE;
    557         rtPathFreeNative(pszNativePath, pszPath);
    558     }
    559     return RT_SUCCESS(rc);
    560 }
    561 
    562 
    563 RTDECL(int)  RTPathGetCurrent(char *pszPath, size_t cchPath)
    564 {
    565     int rc;
    566     char szNativeCurDir[RTPATH_MAX];
    567     if (getcwd(szNativeCurDir, sizeof(szNativeCurDir)) != NULL)
    568         rc = rtPathFromNativeCopy(pszPath, cchPath, szNativeCurDir, NULL);
    569     else
    570         rc = RTErrConvertFromErrno(errno);
    571     return rc;
    572 }
    573 
    574 
    575 RTDECL(int) RTPathSetCurrent(const char *pszPath)
    576 {
    577     /*
    578      * Validate input.
    579      */
    580     AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
    581     AssertReturn(*pszPath, VERR_INVALID_PARAMETER);
    582 
    583     /*
    584      * Change the directory.
    585      */
    586     char const *pszNativePath;
    587     int rc = rtPathToNative(&pszNativePath, pszPath, NULL);
    588     if (RT_SUCCESS(rc))
    589     {
    590         if (chdir(pszNativePath))
    591             rc = RTErrConvertFromErrno(errno);
    592         rtPathFreeNative(pszNativePath, pszPath);
    593     }
    594     return rc;
    595 }
    596 
  • trunk/src/VBox/Runtime/r3/nt/internal-r3-nt.h

    r49150 r52944  
    2929#define ___internal_r3_nt_h___
    3030
    31 
    32 #include <iprt/nt/nt.h>
     31#ifdef IN_SUP_HARDENED_R3
     32# include <iprt/nt/nt-and-windows.h>
     33#else
     34# include <iprt/nt/nt.h>
     35#endif
    3336#include "internal/iprt.h"
    3437
  • trunk/src/VBox/Runtime/r3/nt/pathint-nt.cpp

    r49150 r52944  
    3838
    3939
    40 
    41 /**
    42  * Handles the pass thru case.
     40/*******************************************************************************
     41*   Global Variables                                                           *
     42*******************************************************************************/
     43static char const g_szPrefixUnc[] = "\\??\\UNC\\";
     44static char const g_szPrefix[]    = "\\??\\";
     45
     46
     47/**
     48 * Handles the pass thru case for UTF-8 input.
    4349 *
    4450 * @returns IPRT status code.
     
    4753 * @param   pszPath             The UTF-8 path.
    4854 */
    49 static int rtNtPathToNativePassThruWin(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
     55static int rtNtPathFromWinUtf8PassThru(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
    5056{
    5157    PRTUTF16 pwszPath = NULL;
     
    6167
    6268            pNtName->Buffer = pwszPath;
    63             pNtName->MaximumLength = pNtName->Length = (uint16_t)(cwcLen * 2);
     69            pNtName->Length = (uint16_t)(cwcLen * sizeof(RTUTF16));
     70            pNtName->MaximumLength = pNtName->Length + sizeof(RTUTF16);
    6471            *phRootDir = NULL;
    6572            return VINF_SUCCESS;
     
    7178    return rc;
    7279}
     80
     81
     82/**
     83 * Handles the pass thru case for UTF-16 input.
     84 *
     85 * @returns IPRT status code.
     86 * @param   pNtName             Where to return the NT name.
     87 * @param   phRootDir           Stores NULL here, as we don't use it.
     88 * @param   pwszWinPath         The UTF-16 windows-style path.
     89 * @param   cwcWinPath          The length of the windows-style input path.
     90 */
     91static int rtNtPathFromWinUtf16PassThru(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir,
     92                                        PCRTUTF16 pwszWinPath, size_t cwcWinPath)
     93{
     94    /* Drop a character because: \\?\ -> \.\ */
     95    pwszWinPath++;
     96    cwcWinPath--;
     97
     98    /* Check length and allocate memory for it. */
     99    int rc;
     100    if (cwcWinPath < _32K - 1)
     101    {
     102        PRTUTF16 pwszNtPath = (PRTUTF16)RTUtf16Alloc((cwcWinPath + 1) * sizeof(RTUTF16));
     103        if (pwszNtPath)
     104        {
     105            /* Intialize the path. */
     106            pwszNtPath[0] = '\\';
     107            pwszNtPath[1] = '.';
     108            pwszNtPath[2] = '\\';
     109            memcpy(pwszNtPath + 3, pwszWinPath + 3, (cwcWinPath - 3) * sizeof(RTUTF16));
     110            pwszNtPath[cwcWinPath] = '\0';
     111
     112            /* Initialize the return values. */
     113            pNtName->Buffer = pwszNtPath;
     114            pNtName->Length = (uint16_t)(cwcWinPath * sizeof(RTUTF16));
     115            pNtName->MaximumLength = pNtName->Length + sizeof(RTUTF16);
     116            *phRootDir = NULL;
     117
     118            rc = VINF_SUCCESS;
     119        }
     120        else
     121            rc = VERR_NO_UTF16_MEMORY;
     122    }
     123    else
     124        rc = VERR_FILENAME_TOO_LONG;
     125    return rc;
     126}
     127
     128
     129
    73130
    74131
     
    81138 * @param   pszPath             The UTF-8 path.
    82139 */
    83 static int rtNtPathToNativeToUtf16(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
     140static int rtNtPathUtf8ToUniStr(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
    84141{
    85142    PRTUTF16 pwszPath = NULL;
     
    91148        {
    92149            pNtName->Buffer = pwszPath;
    93             pNtName->MaximumLength = pNtName->Length = (uint16_t)(cwcLen * 2);
     150            pNtName->Length = (uint16_t)(cwcLen * sizeof(RTUTF16));
     151            pNtName->MaximumLength = pNtName->Length + sizeof(RTUTF16);
    94152            *phRootDir = NULL;
    95153            return VINF_SUCCESS;
     
    113171static int rtNtPathToNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
    114172{
    115     static char const s_szPrefixUnc[] = "\\??\\UNC\\";
    116     static char const s_szPrefix[]    = "\\??\\";
    117 
    118173    /*
    119174     * Very simple conversion of a win32-like path into an NT path.
    120175     */
    121     const char *pszPrefix = s_szPrefix;
    122     size_t      cchPrefix = sizeof(s_szPrefix) - 1;
     176    const char *pszPrefix = g_szPrefix;
     177    size_t      cchPrefix = sizeof(g_szPrefix) - 1;
    123178    size_t      cchSkip   = 0;
    124179
     
    130185        if (   pszPath[2] == '?'
    131186            && RTPATH_IS_SLASH(pszPath[3]))
    132             return rtNtPathToNativePassThruWin(pNtName, phRootDir, pszPath);
     187            return rtNtPathFromWinUtf8PassThru(pNtName, phRootDir, pszPath);
    133188
    134189#ifdef IPRT_WITH_NT_PATH_PASSTHRU
     
    136191        if (   pszPath[2] == '!'
    137192            && RTPATH_IS_SLASH(pszPath[3]))
    138             return rtNtPathToNativeToUtf16(pNtName, phRootDir, pszPath + 3);
     193            return rtNtPathUtf8ToUniStr(pNtName, phRootDir, pszPath + 3);
    139194#endif
    140195
     
    151206        {
    152207            /* UNC */
    153             pszPrefix = s_szPrefixUnc;
    154             cchPrefix = sizeof(s_szPrefixUnc) - 1;
     208            pszPrefix = g_szPrefixUnc;
     209            cchPrefix = sizeof(g_szPrefixUnc) - 1;
    155210            cchSkip   = 2;
    156211        }
     
    169224     */
    170225    memcpy(szPath, pszPrefix, cchPrefix);
    171     return rtNtPathToNativeToUtf16(pNtName, phRootDir, szPath);
     226    return rtNtPathUtf8ToUniStr(pNtName, phRootDir, szPath);
     227}
     228
     229
     230/**
     231 * Converts a UTF-16 windows-style path to NT format.
     232 *
     233 * @returns IPRT status code.
     234 * @param   pNtName             Where to return the NT name.  Free using
     235 *                              RTNtPathFree.
     236 * @param   phRootDir           Where to return the root handle, if applicable.
     237 * @param   pwszWinPath         The UTF-16 windows-style path.
     238 * @param   cwcWinPath          The max length of the windows-style path in
     239 *                              RTUTF16 units.  Use RTSTR_MAX if unknown and @a
     240 *                              pwszWinPath is correctly terminated.
     241 */
     242RTDECL(int) RTNtPathFromWinUtf16Ex(struct _UNICODE_STRING *pNtName, HANDLE *phRootDir, PCRTUTF16 pwszWinPath, size_t cwcWinPath)
     243{
     244    /*
     245     * Validate the input, calculating the correct length.
     246     */
     247    if (cwcWinPath == 0 || *pwszWinPath == '\0')
     248        return VERR_INVALID_NAME;
     249
     250    int rc = RTUtf16NLenEx(pwszWinPath, cwcWinPath, &cwcWinPath);
     251    if (RT_FAILURE(rc))
     252        return rc;
     253
     254    /*
     255     * Very simple conversion of a win32-like path into an NT path.
     256     */
     257    const char *pszPrefix = g_szPrefix;
     258    size_t      cchPrefix = sizeof(g_szPrefix) - 1;
     259    size_t      cchSkip   = 0;
     260
     261    if (   RTPATH_IS_SLASH(pwszWinPath[0])
     262        && cwcWinPath >= 3
     263        && RTPATH_IS_SLASH(pwszWinPath[1])
     264        && !RTPATH_IS_SLASH(pwszWinPath[2]) )
     265    {
     266        if (   pwszWinPath[2] == '?'
     267            && cwcWinPath >= 4
     268            && RTPATH_IS_SLASH(pwszWinPath[3]))
     269            return rtNtPathFromWinUtf16PassThru(pNtName, phRootDir, pwszWinPath, cwcWinPath);
     270
     271#ifdef IPRT_WITH_NT_PATH_PASSTHRU
     272        /* Special hack: The path starts with "\\\\!\\", we will skip past the bang and pass it thru. */
     273        if (   pwszWinPath[2] == '!'
     274            && cwcWinPath >= 4
     275            && RTPATH_IS_SLASH(pwszWinPath[3]))
     276        {
     277            pwszWinPath += 3;
     278            cwcWinPath  -= 3;
     279            if (cwcWinPath < _32K - 1)
     280            {
     281                PRTUTF16 pwszNtPath = RTUtf16Alloc((cwcWinPath + 1) * sizeof(RTUTF16));
     282                if (pwszNtPath)
     283                {
     284                    memcpy(pwszNtPath, pwszWinPath, cwcWinPath * sizeof(RTUTF16));
     285                    pwszNtPath[cwcWinPath] = '\0';
     286                    pNtName->Buffer = pwszNtPath;
     287                    pNtName->Length = (uint16_t)(cwcWinPath * sizeof(RTUTF16));
     288                    pNtName->MaximumLength = pNtName->Length + sizeof(RTUTF16);
     289                    *phRootDir = NULL;
     290                    return VINF_SUCCESS;
     291                }
     292                rc = VERR_NO_UTF16_MEMORY;
     293            }
     294            else
     295                rc = VERR_FILENAME_TOO_LONG;
     296            return rc;
     297        }
     298#endif
     299
     300        if (   pwszWinPath[2] == '.'
     301            && cwcWinPath >= 4
     302            && RTPATH_IS_SLASH(pwszWinPath[3]))
     303        {
     304            /*
     305             * Device path.
     306             * Note! I suspect \\.\stuff\..\otherstuff may be handled differently by windows.
     307             */
     308            cchSkip   = 4;
     309        }
     310        else
     311        {
     312            /* UNC */
     313            pszPrefix = g_szPrefixUnc;
     314            cchPrefix = sizeof(g_szPrefixUnc) - 1;
     315            cchSkip   = 2;
     316        }
     317    }
     318
     319    /*
     320     * Straighten out all .. and unnecessary . references and convert slashes.
     321     */
     322    char   szAbsPath[RTPATH_MAX];
     323    char   szRelPath[RTPATH_MAX];
     324    char  *pszRelPath = szRelPath;
     325    size_t cchRelPath;
     326    rc = RTUtf16ToUtf8Ex(pwszWinPath, cwcWinPath, &pszRelPath, sizeof(szRelPath), &cchRelPath);
     327    if (RT_SUCCESS(rc))
     328        rc = RTPathAbs(szRelPath, &szAbsPath[cchPrefix - cchSkip], sizeof(szAbsPath) - (cchPrefix - cchSkip));
     329    if (RT_SUCCESS(rc))
     330    {
     331        /*
     332         * Add prefix and convert it to UTF16.
     333         */
     334        memcpy(szAbsPath, pszPrefix, cchPrefix);
     335        return rtNtPathUtf8ToUniStr(pNtName, phRootDir, szAbsPath);
     336    }
     337    return rc;
    172338}
    173339
     
    181347 *                              rtNtPathToNative.
    182348 */
    183 void rtNtPathFreeNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir)
     349static void rtNtPathFreeNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir)
    184350{
    185351    RTUtf16Free(pNtName->Buffer);
    186352    pNtName->Buffer = NULL;
     353}
     354
     355
     356/**
     357 * Frees the native path and root handle.
     358 *
     359 * @param   pNtName             The NT path after a successful
     360 *                              RTNtPathFromWinUtf16Ex call.
     361 * @param   phRootDir           The root handle variable after a successfull
     362 *                              RTNtPathFromWinUtf16Ex call.
     363 */
     364RTDECL(void) RTNtPathFree(struct _UNICODE_STRING *pNtName, HANDLE *phRootDir)
     365{
     366    rtNtPathFreeNative(pNtName, phRootDir);
    187367}
    188368
  • trunk/src/VBox/Runtime/r3/posix/path-posix.cpp

    r48935 r52944  
    7676    LogFlow(("RTPathReal(%p:{%s}, %p:{%s}, %u): returns %Rrc\n", pszPath, pszPath,
    7777             pszRealPath, RT_SUCCESS(rc) ? pszRealPath : "<failed>",  cchRealPath, rc));
    78     return rc;
    79 }
    80 
    81 
    82 /**
    83  * Cleans up a path specifier a little bit.
    84  * This includes removing duplicate slashes, unnecessary single dots, and
    85  * trailing slashes. Also, replaces all RTPATH_SLASH characters with '/'.
    86  *
    87  * @returns Number of bytes in the clean path.
    88  * @param   pszPath     The path to cleanup.
    89  */
    90 static int fsCleanPath(char *pszPath)
    91 {
    92     /*
    93      * Change to '/' and remove duplicates.
    94      */
    95     char   *pszSrc = pszPath;
    96     char   *pszTrg = pszPath;
    97 #ifdef HAVE_UNC
    98     int     fUnc = 0;
    99     if (    RTPATH_IS_SLASH(pszPath[0])
    100         &&  RTPATH_IS_SLASH(pszPath[1]))
    101     {   /* Skip first slash in a unc path. */
    102         pszSrc++;
    103         *pszTrg++ = '/';
    104         fUnc = 1;
    105     }
    106 #endif
    107 
    108     for (;;)
    109     {
    110         char ch = *pszSrc++;
    111         if (RTPATH_IS_SLASH(ch))
    112         {
    113             *pszTrg++ = '/';
    114             for (;;)
    115             {
    116                 do  ch = *pszSrc++;
    117                 while (RTPATH_IS_SLASH(ch));
    118 
    119                 /* Remove '/./' and '/.'. */
    120                 if (ch != '.' || (*pszSrc && !RTPATH_IS_SLASH(*pszSrc)))
    121                     break;
    122             }
    123         }
    124         *pszTrg = ch;
    125         if (!ch)
    126             break;
    127         pszTrg++;
    128     }
    129 
    130     /*
    131      * Remove trailing slash if the path may be pointing to a directory.
    132      */
    133     int cch = pszTrg - pszPath;
    134     if (    cch > 1
    135         &&  RTPATH_IS_SLASH(pszTrg[-1])
    136 #ifdef HAVE_DRIVE
    137         &&  !RTPATH_IS_VOLSEP(pszTrg[-2])
    138 #endif
    139         &&  !RTPATH_IS_SLASH(pszTrg[-2]))
    140         pszPath[--cch] = '\0';
    141 
    142     return cch;
    143 }
    144 
    145 
    146 RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cchAbsPath)
    147 {
    148     int rc;
    149 
    150     /*
    151      * Validation.
    152      */
    153     AssertPtr(pszAbsPath);
    154     AssertPtr(pszPath);
    155     if (RT_UNLIKELY(!*pszPath))
    156         return VERR_INVALID_PARAMETER;
    157 
    158     /*
    159      * Make a clean working copy of the input.
    160      */
    161     size_t cchPath = strlen(pszPath);
    162     if (cchPath > PATH_MAX)
    163     {
    164         LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cchAbsPath, VERR_FILENAME_TOO_LONG));
    165         return VERR_FILENAME_TOO_LONG;
    166     }
    167 
    168     char szTmpPath[PATH_MAX + 1];
    169     memcpy(szTmpPath, pszPath, cchPath + 1);
    170     size_t cchTmpPath = fsCleanPath(szTmpPath);
    171 
    172     /*
    173      * Handle "." specially (fsCleanPath does).
    174      */
    175     if (szTmpPath[0] == '.' && !szTmpPath[1])
    176         return RTPathGetCurrent(pszAbsPath, cchAbsPath);
    177 
    178     /*
    179      * Do we have a root slash?
    180      */
    181     char *pszCur = szTmpPath;
    182 #ifdef HAVE_DRIVE
    183     if (pszCur[0] && RTPATH_IS_VOLSEP(pszCur[1]) && pszCur[2] == '/')
    184         pszCur += 3;
    185 # ifdef HAVE_UNC
    186     else if (pszCur[0] == '/' && pszCur[1] == '/')
    187         pszCur += 2;
    188 # endif
    189 #else  /* !HAVE_DRIVE */
    190     if (pszCur[0] == '/')
    191         pszCur += 1;
    192 #endif /* !HAVE_DRIVE */
    193     else
    194     {
    195         /*
    196          * No, prepend the current directory to the relative path.
    197          */
    198         char szCurDir[RTPATH_MAX];
    199         rc = RTPathGetCurrent(szCurDir, sizeof(szCurDir));
    200         AssertRCReturn(rc, rc);
    201 
    202         size_t cchCurDir = fsCleanPath(szCurDir); /* paranoia */
    203         if (cchCurDir + cchTmpPath + 1 > PATH_MAX)
    204         {
    205             LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cchAbsPath, VERR_FILENAME_TOO_LONG));
    206             return VERR_FILENAME_TOO_LONG;
    207         }
    208 
    209         memmove(szTmpPath + cchCurDir + 1, szTmpPath, cchTmpPath + 1);
    210         memcpy(szTmpPath, szCurDir, cchCurDir);
    211         szTmpPath[cchCurDir] = '/';
    212 
    213 
    214 #ifdef HAVE_DRIVE
    215         if (pszCur[0] && RTPATH_IS_VOLSEP(pszCur[1]) && pszCur[2] == '/')
    216             pszCur += 3;
    217 # ifdef HAVE_UNC
    218         else if (pszCur[0] == '/' && pszCur[1] == '/')
    219             pszCur += 2;
    220 # endif
    221 #else
    222         if (pszCur[0] == '/')
    223             pszCur += 1;
    224 #endif
    225         else
    226             AssertMsgFailedReturn(("pszCur=%s\n", pszCur), VERR_INTERNAL_ERROR);
    227     }
    228 
    229     char *pszTop = pszCur;
    230 
    231     /*
    232      * Get rid of double dot path components by evaluating them.
    233      */
    234     for (;;)
    235     {
    236         if (   pszCur[0] == '.'
    237             && pszCur[1] == '.'
    238             && (!pszCur[2] || pszCur[2] == '/'))
    239         {
    240             /* rewind to the previous component if any */
    241             char *pszPrev = pszCur - 1;
    242             if (pszPrev > pszTop)
    243                 while (*--pszPrev != '/')
    244                     ;
    245 
    246             AssertMsg(*pszPrev == '/', ("szTmpPath={%s}, pszPrev=+%u\n", szTmpPath, pszPrev - szTmpPath));
    247             memmove(pszPrev, pszCur + 2, strlen(pszCur + 2) + 1);
    248 
    249             pszCur = pszPrev;
    250         }
    251         else
    252         {
    253             /* advance to end of component. */
    254             while (*pszCur && *pszCur != '/')
    255                 pszCur++;
    256         }
    257 
    258         if (!*pszCur)
    259             break;
    260 
    261         /* skip the slash */
    262         ++pszCur;
    263     }
    264 
    265     if (pszCur < pszTop)
    266     {
    267         /*
    268          * We overwrote the root slash with '\0', restore it.
    269          */
    270         *pszCur++ = '/';
    271         *pszCur = '\0';
    272     }
    273     else if (pszCur > pszTop && pszCur[-1] == '/')
    274     {
    275         /*
    276          * Extra trailing slash in a non-root path, remove it.
    277          * (A bit questionable...)
    278          */
    279         *--pszCur = '\0';
    280     }
    281 
    282     /*
    283      * Copy the result to the user buffer.
    284      */
    285     cchTmpPath = pszCur - szTmpPath;
    286     if (cchTmpPath < cchAbsPath)
    287     {
    288         memcpy(pszAbsPath, szTmpPath, cchTmpPath + 1);
    289         rc = VINF_SUCCESS;
    290     }
    291     else
    292         rc = VERR_BUFFER_OVERFLOW;
    293 
    294     LogFlow(("RTPathAbs(%p:{%s}, %p:{%s}, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath,
    295              RT_SUCCESS(rc) ? pszAbsPath : "<failed>", cchAbsPath, rc));
    29678    return rc;
    29779}
  • trunk/src/VBox/Runtime/r3/win/path-win.cpp

    r48935 r52944  
    8989}
    9090
    91 
     91#if 0
    9292/**
    9393 * Get the absolute path (no symlinks, no . or .. components), doesn't have to exit.
     
    125125        if (RT_SUCCESS(rc))
    126126        {
     127# if 1 /** @todo This code is completely bonkers. */
    127128            /*
    128129             * Remove trailing slash if the path may be pointing to a directory.
     
    134135                &&  !RTPATH_IS_SLASH(pszAbsPath[cch - 2]))
    135136                pszAbsPath[cch - 1] = '\0';
     137# endif
    136138        }
    137139    }
     
    144146    return rc;
    145147}
     148#endif
    146149
    147150
     
    684687}
    685688
     689
     690RTDECL(int) RTPathGetCurrentOnDrive(char chDrive, char *pszPath, size_t cbPath)
     691{
     692    WCHAR wszInput[4];
     693    wszInput[0] = chDrive;
     694    wszInput[1] = ':';
     695    wszInput[2] = '\0';
     696
     697    int rc;
     698    RTUTF16 wszFullPath[RTPATH_MAX];
     699    if (GetFullPathNameW(wszInput, RTPATH_MAX, wszFullPath, NULL))
     700        rc = RTUtf16ToUtf8Ex(&wszFullPath[0], RTSTR_MAX, &pszPath, cbPath, NULL);
     701    else
     702        rc = RTErrConvertFromWin32(GetLastError());
     703    return rc;
     704}
     705
  • trunk/src/VBox/Runtime/testcase/tstRTPath.cpp

    r49084 r52944  
    315315    { "C:\\temp", "D:\\data", VINF_SUCCESS, "D:\\data" },
    316316    { NULL, "\\\\server\\..\\share", VINF_SUCCESS, "\\\\server\\..\\share" /* kind of strange */ },
    317     { NULL, "\\\\server/", VINF_SUCCESS, "\\\\server" },
     317    { NULL, "\\\\server/", VINF_SUCCESS, "\\\\server\\" },
    318318    { NULL, "\\\\", VINF_SUCCESS, "\\\\" },
    319319    { NULL, "\\\\\\something", VINF_SUCCESS, "\\\\\\something" /* kind of strange */ },
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