2#include "file-handle-syscalls.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"
12#include "file-syscalls.h"
13#include "modules/system/vfs/MountView.h"
16struct UserHandleHeader {
20static_assert(
sizeof(UserHandleHeader) == 8,
"Linux file_handle header");
21static_assert(__builtin_offsetof(
FileHandle, bytes) == 8,
"FileHandle payload layout");
22constexpr size_t MaximumHandle =
sizeof(FileHandle::bytes);
32 int finish(
int value) {
33 error = value < 0 ? currentThread()->getErrno() : 0;
37 currentThread()->setErrno(error);
44bool importHeader(
const void* user, UserHandleHeader& header,
bool allowZero) {
46 SYSCALL_ERROR(BadAddress);
49 if (header.length > MaximumHandle || (!allowZero && !header.length)) {
50 SYSCALL_ERROR(InvalidArgument);
56bool validOpenFlags(
int flags) {
57 constexpr int accepted = O_RDONLY | O_WRONLY | O_RDWR | O_CLOEXEC | O_NONBLOCK | O_APPEND |
58 O_TRUNC | O_LARGEFILE | O_DIRECTORY;
59 constexpr int unsupported = O_CREAT | O_EXCL | O_NOCTTY | O_DSYNC | O_ASYNC | O_DIRECT | O_SYNC |
60 O_NOFOLLOW | O_NOATIME | O_PATH | (O_TMPFILE & ~O_DIRECTORY);
61 if ((flags & ~(accepted | unsupported)) || (flags & 3) == 3) {
62 SYSCALL_ERROR(InvalidArgument);
65 if (flags & unsupported) {
66 SYSCALL_ERROR(OperationNotSupported);
73int posix_handle_error(FileHandleStatus status) {
75 case FileHandleStatus::Success:
76 currentThread()->setErrno(0);
78 case FileHandleStatus::Unsupported:
79 SYSCALL_ERROR(OperationNotSupported);
81 case FileHandleStatus::Stale:
82 SYSCALL_ERROR(StaleFileHandle);
84 case FileHandleStatus::Invalid:
85 SYSCALL_ERROR(InvalidArgument);
87 case FileHandleStatus::NoMemory:
88 SYSCALL_ERROR(OutOfMemory);
90 case FileHandleStatus::IoError:
91 SYSCALL_ERROR(IoError);
97bool posix_effective_root() {
99 int64_t uid = process->getEffectiveUserId();
105bool PosixHandleTarget::resolve(
int dirfd,
const char* userPath,
bool follow,
bool allowEmpty,
106 bool nullAsDescriptor) {
113 auto* subsystem =
static_cast<PosixSubsystem*
>(process->getSubsystem());
115 SYSCALL_ERROR(InvalidArgument);
119 const bool nullTarget = !userPath && nullAsDescriptor;
122 if (status != PosixSubsystem::UserStringSuccess) {
123 syscallError(status == PosixSubsystem::UserStringTooLong ? Error::NameTooLong
124 : Error::BadAddress);
127 if (!path.length() && !allowEmpty) {
128 SYSCALL_ERROR(DoesNotExist);
132 const bool direct = nullTarget || !path.length();
133 const bool absolute = !direct && path[0] ==
'/';
136 if (dirfd == AT_FDCWD) {
138 auto context = process->acquireFilesystemContext();
140 if (!context || !context->snapshot(snapshot) || !snapshot.cwd) {
141 SYSCALL_ERROR(DoesNotExist);
144 start = snapshot.cwd;
145 file = start->node();
148 if (!subsystem->acquireFileDescriptor(dirfd, descriptor)) {
149 SYSCALL_ERROR(BadFileDescriptor);
152 file = descriptor->getFile();
153 start = descriptor->openingPath();
155 syscallError(direct ? Error::OperationNotSupported : Error::NotADirectory);
159 SYSCALL_ERROR(NotADirectory);
165 pathLease.retain(start);
168 normalisePath(normalised, path.cstr());
169 currentThread()->setErrno(0);
170 const bool directoryRequired = path[path.length() - 1] ==
'/';
171 file = findFilePath(normalised, pathLease, start, follow || directoryRequired);
173 if (!currentThread()->getErrno())
174 SYSCALL_ERROR(DoesNotExist);
178 SYSCALL_ERROR(NotADirectory);
182 if (!file->getFilesystem()) {
183 SYSCALL_ERROR(OperationNotSupported);
186 if (!
VFS::instance().acquireMount(file->getFilesystem(), mount)) {
188 SYSCALL_ERROR(OperationNotSupported);
192 attachmentId = view ? view->attachmentId(pathLease.path()) : 0;
196int posix_name_to_handle_at(
int dirfd,
const char* path,
void* userHandle,
int* userMount,
198 HandleResult completion;
200 if (flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) {
201 SYSCALL_ERROR(InvalidArgument);
202 return completion.finish(-1);
205 if (!target.resolve(dirfd, path, flags & AT_SYMLINK_FOLLOW, flags & AT_EMPTY_PATH))
206 return completion.finish(-1);
207 if (!target.attachmentId) {
208 SYSCALL_ERROR(OperationNotSupported);
209 return completion.finish(-1);
211 if (target.attachmentId > INT_MAX) {
212 SYSCALL_ERROR(ValueTooLarge);
213 return completion.finish(-1);
215 UserHandleHeader input;
216 if (!importHeader(userHandle, input,
true))
217 return completion.finish(-1);
219 const auto status = target.mount.filesystem()->
encodeFileHandle(*target.file, encoded);
220 if (status != FileHandleStatus::Success)
221 return completion.finish(posix_handle_error(status));
222 if (!encoded.length || encoded.length > MaximumHandle) {
223 SYSCALL_ERROR(IoError);
224 return completion.finish(-1);
226 const bool overflow = input.length < encoded.length;
229 const int mountId =
static_cast<int>(target.attachmentId);
232 sizeof(UserHandleHeader) + (overflow ? 0 : encoded.length))) {
233 SYSCALL_ERROR(BadAddress);
234 return completion.finish(-1);
237 SYSCALL_ERROR(ValueTooLarge);
238 return completion.finish(-1);
240 return completion.finish(0);
243int posix_open_by_handle_at(
int mountfd,
const void* userHandle,
int flags) {
244 HandleResult completion;
247 if (!target.resolve(mountfd,
nullptr,
false,
false,
true))
248 return completion.finish(-1);
249 if (!posix_effective_root()) {
250 SYSCALL_ERROR(NotEnoughPermissions);
251 return completion.finish(-1);
253 if (!target.attachmentId) {
254 SYSCALL_ERROR(OperationNotSupported);
255 return completion.finish(-1);
257 UserHandleHeader input;
258 if (!importHeader(userHandle, input,
false))
259 return completion.finish(-1);
261 handle.length = input.length;
262 handle.type = input.type;
263 const uintptr_t user =
reinterpret_cast<uintptr_t
>(userHandle);
264 if (user > ~uintptr_t(0) -
sizeof(input) ||
266 handle.bytes,
reinterpret_cast<const void*
>(user +
sizeof(input)), handle.length)) {
267 SYSCALL_ERROR(BadAddress);
268 return completion.finish(-1);
271 const auto status = target.mount.filesystem()->decodeFileHandle(handle, decoded);
272 if (status != FileHandleStatus::Success)
273 return completion.finish(posix_handle_error(status));
274 if (!validOpenFlags(flags))
275 return completion.finish(-1);
276 File* file = decoded.get();
278 SYSCALL_ERROR(OperationNotSupported);
279 return completion.finish(-1);
281 if (flags & O_DIRECTORY) {
282 SYSCALL_ERROR(NotADirectory);
283 return completion.finish(-1);
285 const int access = flags & 3;
286 const bool writes = access != O_RDONLY || (flags & O_TRUNC);
287 if (writes && target.mount.filesystem()->
isReadOnly()) {
288 SYSCALL_ERROR(ReadOnlyFilesystem);
289 return completion.finish(-1);
292 return completion.finish(-1);
295 if (!view || !view->pathForNode(target.pathLease.path(), file, openedPath)) {
296 if (!currentThread()->getErrno())
297 SYSCALL_ERROR(StaleFileHandle);
298 return completion.finish(-1);
300 const int statusFlags = flags & (3 | O_APPEND | O_NONBLOCK | O_LARGEFILE);
302 flags & O_CLOEXEC ? FD_CLOEXEC : 0, statusFlags);
303 if (!descriptor || !descriptor->acquireOpenFileDescription()) {
304 const int result = completion.finish(posix_handle_error(FileHandleStatus::NoMemory));
308 if ((flags & O_TRUNC) && !file->
resize(0)) {
309 if (!currentThread()->getErrno())
310 SYSCALL_ERROR(IoError);
311 const int result = completion.finish(-1);
315 auto* subsystem =
static_cast<PosixSubsystem*
>(currentThread()->getParent()->getSubsystem());
317 const size_t fd = subsystem->installFileDescriptor(descriptor, published);
319 return completion.finish(
static_cast<int>(fd));
bool supportsRegularFileOperations()
virtual bool isDirectory()
void publishEvent(FileEventMask mask, const StringView &name=StringView(), bool targetIsDirectory=false)
virtual FileHandleStatus encodeFileHandle(File &file, FileHandle &handle)
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)
virtual int64_t getUserId() const
static ProcessorInformation & information()
static bool checkAccess(File *pFile, bool bRead, bool bWrite, bool bExecute)