Files
nt-lite/code/user/personalities/posix/posix_io.c
T

224 lines
7.0 KiB
C

// POSIX compatibility support for posix io.
#include <stddef.h>
#include <string.h>
#include <ntlite/syscall.h>
#include "posix.h"
#include "posix_fd.h"
#include "posix_path.h"
// Implements the clearscreen operation.
__declspec(dllexport) void clearscreen(void) {
SysClearScreen(0x012456);
}
// Implements the clearkeyboard operation.
__declspec(dllexport) void clearkeyboard(void) {
INPUT_KEY key;
while (SysPollKeyboard(&key) == NTLSTATUS_SUCCESS) {
char ignored;
(void)SysReadKeyboardChar(&ignored);
}
}
// Opens the requested operation.
__declspec(dllexport) int open(const char* path, int flags, ...) {
char native[512];
const char* p = PosixTranslatePath(path, native, sizeof(native));
uint32_t pid = SysGetCurrentPid();
FD_TYPE type = FD_FILE;
// 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 disposition = SYS_FILE_OPEN_EXISTING;
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) {
SysCloseHandle(kh); // FdAlloc already set errno
return -1;
}
return fd;
}
// Returns the requested value.
__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;
switch (e->Type) {
case FD_CONSOLE_R: {
// Read up to count chars from keyboard, blocking per char.
char* dst = (char*)buf;
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);
}
return (ssize_t)count;
}
case FD_DEVNULL:
return 0;
case FD_DEVZERO:
memset(buf, 0, count);
return (ssize_t)count;
case FD_FILE: {
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;
}
case FD_SOCKET: {
size_t got = 0;
uint32_t s = SysRecvSocket(e->KHandle, buf, count, 0, &got);
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
return (ssize_t)got;
}
default:
errno = EBADF;
return -1;
}
}
// Updates the requested value.
__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;
switch (e->Type) {
case FD_CONSOLE_W: {
SYS_WRITE_CONSOLE_REQUEST req = { SysSvFromParts((const char*)buf, count) };
SysWriteConsole(&req);
return (ssize_t)count;
}
case FD_DEVNULL:
case FD_DEVZERO:
return (ssize_t)count;
case FD_FILE: {
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;
}
case FD_SOCKET: {
size_t sent = 0;
uint32_t s = SysSendSocket(e->KHandle, buf, count, 0, &sent);
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
return (ssize_t)sent;
}
default:
errno = EBADF;
return -1;
}
}
// Releases the requested object.
__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 0;
}
// Implements the unlink operation.
__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;
}
SYS_PATH_REQUEST req = { SysSvFromCstr(p) };
uint32_t s = SysDeleteFile(&req);
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
return 0;
}
// Implements the lseek operation.
__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;
}
if (target < 0 || target > 0x7FFFFFFFLL) { errno = EINVAL; return -1; }
uint32_t s = SysSeekFile(e->KHandle, (uint64_t)target);
if (s != 0) { errno = PosixStatusToErrno(s); return -1; }
return (off_t)target;
}