From 4ac91384ff124d5b6258a648df5176909ff1b780 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 Mar 2020 19:24:16 +0100 Subject: [PATCH] route all path reading/writing through central read/write methods --- src/helpers.rs | 24 +++++++++++++++++++++++- src/shims/env.rs | 4 ++-- src/shims/fs.rs | 42 +++++++++++++++++++++--------------------- 3 files changed, 46 insertions(+), 24 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 76c5308cfd3..d8731b53771 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,6 +1,8 @@ use std::ffi::{OsStr, OsString}; +use std::path::Path; use std::{iter, mem}; use std::convert::TryFrom; +use std::borrow::Cow; use rustc::mir; use rustc::ty::{ @@ -491,6 +493,16 @@ fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { bytes_to_os_str(bytes) } + /// Read a null-terminated sequence of bytes, and perform path separator conversion if needed. + fn read_path_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, Cow<'a, Path>> + where + 'tcx: 'a, + 'mir: 'a, + { + let os_str = self.read_os_str_from_c_str(scalar)?; + Ok(Cow::Borrowed(Path::new(os_str))) + } + /// Helper function to read an OsString from a 0x0000-terminated sequence of u16, /// which is what the Windows APIs usually handle. fn read_os_str_from_wide_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, OsString> @@ -513,7 +525,6 @@ pub fn u16vec_to_osstring<'tcx, 'a>(u16_vec: Vec) -> InterpResult<'tcx, OsS u16vec_to_osstring(u16_vec) } - /// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. This function returns `Ok((false, length))` without trying /// to write if `size` is not large enough to fit the contents of `os_string` plus a null @@ -553,6 +564,17 @@ fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> Ok((true, string_length)) } + /// Write a Path to the machine memory, adjusting path separators if needed. + fn write_path_to_c_str( + &mut self, + path: &Path, + scalar: Scalar, + size: u64, + ) -> InterpResult<'tcx, (bool, u64)> { + let os_str = path.as_os_str(); + self.write_os_str_to_c_str(os_str, scalar, size) + } + /// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what /// the Windows APIs usually handle. This function returns `Ok((false, length))` without trying /// to write if `size` is not large enough to fit the contents of `os_string` plus a null diff --git a/src/shims/env.rs b/src/shims/env.rs index 6b18cd25a1b..192fc0d47ab 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -134,7 +134,7 @@ fn getcwd( // If we cannot get the current directory, we return null match env::current_dir() { Ok(cwd) => { - if this.write_os_str_to_c_str(&OsString::from(cwd), buf, size)?.0 { + if this.write_path_to_c_str(&cwd, buf, size)?.0 { return Ok(buf); } let erange = this.eval_libc("ERANGE")?; @@ -150,7 +150,7 @@ fn chdir(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { this.check_no_isolation("chdir")?; - let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_path_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; match env::set_current_dir(path) { Ok(()) => Ok(0), diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 16d83188dbc..9778775fca6 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -2,7 +2,7 @@ use std::convert::{TryFrom, TryInto}; use std::fs::{read_dir, remove_dir, remove_file, rename, DirBuilder, File, FileType, OpenOptions, ReadDir}; use std::io::{Read, Seek, SeekFrom, Write}; -use std::path::PathBuf; +use std::path::Path; use std::time::SystemTime; use rustc_data_structures::fx::FxHashMap; @@ -79,9 +79,9 @@ fn macos_stat_or_lstat( let this = self.eval_context_mut(); let path_scalar = this.read_scalar(path_op)?.not_undef()?; - let path: PathBuf = this.read_os_str_from_c_str(path_scalar)?.into(); + let path = this.read_path_from_c_str(path_scalar)?.into_owned(); - let metadata = match FileMetadata::from_path(this, path, follow_symlink)? { + let metadata = match FileMetadata::from_path(this, &path, follow_symlink)? { Some(metadata) => metadata, None => return Ok(-1), }; @@ -303,7 +303,7 @@ fn open( throw_unsup_format!("unsupported flags {:#x}", flag & !mirror); } - let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_path_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; let fd = options.open(&path).map(|file| { let fh = &mut this.machine.file_handler; @@ -524,10 +524,9 @@ fn unlink(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { this.check_no_isolation("unlink")?; - let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_path_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; let result = remove_file(path).map(|_| 0); - this.try_unwrap_io_result(result) } @@ -537,12 +536,12 @@ fn symlink( linkpath_op: OpTy<'tcx, Tag> ) -> InterpResult<'tcx, i32> { #[cfg(target_family = "unix")] - fn create_link(src: PathBuf, dst: PathBuf) -> std::io::Result<()> { + fn create_link(src: &Path, dst: &Path) -> std::io::Result<()> { std::os::unix::fs::symlink(src, dst) } #[cfg(target_family = "windows")] - fn create_link(src: PathBuf, dst: PathBuf) -> std::io::Result<()> { + fn create_link(src: &Path, dst: &Path) -> std::io::Result<()> { use std::os::windows::fs; if src.is_dir() { fs::symlink_dir(src, dst) @@ -555,10 +554,11 @@ fn create_link(src: PathBuf, dst: PathBuf) -> std::io::Result<()> { this.check_no_isolation("symlink")?; - let target = this.read_os_str_from_c_str(this.read_scalar(target_op)?.not_undef()?)?.into(); - let linkpath = this.read_os_str_from_c_str(this.read_scalar(linkpath_op)?.not_undef()?)?.into(); + let target = this.read_path_from_c_str(this.read_scalar(target_op)?.not_undef()?)?; + let linkpath = this.read_path_from_c_str(this.read_scalar(linkpath_op)?.not_undef()?)?; - this.try_unwrap_io_result(create_link(target, linkpath).map(|_| 0)) + let result = create_link(&target, &linkpath).map(|_| 0); + this.try_unwrap_io_result(result) } fn macos_stat( @@ -644,7 +644,7 @@ fn linux_statx( this.ref_to_mplace(statxbuf_imm)? }; - let path: PathBuf = this.read_os_str_from_c_str(pathname_scalar)?.into(); + let path = this.read_path_from_c_str(pathname_scalar)?.into_owned(); // `flags` should be a `c_int` but the `syscall` function provides an `isize`. let flags: i32 = this.read_scalar(flags_op)?.to_machine_isize(&*this.tcx)?.try_into().map_err(|e| { @@ -691,7 +691,7 @@ fn linux_statx( let metadata = if path.as_os_str().is_empty() && empty_path_flag { FileMetadata::from_fd(this, dirfd)? } else { - FileMetadata::from_path(this, path, follow_symlink)? + FileMetadata::from_path(this, &path, follow_symlink)? }; let metadata = match metadata { Some(metadata) => metadata, @@ -785,8 +785,8 @@ fn rename( return Ok(-1); } - let oldpath = this.read_os_str_from_c_str(oldpath_scalar)?; - let newpath = this.read_os_str_from_c_str(newpath_scalar)?; + let oldpath = this.read_path_from_c_str(oldpath_scalar)?; + let newpath = this.read_path_from_c_str(newpath_scalar)?; let result = rename(oldpath, newpath).map(|_| 0); @@ -808,7 +808,7 @@ fn mkdir( this.read_scalar(mode_op)?.to_u32()? }; - let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_path_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; let mut builder = DirBuilder::new(); @@ -833,7 +833,7 @@ fn rmdir( this.check_no_isolation("rmdir")?; - let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_path_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; let result = remove_dir(path).map(|_| 0i32); @@ -845,7 +845,7 @@ fn opendir(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar( ecx: &mut MiriEvalContext<'mir, 'tcx>, - path: PathBuf, + path: &Path, follow_symlink: bool ) -> InterpResult<'tcx, Option> { let metadata = if follow_symlink { -- 2.44.0