Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit cf9cf3f

Browse files
authoredAug 23, 2016
Rollup merge of rust-lang#35704 - tbu-:pr_pread_pwrite, r=sfackler
Implement `read_offset` and `write_offset` These functions allow to read from and write to a file from multiple threads without changing the per-file cursor, avoiding the race between the seek and the read.
2 parents f81abcf + 4e48924 commit cf9cf3f

File tree

5 files changed

+135
-2
lines changed

5 files changed

+135
-2
lines changed
 

‎src/libstd/fs.rs

+71
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,30 @@ impl File {
348348
inner: self.inner.duplicate()?
349349
})
350350
}
351+
352+
/// Reads a number of bytes starting from a given offset.
353+
///
354+
/// The offset is relative to the file start and thus independent from the
355+
/// current cursor.
356+
///
357+
/// Note that similar to `File::read`, it is not an error to return a short
358+
/// read.
359+
#[unstable(feature = "file_offset", issue = "35918")]
360+
pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
361+
self.inner.read_at(buf, offset)
362+
}
363+
364+
/// Writes a number of bytes starting from a given offset.
365+
///
366+
/// The offset is relative to the file start and thus independent from the
367+
/// current cursor.
368+
///
369+
/// Note that similar to `File::write`, it is not an error to return a
370+
/// short write.
371+
#[unstable(feature = "file_offset", issue = "35918")]
372+
pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
373+
self.inner.write_at(buf, offset)
374+
}
351375
}
352376

353377
impl AsInner<fs_imp::File> for File {
@@ -1893,6 +1917,53 @@ mod tests {
18931917
check!(fs::remove_file(filename));
18941918
}
18951919

1920+
#[test]
1921+
fn file_test_io_read_write_at() {
1922+
let tmpdir = tmpdir();
1923+
let filename = tmpdir.join("file_rt_io_file_test_read_write_at.txt");
1924+
let mut buf = [0; 256];
1925+
let write1 = "asdf";
1926+
let write2 = "qwer-";
1927+
let write3 = "-zxcv";
1928+
let content = "qwer-asdf-zxcv";
1929+
{
1930+
let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
1931+
let mut rw = check!(oo.open(&filename));
1932+
assert_eq!(check!(rw.write_at(write1.as_bytes(), 5)), write1.len());
1933+
assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0);
1934+
assert_eq!(check!(rw.read_at(&mut buf, 5)), write1.len());
1935+
assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
1936+
assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0);
1937+
assert_eq!(check!(rw.write(write2.as_bytes())), write2.len());
1938+
assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5);
1939+
assert_eq!(check!(rw.read(&mut buf)), write1.len());
1940+
assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
1941+
assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
1942+
assert_eq!(check!(rw.read_at(&mut buf[..write2.len()], 0)), write2.len());
1943+
assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2));
1944+
assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
1945+
assert_eq!(check!(rw.write_at(write3.as_bytes(), 9)), write3.len());
1946+
assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
1947+
}
1948+
{
1949+
let mut read = check!(File::open(&filename));
1950+
assert_eq!(check!(read.read_at(&mut buf, 0)), content.len());
1951+
assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
1952+
assert_eq!(check!(read.seek(SeekFrom::Current(0))), 0);
1953+
assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9);
1954+
assert_eq!(check!(read.read_at(&mut buf, 0)), content.len());
1955+
assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
1956+
assert_eq!(check!(read.seek(SeekFrom::Current(0))), 9);
1957+
assert_eq!(check!(read.read(&mut buf)), write3.len());
1958+
assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3));
1959+
assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
1960+
assert_eq!(check!(read.read_at(&mut buf, 0)), content.len());
1961+
assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
1962+
assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
1963+
}
1964+
check!(fs::remove_file(&filename));
1965+
}
1966+
18961967
#[test]
18971968
fn file_test_stat_is_correct_on_is_file() {
18981969
let tmpdir = tmpdir();

‎src/libstd/sys/unix/fd.rs

+22-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
use prelude::v1::*;
1414

1515
use io::{self, Read};
16-
use libc::{self, c_int, size_t, c_void};
16+
use libc::{self, c_int, off_t, size_t, c_void};
1717
use mem;
1818
use sync::atomic::{AtomicBool, Ordering};
1919
use sys::cvt;
@@ -42,7 +42,7 @@ impl FileDesc {
4242
let ret = cvt(unsafe {
4343
libc::read(self.fd,
4444
buf.as_mut_ptr() as *mut c_void,
45-
buf.len() as size_t)
45+
buf.len())
4646
})?;
4747
Ok(ret as usize)
4848
}
@@ -52,6 +52,16 @@ impl FileDesc {
5252
(&mut me).read_to_end(buf)
5353
}
5454

