diff options
Diffstat (limited to 'src/util/system.cpp')
-rw-r--r-- | src/util/system.cpp | 262 |
1 files changed, 1 insertions, 261 deletions
diff --git a/src/util/system.cpp b/src/util/system.cpp index 98e89f82e7..88a8f39ecd 100644 --- a/src/util/system.cpp +++ b/src/util/system.cpp @@ -9,6 +9,7 @@ #include <fs.h> #include <sync.h> #include <util/check.h> +#include <util/fs_helpers.h> #include <util/getuniquepath.h> #include <util/strencodings.h> #include <util/string.h> @@ -22,17 +23,6 @@ #endif #ifndef WIN32 -// for posix_fallocate, in configure.ac we check if it is present after this -#ifdef __linux__ - -#ifdef _POSIX_C_SOURCE -#undef _POSIX_C_SOURCE -#endif - -#define _POSIX_C_SOURCE 200112L - -#endif // __linux__ - #include <algorithm> #include <cassert> #include <fcntl.h> @@ -44,7 +34,6 @@ #include <codecvt> -#include <io.h> /* for _commit */ #include <shellapi.h> #include <shlobj.h> #endif @@ -72,78 +61,6 @@ const char * const BITCOIN_SETTINGS_FILENAME = "settings.json"; ArgsManager gArgs; -/** Mutex to protect dir_locks. */ -static GlobalMutex cs_dir_locks; -/** A map that contains all the currently held directory locks. After - * successful locking, these will be held here until the global destructor - * cleans them up and thus automatically unlocks them, or ReleaseDirectoryLocks - * is called. - */ -static std::map<std::string, std::unique_ptr<fsbridge::FileLock>> dir_locks GUARDED_BY(cs_dir_locks); - -bool LockDirectory(const fs::path& directory, const fs::path& lockfile_name, bool probe_only) -{ - LOCK(cs_dir_locks); - fs::path pathLockFile = directory / lockfile_name; - - // If a lock for this directory already exists in the map, don't try to re-lock it - if (dir_locks.count(fs::PathToString(pathLockFile))) { - return true; - } - - // Create empty lock file if it doesn't exist. - FILE* file = fsbridge::fopen(pathLockFile, "a"); - if (file) fclose(file); - auto lock = std::make_unique<fsbridge::FileLock>(pathLockFile); - if (!lock->TryLock()) { - return error("Error while attempting to lock directory %s: %s", fs::PathToString(directory), lock->GetReason()); - } - if (!probe_only) { - // Lock successful and we're not just probing, put it into the map - dir_locks.emplace(fs::PathToString(pathLockFile), std::move(lock)); - } - return true; -} - -void UnlockDirectory(const fs::path& directory, const fs::path& lockfile_name) -{ - LOCK(cs_dir_locks); - dir_locks.erase(fs::PathToString(directory / lockfile_name)); -} - -void ReleaseDirectoryLocks() -{ - LOCK(cs_dir_locks); - dir_locks.clear(); -} - -bool DirIsWritable(const fs::path& directory) -{ - fs::path tmpFile = GetUniquePath(directory); - - FILE* file = fsbridge::fopen(tmpFile, "a"); - if (!file) return false; - - fclose(file); - remove(tmpFile); - - return true; -} - -bool CheckDiskSpace(const fs::path& dir, uint64_t additional_bytes) -{ - constexpr uint64_t min_disk_space = 52428800; // 50 MiB - - uint64_t free_bytes_available = fs::space(dir).available; - return free_bytes_available >= min_disk_space + additional_bytes; -} - -std::streampos GetFileSize(const char* path, std::streamsize max) { - std::ifstream file{path, std::ios::binary}; - file.ignore(max); - return file.gcount(); -} - /** * Interpret a string argument as a boolean. * @@ -1091,182 +1008,6 @@ void ArgsManager::LogArgs() const logArgsPrefix("Command-line arg:", "", m_settings.command_line_options); } -bool RenameOver(fs::path src, fs::path dest) -{ -#ifdef __MINGW64__ - // This is a workaround for a bug in libstdc++ which - // implements std::filesystem::rename with _wrename function. - // This bug has been fixed in upstream: - // - GCC 10.3: 8dd1c1085587c9f8a21bb5e588dfe1e8cdbba79e - // - GCC 11.1: 1dfd95f0a0ca1d9e6cbc00e6cbfd1fa20a98f312 - // For more details see the commits mentioned above. - return MoveFileExW(src.wstring().c_str(), dest.wstring().c_str(), - MOVEFILE_REPLACE_EXISTING) != 0; -#else - std::error_code error; - fs::rename(src, dest, error); - return !error; -#endif -} - -/** - * Ignores exceptions thrown by create_directories if the requested directory exists. - * Specifically handles case where path p exists, but it wasn't possible for the user to - * write to the parent directory. - */ -bool TryCreateDirectories(const fs::path& p) -{ - try - { - return fs::create_directories(p); - } catch (const fs::filesystem_error&) { - if (!fs::exists(p) || !fs::is_directory(p)) - throw; - } - - // create_directories didn't create the directory, it had to have existed already - return false; -} - -bool FileCommit(FILE *file) -{ - if (fflush(file) != 0) { // harmless if redundantly called - LogPrintf("%s: fflush failed: %d\n", __func__, errno); - return false; - } -#ifdef WIN32 - HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file)); - if (FlushFileBuffers(hFile) == 0) { - LogPrintf("%s: FlushFileBuffers failed: %d\n", __func__, GetLastError()); - return false; - } -#elif defined(MAC_OSX) && defined(F_FULLFSYNC) - if (fcntl(fileno(file), F_FULLFSYNC, 0) == -1) { // Manpage says "value other than -1" is returned on success - LogPrintf("%s: fcntl F_FULLFSYNC failed: %d\n", __func__, errno); - return false; - } -#elif HAVE_FDATASYNC - if (fdatasync(fileno(file)) != 0 && errno != EINVAL) { // Ignore EINVAL for filesystems that don't support sync - LogPrintf("%s: fdatasync failed: %d\n", __func__, errno); - return false; - } -#else - if (fsync(fileno(file)) != 0 && errno != EINVAL) { - LogPrintf("%s: fsync failed: %d\n", __func__, errno); - return false; - } -#endif - return true; -} - -void DirectoryCommit(const fs::path &dirname) -{ -#ifndef WIN32 - FILE* file = fsbridge::fopen(dirname, "r"); - if (file) { - fsync(fileno(file)); - fclose(file); - } -#endif -} - -bool TruncateFile(FILE *file, unsigned int length) { -#if defined(WIN32) - return _chsize(_fileno(file), length) == 0; -#else - return ftruncate(fileno(file), length) == 0; -#endif -} - -/** - * this function tries to raise the file descriptor limit to the requested number. - * It returns the actual file descriptor limit (which may be more or less than nMinFD) - */ -int RaiseFileDescriptorLimit(int nMinFD) { -#if defined(WIN32) - return 2048; -#else - struct rlimit limitFD; - if (getrlimit(RLIMIT_NOFILE, &limitFD) != -1) { - if (limitFD.rlim_cur < (rlim_t)nMinFD) { - limitFD.rlim_cur = nMinFD; - if (limitFD.rlim_cur > limitFD.rlim_max) - limitFD.rlim_cur = limitFD.rlim_max; - setrlimit(RLIMIT_NOFILE, &limitFD); - getrlimit(RLIMIT_NOFILE, &limitFD); - } - return limitFD.rlim_cur; - } - return nMinFD; // getrlimit failed, assume it's fine -#endif -} - -/** - * this function tries to make a particular range of a file allocated (corresponding to disk space) - * it is advisory, and the range specified in the arguments will never contain live data - */ -void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length) { -#if defined(WIN32) - // Windows-specific version - HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(file)); - LARGE_INTEGER nFileSize; - int64_t nEndPos = (int64_t)offset + length; - nFileSize.u.LowPart = nEndPos & 0xFFFFFFFF; - nFileSize.u.HighPart = nEndPos >> 32; - SetFilePointerEx(hFile, nFileSize, 0, FILE_BEGIN); - SetEndOfFile(hFile); -#elif defined(MAC_OSX) - // OSX specific version - // NOTE: Contrary to other OS versions, the OSX version assumes that - // NOTE: offset is the size of the file. - fstore_t fst; - fst.fst_flags = F_ALLOCATECONTIG; - fst.fst_posmode = F_PEOFPOSMODE; - fst.fst_offset = 0; - fst.fst_length = length; // mac os fst_length takes the # of free bytes to allocate, not desired file size - fst.fst_bytesalloc = 0; - if (fcntl(fileno(file), F_PREALLOCATE, &fst) == -1) { - fst.fst_flags = F_ALLOCATEALL; - fcntl(fileno(file), F_PREALLOCATE, &fst); - } - ftruncate(fileno(file), static_cast<off_t>(offset) + length); -#else - #if defined(HAVE_POSIX_FALLOCATE) - // Version using posix_fallocate - off_t nEndPos = (off_t)offset + length; - if (0 == posix_fallocate(fileno(file), 0, nEndPos)) return; - #endif - // Fallback version - // TODO: just write one byte per block - static const char buf[65536] = {}; - if (fseek(file, offset, SEEK_SET)) { - return; - } - while (length > 0) { - unsigned int now = 65536; - if (length < now) - now = length; - fwrite(buf, 1, now, file); // allowed to fail; this function is advisory anyway - length -= now; - } -#endif -} - -#ifdef WIN32 -fs::path GetSpecialFolderPath(int nFolder, bool fCreate) -{ - WCHAR pszPath[MAX_PATH] = L""; - - if(SHGetSpecialFolderPathW(nullptr, pszPath, nFolder, fCreate)) - { - return fs::path(pszPath); - } - - LogPrintf("SHGetSpecialFolderPathW() failed, could not obtain requested path.\n"); - return fs::path(""); -} -#endif - #ifndef WIN32 std::string ShellEscape(const std::string& arg) { @@ -1290,7 +1031,6 @@ void runCommand(const std::string& strCommand) } #endif - void SetupEnvironment() { #ifdef HAVE_MALLOPT_ARENA_MAX |