Skip to content

Commit 5c10b96

Browse files
committed
[Rust Install Loader] Fix panic if 100% archive extraction progress reported twice
- Previously, the child would send a 100% value the first time, which caused the parent to think the thread was complete. It would then discard the progress reader/writer - Then the child thread would send another 100% (this was added in a previous commit to make sure 100% was always reported) after the progress reader/writer was deleted, causing a panic (on purpose, as usually sending values shouldn't ever fail) - This happened on my machine, and while the installer still managhed to continue when this happened, I should probably fix it...
1 parent 8310279 commit 5c10b96

File tree

1 file changed

+51
-27
lines changed

1 file changed

+51
-27
lines changed

install_loader/src/archive_extractor.rs

+51-27
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
use crate::version;
22
use progress_streams::ProgressReader;
33
use std::path::{Path, PathBuf};
4-
use std::sync::mpsc;
4+
use std::sync::mpsc::{self, TryRecvError};
55
use std::sync::mpsc::{Receiver, Sender};
66
use std::{fs, thread};
77
use tar::Archive;
88
use xz2::read::XzDecoder;
99

10-
enum ExtractionStatusInternal {
10+
enum ExtractionReport {
11+
InProgress { percentage: usize },
12+
Finished,
13+
}
14+
15+
enum ExtractionStateMachine {
1116
NotStarted,
12-
Started(Receiver<Result<usize, String>>),
17+
Started(Receiver<Result<ExtractionReport, String>>),
1318
Finished,
1419
}
1520

@@ -21,22 +26,22 @@ pub enum ExtractionStatus {
2126
}
2227

2328
pub struct ArchiveExtractor {
24-
receiver: ExtractionStatusInternal,
29+
receiver: ExtractionStateMachine,
2530
}
2631

2732
impl ArchiveExtractor {
2833
pub fn new() -> ArchiveExtractor {
2934
ArchiveExtractor {
30-
receiver: ExtractionStatusInternal::NotStarted,
35+
receiver: ExtractionStateMachine::NotStarted,
3136
}
3237
}
3338

3439
pub fn start_extraction(&mut self, sub_folder_path: &Path) {
3540
match self.receiver {
36-
ExtractionStatusInternal::NotStarted => {
37-
let (sender, receiver) = mpsc::channel::<Result<usize, String>>();
41+
ExtractionStateMachine::NotStarted => {
42+
let (sender, receiver) = mpsc::channel::<Result<ExtractionReport, String>>();
3843
extract_archive_new_thread(sub_folder_path, sender);
39-
self.receiver = ExtractionStatusInternal::Started(receiver);
44+
self.receiver = ExtractionStateMachine::Started(receiver);
4045
}
4146
_ => {}
4247
}
@@ -45,31 +50,47 @@ impl ArchiveExtractor {
4550
// This doesn't correctly handle the case where
4651
pub fn poll_status(&mut self) -> ExtractionStatus {
4752
match &mut self.receiver {
48-
ExtractionStatusInternal::NotStarted => ExtractionStatus::NotStarted,
49-
ExtractionStatusInternal::Started(receiver) => {
50-
if let Ok(progress) = receiver.try_recv() {
51-
match progress {
52-
Ok(progress) => {
53-
if progress >= 100 {
54-
self.receiver = ExtractionStatusInternal::Finished
55-
}
56-
ExtractionStatus::Started(Some(progress))
53+
ExtractionStateMachine::NotStarted => ExtractionStatus::NotStarted,
54+
ExtractionStateMachine::Started(receiver) => {
55+
// Check if an extraction update was received, nothing was received, or if there was an error
56+
let progress = match receiver.try_recv() {
57+
Ok(progress) => progress,
58+
Err(e) => match e {
59+
TryRecvError::Empty => return ExtractionStatus::Started(None),
60+
TryRecvError::Disconnected => {
61+
return ExtractionStatus::Error(
62+
"ArchiveExtractor channel disconnected unexpectedly".to_string(),
63+
)
5764
}
58-
Err(error_str) => ExtractionStatus::Error(error_str),
65+
},
66+
};
67+
68+
// If there was an extraction error, report the error
69+
let progress = match progress {
70+
Ok(progress) => progress,
71+
Err(error_str) => return ExtractionStatus::Error(error_str),
72+
};
73+
74+
// If extraction complete, report 100%, and advance to final state
75+
// Otherwise, return the percentage completion and stay in same state
76+
let percentage: usize = match progress {
77+
ExtractionReport::Finished => {
78+
self.receiver = ExtractionStateMachine::Finished;
79+
100
5980
}
60-
} else {
61-
// Extraction is started but no additional progress to tell
62-
ExtractionStatus::Started(None)
63-
}
81+
ExtractionReport::InProgress { percentage } => percentage,
82+
};
83+
84+
ExtractionStatus::Started(Some(percentage))
6485
}
65-
ExtractionStatusInternal::Finished => ExtractionStatus::Finished,
86+
ExtractionStateMachine::Finished => ExtractionStatus::Finished,
6687
}
6788
}
6889
}
6990

7091
fn extract_archive_new_thread(
7192
sub_folder_path: &Path,
72-
progress_update: Sender<Result<usize, String>>,
93+
progress_update: Sender<Result<ExtractionReport, String>>,
7394
) {
7495
let mut path_copy = PathBuf::new();
7596
path_copy.push(sub_folder_path);
@@ -79,7 +100,10 @@ fn extract_archive_new_thread(
79100
});
80101
}
81102

82-
fn extract_archive(sub_folder_path: &Path, progress_update: Sender<Result<usize, String>>) {
103+
fn extract_archive(
104+
sub_folder_path: &Path,
105+
progress_update: Sender<Result<ExtractionReport, String>>,
106+
) {
83107
let saved_git_tag_path = sub_folder_path.join("installer_loader_extraction_lock.txt");
84108

85109
// During compilation, include the installer archive in .tar.xz format
@@ -103,7 +127,7 @@ fn extract_archive(sub_folder_path: &Path, progress_update: Sender<Result<usize,
103127
if let Some(percentage) = progress_counter.update(progress_bytes) {
104128
println!("Extraction {}%", percentage);
105129
progress_update
106-
.send(Ok(percentage))
130+
.send(Ok(ExtractionReport::InProgress { percentage }))
107131
.expect("Failed to send progress update - aborting extraction");
108132
}
109133
});
@@ -123,7 +147,7 @@ You can also try 'Run as Administrator', but the installer may not work correctl
123147
// so we don't need to extract again unless installer's version changes
124148
write_extraction_lock(&saved_git_tag_path);
125149
progress_update
126-
.send(Ok(100))
150+
.send(Ok(ExtractionReport::Finished))
127151
.expect("Failed to send progress update - aborting extraction");
128152
println!("Extraction Complete.");
129153
}

0 commit comments

Comments
 (0)