2 * File handling functions
4 * Copyright 1993 John Burton
5 * Copyright 1996, 2004 Alexandre Julliard
6 * Copyright 2008 Jeff Zaroyko
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "wine/port.h"
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
33 #define NONAMELESSUNION
34 #define NONAMELESSSTRUCT
37 #define WIN32_NO_STATUS
43 #include "ddk/ntddk.h"
44 #include "kernel_private.h"
48 #include "wine/exception.h"
49 #include "wine/unicode.h"
50 #include "wine/debug.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(file
);
54 static const WCHAR krnl386W
[] = {'k','r','n','l','3','8','6','.','e','x','e','1','6',0};
56 /***********************************************************************
59 * Wrapper for CreateFile that takes OF_* mode flags.
61 static HANDLE
create_file_OF( LPCSTR path
, INT mode
)
63 DWORD access
, sharing
, creation
;
67 creation
= CREATE_ALWAYS
;
68 access
= GENERIC_READ
| GENERIC_WRITE
;
72 creation
= OPEN_EXISTING
;
75 case OF_READ
: access
= GENERIC_READ
; break;
76 case OF_WRITE
: access
= GENERIC_WRITE
; break;
77 case OF_READWRITE
: access
= GENERIC_READ
| GENERIC_WRITE
; break;
78 default: access
= 0; break;
84 case OF_SHARE_EXCLUSIVE
: sharing
= 0; break;
85 case OF_SHARE_DENY_WRITE
: sharing
= FILE_SHARE_READ
; break;
86 case OF_SHARE_DENY_READ
: sharing
= FILE_SHARE_WRITE
; break;
87 case OF_SHARE_DENY_NONE
:
89 default: sharing
= FILE_SHARE_READ
| FILE_SHARE_WRITE
; break;
91 return CreateFileA( path
, access
, sharing
, NULL
, creation
, FILE_ATTRIBUTE_NORMAL
, 0 );
95 /***********************************************************************
98 * Set the DOS error code from errno.
100 void FILE_SetDosError(void)
102 int save_errno
= errno
; /* errno gets overwritten by printf */
104 TRACE("errno = %d %s\n", errno
, strerror(errno
));
108 SetLastError( ERROR_SHARING_VIOLATION
);
111 SetLastError( ERROR_INVALID_HANDLE
);
114 SetLastError( ERROR_HANDLE_DISK_FULL
);
119 SetLastError( ERROR_ACCESS_DENIED
);
122 SetLastError( ERROR_LOCK_VIOLATION
);
125 SetLastError( ERROR_FILE_NOT_FOUND
);
128 SetLastError( ERROR_CANNOT_MAKE
);
132 SetLastError( ERROR_TOO_MANY_OPEN_FILES
);
135 SetLastError( ERROR_FILE_EXISTS
);
139 SetLastError( ERROR_SEEK
);
142 SetLastError( ERROR_DIR_NOT_EMPTY
);
145 SetLastError( ERROR_BAD_FORMAT
);
148 SetLastError( ERROR_PATH_NOT_FOUND
);
151 SetLastError( ERROR_NOT_SAME_DEVICE
);
154 WARN("unknown file error: %s\n", strerror(save_errno
) );
155 SetLastError( ERROR_GEN_FAILURE
);
162 /***********************************************************************
165 * Convert a file name to Unicode, taking into account the OEM/Ansi API mode.
167 * If alloc is FALSE uses the TEB static buffer, so it can only be used when
168 * there is no possibility for the function to do that twice, taking into
169 * account any called function.
171 WCHAR
*FILE_name_AtoW( LPCSTR name
, BOOL alloc
)
174 UNICODE_STRING strW
, *pstrW
;
177 RtlInitAnsiString( &str
, name
);
178 pstrW
= alloc
? &strW
: &NtCurrentTeb()->StaticUnicodeString
;
179 if (!AreFileApisANSI())
180 status
= RtlOemStringToUnicodeString( pstrW
, &str
, alloc
);
182 status
= RtlAnsiStringToUnicodeString( pstrW
, &str
, alloc
);
183 if (status
== STATUS_SUCCESS
) return pstrW
->Buffer
;
185 if (status
== STATUS_BUFFER_OVERFLOW
)
186 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
188 SetLastError( RtlNtStatusToDosError(status
) );
193 /***********************************************************************
196 * Convert a file name back to OEM/Ansi. Returns number of bytes copied.
198 DWORD
FILE_name_WtoA( LPCWSTR src
, INT srclen
, LPSTR dest
, INT destlen
)
202 if (srclen
< 0) srclen
= strlenW( src
) + 1;
205 if (!AreFileApisANSI())
208 strW
.Buffer
= (WCHAR
*)src
;
209 strW
.Length
= srclen
* sizeof(WCHAR
);
210 ret
= RtlUnicodeStringToOemSize( &strW
) - 1;
213 RtlUnicodeToMultiByteSize( &ret
, src
, srclen
* sizeof(WCHAR
) );
217 if (!AreFileApisANSI())
218 RtlUnicodeToOemN( dest
, destlen
, &ret
, src
, srclen
* sizeof(WCHAR
) );
220 RtlUnicodeToMultiByteN( dest
, destlen
, &ret
, src
, srclen
* sizeof(WCHAR
) );
226 /***********************************************************************
227 * _hread (KERNEL32.@)
229 LONG WINAPI
_hread( HFILE hFile
, LPVOID buffer
, LONG count
)
231 return _lread( hFile
, buffer
, count
);
235 /***********************************************************************
236 * _hwrite (KERNEL32.@)
238 * experimentation yields that _lwrite:
239 * o truncates the file at the current position with
241 * o returns 0 on a 0 length write
242 * o works with console handles
245 LONG WINAPI
_hwrite( HFILE handle
, LPCSTR buffer
, LONG count
)
249 TRACE("%d %p %d\n", handle
, buffer
, count
);
253 /* Expand or truncate at current position */
254 if (!SetEndOfFile( LongToHandle(handle
) )) return HFILE_ERROR
;
257 if (!WriteFile( LongToHandle(handle
), buffer
, count
, &result
, NULL
))
263 /***********************************************************************
264 * _lclose (KERNEL32.@)
266 HFILE WINAPI
_lclose( HFILE hFile
)
268 TRACE("handle %d\n", hFile
);
269 return CloseHandle( LongToHandle(hFile
) ) ? 0 : HFILE_ERROR
;
273 /***********************************************************************
274 * _lcreat (KERNEL32.@)
276 HFILE WINAPI
_lcreat( LPCSTR path
, INT attr
)
280 /* Mask off all flags not explicitly allowed by the doc */
281 attr
&= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_SYSTEM
;
282 TRACE("%s %02x\n", path
, attr
);
283 hfile
= CreateFileA( path
, GENERIC_READ
| GENERIC_WRITE
,
284 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
285 CREATE_ALWAYS
, attr
, 0 );
286 return HandleToLong(hfile
);
290 /***********************************************************************
291 * _lopen (KERNEL32.@)
293 HFILE WINAPI
_lopen( LPCSTR path
, INT mode
)
297 TRACE("(%s,%04x)\n", debugstr_a(path
), mode
);
298 hfile
= create_file_OF( path
, mode
& ~OF_CREATE
);
299 return HandleToLong(hfile
);
302 /***********************************************************************
303 * _lread (KERNEL32.@)
305 UINT WINAPI
_lread( HFILE handle
, LPVOID buffer
, UINT count
)
308 if (!ReadFile( LongToHandle(handle
), buffer
, count
, &result
, NULL
))
314 /***********************************************************************
315 * _llseek (KERNEL32.@)
317 LONG WINAPI
_llseek( HFILE hFile
, LONG lOffset
, INT nOrigin
)
319 return SetFilePointer( LongToHandle(hFile
), lOffset
, NULL
, nOrigin
);
323 /***********************************************************************
324 * _lwrite (KERNEL32.@)
326 UINT WINAPI
_lwrite( HFILE hFile
, LPCSTR buffer
, UINT count
)
328 return (UINT
)_hwrite( hFile
, buffer
, (LONG
)count
);
332 /**************************************************************************
333 * SetFileCompletionNotificationModes (KERNEL32.@)
335 BOOL WINAPI
SetFileCompletionNotificationModes( HANDLE file
, UCHAR flags
)
337 FILE_IO_COMPLETION_NOTIFICATION_INFORMATION info
;
341 return set_ntstatus( NtSetInformationFile( file
, &io
, &info
, sizeof(info
),
342 FileIoCompletionNotificationInformation
));
346 /*************************************************************************
347 * SetHandleCount (KERNEL32.@)
349 UINT WINAPI
SetHandleCount( UINT count
)
355 /*************************************************************************
356 * ReadFile (KERNEL32.@)
358 BOOL WINAPI
KERNEL32_ReadFile( HANDLE file
, LPVOID buffer
, DWORD count
,
359 LPDWORD result
, LPOVERLAPPED overlapped
)
361 if (result
) *result
= 0;
363 if (is_console_handle( file
))
367 if (!ReadConsoleA( file
, buffer
, count
, &conread
, NULL
) || !GetConsoleMode( file
, &mode
))
369 /* ctrl-Z (26) means end of file on window (if at beginning of buffer)
370 * but Unix uses ctrl-D (4), and ctrl-Z is a bad idea on Unix :-/
371 * So map both ctrl-D ctrl-Z to EOF.
373 if ((mode
& ENABLE_PROCESSED_INPUT
) && conread
> 0 &&
374 (((char *)buffer
)[0] == 26 || ((char *)buffer
)[0] == 4))
378 if (result
) *result
= conread
;
381 return ReadFile( file
, buffer
, count
, result
, overlapped
);
385 /*************************************************************************
386 * WriteFile (KERNEL32.@)
388 BOOL WINAPI
KERNEL32_WriteFile( HANDLE file
, LPCVOID buffer
, DWORD count
,
389 LPDWORD result
, LPOVERLAPPED overlapped
)
391 if (is_console_handle( file
)) return WriteConsoleA( file
, buffer
, count
, result
, NULL
);
392 return WriteFile( file
, buffer
, count
, result
, overlapped
);
396 /*************************************************************************
397 * FlushFileBuffers (KERNEL32.@)
399 BOOL WINAPI
KERNEL32_FlushFileBuffers( HANDLE file
)
401 IO_STATUS_BLOCK iosb
;
403 /* this will fail (as expected) for an output handle */
404 if (is_console_handle( file
)) return FlushConsoleInputBuffer( file
);
406 return set_ntstatus( NtFlushBuffersFile( file
, &iosb
));
410 /***********************************************************************
411 * DosDateTimeToFileTime (KERNEL32.@)
413 BOOL WINAPI
DosDateTimeToFileTime( WORD fatdate
, WORD fattime
, FILETIME
*ft
)
418 fields
.Year
= (fatdate
>> 9) + 1980;
419 fields
.Month
= ((fatdate
>> 5) & 0x0f);
420 fields
.Day
= (fatdate
& 0x1f);
421 fields
.Hour
= (fattime
>> 11);
422 fields
.Minute
= (fattime
>> 5) & 0x3f;
423 fields
.Second
= (fattime
& 0x1f) * 2;
424 fields
.Milliseconds
= 0;
425 if (!RtlTimeFieldsToTime( &fields
, &time
)) return FALSE
;
426 ft
->dwLowDateTime
= time
.u
.LowPart
;
427 ft
->dwHighDateTime
= time
.u
.HighPart
;
432 /***********************************************************************
433 * FileTimeToDosDateTime (KERNEL32.@)
435 BOOL WINAPI
FileTimeToDosDateTime( const FILETIME
*ft
, WORD
*fatdate
, WORD
*fattime
)
440 if (!fatdate
|| !fattime
)
442 SetLastError( ERROR_INVALID_PARAMETER
);
445 time
.u
.LowPart
= ft
->dwLowDateTime
;
446 time
.u
.HighPart
= ft
->dwHighDateTime
;
447 RtlTimeToTimeFields( &time
, &fields
);
448 if (fields
.Year
< 1980)
450 SetLastError( ERROR_INVALID_PARAMETER
);
453 *fattime
= (fields
.Hour
<< 11) + (fields
.Minute
<< 5) + (fields
.Second
/ 2);
454 *fatdate
= ((fields
.Year
- 1980) << 9) + (fields
.Month
<< 5) + fields
.Day
;
459 /**************************************************************************
460 * Operations on file names *
461 **************************************************************************/
464 /**************************************************************************
465 * ReplaceFileA (KERNEL32.@)
467 BOOL WINAPI
ReplaceFileA(LPCSTR lpReplacedFileName
,LPCSTR lpReplacementFileName
,
468 LPCSTR lpBackupFileName
, DWORD dwReplaceFlags
,
469 LPVOID lpExclude
, LPVOID lpReserved
)
471 WCHAR
*replacedW
, *replacementW
, *backupW
= NULL
;
474 /* This function only makes sense when the first two parameters are defined */
475 if (!lpReplacedFileName
|| !(replacedW
= FILE_name_AtoW( lpReplacedFileName
, TRUE
)))
477 SetLastError(ERROR_INVALID_PARAMETER
);
480 if (!lpReplacementFileName
|| !(replacementW
= FILE_name_AtoW( lpReplacementFileName
, TRUE
)))
482 HeapFree( GetProcessHeap(), 0, replacedW
);
483 SetLastError(ERROR_INVALID_PARAMETER
);
486 /* The backup parameter, however, is optional */
487 if (lpBackupFileName
)
489 if (!(backupW
= FILE_name_AtoW( lpBackupFileName
, TRUE
)))
491 HeapFree( GetProcessHeap(), 0, replacedW
);
492 HeapFree( GetProcessHeap(), 0, replacementW
);
493 SetLastError(ERROR_INVALID_PARAMETER
);
497 ret
= ReplaceFileW( replacedW
, replacementW
, backupW
, dwReplaceFlags
, lpExclude
, lpReserved
);
498 HeapFree( GetProcessHeap(), 0, replacedW
);
499 HeapFree( GetProcessHeap(), 0, replacementW
);
500 HeapFree( GetProcessHeap(), 0, backupW
);
505 /***********************************************************************
506 * OpenVxDHandle (KERNEL32.@)
508 * This function is supposed to return the corresponding Ring 0
509 * ("kernel") handle for a Ring 3 handle in Win9x.
510 * Evidently, Wine will have problems with this. But we try anyway,
513 HANDLE WINAPI
OpenVxDHandle(HANDLE hHandleRing3
)
515 FIXME( "(%p), stub! (returning Ring 3 handle instead of Ring 0)\n", hHandleRing3
);
520 /****************************************************************************
521 * DeviceIoControl (KERNEL32.@)
523 BOOL WINAPI
DeviceIoControl(HANDLE hDevice
, DWORD dwIoControlCode
,
524 LPVOID lpvInBuffer
, DWORD cbInBuffer
,
525 LPVOID lpvOutBuffer
, DWORD cbOutBuffer
,
526 LPDWORD lpcbBytesReturned
,
527 LPOVERLAPPED lpOverlapped
)
531 TRACE( "(%p,%x,%p,%d,%p,%d,%p,%p)\n",
532 hDevice
,dwIoControlCode
,lpvInBuffer
,cbInBuffer
,
533 lpvOutBuffer
,cbOutBuffer
,lpcbBytesReturned
,lpOverlapped
);
535 /* Check if this is a user defined control code for a VxD */
537 if (HIWORD( dwIoControlCode
) == 0 && (GetVersion() & 0x80000000))
539 typedef BOOL (WINAPI
*DeviceIoProc
)(DWORD
, LPVOID
, DWORD
, LPVOID
, DWORD
, LPDWORD
, LPOVERLAPPED
);
540 static DeviceIoProc (*vxd_get_proc
)(HANDLE
);
541 DeviceIoProc proc
= NULL
;
543 if (!vxd_get_proc
) vxd_get_proc
= (void *)GetProcAddress( GetModuleHandleW(krnl386W
),
544 "__wine_vxd_get_proc" );
545 if (vxd_get_proc
) proc
= vxd_get_proc( hDevice
);
546 if (proc
) return proc( dwIoControlCode
, lpvInBuffer
, cbInBuffer
,
547 lpvOutBuffer
, cbOutBuffer
, lpcbBytesReturned
, lpOverlapped
);
550 /* Not a VxD, let ntdll handle it */
554 LPVOID cvalue
= ((ULONG_PTR
)lpOverlapped
->hEvent
& 1) ? NULL
: lpOverlapped
;
555 lpOverlapped
->Internal
= STATUS_PENDING
;
556 lpOverlapped
->InternalHigh
= 0;
557 if (HIWORD(dwIoControlCode
) == FILE_DEVICE_FILE_SYSTEM
)
558 status
= NtFsControlFile(hDevice
, lpOverlapped
->hEvent
,
559 NULL
, cvalue
, (PIO_STATUS_BLOCK
)lpOverlapped
,
560 dwIoControlCode
, lpvInBuffer
, cbInBuffer
,
561 lpvOutBuffer
, cbOutBuffer
);
563 status
= NtDeviceIoControlFile(hDevice
, lpOverlapped
->hEvent
,
564 NULL
, cvalue
, (PIO_STATUS_BLOCK
)lpOverlapped
,
565 dwIoControlCode
, lpvInBuffer
, cbInBuffer
,
566 lpvOutBuffer
, cbOutBuffer
);
567 if (lpcbBytesReturned
) *lpcbBytesReturned
= lpOverlapped
->InternalHigh
;
571 IO_STATUS_BLOCK iosb
;
573 if (HIWORD(dwIoControlCode
) == FILE_DEVICE_FILE_SYSTEM
)
574 status
= NtFsControlFile(hDevice
, NULL
, NULL
, NULL
, &iosb
,
575 dwIoControlCode
, lpvInBuffer
, cbInBuffer
,
576 lpvOutBuffer
, cbOutBuffer
);
578 status
= NtDeviceIoControlFile(hDevice
, NULL
, NULL
, NULL
, &iosb
,
579 dwIoControlCode
, lpvInBuffer
, cbInBuffer
,
580 lpvOutBuffer
, cbOutBuffer
);
581 if (lpcbBytesReturned
) *lpcbBytesReturned
= iosb
.Information
;
583 return set_ntstatus( status
);
587 /***********************************************************************
588 * OpenFile (KERNEL32.@)
590 HFILE WINAPI
OpenFile( LPCSTR name
, OFSTRUCT
*ofs
, UINT mode
)
594 WORD filedatetime
[2];
597 if (!ofs
) return HFILE_ERROR
;
599 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name
,
600 ((mode
& 0x3 )==OF_READ
)?"OF_READ":
601 ((mode
& 0x3 )==OF_WRITE
)?"OF_WRITE":
602 ((mode
& 0x3 )==OF_READWRITE
)?"OF_READWRITE":"unknown",
603 ((mode
& 0x70 )==OF_SHARE_COMPAT
)?"OF_SHARE_COMPAT":
604 ((mode
& 0x70 )==OF_SHARE_DENY_NONE
)?"OF_SHARE_DENY_NONE":
605 ((mode
& 0x70 )==OF_SHARE_DENY_READ
)?"OF_SHARE_DENY_READ":
606 ((mode
& 0x70 )==OF_SHARE_DENY_WRITE
)?"OF_SHARE_DENY_WRITE":
607 ((mode
& 0x70 )==OF_SHARE_EXCLUSIVE
)?"OF_SHARE_EXCLUSIVE":"unknown",
608 ((mode
& OF_PARSE
)==OF_PARSE
)?"OF_PARSE ":"",
609 ((mode
& OF_DELETE
)==OF_DELETE
)?"OF_DELETE ":"",
610 ((mode
& OF_VERIFY
)==OF_VERIFY
)?"OF_VERIFY ":"",
611 ((mode
& OF_SEARCH
)==OF_SEARCH
)?"OF_SEARCH ":"",
612 ((mode
& OF_CANCEL
)==OF_CANCEL
)?"OF_CANCEL ":"",
613 ((mode
& OF_CREATE
)==OF_CREATE
)?"OF_CREATE ":"",
614 ((mode
& OF_PROMPT
)==OF_PROMPT
)?"OF_PROMPT ":"",
615 ((mode
& OF_EXIST
)==OF_EXIST
)?"OF_EXIST ":"",
616 ((mode
& OF_REOPEN
)==OF_REOPEN
)?"OF_REOPEN ":""
620 ofs
->cBytes
= sizeof(OFSTRUCT
);
622 if (mode
& OF_REOPEN
) name
= ofs
->szPathName
;
624 if (!name
) return HFILE_ERROR
;
626 TRACE("%s %04x\n", name
, mode
);
628 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
629 Are there any cases where getting the path here is wrong?
630 Uwe Bonnes 1997 Apr 2 */
631 len
= GetFullPathNameA( name
, sizeof(ofs
->szPathName
), ofs
->szPathName
, NULL
);
632 if (!len
) goto error
;
633 if (len
>= sizeof(ofs
->szPathName
))
635 SetLastError(ERROR_INVALID_DATA
);
639 /* OF_PARSE simply fills the structure */
643 ofs
->fFixedDisk
= (GetDriveTypeA( ofs
->szPathName
) != DRIVE_REMOVABLE
);
644 TRACE("(%s): OF_PARSE, res = '%s'\n", name
, ofs
->szPathName
);
648 /* OF_CREATE is completely different from all other options, so
651 if (mode
& OF_CREATE
)
653 if ((handle
= create_file_OF( name
, mode
)) == INVALID_HANDLE_VALUE
)
658 /* Now look for the file */
660 len
= SearchPathA( NULL
, name
, NULL
, sizeof(ofs
->szPathName
), ofs
->szPathName
, NULL
);
661 if (!len
) goto error
;
662 if (len
>= sizeof(ofs
->szPathName
))
664 SetLastError(ERROR_INVALID_DATA
);
668 TRACE("found %s\n", debugstr_a(ofs
->szPathName
) );
670 if (mode
& OF_DELETE
)
672 if (!DeleteFileA( ofs
->szPathName
)) goto error
;
673 TRACE("(%s): OF_DELETE return = OK\n", name
);
677 handle
= LongToHandle(_lopen( ofs
->szPathName
, mode
));
678 if (handle
== INVALID_HANDLE_VALUE
) goto error
;
680 GetFileTime( handle
, NULL
, NULL
, &filetime
);
681 FileTimeToDosDateTime( &filetime
, &filedatetime
[0], &filedatetime
[1] );
682 if ((mode
& OF_VERIFY
) && (mode
& OF_REOPEN
))
684 if (ofs
->Reserved1
!= filedatetime
[0] || ofs
->Reserved2
!= filedatetime
[1] )
686 CloseHandle( handle
);
687 WARN("(%s): OF_VERIFY failed\n", name
);
688 /* FIXME: what error here? */
689 SetLastError( ERROR_FILE_NOT_FOUND
);
693 ofs
->Reserved1
= filedatetime
[0];
694 ofs
->Reserved2
= filedatetime
[1];
696 TRACE("(%s): OK, return = %p\n", name
, handle
);
697 if (mode
& OF_EXIST
) /* Return TRUE instead of a handle */
699 CloseHandle( handle
);
702 return HandleToLong(handle
);
704 error
: /* We get here if there was an error opening the file */
705 ofs
->nErrCode
= GetLastError();
706 WARN("(%s): return = HFILE_ERROR error= %d\n", name
,ofs
->nErrCode
);