libcoreinst/io/
mod.rs

1// Copyright 2019 CoreOS, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use anyhow::{bail, Result};
16use bincode::Options;
17use std::io::{ErrorKind, Read, Write};
18
19mod bls;
20mod compress;
21mod hash;
22mod ignition;
23mod initrd;
24mod limit;
25mod peek;
26mod tee;
27mod verify;
28mod xz;
29mod zstd;
30
31pub use self::bls::*;
32pub use self::compress::*;
33pub use self::hash::*;
34pub use self::ignition::*;
35pub use self::initrd::*;
36pub use self::limit::*;
37pub use self::peek::*;
38pub use self::tee::*;
39pub use self::verify::*;
40pub use self::xz::*;
41pub use self::zstd::*;
42
43// The default BufReader/BufWriter buffer size is 8 KiB, which isn't large
44// enough to fully amortize system call overhead.
45// https://github.com/rust-lang/rust/issues/49921
46// https://github.com/coreutils/coreutils/blob/6a3d2883/src/ioblksize.h
47pub const BUFFER_SIZE: usize = 256 * 1024;
48
49/// This is like `std::io:copy()`, but limits the number of bytes copied over. The `Read` trait has
50/// `take()`, but that takes ownership of the reader. We also take a buf to avoid re-initializing a
51/// block each time (std::io::copy() gets around this by using MaybeUninit, but that requires using
52/// nightly and unsafe functions).
53pub fn copy_n(
54    reader: &mut (impl Read + ?Sized),
55    writer: &mut (impl Write + ?Sized),
56    mut n: u64,
57    buf: &mut [u8],
58) -> Result<u64> {
59    let mut written = 0;
60    loop {
61        if n == 0 {
62            return Ok(written);
63        }
64        let bufn = if n < (buf.len() as u64) {
65            &mut buf[..n as usize]
66        } else {
67            &mut *buf
68        };
69        let len = match reader.read(bufn) {
70            Ok(0) => return Ok(written),
71            Ok(len) => len,
72            Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
73            Err(e) => return Err(e.into()),
74        };
75        assert!(len as u64 <= n);
76        writer.write_all(&bufn[..len])?;
77        written += len as u64;
78        n -= len as u64;
79    }
80}
81
82/// This is like `copy_n()` but errors if the number of bytes copied is less than expected.
83pub fn copy_exactly_n(
84    reader: &mut (impl Read + ?Sized),
85    writer: &mut (impl Write + ?Sized),
86    n: u64,
87    buf: &mut [u8],
88) -> Result<u64> {
89    let bytes_copied = copy_n(reader, writer, n, buf)?;
90    if bytes_copied != n {
91        bail!(
92            "expected to copy {} bytes but instead copied {} bytes",
93            n,
94            bytes_copied
95        );
96    }
97    Ok(n)
98}
99
100/// Provides uniform bincode options for all our serialization operations.
101pub fn bincoder() -> impl bincode::Options {
102    bincode::options()
103        .allow_trailing_bytes()
104        // make the defaults explicit
105        .with_no_limit()
106        .with_little_endian()
107        .with_varint_encoding()
108}
109
110#[cfg(test)]
111mod tests {
112    use super::*;
113
114    #[test]
115    fn test_copy_n() {
116        let mut sink = std::io::sink();
117        let mut buf = [0u8; 50];
118
119        let data = [0u8; 30];
120        assert_eq!(
121            copy_exactly_n(&mut &data[..], &mut sink, 0, &mut buf).unwrap(),
122            0
123        );
124        assert_eq!(
125            copy_exactly_n(&mut &data[..], &mut sink, 1, &mut buf).unwrap(),
126            1
127        );
128        assert_eq!(
129            copy_exactly_n(&mut &data[..], &mut sink, 29, &mut buf).unwrap(),
130            29
131        );
132        assert_eq!(
133            copy_exactly_n(&mut &data[..], &mut sink, 30, &mut buf).unwrap(),
134            30
135        );
136        assert_eq!(copy_n(&mut &data[..], &mut sink, 31, &mut buf).unwrap(), 30);
137        assert_eq!(copy_n(&mut &data[..], &mut sink, 49, &mut buf).unwrap(), 30);
138        assert_eq!(copy_n(&mut &data[..], &mut sink, 50, &mut buf).unwrap(), 30);
139        assert_eq!(copy_n(&mut &data[..], &mut sink, 51, &mut buf).unwrap(), 30);
140
141        let data = [0u8; 50];
142        assert_eq!(
143            copy_exactly_n(&mut &data[..], &mut sink, 0, &mut buf).unwrap(),
144            0
145        );
146        assert_eq!(
147            copy_exactly_n(&mut &data[..], &mut sink, 1, &mut buf).unwrap(),
148            1
149        );
150        assert_eq!(
151            copy_exactly_n(&mut &data[..], &mut sink, 49, &mut buf).unwrap(),
152            49
153        );
154        assert_eq!(
155            copy_exactly_n(&mut &data[..], &mut sink, 50, &mut buf).unwrap(),
156            50
157        );
158        assert_eq!(copy_n(&mut &data[..], &mut sink, 51, &mut buf).unwrap(), 50);
159
160        let data = [0u8; 80];
161        assert_eq!(
162            copy_exactly_n(&mut &data[..], &mut sink, 0, &mut buf).unwrap(),
163            0
164        );
165        assert_eq!(
166            copy_exactly_n(&mut &data[..], &mut sink, 1, &mut buf).unwrap(),
167            1
168        );
169        assert_eq!(
170            copy_exactly_n(&mut &data[..], &mut sink, 49, &mut buf).unwrap(),
171            49
172        );
173        assert_eq!(
174            copy_exactly_n(&mut &data[..], &mut sink, 50, &mut buf).unwrap(),
175            50
176        );
177        assert_eq!(
178            copy_exactly_n(&mut &data[..], &mut sink, 51, &mut buf).unwrap(),
179            51
180        );
181        assert_eq!(
182            copy_exactly_n(&mut &data[..], &mut sink, 79, &mut buf).unwrap(),
183            79
184        );
185        assert_eq!(
186            copy_exactly_n(&mut &data[..], &mut sink, 80, &mut buf).unwrap(),
187            80
188        );
189        assert_eq!(copy_n(&mut &data[..], &mut sink, 81, &mut buf).unwrap(), 80);
190    }
191}