Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 14 additions & 11 deletions crates/host_env/src/posix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use std::os::fd::{AsFd, AsRawFd, BorrowedFd, IntoRawFd, OwnedFd};
use std::path::Path;

pub use super::posix_unix_like::*;
pub use crate::os::{AccessMode, F_OK, R_OK, W_OK, X_OK};

pub use libc::{c_char, pid_t};

Expand Down Expand Up @@ -947,23 +948,24 @@ pub fn get_number_of_os_threads() -> isize {
0
}

#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita",))]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Permissions {
pub is_readable: bool,
pub is_writable: bool,
pub is_executable: bool,
}

pub use crate::os::{AccessMode, F_OK, R_OK, W_OK, X_OK};

fn get_permissions(mode: u32) -> Permissions {
#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita",))]
const fn get_permissions(mode: u32) -> Permissions {
Permissions {
is_readable: mode & 4 != 0,
is_writable: mode & 2 != 0,
is_executable: mode & 1 != 0,
}
}

#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita",))]
pub fn get_right_permission(
mode: u32,
file_owner: u32,
Expand Down Expand Up @@ -1026,29 +1028,30 @@ pub fn check_access(
mode: u8,
effective_ids: bool,
follow_symlinks: bool,
) -> Result<bool, AccessError> {
) -> bool {
Comment thread
joshuamegnauth54 marked this conversation as resolved.
Resolved
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
use std::os::unix::fs::MetadataExt;

let Some(mode) = AccessMode::from_bits(mode) else {
return Err(AccessError::InvalidMode);
return false;
};

let metadata = match crate::fs::metadata(path) {
Ok(m) => m,
Err(_) => return Ok(false),
let Ok(metadata) = crate::fs::metadata(path) else {
return false;
};

if mode.is_empty() {
return Ok(true);
return true;
}

let perm = get_right_permission(metadata.mode(), metadata.uid(), metadata.gid())?;
let Ok(perm) = get_right_permission(metadata.mode(), metadata.uid(), metadata.gid()) else {
return false;
};

let r_ok = !mode.contains(&crate::os::AccessFlag::R) || perm.is_readable;
let w_ok = !mode.contains(&crate::os::AccessFlag::W) || perm.is_writable;
let x_ok = !mode.contains(&crate::os::AccessFlag::X) || perm.is_executable;

Ok(r_ok && w_ok && x_ok)
r_ok && w_ok && x_ok
}

pub fn close_fds(above: i32, keep: &[BorrowedFd<'_>]) {
Expand Down
6 changes: 3 additions & 3 deletions crates/host_env/src/posix_unix_like.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ pub fn check_access(
access: u8,
#[cfg_attr(target_os = "android", expect(unused))] effective_ids: bool,
follow_symlinks: bool,
) -> Result<bool, AccessError> {
) -> bool {
let dir_fd = dir_fd.as_ref().map_or(fs::CWD, AsFd::as_fd);
let access = Access::from_bits(access as _).ok_or(AccessError::InvalidMode)?;
let access = Access::from_bits_retain(access as _);

#[cfg(not(target_os = "android"))]
let flags = if effective_ids {
Expand All @@ -50,7 +50,7 @@ pub fn check_access(
});

// CPython returns false for all error codes.
Ok(fs::accessat(dir_fd, path.as_ref(), access, flags).is_ok())
fs::accessat(dir_fd, path.as_ref(), access, flags).is_ok()
}

/// https://pubs.opengroup.org/onlinepubs/9799919799/functions/mkdir.html
Expand Down
12 changes: 0 additions & 12 deletions crates/vm/src/exceptions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1652,18 +1652,6 @@ impl ToPyException for rustpython_host_env::fcntl::LockfError {
}
}

#[cfg(unix)]
impl ToPyException for rustpython_host_env::posix::AccessError {
fn to_pyexception(&self, vm: &VirtualMachine) -> PyBaseExceptionRef {
match self {
Self::InvalidMode => vm.new_value_error(
"One of the flags is wrong, there are only 4 possibilities F_OK, R_OK, W_OK and X_OK",
),
Self::Os(errno) => std::io::Error::from_raw_os_error(*errno).to_pyexception(vm),
}
}
}

#[cfg(all(unix, not(target_os = "redox")))]
impl ToPyException for rustpython_host_env::socket::AncillaryPackError {
fn to_pyexception(&self, vm: &VirtualMachine) -> PyBaseExceptionRef {
Expand Down
13 changes: 8 additions & 5 deletions crates/vm/src/stdlib/posix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub mod module {
use crate::{
AsObject, Py, PyObject, PyObjectRef, PyResult, VirtualMachine,
builtins::{PyBytesRef, PyDictRef, PyInt, PyListRef, PyTuple, PyTupleRef, PyUtf8Str},
convert::{IntoPyException, ToPyException, ToPyObject, TryFromObject},
convert::{IntoPyException, ToPyObject, TryFromObject},
exceptions::OSErrorBuilder,
function::{ArgBytesLike, ArgMapping, Either, OptionalArg, PySsize},
ospath::{OsPath, OsPathOrFd},
Expand Down Expand Up @@ -398,8 +398,12 @@ pub mod module {
.collect())
}

#[allow(clippy::unnecessary_wraps)]
#[pyfunction]
pub(super) fn access(args: AccessArgs<'_>, vm: &VirtualMachine) -> PyResult<bool> {
pub(super) fn access(
args: AccessArgs<'_>,
#[allow(unused_variables)] vm: &VirtualMachine,
) -> PyResult<bool> {
#[cfg(any(
target_os = "android",
target_os = "espidf",
Expand Down Expand Up @@ -439,14 +443,13 @@ pub mod module {
)))]
let dir_fd = None;

rustpython_host_env::posix::check_access(
Ok(rustpython_host_env::posix::check_access(
dir_fd,
args.path.as_ref(),
args.mode,
args.effective_ids,
args.follow_symlinks.0,
)
.map_err(|err| err.to_pyexception(vm))
))
}

#[pyfunction]
Expand Down
6 changes: 6 additions & 0 deletions extra_tests/snippets/stdlib_os.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import os
import stat
import sys
import tempfile
import time

from testutils import assert_raises
Expand Down Expand Up @@ -640,6 +641,11 @@ def __exit__(self, exc_type, exc_val, exc_tb):
assert os.access("README.md", os.F_OK) is True
assert os.access("README.md", os.R_OK) is True

# os.access - CPython returns False for invalid modes for Unix
if os.name != "nt":
with tempfile.NamedTemporaryFile() as tmp:
assert not os.access(tmp.name, 255)

# argv and the group list are sequences; an arbitrary iterable must be rejected
# rather than drained.
if hasattr(os, "posix_spawn"):
Expand Down
Loading