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