#include <fstream>
#include "log.h"
#include "config.h"
+#include "porting.h"
namespace fs
{
{
size_t pos = path.size();
size_t dotdot_count = 0;
- while(pos != 0){
+ while (pos != 0) {
size_t component_with_delim_end = pos;
// skip a dir delimiter
- while(pos != 0 && IsDirDelimiter(path[pos-1]))
+ while (pos != 0 && IsDirDelimiter(path[pos-1]))
pos--;
// strip a path component
size_t component_end = pos;
- while(pos != 0 && !IsDirDelimiter(path[pos-1]))
+ while (pos != 0 && !IsDirDelimiter(path[pos-1]))
pos--;
size_t component_start = pos;
std::string component = path.substr(component_start,
component_end - component_start);
bool remove_this_component = false;
- if(component == "."){
+ if (component == ".") {
remove_this_component = true;
- }
- else if(component == ".."){
+ } else if (component == "..") {
remove_this_component = true;
dotdot_count += 1;
- }
- else if(dotdot_count != 0){
+ } else if (dotdot_count != 0) {
remove_this_component = true;
dotdot_count -= 1;
}
- if(remove_this_component){
- while(pos != 0 && IsDirDelimiter(path[pos-1]))
+ if (remove_this_component) {
+ while (pos != 0 && IsDirDelimiter(path[pos-1]))
pos--;
- path = path.substr(0, pos) + DIR_DELIM +
- path.substr(component_with_delim_end,
- std::string::npos);
- pos++;
+ if (component_start == 0) {
+ // We need to remove the delemiter too
+ path = path.substr(component_with_delim_end, std::string::npos);
+ } else {
+ path = path.substr(0, pos) + DIR_DELIM +
+ path.substr(component_with_delim_end, std::string::npos);
+ }
+ if (pos > 0)
+ pos++;
}
}
- if(dotdot_count > 0)
+ if (dotdot_count > 0)
return "";
// remove trailing dir delimiters
pos = path.size();
- while(pos != 0 && IsDirDelimiter(path[pos-1]))
+ while (pos != 0 && IsDirDelimiter(path[pos-1]))
pos--;
return path.substr(0, pos);
}
return false;
}
+ bool rename_success = false;
+
// Move the finished temporary file over the real file
#ifdef _WIN32
+ // When creating the file, it can cause Windows Search indexer, virus scanners and other apps
+ // to query the file. This can make the move file call below fail.
+ // We retry up to 5 times, with a 1ms sleep between, before we consider the whole operation failed
+ int number_attempts = 0;
+ while (number_attempts < 5) {
+ rename_success = MoveFileEx(tmp_file.c_str(), path.c_str(),
+ MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH);
+ if (rename_success)
+ break;
+ sleep_ms(1);
+ ++number_attempts;
+ }
+#else
// On POSIX compliant systems rename() is specified to be able to swap the
// file in place of the destination file, making this a truly error-proof
// transaction.
- // However, on Windows, the target file has to be removed first.
- remove(path.c_str());
+ rename_success = rename(tmp_file.c_str(), path.c_str()) == 0;
#endif
- if(rename(tmp_file.c_str(), path.c_str())) {
+ if (!rename_success) {
+ warningstream << "Failed to write to file: " << path.c_str() << std::endl;
// Remove the temporary file because moving it over the target file
// failed.
remove(tmp_file.c_str());
return false;
- } else {
- return true;
}
+
+ return true;
}
bool Rename(const std::string &from, const std::string &to)