|
2 | 2 |
|
3 | 3 | use std::borrow::Cow;
|
4 | 4 | use std::fs::{
|
5 |
| - DirBuilder, File, FileType, Metadata, OpenOptions, ReadDir, read_dir, remove_dir, remove_file, |
6 |
| - rename, |
| 5 | + DirBuilder, File, FileType, Metadata, OpenOptions, Permissions, ReadDir, read_dir, remove_dir, |
| 6 | + remove_file, rename, |
7 | 7 | };
|
8 | 8 | use std::io::{self, ErrorKind, IsTerminal, Read, Seek, SeekFrom, Write};
|
9 | 9 | use std::path::{Path, PathBuf};
|
@@ -1664,6 +1664,75 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
1664 | 1664 | // We ran out of attempts to create the file, return an error.
|
1665 | 1665 | this.set_last_error_and_return_i32(LibcError("EEXIST"))
|
1666 | 1666 | }
|
| 1667 | + |
| 1668 | + fn chmod(&mut self, path_op: &OpTy<'tcx>, perm_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { |
| 1669 | + let this = self.eval_context_mut(); |
| 1670 | + |
| 1671 | + // Permissions::from_mode is Unix-specific. |
| 1672 | + this.assert_target_os_is_unix("chmod"); |
| 1673 | + |
| 1674 | + #[cfg(unix)] |
| 1675 | + { |
| 1676 | + use std::os::unix::fs::PermissionsExt; |
| 1677 | + |
| 1678 | + let pathname = this.read_path_from_c_str(this.read_pointer(path_op)?)?; |
| 1679 | + let perm = this.read_scalar(perm_op)?.to_u32()?; |
| 1680 | + |
| 1681 | + // Reject if isolation is enabled. |
| 1682 | + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { |
| 1683 | + this.reject_in_isolation("`chmod`", reject_with)?; |
| 1684 | + return this.set_last_error_and_return_i32(LibcError("EACCES")); |
| 1685 | + } |
| 1686 | + |
| 1687 | + let result = std::fs::set_permissions(pathname, Permissions::from_mode(perm)); |
| 1688 | + let result = this.try_unwrap_io_result(result.map(|_| 0i32))?; |
| 1689 | + |
| 1690 | + interp_ok(Scalar::from_i32(result)) |
| 1691 | + } |
| 1692 | + #[cfg(not(unix))] |
| 1693 | + { |
| 1694 | + unreachable!() |
| 1695 | + } |
| 1696 | + } |
| 1697 | + |
| 1698 | + fn fchmod(&mut self, fd_op: &OpTy<'tcx>, perm_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { |
| 1699 | + let this = self.eval_context_mut(); |
| 1700 | + |
| 1701 | + // `Permissions::from_mode` is Unix-specific. |
| 1702 | + this.assert_target_os_is_unix("fchmod"); |
| 1703 | + |
| 1704 | + #[cfg(unix)] |
| 1705 | + { |
| 1706 | + use std::os::unix::fs::PermissionsExt; |
| 1707 | + |
| 1708 | + let fd = this.read_scalar(fd_op)?.to_i32()?; |
| 1709 | + let perm = this.read_scalar(perm_op)?.to_u32()?; |
| 1710 | + |
| 1711 | + // Reject if isolation is enabled. |
| 1712 | + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { |
| 1713 | + this.reject_in_isolation("`fchmod`", reject_with)?; |
| 1714 | + // Set error code as "EBADF" (bad fd) |
| 1715 | + return this.set_last_error_and_return_i32(LibcError("EBADF")); |
| 1716 | + } |
| 1717 | + |
| 1718 | + let Some(fd) = this.machine.fds.get(fd) else { |
| 1719 | + return this.set_last_error_and_return_i32(LibcError("EBADF")); |
| 1720 | + }; |
| 1721 | + |
| 1722 | + let file = fd.downcast::<FileHandle>().ok_or_else(|| { |
| 1723 | + err_unsup_format!("`fchmod` is only supported on file-backed file descriptors") |
| 1724 | + })?; |
| 1725 | + |
| 1726 | + let result = file.file.set_permissions(Permissions::from_mode(perm)); |
| 1727 | + let result = this.try_unwrap_io_result(result.map(|_| 0i32))?; |
| 1728 | + |
| 1729 | + interp_ok(Scalar::from_i32(result)) |
| 1730 | + } |
| 1731 | + #[cfg(not(unix))] |
| 1732 | + { |
| 1733 | + unreachable!() |
| 1734 | + } |
| 1735 | + } |
1667 | 1736 | }
|
1668 | 1737 |
|
1669 | 1738 | /// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch when
|
|
0 commit comments