Print only the complete information if the fd is valid itself (in is_valid_fd).
[reactos.git] / reactos / lib / crt / 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 * Some stuff taken from active perl: perl\win32.c (ioinfo stuff)
13 *
14 * (c) 1995 Microsoft Corporation. All rights reserved.
15 * Developed by hip communications inc., http://info.hip.com/info/
16 * Portions (c) 1993 Intergraph Corporation. All rights reserved.
17 *
18 * You may distribute under the terms of either the GNU General Public
19 * License or the Artistic License, as specified in the README file.
20 */
21 /*
22 * Some functions taken from/based on wine\dlls\msvcrt\file.c:
23 * split_oflags
24 * _open_osfhandle
25 * many more...
26 *
27 * Copyright 1996,1998 Marcus Meissner
28 * Copyright 1996 Jukka Iivonen
29 * Copyright 1997,2000 Uwe Bonnes
30 * Copyright 2000 Jon Griffiths
31 * Copyright 2004 Eric Pouech
32 * Copyright 2004 Juan Lang
33 */
34
35 // rember to interlock the allocation of fileno when making this thread safe
36
37 // possibly store extra information at the handle
38
39 #include "precomp.h"
40
41 #if !defined(NDEBUG) && defined(DBG)
42 #include <stdarg.h>
43 #endif
44
45 #include <io.h>
46 #include <fcntl.h>
47 #include <sys/stat.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <share.h>
51 #include <errno.h>
52 #include <internal/file.h>
53
54 #define NDEBUG
55 #include <internal/debug.h>
56
57
58
59 FDINFO first_bucket[FDINFO_ENTRIES_PER_BUCKET];
60 FDINFO* __pioinfo[FDINFO_BUCKETS] = {first_bucket};
61
62
63 /* This critical section protects the tables MSVCRT_fdesc and MSVCRT_fstreams,
64 * and their related indexes, MSVCRT_fdstart, MSVCRT_fdend,
65 * and MSVCRT_stream_idx, from race conditions.
66 * It doesn't protect against race conditions manipulating the underlying files
67 * or flags; doing so would probably be better accomplished with per-file
68 * protection, rather than locking the whole table for every change.
69 */
70 static CRITICAL_SECTION g_file_cs;
71 #define LOCK_FILES() do { EnterCriticalSection(&g_file_cs); } while (0)
72 #define UNLOCK_FILES() do { LeaveCriticalSection(&g_file_cs); } while (0)
73
74 /////////////////////////////////////////
75
76 static int g_fdstart = 3; /* first unallocated fd */
77 static int g_fdend = 3; /* highest allocated fd */
78
79 /*
80 * INTERNAL
81 */
82 /*
83 static inline FD_INFO* fdinfo(int fd)
84 {
85 FD_INFO* bucket = __pioinfo[fd >> FDINFO_ENTRIES_PER_BUCKET_SHIFT];
86 if (!bucket){
87 bucket = alloc_init_bucket(fd);
88 }
89 return bucket + (fd & (FDINFO_ENTRIES_PER_BUCKET - 1));
90 }
91 */
92
93
94 /*
95 * INTERNAL
96 */
97 inline BOOL is_valid_fd(int fd)
98 {
99 BOOL b = (fd >= 0 && fd < g_fdend && (fdinfo(fd)->fdflags & FOPEN));
100
101 if (!b){
102 if (fd >= 0 && fd < g_fdend)
103 {
104 DPRINT1("not valid fd %i, g_fdend %i, fdinfo %x, bucket %x, fdflags %x\n",
105 fd,g_fdend,fdinfo(fd),fdinfo_bucket(fd),fdinfo(fd)->fdflags);
106 }
107 else
108 {
109 DPRINT1("not valid fd %i, g_fdend %i\n",fd,g_fdend);
110 }
111
112 }
113
114 return b;
115 }
116
117 /*
118 * INTERNAL
119 */
120 char split_oflags(int oflags)
121 {
122 char fdflags = 0;
123
124 if (oflags & _O_APPEND) fdflags |= FAPPEND;
125
126 if (oflags & _O_BINARY) ;
127 else if (oflags & _O_TEXT) fdflags |= FTEXT;
128 else if (_fmode& _O_BINARY) ;
129 else fdflags |= FTEXT; /* default to TEXT*/
130
131 if (oflags & _O_NOINHERIT) fdflags |= FNOINHERIT;
132
133 if (oflags & ~(_O_BINARY|_O_TEXT|_O_APPEND|_O_TRUNC|
134 _O_EXCL|_O_CREAT|_O_RDWR|_O_WRONLY|
135 _O_TEMPORARY|_O_NOINHERIT))
136 DPRINT1(":unsupported oflags 0x%04x\n",oflags);
137
138 return fdflags;
139 }
140
141
142
143 /*
144 * INTERNAL
145 */
146 char __is_text_file(FILE* p)
147 {
148 if ( p == NULL || fdinfo_bucket((p)->_file) == NULL )
149 return FALSE;
150 return (!((p)->_flag&_IOSTRG) && (fdinfo((p)->_file)->fdflags & FTEXT));
151 }
152
153 /*
154 * @implemented
155 */
156 int _open(const char* _path, int _oflag,...)
157 {
158 #if !defined(NDEBUG) && defined(DBG)
159 va_list arg;
160 int pmode;
161 #endif
162 HANDLE hFile;
163 DWORD dwDesiredAccess = 0;
164 DWORD dwShareMode = 0;
165 DWORD dwCreationDistribution = 0;
166 DWORD dwFlagsAndAttributes = 0;
167 SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
168
169 #if !defined(NDEBUG) && defined(DBG)
170 va_start(arg, _oflag);
171 pmode = va_arg(arg, int);
172 #endif
173
174
175 TRACE("_open('%s', %x, (%x))\n", _path, _oflag);
176
177
178 if ((_oflag & S_IREAD ) == S_IREAD)
179 dwShareMode = FILE_SHARE_READ;
180 else if ((_oflag & S_IWRITE) == S_IWRITE) {
181 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
182 }
183 /*
184 *
185 * _O_BINARY Opens file in binary (untranslated) mode. (See fopen for a description of binary mode.)
186 * _O_TEXT Opens file in text (translated) mode. (For more information, see Text and Binary Mode File I/O and fopen.)
187 *
188 * _O_APPEND Moves file pointer to end of file before every write operation.
189 */
190 #ifdef _OLD_BUILD_
191 if ((_oflag & _O_RDWR) == _O_RDWR)
192 dwDesiredAccess |= GENERIC_WRITE|GENERIC_READ;
193 else if ((_oflag & O_RDONLY) == O_RDONLY)
194 dwDesiredAccess |= GENERIC_READ;
195 else if ((_oflag & _O_WRONLY) == _O_WRONLY)
196 dwDesiredAccess |= GENERIC_WRITE ;
197 #else
198 if ((_oflag & _O_WRONLY) == _O_WRONLY )
199 dwDesiredAccess |= GENERIC_WRITE ;
200 else if ((_oflag & _O_RDWR) == _O_RDWR )
201 dwDesiredAccess |= GENERIC_WRITE|GENERIC_READ;
202 else //if ((_oflag & O_RDONLY) == O_RDONLY)
203 dwDesiredAccess |= GENERIC_READ;
204 #endif
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 if ((_oflag & _O_TEMPORARY) == _O_TEMPORARY) {
227 dwFlagsAndAttributes |= FILE_FLAG_DELETE_ON_CLOSE;
228 DPRINT("FILE_FLAG_DELETE_ON_CLOSE\n");
229 }
230 if ((_oflag & _O_SHORT_LIVED) == _O_SHORT_LIVED) {
231 dwFlagsAndAttributes |= FILE_FLAG_DELETE_ON_CLOSE;
232 DPRINT("FILE_FLAG_DELETE_ON_CLOSE\n");
233 }
234 if (_oflag & _O_NOINHERIT)
235 sa.bInheritHandle = FALSE;
236
237 if (dwCreationDistribution == OPEN_EXISTING &&
238 (dwDesiredAccess & (GENERIC_WRITE|GENERIC_READ)) == GENERIC_READ) {
239 /* Allow always shared read for a file which is opened for read only */
240 dwShareMode |= FILE_SHARE_READ;
241 }
242
243 hFile = CreateFileA(_path,
244 dwDesiredAccess,
245 dwShareMode,
246 &sa,
247 dwCreationDistribution,
248 dwFlagsAndAttributes,
249 NULL);
250 if (hFile == (HANDLE)-1) {
251 _dosmaperr(GetLastError());
252 return( -1);
253 }
254 DPRINT("OK\n");
255 if (!(_oflag & (_O_TEXT|_O_BINARY))) {
256 _oflag |= _fmode;
257 }
258 return(alloc_fd(hFile, split_oflags(_oflag)));
259 }
260
261
262
263 /*
264 * INTERNAL
265 */
266 static void init_bucket(FDINFO* entry)
267 {
268 int i;
269
270 for(i=0;
271 i < FDINFO_ENTRIES_PER_BUCKET;
272 i++, entry++)
273 {
274 entry->hFile = INVALID_HANDLE_VALUE;
275 entry->fdflags = 0;
276 entry->pipechar = LF;
277 entry->lockinitflag = 0;
278 }
279 }
280
281 /*
282 * INTERNAL
283 */
284 static BOOL alloc_init_bucket(int fd)
285 {
286 fdinfo_bucket(fd) = malloc(FDINFO_ENTRIES_PER_BUCKET * sizeof(FDINFO));
287 if (!fdinfo_bucket(fd)) return FALSE;
288
289 init_bucket(fdinfo_bucket(fd));
290
291 return TRUE;
292 }
293
294
295
296
297 /*
298 * INTERNAL
299 * Allocate an fd slot from a Win32 HANDLE, starting from fd
300 * caller must hold the files lock
301 */
302 static int alloc_fd_from(HANDLE hand, char flag, int fd)
303 {
304
305 if (fd >= FDINFO_ENTRIES)
306 {
307 DPRINT1("files exhausted!\n");
308 return -1;
309 }
310
311 if (!fdinfo_bucket(fd))
312 {
313 if (!alloc_init_bucket(fd)){
314 //errno = ENOMEM
315 return -1;
316 }
317 }
318
319 fdinfo(fd)->hFile = hand;
320 fdinfo(fd)->fdflags = FOPEN | (flag & (FNOINHERIT | FAPPEND | FTEXT));
321 fdinfo(fd)->pipechar = LF;
322 fdinfo(fd)->lockinitflag = 0;
323 //fdinfo(fd)->lock
324
325 /* locate next free slot */
326 if (fd == g_fdstart && fd == g_fdend)
327 {
328 g_fdstart = g_fdend + 1;
329 }
330 else
331 {
332 #if 0 /* alternate (untested) impl. maybe a tiny bit faster? -Gunnar */
333 int i, bidx;
334
335 for (bidx = fdinfo_bucket_idx(g_fdstart); bidx < FDINFO_BUCKETS && __pioinfo[bidx]; bidx++)
336 {
337 for (i = fdinfo_bucket_entry_idx(g_fdstart);
338 g_fdstart < g_fdend && fdinfo(g_fdstart)->fdflags & FOPEN && i < FDINFO_BUCKET_ENTRIES;
339 i++)
340 {
341 g_fdstart++;
342 }
343 }
344 #else
345
346 while (g_fdstart < g_fdend &&
347 fdinfo_bucket(g_fdstart) &&
348 (fdinfo(g_fdstart)->fdflags & FOPEN))
349 {
350 g_fdstart++;
351 }
352 #endif
353 }
354
355 /* update last fd in use */
356 if (fd >= g_fdend)
357 g_fdend = fd + 1;
358
359 /* alloc more fdinfo buckets by demand.
360 * FIXME: should we dealloc buckets when they become unused also? */
361 if (!fdinfo_bucket(g_fdstart) && g_fdstart < FDINFO_ENTRIES)
362 {
363 alloc_init_bucket(g_fdstart);
364 }
365
366 DPRINT("fdstart is %d, fdend is %d\n", g_fdstart, g_fdend);
367
368 switch (fd)
369 {
370 case 0: SetStdHandle(STD_INPUT_HANDLE, hand); break;
371 case 1: SetStdHandle(STD_OUTPUT_HANDLE, hand); break;
372 case 2: SetStdHandle(STD_ERROR_HANDLE, hand); break;
373 }
374
375 return fd;
376 }
377
378
379 /*
380 * INTERNAL: Allocate an fd slot from a Win32 HANDLE
381 */
382 int alloc_fd(HANDLE hand, char flag)
383 {
384 int ret;
385
386 LOCK_FILES();
387
388 // TRACE(":handle (%p) allocating fd (%d)\n",hand,MSVCRT_fdstart);
389 ret = alloc_fd_from(hand, flag, g_fdstart);
390
391 UNLOCK_FILES();
392 return ret;
393 }
394
395
396
397 /*
398 * INTERNAL
399 */
400 char __fileno_getmode(int fd)
401 {
402 if (!is_valid_fd(fd)) {
403 __set_errno(EBADF);
404 return -1;
405 }
406 return fdinfo(fd)->fdflags;
407
408 }
409
410 /*
411 * INTERNAL
412 */
413 void free_fd(int fd)
414 {
415 LOCK_FILES();
416
417
418 fdinfo(fd)->hFile = INVALID_HANDLE_VALUE;
419 fdinfo(fd)->fdflags = 0;
420
421 if (fd < 3) /* don't use 0,1,2 for user files */
422 {
423 switch (fd)
424 {
425 case 0: SetStdHandle(STD_INPUT_HANDLE, NULL); break;
426 case 1: SetStdHandle(STD_OUTPUT_HANDLE, NULL); break;
427 case 2: SetStdHandle(STD_ERROR_HANDLE, NULL); break;
428 }
429 }
430 else
431 {
432 if (fd == g_fdend - 1)
433 g_fdend--;
434
435 if (fd < g_fdstart)
436 g_fdstart = fd;
437 }
438
439
440 UNLOCK_FILES();
441 }
442
443 /*
444 * @implemented
445 */
446 int _open_osfhandle(long osfhandle, int oflags)
447 {
448 /*
449 PREV:
450 The _open_osfhandle() function in MSVCRT is expected to take the absence
451 of either _O_TEXT or _O_BINARY to mean _O_BINARY. Currently it defaults to
452 _O_TEXT.
453
454 An example of this is MFC's CStdioFile::Open in binary mode - it passes flags
455 of 0 when it wants to write a binary file - under WINE we do text mode conversions!
456
457 The attached patch ensures that _O_BINARY is set if neither is set in the passed-in
458 flags.
459
460
461 * file, so set the write flag. It also only sets _O_TEXT if it wants
462 * text - it never sets _O_BINARY.
463 */
464 /* FIXME: handle more flags */
465 /*
466 flags |= MSVCRT__IOREAD|MSVCRT__IOWRT;
467 if ( !( flags & _O_TEXT ) ) flags |= _O_BINARY;
468
469 fd = msvcrt_alloc_fd((HANDLE)hand,flags);
470 TRACE(":handle (%ld) fd (%d) flags 0x%08x\n",hand,fd, flags);
471 */
472 /* MSVCRT__O_RDONLY (0) always matches, so set the read flag
473 * MFC's CStdioFile clears O_RDONLY (0)! if it wants to write to the
474 * file, so set the write flag. It also only sets MSVCRT__O_TEXT if it wants
475 * text - it never sets MSVCRT__O_BINARY.
476 */
477 /* FIXME: handle more flags */
478 /*
479 LAG TEST SOM TESTER UT ALT DETTE flag tingern
480 */
481 if (!(oflags & (_O_BINARY | _O_TEXT)) && (_fmode & _O_BINARY))
482 oflags |= _O_BINARY;
483 else
484 oflags |= _O_TEXT;
485
486 return alloc_fd((HANDLE)osfhandle, split_oflags(oflags));
487 }
488
489 /*
490 * @implemented
491 */
492 long _get_osfhandle(int fd)
493 {
494 TRACE("_get_osfhandle(%i)",fd);
495
496 if (!is_valid_fd(fd)) {
497 return( -1 );
498 }
499 return( (long)fdinfo(fd)->hFile );
500 }
501
502
503
504 /*
505 * INTERNAL
506 */
507 int __fileno_dup2(int handle1, int handle2)
508 {
509 HANDLE hProcess;
510 BOOL result;
511
512 if (handle1 >= FDINFO_ENTRIES || handle1 < 0 || handle2 >= FDINFO_ENTRIES || handle2 < 0) {
513 __set_errno(EBADF);
514 return -1;
515 }
516 // if (_pioinfo[handle1]->fd == -1) {
517 if (fdinfo(handle1)->hFile == INVALID_HANDLE_VALUE) {
518 __set_errno(EBADF);
519 return -1;
520 }
521 if (handle1 == handle2)
522 return handle1;
523 // if (_pioinfo[handle2]->fd != -1) {
524 if (fdinfo(handle2)->hFile != INVALID_HANDLE_VALUE) {
525 _close(handle2);
526 }
527 hProcess = GetCurrentProcess();
528 result = DuplicateHandle(hProcess,
529 fdinfo(handle1)->hFile,
530 hProcess,
531 &fdinfo(handle2)->hFile,
532 0,
533 fdinfo(handle1)->fdflags & FNOINHERIT ? FALSE : TRUE,
534 DUPLICATE_SAME_ACCESS);
535 if (result) {
536 // _pioinfo[handle2]->fd = handle2;
537 fdinfo(handle2)->fdflags = fdinfo(handle1)->fdflags;
538 switch (handle2) {
539 case 0:
540 SetStdHandle(STD_INPUT_HANDLE, fdinfo(handle2)->hFile);
541 break;
542 case 1:
543 SetStdHandle(STD_OUTPUT_HANDLE, fdinfo(handle2)->hFile);
544 break;
545 case 2:
546 SetStdHandle(STD_ERROR_HANDLE, fdinfo(handle2)->hFile);
547 break;
548 }
549
550 return handle1;
551 } else {
552 __set_errno(EMFILE); // Is this the correct error no.?
553 return -1;
554 }
555 }
556
557
558 void* malloc(size_t sizeObject);
559
560
561
562 /*
563 * INTERNAL
564 */
565 BOOL __fileno_init(void)
566 {
567 STARTUPINFOA si;
568 int i;
569
570 init_bucket(first_bucket);
571
572 GetStartupInfoA(&si);
573
574 if (si.cbReserved2 != 0 && si.lpReserved2 != NULL)
575 {
576 char* fdflags_ptr;
577 HANDLE* handle_ptr;
578
579 g_fdend = *(unsigned*)si.lpReserved2;
580
581 fdflags_ptr= (char*)(si.lpReserved2 + sizeof(unsigned));
582 handle_ptr = (HANDLE*)(fdflags_ptr + g_fdend * sizeof(char));
583
584 g_fdend = min(g_fdend, FDINFO_ENTRIES);
585 for (i = 0; i < g_fdend; i++)
586 {
587 if (!fdinfo_bucket(i))
588 {
589 if (!alloc_init_bucket(i)){
590 /* FIXME: free other buckets? */
591 return FALSE;
592 }
593 }
594
595 if ((*fdflags_ptr & FOPEN) && *handle_ptr != INVALID_HANDLE_VALUE)
596 {
597 fdinfo(i)->fdflags = *fdflags_ptr;
598 fdinfo(i)->hFile = *handle_ptr;
599 }
600 /*
601 else
602 {
603 fdinfo(i)->fdflags = 0;
604 fdinfo(i)->hFile = INVALID_HANDLE_VALUE;
605 }
606 */
607 fdflags_ptr++; handle_ptr++;
608 }
609 for (g_fdstart = 3; g_fdstart < g_fdend; g_fdstart++)
610 if (fdinfo(g_fdstart)->hFile == INVALID_HANDLE_VALUE) break;
611 }
612
613 InitializeCriticalSection(&g_file_cs);
614
615
616 if (fdinfo(0)->hFile == INVALID_HANDLE_VALUE || !(fdinfo(0)->fdflags & FOPEN)) {
617 fdinfo(0)->hFile = GetStdHandle(STD_INPUT_HANDLE);
618 if (fdinfo(0)->hFile == NULL)
619 fdinfo(0)->hFile = INVALID_HANDLE_VALUE;
620 fdinfo(0)->fdflags = FOPEN|FTEXT;
621 }
622 if (fdinfo(1)->hFile == INVALID_HANDLE_VALUE || !(fdinfo(1)->fdflags & FOPEN)) {
623 fdinfo(1)->hFile = GetStdHandle(STD_OUTPUT_HANDLE);
624 if (fdinfo(1)->hFile == NULL)
625 fdinfo(1)->hFile = INVALID_HANDLE_VALUE;
626 fdinfo(1)->fdflags = FOPEN|FTEXT;
627 }
628 if (fdinfo(2)->hFile == INVALID_HANDLE_VALUE || !(fdinfo(2)->fdflags & FOPEN)) {
629 fdinfo(2)->hFile = GetStdHandle(STD_ERROR_HANDLE);
630 if (fdinfo(2)->hFile == NULL)
631 fdinfo(2)->hFile = INVALID_HANDLE_VALUE;
632 fdinfo(2)->fdflags = FOPEN|FTEXT;
633 }
634
635
636
637
638 for (i = 0; i < 3; i++)
639 {
640 /* FILE structs for stdin/out/err are static and never deleted */
641 // MSVCRT_fstreams[i] = &MSVCRT__iob[i];
642 }
643 // MSVCRT_stream_idx = 3;
644
645 return TRUE;
646 }
647
648
649
650 /* INTERNAL: Create an inheritance data block (for spawned process)
651 * The inheritance block is made of:
652 * 00 int nb of file descriptor (NBFD)
653 * 04 char file flags (wxflag): repeated for each fd
654 * 4+NBFD HANDLE file handle: repeated for each fd
655 */
656 unsigned create_io_inherit_block(STARTUPINFOA* si)
657 {
658 int fd;
659 char* fdflags_ptr;
660 HANDLE* handle_ptr;
661
662 TRACE("create_io_inherit_block(%x)",si);
663
664 si->cbReserved2 = sizeof(unsigned) + (sizeof(char) + sizeof(HANDLE)) * g_fdend;
665 si->lpReserved2 = calloc(si->cbReserved2, 1);
666 if (!si->lpReserved2)
667 {
668 si->cbReserved2 = 0;
669 return( FALSE );
670 }
671 fdflags_ptr = (char*)si->lpReserved2 + sizeof(unsigned);
672 handle_ptr = (HANDLE*)(fdflags_ptr + g_fdend * sizeof(char));
673
674 *(unsigned*)si->lpReserved2 = g_fdend;
675 for (fd = 0; fd < g_fdend; fd++)
676 {
677 /* to be inherited, we need it to be open, and that DONTINHERIT isn't set */
678 if ((fdinfo(fd)->fdflags & (FOPEN | FNOINHERIT)) == FOPEN)
679 {
680 *fdflags_ptr = fdinfo(fd)->fdflags;
681 *handle_ptr = fdinfo(fd)->hFile;
682 }
683 else
684 {
685 *fdflags_ptr = 0;
686 *handle_ptr = INVALID_HANDLE_VALUE;
687 }
688 fdflags_ptr++; handle_ptr++;
689 }
690 return( TRUE );
691 }
692
693
694
695
696 /*
697 * @implemented
698 */
699 int _setmode(int fd, int newmode)
700 {
701 int prevmode;
702
703 TRACE("_setmode(%d, %d)", fd, newmode);
704
705 if (!is_valid_fd(fd))
706 {
707 DPRINT1("_setmode: inval fd (%d)\n",fd);
708 //errno = EBADF;
709 return(-1);
710 }
711
712 if (newmode & ~(_O_TEXT|_O_BINARY))
713 {
714 DPRINT1("_setmode: fd (%d) mode (0x%08x) unknown\n",fd,newmode);
715 /* FIXME: Should we fail with EINVAL here? */
716 }
717
718 prevmode = fdinfo(fd)->fdflags & FTEXT ? _O_TEXT : _O_BINARY;
719
720 if ((newmode & _O_TEXT) == _O_TEXT)
721 {
722 fdinfo(fd)->fdflags |= FTEXT;
723 }
724 else
725 {
726 /* FIXME: If both _O_TEXT and _O_BINARY are set, we get here.
727 * Should we fail with EINVAL instead? -Gunnar
728 */
729 fdinfo(fd)->fdflags &= ~FTEXT;
730 }
731
732 return(prevmode);
733 }
734