diff --git a/options/internal/include/mlibc/sysdeps.hpp b/options/internal/include/mlibc/sysdeps.hpp index 868240aa..e438b871 100644 --- a/options/internal/include/mlibc/sysdeps.hpp +++ b/options/internal/include/mlibc/sysdeps.hpp @@ -22,6 +22,7 @@ int sys_dup2(int fd, int newfd); int sys_stat(const char *pathname, struct stat *statbuf); int sys_fstat(int fd, struct stat *statbuf); +int sys_readlink(const char *path, void *buffer, size_t max_size, ssize_t *length); int sys_anon_allocate(size_t size, void **pointer); int sys_anon_free(void *pointer, size_t size); diff --git a/options/posix/generic/unistd-stubs.cpp b/options/posix/generic/unistd-stubs.cpp index 7a81e57e..fda76fcc 100644 --- a/options/posix/generic/unistd-stubs.cpp +++ b/options/posix/generic/unistd-stubs.cpp @@ -1,7 +1,6 @@ -#include - #include +#include #include @@ -176,9 +175,11 @@ ssize_t pwrite(int, const void *, size_t, off_t) { __ensure(!"Not implemented"); __builtin_unreachable(); } -ssize_t readlink(const char *__restrict, char *__restrict, size_t) { - __ensure(!"Not implemented"); - __builtin_unreachable(); +ssize_t readlink(const char *__restrict path, char *__restrict buffer, size_t max_size) { + ssize_t length; + if(mlibc::sys_readlink(path, buffer, max_size, &length)) + return -1; + return length; } ssize_t readlinkat(int, const char *__restrict, char *__restrict, size_t) { __ensure(!"Not implemented"); diff --git a/sysdeps/managarm/generic/file.cpp b/sysdeps/managarm/generic/file.cpp index 32f6f8a2..2b7fe69e 100644 --- a/sysdeps/managarm/generic/file.cpp +++ b/sysdeps/managarm/generic/file.cpp @@ -1686,5 +1686,53 @@ int sys_fstat(int fd, struct stat *result) { return 0; } +int sys_readlink(const char *path, void *data, size_t max_size, ssize_t *length) { + HelAction actions[4]; + globalQueue.trim(); + + managarm::posix::CntRequest req(getAllocator()); + req.set_request_type(managarm::posix::CntReqType::READLINK); + req.set_path(frigg::String(getAllocator(), path)); + + frigg::String ser(getAllocator()); + req.SerializeToString(&ser); + actions[0].type = kHelActionOffer; + actions[0].flags = kHelItemAncillary; + actions[1].type = kHelActionSendFromBuffer; + actions[1].flags = kHelItemChain; + actions[1].buffer = ser.data(); + actions[1].length = ser.size(); + actions[2].type = kHelActionRecvInline; + actions[2].flags = kHelItemChain; + actions[3].type = kHelActionRecvToBuffer; + actions[3].flags = 0; + actions[3].buffer = data; + actions[3].length = max_size; + HEL_CHECK(helSubmitAsync(kHelThisThread, actions, 4, + globalQueue.getQueue(), 0, 0)); + + auto element = globalQueue.dequeueSingle(); + auto offer = parseSimple(element); + auto send_req = parseSimple(element); + auto recv_resp = parseInline(element); + auto recv_data = parseLength(element); + + HEL_CHECK(offer->error); + HEL_CHECK(send_req->error); + HEL_CHECK(recv_resp->error); + HEL_CHECK(recv_data->error); + + managarm::posix::SvrResponse resp(getAllocator()); + resp.ParseFromArray(recv_resp->data, recv_resp->length); + if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { + errno = EINVAL; + return -1; + }else{ + __ensure(resp.error() == managarm::posix::Errors::SUCCESS); + *length = recv_data->length; + return 0; + } +} + } //namespace mlibc