1/*$Header: /p/tcsh/cvsroot/tcsh/win32/stdio.c,v 1.9 2006/03/11 01:47:40 amold Exp $*/ 2/*- 3 * Copyright (c) 1980, 1991 The Regents of the University of California. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of the University nor the names of its contributors 15 * may be used to endorse or promote products derived from this software 16 * without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30/* 31 * stdio.c Implement a whole load of i/o functions. 32 * This makes it much easier to keep track of inherited handles and 33 * also makes us reasonably vendor crt-independent. 34 * -amol 35 * 36 */ 37 38#define WIN32_LEAN_AND_MEAN 39#include <windows.h> 40#include <stdio.h> 41#include <errno.h> 42#include <sys/types.h> 43#include <sys/stat.h> 44#include <fcntl.h> 45#define STDIO_C 46#include <ntport.h> 47#include <forkdata.h> 48 49 50#define __MAX_OPEN_FILES 64 51 52#define FIOCLEX 1 53#define FCONSOLE 2 54 55typedef struct _myfile { 56 HANDLE handle; 57 unsigned long flags; 58} MY_FILE; 59 60typedef unsigned long u_long; 61 62#define INVHL (INVALID_HANDLE_VALUE) 63 64MY_FILE __gOpenFiles[__MAX_OPEN_FILES]={0}; 65MY_FILE __gOpenFilesCopy[__MAX_OPEN_FILES]={0}; 66 67MY_FILE *my_stdin=0, *my_stdout=0, *my_stderr=0; 68 69extern int didfds; 70int __dup_stdin = 0; 71 72 73void init_stdio(void) { 74 75 int i; 76 __gOpenFiles[0].handle = GetStdHandle(STD_INPUT_HANDLE); 77 __gOpenFiles[1].handle = GetStdHandle(STD_OUTPUT_HANDLE); 78 __gOpenFiles[2].handle = GetStdHandle(STD_ERROR_HANDLE); 79 80 __gOpenFiles[0].flags = (GetFileType(ULongToPtr(STD_INPUT_HANDLE))== 81 FILE_TYPE_CHAR)? FCONSOLE:0; 82 __gOpenFiles[1].flags = (GetFileType(ULongToPtr(STD_OUTPUT_HANDLE))== 83 FILE_TYPE_CHAR)? FCONSOLE:0; 84 __gOpenFiles[2].flags = (GetFileType(ULongToPtr(STD_ERROR_HANDLE))== 85 FILE_TYPE_CHAR)? FCONSOLE:0; 86 87 for(i=3;i<__MAX_OPEN_FILES;i++) { 88 __gOpenFiles[i].handle = INVHL; 89 __gOpenFilesCopy[i].handle = INVHL; 90 __gOpenFiles[i].flags = 0; 91 } 92 93 my_stdin = &__gOpenFiles[0]; 94 my_stdout = &__gOpenFiles[1]; 95 my_stderr = &__gOpenFiles[2]; 96} 97 98 void nt_close_on_exec(int fd, int on) { 99 if(on) 100 __gOpenFiles[fd].flags |= FIOCLEX; 101 else 102 __gOpenFiles[fd].flags &= ~FIOCLEX; 103 } 104void restore_fds(void ) { 105 int i; 106 int min=3; 107 108 if (__forked && (didfds|| __dup_stdin)) 109 min =0; 110 // 111 // ok for tcsh. see fork.c for why 112 // 113 __gOpenFiles[0].handle = INVHL; 114 __gOpenFiles[1].handle = INVHL; 115 __gOpenFiles[2].handle = INVHL; 116 my_stdin = &__gOpenFiles[0]; 117 my_stdout = &__gOpenFiles[1]; 118 my_stderr = &__gOpenFiles[2]; 119 for(i=min;i<__MAX_OPEN_FILES;i++) { 120 if (__gOpenFilesCopy[i].handle == INVHL) 121 continue; 122 __gOpenFiles[i].handle = __gOpenFilesCopy[i].handle ; 123 __gOpenFiles[i].flags = __gOpenFilesCopy[i].flags ; 124 } 125} 126void close_copied_fds(void ) { 127 int i; 128 int min=3; 129 if (didfds|| __dup_stdin) 130 min =0; 131 for(i=min;i<__MAX_OPEN_FILES;i++) { 132 if (__gOpenFilesCopy[i].handle == INVHL) 133 continue; 134 CloseHandle((HANDLE)__gOpenFilesCopy[i].handle); 135 __gOpenFilesCopy[i].handle = INVHL; 136 } 137 __dup_stdin=0; 138} 139void copy_fds(void ) { 140 int i; 141 int min=3; 142 if (didfds || __dup_stdin) 143 min =0; 144 for(i=min;i<__MAX_OPEN_FILES;i++) { 145 if (__gOpenFiles[i].handle == INVHL) { 146 __gOpenFilesCopy[i].handle = INVHL; 147 continue; 148 } 149 150 if(!DuplicateHandle(GetCurrentProcess(), 151 (HANDLE)__gOpenFiles[i].handle , 152 GetCurrentProcess(), 153 (HANDLE*)&__gOpenFilesCopy[i].handle, 154 0, TRUE, DUPLICATE_SAME_ACCESS) ) 155 __gOpenFilesCopy[i].handle = INVHL; 156 __gOpenFilesCopy[i].flags = __gOpenFiles[i].flags; 157 } 158} 159intptr_t __nt_get_osfhandle(int fd) { 160 return (intptr_t)(__gOpenFiles[fd].handle); 161} 162int __nt_open_osfhandle(intptr_t h1, int mode) { 163 int i; 164 165 UNREFERENCED_PARAMETER(mode); 166 167 for(i=0;i<__MAX_OPEN_FILES;i++) { 168 if (__gOpenFiles[i].handle == INVHL) { 169 __gOpenFiles[i].handle = (HANDLE)h1; 170 __gOpenFiles[i].flags = 0; 171 return i; 172 } 173 } 174 errno = EMFILE; 175 return -1; 176} 177int nt_close(int fd) { 178 179 if( (fd == -1) ||(__gOpenFiles[fd].handle == INVHL)) 180 return 0; 181 CloseHandle((HANDLE)(__gOpenFiles[fd].handle)); 182 __gOpenFiles[fd].handle = INVHL; 183 __gOpenFiles[fd].flags = 0; 184 185 // dprintf("closing 0x%08x\n",(__gOpenFiles[fd].handle)); 186 return 0; 187} 188int nt_access(char *filename, int mode) { 189 190 DWORD attribs=(DWORD)-1, bintype; 191 int tries=0; 192 char buf[512];/*FIXBUF*/ 193 194 if (!filename) { 195 errno = ENOENT; 196 return -1; 197 } 198 (void)StringCbPrintf(buf,sizeof(buf),"%s",filename); 199retry: 200 attribs = GetFileAttributes(buf); 201 tries++; 202 203 if (attribs == (DWORD) -1) { 204 if( (GetLastError() == ERROR_FILE_NOT_FOUND) && (mode & X_OK) ) { 205 switch(tries){ 206 case 1: 207 (void)StringCbPrintf(buf,sizeof(buf),"%s.exe",filename); 208 break; 209 case 2: 210 (void)StringCbPrintf(buf,sizeof(buf),"%s.cmd",filename); 211 break; 212 case 3: 213 (void)StringCbPrintf(buf,sizeof(buf),"%s.bat",filename); 214 break; 215 case 4: 216 (void)StringCbPrintf(buf,sizeof(buf),"%s.com",filename); 217 break; 218 default: 219 goto giveup; 220 break; 221 } 222 goto retry; 223 } 224 } 225giveup: 226 if (attribs == (DWORD)-1 ) { 227 errno = EACCES; 228 return -1; 229 } 230 if ( (mode & W_OK) && (attribs & FILE_ATTRIBUTE_READONLY) ) { 231 errno = EACCES; 232 return -1; 233 } 234 if (mode & X_OK) { 235 if ((mode & XD_OK) && (attribs & FILE_ATTRIBUTE_DIRECTORY) ){ 236 errno = EACCES; 237 return -1; 238 } 239 if ((!(attribs & FILE_ATTRIBUTE_DIRECTORY)) && 240 !GetBinaryType(buf,&bintype) &&(tries >4) ) { 241 errno = EACCES; 242 return -1; 243 } 244 } 245 return 0; 246} 247int nt_seek(HANDLE h1, long offset, int how) { 248 DWORD dwmove; 249 250 switch(how) { 251 case SEEK_CUR: 252 dwmove = FILE_CURRENT; 253 break; 254 case SEEK_END: 255 dwmove = FILE_END; 256 break; 257 case SEEK_SET: 258 dwmove = FILE_BEGIN; 259 break; 260 default: 261 errno = EINVAL; 262 return -1; 263 } 264 265 if (SetFilePointer(h1,offset,NULL,dwmove) == -1){ 266 errno = EBADF; 267 return -1; 268 } 269 return 0; 270} 271int nt_lseek(int fd,long offset, int how) { 272 HANDLE h1 ; 273 h1 =__gOpenFiles[fd].handle; 274 return nt_seek(h1,offset,how); 275} 276int nt_isatty(int fd) { 277 return (__gOpenFiles[fd].flags & FCONSOLE); 278} 279int nt_dup(int fdin) { 280 281 HANDLE hdup; 282 HANDLE horig = __gOpenFiles[fdin].handle; 283 int ret; 284 285 286 if (!DuplicateHandle(GetCurrentProcess(), 287 horig, 288 GetCurrentProcess(), 289 &hdup, 290 0, 291 FALSE, 292 DUPLICATE_SAME_ACCESS)) { 293 errno = GetLastError(); 294 errno = EBADF; 295 return -1; 296 } 297 ret = __nt_open_osfhandle((intptr_t)hdup,_O_BINARY | _O_NOINHERIT); 298 299 __gOpenFiles[ret].flags = __gOpenFiles[fdin].flags; 300 301 return ret; 302} 303int nt_dup2(int fdorig,int fdcopy) { 304 305 HANDLE hdup; 306 HANDLE horig = __gOpenFiles[fdorig].handle; 307 308 309 if (__gOpenFiles[fdcopy].handle != INVHL) { 310 CloseHandle((HANDLE)__gOpenFiles[fdcopy].handle ); 311 __gOpenFiles[fdcopy].handle = INVHL; 312 __gOpenFiles[fdcopy].flags = 0; 313 } 314 if (!DuplicateHandle(GetCurrentProcess(), 315 horig, 316 GetCurrentProcess(), 317 &hdup, 318 0, 319 fdcopy<3?TRUE:FALSE, DUPLICATE_SAME_ACCESS)) { 320 errno = GetLastError(); 321 errno = EBADF; 322 return -1; 323 } 324 __gOpenFiles[fdcopy].handle = hdup; 325 __gOpenFiles[fdcopy].flags = __gOpenFiles[fdorig].flags; 326 switch(fdcopy) { 327 case 0: 328 SetStdHandle(STD_INPUT_HANDLE,hdup); 329 break; 330 case 1: 331 SetStdHandle(STD_OUTPUT_HANDLE,hdup); 332 break; 333 case 2: 334 SetStdHandle(STD_ERROR_HANDLE,hdup); 335 break; 336 default: 337 break; 338 } 339 340 return 0; 341} 342int nt_pipe2(HANDLE hpipe[2]) { 343 344 SECURITY_ATTRIBUTES secd; 345 346 secd.nLength=sizeof(secd); 347 secd.lpSecurityDescriptor=NULL; 348 secd.bInheritHandle=FALSE; 349 350 return (!CreatePipe(&hpipe[0],&hpipe[1],&secd,0)); 351} 352int nt_pipe(int hpipe[2]) { 353 HANDLE hpipe2[2]; 354 355 nt_pipe2(hpipe2); 356 hpipe[0] = __nt_open_osfhandle((intptr_t)hpipe2[0],O_NOINHERIT); 357 hpipe[1] = __nt_open_osfhandle((intptr_t)hpipe2[1],O_NOINHERIT); 358 return 0; 359} 360/* check if name is //server. if checkifShare is set, 361 * also check if //server/share 362 */ 363int is_server(const char *name,int checkifShare) { 364 const char *p1, *p2; 365 366 if (!*name || !*(name+1)) 367 return 0; 368 369 p1 = name; 370 if (((p1[0] != '/') && (p1[0] != '\\') ) || 371 ((p1[1] != '/') && (p1[1] != '\\') )) 372 return 0; 373 374 p2 = p1 + 2; 375 while (*p2 && *p2 != '/' && *p2 != '\\') 376#ifdef DSPMBYTE 377 if (Ismbyte1(*p2) && *(p2 + 1)) 378 p2 += 2; 379 else 380#endif /* DSPMBYTE */ 381 p2++; 382 383 /* just check for server */ 384 if (!checkifShare) { 385 /* null terminated unc server name */ 386 /* terminating '/' (//server/) is also ok */ 387 if (!*p2 || !*(p2+1)) 388 return 1; 389 390 } 391 else { 392 if (!*p2 || !*(p2+1)) 393 return 0; 394 p2++; 395 while(*p2 && *p2 != '/' && *p2 != '\\') 396 p2++; 397 if (!*p2 || !*(p2+1)) 398 return 1; 399 } 400 return 0; 401 402} 403__inline int is_unc(char *filename) { 404 if (*filename && (*filename == '/' || *filename == '\\') 405 && *(filename+1) 406 && (*(filename+1) == '/' || *(filename+1) == '\\')) { 407 return 1; 408 } 409 return 0; 410} 411int nt_stat(const char *filename, struct stat *stbuf) { 412 413 // stat hangs on server name 414 // Use any directory, since the info in stat means %$!* on 415 // windows anyway. 416 // -amol 5/28/97 417 /* is server or share */ 418 if (is_server(filename,0) || is_server(filename,1) || 419 (*(filename+1) && *(filename+1) == ':' && !*(filename+2)) ) { 420 return _stat("C:/",(struct _stat *)stbuf); 421 } 422 else 423 return _stat(filename,(struct _stat *)stbuf); 424} 425// 426// replacement for creat that makes handle non-inheritable. 427// -amol 428// 429int nt_creat(const char *filename, int mode) { 430 // ignore the bloody mode 431 432 int fd = 0,is_cons =0; 433 HANDLE retval; 434 SECURITY_ATTRIBUTES security; 435 436 UNREFERENCED_PARAMETER(mode); 437 438 439 security.nLength = sizeof(security); 440 security.lpSecurityDescriptor = NULL; 441 security.bInheritHandle = FALSE; 442 443 if (!_stricmp(filename,"/dev/tty") ){ 444 filename = "CONOUT$"; 445 is_cons = 1; 446 } 447 else if (!_stricmp(filename,"/dev/null") ){ 448 filename = "NUL"; 449 } 450 else if (!_stricmp(filename,"/dev/clipboard")) { 451 retval = create_clip_writer_thread(); 452 if (retval == INVHL) 453 return -1; 454 goto get_fd; 455 } 456 retval = CreateFile(filename, 457 GENERIC_READ | GENERIC_WRITE, 458 FILE_SHARE_READ | FILE_SHARE_WRITE, 459 is_cons?NULL:&security, 460 CREATE_ALWAYS, 461 0, 462 NULL); 463 464 if (retval == INVALID_HANDLE_VALUE) { 465 errno = EACCES; 466 return -1; 467 } 468get_fd: 469 fd = __nt_open_osfhandle((intptr_t)retval,_O_BINARY); 470 if (fd <0) { 471 //should never happen 472 abort(); 473 } 474 else { 475 if (is_cons) { 476 __gOpenFiles[fd].flags = FCONSOLE; 477 } 478 } 479 return fd; 480 481} 482int nt_open(const char *filename, int perms,...) { 483 484 // ignore the bloody mode 485 486 int fd,mode, is_cons=0; 487 HANDLE retval; 488 SECURITY_ATTRIBUTES security; 489 DWORD dwAccess, dwFlags, dwCreateDist; 490 va_list ap; 491 492 va_start(ap,perms); 493 mode = va_arg(ap,int); 494 va_end(ap); 495 496 if (!lstrcmp(filename,"/dev/tty") ){ 497 if (perms == O_RDONLY) //o_rdonly is 0 498 filename = "CONIN$"; 499 else if (perms & O_WRONLY) 500 filename = "CONOUT$"; 501 is_cons = 1; 502 } 503 else if (!lstrcmp(filename,"/dev/null") ){ 504 filename = "NUL"; 505 } 506 else if (!_stricmp(filename,"/dev/clipboard")) { 507 retval = create_clip_reader_thread(); 508 goto get_fd; 509 } 510 security.nLength = sizeof(security); 511 security.lpSecurityDescriptor = NULL; 512 security.bInheritHandle = FALSE; 513 514 switch (perms & (_O_RDONLY | _O_WRONLY | _O_RDWR) ) { 515 case _O_RDONLY: 516 dwAccess = GENERIC_READ; 517 break; 518 case _O_WRONLY: 519 dwAccess = GENERIC_WRITE; 520 break; 521 case _O_RDWR: 522 dwAccess = GENERIC_READ | GENERIC_WRITE ; 523 break; 524 default: 525 errno = EINVAL; 526 return -1; 527 } 528 switch (perms & (_O_CREAT | _O_TRUNC) ){ 529 case 0: 530 dwCreateDist = OPEN_EXISTING; 531 break; 532 case _O_CREAT: 533 dwCreateDist = CREATE_ALWAYS; 534 break; 535 case _O_CREAT | _O_TRUNC: 536 dwCreateDist = CREATE_ALWAYS; 537 break; 538 case _O_TRUNC: 539 dwCreateDist = TRUNCATE_EXISTING; 540 break; 541 default: 542 errno = EINVAL; 543 return -1; 544 } 545 dwFlags = 0; 546 if (perms & O_TEMPORARY) 547 dwFlags = FILE_FLAG_DELETE_ON_CLOSE; 548 retval = CreateFile(filename, 549 dwAccess,//GENERIC_READ | GENERIC_WRITE, 550 FILE_SHARE_READ | FILE_SHARE_WRITE, 551 &security, 552 dwCreateDist,//CREATE_ALWAYS, 553 dwFlags, 554 NULL); 555 556 if (retval == INVALID_HANDLE_VALUE) { 557 int err = GetLastError(); 558 if (err == ERROR_FILE_NOT_FOUND) 559 errno = ENOENT; 560 else 561 errno = EACCES; 562 return -1; 563 } 564 if (perms & O_APPEND) { 565 SetFilePointer(retval,0,NULL,FILE_END); 566 } 567get_fd: 568 fd = __nt_open_osfhandle((intptr_t)retval,_O_BINARY); 569 if (fd <0) { 570 //should never happen 571 abort(); 572 } 573 else { 574 if (is_cons) { 575 __gOpenFiles[fd].flags = FCONSOLE; 576 } 577 } 578 return fd; 579 580} 581/* 582 * This should be the LAST FUNCTION IN THIS FILE 583 * 584 */ 585#undef fstat 586#undef _open_osfhandle 587#undef close 588int nt_fstat(int fd, struct stat *stbuf) { 589 int realfd; 590 HANDLE h1; 591 592 errno = EBADF; 593 594 if(!DuplicateHandle(GetCurrentProcess(), 595 (HANDLE)__gOpenFiles[fd].handle, 596 GetCurrentProcess(), 597 &h1, 598 0, 599 FALSE, 600 DUPLICATE_SAME_ACCESS) ) 601 return -1; 602 realfd = _open_osfhandle((intptr_t)h1,0); 603 if (realfd <0 ) 604 return -1; 605 606 if( fstat(realfd,stbuf) <0 ) { 607 _close(realfd); 608 return -1; 609 } 610 _close(realfd); 611 errno =0; 612 return 0; 613 614} 615 616