b59623fe6a0b2fc793640ffd20d4e2583709c5b5
[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 DPRINT1("not valid fd %i, g_fdend %i, fdinfo %x, bucket %x, fdflags %x\n",
103 fd,g_fdend,fdinfo(fd),fdinfo_bucket(fd),fdinfo(fd)->fdflags);
104
105 }
106
107 return b;
108 }
109
110 /*
111 * INTERNAL
112 */
113 char split_oflags(int oflags)
114 {
115 char fdflags = 0;
116
117 if (oflags & _O_APPEND) fdflags |= FAPPEND;
118
119 if (oflags & _O_BINARY) ;
120 else if (oflags & _O_TEXT) fdflags |= FTEXT;
121 else if (_fmode& _O_BINARY) ;
122 else fdflags |= FTEXT; /* default to TEXT*/
123
124 if (oflags & _O_NOINHERIT) fdflags |= FNOINHERIT;
125
126 if (oflags & ~(_O_BINARY|_O_TEXT|_O_APPEND|_O_TRUNC|
127 _O_EXCL|_O_CREAT|_O_RDWR|_O_WRONLY|
128 _O_TEMPORARY|_O_NOINHERIT))
129 DPRINT1(":unsupported oflags 0x%04x\n",oflags);
130
131 return fdflags;
132 }
133
134
135
136 /*
137 * INTERNAL
138 */
139 char __is_text_file(FILE* p)
140 {
141 if ( p == NULL || fdinfo_bucket((p)->_file) == NULL )
142 return FALSE;
143 return (!((p)->_flag&_IOSTRG) && (fdinfo((p)->_file)->fdflags & FTEXT));
144 }
145
146 /*
147 * @implemented
148 */
149 int _open(const char* _path, int _oflag,...)
150 {
151 #if !defined(NDEBUG) && defined(DBG)
152 va_list arg;
153 int pmode;
154 #endif
155 HANDLE hFile;
156 DWORD dwDesiredAccess = 0;
157 DWORD dwShareMode = 0;
158 DWORD dwCreationDistribution = 0;
159 DWORD dwFlagsAndAttributes = 0;
160 SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
161
162 #if !defined(NDEBUG) && defined(DBG)
163 va_start(arg, _oflag);
164 pmode = va_arg(arg, int);
165 #endif
166
167
168 TRACE("_open('%s', %x, (%x))\n", _path, _oflag);
169
170
171 if ((_oflag & S_IREAD ) == S_IREAD)
172 dwShareMode = FILE_SHARE_READ;
173 else if ((_oflag & S_IWRITE) == S_IWRITE) {
174 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
175 }
176 /*
177 *
178 * _O_BINARY Opens file in binary (untranslated) mode. (See fopen for a description of binary mode.)
179 * _O_TEXT Opens file in text (translated) mode. (For more information, see Text and Binary Mode File I/O and fopen.)
180 *
181 * _O_APPEND Moves file pointer to end of file before every write operation.
182 */
183 #ifdef _OLD_BUILD_
184 if ((_oflag & _O_RDWR) == _O_RDWR)
185 dwDesiredAccess |= GENERIC_WRITE|GENERIC_READ;
186 else if ((_oflag & O_RDONLY) == O_RDONLY)
187 dwDesiredAccess |= GENERIC_READ;
188 else if ((_oflag & _O_WRONLY) == _O_WRONLY)
189 dwDesiredAccess |= GENERIC_WRITE ;
190 #else
191 if ((_oflag & _O_WRONLY) == _O_WRONLY )
192 dwDesiredAccess |= GENERIC_WRITE ;
193 else if ((_oflag & _O_RDWR) == _O_RDWR )
194 dwDesiredAccess |= GENERIC_WRITE|GENERIC_READ;
195 else //if ((_oflag & O_RDONLY) == O_RDONLY)
196 dwDesiredAccess |= GENERIC_READ;
197 #endif
198
199 if (( _oflag & (_O_CREAT | _O_EXCL)) == (_O_CREAT | _O_EXCL))
200 dwCreationDistribution |= CREATE_NEW;
201
202 else if ((_oflag & O_TRUNC ) == O_TRUNC) {
203 if ((_oflag & O_CREAT ) == O_CREAT)
204 dwCreationDistribution |= CREATE_ALWAYS;
205 else if ((_oflag & O_RDONLY ) != O_RDONLY)
206 dwCreationDistribution |= TRUNCATE_EXISTING;
207 }
208 else if ((_oflag & _O_APPEND) == _O_APPEND)
209 dwCreationDistribution |= OPEN_EXISTING;
210 else if ((_oflag & _O_CREAT) == _O_CREAT)
211 dwCreationDistribution |= OPEN_ALWAYS;
212 else
213 dwCreationDistribution |= OPEN_EXISTING;
214
215 if ((_oflag & _O_RANDOM) == _O_RANDOM )
216 dwFlagsAndAttributes |= FILE_FLAG_RANDOM_ACCESS;
217 if ((_oflag & _O_SEQUENTIAL) == _O_SEQUENTIAL)
218 dwFlagsAndAttributes |= FILE_FLAG_SEQUENTIAL_SCAN;
219 if ((_oflag & _O_TEMPORARY) == _O_TEMPORARY) {
220 dwFlagsAndAttributes |= FILE_FLAG_DELETE_ON_CLOSE;
221 DPRINT("FILE_FLAG_DELETE_ON_CLOSE\n");
222 }
223 if ((_oflag & _O_SHORT_LIVED) == _O_SHORT_LIVED) {
224 dwFlagsAndAttributes |= FILE_FLAG_DELETE_ON_CLOSE;
225 DPRINT("FILE_FLAG_DELETE_ON_CLOSE\n");
226 }
227 if (_oflag & _O_NOINHERIT)
228 sa.bInheritHandle = FALSE;
229
230 if (dwCreationDistribution == OPEN_EXISTING &&
231 (dwDesiredAccess & (GENERIC_WRITE|GENERIC_READ)) == GENERIC_READ) {
232 /* Allow always shared read for a file which is opened for read only */
233 dwShareMode |= FILE_SHARE_READ;
234 }
235
236 hFile = CreateFileA(_path,
237 dwDesiredAccess,
238 dwShareMode,
239 &sa,
240 dwCreationDistribution,
241 dwFlagsAndAttributes,
242 NULL);
243 if (hFile == (HANDLE)-1) {
244 _dosmaperr(GetLastError());
245 return( -1);
246 }
247 DPRINT("OK\n");
248 if (!(_oflag & (_O_TEXT|_O_BINARY))) {
249 _oflag |= _fmode;
250 }
251 return(alloc_fd(hFile, split_oflags(_oflag)));
252 }
253
254
255
256 /*
257 * INTERNAL
258 */
259 static void init_bucket(FDINFO* entry)
260 {
261 int i;
262
263 for(i=0;
264 i < FDINFO_ENTRIES_PER_BUCKET;
265 i++, entry++)
266 {
267 entry->hFile = INVALID_HANDLE_VALUE;
268 entry->fdflags = 0;
269 entry->pipechar = LF;
270 entry->lockinitflag = 0;
271 }
272 }
273
274 /*
275 * INTERNAL
276 */
277 static BOOL alloc_init_bucket(int fd)
278 {
279 fdinfo_bucket(fd) = malloc(FDINFO_ENTRIES_PER_BUCKET * sizeof(FDINFO));
280 if (!fdinfo_bucket(fd)) return FALSE;
281
282 init_bucket(fdinfo_bucket(fd));
283
284 return TRUE;
285 }
286
287
288
289
290 /*
291 * INTERNAL
292 * Allocate an fd slot from a Win32 HANDLE, starting from fd
293 * caller must hold the files lock
294 */
295 static int alloc_fd_from(HANDLE hand, char flag, int fd)
296 {
297
298 if (fd >= FDINFO_ENTRIES)
299 {
300 DPRINT1("files exhausted!\n");
301 return -1;
302 }
303
304 if (!fdinfo_bucket(fd))
305 {
306 if (!alloc_init_bucket(fd)){
307 //errno = ENOMEM
308 return -1;
309 }
310 }
311
312 fdinfo(fd)->hFile = hand;
313 fdinfo(fd)->fdflags = FOPEN | (flag & (FNOINHERIT | FAPPEND | FTEXT));
314 fdinfo(fd)->pipechar = LF;
315 fdinfo(fd)->lockinitflag = 0;
316 //fdinfo(fd)->lock
317
318 /* locate next free slot */
319 if (fd == g_fdstart && fd == g_fdend)
320 {
321 g_fdstart = g_fdend + 1;
322 }
323 else
324 {
325 #if 0 /* alternate (untested) impl. maybe a tiny bit faster? -Gunnar */
326 int i, bidx;
327
328 for (bidx = fdinfo_bucket_idx(g_fdstart); bidx < FDINFO_BUCKETS && __pioinfo[bidx]; bidx++)
329 {
330 for (i = fdinfo_bucket_entry_idx(g_fdstart);
331 g_fdstart < g_fdend && fdinfo(g_fdstart)->fdflags & FOPEN && i < FDINFO_BUCKET_ENTRIES;
332 i++)
333 {
334 g_fdstart++;
335 }
336 }
337 #else
338
339 while (g_fdstart < g_fdend &&
340 fdinfo_bucket(g_fdstart) &&
341 (fdinfo(g_fdstart)->fdflags & FOPEN))
342 {
343 g_fdstart++;
344 }
345 #endif
346 }
347
348 /* update last fd in use */
349 if (fd >= g_fdend)
350 g_fdend = fd + 1;
351
352 /* alloc more fdinfo buckets by demand.
353 * FIXME: should we dealloc buckets when they become unused also? */
354 if (!fdinfo_bucket(g_fdstart) && g_fdstart < FDINFO_ENTRIES)
355 {
356 alloc_init_bucket(g_fdstart);
357 }
358
359 DPRINT("fdstart is %d, fdend is %d\n", g_fdstart, g_fdend);
360
361 switch (fd)
362 {
363 case 0: SetStdHandle(STD_INPUT_HANDLE, hand); break;
364 case 1: SetStdHandle(STD_OUTPUT_HANDLE, hand); break;
365 case 2: SetStdHandle(STD_ERROR_HANDLE, hand); break;
366 }
367
368 return fd;
369 }
370
371
372 /*
373 * INTERNAL: Allocate an fd slot from a Win32 HANDLE
374 */
375 int alloc_fd(HANDLE hand, char flag)
376 {
377 int ret;
378
379 LOCK_FILES();
380
381 // TRACE(":handle (%p) allocating fd (%d)\n",hand,MSVCRT_fdstart);
382 ret = alloc_fd_from(hand, flag, g_fdstart);
383
384 UNLOCK_FILES();
385 return ret;
386 }
387
388
389
390 /*
391 * INTERNAL
392 */
393 char __fileno_getmode(int fd)
394 {
395 if (!is_valid_fd(fd)) {
396 __set_errno(EBADF);
397 return -1;
398 }
399 return fdinfo(fd)->fdflags;
400
401 }
402
403 /*
404 * INTERNAL
405 */
406 void free_fd(int fd)
407 {
408 LOCK_FILES();
409
410
411 fdinfo(fd)->hFile = INVALID_HANDLE_VALUE;
412 fdinfo(fd)->fdflags = 0;
413
414 if (fd < 3) /* don't use 0,1,2 for user files */
415 {
416 switch (fd)
417 {
418 case 0: SetStdHandle(STD_INPUT_HANDLE, NULL); break;
419 case 1: SetStdHandle(STD_OUTPUT_HANDLE, NULL); break;
420 case 2: SetStdHandle(STD_ERROR_HANDLE, NULL); break;
421 }
422 }
423 else
424 {
425 if (fd == g_fdend - 1)
426 g_fdend--;
427
428 if (fd < g_fdstart)
429 g_fdstart = fd;
430 }
431
432
433 UNLOCK_FILES();
434 }
435
436 /*
437 * @implemented
438 */
439 int _open_osfhandle(long osfhandle, int oflags)
440 {
441 /*
442 PREV:
443 The _open_osfhandle() function in MSVCRT is expected to take the absence
444 of either _O_TEXT or _O_BINARY to mean _O_BINARY. Currently it defaults to
445 _O_TEXT.
446
447 An example of this is MFC's CStdioFile::Open in binary mode - it passes flags
448 of 0 when it wants to write a binary file - under WINE we do text mode conversions!
449
450 The attached patch ensures that _O_BINARY is set if neither is set in the passed-in
451 flags.
452
453
454 * file, so set the write flag. It also only sets _O_TEXT if it wants
455 * text - it never sets _O_BINARY.
456 */
457 /* FIXME: handle more flags */
458 /*
459 flags |= MSVCRT__IOREAD|MSVCRT__IOWRT;
460 if ( !( flags & _O_TEXT ) ) flags |= _O_BINARY;
461
462 fd = msvcrt_alloc_fd((HANDLE)hand,flags);
463 TRACE(":handle (%ld) fd (%d) flags 0x%08x\n",hand,fd, flags);
464 */
465 /* MSVCRT__O_RDONLY (0) always matches, so set the read flag
466 * MFC's CStdioFile clears O_RDONLY (0)! if it wants to write to the
467 * file, so set the write flag. It also only sets MSVCRT__O_TEXT if it wants
468 * text - it never sets MSVCRT__O_BINARY.
469 */
470 /* FIXME: handle more flags */
471 /*
472 LAG TEST SOM TESTER UT ALT DETTE flag tingern
473 */
474 if (!(oflags & (_O_BINARY | _O_TEXT)) && (_fmode & _O_BINARY))
475 oflags |= _O_BINARY;
476 else
477 oflags |= _O_TEXT;
478
479 return alloc_fd((HANDLE)osfhandle, split_oflags(oflags));
480 }
481
482 /*
483 * @implemented
484 */
485 long _get_osfhandle(int fd)
486 {
487 TRACE("_get_osfhandle(%i)",fd);
488
489 if (!is_valid_fd(fd)) {
490 return( -1 );
491 }
492 return( (long)fdinfo(fd)->hFile );
493 }
494
495
496
497 /*
498 * INTERNAL
499 */
500 int __fileno_dup2(int handle1, int handle2)
501 {
502 HANDLE hProcess;
503 BOOL result;
504
505 if (handle1 >= FDINFO_ENTRIES || handle1 < 0 || handle2 >= FDINFO_ENTRIES || handle2 < 0) {
506 __set_errno(EBADF);
507 return -1;
508 }
509 // if (_pioinfo[handle1]->fd == -1) {
510 if (fdinfo(handle1)->hFile == INVALID_HANDLE_VALUE) {
511 __set_errno(EBADF);
512 return -1;
513 }
514 if (handle1 == handle2)
515 return handle1;
516 // if (_pioinfo[handle2]->fd != -1) {
517 if (fdinfo(handle2)->hFile != INVALID_HANDLE_VALUE) {
518 _close(handle2);
519 }
520 hProcess = GetCurrentProcess();
521 result = DuplicateHandle(hProcess,
522 fdinfo(handle1)->hFile,
523 hProcess,
524 &fdinfo(handle2)->hFile,
525 0,
526 fdinfo(handle1)->fdflags & FNOINHERIT ? FALSE : TRUE,
527 DUPLICATE_SAME_ACCESS);
528 if (result) {
529 // _pioinfo[handle2]->fd = handle2;
530 fdinfo(handle2)->fdflags = fdinfo(handle1)->fdflags;
531 switch (handle2) {
532 case 0:
533 SetStdHandle(STD_INPUT_HANDLE, fdinfo(handle2)->hFile);
534 break;
535 case 1:
536 SetStdHandle(STD_OUTPUT_HANDLE, fdinfo(handle2)->hFile);
537 break;
538 case 2:
539 SetStdHandle(STD_ERROR_HANDLE, fdinfo(handle2)->hFile);
540 break;
541 }
542
543 return handle1;
544 } else {
545 __set_errno(EMFILE); // Is this the correct error no.?
546 return -1;
547 }
548 }
549
550
551 void* malloc(size_t sizeObject);
552
553
554
555 /*
556 * INTERNAL
557 */
558 BOOL __fileno_init(void)
559 {
560 STARTUPINFOA si;
561 int i;
562
563 init_bucket(first_bucket);
564
565 GetStartupInfoA(&si);
566
567 if (si.cbReserved2 != 0 && si.lpReserved2 != NULL)
568 {
569 char* fdflags_ptr;
570 HANDLE* handle_ptr;
571
572 g_fdend = *(unsigned*)si.lpReserved2;
573
574 fdflags_ptr= (char*)(si.lpReserved2 + sizeof(unsigned));
575 handle_ptr = (HANDLE*)(fdflags_ptr + g_fdend * sizeof(char));
576
577 g_fdend = min(g_fdend, FDINFO_ENTRIES);
578 for (i = 0; i < g_fdend; i++)
579 {
580 if (!fdinfo_bucket(i))
581 {
582 if (!alloc_init_bucket(i)){
583 /* FIXME: free other buckets? */
584 return FALSE;
585 }
586 }
587
588 if ((*fdflags_ptr & FOPEN) && *handle_ptr != INVALID_HANDLE_VALUE)
589 {
590 fdinfo(i)->fdflags = *fdflags_ptr;
591 fdinfo(i)->hFile = *handle_ptr;
592 }
593 /*
594 else
595 {
596 fdinfo(i)->fdflags = 0;
597 fdinfo(i)->hFile = INVALID_HANDLE_VALUE;
598 }
599 */
600 fdflags_ptr++; handle_ptr++;
601 }
602 for (g_fdstart = 3; g_fdstart < g_fdend; g_fdstart++)
603 if (fdinfo(g_fdstart)->hFile == INVALID_HANDLE_VALUE) break;
604 }
605
606 InitializeCriticalSection(&g_file_cs);
607
608
609 if (fdinfo(0)->hFile == INVALID_HANDLE_VALUE || !(fdinfo(0)->fdflags & FOPEN)) {
610 fdinfo(0)->hFile = GetStdHandle(STD_INPUT_HANDLE);
611 if (fdinfo(0)->hFile == NULL)
612 fdinfo(0)->hFile = INVALID_HANDLE_VALUE;
613 fdinfo(0)->fdflags = FOPEN|FTEXT;
614 }
615 if (fdinfo(1)->hFile == INVALID_HANDLE_VALUE || !(fdinfo(1)->fdflags & FOPEN)) {
616 fdinfo(1)->hFile = GetStdHandle(STD_OUTPUT_HANDLE);
617 if (fdinfo(1)->hFile == NULL)
618 fdinfo(1)->hFile = INVALID_HANDLE_VALUE;
619 fdinfo(1)->fdflags = FOPEN|FTEXT;
620 }
621 if (fdinfo(2)->hFile == INVALID_HANDLE_VALUE || !(fdinfo(2)->fdflags & FOPEN)) {
622 fdinfo(2)->hFile = GetStdHandle(STD_ERROR_HANDLE);
623 if (fdinfo(2)->hFile == NULL)
624 fdinfo(2)->hFile = INVALID_HANDLE_VALUE;
625 fdinfo(2)->fdflags = FOPEN|FTEXT;
626 }
627
628
629
630
631 for (i = 0; i < 3; i++)
632 {
633 /* FILE structs for stdin/out/err are static and never deleted */
634 // MSVCRT_fstreams[i] = &MSVCRT__iob[i];
635 }
636 // MSVCRT_stream_idx = 3;
637
638 return TRUE;
639 }
640
641
642
643 /* INTERNAL: Create an inheritance data block (for spawned process)
644 * The inheritance block is made of:
645 * 00 int nb of file descriptor (NBFD)
646 * 04 char file flags (wxflag): repeated for each fd
647 * 4+NBFD HANDLE file handle: repeated for each fd
648 */
649 unsigned create_io_inherit_block(STARTUPINFOA* si)
650 {
651 int fd;
652 char* fdflags_ptr;
653 HANDLE* handle_ptr;
654
655 TRACE("create_io_inherit_block(%x)",si);
656
657 si->cbReserved2 = sizeof(unsigned) + (sizeof(char) + sizeof(HANDLE)) * g_fdend;
658 si->lpReserved2 = calloc(si->cbReserved2, 1);
659 if (!si->lpReserved2)
660 {
661 si->cbReserved2 = 0;
662 return( FALSE );
663 }
664 fdflags_ptr = (char*)si->lpReserved2 + sizeof(unsigned);
665 handle_ptr = (HANDLE*)(fdflags_ptr + g_fdend * sizeof(char));
666
667 *(unsigned*)si->lpReserved2 = g_fdend;
668 for (fd = 0; fd < g_fdend; fd++)
669 {
670 /* to be inherited, we need it to be open, and that DONTINHERIT isn't set */
671 if ((fdinfo(fd)->fdflags & (FOPEN | FNOINHERIT)) == FOPEN)
672 {
673 *fdflags_ptr = fdinfo(fd)->fdflags;
674 *handle_ptr = fdinfo(fd)->hFile;
675 }
676 else
677 {
678 *fdflags_ptr = 0;
679 *handle_ptr = INVALID_HANDLE_VALUE;
680 }
681 fdflags_ptr++; handle_ptr++;
682 }
683 return( TRUE );
684 }
685
686
687
688
689 /*
690 * @implemented
691 */
692 int _setmode(int fd, int newmode)
693 {
694 int prevmode;
695
696 TRACE("_setmode(%d, %d)", fd, newmode);
697
698 if (!is_valid_fd(fd))
699 {
700 DPRINT1("_setmode: inval fd (%d)\n",fd);
701 //errno = EBADF;
702 return(-1);
703 }
704
705 if (newmode & ~(_O_TEXT|_O_BINARY))
706 {
707 DPRINT1("_setmode: fd (%d) mode (0x%08x) unknown\n",fd,newmode);
708 /* FIXME: Should we fail with EINVAL here? */
709 }
710
711 prevmode = fdinfo(fd)->fdflags & FTEXT ? _O_TEXT : _O_BINARY;
712
713 if ((newmode & _O_TEXT) == _O_TEXT)
714 {
715 fdinfo(fd)->fdflags |= FTEXT;
716 }
717 else
718 {
719 /* FIXME: If both _O_TEXT and _O_BINARY are set, we get here.
720 * Should we fail with EINVAL instead? -Gunnar
721 */
722 fdinfo(fd)->fdflags &= ~FTEXT;
723 }
724
725 return(prevmode);
726 }
727