From 72c2abe98ffaa956517a8127251d41bf4060846e Mon Sep 17 00:00:00 2001 From: Weiyi Wang Date: Mon, 18 Nov 2019 10:58:20 -0500 Subject: [PATCH] support card2 save --- libsave3ds/src/cart_save_data.rs | 22 +++++++++++++--------- libsave3ds/src/lib.rs | 28 ++++++++++++++++++++++++---- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/libsave3ds/src/cart_save_data.rs b/libsave3ds/src/cart_save_data.rs index 8321c67..8e57fae 100644 --- a/libsave3ds/src/cart_save_data.rs +++ b/libsave3ds/src/cart_save_data.rs @@ -7,25 +7,26 @@ use crate::wear_leveling::*; use std::rc::Rc; pub struct CartSaveData { - wear_leveling: Rc, + wear_leveling: Option>, save_data: SaveData, } impl CartSaveData { pub fn new( file: Rc, + wear_leveling: bool, key: [u8; 16], key_cmac: [u8; 16], repeat_ctr: bool, ) -> Result { - let wear_leveling = Rc::new(WearLeveling::new(file)?); + let (wear_leveling, file): (_, Rc) = if wear_leveling { + let wear_leveling = Rc::new(WearLeveling::new(file)?); + (Some(wear_leveling.clone()), wear_leveling) + } else { + (None, file) + }; - let save = Rc::new(AesCtrFile::new( - wear_leveling.clone(), - key, - [0; 16], - repeat_ctr, - )); + let save = Rc::new(AesCtrFile::new(file, key, [0; 16], repeat_ctr)); Ok(CartSaveData { wear_leveling, @@ -49,7 +50,10 @@ impl FileSystem for CartSaveData { fn commit(&self) -> Result<(), Error> { self.save_data.commit()?; - self.wear_leveling.commit() + if let Some(wear_leveling) = &self.wear_leveling { + wear_leveling.commit()?; + } + Ok(()) } fn stat(&self) -> Result { diff --git a/libsave3ds/src/lib.rs b/libsave3ds/src/lib.rs index df3e70c..ecd6f03 100644 --- a/libsave3ds/src/lib.rs +++ b/libsave3ds/src/lib.rs @@ -46,6 +46,12 @@ use std::io::{Read, Seek, SeekFrom}; use std::path::*; use std::rc::Rc; +struct CartInfo { + wear_leveling: bool, + key_y: [u8; 16], + repeat_ctr: bool, +} + pub struct Resource { sd: Option>, nand: Option>, @@ -406,7 +412,7 @@ impl Resource { SaveData::new(file, SaveDataType::Bare) } - pub fn get_cart_save_key_y(&self) -> Result<([u8; 16], bool), Error> { + fn get_cart_info(&self) -> Result { let game = disk_file::DiskFile::new(std::fs::File::open( self.game_path.as_ref().ok_or(Error::MissingGame)?, )?)?; @@ -420,6 +426,12 @@ impl Resource { let mut cci_flags = [0; 8]; game.read(0x188, &mut cci_flags)?; + let wear_leveling = match cci_flags[5] { + 1 => true, + 2 => false, + _ => return Err(Error::BrokenGame), + }; + let cxi_offset = read_struct::(&game, 0x120)?.v * 0x200; let cxi_len = read_struct::(&game, 0x124)?.v * 0x200; let cxi = sub_file::SubFile::new(Rc::new(game), cxi_offset as usize, cxi_len as usize)?; @@ -552,7 +564,11 @@ impl Resource { _ => return Err(Error::Unsupported), } - Ok((key_y, repeat_ctr)) + Ok(CartInfo { + wear_leveling, + key_y, + repeat_ctr, + }) } pub fn open_cart_save(&self, path: &str, write: bool) -> Result { @@ -563,11 +579,15 @@ impl Resource { .open(path)?, )?); - let (key_y, repeat_ctr) = self.get_cart_save_key_y()?; + let CartInfo { + wear_leveling, + key_y, + repeat_ctr, + } = self.get_cart_info()?; let key = key_engine::scramble(self.key_x_dec.ok_or(Error::MissingBoot9)?, key_y); let key_cmac = key_engine::scramble(self.key_x_sign.ok_or(Error::MissingBoot9)?, key_y); - CartSaveData::new(file, key, key_cmac, repeat_ctr) + CartSaveData::new(file, wear_leveling, key, key_cmac, repeat_ctr) } pub fn open_db(&self, db_type: DbType, write: bool) -> Result {