1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-21 15:04:11 -05:00

fix(fs): support rename across filesystems

Rather than expect the user to know that they need to handle a special
case when renaming across filesystems, we can just handle it for them.

Fixes #3092
This commit is contained in:
Joe Hillenbrand 2023-07-19 10:03:38 -07:00
parent 5919f31891
commit 9e40cbe495
No known key found for this signature in database
GPG key ID: 5C6B337CE0857004

View file

@ -179,16 +179,14 @@ impl FileSystem for RealFs {
} }
fn rename_sync(&self, oldpath: &Path, newpath: &Path) -> FsResult<()> { fn rename_sync(&self, oldpath: &Path, newpath: &Path) -> FsResult<()> {
fs::rename(oldpath, newpath).map_err(Into::into) rename(oldpath, newpath)
} }
async fn rename_async( async fn rename_async(
&self, &self,
oldpath: PathBuf, oldpath: PathBuf,
newpath: PathBuf, newpath: PathBuf,
) -> FsResult<()> { ) -> FsResult<()> {
spawn_blocking(move || fs::rename(oldpath, newpath)) spawn_blocking(move || rename(&oldpath, &newpath)).await?
.await?
.map_err(Into::into)
} }
fn link_sync(&self, oldpath: &Path, newpath: &Path) -> FsResult<()> { fn link_sync(&self, oldpath: &Path, newpath: &Path) -> FsResult<()> {
@ -598,6 +596,29 @@ fn read_dir(path: &Path) -> FsResult<Vec<FsDirEntry>> {
Ok(entries) Ok(entries)
} }
fn rename(oldpath: &Path, newpath: &Path) -> FsResult<()> {
match fs::rename(oldpath, newpath) {
Ok(_) => Ok(()),
Err(err) => {
if err.raw_os_error() == Some(libc::EXDEV) {
// EXDEV: rename fails because oldpath and newpath are not on the same
// mounted filesystem. We need to do a copy and remove.
//
// This check can be replaced with the following once
// https://github.com/rust-lang/rust/issues/86442 stabilizes:
//
// if err.kind() == io::ErrorKind::CrossDeviceLink
//
copy_file(oldpath, newpath)?;
fs::remove_file(oldpath)?;
Ok(())
} else {
Err(err.into())
}
}
}
}
#[cfg(not(windows))] #[cfg(not(windows))]
fn symlink( fn symlink(
oldpath: &Path, oldpath: &Path,