fix sys_getdent64. pass ls in coreutils & busybox

master
WangRunji 6 years ago
parent b66c8811d1
commit 472dac5d09

@ -70,7 +70,12 @@ impl FileHandle {
self.inode.metadata()
}
pub fn get_entry(&self, id: usize) -> Result<String> {
self.inode.get_entry(id)
pub fn read_entry(&mut self) -> Result<String> {
if !self.options.read {
return Err(FsError::InvalidParam); // FIXME: => EBADF
}
let name = self.inode.get_entry(self.offset as usize)?;
self.offset += 1;
Ok(name)
}
}

@ -39,9 +39,9 @@ pub fn sys_write_file(proc: &mut Process, fd: usize, base: *const u8, len: usize
}
pub fn sys_readv(fd: usize, iov_ptr: *const IoVec, iov_count: usize) -> SysResult {
info!("readv: fd: {}, iov: {:?}, count: {}", fd, iov_ptr, iov_count);
let mut proc = process();
let mut iovs = IoVecs::check_and_new(iov_ptr, iov_count, &proc.memory_set, true)?;
info!("readv: fd: {}, iov: {:#x?}", fd, iovs);
// read all data to a buf
let file = proc.get_file(fd)?;
@ -53,9 +53,9 @@ pub fn sys_readv(fd: usize, iov_ptr: *const IoVec, iov_count: usize) -> SysResul
}
pub fn sys_writev(fd: usize, iov_ptr: *const IoVec, iov_count: usize) -> SysResult {
info!("writev: fd: {}, iov: {:?}, count: {}", fd, iov_ptr, iov_count);
let mut proc = process();
let iovs = IoVecs::check_and_new(iov_ptr, iov_count, &proc.memory_set, false)?;
info!("writev: fd: {}, iovs: {:#x?}", fd, iovs);
let file = proc.get_file(fd)?;
let buf = iovs.read_all_to_vec();
@ -116,28 +116,34 @@ pub fn sys_close(fd: usize) -> SysResult {
}
pub fn sys_stat(path: *const u8, stat_ptr: *mut Stat) -> SysResult {
warn!("stat is partial implemented as lstat");
sys_lstat(path, stat_ptr)
}
pub fn sys_fstat(fd: usize, stat_ptr: *mut Stat) -> SysResult {
info!("fstat: fd: {}", fd);
let mut proc = process();
let path = unsafe { proc.memory_set.check_and_clone_cstr(path) }
.ok_or(SysError::EINVAL)?;
if !proc.memory_set.check_mut_ptr(stat_ptr) {
return Err(SysError::EINVAL);
}
info!("stat: path: {}", path);
let inode = ROOT_INODE.lookup(path.as_str())?;
let stat = Stat::from(inode.metadata()?);
let file = proc.get_file(fd)?;
let stat = Stat::from(file.info()?);
// TODO: handle symlink
unsafe { stat_ptr.write(stat); }
Ok(0)
}
pub fn sys_fstat(fd: usize, stat_ptr: *mut Stat) -> SysResult {
info!("fstat: fd: {}", fd);
pub fn sys_lstat(path: *const u8, stat_ptr: *mut Stat) -> SysResult {
let mut proc = process();
let path = unsafe { proc.memory_set.check_and_clone_cstr(path) }
.ok_or(SysError::EINVAL)?;
if !proc.memory_set.check_mut_ptr(stat_ptr) {
return Err(SysError::EINVAL);
}
let file = proc.get_file(fd)?;
let stat = Stat::from(file.info()?);
info!("lstat: path: {}", path);
let inode = ROOT_INODE.lookup(path.as_str())?;
let stat = Stat::from(inode.metadata()?);
unsafe { stat_ptr.write(stat); }
Ok(0)
}
@ -157,27 +163,27 @@ pub fn sys_lseek(fd: usize, offset: i64, whence: u8) -> SysResult {
Ok(offset as isize)
}
/// entry_id = dentry.offset / 256
/// dentry.name = entry_name
/// dentry.offset += 256
pub fn sys_getdirentry(fd: usize, dentry_ptr: *mut DirEntry) -> SysResult {
info!("getdirentry: {}", fd);
pub fn sys_getdents64(fd: usize, buf: *mut LinuxDirent64, buf_size: usize) -> SysResult {
info!("getdents64: fd: {}, ptr: {:?}, buf_size: {}", fd, buf, buf_size);
let mut proc = process();
if !proc.memory_set.check_mut_ptr(dentry_ptr) {
if !proc.memory_set.check_mut_array(buf as *mut u8, buf_size) {
return Err(SysError::EINVAL);
}
let file = proc.get_file(fd)?;
let dentry = unsafe { &mut *dentry_ptr };
if !dentry.check() {
return Err(SysError::EINVAL);
}
let info = file.info()?;
if info.type_ != FileType::Dir || info.size <= dentry.entry_id() {
return Err(SysError::EINVAL);
}
let name = file.get_entry(dentry.entry_id())?;
dentry.set_name(name.as_str());
Ok(0)
if info.type_ != FileType::Dir {
return Err(SysError::ENOTDIR);
}
let mut writer = unsafe { DirentBufWriter::new(buf, buf_size) };
loop {
let name = match file.read_entry() {
Err(FsError::EntryNotFound) => break,
r => r,
}?;
let ok = writer.try_write(0, 0, name.as_str());
if !ok { break; }
}
Ok(writer.written_size as isize)
}
pub fn sys_dup2(fd1: usize, fd2: usize) -> SysResult {
@ -260,23 +266,57 @@ impl OpenFlags {
}
}
#[repr(C)]
pub struct DirEntry {
offset: u32,
name: [u8; 256],
#[derive(Debug)]
#[repr(packed)] // Don't use 'C'. Or its size will align up to 8 bytes.
pub struct LinuxDirent64 {
/// Inode number
ino: u64,
/// Offset to next structure
offset: u64,
/// Size of this dirent
reclen: u16,
/// File type
type_: u8,
/// Filename (null-terminated)
name: [u8; 0],
}
impl DirEntry {
fn check(&self) -> bool {
self.offset % 256 == 0
}
fn entry_id(&self) -> usize {
(self.offset / 256) as usize
}
fn set_name(&mut self, name: &str) {
self.name[..name.len()].copy_from_slice(name.as_bytes());
self.name[name.len()] = 0;
self.offset += 256;
struct DirentBufWriter {
ptr: *mut LinuxDirent64,
rest_size: usize,
written_size: usize,
}
impl DirentBufWriter {
unsafe fn new(buf: *mut LinuxDirent64, size: usize) -> Self {
DirentBufWriter {
ptr: buf,
rest_size: size,
written_size: 0,
}
}
fn try_write(&mut self, inode: u64, type_: u8, name: &str) -> bool {
let len = ::core::mem::size_of::<LinuxDirent64>() + name.len() + 1;
let len = (len + 7) / 8 * 8; // align up
if self.rest_size < len {
return false;
}
let dent = LinuxDirent64 {
ino: inode,
offset: 0,
reclen: len as u16,
type_,
name: [],
};
unsafe {
self.ptr.write(dent);
let name_ptr = self.ptr.add(1) as _;
util::write_cstr(name_ptr, name);
self.ptr = (self.ptr as *const u8).add(len) as _;
}
self.rest_size -= len;
self.written_size += len;
true
}
}

@ -37,6 +37,7 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize {
003 => sys_close(args[0]),
004 => sys_stat(args[0] as *const u8, args[1] as *mut Stat),
005 => sys_fstat(args[0], args[1] as *mut Stat),
006 => sys_lstat(args[0] as *const u8, args[1] as *mut Stat),
// 007 => sys_poll(),
008 => sys_lseek(args[0], args[1] as i64, args[2] as u8),
009 => sys_mmap(args[0], args[1], args[2], args[3], args[4] as i32, args[5]),
@ -72,7 +73,6 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize {
// 074 => sys_fsync(),
// 076 => sys_trunc(),
// 077 => sys_ftrunc(),
078 => sys_getdirentry(args[0], args[1] as *mut DirEntry),
// 079 => sys_getcwd(),
// 080 => sys_chdir(),
// 082 => sys_rename(),
@ -87,6 +87,7 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize {
// 160 => sys_setrlimit(),
// 162 => sys_sync(),
// 169 => sys_reboot(),
217 => sys_getdents64(args[0], args[1] as *mut LinuxDirent64, args[2]),
// 293 => sys_pipe(),
// for musl: empty impl
@ -139,6 +140,10 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize {
warn!("sys_set_tid_address is unimplemented");
Ok(thread::current().id() as isize)
}
228 => {
warn!("sys_clock_gettime is unimplemented");
Ok(0)
}
231 => {
warn!("sys_exit_group is unimplemented");
sys_exit(args[0] as isize);

@ -1,6 +1,12 @@
/// Convert C string to Rust string
pub unsafe fn from_cstr(s: *const u8) -> &'static str {
use core::{str, slice};
let len = (0usize..).find(|&i| *s.offset(i as isize) == 0).unwrap();
let len = (0usize..).find(|&i| *s.add(i) == 0).unwrap();
str::from_utf8(slice::from_raw_parts(s, len)).unwrap()
}
/// Write a Rust string to C string
pub unsafe fn write_cstr(ptr: *mut u8, s: &str) {
ptr.copy_from(s.as_ptr(), s.len());
ptr.add(s.len()).write(0);
}

Loading…
Cancel
Save