diff options
Diffstat (limited to 'win32/stdio.c')
-rw-r--r-- | win32/stdio.c | 628 |
1 files changed, 628 insertions, 0 deletions
diff --git a/win32/stdio.c b/win32/stdio.c new file mode 100644 index 0000000000000..2fa3fc66869aa --- /dev/null +++ b/win32/stdio.c @@ -0,0 +1,628 @@ +/*$Header: /p/tcsh/cvsroot/tcsh/win32/stdio.c,v 1.10 2010/05/27 04:00:23 amold Exp $*/ +/*- + * Copyright (c) 1980, 1991 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * stdio.c Implement a whole load of i/o functions. + * This makes it much easier to keep track of inherited handles and + * also makes us reasonably vendor crt-independent. + * -amol + * + */ + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#include <stdio.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#define STDIO_C +#include <ntport.h> +#include <forkdata.h> + + +#define __MAX_OPEN_FILES 64 + +#define FIOCLEX 1 +#define FCONSOLE 2 + +typedef struct _myfile { + HANDLE handle; + unsigned long flags; +} MY_FILE; + +typedef unsigned long u_long; + +#define INVHL (INVALID_HANDLE_VALUE) + +MY_FILE __gOpenFiles[__MAX_OPEN_FILES]={0}; +MY_FILE __gOpenFilesCopy[__MAX_OPEN_FILES]={0}; + +MY_FILE *my_stdin=0, *my_stdout=0, *my_stderr=0; + +extern int didfds; +int __dup_stdin = 0; + + +void init_stdio(void) { + + int i; + __gOpenFiles[0].handle = GetStdHandle(STD_INPUT_HANDLE); + __gOpenFiles[1].handle = GetStdHandle(STD_OUTPUT_HANDLE); + __gOpenFiles[2].handle = GetStdHandle(STD_ERROR_HANDLE); + + __gOpenFiles[0].flags = (GetFileType(ULongToPtr(STD_INPUT_HANDLE))== + FILE_TYPE_CHAR)? FCONSOLE:0; + __gOpenFiles[1].flags = (GetFileType(ULongToPtr(STD_OUTPUT_HANDLE))== + FILE_TYPE_CHAR)? FCONSOLE:0; + __gOpenFiles[2].flags = (GetFileType(ULongToPtr(STD_ERROR_HANDLE))== + FILE_TYPE_CHAR)? FCONSOLE:0; + + for(i=3;i<__MAX_OPEN_FILES;i++) { + __gOpenFiles[i].handle = INVHL; + __gOpenFilesCopy[i].handle = INVHL; + __gOpenFiles[i].flags = 0; + } + + my_stdin = &__gOpenFiles[0]; + my_stdout = &__gOpenFiles[1]; + my_stderr = &__gOpenFiles[2]; +} + + void nt_close_on_exec(int fd, int on) { + if(on) + __gOpenFiles[fd].flags |= FIOCLEX; + else + __gOpenFiles[fd].flags &= ~FIOCLEX; + } +void restore_fds(void ) { + int i; + int min=3; + + if (__forked && (didfds|| __dup_stdin)) + min =0; + // + // ok for tcsh. see fork.c for why + // + __gOpenFiles[0].handle = INVHL; + __gOpenFiles[1].handle = INVHL; + __gOpenFiles[2].handle = INVHL; + my_stdin = &__gOpenFiles[0]; + my_stdout = &__gOpenFiles[1]; + my_stderr = &__gOpenFiles[2]; + for(i=min;i<__MAX_OPEN_FILES;i++) { + if (__gOpenFilesCopy[i].handle == INVHL) + continue; + __gOpenFiles[i].handle = __gOpenFilesCopy[i].handle ; + __gOpenFiles[i].flags = __gOpenFilesCopy[i].flags ; + } +} +void close_copied_fds(void ) { + int i; + int min=3; + if (didfds|| __dup_stdin) + min =0; + for(i=min;i<__MAX_OPEN_FILES;i++) { + if (__gOpenFilesCopy[i].handle == INVHL) + continue; + CloseHandle((HANDLE)__gOpenFilesCopy[i].handle); + __gOpenFilesCopy[i].handle = INVHL; + } + __dup_stdin=0; +} +void copy_fds(void ) { + int i; + int min=3; + if (didfds || __dup_stdin) + min =0; + for(i=min;i<__MAX_OPEN_FILES;i++) { + if (__gOpenFiles[i].handle == INVHL) { + __gOpenFilesCopy[i].handle = INVHL; + continue; + } + + if(!DuplicateHandle(GetCurrentProcess(), + (HANDLE)__gOpenFiles[i].handle , + GetCurrentProcess(), + (HANDLE*)&__gOpenFilesCopy[i].handle, + 0, TRUE, DUPLICATE_SAME_ACCESS) ) + __gOpenFilesCopy[i].handle = INVHL; + __gOpenFilesCopy[i].flags = __gOpenFiles[i].flags; + } +} +intptr_t __nt_get_osfhandle(int fd) { + return (intptr_t)(__gOpenFiles[fd].handle); +} +int __nt_open_osfhandle(intptr_t h1, int mode) { + int i; + + UNREFERENCED_PARAMETER(mode); + + for(i=0;i<__MAX_OPEN_FILES;i++) { + if (__gOpenFiles[i].handle == INVHL) { + __gOpenFiles[i].handle = (HANDLE)h1; + __gOpenFiles[i].flags = 0; + return i; + } + } + errno = EMFILE; + return -1; +} +int nt_close(int fd) { + + if( (fd == -1) ||(__gOpenFiles[fd].handle == INVHL)) + return 0; + CloseHandle((HANDLE)(__gOpenFiles[fd].handle)); + __gOpenFiles[fd].handle = INVHL; + __gOpenFiles[fd].flags = 0; + + // dprintf("closing 0x%08x\n",(__gOpenFiles[fd].handle)); + return 0; +} +int nt_access(char *filename, int mode) { + + DWORD attribs=(DWORD)-1, bintype; + int tries=0; + char buf[512];/*FIXBUF*/ + + if (!filename) { + errno = ENOENT; + return -1; + } + (void)StringCbPrintf(buf,sizeof(buf),"%s",filename); +retry: + attribs = GetFileAttributes(buf); + tries++; + + if (attribs == (DWORD) -1) { + if( (GetLastError() == ERROR_FILE_NOT_FOUND) && (mode & X_OK) ) { + switch(tries){ + case 1: + (void)StringCbPrintf(buf,sizeof(buf),"%s.exe",filename); + break; + case 2: + (void)StringCbPrintf(buf,sizeof(buf),"%s.cmd",filename); + break; + case 3: + (void)StringCbPrintf(buf,sizeof(buf),"%s.bat",filename); + break; + case 4: + (void)StringCbPrintf(buf,sizeof(buf),"%s.com",filename); + break; + default: + goto giveup; + break; + } + goto retry; + } + } +giveup: + if (attribs == (DWORD)-1 ) { + errno = EACCES; + return -1; + } + if ( (mode & W_OK) && (attribs & FILE_ATTRIBUTE_READONLY) ) { + errno = EACCES; + return -1; + } + if (mode & X_OK) { + if ((mode & XD_OK) && (attribs & FILE_ATTRIBUTE_DIRECTORY) ){ + errno = EACCES; + return -1; + } + if ((!(attribs & FILE_ATTRIBUTE_DIRECTORY)) && + !GetBinaryType(buf,&bintype) &&(tries >4) ) { + errno = EACCES; + return -1; + } + } + return 0; +} +int nt_seek(HANDLE h1, long offset, int how) { + DWORD dwmove; + + switch(how) { + case SEEK_CUR: + dwmove = FILE_CURRENT; + break; + case SEEK_END: + dwmove = FILE_END; + break; + case SEEK_SET: + dwmove = FILE_BEGIN; + break; + default: + errno = EINVAL; + return -1; + } + + if (SetFilePointer(h1,offset,NULL,dwmove) == -1){ + errno = EBADF; + return -1; + } + return 0; +} +int nt_lseek(int fd,long offset, int how) { + HANDLE h1 ; + h1 =__gOpenFiles[fd].handle; + return nt_seek(h1,offset,how); +} +int nt_isatty(int fd) { + return (__gOpenFiles[fd].flags & FCONSOLE); +} +int nt_dup(int fdin) { + + HANDLE hdup; + HANDLE horig = __gOpenFiles[fdin].handle; + int ret; + + + if (!DuplicateHandle(GetCurrentProcess(), + horig, + GetCurrentProcess(), + &hdup, + 0, + FALSE, + DUPLICATE_SAME_ACCESS)) { + errno = GetLastError(); + errno = EBADF; + return -1; + } + ret = __nt_open_osfhandle((intptr_t)hdup,_O_BINARY | _O_NOINHERIT); + + __gOpenFiles[ret].flags = __gOpenFiles[fdin].flags; + + return ret; +} +int nt_dup2(int fdorig,int fdcopy) { + + HANDLE hdup; + HANDLE horig = __gOpenFiles[fdorig].handle; + + + if (__gOpenFiles[fdcopy].handle != INVHL) { + CloseHandle((HANDLE)__gOpenFiles[fdcopy].handle ); + __gOpenFiles[fdcopy].handle = INVHL; + __gOpenFiles[fdcopy].flags = 0; + } + if (!DuplicateHandle(GetCurrentProcess(), + horig, + GetCurrentProcess(), + &hdup, + 0, + fdcopy<3?TRUE:FALSE, DUPLICATE_SAME_ACCESS)) { + errno = GetLastError(); + errno = EBADF; + return -1; + } + __gOpenFiles[fdcopy].handle = hdup; + __gOpenFiles[fdcopy].flags = __gOpenFiles[fdorig].flags; + switch(fdcopy) { + case 0: + SetStdHandle(STD_INPUT_HANDLE,hdup); + break; + case 1: + SetStdHandle(STD_OUTPUT_HANDLE,hdup); + break; + case 2: + SetStdHandle(STD_ERROR_HANDLE,hdup); + break; + default: + break; + } + + return 0; +} +int nt_pipe2(HANDLE hpipe[2]) { + + SECURITY_ATTRIBUTES secd; + + secd.nLength=sizeof(secd); + secd.lpSecurityDescriptor=NULL; + secd.bInheritHandle=FALSE; + + return (!CreatePipe(&hpipe[0],&hpipe[1],&secd,0)); +} +int nt_pipe(int hpipe[2]) { + HANDLE hpipe2[2]; + + nt_pipe2(hpipe2); + hpipe[0] = __nt_open_osfhandle((intptr_t)hpipe2[0],O_NOINHERIT); + hpipe[1] = __nt_open_osfhandle((intptr_t)hpipe2[1],O_NOINHERIT); + return 0; +} +/* check if name is //server. if checkifShare is set, + * also check if //server/share + */ +int is_server(const char *name,int checkifShare) { + const char *p1, *p2; + + if (!*name || !*(name+1)) + return 0; + + p1 = name; + if (((p1[0] != '/') && (p1[0] != '\\') ) || + ((p1[1] != '/') && (p1[1] != '\\') )) + return 0; + + p2 = p1 + 2; + while (*p2 && *p2 != '/' && *p2 != '\\') +#ifdef DSPMBYTE + if (Ismbyte1(*p2) && *(p2 + 1)) + p2 += 2; + else +#endif /* DSPMBYTE */ + p2++; + + /* just check for server */ + if (!checkifShare) { + /* null terminated unc server name */ + /* terminating '/' (//server/) is also ok */ + if (!*p2 || !*(p2+1)) + return 1; + + } + else { + if (!*p2 || !*(p2+1)) + return 0; + p2++; + while(*p2 && *p2 != '/' && *p2 != '\\') + p2++; + if (!*p2 || !*(p2+1)) + return 1; + } + return 0; + +} +__inline int is_unc(char *filename) { + if (*filename && (*filename == '/' || *filename == '\\') + && *(filename+1) + && (*(filename+1) == '/' || *(filename+1) == '\\')) { + return 1; + } + return 0; +} +int nt_stat(const char *filename, struct stat *stbuf) { + + // stat hangs on server name + // Use any directory, since the info in stat means %$!* on + // windows anyway. + // -amol 5/28/97 + /* is server or share */ + if (is_server(filename,0) || is_server(filename,1) || + (*(filename+1) && *(filename+1) == ':' && !*(filename+2)) ) { + return _stat("C:/",(struct _stat *)stbuf); + } + else { + char *last = (char*)filename + strlen(filename) -1; + int rc = 0; + BOOL lastslash = (*last == '/'); + if(lastslash) + { + *last = 0; + } + rc = _stat(filename,(struct _stat *)stbuf); + if(lastslash) + { + *last = '/'; + } + return rc; + } +} +// +// replacement for creat that makes handle non-inheritable. +// -amol +// +int nt_creat(const char *filename, int mode) { + // ignore the bloody mode + + int fd = 0,is_cons =0; + HANDLE retval; + SECURITY_ATTRIBUTES security; + + UNREFERENCED_PARAMETER(mode); + + + security.nLength = sizeof(security); + security.lpSecurityDescriptor = NULL; + security.bInheritHandle = FALSE; + + if (!_stricmp(filename,"/dev/tty") ){ + filename = "CONOUT$"; + is_cons = 1; + } + else if (!_stricmp(filename,"/dev/null") ){ + filename = "NUL"; + } + else if (!_stricmp(filename,"/dev/clipboard")) { + retval = create_clip_writer_thread(); + if (retval == INVHL) + return -1; + goto get_fd; + } + retval = CreateFile(filename, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + is_cons?NULL:&security, + CREATE_ALWAYS, + 0, + NULL); + + if (retval == INVALID_HANDLE_VALUE) { + errno = EACCES; + return -1; + } +get_fd: + fd = __nt_open_osfhandle((intptr_t)retval,_O_BINARY); + if (fd <0) { + //should never happen + abort(); + } + else { + if (is_cons) { + __gOpenFiles[fd].flags = FCONSOLE; + } + } + return fd; + +} +int nt_open(const char *filename, int perms,...) { + + // ignore the bloody mode + + int fd,mode, is_cons=0; + HANDLE retval; + SECURITY_ATTRIBUTES security; + DWORD dwAccess, dwFlags, dwCreateDist; + va_list ap; + + va_start(ap,perms); + mode = va_arg(ap,int); + va_end(ap); + + if (!lstrcmp(filename,"/dev/tty") ){ + if (perms == O_RDONLY) //o_rdonly is 0 + filename = "CONIN$"; + else if (perms & O_WRONLY) + filename = "CONOUT$"; + is_cons = 1; + } + else if (!lstrcmp(filename,"/dev/null") ){ + filename = "NUL"; + } + else if (!_stricmp(filename,"/dev/clipboard")) { + retval = create_clip_reader_thread(); + goto get_fd; + } + security.nLength = sizeof(security); + security.lpSecurityDescriptor = NULL; + security.bInheritHandle = FALSE; + + switch (perms & (_O_RDONLY | _O_WRONLY | _O_RDWR) ) { + case _O_RDONLY: + dwAccess = GENERIC_READ; + break; + case _O_WRONLY: + dwAccess = GENERIC_WRITE; + break; + case _O_RDWR: + dwAccess = GENERIC_READ | GENERIC_WRITE ; + break; + default: + errno = EINVAL; + return -1; + } + switch (perms & (_O_CREAT | _O_TRUNC) ){ + case 0: + dwCreateDist = OPEN_EXISTING; + break; + case _O_CREAT: + dwCreateDist = CREATE_ALWAYS; + break; + case _O_CREAT | _O_TRUNC: + dwCreateDist = CREATE_ALWAYS; + break; + case _O_TRUNC: + dwCreateDist = TRUNCATE_EXISTING; + break; + default: + errno = EINVAL; + return -1; + } + dwFlags = 0; + if (perms & O_TEMPORARY) + dwFlags = FILE_FLAG_DELETE_ON_CLOSE; + retval = CreateFile(filename, + dwAccess,//GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + &security, + dwCreateDist,//CREATE_ALWAYS, + dwFlags, + NULL); + + if (retval == INVALID_HANDLE_VALUE) { + int err = GetLastError(); + if (err == ERROR_FILE_NOT_FOUND) + errno = ENOENT; + else + errno = EACCES; + return -1; + } + if (perms & O_APPEND) { + SetFilePointer(retval,0,NULL,FILE_END); + } +get_fd: + fd = __nt_open_osfhandle((intptr_t)retval,_O_BINARY); + if (fd <0) { + //should never happen + abort(); + } + else { + if (is_cons) { + __gOpenFiles[fd].flags = FCONSOLE; + } + } + return fd; + +} +/* + * This should be the LAST FUNCTION IN THIS FILE + * + */ +#undef fstat +#undef _open_osfhandle +#undef close +int nt_fstat(int fd, struct stat *stbuf) { + int realfd; + HANDLE h1; + + errno = EBADF; + + if(!DuplicateHandle(GetCurrentProcess(), + (HANDLE)__gOpenFiles[fd].handle, + GetCurrentProcess(), + &h1, + 0, + FALSE, + DUPLICATE_SAME_ACCESS) ) + return -1; + realfd = _open_osfhandle((intptr_t)h1,0); + if (realfd <0 ) + return -1; + + if( fstat(realfd,stbuf) <0 ) { + _close(realfd); + return -1; + } + _close(realfd); + errno =0; + return 0; + +} + |