Skip to content

Commit 82c8cb2

Browse files
committed
auto merge of #13133 : alexcrichton/rust/issue-13130, r=brson
The libuv fs wrappers are very thin wrappers around the syscalls they correspond to, and a notable worrisome case is the write syscall. This syscall is not guaranteed to write the entire buffer provided, so we may have to continue calling uv_fs_write if a short write occurs. Closes #13130
2 parents de85948 + 5fddb42 commit 82c8cb2

File tree

3 files changed

+32
-11
lines changed

3 files changed

+32
-11
lines changed

src/librustuv/file.rs

+29-8
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use std::c_str::CString;
1212
use std::c_str;
1313
use std::cast::transmute;
1414
use std::cast;
15-
use std::libc::{c_int, c_char, c_void, size_t};
15+
use std::libc::{c_int, c_char, c_void, size_t, ssize_t};
1616
use std::libc;
1717
use std::rt::task::BlockedTask;
1818
use std::io::{FileStat, IoError};
@@ -74,11 +74,32 @@ impl FsRequest {
7474
pub fn write(loop_: &Loop, fd: c_int, buf: &[u8], offset: i64)
7575
-> Result<(), UvError>
7676
{
77-
execute_nop(|req, cb| unsafe {
78-
uvll::uv_fs_write(loop_.handle, req,
79-
fd, buf.as_ptr() as *c_void,
80-
buf.len() as size_t, offset, cb)
81-
})
77+
// In libuv, uv_fs_write is basically just shelling out to a write()
78+
// syscall at some point, with very little fluff around it. This means
79+
// that write() could actually be a short write, so we need to be sure
80+
// to call it continuously if we get a short write back. This method is
81+
// expected to write the full data if it returns success.
82+
let mut written = 0;
83+
while written < buf.len() {
84+
let offset = if offset == -1 {
85+
offset
86+
} else {
87+
offset + written as i64
88+
};
89+
match execute(|req, cb| unsafe {
90+
uvll::uv_fs_write(loop_.handle,
91+
req,
92+
fd,
93+
buf.as_ptr().offset(written as int) as *c_void,
94+
(buf.len() - written) as size_t,
95+
offset,
96+
cb)
97+
}).map(|req| req.get_result()) {
98+
Err(e) => return Err(e),
99+
Ok(n) => { written += n as uint; }
100+
}
101+
}
102+
Ok(())
82103
}
83104

84105
pub fn read(loop_: &Loop, fd: c_int, buf: &mut [u8], offset: i64)
@@ -227,7 +248,7 @@ impl FsRequest {
227248
})
228249
}
229250

230-
pub fn get_result(&self) -> c_int {
251+
pub fn get_result(&self) -> ssize_t {
231252
unsafe { uvll::get_result_from_fs_req(self.req) }
232253
}
233254

@@ -309,7 +330,7 @@ fn execute(f: |*uvll::uv_fs_t, uvll::uv_fs_cb| -> c_int)
309330
unsafe { uvll::set_data_for_req(req.req, &slot) }
310331
});
311332
match req.get_result() {
312-
n if n < 0 => Err(UvError(n)),
333+
n if n < 0 => Err(UvError(n as i32)),
313334
_ => Ok(req),
314335
}
315336
}

src/librustuv/uvll.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ pub unsafe fn set_stdio_container_stream(c: *uv_stdio_container_t,
426426
}
427427

428428
// data access helpers
429-
pub unsafe fn get_result_from_fs_req(req: *uv_fs_t) -> c_int {
429+
pub unsafe fn get_result_from_fs_req(req: *uv_fs_t) -> ssize_t {
430430
rust_uv_get_result_from_fs_req(req)
431431
}
432432
pub unsafe fn get_ptr_from_fs_req(req: *uv_fs_t) -> *libc::c_void {
@@ -501,7 +501,7 @@ extern {
501501
fn rust_uv_get_udp_handle_from_send_req(req: *uv_udp_send_t) -> *uv_udp_t;
502502

503503
fn rust_uv_populate_uv_stat(req_in: *uv_fs_t, stat_out: *uv_stat_t);
504-
fn rust_uv_get_result_from_fs_req(req: *uv_fs_t) -> c_int;
504+
fn rust_uv_get_result_from_fs_req(req: *uv_fs_t) -> ssize_t;
505505
fn rust_uv_get_ptr_from_fs_req(req: *uv_fs_t) -> *libc::c_void;
506506
fn rust_uv_get_path_from_fs_req(req: *uv_fs_t) -> *c_char;
507507
fn rust_uv_get_loop_from_fs_req(req: *uv_fs_t) -> *uv_loop_t;

src/rt/rust_uv.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ rust_uv_req_type_max() {
9797
return UV_REQ_TYPE_MAX;
9898
}
9999

100-
int
100+
ssize_t
101101
rust_uv_get_result_from_fs_req(uv_fs_t* req) {
102102
return req->result;
103103
}

0 commit comments

Comments
 (0)