add ntfs.sys standalone driver target, change default usb vhd layout formatting to ntfs, implement Fat32CreateDir for directory creation support in the fat32 file system driver, add a dedicated HAL serial output endpoint for COM1 writes in hal_serial.c and subscribe serial to HAL text streams, introduce waitable kernel timers with KeTimerCreate, KeTimerSet, and KeTimerCancel alongside spinlock-protected global timer list initialization and scheduler tick tracking, implement SyscallWriteFileAsync system call for asynchronous non-blocking file writes, refactor NetSocketConnect and NetSocketSendTo to use generic SYS_SOCKET_ADDRESS_K structures instead of being hardcoded to IPv4, update gethostbyname and DNS name resolution to support IPv6 parsing via ResolveNameFamily, update tcpserve.exe with -4 and -6 command-line flags to accept and display IPv6 addresses, append size and version headers to all kernel telemetry and statistics structures including SYS_PMM_STATS, SYS_CPU_STATS, and SYS_SCHEDULER_STATS, update winmm timeGetTime to look up high-resolution hardware frequencies via SysGetTickFrequency, integrate 14 native smoke test applications.
This commit is contained in:
1 parent
2c4a68a75f
commit
ed3d065abd
156 files changed
+10509
-2643
No files matched your search
@@ -89,6 +89,43 @@ 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);
|
||||
@@ -101,13 +138,17 @@ 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
|
||||
@@ -125,6 +166,10 @@ 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];
|
||||
@@ -137,6 +182,14 @@ struct sockaddr_in {
|
||||
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;
|
||||
@@ -184,6 +237,8 @@ __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);
|
||||
@@ -208,13 +263,13 @@ 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).
|
||||
// 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).
|
||||
// dirent (used by posix_dir.c).
|
||||
#define NAME_MAX 259
|
||||
|
||||
typedef struct dirent {
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
#include <ntlite/syscall.h>
|
||||
#include <stdlib.h>
|
||||
#include "posix.h"
|
||||
#include "posix_fd.h"
|
||||
#include "posix_path.h"
|
||||
|
||||
typedef SYS_DIR_ENTRY KDIR_ENTRY;
|
||||
|
||||
|
||||
#define KATTR_DIR 0x10
|
||||
|
||||
// Implements the chdir operation.
|
||||
@@ -24,16 +24,84 @@ __declspec(dllexport) int chdir(const char* path) {
|
||||
// Implements the getcwd operation.
|
||||
__declspec(dllexport) char* getcwd(char* buf, size_t size) {
|
||||
if (!buf || size == 0) { errno = EINVAL; return (char*)0; }
|
||||
char native[512];
|
||||
size_t nativeLen = 0;
|
||||
SYS_GET_CWD_REQUEST req = { native, sizeof(native) - 1, &nativeLen };
|
||||
uint32_t s = SysGetCwd(&req);
|
||||
if (s == 0) native[nativeLen] = '\0';
|
||||
if (s != 0) { errno = ERANGE; return (char*)0; }
|
||||
NativeToPosix(native, buf, size);
|
||||
|
||||
SYS_STRING_VIEW cwd = SysGetCurrentDirectoryView();
|
||||
if ((cwd.Length && !cwd.Data) || cwd.Length > SYS_CWD_MAX) {
|
||||
errno = ERANGE;
|
||||
return (char*)0;
|
||||
}
|
||||
|
||||
char native[SYS_CWD_MAX + 1];
|
||||
if (cwd.Length) memcpy(native, cwd.Data, cwd.Length);
|
||||
native[cwd.Length] = '\0';
|
||||
|
||||
char posix[SYS_CWD_MAX + 1];
|
||||
NativeToPosix(native, posix, sizeof(posix));
|
||||
|
||||
size_t needed = strlen(posix) + 1;
|
||||
if (needed > size) {
|
||||
errno = ERANGE;
|
||||
return (char*)0;
|
||||
}
|
||||
|
||||
memcpy(buf, posix, needed);
|
||||
return buf;
|
||||
}
|
||||
|
||||
// Copies one path string into either caller storage or a new allocation.
|
||||
static char* PosixCopyResolvedPath(const char* value, char* resolvedPath) {
|
||||
if (!value) { errno = EINVAL; return (char*)0; }
|
||||
|
||||
size_t needed = strlen(value) + 1;
|
||||
char* out = resolvedPath;
|
||||
if (!out) {
|
||||
out = (char*)malloc(needed);
|
||||
if (!out) { errno = ENOMEM; return (char*)0; }
|
||||
}
|
||||
|
||||
memcpy(out, value, needed);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Implements the realpath operation over the kernel lexical resolver.
|
||||
__declspec(dllexport) char* realpath(const char* path, char* resolved_path) {
|
||||
if (!path) { errno = EINVAL; return (char*)0; }
|
||||
|
||||
char native[SYS_PATH_MAX + 1];
|
||||
const char* translated = PosixTranslatePath(path, native, sizeof(native));
|
||||
if (strcmp(translated, SYNTH_DEVNULL) == 0 || strcmp(translated, SYNTH_DEVZERO) == 0)
|
||||
return PosixCopyResolvedPath(path, resolved_path);
|
||||
|
||||
size_t required = 0;
|
||||
SYS_REAL_PATH_REQUEST query = {
|
||||
sizeof(query),
|
||||
SYS_REAL_PATH_FLAG_NONE,
|
||||
SysSvFromCstr(translated),
|
||||
(char*)0,
|
||||
0,
|
||||
&required,
|
||||
};
|
||||
uint32_t status = SysRealPath(&query);
|
||||
if (status != STATUS_SUCCESS) { errno = PosixStatusToErrno(status); return (char*)0; }
|
||||
if (required == 0 || required > SYS_CWD_MAX) { errno = ERANGE; return (char*)0; }
|
||||
|
||||
char nativeResolved[SYS_CWD_MAX];
|
||||
SYS_REAL_PATH_REQUEST request = {
|
||||
sizeof(request),
|
||||
SYS_REAL_PATH_FLAG_NONE,
|
||||
SysSvFromCstr(translated),
|
||||
nativeResolved,
|
||||
sizeof(nativeResolved),
|
||||
&required,
|
||||
};
|
||||
status = SysRealPath(&request);
|
||||
if (status != STATUS_SUCCESS) { errno = PosixStatusToErrno(status); return (char*)0; }
|
||||
|
||||
char posix[SYS_CWD_MAX];
|
||||
NativeToPosix(nativeResolved, posix, sizeof(posix));
|
||||
return PosixCopyResolvedPath(posix, resolved_path);
|
||||
}
|
||||
|
||||
// Implements the opendir operation.
|
||||
__declspec(dllexport) DIR* opendir(const char* path) {
|
||||
char native[512];
|
||||
@@ -74,3 +142,82 @@ __declspec(dllexport) int closedir(DIR* d) {
|
||||
free(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Converts native file metadata to a POSIX stat structure.
|
||||
static int PosixFillStat(const SYS_FILE_STAT* native, struct stat* out) {
|
||||
if (!native || !out) { errno = EINVAL; return -1; }
|
||||
if (native->FileSize > 0x7FFFFFFFULL) { errno = EINVAL; return -1; }
|
||||
|
||||
memset(out, 0, sizeof(*out));
|
||||
out->st_dev = native->VolumeId;
|
||||
out->st_ino = native->FileId;
|
||||
out->st_nlink = native->LinkCount ? native->LinkCount : 1;
|
||||
out->st_size = (off_t)native->FileSize;
|
||||
out->st_atime = (int64_t)native->LastAccessTime.EpochSeconds;
|
||||
out->st_mtime = (int64_t)native->LastWriteTime.EpochSeconds;
|
||||
out->st_ctime = (int64_t)native->ChangeTime.EpochSeconds;
|
||||
|
||||
if (native->Type == SYS_FILE_TYPE_DIRECTORY) {
|
||||
out->st_mode = S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR |
|
||||
S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
|
||||
} else {
|
||||
out->st_mode = S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
|
||||
}
|
||||
|
||||
if (native->Attributes & SYS_FILE_ATTR_READ_ONLY)
|
||||
out->st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Fills stat for one synthetic descriptor.
|
||||
static int PosixFillSyntheticStat(mode_t type, struct stat* out) {
|
||||
if (!out) { errno = EINVAL; return -1; }
|
||||
memset(out, 0, sizeof(*out));
|
||||
out->st_mode = type | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
|
||||
out->st_nlink = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Implements the stat operation.
|
||||
__declspec(dllexport) int stat(const char* path, struct stat* out) {
|
||||
if (!path || !out) { 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)
|
||||
return PosixFillSyntheticStat(S_IFCHR, out);
|
||||
|
||||
SYS_FILE_STAT nativeStat;
|
||||
SYS_STAT_FILE_REQUEST req = { SysSvFromCstr(p), &nativeStat };
|
||||
uint32_t s = SysStatFile(&req);
|
||||
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
|
||||
return PosixFillStat(&nativeStat, out);
|
||||
}
|
||||
|
||||
// Implements the fstat operation.
|
||||
__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;
|
||||
|
||||
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: {
|
||||
SYS_FILE_STAT nativeStat;
|
||||
uint32_t s = SysGetFileStat(e->KHandle, &nativeStat);
|
||||
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
|
||||
return PosixFillStat(&nativeStat, out);
|
||||
}
|
||||
default:
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -9,20 +9,24 @@ int errno = 0;
|
||||
// Implements the status To Errno operation.
|
||||
int PosixStatusToErrno(uint32_t s) {
|
||||
switch (s) {
|
||||
case 0x0000: return 0; // STATUS_SUCCESS
|
||||
case 0x0002: return ENOSYS; // STATUS_NOT_SUPPORTED
|
||||
case 0x0003: return EAGAIN; // STATUS_TIMEOUT / would block
|
||||
case 0x0010: return EINVAL; // STATUS_INVALID_PARAMETER
|
||||
case 0x0011: return EBADF; // STATUS_INVALID_HANDLE
|
||||
case 0x0012: return ERANGE; // STATUS_BUFFER_TOO_SMALL
|
||||
case 0x0020: return ENOMEM; // STATUS_NO_MEMORY
|
||||
case 0x0021: return EACCES; // STATUS_ACCESS_DENIED
|
||||
case 0x0022: return ENOENT; // STATUS_NOT_FOUND
|
||||
case 0x0023: return EEXIST; // STATUS_ALREADY_EXISTS
|
||||
case 0x0030: return ECONNRESET; // STATUS_OBJECT_DEAD
|
||||
case 0x0031: return EAGAIN; // STATUS_QUEUE_FULL
|
||||
case 0x0032: return EAGAIN; // STATUS_QUEUE_EMPTY
|
||||
default: return EIO;
|
||||
case STATUS_SUCCESS: return 0;
|
||||
case STATUS_NOT_SUPPORTED: return ENOSYS;
|
||||
case STATUS_TIMEOUT: return EAGAIN;
|
||||
case STATUS_WOULD_BLOCK: return EAGAIN;
|
||||
case STATUS_INVALID_PARAMETER: return EINVAL;
|
||||
case STATUS_INVALID_HANDLE: return EBADF;
|
||||
case STATUS_BUFFER_TOO_SMALL: return ERANGE;
|
||||
case STATUS_NO_MEMORY: return ENOMEM;
|
||||
case STATUS_ACCESS_DENIED: return EACCES;
|
||||
case STATUS_NOT_FOUND: return ENOENT;
|
||||
case STATUS_ALREADY_EXISTS: return EEXIST;
|
||||
case STATUS_OBJECT_NAME_COLLISION: return EEXIST;
|
||||
case STATUS_OBJECT_DEAD: return ECONNRESET;
|
||||
case STATUS_QUEUE_FULL: return EAGAIN;
|
||||
case STATUS_QUEUE_EMPTY: return EAGAIN;
|
||||
case STATUS_CANCELLED: return ECANCELED;
|
||||
case STATUS_NO_MORE_FILES: return ENOENT;
|
||||
default: return EIO;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
typedef enum {
|
||||
FD_FREE,
|
||||
FD_FILE,
|
||||
FD_CONSOLE_R, // fd 0 - reads from keyboard via SysReadKeyboardChar
|
||||
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
|
||||
|
||||
@@ -14,7 +14,11 @@ __declspec(dllexport) void clearscreen(void) {
|
||||
|
||||
// Implements the clearkeyboard operation.
|
||||
__declspec(dllexport) void clearkeyboard(void) {
|
||||
while (SysPollKeyboard()) (void)SysReadKeyboardChar();
|
||||
INPUT_KEY key;
|
||||
while (SysPollKeyboard(&key) == STATUS_SUCCESS) {
|
||||
char ignored;
|
||||
(void)SysReadKeyboardChar(&ignored);
|
||||
}
|
||||
}
|
||||
|
||||
// Opens the requested operation.
|
||||
@@ -37,17 +41,33 @@ __declspec(dllexport) int open(const char* path, int flags, ...) {
|
||||
}
|
||||
|
||||
uint32_t kh = 0;
|
||||
SYS_PATH_HANDLE_REQUEST req = { SysSvFromCstr(p), &kh };
|
||||
uint32_t s;
|
||||
if (flags & O_WRONLY) {
|
||||
s = SysCreateFile(&req);
|
||||
} else {
|
||||
s = SysOpenFile(&req);
|
||||
}
|
||||
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
|
||||
uint32_t access = SYS_FILE_ACCESS_QUERY;
|
||||
uint32_t disposition = SYS_FILE_OPEN_EXISTING;
|
||||
|
||||
if ((flags & O_TRUNC) && (flags & O_WRONLY))
|
||||
SysTruncateFile(kh, 0);
|
||||
if ((flags & O_RDWR) == O_RDWR)
|
||||
access |= SYS_FILE_ACCESS_READ | SYS_FILE_ACCESS_WRITE;
|
||||
else if (flags & O_WRONLY)
|
||||
access |= SYS_FILE_ACCESS_WRITE;
|
||||
else
|
||||
access |= SYS_FILE_ACCESS_READ;
|
||||
|
||||
if (flags & O_APPEND)
|
||||
access |= SYS_FILE_ACCESS_APPEND;
|
||||
|
||||
if ((flags & O_CREAT) && (flags & O_TRUNC))
|
||||
disposition = SYS_FILE_CREATE_ALWAYS;
|
||||
else if (flags & O_CREAT)
|
||||
disposition = SYS_FILE_OPEN_ALWAYS;
|
||||
else if (flags & O_TRUNC)
|
||||
disposition = SYS_FILE_TRUNCATE_EXISTING;
|
||||
|
||||
SYS_OPEN_FILE_REQUEST req = SysMakeOpenFileRequest(SysSvFromCstr(p),
|
||||
access,
|
||||
disposition,
|
||||
SYS_FILE_FLAG_NONE,
|
||||
&kh);
|
||||
uint32_t s = SysOpenFile(&req);
|
||||
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
|
||||
|
||||
int fd = FdAlloc(pid, type, kh);
|
||||
if (fd < 0) {
|
||||
@@ -69,7 +89,8 @@ __declspec(dllexport) ssize_t read(int fd, void* buf, size_t count) {
|
||||
// Read up to count chars from keyboard, blocking per char.
|
||||
char* dst = (char*)buf;
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
dst[i] = SysReadKeyboardChar();
|
||||
uint32_t s = SysReadKeyboardChar(&dst[i]);
|
||||
if (s != STATUS_SUCCESS) { errno = PosixStatusToErrno(s); return -1; }
|
||||
if (dst[i] == '\n' || dst[i] == '\r') return (ssize_t)(i + 1);
|
||||
}
|
||||
return (ssize_t)count;
|
||||
@@ -174,13 +195,17 @@ __declspec(dllexport) off_t lseek(int fd, off_t offset, int whence) {
|
||||
target = (int64_t)offset;
|
||||
break;
|
||||
case SEEK_CUR: {
|
||||
uint64_t cur = SysGetFilePos(e->KHandle);
|
||||
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 = SysGetFileSize(e->KHandle);
|
||||
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;
|
||||
|
||||
@@ -52,7 +52,7 @@ __declspec(dllexport) void* mmap(void* addr, size_t length, int prot,
|
||||
uint32_t mapping = 0;
|
||||
uint32_t s = SysCreateFileMapping(e->KHandle, protect, SYS_MAP_FLAG_NONE,
|
||||
maxSize, &mapping);
|
||||
if (s != SYS_STATUS_SUCCESS) {
|
||||
if (s != STATUS_SUCCESS) {
|
||||
errno = PosixStatusToErrno(s);
|
||||
return MAP_FAILED;
|
||||
}
|
||||
@@ -62,7 +62,7 @@ __declspec(dllexport) void* mmap(void* addr, size_t length, int prot,
|
||||
PosixProtToSysMapAccess(prot, flags),
|
||||
SYS_MAP_FLAG_NONE, &base);
|
||||
SysCloseHandle(mapping);
|
||||
if (s != SYS_STATUS_SUCCESS) {
|
||||
if (s != STATUS_SUCCESS) {
|
||||
errno = PosixStatusToErrno(s);
|
||||
return MAP_FAILED;
|
||||
}
|
||||
@@ -73,7 +73,7 @@ __declspec(dllexport) int munmap(void* addr, size_t length) {
|
||||
(void)length;
|
||||
if (!addr) { errno = EINVAL; return -1; }
|
||||
uint32_t s = SysFreeVm(addr);
|
||||
if (s != SYS_STATUS_SUCCESS) { errno = PosixStatusToErrno(s); return -1; }
|
||||
if (s != STATUS_SUCCESS) { errno = PosixStatusToErrno(s); return -1; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include "posix.h"
|
||||
#include "posix_path.h"
|
||||
|
||||
|
||||
static SYS_PEB* gProcessPeb = NULL;
|
||||
|
||||
// Implements the peb operation.
|
||||
@@ -128,7 +127,7 @@ __declspec(dllexport) pid_t waitpid(pid_t pid, int* status, int options) {
|
||||
|
||||
SysWait(handle, SYS_WAIT_FLAG_NONE);
|
||||
|
||||
int exitCode = 0;
|
||||
int32_t exitCode = 0;
|
||||
SysGetProcessExitCode(handle, &exitCode);
|
||||
if (status) *status = exitCode << 8; // WEXITSTATUS convention
|
||||
|
||||
|
||||
@@ -58,6 +58,95 @@ static int ParseIpv4Bytes(const char* text, uint8_t out[4]) {
|
||||
return *p == '\0';
|
||||
}
|
||||
|
||||
static int ParseHex(char c) {
|
||||
if (c >= '0' && c <= '9') return c - '0';
|
||||
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
|
||||
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int ParseIpv6Bytes(const char* text, uint8_t out[16]) {
|
||||
uint16_t words[8];
|
||||
int count = 0;
|
||||
int compress = -1;
|
||||
const char* p = text;
|
||||
|
||||
if (!text || !*text || !out)
|
||||
return 0;
|
||||
memset(words, 0, sizeof(words));
|
||||
|
||||
if (p[0] == ':' && p[1] == ':') {
|
||||
compress = 0;
|
||||
p += 2;
|
||||
if (*p == '\0')
|
||||
count = 0;
|
||||
}
|
||||
|
||||
while (*p) {
|
||||
if (count >= 8)
|
||||
return 0;
|
||||
|
||||
unsigned value = 0;
|
||||
int digits = 0;
|
||||
while (digits < 4) {
|
||||
int h = ParseHex(*p);
|
||||
if (h < 0)
|
||||
break;
|
||||
value = (value << 4) | (unsigned)h;
|
||||
p++;
|
||||
digits++;
|
||||
}
|
||||
if (digits == 0)
|
||||
return 0;
|
||||
words[count++] = (uint16_t)value;
|
||||
|
||||
if (*p == '\0')
|
||||
break;
|
||||
if (*p != ':')
|
||||
return 0;
|
||||
p++;
|
||||
if (*p == ':') {
|
||||
if (compress >= 0)
|
||||
return 0;
|
||||
compress = count;
|
||||
p++;
|
||||
if (*p == '\0')
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (compress >= 0) {
|
||||
int zeros = 8 - count;
|
||||
if (zeros <= 0)
|
||||
return 0;
|
||||
for (int i = count - 1; i >= compress; --i)
|
||||
words[i + zeros] = words[i];
|
||||
for (int i = 0; i < zeros; ++i)
|
||||
words[compress + i] = 0;
|
||||
} else if (count != 8) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
out[i * 2 + 0] = (uint8_t)(words[i] >> 8);
|
||||
out[i * 2 + 1] = (uint8_t)words[i];
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static char* AppendHex16(char* out, uint16_t value) {
|
||||
static const char hex[] = "0123456789abcdef";
|
||||
int started = 0;
|
||||
for (int shift = 12; shift >= 0; shift -= 4) {
|
||||
unsigned nibble = (value >> shift) & 0xfu;
|
||||
if (nibble || started || shift == 0) {
|
||||
*out++ = hex[nibble];
|
||||
started = 1;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Implements the inet addr operation.
|
||||
__declspec(dllexport) in_addr_t inet_addr(const char* text) {
|
||||
uint8_t b[4];
|
||||
@@ -85,41 +174,114 @@ __declspec(dllexport) char* inet_ntoa(struct in_addr in) {
|
||||
return buf;
|
||||
}
|
||||
|
||||
// Implements the sock Addr To Sys operation.
|
||||
static int SockAddrToSys(const struct sockaddr* addr, socklen_t addrlen, SYS_SOCKET_ADDRESS_IPV4* out) {
|
||||
if (!addr || !out || addrlen < sizeof(struct sockaddr_in)) { errno = EINVAL; return -1; }
|
||||
const struct sockaddr_in* in = (const struct sockaddr_in*)addr;
|
||||
if (in->sin_family != AF_INET) { errno = EINVAL; return -1; }
|
||||
// Implements the inet pton operation.
|
||||
__declspec(dllexport) int inet_pton(int af, const char* src, void* dst) {
|
||||
if (!src || !dst) { errno = EINVAL; return -1; }
|
||||
if (af == AF_INET) {
|
||||
uint8_t b[4];
|
||||
if (!ParseIpv4Bytes(src, b))
|
||||
return 0;
|
||||
memcpy(dst, b, 4);
|
||||
return 1;
|
||||
}
|
||||
if (af == AF_INET6) {
|
||||
uint8_t b[16];
|
||||
if (!ParseIpv6Bytes(src, b))
|
||||
return 0;
|
||||
memcpy(dst, b, 16);
|
||||
return 1;
|
||||
}
|
||||
errno = EAFNOSUPPORT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Implements the inet ntop operation.
|
||||
__declspec(dllexport) const char* inet_ntop(int af, const void* src, char* dst, socklen_t size) {
|
||||
if (!src || !dst) { errno = EINVAL; return (const char*)0; }
|
||||
if (af == AF_INET) {
|
||||
if (size < 16) { errno = ERANGE; return (const char*)0; }
|
||||
struct in_addr in;
|
||||
memcpy(&in, src, sizeof(in));
|
||||
strcpy(dst, inet_ntoa(in));
|
||||
return dst;
|
||||
}
|
||||
if (af == AF_INET6) {
|
||||
if (size < 40) { errno = ERANGE; return (const char*)0; }
|
||||
const uint8_t* b = (const uint8_t*)src;
|
||||
char* w = dst;
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
uint16_t value = ((uint16_t)b[i * 2] << 8) | b[i * 2 + 1];
|
||||
w = AppendHex16(w, value);
|
||||
if (i != 7)
|
||||
*w++ = ':';
|
||||
}
|
||||
*w = '\0';
|
||||
return dst;
|
||||
}
|
||||
errno = EAFNOSUPPORT;
|
||||
return (const char*)0;
|
||||
}
|
||||
|
||||
// Implements the sock Addr To Sys operation.
|
||||
static int SockAddrToSys(const struct sockaddr* addr, socklen_t addrlen, SYS_SOCKET_ADDRESS* out) {
|
||||
if (!addr || !out) { errno = EINVAL; return -1; }
|
||||
memset(out, 0, sizeof(*out));
|
||||
out->Family = SYS_AF_INET;
|
||||
out->Port = ntohs(in->sin_port);
|
||||
const uint8_t* p = (const uint8_t*)&in->sin_addr.s_addr;
|
||||
out->Address[0] = p[0];
|
||||
out->Address[1] = p[1];
|
||||
out->Address[2] = p[2];
|
||||
out->Address[3] = p[3];
|
||||
return 0;
|
||||
out->Size = sizeof(*out);
|
||||
|
||||
if (addr->sa_family == AF_INET) {
|
||||
if (addrlen < sizeof(struct sockaddr_in)) { errno = EINVAL; return -1; }
|
||||
const struct sockaddr_in* in = (const struct sockaddr_in*)addr;
|
||||
out->Family = SYS_AF_INET;
|
||||
out->Port = ntohs(in->sin_port);
|
||||
memcpy(out->Address, &in->sin_addr.s_addr, 4);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (addr->sa_family == AF_INET6) {
|
||||
if (addrlen < sizeof(struct sockaddr_in6)) { errno = EINVAL; return -1; }
|
||||
const struct sockaddr_in6* in6 = (const struct sockaddr_in6*)addr;
|
||||
out->Family = SYS_AF_INET6;
|
||||
out->Port = ntohs(in6->sin6_port);
|
||||
memcpy(out->Address, in6->sin6_addr.s6_addr, 16);
|
||||
out->ScopeId = in6->sin6_scope_id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errno = EAFNOSUPPORT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Implements the to Sock Addr operation.
|
||||
static void SysToSockAddr(const SYS_SOCKET_ADDRESS_IPV4* in, struct sockaddr* addr, socklen_t* addrlen) {
|
||||
if (!addr || !addrlen) return;
|
||||
if (*addrlen < sizeof(struct sockaddr_in)) {
|
||||
static void SysToSockAddr(const SYS_SOCKET_ADDRESS* in, struct sockaddr* addr, socklen_t* addrlen) {
|
||||
if (!in || !addr || !addrlen) return;
|
||||
|
||||
if (in->Family == SYS_AF_INET) {
|
||||
if (*addrlen < sizeof(struct sockaddr_in)) {
|
||||
*addrlen = sizeof(struct sockaddr_in);
|
||||
return;
|
||||
}
|
||||
struct sockaddr_in* out = (struct sockaddr_in*)addr;
|
||||
memset(out, 0, sizeof(*out));
|
||||
out->sin_family = AF_INET;
|
||||
out->sin_port = htons(in->Port);
|
||||
memcpy(&out->sin_addr.s_addr, in->Address, 4);
|
||||
*addrlen = sizeof(struct sockaddr_in);
|
||||
return;
|
||||
}
|
||||
|
||||
struct sockaddr_in* out = (struct sockaddr_in*)addr;
|
||||
memset(out, 0, sizeof(*out));
|
||||
out->sin_family = AF_INET;
|
||||
out->sin_port = htons(in->Port);
|
||||
uint8_t* p = (uint8_t*)&out->sin_addr.s_addr;
|
||||
p[0] = in->Address[0];
|
||||
p[1] = in->Address[1];
|
||||
p[2] = in->Address[2];
|
||||
p[3] = in->Address[3];
|
||||
*addrlen = sizeof(struct sockaddr_in);
|
||||
if (in->Family == SYS_AF_INET6) {
|
||||
if (*addrlen < sizeof(struct sockaddr_in6)) {
|
||||
*addrlen = sizeof(struct sockaddr_in6);
|
||||
return;
|
||||
}
|
||||
struct sockaddr_in6* out = (struct sockaddr_in6*)addr;
|
||||
memset(out, 0, sizeof(*out));
|
||||
out->sin6_family = AF_INET6;
|
||||
out->sin6_port = htons(in->Port);
|
||||
memcpy(out->sin6_addr.s6_addr, in->Address, 16);
|
||||
out->sin6_scope_id = in->ScopeId;
|
||||
*addrlen = sizeof(struct sockaddr_in6);
|
||||
}
|
||||
}
|
||||
|
||||
// Implements the socket Fd Get operation.
|
||||
@@ -148,7 +310,7 @@ __declspec(dllexport) int socket(int domain, int type, int protocol) {
|
||||
__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_IPV4 a;
|
||||
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; }
|
||||
@@ -169,10 +331,10 @@ __declspec(dllexport) int accept(int fd, struct sockaddr* addr, socklen_t* addrl
|
||||
FD_ENTRY* e = SocketFdGet(fd);
|
||||
if (!e) return -1;
|
||||
|
||||
SYS_SOCKET_ADDRESS_IPV4 remote;
|
||||
SYS_SOCKET_ADDRESS remote;
|
||||
size_t remoteSize = sizeof(remote);
|
||||
uint32_t kh = 0;
|
||||
uint32_t s = SysAcceptSocket(e->KHandle, addr ? &remote : (SYS_SOCKET_ADDRESS_IPV4*)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; }
|
||||
|
||||
@@ -189,7 +351,7 @@ __declspec(dllexport) int accept(int fd, struct sockaddr* addr, socklen_t* addrl
|
||||
__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_IPV4 a;
|
||||
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; }
|
||||
@@ -220,7 +382,7 @@ __declspec(dllexport) ssize_t sendto(int fd, const void* buf, size_t len, int fl
|
||||
const struct sockaddr* dest, socklen_t destlen) {
|
||||
FD_ENTRY* e = SocketFdGet(fd);
|
||||
if (!e) return -1;
|
||||
SYS_SOCKET_ADDRESS_IPV4 remote;
|
||||
SYS_SOCKET_ADDRESS remote;
|
||||
if (SockAddrToSys(dest, destlen, &remote) != 0) return -1;
|
||||
|
||||
size_t sent = 0;
|
||||
@@ -243,7 +405,7 @@ __declspec(dllexport) ssize_t recvfrom(int fd, void* buf, size_t len, int flags,
|
||||
FD_ENTRY* e = SocketFdGet(fd);
|
||||
if (!e) return -1;
|
||||
|
||||
SYS_SOCKET_ADDRESS_IPV4 remote;
|
||||
SYS_SOCKET_ADDRESS remote;
|
||||
size_t remoteSize = sizeof(remote);
|
||||
size_t got = 0;
|
||||
SYS_SOCKET_RECV_FROM_REQUEST req;
|
||||
@@ -251,7 +413,7 @@ __declspec(dllexport) ssize_t recvfrom(int fd, void* buf, size_t len, int flags,
|
||||
req.Buffer = buf;
|
||||
req.Length = len;
|
||||
req.Flags = (uint32_t)flags;
|
||||
req.RemoteAddressOut = src ? &remote : (SYS_SOCKET_ADDRESS_IPV4*)0;
|
||||
req.RemoteAddressOut = src ? &remote : (SYS_SOCKET_ADDRESS*)0;
|
||||
req.RemoteAddressSizeInOut = src ? &remoteSize : (size_t*)0;
|
||||
req.ReceivedOut = &got;
|
||||
|
||||
@@ -408,21 +570,36 @@ static unsigned ParsePort(const char* s) {
|
||||
return *s == '\0' ? v : 0;
|
||||
}
|
||||
|
||||
// Implements the resolve Name Ipv4 operation.
|
||||
static int ResolveNameIpv4(const char* name, SYS_SOCKET_ADDRESS_IPV4* out) {
|
||||
uint8_t b[4];
|
||||
if (ParseIpv4Bytes(name, b)) {
|
||||
memset(out, 0, sizeof(*out));
|
||||
out->Family = SYS_AF_INET;
|
||||
out->Address[0] = b[0]; out->Address[1] = b[1]; out->Address[2] = b[2]; out->Address[3] = b[3];
|
||||
return 0;
|
||||
// Implements the resolve Name operation.
|
||||
static int ResolveNameFamily(const char* name, int family, SYS_SOCKET_ADDRESS* out) {
|
||||
if (!name || !out) { errno = EINVAL; return -1; }
|
||||
memset(out, 0, sizeof(*out));
|
||||
out->Size = sizeof(*out);
|
||||
|
||||
if (family == AF_INET) {
|
||||
uint8_t b[4];
|
||||
if (ParseIpv4Bytes(name, b)) {
|
||||
out->Family = SYS_AF_INET;
|
||||
memcpy(out->Address, b, 4);
|
||||
return 0;
|
||||
}
|
||||
} else if (family == AF_INET6) {
|
||||
uint8_t b[16];
|
||||
if (ParseIpv6Bytes(name, b)) {
|
||||
out->Family = SYS_AF_INET6;
|
||||
memcpy(out->Address, b, 16);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
errno = EAFNOSUPPORT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t size = sizeof(*out);
|
||||
SYS_RESOLVE_HOST_REQUEST req;
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.Name = SysSvFromCstr(name);
|
||||
req.Family = SYS_AF_INET;
|
||||
req.Family = family == AF_INET6 ? SYS_AF_INET6 : SYS_AF_INET;
|
||||
req.AddressOut = out;
|
||||
req.AddressSizeInOut = &size;
|
||||
uint32_t s = SysResolveHost(&req);
|
||||
@@ -430,6 +607,16 @@ static int ResolveNameIpv4(const char* name, SYS_SOCKET_ADDRESS_IPV4* out) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ResolveNameAny(const char* name, int family, SYS_SOCKET_ADDRESS* out) {
|
||||
if (family == AF_INET || family == AF_INET6)
|
||||
return ResolveNameFamily(name, family, out);
|
||||
if (family != AF_UNSPEC) { errno = EAFNOSUPPORT; return -1; }
|
||||
|
||||
if (ResolveNameFamily(name, AF_INET6, out) == 0)
|
||||
return 0;
|
||||
return ResolveNameFamily(name, AF_INET, out);
|
||||
}
|
||||
|
||||
// Implements the gethostbyname operation.
|
||||
__declspec(dllexport) struct hostent* gethostbyname(const char* name) {
|
||||
static struct hostent h;
|
||||
@@ -440,8 +627,8 @@ __declspec(dllexport) struct hostent* gethostbyname(const char* name) {
|
||||
|
||||
if (!name || strlen(name) >= sizeof(hname)) { errno = EINVAL; return (struct hostent*)0; }
|
||||
|
||||
SYS_SOCKET_ADDRESS_IPV4 a;
|
||||
if (ResolveNameIpv4(name, &a) != 0) return (struct hostent*)0;
|
||||
SYS_SOCKET_ADDRESS a;
|
||||
if (ResolveNameFamily(name, AF_INET, &a) != 0) return (struct hostent*)0;
|
||||
|
||||
strcpy(hname, name);
|
||||
memcpy(addr, a.Address, 4);
|
||||
@@ -462,35 +649,34 @@ __declspec(dllexport) int getaddrinfo(const char* node, const char* service,
|
||||
if (!res) return EINVAL;
|
||||
*res = (struct addrinfo*)0;
|
||||
|
||||
int family = hints ? hints->ai_family : AF_INET;
|
||||
if (family != AF_INET && family != 0) return EINVAL;
|
||||
int family = hints ? hints->ai_family : AF_UNSPEC;
|
||||
if (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC) return EAFNOSUPPORT;
|
||||
|
||||
SYS_SOCKET_ADDRESS_IPV4 a;
|
||||
SYS_SOCKET_ADDRESS a;
|
||||
memset(&a, 0, sizeof(a));
|
||||
a.Family = SYS_AF_INET;
|
||||
a.Size = sizeof(a);
|
||||
if (!node) {
|
||||
a.Address[0] = 0; a.Address[1] = 0; a.Address[2] = 0; a.Address[3] = 0;
|
||||
} else if (ResolveNameIpv4(node, &a) != 0) {
|
||||
a.Family = family == AF_INET6 ? SYS_AF_INET6 : SYS_AF_INET;
|
||||
} else if (ResolveNameAny(node, family, &a) != 0) {
|
||||
return errno;
|
||||
}
|
||||
a.Port = service ? ParsePort(service) : 0;
|
||||
|
||||
size_t total = sizeof(struct addrinfo) + sizeof(struct sockaddr_in);
|
||||
socklen_t addrLen = a.Family == SYS_AF_INET6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
|
||||
size_t total = sizeof(struct addrinfo) + addrLen;
|
||||
struct addrinfo* ai = (struct addrinfo*)malloc(total);
|
||||
if (!ai) return ENOMEM;
|
||||
memset(ai, 0, total);
|
||||
|
||||
struct sockaddr_in* sin = (struct sockaddr_in*)((uint8_t*)ai + sizeof(struct addrinfo));
|
||||
sin->sin_family = AF_INET;
|
||||
sin->sin_port = htons(a.Port);
|
||||
uint8_t* p = (uint8_t*)&sin->sin_addr.s_addr;
|
||||
p[0] = a.Address[0]; p[1] = a.Address[1]; p[2] = a.Address[2]; p[3] = a.Address[3];
|
||||
struct sockaddr* sa = (struct sockaddr*)((uint8_t*)ai + sizeof(struct addrinfo));
|
||||
socklen_t cap = addrLen;
|
||||
SysToSockAddr(&a, sa, &cap);
|
||||
|
||||
ai->ai_family = AF_INET;
|
||||
ai->ai_family = a.Family == SYS_AF_INET6 ? AF_INET6 : AF_INET;
|
||||
ai->ai_socktype = hints ? hints->ai_socktype : 0;
|
||||
ai->ai_protocol = hints ? hints->ai_protocol : 0;
|
||||
ai->ai_addrlen = sizeof(struct sockaddr_in);
|
||||
ai->ai_addr = (struct sockaddr*)sin;
|
||||
ai->ai_addrlen = cap;
|
||||
ai->ai_addr = sa;
|
||||
ai->ai_next = (struct addrinfo*)0;
|
||||
*res = ai;
|
||||
return 0;
|
||||
|
||||
Reference in new issue
Block a user