merge fstat and metadata functions
This commit is contained in:
@@ -105,8 +105,9 @@ pub use rustc_const_eval::interpret::*;
|
||||
// Resolve ambiguity.
|
||||
#[doc(no_inline)]
|
||||
pub use rustc_const_eval::interpret::{self, AllocMap, Provenance as _};
|
||||
use rustc_log::tracing::{self, info, trace};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
pub use rustc_data_structures::either::Either;
|
||||
pub use rustc_log::tracing::{self, info, trace};
|
||||
pub use rustc_middle::{bug, span_bug};
|
||||
|
||||
#[cfg(all(feature = "native-lib", unix))]
|
||||
pub mod native_lib {
|
||||
|
||||
@@ -9,7 +9,7 @@ use std::{fs, io};
|
||||
|
||||
use rustc_abi::Size;
|
||||
|
||||
use crate::shims::unix::{FileMetadata, UnixFileDescription};
|
||||
use crate::shims::unix::UnixFileDescription;
|
||||
use crate::*;
|
||||
|
||||
/// A unique id for file descriptions. While we could use the address, considering that
|
||||
@@ -209,23 +209,14 @@ pub trait FileDescription: std::fmt::Debug + FileDescriptionExt {
|
||||
throw_unsup_format!("cannot close {}", self.name());
|
||||
}
|
||||
|
||||
/// Returns the host `fs::Metadata` for this FD, if available.
|
||||
/// Used by host-aware shims like Windows's `GetFileInformationByHandle`.
|
||||
/// Unrelated to Unix `fstat`, which goes through `fstat()`.
|
||||
fn host_metadata<'tcx>(&self) -> InterpResult<'tcx, io::Result<fs::Metadata>> {
|
||||
/// Returns the metadata for this FD, if available.
|
||||
/// This is either host metadata, or a non-file-backed-FD type.
|
||||
/// The latter is for new represented as a string storing a `libc` name so we only
|
||||
/// support that kind of metadata on Unix targets.
|
||||
fn metadata<'tcx>(&self) -> InterpResult<'tcx, Either<io::Result<fs::Metadata>, &'static str>> {
|
||||
throw_unsup_format!("obtaining metadata is only supported on file-backed file descriptors");
|
||||
}
|
||||
|
||||
/// Return the metadata describing this FD for the `fstat`/`statx` family of syscalls.
|
||||
/// File-backed FDs should call `FileMetadata::from_meta` with their host metadata.
|
||||
/// Non-file-backed FDs should call `FileMetadata::synthetic` with an appropriate mode.
|
||||
fn fstat<'tcx>(
|
||||
&self,
|
||||
_ecx: &mut MiriInterpCx<'tcx>,
|
||||
) -> InterpResult<'tcx, Result<FileMetadata, IoError>> {
|
||||
throw_unsup_format!("fstat is not supported on {}", self.name());
|
||||
}
|
||||
|
||||
fn is_tty(&self, _communicate_allowed: bool) -> bool {
|
||||
// Most FDs are not tty's and the consequence of a wrong `false` are minor,
|
||||
// so we use a default impl here.
|
||||
@@ -445,15 +436,8 @@ impl FileDescription for FileHandle {
|
||||
}
|
||||
}
|
||||
|
||||
fn host_metadata<'tcx>(&self) -> InterpResult<'tcx, io::Result<fs::Metadata>> {
|
||||
interp_ok(self.file.metadata())
|
||||
}
|
||||
|
||||
fn fstat<'tcx>(
|
||||
&self,
|
||||
ecx: &mut MiriInterpCx<'tcx>,
|
||||
) -> InterpResult<'tcx, Result<FileMetadata, IoError>> {
|
||||
FileMetadata::from_meta(ecx, self.file.metadata())
|
||||
fn metadata<'tcx>(&self) -> InterpResult<'tcx, Either<io::Result<fs::Metadata>, &'static str>> {
|
||||
interp_ok(Either::Left(self.file.metadata()))
|
||||
}
|
||||
|
||||
fn is_tty(&self, communicate_allowed: bool) -> bool {
|
||||
|
||||
@@ -348,34 +348,6 @@ trait EvalContextExtPrivate<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn file_type_to_mode_name(file_type: std::fs::FileType) -> &'static str {
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::fs::FileTypeExt;
|
||||
|
||||
if file_type.is_file() {
|
||||
"S_IFREG"
|
||||
} else if file_type.is_dir() {
|
||||
"S_IFDIR"
|
||||
} else if file_type.is_symlink() {
|
||||
"S_IFLNK"
|
||||
} else {
|
||||
// Certain file types are only available when the host is a Unix system.
|
||||
#[cfg(unix)]
|
||||
{
|
||||
if file_type.is_socket() {
|
||||
return "S_IFSOCK";
|
||||
} else if file_type.is_fifo() {
|
||||
return "S_IFIFO";
|
||||
} else if file_type.is_char_device() {
|
||||
return "S_IFCHR";
|
||||
} else if file_type.is_block_device() {
|
||||
return "S_IFBLK";
|
||||
}
|
||||
}
|
||||
"S_IFREG"
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
|
||||
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
fn open(
|
||||
@@ -1662,9 +1634,37 @@ fn extract_sec_and_nsec<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
fn file_type_to_mode_name(file_type: std::fs::FileType) -> &'static str {
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::fs::FileTypeExt;
|
||||
|
||||
if file_type.is_file() {
|
||||
"S_IFREG"
|
||||
} else if file_type.is_dir() {
|
||||
"S_IFDIR"
|
||||
} else if file_type.is_symlink() {
|
||||
"S_IFLNK"
|
||||
} else {
|
||||
// Certain file types are only available when the host is a Unix system.
|
||||
#[cfg(unix)]
|
||||
{
|
||||
if file_type.is_socket() {
|
||||
return "S_IFSOCK";
|
||||
} else if file_type.is_fifo() {
|
||||
return "S_IFIFO";
|
||||
} else if file_type.is_char_device() {
|
||||
return "S_IFCHR";
|
||||
} else if file_type.is_block_device() {
|
||||
return "S_IFBLK";
|
||||
}
|
||||
}
|
||||
"S_IFREG"
|
||||
}
|
||||
}
|
||||
|
||||
/// Stores a file's metadata in order to avoid code duplication in the different metadata related
|
||||
/// shims.
|
||||
pub struct FileMetadata {
|
||||
struct FileMetadata {
|
||||
mode: Scalar,
|
||||
size: u64,
|
||||
created: Option<(u64, u32)>,
|
||||
@@ -1694,18 +1694,20 @@ impl FileMetadata {
|
||||
let Some(fd) = ecx.machine.fds.get(fd_num) else {
|
||||
return interp_ok(Err(LibcError("EBADF")));
|
||||
};
|
||||
fd.fstat(ecx)
|
||||
match fd.metadata()? {
|
||||
Either::Left(host) => Self::from_meta(ecx, host),
|
||||
Either::Right(name) => Self::synthetic(ecx, name),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn synthetic<'tcx>(
|
||||
fn synthetic<'tcx>(
|
||||
ecx: &mut MiriInterpCx<'tcx>,
|
||||
mode_name: &str,
|
||||
size: u64,
|
||||
) -> InterpResult<'tcx, Result<FileMetadata, IoError>> {
|
||||
let mode = ecx.eval_libc(mode_name);
|
||||
interp_ok(Ok(FileMetadata {
|
||||
mode,
|
||||
size,
|
||||
size: 0,
|
||||
created: None,
|
||||
accessed: None,
|
||||
modified: None,
|
||||
@@ -1715,7 +1717,7 @@ impl FileMetadata {
|
||||
}))
|
||||
}
|
||||
|
||||
pub(crate) fn from_meta<'tcx>(
|
||||
fn from_meta<'tcx>(
|
||||
ecx: &mut MiriInterpCx<'tcx>,
|
||||
metadata: Result<std::fs::Metadata, std::io::Error>,
|
||||
) -> InterpResult<'tcx, Result<FileMetadata, IoError>> {
|
||||
|
||||
@@ -10,7 +10,7 @@ use crate::concurrency::VClock;
|
||||
use crate::shims::files::{
|
||||
DynFileDescriptionRef, FdId, FdNum, FileDescription, FileDescriptionRef, WeakFileDescriptionRef,
|
||||
};
|
||||
use crate::shims::unix::{FileMetadata, UnixFileDescription};
|
||||
use crate::shims::unix::UnixFileDescription;
|
||||
use crate::*;
|
||||
|
||||
type EpollEventKey = (FdId, FdNum);
|
||||
@@ -119,12 +119,11 @@ impl FileDescription for Epoll {
|
||||
"epoll"
|
||||
}
|
||||
|
||||
fn fstat<'tcx>(
|
||||
fn metadata<'tcx>(
|
||||
&self,
|
||||
ecx: &mut MiriInterpCx<'tcx>,
|
||||
) -> InterpResult<'tcx, Result<FileMetadata, IoError>> {
|
||||
) -> InterpResult<'tcx, Either<io::Result<std::fs::Metadata>, &'static str>> {
|
||||
// On Linux, epoll is an "anonymous inode" reported as S_IFREG.
|
||||
FileMetadata::synthetic(ecx, "S_IFREG", 0)
|
||||
interp_ok(Either::Right("S_IFREG"))
|
||||
}
|
||||
|
||||
fn destroy<'tcx>(
|
||||
|
||||
@@ -5,8 +5,8 @@ use std::io::ErrorKind;
|
||||
|
||||
use crate::concurrency::VClock;
|
||||
use crate::shims::files::{FdId, FileDescription, FileDescriptionRef, WeakFileDescriptionRef};
|
||||
use crate::shims::unix::UnixFileDescription;
|
||||
use crate::shims::unix::linux_like::epoll::{EpollEvents, EvalContextExt as _};
|
||||
use crate::shims::unix::{FileMetadata, UnixFileDescription};
|
||||
use crate::*;
|
||||
|
||||
/// Maximum value that the eventfd counter can hold.
|
||||
@@ -37,12 +37,11 @@ impl FileDescription for EventFd {
|
||||
"event"
|
||||
}
|
||||
|
||||
fn fstat<'tcx>(
|
||||
fn metadata<'tcx>(
|
||||
&self,
|
||||
ecx: &mut MiriInterpCx<'tcx>,
|
||||
) -> InterpResult<'tcx, Result<FileMetadata, IoError>> {
|
||||
) -> InterpResult<'tcx, Either<io::Result<std::fs::Metadata>, &'static str>> {
|
||||
// On Linux, eventfd is an "anonymous inode" reported as S_IFREG.
|
||||
FileMetadata::synthetic(ecx, "S_IFREG", 0)
|
||||
interp_ok(Either::Right("S_IFREG"))
|
||||
}
|
||||
|
||||
fn destroy<'tcx>(
|
||||
|
||||
@@ -19,7 +19,7 @@ mod solarish;
|
||||
// All the Unix-specific extension traits
|
||||
pub use self::env::{EvalContextExt as _, UnixEnvVars};
|
||||
pub use self::fd::{EvalContextExt as _, UnixFileDescription};
|
||||
pub use self::fs::{DirTable, EvalContextExt as _, FileMetadata};
|
||||
pub use self::fs::{DirTable, EvalContextExt as _};
|
||||
pub use self::linux_like::epoll::EpollInterestTable;
|
||||
pub use self::mem::EvalContextExt as _;
|
||||
pub use self::socket::EvalContextExt as _;
|
||||
|
||||
@@ -12,8 +12,8 @@ use crate::concurrency::VClock;
|
||||
use crate::shims::files::{
|
||||
EvalContextExt as _, FdId, FileDescription, FileDescriptionRef, WeakFileDescriptionRef,
|
||||
};
|
||||
use crate::shims::unix::UnixFileDescription;
|
||||
use crate::shims::unix::linux_like::epoll::{EpollEvents, EvalContextExt as _};
|
||||
use crate::shims::unix::{FileMetadata, UnixFileDescription};
|
||||
use crate::*;
|
||||
|
||||
/// The maximum capacity of the socketpair buffer in bytes.
|
||||
@@ -83,15 +83,14 @@ impl FileDescription for VirtualSocket {
|
||||
}
|
||||
}
|
||||
|
||||
fn fstat<'tcx>(
|
||||
fn metadata<'tcx>(
|
||||
&self,
|
||||
ecx: &mut MiriInterpCx<'tcx>,
|
||||
) -> InterpResult<'tcx, Result<FileMetadata, IoError>> {
|
||||
) -> InterpResult<'tcx, Either<io::Result<std::fs::Metadata>, &'static str>> {
|
||||
let mode_name = match self.fd_type {
|
||||
VirtualSocketType::Socketpair => "S_IFSOCK",
|
||||
VirtualSocketType::PipeRead | VirtualSocketType::PipeWrite => "S_IFIFO",
|
||||
};
|
||||
FileMetadata::synthetic(ecx, mode_name, 0)
|
||||
interp_ok(Either::Right(mode_name))
|
||||
}
|
||||
|
||||
fn destroy<'tcx>(
|
||||
|
||||
@@ -22,8 +22,10 @@ impl FileDescription for DirHandle {
|
||||
"directory"
|
||||
}
|
||||
|
||||
fn host_metadata<'tcx>(&self) -> InterpResult<'tcx, io::Result<Metadata>> {
|
||||
interp_ok(self.path.metadata())
|
||||
fn metadata<'tcx>(
|
||||
&self,
|
||||
) -> InterpResult<'tcx, Either<io::Result<std::fs::Metadata>, &'static str>> {
|
||||
interp_ok(Either::Left(self.path.metadata()))
|
||||
}
|
||||
|
||||
fn destroy<'tcx>(
|
||||
@@ -49,8 +51,10 @@ impl FileDescription for MetadataHandle {
|
||||
"metadata-only"
|
||||
}
|
||||
|
||||
fn host_metadata<'tcx>(&self) -> InterpResult<'tcx, io::Result<Metadata>> {
|
||||
interp_ok(Ok(self.meta.clone()))
|
||||
fn metadata<'tcx>(
|
||||
&self,
|
||||
) -> InterpResult<'tcx, Either<io::Result<std::fs::Metadata>, &'static str>> {
|
||||
interp_ok(Either::Left(Ok(self.meta.clone())))
|
||||
}
|
||||
|
||||
fn destroy<'tcx>(
|
||||
@@ -328,12 +332,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
this.invalid_handle("GetFileInformationByHandle")?
|
||||
};
|
||||
|
||||
let metadata = match desc.host_metadata()? {
|
||||
Ok(meta) => meta,
|
||||
Err(e) => {
|
||||
let metadata = match desc.metadata()? {
|
||||
Either::Left(Ok(meta)) => meta,
|
||||
Either::Left(Err(e)) => {
|
||||
this.set_last_error(e)?;
|
||||
return interp_ok(this.eval_windows("c", "FALSE"));
|
||||
}
|
||||
Either::Right(_mode) =>
|
||||
throw_unsup_format!(
|
||||
"`GetFileInformationByHandle` is not supported on non-file-backed handles"
|
||||
),
|
||||
};
|
||||
|
||||
let size = metadata.len();
|
||||
|
||||
Reference in New Issue
Block a user