diff --git a/src/backend/local.rs b/src/backend/local.rs index 0d077ea9a..f8c00bb53 100644 --- a/src/backend/local.rs +++ b/src/backend/local.rs @@ -10,6 +10,7 @@ use std::{ use aho_corasick::AhoCorasick; use bytes::Bytes; +use cached::proc_macro::cached; use filetime::{set_symlink_file_times, FileTime}; use log::{debug, trace, warn}; #[cfg(not(windows))] @@ -469,6 +470,20 @@ pub struct LocalDestination { is_file: bool, } +// Helper functions to cache uid/gid +#[cfg(not(windows))] +#[cached] + +fn uid_from_name(name: String) -> Option { + User::from_name(&name).unwrap().map(|u| u.uid) +} + +#[cfg(not(windows))] +#[cached] +fn gid_from_name(name: String) -> Option { + Group::from_name(&name).unwrap().map(|g| g.gid) +} + impl LocalDestination { /// Create a new [`LocalDestination`] /// @@ -650,18 +665,18 @@ impl LocalDestination { let user = meta .user - .as_ref() - .and_then(|name| User::from_name(name).unwrap()); - + .clone() + .and_then(|name| uid_from_name(name.to_string())); // use uid from user if valid, else from saved uid (if saved) - let uid = user.map(|u| u.uid).or_else(|| meta.uid.map(Uid::from_raw)); + let uid = user.or_else(|| meta.uid.map(Uid::from_raw)); let group = meta .group - .as_ref() - .and_then(|name| Group::from_name(name).unwrap()); + .clone() + .and_then(|name| gid_from_name(name.to_string())); // use gid from group if valid, else from saved gid (if saved) - let gid = group.map(|g| g.gid).or_else(|| meta.gid.map(Gid::from_raw)); + let gid = group.or_else(|| meta.gid.map(Gid::from_raw)); + fchownat(None, &filename, uid, gid, FchownatFlags::NoFollowSymlink) .map_err(LocalErrorKind::FromErrnoError)?; Ok(())