2 * CRTDLL file functions
4 * Copyright 1996,1998 Marcus Meissner
5 * Copyright 1996 Jukka Iivonen
6 * Copyright 1997,2000 Uwe Bonnes
7 * Copyright 2000 Jon Griffiths
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 compatable 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.
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 ;-)
44 DEFAULT_DEBUG_CHANNEL(crtdll
);
46 /* FIXME: Make this dynamic */
47 #define CRTDLL_MAX_FILES 257
49 HANDLE __CRTDLL_handles
[CRTDLL_MAX_FILES
];
50 CRTDLL_FILE
* __CRTDLL_files
[CRTDLL_MAX_FILES
];
51 INT __CRTDLL_flags
[CRTDLL_MAX_FILES
];
52 CRTDLL_FILE __CRTDLL_iob
[3];
54 static int __CRTDLL_fdstart
= 3; /* first unallocated fd */
55 static int __CRTDLL_fdend
= 3; /* highest allocated fd */
57 /* INTERNAL: process umask */
58 static INT __CRTDLL_umask
= 0;
60 /* INTERNAL: Static buffer for temp file name */
61 static char CRTDLL_tmpname
[MAX_PATH
];
63 /* file extentions recognised as executables */
64 static const unsigned int EXE
= 'e' << 16 | 'x' << 8 | 'e';
65 static const unsigned int BAT
= 'b' << 16 | 'a' << 8 | 't';
66 static const unsigned int CMD
= 'c' << 16 | 'm' << 8 | 'd';
67 static const unsigned int COM
= 'c' << 16 | 'o' << 8 | 'm';
69 /* for stat mode, permissions apply to all,owner and group */
70 #define CRTDLL_S_IREAD (_S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6))
71 #define CRTDLL_S_IWRITE (_S_IWRITE | (_S_IWRITE >> 3) | (_S_IWRITE >> 6))
72 #define CRTDLL_S_IEXEC (_S_IEXEC | (_S_IEXEC >> 3) | (_S_IEXEC >> 6))
75 /* INTERNAL: Get the HANDLE for a fd */
76 static HANDLE
__CRTDLL__fdtoh(INT fd
);
77 static HANDLE
__CRTDLL__fdtoh(INT fd
)
79 if (fd
< 0 || fd
>= __CRTDLL_fdend
||
80 __CRTDLL_handles
[fd
] == INVALID_HANDLE_VALUE
)
82 WARN(":fd (%d) - no handle!\n",fd
);
85 return INVALID_HANDLE_VALUE
;
87 return __CRTDLL_handles
[fd
];
91 /* INTERNAL: free a file entry fd */
92 static void __CRTDLL__free_fd(INT fd
);
93 static void __CRTDLL__free_fd(INT fd
)
95 __CRTDLL_handles
[fd
] = INVALID_HANDLE_VALUE
;
96 __CRTDLL_files
[fd
] = 0;
97 __CRTDLL_flags
[fd
] = 0;
98 TRACE(":fd (%d) freed\n",fd
);
100 return; /* dont use 0,1,2 for user files */
101 if (fd
== __CRTDLL_fdend
- 1)
103 if (fd
< __CRTDLL_fdstart
)
104 __CRTDLL_fdstart
= fd
;
108 /* INTERNAL: Allocate an fd slot from a Win32 HANDLE */
109 static INT
__CRTDLL__alloc_fd(HANDLE hand
, INT flag
);
110 static INT
__CRTDLL__alloc_fd(HANDLE hand
, INT flag
)
112 INT fd
= __CRTDLL_fdstart
;
114 TRACE(":handle (%d) allocating fd (%d)\n",hand
,fd
);
115 if (fd
>= CRTDLL_MAX_FILES
)
117 WARN(":files exhausted!\n");
120 __CRTDLL_handles
[fd
] = hand
;
121 __CRTDLL_flags
[fd
] = flag
;
123 /* locate next free slot */
124 if (fd
== __CRTDLL_fdend
)
125 __CRTDLL_fdstart
= ++__CRTDLL_fdend
;
127 while(__CRTDLL_fdstart
< __CRTDLL_fdend
&&
128 __CRTDLL_handles
[__CRTDLL_fdstart
] != INVALID_HANDLE_VALUE
)
135 /* INTERNAL: Allocate a FILE* for an fd slot
136 * This is done lazily to avoid memory wastage for low level open/write
137 * usage when a FILE* is not requested (but may be later).
139 static CRTDLL_FILE
* __CRTDLL__alloc_fp(INT fd
);
140 static CRTDLL_FILE
* __CRTDLL__alloc_fp(INT fd
)
142 TRACE(":fd (%d) allocating FILE*\n",fd
);
143 if (fd
< 0 || fd
>= __CRTDLL_fdend
||
144 __CRTDLL_handles
[fd
] == INVALID_HANDLE_VALUE
)
146 WARN(":invalid fd %d\n",fd
);
148 CRTDLL_errno
= EBADF
;
151 if (!__CRTDLL_files
[fd
])
153 if ((__CRTDLL_files
[fd
] = CRTDLL_calloc(sizeof(CRTDLL_FILE
),1)))
155 __CRTDLL_files
[fd
]->_file
= fd
;
156 __CRTDLL_files
[fd
]->_flag
= __CRTDLL_flags
[fd
];
157 __CRTDLL_files
[fd
]->_flag
&= ~_IOAPPEND
; /* mask out, see above */
160 TRACE(":got FILE* (%p)\n",__CRTDLL_files
[fd
]);
161 return __CRTDLL_files
[fd
];
165 /* INTERNAL: Set up stdin, stderr and stdout */
166 VOID
__CRTDLL__init_io(VOID
)
169 memset(__CRTDLL_iob
,0,3*sizeof(CRTDLL_FILE
));
170 __CRTDLL_handles
[0] = GetStdHandle(STD_INPUT_HANDLE
);
171 __CRTDLL_flags
[0] = __CRTDLL_iob
[0]._flag
= _IOREAD
;
172 __CRTDLL_handles
[1] = GetStdHandle(STD_OUTPUT_HANDLE
);
173 __CRTDLL_flags
[1] = __CRTDLL_iob
[1]._flag
= _IOWRT
;
174 __CRTDLL_handles
[2] = GetStdHandle(STD_ERROR_HANDLE
);
175 __CRTDLL_flags
[2] = __CRTDLL_iob
[2]._flag
= _IOWRT
;
177 TRACE(":handles (%d)(%d)(%d)\n",__CRTDLL_handles
[0],
178 __CRTDLL_handles
[1],__CRTDLL_handles
[2]);
180 for (i
= 0; i
< 3; i
++)
182 /* FILE structs for stdin/out/err are static and never deleted */
183 __CRTDLL_files
[i
] = &__CRTDLL_iob
[i
];
184 __CRTDLL_iob
[i
]._file
= i
;
189 /*********************************************************************
190 * _access (CRTDLL.37)
192 INT __cdecl
CRTDLL__access(LPCSTR filename
, INT mode
)
194 DWORD attr
= GetFileAttributesA(filename
);
196 if (attr
== 0xffffffff)
200 /* FIXME: Should GetFileAttributesA() return this? */
201 __CRTDLL__set_errno(ERROR_INVALID_DATA
);
204 __CRTDLL__set_errno(GetLastError());
207 if ((attr
& FILE_ATTRIBUTE_READONLY
) && (mode
& W_OK
))
209 __CRTDLL__set_errno(ERROR_ACCESS_DENIED
);
212 TRACE(":file %s, mode (%d) ok\n",filename
,mode
);
217 /*********************************************************************
220 * Close an open file descriptor.
222 INT __cdecl
CRTDLL__close(INT fd
)
224 HANDLE hand
= __CRTDLL__fdtoh(fd
);
226 TRACE(":fd (%d) handle (%d)\n",fd
,hand
);
227 if (hand
== INVALID_HANDLE_VALUE
)
230 /* Dont free std FILE*'s, they are not dynamic */
231 if (fd
> 2 && __CRTDLL_files
[fd
])
232 CRTDLL_free(__CRTDLL_files
[fd
]);
234 __CRTDLL__free_fd(fd
);
236 if (!CloseHandle(hand
))
238 WARN(":failed-last error (%ld)\n",GetLastError());
239 __CRTDLL__set_errno(GetLastError());
247 /*********************************************************************
248 * _commit (CRTDLL.58)
250 * Ensure all file operations have been flushed to the drive.
252 INT __cdecl
CRTDLL__commit(INT fd
)
254 HANDLE hand
= __CRTDLL__fdtoh(fd
);
256 TRACE(":fd (%d) handle (%d)\n",fd
,hand
);
257 if (hand
== INVALID_HANDLE_VALUE
)
260 if (!FlushFileBuffers(hand
))
262 if (GetLastError() == ERROR_INVALID_HANDLE
)
264 /* FlushFileBuffers fails for console handles
265 * so we ignore this error.
269 TRACE(":failed-last error (%ld)\n",GetLastError());
270 __CRTDLL__set_errno(GetLastError());
278 /*********************************************************************
279 * _creat (CRTDLL.066)
281 * Open a file, creating it if it is not present.
283 INT __cdecl
CTRDLL__creat(LPCSTR path
, INT flags
)
285 INT usedFlags
= (flags
& _O_TEXT
)| _O_CREAT
| _O_WRONLY
| _O_TRUNC
;
286 return CRTDLL__open(path
, usedFlags
);
290 /*********************************************************************
293 * Determine if the file pointer is at the end of a file.
295 /* FIXME: Care for large files */
296 INT __cdecl
CRTDLL__eof( INT fd
)
299 HANDLE hand
= __CRTDLL__fdtoh(fd
);
301 TRACE(":fd (%d) handle (%d)\n",fd
,hand
);
303 if (hand
== INVALID_HANDLE_VALUE
)
306 /* If we have a FILE* for this file, the EOF flag
307 * will be set by the read()/write() functions.
309 if (__CRTDLL_files
[fd
])
310 return __CRTDLL_files
[fd
]->_flag
& _IOEOF
;
312 /* Otherwise we do it the hard way */
313 curpos
= SetFilePointer( hand
, 0, NULL
, SEEK_CUR
);
314 endpos
= SetFilePointer( hand
, 0, NULL
, FILE_END
);
316 if (curpos
== endpos
)
319 SetFilePointer( hand
, curpos
, 0, FILE_BEGIN
);
324 /*********************************************************************
325 * _fcloseall (CRTDLL.089)
327 * Close all open files except stdin/stdout/stderr.
329 INT __cdecl
CRTDLL__fcloseall(VOID
)
331 int num_closed
= 0, i
= 3;
333 while(i
< __CRTDLL_fdend
)
334 if (__CRTDLL_handles
[i
] != INVALID_HANDLE_VALUE
)
340 TRACE(":closed (%d) handles\n",num_closed
);
345 /*********************************************************************
346 * _fdopen (CRTDLL.091)
348 * Get a FILE* from a low level file descriptor.
350 CRTDLL_FILE
* __cdecl
CRTDLL__fdopen(INT fd
, LPCSTR mode
)
352 CRTDLL_FILE
* file
= __CRTDLL__alloc_fp(fd
);
354 TRACE(":fd (%d) mode (%s) FILE* (%p)\n",fd
,mode
,file
);
362 /*********************************************************************
363 * _fgetchar (CRTDLL.092)
365 INT __cdecl
CRTDLL__fgetchar( VOID
)
367 return CRTDLL_fgetc(CRTDLL_stdin
);
371 /*********************************************************************
372 * _filbuf (CRTDLL.094)
375 * The macro version of getc calls this function whenever FILE->_cnt
376 * becomes negative. We ensure that _cnt is always 0 after any read
377 * so this function is always called. Our implementation simply calls
378 * fgetc as all the underlying buffering is handled by Wines
379 * implementation of the Win32 file I/O calls.
381 INT __cdecl
CRTDLL__filbuf(CRTDLL_FILE
* file
)
383 return CRTDLL_fgetc(file
);
387 /*********************************************************************
388 * _fileno (CRTDLL.097)
390 * Get the file descriptor from a FILE*.
393 * This returns the CRTDLL fd, _not_ the underlying *nix fd.
395 INT __cdecl
CRTDLL__fileno(CRTDLL_FILE
* file
)
397 TRACE(":FILE* (%p) fd (%d)\n",file
,file
->_file
);
402 /*********************************************************************
403 * _flsbuf (CRTDLL.102)
406 * The macro version of putc calls this function whenever FILE->_cnt
407 * becomes negative. We ensure that _cnt is always 0 after any write
408 * so this function is always called. Our implementation simply calls
409 * fputc as all the underlying buffering is handled by Wines
410 * implementation of the Win32 file I/O calls.
412 INT __cdecl
CRTDLL__flsbuf(INT c
, CRTDLL_FILE
* file
)
414 return CRTDLL_fputc(c
,file
);
418 /*********************************************************************
419 * _flushall (CRTDLL.103)
421 * Flush all open files.
423 INT __cdecl
CRTDLL__flushall(VOID
)
425 int num_flushed
= 0, i
= 3;
427 while(i
< __CRTDLL_fdend
)
428 if (__CRTDLL_handles
[i
] != INVALID_HANDLE_VALUE
)
430 if (CRTDLL__commit(i
) == -1)
431 if (__CRTDLL_files
[i
])
432 __CRTDLL_files
[i
]->_flag
|= _IOERR
;
436 TRACE(":flushed (%d) handles\n",num_flushed
);
441 /*********************************************************************
442 * _fputchar (CRTDLL.108)
444 * Put a character to a file.
446 INT __cdecl
CRTDLL__fputchar(INT c
)
448 return CRTDLL_fputc(c
, CRTDLL_stdout
);
452 /*********************************************************************
453 * _fsopen (CRTDLL.110)
455 * Open a FILE* with sharing.
457 CRTDLL_FILE
* __cdecl
CRTDLL__fsopen(LPCSTR path
, LPCSTR mode
, INT share
)
459 FIXME(":(%s,%s,%d),ignoring share mode!\n",path
,mode
,share
);
460 return CRTDLL_fopen(path
,mode
);
464 /*********************************************************************
465 * _fstat (CRTDLL.111)
467 * Get information about an open file.
469 int __cdecl
CRTDLL__fstat(int fd
, struct _stat
* buf
)
472 BY_HANDLE_FILE_INFORMATION hfi
;
473 HANDLE hand
= __CRTDLL__fdtoh(fd
);
475 TRACE(":fd (%d) stat (%p)\n",fd
,buf
);
476 if (hand
== INVALID_HANDLE_VALUE
)
481 WARN(":failed-NULL buf\n");
482 __CRTDLL__set_errno(ERROR_INVALID_PARAMETER
);
486 memset(&hfi
, 0, sizeof(hfi
));
487 memset(buf
, 0, sizeof(struct _stat
));
488 if (!GetFileInformationByHandle(hand
, &hfi
))
490 WARN(":failed-last error (%ld)\n",GetLastError());
491 __CRTDLL__set_errno(ERROR_INVALID_PARAMETER
);
494 FIXME(":dwFileAttributes = %d, mode set to 0",hfi
.dwFileAttributes
);
495 buf
->st_nlink
= hfi
.nNumberOfLinks
;
496 buf
->st_size
= hfi
.nFileSizeLow
;
497 RtlTimeToSecondsSince1970( &hfi
.ftLastAccessTime
, &dw
);
499 RtlTimeToSecondsSince1970( &hfi
.ftLastWriteTime
, &dw
);
500 buf
->st_mtime
= buf
->st_ctime
= dw
;
505 /*********************************************************************
506 * _futime (CRTDLL.115)
508 * Set the file access/modification times on an open file.
510 INT __cdecl
CRTDLL__futime(INT fd
, struct _utimbuf
*t
)
512 HANDLE hand
= __CRTDLL__fdtoh(fd
);
518 CRTDLL_time(&currTime
);
519 RtlSecondsSince1970ToTime( currTime
, &at
);
520 memcpy( &wt
, &at
, sizeof(wt
) );
524 RtlSecondsSince1970ToTime( t
->actime
, &at
);
525 if (t
->actime
== t
->modtime
)
526 memcpy( &wt
, &at
, sizeof(wt
) );
528 RtlSecondsSince1970ToTime( t
->modtime
, &wt
);
531 if (!SetFileTime( hand
, NULL
, &at
, &wt
))
533 __CRTDLL__set_errno(GetLastError());
540 /*********************************************************************
541 * _get_osfhandle (CRTDLL.117)
543 * Return a Win32 HANDLE from a file descriptor.
546 * fd [in] A valid file descriptor
549 * Success: A Win32 HANDLE
551 * Failure: INVALID_HANDLE_VALUE.
554 HANDLE
CRTDLL__get_osfhandle(INT fd
)
556 HANDLE hand
= __CRTDLL__fdtoh(fd
);
557 HANDLE newhand
= hand
;
558 TRACE(":fd (%d) handle (%d)\n",fd
,hand
);
560 if (hand
!= INVALID_HANDLE_VALUE
)
562 /* FIXME: I'm not convinced that I should be copying the
563 * handle here - it may be leaked if the app doesn't
564 * close it (and the API docs dont say that it should)
565 * Not duplicating it means that it can't be inherited
566 * and so lcc's wedit doesn't cope when it passes it to
567 * child processes. I've an idea that it should either
568 * be copied by CreateProcess, or marked as inheritable
569 * when initialised, or maybe both? JG 21-9-00.
571 DuplicateHandle(GetCurrentProcess(),hand
,GetCurrentProcess(),
572 &newhand
,0,TRUE
,DUPLICATE_SAME_ACCESS
);
578 /*********************************************************************
579 * _isatty (CRTDLL.137)
581 * Return non zero if fd is a character device (e.g console).
583 INT __cdecl
CRTDLL__isatty(INT fd
)
585 HANDLE hand
= __CRTDLL__fdtoh(fd
);
587 TRACE(":fd (%d) handle (%d)\n",fd
,hand
);
588 if (hand
== INVALID_HANDLE_VALUE
)
591 return GetFileType(fd
) == FILE_TYPE_CHAR
? 1 : 0;
595 /*********************************************************************
596 * _lseek (CRTDLL.179)
598 * Move the file pointer within a file.
600 LONG __cdecl
CRTDLL__lseek( INT fd
, LONG offset
, INT whence
)
603 HANDLE hand
= __CRTDLL__fdtoh(fd
);
605 TRACE(":fd (%d) handle (%d)\n",fd
,hand
);
606 if (hand
== INVALID_HANDLE_VALUE
)
609 if (whence
< 0 || whence
> 2)
611 CRTDLL_errno
= EINVAL
;
615 TRACE(":fd (%d) to 0x%08lx pos %s\n",
616 fd
,offset
,(whence
==SEEK_SET
)?"SEEK_SET":
617 (whence
==SEEK_CUR
)?"SEEK_CUR":
618 (whence
==SEEK_END
)?"SEEK_END":"UNKNOWN");
620 if ((ret
= SetFilePointer( hand
, offset
, NULL
, whence
)) != 0xffffffff)
622 if ( __CRTDLL_files
[fd
])
623 __CRTDLL_files
[fd
]->_flag
&= ~_IOEOF
;
624 /* FIXME: What if we seek _to_ EOF - is EOF set? */
627 TRACE(":error-last error (%ld)\n",GetLastError());
628 if ( __CRTDLL_files
[fd
])
629 switch(GetLastError())
631 case ERROR_NEGATIVE_SEEK
:
632 case ERROR_SEEK_ON_DEVICE
:
633 __CRTDLL__set_errno(GetLastError());
634 __CRTDLL_files
[fd
]->_flag
|= _IOERR
;
643 /*********************************************************************
647 INT __cdecl
CRTDLL__open(LPCSTR path
,INT flags
)
649 DWORD access
= 0, creation
= 0;
653 TRACE(":file (%s) mode 0x%04x\n",path
,flags
);
655 switch(flags
& (_O_RDONLY
| _O_WRONLY
| _O_RDWR
))
658 access
|= GENERIC_READ
;
662 access
|= GENERIC_WRITE
;
666 access
|= GENERIC_WRITE
| GENERIC_READ
;
671 if (flags
& _O_CREAT
)
674 creation
= CREATE_NEW
;
675 else if (flags
& _O_TRUNC
)
676 creation
= CREATE_ALWAYS
;
678 creation
= OPEN_ALWAYS
;
680 else /* no _O_CREAT */
682 if (flags
& _O_TRUNC
)
683 creation
= TRUNCATE_EXISTING
;
685 creation
= OPEN_EXISTING
;
687 if (flags
& _O_APPEND
)
691 flags
|= _O_BINARY
; /* FIXME: Default to text */
695 /* Dont warn when writing */
696 if (ioflag
& GENERIC_READ
)
697 FIXME(":TEXT node not implemented\n");
701 if (flags
& ~(_O_BINARY
|_O_TEXT
|_O_APPEND
|_O_TRUNC
|_O_EXCL
|_O_CREAT
|_O_RDWR
))
702 TRACE(":unsupported flags 0x%04x\n",flags
);
704 /* clear those pesky flags ;-) */
705 flags
&= (_O_BINARY
|_O_TEXT
|_O_APPEND
|_O_TRUNC
|_O_EXCL
|_O_CREAT
|_O_RDWR
);
707 hand
= CreateFileA( path
, access
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
708 NULL
, creation
, FILE_ATTRIBUTE_NORMAL
, -1);
710 if (hand
== INVALID_HANDLE_VALUE
)
712 WARN(":failed-last error (%ld)\n",GetLastError());
713 __CRTDLL__set_errno(GetLastError());
717 fd
= __CRTDLL__alloc_fd(hand
,ioflag
);
719 TRACE(":fd (%d) handle (%d)\n",fd
, hand
);
721 if (flags
& _IOAPPEND
&& fd
> 0)
722 CRTDLL__lseek(fd
, 0, FILE_END
);
728 /*********************************************************************
729 * _open_osfhandle (CRTDLL.240)
731 * Create a file descriptor for a file HANDLE.
733 INT __cdecl
CRTDLL__open_osfhandle(HANDLE hand
, INT flags
)
735 INT fd
= __CRTDLL__alloc_fd(hand
,flags
);
736 TRACE(":handle (%d) fd (%d)\n",hand
,fd
);
741 /*********************************************************************
744 * Read data from a file.
746 INT __cdecl
CRTDLL__read(INT fd
, LPVOID buf
, UINT count
)
749 HANDLE hand
= __CRTDLL__fdtoh(fd
);
751 /* Dont trace small reads, it gets *very* annoying */
753 TRACE(":fd (%d) handle (%d) buf (%p) len (%d)\n",fd
,hand
,buf
,count
);
754 if (hand
== INVALID_HANDLE_VALUE
)
757 /* Set _cnt to 0 so optimised binaries will call our implementation
758 * of putc/getc. See _filbuf/_flsbuf comments.
760 if (__CRTDLL_files
[fd
])
761 __CRTDLL_files
[fd
]->_cnt
= 0;
763 if (ReadFile(hand
, buf
, count
, &num_read
, NULL
))
765 if (num_read
!= count
&& __CRTDLL_files
[fd
])
768 __CRTDLL_files
[fd
]->_flag
|= _IOEOF
;
772 TRACE(":failed-last error (%ld)\n",GetLastError());
773 if ( __CRTDLL_files
[fd
])
774 __CRTDLL_files
[fd
]->_flag
|= _IOERR
;
779 /*********************************************************************
780 * _setmode (CRTDLL.265)
782 * FIXME: At present we ignore the request to translate CR/LF to LF.
784 * We always translate when we read with fgets, we never do with fread
787 INT __cdecl
CRTDLL__setmode(INT fd
,INT mode
)
790 FIXME("fd (%d) mode (%d) TEXT not implemented\n",fd
,mode
);
795 /*********************************************************************
798 INT __cdecl
CRTDLL__stat(const char* path
, struct _stat
* buf
)
801 WIN32_FILE_ATTRIBUTE_DATA hfi
;
802 unsigned short mode
= CRTDLL_S_IREAD
;
805 TRACE(":file (%s) buf(%p)\n",path
,buf
);
807 if (!GetFileAttributesExA( path
, GetFileExInfoStandard
, &hfi
))
809 TRACE("failed-last error (%ld)\n",GetLastError());
810 __CRTDLL__set_errno(ERROR_FILE_NOT_FOUND
);
814 memset(buf
,0,sizeof(struct _stat
));
816 /* FIXME: rdev isnt drive num,despite what the docs say-what is it? */
818 buf
->st_dev
= buf
->st_rdev
= toupper(*path
- 'A'); /* drive num */
820 buf
->st_dev
= buf
->st_rdev
= CRTDLL__getdrive() - 1;
824 /* Dir, or regular file? */
825 if ((hfi
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) ||
826 (path
[plen
-1] == '\\'))
827 mode
|= (_S_IFDIR
| CRTDLL_S_IEXEC
);
832 if (plen
> 6 && path
[plen
-4] == '.') /* shortest exe: "\x.exe" */
834 unsigned int ext
= tolower(path
[plen
-1]) | (tolower(path
[plen
-2]) << 8)
835 | (tolower(path
[plen
-3]) << 16);
836 if (ext
== EXE
|| ext
== BAT
|| ext
== CMD
|| ext
== COM
)
837 mode
|= CRTDLL_S_IEXEC
;
841 if (!(hfi
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
))
842 mode
|= CRTDLL_S_IWRITE
;
846 buf
->st_size
= hfi
.nFileSizeLow
;
847 RtlTimeToSecondsSince1970( &hfi
.ftLastAccessTime
, &dw
);
849 RtlTimeToSecondsSince1970( &hfi
.ftLastWriteTime
, &dw
);
850 buf
->st_mtime
= buf
->st_ctime
= dw
;
851 TRACE("\n%d %d %d %d %d %d\n", buf
->st_mode
,buf
->st_nlink
,buf
->st_size
,
852 buf
->st_atime
,buf
->st_mtime
, buf
->st_ctime
);
857 /*********************************************************************
860 * Get current file position.
862 LONG __cdecl
CRTDLL__tell(INT fd
)
864 return CRTDLL__lseek(fd
, 0, SEEK_CUR
);
868 /*********************************************************************
869 * _tempnam (CRTDLL.305)
872 LPSTR __cdecl
CRTDLL__tempnam(LPCSTR dir
, LPCSTR prefix
)
874 char tmpbuf
[MAX_PATH
];
876 TRACE("dir (%s) prefix (%s)\n",dir
,prefix
);
877 if (GetTempFileNameA(dir
,prefix
,0,tmpbuf
))
879 TRACE("got name (%s)\n",tmpbuf
);
880 return CRTDLL__strdup(tmpbuf
);
882 TRACE("failed-last error (%ld)\n",GetLastError());
887 /*********************************************************************
888 * _umask (CRTDLL.310)
890 * Set the process-wide umask.
892 INT __cdecl
CRTDLL__umask(INT umask
)
894 INT old_umask
= __CRTDLL_umask
;
895 TRACE("umask (%d)\n",umask
);
896 __CRTDLL_umask
= umask
;
901 /*********************************************************************
902 * _utime (CRTDLL.314)
904 * Set the file access/modification times on a file.
906 INT __cdecl
CRTDLL__utime(LPCSTR path
, struct _utimbuf
*t
)
908 INT fd
= CRTDLL__open( path
, _O_WRONLY
| _O_BINARY
);
912 INT retVal
= CRTDLL__futime(fd
, t
);
920 /*********************************************************************
921 * _unlink (CRTDLL.315)
925 INT __cdecl
CRTDLL__unlink(LPCSTR path
)
927 TRACE("path (%s)\n",path
);
928 if(DeleteFileA( path
))
931 TRACE("failed-last error (%ld)\n",GetLastError());
932 __CRTDLL__set_errno(GetLastError());
937 /*********************************************************************
938 * _write (CRTDLL.332)
940 * Write data to a file.
942 UINT __cdecl
CRTDLL__write(INT fd
, LPCVOID buf
, UINT count
)
945 HANDLE hand
= __CRTDLL__fdtoh(fd
);
947 /* Dont trace small writes, it gets *very* annoying */
949 TRACE(":fd (%d) handle (%d) buf (%p) len (%d)\n",fd
,hand
,buf
,count
);
950 if (hand
== INVALID_HANDLE_VALUE
)
953 /* If appending, go to EOF */
954 if (__CRTDLL_flags
[fd
] & _IOAPPEND
)
955 CRTDLL__lseek(fd
, 0, FILE_END
);
957 /* Set _cnt to 0 so optimised binaries will call our implementation
958 * of putc/getc. See _filbuf/_flsbuf comments.
960 if (__CRTDLL_files
[fd
])
961 __CRTDLL_files
[fd
]->_cnt
= 0;
963 if (WriteFile(hand
, buf
, count
, &num_written
, NULL
)
964 && (num_written
== count
))
967 TRACE(":failed-last error (%ld)\n",GetLastError());
968 if ( __CRTDLL_files
[fd
])
969 __CRTDLL_files
[fd
]->_flag
|= _IOERR
;
975 /*********************************************************************
976 * clearerr (CRTDLL.349)
978 * Clear a FILE's error indicator.
980 VOID __cdecl
CRTDLL_clearerr(CRTDLL_FILE
* file
)
982 TRACE(":file (%p) fd (%d)\n",file
,file
->_file
);
983 file
->_flag
&= ~(_IOERR
| _IOEOF
);
987 /*********************************************************************
988 * fclose (CRTDLL.362)
990 * Close an open file.
992 INT __cdecl
CRTDLL_fclose( CRTDLL_FILE
* file
)
994 return CRTDLL__close(file
->_file
);
998 /*********************************************************************
1001 * Check the eof indicator on a file.
1003 INT __cdecl
CRTDLL_feof( CRTDLL_FILE
* file
)
1005 return file
->_flag
& _IOEOF
;
1009 /*********************************************************************
1010 * ferror (CRTDLL.361)
1012 * Check the error indicator on a file.
1014 INT __cdecl
CRTDLL_ferror( CRTDLL_FILE
* file
)
1016 return file
->_flag
& _IOERR
;
1020 /*********************************************************************
1021 * fflush (CRTDLL.362)
1023 INT __cdecl
CRTDLL_fflush( CRTDLL_FILE
* file
)
1025 return CRTDLL__commit(file
->_file
);
1029 /*********************************************************************
1030 * fgetc (CRTDLL.363)
1032 INT __cdecl
CRTDLL_fgetc( CRTDLL_FILE
* file
)
1035 if (CRTDLL__read(file
->_file
,&c
,1) != 1)
1041 /*********************************************************************
1042 * fgetpos (CRTDLL.364)
1044 INT __cdecl
CRTDLL_fgetpos( CRTDLL_FILE
* file
, fpos_t *pos
)
1046 *pos
= CRTDLL__tell(file
->_file
);
1047 return (*pos
== -1? -1 : 0);
1051 /*********************************************************************
1052 * fgets (CRTDLL.365)
1054 CHAR
* __cdecl
CRTDLL_fgets(LPSTR s
, INT size
, CRTDLL_FILE
* file
)
1057 LPSTR buf_start
= s
;
1059 TRACE(":file(%p) fd (%d) str (%p) len (%d)\n",
1060 file
,file
->_file
,s
,size
);
1062 /* BAD, for the whole WINE process blocks... just done this way to test
1063 * windows95's ftp.exe.
1064 * JG - Is this true now we use ReadFile() on stdin too?
1066 for(cc
= CRTDLL_fgetc(file
); cc
!= EOF
&& cc
!= '\n';
1067 cc
= CRTDLL_fgetc(file
))
1070 if (--size
<= 0) break;
1073 if ((cc
== EOF
) && (s
== buf_start
)) /* If nothing read, return 0*/
1075 TRACE(":nothing read\n");
1082 TRACE(":got '%s'\n", buf_start
);
1087 /*********************************************************************
1088 * fputs (CRTDLL.375)
1090 INT __cdecl
CRTDLL_fputs( LPCSTR s
, CRTDLL_FILE
* file
)
1092 return CRTDLL_fwrite(s
,strlen(s
),1,file
);
1096 /*********************************************************************
1097 * fprintf (CRTDLL.370)
1099 INT __cdecl
CRTDLL_fprintf( CRTDLL_FILE
* file
, LPCSTR format
, ... )
1104 va_start( valist
, format
);
1105 res
= CRTDLL_vfprintf( file
, format
, valist
);
1111 /*********************************************************************
1112 * fopen (CRTDLL.372)
1116 CRTDLL_FILE
* __cdecl
CRTDLL_fopen(LPCSTR path
, LPCSTR mode
)
1119 INT flags
= 0, plus
= 0, fd
;
1120 const char* search
= mode
;
1122 TRACE(":path (%s) mode (%s)\n",path
,mode
);
1125 if (*search
++ == '+')
1128 /* map mode string to open() flags. "man fopen" for possibilities. */
1132 flags
= (plus
? _O_RDWR
: _O_RDONLY
);
1135 flags
= _O_CREAT
| _O_TRUNC
| (plus
? _O_RDWR
: _O_WRONLY
);
1138 flags
= _O_CREAT
| _O_APPEND
| (plus
? _O_RDWR
: _O_WRONLY
);
1153 flags
&= ~_O_BINARY
;
1158 FIXME(":unknown flag %c not supported\n",mode
[-1]);
1161 fd
= CRTDLL__open(path
, flags
);
1166 file
= __CRTDLL__alloc_fp(fd
);
1167 TRACE(":get file (%p)\n",file
);
1175 /*********************************************************************
1176 * fputc (CRTDLL.374)
1178 INT __cdecl
CRTDLL_fputc( INT c
, CRTDLL_FILE
* file
)
1180 return CRTDLL__write(file
->_file
, &c
, 1) == 1? c
: EOF
;
1184 /*********************************************************************
1185 * fread (CRTDLL.377)
1187 DWORD __cdecl
CRTDLL_fread(LPVOID ptr
, INT size
, INT nmemb
, CRTDLL_FILE
* file
)
1189 DWORD read
= CRTDLL__read(file
->_file
,ptr
, size
* nmemb
);
1196 /*********************************************************************
1197 * freopen (CRTDLL.379)
1200 CRTDLL_FILE
* __cdecl
CRTDLL_freopen(LPCSTR path
, LPCSTR mode
,CRTDLL_FILE
* file
)
1202 CRTDLL_FILE
* newfile
;
1205 TRACE(":path (%p) mode (%s) file (%p) fd (%d)\n",path
,mode
,file
,file
->_file
);
1206 if (!file
|| ((fd
= file
->_file
) < 0) || fd
> __CRTDLL_fdend
)
1211 FIXME(":reopen on user file not implemented!\n");
1212 __CRTDLL__set_errno(ERROR_CALL_NOT_IMPLEMENTED
);
1216 /* first, create the new file */
1217 if ((newfile
= CRTDLL_fopen(path
,mode
)) == NULL
)
1220 if (fd
< 3 && SetStdHandle(fd
== 0 ? STD_INPUT_HANDLE
:
1221 (fd
== 1? STD_OUTPUT_HANDLE
: STD_ERROR_HANDLE
),
1222 __CRTDLL_handles
[newfile
->_file
]))
1224 /* Redirecting std handle to file , copy over.. */
1225 __CRTDLL_handles
[fd
] = __CRTDLL_handles
[newfile
->_file
];
1226 __CRTDLL_flags
[fd
] = __CRTDLL_flags
[newfile
->_file
];
1227 memcpy(&__CRTDLL_iob
[fd
], newfile
, sizeof (CRTDLL_FILE
));
1228 __CRTDLL_iob
[fd
]._file
= fd
;
1229 /* And free up the resources allocated by fopen, but
1230 * not the HANDLE we copied. */
1231 CRTDLL_free(__CRTDLL_files
[fd
]);
1232 __CRTDLL__free_fd(newfile
->_file
);
1233 return &__CRTDLL_iob
[fd
];
1236 WARN(":failed-last error (%ld)\n",GetLastError());
1237 CRTDLL_fclose(newfile
);
1238 __CRTDLL__set_errno(GetLastError());
1243 /*********************************************************************
1244 * fsetpos (CRTDLL.380)
1246 INT __cdecl
CRTDLL_fsetpos( CRTDLL_FILE
* file
, fpos_t *pos
)
1248 return CRTDLL__lseek(file
->_file
,*pos
,SEEK_SET
);
1252 /*********************************************************************
1253 * fscanf (CRTDLL.381)
1255 INT __cdecl
CRTDLL_fscanf( CRTDLL_FILE
* file
, LPSTR format
, ... )
1260 if (!*format
) return 0;
1261 WARN("%p (\"%s\"): semi-stub\n", file
, format
);
1262 nch
= CRTDLL_fgetc(file
);
1263 va_start(ap
, format
);
1265 if (*format
== ' ') {
1266 /* skip whitespace */
1267 while ((nch
!=EOF
) && isspace(nch
))
1268 nch
= CRTDLL_fgetc(file
);
1270 else if (*format
== '%') {
1274 case 'd': { /* read an integer */
1275 int*val
= va_arg(ap
, int*);
1277 /* skip initial whitespace */
1278 while ((nch
!=EOF
) && isspace(nch
))
1279 nch
= CRTDLL_fgetc(file
);
1280 /* get sign and first digit */
1282 nch
= CRTDLL_fgetc(file
);
1291 nch
= CRTDLL_fgetc(file
);
1292 /* read until no more digits */
1293 while ((nch
!=EOF
) && isdigit(nch
)) {
1294 cur
= cur
*10 + (nch
- '0');
1295 nch
= CRTDLL_fgetc(file
);
1301 case 'f': { /* read a float */
1302 float*val
= va_arg(ap
, float*);
1304 /* skip initial whitespace */
1305 while ((nch
!=EOF
) && isspace(nch
))
1306 nch
= CRTDLL_fgetc(file
);
1307 /* get sign and first digit */
1309 nch
= CRTDLL_fgetc(file
);
1318 /* read until no more digits */
1319 while ((nch
!=EOF
) && isdigit(nch
)) {
1320 cur
= cur
*10 + (nch
- '0');
1321 nch
= CRTDLL_fgetc(file
);
1324 /* handle decimals */
1326 nch
= CRTDLL_fgetc(file
);
1327 while ((nch
!=EOF
) && isdigit(nch
)) {
1329 cur
+= dec
* (nch
- '0');
1330 nch
= CRTDLL_fgetc(file
);
1337 case 's': { /* read a word */
1338 char*str
= va_arg(ap
, char*);
1340 /* skip initial whitespace */
1341 while ((nch
!=EOF
) && isspace(nch
))
1342 nch
= CRTDLL_fgetc(file
);
1343 /* read until whitespace */
1344 while ((nch
!=EOF
) && !isspace(nch
)) {
1345 *sptr
++ = nch
; st
++;
1346 nch
= CRTDLL_fgetc(file
);
1350 TRACE("read word: %s\n", str
);
1353 default: FIXME("unhandled: %%%c\n", *format
);
1359 /* check for character match */
1361 nch
= CRTDLL_fgetc(file
);
1368 WARN("need ungetch\n");
1370 TRACE("returning %d\n", rd
);
1375 /*********************************************************************
1376 * fseek (CRTDLL.382)
1378 LONG __cdecl
CRTDLL_fseek( CRTDLL_FILE
* file
, LONG offset
, INT whence
)
1380 return CRTDLL__lseek(file
->_file
,offset
,whence
);
1384 /*********************************************************************
1385 * ftell (CRTDLL.381)
1387 LONG __cdecl
CRTDLL_ftell( CRTDLL_FILE
* file
)
1389 return CRTDLL__tell(file
->_file
);
1393 /*********************************************************************
1394 * fwrite (CRTDLL.383)
1396 UINT __cdecl
CRTDLL_fwrite( LPCVOID ptr
, INT size
, INT nmemb
, CRTDLL_FILE
* file
)
1398 UINT written
= CRTDLL__write(file
->_file
, ptr
, size
* nmemb
);
1401 return written
/ size
;
1405 /*********************************************************************
1406 * getchar (CRTDLL.386)
1408 INT __cdecl
CRTDLL_getchar( VOID
)
1410 return CRTDLL_fgetc(CRTDLL_stdin
);
1414 /*********************************************************************
1417 INT __cdecl
CRTDLL_getc( CRTDLL_FILE
* file
)
1419 return CRTDLL_fgetc( file
);
1423 /*********************************************************************
1426 LPSTR __cdecl
CRTDLL_gets(LPSTR buf
)
1429 LPSTR buf_start
= buf
;
1431 /* BAD, for the whole WINE process blocks... just done this way to test
1432 * windows95's ftp.exe.
1433 * JG 19/9/00: Is this still true, now we are using ReadFile?
1435 for(cc
= CRTDLL_fgetc(CRTDLL_stdin
); cc
!= EOF
&& cc
!= '\n';
1436 cc
= CRTDLL_fgetc(CRTDLL_stdin
))
1437 if(cc
!= '\r') *buf
++ = (char)cc
;
1441 TRACE("got '%s'\n", buf_start
);
1446 /*********************************************************************
1449 INT __cdecl
CRTDLL_putc( INT c
, CRTDLL_FILE
* file
)
1451 return CRTDLL_fputc( c
, file
);
1455 /*********************************************************************
1456 * putchar (CRTDLL.442)
1458 void __cdecl
CRTDLL_putchar( INT c
)
1460 CRTDLL_fputc(c
, CRTDLL_stdout
);
1464 /*********************************************************************
1467 INT __cdecl
CRTDLL_puts(LPCSTR s
)
1469 return CRTDLL_fputs(s
, CRTDLL_stdout
);
1473 /*********************************************************************
1474 * rewind (CRTDLL.447)
1476 * Set the file pointer to the start of a file and clear any error
1479 VOID __cdecl
CRTDLL_rewind(CRTDLL_FILE
* file
)
1481 TRACE(":file (%p) fd (%d)\n",file
,file
->_file
);
1482 CRTDLL__lseek(file
->_file
,0,SEEK_SET
);
1483 file
->_flag
&= ~(_IOEOF
| _IOERR
);
1487 /*********************************************************************
1488 * remove (CRTDLL.448)
1490 INT __cdecl
CRTDLL_remove(LPCSTR path
)
1492 TRACE(":path (%s)\n",path
);
1493 if (DeleteFileA(path
))
1495 TRACE(":failed-last error (%ld)\n",GetLastError());
1496 __CRTDLL__set_errno(GetLastError());
1501 /*********************************************************************
1502 * rename (CRTDLL.449)
1504 INT __cdecl
CRTDLL_rename(LPCSTR oldpath
,LPCSTR newpath
)
1506 TRACE(":from %s to %s\n",oldpath
,newpath
);
1507 if (MoveFileExA( oldpath
, newpath
, MOVEFILE_REPLACE_EXISTING
))
1509 TRACE(":failed-last error (%ld)\n",GetLastError());
1510 __CRTDLL__set_errno(GetLastError());
1515 /*********************************************************************
1516 * setbuf (CRTDLL.452)
1518 INT __cdecl
CRTDLL_setbuf(CRTDLL_FILE
* file
, LPSTR buf
)
1520 TRACE(":file (%p) fd (%d) buf (%p)\n", file
, file
->_file
,buf
);
1522 WARN(":user buffer will not be used!\n");
1523 /* FIXME: no buffering for now */
1528 /*********************************************************************
1529 * tmpnam (CRTDLL.490)
1531 * lcclnk from lcc-win32 relies on a terminating dot in the name returned
1534 LPSTR __cdecl
CRTDLL_tmpnam(LPSTR s
)
1536 char tmpbuf
[MAX_PATH
];
1537 char* prefix
= "TMP";
1538 if (!GetTempPathA(MAX_PATH
,tmpbuf
) ||
1539 !GetTempFileNameA(tmpbuf
,prefix
,0,CRTDLL_tmpname
))
1541 TRACE(":failed-last error (%ld)\n",GetLastError());
1544 TRACE(":got tmpnam %s\n",CRTDLL_tmpname
);
1545 return CRTDLL_tmpname
;
1549 /*********************************************************************
1550 * vfprintf (CRTDLL.494)
1552 * Write formatted output to a file.
1554 /* we have avoided libc stdio.h so far, lets not start now */
1555 extern int vsprintf(void *, const void *, va_list);
1557 INT __cdecl
CRTDLL_vfprintf( CRTDLL_FILE
* file
, LPCSTR format
, va_list args
)
1559 /* FIXME: We should parse the format string, calculate the maximum,
1560 * length of each arg, malloc a buffer, print to it, and fwrite that.
1561 * Yes this sucks, but not as much as crashing 1/2 way through an
1562 * app writing to a file :-(
1565 TRACE(":file (%p) fd (%d) fmt (%s)\n",file
,file
->_file
,format
);
1567 vsprintf( buffer
, format
, args
);
1568 return CRTDLL_fwrite( buffer
, 1, strlen(buffer
), file
);