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