This commit is contained in:
AmandaSternberg-creator 2025-09-15 12:57:22 +00:00 committed by GitHub
commit 93aa27e67c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 36 additions and 1 deletions

View file

@ -242,6 +242,7 @@ Lee Doughty <32392044+leedoughty@users.noreply.github.com>
memchr <memchr@proton.me>
Max Romanowski <maxr777@proton.me>
Aldlss <ayaldlss@gmail.com>
Amanda Sternberg <mandis.sternberg@gmail.com>
********************

View file

@ -320,6 +320,20 @@ pub(crate) fn mtime_as_i64<P: AsRef<Path>>(path: P) -> io::Result<i64> {
.as_millis() as i64)
}
/// On POSIX this is EXDEV (error 18) and on Windows it is ERROR_NOT_SAME_DEVICE
/// (error 17).
pub(crate) fn safe_rename(src: &Path, dst: &Path) -> io::Result<()> {
match fs::rename(src, dst) {
Ok(_) => Ok(()),
Err(e) if e.kind() == io::ErrorKind::CrossesDevices => {
fs::copy(src, dst)?;
fs::remove_file(src)?;
Ok(())
}
Err(e) => Err(e),
}
}
pub fn remove_files<S>(media_folder: &Path, files: &[S]) -> Result<()>
where
S: AsRef<str> + std::fmt::Debug,
@ -344,7 +358,7 @@ where
}
// move file to trash, clobbering any existing file with the same name
fs::rename(&src_path, &dst_path)?;
safe_rename(&src_path, &dst_path)?;
// mark it as modified, so we can expire it in the future
let secs = time::SystemTime::now();
@ -437,9 +451,11 @@ pub(crate) fn data_for_file(media_folder: &Path, fname: &str) -> Result<Option<V
#[cfg(test)]
mod test {
use std::borrow::Cow;
use std::fs;
use tempfile::tempdir;
use super::safe_rename;
use crate::media::files::add_data_to_folder_uniquely;
use crate::media::files::add_hash_suffix_to_file_stem;
use crate::media::files::normalize_filename;
@ -550,4 +566,22 @@ mod test {
Cow::<str>::Owned(format!("{}_", " ".repeat(MAX_MEDIA_FILENAME_LENGTH - 2)))
);
}
#[test]
fn safe_rename_moves_file() {
// This test only verifies that ´safe_rename´calls back to copy+remove logic
// when needed. It does not simulate a real cross-device move.
let dir = tempdir().unwrap();
let src = dir.path().join("test_src.txt");
let dst = dir.path().join("test_dst.txt");
fs::write(&src, b"hello world").unwrap();
safe_rename(&src, &dst).unwrap();
assert!(dst.exists());
assert!(!src.exists());
let contents = fs::read(&dst).unwrap();
assert_eq!(contents, b"hello world");
fs::remove_file(&dst).unwrap();
}
}