libslic3r utils: Add a Windows-proof file move function
This commit is contained in:
parent
eb59568368
commit
55b43077d7
@ -44,6 +44,11 @@ extern local_encoded_string encode_path(const char *src);
|
|||||||
extern std::string decode_path(const char *src);
|
extern std::string decode_path(const char *src);
|
||||||
extern std::string normalize_utf8_nfc(const char *src);
|
extern std::string normalize_utf8_nfc(const char *src);
|
||||||
|
|
||||||
|
// Safely rename a file even if the target exists.
|
||||||
|
// On Windows, the file explorer (or anti-virus or whatever else) often locks the file
|
||||||
|
// for a short while, so the file may not be movable. Retry while we see recoverable errors.
|
||||||
|
extern int rename_file(const std::string &from, const std::string &to);
|
||||||
|
|
||||||
// File path / name / extension splitting utilities, working with UTF-8,
|
// File path / name / extension splitting utilities, working with UTF-8,
|
||||||
// to be published to Perl.
|
// to be published to Perl.
|
||||||
namespace PerlUtils {
|
namespace PerlUtils {
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include <boost/nowide/fstream.hpp>
|
#include <boost/nowide/fstream.hpp>
|
||||||
#include <boost/nowide/integration/filesystem.hpp>
|
#include <boost/nowide/integration/filesystem.hpp>
|
||||||
#include <boost/nowide/convert.hpp>
|
#include <boost/nowide/convert.hpp>
|
||||||
|
#include <boost/nowide/cstdio.hpp>
|
||||||
|
|
||||||
#include <tbb/task_scheduler_init.h>
|
#include <tbb/task_scheduler_init.h>
|
||||||
|
|
||||||
@ -149,6 +150,68 @@ const std::string& data_dir()
|
|||||||
return g_data_dir;
|
return g_data_dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// borrowed from LLVM lib/Support/Windows/Path.inc
|
||||||
|
int rename_file(const std::string &from, const std::string &to)
|
||||||
|
{
|
||||||
|
int ec = 0;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
// Convert to utf-16.
|
||||||
|
std::wstring wide_from = boost::nowide::widen(from);
|
||||||
|
std::wstring wide_to = boost::nowide::widen(to);
|
||||||
|
|
||||||
|
// Retry while we see recoverable errors.
|
||||||
|
// System scanners (eg. indexer) might open the source file when it is written
|
||||||
|
// and closed.
|
||||||
|
bool TryReplace = true;
|
||||||
|
|
||||||
|
// This loop may take more than 2000 x 1ms to finish.
|
||||||
|
for (int i = 0; i < 2000; ++ i) {
|
||||||
|
if (i > 0)
|
||||||
|
// Sleep 1ms
|
||||||
|
::Sleep(1);
|
||||||
|
if (TryReplace) {
|
||||||
|
// Try ReplaceFile first, as it is able to associate a new data stream
|
||||||
|
// with the destination even if the destination file is currently open.
|
||||||
|
if (::ReplaceFileW(wide_to.data(), wide_from.data(), NULL, 0, NULL, NULL))
|
||||||
|
return 0;
|
||||||
|
DWORD ReplaceError = ::GetLastError();
|
||||||
|
ec = -1; // ReplaceError
|
||||||
|
// If ReplaceFileW returned ERROR_UNABLE_TO_MOVE_REPLACEMENT or
|
||||||
|
// ERROR_UNABLE_TO_MOVE_REPLACEMENT_2, retry but only use MoveFileExW().
|
||||||
|
if (ReplaceError == ERROR_UNABLE_TO_MOVE_REPLACEMENT ||
|
||||||
|
ReplaceError == ERROR_UNABLE_TO_MOVE_REPLACEMENT_2) {
|
||||||
|
TryReplace = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// If ReplaceFileW returned ERROR_UNABLE_TO_REMOVE_REPLACED, retry
|
||||||
|
// using ReplaceFileW().
|
||||||
|
if (ReplaceError == ERROR_UNABLE_TO_REMOVE_REPLACED)
|
||||||
|
continue;
|
||||||
|
// We get ERROR_FILE_NOT_FOUND if the destination file is missing.
|
||||||
|
// MoveFileEx can handle this case.
|
||||||
|
if (ReplaceError != ERROR_ACCESS_DENIED && ReplaceError != ERROR_FILE_NOT_FOUND && ReplaceError != ERROR_SHARING_VIOLATION)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (::MoveFileExW(wide_from.c_str(), wide_to.c_str(), MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING))
|
||||||
|
return 0;
|
||||||
|
DWORD MoveError = ::GetLastError();
|
||||||
|
ec = -1; // MoveError
|
||||||
|
if (MoveError != ERROR_ACCESS_DENIED && MoveError != ERROR_SHARING_VIOLATION)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
boost::nowide::remove(to.c_str());
|
||||||
|
ec = boost::nowide::rename(from.c_str(), to.c_str());
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ec;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
||||||
#include <xsinit.h>
|
#include <xsinit.h>
|
||||||
|
Loading…
Reference in New Issue
Block a user