Touch up etcetera cache dir code

This commit is contained in:
David Tolnay 2025-03-02 22:43:27 -08:00
parent 36dbffb78c
commit 4317adcaf1
No known key found for this signature in database
GPG key ID: F9BA143B95FF6D82
2 changed files with 30 additions and 56 deletions

View file

@ -37,7 +37,7 @@ termcolor = "1.0"
toml = "0.8"
toolchain_find = "0.4"
[target.'cfg(windows)'.dependencies]
[target.'cfg(all(windows, not(target_vendor = "uwp")))'.dependencies]
windows-sys = { version = "0.59", features = ["Win32_Foundation", "Win32_System_Com", "Win32_UI_Shell"] }
[package.metadata.docs.rs]

View file

@ -32,96 +32,70 @@ pub fn cache_dir() -> Result<PathBuf> {
#[cfg(windows)]
mod windows {
use std::env;
use std::path::{Path, PathBuf};
fn dir_inner(env: &'static str) -> Option<PathBuf> {
std::env::var_os(env)
pub fn cache_dir(home_dir: &Path) -> PathBuf {
env::var_os("LOCALAPPDATA")
.filter(|s| !s.is_empty())
.map(PathBuf::from)
.or_else(|| dir_crt(env))
.or_else(dir_crt)
.unwrap_or_else(|| home_dir.join("AppData").join("Local"))
}
// Ref: https://github.com/rust-lang/cargo/blob/home-0.5.11/crates/home/src/windows.rs
// We should keep this code in sync with the above.
#[cfg(not(target_vendor = "uwp"))]
fn dir_crt(env: &'static str) -> Option<PathBuf> {
fn dir_crt() -> Option<PathBuf> {
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
use std::ptr;
use std::slice;
use windows_sys::Win32::Foundation::S_OK;
use windows_sys::Win32::System::Com::CoTaskMemFree;
use windows_sys::Win32::UI::Shell::{
FOLDERID_LocalAppData, FOLDERID_RoamingAppData, SHGetKnownFolderPath,
KF_FLAG_DONT_VERIFY,
FOLDERID_LocalAppData, SHGetKnownFolderPath, KF_FLAG_DONT_VERIFY,
};
extern "C" {
fn wcslen(buf: *const u16) -> usize;
}
let folder_id = match env {
"APPDATA" => FOLDERID_RoamingAppData,
"LOCALAPPDATA" => FOLDERID_LocalAppData,
_ => return None,
let mut path = ptr::null_mut();
let S_OK = (unsafe {
SHGetKnownFolderPath(
&FOLDERID_LocalAppData,
KF_FLAG_DONT_VERIFY as u32,
ptr::null_mut(),
&mut path,
)
}) else {
// Free any allocated memory even on failure. A null ptr is a no-op for `CoTaskMemFree`.
unsafe { CoTaskMemFree(path.cast()) };
return None;
};
unsafe {
let mut path = ptr::null_mut();
match SHGetKnownFolderPath(
&folder_id,
KF_FLAG_DONT_VERIFY as u32,
std::ptr::null_mut(),
&mut path,
) {
S_OK => {
let path_slice = slice::from_raw_parts(path, wcslen(path));
let s = OsString::from_wide(path_slice);
CoTaskMemFree(path.cast());
Some(PathBuf::from(s))
}
_ => {
// Free any allocated memory even on failure. A null ptr is a no-op for `CoTaskMemFree`.
CoTaskMemFree(path.cast());
None
}
}
}
let path_slice = unsafe { slice::from_raw_parts(path, wcslen(path)) };
let s = OsString::from_wide(path_slice);
unsafe { CoTaskMemFree(path.cast()) };
Some(PathBuf::from(s))
}
#[cfg(target_vendor = "uwp")]
fn dir_crt(_env: &'static str) -> Option<PathBuf> {
fn dir_crt() -> Option<PathBuf> {
None
}
pub fn cache_dir(home_dir: &Path) -> PathBuf {
dir_inner("LOCALAPPDATA").unwrap_or_else(|| home_dir.join("AppData").join("Local"))
}
}
#[cfg(not(windows))]
mod xdg {
use std::env;
use std::path::{Path, PathBuf};
fn env_var_or_none(env_var: &str) -> Option<PathBuf> {
std::env::var(env_var).ok().and_then(|path| {
let path = PathBuf::from(path);
// Return None if the path obtained from the environment variable isn’t absolute.
if path.is_absolute() {
Some(path)
} else {
None
}
})
}
fn env_var_or_default(home_dir: &Path, env_var: &str, default: impl AsRef<Path>) -> PathBuf {
env_var_or_none(env_var).unwrap_or_else(|| home_dir.join(default))
}
pub fn cache_dir(home_dir: &Path) -> PathBuf {
env_var_or_default(home_dir, "XDG_CACHE_HOME", ".cache/")
env::var_os("XDG_CACHE_HOME")
.map(PathBuf::from)
.filter(|path| path.is_absolute())
.unwrap_or_else(|| home_dir.join(".cache/"))
}
}