555 lines
19 KiB
C
555 lines
19 KiB
C
// 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_internal.h"
|
|
#include "posix_fd.h"
|
|
#include "posix_path.h"
|
|
|
|
// Returns whether one open description permits reading.
|
|
static bool PosixDescriptionReadable(const POSIX_OPEN_DESCRIPTION* description) {
|
|
return description && (PosixFdGetStatusFlags(description) & O_ACCMODE) != O_WRONLY;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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));
|
|
|
|
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);
|
|
|
|
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_ACCMODE) == O_RDWR)
|
|
access |= SYS_FILE_ACCESS_READ | SYS_FILE_ACCESS_WRITE;
|
|
else if ((flags & O_ACCMODE) == 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;
|
|
|
|
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;
|
|
}
|
|
|
|
// 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;
|
|
if (!buf) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
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 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;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case PosixFdDevNull:
|
|
result = 0;
|
|
break;
|
|
case PosixFdDevZero:
|
|
memset(buf, 0, count);
|
|
result = (ssize_t)count;
|
|
break;
|
|
case PosixFdFile: {
|
|
size_t got = 0;
|
|
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 PosixFdPipeRead:
|
|
result = PosixPipeRead(description, buf, count);
|
|
break;
|
|
case PosixFdSocket: {
|
|
size_t got = 0;
|
|
SYS_SOCKET_RECV_REQUEST request = {
|
|
sizeof(SYS_SOCKET_RECV_REQUEST), description->KHandle, 0,
|
|
buf, count, &got
|
|
};
|
|
uint32_t status = SysRecvSocket(&request);
|
|
if (status != NTLSTATUS_SUCCESS)
|
|
errno = PosixStatusToErrno(status);
|
|
else
|
|
result = (ssize_t)got;
|
|
break;
|
|
}
|
|
default:
|
|
errno = EBADF;
|
|
break;
|
|
}
|
|
|
|
PosixFdRelease(description);
|
|
return result;
|
|
}
|
|
|
|
// 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;
|
|
if (!buf) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
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;
|
|
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 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), description->KHandle, 0,
|
|
buf, count, &sent
|
|
};
|
|
uint32_t status = SysSendSocket(&request);
|
|
if (status != NTLSTATUS_SUCCESS)
|
|
errno = PosixStatusToErrno(status);
|
|
else
|
|
result = (ssize_t)sent;
|
|
break;
|
|
}
|
|
default:
|
|
errno = EBADF;
|
|
break;
|
|
}
|
|
|
|
PosixFdRelease(description);
|
|
return result;
|
|
}
|
|
|
|
// Closes one descriptor without invalidating concurrent open-description users.
|
|
__declspec(dllexport) int close(int 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;
|
|
}
|
|
|
|
// 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 status = NtlDeleteFile(SysSvFromCstr(p));
|
|
if (status != NTLSTATUS_SUCCESS) {
|
|
errno = PosixStatusToErrno(status);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Repositions the shared file offset owned by an open description.
|
|
__declspec(dllexport) off_t lseek(int fd, off_t offset, int whence) {
|
|
POSIX_OPEN_DESCRIPTION* description = PosixFdAcquire(fd);
|
|
if (!description)
|
|
return -1;
|
|
if (description->Type != PosixFdFile) {
|
|
PosixFdRelease(description);
|
|
errno = ESPIPE;
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|