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