2#include "pedigree/kernel/process/FilesystemCredentials.h"
3#include "pedigree/kernel/process/TerminationDeferral.h"
4#include "pedigree/kernel/process/Thread.h"
5#include "pedigree/kernel/processor/Processor.h"
6#include "pedigree/kernel/processor/ProcessorInformation.h"
7#include "pedigree/kernel/syscallError.h"
11#include "DevFs-block.h"
12#include "file-handle-syscalls.h"
13#include "modules/system/vfs/Quota.h"
14#include "quota-syscalls.h"
17constexpr uint32_t Sync = 0x800001, Enable = 0x800002, Disable = 0x800003;
18constexpr uint32_t GetFormat = 0x800004, GetInfo = 0x800005, SetInfo = 0x800006;
19constexpr uint32_t GetQuota = 0x800007, SetQuota = 0x800008;
20static_assert(
sizeof(
QuotaRecord) == 72,
"Linux dqblk size");
21static_assert(__builtin_offsetof(
QuotaRecord, valid) == 64,
"Linux dqblk validity mask");
24 QuotaResult(
int result)
26 error(result < 0 ?
Processor::information().getCurrentThread()->getErrno() : 0) {}
30bool permitted(uint32_t command, QuotaType type, uint32_t
id) {
31 if (command == GetFormat || command == Sync)
33 if (posix_effective_root())
35 if (command == GetQuota) {
37 int64_t uid = process->getEffectiveUserId(), gid = process->getEffectiveGroupId();
41 gid = process->getGroupId();
42 if (type == QuotaType::User && uid >= 0 &&
static_cast<uint64_t
>(uid) ==
id)
45 if (type == QuotaType::Group && gid >= 0 &&
46 Process::currentFilesystemCredentials(credentials)) {
47 credentials.gid =
static_cast<uint32_t
>(gid);
48 if (credentials.inGroup(
id))
52 SYSCALL_ERROR(NotEnoughPermissions);
59 SYSCALL_ERROR(OutOfMemory);
63 for (
const auto&
identity : mounts) {
67 error = Error::DeviceDoesNotExist;
71 const auto status = pin.filesystem()->quotaControl(request, response);
72 if (status != QuotaStatus::Unsupported && status != QuotaStatus::NotEnabled &&
73 status != QuotaStatus::Success && !error)
74 error = quotaError(status);
77 return error ? -1 : 0;
80QuotaResult control(
int encoded,
const char* special,
int signedId,
void* address) {
82 const uint32_t type =
static_cast<uint32_t
>(encoded) & 0xff;
83 const uint32_t command =
static_cast<uint32_t
>(encoded) >> 8;
85 SYSCALL_ERROR(InvalidArgument);
89 request.type = type ? QuotaType::Group : QuotaType::User;
90 request.id =
static_cast<uint32_t
>(signedId);
93 request.operation = QuotaOperation::Sync;
96 request.operation = QuotaOperation::Enable;
97 request.format = request.id;
100 request.operation = QuotaOperation::Disable;
103 request.operation = QuotaOperation::GetFormat;
106 request.operation = QuotaOperation::Get;
109 request.operation = QuotaOperation::Set;
113 SYSCALL_ERROR(OperationNotSupported);
116 SYSCALL_ERROR(InvalidArgument);
119 if (!permitted(command, request.type, request.id))
121 if ((command == GetQuota || command == SetQuota) && request.id == 0xffffffffU) {
122 SYSCALL_ERROR(InvalidArgument);
125 if (command == SetQuota &&
127 SYSCALL_ERROR(BadAddress);
132 return syncAll(request);
133 SYSCALL_ERROR(DeviceDoesNotExist);
141 if (command == Enable && !quota.resolve(AT_FDCWD,
static_cast<const char*
>(address),
true,
false))
143 if (!device.resolve(AT_FDCWD, special,
true,
false))
145 if (!device.file->isBlockDevice()) {
146 SYSCALL_ERROR(NotABlockDevice);
149 const uint64_t number = device.file->deviceNumber();
151 if (!PosixBlock::valid(number, PosixBlock::MountedMajor) ||
154 SYSCALL_ERROR(DeviceDoesNotExist);
157 if (command == Enable && quota.file->getFilesystem() != filesystem.filesystem()) {
158 SYSCALL_ERROR(CrossDeviceLink);
162 const auto status = filesystem.filesystem()->quotaControl(request, response, quota.file);
163 if (status != QuotaStatus::Success) {
164 syscallError(quotaError(status));
167 if ((command == GetQuota &&
169 (command == GetFormat &&
171 SYSCALL_ERROR(BadAddress);
178int posix_quotactl(
int command,
const char* special,
int id,
void* address) {
179 const QuotaResult result = control(command, special,
id, address);
180 syscallError(result.error);
static bool copyFromUser(void *destination, const void *source, size_t count, size_t elementSize=1)
static bool copyToUser(void *destination, const void *source, size_t count, size_t elementSize=1)
virtual int64_t getUserId() const
static ProcessorInformation & information()
A vector / dynamic array.