2 * File handling functions
4 * Copyright 1993 John Burton
5 * Copyright 1996 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * Fix the CopyFileEx methods to implement the "extended" functionality.
23 * Right now, they simply call the CopyFile method.
27 #include "wine/port.h"
31 #define NONAMELESSUNION
32 #define NONAMELESSSTRUCT
40 #include "wine/winbase16.h"
41 #include "kernel_private.h"
43 #include "wine/exception.h"
45 #include "wine/unicode.h"
46 #include "wine/debug.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(file
);
51 HANDLE dos_handles
[DOS_TABLE_SIZE
];
53 /* info structure for FindFirstFile handle */
56 HANDLE handle
; /* handle to directory */
57 CRITICAL_SECTION cs
; /* crit section protecting this structure */
58 UNICODE_STRING mask
; /* file mask */
59 BOOL is_root
; /* is directory the root of the drive? */
60 UINT data_pos
; /* current position in dir data */
61 UINT data_len
; /* length of dir data */
62 BYTE data
[8192]; /* directory data */
66 static WINE_EXCEPTION_FILTER(page_fault
)
68 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION
)
69 return EXCEPTION_EXECUTE_HANDLER
;
70 return EXCEPTION_CONTINUE_SEARCH
;
73 /**************************************************************************
74 * Operations on file handles *
75 **************************************************************************/
77 /***********************************************************************
78 * FILE_InitProcessDosHandles
80 * Allocates the default DOS handles for a process. Called either by
81 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
83 static void FILE_InitProcessDosHandles( void )
85 static BOOL init_done
/* = FALSE */;
86 HANDLE cp
= GetCurrentProcess();
88 if (init_done
) return;
90 DuplicateHandle(cp
, GetStdHandle(STD_INPUT_HANDLE
), cp
, &dos_handles
[0],
91 0, TRUE
, DUPLICATE_SAME_ACCESS
);
92 DuplicateHandle(cp
, GetStdHandle(STD_OUTPUT_HANDLE
), cp
, &dos_handles
[1],
93 0, TRUE
, DUPLICATE_SAME_ACCESS
);
94 DuplicateHandle(cp
, GetStdHandle(STD_ERROR_HANDLE
), cp
, &dos_handles
[2],
95 0, TRUE
, DUPLICATE_SAME_ACCESS
);
96 DuplicateHandle(cp
, GetStdHandle(STD_ERROR_HANDLE
), cp
, &dos_handles
[3],
97 0, TRUE
, DUPLICATE_SAME_ACCESS
);
98 DuplicateHandle(cp
, GetStdHandle(STD_ERROR_HANDLE
), cp
, &dos_handles
[4],
99 0, TRUE
, DUPLICATE_SAME_ACCESS
);
103 /***********************************************************************
104 * GetOverlappedResult (KERNEL32.@)
106 * Check the result of an Asynchronous data transfer from a file.
109 * HANDLE hFile [in] handle of file to check on
110 * LPOVERLAPPED lpOverlapped [in/out] pointer to overlapped
111 * LPDWORD lpTransferred [in/out] number of bytes transferred
112 * BOOL bWait [in] wait for the transfer to complete ?
118 * If successful (and relevant) lpTransferred will hold the number of
119 * bytes transferred during the async operation.
123 * Currently only works for WaitCommEvent, ReadFile, WriteFile
124 * with communications ports.
127 BOOL WINAPI
GetOverlappedResult(HANDLE hFile
, LPOVERLAPPED lpOverlapped
,
128 LPDWORD lpTransferred
, BOOL bWait
)
132 TRACE("(%p %p %p %x)\n", hFile
, lpOverlapped
, lpTransferred
, bWait
);
134 if (lpOverlapped
==NULL
)
136 ERR("lpOverlapped was null\n");
139 if (!lpOverlapped
->hEvent
)
141 ERR("lpOverlapped->hEvent was null\n");
148 TRACE("waiting on %p\n",lpOverlapped
);
149 r
= WaitForSingleObjectEx(lpOverlapped
->hEvent
, INFINITE
, TRUE
);
150 TRACE("wait on %p returned %ld\n",lpOverlapped
,r
);
151 } while (r
==STATUS_USER_APC
);
153 else if ( lpOverlapped
->Internal
== STATUS_PENDING
)
155 /* Wait in order to give APCs a chance to run. */
156 /* This is cheating, so we must set the event again in case of success -
157 it may be a non-manual reset event. */
159 TRACE("waiting on %p\n",lpOverlapped
);
160 r
= WaitForSingleObjectEx(lpOverlapped
->hEvent
, 0, TRUE
);
161 TRACE("wait on %p returned %ld\n",lpOverlapped
,r
);
162 } while (r
==STATUS_USER_APC
);
163 if ( r
== WAIT_OBJECT_0
)
164 NtSetEvent ( lpOverlapped
->hEvent
, NULL
);
168 *lpTransferred
= lpOverlapped
->InternalHigh
;
170 switch ( lpOverlapped
->Internal
)
175 SetLastError ( ERROR_IO_INCOMPLETE
);
176 if ( bWait
) ERR ("PENDING status after waiting!\n");
179 SetLastError ( RtlNtStatusToDosError ( lpOverlapped
->Internal
) );
184 /***********************************************************************
185 * CancelIo (KERNEL32.@)
187 BOOL WINAPI
CancelIo(HANDLE handle
)
189 async_private
*ovp
,*t
;
191 TRACE("handle = %p\n",handle
);
193 for (ovp
= NtCurrentTeb()->pending_list
; ovp
; ovp
= t
)
196 if ( ovp
->handle
== handle
)
197 cancel_async ( ovp
);
203 /***********************************************************************
204 * _hread (KERNEL32.@)
206 LONG WINAPI
_hread( HFILE hFile
, LPVOID buffer
, LONG count
)
208 return _lread( hFile
, buffer
, count
);
212 /***********************************************************************
213 * _hwrite (KERNEL32.@)
215 * experimentation yields that _lwrite:
216 * o truncates the file at the current position with
218 * o returns 0 on a 0 length write
219 * o works with console handles
222 LONG WINAPI
_hwrite( HFILE handle
, LPCSTR buffer
, LONG count
)
226 TRACE("%d %p %ld\n", handle
, buffer
, count
);
230 /* Expand or truncate at current position */
231 if (!SetEndOfFile( (HANDLE
)handle
)) return HFILE_ERROR
;
234 if (!WriteFile( (HANDLE
)handle
, buffer
, count
, &result
, NULL
))
240 /***********************************************************************
241 * _lclose (KERNEL32.@)
243 HFILE WINAPI
_lclose( HFILE hFile
)
245 TRACE("handle %d\n", hFile
);
246 return CloseHandle( (HANDLE
)hFile
) ? 0 : HFILE_ERROR
;
250 /***********************************************************************
251 * _lcreat (KERNEL32.@)
253 HFILE WINAPI
_lcreat( LPCSTR path
, INT attr
)
255 /* Mask off all flags not explicitly allowed by the doc */
256 attr
&= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_SYSTEM
;
257 TRACE("%s %02x\n", path
, attr
);
258 return (HFILE
)CreateFileA( path
, GENERIC_READ
| GENERIC_WRITE
,
259 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
260 CREATE_ALWAYS
, attr
, 0 );
264 /***********************************************************************
265 * _lopen (KERNEL32.@)
267 HFILE WINAPI
_lopen( LPCSTR path
, INT mode
)
269 DWORD access
, sharing
;
271 TRACE("('%s',%04x)\n", path
, mode
);
272 FILE_ConvertOFMode( mode
, &access
, &sharing
);
273 return (HFILE
)CreateFileA( path
, access
, sharing
, NULL
, OPEN_EXISTING
, 0, 0 );
277 /***********************************************************************
278 * _lread (KERNEL32.@)
280 UINT WINAPI
_lread( HFILE handle
, LPVOID buffer
, UINT count
)
283 if (!ReadFile( (HANDLE
)handle
, buffer
, count
, &result
, NULL
))
289 /***********************************************************************
290 * _llseek (KERNEL32.@)
292 LONG WINAPI
_llseek( HFILE hFile
, LONG lOffset
, INT nOrigin
)
294 return SetFilePointer( (HANDLE
)hFile
, lOffset
, NULL
, nOrigin
);
298 /***********************************************************************
299 * _lwrite (KERNEL32.@)
301 UINT WINAPI
_lwrite( HFILE hFile
, LPCSTR buffer
, UINT count
)
303 return (UINT
)_hwrite( hFile
, buffer
, (LONG
)count
);
307 /***********************************************************************
308 * FlushFileBuffers (KERNEL32.@)
310 BOOL WINAPI
FlushFileBuffers( HANDLE hFile
)
313 IO_STATUS_BLOCK ioblk
;
315 if (is_console_handle( hFile
))
317 /* this will fail (as expected) for an output handle */
318 /* FIXME: wait until FlushFileBuffers is moved to dll/kernel */
319 /* return FlushConsoleInputBuffer( hFile ); */
322 nts
= NtFlushBuffersFile( hFile
, &ioblk
);
323 if (nts
!= STATUS_SUCCESS
)
325 SetLastError( RtlNtStatusToDosError( nts
) );
333 /***********************************************************************
334 * GetFileSize (KERNEL32.@)
336 DWORD WINAPI
GetFileSize( HANDLE hFile
, LPDWORD filesizehigh
)
338 BY_HANDLE_FILE_INFORMATION info
;
339 if (!GetFileInformationByHandle( hFile
, &info
)) return -1;
340 if (filesizehigh
) *filesizehigh
= info
.nFileSizeHigh
;
341 return info
.nFileSizeLow
;
345 /***********************************************************************
346 * GetFileSizeEx (KERNEL32.@)
348 BOOL WINAPI
GetFileSizeEx( HANDLE hFile
, PLARGE_INTEGER lpFileSize
)
350 BY_HANDLE_FILE_INFORMATION info
;
354 SetLastError( ERROR_INVALID_PARAMETER
);
358 if (!GetFileInformationByHandle( hFile
, &info
))
363 lpFileSize
->u
.LowPart
= info
.nFileSizeLow
;
364 lpFileSize
->u
.HighPart
= info
.nFileSizeHigh
;
370 /**************************************************************************
371 * LockFile (KERNEL32.@)
373 BOOL WINAPI
LockFile( HANDLE hFile
, DWORD offset_low
, DWORD offset_high
,
374 DWORD count_low
, DWORD count_high
)
377 LARGE_INTEGER count
, offset
;
379 TRACE( "%p %lx%08lx %lx%08lx\n",
380 hFile
, offset_high
, offset_low
, count_high
, count_low
);
382 count
.u
.LowPart
= count_low
;
383 count
.u
.HighPart
= count_high
;
384 offset
.u
.LowPart
= offset_low
;
385 offset
.u
.HighPart
= offset_high
;
387 status
= NtLockFile( hFile
, 0, NULL
, NULL
,
388 NULL
, &offset
, &count
, NULL
, TRUE
, TRUE
);
390 if (status
!= STATUS_SUCCESS
) SetLastError( RtlNtStatusToDosError(status
) );
395 /**************************************************************************
396 * LockFileEx [KERNEL32.@]
398 * Locks a byte range within an open file for shared or exclusive access.
405 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
407 BOOL WINAPI
LockFileEx( HANDLE hFile
, DWORD flags
, DWORD reserved
,
408 DWORD count_low
, DWORD count_high
, LPOVERLAPPED overlapped
)
411 LARGE_INTEGER count
, offset
;
415 SetLastError( ERROR_INVALID_PARAMETER
);
419 TRACE( "%p %lx%08lx %lx%08lx flags %lx\n",
420 hFile
, overlapped
->OffsetHigh
, overlapped
->Offset
,
421 count_high
, count_low
, flags
);
423 count
.u
.LowPart
= count_low
;
424 count
.u
.HighPart
= count_high
;
425 offset
.u
.LowPart
= overlapped
->Offset
;
426 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
428 status
= NtLockFile( hFile
, overlapped
->hEvent
, NULL
, NULL
,
429 NULL
, &offset
, &count
, NULL
,
430 flags
& LOCKFILE_FAIL_IMMEDIATELY
,
431 flags
& LOCKFILE_EXCLUSIVE_LOCK
);
433 if (status
) SetLastError( RtlNtStatusToDosError(status
) );
438 /**************************************************************************
439 * UnlockFile (KERNEL32.@)
441 BOOL WINAPI
UnlockFile( HANDLE hFile
, DWORD offset_low
, DWORD offset_high
,
442 DWORD count_low
, DWORD count_high
)
445 LARGE_INTEGER count
, offset
;
447 count
.u
.LowPart
= count_low
;
448 count
.u
.HighPart
= count_high
;
449 offset
.u
.LowPart
= offset_low
;
450 offset
.u
.HighPart
= offset_high
;
452 status
= NtUnlockFile( hFile
, NULL
, &offset
, &count
, NULL
);
453 if (status
) SetLastError( RtlNtStatusToDosError(status
) );
458 /**************************************************************************
459 * UnlockFileEx (KERNEL32.@)
461 BOOL WINAPI
UnlockFileEx( HANDLE hFile
, DWORD reserved
, DWORD count_low
, DWORD count_high
,
462 LPOVERLAPPED overlapped
)
466 SetLastError( ERROR_INVALID_PARAMETER
);
469 if (overlapped
->hEvent
) FIXME("Unimplemented overlapped operation\n");
471 return UnlockFile( hFile
, overlapped
->Offset
, overlapped
->OffsetHigh
, count_low
, count_high
);
475 /***********************************************************************
476 * Win32HandleToDosFileHandle (KERNEL32.21)
478 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
479 * longer valid after this function (even on failure).
481 * Note: this is not exactly right, since on Win95 the Win32 handles
482 * are on top of DOS handles and we do it the other way
483 * around. Should be good enough though.
485 HFILE WINAPI
Win32HandleToDosFileHandle( HANDLE handle
)
489 if (!handle
|| (handle
== INVALID_HANDLE_VALUE
))
492 FILE_InitProcessDosHandles();
493 for (i
= 0; i
< DOS_TABLE_SIZE
; i
++)
496 dos_handles
[i
] = handle
;
497 TRACE("Got %d for h32 %p\n", i
, handle
);
500 CloseHandle( handle
);
501 SetLastError( ERROR_TOO_MANY_OPEN_FILES
);
506 /***********************************************************************
507 * DosFileHandleToWin32Handle (KERNEL32.20)
509 * Return the Win32 handle for a DOS handle.
511 * Note: this is not exactly right, since on Win95 the Win32 handles
512 * are on top of DOS handles and we do it the other way
513 * around. Should be good enough though.
515 HANDLE WINAPI
DosFileHandleToWin32Handle( HFILE handle
)
517 HFILE16 hfile
= (HFILE16
)handle
;
518 if (hfile
< 5) FILE_InitProcessDosHandles();
519 if ((hfile
>= DOS_TABLE_SIZE
) || !dos_handles
[hfile
])
521 SetLastError( ERROR_INVALID_HANDLE
);
522 return INVALID_HANDLE_VALUE
;
524 return dos_handles
[hfile
];
528 /***********************************************************************
529 * DisposeLZ32Handle (KERNEL32.22)
531 * Note: this is not entirely correct, we should only close the
532 * 32-bit handle and not the 16-bit one, but we cannot do
533 * this because of the way our DOS handles are implemented.
534 * It shouldn't break anything though.
536 void WINAPI
DisposeLZ32Handle( HANDLE handle
)
540 if (!handle
|| (handle
== INVALID_HANDLE_VALUE
)) return;
542 for (i
= 5; i
< DOS_TABLE_SIZE
; i
++)
543 if (dos_handles
[i
] == handle
)
546 CloseHandle( handle
);
551 /**************************************************************************
552 * Operations on file names *
553 **************************************************************************/
555 /***********************************************************************
556 * DeleteFileW (KERNEL32.@)
558 BOOL WINAPI
DeleteFileW( LPCWSTR path
)
562 TRACE("%s\n", debugstr_w(path
) );
564 hFile
= CreateFileW( path
, GENERIC_READ
| GENERIC_WRITE
,
565 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
566 NULL
, OPEN_EXISTING
, FILE_FLAG_DELETE_ON_CLOSE
, 0 );
567 if (hFile
== INVALID_HANDLE_VALUE
) return FALSE
;
569 CloseHandle(hFile
); /* last close will delete the file */
574 /***********************************************************************
575 * DeleteFileA (KERNEL32.@)
577 BOOL WINAPI
DeleteFileA( LPCSTR path
)
579 UNICODE_STRING pathW
;
582 if (RtlCreateUnicodeStringFromAsciiz(&pathW
, path
))
584 ret
= DeleteFileW(pathW
.Buffer
);
585 RtlFreeUnicodeString(&pathW
);
588 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
593 /**************************************************************************
594 * ReplaceFileW (KERNEL32.@)
595 * ReplaceFile (KERNEL32.@)
597 BOOL WINAPI
ReplaceFileW(LPCWSTR lpReplacedFileName
,LPCWSTR lpReplacementFileName
,
598 LPCWSTR lpBackupFileName
, DWORD dwReplaceFlags
,
599 LPVOID lpExclude
, LPVOID lpReserved
)
601 FIXME("(%s,%s,%s,%08lx,%p,%p) stub\n",debugstr_w(lpReplacedFileName
),debugstr_w(lpReplacementFileName
),
602 debugstr_w(lpBackupFileName
),dwReplaceFlags
,lpExclude
,lpReserved
);
603 SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT
);
608 /**************************************************************************
609 * ReplaceFileA (KERNEL32.@)
611 BOOL WINAPI
ReplaceFileA(LPCSTR lpReplacedFileName
,LPCSTR lpReplacementFileName
,
612 LPCSTR lpBackupFileName
, DWORD dwReplaceFlags
,
613 LPVOID lpExclude
, LPVOID lpReserved
)
615 FIXME("(%s,%s,%s,%08lx,%p,%p) stub\n",lpReplacedFileName
,lpReplacementFileName
,
616 lpBackupFileName
,dwReplaceFlags
,lpExclude
,lpReserved
);
617 SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT
);
622 /*************************************************************************
623 * FindFirstFileExW (KERNEL32.@)
625 HANDLE WINAPI
FindFirstFileExW( LPCWSTR filename
, FINDEX_INFO_LEVELS level
,
626 LPVOID data
, FINDEX_SEARCH_OPS search_op
,
627 LPVOID filter
, DWORD flags
)
629 WCHAR buffer
[MAX_PATH
];
630 WCHAR
*mask
, *tmp
= buffer
;
631 FIND_FIRST_INFO
*info
= NULL
;
634 if ((search_op
!= FindExSearchNameMatch
) || (flags
!= 0))
636 FIXME("options not implemented 0x%08x 0x%08lx\n", search_op
, flags
);
637 return INVALID_HANDLE_VALUE
;
639 if (level
!= FindExInfoStandard
)
641 FIXME("info level %d not implemented\n", level
);
642 return INVALID_HANDLE_VALUE
;
644 size
= RtlGetFullPathName_U( filename
, sizeof(buffer
), buffer
, &mask
);
647 SetLastError( ERROR_PATH_NOT_FOUND
);
648 return INVALID_HANDLE_VALUE
;
650 if (size
> sizeof(buffer
))
652 tmp
= HeapAlloc( GetProcessHeap(), 0, size
);
655 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
656 return INVALID_HANDLE_VALUE
;
658 size
= RtlGetFullPathName_U( filename
, size
, tmp
, &mask
);
663 SetLastError( ERROR_FILE_NOT_FOUND
);
667 if (!(info
= HeapAlloc( GetProcessHeap(), 0, sizeof(*info
))))
669 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
673 if (!RtlCreateUnicodeString( &info
->mask
, mask
))
675 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
680 /* check if path is the root of the drive */
681 info
->is_root
= FALSE
;
682 if (tmp
[0] && tmp
[1] == ':')
685 while (*p
== '\\') p
++;
686 info
->is_root
= (*p
== 0);
689 info
->handle
= CreateFileW( tmp
, GENERIC_READ
, FILE_SHARE_READ
|FILE_SHARE_WRITE
, NULL
,
690 OPEN_EXISTING
, FILE_FLAG_BACKUP_SEMANTICS
, 0 );
691 if (info
->handle
== INVALID_HANDLE_VALUE
)
693 RtlFreeUnicodeString( &info
->mask
);
697 RtlInitializeCriticalSection( &info
->cs
);
700 if (tmp
!= buffer
) HeapFree( GetProcessHeap(), 0, tmp
);
702 if (!FindNextFileW( (HANDLE
)info
, data
))
704 TRACE( "%s not found\n", debugstr_w(filename
) );
705 FindClose( (HANDLE
)info
);
706 SetLastError( ERROR_FILE_NOT_FOUND
);
707 return INVALID_HANDLE_VALUE
;
712 if (tmp
!= buffer
) HeapFree( GetProcessHeap(), 0, tmp
);
713 if (info
) HeapFree( GetProcessHeap(), 0, info
);
714 return INVALID_HANDLE_VALUE
;
718 /*************************************************************************
719 * FindNextFileW (KERNEL32.@)
721 BOOL WINAPI
FindNextFileW( HANDLE handle
, WIN32_FIND_DATAW
*data
)
723 FIND_FIRST_INFO
*info
;
724 FILE_BOTH_DIR_INFORMATION
*dir_info
;
727 if (handle
== INVALID_HANDLE_VALUE
)
729 SetLastError( ERROR_INVALID_HANDLE
);
732 info
= (FIND_FIRST_INFO
*)handle
;
734 RtlEnterCriticalSection( &info
->cs
);
738 if (info
->data_pos
>= info
->data_len
) /* need to read some more data */
742 NtQueryDirectoryFile( info
->handle
, 0, NULL
, NULL
, &io
, info
->data
, sizeof(info
->data
),
743 FileBothDirectoryInformation
, FALSE
, &info
->mask
, FALSE
);
746 SetLastError( RtlNtStatusToDosError( io
.u
.Status
) );
749 info
->data_len
= io
.Information
;
753 dir_info
= (FILE_BOTH_DIR_INFORMATION
*)(info
->data
+ info
->data_pos
);
755 if (dir_info
->NextEntryOffset
) info
->data_pos
+= dir_info
->NextEntryOffset
;
756 else info
->data_pos
= info
->data_len
;
758 /* don't return '.' and '..' in the root of the drive */
761 if (dir_info
->FileNameLength
== sizeof(WCHAR
) && dir_info
->FileName
[0] == '.') continue;
762 if (dir_info
->FileNameLength
== 2 * sizeof(WCHAR
) &&
763 dir_info
->FileName
[0] == '.' && dir_info
->FileName
[1] == '.') continue;
766 data
->dwFileAttributes
= dir_info
->FileAttributes
;
767 data
->ftCreationTime
= *(FILETIME
*)&dir_info
->CreationTime
;
768 data
->ftLastAccessTime
= *(FILETIME
*)&dir_info
->LastAccessTime
;
769 data
->ftLastWriteTime
= *(FILETIME
*)&dir_info
->LastWriteTime
;
770 data
->nFileSizeHigh
= dir_info
->EndOfFile
.QuadPart
>> 32;
771 data
->nFileSizeLow
= (DWORD
)dir_info
->EndOfFile
.QuadPart
;
772 data
->dwReserved0
= 0;
773 data
->dwReserved1
= 0;
775 memcpy( data
->cFileName
, dir_info
->FileName
, dir_info
->FileNameLength
);
776 data
->cFileName
[dir_info
->FileNameLength
/sizeof(WCHAR
)] = 0;
777 memcpy( data
->cAlternateFileName
, dir_info
->ShortName
, dir_info
->ShortNameLength
);
778 data
->cAlternateFileName
[dir_info
->ShortNameLength
/sizeof(WCHAR
)] = 0;
780 TRACE("returning %s (%s)\n",
781 debugstr_w(data
->cFileName
), debugstr_w(data
->cAlternateFileName
) );
787 RtlLeaveCriticalSection( &info
->cs
);
792 /*************************************************************************
793 * FindClose (KERNEL32.@)
795 BOOL WINAPI
FindClose( HANDLE handle
)
797 FIND_FIRST_INFO
*info
= (FIND_FIRST_INFO
*)handle
;
799 if (!handle
|| handle
== INVALID_HANDLE_VALUE
) goto error
;
803 RtlEnterCriticalSection( &info
->cs
);
804 if (info
->handle
) CloseHandle( info
->handle
);
806 RtlFreeUnicodeString( &info
->mask
);
807 info
->mask
.Buffer
= NULL
;
813 WARN("Illegal handle %p\n", handle
);
814 SetLastError( ERROR_INVALID_HANDLE
);
819 RtlLeaveCriticalSection( &info
->cs
);
820 RtlDeleteCriticalSection( &info
->cs
);
821 HeapFree(GetProcessHeap(), 0, info
);
825 SetLastError( ERROR_INVALID_HANDLE
);
830 /*************************************************************************
831 * FindFirstFileA (KERNEL32.@)
833 HANDLE WINAPI
FindFirstFileA( LPCSTR lpFileName
, WIN32_FIND_DATAA
*lpFindData
)
835 return FindFirstFileExA(lpFileName
, FindExInfoStandard
, lpFindData
,
836 FindExSearchNameMatch
, NULL
, 0);
839 /*************************************************************************
840 * FindFirstFileExA (KERNEL32.@)
842 HANDLE WINAPI
FindFirstFileExA( LPCSTR lpFileName
, FINDEX_INFO_LEVELS fInfoLevelId
,
843 LPVOID lpFindFileData
, FINDEX_SEARCH_OPS fSearchOp
,
844 LPVOID lpSearchFilter
, DWORD dwAdditionalFlags
)
847 WIN32_FIND_DATAA
*dataA
;
848 WIN32_FIND_DATAW dataW
;
849 UNICODE_STRING pathW
;
853 SetLastError(ERROR_PATH_NOT_FOUND
);
854 return INVALID_HANDLE_VALUE
;
857 if (!RtlCreateUnicodeStringFromAsciiz(&pathW
, lpFileName
))
859 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
860 return INVALID_HANDLE_VALUE
;
863 handle
= FindFirstFileExW(pathW
.Buffer
, fInfoLevelId
, &dataW
, fSearchOp
, lpSearchFilter
, dwAdditionalFlags
);
864 RtlFreeUnicodeString(&pathW
);
865 if (handle
== INVALID_HANDLE_VALUE
) return handle
;
867 dataA
= (WIN32_FIND_DATAA
*) lpFindFileData
;
868 dataA
->dwFileAttributes
= dataW
.dwFileAttributes
;
869 dataA
->ftCreationTime
= dataW
.ftCreationTime
;
870 dataA
->ftLastAccessTime
= dataW
.ftLastAccessTime
;
871 dataA
->ftLastWriteTime
= dataW
.ftLastWriteTime
;
872 dataA
->nFileSizeHigh
= dataW
.nFileSizeHigh
;
873 dataA
->nFileSizeLow
= dataW
.nFileSizeLow
;
874 WideCharToMultiByte( CP_ACP
, 0, dataW
.cFileName
, -1,
875 dataA
->cFileName
, sizeof(dataA
->cFileName
), NULL
, NULL
);
876 WideCharToMultiByte( CP_ACP
, 0, dataW
.cAlternateFileName
, -1,
877 dataA
->cAlternateFileName
, sizeof(dataA
->cAlternateFileName
), NULL
, NULL
);
882 /*************************************************************************
883 * FindFirstFileW (KERNEL32.@)
885 HANDLE WINAPI
FindFirstFileW( LPCWSTR lpFileName
, WIN32_FIND_DATAW
*lpFindData
)
887 return FindFirstFileExW(lpFileName
, FindExInfoStandard
, lpFindData
,
888 FindExSearchNameMatch
, NULL
, 0);
892 /*************************************************************************
893 * FindNextFileA (KERNEL32.@)
895 BOOL WINAPI
FindNextFileA( HANDLE handle
, WIN32_FIND_DATAA
*data
)
897 WIN32_FIND_DATAW dataW
;
899 if (!FindNextFileW( handle
, &dataW
)) return FALSE
;
900 data
->dwFileAttributes
= dataW
.dwFileAttributes
;
901 data
->ftCreationTime
= dataW
.ftCreationTime
;
902 data
->ftLastAccessTime
= dataW
.ftLastAccessTime
;
903 data
->ftLastWriteTime
= dataW
.ftLastWriteTime
;
904 data
->nFileSizeHigh
= dataW
.nFileSizeHigh
;
905 data
->nFileSizeLow
= dataW
.nFileSizeLow
;
906 WideCharToMultiByte( CP_ACP
, 0, dataW
.cFileName
, -1,
907 data
->cFileName
, sizeof(data
->cFileName
), NULL
, NULL
);
908 WideCharToMultiByte( CP_ACP
, 0, dataW
.cAlternateFileName
, -1,
909 data
->cAlternateFileName
,
910 sizeof(data
->cAlternateFileName
), NULL
, NULL
);
915 /***********************************************************************
916 * OpenFile (KERNEL32.@)
918 HFILE WINAPI
OpenFile( LPCSTR name
, OFSTRUCT
*ofs
, UINT mode
)
922 WORD filedatetime
[2];
924 if (!ofs
) return HFILE_ERROR
;
926 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name
,
927 ((mode
& 0x3 )==OF_READ
)?"OF_READ":
928 ((mode
& 0x3 )==OF_WRITE
)?"OF_WRITE":
929 ((mode
& 0x3 )==OF_READWRITE
)?"OF_READWRITE":"unknown",
930 ((mode
& 0x70 )==OF_SHARE_COMPAT
)?"OF_SHARE_COMPAT":
931 ((mode
& 0x70 )==OF_SHARE_DENY_NONE
)?"OF_SHARE_DENY_NONE":
932 ((mode
& 0x70 )==OF_SHARE_DENY_READ
)?"OF_SHARE_DENY_READ":
933 ((mode
& 0x70 )==OF_SHARE_DENY_WRITE
)?"OF_SHARE_DENY_WRITE":
934 ((mode
& 0x70 )==OF_SHARE_EXCLUSIVE
)?"OF_SHARE_EXCLUSIVE":"unknown",
935 ((mode
& OF_PARSE
)==OF_PARSE
)?"OF_PARSE ":"",
936 ((mode
& OF_DELETE
)==OF_DELETE
)?"OF_DELETE ":"",
937 ((mode
& OF_VERIFY
)==OF_VERIFY
)?"OF_VERIFY ":"",
938 ((mode
& OF_SEARCH
)==OF_SEARCH
)?"OF_SEARCH ":"",
939 ((mode
& OF_CANCEL
)==OF_CANCEL
)?"OF_CANCEL ":"",
940 ((mode
& OF_CREATE
)==OF_CREATE
)?"OF_CREATE ":"",
941 ((mode
& OF_PROMPT
)==OF_PROMPT
)?"OF_PROMPT ":"",
942 ((mode
& OF_EXIST
)==OF_EXIST
)?"OF_EXIST ":"",
943 ((mode
& OF_REOPEN
)==OF_REOPEN
)?"OF_REOPEN ":""
947 ofs
->cBytes
= sizeof(OFSTRUCT
);
949 if (mode
& OF_REOPEN
) name
= ofs
->szPathName
;
951 if (!name
) return HFILE_ERROR
;
953 TRACE("%s %04x\n", name
, mode
);
955 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
956 Are there any cases where getting the path here is wrong?
957 Uwe Bonnes 1997 Apr 2 */
958 if (!GetFullPathNameA( name
, sizeof(ofs
->szPathName
), ofs
->szPathName
, NULL
)) goto error
;
960 /* OF_PARSE simply fills the structure */
964 ofs
->fFixedDisk
= (GetDriveTypeA( ofs
->szPathName
) != DRIVE_REMOVABLE
);
965 TRACE("(%s): OF_PARSE, res = '%s'\n", name
, ofs
->szPathName
);
969 /* OF_CREATE is completely different from all other options, so
972 if (mode
& OF_CREATE
)
974 DWORD access
, sharing
;
975 FILE_ConvertOFMode( mode
, &access
, &sharing
);
976 if ((handle
= CreateFileA( name
, GENERIC_READ
| GENERIC_WRITE
,
977 sharing
, NULL
, CREATE_ALWAYS
,
978 FILE_ATTRIBUTE_NORMAL
, 0 )) == INVALID_HANDLE_VALUE
)
983 /* Now look for the file */
985 if (!SearchPathA( NULL
, name
, NULL
, sizeof(ofs
->szPathName
), ofs
->szPathName
, NULL
))
988 TRACE("found %s\n", debugstr_a(ofs
->szPathName
) );
990 if (mode
& OF_DELETE
)
992 if (!DeleteFileA( ofs
->szPathName
)) goto error
;
993 TRACE("(%s): OF_DELETE return = OK\n", name
);
997 handle
= (HANDLE
)_lopen( ofs
->szPathName
, mode
);
998 if (handle
== INVALID_HANDLE_VALUE
) goto error
;
1000 GetFileTime( handle
, NULL
, NULL
, &filetime
);
1001 FileTimeToDosDateTime( &filetime
, &filedatetime
[0], &filedatetime
[1] );
1002 if ((mode
& OF_VERIFY
) && (mode
& OF_REOPEN
))
1004 if (ofs
->Reserved1
!= filedatetime
[0] || ofs
->Reserved2
!= filedatetime
[1] )
1006 CloseHandle( handle
);
1007 WARN("(%s): OF_VERIFY failed\n", name
);
1008 /* FIXME: what error here? */
1009 SetLastError( ERROR_FILE_NOT_FOUND
);
1013 ofs
->Reserved1
= filedatetime
[0];
1014 ofs
->Reserved2
= filedatetime
[1];
1016 TRACE("(%s): OK, return = %p\n", name
, handle
);
1017 if (mode
& OF_EXIST
) /* Return TRUE instead of a handle */
1019 CloseHandle( handle
);
1022 else return (HFILE
)handle
;
1024 error
: /* We get here if there was an error opening the file */
1025 ofs
->nErrCode
= GetLastError();
1026 WARN("(%s): return = HFILE_ERROR error= %d\n", name
,ofs
->nErrCode
);