mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-02 19:39:49 +09:00
os: Implement (f)pathconf
Implement pathconf and fpathconf using libc::pathconf. os.pathconf_names is not implemented.
This commit is contained in:
29
Cargo.lock
generated
29
Cargo.lock
generated
@@ -898,6 +898,15 @@ version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.18"
|
||||
@@ -2082,6 +2091,8 @@ dependencies = [
|
||||
"socket2",
|
||||
"sre-engine",
|
||||
"static_assertions",
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"system-configuration",
|
||||
"termios",
|
||||
"thiserror",
|
||||
@@ -2360,6 +2371,24 @@ version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aaf86bbcfd1fa9670b7a129f64fc0c9fcbbfe4f1bc4210e9e98fe71ffc12cde2"
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.21.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d06aaeeee809dbc59eb4556183dd927df67db1540de5be8d3ec0b6636358a5ec"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.4.0"
|
||||
|
||||
@@ -117,6 +117,8 @@ rustpython-common = { path = "../common" }
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
exitcode = "1.1.2"
|
||||
uname = "0.1.1"
|
||||
strum = "0.21"
|
||||
strum_macros = "0.21"
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
gethostname = "0.2.0"
|
||||
|
||||
@@ -10,6 +10,8 @@ use std::{env, fs};
|
||||
use crate::crt_fd::Fd;
|
||||
use crossbeam_utils::atomic::AtomicCell;
|
||||
use num_bigint::BigInt;
|
||||
#[cfg(unix)]
|
||||
use strum_macros::EnumString;
|
||||
|
||||
use super::errno::errors;
|
||||
use crate::builtins::bytes::{PyBytes, PyBytesRef};
|
||||
@@ -1645,6 +1647,232 @@ mod _os {
|
||||
#[pyimpl(with(PyStructSequence))]
|
||||
impl UnameResult {}
|
||||
|
||||
enum NameOrVal {
|
||||
Name(String),
|
||||
Val(i32),
|
||||
}
|
||||
|
||||
impl TryFromObject for NameOrVal {
|
||||
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
|
||||
match obj.downcast::<int::PyInt>() {
|
||||
Ok(int) => int::try_to_primitive(int.as_bigint(), vm).map(Self::Val),
|
||||
Err(obj) => {
|
||||
let cstring = std::ffi::CString::try_from_object(vm, obj)?;
|
||||
cstring.into_string().map(Self::Name).map_err(|e| {
|
||||
vm.new_os_error(format!("error while parsing string: {:?}", e))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy from [nix::unistd::PathconfVar](https://docs.rs/nix/0.21.0/nix/unistd/enum.PathconfVar.html)
|
||||
// Change enum name to fit python doc
|
||||
#[cfg(unix)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, EnumString)]
|
||||
#[repr(i32)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum PathconfVar {
|
||||
#[cfg(any(
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "redox"
|
||||
))]
|
||||
/// Minimum number of bits needed to represent, as a signed integer value,
|
||||
/// the maximum size of a regular file allowed in the specified directory.
|
||||
PC_FILESIZEBITS = libc::_PC_FILESIZEBITS,
|
||||
/// Maximum number of links to a single file.
|
||||
PC_LINK_MAX = libc::_PC_LINK_MAX,
|
||||
/// Maximum number of bytes in a terminal canonical input line.
|
||||
PC_MAX_CANON = libc::_PC_MAX_CANON,
|
||||
/// Minimum number of bytes for which space is available in a terminal input
|
||||
/// queue; therefore, the maximum number of bytes a conforming application
|
||||
/// may require to be typed as input before reading them.
|
||||
PC_MAX_INPUT = libc::_PC_MAX_INPUT,
|
||||
/// Maximum number of bytes in a filename (not including the terminating
|
||||
/// null of a filename string).
|
||||
PC_NAME_MAX = libc::_PC_NAME_MAX,
|
||||
/// Maximum number of bytes the implementation will store as a pathname in a
|
||||
/// user-supplied buffer of unspecified size, including the terminating null
|
||||
/// character. Minimum number the implementation will accept as the maximum
|
||||
/// number of bytes in a pathname.
|
||||
PC_PATH_MAX = libc::_PC_PATH_MAX,
|
||||
/// Maximum number of bytes that is guaranteed to be atomic when writing to
|
||||
/// a pipe.
|
||||
PC_PIPE_BUF = libc::_PC_PIPE_BUF,
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "illumos",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "redox",
|
||||
target_os = "solaris"
|
||||
))]
|
||||
/// Symbolic links can be created.
|
||||
PC_2_SYMLINKS = libc::_PC_2_SYMLINKS,
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "linux",
|
||||
target_os = "openbsd",
|
||||
target_os = "redox"
|
||||
))]
|
||||
/// Minimum number of bytes of storage actually allocated for any portion of
|
||||
/// a file.
|
||||
PC_ALLOC_SIZE_MIN = libc::_PC_ALLOC_SIZE_MIN,
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "linux",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
/// Recommended increment for file transfer sizes between the
|
||||
/// `POSIX_REC_MIN_XFER_SIZE` and `POSIX_REC_MAX_XFER_SIZE` values.
|
||||
PC_REC_INCR_XFER_SIZE = libc::_PC_REC_INCR_XFER_SIZE,
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "linux",
|
||||
target_os = "openbsd",
|
||||
target_os = "redox"
|
||||
))]
|
||||
/// Maximum recommended file transfer size.
|
||||
PC_REC_MAX_XFER_SIZE = libc::_PC_REC_MAX_XFER_SIZE,
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "linux",
|
||||
target_os = "openbsd",
|
||||
target_os = "redox"
|
||||
))]
|
||||
/// Minimum recommended file transfer size.
|
||||
PC_REC_MIN_XFER_SIZE = libc::_PC_REC_MIN_XFER_SIZE,
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "linux",
|
||||
target_os = "openbsd",
|
||||
target_os = "redox"
|
||||
))]
|
||||
/// Recommended file transfer buffer alignment.
|
||||
PC_REC_XFER_ALIGN = libc::_PC_REC_XFER_ALIGN,
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "illumos",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "redox",
|
||||
target_os = "solaris"
|
||||
))]
|
||||
/// Maximum number of bytes in a symbolic link.
|
||||
PC_SYMLINK_MAX = libc::_PC_SYMLINK_MAX,
|
||||
/// The use of `chown` and `fchown` is restricted to a process with
|
||||
/// appropriate privileges, and to changing the group ID of a file only to
|
||||
/// the effective group ID of the process or to one of its supplementary
|
||||
/// group IDs.
|
||||
PC_CHOWN_RESTRICTED = libc::_PC_CHOWN_RESTRICTED,
|
||||
/// Pathname components longer than {NAME_MAX} generate an error.
|
||||
PC_NO_TRUNC = libc::_PC_NO_TRUNC,
|
||||
/// This symbol shall be defined to be the value of a character that shall
|
||||
/// disable terminal special character handling.
|
||||
PC_VDISABLE = libc::_PC_VDISABLE,
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "illumos",
|
||||
target_os = "linux",
|
||||
target_os = "openbsd",
|
||||
target_os = "redox",
|
||||
target_os = "solaris"
|
||||
))]
|
||||
/// Asynchronous input or output operations may be performed for the
|
||||
/// associated file.
|
||||
PC_ASYNC_IO = libc::_PC_ASYNC_IO,
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "illumos",
|
||||
target_os = "linux",
|
||||
target_os = "openbsd",
|
||||
target_os = "redox",
|
||||
target_os = "solaris"
|
||||
))]
|
||||
/// Prioritized input or output operations may be performed for the
|
||||
/// associated file.
|
||||
PC_PRIO_IO = libc::_PC_PRIO_IO,
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "dragonfly",
|
||||
target_os = "freebsd",
|
||||
target_os = "illumos",
|
||||
target_os = "linux",
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "redox",
|
||||
target_os = "solaris"
|
||||
))]
|
||||
/// Synchronized input or output operations may be performed for the
|
||||
/// associated file.
|
||||
PC_SYNC_IO = libc::_PC_SYNC_IO,
|
||||
#[cfg(any(target_os = "dragonfly", target_os = "openbsd"))]
|
||||
/// The resolution in nanoseconds for all file timestamps.
|
||||
PC_TIMESTAMP_RESOLUTION = libc::_PC_TIMESTAMP_RESOLUTION,
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[pyfunction]
|
||||
fn pathconf(path: PathOrFd, name: NameOrVal, vm: &VirtualMachine) -> PyResult<Option<i64>> {
|
||||
use nix::errno::{self, Errno};
|
||||
use std::str::FromStr;
|
||||
let name = match name {
|
||||
NameOrVal::Name(s) => PathconfVar::from_str(&s)
|
||||
.map_err(|_| vm.new_value_error("unrecognized configuration name".to_string()))?
|
||||
as i32,
|
||||
NameOrVal::Val(v) => v,
|
||||
};
|
||||
|
||||
Errno::clear();
|
||||
let raw = match path {
|
||||
PathOrFd::Path(path) => {
|
||||
let path = ffi::CString::new(path.into_bytes())
|
||||
.map_err(|_| vm.new_value_error("embedded null character".to_owned()))?;
|
||||
unsafe { libc::pathconf(path.as_ptr(), name) }
|
||||
}
|
||||
PathOrFd::Fd(fd) => unsafe { libc::fpathconf(fd, name) },
|
||||
};
|
||||
|
||||
if raw == -1 {
|
||||
if errno::errno() == 0 {
|
||||
Ok(None)
|
||||
} else {
|
||||
Err(io::Error::from(Errno::last()).into_pyexception(vm))
|
||||
}
|
||||
} else {
|
||||
Ok(Some(raw))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[pyfunction]
|
||||
fn fpathconf(fd: i32, name: NameOrVal, vm: &VirtualMachine) -> PyResult<Option<i64>> {
|
||||
pathconf(PathOrFd::Fd(fd), name, vm)
|
||||
}
|
||||
|
||||
pub(super) fn support_funcs() -> Vec<SupportFunc> {
|
||||
let mut supports = super::platform::support_funcs();
|
||||
supports.extend(vec![
|
||||
@@ -1656,7 +1884,8 @@ mod _os {
|
||||
SupportFunc::new("mkdir", Some(false), Some(MKDIR_DIR_FD), Some(false)),
|
||||
// mkfifo Some Some None
|
||||
// mknod Some Some None
|
||||
// pathconf Some None None
|
||||
#[cfg(unix)]
|
||||
SupportFunc::new("pathconf", Some(true), None, None),
|
||||
SupportFunc::new("readlink", Some(false), None, Some(false)),
|
||||
SupportFunc::new("remove", Some(false), None, Some(false)),
|
||||
SupportFunc::new("unlink", Some(false), None, Some(false)),
|
||||
|
||||
Reference in New Issue
Block a user