Skip to content

Commit 465e1d8

Browse files
committed
First commit
0 parents  commit 465e1d8

File tree

6 files changed

+159
-0
lines changed

6 files changed

+159
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
target
2+
Cargo.lock

Cargo.toml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
[package]
2+
name = "xdg-home"
3+
version = "1.0.0"
4+
edition = "2021"
5+
authors = ["Zeeshan Ali Khan <[email protected]>"]
6+
rust-version = "1.60"
7+
8+
description = "The user's home directory as per XDG Specification"
9+
repository = "https://github.com/zeenix/xdg-home"
10+
license = "MIT"
11+
keywords = ["xdg", "home"]
12+
categories = ["filesystem", "os::unix-apis", "os::windows-apis"]
13+
readme = "README.md"
14+
15+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
16+
17+
[target.'cfg(unix)'.dependencies]
18+
nix = { version = "0.26.2", features = ["user"], default-features = false }
19+
20+
[target.'cfg(windows)'.dependencies]
21+
winapi = { version = "0.3", features = [
22+
"combaseapi",
23+
"knownfolders",
24+
"shlobj",
25+
"winerror",
26+
] }

LICENSE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
LICENSE-MIT

LICENSE-MIT

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
Permission is hereby granted, free of charge, to any
2+
person obtaining a copy of this software and associated
3+
documentation files (the "Software"), to deal in the
4+
Software without restriction, including without
5+
limitation the rights to use, copy, modify, merge,
6+
publish, distribute, sublicense, and/or sell copies of
7+
the Software, and to permit persons to whom the Software
8+
is furnished to do so, subject to the following
9+
conditions:
10+
11+
The above copyright notice and this permission notice
12+
shall be included in all copies or substantial portions
13+
of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
16+
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
17+
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
18+
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
19+
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
22+
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23+
DEALINGS IN THE SOFTWARE.

README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# xdg-home
2+
3+
Gets the user's home directory as per [XDG Base Directory Specification][xdg].
4+
5+
This is almost the same as [`home`] (and [`dirs`]) crate, except it honors `HOME` environment
6+
variable on the Windows platform as well, which is conformant to the XDG Base Directory
7+
Specification.
8+
9+
Use it where the XDG Base Directory Specification is applicable, such as in [D-Bus] code.
10+
11+
## Example
12+
13+
```rust
14+
use xdg_home::home_dir;
15+
16+
let home = home_dir().unwrap();
17+
assert!(home.is_absolute());
18+
assert!(home.exists());
19+
println!("Home directory: {}", home.display());
20+
```
21+
22+
[xdg]: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
23+
[`home`]: https://crates.io/crates/home
24+
[`dirs`]: https://crates.io/crates/dirs
25+
[D-Bus]: https://dbus.freedesktop.org/doc/dbus-specification.html

src/lib.rs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#![doc = include_str!("../README.md")]
2+
#![doc(test(attr(
3+
warn(unused),
4+
deny(warnings),
5+
// W/o this, we seem to get some bogus warning about `extern crate ..`.
6+
allow(unused_extern_crates),
7+
)))]
8+
9+
use std::path::PathBuf;
10+
11+
/// Get the path of the current user's home directory.
12+
///
13+
/// See the library documentation for more information.
14+
pub fn home_dir() -> Option<PathBuf> {
15+
match std::env::var("HOME") {
16+
Ok(home) => Some(home.into()),
17+
Err(_) => {
18+
#[cfg(unix)]
19+
{
20+
unix::home_dir()
21+
}
22+
23+
#[cfg(windows)]
24+
{
25+
win32::home_dir()
26+
}
27+
}
28+
}
29+
}
30+
31+
#[cfg(unix)]
32+
mod unix {
33+
use nix::unistd::{Uid, User};
34+
use std::path::PathBuf;
35+
36+
pub(super) fn home_dir() -> Option<PathBuf> {
37+
let uid = Uid::effective();
38+
39+
User::from_uid(uid).ok().flatten().map(|u| u.dir)
40+
}
41+
}
42+
43+
#[cfg(windows)]
44+
mod win32 {
45+
use std::{path::PathBuf, ptr};
46+
47+
use winapi::{
48+
shared::winerror::S_OK,
49+
um::{
50+
combaseapi::CoTaskMemFree, knownfolders::FOLDERID_Profile, shlobj::SHGetKnownFolderPath,
51+
},
52+
};
53+
54+
pub(super) fn home_dir() -> Option<PathBuf> {
55+
let mut psz_path = ptr::null_mut();
56+
let res = unsafe {
57+
SHGetKnownFolderPath(
58+
&FOLDERID_Profile,
59+
0,
60+
ptr::null_mut(),
61+
&mut psz_path as *mut _,
62+
)
63+
};
64+
if res != S_OK {
65+
return None;
66+
}
67+
68+
// Determine the length of the UTF-16 string.
69+
let mut len = 0;
70+
// SAFETY: `psz_path` guaranteed to be a valid pointer to a null-terminated UTF-16 string.
71+
while unsafe { *(psz_path as *const u16).offset(len) } != 0 {
72+
len += 1;
73+
}
74+
let slice = unsafe { std::slice::from_raw_parts(psz_path, len as usize) };
75+
let path = String::from_utf16(slice).ok()?;
76+
unsafe {
77+
CoTaskMemFree(psz_path as *mut _);
78+
}
79+
80+
Some(PathBuf::from(path))
81+
}
82+
}

0 commit comments

Comments
 (0)