fs.cpp
1 // Copyright (c) 2017-present The Bitcoin Core developers 2 // Distributed under the MIT software license, see the accompanying 3 // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 5 #include <util/fs.h> 6 #include <util/syserror.h> 7 8 #ifndef WIN32 9 #include <cstring> 10 #include <fcntl.h> 11 #include <sys/file.h> 12 #include <sys/utsname.h> 13 #include <unistd.h> 14 #else 15 #include <codecvt> 16 #include <limits> 17 #include <windows.h> 18 #endif 19 20 #include <cassert> 21 #include <cerrno> 22 #include <string> 23 24 namespace fsbridge { 25 26 FILE *fopen(const fs::path& p, const char *mode) 27 { 28 #ifndef WIN32 29 return ::fopen(p.c_str(), mode); 30 #else 31 std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,wchar_t> utf8_cvt; 32 return ::_wfopen(p.wstring().c_str(), utf8_cvt.from_bytes(mode).c_str()); 33 #endif 34 } 35 36 fs::path AbsPathJoin(const fs::path& base, const fs::path& path) 37 { 38 assert(base.is_absolute()); 39 return path.empty() ? base : fs::path(base / path); 40 } 41 42 #ifndef WIN32 43 44 static std::string GetErrorReason() 45 { 46 return SysErrorString(errno); 47 } 48 49 FileLock::FileLock(const fs::path& file) 50 { 51 fd = open(file.c_str(), O_RDWR); 52 if (fd == -1) { 53 reason = GetErrorReason(); 54 } 55 } 56 57 FileLock::~FileLock() 58 { 59 if (fd != -1) { 60 close(fd); 61 } 62 } 63 64 bool FileLock::TryLock() 65 { 66 if (fd == -1) { 67 return false; 68 } 69 70 struct flock lock; 71 lock.l_type = F_WRLCK; 72 lock.l_whence = SEEK_SET; 73 lock.l_start = 0; 74 lock.l_len = 0; 75 if (fcntl(fd, F_SETLK, &lock) == -1) { 76 reason = GetErrorReason(); 77 return false; 78 } 79 80 return true; 81 } 82 #else 83 84 static std::string GetErrorReason() { 85 return Win32ErrorString(GetLastError()); 86 } 87 88 FileLock::FileLock(const fs::path& file) 89 { 90 hFile = CreateFileW(file.wstring().c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 91 nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); 92 if (hFile == INVALID_HANDLE_VALUE) { 93 reason = GetErrorReason(); 94 } 95 } 96 97 FileLock::~FileLock() 98 { 99 if (hFile != INVALID_HANDLE_VALUE) { 100 CloseHandle(hFile); 101 } 102 } 103 104 bool FileLock::TryLock() 105 { 106 if (hFile == INVALID_HANDLE_VALUE) { 107 return false; 108 } 109 _OVERLAPPED overlapped = {}; 110 if (!LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY, 0, std::numeric_limits<DWORD>::max(), std::numeric_limits<DWORD>::max(), &overlapped)) { 111 reason = GetErrorReason(); 112 return false; 113 } 114 return true; 115 } 116 #endif 117 118 std::string get_filesystem_error_message(const fs::filesystem_error& e) 119 { 120 #ifndef WIN32 121 return e.what(); 122 #else 123 // Convert from Multi Byte to utf-16 124 std::string mb_string(e.what()); 125 int size = MultiByteToWideChar(CP_ACP, 0, mb_string.data(), mb_string.size(), nullptr, 0); 126 127 std::wstring utf16_string(size, L'\0'); 128 MultiByteToWideChar(CP_ACP, 0, mb_string.data(), mb_string.size(), &*utf16_string.begin(), size); 129 // Convert from utf-16 to utf-8 130 return std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t>().to_bytes(utf16_string); 131 #endif 132 } 133 134 } // namespace fsbridge