Rewrite getdents syscall
This commit is contained in:
parent
789b57c6f7
commit
001df6f309
@ -55,8 +55,8 @@ pub trait File: Debug + Sync + Send + Any {
|
|||||||
return_op_unsupported_error!("set_len")
|
return_op_unsupported_error!("set_len")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_entry(&self) -> Result<String> {
|
fn iterate_entries(&self, writer: &mut dyn DirentWriter) -> Result<usize> {
|
||||||
return_op_unsupported_error!("read_entry", ENOTDIR)
|
return_op_unsupported_error!("iterate_entries")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sync_all(&self) -> Result<()> {
|
fn sync_all(&self) -> Result<()> {
|
||||||
|
@ -1,180 +0,0 @@
|
|||||||
use super::*;
|
|
||||||
|
|
||||||
pub fn do_getdents64(fd: FileDesc, buf: &mut [u8]) -> Result<usize> {
|
|
||||||
getdents_common::<u8>(fd, buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_getdents(fd: FileDesc, buf: &mut [u8]) -> Result<usize> {
|
|
||||||
getdents_common::<()>(fd, buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn getdents_common<T: DirentType + Copy>(fd: FileDesc, buf: &mut [u8]) -> Result<usize> {
|
|
||||||
debug!(
|
|
||||||
"getdents: fd: {}, buf: {:?}, buf_size: {}",
|
|
||||||
fd,
|
|
||||||
buf.as_ptr(),
|
|
||||||
buf.len(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let file_ref = current!().file(fd)?;
|
|
||||||
let info = file_ref.metadata()?;
|
|
||||||
if info.type_ != FileType::Dir {
|
|
||||||
return_errno!(ENOTDIR, "");
|
|
||||||
}
|
|
||||||
let mut writer = unsafe { DirentBufWriter::new(buf) };
|
|
||||||
loop {
|
|
||||||
let name = match file_ref.read_entry() {
|
|
||||||
Err(e) => {
|
|
||||||
let errno = e.errno();
|
|
||||||
if errno == ENOENT {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return Err(e.cause_err(|_| errno!(errno, "failed to read entry")));
|
|
||||||
}
|
|
||||||
Ok(name) => name,
|
|
||||||
};
|
|
||||||
// TODO: get ino and type from dirent
|
|
||||||
let dirent = LinuxDirent::<T>::new(1, &name, DT_UNKNOWN);
|
|
||||||
if let Err(e) = writer.try_write(&dirent, &name) {
|
|
||||||
file_ref.seek(SeekFrom::Current(-1))?;
|
|
||||||
if writer.written_size == 0 {
|
|
||||||
return Err(e);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(writer.written_size)
|
|
||||||
}
|
|
||||||
|
|
||||||
const DT_UNKNOWN: u8 = 0;
|
|
||||||
|
|
||||||
#[repr(packed)] // Don't use 'C'. Or its size will align up to 8 bytes.
|
|
||||||
struct LinuxDirent<T: DirentType + Copy> {
|
|
||||||
/// Inode number
|
|
||||||
ino: u64,
|
|
||||||
/// Offset to next structure
|
|
||||||
offset: u64,
|
|
||||||
/// Size of this dirent
|
|
||||||
reclen: u16,
|
|
||||||
/// File type
|
|
||||||
type_: T,
|
|
||||||
/// Filename (null-terminated)
|
|
||||||
name: [u8; 0],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: DirentType + Copy> LinuxDirent<T> {
|
|
||||||
fn new(ino: u64, name: &str, d_type: u8) -> Self {
|
|
||||||
let ori_len = if !T::at_the_end_of_linux_dirent() {
|
|
||||||
core::mem::size_of::<LinuxDirent<T>>() + name.len() + 1
|
|
||||||
} else {
|
|
||||||
// pad the file type at the end
|
|
||||||
core::mem::size_of::<LinuxDirent<T>>() + name.len() + 1 + core::mem::size_of::<u8>()
|
|
||||||
};
|
|
||||||
let len = align_up(ori_len, 8); // align up to 8 bytes
|
|
||||||
Self {
|
|
||||||
ino,
|
|
||||||
offset: 0,
|
|
||||||
reclen: len as u16,
|
|
||||||
type_: T::set_type(d_type),
|
|
||||||
name: [],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn len(&self) -> usize {
|
|
||||||
self.reclen as usize
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: DirentType + Copy> Copy for LinuxDirent<T> {}
|
|
||||||
|
|
||||||
impl<T: DirentType + Copy> Clone for LinuxDirent<T> {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self {
|
|
||||||
ino: self.ino,
|
|
||||||
offset: self.offset,
|
|
||||||
reclen: self.reclen,
|
|
||||||
type_: self.type_,
|
|
||||||
name: self.name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trait DirentType {
|
|
||||||
fn set_type(d_type: u8) -> Self;
|
|
||||||
fn at_the_end_of_linux_dirent() -> bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DirentType for u8 {
|
|
||||||
fn set_type(d_type: u8) -> Self {
|
|
||||||
d_type
|
|
||||||
}
|
|
||||||
fn at_the_end_of_linux_dirent() -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl DirentType for () {
|
|
||||||
fn set_type(d_type: u8) -> Self {
|
|
||||||
Default::default()
|
|
||||||
}
|
|
||||||
fn at_the_end_of_linux_dirent() -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct DirentBufWriter<'a> {
|
|
||||||
buf: &'a mut [u8],
|
|
||||||
rest_size: usize,
|
|
||||||
written_size: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> DirentBufWriter<'a> {
|
|
||||||
unsafe fn new(buf: &'a mut [u8]) -> Self {
|
|
||||||
let rest_size = buf.len();
|
|
||||||
DirentBufWriter {
|
|
||||||
buf,
|
|
||||||
rest_size,
|
|
||||||
written_size: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn try_write<T: DirentType + Copy>(
|
|
||||||
&mut self,
|
|
||||||
dirent: &LinuxDirent<T>,
|
|
||||||
name: &str,
|
|
||||||
) -> Result<()> {
|
|
||||||
if self.rest_size < dirent.len() {
|
|
||||||
return_errno!(EINVAL, "the given buffer is too small");
|
|
||||||
}
|
|
||||||
unsafe {
|
|
||||||
let ptr = self.buf.as_mut_ptr().add(self.written_size) as *mut LinuxDirent<T>;
|
|
||||||
ptr.write(*dirent);
|
|
||||||
let name_ptr = ptr.add(1) as _;
|
|
||||||
write_cstr(name_ptr, name);
|
|
||||||
if T::at_the_end_of_linux_dirent() {
|
|
||||||
// pad zero bytes and file type at the end
|
|
||||||
let mut ptr = name_ptr.add(name.len() + 1);
|
|
||||||
let mut rest_len = {
|
|
||||||
let written_len = core::mem::size_of::<LinuxDirent<T>>() + name.len() + 1;
|
|
||||||
dirent.len() - written_len
|
|
||||||
};
|
|
||||||
while rest_len > 1 {
|
|
||||||
ptr.write(0);
|
|
||||||
ptr = ptr.add(1);
|
|
||||||
rest_len -= 1;
|
|
||||||
}
|
|
||||||
// the last one is file type
|
|
||||||
ptr.write(DT_UNKNOWN);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.rest_size -= dirent.len();
|
|
||||||
self.written_size += dirent.len();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Write a Rust string to C string
|
|
||||||
unsafe fn write_cstr(ptr: *mut u8, s: &str) {
|
|
||||||
ptr.copy_from(s.as_ptr(), s.len());
|
|
||||||
ptr.add(s.len()).write(0);
|
|
||||||
}
|
|
216
src/libos/src/fs/file_ops/getdents.rs
Normal file
216
src/libos/src/fs/file_ops/getdents.rs
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
use super::*;
|
||||||
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
|
pub fn do_getdents64(fd: FileDesc, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
getdents_common::<LinuxDirent64>(fd, buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn do_getdents(fd: FileDesc, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
getdents_common::<LinuxDirent>(fd, buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getdents_common<T: Dirent>(fd: FileDesc, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
debug!(
|
||||||
|
"getdents: fd: {}, buf: {:?}, buf_size: {}",
|
||||||
|
fd,
|
||||||
|
buf.as_ptr(),
|
||||||
|
buf.len(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let file_ref = current!().file(fd)?;
|
||||||
|
let info = file_ref.metadata()?;
|
||||||
|
if info.type_ != FileType::Dir {
|
||||||
|
return_errno!(ENOTDIR, "");
|
||||||
|
}
|
||||||
|
let mut writer = DirentBufWriter::<T>::new(buf);
|
||||||
|
let written_size = file_ref.iterate_entries(&mut writer)?;
|
||||||
|
Ok(written_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DirentBufWriter<'a, T: Dirent> {
|
||||||
|
buf: &'a mut [u8],
|
||||||
|
written_size: usize,
|
||||||
|
phantom: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: Dirent> DirentBufWriter<'a, T> {
|
||||||
|
fn new(buf: &'a mut [u8]) -> Self {
|
||||||
|
Self {
|
||||||
|
buf,
|
||||||
|
written_size: 0,
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_write(&mut self, name: &str, ino: u64, type_: FileType) -> Result<usize> {
|
||||||
|
let dirent: T = Dirent::new(name, ino, type_);
|
||||||
|
if self.buf.len() - self.written_size < dirent.rec_len() {
|
||||||
|
return_errno!(EINVAL, "the given buffer is too small");
|
||||||
|
}
|
||||||
|
dirent.dump(&mut self.buf[self.written_size..], name, type_)?;
|
||||||
|
self.written_size += dirent.rec_len();
|
||||||
|
Ok(dirent.rec_len())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: Dirent> DirentWriter for DirentBufWriter<'a, T> {
|
||||||
|
fn write_entry(
|
||||||
|
&mut self,
|
||||||
|
name: &str,
|
||||||
|
ino: u64,
|
||||||
|
type_: FileType,
|
||||||
|
) -> rcore_fs::vfs::Result<usize> {
|
||||||
|
let written_len = self
|
||||||
|
.try_write(&name, ino, type_)
|
||||||
|
.map_err(|_| FsError::InvalidParam)?;
|
||||||
|
Ok(written_len)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Dirent {
|
||||||
|
fn new(name: &str, ino: u64, type_: FileType) -> Self;
|
||||||
|
fn rec_len(&self) -> usize;
|
||||||
|
fn dump(&self, buf: &mut [u8], name: &str, type_: FileType) -> Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Same with struct linux_dirent64
|
||||||
|
#[repr(packed)] // Don't use 'C'. Or its size will align up to 8 bytes.
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
struct LinuxDirent64 {
|
||||||
|
/// Inode number
|
||||||
|
pub ino: u64,
|
||||||
|
/// Offset to next structure
|
||||||
|
pub offset: u64,
|
||||||
|
/// Size of this dirent
|
||||||
|
pub rec_len: u16,
|
||||||
|
/// File type
|
||||||
|
pub type_: DirentType,
|
||||||
|
/// Filename (null-terminated)
|
||||||
|
pub name: [u8; 0],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dirent for LinuxDirent64 {
|
||||||
|
fn new(name: &str, ino: u64, type_: FileType) -> Self {
|
||||||
|
let ori_len = core::mem::size_of::<Self>() + name.len() + 1;
|
||||||
|
let len = align_up(ori_len, 8); // align up to 8 bytes
|
||||||
|
Self {
|
||||||
|
ino,
|
||||||
|
offset: 0,
|
||||||
|
rec_len: len as u16,
|
||||||
|
type_: DirentType::from_file_type(type_),
|
||||||
|
name: [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rec_len(&self) -> usize {
|
||||||
|
self.rec_len as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dump(&self, buf: &mut [u8], name: &str, _type_: FileType) -> Result<()> {
|
||||||
|
unsafe {
|
||||||
|
let ptr = buf.as_mut_ptr() as *mut Self;
|
||||||
|
ptr.write(*self);
|
||||||
|
let name_ptr = ptr.add(1) as _;
|
||||||
|
write_cstr(name_ptr, name);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Same with struct linux_dirent
|
||||||
|
#[repr(packed)] // Don't use 'C'. Or its size will align up to 8 bytes.
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
struct LinuxDirent {
|
||||||
|
/// Inode number
|
||||||
|
pub ino: u64,
|
||||||
|
/// Offset to next structure
|
||||||
|
pub offset: u64,
|
||||||
|
/// Size of this dirent
|
||||||
|
pub rec_len: u16,
|
||||||
|
/// Filename (null-terminated)
|
||||||
|
pub name: [u8; 0],
|
||||||
|
/*
|
||||||
|
/// Zero padding byte
|
||||||
|
pub pad: [u8],
|
||||||
|
/// File type
|
||||||
|
pub type_: DirentType,
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dirent for LinuxDirent {
|
||||||
|
fn new(name: &str, ino: u64, type_: FileType) -> Self {
|
||||||
|
let ori_len =
|
||||||
|
core::mem::size_of::<Self>() + name.len() + 1 + core::mem::size_of::<FileType>();
|
||||||
|
let len = align_up(ori_len, 8); // align up to 8 bytes
|
||||||
|
Self {
|
||||||
|
ino,
|
||||||
|
offset: 0,
|
||||||
|
rec_len: len as u16,
|
||||||
|
name: [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rec_len(&self) -> usize {
|
||||||
|
self.rec_len as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dump(&self, buf: &mut [u8], name: &str, type_: FileType) -> Result<()> {
|
||||||
|
unsafe {
|
||||||
|
let ptr = buf.as_mut_ptr() as *mut Self;
|
||||||
|
ptr.write(*self);
|
||||||
|
let mut ptr = ptr.add(1) as *mut u8;
|
||||||
|
write_cstr(ptr, name);
|
||||||
|
// Pad zero bytes if necessary
|
||||||
|
ptr = ptr.add(name.len() + 1);
|
||||||
|
let mut remaining_len = {
|
||||||
|
let written_len = core::mem::size_of::<Self>() + name.len() + 1;
|
||||||
|
self.rec_len() - written_len
|
||||||
|
};
|
||||||
|
while remaining_len > 1 {
|
||||||
|
ptr.write(0);
|
||||||
|
ptr = ptr.add(1);
|
||||||
|
remaining_len -= 1;
|
||||||
|
}
|
||||||
|
// Write the type at the end
|
||||||
|
let dirent_type = DirentType::from_file_type(type_);
|
||||||
|
ptr.write(dirent_type as u8);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
#[repr(u8)]
|
||||||
|
enum DirentType {
|
||||||
|
DT_UNKNOWN = 0,
|
||||||
|
DT_FIFO = 1,
|
||||||
|
DT_CHR = 2,
|
||||||
|
DT_DIR = 4,
|
||||||
|
DT_BLK = 6,
|
||||||
|
DT_REG = 8,
|
||||||
|
DT_LNK = 10,
|
||||||
|
DT_SOCK = 12,
|
||||||
|
DT_WHT = 14,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DirentType {
|
||||||
|
fn from_file_type(file_type: FileType) -> DirentType {
|
||||||
|
match file_type {
|
||||||
|
FileType::File => DirentType::DT_REG,
|
||||||
|
FileType::Dir => DirentType::DT_DIR,
|
||||||
|
FileType::SymLink => DirentType::DT_LNK,
|
||||||
|
FileType::CharDevice => DirentType::DT_CHR,
|
||||||
|
FileType::BlockDevice => DirentType::DT_BLK,
|
||||||
|
FileType::Socket => DirentType::DT_SOCK,
|
||||||
|
FileType::NamedPipe => DirentType::DT_FIFO,
|
||||||
|
_ => DirentType::DT_UNKNOWN,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write a Rust string to C string
|
||||||
|
unsafe fn write_cstr(ptr: *mut u8, s: &str) {
|
||||||
|
ptr.copy_from(s.as_ptr(), s.len());
|
||||||
|
ptr.add(s.len()).write(0);
|
||||||
|
}
|
@ -5,7 +5,6 @@ pub use self::access::{do_faccessat, AccessibilityCheckFlags, AccessibilityCheck
|
|||||||
pub use self::chmod::{do_fchmod, do_fchmodat, FileMode};
|
pub use self::chmod::{do_fchmod, do_fchmodat, FileMode};
|
||||||
pub use self::chown::{do_fchown, do_fchownat, ChownFlags};
|
pub use self::chown::{do_fchown, do_fchownat, ChownFlags};
|
||||||
pub use self::close::do_close;
|
pub use self::close::do_close;
|
||||||
pub use self::dirent::{do_getdents, do_getdents64};
|
|
||||||
pub use self::dup::{do_dup, do_dup2, do_dup3};
|
pub use self::dup::{do_dup, do_dup2, do_dup3};
|
||||||
pub use self::fallocate::do_fallocate;
|
pub use self::fallocate::do_fallocate;
|
||||||
pub use self::fcntl::{do_fcntl, FcntlCmd};
|
pub use self::fcntl::{do_fcntl, FcntlCmd};
|
||||||
@ -13,6 +12,7 @@ pub use self::file_flags::{AccessMode, CreationFlags, StatusFlags};
|
|||||||
pub use self::flock::{Flock, FlockType};
|
pub use self::flock::{Flock, FlockType};
|
||||||
pub use self::fspath::{FsPath, AT_FDCWD};
|
pub use self::fspath::{FsPath, AT_FDCWD};
|
||||||
pub use self::fsync::{do_fdatasync, do_fsync};
|
pub use self::fsync::{do_fdatasync, do_fsync};
|
||||||
|
pub use self::getdents::{do_getdents, do_getdents64};
|
||||||
pub use self::ioctl::{
|
pub use self::ioctl::{
|
||||||
do_ioctl, occlum_ocall_ioctl, BuiltinIoctlNum, IfConf, IoctlCmd, StructuredIoctlArgType,
|
do_ioctl, occlum_ocall_ioctl, BuiltinIoctlNum, IfConf, IoctlCmd, StructuredIoctlArgType,
|
||||||
StructuredIoctlNum,
|
StructuredIoctlNum,
|
||||||
@ -35,7 +35,6 @@ mod access;
|
|||||||
mod chmod;
|
mod chmod;
|
||||||
mod chown;
|
mod chown;
|
||||||
mod close;
|
mod close;
|
||||||
mod dirent;
|
|
||||||
mod dup;
|
mod dup;
|
||||||
mod fallocate;
|
mod fallocate;
|
||||||
mod fcntl;
|
mod fcntl;
|
||||||
@ -43,6 +42,7 @@ mod file_flags;
|
|||||||
mod flock;
|
mod flock;
|
||||||
mod fspath;
|
mod fspath;
|
||||||
mod fsync;
|
mod fsync;
|
||||||
|
mod getdents;
|
||||||
mod ioctl;
|
mod ioctl;
|
||||||
mod link;
|
mod link;
|
||||||
mod lseek;
|
mod lseek;
|
||||||
|
@ -3,6 +3,7 @@ use alloc::sync::{Arc, Weak};
|
|||||||
use core::any::Any;
|
use core::any::Any;
|
||||||
use rcore_fs::vfs::*;
|
use rcore_fs::vfs::*;
|
||||||
use std::io::{Read, Seek, SeekFrom, Write};
|
use std::io::{Read, Seek, SeekFrom, Write};
|
||||||
|
use std::os::unix::fs::{DirEntryExt, FileTypeExt};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::{SgxMutex as Mutex, SgxMutexGuard as MutexGuard};
|
use std::sync::{SgxMutex as Mutex, SgxMutexGuard as MutexGuard};
|
||||||
use std::untrusted::fs;
|
use std::untrusted::fs;
|
||||||
@ -209,6 +210,39 @@ impl INode for HNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn iterate_entries(&self, ctx: &mut DirentWriterContext) -> Result<usize> {
|
||||||
|
if !self.path.is_dir() {
|
||||||
|
return Err(FsError::NotDir);
|
||||||
|
}
|
||||||
|
let idx = ctx.pos();
|
||||||
|
let mut total_written_len = 0;
|
||||||
|
for entry in try_std!(self.path.read_dir()).skip(idx) {
|
||||||
|
let entry = try_std!(entry);
|
||||||
|
let written_len = match ctx.write_entry(
|
||||||
|
&entry
|
||||||
|
.file_name()
|
||||||
|
.into_string()
|
||||||
|
.map_err(|_| FsError::InvalidParam)?,
|
||||||
|
entry.ino(),
|
||||||
|
entry
|
||||||
|
.file_type()
|
||||||
|
.map_err(|_| FsError::InvalidParam)?
|
||||||
|
.into_fs_filetype(),
|
||||||
|
) {
|
||||||
|
Ok(written_len) => written_len,
|
||||||
|
Err(e) => {
|
||||||
|
if total_written_len == 0 {
|
||||||
|
return Err(e);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
total_written_len += written_len;
|
||||||
|
}
|
||||||
|
Ok(total_written_len)
|
||||||
|
}
|
||||||
|
|
||||||
fn io_control(&self, cmd: u32, data: usize) -> Result<()> {
|
fn io_control(&self, cmd: u32, data: usize) -> Result<()> {
|
||||||
warn!("HostFS: io_control is unimplemented");
|
warn!("HostFS: io_control is unimplemented");
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -265,6 +299,32 @@ impl IntoFsError for std::io::Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait IntoFsFileType {
|
||||||
|
fn into_fs_filetype(self) -> FileType;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoFsFileType for fs::FileType {
|
||||||
|
fn into_fs_filetype(self) -> FileType {
|
||||||
|
if self.is_dir() {
|
||||||
|
FileType::Dir
|
||||||
|
} else if self.is_file() {
|
||||||
|
FileType::File
|
||||||
|
} else if self.is_symlink() {
|
||||||
|
FileType::SymLink
|
||||||
|
} else if self.is_block_device() {
|
||||||
|
FileType::BlockDevice
|
||||||
|
} else if self.is_char_device() {
|
||||||
|
FileType::CharDevice
|
||||||
|
} else if self.is_fifo() {
|
||||||
|
FileType::NamedPipe
|
||||||
|
} else if self.is_socket() {
|
||||||
|
FileType::Socket
|
||||||
|
} else {
|
||||||
|
unimplemented!("unknown file type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
trait IntoFsMetadata {
|
trait IntoFsMetadata {
|
||||||
fn into_fs_metadata(self) -> Metadata;
|
fn into_fs_metadata(self) -> Metadata;
|
||||||
}
|
}
|
||||||
|
@ -144,14 +144,15 @@ impl File for INodeFile {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_entry(&self) -> Result<String> {
|
fn iterate_entries(&self, writer: &mut dyn DirentWriter) -> Result<usize> {
|
||||||
if !self.access_mode.readable() {
|
if !self.access_mode.readable() {
|
||||||
return_errno!(EACCES, "File not readable. Can't read entry.");
|
return_errno!(EACCES, "File not readable. Can't read entry.");
|
||||||
}
|
}
|
||||||
let mut offset = self.offset.lock().unwrap();
|
let mut offset = self.offset.lock().unwrap();
|
||||||
let name = self.inode.get_entry(*offset)?;
|
let mut dir_ctx = DirentWriterContext::new(*offset, writer);
|
||||||
*offset += 1;
|
let written_size = self.inode.iterate_entries(&mut dir_ctx)?;
|
||||||
Ok(name)
|
*offset = dir_ctx.pos();
|
||||||
|
Ok(written_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn access_mode(&self) -> Result<AccessMode> {
|
fn access_mode(&self) -> Result<AccessMode> {
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use process;
|
use process;
|
||||||
use rcore_fs::vfs::{FileSystem, FileType, FsError, INode, Metadata, Timespec, PATH_MAX};
|
use rcore_fs::vfs::{
|
||||||
|
DirentWriter, DirentWriterContext, FileSystem, FileType, FsError, INode, Metadata, Timespec,
|
||||||
|
PATH_MAX,
|
||||||
|
};
|
||||||
use std;
|
use std;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
Loading…
Reference in New Issue
Block a user