isolate POSIX builds from the host UCRT, wire lwext4 and ntfs-3g as ext4.sys and ntfs.sys, split the FAT driver into directory/file/async/driver/mount units, add posixsrv and dwm plus input/console/desktop syscall clients and a pile of new smoke targets, rename serial.sys to cereal.sys, name HDA/USB/lwIP/AHCI workers, harden ATA probing/reset/removal around actual hardware deadlines, absent-channel detection, diagnostics and explicit worker lifetime, redo ACPI S5 shutdown around GAS/MMIO and HW-reduced firmware, scan SSDTs for _S5 and deal with Intel SMI sleep trapping, make serial and SMP timeouts use real monotonic deadlines, add thread names and fix terminal thread teardown, scheduler and APC prepare/commit races, make advisory file locks queryable and preserve split ranges and add mutable file append state, add shared-memory pipes with kernel-assisted wait/wake, introduce capability-scoped input and display managers, split surface map rights into read/write, add explicit unmap and replace present with commit/generation/damage tracking while keeping physical presentation under the display manager, decouple native exception classes from Win32 exception numbers and translate them in kernel32, add opaque process startup data, bump the resource protocol to v3 with namespace directories, symlinks and enumeration and service control to v2 with generic READY handle exports, add the new POSIX errno/status surface and rebuild fds around posixsrv-owned shared open descriptions, descriptor-local flags, exact inheritance snapshots, dup/fcntl/record locks and shared-ring pipes, add waitpid, POSIX credentials/groups/sessions/passwd/group lookups and move sockets onto stable open descriptions, port the shells and apps to the new console/input services and surface commit API, teach init to load services.ini and start/supervise RSSRV, DWM and generic services under restricted capabilities while publishing their endpoints through RSSRV, split RSSRV into namespace, volume, display, session, input, console and resource components and make /SystemRoot a real symlink to the independently published system volume, shift the syscall table again, expand lock/resource/surface/POSIX/service/thread smoke coverage, make docs scream ASK QUESTIONS and DISCUSS at LLMs, replace MIT No Attribution with WTFPL+.
This commit is contained in:
1 parent
3dacbd32c8
commit
73abd6f90d
441 files changed
+187073
-6549
No files matched your search
@@ -1,299 +0,0 @@
|
||||
// POSIX compatibility support for posix.
|
||||
|
||||
#pragma once
|
||||
// posix.h - POSIX type and constant definitions for posix.dll
|
||||
// Covers just what open/read/write/close/lseek/spawn/pthread/chdir need.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// errno.
|
||||
#ifdef errno
|
||||
#undef errno
|
||||
#endif
|
||||
#ifdef EAGAIN
|
||||
#undef EAGAIN
|
||||
#endif
|
||||
#ifdef ENOSYS
|
||||
#undef ENOSYS
|
||||
#endif
|
||||
#ifdef EWOULDBLOCK
|
||||
#undef EWOULDBLOCK
|
||||
#endif
|
||||
#ifdef EINPROGRESS
|
||||
#undef EINPROGRESS
|
||||
#endif
|
||||
#ifdef ETIMEDOUT
|
||||
#undef ETIMEDOUT
|
||||
#endif
|
||||
#ifdef ECONNRESET
|
||||
#undef ECONNRESET
|
||||
#endif
|
||||
#ifdef ENOTSOCK
|
||||
#undef ENOTSOCK
|
||||
#endif
|
||||
extern int errno; // defined in posix_fd.c; single global in v1
|
||||
|
||||
#define EPERM 1
|
||||
#define ENOENT 2
|
||||
#define ESRCH 3
|
||||
#define EINTR 4
|
||||
#define EIO 5
|
||||
#define EBADF 9
|
||||
#define ENOMEM 12
|
||||
#define EACCES 13
|
||||
#define EEXIST 17
|
||||
#define ENODEV 19
|
||||
#define ENOTDIR 20
|
||||
#define EINVAL 22
|
||||
#define ESPIPE 29
|
||||
#define EMFILE 24
|
||||
#define ENOSPC 28
|
||||
#define ERANGE 34
|
||||
#define EAGAIN 35
|
||||
#define EWOULDBLOCK EAGAIN
|
||||
#define ENOSYS 38
|
||||
#define ENOTSOCK 88
|
||||
#define EINPROGRESS 115
|
||||
#define ETIMEDOUT 116
|
||||
#define ECONNRESET 104
|
||||
|
||||
// open() flags.
|
||||
#define O_RDONLY 0x0000
|
||||
#define O_WRONLY 0x0001
|
||||
#define O_RDWR 0x0002
|
||||
#define O_CREAT 0x0040
|
||||
#define O_TRUNC 0x0200
|
||||
#define O_APPEND 0x0400
|
||||
|
||||
// lseek() whence.
|
||||
#define SEEK_SET 0
|
||||
#define SEEK_CUR 1
|
||||
#define SEEK_END 2
|
||||
|
||||
// mmap() protection and mapping flags.
|
||||
#define PROT_NONE 0x0
|
||||
#define PROT_READ 0x1
|
||||
#define PROT_WRITE 0x2
|
||||
#define PROT_EXEC 0x4
|
||||
#define MAP_SHARED 0x01
|
||||
#define MAP_PRIVATE 0x02
|
||||
#define MAP_FAILED ((void*)(intptr_t)-1)
|
||||
#define MS_SYNC 0x04
|
||||
#define MS_ASYNC 0x01
|
||||
#define MS_INVALIDATE 0x02
|
||||
|
||||
// Dynamic loader flags.
|
||||
#define RTLD_LAZY 0x0001
|
||||
#define RTLD_NOW 0x0002
|
||||
#define RTLD_LOCAL 0x0004
|
||||
#define RTLD_GLOBAL 0x0008
|
||||
|
||||
// Scalar types.
|
||||
typedef int32_t pid_t;
|
||||
typedef int32_t off_t;
|
||||
typedef uint32_t mode_t;
|
||||
typedef int64_t ssize_t;
|
||||
#define S_IFMT 0170000
|
||||
#define S_IFSOCK 0140000
|
||||
#define S_IFCHR 0020000
|
||||
#define S_IFDIR 0040000
|
||||
#define S_IFREG 0100000
|
||||
#define S_IRUSR 0000400
|
||||
#define S_IWUSR 0000200
|
||||
#define S_IXUSR 0000100
|
||||
#define S_IRGRP 0000040
|
||||
#define S_IWGRP 0000020
|
||||
#define S_IXGRP 0000010
|
||||
#define S_IROTH 0000004
|
||||
#define S_IWOTH 0000002
|
||||
#define S_IXOTH 0000001
|
||||
|
||||
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
|
||||
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
|
||||
#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
|
||||
#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
|
||||
|
||||
struct stat {
|
||||
uint64_t st_dev;
|
||||
uint64_t st_ino;
|
||||
mode_t st_mode;
|
||||
uint32_t st_nlink;
|
||||
uint32_t st_uid;
|
||||
uint32_t st_gid;
|
||||
uint64_t st_rdev;
|
||||
off_t st_size;
|
||||
int64_t st_atime;
|
||||
int64_t st_mtime;
|
||||
int64_t st_ctime;
|
||||
};
|
||||
|
||||
__declspec(dllexport) int stat(const char* path, struct stat* out);
|
||||
__declspec(dllexport) int fstat(int fd, struct stat* out);
|
||||
__declspec(dllexport) char* realpath(const char* path, char* resolved_path);
|
||||
|
||||
__declspec(dllexport) void* mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset);
|
||||
__declspec(dllexport) int munmap(void* addr, size_t length);
|
||||
__declspec(dllexport) int msync(void* addr, size_t length, int flags);
|
||||
|
||||
__declspec(dllexport) void* dlopen(const char* filename, int flags);
|
||||
__declspec(dllexport) void* dlsym(void* handle, const char* symbol);
|
||||
__declspec(dllexport) int dlclose(void* handle);
|
||||
__declspec(dllexport) char* dlerror(void);
|
||||
|
||||
// Sockets.
|
||||
typedef uint16_t sa_family_t;
|
||||
typedef uint16_t in_port_t;
|
||||
typedef uint32_t in_addr_t;
|
||||
typedef uint32_t socklen_t;
|
||||
|
||||
#define AF_INET 2
|
||||
#define AF_INET6 10
|
||||
#define AF_UNSPEC 0
|
||||
#define PF_INET AF_INET
|
||||
#define PF_INET6 AF_INET6
|
||||
#define SOCK_STREAM 1
|
||||
#define SOCK_DGRAM 2
|
||||
#define SOCK_RAW 3
|
||||
#define IPPROTO_ICMP 1
|
||||
#define IPPROTO_TCP 6
|
||||
#define IPPROTO_UDP 17
|
||||
#define IPPROTO_ICMPV6 58
|
||||
|
||||
#define SHUT_RD 0
|
||||
#define SHUT_WR 1
|
||||
#define SHUT_RDWR 2
|
||||
|
||||
#define SOL_SOCKET 1
|
||||
#define SO_RCVTIMEO 1
|
||||
#define SO_SNDTIMEO 2
|
||||
#define SO_NONBLOCK 3
|
||||
|
||||
#define INADDR_ANY ((in_addr_t)0x00000000u)
|
||||
#define INADDR_NONE ((in_addr_t)0xFFFFFFFFu)
|
||||
|
||||
struct in_addr {
|
||||
in_addr_t s_addr;
|
||||
};
|
||||
|
||||
struct in6_addr {
|
||||
uint8_t s6_addr[16];
|
||||
};
|
||||
|
||||
struct sockaddr {
|
||||
sa_family_t sa_family;
|
||||
char sa_data[14];
|
||||
};
|
||||
|
||||
struct sockaddr_in {
|
||||
sa_family_t sin_family;
|
||||
in_port_t sin_port;
|
||||
struct in_addr sin_addr;
|
||||
char sin_zero[8];
|
||||
};
|
||||
|
||||
struct sockaddr_in6 {
|
||||
sa_family_t sin6_family;
|
||||
in_port_t sin6_port;
|
||||
uint32_t sin6_flowinfo;
|
||||
struct in6_addr sin6_addr;
|
||||
uint32_t sin6_scope_id;
|
||||
};
|
||||
|
||||
struct hostent {
|
||||
char* h_name;
|
||||
char** h_aliases;
|
||||
int h_addrtype;
|
||||
int h_length;
|
||||
char** h_addr_list;
|
||||
};
|
||||
#define h_addr h_addr_list[0]
|
||||
|
||||
struct addrinfo {
|
||||
int ai_flags;
|
||||
int ai_family;
|
||||
int ai_socktype;
|
||||
int ai_protocol;
|
||||
socklen_t ai_addrlen;
|
||||
struct sockaddr* ai_addr;
|
||||
char* ai_canonname;
|
||||
struct addrinfo* ai_next;
|
||||
};
|
||||
|
||||
#define AI_PASSIVE 0x0001
|
||||
|
||||
struct pollfd {
|
||||
int fd;
|
||||
short events;
|
||||
short revents;
|
||||
};
|
||||
|
||||
#define POLLIN 0x0001
|
||||
#define POLLOUT 0x0002
|
||||
#define POLLERR 0x0004
|
||||
#define POLLHUP 0x0008
|
||||
#define POLLNVAL 0x0010
|
||||
|
||||
typedef unsigned long nfds_t;
|
||||
|
||||
typedef struct timeval {
|
||||
long tv_sec;
|
||||
long tv_usec;
|
||||
} timeval;
|
||||
|
||||
__declspec(dllexport) uint16_t htons(uint16_t x);
|
||||
__declspec(dllexport) uint16_t ntohs(uint16_t x);
|
||||
__declspec(dllexport) uint32_t htonl(uint32_t x);
|
||||
__declspec(dllexport) uint32_t ntohl(uint32_t x);
|
||||
__declspec(dllexport) in_addr_t inet_addr(const char* text);
|
||||
__declspec(dllexport) char* inet_ntoa(struct in_addr in);
|
||||
__declspec(dllexport) int inet_pton(int af, const char* src, void* dst);
|
||||
__declspec(dllexport) const char* inet_ntop(int af, const void* src, char* dst, socklen_t size);
|
||||
|
||||
__declspec(dllexport) int socket(int domain, int type, int protocol);
|
||||
__declspec(dllexport) int bind(int fd, const struct sockaddr* addr, socklen_t addrlen);
|
||||
__declspec(dllexport) int listen(int fd, int backlog);
|
||||
__declspec(dllexport) int accept(int fd, struct sockaddr* addr, socklen_t* addrlen);
|
||||
__declspec(dllexport) int connect(int fd, const struct sockaddr* addr, socklen_t addrlen);
|
||||
__declspec(dllexport) ssize_t send(int fd, const void* buf, size_t len, int flags);
|
||||
__declspec(dllexport) ssize_t recv(int fd, void* buf, size_t len, int flags);
|
||||
__declspec(dllexport) ssize_t sendto(int fd, const void* buf, size_t len, int flags, const struct sockaddr* dest, socklen_t destlen);
|
||||
__declspec(dllexport) ssize_t recvfrom(int fd, void* buf, size_t len, int flags, struct sockaddr* src, socklen_t* srclen);
|
||||
__declspec(dllexport) int shutdown(int fd, int how);
|
||||
__declspec(dllexport) int setsockopt(int fd, int level, int optname, const void* optval, socklen_t optlen);
|
||||
__declspec(dllexport) int getsockopt(int fd, int level, int optname, void* optval, socklen_t* optlen);
|
||||
__declspec(dllexport) int poll(struct pollfd* fds, nfds_t nfds, int timeout);
|
||||
__declspec(dllexport) struct hostent* gethostbyname(const char* name);
|
||||
__declspec(dllexport) int getaddrinfo(const char* node, const char* service, const struct addrinfo* hints, struct addrinfo** res);
|
||||
__declspec(dllexport) void freeaddrinfo(struct addrinfo* res);
|
||||
|
||||
// pthread types.
|
||||
typedef struct { uint32_t Handle; uint32_t Tid; } pthread_t;
|
||||
typedef struct { uint32_t Handle; } pthread_mutex_t;
|
||||
typedef void* pthread_attr_t; // unused in v1
|
||||
typedef void* pthread_mutexattr_t;
|
||||
|
||||
// posix_spawn types (file_actions and attrp both ignored in v1).
|
||||
typedef void* posix_spawn_file_actions_t;
|
||||
typedef void* posix_spawnattr_t;
|
||||
|
||||
__declspec(dllexport) const char* posix_get_command_line(void);
|
||||
|
||||
// dirent (used by posix_dir.c).
|
||||
#define NAME_MAX 259
|
||||
|
||||
typedef struct dirent {
|
||||
char d_name[NAME_MAX + 1];
|
||||
unsigned char d_type; // DT_REG or DT_DIR
|
||||
} dirent;
|
||||
|
||||
#define DT_UNKNOWN 0
|
||||
#define DT_REG 8
|
||||
#define DT_DIR 4
|
||||
|
||||
typedef struct DIR {
|
||||
uint32_t KHandle; // kernel DIR_OBJECT handle
|
||||
dirent Current;
|
||||
bool Valid;
|
||||
} DIR;
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <ntlite/syscall.h>
|
||||
#include <ntlite/path.h>
|
||||
#include <stdlib.h>
|
||||
#include "posix.h"
|
||||
#include "posix_internal.h"
|
||||
#include "posix_fd.h"
|
||||
#include "posix_path.h"
|
||||
|
||||
@@ -12,31 +12,74 @@ typedef SYS_DIR_ENTRY KDIR_ENTRY;
|
||||
|
||||
#define KATTR_DIR 0x10
|
||||
|
||||
// Implements the chdir operation.
|
||||
// Publishes the process-local native CWD into the authoritative posixsrv process record.
|
||||
static KSTATUS PosixPublishCurrentDirectory(const char* nativeDirectory) {
|
||||
if (!nativeDirectory) return NTLSTATUS_INVALID_PARAMETER;
|
||||
size_t length = strlen(nativeDirectory);
|
||||
if (length == 0 || length > SYS_PATH_MAX) return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
NTL_POSIX_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Version = NTL_POSIX_PROTOCOL_VERSION;
|
||||
request.Operation = NTL_POSIX_OP_SET_CURRENT_DIRECTORY;
|
||||
request.Flags = NTL_POSIX_REQUEST_FLAG_NONE;
|
||||
request.PathLength = (uint32_t)length;
|
||||
memcpy(request.Path, nativeDirectory, length + 1u);
|
||||
|
||||
NTL_POSIX_REPLY reply;
|
||||
KSTATUS status = PosixRuntimeCallServer(&request, &reply);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
return reply.Status;
|
||||
}
|
||||
|
||||
// Implements chdir while keeping the local path resolver and posixsrv authority synchronized.
|
||||
__declspec(dllexport) int chdir(const char* path) {
|
||||
char native[512];
|
||||
PosixTranslatePath(path, native, sizeof(native));
|
||||
uint32_t s = NtlSetCurrentDirectory(SysSvFromCstr(native));
|
||||
if (s != 0) { errno = ENOENT; return -1; }
|
||||
if (!path) { errno = EINVAL; return -1; }
|
||||
|
||||
char oldNative[SYS_PATH_MAX + 1u];
|
||||
size_t oldRequired = 0;
|
||||
KSTATUS status = NtlGetCurrentDirectory(oldNative, sizeof(oldNative), &oldRequired);
|
||||
if (!KSUCCESS(status)) { errno = PosixStatusToErrno(status); return -1; }
|
||||
|
||||
char native[SYS_PATH_MAX + 1u];
|
||||
const char* translated = PosixTranslatePath(path, native, sizeof(native));
|
||||
if (translated != native || native[0] == '\0') { errno = EINVAL; return -1; }
|
||||
|
||||
status = NtlSetCurrentDirectory(SysSvFromCstr(native));
|
||||
if (!KSUCCESS(status)) { errno = PosixStatusToErrno(status); return -1; }
|
||||
|
||||
char canonical[SYS_PATH_MAX + 1u];
|
||||
size_t required = 0;
|
||||
status = NtlGetCurrentDirectory(canonical, sizeof(canonical), &required);
|
||||
if (KSUCCESS(status)) status = PosixPublishCurrentDirectory(canonical);
|
||||
if (!KSUCCESS(status)) {
|
||||
(void)NtlSetCurrentDirectory(SysSvFromCstr(oldNative));
|
||||
errno = PosixStatusToErrno(status);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Implements the getcwd operation.
|
||||
// Implements getcwd from the server-owned POSIX process attribute.
|
||||
__declspec(dllexport) char* getcwd(char* buf, size_t size) {
|
||||
if (!buf || size == 0) { errno = EINVAL; return (char*)0; }
|
||||
|
||||
char native[SYS_PATH_MAX + 1u];
|
||||
size_t required = 0;
|
||||
uint32_t status = NtlGetCurrentDirectory(native, sizeof(native), &required);
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
errno = ERANGE;
|
||||
NTL_POSIX_REPLY reply;
|
||||
KSTATUS status = PosixRuntimeGetProcessAttributes(&reply);
|
||||
if (!KSUCCESS(status)) {
|
||||
errno = PosixStatusToErrno(status);
|
||||
return (char*)0;
|
||||
}
|
||||
if (reply.CurrentDirectoryLength == 0 || reply.CurrentDirectoryLength > SYS_PATH_MAX ||
|
||||
reply.CurrentDirectory[reply.CurrentDirectoryLength] != '\0') {
|
||||
errno = EIO;
|
||||
return (char*)0;
|
||||
}
|
||||
|
||||
char posix[SYS_PATH_MAX + 1];
|
||||
NativeToPosix(native, posix, sizeof(posix));
|
||||
|
||||
size_t needed = strlen(posix) + 1;
|
||||
char posix[SYS_PATH_MAX + 1u];
|
||||
NativeToPosix(reply.CurrentDirectory, posix, sizeof(posix));
|
||||
size_t needed = strlen(posix) + 1u;
|
||||
if (needed > size) {
|
||||
errno = ERANGE;
|
||||
return (char*)0;
|
||||
@@ -180,26 +223,37 @@ __declspec(dllexport) int stat(const char* path, struct stat* out) {
|
||||
__declspec(dllexport) int fstat(int fd, struct stat* out) {
|
||||
if (!out) { errno = EINVAL; return -1; }
|
||||
|
||||
uint32_t pid = SysGetCurrentPid();
|
||||
FD_ENTRY* e = FdGet(pid, fd);
|
||||
if (!e) return -1;
|
||||
POSIX_OPEN_DESCRIPTION* description = PosixFdAcquire(fd);
|
||||
if (!description) return -1;
|
||||
|
||||
switch (e->Type) {
|
||||
case FD_CONSOLE_R:
|
||||
case FD_CONSOLE_W:
|
||||
case FD_DEVNULL:
|
||||
case FD_DEVZERO:
|
||||
return PosixFillSyntheticStat(S_IFCHR, out);
|
||||
case FD_SOCKET:
|
||||
return PosixFillSyntheticStat(S_IFSOCK, out);
|
||||
case FD_FILE: {
|
||||
int result = -1;
|
||||
switch (description->Type) {
|
||||
case PosixFdConsoleRead:
|
||||
case PosixFdConsoleWrite:
|
||||
case PosixFdDevNull:
|
||||
case PosixFdDevZero:
|
||||
result = PosixFillSyntheticStat(S_IFCHR, out);
|
||||
break;
|
||||
case PosixFdSocket:
|
||||
result = PosixFillSyntheticStat(S_IFSOCK, out);
|
||||
break;
|
||||
case PosixFdPipeRead:
|
||||
case PosixFdPipeWrite:
|
||||
result = PosixFillSyntheticStat(S_IFIFO, out);
|
||||
break;
|
||||
case PosixFdFile: {
|
||||
SYS_FILE_STAT nativeStat;
|
||||
uint32_t s = SysGetFileStat(e->KHandle, &nativeStat);
|
||||
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
|
||||
return PosixFillStat(&nativeStat, out);
|
||||
uint32_t status = SysGetFileStat(description->KHandle, &nativeStat);
|
||||
if (status != NTLSTATUS_SUCCESS)
|
||||
errno = PosixStatusToErrno(status);
|
||||
else
|
||||
result = PosixFillStat(&nativeStat, out);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
PosixFdRelease(description);
|
||||
return result;
|
||||
}
|
||||
@@ -5,25 +5,18 @@
|
||||
#include <ntlite/syscall.h>
|
||||
#include <ntlite/module_loader.h>
|
||||
#include <ntlite/resource.h>
|
||||
#include "posix.h"
|
||||
#include "posix_internal.h"
|
||||
#include "posix_path.h"
|
||||
#include "posix_fd.h"
|
||||
|
||||
static char gDlError[160];
|
||||
static int gDlErrorPending;
|
||||
|
||||
// Clears the process-local dynamic-loader error string.
|
||||
// Clears the current thread's dynamic-loader error string.
|
||||
static void DlClearError(void) {
|
||||
gDlError[0] = '\0';
|
||||
gDlErrorPending = 0;
|
||||
PosixRuntimeClearDlError();
|
||||
}
|
||||
|
||||
// Stores one process-local dynamic-loader error string.
|
||||
// Stores one current-thread dynamic-loader error string.
|
||||
static void DlSetError(const char* message) {
|
||||
if (!message) message = "dynamic loader error";
|
||||
strncpy(gDlError, message, sizeof(gDlError) - 1);
|
||||
gDlError[sizeof(gDlError) - 1] = '\0';
|
||||
gDlErrorPending = 1;
|
||||
PosixRuntimeSetDlError(message);
|
||||
}
|
||||
|
||||
// Converts one native loader status to errno and a dlerror message.
|
||||
@@ -131,7 +124,5 @@ __declspec(dllexport) int dlclose(void* handle) {
|
||||
|
||||
// Returns and clears the most recent dynamic-loader error string.
|
||||
__declspec(dllexport) char* dlerror(void) {
|
||||
if (!gDlErrorPending || !gDlError[0]) return 0;
|
||||
gDlErrorPending = 0;
|
||||
return gDlError;
|
||||
return PosixRuntimeTakeDlError();
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,39 +1,81 @@
|
||||
// POSIX compatibility support for posix fd.
|
||||
// POSIX descriptor/open-description declarations internal to posix.dll.
|
||||
|
||||
#pragma once
|
||||
// posix_fd.h - file descriptor table (internal to posix.dll).
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <ntlite/syscall.h>
|
||||
|
||||
typedef enum {
|
||||
FD_FREE,
|
||||
FD_FILE,
|
||||
FD_CONSOLE_R, // fd 0 - reads from keyboard through SysReadKeyboardChar
|
||||
FD_CONSOLE_W, // fd 1, 2 - writes via SysWriteConsole
|
||||
FD_DEVNULL, // /dev/null
|
||||
FD_DEVZERO, // /dev/zero
|
||||
FD_SOCKET, // kernel socket handle
|
||||
} FD_TYPE;
|
||||
#define POSIX_FD_MAX 64
|
||||
#define POSIX_FD_INHERIT_SKIP_CLOEXEC 0x00000001u
|
||||
|
||||
typedef struct {
|
||||
FD_TYPE Type;
|
||||
uint32_t KHandle; // kernel handle; 0 for console/devnull/devzero
|
||||
bool Used;
|
||||
} FD_ENTRY;
|
||||
// Open-description kinds owned by the POSIX personality.
|
||||
typedef enum POSIX_FD_TYPE {
|
||||
PosixFdFile = NTL_POSIX_OPEN_TYPE_FILE,
|
||||
PosixFdConsoleRead = NTL_POSIX_OPEN_TYPE_CONSOLE_READ,
|
||||
PosixFdConsoleWrite = NTL_POSIX_OPEN_TYPE_CONSOLE_WRITE,
|
||||
PosixFdDevNull = NTL_POSIX_OPEN_TYPE_DEV_NULL,
|
||||
PosixFdDevZero = NTL_POSIX_OPEN_TYPE_DEV_ZERO,
|
||||
PosixFdSocket = NTL_POSIX_OPEN_TYPE_SOCKET,
|
||||
PosixFdPipeRead = NTL_POSIX_OPEN_TYPE_PIPE_READ,
|
||||
PosixFdPipeWrite = NTL_POSIX_OPEN_TYPE_PIPE_WRITE,
|
||||
} POSIX_FD_TYPE;
|
||||
|
||||
#define FD_MAX 64
|
||||
#define FD_TABLE_PIDS 32 // circular, indexed by pid % FD_TABLE_PIDS
|
||||
// One refcounted open description shared by one or more descriptors.
|
||||
typedef struct POSIX_OPEN_DESCRIPTION {
|
||||
volatile long RefCount;
|
||||
POSIX_FD_TYPE Type;
|
||||
uint32_t KHandle;
|
||||
uint64_t DescriptionId;
|
||||
NTL_POSIX_SHARED_OPEN_DESCRIPTION* Shared;
|
||||
} POSIX_OPEN_DESCRIPTION;
|
||||
|
||||
// Called from PosixStart before main(); sets up fds 0/1/2 for this process.
|
||||
__declspec(dllexport) void PosixFdInit(void);
|
||||
// One process-local descriptor entry with descriptor-local flags.
|
||||
typedef struct POSIX_FD {
|
||||
POSIX_OPEN_DESCRIPTION* Description;
|
||||
int DescriptorFlags;
|
||||
} POSIX_FD;
|
||||
|
||||
// Allocate the lowest free fd >= 3. Returns -1 and sets errno=EMFILE on failure.
|
||||
__declspec(dllexport) int FdAlloc(uint32_t pid, FD_TYPE type, uint32_t khandle);
|
||||
struct POSIX_PROCESS_STATE;
|
||||
|
||||
// Look up an fd. Returns NULL and sets errno=EBADF if invalid.
|
||||
__declspec(dllexport) FD_ENTRY* FdGet(uint32_t pid, int fd);
|
||||
// Initializes the process descriptor table from inherited state or fresh standard descriptors.
|
||||
uint32_t PosixFdInitializeProcess(struct POSIX_PROCESS_STATE* process, uint64_t inheritanceToken);
|
||||
|
||||
// Release an fd slot (does NOT close the kernel handle).
|
||||
__declspec(dllexport) void FdFree(uint32_t pid, int fd);
|
||||
// Captures the current descriptor table in one server-owned inheritance snapshot.
|
||||
KSTATUS PosixFdCreateInheritanceSnapshot(uint32_t flags, uint64_t* tokenOut);
|
||||
|
||||
int PosixStatusToErrno(uint32_t s);
|
||||
// Arms one inheritance snapshot to the lifetime of the native child process.
|
||||
KSTATUS PosixFdArmInheritanceSnapshot(uint64_t token, SYS_HANDLE processHandle);
|
||||
|
||||
// Cancels one unclaimed inheritance snapshot owned by the current process.
|
||||
void PosixFdCancelInheritanceSnapshot(uint64_t token);
|
||||
|
||||
// Releases descriptor-table resources during failed process startup.
|
||||
void PosixFdDestroyProcess(struct POSIX_PROCESS_STATE* process);
|
||||
|
||||
// Creates and installs one new open description at the lowest free descriptor >= 3.
|
||||
int PosixFdCreate(POSIX_FD_TYPE type, uint32_t khandle, int statusFlags);
|
||||
|
||||
// Installs one process-local wrapper for a server-created shared open description.
|
||||
int PosixFdImport(POSIX_FD_TYPE type, uint32_t khandle, uint64_t descriptionId,
|
||||
NTL_POSIX_SHARED_OPEN_DESCRIPTION* shared, int descriptorFlags);
|
||||
|
||||
// Releases one server holder when import/construction fails before a local wrapper exists.
|
||||
void PosixFdReleaseServerDescription(uint64_t descriptionId);
|
||||
|
||||
// Acquires a stable reference to an open description backing fd.
|
||||
POSIX_OPEN_DESCRIPTION* PosixFdAcquire(int fd);
|
||||
|
||||
// Returns one atomic snapshot of shared open-description status flags.
|
||||
int PosixFdGetStatusFlags(const POSIX_OPEN_DESCRIPTION* description);
|
||||
|
||||
// Applies F_SETFL mutable status through the server-owned open-description authority.
|
||||
int PosixFdSetStatusFlags(POSIX_OPEN_DESCRIPTION* description, int statusFlags);
|
||||
|
||||
// Releases one stable open-description reference.
|
||||
void PosixFdRelease(POSIX_OPEN_DESCRIPTION* description);
|
||||
|
||||
// Removes one descriptor and releases its table-owned open-description reference.
|
||||
int PosixFdClose(int fd);
|
||||
|
||||
int PosixStatusToErrno(uint32_t status);
|
||||
@@ -0,0 +1,134 @@
|
||||
// POSIX personality internal declarations and process/thread runtime state.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <pthread.h>
|
||||
#include <spawn.h>
|
||||
#include <dlfcn.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <poll.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <ntlite/posix_service.h>
|
||||
#include <ntlite/posix_extensions.h>
|
||||
#include <ntlite/syscall.h>
|
||||
#include "posix_fd.h"
|
||||
|
||||
#define POSIX_PROCESS_STATE_MAGIC 0x50505243u
|
||||
#define POSIX_THREAD_STATE_MAGIC 0x50544852u
|
||||
#define POSIX_DLERROR_MAX 160u
|
||||
#define POSIX_SPAWN_TABLE_SIZE 32u
|
||||
#define POSIX_PTHREAD_TABLE_SIZE 32u
|
||||
|
||||
typedef struct POSIX_SPAWN_ENTRY {
|
||||
pid_t Pid;
|
||||
SYS_HANDLE Handle;
|
||||
uint64_t FdInheritanceToken;
|
||||
bool Used;
|
||||
} POSIX_SPAWN_ENTRY;
|
||||
|
||||
typedef struct POSIX_PTHREAD_SLOT {
|
||||
uint32_t Tid;
|
||||
void* RetVal;
|
||||
bool Used;
|
||||
} POSIX_PTHREAD_SLOT;
|
||||
|
||||
typedef struct POSIX_LOGICAL_PROCESS_STATE {
|
||||
uint32_t PosixPid;
|
||||
uint32_t Generation;
|
||||
} POSIX_LOGICAL_PROCESS_STATE;
|
||||
|
||||
typedef struct POSIX_PROCESS_STATE {
|
||||
uint32_t Magic;
|
||||
SYS_PEB* Peb;
|
||||
SYS_HANDLE ServerEndpoint;
|
||||
POSIX_LOGICAL_PROCESS_STATE DefaultIdentity;
|
||||
SYS_HANDLE FdLock;
|
||||
POSIX_FD FdTable[POSIX_FD_MAX];
|
||||
POSIX_SPAWN_ENTRY SpawnTable[POSIX_SPAWN_TABLE_SIZE];
|
||||
POSIX_PTHREAD_SLOT PthreadTable[POSIX_PTHREAD_TABLE_SIZE];
|
||||
} POSIX_PROCESS_STATE;
|
||||
|
||||
typedef struct POSIX_THREAD_STATE {
|
||||
uint32_t Magic;
|
||||
int ErrnoValue;
|
||||
uint8_t DlErrorPending;
|
||||
uint8_t Reserved[3];
|
||||
char DlError[POSIX_DLERROR_MAX];
|
||||
POSIX_PROCESS_STATE* NativeProcess;
|
||||
POSIX_LOGICAL_PROCESS_STATE* LogicalProcess;
|
||||
struct passwd PasswordResult;
|
||||
char PasswordName[NTL_POSIX_IDENTITY_NAME_MAX + 1u];
|
||||
char PasswordHome[NTL_POSIX_IDENTITY_HOME_MAX + 1u];
|
||||
char PasswordShell[NTL_POSIX_IDENTITY_SHELL_MAX + 1u];
|
||||
struct group GroupResult;
|
||||
char GroupName[NTL_POSIX_IDENTITY_NAME_MAX + 1u];
|
||||
char* GroupMembers[1];
|
||||
char LoginName[NTL_POSIX_IDENTITY_NAME_MAX + 1u];
|
||||
} POSIX_THREAD_STATE;
|
||||
|
||||
// Initializes process-local POSIX state and attaches the initial thread.
|
||||
uint32_t PosixRuntimeInitializeProcess(void);
|
||||
|
||||
// Returns the POSIX state for the current process after startup.
|
||||
POSIX_PROCESS_STATE* PosixRuntimeProcessState(void);
|
||||
|
||||
// Returns the current thread state, attaching lazily when necessary.
|
||||
POSIX_THREAD_STATE* PosixRuntimeThreadState(void);
|
||||
|
||||
// Attaches POSIX state to the current native TEB.
|
||||
uint32_t PosixRuntimeAttachThread(void);
|
||||
|
||||
// Releases POSIX state owned by the current native TEB.
|
||||
void PosixRuntimeDetachThread(void);
|
||||
|
||||
// Clears the current thread's dynamic-loader error state.
|
||||
void PosixRuntimeClearDlError(void);
|
||||
|
||||
// Stores one dynamic-loader error in current-thread state.
|
||||
void PosixRuntimeSetDlError(const char* message);
|
||||
|
||||
// Returns and consumes the current thread's dynamic-loader error.
|
||||
char* PosixRuntimeTakeDlError(void);
|
||||
|
||||
// Calls posixsrv over the registered process endpoint and validates one fixed-size reply.
|
||||
KSTATUS PosixRuntimeCallServer(const NTL_POSIX_REQUEST* request, NTL_POSIX_REPLY* replyOut);
|
||||
|
||||
// Calls posixsrv while transferring a bounded set of native capabilities.
|
||||
KSTATUS PosixRuntimeCallServerWithHandles(const NTL_POSIX_REQUEST* request,
|
||||
const SYS_PORT_HANDLE_TRANSFER* handles,
|
||||
uint32_t handleCount,
|
||||
NTL_POSIX_REPLY* replyOut);
|
||||
|
||||
// Calls posixsrv with independent request/reply capability transfer.
|
||||
KSTATUS PosixRuntimeCallServerExchange(const NTL_POSIX_REQUEST* request,
|
||||
const SYS_PORT_HANDLE_TRANSFER* requestHandles,
|
||||
uint32_t requestHandleCount,
|
||||
SYS_HANDLE* replyHandlesOut,
|
||||
uint32_t replyHandleCapacity,
|
||||
uint32_t expectedReplyHandleCount,
|
||||
NTL_POSIX_REPLY* replyOut);
|
||||
|
||||
// Calls posixsrv and accepts a variable number of reply capabilities up to the supplied capacity.
|
||||
KSTATUS PosixRuntimeCallServerExchangeVariable(const NTL_POSIX_REQUEST* request,
|
||||
SYS_HANDLE* replyHandlesOut,
|
||||
uint32_t replyHandleCapacity,
|
||||
uint32_t* replyHandleCountOut,
|
||||
NTL_POSIX_REPLY* replyOut);
|
||||
|
||||
// Queries the server-owned shared process attributes for the current logical process.
|
||||
KSTATUS PosixRuntimeGetProcessAttributes(NTL_POSIX_REPLY* replyOut);
|
||||
@@ -1,53 +1,223 @@
|
||||
// POSIX compatibility support for posix io.
|
||||
// POSIX compatibility support for byte-stream file I/O.
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <intrin.h>
|
||||
#include <ntlite/syscall.h>
|
||||
#include <ntlite/console_service.h>
|
||||
#include <ntlite/path.h>
|
||||
#include "posix.h"
|
||||
#include "posix_internal.h"
|
||||
#include "posix_fd.h"
|
||||
#include "posix_path.h"
|
||||
|
||||
// Implements the clearscreen operation.
|
||||
__declspec(dllexport) void clearscreen(void) {
|
||||
SysClearScreen(0x012456);
|
||||
// Returns whether one open description permits reading.
|
||||
static bool PosixDescriptionReadable(const POSIX_OPEN_DESCRIPTION* description) {
|
||||
return description && (PosixFdGetStatusFlags(description) & O_ACCMODE) != O_WRONLY;
|
||||
}
|
||||
|
||||
// Implements the clearkeyboard operation.
|
||||
__declspec(dllexport) void clearkeyboard(void) {
|
||||
INPUT_KEY key;
|
||||
while (SysPollKeyboard(&key) == NTLSTATUS_SUCCESS) {
|
||||
char ignored;
|
||||
(void)SysReadKeyboardChar(&ignored);
|
||||
// Returns whether one open description permits writing.
|
||||
static bool PosixDescriptionWritable(const POSIX_OPEN_DESCRIPTION* description) {
|
||||
return description && (PosixFdGetStatusFlags(description) & O_ACCMODE) != O_RDONLY;
|
||||
}
|
||||
|
||||
// Returns the server-owned shared ring behind one pipe open description.
|
||||
static SYS_PIPE_SHARED_STATE* PosixPipeShared(POSIX_OPEN_DESCRIPTION* description) {
|
||||
if (!description || !description->Shared || description->Shared->SharedObjectData == 0) {
|
||||
errno = EIO;
|
||||
return (SYS_PIPE_SHARED_STATE*)0;
|
||||
}
|
||||
SYS_PIPE_SHARED_STATE* shared =
|
||||
(SYS_PIPE_SHARED_STATE*)(uintptr_t)description->Shared->SharedObjectData;
|
||||
if (shared->Magic != SYS_PIPE_SHARED_MAGIC || shared->Version != SYS_PIPE_SHARED_VERSION ||
|
||||
shared->Capacity != SYS_PIPE_BUFFER_CAPACITY ||
|
||||
shared->HeaderBytes != SYS_PIPE_SHARED_HEADER_BYTES) {
|
||||
errno = EIO;
|
||||
return (SYS_PIPE_SHARED_STATE*)0;
|
||||
}
|
||||
return shared;
|
||||
}
|
||||
|
||||
// Acquires one shared pipe-side serialization lock without entering the kernel.
|
||||
static void PosixPipeLock(volatile long* lock) {
|
||||
while (_InterlockedCompareExchange(lock, 1, 0) != 0)
|
||||
_mm_pause();
|
||||
_ReadWriteBarrier();
|
||||
}
|
||||
|
||||
// Releases one shared pipe-side serialization lock.
|
||||
static void PosixPipeUnlock(volatile long* lock) {
|
||||
_ReadWriteBarrier();
|
||||
_InterlockedExchange(lock, 0);
|
||||
}
|
||||
|
||||
// Returns buffered bytes, rejecting corrupted shared counters.
|
||||
static int PosixPipeUsed(SYS_PIPE_SHARED_STATE* shared, uint64_t* usedOut) {
|
||||
uint64_t readPosition = shared->ReadPosition;
|
||||
_ReadWriteBarrier();
|
||||
uint64_t writePosition = shared->WritePosition;
|
||||
uint64_t used = writePosition - readPosition;
|
||||
if (used > SYS_PIPE_BUFFER_CAPACITY) {
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
*usedOut = used;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Copies bytes out of the shared circular pipe buffer.
|
||||
static void PosixPipeCopyOut(SYS_PIPE_SHARED_STATE* shared, uint64_t readPosition,
|
||||
void* buffer, size_t length) {
|
||||
size_t offset = (size_t)(readPosition % SYS_PIPE_BUFFER_CAPACITY);
|
||||
size_t first = SYS_PIPE_BUFFER_CAPACITY - offset;
|
||||
if (first > length) first = length;
|
||||
memcpy(buffer, shared->Buffer + offset, first);
|
||||
if (first < length)
|
||||
memcpy((uint8_t*)buffer + first, shared->Buffer, length - first);
|
||||
}
|
||||
|
||||
// Copies bytes into the shared circular pipe buffer.
|
||||
static void PosixPipeCopyIn(SYS_PIPE_SHARED_STATE* shared, uint64_t writePosition,
|
||||
const void* buffer, size_t length) {
|
||||
size_t offset = (size_t)(writePosition % SYS_PIPE_BUFFER_CAPACITY);
|
||||
size_t first = SYS_PIPE_BUFFER_CAPACITY - offset;
|
||||
if (first > length) first = length;
|
||||
memcpy(shared->Buffer + offset, buffer, first);
|
||||
if (first < length)
|
||||
memcpy(shared->Buffer, (const uint8_t*)buffer + first, length - first);
|
||||
}
|
||||
|
||||
// Reads one pipe entirely through the shared user mapping except when blocking.
|
||||
static ssize_t PosixPipeRead(POSIX_OPEN_DESCRIPTION* description, void* buffer, size_t length) {
|
||||
SYS_PIPE_SHARED_STATE* shared = PosixPipeShared(description);
|
||||
if (!shared) return -1;
|
||||
|
||||
for (;;) {
|
||||
PosixPipeLock(&shared->ReadLock);
|
||||
uint64_t used = 0;
|
||||
if (PosixPipeUsed(shared, &used) != 0) {
|
||||
PosixPipeUnlock(&shared->ReadLock);
|
||||
return -1;
|
||||
}
|
||||
if (used != 0) {
|
||||
size_t transfer = length < used ? length : (size_t)used;
|
||||
uint64_t readPosition = shared->ReadPosition;
|
||||
PosixPipeCopyOut(shared, readPosition, buffer, transfer);
|
||||
_ReadWriteBarrier();
|
||||
shared->ReadPosition = readPosition + transfer;
|
||||
_ReadWriteBarrier();
|
||||
long writeWaiters = shared->WriteWaiters;
|
||||
PosixPipeUnlock(&shared->ReadLock);
|
||||
if (writeWaiters != 0)
|
||||
(void)SysNotifyPipe(description->KHandle);
|
||||
return (ssize_t)transfer;
|
||||
}
|
||||
if (shared->WriterOpen == 0) {
|
||||
PosixPipeUnlock(&shared->ReadLock);
|
||||
return 0;
|
||||
}
|
||||
if (PosixFdGetStatusFlags(description) & O_NONBLOCK) {
|
||||
PosixPipeUnlock(&shared->ReadLock);
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
PosixPipeUnlock(&shared->ReadLock);
|
||||
|
||||
uint32_t status = SysWait(description->KHandle, SYS_WAIT_FLAG_NONE);
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
errno = PosixStatusToErrno(status);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Opens the requested operation.
|
||||
// Writes one pipe entirely through the shared user mapping except when blocking/waking.
|
||||
static ssize_t PosixPipeWrite(POSIX_OPEN_DESCRIPTION* description, const void* buffer, size_t length) {
|
||||
SYS_PIPE_SHARED_STATE* shared = PosixPipeShared(description);
|
||||
if (!shared) return -1;
|
||||
|
||||
for (;;) {
|
||||
PosixPipeLock(&shared->WriteLock);
|
||||
if (shared->ReaderOpen == 0) {
|
||||
PosixPipeUnlock(&shared->WriteLock);
|
||||
errno = EPIPE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint64_t used = 0;
|
||||
if (PosixPipeUsed(shared, &used) != 0) {
|
||||
PosixPipeUnlock(&shared->WriteLock);
|
||||
return -1;
|
||||
}
|
||||
size_t available = SYS_PIPE_BUFFER_CAPACITY - (size_t)used;
|
||||
size_t transfer = 0;
|
||||
if (length <= SYS_PIPE_ATOMIC_WRITE_MAX) {
|
||||
if (available >= length)
|
||||
transfer = length;
|
||||
} else if (available != 0) {
|
||||
transfer = length < available ? length : available;
|
||||
}
|
||||
|
||||
if (transfer != 0) {
|
||||
uint64_t writePosition = shared->WritePosition;
|
||||
PosixPipeCopyIn(shared, writePosition, buffer, transfer);
|
||||
_ReadWriteBarrier();
|
||||
shared->WritePosition = writePosition + transfer;
|
||||
_ReadWriteBarrier();
|
||||
long readWaiters = shared->ReadWaiters;
|
||||
PosixPipeUnlock(&shared->WriteLock);
|
||||
if (readWaiters != 0)
|
||||
(void)SysNotifyPipe(description->KHandle);
|
||||
return (ssize_t)transfer;
|
||||
}
|
||||
|
||||
if (PosixFdGetStatusFlags(description) & O_NONBLOCK) {
|
||||
PosixPipeUnlock(&shared->WriteLock);
|
||||
errno = EAGAIN;
|
||||
return -1;
|
||||
}
|
||||
PosixPipeUnlock(&shared->WriteLock);
|
||||
|
||||
uint32_t status = SysWait(description->KHandle, SYS_WAIT_FLAG_NONE);
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
errno = PosixStatusToErrno(status);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clears the native console display.
|
||||
__declspec(dllexport) void clearscreen(void) {
|
||||
(void)NtlConsoleClear(SYS_HANDLE_INVALID, 0x012456);
|
||||
}
|
||||
|
||||
// Flushes pending native console keyboard input.
|
||||
__declspec(dllexport) void clearkeyboard(void) {
|
||||
(void)NtlConsoleFlushInput(SYS_HANDLE_INVALID);
|
||||
}
|
||||
|
||||
// Opens one native file or synthetic POSIX device and returns a process-local descriptor.
|
||||
__declspec(dllexport) int open(const char* path, int flags, ...) {
|
||||
if (!path || (flags & O_ACCMODE) == O_ACCMODE) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
char native[512];
|
||||
const char* p = PosixTranslatePath(path, native, sizeof(native));
|
||||
|
||||
uint32_t pid = SysGetCurrentPid();
|
||||
FD_TYPE type = FD_FILE;
|
||||
int statusFlags = flags & (O_ACCMODE | O_APPEND | O_NONBLOCK);
|
||||
if (strcmp(p, SYNTH_DEVNULL) == 0)
|
||||
return PosixFdCreate(PosixFdDevNull, SYS_HANDLE_INVALID, statusFlags);
|
||||
if (strcmp(p, SYNTH_DEVZERO) == 0)
|
||||
return PosixFdCreate(PosixFdDevZero, SYS_HANDLE_INVALID, statusFlags);
|
||||
|
||||
// Synthetic devices.
|
||||
if (strcmp(p, SYNTH_DEVNULL) == 0) {
|
||||
int fd = FdAlloc(pid, FD_DEVNULL, 0);
|
||||
return fd;
|
||||
}
|
||||
|
||||
if (strcmp(p, SYNTH_DEVZERO) == 0) {
|
||||
int fd = FdAlloc(pid, FD_DEVZERO, 0);
|
||||
return fd;
|
||||
}
|
||||
|
||||
uint32_t kh = 0;
|
||||
uint32_t access = SYS_FILE_ACCESS_QUERY;
|
||||
uint32_t kh = SYS_HANDLE_INVALID;
|
||||
uint32_t access = SYS_FILE_ACCESS_QUERY | SYS_FILE_ACCESS_LOCK;
|
||||
uint32_t disposition = SYS_FILE_OPEN_EXISTING;
|
||||
|
||||
if ((flags & O_RDWR) == O_RDWR)
|
||||
if ((flags & O_ACCMODE) == O_RDWR)
|
||||
access |= SYS_FILE_ACCESS_READ | SYS_FILE_ACCESS_WRITE;
|
||||
else if (flags & O_WRONLY)
|
||||
else if ((flags & O_ACCMODE) == O_WRONLY)
|
||||
access |= SYS_FILE_ACCESS_WRITE;
|
||||
else
|
||||
access |= SYS_FILE_ACCESS_READ;
|
||||
@@ -62,166 +232,323 @@ __declspec(dllexport) int open(const char* path, int flags, ...) {
|
||||
else if (flags & O_TRUNC)
|
||||
disposition = SYS_FILE_TRUNCATE_EXISTING;
|
||||
|
||||
uint32_t s = NtlOpenFile(SysSvFromCstr(p), access, disposition,
|
||||
SYS_FILE_FLAG_NONE, &kh);
|
||||
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
|
||||
|
||||
int fd = FdAlloc(pid, type, kh);
|
||||
if (fd < 0) {
|
||||
SysCloseHandle(kh); // FdAlloc already set errno
|
||||
uint32_t status = NtlOpenFile(SysSvFromCstr(p), access, disposition,
|
||||
SYS_FILE_FLAG_NONE, &kh);
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
errno = PosixStatusToErrno(status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fd = PosixFdCreate(PosixFdFile, kh, statusFlags);
|
||||
if (fd < 0)
|
||||
SysCloseHandle(kh);
|
||||
return fd;
|
||||
}
|
||||
|
||||
// Returns the requested value.
|
||||
// Reads bytes from one descriptor through its stable open-description reference.
|
||||
__declspec(dllexport) ssize_t read(int fd, void* buf, size_t count) {
|
||||
if (count == 0) return 0;
|
||||
uint32_t pid = SysGetCurrentPid();
|
||||
FD_ENTRY* e = FdGet(pid, fd);
|
||||
if (!e) return -1;
|
||||
if (count == 0)
|
||||
return 0;
|
||||
if (!buf) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (e->Type) {
|
||||
case FD_CONSOLE_R: {
|
||||
// Read up to count chars from keyboard, blocking per char.
|
||||
POSIX_OPEN_DESCRIPTION* description = PosixFdAcquire(fd);
|
||||
if (!description)
|
||||
return -1;
|
||||
if (!PosixDescriptionReadable(description)) {
|
||||
PosixFdRelease(description);
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t result = -1;
|
||||
switch (description->Type) {
|
||||
case PosixFdConsoleRead: {
|
||||
char* dst = (char*)buf;
|
||||
result = (ssize_t)count;
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
uint32_t s = SysReadKeyboardChar(&dst[i]);
|
||||
if (s != NTLSTATUS_SUCCESS) { errno = PosixStatusToErrno(s); return -1; }
|
||||
if (dst[i] == '\n' || dst[i] == '\r') return (ssize_t)(i + 1);
|
||||
uint32_t status = NtlConsoleReadCharacter(SYS_HANDLE_INVALID, &dst[i]);
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
errno = PosixStatusToErrno(status);
|
||||
result = -1;
|
||||
break;
|
||||
}
|
||||
if (dst[i] == '\n' || dst[i] == '\r') {
|
||||
result = (ssize_t)(i + 1u);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (ssize_t)count;
|
||||
break;
|
||||
}
|
||||
case FD_DEVNULL:
|
||||
return 0;
|
||||
case FD_DEVZERO:
|
||||
case PosixFdDevNull:
|
||||
result = 0;
|
||||
break;
|
||||
case PosixFdDevZero:
|
||||
memset(buf, 0, count);
|
||||
return (ssize_t)count;
|
||||
case FD_FILE: {
|
||||
result = (ssize_t)count;
|
||||
break;
|
||||
case PosixFdFile: {
|
||||
size_t got = 0;
|
||||
SYS_FILE_IO_REQUEST req = SysMakeFileIoRequest(e->KHandle, buf, count, &got);
|
||||
uint32_t s = SysReadFile(&req);
|
||||
if (s != 0 && got == 0) { errno = PosixStatusToErrno(s); return -1; }
|
||||
return (ssize_t)got;
|
||||
SYS_FILE_IO_REQUEST request =
|
||||
SysMakeFileIoRequest(description->KHandle, buf, count, &got);
|
||||
uint32_t status = SysReadFile(&request);
|
||||
if (status != NTLSTATUS_SUCCESS && got == 0)
|
||||
errno = PosixStatusToErrno(status);
|
||||
else
|
||||
result = (ssize_t)got;
|
||||
break;
|
||||
}
|
||||
case FD_SOCKET: {
|
||||
case PosixFdPipeRead:
|
||||
result = PosixPipeRead(description, buf, count);
|
||||
break;
|
||||
case PosixFdSocket: {
|
||||
size_t got = 0;
|
||||
SYS_SOCKET_RECV_REQUEST request = {
|
||||
sizeof(SYS_SOCKET_RECV_REQUEST), e->KHandle, 0,
|
||||
sizeof(SYS_SOCKET_RECV_REQUEST), description->KHandle, 0,
|
||||
buf, count, &got
|
||||
};
|
||||
uint32_t s = SysRecvSocket(&request);
|
||||
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
|
||||
return (ssize_t)got;
|
||||
uint32_t status = SysRecvSocket(&request);
|
||||
if (status != NTLSTATUS_SUCCESS)
|
||||
errno = PosixStatusToErrno(status);
|
||||
else
|
||||
result = (ssize_t)got;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
PosixFdRelease(description);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Updates the requested value.
|
||||
// Writes bytes through one descriptor's shared open description.
|
||||
__declspec(dllexport) ssize_t write(int fd, const void* buf, size_t count) {
|
||||
if (count == 0) return 0;
|
||||
uint32_t pid = SysGetCurrentPid();
|
||||
FD_ENTRY* e = FdGet(pid, fd);
|
||||
if (!e) return -1;
|
||||
if (count == 0)
|
||||
return 0;
|
||||
if (!buf) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (e->Type) {
|
||||
case FD_CONSOLE_W: {
|
||||
SYS_WRITE_CONSOLE_REQUEST req = { sizeof(SYS_WRITE_CONSOLE_REQUEST), SysSvFromParts((const char*)buf, count) };
|
||||
SysWriteConsole(&req);
|
||||
return (ssize_t)count;
|
||||
}
|
||||
case FD_DEVNULL:
|
||||
case FD_DEVZERO:
|
||||
return (ssize_t)count;
|
||||
case FD_FILE: {
|
||||
POSIX_OPEN_DESCRIPTION* description = PosixFdAcquire(fd);
|
||||
if (!description)
|
||||
return -1;
|
||||
if (!PosixDescriptionWritable(description)) {
|
||||
PosixFdRelease(description);
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t result = -1;
|
||||
switch (description->Type) {
|
||||
case PosixFdConsoleWrite: {
|
||||
size_t written = 0;
|
||||
SYS_FILE_IO_REQUEST req = SysMakeFileIoRequest(e->KHandle, buf, count, &written);
|
||||
uint32_t s = SysWriteFile(&req);
|
||||
if (s != 0 && written == 0) { errno = PosixStatusToErrno(s); return -1; }
|
||||
return (ssize_t)written;
|
||||
uint32_t status = NtlConsoleWrite(SYS_HANDLE_INVALID, buf, count, &written);
|
||||
if (status != NTLSTATUS_SUCCESS && written == 0)
|
||||
errno = PosixStatusToErrno(status);
|
||||
else
|
||||
result = (ssize_t)written;
|
||||
break;
|
||||
}
|
||||
case FD_SOCKET: {
|
||||
case PosixFdDevNull:
|
||||
case PosixFdDevZero:
|
||||
result = (ssize_t)count;
|
||||
break;
|
||||
case PosixFdFile: {
|
||||
size_t written = 0;
|
||||
SYS_FILE_IO_REQUEST request =
|
||||
SysMakeFileIoRequest(description->KHandle, (void*)buf, count, &written);
|
||||
uint32_t status = SysWriteFile(&request);
|
||||
if (status != NTLSTATUS_SUCCESS && written == 0)
|
||||
errno = PosixStatusToErrno(status);
|
||||
else
|
||||
result = (ssize_t)written;
|
||||
break;
|
||||
}
|
||||
case PosixFdPipeWrite:
|
||||
result = PosixPipeWrite(description, buf, count);
|
||||
break;
|
||||
case PosixFdSocket: {
|
||||
size_t sent = 0;
|
||||
SYS_SOCKET_SEND_REQUEST request = {
|
||||
sizeof(SYS_SOCKET_SEND_REQUEST), e->KHandle, 0,
|
||||
sizeof(SYS_SOCKET_SEND_REQUEST), description->KHandle, 0,
|
||||
buf, count, &sent
|
||||
};
|
||||
uint32_t s = SysSendSocket(&request);
|
||||
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
|
||||
return (ssize_t)sent;
|
||||
uint32_t status = SysSendSocket(&request);
|
||||
if (status != NTLSTATUS_SUCCESS)
|
||||
errno = PosixStatusToErrno(status);
|
||||
else
|
||||
result = (ssize_t)sent;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
PosixFdRelease(description);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Releases the requested object.
|
||||
// Closes one descriptor without invalidating concurrent open-description users.
|
||||
__declspec(dllexport) int close(int fd) {
|
||||
uint32_t pid = SysGetCurrentPid();
|
||||
FD_ENTRY* e = FdGet(pid, fd);
|
||||
if (!e) return -1;
|
||||
if (e->Type == FD_FILE || e->Type == FD_SOCKET)
|
||||
SysCloseHandle(e->KHandle);
|
||||
FdFree(pid, fd);
|
||||
return PosixFdClose(fd);
|
||||
}
|
||||
|
||||
// Creates one anonymous pipe whose backing and master endpoint capabilities are owned by posixsrv.
|
||||
__declspec(dllexport) int pipe(int pipefd[2]) {
|
||||
if (!pipefd) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
NTL_POSIX_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Version = NTL_POSIX_PROTOCOL_VERSION;
|
||||
request.Operation = NTL_POSIX_OP_CREATE_PIPE;
|
||||
request.Flags = NTL_POSIX_REQUEST_FLAG_NONE;
|
||||
|
||||
SYS_HANDLE handles[2] = { SYS_HANDLE_INVALID, SYS_HANDLE_INVALID };
|
||||
NTL_POSIX_REPLY reply;
|
||||
KSTATUS status = PosixRuntimeCallServerExchange(
|
||||
&request, (const SYS_PORT_HANDLE_TRANSFER*)0, 0, handles, 2u, 2u, &reply);
|
||||
if (!KSUCCESS(status) || !KSUCCESS(reply.Status)) {
|
||||
for (uint32_t i = 0; i < 2u; ++i) {
|
||||
if (handles[i] != SYS_HANDLE_INVALID)
|
||||
(void)SysCloseHandle(handles[i]);
|
||||
}
|
||||
errno = PosixStatusToErrno(KSUCCESS(status) ? reply.Status : status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
NTL_POSIX_SHARED_OPEN_DESCRIPTION* readShared =
|
||||
(NTL_POSIX_SHARED_OPEN_DESCRIPTION*)(uintptr_t)reply.SharedOpenDescription;
|
||||
NTL_POSIX_SHARED_OPEN_DESCRIPTION* writeShared =
|
||||
(NTL_POSIX_SHARED_OPEN_DESCRIPTION*)(uintptr_t)reply.SharedOpenDescription2;
|
||||
SYS_PIPE_SHARED_STATE* pipeShared = readShared ?
|
||||
(SYS_PIPE_SHARED_STATE*)(uintptr_t)readShared->SharedObjectData :
|
||||
(SYS_PIPE_SHARED_STATE*)0;
|
||||
int valid = handles[0] != SYS_HANDLE_INVALID && handles[1] != SYS_HANDLE_INVALID &&
|
||||
reply.OpenDescriptionId != 0 && reply.OpenDescriptionId2 != 0 &&
|
||||
reply.OpenDescriptionId != reply.OpenDescriptionId2 &&
|
||||
reply.OpenDescriptionType == NTL_POSIX_OPEN_TYPE_PIPE_READ &&
|
||||
reply.OpenDescriptionType2 == NTL_POSIX_OPEN_TYPE_PIPE_WRITE &&
|
||||
reply.OpenStatusFlags == NTL_POSIX_OPEN_STATUS_RDONLY &&
|
||||
reply.OpenStatusFlags2 == NTL_POSIX_OPEN_STATUS_WRONLY &&
|
||||
readShared && writeShared &&
|
||||
readShared->Magic == NTL_POSIX_SHARED_OPEN_MAGIC &&
|
||||
writeShared->Magic == NTL_POSIX_SHARED_OPEN_MAGIC &&
|
||||
readShared->Version == NTL_POSIX_SHARED_OPEN_VERSION &&
|
||||
writeShared->Version == NTL_POSIX_SHARED_OPEN_VERSION &&
|
||||
readShared->Type == NTL_POSIX_OPEN_TYPE_PIPE_READ &&
|
||||
writeShared->Type == NTL_POSIX_OPEN_TYPE_PIPE_WRITE &&
|
||||
readShared->DescriptionId == reply.OpenDescriptionId &&
|
||||
writeShared->DescriptionId == reply.OpenDescriptionId2 &&
|
||||
readShared->Reserved == 0 && writeShared->Reserved == 0 &&
|
||||
readShared->Reserved2 == 0 && writeShared->Reserved2 == 0 &&
|
||||
readShared->SharedObjectData != 0 &&
|
||||
readShared->SharedObjectData == writeShared->SharedObjectData &&
|
||||
pipeShared && pipeShared->Magic == SYS_PIPE_SHARED_MAGIC &&
|
||||
pipeShared->Version == SYS_PIPE_SHARED_VERSION &&
|
||||
pipeShared->Capacity == SYS_PIPE_BUFFER_CAPACITY &&
|
||||
pipeShared->HeaderBytes == SYS_PIPE_SHARED_HEADER_BYTES;
|
||||
if (!valid) {
|
||||
(void)SysCloseHandle(handles[0]);
|
||||
(void)SysCloseHandle(handles[1]);
|
||||
PosixFdReleaseServerDescription(reply.OpenDescriptionId);
|
||||
PosixFdReleaseServerDescription(reply.OpenDescriptionId2);
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int readFd = PosixFdImport(PosixFdPipeRead, handles[0], reply.OpenDescriptionId,
|
||||
readShared, 0);
|
||||
handles[0] = SYS_HANDLE_INVALID;
|
||||
if (readFd < 0) {
|
||||
(void)SysCloseHandle(handles[1]);
|
||||
PosixFdReleaseServerDescription(reply.OpenDescriptionId2);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int writeFd = PosixFdImport(PosixFdPipeWrite, handles[1], reply.OpenDescriptionId2,
|
||||
writeShared, 0);
|
||||
handles[1] = SYS_HANDLE_INVALID;
|
||||
if (writeFd < 0) {
|
||||
(void)PosixFdClose(readFd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pipefd[0] = readFd;
|
||||
pipefd[1] = writeFd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Implements the unlink operation.
|
||||
// Deletes one translated native path.
|
||||
__declspec(dllexport) int unlink(const char* path) {
|
||||
if (!path) { errno = EINVAL; return -1; }
|
||||
|
||||
char native[512];
|
||||
const char* p = PosixTranslatePath(path, native, sizeof(native));
|
||||
|
||||
if (strcmp(p, SYNTH_DEVNULL) == 0 || strcmp(p, SYNTH_DEVZERO) == 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t s = NtlDeleteFile(SysSvFromCstr(p));
|
||||
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
|
||||
uint32_t status = NtlDeleteFile(SysSvFromCstr(p));
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
errno = PosixStatusToErrno(status);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Implements the lseek operation.
|
||||
// Repositions the shared file offset owned by an open description.
|
||||
__declspec(dllexport) off_t lseek(int fd, off_t offset, int whence) {
|
||||
uint32_t pid = SysGetCurrentPid();
|
||||
FD_ENTRY* e = FdGet(pid, fd);
|
||||
if (!e || e->Type != FD_FILE) { errno = (e ? ESPIPE : EBADF); return -1; }
|
||||
|
||||
int64_t target = 0;
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
target = (int64_t)offset;
|
||||
break;
|
||||
case SEEK_CUR: {
|
||||
uint64_t cur = 0;
|
||||
uint32_t s = SysGetFilePos(e->KHandle, &cur);
|
||||
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
|
||||
if (cur > 0x7FFFFFFFULL) { errno = EINVAL; return -1; }
|
||||
target = (int64_t)cur + (int64_t)offset;
|
||||
break;
|
||||
}
|
||||
case SEEK_END: {
|
||||
uint64_t size = 0;
|
||||
uint32_t s = SysGetFileSize(e->KHandle, &size);
|
||||
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
|
||||
if (size > 0x7FFFFFFFULL) { errno = EINVAL; return -1; }
|
||||
target = (int64_t)size + (int64_t)offset;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
POSIX_OPEN_DESCRIPTION* description = PosixFdAcquire(fd);
|
||||
if (!description)
|
||||
return -1;
|
||||
if (description->Type != PosixFdFile) {
|
||||
PosixFdRelease(description);
|
||||
errno = ESPIPE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (target < 0 || target > 0x7FFFFFFFLL) { errno = EINVAL; return -1; }
|
||||
int64_t target = 0;
|
||||
uint32_t status = NTLSTATUS_SUCCESS;
|
||||
if (whence == SEEK_SET) {
|
||||
target = (int64_t)offset;
|
||||
} else if (whence == SEEK_CUR) {
|
||||
uint64_t current = 0;
|
||||
status = SysGetFilePos(description->KHandle, ¤t);
|
||||
if (status == NTLSTATUS_SUCCESS && current <= 0x7FFFFFFFULL)
|
||||
target = (int64_t)current + (int64_t)offset;
|
||||
else if (status == NTLSTATUS_SUCCESS)
|
||||
status = NTLSTATUS_INVALID_PARAMETER;
|
||||
} else if (whence == SEEK_END) {
|
||||
uint64_t size = 0;
|
||||
status = SysGetFileSize(description->KHandle, &size);
|
||||
if (status == NTLSTATUS_SUCCESS && size <= 0x7FFFFFFFULL)
|
||||
target = (int64_t)size + (int64_t)offset;
|
||||
else if (status == NTLSTATUS_SUCCESS)
|
||||
status = NTLSTATUS_INVALID_PARAMETER;
|
||||
} else {
|
||||
status = NTLSTATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
uint32_t s = SysSeekFile(e->KHandle, (uint64_t)target);
|
||||
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
|
||||
if (status == NTLSTATUS_SUCCESS && (target < 0 || target > 0x7FFFFFFFLL))
|
||||
status = NTLSTATUS_INVALID_PARAMETER;
|
||||
if (status == NTLSTATUS_SUCCESS)
|
||||
status = SysSeekFile(description->KHandle, (uint64_t)target);
|
||||
|
||||
PosixFdRelease(description);
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
errno = PosixStatusToErrno(status);
|
||||
return -1;
|
||||
}
|
||||
return (off_t)target;
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <ntlite/syscall.h>
|
||||
#include "posix.h"
|
||||
#include "posix_internal.h"
|
||||
#include "posix_fd.h"
|
||||
|
||||
static uint32_t PosixProtToSysMapAccess(int prot, int flags) {
|
||||
@@ -31,16 +31,17 @@ __declspec(dllexport) void* mmap(void* addr, size_t length, int prot,
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
uint32_t pid = SysGetCurrentPid();
|
||||
FD_ENTRY* e = FdGet(pid, fd);
|
||||
if (!e) return MAP_FAILED;
|
||||
if (e->Type != FD_FILE) {
|
||||
POSIX_OPEN_DESCRIPTION* description = PosixFdAcquire(fd);
|
||||
if (!description) return MAP_FAILED;
|
||||
if (description->Type != PosixFdFile) {
|
||||
PosixFdRelease(description);
|
||||
errno = EBADF;
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
uint64_t maxSize = (uint64_t)offset + (uint64_t)length;
|
||||
if (maxSize < (uint64_t)offset) {
|
||||
PosixFdRelease(description);
|
||||
errno = EINVAL;
|
||||
return MAP_FAILED;
|
||||
}
|
||||
@@ -51,10 +52,11 @@ __declspec(dllexport) void* mmap(void* addr, size_t length, int prot,
|
||||
|
||||
uint32_t mapping = 0;
|
||||
SYS_CREATE_FILE_MAPPING_REQUEST createMapping = {
|
||||
sizeof(SYS_CREATE_FILE_MAPPING_REQUEST), e->KHandle, protect,
|
||||
sizeof(SYS_CREATE_FILE_MAPPING_REQUEST), description->KHandle, protect,
|
||||
SYS_MAP_FLAG_NONE, maxSize, &mapping
|
||||
};
|
||||
uint32_t s = SysCreateFileMapping(&createMapping);
|
||||
PosixFdRelease(description);
|
||||
if (s != NTLSTATUS_SUCCESS) {
|
||||
errno = PosixStatusToErrno(s);
|
||||
return MAP_FAILED;
|
||||
|
||||
@@ -5,15 +5,13 @@
|
||||
#include <ntlite/syscall.h>
|
||||
#include <ntlite/path.h>
|
||||
#include <ntlite/process_loader.h>
|
||||
#include "posix.h"
|
||||
#include "posix_internal.h"
|
||||
#include "posix_path.h"
|
||||
|
||||
static SYS_PEB* gProcessPeb = NULL;
|
||||
|
||||
// Implements the peb operation.
|
||||
// Returns the native PEB retained by the process-local POSIX runtime state.
|
||||
static SYS_PEB* PosixPeb(void) {
|
||||
if (!gProcessPeb) gProcessPeb = SysGetPeb();
|
||||
return gProcessPeb;
|
||||
POSIX_PROCESS_STATE* process = PosixRuntimeProcessState();
|
||||
return process ? process->Peb : (SYS_PEB*)0;
|
||||
}
|
||||
|
||||
// Implements the posix get command line operation.
|
||||
@@ -23,40 +21,49 @@ __declspec(dllexport) const char* posix_get_command_line(void) {
|
||||
return peb->CommandLine.Data;
|
||||
}
|
||||
|
||||
// pid -> proc handle table (user-mode side, for waitpid).
|
||||
#define PROC_TABLE_SIZE 32
|
||||
typedef struct {
|
||||
pid_t pid;
|
||||
uint32_t handle;
|
||||
bool used;
|
||||
} ProcEntry;
|
||||
// Records one spawn association in process-local POSIX state.
|
||||
static void ProcTableInsert(pid_t pid, SYS_HANDLE handle, uint64_t inheritanceToken) {
|
||||
POSIX_PROCESS_STATE* process = PosixRuntimeProcessState();
|
||||
if (!process) {
|
||||
SysCloseHandle(handle);
|
||||
return;
|
||||
}
|
||||
|
||||
static ProcEntry gProcTable[PROC_TABLE_SIZE];
|
||||
|
||||
// Implements the proc Table Insert operation.
|
||||
static void ProcTableInsert(pid_t pid, uint32_t handle) {
|
||||
for (int i = 0; i < PROC_TABLE_SIZE; i++) {
|
||||
if (!gProcTable[i].used) {
|
||||
gProcTable[i] = (ProcEntry){ pid, handle, true };
|
||||
for (uint32_t i = 0; i < POSIX_SPAWN_TABLE_SIZE; i++) {
|
||||
if (!process->SpawnTable[i].Used) {
|
||||
process->SpawnTable[i] = (POSIX_SPAWN_ENTRY){ pid, handle, inheritanceToken, true };
|
||||
return;
|
||||
}
|
||||
}
|
||||
SysCloseHandle(handle);
|
||||
if (inheritanceToken != 0) PosixFdCancelInheritanceSnapshot(inheritanceToken);
|
||||
}
|
||||
|
||||
// Implements the proc Table Find operation.
|
||||
static uint32_t ProcTableFind(pid_t pid) {
|
||||
for (int i = 0; i < PROC_TABLE_SIZE; i++)
|
||||
if (gProcTable[i].used && gProcTable[i].pid == pid)
|
||||
return gProcTable[i].handle;
|
||||
return 0;
|
||||
// Finds a spawned process handle retained by the current POSIX process.
|
||||
static SYS_HANDLE ProcTableFind(pid_t pid) {
|
||||
POSIX_PROCESS_STATE* process = PosixRuntimeProcessState();
|
||||
if (!process) return SYS_HANDLE_INVALID;
|
||||
|
||||
for (uint32_t i = 0; i < POSIX_SPAWN_TABLE_SIZE; i++) {
|
||||
if (process->SpawnTable[i].Used && process->SpawnTable[i].Pid == pid)
|
||||
return process->SpawnTable[i].Handle;
|
||||
}
|
||||
return SYS_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
// Implements the proc Table Remove operation.
|
||||
// Removes one spawn association from process-local POSIX state.
|
||||
static void ProcTableRemove(pid_t pid) {
|
||||
for (int i = 0; i < PROC_TABLE_SIZE; i++)
|
||||
if (gProcTable[i].used && gProcTable[i].pid == pid)
|
||||
gProcTable[i].used = false;
|
||||
POSIX_PROCESS_STATE* process = PosixRuntimeProcessState();
|
||||
if (!process) return;
|
||||
|
||||
for (uint32_t i = 0; i < POSIX_SPAWN_TABLE_SIZE; i++) {
|
||||
if (process->SpawnTable[i].Used && process->SpawnTable[i].Pid == pid) {
|
||||
uint64_t inheritanceToken = process->SpawnTable[i].FdInheritanceToken;
|
||||
memset(&process->SpawnTable[i], 0, sizeof(process->SpawnTable[i]));
|
||||
if (inheritanceToken != 0) PosixFdCancelInheritanceSnapshot(inheritanceToken);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build a flat Windows-style cmdline from a NULL-terminated argv array.
|
||||
@@ -82,7 +89,10 @@ static void BuildCmdline(char* const argv[], char* out, size_t outSize) {
|
||||
// POSIX API.
|
||||
|
||||
__declspec(dllexport) pid_t getpid(void) {
|
||||
return (pid_t)SysGetCurrentPid();
|
||||
POSIX_THREAD_STATE* thread = PosixRuntimeThreadState();
|
||||
if (!thread || !thread->LogicalProcess || thread->LogicalProcess->PosixPid == 0)
|
||||
return (pid_t)-1;
|
||||
return (pid_t)thread->LogicalProcess->PosixPid;
|
||||
}
|
||||
|
||||
__declspec(dllexport) int posix_spawn(pid_t* pidOut,
|
||||
@@ -96,12 +106,12 @@ __declspec(dllexport) int posix_spawn(pid_t* pidOut,
|
||||
|
||||
char native[512];
|
||||
uint32_t pathStatus = PosixProcessPath(path, native, sizeof(native));
|
||||
if (pathStatus != NTLSTATUS_SUCCESS) { errno = ENOENT; return -1; }
|
||||
if (pathStatus != NTLSTATUS_SUCCESS) { errno = PosixStatusToErrno(pathStatus); return -1; }
|
||||
|
||||
SYS_HANDLE imageFile = SYS_HANDLE_INVALID;
|
||||
pathStatus = NtlOpenFile(SysSvFromCstr(native), SYS_FILE_ACCESS_READ | SYS_FILE_ACCESS_QUERY,
|
||||
SYS_FILE_OPEN_EXISTING, SYS_FILE_FLAG_NONE, &imageFile);
|
||||
if (pathStatus != NTLSTATUS_SUCCESS) { errno = ENOENT; return -1; }
|
||||
if (pathStatus != NTLSTATUS_SUCCESS) { errno = PosixStatusToErrno(pathStatus); return -1; }
|
||||
|
||||
char cmdline[512];
|
||||
BuildCmdline(argv, cmdline, sizeof(cmdline));
|
||||
@@ -114,6 +124,22 @@ __declspec(dllexport) int posix_spawn(pid_t* pidOut,
|
||||
cmdline[len] = '\0';
|
||||
}
|
||||
|
||||
uint64_t inheritanceToken = 0;
|
||||
uint32_t snapshotStatus =
|
||||
PosixFdCreateInheritanceSnapshot(POSIX_FD_INHERIT_SKIP_CLOEXEC, &inheritanceToken);
|
||||
if (snapshotStatus != NTLSTATUS_SUCCESS) {
|
||||
(void)SysCloseHandle(imageFile);
|
||||
errno = PosixStatusToErrno(snapshotStatus);
|
||||
return -1;
|
||||
}
|
||||
|
||||
NTL_POSIX_BOOTSTRAP_DATA bootstrap;
|
||||
memset(&bootstrap, 0, sizeof(bootstrap));
|
||||
bootstrap.Magic = NTL_POSIX_BOOTSTRAP_MAGIC;
|
||||
bootstrap.Version = NTL_POSIX_BOOTSTRAP_VERSION;
|
||||
bootstrap.Size = sizeof(bootstrap);
|
||||
bootstrap.FdInheritanceToken = inheritanceToken;
|
||||
|
||||
uint32_t procHandle = 0;
|
||||
NTL_CREATE_SYSTEM_PROCESS_REQUEST req;
|
||||
memset(&req, 0, sizeof(req));
|
||||
@@ -124,14 +150,29 @@ __declspec(dllexport) int posix_spawn(pid_t* pidOut,
|
||||
req.CommandLine = SysSvFromCstr(cmdline);
|
||||
req.SecurityContext = SYS_SECURITY_CONTEXT_CURRENT;
|
||||
req.ResolveModuleName = PosixResolveModuleName;
|
||||
req.StartupData = &bootstrap;
|
||||
req.StartupDataSize = sizeof(bootstrap);
|
||||
req.ProcessHandleOut = &procHandle;
|
||||
uint32_t s = NtlCreateSystemProcess(&req);
|
||||
if (imageFile != SYS_HANDLE_INVALID) (void)SysCloseHandle(imageFile);
|
||||
if (s != 0) { errno = ENOENT; return -1; }
|
||||
if (s != NTLSTATUS_SUCCESS) {
|
||||
PosixFdCancelInheritanceSnapshot(inheritanceToken);
|
||||
errno = PosixStatusToErrno(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
KSTATUS armStatus = PosixFdArmInheritanceSnapshot(inheritanceToken, procHandle);
|
||||
if (!KSUCCESS(armStatus) && armStatus != NTLSTATUS_NOT_FOUND) {
|
||||
(void)SysKillProcess(procHandle, (int32_t)NTLSTATUS_PROCESS_KILLED);
|
||||
(void)SysCloseHandle(procHandle);
|
||||
PosixFdCancelInheritanceSnapshot(inheritanceToken);
|
||||
errno = PosixStatusToErrno(armStatus);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t kpid = 0;
|
||||
SysGetProcessPid(procHandle, &kpid);
|
||||
ProcTableInsert((pid_t)kpid, procHandle);
|
||||
ProcTableInsert((pid_t)kpid, procHandle, inheritanceToken);
|
||||
if (pidOut) *pidOut = (pid_t)kpid;
|
||||
return 0;
|
||||
}
|
||||
@@ -140,8 +181,8 @@ __declspec(dllexport) int posix_spawn(pid_t* pidOut,
|
||||
__declspec(dllexport) pid_t waitpid(pid_t pid, int* status, int options) {
|
||||
(void)options;
|
||||
|
||||
uint32_t handle = ProcTableFind(pid);
|
||||
if (!handle) { errno = ESRCH; return -1; }
|
||||
SYS_HANDLE handle = ProcTableFind(pid);
|
||||
if (handle == SYS_HANDLE_INVALID) { errno = ESRCH; return -1; }
|
||||
|
||||
SysWait(handle, SYS_WAIT_FLAG_NONE);
|
||||
|
||||
@@ -157,4 +198,259 @@ __declspec(dllexport) pid_t waitpid(pid_t pid, int* status, int options) {
|
||||
// Implements the exit operation.
|
||||
__declspec(dllexport) void exit(int status) {
|
||||
SysExitProcess(status);
|
||||
while (true) {}
|
||||
}
|
||||
|
||||
// Initializes one ordinary shared-attribute request.
|
||||
static void PosixProcessRequest(NTL_POSIX_REQUEST* request, uint32_t operation) {
|
||||
memset(request, 0, sizeof(*request));
|
||||
request->Size = sizeof(*request);
|
||||
request->Version = NTL_POSIX_PROTOCOL_VERSION;
|
||||
request->Operation = operation;
|
||||
request->Flags = NTL_POSIX_REQUEST_FLAG_NONE;
|
||||
}
|
||||
|
||||
// Executes one shared-attribute request and converts transport/server failure to errno.
|
||||
static int PosixProcessCall(NTL_POSIX_REQUEST* request, NTL_POSIX_REPLY* reply) {
|
||||
KSTATUS status = PosixRuntimeCallServer(request, reply);
|
||||
if (!KSUCCESS(status)) {
|
||||
errno = PosixStatusToErrno(status);
|
||||
return -1;
|
||||
}
|
||||
if (!KSUCCESS(reply->Status)) {
|
||||
errno = PosixStatusToErrno(reply->Status);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Executes one operation whose permission failures are POSIX EPERM rather than EACCES.
|
||||
static int PosixProcessCallPermission(NTL_POSIX_REQUEST* request, NTL_POSIX_REPLY* reply) {
|
||||
KSTATUS status = PosixRuntimeCallServer(request, reply);
|
||||
if (!KSUCCESS(status)) {
|
||||
errno = PosixStatusToErrno(status);
|
||||
return -1;
|
||||
}
|
||||
if (!KSUCCESS(reply->Status)) {
|
||||
errno = reply->Status == NTLSTATUS_ACCESS_DENIED ? EPERM : PosixStatusToErrno(reply->Status);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Returns the real POSIX user id owned by posixsrv.
|
||||
__declspec(dllexport) uid_t getuid(void) {
|
||||
NTL_POSIX_REPLY reply;
|
||||
if (!KSUCCESS(PosixRuntimeGetProcessAttributes(&reply))) return (uid_t)-1;
|
||||
return (uid_t)reply.UserId;
|
||||
}
|
||||
|
||||
// Returns the effective POSIX user id owned by posixsrv.
|
||||
__declspec(dllexport) uid_t geteuid(void) {
|
||||
NTL_POSIX_REPLY reply;
|
||||
if (!KSUCCESS(PosixRuntimeGetProcessAttributes(&reply))) return (uid_t)-1;
|
||||
return (uid_t)reply.EffectiveUserId;
|
||||
}
|
||||
|
||||
// Returns the real POSIX group id owned by posixsrv.
|
||||
__declspec(dllexport) gid_t getgid(void) {
|
||||
NTL_POSIX_REPLY reply;
|
||||
if (!KSUCCESS(PosixRuntimeGetProcessAttributes(&reply))) return (gid_t)-1;
|
||||
return (gid_t)reply.GroupId;
|
||||
}
|
||||
|
||||
// Returns the effective POSIX group id owned by posixsrv.
|
||||
__declspec(dllexport) gid_t getegid(void) {
|
||||
NTL_POSIX_REPLY reply;
|
||||
if (!KSUCCESS(PosixRuntimeGetProcessAttributes(&reply))) return (gid_t)-1;
|
||||
return (gid_t)reply.EffectiveGroupId;
|
||||
}
|
||||
|
||||
// Changes synthetic user credentials; uid zero is the only credential-changing authority.
|
||||
__declspec(dllexport) int setuid(uid_t uid) {
|
||||
NTL_POSIX_REQUEST request;
|
||||
NTL_POSIX_REPLY reply;
|
||||
PosixProcessRequest(&request, NTL_POSIX_OP_SET_UID);
|
||||
request.UserId = (uint32_t)uid;
|
||||
return PosixProcessCallPermission(&request, &reply);
|
||||
}
|
||||
|
||||
// Changes synthetic group credentials; effective uid zero is the authority.
|
||||
__declspec(dllexport) int setgid(gid_t gid) {
|
||||
NTL_POSIX_REQUEST request;
|
||||
NTL_POSIX_REPLY reply;
|
||||
PosixProcessRequest(&request, NTL_POSIX_OP_SET_GID);
|
||||
request.GroupId = (uint32_t)gid;
|
||||
return PosixProcessCallPermission(&request, &reply);
|
||||
}
|
||||
|
||||
// Returns the supplementary group list attached to the current POSIX process.
|
||||
__declspec(dllexport) int getgroups(int size, gid_t list[]) {
|
||||
if (size < 0 || (size != 0 && !list)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
NTL_POSIX_REPLY reply;
|
||||
KSTATUS status = PosixRuntimeGetProcessAttributes(&reply);
|
||||
if (!KSUCCESS(status)) {
|
||||
errno = PosixStatusToErrno(status);
|
||||
return -1;
|
||||
}
|
||||
if (reply.SupplementaryGroupCount > NTL_POSIX_SUPPLEMENTARY_GROUP_MAX) {
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
if (size == 0) return (int)reply.SupplementaryGroupCount;
|
||||
if ((uint32_t)size < reply.SupplementaryGroupCount) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
for (uint32_t i = 0; i < reply.SupplementaryGroupCount; ++i)
|
||||
list[i] = (gid_t)reply.SupplementaryGroups[i];
|
||||
return (int)reply.SupplementaryGroupCount;
|
||||
}
|
||||
|
||||
// Returns the login identity fixed when the POSIX process record is created.
|
||||
__declspec(dllexport) char* getlogin(void) {
|
||||
POSIX_THREAD_STATE* thread = PosixRuntimeThreadState();
|
||||
if (!thread) return (char*)0;
|
||||
NTL_POSIX_REPLY reply;
|
||||
KSTATUS status = PosixRuntimeGetProcessAttributes(&reply);
|
||||
if (!KSUCCESS(status)) {
|
||||
errno = PosixStatusToErrno(status);
|
||||
return (char*)0;
|
||||
}
|
||||
if (reply.NameLength == 0 || reply.NameLength > NTL_POSIX_IDENTITY_NAME_MAX ||
|
||||
reply.Name[reply.NameLength] != '\0') {
|
||||
errno = ENOENT;
|
||||
return (char*)0;
|
||||
}
|
||||
memcpy(thread->LoginName, reply.Name, reply.NameLength + 1u);
|
||||
return thread->LoginName;
|
||||
}
|
||||
|
||||
// Returns the current POSIX process-group id.
|
||||
__declspec(dllexport) pid_t getpgrp(void) {
|
||||
NTL_POSIX_REPLY reply;
|
||||
KSTATUS status = PosixRuntimeGetProcessAttributes(&reply);
|
||||
if (!KSUCCESS(status)) {
|
||||
errno = PosixStatusToErrno(status);
|
||||
return (pid_t)-1;
|
||||
}
|
||||
return (pid_t)reply.ProcessGroupId;
|
||||
}
|
||||
|
||||
// Changes process-group membership under posixsrv's parent/session invariants.
|
||||
__declspec(dllexport) int setpgid(pid_t pid, pid_t pgid) {
|
||||
if (pid < 0 || pgid < 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
NTL_POSIX_REQUEST request;
|
||||
NTL_POSIX_REPLY reply;
|
||||
PosixProcessRequest(&request, NTL_POSIX_OP_SET_PROCESS_GROUP);
|
||||
request.TargetPosixPid = (uint32_t)pid;
|
||||
request.ProcessGroupId = (uint32_t)pgid;
|
||||
return PosixProcessCallPermission(&request, &reply);
|
||||
}
|
||||
|
||||
// Creates a new POSIX session and process group when the caller is not a group leader.
|
||||
__declspec(dllexport) pid_t setsid(void) {
|
||||
NTL_POSIX_REQUEST request;
|
||||
NTL_POSIX_REPLY reply;
|
||||
PosixProcessRequest(&request, NTL_POSIX_OP_CREATE_SESSION);
|
||||
if (PosixProcessCallPermission(&request, &reply) != 0) return (pid_t)-1;
|
||||
return (pid_t)reply.SessionId;
|
||||
}
|
||||
|
||||
// Performs one passwd lookup and builds a thread-local POSIX result view.
|
||||
static struct passwd* PosixLookupUser(uint32_t lookupKind, uid_t uid, const char* name) {
|
||||
POSIX_THREAD_STATE* thread = PosixRuntimeThreadState();
|
||||
if (!thread) return (struct passwd*)0;
|
||||
NTL_POSIX_REQUEST request;
|
||||
NTL_POSIX_REPLY reply;
|
||||
PosixProcessRequest(&request, NTL_POSIX_OP_LOOKUP_USER);
|
||||
request.LookupKind = lookupKind;
|
||||
request.UserId = (uint32_t)uid;
|
||||
if (lookupKind == NTL_POSIX_LOOKUP_BY_NAME) {
|
||||
if (!name) { errno = EINVAL; return (struct passwd*)0; }
|
||||
size_t length = strlen(name);
|
||||
if (length == 0 || length > NTL_POSIX_IDENTITY_NAME_MAX) {
|
||||
errno = ENOENT;
|
||||
return (struct passwd*)0;
|
||||
}
|
||||
memcpy(request.Name, name, length + 1u);
|
||||
request.NameLength = (uint32_t)length;
|
||||
}
|
||||
if (PosixProcessCall(&request, &reply) != 0) return (struct passwd*)0;
|
||||
if (reply.NameLength == 0 || reply.NameLength > NTL_POSIX_IDENTITY_NAME_MAX ||
|
||||
reply.HomeLength > NTL_POSIX_IDENTITY_HOME_MAX ||
|
||||
reply.ShellLength > NTL_POSIX_IDENTITY_SHELL_MAX ||
|
||||
reply.Name[reply.NameLength] != '\0' || reply.Home[reply.HomeLength] != '\0' ||
|
||||
reply.Shell[reply.ShellLength] != '\0') {
|
||||
errno = EIO;
|
||||
return (struct passwd*)0;
|
||||
}
|
||||
memcpy(thread->PasswordName, reply.Name, reply.NameLength + 1u);
|
||||
memcpy(thread->PasswordHome, reply.Home, reply.HomeLength + 1u);
|
||||
memcpy(thread->PasswordShell, reply.Shell, reply.ShellLength + 1u);
|
||||
thread->PasswordResult.pw_name = thread->PasswordName;
|
||||
thread->PasswordResult.pw_uid = (uid_t)reply.UserId;
|
||||
thread->PasswordResult.pw_gid = (gid_t)reply.GroupId;
|
||||
thread->PasswordResult.pw_dir = thread->PasswordHome;
|
||||
thread->PasswordResult.pw_shell = thread->PasswordShell;
|
||||
return &thread->PasswordResult;
|
||||
}
|
||||
|
||||
// Looks up one synthesized passwd entry by name.
|
||||
__declspec(dllexport) struct passwd* getpwnam(const char* name) {
|
||||
return PosixLookupUser(NTL_POSIX_LOOKUP_BY_NAME, 0, name);
|
||||
}
|
||||
|
||||
// Looks up one synthesized passwd entry by uid.
|
||||
__declspec(dllexport) struct passwd* getpwuid(uid_t uid) {
|
||||
return PosixLookupUser(NTL_POSIX_LOOKUP_BY_ID, uid, (const char*)0);
|
||||
}
|
||||
|
||||
// Performs one group lookup and builds a thread-local POSIX result view.
|
||||
static struct group* PosixLookupGroup(uint32_t lookupKind, gid_t gid, const char* name) {
|
||||
POSIX_THREAD_STATE* thread = PosixRuntimeThreadState();
|
||||
if (!thread) return (struct group*)0;
|
||||
NTL_POSIX_REQUEST request;
|
||||
NTL_POSIX_REPLY reply;
|
||||
PosixProcessRequest(&request, NTL_POSIX_OP_LOOKUP_GROUP);
|
||||
request.LookupKind = lookupKind;
|
||||
request.GroupId = (uint32_t)gid;
|
||||
if (lookupKind == NTL_POSIX_LOOKUP_BY_NAME) {
|
||||
if (!name) { errno = EINVAL; return (struct group*)0; }
|
||||
size_t length = strlen(name);
|
||||
if (length == 0 || length > NTL_POSIX_IDENTITY_NAME_MAX) {
|
||||
errno = ENOENT;
|
||||
return (struct group*)0;
|
||||
}
|
||||
memcpy(request.Name, name, length + 1u);
|
||||
request.NameLength = (uint32_t)length;
|
||||
}
|
||||
if (PosixProcessCall(&request, &reply) != 0) return (struct group*)0;
|
||||
if (reply.NameLength == 0 || reply.NameLength > NTL_POSIX_IDENTITY_NAME_MAX ||
|
||||
reply.Name[reply.NameLength] != '\0') {
|
||||
errno = EIO;
|
||||
return (struct group*)0;
|
||||
}
|
||||
memcpy(thread->GroupName, reply.Name, reply.NameLength + 1u);
|
||||
thread->GroupMembers[0] = (char*)0;
|
||||
thread->GroupResult.gr_name = thread->GroupName;
|
||||
thread->GroupResult.gr_gid = (gid_t)reply.GroupId;
|
||||
thread->GroupResult.gr_mem = thread->GroupMembers;
|
||||
return &thread->GroupResult;
|
||||
}
|
||||
|
||||
// Looks up one synthesized group entry by name.
|
||||
__declspec(dllexport) struct group* getgrnam(const char* name) {
|
||||
return PosixLookupGroup(NTL_POSIX_LOOKUP_BY_NAME, 0, name);
|
||||
}
|
||||
|
||||
// Looks up one synthesized group entry by gid.
|
||||
__declspec(dllexport) struct group* getgrgid(gid_t gid) {
|
||||
return PosixLookupGroup(NTL_POSIX_LOOKUP_BY_ID, gid, (const char*)0);
|
||||
}
|
||||
@@ -0,0 +1,438 @@
|
||||
// POSIX personality process/thread runtime state backed by the native TEB extension slot.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ntlite/posix_service.h>
|
||||
#include <ntlite/process_loader.h>
|
||||
#include <ntlite/path.h>
|
||||
#include <ntlite/resource.h>
|
||||
#include <ntlite/status.h>
|
||||
#include "posix_internal.h"
|
||||
#include "posix_fd.h"
|
||||
|
||||
static POSIX_PROCESS_STATE* gPosixProcessState;
|
||||
static int gEmergencyErrno;
|
||||
|
||||
// Resolves the published POSIX service and opens one private client endpoint.
|
||||
static KSTATUS PosixRuntimeConnectServer(SYS_HANDLE* endpointOut) {
|
||||
if (!endpointOut) return NTLSTATUS_INVALID_PARAMETER;
|
||||
*endpointOut = SYS_HANDLE_INVALID;
|
||||
|
||||
SYS_HANDLE resource = SYS_HANDLE_INVALID;
|
||||
KSTATUS status = NtlResourceConnect(&resource);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
|
||||
SYS_HANDLE listener = SYS_HANDLE_INVALID;
|
||||
status = NtlResourceLookup(resource, SYS_SV_LITERAL(NTL_POSIX_SERVICE_PATH),
|
||||
SYS_RIGHT_QUERY | SYS_PORT_RIGHT_CONNECT, &listener);
|
||||
(void)NtlResourceClose(resource);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
|
||||
SYS_CONNECT_PORT_REQUEST connect;
|
||||
memset(&connect, 0, sizeof(connect));
|
||||
connect.Size = sizeof(connect);
|
||||
connect.ListenerHandle = listener;
|
||||
connect.Flags = SYS_PORT_CONNECT_FLAG_NONE;
|
||||
connect.EndpointHandleOut = endpointOut;
|
||||
status = SysConnectPort(&connect);
|
||||
(void)SysCloseHandle(listener);
|
||||
return status;
|
||||
}
|
||||
|
||||
// Calls one fixed-size posixsrv request over an explicitly supplied endpoint.
|
||||
static KSTATUS PosixRuntimeCallEndpoint(SYS_HANDLE endpoint,
|
||||
const NTL_POSIX_REQUEST* request,
|
||||
const SYS_PORT_HANDLE_TRANSFER* requestHandles,
|
||||
uint32_t requestHandleCount,
|
||||
SYS_HANDLE* replyHandlesOut,
|
||||
uint32_t replyHandleCapacity,
|
||||
uint32_t expectedReplyHandleCount,
|
||||
uint32_t* actualReplyHandleCountOut,
|
||||
NTL_POSIX_REPLY* replyOut) {
|
||||
if (endpoint == SYS_HANDLE_INVALID || !request || !replyOut ||
|
||||
(expectedReplyHandleCount != UINT32_MAX && expectedReplyHandleCount > replyHandleCapacity) ||
|
||||
(replyHandleCapacity != 0 && !replyHandlesOut))
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
memset(replyOut, 0, sizeof(*replyOut));
|
||||
if (replyHandlesOut) {
|
||||
for (uint32_t i = 0; i < replyHandleCapacity; ++i)
|
||||
replyHandlesOut[i] = SYS_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
SYS_PORT_MESSAGE_INFO info;
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.Size = sizeof(info);
|
||||
|
||||
SYS_CALL_PORT_REQUEST call;
|
||||
memset(&call, 0, sizeof(call));
|
||||
call.Size = sizeof(call);
|
||||
call.EndpointHandle = endpoint;
|
||||
call.Flags = SYS_PORT_FLAG_NONE;
|
||||
call.RequestPayload = request;
|
||||
call.RequestLength = sizeof(*request);
|
||||
call.RequestHandles = requestHandles;
|
||||
call.RequestHandleCount = requestHandleCount;
|
||||
call.ReplyPayload = replyOut;
|
||||
call.ReplyCapacity = sizeof(*replyOut);
|
||||
call.ReplyHandlesOut = replyHandlesOut;
|
||||
call.ReplyHandleCapacity = replyHandleCapacity;
|
||||
call.ReplyInfoOut = &info;
|
||||
call.TimeoutMilliseconds = SYS_PORT_TIMEOUT_INFINITE;
|
||||
KSTATUS status = SysCallPort(&call);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
|
||||
uint32_t expectedHandles = KSUCCESS(replyOut->Status) ? expectedReplyHandleCount : 0u;
|
||||
int handlesValid = expectedReplyHandleCount == UINT32_MAX ?
|
||||
info.HandleCount <= replyHandleCapacity : info.HandleCount == expectedHandles;
|
||||
if (info.Type != SYS_PORT_MESSAGE_REPLY || !handlesValid ||
|
||||
info.PayloadLength != sizeof(*replyOut) || replyOut->Size != sizeof(*replyOut) ||
|
||||
replyOut->Version != NTL_POSIX_PROTOCOL_VERSION ||
|
||||
replyOut->Operation != request->Operation ||
|
||||
replyOut->Flags != NTL_POSIX_REQUEST_FLAG_NONE) {
|
||||
if (replyHandlesOut) {
|
||||
uint32_t closeCount = info.HandleCount < replyHandleCapacity ?
|
||||
info.HandleCount : replyHandleCapacity;
|
||||
for (uint32_t i = 0; i < closeCount; ++i) {
|
||||
if (replyHandlesOut[i] != SYS_HANDLE_INVALID)
|
||||
(void)SysCloseHandle(replyHandlesOut[i]);
|
||||
replyHandlesOut[i] = SYS_HANDLE_INVALID;
|
||||
}
|
||||
}
|
||||
return NTLSTATUS_FAILURE;
|
||||
}
|
||||
if (actualReplyHandleCountOut) *actualReplyHandleCountOut = info.HandleCount;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Calls posixsrv while optionally transferring native capabilities.
|
||||
KSTATUS PosixRuntimeCallServerWithHandles(const NTL_POSIX_REQUEST* request,
|
||||
const SYS_PORT_HANDLE_TRANSFER* handles,
|
||||
uint32_t handleCount,
|
||||
NTL_POSIX_REPLY* replyOut) {
|
||||
POSIX_PROCESS_STATE* process = gPosixProcessState;
|
||||
if (!process || process->Magic != POSIX_PROCESS_STATE_MAGIC)
|
||||
return NTLSTATUS_NOT_FOUND;
|
||||
return PosixRuntimeCallEndpoint(process->ServerEndpoint, request, handles, handleCount,
|
||||
(SYS_HANDLE*)0, 0, 0, (uint32_t*)0, replyOut);
|
||||
}
|
||||
|
||||
// Calls posixsrv with independent request/reply capability transfer.
|
||||
KSTATUS PosixRuntimeCallServerExchange(const NTL_POSIX_REQUEST* request,
|
||||
const SYS_PORT_HANDLE_TRANSFER* requestHandles,
|
||||
uint32_t requestHandleCount,
|
||||
SYS_HANDLE* replyHandlesOut,
|
||||
uint32_t replyHandleCapacity,
|
||||
uint32_t expectedReplyHandleCount,
|
||||
NTL_POSIX_REPLY* replyOut) {
|
||||
POSIX_PROCESS_STATE* process = gPosixProcessState;
|
||||
if (!process || process->Magic != POSIX_PROCESS_STATE_MAGIC)
|
||||
return NTLSTATUS_NOT_FOUND;
|
||||
return PosixRuntimeCallEndpoint(process->ServerEndpoint, request,
|
||||
requestHandles, requestHandleCount,
|
||||
replyHandlesOut, replyHandleCapacity,
|
||||
expectedReplyHandleCount, (uint32_t*)0, replyOut);
|
||||
}
|
||||
|
||||
KSTATUS PosixRuntimeCallServerExchangeVariable(const NTL_POSIX_REQUEST* request,
|
||||
SYS_HANDLE* replyHandlesOut,
|
||||
uint32_t replyHandleCapacity,
|
||||
uint32_t* replyHandleCountOut,
|
||||
NTL_POSIX_REPLY* replyOut) {
|
||||
POSIX_PROCESS_STATE* process = gPosixProcessState;
|
||||
if (!process || process->Magic != POSIX_PROCESS_STATE_MAGIC || !replyHandleCountOut)
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
*replyHandleCountOut = 0;
|
||||
return PosixRuntimeCallEndpoint(process->ServerEndpoint, request,
|
||||
(const SYS_PORT_HANDLE_TRANSFER*)0, 0,
|
||||
replyHandlesOut, replyHandleCapacity, UINT32_MAX,
|
||||
replyHandleCountOut, replyOut);
|
||||
}
|
||||
|
||||
// Calls posixsrv over the registered process endpoint and validates one reply.
|
||||
KSTATUS PosixRuntimeCallServer(const NTL_POSIX_REQUEST* request, NTL_POSIX_REPLY* replyOut) {
|
||||
return PosixRuntimeCallServerWithHandles(request, (const SYS_PORT_HANDLE_TRANSFER*)0, 0,
|
||||
replyOut);
|
||||
}
|
||||
|
||||
// Queries the current server-owned POSIX process attributes.
|
||||
KSTATUS PosixRuntimeGetProcessAttributes(NTL_POSIX_REPLY* replyOut) {
|
||||
if (!replyOut) return NTLSTATUS_INVALID_PARAMETER;
|
||||
NTL_POSIX_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Version = NTL_POSIX_PROTOCOL_VERSION;
|
||||
request.Operation = NTL_POSIX_OP_GET_PROCESS_ATTRIBUTES;
|
||||
request.Flags = NTL_POSIX_REQUEST_FLAG_NONE;
|
||||
KSTATUS status = PosixRuntimeCallServer(&request, replyOut);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
return replyOut->Status;
|
||||
}
|
||||
|
||||
// Reads and validates optional POSIX bootstrap identity from generic userspace loader data.
|
||||
static KSTATUS PosixRuntimeReadBootstrap(NTL_POSIX_BOOTSTRAP_DATA* bootstrapOut) {
|
||||
if (!bootstrapOut) return NTLSTATUS_INVALID_PARAMETER;
|
||||
memset(bootstrapOut, 0, sizeof(*bootstrapOut));
|
||||
|
||||
size_t size = 0;
|
||||
KSTATUS status = NtlGetProcessStartupData(bootstrapOut, sizeof(*bootstrapOut), &size);
|
||||
if (status == NTLSTATUS_NOT_FOUND)
|
||||
return NTLSTATUS_SUCCESS;
|
||||
if (!KSUCCESS(status)) return status;
|
||||
if (size != sizeof(*bootstrapOut) || bootstrapOut->Magic != NTL_POSIX_BOOTSTRAP_MAGIC ||
|
||||
bootstrapOut->Version != NTL_POSIX_BOOTSTRAP_VERSION ||
|
||||
bootstrapOut->Size != sizeof(*bootstrapOut) || bootstrapOut->Reserved != 0)
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Registers the current native process with posixsrv and caches its stable logical identity.
|
||||
static KSTATUS PosixRuntimeRegisterProcess(POSIX_PROCESS_STATE* process,
|
||||
const NTL_POSIX_BOOTSTRAP_DATA* bootstrap) {
|
||||
if (!process || !bootstrap) return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
KSTATUS status = NTLSTATUS_SUCCESS;
|
||||
SYS_HANDLE endpoint = SYS_HANDLE_INVALID;
|
||||
status = PosixRuntimeConnectServer(&endpoint);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
|
||||
SYS_HANDLE selfProcess = SYS_HANDLE_INVALID;
|
||||
status = SysOpenProcess(SysGetCurrentPid(),
|
||||
SYS_RIGHT_QUERY | SYS_RIGHT_WAIT | SYS_RIGHT_TRANSFER,
|
||||
&selfProcess);
|
||||
if (!KSUCCESS(status)) {
|
||||
(void)SysDisconnectPort(endpoint);
|
||||
(void)SysCloseHandle(endpoint);
|
||||
return status;
|
||||
}
|
||||
|
||||
NTL_POSIX_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Version = NTL_POSIX_PROTOCOL_VERSION;
|
||||
request.Operation = NTL_POSIX_OP_REGISTER_PROCESS;
|
||||
request.Flags = NTL_POSIX_REQUEST_FLAG_NONE;
|
||||
request.TransactionKind = NTL_POSIX_TRANSACTION_NONE;
|
||||
request.BootstrapToken = bootstrap->Token;
|
||||
request.BootstrapPosixPid = bootstrap->PosixPid;
|
||||
request.BootstrapGeneration = bootstrap->Generation;
|
||||
|
||||
size_t currentDirectorySize = 0;
|
||||
status = NtlGetCurrentDirectory(request.Path, sizeof(request.Path), ¤tDirectorySize);
|
||||
if (!KSUCCESS(status) || currentDirectorySize == 0 || currentDirectorySize > sizeof(request.Path)) {
|
||||
(void)SysDisconnectPort(endpoint);
|
||||
(void)SysCloseHandle(endpoint);
|
||||
(void)SysCloseHandle(selfProcess);
|
||||
return KSUCCESS(status) ? NTLSTATUS_FAILURE : status;
|
||||
}
|
||||
request.PathLength = (uint32_t)strlen(request.Path);
|
||||
|
||||
SYS_PORT_HANDLE_TRANSFER transfer;
|
||||
memset(&transfer, 0, sizeof(transfer));
|
||||
transfer.Handle = selfProcess;
|
||||
transfer.DesiredRights = SYS_RIGHT_QUERY | SYS_RIGHT_WAIT;
|
||||
transfer.Flags = SYS_PORT_TRANSFER_FLAG_NONE;
|
||||
|
||||
NTL_POSIX_REPLY reply;
|
||||
status = PosixRuntimeCallEndpoint(endpoint, &request, &transfer, 1u,
|
||||
(SYS_HANDLE*)0, 0, 0, (uint32_t*)0, &reply);
|
||||
(void)SysCloseHandle(selfProcess);
|
||||
if (!KSUCCESS(status)) {
|
||||
(void)SysDisconnectPort(endpoint);
|
||||
(void)SysCloseHandle(endpoint);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (!KSUCCESS(reply.Status)) {
|
||||
(void)SysDisconnectPort(endpoint);
|
||||
(void)SysCloseHandle(endpoint);
|
||||
return reply.Status;
|
||||
}
|
||||
if (reply.ClientProcessId != SysGetCurrentPid() || reply.PosixPid == 0 ||
|
||||
reply.PosixPid > 0x7FFFFFFFu || reply.NativeGeneration == 0 ||
|
||||
reply.ProcessState != NTL_POSIX_PROCESS_STATE_RUNNING) {
|
||||
(void)SysDisconnectPort(endpoint);
|
||||
(void)SysCloseHandle(endpoint);
|
||||
return NTLSTATUS_FAILURE;
|
||||
}
|
||||
|
||||
process->ServerEndpoint = endpoint;
|
||||
process->DefaultIdentity.PosixPid = reply.PosixPid;
|
||||
process->DefaultIdentity.Generation = reply.NativeGeneration;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Initializes process-local POSIX state, registers stable identity, and attaches the initial thread.
|
||||
uint32_t PosixRuntimeInitializeProcess(void) {
|
||||
if (gPosixProcessState)
|
||||
return PosixRuntimeAttachThread();
|
||||
|
||||
SYS_PEB* peb = SysGetPeb();
|
||||
if (!peb || peb->Magic != SYS_PEB_MAGIC || peb->Version != SYS_ENV_VERSION)
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
POSIX_PROCESS_STATE* process = (POSIX_PROCESS_STATE*)calloc(1, sizeof(*process));
|
||||
if (!process)
|
||||
return NTLSTATUS_NO_MEMORY;
|
||||
|
||||
process->Magic = POSIX_PROCESS_STATE_MAGIC;
|
||||
process->Peb = peb;
|
||||
process->ServerEndpoint = SYS_HANDLE_INVALID;
|
||||
process->FdLock = SYS_HANDLE_INVALID;
|
||||
gPosixProcessState = process;
|
||||
|
||||
NTL_POSIX_BOOTSTRAP_DATA bootstrap;
|
||||
uint32_t status = PosixRuntimeReadBootstrap(&bootstrap);
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
gPosixProcessState = (POSIX_PROCESS_STATE*)0;
|
||||
free(process);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = PosixRuntimeRegisterProcess(process, &bootstrap);
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
gPosixProcessState = (POSIX_PROCESS_STATE*)0;
|
||||
free(process);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = PosixFdInitializeProcess(process, bootstrap.FdInheritanceToken);
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
(void)SysDisconnectPort(process->ServerEndpoint);
|
||||
(void)SysCloseHandle(process->ServerEndpoint);
|
||||
process->ServerEndpoint = SYS_HANDLE_INVALID;
|
||||
gPosixProcessState = (POSIX_PROCESS_STATE*)0;
|
||||
free(process);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = PosixRuntimeAttachThread();
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
PosixFdDestroyProcess(process);
|
||||
(void)SysDisconnectPort(process->ServerEndpoint);
|
||||
(void)SysCloseHandle(process->ServerEndpoint);
|
||||
process->ServerEndpoint = SYS_HANDLE_INVALID;
|
||||
gPosixProcessState = (POSIX_PROCESS_STATE*)0;
|
||||
free(process);
|
||||
return status;
|
||||
}
|
||||
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Returns the POSIX state for the current native process after startup.
|
||||
POSIX_PROCESS_STATE* PosixRuntimeProcessState(void) {
|
||||
POSIX_PROCESS_STATE* process = gPosixProcessState;
|
||||
if (!process || process->Magic != POSIX_PROCESS_STATE_MAGIC)
|
||||
return (POSIX_PROCESS_STATE*)0;
|
||||
return process;
|
||||
}
|
||||
|
||||
// Attaches the native thread to the process's default logical POSIX identity.
|
||||
uint32_t PosixRuntimeAttachThread(void) {
|
||||
SYS_TEB* teb = SysGetTeb();
|
||||
POSIX_PROCESS_STATE* process = PosixRuntimeProcessState();
|
||||
if (!teb || teb->Magic != SYS_TEB_MAGIC || !process)
|
||||
return NTLSTATUS_INVALID_PARAMETER;
|
||||
|
||||
if (teb->SubsystemData) {
|
||||
POSIX_THREAD_STATE* existing = (POSIX_THREAD_STATE*)teb->SubsystemData;
|
||||
return existing->Magic == POSIX_THREAD_STATE_MAGIC &&
|
||||
existing->NativeProcess == process && existing->LogicalProcess
|
||||
? NTLSTATUS_SUCCESS
|
||||
: NTLSTATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
POSIX_THREAD_STATE* thread = (POSIX_THREAD_STATE*)calloc(1, sizeof(*thread));
|
||||
if (!thread)
|
||||
return NTLSTATUS_NO_MEMORY;
|
||||
|
||||
thread->Magic = POSIX_THREAD_STATE_MAGIC;
|
||||
thread->NativeProcess = process;
|
||||
thread->LogicalProcess = &process->DefaultIdentity;
|
||||
teb->SubsystemData = thread;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Returns the current thread state, attaching lazily when necessary.
|
||||
POSIX_THREAD_STATE* PosixRuntimeThreadState(void) {
|
||||
if (!PosixRuntimeProcessState()) {
|
||||
if (PosixRuntimeInitializeProcess() != NTLSTATUS_SUCCESS)
|
||||
return (POSIX_THREAD_STATE*)0;
|
||||
}
|
||||
|
||||
SYS_TEB* teb = SysGetTeb();
|
||||
if (!teb || teb->Magic != SYS_TEB_MAGIC)
|
||||
return (POSIX_THREAD_STATE*)0;
|
||||
|
||||
if (!teb->SubsystemData && PosixRuntimeAttachThread() != NTLSTATUS_SUCCESS)
|
||||
return (POSIX_THREAD_STATE*)0;
|
||||
|
||||
POSIX_THREAD_STATE* thread = (POSIX_THREAD_STATE*)teb->SubsystemData;
|
||||
if (!thread || thread->Magic != POSIX_THREAD_STATE_MAGIC ||
|
||||
thread->NativeProcess != PosixRuntimeProcessState() || !thread->LogicalProcess)
|
||||
return (POSIX_THREAD_STATE*)0;
|
||||
return thread;
|
||||
}
|
||||
|
||||
// Releases POSIX state owned by the current native TEB.
|
||||
void PosixRuntimeDetachThread(void) {
|
||||
SYS_TEB* teb = SysGetTeb();
|
||||
if (!teb || teb->Magic != SYS_TEB_MAGIC || !teb->SubsystemData)
|
||||
return;
|
||||
|
||||
POSIX_THREAD_STATE* thread = (POSIX_THREAD_STATE*)teb->SubsystemData;
|
||||
if (thread->Magic != POSIX_THREAD_STATE_MAGIC ||
|
||||
thread->NativeProcess != PosixRuntimeProcessState())
|
||||
return;
|
||||
|
||||
teb->SubsystemData = (void*)0;
|
||||
thread->Magic = 0;
|
||||
free(thread);
|
||||
}
|
||||
|
||||
// Returns the lvalue backing the current thread's errno value.
|
||||
NTL_POSIX_API int* __ntl_posix_errno_location(void) {
|
||||
POSIX_THREAD_STATE* thread = PosixRuntimeThreadState();
|
||||
if (!thread)
|
||||
return &gEmergencyErrno;
|
||||
return &thread->ErrnoValue;
|
||||
}
|
||||
|
||||
// Clears the current thread's dynamic-loader error state.
|
||||
void PosixRuntimeClearDlError(void) {
|
||||
POSIX_THREAD_STATE* thread = PosixRuntimeThreadState();
|
||||
if (!thread)
|
||||
return;
|
||||
thread->DlError[0] = '\0';
|
||||
thread->DlErrorPending = 0;
|
||||
}
|
||||
|
||||
// Stores one dynamic-loader error in current-thread state.
|
||||
void PosixRuntimeSetDlError(const char* message) {
|
||||
POSIX_THREAD_STATE* thread = PosixRuntimeThreadState();
|
||||
if (!thread)
|
||||
return;
|
||||
if (!message)
|
||||
message = "dynamic loader error";
|
||||
strncpy(thread->DlError, message, sizeof(thread->DlError) - 1u);
|
||||
thread->DlError[sizeof(thread->DlError) - 1u] = '\0';
|
||||
thread->DlErrorPending = 1;
|
||||
}
|
||||
|
||||
// Returns and consumes the current thread's dynamic-loader error.
|
||||
char* PosixRuntimeTakeDlError(void) {
|
||||
POSIX_THREAD_STATE* thread = PosixRuntimeThreadState();
|
||||
if (!thread || !thread->DlErrorPending || !thread->DlError[0])
|
||||
return (char*)0;
|
||||
thread->DlErrorPending = 0;
|
||||
return thread->DlError;
|
||||
}
|
||||
|
||||
// Initializes all POSIX process state required before application main.
|
||||
NTL_POSIX_API uint32_t __ntl_posix_process_start(void) {
|
||||
uint32_t status = PosixRuntimeInitializeProcess();
|
||||
if (status != NTLSTATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <ntlite/syscall.h>
|
||||
#include "posix.h"
|
||||
#include "posix_internal.h"
|
||||
#include "posix_fd.h"
|
||||
|
||||
// Implements the bswap16 operation.
|
||||
@@ -284,61 +284,84 @@ static void SysToSockAddr(const SYS_SOCKET_ADDRESS* in, struct sockaddr* addr, s
|
||||
}
|
||||
}
|
||||
|
||||
// Implements the socket Fd Get operation.
|
||||
static FD_ENTRY* SocketFdGet(int fd) {
|
||||
FD_ENTRY* e = FdGet(SysGetCurrentPid(), fd);
|
||||
if (!e) return (FD_ENTRY*)0;
|
||||
if (e->Type != FD_SOCKET) { errno = ENOTSOCK; return (FD_ENTRY*)0; }
|
||||
return e;
|
||||
// Acquires one socket open-description reference.
|
||||
static POSIX_OPEN_DESCRIPTION* SocketFdAcquire(int fd) {
|
||||
POSIX_OPEN_DESCRIPTION* description = PosixFdAcquire(fd);
|
||||
if (!description)
|
||||
return (POSIX_OPEN_DESCRIPTION*)0;
|
||||
if (description->Type != PosixFdSocket) {
|
||||
PosixFdRelease(description);
|
||||
errno = ENOTSOCK;
|
||||
return (POSIX_OPEN_DESCRIPTION*)0;
|
||||
}
|
||||
return description;
|
||||
}
|
||||
|
||||
// Implements the socket operation.
|
||||
// Creates a socket and installs it as a process-local descriptor.
|
||||
__declspec(dllexport) int socket(int domain, int type, int protocol) {
|
||||
uint32_t kh = 0;
|
||||
uint32_t s = SysCreateSocket((uint32_t)domain, (uint32_t)type, (uint32_t)protocol, &kh);
|
||||
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
|
||||
|
||||
int fd = FdAlloc(SysGetCurrentPid(), FD_SOCKET, kh);
|
||||
if (fd < 0) {
|
||||
SysCloseHandle(kh);
|
||||
uint32_t kh = SYS_HANDLE_INVALID;
|
||||
uint32_t status = SysCreateSocket((uint32_t)domain, (uint32_t)type, (uint32_t)protocol, &kh);
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
errno = PosixStatusToErrno(status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fd = PosixFdCreate(PosixFdSocket, kh, O_RDWR);
|
||||
if (fd < 0)
|
||||
SysCloseHandle(kh);
|
||||
return fd;
|
||||
}
|
||||
|
||||
// Implements the bind operation.
|
||||
// Binds one socket descriptor to a local address.
|
||||
__declspec(dllexport) int bind(int fd, const struct sockaddr* addr, socklen_t addrlen) {
|
||||
FD_ENTRY* e = SocketFdGet(fd);
|
||||
if (!e) return -1;
|
||||
SYS_SOCKET_ADDRESS a;
|
||||
if (SockAddrToSys(addr, addrlen, &a) != 0) return -1;
|
||||
uint32_t s = SysBindSocket(e->KHandle, &a, sizeof(a));
|
||||
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
|
||||
POSIX_OPEN_DESCRIPTION* description = SocketFdAcquire(fd);
|
||||
if (!description) return -1;
|
||||
SYS_SOCKET_ADDRESS address;
|
||||
if (SockAddrToSys(addr, addrlen, &address) != 0) {
|
||||
PosixFdRelease(description);
|
||||
return -1;
|
||||
}
|
||||
uint32_t status = SysBindSocket(description->KHandle, &address, sizeof(address));
|
||||
PosixFdRelease(description);
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
errno = PosixStatusToErrno(status);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Implements the listen operation.
|
||||
// Places one socket into listening state.
|
||||
__declspec(dllexport) int listen(int fd, int backlog) {
|
||||
FD_ENTRY* e = SocketFdGet(fd);
|
||||
if (!e) return -1;
|
||||
uint32_t s = SysListenSocket(e->KHandle, backlog < 0 ? 0u : (uint32_t)backlog);
|
||||
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
|
||||
POSIX_OPEN_DESCRIPTION* description = SocketFdAcquire(fd);
|
||||
if (!description) return -1;
|
||||
uint32_t status = SysListenSocket(description->KHandle, backlog < 0 ? 0u : (uint32_t)backlog);
|
||||
PosixFdRelease(description);
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
errno = PosixStatusToErrno(status);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Implements the accept operation.
|
||||
// Accepts one socket and installs the accepted endpoint as a new descriptor.
|
||||
__declspec(dllexport) int accept(int fd, struct sockaddr* addr, socklen_t* addrlen) {
|
||||
FD_ENTRY* e = SocketFdGet(fd);
|
||||
if (!e) return -1;
|
||||
POSIX_OPEN_DESCRIPTION* description = SocketFdAcquire(fd);
|
||||
if (!description) return -1;
|
||||
|
||||
SYS_SOCKET_ADDRESS remote;
|
||||
size_t remoteSize = sizeof(remote);
|
||||
uint32_t kh = 0;
|
||||
uint32_t s = SysAcceptSocket(e->KHandle, addr ? &remote : (SYS_SOCKET_ADDRESS*)0,
|
||||
addr ? &remoteSize : (size_t*)0, &kh);
|
||||
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
|
||||
uint32_t kh = SYS_HANDLE_INVALID;
|
||||
uint32_t status = SysAcceptSocket(description->KHandle,
|
||||
addr ? &remote : (SYS_SOCKET_ADDRESS*)0,
|
||||
addr ? &remoteSize : (size_t*)0,
|
||||
&kh);
|
||||
PosixFdRelease(description);
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
errno = PosixStatusToErrno(status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int outfd = FdAlloc(SysGetCurrentPid(), FD_SOCKET, kh);
|
||||
int outfd = PosixFdCreate(PosixFdSocket, kh, O_RDWR);
|
||||
if (outfd < 0) {
|
||||
SysCloseHandle(kh);
|
||||
return -1;
|
||||
@@ -347,113 +370,145 @@ __declspec(dllexport) int accept(int fd, struct sockaddr* addr, socklen_t* addrl
|
||||
return outfd;
|
||||
}
|
||||
|
||||
// Implements the connect operation.
|
||||
// Connects one socket descriptor to a remote address.
|
||||
__declspec(dllexport) int connect(int fd, const struct sockaddr* addr, socklen_t addrlen) {
|
||||
FD_ENTRY* e = SocketFdGet(fd);
|
||||
if (!e) return -1;
|
||||
SYS_SOCKET_ADDRESS a;
|
||||
if (SockAddrToSys(addr, addrlen, &a) != 0) return -1;
|
||||
uint32_t s = SysConnectSocket(e->KHandle, &a, sizeof(a));
|
||||
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
|
||||
POSIX_OPEN_DESCRIPTION* description = SocketFdAcquire(fd);
|
||||
if (!description) return -1;
|
||||
SYS_SOCKET_ADDRESS address;
|
||||
if (SockAddrToSys(addr, addrlen, &address) != 0) {
|
||||
PosixFdRelease(description);
|
||||
return -1;
|
||||
}
|
||||
uint32_t status = SysConnectSocket(description->KHandle, &address, sizeof(address));
|
||||
PosixFdRelease(description);
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
errno = PosixStatusToErrno(status);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Implements the send operation.
|
||||
// Sends bytes through one socket descriptor.
|
||||
__declspec(dllexport) ssize_t send(int fd, const void* buf, size_t len, int flags) {
|
||||
FD_ENTRY* e = SocketFdGet(fd);
|
||||
if (!e) return -1;
|
||||
POSIX_OPEN_DESCRIPTION* description = SocketFdAcquire(fd);
|
||||
if (!description) return -1;
|
||||
size_t sent = 0;
|
||||
SYS_SOCKET_SEND_REQUEST request = {
|
||||
sizeof(SYS_SOCKET_SEND_REQUEST), e->KHandle, (uint32_t)flags,
|
||||
sizeof(SYS_SOCKET_SEND_REQUEST), description->KHandle, (uint32_t)flags,
|
||||
buf, len, &sent
|
||||
};
|
||||
uint32_t s = SysSendSocket(&request);
|
||||
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
|
||||
uint32_t status = SysSendSocket(&request);
|
||||
PosixFdRelease(description);
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
errno = PosixStatusToErrno(status);
|
||||
return -1;
|
||||
}
|
||||
return (ssize_t)sent;
|
||||
}
|
||||
|
||||
// Implements the recv operation.
|
||||
// Receives bytes through one socket descriptor.
|
||||
__declspec(dllexport) ssize_t recv(int fd, void* buf, size_t len, int flags) {
|
||||
FD_ENTRY* e = SocketFdGet(fd);
|
||||
if (!e) return -1;
|
||||
POSIX_OPEN_DESCRIPTION* description = SocketFdAcquire(fd);
|
||||
if (!description) return -1;
|
||||
size_t got = 0;
|
||||
SYS_SOCKET_RECV_REQUEST request = {
|
||||
sizeof(SYS_SOCKET_RECV_REQUEST), e->KHandle, (uint32_t)flags,
|
||||
sizeof(SYS_SOCKET_RECV_REQUEST), description->KHandle, (uint32_t)flags,
|
||||
buf, len, &got
|
||||
};
|
||||
uint32_t s = SysRecvSocket(&request);
|
||||
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
|
||||
uint32_t status = SysRecvSocket(&request);
|
||||
PosixFdRelease(description);
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
errno = PosixStatusToErrno(status);
|
||||
return -1;
|
||||
}
|
||||
return (ssize_t)got;
|
||||
}
|
||||
|
||||
// Sends one datagram to a remote address.
|
||||
__declspec(dllexport) ssize_t sendto(int fd, const void* buf, size_t len, int flags,
|
||||
const struct sockaddr* dest, socklen_t destlen) {
|
||||
FD_ENTRY* e = SocketFdGet(fd);
|
||||
if (!e) return -1;
|
||||
POSIX_OPEN_DESCRIPTION* description = SocketFdAcquire(fd);
|
||||
if (!description) return -1;
|
||||
SYS_SOCKET_ADDRESS remote;
|
||||
if (SockAddrToSys(dest, destlen, &remote) != 0) return -1;
|
||||
if (SockAddrToSys(dest, destlen, &remote) != 0) {
|
||||
PosixFdRelease(description);
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t sent = 0;
|
||||
SYS_SOCKET_SEND_TO_REQUEST req;
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.Size = sizeof(req);
|
||||
req.Buffer = buf;
|
||||
req.Length = len;
|
||||
req.Flags = (uint32_t)flags;
|
||||
req.RemoteAddress = &remote;
|
||||
req.RemoteAddressSize = sizeof(remote);
|
||||
req.SentOut = &sent;
|
||||
SYS_SOCKET_SEND_TO_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Buffer = buf;
|
||||
request.Length = len;
|
||||
request.Flags = (uint32_t)flags;
|
||||
request.RemoteAddress = &remote;
|
||||
request.RemoteAddressSize = sizeof(remote);
|
||||
request.SentOut = &sent;
|
||||
|
||||
uint32_t s = SysSendToSocket(e->KHandle, &req);
|
||||
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
|
||||
uint32_t status = SysSendToSocket(description->KHandle, &request);
|
||||
PosixFdRelease(description);
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
errno = PosixStatusToErrno(status);
|
||||
return -1;
|
||||
}
|
||||
return (ssize_t)sent;
|
||||
}
|
||||
|
||||
// Receives one datagram and optionally reports its source address.
|
||||
__declspec(dllexport) ssize_t recvfrom(int fd, void* buf, size_t len, int flags,
|
||||
struct sockaddr* src, socklen_t* srclen) {
|
||||
FD_ENTRY* e = SocketFdGet(fd);
|
||||
if (!e) return -1;
|
||||
POSIX_OPEN_DESCRIPTION* description = SocketFdAcquire(fd);
|
||||
if (!description) return -1;
|
||||
|
||||
SYS_SOCKET_ADDRESS remote;
|
||||
size_t remoteSize = sizeof(remote);
|
||||
size_t got = 0;
|
||||
SYS_SOCKET_RECV_FROM_REQUEST req;
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.Size = sizeof(req);
|
||||
req.Buffer = buf;
|
||||
req.Length = len;
|
||||
req.Flags = (uint32_t)flags;
|
||||
req.RemoteAddressOut = src ? &remote : (SYS_SOCKET_ADDRESS*)0;
|
||||
req.RemoteAddressSizeInOut = src ? &remoteSize : (size_t*)0;
|
||||
req.ReceivedOut = &got;
|
||||
SYS_SOCKET_RECV_FROM_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Buffer = buf;
|
||||
request.Length = len;
|
||||
request.Flags = (uint32_t)flags;
|
||||
request.RemoteAddressOut = src ? &remote : (SYS_SOCKET_ADDRESS*)0;
|
||||
request.RemoteAddressSizeInOut = src ? &remoteSize : (size_t*)0;
|
||||
request.ReceivedOut = &got;
|
||||
|
||||
uint32_t s = SysRecvFromSocket(e->KHandle, &req);
|
||||
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
|
||||
uint32_t status = SysRecvFromSocket(description->KHandle, &request);
|
||||
PosixFdRelease(description);
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
errno = PosixStatusToErrno(status);
|
||||
return -1;
|
||||
}
|
||||
if (src) SysToSockAddr(&remote, src, srclen);
|
||||
return (ssize_t)got;
|
||||
}
|
||||
|
||||
// Implements the shutdown operation.
|
||||
// Shuts down one or both directions of a socket.
|
||||
__declspec(dllexport) int shutdown(int fd, int how) {
|
||||
FD_ENTRY* e = SocketFdGet(fd);
|
||||
if (!e) return -1;
|
||||
uint32_t s = SysShutdownSocket(e->KHandle, (uint32_t)how);
|
||||
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
|
||||
POSIX_OPEN_DESCRIPTION* description = SocketFdAcquire(fd);
|
||||
if (!description) return -1;
|
||||
uint32_t status = SysShutdownSocket(description->KHandle, (uint32_t)how);
|
||||
PosixFdRelease(description);
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
errno = PosixStatusToErrno(status);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Implements the timeval To Ms operation.
|
||||
// Converts one timeval into a bounded millisecond count.
|
||||
static uint32_t TimevalToMs(const struct timeval* tv) {
|
||||
if (!tv) return 0;
|
||||
uint64_t ms = (uint64_t)tv->tv_sec * 1000u + (uint64_t)(tv->tv_usec / 1000);
|
||||
return ms > 0xFFFFFFFFu ? 0xFFFFFFFFu : (uint32_t)ms;
|
||||
}
|
||||
|
||||
// Implements the setsockopt operation.
|
||||
// Sets one supported socket option.
|
||||
__declspec(dllexport) int setsockopt(int fd, int level, int optname, const void* optval, socklen_t optlen) {
|
||||
if (level != SOL_SOCKET || !optval) { errno = EINVAL; return -1; }
|
||||
FD_ENTRY* e = SocketFdGet(fd);
|
||||
if (!e) return -1;
|
||||
POSIX_OPEN_DESCRIPTION* description = SocketFdAcquire(fd);
|
||||
if (!description) return -1;
|
||||
|
||||
uint32_t option = 0;
|
||||
uint32_t value = 0;
|
||||
@@ -461,50 +516,80 @@ __declspec(dllexport) int setsockopt(int fd, int level, int optname, const void*
|
||||
option = (optname == SO_RCVTIMEO) ? SYS_SOCKET_OPT_RECV_TIMEOUT_MS : SYS_SOCKET_OPT_SEND_TIMEOUT_MS;
|
||||
if (optlen == sizeof(struct timeval)) value = TimevalToMs((const struct timeval*)optval);
|
||||
else if (optlen == sizeof(uint32_t)) memcpy(&value, optval, sizeof(value));
|
||||
else { errno = EINVAL; return -1; }
|
||||
else {
|
||||
PosixFdRelease(description);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
} else if (optname == SO_NONBLOCK) {
|
||||
option = SYS_SOCKET_OPT_NONBLOCKING;
|
||||
if (optlen < sizeof(int)) { errno = EINVAL; return -1; }
|
||||
if (optlen < sizeof(int)) {
|
||||
PosixFdRelease(description);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
value = (*(const int*)optval) ? 1u : 0u;
|
||||
} else {
|
||||
PosixFdRelease(description);
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
SYS_SOCKET_OPTION_REQUEST req;
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.Size = sizeof(req);
|
||||
req.Option = option;
|
||||
req.Value = &value;
|
||||
req.ValueSize = sizeof(value);
|
||||
uint32_t s = SysSetSocketOption(e->KHandle, &req);
|
||||
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
|
||||
if (optname == SO_NONBLOCK) {
|
||||
int flags = PosixFdGetStatusFlags(description);
|
||||
if (value) flags |= O_NONBLOCK;
|
||||
else flags &= ~O_NONBLOCK;
|
||||
int result = PosixFdSetStatusFlags(description, flags);
|
||||
PosixFdRelease(description);
|
||||
return result;
|
||||
}
|
||||
|
||||
SYS_SOCKET_OPTION_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Option = option;
|
||||
request.Value = &value;
|
||||
request.ValueSize = sizeof(value);
|
||||
uint32_t status = SysSetSocketOption(description->KHandle, &request);
|
||||
PosixFdRelease(description);
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
errno = PosixStatusToErrno(status);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Implements the getsockopt operation.
|
||||
// Queries one supported socket option.
|
||||
__declspec(dllexport) int getsockopt(int fd, int level, int optname, void* optval, socklen_t* optlen) {
|
||||
if (level != SOL_SOCKET || !optval || !optlen) { errno = EINVAL; return -1; }
|
||||
FD_ENTRY* e = SocketFdGet(fd);
|
||||
if (!e) return -1;
|
||||
POSIX_OPEN_DESCRIPTION* description = SocketFdAcquire(fd);
|
||||
if (!description) return -1;
|
||||
|
||||
uint32_t option = 0;
|
||||
if (optname == SO_RCVTIMEO) option = SYS_SOCKET_OPT_RECV_TIMEOUT_MS;
|
||||
else if (optname == SO_SNDTIMEO) option = SYS_SOCKET_OPT_SEND_TIMEOUT_MS;
|
||||
else if (optname == SO_NONBLOCK) option = SYS_SOCKET_OPT_NONBLOCKING;
|
||||
else { errno = ENOSYS; return -1; }
|
||||
else {
|
||||
PosixFdRelease(description);
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t value = 0;
|
||||
size_t actual = sizeof(value);
|
||||
SYS_SOCKET_OPTION_REQUEST req;
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.Size = sizeof(req);
|
||||
req.Option = option;
|
||||
req.Value = &value;
|
||||
req.ValueSize = sizeof(value);
|
||||
req.ActualSizeOut = &actual;
|
||||
uint32_t s = SysGetSocketOption(e->KHandle, &req);
|
||||
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
|
||||
SYS_SOCKET_OPTION_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Option = option;
|
||||
request.Value = &value;
|
||||
request.ValueSize = sizeof(value);
|
||||
request.ActualSizeOut = &actual;
|
||||
uint32_t status = SysGetSocketOption(description->KHandle, &request);
|
||||
PosixFdRelease(description);
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
errno = PosixStatusToErrno(status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) && *optlen >= sizeof(struct timeval)) {
|
||||
struct timeval* tv = (struct timeval*)optval;
|
||||
@@ -521,24 +606,35 @@ __declspec(dllexport) int getsockopt(int fd, int level, int optname, void* optva
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Polls the requested operation.
|
||||
// Polls socket and pipe descriptors while holding stable open-description references.
|
||||
__declspec(dllexport) int poll(struct pollfd* fds, nfds_t nfds, int timeout) {
|
||||
if (!fds || nfds == 0 || nfds > 64) { errno = EINVAL; return -1; }
|
||||
if (!fds || nfds == 0 || nfds > POSIX_FD_MAX) { errno = EINVAL; return -1; }
|
||||
|
||||
SYS_POLLFD* kfds = (SYS_POLLFD*)malloc(sizeof(SYS_POLLFD) * nfds);
|
||||
if (!kfds) { errno = ENOMEM; return -1; }
|
||||
SYS_POLLFD* kfds = (SYS_POLLFD*)calloc(nfds, sizeof(SYS_POLLFD));
|
||||
POSIX_OPEN_DESCRIPTION** descriptions =
|
||||
(POSIX_OPEN_DESCRIPTION**)calloc(nfds, sizeof(POSIX_OPEN_DESCRIPTION*));
|
||||
if (!kfds || !descriptions) {
|
||||
free(kfds);
|
||||
free(descriptions);
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (nfds_t i = 0; i < nfds; i++) {
|
||||
kfds[i].Handle = 0;
|
||||
kfds[i].Events = 0;
|
||||
kfds[i].ReturnedEvents = 0;
|
||||
|
||||
fds[i].revents = 0;
|
||||
FD_ENTRY* e = FdGet(SysGetCurrentPid(), fds[i].fd);
|
||||
if (!e || e->Type != FD_SOCKET) {
|
||||
descriptions[i] = PosixFdAcquire(fds[i].fd);
|
||||
if (!descriptions[i] ||
|
||||
(descriptions[i]->Type != PosixFdSocket &&
|
||||
descriptions[i]->Type != PosixFdPipeRead &&
|
||||
descriptions[i]->Type != PosixFdPipeWrite)) {
|
||||
if (descriptions[i]) {
|
||||
PosixFdRelease(descriptions[i]);
|
||||
descriptions[i] = (POSIX_OPEN_DESCRIPTION*)0;
|
||||
}
|
||||
fds[i].revents = POLLNVAL;
|
||||
continue;
|
||||
}
|
||||
kfds[i].Handle = e->KHandle;
|
||||
kfds[i].Handle = descriptions[i]->KHandle;
|
||||
if (fds[i].events & POLLIN) kfds[i].Events |= SYS_POLL_READ;
|
||||
if (fds[i].events & POLLOUT) kfds[i].Events |= SYS_POLL_WRITE;
|
||||
if (fds[i].events & POLLERR) kfds[i].Events |= SYS_POLL_ERROR;
|
||||
@@ -547,33 +643,38 @@ __declspec(dllexport) int poll(struct pollfd* fds, nfds_t nfds, int timeout) {
|
||||
|
||||
size_t ready = 0;
|
||||
uint32_t timeoutMs = timeout < 0 ? SYS_POLL_TIMEOUT_INFINITE : (uint32_t)timeout;
|
||||
SYS_POLL_REQUEST req;
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.Size = sizeof(req);
|
||||
req.TimeoutMs = timeoutMs;
|
||||
req.Fds = kfds;
|
||||
req.Count = nfds;
|
||||
req.ReadyOut = &ready;
|
||||
KSTATUS s = SysPoll(&req);
|
||||
if (s != 0) {
|
||||
free(kfds);
|
||||
errno = PosixStatusToErrno(s);
|
||||
return -1;
|
||||
}
|
||||
SYS_POLL_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.TimeoutMs = timeoutMs;
|
||||
request.Fds = kfds;
|
||||
request.Count = nfds;
|
||||
request.ReadyOut = &ready;
|
||||
KSTATUS status = SysPoll(&request);
|
||||
|
||||
int out = 0;
|
||||
for (nfds_t i = 0; i < nfds; i++) {
|
||||
short re = 0;
|
||||
if (kfds[i].ReturnedEvents & SYS_POLL_READ) re |= POLLIN;
|
||||
if (kfds[i].ReturnedEvents & SYS_POLL_WRITE) re |= POLLOUT;
|
||||
if (kfds[i].ReturnedEvents & SYS_POLL_ERROR) re |= POLLERR;
|
||||
if (kfds[i].ReturnedEvents & SYS_POLL_HANGUP) re |= POLLHUP;
|
||||
if (kfds[i].ReturnedEvents & SYS_POLL_INVALID) re |= POLLNVAL;
|
||||
fds[i].revents = re;
|
||||
if (re) out++;
|
||||
if (status == NTLSTATUS_SUCCESS) {
|
||||
for (nfds_t i = 0; i < nfds; i++) {
|
||||
short revents = fds[i].revents;
|
||||
if (kfds[i].ReturnedEvents & SYS_POLL_READ) revents |= POLLIN;
|
||||
if (kfds[i].ReturnedEvents & SYS_POLL_WRITE) revents |= POLLOUT;
|
||||
if (kfds[i].ReturnedEvents & SYS_POLL_ERROR) revents |= POLLERR;
|
||||
if (kfds[i].ReturnedEvents & SYS_POLL_HANGUP) revents |= POLLHUP;
|
||||
if (kfds[i].ReturnedEvents & SYS_POLL_INVALID) revents |= POLLNVAL;
|
||||
fds[i].revents = revents;
|
||||
if (revents) out++;
|
||||
}
|
||||
}
|
||||
|
||||
for (nfds_t i = 0; i < nfds; i++)
|
||||
PosixFdRelease(descriptions[i]);
|
||||
free(descriptions);
|
||||
free(kfds);
|
||||
|
||||
if (status != NTLSTATUS_SUCCESS) {
|
||||
errno = PosixStatusToErrno(status);
|
||||
return -1;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,46 +3,38 @@
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <ntlite/syscall.h>
|
||||
#include "posix.h"
|
||||
#include "posix_internal.h"
|
||||
|
||||
// Thread return-value table (PID-keyed like the fd table).
|
||||
#define PTHREAD_TABLE_PIDS 32
|
||||
#define PTHREAD_TABLE_SIZE 32
|
||||
// Allocates a join-result slot in process-local POSIX state.
|
||||
static POSIX_PTHREAD_SLOT* PthreadSlotAlloc(uint32_t tid) {
|
||||
POSIX_PROCESS_STATE* process = PosixRuntimeProcessState();
|
||||
if (!process) return (POSIX_PTHREAD_SLOT*)0;
|
||||
|
||||
typedef struct {
|
||||
uint32_t Tid;
|
||||
void* RetVal;
|
||||
bool Used;
|
||||
} PTHREAD_SLOT;
|
||||
|
||||
static PTHREAD_SLOT gPthreadTable[PTHREAD_TABLE_PIDS][PTHREAD_TABLE_SIZE];
|
||||
|
||||
// Implements the pthread Slot Alloc operation.
|
||||
static PTHREAD_SLOT* PthreadSlotAlloc(uint32_t pid, uint32_t tid) {
|
||||
PTHREAD_SLOT* table = gPthreadTable[pid % PTHREAD_TABLE_PIDS];
|
||||
for (int i = 0; i < PTHREAD_TABLE_SIZE; i++) {
|
||||
if (!table[i].Used) {
|
||||
table[i] = (PTHREAD_SLOT){ tid, (void*)0, true };
|
||||
return &table[i];
|
||||
for (uint32_t i = 0; i < POSIX_PTHREAD_TABLE_SIZE; i++) {
|
||||
if (!process->PthreadTable[i].Used) {
|
||||
process->PthreadTable[i] = (POSIX_PTHREAD_SLOT){ tid, (void*)0, true };
|
||||
return &process->PthreadTable[i];
|
||||
}
|
||||
}
|
||||
return (PTHREAD_SLOT*)0;
|
||||
return (POSIX_PTHREAD_SLOT*)0;
|
||||
}
|
||||
|
||||
// Implements the pthread Slot Find operation.
|
||||
static PTHREAD_SLOT* PthreadSlotFind(uint32_t pid, uint32_t tid) {
|
||||
PTHREAD_SLOT* table = gPthreadTable[pid % PTHREAD_TABLE_PIDS];
|
||||
for (int i = 0; i < PTHREAD_TABLE_SIZE; i++)
|
||||
if (table[i].Used && table[i].Tid == tid)
|
||||
return &table[i];
|
||||
return (PTHREAD_SLOT*)0;
|
||||
// Finds a join-result slot in process-local POSIX state.
|
||||
static POSIX_PTHREAD_SLOT* PthreadSlotFind(uint32_t tid) {
|
||||
POSIX_PROCESS_STATE* process = PosixRuntimeProcessState();
|
||||
if (!process) return (POSIX_PTHREAD_SLOT*)0;
|
||||
|
||||
for (uint32_t i = 0; i < POSIX_PTHREAD_TABLE_SIZE; i++) {
|
||||
if (process->PthreadTable[i].Used && process->PthreadTable[i].Tid == tid)
|
||||
return &process->PthreadTable[i];
|
||||
}
|
||||
return (POSIX_PTHREAD_SLOT*)0;
|
||||
}
|
||||
|
||||
// Trampoline - this is what actually runs as the new thread.
|
||||
typedef struct {
|
||||
void* (*Fn)(void*);
|
||||
void* Arg;
|
||||
uint32_t Pid; // owner pid, for the retval table
|
||||
void* Arg;
|
||||
} PTHREAD_TRAMP;
|
||||
|
||||
// Implements the pthread Trampoline operation.
|
||||
@@ -50,14 +42,18 @@ static void PthreadTrampoline(uintptr_t raw) {
|
||||
PTHREAD_TRAMP* tr = (PTHREAD_TRAMP*)raw;
|
||||
void* (*fn)(void*) = tr->Fn;
|
||||
void* arg = tr->Arg;
|
||||
uint32_t pid = tr->Pid;
|
||||
uint32_t tid = SysGetCurrentTid();
|
||||
|
||||
if (PosixRuntimeAttachThread() != NTLSTATUS_SUCCESS) {
|
||||
free(tr);
|
||||
SysExitThread(ENOMEM);
|
||||
}
|
||||
|
||||
// Create the join slot from inside the new thread. KeCreateThread makes the
|
||||
// thread runnable before the creator regains control, so the old design
|
||||
// raced on tr->Tid and could observe zero/stale memory.
|
||||
PTHREAD_SLOT* slot = PthreadSlotFind(pid, tid);
|
||||
if (!slot) slot = PthreadSlotAlloc(pid, tid);
|
||||
POSIX_PTHREAD_SLOT* slot = PthreadSlotFind(tid);
|
||||
if (!slot) slot = PthreadSlotAlloc(tid);
|
||||
|
||||
free(tr);
|
||||
|
||||
@@ -66,6 +62,7 @@ static void PthreadTrampoline(uintptr_t raw) {
|
||||
// Store retval for pthread_join.
|
||||
if (slot) slot->RetVal = retval;
|
||||
|
||||
PosixRuntimeDetachThread();
|
||||
SysExitThread(0);
|
||||
}
|
||||
|
||||
@@ -75,13 +72,10 @@ __declspec(dllexport) int pthread_create(pthread_t* t, const pthread_attr_t* att
|
||||
void* (*fn)(void*), void* arg) {
|
||||
(void)attr;
|
||||
|
||||
uint32_t pid = SysGetCurrentPid();
|
||||
|
||||
PTHREAD_TRAMP* tr = (PTHREAD_TRAMP*)malloc(sizeof(PTHREAD_TRAMP));
|
||||
if (!tr) return ENOMEM;
|
||||
tr->Fn = fn;
|
||||
tr->Arg = arg;
|
||||
tr->Pid = pid;
|
||||
|
||||
uint32_t tid = 0;
|
||||
uint32_t handle = 0;
|
||||
@@ -111,11 +105,10 @@ __declspec(dllexport) int pthread_create(pthread_t* t, const pthread_attr_t* att
|
||||
|
||||
// Implements the pthread join operation.
|
||||
__declspec(dllexport) int pthread_join(pthread_t t, void** retval) {
|
||||
uint32_t pid = SysGetCurrentPid();
|
||||
uint32_t s = SysWait(t.Handle, SYS_WAIT_FLAG_NONE);
|
||||
if (s != 0) return ESRCH;
|
||||
|
||||
PTHREAD_SLOT* slot = PthreadSlotFind(pid, t.Tid);
|
||||
POSIX_PTHREAD_SLOT* slot = PthreadSlotFind(t.Tid);
|
||||
if (retval) *retval = slot ? slot->RetVal : (void*)0;
|
||||
if (slot) slot->Used = false;
|
||||
SysCloseHandle(t.Handle);
|
||||
@@ -124,10 +117,10 @@ __declspec(dllexport) int pthread_join(pthread_t t, void** retval) {
|
||||
|
||||
// Implements the pthread exit operation.
|
||||
__declspec(dllexport) void pthread_exit(void* retval) {
|
||||
uint32_t pid = SysGetCurrentPid();
|
||||
uint32_t tid = SysGetCurrentTid();
|
||||
PTHREAD_SLOT* slot = PthreadSlotFind(pid, tid);
|
||||
POSIX_PTHREAD_SLOT* slot = PthreadSlotFind(tid);
|
||||
if (slot) slot->RetVal = retval;
|
||||
PosixRuntimeDetachThread();
|
||||
SysExitThread(0);
|
||||
while (1); // unreachable
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#include <string.h>
|
||||
#include <intrin.h>
|
||||
#include <ntlite/syscall.h>
|
||||
#include <ntlite/input_service.h>
|
||||
#include <ntlite/console_service.h>
|
||||
#include <ntlite/exception.h>
|
||||
#include <ntlite/process_loader.h>
|
||||
#include <ntlite/path.h>
|
||||
@@ -338,8 +340,7 @@ static uint32_t K32CreateProcessNative(const char* path, uint32_t imageFile, uin
|
||||
|
||||
// Implements the k32 Write Console Span operation.
|
||||
static void K32WriteConsoleSpan(const char* data, size_t length) {
|
||||
SYS_WRITE_CONSOLE_REQUEST req = { sizeof(SYS_WRITE_CONSOLE_REQUEST), SysSvFromParts(data, length) };
|
||||
SysWriteConsole(&req);
|
||||
(void)NtlConsoleWrite(SYS_HANDLE_INVALID, data, length, 0);
|
||||
}
|
||||
|
||||
// Implements the k32 Debug Print A operation.
|
||||
@@ -745,7 +746,7 @@ __declspec(dllexport) BOOL FlushViewOfFile(const void* lpBaseAddress, size_t dwN
|
||||
// Returns whether one input key is currently held for Win32 adapters.
|
||||
static bool Win32IsInputKeyDown(INPUT_KEY key) {
|
||||
bool down = false;
|
||||
return SysIsKeyDown(key, &down) == NTLSTATUS_SUCCESS && down;
|
||||
return NtlInputIsKeyDown(key, &down) == NTLSTATUS_SUCCESS && down;
|
||||
}
|
||||
|
||||
// GetAsyncKeyState implementation over the canonical input key namespace.
|
||||
@@ -811,18 +812,14 @@ __declspec(dllexport) SHORT GetAsyncKeyState(int vKey) {
|
||||
// FlushConsoleInputBuffer: clear the keyboard input buffer.
|
||||
__declspec(dllexport) BOOL FlushConsoleInputBuffer(HANDLE hConsoleInput) {
|
||||
(void)hConsoleInput;
|
||||
// Drain the keyboard buffer by reading until empty.
|
||||
INPUT_KEY key;
|
||||
while (SysPollKeyboard(&key) == NTLSTATUS_SUCCESS) {
|
||||
char ignored;
|
||||
(void)SysReadKeyboardChar(&ignored);
|
||||
}
|
||||
(void)NtlConsoleFlushInput(SYS_HANDLE_INVALID);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// !Made-up! clear console api.
|
||||
__declspec(dllexport) BOOL ClearConsoleScreenBuffer(HANDLE hConsole) {
|
||||
SysClearScreen(0x012456);
|
||||
(void)hConsole;
|
||||
(void)NtlConsoleClear(SYS_HANDLE_INVALID, 0x012456);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -1948,7 +1945,7 @@ __declspec(dllexport) HANDLE GetStdHandle(DWORD nStdHandle) {
|
||||
}
|
||||
|
||||
// ReadConsoleA: blocking read of up to nNumberOfCharsToRead characters.
|
||||
// Each character is read individually via SysReadKeyboardChar so the caller can
|
||||
// Each character is read individually via NtlInputReadKeyboardChar so the caller can
|
||||
// do its own line-editing (echo, backspace, etc.) one char at a time.
|
||||
__declspec(dllexport) BOOL ReadConsoleA(HANDLE hConsoleInput,
|
||||
void* lpBuffer,
|
||||
@@ -1963,7 +1960,7 @@ __declspec(dllexport) BOOL ReadConsoleA(HANDLE hConsoleInput,
|
||||
|
||||
while (i < nNumberOfCharsToRead) {
|
||||
char c = 0;
|
||||
if (SysReadKeyboardChar(&c) != NTLSTATUS_SUCCESS) continue;
|
||||
if (NtlConsoleReadCharacter(SYS_HANDLE_INVALID, &c) != NTLSTATUS_SUCCESS) continue;
|
||||
|
||||
// Ignore unmapped keys (Shift, Ctrl, etc.).
|
||||
if (c == 0) continue;
|
||||
@@ -2013,8 +2010,8 @@ __declspec(dllexport) BOOL GetConsoleScreenBufferInfo(HANDLE hConsoleOutput,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
SYS_CONSOLE_INFO info;
|
||||
uint32_t s = SysGetConsoleInfo(&info);
|
||||
NTL_CONSOLE_INFO info;
|
||||
uint32_t s = NtlConsoleQueryInfo(SYS_HANDLE_INVALID, &info);
|
||||
if (s != NTLSTATUS_SUCCESS) {
|
||||
K32SetConsoleLastError(s);
|
||||
return FALSE;
|
||||
@@ -2045,7 +2042,7 @@ __declspec(dllexport) BOOL SetConsoleCursorPosition(HANDLE hConsoleOutput,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
uint32_t s = SysSetConsoleCursor((int)dwCursorPosition.X, (int)dwCursorPosition.Y);
|
||||
uint32_t s = NtlConsoleSetCursor(SYS_HANDLE_INVALID, (int)dwCursorPosition.X, (int)dwCursorPosition.Y);
|
||||
if (s != NTLSTATUS_SUCCESS) {
|
||||
K32SetConsoleLastError(s);
|
||||
return FALSE;
|
||||
@@ -2071,11 +2068,9 @@ __declspec(dllexport) BOOL FillConsoleOutputCharacterA(HANDLE hConsoleOutput,
|
||||
return TRUE;
|
||||
|
||||
size_t written = 0;
|
||||
SYS_FILL_CONSOLE_CHARACTER_REQUEST request = {
|
||||
sizeof(SYS_FILL_CONSOLE_CHARACTER_REQUEST), cCharacter, { 0, 0, 0 },
|
||||
(int)dwWriteCoord.X, (int)dwWriteCoord.Y, (size_t)nLength, &written
|
||||
};
|
||||
uint32_t s = SysFillConsoleCharacter(&request);
|
||||
uint32_t s = NtlConsoleFillCharacter(SYS_HANDLE_INVALID, cCharacter,
|
||||
(int)dwWriteCoord.X, (int)dwWriteCoord.Y,
|
||||
(size_t)nLength, &written);
|
||||
if (lpNumberOfCharsWritten) *lpNumberOfCharsWritten = (DWORD)written;
|
||||
if (s != NTLSTATUS_SUCCESS) {
|
||||
K32SetConsoleLastError(s);
|
||||
@@ -2102,11 +2097,9 @@ __declspec(dllexport) BOOL FillConsoleOutputAttribute(HANDLE hConsoleOutput,
|
||||
return TRUE;
|
||||
|
||||
size_t written = 0;
|
||||
SYS_FILL_CONSOLE_ATTRIBUTE_REQUEST request = {
|
||||
sizeof(SYS_FILL_CONSOLE_ATTRIBUTE_REQUEST), wAttribute, 0,
|
||||
(int)dwWriteCoord.X, (int)dwWriteCoord.Y, (size_t)nLength, &written
|
||||
};
|
||||
uint32_t s = SysFillConsoleAttribute(&request);
|
||||
uint32_t s = NtlConsoleFillAttribute(SYS_HANDLE_INVALID, wAttribute,
|
||||
(int)dwWriteCoord.X, (int)dwWriteCoord.Y,
|
||||
(size_t)nLength, &written);
|
||||
if (lpNumberOfAttrsWritten) *lpNumberOfAttrsWritten = (DWORD)written;
|
||||
if (s != NTLSTATUS_SUCCESS) {
|
||||
K32SetConsoleLastError(s);
|
||||
@@ -3120,7 +3113,7 @@ __declspec(dllexport) DWORD GetFileType(HANDLE hFile) {
|
||||
#define EXCEPTION_CONTINUE_SEARCH 0
|
||||
#define EXCEPTION_EXECUTE_HANDLER 1
|
||||
#define EXCEPTION_NONCONTINUABLE 0x1UL
|
||||
#define EXCEPTION_MAXIMUM_PARAMETERS SYS_EXCEPTION_MAXIMUM_PARAMETERS
|
||||
#define EXCEPTION_MAXIMUM_PARAMETERS 15u
|
||||
#define WIN_VECTORED_MAX_HANDLERS 16u
|
||||
#define WIN_SEH_MAX_FRAMES 16u
|
||||
|
||||
@@ -3239,10 +3232,61 @@ static uint32_t* WinpVectoredTailSlot(uint32_t isContinue) {
|
||||
return isContinue ? &gWinVectoredContinueTail : &gWinVectoredExceptionTail;
|
||||
}
|
||||
|
||||
// Windows exception values remain a Win32 personality ABI and are translated
|
||||
// explicitly from the native nt-lite exception classes.
|
||||
#define WIN_EXCEPTION_GUARD_PAGE_VIOLATION 0x80000001u
|
||||
#define WIN_EXCEPTION_DATATYPE_MISALIGNMENT 0x80000002u
|
||||
#define WIN_EXCEPTION_BREAKPOINT 0x80000003u
|
||||
#define WIN_EXCEPTION_SINGLE_STEP 0x80000004u
|
||||
#define WIN_EXCEPTION_ACCESS_VIOLATION 0xC0000005u
|
||||
#define WIN_EXCEPTION_ILLEGAL_INSTRUCTION 0xC000001Du
|
||||
#define WIN_EXCEPTION_ARRAY_BOUNDS_EXCEEDED 0xC000008Cu
|
||||
#define WIN_EXCEPTION_FLT_DENORMAL_OPERAND 0xC000008Du
|
||||
#define WIN_EXCEPTION_FLT_DIVIDE_BY_ZERO 0xC000008Eu
|
||||
#define WIN_EXCEPTION_FLT_INEXACT_RESULT 0xC000008Fu
|
||||
#define WIN_EXCEPTION_FLT_INVALID_OPERATION 0xC0000090u
|
||||
#define WIN_EXCEPTION_FLT_OVERFLOW 0xC0000091u
|
||||
#define WIN_EXCEPTION_FLT_STACK_CHECK 0xC0000092u
|
||||
#define WIN_EXCEPTION_FLT_UNDERFLOW 0xC0000093u
|
||||
#define WIN_EXCEPTION_INT_DIVIDE_BY_ZERO 0xC0000094u
|
||||
#define WIN_EXCEPTION_INT_OVERFLOW 0xC0000095u
|
||||
#define WIN_EXCEPTION_PRIVILEGED_INSTRUCTION 0xC0000096u
|
||||
#define WIN_EXCEPTION_STACK_OVERFLOW 0xC00000FDu
|
||||
#define WIN_EXCEPTION_NTLITE_UNKNOWN 0xE04E544Cu
|
||||
|
||||
// Maps one native exception class to the Win32 exception namespace.
|
||||
static DWORD WinpExceptionCodeFromNative(const SYS_EXCEPTION_RECORD* source) {
|
||||
if (!source) return WIN_EXCEPTION_NTLITE_UNKNOWN;
|
||||
if (source->Code == SYS_EXCEPTION_CODE_USER_RAISED)
|
||||
return source->UserCode;
|
||||
|
||||
switch (source->Code) {
|
||||
case SYS_EXCEPTION_CODE_GUARD_PAGE_VIOLATION: return WIN_EXCEPTION_GUARD_PAGE_VIOLATION;
|
||||
case SYS_EXCEPTION_CODE_DATATYPE_MISALIGNMENT: return WIN_EXCEPTION_DATATYPE_MISALIGNMENT;
|
||||
case SYS_EXCEPTION_CODE_BREAKPOINT: return WIN_EXCEPTION_BREAKPOINT;
|
||||
case SYS_EXCEPTION_CODE_SINGLE_STEP: return WIN_EXCEPTION_SINGLE_STEP;
|
||||
case SYS_EXCEPTION_CODE_ACCESS_VIOLATION: return WIN_EXCEPTION_ACCESS_VIOLATION;
|
||||
case SYS_EXCEPTION_CODE_ILLEGAL_INSTRUCTION: return WIN_EXCEPTION_ILLEGAL_INSTRUCTION;
|
||||
case SYS_EXCEPTION_CODE_ARRAY_BOUNDS_EXCEEDED: return WIN_EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
|
||||
case SYS_EXCEPTION_CODE_FLT_DENORMAL_OPERAND: return WIN_EXCEPTION_FLT_DENORMAL_OPERAND;
|
||||
case SYS_EXCEPTION_CODE_FLT_DIVIDE_BY_ZERO: return WIN_EXCEPTION_FLT_DIVIDE_BY_ZERO;
|
||||
case SYS_EXCEPTION_CODE_FLT_INEXACT_RESULT: return WIN_EXCEPTION_FLT_INEXACT_RESULT;
|
||||
case SYS_EXCEPTION_CODE_FLT_INVALID_OPERATION: return WIN_EXCEPTION_FLT_INVALID_OPERATION;
|
||||
case SYS_EXCEPTION_CODE_FLT_OVERFLOW: return WIN_EXCEPTION_FLT_OVERFLOW;
|
||||
case SYS_EXCEPTION_CODE_FLT_STACK_CHECK: return WIN_EXCEPTION_FLT_STACK_CHECK;
|
||||
case SYS_EXCEPTION_CODE_FLT_UNDERFLOW: return WIN_EXCEPTION_FLT_UNDERFLOW;
|
||||
case SYS_EXCEPTION_CODE_INT_DIVIDE_BY_ZERO: return WIN_EXCEPTION_INT_DIVIDE_BY_ZERO;
|
||||
case SYS_EXCEPTION_CODE_INT_OVERFLOW: return WIN_EXCEPTION_INT_OVERFLOW;
|
||||
case SYS_EXCEPTION_CODE_PRIVILEGED_INSTRUCTION: return WIN_EXCEPTION_PRIVILEGED_INSTRUCTION;
|
||||
case SYS_EXCEPTION_CODE_STACK_OVERFLOW: return WIN_EXCEPTION_STACK_OVERFLOW;
|
||||
default: return WIN_EXCEPTION_NTLITE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
// Copies native exception state into the Win32-facing exception record.
|
||||
static void WinpBuildExceptionRecord(const SYS_EXCEPTION_RECORD* source, EXCEPTION_RECORD* target) {
|
||||
memset(target, 0, sizeof(*target));
|
||||
target->ExceptionCode = source->Code;
|
||||
target->ExceptionCode = WinpExceptionCodeFromNative(source);
|
||||
if (source->Flags & SYS_EXCEPTION_FLAG_NONCONTINUABLE)
|
||||
target->ExceptionFlags |= EXCEPTION_NONCONTINUABLE;
|
||||
target->ExceptionAddress = (void*)(uintptr_t)source->ExceptionAddress;
|
||||
@@ -3603,7 +3647,7 @@ __declspec(dllexport) void RaiseException(DWORD dwExceptionCode, DWORD dwExcepti
|
||||
SYS_RAISE_EXCEPTION_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Code = dwExceptionCode;
|
||||
request.UserCode = dwExceptionCode;
|
||||
request.Flags = (dwExceptionFlags & EXCEPTION_NONCONTINUABLE) ?
|
||||
SYS_RAISE_EXCEPTION_FLAG_NONCONTINUABLE :
|
||||
SYS_RAISE_EXCEPTION_FLAG_NONE;
|
||||
|
||||
Reference in new issue
Block a user