Add fcntl

This commit is contained in:
Tate, Hongliang Tian 2019-04-10 14:45:51 +08:00 committed by Tate Tian
parent 785d3237b9
commit 44ef19726f
3 changed files with 158 additions and 12 deletions

@ -11,12 +11,6 @@ pub struct FileTable {
num_fds: usize,
}
#[derive(Debug, Clone)]
struct FileTableEntry {
file: FileRef,
close_on_spawn: bool,
}
impl FileTable {
pub fn new() -> FileTable {
FileTable {
@ -25,12 +19,38 @@ impl FileTable {
}
}
pub fn dup(&mut self, fd: FileDesc, min_fd: FileDesc, close_on_spawn: bool) -> Result<FileDesc, Error> {
let file_ref = self.get(fd)?;
let min_fd = min_fd as usize;
let min_free_fd = {
let mut table = &mut self.table;
// Make sure that min_fd does not exceed the capacity of the table
if min_fd >= table.len() {
let expand_size = min_fd - table.len() + 1;
for _ in 0..expand_size {
table.push(None)
}
}
table.iter()
.enumerate()
.skip(min_fd as usize)
.find(|&(idx, opt)| opt.is_none())
.unwrap().0
} as FileDesc;
self.put_at(min_free_fd, file_ref, close_on_spawn);
Ok(min_free_fd)
}
pub fn put(&mut self, file: FileRef, close_on_spawn: bool) -> FileDesc {
let mut table = &mut self.table;
let min_free_fd = if self.num_fds < table.len() {
table
.iter()
table.iter()
.enumerate()
.find(|&(idx, opt)| opt.is_none())
.unwrap()
@ -59,13 +79,30 @@ impl FileTable {
}
pub fn get(&self, fd: FileDesc) -> Result<FileRef, Error> {
let entry = self.get_entry(fd)?;
Ok(entry.file.clone())
}
pub fn get_entry(&self, fd: FileDesc) -> Result<&FileTableEntry, Error> {
if fd as usize >= self.table.len() {
return errno!(EBADF, "Invalid file descriptor");
}
let table = &self.table;
match table[fd as usize].as_ref() {
Some(table_entry) => Ok(table_entry.file.clone()),
Some(table_entry) => Ok(table_entry),
None => errno!(EBADF, "Invalid file descriptor"),
}
}
pub fn get_entry_mut(&mut self, fd: FileDesc) -> Result<&mut FileTableEntry, Error> {
if fd as usize >= self.table.len() {
return errno!(EBADF, "Invalid file descriptor");
}
let table = &mut self.table;
match table[fd as usize].as_mut() {
Some(table_entry) => Ok(table_entry),
None => errno!(EBADF, "Invalid file descriptor"),
}
}
@ -114,11 +151,33 @@ impl Clone for FileTable {
}
}
#[derive(Debug, Clone)]
pub struct FileTableEntry {
file: FileRef,
close_on_spawn: bool,
}
impl FileTableEntry {
fn new(file: FileRef, close_on_spawn: bool) -> FileTableEntry {
pub fn new(file: FileRef, close_on_spawn: bool) -> FileTableEntry {
FileTableEntry {
file,
close_on_spawn,
}
}
pub fn get_file(&self) -> &FileRef {
&self.file
}
pub fn is_close_on_spawn(&self) -> bool {
self.close_on_spawn
}
pub fn get_file_mut(&mut self) -> &mut FileRef {
&mut self.file
}
pub fn set_close_on_spawn(&mut self, close_on_spawn: bool) {
self.close_on_spawn = close_on_spawn;
}
}

@ -390,7 +390,7 @@ fn split_path(path: &str) -> (&str, &str) {
}
bitflags! {
struct OpenFlags: u32 {
pub struct OpenFlags: u32 {
/// read only
const RDONLY = 0;
/// write only
@ -614,3 +614,84 @@ pub unsafe fn write_cstr(ptr: *mut u8, s: &str) {
ptr.copy_from(s.as_ptr(), s.len());
ptr.add(s.len()).write(0);
}
#[derive(Debug)]
pub enum FcntlCmd {
/// Duplicate the file descriptor fd using the lowest-numbered available
/// file descriptor greater than or equal to arg.
DupFd(FileDesc),
/// As for `DupFd`, but additionally set the close-on-exec flag for the
/// duplicate file descriptor.
DupFdCloexec(FileDesc),
/// Return (as the function result) the file descriptor flags
GetFd(),
/// Set the file descriptor to be close-on-exec or not
SetFd(u32),
/// Get the file status flags
GetFl(),
/// Set the file status flags
SetFl(OpenFlags),
}
pub const F_DUPFD : u32 = 0;
pub const F_GETFD : u32 = 1;
pub const F_SETFD : u32 = 2;
pub const F_GETFL : u32 = 3;
pub const F_SETFL : u32 = 4;
pub const F_DUPFD_CLOEXEC : u32 = 1030;
pub const FD_CLOEXEC : u32 = 1;
impl FcntlCmd {
#[deny(unreachable_patterns)]
pub fn from_raw(cmd: u32, arg: u64) -> Result<FcntlCmd, Error> {
Ok(match cmd {
F_DUPFD => FcntlCmd::DupFd(arg as FileDesc),
F_DUPFD_CLOEXEC => FcntlCmd::DupFdCloexec(arg as FileDesc),
F_GETFD => FcntlCmd::GetFd(),
F_SETFD => FcntlCmd::SetFd(arg as u32),
F_GETFL => FcntlCmd::GetFl(),
F_SETFL => FcntlCmd::SetFl(OpenFlags::from_bits_truncate(arg as u32)),
_ => return errno!(EINVAL, "invalid command"),
})
}
}
pub fn do_fcntl(fd: FileDesc, cmd: &FcntlCmd) -> Result<isize, Error> {
info!("do_fcntl: {:?}, {:?}", &fd, cmd);
let current_ref = process::get_current();
let mut current = current_ref.lock().unwrap();
let files_ref = current.get_files();
let mut files = files_ref.lock().unwrap();
Ok(match cmd {
FcntlCmd::DupFd(min_fd) => {
let dup_fd = files.dup(fd, *min_fd, false)?;
dup_fd as isize
},
FcntlCmd::DupFdCloexec(min_fd) => {
let dup_fd = files.dup(fd, *min_fd, true)?;
dup_fd as isize
},
FcntlCmd::GetFd() => {
let entry = files.get_entry(fd)?;
let fd_flags = if entry.is_close_on_spawn() {
FD_CLOEXEC
} else {
0
};
fd_flags as isize
},
FcntlCmd::SetFd(fd_flags) => {
let entry = files.get_entry_mut(fd)?;
entry.set_close_on_spawn((fd_flags & FD_CLOEXEC) != 0);
0
},
FcntlCmd::GetFl() => {
unimplemented!();
},
FcntlCmd::SetFl(flags) => {
unimplemented!();
},
})
}

@ -1,5 +1,5 @@
use {fs, process, std, vm};
use fs::{File, FileDesc, off_t, AccessModes, AccessFlags, AT_FDCWD};
use fs::{File, FileDesc, off_t, AccessModes, AccessFlags, AT_FDCWD, FcntlCmd};
use prelude::*;
use process::{ChildProcessFilter, FileAction, pid_t, CloneFlags, FutexFlags, FutexOp};
use std::ffi::{CStr, CString};
@ -72,6 +72,7 @@ pub extern "C" fn dispatch_syscall(
SYS_RMDIR => do_rmdir(arg0 as *const i8),
SYS_LINK => do_link(arg0 as *const i8, arg1 as *const i8),
SYS_UNLINK => do_unlink(arg0 as *const i8),
SYS_FCNTL => do_fcntl(arg0 as FileDesc, arg1 as u32, arg2 as u64),
SYS_EXIT => do_exit(arg0 as i32),
SYS_SPAWN => do_spawn(
@ -726,6 +727,11 @@ fn do_unlink(path: *const i8) -> Result<isize, Error> {
Ok(0)
}
fn do_fcntl(fd: FileDesc, cmd: u32, arg: u64) -> Result<isize, Error> {
let cmd = FcntlCmd::from_raw(cmd, arg)?;
fs::do_fcntl(fd, &cmd)
}
fn do_arch_prctl(code: u32, addr: *mut usize) -> Result<isize, Error> {
let code = process::ArchPrctlCode::from_u32(code)?;
check_mut_ptr(addr)?;