diff --git a/src/services/fs.rs b/src/services/fs.rs index fabacfa..a01ae73 100644 --- a/src/services/fs.rs +++ b/src/services/fs.rs @@ -60,6 +60,11 @@ pub struct File { offset: u64, } +pub struct Metadata { + attributes: u32, + size: u64, +} + #[derive(Clone)] pub struct OpenOptions { read: bool, @@ -74,8 +79,8 @@ pub struct ReadDir { } pub struct DirEntry { - root: Arc, entry: FS_DirectoryEntry, + root: Arc, } struct Dir(u32); @@ -128,25 +133,27 @@ impl File { OpenOptions::new().write(true).create(true).archive(arch).open(path.as_ref()) } - pub fn len(&self) -> Result { + pub fn set_len(&mut self, len: u64) -> Result<(), i32> { unsafe { - let mut len = 0; - let r = FSFILE_GetSize(self.handle, &mut len); + let r = FSFILE_SetSize(self.handle, len); if r < 0 { Err(r) } else { - Ok(len) + Ok(()) } } } - pub fn set_len(&mut self, len: u64) -> Result<(), i32> { + // Right now the only file metadata we really have is file size + // This will probably expand later on + pub fn metadata(&self) -> Result { unsafe { - let r = FSFILE_SetSize(self.handle, len); + let mut size = 0; + let r = FSFILE_GetSize(self.handle, &mut size); if r < 0 { Err(r) } else { - Ok(()) + Ok(Metadata { attributes: 0, size: size }) } } } @@ -197,6 +204,20 @@ impl File { } } +impl Metadata { + pub fn is_dir(&self) -> bool { + self.attributes == self.attributes | FS_ATTRIBUTE_DIRECTORY + } + + pub fn is_file(&self) -> bool { + !self.is_dir() + } + + pub fn len(&self) -> u64 { + self.size + } +} + impl OpenOptions { pub fn new() -> OpenOptions { OpenOptions { @@ -290,6 +311,12 @@ impl DirEntry { self.root.join(&self.file_name()) } + // Requiring the user to explicitly pass in the Archive here is pretty ugly, + // But I'm not sure of how else to do it right now. + pub fn metadata(&self, arch: &Archive) -> Result { + metadata(&arch, self.path()) + } + pub fn file_name(&self) -> OsString { let filename = truncate_utf16_at_nul(&self.entry.name); OsString::from_wide(filename) @@ -309,6 +336,16 @@ pub fn create_dir>(arch: &Archive, path: P) -> Result<(), i32> { } } +pub fn metadata>(arch: &Archive, path: P) -> Result { + let maybe_file = File::open(&arch, path.as_ref()); + let maybe_dir = read_dir(&arch, path.as_ref()); + match (maybe_file, maybe_dir) { + (Ok(file), _) => file.metadata(), + (_, Ok(_dir)) => Ok(Metadata { attributes: FS_ATTRIBUTE_DIRECTORY, size: 0 }), + (Err(r), _) => Err(r), + } +} + pub fn remove_dir>(arch: &Archive, path: P) -> Result<(), i32> { unsafe { let path = to_utf16(path.as_ref()); @@ -390,7 +427,7 @@ fn readdir(arch: &Archive, p: &Path) -> Result { } } -// TODO: Determine if interior NULLs are premitted in 3DS file paths +// TODO: Determine if we should check UTF-16 paths for interior NULs fn to_utf16(path: &Path) -> Vec { path.as_os_str().encode_wide().collect::>() }