Skip to content

Commit 85f3f02

Browse files
committed
Added proper error handling to WAD commands
1 parent 3fd701c commit 85f3f02

File tree

3 files changed

+50
-41
lines changed

3 files changed

+50
-41
lines changed

src/bin/rustii/info.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ fn print_ticket_info(ticket: ticket::Ticket, cert: Option<cert::Certificate>) {
126126
} else {
127127
println!(" Title ID: {}", hex::encode(ticket.title_id).to_uppercase());
128128
}
129-
let converted_ver = versions::dec_to_standard(ticket.title_version, &hex::encode(ticket.title_id), None);
129+
let converted_ver = versions::dec_to_standard(ticket.title_version, &hex::encode(ticket.title_id), Some(ticket.common_key_index == 2));
130130
if hex::encode(ticket.title_id).eq("0000000100000001") {
131131
println!(" Title Version: {} (boot2v{})", ticket.title_version, ticket.title_version);
132132
} else if hex::encode(ticket.title_id)[..8].eq("00000001") && converted_ver.is_some() {

src/bin/rustii/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,10 @@ fn main() -> Result<()> {
5151
wad::convert_wad(input, target, output)?
5252
},
5353
Some(wad::Commands::Pack { input, output}) => {
54-
wad::pack_wad(input, output)
54+
wad::pack_wad(input, output)?
5555
},
5656
Some(wad::Commands::Unpack { input, output }) => {
57-
wad::unpack_wad(input, output)
57+
wad::unpack_wad(input, output)?
5858
},
5959
&None => { /* This is for me handled by clap */}
6060
}

src/bin/rustii/title/wad.rs

