From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/posix/client/alpha/psxthunk.s | 149 ++++ private/posix/client/alpha/sources | 1 + private/posix/client/buildtst.cmd | 3 + private/posix/client/coninit.c | 125 ++++ private/posix/client/conreqst.c | 56 ++ private/posix/client/crtsup.c | 233 ++++++ private/posix/client/dllext.c | 88 +++ private/posix/client/dllfile.c | 1011 ++++++++++++++++++++++++++ private/posix/client/dllinit.c | 377 ++++++++++ private/posix/client/dllio.c | 694 ++++++++++++++++++ private/posix/client/dllname.c | 310 ++++++++ private/posix/client/dllproc.c | 1251 ++++++++++++++++++++++++++++++++ private/posix/client/dllreg.c | 173 +++++ private/posix/client/dllsig.c | 438 +++++++++++ private/posix/client/dlltc.c | 293 ++++++++ private/posix/client/dlltimer.c | 243 +++++++ private/posix/client/i386/psxthunk.asm | 60 ++ private/posix/client/i386/sources | 1 + private/posix/client/makefile | 6 + private/posix/client/makefile.inc | 2 + private/posix/client/mips/psxthunk.s | 147 ++++ private/posix/client/mips/sources | 1 + private/posix/client/ppc/psxthunk.s | 185 +++++ private/posix/client/ppc/sources | 1 + private/posix/client/psxdll.h | 176 +++++ private/posix/client/psxdll.rc | 11 + private/posix/client/psxdll.src | 151 ++++ private/posix/client/sources | 64 ++ private/posix/client/stubs.c | 195 +++++ private/posix/client/sysdb.c | 304 ++++++++ private/posix/client/tst/tstdir.c | 308 ++++++++ private/posix/client/tst/tstexec.c | 68 ++ private/posix/client/tst/tstfile.c | 252 +++++++ private/posix/client/tst/tstfork.c | 598 +++++++++++++++ private/posix/client/tst/tstheap.c | 111 +++ private/posix/client/tst/tsthello.c | 38 + private/posix/client/tst/tsthw.c | 20 + private/posix/client/tst/tstjc.c | 367 ++++++++++ private/posix/client/tst/tstloop.c | 83 +++ private/posix/client/tst/tstmd.c | 54 ++ private/posix/client/tst/tstmisc.c | 242 ++++++ private/posix/client/tst/tstncall.c | 55 ++ private/posix/client/tst/tstnpipe.c | 420 +++++++++++ private/posix/client/tst/tstrmdir.c | 91 +++ private/posix/client/tst/tstsid.c | 284 ++++++++ private/posix/client/tst/tstsig.c | 120 +++ private/posix/client/tst/tstsum.c | 138 ++++ private/posix/client/tst/tsttime.c | 40 + private/posix/client/tst/tsttmp.h | 5 + private/posix/client/tst/tstumask.c | 68 ++ 50 files changed, 10111 insertions(+) create mode 100644 private/posix/client/alpha/psxthunk.s create mode 100644 private/posix/client/alpha/sources create mode 100644 private/posix/client/buildtst.cmd create mode 100644 private/posix/client/coninit.c create mode 100644 private/posix/client/conreqst.c create mode 100644 private/posix/client/crtsup.c create mode 100644 private/posix/client/dllext.c create mode 100644 private/posix/client/dllfile.c create mode 100644 private/posix/client/dllinit.c create mode 100644 private/posix/client/dllio.c create mode 100644 private/posix/client/dllname.c create mode 100644 private/posix/client/dllproc.c create mode 100644 private/posix/client/dllreg.c create mode 100644 private/posix/client/dllsig.c create mode 100644 private/posix/client/dlltc.c create mode 100644 private/posix/client/dlltimer.c create mode 100644 private/posix/client/i386/psxthunk.asm create mode 100644 private/posix/client/i386/sources create mode 100644 private/posix/client/makefile create mode 100644 private/posix/client/makefile.inc create mode 100644 private/posix/client/mips/psxthunk.s create mode 100644 private/posix/client/mips/sources create mode 100644 private/posix/client/ppc/psxthunk.s create mode 100644 private/posix/client/ppc/sources create mode 100644 private/posix/client/psxdll.h create mode 100644 private/posix/client/psxdll.rc create mode 100644 private/posix/client/psxdll.src create mode 100644 private/posix/client/sources create mode 100644 private/posix/client/stubs.c create mode 100644 private/posix/client/sysdb.c create mode 100644 private/posix/client/tst/tstdir.c create mode 100644 private/posix/client/tst/tstexec.c create mode 100644 private/posix/client/tst/tstfile.c create mode 100644 private/posix/client/tst/tstfork.c create mode 100644 private/posix/client/tst/tstheap.c create mode 100644 private/posix/client/tst/tsthello.c create mode 100644 private/posix/client/tst/tsthw.c create mode 100644 private/posix/client/tst/tstjc.c create mode 100644 private/posix/client/tst/tstloop.c create mode 100644 private/posix/client/tst/tstmd.c create mode 100644 private/posix/client/tst/tstmisc.c create mode 100644 private/posix/client/tst/tstncall.c create mode 100644 private/posix/client/tst/tstnpipe.c create mode 100644 private/posix/client/tst/tstrmdir.c create mode 100644 private/posix/client/tst/tstsid.c create mode 100644 private/posix/client/tst/tstsig.c create mode 100644 private/posix/client/tst/tstsum.c create mode 100644 private/posix/client/tst/tsttime.c create mode 100644 private/posix/client/tst/tsttmp.h create mode 100644 private/posix/client/tst/tstumask.c (limited to 'private/posix/client') diff --git a/private/posix/client/alpha/psxthunk.s b/private/posix/client/alpha/psxthunk.s new file mode 100644 index 000000000..ae7f9a41a --- /dev/null +++ b/private/posix/client/alpha/psxthunk.s @@ -0,0 +1,149 @@ +// TITLE("POSIX Thunks") +//++ +// +// Copyright (c) 1991 Microsoft Corporation +// Copyright (c) 1993 Digital Equipment Corporation +// +// Module Name: +// +// psxthunk.s +// +// Abstract: +// +// Author: +// +// Ellena Aycock-Wright (ellena) 11-Jan-1991 +// +// Revision History: +// +// Thomas Van Baak (tvb) 11-Dec-1992 +// +// Adapted for Alpha AXP. +// +//-- + +#include "ksalpha.h" + + SBTTL("Call Null Api") +//++ +// +// The following code is never executed. Its purpose is to support unwinding +// through the call to the null API function. The instructions below are read +// by virtual unwind to restore the context of the calling function. +// +//-- + + NESTED_ENTRY(PdxNullApiCall, ContextFrameLength, zero) + + .set noreorder + .set noat + stq sp, CxIntSp(sp) // stack pointer + stq ra, CxIntRa(sp) // return address + stq ra, CxFir(sp) // continuation address + stq gp, CxIntGp(sp) // integer register gp + + stq s0, CxIntS0(sp) // integer registers s0 - s5 + stq s1, CxIntS1(sp) // + stq s2, CxIntS2(sp) // + stq s3, CxIntS3(sp) // + stq s4, CxIntS4(sp) // + stq s5, CxIntS5(sp) // + stq fp, CxIntFp(sp) // integer register fp + + stt f2, CxFltF2(sp) // floating registers f2 - f9 + stt f3, CxFltF3(sp) // + stt f4, CxFltF4(sp) // + stt f5, CxFltF5(sp) // + stt f6, CxFltF6(sp) // + stt f7, CxFltF7(sp) // + stt f8, CxFltF8(sp) // + stt f9, CxFltF9(sp) // + .set at + .set reorder + + PROLOGUE_END + + ALTERNATE_ENTRY(_PdxNullApiCaller) + + + mov sp, a0 // set address of context record + bsr ra, PdxNullApiCaller // call null api caller + + .end PdxNullApiCaller + + SBTTL("Call Signal Deliverer") +//++ +// +// The following code is never executed. Its purpose is to support unwinding +// through the call to the signal deliverer. The instructions below are read +// by virtual unwind to restore the context of the calling function. +// +//-- + + NESTED_ENTRY(PdxSignalDeliver, ContextFrameLength, zero) + + .set noreorder + .set noat + stq sp, CxIntSp(sp) // stack pointer + stq ra, CxIntRa(sp) // return address + stq ra, CxFir(sp) // continuation address + stq gp, CxIntGp(sp) // integer register gp + + stq s0, CxIntS0(sp) // integer registers s0 - s5 + stq s1, CxIntS1(sp) // + stq s2, CxIntS2(sp) // + stq s3, CxIntS3(sp) // + stq s4, CxIntS4(sp) // + stq s5, CxIntS5(sp) // + stq fp, CxIntFp(sp) // integer register fp + + stt f2, CxFltF2(sp) // floating registers f2 - f9 + stt f3, CxFltF3(sp) // + stt f4, CxFltF4(sp) // + stt f5, CxFltF5(sp) // + stt f6, CxFltF6(sp) // + stt f7, CxFltF7(sp) // + stt f8, CxFltF8(sp) // + stt f9, CxFltF9(sp) // + .set at + .set reorder + + PROLOGUE_END + +//++ +// +// VOID +// _PdxSignalDeliverer ( +// IN PCONTEXT Context, +// IN sigset_t Mask, +// IN int Signal, +// IN _handler Handler +// ) +// +// Routine Description: +// +// The following routine provides linkage to POSIX client routines to +// perform signal delivery. +// +// Arguments: +// +// s0 - s5 - Supply parameter values. +// +// sp - Supplies the address of a context record. +// +// Return Value: +// +// There is no return from these routines. +// +//-- + + ALTERNATE_ENTRY(_PdxSignalDeliverer) + + mov sp, a0 // set address of context record + mov s1, a1 // set previous block mask + mov s2, a2 // set signal number + mov s3, a3 // set signal handler + + bsr ra, PdxSignalDeliverer // deliver signal to POSIX client + + .end _PsxSignalDeliverer diff --git a/private/posix/client/alpha/sources b/private/posix/client/alpha/sources new file mode 100644 index 000000000..92077dc40 --- /dev/null +++ b/private/posix/client/alpha/sources @@ -0,0 +1 @@ +ALPHA_SOURCES=psxthunk.asm diff --git a/private/posix/client/buildtst.cmd b/private/posix/client/buildtst.cmd new file mode 100644 index 000000000..ed85b1247 --- /dev/null +++ b/private/posix/client/buildtst.cmd @@ -0,0 +1,3 @@ +set NTDEBUG=ntsd +set 386_OPTIMIZATION=/Od +build tstdir tsthello tsthw tstmd tstnpipe tstsig tstfile tstmisc tstrmdir tstumask tstfork tstloop tstncall tstsid tstexec tstsum tstheap tsttime tstfp diff --git a/private/posix/client/coninit.c b/private/posix/client/coninit.c new file mode 100644 index 000000000..629dc348c --- /dev/null +++ b/private/posix/client/coninit.c @@ -0,0 +1,125 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + coninit.c + +Abstract: + + This module initialize the connection with the session console port + +Author: + + Avi Nathan (avin) 23-Jul-1991 + +Revision History: + + Ellen Aycock-Wright (ellena) 15-Sept-1991 Modified for POSIX + +--*/ + +#include +#include "psxdll.h" + +NTSTATUS +PsxInitializeSessionPort( + IN ULONG UniqueId + ) +{ + PSXSESCONNECTINFO ConnectionInfoIn; + ULONG ConnectionInfoInLength; + + CHAR SessionName[PSX_SES_BASE_PORT_NAME_LENGTH]; + STRING SessionPortName; + UNICODE_STRING SessionPortName_U; + STRING SessionDataName; + UNICODE_STRING SessionDataName_U; + + NTSTATUS Status; + SECURITY_QUALITY_OF_SERVICE DynamicQos; + HANDLE SessionPortHandle; + HANDLE SectionHandle; + ULONG ViewSize = 0L; + OBJECT_ATTRIBUTES ObjectAttributes; + PVOID PsxSessionDataBaseAddress; + + ConnectionInfoInLength = sizeof(ConnectionInfoIn); + + CONSTRUCT_PSX_SES_NAME(SessionName, PSX_SES_BASE_PORT_PREFIX, UniqueId); + + RtlInitAnsiString(&SessionPortName, SessionName); + RtlAnsiStringToUnicodeString(&SessionPortName_U, &SessionPortName, TRUE); + + DynamicQos.ImpersonationLevel = SecurityImpersonation; + DynamicQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; + DynamicQos.EffectiveOnly = TRUE; + + // + // get the session communication port handle. this handle will be used + // to send console requests to psxses.exe for this session. + // + + Status = NtConnectPort(&SessionPortHandle, &SessionPortName_U, &DynamicQos, + NULL, NULL, NULL, NULL, NULL); + RtlFreeUnicodeString(&SessionPortName_U); + if (!NT_SUCCESS(Status)) { + KdPrint(("PSXDLL: Unable to connect to %s - Status == %X\n", + SessionPortName.Buffer, Status)); + return Status; + } + + + // + // open the session data section and map it to this process + // + + CONSTRUCT_PSX_SES_NAME(SessionName, PSX_SES_BASE_DATA_PREFIX, UniqueId); + + RtlInitAnsiString(&SessionDataName, SessionName); + + Status = RtlAnsiStringToUnicodeString(&SessionDataName_U, &SessionDataName, + TRUE); + ASSERT(NT_SUCCESS(Status)); + + InitializeObjectAttributes(&ObjectAttributes, &SessionDataName_U, 0, NULL, + NULL); + + Status = NtOpenSection(&SectionHandle, SECTION_MAP_WRITE, + &ObjectAttributes); + + RtlFreeUnicodeString(&SessionDataName_U); + + if (!NT_SUCCESS(Status)) { + return Status; + } + + // + // Let MM locate the view + // + + PsxSessionDataBaseAddress = 0; + + Status = NtMapViewOfSection(SectionHandle, NtCurrentProcess(), + &PsxSessionDataBaseAddress, 0L, 0L, NULL, + &ViewSize, ViewUnmap, 0L, PAGE_READWRITE); + if (!NT_SUCCESS(Status)) { + return Status; + } + + // + // record the session port in the PEB. + // + { + PPEB_PSX_DATA Peb; + + Peb = (PPEB_PSX_DATA)(NtCurrentPeb()->SubSystemData); + Peb->SessionPortHandle = SessionPortHandle; + Peb->SessionDataBaseAddress = PsxSessionDataBaseAddress; + } + + // BUGBUG! find cleanup code and close the port, or let exit cleanup + + return Status; +} diff --git a/private/posix/client/conreqst.c b/private/posix/client/conreqst.c new file mode 100644 index 000000000..5e51ecc07 --- /dev/null +++ b/private/posix/client/conreqst.c @@ -0,0 +1,56 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + conreqst.c + +Abstract: + + This module implements the POSIX console API calls + +Author: + + Avi Nathan (avin) 23-Jul-1991 + +Revision History: + + Ellen Aycock-Wright (ellena) 15-Sept-1991 Modified for POSIX + +--*/ + +#include "psxdll.h" + + +NTSTATUS +SendConsoleRequest(IN OUT PSCREQUESTMSG Request) +{ + HANDLE SessionPort; + NTSTATUS Status; + + PORT_MSG_TOTAL_LENGTH(*Request) = sizeof(SCREQUESTMSG); + PORT_MSG_DATA_LENGTH(*Request) = sizeof(SCREQUESTMSG) - sizeof(PORT_MESSAGE); + PORT_MSG_ZERO_INIT(*Request) = 0L; + + SessionPort = ((PPEB_PSX_DATA)(NtCurrentPeb()->SubSystemData))->SessionPortHandle; + + Status = NtRequestWaitReplyPort(SessionPort, (PPORT_MESSAGE)Request, + (PPORT_MESSAGE) Request); + + if (!NT_SUCCESS(Status)) { + KdPrint(("PSXDLL: Unable to send CON request: %X\n", Status)); + if (0xffffffff == Status) { + return STATUS_UNSUCCESSFUL; + } + + // + // Probably somebody shot posix.exe, or he died for some other + // reason. We'll shoot the user's process for him. + // + _exit(99); + } + ASSERT(PORT_MSG_TYPE(*Request) == LPC_REPLY); + + return Request->Status; +} diff --git a/private/posix/client/crtsup.c b/private/posix/client/crtsup.c new file mode 100644 index 000000000..127950fef --- /dev/null +++ b/private/posix/client/crtsup.c @@ -0,0 +1,233 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + crtsup.c + +Abstract: + + This module contains support routines used by the Posix C runtimes. + +Author: + + Ellen Aycock-Wright (ellena) 07-Aug-1991 + +Environment: + + User Mode only + +Revision History: + +--*/ + +#include "psxmsg.h" +#include "psxdll.h" + + +char * +_CRTAPI1 +__PdxGetCmdLine( + VOID + ) + +/*++ + +Routine Description: + + The command line of the current process is available using this + API. + +Arguments: + + None. + +Return Value: + + The address of the current processes command line is returned. The + return value is a pointer to null terminate string. + +--*/ + +{ + return PsxAnsiCommandLine.Buffer; +} + +int +PdxStatusToErrno( + IN NTSTATUS Status + ) + +/*++ + +Routine Description: + + This procedure converts an NT status code to an + equivalent errno value. BUG BUG it is duplicated in the + server as PsxStatusToErrno to avoid calling the server. + + The conversion is a function of the status code class. + +Arguments: + + Class - Supplies the status code class to use. + + Status - Supplies the status code to convert. + +Return Value: + + Returns an equivalent error code to the supplied status code. + +--*/ + +{ + ULONG Error; + + switch (Status) { + + case STATUS_INVALID_PARAMETER: + Error = EINVAL; + break; + + case STATUS_DIRECTORY_NOT_EMPTY: + // Error = ENOTEMPTY; + Error = EEXIST; + break; + + case STATUS_OBJECT_PATH_INVALID: + case STATUS_NOT_A_DIRECTORY: + Error = ENOTDIR; + break; + + case STATUS_OBJECT_PATH_SYNTAX_BAD: + // this for the rename test; 'old' has component too long. + Error = ENAMETOOLONG; + break; + + case STATUS_OBJECT_NAME_COLLISION: + Error = EEXIST; + break; + + case STATUS_OBJECT_PATH_NOT_FOUND: + case STATUS_OBJECT_NAME_NOT_FOUND: + case STATUS_DELETE_PENDING: + Error = ENOENT; + break; + + case STATUS_NO_MEMORY: + case STATUS_INSUFFICIENT_RESOURCES: + Error = ENOMEM; + break; + + case STATUS_CANNOT_DELETE: + Error = ETXTBUSY; + break; + + case STATUS_DISK_FULL: + Error = ENOSPC; + break; + + case STATUS_MEDIA_WRITE_PROTECTED: + Error = EROFS; + break; + + case STATUS_OBJECT_NAME_INVALID: + Error = ENAMETOOLONG; + break; + + case STATUS_FILE_IS_A_DIRECTORY: + Error = EISDIR; + break; + + case STATUS_NOT_SAME_DEVICE: + Error = EXDEV; + break; + + default : + Error = EACCES; + } + + return Error; +} + +// +// Copied from the server side. +// +int +PdxStatusToErrnoPath( + PUNICODE_STRING Path + ) +{ + NTSTATUS Status; + OBJECT_ATTRIBUTES Obj; + HANDLE FileHandle; + ULONG DesiredAccess; + IO_STATUS_BLOCK Iosb; + ULONG Options; + PWCHAR pwc, pwcSav; + ULONG MinLen = sizeof(L"\\DosDevices\\X:\\"); + + DesiredAccess = SYNCHRONIZE; + Options = FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE; + + pwcSav = NULL; + + for (;;) { + // + // Remove trailing component. + // + + pwc = wcsrchr(Path->Buffer, L'\\'); + + if (pwcSav) + *pwcSav = L'\\'; + + if (NULL == pwc) { + break; + } + *pwc = UNICODE_NULL; + pwcSav = pwc; + + Path->Length = wcslen(Path->Buffer) * sizeof(WCHAR); + + if (Path->Length <= MinLen) { + *pwcSav = L'\\'; + break; + } + + InitializeObjectAttributes(&Obj, Path, 0, NULL, NULL); + + Status = NtOpenFile(&FileHandle, DesiredAccess, &Obj, + &Iosb, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + Options); + if (NT_SUCCESS(Status)) { + NtClose(FileHandle);\ + } + if (STATUS_NOT_A_DIRECTORY == Status) { + *pwcSav = L'\\'; + Path->Length = wcslen(Path->Buffer) * sizeof(WCHAR); + return ENOTDIR; + } + } + Path->Length = wcslen(Path->Buffer) * sizeof(WCHAR); + return ENOENT; +} + +int _CRTAPI1 +raise(int sig) +{ + return kill(getpid(), sig); +} + +/* + * This routine is called by heapinit(), in crt32psx/winheap. We + * would have a reference forwarder in psxdll.def, except RtlProcessHeap + * is a macro and can't be forwarded. + */ +void * +GetProcessHeap(void) +{ + return (void *)RtlProcessHeap(); +} diff --git a/private/posix/client/dllext.c b/private/posix/client/dllext.c new file mode 100644 index 000000000..dcf9c8eb6 --- /dev/null +++ b/private/posix/client/dllext.c @@ -0,0 +1,88 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + dllext.c + +Abstract: + + Client implementation of C Language Extensions (Chapter 8 of 1003.1) + +Author: + + Ellen Aycock-Wright (ellena) 15-Oct-1991 + +Revision History: + +--*/ + +#include +#include +#include "psxdll.h" + +extern FILE *_getstream(void); + +int +_CRTAPI1 +fileno(FILE *stream) +{ + return(stream->_file); +} + +#if 0 +FILE * +fdopen(int fildes, const char *type) +{ + FILE *stream; + int mode; + int streamflag = 0; + + // + // XXX.mjb: we need fcntl to check modes and validity of fildes + // + + if (NULL == (stream = _getstream())) { + return NULL; + } + switch (*type) { + case 'r': + mode = O_RDONLY; + streamflag |= _IOREAD; + break; + case 'w': + mode = O_WRONLY; + streamflag |= _IOWRT; + break; + case 'a': + mode = O_WRONLY | O_APPEND; + streamflag |= _IOWRT; + // XXX.mjb: should be _IOWRT | _IOAPPEND; + break; + default: + errno = EINVAL; + return NULL; + } + + switch (*++type) { + case '\0': + break; + case '+': + mode |= O_RDWR; + mode &= ~(O_RDONLY | O_WRONLY); + streamflag |= _IOWRT; + streamflag &= (_IOREAD | _IOWRT); + break; + default: + errno = EINVAL; + return NULL; + } + + stream->_flag = streamflag; + stream->_cnt = 0; + stream->_base = stream->_ptr = NULL; + stream->_file = fildes; + return stream; +} +#endif diff --git a/private/posix/client/dllfile.c b/private/posix/client/dllfile.c new file mode 100644 index 000000000..14b7a3d54 --- /dev/null +++ b/private/posix/client/dllfile.c @@ -0,0 +1,1011 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + dllfile.c + +Abstract: + + Client implementation of File and Directory functions for POSIX. + +Author: + + Mark Lucovsky (markl) 15-Dec-1989 + +Revision History: + +--*/ + +#include +#include +#include "psxdll.h" + +int _CRTAPI1 +closedir(DIR *dirp) +{ + int r = 0; + + try { + if (-1 == close(dirp->Directory)) { + return -1; + } + dirp->Directory = -1; + dirp->Index = (unsigned long)-1; + + RtlFreeHeap(PdxHeap, 0, (PVOID)dirp); + + } except (EXCEPTION_EXECUTE_HANDLER) { + r = -1; + } + + return r; +} + +DIR * _CRTAPI1 +opendir(const char *dirname) +{ + DIR *ReturnedDir; + int fd, i; + + ReturnedDir = RtlAllocateHeap(PdxHeap, 0, sizeof(DIR)); + if (NULL == ReturnedDir) { + errno = ENOMEM; + return NULL; + } + + fd = open(dirname, O_RDONLY); + if (-1 == fd) { + RtlFreeHeap(PdxHeap, 0, (PVOID)ReturnedDir); + return NULL; + } + + i = fcntl(fd, F_SETFD, FD_CLOEXEC); + if (0 != i) { + close(fd); + RtlFreeHeap(PdxHeap, 0, (PVOID)ReturnedDir); + return NULL; + } + + ReturnedDir->Directory = fd; + ReturnedDir->Dirent.d_name[0] = '\0'; + ReturnedDir->Index = 0; + ReturnedDir->RestartScan = FALSE; + + return ReturnedDir; +} + +struct dirent * _CRTAPI1 +readdir(DIR *dirp) +{ + PSX_API_MSG m; + PPSX_READDIR_MSG args; + NTSTATUS Status; + char *buf; + + args = &m.u.ReadDir; + + buf = &dirp->Dirent.d_name[0]; + +again: + for (;;) { + PSX_FORMAT_API_MSG(m, PsxReadDirApi, sizeof(*args)); + args->FileDes = dirp->Directory; + args->Buf = buf; + args->Nbytes = PATH_MAX; + args->RestartScan = dirp->RestartScan; + dirp->RestartScan = 0; + + Status = NtRequestWaitReplyPort(PsxPortHandle, + (PPORT_MESSAGE)&m, (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(Status)); +#endif + + if (EINTR == m.Error && SIGCONT == m.Signal) { + // + // The system call was stopped and continued. Call + // again instead of returning EINTR. + // + continue; + } + if (m.Error) { + errno = m.Error; + return NULL; + } + break; + } + + if (0 == m.ReturnValue) { + return NULL; + } + + // + // Skip dot and dot-dot. + // + + if (m.ReturnValue <= 2 && buf[0] == '.') { + if (m.ReturnValue == 1 || buf[1] == '.') { + goto again; + } + } + + try { + ++dirp->Index; + + dirp->Dirent.d_name[m.ReturnValue] = '\0'; + return &dirp->Dirent; + + } except (EXCEPTION_EXECUTE_HANDLER) { + errno = EFAULT; + } + // we've taken an exception. + return NULL; +} + +void +_CRTAPI1 +rewinddir(DIR *dirp) +{ + dirp->RestartScan = TRUE; + dirp->Index = 0; +} + +int _CRTAPI1 +chdir(const char *path) +{ + NTSTATUS Status; + HANDLE Directory; + IO_STATUS_BLOCK Iosb; + OBJECT_ATTRIBUTES ObjA; + UNICODE_STRING Path_U; + ANSI_STRING Path_A; + PANSI_STRING pCWD; + auto sigset_t set, oset; + int ret_val = 0; + + if (!PdxCanonicalize((PSZ)path, &Path_U, PdxHeap)) { + return -1; + } + InitializeObjectAttributes(&ObjA, &Path_U, OBJ_INHERIT, NULL, NULL); + + // + // Make sure that the path is to a directory + // + + Status = NtOpenFile(&Directory, SYNCHRONIZE, &ObjA, &Iosb, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE); + if (!NT_SUCCESS(Status)) { + if (STATUS_OBJECT_PATH_NOT_FOUND == Status) { + errno = PdxStatusToErrnoPath(&Path_U); + } else { + errno = PdxStatusToErrno(Status); + } + RtlFreeHeap(PdxHeap, 0, (PVOID)Path_U.Buffer); + return -1; + } + + Status = NtClose(Directory); + if (!NT_SUCCESS(Status)) { + KdPrint(("PSXDLL: NtClose: 0x%x\n", Status)); + } + + RtlUnicodeStringToAnsiString(&Path_A, &Path_U, TRUE); + RtlFreeHeap(PdxHeap, 0, (PVOID)Path_U.Buffer); + + pCWD = &PdxDirectoryPrefix.NtCurrentWorkingDirectory; + + // + // The path was opened ok. Make sure that there is space for the + // pathname in the PdxDirectoryPrefix buffer. + // + + if (Path_A.Length > pCWD->MaximumLength + 2) { + RtlFreeAnsiString(&Path_A); + errno = ENOENT; + return -1; + } + + // + // Keep the process from trying to use his CWD while we're modifying + // it. + // + + sigfillset(&set); + sigprocmask(SIG_BLOCK, &set, &oset); + + // + // Update NtCurrentWorkingDirectory + // + + RtlMoveMemory(pCWD->Buffer, Path_A.Buffer, Path_A.Length); + if ('\\' != pCWD->Buffer[Path_A.Length - 1]) { + pCWD->Buffer[Path_A.Length] = '\\'; + pCWD->Buffer[Path_A.Length + 1] = '\0'; + pCWD->Length = Path_A.Length + 1; + } else { + pCWD->Buffer[Path_A.Length + 1] = '\0'; + pCWD->Length = Path_A.Length; + } + + // + // Set length of translated current working directory to zero. + // getcwd() uses this as its hint to translate NtCurrentWorkingDirectory + // to PsxCurrentWorkingDirectory. + // + + PdxDirectoryPrefix.PsxCurrentWorkingDirectory.Length = 0; + + // + // Update the PsxRoot. + // + + RtlMoveMemory(PdxDirectoryPrefix.PsxRoot.Buffer, Path_A.Buffer, + PdxDirectoryPrefix.PsxRoot.Length); + + RtlFreeAnsiString(&Path_A); + sigprocmask(SIG_SETMASK, &oset, NULL); + + return 0; +} + +char * +_CRTAPI1 +getcwd(char *buf, size_t size) +{ + USHORT i, j, CwdSize; + PANSI_STRING pPsxCwd, pNtCwd, pPsxRoot; + + if (size <= 0) { + errno = EINVAL; + return NULL; + } + + // + // Note that NtCwd should always have a trailing backslash. + // + + pNtCwd = &PdxDirectoryPrefix.NtCurrentWorkingDirectory; + pPsxCwd = &PdxDirectoryPrefix.PsxCurrentWorkingDirectory; + pPsxRoot = &PdxDirectoryPrefix.PsxRoot; + + CwdSize = pNtCwd->Length - pPsxRoot->Length; + if (1 == CwdSize) { + // + // If the CWD is "/", then we'll have a trailing slash and + // we'll need space for it. + // + ++CwdSize; + } + if (size < CwdSize) { + errno = ERANGE; + return NULL; + } + + if (0 == pPsxCwd->Length) { + for (i = 0, j = pPsxRoot->Length; i < CwdSize - 1; i++, j++) { + pPsxCwd->Buffer[i] = (pNtCwd->Buffer[j] == '\\') ? + '/' : pNtCwd->Buffer[j]; + } + pPsxCwd->Buffer[CwdSize] = '\0'; + pPsxCwd->Length = CwdSize - 1; + + } + + try { + RtlMoveMemory(buf, pPsxCwd->Buffer, pPsxCwd->Length); + buf[pPsxCwd->Length] = '\0'; + } except (EXCEPTION_EXECUTE_HANDLER) { + errno = EFAULT; + buf = NULL; + } + + return buf; +} + +mode_t +_CRTAPI1 +umask(mode_t cmask) +{ + PSX_API_MSG m; + NTSTATUS Status; + PPSX_UMASK_MSG args; + + args = &m.u.Umask; + PSX_FORMAT_API_MSG(m, PsxUmaskApi, sizeof(*args)); + + args->Cmask = cmask; + + Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(Status)); +#endif + + if (m.Error) { + errno = (int)m.Error; + return (mode_t)-1; + } + return (mode_t)m.ReturnValue; +} + +int +_CRTAPI1 +mkdir(const char *path, mode_t mode) +{ + PSX_API_MSG m; + NTSTATUS Status; + PPSX_MKDIR_MSG args; + UNICODE_STRING Path_U; + + args = &m.u.MkDir; + PSX_FORMAT_API_MSG(m, PsxMkDirApi, sizeof(*args)); + + if (!PdxCanonicalize((PSZ)path, &Path_U, PdxPortHeap)) { + return -1; + } + + args->Path_U = Path_U; + args->Path_U.Buffer = (PVOID)((PCHAR)Path_U.Buffer + + PsxPortMemoryRemoteDelta); + args->Mode = mode; + + Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(Status)); +#endif + + RtlFreeHeap(PdxPortHeap, 0, (PVOID)Path_U.Buffer); + + if (m.Error) { + errno = (int)m.Error; + return -1; + } + return (int)m.ReturnValue; +} + + +int +_CRTAPI1 +mkfifo(const char *path, mode_t mode) +{ + PSX_API_MSG m; + NTSTATUS Status; + PPSX_MKFIFO_MSG args; + PVOID p; + + args = &m.u.MkFifo; + + PSX_FORMAT_API_MSG(m,PsxMkFifoApi,sizeof(*args)); + + if (!PdxCanonicalize((PSZ)path, &args->Path_U, PdxPortHeap)) { + return -1; + } + + p = args->Path_U.Buffer; + args->Path_U.Buffer = (PWSTR)((PCHAR)p + PsxPortMemoryRemoteDelta); + args->Mode = mode; + + Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(Status)); +#endif + + RtlFreeHeap(PdxPortHeap, 0, p); + + if (m.Error) { + errno = (int)m.Error; + return -1; + } + return m.ReturnValue; +} + +int +_CRTAPI1 +rmdir(const char *path) +{ + PSX_API_MSG m; + NTSTATUS Status; + PPSX_RMDIR_MSG args; + PVOID p; + + args = &m.u.RmDir; + + PSX_FORMAT_API_MSG(m,PsxRmDirApi,sizeof(*args)); + + if (!PdxCanonicalize((PSZ)path, &args->Path_U, PdxPortHeap)) { + return -1; + } + + p = args->Path_U.Buffer; + args->Path_U.Buffer = (PWSTR)((PCHAR)p + PsxPortMemoryRemoteDelta); + + Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(Status)); +#endif + + RtlFreeHeap(PdxPortHeap, 0, p); + + if (m.Error) { + errno = (int)m.Error; + return -1; + } + return (int)m.ReturnValue; +} + +int +_CRTAPI1 +stat(const char *path, struct stat *buf) +{ + PSX_API_MSG m; + NTSTATUS Status; + PPSX_STAT_MSG args; + struct stat *tmpbuf; + void *p; + int r; + + args = &m.u.Stat; + PSX_FORMAT_API_MSG(m, PsxStatApi, sizeof(*args)); + + if (!PdxCanonicalize((PSZ)path, &args->Path_U, PdxPortHeap)) { + return -1; + } + + p = args->Path_U.Buffer; + args->Path_U.Buffer = (PWSTR)((PCHAR)p + PsxPortMemoryRemoteDelta); + + tmpbuf = RtlAllocateHeap(PdxPortHeap, 0, sizeof(struct stat)); + ASSERT(NULL != tmpbuf); + + args->StatBuf = (struct stat *)((PCHAR)tmpbuf + PsxPortMemoryRemoteDelta); + Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(Status)); +#endif + + RtlFreeHeap(PdxPortHeap, 0, p); + + if (m.Error) { + RtlFreeHeap(PdxPortHeap, 0, (PVOID)tmpbuf); + errno = (int)m.Error; + return -1; + } + + r = 0; + + try { + (void)memcpy(buf, tmpbuf, sizeof(struct stat)); + } except (EXCEPTION_EXECUTE_HANDLER) { + r = -1; + errno = EFAULT; + } + + RtlFreeHeap(PdxPortHeap, 0, (PVOID)tmpbuf); + return r; +} + +int +_CRTAPI1 +fstat(int fildes, struct stat *buf) +{ + PSX_API_MSG m; + NTSTATUS Status; + PPSX_FSTAT_MSG args; + struct stat *tmpbuf; + int r; + + args = &m.u.FStat; + PSX_FORMAT_API_MSG(m, PsxFStatApi, sizeof(*args)); + + args->FileDes = fildes; + + tmpbuf = RtlAllocateHeap(PdxPortHeap, 0, sizeof(struct stat)); + ASSERT(NULL != tmpbuf); + + args->StatBuf = (struct stat *)((PCHAR)tmpbuf + PsxPortMemoryRemoteDelta); + Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(Status)); +#endif + + if (m.Error) { + RtlFreeHeap(PdxPortHeap, 0, (PVOID)tmpbuf); + errno = (int)m.Error; + return -1; + } + + r = 0; + + try { + (void)memcpy(buf, tmpbuf, sizeof(struct stat)); + } except (EXCEPTION_EXECUTE_HANDLER) { + r = -1; + errno = EFAULT; + } + RtlFreeHeap(PdxPortHeap, 0, (PVOID)tmpbuf); + return r; +} + +int +_CRTAPI1 +access(const char *path, int amode) +{ + PSX_API_MSG m; + NTSTATUS Status; + + PPSX_ACCESS_MSG args; + + if (0 != (amode & ~(W_OK | R_OK | X_OK))) { + errno = EINVAL; + return -1; + } + + args = &m.u.Access; + + PSX_FORMAT_API_MSG(m,PsxAccessApi,sizeof(*args)); + + if (!PdxCanonicalize((PSZ)path, &args->Path_U, PdxPortHeap)) { + return -1; + } + + m.DataBlock = args->Path_U.Buffer; + args->Path_U.Buffer = (PWSTR)((PCHAR)m.DataBlock + PsxPortMemoryRemoteDelta); + args->Amode = amode; + + Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(Status)); +#endif + + RtlFreeHeap(PdxPortHeap, 0, (PVOID)m.DataBlock); + + if (m.Error) { + errno = (int)m.Error; + return -1; + } + return m.ReturnValue; +} + +int +_CRTAPI1 +chmod(const char *path, mode_t mode) +{ + PSX_API_MSG m; + NTSTATUS Status; + PPSX_CHMOD_MSG args; + + args = &m.u.Chmod; + + PSX_FORMAT_API_MSG(m,PsxChmodApi,sizeof(*args)); + + if (!PdxCanonicalize((PSZ)path, &args->Path_U, PdxPortHeap)) { + return -1; + } + + m.DataBlock = args->Path_U.Buffer; + args->Path_U.Buffer = (PWSTR)((PCHAR)m.DataBlock + PsxPortMemoryRemoteDelta); + args->Mode = mode; + + Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(Status)); +#endif + + RtlFreeHeap(PdxPortHeap, 0, (PVOID)m.DataBlock); + + if (m.Error) { + errno = (int)m.Error; + return -1; + } + return m.ReturnValue; +} + +int +_CRTAPI1 +chown(const char *path, uid_t owner, gid_t group) +{ + PSX_API_MSG m; + NTSTATUS Status; + PPSX_CHOWN_MSG args; + + args = &m.u.Chown; + + PSX_FORMAT_API_MSG(m, PsxChownApi, sizeof(*args)); + + if (!PdxCanonicalize((PSZ)path, &args->Path_U, PdxPortHeap)) { + return -1; + } + + m.DataBlock = args->Path_U.Buffer; + args->Path_U.Buffer = (PWSTR)((PCHAR)m.DataBlock + PsxPortMemoryRemoteDelta); + args->Owner = owner; + args->Group = group; + + Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(Status)); +#endif + + RtlFreeHeap(PdxPortHeap, 0, (PVOID)m.DataBlock); + + if (m.Error) { + errno = (int)m.Error; + return -1; + } + return m.ReturnValue; +} + +int +_CRTAPI1 +utime(const char *path, const struct utimbuf *times) +{ + PSX_API_MSG m; + NTSTATUS Status; + + PPSX_UTIME_MSG args; + + args = &m.u.Utime; + + PSX_FORMAT_API_MSG(m, PsxUtimeApi, sizeof(*args)); + + if (!PdxCanonicalize((PSZ)path, &args->Path_U, PdxPortHeap)) { + return -1; + } + + m.DataBlock = args->Path_U.Buffer; + args->Path_U.Buffer = (PWSTR)((PCHAR)m.DataBlock + + PsxPortMemoryRemoteDelta); + args->TimesSpecified = (struct utimbuf *)times; + + if (NULL != times) { + args->Times = *times; + } + + Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(Status)); +#endif + + RtlFreeHeap(PdxPortHeap, 0, (PVOID)m.DataBlock); + + if (m.Error) { + errno = (int)m.Error; + return -1; + } + return m.ReturnValue; +} + +long +_CRTAPI1 +pathconf(const char *path, int name) +{ + PSX_API_MSG m; + NTSTATUS Status; + PPSX_PATHCONF_MSG args; + + args = &m.u.PathConf; + PSX_FORMAT_API_MSG(m, PsxPathConfApi, sizeof(*args)); + + if (!PdxCanonicalize((PSZ)path, &args->Path, PdxPortHeap)) { + return -1; + } + + m.DataBlock = args->Path.Buffer; + args->Path.Buffer = (PWSTR)((PCHAR)m.DataBlock + PsxPortMemoryRemoteDelta); + args->Name = name; + + Status = NtRequestWaitReplyPort(PsxPortHandle, + (PPORT_MESSAGE)&m, (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(Status)); +#endif + + RtlFreeHeap(PdxPortHeap, 0, (PVOID)m.DataBlock); + + if (m.Error) { + errno = (int)m.Error; + return -1; + } + return((long)(m.ReturnValue)); +} + +long +_CRTAPI1 +fpathconf(int fildes, int name) +{ + PSX_API_MSG m; + NTSTATUS Status; + PPSX_FPATHCONF_MSG args; + + args = &m.u.FPathConf; + PSX_FORMAT_API_MSG(m, PsxFPathConfApi, sizeof(*args)); + + args->FileDes = fildes; + args->Name = name; + + Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(Status)); +#endif + + if (m.Error) { + errno = (int)m.Error; + return -1; + } + return m.ReturnValue; +} + +int _CRTAPI1 +rename(const char *old, const char *new) +{ + NTSTATUS Status; + UNICODE_STRING old_U, new_U; + PSX_API_MSG m; + PPSX_RENAME_MSG args; + sigset_t set, oset; + int r; // ret val + static char path[PATH_MAX]; + char *pch, c; + WCHAR *pwc; + int i; + struct stat st_buf1, st_buf2; + static int been_here = 0; // prevent infinite recursion + + args = &m.u.Rename; + PSX_FORMAT_API_MSG(m, PsxRenameApi, sizeof(*args)); + + if (!PdxCanonicalize((PSZ)old, &old_U, PdxPortHeap)) { + return -1; + } + + if (!PdxCanonicalize((PSZ)new, &new_U, PdxPortHeap)) { + RtlFreeHeap(PdxPortHeap, 0, (PVOID)old_U.Buffer); + return -1; + } + + // + // 1003.1-90 (5.5.3.4): EISDIR ... The /new/ argument points + // to a directory, and the /old/ argument points to a file that + // is not a directory. + // + // ENOTDIR ... the /old/ argument names a + // directory and the /new/ argument names a nondirectory file. + // + + i = errno; + if (0 == stat(old, &st_buf1) && 0 == stat(new, &st_buf2)) { + if (S_ISDIR(st_buf2.st_mode) && S_ISREG(st_buf1.st_mode)) { + RtlFreeHeap(PdxPortHeap, 0, (PVOID)old_U.Buffer); + RtlFreeHeap(PdxPortHeap, 0, (PVOID)new_U.Buffer); + errno = EISDIR; + return -1; + } + if (S_ISREG(st_buf2.st_mode) && S_ISDIR(st_buf1.st_mode)) { + RtlFreeHeap(PdxPortHeap, 0, (PVOID)old_U.Buffer); + RtlFreeHeap(PdxPortHeap, 0, (PVOID)new_U.Buffer); + errno = ENOTDIR; + return -1; + } + } + errno = i; + + // + // 1003.1-90 (5.5.3.4): EINVAL ... The /new/ directory + // pathname contains a path prefix that names the /old/ directory. + // + + pwc = wcsrchr(new_U.Buffer, L'\\'); + ASSERT(NULL != pwc); + *pwc = 0; + + if (0 == wcsncmp(new_U.Buffer, old_U.Buffer, old_U.Length)) { + RtlFreeHeap(PdxPortHeap, 0, (PVOID)old_U.Buffer); + RtlFreeHeap(PdxPortHeap, 0, (PVOID)new_U.Buffer); + errno = EINVAL; + return -1; + } + *pwc = L'\\'; // put it back + + args->OldName = old_U; + args->NewName = new_U; + + args->OldName.Buffer = + (PVOID)((PCHAR)old_U.Buffer + PsxPortMemoryRemoteDelta); + args->NewName.Buffer = + (PVOID)((PCHAR)new_U.Buffer + PsxPortMemoryRemoteDelta); + + Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(Status)); +#endif + + RtlFreeHeap(PdxPortHeap, 0, (PVOID)new_U.Buffer); + RtlFreeHeap(PdxPortHeap, 0, (PVOID)old_U.Buffer); + + if (0 == m.Error) { + return m.ReturnValue; + } + if (EACCES != m.Error) { + errno = m.Error; + return -1; + } + + // + // The rename operation failed because the target already + // exists. This happens when trying to rename a directory + // over an existing directory, which POSIX requires but + // NT filesystems don't support. We emulate here. + // + + if (been_here) { + errno = EACCES; + return -1; + } + been_here++; + + // block all signals during the operation. + + sigfillset(&set); + sigprocmask(SIG_SETMASK, &set, &oset); + + r = 0; + + // + // Figure out a temporary pathname to use. The temporary + // dir is created in the same directory as 'new'. + // + + strcpy(path, new); + + // take care of paths that end in slash... + + for (;;) { + i = strlen(path) - 1; + if ('/' == path[i]) { + path[i] = '\0'; + } else { + break; + } + } + + pch = strrchr(path, '/'); + if (NULL != pch) { + ++pch; + strcpy(pch, "_psxtmp.d"); + } else { + // 'new' is in the cwd + + strcpy(path, "_psxtmp.d"); + pch = path; + } + + for (c = 'a'; ; c++) { + if (c > 'z') { + errno = EEXIST; + return -1; + } + *pch = c; + + if (-1 == (r = rename(new, path))) { + if (EEXIST == errno) { + // try the next letter for tmp path + continue; + } + errno = EACCES; // reset errno + break; + } + if (-1 == (r = rename(old, new))) { + (void)rename(path, new); + break; + } + if (-1 == rmdir(path)) { + if (-1 == (r = rename(new, old))) { + // + // If we don't bail here, the following call + // to rename will recurse infinitely. + // + break; + } + (void)rename(path, new); + r = -1; + break; + } + break; + } + been_here = 0; + sigprocmask(SIG_SETMASK, &oset, NULL); + return r; +} + +int +_CRTAPI1 +unlink(const char *path) +{ + PSX_API_MSG m; + NTSTATUS Status; + PPSX_UNLINK_MSG args; + + args = &m.u.Unlink; + PSX_FORMAT_API_MSG(m, PsxUnlinkApi, sizeof(*args)); + + if (!PdxCanonicalize((PSZ)path, &args->Path_U, PdxPortHeap)) { + return -1; + } + + m.DataBlock = args->Path_U.Buffer; + args->Path_U.Buffer = (PWSTR)((PCHAR)m.DataBlock + + PsxPortMemoryRemoteDelta); + + Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(Status)); +#endif + + RtlFreeHeap(PdxPortHeap, 0, (PVOID)m.DataBlock); + + if (m.Error) { + errno = (int)m.Error; + return -1; + } + return 0; +} + +int +_CRTAPI1 +link(const char *existing, const char *new) +{ + PPSX_LINK_MSG args; + PSX_API_MSG m; + UNICODE_STRING old_U, new_U; + NTSTATUS Status; + + args = &m.u.Link; + PSX_FORMAT_API_MSG(m, PsxLinkApi, sizeof(*args)); + + if (!PdxCanonicalize((PSZ)existing, &old_U, PdxPortHeap)) { + return -1; + } + + if (!PdxCanonicalize((PSZ)new, &new_U, PdxPortHeap)) { + RtlFreeHeap(PdxPortHeap, 0, (PVOID)old_U.Buffer); + return -1; + } + + args->OldName = old_U; + args->NewName = new_U; + + args->OldName.Buffer = + (PVOID)((PCHAR)old_U.Buffer + PsxPortMemoryRemoteDelta); + args->NewName.Buffer = + (PVOID)((PCHAR)new_U.Buffer + PsxPortMemoryRemoteDelta); + + Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(Status)); +#endif + + RtlFreeHeap(PdxPortHeap, 0, (PVOID)new_U.Buffer); + RtlFreeHeap(PdxPortHeap, 0, (PVOID)old_U.Buffer); + + if (0 != m.Error) { + errno = m.Error; + return -1; + } + return 0; +} diff --git a/private/posix/client/dllinit.c b/private/posix/client/dllinit.c new file mode 100644 index 000000000..8430706b9 --- /dev/null +++ b/private/posix/client/dllinit.c @@ -0,0 +1,377 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + dllinit.c + +Abstract: + + This module contains the initialization code for the POSIX Subsystem + Client DLL. + +Author: + + Mark Lucovsky (markl) 27-Jun-1989 + +Environment: + + User Mode only + +Revision History: + + Ellen Aycock-Wright (ellena) 03-Jan-1991 + Converted to DLL initialization routine. + +--*/ + +#include +#include +#include "psxdll.h" + +extern void ClientOpen(int); + +ULONG PsxPortMemoryRemoteDelta; +PVOID PsxPortMemoryBase; + +BOOLEAN +PsxDllInitialize( + IN PVOID DllHandle, + IN ULONG Reason, + IN PCONTEXT Context OPTIONAL + ) + +/*++ + +Routine Description: + + This function is the DLL initialization routine for the POSIX Emulation + Subsystem Client DLL. This function gets control when the applications + links to this DLL are snapped. + +Arguments: + + Context - Supplies an optional context buffer that will be restored + after all DLL initialization has been completed. If this + parameter is NULL then this is a dynamic snap of this module. + Otherwise this is a static snap prior to the user process + gaining control. + +Return Value: + + False if initialization failed. + +--*/ +{ + PPEB Peb; + PPEB_PSX_DATA PebPsxData; + NTSTATUS Status; + + if (Reason != DLL_PROCESS_ATTACH) { + return TRUE; + } + + // + // Remember our DLL handle in a global variable. + // + + PsxDllHandle = DllHandle; + + PdxHeap = RtlCreateHeap( HEAP_GROWABLE | HEAP_NO_SERIALIZE, + NULL, + 64 * 1024, // Initial size of heap is 64K + 4 * 1024, + 0, + NULL + ); + + if (PdxHeap == NULL) { + return FALSE; + } + + Status = PsxInitDirectories(); + if ( !NT_SUCCESS( Status )) { + return FALSE; + } + + Status = PsxConnectToServer(); + if (!NT_SUCCESS(Status)) { + return FALSE; + } + + Peb = NtCurrentPeb(); + + // + // This is not really an ANSI_STRING but an undocumented data + // structure. Read crt32psx\startup\crt0.c for the code that + // interprets this. + // + + + PsxAnsiCommandLine = *(PANSI_STRING)&(Peb->ProcessParameters->CommandLine); + if (ARGUMENT_PRESENT(Context)) { + PebPsxData = (PPEB_PSX_DATA)Peb->SubSystemData; + PebPsxData->ClientStartAddress = (PVOID)CONTEXT_TO_PROGRAM_COUNTER(Context); + (PVOID)CONTEXT_TO_PROGRAM_COUNTER(Context) = (PVOID)PdxProcessStartup; + } + + return TRUE; +} + +NTSTATUS +PsxInitDirectories() +{ + + PdxDirectoryPrefix.NtCurrentWorkingDirectory.Buffer = + RtlAllocateHeap(PdxHeap, 0,2*PATH_MAX); + PdxDirectoryPrefix.NtCurrentWorkingDirectory.Length = 0; + PdxDirectoryPrefix.NtCurrentWorkingDirectory.MaximumLength = 2*PATH_MAX; + + PdxDirectoryPrefix.PsxCurrentWorkingDirectory.Buffer = + RtlAllocateHeap(PdxHeap, 0,PATH_MAX+1); + PdxDirectoryPrefix.PsxCurrentWorkingDirectory.Length = 0; + PdxDirectoryPrefix.PsxCurrentWorkingDirectory.MaximumLength = PATH_MAX+1; + + PdxDirectoryPrefix.PsxRoot.Buffer = RtlAllocateHeap(PdxHeap, 0,2*PATH_MAX); + PdxDirectoryPrefix.PsxRoot.Length = 0; + PdxDirectoryPrefix.PsxRoot.MaximumLength = 2*PATH_MAX; + + // + // Check that memory allocations worked. If not, then bail out + // + + ASSERT(PdxDirectoryPrefix.NtCurrentWorkingDirectory.Buffer); + ASSERT(PdxDirectoryPrefix.PsxCurrentWorkingDirectory.Buffer); + ASSERT(PdxDirectoryPrefix.PsxRoot.Buffer); + + if ( PdxDirectoryPrefix.NtCurrentWorkingDirectory.Buffer == NULL | + PdxDirectoryPrefix.PsxCurrentWorkingDirectory.Buffer== NULL | + PdxDirectoryPrefix.PsxRoot.Buffer == NULL ) { + + return ( STATUS_NO_MEMORY ); + } + return ( STATUS_SUCCESS ); +} + +NTSTATUS +PsxConnectToServer(VOID) +{ + UNICODE_STRING PsxPortName; + PSX_API_CONNECTINFO ConnectionInformation; + ULONG ConnectionInformationLength; + PULONG AmIBeingDebugged; + REMOTE_PORT_VIEW ServerView; + HANDLE PortSection; + PPEB Peb; + PPEB_PSX_DATA PebPsxData; + PORT_VIEW ClientView; + LARGE_INTEGER SectionSize; + SECURITY_QUALITY_OF_SERVICE DynamicQos; + NTSTATUS Status; + + ConnectionInformationLength = sizeof(ConnectionInformation); + + // + // Create a section to contain the Port Memory. Port Memory is private + // memory that is shared between the POSIX client and server processes. + // This allows data that is too large to fit into an API request message + // to be passed to the POSIX server. + // + + SectionSize.LowPart = PSX_CLIENT_PORT_MEMORY_SIZE; + SectionSize.HighPart = 0; + + // SEC_RESERVE + + Status = NtCreateSection(&PortSection, SECTION_ALL_ACCESS, NULL, + &SectionSize, PAGE_READWRITE, SEC_COMMIT, NULL); + if (!NT_SUCCESS(Status)) { + KdPrint(("PSXDLL: NtCreateSection: 0x%x\n", Status)); + return Status; + } + + // + // Get the Peb address. Allocate the POSIX subsystem specific portion + // within the Peb. This structure will be filled in by the server + // process as part of the connect logic. + // + + Peb = NtCurrentPeb(); + Peb->SubSystemData = RtlAllocateHeap(Peb->ProcessHeap, 0, + sizeof(PEB_PSX_DATA)); + ASSERT(NULL != Peb->SubSystemData); + + PebPsxData = (PPEB_PSX_DATA)Peb->SubSystemData; + PebPsxData->Length = sizeof(PEB_PSX_DATA); + + // + // Connect to the POSIX Emulation Subsystem server. This includes a + // description of the Port Memory section so that the LPC connection + // logic can make the section visible to both the client and server + // processes. Also pass information the POSIX server needs in the + // connection information structure. + // + + ClientView.Length = sizeof(ClientView); + ClientView.SectionHandle = PortSection; + ClientView.SectionOffset = 0; + ClientView.ViewSize = SectionSize.LowPart; + ClientView.ViewBase = 0; + ClientView.ViewRemoteBase = 0; + + ServerView.Length = sizeof(ServerView); + ServerView.ViewSize = 0; + ServerView.ViewBase = 0; + + ConnectionInformation.SignalDeliverer = _PdxSignalDeliverer; + ConnectionInformation.NullApiCaller = _PdxNullApiCaller; + ConnectionInformation.DirectoryPrefix = &PdxDirectoryPrefix; + ConnectionInformation.InitialPebPsxData.Length = PebPsxData->Length; + + // + // Set up the security quality of service parameters to use over the + // port. + // + + DynamicQos.ImpersonationLevel = SecurityImpersonation; + DynamicQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; + DynamicQos.EffectiveOnly = TRUE; + + RtlInitUnicodeString(&PsxPortName, PSX_SS_API_PORT_NAME); + + Status = NtConnectPort(&PsxPortHandle, &PsxPortName, &DynamicQos, + &ClientView, &ServerView, NULL, + (PVOID)&ConnectionInformation, + (PULONG)&ConnectionInformationLength); + + NtClose(PortSection); + + if (!NT_SUCCESS(Status)) { + KdPrint(("PSXDLL: Unable to connect to Posix server: %lx\n", + Status)); + return Status; + } + + Status = NtRegisterThreadTerminatePort(PsxPortHandle); + ASSERT(NT_SUCCESS(Status)); + + PsxPortMemoryBase = ClientView.ViewBase; + PsxPortMemoryRemoteDelta = (ULONG)ClientView.ViewRemoteBase - + (ULONG)ClientView.ViewBase; + + RtlMoveMemory((PVOID)PebPsxData, + (PVOID)&ConnectionInformation.InitialPebPsxData, + PebPsxData->Length); + + PdxPortHeap = RtlCreateHeap( HEAP_NO_SERIALIZE, + ClientView.ViewBase, + ClientView.ViewSize, + ClientView.ViewSize, + 0, + 0 + ); + + if (PdxPortHeap == NULL) { + KdPrint(("PsxConnectToServer: RtlCreateHeap failed\n")); + return STATUS_NO_MEMORY; + } + + // + // Connect to the session console port and + // set the port handle in the PEB. + // + + Status = PsxInitializeSessionPort((ULONG) PebPsxData->SessionPortHandle); + if (!NT_SUCCESS(Status)) { + KdPrint(("PsxConnectToServer: PsxInitSessionPort failed\n")); + return Status; + } + return STATUS_SUCCESS; +} + + +// +// User mode process entry point. +// + +VOID +PdxProcessStartup( + IN PPEB Peb + ) + +{ + PPEB_PSX_DATA PebPsxData; + PFNPROCESS StartAddress; + int ReturnCodeFromMain; + + PebPsxData = (PPEB_PSX_DATA)Peb->SubSystemData; + StartAddress = (PFNPROCESS)(PebPsxData->ClientStartAddress); + + ReturnCodeFromMain = (*StartAddress) (0, NULL); + + _exit(ReturnCodeFromMain); + + NtTerminateProcess(NtCurrentProcess(),STATUS_ACCESS_DENIED); + +} + + +VOID +PdxNullApiCaller( + IN PCONTEXT Context + ) +{ + PdxNullPosixApi(); +#ifdef _X86_ + Context->Eax = 0; +#endif + NtContinue(Context,FALSE); + //NOTREACHED +} + + +VOID +PdxSignalDeliverer ( + IN PCONTEXT Context, + IN sigset_t PreviousBlockMask, + IN int Signal, + IN _handler Handler + ) +{ + (Handler)(Signal); + sigprocmask(SIG_SETMASK, &PreviousBlockMask, NULL); + + +#ifdef _X86_ + Context->Eax = 0; +#endif + NtContinue(Context, FALSE); + //NOTREACHED +} + +VOID +__PdxInitializeData( + IN int *perrno, + IN char ***penviron + ) +/*++ + +Routine Description: + + This function is called from the RTL startup code to notify the DLL of + the location of the variable 'errno'. Necessary because DLLs cannot + export data. + +Arguments: + + perrno - Supplies the address of errno - declared in rtl/startup.c + +Return Value: + None. + +--*/ +{ + Errno = perrno; + Environ = penviron; +} diff --git a/private/posix/client/dllio.c b/private/posix/client/dllio.c new file mode 100644 index 000000000..18eba2440 --- /dev/null +++ b/private/posix/client/dllio.c @@ -0,0 +1,694 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + dllio.c + +Abstract: + + Client implementation of Input and Output Primitives for POSIX + +Author: + + Mark Lucovsky 21-Feb-1989 + +Revision History: + +--*/ + +#include +#include +#include +#include +#include "psxdll.h" + +int +_CRTAPI1 +close(int fildes) +{ + PSX_API_MSG m; + NTSTATUS st; + PPSX_CLOSE_MSG args; + + args = &m.u.Close; + PSX_FORMAT_API_MSG(m, PsxCloseApi, sizeof(*args)); + + args->FileDes = fildes; + + st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(st)); +#endif + + if (m.Error) { + errno = (int)m.Error; + return -1; + } + return m.ReturnValue; +} + +int +_CRTAPI1 +creat(const char *path, mode_t mode) +{ + return open(path, O_CREAT | O_WRONLY | O_TRUNC, mode); +} + +off_t +_CRTAPI1 +lseek(int fildes, off_t offset, int whence) +{ + PSX_API_MSG m; + NTSTATUS st; + PPSX_LSEEK_MSG args; + + args = &m.u.Lseek; + PSX_FORMAT_API_MSG(m, PsxLseekApi, sizeof(*args)); + + args->FileDes = fildes; + args->Whence = whence; + args->Offset = offset; + + st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(st)); +#endif + + if (m.Error) { + errno = (int)m.Error; + return -1; + } + return args->Offset; +} + +int +_CRTAPI2 +open(const char *path, int oflag, ...) +{ + PSX_API_MSG m; + NTSTATUS st; + PPSX_OPEN_MSG args; + int i; + + va_list va_arg; + + va_start(va_arg, oflag); + + args = &m.u.Open; + PSX_FORMAT_API_MSG(m, PsxOpenApi, sizeof(*args)); + + args->Flags = oflag; + + if (oflag & O_CREAT) { + + // + // Create requires a third parameter of type mode_t + // which supplies the mode for a file being created + // + + args->Mode = va_arg(va_arg, mode_t); + } + + va_end(va_arg); + + if (!PdxCanonicalize((PSZ)path, &args->Path_U, PdxPortHeap)) { + return -1; + } + + ASSERT(NULL != wcschr(args->Path_U.Buffer, L'\\')); + + m.DataBlock = args->Path_U.Buffer; + args->Path_U.Buffer = (PWSTR)((PCHAR)m.DataBlock + + PsxPortMemoryRemoteDelta); + + for (;;) { + st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(st)); +#endif + + if (EINTR == m.Error && SIGCONT == m.Signal) { + // + // The syscall was stopped and continued. Call again + // instead of returning EINTR. + // + + PSX_FORMAT_API_MSG(m, PsxOpenApi, sizeof(*args)); + continue; + } + if (m.Error) { + args->Path_U.Buffer = m.DataBlock; + RtlFreeHeap(PdxPortHeap, 0, (PVOID)args->Path_U.Buffer); + errno = (int)m.Error; + return -1; + } + + // successful return + break; + } + + args->Path_U.Buffer = m.DataBlock; + RtlFreeHeap(PdxPortHeap, 0, (PVOID)args->Path_U.Buffer); + + return m.ReturnValue; +} + +int +_CRTAPI1 +pipe(int *fildes) +{ + PSX_API_MSG m; + NTSTATUS st; + PPSX_PIPE_MSG args; + + args = &m.u.Pipe; + PSX_FORMAT_API_MSG(m, PsxPipeApi, sizeof(*args)); + + st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(st)); +#endif + + if (m.Error) { + errno = (int)m.Error; + return -1; + } + + try { + fildes[0] = args->FileDes0; + fildes[1] = args->FileDes1; + } except (EXCEPTION_EXECUTE_HANDLER) { + st = STATUS_UNSUCCESSFUL; + } + if (!NT_SUCCESS(st)) { + errno = EFAULT; + return -1; + } + + return 0; +} + +int +_CRTAPI1 +read(int fildes, void *buf, unsigned int nbyte) +{ + PSX_API_MSG m; + PPSX_READ_MSG args; + NTSTATUS Status; + PVOID SesBuf; + SCREQUESTMSG Request; + int flags; + + args = &m.u.Read; + + PSX_FORMAT_API_MSG(m, PsxReadApi, sizeof(*args)); + + for (;;) { + args->FileDes = fildes; + args->Buf = buf; + args->Nbytes = nbyte; + args->Command = IO_COMMAND_DONE; + + Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(Status)); +#endif + + if (EINTR == m.Error && SIGCONT == m.Signal) { + // + // The system call was stopped and continued. Call again + // instead of returning EINTR. + // + PSX_FORMAT_API_MSG(m, PsxReadApi, sizeof(*args)); + continue; + } + if (m.Error) { + errno = (int)m.Error; + return -1; + } + break; + } + if (IO_COMMAND_DONE == args->Command) { + return m.ReturnValue; + } + + ASSERT(IO_COMMAND_DO_CONSIO == args->Command); + + flags = args->Scratch1; // do nonblocking io? + + // + // The server says we should read data from the console. + // + + if (nbyte > PSX_CON_PORT_DATA_SIZE) { + nbyte = PSX_CON_PORT_DATA_SIZE; + } + SesBuf = ((PPEB_PSX_DATA)NtCurrentPeb()->SubSystemData)->SessionDataBaseAddress; + Request.Request = ConRequest; + Request.d.Con.Request = ScReadFile; + Request.d.Con.d.IoBuf.Handle = (HANDLE)args->FileDes; + Request.d.Con.d.IoBuf.Len = nbyte; + + if (flags & O_NONBLOCK) { + Request.d.Con.d.IoBuf.Flags = PSXSES_NONBLOCK; + } else { + Request.d.Con.d.IoBuf.Flags = 0; + } + + Status = SendConsoleRequest(&Request); + + // + // Want to handle any signals generated as a result of console + // operations. + // + + PdxNullPosixApi(); + + if (0 != Status) { + errno = Status; + return -1; + } + + nbyte = Request.d.Con.d.IoBuf.Len; + if (-1 == nbyte) { + KdPrint(("PSXDLL: Didn't expect to get here\n")); + errno = EINTR; + return -1; + } + + memcpy(buf, SesBuf, nbyte); + return nbyte; +} + + +ssize_t +_CRTAPI1 +write(int fildes, const void *buf, size_t nbyte) +{ + PSX_API_MSG m; + PPSX_WRITE_MSG args; + NTSTATUS Status; + PVOID SesBuf; + SCREQUESTMSG Request; + int flags; + + args = &m.u.Write; + + PSX_FORMAT_API_MSG(m, PsxWriteApi, sizeof(*args)); + + args->FileDes = fildes; + args->Buf = (void *)buf; + args->Nbytes = nbyte; + args->Command = IO_COMMAND_DONE; + + for (;;) { + Status = NtRequestWaitReplyPort(PsxPortHandle, + (PPORT_MESSAGE)&m, (PPORT_MESSAGE)&m); + if (!NT_SUCCESS(Status)) { +#ifdef PSX_MORE_ERRORS + KdPrint(("PSXDLL: write: NtRequestWaitReplyPort: 0x%x\n", Status)); +#endif + _exit(0); + } + + if (m.Error == EINTR && m.Signal == SIGCONT) { + // + // The system call was stopped and continued. Call + // again instead of returning EINTR. + // + PSX_FORMAT_API_MSG(m, PsxWriteApi, sizeof(*args)); + continue; + } + if (m.Error) { + errno = (int)m.Error; + return -1; + } + break; + } + if (IO_COMMAND_DONE == args->Command) { + return m.ReturnValue; + } + ASSERT(IO_COMMAND_DO_CONSIO == args->Command); + + flags = args->Scratch1; + + if (nbyte > PSX_CON_PORT_DATA_SIZE) { + nbyte = PSX_CON_PORT_DATA_SIZE; + } + SesBuf = ((PPEB_PSX_DATA)(NtCurrentPeb()->SubSystemData))->SessionDataBaseAddress; + Request.Request = ConRequest; + Request.d.Con.Request = ScWriteFile; + Request.d.Con.d.IoBuf.Handle = (HANDLE)args->FileDes; + Request.d.Con.d.IoBuf.Len = nbyte; + + if (flags & O_NONBLOCK) { + Request.d.Con.d.IoBuf.Flags = PSXSES_NONBLOCK; + } + + memcpy(SesBuf, buf, nbyte); + + Status = SendConsoleRequest(&Request); + if (!NT_SUCCESS(Status)) { + errno = PdxStatusToErrno(Status); + return -1; + } + + // + // Want to handle any signals generated as a result of console + // operations. + // + + PdxNullPosixApi(); + + if (-1 == Request.d.Con.d.IoBuf.Len) { + errno = EBADF; + } + return Request.d.Con.d.IoBuf.Len; +} + +int +_CRTAPI1 +dup(int fildes) +{ + return fcntl(fildes, F_DUPFD, 0); +} + +int +_CRTAPI1 +dup2(int fd, int fd2) +{ + PSX_API_MSG m; + NTSTATUS st; + PPSX_DUP2_MSG args; + + args = &m.u.Dup2; + PSX_FORMAT_API_MSG(m, PsxDup2Api, sizeof(*args)); + + args->FileDes = fd; + args->FileDes2 = fd2; + + st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(st)); +#endif + + if (m.Error) { + errno = (int)m.Error; + return -1; + } + + return (int)m.ReturnValue; +} + +int +_CRTAPI2 +fcntl(int fildes, int cmd, ...) +{ + PSX_API_MSG m; + NTSTATUS Status; + PPSX_FCNTL_MSG args; + struct flock *pf, **ppf, *tpf = NULL; + int i; + + va_list optarg; + + va_start(optarg, cmd); + + args = &m.u.Fcntl; + PSX_FORMAT_API_MSG(m, PsxFcntlApi, sizeof(*args)); + + args->FileDes = fildes; + args->Command = cmd; + + switch (cmd) { + case F_DUPFD: + + // third arg is type int + + args->u.i = va_arg(optarg, int); + va_end(optarg); + break; + + case F_GETFD: + + // no third arg + + va_end(optarg); + break; + + case F_SETFD: + + // third arg is type int + + args->u.i = va_arg(optarg, int); + va_end(optarg); + break; + + case F_GETFL: + + // no third arg + + va_end(optarg); + break; + + case F_SETFL: + // third arg is type int + + args->u.i = va_arg(optarg, int); + va_end(optarg); + break; + + case F_GETLK: + case F_SETLK: + case F_SETLKW: + + // third arg is type struct flock* + + pf = va_arg(optarg, struct flock *); + va_end(optarg); + + tpf = RtlAllocateHeap(PdxPortHeap, 0, sizeof(struct flock)); + if (NULL == tpf) { + errno = ENOMEM; + return -1; + } + + Status = STATUS_SUCCESS; + try { + memcpy((PVOID)tpf, (PVOID)pf, sizeof(struct flock)); + } except (EXCEPTION_EXECUTE_HANDLER) { + Status = STATUS_UNSUCCESSFUL; + } + if (!NT_SUCCESS(Status)) { + RtlFreeHeap(PdxPortHeap, 0, (PVOID)tpf); + errno = EFAULT; + return -1; + } + + args->u.pf = (struct flock *)((PCHAR)tpf + PsxPortMemoryRemoteDelta); + + break; +#if DBG + case 99: + // no third arg + va_end(optarg); + break; +#endif + default: + // unknown command + va_end(optarg); + errno = EINVAL; + return -1; + } + + for (;;) { + Status = NtRequestWaitReplyPort(PsxPortHandle, + (PPORT_MESSAGE)&m, (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + if (!NT_SUCCESS(Status)) { + KdPrint(("PSXDLL: fcntl: NtRequest: 0x%x\n", Status)); + NtTerminateProcess(NtCurrentProcess(), 1); + } + ASSERT(NT_SUCCESS(Status)); +#endif + + if (m.Error == EINTR && m.Signal == SIGCONT) { + PSX_FORMAT_API_MSG(m, PsxFcntlApi, sizeof(*args)); + continue; + } + if (m.Error) { + if (NULL != tpf) { + RtlFreeHeap(PdxPortHeap, 0, (PVOID)tpf); + } + errno = (int)m.Error; + return -1; + } + + // successful return + + break; + } + + if (NULL != tpf) { + // copy the flock back to the caller's address + + if (F_GETLK == cmd) { + // + // Copy the retrieved lock back into the user's buf. + // + memcpy((PVOID)pf, (PVOID)tpf, sizeof(struct flock)); + } + RtlFreeHeap(PdxPortHeap, 0, (PVOID)tpf); + } + + return (int)m.ReturnValue; +} + +int +_CRTAPI1 +isatty(int fd) +{ + PSX_API_MSG m; + NTSTATUS Status; + PPSX_ISATTY_MSG args; + SCREQUESTMSG Request; + + args = &m.u.Isatty; + PSX_FORMAT_API_MSG(m, PsxIsattyApi, sizeof(*args)); + + args->FileDes = fd; + args->Command = IO_COMMAND_DONE; + + Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(Status)); +#endif + + if (m.Error) { + errno = (int)m.Error; + return 0; + } + + if (IO_COMMAND_DONE == args->Command) { + return m.ReturnValue; + } + ASSERT(IO_COMMAND_DO_CONSIO == args->Command); + + Request.Request = ConRequest; + Request.d.Con.Request = ScIsatty; + Request.d.Con.d.IoBuf.Handle = (HANDLE)args->FileDes; + + Status = SendConsoleRequest(&Request); + if (!NT_SUCCESS(Status)) { + errno = PdxStatusToErrno(Status); + return 0; + } + + // + // When the request returns, Len holds the value we're + // supposed to return, 0 or 1, and -1 for error. + // + + if (-1 == Request.d.Con.d.IoBuf.Len) { + errno = EBADF; + return 0; + } + return Request.d.Con.d.IoBuf.Len; +} + +// +// isatty2 -- just like isatty, but more permissive. Will return +// TRUE if fd open on a console window, even if _POSIX_TERM is +// not set. +// + +int +_CRTAPI1 +isatty2(int fd) +{ + PSX_API_MSG m; + NTSTATUS Status; + PPSX_ISATTY_MSG args; + SCREQUESTMSG Request; + + args = &m.u.Isatty; + PSX_FORMAT_API_MSG(m, PsxIsattyApi, sizeof(*args)); + + args->FileDes = fd; + args->Command = IO_COMMAND_DONE; + + Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(Status)); +#endif + + if (m.Error) { + errno = (int)m.Error; + return 0; + } + + if (IO_COMMAND_DONE == args->Command) { + return m.ReturnValue; + } + ASSERT(IO_COMMAND_DO_CONSIO == args->Command); + + Request.Request = ConRequest; + Request.d.Con.Request = ScIsatty2; + Request.d.Con.d.IoBuf.Handle = (HANDLE)args->FileDes; + + Status = SendConsoleRequest(&Request); + if (!NT_SUCCESS(Status)) { + errno = PdxStatusToErrno(Status); + return 0; + } + + // + // When the request returns, Len holds the value we're + // supposed to return, 0 or 1, and -1 for error. + // + + if (-1 == Request.d.Con.d.IoBuf.Len) { + errno = EBADF; + return 0; + } + return Request.d.Con.d.IoBuf.Len; +} + +int +_CRTAPI1 +ftruncate(int fildes, off_t len) +{ + PSX_API_MSG m; + PPSX_FTRUNCATE_MSG args; + NTSTATUS Status; + + args = &m.u.Ftruncate; + + PSX_FORMAT_API_MSG(m, PsxFtruncateApi, sizeof(*args)); + + args->FileDes = fildes; + args->Length = len; + + Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); + if (!NT_SUCCESS(Status)) { + return -1; + } + + if (m.Error) { + errno = (int)m.Error; + return -1; + } + + return 0; +} diff --git a/private/posix/client/dllname.c b/private/posix/client/dllname.c new file mode 100644 index 000000000..83a562381 --- /dev/null +++ b/private/posix/client/dllname.c @@ -0,0 +1,310 @@ +#include "psxdll.h" + +#if DBG +VOID DumpNames(PSZ, PSTRING ); +#endif //DBG + +PSTRING +SetPrefix( + char **Source + ) +{ + static STRING SparePrefix; // pointer to this may be returned + static char PrefixBuf[512]; + + // + // Test for leading slash. This tells us whether to start at the root + // or at the current working directory. + // + + if (!IS_POSIX_PATH_SEPARATOR(*Source)) { + // relative pathname + return &PdxDirectoryPrefix.NtCurrentWorkingDirectory; + } + + if (!IS_POSIX_PATH_SEPARATOR(&(*Source)[1])) { + // first char is slash, but second is not. Start at root. + return &PdxDirectoryPrefix.PsxRoot; + } + if (IS_POSIX_PATH_SEPARATOR(&(*Source)[2])) { + // first three chars are slashes; interpreted as single slash. + return &PdxDirectoryPrefix.PsxRoot; + } + + // + // The path starts with "//something": + // //X/ is \DosDevices\X:\ + // + + memset(PrefixBuf, 0, sizeof(PrefixBuf)); + strcpy(PrefixBuf, "\\DosDevices\\"); + + strncat(PrefixBuf, &(*Source)[2], 1); // get "X" + strcat(PrefixBuf, ":"); // make "X:" + *Source += 3; + + SparePrefix.Buffer = PrefixBuf; + SparePrefix.Length = strlen(PrefixBuf); + SparePrefix.MaximumLength = sizeof(PrefixBuf); + + return &SparePrefix; +} + +BOOLEAN +PdxCanonicalize( + IN PCHAR PathName, + OUT PUNICODE_STRING CanonPath_U, + IN PVOID Heap + ) + +/*++ + +Routine Description: + + This function accepts a POSIX pathname and converts it into a + Unicode NT pathname. + +Arguments: + + PathName - Supplies the POSIX pathname to be translated. + + CanonPath_U - Returns the canonicalized Unicode NT pathname. On a + successful call, storage is allocated and the CannonPath_U->Buffer + points to the allocated storage. + + Heap - Supplies the heap that should be used to allocate storage from + to store the canonicalized pathname. + +Return Value: + + TRUE - The pathname was successfully canonicalized. Storage was + allocated, and the CanonPath_U string is initialized. + + FALSE - The pathname was not canonicalized. No Storage was + allocated, and the CanonPath_U string is not initialized. The + 'errno' variable is set appropriately in this case. + + +--*/ + +{ + ANSI_STRING AnsiCanonPath; + PANSI_STRING CanonPath_A; + LONG PathNameLength; + char *Source, *Dest, *pch; + PSTRING Prefix; + ULONG UnicodeLength; + NTSTATUS Status; + + CanonPath_A = &AnsiCanonPath; + CanonPath_A->Buffer = NULL; + + try { + PathNameLength = strlen(PathName); + } except (EXCEPTION_EXECUTE_HANDLER) { + PathNameLength = -1; + } + if (PathNameLength == -1) { + errno = EFAULT; + return FALSE; + } + if (PathNameLength == 0) { + errno = ENOENT; + return FALSE; + } + if (PathNameLength > PATH_MAX) { + errno = ENAMETOOLONG; + return FALSE; + } + + Source = PathName; + + Prefix = SetPrefix(&Source); + + CanonPath_A->MaximumLength = (USHORT)(PathNameLength + Prefix->Length + 1); + CanonPath_A->Buffer = RtlAllocateHeap(Heap, 0, CanonPath_A->MaximumLength); + if (NULL == CanonPath_A->Buffer) { + errno = ENOMEM; + return FALSE; + } + + // + // Copy the prefix + // + + RtlCopyString(CanonPath_A, Prefix); + + Dest = CanonPath_A->Buffer + CanonPath_A->Length; + + while ('\0' != *Source) switch (*Source) { + case '/': + // Skip adjacent /'s + + if (Dest[-1] != '\\') { + *Dest++ = '\\'; + } + + while (IS_POSIX_PATH_SEPARATOR(Source)) { + Source++; + } + break; + case '.': + // + // Eat single dots as in "/./". For dot-dot back up one level. + // Any other dot is just a filename character. + // + + if (IS_POSIX_DOT(Source)) { + Source++; + break; + } + if (IS_POSIX_DOT_DOT(Source)) { + UNICODE_STRING U; + OBJECT_ATTRIBUTES Obj; + HANDLE FileHandle; + IO_STATUS_BLOCK Iosb; + + // back up destination string looking for a \. + + do { + Dest--; + } while (*Dest != '\\'); + + // + // Make sure the directory that we're using dot-dot + // in actually exists. + // + + if (Dest == CanonPath_A->Buffer + + PdxDirectoryPrefix.PsxRoot.Length) { + *(Dest + 1) = '\000'; + } else { + *Dest = '\000'; + } + + CanonPath_A->Length = strlen(CanonPath_A->Buffer); + Status = RtlAnsiStringToUnicodeString(&U, CanonPath_A, + TRUE); + if (!NT_SUCCESS(Status)) { + RtlFreeHeap(Heap, 0, CanonPath_A->Buffer); + errno = ENOMEM; + return FALSE; + } + InitializeObjectAttributes(&Obj, &U, 0, NULL, 0); + Status = NtOpenFile(&FileHandle, SYNCHRONIZE, &Obj, + &Iosb, + FILE_SHARE_READ|FILE_SHARE_WRITE| + FILE_SHARE_DELETE, + FILE_SYNCHRONOUS_IO_NONALERT | + FILE_DIRECTORY_FILE); + RtlFreeUnicodeString(&U); + if (!NT_SUCCESS(Status)) { + RtlFreeHeap(Heap, 0, CanonPath_A->Buffer); + errno = PdxStatusToErrno(Status); + return FALSE; + } + NtClose(FileHandle); + + // + // Back up to previous component: "\a\b\c\" to "\a\b\". + // But if we come to the root, we stay there. + // + + do { + if (Dest == CanonPath_A->Buffer + + PdxDirectoryPrefix.PsxRoot.Length) { + *Dest++ = '\\'; + break; + } + Dest--; + } while (*Dest != '\\'); + + // Advance source past the dot-dot + + Source += 2; + break; + } + + // This dot is just a filename character. + //FALLTHROUGH + + default: + // + // Copy a pathname component. If the pathname component + // is too long, return ENAMETOOLONG. Note that using a + // constant NAME_MAX is bogus, since it could be different + // for different filesystems. + // + + pch = strchr(Source, '/'); + if (NULL == pch) { + // this is the last component in the path. + + if (strlen(Source) > NAME_MAX) { + errno = ENAMETOOLONG; + RtlFreeHeap(Heap, 0, CanonPath_A->Buffer); + return FALSE; + } + } else { + if (pch - Source > NAME_MAX) { + errno = ENAMETOOLONG; + RtlFreeHeap(Heap, 0, CanonPath_A->Buffer); + return FALSE; + + } + } + + while (*Source != '\0' && *Source != '/') { + *Dest++ = *Source++; + } + } + + // + // Make sure that we never give back "/DosDevices/C:" ... the + // Object Manager doesn't deal with that, we need a trailing + // slash. + // + + if (Dest == CanonPath_A->Buffer + PdxDirectoryPrefix.PsxRoot.Length) { + if (Dest[-1] != '\\') { + *Dest++ = '\\'; + } + } + + CanonPath_A->Length = (USHORT)((ULONG)Dest - (ULONG)CanonPath_A->Buffer); + CanonPath_A->Buffer[CanonPath_A->Length] = '\0'; + + // Convert ansi pathname to unicode - use internal heap for Buffer + + UnicodeLength = RtlAnsiStringToUnicodeSize(CanonPath_A); + CanonPath_U->MaximumLength = (USHORT)UnicodeLength; + CanonPath_U->Buffer = RtlAllocateHeap(Heap, 0, UnicodeLength); + + if (NULL == CanonPath_U->Buffer) { + RtlFreeHeap(Heap, 0, CanonPath_A->Buffer); + errno = ENOMEM; + return FALSE; + } + + Status = RtlAnsiStringToUnicodeString(CanonPath_U, CanonPath_A, FALSE); + ASSERT(NT_SUCCESS(Status)); + + RtlFreeHeap(Heap, 0, CanonPath_A->Buffer); + return TRUE; +} + +#if DBG +VOID +DumpNames( + IN PSZ PathName, + IN PSTRING CanonPath_A + ) +{ + USHORT i; + PSZ p; + + KdPrint(("Input Path: \"%s\"\n",PathName)); + KdPrint(("Output Path: \"%Z\"\n", CanonPath_A)); +} + +#endif //DBG diff --git a/private/posix/client/dllproc.c b/private/posix/client/dllproc.c new file mode 100644 index 000000000..74b4b8039 --- /dev/null +++ b/private/posix/client/dllproc.c @@ -0,0 +1,1251 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + dllproc.c + +Abstract: + + This module implements POSIX process structure APIs + +Author: + + Mark Lucovsky (markl) 27-Jun-1989 + +Revision History: + +--*/ + +#include +#include +#include +#include +#include + +#ifdef _ALPHA_ +#include "psxalpha.h" +#endif +#ifdef _MIPS_ +#include "psxmips.h" +#endif +#ifdef _PPC_ +#include "psxppc.h" +#endif +#ifdef _X86_ +#include "psxi386.h" +#endif + +#include "psxdll.h" + +void +_CRTAPI1 +_exit(int status) +{ + PSX_API_MSG m; + PPSX_EXIT_MSG args; + NTSTATUS st; + + args = &m.u.Exit; + + PSX_FORMAT_API_MSG(m, PsxExitApi, sizeof(*args)); + + args->ExitStatus = (ULONG)status; + + st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); + +#ifdef PSX_MORE_ERRORS + if (!NT_SUCCESS(st)) { + KdPrint(("PSXDLL: _exit: 0x%x\n", st)); + } +#endif + NtTerminateProcess(NtCurrentProcess(), 0); +} + +gid_t +_CRTAPI1 +getegid(void) +{ + PSX_API_MSG m; + PPSX_GETIDS_MSG args; + NTSTATUS st; + + args = &m.u.GetIds; + + PSX_FORMAT_API_MSG(m, PsxGetIdsApi, sizeof(*args)); + + st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(st)); +#endif + return args->EffectiveGid; +} + +gid_t +_CRTAPI1 +getgid(void) +{ + PSX_API_MSG m; + PPSX_GETIDS_MSG args; + NTSTATUS st; + + args = &m.u.GetIds; + + PSX_FORMAT_API_MSG(m, PsxGetIdsApi, sizeof(*args)); + + st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(st)); +#endif + return args->RealGid; +} + +uid_t +_CRTAPI1 +geteuid(void) +{ + PSX_API_MSG m; + PPSX_GETIDS_MSG args; + NTSTATUS st; + + args = &m.u.GetIds; + + PSX_FORMAT_API_MSG(m, PsxGetIdsApi, sizeof(*args)); + + st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(st)); +#endif + return args->EffectiveUid; +} + +uid_t +_CRTAPI1 +getuid(void) +{ + PSX_API_MSG m; + PPSX_GETIDS_MSG args; + NTSTATUS st; + + args = &m.u.GetIds; + + PSX_FORMAT_API_MSG(m, PsxGetIdsApi, sizeof(*args)); + + st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(st)); +#endif + return args->RealUid; +} + +pid_t +_CRTAPI1 +getppid(void) +{ + PSX_API_MSG m; + PPSX_GETIDS_MSG args; + NTSTATUS st; + + args = &m.u.GetIds; + + PSX_FORMAT_API_MSG(m, PsxGetIdsApi, sizeof(*args)); + + st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(st)); +#endif + return args->ParentPid; +} + +pid_t +_CRTAPI1 +getpid(void) +{ + PSX_API_MSG m; + PPSX_GETIDS_MSG args; + NTSTATUS st; + + args = &m.u.GetIds; + + PSX_FORMAT_API_MSG(m, PsxGetIdsApi, sizeof(*args)); + + st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(st)); +#endif + return args->Pid; +} + +pid_t +_CRTAPI1 +getpgrp(void) +{ + PSX_API_MSG m; + PPSX_GETIDS_MSG args; + NTSTATUS st; + + args = &m.u.GetIds; + + PSX_FORMAT_API_MSG(m, PsxGetIdsApi, sizeof(*args)); + + st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(st)); +#endif + return args->GroupId; +} + +pid_t +_CRTAPI1 +setsid(void) +{ + PSX_API_MSG m; + NTSTATUS st; + + PSX_FORMAT_API_MSG(m, PsxSetSidApi, 0); + + st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(st)); +#endif + if (m.Error) { + errno = m.Error; + return -1; + } + return (pid_t)m.ReturnValue; +} + +int +_CRTAPI1 +setpgid(pid_t pid, pid_t pgid) +{ + PSX_API_MSG m; + PPSX_SETPGROUPID_MSG args; + NTSTATUS st; + + args = &m.u.SetPGroupId; + + PSX_FORMAT_API_MSG(m, PsxSetPGroupIdApi, sizeof(*args)); + + args->Pid = pid; + args->Pgid = pgid; + + st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(st)); +#endif + if (m.Error) { + errno = (int)m.Error; + return -1; + } + return (int)m.ReturnValue; +} + +pid_t +_CRTAPI1 +waitpid(pid_t pid, int *stat_loc, int options) +{ + PSX_API_MSG m; + PPSX_WAITPID_MSG args; + NTSTATUS st; + + args = &m.u.WaitPid; + + PSX_FORMAT_API_MSG(m, PsxWaitPidApi, sizeof(*args)); + + args->Pid = pid; + args->Options = options; + + for (;;) { + st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + if (!NT_SUCCESS(st)) { + KdPrint(("PSXDLL: waitpid: 0x%x\n", st)); + } + ASSERT(NT_SUCCESS(st)); +#endif + + if (EINTR == m.Error && SIGCONT == m.Signal) { + // We were stopped and then continued. Continue + // waiting. + + PSX_FORMAT_API_MSG(m, PsxWaitPidApi, sizeof(*args)); + continue; + } + + if (m.Error) { + errno = (int)m.Error; + return -1; + } + if (NULL != stat_loc) { + try { + *stat_loc = args->StatLocValue; + } except (EXCEPTION_EXECUTE_HANDLER) { + errno = EFAULT; + m.ReturnValue = (ULONG)-1; + } + } + return (int)m.ReturnValue; + } +} + +pid_t +_CRTAPI1 +wait(int *stat_loc) +{ + PSX_API_MSG m; + PPSX_WAITPID_MSG args; + NTSTATUS st; + + args = &m.u.WaitPid; + + PSX_FORMAT_API_MSG(m, PsxWaitPidApi, sizeof(*args)); + + args->Pid = (pid_t)-1; + args->Options = (pid_t)0; + + for (;;) { + st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + if (!NT_SUCCESS(st)) { + KdPrint(("PSXDLL: wait: NtRequest: 0x%x\n", st)); + } + ASSERT(NT_SUCCESS(st)); +#endif + + if (EINTR == m.Error && SIGCONT == m.Signal) { + // We were stopped and continued. Continue waiting. + PSX_FORMAT_API_MSG(m, PsxWaitPidApi, sizeof(*args)); + continue; + } + + if (m.Error) { + errno = (int)m.Error; + return -1; + } + if (ARGUMENT_PRESENT(stat_loc)) { + try { + *stat_loc = args->StatLocValue; + } except (EXCEPTION_EXECUTE_HANDLER) { + errno = EFAULT; + m.ReturnValue = (ULONG)-1; + } + } + return (int)m.ReturnValue; + } +} + +pid_t +_CRTAPI1 +fork(void) +{ + PSX_API_MSG m; + NTSTATUS st; + PPSX_FORK_MSG args; + PTEB ThreadInfo; + + args = &m.u.Fork; + +again: + PSX_FORMAT_API_MSG(m, PsxForkApi, sizeof(*args)); + + ThreadInfo = NtCurrentTeb(); + args->StackBase = ThreadInfo->NtTib.StackBase; + args->StackLimit = ThreadInfo->NtTib.StackLimit; + args->StackAllocationBase = ThreadInfo->DeallocationStack; + + try { + st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); + } except (EXCEPTION_EXECUTE_HANDLER) { + KdPrint(("PSXDLL: fork: took an exception\n")); + KdPrint(("PSXDLL: exception is 0x%x\n", GetExceptionCode())); + } +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(st)); +#endif + + if (st == PSX_FORK_RETURN) { + st = PsxConnectToServer(); + if (!NT_SUCCESS(st)) { + KdPrint(("PsxConnectToServer: 0x%x\n", st)); + NtTerminateProcess(NtCurrentProcess(), 1); + ASSERT(0); + } + + // take any pending signals now. + PdxNullPosixApi(); + return 0; + } + if (EINTR == m.Error) { + // try again. + goto again; + } + + if (m.Error) { + errno = (int)m.Error; + return -1; + } + + return (int)m.ReturnValue; +} + +// +// vexec -- Varargs exec program, called by execl*. +// + +int +vexec(const char *path, const char *arg0, char * const envp[], va_list arglist) +{ + NTSTATUS st; + PSX_API_MSG m; + PPSX_EXEC_MSG args; + + char **ppch; + char *pch, *pcharg; + int i; + int retval = 0; + char *Args; // the args + env for the call + + va_list save_arglist; + + try { + if (0 == *path) { + errno = ENOENT; + return -1; + } + } except (EXCEPTION_EXECUTE_HANDLER) { + errno = EFAULT; + retval = -1; + } + if (0 != retval) { + return retval; + } + + args = &m.u.Exec; + PSX_FORMAT_API_MSG(m, PsxExecApi, sizeof(*args)); + + if (!PdxCanonicalize((PSZ)path, &args->Path, PdxHeap)) { + return -1; + } + + Args = RtlAllocateHeap(PdxPortHeap, 0, ARG_MAX); + if (NULL == Args) { + errno = ENOMEM; + return -1; + } + + args->Args = Args + PsxPortMemoryRemoteDelta; + + // + // Port Memory Setup is same as for execve, see below. + // + + // + // first we count the strings so we know how much space to leave + // for pointers. + // + + save_arglist = arglist; + + for (i = 0, pcharg = va_arg(arglist, char *); NULL != pcharg; + pcharg = va_arg(arglist, char *)) { + ++i; + } + ++i; // add one for arg0 + for (ppch = (char **)envp; NULL != *ppch; ++ppch) + ++i; + i += 2; // add space for the NULL pointers + + pch = Args + sizeof(char *) * i; + + if (pch > Args + ARG_MAX) { + RtlFreeHeap(PdxPortHeap, 0, (PVOID)Args); + errno = E2BIG; + return -1; + } + + ppch = (char **)Args; + + arglist = save_arglist; // restart arglist + + try { + pcharg = (char *)arg0; + while (NULL != pcharg) { + if (pch + strlen(pcharg) + 1 > Args + ARG_MAX) { + RtlFreeHeap(PdxPortHeap, 0, (PVOID)Args); + errno = E2BIG; + return -1; + } + *ppch = pch - (ULONG)Args; + ppch++; + (void)strcpy(pch, pcharg); + pcharg = va_arg(arglist, char *); + + pch += strlen(pch); + *pch++ = '\0'; + } + *ppch = NULL; + ppch++; + + while (NULL != *envp) { + if (pch + strlen(*envp) + 1 > Args + ARG_MAX) { + RtlFreeHeap(PdxPortHeap, 0, (PVOID)Args); + errno = E2BIG; + return -1; + } + *ppch = pch - (ULONG)Args; + ppch++; + (void)strcpy(pch, *envp); + envp++; + + pch += strlen(pch); + *pch++ = '\0'; + } + *ppch = NULL; + + } except (EXCEPTION_EXECUTE_HANDLER) { + errno = EFAULT; + retval = -1; + } + if (0 != retval) { + RtlFreeHeap(PdxPortHeap, 0, (PVOID)Args); + return -1; + } + + (void)NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); + // + // If we get here, there's been an error. + // + + errno = (int)m.Error; + RtlFreeHeap(PdxHeap, 0, (PVOID)&args->Path); + RtlFreeHeap(PdxPortHeap, 0, (PVOID)Args); + + return -1; +} + +int +_CRTAPI1 +execve(const char *path, char * const argv[], char * const envp[]) +{ + NTSTATUS st; + PSX_API_MSG m; + PPSX_EXEC_MSG args; + PCHAR Args; // allocate args + environ + + char **ppch; + char *pch; + int i; + int retval = 0; + + try { + if (0 == strlen(path)) { + errno = ENOENT; + return -1; + } + } except (EXCEPTION_EXECUTE_HANDLER) { + retval = -1; + errno = EFAULT; + } + if (0 != retval) { + return -1; + } + + args = &m.u.Exec; + PSX_FORMAT_API_MSG(m, PsxExecApi, sizeof(*args)); + + if (!PdxCanonicalize((PSZ)path, &args->Path, PdxHeap)) { + return -1; + } + + // + // Copy the caller's environment into view memory so that it may + // be transmitted to the "overlaid" process. We set up the port + // memory to look like: + // + // ClientPortMemory: + // argv[0] + // argv[1] + // ... + // NULL + // envp[0] + // envp[1] + // ... + // NULL + // + // + // + // The argv and envp pointers are converted to offsets relative to + // ClientPortMemory. + // + // Because we need all this memory for args and environ, we destroy + // the heap and recreate it if the call fails. + // + + Args = RtlAllocateHeap(PdxPortHeap, 0, ARG_MAX); + if (NULL == Args) { + errno = ENOMEM; + return -1; + } + + args->Args = Args + PsxPortMemoryRemoteDelta; + + try { + + // first we count the strings so we know how much space to leave + // for pointers. + + for (i = 0, ppch = (char **)argv; NULL != *ppch; ++ppch) + ++i; + for (ppch = (char **)envp; NULL != *ppch; ++ppch) + ++i; + i += 2; // add space for the NULL pointers + + pch = Args + sizeof(char *) * i; + + if (pch > Args + ARG_MAX) { + RtlFreeHeap(PdxPortHeap, 0, (PVOID)Args); + errno = E2BIG; + return -1; + } + + ppch = (char **)Args; + + while (NULL != *argv) { + if (pch + strlen(*argv) + 1 > Args + ARG_MAX) { + RtlFreeHeap(PdxPortHeap, 0, (PVOID)Args); + errno = E2BIG; + return -1; + } + *ppch = pch - (ULONG)Args; + ppch++; + (void)strcpy(pch, *argv); + argv++; + + pch += strlen(pch); + *pch++ = '\0'; + } + *ppch = NULL; + ppch++; + + while (NULL != *envp) { + if (pch + strlen(*envp) + 1 > Args + ARG_MAX) { + RtlFreeHeap(PdxPortHeap, 0, (PVOID)Args); + errno = E2BIG; + return -1; + } + *ppch = pch - (ULONG)Args; + ppch++; + (void)strcpy(pch, *envp); + envp++; + + pch += strlen(pch); + *pch++ = '\0'; + } + *ppch = NULL; + + } except (EXCEPTION_EXECUTE_HANDLER) { + retval = -1; + errno = EFAULT; + } + if (0 != retval) { + return -1; + } + + (void)NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); + // + // If we get here, there's been an error. + // + + errno = (int)m.Error; + RtlFreeHeap(PdxHeap, 0, (PVOID)&args->Path); + RtlFreeHeap(PdxPortHeap, 0, (PVOID)Args); + + return -1; +} + +int +_CRTAPI1 +execv(const char *path, char * const argv[]) +{ + return execve(path, argv, environ); +} + +int +_CRTAPI2 +execl(const char *path, const char *arg0, ...) +{ + va_list args; + int retval; + + va_start(args, arg0); + + retval = vexec(path, arg0, environ, args); + + va_end(args); + + return retval; +} + +int +_CRTAPI2 +execle(const char *path, const char *arg0, ...) +{ + va_list args; + char * const *Env; + int retval; + + va_start(args, arg0); + + // Skip up to the NULL, then one more, to find environ. + + do { + Env = va_arg(args, char * const *); + } while (NULL != Env); + + Env = va_arg(args, char * const *); + + va_end(args); + + if (NULL == Env) { + return EINVAL; + } + + // Restart the arglist traversal + + va_start(args, arg0); + + retval = vexec(path, arg0, Env, args); + + va_end(args); + + return retval; +} + +int +_CRTAPI2 +execlp(const char *file, const char *arg0, ...) +{ + char *pch; + char *path; + static char buf[PATH_MAX + 1]; + va_list args; + int retval = 0; + BOOLEAN done = FALSE; + + va_start(args, arg0); + + // + // 1003.1-1990 (3.1.2.2): If the file argument contains a slash + // character, the file argument shall be used as the pathname for + // this file.... + // + + try { + if ('\0' == *file) { + errno = ENOENT; + va_end(args); + return -1; + } + if (NULL != (pch = strchr(file, '/'))) { + if (-1 == access(file, F_OK)) { + va_end(args); + return -1; + } + retval = vexec(file, arg0, environ, args); + va_end(args); + return retval; + } + } except (EXCEPTION_EXECUTE_HANDLER) { + errno = EFAULT; + retval = -1; + } + if (0 != retval) { + va_end(args); + return -1; + } + + // + // ... Otherwise, the path prefix for this file is obtained by a + // search of the directories passed as the environment variable + // PATH. + // + + if (NULL == (path = getenv("PATH"))) { + // + // The file name doesn't contain a slash, and we have + // no PATH. We just try for it in the current working + // directory, and will return ENOENT if it's not there. + // + retval = vexec(file, arg0, environ, args); + va_end(args); + return retval; + } + + errno = 0; + do { + pch = strchr(path, ':'); + if (NULL == pch) { + done = TRUE; + } else { + *pch = '\0'; + } + if (strlen(path) + strlen(file) + 1 > PATH_MAX) { + *pch = ':'; + errno = ENAMETOOLONG; + va_end(args); + return -1; + } + strcpy(buf, path); + if (!done) { + *pch = ':'; + path = pch + 1; + } + if (strlen(buf) > 0) { + // this case is "::" in the PATH + strcat(buf, "/"); + } + strcat(buf, file); + + // avoid trying to execute files that do not exist. + + if (-1 != access(buf, F_OK)) { + (void)vexec(buf, arg0, environ, args); + break; + } + } while (!done); + + va_end(args); + + if (0 == errno) { + // + // We went all the way through the PATH without finding + // a file to exec. Since errno didn't get set by execve(), + // we set it here. + // + + errno = ENOENT; + } + + return -1; +} + +int +_CRTAPI1 +execvp(const char *file, char * const argv[]) +{ + char *pch; + char *path; + static char buf[PATH_MAX + 1]; + BOOLEAN done = FALSE; + int retval = 0; + + // + // 1003.1-1990 (3.1.2.2): If the file argument contains a slash + // character, the file argument shall be used as the pathname for + // this file.... + // + + try { + if ('\0' == *file) { + errno = ENOENT; + return -1; + } + if (NULL != (pch = strchr(file, '/'))) { + if (-1 == access(file, F_OK)) { + return -1; + } + return execve(file, argv, environ); + } + } except (EXCEPTION_EXECUTE_HANDLER) { + errno = EFAULT; + retval = -1; + } + if (0 != retval) { + return -1; + } + + // + // ... Otherwise, the path prefix for this file is obtained by a + // search of the directories passed as the environment variable + // PATH. + // + + if (NULL == (path = getenv("PATH"))) { + return execve(file, argv, environ); + } + + errno = 0; + + do { + pch = strchr(path, ':'); + if (NULL == pch) { + done = TRUE; + } else { + *pch = '\0'; + } + if (strlen(path) + strlen(file) + 1 > PATH_MAX) { + *pch = ':'; + errno = ENAMETOOLONG; + return -1; + } + strcpy(buf, path); + if (!done) { + *pch = ':'; + path = pch + 1; + } + if (strlen(buf) > 0) { + // this case is "::" in the PATH + strcat(buf, "/"); + } + strcat(buf, file); + + // avoid trying to execute files that do not exist + + if (-1 != access(buf, F_OK)) { + (void)execve(buf, argv, environ); + break; + } + } while (!done); + + if (0 == errno) { + + // + // We went all the way through the PATH without finding + // a file to exec. Since errno didn't get set by execve(), + // we set it here. + // + + errno = ENOENT; + } + + return -1; +} + +#define COMPUTERNAME_ROOT \ + L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\ComputerName" +#define NON_VOLATILE_COMPUTERNAME L"ComputerName" +#define COMPUTERNAME_VALUE_NAME L"ComputerName" +#define VALUE_BUFFER_SIZE \ + (sizeof(KEY_VALUE_PARTIAL_INFORMATION) \ + + (_POSIX_NAME_MAX * sizeof(WCHAR))) + +int _CRTAPI1 +uname(struct utsname *name) +{ + NTSTATUS Status; + SYSTEM_PROCESSOR_INFORMATION + ProcInfo; + UNICODE_STRING + KeyName, + Class, + ValueName, + Computer_U; + ANSI_STRING + Computer_A; + OBJECT_ATTRIBUTES + ObjectAttributes; + HANDLE hKey = NULL, + hSubKey = NULL; + WCHAR ValueBuf[VALUE_BUFFER_SIZE]; + PKEY_VALUE_PARTIAL_INFORMATION + pKeyValueInfo = (PVOID)ValueBuf; + ULONG ValueLength; + char *pchProcType, // processor type + *pchNode = ""; // node name + int retval = 0; + + Status = NtQuerySystemInformation(SystemProcessorInformation, + (PVOID)&ProcInfo, sizeof(ProcInfo), NULL); + if (!NT_SUCCESS(Status)) { + errno = PdxStatusToErrno(Status); + return -1; + } + + switch (ProcInfo.ProcessorArchitecture) { + case PROCESSOR_ARCHITECTURE_INTEL: + if (ProcInfo.ProcessorLevel == 3) { + pchProcType = "i386"; + } else if (ProcInfo.ProcessorLevel == 4) { + pchProcType = "i486"; + } else if (ProcInfo.ProcessorLevel == 5) { + pchProcType = "Pentium"; + } else { + pchProcType = "Intel Unknown"; + } + break; + + case PROCESSOR_ARCHITECTURE_MIPS: + pchProcType = "R4000"; + break; + + case PROCESSOR_ARCHITECTURE_ALPHA: + if (ProcInfo.ProcessorLevel == 21064) { + pchProcType = "Alpha 21064"; + } else if (ProcInfo.ProcessorLevel == 21164) { + pchProcType = "Alpha 21164"; + } else { + pchProcType = "Alpha Unknown"; + } + break; + + case PROCESSOR_ARCHITECTURE_PPC: + if (ProcInfo.ProcessorLevel == 1) { + pchProcType = "PowerPC 601"; + } else if (ProcInfo.ProcessorLevel == 3) { + pchProcType = "PowerPC 603"; + } else if (ProcInfo.ProcessorLevel == 4) { + pchProcType = "PowerPC 604"; + } else if (ProcInfo.ProcessorLevel == 6) { + pchProcType = "PowerPC 603+"; + } else if (ProcInfo.ProcessorLevel == 9) { + pchProcType = "PowerPC 604+"; + } else if (ProcInfo.ProcessorLevel == 20) { + pchProcType = "PowerPC 620"; + } else { + pchProcType = "PowerPC Unknown"; + } + break; + + default: + pchProcType = "unknown"; + break; + } + + // + // Find the node name: this code lifted from + // windows/base/client/compname.c + // + + RtlInitUnicodeString(&KeyName, COMPUTERNAME_ROOT); + InitializeObjectAttributes(&ObjectAttributes, &KeyName, + OBJ_CASE_INSENSITIVE, NULL, NULL); + + Status = NtOpenKey(&hKey, KEY_READ, &ObjectAttributes); + if (!NT_SUCCESS(Status)) { + KdPrint(("PSXDLL: NtOpenKey: 0x%x\n", Status)); + goto done; + } + + RtlInitUnicodeString(&KeyName, NON_VOLATILE_COMPUTERNAME); + InitializeObjectAttributes(&ObjectAttributes, &KeyName, + OBJ_CASE_INSENSITIVE, hKey, NULL); + + Status = NtOpenKey(&hSubKey, KEY_READ, &ObjectAttributes); + if (!NT_SUCCESS(Status)) { + KdPrint(("PSXDLL: NtOpenKey: 0x%x\n", Status)); + goto done; + } + + RtlInitUnicodeString(&ValueName, COMPUTERNAME_VALUE_NAME); + + Status = NtQueryValueKey(hSubKey, &ValueName, + KeyValuePartialInformation, + (PVOID)pKeyValueInfo, VALUE_BUFFER_SIZE, &ValueLength); + ASSERT(ValueLength < VALUE_BUFFER_SIZE); + + if (!NT_SUCCESS(Status)) { + KdPrint(("PSXDLL: NtQueryValueKey: 0x%x\n", Status)); + goto done; + } + if (pKeyValueInfo->DataLength == 0) { + goto done; + } + + Computer_U.Buffer = (PVOID)&pKeyValueInfo->Data; + Computer_U.Length = Computer_U.MaximumLength = + (USHORT)pKeyValueInfo->DataLength; + + Status = RtlUnicodeStringToAnsiString(&Computer_A, &Computer_U, TRUE); + if (!NT_SUCCESS(Status)) { + goto done; + } + pchNode = Computer_A.Buffer; + +done: + if (NULL != hSubKey) { + NtClose(hSubKey); + } + if (NULL != hKey) { + NtClose(hKey); + } + + try { + strncpy((PCHAR)name->sysname, (PCHAR)UNAME_SYSNAME, sizeof(name->sysname)); + strncpy((PCHAR)name->release, (PCHAR)UNAME_RELEASE, sizeof(name->release)); + strncpy((PCHAR)name->version, (PCHAR)UNAME_VERSION, sizeof(name->version)); + strncpy((PCHAR)name->nodename, (PCHAR)pchNode, sizeof(name->nodename)); + strncpy((PCHAR)name->machine, (PCHAR)pchProcType, sizeof(name->machine)); + } except (EXCEPTION_EXECUTE_HANDLER) { + errno = EFAULT; + retval = -1; + } + RtlFreeAnsiString(&Computer_A); + return retval; +} + +char * _CRTAPI1 +getenv(const char *name) +{ + char **ppch; + char *pch; + + try { + for (ppch = environ; NULL != *ppch; ++ppch) { + if (NULL == (pch = strchr(*ppch, '='))) { + continue; + } + *pch = '\0'; // delete the equals + if (0 == strcmp(*ppch, name)) { + *pch = '='; + return pch + 1; + } + *pch = '='; + } + return NULL; + } except (EXCEPTION_EXECUTE_HANDLER) { + errno = EFAULT; + } + return NULL; +} + +time_t _CRTAPI1 +time(time_t *tloc) +{ + LARGE_INTEGER TimeOfDay; + ULONG PosixTime; + + NtQuerySystemTime(&TimeOfDay); + if (RtlTimeToSecondsSince1970(&TimeOfDay, &PosixTime)) { + if (ARGUMENT_PRESENT(tloc)) { + try { + *tloc = PosixTime; + } except (EXCEPTION_EXECUTE_HANDLER) { + errno = EFAULT; + } + } + } else { + PosixTime = (ULONG)-1; // Time not within range of 1970 - 2105 + } + return (time_t)PosixTime; +} + + +clock_t +_CRTAPI1 +times(struct tms *buffer) +{ + PSX_API_MSG m; + PPSX_GETPROCESSTIMES_MSG args; + LARGE_INTEGER TimeOfDay; + ULONG Remainder; + NTSTATUS st; + int retval = 0; + + args = &m.u.GetProcessTimes; + + PSX_FORMAT_API_MSG(m, PsxGetProcessTimesApi, sizeof(*args)); + + st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(st)); +#endif + if (m.Error) { + errno = (int)m.Error; + return -1; + } + + try { + *buffer = args->ProcessTimes; + } except (EXCEPTION_EXECUTE_HANDLER) { + errno = EFAULT; + retval = -1; + } + if (0 != retval) { + return -1; + } + + NtQuerySystemTime(&TimeOfDay); + + TimeOfDay = RtlExtendedLargeIntegerDivide(TimeOfDay, 10000L, + &Remainder); + + return TimeOfDay.LowPart; +} + +long +_CRTAPI1 +sysconf(int name) +{ + PSX_API_MSG m; + PPSX_SYSCONF_MSG args; + NTSTATUS st; + + args = &m.u.Sysconf; + + args->Name = name; + + PSX_FORMAT_API_MSG(m, PsxSysconfApi, sizeof(*args)); + + st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(st)); +#endif + + if (0 != m.Error) { + errno = m.Error; + return -1; + } + return m.ReturnValue; +} + +int +_CRTAPI1 +getgroups(int gidsetsize, gid_t *grouplist) +{ + PSX_API_MSG m; + PPSX_GETGROUPS_MSG args; + NTSTATUS st; + + args = &m.u.GetGroups; + args->GroupList = grouplist; + args->NGroups = gidsetsize; + + // + // The Posix server will write group id's into the group + // array with NtWriteVirtualMemory, unless gidsetsize is + // 0. In that case, he returns the size required and does + // not try to write the list. + // + + PSX_FORMAT_API_MSG(m, PsxGetGroupsApi, sizeof(*args)); + + st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(st)); +#endif + if (0 != m.Error) { + errno = m.Error; + return -1; + } + return m.ReturnValue; +} diff --git a/private/posix/client/dllreg.c b/private/posix/client/dllreg.c new file mode 100644 index 000000000..3fd5376d8 --- /dev/null +++ b/private/posix/client/dllreg.c @@ -0,0 +1,173 @@ +/*++ + +Copyright (c) 1995 Microsoft Corporation + +Module Name: + + dllreg.c + +Abstract: + + This module implements POSIX registry APIs + +Author: + + Matthew Bradburn (mattbr) 13-Dec-1995 + +Revision History: + +--*/ + +#include +#include +#include +#include +#include "psxdll.h" + + +// +// First guess for value size. +// + +#define KEY_WORK_AREA 256 + +int +_CRTAPI1 +getreg(char *path, int *type, void *data, size_t *size) +{ + NTSTATUS Status; + UNICODE_STRING Key_U, Value_U; + ANSI_STRING Key_A, Value_A; + OBJECT_ATTRIBUTES ObjA; + HANDLE hKey = NULL; + CHAR *pch; + PKEY_VALUE_PARTIAL_INFORMATION pInfo = NULL; + UCHAR Buffer[KEY_WORK_AREA]; + ULONG RequestLength, ResultLength; + int r = 0; + + Key_U.Buffer = NULL; + Value_U.Buffer = NULL; + + if (strlen(path) > PATH_MAX) { + errno = ENAMETOOLONG; + return -1; + } + + // + // Split the path into key and value. + // + + pch = strrchr(path, '\\'); + if (NULL == pch) { + errno = ENOENT; + return -1; + } + + Value_A.Buffer = pch + 1; + Value_A.Length = strlen(Value_A.Buffer); + Value_A.MaximumLength = Value_A.Length + 1; + + Key_A.Buffer = path; + Key_A.Length = pch - path; + Key_A.MaximumLength = Key_A.Length + 1; + + Status = RtlAnsiStringToUnicodeString(&Key_U, &Key_A, TRUE); + if (!NT_SUCCESS(Status)) { + errno = PdxStatusToErrno(Status); + r = -1; + goto out; + } + + Status = RtlAnsiStringToUnicodeString(&Value_U, &Value_A, TRUE); + if (!NT_SUCCESS(Status)) { + errno = PdxStatusToErrno(Status); + r = -1; + goto out; + } + + InitializeObjectAttributes(&ObjA, &Key_U, OBJ_CASE_INSENSITIVE, NULL, NULL); + + Status = NtOpenKey(&hKey, KEY_READ, &ObjA); + if (!NT_SUCCESS(Status)) { + KdPrint(("PSXDLL: NtOpenKey: 0x%x\n", Status)); + errno = PdxStatusToErrno(Status); + r = -1; + goto out; + } + + RequestLength = KEY_WORK_AREA; + pInfo = (PKEY_VALUE_PARTIAL_INFORMATION)Buffer; + + for (;;) { + + Status = NtQueryValueKey(hKey, &Value_U, KeyValuePartialInformation, + (PVOID)pInfo, RequestLength, &ResultLength); + + if (Status == STATUS_BUFFER_OVERFLOW) { + + // + // Try to get a bigger buffer. + // + + if (pInfo != (PKEY_VALUE_PARTIAL_INFORMATION)Buffer) { + + RtlFreeHeap(PdxHeap, 0, pInfo); + } + + RequestLength += 512; + pInfo = (PKEY_VALUE_PARTIAL_INFORMATION) + RtlAllocateHeap(PdxHeap, 0, RequestLength); + + if (NULL == pInfo) { + errno = ENOMEM; + r = -1; + goto out; + } + } else { + break; + } + } + + if (!NT_SUCCESS(Status)) { + + r = -1; + errno = PdxStatusToErrno(Status); + + } else { + + if (pInfo->DataLength > *size) { + *size = pInfo->DataLength; + *type = 0; + errno = E2BIG; + r = -1; + + } else { + + *size = pInfo->DataLength; + *type = pInfo->Type; + memcpy(data, pInfo->Data, pInfo->DataLength); + } + } + +out: + + if (pInfo != NULL && pInfo != (PKEY_VALUE_PARTIAL_INFORMATION)Buffer) { + RtlFreeHeap(PdxHeap, 0, pInfo); + } + + if (Key_U.Buffer != NULL) { + RtlFreeUnicodeString(&Key_U); + } + if (Value_U.Buffer != NULL) { + RtlFreeUnicodeString(&Value_U); + } + if (hKey != NULL) { + NtClose(hKey); + } + if (pInfo != NULL) { + RtlFreeHeap(PdxHeap, 0, (PVOID)pInfo); + } + + return r; +} diff --git a/private/posix/client/dllsig.c b/private/posix/client/dllsig.c new file mode 100644 index 000000000..7ab106bfb --- /dev/null +++ b/private/posix/client/dllsig.c @@ -0,0 +1,438 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + dllsig.c + +Abstract: + + Posix Signal Handling RTL + +Author: + + Mark Lucovsky (markl) 10-Mar-1989 + +Revision History: + +--*/ + +#include "psxdll.h" +#include + +#define _SIGNULLSET 0x0 +#define _SIGFULLSET 0x7ffff // ((1< SIGTTOU) { + errno = EINVAL; + return -1; + } + + SignoAsMask = (ULONG)(1l << (ULONG)(signo-1) ); + + try { + *set |= SignoAsMask; + } except (EXCEPTION_EXECUTE_HANDLER) { + errno = EFAULT; + r = -1; + } + return r; +} + +int _CRTAPI1 +sigdelset(sigset_t *set, int signo) +{ + sigset_t SignoAsMask; + int r = 0; + + if (signo < 1 || signo > SIGTTOU) { + errno = EINVAL; + return -1; + } + + SignoAsMask = (ULONG)(1l << (ULONG)(signo-1) ); + + try { + *set &= ~SignoAsMask; + } except (EXCEPTION_EXECUTE_HANDLER) { + errno = EFAULT; + r = -1; + } + return r; +} + +int _CRTAPI1 +sigismember(const sigset_t *set, int signo) +{ + sigset_t SignoAsMask; + int r = 0; + + if (signo < 1 || signo > SIGTTOU) { + errno = EINVAL; + return -1; + } + + SignoAsMask = (ULONG)(1L << (ULONG)(signo-1)); + + try { + if (*set & SignoAsMask) { + return 1; + } + } except (EXCEPTION_EXECUTE_HANDLER) { + errno = EFAULT; + r = -1; + } + return r; +} + + +// +// System Services +// + +int +_CRTAPI1 +sigaction(int sig, const struct sigaction *act, struct sigaction *oact) +{ + PSX_API_MSG m; + NTSTATUS st; + int r = 0; + + PPSX_SIGACTION_MSG args; + + args = &m.u.SigAction; + + PSX_FORMAT_API_MSG(m, PsxSigActionApi, sizeof(*args)); + + args->Sig = (ULONG)sig; + args->ActSpecified = (struct sigaction *)act; + + if (ARGUMENT_PRESENT(act)) { + try { + args->Act = *act; + } except (EXCEPTION_EXECUTE_HANDLER) { + KdPrint(("PSXDLL: err in sigaction\n")); + errno = EFAULT; + r = -1; + } + if (r != 0) { + return r; + } + } + + args->OactSpecified = oact; + + st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); + + if (!NT_SUCCESS(st)) { +#ifdef PSX_MORE_ERRORS + KdPrint(("PSXDLL: sigaction: NtRequestWaitReplyPort: 0x%x\n", st)); +#endif + _exit(25); + } + + if (m.Error) { + errno = (int)m.Error; + return -1; + } else { + if (ARGUMENT_PRESENT(oact)) { + try { + *oact = args->Oact; + } except (EXCEPTION_EXECUTE_HANDLER) { + errno = EFAULT; + r = -1; + } + if (r != 0) { + return r; + } + } + return (int)m.ReturnValue; + } +} + +int +_CRTAPI1 +sigprocmask(int how, const sigset_t *set, sigset_t *oset) +{ + PSX_API_MSG m; + NTSTATUS st; + int r = 0; + + PPSX_SIGPROCMASK_MSG args; + + args = &m.u.SigProcMask; + + PSX_FORMAT_API_MSG(m, PsxSigProcMaskApi, sizeof(*args)); + + args->How = (ULONG)how; + args->SetSpecified = (sigset_t *)set; + if (ARGUMENT_PRESENT(set)) { + try { + args->Set = *set; + } except (EXCEPTION_EXECUTE_HANDLER) { + r = -1; + errno = EFAULT; + } + if (0 != r) { + return r; + } + } + + st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); + +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(st)); +#endif + + if (m.Error) { + errno = (int)m.Error; + return -1; + } else { + if (ARGUMENT_PRESENT(oset)) { + try { + *oset = args->Oset; + } except (EXCEPTION_EXECUTE_HANDLER) { + errno = EFAULT; + r = -1; + } + if (0 != r) { + return r; + } + } + return (int)m.ReturnValue; + } +} + +int +_CRTAPI1 +sigsuspend(const sigset_t *sigmask) +{ + PSX_API_MSG m; + NTSTATUS st; + + PPSX_SIGSUSPEND_MSG args; + + args = &m.u.SigSuspend; + PSX_FORMAT_API_MSG(m, PsxSigSuspendApi, sizeof(*args)); + + args->SigMaskSpecified = (PVOID)1; + + st = STATUS_SUCCESS; + + try { + args->SigMask = *sigmask; + } except (EXCEPTION_EXECUTE_HANDLER) { + st = STATUS_UNSUCCESSFUL; + } + if (!NT_SUCCESS(st)) { + errno = EFAULT; + return -1; + } + + for (;;) { + st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); + if (!NT_SUCCESS(st)) { + _exit(26); + } + + if (EINTR == m.Error && SIGCONT == m.Signal) { + // + // We were stopped and continued. Continue + // suspending. + // + PSX_FORMAT_API_MSG(m, PsxSigSuspendApi, sizeof(*args)); + continue; + } + + if (m.Error) { + errno = (int)m.Error; + return -1; + } + return (int)m.ReturnValue; + } +} + +int +_CRTAPI1 +pause(void) +{ + PSX_API_MSG m; + NTSTATUS st; + + PPSX_SIGSUSPEND_MSG args; + + args = &m.u.SigSuspend; + + PSX_FORMAT_API_MSG(m, PsxSigSuspendApi, sizeof(*args)); + + args->SigMaskSpecified = NULL; + + for (;;) { + st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); + if (!NT_SUCCESS(st)) { +#ifdef PSX_MORE_ERRORS + KdPrint(("PSXDLL: pause: Request: 0x%x\n", st)); +#endif + _exit(27); + } + + if (EINTR == m.Error && SIGCONT == m.Signal) { + // + // The syscall was stopped and continues. Call + // again instead of returning EINTR. + // + + PSX_FORMAT_API_MSG(m, PsxSigSuspendApi, sizeof(*args)); + continue; + } + if (m.Error) { + errno = (int)m.Error; + return -1; + } + return (int)m.ReturnValue; + } +} + +VOID +PdxNullPosixApi() +{ + PSX_API_MSG m; + NTSTATUS st; + + PSX_FORMAT_API_MSG(m, PsxNullApi, 0); + + st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + if (!NT_SUCCESS(st)) { + KdPrint(("PSXDLL: PdxNullPosixApi: NtRequestWaitReplyPort: 0x%x\n", st)); + } +#endif +} + +int +_CRTAPI1 +kill(pid_t pid, int sig) +{ + PSX_API_MSG m; + NTSTATUS st; + + PPSX_KILL_MSG args; + + args = &m.u.Kill; + + PSX_FORMAT_API_MSG(m, PsxKillApi, sizeof(*args)); + + args->Pid = pid; + args->Sig = (ULONG)sig; + + st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); + if (!NT_SUCCESS(st)) { +#ifdef PSX_MORE_ERRORS + KdPrint(("PSXDLL: kill: NtRequestWaitReplyPort: 0x%x\n", st)); +#endif + _exit(28); + } + + if (m.Error) { + errno = (int)m.Error; + return -1; + } else { + return (int)m.ReturnValue; + } +} + +#ifndef SIG_ERR +#define SIG_ERR 0 +#endif + +_handler _CRTAPI1 +signal(int sig, _handler handler) +{ + struct sigaction act, oact; + + act.sa_handler = handler; + act.sa_flags = 0; + sigemptyset((sigset_t *)&act.sa_mask); + + if (-1 == sigaction(sig, (struct sigaction *)&act, + (struct sigaction *)&oact)) { + return SIG_ERR; + } + return oact.sa_handler; +} + +int +_CRTAPI1 +sigpending(sigset_t *set) +{ + PSX_API_MSG m; + PPSX_SIGPENDING_MSG args; + NTSTATUS st; + int r = 0; + + args = &m.u.SigPending; + + PSX_FORMAT_API_MSG(m, PsxSigPendingApi, sizeof(*args)); + + st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(st)); +#endif + + if (m.Error) { + errno = (int)m.Error; + return -1; + } + + try { + *set = args->Set; + } except (EXCEPTION_EXECUTE_HANDLER) { + errno = EFAULT; + r = -1; + } + return r; +} diff --git a/private/posix/client/dlltc.c b/private/posix/client/dlltc.c new file mode 100644 index 000000000..6276784f0 --- /dev/null +++ b/private/posix/client/dlltc.c @@ -0,0 +1,293 @@ + +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + dlltc.c + +Abstract: + + Client implementation of Terminal Control functions for POSIX + +Author: + + Ellen Aycock-Wright 05-Aug-1991 + +Revision History: + +--*/ + +#include +#include "psxdll.h" + +int +_CRTAPI1 +tcgetattr (int fildes, struct termios *termios_p) +{ + PSX_API_MSG m; + NTSTATUS st; + SCREQUESTMSG Request; + PPSX_TCGETATTR_MSG args; + + args = &m.u.TcGetAttr; + + PSX_FORMAT_API_MSG(m,PsxTcGetAttrApi,sizeof(*args)); + + args->FileDes = fildes; + args->Termios = termios_p; + + st = NtRequestWaitReplyPort( + PsxPortHandle, + (PPORT_MESSAGE) &m, + (PPORT_MESSAGE) &m + ); + + if ( m.Error ) { + errno = (int) m.Error; + return (int) -1; + } + + // + // fildes is a valid file descriptor; now call to posix.exe to get + // the real terminal settings. + // + + Request.Request = TcRequest; + Request.d.Con.Request = TcGetAttr; + + st = SendConsoleRequest(&Request); + + memcpy(termios_p, &Request.d.Tc.Termios, sizeof(*termios_p)); + + if (!NT_SUCCESS(st)) { + errno = PdxStatusToErrno(st); + return -1; + } + return 0; +} + +int +_CRTAPI1 +tcsetattr(int fildes, int optional_actions, const struct termios *termios_p) +{ + PSX_API_MSG m; + NTSTATUS st; + SCREQUESTMSG Request; + PPSX_TCSETATTR_MSG args; + + args = &m.u.TcSetAttr; + + PSX_FORMAT_API_MSG(m,PsxTcSetAttrApi,sizeof(*args)); + + args->FileDes = fildes; + args->OptionalActions = optional_actions; + args->Termios = (struct termios *)termios_p; + + st = NtRequestWaitReplyPort( + PsxPortHandle, + (PPORT_MESSAGE) &m, + (PPORT_MESSAGE) &m + ); + + if ( m.Error ) { + errno = (int) m.Error; + return (int) -1; + } + + // + // The file descriptor is valid; make the request to posix.exe to + // set the attributes. + // + + Request.Request = TcRequest; + Request.d.Con.Request = TcSetAttr; + + memcpy(&Request.d.Tc.Termios, termios_p, sizeof(*termios_p)); + + st = SendConsoleRequest(&Request); + if (!NT_SUCCESS(st)) { + errno = PdxStatusToErrno(st); + return -1; + } + return 0; +} + +int +_CRTAPI1 +tcsendbreak (int fildes, int duration) +{ + PSX_API_MSG m; + NTSTATUS st; + + PPSX_TCSENDBREAK_MSG args; + + args = &m.u.TcSendBreak; + + PSX_FORMAT_API_MSG(m,PsxTcSendBreakApi,sizeof(*args)); + + args->FileDes = fildes; + args->Duration = duration; + + st = NtRequestWaitReplyPort( + PsxPortHandle, + (PPORT_MESSAGE) &m, + (PPORT_MESSAGE) &m + ); + + if ( m.Error ) { + errno = (int) m.Error; + return (int) -1; + } else { + return (int) m.ReturnValue; + } +} + +int +_CRTAPI1 +tcdrain (int fildes) +{ + PSX_API_MSG m; + NTSTATUS st; + + PPSX_TCDRAIN_MSG args; + + args = &m.u.TcDrain; + + PSX_FORMAT_API_MSG(m,PsxTcDrainApi,sizeof(*args)); + + args->FileDes = fildes; + + st = NtRequestWaitReplyPort( + PsxPortHandle, + (PPORT_MESSAGE) &m, + (PPORT_MESSAGE) &m + ); + + if ( m.Error ) { + errno = (int) m.Error; + return (int) -1; + } else { + return (int) m.ReturnValue; + } +} + +int +_CRTAPI1 +tcflush (int fildes, int queue_selector) +{ + PSX_API_MSG m; + NTSTATUS st; + + PPSX_TCFLUSH_MSG args; + + args = &m.u.TcFlush; + + PSX_FORMAT_API_MSG(m,PsxTcFlushApi,sizeof(*args)); + + args->FileDes = fildes; + args->QueueSelector = queue_selector; + + st = NtRequestWaitReplyPort( + PsxPortHandle, + (PPORT_MESSAGE) &m, + (PPORT_MESSAGE) &m + ); + + if ( m.Error ) { + errno = (int) m.Error; + return (int) -1; + } else { + return (int) m.ReturnValue; + } +} + +int +_CRTAPI1 +tcflow (int fildes, int action) +{ + PSX_API_MSG m; + NTSTATUS st; + + PPSX_TCFLOW_MSG args; + + args = &m.u.TcFlow; + + PSX_FORMAT_API_MSG(m,PsxTcFlowApi,sizeof(*args)); + + args->FileDes = fildes; + args->Action = action; + + st = NtRequestWaitReplyPort( + PsxPortHandle, + (PPORT_MESSAGE) &m, + (PPORT_MESSAGE) &m + ); + + if ( m.Error ) { + errno = (int) m.Error; + return (int) -1; + } else { + return (int) m.ReturnValue; + } +} + +pid_t +_CRTAPI1 +tcgetpgrp (int fildes) +{ + PSX_API_MSG m; + NTSTATUS st; + + PPSX_TCGETPGRP_MSG args; + + args = &m.u.TcGetPGrp; + + PSX_FORMAT_API_MSG(m,PsxTcGetPGrpApi,sizeof(*args)); + + args->FileDes = fildes; + + st = NtRequestWaitReplyPort( + PsxPortHandle, + (PPORT_MESSAGE) &m, + (PPORT_MESSAGE) &m + ); + + if ( m.Error ) { + errno = (int) m.Error; + return (pid_t) -1; + } else { + return (pid_t) m.ReturnValue; + } +} + +int +_CRTAPI1 +tcsetpgrp(int fildes, pid_t pgrp_id) +{ + PSX_API_MSG m; + NTSTATUS st; + + PPSX_TCSETPGRP_MSG args; + + args = &m.u.TcSetPGrp; + + PSX_FORMAT_API_MSG(m,PsxTcSetPGrpApi,sizeof(*args)); + + args->FileDes = fildes; + args->PGrpId = pgrp_id; + + st = NtRequestWaitReplyPort( + PsxPortHandle, + (PPORT_MESSAGE) &m, + (PPORT_MESSAGE) &m + ); + + if ( m.Error ) { + errno = (int) m.Error; + return (pid_t) -1; + } else { + return (pid_t) m.ReturnValue; + } +} diff --git a/private/posix/client/dlltimer.c b/private/posix/client/dlltimer.c new file mode 100644 index 000000000..1df993454 --- /dev/null +++ b/private/posix/client/dlltimer.c @@ -0,0 +1,243 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + dlltimer.c + +Abstract: + + This module implements client side stubs for timer related APIs + +Author: + + Mark Lucovsky (markl) 08-Aug-1989 + +Revision History: + +--*/ + +#include "psxdll.h" +#include + + +ULONG MagicMultiplier = 10000000; + +VOID +SecondsToTime ( + OUT PLARGE_INTEGER Time, + IN ULONG Seconds + ) + +/*++ + +Routine Description: + + This function converts from seconds to an equivalent + relative time value in units of 100ns intervals. + +Arguments: + + Time - Returns the equivalant relative time value. + + Seconds - Supplies the time in seconds. + +Return Value: + + None. + +--*/ + + +{ + Time->QuadPart = (LONGLONG)Seconds * (LONGLONG)MagicMultiplier; + Time->QuadPart = -Time->QuadPart; +} + +ULONG +TimeToSeconds ( + IN PLARGE_INTEGER Time + ) + +/*++ + +Routine Description: + + This function converts from absolute time in units of 100ns + intervals to seconds. + +Arguments: + + Time - Supplies an absolute time in units of 100ns intervals. + +Return Value: + + The value of time in seconds. + +--*/ + +{ + LARGE_INTEGER Seconds; + +#if 0 + Seconds = RtlExtendedMagicDivide( + *Time, + MagicDivisor, + MagicShiftCount + ); + +#else + ULONG R; // remainder + + Seconds = RtlExtendedLargeIntegerDivide( + *Time, // Dividend + MagicMultiplier, // Divisor + &R + ); + +#endif + return Seconds.LowPart; + +} + +unsigned int _CRTAPI1 +alarm(unsigned int seconds) +{ + PSX_API_MSG m; + PPSX_ALARM_MSG args; + NTSTATUS st; + unsigned int PreviousSeconds; + + args = &m.u.Alarm; + PSX_FORMAT_API_MSG(m, PsxAlarmApi, sizeof(*args)); + + if (0 == seconds) { + args->CancelAlarm = TRUE; + } else { + SecondsToTime(&args->Seconds, seconds); + args->CancelAlarm = FALSE; + } + + args->PreviousSeconds.LowPart = 0; + args->PreviousSeconds.HighPart = 0; + + st = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); + +#ifdef PSX_MORE_ERRORS + ASSERT(NT_SUCCESS(st)); +#endif + + PreviousSeconds = TimeToSeconds(&args->PreviousSeconds); + + if (args->PreviousSeconds.LowPart != 0 && PreviousSeconds == 0) + PreviousSeconds = 1; + + return PreviousSeconds; +} + +static void +_CRTAPI1 +sigalrm(int signo) +{ + // + // XXX.mjb: do we need to do anything here? + // +} + +unsigned int +_CRTAPI1 +sleep(unsigned int seconds) +{ + unsigned int prev, t; + PVOID ohandler; + sigset_t set, oset; + + if (seconds == 0) { + getpid(); // encourage context switch + return 0; + } + + sigemptyset(&set); + sigaddset(&set, SIGALRM); + sigprocmask(SIG_UNBLOCK, &set, &oset); + + prev = alarm(0); + + if (0 != prev && prev < seconds) { + // + // There was already an alarm scheduled, and it would + // have gone off before the sleep should have been done. + // We sleep for the shorter amount of time, and return + // with no alarm scheduled. + // + + sigset_t s; + + // block SIGALRM until we're ready for it. + + sigemptyset(&s); + sigaddset(&s, SIGALRM); + sigprocmask(SIG_BLOCK, &s, NULL); + + (void)alarm(prev); // restore previous alarm + + s = oset; + sigdelset(&s, SIGALRM); + sigsuspend(&s); + + sigprocmask(SIG_SETMASK, &oset, NULL); + return seconds - prev; + } + + + ohandler = signal(SIGALRM, sigalrm); + + { + sigset_t s; + +#if 1 + // block SIGALARM until we're ready for it. + + sigemptyset(&s); + sigaddset(&s, SIGALRM); + sigprocmask(SIG_BLOCK, &s, NULL); +#endif + + (void)alarm(seconds); +#if 1 + s = oset; + sigdelset(&s, SIGALRM); + sigsuspend(&s); +#else + pause(); +#endif + } + + t = alarm(0); + signal(SIGALRM, ohandler); + + if (0 != prev) { + // + // There was a previous alarm scheduled, and we re-schedule + // it to make it look like we hadn't fiddled with it. + // + + if (prev - seconds == 0) { + // + // the previously-scheduled alarm would have gone + // off at the same time the sleep was supposed to + // return. We want to make sure two alarms are + // actually delivered, so we add a second to the + // previous alarm time. + // + prev++; + } + (void)alarm(prev - seconds); + } + + sigprocmask(SIG_SETMASK, &oset, NULL); + + return t; +} diff --git a/private/posix/client/i386/psxthunk.asm b/private/posix/client/i386/psxthunk.asm new file mode 100644 index 000000000..e31b24177 --- /dev/null +++ b/private/posix/client/i386/psxthunk.asm @@ -0,0 +1,60 @@ + title "PsxSignalThunk" +;++ +; +; Copyright (c) 1990 Microsoft Corporation +; +; Module Name: +; +; psxthunk.asm +; +; Abstract: +; +; This module implements functions to support Posix signal delivery. +; Routines in this module are called with non-standard parameter +; passing. +; +; Author: +; +; Ellen Aycock-Wright (ellena) 10-Oct-1990 +; +; +; Revision History: +; +;-- + +.386p + .xlist +include ks386.inc + .list + + extrn _PdxNullApiCaller@4:PROC + extrn _PdxSignalDeliverer@16:PROC + + +_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE' + ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING + + public __PdxNullApiCaller@4 +__PdxNullApiCaller@4 proc + + mov eax,0 + call _PdxNullApiCaller@4 + +; NOTREACHED + +__PdxNullApiCaller@4 endp + + + public __PdxSignalDeliverer@16 +__PdxSignalDeliverer@16 proc + + mov eax,0 + call _PdxSignalDeliverer@16 + +; NOTREACHED + + +__PdxSignalDeliverer@16 endp + +_TEXT ends + end diff --git a/private/posix/client/i386/sources b/private/posix/client/i386/sources new file mode 100644 index 000000000..901edcf40 --- /dev/null +++ b/private/posix/client/i386/sources @@ -0,0 +1 @@ +i386_SOURCES=psxthunk.asm diff --git a/private/posix/client/makefile b/private/posix/client/makefile new file mode 100644 index 000000000..afc6030de --- /dev/null +++ b/private/posix/client/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT. +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/posix/client/makefile.inc b/private/posix/client/makefile.inc new file mode 100644 index 000000000..e0ee8aa44 --- /dev/null +++ b/private/posix/client/makefile.inc @@ -0,0 +1,2 @@ +obj\$(TARGET_DIRECTORY)\psxdll.def: psxdll.src + $(TARGET_CPP) /EP $(CDEFINES) psxdll.src > obj\$(TARGET_DIRECTORY)\psxdll.def diff --git a/private/posix/client/mips/psxthunk.s b/private/posix/client/mips/psxthunk.s new file mode 100644 index 000000000..3dd27910e --- /dev/null +++ b/private/posix/client/mips/psxthunk.s @@ -0,0 +1,147 @@ +// TITLE("POSIX Thunks) +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + psxthunk.s + +Abstract: + + +Author: + + Ellena Aycock-Wright (ellena) 11-Jan-1991 + +Revision History: + +--*/ + +#include "ksmips.h" + + +//++ +// +// The following code is never executed. Its purpose is to support +// unwinding through the call to the signal deliverer. (Copied from +// ntos/rtl/mips/trampoln.s) +// +//-- + +#define FrameSize (ContextFrameLength) + + NESTED_ENTRY(PdxNullApiCall, FrameSize, zero); + + .set noreorder + .set noat + sd sp,CxXIntSp(sp) // save stack pointer + sd ra,CxXIntRa(sp) // save return address + sw ra,CxFir(sp) // save return address + sd s8,CxXIntS8(sp) // save integer register s8 + sd gp,CxXIntGp(sp) // save integer register gp + sd s0,CxXIntS0(sp) // save integer register s0-s7 + sd s1,CxXIntS1(sp) // + sd s2,CxXIntS2(sp) // + sd s3,CxXIntS3(sp) // + sd s4,CxXIntS4(sp) // + sd s5,CxXIntS5(sp) // + sd s6,CxXIntS6(sp) // + sd s7,CxXIntS7(sp) // + sdc1 f20,CxFltF20(sp) // store floating registers f20 - f31 + sdc1 f22,CxFltF22(sp) // + sdc1 f24,CxFltF24(sp) // + sdc1 f26,CxFltF26(sp) // + sdc1 f28,CxFltF28(sp) // + sdc1 f30,CxFltF30(sp) // +// move s8,sp // set frame pointer + .set at + .set reorder + + PROLOGUE_END + + ALTERNATE_ENTRY(_PdxNullApiCaller) + + move a0,sp // set address of context record + jal PdxNullApiCaller // call null api caller + + .end PdxNullApiCaller + + +//++ +// +// The following code is never executed. Its purpose is to support +// unwinding through the call to the signal deliverer. (Copied from +// ntos/rtl/mips/trampoln.s) +// +//-- + + NESTED_ENTRY(PdxSignalDeliver, FrameSize, zero); + + .set noreorder + .set noat + sd sp,CxXIntSp(sp) // save stack pointer + sd ra,CxXIntRa(sp) // save return address + sw ra,CxFir(sp) // save return address + sd s8,CxXIntS8(sp) // save integer register s8 + sd gp,CxXIntGp(sp) // save integer register gp + sd s0,CxXIntS0(sp) // save integer register s0-s7 + sd s1,CxXIntS1(sp) // + sd s2,CxXIntS2(sp) // + sd s3,CxXIntS3(sp) // + sd s4,CxXIntS4(sp) // + sd s5,CxXIntS5(sp) // + sd s6,CxXIntS6(sp) // + sd s7,CxXIntS7(sp) // + sdc1 f20,CxFltF20(sp) // store floating registers f20 - f31 + sdc1 f22,CxFltF22(sp) // + sdc1 f24,CxFltF24(sp) // + sdc1 f26,CxFltF26(sp) // + sdc1 f28,CxFltF28(sp) // + sdc1 f30,CxFltF30(sp) // +// move s8,sp // set frame pointer + .set at + .set reorder + + PROLOGUE_END + +//++ +// +// VOID +// _PdxSignalDeliverer ( +// IN PCONTEXT Context, +// IN sigset_t Mask, +// IN int Signal, +// IN _handler Handler +// ) +// +// Routine Description: +// +// The following routine provides linkage to POSIX client routines to perform +// signal delivery. +// +// Arguments: +// +// s0 - s7 - Supply parameter values. +// +// sp - Supplies the address of a context record. +// +// Return Value: +// +// There is no return from these routines. +// +//-- + + ALTERNATE_ENTRY(_PdxSignalDeliverer) + + move a0,sp // set address of context record + + move a1,s1 // set previous block mask + move a2,s2 // set signal number + move a3,s3 // set signal handler + + jal PdxSignalDeliverer // deliver signal to POSIX client + + //NOTREACHED + + .end _PdxSignalDeliverer diff --git a/private/posix/client/mips/sources b/private/posix/client/mips/sources new file mode 100644 index 000000000..3dd005ce9 --- /dev/null +++ b/private/posix/client/mips/sources @@ -0,0 +1 @@ +MIPS_SOURCES=psxthunk.asm diff --git a/private/posix/client/ppc/psxthunk.s b/private/posix/client/ppc/psxthunk.s new file mode 100644 index 000000000..bb92dbd64 --- /dev/null +++ b/private/posix/client/ppc/psxthunk.s @@ -0,0 +1,185 @@ + +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + psxthunk.s + +Abstract: + + +Author: + + Ellena Aycock-Wright (ellena) 11-Jan-1991 + +Revision History: + + Curt Fawcett 9-21-94 Modified for PPC + +--*/ + +#include "ksppc.h" + .extern ..PdxNullApiCaller + .extern ..PdxSignalDeliverer + + +//++ +// +// The following code is never executed. Its purpose is to support +// unwinding through the call to the signal deliverer. (Copied from +// ntos/rtl/ppc/trampoln.s) +// +//-- + + FN_TABLE(PdxNullApiCall,0,0) + + DUMMY_ENTRY(PdxNullApiCall) + + mflr r.0 + stw r.sp,-(ContextFrameLength+STK_MIN_FRAME)(r.sp) // Set frame pointer + stw r.sp,(STK_MIN_FRAME+CxGpr1)(r.sp) // Save stack pointer + stw r.0,(STK_MIN_FRAME+CxLr)(r.sp) // Save return address + stw r.13,(STK_MIN_FRAME+CxGpr13)(r.sp) // Save integer register s8 + stw r.14,(STK_MIN_FRAME+CxGpr14)(r.sp) // Save integer register gp + stw r.15,(STK_MIN_FRAME+CxGpr15)(r.sp) // Save integer registers s0 - s7 + stw r.16,(STK_MIN_FRAME+CxGpr16)(r.sp) // + stw r.17,(STK_MIN_FRAME+CxGpr17)(r.sp) // + stw r.18,(STK_MIN_FRAME+CxGpr18)(r.sp) // + stw r.19,(STK_MIN_FRAME+CxGpr19)(r.sp) // + stw r.20,(STK_MIN_FRAME+CxGpr20)(r.sp) // + stw r.21,(STK_MIN_FRAME+CxGpr21)(r.sp) // + stw r.22,(STK_MIN_FRAME+CxGpr22)(r.sp) // + stw r.23,(STK_MIN_FRAME+CxGpr23)(r.sp) // + stw r.24,(STK_MIN_FRAME+CxGpr24)(r.sp) // + stw r.25,(STK_MIN_FRAME+CxGpr25)(r.sp) // + stw r.26,(STK_MIN_FRAME+CxGpr26)(r.sp) // + stw r.27,(STK_MIN_FRAME+CxGpr27)(r.sp) // + stw r.28,(STK_MIN_FRAME+CxGpr28)(r.sp) // + stw r.29,(STK_MIN_FRAME+CxGpr29)(r.sp) // + stw r.30,(STK_MIN_FRAME+CxGpr30)(r.sp) // + stw r.31,(STK_MIN_FRAME+CxGpr31)(r.sp) // + stfd r.14,(STK_MIN_FRAME+CxFpr14)(r.sp) // Store floating regs f20 - f31 + stfd r.15,(STK_MIN_FRAME+CxFpr15)(r.sp) // + stfd r.16,(STK_MIN_FRAME+CxFpr16)(r.sp) // + stfd r.17,(STK_MIN_FRAME+CxFpr17)(r.sp) // + stfd r.18,(STK_MIN_FRAME+CxFpr18)(r.sp) // + stfd r.19,(STK_MIN_FRAME+CxFpr19)(r.sp) // + stfd r.20,(STK_MIN_FRAME+CxFpr20)(r.sp) // + stfd r.21,(STK_MIN_FRAME+CxFpr21)(r.sp) // + stfd r.22,(STK_MIN_FRAME+CxFpr22)(r.sp) // + stfd r.23,(STK_MIN_FRAME+CxFpr23)(r.sp) // + stfd r.24,(STK_MIN_FRAME+CxFpr24)(r.sp) // + stfd r.25,(STK_MIN_FRAME+CxFpr25)(r.sp) // + stfd r.26,(STK_MIN_FRAME+CxFpr26)(r.sp) // + stfd r.27,(STK_MIN_FRAME+CxFpr27)(r.sp) // + stfd r.28,(STK_MIN_FRAME+CxFpr28)(r.sp) // + stfd r.29,(STK_MIN_FRAME+CxFpr29)(r.sp) // + stfd r.30,(STK_MIN_FRAME+CxFpr30)(r.sp) // + stfd r.31,(STK_MIN_FRAME+CxFpr31)(r.sp) // + + PROLOGUE_END(PdxNullApiCall) + + ALTERNATE_ENTRY(_PdxNullApiCaller) + + mr r.3,r.14 + bl ..PdxNullApiCaller // call null api caller + + DUMMY_EXIT(PdxNullApiCall) + + +//++ +// +// The following code is never executed. Its purpose is to support +// unwinding through the call to the signal deliverer. (Copied from +// ntos/rtl/ppc/trampoln.s) +// +//-- + + + FN_TABLE(PdxSignalDeliver,0,0) + + DUMMY_ENTRY(PdxSignalDeliver) + + mflr r.0 + stw r.sp,-(ContextFrameLength+STK_MIN_FRAME)(r.sp) // Set frame pointer + stw r.sp,(STK_MIN_FRAME+CxGpr1)(r.sp) // Save stack pointer + stw r.0,(STK_MIN_FRAME+CxLr)(r.sp) // Save return address + stw r.13,(STK_MIN_FRAME+CxGpr13)(r.sp) // Save integer register s8 + stw r.14,(STK_MIN_FRAME+CxGpr14)(r.sp) // Save integer register gp + stw r.15,(STK_MIN_FRAME+CxGpr15)(r.sp) // Save integer registers s0 - s7 + stw r.16,(STK_MIN_FRAME+CxGpr16)(r.sp) // + stw r.17,(STK_MIN_FRAME+CxGpr17)(r.sp) // + stw r.18,(STK_MIN_FRAME+CxGpr18)(r.sp) // + stw r.19,(STK_MIN_FRAME+CxGpr19)(r.sp) // + stw r.20,(STK_MIN_FRAME+CxGpr20)(r.sp) // + stw r.21,(STK_MIN_FRAME+CxGpr21)(r.sp) // + stw r.22,(STK_MIN_FRAME+CxGpr22)(r.sp) // + stw r.23,(STK_MIN_FRAME+CxGpr23)(r.sp) // + stw r.24,(STK_MIN_FRAME+CxGpr24)(r.sp) // + stw r.25,(STK_MIN_FRAME+CxGpr25)(r.sp) // + stw r.26,(STK_MIN_FRAME+CxGpr26)(r.sp) // + stw r.27,(STK_MIN_FRAME+CxGpr27)(r.sp) // + stw r.28,(STK_MIN_FRAME+CxGpr28)(r.sp) // + stw r.29,(STK_MIN_FRAME+CxGpr29)(r.sp) // + stw r.30,(STK_MIN_FRAME+CxGpr30)(r.sp) // + stw r.31,(STK_MIN_FRAME+CxGpr31)(r.sp) // + stfd r.14,(STK_MIN_FRAME+CxFpr14)(r.sp) // Store floating regs f20 - f31 + stfd r.15,(STK_MIN_FRAME+CxFpr15)(r.sp) // + stfd r.16,(STK_MIN_FRAME+CxFpr16)(r.sp) // + stfd r.17,(STK_MIN_FRAME+CxFpr17)(r.sp) // + stfd r.18,(STK_MIN_FRAME+CxFpr18)(r.sp) // + stfd r.19,(STK_MIN_FRAME+CxFpr19)(r.sp) // + stfd r.20,(STK_MIN_FRAME+CxFpr20)(r.sp) // + stfd r.21,(STK_MIN_FRAME+CxFpr21)(r.sp) // + stfd r.22,(STK_MIN_FRAME+CxFpr22)(r.sp) // + stfd r.23,(STK_MIN_FRAME+CxFpr23)(r.sp) // + stfd r.24,(STK_MIN_FRAME+CxFpr24)(r.sp) // + stfd r.25,(STK_MIN_FRAME+CxFpr25)(r.sp) // + stfd r.26,(STK_MIN_FRAME+CxFpr26)(r.sp) // + stfd r.27,(STK_MIN_FRAME+CxFpr27)(r.sp) // + stfd r.28,(STK_MIN_FRAME+CxFpr28)(r.sp) // + stfd r.29,(STK_MIN_FRAME+CxFpr29)(r.sp) // + stfd r.30,(STK_MIN_FRAME+CxFpr30)(r.sp) // + stfd r.31,(STK_MIN_FRAME+CxFpr31)(r.sp) // + + PROLOGUE_END (PdxSignalDeliver) + +//++ +// +// VOID +// _PdxSignalDeliverer ( +// IN PCONTEXT Context, +// IN sigset_t Mask, +// IN int Signal, +// IN _handler Handler +// ) +// +// Routine Description: +// +// The following routine provides linkage to POSIX client routines to perform +// signal delivery. +// +// Arguments: +// +// r.3 - r.7 - Supply parameter values. +// +// sp - Supplies stack frome pointer. Already set up. +// +// Return Value: +// +// There is no return from these routines. +// +//-- + + ALTERNATE_ENTRY(_PdxSignalDeliverer) + + mr r.3, r.14 // Set address of context record + mr r.4, r.15 // Set previous block mask + mr r.5, r.16 // Set signal number + mr r.6, r.17 // Set signal handler + bl ..PdxSignalDeliverer // deliver signal to POSIX client + + DUMMY_EXIT(PdxSignalDeliver) + diff --git a/private/posix/client/ppc/sources b/private/posix/client/ppc/sources new file mode 100644 index 000000000..fae268538 --- /dev/null +++ b/private/posix/client/ppc/sources @@ -0,0 +1 @@ +PPC_SOURCES=psxthunk.s diff --git a/private/posix/client/psxdll.h b/private/posix/client/psxdll.h new file mode 100644 index 000000000..59b45d5e3 --- /dev/null +++ b/private/posix/client/psxdll.h @@ -0,0 +1,176 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + pdxdll.h + +Abstract: + + Posix Subsystem Dll Private Types and Prototypes + +Author: + + Mark Lucovsky (markl) 04-Oct-1989 + +Revision History: + +--*/ + +#ifndef _PDXP_ +#define _PDXP_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "psxmsg.h" +#define NTPSX_ONLY +#include "sesport.h" + +int *Errno; +#define errno (*Errno) + +char ***Environ; +#define environ (*Environ) + +// +// The PsxDllHandle global variable contains the DLL handle for the WINDLL +// client stubs executable. +// + +HANDLE PsxDllHandle; + +// +// The connection to the Server is described by the PsxPortHandle global +// variable. The connection is established when the PsxConnectToServer +// function is called. +// + +UNICODE_STRING PsxPortName; +HANDLE PsxPortHandle; + +extern ULONG PsxPortMemoryRemoteDelta; + +PVOID PdxHeap; +PVOID PdxPortHeap; +PSX_DIRECTORY_PREFIX PdxDirectoryPrefix; + +ANSI_STRING PsxAnsiCommandLine; + +// +// PathName Conversion Macros +// + +#define IS_POSIX_PATH_SEPARATOR(s) (*(s) == '/' ) +#define IS_POSIX_DOT(s) ( s[0] == '.' && ( s[1] == '/' || s[1] == '\0') ) +#define IS_POSIX_DOT_DOT(s) ( s[0] == '.' && s[1] == '.' && ( s[2] == '/' || s[2] == '\0') ) +#define IN_PORTABLE_CHARACTER_SET(c) (\ + ((c)>='A' && (c)<='Z') || \ + ((c)>='a' && (c)<='z') || \ + ((c)>='0' && (c)<='9') || \ + ((c)=='.') || \ + ((c)=='_') || \ + ((c)=='-') ) + +typedef int (_CRTAPI1 * PFNPROCESS)(ULONG argc, + PCHAR *argv + ); + +// +// Stuff for the uname() syscall. +// + +#define UNAME_SYSNAME "Windows NT" +#define UNAME_RELEASE "3" +#define UNAME_VERSION "5" + +// +// Prototypes +// + +void +ClientOpen( + IN int fd + ); + +VOID +PdxProcessStartup( + IN PPEB Peb + ); + +NTSTATUS +PsxConnectToServer(); + +NTSTATUS +PsxInitDirectories(); + +VOID +PdxNullPosixApi(); + +int +PdxStatusToErrno(NTSTATUS); + +int +PdxStatusToErrnoPath(PUNICODE_STRING); + +VOID +_PdxSignalDeliverer ( + IN PCONTEXT Context, + IN sigset_t PreviousBlockMask, + IN int Signal, + IN _handler Handler + ); + +VOID +PdxSignalDeliverer ( + IN PCONTEXT Context, + IN sigset_t PreviousBlockMask, + IN int Signal, + IN _handler Handler + ); + +VOID +_PdxNullApiCaller( + IN PCONTEXT Context + ); + +VOID +PdxNullApiCaller( + IN PCONTEXT Context + ); + + +BOOLEAN +PdxCanonicalize( + IN PSZ PathName, + OUT PUNICODE_STRING CanonPath, + IN PVOID Heap + ); + +// +// Routines defined in coninit.c +// + +NTSTATUS PsxInitializeSessionPort(IN ULONG UniqueId); + + +// +// Routines defined in conrqust.c +// + +NTSTATUS SendConsoleRequest(IN OUT PSCREQUESTMSG Request); + +#endif // _PDXP_ diff --git a/private/posix/client/psxdll.rc b/private/posix/client/psxdll.rc new file mode 100644 index 000000000..80bcfd562 --- /dev/null +++ b/private/posix/client/psxdll.rc @@ -0,0 +1,11 @@ +#include + +#include + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "Posix Client DLL" +#define VER_INTERNALNAME_STR "psxdll.dll" + +#include "common.ver" + diff --git a/private/posix/client/psxdll.src b/private/posix/client/psxdll.src new file mode 100644 index 000000000..b99f32012 --- /dev/null +++ b/private/posix/client/psxdll.src @@ -0,0 +1,151 @@ +LIBRARY PSXDLL + +DESCRIPTION 'POSIX Emulation Subsystem - Client Stubs' + +EXPORTS + __PdxGetCmdLine + __PdxInitializeData + fork + execl + execv + execle + execve + execlp + execvp + wait + waitpid + _exit + kill + signal + sigemptyset + sigfillset + sigaddset + sigdelset + sigismember + sigaction + sigprocmask + sigpending + sigsuspend + siglongjmp + alarm + pause + sleep + getpid + getppid + getuid + geteuid + getgid + getegid + setuid + setgid + getgroups + getlogin + getpgrp + getreg + setsid + setpgid + uname + time + times + getenv + ctermid + ttyname + isatty + isatty2 + sysconf + opendir + readdir + rewinddir + closedir + chdir + getcwd + open + creat + umask + link + mkdir + mkfifo + unlink + rmdir + rename + stat + fstat + access + chmod + chown + utime + pathconf + fpathconf + pipe + dup + dup2 + close + read + write + fcntl + lseek + fileno + getpwuid + getpwnam + getgrgid + getgrnam + tcgetattr + tcsetattr + tcdrain + tcflush + tcflow + tcsetpgrp + tcgetpgrp + tcsendbreak + cuserid + cfgetispeed + cfgetospeed + cfsetispeed + cfsetospeed + raise + system + remove + _sigjmp_store_mask + + ;; this for libc, but can't be forwarded + + GetProcessHeap + + ;; apis forwarded for libc + + HeapAlloc = NTDLL.RtlAllocateHeap + HeapFree = NTDLL.RtlFreeHeap + HeapReAlloc = NTDLL.RtlReAllocateHeap + HeapSize = NTDLL.RtlSizeHeap + RtlUnwind = NTDLL.RtlUnwind + RtlMoveMemory = NTDLL.RtlMoveMemory + RtlZeroMemory = NTDLL.RtlZeroMemory + RtlFillMemory = NTDLL.RtlFillMemory + + RtlAnsiCharToUnicodeChar = NTDLL.RtlAnsiCharToUnicodeChar + RtlMultiByteToUnicodeN = NTDLL.RtlMultiByteToUnicodeN + RtlUpcaseUnicodeToMultiByteN = NTDLL.RtlUpcaseUnicodeToMultiByteN + RtlUpcaseUnicodeChar = NTDLL.RtlUpcaseUnicodeChar + RtlUnicodeToMultiByteN = NTDLL.RtlUnicodeToMultiByteN + RtlUnicodeToMultiByteSize = NTDLL.RtlUnicodeToMultiByteSize + +#if defined(MIPS) + RtlCaptureContext = NTDLL.RtlCaptureContext + RtlLookupFunctionEntry = NTDLL.RtlLookupFunctionEntry + RtlVirtualUnwind = NTDLL.RtlVirtualUnwind +#endif + +#if defined(ALPHA) + RtlCaptureContext = NTDLL.RtlCaptureContext + RtlLookupFunctionEntry = NTDLL.RtlLookupFunctionEntry + RtlUnwindRfp = NTDLL.RtlUnwindRfp + RtlVirtualUnwind = NTDLL.RtlVirtualUnwind +#endif + +#if defined(PPC) + RtlCaptureContext = NTDLL.RtlCaptureContext + RtlLookupFunctionEntry = NTDLL.RtlLookupFunctionEntry + RtlVirtualUnwind = NTDLL.RtlVirtualUnwind +#endif + + ftruncate diff --git a/private/posix/client/sources b/private/posix/client/sources new file mode 100644 index 000000000..232d54fb0 --- /dev/null +++ b/private/posix/client/sources @@ -0,0 +1,64 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + Steve Wood (stevewo) 12-Apr-1990 + +NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl + +!ENDIF + +WIMPYMASM=1 + +MAJORCOMP=posix +MINORCOMP=client + +TARGETNAME=psxdll +TARGETPATH=\nt\public\sdk\lib +TARGETTYPE=DYNLINK +DLLENTRY=PsxDllInitialize + +LINKLIBS= \ + \nt\public\sdk\lib\*\ntdll.lib + + +INCLUDES=..\inc;\nt\public\sdk\inc\posix + +SOURCES= \ + coninit.c \ + conreqst.c \ + crtsup.c \ + dllext.c \ + dllfile.c \ + dllinit.c \ + dllio.c \ + dllname.c \ + dllproc.c \ + dllsig.c \ + dlltc.c \ + dlltimer.c \ + dllreg.c \ + psxdll.rc \ + stubs.c \ + sysdb.c + +C_DEFINES=-DPSX_IN_WIN -D_POSIX_ +UMTYPE=posix +UMBASE=0xa00000 + +NTTARGETFILE0=obj\*\psxdll.def +DLLDEF=$(NTTARGETFILE0) diff --git a/private/posix/client/stubs.c b/private/posix/client/stubs.c new file mode 100644 index 000000000..b21583de7 --- /dev/null +++ b/private/posix/client/stubs.c @@ -0,0 +1,195 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + stubs.c + +Abstract: + + TEMPORARY - stubs for unimplemented functions + +Author: + + Ellen Aycock-Wright (ellena) 15-Jul-1991 + +Revision History: + +--*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "psxdll.h" + +char * +_CRTAPI1 +ctermid(char *s) +{ + static char returnspace[L_ctermid]; + + if (NULL == s) { + return strcpy(returnspace, ""); + } + return strcpy(s, ""); +} + +int +_CRTAPI1 +setgid(gid_t gid) +{ + if (gid == getgid()) { + return 0; + } + errno = EPERM; + return -1; +} + +int +_CRTAPI1 +setuid(uid_t uid) +{ + if (uid == getuid()) { + return 0; + } + errno = EPERM; + return -1; +} + +char * +_CRTAPI1 +ttyname(int fildes) +{ + static char s[7]; + s[0] = 0; + return NULL; +} + +_JBTYPE * _CRTAPI1 +_sigjmp_store_mask(sigjmp_buf env, int save) +{ + if (save) { + env[_JBLEN] = 1; + sigprocmask(SIG_SETMASK, 0, (void *)&env[_JBLEN + 1]); + } else { + env[_JBLEN] = 0; + } + return env; +} + + +void +_CRTAPI1 +siglongjmp(sigjmp_buf j, int val) +{ + if (j[_JBLEN]) { + (void)sigprocmask(SIG_SETMASK, (PVOID)&j[_JBLEN + 1], NULL); + } + longjmp((void *)&j[0], val); + + //NOTREACHED +} + +int +_CRTAPI1 +cfsetispeed(struct termios *termios_p, speed_t speed) +{ + termios_p->c_ispeed = speed; + return 0; +} + +int +_CRTAPI1 +cfsetospeed(struct termios *termios_p, speed_t speed) +{ + termios_p->c_ospeed = speed; + return 0; +} + +speed_t +_CRTAPI1 +cfgetispeed(const struct termios *termios_p) +{ + return termios_p->c_ispeed; +} + +speed_t +_CRTAPI1 +cfgetospeed(const struct termios *termios_p) +{ + return termios_p->c_ospeed; +} + +int +_CRTAPI1 +system(const char *command) +{ + pid_t pid; + int status; + char *shell; + sigset_t saveblock; + struct sigaction sa, saveintr, savequit; + + if (NULL == command) { + return 0; + } + + // XXX.mjb: should use an absolute path to sh, if there + // was one, instead of $SHELL. + + shell = getenv("SHELL"); + if (NULL == shell) { + return 0; + } + + sa.sa_handler = SIG_IGN; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + + sigaction(SIGINT, &sa, &saveintr); + sigaction(SIGQUIT, &sa, &savequit); + + sigaddset(&sa.sa_mask, SIGCHLD); + sigprocmask(SIG_BLOCK, &sa.sa_mask, &saveblock); + + pid = fork(); + if (-1 == pid) { + return -1; + } + if (0 == pid) { + sigaction(SIGINT, &saveintr, NULL); + sigaction(SIGQUIT, &savequit, NULL); + sigprocmask(SIG_SETMASK, &saveblock, NULL); + execl(shell, "sh", "-c", command, NULL); + _exit(127); + } + if (-1 == waitpid(pid, &status, 0)) + status = -1; + + sigaction(SIGINT, &saveintr, NULL); + sigaction(SIGQUIT, &savequit, NULL); + sigprocmask(SIG_SETMASK, &saveblock, NULL); + + return status; +} + +int _CRTAPI1 +remove(const char *path) +{ + struct stat st_buf; + + if (-1 == stat(path, &st_buf)) + return unlink(path); + + if (S_ISDIR(st_buf.st_mode)) { + return rmdir(path); + } + + return unlink(path); +} diff --git a/private/posix/client/sysdb.c b/private/posix/client/sysdb.c new file mode 100644 index 000000000..84dbfc078 --- /dev/null +++ b/private/posix/client/sysdb.c @@ -0,0 +1,304 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + sysdb.c + +Abstract: + + Client side of system database (password and group) access routines. + +Author: + + Matthew Bradburn (mattbr) 04-Mar-1992 + +Revision History: + +--*/ + +#include +#include +#include +#include +#include "psxdll.h" + +extern PVOID PsxPortMemoryBase; + +static char pwbuf[ARG_MAX]; +static char grbuf[ARG_MAX]; + +struct passwd * +_CRTAPI1 +getpwuid(uid_t uid) +{ + PSX_API_MSG m; + PPSX_GETPWUID_MSG args; + NTSTATUS Status; + struct passwd *tmpbuf; + + args = &m.u.GetPwUid; + PSX_FORMAT_API_MSG(m, PsxGetPwUidApi, sizeof(*args)); + + args->Uid = uid; + args->PwBuf = RtlAllocateHeap(PdxPortHeap, 0, ARG_MAX); + ASSERT(args->PwBuf != NULL); + args->PwBuf = (struct passwd *)((PCHAR)args->PwBuf + + PsxPortMemoryRemoteDelta); + + Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); + + args->PwBuf = (struct passwd *)((PCHAR)args->PwBuf - + PsxPortMemoryRemoteDelta); + + if (0 != m.Error) { + RtlFreeHeap(PdxPortHeap, 0, args->PwBuf); + return NULL; + } + + (void)memcpy(pwbuf, args->PwBuf, args->Length); + + RtlFreeHeap(PdxPortHeap, 0, args->PwBuf); + + tmpbuf = (struct passwd *)pwbuf; + tmpbuf->pw_name += (ULONG)tmpbuf; + tmpbuf->pw_dir += (ULONG)tmpbuf; + tmpbuf->pw_shell += (ULONG)tmpbuf; + + return tmpbuf; +} + +struct passwd * +_CRTAPI1 +getpwnam(const char *name) +{ + PSX_API_MSG m; + PPSX_GETPWNAM_MSG args; + NTSTATUS Status; + struct passwd *tmpbuf; + + args = &m.u.GetPwNam; + PSX_FORMAT_API_MSG(m, PsxGetPwNamApi, sizeof(*args)); + + if ('\0' == *name) { + return NULL; + } + + args->Name = (PCHAR)RtlAllocateHeap(PdxPortHeap, 0, ARG_MAX); + ASSERT(args->Name != NULL); + + strcpy(args->Name,name); + args->Name += PsxPortMemoryRemoteDelta; + args->PwBuf = (struct passwd *)(args->Name + strlen(name) + 1); + + // + // Make sure buffer is properly aligned. + // + + while ((ULONG)args->PwBuf & 0x3) + args->PwBuf = (PVOID)((ULONG)args->PwBuf + 1); + + + Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); + + args->Name = args->Name - PsxPortMemoryRemoteDelta; + args->PwBuf = (struct passwd *)((PCHAR)args->PwBuf - + PsxPortMemoryRemoteDelta); + + if (0 != m.Error) { + RtlFreeHeap(PdxPortHeap, 0, args->Name); + return NULL; + } + + (void)memcpy(pwbuf, args->PwBuf, args->Length); + + RtlFreeHeap(PdxPortHeap, 0, args->Name); + + tmpbuf = (struct passwd *)pwbuf; + tmpbuf->pw_name += (ULONG)tmpbuf; + tmpbuf->pw_dir += (ULONG)tmpbuf; + tmpbuf->pw_shell += (ULONG)tmpbuf; + + return tmpbuf; +} + +struct group * +_CRTAPI1 +getgrgid(gid_t gid) +{ + PSX_API_MSG m; + PPSX_GETGRGID_MSG args; + NTSTATUS Status; + struct group *tmpbuf; + char **ppch; + + args = &m.u.GetGrGid; + PSX_FORMAT_API_MSG(m, PsxGetGrGidApi, sizeof(*args)); + args->Gid = gid; + + args->GrBuf = RtlAllocateHeap(PdxPortHeap, 0, ARG_MAX); + if (NULL == args->GrBuf) { + errno = ENOMEM; + return NULL; + } + args->GrBuf = (struct group *)((PCHAR)args->GrBuf + + PsxPortMemoryRemoteDelta); + + Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); + + args->GrBuf = (struct group *)((PCHAR)args->GrBuf - + PsxPortMemoryRemoteDelta); + + if (0 != m.Error) { + RtlFreeHeap(PdxPortHeap, 0, args->GrBuf); + return NULL; + } + + (void)memcpy(grbuf, args->GrBuf, args->Length); + + RtlFreeHeap(PdxPortHeap, 0, args->GrBuf); + + tmpbuf = (void *)grbuf; + tmpbuf->gr_name = (PCHAR)((ULONG)grbuf + (ULONG)tmpbuf->gr_name); + tmpbuf->gr_mem = (PCHAR *)((ULONG)grbuf + (ULONG)tmpbuf->gr_mem); + + for (ppch = tmpbuf->gr_mem; NULL != *ppch; ++ppch) { + *ppch = (PCHAR)((ULONG)grbuf + (ULONG)*ppch); + } + return tmpbuf; +} + +struct group * +_CRTAPI1 +getgrnam(const char *name) +{ + PSX_API_MSG m; + PPSX_GETGRNAM_MSG args; + NTSTATUS Status; + struct group *tmpbuf; + char **ppch; + + args = &m.u.GetGrNam; + PSX_FORMAT_API_MSG(m, PsxGetGrNamApi, sizeof(*args)); + + if ('\0' == *name) { + // + // We need to take special care of this case, because + // SAM will find a match for the null name. + // + return NULL; + } + + args->Name = (PCHAR)RtlAllocateHeap(PdxPortHeap, 0, ARG_MAX); + ASSERT(args->Name != NULL); + + strcpy(args->Name,name); + args->Name += PsxPortMemoryRemoteDelta; + + args->GrBuf = (struct group *)(args->Name + strlen(name) + 1); + + // + // Make sure buffer is properly aligned. + // + + while ((ULONG)args->GrBuf & 0x3) + args->GrBuf = (PVOID)((ULONG)args->GrBuf + 1); + + Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); + + args->Name = args->Name - PsxPortMemoryRemoteDelta; + args->GrBuf = (struct group *)((PCHAR)args->GrBuf - + PsxPortMemoryRemoteDelta); + + if (0 != m.Error) { + RtlFreeHeap(PdxPortHeap, 0, args->Name); + return NULL; + } + + (void)memcpy(grbuf, args->GrBuf, args->Length); + tmpbuf = (void *)grbuf; + tmpbuf->gr_name = (PCHAR)((ULONG)grbuf + (ULONG)tmpbuf->gr_name); + tmpbuf->gr_mem = (PCHAR *)((ULONG)grbuf + (ULONG)tmpbuf->gr_mem); + + for (ppch = tmpbuf->gr_mem; NULL != *ppch; ++ppch) { + *ppch = (PCHAR)((ULONG)grbuf + (ULONG)*ppch); + } + RtlFreeHeap(PdxPortHeap, 0, (PVOID)args->Name); + return tmpbuf; +} + +char * +_CRTAPI1 +getlogin(void) +{ + static char name[32]; + PSX_API_MSG m; + PPSX_GETPWUID_MSG args; + NTSTATUS Status; + + // + // We just do the equivalent of getpwuid(getuid()) and then + // throw away everything but the name. + // + + // + // XXX.mjb: do I need to use a name outside the POSIX namespace + // for this? Like, what happens if the user has re-defined getuid()? + // + + args = &m.u.GetPwUid; + PSX_FORMAT_API_MSG(m, PsxGetPwUidApi, sizeof(*args)); + + args->Uid = getuid(); + args->PwBuf = (struct passwd *)RtlAllocateHeap(PdxPortHeap, 0, ARG_MAX); + ASSERT(args->PwBuf != NULL); + args->PwBuf = (struct passwd *)((PCHAR)args->PwBuf + + PsxPortMemoryRemoteDelta); + + Status = NtRequestWaitReplyPort(PsxPortHandle, (PPORT_MESSAGE)&m, + (PPORT_MESSAGE)&m); + + args->PwBuf = (struct passwd *)((PCHAR)args->PwBuf - + PsxPortMemoryRemoteDelta); + + if (0 != m.Error) { + RtlFreeHeap(PdxPortHeap, 0, args->PwBuf); + return NULL; + } + + strcpy(name, (PCHAR)((ULONG)(args->PwBuf->pw_name) + (ULONG)args->PwBuf)); + + RtlFreeHeap(PdxPortHeap, 0, args->PwBuf); + + return name; +} + +#ifndef L_cuserid +#define L_cuserid 32 +#endif + +char * +_CRTAPI1 +cuserid(char *s) +{ + static char ReturnSpace[ L_cuserid ]; + struct passwd *PassWd; + char *Dest; + + PassWd = getpwuid( getuid() ); + + if( PassWd == NULL ) { + *s = '\0'; + return( ( s == NULL ) ? NULL : s ); + } else { + Dest = ( ( s == NULL ) ? ReturnSpace : s ); + strncpy( Dest, PassWd->pw_name, L_cuserid - 1 ); + Dest[ L_cuserid - 1 ] = '\0'; + } +} + diff --git a/private/posix/client/tst/tstdir.c b/private/posix/client/tst/tstdir.c new file mode 100644 index 000000000..cac768cd5 --- /dev/null +++ b/private/posix/client/tst/tstdir.c @@ -0,0 +1,308 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tsttmp.h" // defines DbgPrint as printf + +extern int errno; +VOID dir0(char *); +VOID dir1(char *); +VOID dir2(char *); +VOID dir3(char *); +VOID dir4(char *); +VOID dir5(char *); + + +int +main(int argc, char *argv[]) +{ + + DbgPrint("argc = %d, argv[1] = %s\n", argc, argv[1]); + + if (argc != 2) { + DbgPrint("Usage: 'tstdir basedirectory' (basedirectory is usually /psx/test)\n"); + return 1; + } + + dir0(argv[1]); + dir1(argv[1]); + dir2(argv[1]); + dir3(argv[1]); + dir4(argv[1]); + dir5(argv[1]); + + return 1; +} + + +VOID +dir0(char *f) +{ + int rc; + DIR *dir; + struct dirent *dirent; + + DbgPrint("dir0:++ %s\n",f); + + dir = opendir(f); + ASSERT(dir != NULL); + + errno = 0; + dirent = readdir(dir); + while( dirent ) { + DbgPrint("%s\n",&dirent->d_name); + dirent = readdir(dir); + } + ASSERT(errno == 0); + + rc = closedir(dir); + ASSERT(rc==0); + + rc = closedir(dir); + ASSERT(rc==-1 && errno == EBADF); + + DbgPrint("dir0:--\n"); +} + +VOID +dir1(char *f) +{ + int rc,i; + DIR *dir; + + char buf1[256],buf2[256]; + struct dirent *dirent; + + DbgPrint("dir1:++ %s\n",f); + + dir = opendir(f); + ASSERT(dir != NULL); + + // + // Get Two Directory entries. + // + i = 0; + errno = 0; + dirent = readdir(dir); + if ( dirent ) { + strcpy(buf1,(char *)&dirent->d_name); + i++; + } + dirent = readdir(dir); + if ( dirent ) { + strcat(buf1,(char *)&dirent->d_name); + i++; + } + + // + // Go past a few entries + // + + dirent = readdir(dir); + if ( dirent ) { + dirent = readdir(dir); + } + + // + // Rewind the directory stream and then read into a new buffer + // and compare results + // + + rewinddir(dir); + + buf2[0]='\0'; + while(i--) { + dirent = readdir(dir); + ASSERT(dirent); + strcat(buf2,(char *)&dirent->d_name); + } + ASSERT(strcmp(buf1,buf2) == 0); + + rc = closedir(dir); + ASSERT(rc==0); + + rc = closedir(dir); + ASSERT(rc==-1 && errno == EBADF); + + DbgPrint("dir1:--\n"); +} + +VOID +dir2(char *f) +{ + int rc; + char buf[256], *b; + + + DbgPrint("dir2:++ %s\n",f); + + rc = chdir(f); + ASSERT(rc==0); + + b = getcwd(buf,256); + ASSERT(b); + + b = getcwd(buf,-1); + ASSERT(b==NULL && errno == EINVAL); + + b = getcwd(buf,1); + ASSERT(b==NULL && errno == ERANGE); + + rc = chdir("/psx/test/tstdirs"); + ASSERT(rc==0); + + b = getcwd(buf,256); + ASSERT(b); + + b = getcwd(buf,-1); + ASSERT(b==NULL && errno == EINVAL); + + b = getcwd(buf,1); + ASSERT(b==NULL && errno == ERANGE); + + DbgPrint("dir2:--\n"); +} + +VOID +dir3(char *f) +{ + int rc; + DIR *dir; + struct dirent *dirent; + + DbgPrint("dir3:++ %s\n",f); + + rc = chdir(f); + ASSERT(rc==0); + + dir = opendir("."); + ASSERT(dir != NULL); + + errno = 0; + dirent = readdir(dir); + while( dirent ) { + DbgPrint("%s\n",&dirent->d_name); + dirent = readdir(dir); + } + ASSERT(errno == 0); + + rc = closedir(dir); + ASSERT(rc==0); + + rc = chdir("/psx/test/tstdirs"); + ASSERT(rc==0); + + dir = opendir("."); + ASSERT(dir != NULL); + + errno = 0; + dirent = readdir(dir); + while( dirent ) { + DbgPrint("%s\n",&dirent->d_name); + dirent = readdir(dir); + } + ASSERT(errno == 0); + + rc = closedir(dir); + ASSERT(rc==0); + + + DbgPrint("dir3:--\n"); +} + + +VOID +dir4(char *f) +{ + int rc; + DIR *dir; + struct dirent *dirent; + + DbgPrint("dir4:++ %s\n",f); + + dir = opendir(f); + ASSERT(dir != NULL); + + if ( fork() == 0 ) { + sleep(10); + errno = 0; + dirent = readdir(dir); + while( dirent ) { + DbgPrint("%s\n",&dirent->d_name); + dirent = readdir(dir); + } + ASSERT(errno == 0); + + rc = closedir(dir); + ASSERT(rc==0); + + rc = closedir(dir); + ASSERT(rc==-1 && errno == EBADF); + + _exit(0); + } + + rc = closedir(dir); + ASSERT(rc==0); + + rc = closedir(dir); + ASSERT(rc==-1 && errno == EBADF); + + wait(NULL); + + DbgPrint("dir4:--\n"); +} + +VOID +dir5(char *f) +{ + int rc; + char buf[256], *b; + PCH Arg[3], Env[4]; + + + DbgPrint("dir5:++ %s\n",f); + + rc = chdir(f); + ASSERT(rc==0); + + b = getcwd(buf,256); + ASSERT(b); + + b = getcwd(buf,-1); + ASSERT(b==NULL && errno == EINVAL); + + b = getcwd(buf,1); + ASSERT(b==NULL && errno == ERANGE); + + rc = chdir("/psx/test/tstdirs"); + ASSERT(rc==0); + + b = getcwd(buf,256); + ASSERT(b); + + b = getcwd(buf,-1); + ASSERT(b==NULL && errno == EINVAL); + + b = getcwd(buf,1); + ASSERT(b==NULL && errno == ERANGE); + + Arg[0]="tsthello.xxx"; + Arg[1]=(PCH)NULL; + Env[0]="NTUSER=ELLENA"; + Env[1]=(PCH)NULL; + + execve("\\DosDevices\\D:\\PSX\\TSTHELLO.exe",Arg,Env); + + ASSERT(FALSE); + + DbgPrint("dir5:--\n"); +} diff --git a/private/posix/client/tst/tstexec.c b/private/posix/client/tst/tstexec.c new file mode 100644 index 000000000..53c9e53e6 --- /dev/null +++ b/private/posix/client/tst/tstexec.c @@ -0,0 +1,68 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tsttmp.h" // defines DbgPrint as printf + +extern int errno; +VOID dir5(char *); + + +int +_CRTAPI1 +main(int argc, char *argv[]) +{ + + DbgPrint("argc = %d, argv[1] = %s\n", argc, argv[1]); + + if (argc != 2) { + + DbgPrint("Usage: 'tstexec basedirectory' (basedirectory is usually /psx/test)\n"); + return 1; + } + + dir5(argv[1]); + + return 1; +} + +VOID +dir5(char *f) +{ + int rc; + char buf[256], *b; + PCH Arg[3], Env[4]; + + DbgPrint("dir5:++ %s\n",f); + + rc = chdir(f); + ASSERT(rc==0); + + b = getcwd(buf,256); + ASSERT(b); + + rc = chdir("/psx/test/tstdirs"); + ASSERT(rc==0); + + b = getcwd(buf,256); + ASSERT(b); + + Arg[0]="tsthello.xxx"; + Arg[1]=(PCH)NULL; + Env[0]="NTUSER=ELLENA"; + Env[1]=(PCH)NULL; + + execve("\\DosDevices\\D:\\PSX\\TSTHELLO.exe",Arg,Env); + + ASSERT(FALSE); + + DbgPrint("dir5:--\n"); +} diff --git a/private/posix/client/tst/tstfile.c b/private/posix/client/tst/tstfile.c new file mode 100644 index 000000000..102cd984e --- /dev/null +++ b/private/posix/client/tst/tstfile.c @@ -0,0 +1,252 @@ +// +// Usage comments: +// Current working directory default is d:/psx - put test files there +// Needs tstf.one tstf.two out.dat +// 'file tstf.one tstf.two' +// + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "tsttmp.h" // defines DbgPrint as printf + +extern int errno; + +VOID file0(char *); +VOID file1(char *); +VOID file2(char *, char *); +VOID file3(char *); +VOID file4(char *, char *); + + +int +main(int argc, char *argv[]) +{ + + + if (argc != 3) { + DbgPrint("Usage: 'tstfile tstf.one tstf.two'\n"); + return 1; + } + file0(argv[1]); + file1(argv[1]); + file2(argv[1],argv[2]); + file3(argv[1]); + file4(argv[1],argv[2]); + + return 1; +} + + +VOID +file0(char *f) +{ + int rc,fd; + char buf[512]; + + DbgPrint("file0:++ %s\n",f); + + fd = open(f,O_RDONLY); + + ASSERT(fd != -1); + + rc = read(fd,buf,512); + + ASSERT(rc != -1); + + rc = close(fd); + + ASSERT(rc != -1); + + DbgPrint("file0:--\n"); +} + +VOID +file1(char *f) +{ + int rcb,wcb,ifd,ofd; + char buf[512], testbuf[128]; + struct stat statbuf; + struct stat *ps; + int i; + + DbgPrint("file1:++ %s\n",f); + + ps = &statbuf; + // stat always fails with ENOENT for now - see comment in psx/fdapi.c + + rcb = stat(f, ps); + if (rcb == -1) + DbgPrint("FAIL on stat: errno = %d\n", errno); + else { + DbgPrint("Mode = %lx, ino = %lx, dev = %ld, nlink = %ld, uid = %lx\n", + ps->st_mode, ps->st_ino, ps->st_dev, ps->st_nlink, ps->st_uid); + DbgPrint("gid = %lx, size = %ld, atime = %lx, mtime = %lx, ctime = %lx\n", + ps->st_gid, ps->st_size, ps->st_atime, ps->st_mtime, ps->st_ctime); + } + + ifd = open(f,O_RDONLY); + ASSERT(ifd != -1); + + ofd = open("out.dat",O_WRONLY | O_TRUNC); + ASSERT(ofd != -1); + + do { + rcb = read(ifd,buf,512); + ASSERT(rcb != -1); + wcb = write(ofd,buf,rcb); + ASSERT(wcb != -1); + } while (rcb == 512); + + rcb = close(ofd); + ASSERT(rcb != -1); + + ofd = open("out.dat",O_RDWR); + ASSERT(ofd != -1); + + for (i = 0; i < 128; i++) { + testbuf[i] = (char) i; + buf[i] = 0; + } + + wcb = write(ofd,testbuf,128); + ASSERT(wcb != -1); + + lseek(ofd, 0L, SEEK_SET); + rcb = read(ofd,buf,128); + ASSERT(rcb != -1); + if (rcb == -1) + DbgPrint("errno = %d\n", errno); + + for (i = 0; i < 128; i++) { + if (buf[i] != testbuf[i]) { + DbgPrint("FAIL buffer contents check at %d\n", i); + for (i = 0; i < 128; i++) { + DbgPrint("%d ", buf[i]); + } + DbgPrint("\n"); + break; + } + } + + DbgPrint("Testing fstat on %s\n", f); + rcb = fstat(ifd, ps); + if (rcb == -1) + DbgPrint("FAIL on fstat: errno = %d\n", errno); + else + DbgPrint("Mode = %lx, ino = %lx, dev = %ld, nlink = %ld, uid = %lx\n", + ps->st_mode, ps->st_ino, ps->st_dev, ps->st_nlink, ps->st_uid); + DbgPrint("gid = %lx, size = %ld, atime = %lx, mtime = %lx, ctime = %lx\n", + ps->st_gid, ps->st_size, ps->st_atime, ps->st_mtime, ps->st_ctime); + + rcb = close(ifd); + ASSERT(rcb != -1); + rcb = close(ofd); + ASSERT(rcb != -1); + + DbgPrint("file1:--\n"); +} + +VOID +file2(char *f1,char *f2) +{ + int fd; + + DbgPrint("file2:++ %s %s\n",f1,f2); + + fd = open(f1, O_RDONLY | O_CREAT | O_EXCL, 0); + ASSERT(fd == -1 && errno == EEXIST); + if (fd == -1 && errno != EEXIST) + DbgPrint("FAIL: errno = %d\n", errno); + + DbgPrint("file2:--\n"); +} + + +VOID +file3(char *f) +{ + int rc, fd, fd2; + char buf[512]; + + DbgPrint("file3:++ %s - Testing dup\n",f); + + fd = open(f,O_RDONLY); + + ASSERT(fd != -1); + + rc = read(fd,buf,512); + + ASSERT(rc != -1); + + fd2 = dup(fd); + + ASSERT(fd2 != -1); + + rc = close(fd); + + ASSERT(rc != -1); + + rc = read(fd2,buf,512); + + ASSERT(rc != -1); + + rc = close(fd2); + + ASSERT(rc != -1); + + DbgPrint("file3:--\n"); +} + +VOID +file4(char *f1,char *f2) +{ + int rc, fd, fd2, fd3; + char buf[512]; + + DbgPrint("file4:++ %s %s - Testing dup2\n",f1, f2); + + fd = open(f1,O_RDONLY); + fd2 = open(f2,O_RDONLY); + fd3 = open(f2,O_RDONLY); + + ASSERT(fd != -1 && fd2 != -1 && fd3 != -1); + + rc = read(fd,buf,512); + + ASSERT(rc != -1); + + rc = read(fd2,buf,512); + + ASSERT(rc != -1); + + fd2 = dup2(fd, fd2); + + ASSERT(fd2 != -1); + + rc = close(fd); + + ASSERT(rc != -1); + + rc = close(fd3); + + ASSERT(rc != -1); + + rc = read(fd2,buf,512); + + ASSERT(rc != -1); + + rc = close(fd2); + + ASSERT(rc != -1); + + DbgPrint("file4:--\n"); +} diff --git a/private/posix/client/tst/tstfork.c b/private/posix/client/tst/tstfork.c new file mode 100644 index 000000000..c3a316a19 --- /dev/null +++ b/private/posix/client/tst/tstfork.c @@ -0,0 +1,598 @@ +#include +#include + +#include "psxmsg.h" +#include +#include +#include +#include +#include +#include +#include + +#include "tsttmp.h" // defines DbgPrint as printf + +extern int errno; + +VOID p0(VOID); +VOID p1(VOID); +VOID ex0(VOID); +VOID a0(VOID); +VOID s0(VOID); +VOID call0(VOID); +VOID f1(VOID); +VOID f2(VOID); +VOID p0foo(VOID); + +CONTEXT a0JumpBuff; + +int _CRTAPI1 main(int argc, char *argv[]) +{ + + pid_t self; + PCH p,t; + PTEB ThreadInfo; + + ThreadInfo = NtCurrentTeb(); + + self = getpid(); + + DbgPrint("tstfork: My pid is %lx Argc = %lx\n",self,argc); + DbgPrint("tstfork: StackBase %lx\n",ThreadInfo->NtTib.StackBase); + DbgPrint("tstfork: StackLimit %lx\n",ThreadInfo->NtTib.StackLimit); + DbgPrint("tstfork: ClientId %lx.%lx\n",ThreadInfo->ClientId.UniqueProcess,ThreadInfo->ClientId.UniqueThread); + + while(argc--){ + p = *argv++; + t = p; + while(*t++); + DbgPrint("Argv --> %s\n",p); + } + + + p0(); + p1(); + ex0(); + a0(); + s0(); + call0(); + f1(); + f2(); + + _exit(2); + return 1; + +} + +VOID +p0foo(){} + +ULONG +p0touch( + IN PUCHAR pch, + IN ULONG nb + ) +{ + ULONG ct = 0; + + DbgPrint("p0touch: pch %lx nb %lx\n",pch,nb); + + while (nb--) { + ct += *pch++; + } + return ct; +} + +VOID +p0() +{ + int fildes[2]; + int psxst; + UCHAR buffer[525]; + UCHAR buf[525]; + int i; + + for(i=0;i<525;i++){ + buf[i] = (char)(i&255); + } + + DbgPrint("p0:++\n"); + + // + // Create a pipe + // + + psxst = pipe(fildes); + + if ( psxst ) { + DbgPrint("p0: pipe() failed st = %lx errno %lx\n",psxst,errno); + return; + } + + DbgPrint("p0: fildes[0] = %lx filedes[1] = %lx\n",fildes[0],fildes[1]); + + // + // Test write followed by read + // + + psxst = write(fildes[1],"Hello World\n",13); + if ( psxst < 0 ) { + DbgPrint("p0: write() failed st = %lx errno %lx\n",psxst,errno); + return; + } + + DbgPrint("p0: write() success transfered %lx bytes to fd %lx\n",psxst,fildes[1]); + + psxst = read(fildes[0],buffer,32); + if ( psxst < 0 ) { + DbgPrint("p0: read() failed st = %lx errno %lx\n",psxst,errno); + return; + } + + p0touch(buffer,psxst); + DbgPrint("p0: read() success transfered %lx bytes from fd %lx %s\n",psxst,fildes[1],buffer); + // + // End write followed by read + // + + + // + // assume parents read will happen before childs write. + // parents first read blocks testing write unblocks read + // + + if ( !fork() ) { + + + DbgPrint("p0:child pid %lx\n",getpid()); + DbgPrint("p0:child writing\n"); + + sleep(8); + + psxst = write(fildes[1],"From Child\n\0",12); + if ( psxst < 0 ) { + DbgPrint("p0:child write() failed st = %lx errno %lx\n",psxst,errno); + return; + } + DbgPrint("p0:child write() success transfered %lx bytes to fd %lx\n",psxst,fildes[1]); + + psxst = write(fildes[1],"Small Write\n\0",13); + if ( psxst < 0 ) { + DbgPrint("p0:child write() failed st = %lx errno %lx\n",psxst,errno); + return; + } + DbgPrint("p0:child write() success transfered %lx bytes to fd %lx\n",psxst,fildes[1]); + + // + // this write should block and get unblocked when read of + // previous write completes + // + p0foo(); + psxst = write(fildes[1],buf,514); + if ( psxst < 0 ) { + DbgPrint("p0:child write() failed st = %lx errno %lx\n",psxst,errno); + return; + } + DbgPrint("p0:child write() success transfered %lx bytes to fd %lx\n",psxst,fildes[1]); + + _exit(1); + } + + DbgPrint("p0:parent reading\n"); + psxst = read(fildes[0],buffer,12); + + if ( psxst < 0 ) { + DbgPrint("p0:parent read() failed st = %lx errno %lx\n",psxst,errno); + return; + } + p0touch(buffer,psxst); + DbgPrint("p0:parent read() success transfered %lx bytes from fd %lx %s\n",psxst,fildes[1],buffer); + + DbgPrint("p0:parent sleeping\n"); + sleep(12); + DbgPrint("p0:parent back from sleep\n"); + + DbgPrint("p0:parent reading\n"); + psxst = read(fildes[0],buffer,13); + if ( psxst < 0 ) { + DbgPrint("p0:parent read() failed st = %lx errno %lx\n",psxst,errno); + return; + } + p0touch(buffer,psxst); + DbgPrint("p0:parent read() success transfered %lx bytes from fd %lx %s\n",psxst,fildes[1],buffer); + + psxst = read(fildes[0],buffer,512); + if ( psxst < 0 ) { + DbgPrint("p0:parent read() failed st = %lx errno %lx\n",psxst,errno); + return; + } + DbgPrint("p0:parent read() success transfered %lx bytes from fd %lx\n",psxst,fildes[1]); + + for(i=0;i +#include +#include +#include +#include + +// +// 'tstheap.c' +// Tests out malloc, calloc, realloc, and mfree. +// +// 05/22/92 DarekM Created +// + +#define max(a,b) ((a > b) ? a : b ) + + +int +main(int argc, char *argv[]) +{ + int l; // loop counter + int t; // total memory allocated + int c; // count of blocks + int i; // current block index + void *p; // address of block + int numblocks; + int delta; + void **rgp; // array of memory pointers + int fDEBUG = 0; + + if (argc < 3) + { + printf("Usage: tstheap [DUMP]\n\n"); + return; + } + else if (argc > 3) + fDEBUG = 1; + + numblocks = max(1, atoi(argv[1])); + delta = max(1, atoi(argv[2])); + rgp = malloc(numblocks * sizeof(void *)); + + printf("TstHeap: numblocks = %d, delta = %d\n\n", numblocks, delta); + + for (l = 0; ; l++) + { + t = c = 0; + + printf("PASS #%d\n", l); + + for (i = 0; i < numblocks; i++) + { + int cb; + + if (i & 1) + p = malloc(cb = i + l*delta + 1); + else + p = calloc(cb = i + l*delta + (rand() & 255) + 1, 1); + + if (p == NULL) + { + printf("p == NULL\n"); + break; + } + + if (((int)p < 0x1000) || ((int)p < 0)) + { + printf("WIERD P == %d\n", p); + break; + } + + rgp[i] = p; + t += cb; + + if (fDEBUG) + printf(" %d,%02d: Alloced $%08X\n", l, i, p); + } + + if ((c = i) == 0) + break; + + printf(" Blocks alloced: %d Bytes: %d\n", c, t); + + for (i = 0; i < c; i++) + { + rgp[i] = p = realloc(rgp[i], 1); + + if (fDEBUG) + printf(" %d,%02d: Realloced $%08X\n", l, i, p); + } + + printf(" Blocks realloced: %d\n", i); + + for (i = 0; i < c; i++) + { + free(rgp[i]); + + if (fDEBUG) + printf(" %d,%02d: Freed $%08X\n", l, i, rgp[i]); + } + + printf(" Blocks freed: %d\n\n", i); + } + + printf("\n\n"); + + free(rgp); + return 1; +} + + diff --git a/private/posix/client/tst/tsthello.c b/private/posix/client/tst/tsthello.c new file mode 100644 index 000000000..a34d105f8 --- /dev/null +++ b/private/posix/client/tst/tsthello.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include + +#include "tsttmp.h" // defines DbgPrint as printf + +int +main(int argc, char *argv[]) + +{ + PCH p,t; + CHAR Buf[128],c,*b; + struct tms *TimeBuffer; + int psxst; + + while(argc--){ + p = *argv++; + t = p; + while(*t++); + DbgPrint("Argv --> %s\n",p); + } + + b = getcwd(Buf,128); + ASSERT(b); + + psxst = read(0,Buf,128); + if ( psxst > 0 ) { + if ( psxst == sizeof(*TimeBuffer) ) { + DbgPrint("time buffer received\n"); + } else { + c = Buf[0]; + DbgPrint("hello_main: Pipe Read %s\n",Buf,c); + } + } + return 1; +} diff --git a/private/posix/client/tst/tsthw.c b/private/posix/client/tst/tsthw.c new file mode 100644 index 000000000..3327c3024 --- /dev/null +++ b/private/posix/client/tst/tsthw.c @@ -0,0 +1,20 @@ + +#include +#include +#include +#include + +#include "tsttmp.h" // defines DbgPrint as printf + +// +// 'tsthw' +// First step 'hellow world' test +// + +int +main(int argc, char *argv[]) +{ + DbgPrint("Hello World\n"); + return 1; +} + diff --git a/private/posix/client/tst/tstjc.c b/private/posix/client/tst/tstjc.c new file mode 100644 index 000000000..68f559a0e --- /dev/null +++ b/private/posix/client/tst/tstjc.c @@ -0,0 +1,367 @@ +#include +#include + +#include +#include +#include +#include +#include + +#include "tsttmp.h" // defines DbgPrint as printf + +extern int errno; +VOID jc0(VOID); +VOID jc1(VOID); +VOID jc2(VOID); +VOID jc3(VOID); + +int +main(int argc, char *argv[]) +{ + + pid_t self; + PCH p,t; + PTEB ThreadInfo; + + ThreadInfo = NtCurrentTeb(); + + self = getpid(); + + DbgPrint("jc: My pid is %lx Argc = %lx\n",self,argc); + DbgPrint("jc: StackBase %lx\n",ThreadInfo->NtTib.StackBase); + DbgPrint("jc: StackLimit %lx\n",ThreadInfo->NtTib.StackLimit); + DbgPrint("jc: ClientId %lx.%lx\n",ThreadInfo->ClientId.UniqueProcess,ThreadInfo->ClientId.UniqueThread); + + while(argc--){ + p = *argv++; + t = p; + while(*t++); + DbgPrint("Argv --> %s\n",p); + } + + jc0(); + jc1(); + jc2(); + jc3(); + + return 1; +} + + +VOID +jc0() +{ + pid_t child; + int rc,stat_loc; + struct sigaction act; + + + DbgPrint("jc0:++\n"); + + // + // Ignore SIGCHLD signals + // + + act.sa_flags = SA_NOCLDSTOP; + act.sa_handler = SIG_IGN; + rc = sigaction(SIGCHLD, &act, NULL); + ASSERT( rc == 0 ); + + child = fork(); + + if ( !child) { + + for(;;); + + ASSERT(0 != 0); + } + + rc = kill(child,SIGSTOP); + ASSERT(rc==0); + + // + // Make sure that wait is satisfied by stopped child + // + + rc = waitpid(child,&stat_loc,WUNTRACED); + ASSERT(rc == child && WIFSTOPPED(stat_loc) && WSTOPSIG(stat_loc) == SIGSTOP); + + // + // Also make sure that it's status may only be picked up once + // + + rc = waitpid(child,NULL,WUNTRACED | WNOHANG); + ASSERT(rc == 0); + + // + // SEGV the process. Since it is stopped, this should have no effect + // + + rc = kill(child,SIGSEGV); + ASSERT(rc==0); + + rc = waitpid(child,NULL,WUNTRACED | WNOHANG); + ASSERT(rc == 0); + + // + // Kill the process w/ SIGKILL. This should doit + // + + rc = kill(child,SIGKILL); + ASSERT(rc==0); + + rc = waitpid(child,&stat_loc,0); + ASSERT(rc == child && WIFSIGNALED(stat_loc) && WTERMSIG(stat_loc) == SIGKILL); + + DbgPrint("jc0:--\n"); +} + +int thechild; + +void +jc1_sigchld_handler( + IN int sig + ) +{ + int rc, stat_loc; + struct sigaction act; + + ASSERT(sig == SIGCHLD); + rc = waitpid(thechild,&stat_loc,0); + ASSERT(rc == thechild && WIFEXITED(stat_loc) && WEXITSTATUS(stat_loc) == 100); + + act.sa_flags = 0; + sigfillset(&act.sa_mask); + act.sa_handler = SIG_IGN; + rc = sigaction(SIGCHLD, &act, NULL); + ASSERT( rc == 0 ); +} + +void +jc1_sigcont_handler( + IN int sig + ) +{ + ASSERT(sig == SIGCONT); + _exit(100); +} + +VOID +jc1() +{ + int rc,stat_loc; + struct sigaction act; + sigset_t set,oset; + + DbgPrint("jc1:++\n"); + + // + // Catch SIGCHLD signals + // + + act.sa_flags = 0; + sigfillset(&act.sa_mask); + act.sa_handler = jc1_sigchld_handler; + rc = sigaction(SIGCHLD, &act, NULL); + ASSERT( rc == 0 ); + + // + // Catch SIGCONT. This is really set up for Child + // + + act.sa_flags = 0; + sigfillset(&act.sa_mask); + act.sa_handler = jc1_sigcont_handler; + rc = sigaction(SIGCONT, &act, NULL); + ASSERT( rc == 0 ); + + thechild = fork(); + + if ( !thechild) { + + for(;;); + + _exit(99); + + ASSERT(0 != 0); + } + + // + // Block SIGCHLD + // + + sigfillset(&set); + rc = sigprocmask(SIG_SETMASK,&set,&oset); + ASSERT(rc==0); + + rc = kill(thechild,SIGSTOP); + ASSERT(rc==0); + + // + // Make sure that wait is satisfied by stopped child + // + + rc = waitpid(thechild,&stat_loc,WUNTRACED); + ASSERT(rc == thechild && WIFSTOPPED(stat_loc) && WSTOPSIG(stat_loc) == SIGSTOP); + + // + // SIGCONT the process. + // + + rc = kill(thechild,SIGCONT); + ASSERT(rc==0); + + // + // Unblock SIGCHLD + // + + rc = sigprocmask(SIG_SETMASK,&oset,NULL); + ASSERT(rc==0); + + rc = waitpid(thechild,&stat_loc,WUNTRACED); + ASSERT( rc == -1 && errno == ECHILD); + + act.sa_flags = 0; + sigfillset(&act.sa_mask); + act.sa_handler = SIG_DFL; + rc = sigaction(SIGCONT, &act, NULL); + + DbgPrint("jc1:--\n"); +} + +VOID +jc2() +{ + pid_t child, OrigGroup; + int rc,stat_loc; + + DbgPrint("jc2:++\n"); + + OrigGroup = getpgrp(); + + // + // Should be process group leader + // + + ASSERT(getpid() == OrigGroup); + + // + // Fork. Then have child establish its own group. + // Child and parent are in then in different groups, + // but in the same session. + // + + if ( !fork() ) { + + rc = setpgid(0,0); + ASSERT(rc==0 && getpgrp() == getpid()); + + child = fork(); + + if ( !child ) { + + rc = kill(getpid(),SIGSTOP); + ASSERT(rc==0); + } + + rc = waitpid(child,&stat_loc,WUNTRACED); + ASSERT(rc == child && WIFSTOPPED(stat_loc) && WSTOPSIG(stat_loc) == SIGSTOP); + + // + // Conditions are set. If this process exits, then its group + // will zombie. Stopped process should continue w/ SIGCONT/SIGHUP + // + + _exit(123); + + } + + rc = wait(&stat_loc); + ASSERT(WIFEXITED(stat_loc) && WEXITSTATUS(stat_loc) == 123); + sleep(10); + + DbgPrint("jc2:--\n"); +} + +VOID +jc3() +{ + pid_t child, OrigGroup; + int rc,stat_loc; + + DbgPrint("jc3:++\n"); + + OrigGroup = getpgrp(); + + // + // Should be process group leader + // + + ASSERT(getpid() == OrigGroup); + + // + // Fork. Then have child establish its own group. + // Child and parent are in then in different groups, + // but in the same session. + // + + if ( !fork() ) { + + rc = setpgid(0,0); + ASSERT(rc==0 && getpgrp() == getpid()); + + child = fork(); + + if ( !child ) { + struct sigaction act; + + // + // Child should ignore SIGHUP + // + + act.sa_flags = SA_NOCLDSTOP; + act.sa_handler = SIG_IGN; + rc = sigaction(SIGHUP, &act, NULL); + ASSERT( rc == 0 ); + + rc = kill(getpid(),SIGSTOP); + ASSERT(rc==0); + + // + // parents exit SIGCONTs child. At this point child + // is part of an orphaned process group. The process + // should not stop in response to SIGTSTP, SIGTTIN, + // or SIGTTOU + // + + rc = kill(getpid(),SIGTSTP); + ASSERT(rc==0); + + rc = kill(getpid(),SIGTTIN); + ASSERT(rc==0); + + rc = kill(getpid(),SIGTTOU); + ASSERT(rc==0); + + _exit(8); + + } + + rc = waitpid(child,&stat_loc,WUNTRACED); + ASSERT(rc == child && WIFSTOPPED(stat_loc) && WSTOPSIG(stat_loc) == SIGSTOP); + + // + // Conditions are set. If this process exits, then its group + // will zombie. Stopped process should continue w/ SIGCONT/SIGHUP + // + + _exit(123); + + } + + rc = wait(&stat_loc); + ASSERT(WIFEXITED(stat_loc) && WEXITSTATUS(stat_loc) == 123); + sleep(10); + + DbgPrint("jc3:--\n"); +} diff --git a/private/posix/client/tst/tstloop.c b/private/posix/client/tst/tstloop.c new file mode 100644 index 000000000..7c26b6ca2 --- /dev/null +++ b/private/posix/client/tst/tstloop.c @@ -0,0 +1,83 @@ +#include +#include + +#include "psxmsg.h" +#include +#include +#include +#include + +#include "tsttmp.h" // defines DbgPrint as printf + +extern int errno; + +void +_CRTAPI1 +catcher( + IN int sig + ); + +int caught_sig; + +int +_CRTAPI1 +main(int argc, char *argv[]) +{ + LONG i; + int e; + struct sigaction act, oact; + sigset_t eset,fset; + pid_t pid; + LARGE_INTEGER DelayTime; + + pid = getpid(); + + DbgPrint("Looper Posix Process... Pid = %lx\n\n",pid); + + DbgPrint("Looper Delay\n"); + DelayTime.HighPart = -1; + DelayTime.LowPart = -100000; + NtDelayExecution(FALSE,&DelayTime); + DbgPrint("Looper Delay Done\n"); + + _exit(8); + + sigemptyset(&eset); + sigfillset(&fset); + sigdelset(&fset,SIGHUP); + + act.sa_handler = catcher; + sigfillset(&act.sa_mask); + act.sa_flags = 0; + + if (sigaction(SIGUSR1, &act ,&oact) ) { + DbgPrint("main: fail sigaction errno %lx\n",errno); + _exit(-1); + } + + for(i=1;i<0x100000;i++){ + if ( (i & 0xfff) == 0 ) DbgPrint("Looper: i == %lx\n",i); + if ( (i & 0x7fff) == 0) { + DbgPrint("Looper: calling sigprocmask i == %lx\n",i); + sigprocmask(SIG_SETMASK,&fset,NULL); + DbgPrint("Looper: calling sigsuspend i == %lx\n",i); + e = sigsuspend(&eset); + DbgPrint("Looper: returned from sigsuspend %lx errno %lx i %lx\n",e,errno,i); + } + } + + DbgPrint("Looper: Exiting...\n"); + + return 1; +} + + +void +_CRTAPI1 +catcher( + IN int sig + ) +{ + DbgPrint("Looper: In Catcher, signal == %lx\n",sig); + caught_sig = 1; +} diff --git a/private/posix/client/tst/tstmd.c b/private/posix/client/tst/tstmd.c new file mode 100644 index 000000000..727880c50 --- /dev/null +++ b/private/posix/client/tst/tstmd.c @@ -0,0 +1,54 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "tsttmp.h" // defines DbgPrint as printf + +extern int errno; +VOID mkdir0(char *); + + +int +_CRTAPI1 +main(int argc, char *argv[]) +{ + + if (argc != 2) { + DbgPrint("Usage: 'tstmkdir dirname'\n"); + return 1; + } + + mkdir0(argv[1]); + + return 1; +} + + +VOID +mkdir0(char *f) +{ + int rc; + + DbgPrint("mkdir0:++ %s\n",f); + + DbgPrint("creating directory %s\n", f); + rc = mkdir(f,0); + ASSERT(rc != -1); + + DbgPrint("attempting to recreate existing directory %s\n", f); + rc = mkdir(f,0); + ASSERT(rc == -1 && errno == EEXIST); + + DbgPrint("removing directory %s\n", f); + rc = rmdir(f); + ASSERT(rc != -1); + + DbgPrint("mkdir0:--\n"); +} diff --git a/private/posix/client/tst/tstmisc.c b/private/posix/client/tst/tstmisc.c new file mode 100644 index 000000000..2b70950c9 --- /dev/null +++ b/private/posix/client/tst/tstmisc.c @@ -0,0 +1,242 @@ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tsttmp.h" // defines DbgPrint as printf + +extern int errno; +VOID sysconf0(void); +VOID pathconf0(void); +VOID fpathconf0(void); +VOID uname0(void); +VOID time0(void); + +// +// 'tstmisc' +// tests sysconf(), pathconf(), fpathconf(), uname(), time(), times() +// The file /psx/test/conffile should exist +// + +int +_CRTAPI1 +main(int argc, char *argv[]) +{ + + if (argc != 1) { + DbgPrint("Usage: '%s'\n", argv[0]); + return 1; + } + sysconf0(); + pathconf0(); + fpathconf0(); + uname0(); + time0(); + + return 1; +} + + +VOID +sysconf0(void) +{ + BOOLEAN fail = FALSE; + + DbgPrint("sysconf0:++\n"); + if (sysconf(_SC_ARG_MAX) != ARG_MAX) { + DbgPrint("sysconf FAIL on ARG_MAX\n"); + fail = TRUE; + } + if (sysconf(_SC_CHILD_MAX) != CHILD_MAX) { + DbgPrint("sysconf FAIL on CHILD_MAX\n"); + fail = TRUE; + } + if (sysconf(_SC_CLK_TCK) != CLK_TCK) { + DbgPrint("sysconf FAIL on CLK_TCK\n"); + fail = TRUE; + } + if (sysconf(_SC_NGROUPS_MAX) != NGROUPS_MAX) { + DbgPrint("sysconf FAIL on NGROUPS_MAX\n"); + fail = TRUE; + } + if (sysconf(_SC_OPEN_MAX) != OPEN_MAX) { + DbgPrint("sysconf FAIL on OPEN_MAX\n"); + fail = TRUE; + } + if (sysconf(_SC_JOB_CONTROL) == 0L) + DbgPrint("sysconf JOB_CONTROL OFF\n"); + else + DbgPrint("sysconf JOB_CONTROL ON\n"); + if (sysconf(_SC_SAVED_IDS) == 0L) + DbgPrint("sysconf SAVED_IDS OFF\n"); + else + DbgPrint("sysconf SAVED_IDS ON\n"); + DbgPrint("sysconf VERSION = %d\n", sysconf(_SC_VERSION)); + + if (!fail) + DbgPrint("sysconf PASSED\n"); + DbgPrint("sysconf0:--\n"); +} + +VOID pathconf0(void) +{ + BOOLEAN fail = FALSE; + + DbgPrint("pathconf0:++\n"); + if (pathconf("/psx/test/conffile", _PC_LINK_MAX) != LINK_MAX) { + DbgPrint("pathconf FAIL on LINK_MAX\n"); + fail = TRUE; + } + if (pathconf("/psx/test/conffile", _PC_MAX_CANON) != MAX_CANON) { + DbgPrint("pathconf FAIL on MAX_CANON\n"); + fail = TRUE; + } + if (pathconf("/psx/test/conffile", _PC_MAX_INPUT) != MAX_INPUT) { + DbgPrint("pathconf FAIL on MAX_INPUT\n"); + fail = TRUE; + } + if (pathconf("/psx/test/conffile", _PC_NAME_MAX) != NAME_MAX) { + DbgPrint("pathconf FAIL on NAME_MAX\n"); + fail = TRUE; + } + if (pathconf("/psx/test/conffile", _PC_PATH_MAX) != PATH_MAX) { + DbgPrint("pathconf FAIL on PATH_MAX\n"); + fail = TRUE; + } + if (pathconf("/psx/test/conffile", _PC_PIPE_BUF) != PIPE_BUF) { + DbgPrint("pathconf FAIL on PIPE_BUF\n"); + fail = TRUE; + } + if (pathconf("/psx/test/conffile", _PC_CHOWN_RESTRICTED) == 0L) + DbgPrint("pathconf CHOWN_RESTRICTED OFF\n"); + else + DbgPrint("pathconf CHOWN_RESTRICTED ON\n"); + if (pathconf("/psx/test/conffile", _PC_NO_TRUNC) == 0L) + DbgPrint("pathconf NO_TRUNC OFF\n"); + else + DbgPrint("pathconf NO_TRUNC ON\n"); + if (pathconf("/psx/test/conffile", _PC_VDISABLE) == 0L) + DbgPrint("pathconf VDISABLE OFF\n"); + else + DbgPrint("pathconf VDISABLE ON\n"); + + if (!fail) + DbgPrint("pathconf PASSED\n"); + DbgPrint("pathconf0:--\n"); +} + +VOID fpathconf0(void) +{ + BOOLEAN fail = FALSE; + int fd; + + DbgPrint("fpathconf0:++\n"); + + if ( (fd = open("/psx/test/conffile", O_RDONLY)) == -1) { + DbgPrint("Cannot open /psx/test/conffile\n"); + return; + } + + if (fpathconf(fd, _PC_LINK_MAX) != LINK_MAX) { + DbgPrint("fpathconf FAIL on LINK_MAX\n"); + fail = TRUE; + } + if (fpathconf(fd, _PC_MAX_CANON) != MAX_CANON) { + DbgPrint("fpathconf FAIL on MAX_CANON\n"); + fail = TRUE; + } + if (fpathconf(fd, _PC_MAX_INPUT) != MAX_INPUT) { + DbgPrint("fpathconf FAIL on MAX_INPUT\n"); + fail = TRUE; + } + if (fpathconf(fd, _PC_NAME_MAX) != NAME_MAX) { + DbgPrint("fpathconf FAIL on NAME_MAX\n"); + fail = TRUE; + } + if (fpathconf(fd, _PC_PATH_MAX) != PATH_MAX) { + DbgPrint("fpathconf FAIL on PATH_MAX\n"); + fail = TRUE; + } + if (fpathconf(fd, _PC_PIPE_BUF) != PIPE_BUF) { + DbgPrint("fpathconf FAIL on PIPE_BUF\n"); + fail = TRUE; + } + if (fpathconf(fd, _PC_CHOWN_RESTRICTED) == 0L) + DbgPrint("fpathconf CHOWN_RESTRICTED OFF\n"); + else + DbgPrint("fpathconf CHOWN_RESTRICTED ON\n"); + if (fpathconf(fd, _PC_NO_TRUNC) == 0L) + DbgPrint("fpathconf NO_TRUNC OFF\n"); + else + DbgPrint("fpathconf NO_TRUNC ON\n"); + if (fpathconf(fd, _PC_VDISABLE) == 0L) + DbgPrint("fpathconf VDISABLE OFF\n"); + else + DbgPrint("fpathconf VDISABLE ON\n"); + + if (!fail) + DbgPrint("fpathconf PASSED\n"); + DbgPrint("fpathconf0:--\n"); +} + +VOID uname0(void) +{ + struct utsname name; + int rc; + + DbgPrint("uname0:++\n"); + + rc = uname((struct utsname *) &name); + if (rc == -1) { + DbgPrint("FAIL call to uname, errno = %d.\n", errno); + } + else { + DbgPrint("sysname = %s\nnodename = %s(should be null)\nrelease = %s\nversion = %s\nmachine = %s\n", + name.sysname, name.nodename, name.release, name.version, + name.machine); + } + + DbgPrint("uname0:--\n"); +} + +// This should translate to yy mm dd format + +VOID time0(void) +{ + time_t tloc; + time_t rc; + + DbgPrint("time0:++\n"); + + rc = time((time_t *) &tloc); + + ASSERT(rc == tloc); + DbgPrint("Seconds since the Epoch = %ld\n", tloc); + + DbgPrint("time0:--\n"); + +} + +VOID time1(void) +{ + struct tms tbuf; + clock_t rc; + + DbgPrint("time1:++\n"); + + rc = times((struct tms *) &tbuf); + + DbgPrint("stime = %ld, utime = %ld, cstime = %ld, cutime = %ld rc = %ld\n", + tbuf.tms_stime, tbuf.tms_utime,tbuf.tms_cstime,tbuf.tms_cutime,rc); + + DbgPrint("time1:--\n"); +} diff --git a/private/posix/client/tst/tstncall.c b/private/posix/client/tst/tstncall.c new file mode 100644 index 000000000..1444cef36 --- /dev/null +++ b/private/posix/client/tst/tstncall.c @@ -0,0 +1,55 @@ +#include +#include + +#include "psxmsg.h" +#include +#include +#include +#include +#include + +#include "tsttmp.h" // defines DbgPrint as printf + +#define MEM_CTL 0xb0000000 + +int main(int argc, char *argv[]) +{ + + call0(); + _exit(0); + return 1; + +} + +call0() +{ + LONG x,i,j; + ULONG begin,end; + ULONG ibegin,iend; + VOID PdxNullPosixApi(); + volatile PULONG MemCtl; + + MemCtl = (PULONG) MEM_CTL; + +#ifdef SIMULATOR + for(i=0;i<10;i++) { + begin = rnuminstr(); + ibegin = DbgQueryIoCounter(); + PdxNullPosixApi(); + iend = DbgQueryIoCounter(); + end = rnuminstr(); + + DbgPrint("Call Time 0x%lx dec %ld IO %ld\n", end - begin,end-begin, iend-ibegin); + } +#else + for(j=0;j<5;j++) { + DbgPrint("Starting 10000 Calls..."); + x = *MemCtl; + for(i=0;i<10000;i++) { + PdxNullPosixApi(); + } + x = *MemCtl; + DbgPrint("Complete\n"); + } +#endif // SIMULATOR +} diff --git a/private/posix/client/tst/tstnpipe.c b/private/posix/client/tst/tstnpipe.c new file mode 100644 index 000000000..711d4ffeb --- /dev/null +++ b/private/posix/client/tst/tstnpipe.c @@ -0,0 +1,420 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "tsttmp.h" // defines DbgPrint as printf + +extern int errno; +VOID npipe0(char *); +VOID npipe1(char *); +VOID npipe2(char *); +VOID npipe3(char *); +VOID npipe4(char *); +VOID npipe5(VOID); + +// +// 'tstnpipe named.pip'. +// +// The directory /psx/test is used as the base directory. The zero-length +// file named 'named.pip must exist in that directory. +// + +char +nulltouch(char *f) +{ + return 'a'; +} + + +int +main(int argc, char *argv[]) +{ + if (argc != 2) { + DbgPrint("Usage: 'tstnpipe named.pip'\n"); + return 1; + } + ASSERT(strcmp(argv[1],"named.pip") == 0); + + npipe0(argv[1]); + npipe1(argv[1]); + npipe2(argv[1]); + npipe3(argv[1]); + npipe4(argv[1]); + npipe5(); + + return 1; +} + +VOID +npipe0(char *f) +{ + int rc,wfd,rfd; + char buf[512]; + + DbgPrint("npipe0:++ %s\n",f); + nulltouch(f); + + // + // Open for read with NONBLOCK. Open should complete + // without delay. + // + + rfd = open(f, O_RDONLY | O_NONBLOCK); + ASSERT(rfd != -1); + + // + // Since there is no data in pipe, read should complete and + // return 0 as the byte count. + // + + rc = read(rfd,buf,512); + ASSERT(rc == 0); + + // + // Open for write with NONBLOCK. Should succeed + // + + wfd = open(f,O_WRONLY | O_NONBLOCK); + ASSERT(wfd != -1); + + rc = write(wfd,"Hello World\n",13); + ASSERT(rc == 13); + + rc = read(rfd,buf,512); + ASSERT(rc == 13 && (strcmp(buf,"Hello World\n") == 0 )); + + rc = close(rfd); + ASSERT(rc != -1); + + rc = close(wfd); + ASSERT(rc != -1); + + // + // Open for write with NONBLOCK. Should fail since read handle was + // closed. + // + + wfd = open(f,O_WRONLY | O_NONBLOCK); + ASSERT(wfd == -1 && errno == ENXIO); + + DbgPrint("npipe0:--\n"); +} + +VOID +npipe1(char *f) +{ + int rc,wfd,rfd,stat_loc; + pid_t child; + char buf[512]; + + DbgPrint("npipe1:++ %s\n",f); + + wfd = open("foobar.bad",O_WRONLY); + + nulltouch(f); + child = fork(); + nulltouch(f); + + // + // Make sure that in the simple case, + // the named pipe open protocol works + // + + if ( child == 0 ) { + + rfd = open(f,O_RDONLY); + ASSERT(rfd != -1); + + rc = read(rfd,buf,512); + ASSERT(rc == 13 && (strcmp(buf,"Hello World\n") == 0 )); + + _exit(rc); + } + + wfd = open(f,O_WRONLY); + ASSERT(wfd != -1); + + rc = write(wfd,"Hello World\n",13); + ASSERT(rc == 13); + + rc = waitpid(child,&stat_loc,0); + ASSERT(rc == child && WIFEXITED(stat_loc) && WEXITSTATUS(stat_loc) == 13); + + rc = close(wfd); + ASSERT(rc != -1); + + // + // Open for write with NONBLOCK. Should fail since read handle was + // closed by childs process exit. + // + + wfd = open(f,O_WRONLY | O_NONBLOCK); + ASSERT(wfd == -1 && errno == ENXIO); + + DbgPrint("npipe1:--\n"); +} + +VOID +npipe2(char *f) +{ + int rc,wfd,rfd,rfd2,stat_loc; + pid_t child1,child2; + char buf[512]; + + DbgPrint("npipe2:++ %s\n",f); + + nulltouch(f); + child1 = fork(); + nulltouch(f); + + // + // Make sure that if we have a case where two readers open the + // pipe, one writers open will catch them both + // + + if ( child1 == 0 ) { + + nulltouch(f); + child2 = fork(); + nulltouch(f); + + if ( child2 == 0 ) { + + rfd2 = open(f,O_RDONLY); + ASSERT(rfd != -1); + + rc = read(rfd2,buf,512); + ASSERT(rc == 13 && (strcmp(buf,"Hello World\n") == 0 )); + + _exit(rc); + } + + rfd = open(f,O_RDONLY); + ASSERT(rfd != -1); + + rc = waitpid(child2,&stat_loc,0); + ASSERT(rc == child2 && WIFEXITED(stat_loc) && WEXITSTATUS(stat_loc) == 13); + + _exit(WEXITSTATUS(stat_loc)); + } + + sleep(30); + + wfd = open(f,O_WRONLY); + ASSERT(wfd != -1); + + rc = write(wfd,"Hello World\n",13); + ASSERT(rc == 13); + + rc = waitpid(child1,&stat_loc,0); + ASSERT(rc == child1 && WIFEXITED(stat_loc) && WEXITSTATUS(stat_loc) == 13); + + rc = close(wfd); + ASSERT(rc != -1); + + // + // Open for write with NONBLOCK. Should fail since read handle was + // closed by childs process exit. + // + + wfd = open(f,O_WRONLY | O_NONBLOCK); + ASSERT(wfd == -1 && errno == ENXIO); + + DbgPrint("npipe2:--\n"); +} + +void +npipe3_handler( + IN int sig + ) +{ + int wfd; + + ASSERT(sig == SIGUSR1); + wfd = open("named.pip",O_WRONLY | O_NONBLOCK); + ASSERT(wfd == -1 && errno == ENXIO); + +} + +VOID +npipe3(char *f) +{ + int rc,wfd,rfd,stat_loc; + pid_t child; + struct sigaction act; + + DbgPrint("npipe3:++ %s\n",f); + + nulltouch(f); + child = fork(); + nulltouch(f); + + // + // While child is blocked in open, terminate him with a signal + // and make sure everything is ok. + // + + if ( child == 0 ) { + + rfd = open(f,O_RDONLY); + ASSERT(FALSE); + } + + sleep(20); + + rc = kill(child,SIGKILL); + ASSERT(rc==0); + + rc = waitpid(child,&stat_loc,0); + ASSERT(rc == child && WIFSIGNALED(stat_loc) && WTERMSIG(stat_loc) == SIGKILL); + + wfd = open(f,O_WRONLY | O_NONBLOCK); + ASSERT(wfd == -1 && errno == ENXIO); + + // + // Now Try again. This time send a signal that child catches. He should + // come back from his open with EINTR and the pipe should not be left + // open. + // + + nulltouch(f); + child = fork(); + nulltouch(f); + + // + // While child is blocked in open, terminate him with a signal + // and make sure everything is ok. + // + + act.sa_flags = 0; + sigfillset(&act.sa_mask); + act.sa_handler = npipe3_handler; + rc = sigaction(SIGUSR1, &act, NULL); + ASSERT( rc == 0 ); + + if ( child == 0 ) { + + rfd = open(f,O_RDONLY); + ASSERT(rfd == -1 && errno == EINTR); + + wfd = open(f,O_WRONLY | O_NONBLOCK); + ASSERT(wfd == -1 && errno == ENXIO); + + rc = kill(getpid(),SIGKILL); + ASSERT(FALSE); + + } + + sleep(20); + + rc = kill(child,SIGUSR1); + ASSERT(rc==0); + + rc = waitpid(child,&stat_loc,0); + ASSERT(rc == child && WIFSIGNALED(stat_loc) && WTERMSIG(stat_loc) == SIGKILL); + + wfd = open(f,O_WRONLY | O_NONBLOCK); + ASSERT(wfd == -1 && errno == ENXIO); + + DbgPrint("npipe3:--\n"); +} + +VOID +npipe4(char *f) +{ + int rc,rfd; + int fildes[2]; + off_t off; + + DbgPrint("npipe4:++ %s\n",f); + nulltouch(f); + + // + // Open for read with NONBLOCK. Open should complete + // without delay. + // + + rfd = open(f,O_RDONLY | O_NONBLOCK); + ASSERT(rfd != -1); + + // + // lseek on named pipe should fail + // + + off = (off_t) 1; + errno = 0; + + off = lseek(rfd,off,SEEK_SET); + ASSERT(off == -1 && errno == ESPIPE); + + rc = close(rfd); + ASSERT(rc != -1); + + rc = pipe(fildes); + ASSERT(rc == 0); + + // + // lseek on regular pipe should fail + // + + off = (off_t)11; + errno = 0; + + off = lseek(fildes[0],off,SEEK_SET); + ASSERT(off == -1 && errno == ESPIPE); + + off = 10; + errno = 0; + + off = lseek(fildes[1],off,SEEK_SET); + ASSERT(off == -1 && errno == ESPIPE); + + DbgPrint("npipe4:--\n"); +} + + +VOID +npipe5() +{ + int rc,rfd; + off_t off; + + DbgPrint("npipe5:++\n"); + + rc = mkfifo("xpipe.pip",0); + ASSERT(rc==0 || ( rc == -1 && errno == EEXIST ) ); + + if ( rc == -1 ) { + DbgPrint("npipe5: **** Warning Fifo Exists ****\n"); + } + + // + // Open for read with NONBLOCK. Open should complete + // without delay. + // + + rfd = open("xpipe.pip",O_RDONLY | O_NONBLOCK); + ASSERT(rfd != -1); + + // + // lseek on named pipe should fail + // + + off = 1; + errno = 0; + + off = lseek(rfd,off,SEEK_SET); + ASSERT(off == -1 && errno == ESPIPE); + + rc = close(rfd); + ASSERT(rc != -1); + + DbgPrint("npipe5:--\n"); +} diff --git a/private/posix/client/tst/tstrmdir.c b/private/posix/client/tst/tstrmdir.c new file mode 100644 index 000000000..f9614afb5 --- /dev/null +++ b/private/posix/client/tst/tstrmdir.c @@ -0,0 +1,91 @@ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "tsttmp.h" // defines DbgPrint as printf + +extern int errno; +VOID rmdir0(char *); + +// +// 'tstrmdir dirname'. +// +// The directory /psx/test is used as the base directory. It is assumed +// to have the following sub directories: +// rmtst1 containing one file "ab" +// rmtst2 containing one file ".a" (??) +// rmtst3 containing one file "a." +// rmtst4 containing one file "abcde" +// /psx/test must not have an existing subdirectory with the same name as +// the dir argument. +// + +int +main(int argc, char *argv[]) +{ + + if (argc != 2) { + DbgPrint("Usage: 'tstrmdir dirname'\n"); + return 1; + } + rmdir0(argv[1]); + + return 1; +} + + +VOID +rmdir0(char *f) +{ + int rc; + + DbgPrint("rmdir0:++ %s\n",f); + + DbgPrint("chdir to /psx/test\n"); + rc = chdir("/psx/test"); + ASSERT(rc != -1); + if (rc == -1) + DbgPrint("chdir errno = %d\n", errno); + // + // Test deleting an empty directory + // + DbgPrint("mkdir %s\n", f); + rc = mkdir(f, 0); + ASSERT(rc != -1); + if (rc == -1) + DbgPrint("mkdir errno = %d\n", errno); + + DbgPrint("Testing removal of empty directory %s\n", f); + rc = rmdir(f); + ASSERT(rc != -1); + if (rc == -1) + DbgPrint("rmdir errno = %d\n", errno); + + DbgPrint("Testing removal of nonexistent directory %s\n", f); + rc = rmdir(f); + ASSERT(rc == -1 && errno == ENOENT); + + DbgPrint("Testing removal of 'rmtst1' - with one entry 'ab'\n"); + rc = rmdir("rmtst1"); + ASSERT(rc == -1 && errno == ENOTEMPTY); + +// DbgPrint("Testing removal of 'rmtst2' with one entry '.a'\n"); +// rc = rmdir("rmtst2"); +// ASSERT(rc == -1 && errno == ENOTEMPTY); + + DbgPrint("Testing removal of 'rmtst3' with one entry 'a.'\n"); + rc = rmdir("rmtst3"); + ASSERT(rc == -1 && errno == ENOTEMPTY); + + DbgPrint("Testing removal of 'rmtst4' with one entry 'abcde' \n"); + rc = rmdir("rmtst4"); + ASSERT(rc == -1 && errno == ENOTEMPTY); + + DbgPrint("rmdir0:--\n"); +} diff --git a/private/posix/client/tst/tstsid.c b/private/posix/client/tst/tstsid.c new file mode 100644 index 000000000..9f2d2f3f6 --- /dev/null +++ b/private/posix/client/tst/tstsid.c @@ -0,0 +1,284 @@ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "tsttmp.h" // defines DbgPrint as printf + +extern int errno; + +VOID setsid0(VOID); +VOID setpgid0(VOID); +VOID kill0(VOID); +VOID waitpid0(VOID); + +int _CRTAPI1 main(int argc, char *argv[]) +{ + + pid_t self; + PCH p,t; + PTEB ThreadInfo; + + ThreadInfo = NtCurrentTeb(); + + self = getpid(); + + DbgPrint("setsidt: My pid is %lx Argc = %lx\n",self,argc); + DbgPrint("setsidt: StackBase %lx\n",ThreadInfo->NtTib.StackBase); + DbgPrint("setsidt: StackLimit %lx\n",ThreadInfo->NtTib.StackLimit); + DbgPrint("setsidt: ClientId %lx.%lx\n",ThreadInfo->ClientId.UniqueProcess,ThreadInfo->ClientId.UniqueThread); + + while(argc--){ + p = *argv++; + t = p; + while(*t++); + DbgPrint("Argv --> %s\n",p); + } + + setsid0(); + setpgid0(); + kill0(); + waitpid0(); + + return 1; +} + + +VOID +setsid0() +{ + pid_t pid, OrigGroup, NewGroup; + + DbgPrint("setsid0:++\n"); + + OrigGroup = getpgrp(); + + // + // Should be process group leader + // + + ASSERT(getpid() == OrigGroup); + + + NewGroup = setsid(); + + ASSERT(NewGroup == -1 && errno == EPERM); + + // + // Fork. Child then creates a new session id + // + + if ( !fork() ) { + + pid = getpid(); + + ASSERT(getpgrp() == OrigGroup); + + ASSERT(pid != OrigGroup); + + NewGroup = setsid(); + + ASSERT(NewGroup == pid); + + ASSERT(getpgrp() == pid); + + _exit(1); + + } + + wait(NULL); + + DbgPrint("setsid0:--\n"); +} + + +VOID +setpgid0() +{ + pid_t OrigGroup, child; + int rc; + + DbgPrint("setpgid0:++\n"); + + OrigGroup = getpgrp(); + + // + // Bad pid gives EINVAL + // + + rc = setpgid(-1,0); + + ASSERT(rc == -1 && errno == EINVAL); + + // + // Bogus pid gives ESRCH + // + + rc = setpgid(1,0); + + ASSERT(rc == -1 && errno == ESRCH); + + // + // Self (at this level gives EPERM because I am a session leader) + // + + rc = setpgid(0,0); + + ASSERT(rc == -1 && errno == EPERM); + + child = fork(); + + if ( !child) { + child = fork(); + if ( !child ) { + pause(); + } + + // + // Make sure child is not in same session as caller. Then try to + // set it's group id. + // + + setsid(); + rc = setpgid(child,0); + + ASSERT(rc == -1 && errno == EPERM); + + kill(child,SIGKILL); + wait(NULL); + _exit(2); + } + + wait(NULL); + + DbgPrint("setpgid0:--\n"); +} + + +VOID +kill0() +{ + pid_t parent, parentgroup, OrigGroup, child; + int rc; + + DbgPrint("kill0:++\n"); + + OrigGroup = getpgrp(); + + child = fork(); + + if ( !child) { + + // + // Change to a new process group + // + + rc = setpgid(0,0); + + ASSERT(rc == 0); + + child = fork(); + + + if ( !child ) { + + struct sigaction act; + + act.sa_handler = SIG_IGN; + + rc = sigaction(SIGHUP, &act, NULL); + + ASSERT( rc == 0 ); + + parentgroup = getpgrp(); + + // + // Change to a new process group + // + + rc = setpgid(0,0); + + ASSERT(rc == 0); + + // + // Kill Parent by process group + // + + parent = getppid(); + + rc = kill(-1 * parentgroup,SIGKILL); + + ASSERT(rc == 0 && getppid() != parent ); + + _exit(1); + } + + DbgPrint("kill0: Pid to die %lx Child (that will killed) %lx\n",getpid(),child); + + pause(); + } + + DbgPrint("kill0: Pid %lx Child (to be killed) %lx\n",getpid(),child); + + wait(NULL); + sleep(4); + + DbgPrint("kill0:--\n"); +} + +VOID +waitpid0() +{ + pid_t child; + int rc; + + DbgPrint("waitpid0:++\n"); + + // + // Test for existing group with no children + // + + rc = waitpid(0,NULL,0); + + ASSERT(rc == -1 && errno == ECHILD); + + // + // Test for non-existing group with no children + // + + rc = waitpid(0x12345678,NULL,0); + + ASSERT(rc == -1 && errno == ECHILD); + + // + // Test for bad options + // + + rc = waitpid(0,NULL,0x12345678); + + ASSERT(rc == -1 && errno == EINVAL); + + child = fork(); + + if ( !child) { + _exit(1); + } + sleep(5); + + // + // test for specific pid + // + + DbgPrint("waiting on %lx\n",child); + + rc = waitpid(child,NULL,0); + + ASSERT(rc == child); + + DbgPrint("waitpid0:--\n"); +} diff --git a/private/posix/client/tst/tstsig.c b/private/posix/client/tst/tstsig.c new file mode 100644 index 000000000..44b066456 --- /dev/null +++ b/private/posix/client/tst/tstsig.c @@ -0,0 +1,120 @@ +#include +#include + +#include "psxmsg.h" +#include +#include +#include +#include +#include + +#include "tsttmp.h" // defines DbgPrint as printf + +extern int errno; + +void +_CRTAPI1 +catcher( + IN int sig + ); + +int caught_sig; + +int +_CRTAPI1 +main(int argc, char *argv[]) +{ + + pid_t pid,cpid; + ULONG status; + LARGE_INTEGER DelayTime; +#ifdef longtest + LONG i; + struct sigaction act, oact; + ULONG begin,end; +#endif + + pid = getpid(); + + DbgPrint("Posix Process... Pid = %lx\n\n",pid); + + DelayTime.HighPart = -1; + DelayTime.LowPart = -500000; + DbgPrint("Delay\n"); + NtDelayExecution(FALSE,&DelayTime); + DbgPrint("Delay Done\n"); + + cpid = wait(&status); + + DbgPrint("hellol: wait for %lx satisfied... status %lx errno %lx\n", + cpid, + status, + errno + ); + + DbgPrint("hellol: waiting again. Should get ECHILD\n"); + + cpid = wait(&status); + + DbgPrint("hellol: wait for %lx satisfied... status %lx errno %lx\n", + cpid, + status, + errno + ); + return 0; + +#ifdef longtest + + // + // try to catch SIGKILL + // + + act.sa_handler = catcher; + sigfillset(&act.sa_mask); + act.sa_flags = 0; + + if (sigaction(SIGUSR1, &act ,&oact) ) { + DbgPrint("main: fail sigaction errno %lx\n",errno); + _exit(-1); + } + + DbgPrint("hellol: killing self\n"); + caught_sig = 0; + i = kill(pid,SIGUSR1); + if ( !caught_sig ) { + DbgPrint("Error kill returned before signal handler executed\n"); + } + DbgPrint("back from kill %lx\n",i); + + DbgPrint("hellol: killing looper\n"); + i = kill(0x00010001,SIGUSR1); + DbgPrint("back from kill %lx\n",i); + + for(i=0;i<7;i++) { + begin = rnuminstr(); + __NullPosixApi(); + end = rnuminstr(); + + DbgPrint("Call Time bg %lx end %lx totals 0x%lx %ld \n",begin, end, end - begin,end - begin); + } + + DbgPrint("hellol: killing looper again. Should be paused\n"); + i = kill(0x00010001,SIGUSR1); + DbgPrint("back from kill %lx\n",i); + + DbgPrint("Exiting...\n"); + + _exit(1); +#endif +} + + +void +_CRTAPI1 +catcher( + IN int sig + ) +{ + DbgPrint("In Catcher, signal == %lx\n",sig); + caught_sig = 1; +} diff --git a/private/posix/client/tst/tstsum.c b/private/posix/client/tst/tstsum.c new file mode 100644 index 000000000..13a54c1c3 --- /dev/null +++ b/private/posix/client/tst/tstsum.c @@ -0,0 +1,138 @@ + +#include +#include +#include +#include + +// +// 'tstsum.c' +// Largest sum of a subarray +// +// 05/14/92 DarekM created +// + +int +main(int argc, char *argv[]) +{ + Randomize(); + + n1(); Results(1); + n2(); Results(2); + n3(); Results(3); + printf("\n\n"); + return 1; +} + +#define NUM_NUMS 20 + +int x[NUM_NUMS]; + +int sLargest; /* largest sum */ +int iLargest; /* index of subarray */ +int cLargest; /* size of subarray */ + +Randomize() +{ + int i; + int s; + + s = getpid(); + + printf("\n"); + for (i=0; i < NUM_NUMS; i++) + { + s = (s * 89 + 13) % 47; /* generate random numbers around -25 to 25 */ + x[i] = s - 25; + printf("Num[%02d] = %+d\n", i, x[i]); + } + + printf("\n"); +} + + +FindLargest(s, i, c) +int s, i, c; +{ + /* takes the gives sum, index, and count of a subarray and + * if it is a largest sum so far keep track of it. + */ + + if ((s > sLargest) || ((s == sLargest) && (c < cLargest))) + { + sLargest = s; + iLargest = i; + cLargest = c; + } +} + +Results(o) +int o; +{ + printf("O(%d): Largest subarray is Num[%d..%d] with a sum of %d\n", + o, iLargest, iLargest+cLargest-1, sLargest); +} + +n1() +{ + int i, c, s; + + sLargest = -999; + + s = c = 0; + + for (i = 0; i < NUM_NUMS; i++) + { + if (s + x[i] < 0) + { + s = c = 0; + continue; + } + + s += x[i]; + c++; + + FindLargest(s, i-c+1, c); + } +} + + +n2() +{ + int i, c, s; + + sLargest = -999; + + for (i = 0; i < NUM_NUMS; i++) + { + s = 0; + + for (c = 1; c <= (NUM_NUMS-i); c++) + { + s += x[i+c-1]; + + FindLargest(s, i, c); + } + } +} + + +n3() +{ + int i, c, s, j; + + sLargest = -999; + + for (i = 0; i < NUM_NUMS; i++) + { + for (c = 1; c <= (NUM_NUMS-i); c++) + { + s = 0; + + for (j = i; j < (i+c); j++) + s += x[j]; + + FindLargest(s, i, c); + } + } +} + diff --git a/private/posix/client/tst/tsttime.c b/private/posix/client/tst/tsttime.c new file mode 100644 index 000000000..0f9ed5e3b --- /dev/null +++ b/private/posix/client/tst/tsttime.c @@ -0,0 +1,40 @@ + +#include +#include +#include +#include + +// +// 'tsttime.c' +// Time function sanity check. +// +// 06/10/92 DarekM Created +// + +time_t loc_time; +time_t gm_time; + +int +main(int argc, char *argv[]) +{ + int i; // this is to introduce some time delays + + for (i=0; i<20000; i++) + loc_time = time(NULL); + printf("Local Time #1 = %d, %s\n", loc_time, asctime(localtime(&loc_time))); + + for (i=0; i<20000; i++) + time(&loc_time); + printf("Local Time #2 = %d, %s\n", loc_time, asctime(localtime(&loc_time))); + + for (i=0; i<20000; i++) + time(&gm_time); + printf("GMT Time = %d, %s\n", loc_time, asctime(gmtime(&gm_time))); + + printf("Elapsed time = %d ms\n", clock()); + + printf("\n\n"); + return 1; +} + + diff --git a/private/posix/client/tst/tsttmp.h b/private/posix/client/tst/tsttmp.h new file mode 100644 index 000000000..e1a36456c --- /dev/null +++ b/private/posix/client/tst/tsttmp.h @@ -0,0 +1,5 @@ +#ifdef PSX_IN_WIN + +#define DbgPrint printf + +#endif diff --git a/private/posix/client/tst/tstumask.c b/private/posix/client/tst/tstumask.c new file mode 100644 index 000000000..2e185ee0e --- /dev/null +++ b/private/posix/client/tst/tstumask.c @@ -0,0 +1,68 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "tsttmp.h" // defines DbgPrint as printf + +extern int errno; +VOID umask0(void); + +// +// 'tstumask' +// + +int +_CRTAPI1 +main(int argc, char *argv[]) +{ + + if (argc != 1) { + DbgPrint("Usage: '%s'\n", argv[0]); + return 1; + } + umask0(); + + return 1; +} + + +VOID +umask0(void) +{ + mode_t oldmask, savemask; + + DbgPrint("umask0:++\n"); + + oldmask = umask(S_IRWXU); + savemask = oldmask; + oldmask = umask(S_IRWXG); + if ((oldmask & S_IRWXU) != S_IRWXU) { + DbgPrint("FAIL on S_IRWXU\n"); + return; + } + oldmask = umask(S_IRWXO); + if ((oldmask & S_IRWXG) != S_IRWXG) { + DbgPrint("FAIL on S_IRWXG\n"); + return; + } + oldmask = umask((mode_t) 0L); + if ((oldmask & S_IRWXO) != S_IRWXO) { + DbgPrint("FAIL on S_IRWXO\n"); + return; + } + oldmask = umask(savemask); + if ( (oldmask & _S_PROT) != (mode_t) 0L) { + DbgPrint("FAIL on 0 perm\n"); + return; + } + DbgPrint("PASSED\n"); + + DbgPrint("umask0:--\n"); +} -- cgit v1.2.3