Home / fwrite

fwrite

fwrite でのファイルサイズ制限

glibc-2.7/libio/iofwrite.c を見てみる。

--- iofwrite.c ---

_IO_size_t
_IO_fwrite(const void *buf,
           _IO_size_t size,
           _IO_size_t count,
           _IO_FILE *fp)
{
    _IO_size_t request = size * count;
    _IO_size_t written = 0;
    CHECK_FILE (fp, 0);
    if (request == 0)
        return 0;

    _IO_acquire_lock (fp);
    if (_IO_vtable_offset (fp) != 0 || 
        _IO_fwide (fp, -1) == -1)
        written = _IO_sputn(fp, (const char *) buf, request);

    _IO_release_lock (fp);

    if (written == request)
        return count;
    else
        return written / size;
}

これが fwrite になるからくりは良く判らないが、すぐ下に次のように書かれてある。

INTDEF(_IO_fwrite)

#ifdef weak_alias
# include 
weak_alias (_IO_fwrite, fwrite)
libc_hidden_weak (fwrite)
# ifndef _IO_MTSAFE_IO
weak_alias (_IO_fwrite, fwrite_unlocked)
libc_hidden_weak (fwrite_unlocked)
# endif
#endif

_IO_sputn を見てみる。 glibc-2.7\libio\libioP.h

#ifdef _G_USING_THUNKS
# define JUMP2(FUNC, THIS, X1, X2) (_IO_JUMPS_FUNC(THIS)->FUNC) (THIS, X1, X2)
#else
/* These macros will change when we re-implement vtables to use "thunks"! */
# define JUMP2(FUNC, THIS, X1, X2) _IO_JUMPS_FUNC(THIS)->FUNC.pfn (THIS, X1, X2)
#endif


/* The 'xsputn' hook writes upto N characters from buffer DATA.
   Returns the number of character actually written.
   It matches the streambuf::xsputn virtual function. */
typedef _IO_size_t (*_IO_xsputn_t) (_IO_FILE *FP, const void *DATA,
                    _IO_size_t N);
#define _IO_XSPUTN(FP, DATA, N) JUMP2 (__xsputn, FP, DATA, N)
#define _IO_WXSPUTN(FP, DATA, N) WJUMP2 (__xsputn, FP, DATA, N)
(略)
#define _IO_sputn(__fp, __s, __n) _IO_XSPUTN (__fp, __s, __n)

__xsputn 関数を呼んでいるもよう...
関数テーブルらしく、どれが該当するのかはっきりしないが、その1つとして
glibc-2.7\libio\wfileops.c を見てみる。

--- wfileops.c ---

_IO_size_t
_IO_wfile_xsputn(_IO_FILE *f,
                 const void *data,
                 _IO_size_t n)
{
    register const wchar_t *s = (const wchar_t *) data;
    _IO_size_t to_do = n;
    int must_flush = 0;
    _IO_size_t count;

    if (n <= 0)
        return 0;

    /* This is an optimized implementation.
       If the amount to be written straddles a block boundary
       (or the filebuf is unbuffered), use sys_write directly. */

    /* First figure out how much space is available in the buffer. */
    count = f->_wide_data->_IO_write_end - 
            f->_wide_data->_IO_write_ptr;

    if ((f->_flags & _IO_LINE_BUF) && 
        (f->_flags & _IO_CURRENTLY_PUTTING))
    {
        count = f->_wide_data->_IO_buf_end - 
                f->_wide_data->_IO_write_ptr;
        if (count >= n)
        {
            register const wchar_t *p;
            for (p = s + n; p > s; )
            {
                if (*--p == L'\n')
                {
                    count = p - s + 1;
                    must_flush = 1;
                    break;
                }
            }
        }
    }
    /* Then fill the buffer. */
    if (count > 0)
    {
        if (count > to_do)
            count = to_do;
        if (count > 20)
        {
#ifdef _LIBC
            f->_wide_data->_IO_write_ptr =
                __wmempcpy(f->_wide_data->_IO_write_ptr, s, count);
#else
            wmemcpy(f->_wide_data->_IO_write_ptr, s, count);
            f->_wide_data->_IO_write_ptr += count;
#endif
            s += count;
        }
        else
        {
            register wchar_t *p = f->_wide_data->_IO_write_ptr;
            register int i = (int) count;
            while (--i >= 0)
                *p++ = *s++;
            f->_wide_data->_IO_write_ptr = p;
        }
        to_do -= count;
    }

    if (to_do > 0)
        to_do -= INTUSE(_IO_wdefault_xsputn) (f, s, to_do);

    if (must_flush && 
        f->_wide_data->_IO_write_ptr != 
        f->_wide_data->_IO_write_base)
        INTUSE(_IO_wdo_write)(f, 
                              f->_wide_data->_IO_write_base,
                              f->_wide_data->_IO_write_ptr 
                            - f->_wide_data->_IO_write_base);

    return n - to_do;
}
INTDEF(_IO_wfile_xsputn)

