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