Ejemplo n.º 1
0
static int __cdecl dup2_nolock(int const source_fh, int const target_fh) throw()
{
    if ((_osfile(source_fh) & FOPEN) == 0)
    {
        // If the source handle is not open, return an error.  Noe that the
        // DuplicateHandle API will not detect this error, because it implies
        // that _osfhnd(source_fh) == INVALID_HANDLE_VALUE, and this is a 
        // legal HANDLE value to be duplicated.
        errno = EBADF;
        _doserrno = 0;
        _ASSERTE(("Invalid file descriptor. File possibly closed by a different thread",0));
        return -1;
    }

    // If the target is open, close it first.  We ignore the possibility of an
    // error here:  an error simply means that the OS handle value may remain
    // bound for the duration of the process.
    if (_osfile(target_fh) & FOPEN)
    {
        _close_nolock(target_fh);
    }

    // Duplicate the source file onto the target file:
    intptr_t new_osfhandle;

    BOOL const result = DuplicateHandle(
        GetCurrentProcess(),
        reinterpret_cast<HANDLE>(_get_osfhandle(source_fh)),
        GetCurrentProcess(),
        &reinterpret_cast<HANDLE&>(new_osfhandle),
        0,
        TRUE,
        DUPLICATE_SAME_ACCESS);

    if (!result)
    {
        __acrt_errno_map_os_error(GetLastError());
        return -1;
    }

    __acrt_lowio_set_os_handle(target_fh, new_osfhandle);

    // Copy the _osfile information, with the FNOINHERIT bit cleared:
    _osfile(target_fh) = _osfile(source_fh) & ~FNOINHERIT;
    _textmode(target_fh) = _textmode(source_fh);
    _tm_unicode(target_fh) = _tm_unicode(source_fh);

    return 0;
}
Ejemplo n.º 2
0
int __cdecl _setmode_nolock(
    REG1 int fh,
    int mode
) {
    int oldmode;
    int oldtextmode;
    oldmode = _osfile(fh) & FTEXT;
    oldtextmode = _textmode(fh);

    switch (mode) {
    case _O_BINARY :
        _osfile(fh) &= ~FTEXT;
        break;

    case _O_TEXT :
        _osfile(fh) |= FTEXT;
        _textmode(fh) = __IOINFO_TM_ANSI;
        break;

    case _O_U8TEXT :
        _osfile(fh) |= FTEXT;
        _textmode(fh) = __IOINFO_TM_UTF8;
        break;

    case _O_U16TEXT:
    case _O_WTEXT :
        _osfile(fh) |= FTEXT;
        _textmode(fh) = __IOINFO_TM_UTF16LE;
        break;
    }

    if (oldmode == 0) {
        return _O_BINARY;
    }

    if (oldtextmode == __IOINFO_TM_ANSI) {
        return _O_TEXT;
    } else {
        return _O_WTEXT;
    }
}
Ejemplo n.º 3
0
// If a binary mode stream is open for reading and the target of the requested
// seek is within the stream buffer, we can simply adjust the buffer pointer to
// the new location.  This allows us to avoid flushing the buffer.  If the user
// has set a large buffer on the stream and performs frequent seeks that are
// likely to result in targets within the buffer, this is a huge performance win.
// This function handles the most common cases.
static bool __cdecl common_fseek_binary_mode_read_only_fast_track_nolock(
    __crt_stdio_stream const stream,
    __int64                  offset,
    int                      whence
    ) throw()
{
    // This fast-track path does not handle the seek-from-end case (this is not
    // nearly as commonly used as seeking from the beginning or from the current
    // position).
    if (whence == SEEK_END)
    {
        return false;
    }

    // This fast-track path is only useful if the stream is buffered.
    if (!stream.has_any_buffer())
    {
        return false;
    }

    // This fast-track path requires a stream opened only for reading.  It may
    // be possible to handle streams opened for writing or update similarly;
    // further investigation would be required.
    if (stream.has_any_of(_IOWRITE | _IOUPDATE))
    {
        return false;
    }

    // The ftell function handles a case where _cnt is negative.  It isn't clear
    // why _cnt may be negative, so if _cnt is negative, fall back to the
    // expensive path.
    if (stream->_cnt < 0)
    {
        return false;
    }

    // This fast-track path requires a binary mode file handle.  When text mode
    // or UTF transformations are enabled, the contents of the buffer do not
    // exactly match the contents of the underlying file.
    int const fh = stream.lowio_handle();
    if ((_osfile(fh) & FTEXT) != 0 || _textmode(fh) != __crt_lowio_text_mode::ansi)
    {
        return false;
    }

    // Handle the SEEK_SET case by transforming the SEEK_SET offset into a
    // SEEK_CUR offset:
    if (whence == SEEK_SET)
    {
        __int64 const lowio_position = _lseeki64_nolock(fh, 0, SEEK_CUR);
        if (lowio_position < 0)
        {
            return false;
        }

        __int64 const stdio_position = lowio_position - stream->_cnt;
        if (FAILED(LongLongSub(offset, stdio_position, &offset)))
        {
            return false;
        }
        whence = SEEK_CUR;
    }

    // Compute the maximum number of bytes that we can seek in each direction
    // within the buffer and verify that the requested offset is within that
    // range.  Note that the minimum reverse seek is a negative value.
    __int64 const minimum_reverse_seek = -(stream->_ptr - stream->_base);
    __int64 const maximum_forward_seek = stream->_cnt;
    
    bool const seek_is_within_buffer = minimum_reverse_seek <= offset && offset <= maximum_forward_seek;
    if (!seek_is_within_buffer)
    {
        return false;
    }

    stream->_ptr += offset;

    // Note that the cast here is safe:  The buffer will never be larger than
    // INT_MAX bytes in size.  The setvbuf function validates this constraint.
    stream->_cnt -= static_cast<int>(offset);
    return true;
}
Ejemplo n.º 4
0
Archivo: dup.c Proyecto: flychen50/clib
static int __cdecl _dup_nolock(
        int fh
        )
{
        int newfh;                      /* variable for new file handle */
        ULONG dosretval;                /* o.s. return value */
        char fileinfo;                  /* _osfile info for file */
        intptr_t new_osfhandle;
        int success = FALSE;

        fileinfo = _osfile(fh);         /* get file info for file */

        if ( !(_osfile(fh) & FOPEN) )
                return -1;


        /* create duplicate handle */

        if ( (newfh = _alloc_osfhnd()) == -1 )
        {
                errno = EMFILE;         /* too many files error */
                _doserrno = 0L;         /* not an OS error */
                return -1;              /* return error to caller */
        }
        __TRY

            /*
             * duplicate the file handle
             */
            if ( !(DuplicateHandle(GetCurrentProcess(),
                                   (HANDLE)_get_osfhandle(fh),
                                   GetCurrentProcess(),
                                   (PHANDLE)&new_osfhandle,
                                   0L,
                                   TRUE,
                                   DUPLICATE_SAME_ACCESS)) )
            {
                    dosretval = GetLastError();
            }
            else {
                    _set_osfhnd(newfh, new_osfhandle);
                    dosretval = 0;
            }

            if (dosretval)
                        {
                    /* o.s. error -- map errpr and release handle */
                    _dosmaperr(dosretval);
            }
            else
            {
                    /*
                     * copy the _osfile value, with the FNOINHERIT bit cleared
                     */
                    _osfile(newfh) = fileinfo & ~FNOINHERIT;
                    _textmode(newfh) = _textmode(fh);
                    _tm_unicode(newfh) = _tm_unicode(fh);
                    success = TRUE;
            }

        __FINALLY
            if (!success)
            {
                _osfile(newfh) &= ~FOPEN;
            }
            _unlock_fh(newfh);
        __END_TRY_FINALLY

            return success ? newfh : -1;
}
Ejemplo n.º 5
0
static int __cdecl _dup2_nolock (
        int fh1,
        int fh2
        )
{

        ULONG dosretval;                /* o.s. return code */
        intptr_t new_osfhandle;

        /*
         * Re-test and take care of case of unopened source handle. This is
         * necessary only in the multi-thread case where the file have been
         * closed by another thread before the lock was asserted, but after
         * the initial test above.
         */
        if ( !(_osfile(fh1) & FOPEN) ) {
                /*
                 * Source handle isn't open, bail out with an error.
                 * Note that the DuplicateHandle API will not detect this
                 * error since it implies that _osfhnd(fh1) ==
                 * INVALID_HANDLE_VALUE, and this is a legal HANDLE value
                 * (it's the HANDLE for the current process).
                 */
                errno = EBADF;
                _doserrno = 0;  /* not an OS error */
                _ASSERTE(("Invalid file descriptor. File possibly closed by a different thread",0));
                return -1;
        }


        /*
         * Take of the case of equal handles.
         */
        if ( fh1 == fh2 )
                /*
                 * Since fh1 is known to be open, return 0 indicating success.
                 * This is in conformance with the POSIX specification for
                 * dup2.
                 */
                return 0;

        /*
         * if fh2 is open, close it.
         */
        if ( _osfile(fh2) & FOPEN )
                /*
                 * close the handle. ignore the possibility of an error - an
                 * error simply means that an OS handle value may remain bound
                 * for the duration of the process.  Use _close_nolock as we
                 * already own lock
                 */
                (void) _close_nolock(fh2);


        /* Duplicate source file onto target file */

        if ( !(DuplicateHandle(GetCurrentProcess(),
                               (HANDLE)_get_osfhandle(fh1),
                               GetCurrentProcess(),
                               (PHANDLE)&new_osfhandle,
                               0L,
                               TRUE,
                               DUPLICATE_SAME_ACCESS)) )
        {

                dosretval = GetLastError();
        }
        else {
                _set_osfhnd(fh2, new_osfhandle);
                dosretval = 0;
        }

        if (dosretval) {
                _dosmaperr(dosretval);
                return -1;
        }

        /* copy the _osfile information, with the FNOINHERIT bit cleared */
        _osfile(fh2) = _osfile(fh1) & ~FNOINHERIT;
        _textmode(fh2) = _textmode(fh1);
        _tm_unicode(fh2) = _tm_unicode(fh1);

        return 0;
}
Ejemplo n.º 6
0
/* now define version that doesn't lock/unlock, validate fh */
int __cdecl _read_nolock (
        int fh,
        void *inputbuf,
        unsigned cnt
        )
{

        int bytes_read;                 /* number of bytes read */
        char *buffer;                   /* buffer to read to */
        int os_read;                    /* bytes read on OS call */
        char *p, *q;                    /* pointers into buffer */
        wchar_t *pu, *qu;               /* wchar_t pointers into buffer for UTF16 */
        char peekchr;                   /* peek-ahead character */
        wchar_t wpeekchr;               /* peek-ahead wchar_t */
        __int64 filepos;                /* file position after seek */
        ULONG dosretval;                /* o.s. return value */
        char tmode;                         /* textmode - ANSI/UTF-8/UTF-16 */
        void *buf;                          /* buffer to read to */
        int retval = -2;                    /* return value */
        unsigned inputsize = cnt;

        /* validate fh */
        _CHECK_FH_CLEAR_OSSERR_RETURN( fh, EBADF, -1 );
        _VALIDATE_CLEAR_OSSERR_RETURN((fh >= 0 && (unsigned)fh < (unsigned)_nhandle), EBADF, -1);
        _VALIDATE_CLEAR_OSSERR_RETURN((_osfile(fh) & FOPEN), EBADF, -1);


        bytes_read = 0;                 /* nothing read yet */

        if (cnt == 0 || (_osfile(fh) & FEOFLAG)) {
            /* nothing to read or at EOF, so return 0 read */
            return 0;
        }

        _VALIDATE_CLEAR_OSSERR_RETURN( (inputbuf != NULL), EINVAL, -1 );

        tmode = _textmode(fh);

        switch(tmode) {
            case __IOINFO_TM_UTF8 :
                /* For a UTF-8 file, we need 2 buffers, because after reading we
                   need to convert it into UNICODE - MultiByteToWideChar doesn't do
                   in-place conversions. */

                /* MultiByte To WideChar conversion may double the size of the
                   buffer required & hence we divide cnt by 2 */

                /*
                 * Since we are reading UTF8 stream, cnt bytes read may vary
                 * from cnt wchar_t characters to cnt/4 wchar_t characters. For
                 * this reason if we need to read cnt characters, we will
                 * allocate MBCS buffer of cnt. In case cnt is 0, we will
                 * have 4 as minimum value. This will make sure we don't
                 * overflow for reading from pipe case.
                 *
                 *
                 * In this case the numbers of wchar_t characters that we can
                 * read is cnt/2. This means that the buffer size that we will
                 * require is cnt/2.
                 */

                /* For UTF8 we want the count to be an even number */
                _VALIDATE_CLEAR_OSSERR_RETURN(((cnt & 1) == 0), EINVAL, -1);

                cnt = (cnt/2) < 4 ? 4 : (cnt/2);

                buf = _malloc_crt(cnt);

                if(!buf) {
                    errno = ENOMEM;
                    _doserrno = E_nomem;
                    return -1;
                }
                break;

            case __IOINFO_TM_UTF16LE :
                /* For UTF16 the count always needs to be an even number */
                _VALIDATE_CLEAR_OSSERR_RETURN(((cnt & 1) == 0), EINVAL, -1);

                cnt &= (~1);

                /* Fall Through to default */

            default :
                /* For non-UTF8 files, we need only 1 buffer - make buf point to
                   the users input buffer */
                buf = inputbuf;
        }


        buffer = buf;

        if ((_osfile(fh) & (FPIPE|FDEV)) && _pipech(fh) != LF && cnt != 0) {
            /* a pipe/device and pipe lookahead non-empty: read the lookahead
             * char */
            *buffer++ = _pipech(fh);
            ++bytes_read;
            --cnt;
            _pipech(fh) = LF;           /* mark as empty */

            /* For UTF16, there maybe one more look ahead char. For UTF8,
               there maybe 2 more look ahead chars */
            if((tmode != __IOINFO_TM_ANSI) && (_pipech2(fh)[0] != LF) && cnt != 0) {
                *buffer++ = _pipech2(fh)[0];
                ++bytes_read;
                --cnt;
                _pipech2(fh)[0] = LF;   /* mark as empty */

                if((tmode == __IOINFO_TM_UTF8) && (_pipech2(fh)[1] != LF) && cnt != 0) {
                    *buffer++ = _pipech2(fh)[1];
                    ++bytes_read;
                    --cnt;
                    _pipech2(fh)[1] = LF;   /* mark as empty */
                }

            }

        }

        /* read the data */

        if ( !ReadFile( (HANDLE)_osfhnd(fh), buffer, cnt, (LPDWORD)&os_read,
                    NULL ) || os_read < 0 || (size_t)os_read > cnt)
        {
            /* ReadFile has reported an error. recognize two special cases.
             *
             *      1. map ERROR_ACCESS_DENIED to EBADF
             *
             *      2. just return 0 if ERROR_BROKEN_PIPE has occurred. it
             *         means the handle is a read-handle on a pipe for which
             *         all write-handles have been closed and all data has been
             *         read. */

            if ( (dosretval = GetLastError()) == ERROR_ACCESS_DENIED ) {
                /* wrong read/write mode should return EBADF, not EACCES */
                errno = EBADF;
                _doserrno = dosretval;
                retval = -1;
                goto error_return;

            }
            else if ( dosretval == ERROR_BROKEN_PIPE ) {
                retval = 0;
                goto error_return;
            }
            else {
                _dosmaperr(dosretval);
                retval = -1;
                goto error_return;
            }
        }

        bytes_read += os_read;          /* update bytes read */

        if (_osfile(fh) & FTEXT) {
            /* now must translate CR-LFs to LFs in the buffer */

            /* For ANSI & UTF8, we read byte by byte.
               For UTF16, we need to read 2 bytes (wchar_t's) at a time */
            if(tmode != __IOINFO_TM_UTF16LE) {
                /* set CRLF flag to indicate LF at beginning of buffer */
                if ( (os_read != 0) && (*(char *)buf == LF) )
                    _osfile(fh) |= FCRLF;
                else
                    _osfile(fh) &= ~FCRLF;

                /* convert chars in the buffer: p is src, q is dest */
                p = q = buf;
                while (p < (char *)buf + bytes_read) {
                    if (*p == CTRLZ) {
                        /* if fh is not a device, set ctrl-z flag */
                        if ( !(_osfile(fh) & FDEV) )
                            _osfile(fh) |= FEOFLAG;
                        else
                            *q++ = *p++;
                        break;              /* stop translating */
                    }
                    else if (*p != CR)
                        *q++ = *p++;
                    else {
                        /* *p is CR, so must check next char for LF */
                        if (p < (char *)buf + bytes_read - 1) {
                            if (*(p+1) == LF) {
                                p += 2;
                                *q++ = LF;  /* convert CR-LF to LF */
                            }
                            else
                                *q++ = *p++;    /* store char normally */
                        }
                        else {
                            /* This is the hard part.  We found a CR at end of
                               buffer.  We must peek ahead to see if next char
                               is an LF. */
                            ++p;

                            dosretval = 0;
                            if ( !ReadFile( (HANDLE)_osfhnd(fh), &peekchr, 1,
                                        (LPDWORD)&os_read, NULL ) )
                                dosretval = GetLastError();

                            if (dosretval != 0 || os_read == 0) {
                                /* couldn't read ahead, store CR */
                                *q++ = CR;
                            }
                            else {
                                /*
                                 * peekchr now has the extra character -- we now
                                 * have several possibilities:
                                 *
                                 * 1. disk file and char is not LF; just seek
                                 *    back and copy CR
                                 * 2. disk file and char is LF; seek back and
                                 *    discard CR
                                 * 3. disk file, char is LF but this is a
                                 *    one-byte read: store LF, don't seek back
                                 * 4. pipe/device and char is LF; store LF.
                                 * 5. pipe/device and char isn't LF, store CR
                                 *    and put char in pipe lookahead buffer.
                                 */
                                if (_osfile(fh) & (FDEV|FPIPE)) {
                                    /* non-seekable device */
                                    if (peekchr == LF)
                                        *q++ = LF;
                                    else {
                                        *q++ = CR;
                                        _pipech(fh) = peekchr;
                                    }
                                }
                                else {
                                    /* disk file */
                                    if (q == buf && peekchr == LF) {
                                        /* nothing read yet; must make some
                                           progress */
                                        *q++ = LF;
                                    }
                                    else {
                                        /* seek back */
                                        filepos = _lseeki64_nolock(fh, -1i64, FILE_CURRENT);
                                        if (peekchr != LF)
                                            *q++ = CR;
                                    }
                                }
                            }
                        }
                    }
                }


                /* we now change bytes_read to reflect the true number of chars
                   in the buffer */
                bytes_read = (int)(q - (char *)buf);

                if((tmode == __IOINFO_TM_UTF8) && (bytes_read != 0)) {
                    /* UTF8 reads need to be converted into UTF16 */

                    --q; /* q has gone beyond the last char */

                    /*
                     * If the last byte is a standalone UTF-8 char. We then
                     * take the whole buffer. Otherwise we skip back till we
                     * come to a lead byte. If the leadbyte forms a complete
                     * UTF-8 character will the remaining part of the buffer,
                     * then again we take the whole buffer. If not, we skip to
                     * one byte which should be the final trail byte of the
                     * previous UTF-8 char or a standalone UTF-8 character
                     */

                    if(_utf8_is_independent(*q)) {
                        ++q;
                        /*
                         * Final byte is standalone, we reset q, because we
                         * will now consider the full buffer which we have read
                         */
                    }
                    else {
                        int ctr = 1;
                        int cnt_trailbytes;

                        while(!_utf8_is_leadbyte(*q) && ctr <= 4 && q >= (char *)buf) {
                            --q;
                            ++ctr;
                        }

                        cnt_trailbytes = _utf8_no_of_trailbytes(*q);

                        if(cnt_trailbytes == 0) {
                            /*
                             * Should have exited the while by finding a lead
                             * byte else, the file has incorrect UTF-8 chars
                             */
                                errno = EILSEQ;
                                retval = -1;
                                goto error_return;
                            }

                        if(cnt_trailbytes + 1 == ctr) {
                            /*
                             * The leadbyte + the remaining bytes form a full
                             * set
                             */
                            q += ctr;
                        }
                        else {
                            /* Seek back */

                            if (_osfile(fh) & (FDEV|FPIPE)) {
                                /*
                                 * non-seekable device. Put the extra chars in
                                 * _pipech & _pipech2. We would have a maximum
                                 * of 3 extra chars
                                 */
                                _pipech(fh) = *q;
                                ++q;

                                if(ctr >= 2) {
                                    _pipech2(fh)[0] = *q;
                                    ++q;
                                }
                                if(ctr == 3) {
                                    _pipech2(fh)[1] = *q;
                                    ++q;
                                }

                                /*
                                 * We need to point q back to beyond whatever
                                 * we actually took in.
                                 */
                                q -= ctr;

                            }
                            else {
                                /* We have read extra chars, so we seek back */
                                filepos = _lseeki64_nolock(fh, -ctr, FILE_CURRENT);

                        }

                        }
                    }

                    bytes_read = (int)(q - (char *)buf);
                    bytes_read = MultiByteToWideChar(
                            CP_UTF8,
                            0,
                            buf,
                            bytes_read,
                            inputbuf,
                            inputsize/2);

                    if(!bytes_read) {
                        _dosmaperr(GetLastError());
                        retval = -1;
                        goto error_return;
                    }

                    /* MultiByteToWideChar returns no of wchar_t's. Double it */
                    bytes_read = bytes_read*2;
                }
            }
            else {
                /* set CRLF flag to indicate LF at beginning of buffer */
                if ( (os_read != 0) && (*(wchar_t *)buf == LF) )
                    _osfile(fh) |= FCRLF;
                else
                    _osfile(fh) &= ~FCRLF;

                /* convert chars in the buffer: pu is src, qu is dest */
                pu = qu = (wchar_t *)buf;
                while ((char *)pu < (char *)buf + bytes_read) {
                    if (*pu == CTRLZ) {
                        /* if fh is not a device, set ctrl-z flag */
                        if ( !(_osfile(fh) & FDEV) )
                            _osfile(fh) |= FEOFLAG;
                        else
                            *qu++ = *pu++;
                        break;              /* stop translating */
                    }
                    else if (*pu != CR)
                        *qu++ = *pu++;
                    else {
                        /* *pu is CR, so must check next wchar_t for LF */
                        if ((char *)pu < (char *)buf + bytes_read - 2) {
                            if (*(pu+1) == LF) {
                                pu += 2;
                                *qu++ = LF;  /* convert CR-LF to LF */
                            }
                            else
                                *qu++ = *pu++;    /* store char normally */
                        }
                        else {
                            /* This is the hard part.  We found a CR at end of
                               buffer.  We must peek ahead to see if next
                               wchar_t is an LF. */
                            ++pu;

                            dosretval = 0;
                            if ( !ReadFile( (HANDLE)_osfhnd(fh), &wpeekchr, 2,
                                        (LPDWORD)&os_read, NULL ) )
                                dosretval = GetLastError();

                            if (dosretval != 0 || os_read == 0) {
                                /* couldn't read ahead, store CR */
                                *qu++ = CR;
                            }
                            else {
                                /*
                                 * peekchr now has the extra character -- we
                                 * now have several possibilities:
                                 * 1. wchar_t is not LF; just seek back and
                                 * copy CR
                                 * 2. wchar_t is LF; seek back and discard CR
                                 * 3. disk file, wchar_t is LF but this is a
                                 * one-byte read: store LF, don't seek back.
                                 */

                                if (_osfile(fh) & (FDEV|FPIPE)) {
                                    /* non-seekable device */
                                    if (wpeekchr == LF)
                                        *qu++ = LF;
                                    else {
                                        char * pwpeekchr = (char *)&wpeekchr;
                                        *qu++ = CR;
                                        _pipech(fh) = *pwpeekchr;
                                        ++pwpeekchr;
                                        _pipech2(fh)[0] = *pwpeekchr;
                                        _pipech2(fh)[1] = LF; /* Mark as empty */
                                    }
                                }
                                else {
                                    if ((char *)qu == buf && wpeekchr == LF) {
                                        /* nothing read yet; must make some
                                           progress */
                                        *qu++ = LF;
                                    }
                                    else {
                                        /* seek back */
                                        filepos = _lseeki64_nolock(fh, -2, FILE_CURRENT);
                                        if (wpeekchr != LF)
                                            *qu++ = CR;
                                    }
                                }
                            }
                        }
                    }
                }

                /* we now change bytes_read to reflect the true number of chars
                   in the buffer */
                bytes_read = (int)((char *)qu - (char *)buf);

            }

        }

error_return:
        if(buf != inputbuf) {
            free(buf);
        }

        return (retval == -2) ? bytes_read : retval ;

}
Ejemplo n.º 7
0
/* now define version that doesn't lock/unlock, validate fh */
int __cdecl _write_nolock (
        int fh,
        const void *buf,
        unsigned cnt
        )
{

        int lfcount;            /* count of line feeds */
        int charcount;          /* count of chars written so far */
        int written;            /* count of chars written on this write */
        ULONG dosretval;        /* o.s. return value */
        char tmode ;            /* textmode - ANSI or UTF-16 */
        BOOL toConsole = 0;     /* true when writing to console */
        BOOL isCLocale = 0;     /* true when locale handle is C locale */


        lfcount = charcount = 0;        /* nothing written yet */

        if (cnt == 0)
                return 0;               /* nothing to do */

        _VALIDATE_CLEAR_OSSERR_RETURN( (buf != NULL), EINVAL, -1 );

        tmode = _textmode(fh);

        if(tmode == __IOINFO_TM_UTF16LE ||
                tmode == __IOINFO_TM_UTF8)
        {
            /* For a UTF-16 file, the count must always be an even number */
            _VALIDATE_CLEAR_OSSERR_RETURN(((cnt & 1) == 0), EINVAL, -1);
        }

        if (_osfile(fh) & FAPPEND) {
                /* appending - seek to end of file; ignore error, because maybe
                   file doesn't allow seeking */
#if _INTEGRAL_MAX_BITS >= 64
                (void)_lseeki64_nolock(fh, 0, FILE_END);
#else  /* _INTEGRAL_MAX_BITS >= 64 */
                (void)_lseek_nolock(fh, 0, FILE_END);
#endif  /* _INTEGRAL_MAX_BITS >= 64 */
        }

        /* check for text mode with LF's in the buffer */

        /*
         * Note that in case the handle belongs to Console, write file will
         * generate garbage output. For user to print these characters
         * correctly, we will need to print ANSI.
         *
         * Also note that in case of printing to Console, we still have to
         * convert the characters to console codepage.
         */

        if (_isatty(fh) && (_osfile(fh) & FTEXT))
        {
            DWORD dwMode;
            _ptiddata ptd = _getptd();
            isCLocale = (ptd->ptlocinfo->lc_handle[LC_CTYPE] == _CLOCALEHANDLE);
            toConsole = GetConsoleMode((HANDLE)_osfhnd(fh), &dwMode);
        }

        /* don't need double conversion if it's ANSI mode C locale */
        if (toConsole && !(isCLocale && (tmode == __IOINFO_TM_ANSI))) {
            UINT consoleCP = GetConsoleCP();
            char mboutbuf[MB_LEN_MAX];
            wchar_t tmpchar;
            int size = 0;
            int written = 0;
            char *pch;

            for (pch = (char *)buf; (unsigned)(pch - (char *)buf) < cnt; ) {
                BOOL bCR;

                if (tmode == __IOINFO_TM_ANSI) {
                    bCR = *pch == LF;
                    /*
                     * Here we need to do double convert. i.e. convert from
                     * multibyte to unicode and then from unicode to multibyte in
                     * Console codepage.
                     */
                    if (!isleadbyte(*pch)) {
                        if (mbtowc(&tmpchar, pch, 1) == -1) {
                            break;
                        }
                    } else if ((cnt - (pch - (char*)buf)) > 1) {
                        if (mbtowc(&tmpchar, pch, 2) == -1) {
                            break;
                        }
                        /*
                         * Increment pch to accomodate DBCS character.
                         */
                        ++pch;
                    } else {
                        break;
                    }
                    ++pch;
                } else if (tmode == __IOINFO_TM_UTF8 || tmode == __IOINFO_TM_UTF16LE) {
                    /*
                     * Note that bCR set above is not valid in case of UNICODE
                     * stream. We need to set it using unicode character.
                     */
                    tmpchar = *(wchar_t *)pch;
                    bCR = tmpchar == LF;
                    pch += 2;
                }

                if (tmode == __IOINFO_TM_ANSI)
                {
                    if( (size = WideCharToMultiByte(consoleCP,
                                                    0,
                                                    &tmpchar,
                                                    1,
                                                    mboutbuf,
                                                    sizeof(mboutbuf),
                                                    NULL,
                                                    NULL)) == 0) {
                        break;
                    } else {
                        if ( WriteFile( (HANDLE)_osfhnd(fh),
                                        mboutbuf,
                                        size,
                                        (LPDWORD)&written,
                                        NULL) ) {
                            charcount += written;
                            if (written < size)
                                break;
                        } else {
                            dosretval = GetLastError();
                            break;
                        }
                    }

                    if (bCR) {
                        size = 1;
                        mboutbuf[0] = CR;
                        if (WriteFile((HANDLE)_osfhnd(fh),
                                      mboutbuf,
                                      size,
                                      (LPDWORD)&written,
                                      NULL) ) {
                            if (written < size)
                                break;
                            lfcount ++;
                            charcount++;
                        } else {
                            dosretval = GetLastError();
                            break;
                        }
                    }
                }
                else if ( tmode == __IOINFO_TM_UTF8 || tmode == __IOINFO_TM_UTF16LE)
                {
                    if ( _putwch_nolock(tmpchar) == tmpchar )
                    {
                        charcount++;
                    }
                    else
                    {
                        dosretval = GetLastError();
                        break;
                    }
                    if (bCR) /* emit carriage return */
                    {
                        size = 1;
                        tmpchar = CR;
                        if ( _putwch_nolock(tmpchar) == tmpchar )
                        {
                            charcount++;
                            lfcount++;
                        }
                        else
                        {
                            dosretval = GetLastError();
                            break;
                        }
                    }
                }
            }
        } else if ( _osfile(fh) & FTEXT ) {
            /* text mode, translate LF's to CR/LF's on output */

            dosretval = 0;          /* no OS error yet */

            if(tmode == __IOINFO_TM_ANSI) {
                char ch;                    /* current character */
                char *p = NULL, *q = NULL;  /* pointers into buf and lfbuf resp. */
                char lfbuf[BUF_SIZE];
                p = (char *)buf;        /* start at beginning of buffer */
                while ( (unsigned)(p - (char *)buf) < cnt ) {
                    q = lfbuf;      /* start at beginning of lfbuf */

                    /* fill the lf buf, except maybe last char */
                    while ( q - lfbuf < sizeof(lfbuf) - 1 &&
                            (unsigned)(p - (char *)buf) < cnt ) {
                        ch = *p++;
                        if ( ch == LF ) {
                            ++lfcount;
                            *q++ = CR;
                        }
                        *q++ = ch;
                    }

                    /* write the lf buf and update total */
                    if ( WriteFile( (HANDLE)_osfhnd(fh),
                                lfbuf,
                                (int)(q - lfbuf),
                                (LPDWORD)&written,
                                NULL) )
                    {
                        charcount += written;
                        if (written < q - lfbuf)
                            break;
                    }
                    else {
                        dosretval = GetLastError();
                        break;
                    }
                }
            } else if ( tmode == __IOINFO_TM_UTF16LE ){
                char lfbuf[BUF_SIZE];
                wchar_t wch;            /* current wide char */
                wchar_t *pu = (wchar_t *)buf;
                wchar_t *qu = NULL;

                while ( (unsigned)((char *)pu - (char *)buf) < cnt ) {
                    qu = (wchar_t *)lfbuf; /* start at beginning of lfbuf */

                    /* fill the lf buf, except maybe last wchar_t */
                    while ( (((char *)qu - lfbuf) < (sizeof(lfbuf) - 2)) &&
                            ((unsigned)((char *)pu - (char *)buf) < cnt )) {
                        wch = *pu++;
                        if ( wch == LF ) {
                            lfcount+=2;
                            *qu++ = CR;
                        }
                        *qu++ = wch;
                    }

                    /* write the lf buf and update total */
                    if ( WriteFile( (HANDLE)_osfhnd(fh),
                                lfbuf,
                                (int)((char*)qu - lfbuf),
                                (LPDWORD)&written,
                                NULL) )
                    {
                        charcount += written;
                        if (written < ((char *)qu - lfbuf))
                            break;
                    }
                    else {
                        dosretval = GetLastError();
                        break;
                    }
                }
            } else {
                /*
                 * Let's divide the lfbuf in 1:2 wher 1 is for storing
                 * widecharacters and 2 if for converting it to UTF8.  This takes
                 * into account the worst case scenario where all the UTF8
                 * characters are 4 byte long.
                 */
                char utf8_buf[(BUF_SIZE*2)/3];
                wchar_t utf16_buf[BUF_SIZE/6];

                wchar_t wch;            /* current wide char */
                wchar_t *pu = (wchar_t *)buf;
                wchar_t *qu = NULL;

                pu = (wchar_t *)buf;
                while ((unsigned)((char *)pu - (char *)buf) < cnt) {
                    int bytes_converted = 0;
                    qu = utf16_buf; /* start at beginning of lfbuf */

                    while ( (((char *)qu - (char *)utf16_buf) <
                             (sizeof(utf16_buf) - 2)) &&
                            ((unsigned)((char *)pu - (char *)buf) < cnt )) {
                        wch = *pu++;
                        if ( wch == LF ) {
                            /* no need to count the linefeeds here: we calculate the written chars in another way */
                            *qu++ = CR;
                        }
                        *qu++ = wch;
                    }

                    bytes_converted = WideCharToMultiByte(
                            CP_UTF8,
                            0,
                            utf16_buf,
                            ((int)((char *)qu - (char *)utf16_buf))/2,
                            utf8_buf,
                            sizeof(utf8_buf),
                            NULL,
                            NULL);

                    if (bytes_converted == 0) {
                        dosretval = GetLastError();
                        break;
                    } else {
                        /*
                         * Here we need to make every attempt to write all the
                         * converted characters. The resaon behind this is,
                         * incase half the bytes of a UTF8 character is
                         * written, it may currupt whole of the stream or file.
                         *
                         * The loop below will make sure we exit only if all
                         * the bytes converted are written (which makes sure no
                         * partial MBCS is written) or there was some error in
                         * the stream.
                         */
                        int bytes_written = 0;
                        do {
                            if (WriteFile(
                                        (HANDLE)_osfhnd(fh),
                                        utf8_buf + bytes_written,
                                        bytes_converted - bytes_written,
                                        &written,
                                        NULL)) {
                                bytes_written += written;
                            } else {
                                dosretval = GetLastError();
                                break;
                            }
                        } while ( bytes_converted > bytes_written);

                        /*
                         * Only way the condition below could be true is if
                         * there was en error. In case of error we need to
                         * break this loop as well.
                         */
                        if (bytes_converted > bytes_written) {
                            break;
                        }
                        /* if this chunk has been committed successfully, update charcount */
                        charcount = (int)((char *)pu - (char *)buf);
                    }
                }
            }
        }
        else {
                /* binary mode, no translation */
                if ( WriteFile( (HANDLE)_osfhnd(fh),
                                (LPVOID)buf,
                                cnt,
                               (LPDWORD)&written,
                                NULL) )
                {
                        dosretval = 0;
                        charcount = written;
                }
                else
                        dosretval = GetLastError();
        }

        if (charcount == 0) {
                /* If nothing was written, first check if an o.s. error,
                   otherwise we return -1 and set errno to ENOSPC,
                   unless a device and first char was CTRL-Z */
                if (dosretval != 0) {
                        /* o.s. error happened, map error */
                        if (dosretval == ERROR_ACCESS_DENIED) {
                            /* wrong read/write mode should return EBADF, not
                               EACCES */
                                errno = EBADF;
                                _doserrno = dosretval;
                        }
                        else
                                _dosmaperr(dosretval);
                        return -1;
                }
                else if ((_osfile(fh) & FDEV) && *(char *)buf == CTRLZ)
                        return 0;
                else {
                        errno = ENOSPC;
                        _doserrno = 0;  /* no o.s. error */
                        return -1;
                }
        }
        else
                /* return adjusted bytes written */
                return charcount - lfcount;
}
Ejemplo n.º 8
0
// This function handles the extra adjustments that need to be made to the file
// position returned by ftell when a stream is opened in read mode.
static __int64 __cdecl common_ftell_read_mode_nolock(
    __crt_stdio_stream const stream,
    __int64            const lowio_position,
    __int64            const buffer_offset
) throw()
{
    int const fh = _fileno(stream.public_stream());

    // We will need to adjust the file position of UTF-8 files to account for
    // UTF-8 to UTF-16 translation:
    __int64 const translation_factor = _textmode(fh) == __crt_lowio_text_mode::utf8
                                       ? static_cast<__int64>(sizeof(wchar_t))
                                       : static_cast<__int64>(sizeof(char));

    // If the buffer has been exhausted, then the current lowio position is also
    // the current stdio position:
    if (stream->_cnt == 0)
        return lowio_position;

    // The lowio position points one-past-the-end of the current stdio buffer.
    // We need to find the position of the beginning of the buffer.  To start,
    // we compute the number of bytes in the buffer.  Note that we cannot just
    // use the buffer size, because the buffer will not be full if EOF is
    // readhed before the buffer is full.
    __int64 bytes_read = stream->_cnt + static_cast<__int64>(stream->_ptr - stream->_base);

    // If this is a binary mode stream, we can simply subtract this from the
    // lowio position, and combine it with the buffer offset to get the stdio
    // position:
    if ((_osfile(fh) & FTEXT) == 0)
    {
        return lowio_position
               - (bytes_read    / translation_factor)
               + (buffer_offset / translation_factor);
    }

    // If this is a text mode stream, we need to adjust the number of bytes that
    // were read into the buffer to account for newline translation.
    //
    // If we are _not_ at EOF, the number of untranslated characters read is the
    // buffer size.  However, if we are not at EOF, the buffer may not be full,
    // so we need to scan the buffer to count newline characters.  (Note:  we
    // only count newline characters if the stream is at EOF, because doing so
    // is more expensive than seeking to the end and seeking back).

    // Seek to the end of the file.  If the current position is the end of the
    // file, then scan the buffer for newlines and adjust bytes_read:
    if (_lseeki64(fh, 0, SEEK_END) == lowio_position)
    {
        char const* const buffer_first = stream->_base;
        char const* const buffer_last  = buffer_first + bytes_read;
        for (char const* it = buffer_first; it != buffer_last; ++it)
        {
            // We do not know whether the character preceding a newline was a
            // carriage reutrn, but assume that it was:
            if (*it == '\n')
                ++bytes_read;
        }

        // If the last byte was a ^Z, that character will not be present in the
        // buffer (it is omitted by lowio):
        if (stream.ctrl_z())
            ++bytes_read;
    }
    // Otherwise, the current position is not at the end of the file; we need to
    // seek back to the original position and compute the size of the buffer:
    else
    {
        if (_lseeki64(fh, lowio_position, SEEK_SET) == -1)
            return -1;

        // If the number of bytes read is smaller than the small buffer and was
        // not user-provided, the buffer size was set to _SMALL_BUFSIZ during
        // the last call to __acrt_stdio_refill_and_read_{narrow,wide}_nolock:
        if (bytes_read <= _SMALL_BUFSIZ &&
                stream.has_crt_buffer() &&
                !stream.has_setvbuf_buffer())
        {
            bytes_read = _SMALL_BUFSIZ;
        }
        // Otherwise, the buffer size is what is stated in the stream object:
        else
        {
            bytes_read = stream->_bufsiz;
        }

        // If the first byte in the untranslated buffer was a '\n', we assume it
        // was preceded by a '\r', which was discarded by the previous read
        // operation:
        if (_osfile(fh) & FCRLF)
            ++bytes_read;
    }

    return lowio_position
           - (bytes_read    / translation_factor)
           + (buffer_offset / translation_factor);
}
Ejemplo n.º 9
0
static __int64 __cdecl common_ftell_nolock(__crt_stdio_stream const stream) throw()
{
    _VALIDATE_RETURN(stream.public_stream(), EINVAL, -1);

    int const fh = _fileno(stream.public_stream());

    if (stream->_cnt < 0)
        stream->_cnt = 0;

    // Get the current lowio file position.  If stdio is buffering the stream,
    // this position will point one past the end of the current stdio buffer.
    __int64 const lowio_position = _lseeki64(fh, 0, SEEK_CUR);
    if (lowio_position < 0)
        return -1;

    // If the stream is unbuffered or no buffering is designated, we can simply
    // compute the stdio position via the remaining stdio stream count:
    if (!stream.has_big_buffer())
        return lowio_position - stream->_cnt;

    // The above lseek validates the handle, so it's okay to get the text mode:
    __crt_lowio_text_mode const text_mode = _textmode(fh);

    // This is the current offset into the stdio buffer; we will adjust this to
    // account for translation and updates as this function progresses:
    __int64 buffer_offset = stream->_ptr - stream->_base;

    // If the file is in read or write mode, we need special handling for UTF-8
    // and text mode files, to account for newline translation and UTF-8 to
    // UTF-16 conversion:
    if (stream.has_any_of(_IOWRITE | _IOREAD))
    {
        if (text_mode == __crt_lowio_text_mode::utf8 && _utf8translations(fh))
        {
            return common_ftell_translated_utf8_nolock(stream, lowio_position);
        }

        // For text mode files, adjust the buffer offset to account for newline
        // translation:
        if (_osfile(fh) & FTEXT)
        {
            for (char const* it = stream->_base; it != stream->_ptr; ++it)
            {
                if (*it == '\n')
                    ++buffer_offset;
            }
        }
    }
    // Otherwise, if the file is not in read/write mode, ftell cannot proceed:
    else if (!stream.has_all_of(_IOUPDATE))
    {
        errno = EINVAL;
        return -1;
    }

    // If the current lowio position is at the beginning of the file, the stdio
    // position is whatever the offset is:
    if (lowio_position == 0)
        return buffer_offset;

    if (stream.has_all_of(_IOREAD))
    {
        return common_ftell_read_mode_nolock(stream, lowio_position, buffer_offset);
    }

    if (text_mode == __crt_lowio_text_mode::utf8)
        buffer_offset /= sizeof(wchar_t);

    return lowio_position + buffer_offset;
}