VirtualBox

Changeset 70890 in vbox for trunk/src/VBox/Runtime/r3


Ignore:
Timestamp:
Feb 7, 2018 2:05:43 PM (7 years ago)
Author:
vboxsync
Message:

IPRT: dir.c,dir-posix.cpp,direnum-nt.cpp: Implemented RTDIR_F_NO_FOLLOW on posix, adjusted NT implementation and documented the VERR_IS_A_SYMLINK return code for the relevant APIs.

Location:
trunk/src/VBox/Runtime/r3
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r3/dir.cpp

    r69757 r70890  
    527527     * As a sideeffect we also validate the path here.
    528528     */
    529     char szRealPath[RTPATH_MAX + 1];
    530     int rc;
     529    char   szRealPath[RTPATH_MAX + 1];
     530    int    rc;
    531531    size_t cbFilter;                    /* includes '\0' (thus cb and not cch). */
    532532    size_t cucFilter0;                  /* includes U+0. */
     533    bool   fDirSlash = false;
    533534    if (!pszFilter)
    534535    {
     536        /* Note! RTPathAbs currently strips trailing slashes, so we have
     537           to inspect pszPath to figure it out. */
     538        if (*pszPath != '\0')
     539        {
     540            const char *pszLast = strchr(pszPath, '\0') - 1;
     541            if (RTPATH_IS_SLASH(*pszLast))
     542                fDirSlash = true;
     543        }
     544
    535545        cbFilter = cucFilter0 = 0;
    536546        rc = RTPathAbs(pszPath, szRealPath, sizeof(szRealPath) - 1);
     
    553563        else
    554564            rc = RTPathReal(".", szRealPath, sizeof(szRealPath) - 1);
     565        fDirSlash = true;
    555566    }
    556567    if (RT_FAILURE(rc))
     
    618629            break;
    619630    }
    620     pDir->cchPath = cchRealPath;
    621     pDir->pszPath = (char *)memcpy(pb, szRealPath, cchRealPath + 1);
     631    pDir->cchPath       = cchRealPath;
     632    pDir->pszPath       = (char *)memcpy(pb, szRealPath, cchRealPath + 1);
    622633    Assert(pb - (uint8_t *)pDir + cchRealPath + 1 <= cbAllocated);
    623     pDir->pszName = NULL;
    624     pDir->cchName = 0;
    625     pDir->fFlags  = fFlags;
    626     pDir->fDataUnread = false;
     634    pDir->pszName       = NULL;
     635    pDir->cchName       = 0;
     636    pDir->fFlags        = fFlags;
     637    pDir->fDirSlash     = fDirSlash;
     638    pDir->fDataUnread   = false;
    627639
    628640    /*
  • trunk/src/VBox/Runtime/r3/nt/direnum-r3-nt.cpp

    r70889 r70890  
    121121        uint32_t            fOptions         = FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT;
    122122        int fReparsePoints = g_fReparsePoints;
    123         if (fReparsePoints != 0 && (pDir->fFlags & RTDIR_F_NO_FOLLOW))
     123        if (   fReparsePoints != 0
     124            && (pDir->fFlags & RTDIR_F_NO_FOLLOW)
     125            && !pDir->fDirSlash)
    124126            fOptions |= FILE_OPEN_REPARSE_POINT;
    125127
  • trunk/src/VBox/Runtime/r3/posix/dir-posix.cpp

    r70884 r70890  
    3636#include <fcntl.h>
    3737#include <dirent.h>
     38#include <dlfcn.h>
    3839#include <stdio.h>
    3940
     
    4243
    4344#include <iprt/alloca.h>
     45#include <iprt/asm.h>
    4446#include <iprt/assert.h>
    4547#include <iprt/err.h>
     
    233235     * Convert to a native path and try opendir.
    234236     */
     237    char       *pszSlash = NULL;
    235238    char const *pszNativePath;
    236     int rc = rtPathToNative(&pszNativePath, pDir->pszPath, NULL);
     239    int         rc;
     240    if (   !(pDir->fFlags & RTDIR_F_NO_FOLLOW)
     241        || pDir->fDirSlash
     242        || pDir->cchPath <= 1)
     243        rc = rtPathToNative(&pszNativePath, pDir->pszPath, NULL);
     244    else
     245    {
     246        pszSlash = (char *)&pDir->pszPath[pDir->cchPath - 1];
     247        *pszSlash = '\0';
     248        rc = rtPathToNative(&pszNativePath, pDir->pszPath, NULL);
     249    }
    237250    if (RT_SUCCESS(rc))
    238251    {
    239         if (!(pDir->fFlags & RTDIR_F_NO_FOLLOW))
     252        if (   !(pDir->fFlags & RTDIR_F_NO_FOLLOW)
     253            || pDir->fDirSlash)
    240254            pDir->pDir = opendir(pszNativePath);
    241255        else
    242256        {
    243             AssertMsgFailed(("implement RTDIR_F_NO_FOLLOW\n"));
    244             pDir->pDir = opendir(pszNativePath);
     257            /*
     258             * If we can get fdopendir() and have both O_NOFOLLOW and O_DIRECTORY,
     259             * we will use open() to safely open the directory without following
     260             * symlinks in the final component, and then use fdopendir to get a DIR
     261             * from the file descriptor.
     262             *
     263             * If we cannot get that, we will use lstat() + opendir() as a fallback.
     264             *
     265             * We ASSUME that support for the O_NOFOLLOW and O_DIRECTORY flags is
     266             * older than fdopendir().
     267             */
     268#if defined(O_NOFOLLOW) && defined(O_DIRECTORY)
     269            /* Need to resolve fdopendir dynamically. */
     270            typedef DIR * (*PFNFDOPENDIR)(int);
     271            static PFNFDOPENDIR  s_pfnFdOpenDir = NULL;
     272            static bool volatile s_fInitalized = false;
     273
     274            PFNFDOPENDIR pfnFdOpenDir = s_pfnFdOpenDir;
     275            ASMCompilerBarrier();
     276            if (s_fInitalized)
     277            { /* likely */ }
     278            else
     279            {
     280                pfnFdOpenDir = (PFNFDOPENDIR)dlsym(RTLD_DEFAULT, "fdopendir");
     281                s_pfnFdOpenDir = pfnFdOpenDir;
     282                ASMAtomicWriteBool(&s_fInitalized, true);
     283            }
     284
     285            if (pfnFdOpenDir)
     286            {
     287                int fd = open(pszNativePath, O_RDONLY | O_DIRECTORY | O_NOFOLLOW, 0);
     288                if (fd >= 0)
     289                {
     290                    pDir->pDir = pfnFdOpenDir(fd);
     291                    if (RT_UNLIKELY(!pDir->pDir))
     292                    {
     293                        rc = RTErrConvertFromErrno(errno);
     294                        close(fd);
     295                    }
     296                }
     297                else
     298                {
     299                    /* WSL returns ELOOP here, but we take no chances that O_NOFOLLOW
     300                       takes precedence over O_DIRECTORY everywhere. */
     301                    int iErr = errno;
     302                    if (iErr == ELOOP || iErr == ENOTDIR)
     303                    {
     304                        struct stat St;
     305                        if (   lstat(pszNativePath, &St) == 0
     306                            && S_ISLNK(St.st_mode))
     307                            rc = VERR_IS_A_SYMLINK;
     308                        else
     309                            rc = RTErrConvertFromErrno(iErr);
     310                    }
     311                }
     312            }
     313            else
     314#endif
     315            {
     316                /* Fallback.  This contains a race condition. */
     317                struct stat St;
     318                if (   lstat(pszNativePath, &St) != 0
     319                    || !S_ISLNK(St.st_mode))
     320                    pDir->pDir = opendir(pszNativePath);
     321                else
     322                    rc = VERR_IS_A_SYMLINK;
     323            }
    245324        }
    246325        if (pDir->pDir)
     
    251330            pDir->fDataUnread = false; /* spelling it out */
    252331        }
    253         else
     332        else if (RT_SUCCESS_NP(rc))
    254333            rc = RTErrConvertFromErrno(errno);
    255334
    256335        rtPathFreeNative(pszNativePath, pDir->pszPath);
    257336    }
    258 
     337    if (pszSlash)
     338        *pszSlash = RTPATH_SLASH;
    259339    return rc;
    260340}
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