Skip to content

Commit

Permalink
Auto merge of #3770 - oli-obk:duplicator, r=oli-obk
Browse files Browse the repository at this point in the history
Some FileDescriptor/FileDescription refactorings

follow-up to #3763 (comment)

I opted not to change the method names, as I think they are already pretty good (and the common one is the short name), and the docs should explain what they actually do, but if you feel like the names you proposed would be better, I'll just do that.
  • Loading branch information
bors committed Jul 30, 2024
2 parents 3fbdc82 + 1ecd186 commit e9a390a
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 33 deletions.
30 changes: 17 additions & 13 deletions src/shims/unix/fd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,13 @@ impl FileDescription for NullOutput {
}

#[derive(Clone, Debug)]
pub struct FileDescriptor(Rc<RefCell<Box<dyn FileDescription>>>);
pub struct FileDescriptionRef(Rc<RefCell<Box<dyn FileDescription>>>);

impl FileDescriptionRef {
fn new(fd: impl FileDescription) -> Self {
FileDescriptionRef(Rc::new(RefCell::new(Box::new(fd))))
}

impl FileDescriptor {
pub fn borrow(&self) -> Ref<'_, dyn FileDescription> {
Ref::map(self.0.borrow(), |fd| fd.as_ref())
}
Expand All @@ -221,7 +225,7 @@ impl FileDescriptor {
/// The file descriptor table
#[derive(Debug)]
pub struct FdTable {
pub fds: BTreeMap<i32, FileDescriptor>,
fds: BTreeMap<i32, FileDescriptionRef>,
}

impl VisitProvenance for FdTable {
Expand All @@ -247,14 +251,14 @@ impl FdTable {
fds
}

/// Insert a file descriptor to the FdTable.
pub fn insert_fd<T: FileDescription>(&mut self, fd: T) -> i32 {
let file_handle = FileDescriptor(Rc::new(RefCell::new(Box::new(fd))));
/// Insert a new file description to the FdTable.
pub fn insert_fd(&mut self, fd: impl FileDescription) -> i32 {
let file_handle = FileDescriptionRef::new(fd);
self.insert_fd_with_min_fd(file_handle, 0)
}

/// Insert a new FD that is at least `min_fd`.
pub fn insert_fd_with_min_fd(&mut self, file_handle: FileDescriptor, min_fd: i32) -> i32 {
fn insert_fd_with_min_fd(&mut self, file_handle: FileDescriptionRef, min_fd: i32) -> i32 {
// Find the lowest unused FD, starting from min_fd. If the first such unused FD is in
// between used FDs, the find_map combinator will return it. If the first such unused FD
// is after all other used FDs, the find_map combinator will return None, and we will use
Expand Down Expand Up @@ -290,12 +294,12 @@ impl FdTable {
Some(fd.borrow_mut())
}

pub fn dup(&self, fd: i32) -> Option<FileDescriptor> {
pub fn dup(&self, fd: i32) -> Option<FileDescriptionRef> {
let fd = self.fds.get(&fd)?;
Some(fd.clone())
}

pub fn remove(&mut self, fd: i32) -> Option<FileDescriptor> {
pub fn remove(&mut self, fd: i32) -> Option<FileDescriptionRef> {
self.fds.remove(&fd)
}

Expand Down Expand Up @@ -324,9 +328,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
if new_fd != old_fd {
// Close new_fd if it is previously opened.
// If old_fd and new_fd point to the same description, then `dup_fd` ensures we keep the underlying file description alive.
if let Some(file_descriptor) = this.machine.fds.fds.insert(new_fd, dup_fd) {
if let Some(file_description) = this.machine.fds.fds.insert(new_fd, dup_fd) {
// Ignore close error (not interpreter's) according to dup2() doc.
file_descriptor.close(this.machine.communicate())?.ok();
file_description.close(this.machine.communicate())?.ok();
}
}
Ok(new_fd)
Expand Down Expand Up @@ -427,10 +431,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {

let fd = this.read_scalar(fd_op)?.to_i32()?;

let Some(file_descriptor) = this.machine.fds.remove(fd) else {
let Some(file_description) = this.machine.fds.remove(fd) else {
return Ok(Scalar::from_i32(this.fd_not_found()?));
};
let result = file_descriptor.close(this.machine.communicate())?;
let result = file_description.close(this.machine.communicate())?;
// return `0` if close is successful
let result = result.map(|()| 0i32);
Ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
Expand Down
40 changes: 20 additions & 20 deletions src/shims/unix/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -576,13 +576,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {

let communicate = this.machine.communicate();

let Some(mut file_descriptor) = this.machine.fds.get_mut(fd) else {
let Some(mut file_description) = this.machine.fds.get_mut(fd) else {
return Ok(Scalar::from_i64(this.fd_not_found()?));
};
let result = file_descriptor
let result = file_description
.seek(communicate, seek_from)?
.map(|offset| i64::try_from(offset).unwrap());
drop(file_descriptor);
drop(file_description);

let result = this.try_unwrap_io_result(result)?;
Ok(Scalar::from_i64(result))
Expand Down Expand Up @@ -1269,30 +1269,30 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
return Ok(Scalar::from_i32(this.fd_not_found()?));
}

let Some(file_descriptor) = this.machine.fds.get(fd) else {
let Some(file_description) = this.machine.fds.get(fd) else {
return Ok(Scalar::from_i32(this.fd_not_found()?));
};

// FIXME: Support ftruncate64 for all FDs
let FileHandle { file, writable } =
file_descriptor.downcast_ref::<FileHandle>().ok_or_else(|| {
file_description.downcast_ref::<FileHandle>().ok_or_else(|| {
err_unsup_format!("`ftruncate64` is only supported on file-backed file descriptors")
})?;

if *writable {
if let Ok(length) = length.try_into() {
let result = file.set_len(length);
drop(file_descriptor);
drop(file_description);
let result = this.try_unwrap_io_result(result.map(|_| 0i32))?;
Ok(Scalar::from_i32(result))
} else {
drop(file_descriptor);
drop(file_description);
let einval = this.eval_libc("EINVAL");
this.set_last_error(einval)?;
Ok(Scalar::from_i32(-1))
}
} else {
drop(file_descriptor);
drop(file_description);
// The file is not writable
let einval = this.eval_libc("EINVAL");
this.set_last_error(einval)?;
Expand Down Expand Up @@ -1322,16 +1322,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {

fn ffullsync_fd(&mut self, fd: i32) -> InterpResult<'tcx, i32> {
let this = self.eval_context_mut();
let Some(file_descriptor) = this.machine.fds.get(fd) else {
let Some(file_description) = this.machine.fds.get(fd) else {
return Ok(this.fd_not_found()?);
};
// Only regular files support synchronization.
let FileHandle { file, writable } =
file_descriptor.downcast_ref::<FileHandle>().ok_or_else(|| {
file_description.downcast_ref::<FileHandle>().ok_or_else(|| {
err_unsup_format!("`fsync` is only supported on file-backed file descriptors")
})?;
let io_result = maybe_sync_file(file, *writable, File::sync_all);
drop(file_descriptor);
drop(file_description);
this.try_unwrap_io_result(io_result)
}

Expand All @@ -1347,16 +1347,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
return this.fd_not_found();
}

let Some(file_descriptor) = this.machine.fds.get(fd) else {
let Some(file_description) = this.machine.fds.get(fd) else {
return Ok(this.fd_not_found()?);
};
// Only regular files support synchronization.
let FileHandle { file, writable } =
file_descriptor.downcast_ref::<FileHandle>().ok_or_else(|| {
file_description.downcast_ref::<FileHandle>().ok_or_else(|| {
err_unsup_format!("`fdatasync` is only supported on file-backed file descriptors")
})?;
let io_result = maybe_sync_file(file, *writable, File::sync_data);
drop(file_descriptor);
drop(file_description);
this.try_unwrap_io_result(io_result)
}

Expand Down Expand Up @@ -1395,18 +1395,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
return Ok(Scalar::from_i32(this.fd_not_found()?));
}

let Some(file_descriptor) = this.machine.fds.get(fd) else {
let Some(file_description) = this.machine.fds.get(fd) else {
return Ok(Scalar::from_i32(this.fd_not_found()?));
};
// Only regular files support synchronization.
let FileHandle { file, writable } =
file_descriptor.downcast_ref::<FileHandle>().ok_or_else(|| {
file_description.downcast_ref::<FileHandle>().ok_or_else(|| {
err_unsup_format!(
"`sync_data_range` is only supported on file-backed file descriptors"
)
})?;
let io_result = maybe_sync_file(file, *writable, File::sync_data);
drop(file_descriptor);
drop(file_description);
Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?))
}

Expand Down Expand Up @@ -1702,11 +1702,11 @@ impl FileMetadata {
ecx: &mut MiriInterpCx<'tcx>,
fd: i32,
) -> InterpResult<'tcx, Option<FileMetadata>> {
let Some(file_descriptor) = ecx.machine.fds.get(fd) else {
let Some(file_description) = ecx.machine.fds.get(fd) else {
return ecx.fd_not_found().map(|_: i32| None);
};

let file = &file_descriptor
let file = &file_description
.downcast_ref::<FileHandle>()
.ok_or_else(|| {
err_unsup_format!(
Expand All @@ -1716,7 +1716,7 @@ impl FileMetadata {
.file;

let metadata = file.metadata();
drop(file_descriptor);
drop(file_description);
FileMetadata::from_meta(ecx, metadata)
}

Expand Down

0 comments on commit e9a390a

Please sign in to comment.