55+
pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
56+
let ret = cvt(unsafe {
57+
libc::pread(self.fd,
58+
buf.as_mut_ptr() as *mut c_void,
59+
buf.len(),
60+
offset as off_t)
61+
})?;
62+
Ok(ret as usize)
63+
}
64+
5565
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
5666
let ret = cvt(unsafe {
5767
libc::write(self.fd,
@@ -61,6 +71,16 @@ impl FileDesc {
6171
Ok(ret as usize)
6272
}
6373

74+
pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
75+
let ret = cvt(unsafe {
76+
libc::pwrite(self.fd,
77+
buf.as_ptr() as *const c_void,
78+
buf.len(),
79+
offset as off_t)
80+
})?;
81+
Ok(ret as usize)
82+
}
83+
6484
#[cfg(not(any(target_env = "newlib", target_os = "solaris", target_os = "emscripten")))]
6585
pub fn set_cloexec(&self) -> io::Result<()> {
6686
unsafe {

‎src/libstd/sys/unix/fs.rs

+8
Original file line numberDiff line numberDiff line change
@@ -477,10 +477,18 @@ impl File {
477477
self.0.read_to_end(buf)
478478
}
479479

480+
pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
481+
self.0.read_at(buf, offset)
482+
}
483+
480484
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
481485
self.0.write(buf)
482486
}
483487

488+
pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
489+
self.0.write_at(buf, offset)
490+
}
491+
484492
pub fn flush(&self) -> io::Result<()> { Ok(()) }
485493

486494
pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {

‎src/libstd/sys/windows/fs.rs

+8
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,10 @@ impl File {
312312
self.handle.read(buf)
313313
}
314314

315+
pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
316+
self.handle.read_at(buf, offset)
317+
}
318+
315319
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
316320
self.handle.read_to_end(buf)
317321
}
@@ -320,6 +324,10 @@ impl File {
320324
self.handle.write(buf)
321325
}
322326

327+
pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
328+
self.handle.write_at(buf, offset)
329+
}
330+
323331
pub fn flush(&self) -> io::Result<()> { Ok(()) }
324332

325333
pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {

‎src/libstd/sys/windows/handle.rs

+26
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,19 @@ impl RawHandle {
106106
}
107107
}
108108

109+
pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
110+
let mut read = 0;
111+
let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD;
112+
unsafe {
113+
let mut overlapped: c::OVERLAPPED = mem::zeroed();
114+
overlapped.Offset = offset as u32;
115+
overlapped.OffsetHigh = (offset >> 32) as u32;
116+
cvt(c::ReadFile(self.0, buf.as_mut_ptr() as c::LPVOID,
117+
len, &mut read, &mut overlapped))?;
118+
}
119+
Ok(read as usize)
120+
}
121+
109122
pub unsafe fn read_overlapped(&self,
110123
buf: &mut [u8],
111124
overlapped: *mut c::OVERLAPPED)
@@ -176,6 +189,19 @@ impl RawHandle {
176189
Ok(amt as usize)
177190
}
178191

192+
pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
193+
let mut written = 0;
194+
let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD;
195+
unsafe {
196+
let mut overlapped: c::OVERLAPPED = mem::zeroed();
197+
overlapped.Offset = offset as u32;
198+
overlapped.OffsetHigh = (offset >> 32) as u32;
199+
cvt(c::WriteFile(self.0, buf.as_ptr() as c::LPVOID,
200+
len, &mut written, &mut overlapped))?;
201+
}
202+
Ok(written as usize)
203+
}
204+
179205
pub fn duplicate(&self, access: c::DWORD, inherit: bool,
180206
options: c::DWORD) -> io::Result<Handle> {
181207
let mut ret = 0 as c::HANDLE;

0 commit comments

Comments
 (0)
Please sign in to comment.