978 lines
37 KiB
C
978 lines
37 KiB
C
// POSIX descriptor table and shared open-description implementation.
|
|
|
|
#include <stdarg.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <intrin.h>
|
|
#include <ntlite/syscall.h>
|
|
#include "posix_internal.h"
|
|
#include "posix_fd.h"
|
|
|
|
// Maps one native status to the POSIX personality errno space.
|
|
int PosixStatusToErrno(uint32_t s) {
|
|
switch (s) {
|
|
case NTLSTATUS_SUCCESS: return 0;
|
|
case NTLSTATUS_TIMEOUT: return ETIMEDOUT;
|
|
case NTLSTATUS_PENDING: return EINPROGRESS;
|
|
case NTLSTATUS_ALERTED:
|
|
case NTLSTATUS_KERNEL_APC:
|
|
case NTLSTATUS_USER_APC: return EINTR;
|
|
case NTLSTATUS_ABANDONED: return EIO;
|
|
|
|
case NTLSTATUS_FAILURE: return EIO;
|
|
case NTLSTATUS_NOT_SUPPORTED: return ENOSYS;
|
|
case NTLSTATUS_INVALID_PARAMETER: return EINVAL;
|
|
case NTLSTATUS_INVALID_HANDLE: return EBADF;
|
|
case NTLSTATUS_BUFFER_TOO_SMALL: return ERANGE;
|
|
case NTLSTATUS_CHECKSUM_MISMATCH: return EIO;
|
|
case NTLSTATUS_NO_MEMORY: return ENOMEM;
|
|
case NTLSTATUS_ACCESS_DENIED: return EACCES;
|
|
case NTLSTATUS_NOT_FOUND: return ENOENT;
|
|
case NTLSTATUS_ALREADY_EXISTS:
|
|
case NTLSTATUS_OBJECT_NAME_COLLISION: return EEXIST;
|
|
case NTLSTATUS_OBJECT_DEAD: return ECONNRESET;
|
|
case NTLSTATUS_QUEUE_FULL:
|
|
case NTLSTATUS_QUEUE_EMPTY:
|
|
case NTLSTATUS_WOULD_BLOCK: return EAGAIN;
|
|
case NTLSTATUS_CANCELLED: return ECANCELED;
|
|
case NTLSTATUS_DEVICE_ERROR: return EIO;
|
|
case NTLSTATUS_NO_MORE_FILES: return ENOENT;
|
|
case NTLSTATUS_INVALID_IRQL: return EIO;
|
|
case NTLSTATUS_DEADLOCK: return EDEADLK;
|
|
case NTLSTATUS_DEVICE_REMOVED: return ENODEV;
|
|
case NTLSTATUS_ID_EXHAUSTED:
|
|
case NTLSTATUS_LIMIT_REACHED: return EAGAIN;
|
|
case NTLSTATUS_CAPABILITY_REVOKED: return EBADF;
|
|
case NTLSTATUS_PORT_DISCONNECTED: return ECONNRESET;
|
|
case NTLSTATUS_BROKEN_PIPE: return EPIPE;
|
|
|
|
case NTLSTATUS_NOT_A_DIRECTORY: return ENOTDIR;
|
|
case NTLSTATUS_IS_A_DIRECTORY: return EISDIR;
|
|
case NTLSTATUS_DIRECTORY_NOT_EMPTY: return ENOTEMPTY;
|
|
case NTLSTATUS_CROSS_DEVICE: return EXDEV;
|
|
case NTLSTATUS_NO_CHILD: return ECHILD;
|
|
case NTLSTATUS_INVALID_IMAGE_FORMAT: return ENOEXEC;
|
|
case NTLSTATUS_NAME_TOO_LONG: return ENAMETOOLONG;
|
|
case NTLSTATUS_TOO_MANY_LINKS: return EMLINK;
|
|
case NTLSTATUS_READ_ONLY_FILESYSTEM: return EROFS;
|
|
case NTLSTATUS_FILE_TOO_LARGE: return EFBIG;
|
|
|
|
case NTLSTATUS_PROCESS_KILLED: return EINTR;
|
|
case NTLSTATUS_PROCESS_PAGE_FAULT: return EFAULT;
|
|
case NTLSTATUS_PROCESS_GENERAL_PROTECTION:
|
|
case NTLSTATUS_PROCESS_ILLEGAL_OPCODE:
|
|
case NTLSTATUS_PROCESS_DIVIDE_BY_ZERO:
|
|
case NTLSTATUS_PROCESS_BREAKPOINT:
|
|
case NTLSTATUS_PROCESS_ALIGNMENT_FAULT:
|
|
case NTLSTATUS_PROCESS_USER_EXCEPTION:
|
|
case NTLSTATUS_PROCESS_UNKNOWN_FAULT: return EIO;
|
|
default: return EIO;
|
|
}
|
|
}
|
|
|
|
// Locks the process descriptor table.
|
|
static int PosixFdLock(POSIX_PROCESS_STATE* process) {
|
|
if (!process || process->FdLock == SYS_HANDLE_INVALID) {
|
|
errno = EIO;
|
|
return -1;
|
|
}
|
|
uint32_t status = SysWait(process->FdLock, SYS_WAIT_FLAG_NONE);
|
|
if (status != NTLSTATUS_SUCCESS) {
|
|
errno = PosixStatusToErrno(status);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Unlocks the process descriptor table.
|
|
static void PosixFdUnlock(POSIX_PROCESS_STATE* process) {
|
|
uint32_t status = SysReleaseMutex(process->FdLock);
|
|
if (status != NTLSTATUS_SUCCESS)
|
|
errno = PosixStatusToErrno(status);
|
|
}
|
|
|
|
// Returns whether one open-description type requires a retained native capability.
|
|
static int PosixOpenDescriptionNeedsHandle(POSIX_FD_TYPE type) {
|
|
return type == PosixFdFile || type == PosixFdSocket ||
|
|
type == PosixFdPipeRead || type == PosixFdPipeWrite;
|
|
}
|
|
|
|
// Derives the rights retained by posixsrv's master capability for one description.
|
|
static SYS_RIGHTS PosixOpenDescriptionMasterRights(POSIX_FD_TYPE type, int statusFlags) {
|
|
SYS_RIGHTS rights = SYS_RIGHT_TRANSFER | SYS_RIGHT_QUERY;
|
|
if (type == PosixFdFile) {
|
|
rights |= SYS_FILE_RIGHT_LOCK;
|
|
int access = statusFlags & O_ACCMODE;
|
|
if (access == O_RDONLY || access == O_RDWR)
|
|
rights |= SYS_FILE_RIGHT_READ_DATA | SYS_FILE_RIGHT_MAP_READ;
|
|
if (access == O_WRONLY || access == O_RDWR)
|
|
rights |= SYS_FILE_RIGHT_WRITE_DATA | SYS_FILE_RIGHT_MAP_WRITE;
|
|
} else if (type == PosixFdSocket) {
|
|
rights |= SYS_SOCKET_RIGHT_BIND | SYS_SOCKET_RIGHT_CONNECT | SYS_SOCKET_RIGHT_LISTEN |
|
|
SYS_SOCKET_RIGHT_ACCEPT | SYS_SOCKET_RIGHT_SEND | SYS_SOCKET_RIGHT_RECEIVE |
|
|
SYS_SOCKET_RIGHT_SHUTDOWN | SYS_SOCKET_RIGHT_POLL |
|
|
SYS_SOCKET_RIGHT_SET_OPTION;
|
|
} else if (type == PosixFdPipeRead) {
|
|
rights |= SYS_RIGHT_WAIT | SYS_PIPE_RIGHT_READ | SYS_PIPE_RIGHT_POLL;
|
|
} else if (type == PosixFdPipeWrite) {
|
|
rights |= SYS_RIGHT_WAIT | SYS_PIPE_RIGHT_WRITE | SYS_PIPE_RIGHT_POLL;
|
|
}
|
|
return rights;
|
|
}
|
|
|
|
// Best-effort release of one server-owned open description after local teardown/failure.
|
|
void PosixFdReleaseServerDescription(uint64_t descriptionId) {
|
|
if (descriptionId == 0) return;
|
|
NTL_POSIX_REQUEST request;
|
|
memset(&request, 0, sizeof(request));
|
|
request.Size = sizeof(request);
|
|
request.Version = NTL_POSIX_PROTOCOL_VERSION;
|
|
request.Operation = NTL_POSIX_OP_RELEASE_OPEN_DESCRIPTION;
|
|
request.Flags = NTL_POSIX_REQUEST_FLAG_NONE;
|
|
request.OpenDescriptionId = descriptionId;
|
|
NTL_POSIX_REPLY reply;
|
|
(void)PosixRuntimeCallServer(&request, &reply);
|
|
}
|
|
|
|
// Captures process-local descriptor numbers/flags while posixsrv pins unique descriptions.
|
|
KSTATUS PosixFdCreateInheritanceSnapshot(uint32_t flags, uint64_t* tokenOut) {
|
|
if (!tokenOut || (flags & ~POSIX_FD_INHERIT_SKIP_CLOEXEC) != 0)
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
*tokenOut = 0;
|
|
POSIX_PROCESS_STATE* process = PosixRuntimeProcessState();
|
|
if (!process) return NTLSTATUS_NOT_FOUND;
|
|
if (PosixFdLock(process) != 0) return NTLSTATUS_FAILURE;
|
|
|
|
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_FD_INHERITANCE;
|
|
request.Flags = NTL_POSIX_REQUEST_FLAG_NONE;
|
|
request.FdInheritanceFlags = NTL_POSIX_FD_INHERIT_FLAG_NONE;
|
|
for (int fd = 0; fd < POSIX_FD_MAX; ++fd) {
|
|
POSIX_OPEN_DESCRIPTION* description = process->FdTable[fd].Description;
|
|
if (!description) continue;
|
|
int descriptorFlags = process->FdTable[fd].DescriptorFlags & FD_CLOEXEC;
|
|
if ((flags & POSIX_FD_INHERIT_SKIP_CLOEXEC) && (descriptorFlags & FD_CLOEXEC))
|
|
continue;
|
|
uint32_t index = request.FdInheritanceCount++;
|
|
request.FdManifest[index].Descriptor = fd;
|
|
request.FdManifest[index].DescriptorFlags = (uint32_t)descriptorFlags;
|
|
request.FdManifest[index].OpenDescriptionId = description->DescriptionId;
|
|
}
|
|
|
|
NTL_POSIX_REPLY reply;
|
|
KSTATUS status = PosixRuntimeCallServer(&request, &reply);
|
|
PosixFdUnlock(process);
|
|
if (!KSUCCESS(status)) return status;
|
|
if (!KSUCCESS(reply.Status)) return reply.Status;
|
|
if (reply.FdInheritanceToken == 0 ||
|
|
reply.FdInheritanceCount != request.FdInheritanceCount) {
|
|
if (reply.FdInheritanceToken != 0)
|
|
PosixFdCancelInheritanceSnapshot(reply.FdInheritanceToken);
|
|
return NTLSTATUS_FAILURE;
|
|
}
|
|
*tokenOut = reply.FdInheritanceToken;
|
|
return NTLSTATUS_SUCCESS;
|
|
}
|
|
|
|
// Arms one snapshot to a concrete native child lifetime before the parent returns from spawn.
|
|
KSTATUS PosixFdArmInheritanceSnapshot(uint64_t token, SYS_HANDLE processHandle) {
|
|
if (token == 0 || processHandle == SYS_HANDLE_INVALID) 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_ARM_FD_INHERITANCE;
|
|
request.Flags = NTL_POSIX_REQUEST_FLAG_NONE;
|
|
request.FdInheritanceToken = token;
|
|
|
|
SYS_PORT_HANDLE_TRANSFER transfer;
|
|
memset(&transfer, 0, sizeof(transfer));
|
|
transfer.Handle = processHandle;
|
|
transfer.DesiredRights = SYS_RIGHT_QUERY | SYS_RIGHT_WAIT;
|
|
transfer.Flags = SYS_PORT_TRANSFER_FLAG_NONE;
|
|
|
|
NTL_POSIX_REPLY reply;
|
|
KSTATUS status = PosixRuntimeCallServerWithHandles(&request, &transfer, 1u, &reply);
|
|
if (!KSUCCESS(status)) return status;
|
|
return reply.Status;
|
|
}
|
|
|
|
// Cancels one snapshot when native process construction failed before a child could claim it.
|
|
void PosixFdCancelInheritanceSnapshot(uint64_t token) {
|
|
if (token == 0) return;
|
|
NTL_POSIX_REQUEST request;
|
|
memset(&request, 0, sizeof(request));
|
|
request.Size = sizeof(request);
|
|
request.Version = NTL_POSIX_PROTOCOL_VERSION;
|
|
request.Operation = NTL_POSIX_OP_CANCEL_FD_INHERITANCE;
|
|
request.Flags = NTL_POSIX_REQUEST_FLAG_NONE;
|
|
request.FdInheritanceToken = token;
|
|
NTL_POSIX_REPLY reply;
|
|
(void)PosixRuntimeCallServer(&request, &reply);
|
|
}
|
|
|
|
// Allocates one local wrapper backed by one posixsrv-owned shared open description.
|
|
static POSIX_OPEN_DESCRIPTION* PosixOpenDescriptionCreate(POSIX_FD_TYPE type,
|
|
uint32_t khandle,
|
|
int statusFlags) {
|
|
if ((PosixOpenDescriptionNeedsHandle(type) && khandle == SYS_HANDLE_INVALID) ||
|
|
(!PosixOpenDescriptionNeedsHandle(type) && khandle != SYS_HANDLE_INVALID)) {
|
|
errno = EINVAL;
|
|
return (POSIX_OPEN_DESCRIPTION*)0;
|
|
}
|
|
|
|
POSIX_OPEN_DESCRIPTION* description =
|
|
(POSIX_OPEN_DESCRIPTION*)calloc(1, sizeof(*description));
|
|
if (!description) {
|
|
errno = ENOMEM;
|
|
return (POSIX_OPEN_DESCRIPTION*)0;
|
|
}
|
|
|
|
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_OPEN_DESCRIPTION;
|
|
request.Flags = NTL_POSIX_REQUEST_FLAG_NONE;
|
|
request.OpenDescriptionType = (uint32_t)type;
|
|
request.OpenStatusFlags = (uint32_t)statusFlags;
|
|
|
|
SYS_PORT_HANDLE_TRANSFER transfer;
|
|
memset(&transfer, 0, sizeof(transfer));
|
|
const SYS_PORT_HANDLE_TRANSFER* transfers = (const SYS_PORT_HANDLE_TRANSFER*)0;
|
|
uint32_t transferCount = 0;
|
|
if (PosixOpenDescriptionNeedsHandle(type)) {
|
|
transfer.Handle = khandle;
|
|
transfer.DesiredRights = PosixOpenDescriptionMasterRights(type, statusFlags);
|
|
transfer.Flags = SYS_PORT_TRANSFER_FLAG_NONE;
|
|
transfers = &transfer;
|
|
transferCount = 1;
|
|
}
|
|
|
|
NTL_POSIX_REPLY reply;
|
|
KSTATUS status = PosixRuntimeCallServerWithHandles(&request, transfers, transferCount, &reply);
|
|
if (!KSUCCESS(status) || !KSUCCESS(reply.Status)) {
|
|
errno = PosixStatusToErrno(KSUCCESS(status) ? reply.Status : status);
|
|
free(description);
|
|
return (POSIX_OPEN_DESCRIPTION*)0;
|
|
}
|
|
|
|
NTL_POSIX_SHARED_OPEN_DESCRIPTION* shared =
|
|
(NTL_POSIX_SHARED_OPEN_DESCRIPTION*)(uintptr_t)reply.SharedOpenDescription;
|
|
if (!shared || reply.OpenDescriptionId == 0 || reply.OpenDescriptionType != (uint32_t)type ||
|
|
shared->Magic != NTL_POSIX_SHARED_OPEN_MAGIC ||
|
|
shared->Version != NTL_POSIX_SHARED_OPEN_VERSION || shared->Reserved != 0 ||
|
|
shared->Reserved2 != 0 || shared->SharedObjectData != 0 ||
|
|
shared->DescriptionId != reply.OpenDescriptionId ||
|
|
shared->Type != (uint32_t)type) {
|
|
PosixFdReleaseServerDescription(reply.OpenDescriptionId);
|
|
errno = EIO;
|
|
free(description);
|
|
return (POSIX_OPEN_DESCRIPTION*)0;
|
|
}
|
|
|
|
description->RefCount = 1;
|
|
description->Type = type;
|
|
description->KHandle = khandle;
|
|
description->DescriptionId = reply.OpenDescriptionId;
|
|
description->Shared = shared;
|
|
return description;
|
|
}
|
|
|
|
// Adds one reference to an open description.
|
|
static void PosixFdReference(POSIX_OPEN_DESCRIPTION* description) {
|
|
if (description)
|
|
_InterlockedIncrement(&description->RefCount);
|
|
}
|
|
|
|
// Returns one atomic snapshot of server-owned shared open-description status flags.
|
|
int PosixFdGetStatusFlags(const POSIX_OPEN_DESCRIPTION* description) {
|
|
if (!description || !description->Shared)
|
|
return 0;
|
|
return (int)_InterlockedCompareExchange(
|
|
(volatile long*)&description->Shared->StatusFlags, 0, 0);
|
|
}
|
|
|
|
// Applies mutable status flags through posixsrv so native backing and shared state stay serialized.
|
|
int PosixFdSetStatusFlags(POSIX_OPEN_DESCRIPTION* description, int statusFlags) {
|
|
if (!description || !description->Shared || description->DescriptionId == 0) {
|
|
errno = EBADF;
|
|
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_SET_OPEN_STATUS;
|
|
request.Flags = NTL_POSIX_REQUEST_FLAG_NONE;
|
|
request.OpenDescriptionId = description->DescriptionId;
|
|
request.OpenStatusFlags = (uint32_t)statusFlags;
|
|
|
|
NTL_POSIX_REPLY reply;
|
|
KSTATUS status = PosixRuntimeCallServer(&request, &reply);
|
|
if (!KSUCCESS(status) || !KSUCCESS(reply.Status)) {
|
|
errno = PosixStatusToErrno(KSUCCESS(status) ? reply.Status : status);
|
|
return -1;
|
|
}
|
|
if (reply.OpenDescriptionId != description->DescriptionId ||
|
|
reply.OpenDescriptionType != (uint32_t)description->Type) {
|
|
errno = EIO;
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Releases one stable local wrapper and its server holder at the final reference.
|
|
void PosixFdRelease(POSIX_OPEN_DESCRIPTION* description) {
|
|
if (!description)
|
|
return;
|
|
if (_InterlockedDecrement(&description->RefCount) != 0)
|
|
return;
|
|
|
|
if (PosixOpenDescriptionNeedsHandle(description->Type) &&
|
|
description->KHandle != SYS_HANDLE_INVALID)
|
|
(void)SysCloseHandle(description->KHandle);
|
|
PosixFdReleaseServerDescription(description->DescriptionId);
|
|
free(description);
|
|
}
|
|
|
|
// Installs a description at the lowest free descriptor at or above minFd.
|
|
static int PosixFdInstall(POSIX_PROCESS_STATE* process,
|
|
POSIX_OPEN_DESCRIPTION* description,
|
|
int minFd,
|
|
int descriptorFlags) {
|
|
if (!process || !description || minFd < 0 || minFd >= POSIX_FD_MAX) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
if (PosixFdLock(process) != 0)
|
|
return -1;
|
|
|
|
int fd = -1;
|
|
for (int i = minFd; i < POSIX_FD_MAX; i++) {
|
|
if (!process->FdTable[i].Description) {
|
|
PosixFdReference(description);
|
|
process->FdTable[i].Description = description;
|
|
process->FdTable[i].DescriptorFlags = descriptorFlags & FD_CLOEXEC;
|
|
fd = i;
|
|
break;
|
|
}
|
|
}
|
|
PosixFdUnlock(process);
|
|
if (fd < 0)
|
|
errno = EMFILE;
|
|
return fd;
|
|
}
|
|
|
|
// Creates and installs one new open description.
|
|
int PosixFdCreate(POSIX_FD_TYPE type, uint32_t khandle, int statusFlags) {
|
|
POSIX_PROCESS_STATE* process = PosixRuntimeProcessState();
|
|
if (!process) {
|
|
errno = EIO;
|
|
return -1;
|
|
}
|
|
|
|
POSIX_OPEN_DESCRIPTION* description =
|
|
PosixOpenDescriptionCreate(type, khandle, statusFlags);
|
|
if (!description)
|
|
return -1;
|
|
|
|
int fd = PosixFdInstall(process, description, 3, 0);
|
|
PosixFdRelease(description);
|
|
return fd;
|
|
}
|
|
|
|
// Adopts one server-owned description into a process-local wrapper.
|
|
static POSIX_OPEN_DESCRIPTION* PosixOpenDescriptionImport(POSIX_FD_TYPE type,
|
|
uint32_t khandle,
|
|
uint64_t descriptionId,
|
|
NTL_POSIX_SHARED_OPEN_DESCRIPTION* shared) {
|
|
int needsHandle = PosixOpenDescriptionNeedsHandle(type);
|
|
int isPipe = type == PosixFdPipeRead || type == PosixFdPipeWrite;
|
|
if (descriptionId == 0 || !shared ||
|
|
(needsHandle && khandle == SYS_HANDLE_INVALID) ||
|
|
(!needsHandle && khandle != SYS_HANDLE_INVALID) ||
|
|
shared->Magic != NTL_POSIX_SHARED_OPEN_MAGIC ||
|
|
shared->Version != NTL_POSIX_SHARED_OPEN_VERSION || shared->Reserved != 0 ||
|
|
shared->Reserved2 != 0 || shared->DescriptionId != descriptionId ||
|
|
shared->Type != (uint32_t)type ||
|
|
(isPipe && shared->SharedObjectData == 0) ||
|
|
(!isPipe && shared->SharedObjectData != 0)) {
|
|
if (needsHandle && khandle != SYS_HANDLE_INVALID) (void)SysCloseHandle(khandle);
|
|
PosixFdReleaseServerDescription(descriptionId);
|
|
errno = EIO;
|
|
return (POSIX_OPEN_DESCRIPTION*)0;
|
|
}
|
|
POSIX_OPEN_DESCRIPTION* description =
|
|
(POSIX_OPEN_DESCRIPTION*)calloc(1, sizeof(*description));
|
|
if (!description) {
|
|
if (needsHandle) (void)SysCloseHandle(khandle);
|
|
PosixFdReleaseServerDescription(descriptionId);
|
|
errno = ENOMEM;
|
|
return (POSIX_OPEN_DESCRIPTION*)0;
|
|
}
|
|
description->RefCount = 1;
|
|
description->Type = type;
|
|
description->KHandle = khandle;
|
|
description->DescriptionId = descriptionId;
|
|
description->Shared = shared;
|
|
return description;
|
|
}
|
|
|
|
// 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) {
|
|
POSIX_PROCESS_STATE* process = PosixRuntimeProcessState();
|
|
if (!process) { errno = EIO; return -1; }
|
|
POSIX_OPEN_DESCRIPTION* description =
|
|
PosixOpenDescriptionImport(type, khandle, descriptionId, shared);
|
|
if (!description) return -1;
|
|
int fd = PosixFdInstall(process, description, 3, descriptorFlags);
|
|
PosixFdRelease(description);
|
|
return fd;
|
|
}
|
|
|
|
// Acquires a stable reference to the open description backing fd.
|
|
POSIX_OPEN_DESCRIPTION* PosixFdAcquire(int fd) {
|
|
POSIX_PROCESS_STATE* process = PosixRuntimeProcessState();
|
|
if (!process || fd < 0 || fd >= POSIX_FD_MAX) {
|
|
errno = EBADF;
|
|
return (POSIX_OPEN_DESCRIPTION*)0;
|
|
}
|
|
if (PosixFdLock(process) != 0)
|
|
return (POSIX_OPEN_DESCRIPTION*)0;
|
|
|
|
POSIX_OPEN_DESCRIPTION* description = process->FdTable[fd].Description;
|
|
if (description)
|
|
PosixFdReference(description);
|
|
PosixFdUnlock(process);
|
|
|
|
if (!description)
|
|
errno = EBADF;
|
|
return description;
|
|
}
|
|
|
|
// Removes one descriptor and releases its table-owned reference.
|
|
int PosixFdClose(int fd) {
|
|
POSIX_PROCESS_STATE* process = PosixRuntimeProcessState();
|
|
if (!process || fd < 0 || fd >= POSIX_FD_MAX) {
|
|
errno = EBADF;
|
|
return -1;
|
|
}
|
|
if (PosixFdLock(process) != 0)
|
|
return -1;
|
|
|
|
POSIX_OPEN_DESCRIPTION* description = process->FdTable[fd].Description;
|
|
if (!description) {
|
|
PosixFdUnlock(process);
|
|
errno = EBADF;
|
|
return -1;
|
|
}
|
|
process->FdTable[fd].Description = (POSIX_OPEN_DESCRIPTION*)0;
|
|
process->FdTable[fd].DescriptorFlags = 0;
|
|
PosixFdUnlock(process);
|
|
PosixFdRelease(description);
|
|
return 0;
|
|
}
|
|
|
|
// Installs one fixed standard descriptor during process initialization.
|
|
static uint32_t PosixFdInstallStandard(POSIX_PROCESS_STATE* process,
|
|
int fd,
|
|
POSIX_FD_TYPE type,
|
|
int statusFlags) {
|
|
POSIX_OPEN_DESCRIPTION* description =
|
|
PosixOpenDescriptionCreate(type, SYS_HANDLE_INVALID, statusFlags);
|
|
if (!description)
|
|
return NTLSTATUS_NO_MEMORY;
|
|
|
|
PosixFdReference(description);
|
|
process->FdTable[fd].Description = description;
|
|
process->FdTable[fd].DescriptorFlags = 0;
|
|
PosixFdRelease(description);
|
|
return NTLSTATUS_SUCCESS;
|
|
}
|
|
|
|
// Reconstructs one exact descriptor table from a server-owned inheritance snapshot.
|
|
static uint32_t PosixFdImportInheritance(POSIX_PROCESS_STATE* process, uint64_t token) {
|
|
if (!process || token == 0) return NTLSTATUS_INVALID_PARAMETER;
|
|
|
|
NTL_POSIX_FD_MANIFEST_ENTRY manifest[NTL_POSIX_FD_INHERIT_MAX];
|
|
memset(manifest, 0, sizeof(manifest));
|
|
uint32_t manifestCount = UINT32_MAX;
|
|
POSIX_OPEN_DESCRIPTION* descriptions[NTL_POSIX_FD_INHERIT_MAX];
|
|
uint64_t descriptionIds[NTL_POSIX_FD_INHERIT_MAX];
|
|
memset(descriptions, 0, sizeof(descriptions));
|
|
memset(descriptionIds, 0, sizeof(descriptionIds));
|
|
uint32_t descriptionCount = 0;
|
|
uint32_t descriptionIndex = 0;
|
|
uint32_t descriptionTotal = UINT32_MAX;
|
|
uint32_t result = NTLSTATUS_SUCCESS;
|
|
|
|
for (;;) {
|
|
NTL_POSIX_REQUEST request;
|
|
memset(&request, 0, sizeof(request));
|
|
request.Size = sizeof(request);
|
|
request.Version = NTL_POSIX_PROTOCOL_VERSION;
|
|
request.Operation = NTL_POSIX_OP_IMPORT_FD_INHERITANCE;
|
|
request.Flags = NTL_POSIX_REQUEST_FLAG_NONE;
|
|
request.FdInheritanceToken = token;
|
|
request.FdInheritanceIndex = descriptionIndex;
|
|
|
|
SYS_HANDLE handles[NTL_POSIX_FD_IMPORT_BATCH_MAX];
|
|
for (uint32_t i = 0; i < NTL_POSIX_FD_IMPORT_BATCH_MAX; ++i)
|
|
handles[i] = SYS_HANDLE_INVALID;
|
|
uint32_t handleCount = 0;
|
|
NTL_POSIX_REPLY reply;
|
|
KSTATUS status = PosixRuntimeCallServerExchangeVariable(
|
|
&request, handles, NTL_POSIX_FD_IMPORT_BATCH_MAX, &handleCount, &reply);
|
|
if (!KSUCCESS(status) || !KSUCCESS(reply.Status)) {
|
|
result = KSUCCESS(status) ? reply.Status : status;
|
|
for (uint32_t i = 0; i < handleCount; ++i)
|
|
if (handles[i] != SYS_HANDLE_INVALID) (void)SysCloseHandle(handles[i]);
|
|
break;
|
|
}
|
|
if (reply.FdInheritanceToken != token || reply.FdInheritanceIndex != descriptionIndex ||
|
|
reply.FdInheritanceCount > NTL_POSIX_FD_INHERIT_MAX ||
|
|
reply.FdDescriptionIndex != descriptionIndex ||
|
|
reply.FdDescriptionCount > NTL_POSIX_FD_IMPORT_BATCH_MAX ||
|
|
reply.FdDescriptionTotal > NTL_POSIX_FD_INHERIT_MAX ||
|
|
descriptionIndex + reply.FdDescriptionCount > reply.FdDescriptionTotal) {
|
|
result = NTLSTATUS_FAILURE;
|
|
for (uint32_t i = 0; i < handleCount; ++i)
|
|
if (handles[i] != SYS_HANDLE_INVALID) (void)SysCloseHandle(handles[i]);
|
|
break;
|
|
}
|
|
|
|
if (manifestCount == UINT32_MAX) {
|
|
manifestCount = reply.FdInheritanceCount;
|
|
memcpy(manifest, reply.FdManifest, sizeof(manifest));
|
|
descriptionTotal = reply.FdDescriptionTotal;
|
|
} else if (manifestCount != reply.FdInheritanceCount ||
|
|
descriptionTotal != reply.FdDescriptionTotal ||
|
|
memcmp(manifest, reply.FdManifest, sizeof(manifest)) != 0) {
|
|
result = NTLSTATUS_FAILURE;
|
|
for (uint32_t i = 0; i < handleCount; ++i)
|
|
if (handles[i] != SYS_HANDLE_INVALID) (void)SysCloseHandle(handles[i]);
|
|
break;
|
|
}
|
|
|
|
uint8_t handleUsed[NTL_POSIX_FD_IMPORT_BATCH_MAX];
|
|
memset(handleUsed, 0, sizeof(handleUsed));
|
|
for (uint32_t i = 0; i < reply.FdDescriptionCount; ++i) {
|
|
NTL_POSIX_FD_DESCRIPTION_ENTRY* entry = &reply.FdDescriptions[i];
|
|
if (entry->Reserved != 0 || entry->OpenDescriptionId == 0 ||
|
|
entry->OpenDescriptionType < NTL_POSIX_OPEN_TYPE_FILE ||
|
|
entry->OpenDescriptionType > NTL_POSIX_OPEN_TYPE_PIPE_WRITE ||
|
|
descriptionCount >= NTL_POSIX_FD_INHERIT_MAX) {
|
|
result = NTLSTATUS_FAILURE;
|
|
break;
|
|
}
|
|
for (uint32_t j = 0; j < descriptionCount; ++j) {
|
|
if (descriptionIds[j] == entry->OpenDescriptionId) { result = NTLSTATUS_FAILURE; break; }
|
|
}
|
|
if (!KSUCCESS(result)) break;
|
|
POSIX_FD_TYPE type = (POSIX_FD_TYPE)entry->OpenDescriptionType;
|
|
int needsHandle = PosixOpenDescriptionNeedsHandle(type);
|
|
SYS_HANDLE handle = SYS_HANDLE_INVALID;
|
|
if (needsHandle) {
|
|
if (entry->HandleIndex >= handleCount || handleUsed[entry->HandleIndex]) {
|
|
result = NTLSTATUS_FAILURE;
|
|
break;
|
|
}
|
|
handleUsed[entry->HandleIndex] = 1u;
|
|
handle = handles[entry->HandleIndex];
|
|
handles[entry->HandleIndex] = SYS_HANDLE_INVALID;
|
|
} else if (entry->HandleIndex != NTL_POSIX_FD_HANDLE_NONE) {
|
|
result = NTLSTATUS_FAILURE;
|
|
break;
|
|
}
|
|
POSIX_OPEN_DESCRIPTION* description = PosixOpenDescriptionImport(
|
|
type, handle, entry->OpenDescriptionId,
|
|
(NTL_POSIX_SHARED_OPEN_DESCRIPTION*)(uintptr_t)entry->SharedOpenDescription);
|
|
if (!description) { result = NTLSTATUS_FAILURE; break; }
|
|
descriptions[descriptionCount] = description;
|
|
descriptionIds[descriptionCount] = entry->OpenDescriptionId;
|
|
++descriptionCount;
|
|
}
|
|
for (uint32_t i = 0; i < handleCount; ++i) {
|
|
if (handles[i] != SYS_HANDLE_INVALID) {
|
|
(void)SysCloseHandle(handles[i]);
|
|
if (KSUCCESS(result)) result = NTLSTATUS_FAILURE;
|
|
}
|
|
}
|
|
if (!KSUCCESS(result)) break;
|
|
|
|
descriptionIndex += reply.FdDescriptionCount;
|
|
if (descriptionIndex == descriptionTotal) break;
|
|
if (reply.FdDescriptionCount == 0) { result = NTLSTATUS_FAILURE; break; }
|
|
}
|
|
|
|
if (KSUCCESS(result)) {
|
|
if (manifestCount == UINT32_MAX || descriptionTotal == UINT32_MAX ||
|
|
descriptionCount != descriptionTotal)
|
|
result = NTLSTATUS_FAILURE;
|
|
}
|
|
|
|
if (KSUCCESS(result)) {
|
|
uint8_t fdUsed[POSIX_FD_MAX];
|
|
memset(fdUsed, 0, sizeof(fdUsed));
|
|
for (uint32_t i = 0; i < manifestCount; ++i) {
|
|
NTL_POSIX_FD_MANIFEST_ENTRY* entry = &manifest[i];
|
|
if (entry->Descriptor < 0 || entry->Descriptor >= POSIX_FD_MAX ||
|
|
fdUsed[entry->Descriptor] ||
|
|
(entry->DescriptorFlags & ~NTL_POSIX_FD_DESCRIPTOR_CLOEXEC) != 0) {
|
|
result = NTLSTATUS_FAILURE;
|
|
break;
|
|
}
|
|
POSIX_OPEN_DESCRIPTION* description = (POSIX_OPEN_DESCRIPTION*)0;
|
|
for (uint32_t j = 0; j < descriptionCount; ++j) {
|
|
if (descriptionIds[j] == entry->OpenDescriptionId) {
|
|
description = descriptions[j];
|
|
break;
|
|
}
|
|
}
|
|
if (!description) { result = NTLSTATUS_FAILURE; break; }
|
|
fdUsed[entry->Descriptor] = 1u;
|
|
PosixFdReference(description);
|
|
process->FdTable[entry->Descriptor].Description = description;
|
|
process->FdTable[entry->Descriptor].DescriptorFlags =
|
|
(int)(entry->DescriptorFlags & NTL_POSIX_FD_DESCRIPTOR_CLOEXEC);
|
|
}
|
|
}
|
|
|
|
for (uint32_t i = 0; i < descriptionCount; ++i)
|
|
PosixFdRelease(descriptions[i]);
|
|
return result;
|
|
}
|
|
|
|
// Initializes the process descriptor table and standard descriptors.
|
|
uint32_t PosixFdInitializeProcess(POSIX_PROCESS_STATE* process, uint64_t inheritanceToken) {
|
|
if (!process)
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
|
|
uint32_t lock = SYS_HANDLE_INVALID;
|
|
uint32_t status = SysCreateMutex(&lock);
|
|
if (status != NTLSTATUS_SUCCESS)
|
|
return status;
|
|
process->FdLock = lock;
|
|
memset(process->FdTable, 0, sizeof(process->FdTable));
|
|
|
|
if (inheritanceToken != 0) {
|
|
status = PosixFdImportInheritance(process, inheritanceToken);
|
|
if (status != NTLSTATUS_SUCCESS) PosixFdDestroyProcess(process);
|
|
return status;
|
|
}
|
|
|
|
status = PosixFdInstallStandard(process, 0, PosixFdConsoleRead, O_RDONLY);
|
|
if (status == NTLSTATUS_SUCCESS)
|
|
status = PosixFdInstallStandard(process, 1, PosixFdConsoleWrite, O_WRONLY);
|
|
if (status == NTLSTATUS_SUCCESS)
|
|
status = PosixFdInstallStandard(process, 2, PosixFdConsoleWrite, O_WRONLY);
|
|
if (status != NTLSTATUS_SUCCESS)
|
|
PosixFdDestroyProcess(process);
|
|
return status;
|
|
}
|
|
|
|
// Releases descriptor-table resources during failed process startup.
|
|
void PosixFdDestroyProcess(POSIX_PROCESS_STATE* process) {
|
|
if (!process)
|
|
return;
|
|
|
|
for (int fd = 0; fd < POSIX_FD_MAX; fd++) {
|
|
POSIX_OPEN_DESCRIPTION* description = process->FdTable[fd].Description;
|
|
process->FdTable[fd].Description = (POSIX_OPEN_DESCRIPTION*)0;
|
|
process->FdTable[fd].DescriptorFlags = 0;
|
|
PosixFdRelease(description);
|
|
}
|
|
if (process->FdLock != SYS_HANDLE_INVALID) {
|
|
SysCloseHandle(process->FdLock);
|
|
process->FdLock = SYS_HANDLE_INVALID;
|
|
}
|
|
}
|
|
|
|
// Duplicates oldfd into the lowest free descriptor at or above minFd.
|
|
static int PosixFdDuplicateFrom(int oldfd, int minFd) {
|
|
if (minFd < 0 || minFd >= POSIX_FD_MAX) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
POSIX_OPEN_DESCRIPTION* description = PosixFdAcquire(oldfd);
|
|
if (!description)
|
|
return -1;
|
|
int result = PosixFdInstall(PosixRuntimeProcessState(), description, minFd, 0);
|
|
PosixFdRelease(description);
|
|
return result;
|
|
}
|
|
|
|
// Duplicates one descriptor to the lowest available descriptor.
|
|
NTL_POSIX_API int dup(int oldfd) {
|
|
return PosixFdDuplicateFrom(oldfd, 0);
|
|
}
|
|
|
|
// Duplicates oldfd onto newfd, atomically replacing newfd when necessary.
|
|
NTL_POSIX_API int dup2(int oldfd, int newfd) {
|
|
if (newfd < 0 || newfd >= POSIX_FD_MAX) {
|
|
errno = EBADF;
|
|
return -1;
|
|
}
|
|
|
|
POSIX_OPEN_DESCRIPTION* description = PosixFdAcquire(oldfd);
|
|
if (!description)
|
|
return -1;
|
|
if (oldfd == newfd) {
|
|
PosixFdRelease(description);
|
|
return newfd;
|
|
}
|
|
|
|
POSIX_PROCESS_STATE* process = PosixRuntimeProcessState();
|
|
if (PosixFdLock(process) != 0) {
|
|
PosixFdRelease(description);
|
|
return -1;
|
|
}
|
|
|
|
POSIX_OPEN_DESCRIPTION* replaced = process->FdTable[newfd].Description;
|
|
PosixFdReference(description);
|
|
process->FdTable[newfd].Description = description;
|
|
process->FdTable[newfd].DescriptorFlags = 0;
|
|
PosixFdUnlock(process);
|
|
|
|
PosixFdRelease(replaced);
|
|
PosixFdRelease(description);
|
|
return newfd;
|
|
}
|
|
|
|
// Resolves one flock range to the native absolute byte-range form.
|
|
static int PosixFlockRange(POSIX_OPEN_DESCRIPTION* description,
|
|
const struct flock* lock,
|
|
uint64_t* offsetOut,
|
|
uint64_t* lengthOut) {
|
|
if (!description || !lock || !offsetOut || !lengthOut) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
if (description->Type != PosixFdFile) {
|
|
errno = EBADF;
|
|
return -1;
|
|
}
|
|
|
|
int64_t base = 0;
|
|
uint32_t status = NTLSTATUS_SUCCESS;
|
|
if (lock->l_whence == SEEK_CUR) {
|
|
uint64_t current = 0;
|
|
status = SysGetFilePos(description->KHandle, ¤t);
|
|
if (status == NTLSTATUS_SUCCESS) {
|
|
if (current > 0x7FFFFFFFULL) status = NTLSTATUS_INVALID_PARAMETER;
|
|
else base = (int64_t)current;
|
|
}
|
|
} else if (lock->l_whence == SEEK_END) {
|
|
uint64_t size = 0;
|
|
status = SysGetFileSize(description->KHandle, &size);
|
|
if (status == NTLSTATUS_SUCCESS) {
|
|
if (size > 0x7FFFFFFFULL) status = NTLSTATUS_INVALID_PARAMETER;
|
|
else base = (int64_t)size;
|
|
}
|
|
} else if (lock->l_whence != SEEK_SET) {
|
|
status = NTLSTATUS_INVALID_PARAMETER;
|
|
}
|
|
if (status != NTLSTATUS_SUCCESS) {
|
|
errno = PosixStatusToErrno(status);
|
|
return -1;
|
|
}
|
|
|
|
int64_t start = base + (int64_t)lock->l_start;
|
|
int64_t length = (int64_t)lock->l_len;
|
|
if (length < 0) {
|
|
start += length;
|
|
length = -length;
|
|
}
|
|
if (start < 0 || start > 0x7FFFFFFFLL) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
*offsetOut = (uint64_t)start;
|
|
*lengthOut = length == 0 ? SYS_FILE_LOCK_TO_EOF : (uint64_t)length;
|
|
return 0;
|
|
}
|
|
|
|
// Implements F_GETLK/F_SETLK/F_SETLKW on the native process-owned lock table.
|
|
static int PosixFdControlLock(POSIX_OPEN_DESCRIPTION* description, int command, struct flock* lock) {
|
|
if (!description || !lock) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
if (description->Type != PosixFdFile) {
|
|
errno = EBADF;
|
|
return -1;
|
|
}
|
|
|
|
uint64_t offset = 0;
|
|
uint64_t length = 0;
|
|
if (PosixFlockRange(description, lock, &offset, &length) != 0)
|
|
return -1;
|
|
|
|
if (command == F_GETLK) {
|
|
if (lock->l_type != F_RDLCK && lock->l_type != F_WRLCK) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
SYS_FILE_LOCK_INFO info;
|
|
memset(&info, 0, sizeof(info));
|
|
SYS_QUERY_FILE_LOCK_REQUEST request;
|
|
memset(&request, 0, sizeof(request));
|
|
request.Size = sizeof(request);
|
|
request.FileHandle = description->KHandle;
|
|
request.Mode = lock->l_type == F_RDLCK ? SYS_FILE_LOCK_SHARED : SYS_FILE_LOCK_EXCLUSIVE;
|
|
request.Flags = SYS_FILE_LOCK_FLAG_NONE;
|
|
request.Offset = offset;
|
|
request.Length = length;
|
|
request.InfoOut = &info;
|
|
uint32_t status = SysQueryFileLock(&request);
|
|
if (status != NTLSTATUS_SUCCESS) {
|
|
errno = PosixStatusToErrno(status);
|
|
return -1;
|
|
}
|
|
if (info.Mode == SYS_FILE_LOCK_NONE) {
|
|
lock->l_type = F_UNLCK;
|
|
lock->l_pid = 0;
|
|
return 0;
|
|
}
|
|
lock->l_type = info.Mode == SYS_FILE_LOCK_SHARED ? F_RDLCK : F_WRLCK;
|
|
lock->l_whence = SEEK_SET;
|
|
lock->l_start = (off_t)info.Offset;
|
|
lock->l_len = info.Length == SYS_FILE_LOCK_TO_EOF ? 0 : (off_t)info.Length;
|
|
lock->l_pid = (pid_t)info.OwnerProcessId;
|
|
return 0;
|
|
}
|
|
|
|
if (lock->l_type == F_UNLCK) {
|
|
SYS_UNLOCK_FILE_REQUEST request;
|
|
memset(&request, 0, sizeof(request));
|
|
request.Size = sizeof(request);
|
|
request.FileHandle = description->KHandle;
|
|
request.Flags = SYS_FILE_LOCK_FLAG_NONE;
|
|
request.Offset = offset;
|
|
request.Length = length;
|
|
uint32_t status = SysUnlockFile(&request);
|
|
if (status == NTLSTATUS_SUCCESS || status == NTLSTATUS_NOT_FOUND)
|
|
return 0;
|
|
errno = PosixStatusToErrno(status);
|
|
return -1;
|
|
}
|
|
|
|
int statusFlags = PosixFdGetStatusFlags(description);
|
|
uint32_t mode = 0;
|
|
if (lock->l_type == F_RDLCK) {
|
|
if ((statusFlags & O_ACCMODE) == O_WRONLY) {
|
|
errno = EBADF;
|
|
return -1;
|
|
}
|
|
mode = SYS_FILE_LOCK_SHARED;
|
|
} else if (lock->l_type == F_WRLCK) {
|
|
if ((statusFlags & O_ACCMODE) == O_RDONLY) {
|
|
errno = EBADF;
|
|
return -1;
|
|
}
|
|
mode = SYS_FILE_LOCK_EXCLUSIVE;
|
|
} else {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
SYS_LOCK_FILE_REQUEST request;
|
|
memset(&request, 0, sizeof(request));
|
|
request.Size = sizeof(request);
|
|
request.FileHandle = description->KHandle;
|
|
request.Mode = mode;
|
|
request.Flags = SYS_FILE_LOCK_FLAG_NONE;
|
|
request.Offset = offset;
|
|
request.Length = length;
|
|
request.TimeoutMilliseconds = command == F_SETLKW ? SYS_WAIT_TIMEOUT_INFINITE : 0;
|
|
uint32_t status = SysLockFile(&request);
|
|
if (status != NTLSTATUS_SUCCESS) {
|
|
errno = PosixStatusToErrno(status);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Implements descriptor and open-description file-control operations.
|
|
NTL_POSIX_API int fcntl(int fd, int command, ...) {
|
|
POSIX_PROCESS_STATE* process = PosixRuntimeProcessState();
|
|
if (!process || fd < 0 || fd >= POSIX_FD_MAX) {
|
|
errno = EBADF;
|
|
return -1;
|
|
}
|
|
|
|
va_list args;
|
|
va_start(args, command);
|
|
|
|
if (command == F_DUPFD) {
|
|
int minFd = va_arg(args, int);
|
|
va_end(args);
|
|
return PosixFdDuplicateFrom(fd, minFd);
|
|
}
|
|
|
|
if (command == F_GETFL) {
|
|
va_end(args);
|
|
POSIX_OPEN_DESCRIPTION* description = PosixFdAcquire(fd);
|
|
if (!description)
|
|
return -1;
|
|
int flags = PosixFdGetStatusFlags(description);
|
|
PosixFdRelease(description);
|
|
return flags;
|
|
}
|
|
|
|
if (command == F_SETFL) {
|
|
int flags = va_arg(args, int);
|
|
va_end(args);
|
|
POSIX_OPEN_DESCRIPTION* description = PosixFdAcquire(fd);
|
|
if (!description)
|
|
return -1;
|
|
int result = PosixFdSetStatusFlags(description, flags);
|
|
PosixFdRelease(description);
|
|
return result;
|
|
}
|
|
|
|
if (command == F_GETLK || command == F_SETLK || command == F_SETLKW) {
|
|
struct flock* lock = va_arg(args, struct flock*);
|
|
va_end(args);
|
|
POSIX_OPEN_DESCRIPTION* description = PosixFdAcquire(fd);
|
|
if (!description)
|
|
return -1;
|
|
int result = PosixFdControlLock(description, command, lock);
|
|
PosixFdRelease(description);
|
|
return result;
|
|
}
|
|
|
|
if (PosixFdLock(process) != 0) {
|
|
va_end(args);
|
|
return -1;
|
|
}
|
|
if (!process->FdTable[fd].Description) {
|
|
PosixFdUnlock(process);
|
|
va_end(args);
|
|
errno = EBADF;
|
|
return -1;
|
|
}
|
|
|
|
int result = -1;
|
|
if (command == F_GETFD) {
|
|
result = process->FdTable[fd].DescriptorFlags;
|
|
} else if (command == F_SETFD) {
|
|
int flags = va_arg(args, int);
|
|
process->FdTable[fd].DescriptorFlags = flags & FD_CLOEXEC;
|
|
result = 0;
|
|
} else {
|
|
errno = EINVAL;
|
|
}
|
|
PosixFdUnlock(process);
|
|
va_end(args);
|
|
return result;
|
|
}
|