|
|
@ -1,3 +1,9 @@ |
|
|
|
|
|
|
|
//! Filesystem service
|
|
|
|
|
|
|
|
//!
|
|
|
|
|
|
|
|
//! This module contains basic methods to manipulate the contents of the 3DS's filesystem.
|
|
|
|
|
|
|
|
//! Only the SD card is currently supported.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
use core::marker::PhantomData; |
|
|
|
use core::marker::PhantomData; |
|
|
|
use core::ptr; |
|
|
|
use core::ptr; |
|
|
|
use core::slice; |
|
|
|
use core::slice; |
|
|
@ -45,26 +51,106 @@ pub enum ArchiveID { |
|
|
|
DemoSavedata, |
|
|
|
DemoSavedata, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Represents the filesystem service. No file IO can be performed
|
|
|
|
|
|
|
|
/// until an instance of this struct is created.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// The service exits when this struct goes out of scope.
|
|
|
|
pub struct Fs { |
|
|
|
pub struct Fs { |
|
|
|
pd: PhantomData<i32>, |
|
|
|
pd: PhantomData<i32>, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Handle to an open filesystem archive.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// Archives are automatically closed when they go out of scope.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// # Examples
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// ```no_run
|
|
|
|
|
|
|
|
/// use ctru::services::fs::Fs
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// let fs = Fs::init().unwrap();
|
|
|
|
|
|
|
|
/// let sdmc_archive = fs.sdmc().unwrap();
|
|
|
|
|
|
|
|
/// ```
|
|
|
|
pub struct Archive { |
|
|
|
pub struct Archive { |
|
|
|
id: ArchiveID, |
|
|
|
id: ArchiveID, |
|
|
|
handle: u64, |
|
|
|
handle: u64, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// A reference to an open file on the filesystem.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// An instance of a `File` can be read and/or written to depending
|
|
|
|
|
|
|
|
/// on what options It was opened with.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// Files are automatically closed when they go out of scope.
|
|
|
|
pub struct File { |
|
|
|
pub struct File { |
|
|
|
handle: u32, |
|
|
|
handle: u32, |
|
|
|
offset: u64, |
|
|
|
offset: u64, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Metadata information about a file.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// This structure is returned from the [`metadata`] function and
|
|
|
|
|
|
|
|
/// represents known metadata about a file.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// [`metadata`]: fn.metadata.html
|
|
|
|
pub struct Metadata { |
|
|
|
pub struct Metadata { |
|
|
|
attributes: u32, |
|
|
|
attributes: u32, |
|
|
|
size: u64, |
|
|
|
size: u64, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Options and flags which can be used to configure how a [`File`] is opened.
|
|
|
|
|
|
|
|
/// This builder exposes the ability to configure how a `File` is opened
|
|
|
|
|
|
|
|
/// and what operations are permitted on the open file. The [`File::open`]
|
|
|
|
|
|
|
|
/// and [`File::create`] methods are aliases for commonly used options
|
|
|
|
|
|
|
|
/// using this builder.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// [`File`]: struct.File.html
|
|
|
|
|
|
|
|
/// [`File::open`]: struct.File.html#method.open
|
|
|
|
|
|
|
|
/// [`File::create`]: struct.File.html#method.create
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// Generally speaking, when using `OpenOptions`, you'll first call [`new()`],
|
|
|
|
|
|
|
|
/// then chain calls to methods to set each option, then call [`open()`],
|
|
|
|
|
|
|
|
/// passing the path of the file you're trying to open.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// It is required to also pass a reference to the [`Archive`] that the
|
|
|
|
|
|
|
|
/// file lives in.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// [`new()`]: struct.OpenOptions.html#method.new
|
|
|
|
|
|
|
|
/// [`open()`]: struct.OpenOptions.html#method.open
|
|
|
|
|
|
|
|
/// [`Archive`]: struct.Archive.html
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// # Examples
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// Opening a file to read:
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// ```no_run
|
|
|
|
|
|
|
|
/// use ctru::services::fs::OpenOptions;
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// let fs = Fs::init().unwrap();
|
|
|
|
|
|
|
|
/// let sdmc_archive = fs.sdmc().unwrap();
|
|
|
|
|
|
|
|
/// let file = OpenOptions::new()
|
|
|
|
|
|
|
|
/// .read(true)
|
|
|
|
|
|
|
|
/// .archive(&sdmc_archive)
|
|
|
|
|
|
|
|
/// .open("foo.txt")
|
|
|
|
|
|
|
|
/// .unwrap();
|
|
|
|
|
|
|
|
/// ```
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// Opening a file for both reading and writing, as well as creating it if it
|
|
|
|
|
|
|
|
/// doesn't exist:
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// ```no_run
|
|
|
|
|
|
|
|
/// use ctru::services::fs::OpenOptions;
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// let fs = Fs::init().unwrap();
|
|
|
|
|
|
|
|
/// let sdmc_archive = fs.sdmc().unwrap();
|
|
|
|
|
|
|
|
/// let file = OpenOptions::new()
|
|
|
|
|
|
|
|
/// .read(true)
|
|
|
|
|
|
|
|
/// .write(true)
|
|
|
|
|
|
|
|
/// .create(true)
|
|
|
|
|
|
|
|
/// .archive(&sdmc_archive)
|
|
|
|
|
|
|
|
/// .open("foo.txt")
|
|
|
|
|
|
|
|
/// .unwrap();
|
|
|
|
|
|
|
|
/// ```
|
|
|
|
#[derive(Clone)] |
|
|
|
#[derive(Clone)] |
|
|
|
pub struct OpenOptions { |
|
|
|
pub struct OpenOptions { |
|
|
|
read: bool, |
|
|
|
read: bool, |
|
|
@ -73,24 +159,55 @@ pub struct OpenOptions { |
|
|
|
arch_handle: u64, |
|
|
|
arch_handle: u64, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Iterator over the entries in a directory.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// This iterator is returned from the [`read_dir`] function of this module and
|
|
|
|
|
|
|
|
/// will yield instances of `Result<DirEntry, i32>`. Through a [`DirEntry`]
|
|
|
|
|
|
|
|
/// information like the entry's path and possibly other metadata can be
|
|
|
|
|
|
|
|
/// learned.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// [`read_dir`]: fn.read_dir.html
|
|
|
|
|
|
|
|
/// [`DirEntry`]: struct.DirEntry.html
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// # Errors
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// This Result will return Err if there's some sort of intermittent IO error
|
|
|
|
|
|
|
|
/// during iteration.
|
|
|
|
pub struct ReadDir<'a> { |
|
|
|
pub struct ReadDir<'a> { |
|
|
|
handle: Dir, |
|
|
|
handle: Dir, |
|
|
|
root: Arc<PathBuf>, |
|
|
|
root: Arc<PathBuf>, |
|
|
|
arch: &'a Archive, |
|
|
|
arch: &'a Archive, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Entries returned by the [`ReadDir`] iterator.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// [`ReadDir`]: struct.ReadDir.html
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// An instance of `DirEntry` represents an entry inside of a directory on the
|
|
|
|
|
|
|
|
/// filesystem. Each entry can be inspected via methods to learn about the full
|
|
|
|
|
|
|
|
/// path or possibly other metadata.
|
|
|
|
pub struct DirEntry<'a> { |
|
|
|
pub struct DirEntry<'a> { |
|
|
|
entry: FS_DirectoryEntry, |
|
|
|
entry: FS_DirectoryEntry, |
|
|
|
root: Arc<PathBuf>, |
|
|
|
root: Arc<PathBuf>, |
|
|
|
arch: &'a Archive, |
|
|
|
arch: &'a Archive, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[doc(hidden)] |
|
|
|
struct Dir(u32); |
|
|
|
struct Dir(u32); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[doc(hidden)] |
|
|
|
unsafe impl Send for Dir {} |
|
|
|
unsafe impl Send for Dir {} |
|
|
|
|
|
|
|
#[doc(hidden)] |
|
|
|
unsafe impl Sync for Dir {} |
|
|
|
unsafe impl Sync for Dir {} |
|
|
|
|
|
|
|
|
|
|
|
impl Fs { |
|
|
|
impl Fs { |
|
|
|
|
|
|
|
/// Initializes the FS service.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// # Errors
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// This function will return Err if there was an error initializing the
|
|
|
|
|
|
|
|
/// FS service. This typically reflects a problem with the execution
|
|
|
|
|
|
|
|
/// environment and not necessarily your program itself.
|
|
|
|
pub fn init() -> Result<Fs, i32> { |
|
|
|
pub fn init() -> Result<Fs, i32> { |
|
|
|
unsafe { |
|
|
|
unsafe { |
|
|
|
let r = fsInit(); |
|
|
|
let r = fsInit(); |
|
|
@ -102,6 +219,7 @@ impl Fs { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns a handle to the SDMC (memory card) Archive.
|
|
|
|
pub fn sdmc(&self) -> Result<Archive, i32> { |
|
|
|
pub fn sdmc(&self) -> Result<Archive, i32> { |
|
|
|
unsafe { |
|
|
|
unsafe { |
|
|
|
let mut handle = 0; |
|
|
|
let mut handle = 0; |
|
|
@ -121,23 +239,73 @@ impl Fs { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl Archive { |
|
|
|
impl Archive { |
|
|
|
|
|
|
|
/// Retrieves an Archive's [`ArchiveID`]
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// [`ArchiveID`]: enum.ArchiveID.html
|
|
|
|
pub fn get_id(&self) -> ArchiveID { |
|
|
|
pub fn get_id(&self) -> ArchiveID { |
|
|
|
self.id |
|
|
|
self.id |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl File { |
|
|
|
impl File { |
|
|
|
|
|
|
|
/// Attempts to open a file in read-only mode.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// See the [`OpenOptions::open`] method for more details.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// # Errors
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// This function will return an error if `path` does not already exit.
|
|
|
|
|
|
|
|
/// Other errors may also be returned accoridng to [`OpenOptions::open`]
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// [`OpenOptions::open`]: struct.OpenOptions.html#method.open
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// # Examples
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// ```no_run
|
|
|
|
|
|
|
|
/// use ctru::servies::fs::{Fs, File};
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// let fs = Fs::init().unwrap()
|
|
|
|
|
|
|
|
/// let sdmc_archive = fs.sdmc().unwrap()
|
|
|
|
|
|
|
|
/// let mut f = File::open("/foo.txt").unwrap();
|
|
|
|
|
|
|
|
/// ```
|
|
|
|
pub fn open<P: AsRef<Path>>(arch: &Archive, path: P) -> Result<File, i32> { |
|
|
|
pub fn open<P: AsRef<Path>>(arch: &Archive, path: P) -> Result<File, i32> { |
|
|
|
OpenOptions::new().read(true).archive(arch).open(path.as_ref()) |
|
|
|
OpenOptions::new().read(true).archive(arch).open(path.as_ref()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Opens a file in write-only mode.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// This function will create a file if it does not exist.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// See the [`OpenOptions::create`] method for more details.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// # Errors
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// This function will return an error if `path` does not already exit.
|
|
|
|
|
|
|
|
/// Other errors may also be returned accoridng to [`OpenOptions::create`]
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// [`OpenOptions::create`]: struct.OpenOptions.html#method.create
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// # Examples
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// ```no_run
|
|
|
|
|
|
|
|
/// use ctru::servies::fs::{Fs, File};
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// let fs = Fs::init().unwrap()
|
|
|
|
|
|
|
|
/// let sdmc_archive = fs.sdmc().unwrap()
|
|
|
|
|
|
|
|
/// let mut f = File::create("/foo.txt").unwrap();
|
|
|
|
|
|
|
|
/// ```
|
|
|
|
pub fn create<P: AsRef<Path>>(arch: &Archive, path: P) -> Result<File, i32> { |
|
|
|
pub fn create<P: AsRef<Path>>(arch: &Archive, path: P) -> Result<File, i32> { |
|
|
|
OpenOptions::new().write(true).create(true).archive(arch).open(path.as_ref()) |
|
|
|
OpenOptions::new().write(true).create(true).archive(arch).open(path.as_ref()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub fn set_len(&mut self, len: u64) -> Result<(), i32> { |
|
|
|
/// Truncates or extends the underlying file, updating the size of this file to become size.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// If the size is less than the current file's size, then the file will be shrunk. If it is
|
|
|
|
|
|
|
|
/// greater than the current file's size, then the file will be extended to size and have all
|
|
|
|
|
|
|
|
/// of the intermediate data filled in with 0s.
|
|
|
|
|
|
|
|
pub fn set_len(&mut self, size: u64) -> Result<(), i32> { |
|
|
|
unsafe { |
|
|
|
unsafe { |
|
|
|
let r = FSFILE_SetSize(self.handle, len); |
|
|
|
let r = FSFILE_SetSize(self.handle, size); |
|
|
|
if r < 0 { |
|
|
|
if r < 0 { |
|
|
|
Err(r) |
|
|
|
Err(r) |
|
|
|
} else { |
|
|
|
} else { |
|
|
@ -146,9 +314,10 @@ impl File { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Right now the only file metadata we really have is file size
|
|
|
|
/// Queries metadata about the underlying file.
|
|
|
|
// This will probably expand later on
|
|
|
|
|
|
|
|
pub fn metadata(&self) -> Result<Metadata, i32> { |
|
|
|
pub fn metadata(&self) -> Result<Metadata, i32> { |
|
|
|
|
|
|
|
// The only metadata we have for files right now is file size.
|
|
|
|
|
|
|
|
// This is likely to change in the future.
|
|
|
|
unsafe { |
|
|
|
unsafe { |
|
|
|
let mut size = 0; |
|
|
|
let mut size = 0; |
|
|
|
let r = FSFILE_GetSize(self.handle, &mut size); |
|
|
|
let r = FSFILE_GetSize(self.handle, &mut size); |
|
|
@ -160,6 +329,11 @@ impl File { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Pull some bytes from the file into the specified buffer, returning
|
|
|
|
|
|
|
|
/// how many bytes were read.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// This function will become private when std::io support is ported
|
|
|
|
|
|
|
|
/// to this library.
|
|
|
|
pub fn read(&mut self, buf: &mut [u8]) -> Result<usize, i32> { |
|
|
|
pub fn read(&mut self, buf: &mut [u8]) -> Result<usize, i32> { |
|
|
|
unsafe { |
|
|
|
unsafe { |
|
|
|
let mut n_read = 0; |
|
|
|
let mut n_read = 0; |
|
|
@ -179,12 +353,20 @@ impl File { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Read all bytes until EOF in this source, placing them into buf.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// This function will become private when std::io support is ported
|
|
|
|
|
|
|
|
/// to this library.
|
|
|
|
pub fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize, i32> { |
|
|
|
pub fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize, i32> { |
|
|
|
unsafe { |
|
|
|
unsafe { |
|
|
|
read_to_end_uninitialized(self, buf) |
|
|
|
read_to_end_uninitialized(self, buf) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Write a buffer into this object, returning how many bytes were written.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// This function will become private when std::io support is ported
|
|
|
|
|
|
|
|
/// to this library.
|
|
|
|
pub fn write(&mut self, buf: &[u8]) -> Result<usize, i32> { |
|
|
|
pub fn write(&mut self, buf: &[u8]) -> Result<usize, i32> { |
|
|
|
unsafe { |
|
|
|
unsafe { |
|
|
|
let mut n_written = 0; |
|
|
|
let mut n_written = 0; |
|
|
@ -207,20 +389,28 @@ impl File { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl Metadata { |
|
|
|
impl Metadata { |
|
|
|
|
|
|
|
/// Returns whether this metadata is for a directory.
|
|
|
|
pub fn is_dir(&self) -> bool { |
|
|
|
pub fn is_dir(&self) -> bool { |
|
|
|
self.attributes == self.attributes | FS_ATTRIBUTE_DIRECTORY |
|
|
|
self.attributes == self.attributes | FS_ATTRIBUTE_DIRECTORY |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns whether this metadata is for a regular file.
|
|
|
|
pub fn is_file(&self) -> bool { |
|
|
|
pub fn is_file(&self) -> bool { |
|
|
|
!self.is_dir() |
|
|
|
!self.is_dir() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns the size, in bytes, this metadata is for.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// Directories return size = 0.
|
|
|
|
pub fn len(&self) -> u64 { |
|
|
|
pub fn len(&self) -> u64 { |
|
|
|
self.size |
|
|
|
self.size |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl OpenOptions { |
|
|
|
impl OpenOptions { |
|
|
|
|
|
|
|
/// Creates a blank set of options ready for configuration.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// All options are initially set to `false`
|
|
|
|
pub fn new() -> OpenOptions { |
|
|
|
pub fn new() -> OpenOptions { |
|
|
|
OpenOptions { |
|
|
|
OpenOptions { |
|
|
|
read: false, |
|
|
|
read: false, |
|
|
@ -230,26 +420,61 @@ impl OpenOptions { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Sets the option for read access.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// This option, when true, will indicate that the file should be
|
|
|
|
|
|
|
|
/// `read`-able if opened.
|
|
|
|
pub fn read(&mut self, read: bool) -> &mut OpenOptions { |
|
|
|
pub fn read(&mut self, read: bool) -> &mut OpenOptions { |
|
|
|
self.read = read; |
|
|
|
self.read = read; |
|
|
|
self |
|
|
|
self |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Sets the option for write access.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// This option, when true, will indicate that the file should be
|
|
|
|
|
|
|
|
/// `write`-able if opened.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// If the file already exists, any write calls on it will overwrite
|
|
|
|
|
|
|
|
/// its contents, without truncating it.
|
|
|
|
pub fn write(&mut self, write: bool) -> &mut OpenOptions { |
|
|
|
pub fn write(&mut self, write: bool) -> &mut OpenOptions { |
|
|
|
self.write = write; |
|
|
|
self.write = write; |
|
|
|
self |
|
|
|
self |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Sets the option for creating a new file.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// This option indicates whether a new file will be created
|
|
|
|
|
|
|
|
/// if the file does not yet already
|
|
|
|
|
|
|
|
/// exist.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// In order for the file to be created, write access must also be used.
|
|
|
|
pub fn create(&mut self, create: bool) -> &mut OpenOptions { |
|
|
|
pub fn create(&mut self, create: bool) -> &mut OpenOptions { |
|
|
|
self.create = create; |
|
|
|
self.create = create; |
|
|
|
self |
|
|
|
self |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Sets which archive the file is to be opened in.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// Failing to pass in an archive will result in the file failing to open.
|
|
|
|
pub fn archive(&mut self, archive: &Archive) -> &mut OpenOptions { |
|
|
|
pub fn archive(&mut self, archive: &Archive) -> &mut OpenOptions { |
|
|
|
self.arch_handle = archive.handle; |
|
|
|
self.arch_handle = archive.handle; |
|
|
|
self |
|
|
|
self |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Opens a file at `path` with the options specified by `self`
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// # Errors
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// This function will return an error under a number of different
|
|
|
|
|
|
|
|
/// circumstances, including but not limited to:
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// * Opening a file that doesn't exist without setting `create`.
|
|
|
|
|
|
|
|
/// * Attempting to open a file without passing an [`Archive`] reference
|
|
|
|
|
|
|
|
/// to the `archive` method.
|
|
|
|
|
|
|
|
/// * Filesystem-level errors (full disk, etc).
|
|
|
|
|
|
|
|
/// * Invalid combinations of open options.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// [`Archive`]: struct.Archive.html
|
|
|
|
pub fn open<P: AsRef<Path>>(&self, path: P) -> Result<File, i32> { |
|
|
|
pub fn open<P: AsRef<Path>>(&self, path: P) -> Result<File, i32> { |
|
|
|
self._open(path.as_ref(), self.get_open_flags()) |
|
|
|
self._open(path.as_ref(), self.get_open_flags()) |
|
|
|
} |
|
|
|
} |
|
|
@ -310,20 +535,34 @@ impl<'a> Iterator for ReadDir<'a> { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl<'a> DirEntry<'a> { |
|
|
|
impl<'a> DirEntry<'a> { |
|
|
|
|
|
|
|
/// Returns the full path to the file that this entry represents.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// The full path is created by joining the original path to `read_dir`
|
|
|
|
|
|
|
|
/// with the filename of this entry.
|
|
|
|
pub fn path(&self) -> PathBuf { |
|
|
|
pub fn path(&self) -> PathBuf { |
|
|
|
self.root.join(&self.file_name()) |
|
|
|
self.root.join(&self.file_name()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Return the metadata for the file that this entry points at.
|
|
|
|
pub fn metadata(&self) -> Result<Metadata, i32> { |
|
|
|
pub fn metadata(&self) -> Result<Metadata, i32> { |
|
|
|
metadata(self.arch, self.path()) |
|
|
|
metadata(self.arch, self.path()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Return the file type for the file that this entry points at.
|
|
|
|
pub fn file_name(&self) -> OsString { |
|
|
|
pub fn file_name(&self) -> OsString { |
|
|
|
let filename = truncate_utf16_at_nul(&self.entry.name); |
|
|
|
let filename = truncate_utf16_at_nul(&self.entry.name); |
|
|
|
OsString::from_wide(filename) |
|
|
|
OsString::from_wide(filename) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Creates a new, empty directory at the provided path
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// # Errors
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// This function will return an error in the following situations,
|
|
|
|
|
|
|
|
/// but is not limited to just these cases:
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// * User lacks permissions to create directory at `path`
|
|
|
|
pub fn create_dir<P: AsRef<Path>>(arch: &Archive, path: P) -> Result<(), i32> { |
|
|
|
pub fn create_dir<P: AsRef<Path>>(arch: &Archive, path: P) -> Result<(), i32> { |
|
|
|
unsafe { |
|
|
|
unsafe { |
|
|
|
let path = to_utf16(path.as_ref()); |
|
|
|
let path = to_utf16(path.as_ref()); |
|
|
@ -337,6 +576,15 @@ pub fn create_dir<P: AsRef<Path>>(arch: &Archive, path: P) -> Result<(), i32> { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Recursively create a directory and all of its parent components if they are missing.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// # Errors
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// This function will return an error in the following situations,
|
|
|
|
|
|
|
|
/// but is not limited to just these cases:
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// * If any directory in the path specified by `path` does not already exist
|
|
|
|
|
|
|
|
/// and it could not be created otherwise.
|
|
|
|
pub fn create_dir_all<P: AsRef<Path>>(arch: &Archive, path: P) -> Result<(), i32> { |
|
|
|
pub fn create_dir_all<P: AsRef<Path>>(arch: &Archive, path: P) -> Result<(), i32> { |
|
|
|
let path = path.as_ref(); |
|
|
|
let path = path.as_ref(); |
|
|
|
let mut dir = PathBuf::new(); |
|
|
|
let mut dir = PathBuf::new(); |
|
|
@ -350,6 +598,7 @@ pub fn create_dir_all<P: AsRef<Path>>(arch: &Archive, path: P) -> Result<(), i32 |
|
|
|
result |
|
|
|
result |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Given a path, query the file system to get information about a file, directory, etc
|
|
|
|
pub fn metadata<P: AsRef<Path>>(arch: &Archive, path: P) -> Result<Metadata, i32> { |
|
|
|
pub fn metadata<P: AsRef<Path>>(arch: &Archive, path: P) -> Result<Metadata, i32> { |
|
|
|
let maybe_file = File::open(&arch, path.as_ref()); |
|
|
|
let maybe_file = File::open(&arch, path.as_ref()); |
|
|
|
let maybe_dir = read_dir(&arch, path.as_ref()); |
|
|
|
let maybe_dir = read_dir(&arch, path.as_ref()); |
|
|
@ -360,6 +609,15 @@ pub fn metadata<P: AsRef<Path>>(arch: &Archive, path: P) -> Result<Metadata, i32 |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Removes an existing, empty directory.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// # Errors
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// This function will return an error in the following situations, but is not limited to just
|
|
|
|
|
|
|
|
/// these cases:
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// * The user lacks permissions to remove the directory at the provided path.
|
|
|
|
|
|
|
|
/// * The directory isn't empty.
|
|
|
|
pub fn remove_dir<P: AsRef<Path>>(arch: &Archive, path: P) -> Result<(), i32> { |
|
|
|
pub fn remove_dir<P: AsRef<Path>>(arch: &Archive, path: P) -> Result<(), i32> { |
|
|
|
unsafe { |
|
|
|
unsafe { |
|
|
|
let path = to_utf16(path.as_ref()); |
|
|
|
let path = to_utf16(path.as_ref()); |
|
|
@ -373,6 +631,11 @@ pub fn remove_dir<P: AsRef<Path>>(arch: &Archive, path: P) -> Result<(), i32> { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Removes a directory at this path, after removing all its contents. Use carefully!
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// # Errors
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// see `file::remove_file` and `fs::remove_dir`
|
|
|
|
pub fn remove_dir_all<P: AsRef<Path>>(arch: &Archive, path: P) -> Result<(), i32> { |
|
|
|
pub fn remove_dir_all<P: AsRef<Path>>(arch: &Archive, path: P) -> Result<(), i32> { |
|
|
|
unsafe { |
|
|
|
unsafe { |
|
|
|
let path = to_utf16(path.as_ref()); |
|
|
|
let path = to_utf16(path.as_ref()); |
|
|
@ -386,6 +649,17 @@ pub fn remove_dir_all<P: AsRef<Path>>(arch: &Archive, path: P) -> Result<(), i32 |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns an iterator over the entries within a directory.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// The iterator will yield instances of Result<DirEntry, i32>. New errors
|
|
|
|
|
|
|
|
/// may be encountered after an iterator is initially constructed.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// This function will return an error in the following situations, but is not limited to just
|
|
|
|
|
|
|
|
/// these cases:
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// * The provided path doesn't exist.
|
|
|
|
|
|
|
|
/// * The process lacks permissions to view the contents.
|
|
|
|
|
|
|
|
/// * The path points at a non-directory file.
|
|
|
|
pub fn read_dir<P: AsRef<Path>>(arch: &Archive, path: P) -> Result<ReadDir, i32> { |
|
|
|
pub fn read_dir<P: AsRef<Path>>(arch: &Archive, path: P) -> Result<ReadDir, i32> { |
|
|
|
unsafe { |
|
|
|
unsafe { |
|
|
|
let mut handle = 0; |
|
|
|
let mut handle = 0; |
|
|
@ -401,6 +675,15 @@ pub fn read_dir<P: AsRef<Path>>(arch: &Archive, path: P) -> Result<ReadDir, i32> |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Removes a file from the filesystem.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// # Errors
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// This function will return an error in the following situations, but is not limited to just
|
|
|
|
|
|
|
|
/// these cases:
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// * path points to a directory.
|
|
|
|
|
|
|
|
/// * The user lacks permissions to remove the file.
|
|
|
|
pub fn remove_file<P: AsRef<Path>>(arch: &Archive, path: P) -> Result<(), i32> { |
|
|
|
pub fn remove_file<P: AsRef<Path>>(arch: &Archive, path: P) -> Result<(), i32> { |
|
|
|
unsafe { |
|
|
|
unsafe { |
|
|
|
let path = to_utf16(path.as_ref()); |
|
|
|
let path = to_utf16(path.as_ref()); |
|
|
@ -414,6 +697,16 @@ pub fn remove_file<P: AsRef<Path>>(arch: &Archive, path: P) -> Result<(), i32> { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Rename a file or directory to a new name, replacing the original file
|
|
|
|
|
|
|
|
/// if to already exists.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// # Errors
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// This function will return an error in the following situations, but is not limited to just
|
|
|
|
|
|
|
|
/// these cases:
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// * from does not exist.
|
|
|
|
|
|
|
|
/// * The user lacks permissions to view contents.
|
|
|
|
pub fn rename<P, Q>(arch: &Archive, from: P, to: Q) -> Result<(), i32> |
|
|
|
pub fn rename<P, Q>(arch: &Archive, from: P, to: Q) -> Result<(), i32> |
|
|
|
where P: AsRef<Path>, |
|
|
|
where P: AsRef<Path>, |
|
|
|
Q: AsRef<Path> { |
|
|
|
Q: AsRef<Path> { |
|
|
|