178 lines
5.2 KiB
C++
178 lines
5.2 KiB
C++
/***
|
|
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
|
|
|
File: FileAdvisory.Unix.cpp
|
|
Date: 2022-1-29
|
|
Author: Reece
|
|
***/
|
|
#include <Source/RuntimeInternal.hpp>
|
|
#include "FS.hpp"
|
|
#include "FileAdvisory.hpp"
|
|
#include "FileAdvisory.Unix.hpp"
|
|
#include <sys/file.h>
|
|
|
|
#if defined(AURORA_COMPILER_CLANG)
|
|
// warning: enumeration values 'kEnumCount' and 'kEnumInvalid' not handled in switch [-Wswitch
|
|
#pragma clang diagnostic ignored "-Wswitch"
|
|
// Yea, I don't give a shit.
|
|
#endif
|
|
|
|
namespace Aurora::IO::FS
|
|
{
|
|
bool ApplyDumbAdvisoryLock(int fd, EFileAdvisoryLockLevel level)
|
|
{
|
|
#if !defined(AURORA_IS_LINUX_DERIVED)
|
|
int operation = LOCK_NB;
|
|
|
|
switch (level)
|
|
{
|
|
case EFileAdvisoryLockLevel::eEnumCount:
|
|
case EFileAdvisoryLockLevel::eNoSafety:
|
|
return true;
|
|
case EFileAdvisoryLockLevel::eBlockWrite:
|
|
operation |= LOCK_SH;
|
|
break;
|
|
case EFileAdvisoryLockLevel::eBlockReadWrite:
|
|
operation |= LOCK_EX;
|
|
break;
|
|
}
|
|
|
|
// Assume:
|
|
// "Furthermore, the lock is release either by an explicit LOCK_UN
|
|
// operation on any of these duplicate file descriptors, or when
|
|
// all such file descriptors have been closed"
|
|
|
|
return ::flock(fd, operation) == 0;
|
|
#else
|
|
// Linux
|
|
int lease {};
|
|
|
|
switch (level)
|
|
{
|
|
case EFileAdvisoryLockLevel::eEnumCount:
|
|
case EFileAdvisoryLockLevel::eNoSafety:
|
|
return true;
|
|
case EFileAdvisoryLockLevel::eBlockWrite:
|
|
lease = F_RDLCK;
|
|
break;
|
|
case EFileAdvisoryLockLevel::eBlockReadWrite:
|
|
lease = F_WRLCK;
|
|
break;
|
|
}
|
|
|
|
// Ignore warning bc idc
|
|
// I assume c++ compilers under posix land allow for struct init the c way
|
|
struct flock lck =
|
|
{
|
|
.l_whence = SEEK_SET,
|
|
.l_start = 0,
|
|
.l_len = 0,
|
|
.l_type = lease
|
|
};
|
|
|
|
// Assume this is true:
|
|
// * If a process closes any file descriptor referring to a file,
|
|
// then all of the process's locks on that file are released,
|
|
// regardless of the file descriptor(s) on which the locks were
|
|
// obtained. This is bad: it means that a process can lose its
|
|
// locks on a file such as /etc/passwd or /etc/mtab when for some
|
|
// reason a library function decides to open, read, and close the
|
|
// same file.
|
|
// [...]
|
|
//
|
|
// Open file description locks solve both of these problems.
|
|
//
|
|
// OFD's description implies it inherits non-ofd behaviour
|
|
// I wanted to confirm a l_len zero would work to lock all contents,
|
|
// even on expansion of the file. The docs didn't mention anything;
|
|
// however, I don't really see any real difference len processing in
|
|
// the kernel. Furthermore, I saw the kernels implementation checking
|
|
// for MAX_OFFSET of int type (-1) before overloading l_len with zero.
|
|
//
|
|
// I assume this will work. Linux locking is trash.
|
|
return ::fcntl(fd, F_OFD_SETLK, &lck) == 0;
|
|
#endif
|
|
}
|
|
|
|
bool ApplyFileSectionLock(AuSPtr<IIOHandle> pHandle,
|
|
EFileAdvisoryLockLevel level,
|
|
AuUInt64 uOffset,
|
|
AuUInt64 uLength)
|
|
{
|
|
int lease {};
|
|
|
|
auto opt = pHandle->GetOSHandleSafe();
|
|
if (!opt)
|
|
{
|
|
SysPushErrorIOResourceRejected();
|
|
return false;
|
|
}
|
|
|
|
int fd = (int)opt.ValueOr((int)-1);
|
|
if (fd == -1)
|
|
{
|
|
SysPushErrorIOResourceRejected();
|
|
return false;
|
|
}
|
|
|
|
switch (level)
|
|
{
|
|
case EFileAdvisoryLockLevel::eEnumCount:
|
|
case EFileAdvisoryLockLevel::eNoSafety:
|
|
return true;
|
|
case EFileAdvisoryLockLevel::eBlockWrite:
|
|
lease = F_RDLCK;
|
|
break;
|
|
case EFileAdvisoryLockLevel::eBlockReadWrite:
|
|
lease = F_WRLCK;
|
|
break;
|
|
}
|
|
|
|
struct flock lck =
|
|
{
|
|
.l_whence = SEEK_SET,
|
|
.l_start = uLength,
|
|
.l_len = uOffset,
|
|
.l_type = lease
|
|
};
|
|
|
|
#if defined(AURORA_IS_LINUX_DERIVED)
|
|
return ::fcntl(fd, F_OFD_SETLK, &lck) == 0;
|
|
#else
|
|
return ::fcntl(fd, F_SETLK, &lck) == 0;
|
|
#endif
|
|
}
|
|
|
|
bool UnapplyFileSectionLock(AuSPtr<IIOHandle> pHandle,
|
|
AuUInt64 uOffset,
|
|
AuUInt64 uLength)
|
|
{
|
|
auto opt = pHandle->GetOSHandleSafe();
|
|
if (!opt)
|
|
{
|
|
SysPushErrorIOResourceRejected();
|
|
return false;
|
|
}
|
|
|
|
int fd = (int)opt.ValueOr((int)-1);
|
|
if (fd == -1)
|
|
{
|
|
SysPushErrorIOResourceRejected();
|
|
return false;
|
|
}
|
|
|
|
struct flock lck =
|
|
{
|
|
.l_whence = SEEK_SET,
|
|
.l_start = uLength,
|
|
.l_len = uOffset,
|
|
.l_type = F_UNLCK
|
|
};
|
|
|
|
#if defined(AURORA_IS_LINUX_DERIVED)
|
|
return ::fcntl(fd, F_OFD_SETLK, &lck) == 0;
|
|
#else
|
|
return ::fcntl(fd, F_SETLK, &lck) == 0;
|
|
#endif
|
|
}
|
|
} |