VirtualBox

Changeset 77684 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Mar 13, 2019 4:39:57 PM (6 years ago)
Author:
vboxsync
Message:

IPRT: Implemented RTFileOpenEx for posix too. ticketref:9276

Location:
trunk/src/VBox/Runtime
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r3/posix/fileio-posix.cpp

    r77234 r77684  
    6464#include <iprt/err.h>
    6565#include <iprt/log.h>
     66#include <iprt/thread.h>
    6667#include "internal/file.h"
    6768#include "internal/fs.h"
     
    8182
    8283
     84/*********************************************************************************************************************************
     85*   Defined Constants And Macros                                                                                                 *
     86*********************************************************************************************************************************/
     87#ifdef O_CLOEXEC
     88static int volatile g_fHave_O_CLOEXEC = 0; /* {-1,0,1}; since Linux 2.6.23 */
     89#endif
     90
     91
     92
    8393RTDECL(bool) RTFileExists(const char *pszPath)
    8494{
     
    100110
    101111
     112#ifdef O_CLOEXEC
     113/** Worker for RTFileOpenEx that detects whether the kernel supports
     114 *  O_CLOEXEC or not, setting g_fHave_O_CLOEXEC to 1 or -1 accordingly. */
     115static int rtFileOpenExDetectCloExecSupport(void)
     116{
     117    /*
     118     * Open /dev/null with O_CLOEXEC and see if FD_CLOEXEC is set or not.
     119     */
     120    int fHave_O_CLOEXEC = -1;
     121    int fd = open("/dev/null", O_RDONLY | O_CLOEXEC, 0);
     122    if (fd >= 0)
     123    {
     124        int fFlags = fcntl(fd, F_GETFD, 0);
     125        fHave_O_CLOEXEC = fFlags > 0 && (fFlags & FD_CLOEXEC) ? 1 : -1;
     126        close(fd);
     127    }
     128    else
     129        AssertMsg(errno == EINVAL, ("%d\n", errno));
     130    g_fHave_O_CLOEXEC = fHave_O_CLOEXEC;
     131    return fHave_O_CLOEXEC;
     132}
     133#endif
     134
     135
    102136RTR3DECL(int) RTFileOpen(PRTFILE pFile, const char *pszFilename, uint64_t fOpen)
    103137{
     138    return RTFileOpenEx(pszFilename, fOpen, pFile, NULL);
     139}
     140
     141
     142RTDECL(int)  RTFileOpenEx(const char *pszFilename, uint64_t fOpen, PRTFILE phFile, PRTFILEACTION penmActionTaken)
     143{
    104144    /*
    105145     * Validate input.
    106146     */
    107     AssertPtrReturn(pFile, VERR_INVALID_POINTER);
    108     *pFile = NIL_RTFILE;
     147    AssertPtrReturn(phFile, VERR_INVALID_POINTER);
     148    *phFile = NIL_RTFILE;
     149    if (penmActionTaken)
     150        *penmActionTaken = RTFILEACTION_INVALID;
    109151    AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
    110152
     
    116158        return rc;
    117159#ifndef O_NONBLOCK
    118     if (fOpen & RTFILE_O_NON_BLOCK)
    119     {
    120         AssertMsgFailed(("Invalid parameters! fOpen=%#llx\n", fOpen));
    121         return VERR_INVALID_PARAMETER;
    122     }
     160    AssertReturn(!(fOpen & RTFILE_O_NON_BLOCK), VERR_INVALID_FLAGS);
    123161#endif
    124162
     
    138176#endif
    139177#ifdef O_CLOEXEC
    140     static int s_fHave_O_CLOEXEC = 0; /* {-1,0,1}; since Linux 2.6.23 */
    141     if (!(fOpen & RTFILE_O_INHERIT) && s_fHave_O_CLOEXEC >= 0)
     178    int fHave_O_CLOEXEC = g_fHave_O_CLOEXEC;
     179    if (   !(fOpen & RTFILE_O_INHERIT)
     180        && (   fHave_O_CLOEXEC > 0
     181            || (   fHave_O_CLOEXEC == 0
     182                && (fHave_O_CLOEXEC = rtFileOpenExDetectCloExecSupport()) > 0)))
    142183        fOpenMode |= O_CLOEXEC;
    143184#endif
     
    168209        case RTFILE_O_CREATE:           fOpenMode |= O_CREAT | O_EXCL; break;
    169210        case RTFILE_O_CREATE_REPLACE:   fOpenMode |= O_CREAT | O_TRUNC; break; /** @todo replacing needs fixing, this is *not* a 1:1 mapping! */
    170     }
    171     if (fOpen & RTFILE_O_TRUNCATE)
     211        default:
     212            AssertMsgFailed(("fOpen=%#llx\n", fOpen));
     213            fOpen = (fOpen & ~RTFILE_O_ACTION_MASK) | RTFILE_O_OPEN;
     214            break;
     215
     216    }
     217    if (   (fOpen & RTFILE_O_TRUNCATE)
     218        && (fOpen & RTFILE_O_ACTION_MASK) != RTFILE_O_CREATE)
    172219        fOpenMode |= O_TRUNC;
    173220
     
    184231            break;
    185232        default:
    186             AssertMsgFailed(("RTFileOpen received an invalid RW value, fOpen=%#llx\n", fOpen));
    187             return VERR_INVALID_PARAMETER;
     233            AssertMsgFailedReturn(("RTFileOpen received an invalid RW value, fOpen=%#llx\n", fOpen), VERR_INVALID_FLAGS);
    188234    }
    189235
     
    193239              : RT_FILE_PERMISSION;
    194240
    195     /** @todo sharing! */
     241    /** @todo sharing? */
    196242
    197243    /*
     
    203249        return (rc);
    204250
    205     int fh = open(pszNativeFilename, fOpenMode, fMode);
    206     int iErr = errno;
    207 
    208 #ifdef O_CLOEXEC
    209     if (   (fOpenMode & O_CLOEXEC)
    210         && s_fHave_O_CLOEXEC == 0)
    211     {
    212         if (fh < 0 && iErr == EINVAL)
    213         {
    214             s_fHave_O_CLOEXEC = -1;
    215             fh = open(pszNativeFilename, fOpenMode, fMode);
    216             iErr = errno;
    217         }
    218         else if (fh >= 0)
    219             s_fHave_O_CLOEXEC = fcntl(fh, F_GETFD, 0) > 0 ? 1 : -1;
    220     }
    221 #endif
     251    int fh;
     252    int iErr;
     253    if (!penmActionTaken)
     254    {
     255        fh   = open(pszNativeFilename, fOpenMode, fMode);
     256        iErr = errno;
     257    }
     258    else
     259    {
     260        /* We need to know exactly which action was taken by open, Windows &
     261           OS/2 style.  Can be tedious and subject to races:  */
     262        switch (fOpen & RTFILE_O_ACTION_MASK)
     263        {
     264            case RTFILE_O_OPEN:
     265                Assert(!(fOpenMode & O_CREAT));
     266                Assert(!(fOpenMode & O_EXCL));
     267                fh   = open(pszNativeFilename, fOpenMode, fMode);
     268                iErr = errno;
     269                if (fh >= 0)
     270                    *penmActionTaken = fOpenMode & O_TRUNC ? RTFILEACTION_TRUNCATED : RTFILEACTION_OPENED;
     271                break;
     272
     273            case RTFILE_O_CREATE:
     274                Assert(fOpenMode & O_CREAT);
     275                Assert(fOpenMode & O_EXCL);
     276                fh   = open(pszNativeFilename, fOpenMode, fMode);
     277                iErr = errno;
     278                if (fh >= 0)
     279                    *penmActionTaken = RTFILEACTION_CREATED;
     280                else if (iErr == EEXIST)
     281                    *penmActionTaken = RTFILEACTION_ALREADY_EXISTS;
     282                break;
     283
     284            case RTFILE_O_OPEN_CREATE:
     285            case RTFILE_O_CREATE_REPLACE:
     286            {
     287                Assert(fOpenMode & O_CREAT);
     288                Assert(!(fOpenMode & O_EXCL));
     289                int iTries = 64;
     290                while (iTries-- > 0)
     291                {
     292                    /* Yield the CPU if we've raced too long. */
     293                    if (iTries < 4)
     294                        RTThreadSleep(2 - (iTries & 1));
     295
     296                    /* Try exclusive creation first: */
     297                    fh   = open(pszNativeFilename, fOpenMode | O_EXCL, fMode);
     298                    iErr = errno;
     299                    if (fh >= 0)
     300                    {
     301                        *penmActionTaken = RTFILEACTION_CREATED;
     302                        break;
     303                    }
     304                    if (iErr != EEXIST)
     305                        break;
     306
     307                    /* If the file exists, try open it: */
     308                    fh   = open(pszNativeFilename, fOpenMode & ~O_CREAT, fMode);
     309                    iErr = errno;
     310                    if (fh >= 0)
     311                    {
     312                        if ((fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE)
     313                            *penmActionTaken = fOpenMode & O_TRUNC ? RTFILEACTION_TRUNCATED : RTFILEACTION_OPENED;
     314                        else
     315                            *penmActionTaken = RTFILEACTION_REPLACED;
     316                        break;
     317                    }
     318                    if (iErr != ENOENT)
     319                        break;
     320                }
     321                Assert(iTries >= 0);
     322                if (iTries < 0)
     323                {
     324                    /* Thanks for the race, but we need to get on with things.  */
     325                    fh   = open(pszNativeFilename, fOpenMode, fMode);
     326                    iErr = errno;
     327                    if (fh >= 0)
     328                        *penmActionTaken = RTFILEACTION_OPENED;
     329                }
     330                break;
     331            }
     332
     333            default:
     334                AssertMsgFailed(("fOpen=%#llx fOpenMode=%#x\n", fOpen, fOpenMode));
     335                iErr = EINVAL;
     336                fh = -1;
     337                break;
     338        }
     339    }
    222340
    223341    rtPathFreeNative(pszNativeFilename, pszFilename);
     
    234352#endif
    235353#ifdef O_CLOEXEC
    236             &&  s_fHave_O_CLOEXEC <= 0
     354            &&  fHave_O_CLOEXEC <= 0
    237355#endif
    238356            )
     
    329447        if (iErr == 0)
    330448        {
    331             *pFile = (RTFILE)(uintptr_t)fh;
    332             Assert((intptr_t)*pFile == fh);
     449            *phFile = (RTFILE)(uintptr_t)fh;
     450            Assert((intptr_t)*phFile == fh);
    333451            LogFlow(("RTFileOpen(%p:{%RTfile}, %p:{%s}, %#llx): returns %Rrc\n",
    334                      pFile, *pFile, pszFilename, pszFilename, fOpen, rc));
     452                     phFile, *phFile, pszFilename, pszFilename, fOpen, rc));
    335453            return VINF_SUCCESS;
    336454        }
  • trunk/src/VBox/Runtime/testcase/Makefile.kmk

    r77681 r77684  
    7070        tstRTFileModeStringToFlags \
    7171        tstFileLock \
     72        tstRTFileOpenEx-1 \
    7273        tstFork \
    7374        tstRTFsQueries \
     
    160161        tstRTNtPath-1 \
    161162        ntGetTimerResolution \
    162         tstRTDarwinMachKernel \
    163         tstRTFileOpenEx-1
     163        tstRTDarwinMachKernel
    164164
    165165PROGRAMS.linux += \
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