use std::fs::{self, File, OpenOptions};
use std::io::{self, Read, Write};
use std::path::{Path, PathBuf};
use std::fs::metadata;
use std::ffi::OsString;
use std::os::windows::ffi::OsStrExt;
#[cfg(target_family = "unix")]
use std::os::unix::fs::symlink;
#[cfg(target_family = "windows")]
use std::os::windows::fs::{symlink_file, symlink_dir};
pub fn create_symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) -> io::Result<()> {
let original = original.as_ref();
let link = link.as_ref();
#[cfg(target_family = "unix")]
{
std::os::unix::fs::symlink(original, link)
}
#[cfg(target_family = "windows")]
{
if original.is_dir() {
symlink_dir(original, link)
} else {
symlink_file(original, link)
}
}
}
#[cfg(target_family = "unix")]
use std::os::unix::fs::MetadataExt;
#[cfg(target_family = "unix")]
fn get_owner_unix(path: &Path) -> io::Result<OsString> {
let metadata = metadata(path)?;
let uid = metadata.uid();
let pw = unsafe { libc::getpwuid(uid) };
if pw.is_null() {
return Err(io::Error::new(io::ErrorKind::NotFound, "Owner not found"));
}
let owner = unsafe { std::ffi::CStr::from_ptr((*pw).pw_name) }.to_owned();
Ok(owner.into())
}
#[cfg(target_family = "windows")]
fn get_owner_windows(path: &Path) -> io::Result<OsString> {
use std::os::windows::ffi::OsStringExt;
use winapi::um::accctrl::SE_FILE_OBJECT;
use winapi::um::aclapi::GetNamedSecurityInfoW;
use winapi::um::winnt::{PSID, OWNER_SECURITY_INFORMATION};
use winapi::shared::winerror::ERROR_SUCCESS;
use winapi::shared::sddl::ConvertSidToStringSidW;
use std::ptr;
let path_wide: Vec<u16> = path.as_os_str().encode_wide().chain(Some(0)).collect();
let mut owner_sid: PSID = ptr::null_mut();
let mut sec_desc: *mut winapi::ctypes::c_void = ptr::null_mut();
let result = unsafe {
GetNamedSecurityInfoW(
path_wide.as_ptr(),
SE_FILE_OBJECT,
OWNER_SECURITY_INFORMATION,
&mut owner_sid,
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
&mut sec_desc,
)
};
if result != ERROR_SUCCESS {
return Err(io::Error::last_os_error());
}
let mut owner_str: *mut u16 = ptr::null_mut();
let success = unsafe { ConvertSidToStringSidW(owner_sid, &mut owner_str) };
if success == 0 {
return Err(io::Error::last_os_error());
}
let owner = unsafe { OsString::from_wide(std::slice::from_raw_parts(owner_str, libc::wcslen(owner_str))) };
unsafe {
winapi::um::winbase::LocalFree(owner_str as *mut _);
}
Ok(owner)
}
pub fn get_file_owner(path: &Path) -> io::Result<OsString> {
#[cfg(target_family = "unix")]
{
get_owner_unix(path)
}
#[cfg(target_family = "windows")]
{
get_owner_windows(path)
}
}
pub fn create_file(path: &str) -> io::Result<File> {
File::create(path)
}
pub fn open_file(path: &str) -> io::Result<File> {
File::open(path)
}
pub fn read_file(path: &str) -> io::Result<String> {
let mut file = open_file(path)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
Ok(contents)
}
pub fn write_file(path: &str, content: &str, mode: WriteMode) -> io::Result<()> {
let mut file = match mode {
WriteMode::Append => OpenOptions::new().append(true).open(path)?,
WriteMode::Overwrite => File::create(path)?,
WriteMode::Delete(ref to_delete) => {
let mut contents = read_file(path)?;
contents = contents.replace(to_delete, ""); contents = contents.replace(" ", " "); let mut file = File::create(path)?;
file.write_all(contents.as_bytes())?;
return Ok(());
}
};
file.write_all(content.as_bytes())?;
Ok(())
}
pub fn has_file_access<P: AsRef<Path>>(path: P) -> bool {
let path = path.as_ref();
if !path.exists() {
return false;
}
let metadata = match metadata(path) {
Ok(meta) => meta,
Err(_) => return false,
};
let can_read = metadata.permissions().readonly() == false;
let can_write = !metadata.permissions().readonly();
can_read && can_write
}
pub fn get_file_size<P: AsRef<Path>>(path: P) -> io::Result<u64> {
let meta = metadata(path)?;
Ok(meta.len())
}
pub fn get_file_creation_date<P: AsRef<Path>>(path: P) -> io::Result<std::time::SystemTime> {
let meta = metadata(path)?;
let creation_time = meta.created()?;
Ok(creation_time)
}
pub fn get_file_modification_date<P: AsRef<Path>>(path: P) -> io::Result<std::time::SystemTime> {
let meta = metadata(path)?;
let modification_time = meta.modified()?;
Ok(modification_time)
}
pub fn has_directory_access<P: AsRef<Path>>(path: P) -> bool {
let path = path.as_ref();
if !path.exists() || !path.is_dir() {
return false;
}
let metadata = match metadata(path) {
Ok(meta) => meta,
Err(_) => return false,
};
let can_read = metadata.permissions().readonly() == false;
let can_write = !metadata.permissions().readonly();
can_read && can_write
}
pub fn create_directory(path: &str) -> io::Result<()> {
fs::create_dir_all(path)
}
pub fn delete_directory(path: &str) -> io::Result<()> {
if Path::new(path).exists() {
fs::remove_dir_all(path)?;
}
Ok(())
}
pub enum WriteMode {
Append,
Overwrite,
Delete(String),
}
pub fn move_directory(source: &str, destination: &str) -> io::Result<()> {
fs::rename(source, destination)
}
pub fn get_directory_contents(path: &str) -> io::Result<Vec<PathBuf>> {
let mut contents = Vec::new();
for entry in fs::read_dir(path)? {
let entry = entry?;
contents.push(entry.path());
}
Ok(contents)
}