Background
I tried to develop a Rust lib to assist with swapping filenames for any two files, but I had problems when I tried to dealing with paths on WSL.
Examples
Normal Situation
| File1 | File2 | |
|---|---|---|
| Before | D:\test\1.ext1 |
D:\test\2.ext2 |
| After | D:\test\2.ext1 |
D:\test\1.ext2 |
Relative Path
| File1 | File2 | |
|---|---|---|
| Before | ./1.ext1 |
~/2.ext2 |
| After | D:\test\2.ext1 |
C:\Users\xxx\1.ext2 |
WSL Situation
| File1 | File2 | |
|---|---|---|
| Before | \\wsl.localhost\Debian\home\user1\1.ext1 |
\\wsl.localhost\Debian\home\user1\2.ext2 |
| After (WHAT I WANT) | \\wsl.localhost\Debian\home\user1\2.ext1 |
\\wsl.localhost\Debian\home\user1\1.ext2 |
What I've done
MWE:
use std::path::{Path, PathBuf};
fn main() {
// Please create this file in your wsl for test.
// `~/1.ext1`
// MODIFY THIS with your wsl user name
let wsl_user_name = "";
// Please create this on working dir (windows) for test.
// `./2.ext2`
let current_exe = std::env::current_exe().unwrap();
let base_dir = current_exe.parent().unwrap();
let wsl_file = PathBuf::from(format!(
r"\\wsl.localhost\Debian\home\{}\1.ext1",
wsl_user_name
));
let win_file = PathBuf::from(r"./2.ext2");
let result_wsl = path_get_absolute_exist(&wsl_file, base_dir);
dbg!(result_wsl);
let result_win = path_get_absolute_exist(&win_file, base_dir);
dbg!(result_win);
}
fn path_get_absolute_exist(path: &Path, base_dir: &Path) -> (bool, PathBuf) {
if path.as_os_str().is_empty() {
return (false, path.to_path_buf());
}
let mut path = path.to_path_buf();
#[cfg(windows)]
{
use std::path::{Component, Prefix};
path = {
let temp = path.to_str().unwrap_or("").replace("/", "\\");
PathBuf::from(temp)
};
let is_absolute = {
let mut components = path.components();
if let Some(Component::Prefix(prefix_component)) = components.next() {
let has_root_dir = matches!(components.next(), Some(Component::RootDir));
dbg!(has_root_dir);
if !has_root_dir {
false
} else {
dbg!(prefix_component.kind());
matches!(
prefix_component.kind(), //Useful for judge `\\wsl.localhost\` but useless when test exist()
Prefix::VerbatimUNC(..)
| Prefix::UNC(..)
| Prefix::VerbatimDisk(..)
| Prefix::Disk(_)
| Prefix::DeviceNS(..)
| Prefix::Verbatim(_)
)
}
} else {
dbg!(path.is_absolute());
path.is_absolute()
}
};
if !is_absolute {
if path.starts_with("~") {
if let Ok(home_dir) = std::env::var("USERPROFILE") {
let mut new_path = PathBuf::from(home_dir);
let remaining = path.strip_prefix("~/").ok();
if let Some(rem) = remaining {
new_path.push(rem);
path = new_path;
} else if path.to_string_lossy() == "~" {
path = new_path;
} else {
// "~something"
path = base_dir.join(path);
}
}
} else {
path = base_dir.join(path);
}
}
dbg!(format!("Path Final: {}", &path.display()));
}
#[cfg(not(windows))]
{
path = {
let temp = path.to_str().unwrap_or("").replace("\\", "/");
PathBuf::from(temp)
};
if !path.is_absolute() {
if path.starts_with("~") {
if let Ok(home_dir) = std::env::var("HOME") {
let mut new_path = PathBuf::from(home_dir);
if let Some(remaining) = path.strip_prefix("~/") {
new_path.push(remaining);
} else if path.to_string_lossy() == "~" {
// Just "~", so it's the home directory
}
path = new_path;
}
} else {
path = base_dir.join(path);
}
}
dbg!(format!("Path Final: {}", &path.display()));
}
let canonical = path.canonicalize();
match canonical {
Ok(x) => (x.exists(), x),
Err(e) => {
eprintln!("{}", e);
(path.exists(), path)
}
}
}
error info
[src\exchange.rs:161:13] is_absolute = true
[src\exchange.rs:190:9] &path = "\\\\wsl.localhost\\Debian\\home\\user1\\1.ext1"
[src\exchange.rs:161:13] is_absolute = true
[src\exchange.rs:190:9] &path = "\\\\wsl.localhost\\Debian\\home\\user1\\2.ext2"
File does not exist
I didn't give all the code here for length reasons, if you need all the code, please check it out at https://github.com/Mikachu2333/exchange_name_lib