Add support for AT_EMPTY_PATH to statx shim

This commit is contained in:
David Cook
2020-01-25 22:21:33 -06:00
parent b222677766
commit d94b88ef98
2 changed files with 39 additions and 4 deletions
+37 -4
View File
@@ -345,7 +345,7 @@ fn stat_or_lstat(
let buf = this.deref_operand(buf_op)?;
let metadata = match FileMetadata::new(this, path, follow_symlink)? {
let metadata = match FileMetadata::from_path(this, path, follow_symlink)? {
Some(metadata) => metadata,
None => return Ok(-1),
};
@@ -454,6 +454,7 @@ fn statx(
this.read_scalar(flags_op)?.to_machine_isize(&*this.tcx)?.try_into().map_err(|e| {
err_unsup_format!("Failed to convert pointer sized operand to integer: {}", e)
})?;
let empty_path_flag = flags & this.eval_libc("AT_EMPTY_PATH")?.to_i32()? != 0;
// `dirfd` should be a `c_int` but the `syscall` function provides an `isize`.
let dirfd: i32 =
this.read_scalar(dirfd_op)?.to_machine_isize(&*this.tcx)?.try_into().map_err(|e| {
@@ -463,7 +464,11 @@ fn statx(
// to `dirfd` when the latter is `AT_FDCWD`. The behavior of `statx` with a relative path
// and a directory file descriptor other than `AT_FDCWD` is specified but it cannot be
// tested from `libstd`. If you found this error, please open an issue reporting it.
if !(path.is_absolute() || dirfd == this.eval_libc_i32("AT_FDCWD")?) {
if !(
path.is_absolute() ||
dirfd == this.eval_libc_i32("AT_FDCWD")? ||
(path.as_os_str().is_empty() && empty_path_flag)
) {
throw_unsup_format!(
"Using statx with a relative path and a file descriptor different from `AT_FDCWD` is not supported"
)
@@ -480,7 +485,14 @@ fn statx(
// symbolic links.
let follow_symlink = flags & this.eval_libc("AT_SYMLINK_NOFOLLOW")?.to_i32()? == 0;
let metadata = match FileMetadata::new(this, path, follow_symlink)? {
// If the path is empty, and the AT_EMPTY_PATH flag is set, we query the open file
// represented by dirfd, whether it's a directory or otherwise.
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)?
};
let metadata = match metadata {
Some(metadata) => metadata,
None => return Ok(-1),
};
@@ -589,7 +601,7 @@ struct FileMetadata {
}
impl FileMetadata {
fn new<'tcx, 'mir>(
fn from_path<'tcx, 'mir>(
ecx: &mut MiriEvalContext<'mir, 'tcx>,
path: PathBuf,
follow_symlink: bool
@@ -600,6 +612,27 @@ fn new<'tcx, 'mir>(
std::fs::symlink_metadata(path)
};
FileMetadata::from_meta(ecx, metadata)
}
fn from_fd<'tcx, 'mir>(
ecx: &mut MiriEvalContext<'mir, 'tcx>,
fd: i32,
) -> InterpResult<'tcx, Option<FileMetadata>> {
let option = ecx.machine.file_handler.handles.get(&fd);
let handle = match option {
Some(handle) => handle,
None => return ecx.handle_not_found().map(|_: i32| None),
};
let metadata = handle.file.metadata();
FileMetadata::from_meta(ecx, metadata)
}
fn from_meta<'tcx, 'mir>(
ecx: &mut MiriEvalContext<'mir, 'tcx>,
metadata: Result<std::fs::Metadata, std::io::Error>,
) -> InterpResult<'tcx, Option<FileMetadata>> {
let metadata = match metadata {
Ok(metadata) => metadata,
Err(e) => {
+2
View File
@@ -29,8 +29,10 @@ fn main() {
let mut file = File::create(&path).unwrap();
// Writing 0 bytes should not change the file contents.
file.write(&mut []).unwrap();
assert_eq!(file.metadata().unwrap().len(), 0);
file.write(bytes).unwrap();
assert_eq!(file.metadata().unwrap().len(), bytes.len() as u64);
// Test opening, reading and closing a file.
let mut file = File::open(&path).unwrap();
let mut contents = Vec::new();