зеркало из https://github.com/github/ruby.git
* 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
This commit is contained in:
Родитель
3d22e33a06
Коммит
7cbff3b9dd
17
ChangeLog
17
ChangeLog
|
@ -1,3 +1,20 @@
|
||||||
|
Thu Mar 22 22:30:44 2012 Hiroshi Shirosaki <h.shirosaki@gmail.com>
|
||||||
|
|
||||||
|
* 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]
|
||||||
|
|
||||||
Thu Mar 22 19:55:08 2012 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
Thu Mar 22 19:55:08 2012 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
* win32/win32.c (rb_w32_fstat, rb_w32_fstati64): convert FILETIME
|
* win32/win32.c (rb_w32_fstat, rb_w32_fstati64): convert FILETIME
|
||||||
|
|
63
io.c
63
io.c
|
@ -377,6 +377,7 @@ rb_cloexec_fcntl_dupfd(int fd, int minfd)
|
||||||
#define rb_sys_fail_path(path) rb_sys_fail_str(path)
|
#define rb_sys_fail_path(path) rb_sys_fail_str(path)
|
||||||
|
|
||||||
static int io_fflush(rb_io_t *);
|
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_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
|
||||||
#define NEED_NEWLINE_DECORATOR_ON_WRITE(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;\
|
(ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
|
||||||
}\
|
}\
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We use io_seek to back cursor position when changing mode from text to binary,
|
* IO unread with taking care of removed '\r' in text mode.
|
||||||
* but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
|
|
||||||
* conversion for working properly with mode change.
|
|
||||||
*/
|
*/
|
||||||
/*
|
static void
|
||||||
* Return previous translation mode.
|
io_unread(rb_io_t *fptr)
|
||||||
*/
|
|
||||||
static inline int
|
|
||||||
set_binary_mode_with_seek_cur(rb_io_t *fptr)
|
|
||||||
{
|
{
|
||||||
off_t r, pos;
|
off_t r, pos;
|
||||||
ssize_t read_size;
|
ssize_t read_size;
|
||||||
|
@ -429,23 +426,34 @@ set_binary_mode_with_seek_cur(rb_io_t *fptr)
|
||||||
long newlines = 0;
|
long newlines = 0;
|
||||||
long extra_max;
|
long extra_max;
|
||||||
char *p;
|
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) {
|
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;
|
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);
|
pos = lseek(fptr->fd, 0, SEEK_CUR);
|
||||||
if (pos < 0 && errno) {
|
if (pos < 0 && errno) {
|
||||||
if (errno == ESPIPE)
|
if (errno == ESPIPE)
|
||||||
fptr->mode |= FMODE_DUPLEX;
|
fptr->mode |= FMODE_DUPLEX;
|
||||||
return setmode(fptr->fd, O_BINARY);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add extra offset for removed '\r' in rbuf */
|
/* add extra offset for removed '\r' in rbuf */
|
||||||
extra_max = pos - fptr->rbuf.len;
|
extra_max = pos - fptr->rbuf.len;
|
||||||
p = fptr->rbuf.ptr + fptr->rbuf.off;
|
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;
|
if (extra_max == newlines) break;
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buf = ALLOC_N(char, fptr->rbuf.len + newlines);
|
||||||
while (newlines >= 0) {
|
while (newlines >= 0) {
|
||||||
r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
|
r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
|
||||||
if (newlines == 0) break;
|
if (newlines == 0) break;
|
||||||
|
@ -461,7 +471,7 @@ set_binary_mode_with_seek_cur(rb_io_t *fptr)
|
||||||
newlines--;
|
newlines--;
|
||||||
continue;
|
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) {
|
if (read_size < 0) {
|
||||||
rb_sys_fail_path(fptr->pathv);
|
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.off = 0;
|
||||||
fptr->rbuf.len = 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);
|
return setmode(fptr->fd, O_BINARY);
|
||||||
}
|
}
|
||||||
#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
|
#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);
|
return rb_io_check_io(io);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !(defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32))
|
||||||
static void
|
static void
|
||||||
io_unread(rb_io_t *fptr)
|
io_unread(rb_io_t *fptr)
|
||||||
{
|
{
|
||||||
|
@ -624,6 +654,7 @@ io_unread(rb_io_t *fptr)
|
||||||
fptr->rbuf.len = 0;
|
fptr->rbuf.len = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static rb_encoding *io_input_encoding(rb_io_t *fptr);
|
static rb_encoding *io_input_encoding(rb_io_t *fptr);
|
||||||
|
|
||||||
|
|
|
@ -2415,4 +2415,19 @@ EOT
|
||||||
}
|
}
|
||||||
assert_equal(paths.map(&:encoding), encs, bug6072)
|
assert_equal(paths.map(&:encoding), encs, bug6072)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_pos_dont_move_cursor_position
|
||||||
|
bug6179 = '[ruby-core:43497]'
|
||||||
|
with_tmpdir {
|
||||||
|
str = "line one\r\nline two\r\nline three\r\n"
|
||||||
|
generate_file("tmp", str)
|
||||||
|
open("tmp", "r") do |f|
|
||||||
|
assert_equal("line one\n", f.readline)
|
||||||
|
assert_equal(10, f.pos, bug6179)
|
||||||
|
assert_equal("line two\n", f.readline, bug6179)
|
||||||
|
assert_equal(20, f.pos, bug6179)
|
||||||
|
assert_equal("line three\n", f.readline, bug6179)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end if /mswin|mingw/ =~ RUBY_PLATFORM
|
||||||
end
|
end
|
||||||
|
|
Загрузка…
Ссылка в новой задаче