diff --git a/Cargo.lock b/Cargo.lock index ed6d2ebd6..8d2d1081b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -749,6 +749,16 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" +[[package]] +name = "filepath" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd50318458226958db06f173610f54f01d26f0a9ccfa3d38bd60f70bc9939ff" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "fixedbitset" version = "0.2.0" @@ -1986,6 +1996,7 @@ dependencies = [ "digest", "dns-lookup", "exitcode", + "filepath", "flame", "flamer", "flate2", diff --git a/vm/Cargo.toml b/vm/Cargo.toml index 66472be5d..0ac133af5 100644 --- a/vm/Cargo.toml +++ b/vm/Cargo.toml @@ -149,5 +149,8 @@ features = [ [target.'cfg(target_arch = "wasm32")'.dependencies] wasm-bindgen = "0.2" +[target.'cfg(any(target_os = "linux", target_os = "macos", windows))'.dependencies] +filepath = "0.1.1" + [build-dependencies] itertools = "0.9" diff --git a/vm/src/stdlib/os.rs b/vm/src/stdlib/os.rs index 6257916b4..ac2910588 100644 --- a/vm/src/stdlib/os.rs +++ b/vm/src/stdlib/os.rs @@ -7,6 +7,8 @@ use std::time::{Duration, SystemTime}; use std::{env, fs}; use crossbeam_utils::atomic::AtomicCell; +#[cfg(any(target_os = "linux", target_os = "macos", windows))] +use filepath::FilePath; use num_bigint::BigInt; use super::errno::errors; @@ -161,11 +163,25 @@ fn make_path<'a>( vm: &VirtualMachine, path: &'a PyPathLike, dir_fd: &DirFd, -) -> PyResult<&'a ffi::OsStr> { - if dir_fd.0.is_some() { - Err(vm.new_os_error("dir_fd not supported yet".to_owned())) - } else { - Ok(path.path.as_os_str()) +) -> PyResult> { + let path = &path.path; + if dir_fd.0.is_none() || path.is_absolute() { + return Ok(path.as_os_str().into()); + } + + cfg_if::cfg_if! { + if #[cfg(any(target_os = "linux", target_os = "macos", windows))] { + let dir_path = match rust_file(dir_fd.0.unwrap().into()).path() { + Ok(dir_path) => dir_path, + Err(_) => { + return Err(vm.new_os_error(format!("Cannot determine path of dir_fd: {:?}", dir_fd.0))); + } + }; + let p: PathBuf = vec![dir_path, path.to_path_buf()].iter().collect(); + Ok(p.into_os_string().into()) + } else { + return Err(vm.new_os_error("dir_fd not supported on wasi yet".to_owned())); + } } } @@ -349,7 +365,7 @@ mod _os { vm: &VirtualMachine, ) -> PyResult { let fname = make_path(vm, &name, &dir_fd)?; - if osstr_contains_nul(fname) { + if osstr_contains_nul(&fname) { return Err(vm.new_value_error("embedded null character".to_owned())); } @@ -504,14 +520,14 @@ mod _os { fn remove(path: PyPathLike, dir_fd: DirFd, vm: &VirtualMachine) -> PyResult<()> { let path = make_path(vm, &path, &dir_fd)?; let is_junction = cfg!(windows) - && fs::symlink_metadata(path).map_or(false, |meta| { + && fs::symlink_metadata(&path).map_or(false, |meta| { let ty = meta.file_type(); ty.is_dir() && ty.is_symlink() }); let res = if is_junction { - fs::remove_dir(path) + fs::remove_dir(&path) } else { - fs::remove_file(path) + fs::remove_file(&path) }; res.map_err(|err| err.into_pyexception(vm)) } @@ -1221,7 +1237,7 @@ mod _os { pub(super) fn support_funcs(vm: &VirtualMachine) -> Vec { let mut supports = super::platform::support_funcs(vm); supports.extend(vec![ - SupportFunc::new(vm, "open", open, None, Some(false), None), + SupportFunc::new(vm, "open", open, None, Some(true), None), SupportFunc::new( vm, "access", @@ -1800,10 +1816,10 @@ mod posix { let path = make_path(vm, &path, &dir_fd)?; let body = move || { use std::os::unix::fs::PermissionsExt; - let meta = fs_metadata(path, follow_symlinks.0)?; + let meta = fs_metadata(&path, follow_symlinks.0)?; let mut permissions = meta.permissions(); permissions.set_mode(mode); - fs::set_permissions(path, permissions) + fs::set_permissions(&path, permissions) }; body().map_err(|err| err.into_pyexception(vm)) } @@ -2675,14 +2691,14 @@ mod nt { const S_IWRITE: u32 = 128; let path = make_path(vm, &path, &dir_fd)?; let metadata = if follow_symlinks.0 { - fs::metadata(path) + fs::metadata(&path) } else { - fs::symlink_metadata(path) + fs::symlink_metadata(&path) }; let meta = metadata.map_err(|err| err.into_pyexception(vm))?; let mut permissions = meta.permissions(); permissions.set_readonly(mode & S_IWRITE != 0); - fs::set_permissions(path, permissions).map_err(|err| err.into_pyexception(vm)) + fs::set_permissions(&path, permissions).map_err(|err| err.into_pyexception(vm)) } // cwait is available on MSVC only (according to CPython)