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 7 #include <util/check.h> 8 #include <util/syserror.h> 9 10 #include <cerrno> 11 #include <string> 12 13 #ifndef WIN32 14 #include <fcntl.h> 15 #include <unistd.h> 16 #else 17 #include <limits> 18 #include <windows.h> 19 #endif 20 21 namespace fsbridge { 22 23 FILE *fopen(const fs::path& p, const char *mode) 24 { 25 #ifndef WIN32 26 return ::fopen(p.c_str(), mode); 27 #else 28 return ::fopen(p.utf8string().c_str(), mode); 29 #endif 30 } 31 32 fs::path AbsPathJoin(const fs::path& base, const fs::path& path) 33 { 34 assert(base.is_absolute()); 35 return path.empty() ? base : fs::path(base / path); 36 } 37 38 #ifndef WIN32 39 40 static std::string GetErrorReason() 41 { 42 return SysErrorString(errno); 43 } 44 45 FileLock::FileLock(const fs::path& file) 46 { 47 fd = open(file.c_str(), O_RDWR); 48 if (fd == -1) { 49 reason = GetErrorReason(); 50 } 51 } 52 53 FileLock::~FileLock() 54 { 55 if (fd != -1) { 56 close(fd); 57 } 58 } 59 60 bool FileLock::TryLock() 61 { 62 if (fd == -1) { 63 return false; 64 } 65 66 struct flock lock; 67 lock.l_type = F_WRLCK; 68 lock.l_whence = SEEK_SET; 69 lock.l_start = 0; 70 lock.l_len = 0; 71 if (fcntl(fd, F_SETLK, &lock) == -1) { 72 reason = GetErrorReason(); 73 return false; 74 } 75 76 return true; 77 } 78 #else 79 80 static std::string GetErrorReason() { 81 return Win32ErrorString(GetLastError()); 82 } 83 84 FileLock::FileLock(const fs::path& file) 85 { 86 hFile = CreateFileW(file.wstring().c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 87 nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); 88 if (hFile == INVALID_HANDLE_VALUE) { 89 reason = GetErrorReason(); 90 } 91 } 92 93 FileLock::~FileLock() 94 { 95 if (hFile != INVALID_HANDLE_VALUE) { 96 CloseHandle(hFile); 97 } 98 } 99 100 bool FileLock::TryLock() 101 { 102 if (hFile == INVALID_HANDLE_VALUE) { 103 return false; 104 } 105 _OVERLAPPED overlapped = {}; 106 if (!LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY, 0, std::numeric_limits<DWORD>::max(), std::numeric_limits<DWORD>::max(), &overlapped)) { 107 reason = GetErrorReason(); 108 return false; 109 } 110 return true; 111 } 112 #endif 113 114 } // namespace fsbridge