blob: f723a23bd5dffc41c93a0bd9846a360c8479faae [file] [log] [blame] [edit]
use crate::ffi::OsString;
use crate::hash::Hash;
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
use crate::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
use crate::path::{Path, PathBuf};
use crate::sys::fd::FileDesc;
pub use crate::sys::fs::common::exists;
use crate::sys::time::SystemTime;
use crate::sys::{map_motor_error, unsupported};
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct FileType {
rt_filetype: u8,
}
impl FileType {
pub fn is_dir(&self) -> bool {
self.rt_filetype == moto_rt::fs::FILETYPE_DIRECTORY
}
pub fn is_file(&self) -> bool {
self.rt_filetype == moto_rt::fs::FILETYPE_FILE
}
pub fn is_symlink(&self) -> bool {
false
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct FilePermissions {
rt_perm: u64,
}
impl FilePermissions {
pub fn readonly(&self) -> bool {
(self.rt_perm & moto_rt::fs::PERM_WRITE == 0)
&& (self.rt_perm & moto_rt::fs::PERM_READ != 0)
}
pub fn set_readonly(&mut self, readonly: bool) {
if readonly {
self.rt_perm = moto_rt::fs::PERM_READ;
} else {
self.rt_perm = moto_rt::fs::PERM_READ | moto_rt::fs::PERM_WRITE;
}
}
}
#[derive(Copy, Clone, Debug, Default)]
pub struct FileTimes {
modified: u128,
accessed: u128,
}
impl FileTimes {
pub fn set_accessed(&mut self, t: SystemTime) {
self.accessed = t.as_u128();
}
pub fn set_modified(&mut self, t: SystemTime) {
self.modified = t.as_u128();
}
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct FileAttr {
inner: moto_rt::fs::FileAttr,
}
impl FileAttr {
pub fn size(&self) -> u64 {
self.inner.size
}
pub fn perm(&self) -> FilePermissions {
FilePermissions { rt_perm: self.inner.perm }
}
pub fn file_type(&self) -> FileType {
FileType { rt_filetype: self.inner.file_type }
}
pub fn modified(&self) -> io::Result<SystemTime> {
match self.inner.modified {
0 => Err(crate::io::Error::from(crate::io::ErrorKind::Other)),
x => Ok(SystemTime::from_u128(x)),
}
}
pub fn accessed(&self) -> io::Result<SystemTime> {
match self.inner.accessed {
0 => Err(crate::io::Error::from(crate::io::ErrorKind::Other)),
x => Ok(SystemTime::from_u128(x)),
}
}
pub fn created(&self) -> io::Result<SystemTime> {
match self.inner.created {
0 => Err(crate::io::Error::from(crate::io::ErrorKind::Other)),
x => Ok(SystemTime::from_u128(x)),
}
}
}
#[derive(Clone, Debug)]
pub struct OpenOptions {
rt_open_options: u32,
}
impl OpenOptions {
pub fn new() -> OpenOptions {
OpenOptions { rt_open_options: 0 }
}
pub fn read(&mut self, read: bool) {
if read {
self.rt_open_options |= moto_rt::fs::O_READ;
} else {
self.rt_open_options &= !moto_rt::fs::O_READ;
}
}
pub fn write(&mut self, write: bool) {
if write {
self.rt_open_options |= moto_rt::fs::O_WRITE;
} else {
self.rt_open_options &= !moto_rt::fs::O_WRITE;
}
}
pub fn append(&mut self, append: bool) {
if append {
self.rt_open_options |= moto_rt::fs::O_APPEND;
} else {
self.rt_open_options &= !moto_rt::fs::O_APPEND;
}
}
pub fn truncate(&mut self, truncate: bool) {
if truncate {
self.rt_open_options |= moto_rt::fs::O_TRUNCATE;
} else {
self.rt_open_options &= !moto_rt::fs::O_TRUNCATE;
}
}
pub fn create(&mut self, create: bool) {
if create {
self.rt_open_options |= moto_rt::fs::O_CREATE;
} else {
self.rt_open_options &= !moto_rt::fs::O_CREATE;
}
}
pub fn create_new(&mut self, create_new: bool) {
if create_new {
self.rt_open_options |= moto_rt::fs::O_CREATE_NEW;
} else {
self.rt_open_options &= !moto_rt::fs::O_CREATE_NEW;
}
}
}
#[derive(Debug)]
pub struct File(FileDesc);
impl File {
pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?;
moto_rt::fs::open(path, opts.rt_open_options)
.map(|fd| unsafe { Self::from_raw_fd(fd) })
.map_err(map_motor_error)
}
pub fn file_attr(&self) -> io::Result<FileAttr> {
moto_rt::fs::get_file_attr(self.as_raw_fd())
.map(|inner| -> FileAttr { FileAttr { inner } })
.map_err(map_motor_error)
}
pub fn fsync(&self) -> io::Result<()> {
moto_rt::fs::fsync(self.as_raw_fd()).map_err(map_motor_error)
}
pub fn datasync(&self) -> io::Result<()> {
moto_rt::fs::datasync(self.as_raw_fd()).map_err(map_motor_error)
}
pub fn truncate(&self, size: u64) -> io::Result<()> {
moto_rt::fs::truncate(self.as_raw_fd(), size).map_err(map_motor_error)
}
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
moto_rt::fs::read(self.as_raw_fd(), buf).map_err(map_motor_error)
}
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
crate::io::default_read_vectored(|b| self.read(b), bufs)
}
pub fn is_read_vectored(&self) -> bool {
false
}
pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
crate::io::default_read_buf(|buf| self.read(buf), cursor)
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
moto_rt::fs::write(self.as_raw_fd(), buf).map_err(map_motor_error)
}
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
crate::io::default_write_vectored(|b| self.write(b), bufs)
}
pub fn is_write_vectored(&self) -> bool {
false
}
pub fn flush(&self) -> io::Result<()> {
moto_rt::fs::flush(self.as_raw_fd()).map_err(map_motor_error)
}
pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
match pos {
SeekFrom::Start(offset) => {
moto_rt::fs::seek(self.as_raw_fd(), offset as i64, moto_rt::fs::SEEK_SET)
.map_err(map_motor_error)
}
SeekFrom::End(offset) => {
moto_rt::fs::seek(self.as_raw_fd(), offset, moto_rt::fs::SEEK_END)
.map_err(map_motor_error)
}
SeekFrom::Current(offset) => {
moto_rt::fs::seek(self.as_raw_fd(), offset, moto_rt::fs::SEEK_CUR)
.map_err(map_motor_error)
}
}
}
pub fn tell(&self) -> io::Result<u64> {
self.seek(SeekFrom::Current(0))
}
pub fn duplicate(&self) -> io::Result<File> {
moto_rt::fs::duplicate(self.as_raw_fd())
.map(|fd| unsafe { Self::from_raw_fd(fd) })
.map_err(map_motor_error)
}
pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> {
moto_rt::fs::set_file_perm(self.as_raw_fd(), perm.rt_perm).map_err(map_motor_error)
}
pub fn set_times(&self, _times: FileTimes) -> io::Result<()> {
unsupported() // Let's not do that.
}
pub fn lock(&self) -> io::Result<()> {
unsupported()
}
pub fn lock_shared(&self) -> io::Result<()> {
unsupported()
}
pub fn try_lock(&self) -> Result<(), crate::fs::TryLockError> {
Err(crate::fs::TryLockError::Error(io::Error::from(io::ErrorKind::Unsupported)))
}
pub fn try_lock_shared(&self) -> Result<(), crate::fs::TryLockError> {
Err(crate::fs::TryLockError::Error(io::Error::from(io::ErrorKind::Unsupported)))
}
pub fn unlock(&self) -> io::Result<()> {
unsupported()
}
pub fn size(&self) -> Option<io::Result<u64>> {
None
}
}
#[derive(Debug)]
pub struct DirBuilder {}
impl DirBuilder {
pub fn new() -> DirBuilder {
DirBuilder {}
}
pub fn mkdir(&self, path: &Path) -> io::Result<()> {
let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?;
moto_rt::fs::mkdir(path).map_err(map_motor_error)
}
}
pub fn unlink(path: &Path) -> io::Result<()> {
let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?;
moto_rt::fs::unlink(path).map_err(map_motor_error)
}
pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
let old = old.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?;
let new = new.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?;
moto_rt::fs::rename(old, new).map_err(map_motor_error)
}
pub fn rmdir(path: &Path) -> io::Result<()> {
let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?;
moto_rt::fs::rmdir(path).map_err(map_motor_error)
}
pub fn remove_dir_all(path: &Path) -> io::Result<()> {
let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?;
moto_rt::fs::rmdir_all(path).map_err(map_motor_error)
}
pub fn set_perm(path: &Path, perm: FilePermissions) -> io::Result<()> {
let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?;
moto_rt::fs::set_perm(path, perm.rt_perm).map_err(map_motor_error)
}
pub fn set_times(_p: &Path, _times: FileTimes) -> io::Result<()> {
unsupported()
}
pub fn set_times_nofollow(_p: &Path, _times: FileTimes) -> io::Result<()> {
unsupported()
}
pub fn readlink(_p: &Path) -> io::Result<PathBuf> {
unsupported()
}
pub fn symlink(_original: &Path, _link: &Path) -> io::Result<()> {
unsupported()
}
pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
unsupported()
}
pub fn stat(path: &Path) -> io::Result<FileAttr> {
let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?;
let inner = moto_rt::fs::stat(path).map_err(map_motor_error)?;
Ok(FileAttr { inner })
}
pub fn lstat(path: &Path) -> io::Result<FileAttr> {
stat(path)
}
pub fn canonicalize(path: &Path) -> io::Result<PathBuf> {
let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?;
let path = moto_rt::fs::canonicalize(path).map_err(map_motor_error)?;
Ok(path.into())
}
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
let from = from.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?;
let to = to.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?;
moto_rt::fs::copy(from, to).map_err(map_motor_error)
}
#[derive(Debug)]
pub struct ReadDir {
rt_fd: moto_rt::RtFd,
path: String,
}
impl Drop for ReadDir {
fn drop(&mut self) {
moto_rt::fs::closedir(self.rt_fd).unwrap();
}
}
pub fn readdir(path: &Path) -> io::Result<ReadDir> {
let path = path.to_str().ok_or(io::Error::from(io::ErrorKind::InvalidFilename))?;
Ok(ReadDir {
rt_fd: moto_rt::fs::opendir(path).map_err(map_motor_error)?,
path: path.to_owned(),
})
}
impl Iterator for ReadDir {
type Item = io::Result<DirEntry>;
fn next(&mut self) -> Option<io::Result<DirEntry>> {
match moto_rt::fs::readdir(self.rt_fd).map_err(map_motor_error) {
Ok(maybe_item) => match maybe_item {
Some(inner) => Some(Ok(DirEntry { inner, parent_path: self.path.clone() })),
None => None,
},
Err(err) => Some(Err(err)),
}
}
}
pub struct DirEntry {
parent_path: String,
inner: moto_rt::fs::DirEntry,
}
impl DirEntry {
fn filename(&self) -> &str {
core::str::from_utf8(unsafe {
core::slice::from_raw_parts(self.inner.fname.as_ptr(), self.inner.fname_size as usize)
})
.unwrap()
}
pub fn path(&self) -> PathBuf {
let mut path = self.parent_path.clone();
path.push_str("/");
path.push_str(self.filename());
path.into()
}
pub fn file_name(&self) -> OsString {
self.filename().to_owned().into()
}
pub fn metadata(&self) -> io::Result<FileAttr> {
Ok(FileAttr { inner: self.inner.attr })
}
pub fn file_type(&self) -> io::Result<FileType> {
Ok(FileType { rt_filetype: self.inner.attr.file_type })
}
}
impl AsInner<FileDesc> for File {
#[inline]
fn as_inner(&self) -> &FileDesc {
&self.0
}
}
impl AsInnerMut<FileDesc> for File {
#[inline]
fn as_inner_mut(&mut self) -> &mut FileDesc {
&mut self.0
}
}
impl IntoInner<FileDesc> for File {
fn into_inner(self) -> FileDesc {
self.0
}
}
impl FromInner<FileDesc> for File {
fn from_inner(file_desc: FileDesc) -> Self {
Self(file_desc)
}
}
impl AsFd for File {
#[inline]
fn as_fd(&self) -> BorrowedFd<'_> {
self.0.as_fd()
}
}
impl AsRawFd for File {
#[inline]
fn as_raw_fd(&self) -> RawFd {
self.0.as_raw_fd()
}
}
impl IntoRawFd for File {
fn into_raw_fd(self) -> RawFd {
self.0.into_raw_fd()
}
}
impl FromRawFd for File {
unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
unsafe { Self(FromRawFd::from_raw_fd(raw_fd)) }
}
}