Files
RustPython/vm/src/stdlib/os.rs
2019-02-09 12:03:08 +01:00

109 lines
3.5 KiB
Rust

//library imports
use std::fs::File;
use std::fs::OpenOptions;
use std::io::ErrorKind;
//3rd party imports
use num_traits::cast::ToPrimitive;
//custom imports
use super::super::obj::objint;
use super::super::obj::objstr;
use super::super::obj::objtype;
use super::super::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol};
use super::super::vm::VirtualMachine;
#[cfg(target_family = "unix")]
pub fn raw_file_number(handle: File) -> i64 {
use std::os::unix::io::IntoRawFd;
handle.into_raw_fd() as i64
}
#[cfg(target_family = "unix")]
pub fn rust_file(raw_fileno: i64) -> File {
use std::os::unix::io::FromRawFd;
unsafe { File::from_raw_fd(raw_fileno as i32) }
}
#[cfg(target_family = "windows")]
pub fn raw_file_number(handle: File) -> i64 {
use std::os::windows::io::IntoRawHandle;
handle.into_raw_handle() as i64
}
#[cfg(target_family = "windows")]
pub fn rust_file(raw_fileno: i64) -> File {
use std::ffi::c_void;
use std::os::windows::io::FromRawHandle;
//TODO: This is untested and (very) unsafe handling or
//raw pointers - This should be patched urgently by
//comparison to the cpython handling of the equivalent fileno
//fields for windows
unsafe { File::from_raw_handle(raw_fileno as *mut c_void) }
}
pub fn os_close(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(vm, args, required = [(fileno, Some(vm.ctx.int_type()))]);
let raw_fileno = objint::get_value(&fileno);
//The File type automatically closes when it goes out of scope.
//To enable us to close these file descriptors (and hence prevent leaks)
//we seek to create the relevant File and simply let it pass out of scope!
rust_file(raw_fileno.to_i64().unwrap());
Ok(vm.get_none())
}
pub fn os_open(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
arg_check!(
vm,
args,
required = [
(name, Some(vm.ctx.str_type())),
(mode, Some(vm.ctx.int_type()))
]
);
let fname = objstr::get_value(&name);
let handle = match objint::get_value(mode).to_u16().unwrap() {
0 => OpenOptions::new().read(true).open(&fname),
1 => OpenOptions::new().write(true).open(&fname),
512 => OpenOptions::new().write(true).create(true).open(&fname),
_ => OpenOptions::new().read(true).open(&fname),
}
.map_err(|err| match err.kind() {
ErrorKind::NotFound => {
let exc_type = vm.ctx.exceptions.file_not_found_error.clone();
vm.new_exception(exc_type, format!("No such file or directory: {}", &fname))
}
ErrorKind::PermissionDenied => {
let exc_type = vm.ctx.exceptions.permission_error.clone();
vm.new_exception(exc_type, format!("Permission denied: {}", &fname))
}
_ => vm.new_value_error("Unhandled file IO error".to_string()),
})?;
Ok(vm.ctx.new_int(raw_file_number(handle)))
}
pub fn mk_module(ctx: &PyContext) -> PyObjectRef {
let py_mod = ctx.new_module(&"io".to_string(), ctx.new_scope(None));
ctx.set_attr(&py_mod, "open", ctx.new_rustfunc(os_open));
ctx.set_attr(&py_mod, "close", ctx.new_rustfunc(os_close));
ctx.set_attr(&py_mod, "O_RDONLY", ctx.new_int(0));
ctx.set_attr(&py_mod, "O_WRONLY", ctx.new_int(1));
ctx.set_attr(&py_mod, "O_RDWR", ctx.new_int(2));
ctx.set_attr(&py_mod, "O_NONBLOCK", ctx.new_int(4));
ctx.set_attr(&py_mod, "O_APPEND", ctx.new_int(8));
ctx.set_attr(&py_mod, "O_CREAT", ctx.new_int(512));
py_mod
}