VirtualBox

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


Ignore:
Timestamp:
Feb 7, 2018 2:05:43 PM (7 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
120716
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.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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.

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