libcosmos
Linux C++ System Programming Library
|
Thin Wrapper around OS file descriptors. More...
#include <FileDescriptor.hxx>
Classes | |
struct | Owner |
Information about file owner settings. More... | |
Public Types | |
enum class | DescFlag : int { NONE = 0 , CLOEXEC = FD_CLOEXEC } |
Configurable per file-descriptors flags. More... | |
enum class | SealFlag : unsigned int { SEAL = F_SEAL_SEAL , SHRINK = F_SEAL_SHRINK , GROW = F_SEAL_GROW , WRITE = F_SEAL_WRITE , FUTURE_WRITE = F_SEAL_FUTURE_WRITE } |
Flags used in addSeals(). More... | |
enum class | LeaseType : int { READ = F_RDLCK , WRITE = F_WRLCK , UNLOCK = F_UNLCK } |
Different request types for managing file leases. More... | |
using | DescFlags = BitMask<DescFlag> |
Collection of OpenFlag used for opening files. | |
using | SealFlags = BitMask<SealFlag> |
Collection flags for applying seals in addSeals(). | |
Public Member Functions | |
constexpr | FileDescriptor (FileNum fd) |
bool | valid () const |
Returns whether currently a valid file descriptor number is assigned. | |
bool | invalid () const |
void | setFD (const FileNum fd) |
Assigns a new primitive file descriptor to the object. | |
void | reset () |
Invalidates the stored file descriptor. | |
void | close () |
Explicitly close the contained FD. | |
void | duplicate (const FileDescriptor new_fd, const CloseOnExec cloexec=CloseOnExec{true}) const |
Get a duplicate file descriptor that will further be known as new_fd. | |
FileDescriptor | duplicate (const FileNum lowest=FileNum{0}, const CloseOnExec cloexec=CloseOnExec{true}) const |
Get a duplicate file descriptor using the lowest available free file descriptor number. | |
DescFlags | getFlags () const |
Retrieves the current file descriptor flags. | |
void | setFlags (const DescFlags flags) |
Changes the current file descriptor flags. | |
void | setCloseOnExec (bool on_off) |
convenience wrapper around setFlags to change CLOEXEC setting | |
std::tuple< OpenMode, OpenFlags > | getStatusFlags () const |
Retrieve the file's OpenMode and current OpenFlags. | |
void | setStatusFlags (const OpenFlags flags) |
Change certain file descriptor status flags. | |
void | sync () |
Flush oustanding writes to disk. | |
void | dataSync () |
Flush outstanding writes to disk except metadata. | |
void | addSeals (const SealFlags flags) |
Add a seal for memory file descriptors. | |
SealFlags | getSeals () const |
Get the currently set SealFlags for the file descriptor. | |
int | getPipeSize () const |
For pipe file descriptors return the size of the pipe buffer in the kernel. | |
int | setPipeSize (const int new_size) |
For pipe file descriptors this sets a new size for the pipe buffer in the kernel. | |
FileNum | raw () const |
Returns the primitive file descriptor contained in the object. | |
bool | operator== (const FileDescriptor &other) const |
bool | operator!= (const FileDescriptor &other) const |
bool | getLock (FileLock &lock) const |
Check lock availability for traditional process-wide POSIX locks. | |
bool | setLock (const FileLock &lock) const |
Release, or attempt to obtain, a traditional process-wide POSIX lock. | |
void | setLockWait (const FileLock &lock) const |
Blocking version of setLock(). | |
bool | getOFDLock (FileLock &lock) const |
Just like getLock() but using open-file-description locks. | |
bool | setOFDLock (const FileLock &lock) const |
Just like setLock() but using open-file-description locks. | |
void | setOFDLockWait (const FileLock &lock) const |
Just like setLockWait() but using open-file-description locks. | |
void | getOwner (Owner &owner) const |
Returns the current file descriptor owner settings. | |
void | setOwner (const Owner owner) |
Change the current file descriptor owner settings. | |
std::optional< Signal > | getSignal () const |
Returns the currently configured signal for asynchronous I/O. | |
void | setSignal (std::optional< Signal > sig) |
Configure the signal to be used for asynchronous I/O. | |
LeaseType | getLease () const |
Gets the lease type currently set, or required to resolve a lease break. | |
void | setLease (const LeaseType lease) |
Sets a new lease type on the file descriptor. | |
Protected Member Functions | |
int | fcntl (int cmd) const |
template<typename T > | |
int | fcntl (int cmd, T val) const |
Protected Attributes | |
FileNum | m_fd = FileNum::INVALID |
Thin Wrapper around OS file descriptors.
This type carries a primitive file descriptor and provides various operations to perform on it. This is mostly kept on a generic level without knowledge about the actual object represented by the file descriptor.
Instances of this type are not intended to be used on their own, they should only be used as building blocks to provide more abstract mechanisms. In particular this type does not automatically close the associated file descriptor during destruction. This has to be done explicitly instead.
Definition at line 35 of file FileDescriptor.hxx.
Collection of OpenFlag used for opening files.
Definition at line 45 of file FileDescriptor.hxx.
Collection flags for applying seals in addSeals().
Definition at line 57 of file FileDescriptor.hxx.
|
strong |
Configurable per file-descriptors flags.
Definition at line 39 of file FileDescriptor.hxx.
|
strong |
Different request types for managing file leases.
The basic constants are the same as for FileLock::Type, but the underlying type is different. Semantically is also not quite the same, thus a distinct type is used here for file leases.
Definition at line 65 of file FileDescriptor.hxx.
|
strong |
Flags used in addSeals().
Definition at line 48 of file FileDescriptor.hxx.
|
inlineexplicitconstexpr |
Definition at line 191 of file FileDescriptor.hxx.
void cosmos::FileDescriptor::addSeals | ( | const SealFlags | flags | ) |
Add a seal for memory file descriptors.
This is only supported for file descriptors referring to a "memfd" as it is created by MemFile. It allows to restrict what operations can be performed on the file in the future (this affects all open file descriptions referring to the file).
Definition at line 127 of file FileDescriptor.cxx.
void cosmos::FileDescriptor::close | ( | ) |
Explicitly close the contained FD.
This asks the operating system to close the associated file. The stored file descriptor will be reset().
On rare occasions closing a file can fail. The most prominent error is "invalid file descriptor" (EINVAL) but there can be other situations, like when during close() outstanding writes are performed.
This member function can thus throw an exception on these conditions. In this case the contained file descriptor will still be reset() to avoid identical follow-up errors.
Definition at line 17 of file FileDescriptor.cxx.
void cosmos::FileDescriptor::dataSync | ( | ) |
Flush outstanding writes to disk except metadata.
This is an optimization of sync() that only writes out the actual file data, but not the metadata. This can make sense if e.g. the file size did not change but the data changed (e.g. for fixed size database files etc.).
Definition at line 123 of file FileDescriptor.cxx.
void cosmos::FileDescriptor::duplicate | ( | const FileDescriptor | new_fd, |
const CloseOnExec | cloexec = CloseOnExec{true} ) const |
Get a duplicate file descriptor that will further be known as new_fd.
The currently stored file descriptor will be duplicated and the primitive file descriptor number set in new_fd
will be used as the duplicate representation. If new_fd
is already an open file object then it will first be silently closed, errors ignored.
[in] | cloexec | Denotes whether the duplicate file descriptor will have the close-on-exec flag set. |
Definition at line 38 of file FileDescriptor.cxx.
FileDescriptor cosmos::FileDescriptor::duplicate | ( | const FileNum | lowest = FileNum{0}, |
const CloseOnExec | cloexec = CloseOnExec{true} ) const |
Get a duplicate file descriptor using the lowest available free file descriptor number.
Be careful to close the returned file descriptor again when necessary. It is best to turn it into some object that manages file descriptor lifetime automatically.
[in] | lowest | From which file descriptor to start looking for a free entry. By default zero, i.e. the lowest available free file descriptor number will be used. |
[in] | cloexec | Denotes whether the duplicate file descriptor will have the close-on-exec flag set. |
Definition at line 46 of file FileDescriptor.cxx.
|
protected |
Definition at line 29 of file FileDescriptor.cxx.
|
protected |
Definition at line 34 of file FileDescriptor.cxx.
FileDescriptor::DescFlags cosmos::FileDescriptor::getFlags | ( | ) | const |
Retrieves the current file descriptor flags.
Definition at line 56 of file FileDescriptor.cxx.
FileDescriptor::LeaseType cosmos::FileDescriptor::getLease | ( | ) | const |
Gets the lease type currently set, or required to resolve a lease break.
For an overview of file leases, see setLease()
.
The semantics for getLease()
are somewhat confusing. As long as there is no lease break in progress it returns the lease that is currently held on the file, or LeaseType::UNLOCK if no lease is currently present. As soon as a lease break happens and the lease holder is notified of it, getLease()
returns the new target lease type that is necessary to resolve the lease break situation, which can be LeaseType::READ, if the lease breaker wants to open the file read-only and the lease can be downgraded, or LeaseType::UNLOCK if the lease breaker wants to open the file for writing and the lease has to be removed.
Definition at line 278 of file FileDescriptor.cxx.
bool cosmos::FileDescriptor::getLock | ( | FileLock & | lock | ) | const |
Check lock availability for traditional process-wide POSIX locks.
On input the lock
data structure describes a lock that the caller would like to place on the file. On output, if placing the lock would be possible, lock.type()
will be FileLock::Type::UNLOCK
. Otherwise lock
will describe the conflicting lock that prevents placing the lock. More than one lock can be conflicting, but only the information for a single lock will be returned.
This check is subject to race conditions and cannot guarantee that a later call to setLock()
will succeed. If true
is returned, then placing the lock is currently possible (i.e. lock.type() == FileLock::Type::UNLOCK
).
Definition at line 165 of file FileDescriptor.cxx.
bool cosmos::FileDescriptor::getOFDLock | ( | FileLock & | lock | ) | const |
Just like getLock() but using open-file-description locks.
Definition at line 199 of file FileDescriptor.cxx.
void cosmos::FileDescriptor::getOwner | ( | Owner & | owner | ) | const |
Returns the current file descriptor owner settings.
If no owner has been set previously, then the call will succeed but owner.valid()
will return false
. This is no fully specified in fcntl(2)
but practical tests show that in this case Owner::Type::THREAD with a ThreadID of zero is returned by the kernel.
Definition at line 241 of file FileDescriptor.cxx.
int cosmos::FileDescriptor::getPipeSize | ( | ) | const |
For pipe file descriptors return the size of the pipe buffer in the kernel.
Definition at line 145 of file FileDescriptor.cxx.
FileDescriptor::SealFlags cosmos::FileDescriptor::getSeals | ( | ) | const |
Get the currently set SealFlags for the file descriptor.
Definition at line 135 of file FileDescriptor.cxx.
std::optional< Signal > cosmos::FileDescriptor::getSignal | ( | ) | const |
Returns the currently configured signal for asynchronous I/O.
If std::nullopt is returned, then the default SIGIO signal (cosmos::signal::IO_EVENT) is configured. Otherwise the returned signal will be delivered together with extra information if SA_SIGINFO handler is setup for it. This extra information allows to identify the file descriptor for which the event was sent.
There exists a corner case, though, if the file descriptor for which the event was configured is closed but a copy of the file descriptor is still around. Then the signal will report the original now closed file descriptor.
To keep track of multiple file descriptor events occurring in parallel it is recommended to use a realtime signal, which is queued in the kernel up to a certain limit.
Definition at line 257 of file FileDescriptor.cxx.
Retrieve the file's OpenMode and current OpenFlags.
Definition at line 74 of file FileDescriptor.cxx.
|
inline |
Definition at line 196 of file FileDescriptor.hxx.
|
inline |
Definition at line 347 of file FileDescriptor.hxx.
|
inline |
Definition at line 343 of file FileDescriptor.hxx.
|
inline |
Returns the primitive file descriptor contained in the object.
Definition at line 341 of file FileDescriptor.hxx.
|
inline |
Invalidates the stored file descriptor.
This operation simply resets the stored file descriptor to FileNum::INVALID. No system call will be performed and if the file is not closed by other means a file descriptor leak will be the result.
Definition at line 212 of file FileDescriptor.hxx.
|
inline |
convenience wrapper around setFlags to change CLOEXEC setting
Definition at line 266 of file FileDescriptor.hxx.
|
inline |
Assigns a new primitive file descriptor to the object.
A potentially already contained file descriptor will not be closed, the caller is responsible for preventing leaks.
Definition at line 203 of file FileDescriptor.hxx.
void cosmos::FileDescriptor::setFlags | ( | const DescFlags | flags | ) |
Changes the current file descriptor flags.
Definition at line 66 of file FileDescriptor.cxx.
void cosmos::FileDescriptor::setLease | ( | const LeaseType | lease | ) |
Sets a new lease type on the file descriptor.
A file lease is a mechanism that allows the lease holder to act on the file before another process (the lease breaker) accesses it. It has some similarity to a mandatory file lock in so far as the lease breaker will be blocked (in open()
or truncate()
) until the lease holder unlocks or downgrades the lease. The kernel puts a limit on the maximum block time in seconds until the lease holder has to resolve the situation, otherwise the lease will be forcibly removed. This time is configured in the sys.fs.lease-break-time sysctl.
The lease holder is informed of a lease break situation by a signal, which is configured via setSignal()
. See also getSignal()
.
Leases are associated with the open file description and thus shared by copies of the file descriptor, can be inherited to child processes and will be automatically released once all copies of the file descriptor are closed.
File leases are only supported on regular files. A process may only acquire a lease for files it owns, or if the process has the CAP_LEASE
capability, otherwise an ApiError with Errno::ACCESS is thrown.
This call is used to establish, remove or change an existing lease. To remove an existing lease pass LeaseType::UNLOCK to this function.
A lease of LeaseType::READ can only be placed on a file descriptor opened read-only. In this case the lease holder will be notified when the file is opened for writing or is truncated.
A lease of LeaseType::WRITE can only be placed if there are currently no other open file descriptors for the file (otherwise the lease would already be broken). The lease holder will be notified when the file is opened for reading, writing or is truncated. The file descriptor can be open for reading and writing.
A lease can be downgraded from LeaseType::WRITE to LeaseType::READ, which will allow lease breakers, that want to open the file for reading, to be unblocked. This only works if the file descriptor has been opened read-only, though.
If a conflicting lease is currently set on the file, or the file's OpenMode is not compatible with the requested lease, an ApiError with Errno::AGAIN is thrown.
Another process can open a file on which a lease is held in non-blocking mode, which will result in Errno::WOULD_BLOCK error. Even this attempt to open the file will trigger the lease breaker logic. The same is true if the lease breaker's system call is interrupted by a signal, or the lease breaker gets killed while blocking on the lease.
Definition at line 288 of file FileDescriptor.cxx.
bool cosmos::FileDescriptor::setLock | ( | const FileLock & | lock | ) | const |
Release, or attempt to obtain, a traditional process-wide POSIX lock.
lock
describes a lock to be released or to be placed on the file.
For unlocking set lock.type()
to FileLock::Type::UNLOCK
. Unlock operations always return true
or throw an ApiError
.
For unlocking this always returns true
. For locking, if placing the lock succeeds, true
is returned, false
otherwise. This call will not block if the lock cannot be obtained. On error conditions an ApiError
is thrown.
Definition at line 175 of file FileDescriptor.cxx.
void cosmos::FileDescriptor::setLockWait | ( | const FileLock & | lock | ) | const |
Blocking version of setLock().
This call will block until the described lock
is placed on the file. On error conditions an ApiError
is thrown.
There is some basic deadlock detection for this operation which can result in an ApiError
with Errno::DEADLOCK to be thrown.
Definition at line 191 of file FileDescriptor.cxx.
bool cosmos::FileDescriptor::setOFDLock | ( | const FileLock & | lock | ) | const |
Just like setLock() but using open-file-description locks.
Definition at line 209 of file FileDescriptor.cxx.
void cosmos::FileDescriptor::setOFDLockWait | ( | const FileLock & | lock | ) | const |
Just like setLockWait() but using open-file-description locks.
Definition at line 229 of file FileDescriptor.cxx.
void cosmos::FileDescriptor::setOwner | ( | const Owner | owner | ) |
Change the current file descriptor owner settings.
The credentials at the time of this call will be associated with the file descriptor and will be used for permission checks when an asynchronous I/O signal needs to be delivered.
Definition at line 249 of file FileDescriptor.cxx.
int cosmos::FileDescriptor::setPipeSize | ( | const int | new_size | ) |
For pipe file descriptors this sets a new size for the pipe buffer in the kernel.
The kernel can choose a larger size if it deems this necessary. /proc/sys/fs/pipe-max-size defines a maximum pipe buffer size for the system. The actually used size will be returned from this call.
Definition at line 155 of file FileDescriptor.cxx.
void cosmos::FileDescriptor::setSignal | ( | std::optional< Signal > | sig | ) |
Configure the signal to be used for asynchronous I/O.
If std::nullopt is passed then the default SIGIO signal will be configured and no extra information is provided to the signal handler. Otherwise the supplied signal is used and the extra information is supplied as described at getSignal()
.
This signal is also used to notify a process of file lease events, see setLease()
.
Definition at line 270 of file FileDescriptor.cxx.
void cosmos::FileDescriptor::setStatusFlags | ( | const OpenFlags | flags | ) |
Change certain file descriptor status flags.
The basic file OpenMode cannot be changed for an open file descriptor. From OpenFlags only the flags APPEND, ASYNC, DIRECT, NOATIME and NONBLOCK can be changed afterwards.
Definition at line 87 of file FileDescriptor.cxx.
void cosmos::FileDescriptor::sync | ( | ) |
Flush oustanding writes to disk.
Kernel buffering may cause written data to stay in memory until it is deemed necessary to actually write to disk. Use this function to make sure that any writes that happened on the file descriptor will actually be transferred to the underlying disk device. This covers not only the actual file data but also the metadata (inode data).
This operation ensures that the data is on disk even if the system is hard reset, crashes or loses power. The call blocks until the underlying device reports that the transfer has completed.
Even after that it is not yet ensured that the directory containing the file has actually the directory entry written to disk. To ensure this as well perform sync() also on a file descriptor for the directory containing the file.
This call can cause an ApiError to be thrown e.g. if:
Definition at line 119 of file FileDescriptor.cxx.
|
inline |
Returns whether currently a valid file descriptor number is assigned.
Definition at line 195 of file FileDescriptor.hxx.
|
protected |
Definition at line 535 of file FileDescriptor.hxx.