bb_flasher_sd/
flashing.rs1use std::io::{BufReader, BufWriter, Read, Seek, SeekFrom, Write};
2use std::path::Path;
3use std::sync::Weak;
4
5use futures::channel::mpsc;
6use sha2::{Digest, Sha256};
7
8use crate::customization::Customization;
9use crate::helpers::{chan_send, check_arc, progress, sha256_reader_progress};
10use crate::{Error, Result, Status};
11
12fn read_aligned(mut img: impl Read, buf: &mut [u8]) -> Result<usize> {
13 let mut pos = 0;
14
15 while pos != buf.len() {
16 let count = img.read(&mut buf[pos..])?;
17 if count == 0 {
19 buf[pos..].fill(0);
20 return Ok(pos);
21 }
22
23 pos += count;
24 }
25
26 Ok(pos)
27}
28
29fn write_sd(
30 mut img: impl Read,
31 img_size: u64,
32 mut sd: impl Write,
33 mut hasher: Option<&mut Sha256>,
34 mut chan: Option<&mut mpsc::Sender<Status>>,
35 cancel: Option<&Weak<()>>,
36) -> Result<()> {
37 let mut buf = [0u8; 512];
38 let mut pos = 0;
39
40 chan_send(
41 chan.as_mut().map_or(None, |p| Some(p)),
42 Status::Flashing(0.0),
43 );
44 loop {
45 let count = read_aligned(&mut img, &mut buf)?;
46 if count == 0 {
47 break;
48 }
49
50 sd.write_all(&buf)?;
53 if let Some(ref mut h) = hasher {
54 h.update(&buf[..count]);
55 }
56
57 pos += count;
58 chan_send(
59 chan.as_mut().map_or(None, |p| Some(p)),
60 Status::Flashing(progress(pos, img_size)),
61 );
62 check_arc(cancel)?;
63 }
64
65 sd.flush().map_err(Into::into)
66}
67
68pub fn flash<R: Read>(
97 img_resolver: impl FnOnce() -> std::io::Result<(R, u64)>,
98 dst: &Path,
99 verify: bool,
100 mut chan: Option<mpsc::Sender<Status>>,
101 customization: Option<Customization>,
102 cancel: Option<Weak<()>>,
103) -> Result<()> {
104 let mut sd = crate::pal::open(dst)?;
105 let (img, img_size) = img_resolver()?;
106
107 chan_send(chan.as_mut(), Status::Flashing(0.0));
108 if verify {
109 let mut hasher = Sha256::new();
110 write_sd(
111 img,
112 img_size,
113 BufWriter::new(&mut sd),
114 Some(&mut hasher),
115 chan.as_mut(),
116 cancel.as_ref(),
117 )?;
118
119 let img_hash: [u8; 32] = hasher
120 .finalize()
121 .as_slice()
122 .try_into()
123 .expect("SHA-256 is 32 bytes");
124
125 chan_send(chan.as_mut(), Status::Verifying(0.0));
127 sd.seek(std::io::SeekFrom::Start(0))?;
128 let hash =
129 sha256_reader_progress(BufReader::new((&mut sd).take(img_size)), img_size, chan)?;
130
131 check_arc(cancel.as_ref())?;
132 if hash != img_hash {
133 tracing::debug!("Sd SHA256: {:?}", hash);
134 return Err(Error::Sha256Verification);
135 }
136 } else {
137 write_sd(
138 img,
139 img_size,
140 BufWriter::new(&mut sd),
141 None,
142 chan.as_mut(),
143 cancel.as_ref(),
144 )?;
145 }
146
147 check_arc(cancel.as_ref())?;
148
149 if let Some(c) = customization {
150 sd.seek(SeekFrom::Start(0))?;
151 c.customize(sd)?;
152 }
153
154 Ok(())
155}