amstream: Implement AMAudioStream::NewSegment.
[wine/zf.git] / dlls / kernel32 / file.c
blob29dd5791af41086f0a8f6b046a32d2bf09dac9cd
1 /*
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
23 #include "config.h"
24 #include "wine/port.h"
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <errno.h>
29 #ifdef HAVE_SYS_STAT_H
30 # include <sys/stat.h>
31 #endif
33 #define NONAMELESSUNION
34 #define NONAMELESSSTRUCT
35 #include "winerror.h"
36 #include "ntstatus.h"
37 #define WIN32_NO_STATUS
38 #include "windef.h"
39 #include "winbase.h"
40 #include "winternl.h"
41 #include "winioctl.h"
42 #include "wincon.h"
43 #include "ddk/ntddk.h"
44 #include "kernel_private.h"
45 #include "fileapi.h"
46 #include "shlwapi.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 /***********************************************************************
57 * create_file_OF
59 * Wrapper for CreateFile that takes OF_* mode flags.
61 static HANDLE create_file_OF( LPCSTR path, INT mode )
63 DWORD access, sharing, creation;
65 if (mode & OF_CREATE)
67 creation = CREATE_ALWAYS;
68 access = GENERIC_READ | GENERIC_WRITE;
70 else
72 creation = OPEN_EXISTING;
73 switch(mode & 0x03)
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;
82 switch(mode & 0x70)
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:
88 case OF_SHARE_COMPAT:
89 default: sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
91 return CreateFileA( path, access, sharing, NULL, creation, FILE_ATTRIBUTE_NORMAL, 0 );
95 /***********************************************************************
96 * FILE_SetDosError
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));
105 switch (save_errno)
107 case EAGAIN:
108 SetLastError( ERROR_SHARING_VIOLATION );
109 break;
110 case EBADF:
111 SetLastError( ERROR_INVALID_HANDLE );
112 break;
113 case ENOSPC:
114 SetLastError( ERROR_HANDLE_DISK_FULL );
115 break;
116 case EACCES:
117 case EPERM:
118 case EROFS:
119 SetLastError( ERROR_ACCESS_DENIED );
120 break;
121 case EBUSY:
122 SetLastError( ERROR_LOCK_VIOLATION );
123 break;
124 case ENOENT:
125 SetLastError( ERROR_FILE_NOT_FOUND );
126 break;
127 case EISDIR:
128 SetLastError( ERROR_CANNOT_MAKE );
129 break;
130 case ENFILE:
131 case EMFILE:
132 SetLastError( ERROR_TOO_MANY_OPEN_FILES );
133 break;
134 case EEXIST:
135 SetLastError( ERROR_FILE_EXISTS );
136 break;
137 case EINVAL:
138 case ESPIPE:
139 SetLastError( ERROR_SEEK );
140 break;
141 case ENOTEMPTY:
142 SetLastError( ERROR_DIR_NOT_EMPTY );
143 break;
144 case ENOEXEC:
145 SetLastError( ERROR_BAD_FORMAT );
146 break;
147 case ENOTDIR:
148 SetLastError( ERROR_PATH_NOT_FOUND );
149 break;
150 case EXDEV:
151 SetLastError( ERROR_NOT_SAME_DEVICE );
152 break;
153 default:
154 WARN("unknown file error: %s\n", strerror(save_errno) );
155 SetLastError( ERROR_GEN_FAILURE );
156 break;
158 errno = save_errno;
162 /***********************************************************************
163 * FILE_name_AtoW
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 )
173 ANSI_STRING str;
174 UNICODE_STRING strW, *pstrW;
175 NTSTATUS status;
177 RtlInitAnsiString( &str, name );
178 pstrW = alloc ? &strW : &NtCurrentTeb()->StaticUnicodeString;
179 if (!AreFileApisANSI())
180 status = RtlOemStringToUnicodeString( pstrW, &str, alloc );
181 else
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 );
187 else
188 SetLastError( RtlNtStatusToDosError(status) );
189 return NULL;
193 /***********************************************************************
194 * FILE_name_WtoA
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 )
200 DWORD ret;
202 if (srclen < 0) srclen = strlenW( src ) + 1;
203 if (!destlen)
205 if (!AreFileApisANSI())
207 UNICODE_STRING strW;
208 strW.Buffer = (WCHAR *)src;
209 strW.Length = srclen * sizeof(WCHAR);
210 ret = RtlUnicodeStringToOemSize( &strW ) - 1;
212 else
213 RtlUnicodeToMultiByteSize( &ret, src, srclen * sizeof(WCHAR) );
215 else
217 if (!AreFileApisANSI())
218 RtlUnicodeToOemN( dest, destlen, &ret, src, srclen * sizeof(WCHAR) );
219 else
220 RtlUnicodeToMultiByteN( dest, destlen, &ret, src, srclen * sizeof(WCHAR) );
222 return ret;
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
240 * a 0 len write
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 )
247 DWORD result;
249 TRACE("%d %p %d\n", handle, buffer, count );
251 if (!count)
253 /* Expand or truncate at current position */
254 if (!SetEndOfFile( LongToHandle(handle) )) return HFILE_ERROR;
255 return 0;
257 if (!WriteFile( LongToHandle(handle), buffer, count, &result, NULL ))
258 return HFILE_ERROR;
259 return result;
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 )
278 HANDLE hfile;
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 )
295 HANDLE hfile;
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 )
307 DWORD result;
308 if (!ReadFile( LongToHandle(handle), buffer, count, &result, NULL ))
309 return HFILE_ERROR;
310 return result;
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;
338 IO_STATUS_BLOCK io;
340 info.Flags = flags;
341 return set_ntstatus( NtSetInformationFile( file, &io, &info, sizeof(info),
342 FileIoCompletionNotificationInformation ));
346 /*************************************************************************
347 * SetHandleCount (KERNEL32.@)
349 UINT WINAPI SetHandleCount( UINT count )
351 return 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 ))
365 DWORD conread, mode;
367 if (!ReadConsoleA( file, buffer, count, &conread, NULL) || !GetConsoleMode( file, &mode ))
368 return FALSE;
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))
376 conread = 0;
378 if (result) *result = conread;
379 return TRUE;
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 )
415 TIME_FIELDS fields;
416 LARGE_INTEGER time;
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;
428 return TRUE;
432 /***********************************************************************
433 * FileTimeToDosDateTime (KERNEL32.@)
435 BOOL WINAPI FileTimeToDosDateTime( const FILETIME *ft, WORD *fatdate, WORD *fattime )
437 TIME_FIELDS fields;
438 LARGE_INTEGER time;
440 if (!fatdate || !fattime)
442 SetLastError( ERROR_INVALID_PARAMETER );
443 return FALSE;
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 );
451 return FALSE;
453 *fattime = (fields.Hour << 11) + (fields.Minute << 5) + (fields.Second / 2);
454 *fatdate = ((fields.Year - 1980) << 9) + (fields.Month << 5) + fields.Day;
455 return TRUE;
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;
472 BOOL ret;
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);
478 return FALSE;
480 if (!lpReplacementFileName || !(replacementW = FILE_name_AtoW( lpReplacementFileName, TRUE )))
482 HeapFree( GetProcessHeap(), 0, replacedW );
483 SetLastError(ERROR_INVALID_PARAMETER);
484 return FALSE;
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);
494 return FALSE;
497 ret = ReplaceFileW( replacedW, replacementW, backupW, dwReplaceFlags, lpExclude, lpReserved );
498 HeapFree( GetProcessHeap(), 0, replacedW );
499 HeapFree( GetProcessHeap(), 0, replacementW );
500 HeapFree( GetProcessHeap(), 0, backupW );
501 return ret;
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,
511 * maybe it helps...
513 HANDLE WINAPI OpenVxDHandle(HANDLE hHandleRing3)
515 FIXME( "(%p), stub! (returning Ring 3 handle instead of Ring 0)\n", hHandleRing3);
516 return 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)
529 NTSTATUS status;
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 */
552 if (lpOverlapped)
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);
562 else
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;
569 else
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);
577 else
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 )
592 HANDLE handle;
593 FILETIME filetime;
594 WORD filedatetime[2];
595 DWORD len;
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);
621 ofs->nErrCode = 0;
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);
636 goto error;
639 /* OF_PARSE simply fills the structure */
641 if (mode & OF_PARSE)
643 ofs->fFixedDisk = (GetDriveTypeA( ofs->szPathName ) != DRIVE_REMOVABLE);
644 TRACE("(%s): OF_PARSE, res = '%s'\n", name, ofs->szPathName );
645 return 0;
648 /* OF_CREATE is completely different from all other options, so
649 handle it first */
651 if (mode & OF_CREATE)
653 if ((handle = create_file_OF( name, mode )) == INVALID_HANDLE_VALUE)
654 goto error;
656 else
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);
665 goto error;
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);
674 return TRUE;
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 );
690 goto error;
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 );
700 return TRUE;
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 );
707 return HFILE_ERROR;