13#ifdef JOEDB_HAS_BROKEN_POSIX_LOCKING
14#define JOEDB_SETLK F_SETLK
15#define JOEDB_SETLKW F_SETLKW
19#define JOEDB_SETLK F_OFD_SETLK
20#define JOEDB_SETLKW F_OFD_SETLKW
25#ifndef _FILE_OFFSET_BITS
28 sizeof(off_t) ==
sizeof(int64_t),
29 "Define the _FILE_OFFSET_BITS macro to 32 or 64 to silence this error. 64 is recommended if possible. Joedb does not check for file-size overflow."
34 void Posix_File::throw_last_error(
const char *action)
const
39 std::string(action) +
' ' + file_name +
": " + ::strerror(errno)
45 int Posix_File::lock(
int command,
short type, int64_t start, int64_t size)
50 lock.l_whence = SEEK_SET;
51 lock.l_start = off_t(start);
52 lock.l_len = off_t(size);
55 return ::fcntl(posix_fd.
get_fd(), command, &lock);
59 bool Posix_File::try_exclusive_lock(int64_t start, int64_t size)
62 return lock(
JOEDB_SETLK, F_WRLCK, start, size) == 0;
70 throw_last_error(
"read-locking");
78 throw_last_error(
"write-locking");
92 const ssize_t result =
::pread(posix_fd.get_fd(), buffer, size, offset);
95 throw_last_error(
"reading");
97 return size_t(result);
106 while (written < size)
117 throw_last_error(
"writing");
119 written += size_t(result);
128 return ::fcntl(fd, F_FULLFSYNC);
138 if (posix_fd.fullsync() == -1)
139 throw_last_error(
"syncing");
141 if (!created_durably && !file_name.empty())
143 auto directory = std::filesystem::path(file_name).parent_path();
144 if (directory.empty())
147 Posix_FD dir_fd(::open(directory.c_str(), O_RDONLY | O_DIRECTORY));
163 created_durably =
true;
167#if _POSIX_SYNCHRONIZED_IO > 0
172 if (::fdatasync(posix_fd.
get_fd()) == -1)
174 throw_last_error(
"syncing");
184 fd = ::open(file_name, O_RDONLY);
186 fd = ::open(file_name, O_RDWR);
188 fd = ::open(file_name, O_RDWR | O_CREAT | O_EXCL, 00644);
196 fd = ::open(file_name, O_RDWR | O_CREAT, 00644);
206 posix_fd(file_name, mode),
209 if (posix_fd.get_fd() < 0)
210 throw_last_error(
"opening");
220 throw_last_error(
"locking");
230 if (::fstat(posix_fd.get_fd(), &s) < 0)
231 throw_last_error(
"getting size of");
233 return int64_t(s.st_size);
static constexpr int64_t last_position
Abstract_File(Open_Mode mode)
virtual void datasync()
Write data durably (no file-size change).
void exclusive_lock_tail()
static void warning(beman::cstring_view message) noexcept
size_t pread(char *buffer, size_t size, int64_t offset) const override
Read a range of bytes.
void unlock(int64_t start, int64_t size) noexcept override
Remove a lock. The range should match the range of a corresponding lock.
void pwrite(const char *buffer, size_t size, int64_t offset) override
Write a range of bytes. Extend file size if necessary.
void exclusive_lock(int64_t start, int64_t size) override
Lock a range of bytes for writing (prevents both writes and reads).
void shared_lock(int64_t start, int64_t size) override
Lock a range of bytes for reading (prevents writes, not reads).
void sync() override
Write data durably (including file-size change).
Posix_File(int fd, Open_Mode mode)
int64_t get_size() const override
Get the size of the file, or -1 if it is unknown.
@ create_new
fails if already exists, locks the file for writing
@ write_existing
fails if does not exist or locked, locks the file for writing
@ shared_write
like write_existing_or_create_new, but does not lock the file, and does not fail if locked
@ write_existing_or_create_new
either write_existing or create_new depending on whether the file exists
@ write_lock
like write_existing_or_create_new, but waits instead of failing if already locked
@ read_existing
fails if does not exist