From 491ca575b274bc4d47a1f068be9e112e75adaa78 Mon Sep 17 00:00:00 2001 From: Noah <33094578+coolreader18@users.noreply.github.com> Date: Fri, 10 Jul 2020 12:08:51 -0500 Subject: [PATCH] Implement os.utime() and fix some other things --- Cargo.lock | 11 +++++++++ vm/Cargo.toml | 1 + vm/src/stdlib/os.rs | 58 +++++++++++++++++++++++++++++++++++---------- 3 files changed, 57 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fe26180ae..156c88a12 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1715,6 +1715,7 @@ dependencies = [ "unic-ucd-ident", "unicode-casing", "unicode_names2", + "utime", "volatile", "wasm-bindgen", "winapi", @@ -2262,6 +2263,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372" +[[package]] +name = "utime" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91baa0c65eabd12fcbdac8cc35ff16159cab95cae96d0222d6d0271db6193cef" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "vcpkg" version = "0.2.8" diff --git a/vm/Cargo.toml b/vm/Cargo.toml index 289fa2481..a65bc2408 100644 --- a/vm/Cargo.toml +++ b/vm/Cargo.toml @@ -108,6 +108,7 @@ rustyline = "6.0" openssl = { version = "0.10", features = ["vendored"], optional = true } openssl-sys = { version = "0.9", optional = true } openssl-probe = { version = "0.1", optional = true } +utime = "0.3" [target.'cfg(any(not(target_arch = "wasm32"), target_os = "wasi"))'.dependencies] num_cpus = "1" diff --git a/vm/src/stdlib/os.rs b/vm/src/stdlib/os.rs index 500ecada0..e709417f8 100644 --- a/vm/src/stdlib/os.rs +++ b/vm/src/stdlib/os.rs @@ -18,6 +18,7 @@ use nix::errno::Errno; use nix::pty::openpty; #[cfg(unix)] use nix::unistd::{self, Gid, Pid, Uid}; +use num_traits::ToPrimitive; #[cfg(unix)] use std::os::unix::io::RawFd; #[cfg(windows)] @@ -29,7 +30,7 @@ use crate::function::{IntoPyNativeFunc, OptionalArg, PyFuncArgs}; use crate::obj::objbyteinner::PyBytesLike; use crate::obj::objbytes::{PyBytes, PyBytesRef}; use crate::obj::objdict::PyDictRef; -use crate::obj::objint::PyIntRef; +use crate::obj::objint::{PyInt, PyIntRef}; use crate::obj::objiter; use crate::obj::objset::PySet; use crate::obj::objstr::{PyString, PyStringRef}; @@ -1018,13 +1019,13 @@ fn os_getcwd(vm: &VirtualMachine) -> PyResult { .to_owned()) } -fn os_chdir(path: PyStringRef, vm: &VirtualMachine) -> PyResult<()> { - env::set_current_dir(path.as_str()).map_err(|err| convert_io_error(vm, err)) +fn os_chdir(path: PyPathLike, vm: &VirtualMachine) -> PyResult<()> { + env::set_current_dir(&path.path).map_err(|err| convert_io_error(vm, err)) } #[cfg(all(unix, not(target_os = "redox")))] -fn os_chroot(path: PyStringRef, vm: &VirtualMachine) -> PyResult<()> { - nix::unistd::chroot(path.as_str()).map_err(|err| convert_nix_error(vm, err)) +fn os_chroot(path: PyPathLike, vm: &VirtualMachine) -> PyResult<()> { + nix::unistd::chroot(&*path.path).map_err(|err| convert_nix_error(vm, err)) } #[cfg(unix)] @@ -1485,17 +1486,48 @@ struct UtimeArgs { #[pyarg(keyword_only, default = "None")] ns: Option, #[pyarg(flatten)] - dir_fd: DirFd, + _dir_fd: DirFd, #[pyarg(flatten)] - follow_symlinks: FollowSymlinks, + _follow_symlinks: FollowSymlinks, } -fn os_utime( - _path: PyPathLike, - _time: OptionalArg, - _vm: &VirtualMachine, -) -> PyResult<()> { - unimplemented!("utime") +fn os_utime(args: UtimeArgs, vm: &VirtualMachine) -> PyResult<()> { + let parse_tup = |tup: PyTupleRef| -> Option<(i64, i64)> { + let tup = tup.as_slice(); + if tup.len() != 2 { + return None; + } + let i = |e: &PyObjectRef| e.clone().downcast::().ok()?.as_bigint().to_i64(); + Some((i(&tup[0])?, i(&tup[1])?)) + }; + let (acc, modif) = match (args.times, args.ns) { + (Some(t), None) => parse_tup(t).ok_or_else(|| { + vm.new_type_error( + "utime: 'times' must be either a tuple of two ints or None".to_owned(), + ) + })?, + (None, Some(ns)) => { + let (a, m) = parse_tup(ns).ok_or_else(|| { + vm.new_type_error("utime: 'ns' must be a tuple of two ints".to_owned()) + })?; + // TODO: do validation to make sure this doesn't.. underflow? + (a / 1_000_000_000, m / 1_000_000_000) + } + (None, None) => { + let now = SystemTime::now(); + let now = now + .duration_since(SystemTime::UNIX_EPOCH) + .map(|d| d.as_secs() as i64) + .unwrap_or_else(|e| -(e.duration().as_secs() as i64)); + (now, now) + } + (Some(_), Some(_)) => { + return Err(vm.new_value_error( + "utime: you may specify either 'times' or 'ns' but not both".to_owned(), + )) + } + }; + utime::set_file_times(&args.path.path, acc, modif).map_err(|e| convert_io_error(vm, e)) } #[cfg(unix)]