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