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
27 #define NONAMELESSUNION
28 #define NONAMELESSSTRUCT
31 #define WIN32_NO_STATUS
37 #include "ddk/ntddk.h"
38 #include "kernel_private.h"
42 #include "wine/exception.h"
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(file
);
47 static const WCHAR krnl386W
[] = {'k','r','n','l','3','8','6','.','e','x','e','1','6',0};
49 /***********************************************************************
52 * Wrapper for CreateFile that takes OF_* mode flags.
54 static HANDLE
create_file_OF( LPCSTR path
, INT mode
)
56 DWORD access
, sharing
, creation
;
60 creation
= CREATE_ALWAYS
;
61 access
= GENERIC_READ
| GENERIC_WRITE
;
65 creation
= OPEN_EXISTING
;
68 case OF_READ
: access
= GENERIC_READ
; break;
69 case OF_WRITE
: access
= GENERIC_WRITE
; break;
70 case OF_READWRITE
: access
= GENERIC_READ
| GENERIC_WRITE
; break;
71 default: access
= 0; break;
77 case OF_SHARE_EXCLUSIVE
: sharing
= 0; break;
78 case OF_SHARE_DENY_WRITE
: sharing
= FILE_SHARE_READ
; break;
79 case OF_SHARE_DENY_READ
: sharing
= FILE_SHARE_WRITE
; break;
80 case OF_SHARE_DENY_NONE
:
82 default: sharing
= FILE_SHARE_READ
| FILE_SHARE_WRITE
; break;
84 return CreateFileA( path
, access
, sharing
, NULL
, creation
, FILE_ATTRIBUTE_NORMAL
, 0 );
88 /***********************************************************************
91 * Convert a file name to Unicode, taking into account the OEM/Ansi API mode.
93 * If alloc is FALSE uses the TEB static buffer, so it can only be used when
94 * there is no possibility for the function to do that twice, taking into
95 * account any called function.
97 WCHAR
*FILE_name_AtoW( LPCSTR name
, BOOL alloc
)
100 UNICODE_STRING strW
, *pstrW
;
103 RtlInitAnsiString( &str
, name
);
104 pstrW
= alloc
? &strW
: &NtCurrentTeb()->StaticUnicodeString
;
105 if (!AreFileApisANSI())
106 status
= RtlOemStringToUnicodeString( pstrW
, &str
, alloc
);
108 status
= RtlAnsiStringToUnicodeString( pstrW
, &str
, alloc
);
109 if (status
== STATUS_SUCCESS
) return pstrW
->Buffer
;
111 if (status
== STATUS_BUFFER_OVERFLOW
)
112 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
114 SetLastError( RtlNtStatusToDosError(status
) );
119 /***********************************************************************
122 * Convert a file name back to OEM/Ansi. Returns number of bytes copied.
124 DWORD
FILE_name_WtoA( LPCWSTR src
, INT srclen
, LPSTR dest
, INT destlen
)
128 if (srclen
< 0) srclen
= lstrlenW( src
) + 1;
131 if (!AreFileApisANSI())
134 strW
.Buffer
= (WCHAR
*)src
;
135 strW
.Length
= srclen
* sizeof(WCHAR
);
136 ret
= RtlUnicodeStringToOemSize( &strW
) - 1;
139 RtlUnicodeToMultiByteSize( &ret
, src
, srclen
* sizeof(WCHAR
) );
143 if (!AreFileApisANSI())
144 RtlUnicodeToOemN( dest
, destlen
, &ret
, src
, srclen
* sizeof(WCHAR
) );
146 RtlUnicodeToMultiByteN( dest
, destlen
, &ret
, src
, srclen
* sizeof(WCHAR
) );
152 /***********************************************************************
153 * _hread (KERNEL32.@)
155 LONG WINAPI
_hread( HFILE hFile
, LPVOID buffer
, LONG count
)
157 return _lread( hFile
, buffer
, count
);
161 /***********************************************************************
162 * _hwrite (KERNEL32.@)
164 * experimentation yields that _lwrite:
165 * o truncates the file at the current position with
167 * o returns 0 on a 0 length write
168 * o works with console handles
171 LONG WINAPI
_hwrite( HFILE handle
, LPCSTR buffer
, LONG count
)
175 TRACE("%d %p %d\n", handle
, buffer
, count
);
179 /* Expand or truncate at current position */
180 if (!SetEndOfFile( LongToHandle(handle
) )) return HFILE_ERROR
;
183 if (!WriteFile( LongToHandle(handle
), buffer
, count
, &result
, NULL
))
189 /***********************************************************************
190 * _lclose (KERNEL32.@)
192 HFILE WINAPI
_lclose( HFILE hFile
)
194 TRACE("handle %d\n", hFile
);
195 return CloseHandle( LongToHandle(hFile
) ) ? 0 : HFILE_ERROR
;
199 /***********************************************************************
200 * _lcreat (KERNEL32.@)
202 HFILE WINAPI
_lcreat( LPCSTR path
, INT attr
)
206 /* Mask off all flags not explicitly allowed by the doc */
207 attr
&= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_SYSTEM
;
208 TRACE("%s %02x\n", path
, attr
);
209 hfile
= CreateFileA( path
, GENERIC_READ
| GENERIC_WRITE
,
210 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
211 CREATE_ALWAYS
, attr
, 0 );
212 return HandleToLong(hfile
);
216 /***********************************************************************
217 * _lopen (KERNEL32.@)
219 HFILE WINAPI
_lopen( LPCSTR path
, INT mode
)
223 TRACE("(%s,%04x)\n", debugstr_a(path
), mode
);
224 hfile
= create_file_OF( path
, mode
& ~OF_CREATE
);
225 return HandleToLong(hfile
);
228 /***********************************************************************
229 * _lread (KERNEL32.@)
231 UINT WINAPI
_lread( HFILE handle
, LPVOID buffer
, UINT count
)
234 if (!ReadFile( LongToHandle(handle
), buffer
, count
, &result
, NULL
))
240 /***********************************************************************
241 * _llseek (KERNEL32.@)
243 LONG WINAPI
_llseek( HFILE hFile
, LONG lOffset
, INT nOrigin
)
245 return SetFilePointer( LongToHandle(hFile
), lOffset
, NULL
, nOrigin
);
249 /***********************************************************************
250 * _lwrite (KERNEL32.@)
252 UINT WINAPI
_lwrite( HFILE hFile
, LPCSTR buffer
, UINT count
)
254 return (UINT
)_hwrite( hFile
, buffer
, (LONG
)count
);
258 /**************************************************************************
259 * SetFileCompletionNotificationModes (KERNEL32.@)
261 BOOL WINAPI
SetFileCompletionNotificationModes( HANDLE file
, UCHAR flags
)
263 FILE_IO_COMPLETION_NOTIFICATION_INFORMATION info
;
267 return set_ntstatus( NtSetInformationFile( file
, &io
, &info
, sizeof(info
),
268 FileIoCompletionNotificationInformation
));
272 /*************************************************************************
273 * SetHandleCount (KERNEL32.@)
275 UINT WINAPI
SetHandleCount( UINT count
)
281 /*************************************************************************
282 * ReadFile (KERNEL32.@)
284 BOOL WINAPI
KERNEL32_ReadFile( HANDLE file
, LPVOID buffer
, DWORD count
,
285 LPDWORD result
, LPOVERLAPPED overlapped
)
287 if (result
) *result
= 0;
289 if (is_console_handle( file
))
293 if (!ReadConsoleA( file
, buffer
, count
, &conread
, NULL
) || !GetConsoleMode( file
, &mode
))
295 /* ctrl-Z (26) means end of file on window (if at beginning of buffer)
296 * but Unix uses ctrl-D (4), and ctrl-Z is a bad idea on Unix :-/
297 * So map both ctrl-D ctrl-Z to EOF.
299 if ((mode
& ENABLE_PROCESSED_INPUT
) && conread
> 0 &&
300 (((char *)buffer
)[0] == 26 || ((char *)buffer
)[0] == 4))
304 if (result
) *result
= conread
;
307 return ReadFile( file
, buffer
, count
, result
, overlapped
);
311 /*************************************************************************
312 * WriteFile (KERNEL32.@)
314 BOOL WINAPI
KERNEL32_WriteFile( HANDLE file
, LPCVOID buffer
, DWORD count
,
315 LPDWORD result
, LPOVERLAPPED overlapped
)
317 if (is_console_handle( file
)) return WriteConsoleA( file
, buffer
, count
, result
, NULL
);
318 return WriteFile( file
, buffer
, count
, result
, overlapped
);
322 /***********************************************************************
323 * DosDateTimeToFileTime (KERNEL32.@)
325 BOOL WINAPI
DosDateTimeToFileTime( WORD fatdate
, WORD fattime
, FILETIME
*ft
)
330 fields
.Year
= (fatdate
>> 9) + 1980;
331 fields
.Month
= ((fatdate
>> 5) & 0x0f);
332 fields
.Day
= (fatdate
& 0x1f);
333 fields
.Hour
= (fattime
>> 11);
334 fields
.Minute
= (fattime
>> 5) & 0x3f;
335 fields
.Second
= (fattime
& 0x1f) * 2;
336 fields
.Milliseconds
= 0;
337 if (!RtlTimeFieldsToTime( &fields
, &time
)) return FALSE
;
338 ft
->dwLowDateTime
= time
.u
.LowPart
;
339 ft
->dwHighDateTime
= time
.u
.HighPart
;
344 /***********************************************************************
345 * FileTimeToDosDateTime (KERNEL32.@)
347 BOOL WINAPI
FileTimeToDosDateTime( const FILETIME
*ft
, WORD
*fatdate
, WORD
*fattime
)
352 if (!fatdate
|| !fattime
)
354 SetLastError( ERROR_INVALID_PARAMETER
);
357 time
.u
.LowPart
= ft
->dwLowDateTime
;
358 time
.u
.HighPart
= ft
->dwHighDateTime
;
359 RtlTimeToTimeFields( &time
, &fields
);
360 if (fields
.Year
< 1980)
362 SetLastError( ERROR_INVALID_PARAMETER
);
365 *fattime
= (fields
.Hour
<< 11) + (fields
.Minute
<< 5) + (fields
.Second
/ 2);
366 *fatdate
= ((fields
.Year
- 1980) << 9) + (fields
.Month
<< 5) + fields
.Day
;
371 /**************************************************************************
372 * Operations on file names *
373 **************************************************************************/
376 /**************************************************************************
377 * ReplaceFileA (KERNEL32.@)
379 BOOL WINAPI
ReplaceFileA(LPCSTR lpReplacedFileName
,LPCSTR lpReplacementFileName
,
380 LPCSTR lpBackupFileName
, DWORD dwReplaceFlags
,
381 LPVOID lpExclude
, LPVOID lpReserved
)
383 WCHAR
*replacedW
, *replacementW
, *backupW
= NULL
;
386 /* This function only makes sense when the first two parameters are defined */
387 if (!lpReplacedFileName
|| !(replacedW
= FILE_name_AtoW( lpReplacedFileName
, TRUE
)))
389 SetLastError(ERROR_INVALID_PARAMETER
);
392 if (!lpReplacementFileName
|| !(replacementW
= FILE_name_AtoW( lpReplacementFileName
, TRUE
)))
394 HeapFree( GetProcessHeap(), 0, replacedW
);
395 SetLastError(ERROR_INVALID_PARAMETER
);
398 /* The backup parameter, however, is optional */
399 if (lpBackupFileName
)
401 if (!(backupW
= FILE_name_AtoW( lpBackupFileName
, TRUE
)))
403 HeapFree( GetProcessHeap(), 0, replacedW
);
404 HeapFree( GetProcessHeap(), 0, replacementW
);
405 SetLastError(ERROR_INVALID_PARAMETER
);
409 ret
= ReplaceFileW( replacedW
, replacementW
, backupW
, dwReplaceFlags
, lpExclude
, lpReserved
);
410 HeapFree( GetProcessHeap(), 0, replacedW
);
411 HeapFree( GetProcessHeap(), 0, replacementW
);
412 HeapFree( GetProcessHeap(), 0, backupW
);
417 /***********************************************************************
418 * OpenVxDHandle (KERNEL32.@)
420 * This function is supposed to return the corresponding Ring 0
421 * ("kernel") handle for a Ring 3 handle in Win9x.
422 * Evidently, Wine will have problems with this. But we try anyway,
425 HANDLE WINAPI
OpenVxDHandle(HANDLE hHandleRing3
)
427 FIXME( "(%p), stub! (returning Ring 3 handle instead of Ring 0)\n", hHandleRing3
);
432 /****************************************************************************
433 * DeviceIoControl (KERNEL32.@)
435 BOOL WINAPI
DeviceIoControl(HANDLE hDevice
, DWORD dwIoControlCode
,
436 LPVOID lpvInBuffer
, DWORD cbInBuffer
,
437 LPVOID lpvOutBuffer
, DWORD cbOutBuffer
,
438 LPDWORD lpcbBytesReturned
,
439 LPOVERLAPPED lpOverlapped
)
443 TRACE( "(%p,%x,%p,%d,%p,%d,%p,%p)\n",
444 hDevice
,dwIoControlCode
,lpvInBuffer
,cbInBuffer
,
445 lpvOutBuffer
,cbOutBuffer
,lpcbBytesReturned
,lpOverlapped
);
447 /* Check if this is a user defined control code for a VxD */
449 if (HIWORD( dwIoControlCode
) == 0 && (GetVersion() & 0x80000000))
451 typedef BOOL (WINAPI
*DeviceIoProc
)(DWORD
, LPVOID
, DWORD
, LPVOID
, DWORD
, LPDWORD
, LPOVERLAPPED
);
452 static DeviceIoProc (*vxd_get_proc
)(HANDLE
);
453 DeviceIoProc proc
= NULL
;
455 if (!vxd_get_proc
) vxd_get_proc
= (void *)GetProcAddress( GetModuleHandleW(krnl386W
),
456 "__wine_vxd_get_proc" );
457 if (vxd_get_proc
) proc
= vxd_get_proc( hDevice
);
458 if (proc
) return proc( dwIoControlCode
, lpvInBuffer
, cbInBuffer
,
459 lpvOutBuffer
, cbOutBuffer
, lpcbBytesReturned
, lpOverlapped
);
462 /* Not a VxD, let ntdll handle it */
466 LPVOID cvalue
= ((ULONG_PTR
)lpOverlapped
->hEvent
& 1) ? NULL
: lpOverlapped
;
467 lpOverlapped
->Internal
= STATUS_PENDING
;
468 lpOverlapped
->InternalHigh
= 0;
469 if (HIWORD(dwIoControlCode
) == FILE_DEVICE_FILE_SYSTEM
)
470 status
= NtFsControlFile(hDevice
, lpOverlapped
->hEvent
,
471 NULL
, cvalue
, (PIO_STATUS_BLOCK
)lpOverlapped
,
472 dwIoControlCode
, lpvInBuffer
, cbInBuffer
,
473 lpvOutBuffer
, cbOutBuffer
);
475 status
= NtDeviceIoControlFile(hDevice
, lpOverlapped
->hEvent
,
476 NULL
, cvalue
, (PIO_STATUS_BLOCK
)lpOverlapped
,
477 dwIoControlCode
, lpvInBuffer
, cbInBuffer
,
478 lpvOutBuffer
, cbOutBuffer
);
479 if (lpcbBytesReturned
) *lpcbBytesReturned
= lpOverlapped
->InternalHigh
;
483 IO_STATUS_BLOCK iosb
;
485 if (HIWORD(dwIoControlCode
) == FILE_DEVICE_FILE_SYSTEM
)
486 status
= NtFsControlFile(hDevice
, NULL
, NULL
, NULL
, &iosb
,
487 dwIoControlCode
, lpvInBuffer
, cbInBuffer
,
488 lpvOutBuffer
, cbOutBuffer
);
490 status
= NtDeviceIoControlFile(hDevice
, NULL
, NULL
, NULL
, &iosb
,
491 dwIoControlCode
, lpvInBuffer
, cbInBuffer
,
492 lpvOutBuffer
, cbOutBuffer
);
493 if (lpcbBytesReturned
) *lpcbBytesReturned
= iosb
.Information
;
495 return set_ntstatus( status
);
499 /***********************************************************************
500 * OpenFile (KERNEL32.@)
502 HFILE WINAPI
OpenFile( LPCSTR name
, OFSTRUCT
*ofs
, UINT mode
)
506 WORD filedatetime
[2];
509 if (!ofs
) return HFILE_ERROR
;
511 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name
,
512 ((mode
& 0x3 )==OF_READ
)?"OF_READ":
513 ((mode
& 0x3 )==OF_WRITE
)?"OF_WRITE":
514 ((mode
& 0x3 )==OF_READWRITE
)?"OF_READWRITE":"unknown",
515 ((mode
& 0x70 )==OF_SHARE_COMPAT
)?"OF_SHARE_COMPAT":
516 ((mode
& 0x70 )==OF_SHARE_DENY_NONE
)?"OF_SHARE_DENY_NONE":
517 ((mode
& 0x70 )==OF_SHARE_DENY_READ
)?"OF_SHARE_DENY_READ":
518 ((mode
& 0x70 )==OF_SHARE_DENY_WRITE
)?"OF_SHARE_DENY_WRITE":
519 ((mode
& 0x70 )==OF_SHARE_EXCLUSIVE
)?"OF_SHARE_EXCLUSIVE":"unknown",
520 ((mode
& OF_PARSE
)==OF_PARSE
)?"OF_PARSE ":"",
521 ((mode
& OF_DELETE
)==OF_DELETE
)?"OF_DELETE ":"",
522 ((mode
& OF_VERIFY
)==OF_VERIFY
)?"OF_VERIFY ":"",
523 ((mode
& OF_SEARCH
)==OF_SEARCH
)?"OF_SEARCH ":"",
524 ((mode
& OF_CANCEL
)==OF_CANCEL
)?"OF_CANCEL ":"",
525 ((mode
& OF_CREATE
)==OF_CREATE
)?"OF_CREATE ":"",
526 ((mode
& OF_PROMPT
)==OF_PROMPT
)?"OF_PROMPT ":"",
527 ((mode
& OF_EXIST
)==OF_EXIST
)?"OF_EXIST ":"",
528 ((mode
& OF_REOPEN
)==OF_REOPEN
)?"OF_REOPEN ":""
532 ofs
->cBytes
= sizeof(OFSTRUCT
);
534 if (mode
& OF_REOPEN
) name
= ofs
->szPathName
;
536 if (!name
) return HFILE_ERROR
;
538 TRACE("%s %04x\n", name
, mode
);
540 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
541 Are there any cases where getting the path here is wrong?
542 Uwe Bonnes 1997 Apr 2 */
543 len
= GetFullPathNameA( name
, sizeof(ofs
->szPathName
), ofs
->szPathName
, NULL
);
544 if (!len
) goto error
;
545 if (len
>= sizeof(ofs
->szPathName
))
547 SetLastError(ERROR_INVALID_DATA
);
551 /* OF_PARSE simply fills the structure */
555 ofs
->fFixedDisk
= (GetDriveTypeA( ofs
->szPathName
) != DRIVE_REMOVABLE
);
556 TRACE("(%s): OF_PARSE, res = '%s'\n", name
, ofs
->szPathName
);
560 /* OF_CREATE is completely different from all other options, so
563 if (mode
& OF_CREATE
)
565 if ((handle
= create_file_OF( name
, mode
)) == INVALID_HANDLE_VALUE
)
570 /* Now look for the file */
572 len
= SearchPathA( NULL
, name
, NULL
, sizeof(ofs
->szPathName
), ofs
->szPathName
, NULL
);
573 if (!len
) goto error
;
574 if (len
>= sizeof(ofs
->szPathName
))
576 SetLastError(ERROR_INVALID_DATA
);
580 TRACE("found %s\n", debugstr_a(ofs
->szPathName
) );
582 if (mode
& OF_DELETE
)
584 if (!DeleteFileA( ofs
->szPathName
)) goto error
;
585 TRACE("(%s): OF_DELETE return = OK\n", name
);
589 handle
= LongToHandle(_lopen( ofs
->szPathName
, mode
));
590 if (handle
== INVALID_HANDLE_VALUE
) goto error
;
592 GetFileTime( handle
, NULL
, NULL
, &filetime
);
593 FileTimeToDosDateTime( &filetime
, &filedatetime
[0], &filedatetime
[1] );
594 if ((mode
& OF_VERIFY
) && (mode
& OF_REOPEN
))
596 if (ofs
->Reserved1
!= filedatetime
[0] || ofs
->Reserved2
!= filedatetime
[1] )
598 CloseHandle( handle
);
599 WARN("(%s): OF_VERIFY failed\n", name
);
600 /* FIXME: what error here? */
601 SetLastError( ERROR_FILE_NOT_FOUND
);
605 ofs
->Reserved1
= filedatetime
[0];
606 ofs
->Reserved2
= filedatetime
[1];
608 TRACE("(%s): OK, return = %p\n", name
, handle
);
609 if (mode
& OF_EXIST
) /* Return TRUE instead of a handle */
611 CloseHandle( handle
);
614 return HandleToLong(handle
);
616 error
: /* We get here if there was an error opening the file */
617 ofs
->nErrCode
= GetLastError();
618 WARN("(%s): return = HFILE_ERROR error= %d\n", name
,ofs
->nErrCode
);