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
29 #define WIN32_NO_STATUS
35 #include "ddk/ntddk.h"
36 #include "kernel_private.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(file
);
44 /***********************************************************************
47 * Wrapper for CreateFile that takes OF_* mode flags.
49 static HANDLE
create_file_OF( LPCSTR path
, INT mode
)
51 DWORD access
, sharing
, creation
;
55 creation
= CREATE_ALWAYS
;
56 access
= GENERIC_READ
| GENERIC_WRITE
;
60 creation
= OPEN_EXISTING
;
63 case OF_READ
: access
= GENERIC_READ
; break;
64 case OF_WRITE
: access
= GENERIC_WRITE
; break;
65 case OF_READWRITE
: access
= GENERIC_READ
| GENERIC_WRITE
; break;
66 default: access
= 0; break;
72 case OF_SHARE_EXCLUSIVE
: sharing
= 0; break;
73 case OF_SHARE_DENY_WRITE
: sharing
= FILE_SHARE_READ
; break;
74 case OF_SHARE_DENY_READ
: sharing
= FILE_SHARE_WRITE
; break;
75 case OF_SHARE_DENY_NONE
:
77 default: sharing
= FILE_SHARE_READ
| FILE_SHARE_WRITE
; break;
79 return CreateFileA( path
, access
, sharing
, NULL
, creation
, FILE_ATTRIBUTE_NORMAL
, 0 );
83 /***********************************************************************
86 * Convert a file name to Unicode, taking into account the OEM/Ansi API mode.
88 * If alloc is FALSE uses the TEB static buffer, so it can only be used when
89 * there is no possibility for the function to do that twice, taking into
90 * account any called function.
92 WCHAR
*FILE_name_AtoW( LPCSTR name
, BOOL alloc
)
95 UNICODE_STRING strW
, *pstrW
;
98 RtlInitAnsiString( &str
, name
);
99 pstrW
= alloc
? &strW
: &NtCurrentTeb()->StaticUnicodeString
;
100 if (!AreFileApisANSI())
101 status
= RtlOemStringToUnicodeString( pstrW
, &str
, alloc
);
103 status
= RtlAnsiStringToUnicodeString( pstrW
, &str
, alloc
);
104 if (status
== STATUS_SUCCESS
) return pstrW
->Buffer
;
106 if (status
== STATUS_BUFFER_OVERFLOW
)
107 SetLastError( ERROR_FILENAME_EXCED_RANGE
);
109 SetLastError( RtlNtStatusToDosError(status
) );
114 /***********************************************************************
117 * Convert a file name back to OEM/Ansi. Returns number of bytes copied.
119 DWORD
FILE_name_WtoA( LPCWSTR src
, INT srclen
, LPSTR dest
, INT destlen
)
123 if (srclen
< 0) srclen
= lstrlenW( src
) + 1;
126 if (!AreFileApisANSI())
129 strW
.Buffer
= (WCHAR
*)src
;
130 strW
.Length
= srclen
* sizeof(WCHAR
);
131 ret
= RtlUnicodeStringToOemSize( &strW
) - 1;
134 RtlUnicodeToMultiByteSize( &ret
, src
, srclen
* sizeof(WCHAR
) );
138 if (!AreFileApisANSI())
139 RtlUnicodeToOemN( dest
, destlen
, &ret
, src
, srclen
* sizeof(WCHAR
) );
141 RtlUnicodeToMultiByteN( dest
, destlen
, &ret
, src
, srclen
* sizeof(WCHAR
) );
147 /***********************************************************************
148 * _hread (KERNEL32.@)
150 LONG WINAPI
_hread( HFILE hFile
, LPVOID buffer
, LONG count
)
152 return _lread( hFile
, buffer
, count
);
156 /***********************************************************************
157 * _hwrite (KERNEL32.@)
159 * experimentation yields that _lwrite:
160 * o truncates the file at the current position with
162 * o returns 0 on a 0 length write
163 * o works with console handles
166 LONG WINAPI
_hwrite( HFILE handle
, LPCSTR buffer
, LONG count
)
170 TRACE("%d %p %ld\n", handle
, buffer
, count
);
174 /* Expand or truncate at current position */
175 if (!SetEndOfFile( LongToHandle(handle
) )) return HFILE_ERROR
;
178 if (!WriteFile( LongToHandle(handle
), buffer
, count
, &result
, NULL
))
184 /***********************************************************************
185 * _lclose (KERNEL32.@)
187 HFILE WINAPI
_lclose( HFILE hFile
)
189 TRACE("handle %d\n", hFile
);
190 return CloseHandle( LongToHandle(hFile
) ) ? 0 : HFILE_ERROR
;
194 /***********************************************************************
195 * _lcreat (KERNEL32.@)
197 HFILE WINAPI
_lcreat( LPCSTR path
, INT attr
)
201 /* Mask off all flags not explicitly allowed by the doc */
202 attr
&= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_SYSTEM
;
203 TRACE("%s %02x\n", path
, attr
);
204 hfile
= CreateFileA( path
, GENERIC_READ
| GENERIC_WRITE
,
205 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
206 CREATE_ALWAYS
, attr
, 0 );
207 return HandleToLong(hfile
);
211 /***********************************************************************
212 * _lopen (KERNEL32.@)
214 HFILE WINAPI
_lopen( LPCSTR path
, INT mode
)
218 TRACE("(%s,%04x)\n", debugstr_a(path
), mode
);
219 hfile
= create_file_OF( path
, mode
& ~OF_CREATE
);
220 return HandleToLong(hfile
);
223 /***********************************************************************
224 * _lread (KERNEL32.@)
226 UINT WINAPI
_lread( HFILE handle
, LPVOID buffer
, UINT count
)
229 if (!ReadFile( LongToHandle(handle
), buffer
, count
, &result
, NULL
))
235 /***********************************************************************
236 * _llseek (KERNEL32.@)
238 LONG WINAPI
_llseek( HFILE hFile
, LONG lOffset
, INT nOrigin
)
240 return SetFilePointer( LongToHandle(hFile
), lOffset
, NULL
, nOrigin
);
244 /***********************************************************************
245 * _lwrite (KERNEL32.@)
247 UINT WINAPI
_lwrite( HFILE hFile
, LPCSTR buffer
, UINT count
)
249 return (UINT
)_hwrite( hFile
, buffer
, (LONG
)count
);
253 /**************************************************************************
254 * SetFileCompletionNotificationModes (KERNEL32.@)
256 BOOL WINAPI
SetFileCompletionNotificationModes( HANDLE file
, UCHAR flags
)
258 FILE_IO_COMPLETION_NOTIFICATION_INFORMATION info
;
262 return set_ntstatus( NtSetInformationFile( file
, &io
, &info
, sizeof(info
),
263 FileIoCompletionNotificationInformation
));
267 /*************************************************************************
268 * SetHandleCount (KERNEL32.@)
270 UINT WINAPI
SetHandleCount( UINT count
)
276 /***********************************************************************
277 * DosDateTimeToFileTime (KERNEL32.@)
279 BOOL WINAPI
DosDateTimeToFileTime( WORD fatdate
, WORD fattime
, FILETIME
*ft
)
284 fields
.Year
= (fatdate
>> 9) + 1980;
285 fields
.Month
= ((fatdate
>> 5) & 0x0f);
286 fields
.Day
= (fatdate
& 0x1f);
287 fields
.Hour
= (fattime
>> 11);
288 fields
.Minute
= (fattime
>> 5) & 0x3f;
289 fields
.Second
= (fattime
& 0x1f) * 2;
290 fields
.Milliseconds
= 0;
291 if (!RtlTimeFieldsToTime( &fields
, &time
)) return FALSE
;
292 ft
->dwLowDateTime
= time
.u
.LowPart
;
293 ft
->dwHighDateTime
= time
.u
.HighPart
;
298 /***********************************************************************
299 * FileTimeToDosDateTime (KERNEL32.@)
301 BOOL WINAPI
FileTimeToDosDateTime( const FILETIME
*ft
, WORD
*fatdate
, WORD
*fattime
)
306 if (!fatdate
|| !fattime
)
308 SetLastError( ERROR_INVALID_PARAMETER
);
311 time
.u
.LowPart
= ft
->dwLowDateTime
;
312 time
.u
.HighPart
= ft
->dwHighDateTime
;
313 RtlTimeToTimeFields( &time
, &fields
);
314 if (fields
.Year
< 1980)
316 SetLastError( ERROR_INVALID_PARAMETER
);
319 *fattime
= (fields
.Hour
<< 11) + (fields
.Minute
<< 5) + (fields
.Second
/ 2);
320 *fatdate
= ((fields
.Year
- 1980) << 9) + (fields
.Month
<< 5) + fields
.Day
;
325 /**************************************************************************
326 * Operations on file names *
327 **************************************************************************/
330 /**************************************************************************
331 * ReplaceFileA (KERNEL32.@)
333 BOOL WINAPI
ReplaceFileA(LPCSTR lpReplacedFileName
,LPCSTR lpReplacementFileName
,
334 LPCSTR lpBackupFileName
, DWORD dwReplaceFlags
,
335 LPVOID lpExclude
, LPVOID lpReserved
)
337 WCHAR
*replacedW
, *replacementW
, *backupW
= NULL
;
340 /* This function only makes sense when the first two parameters are defined */
341 if (!lpReplacedFileName
|| !(replacedW
= FILE_name_AtoW( lpReplacedFileName
, TRUE
)))
343 SetLastError(ERROR_INVALID_PARAMETER
);
346 if (!lpReplacementFileName
|| !(replacementW
= FILE_name_AtoW( lpReplacementFileName
, TRUE
)))
348 HeapFree( GetProcessHeap(), 0, replacedW
);
349 SetLastError(ERROR_INVALID_PARAMETER
);
352 /* The backup parameter, however, is optional */
353 if (lpBackupFileName
)
355 if (!(backupW
= FILE_name_AtoW( lpBackupFileName
, TRUE
)))
357 HeapFree( GetProcessHeap(), 0, replacedW
);
358 HeapFree( GetProcessHeap(), 0, replacementW
);
359 SetLastError(ERROR_INVALID_PARAMETER
);
363 ret
= ReplaceFileW( replacedW
, replacementW
, backupW
, dwReplaceFlags
, lpExclude
, lpReserved
);
364 HeapFree( GetProcessHeap(), 0, replacedW
);
365 HeapFree( GetProcessHeap(), 0, replacementW
);
366 HeapFree( GetProcessHeap(), 0, backupW
);
371 /***********************************************************************
372 * OpenVxDHandle (KERNEL32.@)
374 * This function is supposed to return the corresponding Ring 0
375 * ("kernel") handle for a Ring 3 handle in Win9x.
376 * Evidently, Wine will have problems with this. But we try anyway,
379 HANDLE WINAPI
OpenVxDHandle(HANDLE hHandleRing3
)
381 FIXME( "(%p), stub! (returning Ring 3 handle instead of Ring 0)\n", hHandleRing3
);
386 /****************************************************************************
387 * DeviceIoControl (KERNEL32.@)
389 BOOL WINAPI
KERNEL32_DeviceIoControl( HANDLE handle
, DWORD code
, void *in_buff
, DWORD in_count
,
390 void *out_buff
, DWORD out_count
, DWORD
*returned
,
391 OVERLAPPED
*overlapped
)
393 TRACE( "(%p,%#lx,%p,%ld,%p,%ld,%p,%p)\n",
394 handle
, code
, in_buff
, in_count
, out_buff
, out_count
, returned
, overlapped
);
396 /* Check if this is a user defined control code for a VxD */
398 if (HIWORD( code
) == 0 && (GetVersion() & 0x80000000))
400 typedef BOOL (WINAPI
*DeviceIoProc
)(DWORD
, LPVOID
, DWORD
, LPVOID
, DWORD
, LPDWORD
, LPOVERLAPPED
);
401 static DeviceIoProc (*vxd_get_proc
)(HANDLE
);
402 DeviceIoProc proc
= NULL
;
404 if (!vxd_get_proc
) vxd_get_proc
= (void *)GetProcAddress( GetModuleHandleW(L
"krnl386.exe16"),
405 "__wine_vxd_get_proc" );
406 if (vxd_get_proc
) proc
= vxd_get_proc( handle
);
407 if (proc
) return proc( code
, in_buff
, in_count
, out_buff
, out_count
, returned
, overlapped
);
410 return DeviceIoControl( handle
, code
, in_buff
, in_count
, out_buff
, out_count
, returned
, overlapped
);
414 /***********************************************************************
415 * OpenFile (KERNEL32.@)
417 HFILE WINAPI
OpenFile( LPCSTR name
, OFSTRUCT
*ofs
, UINT mode
)
421 WORD filedatetime
[2];
424 if (!ofs
) return HFILE_ERROR
;
426 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name
,
427 ((mode
& 0x3 )==OF_READ
)?"OF_READ":
428 ((mode
& 0x3 )==OF_WRITE
)?"OF_WRITE":
429 ((mode
& 0x3 )==OF_READWRITE
)?"OF_READWRITE":"unknown",
430 ((mode
& 0x70 )==OF_SHARE_COMPAT
)?"OF_SHARE_COMPAT":
431 ((mode
& 0x70 )==OF_SHARE_DENY_NONE
)?"OF_SHARE_DENY_NONE":
432 ((mode
& 0x70 )==OF_SHARE_DENY_READ
)?"OF_SHARE_DENY_READ":
433 ((mode
& 0x70 )==OF_SHARE_DENY_WRITE
)?"OF_SHARE_DENY_WRITE":
434 ((mode
& 0x70 )==OF_SHARE_EXCLUSIVE
)?"OF_SHARE_EXCLUSIVE":"unknown",
435 ((mode
& OF_PARSE
)==OF_PARSE
)?"OF_PARSE ":"",
436 ((mode
& OF_DELETE
)==OF_DELETE
)?"OF_DELETE ":"",
437 ((mode
& OF_VERIFY
)==OF_VERIFY
)?"OF_VERIFY ":"",
438 ((mode
& OF_SEARCH
)==OF_SEARCH
)?"OF_SEARCH ":"",
439 ((mode
& OF_CANCEL
)==OF_CANCEL
)?"OF_CANCEL ":"",
440 ((mode
& OF_CREATE
)==OF_CREATE
)?"OF_CREATE ":"",
441 ((mode
& OF_PROMPT
)==OF_PROMPT
)?"OF_PROMPT ":"",
442 ((mode
& OF_EXIST
)==OF_EXIST
)?"OF_EXIST ":"",
443 ((mode
& OF_REOPEN
)==OF_REOPEN
)?"OF_REOPEN ":""
447 ofs
->cBytes
= sizeof(OFSTRUCT
);
449 if (mode
& OF_REOPEN
) name
= ofs
->szPathName
;
451 if (!name
) return HFILE_ERROR
;
453 TRACE("%s %04x\n", name
, mode
);
455 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
456 Are there any cases where getting the path here is wrong?
457 Uwe Bonnes 1997 Apr 2 */
458 len
= GetFullPathNameA( name
, sizeof(ofs
->szPathName
), ofs
->szPathName
, NULL
);
459 if (!len
) goto error
;
460 if (len
>= sizeof(ofs
->szPathName
))
462 SetLastError(ERROR_INVALID_DATA
);
466 /* OF_PARSE simply fills the structure */
470 ofs
->fFixedDisk
= (GetDriveTypeA( ofs
->szPathName
) != DRIVE_REMOVABLE
);
471 TRACE("(%s): OF_PARSE, res = '%s'\n", name
, ofs
->szPathName
);
475 /* OF_CREATE is completely different from all other options, so
478 if (mode
& OF_CREATE
)
480 if ((handle
= create_file_OF( name
, mode
)) == INVALID_HANDLE_VALUE
)
485 /* Now look for the file */
487 len
= SearchPathA( NULL
, name
, NULL
, sizeof(ofs
->szPathName
), ofs
->szPathName
, NULL
);
488 if (!len
) goto error
;
489 if (len
>= sizeof(ofs
->szPathName
))
491 SetLastError(ERROR_INVALID_DATA
);
495 TRACE("found %s\n", debugstr_a(ofs
->szPathName
) );
497 if (mode
& OF_DELETE
)
499 if (!DeleteFileA( ofs
->szPathName
)) goto error
;
500 TRACE("(%s): OF_DELETE return = OK\n", name
);
504 handle
= LongToHandle(_lopen( ofs
->szPathName
, mode
));
505 if (handle
== INVALID_HANDLE_VALUE
) goto error
;
507 GetFileTime( handle
, NULL
, NULL
, &filetime
);
508 FileTimeToDosDateTime( &filetime
, &filedatetime
[0], &filedatetime
[1] );
509 if ((mode
& OF_VERIFY
) && (mode
& OF_REOPEN
))
511 if (ofs
->Reserved1
!= filedatetime
[0] || ofs
->Reserved2
!= filedatetime
[1] )
513 CloseHandle( handle
);
514 WARN("(%s): OF_VERIFY failed\n", name
);
515 /* FIXME: what error here? */
516 SetLastError( ERROR_FILE_NOT_FOUND
);
520 ofs
->Reserved1
= filedatetime
[0];
521 ofs
->Reserved2
= filedatetime
[1];
523 TRACE("(%s): OK, return = %p\n", name
, handle
);
524 if (mode
& OF_EXIST
) /* Return TRUE instead of a handle */
526 CloseHandle( handle
);
529 return HandleToLong(handle
);
531 error
: /* We get here if there was an error opening the file */
532 ofs
->nErrCode
= GetLastError();
533 WARN("(%s): return = HFILE_ERROR error= %d\n", name
,ofs
->nErrCode
);