summary refs log tree commit diff
path: root/sys_util/src/file_traits.rs
blob: c0c7a9b99d6d7aabb6d91d7094194c90a77f6827 (plain) (blame)
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::fs::File;
use std::io::{Error, ErrorKind, Result};
use std::os::unix::io::{AsRawFd, RawFd};

use data_model::VolatileSlice;

use libc::{c_void, read, write};

/// A trait for flushing the contents of a file to disk.
/// This is equivalent to File's `sync_all` method, but
/// wrapped in a trait so that it can be implemented for
/// other types.
pub trait FileSync {
    // Flush buffers related to this file to disk.
    fn fsync(&mut self) -> Result<()>;
}

impl FileSync for File {
    fn fsync(&mut self) -> Result<()> {
        self.sync_all()
    }
}

/// A trait for setting the size of a file.
/// This is equivalent to File's `set_len` method, but
/// wrapped in a trait so that it can be implemented for
/// other types.
pub trait FileSetLen {
    // Set the size of this file.
    // This is the moral equivalent of `ftruncate()`.
    fn set_len(&self, _len: u64) -> Result<()>;
}

impl FileSetLen for File {
    fn set_len(&self, len: u64) -> Result<()> {
        File::set_len(self, len)
    }
}

/// A trait similar to `Read` and `Write`, but uses volatile memory as buffers.
pub trait FileReadWriteVolatile {
    /// Read bytes from this file into the given slice, returning the number of bytes read on
    /// success.
    fn read_volatile(&mut self, slice: VolatileSlice) -> Result<usize>;

    /// Reads bytes from this into the given slice until all bytes in the slice are written, or an
    /// error is returned.
    fn read_exact_volatile(&mut self, mut slice: VolatileSlice) -> Result<()> {
        while slice.size() > 0 {
            let bytes_read = self.read_volatile(slice)?;
            if bytes_read == 0 {
                return Err(Error::from(ErrorKind::UnexpectedEof));
            }
            // Will panic if read_volatile read more bytes than we gave it, which would be worthy of
            // a panic.
            slice = slice.offset(bytes_read as u64).unwrap();
        }
        Ok(())
    }

    /// Write bytes from the slice to the given file, returning the number of bytes written on
    /// success.
    fn write_volatile(&mut self, slice: VolatileSlice) -> Result<usize>;

    /// Write bytes from the slice to the given file until all the bytes from the slice have been
    /// written, or an error is returned.
    fn write_all_volatile(&mut self, mut slice: VolatileSlice) -> Result<()> {
        while slice.size() > 0 {
            let bytes_written = self.write_volatile(slice)?;
            if bytes_written == 0 {
                return Err(Error::from(ErrorKind::WriteZero));
            }
            // Will panic if read_volatile read more bytes than we gave it, which would be worthy of
            // a panic.
            slice = slice.offset(bytes_written as u64).unwrap();
        }
        Ok(())
    }
}

impl FileReadWriteVolatile for File {
    fn read_volatile(&mut self, slice: VolatileSlice) -> Result<usize> {
        // Safe because only bytes inside the slice are accessed and the kernel is expected to
        // handle arbitrary memory for I/O.
        let ret = unsafe {
            read(
                self.as_raw_fd(),
                slice.as_ptr() as *mut c_void,
                slice.size() as usize,
            )
        };
        if ret >= 0 {
            Ok(ret as usize)
        } else {
            Err(Error::last_os_error())
        }
    }

    fn write_volatile(&mut self, slice: VolatileSlice) -> Result<usize> {
        // Safe because only bytes inside the slice are accessed and the kernel is expected to
        // handle arbitrary memory for I/O.
        let ret = unsafe {
            write(
                self.as_raw_fd(),
                slice.as_ptr() as *const c_void,
                slice.size() as usize,
            )
        };
        if ret >= 0 {
            Ok(ret as usize)
        } else {
            Err(Error::last_os_error())
        }
    }
}

/// A trait similar to `AsRawFd` but supports an arbitrary number of file descriptors.
pub trait AsRawFds {
    fn as_raw_fds(&self) -> Vec<RawFd>;
}

impl<T> AsRawFds for T
where
    T: AsRawFd,
{
    fn as_raw_fds(&self) -> Vec<RawFd> {
        vec![self.as_raw_fd()]
    }
}