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