2#include "pedigree/kernel/process/Process.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"
8#include "pedigree/kernel/utilities/Pointers.h"
13#include "FileDescriptor.h"
14#include "PosixSubsystem.h"
15#include "ResolvedPath.h"
16#include "file-syscalls.h"
17#include "modules/system/vfs/ExtendedAttributes.h"
18#include "modules/system/vfs/MountView.h"
19#include "user-namespace.h"
20#include "xattr-syscalls.h"
23constexpr size_t MaximumName = Xattr::MaximumNameLength, MaximumValue = Xattr::MaximumValueLength;
24enum class TargetKind { Follow, NoFollow, Descriptor };
28 XattrResult(ssize_t result)
30 error(result < 0 ?
Processor::information().getCurrentThread()->getErrno() : 0) {}
35ssize_t finishResult(
const XattrResult& result) {
36 syscallError(result.error);
40bool copyString(
const char* user,
String& snapshot,
size_t limit, Error::PosixError tooLong) {
42 if (result == PosixSubsystem::UserStringSuccess)
44 syscallError(result == PosixSubsystem::UserStringBadAddress ? Error::BadAddress : tooLong);
48bool copyName(
const char* user,
String& snapshot) {
49 if (!copyString(user, snapshot, MaximumName + 1, Error::BadRange))
51 if (!snapshot.length()) {
52 SYSCALL_ERROR(BadRange);
63 bool resolve(TargetKind kind,
const char* userPath,
int fd) {
65 auto* subsystem =
static_cast<PosixSubsystem*
>(thread->getParent()->getSubsystem());
66 if (kind == TargetKind::Descriptor) {
67 if (!subsystem || !subsystem->acquireFileDescriptor(fd, descriptor) ||
69 SYSCALL_ERROR(BadFileDescriptor);
72 file = descriptor->getFile();
74 SYSCALL_ERROR(OperationNotSupported);
81 if (!copyString(userPath, path, PATH_MAX, Error::NameTooLong))
84 SYSCALL_ERROR(DoesNotExist);
88 normalisePath(normalised, path.cstr());
89 const bool requireDirectory = path[path.length() - 1] ==
'/';
92 kind == TargetKind::Follow || requireDirectory);
94 if (!thread->getErrno())
95 SYSCALL_ERROR(DoesNotExist);
99 SYSCALL_ERROR(NotADirectory);
106bool permitted(
File* file,
const String& name,
bool write) {
107 if (write && file->getFilesystem() && file->getFilesystem()->
isReadOnly()) {
108 SYSCALL_ERROR(ReadOnlyFilesystem);
114 SYSCALL_ERROR(OperationNotSupported);
118 syscallError(write ? Error::NotEnoughPermissions : Error::NoData);
122 const auto attributes = file->getAttributes();
124 if (!Process::currentFilesystemCredentials(credentials)) {
125 SYSCALL_ERROR(NotEnoughPermissions);
128 const uint32_t uid = credentials.uid;
129 if ((attributes.permissions & FILE_STICKY) &&
130 !posix_global_capable(PosixCapabilities::Fowner) &&
131 static_cast<uint64_t
>(uid) != attributes.uid) {
132 SYSCALL_ERROR(NotEnoughPermissions);
138 if (name.length() == 5) {
139 SYSCALL_ERROR(InvalidArgument);
145ssize_t finish(XattrStatus status,
size_t count = 0) {
147 case XattrStatus::Success:
149 return static_cast<ssize_t
>(count);
150 case XattrStatus::Missing:
151 SYSCALL_ERROR(NoData);
153 case XattrStatus::Exists:
154 SYSCALL_ERROR(FileExists);
156 case XattrStatus::Range:
157 SYSCALL_ERROR(BadRange);
159 case XattrStatus::Quota:
160 SYSCALL_ERROR(QuotaExceeded);
162 case XattrStatus::Overflow:
163 SYSCALL_ERROR(ValueTooLarge);
165 case XattrStatus::NoSpace:
166 SYSCALL_ERROR(NoSpaceLeftOnDevice);
168 case XattrStatus::NoMemory:
169 SYSCALL_ERROR(OutOfMemory);
171 case XattrStatus::Unsupported:
172 SYSCALL_ERROR(OperationNotSupported);
174 case XattrStatus::Denied:
175 SYSCALL_ERROR(PermissionDenied);
177 case XattrStatus::IoError:
178 SYSCALL_ERROR(IoError);
180 case XattrStatus::Invalid:
181 SYSCALL_ERROR(InvalidArgument);
183 case XattrStatus::ReadOnly:
184 SYSCALL_ERROR(ReadOnlyFilesystem);
190XattrResult readAttribute(TargetKind kind,
const char* path,
int fd,
const char* userName,
191 void* output,
size_t size,
bool list) {
194 if (!target.resolve(kind, path, fd))
197 if (!list && !copyName(userName, name))
199 const size_t capacity = size < MaximumValue ? size : MaximumValue;
201 if (capacity && !buffer) {
202 SYSCALL_ERROR(OutOfMemory);
206 if (!list && !permitted(target.file, name,
false))
210 list ? target.file->listExtendedAttributes(buffer.get(), capacity, required)
211 : target.file->getExtendedAttribute(name.view(), buffer.get(), capacity, required);
212 if ((status == XattrStatus::Range && capacity == MaximumValue) ||
213 (status == XattrStatus::Success && required > MaximumValue)) {
214 SYSCALL_ERROR(TooBig);
217 if (status != XattrStatus::Success)
218 return finish(status);
219 if (capacity && required) {
220 if (required > capacity) {
221 SYSCALL_ERROR(IoError);
225 SYSCALL_ERROR(BadAddress);
229 return finish(status, required);
232XattrResult changeAttribute(TargetKind kind,
const char* path,
int fd,
const char* userName,
233 const void* value,
size_t size,
int flags,
bool remove) {
236 if (kind == TargetKind::Descriptor && !target.resolve(kind, path, fd))
239 SYSCALL_ERROR(InvalidArgument);
243 if (!copyName(userName, name))
245 if (size > MaximumValue) {
246 SYSCALL_ERROR(TooBig);
252 SYSCALL_ERROR(OutOfMemory);
256 SYSCALL_ERROR(BadAddress);
260 if (kind != TargetKind::Descriptor && !target.resolve(kind, path, fd))
263 const auto retainedPath = target.pathLease.path() ? target.pathLease.path()
264 : target.descriptor ? target.descriptor->openingPath()
266 if (retainedPath && !mountWrite.acquire(retainedPath)) {
269 if (!permitted(target.file, name,
true))
271 return static_cast<int>(
272 finish(remove ? target.file->removeExtendedAttribute(name.view())
273 : target.file->setExtendedAttribute(name.view(), buffer.get(), size, flags)));
277int posix_setxattr(
const char* path,
const char* name,
const void* value,
size_t size,
int flags) {
279 changeAttribute(TargetKind::Follow, path, -1, name, value, size, flags,
false));
281int posix_lsetxattr(
const char* path,
const char* name,
const void* value,
size_t size,
int flags) {
283 changeAttribute(TargetKind::NoFollow, path, -1, name, value, size, flags,
false));
285int posix_fsetxattr(
int fd,
const char* name,
const void* value,
size_t size,
int flags) {
287 changeAttribute(TargetKind::Descriptor,
nullptr, fd, name, value, size, flags,
false));
289ssize_t posix_getxattr(
const char* path,
const char* name,
void* value,
size_t size) {
290 return finishResult(readAttribute(TargetKind::Follow, path, -1, name, value, size,
false));
292ssize_t posix_lgetxattr(
const char* path,
const char* name,
void* value,
size_t size) {
293 return finishResult(readAttribute(TargetKind::NoFollow, path, -1, name, value, size,
false));
295ssize_t posix_fgetxattr(
int fd,
const char* name,
void* value,
size_t size) {
296 return finishResult(readAttribute(TargetKind::Descriptor,
nullptr, fd, name, value, size,
false));
298ssize_t posix_listxattr(
const char* path,
char* list,
size_t size) {
299 return finishResult(readAttribute(TargetKind::Follow, path, -1,
nullptr, list, size,
true));
301ssize_t posix_llistxattr(
const char* path,
char* list,
size_t size) {
302 return finishResult(readAttribute(TargetKind::NoFollow, path, -1,
nullptr, list, size,
true));
304ssize_t posix_flistxattr(
int fd,
char* list,
size_t size) {
306 readAttribute(TargetKind::Descriptor,
nullptr, fd,
nullptr, list, size,
true));
308int posix_removexattr(
const char* path,
const char* name) {
309 return finishResult(changeAttribute(TargetKind::Follow, path, -1, name,
nullptr, 0, 0,
true));
311int posix_lremovexattr(
const char* path,
const char* name) {
312 return finishResult(changeAttribute(TargetKind::NoFollow, path, -1, name,
nullptr, 0, 0,
true));
314int posix_fremovexattr(
int fd,
const char* name) {
316 changeAttribute(TargetKind::Descriptor,
nullptr, fd, name,
nullptr, 0, 0,
true));
int getStatusFlags() const
Get current status flags.
bool supportsRegularFileOperations()
virtual bool isDirectory()
static bool copyFromUser(void *destination, const void *source, size_t count, size_t elementSize=1)
static UserStringResult copyUserString(const char *userString, String ©, size_t maxLength)
static bool copyToUser(void *destination, const void *source, size_t count, size_t elementSize=1)
static ProcessorInformation & information()
bool compare(const char *s, size_t length) const
static bool checkAccess(File *pFile, bool bRead, bool bWrite, bool bExecute)