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