1 #![warn(rust_2018_idioms)]
3 use std
::ffi
::OsString
;
4 use std
::path
::PathBuf
;
6 // we don't need to explicitly handle empty strings in the code above,
7 // because an empty string is not considered to be a absolute path here.
8 pub fn is_absolute_path(path
: OsString
) -> Option
<PathBuf
> {
9 let path
= PathBuf
::from(path
);
10 if path
.is_absolute() {
17 #[cfg(all(unix, not(target_os = "redox")))]
18 mod target_unix_not_redox
{
21 use std
::ffi
::{CStr, OsString}
;
23 use std
::os
::unix
::ffi
::OsStringExt
;
24 use std
::path
::PathBuf
;
27 // https://github.com/rust-lang/rust/blob/ef3e3863939217678e5f7e755c4234d224107c64/library/std/src/sys/unix/os.rs#L587
28 pub fn home_dir() -> Option
<PathBuf
> {
29 return env
::var_os("HOME")
30 .and_then(|h
| if h
.is_empty() { None }
else { Some(h) }
)
31 .or_else(|| unsafe { fallback() }
)
34 #[cfg(any(target_os = "android", target_os = "ios", target_os = "emscripten"))]
35 unsafe fn fallback() -> Option
<OsString
> {
38 #[cfg(not(any(target_os = "android", target_os = "ios", target_os = "emscripten")))]
39 unsafe fn fallback() -> Option
<OsString
> {
40 let amt
= match libc
::sysconf(libc
::_SC_GETPW_R_SIZE_MAX
) {
41 n
if n
< 0 => 512 as usize,
44 let mut buf
= Vec
::with_capacity(amt
);
45 let mut passwd
: libc
::passwd
= mem
::zeroed();
46 let mut result
= ptr
::null_mut();
47 match libc
::getpwuid_r(libc
::getuid(), &mut passwd
, buf
.as_mut_ptr(), buf
.capacity(), &mut result
) {
48 0 if !result
.is_null() => {
49 let ptr
= passwd
.pw_dir
as *const _
;
50 let bytes
= CStr
::from_ptr(ptr
).to_bytes();
54 Some(OsStringExt
::from_vec(bytes
.to_vec()))
63 #[cfg(all(unix, not(target_os = "redox")))]
64 pub use self::target_unix_not_redox
::home_dir
;
66 #[cfg(target_os = "redox")]
69 use std
::path
::PathBuf
;
71 use redox_users
::{All, AllUsers, Config}
;
73 pub fn home_dir() -> Option
<PathBuf
> {
74 let current_uid
= redox_users
::get_uid().ok()?
;
75 let users
= AllUsers
::basic(Config
::default()).ok()?
;
76 let user
= users
.get_by_id(current_uid
)?
;
78 Some(PathBuf
::from(user
.home
.clone()))
82 #[cfg(target_os = "redox")]
83 pub use self::target_redox
::home_dir
;
85 #[cfg(all(unix, not(any(target_os = "macos", target_os = "ios"))))]
88 #[cfg(all(unix, not(any(target_os = "macos", target_os = "ios"))))]
89 mod target_unix_not_mac
{
91 use std
::collections
::HashMap
;
93 use std
::path
::{Path, PathBuf}
;
95 use super::xdg_user_dirs
;
96 use super::{home_dir, is_absolute_path}
;
98 fn user_dir_file(home_dir
: &Path
) -> PathBuf
{
99 env
::var_os("XDG_CONFIG_HOME")
100 .and_then(is_absolute_path
)
101 .unwrap_or_else(|| home_dir
.join(".config"))
102 .join("user-dirs.dirs")
105 // this could be optimized further to not create a map and instead retrieve the requested path only
106 pub fn user_dir(user_dir_name
: &str) -> Option
<PathBuf
> {
107 if let Some(home_dir
) = home_dir() {
108 xdg_user_dirs
::single(&home_dir
, &user_dir_file(&home_dir
), user_dir_name
).remove(user_dir_name
)
114 pub fn user_dirs(home_dir_path
: &Path
) -> HashMap
<String
, PathBuf
> {
115 xdg_user_dirs
::all(home_dir_path
, &user_dir_file(home_dir_path
))
119 #[cfg(all(unix, not(any(target_os = "macos", target_os = "ios"))))]
120 pub use self::target_unix_not_mac
::{user_dir, user_dirs}
;
122 #[cfg(target_os = "windows")]
125 use std
::ffi
::OsString
;
126 use std
::os
::windows
::ffi
::OsStringExt
;
127 use std
::path
::PathBuf
;
131 use winapi
::shared
::winerror
;
132 use winapi
::um
::{combaseapi, knownfolders, shlobj, shtypes, winbase, winnt}
;
134 pub fn known_folder(folder_id
: shtypes
::REFKNOWNFOLDERID
) -> Option
<PathBuf
> {
136 let mut path_ptr
: winnt
::PWSTR
= ptr
::null_mut();
137 let result
= shlobj
::SHGetKnownFolderPath(folder_id
, 0, ptr
::null_mut(), &mut path_ptr
);
138 if result
== winerror
::S_OK
{
139 let len
= winbase
::lstrlenW(path_ptr
) as usize;
140 let path
= slice
::from_raw_parts(path_ptr
, len
);
141 let ostr
: OsString
= OsStringExt
::from_wide(path
);
142 combaseapi
::CoTaskMemFree(path_ptr
as *mut winapi
::ctypes
::c_void
);
143 Some(PathBuf
::from(ostr
))
150 pub fn known_folder_profile() -> Option
<PathBuf
> {
151 known_folder(&knownfolders
::FOLDERID_Profile
)
154 pub fn known_folder_roaming_app_data() -> Option
<PathBuf
> {
155 known_folder(&knownfolders
::FOLDERID_RoamingAppData
)
158 pub fn known_folder_local_app_data() -> Option
<PathBuf
> {
159 known_folder(&knownfolders
::FOLDERID_LocalAppData
)
162 pub fn known_folder_music() -> Option
<PathBuf
> {
163 known_folder(&knownfolders
::FOLDERID_Music
)
166 pub fn known_folder_desktop() -> Option
<PathBuf
> {
167 known_folder(&knownfolders
::FOLDERID_Desktop
)
170 pub fn known_folder_documents() -> Option
<PathBuf
> {
171 known_folder(&knownfolders
::FOLDERID_Documents
)
174 pub fn known_folder_downloads() -> Option
<PathBuf
> {
175 known_folder(&knownfolders
::FOLDERID_Downloads
)
178 pub fn known_folder_pictures() -> Option
<PathBuf
> {
179 known_folder(&knownfolders
::FOLDERID_Pictures
)
182 pub fn known_folder_public() -> Option
<PathBuf
> {
183 known_folder(&knownfolders
::FOLDERID_Public
)
185 pub fn known_folder_templates() -> Option
<PathBuf
> {
186 known_folder(&knownfolders
::FOLDERID_Templates
)
188 pub fn known_folder_videos() -> Option
<PathBuf
> {
189 known_folder(&knownfolders
::FOLDERID_Videos
)
193 #[cfg(target_os = "windows")]
194 pub use self::target_windows
::{
195 known_folder
, known_folder_desktop
, known_folder_documents
, known_folder_downloads
, known_folder_local_app_data
,
196 known_folder_music
, known_folder_pictures
, known_folder_profile
, known_folder_public
,
197 known_folder_roaming_app_data
, known_folder_templates
, known_folder_videos
,