rename: Fallback to a copy if the filesystems mismatch
In `nix::rename`, if the call to `rename` fails with `EXDEV` (failure because the source and the destination are in a different filesystems) switch to copying and removing the source. To avoid having to re-implement the copy manually, I switched the function to use the c++17 `filesystem` library (which has a `copy` function that should do what we want). Fix #6262
This commit is contained in:
parent
c2de0a232c
commit
6f89fb6008
1 changed files with 13 additions and 2 deletions
|
@ -1,8 +1,11 @@
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
#include "types.hh"
|
#include "types.hh"
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
void createSymlink(const Path & target, const Path & link,
|
void createSymlink(const Path & target, const Path & link,
|
||||||
|
@ -42,8 +45,16 @@ void replaceSymlink(const Path & target, const Path & link,
|
||||||
|
|
||||||
void moveFile(const Path & oldName, const Path & newName)
|
void moveFile(const Path & oldName, const Path & newName)
|
||||||
{
|
{
|
||||||
if (::rename(oldName.c_str(), newName.c_str()))
|
auto oldPath = fs::path(oldName);
|
||||||
throw SysError("renaming '%1%' to '%2%'", oldName, newName);
|
auto newPath = fs::path(newName);
|
||||||
|
try {
|
||||||
|
fs::rename(oldPath, newPath);
|
||||||
|
} catch (fs::filesystem_error & e) {
|
||||||
|
if (e.code().value() == EXDEV) {
|
||||||
|
fs::copy(oldName, newName, fs::copy_options::copy_symlinks);
|
||||||
|
fs::remove_all(oldName);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue