#[cfg(target_os = "linux")]
use std::ffi::CString;
#[cfg(windows)]
use windows_sys::Win32::Storage::FileSystem::CreateSymbolicLinkW;
#[cfg(target_os = "linux")]
use crate::op::{HardLinkOp, Op, SymlinkOp};
#[cfg(windows)]
pub fn windows_symlink_dir(path: String, target: String) -> std::io::Result<()> {
let path_w: Vec<u16> = path.encode_utf16().chain(std::iter::once(0)).collect();
let target_w: Vec<u16> = target.encode_utf16().chain(std::iter::once(0)).collect();
unsafe {
let res = CreateSymbolicLinkW(
path_w.as_ptr(),
target_w.as_ptr(),
1, );
if !res {
Err(std::io::Error::last_os_error())
} else {
Ok(())
}
}
}
#[cfg(windows)]
pub fn windows_symlink_file(path: String, target: String) -> std::io::Result<()> {
let path_w: Vec<u16> = path.encode_utf16().chain(std::iter::once(0)).collect();
let target_w: Vec<u16> = target.encode_utf16().chain(std::iter::once(0)).collect();
unsafe {
let res = CreateSymbolicLinkW(
path_w.as_ptr(),
target_w.as_ptr(),
0, );
if !res {
Err(std::io::Error::last_os_error())
} else {
Ok(())
}
}
}
#[cfg(target_os = "linux")]
pub async fn hard_link(
src: impl AsRef<std::path::Path>,
dst: impl AsRef<std::path::Path>,
) -> std::io::Result<()> {
let src = src.as_ref();
let dst = dst.as_ref();
let driver = crate::executor::current_driver();
if driver.as_ref().is_some_and(|d| d.supports_completion()) {
let src_cstr = CString::new(src.as_os_str().as_encoded_bytes()).map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::InvalidInput,
format!("Invalid path: {}", e),
)
})?;
let dst_cstr = CString::new(dst.as_os_str().as_encoded_bytes()).map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::InvalidInput,
format!("Invalid path: {}", e),
)
})?;
let driver = driver.expect("invalid driver state");
let mut op = HardLinkOp::new(src_cstr, dst_cstr);
std::future::poll_fn(|cx| op.poll_completion(cx, driver.as_ref())).await
} else if crate::executor::offload_fs() {
let src = src.to_owned();
let dst = dst.to_owned();
crate::spawn_blocking(move || std::fs::hard_link(src, dst))
.await
.map_err(|_| crate::fs::file::blocking_pool_io_error())?
} else {
std::fs::hard_link(src, dst)
}
}
#[cfg(not(target_os = "linux"))]
pub async fn hard_link(
src: impl AsRef<std::path::Path>,
dst: impl AsRef<std::path::Path>,
) -> std::io::Result<()> {
if crate::executor::offload_fs() {
let src = src.as_ref().to_owned();
let dst = dst.as_ref().to_owned();
crate::spawn_blocking(move || std::fs::hard_link(src, dst))
.await
.map_err(|_| crate::fs::file::blocking_pool_io_error())?
} else {
std::fs::hard_link(src, dst)
}
}
#[cfg(windows)]
pub async fn symlink_dir(
src: impl AsRef<std::path::Path>,
dst: impl AsRef<std::path::Path>,
) -> std::io::Result<()> {
if crate::executor::offload_fs() {
let src = src.as_ref();
let dst = dst.as_ref();
let src_str = src.to_string_lossy().to_string();
let dst_str = dst.to_string_lossy().to_string();
crate::spawn_blocking(move || windows_symlink_dir(src_str, dst_str))
.await
.map_err(|_| crate::fs::file::blocking_pool_io_error())?
} else {
let src = src.as_ref();
let dst = dst.as_ref();
let src_str = src.to_string_lossy().to_string();
let dst_str = dst.to_string_lossy().to_string();
windows_symlink_dir(src_str, dst_str)
}
}
#[cfg(target_os = "linux")]
pub async fn symlink_dir(
src: impl AsRef<std::path::Path>,
dst: impl AsRef<std::path::Path>,
) -> std::io::Result<()> {
let src = src.as_ref();
let dst = dst.as_ref();
let driver = crate::executor::current_driver();
if driver.as_ref().is_some_and(|d| d.supports_completion()) {
let src_cstr = CString::new(src.as_os_str().as_encoded_bytes()).map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::InvalidInput,
format!("Invalid path: {}", e),
)
})?;
let dst_cstr = CString::new(dst.as_os_str().as_encoded_bytes()).map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::InvalidInput,
format!("Invalid path: {}", e),
)
})?;
let driver = driver.expect("invalid driver state");
let mut op = SymlinkOp::new(src_cstr, dst_cstr);
std::future::poll_fn(|cx| op.poll_completion(cx, driver.as_ref())).await
} else if crate::executor::offload_fs() {
let src = src.to_owned();
let dst = dst.to_owned();
crate::spawn_blocking(move || std::os::unix::fs::symlink(src, dst))
.await
.map_err(|_| crate::fs::file::blocking_pool_io_error())?
} else {
std::os::unix::fs::symlink(src, dst)
}
}
#[cfg(not(any(windows, target_os = "linux")))]
pub async fn symlink_dir(
src: impl AsRef<std::path::Path>,
dst: impl AsRef<std::path::Path>,
) -> std::io::Result<()> {
if crate::executor::offload_fs() {
let src = src.as_ref().to_owned();
let dst = dst.as_ref().to_owned();
crate::spawn_blocking(move || std::os::unix::fs::symlink(src, dst))
.await
.map_err(|_| crate::fs::file::blocking_pool_io_error())?
} else {
std::os::unix::fs::symlink(src, dst)
}
}
#[cfg(windows)]
pub async fn symlink_file(
src: impl AsRef<std::path::Path>,
dst: impl AsRef<std::path::Path>,
) -> std::io::Result<()> {
if crate::executor::offload_fs() {
let src = src.as_ref();
let dst = dst.as_ref();
let src_str = src.to_string_lossy().to_string();
let dst_str = dst.to_string_lossy().to_string();
crate::spawn_blocking(move || windows_symlink_file(src_str, dst_str))
.await
.map_err(|_| crate::fs::file::blocking_pool_io_error())?
} else {
let src = src.as_ref();
let dst = dst.as_ref();
let src_str = src.to_string_lossy().to_string();
let dst_str = dst.to_string_lossy().to_string();
windows_symlink_file(src_str, dst_str)
}
}
#[cfg(target_os = "linux")]
pub async fn symlink_file(
src: impl AsRef<std::path::Path>,
dst: impl AsRef<std::path::Path>,
) -> std::io::Result<()> {
let src = src.as_ref();
let dst = dst.as_ref();
let driver = crate::executor::current_driver();
if driver.as_ref().is_some_and(|d| d.supports_completion()) {
let src_cstr = CString::new(src.as_os_str().as_encoded_bytes()).map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::InvalidInput,
format!("Invalid path: {}", e),
)
})?;
let dst_cstr = CString::new(dst.as_os_str().as_encoded_bytes()).map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::InvalidInput,
format!("Invalid path: {}", e),
)
})?;
let driver = driver.expect("invalid driver state");
let mut op = SymlinkOp::new(src_cstr, dst_cstr);
std::future::poll_fn(|cx| op.poll_completion(cx, driver.as_ref())).await
} else if crate::executor::offload_fs() {
let src = src.to_owned();
let dst = dst.to_owned();
crate::spawn_blocking(move || std::os::unix::fs::symlink(src, dst))
.await
.map_err(|_| crate::fs::file::blocking_pool_io_error())?
} else {
std::os::unix::fs::symlink(src, dst)
}
}
#[cfg(not(any(windows, target_os = "linux")))]
pub async fn symlink_file(
src: impl AsRef<std::path::Path>,
dst: impl AsRef<std::path::Path>,
) -> std::io::Result<()> {
if crate::executor::offload_fs() {
let src = src.as_ref().to_owned();
let dst = dst.as_ref().to_owned();
crate::spawn_blocking(move || std::os::unix::fs::symlink(src, dst))
.await
.map_err(|_| crate::fs::file::blocking_pool_io_error())?
} else {
std::os::unix::fs::symlink(src, dst)
}
}
pub async fn symlink(
src: impl AsRef<std::path::Path>,
dst: impl AsRef<std::path::Path>,
) -> std::io::Result<()> {
symlink_file(src, dst).await
}