|
|
@ -5,17 +5,15 @@ |
|
|
|
// TODO: Refactor service to accomodate for various changes (such as SMDH support). Properly document the public API.
|
|
|
|
// TODO: Refactor service to accomodate for various changes (such as SMDH support). Properly document the public API.
|
|
|
|
#![doc(alias = "filesystem")] |
|
|
|
#![doc(alias = "filesystem")] |
|
|
|
|
|
|
|
|
|
|
|
use bitflags::bitflags; |
|
|
|
|
|
|
|
use std::ffi::OsString; |
|
|
|
use std::ffi::OsString; |
|
|
|
use std::io::Error as IoError; |
|
|
|
use std::io::{ |
|
|
|
use std::io::ErrorKind as IoErrorKind; |
|
|
|
Error as IoError, ErrorKind as IoErrorKind, Read, Result as IoResult, Seek, SeekFrom, Write, |
|
|
|
use std::io::Result as IoResult; |
|
|
|
}; |
|
|
|
use std::io::{Read, Seek, SeekFrom, Write}; |
|
|
|
|
|
|
|
use std::mem; |
|
|
|
|
|
|
|
use std::path::{Path, PathBuf}; |
|
|
|
use std::path::{Path, PathBuf}; |
|
|
|
use std::ptr; |
|
|
|
|
|
|
|
use std::slice; |
|
|
|
|
|
|
|
use std::sync::Arc; |
|
|
|
use std::sync::Arc; |
|
|
|
|
|
|
|
use std::{mem, ptr, slice}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
use bitflags::bitflags; |
|
|
|
use widestring::{WideCStr, WideCString}; |
|
|
|
use widestring::{WideCStr, WideCString}; |
|
|
|
|
|
|
|
|
|
|
|
bitflags! { |
|
|
|
bitflags! { |
|
|
@ -136,7 +134,8 @@ pub struct Fs(()); |
|
|
|
///
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// ```
|
|
|
|
|
|
|
|
/// # let _runner = test_runner::GdbRunner::default();
|
|
|
|
/// use ctru::services::fs::Fs;
|
|
|
|
/// use ctru::services::fs::Fs;
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// let mut fs = Fs::new().unwrap();
|
|
|
|
/// let mut fs = Fs::new().unwrap();
|
|
|
@ -158,12 +157,14 @@ pub struct Archive { |
|
|
|
///
|
|
|
|
///
|
|
|
|
/// Create a new file and write bytes to it:
|
|
|
|
/// Create a new file and write bytes to it:
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// ```
|
|
|
|
|
|
|
|
/// # let _runner = test_runner::GdbRunner::default();
|
|
|
|
/// # use std::error::Error;
|
|
|
|
/// # use std::error::Error;
|
|
|
|
/// # fn main() -> Result<(), Box<dyn Error>> {
|
|
|
|
/// # fn main() -> Result<(), Box<dyn Error>> {
|
|
|
|
/// #
|
|
|
|
/// #
|
|
|
|
/// use std::io::prelude::*;
|
|
|
|
/// use std::io::prelude::*;
|
|
|
|
/// use ctru::services::fs::{Fs, File};
|
|
|
|
///
|
|
|
|
|
|
|
|
/// use ctru::services::fs::{File, Fs};
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// let mut fs = Fs::new()?;
|
|
|
|
/// let mut fs = Fs::new()?;
|
|
|
|
/// let mut sdmc = fs.sdmc()?;
|
|
|
|
/// let mut sdmc = fs.sdmc()?;
|
|
|
@ -174,12 +175,14 @@ pub struct Archive { |
|
|
|
///
|
|
|
|
///
|
|
|
|
/// Read the contents of a file into a `String`::
|
|
|
|
/// Read the contents of a file into a `String`::
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// ```
|
|
|
|
|
|
|
|
/// # let _runner = test_runner::GdbRunner::default();
|
|
|
|
/// # use std::error::Error;
|
|
|
|
/// # use std::error::Error;
|
|
|
|
/// # fn main() -> Result<(), Box<dyn Error>> {
|
|
|
|
/// # fn main() -> Result<(), Box<dyn Error>> {
|
|
|
|
/// #
|
|
|
|
/// #
|
|
|
|
/// use std::io::prelude::*;
|
|
|
|
/// use std::io::prelude::*;
|
|
|
|
/// use ctru::services::fs::{Fs, File};
|
|
|
|
///
|
|
|
|
|
|
|
|
/// use ctru::services::fs::{File, Fs};
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// let mut fs = Fs::new()?;
|
|
|
|
/// let mut fs = Fs::new()?;
|
|
|
|
/// let mut sdmc = fs.sdmc()?;
|
|
|
|
/// let mut sdmc = fs.sdmc()?;
|
|
|
@ -196,13 +199,15 @@ pub struct Archive { |
|
|
|
/// It can be more efficient to read the contents of a file with a buffered
|
|
|
|
/// It can be more efficient to read the contents of a file with a buffered
|
|
|
|
/// `Read`er. This can be accomplished with `BufReader<R>`:
|
|
|
|
/// `Read`er. This can be accomplished with `BufReader<R>`:
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// ```
|
|
|
|
|
|
|
|
/// # let _runner = test_runner::GdbRunner::default();
|
|
|
|
/// # use std::error::Error;
|
|
|
|
/// # use std::error::Error;
|
|
|
|
/// # fn main() -> Result<(), Box<dyn Error>> {
|
|
|
|
/// # fn main() -> Result<(), Box<dyn Error>> {
|
|
|
|
/// #
|
|
|
|
/// #
|
|
|
|
/// use std::io::BufReader;
|
|
|
|
|
|
|
|
/// use std::io::prelude::*;
|
|
|
|
/// use std::io::prelude::*;
|
|
|
|
/// use ctru::services::fs::{Fs, File};
|
|
|
|
/// use std::io::BufReader;
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// use ctru::services::fs::{File, Fs};
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// let mut fs = Fs::new()?;
|
|
|
|
/// let mut fs = Fs::new()?;
|
|
|
|
/// let mut sdmc = fs.sdmc()?;
|
|
|
|
/// let mut sdmc = fs.sdmc()?;
|
|
|
@ -247,33 +252,36 @@ pub struct Metadata { |
|
|
|
///
|
|
|
|
///
|
|
|
|
/// Opening a file to read:
|
|
|
|
/// Opening a file to read:
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// ```
|
|
|
|
|
|
|
|
/// # let _runner = test_runner::GdbRunner::default();
|
|
|
|
/// use ctru::services::fs::{Fs, OpenOptions};
|
|
|
|
/// use ctru::services::fs::{Fs, OpenOptions};
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// let mut fs = Fs::new().unwrap();
|
|
|
|
/// let mut fs = Fs::new().unwrap();
|
|
|
|
/// let mut sdmc_archive = fs.sdmc().unwrap();
|
|
|
|
/// let mut sdmc_archive = fs.sdmc().unwrap();
|
|
|
|
/// let file = OpenOptions::new()
|
|
|
|
/// let result = OpenOptions::new()
|
|
|
|
/// .read(true)
|
|
|
|
/// .read(true)
|
|
|
|
/// .archive(&sdmc_archive)
|
|
|
|
/// .archive(&sdmc_archive)
|
|
|
|
/// .open("foo.txt")
|
|
|
|
/// .open("foo.txt");
|
|
|
|
/// .unwrap();
|
|
|
|
///
|
|
|
|
|
|
|
|
/// assert!(result.is_err());
|
|
|
|
/// ```
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// Opening a file for both reading and writing, as well as creating it if it
|
|
|
|
/// Opening a file for both reading and writing, as well as creating it if it
|
|
|
|
/// doesn't exist:
|
|
|
|
/// doesn't exist:
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// ```
|
|
|
|
|
|
|
|
/// # let _runner = test_runner::GdbRunner::default();
|
|
|
|
/// use ctru::services::fs::{Fs, OpenOptions};
|
|
|
|
/// use ctru::services::fs::{Fs, OpenOptions};
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// let mut fs = Fs::new().unwrap();
|
|
|
|
/// let mut fs = Fs::new().unwrap();
|
|
|
|
/// let mut sdmc_archive = fs.sdmc().unwrap();
|
|
|
|
/// let mut sdmc_archive = fs.sdmc().unwrap();
|
|
|
|
/// let file = OpenOptions::new()
|
|
|
|
/// let file = OpenOptions::new()
|
|
|
|
/// .read(true)
|
|
|
|
/// .read(true)
|
|
|
|
/// .write(true)
|
|
|
|
/// .write(true)
|
|
|
|
/// .create(true)
|
|
|
|
/// .create(true)
|
|
|
|
/// .archive(&sdmc_archive)
|
|
|
|
/// .archive(&sdmc_archive)
|
|
|
|
/// .open("foo.txt")
|
|
|
|
/// .open("/foo.txt")
|
|
|
|
/// .unwrap();
|
|
|
|
/// .unwrap();
|
|
|
|
/// ```
|
|
|
|
/// ```
|
|
|
|
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] |
|
|
|
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] |
|
|
|
pub struct OpenOptions { |
|
|
|
pub struct OpenOptions { |
|
|
@ -380,12 +388,14 @@ impl File { |
|
|
|
///
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// ```
|
|
|
|
/// use ctru::services::fs::{Fs, File};
|
|
|
|
/// # let _runner = test_runner::GdbRunner::default();
|
|
|
|
|
|
|
|
/// use ctru::services::fs::{File, Fs};
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// let mut fs = Fs::new().unwrap();
|
|
|
|
/// let mut fs = Fs::new().unwrap();
|
|
|
|
/// let mut sdmc_archive = fs.sdmc().unwrap();
|
|
|
|
/// let mut sdmc_archive = fs.sdmc().unwrap();
|
|
|
|
/// let mut f = File::open(&sdmc_archive, "/foo.txt").unwrap();
|
|
|
|
/// // Non-existent file:
|
|
|
|
|
|
|
|
/// assert!(File::open(&sdmc_archive, "/foo.txt").is_err());
|
|
|
|
/// ```
|
|
|
|
/// ```
|
|
|
|
pub fn open<P: AsRef<Path>>(arch: &Archive, path: P) -> IoResult<File> { |
|
|
|
pub fn open<P: AsRef<Path>>(arch: &Archive, path: P) -> IoResult<File> { |
|
|
|
OpenOptions::new() |
|
|
|
OpenOptions::new() |
|
|
@ -407,10 +417,11 @@ impl File { |
|
|
|
///
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// ```no_run
|
|
|
|
/// ```
|
|
|
|
/// use ctru::services::fs::{Fs, File};
|
|
|
|
/// # let _runner = test_runner::GdbRunner::default();
|
|
|
|
|
|
|
|
/// use ctru::services::fs::{File, Fs};
|
|
|
|
///
|
|
|
|
///
|
|
|
|
/// let mut fs = Fs::new().unwrap();
|
|
|
|
/// let mut fs = Fs::new().unwrap();
|
|
|
|
/// let mut sdmc_archive = fs.sdmc().unwrap();
|
|
|
|
/// let mut sdmc_archive = fs.sdmc().unwrap();
|
|
|
|
/// let mut f = File::create(&mut sdmc_archive, "/foo.txt").unwrap();
|
|
|
|
/// let mut f = File::create(&mut sdmc_archive, "/foo.txt").unwrap();
|
|
|
|
/// ```
|
|
|
|
/// ```
|
|
|
|