肝心なのは最後の部分の _IO_wdo_write 関数と思われる。

--- wfileops.c ---

/* Convert TO_DO wide character from DATA to FP.
   Then mark FP as having empty buffers. */
int
_IO_wdo_write(_IO_FILE *fp,
              const wchar_t *data,
              _IO_size_t to_do)
{
    struct _IO_codecvt *cc = fp->_codecvt;

    if (to_do > 0)
    {
        if (fp->_IO_write_end == fp->_IO_write_ptr && 
            fp->_IO_write_end != fp->_IO_write_base)
        {
            if (_IO_new_do_write(fp, 
                                 fp->_IO_write_base,
                                 fp->_IO_write_ptr - fp->_IO_write_base) == EOF)
                return WEOF;
        }

        do
        {
            enum __codecvt_result result;
            const wchar_t *new_data;

            /* Now convert from the internal format into the external buffer.  */
            result = (*cc->__codecvt_do_out)(
                        cc, 
                        &fp->_wide_data->_IO_state,
                        data, data + to_do, &new_data,
                        fp->_IO_write_ptr,
                        fp->_IO_buf_end,
                        &fp->_IO_write_ptr);

            /* Write out what we produced so far.  */
            if (_IO_new_do_write(fp, 
                                 fp->_IO_write_base,
                                 fp->_IO_write_ptr - fp->_IO_write_base) == EOF)
                /* Something went wrong.  */
                return WEOF;

            to_do -= new_data - data;

            /* Next see whether we had problems during the conversion.  If yes,
               we cannot go on.  */
            if (result != __codecvt_ok && 
                (result != __codecvt_partial || new_data - data == 0))
                break;

            data = new_data;
        }
        while (to_do > 0);
    }

    _IO_wsetg(fp, 
              fp->_wide_data->_IO_buf_base, 
              fp->_wide_data->_IO_buf_base,
              fp->_wide_data->_IO_buf_base);

    fp->_wide_data->_IO_write_base = 
    fp->_wide_data->_IO_write_ptr  = 
    fp->_wide_data->_IO_buf_base;

    fp->_wide_data->_IO_write_end = ((fp->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
                   ? fp->_wide_data->_IO_buf_base
                   : fp->_wide_data->_IO_buf_end);

    return to_do == 0 ? 0 : WEOF;
}
INTDEF(_IO_wdo_write)

ふぅ、_IO_new_do_write が肝心か...

--- glibc-2.7/libio/fileops.c ---

/* Write TO_DO bytes from DATA to FP.
   Then mark FP as having empty buffers. */

int
_IO_new_do_write(_IO_FILE *fp,
                 const char *data,
                 _IO_size_t to_do)
{
    return (to_do == 0 || 
            (_IO_size_t) new_do_write (fp, data, to_do) == to_do) 
        ? 0 : EOF;
}
INTDEF2(_IO_new_do_write, _IO_do_write)

static
_IO_size_t
new_do_write(_IO_FILE *fp,
             const char *data,
             _IO_size_t to_do)
{
    _IO_size_t count;

    if (fp->_flags & _IO_IS_APPENDING)
        /* On a system without a proper O_APPEND implementation,
           you would need to sys_seek(0, SEEK_END) here, but is
           is not needed nor desirable for Unix- or Posix-like systems.
           Instead, just indicate that offset (before and after) is
           unpredictable. */
        fp->_offset = _IO_pos_BAD;
    else if (fp->_IO_read_end != fp->_IO_write_base)
    {
        _IO_off64_t new_pos = _IO_SYSSEEK(fp, 
                                          fp->_IO_write_base - 
                                          fp->_IO_read_end, 
                                          1);
        if (new_pos == _IO_pos_BAD)
            return 0;

        fp->_offset = new_pos;
    }

    count = _IO_SYSWRITE(fp, data, to_do);

    if (fp->_cur_column && count)
        fp->_cur_column = INTUSE(_IO_adjust_column) (fp->_cur_column - 1, data,
                         count) + 1;
    _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
    fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_buf_base;
    fp->_IO_write_end = (fp->_mode <= 0
               && (fp->_flags & (_IO_LINE_BUF+_IO_UNBUFFERED))
               ? fp->_IO_buf_base : fp->_IO_buf_end);

    return count;
}

Home / fwrite
http://usskim.web.fc2.com/
inserted by FC2 system