forked from Rust-related/RustPython
101 lines
3.2 KiB
Rust
101 lines
3.2 KiB
Rust
pub(crate) use grp::make_module;
|
|
|
|
#[pymodule]
|
|
mod grp {
|
|
use crate::vm::{
|
|
builtins::{PyIntRef, PyListRef, PyStrRef},
|
|
convert::{IntoPyException, ToPyObject},
|
|
exceptions,
|
|
types::PyStructSequence,
|
|
PyObjectRef, PyResult, VirtualMachine,
|
|
};
|
|
use nix::unistd;
|
|
use std::ptr::NonNull;
|
|
|
|
#[pyattr]
|
|
#[pyclass(module = "grp", name = "struct_group", traverse)]
|
|
#[derive(PyStructSequence)]
|
|
struct Group {
|
|
#[pytraverse(skip)]
|
|
gr_name: String,
|
|
#[pytraverse(skip)]
|
|
gr_passwd: String,
|
|
#[pytraverse(skip)]
|
|
gr_gid: u32,
|
|
gr_mem: PyListRef,
|
|
}
|
|
#[pyclass(with(PyStructSequence))]
|
|
impl Group {
|
|
fn from_unistd_group(group: unistd::Group, vm: &VirtualMachine) -> Self {
|
|
let cstr_lossy = |s: std::ffi::CString| {
|
|
s.into_string()
|
|
.unwrap_or_else(|e| e.into_cstring().to_string_lossy().into_owned())
|
|
};
|
|
Group {
|
|
gr_name: group.name,
|
|
gr_passwd: cstr_lossy(group.passwd),
|
|
gr_gid: group.gid.as_raw(),
|
|
gr_mem: vm
|
|
.ctx
|
|
.new_list(group.mem.iter().map(|s| s.to_pyobject(vm)).collect()),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[pyfunction]
|
|
fn getgrgid(gid: PyIntRef, vm: &VirtualMachine) -> PyResult<Group> {
|
|
let gr_gid = gid.as_bigint();
|
|
let gid = libc::gid_t::try_from(gr_gid)
|
|
.map(unistd::Gid::from_raw)
|
|
.ok();
|
|
let group = gid
|
|
.map(unistd::Group::from_gid)
|
|
.transpose()
|
|
.map_err(|err| err.into_pyexception(vm))?
|
|
.flatten();
|
|
let group = group.ok_or_else(|| {
|
|
vm.new_key_error(
|
|
vm.ctx
|
|
.new_str(format!("getgrgid: group id {gr_gid} not found"))
|
|
.into(),
|
|
)
|
|
})?;
|
|
Ok(Group::from_unistd_group(group, vm))
|
|
}
|
|
|
|
#[pyfunction]
|
|
fn getgrnam(name: PyStrRef, vm: &VirtualMachine) -> PyResult<Group> {
|
|
let gr_name = name.as_str();
|
|
if gr_name.contains('\0') {
|
|
return Err(exceptions::cstring_error(vm));
|
|
}
|
|
let group = unistd::Group::from_name(gr_name).map_err(|err| err.into_pyexception(vm))?;
|
|
let group = group.ok_or_else(|| {
|
|
vm.new_key_error(
|
|
vm.ctx
|
|
.new_str(format!("getgrnam: group name {gr_name} not found"))
|
|
.into(),
|
|
)
|
|
})?;
|
|
Ok(Group::from_unistd_group(group, vm))
|
|
}
|
|
|
|
#[pyfunction]
|
|
fn getgrall(vm: &VirtualMachine) -> PyResult<Vec<PyObjectRef>> {
|
|
// setgrent, getgrent, etc are not thread safe. Could use fgetgrent_r, but this is easier
|
|
static GETGRALL: parking_lot::Mutex<()> = parking_lot::const_mutex(());
|
|
let _guard = GETGRALL.lock();
|
|
let mut list = Vec::new();
|
|
|
|
unsafe { libc::setgrent() };
|
|
while let Some(ptr) = NonNull::new(unsafe { libc::getgrent() }) {
|
|
let group = unistd::Group::from(unsafe { ptr.as_ref() });
|
|
let group = Group::from_unistd_group(group, vm).to_pyobject(vm);
|
|
list.push(group);
|
|
}
|
|
unsafe { libc::endgrent() };
|
|
|
|
Ok(list)
|
|
}
|
|
}
|