/ src / util / fs.cpp
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