|
|
|
@ -1,14 +1,14 @@
|
|
|
|
|
//! Syscalls for file system
|
|
|
|
|
|
|
|
|
|
use core::mem::size_of;
|
|
|
|
|
use core::cmp::min;
|
|
|
|
|
use core::cell::UnsafeCell;
|
|
|
|
|
use core::cmp::min;
|
|
|
|
|
use core::mem::size_of;
|
|
|
|
|
use rcore_fs::vfs::Timespec;
|
|
|
|
|
|
|
|
|
|
use crate::drivers::SOCKET_ACTIVITY;
|
|
|
|
|
use crate::fs::*;
|
|
|
|
|
use crate::memory::MemorySet;
|
|
|
|
|
use crate::sync::Condvar;
|
|
|
|
|
use crate::drivers::SOCKET_ACTIVITY;
|
|
|
|
|
|
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
|
@ -19,11 +19,10 @@ pub fn sys_read(fd: usize, base: *mut u8, len: usize) -> SysResult {
|
|
|
|
|
info!("read: fd: {}, base: {:?}, len: {:#x}", fd, base, len);
|
|
|
|
|
}
|
|
|
|
|
proc.vm.check_write_array(base, len)?;
|
|
|
|
|
match proc.files.get(&fd) {
|
|
|
|
|
Some(FileLike::File(_)) => sys_read_file(&mut proc, fd, base, len),
|
|
|
|
|
Some(FileLike::Socket(_)) => sys_read_socket(&mut proc, fd, base, len),
|
|
|
|
|
None => Err(SysError::EINVAL)
|
|
|
|
|
}
|
|
|
|
|
let slice = unsafe { slice::from_raw_parts_mut(base, len) };
|
|
|
|
|
let file_like = proc.get_file_like(fd)?;
|
|
|
|
|
let len = file_like.read(slice)?;
|
|
|
|
|
Ok(len)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn sys_write(fd: usize, base: *const u8, len: usize) -> SysResult {
|
|
|
|
@ -33,16 +32,17 @@ pub fn sys_write(fd: usize, base: *const u8, len: usize) -> SysResult {
|
|
|
|
|
info!("write: fd: {}, base: {:?}, len: {:#x}", fd, base, len);
|
|
|
|
|
}
|
|
|
|
|
proc.vm.check_read_array(base, len)?;
|
|
|
|
|
|
|
|
|
|
match proc.files.get(&fd) {
|
|
|
|
|
Some(FileLike::File(_)) => sys_write_file(&mut proc, fd, base, len),
|
|
|
|
|
Some(FileLike::Socket(_)) => sys_write_socket(&mut proc, fd, base, len),
|
|
|
|
|
None => Err(SysError::EINVAL)
|
|
|
|
|
}
|
|
|
|
|
let slice = unsafe { slice::from_raw_parts(base, len) };
|
|
|
|
|
let file_like = proc.get_file_like(fd)?;
|
|
|
|
|
let len = file_like.write(slice)?;
|
|
|
|
|
Ok(len)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn sys_pread(fd: usize, base: *mut u8, len: usize, offset: usize) -> SysResult {
|
|
|
|
|
info!("pread: fd: {}, base: {:?}, len: {}, offset: {}", fd, base, len, offset);
|
|
|
|
|
info!(
|
|
|
|
|
"pread: fd: {}, base: {:?}, len: {}, offset: {}",
|
|
|
|
|
fd, base, len, offset
|
|
|
|
|
);
|
|
|
|
|
let mut proc = process();
|
|
|
|
|
proc.vm.check_write_array(base, len)?;
|
|
|
|
|
|
|
|
|
@ -52,7 +52,10 @@ pub fn sys_pread(fd: usize, base: *mut u8, len: usize, offset: usize) -> SysResu
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn sys_pwrite(fd: usize, base: *const u8, len: usize, offset: usize) -> SysResult {
|
|
|
|
|
info!("pwrite: fd: {}, base: {:?}, len: {}, offset: {}", fd, base, len, offset);
|
|
|
|
|
info!(
|
|
|
|
|
"pwrite: fd: {}, base: {:?}, len: {}, offset: {}",
|
|
|
|
|
fd, base, len, offset
|
|
|
|
|
);
|
|
|
|
|
let mut proc = process();
|
|
|
|
|
proc.vm.check_read_array(base, len)?;
|
|
|
|
|
|
|
|
|
@ -61,20 +64,11 @@ pub fn sys_pwrite(fd: usize, base: *const u8, len: usize, offset: usize) -> SysR
|
|
|
|
|
Ok(len)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn sys_read_file(proc: &mut Process, fd: usize, base: *mut u8, len: usize) -> SysResult {
|
|
|
|
|
let slice = unsafe { slice::from_raw_parts_mut(base, len) };
|
|
|
|
|
let len = proc.get_file(fd)?.read(slice)?;
|
|
|
|
|
Ok(len)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn sys_write_file(proc: &mut Process, fd: usize, base: *const u8, len: usize) -> SysResult {
|
|
|
|
|
let slice = unsafe { slice::from_raw_parts(base, len) };
|
|
|
|
|
let len = proc.get_file(fd)?.write(slice)?;
|
|
|
|
|
Ok(len)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn sys_poll(ufds: *mut PollFd, nfds: usize, timeout_msecs: usize) -> SysResult {
|
|
|
|
|
info!("poll: ufds: {:?}, nfds: {}, timeout_msecs: {:#x}", ufds, nfds, timeout_msecs);
|
|
|
|
|
info!(
|
|
|
|
|
"poll: ufds: {:?}, nfds: {}, timeout_msecs: {:#x}",
|
|
|
|
|
ufds, nfds, timeout_msecs
|
|
|
|
|
);
|
|
|
|
|
let proc = process();
|
|
|
|
|
proc.vm.check_write_array(ufds, nfds)?;
|
|
|
|
|
|
|
|
|
@ -100,9 +94,9 @@ pub fn sys_poll(ufds: *mut PollFd, nfds: usize, timeout_msecs: usize) -> SysResu
|
|
|
|
|
poll.revents = poll.revents | PE::IN;
|
|
|
|
|
events = events + 1;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
Some(FileLike::Socket(wrapper)) => {
|
|
|
|
|
let (input, output, err) = poll_socket(&wrapper);
|
|
|
|
|
}
|
|
|
|
|
Some(FileLike::Socket(socket)) => {
|
|
|
|
|
let (input, output, err) = socket.poll();
|
|
|
|
|
if err {
|
|
|
|
|
poll.revents = poll.revents | PE::HUP;
|
|
|
|
|
events = events + 1;
|
|
|
|
@ -137,67 +131,17 @@ pub fn sys_poll(ufds: *mut PollFd, nfds: usize, timeout_msecs: usize) -> SysResu
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const FD_PER_ITEM: usize = 8 * size_of::<u32>();
|
|
|
|
|
const MAX_FDSET_SIZE: usize = 1024 / FD_PER_ITEM;
|
|
|
|
|
|
|
|
|
|
struct FdSet {
|
|
|
|
|
addr: *mut u32,
|
|
|
|
|
pub fn sys_select(
|
|
|
|
|
nfds: usize,
|
|
|
|
|
saved: [u32; MAX_FDSET_SIZE]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl FdSet {
|
|
|
|
|
/// Initialize a `FdSet` from pointer and number of fds
|
|
|
|
|
/// Check if the array is large enough
|
|
|
|
|
fn new(vm: &MemorySet, addr: *mut u32, nfds: usize) -> Result<FdSet, SysError> {
|
|
|
|
|
let mut saved = [0u32; MAX_FDSET_SIZE];
|
|
|
|
|
if addr as usize != 0 {
|
|
|
|
|
let len = (nfds + FD_PER_ITEM - 1) / FD_PER_ITEM;
|
|
|
|
|
vm.check_write_array(addr, len)?;
|
|
|
|
|
if len > MAX_FDSET_SIZE {
|
|
|
|
|
return Err(SysError::EINVAL);
|
|
|
|
|
}
|
|
|
|
|
let slice = unsafe {slice::from_raw_parts_mut(addr, len)};
|
|
|
|
|
|
|
|
|
|
// save the fdset, and clear it
|
|
|
|
|
for i in 0..len {
|
|
|
|
|
saved[i] = slice[i];
|
|
|
|
|
slice[i] = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(FdSet {
|
|
|
|
|
addr,
|
|
|
|
|
nfds,
|
|
|
|
|
saved
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Try to set fd in `FdSet`
|
|
|
|
|
/// Return true when `FdSet` is valid, and false when `FdSet` is bad (i.e. null pointer)
|
|
|
|
|
/// Fd should be less than nfds
|
|
|
|
|
fn set(&mut self, fd: usize) -> bool {
|
|
|
|
|
if self.addr as usize != 0 {
|
|
|
|
|
assert!(fd < self.nfds);
|
|
|
|
|
unsafe {
|
|
|
|
|
*self.addr.add(fd / 8 / size_of::<u32>()) |= 1 << (fd % (8 * size_of::<u32>()));
|
|
|
|
|
}
|
|
|
|
|
true
|
|
|
|
|
} else {
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Check to see fd is see in original `FdSet`
|
|
|
|
|
/// Fd should be less than nfds
|
|
|
|
|
fn is_set(&mut self, fd: usize) -> bool {
|
|
|
|
|
assert!(fd < self.nfds);
|
|
|
|
|
self.saved[fd / 8 / size_of::<u32>()] & (1 << (fd % (8 * size_of::<u32>()))) != 0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn sys_select(nfds: usize, read: *mut u32, write: *mut u32, err: *mut u32, timeout: *const TimeVal) -> SysResult {
|
|
|
|
|
info!("select: nfds: {}, read: {:?}, write: {:?}, err: {:?}, timeout: {:?}", nfds, read, write, err, timeout);
|
|
|
|
|
read: *mut u32,
|
|
|
|
|
write: *mut u32,
|
|
|
|
|
err: *mut u32,
|
|
|
|
|
timeout: *const TimeVal,
|
|
|
|
|
) -> SysResult {
|
|
|
|
|
info!(
|
|
|
|
|
"select: nfds: {}, read: {:?}, write: {:?}, err: {:?}, timeout: {:?}",
|
|
|
|
|
nfds, read, write, err, timeout
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let proc = process();
|
|
|
|
|
let mut read_fds = FdSet::new(&proc.vm, read, nfds)?;
|
|
|
|
@ -216,29 +160,29 @@ pub fn sys_select(nfds: usize, read: *mut u32, write: *mut u32, err: *mut u32, t
|
|
|
|
|
loop {
|
|
|
|
|
let proc = process();
|
|
|
|
|
let mut events = 0;
|
|
|
|
|
for (fd, file) in proc.files.iter() {
|
|
|
|
|
for (fd, file_like) in proc.files.iter() {
|
|
|
|
|
if *fd < nfds {
|
|
|
|
|
match file {
|
|
|
|
|
match file_like {
|
|
|
|
|
FileLike::File(_) => {
|
|
|
|
|
// FIXME: assume it is stdin for now
|
|
|
|
|
if STDIN.can_read() {
|
|
|
|
|
if read_fds.is_set(*fd){
|
|
|
|
|
if read_fds.is_set(*fd) {
|
|
|
|
|
read_fds.set(*fd);
|
|
|
|
|
events = events + 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
FileLike::Socket(wrapper) => {
|
|
|
|
|
let (input, output, err) = poll_socket(&wrapper);
|
|
|
|
|
if err && err_fds.is_set(*fd){
|
|
|
|
|
}
|
|
|
|
|
FileLike::Socket(socket) => {
|
|
|
|
|
let (input, output, err) = socket.poll();
|
|
|
|
|
if err && err_fds.is_set(*fd) {
|
|
|
|
|
err_fds.set(*fd);
|
|
|
|
|
events = events + 1;
|
|
|
|
|
}
|
|
|
|
|
if input && read_fds.is_set(*fd){
|
|
|
|
|
if input && read_fds.is_set(*fd) {
|
|
|
|
|
read_fds.set(*fd);
|
|
|
|
|
events = events + 1;
|
|
|
|
|
}
|
|
|
|
|
if output && write_fds.is_set(*fd){
|
|
|
|
|
if output && write_fds.is_set(*fd) {
|
|
|
|
|
write_fds.set(*fd);
|
|
|
|
|
events = events + 1;
|
|
|
|
|
}
|
|
|
|
@ -268,37 +212,38 @@ pub fn sys_select(nfds: usize, read: *mut u32, write: *mut u32, err: *mut u32, t
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn sys_readv(fd: usize, iov_ptr: *const IoVec, iov_count: usize) -> SysResult {
|
|
|
|
|
info!("readv: fd: {}, iov: {:?}, count: {}", fd, iov_ptr, iov_count);
|
|
|
|
|
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.vm, true)?;
|
|
|
|
|
|
|
|
|
|
// read all data to a buf
|
|
|
|
|
let mut file = proc.get_file(fd)?.clone();
|
|
|
|
|
drop(proc);
|
|
|
|
|
let file_like = proc.get_file_like(fd)?;
|
|
|
|
|
let mut buf = iovs.new_buf(true);
|
|
|
|
|
let len = file.read(buf.as_mut_slice())?;
|
|
|
|
|
let len = file_like.read(buf.as_mut_slice())?;
|
|
|
|
|
// copy data to user
|
|
|
|
|
iovs.write_all_from_slice(&buf[..len]);
|
|
|
|
|
Ok(len)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn sys_writev(fd: usize, iov_ptr: *const IoVec, iov_count: usize) -> SysResult {
|
|
|
|
|
info!("writev: fd: {}, iov: {:?}, count: {}", fd, iov_ptr, iov_count);
|
|
|
|
|
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.vm, false)?;
|
|
|
|
|
|
|
|
|
|
let buf = iovs.read_all_to_vec();
|
|
|
|
|
let len = buf.len();
|
|
|
|
|
|
|
|
|
|
match proc.files.get(&fd) {
|
|
|
|
|
Some(FileLike::File(_)) => sys_write_file(&mut proc, fd, buf.as_ptr(), len),
|
|
|
|
|
Some(FileLike::Socket(_)) => sys_write_socket(&mut proc, fd, buf.as_ptr(), len),
|
|
|
|
|
None => Err(SysError::EINVAL)
|
|
|
|
|
}
|
|
|
|
|
let file_like = proc.get_file_like(fd)?;
|
|
|
|
|
let len = file_like.write(buf.as_slice())?;
|
|
|
|
|
Ok(len)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const AT_FDCWD: usize = -100isize as usize;
|
|
|
|
|
|
|
|
|
|
pub fn sys_open(path: *const u8, flags: usize, mode: usize) -> SysResult {
|
|
|
|
|
sys_openat(AT_FDCWD, path, flags, mode)
|
|
|
|
|
}
|
|
|
|
@ -307,10 +252,12 @@ pub fn sys_openat(dir_fd: usize, path: *const u8, flags: usize, mode: usize) ->
|
|
|
|
|
let mut proc = process();
|
|
|
|
|
let path = unsafe { proc.vm.check_and_clone_cstr(path)? };
|
|
|
|
|
let flags = OpenFlags::from_bits_truncate(flags);
|
|
|
|
|
info!("openat: dir_fd: {}, path: {:?}, flags: {:?}, mode: {:#o}", dir_fd as isize, path, flags, mode);
|
|
|
|
|
info!(
|
|
|
|
|
"openat: dir_fd: {}, path: {:?}, flags: {:?}, mode: {:#o}",
|
|
|
|
|
dir_fd as isize, path, flags, mode
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let inode =
|
|
|
|
|
if dir_fd == AT_FDCWD {
|
|
|
|
|
let inode = if dir_fd == AT_FDCWD {
|
|
|
|
|
// from process cwd
|
|
|
|
|
if flags.contains(OpenFlags::CREATE) {
|
|
|
|
|
let (dir_path, file_name) = split_path(&path);
|
|
|
|
@ -322,7 +269,7 @@ pub fn sys_openat(dir_fd: usize, path: *const u8, flags: usize, mode: usize) ->
|
|
|
|
|
return Err(SysError::EEXIST);
|
|
|
|
|
}
|
|
|
|
|
file_inode
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
Err(FsError::EntryNotFound) => {
|
|
|
|
|
dir_inode.create(file_name, FileType::File, mode as u32)?
|
|
|
|
|
}
|
|
|
|
@ -344,7 +291,7 @@ pub fn sys_openat(dir_fd: usize, path: *const u8, flags: usize, mode: usize) ->
|
|
|
|
|
return Err(SysError::EEXIST);
|
|
|
|
|
}
|
|
|
|
|
file_inode
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
Err(FsError::EntryNotFound) => {
|
|
|
|
|
dir_inode.create(file_name, FileType::File, mode as u32)?
|
|
|
|
|
}
|
|
|
|
@ -391,9 +338,7 @@ pub fn sys_getcwd(buf: *mut u8, len: usize) -> SysResult {
|
|
|
|
|
if proc.cwd.len() + 1 > len {
|
|
|
|
|
return Err(SysError::ERANGE);
|
|
|
|
|
}
|
|
|
|
|
unsafe {
|
|
|
|
|
util::write_cstr(buf, &proc.cwd)
|
|
|
|
|
}
|
|
|
|
|
unsafe { util::write_cstr(buf, &proc.cwd) }
|
|
|
|
|
Ok(buf as usize)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -409,7 +354,9 @@ pub fn sys_fstat(fd: usize, stat_ptr: *mut Stat) -> SysResult {
|
|
|
|
|
let file = proc.get_file(fd)?;
|
|
|
|
|
let stat = Stat::from(file.metadata()?);
|
|
|
|
|
// TODO: handle symlink
|
|
|
|
|
unsafe { stat_ptr.write(stat); }
|
|
|
|
|
unsafe {
|
|
|
|
|
stat_ptr.write(stat);
|
|
|
|
|
}
|
|
|
|
|
Ok(0)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -421,7 +368,9 @@ pub fn sys_lstat(path: *const u8, stat_ptr: *mut Stat) -> SysResult {
|
|
|
|
|
|
|
|
|
|
let inode = proc.lookup_inode(&path)?;
|
|
|
|
|
let stat = Stat::from(inode.metadata()?);
|
|
|
|
|
unsafe { stat_ptr.write(stat); }
|
|
|
|
|
unsafe {
|
|
|
|
|
stat_ptr.write(stat);
|
|
|
|
|
}
|
|
|
|
|
Ok(0)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -484,7 +433,10 @@ pub fn sys_ftruncate(fd: usize, len: usize) -> SysResult {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn sys_getdents64(fd: usize, buf: *mut LinuxDirent64, buf_size: usize) -> SysResult {
|
|
|
|
|
info!("getdents64: fd: {}, ptr: {:?}, buf_size: {}", fd, buf, buf_size);
|
|
|
|
|
info!(
|
|
|
|
|
"getdents64: fd: {}, ptr: {:?}, buf_size: {}",
|
|
|
|
|
fd, buf, buf_size
|
|
|
|
|
);
|
|
|
|
|
let mut proc = process();
|
|
|
|
|
proc.vm.check_write_array(buf as *mut u8, buf_size)?;
|
|
|
|
|
let file = proc.get_file(fd)?;
|
|
|
|
@ -500,7 +452,9 @@ pub fn sys_getdents64(fd: usize, buf: *mut LinuxDirent64, buf_size: usize) -> Sy
|
|
|
|
|
}?;
|
|
|
|
|
// TODO: get ino from dirent
|
|
|
|
|
let ok = writer.try_write(0, DirentType::from_type(&info.type_).bits(), &name);
|
|
|
|
|
if !ok { break; }
|
|
|
|
|
if !ok {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Ok(writer.written_size)
|
|
|
|
|
}
|
|
|
|
@ -511,18 +465,9 @@ pub fn sys_dup2(fd1: usize, fd2: usize) -> SysResult {
|
|
|
|
|
// close fd2 first if it is opened
|
|
|
|
|
proc.files.remove(&fd2);
|
|
|
|
|
|
|
|
|
|
match proc.files.get(&fd1) {
|
|
|
|
|
Some(FileLike::File(file)) => {
|
|
|
|
|
let new_file = FileLike::File(file.clone());
|
|
|
|
|
proc.files.insert(fd2, new_file);
|
|
|
|
|
let file_like = proc.get_file_like(fd1)?.clone();
|
|
|
|
|
proc.files.insert(fd2, file_like);
|
|
|
|
|
Ok(fd2)
|
|
|
|
|
},
|
|
|
|
|
Some(FileLike::Socket(wrapper)) => {
|
|
|
|
|
let new_wrapper = wrapper.clone();
|
|
|
|
|
sys_dup2_socket(&mut proc, new_wrapper, fd2)
|
|
|
|
|
},
|
|
|
|
|
None => Err(SysError::EINVAL)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn sys_chdir(path: *const u8) -> SysResult {
|
|
|
|
@ -553,23 +498,33 @@ pub fn sys_rename(oldpath: *const u8, newpath: *const u8) -> SysResult {
|
|
|
|
|
sys_renameat(AT_FDCWD, oldpath, AT_FDCWD, newpath)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn sys_renameat(olddirfd: usize, oldpath: *const u8, newdirfd: usize, newpath: *const u8) -> SysResult {
|
|
|
|
|
pub fn sys_renameat(
|
|
|
|
|
olddirfd: usize,
|
|
|
|
|
oldpath: *const u8,
|
|
|
|
|
newdirfd: usize,
|
|
|
|
|
newpath: *const u8,
|
|
|
|
|
) -> SysResult {
|
|
|
|
|
let mut proc = process();
|
|
|
|
|
let oldpath = unsafe { proc.vm.check_and_clone_cstr(oldpath)? };
|
|
|
|
|
let newpath = unsafe { proc.vm.check_and_clone_cstr(newpath)? };
|
|
|
|
|
info!("renameat: olddirfd: {}, oldpath: {:?}, newdirfd: {}, newpath: {:?}", olddirfd, oldpath, newdirfd, newpath);
|
|
|
|
|
info!(
|
|
|
|
|
"renameat: olddirfd: {}, oldpath: {:?}, newdirfd: {}, newpath: {:?}",
|
|
|
|
|
olddirfd, oldpath, newdirfd, newpath
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let (old_dir_path, old_file_name) = split_path(&oldpath);
|
|
|
|
|
let (new_dir_path, new_file_name) = split_path(&newpath);
|
|
|
|
|
let old_dir_inode = if olddirfd == AT_FDCWD {
|
|
|
|
|
proc.lookup_inode(old_dir_path)?
|
|
|
|
|
} else {
|
|
|
|
|
proc.get_file(olddirfd)?.lookup_follow(old_dir_path, FOLLOW_MAX_DEPTH)?
|
|
|
|
|
proc.get_file(olddirfd)?
|
|
|
|
|
.lookup_follow(old_dir_path, FOLLOW_MAX_DEPTH)?
|
|
|
|
|
};
|
|
|
|
|
let new_dir_inode = if newdirfd == AT_FDCWD {
|
|
|
|
|
proc.lookup_inode(new_dir_path)?
|
|
|
|
|
} else {
|
|
|
|
|
proc.get_file(newdirfd)?.lookup_follow(new_dir_path, FOLLOW_MAX_DEPTH)?
|
|
|
|
|
proc.get_file(newdirfd)?
|
|
|
|
|
.lookup_follow(new_dir_path, FOLLOW_MAX_DEPTH)?
|
|
|
|
|
};
|
|
|
|
|
old_dir_inode.move_(old_file_name, &new_dir_inode, new_file_name)?;
|
|
|
|
|
Ok(0)
|
|
|
|
@ -641,10 +596,30 @@ pub fn sys_pipe(fds: *mut u32) -> SysResult {
|
|
|
|
|
let (read, write) = Pipe::create_pair();
|
|
|
|
|
|
|
|
|
|
let read_fd = proc.get_free_fd();
|
|
|
|
|
proc.files.insert(read_fd, FileLike::File(FileHandle::new(Arc::new(read), OpenOptions { read: true, write: false, append: false })));
|
|
|
|
|
proc.files.insert(
|
|
|
|
|
read_fd,
|
|
|
|
|
FileLike::File(FileHandle::new(
|
|
|
|
|
Arc::new(read),
|
|
|
|
|
OpenOptions {
|
|
|
|
|
read: true,
|
|
|
|
|
write: false,
|
|
|
|
|
append: false,
|
|
|
|
|
},
|
|
|
|
|
)),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
let write_fd = proc.get_free_fd();
|
|
|
|
|
proc.files.insert(write_fd, FileLike::File(FileHandle::new(Arc::new(write), OpenOptions { read: false, write: true, append: false })));
|
|
|
|
|
proc.files.insert(
|
|
|
|
|
write_fd,
|
|
|
|
|
FileLike::File(FileHandle::new(
|
|
|
|
|
Arc::new(write),
|
|
|
|
|
OpenOptions {
|
|
|
|
|
read: false,
|
|
|
|
|
write: true,
|
|
|
|
|
append: false,
|
|
|
|
|
},
|
|
|
|
|
)),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
|
*fds = read_fd as u32;
|
|
|
|
@ -662,12 +637,15 @@ pub fn sys_sync() -> SysResult {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn sys_sendfile(out_fd: usize, in_fd: usize, offset: *mut usize, count: usize) -> SysResult {
|
|
|
|
|
info!("sendfile: out: {}, in: {}, offset: {:?}, count: {}", out_fd, in_fd, offset, count);
|
|
|
|
|
info!(
|
|
|
|
|
"sendfile: out: {}, in: {}, offset: {:?}, count: {}",
|
|
|
|
|
out_fd, in_fd, offset, count
|
|
|
|
|
);
|
|
|
|
|
let proc = process();
|
|
|
|
|
// We know it's save, pacify the borrow checker
|
|
|
|
|
let proc_cell = UnsafeCell::new(proc);
|
|
|
|
|
let proc_in = unsafe {&mut *proc_cell.get()};
|
|
|
|
|
let proc_out = unsafe {&mut *proc_cell.get()};
|
|
|
|
|
let proc_in = unsafe { &mut *proc_cell.get() };
|
|
|
|
|
let proc_out = unsafe { &mut *proc_cell.get() };
|
|
|
|
|
//let in_file: &mut FileHandle = unsafe { &mut *UnsafeCell::new(proc.get_file(in_fd)?).get() };
|
|
|
|
|
//let out_file: &mut FileHandle = unsafe { &mut *UnsafeCell::new(proc.get_file(out_fd)?).get() };
|
|
|
|
|
let in_file = proc_in.get_file(in_fd)?;
|
|
|
|
@ -694,11 +672,9 @@ pub fn sys_sendfile(out_fd: usize, in_fd: usize, offset: *mut usize, count: usiz
|
|
|
|
|
}
|
|
|
|
|
return Ok(bytes_read);
|
|
|
|
|
} else {
|
|
|
|
|
let proc_mem = unsafe {&mut *proc_cell.get()};
|
|
|
|
|
let proc_mem = unsafe { &mut *proc_cell.get() };
|
|
|
|
|
proc_mem.vm.check_read_ptr(offset)?;
|
|
|
|
|
let mut read_offset = unsafe {
|
|
|
|
|
*offset
|
|
|
|
|
};
|
|
|
|
|
let mut read_offset = unsafe { *offset };
|
|
|
|
|
// read from specified offset and write new offset back
|
|
|
|
|
let mut bytes_read = 0;
|
|
|
|
|
while bytes_read < count {
|
|
|
|
@ -726,17 +702,20 @@ pub fn sys_sendfile(out_fd: usize, in_fd: usize, offset: *mut usize, count: usiz
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Process {
|
|
|
|
|
pub fn get_file_like(&mut self, fd: usize) -> Result<&mut FileLike, SysError> {
|
|
|
|
|
self.files.get_mut(&fd).ok_or(SysError::EBADF)
|
|
|
|
|
}
|
|
|
|
|
pub fn get_file(&mut self, fd: usize) -> Result<&mut FileHandle, SysError> {
|
|
|
|
|
self.files.get_mut(&fd).ok_or(SysError::EBADF).and_then(|f| {
|
|
|
|
|
match f {
|
|
|
|
|
match self.get_file_like(fd)? {
|
|
|
|
|
FileLike::File(file) => Ok(file),
|
|
|
|
|
_ => Err(SysError::EBADF)
|
|
|
|
|
_ => Err(SysError::EBADF),
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
pub fn lookup_inode(&self, path: &str) -> Result<Arc<INode>, SysError> {
|
|
|
|
|
debug!("lookup_inode: cwd {} path {}", self.cwd, path);
|
|
|
|
|
Ok(ROOT_INODE.lookup(&self.cwd)?.lookup_follow(path, FOLLOW_MAX_DEPTH)?)
|
|
|
|
|
Ok(ROOT_INODE
|
|
|
|
|
.lookup(&self.cwd)?
|
|
|
|
|
.lookup_follow(path, FOLLOW_MAX_DEPTH)?)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1059,7 +1038,7 @@ impl From<Metadata> for Stat {
|
|
|
|
|
atime: info.atime,
|
|
|
|
|
mtime: info.mtime,
|
|
|
|
|
ctime: info.ctime,
|
|
|
|
|
_pad0: 0
|
|
|
|
|
_pad0: 0,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1080,14 +1059,14 @@ impl From<Metadata> for Stat {
|
|
|
|
|
mtime: info.mtime,
|
|
|
|
|
ctime: info.ctime,
|
|
|
|
|
__pad: 0,
|
|
|
|
|
__pad2: 0
|
|
|
|
|
__pad2: 0,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const SEEK_SET: u8 = 1;
|
|
|
|
|
const SEEK_CUR: u8 = 2;
|
|
|
|
|
const SEEK_END: u8 = 4;
|
|
|
|
|
const SEEK_SET: u8 = 0;
|
|
|
|
|
const SEEK_CUR: u8 = 1;
|
|
|
|
|
const SEEK_END: u8 = 2;
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Copy, Clone)]
|
|
|
|
|
#[repr(C)]
|
|
|
|
@ -1103,7 +1082,12 @@ pub struct IoVec {
|
|
|
|
|
struct IoVecs(Vec<&'static mut [u8]>);
|
|
|
|
|
|
|
|
|
|
impl IoVecs {
|
|
|
|
|
fn check_and_new(iov_ptr: *const IoVec, iov_count: usize, vm: &MemorySet, readv: bool) -> Result<Self, SysError> {
|
|
|
|
|
fn check_and_new(
|
|
|
|
|
iov_ptr: *const IoVec,
|
|
|
|
|
iov_count: usize,
|
|
|
|
|
vm: &MemorySet,
|
|
|
|
|
readv: bool,
|
|
|
|
|
) -> Result<Self, SysError> {
|
|
|
|
|
vm.check_read_array(iov_ptr, iov_count)?;
|
|
|
|
|
let iovs = unsafe { slice::from_raw_parts(iov_ptr, iov_count) }.to_vec();
|
|
|
|
|
// check all bufs in iov
|
|
|
|
@ -1117,7 +1101,10 @@ impl IoVecs {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
let slices = iovs.iter().map(|iov| unsafe { slice::from_raw_parts_mut(iov.base, iov.len as usize) }).collect();
|
|
|
|
|
let slices = iovs
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|iov| unsafe { slice::from_raw_parts_mut(iov.base, iov.len as usize) })
|
|
|
|
|
.collect();
|
|
|
|
|
Ok(IoVecs(slices))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1149,7 +1136,9 @@ impl IoVecs {
|
|
|
|
|
let total_len = self.0.iter().map(|slice| slice.len()).sum::<usize>();
|
|
|
|
|
let mut buf = Vec::with_capacity(total_len);
|
|
|
|
|
if set_len {
|
|
|
|
|
unsafe { buf.set_len(total_len); }
|
|
|
|
|
unsafe {
|
|
|
|
|
buf.set_len(total_len);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
buf
|
|
|
|
|
}
|
|
|
|
@ -1178,3 +1167,60 @@ bitflags! {
|
|
|
|
|
const INVAL = 0x0020;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const FD_PER_ITEM: usize = 8 * size_of::<u32>();
|
|
|
|
|
const MAX_FDSET_SIZE: usize = 1024 / FD_PER_ITEM;
|
|
|
|
|
|
|
|
|
|
struct FdSet {
|
|
|
|
|
addr: *mut u32,
|
|
|
|
|
nfds: usize,
|
|
|
|
|
saved: [u32; MAX_FDSET_SIZE],
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl FdSet {
|
|
|
|
|
/// Initialize a `FdSet` from pointer and number of fds
|
|
|
|
|
/// Check if the array is large enough
|
|
|
|
|
fn new(vm: &MemorySet, addr: *mut u32, nfds: usize) -> Result<FdSet, SysError> {
|
|
|
|
|
let mut saved = [0u32; MAX_FDSET_SIZE];
|
|
|
|
|
if addr as usize != 0 {
|
|
|
|
|
let len = (nfds + FD_PER_ITEM - 1) / FD_PER_ITEM;
|
|
|
|
|
vm.check_write_array(addr, len)?;
|
|
|
|
|
if len > MAX_FDSET_SIZE {
|
|
|
|
|
return Err(SysError::EINVAL);
|
|
|
|
|
}
|
|
|
|
|
let slice = unsafe { slice::from_raw_parts_mut(addr, len) };
|
|
|
|
|
|
|
|
|
|
// save the fdset, and clear it
|
|
|
|
|
for i in 0..len {
|
|
|
|
|
saved[i] = slice[i];
|
|
|
|
|
slice[i] = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(FdSet { addr, nfds, saved })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Try to set fd in `FdSet`
|
|
|
|
|
/// Return true when `FdSet` is valid, and false when `FdSet` is bad (i.e. null pointer)
|
|
|
|
|
/// Fd should be less than nfds
|
|
|
|
|
fn set(&mut self, fd: usize) -> bool {
|
|
|
|
|
if self.addr as usize != 0 {
|
|
|
|
|
assert!(fd < self.nfds);
|
|
|
|
|
unsafe {
|
|
|
|
|
*self.addr.add(fd / 8 / size_of::<u32>()) |= 1 << (fd % (8 * size_of::<u32>()));
|
|
|
|
|
}
|
|
|
|
|
true
|
|
|
|
|
} else {
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Check to see fd is see in original `FdSet`
|
|
|
|
|
/// Fd should be less than nfds
|
|
|
|
|
fn is_set(&mut self, fd: usize) -> bool {
|
|
|
|
|
assert!(fd < self.nfds);
|
|
|
|
|
self.saved[fd / 8 / size_of::<u32>()] & (1 << (fd % (8 * size_of::<u32>()))) != 0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const AT_FDCWD: usize = -100isize as usize;
|
|
|
|
|