Fixed some issues found by winapi_check.
[wine] / dlls / crtdll / file.c
1 /*
2  * CRTDLL 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  * Implementation Notes:
10  * Mapping is performed between FILE*, fd and HANDLE's. This allows us to 
11  * implement all calls using the Win32 API, support remapping fd's to 
12  * FILES and do some other tricks as well (like closeall, _get_osfhandle).
13  * For mix and matching with the host libc, processes can use the Win32 HANDLE
14  * to get a real unix fd from the wineserver. Or we could do this once
15  * on create, and provide a function to return it quickly (store it
16  * in the mapping table). Note that If you actuall _do_ this, you should
17  * call rewind() before using any other crt functions on the file. To avoid
18  * the confusion I got when reading the API docs, fd is always refered
19  * to as a file descriptor here. In the API docs its called a file handle
20  * which is confusing with Win32 HANDLES.
21  * M$ CRT includes inline versions of some of these functions (like feof()).
22  * These inlines check/modify bitfields in the FILE structure, so we set
23  * _flags/_file/_cnt in the FILE* to be binary compatible with the win dll.
24  * lcc defines _IOAPPEND as one of the flags for a FILE*, but testing shows
25  * that M$ CRT never sets it. So we keep the flag in our mapping table but
26  * mask it out when we populate a FILE* with it. Then when we write we seek
27  * to EOF if _IOAPPEND is set for the underlying fd.
28  *
29  * FIXME:
30  * Not MT safe. Need locking around file access and allocation for this.
31  * NT has no effective limit on files - neither should we. This will be fixed
32  * with dynamic allocation of the file mapping array.
33  * Buffering is handled differently. Have to investigate a) how much control
34  * we have over buffering in win32, and b) if we care ;-)
35  */
36
37 #include "crtdll.h"
38 #include <stdarg.h>
39 #include <string.h>
40 #include <ctype.h>
41 #include <errno.h>
42 #include "ntddk.h"
43
44 DEFAULT_DEBUG_CHANNEL(crtdll);
45
46 /* FIXME: Make this dynamic */
47 #define CRTDLL_MAX_FILES 257
48
49 HANDLE __CRTDLL_handles[CRTDLL_MAX_FILES];
50 CRTDLL_FILE* __CRTDLL_files[CRTDLL_MAX_FILES];
51 INT  __CRTDLL_flags[CRTDLL_MAX_FILES];
52 LPSTR __CRTDLL_tempfiles[CRTDLL_MAX_FILES];
53 CRTDLL_FILE __CRTDLL_iob[3];
54
55 static int __CRTDLL_fdstart = 3; /* first unallocated fd */
56 static int __CRTDLL_fdend = 3; /* highest allocated fd */
57
58 /* INTERNAL: process umask */
59 static INT __CRTDLL_umask = 0;
60
61 /* INTERNAL: Static buffer for temp file name */
62 static char CRTDLL_tmpname[MAX_PATH];
63
64 /* file extentions recognised as executables */
65 static const unsigned int EXE = 'e' << 16 | 'x' << 8 | 'e';
66 static const unsigned int BAT = 'b' << 16 | 'a' << 8 | 't';
67 static const unsigned int CMD = 'c' << 16 | 'm' << 8 | 'd';
68 static const unsigned int COM = 'c' << 16 | 'o' << 8 | 'm';
69
70 /* for stat mode, permissions apply to all,owner and group */
71 #define CRTDLL_S_IREAD  (_S_IREAD  | (_S_IREAD  >> 3) | (_S_IREAD  >> 6))
72 #define CRTDLL_S_IWRITE (_S_IWRITE | (_S_IWRITE >> 3) | (_S_IWRITE >> 6))
73 #define CRTDLL_S_IEXEC  (_S_IEXEC  | (_S_IEXEC  >> 3) | (_S_IEXEC  >> 6))
74
75
76 /* INTERNAL: Get the HANDLE for a fd */
77 static HANDLE __CRTDLL__fdtoh(INT fd);
78 static HANDLE __CRTDLL__fdtoh(INT fd)
79 {
80   if (fd < 0 || fd >= __CRTDLL_fdend ||
81       __CRTDLL_handles[fd] == INVALID_HANDLE_VALUE)
82   {
83     WARN(":fd (%d) - no handle!\n",fd);
84     CRTDLL_doserrno = 0;
85     CRTDLL_errno = EBADF;
86    return INVALID_HANDLE_VALUE;
87   }
88   return __CRTDLL_handles[fd];
89 }
90
91
92 /* INTERNAL: free a file entry fd */
93 static void __CRTDLL__free_fd(INT fd);
94 static void __CRTDLL__free_fd(INT fd)
95 {
96   __CRTDLL_handles[fd] = INVALID_HANDLE_VALUE;
97   __CRTDLL_files[fd] = 0;
98   __CRTDLL_flags[fd] = 0;
99   TRACE(":fd (%d) freed\n",fd);
100   if (fd < 3)
101     return; /* dont use 0,1,2 for user files */
102   if (fd == __CRTDLL_fdend - 1)
103     __CRTDLL_fdend--;
104   if (fd < __CRTDLL_fdstart)
105     __CRTDLL_fdstart = fd;
106 }
107
108
109 /* INTERNAL: Allocate an fd slot from a Win32 HANDLE */
110 static INT __CRTDLL__alloc_fd(HANDLE hand, INT flag);
111 static INT __CRTDLL__alloc_fd(HANDLE hand, INT flag)
112 {
113   INT fd = __CRTDLL_fdstart;
114
115   TRACE(":handle (%d) allocating fd (%d)\n",hand,fd);
116   if (fd >= CRTDLL_MAX_FILES)
117   {
118     WARN(":files exhausted!\n");
119     return -1;
120   }
121   __CRTDLL_handles[fd] = hand;
122   __CRTDLL_flags[fd] = flag;
123
124   /* locate next free slot */
125   if (fd == __CRTDLL_fdend)
126     __CRTDLL_fdstart = ++__CRTDLL_fdend;
127   else
128     while(__CRTDLL_fdstart < __CRTDLL_fdend &&
129           __CRTDLL_handles[__CRTDLL_fdstart] != INVALID_HANDLE_VALUE)
130       __CRTDLL_fdstart++;
131
132   return fd;
133 }
134
135
136 /* INTERNAL: Allocate a FILE* for an fd slot
137  * This is done lazily to avoid memory wastage for low level open/write
138  * usage when a FILE* is not requested (but may be later).
139  */
140 static CRTDLL_FILE* __CRTDLL__alloc_fp(INT fd);
141 static CRTDLL_FILE* __CRTDLL__alloc_fp(INT fd)
142 {
143   TRACE(":fd (%d) allocating FILE*\n",fd);
144   if (fd < 0 || fd >= __CRTDLL_fdend || 
145       __CRTDLL_handles[fd] == INVALID_HANDLE_VALUE)
146   {
147     WARN(":invalid fd %d\n",fd);
148     CRTDLL_doserrno = 0;
149     CRTDLL_errno = EBADF;
150     return NULL;
151   }
152   if (!__CRTDLL_files[fd])
153   {
154     if ((__CRTDLL_files[fd] = CRTDLL_calloc(sizeof(CRTDLL_FILE),1)))
155     {
156       __CRTDLL_files[fd]->_file = fd;
157       __CRTDLL_files[fd]->_flag = __CRTDLL_flags[fd];
158       __CRTDLL_files[fd]->_flag &= ~_IOAPPEND; /* mask out, see above */
159     }
160   }
161   TRACE(":got FILE* (%p)\n",__CRTDLL_files[fd]);
162   return __CRTDLL_files[fd];
163 }
164
165
166 /* INTERNAL: Set up stdin, stderr and stdout */
167 VOID __CRTDLL__init_io(VOID)
168 {
169   int i;
170   memset(__CRTDLL_iob,0,3*sizeof(CRTDLL_FILE));
171   __CRTDLL_handles[0] = GetStdHandle(STD_INPUT_HANDLE);
172   __CRTDLL_flags[0] = __CRTDLL_iob[0]._flag = _IOREAD;
173   __CRTDLL_handles[1] = GetStdHandle(STD_OUTPUT_HANDLE);
174   __CRTDLL_flags[1] = __CRTDLL_iob[1]._flag = _IOWRT;
175   __CRTDLL_handles[2] = GetStdHandle(STD_ERROR_HANDLE);
176   __CRTDLL_flags[2] = __CRTDLL_iob[2]._flag = _IOWRT;
177
178   TRACE(":handles (%d)(%d)(%d)\n",__CRTDLL_handles[0],
179         __CRTDLL_handles[1],__CRTDLL_handles[2]);
180
181   for (i = 0; i < 3; i++)
182   {
183     /* FILE structs for stdin/out/err are static and never deleted */
184     __CRTDLL_files[i] = &__CRTDLL_iob[i];
185     __CRTDLL_iob[i]._file = i;
186     __CRTDLL_tempfiles[i] = NULL;
187   }
188 }
189
190
191 /*********************************************************************
192  *                  _access          (CRTDLL.37)
193  */
194 INT __cdecl CRTDLL__access(LPCSTR filename, INT mode)
195 {
196   DWORD attr = GetFileAttributesA(filename);
197
198   if (attr == 0xffffffff)
199   {
200     if (!filename)
201     {
202         /* FIXME: Should GetFileAttributesA() return this? */
203       __CRTDLL__set_errno(ERROR_INVALID_DATA);
204       return -1;
205     }
206     __CRTDLL__set_errno(GetLastError());
207     return -1;
208   }
209   if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & W_OK))
210   {
211     __CRTDLL__set_errno(ERROR_ACCESS_DENIED);
212     return -1;
213   }
214   TRACE(":file %s, mode (%d) ok\n",filename,mode);
215   return 0;
216 }
217
218
219 /*********************************************************************
220  *                  _chmod           (CRTDLL.054)
221  *
222  * Change a files permissions.
223  */
224 INT __cdecl CRTDLL__chmod(LPCSTR path, INT flags)
225 {
226   DWORD oldFlags = GetFileAttributesA(path);
227  
228   if (oldFlags != 0x0FFFFFFFF)
229   {
230     DWORD newFlags = (flags & _S_IWRITE)? oldFlags & ~FILE_ATTRIBUTE_READONLY:
231       oldFlags | FILE_ATTRIBUTE_READONLY;
232
233     if (newFlags == oldFlags || SetFileAttributesA( path, newFlags ))
234       return 0;
235   }
236   __CRTDLL__set_errno(GetLastError());
237   return -1;
238 }
239
240
241 /*********************************************************************
242  *                  _close           (CRTDLL.57)
243  *
244  * Close an open file descriptor.
245  */
246 INT __cdecl CRTDLL__close(INT fd)
247 {
248   HANDLE hand = __CRTDLL__fdtoh(fd);
249
250   TRACE(":fd (%d) handle (%d)\n",fd,hand);
251   if (hand == INVALID_HANDLE_VALUE)
252     return -1;
253
254   /* Dont free std FILE*'s, they are not dynamic */
255   if (fd > 2 && __CRTDLL_files[fd])
256     CRTDLL_free(__CRTDLL_files[fd]);
257
258   __CRTDLL__free_fd(fd);
259
260   if (!CloseHandle(hand))
261   {
262     WARN(":failed-last error (%ld)\n",GetLastError());
263     __CRTDLL__set_errno(GetLastError());
264     return -1;
265   }
266   if (__CRTDLL_tempfiles[fd])
267   {
268     TRACE("deleting temporary file '%s'\n",__CRTDLL_tempfiles[fd]);
269     CRTDLL__unlink(__CRTDLL_tempfiles[fd]);
270     CRTDLL_free(__CRTDLL_tempfiles[fd]);
271     __CRTDLL_tempfiles[fd] = NULL;
272   }
273
274   TRACE(":ok\n");
275   return 0;
276 }
277
278
279 /*********************************************************************
280  *                  _commit           (CRTDLL.58)
281  *
282  * Ensure all file operations have been flushed to the drive.
283  */
284 INT __cdecl CRTDLL__commit(INT fd)
285 {
286   HANDLE hand = __CRTDLL__fdtoh(fd);
287
288   TRACE(":fd (%d) handle (%d)\n",fd,hand);
289   if (hand == INVALID_HANDLE_VALUE)
290     return -1;
291
292   if (!FlushFileBuffers(hand))
293   {
294     if (GetLastError() == ERROR_INVALID_HANDLE)
295     {
296       /* FlushFileBuffers fails for console handles
297        * so we ignore this error.
298        */
299       return 0;
300     }
301     TRACE(":failed-last error (%ld)\n",GetLastError());
302     __CRTDLL__set_errno(GetLastError());
303     return -1;
304   }
305   TRACE(":ok\n");
306   return 0;
307 }
308
309
310 /*********************************************************************
311  *                  _creat         (CRTDLL.066)
312  *
313  * Open a file, creating it if it is not present.
314  */
315 INT __cdecl CRTDLL__creat(LPCSTR path, INT flags)
316 {
317   INT usedFlags = (flags & _O_TEXT)| _O_CREAT| _O_WRONLY| _O_TRUNC;
318   return CRTDLL__open(path, usedFlags);
319 }
320
321
322 /*********************************************************************
323  *                  _eof           (CRTDLL.076)
324  *
325  * Determine if the file pointer is at the end of a file.
326  *
327  * FIXME
328  *      Care for large files
329  */
330 INT __cdecl CRTDLL__eof( INT fd )
331 {
332   DWORD curpos,endpos;
333   HANDLE hand = __CRTDLL__fdtoh(fd);
334
335   TRACE(":fd (%d) handle (%d)\n",fd,hand);
336
337   if (hand == INVALID_HANDLE_VALUE)
338     return -1;
339
340   /* If we have a FILE* for this file, the EOF flag
341    * will be set by the read()/write() functions.
342    */
343   if (__CRTDLL_files[fd])
344     return __CRTDLL_files[fd]->_flag & _IOEOF;
345
346   /* Otherwise we do it the hard way */
347   curpos = SetFilePointer( hand, 0, NULL, SEEK_CUR );
348   endpos = SetFilePointer( hand, 0, NULL, FILE_END );
349
350   if (curpos == endpos)
351     return TRUE;
352
353   SetFilePointer( hand, curpos, 0, FILE_BEGIN);
354   return FALSE;
355 }
356
357
358 /*********************************************************************
359  *                  _fcloseall     (CRTDLL.089)
360  *
361  * Close all open files except stdin/stdout/stderr.
362  */
363 INT __cdecl CRTDLL__fcloseall(VOID)
364 {
365   int num_closed = 0, i;
366
367   for (i = 3; i < __CRTDLL_fdend; i++)
368     if (__CRTDLL_handles[i] != INVALID_HANDLE_VALUE)
369     {
370       CRTDLL__close(i);
371       num_closed++;
372     }
373
374   if (num_closed)
375     TRACE(":closed (%d) handles\n",num_closed);
376   return num_closed;
377 }
378
379
380 /*********************************************************************
381  *                  _fdopen     (CRTDLL.091)
382  *
383  * Get a FILE* from a low level file descriptor.
384  */
385 CRTDLL_FILE* __cdecl CRTDLL__fdopen(INT fd, LPCSTR mode)
386 {
387   CRTDLL_FILE* file = __CRTDLL__alloc_fp(fd);
388
389   TRACE(":fd (%d) mode (%s) FILE* (%p)\n",fd,mode,file);
390   if (file)
391     CRTDLL_rewind(file);
392
393   return file;
394 }
395
396
397 /*********************************************************************
398  *                  _fgetwchar       (CRTDLL.062)
399  *
400  * Read a wide character from stdin.
401  */
402 WCHAR __cdecl CRTDLL__fgetwchar( VOID )
403 {
404   return CRTDLL_fgetwc(CRTDLL_stdin);
405 }
406
407
408 /*********************************************************************
409  *                  _fgetchar       (CRTDLL.092)
410  *
411  * Read a character from stdin.
412  */
413 INT __cdecl CRTDLL__fgetchar( VOID )
414 {
415   return CRTDLL_fgetc(CRTDLL_stdin);
416 }
417
418
419 /*********************************************************************
420  *                  _filbuf     (CRTDLL.094)
421  *
422  * NOTES
423  * The macro version of getc calls this function whenever FILE->_cnt
424  * becomes negative. We ensure that _cnt is always 0 after any read
425  * so this function is always called. Our implementation simply calls
426  * fgetc as all the underlying buffering is handled by Wines 
427  * implementation of the Win32 file I/O calls.
428  */
429 INT __cdecl CRTDLL__filbuf(CRTDLL_FILE* file)
430 {
431   return CRTDLL_fgetc(file);
432 }
433
434 /*********************************************************************
435  *                   _filelength    (CRTDLL.097)
436  *
437  * Get the length of an open file.
438  */
439 LONG __cdecl CRTDLL__filelength(INT fd)
440 {
441   LONG curPos = CRTDLL__lseek(fd, 0, SEEK_CUR);
442   if (curPos != -1)
443   {
444     LONG endPos = CRTDLL__lseek(fd, 0, SEEK_END);
445     if (endPos != -1)
446     {
447       if (endPos != curPos)
448         CRTDLL__lseek(fd, curPos, SEEK_SET);
449       return endPos;
450     }
451   }
452   return -1;
453 }
454
455
456 /*********************************************************************
457  *                  _fileno     (CRTDLL.097)
458  *
459  * Get the file descriptor from a FILE*.
460  *
461  * NOTES
462  * This returns the CRTDLL fd, _not_ the underlying *nix fd.
463  */
464 INT __cdecl CRTDLL__fileno(CRTDLL_FILE* file)
465 {
466   TRACE(":FILE* (%p) fd (%d)\n",file,file->_file);
467   return file->_file;
468 }
469
470
471 /*********************************************************************
472  *                  _flsbuf     (CRTDLL.102)
473  *
474  * NOTES
475  * The macro version of putc calls this function whenever FILE->_cnt
476  * becomes negative. We ensure that _cnt is always 0 after any write
477  * so this function is always called. Our implementation simply calls
478  * fputc as all the underlying buffering is handled by Wines
479  * implementation of the Win32 file I/O calls.
480  */
481 INT __cdecl CRTDLL__flsbuf(INT c, CRTDLL_FILE* file)
482 {
483   return CRTDLL_fputc(c,file);
484 }
485
486
487 /*********************************************************************
488  *                  _flushall     (CRTDLL.103)
489  *
490  * Flush all open files.
491  */
492 INT __cdecl CRTDLL__flushall(VOID)
493 {
494   int num_flushed = 0, i = 3;
495
496   while(i < __CRTDLL_fdend)
497     if (__CRTDLL_handles[i] != INVALID_HANDLE_VALUE)
498     {
499       if (CRTDLL__commit(i) == -1)
500         if (__CRTDLL_files[i])
501           __CRTDLL_files[i]->_flag |= _IOERR;
502       num_flushed++;
503     }
504
505   TRACE(":flushed (%d) handles\n",num_flushed);
506   return num_flushed;
507 }
508
509
510 /*********************************************************************
511  *                  _fputchar     (CRTDLL.108)
512  *
513  * Put a character to a file.
514  */
515 INT __cdecl CRTDLL__fputchar(INT c)
516 {
517   return CRTDLL_fputc(c, CRTDLL_stdout);
518 }
519
520
521 /*********************************************************************
522  *                  _fputwchar       (CRTDLL.109)
523  *
524  * Put a wide character to stdout.
525  */
526 WCHAR __cdecl CRTDLL__fputwchar( WCHAR wc )
527 {
528   return CRTDLL_fputwc(wc, CRTDLL_stdout);
529 }
530
531
532 /*********************************************************************
533  *                  _fsopen     (CRTDLL.110)
534  *
535  * Open a FILE* with sharing.
536  */
537 CRTDLL_FILE*  __cdecl CRTDLL__fsopen(LPCSTR path, LPCSTR mode, INT share)
538 {
539   FIXME(":(%s,%s,%d),ignoring share mode!\n",path,mode,share);
540   return CRTDLL_fopen(path,mode);
541 }
542
543
544 /*********************************************************************
545  *                  _fstat        (CRTDLL.111)
546  * 
547  * Get information about an open file.
548  */
549 int __cdecl CRTDLL__fstat(int fd, struct _stat* buf)
550 {
551   DWORD dw;
552   BY_HANDLE_FILE_INFORMATION hfi;
553   HANDLE hand = __CRTDLL__fdtoh(fd);
554
555   TRACE(":fd (%d) stat (%p)\n",fd,buf);
556   if (hand == INVALID_HANDLE_VALUE)
557     return -1;
558
559   if (!buf)
560   {
561     WARN(":failed-NULL buf\n");
562     __CRTDLL__set_errno(ERROR_INVALID_PARAMETER);
563     return -1;
564   }
565
566   memset(&hfi, 0, sizeof(hfi));
567   memset(buf, 0, sizeof(struct _stat));
568   if (!GetFileInformationByHandle(hand, &hfi))
569   {
570     WARN(":failed-last error (%ld)\n",GetLastError());
571     __CRTDLL__set_errno(ERROR_INVALID_PARAMETER);
572     return -1;
573   }
574   FIXME(":dwFileAttributes = %d, mode set to 0",hfi.dwFileAttributes);
575   buf->st_nlink = hfi.nNumberOfLinks;
576   buf->st_size  = hfi.nFileSizeLow;
577   RtlTimeToSecondsSince1970( &hfi.ftLastAccessTime, &dw );
578   buf->st_atime = dw;
579   RtlTimeToSecondsSince1970( &hfi.ftLastWriteTime, &dw );
580   buf->st_mtime = buf->st_ctime = dw;
581   return 0;
582 }
583
584
585 /*********************************************************************
586  *                  _futime        (CRTDLL.115)
587  * 
588  * Set the file access/modification times on an open file.
589  */
590 INT __cdecl CRTDLL__futime(INT fd, struct _utimbuf *t)
591 {
592   HANDLE hand = __CRTDLL__fdtoh(fd);
593   FILETIME at, wt;
594
595   if (!t)
596   {
597     time_t currTime;
598     CRTDLL_time(&currTime);
599     RtlSecondsSince1970ToTime( currTime, &at );
600     memcpy( &wt, &at, sizeof(wt) );
601   }
602   else
603   {
604     RtlSecondsSince1970ToTime( t->actime, &at );
605     if (t->actime == t->modtime)
606       memcpy( &wt, &at, sizeof(wt) );
607     else
608       RtlSecondsSince1970ToTime( t->modtime, &wt );
609   }
610
611   if (!SetFileTime( hand, NULL, &at, &wt ))
612   {
613     __CRTDLL__set_errno(GetLastError());
614     return -1 ;
615   }
616   return 0;
617 }
618
619
620 /*********************************************************************
621  *                  _get_osfhandle     (CRTDLL.117)
622  *
623  * Return a Win32 HANDLE from a file descriptor.
624  *
625  * PARAMS
626  * fd [in] A valid file descriptor
627  *
628  * RETURNS
629  * Success: A Win32 HANDLE
630  *
631  * Failure: INVALID_HANDLE_VALUE.
632  *
633  */
634 HANDLE CRTDLL__get_osfhandle(INT fd)
635 {
636   HANDLE hand = __CRTDLL__fdtoh(fd);
637   HANDLE newhand = hand;
638   TRACE(":fd (%d) handle (%d)\n",fd,hand);
639
640   if (hand != INVALID_HANDLE_VALUE)
641   {
642     /* FIXME: I'm not convinced that I should be copying the
643      * handle here - it may be leaked if the app doesn't 
644      * close it (and the API docs dont say that it should)
645      * Not duplicating it means that it can't be inherited
646      * and so lcc's wedit doesn't cope when it passes it to
647      * child processes. I've an idea that it should either
648      * be copied by CreateProcess, or marked as inheritable
649      * when initialised, or maybe both? JG 21-9-00.
650      */
651     DuplicateHandle(GetCurrentProcess(),hand,GetCurrentProcess(),
652                     &newhand,0,TRUE,DUPLICATE_SAME_ACCESS );
653   }
654   return newhand;
655 }
656
657
658 /*********************************************************************
659  *                  _getw       (CRTDLL.128)
660  *
661  * Read an integter from a FILE*.
662  */
663 INT __cdecl CRTDLL__getw( CRTDLL_FILE* file )
664 {
665   INT i;
666   if (CRTDLL__read(file->_file, &i, sizeof(INT)) != 1)
667     return CRTDLL_EOF;
668   return i;
669 }
670
671
672 /*********************************************************************
673  *                  _isatty       (CRTDLL.137)
674  *
675  * Return non zero if fd is a character device (e.g console).
676  */
677 INT __cdecl CRTDLL__isatty(INT fd)
678 {
679   HANDLE hand = __CRTDLL__fdtoh(fd);
680
681   TRACE(":fd (%d) handle (%d)\n",fd,hand);
682   if (hand == INVALID_HANDLE_VALUE)
683     return 0;
684
685   return GetFileType(fd) == FILE_TYPE_CHAR? 1 : 0;
686 }
687
688
689 /*********************************************************************
690  *                  _lseek     (CRTDLL.179)
691  *
692  * Move the file pointer within a file.
693  */
694 LONG __cdecl CRTDLL__lseek( INT fd, LONG offset, INT whence)
695 {
696   DWORD ret;
697   HANDLE hand = __CRTDLL__fdtoh(fd);
698
699   TRACE(":fd (%d) handle (%d)\n",fd,hand);
700   if (hand == INVALID_HANDLE_VALUE)
701     return -1;
702
703   if (whence < 0 || whence > 2)
704   {
705     CRTDLL_errno = EINVAL;
706     return -1;
707   }
708
709   TRACE(":fd (%d) to 0x%08lx pos %s\n",
710         fd,offset,(whence==SEEK_SET)?"SEEK_SET":
711         (whence==SEEK_CUR)?"SEEK_CUR":
712         (whence==SEEK_END)?"SEEK_END":"UNKNOWN");
713
714   if ((ret = SetFilePointer( hand, offset, NULL, whence )) != 0xffffffff)
715   {
716     if ( __CRTDLL_files[fd])
717       __CRTDLL_files[fd]->_flag &= ~_IOEOF;
718     /* FIXME: What if we seek _to_ EOF - is EOF set? */
719     return ret;
720   }
721   TRACE(":error-last error (%ld)\n",GetLastError());
722   if ( __CRTDLL_files[fd])
723     switch(GetLastError())
724     {
725     case ERROR_NEGATIVE_SEEK:
726     case ERROR_SEEK_ON_DEVICE:
727       __CRTDLL__set_errno(GetLastError());
728       __CRTDLL_files[fd]->_flag |= _IOERR;
729       break;
730     default:
731       break;
732     }
733   return -1;
734 }
735
736 /*********************************************************************
737  *                  _mktemp           (CRTDLL.239)
738  *
739  * Create a temporary file name.
740  */
741 LPSTR __cdecl CRTDLL__mktemp(LPSTR pattern)
742 {
743   int numX = 0;
744   LPSTR retVal = pattern;
745   INT id;
746   char letter = 'a';
747
748   while(*pattern)
749     numX = (*pattern++ == 'X')? numX + 1 : 0;
750   if (numX < 5)
751     return NULL;
752   pattern--;
753   id = GetCurrentProcessId();
754   numX = 6;
755   while(numX--)
756   {
757     INT tempNum = id / 10;
758     *pattern-- = id - (tempNum * 10) + '0';
759     id = tempNum;
760   }
761   pattern++;
762   do
763   {
764     if (GetFileAttributesA( retVal ) == 0xFFFFFFFF &&
765         GetLastError() == ERROR_FILE_NOT_FOUND)
766       return retVal;
767     *pattern = letter++;
768   } while(letter != '|');
769   return NULL;
770 }
771
772 /*********************************************************************
773  *                  _open           (CRTDLL.239)
774  * Open a file.
775  */
776 INT __cdecl CRTDLL__open(LPCSTR path,INT flags)
777 {
778   DWORD access = 0, creation = 0;
779   INT ioflag = 0, fd;
780   HANDLE hand;
781
782   TRACE(":file (%s) mode 0x%04x\n",path,flags);
783
784   switch(flags & (_O_RDONLY | _O_WRONLY | _O_RDWR))
785   {
786   case _O_RDONLY:
787     access |= GENERIC_READ;
788     ioflag |= _IOREAD;
789     break;
790   case _O_WRONLY:
791     access |= GENERIC_WRITE;
792     ioflag |= _IOWRT;
793     break;
794   case _O_RDWR:
795     access |= GENERIC_WRITE | GENERIC_READ;
796     ioflag |= _IORW;
797     break;
798   }
799
800   if (flags & _O_CREAT)
801   {
802     if (flags & _O_EXCL)
803       creation = CREATE_NEW;
804     else if (flags & _O_TRUNC)
805       creation = CREATE_ALWAYS;
806     else
807       creation = OPEN_ALWAYS;
808   }
809   else  /* no _O_CREAT */
810   {
811     if (flags & _O_TRUNC)
812       creation = TRUNCATE_EXISTING;
813     else
814       creation = OPEN_EXISTING;
815   }
816   if (flags & _O_APPEND)
817     ioflag |= _IOAPPEND;
818
819
820   flags |= _O_BINARY; /* FIXME: Default to text */
821
822   if (flags & _O_TEXT)
823   {
824     /* Dont warn when writing */
825     if (ioflag & GENERIC_READ)
826       FIXME(":TEXT node not implemented\n");
827     flags &= ~_O_TEXT;
828   }
829
830   if (flags & ~(_O_BINARY|_O_TEXT|_O_APPEND|_O_TRUNC|_O_EXCL
831                 |_O_CREAT|_O_RDWR|_O_TEMPORARY))
832     TRACE(":unsupported flags 0x%04x\n",flags);
833
834   hand = CreateFileA( path, access, FILE_SHARE_READ | FILE_SHARE_WRITE,
835                       NULL, creation, FILE_ATTRIBUTE_NORMAL, -1);
836
837   if (hand == INVALID_HANDLE_VALUE)
838   {
839     WARN(":failed-last error (%ld)\n",GetLastError());
840     __CRTDLL__set_errno(GetLastError());
841     return -1;
842   }
843
844   fd = __CRTDLL__alloc_fd(hand, ioflag);
845
846   TRACE(":fd (%d) handle (%d)\n",fd, hand);
847
848   if (fd > 0)
849   {
850     if (flags & _O_TEMPORARY)
851       __CRTDLL_tempfiles[fd] = CRTDLL__strdup(path);
852     if (ioflag & _IOAPPEND)
853       CRTDLL__lseek(fd, 0, FILE_END );
854   }
855
856   return fd;
857 }
858
859
860 /*********************************************************************
861  *                  _open_osfhandle         (CRTDLL.240)
862  *
863  * Create a file descriptor for a file HANDLE.
864  */
865 INT __cdecl CRTDLL__open_osfhandle(HANDLE hand, INT flags)
866 {
867   INT fd = __CRTDLL__alloc_fd(hand,flags);
868   TRACE(":handle (%d) fd (%d)\n",hand,fd);
869   return fd;
870 }
871
872
873 /*********************************************************************
874  *                  _putw         (CRTDLL.254)
875  *
876  * Write an int to a FILE*.
877  */
878 INT __cdecl CRTDLL__putw(INT val, CRTDLL_FILE* file)
879 {
880   return CRTDLL__write(file->_file, &val, sizeof(val)) == 1? val : CRTDLL_EOF;
881 }
882
883
884 /*********************************************************************
885  *                  _rmtmp     (CRTDLL.256)
886  *
887  * Remove all temporary files created by tmpfile().
888  */
889 INT __cdecl CRTDLL__rmtmp(void)
890 {
891   int num_removed = 0, i = 3;
892
893   while(i < __CRTDLL_fdend)
894     if (__CRTDLL_tempfiles[i])
895     {
896       CRTDLL__close(i);
897       num_removed++;
898     }
899
900   if (num_removed)
901     TRACE(":removed (%d) temp files\n",num_removed);
902   return num_removed;
903 }
904
905
906 /*********************************************************************
907  *                  _read     (CRTDLL.256)
908  *
909  * Read data from a file.
910  */
911 INT __cdecl CRTDLL__read(INT fd, LPVOID buf, UINT count)
912 {
913   DWORD num_read;
914   HANDLE hand = __CRTDLL__fdtoh(fd);
915
916   /* Dont trace small reads, it gets *very* annoying */
917   if (count > 4)
918     TRACE(":fd (%d) handle (%d) buf (%p) len (%d)\n",fd,hand,buf,count);
919   if (hand == INVALID_HANDLE_VALUE)
920     return -1;
921
922   /* Set _cnt to 0 so optimised binaries will call our implementation
923    * of putc/getc. See _filbuf/_flsbuf comments.
924    */
925   if (__CRTDLL_files[fd])
926     __CRTDLL_files[fd]->_cnt = 0;
927
928   if (ReadFile(hand, buf, count, &num_read, NULL))
929   {
930     if (num_read != count && __CRTDLL_files[fd])
931     {
932       TRACE(":EOF\n");
933       __CRTDLL_files[fd]->_flag |= _IOEOF;
934     }
935     return num_read;
936   }
937   TRACE(":failed-last error (%ld)\n",GetLastError());
938   if ( __CRTDLL_files[fd])
939      __CRTDLL_files[fd]->_flag |= _IOERR;
940   return -1;
941 }
942
943
944 /*********************************************************************
945  *                  _setmode           (CRTDLL.265)
946  *
947  * FIXME: At present we ignore the request to translate CR/LF to LF.
948  *
949  * We always translate when we read with fgets, we never do with fread
950  *
951  */
952 INT __cdecl CRTDLL__setmode(INT fd,INT mode)
953 {
954   if (mode & _O_TEXT)
955     FIXME("fd (%d) mode (%d) TEXT not implemented\n",fd,mode);
956   return 0;
957 }
958
959
960 /*********************************************************************
961  *                  _stat          (CRTDLL.280)
962  */
963 INT __cdecl CRTDLL__stat(const char* path, struct _stat * buf)
964 {
965   DWORD dw;
966   WIN32_FILE_ATTRIBUTE_DATA hfi;
967   unsigned short mode = CRTDLL_S_IREAD;
968   int plen;
969
970   TRACE(":file (%s) buf(%p)\n",path,buf);
971
972   if (!GetFileAttributesExA( path, GetFileExInfoStandard, &hfi ))
973   {
974       TRACE("failed-last error (%ld)\n",GetLastError());
975       __CRTDLL__set_errno(ERROR_FILE_NOT_FOUND);
976       return -1;
977   }
978
979   memset(buf,0,sizeof(struct _stat));
980
981   /* FIXME: rdev isnt drive num,despite what the docs say-what is it? */
982   if (isalpha(*path))
983     buf->st_dev = buf->st_rdev = toupper(*path - 'A'); /* drive num */
984   else
985     buf->st_dev = buf->st_rdev = CRTDLL__getdrive() - 1;
986
987   plen = strlen(path);
988
989   /* Dir, or regular file? */
990   if ((hfi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
991       (path[plen-1] == '\\'))
992     mode |= (_S_IFDIR | CRTDLL_S_IEXEC);
993   else
994   {
995     mode |= _S_IFREG;
996     /* executable? */
997     if (plen > 6 && path[plen-4] == '.')  /* shortest exe: "\x.exe" */
998     {
999       unsigned int ext = tolower(path[plen-1]) | (tolower(path[plen-2]) << 8)
1000         | (tolower(path[plen-3]) << 16);
1001       if (ext == EXE || ext == BAT || ext == CMD || ext == COM)
1002         mode |= CRTDLL_S_IEXEC;
1003     }
1004   }
1005
1006   if (!(hfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
1007     mode |= CRTDLL_S_IWRITE;
1008
1009   buf->st_mode  = mode;
1010   buf->st_nlink = 1;
1011   buf->st_size  = hfi.nFileSizeLow;
1012   RtlTimeToSecondsSince1970( &hfi.ftLastAccessTime, &dw );
1013   buf->st_atime = dw;
1014   RtlTimeToSecondsSince1970( &hfi.ftLastWriteTime, &dw );
1015   buf->st_mtime = buf->st_ctime = dw;
1016   TRACE("\n%d %d %d %d %d %d\n", buf->st_mode,buf->st_nlink,buf->st_size,
1017         buf->st_atime,buf->st_mtime, buf->st_ctime);
1018   return 0;
1019 }
1020
1021
1022 /*********************************************************************
1023  *                  _tell           (CRTDLL.302)
1024  *
1025  * Get current file position.
1026  */
1027 LONG __cdecl CRTDLL__tell(INT fd)
1028 {
1029   return CRTDLL__lseek(fd, 0, SEEK_CUR);
1030 }
1031
1032
1033 /*********************************************************************
1034  *                  _tempnam           (CRTDLL.305)
1035  * 
1036  */
1037 LPSTR __cdecl CRTDLL__tempnam(LPCSTR dir, LPCSTR prefix)
1038 {
1039   char tmpbuf[MAX_PATH];
1040
1041   TRACE("dir (%s) prefix (%s)\n",dir,prefix);
1042   if (GetTempFileNameA(dir,prefix,0,tmpbuf))
1043   {
1044     TRACE("got name (%s)\n",tmpbuf);
1045     return CRTDLL__strdup(tmpbuf);
1046   }
1047   TRACE("failed-last error (%ld)\n",GetLastError());
1048   return NULL;
1049 }
1050
1051
1052 /*********************************************************************
1053  *                  _umask           (CRTDLL.310)
1054  *
1055  * Set the process-wide umask.
1056  */
1057 INT __cdecl CRTDLL__umask(INT umask)
1058 {
1059   INT old_umask = __CRTDLL_umask;
1060   TRACE("umask (%d)\n",umask);
1061   __CRTDLL_umask = umask;
1062   return old_umask;
1063 }
1064
1065
1066 /*********************************************************************
1067  *                  _utime         (CRTDLL.314)
1068  * 
1069  * Set the file access/modification times on a file.
1070  */
1071 INT __cdecl CRTDLL__utime(LPCSTR path, struct _utimbuf *t)
1072 {
1073   INT fd = CRTDLL__open( path, _O_WRONLY | _O_BINARY );
1074
1075   if (fd > 0)
1076   {
1077     INT retVal = CRTDLL__futime(fd, t);
1078     CRTDLL__close(fd);
1079     return retVal;
1080   }
1081   return -1;
1082 }
1083
1084
1085 /*********************************************************************
1086  *                  _unlink           (CRTDLL.315)
1087  *
1088  * Delete a file.
1089  */
1090 INT __cdecl CRTDLL__unlink(LPCSTR path)
1091 {
1092   TRACE("path (%s)\n",path);
1093   if(DeleteFileA( path ))
1094     return 0;
1095
1096   TRACE("failed-last error (%ld)\n",GetLastError());
1097   __CRTDLL__set_errno(GetLastError());
1098   return -1;
1099 }
1100
1101
1102 /*********************************************************************
1103  *                  _write        (CRTDLL.332)
1104  *
1105  * Write data to a file.
1106  */
1107 UINT __cdecl CRTDLL__write(INT fd, LPCVOID buf, UINT count)
1108 {
1109   DWORD num_written;
1110   HANDLE hand = __CRTDLL__fdtoh(fd);
1111
1112   /* Dont trace small writes, it gets *very* annoying */
1113   if (count > 4)
1114     TRACE(":fd (%d) handle (%d) buf (%p) len (%d)\n",fd,hand,buf,count);
1115   if (hand == INVALID_HANDLE_VALUE)
1116     return -1;
1117
1118   /* If appending, go to EOF */
1119   if (__CRTDLL_flags[fd] & _IOAPPEND)
1120     CRTDLL__lseek(fd, 0, FILE_END );
1121
1122   /* Set _cnt to 0 so optimised binaries will call our implementation
1123    * of putc/getc. See _filbuf/_flsbuf comments.
1124    */
1125   if (__CRTDLL_files[fd])
1126     __CRTDLL_files[fd]->_cnt = 0;
1127
1128   if (WriteFile(hand, buf, count, &num_written, NULL)
1129       &&  (num_written == count))
1130     return num_written;
1131
1132   TRACE(":failed-last error (%ld)\n",GetLastError());
1133   if ( __CRTDLL_files[fd])
1134      __CRTDLL_files[fd]->_flag |= _IOERR;
1135
1136   return -1;
1137 }
1138
1139
1140 /*********************************************************************
1141  *                  clearerr     (CRTDLL.349)
1142  *
1143  * Clear a FILE's error indicator.
1144  */
1145 VOID __cdecl CRTDLL_clearerr(CRTDLL_FILE* file)
1146 {
1147   TRACE(":file (%p) fd (%d)\n",file,file->_file);
1148   file->_flag &= ~(_IOERR | _IOEOF);
1149 }
1150
1151
1152 /*********************************************************************
1153  *                  fclose           (CRTDLL.362)
1154  *
1155  * Close an open file.
1156  */
1157 INT __cdecl CRTDLL_fclose( CRTDLL_FILE* file )
1158 {
1159   return CRTDLL__close(file->_file);
1160 }
1161
1162
1163 /*********************************************************************
1164  *                  feof           (CRTDLL.363)
1165  *
1166  * Check the eof indicator on a file.
1167  */
1168 INT __cdecl CRTDLL_feof( CRTDLL_FILE* file )
1169 {
1170   return file->_flag & _IOEOF;
1171 }
1172
1173
1174 /*********************************************************************
1175  *                  ferror         (CRTDLL.361)
1176  *
1177  * Check the error indicator on a file.
1178  */
1179 INT __cdecl CRTDLL_ferror( CRTDLL_FILE* file )
1180 {
1181   return file->_flag & _IOERR;
1182 }
1183
1184
1185 /*********************************************************************
1186  *                  fflush        (CRTDLL.362)
1187  */
1188 INT __cdecl CRTDLL_fflush( CRTDLL_FILE* file )
1189 {
1190   return CRTDLL__commit(file->_file);
1191 }
1192
1193
1194 /*********************************************************************
1195  *                  fgetc       (CRTDLL.363)
1196  */
1197 INT __cdecl CRTDLL_fgetc( CRTDLL_FILE* file )
1198 {
1199   char c;
1200   if (CRTDLL__read(file->_file,&c,1) != 1)
1201     return CRTDLL_EOF;
1202   return c;
1203 }
1204
1205
1206 /*********************************************************************
1207  *                  fgetpos       (CRTDLL.364)
1208  */
1209 INT __cdecl CRTDLL_fgetpos( CRTDLL_FILE* file, CRTDLL_fpos_t *pos)
1210 {
1211   *pos = CRTDLL__tell(file->_file);
1212   return (*pos == -1? -1 : 0);
1213 }
1214
1215
1216 /*********************************************************************
1217  *                  fgets       (CRTDLL.365)
1218  */
1219 CHAR* __cdecl CRTDLL_fgets(LPSTR s, INT size, CRTDLL_FILE* file)
1220 {
1221   int    cc;
1222   LPSTR  buf_start = s;
1223
1224   TRACE(":file(%p) fd (%d) str (%p) len (%d)\n",
1225         file,file->_file,s,size);
1226
1227   /* BAD, for the whole WINE process blocks... just done this way to test
1228    * windows95's ftp.exe.
1229    * JG - Is this true now we use ReadFile() on stdin too?
1230    */
1231   for(cc = CRTDLL_fgetc(file); cc != CRTDLL_EOF && cc != '\n';
1232       cc = CRTDLL_fgetc(file))
1233     if (cc != '\r')
1234     {
1235       if (--size <= 0) break;
1236       *s++ = (char)cc;
1237     }
1238   if ((cc == CRTDLL_EOF) && (s == buf_start)) /* If nothing read, return 0*/
1239   {
1240     TRACE(":nothing read\n");
1241     return 0;
1242   }
1243   if (cc == '\n')
1244     if (--size > 0)
1245       *s++ = '\n';
1246   *s = '\0';
1247   TRACE(":got '%s'\n", buf_start);
1248   return buf_start;
1249 }
1250
1251
1252 /*********************************************************************
1253  *                  fgetwc       (CRTDLL.366)
1254  *
1255  * Read a wide character from a FILE*.
1256  */
1257 WCHAR __cdecl CRTDLL_fgetwc( CRTDLL_FILE* file )
1258 {
1259   WCHAR wc;
1260   if (CRTDLL__read(file->_file, &wc, sizeof(wc)) != sizeof(wc))
1261     return CRTDLL_WEOF;
1262   return wc;
1263 }
1264
1265
1266 /*********************************************************************
1267  *                  fputwc       (CRTDLL.373)
1268  *
1269  * Write a wide character to a FILE*.
1270  */
1271 WCHAR __cdecl CRTDLL_fputwc( WCHAR wc, CRTDLL_FILE* file)
1272 {
1273   if (CRTDLL__write(file->_file, &wc, sizeof(wc)) != sizeof(wc))
1274     return CRTDLL_WEOF;
1275   return wc;
1276 }
1277
1278
1279 /*********************************************************************
1280  *                  fputs       (CRTDLL.375)
1281  */
1282 INT __cdecl CRTDLL_fputs( LPCSTR s, CRTDLL_FILE* file )
1283 {
1284   return CRTDLL_fwrite(s,strlen(s),1,file);
1285 }
1286
1287
1288 /*********************************************************************
1289  *                  fprintf       (CRTDLL.370)
1290  */
1291 INT __cdecl CRTDLL_fprintf( CRTDLL_FILE* file, LPCSTR format, ... )
1292 {
1293     va_list valist;
1294     INT res;
1295
1296     va_start( valist, format );
1297     res = CRTDLL_vfprintf( file, format, valist );
1298     va_end( valist );
1299     return res;
1300 }
1301
1302
1303 /*********************************************************************
1304  *                  fopen     (CRTDLL.372)
1305  *
1306  * Open a file.
1307  */
1308 CRTDLL_FILE* __cdecl CRTDLL_fopen(LPCSTR path, LPCSTR mode)
1309 {
1310   CRTDLL_FILE* file;
1311   INT flags = 0, plus = 0, fd;
1312   const char* search = mode;
1313
1314   TRACE(":path (%s) mode (%s)\n",path,mode);
1315
1316   while (*search)
1317     if (*search++ == '+')
1318       plus = 1;
1319
1320   /* map mode string to open() flags. "man fopen" for possibilities. */
1321   switch(*mode++)
1322   {
1323   case 'R': case 'r':
1324     flags = (plus ? _O_RDWR : _O_RDONLY);
1325     break;
1326   case 'W': case 'w':
1327     flags = _O_CREAT | _O_TRUNC | (plus  ? _O_RDWR : _O_WRONLY);
1328     break;
1329   case 'A': case 'a':
1330     flags = _O_CREAT | _O_APPEND | (plus  ? _O_RDWR : _O_WRONLY);
1331     break;
1332   default:
1333     return NULL;
1334   }
1335
1336   while (*mode)
1337     switch (*mode++)
1338     {
1339     case 'B': case 'b':
1340       flags |=  _O_BINARY;
1341       flags &= ~_O_TEXT;
1342       break;
1343     case 'T': case 't':
1344       flags |=  _O_TEXT;
1345       flags &= ~_O_BINARY;
1346       break;
1347     case '+':
1348       break;
1349     default:
1350       FIXME(":unknown flag %c not supported\n",mode[-1]);
1351     }
1352
1353   fd = CRTDLL__open(path, flags);
1354
1355   if (fd < 0)
1356     return NULL;
1357
1358   file = __CRTDLL__alloc_fp(fd);
1359   TRACE(":get file (%p)\n",file);
1360   if (!file)
1361     CRTDLL__close(fd);
1362
1363   return file;
1364 }
1365
1366
1367 /*********************************************************************
1368  *                  fputc       (CRTDLL.374)
1369  */
1370 INT __cdecl CRTDLL_fputc( INT c, CRTDLL_FILE* file )
1371 {
1372   return CRTDLL__write(file->_file, &c, 1) == 1? c : CRTDLL_EOF;
1373 }
1374
1375
1376 /*********************************************************************
1377  *                  fread     (CRTDLL.377)
1378  */
1379 DWORD __cdecl CRTDLL_fread(LPVOID ptr, INT size, INT nmemb, CRTDLL_FILE* file)
1380 {
1381   DWORD read = CRTDLL__read(file->_file,ptr, size * nmemb);
1382   if (read <= 0)
1383     return 0;
1384   return read / size;
1385 }
1386
1387
1388 /*********************************************************************
1389  *                  freopen    (CRTDLL.379)
1390  * 
1391  */
1392 CRTDLL_FILE* __cdecl CRTDLL_freopen(LPCSTR path, LPCSTR mode,CRTDLL_FILE* file)
1393 {
1394   CRTDLL_FILE* newfile;
1395   INT fd;
1396
1397   TRACE(":path (%p) mode (%s) file (%p) fd (%d)\n",path,mode,file,file->_file);
1398   if (!file || ((fd = file->_file) < 0) || fd > __CRTDLL_fdend)
1399     return NULL;
1400
1401   if (fd > 2)
1402   {
1403     FIXME(":reopen on user file not implemented!\n");
1404     __CRTDLL__set_errno(ERROR_CALL_NOT_IMPLEMENTED);
1405     return NULL;
1406   }
1407
1408   /* first, create the new file */
1409   if ((newfile = CRTDLL_fopen(path,mode)) == NULL)
1410     return NULL;
1411
1412   if (fd < 3 && SetStdHandle(fd == 0 ? STD_INPUT_HANDLE :
1413      (fd == 1? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE),
1414       __CRTDLL_handles[newfile->_file]))
1415   {
1416     /* Redirecting std handle to file , copy over.. */
1417     __CRTDLL_handles[fd] = __CRTDLL_handles[newfile->_file];
1418     __CRTDLL_flags[fd] = __CRTDLL_flags[newfile->_file];
1419     memcpy(&__CRTDLL_iob[fd], newfile, sizeof (CRTDLL_FILE));
1420     __CRTDLL_iob[fd]._file = fd;
1421     /* And free up the resources allocated by fopen, but
1422      * not the HANDLE we copied. */
1423     CRTDLL_free(__CRTDLL_files[fd]);
1424     __CRTDLL__free_fd(newfile->_file);
1425     return &__CRTDLL_iob[fd];
1426   }
1427
1428   WARN(":failed-last error (%ld)\n",GetLastError());
1429   CRTDLL_fclose(newfile);
1430   __CRTDLL__set_errno(GetLastError());
1431   return NULL;
1432 }
1433
1434
1435 /*********************************************************************
1436  *                  fsetpos       (CRTDLL.380)
1437  */
1438 INT __cdecl CRTDLL_fsetpos( CRTDLL_FILE* file, CRTDLL_fpos_t *pos)
1439 {
1440   return CRTDLL__lseek(file->_file,*pos,SEEK_SET);
1441 }
1442
1443
1444 /*********************************************************************
1445  *                  fscanf     (CRTDLL.381)
1446  */
1447 INT __cdecl CRTDLL_fscanf( CRTDLL_FILE* file, LPCSTR format, ... )
1448 {
1449     /* NOTE: If you extend this function, extend CRTDLL__cscanf in console.c too */
1450     INT rd = 0;
1451     int nch;
1452     va_list ap;
1453     if (!*format) return 0;
1454     WARN("%p (\"%s\"): semi-stub\n", file, format);
1455     nch = CRTDLL_fgetc(file);
1456     va_start(ap, format);
1457     while (*format) {
1458         if (*format == ' ') {
1459             /* skip whitespace */
1460             while ((nch!=CRTDLL_EOF) && isspace(nch))
1461                 nch = CRTDLL_fgetc(file);
1462         }
1463         else if (*format == '%') {
1464             int st = 0;
1465             format++;
1466             switch(*format) {
1467             case 'd': { /* read an integer */
1468                     int*val = va_arg(ap, int*);
1469                     int cur = 0;
1470                     /* skip initial whitespace */
1471                     while ((nch!=CRTDLL_EOF) && isspace(nch))
1472                         nch = CRTDLL_fgetc(file);
1473                     /* get sign and first digit */
1474                     if (nch == '-') {
1475                         nch = CRTDLL_fgetc(file);
1476                         if (isdigit(nch))
1477                             cur = -(nch - '0');
1478                         else break;
1479                     } else {
1480                         if (isdigit(nch))
1481                             cur = nch - '0';
1482                         else break;
1483                     }
1484                     nch = CRTDLL_fgetc(file);
1485                     /* read until no more digits */
1486                     while ((nch!=CRTDLL_EOF) && isdigit(nch)) {
1487                         cur = cur*10 + (nch - '0');
1488                         nch = CRTDLL_fgetc(file);
1489                     }
1490                     st = 1;
1491                     *val = cur;
1492                 }
1493                 break;
1494             case 'f': { /* read a float */
1495                     float*val = va_arg(ap, float*);
1496                     float cur = 0;
1497                     /* skip initial whitespace */
1498                     while ((nch!=CRTDLL_EOF) && isspace(nch))
1499                         nch = CRTDLL_fgetc(file);
1500                     /* get sign and first digit */
1501                     if (nch == '-') {
1502                         nch = CRTDLL_fgetc(file);
1503                         if (isdigit(nch))
1504                             cur = -(nch - '0');
1505                         else break;
1506                     } else {
1507                         if (isdigit(nch))
1508                             cur = nch - '0';
1509                         else break;
1510                     }
1511                     /* read until no more digits */
1512                     while ((nch!=CRTDLL_EOF) && isdigit(nch)) {
1513                         cur = cur*10 + (nch - '0');
1514                         nch = CRTDLL_fgetc(file);
1515                     }
1516                     if (nch == '.') {
1517                         /* handle decimals */
1518                         float dec = 1;
1519                         nch = CRTDLL_fgetc(file);
1520                         while ((nch!=CRTDLL_EOF) && isdigit(nch)) {
1521                             dec /= 10;
1522                             cur += dec * (nch - '0');
1523                             nch = CRTDLL_fgetc(file);
1524                         }
1525                     }
1526                     st = 1;
1527                     *val = cur;
1528                 }
1529                 break;
1530             case 's': { /* read a word */
1531                     char*str = va_arg(ap, char*);
1532                     char*sptr = str;
1533                     /* skip initial whitespace */
1534                     while ((nch!=CRTDLL_EOF) && isspace(nch))
1535                         nch = CRTDLL_fgetc(file);
1536                     /* read until whitespace */
1537                     while ((nch!=CRTDLL_EOF) && !isspace(nch)) {
1538                         *sptr++ = nch; st++;
1539                         nch = CRTDLL_fgetc(file);
1540                     }
1541                     /* terminate */
1542                     *sptr = 0;
1543                     TRACE("read word: %s\n", str);
1544                 }
1545                 break;
1546             default: FIXME("unhandled: %%%c\n", *format);
1547             }
1548             if (st) rd++;
1549             else break;
1550         }
1551         else {
1552             /* check for character match */
1553             if (nch == *format)
1554                nch = CRTDLL_fgetc(file);
1555             else break;
1556         }
1557         format++;
1558     }
1559     va_end(ap);
1560     if (nch!=CRTDLL_EOF) {
1561         WARN("need ungetch\n");
1562     }
1563     TRACE("returning %d\n", rd);
1564     return rd;
1565 }
1566
1567
1568 /*********************************************************************
1569  *                  fseek     (CRTDLL.382)
1570  */
1571 LONG __cdecl CRTDLL_fseek( CRTDLL_FILE* file, LONG offset, INT whence)
1572 {
1573   return CRTDLL__lseek(file->_file,offset,whence);
1574 }
1575
1576
1577 /*********************************************************************
1578  *                  ftell     (CRTDLL.381)
1579  */
1580 LONG __cdecl CRTDLL_ftell( CRTDLL_FILE* file )
1581 {
1582   return CRTDLL__tell(file->_file);
1583 }
1584
1585
1586 /*********************************************************************
1587  *                  fwrite     (CRTDLL.383)
1588  */
1589 UINT __cdecl CRTDLL_fwrite( LPCVOID ptr, INT size, INT nmemb, CRTDLL_FILE* file )
1590 {
1591   UINT written = CRTDLL__write(file->_file, ptr, size * nmemb);
1592   if (written <= 0)
1593     return 0;
1594   return written / size;
1595 }
1596
1597
1598 /*********************************************************************
1599  *                  getchar       (CRTDLL.386)
1600  */
1601 INT __cdecl CRTDLL_getchar( VOID )
1602 {
1603   return CRTDLL_fgetc(CRTDLL_stdin);
1604 }
1605
1606
1607 /*********************************************************************
1608  *                  getc       (CRTDLL.388)
1609  */
1610 INT __cdecl CRTDLL_getc( CRTDLL_FILE* file )
1611 {
1612     return CRTDLL_fgetc( file );
1613 }
1614
1615
1616 /*********************************************************************
1617  *                  gets          (CRTDLL.391)
1618  */
1619 LPSTR __cdecl CRTDLL_gets(LPSTR buf)
1620 {
1621     int    cc;
1622     LPSTR  buf_start = buf;
1623
1624     /* BAD, for the whole WINE process blocks... just done this way to test
1625      * windows95's ftp.exe.
1626      * JG 19/9/00: Is this still true, now we are using ReadFile?
1627      */
1628     for(cc = CRTDLL_fgetc(CRTDLL_stdin); cc != CRTDLL_EOF && cc != '\n';
1629         cc = CRTDLL_fgetc(CRTDLL_stdin))
1630         if(cc != '\r') *buf++ = (char)cc;
1631
1632     *buf = '\0';
1633
1634     TRACE("got '%s'\n", buf_start);
1635     return buf_start;
1636 }
1637
1638
1639 /*********************************************************************
1640  *                  putc       (CRTDLL.441)
1641  */
1642 INT __cdecl CRTDLL_putc( INT c, CRTDLL_FILE* file )
1643 {
1644   return CRTDLL_fputc( c, file );
1645 }
1646
1647
1648 /*********************************************************************
1649  *                  putchar       (CRTDLL.442)
1650  */
1651 void __cdecl CRTDLL_putchar( INT c )
1652 {
1653   CRTDLL_fputc(c, CRTDLL_stdout);
1654 }
1655
1656
1657 /*********************************************************************
1658  *                  puts       (CRTDLL.443)
1659  */
1660 INT __cdecl CRTDLL_puts(LPCSTR s)
1661 {
1662   return CRTDLL_fputs(s, CRTDLL_stdout);
1663 }
1664
1665
1666 /*********************************************************************
1667  *                  remove           (CRTDLL.445)
1668  */
1669 INT __cdecl CRTDLL_remove(LPCSTR path)
1670 {
1671   TRACE(":path (%s)\n",path);
1672   if (DeleteFileA(path))
1673     return 0;
1674   TRACE(":failed-last error (%ld)\n",GetLastError());
1675   __CRTDLL__set_errno(GetLastError());
1676   return -1;
1677 }
1678
1679
1680 /*********************************************************************
1681  *                  rewind     (CRTDLL.447)
1682  *
1683  * Set the file pointer to the start of a file and clear any error
1684  * indicators.
1685  */
1686 VOID __cdecl CRTDLL_rewind(CRTDLL_FILE* file)
1687 {
1688   TRACE(":file (%p) fd (%d)\n",file,file->_file);
1689   CRTDLL__lseek(file->_file,0,SEEK_SET);
1690   file->_flag &= ~(_IOEOF | _IOERR);
1691 }
1692
1693
1694 /*********************************************************************
1695  *                  scanf      (CRTDLL.448)
1696  */
1697 INT __cdecl CRTDLL_scanf( LPCSTR format, ... )
1698 {
1699   va_list valist;
1700   INT res;
1701
1702   va_start( valist, format );
1703   res = CRTDLL_fscanf(CRTDLL_stdin, format, valist);
1704   va_end(va_list);
1705   return res;
1706 }
1707
1708
1709 /*********************************************************************
1710  *                  rename           (CRTDLL.449)
1711  */
1712 INT __cdecl CRTDLL_rename(LPCSTR oldpath,LPCSTR newpath)
1713 {
1714   TRACE(":from %s to %s\n",oldpath,newpath);
1715   if (MoveFileExA( oldpath, newpath, MOVEFILE_REPLACE_EXISTING))
1716     return 0;
1717   TRACE(":failed-last error (%ld)\n",GetLastError());
1718   __CRTDLL__set_errno(GetLastError());
1719   return -1;
1720 }
1721
1722
1723 /*********************************************************************
1724  *                  setbuf     (CRTDLL.452)
1725  */
1726 INT __cdecl CRTDLL_setbuf(CRTDLL_FILE* file, LPSTR buf)
1727 {
1728   TRACE(":file (%p) fd (%d) buf (%p)\n", file, file->_file,buf);
1729   if (buf)
1730     WARN(":user buffer will not be used!\n");
1731   /* FIXME: no buffering for now */
1732   return 0;
1733 }
1734
1735
1736 /*********************************************************************
1737  *                  tmpfile     (CRTDLL.486)
1738  *
1739  * Create and return a temporary file.
1740  */
1741 CRTDLL_FILE* __cdecl CRTDLL_tmpfile(void)
1742 {
1743   LPSTR filename = CRTDLL_tmpnam(NULL);
1744   int fd = CRTDLL__open(filename, _O_CREAT | _O_BINARY |
1745                         _O_RDWR | _O_TEMPORARY);
1746
1747   if (fd != -1)
1748     return __CRTDLL__alloc_fp(fd);
1749
1750   return NULL;
1751 }
1752
1753
1754 /*********************************************************************
1755  *                  tmpnam           (CRTDLL.490)
1756  *
1757  * lcclnk from lcc-win32 relies on a terminating dot in the name returned
1758  * 
1759  */
1760 LPSTR __cdecl CRTDLL_tmpnam(LPSTR s)
1761 {
1762   char tmpbuf[MAX_PATH];
1763   char* prefix = "TMP";
1764   if (!GetTempPathA(MAX_PATH,tmpbuf) ||
1765       !GetTempFileNameA(tmpbuf,prefix,0,CRTDLL_tmpname))
1766   {
1767     TRACE(":failed-last error (%ld)\n",GetLastError());
1768     return NULL;
1769   }
1770   TRACE(":got tmpnam %s\n",CRTDLL_tmpname);
1771   s = CRTDLL_tmpname;
1772   return s;
1773 }
1774
1775
1776 /*********************************************************************
1777  *                  vfprintf       (CRTDLL.494)
1778  *
1779  * Write formatted output to a file.
1780  */
1781
1782 /* we have avoided libc stdio.h so far, lets not start now */
1783 extern int vsprintf(void *, const void *, va_list);
1784
1785 /********************************************************************/
1786
1787 INT __cdecl CRTDLL_vfprintf( CRTDLL_FILE* file, LPCSTR format, va_list args )
1788 {
1789   /* FIXME: We should parse the format string, calculate the maximum,
1790    * length of each arg, malloc a buffer, print to it, and fwrite that.
1791    * Yes this sucks, but not as much as crashing 1/2 way through an
1792    * app writing to a file :-(
1793    */
1794   char buffer[2048];
1795   TRACE(":file (%p) fd (%d) fmt (%s)\n",file,file->_file,format);
1796
1797   vsprintf( buffer, format, args );
1798   return CRTDLL_fwrite( buffer, 1, strlen(buffer), file );
1799 }
1800