/*++ Copyright (c) 1989 Microsoft Corporation Module Name: dllio.c Abstract: Client implementation of Input and Output Primitives for POSIX Author: Mark Lucovsky 21-Feb-1989 Revision History: --*/ #include #include #include #include #include "psxdll.h" int __cdecl 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 __cdecl creat(const char *path, mode_t mode) { return open(path, O_CREAT | O_WRONLY | O_TRUNC, mode); } off_t __cdecl 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 __cdecl 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 __cdecl 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 __cdecl 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 __cdecl write(int fildes, const void *buf, unsigned int 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 __cdecl dup(int fildes) { return fcntl(fildes, F_DUPFD, 0); } int __cdecl 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 __cdecl 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 __cdecl 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 __cdecl 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 __cdecl 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; }