Skip to content

Commit f1e3e7c

Browse files
committed
detail Missing errors
1 parent 7b783cf commit f1e3e7c

File tree

3 files changed

+73
-52
lines changed

3 files changed

+73
-52
lines changed

libsave3ds/src/error.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,14 @@ pub enum Error {
1414
AlreadyExist,
1515
DeletingRoot,
1616
SignatureMismatch,
17-
Missing,
17+
MissingBoot9,
18+
MissingSd,
19+
MissingNand,
20+
MissingGame,
21+
MissingPriv,
22+
MissingKeyY2F,
23+
MissingOtp,
24+
BrokenSd,
1825
NotEmpty,
1926
Unsupported,
2027
UniqueIdMismatch,
@@ -41,10 +48,14 @@ impl fmt::Display for Error {
4148
Error::AlreadyExist => write!(f, "The file or directory to create already exists"),
4249
Error::DeletingRoot => write!(f, "Trying to delete the root directory"),
4350
Error::SignatureMismatch => write!(f, "Signature mismatch, caused by corrupted data"),
44-
Error::Missing => write!(
45-
f,
46-
"Provided resource (SD, NAND, OTP etc.) is insufficient for opening the archive"
47-
),
51+
Error::MissingBoot9 => write!(f, "Missing boot9.bin"),
52+
Error::MissingSd => write!(f, "Cannot open SD due to missing SD or movable.sed"),
53+
Error::MissingNand => write!(f, "Missing NAND"),
54+
Error::MissingGame => write!(f, "Missing game"),
55+
Error::MissingPriv => write!(f, "Missing private header"),
56+
Error::MissingKeyY2F => write!(f, "Missing 0x2F key Y"),
57+
Error::MissingOtp => write!(f, "Missing OTP"),
58+
Error::BrokenSd => write!(f, "Corrupted SD"),
4859
Error::NotEmpty => write!(f, "Trying to delete a non-empty directory"),
4960
Error::Unsupported => write!(f, "The operation is not supported on this archive"),
5061
Error::UniqueIdMismatch => {

libsave3ds/src/lib.rs

Lines changed: 56 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,8 @@ impl Resource {
152152
};
153153

154154
let key_x_db = if let Some(otp_path) = otp_path {
155-
let key_otp = key_otp.ok_or(Error::Missing)?;
156-
let mut iv_otp = iv_otp.ok_or(Error::Missing)?;
155+
let key_otp = key_otp.ok_or(Error::MissingBoot9)?;
156+
let mut iv_otp = iv_otp.ok_or(Error::MissingBoot9)?;
157157
let mut otp_file = std::fs::File::open(otp_path)?;
158158
let mut otp = [0; 0x100];
159159
otp_file.read_exact(&mut otp)?;
@@ -174,7 +174,8 @@ impl Resource {
174174
return make_error(Error::BrokenOtp);
175175
}
176176

177-
let (otp_salt, mut otp_salt_iv, mut otp_salt_block) = otp_salt.ok_or(Error::Missing)?;
177+
let (otp_salt, mut otp_salt_iv, mut otp_salt_block) =
178+
otp_salt.ok_or(Error::MissingBoot9)?;
178179
let mut hasher = Sha256::new();
179180
hasher.input(&otp[0x90..0xAC]);
180181
hasher.input(&otp_salt[..]);
@@ -221,21 +222,21 @@ impl Resource {
221222

222223
pub fn format_sd_ext(&self, id: u64, param: &ExtDataFormatParam) -> Result<(), Error> {
223224
ExtData::format(
224-
self.sd.as_ref().ok_or(Error::Missing)?.as_ref(),
225+
self.sd.as_ref().ok_or(Error::MissingSd)?.as_ref(),
225226
&["extdata"],
226227
id,
227-
self.key_sign.ok_or(Error::Missing)?,
228+
self.key_sign.ok_or(Error::MissingBoot9)?,
228229
None,
229230
param,
230231
)
231232
}
232233

233234
pub fn open_sd_ext(&self, id: u64, write: bool) -> Result<ExtData, Error> {
234235
ExtData::new(
235-
self.sd.as_ref().ok_or(Error::Missing)?.clone(),
236+
self.sd.as_ref().ok_or(Error::MissingSd)?.clone(),
236237
&["extdata"],
237238
id,
238-
self.key_sign.ok_or(Error::Missing)?,
239+
self.key_sign.ok_or(Error::MissingBoot9)?,
239240
false,
240241
write,
241242
)
@@ -256,13 +257,13 @@ impl Resource {
256257
let id_low = format!("{:08x}", id & 0xFFFF_FFFF);
257258
let sub_path = ["title", &id_high, &id_low, "data", "00000001.sav"];
258259

259-
let sd = self.sd.as_ref().ok_or(Error::Missing)?;
260+
let sd = self.sd.as_ref().ok_or(Error::MissingSd)?;
260261
sd.create(&sub_path, len)?;
261262
let file = sd.open(&sub_path, true)?;
262263

263264
SaveData::format(
264265
file,
265-
SaveDataType::Sd(self.key_sign.ok_or(Error::Missing)?, id),
266+
SaveDataType::Sd(self.key_sign.ok_or(Error::MissingBoot9)?, id),
266267
&param,
267268
block_count,
268269
)?;
@@ -278,12 +279,12 @@ impl Resource {
278279
let dec_file = self
279280
.sd
280281
.as_ref()
281-
.ok_or(Error::Missing)?
282+
.ok_or(Error::MissingSd)?
282283
.open(&sub_path, write)?;
283284

284285
SaveData::new(
285286
dec_file,
286-
SaveDataType::Sd(self.key_sign.ok_or(Error::Missing)?, id),
287+
SaveDataType::Sd(self.key_sign.ok_or(Error::MissingBoot9)?, id),
287288
)
288289
}
289290

@@ -300,19 +301,19 @@ impl Resource {
300301

301302
let sub_path = [
302303
"data",
303-
self.id0.as_ref().ok_or(Error::Missing)?,
304+
self.id0.as_ref().ok_or(Error::MissingNand)?,
304305
"sysdata",
305306
&format!("{:08x}", id),
306307
"00000000",
307308
];
308309

309-
let nand = self.nand.as_ref().ok_or(Error::Missing)?;
310+
let nand = self.nand.as_ref().ok_or(Error::MissingNand)?;
310311
nand.create(&sub_path, len)?;
311312
let file = nand.open(&sub_path, true)?;
312313

313314
SaveData::format(
314315
file,
315-
SaveDataType::Nand(self.key_sign.ok_or(Error::Missing)?, id),
316+
SaveDataType::Nand(self.key_sign.ok_or(Error::MissingBoot9)?, id),
316317
&param,
317318
block_count,
318319
)?;
@@ -321,10 +322,10 @@ impl Resource {
321322
}
322323

323324
pub fn open_nand_save(&self, id: u32, write: bool) -> Result<SaveData, Error> {
324-
let file = self.nand.as_ref().ok_or(Error::Missing)?.open(
325+
let file = self.nand.as_ref().ok_or(Error::MissingNand)?.open(
325326
&[
326327
"data",
327-
self.id0.as_ref().ok_or(Error::Missing)?,
328+
self.id0.as_ref().ok_or(Error::MissingNand)?,
328329
"sysdata",
329330
&format!("{:08x}", id),
330331
"00000000",
@@ -333,27 +334,35 @@ impl Resource {
333334
)?;
334335
SaveData::new(
335336
file,
336-
SaveDataType::Nand(self.key_sign.ok_or(Error::Missing)?, id),
337+
SaveDataType::Nand(self.key_sign.ok_or(Error::MissingBoot9)?, id),
337338
)
338339
}
339340

340341
pub fn format_nand_ext(&self, id: u64, param: &ExtDataFormatParam) -> Result<(), Error> {
341342
ExtData::format(
342-
self.nand.as_ref().ok_or(Error::Missing)?.as_ref(),
343-
&["data", self.id0.as_ref().ok_or(Error::Missing)?, "extdata"],
343+
self.nand.as_ref().ok_or(Error::MissingNand)?.as_ref(),
344+
&[
345+
"data",
346+
self.id0.as_ref().ok_or(Error::MissingNand)?,
347+
"extdata",
348+
],
344349
id,
345-
self.key_sign.ok_or(Error::Missing)?,
350+
self.key_sign.ok_or(Error::MissingBoot9)?,
346351
Some(1024 * 1024),
347352
param,
348353
)
349354
}
350355

351356
pub fn open_nand_ext(&self, id: u64, write: bool) -> Result<ExtData, Error> {
352357
ExtData::new(
353-
self.nand.as_ref().ok_or(Error::Missing)?.clone(),
354-
&["data", self.id0.as_ref().ok_or(Error::Missing)?, "extdata"],
358+
self.nand.as_ref().ok_or(Error::MissingNand)?.clone(),
359+
&[
360+
"data",
361+
self.id0.as_ref().ok_or(Error::MissingNand)?,
362+
"extdata",
363+
],
355364
id,
356-
self.key_sign.ok_or(Error::Missing)?,
365+
self.key_sign.ok_or(Error::MissingBoot9)?,
357366
true,
358367
write,
359368
)
@@ -397,7 +406,7 @@ impl Resource {
397406

398407
pub fn get_cart_save_key_y(&self) -> Result<([u8; 16], bool), Error> {
399408
let game = disk_file::DiskFile::new(std::fs::File::open(
400-
self.game_path.as_ref().ok_or(Error::Missing)?,
409+
self.game_path.as_ref().ok_or(Error::MissingGame)?,
401410
)?)?;
402411

403412
use byte_struct_common::*;
@@ -422,7 +431,8 @@ impl Resource {
422431

423432
let mut key_y_ncch = [0; 16];
424433
cxi.read(0, &mut key_y_ncch)?;
425-
let ncch_key = key_engine::scramble(self.key_x_ncch.ok_or(Error::Missing)?, key_y_ncch);
434+
let ncch_key =
435+
key_engine::scramble(self.key_x_ncch.ok_or(Error::MissingBoot9)?, key_y_ncch);
426436

427437
let ncch_version = read_struct::<U16le>(&cxi, 0x112)?.v;
428438
let exefs_offset = read_struct::<U32le>(&cxi, 0x1A0)?.v * 0x200;
@@ -498,14 +508,14 @@ impl Resource {
498508
// TODO: version 0 is unverified yet
499509
let mut key_y_block = vec![];
500510
key_y_block.extend_from_slice(&exheader_signature);
501-
key_y_block.extend_from_slice(&self.cart_id_short.ok_or(Error::Missing)?);
511+
key_y_block.extend_from_slice(&self.cart_id_short.ok_or(Error::MissingPriv)?);
502512
key_y[..].copy_from_slice(&key_y_block[..]);
503513
repeat_ctr = true;
504514
}
505515
2 => {
506516
let mut key_y_block = vec![];
507517
key_y_block.extend_from_slice(&exheader_signature);
508-
key_y_block.extend_from_slice(&self.cart_id_long.ok_or(Error::Missing)?);
518+
key_y_block.extend_from_slice(&self.cart_id_long.ok_or(Error::MissingPriv)?);
509519

510520
let mut hasher = Sha256::new();
511521
hasher.input(&key_y_block[..]);
@@ -517,7 +527,7 @@ impl Resource {
517527
6 => {
518528
let mut key_y_block = vec![];
519529
key_y_block.extend_from_slice(&exheader_signature);
520-
key_y_block.extend_from_slice(&self.cart_id_long.ok_or(Error::Missing)?);
530+
key_y_block.extend_from_slice(&self.cart_id_long.ok_or(Error::MissingPriv)?);
521531
key_y_block.extend_from_slice(&program_id);
522532
key_y_block.extend_from_slice(&exefs_hash);
523533

@@ -527,8 +537,8 @@ impl Resource {
527537

528538
// Yup this one use the same key x as ncch
529539
let cmac_key = key_engine::scramble(
530-
self.key_x_ncch.ok_or(Error::Missing)?,
531-
self.x2f_key_y.ok_or(Error::Missing)?,
540+
self.key_x_ncch.ok_or(Error::MissingBoot9)?,
541+
self.x2f_key_y.ok_or(Error::MissingKeyY2F)?,
532542
);
533543

534544
use cmac::*;
@@ -554,8 +564,8 @@ impl Resource {
554564
let save = wear_leveling::WearLeveling::new(file)?;
555565

556566
let (key_y, repeat_ctr) = self.get_cart_save_key_y()?;
557-
let key = key_engine::scramble(self.key_x_dec.ok_or(Error::Missing)?, key_y);
558-
let key_cmac = key_engine::scramble(self.key_x_sign.ok_or(Error::Missing)?, key_y);
567+
let key = key_engine::scramble(self.key_x_dec.ok_or(Error::MissingBoot9)?, key_y);
568+
let key_cmac = key_engine::scramble(self.key_x_sign.ok_or(Error::MissingBoot9)?, key_y);
559569

560570
let save = Rc::new(aes_ctr_file::AesCtrFile::new(
561571
Rc::new(save),
@@ -572,51 +582,51 @@ impl Resource {
572582
DbType::NandTitle => (
573583
self.nand
574584
.as_ref()
575-
.ok_or(Error::Missing)?
585+
.ok_or(Error::MissingNand)?
576586
.open(&["dbs", "title.db"], write)?,
577-
self.key_db.ok_or(Error::Missing)?,
587+
self.key_db.ok_or(Error::MissingOtp)?,
578588
),
579589
DbType::NandImport => (
580590
self.nand
581591
.as_ref()
582-
.ok_or(Error::Missing)?
592+
.ok_or(Error::MissingNand)?
583593
.open(&["dbs", "import.db"], write)?,
584-
self.key_db.ok_or(Error::Missing)?,
594+
self.key_db.ok_or(Error::MissingOtp)?,
585595
),
586596
DbType::TmpTitle => (
587597
self.nand
588598
.as_ref()
589-
.ok_or(Error::Missing)?
599+
.ok_or(Error::MissingNand)?
590600
.open(&["dbs", "tmp_t.db"], write)?,
591-
self.key_db.ok_or(Error::Missing)?,
601+
self.key_db.ok_or(Error::MissingOtp)?,
592602
),
593603
DbType::TmpImport => (
594604
self.nand
595605
.as_ref()
596-
.ok_or(Error::Missing)?
606+
.ok_or(Error::MissingNand)?
597607
.open(&["dbs", "tmp_i.db"], write)?,
598-
self.key_db.ok_or(Error::Missing)?,
608+
self.key_db.ok_or(Error::MissingOtp)?,
599609
),
600610
DbType::Ticket => (
601611
self.nand
602612
.as_ref()
603-
.ok_or(Error::Missing)?
613+
.ok_or(Error::MissingNand)?
604614
.open(&["dbs", "ticket.db"], write)?,
605-
self.key_db.ok_or(Error::Missing)?,
615+
self.key_db.ok_or(Error::MissingOtp)?,
606616
),
607617
DbType::SdTitle => (
608618
self.sd
609619
.as_ref()
610-
.ok_or(Error::Missing)?
620+
.ok_or(Error::MissingSd)?
611621
.open(&["dbs", "title.db"], write)?,
612-
self.key_sign.ok_or(Error::Missing)?,
622+
self.key_sign.ok_or(Error::MissingSd)?,
613623
),
614624
DbType::SdImport => (
615625
self.sd
616626
.as_ref()
617-
.ok_or(Error::Missing)?
627+
.ok_or(Error::MissingSd)?
618628
.open(&["dbs", "import.db"], write)?,
619-
self.key_sign.ok_or(Error::Missing)?,
629+
self.key_sign.ok_or(Error::MissingSd)?,
620630
),
621631
};
622632

libsave3ds/src/sd.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ impl Sd {
2626
.map(|a| a.file_type().map(|a| a.is_dir()).unwrap_or(false))
2727
.unwrap_or(false)
2828
})
29-
.ok_or(Error::Missing)??
29+
.ok_or(Error::BrokenSd)??
3030
.path();
3131
let key = scramble(key_x, key_y);
3232
Ok(Sd { path, key })

0 commit comments

Comments
 (0)