summaryrefslogtreecommitdiffstats
path: root/private/posix/client
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/posix/client/alpha/psxthunk.s149
-rw-r--r--private/posix/client/alpha/sources1
-rw-r--r--private/posix/client/buildtst.cmd3
-rw-r--r--private/posix/client/coninit.c125
-rw-r--r--private/posix/client/conreqst.c56
-rw-r--r--private/posix/client/crtsup.c233
-rw-r--r--private/posix/client/dllext.c88
-rw-r--r--private/posix/client/dllfile.c1011
-rw-r--r--private/posix/client/dllinit.c377
-rw-r--r--private/posix/client/dllio.c694
-rw-r--r--private/posix/client/dllname.c310
-rw-r--r--private/posix/client/dllproc.c1251
-rw-r--r--private/posix/client/dllreg.c173
-rw-r--r--private/posix/client/dllsig.c438
-rw-r--r--private/posix/client/dlltc.c293
-rw-r--r--private/posix/client/dlltimer.c243
-rw-r--r--private/posix/client/i386/psxthunk.asm60
-rw-r--r--private/posix/client/i386/sources1
-rw-r--r--private/posix/client/makefile6
-rw-r--r--private/posix/client/makefile.inc2
-rw-r--r--private/posix/client/mips/psxthunk.s147
-rw-r--r--private/posix/client/mips/sources1
-rw-r--r--private/posix/client/ppc/psxthunk.s185
-rw-r--r--private/posix/client/ppc/sources1
-rw-r--r--private/posix/client/psxdll.h176
-rw-r--r--private/posix/client/psxdll.rc11
-rw-r--r--private/posix/client/psxdll.src151
-rw-r--r--private/posix/client/sources64
-rw-r--r--private/posix/client/stubs.c195
-rw-r--r--private/posix/client/sysdb.c304
-rw-r--r--private/posix/client/tst/tstdir.c308
-rw-r--r--private/posix/client/tst/tstexec.c68
-rw-r--r--private/posix/client/tst/tstfile.c252
-rw-r--r--private/posix/client/tst/tstfork.c598
-rw-r--r--private/posix/client/tst/tstheap.c111
-rw-r--r--private/posix/client/tst/tsthello.c38
-rw-r--r--private/posix/client/tst/tsthw.c20
-rw-r--r--private/posix/client/tst/tstjc.c367
-rw-r--r--private/posix/client/tst/tstloop.c83
-rw-r--r--private/posix/client/tst/tstmd.c54
-rw-r--r--private/posix/client/tst/tstmisc.c242
-rw-r--r--private/posix/client/tst/tstncall.c55
-rw-r--r--private/posix/client/tst/tstnpipe.c420
-rw-r--r--private/posix/client/tst/tstrmdir.c91
-rw-r--r--private/posix/client/tst/tstsid.c284
-rw-r--r--private/posix/client/tst/tstsig.c120
-rw-r--r--private/posix/client/tst/tstsum.c138
-rw-r--r--private/posix/client/tst/tsttime.c40
-rw-r--r--private/posix/client/tst/tsttmp.h5
-rw-r--r--private/posix/client/tst/tstumask.c68
50 files changed, 10111 insertions, 0 deletions
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 <stdio.h>
+#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 <stdio.h>
+#include <fcntl.h>
+#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 <unistd.h>
+#include <sys/stat.h>
+#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 <nt.h>
+#include <ntrtl.h>
+#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 <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#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 <sys\utsname.h>
+#include <unistd.h>
+#include <time.h>
+#include <string.h>
+#include <stdarg.h>
+
+#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
+ // <argv strings>
+ // <environ strings>
+ //
+ // 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 <sys\utsname.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdarg.h>
+#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 <excpt.h>
+
+#define _SIGNULLSET 0x0
+#define _SIGFULLSET 0x7ffff // ((1<<SIGTTOU) - 1)
+
+int
+_CRTAPI1
+sigemptyset(sigset_t *set)
+{
+ int r = 0;
+try {
+ *set = _SIGNULLSET;
+} except (EXCEPTION_EXECUTE_HANDLER) {
+ KdPrint(("PSXDLL: error in sigemptyset\n"));
+ KdPrint(("PSXDLL: set is 0x%x\n", set));
+ KdPrint(("PSXDLL: exception code 0x%x\n", GetExceptionCode()));
+}
+ return r;
+}
+
+int
+_CRTAPI1
+sigfillset(sigset_t *set)
+{
+ int r = 0;
+
+ try {
+ *set = _SIGFULLSET;
+ } except (EXCEPTION_EXECUTE_HANDLER) {
+ errno = EFAULT;
+ r = -1;
+ }
+ return r;
+}
+
+int _CRTAPI1
+sigaddset(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
+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 <termios.h>
+#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 <signal.h>
+
+
+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 <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <excpt.h>
+#include <sys\types.h>
+#include <string.h>
+#include <limits.h>
+#include <signal.h>
+#include <errno.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys\stat.h>
+#include <sys\wait.h>
+#include <ntsm.h>
+#include <unistd.h>
+#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 <windows.h>
+
+#include <ntverp.h>
+
+#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 <unistd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <setjmpex.h>
+#include <termios.h>
+#include <sys/stat.h>
+#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 <unistd.h>
+#include <pwd.h>
+#include <grp.h>
+#include <stdio.h>
+#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 <nt.h>
+#include <ntrtl.h>
+
+#include <string.h>
+#include <signal.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <fcntl.h>
+
+#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 <nt.h>
+#include <ntrtl.h>
+
+#include <string.h>
+#include <stdio.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <fcntl.h>
+
+#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 <nt.h>
+#include <ntrtl.h>
+
+#include <signal.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#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 <nt.h>
+#include <ntrtl.h>
+
+#include "psxmsg.h"
+#include <signal.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <sys/times.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#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<psxst;i++){
+ if ( buf[i] != buffer[i] ) {
+ DbgPrint("p0: Compare failed. i %lx master %lx vs. %lx\n",i,buf[i],buffer[i]);
+ }
+ }
+
+ 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<psxst;i++){
+ if ( buf[i] != buffer[i] ) {
+ DbgPrint("p0: Compare failed. i %lx master %lx vs. %lx\n",i,buf[i],buffer[i]);
+ }
+ }
+ wait(NULL);
+
+ close(fildes[0]);
+ close(fildes[1]);
+
+ DbgPrint("p0:--\n");
+
+}
+
+VOID
+p1()
+{
+ 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("p1:++\n");
+
+ //
+ // Create a pipe
+ //
+
+ psxst = pipe(fildes);
+
+ if ( psxst ) {
+ DbgPrint("p1: pipe() failed st = %lx errno %lx\n",psxst,errno);
+ return;
+ }
+
+ DbgPrint("p1: fildes[0] = %lx filedes[1] = %lx\n",fildes[0],fildes[1]);
+
+ //
+ // Test write to readonly fd
+ //
+
+ psxst = write(fildes[0],"Hello World\n",13);
+ if ( psxst < 0 ) {
+ DbgPrint("p1: write test NT_SUCCESS %lx errno %lx\n",psxst,errno);
+ }
+
+ //
+ // Test read to writeonly fd
+ //
+
+ psxst = read(fildes[1],buf,13);
+ if ( psxst < 0 ) {
+ DbgPrint("p1: read test NT_SUCCESS %lx errno %lx\n",psxst,errno);
+ }
+
+
+ //
+ // Close Write Handle
+ //
+
+ close(fildes[1]);
+
+ //
+ // Test read w/ no writers
+ //
+
+ psxst = read(fildes[0],buffer,32);
+ if ( psxst == 0 ) {
+ DbgPrint("p1: read test NT_SUCCESS %lx\n",psxst);
+ }
+
+ close(fildes[0]);
+
+ DbgPrint("p1:--\n");
+
+}
+
+VOID
+ex0()
+{
+ PCH Arg[3], Env[4];
+ struct tms TimeBuffer;
+ clock_t TimesRtn;
+ int fildes[2];
+ int rc;
+
+ DbgPrint("ex0:++\n");
+
+ rc = pipe(fildes);
+ ASSERT(rc==0 && fildes[0] == 0 && fildes[1] == 1);
+
+ if ( !fork() ) {
+
+ if ( !fork() ) {
+
+ Arg[0]="tsthello.n10";
+ Arg[1]=(PCH)NULL;
+ Env[0]="NTUSER=MARKL";
+ Env[1]=(PCH)NULL;
+
+ //
+ // We should not have any accumulated child times
+ //
+
+ TimesRtn = times(&TimeBuffer);
+ ASSERT(TimesRtn != 0);
+ ASSERT(TimeBuffer.tms_cstime == 0 && TimeBuffer.tms_cutime == 0);
+
+ write(1,&TimeBuffer,sizeof(TimeBuffer));
+ execve("\\DosDevices\\D:\\PSX\\TSTHELLO.exe",Arg,Env);
+
+ DbgPrint("ex0:child returned from exec ? errno %lx\n",errno);
+
+ _exit(1);
+ }
+
+ wait(NULL);
+
+ //
+ // We should not have any accumulated child times
+ //
+
+ TimesRtn = times(&TimeBuffer);
+ ASSERT(TimesRtn != 0);
+ DbgPrint("tms_cstime %lx tms_cutime %lx\n",TimeBuffer.tms_cstime,TimeBuffer.tms_cutime);
+ ASSERT(TimeBuffer.tms_cstime != 0 || TimeBuffer.tms_cutime != 0);
+
+ _exit(2);
+ }
+
+ wait(NULL);
+
+ DbgPrint("ex0:parent wait satisfied \n");
+
+ close(fildes[0]);
+ close(fildes[1]);
+
+ DbgPrint("ex0:--\n");
+
+}
+
+VOID
+call0()
+{
+ VOID PdxNullPosixApi();
+
+#ifdef SIMULATOR
+ for(i=0;i<10;i++) {
+ begin = rnuminstr();
+ PdxNullPosixApi();
+ end = rnuminstr();
+
+ DbgPrint("Call Time 0x%lx 0x%lx 0x%lx dec %ld\n",begin, end, end - begin,end-begin);
+ }
+#endif // SIMULATOR
+
+}
+
+VOID
+f1()
+{
+ pid_t child,wchild;
+
+ DbgPrint("f1:+++\n");
+
+ child = fork();
+
+ if ( child == 0 ) {
+ DbgPrint("tstfork_child: I am the child %lx\n",getpid());
+ _exit(1);
+ }
+
+ DbgPrint("tstfork_parent: My child is %lx\n",child);
+
+ wchild = wait(NULL);
+
+ DbgPrint("tstfork_parent: Wait on child %lx satisfied %lx errno %lx\n",
+ child,
+ wchild,
+ errno
+ );
+ DbgPrint("f1:---\n");
+}
+
+void
+_CRTAPI1
+f2catcher(
+ IN int sig
+ )
+{
+ DbgPrint("f2catcher, signal == %lx\n",sig);
+}
+
+VOID
+f2()
+{
+ struct sigaction act, oact;
+ pid_t child,wchild,parent;
+ int psxst;
+
+
+ //
+ // Send signal to parent which sould be in wait. Parent should
+ // get EINTR from wait. If it retries, then wait will succeed.
+ //
+
+ DbgPrint("f2:+++\n");
+
+ act.sa_handler = f2catcher;
+ sigfillset(&act.sa_mask);
+ act.sa_flags = 0;
+
+ if (sigaction(SIGUSR1, &act ,&oact) ) {
+ DbgPrint("f2: fail sigaction errno %lx\n",errno);
+ _exit(-1);
+ }
+
+ child = fork();
+ if( !child ) {
+
+ DbgPrint("tstfork_child: I am the child %lx parent %lx\n",
+ getpid(),
+ (parent = getppid())
+ );
+
+ DbgPrint("tstfork_child: Killing SIGUSR1 parent %lx\n",parent);
+
+ psxst = kill(parent,SIGUSR1);
+
+ if ( psxst < 0 ) {
+ DbgPrint("tstfork_child: kill failed %lx errno %lx\n",psxst,errno);
+ _exit(errno);
+ }
+
+ _exit(1);
+ }
+
+ DbgPrint("tstfork_parent: My child is %lx\n",child);
+
+ wchild = wait(NULL);
+
+ DbgPrint("tstfork_parent: Wait on child %lx satisfied %lx errno %lx\n",
+ child,
+ wchild,
+ errno
+ );
+
+ if ( wchild < 0 && errno == EINTR ) {
+ DbgPrint("tstfork_parent: wait interrupted by SIGUSR1. Rewait\n");
+
+ wchild = wait(NULL);
+
+ DbgPrint("tstfork_parent: Wait on child %lx satisfied %lx errno %lx\n",
+ child,
+ wchild,
+ errno
+ );
+ }
+
+ DbgPrint("f2:---\n");
+}
+
+void
+_CRTAPI1
+a0catcher(
+ IN int sig
+ )
+{
+ DbgPrint("a0catcher, signal == %lx long jumping...\n",sig);
+ NtContinue(&a0JumpBuff,FALSE);
+}
+
+VOID
+a0()
+{
+ struct sigaction act, oact;
+ unsigned int previous;
+ NTSTATUS st;
+ sigset_t eset;
+
+ //
+ // Call alarm and then sit in a loop
+ //
+
+ DbgPrint("a0:+++\n");
+
+ act.sa_handler = a0catcher;
+ sigfillset(&act.sa_mask);
+ act.sa_flags = 0;
+
+ if (sigaction(SIGALRM, &act ,&oact) ) {
+ DbgPrint("a0: fail sigaction errno %lx\n",errno);
+ _exit(-1);
+ }
+
+ a0JumpBuff.ContextFlags = CONTEXT_FULL;
+
+ st = NtGetContextThread(NtCurrentThread(),&a0JumpBuff);
+
+#ifdef MIPS
+ a0JumpBuff.IntV0 = 0x12345678;
+#endif
+
+#ifdef i386
+ a0JumpBuff.Eax = 0x12345678;
+#endif
+
+ if (st == STATUS_SUCCESS) {
+ previous = alarm(2);
+ for(;;);
+ }
+
+ sigemptyset(&eset);
+ sigprocmask(SIG_SETMASK,&eset,NULL);
+
+ DbgPrint("a0: Longjumpp st = %lx\n",st);
+
+ //
+ // start a 10 second alarm and then cancel it
+ //
+
+ a0JumpBuff.ContextFlags = CONTEXT_FULL;
+
+ st = NtGetContextThread(NtCurrentThread(),&a0JumpBuff);
+
+#ifdef MIPS
+ a0JumpBuff.IntV0 = 0x12345678;
+#endif
+
+#ifdef i386
+ a0JumpBuff.Eax = 0x12345678;
+#endif
+
+ if (st == STATUS_SUCCESS) {
+ previous = alarm(10);
+ sleep(1);
+ previous = alarm(0);
+ DbgPrint("Previous = %lx\n",previous);
+ }
+
+ sigemptyset(&eset);
+ sigprocmask(SIG_SETMASK,&eset,NULL);
+
+ DbgPrint("a0:---\n");
+}
+
+VOID
+s0()
+{
+
+ LARGE_INTEGER BeginTime,EndTime;
+ unsigned int psxst;
+
+ DbgPrint("s0:+++\n");
+
+ NtQuerySystemTime(&BeginTime);
+
+ DbgPrint("s0: sleeping\n");
+
+ psxst = sleep(1);
+
+ NtQuerySystemTime(&EndTime);
+
+ DbgPrint("s0: sleep(1) returned %lx\n",psxst);
+ DbgPrint("s0: BeginTime %lx %lx\n",BeginTime.HighPart,BeginTime.LowPart);
+ DbgPrint("s0: EndTime %lx %lx\n",EndTime.HighPart,EndTime.LowPart);
+
+ DbgPrint("s0:---\n");
+
+}
diff --git a/private/posix/client/tst/tstheap.c b/private/posix/client/tst/tstheap.c
new file mode 100644
index 000000000..5752dbd64
--- /dev/null
+++ b/private/posix/client/tst/tstheap.c
@@ -0,0 +1,111 @@
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <malloc.h>
+
+//
+// '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 <numblocks> <delta> [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 <nt.h>
+#include <ntrtl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/times.h>
+
+#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 <nt.h>
+#include <ntrtl.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#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 <nt.h>
+#include <ntrtl.h>
+
+#include <signal.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#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 <nt.h>
+#include <ntrtl.h>
+
+#include "psxmsg.h"
+#include <unistd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <errno.h>
+
+#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 <nt.h>
+#include <ntrtl.h>
+
+#include <signal.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#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 <nt.h>
+#include <ntrtl.h>
+
+#include <signal.h>
+#include <errno.h>
+#include <unistd.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/wait.h>
+#include <sys/utsname.h>
+#include <sys/times.h>
+
+#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 <nt.h>
+#include <ntrtl.h>
+
+#include "psxmsg.h"
+#include <signal.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#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 <nt.h>
+#include <ntrtl.h>
+
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#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 <nt.h>
+#include <ntrtl.h>
+
+#include <signal.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#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 <nt.h>
+#include <ntrtl.h>
+
+#include <signal.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#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 <nt.h>
+#include <ntrtl.h>
+
+#include "psxmsg.h"
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <stdio.h>
+
+#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 <nt.h>
+#include <ntrtl.h>
+#include <unistd.h>
+#include <stdio.h>
+
+//
+// '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 <unistd.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <time.h>
+
+//
+// '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 <nt.h>
+#include <ntrtl.h>
+
+#include <signal.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#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");
+}