Improved unicode fileio support.
[reactos.git] / reactos / lib / msvcrt / io / open.c
1 /* $Id: open.c,v 1.13 2002/12/05 15:30:44 robd Exp $
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 typedef struct _fileno_modes_type
38 {
39 HANDLE hFile;
40 int mode;
41 int fd;
42 } fileno_modes_type;
43
44 static fileno_modes_type* fileno_modes = NULL;
45
46 int maxfno = 0;
47
48 char __is_text_file(FILE* p)
49 {
50 if ( p == NULL || fileno_modes == NULL )
51 return FALSE;
52 return (!((p)->_flag&_IOSTRG) && (fileno_modes[(p)->_file].mode&O_TEXT));
53 }
54
55 int _open(const char* _path, int _oflag,...)
56 {
57 #if !defined(NDEBUG) && defined(DBG)
58 va_list arg;
59 int pmode;
60 #endif
61 HANDLE hFile;
62 DWORD dwDesiredAccess = 0;
63 DWORD dwShareMode = 0;
64 DWORD dwCreationDistribution = 0;
65 DWORD dwFlagsAndAttributes = 0;
66 DWORD dwLastError;
67 SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
68
69 #if !defined(NDEBUG) && defined(DBG)
70 va_start(arg, _oflag);
71 pmode = va_arg(arg, int);
72 #endif
73
74 // DPRINT("_open('%s', %x, (%x))\n", _path, _oflag, pmode);
75
76 if ((_oflag & S_IREAD ) == S_IREAD)
77 dwShareMode = FILE_SHARE_READ;
78 else if ((_oflag & S_IWRITE) == S_IWRITE) {
79 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
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 #ifdef _OLD_BUILD_
89 if ((_oflag & _O_RDWR) == _O_RDWR)
90 dwDesiredAccess |= GENERIC_WRITE|GENERIC_READ;
91 else if ((_oflag & O_RDONLY) == O_RDONLY)
92 dwDesiredAccess |= GENERIC_READ;
93 else if ((_oflag & _O_WRONLY) == _O_WRONLY)
94 dwDesiredAccess |= GENERIC_WRITE ;
95 #else
96 if ((_oflag & _O_WRONLY) == _O_WRONLY )
97 dwDesiredAccess |= GENERIC_WRITE ;
98 else if ((_oflag & _O_RDWR) == _O_RDWR )
99 dwDesiredAccess |= GENERIC_WRITE|GENERIC_READ;
100 else //if ((_oflag & O_RDONLY) == O_RDONLY)
101 dwDesiredAccess |= GENERIC_READ;
102 #endif
103 if (( _oflag & S_IREAD ) == S_IREAD)
104 dwShareMode |= FILE_SHARE_READ;
105
106 if (( _oflag & S_IWRITE ) == S_IWRITE)
107 dwShareMode |= FILE_SHARE_WRITE;
108
109 if (( _oflag & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL))
110 dwCreationDistribution |= CREATE_NEW;
111
112 else if ((_oflag & O_TRUNC ) == O_TRUNC) {
113 if ((_oflag & O_CREAT ) == O_CREAT)
114 dwCreationDistribution |= CREATE_ALWAYS;
115 else if ((_oflag & O_RDONLY ) != O_RDONLY)
116 dwCreationDistribution |= TRUNCATE_EXISTING;
117 }
118 else if ((_oflag & _O_APPEND) == _O_APPEND)
119 dwCreationDistribution |= OPEN_EXISTING;
120 else if ((_oflag & _O_CREAT) == _O_CREAT)
121 dwCreationDistribution |= OPEN_ALWAYS;
122 else
123 dwCreationDistribution |= OPEN_EXISTING;
124
125 if ((_oflag & _O_RANDOM) == _O_RANDOM )
126 dwFlagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS;
127 if ((_oflag & _O_SEQUENTIAL) == _O_SEQUENTIAL)
128 dwFlagsAndAttributes |= FILE_FLAG_SEQUENTIAL_SCAN;
129 if ((_oflag & _O_TEMPORARY) == _O_TEMPORARY) {
130 dwFlagsAndAttributes |= FILE_FLAG_DELETE_ON_CLOSE;
131 DPRINT("FILE_FLAG_DELETE_ON_CLOSE\n");
132 }
133 if ((_oflag & _O_SHORT_LIVED) == _O_SHORT_LIVED) {
134 dwFlagsAndAttributes |= FILE_FLAG_DELETE_ON_CLOSE;
135 DPRINT("FILE_FLAG_DELETE_ON_CLOSE\n");
136 }
137 if (_oflag & _O_NOINHERIT)
138 sa.bInheritHandle = FALSE;
139 hFile = CreateFileA(_path,
140 dwDesiredAccess,
141 dwShareMode,
142 &sa,
143 dwCreationDistribution,
144 dwFlagsAndAttributes,
145 NULL);
146 if (hFile == (HANDLE)-1) {
147 dwLastError = GetLastError();
148 if (dwLastError == ERROR_ALREADY_EXISTS) {
149 DPRINT("ERROR_ALREADY_EXISTS\n");
150 __set_errno(EEXIST);
151 } else {
152 DPRINT("%x\n", dwLastError);
153 __set_errno(ENOFILE);
154 }
155 return -1;
156 }
157 DPRINT("OK\n");
158 if (!(_oflag & (_O_TEXT|_O_BINARY))) {
159 _oflag |= _fmode;
160 }
161 return __fileno_alloc(hFile,_oflag);
162 }
163
164
165 int __fileno_alloc(HANDLE hFile, int mode)
166 {
167 int i;
168 /* Check for bogus values */
169 if (hFile < 0)
170 return -1;
171
172 for (i = 5; i < maxfno; i++) {
173 if (fileno_modes[i].fd == -1 ) {
174 fileno_modes[i].fd = i;
175 fileno_modes[i].mode = mode;
176 fileno_modes[i].hFile = hFile;
177 return i;
178 }
179 }
180
181 /* See if we need to expand the tables. Check this BEFORE it might fail,
182 so that when we hit the count'th request, we've already up'd it. */
183 if (i == maxfno) {
184 int oldcount = maxfno;
185 fileno_modes_type* old_fileno_modes = fileno_modes;
186 maxfno += 255;
187 fileno_modes = (fileno_modes_type*)malloc(maxfno * sizeof(fileno_modes_type));
188 if (old_fileno_modes != NULL) {
189 memcpy(fileno_modes, old_fileno_modes, oldcount * sizeof(fileno_modes_type));
190 free(old_fileno_modes);
191 }
192 memset(fileno_modes + oldcount, -1, (maxfno-oldcount)*sizeof(fileno_modes_type));
193 }
194
195 /* Fill in the value */
196 fileno_modes[i].fd = i;
197 fileno_modes[i].mode = mode;
198 fileno_modes[i].hFile = hFile;
199 return i;
200 }
201
202 void* filehnd(int fileno)
203 {
204 if (fileno < 0 || fileno >= maxfno || fileno_modes[fileno].fd == -1) {
205 return (void*)-1;
206 }
207 return fileno_modes[fileno].hFile;
208 }
209
210 int __fileno_setmode(int _fd, int _newmode)
211 {
212 int m;
213 if (_fd < 0 || _fd >= maxfno) {
214 __set_errno(EBADF);
215 return -1;
216 }
217 m = fileno_modes[_fd].mode;
218 fileno_modes[_fd].mode = _newmode;
219 return m;
220 }
221
222 int __fileno_getmode(int _fd)
223 {
224 if (_fd < 0 || _fd >= maxfno) {
225 __set_errno(EBADF);
226 return -1;
227 }
228 return fileno_modes[_fd].mode;
229
230 }
231
232 int __fileno_close(int _fd)
233 {
234 if (_fd < 0 || _fd >= maxfno) {
235 __set_errno(EBADF);
236 return -1;
237 }
238 fileno_modes[_fd].fd = -1;
239 fileno_modes[_fd].hFile = (HANDLE)-1;
240 return 0;
241 }
242
243 int _open_osfhandle(void* osfhandle, int flags)
244 {
245 return __fileno_alloc((HANDLE)osfhandle, flags);
246 }
247
248 void* _get_osfhandle( int fileno )
249 {
250 return filehnd(fileno);
251 }
252
253 int __fileno_dup2(int handle1, int handle2)
254 {
255 HANDLE hProcess;
256 BOOL result;
257 if (handle1 >= maxfno || handle1 < 0 || handle2 >= maxfno || handle2 < 0) {
258 __set_errno(EBADF);
259 return -1;
260 }
261 if (fileno_modes[handle1].fd == -1) {
262 __set_errno(EBADF);
263 return -1;
264 }
265 if (handle1 == handle2)
266 return handle1;
267 if (fileno_modes[handle2].fd != -1) {
268 _close(handle2);
269 }
270 hProcess = GetCurrentProcess();
271 result = DuplicateHandle(hProcess,
272 fileno_modes[handle1].hFile,
273 hProcess,
274 &fileno_modes[handle2].hFile,
275 0,
276 TRUE,
277 DUPLICATE_SAME_ACCESS);
278 if (result) {
279 fileno_modes[handle2].fd = handle2;
280 fileno_modes[handle2].mode = fileno_modes[handle1].mode;
281 switch (handle2) {
282 case 0:
283 SetStdHandle(STD_INPUT_HANDLE, fileno_modes[handle2].hFile);
284 break;
285 case 1:
286 SetStdHandle(STD_OUTPUT_HANDLE, fileno_modes[handle2].hFile);
287 break;
288 case 2:
289 SetStdHandle(STD_ERROR_HANDLE, fileno_modes[handle2].hFile);
290 break;
291 case 3:
292 SetStdHandle(STD_AUX_HANDLE, fileno_modes[handle2].hFile);
293 break;
294 case 4:
295 SetStdHandle(STD_AUX_HANDLE, fileno_modes[handle2].hFile);
296 break;
297 }
298 return handle1;
299 } else {
300 __set_errno(EMFILE); // Is this the correct error no.?
301 return -1;
302 }
303 }
304
305
306 void* malloc(size_t sizeObject);
307
308 BOOL __fileno_init(void)
309 {
310 ULONG count = 0, i;
311 HANDLE* pFile;
312 char* pmode;
313 STARTUPINFO StInfo;
314
315 GetStartupInfoA(&StInfo);
316 if (StInfo.lpReserved2 && StInfo.cbReserved2 >= sizeof(ULONG)) {
317 count = *(ULONG*)StInfo.lpReserved2;
318 /*
319 if (sizeof(ULONG) + count * (sizeof(HANDLE) + sizeof(char)) != StInfo.cbReserved2)
320 {
321 count = 0;
322 }
323 */
324 }
325 maxfno = 255;
326 while(count >= maxfno)
327 maxfno += 255;
328
329 {
330 #ifdef _OLD_BUILD_
331 // why was this here ???? - robd.
332 int result;
333 result = malloc(50);
334 #endif
335 }
336 //fileno_modes = (fileno_modes_type*)malloc(sizeof(fileno_modes_type) * maxfno);
337 fileno_modes = malloc(sizeof(fileno_modes_type) * maxfno);
338 if (fileno_modes == NULL) {
339 return FALSE;
340 }
341 memset(fileno_modes, -1, sizeof(fileno_modes_type) * maxfno);
342 if (count) {
343 pFile = (HANDLE*)(StInfo.lpReserved2 + sizeof(ULONG) + count * sizeof(char));
344 pmode = (char*)(StInfo.lpReserved2 + sizeof(ULONG));
345 for (i = 0; i < count; i++) {
346 if (*pFile != INVALID_HANDLE_VALUE) {
347 fileno_modes[i].fd = i;
348 fileno_modes[i].mode = ((*pmode << 8) & (_O_TEXT|_O_BINARY)) | (*pmode & _O_ACCMODE);
349 fileno_modes[i].hFile = *pFile;
350 }
351 pFile++;
352 pmode++;
353 }
354 }
355 if (fileno_modes[0].fd == -1) {
356 fileno_modes[0].fd = 0;
357 fileno_modes[0].hFile = GetStdHandle(STD_INPUT_HANDLE);
358 fileno_modes[0].mode = _O_RDONLY|_O_TEXT;
359 }
360 if (fileno_modes[1].fd == -1) {
361 fileno_modes[1].fd = 1;
362 fileno_modes[1].hFile = GetStdHandle(STD_OUTPUT_HANDLE);
363 fileno_modes[1].mode = _O_WRONLY|_O_TEXT;
364 }
365 if (fileno_modes[2].fd == -1) {
366 fileno_modes[2].fd = 2;
367 fileno_modes[2].hFile = GetStdHandle(STD_ERROR_HANDLE);
368 fileno_modes[2].mode = _O_WRONLY|_O_TEXT;
369 }
370 if (fileno_modes[3].fd == -1) {
371 fileno_modes[3].fd = 3;
372 fileno_modes[3].hFile = GetStdHandle(STD_AUX_HANDLE);
373 fileno_modes[3].mode = _O_WRONLY|_O_TEXT;
374 }
375 if (fileno_modes[4].fd == -1) {
376 fileno_modes[4].fd = 4;
377 fileno_modes[4].hFile = GetStdHandle(STD_PRINTER_HANDLE);
378 fileno_modes[4].mode = _O_WRONLY|_O_TEXT;
379 }
380 return TRUE;
381 }