X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Ffilesys.cpp;h=f61b39b9465b191badf70befdb27da41e27b13f5;hb=09f9e465e760cb8fd791222405a9e5e68a676ba0;hp=501f9ad6ca53f721f4d117b2a199bb6b2e251af9;hpb=64c060e1f2d94d8277246d8cdd8a886010564770;p=oweals%2Fminetest.git diff --git a/src/filesys.cpp b/src/filesys.cpp index 501f9ad6c..f61b39b94 100644 --- a/src/filesys.cpp +++ b/src/filesys.cpp @@ -20,12 +20,16 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "filesys.h" #include "util/string.h" #include -#include -#include -#include +#include +#include +#include #include #include "log.h" #include "config.h" +#include "porting.h" +#ifdef __ANDROID__ +#include "settings.h" // For g_settings +#endif namespace fs { @@ -121,46 +125,33 @@ bool IsDirDelimiter(char c) bool RecursiveDelete(const std::string &path) { - infostream<<"Recursively deleting \""< content = GetDirListing(path); - for(size_t i=0; i content = GetDirListing(path); + for (const DirListNode &n: content) { + std::string fullpath = path + DIR_DELIM + n.name; + if (!RecursiveDelete(fullpath)) { + errorstream << "RecursiveDelete: Failed to recurse to " + << fullpath << std::endl; return false; } } + infostream << "RecursiveDelete: Deleting directory " << path << std::endl; + if (!RemoveDirectory(path.c_str())) { + errorstream << "Failed to recursively delete directory " + << path << std::endl; + return false; + } return true; } @@ -245,7 +236,7 @@ std::vector GetDirListing(const std::string &pathstring) If so, try stat(). */ if(isdir == -1) { - struct stat statbuf; + struct stat statbuf{}; if (stat((pathstring + "/" + node.name).c_str(), &statbuf)) continue; isdir = ((statbuf.st_mode & S_IFDIR) == S_IFDIR); @@ -261,22 +252,20 @@ std::vector GetDirListing(const std::string &pathstring) bool CreateDir(const std::string &path) { int r = mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); - if(r == 0) - { + if (r == 0) { return true; } - else - { - // If already exists, return true - if(errno == EEXIST) - return true; - return false; - } + + // If already exists, return true + if (errno == EEXIST) + return true; + return false; + } bool PathExists(const std::string &path) { - struct stat st; + struct stat st{}; return (stat(path.c_str(),&st) == 0); } @@ -287,7 +276,7 @@ bool IsPathAbsolute(const std::string &path) bool IsDir(const std::string &path) { - struct stat statbuf; + struct stat statbuf{}; if(stat(path.c_str(), &statbuf)) return false; // Actually error; but certainly not a directory return ((statbuf.st_mode & S_IFDIR) == S_IFDIR); @@ -314,9 +303,13 @@ bool RecursiveDelete(const std::string &path) { // Child char argv_data[3][10000]; +#ifdef __ANDROID__ + strcpy(argv_data[0], "/system/bin/rm"); +#else strcpy(argv_data[0], "/bin/rm"); +#endif strcpy(argv_data[1], "-rf"); - strncpy(argv_data[2], path.c_str(), 10000); + strncpy(argv_data[2], path.c_str(), sizeof(argv_data[2]) - 1); char *argv[4]; argv[0] = argv_data[0]; argv[1] = argv_data[1]; @@ -346,19 +339,19 @@ bool RecursiveDelete(const std::string &path) bool DeleteSingleFileOrEmptyDirectory(const std::string &path) { - if(IsDir(path)){ + if (IsDir(path)) { bool did = (rmdir(path.c_str()) == 0); - if(!did) - errorstream<<"rmdir errno: "<get("TMPFolder"); #else return DIR_DELIM "tmp"; #endif @@ -381,16 +374,36 @@ std::string TempPath() #endif -void GetRecursiveSubPaths(const std::string &path, std::vector &dst) +void GetRecursiveDirs(std::vector &dirs, const std::string &dir) +{ + static const std::set chars_to_ignore = { '_', '.' }; + if (dir.empty() || !IsDir(dir)) + return; + dirs.push_back(dir); + fs::GetRecursiveSubPaths(dir, dirs, false, chars_to_ignore); +} + +std::vector GetRecursiveDirs(const std::string &dir) +{ + std::vector result; + GetRecursiveDirs(result, dir); + return result; +} + +void GetRecursiveSubPaths(const std::string &path, + std::vector &dst, + bool list_files, + const std::set &ignore) { std::vector content = GetDirListing(path); - for(unsigned int i=0; i list = GetDirListing(path); - for(unsigned int i=0; i content = fs::GetDirListing(source); - for(unsigned int i=0; i < content.size(); i++){ - std::string sourcechild = source + DIR_DELIM + content[i].name; - std::string targetchild = target + DIR_DELIM + content[i].name; - if(content[i].dir){ + for (const auto &dln : content) { + std::string sourcechild = source + DIR_DELIM + dln.name; + std::string targetchild = target + DIR_DELIM + dln.name; + if(dln.dir){ if(!fs::CopyDir(sourcechild, targetchild)){ retval = false; } @@ -525,9 +536,8 @@ bool CopyDir(const std::string &source, const std::string &target) } return retval; } - else { - return false; - } + + return false; } bool PathStartsWith(const std::string &path, const std::string &prefix) @@ -616,48 +626,51 @@ std::string RemoveRelativePathComponents(std::string path) { 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); } @@ -698,22 +711,37 @@ bool safeWriteToFile(const std::string &path, const std::string &content) 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)