diff --git a/src/shims/windows/fs.rs b/src/shims/windows/fs.rs index a2ac9fc51a..2764aac18f 100644 --- a/src/shims/windows/fs.rs +++ b/src/shims/windows/fs.rs @@ -4,7 +4,7 @@ use std::io::IsTerminal; use std::path::PathBuf; use std::time::SystemTime; -use crate::shims::files::{FileDescription, FileDescriptionRef}; +use crate::shims::files::FileDescription; use crate::shims::time::system_time_to_duration; use crate::shims::windows::handle::{EvalContextExt as _, Handle}; use crate::*; @@ -80,7 +80,7 @@ impl FileDescription for DirHandle { #[derive(Debug)] pub struct MetadataHandle { - pub(crate) path: PathBuf, + pub(crate) meta: Metadata, } impl FileDescription for MetadataHandle { @@ -89,7 +89,7 @@ impl FileDescription for MetadataHandle { } fn metadata<'tcx>(&self) -> InterpResult<'tcx, io::Result> { - interp_ok(self.path.metadata()) + interp_ok(Ok(self.meta.clone())) } fn close<'tcx>( @@ -238,8 +238,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Windows supports handles with no permissions. These allow things such as reading // metadata, but not file content. let fh = &mut this.machine.fds; - let fd_num = fh.insert_new(MetadataHandle { path: file_name }); - Ok(Handle::File(fd_num)) + file_name.metadata().map(|meta| { + let fd_num = fh.insert_new(MetadataHandle { meta }); + Handle::File(fd_num) + }) } else { options.open(file_name).map(|file| { let fh = &mut this.machine.fds; diff --git a/tests/pass-dep/shims/windows-fs.rs b/tests/pass-dep/shims/windows-fs.rs index 2c1cc386dc..07f1aa41a0 100644 --- a/tests/pass-dep/shims/windows-fs.rs +++ b/tests/pass-dep/shims/windows-fs.rs @@ -3,6 +3,7 @@ #![allow(nonstandard_style)] use std::os::windows::ffi::OsStrExt; +use std::path::Path; use std::ptr; #[path = "../../utils/mod.rs"] @@ -24,10 +25,7 @@ fn main() { unsafe fn test_create_dir_file() { let temp = utils::tmp(); - let mut raw_path = temp.as_os_str().encode_wide().collect::>(); - // encode_wide doesn't add a null-terminator - raw_path.push(0); - raw_path.push(0); + let raw_path = to_wide_cstr(&temp); let handle = CreateFileW( raw_path.as_ptr(), GENERIC_READ, @@ -37,7 +35,7 @@ unsafe fn test_create_dir_file() { FILE_FLAG_BACKUP_SEMANTICS, 0, ); - assert_ne!(handle, -1, "CreateNewW Failed: {}", GetLastError()); + assert_ne!(handle, -1, "CreateFileW Failed: {}", GetLastError()); let mut info = std::mem::zeroed::(); if GetFileInformationByHandle(handle, &mut info) == 0 { panic!("Failed to get file information") @@ -50,10 +48,7 @@ unsafe fn test_create_dir_file() { unsafe fn test_create_normal_file() { let temp = utils::tmp().join("test.txt"); - let mut raw_path = temp.as_os_str().encode_wide().collect::>(); - // encode_wide doesn't add a null-terminator - raw_path.push(0); - raw_path.push(0); + let raw_path = to_wide_cstr(&temp); let handle = CreateFileW( raw_path.as_ptr(), GENERIC_READ | GENERIC_WRITE, @@ -63,7 +58,7 @@ unsafe fn test_create_normal_file() { 0, 0, ); - assert_ne!(handle, -1, "CreateNewW Failed: {}", GetLastError()); + assert_ne!(handle, -1, "CreateFileW Failed: {}", GetLastError()); let mut info = std::mem::zeroed::(); if GetFileInformationByHandle(handle, &mut info) == 0 { panic!("Failed to get file information: {}", GetLastError()) @@ -72,4 +67,30 @@ unsafe fn test_create_normal_file() { if CloseHandle(handle) == 0 { panic!("Failed to close file") }; + + // Test metadata-only handle + let handle = CreateFileW( + raw_path.as_ptr(), + 0, + FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, + ptr::null_mut(), + OPEN_EXISTING, + 0, + 0, + ); + assert_ne!(handle, -1, "CreateFileW Failed: {}", GetLastError()); + let mut info = std::mem::zeroed::(); + if GetFileInformationByHandle(handle, &mut info) == 0 { + panic!("Failed to get file information: {}", GetLastError()) + }; + assert!(info.dwFileAttributes & FILE_ATTRIBUTE_NORMAL != 0); + if CloseHandle(handle) == 0 { + panic!("Failed to close file") + }; +} + +fn to_wide_cstr(path: &Path) -> Vec { + let mut raw_path = path.as_os_str().encode_wide().collect::>(); + raw_path.extend([0, 0]); + raw_path }