Fixed varargs handling in the scanf functions (spotted by Eric
[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  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23
24 #include "config.h"
25 #include "wine/port.h"
26
27 #include <time.h>
28 #include <stdarg.h>
29 #include <stdio.h>
30 #ifdef HAVE_UNISTD_H
31 # include <unistd.h>
32 #endif
33
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winreg.h"
37 #include "winternl.h"
38 #include "msvcrt.h"
39 #include "msvcrt/errno.h"
40
41 #include "wine/unicode.h"
42 #include "msvcrt/direct.h"
43 #include "msvcrt/fcntl.h"
44 #include "msvcrt/io.h"
45 #include "msvcrt/sys/locking.h"
46 #include "msvcrt/stdio.h"
47 #include "msvcrt/stdlib.h"
48 #include "msvcrt/string.h"
49 #include "msvcrt/sys/stat.h"
50 #include "msvcrt/sys/utime.h"
51 #include "msvcrt/time.h"
52 #include "msvcrt/share.h"
53 #include "msvcrt/wctype.h"
54
55 #include "wine/debug.h"
56
57 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
58
59 /* for stat mode, permissions apply to all,owner and group */
60 #define MSVCRT_S_IREAD  (_S_IREAD  | (_S_IREAD  >> 3) | (_S_IREAD  >> 6))
61 #define MSVCRT_S_IWRITE (_S_IWRITE | (_S_IWRITE >> 3) | (_S_IWRITE >> 6))
62 #define MSVCRT_S_IEXEC  (_S_IEXEC  | (_S_IEXEC  >> 3) | (_S_IEXEC  >> 6))
63
64 /* _access() bit flags FIXME: incomplete */
65 #define MSVCRT_W_OK      0x02
66
67
68 /* FIXME: Make this dynamic */
69 #define MSVCRT_MAX_FILES 257
70
71 HANDLE MSVCRT_handles[MSVCRT_MAX_FILES];
72 MSVCRT_FILE* MSVCRT_files[MSVCRT_MAX_FILES];
73 int  MSVCRT_flags[MSVCRT_MAX_FILES];
74 char *MSVCRT_tempfiles[MSVCRT_MAX_FILES];
75 MSVCRT_FILE MSVCRT__iob[3];
76
77 static int MSVCRT_fdstart = 3; /* first unallocated fd */
78 static int MSVCRT_fdend = 3; /* highest allocated fd */
79
80 /* INTERNAL: process umask */
81 static int MSVCRT_umask = 0;
82
83 /* INTERNAL: Static buffer for temp file name */
84 static char MSVCRT_tmpname[MAX_PATH];
85
86 static const unsigned int EXE = 'e' << 16 | 'x' << 8 | 'e';
87 static const unsigned int BAT = 'b' << 16 | 'a' << 8 | 't';
88 static const unsigned int CMD = 'c' << 16 | 'm' << 8 | 'd';
89 static const unsigned int COM = 'c' << 16 | 'o' << 8 | 'm';
90
91 #define TOUL(x) (ULONGLONG)(x)
92 static const ULONGLONG WCEXE = TOUL('e') << 32 | TOUL('x') << 16 | TOUL('e');
93 static const ULONGLONG WCBAT = TOUL('b') << 32 | TOUL('a') << 16 | TOUL('t');
94 static const ULONGLONG WCCMD = TOUL('c') << 32 | TOUL('m') << 16 | TOUL('d');
95 static const ULONGLONG WCCOM = TOUL('c') << 32 | TOUL('o') << 16 | TOUL('m');
96
97 extern CRITICAL_SECTION MSVCRT_file_cs;
98 #define LOCK_FILES     EnterCriticalSection(&MSVCRT_file_cs)
99 #define UNLOCK_FILES   LeaveCriticalSection(&MSVCRT_file_cs)
100
101 static void msvcrt_cp_from_stati64(const struct _stati64 *bufi64, struct _stat *buf)
102 {
103     buf->st_dev   = bufi64->st_dev;
104     buf->st_ino   = bufi64->st_ino;
105     buf->st_mode  = bufi64->st_mode;
106     buf->st_nlink = bufi64->st_nlink;
107     buf->st_uid   = bufi64->st_uid;
108     buf->st_gid   = bufi64->st_gid;
109     buf->st_rdev  = bufi64->st_rdev;
110     buf->st_size  = bufi64->st_size;
111     buf->st_atime = bufi64->st_atime;
112     buf->st_mtime = bufi64->st_mtime;
113     buf->st_ctime = bufi64->st_ctime;
114 }
115
116 /* INTERNAL: Get the HANDLE for a fd */
117 static HANDLE msvcrt_fdtoh(int fd)
118 {
119   if (fd < 0 || fd >= MSVCRT_fdend ||
120       MSVCRT_handles[fd] == INVALID_HANDLE_VALUE)
121   {
122     WARN(":fd (%d) - no handle!\n",fd);
123     *__doserrno() = 0;
124     *MSVCRT__errno() = MSVCRT_EBADF;
125    return INVALID_HANDLE_VALUE;
126   }
127   return MSVCRT_handles[fd];
128 }
129
130 /* INTERNAL: free a file entry fd */
131 static void msvcrt_free_fd(int fd)
132 {
133   MSVCRT_handles[fd] = INVALID_HANDLE_VALUE;
134   MSVCRT_files[fd] = 0;
135   MSVCRT_flags[fd] = 0;
136   TRACE(":fd (%d) freed\n",fd);
137   if (fd < 3)
138     return; /* don't use 0,1,2 for user files */
139   if (fd == MSVCRT_fdend - 1)
140     MSVCRT_fdend--;
141   if (fd < MSVCRT_fdstart)
142     MSVCRT_fdstart = fd;
143 }
144
145 /* INTERNAL: Allocate an fd slot from a Win32 HANDLE */
146 static int msvcrt_alloc_fd(HANDLE hand, int flag)
147 {
148   int fd = MSVCRT_fdstart;
149
150   TRACE(":handle (%p) allocating fd (%d)\n",hand,fd);
151   if (fd >= MSVCRT_MAX_FILES)
152   {
153     WARN(":files exhausted!\n");
154     return -1;
155   }
156   MSVCRT_handles[fd] = hand;
157   MSVCRT_flags[fd] = flag;
158
159   /* locate next free slot */
160   if (fd == MSVCRT_fdend)
161     MSVCRT_fdstart = ++MSVCRT_fdend;
162   else
163     while(MSVCRT_fdstart < MSVCRT_fdend &&
164           MSVCRT_handles[MSVCRT_fdstart] != INVALID_HANDLE_VALUE)
165       MSVCRT_fdstart++;
166
167   return fd;
168 }
169
170 /* INTERNAL: Allocate a FILE* for an fd slot
171  * This is done lazily to avoid memory wastage for low level open/write
172  * usage when a FILE* is not requested (but may be later).
173  */
174 static MSVCRT_FILE* msvcrt_alloc_fp(int fd)
175 {
176   TRACE(":fd (%d) allocating FILE*\n",fd);
177   if (fd < 0 || fd >= MSVCRT_fdend ||
178       MSVCRT_handles[fd] == INVALID_HANDLE_VALUE)
179   {
180     WARN(":invalid fd %d\n",fd);
181     *__doserrno() = 0;
182     *MSVCRT__errno() = MSVCRT_EBADF;
183     return NULL;
184   }
185   if (!MSVCRT_files[fd])
186   {
187     if ((MSVCRT_files[fd] = MSVCRT_calloc(sizeof(MSVCRT_FILE),1)))
188     {
189       MSVCRT_files[fd]->_file = fd;
190       MSVCRT_files[fd]->_flag = MSVCRT_flags[fd];
191       MSVCRT_files[fd]->_flag &= ~MSVCRT__IOAPPEND; /* mask out, see above */
192     }
193   }
194   TRACE(":got FILE* (%p)\n",MSVCRT_files[fd]);
195   return MSVCRT_files[fd];
196 }
197
198
199 /* INTERNAL: Set up stdin, stderr and stdout */
200 void msvcrt_init_io(void)
201 {
202   int i;
203   memset(MSVCRT__iob,0,3*sizeof(MSVCRT_FILE));
204   DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_INPUT_HANDLE),
205     GetCurrentProcess(), &MSVCRT_handles[0], 0, FALSE, DUPLICATE_SAME_ACCESS);
206   MSVCRT_flags[0] = MSVCRT__iob[0]._flag = MSVCRT__IOREAD;
207   DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_OUTPUT_HANDLE),
208     GetCurrentProcess(), &MSVCRT_handles[1], 0, FALSE, DUPLICATE_SAME_ACCESS);
209   MSVCRT_flags[1] = MSVCRT__iob[1]._flag = MSVCRT__IOWRT;
210   DuplicateHandle(GetCurrentProcess(), GetStdHandle(STD_ERROR_HANDLE),
211     GetCurrentProcess(), &MSVCRT_handles[2], 0, FALSE, DUPLICATE_SAME_ACCESS);
212   MSVCRT_flags[2] = MSVCRT__iob[2]._flag = MSVCRT__IOWRT;
213
214   TRACE(":handles (%p)(%p)(%p)\n",MSVCRT_handles[0],
215         MSVCRT_handles[1],MSVCRT_handles[2]);
216
217   for (i = 0; i < 3; i++)
218   {
219     /* FILE structs for stdin/out/err are static and never deleted */
220     MSVCRT_files[i] = &MSVCRT__iob[i];
221     MSVCRT__iob[i]._file = i;
222     MSVCRT_tempfiles[i] = NULL;
223   }
224 }
225
226 /* free everything on process exit */
227 void msvcrt_free_io(void)
228 {
229     _fcloseall();
230     _close(0);
231     _close(1);
232     _close(2);
233 }
234
235 /* INTERNAL: Flush stdio file buffer */
236 static int msvcrt_flush_buffer(MSVCRT_FILE* file)
237 {
238   if(file->_bufsiz) {
239         int cnt=file->_ptr-file->_base;
240         if(cnt>0 && _write(file->_file, file->_base, cnt) != cnt) {
241                 return MSVCRT_EOF;
242         }
243         file->_ptr=file->_base;
244         file->_cnt=file->_bufsiz;
245   }
246   return 0;
247 }
248
249 /* INTERNAL: Allocate stdio file buffer */
250 static void msvcrt_alloc_buffer(MSVCRT_FILE* file)
251 {
252         file->_base = MSVCRT_calloc(MSVCRT_BUFSIZ,1);
253         if(file->_base) {
254                 file->_bufsiz = MSVCRT_BUFSIZ;
255                 file->_flag |= MSVCRT__IOMYBUF;
256         } else {
257                 file->_base = (unsigned char *)(&file->_charbuf);
258                 /* put here 2 ??? */
259                 file->_bufsiz = sizeof(file->_charbuf);
260         }
261         file->_ptr = file->_base;
262         file->_cnt = 0;
263 }
264
265 /* INTERNAL: Convert integer to base32 string (0-9a-v), 0 becomes "" */
266 static void msvcrt_int_to_base32(int num, char *str)
267 {
268   char *p;
269   int n = num;
270   int digits = 0;
271
272   while (n != 0)
273   {
274     n >>= 5;
275     digits++;
276   }
277   p = str + digits;
278   *p = 0;
279   while (--p >= str)
280   {
281     *p = (num & 31) + '0';
282     if (*p > '9')
283       *p += ('a' - '0' - 10);
284     num >>= 5;
285   }
286 }
287
288 /*********************************************************************
289  *              __p__iob(MSVCRT.@)
290  */
291 MSVCRT_FILE *__p__iob(void)
292 {
293  return &MSVCRT__iob[0];
294 }
295
296 /*********************************************************************
297  *              _access (MSVCRT.@)
298  */
299 int _access(const char *filename, int mode)
300 {
301   DWORD attr = GetFileAttributesA(filename);
302
303   TRACE("(%s,%d) %ld\n",filename,mode,attr);
304
305   if (!filename || attr == INVALID_FILE_ATTRIBUTES)
306   {
307     MSVCRT__set_errno(GetLastError());
308     return -1;
309   }
310   if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & MSVCRT_W_OK))
311   {
312     MSVCRT__set_errno(ERROR_ACCESS_DENIED);
313     return -1;
314   }
315   return 0;
316 }
317
318 /*********************************************************************
319  *              _waccess (MSVCRT.@)
320  */
321 int _waccess(const MSVCRT_wchar_t *filename, int mode)
322 {
323   DWORD attr = GetFileAttributesW(filename);
324
325   TRACE("(%s,%d) %ld\n",debugstr_w(filename),mode,attr);
326
327   if (!filename || attr == INVALID_FILE_ATTRIBUTES)
328   {
329     MSVCRT__set_errno(GetLastError());
330     return -1;
331   }
332   if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & MSVCRT_W_OK))
333   {
334     MSVCRT__set_errno(ERROR_ACCESS_DENIED);
335     return -1;
336   }
337   return 0;
338 }
339
340 /*********************************************************************
341  *              _chmod (MSVCRT.@)
342  */
343 int _chmod(const char *path, int flags)
344 {
345   DWORD oldFlags = GetFileAttributesA(path);
346
347   if (oldFlags != INVALID_FILE_ATTRIBUTES)
348   {
349     DWORD newFlags = (flags & _S_IWRITE)? oldFlags & ~FILE_ATTRIBUTE_READONLY:
350       oldFlags | FILE_ATTRIBUTE_READONLY;
351
352     if (newFlags == oldFlags || SetFileAttributesA(path, newFlags))
353       return 0;
354   }
355   MSVCRT__set_errno(GetLastError());
356   return -1;
357 }
358
359 /*********************************************************************
360  *              _wchmod (MSVCRT.@)
361  */
362 int _wchmod(const MSVCRT_wchar_t *path, int flags)
363 {
364   DWORD oldFlags = GetFileAttributesW(path);
365
366   if (oldFlags != INVALID_FILE_ATTRIBUTES)
367   {
368     DWORD newFlags = (flags & _S_IWRITE)? oldFlags & ~FILE_ATTRIBUTE_READONLY:
369       oldFlags | FILE_ATTRIBUTE_READONLY;
370
371     if (newFlags == oldFlags || SetFileAttributesW(path, newFlags))
372       return 0;
373   }
374   MSVCRT__set_errno(GetLastError());
375   return -1;
376 }
377
378 /*********************************************************************
379  *              _chsize (MSVCRT.@)
380  */
381 int _chsize(int fd, long size)
382 {
383     FIXME("(fd=%d, size=%ld): stub\n", fd, size);
384     return -1;
385 }
386
387 /*********************************************************************
388  *              _dup (MSVCRT.@)
389  */
390 int _dup(int od)
391 {
392     FIXME("(od=%d): stub\n", od);
393     return -1;
394 }
395
396 /*********************************************************************
397  *              _dup2 (MSVCRT.@)
398  */
399 int _dup2(int od, int nd)
400 {
401     FIXME("(od=%d, nd=%d): stub\n", od, nd);
402     return -1;
403 }
404
405 /*********************************************************************
406  *              _unlink (MSVCRT.@)
407  */
408 int _unlink(const char *path)
409 {
410   TRACE("(%s)\n",path);
411   if(DeleteFileA(path))
412     return 0;
413   TRACE("failed (%ld)\n",GetLastError());
414   MSVCRT__set_errno(GetLastError());
415   return -1;
416 }
417
418 /*********************************************************************
419  *              _wunlink (MSVCRT.@)
420  */
421 int _wunlink(const MSVCRT_wchar_t *path)
422 {
423   TRACE("(%s)\n",debugstr_w(path));
424   if(DeleteFileW(path))
425     return 0;
426   TRACE("failed (%ld)\n",GetLastError());
427   MSVCRT__set_errno(GetLastError());
428   return -1;
429 }
430
431 /*********************************************************************
432  *              _close (MSVCRT.@)
433  */
434 int _close(int fd)
435 {
436   HANDLE hand = msvcrt_fdtoh(fd);
437
438   TRACE(":fd (%d) handle (%p)\n",fd,hand);
439   if (hand == INVALID_HANDLE_VALUE)
440     return -1;
441   /* flush stdio buffers */
442   if(MSVCRT_files[fd]) {
443         if(MSVCRT_files[fd]->_flag & MSVCRT__IOWRT)
444                 MSVCRT_fflush(MSVCRT_files[fd]);
445
446         if(MSVCRT_files[fd]->_flag & MSVCRT__IOMYBUF)
447                 MSVCRT_free(MSVCRT_files[fd]->_base);
448   }
449
450   /* Don't free std FILE*'s, they are not dynamic */
451   if (fd > 2 && MSVCRT_files[fd])
452     MSVCRT_free(MSVCRT_files[fd]);
453
454   msvcrt_free_fd(fd);
455
456   if (!CloseHandle(hand))
457   {
458     WARN(":failed-last error (%ld)\n",GetLastError());
459     MSVCRT__set_errno(GetLastError());
460     return -1;
461   }
462   if (MSVCRT_tempfiles[fd])
463   {
464     TRACE("deleting temporary file '%s'\n",MSVCRT_tempfiles[fd]);
465     _unlink(MSVCRT_tempfiles[fd]);
466     MSVCRT_free(MSVCRT_tempfiles[fd]);
467     MSVCRT_tempfiles[fd] = NULL;
468   }
469
470   TRACE(":ok\n");
471   return 0;
472 }
473
474 /*********************************************************************
475  *              _commit (MSVCRT.@)
476  */
477 int _commit(int fd)
478 {
479   HANDLE hand = msvcrt_fdtoh(fd);
480
481   TRACE(":fd (%d) handle (%p)\n",fd,hand);
482   if (hand == INVALID_HANDLE_VALUE)
483     return -1;
484
485   if (!FlushFileBuffers(hand))
486   {
487     if (GetLastError() == ERROR_INVALID_HANDLE)
488     {
489       /* FlushFileBuffers fails for console handles
490        * so we ignore this error.
491        */
492       return 0;
493     }
494     TRACE(":failed-last error (%ld)\n",GetLastError());
495     MSVCRT__set_errno(GetLastError());
496     return -1;
497   }
498   TRACE(":ok\n");
499   return 0;
500 }
501
502 /*********************************************************************
503  *              _eof (MSVCRT.@)
504  */
505 int _eof(int fd)
506 {
507   DWORD curpos,endpos;
508   HANDLE hand = msvcrt_fdtoh(fd);
509
510   TRACE(":fd (%d) handle (%p)\n",fd,hand);
511
512   if (hand == INVALID_HANDLE_VALUE)
513     return -1;
514
515   /* If we have a FILE* for this file, the EOF flag
516    * will be set by the read()/write() functions.
517    */
518   if (MSVCRT_files[fd])
519     return MSVCRT_flags[fd] & MSVCRT__IOEOF;
520
521   /* Otherwise we do it the hard way */
522   curpos = SetFilePointer(hand, 0, NULL, SEEK_CUR);
523   endpos = SetFilePointer(hand, 0, NULL, FILE_END);
524
525   if (curpos == endpos)
526     return TRUE;
527
528   SetFilePointer(hand, curpos, 0, FILE_BEGIN);
529   return FALSE;
530 }
531
532 /*********************************************************************
533  *              _fcloseall (MSVCRT.@)
534  */
535 int _fcloseall(void)
536 {
537   int num_closed = 0, i;
538
539   for (i = 3; i < MSVCRT_fdend; i++)
540     if (MSVCRT_handles[i] != INVALID_HANDLE_VALUE)
541     {
542       _close(i);
543       num_closed++;
544     }
545
546   TRACE(":closed (%d) handles\n",num_closed);
547   return num_closed;
548 }
549
550 /*********************************************************************
551  *              _lseeki64 (MSVCRT.@)
552  */
553 __int64 _lseeki64(int fd, __int64 offset, int whence)
554 {
555   DWORD ret, hoffset = (DWORD) (offset >> 32);
556   HANDLE hand = msvcrt_fdtoh(fd);
557
558   TRACE(":fd (%d) handle (%p)\n",fd,hand);
559   if (hand == INVALID_HANDLE_VALUE)
560     return -1;
561
562   if (whence < 0 || whence > 2)
563   {
564     *MSVCRT__errno() = MSVCRT_EINVAL;
565     return -1;
566   }
567
568   TRACE(":fd (%d) to 0x%08lx%08lx pos %s\n",
569         fd,hoffset,(long)offset,
570         (whence==SEEK_SET)?"SEEK_SET":
571         (whence==SEEK_CUR)?"SEEK_CUR":
572         (whence==SEEK_END)?"SEEK_END":"UNKNOWN");
573
574   if (((ret = SetFilePointer(hand, (long)offset, &hoffset,
575                              whence)) != INVALID_SET_FILE_POINTER) || !GetLastError())
576   {
577     if (MSVCRT_files[fd])
578       MSVCRT_files[fd]->_flag &= ~MSVCRT__IOEOF;
579     /* FIXME: What if we seek _to_ EOF - is EOF set? */
580
581     return ((__int64)hoffset << 32) | ret;
582   }
583   TRACE(":error-last error (%ld)\n",GetLastError());
584   if (MSVCRT_files[fd])
585     switch(GetLastError())
586     {
587     case ERROR_NEGATIVE_SEEK:
588     case ERROR_SEEK_ON_DEVICE:
589       MSVCRT__set_errno(GetLastError());
590       MSVCRT_files[fd]->_flag |= MSVCRT__IOERR;
591       break;
592     default:
593       break;
594     }
595   return -1;
596 }
597
598 /*********************************************************************
599  *              _lseek (MSVCRT.@)
600  */
601 LONG _lseek(int fd, LONG offset, int whence)
602 {
603     return _lseeki64(fd, offset, whence);
604 }
605
606 /*********************************************************************
607  *              _locking (MSVCRT.@)
608  *
609  * This is untested; the underlying LockFile doesn't work yet.
610  */
611 int _locking(int fd, int mode, LONG nbytes)
612 {
613   BOOL ret;
614   DWORD cur_locn;
615   HANDLE hand = msvcrt_fdtoh(fd);
616
617   TRACE(":fd (%d) handle (%p)\n",fd,hand);
618   if (hand == INVALID_HANDLE_VALUE)
619     return -1;
620
621   if (mode < 0 || mode > 4)
622   {
623     *MSVCRT__errno() = MSVCRT_EINVAL;
624     return -1;
625   }
626
627   TRACE(":fd (%d) by 0x%08lx mode %s\n",
628         fd,nbytes,(mode==_LK_UNLCK)?"_LK_UNLCK":
629         (mode==_LK_LOCK)?"_LK_LOCK":
630         (mode==_LK_NBLCK)?"_LK_NBLCK":
631         (mode==_LK_RLCK)?"_LK_RLCK":
632         (mode==_LK_NBRLCK)?"_LK_NBRLCK":
633                           "UNKNOWN");
634
635   if ((cur_locn = SetFilePointer(hand, 0L, NULL, SEEK_CUR)) == INVALID_SET_FILE_POINTER)
636   {
637     FIXME ("Seek failed\n");
638     *MSVCRT__errno() = MSVCRT_EINVAL; /* FIXME */
639     return -1;
640   }
641   if (mode == _LK_LOCK || mode == _LK_RLCK)
642   {
643     int nretry = 10;
644     ret = 1; /* just to satisfy gcc */
645     while (nretry--)
646     {
647       ret = LockFile(hand, cur_locn, 0L, nbytes, 0L);
648       if (ret) break;
649       sleep (1);
650     }
651   }
652   else if (mode == _LK_UNLCK)
653     ret = UnlockFile(hand, cur_locn, 0L, nbytes, 0L);
654   else
655     ret = LockFile(hand, cur_locn, 0L, nbytes, 0L);
656   /* FIXME - what about error settings? */
657   return ret ? 0 : -1;
658 }
659
660 /*********************************************************************
661  *              rewind (MSVCRT.@)
662  */
663 void MSVCRT_rewind(MSVCRT_FILE* file)
664 {
665   TRACE(":file (%p) fd (%d)\n",file,file->_file);
666   MSVCRT_fseek(file, 0L, SEEK_SET);
667   MSVCRT_clearerr(file);
668 }
669
670 /*********************************************************************
671  *              _fdopen (MSVCRT.@)
672  */
673 MSVCRT_FILE* _fdopen(int fd, const char *mode)
674 {
675   MSVCRT_FILE* file = msvcrt_alloc_fp(fd);
676
677   TRACE(":fd (%d) mode (%s) FILE* (%p)\n",fd,mode,file);
678
679   return file;
680 }
681
682 /*********************************************************************
683  *              _wfdopen (MSVCRT.@)
684  */
685 MSVCRT_FILE* _wfdopen(int fd, const MSVCRT_wchar_t *mode)
686 {
687   MSVCRT_FILE* file = msvcrt_alloc_fp(fd);
688
689   TRACE(":fd (%d) mode (%s) FILE* (%p)\n",fd,debugstr_w(mode),file);
690   if (file)
691     MSVCRT_rewind(file);
692
693   return file;
694 }
695
696 /*********************************************************************
697  *              _filelength (MSVCRT.@)
698  */
699 LONG _filelength(int fd)
700 {
701   LONG curPos = _lseek(fd, 0, SEEK_CUR);
702   if (curPos != -1)
703   {
704     LONG endPos = _lseek(fd, 0, SEEK_END);
705     if (endPos != -1)
706     {
707       if (endPos != curPos)
708         _lseek(fd, curPos, SEEK_SET);
709       return endPos;
710     }
711   }
712   return -1;
713 }
714
715 /*********************************************************************
716  *              _filelengthi64 (MSVCRT.@)
717  */
718 __int64 _filelengthi64(int fd)
719 {
720   __int64 curPos = _lseeki64(fd, 0, SEEK_CUR);
721   if (curPos != -1)
722   {
723     __int64 endPos = _lseeki64(fd, 0, SEEK_END);
724     if (endPos != -1)
725     {
726       if (endPos != curPos)
727         _lseeki64(fd, curPos, SEEK_SET);
728       return endPos;
729     }
730   }
731   return -1;
732 }
733
734 /*********************************************************************
735  *              _fileno (MSVCRT.@)
736  */
737 int _fileno(MSVCRT_FILE* file)
738 {
739   TRACE(":FILE* (%p) fd (%d)\n",file,file->_file);
740   return file->_file;
741 }
742
743 /*********************************************************************
744  *              _flushall (MSVCRT.@)
745  */
746 int _flushall(void)
747 {
748   int i, num_flushed = 0;
749
750   for (i = 3; i < MSVCRT_fdend; i++)
751     if (MSVCRT_handles[i] != INVALID_HANDLE_VALUE)
752     {
753 #if 0
754       /* FIXME: flush, do not commit */
755       if (_commit(i) == -1)
756         if (MSVCRT_files[i])
757           MSVCRT_files[i]->_flag |= MSVCRT__IOERR;
758 #endif
759       if(MSVCRT_files[i] && MSVCRT_files[i]->_flag & MSVCRT__IOWRT) {
760         MSVCRT_fflush(MSVCRT_files[i]);
761         num_flushed++;
762       }
763     }
764
765   TRACE(":flushed (%d) handles\n",num_flushed);
766   return num_flushed;
767 }
768
769 /*********************************************************************
770  *              _fstati64 (MSVCRT.@)
771  */
772 int _fstati64(int fd, struct _stati64* buf)
773 {
774   DWORD dw;
775   BY_HANDLE_FILE_INFORMATION hfi;
776   HANDLE hand = msvcrt_fdtoh(fd);
777
778   TRACE(":fd (%d) stat (%p)\n",fd,buf);
779   if (hand == INVALID_HANDLE_VALUE)
780     return -1;
781
782   if (!buf)
783   {
784     WARN(":failed-NULL buf\n");
785     MSVCRT__set_errno(ERROR_INVALID_PARAMETER);
786     return -1;
787   }
788
789   memset(&hfi, 0, sizeof(hfi));
790   memset(buf, 0, sizeof(struct _stati64));
791   if (!GetFileInformationByHandle(hand, &hfi))
792   {
793     WARN(":failed-last error (%ld)\n",GetLastError());
794     MSVCRT__set_errno(ERROR_INVALID_PARAMETER);
795     return -1;
796   }
797   FIXME(":dwFileAttributes = %ld, mode set to 0\n",hfi.dwFileAttributes);
798   buf->st_nlink = hfi.nNumberOfLinks;
799   buf->st_size  = ((__int64)hfi.nFileSizeHigh << 32) + hfi.nFileSizeLow;
800   RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastAccessTime, &dw);
801   buf->st_atime = dw;
802   RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastWriteTime, &dw);
803   buf->st_mtime = buf->st_ctime = dw;
804   return 0;
805 }
806
807 /*********************************************************************
808  *              _fstat (MSVCRT.@)
809  */
810 int MSVCRT__fstat(int fd, struct _stat* buf)
811 { int ret;
812   struct _stati64 bufi64;
813
814   ret = _fstati64(fd, &bufi64);
815   if (!ret)
816       msvcrt_cp_from_stati64(&bufi64, buf);
817   return ret;
818 }
819
820 /*********************************************************************
821  *              _futime (MSVCRT.@)
822  */
823 int _futime(int fd, struct _utimbuf *t)
824 {
825   HANDLE hand = msvcrt_fdtoh(fd);
826   FILETIME at, wt;
827
828   if (!t)
829   {
830     MSVCRT_time_t currTime;
831     MSVCRT_time(&currTime);
832     RtlSecondsSince1970ToTime(currTime, (LARGE_INTEGER *)&at);
833     memcpy(&wt, &at, sizeof(wt));
834   }
835   else
836   {
837     RtlSecondsSince1970ToTime(t->actime, (LARGE_INTEGER *)&at);
838     if (t->actime == t->modtime)
839       memcpy(&wt, &at, sizeof(wt));
840     else
841       RtlSecondsSince1970ToTime(t->modtime, (LARGE_INTEGER *)&wt);
842   }
843
844   if (!SetFileTime(hand, NULL, &at, &wt))
845   {
846     MSVCRT__set_errno(GetLastError());
847     return -1 ;
848   }
849   return 0;
850 }
851
852 /*********************************************************************
853  *              _get_osfhandle (MSVCRT.@)
854  */
855 long _get_osfhandle(int fd)
856 {
857   HANDLE hand = msvcrt_fdtoh(fd);
858   HANDLE newhand = hand;
859   TRACE(":fd (%d) handle (%p)\n",fd,hand);
860
861   if (hand != INVALID_HANDLE_VALUE)
862   {
863     /* FIXME: I'm not convinced that I should be copying the
864      * handle here - it may be leaked if the app doesn't
865      * close it (and the API docs don't say that it should)
866      * Not duplicating it means that it can't be inherited
867      * and so lcc's wedit doesn't cope when it passes it to
868      * child processes. I've an idea that it should either
869      * be copied by CreateProcess, or marked as inheritable
870      * when initialised, or maybe both? JG 21-9-00.
871      */
872     DuplicateHandle(GetCurrentProcess(),hand,GetCurrentProcess(),
873                     &newhand,0,TRUE,DUPLICATE_SAME_ACCESS);
874   }
875   return (long)newhand;
876 }
877
878 /*********************************************************************
879  *              _isatty (MSVCRT.@)
880  */
881 int _isatty(int fd)
882 {
883   HANDLE hand = msvcrt_fdtoh(fd);
884
885   TRACE(":fd (%d) handle (%p)\n",fd,hand);
886   if (hand == INVALID_HANDLE_VALUE)
887     return 0;
888
889   return GetFileType(hand) == FILE_TYPE_CHAR? 1 : 0;
890 }
891
892 /*********************************************************************
893  *              _mktemp (MSVCRT.@)
894  */
895 char *_mktemp(char *pattern)
896 {
897   int numX = 0;
898   char *retVal = pattern;
899   int id;
900   char letter = 'a';
901
902   while(*pattern)
903     numX = (*pattern++ == 'X')? numX + 1 : 0;
904   if (numX < 5)
905     return NULL;
906   pattern--;
907   id = GetCurrentProcessId();
908   numX = 6;
909   while(numX--)
910   {
911     int tempNum = id / 10;
912     *pattern-- = id - (tempNum * 10) + '0';
913     id = tempNum;
914   }
915   pattern++;
916   do
917   {
918     if (GetFileAttributesA(retVal) == INVALID_FILE_ATTRIBUTES &&
919         GetLastError() == ERROR_FILE_NOT_FOUND)
920       return retVal;
921     *pattern = letter++;
922   } while(letter != '|');
923   return NULL;
924 }
925
926 /*********************************************************************
927  *              _wmktemp (MSVCRT.@)
928  */
929 MSVCRT_wchar_t *_wmktemp(MSVCRT_wchar_t *pattern)
930 {
931   int numX = 0;
932   MSVCRT_wchar_t *retVal = pattern;
933   int id;
934   MSVCRT_wchar_t letter = 'a';
935
936   while(*pattern)
937     numX = (*pattern++ == 'X')? numX + 1 : 0;
938   if (numX < 5)
939     return NULL;
940   pattern--;
941   id = GetCurrentProcessId();
942   numX = 6;
943   while(numX--)
944   {
945     int tempNum = id / 10;
946     *pattern-- = id - (tempNum * 10) + '0';
947     id = tempNum;
948   }
949   pattern++;
950   do
951   {
952     if (GetFileAttributesW(retVal) == INVALID_FILE_ATTRIBUTES &&
953         GetLastError() == ERROR_FILE_NOT_FOUND)
954       return retVal;
955     *pattern = letter++;
956   } while(letter != '|');
957   return NULL;
958 }
959
960 /*********************************************************************
961  *              _sopen (MSVCRT.@)
962  */
963 int MSVCRT__sopen( const char *path, int oflags, int shflags, ... )
964 {
965   va_list ap;
966   int pmode;
967   DWORD access = 0, creation = 0;
968   DWORD sharing;
969   int ioflag = 0, fd;
970   HANDLE hand;
971   SECURITY_ATTRIBUTES sa;
972
973
974   TRACE(":file (%s) oflags: 0x%04x shflags: 0x%04x\n",
975         path, oflags, shflags);
976
977   switch(oflags & (_O_RDONLY | _O_WRONLY | _O_RDWR))
978   {
979   case _O_RDONLY:
980     access |= GENERIC_READ;
981     ioflag |= MSVCRT__IOREAD;
982     break;
983   case _O_WRONLY:
984     access |= GENERIC_WRITE;
985     ioflag |= MSVCRT__IOWRT;
986     break;
987   case _O_RDWR:
988     access |= GENERIC_WRITE | GENERIC_READ;
989     ioflag |= MSVCRT__IORW;
990     break;
991   }
992
993   if (oflags & _O_CREAT)
994   {
995     va_start(ap, shflags);
996       pmode = va_arg(ap, int);
997     va_end(ap);
998
999     if(pmode & ~(_S_IREAD | _S_IWRITE))
1000       FIXME(": pmode 0x%04x ignored\n", pmode);
1001     else
1002       WARN(": pmode 0x%04x ignored\n", pmode);
1003
1004     if (oflags & _O_EXCL)
1005       creation = CREATE_NEW;
1006     else if (oflags & _O_TRUNC)
1007       creation = CREATE_ALWAYS;
1008     else
1009       creation = OPEN_ALWAYS;
1010   }
1011   else  /* no _O_CREAT */
1012   {
1013     if (oflags & _O_TRUNC)
1014       creation = TRUNCATE_EXISTING;
1015     else
1016       creation = OPEN_EXISTING;
1017   }
1018   if (oflags & _O_APPEND)
1019     ioflag |= MSVCRT__IOAPPEND;
1020
1021   if (oflags & _O_BINARY)
1022     ioflag |= _O_BINARY;
1023   else if (oflags & _O_TEXT)
1024     ioflag |= _O_TEXT;
1025   else if (*__p__fmode() & _O_BINARY)
1026     ioflag |= _O_BINARY;
1027   else
1028     ioflag |= _O_TEXT; /* default to TEXT*/
1029   
1030   switch( shflags )
1031   {
1032     case _SH_DENYRW:
1033       sharing = 0L;
1034       break;
1035     case _SH_DENYWR:
1036       sharing = FILE_SHARE_READ;
1037       break;
1038     case _SH_DENYRD:
1039       sharing = FILE_SHARE_WRITE;
1040       break;
1041     case _SH_DENYNO:
1042       sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
1043       break;
1044     default:
1045       ERR( "Unhandled shflags 0x%x\n", shflags );
1046       return -1;
1047   }
1048
1049   if (oflags & ~(_O_BINARY|_O_TEXT|_O_APPEND|_O_TRUNC|_O_EXCL
1050                 |_O_CREAT|_O_RDWR|_O_WRONLY|_O_TEMPORARY|_O_NOINHERIT))
1051     ERR(":unsupported oflags 0x%04x\n",oflags);
1052
1053   sa.nLength              = sizeof( SECURITY_ATTRIBUTES );
1054   sa.lpSecurityDescriptor = NULL;
1055   sa.bInheritHandle       = (oflags & _O_NOINHERIT) ? FALSE : TRUE;
1056
1057   hand = CreateFileA(path, access, sharing,
1058                       &sa, creation, FILE_ATTRIBUTE_NORMAL, 0);
1059
1060   if (hand == INVALID_HANDLE_VALUE)  {
1061     WARN(":failed-last error (%ld)\n",GetLastError());
1062     MSVCRT__set_errno(GetLastError());
1063     return -1;
1064   }
1065
1066   fd = msvcrt_alloc_fd(hand, ioflag);
1067
1068   TRACE(":fd (%d) handle (%p)\n",fd, hand);
1069
1070   if (fd > 0)
1071   {
1072     if (oflags & _O_TEMPORARY)
1073       MSVCRT_tempfiles[fd] = _strdup(path);
1074     if (ioflag & MSVCRT__IOAPPEND)
1075       _lseek(fd, 0, FILE_END);
1076   }
1077
1078   return fd;
1079 }
1080
1081 /*********************************************************************
1082  *              _wsopen (MSVCRT.@)
1083  */
1084 int MSVCRT__wsopen( const MSVCRT_wchar_t* path, int oflags, int shflags, ... )
1085 {
1086   const unsigned int len = strlenW(path);
1087   char *patha = MSVCRT_calloc(len + 1,1);
1088   va_list ap;
1089   int pmode;
1090
1091   va_start(ap, shflags);
1092   pmode = va_arg(ap, int);
1093   va_end(ap);
1094
1095   if (patha && WideCharToMultiByte(CP_ACP,0,path,len,patha,len,NULL,NULL))
1096   {
1097     int retval = MSVCRT__sopen(patha,oflags,shflags,pmode);
1098     MSVCRT_free(patha);
1099     return retval;
1100   }
1101
1102   MSVCRT__set_errno(GetLastError());
1103   return -1;
1104 }
1105
1106 /*********************************************************************
1107  *              _open (MSVCRT.@)
1108  */
1109 int _open( const char *path, int flags, ... )
1110 {
1111   va_list ap;
1112
1113   if (flags & _O_CREAT)
1114   {
1115     int pmode;
1116     va_start(ap, flags);
1117     pmode = va_arg(ap, int);
1118     va_end(ap);
1119     return MSVCRT__sopen( path, flags, _SH_DENYNO, pmode );
1120   }
1121   else
1122     return MSVCRT__sopen( path, flags, _SH_DENYNO);
1123 }
1124
1125 /*********************************************************************
1126  *              _wopen (MSVCRT.@)
1127  */
1128 int _wopen(const MSVCRT_wchar_t *path,int flags,...)
1129 {
1130   const unsigned int len = strlenW(path);
1131   char *patha = MSVCRT_calloc(len + 1,1);
1132   va_list ap;
1133   int pmode;
1134
1135   va_start(ap, flags);
1136   pmode = va_arg(ap, int);
1137   va_end(ap);
1138
1139   if (patha && WideCharToMultiByte(CP_ACP,0,path,len,patha,len,NULL,NULL))
1140   {
1141     int retval = _open(patha,flags,pmode);
1142     MSVCRT_free(patha);
1143     return retval;
1144   }
1145
1146   MSVCRT__set_errno(GetLastError());
1147   return -1;
1148 }
1149
1150 /*********************************************************************
1151  *              _creat (MSVCRT.@)
1152  */
1153 int _creat(const char *path, int flags)
1154 {
1155   int usedFlags = (flags & _O_TEXT)| _O_CREAT| _O_WRONLY| _O_TRUNC;
1156   return _open(path, usedFlags);
1157 }
1158
1159 /*********************************************************************
1160  *              _wcreat (MSVCRT.@)
1161  */
1162 int _wcreat(const MSVCRT_wchar_t *path, int flags)
1163 {
1164   int usedFlags = (flags & _O_TEXT)| _O_CREAT| _O_WRONLY| _O_TRUNC;
1165   return _wopen(path, usedFlags);
1166 }
1167
1168 /*********************************************************************
1169  *              _open_osfhandle (MSVCRT.@)
1170  */
1171 int _open_osfhandle(long hand, int flags)
1172 {
1173   int fd;
1174
1175   /* _O_RDONLY (0) always matches, so set the read flag
1176    * MFC's CStdioFile clears O_RDONLY (0)! if it wants to write to the
1177    * file, so set the write flag. It also only sets _O_TEXT if it wants
1178    * text - it never sets _O_BINARY.
1179    */
1180   /* FIXME: handle more flags */
1181   flags |= MSVCRT__IOREAD|MSVCRT__IOWRT;
1182   if ( !( flags & _O_TEXT ) ) flags |= _O_BINARY;
1183
1184   fd = msvcrt_alloc_fd((HANDLE)hand,flags);
1185   TRACE(":handle (%ld) fd (%d) flags 0x%08x\n",hand,fd, flags);
1186   return fd;
1187 }
1188
1189 /*********************************************************************
1190  *              _rmtmp (MSVCRT.@)
1191  */
1192 int _rmtmp(void)
1193 {
1194   int num_removed = 0, i;
1195
1196   for (i = 3; i < MSVCRT_fdend; i++)
1197     if (MSVCRT_tempfiles[i])
1198     {
1199       _close(i);
1200       num_removed++;
1201     }
1202
1203   if (num_removed)
1204     TRACE(":removed (%d) temp files\n",num_removed);
1205   return num_removed;
1206 }
1207
1208 /*********************************************************************
1209  * (internal) remove_cr
1210  *
1211  *    Remove all \r inplace.
1212  * return the number of \r removed
1213  */
1214 static unsigned int remove_cr(char *buf, unsigned int count)
1215 {
1216     unsigned int i, j;
1217
1218     for (i = 0; i < count; i++) if (buf[i] == '\r') break;
1219     for (j = i + 1; j < count; j++) if (buf[j] != '\r') buf[i++] = buf[j];
1220     return count - i;
1221 }
1222
1223 /*********************************************************************
1224  *              _read (MSVCRT.@)
1225  */
1226 int _read(int fd, void *buf, unsigned int count)
1227 {
1228   DWORD num_read, all_read =0;
1229   char *bufstart = buf;
1230   HANDLE hand = msvcrt_fdtoh(fd);
1231
1232   /* Don't trace small reads, it gets *very* annoying */
1233   if (count > 4)
1234     TRACE(":fd (%d) handle (%p) buf (%p) len (%d)\n",fd,hand,buf,count);
1235   if (hand == INVALID_HANDLE_VALUE)
1236     return -1;
1237
1238   /* Reading single bytes in O_TEXT mode makes things slow
1239    * So read big chunks, then remove the \r in memory and try reading
1240    * the rest until the request is satisfied or EOF is met
1241    */
1242   while (  all_read < count)
1243   {
1244       if (ReadFile(hand, bufstart+all_read, count - all_read, &num_read, NULL))
1245       {
1246           if (num_read != (count- all_read))
1247           {
1248               TRACE(":EOF\n");
1249               if ( MSVCRT_files[fd])
1250               {
1251                   MSVCRT_flags[fd] |= MSVCRT__IOEOF;
1252                   /*
1253                     MSVCRT_files[fd]->_flag |= MSVCRT__IOEOF;
1254                   */
1255               }
1256               if ((MSVCRT_flags[fd]& _O_BINARY ) !=  _O_BINARY )
1257                   num_read -= remove_cr(bufstart+all_read,num_read);
1258               all_read += num_read;
1259               if (count > 4)
1260                   TRACE("%s\n",debugstr_an(buf,all_read));
1261               return all_read;
1262           }
1263           if ((MSVCRT_flags[fd]& _O_BINARY ) !=  _O_BINARY )
1264           {
1265               num_read -= remove_cr(bufstart+all_read,num_read);
1266           }
1267           all_read += num_read;
1268       }
1269       else
1270       {
1271           TRACE(":failed-last error (%ld)\n",GetLastError());
1272           if (MSVCRT_files[fd])
1273               MSVCRT_files[fd]->_flag |= MSVCRT__IOERR;
1274           return -1;
1275       }
1276   }
1277
1278   if (count > 4)
1279       TRACE("%s\n",debugstr_an(buf, all_read));
1280   return all_read;
1281 }
1282
1283 /*********************************************************************
1284  *              _getw (MSVCRT.@)
1285  */
1286 int _getw(MSVCRT_FILE* file)
1287 {
1288   int i;
1289   if (_read(file->_file, &i, sizeof(int)) != 1)
1290     return MSVCRT_EOF;
1291   return i;
1292 }
1293
1294 /*********************************************************************
1295  *              _setmode (MSVCRT.@)
1296  */
1297 int _setmode(int fd,int mode)
1298 {
1299   int ret = MSVCRT_flags[fd] & (_O_TEXT | _O_BINARY);
1300   if (mode & (~(_O_TEXT|_O_BINARY)))
1301     FIXME("fd (%d) mode (0x%08x) unknown\n",fd,mode);
1302   MSVCRT_flags[fd] &= ~(_O_TEXT|_O_BINARY);
1303   MSVCRT_flags[fd] |= mode & (_O_TEXT | _O_BINARY);
1304   return ret;
1305 }
1306
1307 /*********************************************************************
1308  *              _stati64 (MSVCRT.@)
1309  */
1310 int _stati64(const char* path, struct _stati64 * buf)
1311 {
1312   DWORD dw;
1313   WIN32_FILE_ATTRIBUTE_DATA hfi;
1314   unsigned short mode = MSVCRT_S_IREAD;
1315   int plen;
1316
1317   TRACE(":file (%s) buf(%p)\n",path,buf);
1318
1319   if (!GetFileAttributesExA(path, GetFileExInfoStandard, &hfi))
1320   {
1321       TRACE("failed (%ld)\n",GetLastError());
1322       MSVCRT__set_errno(ERROR_FILE_NOT_FOUND);
1323       return -1;
1324   }
1325
1326   memset(buf,0,sizeof(struct _stati64));
1327
1328   /* FIXME: rdev isn't drive num, despite what the docs say-what is it?
1329      Bon 011120: This FIXME seems incorrect
1330                  Also a letter as first char isn't enough to be classified
1331                  as a drive letter
1332   */
1333   if (isalpha(*path)&& (*(path+1)==':'))
1334     buf->st_dev = buf->st_rdev = toupper(*path) - 'A'; /* drive num */
1335   else
1336     buf->st_dev = buf->st_rdev = _getdrive() - 1;
1337
1338   plen = strlen(path);
1339
1340   /* Dir, or regular file? */
1341   if ((hfi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
1342       (path[plen-1] == '\\'))
1343     mode |= (_S_IFDIR | MSVCRT_S_IEXEC);
1344   else
1345   {
1346     mode |= _S_IFREG;
1347     /* executable? */
1348     if (plen > 6 && path[plen-4] == '.')  /* shortest exe: "\x.exe" */
1349     {
1350       unsigned int ext = tolower(path[plen-1]) | (tolower(path[plen-2]) << 8) |
1351                                  (tolower(path[plen-3]) << 16);
1352       if (ext == EXE || ext == BAT || ext == CMD || ext == COM)
1353           mode |= MSVCRT_S_IEXEC;
1354     }
1355   }
1356
1357   if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
1358     mode |= MSVCRT_S_IWRITE;
1359
1360   buf->st_mode  = mode;
1361   buf->st_nlink = 1;
1362   buf->st_size  = ((__int64)hfi.nFileSizeHigh << 32) + hfi.nFileSizeLow;
1363   RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastAccessTime, &dw);
1364   buf->st_atime = dw;
1365   RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastWriteTime, &dw);
1366   buf->st_mtime = buf->st_ctime = dw;
1367   TRACE("%d %d 0x%08lx%08lx %ld %ld %ld\n", buf->st_mode,buf->st_nlink,
1368         (long)(buf->st_size >> 32),(long)buf->st_size,
1369         buf->st_atime,buf->st_mtime, buf->st_ctime);
1370   return 0;
1371 }
1372
1373 /*********************************************************************
1374  *              _stat (MSVCRT.@)
1375  */
1376 int MSVCRT__stat(const char* path, struct _stat * buf)
1377 { int ret;
1378   struct _stati64 bufi64;
1379
1380   ret = _stati64( path, &bufi64);
1381   if (!ret)
1382       msvcrt_cp_from_stati64(&bufi64, buf);
1383   return ret;
1384 }
1385
1386 /*********************************************************************
1387  *              _wstati64 (MSVCRT.@)
1388  */
1389 int _wstati64(const MSVCRT_wchar_t* path, struct _stati64 * buf)
1390 {
1391   DWORD dw;
1392   WIN32_FILE_ATTRIBUTE_DATA hfi;
1393   unsigned short mode = MSVCRT_S_IREAD;
1394   int plen;
1395
1396   TRACE(":file (%s) buf(%p)\n",debugstr_w(path),buf);
1397
1398   if (!GetFileAttributesExW(path, GetFileExInfoStandard, &hfi))
1399   {
1400       TRACE("failed (%ld)\n",GetLastError());
1401       MSVCRT__set_errno(ERROR_FILE_NOT_FOUND);
1402       return -1;
1403   }
1404
1405   memset(buf,0,sizeof(struct _stat));
1406
1407   /* FIXME: rdev isn't drive num, despite what the docs says-what is it? */
1408   if (MSVCRT_iswalpha(*path))
1409     buf->st_dev = buf->st_rdev = toupperW(*path - 'A'); /* drive num */
1410   else
1411     buf->st_dev = buf->st_rdev = _getdrive() - 1;
1412
1413   plen = strlenW(path);
1414
1415   /* Dir, or regular file? */
1416   if ((hfi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
1417       (path[plen-1] == '\\'))
1418     mode |= (_S_IFDIR | MSVCRT_S_IEXEC);
1419   else
1420   {
1421     mode |= _S_IFREG;
1422     /* executable? */
1423     if (plen > 6 && path[plen-4] == '.')  /* shortest exe: "\x.exe" */
1424     {
1425       ULONGLONG ext = tolowerW(path[plen-1]) | (tolowerW(path[plen-2]) << 16) |
1426                                ((ULONGLONG)tolowerW(path[plen-3]) << 32);
1427       if (ext == WCEXE || ext == WCBAT || ext == WCCMD || ext == WCCOM)
1428         mode |= MSVCRT_S_IEXEC;
1429     }
1430   }
1431
1432   if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
1433     mode |= MSVCRT_S_IWRITE;
1434
1435   buf->st_mode  = mode;
1436   buf->st_nlink = 1;
1437   buf->st_size  = ((__int64)hfi.nFileSizeHigh << 32) + hfi.nFileSizeLow;
1438   RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastAccessTime, &dw);
1439   buf->st_atime = dw;
1440   RtlTimeToSecondsSince1970((LARGE_INTEGER *)&hfi.ftLastWriteTime, &dw);
1441   buf->st_mtime = buf->st_ctime = dw;
1442   TRACE("%d %d 0x%08lx%08lx %ld %ld %ld\n", buf->st_mode,buf->st_nlink,
1443         (long)(buf->st_size >> 32),(long)buf->st_size,
1444         buf->st_atime,buf->st_mtime, buf->st_ctime);
1445   return 0;
1446 }
1447
1448 /*********************************************************************
1449  *              _wstat (MSVCRT.@)
1450  */
1451 int _wstat(const MSVCRT_wchar_t* path, struct _stat * buf)
1452 {
1453   int ret;
1454   struct _stati64 bufi64;
1455
1456   ret = _wstati64( path, &bufi64 );
1457   if (!ret) msvcrt_cp_from_stati64(&bufi64, buf);
1458   return ret;
1459 }
1460
1461 /*********************************************************************
1462  *              _tell (MSVCRT.@)
1463  */
1464 long _tell(int fd)
1465 {
1466   return _lseek(fd, 0, SEEK_CUR);
1467 }
1468
1469 /*********************************************************************
1470  *              _telli64 (MSVCRT.@)
1471  */
1472 __int64 _telli64(int fd)
1473 {
1474   return _lseeki64(fd, 0, SEEK_CUR);
1475 }
1476
1477 /*********************************************************************
1478  *              _tempnam (MSVCRT.@)
1479  */
1480 char *_tempnam(const char *dir, const char *prefix)
1481 {
1482   char tmpbuf[MAX_PATH];
1483
1484   TRACE("dir (%s) prefix (%s)\n",dir,prefix);
1485   if (GetTempFileNameA(dir,prefix,0,tmpbuf))
1486   {
1487     TRACE("got name (%s)\n",tmpbuf);
1488     DeleteFileA(tmpbuf);
1489     return _strdup(tmpbuf);
1490   }
1491   TRACE("failed (%ld)\n",GetLastError());
1492   return NULL;
1493 }
1494
1495 /*********************************************************************
1496  *              _wtempnam (MSVCRT.@)
1497  */
1498 MSVCRT_wchar_t *_wtempnam(const MSVCRT_wchar_t *dir, const MSVCRT_wchar_t *prefix)
1499 {
1500   MSVCRT_wchar_t tmpbuf[MAX_PATH];
1501
1502   TRACE("dir (%s) prefix (%s)\n",debugstr_w(dir),debugstr_w(prefix));
1503   if (GetTempFileNameW(dir,prefix,0,tmpbuf))
1504   {
1505     TRACE("got name (%s)\n",debugstr_w(tmpbuf));
1506     DeleteFileW(tmpbuf);
1507     return _wcsdup(tmpbuf);
1508   }
1509   TRACE("failed (%ld)\n",GetLastError());
1510   return NULL;
1511 }
1512
1513 /*********************************************************************
1514  *              _umask (MSVCRT.@)
1515  */
1516 int _umask(int umask)
1517 {
1518   int old_umask = MSVCRT_umask;
1519   TRACE("(%d)\n",umask);
1520   MSVCRT_umask = umask;
1521   return old_umask;
1522 }
1523
1524 /*********************************************************************
1525  *              _utime (MSVCRT.@)
1526  */
1527 int _utime(const char* path, struct _utimbuf *t)
1528 {
1529   int fd = _open(path, _O_WRONLY | _O_BINARY);
1530
1531   if (fd > 0)
1532   {
1533     int retVal = _futime(fd, t);
1534     _close(fd);
1535     return retVal;
1536   }
1537   return -1;
1538 }
1539
1540 /*********************************************************************
1541  *              _wutime (MSVCRT.@)
1542  */
1543 int _wutime(const MSVCRT_wchar_t* path, struct _utimbuf *t)
1544 {
1545   int fd = _wopen(path, _O_WRONLY | _O_BINARY);
1546
1547   if (fd > 0)
1548   {
1549     int retVal = _futime(fd, t);
1550     _close(fd);
1551     return retVal;
1552   }
1553   return -1;
1554 }
1555
1556 /*********************************************************************
1557  *              _write (MSVCRT.@)
1558  */
1559 int _write(int fd, const void* buf, unsigned int count)
1560 {
1561   DWORD num_written;
1562   HANDLE hand = msvcrt_fdtoh(fd);
1563
1564   /* Don't trace small writes, it gets *very* annoying */
1565 #if 0
1566   if (count > 32)
1567     TRACE(":fd (%d) handle (%d) buf (%p) len (%d)\n",fd,hand,buf,count);
1568 #endif
1569   if (hand == INVALID_HANDLE_VALUE)
1570     {
1571       *MSVCRT__errno() = MSVCRT_EBADF;
1572       return -1;
1573     }
1574
1575   /* If appending, go to EOF */
1576   if (MSVCRT_flags[fd] & MSVCRT__IOAPPEND)
1577     _lseek(fd, 0, FILE_END);
1578
1579   if (MSVCRT_flags[fd] & _O_BINARY)
1580     {
1581       if (WriteFile(hand, buf, count, &num_written, NULL)
1582           &&  (num_written == count))
1583         return num_written;
1584       TRACE(":failed-last error (%ld)\n",GetLastError());
1585       if (MSVCRT_files[fd])
1586         {
1587           MSVCRT_files[fd]->_flag |= MSVCRT__IOERR;
1588           *MSVCRT__errno() = MSVCRT_ENOSPC;
1589         }
1590     }
1591   else
1592   {
1593       unsigned int i, j, nr_lf;
1594       char *s=(char*)buf, *buf_start=(char*)buf, *p;
1595       /* find number of \n ( without preceeding \r */
1596       for ( nr_lf=0,i = 0; i <count; i++)
1597       {
1598           if (s[i]== '\n')
1599           {
1600               nr_lf++;
1601               /*if ((i >1) && (s[i-1] == '\r')) nr_lf--; */
1602           }
1603       }
1604       if (nr_lf)
1605       {
1606           if ((p = MSVCRT_malloc(count + nr_lf)))
1607           {
1608               for(s=(char*)buf, i=0, j=0; i<count; i++)
1609               {
1610                   if (s[i]== '\n')
1611                   {
1612                       p[j++] = '\r';
1613                       /*if ((i >1) && (s[i-1] == '\r'))j--;*/
1614                   }
1615                   p[j++] = s[i];
1616               }
1617           }
1618           else
1619           {
1620               FIXME("Malloc failed\n");
1621               nr_lf =0;
1622               p = (char*)buf;
1623           }
1624       }
1625       else
1626           p = (char*)buf;
1627
1628       if ((WriteFile(hand, p, count+nr_lf, &num_written, NULL) == 0 ) || (num_written != count+nr_lf))
1629       {
1630           TRACE(":failed-last error (%ld) num_written %ld\n",GetLastError(),num_written);
1631           if (MSVCRT_files[fd])
1632           {
1633               MSVCRT_files[fd]->_flag |= MSVCRT__IOERR;
1634               *MSVCRT__errno() = MSVCRT_ENOSPC;
1635               if(nr_lf)
1636                   MSVCRT_free(p);
1637               return s - buf_start;
1638           }
1639       }
1640       else
1641       {
1642           if(nr_lf)
1643               MSVCRT_free(p);
1644           return count;
1645       }
1646   }
1647   return -1;
1648 }
1649
1650 /*********************************************************************
1651  *              _putw (MSVCRT.@)
1652  */
1653 int _putw(int val, MSVCRT_FILE* file)
1654 {
1655   return _write(file->_file, &val, sizeof(val)) == 1? val : MSVCRT_EOF;
1656 }
1657
1658 /*********************************************************************
1659  *              clearerr (MSVCRT.@)
1660  */
1661 void MSVCRT_clearerr(MSVCRT_FILE* file)
1662 {
1663   TRACE(":file (%p) fd (%d)\n",file,file->_file);
1664   file->_flag &= ~(MSVCRT__IOERR | MSVCRT__IOEOF);
1665 }
1666
1667 /*********************************************************************
1668  *              fclose (MSVCRT.@)
1669  */
1670 int MSVCRT_fclose(MSVCRT_FILE* file)
1671 {
1672   int r, flag;
1673
1674   flag = file->_flag;
1675   r=_close(file->_file);
1676   return ((r==MSVCRT_EOF) || (flag & MSVCRT__IOERR) ? MSVCRT_EOF : 0);
1677 }
1678
1679 /*********************************************************************
1680  *              feof (MSVCRT.@)
1681  */
1682 int MSVCRT_feof(MSVCRT_FILE* file)
1683 {
1684   return file->_flag & MSVCRT__IOEOF;
1685 }
1686
1687 /*********************************************************************
1688  *              ferror (MSVCRT.@)
1689  */
1690 int MSVCRT_ferror(MSVCRT_FILE* file)
1691 {
1692   return file->_flag & MSVCRT__IOERR;
1693 }
1694
1695 /*********************************************************************
1696  *              fflush (MSVCRT.@)
1697  */
1698 int MSVCRT_fflush(MSVCRT_FILE* file)
1699 {
1700   if(!file) {
1701         _flushall();
1702         return 0;
1703   } else {
1704         int res=msvcrt_flush_buffer(file);
1705         return res;
1706   }
1707 }
1708
1709 /*********************************************************************
1710  *              fgetc (MSVCRT.@)
1711  */
1712 int MSVCRT_fgetc(MSVCRT_FILE* file)
1713 {
1714   if (file->_cnt>0) {
1715         file->_cnt--;
1716         return *(unsigned char *)file->_ptr++;
1717   } else {
1718         return _filbuf(file);
1719   }
1720 }
1721
1722 /*********************************************************************
1723  *              _fgetchar (MSVCRT.@)
1724  */
1725 int _fgetchar(void)
1726 {
1727   return MSVCRT_fgetc(MSVCRT_stdin);
1728 }
1729
1730 /*********************************************************************
1731  *              _filbuf (MSVCRT.@)
1732  */
1733 int _filbuf(MSVCRT_FILE* file)
1734 {
1735
1736   /* Allocate buffer if needed */
1737   if(file->_bufsiz == 0 && !(file->_flag & MSVCRT__IONBF) ) {
1738         msvcrt_alloc_buffer(file);
1739   }
1740   if(!(file->_flag & MSVCRT__IOREAD)) {
1741         if(file->_flag & MSVCRT__IORW) {
1742                 file->_flag |= MSVCRT__IOREAD;
1743         } else {
1744                 return MSVCRT_EOF;
1745         }
1746   }
1747   if(file->_flag & MSVCRT__IONBF) {
1748         unsigned char c;
1749         if (_read(file->_file,&c,1) != 1) {
1750                 file->_flag |= MSVCRT__IOEOF;
1751                 return MSVCRT_EOF;
1752         }
1753         return c;
1754   } else {
1755         file->_cnt = _read(file->_file, file->_base, file->_bufsiz);
1756         if(file->_cnt<0) file->_cnt = 0;
1757         if(!file->_cnt) {
1758                 file->_flag |= MSVCRT__IOEOF;
1759                 return MSVCRT_EOF;
1760         }
1761         file->_cnt--;
1762         file->_ptr = file->_base+1;
1763         return *(unsigned char *)file->_base;
1764   }
1765 }
1766
1767 /*********************************************************************
1768  *              fgetpos (MSVCRT.@)
1769  */
1770 int MSVCRT_fgetpos(MSVCRT_FILE* file, MSVCRT_fpos_t *pos)
1771 {
1772   *pos = MSVCRT_ftell(file);
1773   return (*pos == -1? -1 : 0);
1774 }
1775
1776 /*********************************************************************
1777  *              fgets (MSVCRT.@)
1778  */
1779 char *MSVCRT_fgets(char *s, int size, MSVCRT_FILE* file)
1780 {
1781   int    cc = MSVCRT_EOF;
1782   char * buf_start = s;
1783
1784   TRACE(":file(%p) fd (%d) str (%p) len (%d)\n",
1785         file,file->_file,s,size);
1786
1787   while ((size >1) && (cc = MSVCRT_fgetc(file)) != MSVCRT_EOF && cc != '\n')
1788     {
1789       *s++ = (char)cc;
1790       size --;
1791     }
1792   if ((cc == MSVCRT_EOF) && (s == buf_start)) /* If nothing read, return 0*/
1793   {
1794     TRACE(":nothing read\n");
1795     return NULL;
1796   }
1797   if ((cc != MSVCRT_EOF) && (size > 1))
1798     *s++ = cc;
1799   *s = '\0';
1800   TRACE(":got '%s'\n", debugstr_a(buf_start));
1801   return buf_start;
1802 }
1803
1804 /*********************************************************************
1805  *              fgetwc (MSVCRT.@)
1806  *
1807  * In _O_TEXT mode, bultibyte characters are read from the file, dropping
1808  * the CR from CR/LF combinations
1809  */
1810 MSVCRT_wint_t MSVCRT_fgetwc(MSVCRT_FILE* file)
1811 {
1812   char c;
1813
1814   if (file->_flag & _O_BINARY)
1815     {
1816       MSVCRT_wchar_t wc;
1817       if (_read(file->_file, &wc, sizeof(wc)) != sizeof(wc))
1818         return MSVCRT_WEOF;
1819       return wc;
1820     }
1821   c = MSVCRT_fgetc(file);
1822   if ((*__p___mb_cur_max() > 1) && MSVCRT_isleadbyte(c))
1823     {
1824       FIXME("Treat Multibyte characters\n");
1825     }
1826   if (c == MSVCRT_EOF)
1827     return MSVCRT_WEOF;
1828   else
1829     return (MSVCRT_wint_t)c;
1830 }
1831
1832 /*********************************************************************
1833  *              getwc (MSVCRT.@)
1834  */
1835 MSVCRT_wint_t MSVCRT_getwc(MSVCRT_FILE* file)
1836 {
1837   return MSVCRT_fgetwc(file);
1838 }
1839
1840 /*********************************************************************
1841  *              _fgetwchar (MSVCRT.@)
1842  */
1843 MSVCRT_wint_t _fgetwchar(void)
1844 {
1845   return MSVCRT_fgetwc(MSVCRT_stdin);
1846 }
1847
1848 /*********************************************************************
1849  *              getwchar (MSVCRT.@)
1850  */
1851 MSVCRT_wint_t MSVCRT_getwchar(void)
1852 {
1853   return _fgetwchar();
1854 }
1855
1856 /*********************************************************************
1857  *              fgetws (MSVCRT.@)
1858  */
1859 MSVCRT_wchar_t *MSVCRT_fgetws(MSVCRT_wchar_t *s, int size, MSVCRT_FILE* file)
1860 {
1861   int    cc = MSVCRT_WEOF;
1862   MSVCRT_wchar_t * buf_start = s;
1863
1864   TRACE(":file(%p) fd (%d) str (%p) len (%d)\n",
1865         file,file->_file,s,size);
1866
1867   while ((size >1) && (cc = MSVCRT_fgetwc(file)) != MSVCRT_WEOF && cc != '\n')
1868     {
1869       *s++ = (char)cc;
1870       size --;
1871     }
1872   if ((cc == MSVCRT_WEOF) && (s == buf_start)) /* If nothing read, return 0*/
1873   {
1874     TRACE(":nothing read\n");
1875     return NULL;
1876   }
1877   if ((cc != MSVCRT_WEOF) && (size > 1))
1878     *s++ = cc;
1879   *s = 0;
1880   TRACE(":got %s\n", debugstr_w(buf_start));
1881   return buf_start;
1882 }
1883
1884
1885 /*********************************************************************
1886  *              fputwc (MSVCRT.@)
1887  */
1888 MSVCRT_wint_t MSVCRT_fputwc(MSVCRT_wint_t wc, MSVCRT_FILE* file)
1889 {
1890   MSVCRT_wchar_t mwc=wc;
1891   if (MSVCRT_fwrite( &mwc, sizeof(mwc), 1, file) != 1)
1892     return MSVCRT_WEOF;
1893   return wc;
1894 }
1895
1896 /*********************************************************************
1897  *              _fputwchar (MSVCRT.@)
1898  */
1899 MSVCRT_wint_t _fputwchar(MSVCRT_wint_t wc)
1900 {
1901   return MSVCRT_fputwc(wc, MSVCRT_stdout);
1902 }
1903
1904 /*********************************************************************
1905  *              fopen (MSVCRT.@)
1906  */
1907 MSVCRT_FILE* MSVCRT_fopen(const char *path, const char *mode)
1908 {
1909   MSVCRT_FILE* file;
1910   int flags = 0, plus = 0, fd;
1911   const char* search = mode;
1912
1913   TRACE("(%s,%s)\n",path,mode);
1914
1915   while (*search)
1916     if (*search++ == '+')
1917       plus = 1;
1918
1919   /* map mode string to open() flags. "man fopen" for possibilities. */
1920   switch(*mode++)
1921   {
1922   case 'R': case 'r':
1923     flags = (plus ? _O_RDWR : _O_RDONLY);
1924     break;
1925   case 'W': case 'w':
1926     flags = _O_CREAT | _O_TRUNC | (plus  ? _O_RDWR : _O_WRONLY);
1927     break;
1928   case 'A': case 'a':
1929     flags = _O_CREAT | _O_APPEND | (plus  ? _O_RDWR : _O_WRONLY);
1930     break;
1931   default:
1932     return NULL;
1933   }
1934
1935   while (*mode)
1936     switch (*mode++)
1937     {
1938     case 'B': case 'b':
1939       flags |=  _O_BINARY;
1940       flags &= ~_O_TEXT;
1941       break;
1942     case 'T': case 't':
1943       flags |=  _O_TEXT;
1944       flags &= ~_O_BINARY;
1945       break;
1946     case '+':
1947       break;
1948     default:
1949       FIXME(":unknown flag %c not supported\n",mode[-1]);
1950     }
1951
1952   fd = _open(path, flags, _S_IREAD | _S_IWRITE);
1953
1954   if (fd < 0)
1955     return NULL;
1956
1957   file = msvcrt_alloc_fp(fd);
1958   TRACE(":got (%p)\n",file);
1959   if (!file)
1960     _close(fd);
1961
1962   return file;
1963 }
1964
1965 /*********************************************************************
1966  *              _wfopen (MSVCRT.@)
1967  */
1968 MSVCRT_FILE *_wfopen(const MSVCRT_wchar_t *path, const MSVCRT_wchar_t *mode)
1969 {
1970   const unsigned int plen = strlenW(path), mlen = strlenW(mode);
1971   char *patha = MSVCRT_calloc(plen + 1, 1);
1972   char *modea = MSVCRT_calloc(mlen + 1, 1);
1973
1974   TRACE("(%s,%s)\n",debugstr_w(path),debugstr_w(mode));
1975
1976   if (patha && modea &&
1977       WideCharToMultiByte(CP_ACP,0,path,plen,patha,plen,NULL,NULL) &&
1978       WideCharToMultiByte(CP_ACP,0,mode,mlen,modea,mlen,NULL,NULL))
1979   {
1980     MSVCRT_FILE *retval = MSVCRT_fopen(patha,modea);
1981     MSVCRT_free(patha);
1982     MSVCRT_free(modea);
1983     return retval;
1984   }
1985
1986   MSVCRT__set_errno(GetLastError());
1987   return NULL;
1988 }
1989
1990 /*********************************************************************
1991  *              _fsopen (MSVCRT.@)
1992  */
1993 MSVCRT_FILE*  _fsopen(const char *path, const char *mode, int share)
1994 {
1995   FIXME(":(%s,%s,%d),ignoring share mode!\n",path,mode,share);
1996   return MSVCRT_fopen(path,mode);
1997 }
1998
1999 /*********************************************************************
2000  *              _wfsopen (MSVCRT.@)
2001  */
2002 MSVCRT_FILE*  _wfsopen(const MSVCRT_wchar_t *path, const MSVCRT_wchar_t *mode, int share)
2003 {
2004   FIXME(":(%s,%s,%d),ignoring share mode!\n",
2005         debugstr_w(path),debugstr_w(mode),share);
2006   return _wfopen(path,mode);
2007 }
2008
2009 /*********************************************************************
2010  *              fputc (MSVCRT.@)
2011  */
2012 int MSVCRT_fputc(int c, MSVCRT_FILE* file)
2013 {
2014   if(file->_cnt>0) {
2015         *file->_ptr++=c;
2016         file->_cnt--;
2017         return c;
2018   } else {
2019         return _flsbuf(c, file);
2020   }
2021 }
2022
2023 /*********************************************************************
2024  *              _flsbuf (MSVCRT.@)
2025  */
2026 int _flsbuf(int c, MSVCRT_FILE* file)
2027 {
2028   /* Flush output buffer */
2029   if(file->_bufsiz == 0 && !(file->_flag & MSVCRT__IONBF)) {
2030         msvcrt_alloc_buffer(file);
2031   }
2032   if(!(file->_flag & MSVCRT__IOWRT)) {
2033         if(file->_flag & MSVCRT__IORW) {
2034                 file->_flag |= MSVCRT__IOWRT;
2035         } else {
2036                 return MSVCRT_EOF;
2037         }
2038   }
2039   if(file->_bufsiz) {
2040         int res=msvcrt_flush_buffer(file);
2041         return res?res : MSVCRT_fputc(c, file);
2042   } else {
2043         unsigned char cc=c;
2044         return _write(file->_file, &cc, 1) == 1? c : MSVCRT_EOF;
2045   }
2046 }
2047
2048 /*********************************************************************
2049  *              _fputchar (MSVCRT.@)
2050  */
2051 int _fputchar(int c)
2052 {
2053   return MSVCRT_fputc(c, MSVCRT_stdout);
2054 }
2055
2056 /*********************************************************************
2057  *              fread (MSVCRT.@)
2058  */
2059 MSVCRT_size_t MSVCRT_fread(void *ptr, MSVCRT_size_t size, MSVCRT_size_t nmemb, MSVCRT_FILE* file)
2060 { MSVCRT_size_t rcnt=size * nmemb;
2061   MSVCRT_size_t read=0;
2062   int pread=0;
2063   /* first buffered data */
2064   if(file->_cnt>0) {
2065         int pcnt= (rcnt>file->_cnt)? file->_cnt:rcnt;
2066         memcpy(ptr, file->_ptr, pcnt);
2067         file->_cnt -= pcnt;
2068         file->_ptr += pcnt;
2069         read += pcnt ;
2070         rcnt -= pcnt ;
2071        ptr = (char*)ptr + pcnt;
2072   } else if(!(file->_flag & MSVCRT__IOREAD )) {
2073         if(file->_flag & MSVCRT__IORW) {
2074                 file->_flag |= MSVCRT__IOREAD;
2075         } else
2076                 return 0;
2077   }
2078   if(rcnt) pread = _read(file->_file,ptr, rcnt);
2079   if (MSVCRT_flags[file->_file] & MSVCRT__IOEOF)
2080      /* expose feof condition in the flags
2081         MFC tests file->_flag for feof, and doesn't not call feof())
2082     */
2083     file->_flag |= MSVCRT__IOEOF;
2084   if (pread <= 0)
2085     pread = 0;
2086   read+=pread;
2087   return read / size;
2088 }
2089
2090 /*********************************************************************
2091  *              freopen (MSVCRT.@)
2092  *
2093  */
2094 MSVCRT_FILE* MSVCRT_freopen(const char *path, const char *mode,MSVCRT_FILE* file)
2095 {
2096   MSVCRT_FILE* newfile;
2097   int fd;
2098
2099   TRACE(":path (%p) mode (%s) file (%p) fd (%d)\n",path,mode,file,file->_file);
2100   if (!file || ((fd = file->_file) < 0) || fd > MSVCRT_fdend)
2101     return NULL;
2102
2103   if (fd > 2)
2104   {
2105 #if 0
2106     FIXME(":reopen on user file not implemented!\n");
2107     MSVCRT__set_errno(ERROR_CALL_NOT_IMPLEMENTED);
2108     return NULL;
2109 #endif
2110     if(MSVCRT_fclose(file))
2111         return NULL;
2112     return MSVCRT_fopen(path, mode);
2113   }
2114
2115   /* first, create the new file */
2116   if ((newfile = MSVCRT_fopen(path,mode)) == NULL)
2117     return NULL;
2118
2119   if (fd < 3 && SetStdHandle(fd == 0 ? STD_INPUT_HANDLE :
2120      (fd == 1? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE),
2121       MSVCRT_handles[newfile->_file]))
2122   {
2123     /* Redirecting std handle to file , copy over.. */
2124     MSVCRT_handles[fd] = MSVCRT_handles[newfile->_file];
2125     MSVCRT_flags[fd] = MSVCRT_flags[newfile->_file];
2126     memcpy(&MSVCRT__iob[fd], newfile, sizeof (MSVCRT_FILE));
2127     MSVCRT__iob[fd]._file = fd;
2128     /* And free up the resources allocated by fopen, but
2129      * not the HANDLE we copied. */
2130     MSVCRT_free(MSVCRT_files[fd]);
2131     msvcrt_free_fd(newfile->_file);
2132     return &MSVCRT__iob[fd];
2133   }
2134
2135   WARN(":failed-last error (%ld)\n",GetLastError());
2136   MSVCRT_fclose(newfile);
2137   MSVCRT__set_errno(GetLastError());
2138   return NULL;
2139 }
2140
2141 /*********************************************************************
2142  *              fsetpos (MSVCRT.@)
2143  */
2144 int MSVCRT_fsetpos(MSVCRT_FILE* file, MSVCRT_fpos_t *pos)
2145 {
2146   return _lseek(file->_file,*pos,SEEK_SET);
2147 }
2148
2149 /*********************************************************************
2150  *              fseek (MSVCRT.@)
2151  */
2152 int MSVCRT_fseek(MSVCRT_FILE* file, long offset, int whence)
2153 {
2154   /* Flush output if needed */
2155   if(file->_flag & MSVCRT__IOWRT)
2156         msvcrt_flush_buffer(file);
2157
2158   if(whence == SEEK_CUR && file->_flag & MSVCRT__IOREAD ) {
2159         offset -= file->_cnt;
2160   }
2161   /* Discard buffered input */
2162   file->_cnt = 0;
2163   file->_ptr = file->_base;
2164   /* Reset direction of i/o */
2165   if(file->_flag & MSVCRT__IORW) {
2166         file->_flag &= ~(MSVCRT__IOREAD|MSVCRT__IOWRT);
2167   }
2168   return (_lseek(file->_file,offset,whence) == -1)?-1:0;
2169 }
2170
2171 /*********************************************************************
2172  *              ftell (MSVCRT.@)
2173  */
2174 LONG MSVCRT_ftell(MSVCRT_FILE* file)
2175 {
2176   int off=0;
2177   long pos;
2178   if(file->_bufsiz)  {
2179         if( file->_flag & MSVCRT__IOWRT ) {
2180                 off = file->_ptr - file->_base;
2181         } else {
2182                 off = -file->_cnt;
2183         }
2184   }
2185   pos = _tell(file->_file);
2186   if(pos == -1) return pos;
2187   return off + pos;
2188 }
2189
2190 /*********************************************************************
2191  *              fwrite (MSVCRT.@)
2192  */
2193 MSVCRT_size_t MSVCRT_fwrite(const void *ptr, MSVCRT_size_t size, MSVCRT_size_t nmemb, MSVCRT_FILE* file)
2194 {
2195   MSVCRT_size_t wrcnt=size * nmemb;
2196   int written = 0;
2197   if (size == 0)
2198       return 0;
2199   if(file->_cnt) {
2200         int pcnt=(file->_cnt>wrcnt)? wrcnt: file->_cnt;
2201         memcpy(file->_ptr, ptr, pcnt);
2202         file->_cnt -= pcnt;
2203         file->_ptr += pcnt;
2204         written = pcnt;
2205         wrcnt -= pcnt;
2206        ptr = (char*)ptr + pcnt;
2207   } else if(!(file->_flag & MSVCRT__IOWRT)) {
2208         if(file->_flag & MSVCRT__IORW) {
2209                 file->_flag |= MSVCRT__IOWRT;
2210         } else
2211                 return 0;
2212   }
2213   if(wrcnt) {
2214         /* Flush buffer */
2215         int res=msvcrt_flush_buffer(file);
2216         if(!res) {
2217                 int pwritten = _write(file->_file, ptr, wrcnt);
2218                 if (pwritten <= 0) pwritten=0;
2219                 written += pwritten;
2220         }
2221   }
2222   return written / size;
2223 }
2224
2225 /*********************************************************************
2226  *              fputs (MSVCRT.@)
2227  */
2228 int MSVCRT_fputs(const char *s, MSVCRT_FILE* file)
2229 {
2230     size_t i, len = strlen(s);
2231     if (file->_flag & _O_BINARY)
2232       return MSVCRT_fwrite(s,sizeof(*s),len,file) == len ? 0 : MSVCRT_EOF;
2233     for (i=0; i<len; i++)
2234       if (MSVCRT_fputc(s[i], file) == MSVCRT_EOF) 
2235         return MSVCRT_EOF;
2236     return 0;
2237 }
2238
2239 /*********************************************************************
2240  *              fputws (MSVCRT.@)
2241  */
2242 int MSVCRT_fputws(const MSVCRT_wchar_t *s, MSVCRT_FILE* file)
2243 {
2244     size_t i, len = strlenW(s);
2245     if (file->_flag & _O_BINARY)
2246       return MSVCRT_fwrite(s,sizeof(*s),len,file) == len ? 0 : MSVCRT_EOF;
2247     for (i=0; i<len; i++)
2248       {
2249         if ((s[i] == L'\n') && (MSVCRT_fputc('\r', file) == MSVCRT_EOF))
2250           return MSVCRT_WEOF;
2251         if (MSVCRT_fputwc(s[i], file) == MSVCRT_WEOF)
2252           return MSVCRT_WEOF; 
2253       }
2254     return 0;
2255 }
2256
2257 /*********************************************************************
2258  *              getchar (MSVCRT.@)
2259  */
2260 int MSVCRT_getchar(void)
2261 {
2262   return MSVCRT_fgetc(MSVCRT_stdin);
2263 }
2264
2265 /*********************************************************************
2266  *              getc (MSVCRT.@)
2267  */
2268 int MSVCRT_getc(MSVCRT_FILE* file)
2269 {
2270   return MSVCRT_fgetc(file);
2271 }
2272
2273 /*********************************************************************
2274  *              gets (MSVCRT.@)
2275  */
2276 char *MSVCRT_gets(char *buf)
2277 {
2278   int    cc;
2279   char * buf_start = buf;
2280
2281   for(cc = MSVCRT_fgetc(MSVCRT_stdin); cc != MSVCRT_EOF && cc != '\n';
2282       cc = MSVCRT_fgetc(MSVCRT_stdin))
2283   if(cc != '\r') *buf++ = (char)cc;
2284
2285   *buf = '\0';
2286
2287   TRACE("got '%s'\n", buf_start);
2288   return buf_start;
2289 }
2290
2291 /*********************************************************************
2292  *              _getws (MSVCRT.@)
2293  */
2294 MSVCRT_wchar_t* MSVCRT__getws(MSVCRT_wchar_t* buf)
2295 {
2296     MSVCRT_wint_t cc;
2297     MSVCRT_wchar_t* ws = buf;
2298
2299     for (cc = MSVCRT_fgetwc(MSVCRT_stdin); cc != MSVCRT_WEOF && cc != '\n';
2300          cc = MSVCRT_fgetwc(MSVCRT_stdin))
2301     {
2302         if (cc != '\r')
2303             *buf++ = (MSVCRT_wchar_t)cc;
2304     }
2305     *buf = '\0';
2306
2307     TRACE("got '%s'\n", debugstr_w(ws));
2308     return ws;
2309 }
2310
2311 /*********************************************************************
2312  *              putc (MSVCRT.@)
2313  */
2314 int MSVCRT_putc(int c, MSVCRT_FILE* file)
2315 {
2316   return MSVCRT_fputc(c, file);
2317 }
2318
2319 /*********************************************************************
2320  *              putchar (MSVCRT.@)
2321  */
2322 int MSVCRT_putchar(int c)
2323 {
2324   return MSVCRT_fputc(c, MSVCRT_stdout);
2325 }
2326
2327 /*********************************************************************
2328  *              puts (MSVCRT.@)
2329  */
2330 int MSVCRT_puts(const char *s)
2331 {
2332     size_t len = strlen(s);
2333     if (MSVCRT_fwrite(s,sizeof(*s),len,MSVCRT_stdout) != len) return MSVCRT_EOF;
2334     return MSVCRT_fwrite("\n",1,1,MSVCRT_stdout) == 1 ? 0 : MSVCRT_EOF;
2335 }
2336
2337 /*********************************************************************
2338  *              _putws (MSVCRT.@)
2339  */
2340 int _putws(const MSVCRT_wchar_t *s)
2341 {
2342     static const MSVCRT_wchar_t nl = '\n';
2343     size_t len = strlenW(s);
2344     if (MSVCRT_fwrite(s,sizeof(*s),len,MSVCRT_stdout) != len) return MSVCRT_EOF;
2345     return MSVCRT_fwrite(&nl,sizeof(nl),1,MSVCRT_stdout) == 1 ? 0 : MSVCRT_EOF;
2346 }
2347
2348 /*********************************************************************
2349  *              remove (MSVCRT.@)
2350  */
2351 int MSVCRT_remove(const char *path)
2352 {
2353   TRACE("(%s)\n",path);
2354   if (DeleteFileA(path))
2355     return 0;
2356   TRACE(":failed (%ld)\n",GetLastError());
2357   MSVCRT__set_errno(GetLastError());
2358   return -1;
2359 }
2360
2361 /*********************************************************************
2362  *              _wremove (MSVCRT.@)
2363  */
2364 int _wremove(const MSVCRT_wchar_t *path)
2365 {
2366   TRACE("(%s)\n",debugstr_w(path));
2367   if (DeleteFileW(path))
2368     return 0;
2369   TRACE(":failed (%ld)\n",GetLastError());
2370   MSVCRT__set_errno(GetLastError());
2371   return -1;
2372 }
2373
2374 /*********************************************************************
2375  *              rename (MSVCRT.@)
2376  */
2377 int MSVCRT_rename(const char *oldpath,const char *newpath)
2378 {
2379   TRACE(":from %s to %s\n",oldpath,newpath);
2380   if (MoveFileExA(oldpath, newpath, MOVEFILE_COPY_ALLOWED))
2381     return 0;
2382   TRACE(":failed (%ld)\n",GetLastError());
2383   MSVCRT__set_errno(GetLastError());
2384   return -1;
2385 }
2386
2387 /*********************************************************************
2388  *              _wrename (MSVCRT.@)
2389  */
2390 int _wrename(const MSVCRT_wchar_t *oldpath,const MSVCRT_wchar_t *newpath)
2391 {
2392   TRACE(":from %s to %s\n",debugstr_w(oldpath),debugstr_w(newpath));
2393   if (MoveFileExW(oldpath, newpath, MOVEFILE_COPY_ALLOWED))
2394     return 0;
2395   TRACE(":failed (%ld)\n",GetLastError());
2396   MSVCRT__set_errno(GetLastError());
2397   return -1;
2398 }
2399
2400 /*********************************************************************
2401  *              setvbuf (MSVCRT.@)
2402  */
2403 int MSVCRT_setvbuf(MSVCRT_FILE* file, char *buf, int mode, MSVCRT_size_t size)
2404 {
2405   /* TODO: Check if file busy */
2406   if(file->_bufsiz) {
2407         MSVCRT_free(file->_base);
2408         file->_bufsiz = 0;
2409         file->_cnt = 0;
2410   }
2411   if(mode == MSVCRT__IOFBF) {
2412         file->_flag &= ~MSVCRT__IONBF;
2413         file->_base = file->_ptr = buf;
2414         if(buf) {
2415                 file->_bufsiz = size;
2416         }
2417   } else {
2418         file->_flag |= MSVCRT__IONBF;
2419   }
2420   return 0;
2421 }
2422
2423 /*********************************************************************
2424  *              setbuf (MSVCRT.@)
2425  */
2426 void MSVCRT_setbuf(MSVCRT_FILE* file, char *buf)
2427 {
2428   MSVCRT_setvbuf(file, buf, buf ? MSVCRT__IOFBF : MSVCRT__IONBF, MSVCRT_BUFSIZ);
2429 }
2430
2431 /*********************************************************************
2432  *              tmpnam (MSVCRT.@)
2433  */
2434 char *MSVCRT_tmpnam(char *s)
2435 {
2436   static int unique;
2437   char tmpstr[16];
2438   char *p;
2439   int count;
2440   if (s == 0)
2441     s = MSVCRT_tmpname;
2442   msvcrt_int_to_base32(GetCurrentProcessId(), tmpstr);
2443   p = s + sprintf(s, "\\s%s.", tmpstr);
2444   for (count = 0; count < MSVCRT_TMP_MAX; count++)
2445   {
2446     msvcrt_int_to_base32(unique++, tmpstr);
2447     strcpy(p, tmpstr);
2448     if (GetFileAttributesA(s) == INVALID_FILE_ATTRIBUTES &&
2449         GetLastError() == ERROR_FILE_NOT_FOUND)
2450       break;
2451   }
2452   return s;
2453 }
2454
2455 /*********************************************************************
2456  *              tmpfile (MSVCRT.@)
2457  */
2458 MSVCRT_FILE* MSVCRT_tmpfile(void)
2459 {
2460   char *filename = MSVCRT_tmpnam(NULL);
2461   int fd;
2462   fd = _open(filename, _O_CREAT | _O_BINARY | _O_RDWR | _O_TEMPORARY);
2463   if (fd != -1)
2464     return msvcrt_alloc_fp(fd);
2465   return NULL;
2466 }
2467
2468 /*********************************************************************
2469  *              vfprintf (MSVCRT.@)
2470  */
2471 int MSVCRT_vfprintf(MSVCRT_FILE* file, const char *format, va_list valist)
2472 {
2473   char buf[2048], *mem = buf;
2474   int written, resize = sizeof(buf), retval;
2475   /* There are two conventions for vsnprintf failing:
2476    * Return -1 if we truncated, or
2477    * Return the number of bytes that would have been written
2478    * The code below handles both cases
2479    */
2480   while ((written = vsnprintf(mem, resize, format, valist)) == -1 ||
2481           written > resize)
2482   {
2483     resize = (written == -1 ? resize * 2 : written + 1);
2484     if (mem != buf)
2485       MSVCRT_free (mem);
2486     if (!(mem = (char *)MSVCRT_malloc(resize)))
2487       return MSVCRT_EOF;
2488   }
2489   retval = MSVCRT_fwrite(mem, sizeof(*mem), written, file);
2490   if (mem != buf)
2491     MSVCRT_free (mem);
2492   return retval;
2493 }
2494
2495 /*********************************************************************
2496  *              vfwprintf (MSVCRT.@)
2497  * FIXME:
2498  * Is final char included in written (then resize is too big) or not
2499  * (then we must test for equality too)?
2500  */
2501 int MSVCRT_vfwprintf(MSVCRT_FILE* file, const MSVCRT_wchar_t *format, va_list valist)
2502 {
2503   MSVCRT_wchar_t buf[2048], *mem = buf;
2504   int written, resize = sizeof(buf) / sizeof(MSVCRT_wchar_t), retval;
2505   /* See vfprintf comments */
2506   while ((written = _vsnwprintf(mem, resize, format, valist)) == -1 ||
2507           written > resize)
2508   {
2509     resize = (written == -1 ? resize * 2 : written + sizeof(MSVCRT_wchar_t));
2510     if (mem != buf)
2511       MSVCRT_free (mem);
2512     if (!(mem = (MSVCRT_wchar_t *)MSVCRT_malloc(resize*sizeof(*mem))))
2513       return MSVCRT_EOF;
2514   }
2515   retval = MSVCRT_fwrite(mem, sizeof(*mem), written, file);
2516   if (mem != buf)
2517     MSVCRT_free (mem);
2518   return retval;
2519 }
2520
2521 /*********************************************************************
2522  *              vprintf (MSVCRT.@)
2523  */
2524 int MSVCRT_vprintf(const char *format, va_list valist)
2525 {
2526   return MSVCRT_vfprintf(MSVCRT_stdout,format,valist);
2527 }
2528
2529 /*********************************************************************
2530  *              vwprintf (MSVCRT.@)
2531  */
2532 int MSVCRT_vwprintf(const MSVCRT_wchar_t *format, va_list valist)
2533 {
2534   return MSVCRT_vfwprintf(MSVCRT_stdout,format,valist);
2535 }
2536
2537 /*********************************************************************
2538  *              fprintf (MSVCRT.@)
2539  */
2540 int MSVCRT_fprintf(MSVCRT_FILE* file, const char *format, ...)
2541 {
2542     va_list valist;
2543     int res;
2544     va_start(valist, format);
2545     res = MSVCRT_vfprintf(file, format, valist);
2546     va_end(valist);
2547     return res;
2548 }
2549
2550 /*********************************************************************
2551  *              fwprintf (MSVCRT.@)
2552  */
2553 int MSVCRT_fwprintf(MSVCRT_FILE* file, const MSVCRT_wchar_t *format, ...)
2554 {
2555     va_list valist;
2556     int res;
2557     va_start(valist, format);
2558     res = MSVCRT_vfwprintf(file, format, valist);
2559     va_end(valist);
2560     return res;
2561 }
2562
2563 /*********************************************************************
2564  *              printf (MSVCRT.@)
2565  */
2566 int MSVCRT_printf(const char *format, ...)
2567 {
2568     va_list valist;
2569     int res;
2570     va_start(valist, format);
2571     res = MSVCRT_vfprintf(MSVCRT_stdout, format, valist);
2572     va_end(valist);
2573     return res;
2574 }
2575
2576 /*********************************************************************
2577  *              ungetc (MSVCRT.@)
2578  */
2579 int MSVCRT_ungetc(int c, MSVCRT_FILE * file)
2580 {
2581         if(file->_bufsiz == 0 && !(file->_flag & MSVCRT__IONBF)) {
2582                 msvcrt_alloc_buffer(file);
2583                 file->_ptr++;
2584         }
2585         if(file->_ptr>file->_base) {
2586                 file->_ptr--;
2587                 *file->_ptr=c;
2588                 file->_cnt++;
2589                 return c;
2590         }
2591         return MSVCRT_EOF;
2592 }
2593
2594 /*********************************************************************
2595  *              ungetwc (MSVCRT.@)
2596  */
2597 MSVCRT_wint_t MSVCRT_ungetwc(MSVCRT_wint_t wc, MSVCRT_FILE * file)
2598 {
2599         MSVCRT_wchar_t mwc = wc;
2600         char * pp = (char *)&mwc;
2601         int i;
2602         for(i=sizeof(MSVCRT_wchar_t)-1;i>=0;i--) {
2603                 if(pp[i] != MSVCRT_ungetc(pp[i],file))
2604                         return MSVCRT_WEOF;
2605         }
2606         return mwc;
2607 }
2608
2609 /*********************************************************************
2610  *              wprintf (MSVCRT.@)
2611  */
2612 int MSVCRT_wprintf(const MSVCRT_wchar_t *format, ...)
2613 {
2614     va_list valist;
2615     int res;
2616     va_start(valist, format);
2617     res = MSVCRT_vwprintf(format, valist);
2618     va_end(valist);
2619     return res;
2620 }