// POSIX descriptor table and shared open-description implementation. #include #include #include #include #include #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; }