1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
//
//! `file_offset` provides a platform-independent way of atomically reading and
//! writing files at specified offsets.
//!
//! ```
//! use file_offset::FileExt;
//! use std::fs::File;
//! use std::str;
//!
//! let mut buffer = [0; 2048];
//! let f = File::open("src/lib.rs").unwrap();
//! f.read_offset(&mut buffer, 3);
//! print!("{}", str::from_utf8(&buffer).unwrap());
//! ```

use std::fs::File;
use std::io;

mod sys;

/// This trait provides the extension methods for reading and writing files at
/// specified offsets.
///
/// Note the difference between Windows and Unix behavior listed in the
/// "Platform-specific behavior" sections.
pub trait FileExt {
    /// Reads a number of bytes, starting at a given file offset.
    ///
    /// Returns the number of bytes read.
    ///
    /// The offset is relative to the start of the file and thus independent of
    /// the current cursor. Note that similarly to `File::read`, returning with
    /// a short read is not an error. Additionally, read errors that are of
    /// `ErrorKind::Interrupted` are transient and the read call should
    /// usually be retried.
    ///
    /// # Platform-specific behavior
    ///
    /// This function delegates to `std::os::unix::fs::FileExt::read_at` and
    /// thus the `pread64` function on Unix and to
    /// `std::os::windows::fs::FileExt::seek_read` and hence to a `ReadFile`
    /// function call using the `lpOverlapped` parameter on Windows.
    ///
    /// The actions performed by these functions are **not identical**. In
    /// particular, the Windows version of this function moves the file cursor,
    /// whereas the Unix version does not.
    fn read_offset(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;

    /// Writes a number of bytes, starting at a given file offset.
    ///
    /// Returns the number of bytes written.
    ///
    /// The offset is relative to the start of the file and thus independent of
    /// the current cursor. Note that similarly to `File::write`, returning
    /// with a short write is not an error. Additionally, write errors that are
    /// of `ErrorKind::Interrupted` are transient and the write call should
    /// usually be retried.
    ///
    /// # Platform-specific behavior
    ///
    /// This function delegates to `std::os::unix::fs::FileExt::write_at` and
    /// thus the `pwrite64` function on Unix and to
    /// `std::os::windows::fs::FileExt::seek_write` and hence to a `WriteFile`
    /// function call using the `lpOverlapped` parameter on Windows.
    ///
    /// The actions performed by these functions are **not identical**. In
    /// particular, the Windows version of this function moves the file cursor,
    /// whereas the Unix version does not.
    fn write_offset(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
}

impl FileExt for File {
    #[inline]
    fn read_offset(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
        sys::read_offset(self, buf, offset)
    }
    #[inline]
    fn write_offset(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
        sys::write_offset(self, buf, offset)
    }
}