Skip to content

Commit

Permalink
support card2 save
Browse files Browse the repository at this point in the history
  • Loading branch information
wwylele committed Nov 18, 2019
1 parent a9205da commit 72c2abe
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 13 deletions.
22 changes: 13 additions & 9 deletions libsave3ds/src/cart_save_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,26 @@ use crate::wear_leveling::*;
use std::rc::Rc;

pub struct CartSaveData {
wear_leveling: Rc<WearLeveling>,
wear_leveling: Option<Rc<WearLeveling>>,
save_data: SaveData,
}

impl CartSaveData {
pub fn new(
file: Rc<dyn RandomAccessFile>,
wear_leveling: bool,
key: [u8; 16],
key_cmac: [u8; 16],
repeat_ctr: bool,
) -> Result<CartSaveData, Error> {
let wear_leveling = Rc::new(WearLeveling::new(file)?);
let (wear_leveling, file): (_, Rc<dyn RandomAccessFile>) = 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,
Expand All @@ -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<Stat, Error> {
Expand Down
28 changes: 24 additions & 4 deletions libsave3ds/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Rc<Sd>>,
nand: Option<Rc<Nand>>,
Expand Down Expand Up @@ -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<CartInfo, Error> {
let game = disk_file::DiskFile::new(std::fs::File::open(
self.game_path.as_ref().ok_or(Error::MissingGame)?,
)?)?;
Expand All @@ -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::<U32le>(&game, 0x120)?.v * 0x200;
let cxi_len = read_struct::<U32le>(&game, 0x124)?.v * 0x200;
let cxi = sub_file::SubFile::new(Rc::new(game), cxi_offset as usize, cxi_len as usize)?;
Expand Down Expand Up @@ -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<CartSaveData, Error> {
Expand All @@ -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<Db, Error> {
Expand Down

0 comments on commit 72c2abe

Please sign in to comment.