Skip to content

Commit

Permalink
implement cart save write
Browse files Browse the repository at this point in the history
  • Loading branch information
wwylele committed Nov 14, 2019
1 parent 5c17df3 commit a9205da
Show file tree
Hide file tree
Showing 7 changed files with 265 additions and 69 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ If you want leave all parameters in default values, you can specify an empty opt
These parameters behave the same as those in the `fs:USER` 3DS service functions: `FormatSaveData`, `CreateSystemSaveData` and `CreateExtSaveData`. However, the `max_dir`/`max_file` specified here is two/one larger than the one in `CreateExtSaveData`, as the latter one automatically counts the required `/user`, `/boss` and `/icon`.
Title database files currently doesn't support `--format`.
Title database files and cartridge save currently don't support `--format`.
## Example command
```bash
Expand Down
58 changes: 58 additions & 0 deletions libsave3ds/src/cart_save_data.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
use crate::aes_ctr_file::*;
use crate::error::*;
use crate::file_system::*;
use crate::random_access_file::*;
use crate::save_data::*;
use crate::wear_leveling::*;
use std::rc::Rc;

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

impl CartSaveData {
pub fn new(
file: Rc<dyn RandomAccessFile>,
key: [u8; 16],
key_cmac: [u8; 16],
repeat_ctr: bool,
) -> Result<CartSaveData, Error> {
let wear_leveling = Rc::new(WearLeveling::new(file)?);

let save = Rc::new(AesCtrFile::new(
wear_leveling.clone(),
key,
[0; 16],
repeat_ctr,
));

Ok(CartSaveData {
wear_leveling,
save_data: SaveData::new(save, SaveDataType::Cart(key_cmac))?,
})
}
}

impl FileSystem for CartSaveData {
type FileType = <SaveData as FileSystem>::FileType;
type DirType = <SaveData as FileSystem>::DirType;
type NameType = <SaveData as FileSystem>::NameType;

fn open_file(&self, ino: u32) -> Result<Self::FileType, Error> {
self.save_data.open_file(ino)
}

fn open_dir(&self, ino: u32) -> Result<Self::DirType, Error> {
self.save_data.open_dir(ino)
}

fn commit(&self) -> Result<(), Error> {
self.save_data.commit()?;
self.wear_leveling.commit()
}

fn stat(&self) -> Result<Stat, Error> {
self.save_data.stat()
}
}
15 changes: 4 additions & 11 deletions libsave3ds/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod aes_ctr_file;
mod byte_struct_common;
mod cart_save_data;
pub mod db;
mod diff;
mod difi_partition;
Expand Down Expand Up @@ -29,6 +30,7 @@ mod wear_leveling;
use aes::block_cipher_trait::generic_array::GenericArray;
use aes::block_cipher_trait::*;
use aes::*;
use cart_save_data::*;
use db::*;
use disk_file::DiskFile;
use error::*;
Expand Down Expand Up @@ -553,28 +555,19 @@ impl Resource {
Ok((key_y, repeat_ctr))
}

pub fn open_cart_save(&self, path: &str, write: bool) -> Result<SaveData, Error> {
pub fn open_cart_save(&self, path: &str, write: bool) -> Result<CartSaveData, Error> {
let file = Rc::new(DiskFile::new(
std::fs::OpenOptions::new()
.read(true)
.write(write)
.open(path)?,
)?);

let save = wear_leveling::WearLeveling::new(file)?;

let (key_y, repeat_ctr) = self.get_cart_save_key_y()?;
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);

let save = Rc::new(aes_ctr_file::AesCtrFile::new(
Rc::new(save),
key,
[0; 16],
repeat_ctr,
));

SaveData::new(save, SaveDataType::Cart(key_cmac))
CartSaveData::new(file, key, key_cmac, repeat_ctr)
}

pub fn open_db(&self, db_type: DbType, write: bool) -> Result<Db, Error> {
Expand Down
8 changes: 8 additions & 0 deletions libsave3ds/src/memory_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ impl MemoryFile {
data: RefCell::new(data),
}
}

pub fn from_file(file: &dyn RandomAccessFile) -> Result<MemoryFile, Error> {
let mut data = vec![0; file.len()];
file.read(0, &mut data)?;
Ok(MemoryFile {
data: RefCell::new(data),
})
}
}

impl RandomAccessFile for MemoryFile {
Expand Down
6 changes: 4 additions & 2 deletions libsave3ds/src/save_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,8 +341,10 @@ impl SaveData {
file_table,
param.max_file + 1,
)?;
let dir_table_combo = OffsetOrFatFile::from_offset(info.dir_table_offset.unwrap() as u64);
let file_table_combo = OffsetOrFatFile::from_offset(info.file_table_offset.unwrap() as u64);
let dir_table_combo =
OffsetOrFatFile::from_offset(info.dir_table_offset.unwrap() as u64);
let file_table_combo =
OffsetOrFatFile::from_offset(info.file_table_offset.unwrap() as u64);
(dir_table_combo, file_table_combo)
} else {
let fat = Fat::new(fat_table, data, info.block_len)?;
Expand Down
Loading

0 comments on commit a9205da

Please sign in to comment.