diff options
author | shirosaki <shirosaki@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-03-22 14:05:31 +0000 |
---|---|---|
committer | shirosaki <shirosaki@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2012-03-22 14:05:31 +0000 |
commit | 7cbff3b9dd51dbb43cbd3757bd719b52eb03a3b1 (patch) | |
tree | e9ec2f5bcf9816343a64838124d9fbf0e436e8a6 /io.c | |
parent | 3d22e33a0636eaf4ea659372b59c3f98fb247b7c (diff) |
* io.c (static int io_fflush): add the definition.
Use it in set_binary_mode_with_seek_cur().
* io.c (set_binary_mode_with_seek_cur): refactoring to split the
content into io_unread(). Fix the possibility of buffer overflow.
* io.c (io_unread): add new implementation for Windows. Previous one
caused invalid cursor position using IO#pos with OS text mode. New
one fixes the bug.
* test/ruby/test_io_m17n.rb
(TestIO_M17N#test_pos_dont_move_cursor_position): add a test for
above bug.
[ruby-core:43497] [Bug #6179]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@35111 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'io.c')
-rw-r--r-- | io.c | 63 |
1 files changed, 47 insertions, 16 deletions
@@ -377,6 +377,7 @@ rb_cloexec_fcntl_dupfd(int fd, int minfd) #define rb_sys_fail_path(path) rb_sys_fail_str(path) static int io_fflush(rb_io_t *); +static rb_io_t *flush_before_seek(rb_io_t *fptr); #define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE) #define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE) @@ -412,16 +413,12 @@ static int io_fflush(rb_io_t *); (ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\ }\ } while(0) + /* - * We use io_seek to back cursor position when changing mode from text to binary, - * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding - * conversion for working properly with mode change. - */ -/* - * Return previous translation mode. + * IO unread with taking care of removed '\r' in text mode. */ -static inline int -set_binary_mode_with_seek_cur(rb_io_t *fptr) +static void +io_unread(rb_io_t *fptr) { off_t r, pos; ssize_t read_size; @@ -429,23 +426,34 @@ set_binary_mode_with_seek_cur(rb_io_t *fptr) long newlines = 0; long extra_max; char *p; + char *buf; - if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY; - + rb_io_check_closed(fptr); if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) { - return setmode(fptr->fd, O_BINARY); + return; } - if (io_fflush(fptr) < 0) { - rb_sys_fail(0); - } errno = 0; + if (!rb_w32_fd_is_text(fptr->fd)) { + r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR); + if (r < 0 && errno) { + if (errno == ESPIPE) + fptr->mode |= FMODE_DUPLEX; + return; + } + + fptr->rbuf.off = 0; + fptr->rbuf.len = 0; + return; + } + pos = lseek(fptr->fd, 0, SEEK_CUR); if (pos < 0 && errno) { if (errno == ESPIPE) fptr->mode |= FMODE_DUPLEX; - return setmode(fptr->fd, O_BINARY); + return; } + /* add extra offset for removed '\r' in rbuf */ extra_max = pos - fptr->rbuf.len; p = fptr->rbuf.ptr + fptr->rbuf.off; @@ -454,6 +462,8 @@ set_binary_mode_with_seek_cur(rb_io_t *fptr) if (extra_max == newlines) break; p++; } + + buf = ALLOC_N(char, fptr->rbuf.len + newlines); while (newlines >= 0) { r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET); if (newlines == 0) break; @@ -461,7 +471,7 @@ set_binary_mode_with_seek_cur(rb_io_t *fptr) newlines--; continue; } - read_size = _read(fptr->fd, fptr->rbuf.ptr, fptr->rbuf.len + newlines); + read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines); if (read_size < 0) { rb_sys_fail_path(fptr->pathv); } @@ -475,6 +485,25 @@ set_binary_mode_with_seek_cur(rb_io_t *fptr) } fptr->rbuf.off = 0; fptr->rbuf.len = 0; + return; +} + +/* + * We use io_seek to back cursor position when changing mode from text to binary, + * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding + * conversion for working properly with mode change. + * + * Return previous translation mode. + */ +static inline int +set_binary_mode_with_seek_cur(rb_io_t *fptr) +{ + if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY; + + if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) { + return setmode(fptr->fd, O_BINARY); + } + flush_before_seek(fptr); return setmode(fptr->fd, O_BINARY); } #define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr) @@ -605,6 +634,7 @@ rb_io_s_try_convert(VALUE dummy, VALUE io) return rb_io_check_io(io); } +#if !(defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32)) static void io_unread(rb_io_t *fptr) { @@ -624,6 +654,7 @@ io_unread(rb_io_t *fptr) fptr->rbuf.len = 0; return; } +#endif static rb_encoding *io_input_encoding(rb_io_t *fptr); |