1use opts;
2use results::elapsed;
3use std::{
4 io::{Result, Write},
5 time::SystemTime,
6};
7use units;
8
9pub struct ErrHandler<E: std::io::Write> {
12 e: E,
14 report: bool,
17 continue_on_err: bool,
19
20 prev_report: usize,
22}
23
24impl<E: Write> ErrHandler<E> {
25 pub fn new(e: E, o: &opts::Opts) -> Self {
26 let report = o.status == opts::StatusLevel::Progress;
27 let continue_on_err = o.cflag(opts::CFlag::NOERROR);
28 ErrHandler {
29 e,
30 report,
31 continue_on_err,
32 prev_report: 0,
33 }
34 }
35}
36impl<E: Write> ErrHandler<E> {
37 pub const BLOCK_THRESHOLD_FOR_REPORT: usize = 25;
39 pub const LINE_THRESHOLD_FOR_REPORT: usize = 20;
41 pub const STANDARD_BYTE_THRESHOLD: usize = 5 * units::MB;
43
44 pub fn handle<T>(&mut self, res: Result<T>) -> Result<Option<T>> {
46 match (res, self.continue_on_err) {
47 (Err(err), true) => {
48 writeln!(self.e, "io error: <{}>; continuing", err);
49 Ok(None)
50 },
51 (Err(err), false) => Err(err),
52 (Ok(t), _) => Ok(Some(t)),
53 }
54 }
55
56 pub fn report_status_standard(&mut self, bytes: usize, start: &SystemTime) -> std::io::Result<()> {
58 if self.report && bytes.saturating_sub(self.prev_report) > Self::STANDARD_BYTE_THRESHOLD {
59 self.prev_report = bytes;
60 writeln!(
61 self,
62 "dd in progress: elapsed: {}: wrote {} bytes",
63 elapsed(start),
64 bytes
65 )?;
66 }
67 Ok(())
68 }
69
70 pub fn report_status_block(&mut self, lines: usize, start: &SystemTime) {
71 if self.report && lines % Self::LINE_THRESHOLD_FOR_REPORT == 0 {
72 writeln!(
73 self,
74 "dd in progress: unblock: elapsed: {}, wrote {} lines",
75 elapsed(&start),
76 lines
77 );
78 }
79 }
80
81 pub fn report_status_unblock(&mut self, blocks: usize, start: &SystemTime) {
82 if self.report && blocks % Self::BLOCK_THRESHOLD_FOR_REPORT == 0 {
83 writeln!(
84 self,
85 "dd in progress: unblock: elapsed: {}, wrote {} fixed-length blocks",
86 elapsed(&start),
87 blocks
88 );
89 }
90 }
91}
92impl<E: Write> Write for ErrHandler<E> {
93 fn write(&mut self, buf: &[u8]) -> Result<usize> { self.e.write(buf) }
94
95 fn flush(&mut self) -> Result<()> { self.e.flush() }
96}