From 472dac5d09ce414d1deaeee2f2999502719ed769 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Sat, 2 Mar 2019 17:17:57 +0800 Subject: [PATCH] fix sys_getdent64. pass ls in coreutils & busybox --- kernel/src/fs/file.rs | 9 ++- kernel/src/syscall/fs.rs | 122 +++++++++++++++++++++++++------------- kernel/src/syscall/mod.rs | 7 ++- kernel/src/util.rs | 8 ++- 4 files changed, 101 insertions(+), 45 deletions(-) diff --git a/kernel/src/fs/file.rs b/kernel/src/fs/file.rs index 6efa7c3..f10a3af 100644 --- a/kernel/src/fs/file.rs +++ b/kernel/src/fs/file.rs @@ -70,7 +70,12 @@ impl FileHandle { self.inode.metadata() } - pub fn get_entry(&self, id: usize) -> Result { - self.inode.get_entry(id) + pub fn read_entry(&mut self) -> Result { + 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) } } \ No newline at end of file diff --git a/kernel/src/syscall/fs.rs b/kernel/src/syscall/fs.rs index 7473e17..4e38c13 100644 --- a/kernel/src/syscall/fs.rs +++ b/kernel/src/syscall/fs.rs @@ -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); + if info.type_ != FileType::Dir { + return Err(SysError::ENOTDIR); } - let name = file.get_entry(dentry.entry_id())?; - dentry.set_name(name.as_str()); - Ok(0) + 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 +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 set_name(&mut self, name: &str) { - self.name[..name.len()].copy_from_slice(name.as_bytes()); - self.name[name.len()] = 0; - self.offset += 256; + fn try_write(&mut self, inode: u64, type_: u8, name: &str) -> bool { + let len = ::core::mem::size_of::() + 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 } } diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index a62d576..5c31dc2 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -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); diff --git a/kernel/src/util.rs b/kernel/src/util.rs index a4ff86a..dc9ffa0 100644 --- a/kernel/src/util.rs +++ b/kernel/src/util.rs @@ -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); +}