Lines changed: 47 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ impl fmt::Display for Target {
7474
pub fn convert_wad(input: &str, target: &ConvertTargets, output: &Option<String>) -> Result<()> {
7575
let in_path = Path::new(input);
7676
if !in_path.exists() {
77-
bail!("Source WAD \"{}\" could not be found.", input);
77+
bail!("Source WAD \"{}\" could not be found.", in_path.display());
7878
}
7979
// Parse the target passed to identify the encryption target.
8080
let target = if target.dev {
@@ -119,18 +119,21 @@ pub fn convert_wad(input: &str, target: &ConvertTargets, output: &Option<String>
119119
title.ticket.set_signature_issuer(String::from("Root-CA00000002-XS00000006"))?;
120120
title_key_new = crypto::encrypt_title_key(title_key, 0, title.ticket.title_id, Some(true));
121121
title.ticket.common_key_index = 0;
122+
title.tmd.is_vwii = 0;
122123
},
123124
Target::Retail => {
124125
title.tmd.set_signature_issuer(String::from("Root-CA00000001-CP00000004"))?;
125126
title.ticket.set_signature_issuer(String::from("Root-CA00000001-XS00000003"))?;
126127
title_key_new = crypto::encrypt_title_key(title_key, 0, title.ticket.title_id, Some(false));
127128
title.ticket.common_key_index = 0;
129+
title.tmd.is_vwii = 0;
128130
},
129131
Target::Vwii => {
130132
title.tmd.set_signature_issuer(String::from("Root-CA00000001-CP00000004"))?;
131133
title.ticket.set_signature_issuer(String::from("Root-CA00000001-XS00000003"))?;
132134
title_key_new = crypto::encrypt_title_key(title_key, 2, title.ticket.title_id, Some(false));
133135
title.ticket.common_key_index = 2;
136+
title.tmd.is_vwii = 1;
134137
}
135138
}
136139
title.ticket.title_key = title_key_new;
@@ -140,56 +143,56 @@ pub fn convert_wad(input: &str, target: &ConvertTargets, output: &Option<String>
140143
Ok(())
141144
}
142145

143-
pub fn pack_wad(input: &str, output: &str) {
146+
pub fn pack_wad(input: &str, output: &str) -> Result<()> {
144147
let in_path = Path::new(input);
145148
if !in_path.exists() {
146-
panic!("Error: Source directory does not exist.");
149+
bail!("Source directory \"{}\" does not exist.", in_path.display());
147150
}
148151
// Read TMD file (only accept one file).
149-
let tmd_files: Vec<PathBuf> = glob(&format!("{}/*.tmd", in_path.display()))
150-
.expect("failed to read glob pattern")
152+
let tmd_files: Vec<PathBuf> = glob(&format!("{}/*.tmd", in_path.display()))?
151153
.filter_map(|f| f.ok()).collect();
152154
if tmd_files.is_empty() {
153-
panic!("Error: No TMD file found in the source directory.");
155+
bail!("No TMD file found in the source directory.");
154156
} else if tmd_files.len() > 1 {
155-
panic!("Error: More than one TMD file found in the source directory.")
157+
bail!("More than one TMD file found in the source directory.");
156158
}
157-
let tmd = tmd::TMD::from_bytes(&fs::read(&tmd_files[0]).expect("could not read TMD file")).unwrap();
159+
let tmd = tmd::TMD::from_bytes(&fs::read(&tmd_files[0]).with_context(|| "Could not open TMD file for reading.")?)
160+
.with_context(|| "The provided TMD file appears to be invalid.")?;
158161
// Read Ticket file (only accept one file).
159-
let ticket_files: Vec<PathBuf> = glob(&format!("{}/*.tik", in_path.display()))
160-
.expect("failed to read glob pattern")
162+
let ticket_files: Vec<PathBuf> = glob(&format!("{}/*.tik", in_path.display()))?
161163
.filter_map(|f| f.ok()).collect();
162164
if ticket_files.is_empty() {
163-
panic!("Error: No Ticket file found in the source directory.");
165+
bail!("No Ticket file found in the source directory.");
164166
} else if ticket_files.len() > 1 {
165-
panic!("Error: More than one Ticket file found in the source directory.")
167+
bail!("More than one Ticket file found in the source directory.");
166168
}
167-
let tik = ticket::Ticket::from_bytes(&fs::read(&ticket_files[0]).expect("could not read Ticket file")).unwrap();
169+
let tik = ticket::Ticket::from_bytes(&fs::read(&ticket_files[0]).with_context(|| "Could not open Ticket file for reading.")?)
170+
.with_context(|| "The provided Ticket file appears to be invalid.")?;
168171
// Read cert chain (only accept one file).
169-
let cert_files: Vec<PathBuf> = glob(&format!("{}/*.cert", in_path.display()))
170-
.expect("failed to read glob pattern")
172+
let cert_files: Vec<PathBuf> = glob(&format!("{}/*.cert", in_path.display()))?
171173
.filter_map(|f| f.ok()).collect();
172174
if cert_files.is_empty() {
173-
panic!("Error: No cert file found in the source directory.");
175+
bail!("No cert file found in the source directory.");
174176
} else if cert_files.len() > 1 {
175-
panic!("Error: More than one Cert file found in the source directory.")
177+
bail!("More than one Cert file found in the source directory.");
176178
}
177-
let cert_chain = cert::CertificateChain::from_bytes(&fs::read(&cert_files[0]).expect("could not read cert chain file")).unwrap();
179+
let cert_chain = cert::CertificateChain::from_bytes(&fs::read(&cert_files[0]).with_context(|| "Could not open cert chain file for reading.")?)
180+
.with_context(|| "The provided certificate chain appears to be invalid.")?;
178181
// Read footer, if one exists (only accept one file).
179-
let footer_files: Vec<PathBuf> = glob(&format!("{}/*.footer", in_path.display()))
180-
.expect("failed to read glob pattern")
182+
let footer_files: Vec<PathBuf> = glob(&format!("{}/*.footer", in_path.display()))?
181183
.filter_map(|f| f.ok()).collect();
182184
let mut footer: Vec<u8> = Vec::new();
183185
if footer_files.len() == 1 {
184-
footer = fs::read(&footer_files[0]).unwrap();
186+
footer = fs::read(&footer_files[0]).with_context(|| "Could not open footer file for reading.")?;
185187
}
186188
// Iterate over expected content and read it into a content region.
187-
let mut content_region = content::ContentRegion::new(tmd.content_records.clone()).expect("could not create content region");
189+
let mut content_region = content::ContentRegion::new(tmd.content_records.clone())?;
188190
for content in tmd.content_records.clone() {
189-
let data = fs::read(format!("{}/{:08X}.app", in_path.display(), content.index)).expect("could not read required content");
190-
content_region.load_content(&data, content.index as usize, tik.dec_title_key()).expect("failed to load content into ContentRegion");
191+
let data = fs::read(format!("{}/{:08X}.app", in_path.display(), content.index)).with_context(|| format!("Could not open content file \"{:08X}.app\" for reading.", content.index))?;
192+
content_region.load_content(&data, content.index as usize, tik.dec_title_key())
193+
.expect("failed to load content into ContentRegion, this is probably because content was modified which isn't supported yet");
191194
}
192-
let wad = wad::WAD::from_parts(&cert_chain, &[], &tik, &tmd, &content_region, &footer).expect("failed to create WAD");
195+
let wad = wad::WAD::from_parts(&cert_chain, &[], &tik, &tmd, &content_region, &footer).with_context(|| "An unknown error occurred while building a WAD from the input files.")?;
193196
// Write out WAD file.
194197
let mut out_path = PathBuf::from(output);
195198
match out_path.extension() {
@@ -202,33 +205,39 @@ pub fn pack_wad(input: &str, output: &str) {
202205
out_path.set_extension("wad");
203206
}
204207
}
205-
fs::write(out_path, wad.to_bytes().unwrap()).expect("could not write to wad file");
208+
fs::write(out_path.clone(), wad.to_bytes()?).with_context(|| format!("Could not open output file \"{}\" for writing.", out_path.display()))?;
206209
println!("WAD file packed!");
210+
Ok(())
207211
}
208212

209-
pub fn unpack_wad(input: &str, output: &str) {
210-
let wad_file = fs::read(input).expect("could not read WAD");
211-
let title = title::Title::from_bytes(&wad_file).unwrap();
213+
pub fn unpack_wad(input: &str, output: &str) -> Result<()> {
214+
let in_path = Path::new(input);
215+
if !in_path.exists() {
216+
bail!("Source WAD \"{}\" could not be found.", input);
217+
}
218+
let wad_file = fs::read(in_path).with_context(|| format!("Failed to open WAD file \"{}\" for reading.", in_path.display()))?;
219+
let title = title::Title::from_bytes(&wad_file).with_context(|| format!("The provided WAD file \"{}\" appears to be invalid.", in_path.display()))?;
212220
let tid = hex::encode(title.tmd.title_id);
213221
// Create output directory if it doesn't exist.
214-
if !Path::new(output).exists() {
215-
fs::create_dir(output).expect("could not create output directory");
216-
}
217222
let out_path = Path::new(output);
223+
if !Path::new(out_path).exists() {
224+
fs::create_dir(out_path).with_context(|| format!("The output directory \"{}\" could not be created.", out_path.display()))?;
225+
}
218226
// Write out all WAD components.
219227
let tmd_file_name = format!("{}.tmd", tid);
220-
fs::write(Path::join(out_path, tmd_file_name), title.tmd.to_bytes().unwrap()).expect("could not write TMD file");
228+
fs::write(Path::join(out_path, tmd_file_name.clone()), title.tmd.to_bytes()?).with_context(|| format!("Failed to open TMD file \"{}\" for writing.", tmd_file_name))?;
221229
let ticket_file_name = format!("{}.tik", tid);
222-
fs::write(Path::join(out_path, ticket_file_name), title.ticket.to_bytes().unwrap()).expect("could not write Ticket file");
230+
fs::write(Path::join(out_path, ticket_file_name.clone()), title.ticket.to_bytes()?).with_context(|| format!("Failed to open Ticket file \"{}\" for writing.", ticket_file_name))?;
223231
let cert_file_name = format!("{}.cert", tid);
224-
fs::write(Path::join(out_path, cert_file_name), title.cert_chain.to_bytes().unwrap()).expect("could not write Cert file");
232+
fs::write(Path::join(out_path, cert_file_name.clone()), title.cert_chain.to_bytes()?).with_context(|| format!("Failed to open certificate chain file \"{}\" for writing.", cert_file_name))?;
225233
let meta_file_name = format!("{}.footer", tid);
226-
fs::write(Path::join(out_path, meta_file_name), title.meta()).expect("could not write footer file");
234+
fs::write(Path::join(out_path, meta_file_name.clone()), title.meta()).with_context(|| format!("Failed to open footer file \"{}\" for writing.", meta_file_name))?;
227235
// Iterate over contents, decrypt them, and write them out.
228236
for i in 0..title.tmd.num_contents {
229237
let content_file_name = format!("{:08X}.app", title.content.content_records[i as usize].index);
230-
let dec_content = title.get_content_by_index(i as usize).unwrap();
231-
fs::write(Path::join(out_path, content_file_name), dec_content).unwrap();
238+
let dec_content = title.get_content_by_index(i as usize).with_context(|| format!("Failed to unpack content with Content ID {:08X}.", title.content.content_records[i as usize].content_id))?;
239+
fs::write(Path::join(out_path, content_file_name), dec_content).with_context(|| format!("Failed to open content file \"{:08X}.app\" for writing.", title.content.content_records[i as usize].content_id))?;
232240
}
233241
println!("WAD file unpacked!");
242+
Ok(())
234243
}

0 commit comments

Comments
 (0)