2 * File handling functions
4 * Copyright 1993 John Burton
5 * Copyright 1996, 2004 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
23 #include "wine/port.h"
28 #define NONAMELESSUNION
29 #define NONAMELESSSTRUCT
38 #include "wine/winbase16.h"
39 #include "kernel_private.h"
41 #include "wine/exception.h"
43 #include "wine/unicode.h"
44 #include "wine/debug.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(file
);
49 HANDLE dos_handles
[DOS_TABLE_SIZE
];
51 /* info structure for FindFirstFile handle */
54 HANDLE handle
; /* handle to directory */
55 CRITICAL_SECTION cs
; /* crit section protecting this structure */
56 UNICODE_STRING mask
; /* file mask */
57 BOOL is_root
; /* is directory the root of the drive? */
58 UINT data_pos
; /* current position in dir data */
59 UINT data_len
; /* length of dir data */
60 BYTE data
[8192]; /* directory data */
64 static WINE_EXCEPTION_FILTER(page_fault
)
66 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION
)
67 return EXCEPTION_EXECUTE_HANDLER
;
68 return EXCEPTION_CONTINUE_SEARCH
;
72 /***********************************************************************
75 * Wrapper for CreateFile that takes OF_* mode flags.
77 static HANDLE
create_file_OF( LPCSTR path
, INT mode
, DWORD creation
)
79 DWORD access
, sharing
;
83 case OF_READ
: access
= GENERIC_READ
; break;
84 case OF_WRITE
: access
= GENERIC_WRITE
; break;
85 case OF_READWRITE
: access
= GENERIC_READ
| GENERIC_WRITE
; break;
86 default: access
= 0; break;
90 case OF_SHARE_EXCLUSIVE
: sharing
= 0; break;
91 case OF_SHARE_DENY_WRITE
: sharing
= FILE_SHARE_READ
; break;
92 case OF_SHARE_DENY_READ
: sharing
= FILE_SHARE_WRITE
; break;
93 case OF_SHARE_DENY_NONE
:
95 default: sharing
= FILE_SHARE_READ
| FILE_SHARE_WRITE
; break;
97 return CreateFileA( path
, access
, sharing
, NULL
, creation
, FILE_ATTRIBUTE_NORMAL
, 0 );
101 /***********************************************************************
104 * Set the DOS error code from errno.
106 void FILE_SetDosError(void)
108 int save_errno
= errno
; /* errno gets overwritten by printf */
110 TRACE("errno = %d %s\n", errno
, strerror(errno
));
114 SetLastError( ERROR_SHARING_VIOLATION
);
117 SetLastError( ERROR_INVALID_HANDLE
);
120 SetLastError( ERROR_HANDLE_DISK_FULL
);
125 SetLastError( ERROR_ACCESS_DENIED
);
128 SetLastError( ERROR_LOCK_VIOLATION
);
131 SetLastError( ERROR_FILE_NOT_FOUND
);
134 SetLastError( ERROR_CANNOT_MAKE
);
138 SetLastError( ERROR_TOO_MANY_OPEN_FILES
);
141 SetLastError( ERROR_FILE_EXISTS
);
145 SetLastError( ERROR_SEEK
);
148 SetLastError( ERROR_DIR_NOT_EMPTY
);
151 SetLastError( ERROR_BAD_FORMAT
);
154 SetLastError( ERROR_PATH_NOT_FOUND
);
157 SetLastError( ERROR_NOT_SAME_DEVICE
);
160 WARN("unknown file error: %s\n", strerror(save_errno
) );
161 SetLastError( ERROR_GEN_FAILURE
);
168 /**************************************************************************
169 * Operations on file handles *
170 **************************************************************************/
172 /***********************************************************************
173 * FILE_InitProcessDosHandles
175 * Allocates the default DOS handles for a process. Called either by
176 * Win32HandleToDosFileHandle below or by the DOSVM stuff.
178 static void FILE_InitProcessDosHandles( void )
180 static BOOL init_done
/* = FALSE */;
181 HANDLE cp
= GetCurrentProcess();
183 if (init_done
) return;
185 DuplicateHandle(cp
, GetStdHandle(STD_INPUT_HANDLE
), cp
, &dos_handles
[0],
186 0, TRUE
, DUPLICATE_SAME_ACCESS
);
187 DuplicateHandle(cp
, GetStdHandle(STD_OUTPUT_HANDLE
), cp
, &dos_handles
[1],
188 0, TRUE
, DUPLICATE_SAME_ACCESS
);
189 DuplicateHandle(cp
, GetStdHandle(STD_ERROR_HANDLE
), cp
, &dos_handles
[2],
190 0, TRUE
, DUPLICATE_SAME_ACCESS
);
191 DuplicateHandle(cp
, GetStdHandle(STD_ERROR_HANDLE
), cp
, &dos_handles
[3],
192 0, TRUE
, DUPLICATE_SAME_ACCESS
);
193 DuplicateHandle(cp
, GetStdHandle(STD_ERROR_HANDLE
), cp
, &dos_handles
[4],
194 0, TRUE
, DUPLICATE_SAME_ACCESS
);
198 /******************************************************************
199 * FILE_ReadWriteApc (internal)
201 static void WINAPI
FILE_ReadWriteApc(void* apc_user
, PIO_STATUS_BLOCK io_status
, ULONG len
)
203 LPOVERLAPPED_COMPLETION_ROUTINE cr
= (LPOVERLAPPED_COMPLETION_ROUTINE
)apc_user
;
205 cr(RtlNtStatusToDosError(io_status
->u
.Status
), len
, (LPOVERLAPPED
)io_status
);
209 /***********************************************************************
210 * ReadFileEx (KERNEL32.@)
212 BOOL WINAPI
ReadFileEx(HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
213 LPOVERLAPPED overlapped
,
214 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
216 LARGE_INTEGER offset
;
218 PIO_STATUS_BLOCK io_status
;
222 SetLastError(ERROR_INVALID_PARAMETER
);
226 offset
.u
.LowPart
= overlapped
->Offset
;
227 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
228 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
229 io_status
->u
.Status
= STATUS_PENDING
;
231 status
= NtReadFile(hFile
, NULL
, FILE_ReadWriteApc
, lpCompletionRoutine
,
232 io_status
, buffer
, bytesToRead
, &offset
, NULL
);
236 SetLastError( RtlNtStatusToDosError(status
) );
243 /***********************************************************************
244 * ReadFile (KERNEL32.@)
246 BOOL WINAPI
ReadFile( HANDLE hFile
, LPVOID buffer
, DWORD bytesToRead
,
247 LPDWORD bytesRead
, LPOVERLAPPED overlapped
)
249 LARGE_INTEGER offset
;
250 PLARGE_INTEGER poffset
= NULL
;
251 IO_STATUS_BLOCK iosb
;
252 PIO_STATUS_BLOCK io_status
= &iosb
;
256 TRACE("%p %p %ld %p %p\n", hFile
, buffer
, bytesToRead
,
257 bytesRead
, overlapped
);
259 if (bytesRead
) *bytesRead
= 0; /* Do this before anything else */
260 if (!bytesToRead
) return TRUE
;
262 if (IsBadReadPtr(buffer
, bytesToRead
))
264 SetLastError(ERROR_WRITE_FAULT
); /* FIXME */
267 if (is_console_handle(hFile
))
268 return ReadConsoleA(hFile
, buffer
, bytesToRead
, bytesRead
, NULL
);
270 if (overlapped
!= NULL
)
272 offset
.u
.LowPart
= overlapped
->Offset
;
273 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
275 hEvent
= overlapped
->hEvent
;
276 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
278 io_status
->u
.Status
= STATUS_PENDING
;
279 io_status
->Information
= 0;
281 status
= NtReadFile(hFile
, hEvent
, NULL
, NULL
, io_status
, buffer
, bytesToRead
, poffset
, NULL
);
283 if (status
!= STATUS_PENDING
&& bytesRead
)
284 *bytesRead
= io_status
->Information
;
286 if (status
&& status
!= STATUS_END_OF_FILE
)
288 SetLastError( RtlNtStatusToDosError(status
) );
295 /***********************************************************************
296 * WriteFileEx (KERNEL32.@)
298 BOOL WINAPI
WriteFileEx(HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
299 LPOVERLAPPED overlapped
,
300 LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
)
302 LARGE_INTEGER offset
;
304 PIO_STATUS_BLOCK io_status
;
306 TRACE("%p %p %ld %p %p\n", hFile
, buffer
, bytesToWrite
, overlapped
, lpCompletionRoutine
);
308 if (overlapped
== NULL
)
310 SetLastError(ERROR_INVALID_PARAMETER
);
313 offset
.u
.LowPart
= overlapped
->Offset
;
314 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
316 io_status
= (PIO_STATUS_BLOCK
)overlapped
;
317 io_status
->u
.Status
= STATUS_PENDING
;
319 status
= NtWriteFile(hFile
, NULL
, FILE_ReadWriteApc
, lpCompletionRoutine
,
320 io_status
, buffer
, bytesToWrite
, &offset
, NULL
);
322 if (status
) SetLastError( RtlNtStatusToDosError(status
) );
327 /***********************************************************************
328 * WriteFile (KERNEL32.@)
330 BOOL WINAPI
WriteFile( HANDLE hFile
, LPCVOID buffer
, DWORD bytesToWrite
,
331 LPDWORD bytesWritten
, LPOVERLAPPED overlapped
)
333 HANDLE hEvent
= NULL
;
334 LARGE_INTEGER offset
;
335 PLARGE_INTEGER poffset
= NULL
;
337 IO_STATUS_BLOCK iosb
;
338 PIO_STATUS_BLOCK piosb
= &iosb
;
340 TRACE("%p %p %ld %p %p\n", hFile
, buffer
, bytesToWrite
, bytesWritten
, overlapped
);
342 if (is_console_handle(hFile
))
343 return WriteConsoleA(hFile
, buffer
, bytesToWrite
, bytesWritten
, NULL
);
345 if (IsBadReadPtr(buffer
, bytesToWrite
))
347 SetLastError(ERROR_READ_FAULT
); /* FIXME */
353 offset
.u
.LowPart
= overlapped
->Offset
;
354 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
356 hEvent
= overlapped
->hEvent
;
357 piosb
= (PIO_STATUS_BLOCK
)overlapped
;
359 piosb
->u
.Status
= STATUS_PENDING
;
360 piosb
->Information
= 0;
362 status
= NtWriteFile(hFile
, hEvent
, NULL
, NULL
, piosb
,
363 buffer
, bytesToWrite
, poffset
, NULL
);
366 SetLastError( RtlNtStatusToDosError(status
) );
369 if (bytesWritten
) *bytesWritten
= piosb
->Information
;
375 /***********************************************************************
376 * GetOverlappedResult (KERNEL32.@)
378 * Check the result of an Asynchronous data transfer from a file.
381 * HANDLE hFile [in] handle of file to check on
382 * LPOVERLAPPED lpOverlapped [in/out] pointer to overlapped
383 * LPDWORD lpTransferred [in/out] number of bytes transferred
384 * BOOL bWait [in] wait for the transfer to complete ?
390 * If successful (and relevant) lpTransferred will hold the number of
391 * bytes transferred during the async operation.
395 * Currently only works for WaitCommEvent, ReadFile, WriteFile
396 * with communications ports.
399 BOOL WINAPI
GetOverlappedResult(HANDLE hFile
, LPOVERLAPPED lpOverlapped
,
400 LPDWORD lpTransferred
, BOOL bWait
)
404 TRACE("(%p %p %p %x)\n", hFile
, lpOverlapped
, lpTransferred
, bWait
);
406 if (lpOverlapped
==NULL
)
408 ERR("lpOverlapped was null\n");
411 if (!lpOverlapped
->hEvent
)
413 ERR("lpOverlapped->hEvent was null\n");
420 TRACE("waiting on %p\n",lpOverlapped
);
421 r
= WaitForSingleObjectEx(lpOverlapped
->hEvent
, INFINITE
, TRUE
);
422 TRACE("wait on %p returned %ld\n",lpOverlapped
,r
);
423 } while (r
==STATUS_USER_APC
);
425 else if ( lpOverlapped
->Internal
== STATUS_PENDING
)
427 /* Wait in order to give APCs a chance to run. */
428 /* This is cheating, so we must set the event again in case of success -
429 it may be a non-manual reset event. */
431 TRACE("waiting on %p\n",lpOverlapped
);
432 r
= WaitForSingleObjectEx(lpOverlapped
->hEvent
, 0, TRUE
);
433 TRACE("wait on %p returned %ld\n",lpOverlapped
,r
);
434 } while (r
==STATUS_USER_APC
);
435 if ( r
== WAIT_OBJECT_0
)
436 NtSetEvent ( lpOverlapped
->hEvent
, NULL
);
440 *lpTransferred
= lpOverlapped
->InternalHigh
;
442 switch ( lpOverlapped
->Internal
)
447 SetLastError ( ERROR_IO_INCOMPLETE
);
448 if ( bWait
) ERR ("PENDING status after waiting!\n");
451 SetLastError ( RtlNtStatusToDosError ( lpOverlapped
->Internal
) );
456 /***********************************************************************
457 * CancelIo (KERNEL32.@)
459 BOOL WINAPI
CancelIo(HANDLE handle
)
461 async_private
*ovp
,*t
;
463 TRACE("handle = %p\n",handle
);
465 for (ovp
= NtCurrentTeb()->pending_list
; ovp
; ovp
= t
)
468 if ( ovp
->handle
== handle
)
469 cancel_async ( ovp
);
475 /***********************************************************************
476 * _hread (KERNEL32.@)
478 LONG WINAPI
_hread( HFILE hFile
, LPVOID buffer
, LONG count
)
480 return _lread( hFile
, buffer
, count
);
484 /***********************************************************************
485 * _hwrite (KERNEL32.@)
487 * experimentation yields that _lwrite:
488 * o truncates the file at the current position with
490 * o returns 0 on a 0 length write
491 * o works with console handles
494 LONG WINAPI
_hwrite( HFILE handle
, LPCSTR buffer
, LONG count
)
498 TRACE("%d %p %ld\n", handle
, buffer
, count
);
502 /* Expand or truncate at current position */
503 if (!SetEndOfFile( (HANDLE
)handle
)) return HFILE_ERROR
;
506 if (!WriteFile( (HANDLE
)handle
, buffer
, count
, &result
, NULL
))
512 /***********************************************************************
513 * _lclose (KERNEL32.@)
515 HFILE WINAPI
_lclose( HFILE hFile
)
517 TRACE("handle %d\n", hFile
);
518 return CloseHandle( (HANDLE
)hFile
) ? 0 : HFILE_ERROR
;
522 /***********************************************************************
523 * _lcreat (KERNEL32.@)
525 HFILE WINAPI
_lcreat( LPCSTR path
, INT attr
)
527 /* Mask off all flags not explicitly allowed by the doc */
528 attr
&= FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_SYSTEM
;
529 TRACE("%s %02x\n", path
, attr
);
530 return (HFILE
)CreateFileA( path
, GENERIC_READ
| GENERIC_WRITE
,
531 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
532 CREATE_ALWAYS
, attr
, 0 );
536 /***********************************************************************
537 * _lopen (KERNEL32.@)
539 HFILE WINAPI
_lopen( LPCSTR path
, INT mode
)
541 TRACE("(%s,%04x)\n", debugstr_a(path
), mode
);
542 return (HFILE
)create_file_OF( path
, mode
, OPEN_EXISTING
);
546 /***********************************************************************
547 * _lread (KERNEL32.@)
549 UINT WINAPI
_lread( HFILE handle
, LPVOID buffer
, UINT count
)
552 if (!ReadFile( (HANDLE
)handle
, buffer
, count
, &result
, NULL
))
558 /***********************************************************************
559 * _llseek (KERNEL32.@)
561 LONG WINAPI
_llseek( HFILE hFile
, LONG lOffset
, INT nOrigin
)
563 return SetFilePointer( (HANDLE
)hFile
, lOffset
, NULL
, nOrigin
);
567 /***********************************************************************
568 * _lwrite (KERNEL32.@)
570 UINT WINAPI
_lwrite( HFILE hFile
, LPCSTR buffer
, UINT count
)
572 return (UINT
)_hwrite( hFile
, buffer
, (LONG
)count
);
576 /***********************************************************************
577 * FlushFileBuffers (KERNEL32.@)
579 BOOL WINAPI
FlushFileBuffers( HANDLE hFile
)
582 IO_STATUS_BLOCK ioblk
;
584 if (is_console_handle( hFile
))
586 /* this will fail (as expected) for an output handle */
587 /* FIXME: wait until FlushFileBuffers is moved to dll/kernel */
588 /* return FlushConsoleInputBuffer( hFile ); */
591 nts
= NtFlushBuffersFile( hFile
, &ioblk
);
592 if (nts
!= STATUS_SUCCESS
)
594 SetLastError( RtlNtStatusToDosError( nts
) );
602 /***********************************************************************
603 * GetFileType (KERNEL32.@)
605 DWORD WINAPI
GetFileType( HANDLE hFile
)
607 FILE_FS_DEVICE_INFORMATION info
;
611 if (is_console_handle( hFile
)) return FILE_TYPE_CHAR
;
613 status
= NtQueryVolumeInformationFile( hFile
, &io
, &info
, sizeof(info
), FileFsDeviceInformation
);
614 if (status
!= STATUS_SUCCESS
)
616 SetLastError( RtlNtStatusToDosError(status
) );
617 return FILE_TYPE_UNKNOWN
;
620 switch(info
.DeviceType
)
622 case FILE_DEVICE_NULL
:
623 case FILE_DEVICE_SERIAL_PORT
:
624 case FILE_DEVICE_PARALLEL_PORT
:
625 case FILE_DEVICE_UNKNOWN
:
626 return FILE_TYPE_CHAR
;
627 case FILE_DEVICE_NAMED_PIPE
:
628 return FILE_TYPE_PIPE
;
630 return FILE_TYPE_DISK
;
635 /***********************************************************************
636 * GetFileInformationByHandle (KERNEL32.@)
638 BOOL WINAPI
GetFileInformationByHandle( HANDLE hFile
, BY_HANDLE_FILE_INFORMATION
*info
)
640 FILE_ALL_INFORMATION all_info
;
644 status
= NtQueryInformationFile( hFile
, &io
, &all_info
, sizeof(all_info
), FileAllInformation
);
645 if (status
== STATUS_SUCCESS
)
647 info
->dwFileAttributes
= all_info
.BasicInformation
.FileAttributes
;
648 info
->ftCreationTime
.dwHighDateTime
= all_info
.BasicInformation
.CreationTime
.u
.HighPart
;
649 info
->ftCreationTime
.dwLowDateTime
= all_info
.BasicInformation
.CreationTime
.u
.LowPart
;
650 info
->ftLastAccessTime
.dwHighDateTime
= all_info
.BasicInformation
.LastAccessTime
.u
.HighPart
;
651 info
->ftLastAccessTime
.dwLowDateTime
= all_info
.BasicInformation
.LastAccessTime
.u
.LowPart
;
652 info
->ftLastWriteTime
.dwHighDateTime
= all_info
.BasicInformation
.LastWriteTime
.u
.HighPart
;
653 info
->ftLastWriteTime
.dwLowDateTime
= all_info
.BasicInformation
.LastWriteTime
.u
.LowPart
;
654 info
->dwVolumeSerialNumber
= 0; /* FIXME */
655 info
->nFileSizeHigh
= all_info
.StandardInformation
.EndOfFile
.u
.HighPart
;
656 info
->nFileSizeLow
= all_info
.StandardInformation
.EndOfFile
.u
.LowPart
;
657 info
->nNumberOfLinks
= all_info
.StandardInformation
.NumberOfLinks
;
658 info
->nFileIndexHigh
= all_info
.InternalInformation
.IndexNumber
.u
.HighPart
;
659 info
->nFileIndexLow
= all_info
.InternalInformation
.IndexNumber
.u
.LowPart
;
662 SetLastError( RtlNtStatusToDosError(status
) );
667 /***********************************************************************
668 * GetFileSize (KERNEL32.@)
670 DWORD WINAPI
GetFileSize( HANDLE hFile
, LPDWORD filesizehigh
)
673 if (!GetFileSizeEx( hFile
, &size
)) return INVALID_FILE_SIZE
;
674 if (filesizehigh
) *filesizehigh
= size
.u
.HighPart
;
675 if (size
.u
.LowPart
== INVALID_FILE_SIZE
) SetLastError(0);
676 return size
.u
.LowPart
;
680 /***********************************************************************
681 * GetFileSizeEx (KERNEL32.@)
683 BOOL WINAPI
GetFileSizeEx( HANDLE hFile
, PLARGE_INTEGER lpFileSize
)
685 FILE_END_OF_FILE_INFORMATION info
;
689 status
= NtQueryInformationFile( hFile
, &io
, &info
, sizeof(info
), FileEndOfFileInformation
);
690 if (status
== STATUS_SUCCESS
)
692 *lpFileSize
= info
.EndOfFile
;
695 SetLastError( RtlNtStatusToDosError(status
) );
700 /**************************************************************************
701 * SetEndOfFile (KERNEL32.@)
703 BOOL WINAPI
SetEndOfFile( HANDLE hFile
)
705 FILE_POSITION_INFORMATION pos
;
706 FILE_END_OF_FILE_INFORMATION eof
;
710 status
= NtQueryInformationFile( hFile
, &io
, &pos
, sizeof(pos
), FilePositionInformation
);
711 if (status
== STATUS_SUCCESS
)
713 eof
.EndOfFile
= pos
.CurrentByteOffset
;
714 status
= NtSetInformationFile( hFile
, &io
, &eof
, sizeof(eof
), FileEndOfFileInformation
);
716 if (status
== STATUS_SUCCESS
) return TRUE
;
717 SetLastError( RtlNtStatusToDosError(status
) );
722 /***********************************************************************
723 * SetFilePointer (KERNEL32.@)
725 DWORD WINAPI
SetFilePointer( HANDLE hFile
, LONG distance
, LONG
*highword
,
728 static const int whence
[3] = { SEEK_SET
, SEEK_CUR
, SEEK_END
};
729 DWORD ret
= INVALID_SET_FILE_POINTER
;
733 TRACE("handle %p offset %ld high %ld origin %ld\n",
734 hFile
, distance
, highword
?*highword
:0, method
);
736 if (method
> FILE_END
)
738 SetLastError( ERROR_INVALID_PARAMETER
);
742 if (!(status
= wine_server_handle_to_fd( hFile
, 0, &fd
, NULL
, NULL
)))
746 if (highword
) pos
= ((off_t
)*highword
<< 32) | (ULONG
)distance
;
747 else pos
= (off_t
)distance
;
748 if ((res
= lseek( fd
, pos
, whence
[method
] )) == (off_t
)-1)
750 /* also check EPERM due to SuSE7 2.2.16 lseek() EPERM kernel bug */
751 if (((errno
== EINVAL
) || (errno
== EPERM
)) && (method
!= FILE_BEGIN
) && (pos
< 0))
752 SetLastError( ERROR_NEGATIVE_SEEK
);
759 if (highword
) *highword
= (res
>> 32);
760 if (ret
== INVALID_SET_FILE_POINTER
) SetLastError( 0 );
762 wine_server_release_fd( hFile
, fd
);
764 else SetLastError( RtlNtStatusToDosError(status
) );
770 /***********************************************************************
771 * GetFileTime (KERNEL32.@)
773 BOOL WINAPI
GetFileTime( HANDLE hFile
, FILETIME
*lpCreationTime
,
774 FILETIME
*lpLastAccessTime
, FILETIME
*lpLastWriteTime
)
776 FILE_BASIC_INFORMATION info
;
780 status
= NtQueryInformationFile( hFile
, &io
, &info
, sizeof(info
), FileBasicInformation
);
781 if (status
== STATUS_SUCCESS
)
785 lpCreationTime
->dwHighDateTime
= info
.CreationTime
.u
.HighPart
;
786 lpCreationTime
->dwLowDateTime
= info
.CreationTime
.u
.LowPart
;
788 if (lpLastAccessTime
)
790 lpLastAccessTime
->dwHighDateTime
= info
.LastAccessTime
.u
.HighPart
;
791 lpLastAccessTime
->dwLowDateTime
= info
.LastAccessTime
.u
.LowPart
;
795 lpLastWriteTime
->dwHighDateTime
= info
.LastWriteTime
.u
.HighPart
;
796 lpLastWriteTime
->dwLowDateTime
= info
.LastWriteTime
.u
.LowPart
;
800 SetLastError( RtlNtStatusToDosError(status
) );
805 /***********************************************************************
806 * SetFileTime (KERNEL32.@)
808 BOOL WINAPI
SetFileTime( HANDLE hFile
, const FILETIME
*ctime
,
809 const FILETIME
*atime
, const FILETIME
*mtime
)
811 FILE_BASIC_INFORMATION info
;
815 memset( &info
, 0, sizeof(info
) );
818 info
.CreationTime
.u
.HighPart
= ctime
->dwHighDateTime
;
819 info
.CreationTime
.u
.LowPart
= ctime
->dwLowDateTime
;
823 info
.LastAccessTime
.u
.HighPart
= atime
->dwHighDateTime
;
824 info
.LastAccessTime
.u
.LowPart
= atime
->dwLowDateTime
;
828 info
.LastWriteTime
.u
.HighPart
= mtime
->dwHighDateTime
;
829 info
.LastWriteTime
.u
.LowPart
= mtime
->dwLowDateTime
;
832 status
= NtSetInformationFile( hFile
, &io
, &info
, sizeof(info
), FileBasicInformation
);
833 if (status
== STATUS_SUCCESS
) return TRUE
;
834 SetLastError( RtlNtStatusToDosError(status
) );
839 /**************************************************************************
840 * LockFile (KERNEL32.@)
842 BOOL WINAPI
LockFile( HANDLE hFile
, DWORD offset_low
, DWORD offset_high
,
843 DWORD count_low
, DWORD count_high
)
846 LARGE_INTEGER count
, offset
;
848 TRACE( "%p %lx%08lx %lx%08lx\n",
849 hFile
, offset_high
, offset_low
, count_high
, count_low
);
851 count
.u
.LowPart
= count_low
;
852 count
.u
.HighPart
= count_high
;
853 offset
.u
.LowPart
= offset_low
;
854 offset
.u
.HighPart
= offset_high
;
856 status
= NtLockFile( hFile
, 0, NULL
, NULL
,
857 NULL
, &offset
, &count
, NULL
, TRUE
, TRUE
);
859 if (status
!= STATUS_SUCCESS
) SetLastError( RtlNtStatusToDosError(status
) );
864 /**************************************************************************
865 * LockFileEx [KERNEL32.@]
867 * Locks a byte range within an open file for shared or exclusive access.
874 * Per Microsoft docs, the third parameter (reserved) must be set to 0.
876 BOOL WINAPI
LockFileEx( HANDLE hFile
, DWORD flags
, DWORD reserved
,
877 DWORD count_low
, DWORD count_high
, LPOVERLAPPED overlapped
)
880 LARGE_INTEGER count
, offset
;
884 SetLastError( ERROR_INVALID_PARAMETER
);
888 TRACE( "%p %lx%08lx %lx%08lx flags %lx\n",
889 hFile
, overlapped
->OffsetHigh
, overlapped
->Offset
,
890 count_high
, count_low
, flags
);
892 count
.u
.LowPart
= count_low
;
893 count
.u
.HighPart
= count_high
;
894 offset
.u
.LowPart
= overlapped
->Offset
;
895 offset
.u
.HighPart
= overlapped
->OffsetHigh
;
897 status
= NtLockFile( hFile
, overlapped
->hEvent
, NULL
, NULL
,
898 NULL
, &offset
, &count
, NULL
,
899 flags
& LOCKFILE_FAIL_IMMEDIATELY
,
900 flags
& LOCKFILE_EXCLUSIVE_LOCK
);
902 if (status
) SetLastError( RtlNtStatusToDosError(status
) );
907 /**************************************************************************
908 * UnlockFile (KERNEL32.@)
910 BOOL WINAPI
UnlockFile( HANDLE hFile
, DWORD offset_low
, DWORD offset_high
,
911 DWORD count_low
, DWORD count_high
)
914 LARGE_INTEGER count
, offset
;
916 count
.u
.LowPart
= count_low
;
917 count
.u
.HighPart
= count_high
;
918 offset
.u
.LowPart
= offset_low
;
919 offset
.u
.HighPart
= offset_high
;
921 status
= NtUnlockFile( hFile
, NULL
, &offset
, &count
, NULL
);
922 if (status
) SetLastError( RtlNtStatusToDosError(status
) );
927 /**************************************************************************
928 * UnlockFileEx (KERNEL32.@)
930 BOOL WINAPI
UnlockFileEx( HANDLE hFile
, DWORD reserved
, DWORD count_low
, DWORD count_high
,
931 LPOVERLAPPED overlapped
)
935 SetLastError( ERROR_INVALID_PARAMETER
);
938 if (overlapped
->hEvent
) FIXME("Unimplemented overlapped operation\n");
940 return UnlockFile( hFile
, overlapped
->Offset
, overlapped
->OffsetHigh
, count_low
, count_high
);
944 /***********************************************************************
945 * Win32HandleToDosFileHandle (KERNEL32.21)
947 * Allocate a DOS handle for a Win32 handle. The Win32 handle is no
948 * longer valid after this function (even on failure).
950 * Note: this is not exactly right, since on Win95 the Win32 handles
951 * are on top of DOS handles and we do it the other way
952 * around. Should be good enough though.
954 HFILE WINAPI
Win32HandleToDosFileHandle( HANDLE handle
)
958 if (!handle
|| (handle
== INVALID_HANDLE_VALUE
))
961 FILE_InitProcessDosHandles();
962 for (i
= 0; i
< DOS_TABLE_SIZE
; i
++)
965 dos_handles
[i
] = handle
;
966 TRACE("Got %d for h32 %p\n", i
, handle
);
969 CloseHandle( handle
);
970 SetLastError( ERROR_TOO_MANY_OPEN_FILES
);
975 /***********************************************************************
976 * DosFileHandleToWin32Handle (KERNEL32.20)
978 * Return the Win32 handle for a DOS handle.
980 * Note: this is not exactly right, since on Win95 the Win32 handles
981 * are on top of DOS handles and we do it the other way
982 * around. Should be good enough though.
984 HANDLE WINAPI
DosFileHandleToWin32Handle( HFILE handle
)
986 HFILE16 hfile
= (HFILE16
)handle
;
987 if (hfile
< 5) FILE_InitProcessDosHandles();
988 if ((hfile
>= DOS_TABLE_SIZE
) || !dos_handles
[hfile
])
990 SetLastError( ERROR_INVALID_HANDLE
);
991 return INVALID_HANDLE_VALUE
;
993 return dos_handles
[hfile
];
997 /*************************************************************************
998 * SetHandleCount (KERNEL32.@)
1000 UINT WINAPI
SetHandleCount( UINT count
)
1002 return min( 256, count
);
1006 /***********************************************************************
1007 * DisposeLZ32Handle (KERNEL32.22)
1009 * Note: this is not entirely correct, we should only close the
1010 * 32-bit handle and not the 16-bit one, but we cannot do
1011 * this because of the way our DOS handles are implemented.
1012 * It shouldn't break anything though.
1014 void WINAPI
DisposeLZ32Handle( HANDLE handle
)
1018 if (!handle
|| (handle
== INVALID_HANDLE_VALUE
)) return;
1020 for (i
= 5; i
< DOS_TABLE_SIZE
; i
++)
1021 if (dos_handles
[i
] == handle
)
1024 CloseHandle( handle
);
1029 /**************************************************************************
1030 * Operations on file names *
1031 **************************************************************************/
1034 /*************************************************************************
1035 * CreateFileW [KERNEL32.@] Creates or opens a file or other object
1037 * Creates or opens an object, and returns a handle that can be used to
1038 * access that object.
1042 * filename [in] pointer to filename to be accessed
1043 * access [in] access mode requested
1044 * sharing [in] share mode
1045 * sa [in] pointer to security attributes
1046 * creation [in] how to create the file
1047 * attributes [in] attributes for newly created file
1048 * template [in] handle to file with extended attributes to copy
1051 * Success: Open handle to specified file
1052 * Failure: INVALID_HANDLE_VALUE
1054 HANDLE WINAPI
CreateFileW( LPCWSTR filename
, DWORD access
, DWORD sharing
,
1055 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
1056 DWORD attributes
, HANDLE
template )
1060 OBJECT_ATTRIBUTES attr
;
1061 UNICODE_STRING nameW
;
1065 static const WCHAR bkslashes_with_dotW
[] = {'\\','\\','.','\\',0};
1066 static const WCHAR coninW
[] = {'C','O','N','I','N','$',0};
1067 static const WCHAR conoutW
[] = {'C','O','N','O','U','T','$',0};
1069 static const char * const creation_name
[5] =
1070 { "CREATE_NEW", "CREATE_ALWAYS", "OPEN_EXISTING", "OPEN_ALWAYS", "TRUNCATE_EXISTING" };
1072 static const UINT nt_disposition
[5] =
1074 FILE_CREATE
, /* CREATE_NEW */
1075 FILE_OVERWRITE_IF
, /* CREATE_ALWAYS */
1076 FILE_OPEN
, /* OPEN_EXISTING */
1077 FILE_OPEN_IF
, /* OPEN_ALWAYS */
1078 FILE_OVERWRITE
/* TRUNCATE_EXISTING */
1084 if (!filename
|| !filename
[0])
1086 SetLastError( ERROR_PATH_NOT_FOUND
);
1087 return INVALID_HANDLE_VALUE
;
1090 if (creation
< CREATE_NEW
|| creation
> TRUNCATE_EXISTING
)
1092 SetLastError( ERROR_INVALID_PARAMETER
);
1093 return INVALID_HANDLE_VALUE
;
1096 TRACE("%s %s%s%s%s%s%s%s attributes 0x%lx\n", debugstr_w(filename
),
1097 (access
& GENERIC_READ
)?"GENERIC_READ ":"",
1098 (access
& GENERIC_WRITE
)?"GENERIC_WRITE ":"",
1099 (!access
)?"QUERY_ACCESS ":"",
1100 (sharing
& FILE_SHARE_READ
)?"FILE_SHARE_READ ":"",
1101 (sharing
& FILE_SHARE_WRITE
)?"FILE_SHARE_WRITE ":"",
1102 (sharing
& FILE_SHARE_DELETE
)?"FILE_SHARE_DELETE ":"",
1103 creation_name
[creation
- CREATE_NEW
], attributes
);
1105 /* Open a console for CONIN$ or CONOUT$ */
1107 if (!strcmpiW(filename
, coninW
) || !strcmpiW(filename
, conoutW
))
1109 ret
= OpenConsoleW(filename
, access
, (sa
&& sa
->bInheritHandle
), creation
);
1113 if (!strncmpW(filename
, bkslashes_with_dotW
, 4))
1115 static const WCHAR pipeW
[] = {'P','I','P','E','\\',0};
1117 if ((isalphaW(filename
[4]) && filename
[5] == ':' && filename
[6] == '\0') ||
1118 !strncmpiW( filename
+ 4, pipeW
, 5 ))
1122 else if ((dosdev
= RtlIsDosDeviceName_U( filename
+ 4 )))
1124 dosdev
+= MAKELONG( 0, 4*sizeof(WCHAR
) ); /* adjust position to start of filename */
1126 else if (filename
[4])
1128 ret
= VXD_Open( filename
+4, access
, sa
);
1133 SetLastError( ERROR_INVALID_NAME
);
1134 return INVALID_HANDLE_VALUE
;
1137 else dosdev
= RtlIsDosDeviceName_U( filename
);
1141 static const WCHAR conW
[] = {'C','O','N'};
1143 if (LOWORD(dosdev
) == sizeof(conW
) &&
1144 !memicmpW( filename
+ HIWORD(dosdev
)/sizeof(WCHAR
), conW
, sizeof(conW
)))
1146 switch (access
& (GENERIC_READ
|GENERIC_WRITE
))
1149 ret
= OpenConsoleW(coninW
, access
, (sa
&& sa
->bInheritHandle
), creation
);
1152 ret
= OpenConsoleW(conoutW
, access
, (sa
&& sa
->bInheritHandle
), creation
);
1155 SetLastError( ERROR_FILE_NOT_FOUND
);
1156 return INVALID_HANDLE_VALUE
;
1161 if (!RtlDosPathNameToNtPathName_U( filename
, &nameW
, NULL
, NULL
))
1163 SetLastError( ERROR_PATH_NOT_FOUND
);
1164 return INVALID_HANDLE_VALUE
;
1167 /* now call NtCreateFile */
1170 if (attributes
& FILE_FLAG_BACKUP_SEMANTICS
)
1171 options
|= FILE_OPEN_FOR_BACKUP_INTENT
;
1173 options
|= FILE_NON_DIRECTORY_FILE
;
1174 if (attributes
& FILE_FLAG_DELETE_ON_CLOSE
)
1175 options
|= FILE_DELETE_ON_CLOSE
;
1176 if (!(attributes
& FILE_FLAG_OVERLAPPED
))
1177 options
|= FILE_SYNCHRONOUS_IO_ALERT
;
1178 if (attributes
& FILE_FLAG_RANDOM_ACCESS
)
1179 options
|= FILE_RANDOM_ACCESS
;
1180 attributes
&= FILE_ATTRIBUTE_VALID_FLAGS
;
1182 attr
.Length
= sizeof(attr
);
1183 attr
.RootDirectory
= 0;
1184 attr
.Attributes
= OBJ_CASE_INSENSITIVE
;
1185 attr
.ObjectName
= &nameW
;
1186 attr
.SecurityDescriptor
= sa
? sa
->lpSecurityDescriptor
: NULL
;
1187 attr
.SecurityQualityOfService
= NULL
;
1189 if (sa
&& sa
->bInheritHandle
) attr
.Attributes
|= OBJ_INHERIT
;
1191 status
= NtCreateFile( &ret
, access
, &attr
, &io
, NULL
, attributes
,
1192 sharing
, nt_disposition
[creation
- CREATE_NEW
],
1196 WARN("Unable to create file %s (status %lx)\n", debugstr_w(filename
), status
);
1197 ret
= INVALID_HANDLE_VALUE
;
1199 /* In the case file creation was rejected due to CREATE_NEW flag
1200 * was specified and file with that name already exists, correct
1201 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
1202 * Note: RtlNtStatusToDosError is not the subject to blame here.
1204 if (status
== STATUS_OBJECT_NAME_COLLISION
)
1205 SetLastError( ERROR_FILE_EXISTS
);
1207 SetLastError( RtlNtStatusToDosError(status
) );
1209 else SetLastError(0);
1210 RtlFreeUnicodeString( &nameW
);
1213 if (!ret
) ret
= INVALID_HANDLE_VALUE
;
1214 TRACE("returning %p\n", ret
);
1220 /*************************************************************************
1221 * CreateFileA (KERNEL32.@)
1223 HANDLE WINAPI
CreateFileA( LPCSTR filename
, DWORD access
, DWORD sharing
,
1224 LPSECURITY_ATTRIBUTES sa
, DWORD creation
,
1225 DWORD attributes
, HANDLE
template)
1227 UNICODE_STRING filenameW
;
1228 HANDLE ret
= INVALID_HANDLE_VALUE
;
1232 SetLastError( ERROR_INVALID_PARAMETER
);
1233 return INVALID_HANDLE_VALUE
;
1236 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, filename
))
1238 ret
= CreateFileW(filenameW
.Buffer
, access
, sharing
, sa
, creation
,
1239 attributes
, template);
1240 RtlFreeUnicodeString(&filenameW
);
1243 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1248 /***********************************************************************
1249 * DeleteFileW (KERNEL32.@)
1251 BOOL WINAPI
DeleteFileW( LPCWSTR path
)
1255 TRACE("%s\n", debugstr_w(path
) );
1257 hFile
= CreateFileW( path
, GENERIC_READ
| GENERIC_WRITE
,
1258 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
1259 NULL
, OPEN_EXISTING
, FILE_FLAG_DELETE_ON_CLOSE
, 0 );
1260 if (hFile
== INVALID_HANDLE_VALUE
) return FALSE
;
1262 CloseHandle(hFile
); /* last close will delete the file */
1267 /***********************************************************************
1268 * DeleteFileA (KERNEL32.@)
1270 BOOL WINAPI
DeleteFileA( LPCSTR path
)
1272 UNICODE_STRING pathW
;
1275 if (RtlCreateUnicodeStringFromAsciiz(&pathW
, path
))
1277 ret
= DeleteFileW(pathW
.Buffer
);
1278 RtlFreeUnicodeString(&pathW
);
1281 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1286 /**************************************************************************
1287 * ReplaceFileW (KERNEL32.@)
1288 * ReplaceFile (KERNEL32.@)
1290 BOOL WINAPI
ReplaceFileW(LPCWSTR lpReplacedFileName
,LPCWSTR lpReplacementFileName
,
1291 LPCWSTR lpBackupFileName
, DWORD dwReplaceFlags
,
1292 LPVOID lpExclude
, LPVOID lpReserved
)
1294 FIXME("(%s,%s,%s,%08lx,%p,%p) stub\n",debugstr_w(lpReplacedFileName
),debugstr_w(lpReplacementFileName
),
1295 debugstr_w(lpBackupFileName
),dwReplaceFlags
,lpExclude
,lpReserved
);
1296 SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT
);
1301 /**************************************************************************
1302 * ReplaceFileA (KERNEL32.@)
1304 BOOL WINAPI
ReplaceFileA(LPCSTR lpReplacedFileName
,LPCSTR lpReplacementFileName
,
1305 LPCSTR lpBackupFileName
, DWORD dwReplaceFlags
,
1306 LPVOID lpExclude
, LPVOID lpReserved
)
1308 FIXME("(%s,%s,%s,%08lx,%p,%p) stub\n",lpReplacedFileName
,lpReplacementFileName
,
1309 lpBackupFileName
,dwReplaceFlags
,lpExclude
,lpReserved
);
1310 SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT
);
1315 /*************************************************************************
1316 * FindFirstFileExW (KERNEL32.@)
1318 HANDLE WINAPI
FindFirstFileExW( LPCWSTR filename
, FINDEX_INFO_LEVELS level
,
1319 LPVOID data
, FINDEX_SEARCH_OPS search_op
,
1320 LPVOID filter
, DWORD flags
)
1323 FIND_FIRST_INFO
*info
= NULL
;
1324 UNICODE_STRING nt_name
;
1325 OBJECT_ATTRIBUTES attr
;
1329 if ((search_op
!= FindExSearchNameMatch
) || (flags
!= 0))
1331 FIXME("options not implemented 0x%08x 0x%08lx\n", search_op
, flags
);
1332 return INVALID_HANDLE_VALUE
;
1334 if (level
!= FindExInfoStandard
)
1336 FIXME("info level %d not implemented\n", level
);
1337 return INVALID_HANDLE_VALUE
;
1340 if (!RtlDosPathNameToNtPathName_U( filename
, &nt_name
, &mask
, NULL
))
1342 SetLastError( ERROR_PATH_NOT_FOUND
);
1343 return INVALID_HANDLE_VALUE
;
1346 if (!mask
|| !*mask
)
1348 SetLastError( ERROR_FILE_NOT_FOUND
);
1352 if (!(info
= HeapAlloc( GetProcessHeap(), 0, sizeof(*info
))))
1354 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1358 if (!RtlCreateUnicodeString( &info
->mask
, mask
))
1360 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1364 /* truncate dir name before mask */
1366 nt_name
.Length
= (mask
- nt_name
.Buffer
) * sizeof(WCHAR
);
1368 /* check if path is the root of the drive */
1369 info
->is_root
= FALSE
;
1370 p
= nt_name
.Buffer
+ 4; /* skip \??\ prefix */
1371 if (p
[0] && p
[1] == ':')
1374 while (*p
== '\\') p
++;
1375 info
->is_root
= (*p
== 0);
1378 attr
.Length
= sizeof(attr
);
1379 attr
.RootDirectory
= 0;
1380 attr
.Attributes
= OBJ_CASE_INSENSITIVE
;
1381 attr
.ObjectName
= &nt_name
;
1382 attr
.SecurityDescriptor
= NULL
;
1383 attr
.SecurityQualityOfService
= NULL
;
1385 status
= NtOpenFile( &info
->handle
, GENERIC_READ
, &attr
, &io
,
1386 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
1387 FILE_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
1389 if (status
!= STATUS_SUCCESS
)
1391 RtlFreeUnicodeString( &info
->mask
);
1392 SetLastError( RtlNtStatusToDosError(status
) );
1395 RtlFreeUnicodeString( &nt_name
);
1397 RtlInitializeCriticalSection( &info
->cs
);
1401 if (!FindNextFileW( (HANDLE
)info
, data
))
1403 TRACE( "%s not found\n", debugstr_w(filename
) );
1404 FindClose( (HANDLE
)info
);
1405 SetLastError( ERROR_FILE_NOT_FOUND
);
1406 return INVALID_HANDLE_VALUE
;
1408 return (HANDLE
)info
;
1411 if (info
) HeapFree( GetProcessHeap(), 0, info
);
1412 RtlFreeUnicodeString( &nt_name
);
1413 return INVALID_HANDLE_VALUE
;
1417 /*************************************************************************
1418 * FindNextFileW (KERNEL32.@)
1420 BOOL WINAPI
FindNextFileW( HANDLE handle
, WIN32_FIND_DATAW
*data
)
1422 FIND_FIRST_INFO
*info
;
1423 FILE_BOTH_DIR_INFORMATION
*dir_info
;
1426 if (handle
== INVALID_HANDLE_VALUE
)
1428 SetLastError( ERROR_INVALID_HANDLE
);
1431 info
= (FIND_FIRST_INFO
*)handle
;
1433 RtlEnterCriticalSection( &info
->cs
);
1437 if (info
->data_pos
>= info
->data_len
) /* need to read some more data */
1441 NtQueryDirectoryFile( info
->handle
, 0, NULL
, NULL
, &io
, info
->data
, sizeof(info
->data
),
1442 FileBothDirectoryInformation
, FALSE
, &info
->mask
, FALSE
);
1445 SetLastError( RtlNtStatusToDosError( io
.u
.Status
) );
1448 info
->data_len
= io
.Information
;
1452 dir_info
= (FILE_BOTH_DIR_INFORMATION
*)(info
->data
+ info
->data_pos
);
1454 if (dir_info
->NextEntryOffset
) info
->data_pos
+= dir_info
->NextEntryOffset
;
1455 else info
->data_pos
= info
->data_len
;
1457 /* don't return '.' and '..' in the root of the drive */
1460 if (dir_info
->FileNameLength
== sizeof(WCHAR
) && dir_info
->FileName
[0] == '.') continue;
1461 if (dir_info
->FileNameLength
== 2 * sizeof(WCHAR
) &&
1462 dir_info
->FileName
[0] == '.' && dir_info
->FileName
[1] == '.') continue;
1465 data
->dwFileAttributes
= dir_info
->FileAttributes
;
1466 data
->ftCreationTime
= *(FILETIME
*)&dir_info
->CreationTime
;
1467 data
->ftLastAccessTime
= *(FILETIME
*)&dir_info
->LastAccessTime
;
1468 data
->ftLastWriteTime
= *(FILETIME
*)&dir_info
->LastWriteTime
;
1469 data
->nFileSizeHigh
= dir_info
->EndOfFile
.QuadPart
>> 32;
1470 data
->nFileSizeLow
= (DWORD
)dir_info
->EndOfFile
.QuadPart
;
1471 data
->dwReserved0
= 0;
1472 data
->dwReserved1
= 0;
1474 memcpy( data
->cFileName
, dir_info
->FileName
, dir_info
->FileNameLength
);
1475 data
->cFileName
[dir_info
->FileNameLength
/sizeof(WCHAR
)] = 0;
1476 memcpy( data
->cAlternateFileName
, dir_info
->ShortName
, dir_info
->ShortNameLength
);
1477 data
->cAlternateFileName
[dir_info
->ShortNameLength
/sizeof(WCHAR
)] = 0;
1479 TRACE("returning %s (%s)\n",
1480 debugstr_w(data
->cFileName
), debugstr_w(data
->cAlternateFileName
) );
1486 RtlLeaveCriticalSection( &info
->cs
);
1491 /*************************************************************************
1492 * FindClose (KERNEL32.@)
1494 BOOL WINAPI
FindClose( HANDLE handle
)
1496 FIND_FIRST_INFO
*info
= (FIND_FIRST_INFO
*)handle
;
1498 if (!handle
|| handle
== INVALID_HANDLE_VALUE
) goto error
;
1502 RtlEnterCriticalSection( &info
->cs
);
1503 if (info
->handle
) CloseHandle( info
->handle
);
1505 RtlFreeUnicodeString( &info
->mask
);
1506 info
->mask
.Buffer
= NULL
;
1510 __EXCEPT(page_fault
)
1512 WARN("Illegal handle %p\n", handle
);
1513 SetLastError( ERROR_INVALID_HANDLE
);
1518 RtlLeaveCriticalSection( &info
->cs
);
1519 RtlDeleteCriticalSection( &info
->cs
);
1520 HeapFree(GetProcessHeap(), 0, info
);
1524 SetLastError( ERROR_INVALID_HANDLE
);
1529 /*************************************************************************
1530 * FindFirstFileA (KERNEL32.@)
1532 HANDLE WINAPI
FindFirstFileA( LPCSTR lpFileName
, WIN32_FIND_DATAA
*lpFindData
)
1534 return FindFirstFileExA(lpFileName
, FindExInfoStandard
, lpFindData
,
1535 FindExSearchNameMatch
, NULL
, 0);
1538 /*************************************************************************
1539 * FindFirstFileExA (KERNEL32.@)
1541 HANDLE WINAPI
FindFirstFileExA( LPCSTR lpFileName
, FINDEX_INFO_LEVELS fInfoLevelId
,
1542 LPVOID lpFindFileData
, FINDEX_SEARCH_OPS fSearchOp
,
1543 LPVOID lpSearchFilter
, DWORD dwAdditionalFlags
)
1546 WIN32_FIND_DATAA
*dataA
;
1547 WIN32_FIND_DATAW dataW
;
1548 UNICODE_STRING pathW
;
1552 SetLastError(ERROR_PATH_NOT_FOUND
);
1553 return INVALID_HANDLE_VALUE
;
1556 if (!RtlCreateUnicodeStringFromAsciiz(&pathW
, lpFileName
))
1558 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1559 return INVALID_HANDLE_VALUE
;
1562 handle
= FindFirstFileExW(pathW
.Buffer
, fInfoLevelId
, &dataW
, fSearchOp
, lpSearchFilter
, dwAdditionalFlags
);
1563 RtlFreeUnicodeString(&pathW
);
1564 if (handle
== INVALID_HANDLE_VALUE
) return handle
;
1566 dataA
= (WIN32_FIND_DATAA
*) lpFindFileData
;
1567 dataA
->dwFileAttributes
= dataW
.dwFileAttributes
;
1568 dataA
->ftCreationTime
= dataW
.ftCreationTime
;
1569 dataA
->ftLastAccessTime
= dataW
.ftLastAccessTime
;
1570 dataA
->ftLastWriteTime
= dataW
.ftLastWriteTime
;
1571 dataA
->nFileSizeHigh
= dataW
.nFileSizeHigh
;
1572 dataA
->nFileSizeLow
= dataW
.nFileSizeLow
;
1573 WideCharToMultiByte( CP_ACP
, 0, dataW
.cFileName
, -1,
1574 dataA
->cFileName
, sizeof(dataA
->cFileName
), NULL
, NULL
);
1575 WideCharToMultiByte( CP_ACP
, 0, dataW
.cAlternateFileName
, -1,
1576 dataA
->cAlternateFileName
, sizeof(dataA
->cAlternateFileName
), NULL
, NULL
);
1581 /*************************************************************************
1582 * FindFirstFileW (KERNEL32.@)
1584 HANDLE WINAPI
FindFirstFileW( LPCWSTR lpFileName
, WIN32_FIND_DATAW
*lpFindData
)
1586 return FindFirstFileExW(lpFileName
, FindExInfoStandard
, lpFindData
,
1587 FindExSearchNameMatch
, NULL
, 0);
1591 /*************************************************************************
1592 * FindNextFileA (KERNEL32.@)
1594 BOOL WINAPI
FindNextFileA( HANDLE handle
, WIN32_FIND_DATAA
*data
)
1596 WIN32_FIND_DATAW dataW
;
1598 if (!FindNextFileW( handle
, &dataW
)) return FALSE
;
1599 data
->dwFileAttributes
= dataW
.dwFileAttributes
;
1600 data
->ftCreationTime
= dataW
.ftCreationTime
;
1601 data
->ftLastAccessTime
= dataW
.ftLastAccessTime
;
1602 data
->ftLastWriteTime
= dataW
.ftLastWriteTime
;
1603 data
->nFileSizeHigh
= dataW
.nFileSizeHigh
;
1604 data
->nFileSizeLow
= dataW
.nFileSizeLow
;
1605 WideCharToMultiByte( CP_ACP
, 0, dataW
.cFileName
, -1,
1606 data
->cFileName
, sizeof(data
->cFileName
), NULL
, NULL
);
1607 WideCharToMultiByte( CP_ACP
, 0, dataW
.cAlternateFileName
, -1,
1608 data
->cAlternateFileName
,
1609 sizeof(data
->cAlternateFileName
), NULL
, NULL
);
1614 /**************************************************************************
1615 * GetFileAttributesW (KERNEL32.@)
1617 DWORD WINAPI
GetFileAttributesW( LPCWSTR name
)
1619 FILE_BASIC_INFORMATION info
;
1620 UNICODE_STRING nt_name
;
1621 OBJECT_ATTRIBUTES attr
;
1624 if (!RtlDosPathNameToNtPathName_U( name
, &nt_name
, NULL
, NULL
))
1626 SetLastError( ERROR_PATH_NOT_FOUND
);
1627 return INVALID_FILE_ATTRIBUTES
;
1630 attr
.Length
= sizeof(attr
);
1631 attr
.RootDirectory
= 0;
1632 attr
.Attributes
= OBJ_CASE_INSENSITIVE
;
1633 attr
.ObjectName
= &nt_name
;
1634 attr
.SecurityDescriptor
= NULL
;
1635 attr
.SecurityQualityOfService
= NULL
;
1637 status
= NtQueryAttributesFile( &attr
, &info
);
1638 RtlFreeUnicodeString( &nt_name
);
1640 if (status
== STATUS_SUCCESS
) return info
.FileAttributes
;
1642 /* NtQueryAttributesFile fails on devices, but GetFileAttributesW succeeds */
1643 if (RtlIsDosDeviceName_U( name
)) return FILE_ATTRIBUTE_ARCHIVE
;
1645 SetLastError( RtlNtStatusToDosError(status
) );
1646 return INVALID_FILE_ATTRIBUTES
;
1650 /**************************************************************************
1651 * GetFileAttributesA (KERNEL32.@)
1653 DWORD WINAPI
GetFileAttributesA( LPCSTR name
)
1655 UNICODE_STRING nameW
;
1656 DWORD ret
= INVALID_FILE_ATTRIBUTES
;
1660 SetLastError( ERROR_INVALID_PARAMETER
);
1661 return INVALID_FILE_ATTRIBUTES
;
1664 if (RtlCreateUnicodeStringFromAsciiz(&nameW
, name
))
1666 ret
= GetFileAttributesW(nameW
.Buffer
);
1667 RtlFreeUnicodeString(&nameW
);
1670 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1675 /**************************************************************************
1676 * SetFileAttributesW (KERNEL32.@)
1678 BOOL WINAPI
SetFileAttributesW( LPCWSTR name
, DWORD attributes
)
1680 UNICODE_STRING nt_name
;
1681 OBJECT_ATTRIBUTES attr
;
1686 if (!RtlDosPathNameToNtPathName_U( name
, &nt_name
, NULL
, NULL
))
1688 SetLastError( ERROR_PATH_NOT_FOUND
);
1692 attr
.Length
= sizeof(attr
);
1693 attr
.RootDirectory
= 0;
1694 attr
.Attributes
= OBJ_CASE_INSENSITIVE
;
1695 attr
.ObjectName
= &nt_name
;
1696 attr
.SecurityDescriptor
= NULL
;
1697 attr
.SecurityQualityOfService
= NULL
;
1699 status
= NtOpenFile( &handle
, 0, &attr
, &io
, 0, FILE_SYNCHRONOUS_IO_NONALERT
);
1700 RtlFreeUnicodeString( &nt_name
);
1702 if (status
== STATUS_SUCCESS
)
1704 FILE_BASIC_INFORMATION info
;
1706 memset( &info
, 0, sizeof(info
) );
1707 info
.FileAttributes
= attributes
| FILE_ATTRIBUTE_NORMAL
; /* make sure it's not zero */
1708 status
= NtSetInformationFile( handle
, &io
, &info
, sizeof(info
), FileBasicInformation
);
1712 if (status
== STATUS_SUCCESS
) return TRUE
;
1713 SetLastError( RtlNtStatusToDosError(status
) );
1718 /**************************************************************************
1719 * SetFileAttributesA (KERNEL32.@)
1721 BOOL WINAPI
SetFileAttributesA( LPCSTR name
, DWORD attributes
)
1723 UNICODE_STRING filenameW
;
1728 SetLastError( ERROR_INVALID_PARAMETER
);
1732 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, name
))
1734 ret
= SetFileAttributesW(filenameW
.Buffer
, attributes
);
1735 RtlFreeUnicodeString(&filenameW
);
1738 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1743 /**************************************************************************
1744 * GetFileAttributesExW (KERNEL32.@)
1746 BOOL WINAPI
GetFileAttributesExW( LPCWSTR name
, GET_FILEEX_INFO_LEVELS level
, LPVOID ptr
)
1748 FILE_NETWORK_OPEN_INFORMATION info
;
1749 WIN32_FILE_ATTRIBUTE_DATA
*data
= ptr
;
1750 UNICODE_STRING nt_name
;
1751 OBJECT_ATTRIBUTES attr
;
1754 if (level
!= GetFileExInfoStandard
)
1756 SetLastError( ERROR_INVALID_PARAMETER
);
1760 if (!RtlDosPathNameToNtPathName_U( name
, &nt_name
, NULL
, NULL
))
1762 SetLastError( ERROR_PATH_NOT_FOUND
);
1766 attr
.Length
= sizeof(attr
);
1767 attr
.RootDirectory
= 0;
1768 attr
.Attributes
= OBJ_CASE_INSENSITIVE
;
1769 attr
.ObjectName
= &nt_name
;
1770 attr
.SecurityDescriptor
= NULL
;
1771 attr
.SecurityQualityOfService
= NULL
;
1773 status
= NtQueryFullAttributesFile( &attr
, &info
);
1774 RtlFreeUnicodeString( &nt_name
);
1776 if (status
!= STATUS_SUCCESS
)
1778 SetLastError( RtlNtStatusToDosError(status
) );
1782 data
->dwFileAttributes
= info
.FileAttributes
;
1783 data
->ftCreationTime
.dwLowDateTime
= info
.CreationTime
.u
.LowPart
;
1784 data
->ftCreationTime
.dwHighDateTime
= info
.CreationTime
.u
.HighPart
;
1785 data
->ftLastAccessTime
.dwLowDateTime
= info
.LastAccessTime
.u
.LowPart
;
1786 data
->ftLastAccessTime
.dwHighDateTime
= info
.LastAccessTime
.u
.HighPart
;
1787 data
->ftLastWriteTime
.dwLowDateTime
= info
.LastWriteTime
.u
.LowPart
;
1788 data
->ftLastWriteTime
.dwHighDateTime
= info
.LastWriteTime
.u
.HighPart
;
1789 data
->nFileSizeLow
= info
.EndOfFile
.u
.LowPart
;
1790 data
->nFileSizeHigh
= info
.EndOfFile
.u
.HighPart
;
1795 /**************************************************************************
1796 * GetFileAttributesExA (KERNEL32.@)
1798 BOOL WINAPI
GetFileAttributesExA( LPCSTR name
, GET_FILEEX_INFO_LEVELS level
, LPVOID ptr
)
1800 UNICODE_STRING filenameW
;
1805 SetLastError(ERROR_INVALID_PARAMETER
);
1809 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, name
))
1811 ret
= GetFileAttributesExW(filenameW
.Buffer
, level
, ptr
);
1812 RtlFreeUnicodeString(&filenameW
);
1815 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1820 /******************************************************************************
1821 * GetCompressedFileSizeW (KERNEL32.@)
1824 * Success: Low-order doubleword of number of bytes
1825 * Failure: INVALID_FILE_SIZE
1827 DWORD WINAPI
GetCompressedFileSizeW(
1828 LPCWSTR name
, /* [in] Pointer to name of file */
1829 LPDWORD size_high
) /* [out] Receives high-order doubleword of size */
1831 UNICODE_STRING nt_name
;
1832 OBJECT_ATTRIBUTES attr
;
1836 DWORD ret
= INVALID_FILE_SIZE
;
1838 if (!RtlDosPathNameToNtPathName_U( name
, &nt_name
, NULL
, NULL
))
1840 SetLastError( ERROR_PATH_NOT_FOUND
);
1841 return INVALID_FILE_SIZE
;
1844 attr
.Length
= sizeof(attr
);
1845 attr
.RootDirectory
= 0;
1846 attr
.Attributes
= OBJ_CASE_INSENSITIVE
;
1847 attr
.ObjectName
= &nt_name
;
1848 attr
.SecurityDescriptor
= NULL
;
1849 attr
.SecurityQualityOfService
= NULL
;
1851 status
= NtOpenFile( &handle
, 0, &attr
, &io
, 0, FILE_SYNCHRONOUS_IO_NONALERT
);
1852 RtlFreeUnicodeString( &nt_name
);
1854 if (status
== STATUS_SUCCESS
)
1856 /* we don't support compressed files, simply return the file size */
1857 ret
= GetFileSize( handle
, size_high
);
1860 else SetLastError( RtlNtStatusToDosError(status
) );
1866 /******************************************************************************
1867 * GetCompressedFileSizeA (KERNEL32.@)
1869 DWORD WINAPI
GetCompressedFileSizeA( LPCSTR name
, LPDWORD size_high
)
1871 UNICODE_STRING filenameW
;
1874 if (RtlCreateUnicodeStringFromAsciiz(&filenameW
, name
))
1876 ret
= GetCompressedFileSizeW(filenameW
.Buffer
, size_high
);
1877 RtlFreeUnicodeString(&filenameW
);
1881 ret
= INVALID_FILE_SIZE
;
1882 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1888 /***********************************************************************
1889 * OpenFile (KERNEL32.@)
1891 HFILE WINAPI
OpenFile( LPCSTR name
, OFSTRUCT
*ofs
, UINT mode
)
1895 WORD filedatetime
[2];
1897 if (!ofs
) return HFILE_ERROR
;
1899 TRACE("%s %s %s %s%s%s%s%s%s%s%s%s\n",name
,
1900 ((mode
& 0x3 )==OF_READ
)?"OF_READ":
1901 ((mode
& 0x3 )==OF_WRITE
)?"OF_WRITE":
1902 ((mode
& 0x3 )==OF_READWRITE
)?"OF_READWRITE":"unknown",
1903 ((mode
& 0x70 )==OF_SHARE_COMPAT
)?"OF_SHARE_COMPAT":
1904 ((mode
& 0x70 )==OF_SHARE_DENY_NONE
)?"OF_SHARE_DENY_NONE":
1905 ((mode
& 0x70 )==OF_SHARE_DENY_READ
)?"OF_SHARE_DENY_READ":
1906 ((mode
& 0x70 )==OF_SHARE_DENY_WRITE
)?"OF_SHARE_DENY_WRITE":
1907 ((mode
& 0x70 )==OF_SHARE_EXCLUSIVE
)?"OF_SHARE_EXCLUSIVE":"unknown",
1908 ((mode
& OF_PARSE
)==OF_PARSE
)?"OF_PARSE ":"",
1909 ((mode
& OF_DELETE
)==OF_DELETE
)?"OF_DELETE ":"",
1910 ((mode
& OF_VERIFY
)==OF_VERIFY
)?"OF_VERIFY ":"",
1911 ((mode
& OF_SEARCH
)==OF_SEARCH
)?"OF_SEARCH ":"",
1912 ((mode
& OF_CANCEL
)==OF_CANCEL
)?"OF_CANCEL ":"",
1913 ((mode
& OF_CREATE
)==OF_CREATE
)?"OF_CREATE ":"",
1914 ((mode
& OF_PROMPT
)==OF_PROMPT
)?"OF_PROMPT ":"",
1915 ((mode
& OF_EXIST
)==OF_EXIST
)?"OF_EXIST ":"",
1916 ((mode
& OF_REOPEN
)==OF_REOPEN
)?"OF_REOPEN ":""
1920 ofs
->cBytes
= sizeof(OFSTRUCT
);
1922 if (mode
& OF_REOPEN
) name
= ofs
->szPathName
;
1924 if (!name
) return HFILE_ERROR
;
1926 TRACE("%s %04x\n", name
, mode
);
1928 /* the watcom 10.6 IDE relies on a valid path returned in ofs->szPathName
1929 Are there any cases where getting the path here is wrong?
1930 Uwe Bonnes 1997 Apr 2 */
1931 if (!GetFullPathNameA( name
, sizeof(ofs
->szPathName
), ofs
->szPathName
, NULL
)) goto error
;
1933 /* OF_PARSE simply fills the structure */
1935 if (mode
& OF_PARSE
)
1937 ofs
->fFixedDisk
= (GetDriveTypeA( ofs
->szPathName
) != DRIVE_REMOVABLE
);
1938 TRACE("(%s): OF_PARSE, res = '%s'\n", name
, ofs
->szPathName
);
1942 /* OF_CREATE is completely different from all other options, so
1945 if (mode
& OF_CREATE
)
1947 if ((handle
= create_file_OF( name
, mode
, CREATE_ALWAYS
)) == INVALID_HANDLE_VALUE
)
1952 /* Now look for the file */
1954 if (!SearchPathA( NULL
, name
, NULL
, sizeof(ofs
->szPathName
), ofs
->szPathName
, NULL
))
1957 TRACE("found %s\n", debugstr_a(ofs
->szPathName
) );
1959 if (mode
& OF_DELETE
)
1961 if (!DeleteFileA( ofs
->szPathName
)) goto error
;
1962 TRACE("(%s): OF_DELETE return = OK\n", name
);
1966 handle
= (HANDLE
)_lopen( ofs
->szPathName
, mode
);
1967 if (handle
== INVALID_HANDLE_VALUE
) goto error
;
1969 GetFileTime( handle
, NULL
, NULL
, &filetime
);
1970 FileTimeToDosDateTime( &filetime
, &filedatetime
[0], &filedatetime
[1] );
1971 if ((mode
& OF_VERIFY
) && (mode
& OF_REOPEN
))
1973 if (ofs
->Reserved1
!= filedatetime
[0] || ofs
->Reserved2
!= filedatetime
[1] )
1975 CloseHandle( handle
);
1976 WARN("(%s): OF_VERIFY failed\n", name
);
1977 /* FIXME: what error here? */
1978 SetLastError( ERROR_FILE_NOT_FOUND
);
1982 ofs
->Reserved1
= filedatetime
[0];
1983 ofs
->Reserved2
= filedatetime
[1];
1985 TRACE("(%s): OK, return = %p\n", name
, handle
);
1986 if (mode
& OF_EXIST
) /* Return TRUE instead of a handle */
1988 CloseHandle( handle
);
1991 else return (HFILE
)handle
;
1993 error
: /* We get here if there was an error opening the file */
1994 ofs
->nErrCode
= GetLastError();
1995 WARN("(%s): return = HFILE_ERROR error= %d\n", name
,ofs
->nErrCode
);