Skip to content

Instantly share code, notes, and snippets.

@zekroTJA
Created October 13, 2024 10:25
Show Gist options
  • Save zekroTJA/9860be965833d2f34dae6fa28afe4b18 to your computer and use it in GitHub Desktop.
Save zekroTJA/9860be965833d2f34dae6fa28afe4b18 to your computer and use it in GitHub Desktop.
A simple implementation to rename files when on the same device or move them by copy and delete if not.
use std::{fs, io, path::Path};
pub fn move_recursively(from: impl AsRef<Path>, to: impl AsRef<Path>) -> Result<(), io::Error> {
if !to.as_ref().exists() {
fs::create_dir_all(to.as_ref())?;
}
let from_meta = from.as_ref().metadata()?;
let to_meta = to.as_ref().metadata()?;
// On non-unix systems, we can not check if from and to are on the same device, so we
// just perform a full recursive move by copy.
#[cfg(not(unix))]
return move_by_copy_recursively(from, to);
// On unix-system, we can simply use rename to move files if both from and to are on
// the same storage device. Otherwise, we need to perform a full recursive move by copy.
#[cfg(unix)]
{
use std::os::unix::fs::MetadataExt;
if from_meta.dev() == to_meta.dev() {
fs::rename(from, to)?;
} else {
move_by_copy_recursively(from.as_ref(), to.as_ref())?;
}
Ok(())
}
}
pub fn move_by_copy_recursively(from: &Path, to: &Path) -> Result<(), io::Error> {
if !to.exists() {
fs::create_dir(to)?;
}
for entry in fs::read_dir(from)? {
let entry = entry?;
let path = entry.path();
let to_path = to.join(path.file_name().expect("file name"));
if entry.metadata()?.is_dir() {
move_by_copy_recursively(&path, &to_path)?;
fs::remove_dir(&path)?;
} else {
fs::copy(&path, &to_path)?;
fs::remove_file(&path)?;
}
}
Ok(())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment