stc
Loading...
Searching...
No Matches
FileLock.hpp
Go to the documentation of this file.
1
2#pragma once
3
4#include <chrono>
5#include <functional>
6#include <memory>
7#include <thread>
8#include <filesystem>
9
10#ifndef _WIN32
11#include <fcntl.h>
12#include <cstdio>
13#include <unistd.h>
14#include <sys/file.h>
15#else
16
17#define NOMINMAX
18#include <windows.h>
19#include <handleapi.h>
20#endif
21
22namespace stc {
23
44class FileLock {
45private:
46#ifndef _WIN32
47 int fd;
48#else
49 HANDLE fd;
50#endif
51
52 const std::filesystem::path lockPath;
53
54 bool locked = false;
55
56public:
57 enum class Errors {
58 OPEN_ERROR = 42,
59 LOCK_ERROR = 43
60 };
61
72 FileLock(const std::filesystem::path& lockPath, bool lockNonblocking = true) : lockPath(lockPath) {
73#ifndef _WIN32
74 fd = open(lockPath.c_str(), O_RDWR | O_CREAT, 0666);
75 if (fd < 0) {
77 }
78
79
80 // TODO: better error handling of flock()s return value.
81 if ((locked = flock(fd, LOCK_EX | (lockNonblocking == true ? LOCK_NB : 0)) == 0) == false) {
82 close(fd);
83 fd = -1;
84 // While removing the file here would look relevant, it isn't.
85 // If the file is locked, it obviously shouldn't be removed.
86 }
87
88 if (!locked) {
90 }
91#else
92 auto _cppStr = lockPath.string();
93 auto str = _cppStr.c_str();
94 fd = CreateFileA(
95 str,
96 GENERIC_WRITE,
97 0,
98 NULL,
99 CREATE_ALWAYS,
100 FILE_FLAG_DELETE_ON_CLOSE,
101 NULL
102 );
103
104 if (fd == INVALID_HANDLE_VALUE) {
105 DWORD err = GetLastError();
106 if (err == 32) {
107 throw Errors::LOCK_ERROR;
108 }
109 throw Errors::OPEN_ERROR;
110 }
111
112 locked = true;
113#endif
114
115 }
116
118 unlock();
119 }
120
121 // I might add these in the future with some fancy move stuff
122 // or whatever to allow for moving locks around.
123 // For now, it sounds useless.
124 FileLock(const FileLock&) = delete;
125 FileLock& operator=(const FileLock&) = delete;
126
132 bool hasLock() { return locked; }
133
141 void unlock() {
142 if (!locked) return;
143
144 locked = false;
145#ifndef _WIN32
146 if (fd >= 0) {
147 flock(fd, LOCK_UN);
148 close(fd);
149 }
150 // TODO: this results in a race condition. Fix
151 if (std::filesystem::exists(lockPath)) {
152 std::filesystem::remove(lockPath);
153 }
154#else
155 if (fd != INVALID_HANDLE_VALUE && CloseHandle(fd)) {
156 auto _cppStr = lockPath.string();
157 auto str = _cppStr.c_str();
158
159 CloseHandle(fd);
160 }
161#endif
162 }
163
192 // Fuck you MSVC
193#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201907L) || __cplusplus >= 201907L)
194 [[nodiscard("Ignoring the return value of dynamicAcquireLock results in the immediate unlock of the returned lock")]]
195#else
196 [[nodiscard]]
197#endif
198 static std::shared_ptr<FileLock> dynamicAcquireLock(
199 const std::filesystem::path& path,
200 std::function<bool()> control,
201 unsigned int sleepSeconds = 1
202 ) {
203 while (control()) {
204 try {
205 std::shared_ptr<FileLock> lock = std::make_shared<FileLock>(path, true);
206 if (lock->hasLock()) {
207 return lock;
208 }
209 } catch (const Errors& e) {
210 if (e == Errors::OPEN_ERROR) {
211 return nullptr;
212 }
213 }
214 if (sleepSeconds != 0) {
215 std::this_thread::sleep_for(std::chrono::seconds(sleepSeconds));
216 }
217 }
218 return nullptr;
219 }
220};
221
222}
Definition FileLock.hpp:44
FileLock(const FileLock &)=delete
bool hasLock()
Definition FileLock.hpp:132
~FileLock()
Definition FileLock.hpp:117
FileLock & operator=(const FileLock &)=delete
void unlock()
Definition FileLock.hpp:141
FileLock(const std::filesystem::path &lockPath, bool lockNonblocking=true)
Definition FileLock.hpp:72
Errors
Definition FileLock.hpp:57
static std::shared_ptr< FileLock > dynamicAcquireLock(const std::filesystem::path &path, std::function< bool()> control, unsigned int sleepSeconds=1)
Definition FileLock.hpp:198
Definition CaptureStream.hpp:6