update for HEAD-2003091401
[reactos.git] / lib / msvcrt / io / open.c
1 /* $Id$
2  *
3  * COPYRIGHT:   See COPYING in the top level directory
4  * PROJECT:     ReactOS system libraries
5  * FILE:        lib/msvcrt/io/open.c
6  * PURPOSE:     Opens a file and translates handles to fileno
7  * PROGRAMER:   Boudewijn Dekker
8  * UPDATE HISTORY:
9  *              28/12/98: Created
10  */
11
12 // rember to interlock the allocation of fileno when making this thread safe
13
14 // possibly store extra information at the handle
15
16 #include <windows.h>
17 #if !defined(NDEBUG) && defined(DBG)
18 #include <msvcrt/stdarg.h>
19 #endif
20 #include <msvcrt/io.h>
21 #include <msvcrt/fcntl.h>
22 #include <msvcrt/sys/stat.h>
23 #include <msvcrt/stdlib.h>
24 #include <msvcrt/internal/file.h>
25 #include <msvcrt/string.h>
26 #include <msvcrt/share.h>
27 #include <msvcrt/errno.h>
28
29 #define NDEBUG
30 #include <msvcrt/msvcrtdbg.h>
31
32 //#define _OLD_BUILD_
33
34 #define STD_AUX_HANDLE 3
35 #define STD_PRINTER_HANDLE 4
36
37
38 /////////////////////////////////////////
39 #if 0 // from perl sources
40
41 #ifndef _INTPTR_T_DEFINED
42 typedef int             intptr_t;
43 #define _INTPTR_T_DEFINED
44 #endif
45
46 #ifndef _UINTPTR_T_DEFINED
47 typedef unsigned int    uintptr_t;
48 #define _UINTPTR_T_DEFINED
49 #endif
50
51 /*
52  * Control structure for lowio file handles
53  */
54 typedef struct {
55     intptr_t osfhnd;/* underlying OS file HANDLE */
56     char osfile;    /* attributes of file (e.g., open in text mode?) */
57     char pipech;    /* one char buffer for handles opened on pipes */
58     int lockinitflag;
59     //CRITICAL_SECTION lock;
60 } ioinfo;
61
62 /*
63  * Array of arrays of control structures for lowio files.
64  */
65 //ioinfo* __pioinfo[];
66 //ioinfo* __pioinfo[] = { NULL };
67
68 #endif
69 /////////////////////////////////////////
70
71 typedef struct _fileno_modes_type
72 {
73     HANDLE hFile;
74     int mode;
75     char pipech;    /* one char buffer for handles opened on pipes */
76     int lockinitflag;
77     /*CRITICAL_SECTION*/int lock;
78     int fd;
79 } fileno_modes_type;
80
81 //static fileno_modes_type* fileno_modes = NULL;
82 fileno_modes_type* __pioinfo = NULL;
83
84 /////////////////////////////////////////
85 int maxfno = 0;
86
87 char __is_text_file(FILE* p)
88 {
89    if ( p == NULL || __pioinfo == NULL )
90      return FALSE;
91    return (!((p)->_flag&_IOSTRG) && (__pioinfo[(p)->_file].mode&O_TEXT));
92 }
93
94 /*
95  * @implemented
96  */
97 int _open(const char* _path, int _oflag,...)
98 {
99 #if !defined(NDEBUG) && defined(DBG)
100    va_list arg;
101    int pmode;
102 #endif
103    HANDLE hFile;
104    DWORD dwDesiredAccess = 0;
105    DWORD dwShareMode = 0;
106    DWORD dwCreationDistribution = 0;
107    DWORD dwFlagsAndAttributes = 0;
108    DWORD dwLastError;
109    SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
110
111 #if !defined(NDEBUG) && defined(DBG)
112    va_start(arg, _oflag);
113    pmode = va_arg(arg, int);
114 #endif
115
116 //   DPRINT("_open('%s', %x, (%x))\n", _path, _oflag, pmode);
117
118    if ((_oflag & S_IREAD ) == S_IREAD)
119      dwShareMode = FILE_SHARE_READ;
120    else if ((_oflag & S_IWRITE) == S_IWRITE) {
121       dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
122    }
123    /*
124     *
125     * _O_BINARY   Opens file in binary (untranslated) mode. (See fopen for a description of binary mode.)
126     * _O_TEXT   Opens file in text (translated) mode. (For more information, see Text and Binary Mode File I/O and fopen.)
127     *
128     * _O_APPEND   Moves file pointer to end of file before every write operation.
129     */
130 #ifdef _OLD_BUILD_
131    if ((_oflag & _O_RDWR) == _O_RDWR)
132      dwDesiredAccess |= GENERIC_WRITE|GENERIC_READ;
133    else if ((_oflag & O_RDONLY) == O_RDONLY)
134      dwDesiredAccess |= GENERIC_READ;
135    else if ((_oflag & _O_WRONLY) == _O_WRONLY)
136      dwDesiredAccess |= GENERIC_WRITE ;
137 #else
138    if ((_oflag & _O_WRONLY) == _O_WRONLY )
139      dwDesiredAccess |= GENERIC_WRITE ;
140    else if ((_oflag & _O_RDWR) == _O_RDWR )
141      dwDesiredAccess |= GENERIC_WRITE|GENERIC_READ;
142    else //if ((_oflag & O_RDONLY) == O_RDONLY)
143      dwDesiredAccess |= GENERIC_READ;
144 #endif
145    if (( _oflag & S_IREAD ) == S_IREAD)
146      dwShareMode |= FILE_SHARE_READ;
147    
148    if (( _oflag & S_IWRITE ) == S_IWRITE)
149      dwShareMode |= FILE_SHARE_WRITE;
150
151    if (( _oflag & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL))
152      dwCreationDistribution |= CREATE_NEW;
153
154    else if ((_oflag &  O_TRUNC ) == O_TRUNC) {
155       if ((_oflag &  O_CREAT ) ==  O_CREAT)
156     dwCreationDistribution |= CREATE_ALWAYS;
157       else if ((_oflag & O_RDONLY ) != O_RDONLY)
158     dwCreationDistribution |= TRUNCATE_EXISTING;
159    }
160    else if ((_oflag & _O_APPEND) == _O_APPEND)
161      dwCreationDistribution |= OPEN_EXISTING;
162    else if ((_oflag &  _O_CREAT) == _O_CREAT)
163      dwCreationDistribution |= OPEN_ALWAYS;
164    else
165      dwCreationDistribution |= OPEN_EXISTING;
166
167    if ((_oflag &  _O_RANDOM) == _O_RANDOM )
168      dwFlagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS;
169    if ((_oflag &  _O_SEQUENTIAL) == _O_SEQUENTIAL)
170      dwFlagsAndAttributes |= FILE_FLAG_SEQUENTIAL_SCAN;
171    if ((_oflag &  _O_TEMPORARY) == _O_TEMPORARY) {
172      dwFlagsAndAttributes |= FILE_FLAG_DELETE_ON_CLOSE;
173      DPRINT("FILE_FLAG_DELETE_ON_CLOSE\n");
174    }
175    if ((_oflag &  _O_SHORT_LIVED) == _O_SHORT_LIVED) {
176      dwFlagsAndAttributes |= FILE_FLAG_DELETE_ON_CLOSE;
177      DPRINT("FILE_FLAG_DELETE_ON_CLOSE\n");
178    }
179    if (_oflag & _O_NOINHERIT)
180      sa.bInheritHandle = FALSE;
181    hFile = CreateFileA(_path,
182                dwDesiredAccess,
183                dwShareMode, 
184                &sa,
185                dwCreationDistribution,
186                dwFlagsAndAttributes,
187                NULL);
188    if (hFile == (HANDLE)-1) {
189      dwLastError = GetLastError();
190      if (dwLastError == ERROR_ALREADY_EXISTS) {
191         DPRINT("ERROR_ALREADY_EXISTS\n");
192         __set_errno(EEXIST);
193      } else {
194         DPRINT("%x\n", dwLastError);
195         __set_errno(ENOFILE);
196      }
197      return -1;
198    }
199    DPRINT("OK\n");
200    if (!(_oflag & (_O_TEXT|_O_BINARY))) {
201        _oflag |= _fmode;
202    }
203    return __fileno_alloc(hFile,_oflag);
204 }
205
206
207 int __fileno_alloc(HANDLE hFile, int mode)
208 {
209   int i;
210   /* Check for bogus values */
211   if (hFile < 0)
212     return -1;
213
214   for (i = 5; i < maxfno; i++) {
215     if (__pioinfo[i].fd == -1 ) {
216         __pioinfo[i].fd = i;
217         __pioinfo[i].mode = mode;
218         __pioinfo[i].hFile = hFile;
219         return i;
220     }
221   }
222
223   /* See if we need to expand the tables.  Check this BEFORE it might fail,
224      so that when we hit the count'th request, we've already up'd it. */
225   if (i == maxfno) {
226     int oldcount = maxfno;
227     fileno_modes_type* old_fileno_modes = __pioinfo;
228     maxfno += 255;
229     __pioinfo = (fileno_modes_type*)malloc(maxfno * sizeof(fileno_modes_type));
230     if (old_fileno_modes != NULL) {
231         memcpy(__pioinfo, old_fileno_modes, oldcount * sizeof(fileno_modes_type));
232         free(old_fileno_modes);
233     }
234     memset(__pioinfo + oldcount, -1, (maxfno-oldcount)*sizeof(fileno_modes_type));
235   }
236
237   /* Fill in the value */
238   __pioinfo[i].fd = i;
239   __pioinfo[i].mode = mode;
240   __pioinfo[i].hFile = hFile;
241   return i;
242 }
243
244 void* filehnd(int fileno)
245 {
246     if (fileno < 0 || fileno >= maxfno || __pioinfo[fileno].fd == -1) {
247         return (void*)-1;
248     }
249     return __pioinfo[fileno].hFile;
250 }
251
252 int __fileno_setmode(int _fd, int _newmode)
253 {
254     int m;
255     if (_fd < 0 || _fd >= maxfno) {
256         __set_errno(EBADF);
257         return -1;
258     }
259     m = __pioinfo[_fd].mode;
260     __pioinfo[_fd].mode = _newmode;
261     return m;
262 }
263
264 int __fileno_getmode(int _fd)
265 {
266     if (_fd < 0 || _fd >= maxfno) {
267         __set_errno(EBADF);
268         return -1;
269     }
270     return __pioinfo[_fd].mode;
271
272 }
273
274 int __fileno_close(int _fd)
275 {
276     if (_fd < 0 || _fd >= maxfno) {
277         __set_errno(EBADF);
278         return -1;
279     }
280     __pioinfo[_fd].fd = -1;
281     __pioinfo[_fd].hFile = (HANDLE)-1;
282     return 0;
283 }
284
285 /*
286  * @implemented
287  */
288 int _open_osfhandle(void* osfhandle, int flags)
289 {
290     return __fileno_alloc((HANDLE)osfhandle, flags);
291 }
292
293 /*
294  * @implemented
295  */
296 void* _get_osfhandle( int fileno )
297 {
298     return filehnd(fileno);
299 }
300
301 int __fileno_dup2(int handle1, int handle2)
302 {
303    HANDLE hProcess;
304    BOOL result;
305    if (handle1 >= maxfno || handle1 < 0 || handle2 >= maxfno || handle2 < 0) {
306       __set_errno(EBADF);
307       return -1;
308    }
309    if (__pioinfo[handle1].fd == -1) {
310       __set_errno(EBADF);
311       return -1;
312    }
313    if (handle1 == handle2)
314       return handle1;
315    if (__pioinfo[handle2].fd != -1) {
316       _close(handle2);
317    }
318    hProcess = GetCurrentProcess();
319    result = DuplicateHandle(hProcess, 
320                 __pioinfo[handle1].hFile, 
321                 hProcess, 
322                 &__pioinfo[handle2].hFile, 
323                 0, 
324                 TRUE,  
325                 DUPLICATE_SAME_ACCESS);
326    if (result) {
327       __pioinfo[handle2].fd = handle2;
328       __pioinfo[handle2].mode = __pioinfo[handle1].mode;
329       switch (handle2) {
330       case 0:
331          SetStdHandle(STD_INPUT_HANDLE, __pioinfo[handle2].hFile);
332          break;
333       case 1:
334          SetStdHandle(STD_OUTPUT_HANDLE, __pioinfo[handle2].hFile);
335          break;
336       case 2:
337          SetStdHandle(STD_ERROR_HANDLE, __pioinfo[handle2].hFile);
338          break;
339       case 3:
340          SetStdHandle(STD_AUX_HANDLE, __pioinfo[handle2].hFile);
341          break;
342       case 4:
343          SetStdHandle(STD_AUX_HANDLE, __pioinfo[handle2].hFile);
344          break;
345       }
346       return handle1;
347    } else {
348       __set_errno(EMFILE);  // Is this the correct error no.?
349       return -1;
350    }
351 }
352
353
354 void* malloc(size_t sizeObject);
355
356 BOOL __fileno_init(void)
357 {
358    ULONG count = 0, i;
359    HANDLE* pFile;
360    char* pmode;
361    STARTUPINFOA StInfo;
362
363    GetStartupInfoA(&StInfo);
364    if (StInfo.lpReserved2 && StInfo.cbReserved2 >= sizeof(ULONG)) {
365       count = *(ULONG*)StInfo.lpReserved2;
366 /*
367       if (sizeof(ULONG) + count * (sizeof(HANDLE) + sizeof(char)) != StInfo.cbReserved2)
368       {
369           count = 0;
370       }
371 */
372    }
373    maxfno = 255;
374    while(count >= maxfno)
375       maxfno += 255;
376
377    {
378 #ifdef _OLD_BUILD_
379        // why was this here ???? - robd.
380        int result;
381        result = malloc(50);
382 #endif
383    }
384    //__pioinfo = (fileno_modes_type*)malloc(sizeof(fileno_modes_type) * maxfno);
385    __pioinfo = malloc(sizeof(fileno_modes_type) * maxfno);
386    if (__pioinfo == NULL) {
387        return FALSE;
388    }
389    memset(__pioinfo, -1, sizeof(fileno_modes_type) * maxfno);
390    if (count) {
391       pFile = (HANDLE*)(StInfo.lpReserved2 + sizeof(ULONG) + count * sizeof(char));
392       pmode = (char*)(StInfo.lpReserved2 + sizeof(ULONG));
393       for (i = 0; i <  count; i++) {
394           if (*pFile != INVALID_HANDLE_VALUE) {
395              __pioinfo[i].fd = i;
396              __pioinfo[i].mode = ((*pmode << 8) & (_O_TEXT|_O_BINARY)) | (*pmode & _O_ACCMODE);
397              __pioinfo[i].hFile = *pFile;
398           }
399           pFile++;
400           pmode++;
401       }
402    }
403    if (__pioinfo[0].fd == -1) {
404       __pioinfo[0].fd = 0;
405       __pioinfo[0].hFile = GetStdHandle(STD_INPUT_HANDLE);
406       __pioinfo[0].mode = _O_RDONLY|_O_TEXT;
407    }
408    if (__pioinfo[1].fd == -1) {
409       __pioinfo[1].fd = 1;
410       __pioinfo[1].hFile = GetStdHandle(STD_OUTPUT_HANDLE);
411       __pioinfo[1].mode = _O_WRONLY|_O_TEXT;
412    }
413    if (__pioinfo[2].fd == -1) {
414       __pioinfo[2].fd = 2;
415       __pioinfo[2].hFile = GetStdHandle(STD_ERROR_HANDLE);
416       __pioinfo[2].mode = _O_WRONLY|_O_TEXT;
417    }
418    if (__pioinfo[3].fd == -1) {
419       __pioinfo[3].fd = 3;
420       __pioinfo[3].hFile = GetStdHandle(STD_AUX_HANDLE);
421       __pioinfo[3].mode = _O_WRONLY|_O_TEXT;
422    }
423    if (__pioinfo[4].fd == -1) {
424       __pioinfo[4].fd = 4;
425       __pioinfo[4].hFile = GetStdHandle(STD_PRINTER_HANDLE);
426       __pioinfo[4].mode = _O_WRONLY|_O_TEXT;
427    }
428    return TRUE;
429 }