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 /***********************************************************************
50 * Wrapper for CreateFile that takes OF_* mode flags.
52 static HANDLE
create_file_OF( LPCSTR path
, INT mode
)
54 DWORD access
, sharing
, creation
;
58 creation
= CREATE_ALWAYS
;
59 access
= GENERIC_READ
| GENERIC_WRITE
;
63 creation
= OPEN_EXISTING
;
66 case OF_READ
: access
= GENERIC_READ
; break;
67 case OF_WRITE
: access
= GENERIC_WRITE
; break;
68 case OF_READWRITE
: access
= GENERIC_READ
| GENERIC_WRITE
; break;
69 default: access
= 0; break;
75 case OF_SHARE_EXCLUSIVE
: sharing
= 0; break;
76 case OF_SHARE_DENY_WRITE
: sharing
= FILE_SHARE_READ
; break;
77 case OF_SHARE_DENY_READ
: sharing
= FILE_SHARE_WRITE
; break;
78 case OF_SHARE_DENY_NONE
:
80 default: sharing
= FILE_SHARE_READ
| FILE_SHARE_WRITE
; break;
82 return CreateFileA( path
, access
, sharing
, NULL
, creation
, FILE_ATTRIBUTE_NORMAL
, 0 );
86 /***********************************************************************
89 * Convert a file name to Unicode, taking into account the OEM/Ansi API mode.
91 * If alloc is FALSE uses the TEB static buffer, so it can only be used when
92 * there is no possibility for the function to do that twice, taking into
93 * account any called function.
95 WCHAR
*FILE_name_AtoW( LPCSTR name
, BOOL alloc
)
98 UNICODE_STRING strW
, *pstrW
;
101 RtlInitAnsiString( &str
, name
);
102 pstrW
= alloc
? &strW
: &NtCurrentTeb()->StaticUnicodeString
;
103 if (!AreFileApisANSI())
104 status
= RtlOemStringToUnicodeString( pstrW
, &str
, alloc
);
106 status
= RtlAnsiStringToUnicodeString( pstrW
, &str
, alloc
);
107 if (status
== STATUS_SUCCESS
) return pstrW
->Buffer
;
109 if (status
== STATUS_BUFFER_OVERFLOW
)
110 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
112 SetLastError( RtlNtStatusToDosError(status
) );
117 /***********************************************************************
120 * Convert a file name back to OEM/Ansi. Returns number of bytes copied.
122 DWORD
FILE_name_WtoA( LPCWSTR src
, INT srclen
, LPSTR dest
, INT destlen
)
126 if (srclen
< 0) srclen
= lstrlenW( src
) + 1;
129 if (!AreFileApisANSI())
132 strW
.Buffer
= (WCHAR
*)src
;
133 strW
.Length
= srclen
* sizeof(WCHAR
);
134 ret
= RtlUnicodeStringToOemSize( &strW
) - 1;
137 RtlUnicodeToMultiByteSize( &ret
, src
, srclen
* sizeof(WCHAR
) );
141 if (!AreFileApisANSI())
142 RtlUnicodeToOemN( dest
, destlen
, &ret
, src
, srclen
* sizeof(WCHAR
) );
144 RtlUnicodeToMultiByteN( dest
, destlen
, &ret
, src
, srclen
* sizeof(WCHAR
) );
150 /***********************************************************************
151 * _hread (KERNEL32.@)
153 LONG WINAPI
_hread( HFILE hFile
, LPVOID buffer
, LONG count
)
155 return _lread( hFile
, buffer
, count
);
159 /***********************************************************************
160 * _hwrite (KERNEL32.@)
162 * experimentation yields that _lwrite:
163 * o truncates the file at the current position with
165 * o returns 0 on a 0 length write
166 * o works with console handles
169 LONG WINAPI
_hwrite( HFILE handle
, LPCSTR buffer
, LONG count
)
173 TRACE("%d %p %d\n", handle
, buffer
, count
);
177 /* Expand or truncate at current position */
178 if (!SetEndOfFile( LongToHandle(handle
) )) return HFILE_ERROR
;
181 if (!WriteFile( LongToHandle(handle
), buffer
, count
, &result
, NULL
))
187 /***********************************************************************
188 * _lclose (KERNEL32.@)
190 HFILE WINAPI
_lclose( HFILE hFile
)
192 TRACE("handle %d\n", hFile
);
193 return CloseHandle( LongToHandle(hFile
) ) ? 0 : HFILE_ERROR
;
197 /***********************************************************************
198 * _lcreat (KERNEL32.@)
200 HFILE WINAPI
_lcreat( LPCSTR path
, INT attr
)
204 /* Mask off all flags not explicitly allowed by the doc */
205 attr
&= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_SYSTEM
;
206 TRACE("%s %02x\n", path
, attr
);
207 hfile
= CreateFileA( path
, GENERIC_READ
| GENERIC_WRITE
,
208 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
209 CREATE_ALWAYS
, attr
, 0 );
210 return HandleToLong(hfile
);
214 /***********************************************************************
215 * _lopen (KERNEL32.@)
217 HFILE WINAPI
_lopen( LPCSTR path
, INT mode
)
221 TRACE("(%s,%04x)\n", debugstr_a(path
), mode
);
222 hfile
= create_file_OF( path
, mode
& ~OF_CREATE
);
223 return HandleToLong(hfile
);
226 /***********************************************************************
227 * _lread (KERNEL32.@)
229 UINT WINAPI
_lread( HFILE handle
, LPVOID buffer
, UINT count
)
232 if (!ReadFile( LongToHandle(handle
), buffer
, count
, &result
, NULL
))
238 /***********************************************************************
239 * _llseek (KERNEL32.@)
241 LONG WINAPI
_llseek( HFILE hFile
, LONG lOffset
, INT nOrigin
)
243 return SetFilePointer( LongToHandle(hFile
), lOffset
, NULL
, nOrigin
);
247 /***********************************************************************
248 * _lwrite (KERNEL32.@)
250 UINT WINAPI
_lwrite( HFILE hFile
, LPCSTR buffer
, UINT count
)
252 return (UINT
)_hwrite( hFile
, buffer
, (LONG
)count
);
256 /**************************************************************************
257 * SetFileCompletionNotificationModes (KERNEL32.@)
259 BOOL WINAPI
SetFileCompletionNotificationModes( HANDLE file
, UCHAR flags
)
261 FILE_IO_COMPLETION_NOTIFICATION_INFORMATION info
;
265 return set_ntstatus( NtSetInformationFile( file
, &io
, &info
, sizeof(info
),
266 FileIoCompletionNotificationInformation
));
270 /*************************************************************************
271 * SetHandleCount (KERNEL32.@)
273 UINT WINAPI
SetHandleCount( UINT count
)
279 /***********************************************************************
280 * DosDateTimeToFileTime (KERNEL32.@)
282 BOOL WINAPI
DosDateTimeToFileTime( WORD fatdate
, WORD fattime
, FILETIME
*ft
)
287 fields
.Year
= (fatdate
>> 9) + 1980;
288 fields
.Month
= ((fatdate
>> 5) & 0x0f);
289 fields
.Day
= (fatdate
& 0x1f);
290 fields
.Hour
= (fattime
>> 11);
291 fields
.Minute
= (fattime
>> 5) & 0x3f;
292 fields
.Second
= (fattime
& 0x1f) * 2;
293 fields
.Milliseconds
= 0;
294 if (!RtlTimeFieldsToTime( &fields
, &time
)) return FALSE
;
295 ft
->dwLowDateTime
= time
.u
.LowPart
;
296 ft
->dwHighDateTime
= time
.u
.HighPart
;
301 /***********************************************************************
302 * FileTimeToDosDateTime (KERNEL32.@)
304 BOOL WINAPI
FileTimeToDosDateTime( const FILETIME
*ft
, WORD
*fatdate
, WORD
*fattime
)
309 if (!fatdate
|| !fattime
)
311 SetLastError( ERROR_INVALID_PARAMETER
);
314 time
.u
.LowPart
= ft
->dwLowDateTime
;
315 time
.u
.HighPart
= ft
->dwHighDateTime
;
316 RtlTimeToTimeFields( &time
, &fields
);
317 if (fields
.Year
< 1980)
319 SetLastError( ERROR_INVALID_PARAMETER
);
322 *fattime
= (fields
.Hour
<< 11) + (fields
.Minute
<< 5) + (fields
.Second
/ 2);
323 *fatdate
= ((fields
.Year
- 1980) << 9) + (fields
.Month
<< 5) + fields
.Day
;
328 /**************************************************************************
329 * Operations on file names *
330 **************************************************************************/
333 /**************************************************************************
334 * ReplaceFileA (KERNEL32.@)
336 BOOL WINAPI
ReplaceFileA(LPCSTR lpReplacedFileName
,LPCSTR lpReplacementFileName
,
337 LPCSTR lpBackupFileName
, DWORD dwReplaceFlags
,
338 LPVOID lpExclude
, LPVOID lpReserved
)
340 WCHAR
*replacedW
, *replacementW
, *backupW
= NULL
;
343 /* This function only makes sense when the first two parameters are defined */
344 if (!lpReplacedFileName
|| !(replacedW
= FILE_name_AtoW( lpReplacedFileName
, TRUE
)))
346 SetLastError(ERROR_INVALID_PARAMETER
);
349 if (!lpReplacementFileName
|| !(replacementW
= FILE_name_AtoW( lpReplacementFileName
, TRUE
)))
351 HeapFree( GetProcessHeap(), 0, replacedW
);
352 SetLastError(ERROR_INVALID_PARAMETER
);
355 /* The backup parameter, however, is optional */
356 if (lpBackupFileName
)
358 if (!(backupW
= FILE_name_AtoW( lpBackupFileName
, TRUE
)))
360 HeapFree( GetProcessHeap(), 0, replacedW
);
361 HeapFree( GetProcessHeap(), 0, replacementW
);
362 SetLastError(ERROR_INVALID_PARAMETER
);
366 ret
= ReplaceFileW( replacedW
, replacementW
, backupW
, dwReplaceFlags
, lpExclude
, lpReserved
);
367 HeapFree( GetProcessHeap(), 0, replacedW
);
368 HeapFree( GetProcessHeap(), 0, replacementW
);
369 HeapFree( GetProcessHeap(), 0, backupW
);
374 /***********************************************************************
375 * OpenVxDHandle (KERNEL32.@)
377 * This function is supposed to return the corresponding Ring 0
378 * ("kernel") handle for a Ring 3 handle in Win9x.
379 * Evidently, Wine will have problems with this. But we try anyway,
382 HANDLE WINAPI
OpenVxDHandle(HANDLE hHandleRing3
)
384 FIXME( "(%p), stub! (returning Ring 3 handle instead of Ring 0)\n", hHandleRing3
);
389 /****************************************************************************
390 * DeviceIoControl (KERNEL32.@)
392 BOOL WINAPI
DeviceIoControl(HANDLE hDevice
, DWORD dwIoControlCode
,
393 LPVOID lpvInBuffer
, DWORD cbInBuffer
,
394 LPVOID lpvOutBuffer
, DWORD cbOutBuffer
,
395 LPDWORD lpcbBytesReturned
,
396 LPOVERLAPPED lpOverlapped
)
400 TRACE( "(%p,%x,%p,%d,%p,%d,%p,%p)\n",
401 hDevice
,dwIoControlCode
,lpvInBuffer
,cbInBuffer
,
402 lpvOutBuffer
,cbOutBuffer
,lpcbBytesReturned
,lpOverlapped
);
404 /* Check if this is a user defined control code for a VxD */
406 if (HIWORD( dwIoControlCode
) == 0 && (GetVersion() & 0x80000000))
408 typedef BOOL (WINAPI
*DeviceIoProc
)(DWORD
, LPVOID
, DWORD
, LPVOID
, DWORD
, LPDWORD
, LPOVERLAPPED
);
409 static DeviceIoProc (*vxd_get_proc
)(HANDLE
);
410 DeviceIoProc proc
= NULL
;
412 if (!vxd_get_proc
) vxd_get_proc
= (void *)GetProcAddress( GetModuleHandleW(L
"krnl386.exe16"),
413 "__wine_vxd_get_proc" );
414 if (vxd_get_proc
) proc
= vxd_get_proc( hDevice
);
415 if (proc
) return proc( dwIoControlCode
, lpvInBuffer
, cbInBuffer
,
416 lpvOutBuffer
, cbOutBuffer
, lpcbBytesReturned
, lpOverlapped
);
419 /* Not a VxD, let ntdll handle it */
423 LPVOID cvalue
= ((ULONG_PTR
)lpOverlapped
->hEvent
& 1) ? NULL
: lpOverlapped
;
424 lpOverlapped
->Internal
= STATUS_PENDING
;
425 lpOverlapped
->InternalHigh
= 0;
426 if (HIWORD(dwIoControlCode
) == FILE_DEVICE_FILE_SYSTEM
)
427 status
= NtFsControlFile(hDevice
, lpOverlapped
->hEvent
,
428 NULL
, cvalue
, (PIO_STATUS_BLOCK
)lpOverlapped
,
429 dwIoControlCode
, lpvInBuffer
, cbInBuffer
,
430 lpvOutBuffer
, cbOutBuffer
);
432 status
= NtDeviceIoControlFile(hDevice
, lpOverlapped
->hEvent
,
433 NULL
, cvalue
, (PIO_STATUS_BLOCK
)lpOverlapped
,
434 dwIoControlCode
, lpvInBuffer
, cbInBuffer
,
435 lpvOutBuffer
, cbOutBuffer
);
436 if (lpcbBytesReturned
) *lpcbBytesReturned
= lpOverlapped
->InternalHigh
;
440 IO_STATUS_BLOCK iosb
;
442 if (HIWORD(dwIoControlCode
) == FILE_DEVICE_FILE_SYSTEM
)
443 status
= NtFsControlFile(hDevice
, NULL
, NULL
, NULL
, &iosb
,
444 dwIoControlCode
, lpvInBuffer
, cbInBuffer
,
445 lpvOutBuffer
, cbOutBuffer
);
447 status
= NtDeviceIoControlFile(hDevice
, NULL
, NULL
, NULL
, &iosb
,
448 dwIoControlCode
, lpvInBuffer
, cbInBuffer
,
449 lpvOutBuffer
, cbOutBuffer
);
450 if (lpcbBytesReturned
) *lpcbBytesReturned
= iosb
.Information
;
452 return set_ntstatus( status
);
456 /***********************************************************************
457 * OpenFile (KERNEL32.@)
459 HFILE WINAPI
OpenFile( LPCSTR name
, OFSTRUCT
*ofs
, UINT mode
)
463 WORD filedatetime
[2];
466 if (!ofs
) return HFILE_ERROR
;
468 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name
,
469 ((mode
& 0x3 )==OF_READ
)?"OF_READ":
470 ((mode
& 0x3 )==OF_WRITE
)?"OF_WRITE":
471 ((mode
& 0x3 )==OF_READWRITE
)?"OF_READWRITE":"unknown",
472 ((mode
& 0x70 )==OF_SHARE_COMPAT
)?"OF_SHARE_COMPAT":
473 ((mode
& 0x70 )==OF_SHARE_DENY_NONE
)?"OF_SHARE_DENY_NONE":
474 ((mode
& 0x70 )==OF_SHARE_DENY_READ
)?"OF_SHARE_DENY_READ":
475 ((mode
& 0x70 )==OF_SHARE_DENY_WRITE
)?"OF_SHARE_DENY_WRITE":
476 ((mode
& 0x70 )==OF_SHARE_EXCLUSIVE
)?"OF_SHARE_EXCLUSIVE":"unknown",
477 ((mode
& OF_PARSE
)==OF_PARSE
)?"OF_PARSE ":"",
478 ((mode
& OF_DELETE
)==OF_DELETE
)?"OF_DELETE ":"",
479 ((mode
& OF_VERIFY
)==OF_VERIFY
)?"OF_VERIFY ":"",
480 ((mode
& OF_SEARCH
)==OF_SEARCH
)?"OF_SEARCH ":"",
481 ((mode
& OF_CANCEL
)==OF_CANCEL
)?"OF_CANCEL ":"",
482 ((mode
& OF_CREATE
)==OF_CREATE
)?"OF_CREATE ":"",
483 ((mode
& OF_PROMPT
)==OF_PROMPT
)?"OF_PROMPT ":"",
484 ((mode
& OF_EXIST
)==OF_EXIST
)?"OF_EXIST ":"",
485 ((mode
& OF_REOPEN
)==OF_REOPEN
)?"OF_REOPEN ":""
489 ofs
->cBytes
= sizeof(OFSTRUCT
);
491 if (mode
& OF_REOPEN
) name
= ofs
->szPathName
;
493 if (!name
) return HFILE_ERROR
;
495 TRACE("%s %04x\n", name
, mode
);
497 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
498 Are there any cases where getting the path here is wrong?
499 Uwe Bonnes 1997 Apr 2 */
500 len
= GetFullPathNameA( name
, sizeof(ofs
->szPathName
), ofs
->szPathName
, NULL
);
501 if (!len
) goto error
;
502 if (len
>= sizeof(ofs
->szPathName
))
504 SetLastError(ERROR_INVALID_DATA
);
508 /* OF_PARSE simply fills the structure */
512 ofs
->fFixedDisk
= (GetDriveTypeA( ofs
->szPathName
) != DRIVE_REMOVABLE
);
513 TRACE("(%s): OF_PARSE, res = '%s'\n", name
, ofs
->szPathName
);
517 /* OF_CREATE is completely different from all other options, so
520 if (mode
& OF_CREATE
)
522 if ((handle
= create_file_OF( name
, mode
)) == INVALID_HANDLE_VALUE
)
527 /* Now look for the file */
529 len
= SearchPathA( NULL
, name
, NULL
, sizeof(ofs
->szPathName
), ofs
->szPathName
, NULL
);
530 if (!len
) goto error
;
531 if (len
>= sizeof(ofs
->szPathName
))
533 SetLastError(ERROR_INVALID_DATA
);
537 TRACE("found %s\n", debugstr_a(ofs
->szPathName
) );
539 if (mode
& OF_DELETE
)
541 if (!DeleteFileA( ofs
->szPathName
)) goto error
;
542 TRACE("(%s): OF_DELETE return = OK\n", name
);
546 handle
= LongToHandle(_lopen( ofs
->szPathName
, mode
));
547 if (handle
== INVALID_HANDLE_VALUE
) goto error
;
549 GetFileTime( handle
, NULL
, NULL
, &filetime
);
550 FileTimeToDosDateTime( &filetime
, &filedatetime
[0], &filedatetime
[1] );
551 if ((mode
& OF_VERIFY
) && (mode
& OF_REOPEN
))
553 if (ofs
->Reserved1
!= filedatetime
[0] || ofs
->Reserved2
!= filedatetime
[1] )
555 CloseHandle( handle
);
556 WARN("(%s): OF_VERIFY failed\n", name
);
557 /* FIXME: what error here? */
558 SetLastError( ERROR_FILE_NOT_FOUND
);
562 ofs
->Reserved1
= filedatetime
[0];
563 ofs
->Reserved2
= filedatetime
[1];
565 TRACE("(%s): OK, return = %p\n", name
, handle
);
566 if (mode
& OF_EXIST
) /* Return TRUE instead of a handle */
568 CloseHandle( handle
);
571 return HandleToLong(handle
);
573 error
: /* We get here if there was an error opening the file */
574 ofs
->nErrCode
= GetLastError();
575 WARN("(%s): return = HFILE_ERROR error= %d\n", name
,ofs
->nErrCode
);