1use std::{
20 env,
21 ffi::OsString,
22 fs,
23 path::{Path, PathBuf},
24};
25
26use crate::{Error, Result};
27
28#[cfg(target_family = "unix")]
29mod home_dir_impl {
30 use std::{
31 env,
32 ffi::{CStr, OsString},
33 mem,
34 os::unix::prelude::OsStringExt,
35 path::PathBuf,
36 ptr,
37 };
38
39 pub fn home_dir() -> Option<PathBuf> {
42 env::var_os("HOME")
43 .and_then(|h| if h.is_empty() { None } else { Some(h) })
44 .or_else(|| unsafe { home_fallback() })
45 .map(PathBuf::from)
46 }
47
48 unsafe fn home_fallback() -> Option<OsString> {
51 let amt = match libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) {
52 n if n < 0 => 512_usize,
53 n => n as usize,
54 };
55
56 let mut buf = Vec::with_capacity(amt);
57 let mut passwd: libc::passwd = mem::zeroed();
58 let mut result = ptr::null_mut();
59
60 let r = libc::getpwuid_r(
61 libc::getuid(),
62 &mut passwd,
63 buf.as_mut_ptr(),
64 buf.capacity(),
65 &mut result,
66 );
67
68 match r {
69 0 if !result.is_null() => {
70 let ptr = passwd.pw_dir as *const _;
71 let bytes = CStr::from_ptr(ptr).to_bytes();
72 if bytes.is_empty() {
73 return None
74 }
75
76 Some(OsStringExt::from_vec(bytes.to_vec()))
77 }
78
79 _ => None,
80 }
81 }
82}
83
84#[cfg(target_family = "windows")]
85mod home_dir_impl {
86 use std::{env, path::PathBuf};
87
88 pub fn home_dir() -> Option<PathBuf> {
89 env::var_os("APPDATA").map(PathBuf::from)
90 }
91}
92
93pub use home_dir_impl::home_dir;
94
95pub fn config_dir() -> Option<PathBuf> {
97 env::var_os("XDG_CONFIG_HOME")
98 .and_then(is_absolute_path)
99 .or_else(|| home_dir().map(|h| h.join(".config")))
100}
101
102fn is_absolute_path(path: OsString) -> Option<PathBuf> {
103 let path = PathBuf::from(path);
104 if path.is_absolute() {
105 Some(path)
106 } else {
107 None
108 }
109}
110
111pub fn expand_path(path: &str) -> Result<PathBuf> {
112 let ret: PathBuf;
113
114 if path.starts_with("~/") {
115 if let Some(homedir) = home_dir() {
116 let remains = PathBuf::from(path.strip_prefix("~/").unwrap());
117 ret = [homedir, remains].iter().collect();
118 } else {
119 panic!("Could not fetch path for home directory");
120 }
121 } else if path.starts_with('~') {
122 if let Some(homedir) = home_dir() {
123 ret = homedir
124 } else {
125 panic!("Could not fetch path for home directory");
126 }
127 } else {
128 ret = PathBuf::from(path);
129 }
130
131 Ok(ret)
132}
133
134pub fn join_config_path(file: &Path) -> Result<PathBuf> {
136 let mut path = PathBuf::new();
137 let dfi_path = Path::new("darkfi");
138
139 if let Some(v) = config_dir() {
140 path.push(v);
141 }
142
143 path.push(dfi_path);
144 path.push(file);
145
146 Ok(path)
147}
148
149pub fn get_config_path(arg: Option<String>, fallback: &str) -> Result<PathBuf> {
150 if let Some(a) = arg {
151 expand_path(&a)
152 } else {
153 join_config_path(&PathBuf::from(fallback))
154 }
155}
156
157pub fn load_keypair_to_str(path: PathBuf) -> Result<String> {
158 if Path::new(&path).exists() {
159 let key = fs::read(&path)?;
160 let str_buff = std::str::from_utf8(&key)?;
161 Ok(str_buff.to_string())
162 } else {
163 println!("Could not parse keypair path");
164 Err(Error::KeypairPathNotFound)
165 }
166}