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