Skip to content

Commit

Permalink
Replace std::env::home_dir with working implementation on Unix
Browse files Browse the repository at this point in the history
  • Loading branch information
soc committed Jun 24, 2018
1 parent 6536c1f commit b7ea3b7
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 4 deletions.
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,8 @@ repository = "https://github.com/soc/dirs-rs"
maintenance = { status = "actively-developed" }
keywords = ["xdg", "basedir", "app_dirs", "path", "folder"]

[dependencies]
[target.'cfg(unix)'.dependencies]
libc = "0.2"

[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["knownfolders", "objbase", "shlobj"] }
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use std::path::PathBuf;
#[cfg(target_os = "linux")] mod lin;
#[cfg(target_os = "windows")] mod win;
#[cfg(target_os = "macos")] mod mac;
#[cfg(unix)] mod unix;

#[cfg(target_os = "linux")] use lin as sys;
#[cfg(target_os = "windows")] use win as sys;
Expand Down
4 changes: 3 additions & 1 deletion src/lin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ use std::ffi::OsString;
use std::path::PathBuf;
use std::process::Command;

pub fn home_dir() -> Option<PathBuf> { env::home_dir() }
use unix;

pub fn home_dir() -> Option<PathBuf> { unix::home_dir() }
pub fn cache_dir() -> Option<PathBuf> { env::var_os("XDG_CACHE_HOME") .and_then(is_absolute_path).or_else(|| home_dir().map(|h| h.join(".cache"))) }
pub fn config_dir() -> Option<PathBuf> { env::var_os("XDG_CONFIG_HOME").and_then(is_absolute_path).or_else(|| home_dir().map(|h| h.join(".config"))) }
pub fn data_dir() -> Option<PathBuf> { env::var_os("XDG_DATA_HOME") .and_then(is_absolute_path).or_else(|| home_dir().map(|h| h.join(".local/share"))) }
Expand Down
5 changes: 3 additions & 2 deletions src/mac.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#![cfg(target_os = "macos")]

use std::env;
use std::path::PathBuf;

pub fn home_dir() -> Option<PathBuf> { env::home_dir() }
use unix;

pub fn home_dir() -> Option<PathBuf> { unix::home_dir() }
pub fn cache_dir() -> Option<PathBuf> { home_dir().map(|h| h.join("Library/Caches")) }
pub fn config_dir() -> Option<PathBuf> { home_dir().map(|h| h.join("Library/Preferences")) }
pub fn data_dir() -> Option<PathBuf> { home_dir().map(|h| h.join("Library/Application Support")) }
Expand Down
48 changes: 48 additions & 0 deletions src/unix.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#![cfg(unix)]

use std::env;
use std::path::PathBuf;
use std::mem;
use std::ptr;
use std::ffi::CStr;
use std::ffi::OsString;
use std::os::unix::ffi::OsStringExt;

extern crate libc;

// https://github.com/rust-lang/rust/blob/master/src/libstd/sys/unix/os.rs#L498
pub fn home_dir() -> Option<PathBuf> {
return env::var_os("HOME").filter(|h| !h.is_empty()).or_else(|| unsafe {
fallback()
}).map(PathBuf::from);

#[cfg(any(target_os = "android",
target_os = "ios",
target_os = "emscripten"))]
unsafe fn fallback() -> Option<OsString> { None }
#[cfg(not(any(target_os = "android",
target_os = "ios",
target_os = "emscripten")))]
unsafe fn fallback() -> Option<OsString> {
let amt = match libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) {
n if n < 0 => 512 as usize,
n => n as usize,
};
let mut buf = Vec::with_capacity(amt);
let mut passwd: libc::passwd = mem::zeroed();
let mut result = ptr::null_mut();
match libc::getpwuid_r(libc::getuid(), &mut passwd, buf.as_mut_ptr(),
buf.capacity(), &mut result) {
0 if !result.is_null() => {
let ptr = passwd.pw_dir as *const _;
let bytes = CStr::from_ptr(ptr).to_bytes();
if bytes.is_empty() {
None
} else {
Some(OsStringExt::from_vec(bytes.to_vec()))
}
},
_ => None,
}
}
}

0 comments on commit b7ea3b7

Please sign in to comment.