mirror of
https://github.com/privatevoid-net/nix-super.git
synced 2024-11-11 00:36:20 +02:00
6f89fb6008
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
60 lines
1.5 KiB
C++
60 lines
1.5 KiB
C++
#include <sys/time.h>
|
|
#include <filesystem>
|
|
|
|
#include "util.hh"
|
|
#include "types.hh"
|
|
|
|
namespace fs = std::filesystem;
|
|
|
|
namespace nix {
|
|
|
|
void createSymlink(const Path & target, const Path & link,
|
|
std::optional<time_t> mtime)
|
|
{
|
|
if (symlink(target.c_str(), link.c_str()))
|
|
throw SysError("creating symlink from '%1%' to '%2%'", link, target);
|
|
if (mtime) {
|
|
struct timeval times[2];
|
|
times[0].tv_sec = *mtime;
|
|
times[0].tv_usec = 0;
|
|
times[1].tv_sec = *mtime;
|
|
times[1].tv_usec = 0;
|
|
if (lutimes(link.c_str(), times))
|
|
throw SysError("setting time of symlink '%s'", link);
|
|
}
|
|
}
|
|
|
|
void replaceSymlink(const Path & target, const Path & link,
|
|
std::optional<time_t> mtime)
|
|
{
|
|
for (unsigned int n = 0; true; n++) {
|
|
Path tmp = canonPath(fmt("%s/.%d_%s", dirOf(link), n, baseNameOf(link)));
|
|
|
|
try {
|
|
createSymlink(target, tmp, mtime);
|
|
} catch (SysError & e) {
|
|
if (e.errNo == EEXIST) continue;
|
|
throw;
|
|
}
|
|
|
|
moveFile(tmp, link);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
void moveFile(const Path & oldName, const Path & newName)
|
|
{
|
|
auto oldPath = fs::path(oldName);
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|