Release 1.5.29.
[wine] / dlls / msvcrt / file.c
1 /*
2  * msvcrt.dll file functions
3  *
4  * Copyright 1996,1998 Marcus Meissner
5  * Copyright 1996 Jukka Iivonen
6  * Copyright 1997,2000 Uwe Bonnes
7  * Copyright 2000 Jon Griffiths
8  * Copyright 2004 Eric Pouech
9  * Copyright 2004 Juan Lang
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24  *
25  * TODO
26  * Use the file flag hints O_SEQUENTIAL, O_RANDOM, O_SHORT_LIVED
27  */
28
29 #include "config.h"
30 #include "wine/port.h"
31
32 #include <stdarg.h>
33 #include <stdio.h>
34 #ifdef HAVE_UNISTD_H
35 # include <unistd.h>
36 #endif
37 #include <sys/types.h>
38 #include <limits.h>
39
40 #include "windef.h"
41 #include "winbase.h"
42 #include "winternl.h"
43 #include "msvcrt.h"
44 #include "mtdll.h"
45
46 #include "wine/unicode.h"
47
48 #include "wine/debug.h"
49
50 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
51
52 /* for stat mode, permissions apply to all,owner and group */
53 #define ALL_S_IREAD  (MSVCRT__S_IREAD  | (MSVCRT__S_IREAD  >> 3) | (MSVCRT__S_IREAD  >> 6))
54 #define ALL_S_IWRITE (MSVCRT__S_IWRITE | (MSVCRT__S_IWRITE >> 3) | (MSVCRT__S_IWRITE >> 6))
55 #define ALL_S_IEXEC  (MSVCRT__S_IEXEC  | (MSVCRT__S_IEXEC  >> 3) | (MSVCRT__S_IEXEC  >> 6))
56
57 /* _access() bit flags FIXME: incomplete */
58 #define MSVCRT_W_OK      0x02
59 #define MSVCRT_R_OK      0x04
60
61 /* values for wxflag in file descriptor */
62 #define WX_OPEN           0x01
63 #define WX_ATEOF          0x02
64 #define WX_READNL         0x04  /* read started with \n */
65 #define WX_PIPE           0x08
66 #define WX_DONTINHERIT    0x10
67 #define WX_APPEND         0x20
68 #define WX_TEXT           0x80
69
70 /* values for exflag - it's used differently in msvcr90.dll*/
71 #define EF_UTF8           0x01
72 #define EF_UTF16          0x02
73 #define EF_CRIT_INIT      0x04
74 #define EF_UNK_UNICODE    0x08
75
76 static char utf8_bom[3] = { 0xef, 0xbb, 0xbf };
77 static char utf16_bom[2] = { 0xff, 0xfe };
78
79 /* FIXME: this should be allocated dynamically */
80 #define MSVCRT_MAX_FILES 2048
81 #define MSVCRT_FD_BLOCK_SIZE 32
82
83 /* ioinfo structure size is different in msvcrXX.dll's */
84 typedef struct {
85     HANDLE              handle;
86     unsigned char       wxflag;
87     char                lookahead[3];
88     int                 exflag;
89     CRITICAL_SECTION    crit;
90 } ioinfo;
91
92 /*********************************************************************
93  *              __pioinfo (MSVCRT.@)
94  * array of pointers to ioinfo arrays [32]
95  */
96 ioinfo * MSVCRT___pioinfo[MSVCRT_MAX_FILES/MSVCRT_FD_BLOCK_SIZE] = { 0 };
97
98 /*********************************************************************
99  *              __badioinfo (MSVCRT.@)
100  */
101 ioinfo MSVCRT___badioinfo = { INVALID_HANDLE_VALUE, WX_TEXT };
102
103 static int MSVCRT_fdstart = 3; /* first unallocated fd */
104 static int MSVCRT_fdend = 3; /* highest allocated fd */
105
106 typedef struct {
107     MSVCRT_FILE file;
108     CRITICAL_SECTION crit;
109 } file_crit;
110
111 MSVCRT_FILE MSVCRT__iob[_IOB_ENTRIES] = { { 0 } };
112 static file_crit* MSVCRT_fstream[MSVCRT_MAX_FILES/MSVCRT_FD_BLOCK_SIZE];
113 static int MSVCRT_max_streams = 512, MSVCRT_stream_idx;
114
115 /* INTERNAL: process umask */
116 static int MSVCRT_umask = 0;
117
118 /* INTERNAL: static data for tmpnam and _wtmpname functions */
119 static int tmpnam_unique;
120
121 static const unsigned int EXE = 'e' << 16 | 'x' << 8 | 'e';
122 static const unsigned int BAT = 'b' << 16 | 'a' << 8 | 't';
123 static const unsigned int CMD = 'c' << 16 | 'm' << 8 | 'd';
124 static const unsigned int COM = 'c' << 16 | 'o' << 8 | 'm';
125
126 #define TOUL(x) (ULONGLONG)(x)
127 static const ULONGLONG WCEXE = TOUL('e') << 32 | TOUL('x') << 16 | TOUL('e');
128 static const ULONGLONG WCBAT = TOUL('b') << 32 | TOUL('a') << 16 | TOUL('t');
129 static const ULONGLONG WCCMD = TOUL('c') << 32 | TOUL('m') << 16 | TOUL('d');
130 static const ULONGLONG WCCOM = TOUL('c') << 32 | TOUL('o') << 16 | TOUL('m');
131
132 /* This critical section protects the tables MSVCRT___pioinfo and MSVCRT_fstreams,
133  * and their related indexes, MSVCRT_fdstart, MSVCRT_fdend,
134  * and MSVCRT_stream_idx, from race conditions.
135  * It doesn't protect against race conditions manipulating the underlying files
136  * or flags; doing so would probably be better accomplished with per-file
137  * protection, rather than locking the whole table for every change.
138  */
139 static CRITICAL_SECTION MSVCRT_file_cs;
140 static CRITICAL_SECTION_DEBUG MSVCRT_file_cs_debug =
141 {
142     0, 0, &MSVCRT_file_cs,
143     { &MSVCRT_file_cs_debug.ProcessLocksList, &MSVCRT_file_cs_debug.ProcessLocksList },
144       0, 0, { (DWORD_PTR)(__FILE__ ": MSVCRT_file_cs") }
145 };
146 static CRITICAL_SECTION MSVCRT_file_cs = { &MSVCRT_file_cs_debug, -1, 0, 0, 0, 0 };
147 #define LOCK_FILES()    do { EnterCriticalSection(&MSVCRT_file_cs); } while (0)
148 #define UNLOCK_FILES()  do { LeaveCriticalSection(&MSVCRT_file_cs); } while (0)
149
150 static void msvcrt_stat64_to_stat(const struct MSVCRT__stat64 *buf64, struct MSVCRT__stat *buf)
151 {
152     buf->st_dev   = buf64->st_dev;
153     buf->st_ino   = buf64->st_ino;
154     buf->st_mode  = buf64->st_mode;
155     buf->st_nlink = buf64->st_nlink;
156     buf->st_uid   = buf64->st_uid;
157     buf->st_gid   = buf64->st_gid;
158     buf->st_rdev  = buf64->st_rdev;
159     buf->st_size  = buf64->st_size;
160     buf->st_atime = buf64->st_atime;
161     buf->st_mtime = buf64->st_mtime;
162     buf->st_ctime = buf64->st_ctime;
163 }
164
165 static void msvcrt_stat64_to_stati64(const struct MSVCRT__stat64 *buf64, struct MSVCRT__stati64 *buf)
166 {
167     buf->st_dev   = buf64->st_dev;
168     buf->st_ino   = buf64->st_ino;
169     buf->st_mode  = buf64->st_mode;
170     buf->st_nlink = buf64->st_nlink;
171     buf->st_uid   = buf64->st_uid;
172     buf->st_gid   = buf64->st_gid;
173     buf->st_rdev  = buf64->st_rdev;
174     buf->st_size  = buf64->st_size;
175     buf->st_atime = buf64->st_atime;
176     buf->st_mtime = buf64->st_mtime;
177     buf->st_ctime = buf64->st_ctime;
178 }
179
180 static void time_to_filetime( MSVCRT___time64_t time, FILETIME *ft )
181 {
182     /* 1601 to 1970 is 369 years plus 89 leap days */
183     static const __int64 secs_1601_to_1970 = ((369 * 365 + 89) * (__int64)86400);
184
185     __int64 ticks = (time + secs_1601_to_1970) * 10000000;
186     ft->dwHighDateTime = ticks >> 32;
187     ft->dwLowDateTime = ticks;
188 }
189
190 static inline ioinfo* msvcrt_get_ioinfo(int fd)
191 {
192     ioinfo *ret = NULL;
193     if(fd < MSVCRT_MAX_FILES)
194         ret = MSVCRT___pioinfo[fd/MSVCRT_FD_BLOCK_SIZE];
195     if(!ret)
196         return &MSVCRT___badioinfo;
197
198     return ret + (fd%MSVCRT_FD_BLOCK_SIZE);
199 }
200
201 static inline MSVCRT_FILE* msvcrt_get_file(int i)
202 {
203     file_crit *ret;
204
205     if(i >= MSVCRT_max_streams)
206         return NULL;
207
208     if(i < _IOB_ENTRIES)
209         return &MSVCRT__iob[i];
210
211     ret = MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE];
212     if(!ret) {
213         MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE] = MSVCRT_calloc(MSVCRT_FD_BLOCK_SIZE, sizeof(file_crit));
214         if(!MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE]) {
215             ERR("out of memory\n");
216             *MSVCRT__errno() = MSVCRT_ENOMEM;
217             return NULL;
218         }
219
220         ret = MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE] + (i%MSVCRT_FD_BLOCK_SIZE);
221     } else
222         ret += i%MSVCRT_FD_BLOCK_SIZE;
223
224     return &ret->file;
225 }
226
227 static inline BOOL msvcrt_is_valid_fd(int fd)
228 {
229     return fd >= 0 && fd < MSVCRT_fdend && (msvcrt_get_ioinfo(fd)->wxflag & WX_OPEN);
230 }
231
232 /* INTERNAL: Get the HANDLE for a fd
233  * This doesn't lock the table, because a failure will result in
234  * INVALID_HANDLE_VALUE being returned, which should be handled correctly.  If
235  * it returns a valid handle which is about to be closed, a subsequent call
236  * will fail, most likely in a sane way.
237  */
238 static HANDLE msvcrt_fdtoh(int fd)
239 {
240   if (!msvcrt_is_valid_fd(fd))
241   {
242     WARN(":fd (%d) - no handle!\n",fd);
243     *MSVCRT___doserrno() = 0;
244     *MSVCRT__errno() = MSVCRT_EBADF;
245     return INVALID_HANDLE_VALUE;
246   }
247   if (msvcrt_get_ioinfo(fd)->handle == INVALID_HANDLE_VALUE)
248       WARN("returning INVALID_HANDLE_VALUE for %d\n", fd);
249   return msvcrt_get_ioinfo(fd)->handle;
250 }
251
252 /* INTERNAL: free a file entry fd */
253 static void msvcrt_free_fd(int fd)
254 {
255   ioinfo *fdinfo;
256
257   LOCK_FILES();
258   fdinfo = msvcrt_get_ioinfo(fd);
259   if(fdinfo != &MSVCRT___badioinfo)
260   {
261     fdinfo->handle = INVALID_HANDLE_VALUE;
262     fdinfo->wxflag = 0;
263   }
264   TRACE(":fd (%d) freed\n",fd);
265
266   if (fd < 3)
267   {
268     switch (fd)
269     {
270     case 0:
271         SetStdHandle(STD_INPUT_HANDLE, 0);
272         break;
273     case 1:
274         SetStdHandle(STD_OUTPUT_HANDLE, 0);
275         break;
276     case 2:
277         SetStdHandle(STD_ERROR_HANDLE, 0);
278         break;
279     }
280   }
281
282   if (fd == MSVCRT_fdend - 1)
283     MSVCRT_fdend--;
284   if (fd < MSVCRT_fdstart)
285     MSVCRT_fdstart = fd;
286   UNLOCK_FILES();
287 }
288
289 /* INTERNAL: Allocate an fd slot from a Win32 HANDLE, starting from fd */
290 /* caller must hold the files lock */
291 static int msvcrt_set_fd(HANDLE hand, int flag, int fd)
292 {
293   ioinfo *fdinfo;
294
295   if (fd >= MSVCRT_MAX_FILES)
296   {
297     WARN(":files exhausted!\n");
298     *MSVCRT__errno() = MSVCRT_ENFILE;
299     return -1;
300   }
301
302   fdinfo = msvcrt_get_ioinfo(fd);
303   if(fdinfo == &MSVCRT___badioinfo) {
304     int i;
305
306     MSVCRT___pioinfo[fd/MSVCRT_FD_BLOCK_SIZE] = MSVCRT_calloc(MSVCRT_FD_BLOCK_SIZE, sizeof(ioinfo));
307     if(!MSVCRT___pioinfo[fd/MSVCRT_FD_BLOCK_SIZE]) {
308       WARN(":out of memory!\n");
309       *MSVCRT__errno() = MSVCRT_ENOMEM;
310       return -1;
311     }
312
313     for(i=0; i<MSVCRT_FD_BLOCK_SIZE; i++)
314       MSVCRT___pioinfo[fd/MSVCRT_FD_BLOCK_SIZE][i].handle = INVALID_HANDLE_VALUE;
315
316     fdinfo = msvcrt_get_ioinfo(fd);
317   }
318
319   fdinfo->handle = hand;
320   fdinfo->wxflag = WX_OPEN | (flag & (WX_DONTINHERIT | WX_APPEND | WX_TEXT | WX_PIPE));
321   fdinfo->lookahead[0] = '\n';
322   fdinfo->lookahead[1] = '\n';
323   fdinfo->lookahead[2] = '\n';
324   fdinfo->exflag = 0;
325
326   /* locate next free slot */
327   if (fd == MSVCRT_fdstart && fd == MSVCRT_fdend)
328     MSVCRT_fdstart = MSVCRT_fdend + 1;
329   else
330     while (MSVCRT_fdstart < MSVCRT_fdend &&
331       msvcrt_get_ioinfo(MSVCRT_fdstart)->handle != INVALID_HANDLE_VALUE)
332       MSVCRT_fdstart++;
333   /* update last fd in use */
334   if (fd >= MSVCRT_fdend)
335     MSVCRT_fdend = fd + 1;
336   TRACE("fdstart is %d, fdend is %d\n", MSVCRT_fdstart, MSVCRT_fdend);
337
338   switch (fd)
339   {
340   case 0: SetStdHandle(STD_INPUT_HANDLE,  hand); break;
341   case 1: SetStdHandle(STD_OUTPUT_HANDLE, hand); break;
342   case 2: SetStdHandle(STD_ERROR_HANDLE,  hand); break;
343   }
344
345   return fd;
346 }
347
348 /* INTERNAL: Allocate an fd slot from a Win32 HANDLE */
349 static int msvcrt_alloc_fd(HANDLE hand, int flag)
350 {
351   int ret;
352
353   LOCK_FILES();
354   TRACE(":handle (%p) allocating fd (%d)\n",hand,MSVCRT_fdstart);
355   ret = msvcrt_set_fd(hand, flag, MSVCRT_fdstart);
356   UNLOCK_FILES();
357   return ret;
358 }
359
360 /* INTERNAL: Allocate a FILE* for an fd slot */
361 /* caller must hold the files lock */
362 static MSVCRT_FILE* msvcrt_alloc_fp(void)
363 {
364   int i;
365   MSVCRT_FILE *file;
366
367   for (i = 3; i < MSVCRT_max_streams; i++)
368   {
369     file = msvcrt_get_file(i);
370     if (!file)
371       return NULL;
372
373     if (file->_flag == 0)
374     {
375       if (i == MSVCRT_stream_idx)
376       {
377           if (file<MSVCRT__iob || file>=MSVCRT__iob+_IOB_ENTRIES)
378           {
379               InitializeCriticalSection(&((file_crit*)file)->crit);
380               ((file_crit*)file)->crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": file_crit.crit");
381           }
382           MSVCRT_stream_idx++;
383       }
384       return file;
385     }
386   }
387
388   return NULL;
389 }
390
391 /* INTERNAL: initialize a FILE* from an open fd */
392 static int msvcrt_init_fp(MSVCRT_FILE* file, int fd, unsigned stream_flags)
393 {
394   TRACE(":fd (%d) allocating FILE*\n",fd);
395   if (!msvcrt_is_valid_fd(fd))
396   {
397     WARN(":invalid fd %d\n",fd);
398     *MSVCRT___doserrno() = 0;
399     *MSVCRT__errno() = MSVCRT_EBADF;
400     return -1;
401   }
402   memset(file, 0, sizeof(*file));
403   file->_file = fd;
404   file->_flag = stream_flags;
405
406   TRACE(":got FILE* (%p)\n",file);
407   return 0;
408 }
409
410 /* INTERNAL: Create an inheritance data block (for spawned process)
411  * The inheritance block is made of:
412  *      00      int     nb of file descriptor (NBFD)
413  *      04      char    file flags (wxflag): repeated for each fd
414  *      4+NBFD  HANDLE  file handle: repeated for each fd
415  */
416 unsigned msvcrt_create_io_inherit_block(WORD *size, BYTE **block)
417 {
418   int         fd;
419   char*       wxflag_ptr;
420   HANDLE*     handle_ptr;
421   ioinfo*     fdinfo;
422
423   *size = sizeof(unsigned) + (sizeof(char) + sizeof(HANDLE)) * MSVCRT_fdend;
424   *block = MSVCRT_calloc(*size, 1);
425   if (!*block)
426   {
427     *size = 0;
428     return FALSE;
429   }
430   wxflag_ptr = (char*)*block + sizeof(unsigned);
431   handle_ptr = (HANDLE*)(wxflag_ptr + MSVCRT_fdend * sizeof(char));
432
433   *(unsigned*)*block = MSVCRT_fdend;
434   for (fd = 0; fd < MSVCRT_fdend; fd++)
435   {
436     /* to be inherited, we need it to be open, and that DONTINHERIT isn't set */
437     fdinfo = msvcrt_get_ioinfo(fd);
438     if ((fdinfo->wxflag & (WX_OPEN | WX_DONTINHERIT)) == WX_OPEN)
439     {
440       *wxflag_ptr = fdinfo->wxflag;
441       *handle_ptr = fdinfo->handle;
442     }
443     else
444     {
445       *wxflag_ptr = 0;
446       *handle_ptr = INVALID_HANDLE_VALUE;
447     }
448     wxflag_ptr++; handle_ptr++;
449   } 
450   return TRUE;
451 }
452
453 /* INTERNAL: Set up all file descriptors, 
454  * as well as default streams (stdin, stderr and stdout) 
455  */
456 void msvcrt_init_io(void)
457 {
458   STARTUPINFOA  si;
459   int           i;
460   ioinfo        *fdinfo;
461
462   GetStartupInfoA(&si);
463   if (si.cbReserved2 >= sizeof(unsigned int) && si.lpReserved2 != NULL)
464   {
465     BYTE*       wxflag_ptr;
466     HANDLE*     handle_ptr;
467     unsigned int count;
468
469     count = *(unsigned*)si.lpReserved2;
470     wxflag_ptr = si.lpReserved2 + sizeof(unsigned);
471     handle_ptr = (HANDLE*)(wxflag_ptr + count);
472
473     count = min(count, (si.cbReserved2 - sizeof(unsigned)) / (sizeof(HANDLE) + 1));
474     count = min(count, MSVCRT_MAX_FILES);
475     for (i = 0; i < count; i++)
476     {
477       if ((*wxflag_ptr & WX_OPEN) && *handle_ptr != INVALID_HANDLE_VALUE)
478         msvcrt_set_fd(*handle_ptr, *wxflag_ptr, i);
479
480       wxflag_ptr++; handle_ptr++;
481     }
482     MSVCRT_fdend = max( 3, count );
483     for (MSVCRT_fdstart = 3; MSVCRT_fdstart < MSVCRT_fdend; MSVCRT_fdstart++)
484         if (msvcrt_get_ioinfo(MSVCRT_fdstart)->handle == INVALID_HANDLE_VALUE) break;
485   }
486
487   fdinfo = msvcrt_get_ioinfo(MSVCRT_STDIN_FILENO);
488   if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE)
489     msvcrt_set_fd(GetStdHandle(STD_INPUT_HANDLE), WX_OPEN|WX_TEXT, MSVCRT_STDIN_FILENO);
490
491   fdinfo = msvcrt_get_ioinfo(MSVCRT_STDOUT_FILENO);
492   if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE)
493     msvcrt_set_fd(GetStdHandle(STD_OUTPUT_HANDLE), WX_OPEN|WX_TEXT, MSVCRT_STDOUT_FILENO);
494
495   fdinfo = msvcrt_get_ioinfo(MSVCRT_STDERR_FILENO);
496   if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE)
497     msvcrt_set_fd(GetStdHandle(STD_ERROR_HANDLE), WX_OPEN|WX_TEXT, MSVCRT_STDERR_FILENO);
498
499   TRACE(":handles (%p)(%p)(%p)\n", msvcrt_get_ioinfo(MSVCRT_STDIN_FILENO)->handle,
500         msvcrt_get_ioinfo(MSVCRT_STDOUT_FILENO)->handle,
501         msvcrt_get_ioinfo(MSVCRT_STDERR_FILENO)->handle);
502
503   memset(MSVCRT__iob,0,3*sizeof(MSVCRT_FILE));
504   for (i = 0; i < 3; i++)
505   {
506     /* FILE structs for stdin/out/err are static and never deleted */
507     MSVCRT__iob[i]._file = i;
508     MSVCRT__iob[i]._tmpfname = NULL;
509     MSVCRT__iob[i]._flag = (i == 0) ? MSVCRT__IOREAD : MSVCRT__IOWRT;
510   }
511   MSVCRT_stream_idx = 3;
512 }
513
514 /* INTERNAL: Flush stdio file buffer */
515 static int msvcrt_flush_buffer(MSVCRT_FILE* file)
516 {
517   if(file->_bufsiz) {
518         int cnt=file->_ptr-file->_base;
519         if(cnt>0 && MSVCRT__write(file->_file, file->_base, cnt) != cnt) {
520             file->_flag |= MSVCRT__IOERR;
521             return MSVCRT_EOF;
522         }
523         file->_ptr=file->_base;
524         file->_cnt=file->_bufsiz;
525   }
526   return 0;
527 }
528
529 /*********************************************************************
530  *              _isatty (MSVCRT.@)
531  */
532 int CDECL MSVCRT__isatty(int fd)
533 {
534     HANDLE hand = msvcrt_fdtoh(fd);
535
536     TRACE(":fd (%d) handle (%p)\n",fd,hand);
537     if (hand == INVALID_HANDLE_VALUE)
538         return 0;
539
540     return GetFileType(hand) == FILE_TYPE_CHAR? 1 : 0;
541 }
542
543 /* INTERNAL: Allocate stdio file buffer */
544 static BOOL msvcrt_alloc_buffer(MSVCRT_FILE* file)
545 {
546     if((file->_file==MSVCRT_STDOUT_FILENO || file->_file==MSVCRT_STDERR_FILENO)
547             && MSVCRT__isatty(file->_file))
548         return FALSE;
549
550     file->_base = MSVCRT_calloc(MSVCRT_BUFSIZ,1);
551     if(file->_base) {
552         file->_bufsiz = MSVCRT_BUFSIZ;
553         file->_flag |= MSVCRT__IOMYBUF;
554     } else {
555         file->_base = (char*)(&file->_charbuf);
556         /* put here 2 ??? */
557         file->_bufsiz = sizeof(file->_charbuf);
558     }
559     file->_ptr = file->_base;
560     file->_cnt = 0;
561     return TRUE;
562 }
563
564 /* INTERNAL: Allocate temporary buffer for stdout and stderr */
565 static BOOL add_std_buffer(MSVCRT_FILE *file)
566 {
567     static char buffers[2][MSVCRT_BUFSIZ];
568
569     if((file->_file!=MSVCRT_STDOUT_FILENO && file->_file!=MSVCRT_STDERR_FILENO)
570             || !MSVCRT__isatty(file->_file) || file->_bufsiz)
571         return FALSE;
572
573     file->_ptr = file->_base = buffers[file->_file == MSVCRT_STDOUT_FILENO ? 0 : 1];
574     file->_bufsiz = file->_cnt = MSVCRT_BUFSIZ;
575     return TRUE;
576 }
577
578 /* INTERNAL: Removes temporary buffer from stdout or stderr */
579 /* Only call this function when add_std_buffer returned TRUE */
580 static void remove_std_buffer(MSVCRT_FILE *file)
581 {
582     msvcrt_flush_buffer(file);
583     file->_ptr = file->_base = NULL;
584     file->_bufsiz = file->_cnt = 0;
585 }
586
587 /* INTERNAL: Convert integer to base32 string (0-9a-v), 0 becomes "" */
588 static int msvcrt_int_to_base32(int num, char *str)
589 {
590   char *p;
591   int n = num;
592   int digits = 0;
593
594   while (n != 0)
595   {
596     n >>= 5;
597     digits++;
598   }
599   p = str + digits;
600   *p = 0;
601   while (--p >= str)
602   {
603     *p = (num & 31) + '0';
604     if (*p > '9')
605       *p += ('a' - '0' - 10);
606     num >>= 5;
607   }
608
609   return digits;
610 }
611
612 /* INTERNAL: wide character version of msvcrt_int_to_base32 */
613 static int msvcrt_int_to_base32_w(int num, MSVCRT_wchar_t *str)
614 {
615     MSVCRT_wchar_t *p;
616     int n = num;
617     int digits = 0;
618
619     while (n != 0)
620     {
621         n >>= 5;
622         digits++;
623     }
624     p = str + digits;
625     *p = 0;
626     while (--p >= str)
627     {
628         *p = (num & 31) + '0';
629         if (*p > '9')
630             *p += ('a' - '0' - 10);
631         num >>= 5;
632     }
633
634     return digits;
635 }
636
637 /*********************************************************************
638  *              __iob_func(MSVCRT.@)
639  */
640 MSVCRT_FILE * CDECL MSVCRT___iob_func(void)
641 {
642  return &MSVCRT__iob[0];
643 }
644
645 /*********************************************************************
646  *              _access (MSVCRT.@)
647  */
648 int CDECL MSVCRT__access(const char *filename, int mode)
649 {
650   DWORD attr = GetFileAttributesA(filename);
651
652   TRACE("(%s,%d) %d\n",filename,mode,attr);
653
654   if (!filename || attr == INVALID_FILE_ATTRIBUTES)
655   {
656     msvcrt_set_errno(GetLastError());
657     return -1;
658   }
659   if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & MSVCRT_W_OK))
660   {
661     msvcrt_set_errno(ERROR_ACCESS_DENIED);
662     return -1;
663   }
664   return 0;
665 }
666
667 /*********************************************************************
668  *              _access_s (MSVCRT.@)
669  */
670 int CDECL _access_s(const char *filename, int mode)
671 {
672   if (!MSVCRT_CHECK_PMT(filename != NULL)) return -1;
673   if (!MSVCRT_CHECK_PMT((mode & ~(MSVCRT_R_OK | MSVCRT_W_OK)) == 0)) return -1;
674
675   return MSVCRT__access(filename, mode);
676 }
677
678 /*********************************************************************
679  *              _waccess (MSVCRT.@)
680  */
681 int CDECL MSVCRT__waccess(const MSVCRT_wchar_t *filename, int mode)
682 {
683   DWORD attr = GetFileAttributesW(filename);
684
685   TRACE("(%s,%d) %d\n",debugstr_w(filename),mode,attr);
686
687   if (!filename || attr == INVALID_FILE_ATTRIBUTES)
688   {
689     msvcrt_set_errno(GetLastError());
690     return -1;
691   }
692   if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & MSVCRT_W_OK))
693   {
694     msvcrt_set_errno(ERROR_ACCESS_DENIED);
695     return -1;
696   }
697   return 0;
698 }
699
700 /*********************************************************************
701  *              _waccess_s (MSVCRT.@)
702  */
703 int CDECL _waccess_s(const MSVCRT_wchar_t *filename, int mode)
704 {
705   if (!MSVCRT_CHECK_PMT(filename != NULL)) return -1;
706   if (!MSVCRT_CHECK_PMT((mode & ~(MSVCRT_R_OK | MSVCRT_W_OK)) == 0)) return -1;
707
708   return MSVCRT__waccess(filename, mode);
709 }
710
711 /*********************************************************************
712  *              _chmod (MSVCRT.@)
713  */
714 int CDECL MSVCRT__chmod(const char *path, int flags)
715 {
716   DWORD oldFlags = GetFileAttributesA(path);
717
718   if (oldFlags != INVALID_FILE_ATTRIBUTES)
719   {
720     DWORD newFlags = (flags & MSVCRT__S_IWRITE)? oldFlags & ~FILE_ATTRIBUTE_READONLY:
721       oldFlags | FILE_ATTRIBUTE_READONLY;
722
723     if (newFlags == oldFlags || SetFileAttributesA(path, newFlags))
724       return 0;
725   }
726   msvcrt_set_errno(GetLastError());
727   return -1;
728 }
729
730 /*********************************************************************
731  *              _wchmod (MSVCRT.@)
732  */
733 int CDECL MSVCRT__wchmod(const MSVCRT_wchar_t *path, int flags)
734 {
735   DWORD oldFlags = GetFileAttributesW(path);
736
737   if (oldFlags != INVALID_FILE_ATTRIBUTES)
738   {
739     DWORD newFlags = (flags & MSVCRT__S_IWRITE)? oldFlags & ~FILE_ATTRIBUTE_READONLY:
740       oldFlags | FILE_ATTRIBUTE_READONLY;
741
742     if (newFlags == oldFlags || SetFileAttributesW(path, newFlags))
743       return 0;
744   }
745   msvcrt_set_errno(GetLastError());
746   return -1;
747 }
748
749 /*********************************************************************
750  *              _unlink (MSVCRT.@)
751  */
752 int CDECL MSVCRT__unlink(const char *path)
753 {
754   TRACE("%s\n",debugstr_a(path));
755   if(DeleteFileA(path))
756     return 0;
757   TRACE("failed (%d)\n",GetLastError());
758   msvcrt_set_errno(GetLastError());
759   return -1;
760 }
761
762 /*********************************************************************
763  *              _wunlink (MSVCRT.@)
764  */
765 int CDECL MSVCRT__wunlink(const MSVCRT_wchar_t *path)
766 {
767   TRACE("(%s)\n",debugstr_w(path));
768   if(DeleteFileW(path))
769     return 0;
770   TRACE("failed (%d)\n",GetLastError());
771   msvcrt_set_errno(GetLastError());
772   return -1;
773 }
774
775 /*********************************************************************
776  *              _commit (MSVCRT.@)
777  */
778 int CDECL MSVCRT__commit(int fd)
779 {
780     HANDLE hand = msvcrt_fdtoh(fd);
781
782     TRACE(":fd (%d) handle (%p)\n",fd,hand);
783     if (hand == INVALID_HANDLE_VALUE)
784         return -1;
785
786     if (!FlushFileBuffers(hand))
787     {
788         if (GetLastError() == ERROR_INVALID_HANDLE)
789         {
790             /* FlushFileBuffers fails for console handles
791              * so we ignore this error.
792              */
793             return 0;
794         }
795         TRACE(":failed-last error (%d)\n",GetLastError());
796         msvcrt_set_errno(GetLastError());
797         return -1;
798     }
799     TRACE(":ok\n");
800     return 0;
801 }
802
803 /* flush_all_buffers calls MSVCRT_fflush which calls flush_all_buffers */
804 int CDECL MSVCRT_fflush(MSVCRT_FILE* file);
805
806 /* INTERNAL: Flush all stream buffer */
807 static int msvcrt_flush_all_buffers(int mask)
808 {
809   int i, num_flushed = 0;
810   MSVCRT_FILE *file;
811
812   LOCK_FILES();
813   for (i = 3; i < MSVCRT_stream_idx; i++) {
814     file = msvcrt_get_file(i);
815
816     if (file->_flag)
817     {
818       if(file->_flag & mask) {
819         MSVCRT_fflush(file);
820         num_flushed++;
821       }
822     }
823   }
824   UNLOCK_FILES();
825
826   TRACE(":flushed (%d) handles\n",num_flushed);
827   return num_flushed;
828 }
829
830 /*********************************************************************
831  *              _flushall (MSVCRT.@)
832  */
833 int CDECL MSVCRT__flushall(void)
834 {
835     return msvcrt_flush_all_buffers(MSVCRT__IOWRT | MSVCRT__IOREAD);
836 }
837
838 /*********************************************************************
839  *              fflush (MSVCRT.@)
840  */
841 int CDECL MSVCRT_fflush(MSVCRT_FILE* file)
842 {
843     if(!file) {
844         msvcrt_flush_all_buffers(MSVCRT__IOWRT);
845     } else if(file->_flag & MSVCRT__IOWRT) {
846         int res;
847
848         MSVCRT__lock_file(file);
849         res = msvcrt_flush_buffer(file);
850
851         if(!res && (file->_flag & MSVCRT__IOCOMMIT))
852             res = MSVCRT__commit(file->_file) ? MSVCRT_EOF : 0;
853         MSVCRT__unlock_file(file);
854
855         return res;
856     } else if(file->_flag & MSVCRT__IOREAD) {
857         MSVCRT__lock_file(file);
858         file->_cnt = 0;
859         file->_ptr = file->_base;
860         MSVCRT__unlock_file(file);
861
862         return 0;
863     }
864     return 0;
865 }
866
867 /*********************************************************************
868  *              _close (MSVCRT.@)
869  */
870 int CDECL MSVCRT__close(int fd)
871 {
872   HANDLE hand;
873   int ret;
874
875   LOCK_FILES();
876   hand = msvcrt_fdtoh(fd);
877   TRACE(":fd (%d) handle (%p)\n",fd,hand);
878   if (!msvcrt_is_valid_fd(fd)) {
879     ret = -1;
880   } else {
881     msvcrt_free_fd(fd);
882     ret = CloseHandle(hand) ? 0 : -1;
883     if (ret) {
884       WARN(":failed-last error (%d)\n",GetLastError());
885       msvcrt_set_errno(GetLastError());
886     }
887   }
888   UNLOCK_FILES();
889   TRACE(":ok\n");
890   return ret;
891 }
892
893 /*********************************************************************
894  *              _dup2 (MSVCRT.@)
895  * NOTES
896  * MSDN isn't clear on this point, but the remarks for _pipe
897  * indicate file descriptors duplicated with _dup and _dup2 are always
898  * inheritable.
899  */
900 int CDECL MSVCRT__dup2(int od, int nd)
901 {
902   int ret;
903
904   TRACE("(od=%d, nd=%d)\n", od, nd);
905   LOCK_FILES();
906   if (nd < MSVCRT_MAX_FILES && nd >= 0 && msvcrt_is_valid_fd(od))
907   {
908     HANDLE handle;
909
910     if (DuplicateHandle(GetCurrentProcess(), msvcrt_get_ioinfo(od)->handle,
911      GetCurrentProcess(), &handle, 0, TRUE, DUPLICATE_SAME_ACCESS))
912     {
913       int wxflag = msvcrt_get_ioinfo(od)->wxflag & ~MSVCRT__O_NOINHERIT;
914
915       if (msvcrt_is_valid_fd(nd))
916         MSVCRT__close(nd);
917       ret = msvcrt_set_fd(handle, wxflag, nd);
918       if (ret == -1)
919       {
920         CloseHandle(handle);
921         *MSVCRT__errno() = MSVCRT_EMFILE;
922       }
923       else
924       {
925         /* _dup2 returns 0, not nd, on success */
926         ret = 0;
927       }
928     }
929     else
930     {
931       ret = -1;
932       msvcrt_set_errno(GetLastError());
933     }
934   }
935   else
936   {
937     *MSVCRT__errno() = MSVCRT_EBADF;
938     ret = -1;
939   }
940   UNLOCK_FILES();
941   return ret;
942 }
943
944 /*********************************************************************
945  *              _dup (MSVCRT.@)
946  */
947 int CDECL MSVCRT__dup(int od)
948 {
949   int fd, ret;
950  
951   LOCK_FILES();
952   fd = MSVCRT_fdstart;
953   if (MSVCRT__dup2(od, fd) == 0)
954     ret = fd;
955   else
956     ret = -1;
957   UNLOCK_FILES();
958   return ret;
959 }
960
961 /*********************************************************************
962  *              _eof (MSVCRT.@)
963  */
964 int CDECL MSVCRT__eof(int fd)
965 {
966   DWORD curpos,endpos;
967   LONG hcurpos,hendpos;
968   HANDLE hand = msvcrt_fdtoh(fd);
969
970   TRACE(":fd (%d) handle (%p)\n",fd,hand);
971
972   if (hand == INVALID_HANDLE_VALUE)
973     return -1;
974
975   if (msvcrt_get_ioinfo(fd)->wxflag & WX_ATEOF) return TRUE;
976
977   /* Otherwise we do it the hard way */
978   hcurpos = hendpos = 0;
979   curpos = SetFilePointer(hand, 0, &hcurpos, FILE_CURRENT);
980   endpos = SetFilePointer(hand, 0, &hendpos, FILE_END);
981
982   if (curpos == endpos && hcurpos == hendpos)
983   {
984     /* FIXME: shouldn't WX_ATEOF be set here? */
985     return TRUE;
986   }
987
988   SetFilePointer(hand, curpos, &hcurpos, FILE_BEGIN);
989   return FALSE;
990 }
991
992 /*********************************************************************
993  *              _fcloseall (MSVCRT.@)
994  */
995 int CDECL MSVCRT__fcloseall(void)
996 {
997   int num_closed = 0, i;
998   MSVCRT_FILE *file;
999
1000   LOCK_FILES();
1001   for (i = 3; i < MSVCRT_stream_idx; i++) {
1002     file = msvcrt_get_file(i);
1003
1004     if (file->_flag && !MSVCRT_fclose(file))
1005       num_closed++;
1006   }
1007   UNLOCK_FILES();
1008
1009   TRACE(":closed (%d) handles\n",num_closed);
1010   return num_closed;
1011 }
1012
1013 /* free everything on process exit */
1014 void msvcrt_free_io(void)
1015 {
1016     unsigned int i;
1017     int j;
1018
1019     MSVCRT__fcloseall();
1020     /* The Win32 _fcloseall() function explicitly doesn't close stdin,
1021      * stdout, and stderr (unlike GNU), so we need to fclose() them here
1022      * or they won't get flushed.
1023      */
1024     MSVCRT_fclose(&MSVCRT__iob[0]);
1025     MSVCRT_fclose(&MSVCRT__iob[1]);
1026     MSVCRT_fclose(&MSVCRT__iob[2]);
1027
1028     for(i=0; i<sizeof(MSVCRT___pioinfo)/sizeof(MSVCRT___pioinfo[0]); i++)
1029         MSVCRT_free(MSVCRT___pioinfo[i]);
1030
1031     for(j=0; j<MSVCRT_stream_idx; j++)
1032     {
1033         MSVCRT_FILE *file = msvcrt_get_file(j);
1034         if(file<MSVCRT__iob || file>=MSVCRT__iob+_IOB_ENTRIES)
1035         {
1036             ((file_crit*)file)->crit.DebugInfo->Spare[0] = 0;
1037             DeleteCriticalSection(&((file_crit*)file)->crit);
1038         }
1039     }
1040
1041     for(i=0; i<sizeof(MSVCRT_fstream)/sizeof(MSVCRT_fstream[0]); i++)
1042         MSVCRT_free(MSVCRT_fstream[i]);
1043
1044     DeleteCriticalSection(&MSVCRT_file_cs);
1045 }
1046
1047 /*********************************************************************
1048  *              _lseeki64 (MSVCRT.@)
1049  */
1050 __int64 CDECL MSVCRT__lseeki64(int fd, __int64 offset, int whence)
1051 {
1052   HANDLE hand = msvcrt_fdtoh(fd);
1053   LARGE_INTEGER ofs;
1054
1055   TRACE(":fd (%d) handle (%p)\n",fd,hand);
1056   if (hand == INVALID_HANDLE_VALUE)
1057     return -1;
1058
1059   if (whence < 0 || whence > 2)
1060   {
1061     *MSVCRT__errno() = MSVCRT_EINVAL;
1062     return -1;
1063   }
1064
1065   TRACE(":fd (%d) to %s pos %s\n",
1066         fd,wine_dbgstr_longlong(offset),
1067         (whence==SEEK_SET)?"SEEK_SET":
1068         (whence==SEEK_CUR)?"SEEK_CUR":
1069         (whence==SEEK_END)?"SEEK_END":"UNKNOWN");
1070
1071   /* The MoleBox protection scheme expects msvcrt to use SetFilePointer only,
1072    * so a LARGE_INTEGER offset cannot be passed directly via SetFilePointerEx. */
1073   ofs.QuadPart = offset;
1074   if ((ofs.u.LowPart = SetFilePointer(hand, ofs.u.LowPart, &ofs.u.HighPart, whence)) != INVALID_SET_FILE_POINTER ||
1075       GetLastError() == ERROR_SUCCESS)
1076   {
1077     msvcrt_get_ioinfo(fd)->wxflag &= ~WX_ATEOF;
1078     /* FIXME: What if we seek _to_ EOF - is EOF set? */
1079
1080     return ofs.QuadPart;
1081   }
1082   TRACE(":error-last error (%d)\n",GetLastError());
1083   msvcrt_set_errno(GetLastError());
1084   return -1;
1085 }
1086
1087 /*********************************************************************
1088  *              _lseek (MSVCRT.@)
1089  */
1090 LONG CDECL MSVCRT__lseek(int fd, LONG offset, int whence)
1091 {
1092     return MSVCRT__lseeki64(fd, offset, whence);
1093 }
1094
1095 /*********************************************************************
1096  *              _lock_file (MSVCRT.@)
1097  */
1098 void CDECL MSVCRT__lock_file(MSVCRT_FILE *file)
1099 {
1100     if(file>=MSVCRT__iob && file<MSVCRT__iob+_IOB_ENTRIES)
1101         _lock(_STREAM_LOCKS+(file-MSVCRT__iob));
1102     else
1103         EnterCriticalSection(&((file_crit*)file)->crit);
1104 }
1105
1106 /*********************************************************************
1107  *              _unlock_file (MSVCRT.@)
1108  */
1109 void CDECL MSVCRT__unlock_file(MSVCRT_FILE *file)
1110 {
1111     if(file>=MSVCRT__iob && file<MSVCRT__iob+_IOB_ENTRIES)
1112         _unlock(_STREAM_LOCKS+(file-MSVCRT__iob));
1113     else
1114         LeaveCriticalSection(&((file_crit*)file)->crit);
1115 }
1116
1117 /*********************************************************************
1118  *              _locking (MSVCRT.@)
1119  *
1120  * This is untested; the underlying LockFile doesn't work yet.
1121  */
1122 int CDECL MSVCRT__locking(int fd, int mode, LONG nbytes)
1123 {
1124   BOOL ret;
1125   DWORD cur_locn;
1126   HANDLE hand = msvcrt_fdtoh(fd);
1127
1128   TRACE(":fd (%d) handle (%p)\n",fd,hand);
1129   if (hand == INVALID_HANDLE_VALUE)
1130     return -1;
1131
1132   if (mode < 0 || mode > 4)
1133   {
1134     *MSVCRT__errno() = MSVCRT_EINVAL;
1135     return -1;
1136   }
1137
1138   TRACE(":fd (%d) by 0x%08x mode %s\n",
1139         fd,nbytes,(mode==MSVCRT__LK_UNLCK)?"_LK_UNLCK":
1140         (mode==MSVCRT__LK_LOCK)?"_LK_LOCK":
1141         (mode==MSVCRT__LK_NBLCK)?"_LK_NBLCK":
1142         (mode==MSVCRT__LK_RLCK)?"_LK_RLCK":
1143         (mode==MSVCRT__LK_NBRLCK)?"_LK_NBRLCK":
1144                           "UNKNOWN");
1145
1146   if ((cur_locn = SetFilePointer(hand, 0L, NULL, SEEK_CUR)) == INVALID_SET_FILE_POINTER)
1147   {
1148     FIXME ("Seek failed\n");
1149     *MSVCRT__errno() = MSVCRT_EINVAL; /* FIXME */
1150     return -1;
1151   }
1152   if (mode == MSVCRT__LK_LOCK || mode == MSVCRT__LK_RLCK)
1153   {
1154     int nretry = 10;
1155     ret = 1; /* just to satisfy gcc */
1156     while (nretry--)
1157     {
1158       ret = LockFile(hand, cur_locn, 0L, nbytes, 0L);
1159       if (ret) break;
1160       Sleep(1);
1161     }
1162   }
1163   else if (mode == MSVCRT__LK_UNLCK)
1164     ret = UnlockFile(hand, cur_locn, 0L, nbytes, 0L);
1165   else
1166     ret = LockFile(hand, cur_locn, 0L, nbytes, 0L);
1167   /* FIXME - what about error settings? */
1168   return ret ? 0 : -1;
1169 }
1170
1171 /*********************************************************************
1172  *              _fseeki64 (MSVCRT.@)
1173  */
1174 int CDECL MSVCRT__fseeki64(MSVCRT_FILE* file, __int64 offset, int whence)
1175 {
1176   int ret;
1177
1178   MSVCRT__lock_file(file);
1179   /* Flush output if needed */
1180   if(file->_flag & MSVCRT__IOWRT)
1181         msvcrt_flush_buffer(file);
1182
1183   if(whence == SEEK_CUR && file->_flag & MSVCRT__IOREAD ) {
1184       whence = SEEK_SET;
1185       offset += MSVCRT__ftelli64(file);
1186   }
1187
1188   /* Discard buffered input */
1189   file->_cnt = 0;
1190   file->_ptr = file->_base;
1191   /* Reset direction of i/o */
1192   if(file->_flag & MSVCRT__IORW) {
1193         file->_flag &= ~(MSVCRT__IOREAD|MSVCRT__IOWRT);
1194   }
1195   /* Clear end of file flag */
1196   file->_flag &= ~MSVCRT__IOEOF;
1197   ret = (MSVCRT__lseeki64(file->_file,offset,whence) == -1)?-1:0;
1198
1199   MSVCRT__unlock_file(file);
1200   return ret;
1201 }
1202
1203 /*********************************************************************
1204  *              fseek (MSVCRT.@)
1205  */
1206 int CDECL MSVCRT_fseek(MSVCRT_FILE* file, MSVCRT_long offset, int whence)
1207 {
1208     return MSVCRT__fseeki64( file, offset, whence );
1209 }
1210
1211 /*********************************************************************
1212  *              _chsize (MSVCRT.@)
1213  */
1214 int CDECL MSVCRT__chsize(int fd, MSVCRT_long size)
1215 {
1216     LONG cur, pos;
1217     HANDLE handle;
1218     BOOL ret = FALSE;
1219
1220     TRACE("(fd=%d, size=%d)\n", fd, size);
1221
1222     LOCK_FILES();
1223
1224     handle = msvcrt_fdtoh(fd);
1225     if (handle != INVALID_HANDLE_VALUE)
1226     {
1227         /* save the current file pointer */
1228         cur = MSVCRT__lseek(fd, 0, SEEK_CUR);
1229         if (cur >= 0)
1230         {
1231             pos = MSVCRT__lseek(fd, size, SEEK_SET);
1232             if (pos >= 0)
1233             {
1234                 ret = SetEndOfFile(handle);
1235                 if (!ret) msvcrt_set_errno(GetLastError());
1236             }
1237
1238             /* restore the file pointer */
1239             MSVCRT__lseek(fd, cur, SEEK_SET);
1240         }
1241     }
1242
1243     UNLOCK_FILES();
1244     return ret ? 0 : -1;
1245 }
1246
1247 /*********************************************************************
1248  *              clearerr (MSVCRT.@)
1249  */
1250 void CDECL MSVCRT_clearerr(MSVCRT_FILE* file)
1251 {
1252   TRACE(":file (%p) fd (%d)\n",file,file->_file);
1253
1254   MSVCRT__lock_file(file);
1255   file->_flag &= ~(MSVCRT__IOERR | MSVCRT__IOEOF);
1256   MSVCRT__unlock_file(file);
1257 }
1258
1259 /*********************************************************************
1260  *              rewind (MSVCRT.@)
1261  */
1262 void CDECL MSVCRT_rewind(MSVCRT_FILE* file)
1263 {
1264   TRACE(":file (%p) fd (%d)\n",file,file->_file);
1265
1266   MSVCRT__lock_file(file);
1267   MSVCRT_fseek(file, 0L, SEEK_SET);
1268   MSVCRT_clearerr(file);
1269   MSVCRT__unlock_file(file);
1270 }
1271
1272 static int msvcrt_get_flags(const MSVCRT_wchar_t* mode, int *open_flags, int* stream_flags)
1273 {
1274   int plus = strchrW(mode, '+') != NULL;
1275
1276   TRACE("%s\n", debugstr_w(mode));
1277
1278   while(*mode == ' ') mode++;
1279
1280   switch(*mode++)
1281   {
1282   case 'R': case 'r':
1283     *open_flags = plus ? MSVCRT__O_RDWR : MSVCRT__O_RDONLY;
1284     *stream_flags = plus ? MSVCRT__IORW : MSVCRT__IOREAD;
1285     break;
1286   case 'W': case 'w':
1287     *open_flags = MSVCRT__O_CREAT | MSVCRT__O_TRUNC | (plus  ? MSVCRT__O_RDWR : MSVCRT__O_WRONLY);
1288     *stream_flags = plus ? MSVCRT__IORW : MSVCRT__IOWRT;
1289     break;
1290   case 'A': case 'a':
1291     *open_flags = MSVCRT__O_CREAT | MSVCRT__O_APPEND | (plus  ? MSVCRT__O_RDWR : MSVCRT__O_WRONLY);
1292     *stream_flags = plus ? MSVCRT__IORW : MSVCRT__IOWRT;
1293     break;
1294   default:
1295     MSVCRT_INVALID_PMT(0, MSVCRT_EINVAL);
1296     return -1;
1297   }
1298
1299   *stream_flags |= MSVCRT__commode;
1300
1301   while (*mode && *mode!=',')
1302     switch (*mode++)
1303     {
1304     case 'B': case 'b':
1305       *open_flags |=  MSVCRT__O_BINARY;
1306       *open_flags &= ~MSVCRT__O_TEXT;
1307       break;
1308     case 't':
1309       *open_flags |=  MSVCRT__O_TEXT;
1310       *open_flags &= ~MSVCRT__O_BINARY;
1311       break;
1312     case 'D':
1313       *open_flags |= MSVCRT__O_TEMPORARY;
1314       break;
1315     case 'T':
1316       *open_flags |= MSVCRT__O_SHORT_LIVED;
1317       break;
1318     case 'c':
1319       *stream_flags |= MSVCRT__IOCOMMIT;
1320       break;
1321     case 'n':
1322       *stream_flags &= ~MSVCRT__IOCOMMIT;
1323       break;
1324     case 'N':
1325       *open_flags |= MSVCRT__O_NOINHERIT;
1326       break;
1327     case '+':
1328     case ' ':
1329     case 'a':
1330     case 'w':
1331       break;
1332     case 'S':
1333     case 'R':
1334       FIXME("ignoring cache optimization flag: %c\n", mode[-1]);
1335       break;
1336     default:
1337       MSVCRT_INVALID_PMT(0, MSVCRT_EINVAL);
1338       return -1;
1339     }
1340
1341   if(*mode == ',')
1342   {
1343     static const WCHAR ccs[] = {'c','c','s'};
1344     static const WCHAR utf8[] = {'u','t','f','-','8'};
1345     static const WCHAR utf16le[] = {'u','t','f','-','1','6','l','e'};
1346     static const WCHAR unicode[] = {'u','n','i','c','o','d','e'};
1347
1348     mode++;
1349     while(*mode == ' ') mode++;
1350     if(!MSVCRT_CHECK_PMT(!strncmpW(ccs, mode, sizeof(ccs)/sizeof(ccs[0]))))
1351       return -1;
1352     mode += sizeof(ccs)/sizeof(ccs[0]);
1353     while(*mode == ' ') mode++;
1354     if(!MSVCRT_CHECK_PMT(*mode == '='))
1355         return -1;
1356     mode++;
1357     while(*mode == ' ') mode++;
1358
1359     if(!strncmpiW(utf8, mode, sizeof(utf8)/sizeof(utf8[0])))
1360     {
1361       *open_flags |= MSVCRT__O_U8TEXT;
1362       mode += sizeof(utf8)/sizeof(utf8[0]);
1363     }
1364     else if(!strncmpiW(utf16le, mode, sizeof(utf16le)/sizeof(utf16le[0])))
1365     {
1366       *open_flags |= MSVCRT__O_U16TEXT;
1367       mode += sizeof(utf16le)/sizeof(utf16le[0]);
1368     }
1369     else if(!strncmpiW(unicode, mode, sizeof(unicode)/sizeof(unicode[0])))
1370     {
1371       *open_flags |= MSVCRT__O_WTEXT;
1372       mode += sizeof(unicode)/sizeof(unicode[0]);
1373     }
1374     else
1375     {
1376       MSVCRT_INVALID_PMT(0, MSVCRT_EINVAL);
1377       return -1;
1378     }
1379
1380     while(*mode == ' ') mode++;
1381   }
1382
1383   if(!MSVCRT_CHECK_PMT(*mode == 0))
1384     return -1;
1385   return 0;
1386 }
1387
1388 /*********************************************************************
1389  *              _fdopen (MSVCRT.@)
1390  */
1391 MSVCRT_FILE* CDECL MSVCRT__fdopen(int fd, const char *mode)
1392 {
1393     MSVCRT_FILE *ret;
1394     MSVCRT_wchar_t *modeW = NULL;
1395
1396     if (mode && !(modeW = msvcrt_wstrdupa(mode))) return NULL;
1397
1398     ret = MSVCRT__wfdopen(fd, modeW);
1399
1400     MSVCRT_free(modeW);
1401     return ret;
1402 }
1403
1404 /*********************************************************************
1405  *              _wfdopen (MSVCRT.@)
1406  */
1407 MSVCRT_FILE* CDECL MSVCRT__wfdopen(int fd, const MSVCRT_wchar_t *mode)
1408 {
1409   int open_flags, stream_flags;
1410   MSVCRT_FILE* file;
1411
1412   if (msvcrt_get_flags(mode, &open_flags, &stream_flags) == -1) return NULL;
1413
1414   LOCK_FILES();
1415   if (!(file = msvcrt_alloc_fp()))
1416     file = NULL;
1417   else if (msvcrt_init_fp(file, fd, stream_flags) == -1)
1418   {
1419     file->_flag = 0;
1420     file = NULL;
1421   }
1422   else TRACE(":fd (%d) mode (%s) FILE* (%p)\n", fd, debugstr_w(mode), file);
1423   UNLOCK_FILES();
1424
1425   return file;
1426 }
1427
1428 /*********************************************************************
1429  *              _filelength (MSVCRT.@)
1430  */
1431 LONG CDECL MSVCRT__filelength(int fd)
1432 {
1433   LONG curPos = MSVCRT__lseek(fd, 0, SEEK_CUR);
1434   if (curPos != -1)
1435   {
1436     LONG endPos = MSVCRT__lseek(fd, 0, SEEK_END);
1437     if (endPos != -1)
1438     {
1439       if (endPos != curPos)
1440         MSVCRT__lseek(fd, curPos, SEEK_SET);
1441       return endPos;
1442     }
1443   }
1444   return -1;
1445 }
1446
1447 /*********************************************************************
1448  *              _filelengthi64 (MSVCRT.@)
1449  */
1450 __int64 CDECL MSVCRT__filelengthi64(int fd)
1451 {
1452   __int64 curPos = MSVCRT__lseeki64(fd, 0, SEEK_CUR);
1453   if (curPos != -1)
1454   {
1455     __int64 endPos = MSVCRT__lseeki64(fd, 0, SEEK_END);
1456     if (endPos != -1)
1457     {
1458       if (endPos != curPos)
1459         MSVCRT__lseeki64(fd, curPos, SEEK_SET);
1460       return endPos;
1461     }
1462   }
1463   return -1;
1464 }
1465
1466 /*********************************************************************
1467  *              _fileno (MSVCRT.@)
1468  */
1469 int CDECL MSVCRT__fileno(MSVCRT_FILE* file)
1470 {
1471   TRACE(":FILE* (%p) fd (%d)\n",file,file->_file);
1472   return file->_file;
1473 }
1474
1475 /*********************************************************************
1476  *              _fstat64 (MSVCRT.@)
1477  */
1478 int CDECL MSVCRT__fstat64(int fd, struct MSVCRT__stat64* buf)
1479 {
1480   DWORD dw;
1481   DWORD type;
1482   BY_HANDLE_FILE_INFORMATION hfi;
1483   HANDLE hand = msvcrt_fdtoh(fd);
1484
1485   TRACE(":fd (%d) stat (%p)\n",fd,buf);
1486   if (hand == INVALID_HANDLE_VALUE)
1487     return -1;
1488
1489   if (!buf)
1490   {
1491     WARN(":failed-NULL buf\n");
1492     msvcrt_set_errno(ERROR_INVALID_PARAMETER);
1493     return -1;
1494   }
1495
1496   memset(&hfi, 0, sizeof(hfi));
1497   memset(buf, 0, sizeof(struct MSVCRT__stat64));
1498   type = GetFileType(hand);
1499   if (type == FILE_TYPE_PIPE)
1500   {
1501     buf->st_dev = buf->st_rdev = fd;
1502     buf->st_mode = S_IFIFO;
1503     buf->st_nlink = 1;
1504   }
1505   else if (type == FILE_TYPE_CHAR)
1506   {
1507     buf->st_dev = buf->st_rdev = fd;
1508     buf->st_mode = S_IFCHR;
1509     buf->st_nlink = 1;
1510   }
1511   else /* FILE_TYPE_DISK etc. */
1512   {
1513     if (!GetFileInformationByHandle(hand, &hfi))
1514     {
1515       WARN(":failed-last error (%d)\n",GetLastError());
1516       msvcrt_set_errno(ERROR_INVALID_PARAMETER);
1517       return -1;
1518     }
1519     buf->st_mode = S_IFREG | 0444;
1520     if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
1521       buf->st_mode |= 0222;
1522     buf->st_size  = ((__int64)hfi.nFileSizeHigh << 32) + hfi.nFileSizeLow;
1523     RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastAccessTime, &dw);
1524     buf->st_atime = dw;
1525     RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastWriteTime, &dw);
1526     buf->st_mtime = buf->st_ctime = dw;
1527     buf->st_nlink = hfi.nNumberOfLinks;
1528   }
1529   TRACE(":dwFileAttributes = 0x%x, mode set to 0x%x\n",hfi.dwFileAttributes,
1530    buf->st_mode);
1531   return 0;
1532 }
1533
1534 /*********************************************************************
1535  *              _fstati64 (MSVCRT.@)
1536  */
1537 int CDECL MSVCRT__fstati64(int fd, struct MSVCRT__stati64* buf)
1538 {
1539   int ret;
1540   struct MSVCRT__stat64 buf64;
1541
1542   ret = MSVCRT__fstat64(fd, &buf64);
1543   if (!ret)
1544     msvcrt_stat64_to_stati64(&buf64, buf);
1545   return ret;
1546 }
1547
1548 /*********************************************************************
1549  *              _fstat (MSVCRT.@)
1550  */
1551 int CDECL MSVCRT__fstat(int fd, struct MSVCRT__stat* buf)
1552 { int ret;
1553   struct MSVCRT__stat64 buf64;
1554
1555   ret = MSVCRT__fstat64(fd, &buf64);
1556   if (!ret)
1557       msvcrt_stat64_to_stat(&buf64, buf);
1558   return ret;
1559 }
1560
1561 /*********************************************************************
1562  *              _futime64 (MSVCRT.@)
1563  */
1564 int CDECL _futime64(int fd, struct MSVCRT___utimbuf64 *t)
1565 {
1566   HANDLE hand = msvcrt_fdtoh(fd);
1567   FILETIME at, wt;
1568
1569   if (!t)
1570   {
1571       time_to_filetime( MSVCRT__time64(NULL), &at );
1572       wt = at;
1573   }
1574   else
1575   {
1576       time_to_filetime( t->actime, &at );
1577       time_to_filetime( t->modtime, &wt );
1578   }
1579
1580   if (!SetFileTime(hand, NULL, &at, &wt))
1581   {
1582     msvcrt_set_errno(GetLastError());
1583     return -1 ;
1584   }
1585   return 0;
1586 }
1587
1588 /*********************************************************************
1589  *              _futime32 (MSVCRT.@)
1590  */
1591 int CDECL _futime32(int fd, struct MSVCRT___utimbuf32 *t)
1592 {
1593     if (t)
1594     {
1595         struct MSVCRT___utimbuf64 t64;
1596         t64.actime = t->actime;
1597         t64.modtime = t->modtime;
1598         return _futime64( fd, &t64 );
1599     }
1600     else
1601         return _futime64( fd, NULL );
1602 }
1603
1604 /*********************************************************************
1605  *              _futime (MSVCRT.@)
1606  */
1607 #ifdef _WIN64
1608 int CDECL _futime(int fd, struct MSVCRT___utimbuf64 *t)
1609 {
1610     return _futime64( fd, t );
1611 }
1612 #else
1613 int CDECL _futime(int fd, struct MSVCRT___utimbuf32 *t)
1614 {
1615     return _futime32( fd, t );
1616 }
1617 #endif
1618
1619 /*********************************************************************
1620  *              _get_osfhandle (MSVCRT.@)
1621  */
1622 MSVCRT_intptr_t CDECL MSVCRT__get_osfhandle(int fd)
1623 {
1624   HANDLE hand = msvcrt_fdtoh(fd);
1625   TRACE(":fd (%d) handle (%p)\n",fd,hand);
1626
1627   return (MSVCRT_intptr_t)hand;
1628 }
1629
1630 /*********************************************************************
1631  *              _mktemp (MSVCRT.@)
1632  */
1633 char * CDECL MSVCRT__mktemp(char *pattern)
1634 {
1635   int numX = 0;
1636   char *retVal = pattern;
1637   int id;
1638   char letter = 'a';
1639
1640   while(*pattern)
1641     numX = (*pattern++ == 'X')? numX + 1 : 0;
1642   if (numX < 5)
1643     return NULL;
1644   pattern--;
1645   id = GetCurrentProcessId();
1646   numX = 6;
1647   while(numX--)
1648   {
1649     int tempNum = id / 10;
1650     *pattern-- = id - (tempNum * 10) + '0';
1651     id = tempNum;
1652   }
1653   pattern++;
1654   do
1655   {
1656     *pattern = letter++;
1657     if (GetFileAttributesA(retVal) == INVALID_FILE_ATTRIBUTES &&
1658         GetLastError() == ERROR_FILE_NOT_FOUND)
1659       return retVal;
1660   } while(letter <= 'z');
1661   return NULL;
1662 }
1663
1664 /*********************************************************************
1665  *              _wmktemp (MSVCRT.@)
1666  */
1667 MSVCRT_wchar_t * CDECL MSVCRT__wmktemp(MSVCRT_wchar_t *pattern)
1668 {
1669   int numX = 0;
1670   MSVCRT_wchar_t *retVal = pattern;
1671   int id;
1672   MSVCRT_wchar_t letter = 'a';
1673
1674   while(*pattern)
1675     numX = (*pattern++ == 'X')? numX + 1 : 0;
1676   if (numX < 5)
1677     return NULL;
1678   pattern--;
1679   id = GetCurrentProcessId();
1680   numX = 6;
1681   while(numX--)
1682   {
1683     int tempNum = id / 10;
1684     *pattern-- = id - (tempNum * 10) + '0';
1685     id = tempNum;
1686   }
1687   pattern++;
1688   do
1689   {
1690     if (GetFileAttributesW(retVal) == INVALID_FILE_ATTRIBUTES &&
1691         GetLastError() == ERROR_FILE_NOT_FOUND)
1692       return retVal;
1693     *pattern = letter++;
1694   } while(letter != '|');
1695   return NULL;
1696 }
1697
1698 static unsigned split_oflags(unsigned oflags)
1699 {
1700     int         wxflags = 0;
1701     unsigned unsupp; /* until we support everything */
1702
1703     if (oflags & MSVCRT__O_APPEND)              wxflags |= WX_APPEND;
1704     if (oflags & MSVCRT__O_BINARY)              {/* Nothing to do */}
1705     else if (oflags & MSVCRT__O_TEXT)           wxflags |= WX_TEXT;
1706     else if (oflags & MSVCRT__O_WTEXT)          wxflags |= WX_TEXT;
1707     else if (oflags & MSVCRT__O_U16TEXT)        wxflags |= WX_TEXT;
1708     else if (oflags & MSVCRT__O_U8TEXT)         wxflags |= WX_TEXT;
1709     else if (*__p__fmode() & MSVCRT__O_BINARY)  {/* Nothing to do */}
1710     else                                        wxflags |= WX_TEXT; /* default to TEXT*/
1711     if (oflags & MSVCRT__O_NOINHERIT)           wxflags |= WX_DONTINHERIT;
1712
1713     if ((unsupp = oflags & ~(
1714                     MSVCRT__O_BINARY|MSVCRT__O_TEXT|MSVCRT__O_APPEND|
1715                     MSVCRT__O_TRUNC|MSVCRT__O_EXCL|MSVCRT__O_CREAT|
1716                     MSVCRT__O_RDWR|MSVCRT__O_WRONLY|MSVCRT__O_TEMPORARY|
1717                     MSVCRT__O_NOINHERIT|
1718                     MSVCRT__O_SEQUENTIAL|MSVCRT__O_RANDOM|MSVCRT__O_SHORT_LIVED|
1719                     MSVCRT__O_WTEXT|MSVCRT__O_U16TEXT|MSVCRT__O_U8TEXT
1720                     )))
1721         ERR(":unsupported oflags 0x%04x\n",unsupp);
1722
1723     return wxflags;
1724 }
1725
1726 /*********************************************************************
1727  *              _pipe (MSVCRT.@)
1728  */
1729 int CDECL MSVCRT__pipe(int *pfds, unsigned int psize, int textmode)
1730 {
1731   int ret = -1;
1732   SECURITY_ATTRIBUTES sa;
1733   HANDLE readHandle, writeHandle;
1734
1735   if (!pfds)
1736   {
1737     *MSVCRT__errno() = MSVCRT_EINVAL;
1738     return -1;
1739   }
1740
1741   sa.nLength = sizeof(SECURITY_ATTRIBUTES);
1742   sa.bInheritHandle = !(textmode & MSVCRT__O_NOINHERIT);
1743   sa.lpSecurityDescriptor = NULL;
1744   if (CreatePipe(&readHandle, &writeHandle, &sa, psize))
1745   {
1746     unsigned int wxflags = split_oflags(textmode);
1747     int fd;
1748
1749     LOCK_FILES();
1750     fd = msvcrt_alloc_fd(readHandle, wxflags|WX_PIPE);
1751     if (fd != -1)
1752     {
1753       pfds[0] = fd;
1754       fd = msvcrt_alloc_fd(writeHandle, wxflags|WX_PIPE);
1755       if (fd != -1)
1756       {
1757         pfds[1] = fd;
1758         ret = 0;
1759       }
1760       else
1761       {
1762         MSVCRT__close(pfds[0]);
1763         CloseHandle(writeHandle);
1764         *MSVCRT__errno() = MSVCRT_EMFILE;
1765       }
1766     }
1767     else
1768     {
1769       CloseHandle(readHandle);
1770       CloseHandle(writeHandle);
1771       *MSVCRT__errno() = MSVCRT_EMFILE;
1772     }
1773     UNLOCK_FILES();
1774   }
1775   else
1776     msvcrt_set_errno(GetLastError());
1777
1778   return ret;
1779 }
1780
1781 static int check_bom(HANDLE h, int oflags, BOOL seek)
1782 {
1783     char bom[sizeof(utf8_bom)];
1784     DWORD r;
1785
1786     oflags &= ~(MSVCRT__O_WTEXT|MSVCRT__O_U16TEXT|MSVCRT__O_U8TEXT);
1787
1788     if (!ReadFile(h, bom, sizeof(utf8_bom), &r, NULL))
1789         return oflags;
1790
1791     if (r==sizeof(utf8_bom) && !memcmp(bom, utf8_bom, sizeof(utf8_bom))) {
1792         oflags |= MSVCRT__O_U8TEXT;
1793     }else if (r>=sizeof(utf16_bom) && !memcmp(bom, utf16_bom, sizeof(utf16_bom))) {
1794         if (seek && r>2)
1795             SetFilePointer(h, 2, NULL, FILE_BEGIN);
1796         oflags |= MSVCRT__O_U16TEXT;
1797     }else if (seek) {
1798         SetFilePointer(h, 0, NULL, FILE_BEGIN);
1799     }
1800
1801     return oflags;
1802 }
1803
1804 /*********************************************************************
1805  *              _wsopen_s (MSVCRT.@)
1806  */
1807 int CDECL MSVCRT__wsopen_s( int *fd, const MSVCRT_wchar_t* path, int oflags, int shflags, int pmode )
1808 {
1809   DWORD access = 0, creation = 0, attrib;
1810   SECURITY_ATTRIBUTES sa;
1811   DWORD sharing;
1812   int wxflag;
1813   HANDLE hand;
1814
1815   TRACE("fd*: %p :file (%s) oflags: 0x%04x shflags: 0x%04x pmode: 0x%04x\n",
1816         fd, debugstr_w(path), oflags, shflags, pmode);
1817
1818   if (!MSVCRT_CHECK_PMT( fd != NULL )) return MSVCRT_EINVAL;
1819
1820   *fd = -1;
1821   wxflag = split_oflags(oflags);
1822   switch (oflags & (MSVCRT__O_RDONLY | MSVCRT__O_WRONLY | MSVCRT__O_RDWR))
1823   {
1824   case MSVCRT__O_RDONLY: access |= GENERIC_READ; break;
1825   case MSVCRT__O_WRONLY: access |= GENERIC_WRITE; break;
1826   case MSVCRT__O_RDWR:   access |= GENERIC_WRITE | GENERIC_READ; break;
1827   }
1828
1829   if (oflags & MSVCRT__O_CREAT)
1830   {
1831     if(pmode & ~(MSVCRT__S_IREAD | MSVCRT__S_IWRITE))
1832       FIXME(": pmode 0x%04x ignored\n", pmode);
1833     else
1834       WARN(": pmode 0x%04x ignored\n", pmode);
1835
1836     if (oflags & MSVCRT__O_EXCL)
1837       creation = CREATE_NEW;
1838     else if (oflags & MSVCRT__O_TRUNC)
1839       creation = CREATE_ALWAYS;
1840     else
1841       creation = OPEN_ALWAYS;
1842   }
1843   else  /* no MSVCRT__O_CREAT */
1844   {
1845     if (oflags & MSVCRT__O_TRUNC)
1846       creation = TRUNCATE_EXISTING;
1847     else
1848       creation = OPEN_EXISTING;
1849   }
1850
1851   switch( shflags )
1852   {
1853     case MSVCRT__SH_DENYRW:
1854       sharing = 0L;
1855       break;
1856     case MSVCRT__SH_DENYWR:
1857       sharing = FILE_SHARE_READ;
1858       break;
1859     case MSVCRT__SH_DENYRD:
1860       sharing = FILE_SHARE_WRITE;
1861       break;
1862     case MSVCRT__SH_DENYNO:
1863       sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
1864       break;
1865     default:
1866       ERR( "Unhandled shflags 0x%x\n", shflags );
1867       return MSVCRT_EINVAL;
1868   }
1869   attrib = FILE_ATTRIBUTE_NORMAL;
1870
1871   if (oflags & MSVCRT__O_TEMPORARY)
1872   {
1873       attrib |= FILE_FLAG_DELETE_ON_CLOSE;
1874       access |= DELETE;
1875       sharing |= FILE_SHARE_DELETE;
1876   }
1877
1878   sa.nLength              = sizeof( SECURITY_ATTRIBUTES );
1879   sa.lpSecurityDescriptor = NULL;
1880   sa.bInheritHandle       = !(oflags & MSVCRT__O_NOINHERIT);
1881
1882   if ((oflags&(MSVCRT__O_WTEXT|MSVCRT__O_U16TEXT|MSVCRT__O_U8TEXT))
1883           && (creation==OPEN_ALWAYS || creation==OPEN_EXISTING)
1884           && !(access&GENERIC_READ))
1885   {
1886       hand = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
1887               &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
1888       if (hand != INVALID_HANDLE_VALUE)
1889       {
1890           oflags = check_bom(hand, oflags, FALSE);
1891           CloseHandle(hand);
1892       }
1893       else
1894           oflags &= ~(MSVCRT__O_WTEXT|MSVCRT__O_U16TEXT|MSVCRT__O_U8TEXT);
1895   }
1896
1897   hand = CreateFileW(path, access, sharing, &sa, creation, attrib, 0);
1898   if (hand == INVALID_HANDLE_VALUE)  {
1899     WARN(":failed-last error (%d)\n",GetLastError());
1900     msvcrt_set_errno(GetLastError());
1901     return *MSVCRT__errno();
1902   }
1903
1904   if (oflags & (MSVCRT__O_WTEXT|MSVCRT__O_U16TEXT|MSVCRT__O_U8TEXT))
1905   {
1906       if ((access & GENERIC_WRITE) && (creation==CREATE_NEW
1907                   || creation==CREATE_ALWAYS || creation==TRUNCATE_EXISTING
1908                   || (creation==OPEN_ALWAYS && GetLastError()==ERROR_ALREADY_EXISTS)))
1909       {
1910           if (oflags & MSVCRT__O_U8TEXT)
1911           {
1912               DWORD written = 0, tmp;
1913
1914               while(written!=sizeof(utf8_bom) && WriteFile(hand, (char*)utf8_bom+written,
1915                           sizeof(utf8_bom)-written, &tmp, NULL))
1916                   written += tmp;
1917               if (written != sizeof(utf8_bom)) {
1918                   WARN("error writing BOM\n");
1919                   CloseHandle(hand);
1920                   msvcrt_set_errno(GetLastError());
1921                   return *MSVCRT__errno();
1922               }
1923           }
1924           else
1925           {
1926               DWORD written = 0, tmp;
1927
1928               while(written!=sizeof(utf16_bom) && WriteFile(hand, (char*)utf16_bom+written,
1929                           sizeof(utf16_bom)-written, &tmp, NULL))
1930                   written += tmp;
1931               if (written != sizeof(utf16_bom))
1932               {
1933                   WARN("error writing BOM\n");
1934                   CloseHandle(hand);
1935                   msvcrt_set_errno(GetLastError());
1936                   return *MSVCRT__errno();
1937               }
1938           }
1939       }
1940       else if (access & GENERIC_READ)
1941           oflags = check_bom(hand, oflags, TRUE);
1942   }
1943
1944   *fd = msvcrt_alloc_fd(hand, wxflag);
1945   if (*fd == -1)
1946       return *MSVCRT__errno();
1947
1948   if (oflags & MSVCRT__O_WTEXT)
1949       msvcrt_get_ioinfo(*fd)->exflag |= EF_UTF16|EF_UNK_UNICODE;
1950   else if (oflags & MSVCRT__O_U16TEXT)
1951       msvcrt_get_ioinfo(*fd)->exflag |= EF_UTF16;
1952   else if (oflags & MSVCRT__O_U8TEXT)
1953       msvcrt_get_ioinfo(*fd)->exflag |= EF_UTF8;
1954
1955   TRACE(":fd (%d) handle (%p)\n", *fd, hand);
1956   return 0;
1957 }
1958
1959 /*********************************************************************
1960  *              _wsopen (MSVCRT.@)
1961  */
1962 int CDECL MSVCRT__wsopen( const MSVCRT_wchar_t *path, int oflags, int shflags, ... )
1963 {
1964   int pmode;
1965   int fd;
1966
1967   if (oflags & MSVCRT__O_CREAT)
1968   {
1969     __ms_va_list ap;
1970
1971     __ms_va_start(ap, shflags);
1972     pmode = va_arg(ap, int);
1973     __ms_va_end(ap);
1974   }
1975   else
1976     pmode = 0;
1977
1978   MSVCRT__wsopen_s(&fd, path, oflags, shflags, pmode);
1979   return fd;
1980 }
1981
1982 /*********************************************************************
1983  *              _sopen_s (MSVCRT.@)
1984  */
1985 int CDECL MSVCRT__sopen_s( int *fd, const char *path, int oflags, int shflags, int pmode )
1986 {
1987     MSVCRT_wchar_t *pathW;
1988     int ret;
1989
1990     if(!MSVCRT_CHECK_PMT(path && (pathW = msvcrt_wstrdupa(path))))
1991         return MSVCRT_EINVAL;
1992
1993     ret = MSVCRT__wsopen_s(fd, pathW, oflags, shflags, pmode);
1994     MSVCRT_free(pathW);
1995     return ret;
1996 }
1997
1998 /*********************************************************************
1999  *              _sopen (MSVCRT.@)
2000  */
2001 int CDECL MSVCRT__sopen( const char *path, int oflags, int shflags, ... )
2002 {
2003   int pmode;
2004   int fd;
2005
2006   if (oflags & MSVCRT__O_CREAT)
2007   {
2008     __ms_va_list ap;
2009
2010     __ms_va_start(ap, shflags);
2011     pmode = va_arg(ap, int);
2012     __ms_va_end(ap);
2013   }
2014   else
2015     pmode = 0;
2016
2017   MSVCRT__sopen_s(&fd, path, oflags, shflags, pmode);
2018   return fd;
2019 }
2020
2021 /*********************************************************************
2022  *              _open (MSVCRT.@)
2023  */
2024 int CDECL MSVCRT__open( const char *path, int flags, ... )
2025 {
2026   __ms_va_list ap;
2027
2028   if (flags & MSVCRT__O_CREAT)
2029   {
2030     int pmode;
2031     __ms_va_start(ap, flags);
2032     pmode = va_arg(ap, int);
2033     __ms_va_end(ap);
2034     return MSVCRT__sopen( path, flags, MSVCRT__SH_DENYNO, pmode );
2035   }
2036   else
2037     return MSVCRT__sopen( path, flags, MSVCRT__SH_DENYNO);
2038 }
2039
2040 /*********************************************************************
2041  *              _wopen (MSVCRT.@)
2042  */
2043 int CDECL MSVCRT__wopen(const MSVCRT_wchar_t *path,int flags,...)
2044 {
2045   __ms_va_list ap;
2046
2047   if (flags & MSVCRT__O_CREAT)
2048   {
2049     int pmode;
2050     __ms_va_start(ap, flags);
2051     pmode = va_arg(ap, int);
2052     __ms_va_end(ap);
2053     return MSVCRT__wsopen( path, flags, MSVCRT__SH_DENYNO, pmode );
2054   }
2055   else
2056     return MSVCRT__wsopen( path, flags, MSVCRT__SH_DENYNO);
2057 }
2058
2059 /*********************************************************************
2060  *              _creat (MSVCRT.@)
2061  */
2062 int CDECL MSVCRT__creat(const char *path, int flags)
2063 {
2064   int usedFlags = (flags & MSVCRT__O_TEXT)| MSVCRT__O_CREAT| MSVCRT__O_WRONLY| MSVCRT__O_TRUNC;
2065   return MSVCRT__open(path, usedFlags);
2066 }
2067
2068 /*********************************************************************
2069  *              _wcreat (MSVCRT.@)
2070  */
2071 int CDECL MSVCRT__wcreat(const MSVCRT_wchar_t *path, int flags)
2072 {
2073   int usedFlags = (flags & MSVCRT__O_TEXT)| MSVCRT__O_CREAT| MSVCRT__O_WRONLY| MSVCRT__O_TRUNC;
2074   return MSVCRT__wopen(path, usedFlags);
2075 }
2076
2077 /*********************************************************************
2078  *              _open_osfhandle (MSVCRT.@)
2079  */
2080 int CDECL MSVCRT__open_osfhandle(MSVCRT_intptr_t handle, int oflags)
2081 {
2082   int fd;
2083
2084   /* MSVCRT__O_RDONLY (0) always matches, so set the read flag
2085    * MFC's CStdioFile clears O_RDONLY (0)! if it wants to write to the
2086    * file, so set the write flag. It also only sets MSVCRT__O_TEXT if it wants
2087    * text - it never sets MSVCRT__O_BINARY.
2088    */
2089   /* don't let split_oflags() decide the mode if no mode is passed */
2090   if (!(oflags & (MSVCRT__O_BINARY | MSVCRT__O_TEXT)))
2091       oflags |= MSVCRT__O_BINARY;
2092
2093   fd = msvcrt_alloc_fd((HANDLE)handle, split_oflags(oflags));
2094   TRACE(":handle (%ld) fd (%d) flags 0x%08x\n", handle, fd, oflags);
2095   return fd;
2096 }
2097
2098 /*********************************************************************
2099  *              _rmtmp (MSVCRT.@)
2100  */
2101 int CDECL MSVCRT__rmtmp(void)
2102 {
2103   int num_removed = 0, i;
2104   MSVCRT_FILE *file;
2105
2106   LOCK_FILES();
2107   for (i = 3; i < MSVCRT_stream_idx; i++) {
2108     file = msvcrt_get_file(i);
2109
2110     if (file->_tmpfname)
2111     {
2112       MSVCRT_fclose(file);
2113       num_removed++;
2114     }
2115   }
2116   UNLOCK_FILES();
2117
2118   if (num_removed)
2119     TRACE(":removed (%d) temp files\n",num_removed);
2120   return num_removed;
2121 }
2122
2123 static inline int get_utf8_char_len(char ch)
2124 {
2125     if((ch&0xf8) == 0xf0)
2126         return 4;
2127     else if((ch&0xf0) == 0xe0)
2128         return 3;
2129     else if((ch&0xe0) == 0xc0)
2130         return 2;
2131     return 1;
2132 }
2133
2134 /*********************************************************************
2135  * (internal) read_utf8
2136  */
2137 static int read_utf8(int fd, MSVCRT_wchar_t *buf, unsigned int count)
2138 {
2139     ioinfo *fdinfo = msvcrt_get_ioinfo(fd);
2140     HANDLE hand = fdinfo->handle;
2141     char min_buf[4], *readbuf, lookahead;
2142     DWORD readbuf_size, pos=0, num_read=1, char_len, i, j;
2143
2144     /* make the buffer big enough to hold at least one character */
2145     /* read bytes have to fit to output and lookahead buffers */
2146     count /= 2;
2147     readbuf_size = count < 4 ? 4 : count;
2148     if(readbuf_size<=4 || !(readbuf = MSVCRT_malloc(readbuf_size))) {
2149         readbuf_size = 4;
2150         readbuf = min_buf;
2151     }
2152
2153     if(fdinfo->lookahead[0] != '\n') {
2154         readbuf[pos++] = fdinfo->lookahead[0];
2155         fdinfo->lookahead[0] = '\n';
2156
2157         if(fdinfo->lookahead[1] != '\n') {
2158             readbuf[pos++] = fdinfo->lookahead[1];
2159             fdinfo->lookahead[1] = '\n';
2160
2161             if(fdinfo->lookahead[2] != '\n') {
2162                 readbuf[pos++] = fdinfo->lookahead[2];
2163                 fdinfo->lookahead[2] = '\n';
2164             }
2165         }
2166     }
2167
2168     /* NOTE: this case is broken in native dll, reading
2169      *        sometimes fails when small buffer is passed
2170      */
2171     if(count < 4) {
2172         if(!pos && !ReadFile(hand, readbuf, 1, &num_read, NULL)) {
2173             if (GetLastError() == ERROR_BROKEN_PIPE) {
2174                 fdinfo->wxflag |= WX_ATEOF;
2175                 return 0;
2176             }else {
2177                 msvcrt_set_errno(GetLastError());
2178                 return -1;
2179             }
2180         }else if(!num_read) {
2181             fdinfo->wxflag |= WX_ATEOF;
2182             return 0;
2183         }else {
2184             pos++;
2185         }
2186
2187         char_len = get_utf8_char_len(readbuf[0]);
2188         if(char_len>pos) {
2189             if(ReadFile(hand, readbuf+pos, char_len-pos, &num_read, NULL))
2190                 pos += num_read;
2191         }
2192
2193         if(readbuf[0] == '\n')
2194             fdinfo->wxflag |= WX_READNL;
2195         else
2196             fdinfo->wxflag &= ~WX_READNL;
2197
2198         if(readbuf[0] == 0x1a) {
2199             fdinfo->wxflag |= WX_ATEOF;
2200             return 0;
2201         }
2202
2203         if(readbuf[0] == '\r') {
2204             if(!ReadFile(hand, &lookahead, 1, &num_read, NULL) || num_read!=1)
2205                 buf[0] = '\r';
2206             else if(lookahead == '\n')
2207                 buf[0] = '\n';
2208             else {
2209                 buf[0] = '\r';
2210                 if(fdinfo->wxflag & WX_PIPE)
2211                     fdinfo->lookahead[0] = lookahead;
2212                 else
2213                     SetFilePointer(fdinfo->handle, -1, NULL, FILE_CURRENT);
2214             }
2215             return 2;
2216         }
2217
2218         if(!(num_read = MultiByteToWideChar(CP_UTF8, 0, readbuf, pos, buf, count))) {
2219             msvcrt_set_errno(GetLastError());
2220             return -1;
2221         }
2222
2223         return num_read*2;
2224     }
2225
2226     if(!ReadFile(hand, readbuf+pos, readbuf_size-pos, &num_read, NULL)) {
2227         if(pos) {
2228             num_read = 0;
2229         }else if(GetLastError() == ERROR_BROKEN_PIPE) {
2230             fdinfo->wxflag |= WX_ATEOF;
2231             if (readbuf != min_buf) MSVCRT_free(readbuf);
2232             return 0;
2233         }else {
2234             msvcrt_set_errno(GetLastError());
2235             if (readbuf != min_buf) MSVCRT_free(readbuf);
2236             return -1;
2237         }
2238     }else if(!pos && !num_read) {
2239         fdinfo->wxflag |= WX_ATEOF;
2240         if (readbuf != min_buf) MSVCRT_free(readbuf);
2241         return 0;
2242     }
2243
2244     pos += num_read;
2245     if(readbuf[0] == '\n')
2246         fdinfo->wxflag |= WX_READNL;
2247     else
2248         fdinfo->wxflag &= ~WX_READNL;
2249
2250     /* Find first byte of last character (may be incomplete) */
2251     for(i=pos-1; i>0 && i>pos-4; i--)
2252         if((readbuf[i]&0xc0) != 0x80)
2253             break;
2254     char_len = get_utf8_char_len(readbuf[i]);
2255     if(char_len+i <= pos)
2256         i += char_len;
2257
2258     if(fdinfo->wxflag & WX_PIPE) {
2259         if(i < pos)
2260             fdinfo->lookahead[0] = readbuf[i];
2261         if(i+1 < pos)
2262             fdinfo->lookahead[1] = readbuf[i+1];
2263         if(i+2 < pos)
2264             fdinfo->lookahead[2] = readbuf[i+2];
2265     }else if(i < pos) {
2266         SetFilePointer(fdinfo->handle, i-pos, NULL, FILE_CURRENT);
2267     }
2268     pos = i;
2269
2270     for(i=0, j=0; i<pos; i++) {
2271         if(readbuf[i] == 0x1a) {
2272             fdinfo->wxflag |= WX_ATEOF;
2273             break;
2274         }
2275
2276         /* strip '\r' if followed by '\n' */
2277         if(readbuf[i] == '\r' && i+1==pos) {
2278             if(fdinfo->lookahead[0] != '\n' || !ReadFile(hand, &lookahead, 1, &num_read, NULL) || !num_read) {
2279                 readbuf[j++] = '\r';
2280             }else if(lookahead == '\n' && j==0) {
2281                 readbuf[j++] = '\n';
2282             }else {
2283                 if(lookahead != '\n')
2284                     readbuf[j++] = '\r';
2285
2286                 if(fdinfo->wxflag & WX_PIPE)
2287                     fdinfo->lookahead[0] = lookahead;
2288                 else
2289                     SetFilePointer(fdinfo->handle, -1, NULL, FILE_CURRENT);
2290             }
2291         }else if(readbuf[i]!='\r' || readbuf[i+1]!='\n') {
2292             readbuf[j++] = readbuf[i];
2293         }
2294     }
2295     pos = j;
2296
2297     if(!(num_read = MultiByteToWideChar(CP_UTF8, 0, readbuf, pos, buf, count))) {
2298         msvcrt_set_errno(GetLastError());
2299         if (readbuf != min_buf) MSVCRT_free(readbuf);
2300         return -1;
2301     }
2302
2303     if (readbuf != min_buf) MSVCRT_free(readbuf);
2304     return num_read*2;
2305 }
2306
2307 /*********************************************************************
2308  * (internal) read_i
2309  *
2310  * When reading \r as last character in text mode, read() positions
2311  * the file pointer on the \r character while getc() goes on to
2312  * the following \n
2313  */
2314 static int read_i(int fd, void *buf, unsigned int count)
2315 {
2316     DWORD num_read, utf16;
2317     char *bufstart = buf;
2318     HANDLE hand = msvcrt_fdtoh(fd);
2319     ioinfo *fdinfo = msvcrt_get_ioinfo(fd);
2320
2321     if (count == 0)
2322         return 0;
2323
2324     if (fdinfo->wxflag & WX_ATEOF) {
2325         TRACE("already at EOF, returning 0\n");
2326         return 0;
2327     }
2328     /* Don't trace small reads, it gets *very* annoying */
2329     if (count > 4)
2330         TRACE(":fd (%d) handle (%p) buf (%p) len (%d)\n",fd,hand,buf,count);
2331     if (hand == INVALID_HANDLE_VALUE)
2332     {
2333         *MSVCRT__errno() = MSVCRT_EBADF;
2334         return -1;
2335     }
2336
2337     utf16 = (fdinfo->exflag & EF_UTF16) != 0;
2338     if (((fdinfo->exflag&EF_UTF8) || utf16) && count&1)
2339     {
2340         *MSVCRT__errno() = MSVCRT_EINVAL;
2341         return -1;
2342     }
2343
2344     if((fdinfo->wxflag&WX_TEXT) && (fdinfo->exflag&EF_UTF8))
2345         return read_utf8(fd, buf, count);
2346
2347     if (fdinfo->lookahead[0]!='\n' || ReadFile(hand, bufstart, count, &num_read, NULL))
2348     {
2349         if (fdinfo->lookahead[0] != '\n')
2350         {
2351             bufstart[0] = fdinfo->lookahead[0];
2352             fdinfo->lookahead[0] = '\n';
2353
2354             if (utf16)
2355             {
2356                 bufstart[1] =  fdinfo->lookahead[1];
2357                 fdinfo->lookahead[1] = '\n';
2358             }
2359
2360             if(count>1+utf16 && ReadFile(hand, bufstart+1+utf16, count-1-utf16, &num_read, NULL))
2361                 num_read += 1+utf16;
2362             else
2363                 num_read = 1+utf16;
2364         }
2365
2366         if(utf16 && (num_read&1))
2367         {
2368             /* msvcr90 uses uninitialized value from the buffer in this case */
2369             /* msvcrt ignores additional data */
2370             ERR("got odd number of bytes in UTF16 mode\n");
2371             num_read--;
2372         }
2373
2374         if (count != 0 && num_read == 0)
2375         {
2376             fdinfo->wxflag |= WX_ATEOF;
2377             TRACE(":EOF %s\n",debugstr_an(buf,num_read));
2378         }
2379         else if (fdinfo->wxflag & WX_TEXT)
2380         {
2381             DWORD i, j;
2382
2383             if (bufstart[0]=='\n' && (!utf16 || bufstart[1]==0))
2384                 fdinfo->wxflag |= WX_READNL;
2385             else
2386                 fdinfo->wxflag &= ~WX_READNL;
2387
2388             for (i=0, j=0; i<num_read; i+=1+utf16)
2389             {
2390                 /* in text mode, a ctrl-z signals EOF */
2391                 if (bufstart[i]==0x1a && (!utf16 || bufstart[i+1]==0))
2392                 {
2393                     fdinfo->wxflag |= WX_ATEOF;
2394                     TRACE(":^Z EOF %s\n",debugstr_an(buf,num_read));
2395                     break;
2396                 }
2397
2398                 /* in text mode, strip \r if followed by \n */
2399                 if (bufstart[i]=='\r' && (!utf16 || bufstart[i+1]==0) && i+1+utf16==num_read)
2400                 {
2401                     char lookahead[2];
2402                     DWORD len;
2403
2404                     lookahead[1] = '\n';
2405                     if (ReadFile(hand, lookahead, 1+utf16, &len, NULL) && len)
2406                     {
2407                         if(lookahead[0]=='\n' && (!utf16 || lookahead[1]==0) && j==0)
2408                         {
2409                             bufstart[j++] = '\n';
2410                             if(utf16) bufstart[j++] = 0;
2411                         }
2412                         else
2413                         {
2414                             if(lookahead[0]!='\n' || (utf16 && lookahead[1]!=0))
2415                             {
2416                                 bufstart[j++] = '\r';
2417                                 if(utf16) bufstart[j++] = 0;
2418                             }
2419
2420                             if (fdinfo->wxflag & WX_PIPE)
2421                             {
2422                                 fdinfo->lookahead[0] = lookahead[0];
2423                                 fdinfo->lookahead[1] = lookahead[1];
2424                             }
2425                             else
2426                                 SetFilePointer(fdinfo->handle, -1-utf16, NULL, FILE_CURRENT);
2427                         }
2428                     }
2429                     else
2430                     {
2431                         bufstart[j++] = '\r';
2432                         if(utf16) bufstart[j++] = 0;
2433                     }
2434                 }
2435                 else if((bufstart[i]!='\r' || (utf16 && bufstart[i+1]!=0))
2436                         || (bufstart[i+1+utf16]!='\n' || (utf16 && bufstart[i+3]!=0)))
2437                 {
2438                     bufstart[j++] = bufstart[i];
2439                     if(utf16) bufstart[j++] = bufstart[i+1];
2440                 }
2441             }
2442             num_read = j;
2443         }
2444     }
2445     else
2446     {
2447         if (GetLastError() == ERROR_BROKEN_PIPE)
2448         {
2449             TRACE(":end-of-pipe\n");
2450             fdinfo->wxflag |= WX_ATEOF;
2451             return 0;
2452         }
2453         else
2454         {
2455             TRACE(":failed-last error (%d)\n",GetLastError());
2456             return -1;
2457         }
2458     }
2459
2460     if (count > 4)
2461         TRACE("(%u), %s\n",num_read,debugstr_an(buf, num_read));
2462     return num_read;
2463 }
2464
2465 /*********************************************************************
2466  *              _read (MSVCRT.@)
2467  */
2468 int CDECL MSVCRT__read(int fd, void *buf, unsigned int count)
2469 {
2470   int num_read;
2471   num_read = read_i(fd, buf, count);
2472   return num_read;
2473 }
2474
2475 /*********************************************************************
2476  *              _setmode (MSVCRT.@)
2477  */
2478 int CDECL MSVCRT__setmode(int fd,int mode)
2479 {
2480     int ret = msvcrt_get_ioinfo(fd)->wxflag & WX_TEXT ? MSVCRT__O_TEXT : MSVCRT__O_BINARY;
2481     if(ret==MSVCRT__O_TEXT && (msvcrt_get_ioinfo(fd)->exflag & (EF_UTF8|EF_UTF16)))
2482         ret = MSVCRT__O_WTEXT;
2483
2484     if(mode!=MSVCRT__O_TEXT && mode!=MSVCRT__O_BINARY && mode!=MSVCRT__O_WTEXT
2485                 && mode!=MSVCRT__O_U16TEXT && mode!=MSVCRT__O_U8TEXT) {
2486         *MSVCRT__errno() = MSVCRT_EINVAL;
2487         return -1;
2488     }
2489
2490     if(mode == MSVCRT__O_BINARY) {
2491         msvcrt_get_ioinfo(fd)->wxflag &= ~WX_TEXT;
2492         msvcrt_get_ioinfo(fd)->exflag &= ~(EF_UTF8|EF_UTF16);
2493         return ret;
2494     }
2495
2496     msvcrt_get_ioinfo(fd)->wxflag |= WX_TEXT;
2497     if(mode == MSVCRT__O_TEXT)
2498         msvcrt_get_ioinfo(fd)->exflag &= ~(EF_UTF8|EF_UTF16);
2499     else if(mode == MSVCRT__O_U8TEXT)
2500         msvcrt_get_ioinfo(fd)->exflag = (msvcrt_get_ioinfo(fd)->exflag & ~EF_UTF16) | EF_UTF8;
2501     else
2502         msvcrt_get_ioinfo(fd)->exflag = (msvcrt_get_ioinfo(fd)->exflag & ~EF_UTF8) | EF_UTF16;
2503
2504     return ret;
2505 }
2506
2507 /*********************************************************************
2508  *              _stat64 (MSVCRT.@)
2509  */
2510 int CDECL MSVCRT_stat64(const char* path, struct MSVCRT__stat64 * buf)
2511 {
2512   DWORD dw;
2513   WIN32_FILE_ATTRIBUTE_DATA hfi;
2514   unsigned short mode = ALL_S_IREAD;
2515   int plen;
2516
2517   TRACE(":file (%s) buf(%p)\n",path,buf);
2518
2519   plen = strlen(path);
2520   while (plen && path[plen-1]==' ')
2521     plen--;
2522
2523   if (plen && (path[plen-1]=='\\' || path[plen-1]=='/'))
2524   {
2525     *MSVCRT__errno() = MSVCRT_ENOENT;
2526     return -1;
2527   }
2528
2529   if (!GetFileAttributesExA(path, GetFileExInfoStandard, &hfi))
2530   {
2531       TRACE("failed (%d)\n",GetLastError());
2532       *MSVCRT__errno() = MSVCRT_ENOENT;
2533       return -1;
2534   }
2535
2536   memset(buf,0,sizeof(struct MSVCRT__stat64));
2537
2538   /* FIXME: rdev isn't drive num, despite what the docs say-what is it?
2539      Bon 011120: This FIXME seems incorrect
2540                  Also a letter as first char isn't enough to be classified
2541                  as a drive letter
2542   */
2543   if (isalpha(*path)&& (*(path+1)==':'))
2544     buf->st_dev = buf->st_rdev = toupper(*path) - 'A'; /* drive num */
2545   else
2546     buf->st_dev = buf->st_rdev = MSVCRT__getdrive() - 1;
2547
2548   /* Dir, or regular file? */
2549   if (hfi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2550     mode |= (MSVCRT__S_IFDIR | ALL_S_IEXEC);
2551   else
2552   {
2553     mode |= MSVCRT__S_IFREG;
2554     /* executable? */
2555     if (plen > 6 && path[plen-4] == '.')  /* shortest exe: "\x.exe" */
2556     {
2557       unsigned int ext = tolower(path[plen-1]) | (tolower(path[plen-2]) << 8) |
2558                                  (tolower(path[plen-3]) << 16);
2559       if (ext == EXE || ext == BAT || ext == CMD || ext == COM)
2560           mode |= ALL_S_IEXEC;
2561     }
2562   }
2563
2564   if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
2565     mode |= ALL_S_IWRITE;
2566
2567   buf->st_mode  = mode;
2568   buf->st_nlink = 1;
2569   buf->st_size  = ((__int64)hfi.nFileSizeHigh << 32) + hfi.nFileSizeLow;
2570   RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastAccessTime, &dw);
2571   buf->st_atime = dw;
2572   RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastWriteTime, &dw);
2573   buf->st_mtime = buf->st_ctime = dw;
2574   TRACE("%d %d 0x%08x%08x %d %d %d\n", buf->st_mode,buf->st_nlink,
2575         (int)(buf->st_size >> 32),(int)buf->st_size,
2576         (int)buf->st_atime,(int)buf->st_mtime,(int)buf->st_ctime);
2577   return 0;
2578 }
2579
2580 /*********************************************************************
2581  *              _stati64 (MSVCRT.@)
2582  */
2583 int CDECL MSVCRT_stati64(const char* path, struct MSVCRT__stati64 * buf)
2584 {
2585   int ret;
2586   struct MSVCRT__stat64 buf64;
2587
2588   ret = MSVCRT_stat64(path, &buf64);
2589   if (!ret)
2590     msvcrt_stat64_to_stati64(&buf64, buf);
2591   return ret;
2592 }
2593
2594 /*********************************************************************
2595  *              _stat (MSVCRT.@)
2596  */
2597 int CDECL MSVCRT_stat(const char* path, struct MSVCRT__stat * buf)
2598 { int ret;
2599   struct MSVCRT__stat64 buf64;
2600
2601   ret = MSVCRT_stat64( path, &buf64);
2602   if (!ret)
2603       msvcrt_stat64_to_stat(&buf64, buf);
2604   return ret;
2605 }
2606
2607 /*********************************************************************
2608  *              _wstat64 (MSVCRT.@)
2609  */
2610 int CDECL MSVCRT__wstat64(const MSVCRT_wchar_t* path, struct MSVCRT__stat64 * buf)
2611 {
2612   DWORD dw;
2613   WIN32_FILE_ATTRIBUTE_DATA hfi;
2614   unsigned short mode = ALL_S_IREAD;
2615   int plen;
2616
2617   TRACE(":file (%s) buf(%p)\n",debugstr_w(path),buf);
2618
2619   plen = strlenW(path);
2620   while (plen && path[plen-1]==' ')
2621     plen--;
2622
2623   if(plen && (path[plen-1]=='\\' || path[plen-1]=='/'))
2624   {
2625     *MSVCRT__errno() = MSVCRT_ENOENT;
2626     return -1;
2627   }
2628
2629   if (!GetFileAttributesExW(path, GetFileExInfoStandard, &hfi))
2630   {
2631       TRACE("failed (%d)\n",GetLastError());
2632       *MSVCRT__errno() = MSVCRT_ENOENT;
2633       return -1;
2634   }
2635
2636   memset(buf,0,sizeof(struct MSVCRT__stat64));
2637
2638   /* FIXME: rdev isn't drive num, despite what the docs says-what is it? */
2639   if (MSVCRT_iswalpha(*path))
2640     buf->st_dev = buf->st_rdev = toupperW(*path - 'A'); /* drive num */
2641   else
2642     buf->st_dev = buf->st_rdev = MSVCRT__getdrive() - 1;
2643
2644   /* Dir, or regular file? */
2645   if (hfi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
2646     mode |= (MSVCRT__S_IFDIR | ALL_S_IEXEC);
2647   else
2648   {
2649     mode |= MSVCRT__S_IFREG;
2650     /* executable? */
2651     if (plen > 6 && path[plen-4] == '.')  /* shortest exe: "\x.exe" */
2652     {
2653       ULONGLONG ext = tolowerW(path[plen-1]) | (tolowerW(path[plen-2]) << 16) |
2654                                ((ULONGLONG)tolowerW(path[plen-3]) << 32);
2655       if (ext == WCEXE || ext == WCBAT || ext == WCCMD || ext == WCCOM)
2656         mode |= ALL_S_IEXEC;
2657     }
2658   }
2659
2660   if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
2661     mode |= ALL_S_IWRITE;
2662
2663   buf->st_mode  = mode;
2664   buf->st_nlink = 1;
2665   buf->st_size  = ((__int64)hfi.nFileSizeHigh << 32) + hfi.nFileSizeLow;
2666   RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastAccessTime, &dw);
2667   buf->st_atime = dw;
2668   RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastWriteTime, &dw);
2669   buf->st_mtime = buf->st_ctime = dw;
2670   TRACE("%d %d 0x%08x%08x %d %d %d\n", buf->st_mode,buf->st_nlink,
2671         (int)(buf->st_size >> 32),(int)buf->st_size,
2672         (int)buf->st_atime,(int)buf->st_mtime,(int)buf->st_ctime);
2673   return 0;
2674 }
2675
2676 /*********************************************************************
2677  *              _wstati64 (MSVCRT.@)
2678  */
2679 int CDECL MSVCRT__wstati64(const MSVCRT_wchar_t* path, struct MSVCRT__stati64 * buf)
2680 {
2681   int ret;
2682   struct MSVCRT__stat64 buf64;
2683
2684   ret = MSVCRT__wstat64(path, &buf64);
2685   if (!ret)
2686     msvcrt_stat64_to_stati64(&buf64, buf);
2687   return ret;
2688 }
2689
2690 /*********************************************************************
2691  *              _wstat (MSVCRT.@)
2692  */
2693 int CDECL MSVCRT__wstat(const MSVCRT_wchar_t* path, struct MSVCRT__stat * buf)
2694 {
2695   int ret;
2696   struct MSVCRT__stat64 buf64;
2697
2698   ret = MSVCRT__wstat64( path, &buf64 );
2699   if (!ret) msvcrt_stat64_to_stat(&buf64, buf);
2700   return ret;
2701 }
2702
2703 /*********************************************************************
2704  *              _tell (MSVCRT.@)
2705  */
2706 MSVCRT_long CDECL MSVCRT__tell(int fd)
2707 {
2708   return MSVCRT__lseek(fd, 0, SEEK_CUR);
2709 }
2710
2711 /*********************************************************************
2712  *              _telli64 (MSVCRT.@)
2713  */
2714 __int64 CDECL _telli64(int fd)
2715 {
2716   return MSVCRT__lseeki64(fd, 0, SEEK_CUR);
2717 }
2718
2719 /*********************************************************************
2720  *              _tempnam (MSVCRT.@)
2721  */
2722 char * CDECL MSVCRT__tempnam(const char *dir, const char *prefix)
2723 {
2724   char tmpbuf[MAX_PATH];
2725   const char *tmp_dir = MSVCRT_getenv("TMP");
2726
2727   if (tmp_dir) dir = tmp_dir;
2728
2729   TRACE("dir (%s) prefix (%s)\n",dir,prefix);
2730   if (GetTempFileNameA(dir,prefix,0,tmpbuf))
2731   {
2732     TRACE("got name (%s)\n",tmpbuf);
2733     DeleteFileA(tmpbuf);
2734     return MSVCRT__strdup(tmpbuf);
2735   }
2736   TRACE("failed (%d)\n",GetLastError());
2737   return NULL;
2738 }
2739
2740 /*********************************************************************
2741  *              _wtempnam (MSVCRT.@)
2742  */
2743 MSVCRT_wchar_t * CDECL MSVCRT__wtempnam(const MSVCRT_wchar_t *dir, const MSVCRT_wchar_t *prefix)
2744 {
2745   static const MSVCRT_wchar_t tmpW[] = {'T','M','P',0};
2746   MSVCRT_wchar_t tmpbuf[MAX_PATH];
2747   const MSVCRT_wchar_t *tmp_dir = MSVCRT__wgetenv(tmpW);
2748
2749   if (tmp_dir) dir = tmp_dir;
2750
2751   TRACE("dir (%s) prefix (%s)\n",debugstr_w(dir),debugstr_w(prefix));
2752   if (GetTempFileNameW(dir,prefix,0,tmpbuf))
2753   {
2754     TRACE("got name (%s)\n",debugstr_w(tmpbuf));
2755     DeleteFileW(tmpbuf);
2756     return MSVCRT__wcsdup(tmpbuf);
2757   }
2758   TRACE("failed (%d)\n",GetLastError());
2759   return NULL;
2760 }
2761
2762 /*********************************************************************
2763  *              _umask (MSVCRT.@)
2764  */
2765 int CDECL MSVCRT__umask(int umask)
2766 {
2767   int old_umask = MSVCRT_umask;
2768   TRACE("(%d)\n",umask);
2769   MSVCRT_umask = umask;
2770   return old_umask;
2771 }
2772
2773 /*********************************************************************
2774  *              _utime64 (MSVCRT.@)
2775  */
2776 int CDECL _utime64(const char* path, struct MSVCRT___utimbuf64 *t)
2777 {
2778   int fd = MSVCRT__open(path, MSVCRT__O_WRONLY | MSVCRT__O_BINARY);
2779
2780   if (fd > 0)
2781   {
2782     int retVal = _futime64(fd, t);
2783     MSVCRT__close(fd);
2784     return retVal;
2785   }
2786   return -1;
2787 }
2788
2789 /*********************************************************************
2790  *              _utime32 (MSVCRT.@)
2791  */
2792 int CDECL _utime32(const char* path, struct MSVCRT___utimbuf32 *t)
2793 {
2794     if (t)
2795     {
2796         struct MSVCRT___utimbuf64 t64;
2797         t64.actime = t->actime;
2798         t64.modtime = t->modtime;
2799         return _utime64( path, &t64 );
2800     }
2801     else
2802         return _utime64( path, NULL );
2803 }
2804
2805 /*********************************************************************
2806  *              _utime (MSVCRT.@)
2807  */
2808 #ifdef _WIN64
2809 int CDECL _utime(const char* path, struct MSVCRT___utimbuf64 *t)
2810 {
2811     return _utime64( path, t );
2812 }
2813 #else
2814 int CDECL _utime(const char* path, struct MSVCRT___utimbuf32 *t)
2815 {
2816     return _utime32( path, t );
2817 }
2818 #endif
2819
2820 /*********************************************************************
2821  *              _wutime64 (MSVCRT.@)
2822  */
2823 int CDECL _wutime64(const MSVCRT_wchar_t* path, struct MSVCRT___utimbuf64 *t)
2824 {
2825   int fd = MSVCRT__wopen(path, MSVCRT__O_WRONLY | MSVCRT__O_BINARY);
2826
2827   if (fd > 0)
2828   {
2829     int retVal = _futime64(fd, t);
2830     MSVCRT__close(fd);
2831     return retVal;
2832   }
2833   return -1;
2834 }
2835
2836 /*********************************************************************
2837  *              _wutime32 (MSVCRT.@)
2838  */
2839 int CDECL _wutime32(const MSVCRT_wchar_t* path, struct MSVCRT___utimbuf32 *t)
2840 {
2841     if (t)
2842     {
2843         struct MSVCRT___utimbuf64 t64;
2844         t64.actime = t->actime;
2845         t64.modtime = t->modtime;
2846         return _wutime64( path, &t64 );
2847     }
2848     else
2849         return _wutime64( path, NULL );
2850 }
2851
2852 /*********************************************************************
2853  *              _wutime (MSVCRT.@)
2854  */
2855 #ifdef _WIN64
2856 int CDECL _wutime(const MSVCRT_wchar_t* path, struct MSVCRT___utimbuf64 *t)
2857 {
2858     return _wutime64( path, t );
2859 }
2860 #else
2861 int CDECL _wutime(const MSVCRT_wchar_t* path, struct MSVCRT___utimbuf32 *t)
2862 {
2863     return _wutime32( path, t );
2864 }
2865 #endif
2866
2867 /*********************************************************************
2868  *              _write (MSVCRT.@)
2869  */
2870 int CDECL MSVCRT__write(int fd, const void* buf, unsigned int count)
2871 {
2872     DWORD num_written;
2873     ioinfo *info = msvcrt_get_ioinfo(fd);
2874     HANDLE hand = info->handle;
2875
2876     /* Don't trace small writes, it gets *very* annoying */
2877 #if 0
2878     if (count > 32)
2879         TRACE(":fd (%d) handle (%d) buf (%p) len (%d)\n",fd,hand,buf,count);
2880 #endif
2881     if (hand == INVALID_HANDLE_VALUE)
2882     {
2883         *MSVCRT__errno() = MSVCRT_EBADF;
2884         return -1;
2885     }
2886
2887     if (((info->exflag&EF_UTF8) || (info->exflag&EF_UTF16)) && count&1)
2888     {
2889         *MSVCRT__errno() = MSVCRT_EINVAL;
2890         return -1;
2891     }
2892
2893     /* If appending, go to EOF */
2894     if (info->wxflag & WX_APPEND)
2895         MSVCRT__lseek(fd, 0, FILE_END);
2896
2897     if (!(info->wxflag & WX_TEXT))
2898     {
2899         if (WriteFile(hand, buf, count, &num_written, NULL)
2900                 &&  (num_written == count))
2901             return num_written;
2902         TRACE("WriteFile (fd %d, hand %p) failed-last error (%d)\n", fd,
2903                 hand, GetLastError());
2904         *MSVCRT__errno() = MSVCRT_ENOSPC;
2905     }
2906     else
2907     {
2908         unsigned int i, j, nr_lf, size;
2909         char *p = NULL;
2910         const char *q;
2911         const char *s = buf, *buf_start = buf;
2912
2913         if (!(info->exflag & (EF_UTF8|EF_UTF16)))
2914         {
2915             /* find number of \n */
2916             for (nr_lf=0, i=0; i<count; i++)
2917                 if (s[i] == '\n')
2918                     nr_lf++;
2919             if (nr_lf)
2920             {
2921                 size = count+nr_lf;
2922                 if ((q = p = MSVCRT_malloc(size)))
2923                 {
2924                     for (s = buf, i = 0, j = 0; i < count; i++)
2925                     {
2926                         if (s[i] == '\n')
2927                             p[j++] = '\r';
2928                         p[j++] = s[i];
2929                     }
2930                 }
2931                 else
2932                 {
2933                     FIXME("Malloc failed\n");
2934                     nr_lf = 0;
2935                     size = count;
2936                     q = buf;
2937                 }
2938             }
2939             else
2940             {
2941                 size = count;
2942                 q = buf;
2943             }
2944         }
2945         else if (info->exflag & EF_UTF16)
2946         {
2947             for (nr_lf=0, i=0; i<count; i+=2)
2948                 if (s[i]=='\n' && s[i+1]==0)
2949                     nr_lf += 2;
2950             if (nr_lf)
2951             {
2952                 size = count+nr_lf;
2953                 if ((q = p = MSVCRT_malloc(size)))
2954                 {
2955                     for (s=buf, i=0, j=0; i<count; i++)
2956                     {
2957                         if (s[i]=='\n' && s[i+1]==0)
2958                         {
2959                             p[j++] = '\r';
2960                             p[j++] = 0;
2961                         }
2962                         p[j++] = s[i++];
2963                         p[j++] = s[i];
2964                     }
2965                 }
2966                 else
2967                 {
2968                     FIXME("Malloc failed\n");
2969                     nr_lf = 0;
2970                     size = count;
2971                     q = buf;
2972                 }
2973             }
2974             else
2975             {
2976                 size = count;
2977                 q = buf;
2978             }
2979         }
2980         else
2981         {
2982             DWORD conv_len;
2983
2984             for(nr_lf=0, i=0; i<count; i+=2)
2985                 if (s[i]=='\n' && s[i+1]==0)
2986                     nr_lf++;
2987
2988             conv_len = WideCharToMultiByte(CP_UTF8, 0, (WCHAR*)buf, count/2, NULL, 0, NULL, NULL);
2989             if(!conv_len) {
2990                 msvcrt_set_errno(GetLastError());
2991                 MSVCRT_free(p);
2992                 return -1;
2993             }
2994
2995             size = conv_len+nr_lf;
2996             if((p = MSVCRT_malloc(count+nr_lf*2+size)))
2997             {
2998                 for (s=buf, i=0, j=0; i<count; i++)
2999                 {
3000                     if (s[i]=='\n' && s[i+1]==0)
3001                     {
3002                         p[j++] = '\r';
3003                         p[j++] = 0;
3004                     }
3005                     p[j++] = s[i++];
3006                     p[j++] = s[i];
3007                 }
3008                 q = p+count+nr_lf*2;
3009                 WideCharToMultiByte(CP_UTF8, 0, (WCHAR*)p, count/2+nr_lf,
3010                         p+count+nr_lf*2, conv_len+nr_lf, NULL, NULL);
3011             }
3012             else
3013             {
3014                 FIXME("Malloc failed\n");
3015                 nr_lf = 0;
3016                 size = count;
3017                 q = buf;
3018             }
3019         }
3020
3021         if (!WriteFile(hand, q, size, &num_written, NULL))
3022             num_written = -1;
3023         if(p)
3024             MSVCRT_free(p);
3025         if (num_written != size)
3026         {
3027             TRACE("WriteFile (fd %d, hand %p) failed-last error (%d), num_written %d\n",
3028                     fd, hand, GetLastError(), num_written);
3029             *MSVCRT__errno() = MSVCRT_ENOSPC;
3030             return s - buf_start;
3031         }
3032         return count;
3033     }
3034
3035     return -1;
3036 }
3037
3038 /*********************************************************************
3039  *              _putw (MSVCRT.@)
3040  */
3041 int CDECL MSVCRT__putw(int val, MSVCRT_FILE* file)
3042 {
3043   int len;
3044
3045   MSVCRT__lock_file(file);
3046   len = MSVCRT__write(file->_file, &val, sizeof(val));
3047   if (len == sizeof(val)) {
3048     MSVCRT__unlock_file(file);
3049     return val;
3050   }
3051
3052   file->_flag |= MSVCRT__IOERR;
3053   MSVCRT__unlock_file(file);
3054   return MSVCRT_EOF;
3055 }
3056
3057 /*********************************************************************
3058  *              fclose (MSVCRT.@)
3059  */
3060 int CDECL MSVCRT_fclose(MSVCRT_FILE* file)
3061 {
3062   int r, flag;
3063
3064   MSVCRT__lock_file(file);
3065   flag = file->_flag;
3066   MSVCRT_free(file->_tmpfname);
3067   file->_tmpfname = NULL;
3068   /* flush stdio buffers */
3069   if(file->_flag & MSVCRT__IOWRT)
3070       MSVCRT_fflush(file);
3071   if(file->_flag & MSVCRT__IOMYBUF)
3072       MSVCRT_free(file->_base);
3073
3074   r=MSVCRT__close(file->_file);
3075
3076   file->_flag = 0;
3077   MSVCRT__unlock_file(file);
3078
3079   return ((r == -1) || (flag & MSVCRT__IOERR) ? MSVCRT_EOF : 0);
3080 }
3081
3082 /*********************************************************************
3083  *              feof (MSVCRT.@)
3084  */
3085 int CDECL MSVCRT_feof(MSVCRT_FILE* file)
3086 {
3087     return file->_flag & MSVCRT__IOEOF;
3088 }
3089
3090 /*********************************************************************
3091  *              ferror (MSVCRT.@)
3092  */
3093 int CDECL MSVCRT_ferror(MSVCRT_FILE* file)
3094 {
3095     return file->_flag & MSVCRT__IOERR;
3096 }
3097
3098 /*********************************************************************
3099  *              _filbuf (MSVCRT.@)
3100  */
3101 int CDECL MSVCRT__filbuf(MSVCRT_FILE* file)
3102 {
3103     unsigned char c;
3104     MSVCRT__lock_file(file);
3105
3106     /* Allocate buffer if needed */
3107     if(file->_bufsiz == 0 && !(file->_flag & MSVCRT__IONBF))
3108         msvcrt_alloc_buffer(file);
3109
3110     if(!(file->_flag & MSVCRT__IOREAD)) {
3111         if(file->_flag & MSVCRT__IORW)
3112             file->_flag |= MSVCRT__IOREAD;
3113         else {
3114             MSVCRT__unlock_file(file);
3115             return MSVCRT_EOF;
3116         }
3117     }
3118
3119     if(file->_flag & MSVCRT__IONBF) {
3120         int r;
3121         if ((r = read_i(file->_file,&c,1)) != 1) {
3122             file->_flag |= (r == 0) ? MSVCRT__IOEOF : MSVCRT__IOERR;
3123             MSVCRT__unlock_file(file);
3124             return MSVCRT_EOF;
3125         }
3126
3127         MSVCRT__unlock_file(file);
3128         return c;
3129     } else {
3130         file->_cnt = read_i(file->_file, file->_base, file->_bufsiz);
3131         if(file->_cnt<=0) {
3132             file->_flag |= (file->_cnt == 0) ? MSVCRT__IOEOF : MSVCRT__IOERR;
3133             file->_cnt = 0;
3134             MSVCRT__unlock_file(file);
3135             return MSVCRT_EOF;
3136         }
3137
3138         file->_cnt--;
3139         file->_ptr = file->_base+1;
3140         c = *(unsigned char *)file->_base;
3141         MSVCRT__unlock_file(file);
3142         return c;
3143     }
3144 }
3145
3146 /*********************************************************************
3147  *              fgetc (MSVCRT.@)
3148  */
3149 int CDECL MSVCRT_fgetc(MSVCRT_FILE* file)
3150 {
3151   unsigned char *i;
3152   unsigned int j;
3153
3154   MSVCRT__lock_file(file);
3155   if (file->_cnt>0) {
3156     file->_cnt--;
3157     i = (unsigned char *)file->_ptr++;
3158     j = *i;
3159   } else
3160     j = MSVCRT__filbuf(file);
3161
3162   MSVCRT__unlock_file(file);
3163   return j;
3164 }
3165
3166 /*********************************************************************
3167  *              _fgetchar (MSVCRT.@)
3168  */
3169 int CDECL MSVCRT__fgetchar(void)
3170 {
3171   return MSVCRT_fgetc(MSVCRT_stdin);
3172 }
3173
3174 /*********************************************************************
3175  *              fgets (MSVCRT.@)
3176  */
3177 char * CDECL MSVCRT_fgets(char *s, int size, MSVCRT_FILE* file)
3178 {
3179   int    cc = MSVCRT_EOF;
3180   char * buf_start = s;
3181
3182   TRACE(":file(%p) fd (%d) str (%p) len (%d)\n",
3183         file,file->_file,s,size);
3184
3185   MSVCRT__lock_file(file);
3186
3187   while ((size >1) && (cc = MSVCRT_fgetc(file)) != MSVCRT_EOF && cc != '\n')
3188     {
3189       *s++ = (char)cc;
3190       size --;
3191     }
3192   if ((cc == MSVCRT_EOF) && (s == buf_start)) /* If nothing read, return 0*/
3193   {
3194     TRACE(":nothing read\n");
3195     MSVCRT__unlock_file(file);
3196     return NULL;
3197   }
3198   if ((cc != MSVCRT_EOF) && (size > 1))
3199     *s++ = cc;
3200   *s = '\0';
3201   TRACE(":got %s\n", debugstr_a(buf_start));
3202   MSVCRT__unlock_file(file);
3203   return buf_start;
3204 }
3205
3206 /*********************************************************************
3207  *              fgetwc (MSVCRT.@)
3208  */
3209 MSVCRT_wint_t CDECL MSVCRT_fgetwc(MSVCRT_FILE* file)
3210 {
3211     MSVCRT_wint_t ret;
3212     int ch;
3213
3214     MSVCRT__lock_file(file);
3215
3216     if((msvcrt_get_ioinfo(file->_file)->exflag & (EF_UTF8 | EF_UTF16))
3217             || !(msvcrt_get_ioinfo(file->_file)->wxflag & WX_TEXT)) {
3218         char *p;
3219
3220         for(p=(char*)&ret; (MSVCRT_wint_t*)p<&ret+1; p++) {
3221             ch = MSVCRT_fgetc(file);
3222             if(ch == MSVCRT_EOF) {
3223                 ret = MSVCRT_WEOF;
3224                 break;
3225             }
3226             *p = (char)ch;
3227         }
3228     }else {
3229         char mbs[MSVCRT_MB_LEN_MAX];
3230         int len = 0;
3231
3232         ch = MSVCRT_fgetc(file);
3233         if(ch != MSVCRT_EOF) {
3234             mbs[0] = (char)ch;
3235             if(MSVCRT_isleadbyte((unsigned char)mbs[0])) {
3236                 ch = MSVCRT_fgetc(file);
3237                 if(ch != MSVCRT_EOF) {
3238                     mbs[1] = (char)ch;
3239                     len = 2;
3240                 }
3241             }else {
3242                 len = 1;
3243             }
3244         }
3245
3246         if(!len || MSVCRT_mbtowc(&ret, mbs, len)==-1)
3247             ret = MSVCRT_WEOF;
3248     }
3249
3250     MSVCRT__unlock_file(file);
3251     return ret;
3252 }
3253
3254 /*********************************************************************
3255  *              _getw (MSVCRT.@)
3256  */
3257 int CDECL MSVCRT__getw(MSVCRT_FILE* file)
3258 {
3259   char *ch;
3260   int i, k;
3261   unsigned int j;
3262   ch = (char *)&i;
3263
3264   MSVCRT__lock_file(file);
3265   for (j=0; j<sizeof(int); j++) {
3266     k = MSVCRT_fgetc(file);
3267     if (k == MSVCRT_EOF) {
3268       file->_flag |= MSVCRT__IOEOF;
3269       MSVCRT__unlock_file(file);
3270       return EOF;
3271     }
3272     ch[j] = k;
3273   }
3274
3275   MSVCRT__unlock_file(file);
3276   return i;
3277 }
3278
3279 /*********************************************************************
3280  *              getwc (MSVCRT.@)
3281  */
3282 MSVCRT_wint_t CDECL MSVCRT_getwc(MSVCRT_FILE* file)
3283 {
3284   return MSVCRT_fgetwc(file);
3285 }
3286
3287 /*********************************************************************
3288  *              _fgetwchar (MSVCRT.@)
3289  */
3290 MSVCRT_wint_t CDECL MSVCRT__fgetwchar(void)
3291 {
3292   return MSVCRT_fgetwc(MSVCRT_stdin);
3293 }
3294
3295 /*********************************************************************
3296  *              getwchar (MSVCRT.@)
3297  */
3298 MSVCRT_wint_t CDECL MSVCRT_getwchar(void)
3299 {
3300   return MSVCRT__fgetwchar();
3301 }
3302
3303 /*********************************************************************
3304  *              fgetws (MSVCRT.@)
3305  */
3306 MSVCRT_wchar_t * CDECL MSVCRT_fgetws(MSVCRT_wchar_t *s, int size, MSVCRT_FILE* file)
3307 {
3308   MSVCRT_wint_t cc = MSVCRT_WEOF;
3309   MSVCRT_wchar_t * buf_start = s;
3310
3311   TRACE(":file(%p) fd (%d) str (%p) len (%d)\n",
3312         file,file->_file,s,size);
3313
3314   MSVCRT__lock_file(file);
3315
3316   while ((size >1) && (cc = MSVCRT_fgetwc(file)) != MSVCRT_WEOF && cc != '\n')
3317     {
3318       *s++ = cc;
3319       size --;
3320     }
3321   if ((cc == MSVCRT_WEOF) && (s == buf_start)) /* If nothing read, return 0*/
3322   {
3323     TRACE(":nothing read\n");
3324     MSVCRT__unlock_file(file);
3325     return NULL;
3326   }
3327   if ((cc != MSVCRT_WEOF) && (size > 1))
3328     *s++ = cc;
3329   *s = 0;
3330   TRACE(":got %s\n", debugstr_w(buf_start));
3331   MSVCRT__unlock_file(file);
3332   return buf_start;
3333 }
3334
3335 /*********************************************************************
3336  *              fwrite (MSVCRT.@)
3337  */
3338 MSVCRT_size_t CDECL MSVCRT_fwrite(const void *ptr, MSVCRT_size_t size, MSVCRT_size_t nmemb, MSVCRT_FILE* file)
3339 {
3340     MSVCRT_size_t wrcnt=size * nmemb;
3341     int written = 0;
3342     if (size == 0)
3343         return 0;
3344
3345     MSVCRT__lock_file(file);
3346     if(file->_cnt) {
3347         int pcnt=(file->_cnt>wrcnt)? wrcnt: file->_cnt;
3348         memcpy(file->_ptr, ptr, pcnt);
3349         file->_cnt -= pcnt;
3350         file->_ptr += pcnt;
3351         written = pcnt;
3352         wrcnt -= pcnt;
3353         ptr = (const char*)ptr + pcnt;
3354     } else if(!(file->_flag & MSVCRT__IOWRT)) {
3355         if(file->_flag & MSVCRT__IORW) {
3356             file->_flag |= MSVCRT__IOWRT;
3357         } else {
3358             MSVCRT__unlock_file(file);
3359             return 0;
3360         }
3361     }
3362     if(wrcnt) {
3363         int res;
3364
3365         if(file->_bufsiz == 0 && !(file->_flag & MSVCRT__IONBF))
3366             msvcrt_alloc_buffer(file);
3367
3368         /* Flush buffer */
3369         res=msvcrt_flush_buffer(file);
3370         if(!res) {
3371             int pwritten = MSVCRT__write(file->_file, ptr, wrcnt);
3372             if (pwritten <= 0)
3373             {
3374                 file->_flag |= MSVCRT__IOERR;
3375                 pwritten=0;
3376             }
3377             written += pwritten;
3378         }
3379     }
3380
3381     MSVCRT__unlock_file(file);
3382     return written / size;
3383 }
3384
3385 /*********************************************************************
3386  *              fputwc (MSVCRT.@)
3387  */
3388 MSVCRT_wint_t CDECL MSVCRT_fputwc(MSVCRT_wint_t wc, MSVCRT_FILE* file)
3389 {
3390     MSVCRT_wchar_t mwc=wc;
3391     ioinfo *fdinfo;
3392     MSVCRT_wint_t ret;
3393
3394     MSVCRT__lock_file(file);
3395     fdinfo = msvcrt_get_ioinfo(file->_file);
3396
3397     if((fdinfo->wxflag&WX_TEXT) && !(fdinfo->exflag&(EF_UTF8|EF_UTF16))) {
3398         char buf[MSVCRT_MB_LEN_MAX];
3399         int char_len;
3400
3401         char_len = MSVCRT_wctomb(buf, mwc);
3402         if(char_len!=-1 && MSVCRT_fwrite(buf, char_len, 1, file)==1)
3403             ret = wc;
3404         else
3405             ret = MSVCRT_WEOF;
3406     }else if(MSVCRT_fwrite(&mwc, sizeof(mwc), 1, file) == 1) {
3407         ret = wc;
3408     }else {
3409         ret = MSVCRT_WEOF;
3410     }
3411
3412     MSVCRT__unlock_file(file);
3413     return ret;
3414 }
3415
3416 /*********************************************************************
3417  *              _fputwchar (MSVCRT.@)
3418  */
3419 MSVCRT_wint_t CDECL MSVCRT__fputwchar(MSVCRT_wint_t wc)
3420 {
3421   return MSVCRT_fputwc(wc, MSVCRT_stdout);
3422 }
3423
3424 /*********************************************************************
3425  *              _wfsopen (MSVCRT.@)
3426  */
3427 MSVCRT_FILE * CDECL MSVCRT__wfsopen(const MSVCRT_wchar_t *path, const MSVCRT_wchar_t *mode, int share)
3428 {
3429   MSVCRT_FILE* file;
3430   int open_flags, stream_flags, fd;
3431
3432   TRACE("(%s,%s)\n", debugstr_w(path), debugstr_w(mode));
3433
3434   /* map mode string to open() flags. "man fopen" for possibilities. */
3435   if (msvcrt_get_flags(mode, &open_flags, &stream_flags) == -1)
3436       return NULL;
3437
3438   LOCK_FILES();
3439   fd = MSVCRT__wsopen(path, open_flags, share, MSVCRT__S_IREAD | MSVCRT__S_IWRITE);
3440   if (fd < 0)
3441     file = NULL;
3442   else if ((file = msvcrt_alloc_fp()) && msvcrt_init_fp(file, fd, stream_flags)
3443    != -1)
3444     TRACE(":fd (%d) mode (%s) FILE* (%p)\n", fd, debugstr_w(mode), file);
3445   else if (file)
3446   {
3447     file->_flag = 0;
3448     file = NULL;
3449   }
3450
3451   TRACE(":got (%p)\n",file);
3452   if (fd >= 0 && !file)
3453     MSVCRT__close(fd);
3454   UNLOCK_FILES();
3455   return file;
3456 }
3457
3458 /*********************************************************************
3459  *              _fsopen (MSVCRT.@)
3460  */
3461 MSVCRT_FILE * CDECL MSVCRT__fsopen(const char *path, const char *mode, int share)
3462 {
3463     MSVCRT_FILE *ret;
3464     MSVCRT_wchar_t *pathW = NULL, *modeW = NULL;
3465
3466     if (path && !(pathW = msvcrt_wstrdupa(path))) {
3467         MSVCRT__invalid_parameter(NULL, NULL, NULL, 0, 0);
3468         *MSVCRT__errno() = MSVCRT_EINVAL;
3469         return NULL;
3470     }
3471     if (mode && !(modeW = msvcrt_wstrdupa(mode)))
3472     {
3473         MSVCRT_free(pathW);
3474         MSVCRT__invalid_parameter(NULL, NULL, NULL, 0, 0);
3475         *MSVCRT__errno() = MSVCRT_EINVAL;
3476         return NULL;
3477     }
3478
3479     ret = MSVCRT__wfsopen(pathW, modeW, share);
3480
3481     MSVCRT_free(pathW);
3482     MSVCRT_free(modeW);
3483     return ret;
3484 }
3485
3486 /*********************************************************************
3487  *              fopen (MSVCRT.@)
3488  */
3489 MSVCRT_FILE * CDECL MSVCRT_fopen(const char *path, const char *mode)
3490 {
3491     return MSVCRT__fsopen( path, mode, MSVCRT__SH_DENYNO );
3492 }
3493
3494 /*********************************************************************
3495  *              fopen_s (MSVCRT.@)
3496  */
3497 int CDECL MSVCRT_fopen_s(MSVCRT_FILE** pFile,
3498         const char *filename, const char *mode)
3499 {
3500     if (!MSVCRT_CHECK_PMT(pFile != NULL)) return MSVCRT_EINVAL;
3501     if (!MSVCRT_CHECK_PMT(filename != NULL)) return MSVCRT_EINVAL;
3502     if (!MSVCRT_CHECK_PMT(mode != NULL)) return MSVCRT_EINVAL;
3503
3504     *pFile = MSVCRT_fopen(filename, mode);
3505
3506     if(!*pFile)
3507         return *MSVCRT__errno();
3508     return 0;
3509 }
3510
3511 /*********************************************************************
3512  *              _wfopen (MSVCRT.@)
3513  */
3514 MSVCRT_FILE * CDECL MSVCRT__wfopen(const MSVCRT_wchar_t *path, const MSVCRT_wchar_t *mode)
3515 {
3516     return MSVCRT__wfsopen( path, mode, MSVCRT__SH_DENYNO );
3517 }
3518
3519 /*********************************************************************
3520  *              _wfopen_s (MSVCRT.@)
3521  */
3522 int CDECL MSVCRT__wfopen_s(MSVCRT_FILE** pFile, const MSVCRT_wchar_t *filename,
3523         const MSVCRT_wchar_t *mode)
3524 {
3525     if (!MSVCRT_CHECK_PMT(pFile != NULL)) return MSVCRT_EINVAL;
3526     if (!MSVCRT_CHECK_PMT(filename != NULL)) return MSVCRT_EINVAL;
3527     if (!MSVCRT_CHECK_PMT(mode != NULL)) return MSVCRT_EINVAL;
3528
3529     *pFile = MSVCRT__wfopen(filename, mode);
3530
3531     if(!*pFile)
3532         return *MSVCRT__errno();
3533     return 0;
3534 }
3535
3536 /*********************************************************************
3537  *              _flsbuf (MSVCRT.@)
3538  */
3539 int CDECL MSVCRT__flsbuf(int c, MSVCRT_FILE* file)
3540 {
3541     /* Flush output buffer */
3542     if(file->_bufsiz == 0 && !(file->_flag & MSVCRT__IONBF)) {
3543         msvcrt_alloc_buffer(file);
3544     }
3545     if(!(file->_flag & MSVCRT__IOWRT)) {
3546         if(file->_flag & MSVCRT__IORW)
3547             file->_flag |= MSVCRT__IOWRT;
3548         else
3549             return MSVCRT_EOF;
3550     }
3551     if(file->_bufsiz) {
3552         int res = 0;
3553
3554         if(file->_cnt <= 0)
3555             res = msvcrt_flush_buffer(file);
3556         if(!res) {
3557             *file->_ptr++ = c;
3558             file->_cnt--;
3559             res = msvcrt_flush_buffer(file);
3560         }
3561
3562         return res ? res : c&0xff;
3563     } else {
3564         unsigned char cc=c;
3565         int len;
3566         /* set _cnt to 0 for unbuffered FILEs */
3567         file->_cnt = 0;
3568         len = MSVCRT__write(file->_file, &cc, 1);
3569         if (len == 1)
3570             return c & 0xff;
3571         file->_flag |= MSVCRT__IOERR;
3572         return MSVCRT_EOF;
3573     }
3574 }
3575
3576 /*********************************************************************
3577  *              fputc (MSVCRT.@)
3578  */
3579 int CDECL MSVCRT_fputc(int c, MSVCRT_FILE* file)
3580 {
3581   int res;
3582
3583   MSVCRT__lock_file(file);
3584   if(file->_cnt>0) {
3585     *file->_ptr++=c;
3586     file->_cnt--;
3587     if (c == '\n')
3588     {
3589       res = msvcrt_flush_buffer(file);
3590       MSVCRT__unlock_file(file);
3591       return res ? res : c;
3592     }
3593     else {
3594       MSVCRT__unlock_file(file);
3595       return c & 0xff;
3596     }
3597   } else {
3598     res = MSVCRT__flsbuf(c, file);
3599     MSVCRT__unlock_file(file);
3600     return res;
3601   }
3602 }
3603
3604 /*********************************************************************
3605  *              _fputchar (MSVCRT.@)
3606  */
3607 int CDECL MSVCRT__fputchar(int c)
3608 {
3609   return MSVCRT_fputc(c, MSVCRT_stdout);
3610 }
3611
3612 /*********************************************************************
3613  *              fread (MSVCRT.@)
3614  */
3615 MSVCRT_size_t CDECL MSVCRT_fread(void *ptr, MSVCRT_size_t size, MSVCRT_size_t nmemb, MSVCRT_FILE* file)
3616 {
3617   MSVCRT_size_t rcnt=size * nmemb;
3618   MSVCRT_size_t read=0;
3619   int pread=0;
3620
3621   if(!rcnt)
3622         return 0;
3623
3624   MSVCRT__lock_file(file);
3625
3626   /* first buffered data */
3627   if(file->_cnt>0) {
3628         int pcnt= (rcnt>file->_cnt)? file->_cnt:rcnt;
3629         memcpy(ptr, file->_ptr, pcnt);
3630         file->_cnt -= pcnt;
3631         file->_ptr += pcnt;
3632         read += pcnt ;
3633         rcnt -= pcnt ;
3634         ptr = (char*)ptr + pcnt;
3635   } else if(!(file->_flag & MSVCRT__IOREAD )) {
3636         if(file->_flag & MSVCRT__IORW) {
3637                 file->_flag |= MSVCRT__IOREAD;
3638         } else {
3639         MSVCRT__unlock_file(file);
3640         return 0;
3641     }
3642   }
3643   while(rcnt>0)
3644   {
3645     int i;
3646     if (!file->_cnt && rcnt<MSVCRT_BUFSIZ && !(file->_flag & MSVCRT__IONBF)
3647             && (file->_bufsiz != 0 || msvcrt_alloc_buffer(file))) {
3648       file->_cnt = MSVCRT__read(file->_file, file->_base, file->_bufsiz);
3649       file->_ptr = file->_base;
3650       i = (file->_cnt<rcnt) ? file->_cnt : rcnt;
3651       /* If the buffer fill reaches eof but fread wouldn't, clear eof. */
3652       if (i > 0 && i < file->_cnt) {
3653         msvcrt_get_ioinfo(file->_file)->wxflag &= ~WX_ATEOF;
3654         file->_flag &= ~MSVCRT__IOEOF;
3655       }
3656       if (i > 0) {
3657         memcpy(ptr, file->_ptr, i);
3658         file->_cnt -= i;
3659         file->_ptr += i;
3660       }
3661     } else if (rcnt > UINT_MAX) {
3662       i = MSVCRT__read(file->_file, ptr, UINT_MAX);
3663     } else if (rcnt < MSVCRT_BUFSIZ) {
3664       i = MSVCRT__read(file->_file, ptr, rcnt);
3665     } else {
3666       i = MSVCRT__read(file->_file, ptr, rcnt - MSVCRT_BUFSIZ/2);
3667     }
3668     pread += i;
3669     rcnt -= i;
3670     ptr = (char *)ptr+i;
3671     /* expose feof condition in the flags
3672      * MFC tests file->_flag for feof, and doesn't call feof())
3673      */
3674     if (msvcrt_get_ioinfo(file->_file)->wxflag & WX_ATEOF)
3675         file->_flag |= MSVCRT__IOEOF;
3676     else if (i == -1)
3677     {
3678         file->_flag |= MSVCRT__IOERR;
3679         pread = 0;
3680         rcnt = 0;
3681     }
3682     if (i < 1) break;
3683   }
3684   read+=pread;
3685   MSVCRT__unlock_file(file);
3686   return read / size;
3687 }
3688
3689
3690 /* fread_s - not exported in native msvcrt */
3691 MSVCRT_size_t CDECL fread_s(void *buf, MSVCRT_size_t buf_size, MSVCRT_size_t elem_size,
3692         MSVCRT_size_t count, MSVCRT_FILE *stream)
3693 {
3694     size_t bytes_left, buf_pos;
3695
3696     TRACE("(%p %lu %lu %lu %p\n", buf, buf_size, elem_size, count, stream);
3697
3698     if(!MSVCRT_CHECK_PMT(stream != NULL)) {
3699         if(buf && buf_size)
3700             memset(buf, 0, buf_size);
3701         return 0;
3702     }
3703     if(!elem_size || !count) return 0;
3704     if(!MSVCRT_CHECK_PMT(buf != NULL)) return 0;
3705     if(!MSVCRT_CHECK_PMT(MSVCRT_SIZE_MAX/count >= elem_size)) return 0;
3706
3707     bytes_left = elem_size*count;
3708     buf_pos = 0;
3709     while(bytes_left) {
3710         if(stream->_cnt > 0) {
3711             size_t size = bytes_left<stream->_cnt ? bytes_left : stream->_cnt;
3712
3713             if(!MSVCRT_CHECK_PMT_ERR(size <= buf_size-buf_pos, MSVCRT_ERANGE)) {
3714                 memset(buf, 0, buf_size);
3715                 return 0;
3716             }
3717
3718             MSVCRT_fread((char*)buf+buf_pos, 1, size, stream);
3719             buf_pos += size;
3720             bytes_left -= size;
3721         }else {
3722             int c = MSVCRT__filbuf(stream);
3723
3724             if(c == EOF)
3725                 break;
3726
3727             if(!MSVCRT_CHECK_PMT_ERR(buf_size-buf_pos > 0, MSVCRT_ERANGE)) {
3728                 memset(buf, 0, buf_size);
3729                 return 0;
3730             }
3731
3732             ((char*)buf)[buf_pos++] = c;
3733             bytes_left--;
3734         }
3735     }
3736
3737     return buf_pos/elem_size;
3738 }
3739
3740 /*********************************************************************
3741  *              _wfreopen (MSVCRT.@)
3742  *
3743  */
3744 MSVCRT_FILE* CDECL MSVCRT__wfreopen(const MSVCRT_wchar_t *path, const MSVCRT_wchar_t *mode, MSVCRT_FILE* file)
3745 {
3746   int fd;
3747
3748   TRACE(":path (%s) mode (%s) file (%p) fd (%d)\n", debugstr_w(path), debugstr_w(mode), file, file->_file);
3749
3750   LOCK_FILES();
3751   if (!file || ((fd = file->_file) < 0) || fd > MSVCRT_fdend)
3752     file = NULL;
3753   else
3754   {
3755     MSVCRT_fclose(file);
3756     file = MSVCRT__wfsopen(path, mode, MSVCRT__SH_DENYNO);
3757   }
3758   UNLOCK_FILES();
3759   return file;
3760 }
3761
3762 /*********************************************************************
3763  *      _wfreopen_s (MSVCRT.@)
3764  */
3765 int CDECL MSVCRT__wfreopen_s(MSVCRT_FILE** pFile,
3766         const MSVCRT_wchar_t *path, const MSVCRT_wchar_t *mode, MSVCRT_FILE* file)
3767 {
3768     if (!MSVCRT_CHECK_PMT(pFile != NULL)) return MSVCRT_EINVAL;
3769     if (!MSVCRT_CHECK_PMT(path != NULL)) return MSVCRT_EINVAL;
3770     if (!MSVCRT_CHECK_PMT(mode != NULL)) return MSVCRT_EINVAL;
3771     if (!MSVCRT_CHECK_PMT(file != NULL)) return MSVCRT_EINVAL;
3772
3773     *pFile = MSVCRT__wfreopen(path, mode, file);
3774
3775     if(!*pFile)
3776         return *MSVCRT__errno();
3777     return 0;
3778 }
3779
3780 /*********************************************************************
3781  *      freopen (MSVCRT.@)
3782  *
3783  */
3784 MSVCRT_FILE* CDECL MSVCRT_freopen(const char *path, const char *mode, MSVCRT_FILE* file)
3785 {
3786     MSVCRT_FILE *ret;
3787     MSVCRT_wchar_t *pathW = NULL, *modeW = NULL;
3788
3789     if (path && !(pathW = msvcrt_wstrdupa(path))) return NULL;
3790     if (mode && !(modeW = msvcrt_wstrdupa(mode)))
3791     {
3792         MSVCRT_free(pathW);
3793         return NULL;
3794     }
3795
3796     ret = MSVCRT__wfreopen(pathW, modeW, file);
3797
3798     MSVCRT_free(pathW);
3799     MSVCRT_free(modeW);
3800     return ret;
3801 }
3802
3803 /*********************************************************************
3804  *      freopen_s (MSVCRT.@)
3805  */
3806 int CDECL MSVCRT_freopen_s(MSVCRT_FILE** pFile,
3807         const char *path, const char *mode, MSVCRT_FILE* file)
3808 {
3809     if (!MSVCRT_CHECK_PMT(pFile != NULL)) return MSVCRT_EINVAL;
3810     if (!MSVCRT_CHECK_PMT(path != NULL)) return MSVCRT_EINVAL;
3811     if (!MSVCRT_CHECK_PMT(mode != NULL)) return MSVCRT_EINVAL;
3812     if (!MSVCRT_CHECK_PMT(file != NULL)) return MSVCRT_EINVAL;
3813
3814     *pFile = MSVCRT_freopen(path, mode, file);
3815
3816     if(!*pFile)
3817         return *MSVCRT__errno();
3818     return 0;
3819 }
3820
3821 /*********************************************************************
3822  *              fsetpos (MSVCRT.@)
3823  */
3824 int CDECL MSVCRT_fsetpos(MSVCRT_FILE* file, MSVCRT_fpos_t *pos)
3825 {
3826   int ret;
3827
3828   MSVCRT__lock_file(file);
3829   /* Note that all this has been lifted 'as is' from fseek */
3830   if(file->_flag & MSVCRT__IOWRT)
3831         msvcrt_flush_buffer(file);
3832
3833   /* Discard buffered input */
3834   file->_cnt = 0;
3835   file->_ptr = file->_base;
3836   
3837   /* Reset direction of i/o */
3838   if(file->_flag & MSVCRT__IORW) {
3839         file->_flag &= ~(MSVCRT__IOREAD|MSVCRT__IOWRT);
3840   }
3841
3842   ret = (MSVCRT__lseeki64(file->_file,*pos,SEEK_SET) == -1) ? -1 : 0;
3843   MSVCRT__unlock_file(file);
3844   return ret;
3845 }
3846
3847 /*********************************************************************
3848  *              _ftelli64 (MSVCRT.@)
3849  */
3850 __int64 CDECL MSVCRT__ftelli64(MSVCRT_FILE* file)
3851 {
3852     __int64 pos;
3853
3854     MSVCRT__lock_file(file);
3855     pos = _telli64(file->_file);
3856     if(pos == -1) {
3857         MSVCRT__unlock_file(file);
3858         return -1;
3859     }
3860     if(file->_bufsiz)  {
3861         if(file->_flag & MSVCRT__IOWRT) {
3862             pos += file->_ptr - file->_base;
3863
3864             if(msvcrt_get_ioinfo(file->_file)->wxflag & WX_TEXT) {
3865                 char *p;
3866
3867                 for(p=file->_base; p<file->_ptr; p++)
3868                     if(*p == '\n')
3869                         pos++;
3870             }
3871         } else if(!file->_cnt) { /* nothing to do */
3872         } else if(MSVCRT__lseeki64(file->_file, 0, SEEK_END)==pos) {
3873             int i;
3874
3875             pos -= file->_cnt;
3876             if(msvcrt_get_ioinfo(file->_file)->wxflag & WX_TEXT) {
3877                 for(i=0; i<file->_cnt; i++)
3878                     if(file->_ptr[i] == '\n')
3879                         pos--;
3880             }
3881         } else {
3882             char *p;
3883
3884             if(MSVCRT__lseeki64(file->_file, pos, SEEK_SET) != pos) {
3885                 MSVCRT__unlock_file(file);
3886                 return -1;
3887             }
3888
3889             pos -= file->_bufsiz;
3890             pos += file->_ptr - file->_base;
3891
3892             if(msvcrt_get_ioinfo(file->_file)->wxflag & WX_TEXT) {
3893                 if(msvcrt_get_ioinfo(file->_file)->wxflag & WX_READNL)
3894                     pos--;
3895
3896                 for(p=file->_base; p<file->_ptr; p++)
3897                     if(*p == '\n')
3898                         pos++;
3899             }
3900         }
3901     }
3902
3903     MSVCRT__unlock_file(file);
3904     return pos;
3905 }
3906
3907 /*********************************************************************
3908  *              ftell (MSVCRT.@)
3909  */
3910 LONG CDECL MSVCRT_ftell(MSVCRT_FILE* file)
3911 {
3912   return MSVCRT__ftelli64(file);
3913 }
3914
3915 /*********************************************************************
3916  *              fgetpos (MSVCRT.@)
3917  */
3918 int CDECL MSVCRT_fgetpos(MSVCRT_FILE* file, MSVCRT_fpos_t *pos)
3919 {
3920     *pos = MSVCRT__ftelli64(file);
3921     if(*pos == -1)
3922         return -1;
3923     return 0;
3924 }
3925
3926 /*********************************************************************
3927  *              fputs (MSVCRT.@)
3928  */
3929 int CDECL MSVCRT_fputs(const char *s, MSVCRT_FILE* file)
3930 {
3931     MSVCRT_size_t len = strlen(s);
3932     int ret;
3933
3934     MSVCRT__lock_file(file);
3935     ret = MSVCRT_fwrite(s, sizeof(*s), len, file) == len ? 0 : MSVCRT_EOF;
3936     MSVCRT__unlock_file(file);
3937     return ret;
3938 }
3939
3940 /*********************************************************************
3941  *              fputws (MSVCRT.@)
3942  */
3943 int CDECL MSVCRT_fputws(const MSVCRT_wchar_t *s, MSVCRT_FILE* file)
3944 {
3945     MSVCRT_size_t i, len = strlenW(s);
3946     BOOL tmp_buf;
3947     int ret;
3948
3949     MSVCRT__lock_file(file);
3950     if (!(msvcrt_get_ioinfo(file->_file)->wxflag & WX_TEXT)) {
3951         ret = MSVCRT_fwrite(s,sizeof(*s),len,file) == len ? 0 : MSVCRT_EOF;
3952         MSVCRT__unlock_file(file);
3953         return ret;
3954     }
3955
3956     tmp_buf = add_std_buffer(file);
3957     for (i=0; i<len; i++) {
3958         if(MSVCRT_fputwc(s[i], file) == MSVCRT_WEOF) {
3959             if(tmp_buf) remove_std_buffer(file);
3960             MSVCRT__unlock_file(file);
3961             return MSVCRT_WEOF;
3962         }
3963     }
3964
3965     if(tmp_buf) remove_std_buffer(file);
3966     MSVCRT__unlock_file(file);
3967     return 0;
3968 }
3969
3970 /*********************************************************************
3971  *              getchar (MSVCRT.@)
3972  */
3973 int CDECL MSVCRT_getchar(void)
3974 {
3975   return MSVCRT_fgetc(MSVCRT_stdin);
3976 }
3977
3978 /*********************************************************************
3979  *              getc (MSVCRT.@)
3980  */
3981 int CDECL MSVCRT_getc(MSVCRT_FILE* file)
3982 {
3983   return MSVCRT_fgetc(file);
3984 }
3985
3986 /*********************************************************************
3987  *              gets (MSVCRT.@)
3988  */
3989 char * CDECL MSVCRT_gets(char *buf)
3990 {
3991   int    cc;
3992   char * buf_start = buf;
3993
3994   MSVCRT__lock_file(MSVCRT_stdin);
3995   for(cc = MSVCRT_fgetc(MSVCRT_stdin); cc != MSVCRT_EOF && cc != '\n';
3996       cc = MSVCRT_fgetc(MSVCRT_stdin))
3997   if(cc != '\r') *buf++ = (char)cc;
3998
3999   *buf = '\0';
4000
4001   TRACE("got '%s'\n", buf_start);
4002   MSVCRT__unlock_file(MSVCRT_stdin);
4003   return buf_start;
4004 }
4005
4006 /*********************************************************************
4007  *              _getws (MSVCRT.@)
4008  */
4009 MSVCRT_wchar_t* CDECL MSVCRT__getws(MSVCRT_wchar_t* buf)
4010 {
4011     MSVCRT_wint_t cc;
4012     MSVCRT_wchar_t* ws = buf;
4013
4014     MSVCRT__lock_file(MSVCRT_stdin);
4015     for (cc = MSVCRT_fgetwc(MSVCRT_stdin); cc != MSVCRT_WEOF && cc != '\n';
4016          cc = MSVCRT_fgetwc(MSVCRT_stdin))
4017     {
4018         if (cc != '\r')
4019             *buf++ = (MSVCRT_wchar_t)cc;
4020     }
4021     *buf = '\0';
4022
4023     TRACE("got %s\n", debugstr_w(ws));
4024     MSVCRT__unlock_file(MSVCRT_stdin);
4025     return ws;
4026 }
4027
4028 /*********************************************************************
4029  *              putc (MSVCRT.@)
4030  */
4031 int CDECL MSVCRT_putc(int c, MSVCRT_FILE* file)
4032 {
4033   return MSVCRT_fputc(c, file);
4034 }
4035
4036 /*********************************************************************
4037  *              putchar (MSVCRT.@)
4038  */
4039 int CDECL MSVCRT_putchar(int c)
4040 {
4041   return MSVCRT_fputc(c, MSVCRT_stdout);
4042 }
4043
4044 /*********************************************************************
4045  *              _putwch (MSVCRT.@)
4046  */
4047 int CDECL MSVCRT__putwch(int c)
4048 {
4049   return MSVCRT_fputwc(c, MSVCRT_stdout);
4050 }
4051
4052 /*********************************************************************
4053  *              puts (MSVCRT.@)
4054  */
4055 int CDECL MSVCRT_puts(const char *s)
4056 {
4057     MSVCRT_size_t len = strlen(s);
4058     int ret;
4059
4060     MSVCRT__lock_file(MSVCRT_stdout);
4061     if(MSVCRT_fwrite(s, sizeof(*s), len, MSVCRT_stdout) != len) {
4062         MSVCRT__unlock_file(MSVCRT_stdout);
4063         return MSVCRT_EOF;
4064     }
4065
4066     ret = MSVCRT_fwrite("\n",1,1,MSVCRT_stdout) == 1 ? 0 : MSVCRT_EOF;
4067     MSVCRT__unlock_file(MSVCRT_stdout);
4068     return ret;
4069 }
4070
4071 /*********************************************************************
4072  *              _putws (MSVCRT.@)
4073  */
4074 int CDECL MSVCRT__putws(const MSVCRT_wchar_t *s)
4075 {
4076     static const MSVCRT_wchar_t nl = '\n';
4077     MSVCRT_size_t len = strlenW(s);
4078     int ret;
4079
4080     MSVCRT__lock_file(MSVCRT_stdout);
4081     if(MSVCRT_fwrite(s, sizeof(*s), len, MSVCRT_stdout) != len) {
4082         MSVCRT__unlock_file(MSVCRT_stdout);
4083         return MSVCRT_EOF;
4084     }
4085
4086     ret = MSVCRT_fwrite(&nl,sizeof(nl),1,MSVCRT_stdout) == 1 ? 0 : MSVCRT_EOF;
4087     MSVCRT__unlock_file(MSVCRT_stdout);
4088     return ret;
4089 }
4090
4091 /*********************************************************************
4092  *              remove (MSVCRT.@)
4093  */
4094 int CDECL MSVCRT_remove(const char *path)
4095 {
4096   TRACE("(%s)\n",path);
4097   if (DeleteFileA(path))
4098     return 0;
4099   TRACE(":failed (%d)\n",GetLastError());
4100   msvcrt_set_errno(GetLastError());
4101   return -1;
4102 }
4103
4104 /*********************************************************************
4105  *              _wremove (MSVCRT.@)
4106  */
4107 int CDECL MSVCRT__wremove(const MSVCRT_wchar_t *path)
4108 {
4109   TRACE("(%s)\n",debugstr_w(path));
4110   if (DeleteFileW(path))
4111     return 0;
4112   TRACE(":failed (%d)\n",GetLastError());
4113   msvcrt_set_errno(GetLastError());
4114   return -1;
4115 }
4116
4117 /*********************************************************************
4118  *              rename (MSVCRT.@)
4119  */
4120 int CDECL MSVCRT_rename(const char *oldpath,const char *newpath)
4121 {
4122   TRACE(":from %s to %s\n",oldpath,newpath);
4123   if (MoveFileExA(oldpath, newpath, MOVEFILE_COPY_ALLOWED))
4124     return 0;
4125   TRACE(":failed (%d)\n",GetLastError());
4126   msvcrt_set_errno(GetLastError());
4127   return -1;
4128 }
4129
4130 /*********************************************************************
4131  *              _wrename (MSVCRT.@)
4132  */
4133 int CDECL MSVCRT__wrename(const MSVCRT_wchar_t *oldpath,const MSVCRT_wchar_t *newpath)
4134 {
4135   TRACE(":from %s to %s\n",debugstr_w(oldpath),debugstr_w(newpath));
4136   if (MoveFileExW(oldpath, newpath, MOVEFILE_COPY_ALLOWED))
4137     return 0;
4138   TRACE(":failed (%d)\n",GetLastError());
4139   msvcrt_set_errno(GetLastError());
4140   return -1;
4141 }
4142
4143 /*********************************************************************
4144  *              setvbuf (MSVCRT.@)
4145  */
4146 int CDECL MSVCRT_setvbuf(MSVCRT_FILE* file, char *buf, int mode, MSVCRT_size_t size)
4147 {
4148   MSVCRT__lock_file(file);
4149   if(file->_bufsiz) {
4150         MSVCRT_free(file->_base);
4151         file->_bufsiz = 0;
4152         file->_cnt = 0;
4153   }
4154   if(mode == MSVCRT__IOFBF) {
4155         file->_flag &= ~MSVCRT__IONBF;
4156         file->_base = file->_ptr = buf;
4157         if(buf) {
4158                 file->_bufsiz = size;
4159         }
4160   } else {
4161         file->_flag |= MSVCRT__IONBF;
4162   }
4163   MSVCRT__unlock_file(file);
4164   return 0;
4165 }
4166
4167 /*********************************************************************
4168  *              setbuf (MSVCRT.@)
4169  */
4170 void CDECL MSVCRT_setbuf(MSVCRT_FILE* file, char *buf)
4171 {
4172   MSVCRT_setvbuf(file, buf, buf ? MSVCRT__IOFBF : MSVCRT__IONBF, MSVCRT_BUFSIZ);
4173 }
4174
4175 /*********************************************************************
4176  *              tmpnam (MSVCRT.@)
4177  */
4178 char * CDECL MSVCRT_tmpnam(char *s)
4179 {
4180   char tmpstr[16];
4181   char *p;
4182   int count, size;
4183
4184   if (!s) {
4185     thread_data_t *data = msvcrt_get_thread_data();
4186
4187     if(!data->tmpnam_buffer)
4188       data->tmpnam_buffer = MSVCRT_malloc(MAX_PATH);
4189
4190     s = data->tmpnam_buffer;
4191   }
4192
4193   msvcrt_int_to_base32(GetCurrentProcessId(), tmpstr);
4194   p = s + sprintf(s, "\\s%s.", tmpstr);
4195   for (count = 0; count < MSVCRT_TMP_MAX; count++)
4196   {
4197     size = msvcrt_int_to_base32(tmpnam_unique++, tmpstr);
4198     memcpy(p, tmpstr, size);
4199     p[size] = '\0';
4200     if (GetFileAttributesA(s) == INVALID_FILE_ATTRIBUTES &&
4201         GetLastError() == ERROR_FILE_NOT_FOUND)
4202       break;
4203   }
4204   return s;
4205 }
4206
4207 /*********************************************************************
4208  *              _wtmpnam (MSVCRT.@)
4209  */
4210 MSVCRT_wchar_t * CDECL MSVCRT_wtmpnam(MSVCRT_wchar_t *s)
4211 {
4212     static const MSVCRT_wchar_t format[] = {'\\','s','%','s','.',0};
4213     MSVCRT_wchar_t tmpstr[16];
4214     MSVCRT_wchar_t *p;
4215     int count, size;
4216     if (!s) {
4217         thread_data_t *data = msvcrt_get_thread_data();
4218
4219         if(!data->wtmpnam_buffer)
4220             data->wtmpnam_buffer = MSVCRT_malloc(sizeof(MSVCRT_wchar_t[MAX_PATH]));
4221
4222         s = data->wtmpnam_buffer;
4223     }
4224
4225     msvcrt_int_to_base32_w(GetCurrentProcessId(), tmpstr);
4226     p = s + MSVCRT__snwprintf(s, MAX_PATH, format, tmpstr);
4227     for (count = 0; count < MSVCRT_TMP_MAX; count++)
4228     {
4229         size = msvcrt_int_to_base32_w(tmpnam_unique++, tmpstr);
4230         memcpy(p, tmpstr, size*sizeof(MSVCRT_wchar_t));
4231         p[size] = '\0';
4232         if (GetFileAttributesW(s) == INVALID_FILE_ATTRIBUTES &&
4233                 GetLastError() == ERROR_FILE_NOT_FOUND)
4234             break;
4235     }
4236     return s;
4237 }
4238
4239 /*********************************************************************
4240  *              tmpfile (MSVCRT.@)
4241  */
4242 MSVCRT_FILE* CDECL MSVCRT_tmpfile(void)
4243 {
4244   char *filename = MSVCRT_tmpnam(NULL);
4245   int fd;
4246   MSVCRT_FILE* file = NULL;
4247
4248   LOCK_FILES();
4249   fd = MSVCRT__open(filename, MSVCRT__O_CREAT | MSVCRT__O_BINARY | MSVCRT__O_RDWR | MSVCRT__O_TEMPORARY,
4250           MSVCRT__S_IREAD | MSVCRT__S_IWRITE);
4251   if (fd != -1 && (file = msvcrt_alloc_fp()))
4252   {
4253     if (msvcrt_init_fp(file, fd, MSVCRT__IORW) == -1)
4254     {
4255         file->_flag = 0;
4256         file = NULL;
4257     }
4258     else file->_tmpfname = MSVCRT__strdup(filename);
4259   }
4260
4261   if(fd != -1 && !file)
4262       MSVCRT__close(fd);
4263   UNLOCK_FILES();
4264   return file;
4265 }
4266
4267 /*********************************************************************
4268  *      tmpfile_s (MSVCRT.@)
4269  */
4270 int CDECL MSVCRT_tmpfile_s(MSVCRT_FILE** file)
4271 {
4272     if (!MSVCRT_CHECK_PMT(file != NULL)) return MSVCRT_EINVAL;
4273
4274     *file = MSVCRT_tmpfile();
4275     return 0;
4276 }
4277
4278 static int puts_clbk_file_a(void *file, int len, const char *str)
4279 {
4280     return MSVCRT_fwrite(str, sizeof(char), len, file);
4281 }
4282
4283 static int puts_clbk_file_w(void *file, int len, const MSVCRT_wchar_t *str)
4284 {
4285     int i, ret;
4286
4287     MSVCRT__lock_file(file);
4288
4289     if(!(msvcrt_get_ioinfo(((MSVCRT_FILE*)file)->_file)->wxflag & WX_TEXT)) {
4290         ret = MSVCRT_fwrite(str, sizeof(MSVCRT_wchar_t), len, file);
4291         MSVCRT__unlock_file(file);
4292         return ret;
4293     }
4294
4295     for(i=0; i<len; i++) {
4296         if(MSVCRT_fputwc(str[i], file) == MSVCRT_WEOF) {
4297             MSVCRT__unlock_file(file);
4298             return -1;
4299         }
4300     }
4301
4302     MSVCRT__unlock_file(file);
4303     return len;
4304 }
4305
4306 /*********************************************************************
4307  *              vfprintf (MSVCRT.@)
4308  */
4309 int CDECL MSVCRT_vfprintf(MSVCRT_FILE* file, const char *format, __ms_va_list valist)
4310 {
4311     BOOL tmp_buf;
4312     int ret;
4313
4314     MSVCRT__lock_file(file);
4315     tmp_buf = add_std_buffer(file);
4316     ret = pf_printf_a(puts_clbk_file_a, file, format, NULL, FALSE, FALSE, arg_clbk_valist, NULL, &valist);
4317     if(tmp_buf) remove_std_buffer(file);
4318     MSVCRT__unlock_file(file);
4319
4320     return ret;
4321 }
4322
4323 /*********************************************************************
4324  *              vfprintf_s (MSVCRT.@)
4325  */
4326 int CDECL MSVCRT_vfprintf_s(MSVCRT_FILE* file, const char *format, __ms_va_list valist)
4327 {
4328     BOOL tmp_buf;
4329     int ret;
4330
4331     if(!MSVCRT_CHECK_PMT(file != NULL)) return -1;
4332
4333     MSVCRT__lock_file(file);
4334     tmp_buf = add_std_buffer(file);
4335     ret = pf_printf_a(puts_clbk_file_a, file, format, NULL, FALSE, TRUE, arg_clbk_valist, NULL, &valist);
4336     if(tmp_buf) remove_std_buffer(file);
4337     MSVCRT__unlock_file(file);
4338
4339     return ret;
4340 }
4341
4342 /*********************************************************************
4343  *              vfwprintf (MSVCRT.@)
4344  */
4345 int CDECL MSVCRT_vfwprintf(MSVCRT_FILE* file, const MSVCRT_wchar_t *format, __ms_va_list valist)
4346 {
4347     BOOL tmp_buf;
4348     int ret;
4349
4350     MSVCRT__lock_file(file);
4351     tmp_buf = add_std_buffer(file);
4352     ret = pf_printf_w(puts_clbk_file_w, file, format, NULL, FALSE, FALSE, arg_clbk_valist, NULL, &valist);
4353     if(tmp_buf) remove_std_buffer(file);
4354     MSVCRT__unlock_file(file);
4355
4356     return ret;
4357 }
4358
4359 /*********************************************************************
4360  *              vfwprintf_s (MSVCRT.@)
4361  */
4362 int CDECL MSVCRT_vfwprintf_s(MSVCRT_FILE* file, const MSVCRT_wchar_t *format, __ms_va_list valist)
4363 {
4364     BOOL tmp_buf;
4365     int ret;
4366
4367     if (!MSVCRT_CHECK_PMT( file != NULL )) return -1;
4368
4369     MSVCRT__lock_file(file);
4370     tmp_buf = add_std_buffer(file);
4371     ret = pf_printf_w(puts_clbk_file_w, file, format, NULL, FALSE, TRUE, arg_clbk_valist, NULL, &valist);
4372     if(tmp_buf) remove_std_buffer(file);
4373     MSVCRT__unlock_file(file);
4374
4375     return ret;
4376 }
4377
4378 /*********************************************************************
4379  *              _vfwprintf_l (MSVCRT.@)
4380  */
4381 int CDECL MSVCRT__vfwprintf_l(MSVCRT_FILE* file, const MSVCRT_wchar_t *format,
4382         MSVCRT__locale_t locale, __ms_va_list valist)
4383 {
4384     BOOL tmp_buf;
4385     int ret;
4386
4387     if (!MSVCRT_CHECK_PMT( file != NULL )) return -1;
4388
4389     MSVCRT__lock_file(file);
4390     tmp_buf = add_std_buffer(file);
4391     ret = pf_printf_w(puts_clbk_file_w, file, format, locale, FALSE, FALSE, arg_clbk_valist, NULL, &valist);
4392     if(tmp_buf) remove_std_buffer(file);
4393     MSVCRT__unlock_file(file);
4394
4395     return ret;
4396 }
4397
4398 /*********************************************************************
4399  *              vprintf (MSVCRT.@)
4400  */
4401 int CDECL MSVCRT_vprintf(const char *format, __ms_va_list valist)
4402 {
4403   return MSVCRT_vfprintf(MSVCRT_stdout,format,valist);
4404 }
4405
4406 /*********************************************************************
4407  *              vprintf_s (MSVCRT.@)
4408  */
4409 int CDECL MSVCRT_vprintf_s(const char *format, __ms_va_list valist)
4410 {
4411   return MSVCRT_vfprintf_s(MSVCRT_stdout,format,valist);
4412 }
4413
4414 /*********************************************************************
4415  *              vwprintf (MSVCRT.@)
4416  */
4417 int CDECL MSVCRT_vwprintf(const MSVCRT_wchar_t *format, __ms_va_list valist)
4418 {
4419   return MSVCRT_vfwprintf(MSVCRT_stdout,format,valist);
4420 }
4421
4422 /*********************************************************************
4423  *              vwprintf_s (MSVCRT.@)
4424  */
4425 int CDECL MSVCRT_vwprintf_s(const MSVCRT_wchar_t *format, __ms_va_list valist)
4426 {
4427   return MSVCRT_vfwprintf_s(MSVCRT_stdout,format,valist);
4428 }
4429
4430 /*********************************************************************
4431  *              fprintf (MSVCRT.@)
4432  */
4433 int CDECL MSVCRT_fprintf(MSVCRT_FILE* file, const char *format, ...)
4434 {
4435     __ms_va_list valist;
4436     int res;
4437     __ms_va_start(valist, format);
4438     res = MSVCRT_vfprintf(file, format, valist);
4439     __ms_va_end(valist);
4440     return res;
4441 }
4442
4443 /*********************************************************************
4444  *              fprintf_s (MSVCRT.@)
4445  */
4446 int CDECL MSVCRT_fprintf_s(MSVCRT_FILE* file, const char *format, ...)
4447 {
4448     __ms_va_list valist;
4449     int res;
4450     __ms_va_start(valist, format);
4451     res = MSVCRT_vfprintf_s(file, format, valist);
4452     __ms_va_end(valist);
4453     return res;
4454 }
4455
4456 /*********************************************************************
4457  *              fwprintf (MSVCRT.@)
4458  */
4459 int CDECL MSVCRT_fwprintf(MSVCRT_FILE* file, const MSVCRT_wchar_t *format, ...)
4460 {
4461     __ms_va_list valist;
4462     int res;
4463     __ms_va_start(valist, format);
4464     res = MSVCRT_vfwprintf(file, format, valist);
4465     __ms_va_end(valist);
4466     return res;
4467 }
4468
4469 /*********************************************************************
4470  *              fwprintf_s (MSVCRT.@)
4471  */
4472 int CDECL MSVCRT_fwprintf_s(MSVCRT_FILE* file, const MSVCRT_wchar_t *format, ...)
4473 {
4474     __ms_va_list valist;
4475     int res;
4476     __ms_va_start(valist, format);
4477     res = MSVCRT_vfwprintf_s(file, format, valist);
4478     __ms_va_end(valist);
4479     return res;
4480 }
4481
4482 /*********************************************************************
4483  *              _fwprintf_l (MSVCRT.@)
4484  */
4485 int CDECL MSVCRT__fwprintf_l(MSVCRT_FILE* file, const MSVCRT_wchar_t *format, MSVCRT__locale_t locale, ...)
4486 {
4487     __ms_va_list valist;
4488     int res;
4489     __ms_va_start(valist, locale);
4490     res = MSVCRT__vfwprintf_l(file, format, locale, valist);
4491     __ms_va_end(valist);
4492     return res;
4493 }
4494
4495 /*********************************************************************
4496  *              printf (MSVCRT.@)
4497  */
4498 int CDECL MSVCRT_printf(const char *format, ...)
4499 {
4500     __ms_va_list valist;
4501     int res;
4502     __ms_va_start(valist, format);
4503     res = MSVCRT_vfprintf(MSVCRT_stdout, format, valist);
4504     __ms_va_end(valist);
4505     return res;
4506 }
4507
4508 /*********************************************************************
4509  *              printf_s (MSVCRT.@)
4510  */
4511 int CDECL MSVCRT_printf_s(const char *format, ...)
4512 {
4513     __ms_va_list valist;
4514     int res;
4515     __ms_va_start(valist, format);
4516     res = MSVCRT_vprintf_s(format, valist);
4517     __ms_va_end(valist);
4518     return res;
4519 }
4520
4521 /*********************************************************************
4522  *              ungetc (MSVCRT.@)
4523  */
4524 int CDECL MSVCRT_ungetc(int c, MSVCRT_FILE * file)
4525 {
4526     if (c == MSVCRT_EOF)
4527         return MSVCRT_EOF;
4528
4529     MSVCRT__lock_file(file);
4530     if(file->_bufsiz == 0 && msvcrt_alloc_buffer(file))
4531         file->_ptr++;
4532     if(file->_ptr>file->_base) {
4533         file->_ptr--;
4534         *file->_ptr=c;
4535         file->_cnt++;
4536         MSVCRT_clearerr(file);
4537         MSVCRT__unlock_file(file);
4538         return c;
4539     }
4540
4541     MSVCRT__unlock_file(file);
4542     return MSVCRT_EOF;
4543 }
4544
4545 /*********************************************************************
4546  *              ungetwc (MSVCRT.@)
4547  */
4548 MSVCRT_wint_t CDECL MSVCRT_ungetwc(MSVCRT_wint_t wc, MSVCRT_FILE * file)
4549 {
4550     MSVCRT_wchar_t mwc = wc;
4551     unsigned char * pp = (unsigned char *)&mwc;
4552     int i;
4553
4554     if (wc == MSVCRT_WEOF)
4555         return MSVCRT_WEOF;
4556
4557     MSVCRT__lock_file(file);
4558     for(i=sizeof(MSVCRT_wchar_t)-1;i>=0;i--) {
4559         if(pp[i] != MSVCRT_ungetc(pp[i],file)) {
4560             MSVCRT__unlock_file(file);
4561             return MSVCRT_WEOF;
4562         }
4563     }
4564
4565     MSVCRT__unlock_file(file);
4566     return mwc;
4567 }
4568
4569 /*********************************************************************
4570  *              wprintf (MSVCRT.@)
4571  */
4572 int CDECL MSVCRT_wprintf(const MSVCRT_wchar_t *format, ...)
4573 {
4574     __ms_va_list valist;
4575     int res;
4576     __ms_va_start(valist, format);
4577     res = MSVCRT_vwprintf(format, valist);
4578     __ms_va_end(valist);
4579     return res;
4580 }
4581
4582 /*********************************************************************
4583  *              wprintf_s (MSVCRT.@)
4584  */
4585 int CDECL MSVCRT_wprintf_s(const MSVCRT_wchar_t *format, ...)
4586 {
4587     __ms_va_list valist;
4588     int res;
4589     __ms_va_start(valist, format);
4590     res = MSVCRT_vwprintf_s(format, valist);
4591     __ms_va_end(valist);
4592     return res;
4593 }
4594
4595 /*********************************************************************
4596  *              _getmaxstdio (MSVCRT.@)
4597  */
4598 int CDECL MSVCRT__getmaxstdio(void)
4599 {
4600     return MSVCRT_max_streams;
4601 }
4602
4603 /*********************************************************************
4604  *              _setmaxstdio (MSVCRT.@)
4605  */
4606 int CDECL MSVCRT__setmaxstdio(int newmax)
4607 {
4608     TRACE("%d\n", newmax);
4609
4610     if(newmax<_IOB_ENTRIES || newmax>MSVCRT_MAX_FILES || newmax<MSVCRT_stream_idx)
4611         return -1;
4612
4613     MSVCRT_max_streams = newmax;
4614     return MSVCRT_max_streams;
4615 }