update for HEAD-2003021201
[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 int _open(const char* _path, int _oflag,...)
95 {
96 #if !defined(NDEBUG) && defined(DBG)
97    va_list arg;
98    int pmode;
99 #endif
100    HANDLE hFile;
101    DWORD dwDesiredAccess = 0;
102    DWORD dwShareMode = 0;
103    DWORD dwCreationDistribution = 0;
104    DWORD dwFlagsAndAttributes = 0;
105    DWORD dwLastError;
106    SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
107
108 #if !defined(NDEBUG) && defined(DBG)
109    va_start(arg, _oflag);
110    pmode = va_arg(arg, int);
111 #endif
112
113 //   DPRINT("_open('%s', %x, (%x))\n", _path, _oflag, pmode);
114
115    if ((_oflag & S_IREAD ) == S_IREAD)
116      dwShareMode = FILE_SHARE_READ;
117    else if ((_oflag & S_IWRITE) == S_IWRITE) {
118       dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
119    }
120    /*
121     *
122     * _O_BINARY   Opens file in binary (untranslated) mode. (See fopen for a description of binary mode.)
123     * _O_TEXT   Opens file in text (translated) mode. (For more information, see Text and Binary Mode File I/O and fopen.)
124     *
125     * _O_APPEND   Moves file pointer to end of file before every write operation.
126     */
127 #ifdef _OLD_BUILD_
128    if ((_oflag & _O_RDWR) == _O_RDWR)
129      dwDesiredAccess |= GENERIC_WRITE|GENERIC_READ;
130    else if ((_oflag & O_RDONLY) == O_RDONLY)
131      dwDesiredAccess |= GENERIC_READ;
132    else if ((_oflag & _O_WRONLY) == _O_WRONLY)
133      dwDesiredAccess |= GENERIC_WRITE ;
134 #else
135    if ((_oflag & _O_WRONLY) == _O_WRONLY )
136      dwDesiredAccess |= GENERIC_WRITE ;
137    else if ((_oflag & _O_RDWR) == _O_RDWR )
138      dwDesiredAccess |= GENERIC_WRITE|GENERIC_READ;
139    else //if ((_oflag & O_RDONLY) == O_RDONLY)
140      dwDesiredAccess |= GENERIC_READ;
141 #endif
142    if (( _oflag & S_IREAD ) == S_IREAD)
143      dwShareMode |= FILE_SHARE_READ;
144    
145    if (( _oflag & S_IWRITE ) == S_IWRITE)
146      dwShareMode |= FILE_SHARE_WRITE;
147
148    if (( _oflag & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL))
149      dwCreationDistribution |= CREATE_NEW;
150
151    else if ((_oflag &  O_TRUNC ) == O_TRUNC) {
152       if ((_oflag &  O_CREAT ) ==  O_CREAT)
153     dwCreationDistribution |= CREATE_ALWAYS;
154       else if ((_oflag & O_RDONLY ) != O_RDONLY)
155     dwCreationDistribution |= TRUNCATE_EXISTING;
156    }
157    else if ((_oflag & _O_APPEND) == _O_APPEND)
158      dwCreationDistribution |= OPEN_EXISTING;
159    else if ((_oflag &  _O_CREAT) == _O_CREAT)
160      dwCreationDistribution |= OPEN_ALWAYS;
161    else
162      dwCreationDistribution |= OPEN_EXISTING;
163
164    if ((_oflag &  _O_RANDOM) == _O_RANDOM )
165      dwFlagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS;
166    if ((_oflag &  _O_SEQUENTIAL) == _O_SEQUENTIAL)
167      dwFlagsAndAttributes |= FILE_FLAG_SEQUENTIAL_SCAN;
168    if ((_oflag &  _O_TEMPORARY) == _O_TEMPORARY) {
169      dwFlagsAndAttributes |= FILE_FLAG_DELETE_ON_CLOSE;
170      DPRINT("FILE_FLAG_DELETE_ON_CLOSE\n");
171    }
172    if ((_oflag &  _O_SHORT_LIVED) == _O_SHORT_LIVED) {
173      dwFlagsAndAttributes |= FILE_FLAG_DELETE_ON_CLOSE;
174      DPRINT("FILE_FLAG_DELETE_ON_CLOSE\n");
175    }
176    if (_oflag & _O_NOINHERIT)
177      sa.bInheritHandle = FALSE;
178    hFile = CreateFileA(_path,
179                dwDesiredAccess,
180                dwShareMode, 
181                &sa,
182                dwCreationDistribution,
183                dwFlagsAndAttributes,
184                NULL);
185    if (hFile == (HANDLE)-1) {
186      dwLastError = GetLastError();
187      if (dwLastError == ERROR_ALREADY_EXISTS) {
188         DPRINT("ERROR_ALREADY_EXISTS\n");
189         __set_errno(EEXIST);
190      } else {
191         DPRINT("%x\n", dwLastError);
192         __set_errno(ENOFILE);
193      }
194      return -1;
195    }
196    DPRINT("OK\n");
197    if (!(_oflag & (_O_TEXT|_O_BINARY))) {
198        _oflag |= _fmode;
199    }
200    return __fileno_alloc(hFile,_oflag);
201 }
202
203
204 int __fileno_alloc(HANDLE hFile, int mode)
205 {
206   int i;
207   /* Check for bogus values */
208   if (hFile < 0)
209     return -1;
210
211   for (i = 5; i < maxfno; i++) {
212     if (__pioinfo[i].fd == -1 ) {
213         __pioinfo[i].fd = i;
214         __pioinfo[i].mode = mode;
215         __pioinfo[i].hFile = hFile;
216         return i;
217     }
218   }
219
220   /* See if we need to expand the tables.  Check this BEFORE it might fail,
221      so that when we hit the count'th request, we've already up'd it. */
222   if (i == maxfno) {
223     int oldcount = maxfno;
224     fileno_modes_type* old_fileno_modes = __pioinfo;
225     maxfno += 255;
226     __pioinfo = (fileno_modes_type*)malloc(maxfno * sizeof(fileno_modes_type));
227     if (old_fileno_modes != NULL) {
228         memcpy(__pioinfo, old_fileno_modes, oldcount * sizeof(fileno_modes_type));
229         free(old_fileno_modes);
230     }
231     memset(__pioinfo + oldcount, -1, (maxfno-oldcount)*sizeof(fileno_modes_type));
232   }
233
234   /* Fill in the value */
235   __pioinfo[i].fd = i;
236   __pioinfo[i].mode = mode;
237   __pioinfo[i].hFile = hFile;
238   return i;
239 }
240
241 void* filehnd(int fileno)
242 {
243     if (fileno < 0 || fileno >= maxfno || __pioinfo[fileno].fd == -1) {
244         return (void*)-1;
245     }
246     return __pioinfo[fileno].hFile;
247 }
248
249 int __fileno_setmode(int _fd, int _newmode)
250 {
251     int m;
252     if (_fd < 0 || _fd >= maxfno) {
253         __set_errno(EBADF);
254         return -1;
255     }
256     m = __pioinfo[_fd].mode;
257     __pioinfo[_fd].mode = _newmode;
258     return m;
259 }
260
261 int __fileno_getmode(int _fd)
262 {
263     if (_fd < 0 || _fd >= maxfno) {
264         __set_errno(EBADF);
265         return -1;
266     }
267     return __pioinfo[_fd].mode;
268
269 }
270
271 int __fileno_close(int _fd)
272 {
273     if (_fd < 0 || _fd >= maxfno) {
274         __set_errno(EBADF);
275         return -1;
276     }
277     __pioinfo[_fd].fd = -1;
278     __pioinfo[_fd].hFile = (HANDLE)-1;
279     return 0;
280 }
281
282 int _open_osfhandle(void* osfhandle, int flags)
283 {
284     return __fileno_alloc((HANDLE)osfhandle, flags);
285 }
286
287 void* _get_osfhandle( int fileno )
288 {
289     return filehnd(fileno);
290 }
291
292 int __fileno_dup2(int handle1, int handle2)
293 {
294    HANDLE hProcess;
295    BOOL result;
296    if (handle1 >= maxfno || handle1 < 0 || handle2 >= maxfno || handle2 < 0) {
297       __set_errno(EBADF);
298       return -1;
299    }
300    if (__pioinfo[handle1].fd == -1) {
301       __set_errno(EBADF);
302       return -1;
303    }
304    if (handle1 == handle2)
305       return handle1;
306    if (__pioinfo[handle2].fd != -1) {
307       _close(handle2);
308    }
309    hProcess = GetCurrentProcess();
310    result = DuplicateHandle(hProcess, 
311                 __pioinfo[handle1].hFile, 
312                 hProcess, 
313                 &__pioinfo[handle2].hFile, 
314                 0, 
315                 TRUE,  
316                 DUPLICATE_SAME_ACCESS);
317    if (result) {
318       __pioinfo[handle2].fd = handle2;
319       __pioinfo[handle2].mode = __pioinfo[handle1].mode;
320       switch (handle2) {
321       case 0:
322          SetStdHandle(STD_INPUT_HANDLE, __pioinfo[handle2].hFile);
323          break;
324       case 1:
325          SetStdHandle(STD_OUTPUT_HANDLE, __pioinfo[handle2].hFile);
326          break;
327       case 2:
328          SetStdHandle(STD_ERROR_HANDLE, __pioinfo[handle2].hFile);
329          break;
330       case 3:
331          SetStdHandle(STD_AUX_HANDLE, __pioinfo[handle2].hFile);
332          break;
333       case 4:
334          SetStdHandle(STD_AUX_HANDLE, __pioinfo[handle2].hFile);
335          break;
336       }
337       return handle1;
338    } else {
339       __set_errno(EMFILE);  // Is this the correct error no.?
340       return -1;
341    }
342 }
343
344
345 void* malloc(size_t sizeObject);
346
347 BOOL __fileno_init(void)
348 {
349    ULONG count = 0, i;
350    HANDLE* pFile;
351    char* pmode;
352    STARTUPINFO StInfo;
353
354    GetStartupInfoA(&StInfo);
355    if (StInfo.lpReserved2 && StInfo.cbReserved2 >= sizeof(ULONG)) {
356       count = *(ULONG*)StInfo.lpReserved2;
357 /*
358       if (sizeof(ULONG) + count * (sizeof(HANDLE) + sizeof(char)) != StInfo.cbReserved2)
359       {
360           count = 0;
361       }
362 */
363    }
364    maxfno = 255;
365    while(count >= maxfno)
366       maxfno += 255;
367
368    {
369 #ifdef _OLD_BUILD_
370        // why was this here ???? - robd.
371        int result;
372        result = malloc(50);
373 #endif
374    }
375    //__pioinfo = (fileno_modes_type*)malloc(sizeof(fileno_modes_type) * maxfno);
376    __pioinfo = malloc(sizeof(fileno_modes_type) * maxfno);
377    if (__pioinfo == NULL) {
378        return FALSE;
379    }
380    memset(__pioinfo, -1, sizeof(fileno_modes_type) * maxfno);
381    if (count) {
382       pFile = (HANDLE*)(StInfo.lpReserved2 + sizeof(ULONG) + count * sizeof(char));
383       pmode = (char*)(StInfo.lpReserved2 + sizeof(ULONG));
384       for (i = 0; i <  count; i++) {
385           if (*pFile != INVALID_HANDLE_VALUE) {
386              __pioinfo[i].fd = i;
387              __pioinfo[i].mode = ((*pmode << 8) & (_O_TEXT|_O_BINARY)) | (*pmode & _O_ACCMODE);
388              __pioinfo[i].hFile = *pFile;
389           }
390           pFile++;
391           pmode++;
392       }
393    }
394    if (__pioinfo[0].fd == -1) {
395       __pioinfo[0].fd = 0;
396       __pioinfo[0].hFile = GetStdHandle(STD_INPUT_HANDLE);
397       __pioinfo[0].mode = _O_RDONLY|_O_TEXT;
398    }
399    if (__pioinfo[1].fd == -1) {
400       __pioinfo[1].fd = 1;
401       __pioinfo[1].hFile = GetStdHandle(STD_OUTPUT_HANDLE);
402       __pioinfo[1].mode = _O_WRONLY|_O_TEXT;
403    }
404    if (__pioinfo[2].fd == -1) {
405       __pioinfo[2].fd = 2;
406       __pioinfo[2].hFile = GetStdHandle(STD_ERROR_HANDLE);
407       __pioinfo[2].mode = _O_WRONLY|_O_TEXT;
408    }
409    if (__pioinfo[3].fd == -1) {
410       __pioinfo[3].fd = 3;
411       __pioinfo[3].hFile = GetStdHandle(STD_AUX_HANDLE);
412       __pioinfo[3].mode = _O_WRONLY|_O_TEXT;
413    }
414    if (__pioinfo[4].fd == -1) {
415       __pioinfo[4].fd = 4;
416       __pioinfo[4].hFile = GetStdHandle(STD_PRINTER_HANDLE);
417       __pioinfo[4].mode = _O_WRONLY|_O_TEXT;
418    }
419    return TRUE;
420 }