Skip to content

Commit 36f1de3

Browse files
committed
Optimize user/group operations
Previously, this work was being done multiple times and we were iterating over directory entries even if we weren't going to change user, mode, group settings at all. We now make use of a cache for users/groups (if needed at all) and completely skip iterating over files if not required. Signed-off-by: Paul Osborne <osbpau@gmail.com>
1 parent cd38a41 commit 36f1de3

File tree

4 files changed

+50
-19
lines changed

4 files changed

+50
-19
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ error-chain = "0.12"
1919
sysfs_gpio = "0.5.2"
2020
toml = "0.4"
2121
glob = "0.2"
22+
lazy_static = "1.1"
2223
log = "0.4"
2324
env_logger = "0.5"
2425
nix = "0.11"

src/export.rs

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,17 @@ use std::os::unix::fs as unix_fs;
1111
use std::os::unix::fs::PermissionsExt;
1212
use std::fs;
1313
use std::io::ErrorKind;
14+
use std::sync::Mutex;
1415
use config::PinConfig;
1516
use nix::unistd::{chown, Gid, Uid};
1617
use sysfs_gpio;
17-
use users::{get_user_by_name, get_group_by_name};
18+
use users::{UsersCache, Groups, Users};
1819
use error::*;
1920

21+
lazy_static! {
22+
static ref USERS_CACHE: Mutex<UsersCache> = Mutex::new(UsersCache::new());
23+
}
24+
2025
/// Unexport the pin specified in the provided config
2126
///
2227
/// Unexporting a config (in this context) involves a few different
@@ -69,32 +74,54 @@ pub fn unexport(pin_config: &PinConfig,
6974
/// without an error as the desired end state is achieved.
7075
pub fn export(pin_config: &PinConfig, symlink_root: Option<&str>) -> Result<()> {
7176
let pin = pin_config.get_pin();
72-
try!(pin.export());
77+
pin.export()?;
7378

74-
// change user, group, mode for files in gpio directory
75-
for entry in fs::read_dir(format!("/sys/class/gpio/gpio{}", &pin_config.num))? {
76-
let e = entry?;
77-
let metadata = e.metadata()?;
79+
let uid = if let Some(username) = pin_config.user.as_ref() {
80+
Some(
81+
USERS_CACHE
82+
.lock()
83+
.unwrap()
84+
.get_user_by_name(username)
85+
.map(|u| Uid::from_raw(u.uid()))
86+
.ok_or_else(|| format!("Unable to find user {:?}", username))?,
87+
)
88+
} else {
89+
None
90+
};
7891

79-
let user = pin_config.user.as_ref().and_then(|username| get_user_by_name(username));
80-
let group = pin_config.group.as_ref().and_then(|groupname| get_group_by_name(groupname));
92+
let gid = if let Some(groupname) = pin_config.group.as_ref() {
93+
Some(
94+
USERS_CACHE
95+
.lock()
96+
.unwrap()
97+
.get_group_by_name(groupname)
98+
.map(|g| Gid::from_raw(g.gid()))
99+
.ok_or_else(|| format!("Unable to find group {:?}", groupname))?,
100+
)
101+
} else {
102+
None
103+
};
81104

82-
if metadata.is_file() {
83-
if user.is_some() && group.is_some() {
84-
chown(e.path().as_path(),
85-
user.as_ref().map(|u| Uid::from_raw(u.uid())),
86-
group.as_ref().map(|g| Gid::from_raw(g.gid())))?;
87-
}
105+
// change user, group, mode for files in gpio directory
106+
if uid.is_some() || gid.is_some() || pin_config.mode.is_some() {
107+
for entry in fs::read_dir(format!("/sys/class/gpio/gpio{}", &pin_config.num))? {
108+
let e = entry?;
109+
let metadata = e.metadata()?;
88110

89-
if let Some(mode) = pin_config.mode {
90-
let mut permissions = metadata.permissions();
91-
permissions.set_mode(mode);
92-
fs::set_permissions(e.path().as_path(), permissions)?;
111+
if metadata.is_file() {
112+
if uid.is_some() || gid.is_some() {
113+
chown(e.path().as_path(), uid, gid)?;
114+
}
115+
116+
if let Some(mode) = pin_config.mode {
117+
let mut permissions = metadata.permissions();
118+
permissions.set_mode(mode);
119+
fs::set_permissions(e.path().as_path(), permissions)?;
120+
}
93121
}
94122
}
95123
}
96124

97-
98125
// if there is a symlink root provided, create symlink
99126
if let Some(symroot) = symlink_root {
100127
// create root directory if not exists

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#[macro_use]
1010
extern crate error_chain;
1111
extern crate glob;
12+
#[macro_use]
13+
extern crate lazy_static;
1214
extern crate log;
1315
extern crate nix;
1416
extern crate serde;

0 commit comments

Comments
 (0)