Skip to content

Commit

Permalink
Move home_dir from PathBuf to Option<PathBuf>
Browse files Browse the repository at this point in the history
  • Loading branch information
soc committed Jun 24, 2018
1 parent 0c137ba commit 6536c1f
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 49 deletions.
11 changes: 5 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,14 @@ use std::path::PathBuf;
/// - Use `$HOME` if it is set.
/// - If `$HOME` is not set, the function `getpwuid_r` is used to determine
/// the home directory of the current user.
/// - If this also fails, creation of `BaseDirs` panics.
///
/// On Windows, this function retrieves the user profile folder using
/// `SHGetKnownFolderPath`.
///
/// All the examples on this page mentioning `$HOME` use this behavior.
///
/// [`std::env::home_dir`]: https://doc.rust-lang.org/std/env/fn.home_dir.html
pub fn home_dir() -> PathBuf {
pub fn home_dir() -> Option<PathBuf> {
sys::home_dir()
}
/// Returns the path to the user's cache directory.
Expand All @@ -55,7 +54,7 @@ pub fn home_dir() -> PathBuf {
/// | Linux | `$XDG_CACHE_HOME` or `$HOME/.cache` | /home/alice/.cache |
/// | macOS | `$HOME/Library/Caches` | /Users/Alice/Library/Caches |
/// | Windows | `{FOLDERID_LocalAppData}` | C:\Users\Alice\AppData\Local |
pub fn cache_dir() -> PathBuf {
pub fn cache_dir() -> Option<PathBuf> {
sys::cache_dir()
}
/// Returns the path to the user's config directory.
Expand All @@ -65,7 +64,7 @@ pub fn cache_dir() -> PathBuf {
/// | Linux | `$XDG_CONFIG_HOME` or `$HOME/.config` | /home/alice/.config |
/// | macOS | `$HOME/Library/Preferences` | /Users/Alice/Library/Preferences |
/// | Windows | `{FOLDERID_RoamingAppData}` | C:\Users\Alice\AppData\Roaming |
pub fn config_dir() -> PathBuf {
pub fn config_dir() -> Option<PathBuf> {
sys::config_dir()
}
/// Returns the path to the user's data directory.
Expand All @@ -75,7 +74,7 @@ pub fn config_dir() -> PathBuf {
/// | Linux | `$XDG_DATA_HOME` or `$HOME/.local/share` | /home/alice/.local/share |
/// | macOS | `$HOME/Library/Application Support` | /Users/Alice/Library/Application Support |
/// | Windows | `{FOLDERID_RoamingAppData}` | C:\Users\Alice\AppData\Roaming |
pub fn data_dir() -> PathBuf {
pub fn data_dir() -> Option<PathBuf> {
sys::data_dir()
}
/// Returns the path to the user's local data directory.
Expand All @@ -85,7 +84,7 @@ pub fn data_dir() -> PathBuf {
/// | Linux | `$XDG_DATA_HOME` or `$HOME/.local/share` | /home/alice/.local/share |
/// | macOS | `$HOME/Library/Application Support` | /Users/Alice/Library/Application Support |
/// | Windows | `{FOLDERID_LocalAppData}` | C:\Users\Alice\AppData\Local |
pub fn data_local_dir() -> PathBuf {
pub fn data_local_dir() -> Option<PathBuf> {
sys::data_local_dir()
}
/// Returns the path to the user's executable directory.
Expand Down
23 changes: 13 additions & 10 deletions src/lin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,30 @@ use std::ffi::OsString;
use std::path::PathBuf;
use std::process::Command;

pub fn home_dir() -> PathBuf { env::home_dir().unwrap() }
pub fn cache_dir() -> PathBuf { env::var_os("XDG_CACHE_HOME") .and_then(is_absolute_path).unwrap_or_else(|| home_dir().join(".cache")) }
pub fn config_dir() -> PathBuf { env::var_os("XDG_CONFIG_HOME").and_then(is_absolute_path).unwrap_or_else(|| home_dir().join(".config")) }
pub fn data_dir() -> PathBuf { env::var_os("XDG_DATA_HOME") .and_then(is_absolute_path).unwrap_or_else(|| home_dir().join(".local/share")) }
pub fn data_local_dir() -> PathBuf { data_dir().clone() }
pub fn home_dir() -> Option<PathBuf> { env::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"))) }
pub fn data_local_dir() -> Option<PathBuf> { data_dir().clone() }
pub fn runtime_dir() -> Option<PathBuf> { env::var_os("XDG_RUNTIME_DIR").and_then(is_absolute_path) }
pub fn executable_dir() -> Option<PathBuf> {
let exec_dir = env::var_os("XDG_BIN_HOME").and_then(is_absolute_path).unwrap_or_else(|| {
let mut new_dir = data_dir(); new_dir.pop(); new_dir.push("bin"); new_dir });
Some(exec_dir)
let exec_dir = env::var_os("XDG_BIN_HOME").and_then(is_absolute_path).or_else(|| {
data_dir().map(|mut e| { e.pop(); e.push("bin"); e })
});
exec_dir
}
pub fn audio_dir() -> Option<PathBuf> { run_xdg_user_dir_command("MUSIC") }
pub fn desktop_dir() -> Option<PathBuf> { run_xdg_user_dir_command("DESKTOP") }
pub fn document_dir() -> Option<PathBuf> { run_xdg_user_dir_command("DOCUMENTS") }
pub fn download_dir() -> Option<PathBuf> { run_xdg_user_dir_command("DOWNLOAD") }
pub fn font_dir() -> Option<PathBuf> { Some(data_dir().join("fonts")) }
pub fn font_dir() -> Option<PathBuf> { data_dir().map(|d| d.join("fonts")) }
pub fn picture_dir() -> Option<PathBuf> { run_xdg_user_dir_command("PICTURES") }
pub fn public_dir() -> Option<PathBuf> { run_xdg_user_dir_command("PUBLICSHARE") }
pub fn template_dir() -> Option<PathBuf> { run_xdg_user_dir_command("TEMPLATES") }
pub fn video_dir() -> Option<PathBuf> { run_xdg_user_dir_command("VIDEOS") }

// we don't need to explicitly handle empty strings in the code above,
// because an empty string is not considered to be a absolute path here.
fn is_absolute_path(path: OsString) -> Option<PathBuf> {
let path = PathBuf::from(path);
if path.is_absolute() {
Expand All @@ -47,7 +50,7 @@ fn run_xdg_user_dir_command(arg: &str) -> Option<PathBuf> {
mod tests {
#[test]
fn test_file_user_dirs_exists() {
let user_dirs_file = ::config_dir().join("user-dirs.dirs");
let user_dirs_file = ::config_dir().unwrap().join("user-dirs.dirs");
println!("{:?} exists: {:?}", user_dirs_file, user_dirs_file.exists());
}
}
26 changes: 13 additions & 13 deletions src/mac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@
use std::env;
use std::path::PathBuf;

pub fn home_dir() -> PathBuf { env::home_dir().unwrap() }
pub fn cache_dir() -> PathBuf { home_dir().join("Library/Caches") }
pub fn config_dir() -> PathBuf { home_dir().join("Library/Preferences") }
pub fn data_dir() -> PathBuf { home_dir().join("Library/Application Support") }
pub fn data_local_dir() -> PathBuf { data_dir() }
pub fn home_dir() -> Option<PathBuf> { env::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")) }
pub fn data_local_dir() -> Option<PathBuf> { data_dir() }
pub fn executable_dir() -> Option<PathBuf> { None }
pub fn runtime_dir() -> Option<PathBuf> { None }
pub fn audio_dir() -> Option<PathBuf> { Some(home_dir().join("Music")) }
pub fn desktop_dir() -> Option<PathBuf> { Some(home_dir().join("Desktop")) }
pub fn document_dir() -> Option<PathBuf> { Some(home_dir().join("Documents")) }
pub fn download_dir() -> Option<PathBuf> { Some(home_dir().join("Downloads")) }
pub fn font_dir() -> Option<PathBuf> { Some(home_dir().join("Library/Fonts")) }
pub fn picture_dir() -> Option<PathBuf> { Some(home_dir().join("Pictures")) }
pub fn public_dir() -> Option<PathBuf> { Some(home_dir().join("Public")) }
pub fn audio_dir() -> Option<PathBuf> { home_dir().map(|h| h.join("Music")) }
pub fn desktop_dir() -> Option<PathBuf> { home_dir().map(|h| h.join("Desktop")) }
pub fn document_dir() -> Option<PathBuf> { home_dir().map(|h| h.join("Documents")) }
pub fn download_dir() -> Option<PathBuf> { home_dir().map(|h| h.join("Downloads")) }
pub fn font_dir() -> Option<PathBuf> { home_dir().map(|h| h.join("Library/Fonts")) }
pub fn picture_dir() -> Option<PathBuf> { home_dir().map(|h| h.join("Pictures")) }
pub fn public_dir() -> Option<PathBuf> { home_dir().map(|h| h.join("Public")) }
pub fn template_dir() -> Option<PathBuf> { None }
// pub fn trash_dir() -> Option<PathBuf> { Some(home_dir().join(".trash")) }
pub fn video_dir() -> Option<PathBuf> { Some(home_dir().join("Movies")) }
pub fn video_dir() -> Option<PathBuf> { home_dir().map(|h| h.join("Movies")) }
44 changes: 24 additions & 20 deletions src/win.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,33 +10,37 @@ use self::winapi::um::shlobj;
use self::winapi::um::shtypes;
use self::winapi::um::winnt;

pub fn home_dir() -> PathBuf { unsafe { known_folder(&knownfolders::FOLDERID_Profile) } }
pub fn data_dir() -> PathBuf { unsafe { known_folder(&knownfolders::FOLDERID_RoamingAppData) } }
pub fn data_local_dir() -> PathBuf { unsafe { known_folder(&knownfolders::FOLDERID_LocalAppData) } }
pub fn cache_dir() -> PathBuf { data_local_dir() }
pub fn config_dir() -> PathBuf { data_dir() }
pub fn home_dir() -> Option<PathBuf> { unsafe { known_folder(&knownfolders::FOLDERID_Profile) } }
pub fn data_dir() -> Option<PathBuf> { unsafe { known_folder(&knownfolders::FOLDERID_RoamingAppData) } }
pub fn data_local_dir() -> Option<PathBuf> { unsafe { known_folder(&knownfolders::FOLDERID_LocalAppData) } }
pub fn cache_dir() -> Option<PathBuf> { data_local_dir() }
pub fn config_dir() -> Option<PathBuf> { data_dir() }
pub fn executable_dir() -> Option<PathBuf> { None }
pub fn runtime_dir() -> Option<PathBuf> { None }
pub fn audio_dir() -> Option<PathBuf> { Some(unsafe { known_folder(&knownfolders::FOLDERID_Music) }) }
pub fn desktop_dir() -> Option<PathBuf> { Some(unsafe { known_folder(&knownfolders::FOLDERID_Desktop) }) }
pub fn document_dir() -> Option<PathBuf> { Some(unsafe { known_folder(&knownfolders::FOLDERID_Documents) }) }
pub fn download_dir() -> Option<PathBuf> { Some(unsafe { known_folder(&knownfolders::FOLDERID_Downloads) }) }
pub fn audio_dir() -> Option<PathBuf> { unsafe { known_folder(&knownfolders::FOLDERID_Music) } }
pub fn desktop_dir() -> Option<PathBuf> { unsafe { known_folder(&knownfolders::FOLDERID_Desktop) } }
pub fn document_dir() -> Option<PathBuf> { unsafe { known_folder(&knownfolders::FOLDERID_Documents) } }
pub fn download_dir() -> Option<PathBuf> { unsafe { known_folder(&knownfolders::FOLDERID_Downloads) } }
pub fn font_dir() -> Option<PathBuf> { None }
pub fn picture_dir() -> Option<PathBuf> { Some(unsafe { known_folder(&knownfolders::FOLDERID_Pictures) }) }
pub fn public_dir() -> Option<PathBuf> { Some(unsafe { known_folder(&knownfolders::FOLDERID_Public) }) }
pub fn template_dir() -> Option<PathBuf> { Some(unsafe { known_folder(&knownfolders::FOLDERID_Templates) }) }
pub fn picture_dir() -> Option<PathBuf> { unsafe { known_folder(&knownfolders::FOLDERID_Pictures) } }
pub fn public_dir() -> Option<PathBuf> { unsafe { known_folder(&knownfolders::FOLDERID_Public) } }
pub fn template_dir() -> Option<PathBuf> { unsafe { known_folder(&knownfolders::FOLDERID_Templates) } }
// see https://github.com/soc/directories-rs/issues/18
// let trash_dir = unsafe { known_folder(&knownfolders::FOLDERID_RecycleBinFolder) };
pub fn video_dir() -> Option<PathBuf> { Some(unsafe { known_folder(&knownfolders::FOLDERID_Videos) }) }
pub fn video_dir() -> Option<PathBuf> { unsafe { known_folder(&knownfolders::FOLDERID_Videos) } }

unsafe fn known_folder(folder_id: shtypes::REFKNOWNFOLDERID) -> PathBuf {
unsafe fn known_folder(folder_id: shtypes::REFKNOWNFOLDERID) -> Option<PathBuf> {
let mut path_ptr: winnt::PWSTR = std::ptr::null_mut();
let _result = shlobj::SHGetKnownFolderPath(folder_id, 0, std::ptr::null_mut(), &mut path_ptr);
let len = length_of_u16_string(path_ptr);
let path = std::slice::from_raw_parts(path_ptr, len);
let ostr: std::ffi::OsString = std::os::windows::ffi::OsStringExt::from_wide(path);
combaseapi::CoTaskMemFree(path_ptr as *mut winapi::ctypes::c_void);
PathBuf::from(ostr)
let result = shlobj::SHGetKnownFolderPath(folder_id, 0, std::ptr::null_mut(), &mut path_ptr);
if result == 0 { // 0 == S_OK
let len = length_of_u16_string(path_ptr);
let path = std::slice::from_raw_parts(path_ptr, len);
let ostr: std::ffi::OsString = std::os::windows::ffi::OsStringExt::from_wide(path);
combaseapi::CoTaskMemFree(path_ptr as *mut winapi::ctypes::c_void);
Some(PathBuf::from(ostr))
} else {
None
}
}

unsafe fn length_of_u16_string(ptr: *mut u16) -> usize {
Expand Down

0 comments on commit 6536c1f

Please sign in to comment.