1a361c454d4e68920734d704ccfd0497e418f432
[reactos.git] / reactos / lib / sdk / crt / stdio / file.c
1 /*
2 * PROJECT: ReactOS CRT library
3 * LICENSE: LGPL - See COPYING in the top level directory
4 * FILE: lib/sdk/crt/stdio/file.c
5 * PURPOSE: File CRT functions
6 * PROGRAMMERS: Wine team
7 * Ported to ReactOS by Aleksey Bragin (aleksey@reactos.org)
8 */
9
10 /*********************************************
11 * This file contains ReactOS changes!!
12 * Don't blindly sync it with Wine code!
13 *
14 * If you break Unicode output on the console again, please update this counter:
15 * int hours_wasted_on_this = 42;
16 *********************************************/
17
18 /*
19 * msvcrt.dll file functions
20 *
21 * Copyright 1996,1998 Marcus Meissner
22 * Copyright 1996 Jukka Iivonen
23 * Copyright 1997,2000 Uwe Bonnes
24 * Copyright 2000 Jon Griffiths
25 * Copyright 2004 Eric Pouech
26 * Copyright 2004 Juan Lang
27 *
28 * This library is free software; you can redistribute it and/or
29 * modify it under the terms of the GNU Lesser General Public
30 * License as published by the Free Software Foundation; either
31 * version 2.1 of the License, or (at your option) any later version.
32 *
33 * This library is distributed in the hope that it will be useful,
34 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
36 * Lesser General Public License for more details.
37 *
38 * You should have received a copy of the GNU Lesser General Public
39 * License along with this library; if not, write to the Free Software
40 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
41 *
42 * TODO
43 * Use the file flag hints O_SEQUENTIAL, O_RANDOM, O_SHORT_LIVED
44 */
45
46 #include <precomp.h>
47 #include "wine/unicode.h"
48
49 #include <sys/utime.h>
50 #include <direct.h>
51
52 int *__p__fmode(void);
53 int *__p___mb_cur_max(void);
54
55 #ifdef feof
56 #undef feof
57 #endif
58 #ifdef _fileno
59 #undef _fileno
60 #endif
61 #ifdef ferror
62 #undef ferror
63 #endif
64 #ifdef clearerr
65 #undef clearerr
66 #endif
67
68 #undef getc
69 #undef getwc
70 #undef getchar
71 #undef getwchar
72 #undef putc
73 #undef putwc
74 #undef putchar
75 #undef putwchar
76
77 #undef vprintf
78 #undef vwprintf
79
80 /* _access() bit flags FIXME: incomplete */
81 /* defined in crt/io.h */
82
83 /* values for wxflag in file descriptor */
84 #define WX_OPEN 0x01
85 #define WX_ATEOF 0x02
86 #define WX_READEOF 0x04 /* like ATEOF, but for underlying file rather than buffer */
87 #define WX_READCR 0x08 /* underlying file is at \r */
88 #define WX_DONTINHERIT 0x10
89 #define WX_APPEND 0x20
90 #define WX_TEXT 0x80
91
92 /* values for exflag - it's used differently in msvcr90.dll*/
93 #define EF_UTF8 0x01
94 #define EF_UTF16 0x02
95 #define EF_CRIT_INIT 0x04
96 #define EF_UNK_UNICODE 0x08
97
98 static char utf8_bom[3] = { 0xef, 0xbb, 0xbf };
99 static char utf16_bom[2] = { 0xff, 0xfe };
100
101 /* FIXME: this should be allocated dynamically */
102 #define MAX_FILES 2048
103 #define FD_BLOCK_SIZE 64
104
105 /* ioinfo structure size is different in msvcrXX.dll's */
106 typedef struct {
107 HANDLE handle;
108 unsigned char wxflag;
109 char unk1;
110 int exflag;
111 CRITICAL_SECTION crit;
112 } ioinfo;
113
114 /*********************************************************************
115 * __pioinfo (MSVCRT.@)
116 * array of pointers to ioinfo arrays [64]
117 */
118 ioinfo * __pioinfo[MAX_FILES/FD_BLOCK_SIZE] = { 0 };
119
120 /*********************************************************************
121 * __badioinfo (MSVCRT.@)
122 */
123 ioinfo __badioinfo = { INVALID_HANDLE_VALUE, WX_TEXT };
124
125 static int fdstart = 3; /* first unallocated fd */
126 static int fdend = 3; /* highest allocated fd */
127
128 typedef struct {
129 FILE file;
130 CRITICAL_SECTION crit;
131 } file_crit;
132
133 FILE _iob[_IOB_ENTRIES] = { { 0 } };
134 static file_crit* fstream[MAX_FILES/FD_BLOCK_SIZE] = { NULL };
135 static int max_streams = 512, stream_idx;
136
137 /* INTERNAL: process umask */
138 static int MSVCRT_umask = 0;
139
140 /* INTERNAL: static data for tmpnam and _wtmpname functions */
141 static int tmpnam_unique;
142
143 /* This critical section protects the tables __pioinfo and fstreams,
144 * and their related indexes, fdstart, fdend,
145 * and stream_idx, from race conditions.
146 * It doesn't protect against race conditions manipulating the underlying files
147 * or flags; doing so would probably be better accomplished with per-file
148 * protection, rather than locking the whole table for every change.
149 */
150 static CRITICAL_SECTION file_cs;
151 #define LOCK_FILES() do { EnterCriticalSection(&file_cs); } while (0)
152 #define UNLOCK_FILES() do { LeaveCriticalSection(&file_cs); } while (0)
153
154 static inline ioinfo* get_ioinfo(int fd)
155 {
156 ioinfo *ret = NULL;
157 if(fd < MAX_FILES)
158 ret = __pioinfo[fd/FD_BLOCK_SIZE];
159 if(!ret)
160 return &__badioinfo;
161
162 return ret + (fd%FD_BLOCK_SIZE);
163 }
164
165 static inline FILE* get_file(int i)
166 {
167 file_crit *ret;
168
169 if(i >= max_streams)
170 return NULL;
171
172 if(i < _IOB_ENTRIES)
173 return &_iob[i];
174
175 ret = fstream[i/FD_BLOCK_SIZE];
176 if(!ret) {
177 fstream[i/FD_BLOCK_SIZE] = calloc(FD_BLOCK_SIZE, sizeof(file_crit));
178 if(!fstream[i/FD_BLOCK_SIZE]) {
179 ERR("out of memory\n");
180 *_errno() = ENOMEM;
181 return NULL;
182 }
183
184 ret = fstream[i/FD_BLOCK_SIZE] + (i%FD_BLOCK_SIZE);
185 } else
186 ret += i%FD_BLOCK_SIZE;
187
188 return &ret->file;
189 }
190
191 static inline BOOL is_valid_fd(int fd)
192 {
193 return fd >= 0 && fd < fdend && (get_ioinfo(fd)->wxflag & WX_OPEN);
194 }
195
196 /* INTERNAL: Get the HANDLE for a fd
197 * This doesn't lock the table, because a failure will result in
198 * INVALID_HANDLE_VALUE being returned, which should be handled correctly. If
199 * it returns a valid handle which is about to be closed, a subsequent call
200 * will fail, most likely in a sane way.
201 */
202 /*static*/ HANDLE fdtoh(int fd)
203 {
204 if (!is_valid_fd(fd))
205 {
206 WARN(":fd (%d) - no handle!\n",fd);
207 *__doserrno() = 0;
208 *_errno() = EBADF;
209 return INVALID_HANDLE_VALUE;
210 }
211 //if (get_ioinfo(fd)->handle == INVALID_HANDLE_VALUE)
212 //FIXME("returning INVALID_HANDLE_VALUE for %d\n", fd);
213 return get_ioinfo(fd)->handle;
214 }
215
216 /* INTERNAL: free a file entry fd */
217 static void free_fd(int fd)
218 {
219 HANDLE old_handle;
220 ioinfo *fdinfo;
221
222 LOCK_FILES();
223 fdinfo = get_ioinfo(fd);
224 old_handle = fdinfo->handle;
225 if(fdinfo != &__badioinfo)
226 {
227 fdinfo->handle = INVALID_HANDLE_VALUE;
228 fdinfo->wxflag = 0;
229 }
230 TRACE(":fd (%d) freed\n",fd);
231 if (fd < 3) /* don't use 0,1,2 for user files */
232 {
233 switch (fd)
234 {
235 case 0:
236 if (GetStdHandle(STD_INPUT_HANDLE) == old_handle) SetStdHandle(STD_INPUT_HANDLE, 0);
237 break;
238 case 1:
239 if (GetStdHandle(STD_OUTPUT_HANDLE) == old_handle) SetStdHandle(STD_OUTPUT_HANDLE, 0);
240 break;
241 case 2:
242 if (GetStdHandle(STD_ERROR_HANDLE) == old_handle) SetStdHandle(STD_ERROR_HANDLE, 0);
243 break;
244 }
245 }
246 else
247 {
248 if (fd == fdend - 1)
249 fdend--;
250 if (fd < fdstart)
251 fdstart = fd;
252 }
253 UNLOCK_FILES();
254 }
255
256 /* INTERNAL: Allocate an fd slot from a Win32 HANDLE, starting from fd */
257 /* caller must hold the files lock */
258 static int alloc_fd_from(HANDLE hand, int flag, int fd)
259 {
260 ioinfo *fdinfo;
261
262 if (fd >= MAX_FILES)
263 {
264 WARN(":files exhausted!\n");
265 *_errno() = ENFILE;
266 return -1;
267 }
268
269 fdinfo = get_ioinfo(fd);
270 if(fdinfo == &__badioinfo) {
271 int i;
272
273 __pioinfo[fd/FD_BLOCK_SIZE] = calloc(FD_BLOCK_SIZE, sizeof(ioinfo));
274 if(!__pioinfo[fd/FD_BLOCK_SIZE]) {
275 WARN(":out of memory!\n");
276 *_errno() = ENOMEM;
277 return -1;
278 }
279
280 for(i=0; i<FD_BLOCK_SIZE; i++)
281 __pioinfo[fd/FD_BLOCK_SIZE][i].handle = INVALID_HANDLE_VALUE;
282
283 fdinfo = get_ioinfo(fd);
284 }
285
286 fdinfo->handle = hand;
287 fdinfo->wxflag = WX_OPEN | (flag & (WX_DONTINHERIT | WX_APPEND | WX_TEXT));
288
289 /* locate next free slot */
290 if (fd == fdstart && fd == fdend)
291 fdstart = fdend + 1;
292 else
293 while (fdstart < fdend &&
294 get_ioinfo(fdstart)->handle != INVALID_HANDLE_VALUE)
295 fdstart++;
296 /* update last fd in use */
297 if (fd >= fdend)
298 fdend = fd + 1;
299 TRACE("fdstart is %d, fdend is %d\n", fdstart, fdend);
300
301 switch (fd)
302 {
303 case 0: SetStdHandle(STD_INPUT_HANDLE, hand); break;
304 case 1: SetStdHandle(STD_OUTPUT_HANDLE, hand); break;
305 case 2: SetStdHandle(STD_ERROR_HANDLE, hand); break;
306 }
307
308 return fd;
309 }
310
311 /* INTERNAL: Allocate an fd slot from a Win32 HANDLE */
312 /*static*/ int alloc_fd(HANDLE hand, int flag)
313 {
314 int ret;
315
316 LOCK_FILES();
317 TRACE(":handle (%p) allocating fd (%d)\n",hand,fdstart);
318 ret = alloc_fd_from(hand, flag, fdstart);
319 UNLOCK_FILES();
320 return ret;
321 }
322
323 /* INTERNAL: Allocate a FILE* for an fd slot */
324 /* caller must hold the files lock */
325 static FILE* alloc_fp(void)
326 {
327 unsigned int i;
328 FILE *file;
329
330 for (i = 3; i < (unsigned int)max_streams; i++)
331 {
332 file = get_file(i);
333 if (!file)
334 return NULL;
335
336 if (file->_flag == 0)
337 {
338 if (i == stream_idx) stream_idx++;
339 return file;
340 }
341 }
342
343 return NULL;
344 }
345
346 /* INTERNAL: initialize a FILE* from an open fd */
347 static int init_fp(FILE* file, int fd, unsigned stream_flags)
348 {
349 TRACE(":fd (%d) allocating FILE*\n",fd);
350 if (!is_valid_fd(fd))
351 {
352 WARN(":invalid fd %d\n",fd);
353 *__doserrno() = 0;
354 *_errno() = EBADF;
355 return -1;
356 }
357 memset(file, 0, sizeof(*file));
358 file->_file = fd;
359 file->_flag = stream_flags;
360
361 if(file<_iob || file>=_iob+_IOB_ENTRIES)
362 InitializeCriticalSection(&((file_crit*)file)->crit);
363
364 TRACE(":got FILE* (%p)\n",file);
365 return 0;
366 }
367
368 /* INTERNAL: Create an inheritance data block (for spawned process)
369 * The inheritance block is made of:
370 * 00 int nb of file descriptor (NBFD)
371 * 04 char file flags (wxflag): repeated for each fd
372 * 4+NBFD HANDLE file handle: repeated for each fd
373 */
374 unsigned create_io_inherit_block(WORD *size, BYTE **block)
375 {
376 int fd;
377 char* wxflag_ptr;
378 HANDLE* handle_ptr;
379 ioinfo* fdinfo;
380
381 *size = sizeof(unsigned) + (sizeof(char) + sizeof(HANDLE)) * fdend;
382 *block = calloc(*size, 1);
383 if (!*block)
384 {
385 *size = 0;
386 return FALSE;
387 }
388 wxflag_ptr = (char*)*block + sizeof(unsigned);
389 handle_ptr = (HANDLE*)(wxflag_ptr + fdend * sizeof(char));
390
391 *(unsigned*)*block = fdend;
392 for (fd = 0; fd < fdend; fd++)
393 {
394 /* to be inherited, we need it to be open, and that DONTINHERIT isn't set */
395 fdinfo = get_ioinfo(fd);
396 if ((fdinfo->wxflag & (WX_OPEN | WX_DONTINHERIT)) == WX_OPEN)
397 {
398 *wxflag_ptr = fdinfo->wxflag;
399 *handle_ptr = fdinfo->handle;
400 }
401 else
402 {
403 *wxflag_ptr = 0;
404 *handle_ptr = INVALID_HANDLE_VALUE;
405 }
406 wxflag_ptr++; handle_ptr++;
407 }
408 return TRUE;
409 }
410
411 /* INTERNAL: Set up all file descriptors,
412 * as well as default streams (stdin, stderr and stdout)
413 */
414 void msvcrt_init_io(void)
415 {
416 STARTUPINFOA si;
417 unsigned int i;
418 ioinfo *fdinfo;
419
420 InitializeCriticalSection(&file_cs);
421 file_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": file_cs");
422 GetStartupInfoA(&si);
423 if (si.cbReserved2 >= sizeof(unsigned int) && si.lpReserved2 != NULL)
424 {
425 BYTE* wxflag_ptr;
426 HANDLE* handle_ptr;
427 unsigned int count;
428
429 count = *(unsigned*)si.lpReserved2;
430 wxflag_ptr = si.lpReserved2 + sizeof(unsigned);
431 handle_ptr = (HANDLE*)(wxflag_ptr + count);
432
433 count = min(count, (si.cbReserved2 - sizeof(unsigned)) / (sizeof(HANDLE) + 1));
434 count = min(count, MAX_FILES);
435 for (i = 0; i < count; i++)
436 {
437 if ((*wxflag_ptr & WX_OPEN) && *handle_ptr != INVALID_HANDLE_VALUE)
438 alloc_fd_from(*handle_ptr, *wxflag_ptr, i);
439
440 wxflag_ptr++; handle_ptr++;
441 }
442 fdend = max( 3, count );
443 for (fdstart = 3; fdstart < fdend; fdstart++)
444 if (get_ioinfo(fdstart)->handle == INVALID_HANDLE_VALUE) break;
445 }
446
447 if(!__pioinfo[0])
448 alloc_fd_from(INVALID_HANDLE_VALUE, 0, 3);
449
450 fdinfo = get_ioinfo(0);
451 if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE)
452 {
453 HANDLE std = GetStdHandle(STD_INPUT_HANDLE);
454 #ifndef __REACTOS__
455 if (std != INVALID_HANDLE_VALUE && DuplicateHandle(GetCurrentProcess(), std,
456 GetCurrentProcess(), &fdinfo->handle,
457 0, TRUE, DUPLICATE_SAME_ACCESS))
458 #else
459 fdinfo->handle = std;
460 #endif
461 fdinfo->wxflag = WX_OPEN | WX_TEXT;
462 }
463
464 fdinfo = get_ioinfo(1);
465 if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE)
466 {
467 HANDLE std = GetStdHandle(STD_OUTPUT_HANDLE);
468 #ifndef __REACTOS__
469 if (std != INVALID_HANDLE_VALUE && DuplicateHandle(GetCurrentProcess(), std,
470 GetCurrentProcess(), &fdinfo->handle,
471 0, TRUE, DUPLICATE_SAME_ACCESS))
472 #else
473 fdinfo->handle = std;
474 #endif
475 fdinfo->wxflag = WX_OPEN | WX_TEXT;
476 }
477
478 fdinfo = get_ioinfo(2);
479 if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE)
480 {
481 HANDLE std = GetStdHandle(STD_ERROR_HANDLE);
482 #ifndef __REACTOS__
483 if (std != INVALID_HANDLE_VALUE && DuplicateHandle(GetCurrentProcess(), std,
484 GetCurrentProcess(), &fdinfo->handle,
485 0, TRUE, DUPLICATE_SAME_ACCESS))
486 #else
487 fdinfo->handle = std;
488 #endif
489 fdinfo->wxflag = WX_OPEN | WX_TEXT;
490 }
491
492 TRACE(":handles (%p)(%p)(%p)\n", get_ioinfo(0)->handle,
493 get_ioinfo(1)->handle, get_ioinfo(2)->handle);
494
495 memset(_iob,0,3*sizeof(FILE));
496 for (i = 0; i < 3; i++)
497 {
498 /* FILE structs for stdin/out/err are static and never deleted */
499 _iob[i]._file = i;
500 _iob[i]._tmpfname = NULL;
501 _iob[i]._flag = (i == 0) ? _IOREAD : _IOWRT;
502 }
503 stream_idx = 3;
504 }
505
506 /* INTERNAL: Flush stdio file buffer */
507 static int flush_buffer(FILE* file)
508 {
509 if(file->_bufsiz) {
510 int cnt=file->_ptr-file->_base;
511 if(cnt>0 && _write(file->_file, file->_base, cnt) != cnt) {
512 file->_flag |= _IOERR;
513 return EOF;
514 }
515 file->_ptr=file->_base;
516 file->_cnt=file->_bufsiz;
517 }
518 return 0;
519 }
520
521 /* INTERNAL: Allocate stdio file buffer */
522 /*static*/ void alloc_buffer(FILE* file)
523 {
524 file->_base = calloc(BUFSIZ,1);
525 if(file->_base) {
526 file->_bufsiz = BUFSIZ;
527 file->_flag |= _IOMYBUF;
528 } else {
529 file->_base = (char*)(&file->_charbuf);
530 /* put here 2 ??? */
531 file->_bufsiz = sizeof(file->_charbuf);
532 }
533 file->_ptr = file->_base;
534 file->_cnt = 0;
535 }
536
537 /* INTERNAL: Convert integer to base32 string (0-9a-v), 0 becomes "" */
538 static int int_to_base32(int num, char *str)
539 {
540 char *p;
541 int n = num;
542 int digits = 0;
543
544 while (n != 0)
545 {
546 n >>= 5;
547 digits++;
548 }
549 p = str + digits;
550 *p = 0;
551 while (--p >= str)
552 {
553 *p = (num & 31) + '0';
554 if (*p > '9')
555 *p += ('a' - '0' - 10);
556 num >>= 5;
557 }
558
559 return digits;
560 }
561
562 /* INTERNAL: wide character version of int_to_base32 */
563 static int int_to_base32_w(int num, wchar_t *str)
564 {
565 wchar_t *p;
566 int n = num;
567 int digits = 0;
568
569 while (n != 0)
570 {
571 n >>= 5;
572 digits++;
573 }
574 p = str + digits;
575 *p = 0;
576 while (--p >= str)
577 {
578 *p = (num & 31) + '0';
579 if (*p > '9')
580 *p += ('a' - '0' - 10);
581 num >>= 5;
582 }
583
584 return digits;
585 }
586
587 /* INTERNAL: Create a wide string from an ascii string */
588 wchar_t *msvcrt_wstrdupa(const char *str)
589 {
590 const unsigned int len = strlen(str) + 1 ;
591 wchar_t *wstr = malloc(len* sizeof (wchar_t));
592 if (!wstr)
593 return NULL;
594 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,str,len,wstr,len);
595 return wstr;
596 }
597
598 /*********************************************************************
599 * __iob_func(MSVCRT.@)
600 */
601 FILE * CDECL __iob_func(void)
602 {
603 return &_iob[0];
604 }
605
606 /*********************************************************************
607 * _access (MSVCRT.@)
608 */
609 int CDECL _access(const char *filename, int mode)
610 {
611 DWORD attr = GetFileAttributesA(filename);
612
613 TRACE("(%s,%d) %d\n",filename,mode,attr);
614
615 if (!filename || attr == INVALID_FILE_ATTRIBUTES)
616 {
617 _dosmaperr(GetLastError());
618 return -1;
619 }
620 if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & W_OK))
621 {
622 _set_errno(ERROR_ACCESS_DENIED);
623 return -1;
624 }
625 return 0;
626 }
627
628 /*********************************************************************
629 * _access_s (MSVCRT.@)
630 */
631 int CDECL _access_s(const char *filename, int mode)
632 {
633 if (!MSVCRT_CHECK_PMT(filename != NULL) ||
634 !MSVCRT_CHECK_PMT((mode & ~(R_OK | W_OK)) == 0))
635 {
636 _set_errno(EINVAL);
637 return -1;
638 }
639
640 return _access(filename, mode);
641 }
642
643 /*********************************************************************
644 * _waccess (MSVCRT.@)
645 */
646 int CDECL _waccess(const wchar_t *filename, int mode)
647 {
648 DWORD attr = GetFileAttributesW(filename);
649
650 TRACE("(%s,%d) %d\n",debugstr_w(filename),mode,attr);
651
652 if (!filename || attr == INVALID_FILE_ATTRIBUTES)
653 {
654 _dosmaperr(GetLastError());
655 return -1;
656 }
657 if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & W_OK))
658 {
659 _set_errno(ERROR_ACCESS_DENIED);
660 return -1;
661 }
662 return 0;
663 }
664
665 /*********************************************************************
666 * _waccess_s (MSVCRT.@)
667 */
668 int CDECL _waccess_s(const wchar_t *filename, int mode)
669 {
670 if (!MSVCRT_CHECK_PMT(filename != NULL) ||
671 !MSVCRT_CHECK_PMT((mode & ~(R_OK | W_OK)) == 0))
672 {
673 *_errno() = EINVAL;
674 return -1;
675 }
676
677 return _waccess(filename, mode);
678 }
679
680 /*********************************************************************
681 * _chmod (MSVCRT.@)
682 */
683 int CDECL _chmod(const char *path, int flags)
684 {
685 DWORD oldFlags = GetFileAttributesA(path);
686
687 if (oldFlags != INVALID_FILE_ATTRIBUTES)
688 {
689 DWORD newFlags = (flags & _S_IWRITE)? oldFlags & ~FILE_ATTRIBUTE_READONLY:
690 oldFlags | FILE_ATTRIBUTE_READONLY;
691
692 if (newFlags == oldFlags || SetFileAttributesA(path, newFlags))
693 return 0;
694 }
695 _dosmaperr(GetLastError());
696 return -1;
697 }
698
699 /*********************************************************************
700 * _wchmod (MSVCRT.@)
701 */
702 int CDECL _wchmod(const wchar_t *path, int flags)
703 {
704 DWORD oldFlags = GetFileAttributesW(path);
705
706 if (oldFlags != INVALID_FILE_ATTRIBUTES)
707 {
708 DWORD newFlags = (flags & _S_IWRITE)? oldFlags & ~FILE_ATTRIBUTE_READONLY:
709 oldFlags | FILE_ATTRIBUTE_READONLY;
710
711 if (newFlags == oldFlags || SetFileAttributesW(path, newFlags))
712 return 0;
713 }
714 _dosmaperr(GetLastError());
715 return -1;
716 }
717
718 /*********************************************************************
719 * _unlink (MSVCRT.@)
720 */
721 int CDECL _unlink(const char *path)
722 {
723 TRACE("%s\n",debugstr_a(path));
724 if(DeleteFileA(path))
725 return 0;
726 TRACE("failed (%d)\n",GetLastError());
727 _dosmaperr(GetLastError());
728 return -1;
729 }
730
731 /*********************************************************************
732 * _wunlink (MSVCRT.@)
733 */
734 int CDECL _wunlink(const wchar_t *path)
735 {
736 TRACE("(%s)\n",debugstr_w(path));
737 if(DeleteFileW(path))
738 return 0;
739 TRACE("failed (%d)\n",GetLastError());
740 _dosmaperr(GetLastError());
741 return -1;
742 }
743
744 /* _flushall calls fflush which calls _flushall */
745 int CDECL fflush(FILE* file);
746
747 /* INTERNAL: Flush all stream buffer */
748 static int flush_all_buffers(int mask)
749 {
750 int i, num_flushed = 0;
751 FILE *file;
752
753 LOCK_FILES();
754 for (i = 3; i < stream_idx; i++) {
755 file = get_file(i);
756
757 if (file->_flag)
758 {
759 if(file->_flag & mask) {
760 fflush(file);
761 num_flushed++;
762 }
763 }
764 }
765 UNLOCK_FILES();
766
767 TRACE(":flushed (%d) handles\n",num_flushed);
768 return num_flushed;
769 }
770
771 /*********************************************************************
772 * _flushall (MSVCRT.@)
773 */
774 int CDECL _flushall(void)
775 {
776 return flush_all_buffers(_IOWRT | _IOREAD);
777 }
778
779 /*********************************************************************
780 * fflush (MSVCRT.@)
781 */
782 int CDECL fflush(FILE* file)
783 {
784 if(!file) {
785 flush_all_buffers(_IOWRT);
786 } else if(file->_flag & _IOWRT) {
787 int res;
788
789 _lock_file(file);
790 res = flush_buffer(file);
791 /* FIXME
792 if(!res && (file->_flag & _IOCOMMIT))
793 res = _commit(file->_file) ? EOF : 0;
794 */
795 _unlock_file(file);
796
797 return res;
798 } else if(file->_flag & _IOREAD) {
799 _lock_file(file);
800 file->_cnt = 0;
801 file->_ptr = file->_base;
802 _unlock_file(file);
803
804 return 0;
805 }
806 return 0;
807 }
808
809 /*********************************************************************
810 * _close (MSVCRT.@)
811 */
812 int CDECL _close(int fd)
813 {
814 HANDLE hand;
815 int ret;
816
817 LOCK_FILES();
818 hand = fdtoh(fd);
819 TRACE(":fd (%d) handle (%p)\n",fd,hand);
820 if (!is_valid_fd(fd)) {
821 ret = -1;
822 } else {
823 free_fd(fd);
824 ret = CloseHandle(hand) ? 0 : -1;
825 if (ret) {
826 WARN(":failed-last error (%d)\n",GetLastError());
827 _dosmaperr(GetLastError());
828 }
829 }
830 UNLOCK_FILES();
831 TRACE(":ok\n");
832 return ret;
833 }
834
835 /*********************************************************************
836 * _commit (MSVCRT.@)
837 */
838 int CDECL _commit(int fd)
839 {
840 HANDLE hand = fdtoh(fd);
841
842 TRACE(":fd (%d) handle (%p)\n",fd,hand);
843 if (hand == INVALID_HANDLE_VALUE)
844 return -1;
845
846 if (!FlushFileBuffers(hand))
847 {
848 if (GetLastError() == ERROR_INVALID_HANDLE)
849 {
850 /* FlushFileBuffers fails for console handles
851 * so we ignore this error.
852 */
853 return 0;
854 }
855 TRACE(":failed-last error (%d)\n",GetLastError());
856 _dosmaperr(GetLastError());
857 return -1;
858 }
859 TRACE(":ok\n");
860 return 0;
861 }
862
863 /*********************************************************************
864 * _dup2 (MSVCRT.@)
865 * NOTES
866 * MSDN isn't clear on this point, but the remarks for _pipe
867 * indicate file descriptors duplicated with _dup and _dup2 are always
868 * inheritable.
869 */
870 int CDECL _dup2(int od, int nd)
871 {
872 int ret;
873
874 TRACE("(od=%d, nd=%d)\n", od, nd);
875 LOCK_FILES();
876 if (nd < MAX_FILES && nd >= 0 && is_valid_fd(od))
877 {
878 HANDLE handle;
879
880 if (DuplicateHandle(GetCurrentProcess(), get_ioinfo(od)->handle,
881 GetCurrentProcess(), &handle, 0, TRUE, DUPLICATE_SAME_ACCESS))
882 {
883 int wxflag = get_ioinfo(od)->wxflag & ~_O_NOINHERIT;
884
885 if (is_valid_fd(nd))
886 _close(nd);
887 ret = alloc_fd_from(handle, wxflag, nd);
888 if (ret == -1)
889 {
890 CloseHandle(handle);
891 *_errno() = EMFILE;
892 }
893 else
894 {
895 /* _dup2 returns 0, not nd, on success */
896 ret = 0;
897 }
898 }
899 else
900 {
901 ret = -1;
902 _dosmaperr(GetLastError());
903 }
904 }
905 else
906 {
907 *_errno() = EBADF;
908 ret = -1;
909 }
910 UNLOCK_FILES();
911 return ret;
912 }
913
914 /*********************************************************************
915 * _dup (MSVCRT.@)
916 */
917 int CDECL _dup(int od)
918 {
919 int fd, ret;
920
921 LOCK_FILES();
922 fd = fdstart;
923 if (_dup2(od, fd) == 0)
924 ret = fd;
925 else
926 ret = -1;
927 UNLOCK_FILES();
928 return ret;
929 }
930
931 /*********************************************************************
932 * _eof (MSVCRT.@)
933 */
934 int CDECL _eof(int fd)
935 {
936 DWORD curpos,endpos;
937 LONG hcurpos,hendpos;
938 HANDLE hand = fdtoh(fd);
939
940 TRACE(":fd (%d) handle (%p)\n",fd,hand);
941
942 if (hand == INVALID_HANDLE_VALUE)
943 return -1;
944
945 if (get_ioinfo(fd)->wxflag & WX_ATEOF) return TRUE;
946
947 /* Otherwise we do it the hard way */
948 hcurpos = hendpos = 0;
949 curpos = SetFilePointer(hand, 0, &hcurpos, FILE_CURRENT);
950 endpos = SetFilePointer(hand, 0, &hendpos, FILE_END);
951
952 if (curpos == endpos && hcurpos == hendpos)
953 {
954 /* FIXME: shouldn't WX_ATEOF be set here? */
955 return TRUE;
956 }
957
958 SetFilePointer(hand, curpos, &hcurpos, FILE_BEGIN);
959 return FALSE;
960 }
961
962 /*********************************************************************
963 * _fcloseall (MSVCRT.@)
964 */
965 int CDECL _fcloseall(void)
966 {
967 int num_closed = 0, i;
968 FILE *file;
969
970 LOCK_FILES();
971 for (i = 3; i < stream_idx; i++) {
972 file = get_file(i);
973
974 if (file->_flag && !fclose(file))
975 num_closed++;
976 }
977 UNLOCK_FILES();
978
979 TRACE(":closed (%d) handles\n",num_closed);
980 return num_closed;
981 }
982
983 /* free everything on process exit */
984 void msvcrt_free_io(void)
985 {
986 int i;
987
988 _fcloseall();
989 /* The Win32 _fcloseall() function explicitly doesn't close stdin,
990 * stdout, and stderr (unlike GNU), so we need to fclose() them here
991 * or they won't get flushed.
992 */
993 fclose(&_iob[0]);
994 fclose(&_iob[1]);
995 fclose(&_iob[2]);
996
997 for(i=0; i<sizeof(__pioinfo)/sizeof(__pioinfo[0]); i++)
998 free(__pioinfo[i]);
999
1000 for(i=0; i<sizeof(fstream)/sizeof(fstream[0]); i++)
1001 free(fstream[i]);
1002
1003 file_cs.DebugInfo->Spare[0] = 0;
1004 DeleteCriticalSection(&file_cs);
1005 }
1006
1007 /*********************************************************************
1008 * _lseeki64 (MSVCRT.@)
1009 */
1010 __int64 CDECL _lseeki64(int fd, __int64 offset, int whence)
1011 {
1012 HANDLE hand = fdtoh(fd);
1013 LARGE_INTEGER ofs;
1014
1015 TRACE(":fd (%d) handle (%p)\n",fd,hand);
1016 if (hand == INVALID_HANDLE_VALUE)
1017 return -1;
1018
1019 if (whence < 0 || whence > 2)
1020 {
1021 *_errno() = EINVAL;
1022 return -1;
1023 }
1024
1025 TRACE(":fd (%d) to %s pos %s\n",
1026 fd,wine_dbgstr_longlong(offset),
1027 (whence==SEEK_SET)?"SEEK_SET":
1028 (whence==SEEK_CUR)?"SEEK_CUR":
1029 (whence==SEEK_END)?"SEEK_END":"UNKNOWN");
1030
1031 /* The MoleBox protection scheme expects msvcrt to use SetFilePointer only,
1032 * so a LARGE_INTEGER offset cannot be passed directly via SetFilePointerEx. */
1033 ofs.QuadPart = offset;
1034 if ((ofs.u.LowPart = SetFilePointer(hand, ofs.u.LowPart, &ofs.u.HighPart, whence)) != INVALID_SET_FILE_POINTER ||
1035 GetLastError() == ERROR_SUCCESS)
1036 {
1037 get_ioinfo(fd)->wxflag &= ~(WX_ATEOF|WX_READEOF);
1038 /* FIXME: What if we seek _to_ EOF - is EOF set? */
1039
1040 return ofs.QuadPart;
1041 }
1042 TRACE(":error-last error (%d)\n",GetLastError());
1043 _dosmaperr(GetLastError());
1044 return -1;
1045 }
1046
1047 /*********************************************************************
1048 * _lseek (MSVCRT.@)
1049 */
1050 LONG CDECL _lseek(int fd, LONG offset, int whence)
1051 {
1052 return (LONG)_lseeki64(fd, offset, whence);
1053 }
1054
1055 /*********************************************************************
1056 * _lock_file (MSVCRT.@)
1057 */
1058 void CDECL _lock_file(FILE *file)
1059 {
1060 if(file>=_iob && file<_iob+_IOB_ENTRIES)
1061 _lock(_STREAM_LOCKS+(file-_iob));
1062 /* ReactOS: string streams dont need to be locked */
1063 else if(!(file->_flag & _IOSTRG))
1064 EnterCriticalSection(&((file_crit*)file)->crit);
1065 }
1066
1067 /*********************************************************************
1068 * _unlock_file (MSVCRT.@)
1069 */
1070 void CDECL _unlock_file(FILE *file)
1071 {
1072 if(file>=_iob && file<_iob+_IOB_ENTRIES)
1073 _unlock(_STREAM_LOCKS+(file-_iob));
1074 /* ReactOS: string streams dont need to be locked */
1075 else if(!(file->_flag & _IOSTRG))
1076 LeaveCriticalSection(&((file_crit*)file)->crit);
1077
1078 }
1079
1080 /*********************************************************************
1081 * _locking (MSVCRT.@)
1082 *
1083 * This is untested; the underlying LockFile doesn't work yet.
1084 */
1085 int CDECL _locking(int fd, int mode, LONG nbytes)
1086 {
1087 BOOL ret;
1088 DWORD cur_locn;
1089 HANDLE hand = fdtoh(fd);
1090
1091 TRACE(":fd (%d) handle (%p)\n",fd,hand);
1092 if (hand == INVALID_HANDLE_VALUE)
1093 return -1;
1094
1095 if (mode < 0 || mode > 4)
1096 {
1097 *_errno() = EINVAL;
1098 return -1;
1099 }
1100
1101 TRACE(":fd (%d) by 0x%08x mode %s\n",
1102 fd,nbytes,(mode==_LK_UNLCK)?"_LK_UNLCK":
1103 (mode==_LK_LOCK)?"_LK_LOCK":
1104 (mode==_LK_NBLCK)?"_LK_NBLCK":
1105 (mode==_LK_RLCK)?"_LK_RLCK":
1106 (mode==_LK_NBRLCK)?"_LK_NBRLCK":
1107 "UNKNOWN");
1108
1109 if ((cur_locn = SetFilePointer(hand, 0L, NULL, SEEK_CUR)) == INVALID_SET_FILE_POINTER)
1110 {
1111 FIXME ("Seek failed\n");
1112 *_errno() = EINVAL; /* FIXME */
1113 return -1;
1114 }
1115 if (mode == _LK_LOCK || mode == _LK_RLCK)
1116 {
1117 int nretry = 10;
1118 ret = 1; /* just to satisfy gcc */
1119 while (nretry--)
1120 {
1121 ret = LockFile(hand, cur_locn, 0L, nbytes, 0L);
1122 if (ret) break;
1123 Sleep(1);
1124 }
1125 }
1126 else if (mode == _LK_UNLCK)
1127 ret = UnlockFile(hand, cur_locn, 0L, nbytes, 0L);
1128 else
1129 ret = LockFile(hand, cur_locn, 0L, nbytes, 0L);
1130 /* FIXME - what about error settings? */
1131 return ret ? 0 : -1;
1132 }
1133
1134 /*********************************************************************
1135 * _fseeki64 (MSVCRT.@)
1136 */
1137 int CDECL _fseeki64(FILE* file, __int64 offset, int whence)
1138 {
1139 int ret;
1140
1141 _lock_file(file);
1142 /* Flush output if needed */
1143 if(file->_flag & _IOWRT)
1144 flush_buffer(file);
1145
1146 if(whence == SEEK_CUR && file->_flag & _IOREAD ) {
1147 offset -= file->_cnt;
1148 if (get_ioinfo(file->_file)->wxflag & WX_TEXT) {
1149 /* Black magic correction for CR removal */
1150 int i;
1151 for (i=0; i<file->_cnt; i++) {
1152 if (file->_ptr[i] == '\n')
1153 offset--;
1154 }
1155 /* Black magic when reading CR at buffer boundary*/
1156 if(get_ioinfo(file->_file)->wxflag & WX_READCR)
1157 offset--;
1158 }
1159 }
1160 /* Discard buffered input */
1161 file->_cnt = 0;
1162 file->_ptr = file->_base;
1163 /* Reset direction of i/o */
1164 if(file->_flag & _IORW) {
1165 file->_flag &= ~(_IOREAD|_IOWRT);
1166 }
1167 /* Clear end of file flag */
1168 file->_flag &= ~_IOEOF;
1169 ret = (_lseeki64(file->_file,offset,whence) == -1)?-1:0;
1170
1171 _unlock_file(file);
1172 return ret;
1173 }
1174
1175 /*********************************************************************
1176 * fseek (MSVCRT.@)
1177 */
1178 int CDECL fseek(FILE* file, long offset, int whence)
1179 {
1180 return _fseeki64( file, offset, whence );
1181 }
1182
1183 /*********************************************************************
1184 * _chsize (MSVCRT.@)
1185 */
1186 int CDECL _chsize(int fd, long size)
1187 {
1188 LONG cur, pos;
1189 HANDLE handle;
1190 BOOL ret = FALSE;
1191
1192 TRACE("(fd=%d, size=%d)\n", fd, size);
1193
1194 LOCK_FILES();
1195
1196 handle = fdtoh(fd);
1197 if (handle != INVALID_HANDLE_VALUE)
1198 {
1199 /* save the current file pointer */
1200 cur = _lseek(fd, 0, SEEK_CUR);
1201 if (cur >= 0)
1202 {
1203 pos = _lseek(fd, size, SEEK_SET);
1204 if (pos >= 0)
1205 {
1206 ret = SetEndOfFile(handle);
1207 if (!ret) _dosmaperr(GetLastError());
1208 }
1209
1210 /* restore the file pointer */
1211 _lseek(fd, cur, SEEK_SET);
1212 }
1213 }
1214
1215 UNLOCK_FILES();
1216 return ret ? 0 : -1;
1217 }
1218
1219 /*********************************************************************
1220 * clearerr (MSVCRT.@)
1221 */
1222 void CDECL clearerr(FILE* file)
1223 {
1224 TRACE(":file (%p) fd (%d)\n",file,file->_file);
1225
1226 _lock_file(file);
1227 file->_flag &= ~(_IOERR | _IOEOF);
1228 _unlock_file(file);
1229 }
1230
1231 /*********************************************************************
1232 * rewind (MSVCRT.@)
1233 */
1234 void CDECL rewind(FILE* file)
1235 {
1236 TRACE(":file (%p) fd (%d)\n",file,file->_file);
1237
1238 _lock_file(file);
1239 fseek(file, 0L, SEEK_SET);
1240 clearerr(file);
1241 _unlock_file(file);
1242 }
1243
1244 static int get_flags(const wchar_t* mode, int *open_flags, int* stream_flags)
1245 {
1246 int plus = strchrW(mode, '+') != NULL;
1247
1248 while(*mode == ' ') mode++;
1249
1250 switch(*mode++)
1251 {
1252 case 'R': case 'r':
1253 *open_flags = plus ? _O_RDWR : _O_RDONLY;
1254 *stream_flags = plus ? _IORW : _IOREAD;
1255 break;
1256 case 'W': case 'w':
1257 *open_flags = _O_CREAT | _O_TRUNC | (plus ? _O_RDWR : _O_WRONLY);
1258 *stream_flags = plus ? _IORW : _IOWRT;
1259 break;
1260 case 'A': case 'a':
1261 *open_flags = _O_CREAT | _O_APPEND | (plus ? _O_RDWR : _O_WRONLY);
1262 *stream_flags = plus ? _IORW : _IOWRT;
1263 break;
1264 default:
1265 _invalid_parameter(NULL, NULL, NULL, 0, 0);
1266 *_errno() = EINVAL;
1267 return -1;
1268 }
1269
1270 /* FIXME */
1271 /* *stream_flags |= MSVCRT__commode; */
1272
1273 while (*mode && *mode!=',')
1274 switch (*mode++)
1275 {
1276 case 'B': case 'b':
1277 *open_flags |= _O_BINARY;
1278 *open_flags &= ~_O_TEXT;
1279 break;
1280 case 't':
1281 *open_flags |= _O_TEXT;
1282 *open_flags &= ~_O_BINARY;
1283 break;
1284 case 'D':
1285 *open_flags |= _O_TEMPORARY;
1286 break;
1287 case 'T':
1288 *open_flags |= _O_SHORT_LIVED;
1289 break;
1290 /* FIXME
1291 case 'c':
1292 *stream_flags |= _IOCOMMIT;
1293 break;
1294 case 'n':
1295 *stream_flags &= ~_IOCOMMIT;
1296 break;
1297 */
1298 case 'N':
1299 *open_flags |= _O_NOINHERIT;
1300 break;
1301 case '+':
1302 case ' ':
1303 case 'a':
1304 case 'w':
1305 break;
1306 case 'S':
1307 case 'R':
1308 FIXME("ignoring cache optimization flag: %c\n", mode[-1]);
1309 break;
1310 default:
1311 ERR("incorrect mode flag: %c\n", mode[-1]);
1312 break;
1313 }
1314
1315 if(*mode == ',')
1316 {
1317 static const WCHAR ccs[] = {'c','c','s'};
1318 static const WCHAR utf8[] = {'u','t','f','-','8'};
1319 static const WCHAR utf16le[] = {'u','t','f','-','1','6','l','e'};
1320 static const WCHAR unicode[] = {'u','n','i','c','o','d','e'};
1321
1322 mode++;
1323 while(*mode == ' ') mode++;
1324 if(!MSVCRT_CHECK_PMT(!strncmpW(ccs, mode, sizeof(ccs)/sizeof(ccs[0]))))
1325 return -1;
1326 mode += sizeof(ccs)/sizeof(ccs[0]);
1327 while(*mode == ' ') mode++;
1328 if(!MSVCRT_CHECK_PMT(*mode == '='))
1329 return -1;
1330 mode++;
1331 while(*mode == ' ') mode++;
1332
1333 if(!strncmpiW(utf8, mode, sizeof(utf8)/sizeof(utf8[0])))
1334 {
1335 *open_flags |= _O_U8TEXT;
1336 mode += sizeof(utf8)/sizeof(utf8[0]);
1337 }
1338 else if(!strncmpiW(utf16le, mode, sizeof(utf16le)/sizeof(utf16le[0])))
1339 {
1340 *open_flags |= _O_U16TEXT;
1341 mode += sizeof(utf16le)/sizeof(utf16le[0]);
1342 }
1343 else if(!strncmpiW(unicode, mode, sizeof(unicode)/sizeof(unicode[0])))
1344 {
1345 *open_flags |= _O_WTEXT;
1346 mode += sizeof(unicode)/sizeof(unicode[0]);
1347 }
1348 else
1349 {
1350 _invalid_parameter(NULL, NULL, NULL, 0, 0);
1351 *_errno() = EINVAL;
1352 return -1;
1353 }
1354
1355 while(*mode == ' ') mode++;
1356 }
1357
1358 if(!MSVCRT_CHECK_PMT(*mode == 0))
1359 return -1;
1360
1361 return 0;
1362 }
1363
1364 /*********************************************************************
1365 * _fdopen (MSVCRT.@)
1366 */
1367 FILE* CDECL _fdopen(int fd, const char *mode)
1368 {
1369 FILE *ret;
1370 wchar_t *modeW = NULL;
1371
1372 if (mode && !(modeW = msvcrt_wstrdupa(mode))) return NULL;
1373
1374 ret = _wfdopen(fd, modeW);
1375
1376 free(modeW);
1377 return ret;
1378 }
1379
1380 /*********************************************************************
1381 * _wfdopen (MSVCRT.@)
1382 */
1383 FILE* CDECL _wfdopen(int fd, const wchar_t *mode)
1384 {
1385 int open_flags, stream_flags;
1386 FILE* file;
1387
1388 if (get_flags(mode, &open_flags, &stream_flags) == -1) return NULL;
1389
1390 LOCK_FILES();
1391 if (!(file = alloc_fp()))
1392 file = NULL;
1393 else if (init_fp(file, fd, stream_flags) == -1)
1394 {
1395 file->_flag = 0;
1396 file = NULL;
1397 }
1398 else TRACE(":fd (%d) mode (%s) FILE* (%p)\n", fd, debugstr_w(mode), file);
1399 UNLOCK_FILES();
1400
1401 return file;
1402 }
1403
1404 /*********************************************************************
1405 * _filelength (MSVCRT.@)
1406 */
1407 LONG CDECL _filelength(int fd)
1408 {
1409 LONG curPos = _lseek(fd, 0, SEEK_CUR);
1410 if (curPos != -1)
1411 {
1412 LONG endPos = _lseek(fd, 0, SEEK_END);
1413 if (endPos != -1)
1414 {
1415 if (endPos != curPos)
1416 _lseek(fd, curPos, SEEK_SET);
1417 return endPos;
1418 }
1419 }
1420 return -1;
1421 }
1422
1423 /*********************************************************************
1424 * _filelengthi64 (MSVCRT.@)
1425 */
1426 __int64 CDECL _filelengthi64(int fd)
1427 {
1428 __int64 curPos = _lseeki64(fd, 0, SEEK_CUR);
1429 if (curPos != -1)
1430 {
1431 __int64 endPos = _lseeki64(fd, 0, SEEK_END);
1432 if (endPos != -1)
1433 {
1434 if (endPos != curPos)
1435 _lseeki64(fd, curPos, SEEK_SET);
1436 return endPos;
1437 }
1438 }
1439 return -1;
1440 }
1441
1442 /*********************************************************************
1443 * _fileno (MSVCRT.@)
1444 */
1445 int CDECL _fileno(FILE* file)
1446 {
1447 TRACE(":FILE* (%p) fd (%d)\n",file,file->_file);
1448 return file->_file;
1449 }
1450
1451 /*********************************************************************
1452 * _get_osfhandle (MSVCRT.@)
1453 */
1454 intptr_t CDECL _get_osfhandle(int fd)
1455 {
1456 HANDLE hand = fdtoh(fd);
1457 TRACE(":fd (%d) handle (%p)\n",fd,hand);
1458
1459 return (intptr_t)hand;
1460 }
1461
1462 /*********************************************************************
1463 * _isatty (MSVCRT.@)
1464 */
1465 int CDECL _isatty(int fd)
1466 {
1467 HANDLE hand = fdtoh(fd);
1468
1469 TRACE(":fd (%d) handle (%p)\n",fd,hand);
1470 if (hand == INVALID_HANDLE_VALUE)
1471 return 0;
1472
1473 return GetFileType(hand) == FILE_TYPE_CHAR? 1 : 0;
1474 }
1475
1476 /*********************************************************************
1477 * _mktemp (MSVCRT.@)
1478 */
1479 char * CDECL _mktemp(char *pattern)
1480 {
1481 int numX = 0;
1482 char *retVal = pattern;
1483 int id;
1484 char letter = 'a';
1485
1486 while(*pattern)
1487 numX = (*pattern++ == 'X')? numX + 1 : 0;
1488 if (numX < 5)
1489 return NULL;
1490 pattern--;
1491 id = GetCurrentProcessId();
1492 numX = 6;
1493 while(numX--)
1494 {
1495 int tempNum = id / 10;
1496 *pattern-- = id - (tempNum * 10) + '0';
1497 id = tempNum;
1498 }
1499 pattern++;
1500 do
1501 {
1502 *pattern = letter++;
1503 if (GetFileAttributesA(retVal) == INVALID_FILE_ATTRIBUTES &&
1504 GetLastError() == ERROR_FILE_NOT_FOUND)
1505 return retVal;
1506 } while(letter <= 'z');
1507 return NULL;
1508 }
1509
1510 /*********************************************************************
1511 * _wmktemp (MSVCRT.@)
1512 */
1513 wchar_t * CDECL _wmktemp(wchar_t *pattern)
1514 {
1515 int numX = 0;
1516 wchar_t *retVal = pattern;
1517 int id;
1518 wchar_t letter = 'a';
1519
1520 while(*pattern)
1521 numX = (*pattern++ == 'X')? numX + 1 : 0;
1522 if (numX < 5)
1523 return NULL;
1524 pattern--;
1525 id = GetCurrentProcessId();
1526 numX = 6;
1527 while(numX--)
1528 {
1529 int tempNum = id / 10;
1530 *pattern-- = id - (tempNum * 10) + '0';
1531 id = tempNum;
1532 }
1533 pattern++;
1534 do
1535 {
1536 if (GetFileAttributesW(retVal) == INVALID_FILE_ATTRIBUTES &&
1537 GetLastError() == ERROR_FILE_NOT_FOUND)
1538 return retVal;
1539 *pattern = letter++;
1540 } while(letter != '|');
1541 return NULL;
1542 }
1543
1544 /*static*/ unsigned split_oflags(unsigned oflags)
1545 {
1546 int wxflags = 0;
1547 unsigned unsupp; /* until we support everything */
1548
1549 if (oflags & _O_APPEND) wxflags |= WX_APPEND;
1550 if (oflags & _O_BINARY) {/* Nothing to do */}
1551 else if (oflags & _O_TEXT) wxflags |= WX_TEXT;
1552 else if (oflags & _O_WTEXT) wxflags |= WX_TEXT;
1553 else if (oflags & _O_U16TEXT) wxflags |= WX_TEXT;
1554 else if (oflags & _O_U8TEXT) wxflags |= WX_TEXT;
1555 else if (*__p__fmode() & _O_BINARY) {/* Nothing to do */}
1556 else wxflags |= WX_TEXT; /* default to TEXT*/
1557 if (oflags & _O_NOINHERIT) wxflags |= WX_DONTINHERIT;
1558
1559 if ((unsupp = oflags & ~(
1560 _O_BINARY|_O_TEXT|_O_APPEND|
1561 _O_TRUNC|_O_EXCL|_O_CREAT|
1562 _O_RDWR|_O_WRONLY|_O_TEMPORARY|
1563 _O_NOINHERIT|
1564 _O_SEQUENTIAL|_O_RANDOM|_O_SHORT_LIVED|
1565 _O_WTEXT|_O_U16TEXT|_O_U8TEXT
1566 )))
1567 ERR(":unsupported oflags 0x%04x\n",unsupp);
1568
1569 return wxflags;
1570 }
1571
1572 /*********************************************************************
1573 * _pipe (MSVCRT.@)
1574 */
1575 int CDECL _pipe(int *pfds, unsigned int psize, int textmode)
1576 {
1577 int ret = -1;
1578 SECURITY_ATTRIBUTES sa;
1579 HANDLE readHandle, writeHandle;
1580
1581 if (!pfds)
1582 {
1583 *_errno() = EINVAL;
1584 return -1;
1585 }
1586
1587 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
1588 sa.bInheritHandle = !(textmode & _O_NOINHERIT);
1589 sa.lpSecurityDescriptor = NULL;
1590 if (CreatePipe(&readHandle, &writeHandle, &sa, psize))
1591 {
1592 unsigned int wxflags = split_oflags(textmode);
1593 int fd;
1594
1595 LOCK_FILES();
1596 fd = alloc_fd(readHandle, wxflags);
1597 if (fd != -1)
1598 {
1599 pfds[0] = fd;
1600 fd = alloc_fd(writeHandle, wxflags);
1601 if (fd != -1)
1602 {
1603 pfds[1] = fd;
1604 ret = 0;
1605 }
1606 else
1607 {
1608 _close(pfds[0]);
1609 CloseHandle(writeHandle);
1610 *_errno() = EMFILE;
1611 }
1612 }
1613 else
1614 {
1615 CloseHandle(readHandle);
1616 CloseHandle(writeHandle);
1617 *_errno() = EMFILE;
1618 }
1619 UNLOCK_FILES();
1620 }
1621 else
1622 _dosmaperr(GetLastError());
1623
1624 return ret;
1625 }
1626
1627 /*********************************************************************
1628 * _sopen_s (MSVCRT.@)
1629 */
1630 int CDECL _sopen_s( int *fd, const char *path, int oflags, int shflags, int pmode )
1631 {
1632 DWORD access = 0, creation = 0, attrib;
1633 DWORD sharing;
1634 int wxflag;
1635 HANDLE hand;
1636 SECURITY_ATTRIBUTES sa;
1637
1638 TRACE("fd*: %p file: (%s) oflags: 0x%04x shflags: 0x%04x pmode: 0x%04x\n",
1639 fd, path, oflags, shflags, pmode);
1640
1641 if (!fd)
1642 {
1643 MSVCRT_INVALID_PMT("null out fd pointer");
1644 *_errno() = EINVAL;
1645 return EINVAL;
1646 }
1647
1648 *fd = -1;
1649 wxflag = split_oflags(oflags);
1650 switch (oflags & (_O_RDONLY | _O_WRONLY | _O_RDWR))
1651 {
1652 case _O_RDONLY: access |= GENERIC_READ; break;
1653 case _O_WRONLY: access |= GENERIC_WRITE; break;
1654 case _O_RDWR: access |= GENERIC_WRITE | GENERIC_READ; break;
1655 }
1656
1657 if (oflags & _O_CREAT)
1658 {
1659 if(pmode & ~(_S_IREAD | _S_IWRITE))
1660 FIXME(": pmode 0x%04x ignored\n", pmode);
1661 else
1662 WARN(": pmode 0x%04x ignored\n", pmode);
1663
1664 if (oflags & _O_EXCL)
1665 creation = CREATE_NEW;
1666 else if (oflags & _O_TRUNC)
1667 creation = CREATE_ALWAYS;
1668 else
1669 creation = OPEN_ALWAYS;
1670 }
1671 else /* no _O_CREAT */
1672 {
1673 if (oflags & _O_TRUNC)
1674 creation = TRUNCATE_EXISTING;
1675 else
1676 creation = OPEN_EXISTING;
1677 }
1678
1679 switch( shflags )
1680 {
1681 case _SH_DENYRW:
1682 sharing = 0L;
1683 break;
1684 case _SH_DENYWR:
1685 sharing = FILE_SHARE_READ;
1686 break;
1687 case _SH_DENYRD:
1688 sharing = FILE_SHARE_WRITE;
1689 break;
1690 case _SH_DENYNO:
1691 sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
1692 break;
1693 default:
1694 ERR( "Unhandled shflags 0x%x\n", shflags );
1695 return EINVAL;
1696 }
1697 attrib = FILE_ATTRIBUTE_NORMAL;
1698
1699 if (oflags & _O_TEMPORARY)
1700 {
1701 attrib |= FILE_FLAG_DELETE_ON_CLOSE;
1702 access |= DELETE;
1703 sharing |= FILE_SHARE_DELETE;
1704 }
1705
1706 sa.nLength = sizeof( SECURITY_ATTRIBUTES );
1707 sa.lpSecurityDescriptor = NULL;
1708 sa.bInheritHandle = (oflags & _O_NOINHERIT) ? FALSE : TRUE;
1709
1710 hand = CreateFileA(path, access, sharing, &sa, creation, attrib, 0);
1711 if (hand == INVALID_HANDLE_VALUE) {
1712 WARN(":failed-last error (%d)\n", GetLastError());
1713 _dosmaperr(GetLastError());
1714 return *_errno();
1715 }
1716
1717 *fd = alloc_fd(hand, wxflag);
1718 if (*fd == -1)
1719 return *_errno();
1720
1721 TRACE(":fd (%d) handle (%p)\n", *fd, hand);
1722 return 0;
1723 }
1724
1725 /*********************************************************************
1726 * _sopen (MSVCRT.@)
1727 */
1728 int CDECL _sopen( const char *path, int oflags, int shflags, ... )
1729 {
1730 int pmode;
1731 int fd;
1732
1733 if (oflags & _O_CREAT)
1734 {
1735 va_list ap;
1736
1737 va_start(ap, shflags);
1738 pmode = va_arg(ap, int);
1739 va_end(ap);
1740 }
1741 else
1742 pmode = 0;
1743
1744 _sopen_s(&fd, path, oflags, shflags, pmode);
1745 return fd;
1746 }
1747
1748 static int check_bom(HANDLE h, int oflags, BOOL seek)
1749 {
1750 char bom[sizeof(utf8_bom)];
1751 DWORD r;
1752
1753 oflags &= ~(_O_WTEXT|_O_U16TEXT|_O_U8TEXT);
1754
1755 if (!ReadFile(h, bom, sizeof(utf8_bom), &r, NULL))
1756 return oflags;
1757
1758 if (r==sizeof(utf8_bom) && !memcmp(bom, utf8_bom, sizeof(utf8_bom))) {
1759 oflags |= _O_U8TEXT;
1760 }else if (r>=sizeof(utf16_bom) && !memcmp(bom, utf16_bom, sizeof(utf16_bom))) {
1761 if (seek && r>2)
1762 SetFilePointer(h, 2, NULL, FILE_BEGIN);
1763 oflags |= _O_U16TEXT;
1764 }else if (seek) {
1765 SetFilePointer(h, 0, NULL, FILE_BEGIN);
1766 }
1767
1768 return oflags;
1769 }
1770
1771 /*********************************************************************
1772 * _wsopen_s (MSVCRT.@)
1773 */
1774 int CDECL _wsopen_s( int *fd, const wchar_t* path, int oflags, int shflags, int pmode )
1775 {
1776 DWORD access = 0, creation = 0, attrib;
1777 SECURITY_ATTRIBUTES sa;
1778 DWORD sharing;
1779 int wxflag;
1780 HANDLE hand;
1781
1782 TRACE("fd*: %p :file (%s) oflags: 0x%04x shflags: 0x%04x pmode: 0x%04x\n",
1783 fd, debugstr_w(path), oflags, shflags, pmode);
1784
1785 if (!MSVCRT_CHECK_PMT( fd != NULL )) return EINVAL;
1786
1787 *fd = -1;
1788 wxflag = split_oflags(oflags);
1789 switch (oflags & (_O_RDONLY | _O_WRONLY | _O_RDWR))
1790 {
1791 case _O_RDONLY: access |= GENERIC_READ; break;
1792 case _O_WRONLY: access |= GENERIC_WRITE; break;
1793 case _O_RDWR: access |= GENERIC_WRITE | GENERIC_READ; break;
1794 }
1795
1796 if (oflags & _O_CREAT)
1797 {
1798 if(pmode & ~(_S_IREAD | _S_IWRITE))
1799 FIXME(": pmode 0x%04x ignored\n", pmode);
1800 else
1801 WARN(": pmode 0x%04x ignored\n", pmode);
1802
1803 if (oflags & _O_EXCL)
1804 creation = CREATE_NEW;
1805 else if (oflags & _O_TRUNC)
1806 creation = CREATE_ALWAYS;
1807 else
1808 creation = OPEN_ALWAYS;
1809 }
1810 else /* no _O_CREAT */
1811 {
1812 if (oflags & _O_TRUNC)
1813 creation = TRUNCATE_EXISTING;
1814 else
1815 creation = OPEN_EXISTING;
1816 }
1817
1818 switch( shflags )
1819 {
1820 case _SH_DENYRW:
1821 sharing = 0L;
1822 break;
1823 case _SH_DENYWR:
1824 sharing = FILE_SHARE_READ;
1825 break;
1826 case _SH_DENYRD:
1827 sharing = FILE_SHARE_WRITE;
1828 break;
1829 case _SH_DENYNO:
1830 sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
1831 break;
1832 default:
1833 ERR( "Unhandled shflags 0x%x\n", shflags );
1834 return EINVAL;
1835 }
1836 attrib = FILE_ATTRIBUTE_NORMAL;
1837
1838 if (oflags & _O_TEMPORARY)
1839 {
1840 attrib |= FILE_FLAG_DELETE_ON_CLOSE;
1841 access |= DELETE;
1842 sharing |= FILE_SHARE_DELETE;
1843 }
1844
1845 sa.nLength = sizeof( SECURITY_ATTRIBUTES );
1846 sa.lpSecurityDescriptor = NULL;
1847 sa.bInheritHandle = (oflags & _O_NOINHERIT) ? FALSE : TRUE;
1848
1849 if ((oflags&(_O_WTEXT|_O_U16TEXT|_O_U8TEXT))
1850 && (creation==OPEN_ALWAYS || creation==OPEN_EXISTING)
1851 && !(access&GENERIC_READ))
1852 {
1853 hand = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
1854 &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
1855 if (hand != INVALID_HANDLE_VALUE)
1856 {
1857 oflags = check_bom(hand, oflags, FALSE);
1858 CloseHandle(hand);
1859 }
1860 else
1861 oflags &= ~(_O_WTEXT|_O_U16TEXT|_O_U8TEXT);
1862 }
1863
1864 hand = CreateFileW(path, access, sharing, &sa, creation, attrib, 0);
1865 if (hand == INVALID_HANDLE_VALUE) {
1866 WARN(":failed-last error (%d)\n",GetLastError());
1867 _dosmaperr(GetLastError());
1868 return *_errno();
1869 }
1870
1871 if (oflags & (_O_WTEXT|_O_U16TEXT|_O_U8TEXT))
1872 {
1873 if ((access & GENERIC_WRITE) && (creation==CREATE_NEW
1874 || creation==CREATE_ALWAYS || creation==TRUNCATE_EXISTING
1875 || (creation==OPEN_ALWAYS && GetLastError()==ERROR_ALREADY_EXISTS)))
1876 {
1877 if (oflags & _O_U8TEXT)
1878 {
1879 DWORD written = 0, tmp;
1880
1881 while(written!=sizeof(utf8_bom) && WriteFile(hand, (char*)utf8_bom+written,
1882 sizeof(utf8_bom)-written, &tmp, NULL))
1883 written += tmp;
1884 if (written != sizeof(utf8_bom)) {
1885 WARN("error writing BOM\n");
1886 CloseHandle(hand);
1887 _dosmaperr(GetLastError());
1888 return *_errno();
1889 }
1890 }
1891 else
1892 {
1893 DWORD written = 0, tmp;
1894
1895 while(written!=sizeof(utf16_bom) && WriteFile(hand, (char*)utf16_bom+written,
1896 sizeof(utf16_bom)-written, &tmp, NULL))
1897 written += tmp;
1898 if (written != sizeof(utf16_bom))
1899 {
1900 WARN("error writing BOM\n");
1901 CloseHandle(hand);
1902 _dosmaperr(GetLastError());
1903 return *_errno();
1904 }
1905 }
1906 }
1907 else if (access & GENERIC_READ)
1908 oflags = check_bom(hand, oflags, TRUE);
1909 }
1910
1911 *fd = alloc_fd(hand, wxflag);
1912 if (*fd == -1)
1913 return *_errno();
1914
1915 if (oflags & _O_WTEXT)
1916 get_ioinfo(*fd)->exflag |= EF_UTF16|EF_UNK_UNICODE;
1917 else if (oflags & _O_U16TEXT)
1918 get_ioinfo(*fd)->exflag |= EF_UTF16;
1919 else if (oflags & _O_U8TEXT)
1920 get_ioinfo(*fd)->exflag |= EF_UTF8;
1921
1922 TRACE(":fd (%d) handle (%p)\n", *fd, hand);
1923 return 0;
1924 }
1925
1926 /*********************************************************************
1927 * _wsopen (MSVCRT.@)
1928 */
1929 int CDECL _wsopen( const wchar_t *path, int oflags, int shflags, ... )
1930 {
1931 int pmode;
1932 int fd;
1933
1934 if (oflags & _O_CREAT)
1935 {
1936 va_list ap;
1937
1938 va_start(ap, shflags);
1939 pmode = va_arg(ap, int);
1940 va_end(ap);
1941 }
1942 else
1943 pmode = 0;
1944
1945 _wsopen_s(&fd, path, oflags, shflags, pmode);
1946 return fd;
1947 }
1948
1949 /*********************************************************************
1950 * _open (MSVCRT.@)
1951 */
1952 int CDECL _open( const char *path, int flags, ... )
1953 {
1954 va_list ap;
1955
1956 if (flags & _O_CREAT)
1957 {
1958 int pmode;
1959 va_start(ap, flags);
1960 pmode = va_arg(ap, int);
1961 va_end(ap);
1962 return _sopen( path, flags, _SH_DENYNO, pmode );
1963 }
1964 else
1965 return _sopen( path, flags, _SH_DENYNO);
1966 }
1967
1968 /*********************************************************************
1969 * _wopen (MSVCRT.@)
1970 */
1971 int CDECL _wopen(const wchar_t *path,int flags,...)
1972 {
1973 va_list ap;
1974
1975 if (flags & _O_CREAT)
1976 {
1977 int pmode;
1978 va_start(ap, flags);
1979 pmode = va_arg(ap, int);
1980 va_end(ap);
1981 return _wsopen( path, flags, _SH_DENYNO, pmode );
1982 }
1983 else
1984 return _wsopen( path, flags, _SH_DENYNO);
1985 }
1986
1987 /*********************************************************************
1988 * _creat (MSVCRT.@)
1989 */
1990 int CDECL _creat(const char *path, int flags)
1991 {
1992 int usedFlags = (flags & _O_TEXT)| _O_CREAT| _O_WRONLY| _O_TRUNC;
1993 return _open(path, usedFlags);
1994 }
1995
1996 /*********************************************************************
1997 * _wcreat (MSVCRT.@)
1998 */
1999 int CDECL _wcreat(const wchar_t *path, int flags)
2000 {
2001 int usedFlags = (flags & _O_TEXT)| _O_CREAT| _O_WRONLY| _O_TRUNC;
2002 return _wopen(path, usedFlags);
2003 }
2004
2005 /*********************************************************************
2006 * _open_osfhandle (MSVCRT.@)
2007 */
2008 int CDECL _open_osfhandle(intptr_t handle, int oflags)
2009 {
2010 int fd;
2011
2012 /* _O_RDONLY (0) always matches, so set the read flag
2013 * MFC's CStdioFile clears O_RDONLY (0)! if it wants to write to the
2014 * file, so set the write flag. It also only sets _O_TEXT if it wants
2015 * text - it never sets _O_BINARY.
2016 */
2017 /* don't let split_oflags() decide the mode if no mode is passed */
2018 if (!(oflags & (_O_BINARY | _O_TEXT)))
2019 oflags |= _O_BINARY;
2020
2021 fd = alloc_fd((HANDLE)handle, split_oflags(oflags));
2022 TRACE(":handle (%ld) fd (%d) flags 0x%08x\n", handle, fd, oflags);
2023 return fd;
2024 }
2025
2026 /*********************************************************************
2027 * _rmtmp (MSVCRT.@)
2028 */
2029 int CDECL _rmtmp(void)
2030 {
2031 int num_removed = 0, i;
2032 FILE *file;
2033
2034 LOCK_FILES();
2035 for (i = 3; i < stream_idx; i++) {
2036 file = get_file(i);
2037
2038 if (file->_tmpfname)
2039 {
2040 fclose(file);
2041 num_removed++;
2042 }
2043 }
2044 UNLOCK_FILES();
2045
2046 if (num_removed)
2047 TRACE(":removed (%d) temp files\n",num_removed);
2048 return num_removed;
2049 }
2050
2051 /*********************************************************************
2052 * (internal) read_i
2053 *
2054 * When reading \r as last character in text mode, read() positions
2055 * the file pointer on the \r character while getc() goes on to
2056 * the following \n
2057 */
2058 static int read_i(int fd, void *buf, unsigned int count)
2059 {
2060 DWORD num_read;
2061 char *bufstart = buf;
2062 HANDLE hand = fdtoh(fd);
2063 ioinfo *fdinfo = get_ioinfo(fd);
2064
2065 if (count == 0)
2066 return 0;
2067
2068 if (fdinfo->wxflag & WX_READEOF) {
2069 fdinfo->wxflag |= WX_ATEOF;
2070 TRACE("already at EOF, returning 0\n");
2071 return 0;
2072 }
2073 /* Don't trace small reads, it gets *very* annoying */
2074 if (count > 4)
2075 TRACE(":fd (%d) handle (%p) buf (%p) len (%d)\n",fd,hand,buf,count);
2076 if (hand == INVALID_HANDLE_VALUE)
2077 return -1;
2078
2079 /* Reading single bytes in O_TEXT mode makes things slow
2080 * So read big chunks
2081 */
2082 if (ReadFile(hand, bufstart, count, &num_read, NULL))
2083 {
2084 if (count != 0 && num_read == 0)
2085 {
2086 fdinfo->wxflag |= (WX_ATEOF|WX_READEOF);
2087 TRACE(":EOF %s\n",debugstr_an(buf,num_read));
2088 }
2089 else if (fdinfo->wxflag & WX_TEXT)
2090 {
2091 DWORD i, j;
2092 if (bufstart[num_read-1] == '\r')
2093 {
2094 if(count == 1)
2095 {
2096 fdinfo->wxflag &= ~WX_READCR;
2097 ReadFile(hand, bufstart, 1, &num_read, NULL);
2098 }
2099 else
2100 {
2101 fdinfo->wxflag |= WX_READCR;
2102 num_read--;
2103 }
2104 }
2105 else
2106 fdinfo->wxflag &= ~WX_READCR;
2107 for (i=0, j=0; i<num_read; i++)
2108 {
2109 /* in text mode, a ctrl-z signals EOF */
2110 if (bufstart[i] == 0x1a)
2111 {
2112 fdinfo->wxflag |= (WX_ATEOF|WX_READEOF);
2113 TRACE(":^Z EOF %s\n",debugstr_an(buf,num_read));
2114 break;
2115 }
2116 /* in text mode, strip \r if followed by \n.
2117 * BUG: should save state across calls somehow, so CR LF that
2118 * straddles buffer boundary gets recognized properly?
2119 */
2120 if ((bufstart[i] != '\r')
2121 || ((i+1) < num_read && bufstart[i+1] != '\n'))
2122 bufstart[j++] = bufstart[i];
2123 }
2124 num_read = j;
2125 }
2126 }
2127 else
2128 {
2129 if (GetLastError() == ERROR_BROKEN_PIPE)
2130 {
2131 TRACE(":end-of-pipe\n");
2132 fdinfo->wxflag |= (WX_ATEOF|WX_READEOF);
2133 return 0;
2134 }
2135 else
2136 {
2137 TRACE(":failed-last error (%d)\n",GetLastError());
2138 return -1;
2139 }
2140 }
2141
2142 if (count > 4)
2143 TRACE("(%u), %s\n",num_read,debugstr_an(buf, num_read));
2144 return num_read;
2145 }
2146
2147 /*********************************************************************
2148 * _read (MSVCRT.@)
2149 */
2150 int CDECL _read(int fd, void *buf, unsigned int count)
2151 {
2152 int num_read;
2153 num_read = read_i(fd, buf, count);
2154 return num_read;
2155 }
2156
2157 /*********************************************************************
2158 * _setmode (MSVCRT.@)
2159 */
2160 int CDECL _setmode(int fd,int mode)
2161 {
2162 int ret = get_ioinfo(fd)->wxflag & WX_TEXT ? _O_TEXT : _O_BINARY;
2163 if (mode & (~(_O_TEXT|_O_BINARY)))
2164 FIXME("fd (%d) mode (0x%08x) unknown\n",fd,mode);
2165 if ((mode & _O_TEXT) == _O_TEXT)
2166 get_ioinfo(fd)->wxflag |= WX_TEXT;
2167 else
2168 get_ioinfo(fd)->wxflag &= ~WX_TEXT;
2169 return ret;
2170 }
2171
2172 /*********************************************************************
2173 * _tell (MSVCRT.@)
2174 */
2175 long CDECL _tell(int fd)
2176 {
2177 return _lseek(fd, 0, SEEK_CUR);
2178 }
2179
2180 /*********************************************************************
2181 * _telli64 (MSVCRT.@)
2182 */
2183 __int64 CDECL _telli64(int fd)
2184 {
2185 return _lseeki64(fd, 0, SEEK_CUR);
2186 }
2187
2188 /*********************************************************************
2189 * _tempnam (MSVCRT.@)
2190 */
2191 char * CDECL _tempnam(const char *dir, const char *prefix)
2192 {
2193 char tmpbuf[MAX_PATH];
2194 const char *tmp_dir = getenv("TMP");
2195
2196 if (tmp_dir) dir = tmp_dir;
2197
2198 TRACE("dir (%s) prefix (%s)\n",dir,prefix);
2199 if (GetTempFileNameA(dir,prefix,0,tmpbuf))
2200 {
2201 TRACE("got name (%s)\n",tmpbuf);
2202 DeleteFileA(tmpbuf);
2203 return _strdup(tmpbuf);
2204 }
2205 TRACE("failed (%d)\n",GetLastError());
2206 return NULL;
2207 }
2208
2209 /*********************************************************************
2210 * _wtempnam (MSVCRT.@)
2211 */
2212 wchar_t * CDECL _wtempnam(const wchar_t *dir, const wchar_t *prefix)
2213 {
2214 wchar_t tmpbuf[MAX_PATH];
2215
2216 TRACE("dir (%s) prefix (%s)\n",debugstr_w(dir),debugstr_w(prefix));
2217 if (GetTempFileNameW(dir,prefix,0,tmpbuf))
2218 {
2219 TRACE("got name (%s)\n",debugstr_w(tmpbuf));
2220 DeleteFileW(tmpbuf);
2221 return _wcsdup(tmpbuf);
2222 }
2223 TRACE("failed (%d)\n",GetLastError());
2224 return NULL;
2225 }
2226
2227 /*********************************************************************
2228 * _umask (MSVCRT.@)
2229 */
2230 int CDECL _umask(int umask)
2231 {
2232 int old_umask = umask;
2233 TRACE("(%d)\n",umask);
2234 MSVCRT_umask = umask;
2235 return old_umask;
2236 }
2237
2238 /*********************************************************************
2239 * _write (MSVCRT.@)
2240 */
2241 int CDECL _write(int fd, const void* buf, unsigned int count)
2242 {
2243 DWORD num_written;
2244 HANDLE hand = fdtoh(fd);
2245
2246 /* Don't trace small writes, it gets *very* annoying */
2247 #if 0
2248 if (count > 32)
2249 TRACE(":fd (%d) handle (%d) buf (%p) len (%d)\n",fd,hand,buf,count);
2250 #endif
2251 if (hand == INVALID_HANDLE_VALUE)
2252 {
2253 *_errno() = EBADF;
2254 return -1;
2255 }
2256
2257 /* If appending, go to EOF */
2258 if (get_ioinfo(fd)->wxflag & WX_APPEND)
2259 _lseek(fd, 0, FILE_END);
2260
2261 if (!(get_ioinfo(fd)->wxflag & WX_TEXT))
2262 {
2263 if (WriteFile(hand, buf, count, &num_written, NULL)
2264 && (num_written == count))
2265 return num_written;
2266 TRACE("WriteFile (fd %d, hand %p) failed-last error (%d)\n", fd,
2267 hand, GetLastError());
2268 *_errno() = ENOSPC;
2269 }
2270 else
2271 {
2272 unsigned int i, j, nr_lf;
2273 char *p = NULL;
2274 const char *q;
2275 const char *s = buf, *buf_start = buf;
2276 /* find number of \n ( without preceding \r ) */
2277 for ( nr_lf=0,i = 0; i <count; i++)
2278 {
2279 if (s[i]== '\n')
2280 {
2281 nr_lf++;
2282 /*if ((i >1) && (s[i-1] == '\r')) nr_lf--; */
2283 }
2284 }
2285 if (nr_lf)
2286 {
2287 if ((q = p = malloc(count + nr_lf)))
2288 {
2289 for (s = buf, i = 0, j = 0; i < count; i++)
2290 {
2291 if (s[i]== '\n')
2292 {
2293 p[j++] = '\r';
2294 /*if ((i >1) && (s[i-1] == '\r'))j--;*/
2295 }
2296 p[j++] = s[i];
2297 }
2298 }
2299 else
2300 {
2301 FIXME("Malloc failed\n");
2302 nr_lf =0;
2303 q = buf;
2304 }
2305 }
2306 else
2307 q = buf;
2308
2309 if ((WriteFile(hand, q, count+nr_lf, &num_written, NULL) == 0 ) || (num_written != count+nr_lf))
2310 {
2311 TRACE("WriteFile (fd %d, hand %p) failed-last error (%d), num_written %d\n",
2312 fd, hand, GetLastError(), num_written);
2313 *_errno() = ENOSPC;
2314 if(nr_lf)
2315 free(p);
2316 return s - buf_start;
2317 }
2318 else
2319 {
2320 if(nr_lf)
2321 free(p);
2322 return count;
2323 }
2324 }
2325 return -1;
2326 }
2327
2328 /*********************************************************************
2329 * _putw (MSVCRT.@)
2330 */
2331 int CDECL _putw(int val, FILE* file)
2332 {
2333 int len;
2334
2335 _lock_file(file);
2336 len = _write(file->_file, &val, sizeof(val));
2337 if (len == sizeof(val)) {
2338 _unlock_file(file);
2339 return val;
2340 }
2341
2342 file->_flag |= _IOERR;
2343 _unlock_file(file);
2344 return EOF;
2345 }
2346
2347 /*********************************************************************
2348 * fclose (MSVCRT.@)
2349 */
2350 int CDECL fclose(FILE* file)
2351 {
2352 int r, flag;
2353
2354 _lock_file(file);
2355 flag = file->_flag;
2356 free(file->_tmpfname);
2357 file->_tmpfname = NULL;
2358 /* flush stdio buffers */
2359 if(file->_flag & _IOWRT)
2360 fflush(file);
2361 if(file->_flag & _IOMYBUF)
2362 free(file->_base);
2363
2364 r=_close(file->_file);
2365
2366 file->_flag = 0;
2367 _unlock_file(file);
2368 if(file<_iob || file>=_iob+_IOB_ENTRIES)
2369 DeleteCriticalSection(&((file_crit*)file)->crit);
2370
2371 if(file == get_file(stream_idx-1)) {
2372 while(stream_idx>3 && !file->_flag) {
2373 stream_idx--;
2374 file = get_file(stream_idx-1);
2375 }
2376 }
2377
2378 return ((r == -1) || (flag & _IOERR) ? EOF : 0);
2379 }
2380
2381 /*********************************************************************
2382 * feof (MSVCRT.@)
2383 */
2384 int CDECL feof(FILE* file)
2385 {
2386 int ret;
2387
2388 _lock_file(file);
2389 ret = file->_flag & _IOEOF;
2390 _unlock_file(file);
2391
2392 return ret;
2393 }
2394
2395 /*********************************************************************
2396 * ferror (MSVCRT.@)
2397 */
2398 int CDECL ferror(FILE* file)
2399 {
2400 int ret;
2401
2402 _lock_file(file);
2403 ret = file->_flag & _IOERR;
2404 _unlock_file(file);
2405
2406 return ret;
2407 }
2408
2409 /*********************************************************************
2410 * _filbuf (MSVCRT.@)
2411 */
2412 int CDECL _filbuf(FILE* file)
2413 {
2414 unsigned char c;
2415 _lock_file(file);
2416
2417 /* Allocate buffer if needed */
2418 if(file->_bufsiz == 0 && !(file->_flag & _IONBF))
2419 alloc_buffer(file);
2420
2421 if(!(file->_flag & _IOREAD)) {
2422 if(file->_flag & _IORW)
2423 file->_flag |= _IOREAD;
2424 else {
2425 _unlock_file(file);
2426 return EOF;
2427 }
2428 }
2429
2430 if(file->_flag & _IONBF) {
2431 int r;
2432 if ((r = read_i(file->_file,&c,1)) != 1) {
2433 file->_flag |= (r == 0) ? _IOEOF : _IOERR;
2434 _unlock_file(file);
2435 return EOF;
2436 }
2437
2438 _unlock_file(file);
2439 return c;
2440 } else {
2441 file->_cnt = read_i(file->_file, file->_base, file->_bufsiz);
2442 if(file->_cnt<=0) {
2443 file->_flag |= (file->_cnt == 0) ? _IOEOF : _IOERR;
2444 file->_cnt = 0;
2445 _unlock_file(file);
2446 return EOF;
2447 }
2448
2449 file->_cnt--;
2450 file->_ptr = file->_base+1;
2451 c = *(unsigned char *)file->_base;
2452 _unlock_file(file);
2453 return c;
2454 }
2455 }
2456
2457 /*********************************************************************
2458 * fgetc (MSVCRT.@)
2459 */
2460 int CDECL fgetc(FILE* file)
2461 {
2462 unsigned char *i;
2463 unsigned int j;
2464
2465 _lock_file(file);
2466 if (file->_cnt>0) {
2467 file->_cnt--;
2468 i = (unsigned char *)file->_ptr++;
2469 j = *i;
2470 } else
2471 j = _filbuf(file);
2472
2473 _unlock_file(file);
2474 return j;
2475 }
2476
2477 /*********************************************************************
2478 * _fgetchar (MSVCRT.@)
2479 */
2480 int CDECL _fgetchar(void)
2481 {
2482 return fgetc(stdin);
2483 }
2484
2485 /*********************************************************************
2486 * fgets (MSVCRT.@)
2487 */
2488 char * CDECL fgets(char *s, int size, FILE* file)
2489 {
2490 int cc = EOF;
2491 char * buf_start = s;
2492
2493 TRACE(":file(%p) fd (%d) str (%p) len (%d)\n",
2494 file,file->_file,s,size);
2495
2496 _lock_file(file);
2497
2498 while ((size >1) && (cc = fgetc(file)) != EOF && cc != '\n')
2499 {
2500 *s++ = (char)cc;
2501 size --;
2502 }
2503 if ((cc == EOF) && (s == buf_start)) /* If nothing read, return 0*/
2504 {
2505 TRACE(":nothing read\n");
2506 _unlock_file(file);
2507 return NULL;
2508 }
2509 if ((cc != EOF) && (size > 1))
2510 *s++ = cc;
2511 *s = '\0';
2512 TRACE(":got %s\n", debugstr_a(buf_start));
2513 _unlock_file(file);
2514 return buf_start;
2515 }
2516
2517 /*********************************************************************
2518 * fgetwc (MSVCRT.@)
2519 *
2520 * In _O_TEXT mode, multibyte characters are read from the file, dropping
2521 * the CR from CR/LF combinations
2522 */
2523 wint_t CDECL fgetwc(FILE* file)
2524 {
2525 int c;
2526
2527 _lock_file(file);
2528 if (!(get_ioinfo(file->_file)->wxflag & WX_TEXT))
2529 {
2530 wchar_t wc;
2531 unsigned int i;
2532 int j;
2533 char *chp, *wcp;
2534 wcp = (char *)&wc;
2535 for(i=0; i<sizeof(wc); i++)
2536 {
2537 if (file->_cnt>0)
2538 {
2539 file->_cnt--;
2540 chp = file->_ptr++;
2541 wcp[i] = *chp;
2542 }
2543 else
2544 {
2545 j = _filbuf(file);
2546 if(file->_cnt<=0)
2547 {
2548 file->_flag |= (file->_cnt == 0) ? _IOEOF : _IOERR;
2549 file->_cnt = 0;
2550
2551 _unlock_file(file);
2552 return WEOF;
2553 }
2554 wcp[i] = j;
2555 }
2556 }
2557
2558 _unlock_file(file);
2559 return wc;
2560 }
2561
2562 c = fgetc(file);
2563 if ((__mb_cur_max > 1) && isleadbyte(c))
2564 {
2565 FIXME("Treat Multibyte characters\n");
2566 }
2567
2568 _unlock_file(file);
2569 if (c == EOF)
2570 return WEOF;
2571 else
2572 return (wint_t)c;
2573 }
2574
2575 /*********************************************************************
2576 * _getw (MSVCRT.@)
2577 */
2578 int CDECL _getw(FILE* file)
2579 {
2580 char *ch;
2581 int i, k;
2582 unsigned int j;
2583 ch = (char *)&i;
2584
2585 _lock_file(file);
2586 for (j=0; j<sizeof(int); j++) {
2587 k = fgetc(file);
2588 if (k == EOF) {
2589 file->_flag |= _IOEOF;
2590 _unlock_file(file);
2591 return EOF;
2592 }
2593 ch[j] = k;
2594 }
2595
2596 _unlock_file(file);
2597 return i;
2598 }
2599
2600 /*********************************************************************
2601 * getwc (MSVCRT.@)
2602 */
2603 wint_t CDECL getwc(FILE* file)
2604 {
2605 return fgetwc(file);
2606 }
2607
2608 /*********************************************************************
2609 * _fgetwchar (MSVCRT.@)
2610 */
2611 wint_t CDECL _fgetwchar(void)
2612 {
2613 return fgetwc(stdin);
2614 }
2615
2616 /*********************************************************************
2617 * getwchar (MSVCRT.@)
2618 */
2619 wint_t CDECL getwchar(void)
2620 {
2621 return _fgetwchar();
2622 }
2623
2624 /*********************************************************************
2625 * fgetws (MSVCRT.@)
2626 */
2627 wchar_t * CDECL fgetws(wchar_t *s, int size, FILE* file)
2628 {
2629 int cc = WEOF;
2630 wchar_t * buf_start = s;
2631
2632 TRACE(":file(%p) fd (%d) str (%p) len (%d)\n",
2633 file,file->_file,s,size);
2634
2635 _lock_file(file);
2636
2637 while ((size >1) && (cc = fgetwc(file)) != WEOF && cc != '\n')
2638 {
2639 *s++ = (char)cc;
2640 size --;
2641 }
2642 if ((cc == WEOF) && (s == buf_start)) /* If nothing read, return 0*/
2643 {
2644 TRACE(":nothing read\n");
2645 _unlock_file(file);
2646 return NULL;
2647 }
2648 if ((cc != WEOF) && (size > 1))
2649 *s++ = cc;
2650 *s = 0;
2651 TRACE(":got %s\n", debugstr_w(buf_start));
2652 _unlock_file(file);
2653 return buf_start;
2654 }
2655
2656 /*********************************************************************
2657 * fwrite (MSVCRT.@)
2658 */
2659 size_t CDECL fwrite(const void *ptr, size_t size, size_t nmemb, FILE* file)
2660 {
2661 size_t wrcnt=size * nmemb;
2662 int written = 0;
2663 if (size == 0)
2664 return 0;
2665
2666 _lock_file(file);
2667 if(file->_cnt) {
2668 int pcnt=((unsigned)file->_cnt>wrcnt)? wrcnt: file->_cnt;
2669 memcpy(file->_ptr, ptr, pcnt);
2670 file->_cnt -= pcnt;
2671 file->_ptr += pcnt;
2672 written = pcnt;
2673 wrcnt -= pcnt;
2674 ptr = (const char*)ptr + pcnt;
2675 } else if(!(file->_flag & _IOWRT)) {
2676 if(file->_flag & _IORW) {
2677 file->_flag |= _IOWRT;
2678 } else {
2679 _unlock_file(file);
2680 return 0;
2681 }
2682 }
2683 if(wrcnt) {
2684 /* Flush buffer */
2685 int res=flush_buffer(file);
2686 if(!res) {
2687 int pwritten = _write(file->_file, ptr, wrcnt);
2688 if (pwritten <= 0)
2689 {
2690 file->_flag |= _IOERR;
2691 pwritten=0;
2692 }
2693 written += pwritten;
2694 }
2695 }
2696
2697 _unlock_file(file);
2698 return written / size;
2699 }
2700
2701 /*********************************************************************
2702 * fputwc (MSVCRT.@)
2703 * FORKED for ReactOS, don't sync with Wine!
2704 * References:
2705 * - http://jira.reactos.org/browse/CORE-6495
2706 * - http://bugs.winehq.org/show_bug.cgi?id=8598
2707 */
2708 wint_t CDECL fputwc(wchar_t c, FILE* stream)
2709 {
2710 /* If this is a real file stream (and not some temporary one for
2711 sprintf-like functions), check whether it is opened in text mode.
2712 In this case, we have to perform an implicit conversion to ANSI. */
2713 if (!(stream->_flag & _IOSTRG) && get_ioinfo(stream->_file)->wxflag & WX_TEXT)
2714 {
2715 /* Convert to multibyte in text mode */
2716 char mbc[MB_LEN_MAX];
2717 int mb_return;
2718
2719 mb_return = wctomb(mbc, c);
2720
2721 if(mb_return == -1)
2722 return WEOF;
2723
2724 /* Output all characters */
2725 if (fwrite(mbc, mb_return, 1, stream) != 1)
2726 return WEOF;
2727 }
2728 else
2729 {
2730 if (fwrite(&c, sizeof(c), 1, stream) != 1)
2731 return WEOF;
2732 }
2733
2734 return c;
2735 }
2736
2737 /*********************************************************************
2738 * _fputwchar (MSVCRT.@)
2739 */
2740 wint_t CDECL _fputwchar(wint_t wc)
2741 {
2742 return fputwc(wc, stdout);
2743 }
2744
2745 /*********************************************************************
2746 * _wfsopen (MSVCRT.@)
2747 */
2748 FILE * CDECL _wfsopen(const wchar_t *path, const wchar_t *mode, int share)
2749 {
2750 FILE* file;
2751 int open_flags, stream_flags, fd;
2752
2753 TRACE("(%s,%s)\n", debugstr_w(path), debugstr_w(mode));
2754
2755 /* map mode string to open() flags. "man fopen" for possibilities. */
2756 if (get_flags(mode, &open_flags, &stream_flags) == -1)
2757 return NULL;
2758
2759 LOCK_FILES();
2760 fd = _wsopen(path, open_flags, share, _S_IREAD | _S_IWRITE);
2761 if (fd < 0)
2762 file = NULL;
2763 else if ((file = alloc_fp()) && init_fp(file, fd, stream_flags)
2764 != -1)
2765 TRACE(":fd (%d) mode (%s) FILE* (%p)\n", fd, debugstr_w(mode), file);
2766 else if (file)
2767 {
2768 file->_flag = 0;
2769 file = NULL;
2770 }
2771
2772 TRACE(":got (%p)\n",file);
2773 if (fd >= 0 && !file)
2774 _close(fd);
2775 UNLOCK_FILES();
2776 return file;
2777 }
2778
2779 /*********************************************************************
2780 * _fsopen (MSVCRT.@)
2781 */
2782 FILE * CDECL _fsopen(const char *path, const char *mode, int share)
2783 {
2784 FILE *ret;
2785 wchar_t *pathW = NULL, *modeW = NULL;
2786
2787 if (path && !(pathW = msvcrt_wstrdupa(path))) {
2788 _invalid_parameter(NULL, NULL, NULL, 0, 0);
2789 *_errno() = EINVAL;
2790 return NULL;
2791 }
2792 if (mode && !(modeW = msvcrt_wstrdupa(mode)))
2793 {
2794 free(pathW);
2795 _invalid_parameter(NULL, NULL, NULL, 0, 0);
2796 *_errno() = EINVAL;
2797 return NULL;
2798 }
2799
2800 ret = _wfsopen(pathW, modeW, share);
2801
2802 free(pathW);
2803 free(modeW);
2804 return ret;
2805 }
2806
2807 /*********************************************************************
2808 * fopen (MSVCRT.@)
2809 */
2810 FILE * CDECL fopen(const char *path, const char *mode)
2811 {
2812 return _fsopen( path, mode, _SH_DENYNO );
2813 }
2814
2815 /*********************************************************************
2816 * fopen_s (MSVCRT.@)
2817 */
2818 int CDECL fopen_s(FILE** pFile,
2819 const char *filename, const char *mode)
2820 {
2821 if (!MSVCRT_CHECK_PMT(pFile != NULL) || !MSVCRT_CHECK_PMT(filename != NULL) ||
2822 !MSVCRT_CHECK_PMT(mode != NULL)) {
2823 *_errno() = EINVAL;
2824 return EINVAL;
2825 }
2826
2827 *pFile = fopen(filename, mode);
2828
2829 if(!*pFile)
2830 return *_errno();
2831 return 0;
2832 }
2833
2834 /*********************************************************************
2835 * _wfopen (MSVCRT.@)
2836 */
2837 FILE * CDECL _wfopen(const wchar_t *path, const wchar_t *mode)
2838 {
2839 return _wfsopen( path, mode, _SH_DENYNO );
2840 }
2841
2842 /*********************************************************************
2843 * _wfopen_s (MSVCRT.@)
2844 */
2845 int CDECL _wfopen_s(FILE** pFile, const wchar_t *filename,
2846 const wchar_t *mode)
2847 {
2848 if (!MSVCRT_CHECK_PMT(pFile != NULL) || !MSVCRT_CHECK_PMT(filename != NULL) ||
2849 !MSVCRT_CHECK_PMT(mode != NULL)) {
2850 *_errno() = EINVAL;
2851 return EINVAL;
2852 }
2853
2854 *pFile = _wfopen(filename, mode);
2855
2856 if(!*pFile)
2857 return *_errno();
2858 return 0;
2859 }
2860
2861 /* fputc calls _flsbuf which calls fputc */
2862 int CDECL _flsbuf(int c, FILE* file);
2863
2864 /*********************************************************************
2865 * fputc (MSVCRT.@)
2866 */
2867 int CDECL fputc(int c, FILE* file)
2868 {
2869 int res;
2870
2871 _lock_file(file);
2872 if(file->_cnt>0) {
2873 *file->_ptr++=c;
2874 file->_cnt--;
2875 if (c == '\n')
2876 {
2877 res = flush_buffer(file);
2878 _unlock_file(file);
2879 return res ? res : c;
2880 }
2881 else {
2882 _unlock_file(file);
2883 return c & 0xff;
2884 }
2885 } else {
2886 res = _flsbuf(c, file);
2887 _unlock_file(file);
2888 return res;
2889 }
2890 }
2891
2892 /*********************************************************************
2893 * _fputchar (MSVCRT.@)
2894 */
2895 int CDECL _fputchar(int c)
2896 {
2897 return fputc(c, stdout);
2898 }
2899
2900 /*********************************************************************
2901 * fread (MSVCRT.@)
2902 */
2903 size_t CDECL fread(void *ptr, size_t size, size_t nmemb, FILE* file)
2904 {
2905 size_t rcnt=size * nmemb;
2906 size_t read=0;
2907 int pread=0;
2908
2909 if(!rcnt)
2910 return 0;
2911
2912 _lock_file(file);
2913
2914 /* first buffered data */
2915 if(file->_cnt>0) {
2916 int pcnt= (rcnt>(unsigned int)file->_cnt)? file->_cnt:rcnt;
2917 memcpy(ptr, file->_ptr, pcnt);
2918 file->_cnt -= pcnt;
2919 file->_ptr += pcnt;
2920 read += pcnt ;
2921 rcnt -= pcnt ;
2922 ptr = (char*)ptr + pcnt;
2923 } else if(!(file->_flag & _IOREAD )) {
2924 if(file->_flag & _IORW) {
2925 file->_flag |= _IOREAD;
2926 } else {
2927 _unlock_file(file);
2928 return 0;
2929 }
2930 }
2931 while(rcnt>0)
2932 {
2933 int i;
2934 /* Fill the buffer on small reads.
2935 * TODO: Use a better buffering strategy.
2936 */
2937 if (!file->_cnt && size*nmemb <= BUFSIZ/2 && !(file->_flag & _IONBF)) {
2938 if (file->_bufsiz == 0) {
2939 alloc_buffer(file);
2940 }
2941 file->_cnt = _read(file->_file, file->_base, file->_bufsiz);
2942 file->_ptr = file->_base;
2943 i = ((unsigned int)file->_cnt<rcnt) ? file->_cnt : rcnt;
2944 /* If the buffer fill reaches eof but fread wouldn't, clear eof. */
2945 if (i > 0 && i < file->_cnt) {
2946 get_ioinfo(file->_file)->wxflag &= ~WX_ATEOF;
2947 file->_flag &= ~_IOEOF;
2948 }
2949 if (i > 0) {
2950 memcpy(ptr, file->_ptr, i);
2951 file->_cnt -= i;
2952 file->_ptr += i;
2953 }
2954 } else {
2955 i = _read(file->_file,ptr, rcnt);
2956 }
2957 pread += i;
2958 rcnt -= i;
2959 ptr = (char *)ptr+i;
2960 /* expose feof condition in the flags
2961 * MFC tests file->_flag for feof, and doesn't call feof())
2962 */
2963 if (get_ioinfo(file->_file)->wxflag & WX_ATEOF)
2964 file->_flag |= _IOEOF;
2965 else if (i == -1)
2966 {
2967 file->_flag |= _IOERR;
2968 pread = 0;
2969 rcnt = 0;
2970 }
2971 if (i < 1) break;
2972 }
2973 read+=pread;
2974 _unlock_file(file);
2975 return read / size;
2976 }
2977
2978 /*********************************************************************
2979 * _wfreopen (MSVCRT.@)
2980 *
2981 */
2982 FILE* CDECL _wfreopen(const wchar_t *path, const wchar_t *mode, FILE* file)
2983 {
2984 int open_flags, stream_flags, fd;
2985
2986 TRACE(":path (%p) mode (%s) file (%p) fd (%d)\n", debugstr_w(path), debugstr_w(mode), file, file->_file);
2987
2988 LOCK_FILES();
2989 if (!file || ((fd = file->_file) < 0) || fd > fdend)
2990 file = NULL;
2991 else
2992 {
2993 fclose(file);
2994 /* map mode string to open() flags. "man fopen" for possibilities. */
2995 if (get_flags(mode, &open_flags, &stream_flags) == -1)
2996 file = NULL;
2997 else
2998 {
2999 fd = _wopen(path, open_flags, _S_IREAD | _S_IWRITE);
3000 if (fd < 0)
3001 file = NULL;
3002 else if (init_fp(file, fd, stream_flags) == -1)
3003 {
3004 file->_flag = 0;
3005 WARN(":failed-last error (%d)\n",GetLastError());
3006 _dosmaperr(GetLastError());
3007 file = NULL;
3008 }
3009 }
3010 }
3011 UNLOCK_FILES();
3012 return file;
3013 }
3014
3015 /*********************************************************************
3016 * freopen (MSVCRT.@)
3017 *
3018 */
3019 FILE* CDECL freopen(const char *path, const char *mode, FILE* file)
3020 {
3021 FILE *ret;
3022 wchar_t *pathW = NULL, *modeW = NULL;
3023
3024 if (path && !(pathW = msvcrt_wstrdupa(path))) return NULL;
3025 if (mode && !(modeW = msvcrt_wstrdupa(mode)))
3026 {
3027 free(pathW);
3028 return NULL;
3029 }
3030
3031 ret = _wfreopen(pathW, modeW, file);
3032
3033 free(pathW);
3034 free(modeW);
3035 return ret;
3036 }
3037
3038 /*********************************************************************
3039 * fsetpos (MSVCRT.@)
3040 */
3041 int CDECL fsetpos(FILE* file, const fpos_t *pos)
3042 {
3043 int ret;
3044
3045 _lock_file(file);
3046 /* Note that all this has been lifted 'as is' from fseek */
3047 if(file->_flag & _IOWRT)
3048 flush_buffer(file);
3049
3050 /* Discard buffered input */
3051 file->_cnt = 0;
3052 file->_ptr = file->_base;
3053
3054 /* Reset direction of i/o */
3055 if(file->_flag & _IORW) {
3056 file->_flag &= ~(_IOREAD|_IOWRT);
3057 }
3058
3059 ret = (_lseeki64(file->_file,*pos,SEEK_SET) == -1) ? -1 : 0;
3060 _unlock_file(file);
3061 return ret;
3062 }
3063
3064 /*********************************************************************
3065 * _ftelli64 (MSVCRT.@)
3066 */
3067 __int64 CDECL _ftelli64(FILE* file)
3068 {
3069 /* TODO: just call fgetpos and return lower half of result */
3070 int off=0;
3071 __int64 pos;
3072
3073 _lock_file(file);
3074 pos = _telli64(file->_file);
3075 if(pos == -1) {
3076 _unlock_file(file);
3077 return -1;
3078 }
3079 if(file->_bufsiz) {
3080 if( file->_flag & _IOWRT ) {
3081 off = file->_ptr - file->_base;
3082 } else {
3083 off = -file->_cnt;
3084 if (get_ioinfo(file->_file)->wxflag & WX_TEXT) {
3085 /* Black magic correction for CR removal */
3086 int i;
3087 for (i=0; i<file->_cnt; i++) {
3088 if (file->_ptr[i] == '\n')
3089 off--;
3090 }
3091 /* Black magic when reading CR at buffer boundary*/
3092 if(get_ioinfo(file->_file)->wxflag & WX_READCR)
3093 off--;
3094 }
3095 }
3096 }
3097
3098 _unlock_file(file);
3099 return off + pos;
3100 }
3101
3102 /*********************************************************************
3103 * ftell (MSVCRT.@)
3104 */
3105 LONG CDECL ftell(FILE* file)
3106 {
3107 return (LONG)_ftelli64(file);
3108 }
3109
3110 /*********************************************************************
3111 * fgetpos (MSVCRT.@)
3112 */
3113 int CDECL fgetpos(FILE* file, fpos_t *pos)
3114 {
3115 int off=0;
3116
3117 _lock_file(file);
3118 *pos = _lseeki64(file->_file,0,SEEK_CUR);
3119 if(*pos == -1) {
3120 _unlock_file(file);
3121 return -1;
3122 }
3123 if(file->_bufsiz) {
3124 if( file->_flag & _IOWRT ) {
3125 off = file->_ptr - file->_base;
3126 } else {
3127 off = -file->_cnt;
3128 if (get_ioinfo(file->_file)->wxflag & WX_TEXT) {
3129 /* Black magic correction for CR removal */
3130 int i;
3131 for (i=0; i<file->_cnt; i++) {
3132 if (file->_ptr[i] == '\n')
3133 off--;
3134 }
3135 /* Black magic when reading CR at buffer boundary*/
3136 if(get_ioinfo(file->_file)->wxflag & WX_READCR)
3137 off--;
3138 }
3139 }
3140 }
3141 *pos += off;
3142 _unlock_file(file);
3143 return 0;
3144 }
3145
3146 /*********************************************************************
3147 * fputs (MSVCRT.@)
3148 */
3149 int CDECL fputs(const char *s, FILE* file)
3150 {
3151 size_t i, len = strlen(s);
3152 int ret;
3153
3154 _lock_file(file);
3155 if (!(get_ioinfo(file->_file)->wxflag & WX_TEXT)) {
3156 ret = fwrite(s,sizeof(*s),len,file) == len ? 0 : EOF;
3157 _unlock_file(file);
3158 return ret;
3159 }
3160 for (i=0; i<len; i++)
3161 if (fputc(s[i], file) == EOF) {
3162 _unlock_file(file);
3163 return EOF;
3164 }
3165
3166 _unlock_file(file);
3167 return 0;
3168 }
3169
3170 /*********************************************************************
3171 * fputws (MSVCRT.@)
3172 */
3173 int CDECL fputws(const wchar_t *s, FILE* file)
3174 {
3175 size_t i, len = strlenW(s);
3176 int ret;
3177
3178 _lock_file(file);
3179 if (!(get_ioinfo(file->_file)->wxflag & WX_TEXT)) {
3180 ret = fwrite(s,sizeof(*s),len,file) == len ? 0 : EOF;
3181 _unlock_file(file);
3182 return ret;
3183 }
3184 for (i=0; i<len; i++) {
3185 if (((s[i] == '\n') && (fputc('\r', file) == EOF))
3186 || fputwc(s[i], file) == WEOF) {
3187 _unlock_file(file);
3188 return WEOF;
3189 }
3190 }
3191
3192 _unlock_file(file);
3193 return 0;
3194 }
3195
3196 /*********************************************************************
3197 * getchar (MSVCRT.@)
3198 */
3199 int CDECL getchar(void)
3200 {
3201 return fgetc(stdin);
3202 }
3203
3204 /*********************************************************************
3205 * getc (MSVCRT.@)
3206 */
3207 int CDECL getc(FILE* file)
3208 {
3209 return fgetc(file);
3210 }
3211
3212 /*********************************************************************
3213 * gets (MSVCRT.@)
3214 */
3215 char * CDECL gets(char *buf)
3216 {
3217 int cc;
3218 char * buf_start = buf;
3219
3220 _lock_file(stdin);
3221 for(cc = fgetc(stdin); cc != EOF && cc != '\n';
3222 cc = fgetc(stdin))
3223 if(cc != '\r') *buf++ = (char)cc;
3224
3225 *buf = '\0';
3226
3227 TRACE("got '%s'\n", buf_start);
3228 _unlock_file(stdin);
3229 return buf_start;
3230 }
3231
3232 /*********************************************************************
3233 * _getws (MSVCRT.@)
3234 */
3235 wchar_t* CDECL _getws(wchar_t* buf)
3236 {
3237 wint_t cc;
3238 wchar_t* ws = buf;
3239
3240 _lock_file(stdin);
3241 for (cc = fgetwc(stdin); cc != WEOF && cc != '\n';
3242 cc = fgetwc(stdin))
3243 {
3244 if (cc != '\r')
3245 *buf++ = (wchar_t)cc;
3246 }
3247 *buf = '\0';
3248
3249 TRACE("got %s\n", debugstr_w(ws));
3250 _unlock_file(stdin);
3251 return ws;
3252 }
3253
3254 /*********************************************************************
3255 * putc (MSVCRT.@)
3256 */
3257 int CDECL putc(int c, FILE* file)
3258 {
3259 return fputc(c, file);
3260 }
3261
3262 /*********************************************************************
3263 * putchar (MSVCRT.@)
3264 */
3265 int CDECL putchar(int c)
3266 {
3267 return fputc(c, stdout);
3268 }
3269
3270 /*********************************************************************
3271 * _putwch (MSVCRT.@)
3272 */
3273 wint_t CDECL _putwch(wchar_t c)
3274 {
3275 return fputwc(c, stdout);
3276 }
3277
3278 /*********************************************************************
3279 * puts (MSVCRT.@)
3280 */
3281 int CDECL puts(const char *s)
3282 {
3283 size_t len = strlen(s);
3284 int ret;
3285
3286 _lock_file(stdout);
3287 if(fwrite(s, sizeof(*s), len, stdout) != len) {
3288 _unlock_file(stdout);
3289 return EOF;
3290 }
3291
3292 ret = fwrite("\n",1,1,stdout) == 1 ? 0 : EOF;
3293 _unlock_file(stdout);
3294 return ret;
3295 }
3296
3297 /*********************************************************************
3298 * _putws (MSVCRT.@)
3299 */
3300 int CDECL _putws(const wchar_t *s)
3301 {
3302 static const wchar_t nl = '\n';
3303 size_t len = strlenW(s);
3304 int ret;
3305
3306 _lock_file(stdout);
3307 if(fwrite(s, sizeof(*s), len, stdout) != len) {
3308 _unlock_file(stdout);
3309 return EOF;
3310 }
3311
3312 ret = fwrite(&nl,sizeof(nl),1,stdout) == 1 ? 0 : EOF;
3313 _unlock_file(stdout);
3314 return ret;
3315 }
3316
3317 /*********************************************************************
3318 * remove (MSVCRT.@)
3319 */
3320 int CDECL remove(const char *path)
3321 {
3322 TRACE("(%s)\n",path);
3323 if (DeleteFileA(path))
3324 return 0;
3325 TRACE(":failed (%d)\n",GetLastError());
3326 _dosmaperr(GetLastError());
3327 return -1;
3328 }
3329
3330 /*********************************************************************
3331 * _wremove (MSVCRT.@)
3332 */
3333 int CDECL _wremove(const wchar_t *path)
3334 {
3335 TRACE("(%s)\n",debugstr_w(path));
3336 if (DeleteFileW(path))
3337 return 0;
3338 TRACE(":failed (%d)\n",GetLastError());
3339 _dosmaperr(GetLastError());
3340 return -1;
3341 }
3342
3343 /*********************************************************************
3344 * rename (MSVCRT.@)
3345 */
3346 int CDECL rename(const char *oldpath,const char *newpath)
3347 {
3348 TRACE(":from %s to %s\n",oldpath,newpath);
3349 if (MoveFileExA(oldpath, newpath, MOVEFILE_COPY_ALLOWED))
3350 return 0;
3351 TRACE(":failed (%d)\n",GetLastError());
3352 _dosmaperr(GetLastError());
3353 return -1;
3354 }
3355
3356 /*********************************************************************
3357 * _wrename (MSVCRT.@)
3358 */
3359 int CDECL _wrename(const wchar_t *oldpath,const wchar_t *newpath)
3360 {
3361 TRACE(":from %s to %s\n",debugstr_w(oldpath),debugstr_w(newpath));
3362 if (MoveFileExW(oldpath, newpath, MOVEFILE_COPY_ALLOWED))
3363 return 0;
3364 TRACE(":failed (%d)\n",GetLastError());
3365 _dosmaperr(GetLastError());
3366 return -1;
3367 }
3368
3369 /*********************************************************************
3370 * setvbuf (MSVCRT.@)
3371 */
3372 int CDECL setvbuf(FILE* file, char *buf, int mode, size_t size)
3373 {
3374 _lock_file(file);
3375 if(file->_bufsiz) {
3376 free(file->_base);
3377 file->_bufsiz = 0;
3378 file->_cnt = 0;
3379 }
3380 if(mode == _IOFBF) {
3381 file->_flag &= ~_IONBF;
3382 file->_base = file->_ptr = buf;
3383 if(buf) {
3384 file->_bufsiz = size;
3385 }
3386 } else {
3387 file->_flag |= _IONBF;
3388 }
3389 _unlock_file(file);
3390 return 0;
3391 }
3392
3393 /*********************************************************************
3394 * setbuf (MSVCRT.@)
3395 */
3396 void CDECL setbuf(FILE* file, char *buf)
3397 {
3398 setvbuf(file, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
3399 }
3400
3401 /*********************************************************************
3402 * tmpnam (MSVCRT.@)
3403 */
3404 char * CDECL tmpnam(char *s)
3405 {
3406 char tmpstr[16];
3407 char *p;
3408 int count, size;
3409
3410 if (!s) {
3411 thread_data_t *data = msvcrt_get_thread_data();
3412
3413 if(!data->tmpnam_buffer)
3414 data->tmpnam_buffer = malloc(MAX_PATH);
3415
3416 s = data->tmpnam_buffer;
3417 }
3418
3419 int_to_base32(GetCurrentProcessId(), tmpstr);
3420 p = s + sprintf(s, "\\s%s.", tmpstr);
3421 for (count = 0; count < TMP_MAX; count++)
3422 {
3423 size = int_to_base32(tmpnam_unique++, tmpstr);
3424 memcpy(p, tmpstr, size);
3425 if (GetFileAttributesA(s) == INVALID_FILE_ATTRIBUTES &&
3426 GetLastError() == ERROR_FILE_NOT_FOUND)
3427 break;
3428 }
3429 return s;
3430 }
3431
3432 /*********************************************************************
3433 * _wtmpnam (MSVCRT.@)
3434 */
3435 wchar_t * CDECL _wtmpnam(wchar_t *s)
3436 {
3437 static const wchar_t format[] = {'\\','s','%','s','.',0};
3438 wchar_t tmpstr[16];
3439 wchar_t *p;
3440 int count, size;
3441 if (!s) {
3442 thread_data_t *data = msvcrt_get_thread_data();
3443
3444 if(!data->wtmpnam_buffer)
3445 data->wtmpnam_buffer = malloc(sizeof(wchar_t[MAX_PATH]));
3446
3447 s = data->wtmpnam_buffer;
3448 }
3449
3450 int_to_base32_w(GetCurrentProcessId(), tmpstr);
3451 p = s + _snwprintf(s, MAX_PATH, format, tmpstr);
3452 for (count = 0; count < TMP_MAX; count++)
3453 {
3454 size = int_to_base32_w(tmpnam_unique++, tmpstr);
3455 memcpy(p, tmpstr, size*sizeof(wchar_t));
3456 if (GetFileAttributesW(s) == INVALID_FILE_ATTRIBUTES &&
3457 GetLastError() == ERROR_FILE_NOT_FOUND)
3458 break;
3459 }
3460 return s;
3461 }
3462
3463 /*********************************************************************
3464 * tmpfile (MSVCRT.@)
3465 */
3466 FILE* CDECL tmpfile(void)
3467 {
3468 char *filename = tmpnam(NULL);
3469 int fd;
3470 FILE* file = NULL;
3471
3472 LOCK_FILES();
3473 fd = _open(filename, _O_CREAT | _O_BINARY | _O_RDWR | _O_TEMPORARY);
3474 if (fd != -1 && (file = alloc_fp()))
3475 {
3476 if (init_fp(file, fd, _O_RDWR) == -1)
3477 {
3478 file->_flag = 0;
3479 file = NULL;
3480 }
3481 else file->_tmpfname = _strdup(filename);
3482 }
3483 UNLOCK_FILES();
3484 return file;
3485 }
3486
3487 /*********************************************************************
3488 * ungetc (MSVCRT.@)
3489 */
3490 int CDECL ungetc(int c, FILE * file)
3491 {
3492 if (c == EOF)
3493 return EOF;
3494
3495 _lock_file(file);
3496 if(file->_bufsiz == 0) {
3497 alloc_buffer(file);
3498 file->_ptr++;
3499 }
3500 if(file->_ptr>file->_base) {
3501 file->_ptr--;
3502 *file->_ptr=c;
3503 file->_cnt++;
3504 clearerr(file);
3505 _unlock_file(file);
3506 return c;
3507 }
3508
3509 _unlock_file(file);
3510 return EOF;
3511 }
3512
3513 /*********************************************************************
3514 * ungetwc (MSVCRT.@)
3515 */
3516 wint_t CDECL ungetwc(wint_t wc, FILE * file)
3517 {
3518 wchar_t mwc = wc;
3519 char * pp = (char *)&mwc;
3520 int i;
3521
3522 _lock_file(file);
3523 for(i=sizeof(wchar_t)-1;i>=0;i--) {
3524 if(pp[i] != ungetc(pp[i],file)) {
3525 _unlock_file(file);
3526 return WEOF;
3527 }
3528 }
3529
3530 _unlock_file(file);
3531 return mwc;
3532 }
3533
3534
3535
3536 /*********************************************************************
3537 * _getmaxstdio (MSVCRT.@)
3538 */
3539 int CDECL _getmaxstdio(void)
3540 {
3541 return max_streams;
3542 }
3543
3544 /*********************************************************************
3545 * _setmaxstdio (MSVCRT.@)
3546 */
3547 int CDECL _setmaxstdio(int newmax)
3548 {
3549 TRACE("%d\n", newmax);
3550
3551 if(newmax<_IOB_ENTRIES || newmax>MAX_FILES || newmax<stream_idx)
3552 return -1;
3553
3554 max_streams = newmax;
3555 return max_streams;
3556 }