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"
14#include "user-namespace.h"
17struct UserHandleHeader {
21static_assert(
sizeof(UserHandleHeader) == 8,
"Linux file_handle header");
22static_assert(__builtin_offsetof(
FileHandle, bytes) == 8,
"FileHandle payload layout");
23constexpr size_t MaximumHandle =
sizeof(FileHandle::bytes);
33 int finish(
int value) {
34 error = value < 0 ? currentThread()->getErrno() : 0;
38 currentThread()->setErrno(error);
45bool importHeader(
const void* user, UserHandleHeader& header,
bool allowZero) {
47 SYSCALL_ERROR(BadAddress);
50 if (header.length > MaximumHandle || (!allowZero && !header.length)) {
51 SYSCALL_ERROR(InvalidArgument);
57bool validOpenFlags(
int flags) {
58 constexpr int accepted = O_RDONLY | O_WRONLY | O_RDWR | O_CLOEXEC | O_NONBLOCK | O_APPEND |
59 O_TRUNC | O_LARGEFILE | O_DIRECTORY;
60 constexpr int unsupported = O_CREAT | O_EXCL | O_NOCTTY | O_DSYNC | O_ASYNC | O_DIRECT | O_SYNC |
61 O_NOFOLLOW | O_NOATIME | O_PATH | (O_TMPFILE & ~O_DIRECTORY);
62 if ((flags & ~(accepted | unsupported)) || (flags & 3) == 3) {
63 SYSCALL_ERROR(InvalidArgument);
66 if (flags & unsupported) {
67 SYSCALL_ERROR(OperationNotSupported);
74int posix_handle_error(FileHandleStatus status) {
76 case FileHandleStatus::Success:
77 currentThread()->setErrno(0);
79 case FileHandleStatus::Unsupported:
80 SYSCALL_ERROR(OperationNotSupported);
82 case FileHandleStatus::Stale:
83 SYSCALL_ERROR(StaleFileHandle);
85 case FileHandleStatus::Invalid:
86 SYSCALL_ERROR(InvalidArgument);
88 case FileHandleStatus::NoMemory:
89 SYSCALL_ERROR(OutOfMemory);
91 case FileHandleStatus::IoError:
92 SYSCALL_ERROR(IoError);
98bool posix_effective_root() {
99 return posix_global_capable(PosixCapabilities::SysAdmin);
102bool PosixHandleTarget::resolve(
int dirfd,
const char* userPath,
bool follow,
bool allowEmpty,
103 bool nullAsDescriptor) {
110 auto* subsystem =
static_cast<PosixSubsystem*
>(process->getSubsystem());
112 SYSCALL_ERROR(InvalidArgument);
116 const bool nullTarget = !userPath && nullAsDescriptor;
119 if (status != PosixSubsystem::UserStringSuccess) {
120 syscallError(status == PosixSubsystem::UserStringTooLong ? Error::NameTooLong
121 : Error::BadAddress);
124 if (!path.length() && !allowEmpty) {
125 SYSCALL_ERROR(DoesNotExist);
129 const bool direct = nullTarget || !path.length();
130 const bool absolute = !direct && path[0] ==
'/';
133 if (dirfd == AT_FDCWD) {
135 auto context = process->acquireFilesystemContext();
137 if (!context || !context->snapshot(snapshot) || !snapshot.cwd) {
138 SYSCALL_ERROR(DoesNotExist);
141 start = snapshot.cwd;
142 file = start->node();
145 if (!subsystem->acquireFileDescriptor(dirfd, descriptor)) {
146 SYSCALL_ERROR(BadFileDescriptor);
149 file = descriptor->getFile();
150 start = descriptor->openingPath();
152 syscallError(direct ? Error::OperationNotSupported : Error::NotADirectory);
156 SYSCALL_ERROR(NotADirectory);
162 pathLease.retain(start);
165 normalisePath(normalised, path.cstr());
166 currentThread()->setErrno(0);
167 const bool directoryRequired = path[path.length() - 1] ==
'/';
168 file = findFilePath(normalised, pathLease, start, follow || directoryRequired);
170 if (!currentThread()->getErrno())
171 SYSCALL_ERROR(DoesNotExist);
175 SYSCALL_ERROR(NotADirectory);
179 if (!file->getFilesystem()) {
180 SYSCALL_ERROR(OperationNotSupported);
183 if (!
VFS::instance().acquireMount(file->getFilesystem(), mount)) {
185 SYSCALL_ERROR(OperationNotSupported);
189 attachmentId = view ? view->attachmentId(pathLease.path()) : 0;
193int posix_name_to_handle_at(
int dirfd,
const char* path,
void* userHandle,
int* userMount,
195 HandleResult completion;
197 if (flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) {
198 SYSCALL_ERROR(InvalidArgument);
199 return completion.finish(-1);
202 if (!target.resolve(dirfd, path, flags & AT_SYMLINK_FOLLOW, flags & AT_EMPTY_PATH))
203 return completion.finish(-1);
204 if (!target.attachmentId) {
205 SYSCALL_ERROR(OperationNotSupported);
206 return completion.finish(-1);
208 if (target.attachmentId > INT_MAX) {
209 SYSCALL_ERROR(ValueTooLarge);
210 return completion.finish(-1);
212 UserHandleHeader input;
213 if (!importHeader(userHandle, input,
true))
214 return completion.finish(-1);
216 const auto status = target.mount.filesystem()->
encodeFileHandle(*target.file, encoded);
217 if (status != FileHandleStatus::Success)
218 return completion.finish(posix_handle_error(status));
219 if (!encoded.length || encoded.length > MaximumHandle) {
220 SYSCALL_ERROR(IoError);
221 return completion.finish(-1);
223 const bool overflow = input.length < encoded.length;
226 const int mountId =
static_cast<int>(target.attachmentId);
229 sizeof(UserHandleHeader) + (overflow ? 0 : encoded.length))) {
230 SYSCALL_ERROR(BadAddress);
231 return completion.finish(-1);
234 SYSCALL_ERROR(ValueTooLarge);
235 return completion.finish(-1);
237 return completion.finish(0);
240int posix_open_by_handle_at(
int mountfd,
const void* userHandle,
int flags) {
241 HandleResult completion;
244 if (!target.resolve(mountfd,
nullptr,
false,
false,
true))
245 return completion.finish(-1);
246 if (!posix_effective_root()) {
247 SYSCALL_ERROR(NotEnoughPermissions);
248 return completion.finish(-1);
250 if (!target.attachmentId) {
251 SYSCALL_ERROR(OperationNotSupported);
252 return completion.finish(-1);
254 UserHandleHeader input;
255 if (!importHeader(userHandle, input,
false))
256 return completion.finish(-1);
258 handle.length = input.length;
259 handle.type = input.type;
260 const uintptr_t user =
reinterpret_cast<uintptr_t
>(userHandle);
261 if (user > ~uintptr_t(0) -
sizeof(input) ||
263 handle.bytes,
reinterpret_cast<const void*
>(user +
sizeof(input)), handle.length)) {
264 SYSCALL_ERROR(BadAddress);
265 return completion.finish(-1);
268 const auto status = target.mount.filesystem()->decodeFileHandle(handle, decoded);
269 if (status != FileHandleStatus::Success)
270 return completion.finish(posix_handle_error(status));
271 if (!validOpenFlags(flags))
272 return completion.finish(-1);
273 File* file = decoded.get();
275 SYSCALL_ERROR(OperationNotSupported);
276 return completion.finish(-1);
278 if (flags & O_DIRECTORY) {
279 SYSCALL_ERROR(NotADirectory);
280 return completion.finish(-1);
282 const int access = flags & 3;
283 const bool writes = access != O_RDONLY || (flags & O_TRUNC);
284 if (writes && target.mount.filesystem()->
isReadOnly()) {
285 SYSCALL_ERROR(ReadOnlyFilesystem);
286 return completion.finish(-1);
289 return completion.finish(-1);
292 if (!view || !view->pathForNode(target.pathLease.path(), file, openedPath)) {
293 if (!currentThread()->getErrno())
294 SYSCALL_ERROR(StaleFileHandle);
295 return completion.finish(-1);
298 if (writes && !VfsMountView::retainWrite(openedPath, mountWrite)) {
299 return completion.finish(-1);
301 const int statusFlags = flags & (3 | O_APPEND | O_NONBLOCK | O_LARGEFILE);
303 flags & O_CLOEXEC ? FD_CLOEXEC : 0, statusFlags);
304 if (!descriptor || !descriptor->acquireOpenFileDescription()) {
305 const int result = completion.finish(posix_handle_error(FileHandleStatus::NoMemory));
309 if (access != O_RDONLY) {
310 descriptor->acquireOpenFileDescription()->mountWrite = mountWrite;
312 if ((flags & O_TRUNC) && !file->
resize(0)) {
313 if (!currentThread()->getErrno())
314 SYSCALL_ERROR(IoError);
315 const int result = completion.finish(-1);
319 auto* subsystem =
static_cast<PosixSubsystem*
>(currentThread()->getParent()->getSubsystem());
321 const size_t fd = subsystem->installFileDescriptor(descriptor, published);
323 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)
static ProcessorInformation & information()
static bool checkAccess(File *pFile, bool bRead, bool bWrite, bool bExecute)