mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-03 05:27:36 +00:00
Extending filesystem support for hermit-os
This commit is contained in:
parent
384d26fc7e
commit
aa11bf6f0a
@ -48,6 +48,11 @@ impl FileDesc {
|
||||
pub fn set_nonblocking(&self, _nonblocking: bool) -> io::Result<()> {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
pub fn fstat(&self, stat: *mut abi::stat) -> io::Result<()> {
|
||||
cvt(unsafe { abi::fstat(self.fd.as_raw_fd(), stat) })?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Read for &'a FileDesc {
|
||||
|
@ -2,11 +2,14 @@ use super::abi::{self, O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_W
|
||||
use super::fd::FileDesc;
|
||||
use crate::ffi::{CStr, OsString};
|
||||
use crate::fmt;
|
||||
use crate::hash::{Hash, Hasher};
|
||||
use crate::io::{self, Error, ErrorKind};
|
||||
use crate::io::{BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
|
||||
use crate::mem;
|
||||
use crate::os::hermit::ffi::OsStringExt;
|
||||
use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
|
||||
use crate::path::{Path, PathBuf};
|
||||
use crate::ptr;
|
||||
use crate::sync::Arc;
|
||||
use crate::sys::common::small_c_string::run_path_with_cstr;
|
||||
use crate::sys::cvt;
|
||||
use crate::sys::time::SystemTime;
|
||||
@ -18,12 +21,44 @@ pub use crate::sys_common::fs::{copy, try_exists};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct File(FileDesc);
|
||||
#[derive(Clone)]
|
||||
pub struct FileAttr {
|
||||
stat_val: stat_struct,
|
||||
}
|
||||
|
||||
pub struct FileAttr(!);
|
||||
impl FileAttr {
|
||||
fn from_stat(stat_val: stat_struct) -> Self {
|
||||
Self { stat_val }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ReadDir(!);
|
||||
// all DirEntry's will have a reference to this struct
|
||||
struct InnerReadDir {
|
||||
dirp: FileDesc,
|
||||
root: PathBuf,
|
||||
}
|
||||
|
||||
pub struct DirEntry(!);
|
||||
pub struct ReadDir {
|
||||
inner: Arc<InnerReadDir>,
|
||||
end_of_stream: bool,
|
||||
}
|
||||
|
||||
impl ReadDir {
|
||||
fn new(inner: InnerReadDir) -> Self {
|
||||
Self { inner: Arc::new(inner), end_of_stream: false }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DirEntry {
|
||||
dir: Arc<InnerReadDir>,
|
||||
entry: dirent_min,
|
||||
name: OsString,
|
||||
}
|
||||
|
||||
struct dirent_min {
|
||||
d_ino: u64,
|
||||
d_type: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct OpenOptions {
|
||||
@ -41,72 +76,78 @@ pub struct OpenOptions {
|
||||
#[derive(Copy, Clone, Debug, Default)]
|
||||
pub struct FileTimes {}
|
||||
|
||||
pub struct FilePermissions(!);
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct FilePermissions {
|
||||
mode: u32,
|
||||
}
|
||||
|
||||
pub struct FileType(!);
|
||||
#[derive(Copy, Clone, Eq, Debug)]
|
||||
pub struct FileType {
|
||||
mode: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DirBuilder {}
|
||||
|
||||
impl FileAttr {
|
||||
pub fn size(&self) -> u64 {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn perm(&self) -> FilePermissions {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn file_type(&self) -> FileType {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn modified(&self) -> io::Result<SystemTime> {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn accessed(&self) -> io::Result<SystemTime> {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn created(&self) -> io::Result<SystemTime> {
|
||||
self.0
|
||||
impl PartialEq for FileType {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.mode == other.mode
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for FileAttr {
|
||||
fn clone(&self) -> FileAttr {
|
||||
self.0
|
||||
impl core::hash::Hash for FileType {
|
||||
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||
self.mode.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DirBuilder {
|
||||
mode: u32,
|
||||
}
|
||||
|
||||
impl FileAttr {
|
||||
pub fn modified(&self) -> io::Result<SystemTime> {
|
||||
Ok(SystemTime::new(self.stat_val.st_mtime, self.stat_val.st_mtime_nsec))
|
||||
}
|
||||
|
||||
pub fn accessed(&self) -> io::Result<SystemTime> {
|
||||
Ok(SystemTime::new(self.stat_val.st_atime, self.stat_val.st_atime_nsec))
|
||||
}
|
||||
|
||||
pub fn created(&self) -> io::Result<SystemTime> {
|
||||
Ok(SystemTime::new(self.stat_val.st_ctime, self.stat_val.st_ctime_nsec))
|
||||
}
|
||||
|
||||
pub fn size(&self) -> u64 {
|
||||
self.stat_val.st_size as u64
|
||||
}
|
||||
pub fn perm(&self) -> FilePermissions {
|
||||
FilePermissions { mode: (self.stat_val.st_mode) }
|
||||
}
|
||||
|
||||
pub fn file_type(&self) -> FileType {
|
||||
let masked_mode = self.stat_val.st_mode & S_IFMT;
|
||||
let mode = match masked_mode {
|
||||
S_IFDIR => DT_DIR,
|
||||
S_IFLNK => DT_LNK,
|
||||
S_IFREG => DT_REG,
|
||||
_ => DT_UNKNOWN,
|
||||
};
|
||||
FileType { mode: mode }
|
||||
}
|
||||
}
|
||||
|
||||
impl FilePermissions {
|
||||
pub fn readonly(&self) -> bool {
|
||||
self.0
|
||||
// check if any class (owner, group, others) has write permission
|
||||
self.mode & 0o222 == 0
|
||||
}
|
||||
|
||||
pub fn set_readonly(&mut self, _readonly: bool) {
|
||||
self.0
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for FilePermissions {
|
||||
fn clone(&self) -> FilePermissions {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for FilePermissions {
|
||||
fn eq(&self, _other: &FilePermissions) -> bool {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for FilePermissions {}
|
||||
|
||||
impl fmt::Debug for FilePermissions {
|
||||
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.0
|
||||
#[allow(dead_code)]
|
||||
pub fn mode(&self) -> u32 {
|
||||
self.mode as u32
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,49 +158,21 @@ impl FileTimes {
|
||||
|
||||
impl FileType {
|
||||
pub fn is_dir(&self) -> bool {
|
||||
self.0
|
||||
self.mode == DT_DIR
|
||||
}
|
||||
|
||||
pub fn is_file(&self) -> bool {
|
||||
self.0
|
||||
self.mode == DT_REG
|
||||
}
|
||||
|
||||
pub fn is_symlink(&self) -> bool {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for FileType {
|
||||
fn clone(&self) -> FileType {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Copy for FileType {}
|
||||
|
||||
impl PartialEq for FileType {
|
||||
fn eq(&self, _other: &FileType) -> bool {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for FileType {}
|
||||
|
||||
impl Hash for FileType {
|
||||
fn hash<H: Hasher>(&self, _h: &mut H) {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for FileType {
|
||||
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.0
|
||||
self.mode == DT_LNK
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ReadDir {
|
||||
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.0
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame.
|
||||
// Thus the result will be e g 'ReadDir("/home")'
|
||||
fmt::Debug::fmt(&*self.inner.root, f)
|
||||
}
|
||||
}
|
||||
|
||||
@ -167,25 +180,105 @@ impl Iterator for ReadDir {
|
||||
type Item = io::Result<DirEntry>;
|
||||
|
||||
fn next(&mut self) -> Option<io::Result<DirEntry>> {
|
||||
self.0
|
||||
if self.end_of_stream {
|
||||
return None;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
loop {
|
||||
// As of POSIX.1-2017, readdir() is not required to be thread safe; only
|
||||
// readdir_r() is. However, readdir_r() cannot correctly handle platforms
|
||||
// with unlimited or variable NAME_MAX. Many modern platforms guarantee
|
||||
// thread safety for readdir() as long an individual DIR* is not accessed
|
||||
// concurrently, which is sufficient for Rust.
|
||||
let entry_ptr = match abi::readdir(self.inner.dirp.as_raw_fd()) {
|
||||
abi::DirectoryEntry::Invalid(e) => {
|
||||
// We either encountered an error, or reached the end. Either way,
|
||||
// the next call to next() should return None.
|
||||
self.end_of_stream = true;
|
||||
|
||||
return Some(Err(Error::from_raw_os_error(e)));
|
||||
}
|
||||
abi::DirectoryEntry::Valid(ptr) => {
|
||||
if ptr.is_null() {
|
||||
return None;
|
||||
}
|
||||
|
||||
ptr
|
||||
}
|
||||
};
|
||||
|
||||
macro_rules! offset_ptr {
|
||||
($entry_ptr:expr, $field:ident) => {{
|
||||
const OFFSET: isize = {
|
||||
let delusion = MaybeUninit::<dirent>::uninit();
|
||||
let entry_ptr = delusion.as_ptr();
|
||||
unsafe {
|
||||
ptr::addr_of!((*entry_ptr).$field)
|
||||
.cast::<u8>()
|
||||
.offset_from(entry_ptr.cast::<u8>())
|
||||
}
|
||||
};
|
||||
if true {
|
||||
// Cast to the same type determined by the else branch.
|
||||
$entry_ptr.byte_offset(OFFSET).cast::<_>()
|
||||
} else {
|
||||
#[allow(deref_nullptr)]
|
||||
{
|
||||
ptr::addr_of!((*ptr::null::<dirent>()).$field)
|
||||
}
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
// d_name is NOT guaranteed to be null-terminated.
|
||||
let name_bytes = core::slice::from_raw_parts(
|
||||
offset_ptr!(entry_ptr, d_name) as *const u8,
|
||||
*offset_ptr!(entry_ptr, d_namelen) as usize,
|
||||
)
|
||||
.to_vec();
|
||||
|
||||
if name_bytes == b"." || name_bytes == b".." {
|
||||
continue;
|
||||
}
|
||||
|
||||
let name = OsString::from_vec(name_bytes);
|
||||
|
||||
let entry = dirent_min {
|
||||
d_ino: *offset_ptr!(entry_ptr, d_ino),
|
||||
d_type: *offset_ptr!(entry_ptr, d_type),
|
||||
};
|
||||
|
||||
return Some(Ok(DirEntry { entry, name: name, dir: Arc::clone(&self.inner) }));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DirEntry {
|
||||
pub fn path(&self) -> PathBuf {
|
||||
self.0
|
||||
self.dir.root.join(self.file_name_os_str())
|
||||
}
|
||||
|
||||
pub fn file_name(&self) -> OsString {
|
||||
self.0
|
||||
self.file_name_os_str().to_os_string()
|
||||
}
|
||||
|
||||
pub fn metadata(&self) -> io::Result<FileAttr> {
|
||||
self.0
|
||||
lstat(&self.path())
|
||||
}
|
||||
|
||||
pub fn file_type(&self) -> io::Result<FileType> {
|
||||
self.0
|
||||
Ok(FileType { mode: self.entry.d_type })
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn ino(&self) -> u64 {
|
||||
self.entry.d_ino
|
||||
}
|
||||
|
||||
pub fn file_name_os_str(&self) -> &OsStr {
|
||||
self.name.as_os_str()
|
||||
}
|
||||
}
|
||||
|
||||
@ -288,7 +381,9 @@ impl File {
|
||||
}
|
||||
|
||||
pub fn file_attr(&self) -> io::Result<FileAttr> {
|
||||
Err(Error::from_raw_os_error(22))
|
||||
let mut stat_val: stat_struct = unsafe { mem::zeroed() };
|
||||
self.0.fstat(&mut stat_val)?;
|
||||
Ok(FileAttr::from_stat(stat_val))
|
||||
}
|
||||
|
||||
pub fn fsync(&self) -> io::Result<()> {
|
||||
@ -357,11 +452,18 @@ impl File {
|
||||
|
||||
impl DirBuilder {
|
||||
pub fn new() -> DirBuilder {
|
||||
DirBuilder {}
|
||||
DirBuilder { mode: 0o777 }
|
||||
}
|
||||
|
||||
pub fn mkdir(&self, _p: &Path) -> io::Result<()> {
|
||||
unsupported()
|
||||
pub fn mkdir(&self, path: &Path) -> io::Result<()> {
|
||||
run_path_with_cstr(path, |path| {
|
||||
cvt(unsafe { abi::mkdir(path.as_ptr(), self.mode) }).map(|_| ())
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn set_mode(&mut self, mode: u32) {
|
||||
self.mode = mode as u32;
|
||||
}
|
||||
}
|
||||
|
||||
@ -416,8 +518,12 @@ impl FromRawFd for File {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn readdir(_p: &Path) -> io::Result<ReadDir> {
|
||||
unsupported()
|
||||
pub fn readdir(path: &Path) -> io::Result<ReadDir> {
|
||||
let fd_raw = run_path_with_cstr(path, |path| cvt(unsafe { abi::opendir(path.as_ptr()) }))?;
|
||||
let fd = unsafe { FileDesc::from_raw_fd(fd_raw as i32) };
|
||||
let root = path.to_path_buf();
|
||||
let inner = InnerReadDir { dirp: fd, root };
|
||||
Ok(ReadDir::new(inner))
|
||||
}
|
||||
|
||||
pub fn unlink(path: &Path) -> io::Result<()> {
|
||||
@ -428,12 +534,12 @@ pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> {
|
||||
match perm.0 {}
|
||||
pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> {
|
||||
Err(Error::from_raw_os_error(22))
|
||||
}
|
||||
|
||||
pub fn rmdir(_p: &Path) -> io::Result<()> {
|
||||
unsupported()
|
||||
pub fn rmdir(path: &Path) -> io::Result<()> {
|
||||
run_path_with_cstr(path, |path| cvt(unsafe { abi::rmdir(path.as_ptr()) }).map(|_| ()))
|
||||
}
|
||||
|
||||
pub fn remove_dir_all(_path: &Path) -> io::Result<()> {
|
||||
@ -453,12 +559,20 @@ pub fn link(_original: &Path, _link: &Path) -> io::Result<()> {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
pub fn stat(_p: &Path) -> io::Result<FileAttr> {
|
||||
unsupported()
|
||||
pub fn stat(path: &Path) -> io::Result<FileAttr> {
|
||||
run_path_with_cstr(path, |path| {
|
||||
let mut stat_val: stat_struct = unsafe { mem::zeroed() };
|
||||
cvt(unsafe { abi::stat(path.as_ptr(), &mut stat_val) })?;
|
||||
Ok(FileAttr::from_stat(stat_val))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn lstat(_p: &Path) -> io::Result<FileAttr> {
|
||||
unsupported()
|
||||
pub fn lstat(path: &Path) -> io::Result<FileAttr> {
|
||||
run_path_with_cstr(path, |path| {
|
||||
let mut stat_val: stat_struct = unsafe { mem::zeroed() };
|
||||
cvt(unsafe { abi::lstat(path.as_ptr(), &mut stat_val) })?;
|
||||
Ok(FileAttr::from_stat(stat_val))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
|
||||
|
@ -18,6 +18,12 @@ impl Timespec {
|
||||
Timespec { t: timespec { tv_sec: 0, tv_nsec: 0 } }
|
||||
}
|
||||
|
||||
const fn new(tv_sec: i64, tv_nsec: i64) -> Timespec {
|
||||
assert!(tv_nsec >= 0 && tv_nsec < NSEC_PER_SEC as i64);
|
||||
// SAFETY: The assert above checks tv_nsec is within the valid range
|
||||
Timespec { t: timespec { tv_sec: tv_sec, tv_nsec: tv_nsec } }
|
||||
}
|
||||
|
||||
fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
|
||||
if self >= other {
|
||||
Ok(if self.t.tv_nsec >= other.t.tv_nsec {
|
||||
@ -195,6 +201,10 @@ pub struct SystemTime(Timespec);
|
||||
pub const UNIX_EPOCH: SystemTime = SystemTime(Timespec::zero());
|
||||
|
||||
impl SystemTime {
|
||||
pub fn new(tv_sec: i64, tv_nsec: i64) -> SystemTime {
|
||||
SystemTime(Timespec::new(tv_sec, tv_nsec))
|
||||
}
|
||||
|
||||
pub fn now() -> SystemTime {
|
||||
let mut time: Timespec = Timespec::zero();
|
||||
let _ = unsafe { abi::clock_gettime(CLOCK_REALTIME, core::ptr::addr_of_mut!(time.t)) };
|
||||
|
Loading…
Reference in New Issue
Block a user