Merge pull request #2001 from RustPython/coolreader18/update-pwd

Update the pwd module
This commit is contained in:
Jeong YunWon authored and GitHub committed 2020-07-17 15:47:04 +09:00
commit 2d31f4e7c8
7 files changed
+211 -154

No files matched your search

Generated
+10 -83
View File
@@ -104,28 +104,6 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
[[package]]
name = "backtrace"
version = "0.3.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4ed64ae6d9ebfd9893193c4b2532b1292ec97bd8271c9d7d0fa90cd78a34cba"
dependencies = [
"backtrace-sys",
"cfg-if",
"libc",
"rustc-demangle",
]
[[package]]
name = "backtrace-sys"
version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7de8aba10a69c8e8d7622c5710229485ec32e9d55fdad160ea559c086fdcd118"
dependencies = [
"cc",
"libc",
]
[[package]]
name = "base64"
version = "0.11.0"
@@ -532,28 +510,6 @@ version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de853764b47027c2e862a995c34978ffa63c1501f2e15f987ba11bd4f9bba193"
[[package]]
name = "failure"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8529c2421efa3066a5cbd8063d2244603824daccb6936b079010bb2aa89464b"
dependencies = [
"backtrace",
"failure_derive",
]
[[package]]
name = "failure_derive"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "030a733c8287d6213886dd487564ff5c8f6aae10278b3588ed177f9d18f8d231"
dependencies = [
"proc-macro2 1.0.10",
"quote 1.0.3",
"syn 1.0.17",
"synstructure",
]
[[package]]
name = "fake-simd"
version = "0.1.2"
@@ -964,9 +920,9 @@ checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
[[package]]
name = "num-bigint"
version = "0.2.6"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304"
checksum = "b7f3fc75e3697059fb1bc465e3d8cca6cf92f56854f201158b3f9c77d5a3cfa0"
dependencies = [
"autocfg 1.0.0",
"num-integer",
@@ -987,9 +943,9 @@ dependencies = [
[[package]]
name = "num-integer"
version = "0.1.42"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba"
checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b"
dependencies = [
"autocfg 1.0.0",
"num-traits",
@@ -997,9 +953,9 @@ dependencies = [
[[package]]
name = "num-iter"
version = "0.1.40"
version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfb0800a0291891dd9f4fe7bd9c19384f98f7fbe0cd0f39a2c6b88b9868bbc00"
checksum = "7a6e6b7c748f995c4c29c5f5ae0248536e04a5739927c74ec0fa564805094b9f"
dependencies = [
"autocfg 1.0.0",
"num-integer",
@@ -1008,9 +964,9 @@ dependencies = [
[[package]]
name = "num-rational"
version = "0.2.4"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef"
checksum = "a5b4d7360f362cfb50dde8143501e6940b22f644be75a4cc90b2d81968908138"
dependencies = [
"autocfg 1.0.0",
"num-bigint",
@@ -1020,9 +976,9 @@ dependencies = [
[[package]]
name = "num-traits"
version = "0.2.11"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
dependencies = [
"autocfg 1.0.0",
]
@@ -1259,16 +1215,6 @@ dependencies = [
"unicode-xid 0.2.0",
]
[[package]]
name = "pwd"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dd32d8bece608e144ca20251e714ed107cdecdabb20c2d383cfc687825106a5"
dependencies = [
"failure",
"libc",
]
[[package]]
name = "python3-sys"
version = "0.2.1"
@@ -1524,12 +1470,6 @@ dependencies = [
"crossbeam-utils",
]
[[package]]
name = "rustc-demangle"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
[[package]]
name = "rustc_version"
version = "0.2.3"
@@ -1685,7 +1625,6 @@ dependencies = [
"openssl-sys",
"parking_lot",
"paste",
"pwd",
"rand 0.7.3",
"rand_core 0.5.1",
"regex",
@@ -2001,18 +1940,6 @@ dependencies = [
"unicode-xid 0.2.0",
]
[[package]]
name = "synstructure"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545"
dependencies = [
"proc-macro2 1.0.10",
"quote 1.0.3",
"syn 1.0.17",
"unicode-xid 0.2.0",
]
[[package]]
name = "term"
version = "0.5.2"
+112
View File
@@ -0,0 +1,112 @@
import sys
import unittest
from test import support
pwd = support.import_module('pwd')
@unittest.skipUnless(hasattr(pwd, 'getpwall'), 'Does not have getpwall()')
class PwdTest(unittest.TestCase):
def test_values(self):
entries = pwd.getpwall()
for e in entries:
self.assertEqual(len(e), 7)
self.assertEqual(e[0], e.pw_name)
self.assertIsInstance(e.pw_name, str)
self.assertEqual(e[1], e.pw_passwd)
self.assertIsInstance(e.pw_passwd, str)
self.assertEqual(e[2], e.pw_uid)
self.assertIsInstance(e.pw_uid, int)
self.assertEqual(e[3], e.pw_gid)
self.assertIsInstance(e.pw_gid, int)
self.assertEqual(e[4], e.pw_gecos)
self.assertIsInstance(e.pw_gecos, str)
self.assertEqual(e[5], e.pw_dir)
self.assertIsInstance(e.pw_dir, str)
self.assertEqual(e[6], e.pw_shell)
self.assertIsInstance(e.pw_shell, str)
# The following won't work, because of duplicate entries
# for one uid
# self.assertEqual(pwd.getpwuid(e.pw_uid), e)
# instead of this collect all entries for one uid
# and check afterwards (done in test_values_extended)
def test_values_extended(self):
entries = pwd.getpwall()
entriesbyname = {}
entriesbyuid = {}
if len(entries) > 1000: # Huge passwd file (NIS?) -- skip this test
self.skipTest('passwd file is huge; extended test skipped')
for e in entries:
entriesbyname.setdefault(e.pw_name, []).append(e)
entriesbyuid.setdefault(e.pw_uid, []).append(e)
# check whether the entry returned by getpwuid()
# for each uid is among those from getpwall() for this uid
for e in entries:
if not e[0] or e[0] == '+':
continue # skip NIS entries etc.
self.assertIn(pwd.getpwnam(e.pw_name), entriesbyname[e.pw_name])
self.assertIn(pwd.getpwuid(e.pw_uid), entriesbyuid[e.pw_uid])
def test_errors(self):
self.assertRaises(TypeError, pwd.getpwuid)
self.assertRaises(TypeError, pwd.getpwuid, 3.14)
self.assertRaises(TypeError, pwd.getpwnam)
self.assertRaises(TypeError, pwd.getpwnam, 42)
self.assertRaises(TypeError, pwd.getpwall, 42)
# try to get some errors
bynames = {}
byuids = {}
for (n, p, u, g, gecos, d, s) in pwd.getpwall():
bynames[n] = u
byuids[u] = n
allnames = list(bynames.keys())
namei = 0
fakename = allnames[namei]
while fakename in bynames:
chars = list(fakename)
for i in range(len(chars)):
if chars[i] == 'z':
chars[i] = 'A'
break
elif chars[i] == 'Z':
continue
else:
chars[i] = chr(ord(chars[i]) + 1)
break
else:
namei = namei + 1
try:
fakename = allnames[namei]
except IndexError:
# should never happen... if so, just forget it
break
fakename = ''.join(chars)
self.assertRaises(KeyError, pwd.getpwnam, fakename)
# In some cases, byuids isn't a complete list of all users in the
# system, so if we try to pick a value not in byuids (via a perturbing
# loop, say), pwd.getpwuid() might still be able to find data for that
# uid. Using sys.maxint may provoke the same problems, but hopefully
# it will be a more repeatable failure.
fakeuid = sys.maxsize
self.assertNotIn(fakeuid, byuids)
self.assertRaises(KeyError, pwd.getpwuid, fakeuid)
# -1 shouldn't be a valid uid because it has a special meaning in many
# uid-related functions
self.assertRaises(KeyError, pwd.getpwuid, -1)
# should be out of uid_t range
self.assertRaises(KeyError, pwd.getpwuid, 2**128)
self.assertRaises(KeyError, pwd.getpwuid, -2**128)
if __name__ == "__main__":
unittest.main()
+1 -1
View File
@@ -12,7 +12,7 @@ license = "MIT"
bincode = "1.1"
bitflags = "1.1"
lz4-compress = "0.1.1"
num-bigint = { version = "0.2", features = ["serde"] }
num-bigint = { version = "0.3", features = ["serde"] }
num-complex = { version = "0.2", features = ["serde"] }
serde = { version = "1.0", features = ["derive"] }
itertools = "0.8"
+1 -1
View File
@@ -14,7 +14,7 @@ lalrpop="0.17"
[dependencies]
lalrpop-util="0.17"
log="0.4.1"
num-bigint = "0.2"
num-bigint = "0.3"
num-traits = "0.2"
unic-emoji-char = "0.9"
unic-ucd-ident = "0.9"
+2 -5
View File
@@ -27,10 +27,10 @@ blake2 = "0.8"
volatile = "0.2"
num-complex = { version = "0.2.2", features = ["serde"] }
num-bigint = { version = "0.2.4", features = ["serde"] }
num-bigint = { version = "0.3", features = ["serde"] }
num-traits = "0.2.8"
num-integer = "0.1.41"
num-rational = "0.2.2"
num-rational = "0.3"
num-iter = "0.1.39"
rand = { version = "0.7", features = ["wasm-bindgen"] }
rand_core = "0.5"
@@ -92,9 +92,6 @@ unic-ucd-ident = "0.9"
flame = { version = "0.2", optional = true }
flamer = { version = "0.3", optional = true }
[target.'cfg(all(unix, not(any(target_os = "android", target_os = "redox"))))'.dependencies]
pwd = "1"
[target.'cfg(unix)'.dependencies]
exitcode = "1.1.2"
uname = "0.1.1"
+3 -3
View File
@@ -124,7 +124,7 @@ fn inner_pow(int1: &BigInt, int2: &BigInt, vm: &VirtualMachine) -> PyResult {
objfloat::float_pow(v1, v2, vm).into_pyobject(vm)
} else {
Ok(if let Some(v2) = int2.to_u64() {
vm.ctx.new_int(int1.pow(v2))
vm.ctx.new_int(Pow::pow(int1, v2))
} else if int1.is_one() {
vm.ctx.new_int(1)
} else if int1.is_zero() {
@@ -519,7 +519,7 @@ impl PyInt {
#[pymethod(name = "__sizeof__")]
fn sizeof(&self) -> usize {
size_of::<Self>() + ((self.value.bits() + 7) & !7) / 8
size_of::<Self>() + (((self.value.bits() + 7) & !7) / 8) as usize
}
#[pymethod(name = "as_integer_ratio")]
@@ -531,7 +531,7 @@ impl PyInt {
}
#[pymethod]
fn bit_length(&self) -> usize {
fn bit_length(&self) -> u64 {
self.value.bits()
}
+82 -61
View File
@@ -1,52 +1,54 @@
use pwd::Passwd;
use super::os::convert_nix_error;
use crate::obj::objint::PyIntRef;
use crate::obj::objstr::PyStringRef;
use crate::obj::objtype::PyClassRef;
use crate::pyobject::{PyObjectRef, PyRef, PyResult, PyValue};
use crate::pyobject::{PyClassImpl, PyObjectRef, PyResult};
use crate::vm::VirtualMachine;
use std::convert::TryFrom;
use std::ptr::NonNull;
impl PyValue for Passwd {
fn class(vm: &VirtualMachine) -> PyClassRef {
vm.class("pwd", "struct_passwd")
use nix::unistd::{self, User};
#[pystruct_sequence(name = "pwd.struct_passwd")]
struct Passwd {
pw_name: String,
pw_passwd: String,
pw_uid: u32,
pw_gid: u32,
pw_gecos: String,
pw_dir: String,
pw_shell: String,
}
impl From<User> for Passwd {
fn from(user: User) -> Self {
// this is just a pain...
let cstr_lossy = |s: std::ffi::CString| {
s.into_string()
.unwrap_or_else(|e| e.into_cstring().to_string_lossy().into_owned())
};
let pathbuf_lossy = |p: std::path::PathBuf| {
p.into_os_string()
.into_string()
.unwrap_or_else(|s| s.to_string_lossy().into_owned())
};
Passwd {
pw_name: user.name,
pw_passwd: cstr_lossy(user.passwd),
pw_uid: user.uid.as_raw(),
pw_gid: user.gid.as_raw(),
pw_gecos: cstr_lossy(user.gecos),
pw_dir: pathbuf_lossy(user.dir),
pw_shell: pathbuf_lossy(user.shell),
}
}
}
type PasswdRef = PyRef<Passwd>;
impl PasswdRef {
fn pw_name(self) -> String {
self.name.clone()
}
fn pw_passwd(self) -> Option<String> {
self.passwd.clone()
}
fn pw_uid(self) -> u32 {
self.uid
}
fn pw_gid(self) -> u32 {
self.gid
}
fn pw_gecos(self) -> Option<String> {
self.gecos.clone()
}
fn pw_dir(self) -> String {
self.dir.clone()
}
fn pw_shell(self) -> String {
self.shell.clone()
}
}
fn pwd_getpwnam(name: PyStringRef, vm: &VirtualMachine) -> PyResult<Passwd> {
match Passwd::from_name(name.as_str()) {
Ok(Some(passwd)) => Ok(passwd),
_ => {
fn pwd_getpwnam(name: PyStringRef, vm: &VirtualMachine) -> PyResult {
match User::from_name(name.as_str()).map_err(|e| convert_nix_error(vm, e))? {
Some(user) => Ok(Passwd::from(user)
.into_struct_sequence(vm, vm.try_class("pwd", "struct_passwd")?)?
.into_object()),
None => {
let name_repr = vm.to_repr(name.as_object())?;
let message = vm.new_str(format!("getpwnam(): name not found: {}", name_repr));
Err(vm.new_key_error(message))
@@ -54,32 +56,51 @@ fn pwd_getpwnam(name: PyStringRef, vm: &VirtualMachine) -> PyResult<Passwd> {
}
}
fn pwd_getpwuid(uid: u32, vm: &VirtualMachine) -> PyResult<Passwd> {
match Passwd::from_uid(uid) {
Some(passwd) => Ok(passwd),
_ => {
let message = vm.new_str(format!("getpwuid(): uid not found: {}", uid));
fn pwd_getpwuid(uid: PyIntRef, vm: &VirtualMachine) -> PyResult {
let uid_t = libc::uid_t::try_from(uid.as_bigint()).map(unistd::Uid::from_raw);
let user = match uid_t {
Ok(uid) => User::from_uid(uid).map_err(|e| convert_nix_error(vm, e))?,
Err(_) => None,
};
match user {
Some(user) => Ok(Passwd::from(user)
.into_struct_sequence(vm, vm.try_class("pwd", "struct_passwd")?)?
.into_object()),
None => {
let message = vm.new_str(format!("getpwuid(): uid not found: {}", uid.as_bigint()));
Err(vm.new_key_error(message))
}
}
}
// TODO: maybe merge this functionality into nix?
fn pwd_getpwall(vm: &VirtualMachine) -> PyResult {
// setpwent, getpwent, etc are not thread safe. Could use fgetpwent_r, but this is easier
static GETPWALL: parking_lot::Mutex<()> = parking_lot::const_mutex(());
let _guard = GETPWALL.lock();
let mut list = Vec::new();
let cls = vm.try_class("pwd", "struct_passwd")?;
unsafe { libc::setpwent() };
while let Some(ptr) = NonNull::new(unsafe { libc::getpwent() }) {
let user = User::from(unsafe { ptr.as_ref() });
let passwd = Passwd::from(user)
.into_struct_sequence(vm, cls.clone())?
.into_object();
list.push(passwd);
}
unsafe { libc::endpwent() };
Ok(vm.ctx.new_list(list))
}
pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
let ctx = &vm.ctx;
let passwd_type = py_class!(ctx, "struct_passwd", ctx.object(), {
"pw_name" => ctx.new_readonly_getset("pw_name", PasswdRef::pw_name),
"pw_passwd" => ctx.new_readonly_getset("pw_passwd", PasswdRef::pw_passwd),
"pw_uid" => ctx.new_readonly_getset("pw_uid", PasswdRef::pw_uid),
"pw_gid" => ctx.new_readonly_getset("pw_gid", PasswdRef::pw_gid),
"pw_gecos" => ctx.new_readonly_getset("pw_gecos", PasswdRef::pw_gecos),
"pw_dir" => ctx.new_readonly_getset("pw_dir", PasswdRef::pw_dir),
"pw_shell" => ctx.new_readonly_getset("pw_shell", PasswdRef::pw_shell),
});
py_module!(vm, "pwd", {
"struct_passwd" => passwd_type,
"getpwnam" => ctx.new_function(pwd_getpwnam),
"getpwuid" => ctx.new_function(pwd_getpwuid),
"struct_passwd" => Passwd::make_class(ctx),
"getpwnam" => named_function!(ctx, pwd, getpwnam),
"getpwuid" => named_function!(ctx, pwd, getpwuid),
"getpwall" => named_function!(ctx, pwd, getpwall),
})
}