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