Skip to content

Commit

Permalink
Fallible for username(), realname() and _os varaints
Browse files Browse the repository at this point in the history
  • Loading branch information
AldaronLau committed Aug 17, 2023
1 parent 188c446 commit 7a0de2b
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 42 deletions.
14 changes: 7 additions & 7 deletions src/fake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ pub(crate) fn lang() -> impl Iterator<Item = String> {
}

#[inline(always)]
pub(crate) fn username_os() -> OsString {
username().into()
pub(crate) fn username_os() -> Result<OsString> {
Ok(username()?.into())
}

#[inline(always)]
pub(crate) fn realname_os() -> OsString {
realname().into()
pub(crate) fn realname_os() -> Result<OsString> {
Ok(realname()?.into())
}

#[inline(always)]
Expand All @@ -33,12 +33,12 @@ pub(crate) fn distro_os() -> Option<OsString> {
}

#[inline(always)]
pub(crate) fn username() -> String {
"anonymous".to_string()
pub(crate) fn username() -> Result<String> {
Ok("anonymous".to_string())
}

#[inline(always)]
pub(crate) fn realname() -> String {
pub(crate) fn realname() -> Result<String> {
"Anonymous".to_string()
}

Expand Down
39 changes: 39 additions & 0 deletions src/fallible.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//! Fallible versions of the whoami APIs.
//!
//! Some of the functions in the root module will return "Unknown" on error.
//! This might not be desirable in some situations. The functions in this
//! module all return a [`Result`].

use std::ffi::OsString;

use crate::{platform, Result};

/// Get the user's username.
///
/// On unix-systems this differs from [`realname()`] most notably in that spaces
/// are not allowed.
#[inline(always)]
pub fn username() -> Result<String> {
platform::username()
}

/// Get the user's username.
///
/// On unix-systems this differs from [`realname()`] most notably in that spaces
/// are not allowed.
#[inline(always)]
pub fn username_os() -> Result<OsString> {
platform::username_os()
}

/// Get the user's real (full) name.
#[inline(always)]
pub fn realname() -> Result<String> {
platform::realname()
}

/// Get the user's real (full) name.
#[inline(always)]
pub fn realname_os() -> Result<OsString> {
platform::realname_os()
}
14 changes: 10 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@
html_favicon_url = "https://raw.githubusercontent.com/ardaku/whoami/stable/res/icon.svg"
)]

const DEFAULT_USERNAME: &str = "Unknown";

pub mod fallible;

#[allow(unsafe_code)]
// Unix
#[cfg_attr(
Expand Down Expand Up @@ -395,7 +399,7 @@ pub fn arch() -> Arch {
/// are not allowed.
#[inline(always)]
pub fn username() -> String {
platform::username()
fallible::username().unwrap_or_else(|_| DEFAULT_USERNAME.to_owned())
}

/// Get the user's username.
Expand All @@ -404,19 +408,21 @@ pub fn username() -> String {
/// are not allowed.
#[inline(always)]
pub fn username_os() -> OsString {
platform::username_os()
fallible::username_os()
.unwrap_or_else(|_| DEFAULT_USERNAME.to_owned().into())
}

/// Get the user's real (full) name.
#[inline(always)]
pub fn realname() -> String {
platform::realname()
fallible::realname().unwrap_or_else(|_| DEFAULT_USERNAME.to_owned())
}

/// Get the user's real (full) name.
#[inline(always)]
pub fn realname_os() -> OsString {
platform::realname_os()
fallible::realname_os()
.unwrap_or_else(|_| DEFAULT_USERNAME.to_owned().into())
}

/// Get the device name (also known as "Pretty Name").
Expand Down
25 changes: 13 additions & 12 deletions src/unix.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::{
borrow::Cow,
ffi::{c_void, CStr, OsString},
io::{Error, ErrorKind},
mem,
os::{
raw::{c_char, c_int},
Expand All @@ -16,7 +17,7 @@ use std::{
ptr::null_mut,
};

use crate::{Arch, DesktopEnv, Platform};
use crate::{Arch, DesktopEnv, Platform, Result};

#[repr(C)]
struct PassWd {
Expand Down Expand Up @@ -192,7 +193,7 @@ fn os_from_cfstring(string: *mut c_void) -> OsString {
// This function must allocate, because a slice or Cow<OsStr> would still
// reference `passwd` which is dropped when this function returns.
#[inline(always)]
fn getpwuid(real: bool) -> OsString {
fn getpwuid(real: bool) -> Result<OsString> {
const BUF_SIZE: usize = 16_384; // size from the man page
let mut buffer = mem::MaybeUninit::<[u8; BUF_SIZE]>::uninit();
let mut passwd = mem::MaybeUninit::<PassWd>::uninit();
Expand All @@ -209,20 +210,20 @@ fn getpwuid(real: bool) -> OsString {
);

if ret != 0 {
return "Unknown".to_string().into();
return Err(Error::last_os_error());
}

let _passwd = _passwd.assume_init();

if _passwd.is_null() {
return "Unknown".to_string().into();
return Err(Error::new(ErrorKind::NotFound, "Missing record"));
}

passwd.assume_init()
};

// Extract names.
if real {
Ok(if real {
let string = os_from_cstring_gecos(passwd.pw_gecos);
let result = if let Some(string) = string {
Ok(string)
Expand All @@ -232,14 +233,14 @@ fn getpwuid(real: bool) -> OsString {
fancy_fallback_os(result)
} else {
os_from_cstring(passwd.pw_name)
}
})
}

pub(crate) fn username() -> String {
string_from_os(username_os())
pub(crate) fn username() -> Result<String> {
Ok(string_from_os(username_os()?))
}

pub(crate) fn username_os() -> OsString {
pub(crate) fn username_os() -> Result<OsString> {
getpwuid(false)
}

Expand Down Expand Up @@ -285,11 +286,11 @@ fn fancy_fallback_os(result: Result<OsString, OsString>) -> OsString {
}
}

pub(crate) fn realname() -> String {
string_from_os(realname_os())
pub(crate) fn realname() -> Result<String> {
Ok(string_from_os(realname_os()?))
}

pub(crate) fn realname_os() -> OsString {
pub(crate) fn realname_os() -> Result<OsString> {
getpwuid(true)
}

Expand Down
16 changes: 8 additions & 8 deletions src/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,13 @@ pub(crate) fn lang() -> impl Iterator<Item = String> {
}

#[inline(always)]
pub(crate) fn username_os() -> OsString {
username().into()
pub(crate) fn username_os() -> Result<OsString> {
Ok(username()?.into())
}

#[inline(always)]
pub(crate) fn realname_os() -> OsString {
realname().into()
pub(crate) fn realname_os() -> Result<OsString> {
Ok(realname()?.into())
}

#[inline(always)]
Expand All @@ -73,13 +73,13 @@ pub(crate) fn distro_os() -> Option<OsString> {
}

#[inline(always)]
pub(crate) fn username() -> String {
"anonymous".to_string()
pub(crate) fn username() -> Result<String> {
Ok("anonymous".to_string())
}

#[inline(always)]
pub(crate) fn realname() -> String {
"Anonymous".to_string()
pub(crate) fn realname() -> Result<String> {
Ok("Anonymous".to_string())
}

pub(crate) fn devicename() -> String {
Expand Down
23 changes: 12 additions & 11 deletions src/windows.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::{
convert::TryInto,
ffi::OsString,
io::Error,
mem::MaybeUninit,
os::{
raw::{c_char, c_int, c_uchar, c_ulong, c_ushort, c_void},
Expand All @@ -9,7 +10,7 @@ use std::{
ptr,
};

use crate::{Arch, DesktopEnv, Platform};
use crate::{Arch, DesktopEnv, Platform, Result};

#[repr(C)]
struct OsVersionInfoEx {
Expand Down Expand Up @@ -109,11 +110,11 @@ fn string_from_os(string: OsString) -> String {
}
}

pub(crate) fn username() -> String {
string_from_os(username_os())
pub(crate) fn username() -> Result<String> {
Ok(string_from_os(username_os()?))
}

pub(crate) fn username_os() -> OsString {
pub(crate) fn username_os() -> Result<OsString> {
// Step 1. Retreive the entire length of the username
let mut size = 0;
let success = unsafe {
Expand All @@ -130,7 +131,7 @@ pub(crate) fn username_os() -> OsString {
let fail =
unsafe { GetUserNameW(name.as_mut_ptr().cast(), &mut size) == 0 };
if fail {
return "unknown".to_string().into();
return Err(Error::last_os_error());
}
debug_assert_eq!(orig_size, size);
unsafe {
Expand All @@ -140,16 +141,16 @@ pub(crate) fn username_os() -> OsString {
debug_assert_eq!(terminator, Some(0u16));

// Step 3. Convert to Rust String
OsString::from_wide(&name)
Ok(OsString::from_wide(&name))
}

#[inline(always)]
pub(crate) fn realname() -> String {
string_from_os(realname_os())
pub(crate) fn realname() -> Result<String> {
Ok(string_from_os(realname_os()?))
}

#[inline(always)]
pub(crate) fn realname_os() -> OsString {
pub(crate) fn realname_os() -> Result<OsString> {
// Step 1. Retrieve the entire length of the username
let mut buf_size = 0;
let success = unsafe {
Expand Down Expand Up @@ -180,15 +181,15 @@ pub(crate) fn realname_os() -> OsString {
) == 0
};
if fail {
return "Unknown".to_string().into();
return Err(Error::last_os_error());
}
debug_assert_eq!(buf_size, name_len + 1);
unsafe {
name.set_len(name_len.try_into().unwrap_or(std::usize::MAX));
}

// Step 3. Convert to Rust String
OsString::from_wide(&name)
Ok(OsString::from_wide(&name))
}

#[inline(always)]
Expand Down

0 comments on commit 7a0de2b

Please sign in to comment.