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