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