aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--io.c26
-rw-r--r--test/ruby/test_io.rb10
2 files changed, 23 insertions, 13 deletions
diff --git a/io.c b/io.c
index bcd792861e..61d6548dbb 100644
--- a/io.c
+++ b/io.c
@@ -1534,7 +1534,7 @@ io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
}
else {
iov++;
- iovcnt--;
+ if (!--iovcnt) return 0;
}
retry:
@@ -1557,25 +1557,25 @@ io_binwritev(struct iovec *iov, int iovcnt, rb_io_t *fptr)
fptr->wbuf.len -= r;
}
else {
+ written_len -= fptr->wbuf.len;
fptr->wbuf.off = 0;
fptr->wbuf.len = 0;
}
}
- if (written_len == total) return written_len;
+ if (written_len == total) return total;
- for (i = 0; i < iovcnt; i++) {
- if (r > (ssize_t)iov[i].iov_len) {
- r -= iov[i].iov_len;
- iov[i].iov_len = 0;
- }
- else {
- iov[i].iov_base = (char *)iov[i].iov_base + r;
- iov[i].iov_len -= r;
- break;
- }
+ while (r >= (ssize_t)iov->iov_len) {
+ /* iovcnt > 0 */
+ r -= iov->iov_len;
+ iov->iov_len = 0;
+ iov++;
+ if (!--iovcnt) return total;
+ /* defensive check: written_len should == total */
}
+ iov->iov_base = (char *)iov->iov_base + r;
+ iov->iov_len -= r;
- errno = EAGAIN;
+ errno = EAGAIN;
}
if (rb_io_wait_writable(fptr->fd)) {
rb_io_check_closed(fptr);
diff --git a/test/ruby/test_io.rb b/test/ruby/test_io.rb
index 1fa9dbb443..c7de83784b 100644
--- a/test/ruby/test_io.rb
+++ b/test/ruby/test_io.rb
@@ -1236,6 +1236,16 @@ class TestIO < Test::Unit::TestCase
open(file, "rb") do |r|
assert_equal([line, line, "\n"], r.readlines)
end
+
+ line = "x"*99+"\n"
+ open(file, "wb") do |w|
+ w.write(line*81) # 8100 bytes
+ assert_equal(100, w.write("a"*99, "\n"))
+ end
+ open(file, "rb") do |r|
+ 81.times {assert_equal(line, r.gets)}
+ assert_equal("a"*99+"\n", r.gets)
+ end
end
end