summaryrefslogtreecommitdiff
path: root/io.c
diff options
context:
space:
mode:
authorshirosaki <shirosaki@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-03-22 14:05:31 +0000
committershirosaki <shirosaki@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-03-22 14:05:31 +0000
commit7cbff3b9dd51dbb43cbd3757bd719b52eb03a3b1 (patch)
treee9ec2f5bcf9816343a64838124d9fbf0e436e8a6 /io.c
parent3d22e33a0636eaf4ea659372b59c3f98fb247b7c (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.c63
1 files changed, 47 insertions, 16 deletions
diff --git a/io.c b/io.c
index 3fb9f1af02..d569e4d8d7 100644
--- a/io.c
+++ b/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)
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);