:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[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/crtdll/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 STD_AUX_HANDLE 3
33 #define STD_PRINTER_HANDLE 4
34
35 typedef struct _fileno_modes_type
36 {
37         HANDLE hFile;
38         int mode;
39         int fd;
40 } fileno_modes_type;
41
42 fileno_modes_type *fileno_modes = NULL;
43
44 int maxfno = 0;
45
46 char __is_text_file(FILE *p)
47 {
48    if ( p == NULL || fileno_modes == NULL )
49      return FALSE;
50    return (!((p)->_flag&_IOSTRG) && (fileno_modes[(p)->_file].mode&O_TEXT));
51 }
52
53
54 int _open(const char *_path, int _oflag,...)
55 {
56 #if !defined(NDEBUG) && defined(DBG)
57    va_list arg;
58    int pmode;
59 #endif
60    HANDLE hFile;
61    DWORD dwDesiredAccess = 0;
62    DWORD dwShareMode = 0;
63    DWORD dwCreationDistribution = 0;
64    DWORD dwFlagsAndAttributes = 0;
65    DWORD dwLastError;
66    SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
67
68 #if !defined(NDEBUG) && defined(DBG)
69    va_start(arg, _oflag);
70    pmode = va_arg(arg, int);
71 #endif
72
73    DPRINT("_open('%s', %x, (%x))\n", _path, _oflag, pmode);
74
75    if (( _oflag & S_IREAD ) == S_IREAD)
76      dwShareMode = FILE_SHARE_READ;
77    else if ( ( _oflag & S_IWRITE) == S_IWRITE ) {
78       dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
79    }
80
81    /*
82     *
83     * _O_BINARY   Opens file in binary (untranslated) mode. (See fopen for a description of binary mode.)
84     * _O_TEXT   Opens file in text (translated) mode. (For more information, see Text and Binary Mode File I/O and fopen.)
85     *
86     * _O_APPEND   Moves file pointer to end of file before every write operation.
87     */
88    if (( _oflag & _O_RDWR ) == _O_RDWR ) 
89      dwDesiredAccess |= GENERIC_WRITE|GENERIC_READ ;
90    else if (( _oflag & O_RDONLY ) == O_RDONLY ) 
91      dwDesiredAccess |= GENERIC_READ ;
92    else if (( _oflag & _O_WRONLY ) == _O_WRONLY )
93      dwDesiredAccess |= GENERIC_WRITE ;
94
95    if (( _oflag & S_IREAD ) == S_IREAD )
96      dwShareMode |= FILE_SHARE_READ;
97    
98    if (( _oflag & S_IWRITE ) == S_IWRITE )
99      dwShareMode |= FILE_SHARE_WRITE;   
100
101    if (( _oflag & (_O_CREAT | _O_EXCL ) ) == (_O_CREAT | _O_EXCL) )
102      dwCreationDistribution |= CREATE_NEW;
103
104    else if (( _oflag &  O_TRUNC ) == O_TRUNC  ) {
105       if (( _oflag &  O_CREAT ) ==  O_CREAT ) 
106         dwCreationDistribution |= CREATE_ALWAYS;
107       else if (( _oflag & O_RDONLY ) != O_RDONLY ) 
108         dwCreationDistribution |= TRUNCATE_EXISTING;
109    }
110    else if (( _oflag & _O_APPEND ) == _O_APPEND )
111      dwCreationDistribution |= OPEN_EXISTING;
112    else if (( _oflag &  _O_CREAT ) == _O_CREAT )
113      dwCreationDistribution |= OPEN_ALWAYS;
114    else
115      dwCreationDistribution |= OPEN_EXISTING;
116    
117    if (( _oflag &  _O_RANDOM ) == _O_RANDOM )
118      dwFlagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS;   
119    if (( _oflag &  _O_SEQUENTIAL ) == _O_SEQUENTIAL )
120      dwFlagsAndAttributes |= FILE_FLAG_SEQUENTIAL_SCAN;
121    
122    if (( _oflag &  _O_TEMPORARY ) == _O_TEMPORARY )
123    {
124      dwFlagsAndAttributes |= FILE_FLAG_DELETE_ON_CLOSE;
125      DPRINT("FILE_FLAG_DELETE_ON_CLOSE\n");
126    }
127    
128    if (( _oflag &  _O_SHORT_LIVED ) == _O_SHORT_LIVED )
129    {
130      dwFlagsAndAttributes |= FILE_FLAG_DELETE_ON_CLOSE;
131      DPRINT("FILE_FLAG_DELETE_ON_CLOSE\n");
132    }
133
134    if (_oflag & _O_NOINHERIT)
135      sa.bInheritHandle = FALSE;
136    
137    hFile = CreateFileA(_path,
138                        dwDesiredAccess,
139                        dwShareMode,     
140                        &sa, 
141                        dwCreationDistribution,  
142                        dwFlagsAndAttributes,
143                        NULL);
144    if (hFile == (HANDLE)-1)
145    {
146      dwLastError = GetLastError();
147      if (dwLastError == ERROR_ALREADY_EXISTS)
148      {
149         DPRINT("ERROR_ALREADY_EXISTS\n");
150         __set_errno(EEXIST);
151      }
152      else 
153      {
154         DPRINT("%x\n", dwLastError);
155         __set_errno(ENOFILE);
156      }
157      return -1;
158    }
159    DPRINT("OK\n");
160    if (!(_oflag & (_O_TEXT|_O_BINARY)))
161    {
162            _oflag |= _fmode;
163    }
164    return  __fileno_alloc(hFile,_oflag);
165 }
166
167
168 int _wopen(const wchar_t *_path, int _oflag,...)
169 {
170 #if !defined(NDEBUG) && defined(DBG)
171    va_list arg;
172    int pmode;
173 #endif
174    HANDLE hFile;
175    DWORD dwDesiredAccess = 0;
176    DWORD dwShareMode = 0;
177    DWORD dwCreationDistribution = 0;
178    DWORD dwFlagsAndAttributes = 0;
179    SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
180
181 #if !defined(NDEBUG) && defined(DBG)
182    va_start(arg, _oflag);
183    pmode = va_arg(arg, int);
184 #endif
185
186    DPRINT("_wopen('%S', %x, (%x))\n", _path, _oflag, pmode);
187
188    if (( _oflag & S_IREAD ) == S_IREAD)
189      dwShareMode = FILE_SHARE_READ;
190    else if ( ( _oflag & S_IWRITE) == S_IWRITE ) {
191       dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
192    }
193
194    /*
195     *
196     * _O_BINARY   Opens file in binary (untranslated) mode. (See fopen for a description of binary mode.)
197     * _O_TEXT   Opens file in text (translated) mode. (For more information, see Text and Binary Mode File I/O and fopen.)
198     * 
199     * _O_APPEND   Moves file pointer to end of file before every write operation.
200     */
201    if (( _oflag & _O_RDWR ) == _O_RDWR )
202      dwDesiredAccess |= GENERIC_WRITE|GENERIC_READ | FILE_READ_DATA |
203                         FILE_WRITE_DATA | FILE_READ_ATTRIBUTES |
204                         FILE_WRITE_ATTRIBUTES;
205    else if (( _oflag & O_RDONLY ) == O_RDONLY )
206      dwDesiredAccess |= GENERIC_READ | FILE_READ_DATA | FILE_READ_ATTRIBUTES
207                      | FILE_WRITE_ATTRIBUTES;
208    else if (( _oflag & _O_WRONLY ) == _O_WRONLY )
209      dwDesiredAccess |= GENERIC_WRITE | FILE_WRITE_DATA |
210                         FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES;
211
212    if (( _oflag & S_IREAD ) == S_IREAD )
213      dwShareMode |= FILE_SHARE_READ;
214    
215    if (( _oflag & S_IWRITE ) == S_IWRITE )
216      dwShareMode |= FILE_SHARE_WRITE;
217
218    if (( _oflag & (_O_CREAT | _O_EXCL ) ) == (_O_CREAT | _O_EXCL) )
219      dwCreationDistribution |= CREATE_NEW;
220
221    else if (( _oflag &  O_TRUNC ) == O_TRUNC  ) {
222       if (( _oflag &  O_CREAT ) ==  O_CREAT )
223         dwCreationDistribution |= CREATE_ALWAYS;
224       else if (( _oflag & O_RDONLY ) != O_RDONLY )
225         dwCreationDistribution |= TRUNCATE_EXISTING;
226    }
227    else if (( _oflag & _O_APPEND ) == _O_APPEND )
228      dwCreationDistribution |= OPEN_EXISTING;
229    else if (( _oflag &  _O_CREAT ) == _O_CREAT )
230      dwCreationDistribution |= OPEN_ALWAYS;
231    else
232      dwCreationDistribution |= OPEN_EXISTING;
233    
234    if (( _oflag &  _O_RANDOM ) == _O_RANDOM )
235      dwFlagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS;
236    if (( _oflag &  _O_SEQUENTIAL ) == _O_SEQUENTIAL )
237      dwFlagsAndAttributes |= FILE_FLAG_SEQUENTIAL_SCAN;
238    
239    if (( _oflag &  _O_TEMPORARY ) == _O_TEMPORARY )
240      dwFlagsAndAttributes |= FILE_FLAG_DELETE_ON_CLOSE;
241    
242    if (( _oflag &  _O_SHORT_LIVED ) == _O_SHORT_LIVED )
243      dwFlagsAndAttributes |= FILE_FLAG_DELETE_ON_CLOSE;
244    
245    if (_oflag & _O_NOINHERIT)
246      sa.bInheritHandle = FALSE;
247
248    hFile = CreateFileW(_path,
249                        dwDesiredAccess,
250                        dwShareMode,
251                        &sa,
252                        dwCreationDistribution,
253                        dwFlagsAndAttributes,
254                        NULL);
255    if (hFile == (HANDLE)-1)
256      return -1;
257    return __fileno_alloc(hFile,_oflag);
258 }
259
260
261 int
262 __fileno_alloc(HANDLE hFile, int mode)
263 {
264   int i;
265   /* Check for bogus values */
266   if (hFile < 0)
267         return -1;
268
269   for(i=5;i<maxfno;i++) {
270         if (fileno_modes[i].fd == -1 ) {
271                 fileno_modes[i].fd = i;
272                 fileno_modes[i].mode = mode;
273                 fileno_modes[i].hFile = hFile;
274                 return i;
275         }
276   }
277
278   /* See if we need to expand the tables.  Check this BEFORE it might fail,
279      so that when we hit the count'th request, we've already up'd it. */
280   if ( i == maxfno)
281   {
282     int oldcount = maxfno;
283     fileno_modes_type *old_fileno_modes = fileno_modes;
284         maxfno  += 255;
285     fileno_modes = (fileno_modes_type *)malloc(maxfno * sizeof(fileno_modes_type));
286     if ( old_fileno_modes != NULL )
287     {
288         memcpy(fileno_modes, old_fileno_modes, oldcount * sizeof(fileno_modes_type));
289         free ( old_fileno_modes );
290     }
291     memset(fileno_modes + oldcount, -1, (maxfno-oldcount)*sizeof(fileno_modes_type));
292   }
293
294   /* Fill in the value */
295   fileno_modes[i].fd = i;
296   fileno_modes[i].mode = mode;
297   fileno_modes[i].hFile = hFile;
298   return i;
299 }
300
301 void *filehnd(int fileno)
302 {
303         if ( fileno < 0 || fileno>= maxfno || fileno_modes[fileno].fd == -1)
304         {
305                 return (void *)-1;
306         }
307         return fileno_modes[fileno].hFile;
308 }
309
310 int __fileno_dup2( int handle1, int handle2 )
311 {
312    HANDLE hProcess;
313    BOOL result;
314    if (handle1 >= maxfno || handle1 < 0 || handle2 >= maxfno || handle2 < 0 )
315    {
316       __set_errno(EBADF);
317       return -1;
318    }
319    if (fileno_modes[handle1].fd == -1)
320    {
321       __set_errno(EBADF);
322       return -1;
323    }
324    if (handle1 == handle2)
325       return handle1;
326    if (fileno_modes[handle2].fd != -1)
327    {
328       _close(handle2);
329    }
330    hProcess = GetCurrentProcess();
331    result = DuplicateHandle(hProcess, 
332                             fileno_modes[handle1].hFile, 
333                             hProcess, 
334                             &fileno_modes[handle2].hFile, 
335                             0, 
336                             TRUE,  
337                             DUPLICATE_SAME_ACCESS);
338    if (result)
339    {
340       fileno_modes[handle2].fd = handle2;
341       fileno_modes[handle2].mode = fileno_modes[handle1].mode;
342       switch (handle2)
343       {
344          case 0:
345             SetStdHandle(STD_INPUT_HANDLE, fileno_modes[handle2].hFile);
346             break;
347          case 1:
348             SetStdHandle(STD_OUTPUT_HANDLE, fileno_modes[handle2].hFile);
349             break;
350          case 2:
351             SetStdHandle(STD_ERROR_HANDLE, fileno_modes[handle2].hFile);
352             break;
353          case 3:
354             SetStdHandle(STD_AUX_HANDLE, fileno_modes[handle2].hFile);
355             break;
356          case 4:
357             SetStdHandle(STD_AUX_HANDLE, fileno_modes[handle2].hFile);
358             break;
359       }
360       return handle1;
361    }
362    else
363    {
364       __set_errno(EMFILE);      // Is this the correct error no.?
365       return -1;
366    }
367 }
368
369 int __fileno_setmode(int _fd, int _newmode)
370 {
371         int m;
372         if ( _fd < 0 || _fd >= maxfno )
373         {
374                 __set_errno(EBADF);
375                 return -1;
376         }
377
378         m = fileno_modes[_fd].mode;
379         fileno_modes[_fd].mode = _newmode;
380         return m;
381 }
382
383 int __fileno_getmode(int _fd)
384 {
385         if ( _fd < 0 || _fd >= maxfno )
386         {
387                 __set_errno(EBADF);
388                 return -1;
389         }
390         return fileno_modes[_fd].mode;
391
392 }
393
394 int __fileno_close(int _fd)
395 {
396         if ( _fd < 0 || _fd >= maxfno )
397         {
398                 __set_errno(EBADF);
399                 return -1;
400         }
401
402         fileno_modes[_fd].fd = -1;
403         fileno_modes[_fd].hFile = (HANDLE)-1;
404         return 0;
405 }
406
407 int _open_osfhandle (void *osfhandle, int flags )
408 {
409         return __fileno_alloc((HANDLE)osfhandle, flags);
410 }
411
412 void *_get_osfhandle( int fileno )
413 {
414         return filehnd(fileno);
415 }
416
417 void __fileno_init(void)
418 {
419    ULONG count = 0, i;
420    HANDLE *pFile;
421    char* pmode;
422    STARTUPINFO StInfo;
423
424    GetStartupInfoA(&StInfo);
425
426    if (StInfo.lpReserved2 && StInfo.cbReserved2 >= sizeof(ULONG))
427    {
428       count = *(ULONG*)StInfo.lpReserved2;
429 /*
430       if (sizeof(ULONG) + count * (sizeof(HANDLE) + sizeof(char)) != StInfo.cbReserved2)
431       {
432           count = 0;
433       }
434 */
435    }
436    maxfno = 255;
437    while(count >= maxfno)
438       maxfno += 255;
439
440    fileno_modes = (fileno_modes_type*)malloc(sizeof(fileno_modes_type) * maxfno);
441    memset(fileno_modes, -1, sizeof(fileno_modes_type) * maxfno);
442
443    if (count)
444    {
445       pFile = (HANDLE*)(StInfo.lpReserved2 + sizeof(ULONG) + count * sizeof(char));
446       pmode = (char*)(StInfo.lpReserved2 + sizeof(ULONG));
447       for (i = 0; i <  count; i++)
448       {
449           if (*pFile != INVALID_HANDLE_VALUE)
450           {
451              fileno_modes[i].fd = i;
452              fileno_modes[i].mode = ((*pmode << 8) & (_O_TEXT|_O_BINARY)) | (*pmode & _O_ACCMODE);
453              fileno_modes[i].hFile = *pFile;
454           }
455           pFile++;
456           pmode++;
457       }
458    }
459
460    if (fileno_modes[0].fd == -1)
461    {
462       fileno_modes[0].fd = 0;
463       fileno_modes[0].hFile = GetStdHandle(STD_INPUT_HANDLE);
464       fileno_modes[0].mode = _O_RDONLY|_O_TEXT;
465    }
466    if (fileno_modes[1].fd == -1)
467    {
468       fileno_modes[1].fd = 1;
469       fileno_modes[1].hFile = GetStdHandle(STD_OUTPUT_HANDLE);
470       fileno_modes[1].mode = _O_WRONLY|_O_TEXT;
471    }
472    if (fileno_modes[2].fd == -1)
473    {
474       fileno_modes[2].fd = 2;
475       fileno_modes[2].hFile = GetStdHandle(STD_ERROR_HANDLE);
476       fileno_modes[2].mode = _O_WRONLY|_O_TEXT;
477    }
478    if (fileno_modes[3].fd == -1)
479    {
480       fileno_modes[3].fd = 3;
481       fileno_modes[3].hFile = GetStdHandle(STD_AUX_HANDLE);
482       fileno_modes[3].mode = _O_WRONLY|_O_TEXT;
483    }
484    if (fileno_modes[4].fd == -1)
485    {
486       fileno_modes[4].fd = 4;
487       fileno_modes[4].hFile = GetStdHandle(STD_PRINTER_HANDLE);
488       fileno_modes[4].mode = _O_WRONLY|_O_TEXT;
489    }
490 }