blob: b8e0f8c7300814ee996771cba5de6281e5d96b3d [file] [log] [blame] [raw]
/* A part of the Native C Library for Windows NT
Copyright 2007-2015 PC GO Ld.
Copyright 2016-2026 Rivoreo
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at
your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
*/
#include <sys/types.h>
#include <stdint.h>
#include <windows.h>
#include <nt.h>
#include <errno.h>
#include <unistd.h>
#include <process.h>
static int is_child = 0;
pid_t fork() {
if(is_child) {
is_child = 0;
return 0;
}
CONTEXT context = { .ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT };
long int status = NtGetContextThread((void *)-2, &context);
if(status < 0) {
__set_errno_from_ntstatus(status);
return -1;
}
void *ph;
OBJECT_ATTRIBUTES empty_obj_attr = { .Length = sizeof(OBJECT_ATTRIBUTES) };
status = NtCreateProcess(&ph, PROCESS_ALL_ACCESS, &empty_obj_attr, (void *)-1, 1, NULL, NULL, NULL);
if(status < 0) {
__set_errno_from_ntstatus(status);
return -1;
}
MEMORY_BASIC_INFORMATION mbi;
#ifdef __i386__
context.Eip = (uint32_t)fork + 12;
status = NtQueryVirtualMemory((void *)-1, (void *)context.Esp, MemoryBasicInformation, &mbi, sizeof mbi, NULL);
if(status < 0) {
__set_errno_from_ntstatus(status);
NtClose(ph);
return -1;
}
#else
#error "Architecture not supported"
#endif
void *th;
INITIAL_TEB stack = { 0, 0, (char *)mbi.BaseAddress + mbi.RegionSize, mbi.BaseAddress, mbi.AllocationBase };
CLIENT_ID cid;
status = NtCreateThread(&th, THREAD_ALL_ACCESS, &empty_obj_attr, ph, &cid, &context, &stack, 1);
if(status < 0) {
NtClose(ph);
__set_errno_from_ntstatus(status);
return -1;
}
THREAD_BASIC_INFORMATION tbi;
status = NtQueryInformationThread((void *)-2, ThreadBasicInformation, &tbi, sizeof tbi, NULL);
//printf("nativelibc debug: fork: status = 0x%lx\n", status);
if(status < 0) goto failed;
NT_TIB *tib = &tbi.TebBaseAddress->Tib;
status = NtQueryInformationThread(th, ThreadBasicInformation, &tbi, sizeof tbi, NULL);
//printf("nativelibc debug: fork: status = 0x%lx\n", status);
if(status < 0) goto failed;
status = NtWriteVirtualMemory(ph, tbi.TebBaseAddress, &tib->ExceptionList, sizeof tib->ExceptionList, NULL);
//printf("nativelibc debug: fork: status = 0x%lx\n", status);
if(status < 0) goto failed;
int value = 1;
status = NtWriteVirtualMemory(ph, &is_child, &value, sizeof value, NULL);
if(status < 0) goto failed;
status = NtResumeThread(th, NULL);
//printf("nativelibc debug: fork: status = 0x%lx\n", status);
NtClose(th);
if(status < 0) {
NtClose(ph);
__set_errno_from_ntstatus(status);
return -1;
}
__child_process_table_add(cid.UniqueProcess, ph);
return cid.UniqueProcess;
failed:
NtClose(ph);
NtClose(th);
__set_errno_from_ntstatus(status);
return -1;
}