VirtualBox

Changeset 95977 in vbox


Ignore:
Timestamp:
Aug 2, 2022 1:23:43 AM (3 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
152735
Message:

IPRT/stream.cpp: Re-did the mode string handling in RTStrmOpen, switching to use fdopen instead of fopen, adding a few new options. bugref:10261

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/stream.h

    r95934 r95977  
    6262 * @param   pszFilename     Path to the file to open.
    6363 * @param   pszMode         The open mode. See fopen() standard.
    64  *                          Format: <a|r|w>[+][b]
     64 *                          Format: <a|r|w>[+][b|t][x][e|N|E]
     65 *                              - 'a': Open or create file and writes
     66 *                                append tos it.
     67 *                              - 'r': Open existing file and read from it.
     68 *                              - 'w': Open or truncate existing file and write
     69 *                                to it.
     70 *                              - '+': Open for both read and write access.
     71 *                              - 'b' / 't': binary / text
     72 *                              - 'x': exclusively create, no open. Only
     73 *                                possible with 'w'.
     74 *                              - 'e' / 'N': No inherit on exec.  (The 'e' is
     75 *                                how Linux and FreeBSD expresses this, the
     76 *                                latter is Visual C++).
    6577 * @param   ppStream        Where to store the opened stream.
    6678 */
     
    7284 * @returns iprt status code.
    7385 * @param   pszMode         The open mode. See fopen() standard.
    74  *                          Format: <a|r|w>[+][b]
     86 *                          Format: <a|r|w>[+][b|t][x][e|N|E]
     87 *                              - 'a': Open or create file and writes
     88 *                                append tos it.
     89 *                              - 'r': Open existing file and read from it.
     90 *                              - 'w': Open or truncate existing file and write
     91 *                                to it.
     92 *                              - '+': Open for both read and write access.
     93 *                              - 'b' / 't': binary / text
     94 *                              - 'x': exclusively create, no open. Only
     95 *                                possible with 'w'.
     96 *                              - 'e' / 'N': No inherit on exec.  (The 'e' is
     97 *                                how Linux and FreeBSD expresses this, the
     98 *                                latter is Visual C++).
    7599 * @param   ppStream        Where to store the opened stream.
    76100 * @param   pszFilenameFmt  Filename path format string.
     
    85109 * @returns iprt status code.
    86110 * @param   pszMode         The open mode. See fopen() standard.
    87  *                          Format: <a|r|w>[+][b]
     111 *                          Format: <a|r|w>[+][b|t][x][e|N|E]
     112 *                              - 'a': Open or create file and writes
     113 *                                append tos it.
     114 *                              - 'r': Open existing file and read from it.
     115 *                              - 'w': Open or truncate existing file and write
     116 *                                to it.
     117 *                              - '+': Open for both read and write access.
     118 *                              - 'b' / 't': binary / text
     119 *                              - 'x': exclusively create, no open. Only
     120 *                                possible with 'w'.
     121 *                              - 'e' / 'N': No inherit on exec.  (The 'e' is
     122 *                                how Linux and FreeBSD expresses this, the
     123 *                                latter is Visual C++).
    88124 * @param   ppStream        Where to store the opened stream.
    89125 * @param   pszFilenameFmt  Filename path format string.
  • trunk/src/VBox/Runtime/r3/stream.cpp

    r95943 r95977  
    6666#include <iprt/ctype.h>
    6767#include <iprt/err.h>
    68 #ifdef RTSTREAM_STANDALONE
    6968# include <iprt/file.h>
     69#ifdef RTSTREAM_STANDALONE
    7070# include <iprt/list.h>
    7171#endif
     
    410410 * @param   pszFilename     Path to the file to open.
    411411 * @param   pszMode         The open mode. See fopen() standard.
    412  *                          Format: <a|r|w>[+][b]
     412 *                          Format: <a|r|w>[+][b|t][x][e|N|E]
     413 *                              - 'a': Open or create file and writes
     414 *                                append tos it.
     415 *                              - 'r': Open existing file and read from it.
     416 *                              - 'w': Open or truncate existing file and write
     417 *                                to it.
     418 *                              - '+': Open for both read and write access.
     419 *                              - 'b' / 't': binary / text
     420 *                              - 'x': exclusively create, no open. Only
     421 *                                possible with 'w'.
     422 *                              - 'e' / 'N': No inherit on exec.  (The 'e' is
     423 *                                how Linux and FreeBSD expresses this, the
     424 *                                latter is Visual C++).
    413425 * @param   ppStream        Where to store the opened stream.
    414426 */
     
    421433    AssertReturn(pszFilename, VERR_INVALID_PARAMETER);
    422434
    423     bool        fOk     = true;
    424     bool        fBinary = false;
    425 #ifdef RTSTREAM_STANDALONE
    426     uint64_t    fOpen   = RTFILE_O_DENY_NONE;
    427 #endif
    428     switch (*pszMode)
    429     {
    430         case 'a':
    431         case 'w':
    432         case 'r':
    433             switch (pszMode[1])
    434             {
    435                 case 'b':
    436                     fBinary = true;
    437                     RT_FALL_THRU();
    438                 case '\0':
    439 #ifdef RTSTREAM_STANDALONE
    440                     fOpen |= *pszMode == 'a' ? RTFILE_O_OPEN_CREATE    | RTFILE_O_WRITE | RTFILE_O_APPEND
    441                            : *pszMode == 'w' ? RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE
    442                            :                   RTFILE_O_OPEN           | RTFILE_O_READ;
    443 #endif
    444                     break;
    445 
    446                 case '+':
    447 #ifdef RTSTREAM_STANDALONE
    448                     fOpen |= *pszMode == 'a' ? RTFILE_O_OPEN_CREATE    | RTFILE_O_READ | RTFILE_O_WRITE | RTFILE_O_APPEND
    449                            : *pszMode == 'w' ? RTFILE_O_CREATE_REPLACE | RTFILE_O_READ | RTFILE_O_WRITE
    450                            :                   RTFILE_O_OPEN           | RTFILE_O_READ | RTFILE_O_WRITE;
    451 #endif
    452                     switch (pszMode[2])
    453                     {
    454                         case '\0':
    455                             break;
    456 
    457                         case 'b':
    458                             fBinary = true;
    459                             break;
    460 
    461                         default:
    462                             fOk = false;
    463                             break;
    464                     }
    465                     break;
    466 
    467                 default:
    468                     fOk = false;
    469                     break;
    470             }
    471             break;
     435    /*
     436     * Process the mode string.
     437     */
     438    char    chMode     = '\0';  /* a|r|w */
     439    bool    fPlus      = false; /* + */
     440    bool    fBinary    = false; /* b | !t */
     441    bool    fExclusive = false; /* x */
     442    bool    fNoInherit = false;  /* e (linux, freebsd) | N (win) | E (our for reverse) */
     443    const char *psz = pszMode;
     444    char        ch;
     445    while ((ch = *psz++) != '\0')
     446    {
     447        switch (ch)
     448        {
     449            case 'a':
     450            case 'r':
     451            case 'w':
     452                chMode = ch;
     453                break;
     454            case '+':
     455                fPlus = true;
     456                break;
     457            case 'b':
     458                fBinary = true;
     459                break;
     460            case 't':
     461                fBinary = false;
     462                break;
     463            case 'x':
     464                fExclusive = true;
     465                break;
     466            case 'e':
     467            case 'N':
     468                fNoInherit = true;
     469                break;
     470            case 'E':
     471                fNoInherit = false;
     472                break;
     473            default:
     474                AssertMsgFailedReturn(("Invalid ch='%c' in pszMode='%s', '<a|r|w>[+][b|t][x][e|N|E]'\n", pszMode),
     475                                      VERR_INVALID_FLAGS);
     476        }
     477    }
     478
     479    /*
     480     * Translate into to RTFILE_O_* flags:
     481     */
     482    uint64_t fOpen;
     483    switch (chMode)
     484    {
     485        case 'a': fOpen = RTFILE_O_OPEN_CREATE    | RTFILE_O_WRITE | RTFILE_O_APPEND; break;
     486        case 'w': fOpen = !fExclusive
     487                        ? RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE
     488                        : RTFILE_O_CREATE         | RTFILE_O_WRITE;  break;
     489        case 'r': fOpen = RTFILE_O_OPEN           | RTFILE_O_READ;
    472490        default:
    473             fOk = false;
    474             break;
    475     }
    476     if (!fOk)
    477     {
    478         AssertMsgFailed(("Invalid pszMode='%s', '<a|r|w>[+][b]'\n", pszMode));
    479         return VINF_SUCCESS;
    480     }
     491            AssertMsgReturn(chMode, ("No main mode (a|r|w) specified in '%s'!\n", pszMode), VERR_INVALID_FLAGS);
     492    }
     493    AssertMsgReturn(!fExclusive || chMode == 'w', ("the 'x' flag is only allowed with 'w'! (%s)\n", pszMode),
     494                    VERR_INVALID_FLAGS);
     495    if (fExclusive)
     496        fOpen |= RTFILE_O_READ | RTFILE_O_WRITE;
     497    if (fPlus)
     498        fOpen |= RTFILE_O_READ | RTFILE_O_WRITE;
     499    if (!fNoInherit)
     500        fOpen |= RTFILE_O_INHERIT;
     501    fOpen |= RTFILE_O_DENY_NONE;
     502    fOpen |= 0666 << RTFILE_O_CREATE_MODE_SHIFT;
     503
     504#ifndef RTSTREAM_STANDALONE
     505    /*
     506     * Normalize mode for fdopen.
     507     */
     508    char szNormalizedMode[8];
     509    szNormalizedMode[0] = chMode;
     510    size_t off = 1;
     511    if (fPlus)
     512        szNormalizedMode[off++] = '+';
     513    if (fBinary)
     514        szNormalizedMode[off++] = 'b';
     515    szNormalizedMode[off] = '\0';
     516#endif
    481517
    482518#ifdef RTSTREAM_STANDALONE
     
    516552        pStream->pCritSect          = NULL;
    517553#endif
    518 #ifdef RTSTREAM_STANDALONE
    519         rc = RTFileOpen(&pStream->hFile, pszFilename, fOpen);
    520 #else
    521         pStream->pFile = fopen(pszFilename, pszMode);
    522         rc = pStream->pFile ? VINF_SUCCESS : RTErrConvertFromErrno(errno);
    523         if (pStream->pFile)
    524 #endif
     554        RTFILE       hFile          = NIL_RTFILE;
     555        RTFILEACTION enmActionTaken = RTFILEACTION_INVALID;
     556        rc = RTFileOpenEx(pszFilename, fOpen, &hFile, &enmActionTaken);
    525557        if (RT_SUCCESS(rc))
    526558        {
    527 #ifdef RTSTREAM_STANDALONE
    528             /* We keep a list of these for cleanup purposes. */
    529             RTCritSectEnter(&g_StreamListCritSect);
    530             RTListAppend(&g_StreamList, &pStream->ListEntry);
    531             RTCritSectLeave(&g_StreamListCritSect);
    532 #endif
    533             *ppStream = pStream;
    534             return VINF_SUCCESS;
     559#ifndef RTSTREAM_STANDALONE
     560# ifndef _MSC_VER
     561            int fd = (int)RTFileToNative(hFile);
     562# else
     563            int fd = _open_osfhandle(RTFileToNative(hFile),
     564                                       (fPlus ? _O_RDWR : chMode == 'r' ? _O_RDONLY : _O_WRONLY)
     565                                     | (chMode == 'a' ? _O_APPEND : 0)
     566                                     | (fBinary ? _O_BINARY : _O_TEXT)
     567                                     | (fNoInherit ? _O_NOINHERIT : 0));
     568# endif
     569            if (fd >= 0)
     570            {
     571                pStream->pFile = fdopen(fd, szNormalizedMode);
     572                if (pStream->pFile)
     573#endif
     574                {
     575#ifdef RTSTREAM_STANDALONE
     576                    pStream->hFile = hFile;
     577
     578                    /* We keep a list of these for cleanup purposes. */
     579                    RTCritSectEnter(&g_StreamListCritSect);
     580                    RTListAppend(&g_StreamList, &pStream->ListEntry);
     581                    RTCritSectLeave(&g_StreamListCritSect);
     582#endif
     583                    *ppStream = pStream;
     584                    return VINF_SUCCESS;
     585                }
     586
     587                /*
     588                 * This better not happen too often as in 'w' mode we might've
     589                 * truncated a file, and in 'w' and 'a' modes there is a chance
     590                 * that we'll race other access to the file when deleting it.
     591                 */
     592#ifndef RTSTREAM_STANDALONE
     593                rc = RTErrConvertFromErrno(errno);
     594# ifdef _MSC_VER
     595                close(fd);
     596                hFile = NIL_RTFILE;
     597# endif
     598            }
     599            else
     600            {
     601# ifdef _MSC_VER
     602                rc = RTErrConvertFromErrno(errno);
     603# else
     604                AssertFailedStmt(rc = VERR_INVALID_HANDLE);
     605# endif
     606            }
     607            RTFileClose(hFile);
     608            if (enmActionTaken == RTFILEACTION_CREATED)
     609                RTFileDelete(pszFilename);
     610#endif
    535611        }
    536612        RTMemFree(pStream);
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