use core::{ffi::CStr, fmt};
use crate::{
fd::{AsFd as _, OwnedFd},
io::{self, Write as _},
sys,
};
pub fn write<P: AsRef<CStr>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> {
fn inner(path: &CStr, contents: &[u8]) -> io::Result<()> {
File::create(path)?.write_all(contents)
}
inner(path.as_ref(), contents.as_ref())
}
#[doc(alias = "rm", alias = "unlink", alias = "DeleteFile")]
#[doc(alias = "SYS_REMOVE")] #[doc(alias = "UHI_unlink")] pub fn remove_file<P: AsRef<CStr>>(path: P) -> io::Result<()> {
sys::fs::unlink(path.as_ref())
}
#[doc(alias = "mv", alias = "MoveFile", alias = "MoveFileEx")]
#[doc(alias = "SYS_RENAME")] pub fn rename<P: AsRef<CStr>, Q: AsRef<CStr>>(from: P, to: Q) -> io::Result<()> {
sys::fs::rename(from.as_ref(), to.as_ref())
}
pub struct File(OwnedFd);
impl File {
pub fn open<P: AsRef<CStr>>(path: P) -> io::Result<Self> {
OpenOptions::new().read(true).open(path.as_ref())
}
pub fn create<P: AsRef<CStr>>(path: P) -> io::Result<Self> {
OpenOptions::new().write(true).create(true).truncate(true).open(path.as_ref())
}
#[must_use]
pub fn options() -> OpenOptions {
OpenOptions::new()
}
#[doc(alias = "SYS_FLEN")] #[doc(alias = "UHI_fstat")] pub fn metadata(&self) -> io::Result<Metadata> {
sys::fs::metadata(self.as_fd()).map(Metadata)
}
}
impl_as_fd!(File);
impl_from_fd!(File);
impl fmt::Debug for File {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("File").field("fd", &self.as_fd().as_raw_fd()).finish()
}
}
impl io::Read for File {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
sys::read(self.as_fd(), buf)
}
}
impl io::Write for File {
fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
sys::write(self.as_fd(), bytes)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl io::Seek for File {
fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
sys::fs::seek(self.as_fd(), pos)
}
}
impl io::Read for &File {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
sys::read(self.as_fd(), buf)
}
}
impl io::Write for &File {
fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
sys::write(self.as_fd(), bytes)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl io::Seek for &File {
fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
sys::fs::seek(self.as_fd(), pos)
}
}
#[derive(Clone, Debug)]
pub struct OpenOptions {
pub(crate) read: bool,
pub(crate) write: bool,
pub(crate) append: bool,
pub(crate) truncate: bool,
pub(crate) create: bool,
#[allow(dead_code)]
pub(crate) create_new: bool,
#[allow(dead_code)]
pub(crate) mode: u32,
}
#[allow(missing_docs)] impl OpenOptions {
pub fn new() -> Self {
Self {
read: false,
write: false,
append: false,
truncate: false,
create: false,
create_new: false,
mode: 0o666,
}
}
pub fn read(&mut self, read: bool) -> &mut Self {
self.read = read;
self
}
pub fn write(&mut self, write: bool) -> &mut Self {
self.write = write;
self
}
pub fn append(&mut self, append: bool) -> &mut Self {
self.append = append;
self
}
pub fn truncate(&mut self, truncate: bool) -> &mut Self {
self.truncate = truncate;
self
}
pub fn create(&mut self, create: bool) -> &mut Self {
self.create = create;
self
}
pub fn open<P: AsRef<CStr>>(&self, path: P) -> io::Result<File> {
sys::fs::open(path.as_ref(), self).map(File)
}
}
pub struct Metadata(sys::fs::Metadata);
impl Metadata {
#[must_use]
pub fn len(&self) -> u64 {
self.0.size()
}
}
impl fmt::Debug for Metadata {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Metadata").finish_non_exhaustive()
}
}