Add fcntl
This commit is contained in:
parent
785d3237b9
commit
44ef19726f
@ -11,12 +11,6 @@ pub struct FileTable {
|
|||||||
num_fds: usize,
|
num_fds: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
struct FileTableEntry {
|
|
||||||
file: FileRef,
|
|
||||||
close_on_spawn: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FileTable {
|
impl FileTable {
|
||||||
pub fn new() -> FileTable {
|
pub fn new() -> FileTable {
|
||||||
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 {
|
pub fn put(&mut self, file: FileRef, close_on_spawn: bool) -> FileDesc {
|
||||||
let mut table = &mut self.table;
|
let mut table = &mut self.table;
|
||||||
|
|
||||||
let min_free_fd = if self.num_fds < table.len() {
|
let min_free_fd = if self.num_fds < table.len() {
|
||||||
table
|
table.iter()
|
||||||
.iter()
|
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find(|&(idx, opt)| opt.is_none())
|
.find(|&(idx, opt)| opt.is_none())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -59,13 +79,30 @@ impl FileTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, fd: FileDesc) -> Result<FileRef, Error> {
|
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() {
|
if fd as usize >= self.table.len() {
|
||||||
return errno!(EBADF, "Invalid file descriptor");
|
return errno!(EBADF, "Invalid file descriptor");
|
||||||
}
|
}
|
||||||
|
|
||||||
let table = &self.table;
|
let table = &self.table;
|
||||||
match table[fd as usize].as_ref() {
|
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"),
|
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 {
|
impl FileTableEntry {
|
||||||
fn new(file: FileRef, close_on_spawn: bool) -> FileTableEntry {
|
pub fn new(file: FileRef, close_on_spawn: bool) -> FileTableEntry {
|
||||||
FileTableEntry {
|
FileTableEntry {
|
||||||
file,
|
file,
|
||||||
close_on_spawn,
|
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! {
|
bitflags! {
|
||||||
struct OpenFlags: u32 {
|
pub struct OpenFlags: u32 {
|
||||||
/// read only
|
/// read only
|
||||||
const RDONLY = 0;
|
const RDONLY = 0;
|
||||||
/// write only
|
/// 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.copy_from(s.as_ptr(), s.len());
|
||||||
ptr.add(s.len()).write(0);
|
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, 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 prelude::*;
|
||||||
use process::{ChildProcessFilter, FileAction, pid_t, CloneFlags, FutexFlags, FutexOp};
|
use process::{ChildProcessFilter, FileAction, pid_t, CloneFlags, FutexFlags, FutexOp};
|
||||||
use std::ffi::{CStr, CString};
|
use std::ffi::{CStr, CString};
|
||||||
@ -72,6 +72,7 @@ pub extern "C" fn dispatch_syscall(
|
|||||||
SYS_RMDIR => do_rmdir(arg0 as *const i8),
|
SYS_RMDIR => do_rmdir(arg0 as *const i8),
|
||||||
SYS_LINK => do_link(arg0 as *const i8, arg1 as *const i8),
|
SYS_LINK => do_link(arg0 as *const i8, arg1 as *const i8),
|
||||||
SYS_UNLINK => do_unlink(arg0 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_EXIT => do_exit(arg0 as i32),
|
||||||
SYS_SPAWN => do_spawn(
|
SYS_SPAWN => do_spawn(
|
||||||
@ -726,6 +727,11 @@ fn do_unlink(path: *const i8) -> Result<isize, Error> {
|
|||||||
Ok(0)
|
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> {
|
fn do_arch_prctl(code: u32, addr: *mut usize) -> Result<isize, Error> {
|
||||||
let code = process::ArchPrctlCode::from_u32(code)?;
|
let code = process::ArchPrctlCode::from_u32(code)?;
|
||||||
check_mut_ptr(addr)?;
|
check_mut_ptr(addr)?;
|
||||||
|
Loading…
Reference in New Issue
Block a user